From 37a821f6cf167900e6df0d7632ab49195c4a4848 Mon Sep 17 00:00:00 2001 From: Stefano Ceccherini Date: Mon, 29 Dec 2003 07:19:42 +0000 Subject: [PATCH] BOptionPopUp and its abstract class BOptionControl, completed. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5795 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/interface/OptionControl.cpp | 161 +++++++++++++ src/kits/interface/OptionPopUp.cpp | 345 +++++++++++++++++++++++++++ src/kits/interface/interface.src | 2 + 3 files changed, 508 insertions(+) create mode 100644 src/kits/interface/OptionControl.cpp create mode 100644 src/kits/interface/OptionPopUp.cpp diff --git a/src/kits/interface/OptionControl.cpp b/src/kits/interface/OptionControl.cpp new file mode 100644 index 0000000000..31306a524b --- /dev/null +++ b/src/kits/interface/OptionControl.cpp @@ -0,0 +1,161 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2003 Stefano Ceccherini +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: OptionControl.cpp +// Description: An abstract base class for option controls. +//------------------------------------------------------------------------------ +#include + +#include + +/*! \brief Creates and initializes a BOptionControl. + \param frame The control's frame rectangle. + \param name The control's name. + \param label The label displayed by the control. + \param message The message which the control will send when operated. + \param resize Resize mask, passed to the base class's constructor. + \param flags View flags, passed to the base class's constructor. +*/ +BOptionControl::BOptionControl(BRect frame, const char *name, const char *label, + BMessage *message, uint32 resize, uint32 flags) + : + BControl(frame, name, label, message, resize, flags) +{ +} + + +BOptionControl::~BOptionControl() +{ +} + + +void +BOptionControl::MessageReceived(BMessage *message) +{ + switch (message->what) { + case B_OPTION_CONTROL_VALUE: + { + int32 value; + if (message->FindInt32("be:value", &value) == B_OK) + SetValue(value); + break; + } + default: + BControl::MessageReceived(message); + break; + } +} + + +/*! \brief Adds an "option" after the last one. + \param name The name of the option. + \param value The value of the option. + \return \c B_OK if the option was added succesfully, + an error code otherwise. +*/ +status_t +BOptionControl::AddOption(const char *name, int32 value) +{ + int32 numOptions = CountOptions(); + return AddOptionAt(name, value, numOptions); +} + + +/*! \brief Select the option which has the given value. + \param value The value of the option. + \return \c B_OK if there was an option with that value, + and it was correctly selected, an error code otherwise. + It works exactly as SetValue(value); +*/ +status_t +BOptionControl::SelectOptionFor(int32 value) +{ + // XXX: I wonder why this method was created in the first place, + // since you can obtain the same result simply by calling SetValue(). + // The only difference I can see is that this method iterates over + // all the options contained in the contrl, and thens elects the right one. + int32 numOptions = CountOptions(); + for (int32 c = 0; c < numOptions; c++) { + const char *name; + int32 optionValue; + if (GetOptionAt(c, &name, &optionValue) && optionValue == value) { + SetValue(optionValue); + return B_OK; + } + } + + return B_ERROR; +} + + +/*! \brief Select the option which has the given name. + \param name The name of the option. + \return \c B_OK if there was an option with that name, + and it was correctly selected, an error code otherwise. +*/ +status_t +BOptionControl::SelectOptionFor(const char *name) +{ + int32 numOptions = CountOptions(); + for (int32 c = 0; c < numOptions; c++) { + const char *optionName = NULL; + int32 optionValue; + if (GetOptionAt(c, &optionName, &optionValue) + && !strcmp(name, optionName)) { + SetValue(optionValue); + return B_OK; + } + } + return B_ERROR; +} + + +// Protected +/*! \brief Creates a BMessage which contains the given value. + \param The value to be added to the message. + \return A pointer to a BMessage, NULL if something went wrong. +*/ +BMessage * +BOptionControl::MakeValueMessage(int32 value) +{ + BMessage *message = new BMessage(B_OPTION_CONTROL_VALUE); + if (message->AddInt32("be:value", value) != B_OK) { + delete message; + message = NULL; + } + + return message; +} + + +// FBC +status_t BOptionControl::_Reserved_OptionControl_0(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_1(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_2(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_3(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_4(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_5(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_6(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_7(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_8(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_9(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_10(void *, ...) { return B_ERROR; } +status_t BOptionControl::_Reserved_OptionControl_11(void *, ...) { return B_ERROR; } diff --git a/src/kits/interface/OptionPopUp.cpp b/src/kits/interface/OptionPopUp.cpp new file mode 100644 index 0000000000..664bbe7441 --- /dev/null +++ b/src/kits/interface/OptionPopUp.cpp @@ -0,0 +1,345 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2003 Stefano Ceccherini +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: OptionPopUp.cpp +// Description: An option like control. +//------------------------------------------------------------------------------ +#include +#include +#include +#include + +#include + +const float kLabelSpace = 8.0; +const float kWidthModifier = 25.0; +const float kHeightModifier = 10.0; + +/*! \brief Creates and initializes a BOptionPopUp. + \param frame The frame of the control. + \param name The name of the control. + \param label The label which will be displayed by the control. + \param message The message which the control will send when operated. + \param resize Resizing flags. They will be passed to the base class. + \param flags View flags. They will be passed to the base class. +*/ +BOptionPopUp::BOptionPopUp(BRect frame, const char *name, const char *label, + BMessage *message, uint32 resize, uint32 flags) + : + BOptionControl(frame, name, label, message, resize, flags) +{ + BPopUpMenu *popUp = new BPopUpMenu(label, true, true); + _mField = new BMenuField(Bounds(), "_menu", label, popUp); + AddChild(_mField); +} + + +/*! \brief Creates and initializes a BOptionPopUp. + \param frame The frame of the control. + \param name The name of the control. + \param label The label which will be displayed by the control. + \param message The message which the control will send when operated. + \param fixed ? + \param resize Resizing flags. They will be passed to the base class. + \param flags View flags. They will be passed to the base class. +*/ +BOptionPopUp::BOptionPopUp(BRect frame, const char *name, const char *label, + BMessage *message, bool fixed, uint32 resize, uint32 flags) + : + BOptionControl(frame, name, label, message, resize, flags) +{ + BPopUpMenu *popUp = new BPopUpMenu(label, true, true); + _mField = new BMenuField(Bounds(), "_menu", label, popUp, fixed); + AddChild(_mField); +} + + +/*! \brief Frees the allocated resources. + It does nothing. +*/ +BOptionPopUp::~BOptionPopUp() +{ +} + + +/*! \brief Returns a pointer to the BMenuField used internally. + \return A Pointer to the BMenuField which the class uses internally. +*/ +BMenuField * +BOptionPopUp::MenuField() +{ + return _mField; +} + + +/*! \brief Gets the option at the given index. + \param index The option's index. + \param outName A pointer to a string which will held the option's name, + as soon as the function returns. + \param outValue A pointer to an integer which will held the option's value, + as soon as the funciton returns. + \return \c true if The wanted option was found, + \c false otherwise. +*/ +bool +BOptionPopUp::GetOptionAt(int32 index, const char **outName, int32 *outValue) +{ + bool result = false; + BMenu *menu = _mField->Menu(); + + if (menu != NULL) { + BMenuItem *item = menu->ItemAt(index); + if (item != NULL) { + if (outName != NULL) + *outName = item->Label(); + if (outValue != NULL) + item->Message()->FindInt32("be:value", outValue); + + result = true; + } + } + return result; +} + + +/*! \brief Removes the option at the given index. + \param index The index of the option to remove. +*/ +void +BOptionPopUp::RemoveOptionAt(int32 index) +{ + BMenu *menu = _mField->Menu(); + if (menu != NULL) { + BMenuItem *item = menu->ItemAt(index); + if (item != NULL) { + menu->RemoveItem(item); + delete item; + } + } +} + + +/*! \brief Returns the amount of "Options" (entries) contained in the control. +*/ +int32 +BOptionPopUp::CountOptions() const +{ + BMenu *menu = _mField->Menu(); + return (menu != NULL) ? menu->CountItems() : 0; +} + +/*! \brief Adds an option to the control, at the given position. + \param name The name of the option to add. + \param value The value of the option. + \param index The index which the new option will have in the control. + \return \c B_OK if the option was added succesfully, + \c B_BAD_VALUE if the given index was invalid. + \c B_ERROR if something else happened. +*/ +status_t +BOptionPopUp::AddOptionAt(const char *name, int32 value, int32 index) +{ + BMenu *menu = _mField->Menu(); + if (menu != NULL) { + int32 numItems = menu->CountItems(); + if (index < 0 || index > numItems) + return B_BAD_VALUE; + + BMessage *message = MakeValueMessage(value); + if (message == NULL) + return B_ERROR; + + BMenuItem *newItem = new BMenuItem(name, message); + menu->AddItem(newItem, index); + + // We didnt' have any items before, so select the newly added one + if (numItems == 0) + SetValue(value); + return B_OK; + } + + return B_ERROR; +} + + +/*! \brief Called to take special actions when the child views are attached. + It's used to set correctly the divider for the BMenuField. +*/ +void +BOptionPopUp::AllAttached() +{ + BMenu *menu = _mField->Menu(); + if (menu != NULL) { + float labelWidth = _mField->StringWidth(_mField->Label()); + _mField->SetDivider(labelWidth + kLabelSpace); + } +} + + +void +BOptionPopUp::MessageReceived(BMessage *message) +{ + BOptionControl::MessageReceived(message); +} + + +/*! \brief Set the label of the control. + \param text The new label of the control. +*/ +void +BOptionPopUp::SetLabel(const char *text) +{ + BControl::SetLabel(text); + _mField->SetLabel(text); + // We are not sure the menu can keep the whole + // string as label, so we ask it what label it's got + float newWidth = _mField->StringWidth(_mField->Label()); + _mField->SetDivider(newWidth + kLabelSpace); +} + + +/*! \brief Set the control's value. + \param value The new value of the control. + Selects the option which has the given value. +*/ +void +BOptionPopUp::SetValue(int32 value) +{ + BControl::SetValue(value); + BMenu *menu = _mField->Menu(); + int32 numItems = menu->CountItems(); + for (int32 i = 0; i < numItems; i++) { + BMenuItem *item = menu->ItemAt(i); + if (item && item->Message()) { + int32 val; + item->Message()->FindInt32("be:value", &val); + if (val == value) { + // TODO: This double call is needed because SetValue() doesn't mark + // items which are selected. Is there a better way to select + // an item without marking it ? + item->SetMarked(true); + item->SetMarked(false); + break; + } + } + } +} + + +/*! \brief Enables or disables the control. + \param state The new control's state. +*/ +void +BOptionPopUp::SetEnabled(bool state) +{ + BOptionControl::SetEnabled(state); +} + + +/*! \brief Gets the preferred size for the control. + \param width A pointer to a float which will held the control's + preferred width. + \param height A pointer to a float which will held the control's + preferred height. +*/ +void +BOptionPopUp::GetPreferredSize(float *width, float *height) +{ + font_height fontHeight; + _mField->GetFontHeight(&fontHeight); + + if (height != NULL) + *height = fontHeight.ascent + fontHeight.descent + + fontHeight.leading + kHeightModifier; + + float maxWidth = 0; + BMenu *menu = _mField->Menu(); + if (menu == NULL) + return; + + int32 numItems = menu->CountItems(); + for (int32 i = 0; i < numItems; i++) { + BMenuItem *item = menu->ItemAt(i); + if (item != NULL) { + float stringWidth = menu->StringWidth(item->Label()); + maxWidth = max_c(maxWidth, stringWidth); + } + } + + maxWidth += _mField->StringWidth(BControl::Label()) + kLabelSpace + kWidthModifier; + if (width != NULL) + *width = maxWidth; +} + + +/*! \brief Resizes the control to its preferred size. +*/ +void +BOptionPopUp::ResizeToPreferred() +{ + // TODO: Some more work is needed either here or in GetPreferredSize(), + // since the control doesnt' always resize as it should. + float width, height; + GetPreferredSize(&width, &height); + ResizeTo(width, height); + + float newWidth = _mField->StringWidth(BControl::Label()); + _mField->SetDivider(newWidth + kLabelSpace); +} + + +/*! \brief Gets the currently selected option. + \param outName A pointer to a string which will held the option's name. + \param outValue A pointer to an integer which will held the option's value. + \return The index of the selected option. +*/ +int32 +BOptionPopUp::SelectedOption(const char **outName, int32 *outValue) const +{ + BMenu *menu = _mField->Menu(); + if (menu != NULL) { + BMenuItem *marked = menu->FindMarked(); + if (marked != NULL) { + if (outName != NULL) + *outName = marked->Label(); + if (outValue != NULL) + *outValue = marked->Message()->FindInt32("be:value", outValue); + + return menu->IndexOf(marked); + } + } + + return B_ERROR; +} + + +status_t BOptionPopUp::_Reserved_OptionControl_0(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionControl_1(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionControl_2(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionControl_3(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionPopUp_0(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionPopUp_1(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionPopUp_2(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionPopUp_3(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionPopUp_4(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionPopUp_5(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionPopUp_6(void *, ...) { return B_ERROR; } +status_t BOptionPopUp::_Reserved_OptionPopUp_7(void *, ...) { return B_ERROR; } diff --git a/src/kits/interface/interface.src b/src/kits/interface/interface.src index ea745a71db..fe3bdcf87c 100644 --- a/src/kits/interface/interface.src +++ b/src/kits/interface/interface.src @@ -11,6 +11,8 @@ INTERFACE_KIT_SOURCE = Font.cpp Globals.cpp Input.cpp + OptionControl.cpp + OptionPopUp.cpp Picture.cpp PictureButton.cpp Point.cpp