1 // -*- C++ -*- 2 /* GG is a GUI for OpenGL. 3 Copyright (C) 2003-2008 T. Zachary Laine 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public License 7 as published by the Free Software Foundation; either version 2.1 8 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free 17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 02111-1307 USA 19 20 If you do not wish to comply with the terms of the LGPL please 21 contact the author as other terms are available for a fee. 22 23 Zach Laine 24 whatwasthataddress@gmail.com */ 25 26 /** \file Button.h \brief Contains the Button push-button control class; the 27 StateButton control class, which represents check boxes and radio buttons; 28 and the RadioButtonGroup control class, which allows multiple radio 29 buttons to be combined into a single control. */ 30 31 #ifndef _GG_Button_h_ 32 #define _GG_Button_h_ 33 34 #include <GG/ClrConstants.h> 35 #include <GG/TextControl.h> 36 #include <GG/Enum.h> 37 38 #include <boost/signals2/signal.hpp> 39 40 41 namespace GG { 42 43 /** \brief This is a basic button control. 44 45 Has three states: BN_UNPRESSED, BN_PRESSED, and BN_ROLLOVER. BN_ROLLOVER 46 is when the cursor "rolls over" the button, without depressing it, 47 allowing rollover effects on the button. To create a bitmap button, 48 simply set the unpressed, pressed, and/or rollover graphics to the desired 49 SubTextures. \see GG::SubTexture */ 50 class GG_API Button : public Control 51 { 52 public: 53 /// the states of being for a GG::Button 54 GG_CLASS_ENUM(ButtonState, 55 BN_PRESSED, ///< The button is being pressed by the user, and the cursor is over the button 56 BN_UNPRESSED, ///< The button is unpressed 57 BN_ROLLOVER ///< The button has the cursor over it, but is unpressed 58 ) 59 60 /** \name Signal Types */ ///@{ 61 /** Emitted when the button is clicked by the user */ 62 typedef boost::signals2::signal<void ()> ClickedSignalType; 63 //@} 64 65 /** \name Structors */ ///@{ 66 Button(const std::string& str, const std::shared_ptr<Font>& font, Clr color, 67 Clr text_color = CLR_BLACK, Flags<WndFlag> flags = INTERACTIVE); 68 //@} 69 void CompleteConstruction() override; 70 71 /** \name Accessors */ ///@{ 72 Pt MinUsableSize() const override; 73 74 /** Returns button state \see ButtonState */ 75 ButtonState State() const; 76 77 const std::string& Text() const; ///< Returns the label to be used as the button label 78 const SubTexture& UnpressedGraphic() const; ///< Returns the SubTexture to be used as the image of the button when unpressed 79 const SubTexture& PressedGraphic() const; ///< Returns the SubTexture to be used as the image of the button when pressed 80 const SubTexture& RolloverGraphic() const; ///< Returns the SubTexture to be used as the image of the button when it contains the cursor, but is not pressed 81 82 /** The left clicked signal object for this Button */ 83 mutable ClickedSignalType LeftClickedSignal; 84 /** The right clicked signal object for this Button */ 85 mutable ClickedSignalType RightClickedSignal; 86 /** The left pressed signal object for this Button */ 87 mutable ClickedSignalType LeftPressedSignal; 88 /** The right pressed signal object for this Button */ 89 mutable ClickedSignalType RightPressedSignal; 90 //@} 91 92 /** \name Mutators */ ///@{ 93 void Show() override; 94 void Render() override; 95 void SizeMove(const Pt& ul, const Pt& lr) override; 96 97 /** Sets the control's color; does not affect the text color. */ 98 void SetColor(Clr c) override; 99 100 /** Sets button state programmatically \see ButtonState */ 101 void SetState(ButtonState state); 102 103 void SetText(const std::string& text); ///< Sets the text to be used as the button label 104 void SetUnpressedGraphic(const SubTexture& st); ///< Sets the SubTexture to be used as the image of the button when unpressed 105 void SetPressedGraphic(const SubTexture& st); ///< Sets the SubTexture to be used as the image of the button when pressed 106 void SetRolloverGraphic(const SubTexture& st); ///< Sets the SubTexture to be used as the image of the button when it contains the cursor, but is not pressed 107 //@} 108 109 protected: 110 /** \name Mutators */ ///@{ 111 void LButtonDown(const Pt& pt, Flags<ModKey> mod_keys) override; 112 void LDrag(const Pt& pt, const Pt& move, Flags<ModKey> mod_keys) override; 113 void LButtonUp(const Pt& pt, Flags<ModKey> mod_keys) override; 114 void LClick(const Pt& pt, Flags<ModKey> mod_keys) override; 115 void RButtonDown(const Pt& pt, Flags<ModKey> mod_keys) override; 116 void RDrag(const Pt& pt, const Pt& move, Flags<ModKey> mod_keys) override; 117 void RButtonUp(const Pt& pt, Flags<ModKey> mod_keys) override; 118 void RClick(const Pt& pt, Flags<ModKey> mod_keys) override; 119 void MouseEnter(const Pt& pt, Flags<ModKey> mod_keys) override; 120 void MouseHere(const Pt& pt, Flags<ModKey> mod_keys) override; 121 void MouseLeave() override; 122 123 /** Draws the button unpressed. If an unpressed graphic has been supplied, it is used. */ 124 virtual void RenderUnpressed(); 125 /** Draws the button pressed. If an pressed graphic has been supplied, it is used. */ 126 virtual void RenderPressed(); 127 /** Draws the button rolled-over. If an rollover graphic has been supplied, it is used. */ 128 virtual void RenderRollover(); 129 //@} 130 131 std::shared_ptr<TextControl> m_label; ///< Label used to display text 132 133 private: 134 void RenderDefault(); ///< This just draws the default unadorned square-and-rectangle button 135 136 ButtonState m_state; ///< Button is always in exactly one of the ButtonState states above 137 SubTexture m_unpressed_graphic; ///< Graphic used to display button when it's unpressed 138 SubTexture m_pressed_graphic; ///< Graphic used to display button when it's depressed 139 SubTexture m_rollover_graphic; ///< Graphic used to display button when it's under the mouse and not pressed 140 }; 141 142 143 class StateButtonRepresenter; 144 145 146 /** \brief This is a basic state button control. 147 148 This class is for checkboxes and radio buttons, etc. The button/checkbox 149 area is determined from the text height and format; the button height and 150 width will be the text height, and the the button will be positioned to 151 the left of the text and vertically the same as the text, unless the text 152 is centered, in which case the button and text will be centered, and the 153 button will appear above or below the text. Whenever there is not room to 154 place the button and the text in the proper orientation because the entire 155 control's size is too small, the button and text are positioned in their 156 default spots (button on left, text on right, centered vertically). */ 157 class GG_API StateButton : public Control 158 { 159 public: 160 /// the states of being for a GG::Button 161 GG_CLASS_ENUM(ButtonState, 162 BN_PRESSED, ///< The button is being pressed by the user, and the cursor is over the button 163 BN_UNPRESSED, ///< The button is unpressed 164 BN_ROLLOVER ///< The button has the cursor over it, but is unpressed 165 ) 166 167 /** \name Signal Types */ ///@{ 168 /** Emitted when the StateButton is checked or unchecked; the checked or 169 unchecked status is indicated by the bool parameter */ 170 typedef boost::signals2::signal<void (bool)> CheckedSignalType; 171 //@} 172 173 /** \name Structors */ ///@{ 174 StateButton(const std::string& str, const std::shared_ptr<Font>& font, Flags<TextFormat> format, 175 Clr color, std::shared_ptr<StateButtonRepresenter> representer, Clr text_color = CLR_BLACK); ///< Ctor 176 //@} 177 void CompleteConstruction() override; 178 179 /** \name Accessors */ ///@{ 180 Pt MinUsableSize() const override; 181 182 /** Returns button state \see ButtonState */ 183 ButtonState State() const; 184 185 const std::string& Text() const; ///< Returns the label to be used as the button label 186 187 bool Checked() const; ///< Returns true if button is checked 188 189 TextControl* GetLabel() const; 190 191 mutable CheckedSignalType CheckedSignal; ///< The checked signal object for this StaticButton 192 //@} 193 194 /** \name Mutators */ ///@{ 195 void Show() override; 196 void Render() override; 197 void SizeMove(const Pt& ul, const Pt& lr) override; 198 199 void Reset(); ///< Unchecks button 200 void SetCheck(bool b = true); ///< (Un)checks button 201 void SetTextColor(Clr c); ///< Sets the color of the box label text 202 //@} 203 204 protected: 205 /** \name Mutators */ ///@{ 206 void LButtonDown(const Pt& pt, Flags<ModKey> mod_keys) override; 207 void LDrag(const Pt& pt, const Pt& move, Flags<ModKey> mod_keys) override; 208 void LButtonUp(const Pt& pt, Flags<ModKey> mod_keys) override; 209 void LClick(const Pt& pt, Flags<ModKey> mod_keys) override; 210 void MouseHere(const Pt& pt, Flags<ModKey> mod_keys) override; 211 void MouseLeave() override; 212 213 /** Sets button state programmatically \see ButtonState */ 214 void SetState(ButtonState next_state); 215 //@} 216 217 private: 218 std::shared_ptr<StateButtonRepresenter> m_representer; 219 std::shared_ptr<TextControl> m_label; ///< Label used to display text 220 ButtonState m_state; ///< Button is always in exactly one of the ButtonState states above 221 bool m_checked; ///< true when this button in a checked, active state 222 }; 223 224 225 /** \brief Visual representation of a state button. 226 227 The StateButtonRepresenter is a stub interface to implement a visual 228 representation of a StateButton instance. A representer can be shared 229 amongst multiple instances of a StateButton, so no subclass should 230 store instance specific attributes of a state button. 231 */ 232 class GG_API StateButtonRepresenter 233 { 234 public: 235 /** \brief Render the given state button according to its state. 236 237 \param button The StateButton instance to render. 238 */ 239 virtual void Render(const StateButton& button) const; 240 241 /** \brief Respong to a button state change. 242 243 This method is called whenever a Button chanes its state. 244 245 \param button The button that changed its state and is in the most 246 recent state. 247 \param previous_state The previous button state. 248 */ 249 virtual void OnChanged(const StateButton& button, StateButton::ButtonState previous_state) const; 250 251 /** \brief Respond to a state button change. 252 253 This method is called whenever a StateButton changes its 254 state. 255 256 \param checked True if the state button was checked, False 257 if not. 258 */ 259 virtual void OnChecked(bool checked) const; 260 261 /** \brief Return the minimum size required for a usable representation 262 263 \param button The state button to calculate the minimum size of. 264 \return The minimum size to create a usable representation of the 265 given state button. 266 */ 267 virtual Pt MinUsableSize(const StateButton& button) const; 268 269 protected: 270 /** \brief Calculate the layout of text and button component. 271 272 \param button The StateButton instance to layout. 273 \param button_ul[out] The upper left corner of the visual 274 button. 275 \param button_lr[out] The lower right corner of the visual 276 button. 277 \param text_ul[out] The upper left corner of the button 278 label. 279 */ 280 virtual void DoLayout(const GG::StateButton& button, Pt& button_ul, Pt& button_lr, Pt& text_ul) const; 281 }; 282 283 284 /** \brief Builtin representation of a check box state button. */ 285 class GG_API BeveledCheckBoxRepresenter: public StateButtonRepresenter 286 { 287 public: 288 explicit BeveledCheckBoxRepresenter(Clr int_color = CLR_ZERO); 289 290 void Render(const StateButton& button) const override; 291 292 private: 293 Clr m_int_color; 294 }; 295 296 297 /** \brief Builtin representation of a radio state button. */ 298 class GG_API BeveledRadioRepresenter: public StateButtonRepresenter 299 { 300 public: 301 explicit BeveledRadioRepresenter(Clr int_color = CLR_ZERO); 302 303 void Render(const StateButton& button) const override; 304 305 private: 306 Clr m_int_color; 307 }; 308 309 310 /** \brief Builtin representation of a tab state button (part of the TabWnd). */ 311 class GG_API BeveledTabRepresenter: public StateButtonRepresenter 312 { 313 public: 314 void Render(const StateButton& button) const override; 315 316 Pt MinUsableSize(const StateButton& button) const override; 317 }; 318 319 320 /** \brief This is a class that encapsulates multiple GG::StateButtons into a 321 single radio-button control. 322 323 RadioButtonGroup emits a signal whenever its currently-checked button 324 changes. The signal indicates which button has been pressed, by passing 325 the index of the button; the currently-checked button index is NO_BUTTON 326 when no button is checked. Any StateButton-derived controls can be used 327 in a RadioButtonGroup. */ 328 class GG_API RadioButtonGroup : public Control 329 { 330 public: 331 /** \name Signal Types */ ///@{ 332 /** emitted when the currently-selected button has changed; the new 333 selected button's index in the group is provided (this may be 334 NO_BUTTON if no button is currently selected) */ 335 typedef boost::signals2::signal<void (std::size_t)> ButtonChangedSignalType; 336 //@} 337 338 /** \name Structors */ ///@{ 339 RadioButtonGroup(Orientation orientation); 340 //@} 341 342 /** \name Accessors */ ///@{ 343 Pt MinUsableSize() const override; 344 345 /** Returns the orientation of the buttons in the group */ 346 Orientation GetOrientation() const; 347 348 /** Returns true iff NumButtons() == 0 */ 349 bool Empty() const; 350 351 /** Returns the number of buttons in this control */ 352 std::size_t NumButtons() const; 353 354 /** Returns the index of the currently checked button, or NO_BUTTON if 355 none are checked */ 356 std::size_t CheckedButton() const; 357 358 /** Returns true iff the buttons in the group are to be expanded to fill 359 the group's available space. If false, this indicates that the 360 buttons are to be spaced out evenly, and that they should all be their 361 MinUsableSize()s. */ 362 bool ExpandButtons() const; 363 364 /** Returns true iff the buttons in the group are to be expanded in 365 proportion to their initial sizes. If false, this indicates that the 366 buttons are to be expanded evenly. Note that this has no effect if 367 ExpandButtons() is false. */ 368 bool ExpandButtonsProportionally() const; 369 370 /** Returns true iff this button group will render an outline of itself; 371 this is sometimes useful for debugging purposes */ 372 bool RenderOutline() const; 373 374 mutable ButtonChangedSignalType ButtonChangedSignal; ///< The button changed signal object for this RadioButtonGroup 375 //@} 376 377 /** \name Mutators */ ///@{ 378 void Render() override; 379 380 /** Checks the index-th button, and unchecks all others. If there is no 381 index-th button, they are all unchecked, and the currently-checked 382 button index is set to NO_BUTTON. */ 383 void SetCheck(std::size_t index); 384 385 /** Disables (with b == true) or enables (with b == false) the index-th 386 button, if it exists. If the button exists, is being disabled, and is 387 the one currently checked, the currently-checked button index is set 388 to NO_BUTTON. */ 389 void DisableButton(std::size_t index, bool b = true); 390 391 /** Adds a button to the end of the group. The button group owns \p bn.*/ 392 void AddButton(std::shared_ptr<StateButton> bn); 393 394 /** Adds a button to the group at position \a index. \a index must be in 395 the range [0, NumButtons()]. The button group owns \p bn.*/ 396 void InsertButton(std::size_t index, std::shared_ptr<StateButton> bn); 397 398 /** Removes \a button from the group. If \a button is at index i, and is 399 the currently-checked button, the currently-checked button index is 400 set to NO_BUTTON. If the currently-checked button is after i, the 401 currently-checked button index will be decremented. In either case, a 402 ButtonChangedSignal will be emitted. Note that this causes the layout 403 to relinquish responsibility for \a wnd's memory management. */ 404 void RemoveButton(StateButton* button); 405 406 /** Set this to true if the buttons in the group are to be expanded to 407 fill the group's available space. If set to false, the buttons are to 408 be spaced out evenly, and they will all be at least their 409 MinUsableSize()s. */ 410 void ExpandButtons(bool expand); 411 412 /** Set this to true if the buttons in the group are to be expanded in 413 proportion to their initial sizes. If set to false, this indicates 414 that the buttons are to be expanded evenly. Note that this has no 415 effect if ExpandButtons() is false. */ 416 void ExpandButtonsProportionally(bool proportional); 417 418 /** Set this to true if this button group should render an outline of 419 itself; this is sometimes useful for debugging purposes */ 420 void RenderOutline(bool render_outline); 421 422 /** Raises the currently-selected button to the top of the child z-order. 423 If there is no currently-selected button, no action is taken. */ 424 void RaiseCheckedButton(); 425 426 /** The invalid button position index that there is no currently-checked 427 button. */ 428 static const std::size_t NO_BUTTON; 429 //@} 430 431 protected: 432 /** \brief Encapsulates all data pertaining ot a single button in a 433 RadioButtonGroup. */ 434 struct GG_API ButtonSlot 435 { 436 ButtonSlot(std::shared_ptr<StateButton>& button_); 437 438 std::shared_ptr<StateButton> button; 439 440 boost::signals2::connection connection; 441 }; 442 443 /** \name Accessors */ ///@{ 444 const std::vector<ButtonSlot>& ButtonSlots() const; ///< returns the state buttons in the group 445 //@} 446 447 private: 448 void ConnectSignals(); 449 void SetCheckImpl(std::size_t index, bool signal); 450 void Reconnect(); 451 452 const Orientation m_orientation; 453 std::vector<ButtonSlot> m_button_slots; 454 std::size_t m_checked_button; ///< the index of the currently-checked button; NO_BUTTON if none is clicked 455 bool m_expand_buttons; 456 bool m_expand_buttons_proportionally; 457 bool m_render_outline; 458 }; 459 460 } // namespace GG 461 462 #endif 463