diff options
Diffstat (limited to 'libraries/irrlicht-1.8.1/source/Irrlicht/CGUIButton.cpp')
-rw-r--r-- | libraries/irrlicht-1.8.1/source/Irrlicht/CGUIButton.cpp | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8.1/source/Irrlicht/CGUIButton.cpp b/libraries/irrlicht-1.8.1/source/Irrlicht/CGUIButton.cpp new file mode 100644 index 0000000..5a451cd --- /dev/null +++ b/libraries/irrlicht-1.8.1/source/Irrlicht/CGUIButton.cpp | |||
@@ -0,0 +1,531 @@ | |||
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 | #include "CGUIButton.h" | ||
6 | #ifdef _IRR_COMPILE_WITH_GUI_ | ||
7 | |||
8 | #include "IGUISkin.h" | ||
9 | #include "IGUIEnvironment.h" | ||
10 | #include "IVideoDriver.h" | ||
11 | #include "IGUIFont.h" | ||
12 | #include "os.h" | ||
13 | |||
14 | namespace irr | ||
15 | { | ||
16 | namespace gui | ||
17 | { | ||
18 | |||
19 | //! constructor | ||
20 | CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent, | ||
21 | s32 id, core::rect<s32> rectangle, bool noclip) | ||
22 | : IGUIButton(environment, parent, id, rectangle), | ||
23 | SpriteBank(0), OverrideFont(0), Image(0), PressedImage(0), | ||
24 | ClickTime(0), HoverTime(0), FocusTime(0), | ||
25 | IsPushButton(false), Pressed(false), | ||
26 | UseAlphaChannel(false), DrawBorder(true), ScaleImage(false) | ||
27 | { | ||
28 | #ifdef _DEBUG | ||
29 | setDebugName("CGUIButton"); | ||
30 | #endif | ||
31 | setNotClipped(noclip); | ||
32 | |||
33 | // Initialize the sprites. | ||
34 | for (u32 i=0; i<EGBS_COUNT; ++i) | ||
35 | ButtonSprites[i].Index = -1; | ||
36 | |||
37 | // This element can be tabbed. | ||
38 | setTabStop(true); | ||
39 | setTabOrder(-1); | ||
40 | } | ||
41 | |||
42 | |||
43 | //! destructor | ||
44 | CGUIButton::~CGUIButton() | ||
45 | { | ||
46 | if (OverrideFont) | ||
47 | OverrideFont->drop(); | ||
48 | |||
49 | if (Image) | ||
50 | Image->drop(); | ||
51 | |||
52 | if (PressedImage) | ||
53 | PressedImage->drop(); | ||
54 | |||
55 | if (SpriteBank) | ||
56 | SpriteBank->drop(); | ||
57 | } | ||
58 | |||
59 | |||
60 | //! Sets if the images should be scaled to fit the button | ||
61 | void CGUIButton::setScaleImage(bool scaleImage) | ||
62 | { | ||
63 | ScaleImage = scaleImage; | ||
64 | } | ||
65 | |||
66 | |||
67 | //! Returns whether the button scale the used images | ||
68 | bool CGUIButton::isScalingImage() const | ||
69 | { | ||
70 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
71 | return ScaleImage; | ||
72 | } | ||
73 | |||
74 | |||
75 | //! Sets if the button should use the skin to draw its border | ||
76 | void CGUIButton::setDrawBorder(bool border) | ||
77 | { | ||
78 | DrawBorder = border; | ||
79 | } | ||
80 | |||
81 | |||
82 | void CGUIButton::setSpriteBank(IGUISpriteBank* sprites) | ||
83 | { | ||
84 | if (sprites) | ||
85 | sprites->grab(); | ||
86 | |||
87 | if (SpriteBank) | ||
88 | SpriteBank->drop(); | ||
89 | |||
90 | SpriteBank = sprites; | ||
91 | } | ||
92 | |||
93 | |||
94 | void CGUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop) | ||
95 | { | ||
96 | if (SpriteBank) | ||
97 | { | ||
98 | ButtonSprites[(u32)state].Index = index; | ||
99 | ButtonSprites[(u32)state].Color = color; | ||
100 | ButtonSprites[(u32)state].Loop = loop; | ||
101 | } | ||
102 | else | ||
103 | { | ||
104 | ButtonSprites[(u32)state].Index = -1; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | |||
109 | //! called if an event happened. | ||
110 | bool CGUIButton::OnEvent(const SEvent& event) | ||
111 | { | ||
112 | if (!isEnabled()) | ||
113 | return IGUIElement::OnEvent(event); | ||
114 | |||
115 | switch(event.EventType) | ||
116 | { | ||
117 | case EET_KEY_INPUT_EVENT: | ||
118 | if (event.KeyInput.PressedDown && | ||
119 | (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) | ||
120 | { | ||
121 | if (!IsPushButton) | ||
122 | setPressed(true); | ||
123 | else | ||
124 | setPressed(!Pressed); | ||
125 | |||
126 | return true; | ||
127 | } | ||
128 | if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE) | ||
129 | { | ||
130 | setPressed(false); | ||
131 | return true; | ||
132 | } | ||
133 | else | ||
134 | if (!event.KeyInput.PressedDown && Pressed && | ||
135 | (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) | ||
136 | { | ||
137 | |||
138 | if (!IsPushButton) | ||
139 | setPressed(false); | ||
140 | |||
141 | if (Parent) | ||
142 | { | ||
143 | SEvent newEvent; | ||
144 | newEvent.EventType = EET_GUI_EVENT; | ||
145 | newEvent.GUIEvent.Caller = this; | ||
146 | newEvent.GUIEvent.Element = 0; | ||
147 | newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED; | ||
148 | Parent->OnEvent(newEvent); | ||
149 | } | ||
150 | return true; | ||
151 | } | ||
152 | break; | ||
153 | case EET_GUI_EVENT: | ||
154 | if (event.GUIEvent.Caller == this) | ||
155 | { | ||
156 | if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) | ||
157 | { | ||
158 | if (!IsPushButton) | ||
159 | setPressed(false); | ||
160 | FocusTime = os::Timer::getTime(); | ||
161 | } | ||
162 | else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED) | ||
163 | { | ||
164 | FocusTime = os::Timer::getTime(); | ||
165 | } | ||
166 | else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT) | ||
167 | { | ||
168 | HoverTime = os::Timer::getTime(); | ||
169 | } | ||
170 | } | ||
171 | break; | ||
172 | case EET_MOUSE_INPUT_EVENT: | ||
173 | if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) | ||
174 | { | ||
175 | if (Environment->hasFocus(this) && | ||
176 | !AbsoluteClippingRect.isPointInside(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y))) | ||
177 | { | ||
178 | Environment->removeFocus(this); | ||
179 | return false; | ||
180 | } | ||
181 | |||
182 | if (!IsPushButton) | ||
183 | setPressed(true); | ||
184 | |||
185 | Environment->setFocus(this); | ||
186 | return true; | ||
187 | } | ||
188 | else | ||
189 | if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) | ||
190 | { | ||
191 | bool wasPressed = Pressed; | ||
192 | |||
193 | if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) ) | ||
194 | { | ||
195 | if (!IsPushButton) | ||
196 | setPressed(false); | ||
197 | return true; | ||
198 | } | ||
199 | |||
200 | if (!IsPushButton) | ||
201 | setPressed(false); | ||
202 | else | ||
203 | { | ||
204 | setPressed(!Pressed); | ||
205 | } | ||
206 | |||
207 | if ((!IsPushButton && wasPressed && Parent) || | ||
208 | (IsPushButton && wasPressed != Pressed)) | ||
209 | { | ||
210 | SEvent newEvent; | ||
211 | newEvent.EventType = EET_GUI_EVENT; | ||
212 | newEvent.GUIEvent.Caller = this; | ||
213 | newEvent.GUIEvent.Element = 0; | ||
214 | newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED; | ||
215 | Parent->OnEvent(newEvent); | ||
216 | } | ||
217 | |||
218 | return true; | ||
219 | } | ||
220 | break; | ||
221 | default: | ||
222 | break; | ||
223 | } | ||
224 | |||
225 | return Parent ? Parent->OnEvent(event) : false; | ||
226 | } | ||
227 | |||
228 | |||
229 | //! draws the element and its children | ||
230 | void CGUIButton::draw() | ||
231 | { | ||
232 | if (!IsVisible) | ||
233 | return; | ||
234 | |||
235 | IGUISkin* skin = Environment->getSkin(); | ||
236 | video::IVideoDriver* driver = Environment->getVideoDriver(); | ||
237 | |||
238 | // todo: move sprite up and text down if the pressed state has a sprite | ||
239 | const core::position2di spritePos = AbsoluteRect.getCenter(); | ||
240 | |||
241 | if (!Pressed) | ||
242 | { | ||
243 | if (DrawBorder) | ||
244 | skin->draw3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect); | ||
245 | |||
246 | if (Image) | ||
247 | { | ||
248 | core::position2d<s32> pos = spritePos; | ||
249 | pos.X -= ImageRect.getWidth() / 2; | ||
250 | pos.Y -= ImageRect.getHeight() / 2; | ||
251 | |||
252 | driver->draw2DImage(Image, | ||
253 | ScaleImage? AbsoluteRect : | ||
254 | core::recti(pos, ImageRect.getSize()), | ||
255 | ImageRect, &AbsoluteClippingRect, | ||
256 | 0, UseAlphaChannel); | ||
257 | } | ||
258 | } | ||
259 | else | ||
260 | { | ||
261 | if (DrawBorder) | ||
262 | skin->draw3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect); | ||
263 | |||
264 | if (PressedImage) | ||
265 | { | ||
266 | core::position2d<s32> pos = spritePos; | ||
267 | pos.X -= PressedImageRect.getWidth() / 2; | ||
268 | pos.Y -= PressedImageRect.getHeight() / 2; | ||
269 | |||
270 | if (Image == PressedImage && PressedImageRect == ImageRect) | ||
271 | { | ||
272 | pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X); | ||
273 | pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y); | ||
274 | } | ||
275 | driver->draw2DImage(PressedImage, | ||
276 | ScaleImage? AbsoluteRect : | ||
277 | core::recti(pos, PressedImageRect.getSize()), | ||
278 | PressedImageRect, &AbsoluteClippingRect, | ||
279 | 0, UseAlphaChannel); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | if (SpriteBank) | ||
284 | { | ||
285 | // pressed / unpressed animation | ||
286 | u32 state = Pressed ? (u32)EGBS_BUTTON_DOWN : (u32)EGBS_BUTTON_UP; | ||
287 | if (ButtonSprites[state].Index != -1) | ||
288 | { | ||
289 | SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos, | ||
290 | &AbsoluteClippingRect, ButtonSprites[state].Color, ClickTime, os::Timer::getTime(), | ||
291 | ButtonSprites[state].Loop, true); | ||
292 | } | ||
293 | |||
294 | // focused / unfocused animation | ||
295 | state = Environment->hasFocus(this) ? (u32)EGBS_BUTTON_FOCUSED : (u32)EGBS_BUTTON_NOT_FOCUSED; | ||
296 | if (ButtonSprites[state].Index != -1) | ||
297 | { | ||
298 | SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos, | ||
299 | &AbsoluteClippingRect, ButtonSprites[state].Color, FocusTime, os::Timer::getTime(), | ||
300 | ButtonSprites[state].Loop, true); | ||
301 | } | ||
302 | |||
303 | // mouse over / off animation | ||
304 | if (isEnabled()) | ||
305 | { | ||
306 | state = Environment->getHovered() == this ? (u32)EGBS_BUTTON_MOUSE_OVER : (u32)EGBS_BUTTON_MOUSE_OFF; | ||
307 | if (ButtonSprites[state].Index != -1) | ||
308 | { | ||
309 | SpriteBank->draw2DSprite(ButtonSprites[state].Index, spritePos, | ||
310 | &AbsoluteClippingRect, ButtonSprites[state].Color, HoverTime, os::Timer::getTime(), | ||
311 | ButtonSprites[state].Loop, true); | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | |||
316 | if (Text.size()) | ||
317 | { | ||
318 | IGUIFont* font = getActiveFont(); | ||
319 | |||
320 | core::rect<s32> rect = AbsoluteRect; | ||
321 | if (Pressed) | ||
322 | { | ||
323 | rect.UpperLeftCorner.X += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_X); | ||
324 | rect.UpperLeftCorner.Y += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y); | ||
325 | } | ||
326 | |||
327 | if (font) | ||
328 | font->draw(Text.c_str(), rect, | ||
329 | skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), | ||
330 | true, true, &AbsoluteClippingRect); | ||
331 | } | ||
332 | |||
333 | IGUIElement::draw(); | ||
334 | } | ||
335 | |||
336 | |||
337 | //! sets another skin independent font. if this is set to zero, the button uses the font of the skin. | ||
338 | void CGUIButton::setOverrideFont(IGUIFont* font) | ||
339 | { | ||
340 | if (OverrideFont == font) | ||
341 | return; | ||
342 | |||
343 | if (OverrideFont) | ||
344 | OverrideFont->drop(); | ||
345 | |||
346 | OverrideFont = font; | ||
347 | |||
348 | if (OverrideFont) | ||
349 | OverrideFont->grab(); | ||
350 | } | ||
351 | |||
352 | //! Gets the override font (if any) | ||
353 | IGUIFont * CGUIButton::getOverrideFont() const | ||
354 | { | ||
355 | return OverrideFont; | ||
356 | } | ||
357 | |||
358 | //! Get the font which is used right now for drawing | ||
359 | IGUIFont* CGUIButton::getActiveFont() const | ||
360 | { | ||
361 | if ( OverrideFont ) | ||
362 | return OverrideFont; | ||
363 | IGUISkin* skin = Environment->getSkin(); | ||
364 | if (skin) | ||
365 | return skin->getFont(EGDF_BUTTON); | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | //! Sets an image which should be displayed on the button when it is in normal state. | ||
370 | void CGUIButton::setImage(video::ITexture* image) | ||
371 | { | ||
372 | if (image) | ||
373 | image->grab(); | ||
374 | if (Image) | ||
375 | Image->drop(); | ||
376 | |||
377 | Image = image; | ||
378 | if (image) | ||
379 | ImageRect = core::rect<s32>(core::position2d<s32>(0,0), image->getOriginalSize()); | ||
380 | |||
381 | if (!PressedImage) | ||
382 | setPressedImage(Image); | ||
383 | } | ||
384 | |||
385 | |||
386 | //! Sets the image which should be displayed on the button when it is in its normal state. | ||
387 | void CGUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos) | ||
388 | { | ||
389 | setImage(image); | ||
390 | ImageRect = pos; | ||
391 | } | ||
392 | |||
393 | |||
394 | //! Sets an image which should be displayed on the button when it is in pressed state. | ||
395 | void CGUIButton::setPressedImage(video::ITexture* image) | ||
396 | { | ||
397 | if (image) | ||
398 | image->grab(); | ||
399 | |||
400 | if (PressedImage) | ||
401 | PressedImage->drop(); | ||
402 | |||
403 | PressedImage = image; | ||
404 | if (image) | ||
405 | PressedImageRect = core::rect<s32>(core::position2d<s32>(0,0), image->getOriginalSize()); | ||
406 | } | ||
407 | |||
408 | |||
409 | //! Sets the image which should be displayed on the button when it is in its pressed state. | ||
410 | void CGUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos) | ||
411 | { | ||
412 | setPressedImage(image); | ||
413 | PressedImageRect = pos; | ||
414 | } | ||
415 | |||
416 | |||
417 | //! Sets if the button should behave like a push button. Which means it | ||
418 | //! can be in two states: Normal or Pressed. With a click on the button, | ||
419 | //! the user can change the state of the button. | ||
420 | void CGUIButton::setIsPushButton(bool isPushButton) | ||
421 | { | ||
422 | IsPushButton = isPushButton; | ||
423 | } | ||
424 | |||
425 | |||
426 | //! Returns if the button is currently pressed | ||
427 | bool CGUIButton::isPressed() const | ||
428 | { | ||
429 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
430 | return Pressed; | ||
431 | } | ||
432 | |||
433 | |||
434 | //! Sets the pressed state of the button if this is a pushbutton | ||
435 | void CGUIButton::setPressed(bool pressed) | ||
436 | { | ||
437 | if (Pressed != pressed) | ||
438 | { | ||
439 | ClickTime = os::Timer::getTime(); | ||
440 | Pressed = pressed; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | |||
445 | //! Returns whether the button is a push button | ||
446 | bool CGUIButton::isPushButton() const | ||
447 | { | ||
448 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
449 | return IsPushButton; | ||
450 | } | ||
451 | |||
452 | |||
453 | //! Sets if the alpha channel should be used for drawing images on the button (default is false) | ||
454 | void CGUIButton::setUseAlphaChannel(bool useAlphaChannel) | ||
455 | { | ||
456 | UseAlphaChannel = useAlphaChannel; | ||
457 | } | ||
458 | |||
459 | |||
460 | //! Returns if the alpha channel should be used for drawing images on the button | ||
461 | bool CGUIButton::isAlphaChannelUsed() const | ||
462 | { | ||
463 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
464 | return UseAlphaChannel; | ||
465 | } | ||
466 | |||
467 | |||
468 | bool CGUIButton::isDrawingBorder() const | ||
469 | { | ||
470 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
471 | return DrawBorder; | ||
472 | } | ||
473 | |||
474 | |||
475 | //! Writes attributes of the element. | ||
476 | void CGUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const | ||
477 | { | ||
478 | IGUIButton::serializeAttributes(out,options); | ||
479 | |||
480 | out->addBool ("PushButton", IsPushButton ); | ||
481 | if (IsPushButton) | ||
482 | out->addBool("Pressed", Pressed); | ||
483 | |||
484 | out->addTexture ("Image", Image); | ||
485 | out->addRect ("ImageRect", ImageRect); | ||
486 | out->addTexture ("PressedImage", PressedImage); | ||
487 | out->addRect ("PressedImageRect", PressedImageRect); | ||
488 | |||
489 | out->addBool ("UseAlphaChannel", isAlphaChannelUsed()); | ||
490 | out->addBool ("Border", isDrawingBorder()); | ||
491 | out->addBool ("ScaleImage", isScalingImage()); | ||
492 | |||
493 | // out->addString ("OverrideFont", OverrideFont); | ||
494 | } | ||
495 | |||
496 | |||
497 | //! Reads attributes of the element | ||
498 | void CGUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) | ||
499 | { | ||
500 | IGUIButton::deserializeAttributes(in,options); | ||
501 | |||
502 | IsPushButton = in->getAttributeAsBool("PushButton"); | ||
503 | Pressed = IsPushButton ? in->getAttributeAsBool("Pressed") : false; | ||
504 | |||
505 | core::rect<s32> rec = in->getAttributeAsRect("ImageRect"); | ||
506 | if (rec.isValid()) | ||
507 | setImage( in->getAttributeAsTexture("Image"), rec); | ||
508 | else | ||
509 | setImage( in->getAttributeAsTexture("Image") ); | ||
510 | |||
511 | rec = in->getAttributeAsRect("PressedImageRect"); | ||
512 | if (rec.isValid()) | ||
513 | setPressedImage( in->getAttributeAsTexture("PressedImage"), rec); | ||
514 | else | ||
515 | setPressedImage( in->getAttributeAsTexture("PressedImage") ); | ||
516 | |||
517 | setDrawBorder(in->getAttributeAsBool("Border")); | ||
518 | setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel")); | ||
519 | setScaleImage(in->getAttributeAsBool("ScaleImage")); | ||
520 | |||
521 | // setOverrideFont(in->getAttributeAsString("OverrideFont")); | ||
522 | |||
523 | updateAbsolutePosition(); | ||
524 | } | ||
525 | |||
526 | |||
527 | } // end namespace gui | ||
528 | } // end namespace irr | ||
529 | |||
530 | #endif // _IRR_COMPILE_WITH_GUI_ | ||
531 | |||