1 //  SuperTuxKart - a fun racing game with go-kart
2 //  Copyright (C) 2009-2015 Marianne Gagnon
3 //
4 //  This program is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU General Public License
6 //  as published by the Free Software Foundation; either version 3
7 //  of the License, or (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 
18 
19 
20 #ifndef HEADER_RIBBON_HPP
21 #define HEADER_RIBBON_HPP
22 
23 #include <irrString.h>
24 
25 #include "guiengine/widget.hpp"
26 #include "guiengine/widgets/icon_button_widget.hpp"
27 #include "utils/cpp2011.hpp"
28 #include "utils/leak_check.hpp"
29 #include "utils/ptr_vector.hpp"
30 
31 #include <IGUIStaticText.h>
32 
33 namespace GUIEngine
34 {
35     /** Types of ribbons */
36     enum RibbonType
37     {
38         RIBBON_COMBO,   //!< select one item out of many, like in a combo box
39         RIBBON_TOOLBAR, //!< a row of individual buttons
40         RIBBON_TABS,    //!< a tab bar
41         RIBBON_VERTICAL_TABS //!< a vertical tab bar
42     };
43 
44     /** Filp directions of ribbons */
45     enum RibbonFlip
46     {
47         FLIP_NO, // For non-tab ribbons
48         FLIP_UP_LEFT, // For horizontal tabs it goes up vertical ones it goes left
49         FLIP_DOWN_RIGHT // For horizontal tabs it goes down vertical ones it goes right
50     };
51 
52     /** \brief A static text/icons/tabs bar widget.
53       * The contents of this ribbon are static.
54       * \ingroup widgetsgroup
55       * \note items you add to a list are kept after the the ribbon was in
56       *       is removed (i.e. you don't need to add items everytime the
57       *       screen is shown, only upon loading)
58       */
59     class RibbonWidget : public Widget
60     {
61     public:
62         class IRibbonListener
63         {
64         public:
~IRibbonListener()65             virtual ~IRibbonListener(){}
66             virtual void onRibbonWidgetScroll(const int delta_x) = 0;
67             virtual void onRibbonWidgetFocus(RibbonWidget* emitter,
68                                              const int playerID) = 0;
69             virtual void onSelectionChange() = 0;
70         };
71 
72     private:
73         friend class DynamicRibbonWidget;
74         friend class EventHandler;
75 
76         int m_selection[MAX_PLAYER_COUNT];
77 
78         /** The type of this ribbon (toolbar, combo, tabs, vertical tabs) */
79         RibbonType m_ribbon_type;
80 
81         /** The flip direction of this ribbon */
82         RibbonFlip m_ribbon_flip;
83 
84         /** Each item within the ribbon holds a flag saying whether it is
85          *  selected or not. This method updates the flag in all of this
86          *  ribbon's children. Called everytime selection changes.*/
87         void updateSelection();
88 
89         /** Callbacks */
90         virtual EventPropagation rightPressed(const int playerID=0) OVERRIDE;
91         virtual EventPropagation leftPressed (const int playerID=0) OVERRIDE;
92         virtual EventPropagation upPressed   (const int playerID=0) OVERRIDE;
93         virtual EventPropagation downPressed (const int playerID=0) OVERRIDE;
94         EventPropagation moveToNextItem(const bool horizontally, const bool reverse, const int playerID);
95         EventPropagation propagationType(const bool horizontally);
96         void selectNextActiveWidget(const bool horizontally, const bool reverse,
97                                     const int playerID, const int old_selection);
98         virtual EventPropagation mouseHovered(Widget* child,
99                                               const int playerID) OVERRIDE;
100         virtual EventPropagation transmitEvent(Widget* w,
101                                                const std::string& originator,
102                                                const int playerID=0) OVERRIDE;
103         virtual EventPropagation focused(const int playerID) OVERRIDE;
104         virtual void unfocused(const int playerID, Widget* new_focus) OVERRIDE;
105 
106         virtual EventPropagation onClick() OVERRIDE;
107 
108         PtrVector<irr::gui::IGUIStaticText, REF> m_labels;
109 
110         IRibbonListener* m_listener;
111         PtrVector<Widget> m_active_children;
112 
113     public:
114 
115         LEAK_CHECK()
116 
117         /** Internal identifier of filler items that are added in a ribbon
118          *  widget to filllines when the number of items cannot be divided
119          *  by the number of rows in the grid (mostly used by dynamic ribbon
120          *  widgets, but the base ribbon needs to know about filler items)
121          */
122         static const char NO_ITEM_ID[];
123 
124         /** Contains which element within the ribbon is currently focused by
125          *  player 0 (used by the skin to show mouse hovers over items that
126          *  are not selected). Only used for COMBO and TAB ribbons. */
127         Widget* m_mouse_focus;
128 
129         RibbonWidget(const RibbonType type=RIBBON_COMBO);
130         virtual ~RibbonWidget();
131 
132         virtual void add() OVERRIDE;
133 
134         /** Sets a listener that will be notified of changes on this ribbon.
135          *  Does _not_ take ownership of the listener, i.e. will not delete it.
136          *  You may call this with the listener parameter set to NULL to
137          *  remove the listener. */
setListener(IRibbonListener * listener)138         void setListener(IRibbonListener* listener) { m_listener = listener; }
139         // --------------------------------------------------------------------
140         /** Returns the type of this ribbon (see the GUI module overview page
141          *  for detailed descriptions) */
getRibbonType() const142         RibbonType getRibbonType() const { return m_ribbon_type; }
143         // --------------------------------------------------------------------
144         /** Returns the flip direction of thin ribbon */
getRibbonFlip() const145         RibbonFlip getRibbonFlip() const { return m_ribbon_flip; }
146         // --------------------------------------------------------------------
147         /** Returns the number of active items within the ribbon */
getActiveChildrenNumber(const int playerID) const148         int getActiveChildrenNumber(const int playerID) const
149                                               { return m_active_children.size(); }
150         // --------------------------------------------------------------------
151         /** Returns the numerical ID of the selected item within the ribbon */
getSelection(const int playerID) const152         int getSelection(const int playerID) const
153                                               { return m_selection[playerID]; }
154         // --------------------------------------------------------------------
155         /** Returns the string ID (internal name) of the selection */
156         const std::string& getSelectionIDString(const int playerID);
157         // --------------------------------------------------------------------
158         /** Returns the user-visible text of the selection */
getSelectionText(const int playerID)159         irr::core::stringw getSelectionText(const int playerID)
160         {
161             const int selection = m_selection[playerID];
162             if (selection < 0 || selection >= int(m_children.size())) return "";
163             return m_children[selection].m_text;
164         }
165         // --------------------------------------------------------------------
166 
167         /** Sets the ID of the selected item within the ribbon */
setSelection(const int i,const int playerID)168         void setSelection(const int i, const int playerID)
169                              { m_selection[playerID] = i; updateSelection(); }
170 
171         /** Select an item in the ribbon by its internal name */
172         void select(std::string item, const int playerID);
173 
174         /**
175           * \brief This method can be used to rename an item.
176           * Has no effect for ribbons without individual labels.
177           *
178           * \pre Must be called after the ribbon was add()ed
179           * \param id The index of the item to rename, in range [0 .. item count - 1]
180           */
181         void setLabel(const unsigned int id, irr::core::stringw new_name);
182 
183         void setItemVisible(const unsigned int id, bool visible);
184 
185         void setFlip(RibbonFlip direction);
186 
187         /** Returns the ID of the item, or -1 if not found */
188         int findItemNamed(const char* internalName);
189 
190         /** Returns the the widget, or NULL if not found */
191         GUIEngine::Widget * findWidgetNamed(const char* interalName);
192 
193         /** \brief Dynamically (at runtime) add a text item to this ribbon
194           * \pre This must be called before RibbonWidget::add, while the
195           *      widget is not yet displayed
196           * \pre only valid for ribbons that take text-only contents
197           *       (e.g. tab bars)
198           */
199         void addTextChild(const core::stringw& text, const std::string &id);
200 
201 
202         /** \brief Dynamically (at runtime) add an icon item to this ribbon.
203          *  \pre this must be called before RibbonWidget::add, while the widget
204          *       is not yet displayed
205          *  \pre only valid for ribbons that take icon contents
206          */
207         void addIconChild(const core::stringw& text, const std::string &id,
208                           const int w, const int h, const std::string &icon,
209                           const IconButtonWidget::IconPathType iconPathType=
210                                     IconButtonWidget::ICON_PATH_TYPE_RELATIVE);
211 
212         /**
213           * \brief clear all children of this ribbon (likely because new ones will be added soon after)
214           * \pre this must be called before RibbonWidget::add, while the widget is not yet displayed
215           */
216         void clearAllChildren();
217 
218         /**
219          * \brief clear one child from this ribbon
220          * \pre this must be called before RibbonWidget::add, while the widget is not yet displayed
221          */
222         void removeChildNamed(const char* name);
223 
getRibbonChildren()224         PtrVector<Widget>& getRibbonChildren() { return m_children; }
225 
226         virtual EventPropagation onActivationInput(const int playerID) OVERRIDE;
227     };
228 
229 }
230 
231 #endif
232