1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #pragma once
6 
7 #include "IrrCompileConfig.h"
8 
9 #include <IGUIStaticText.h>
10 #include "irrlicht_changes/static_text.h"
11 #include "IGUIButton.h"
12 #include "IGUISpriteBank.h"
13 #include "ITexture.h"
14 #include "SColor.h"
15 #include "guiSkin.h"
16 #include "StyleSpec.h"
17 
18 using namespace irr;
19 
20 #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8)
21 	namespace irr { namespace gui {
22 
23 		//! State of buttons used for drawing texture images.
24 		//! Note that only a single state is active at a time
25 		//! Also when no image is defined for a state it will use images from another state
26 		//! and if that state is not set from the replacement for that,etc.
27 		//! So in many cases setting EGBIS_IMAGE_UP and EGBIS_IMAGE_DOWN is sufficient.
28 		enum EGUI_BUTTON_IMAGE_STATE {
29 			//! When no other states have images they will all use this one.
30 					EGBIS_IMAGE_UP,
31 			//! When not set EGBIS_IMAGE_UP is used.
32 					EGBIS_IMAGE_UP_MOUSEOVER,
33 			//! When not set EGBIS_IMAGE_UP_MOUSEOVER is used.
34 					EGBIS_IMAGE_UP_FOCUSED,
35 			//! When not set EGBIS_IMAGE_UP_FOCUSED is used.
36 					EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER,
37 			//! When not set EGBIS_IMAGE_UP is used.
38 					EGBIS_IMAGE_DOWN,
39 			//! When not set EGBIS_IMAGE_DOWN is used.
40 					EGBIS_IMAGE_DOWN_MOUSEOVER,
41 			//! When not set EGBIS_IMAGE_DOWN_MOUSEOVER is used.
42 					EGBIS_IMAGE_DOWN_FOCUSED,
43 			//! When not set EGBIS_IMAGE_DOWN_FOCUSED is used.
44 					EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER,
45 			//! When not set EGBIS_IMAGE_UP or EGBIS_IMAGE_DOWN are used (depending on button state).
46 					EGBIS_IMAGE_DISABLED,
47 			//! not used, counts the number of enumerated items
48 					EGBIS_COUNT
49 		};
50 
51 		//! Names for gui button image states
52 		const c8 *const GUIButtonImageStateNames[EGBIS_COUNT + 1] =
53 				{
54 						"Image",    // not "ImageUp" as it otherwise breaks serialization of old files
55 						"ImageUpOver",
56 						"ImageUpFocused",
57 						"ImageUpFocusedOver",
58 						"PressedImage",    // not "ImageDown" as it otherwise breaks serialization of old files
59 						"ImageDownOver",
60 						"ImageDownFocused",
61 						"ImageDownFocusedOver",
62 						"ImageDisabled",
63 						0    // count
64 				};
65 
66 	}}
67 
68 #endif
69 
70 class ISimpleTextureSource;
71 
72 class GUIButton : public gui::IGUIButton
73 {
74 public:
75 
76 	//! constructor
77 	GUIButton(gui::IGUIEnvironment* environment, gui::IGUIElement* parent,
78 			   s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
79 			   bool noclip=false);
80 
81 	//! destructor
82 	virtual ~GUIButton();
83 
84 	//! called if an event happened.
85 	virtual bool OnEvent(const SEvent& event) override;
86 
87 	//! draws the element and its children
88 	virtual void draw() override;
89 
90 	//! sets another skin independent font. if this is set to zero, the button uses the font of the skin.
91 	virtual void setOverrideFont(gui::IGUIFont* font=0) override;
92 
93 	//! Gets the override font (if any)
94 	virtual gui::IGUIFont* getOverrideFont() const override;
95 
96 	//! Get the font which is used right now for drawing
97 	virtual gui::IGUIFont* getActiveFont() const override;
98 
99 	//! Sets another color for the button text.
100 	virtual void setOverrideColor(video::SColor color);
101 
102 	//! Gets the override color
103 	virtual video::SColor getOverrideColor(void) const;
104 
105 	//! Sets if the button text should use the override color or the color in the gui skin.
106 	virtual void enableOverrideColor(bool enable);
107 
108 	//! Checks if an override color is enabled
109 	virtual bool isOverrideColorEnabled(void) const;
110 
111 	// PATCH
112 	//! Sets an image which should be displayed on the button when it is in the given state.
113 	virtual void setImage(gui::EGUI_BUTTON_IMAGE_STATE state,
114 			video::ITexture* image=nullptr,
115 			const core::rect<s32>& sourceRect=core::rect<s32>(0,0,0,0));
116 
117 	//! Sets an image which should be displayed on the button when it is in normal state.
118 	virtual void setImage(video::ITexture* image=nullptr) override;
119 
120 	//! Sets an image which should be displayed on the button when it is in normal state.
121 	virtual void setImage(video::ITexture* image, const core::rect<s32>& pos) override;
122 
123 	//! Sets an image which should be displayed on the button when it is in pressed state.
124 	virtual void setPressedImage(video::ITexture* image=nullptr) override;
125 
126 	//! Sets an image which should be displayed on the button when it is in pressed state.
127 	virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) override;
128 
129 	//! Sets the text displayed by the button
130 	virtual void setText(const wchar_t* text) override;
131 	// END PATCH
132 
133 	//! Sets the sprite bank used by the button
134 	virtual void setSpriteBank(gui::IGUISpriteBank* bank=0) override;
135 
136 	//! Sets the animated sprite for a specific button state
137 	/** \param index: Number of the sprite within the sprite bank, use -1 for no sprite
138 	\param state: State of the button to set the sprite for
139 	\param index: The sprite number from the current sprite bank
140 	\param color: The color of the sprite
141 	*/
142 	virtual void setSprite(gui::EGUI_BUTTON_STATE state, s32 index,
143 						   video::SColor color=video::SColor(255,255,255,255),
144 						   bool loop=false, bool scale=false);
145 
146 #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8)
setSprite(gui::EGUI_BUTTON_STATE state,s32 index,video::SColor color,bool loop)147 	void setSprite(gui::EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop) override {
148 		setSprite(state, index, color, loop, false);
149 	}
150 #endif
151 
152 	//! Get the sprite-index for the given state or -1 when no sprite is set
153 	virtual s32 getSpriteIndex(gui::EGUI_BUTTON_STATE state) const;
154 
155 	//! Get the sprite color for the given state. Color is only used when a sprite is set.
156 	virtual video::SColor getSpriteColor(gui::EGUI_BUTTON_STATE state) const;
157 
158 	//! Returns if the sprite in the given state does loop
159 	virtual bool getSpriteLoop(gui::EGUI_BUTTON_STATE state) const;
160 
161 	//! Returns if the sprite in the given state is scaled
162 	virtual bool getSpriteScale(gui::EGUI_BUTTON_STATE state) const;
163 
164 	//! Sets if the button should behave like a push button. Which means it
165 	//! can be in two states: Normal or Pressed. With a click on the button,
166 	//! the user can change the state of the button.
167 	virtual void setIsPushButton(bool isPushButton=true) override;
168 
169 	//! Checks whether the button is a push button
170 	virtual bool isPushButton() const override;
171 
172 	//! Sets the pressed state of the button if this is a pushbutton
173 	virtual void setPressed(bool pressed=true) override;
174 
175 	//! Returns if the button is currently pressed
176 	virtual bool isPressed() const override;
177 
178 	// PATCH
179 	//! Returns if this element (or one of its direct children) is hovered
180 	bool isHovered() const;
181 	// END PATCH
182 
183 	//! Sets if the button should use the skin to draw its border
184 	virtual void setDrawBorder(bool border=true) override;
185 
186 	//! Checks if the button face and border are being drawn
187 	virtual bool isDrawingBorder() const override;
188 
189 	//! Sets if the alpha channel should be used for drawing images on the button (default is false)
190 	virtual void setUseAlphaChannel(bool useAlphaChannel=true) override;
191 
192 	//! Checks if the alpha channel should be used for drawing images on the button
193 	virtual bool isAlphaChannelUsed() const override;
194 
195 	//! Sets if the button should scale the button images to fit
196 	virtual void setScaleImage(bool scaleImage=true) override;
197 
198 	//! Checks whether the button scales the used images
199 	virtual bool isScalingImage() const override;
200 
201 	//! Get if the shift key was pressed in last EGET_BUTTON_CLICKED event
getClickShiftState()202 	virtual bool getClickShiftState() const
203 	{
204 		return ClickShiftState;
205 	}
206 
207 	//! Get if the control key was pressed in last EGET_BUTTON_CLICKED event
getClickControlState()208 	virtual bool getClickControlState() const
209 	{
210 		return ClickControlState;
211 	}
212 
213 	//! Writes attributes of the element.
214 	virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const override;
215 
216 	//! Reads attributes of the element
217 	virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) override;
218 
219 
220 
221 	void setColor(video::SColor color);
222 	// PATCH
223 	//! Set element properties from a StyleSpec corresponding to the button state
224 	void setFromState();
225 
226 	//! Set element properties from a StyleSpec
227 	virtual void setFromStyle(const StyleSpec& style);
228 
229 	//! Set the styles used for each state
230 	void setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles);
231 	// END PATCH
232 
233 
234 	//! Do not drop returned handle
235 	static GUIButton* addButton(gui::IGUIEnvironment *environment,
236 			const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,
237 			IGUIElement* parent, s32 id, const wchar_t* text,
238 			const wchar_t *tooltiptext=L"");
239 
240 protected:
241 	void drawSprite(gui::EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center);
242 	gui::EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const;
243 
getTextureSource()244 	ISimpleTextureSource *getTextureSource() { return TSrc; }
245 
246 	struct ButtonImage
247 	{
ButtonImageButtonImage248 		ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
249 		{
250 		}
251 
ButtonImageButtonImage252 		ButtonImage(const ButtonImage& other) : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
253 		{
254 			*this = other;
255 		}
256 
~ButtonImageButtonImage257 		~ButtonImage()
258 		{
259 			if ( Texture )
260 				Texture->drop();
261 		}
262 
263 		ButtonImage& operator=(const ButtonImage& other)
264 		{
265 			if ( this == &other )
266 				return *this;
267 
268 			if (other.Texture)
269 				other.Texture->grab();
270 			if ( Texture )
271 				Texture->drop();
272 			Texture = other.Texture;
273 			SourceRect = other.SourceRect;
274 			return *this;
275 		}
276 
277 		bool operator==(const ButtonImage& other) const
278 		{
279 			return Texture == other.Texture && SourceRect == other.SourceRect;
280 		}
281 
282 
283 		video::ITexture* Texture;
284 		core::rect<s32> SourceRect;
285 	};
286 
287 	gui::EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed, const ButtonImage* images) const;
288 
289 private:
290 
291 	struct ButtonSprite
292 	{
ButtonSpriteButtonSprite293 		ButtonSprite() : Index(-1), Loop(false), Scale(false)
294 		{
295 		}
296 
297 		bool operator==(const ButtonSprite& other) const
298 		{
299 			return Index == other.Index && Color == other.Color && Loop == other.Loop && Scale == other.Scale;
300 		}
301 
302 		s32 Index;
303 		video::SColor Color;
304 		bool Loop;
305 		bool Scale;
306 	};
307 
308 	ButtonSprite ButtonSprites[gui::EGBS_COUNT];
309 	gui::IGUISpriteBank* SpriteBank;
310 
311 	ButtonImage ButtonImages[gui::EGBIS_COUNT];
312 
313 	std::array<StyleSpec, StyleSpec::NUM_STATES> Styles;
314 
315 	gui::IGUIFont* OverrideFont;
316 
317 	bool OverrideColorEnabled;
318 	video::SColor OverrideColor;
319 
320 	u32 ClickTime, HoverTime, FocusTime;
321 
322 	bool ClickShiftState;
323 	bool ClickControlState;
324 
325 	bool IsPushButton;
326 	bool Pressed;
327 	bool UseAlphaChannel;
328 	bool DrawBorder;
329 	bool ScaleImage;
330 
331 	video::SColor Colors[4];
332 	// PATCH
333 	bool WasHovered = false;
334 	ISimpleTextureSource *TSrc;
335 
336 	gui::IGUIStaticText *StaticText;
337 
338 	core::rect<s32> BgMiddle;
339 	core::rect<s32> Padding;
340 	core::vector2d<s32> ContentOffset;
341 	video::SColor BgColor;
342 	// END PATCH
343 };
344