]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CGUIModalScreen.cpp
Merging r6196 through r6248 from trunk to ogl-es branch
[irrlicht.git] / source / Irrlicht / CGUIModalScreen.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CGUIModalScreen.h"\r
6 #ifdef _IRR_COMPILE_WITH_GUI_\r
7 \r
8 #include "IGUIEnvironment.h"\r
9 #include "os.h"\r
10 #include "IVideoDriver.h"\r
11 #include "IGUISkin.h"\r
12 \r
13 namespace irr\r
14 {\r
15 namespace gui\r
16 {\r
17 \r
18 //! constructor\r
19 CGUIModalScreen::CGUIModalScreen(IGUIEnvironment* environment, IGUIElement* parent, s32 id)\r
20 : IGUIElement(EGUIET_MODAL_SCREEN, environment, parent, id, core::recti(0, 0, parent->getAbsolutePosition().getWidth(), parent->getAbsolutePosition().getHeight()) ),\r
21         BlinkMode(3),\r
22         MouseDownTime(0)\r
23 {\r
24         #ifdef _DEBUG\r
25         setDebugName("CGUIModalScreen");\r
26         #endif\r
27         setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);\r
28 \r
29         // this element is a tab group\r
30         setTabGroup(true);\r
31 }\r
32 \r
33 bool CGUIModalScreen::canTakeFocus(IGUIElement* target) const\r
34 {\r
35     return (target && ((const IGUIElement*)target == this // this element can take it\r
36                         || isMyChild(target)    // own children also\r
37                         || (target->getType() == EGUIET_MODAL_SCREEN )  // other modals also fine (is now on top or explicitely requested)\r
38                         || (target->getParent() && target->getParent()->getType() == EGUIET_MODAL_SCREEN )))   // children of other modals will do\r
39             ;\r
40 }\r
41 \r
42 bool CGUIModalScreen::isVisible() const\r
43 {\r
44     // any parent invisible?\r
45     IGUIElement * parentElement = getParent();\r
46     while ( parentElement )\r
47     {\r
48         if ( !parentElement->isVisible() )\r
49             return false;\r
50         parentElement = parentElement->getParent();\r
51     }\r
52 \r
53     // if we have no children then the modal is probably abused as a way to block input\r
54     if ( Children.empty() )\r
55     {\r
56         return IGUIElement::isVisible();\r
57     }\r
58 \r
59     // any child visible?\r
60     bool visible = false;\r
61     core::list<IGUIElement*>::ConstIterator it = Children.begin();\r
62     for (; it != Children.end(); ++it)\r
63     {\r
64         if ( (*it)->isVisible() )\r
65         {\r
66             visible = true;\r
67             break;\r
68         }\r
69     }\r
70     return visible;\r
71 }\r
72 \r
73 bool CGUIModalScreen::isPointInside(const core::position2d<s32>& point) const\r
74 {\r
75     return true;\r
76 }\r
77 \r
78 //! called if an event happened.\r
79 bool CGUIModalScreen::OnEvent(const SEvent& event)\r
80 {\r
81     if (!isEnabled() || !isVisible() )\r
82         return IGUIElement::OnEvent(event);\r
83 \r
84     switch(event.EventType)\r
85         {\r
86         case EET_GUI_EVENT:\r
87                 switch(event.GUIEvent.EventType)\r
88                 {\r
89                 case EGET_ELEMENT_FOCUSED:\r
90                         if ( event.GUIEvent.Caller == this && isMyChild(event.GUIEvent.Element) )\r
91                         {\r
92                                 Environment->removeFocus(0);    // can't setFocus otherwise at it still has focus here\r
93                                 Environment->setFocus(event.GUIEvent.Element);\r
94                                 if ( BlinkMode&1 )\r
95                                         MouseDownTime = os::Timer::getTime();\r
96                                 return true;\r
97                         }\r
98                         if ( !canTakeFocus(event.GUIEvent.Caller))\r
99                         {\r
100                                 if ( !Children.empty() )\r
101                                         Environment->setFocus(*(Children.begin()));\r
102                                 else\r
103                                         Environment->setFocus(this);\r
104                         }\r
105                         IGUIElement::OnEvent(event);\r
106                         return false;\r
107                 case EGET_ELEMENT_FOCUS_LOST:\r
108                         if ( !canTakeFocus(event.GUIEvent.Element))\r
109             {\r
110                 if ( isMyChild(event.GUIEvent.Caller) )\r
111                                 {\r
112                                         if ( !Children.empty() )\r
113                                                 Environment->setFocus(*(Children.begin()));\r
114                                         else\r
115                                                 Environment->setFocus(this);\r
116                                 }\r
117                                 else if ( BlinkMode&1 )\r
118                                 {\r
119                                         MouseDownTime = os::Timer::getTime();\r
120                                 }\r
121                                 return true;\r
122                         }\r
123                         else\r
124                         {\r
125                                 return IGUIElement::OnEvent(event);\r
126                         }\r
127                 case EGET_ELEMENT_CLOSED:\r
128                         // do not interfere with children being removed\r
129                         return IGUIElement::OnEvent(event);\r
130                 default:\r
131                         break;\r
132                 }\r
133                 break;\r
134         case EET_MOUSE_INPUT_EVENT:\r
135                 if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN && (BlinkMode & 2))\r
136                 {\r
137                         MouseDownTime = os::Timer::getTime();\r
138         }\r
139         break;\r
140         case EET_KEY_INPUT_EVENT:\r
141                 // CAREFUL when changing - there's an identical check in CGUIEnvironment::postEventFromUser\r
142                 if (Environment->getFocusBehavior() & EFF_SET_ON_TAB &&\r
143                         event.KeyInput.PressedDown &&\r
144                         event.KeyInput.Key == KEY_TAB)\r
145                 {\r
146                         IGUIElement* next = Environment->getNextElement(event.KeyInput.Shift, event.KeyInput.Control);\r
147                         if ( next && isMyChild(next) )\r
148                         {\r
149                                 // Pass on the TAB-key, otherwise focus-tabbing inside modal screens breaks\r
150                                 return false;\r
151                         }\r
152                 }\r
153         default:\r
154                 break;\r
155         }\r
156 \r
157         IGUIElement::OnEvent(event);    // anyone knows why events are passed on here? Causes p.e. problems when this is child of a CGUIWindow.\r
158 \r
159         return true; // absorb everything else\r
160 }\r
161 \r
162 \r
163 //! draws the element and its children\r
164 void CGUIModalScreen::draw()\r
165 {\r
166         IGUISkin *skin = Environment->getSkin();\r
167 \r
168         if (!skin)\r
169                 return;\r
170 \r
171         u32 now = os::Timer::getTime();\r
172         if (BlinkMode && now - MouseDownTime < 300 && (now / 70)%2)\r
173         {\r
174                 core::list<IGUIElement*>::Iterator it = Children.begin();\r
175                 core::rect<s32> r;\r
176                 video::SColor c = Environment->getSkin()->getColor(gui::EGDC_3D_HIGH_LIGHT);\r
177 \r
178                 for (; it != Children.end(); ++it)\r
179                 {\r
180                         if ((*it)->isVisible())\r
181                         {\r
182                                 r = (*it)->getAbsolutePosition();\r
183                                 r.LowerRightCorner.X += 1;\r
184                                 r.LowerRightCorner.Y += 1;\r
185                                 r.UpperLeftCorner.X -= 1;\r
186                                 r.UpperLeftCorner.Y -= 1;\r
187 \r
188                                 skin->draw2DRectangle(this, c, r, &AbsoluteClippingRect);\r
189                         }\r
190                 }\r
191         }\r
192 \r
193         IGUIElement::draw();\r
194 }\r
195 \r
196 \r
197 //! Removes a child.\r
198 void CGUIModalScreen::removeChild(IGUIElement* child)\r
199 {\r
200         IGUIElement::removeChild(child);\r
201 \r
202         if (Children.empty())\r
203         {\r
204                 remove();\r
205         }\r
206 }\r
207 \r
208 \r
209 //! adds a child\r
210 void CGUIModalScreen::addChild(IGUIElement* child)\r
211 {\r
212         IGUIElement::addChild(child);\r
213         Environment->setFocus(child);\r
214 }\r
215 \r
216 \r
217 void CGUIModalScreen::updateAbsolutePosition()\r
218 {\r
219         core::rect<s32> parentRect(0,0,0,0);\r
220 \r
221         if (Parent)\r
222         {\r
223                 parentRect = Parent->getAbsolutePosition();\r
224                 RelativeRect.UpperLeftCorner.X = 0;\r
225                 RelativeRect.UpperLeftCorner.Y = 0;\r
226                 RelativeRect.LowerRightCorner.X = parentRect.getWidth();\r
227                 RelativeRect.LowerRightCorner.Y = parentRect.getHeight();\r
228         }\r
229 \r
230         IGUIElement::updateAbsolutePosition();\r
231 }\r
232 \r
233 \r
234 //! Writes attributes of the element.\r
235 void CGUIModalScreen::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const\r
236 {\r
237         IGUIElement::serializeAttributes(out,options);\r
238 \r
239         out->addInt("BlinkMode", BlinkMode );\r
240 }\r
241 \r
242 //! Reads attributes of the element\r
243 void CGUIModalScreen::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)\r
244 {\r
245         IGUIElement::deserializeAttributes(in, options);\r
246 \r
247         BlinkMode = in->getAttributeAsInt("BlinkMode", BlinkMode);\r
248 }\r
249 \r
250 \r
251 } // end namespace gui\r
252 } // end namespace irr\r
253 \r
254 #endif // _IRR_COMPILE_WITH_GUI_\r
255 \r