diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index edcb34c35..39c6b88ab 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -629,7 +629,7 @@ void Skin::drawRibbonChild(const core::rect< s32 > &rect, Widget* widget, const } const bool mark_focused = focused || (parent_focused && w != NULL && w->m_focus == widget) || - (mark_selected && !always_show_selection && parent_focused); + (mark_selected && !always_show_selection && parent_focused); if(always_show_selection && mark_selected) diff --git a/src/guiengine/widget.hpp b/src/guiengine/widget.hpp index dd1319cc4..4d3229e79 100644 --- a/src/guiengine/widget.hpp +++ b/src/guiengine/widget.hpp @@ -186,7 +186,7 @@ namespace GUIEngine 1) For 'placeholder' divisions; at the time the layout is created, there is nothing to place there yet, but we know there eventually will. So in this case pass 'true' to the Widget constructor and it will reserve a widget ID and store it here. - 2) Theorically, in 'add()', derivded widgets should checked if this value is set, and use + 2) Theorically, in 'add()', derived widgets should checked if this value is set, and use it instead of creating a new ID if it is. In practice, it's not widely implemented (FIXME) */ int m_reserved_id; diff --git a/src/guiengine/widgets/button_widget.cpp b/src/guiengine/widgets/button_widget.cpp index 23765b8bd..500e25714 100644 --- a/src/guiengine/widgets/button_widget.cpp +++ b/src/guiengine/widgets/button_widget.cpp @@ -23,7 +23,7 @@ ButtonWidget::ButtonWidget() { m_type = WTYPE_BUTTON; } - +// ----------------------------------------------------------------------------- void ButtonWidget::add() { rect widget_size = rect(x, y, x + w, y + h); @@ -34,6 +34,7 @@ void ButtonWidget::add() m_element->setTabOrder(id); m_element->setTabGroup(false); } +// ----------------------------------------------------------------------------- void ButtonWidget::setLabel(const char* label) { m_element->setText( stringw(label).c_str() ); diff --git a/src/guiengine/widgets/button_widget.hpp b/src/guiengine/widgets/button_widget.hpp index a805f1dcd..5e968bf7d 100644 --- a/src/guiengine/widgets/button_widget.hpp +++ b/src/guiengine/widgets/button_widget.hpp @@ -30,6 +30,7 @@ using namespace gui; namespace GUIEngine { + /** A text button widget. See guiengine/engine.hpp for a detailed overview */ class ButtonWidget : public Widget { public: @@ -37,6 +38,8 @@ namespace GUIEngine virtual ~ButtonWidget() {} void add(); + + /** Change the label on the button */ void setLabel(const char* label); }; } diff --git a/src/guiengine/widgets/check_box_widget.cpp b/src/guiengine/widgets/check_box_widget.cpp index c2bb91007..163c4dc97 100644 --- a/src/guiengine/widgets/check_box_widget.cpp +++ b/src/guiengine/widgets/check_box_widget.cpp @@ -25,7 +25,7 @@ CheckBoxWidget::CheckBoxWidget() m_event_handler = this; m_type = WTYPE_CHECKBOX; } - +// ----------------------------------------------------------------------------- void CheckBoxWidget::add() { rect widget_size = rect(x, y, x + w, y + h); @@ -37,7 +37,7 @@ void CheckBoxWidget::add() m_element->setTabOrder(id); m_element->setTabGroup(false); } - +// ----------------------------------------------------------------------------- bool CheckBoxWidget::transmitEvent(Widget* w, std::string& originator) { /* toggle */ diff --git a/src/guiengine/widgets/check_box_widget.hpp b/src/guiengine/widgets/check_box_widget.hpp index 8cff8782d..fb7a02f1c 100644 --- a/src/guiengine/widgets/check_box_widget.hpp +++ b/src/guiengine/widgets/check_box_widget.hpp @@ -30,6 +30,7 @@ using namespace gui; namespace GUIEngine { + /** A checkbox widget. See guiengine/engine.hpp for a detailed overview */ class CheckBoxWidget : public Widget { bool m_state; @@ -40,8 +41,12 @@ namespace GUIEngine virtual ~CheckBoxWidget() {} void add(); + + /** Get whether the checkbox is checked */ bool getState() const { return m_state; } - void setState(const bool enabled) { m_state = enabled; } + + /** Set whether the checkbox is checked */ + void setState(const bool checked) { m_state = checked; } }; } diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index b5d710026..02a8f6827 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -30,6 +30,7 @@ IconButtonWidget::IconButtonWidget(const bool clickable) // ----------------------------------------------------------------------------- void IconButtonWidget::add() { + // ---- Icon ITexture* texture = GUIEngine::getDriver()->getTexture((file_manager->getDataDir() + "/" +m_properties[PROP_ICON]).c_str()); const int texture_w = texture->getSize().Width, texture_h = texture->getSize().Height; /* @@ -63,8 +64,10 @@ void IconButtonWidget::add() btn->setTabStop(false); btn->setScaleImage(true); } + + // ---- label if any stringw message = m_properties[PROP_TEXT].c_str(); - if(message.size() > 0) + if (message.size() > 0) { widget_size += position2d(0, widget_size.getHeight()); label = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), widget_size, false, false /* word wrap */, m_parent); @@ -72,6 +75,7 @@ void IconButtonWidget::add() label->setTabStop(false); } + // ---- IDs id = m_element->getID(); if(clickable) m_element->setTabOrder(id); m_element->setTabGroup(false); @@ -96,10 +100,10 @@ void IconButtonWidget::add() button->setSprite(EGBS_BUTTON_DOWN, sprite_bank->getSprites().size()-1); */ } - +// ----------------------------------------------------------------------------- void IconButtonWidget::setLabel(std::string new_label) { - if(label == NULL) return; + if (label == NULL) return; label->setText( stringw(new_label.c_str()).c_str() ); } diff --git a/src/guiengine/widgets/icon_button_widget.hpp b/src/guiengine/widgets/icon_button_widget.hpp index 55bdd631b..7206f1b10 100644 --- a/src/guiengine/widgets/icon_button_widget.hpp +++ b/src/guiengine/widgets/icon_button_widget.hpp @@ -30,6 +30,8 @@ using namespace gui; namespace GUIEngine { + /** A button widget with an icon and optionnaly a label beneath (from its properties in base class Widget) + See guiengine/engine.hpp for a detailed overview */ class IconButtonWidget : public Widget { bool clickable; @@ -39,6 +41,8 @@ namespace GUIEngine virtual ~IconButtonWidget() {} void add(); + + /** Change the text label if there is a label (label won't be added if there initially wasn't one) */ void setLabel(std::string new_label); }; } diff --git a/src/guiengine/widgets/label_widget.cpp b/src/guiengine/widgets/label_widget.cpp index a30b8d7c7..11384bc4e 100644 --- a/src/guiengine/widgets/label_widget.cpp +++ b/src/guiengine/widgets/label_widget.cpp @@ -23,7 +23,7 @@ LabelWidget::LabelWidget() { m_type = WTYPE_LABEL; } - +// ----------------------------------------------------------------------------- void LabelWidget::add() { rect widget_size = rect(x, y, x + w, y + h); @@ -44,7 +44,7 @@ void LabelWidget::add() m_element->setTabStop(false); m_element->setTabGroup(false); } - +// ----------------------------------------------------------------------------- void LabelWidget::setText(stringw newText) { IGUIStaticText* irrwidget = Widget::getIrrlichtElement(); diff --git a/src/guiengine/widgets/label_widget.hpp b/src/guiengine/widgets/label_widget.hpp index e871ec605..a87e5c785 100644 --- a/src/guiengine/widgets/label_widget.hpp +++ b/src/guiengine/widgets/label_widget.hpp @@ -30,6 +30,7 @@ using namespace gui; namespace GUIEngine { + /** A simple label widget. See guiengine/engine.hpp for a detailed overview. */ class LabelWidget : public Widget { public: @@ -37,6 +38,8 @@ namespace GUIEngine virtual ~LabelWidget() {} void add(); + + /** Change the text in the label */ void setText(stringw newText); }; } diff --git a/src/guiengine/widgets/list_widget.cpp b/src/guiengine/widgets/list_widget.cpp index f15d2843c..87ebb4c5a 100644 --- a/src/guiengine/widgets/list_widget.cpp +++ b/src/guiengine/widgets/list_widget.cpp @@ -23,13 +23,14 @@ ListWidget::ListWidget() { m_type = WTYPE_LIST; } +// ----------------------------------------------------------------------------- void ListWidget::add() { rect widget_size = rect(x, y, x + w, y + h); m_element = GUIEngine::getGUIEnv()->addListBox (widget_size, m_parent, getNewID()); } - +// ----------------------------------------------------------------------------- void ListWidget::clear() { IGUIListBox* list = getIrrlichtElement(); @@ -37,20 +38,21 @@ void ListWidget::clear() list->clear(); } - +// ----------------------------------------------------------------------------- void ListWidget::addItem(const char* item) { IGUIListBox* list = getIrrlichtElement(); assert(list != NULL); list->addItem( stringw(item).c_str() ); } - +// ----------------------------------------------------------------------------- int ListWidget::getSelection() const { const IGUIListBox* list = getIrrlichtElement(); assert(list != NULL); return list->getSelected(); } +// ----------------------------------------------------------------------------- std::string ListWidget::getSelectionName() const { const IGUIListBox* list = getIrrlichtElement(); diff --git a/src/guiengine/widgets/list_widget.hpp b/src/guiengine/widgets/list_widget.hpp index 068743e1f..4f0fd9709 100644 --- a/src/guiengine/widgets/list_widget.hpp +++ b/src/guiengine/widgets/list_widget.hpp @@ -30,6 +30,7 @@ using namespace gui; namespace GUIEngine { + /** A vertical list widget with text entries. See guiengine/engine.hpp for a detailed overview */ class ListWidget : public Widget { public: diff --git a/src/guiengine/widgets/model_view_widget.hpp b/src/guiengine/widgets/model_view_widget.hpp index ad8c9b81a..acc54f510 100644 --- a/src/guiengine/widgets/model_view_widget.hpp +++ b/src/guiengine/widgets/model_view_widget.hpp @@ -30,7 +30,7 @@ using namespace gui; namespace GUIEngine { - + /** A model view widget. See guiengine/engine.hpp for a detailed overview */ class ModelViewWidget : public Widget { diff --git a/src/guiengine/widgets/ribbon_grid_widget.cpp b/src/guiengine/widgets/ribbon_grid_widget.cpp index 3777a6cc6..1ad3b5503 100644 --- a/src/guiengine/widgets/ribbon_grid_widget.cpp +++ b/src/guiengine/widgets/ribbon_grid_widget.cpp @@ -43,7 +43,7 @@ RibbonGridWidget::RibbonGridWidget(const bool combo, const int max_rows) // ----------------------------------------------------------------------------- void RibbonGridWidget::add() { - m_has_label = m_properties[PROP_TEXT] == "bottom"; + m_has_label = (m_properties[PROP_TEXT] == "bottom"); m_label_height = m_has_label ? 25 : 0; // FIXME : get height from font, don't hardcode // ----- add dynamic label at bottom @@ -172,13 +172,18 @@ void RibbonGridWidget::setSubElements() } // add rows - for(int n=0; nm_reserved_id = m_ids[n]; ribbon->x = x + m_arrows_w; ribbon->y = y + (int)(n*row_height); @@ -374,6 +379,7 @@ bool RibbonGridWidget::mouseHovered(Widget* child) // ----------------------------------------------------------------------------- void RibbonGridWidget::focused() { + Widget::focused(); updateLabel(); const int listenerAmount = m_hover_listeners.size(); @@ -494,11 +500,11 @@ void RibbonGridWidget::updateItemDisplay() const int max_scroll = std::max(m_col_amount, m_needed_cols) - 1; - for(int n=0; n(&row.m_children[i]); assert(icon != NULL); @@ -510,7 +516,7 @@ void RibbonGridWidget::updateItemDisplay() icon_id = (col_scroll)*row_amount + n; - if( icon_id < item_amount ) + if (icon_id < item_amount) { std::string track_sshot = m_items[icon_id].m_sshot_file; button->setImage( GUIEngine::getDriver()->getTexture( track_sshot.c_str() )); diff --git a/src/guiengine/widgets/ribbon_grid_widget.hpp b/src/guiengine/widgets/ribbon_grid_widget.hpp index ad7362c43..4c35126a6 100644 --- a/src/guiengine/widgets/ribbon_grid_widget.hpp +++ b/src/guiengine/widgets/ribbon_grid_widget.hpp @@ -49,6 +49,8 @@ namespace GUIEngine std::string m_sshot_file; }; + /** A dynamic ribbon (builds upon RibbonWidget, adding dynamic contents creation and sizing, scrolling, multiple-row + layouts). See guiengine/engine.hpp for a detailed overview */ class RibbonGridWidget : public Widget { friend class RibbonWidget; @@ -57,10 +59,11 @@ namespace GUIEngine virtual ~RibbonGridWidget() {} - /** reference pointers only, the actual instances are owned by m_children */ + /** Reference pointers only, the actual instances are owned by m_children. Used to create mtultiple-row + ribbons (what appears to be a grid of icons is actually a vector of stacked basic ribbons) */ ptr_vector m_rows; - /** Used for ribbon grids that have a label */ + /** Used for ribbon grids that have a label at the bottom */ bool m_has_label; IGUIStaticText* m_label; int m_label_height; @@ -74,9 +77,10 @@ namespace GUIEngine /** Width of the scrolling arrows on each side */ int m_arrows_w; + /** Current scroll offset within items */ int m_scroll_offset; - int m_needed_cols; + /** Width and height of children as declared in the GUI file */ int m_child_width, m_child_height; /** Number of rows and columns. Number of columns can dynamically change, number of row is @@ -84,7 +88,18 @@ namespace GUIEngine int m_row_amount; int m_col_amount; + /** The total number of columns given item count and row count (even counting not visible with current scrolling) */ + int m_needed_cols; + + /** The maximum number of rows, as passed to the constructor */ int m_max_rows; + + /** irrlicht relies on consecutive IDs to perform keyboard navigation between widgets. However, since this + widget is dynamic, irrlicht widgets are not created as early as all others, so by the time we're ready + to create the full contents of this widget, the ID generator is already incremented, thus messing up + keyboard navigation. To work around this, at the same time all other widgets are created, I gather a + number of IDs (the number of rows) and store them here. Then, when we're finally ready to create the + contents dynamically, we can re-use these IDs and get correct navigation order. */ std::vector m_ids; /** Whether this is a "combo" style ribbon grid widget */ @@ -94,7 +109,10 @@ namespace GUIEngine Widget* m_left_widget; Widget* m_right_widget; + /** Returns the currently selected row */ RibbonWidget* getSelectedRibbon() const; + + /** Returns the row */ RibbonWidget* getRowContaining(Widget* w) const; /** Updates the visible label to match the currently selected item */ @@ -114,35 +132,48 @@ namespace GUIEngine /** Removes all previously added contents icons, and re-adds them (calculating the new amount) */ void setSubElements(); + /** Call this to scroll within a scrollable ribbon */ void scroll(const int x_delta); /** Used for combo ribbons, to contain the ID of the currently selected item */ int m_selected_item; + /** Callbacks */ + void onRowChange(RibbonWidget* row); + void add(); + bool mouseHovered(Widget* child); + public: RibbonGridWidget(const bool combo=false, const int max_rows=4); + /** Register a listener to be notified of selection changes within the ribbon */ void registerHoverListener(RibbonGridHoverListener* listener); - void add(); - /** Called when right key is pressed */ bool rightPressed(); /** Called when left key is pressed */ bool leftPressed(); + /** Dynamically add an item to the ribbon's list of items (will not be visible until you + call 'updateItemDisplay' or 'add') */ void addItem( std::string user_name, std::string code_name, std::string image_file ); + /** Updates icons/labels given current items and scrolling offset, taking care of resizing + the dynamic ribbon if the number of items changed */ void updateItemDisplay(); - bool mouseHovered(Widget* child); - void onRowChange(RibbonWidget* row); - + /** Get the internal name (ID) of the selected item */ const std::string& getSelectionIDString(); + + /** Get the user-visible text of the selected item */ const std::string& getSelectionText(); + /** Select an item from its numerical ID. Only for [1-row] combo ribbons. + ID ranges from {0} to {number of items added through 'addItem' - 1} */ void setSelection(int item_id); + + /** Select an item from its internal name */ void setSelection(const std::string& code_name); }; diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index 2c62fc062..a1a94ea29 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -26,14 +26,14 @@ using namespace GUIEngine; # define round(x) (floor(x+0.5f)) #endif -RibbonWidget::RibbonWidget(const RibbonType type, int id) +// ----------------------------------------------------------------------------- +RibbonWidget::RibbonWidget(const RibbonType type) { m_selection = 0; m_ribbon_type = type; m_focus = NULL; updateSelection(); m_type = WTYPE_RIBBON; - m_given_id = id; } // ----------------------------------------------------------------------------- void RibbonWidget::add() @@ -43,7 +43,7 @@ void RibbonWidget::add() rect widget_size = rect(x, y, x + w, y + h); - int id = (m_given_id == -1 ? getNewID() : m_given_id); + int id = (m_reserved_id == -1 ? getNewID() : m_reserved_id); IGUIButton * btn = GUIEngine::getGUIEnv()->addButton(widget_size, m_parent, id, L""); m_element = btn; @@ -250,11 +250,14 @@ bool RibbonWidget::leftPressed() // ----------------------------------------------------------------------------- void RibbonWidget::focused() { - if(m_focus == NULL) m_focus = m_children.get(m_selection); + Widget::focused(); - if(m_event_handler != NULL) + if (m_focus == NULL) m_focus = m_children.get(m_selection); + + if (m_event_handler != NULL) { GUIEngine::getGUIEnv()->setFocus(m_focus->m_element); + // FIXME : unclean, children ribbons shouldn't need to know about their parent ((RibbonGridWidget*)m_event_handler)->onRowChange( this ); } } @@ -265,12 +268,12 @@ bool RibbonWidget::mouseHovered(Widget* child) m_focus = child; - for(int i=0; isetFocus(m_element); return true; } - +// ----------------------------------------------------------------------------- void RibbonWidget::setLabel(const int id, std::string new_name) { - if(m_labels.size() == 0) return; // ignore this call for ribbons without labels + if (m_labels.size() == 0) return; // ignore this call for ribbons without labels assert(id >= 0); assert(id < m_labels.size()); diff --git a/src/guiengine/widgets/ribbon_widget.hpp b/src/guiengine/widgets/ribbon_widget.hpp index 9bbf43aaa..7c686b54e 100644 --- a/src/guiengine/widgets/ribbon_widget.hpp +++ b/src/guiengine/widgets/ribbon_widget.hpp @@ -38,40 +38,64 @@ namespace GUIEngine RIBBON_TABS /* a tab bar */ }; + /** A static text/icons/tabs bar widget. The contents of this ribbon are static. + See guiengine/engine.hpp for a detailed overview */ class RibbonWidget : public Widget { friend class RibbonGridWidget; friend class EventHandler; int m_selection; - RibbonType m_ribbon_type; - int m_given_id; + /** The type of this ribbon (toolbar, combo, tabs) */ + RibbonType m_ribbon_type; void add(); + /** Each item within the ribbon holds a flag saying whether it is selected or not. + This method updates the flag in all of this ribbon's children. Called everytime + selection changes.*/ + void updateSelection(); + + /** Callbacks */ bool rightPressed(); bool leftPressed(); bool mouseHovered(Widget* child); - - void updateSelection(); bool transmitEvent(Widget* w, std::string& originator); void focused(); ptr_vector m_labels; + public: + + /** Contains which element within the ribbon is currently focused (used by the skin) */ Widget* m_focus; - RibbonWidget(const RibbonType type=RIBBON_COMBO, int id=-1); + RibbonWidget(const RibbonType type=RIBBON_COMBO); virtual ~RibbonWidget() {} + /** Returns the numerical ID of the selected item within the ribbon */ int getSelection() const { return m_selection; } + + /** Returns the string ID (internal name) of the selection */ + const std::string& getSelectionIDString() { return m_children[m_selection].m_properties[PROP_ID]; } + + /** Returns the user-visible text of the selection */ + const std::string& getSelectionText() { return m_children[m_selection].m_properties[PROP_TEXT]; } + + /** Returns the type of this ribbon (see guiengine/engine.hpp for detaield descriptions) */ + RibbonType getRibbonType() const { return m_ribbon_type; } + + /** Sets the ID of the selected item within the ribbon */ void setSelection(const int i) { m_selection = i; updateSelection(); } + + /** Select an item in the ribbon by its internal name */ void select(std::string item); - RibbonType getRibbonType() const { return m_ribbon_type; } - const std::string& getSelectionIDString() { return m_children[m_selection].m_properties[PROP_ID]; } - const std::string& getSelectionText() { return m_children[m_selection].m_properties[PROP_TEXT]; } + /** When each item has a label, this method can be used to rename an item + (especially used in scrolling ribbons, when scrolling occurs by renaming + items - note that this statis ribbon doesn't support scrolling, only + superclasses/wrappers of this do.) */ void setLabel(const int id, std::string new_name); }; diff --git a/src/guiengine/widgets/spinner_widget.cpp b/src/guiengine/widgets/spinner_widget.cpp index 3eda910bf..2f7dc0d13 100644 --- a/src/guiengine/widgets/spinner_widget.cpp +++ b/src/guiengine/widgets/spinner_widget.cpp @@ -25,12 +25,13 @@ #include "utils/translation.hpp" using namespace GUIEngine; +// ----------------------------------------------------------------------------- SpinnerWidget::SpinnerWidget(const bool gauge) { m_gauge = gauge; m_type = WTYPE_SPINNER; } - +// ----------------------------------------------------------------------------- void SpinnerWidget::add() { // retrieve min and max values @@ -142,7 +143,7 @@ void SpinnerWidget::add() m_children[2].m_properties[PROP_ID] = "right"; m_children[2].id = m_children[2].m_element->getID(); } - +// ----------------------------------------------------------------------------- void SpinnerWidget::move(const int x, const int y, const int w, const int h) { Widget::move(x, y, w, h); diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index b05b07a09..964be9f25 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -30,6 +30,7 @@ using namespace gui; namespace GUIEngine { + /** A spinner or gauge widget (to select numbers / percentages). See guiengine/engine.hpp for a detailed overview */ class SpinnerWidget : public Widget { int m_value, m_min, m_max; diff --git a/src/guiengine/widgets/text_box_widget.hpp b/src/guiengine/widgets/text_box_widget.hpp index ab58c108a..380f85088 100644 --- a/src/guiengine/widgets/text_box_widget.hpp +++ b/src/guiengine/widgets/text_box_widget.hpp @@ -30,6 +30,7 @@ using namespace gui; namespace GUIEngine { + /** A text field widget. See guiengine/engine.hpp for a detailed overview */ class TextBoxWidget : public Widget { public: