]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CGUIEnvironment.cpp
e29195b2c3ff181c9f7e652d0aa7758648db032e
[irrlicht.git] / source / Irrlicht / CGUIEnvironment.cpp
1 \r
2 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
3 // This file is part of the "Irrlicht Engine".\r
4 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
5 \r
6 #include "CGUIEnvironment.h"\r
7 \r
8 #ifdef _IRR_COMPILE_WITH_GUI_\r
9 \r
10 #include "IVideoDriver.h"\r
11 \r
12 #include "CGUISkin.h"\r
13 #include "CGUIButton.h"\r
14 #include "CGUIWindow.h"\r
15 #include "CGUIScrollBar.h"\r
16 #include "CGUIFont.h"\r
17 #include "CGUISpriteBank.h"\r
18 #include "CGUIImage.h"\r
19 #include "CGUIMeshViewer.h"\r
20 #include "CGUICheckBox.h"\r
21 #include "CGUIListBox.h"\r
22 #include "CGUITreeView.h"\r
23 #include "CGUIImageList.h"\r
24 #include "CGUIFileOpenDialog.h"\r
25 #include "CGUIColorSelectDialog.h"\r
26 #include "CGUIStaticText.h"\r
27 #include "CGUIEditBox.h"\r
28 #include "CGUISpinBox.h"\r
29 #include "CGUIInOutFader.h"\r
30 #include "CGUIMessageBox.h"\r
31 #include "CGUIModalScreen.h"\r
32 #include "CGUITabControl.h"\r
33 #include "CGUIContextMenu.h"\r
34 #include "CGUIComboBox.h"\r
35 #include "CGUIMenu.h"\r
36 #include "CGUIToolBar.h"\r
37 #include "CGUITable.h"\r
38 #include "CGUIProfiler.h"\r
39 \r
40 #include "CDefaultGUIElementFactory.h"\r
41 #include "IWriteFile.h"\r
42 #include "IXMLWriter.h"\r
43 \r
44 #include "BuiltInFont.h"\r
45 #include "os.h"\r
46 \r
47 namespace irr\r
48 {\r
49 namespace gui\r
50 {\r
51 \r
52 const wchar_t IRR_XML_FORMAT_GUI_ENV[]                  = L"irr_gui";\r
53 const wchar_t IRR_XML_FORMAT_GUI_ELEMENT[]              = L"element";\r
54 const wchar_t IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE[]    = L"type";\r
55 \r
56 const io::path CGUIEnvironment::DefaultFontName = "#DefaultFont";\r
57 \r
58 //! constructor\r
59 CGUIEnvironment::CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* driver, IOSOperator* op)\r
60 : IGUIElement(EGUIET_ROOT, 0, 0, 0, core::rect<s32>(driver ? core::dimension2d<s32>(driver->getScreenSize()) : core::dimension2d<s32>(0,0))),\r
61         Driver(driver), Hovered(0), HoveredNoSubelement(0), Focus(0), LastHoveredMousePos(0,0), CurrentSkin(0),\r
62         FileSystem(fs), UserReceiver(0), Operator(op), FocusFlags(EFF_SET_ON_LMOUSE_DOWN|EFF_SET_ON_TAB)\r
63 {\r
64         if (Driver)\r
65                 Driver->grab();\r
66 \r
67         if (FileSystem)\r
68                 FileSystem->grab();\r
69 \r
70         if (Operator)\r
71                 Operator->grab();\r
72 \r
73         #ifdef _DEBUG\r
74         IGUIEnvironment::setDebugName("CGUIEnvironment");\r
75         #endif\r
76 \r
77         // gui factory\r
78         IGUIElementFactory* factory = new CDefaultGUIElementFactory(this);\r
79         registerGUIElementFactory(factory);\r
80         factory->drop();\r
81 \r
82         loadBuiltInFont();\r
83 \r
84         IGUISkin* skin = createSkin( gui::EGST_WINDOWS_METALLIC );\r
85         setSkin(skin);\r
86         skin->drop();\r
87 \r
88         //set tooltip default\r
89         ToolTip.LastTime = 0;\r
90         ToolTip.EnterTime = 0;\r
91         ToolTip.LaunchTime = 1000;\r
92         ToolTip.RelaunchTime = 500;\r
93         ToolTip.Element = 0;\r
94 \r
95         // environment is root tab group\r
96         Environment = this;\r
97         setTabGroup(true);\r
98 }\r
99 \r
100 \r
101 //! destructor\r
102 CGUIEnvironment::~CGUIEnvironment()\r
103 {\r
104         if ( HoveredNoSubelement && HoveredNoSubelement != this )\r
105         {\r
106                 HoveredNoSubelement->drop();\r
107                 HoveredNoSubelement = 0;\r
108         }\r
109 \r
110         if (Hovered && Hovered != this)\r
111         {\r
112                 Hovered->drop();\r
113                 Hovered = 0;\r
114         }\r
115 \r
116         if (Focus)\r
117         {\r
118                 Focus->drop();\r
119                 Focus = 0;\r
120         }\r
121 \r
122         if (ToolTip.Element)\r
123         {\r
124                 ToolTip.Element->drop();\r
125                 ToolTip.Element = 0;\r
126         }\r
127 \r
128         // drop skin\r
129         if (CurrentSkin)\r
130         {\r
131                 CurrentSkin->drop();\r
132                 CurrentSkin = 0;\r
133         }\r
134 \r
135         u32 i;\r
136 \r
137         // delete all sprite banks\r
138         for (i=0; i<Banks.size(); ++i)\r
139                 if (Banks[i].Bank)\r
140                         Banks[i].Bank->drop();\r
141 \r
142         // delete all fonts\r
143         for (i=0; i<Fonts.size(); ++i)\r
144                 Fonts[i].Font->drop();\r
145 \r
146         // remove all factories\r
147         for (i=0; i<GUIElementFactoryList.size(); ++i)\r
148                 GUIElementFactoryList[i]->drop();\r
149 \r
150         if (Operator)\r
151         {\r
152                 Operator->drop();\r
153                 Operator = 0;\r
154         }\r
155 \r
156         if (FileSystem)\r
157         {\r
158                 FileSystem->drop();\r
159                 FileSystem = 0;\r
160         }\r
161 \r
162         if (Driver)\r
163         {\r
164                 Driver->drop();\r
165                 Driver = 0;\r
166         }\r
167 }\r
168 \r
169 \r
170 void CGUIEnvironment::loadBuiltInFont()\r
171 {\r
172         io::IReadFile* file = FileSystem->createMemoryReadFile(BuiltInFontData,\r
173                                 BuiltInFontDataSize, DefaultFontName, false);\r
174 \r
175         CGUIFont* font = new CGUIFont(this, DefaultFontName );\r
176         if (!font->load(file))\r
177         {\r
178                 os::Printer::log("Error: Could not load built-in Font. Did you compile without the BMP loader?", ELL_ERROR);\r
179                 font->drop();\r
180                 file->drop();\r
181                 return;\r
182         }\r
183 \r
184         SFont f;\r
185         f.NamedPath.setPath(DefaultFontName);\r
186         f.Font = font;\r
187         Fonts.push_back(f);\r
188 \r
189         file->drop();\r
190 }\r
191 \r
192 \r
193 //! draws all gui elements\r
194 void CGUIEnvironment::drawAll()\r
195 {\r
196         if (Driver)\r
197         {\r
198                 core::dimension2d<s32> dim(Driver->getScreenSize());\r
199                 if (AbsoluteRect.LowerRightCorner.X != dim.Width ||\r
200                         AbsoluteRect.LowerRightCorner.Y != dim.Height)\r
201                 {\r
202                         // resize gui environment\r
203                         DesiredRect.LowerRightCorner = dim;\r
204                         AbsoluteClippingRect = DesiredRect;\r
205                         AbsoluteRect = DesiredRect;\r
206                         updateAbsolutePosition();\r
207                 }\r
208         }\r
209 \r
210         // make sure tooltip is always on top\r
211         if (ToolTip.Element)\r
212                 bringToFront(ToolTip.Element);\r
213 \r
214         draw();\r
215         OnPostRender ( os::Timer::getTime () );\r
216 }\r
217 \r
218 \r
219 //! sets the focus to an element\r
220 bool CGUIEnvironment::setFocus(IGUIElement* element)\r
221 {\r
222         if (Focus == element)\r
223         {\r
224                 return false;\r
225         }\r
226 \r
227         // GUI Environment should just reset the focus to 0\r
228         if (element == this)\r
229                 element = 0;\r
230 \r
231         // stop element from being deleted\r
232         if (element)\r
233                 element->grab();\r
234 \r
235         // focus may change or be removed in this call\r
236         IGUIElement *currentFocus = 0;\r
237         if (Focus)\r
238         {\r
239                 currentFocus = Focus;\r
240                 currentFocus->grab();\r
241                 SEvent e;\r
242                 e.EventType = EET_GUI_EVENT;\r
243                 e.GUIEvent.Caller = Focus;\r
244                 e.GUIEvent.Element = element;\r
245                 e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST;\r
246                 if (Focus->OnEvent(e))\r
247                 {\r
248                         if (element)\r
249                                 element->drop();\r
250                         currentFocus->drop();\r
251                         return false;\r
252                 }\r
253                 currentFocus->drop();\r
254                 currentFocus = 0;\r
255         }\r
256 \r
257         if (element)\r
258         {\r
259                 currentFocus = Focus;\r
260                 if (currentFocus)\r
261                         currentFocus->grab();\r
262 \r
263                 // send focused event\r
264                 SEvent e;\r
265                 e.EventType = EET_GUI_EVENT;\r
266                 e.GUIEvent.Caller = element;\r
267                 e.GUIEvent.Element = Focus;\r
268                 e.GUIEvent.EventType = EGET_ELEMENT_FOCUSED;\r
269                 if (element->OnEvent(e))\r
270                 {\r
271                         if (element)\r
272                                 element->drop();\r
273                         if (currentFocus)\r
274                                 currentFocus->drop();\r
275                         return false;\r
276                 }\r
277         }\r
278 \r
279         if (currentFocus)\r
280                 currentFocus->drop();\r
281 \r
282         if (Focus)\r
283                 Focus->drop();\r
284 \r
285         // element is the new focus so it doesn't have to be dropped\r
286         Focus = element;\r
287 \r
288         return true;\r
289 }\r
290 \r
291 \r
292 //! returns the element with the focus\r
293 IGUIElement* CGUIEnvironment::getFocus() const\r
294 {\r
295         return Focus;\r
296 }\r
297 \r
298 //! returns the element last known to be under the mouse cursor\r
299 IGUIElement* CGUIEnvironment::getHovered() const\r
300 {\r
301         return Hovered;\r
302 }\r
303 \r
304 \r
305 //! removes the focus from an element\r
306 bool CGUIEnvironment::removeFocus(IGUIElement* element)\r
307 {\r
308         if (Focus && Focus==element)\r
309         {\r
310                 SEvent e;\r
311                 e.EventType = EET_GUI_EVENT;\r
312                 e.GUIEvent.Caller = Focus;\r
313                 e.GUIEvent.Element = 0;\r
314                 e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST;\r
315                 if (Focus->OnEvent(e))\r
316                 {\r
317                         return false;\r
318                 }\r
319         }\r
320         if (Focus)\r
321         {\r
322                 Focus->drop();\r
323                 Focus = 0;\r
324         }\r
325 \r
326         return true;\r
327 }\r
328 \r
329 \r
330 //! Returns whether the element has focus\r
331 bool CGUIEnvironment::hasFocus(const IGUIElement* element, bool checkSubElements) const\r
332 {\r
333         if (element == Focus)\r
334                 return true;\r
335 \r
336         if ( !checkSubElements || !element )\r
337                 return false;\r
338 \r
339         IGUIElement* f = Focus;\r
340         while ( f && f->isSubElement() )\r
341         {\r
342                 f = f->getParent();\r
343                 if ( f == element )\r
344                         return true;\r
345         }\r
346         return false;\r
347 }\r
348 \r
349 \r
350 //! returns the current video driver\r
351 video::IVideoDriver* CGUIEnvironment::getVideoDriver() const\r
352 {\r
353         return Driver;\r
354 }\r
355 \r
356 \r
357 //! returns the current file system\r
358 io::IFileSystem* CGUIEnvironment::getFileSystem() const\r
359 {\r
360         return FileSystem;\r
361 }\r
362 \r
363 \r
364 //! returns a pointer to the OS operator\r
365 IOSOperator* CGUIEnvironment::getOSOperator() const\r
366 {\r
367         return Operator;\r
368 }\r
369 \r
370 \r
371 //! clear all GUI elements\r
372 void CGUIEnvironment::clear()\r
373 {\r
374         // Remove the focus\r
375         if (Focus)\r
376         {\r
377                 Focus->drop();\r
378                 Focus = 0;\r
379         }\r
380 \r
381         if (Hovered && Hovered != this)\r
382         {\r
383                 Hovered->drop();\r
384                 Hovered = 0;\r
385         }\r
386         if ( HoveredNoSubelement && HoveredNoSubelement != this)\r
387         {\r
388                 HoveredNoSubelement->drop();\r
389                 HoveredNoSubelement = 0;\r
390         }\r
391 \r
392         // get the root's children in case the root changes in future\r
393         const core::list<IGUIElement*>& children = getRootGUIElement()->getChildren();\r
394 \r
395         while (!children.empty())\r
396                 (*children.getLast())->remove();\r
397 }\r
398 \r
399 \r
400 //! called by ui if an event happened.\r
401 bool CGUIEnvironment::OnEvent(const SEvent& event)\r
402 {\r
403 \r
404         bool ret = false;\r
405         if (UserReceiver\r
406                 && (event.EventType != EET_MOUSE_INPUT_EVENT)\r
407                 && (event.EventType != EET_KEY_INPUT_EVENT)\r
408                 && (event.EventType != EET_GUI_EVENT || event.GUIEvent.Caller != this))\r
409         {\r
410                 ret = UserReceiver->OnEvent(event);\r
411         }\r
412 \r
413         return ret;\r
414 }\r
415 \r
416 //\r
417 void CGUIEnvironment::OnPostRender( u32 time )\r
418 {\r
419         // launch tooltip\r
420         if ( ToolTip.Element == 0 &&\r
421                 HoveredNoSubelement && HoveredNoSubelement != this &&\r
422                 (time - ToolTip.EnterTime >= ToolTip.LaunchTime\r
423                 || (time - ToolTip.LastTime >= ToolTip.RelaunchTime && time - ToolTip.LastTime < ToolTip.LaunchTime)) &&\r
424                 HoveredNoSubelement->getToolTipText().size() &&\r
425                 getSkin() &&\r
426                 getSkin()->getFont(EGDF_TOOLTIP)\r
427                 )\r
428         {\r
429                 core::rect<s32> pos;\r
430 \r
431                 pos.UpperLeftCorner = LastHoveredMousePos;\r
432                 core::dimension2du dim = getSkin()->getFont(EGDF_TOOLTIP)->getDimension(HoveredNoSubelement->getToolTipText().c_str());\r
433                 dim.Width += getSkin()->getSize(EGDS_TEXT_DISTANCE_X)*2;\r
434                 dim.Height += getSkin()->getSize(EGDS_TEXT_DISTANCE_Y)*2;\r
435 \r
436                 pos.UpperLeftCorner.Y -= dim.Height+1;\r
437                 pos.LowerRightCorner.Y = pos.UpperLeftCorner.Y + dim.Height-1;\r
438                 pos.LowerRightCorner.X = pos.UpperLeftCorner.X + dim.Width;\r
439 \r
440                 pos.constrainTo(getAbsolutePosition());\r
441 \r
442                 ToolTip.Element = addStaticText(HoveredNoSubelement->getToolTipText().c_str(), pos, true, true, this, -1, true);\r
443                 ToolTip.Element->setOverrideColor(getSkin()->getColor(EGDC_TOOLTIP));\r
444                 ToolTip.Element->setBackgroundColor(getSkin()->getColor(EGDC_TOOLTIP_BACKGROUND));\r
445                 ToolTip.Element->setOverrideFont(getSkin()->getFont(EGDF_TOOLTIP));\r
446                 ToolTip.Element->setSubElement(true);\r
447                 ToolTip.Element->grab();\r
448 \r
449                 s32 textHeight = ToolTip.Element->getTextHeight();\r
450                 pos = ToolTip.Element->getRelativePosition();\r
451                 pos.LowerRightCorner.Y = pos.UpperLeftCorner.Y + textHeight;\r
452                 ToolTip.Element->setRelativePosition(pos);\r
453         }\r
454 \r
455         if (ToolTip.Element && ToolTip.Element->isVisible() )   // (isVisible() check only because we might use visibility for ToolTip one day)\r
456         {\r
457                 ToolTip.LastTime = time;\r
458 \r
459                 // got invisible or removed in the meantime?\r
460                 if ( !HoveredNoSubelement ||\r
461                         !HoveredNoSubelement->isVisible() ||\r
462                         !HoveredNoSubelement->getParent()\r
463                         )       // got invisible or removed in the meantime?\r
464                 {\r
465                         ToolTip.Element->remove();\r
466                         ToolTip.Element->drop();\r
467                         ToolTip.Element = 0;\r
468                 }\r
469         }\r
470 \r
471         IGUIElement::OnPostRender ( time );\r
472 }\r
473 \r
474 \r
475 //\r
476 void CGUIEnvironment::updateHoveredElement(core::position2d<s32> mousePos)\r
477 {\r
478         IGUIElement* lastHovered = Hovered;\r
479         IGUIElement* lastHoveredNoSubelement = HoveredNoSubelement;\r
480         LastHoveredMousePos = mousePos;\r
481 \r
482         Hovered = getElementFromPoint(mousePos);\r
483 \r
484         if ( ToolTip.Element && Hovered == ToolTip.Element )\r
485         {\r
486                 // When the mouse is over the ToolTip we remove that so it will be re-created at a new position.\r
487                 // Note that ToolTip.EnterTime does not get changed here, so it will be re-created at once.\r
488                 ToolTip.Element->remove();\r
489                 ToolTip.Element->drop();\r
490                 ToolTip.Element = 0;\r
491 \r
492                 // Get the real Hovered\r
493                 Hovered = getElementFromPoint(mousePos);\r
494         }\r
495 \r
496         // for tooltips we want the element itself and not some of it's subelements\r
497         HoveredNoSubelement = Hovered;\r
498         while ( HoveredNoSubelement && HoveredNoSubelement->isSubElement() )\r
499         {\r
500                 HoveredNoSubelement = HoveredNoSubelement->getParent();\r
501         }\r
502 \r
503         if (Hovered && Hovered != this)\r
504                 Hovered->grab();\r
505         if ( HoveredNoSubelement && HoveredNoSubelement != this)\r
506                 HoveredNoSubelement->grab();\r
507 \r
508         if (Hovered != lastHovered)\r
509         {\r
510                 SEvent event;\r
511                 event.EventType = EET_GUI_EVENT;\r
512 \r
513                 if (lastHovered)\r
514                 {\r
515                         event.GUIEvent.Caller = lastHovered;\r
516                         event.GUIEvent.Element = 0;\r
517                         event.GUIEvent.EventType = EGET_ELEMENT_LEFT;\r
518                         lastHovered->OnEvent(event);\r
519                 }\r
520 \r
521                 if ( Hovered )\r
522                 {\r
523                         event.GUIEvent.Caller  = Hovered;\r
524                         event.GUIEvent.Element = Hovered;\r
525                         event.GUIEvent.EventType = EGET_ELEMENT_HOVERED;\r
526                         Hovered->OnEvent(event);\r
527                 }\r
528         }\r
529 \r
530         if ( lastHoveredNoSubelement != HoveredNoSubelement )\r
531         {\r
532                 if (ToolTip.Element)\r
533                 {\r
534                         ToolTip.Element->remove();\r
535                         ToolTip.Element->drop();\r
536                         ToolTip.Element = 0;\r
537                 }\r
538 \r
539                 if ( HoveredNoSubelement )\r
540                 {\r
541                         u32 now = os::Timer::getTime();\r
542                         ToolTip.EnterTime = now;\r
543                 }\r
544         }\r
545 \r
546         if (lastHovered && lastHovered != this)\r
547                 lastHovered->drop();\r
548         if (lastHoveredNoSubelement && lastHoveredNoSubelement != this)\r
549                 lastHoveredNoSubelement->drop();\r
550 }\r
551 \r
552 \r
553 //! This sets a new event receiver for gui events. Usually you do not have to\r
554 //! use this method, it is used by the internal engine.\r
555 void CGUIEnvironment::setUserEventReceiver(IEventReceiver* evr)\r
556 {\r
557         UserReceiver = evr;\r
558 }\r
559 \r
560 \r
561 //! posts an input event to the environment\r
562 bool CGUIEnvironment::postEventFromUser(const SEvent& event)\r
563 {\r
564         switch(event.EventType)\r
565         {\r
566         case EET_GUI_EVENT:\r
567                 {\r
568                         // hey, why is the user sending gui events..?\r
569                 }\r
570 \r
571                 break;\r
572         case EET_MOUSE_INPUT_EVENT:\r
573 \r
574                 updateHoveredElement(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));\r
575 \r
576                 if ( Hovered != Focus )\r
577                 {\r
578                         IGUIElement * focusCandidate = Hovered;\r
579 \r
580                         // Only allow enabled elements to be focused (unless EFF_CAN_FOCUS_DISABLED is set)\r
581                         if ( Hovered && !Hovered->isEnabled() && !(FocusFlags & EFF_CAN_FOCUS_DISABLED))\r
582                                 focusCandidate = NULL;  // we still remove focus from the active element\r
583 \r
584                         // Please don't merge this into a single if clause, it's easier to debug the way it is\r
585                         if (FocusFlags & EFF_SET_ON_LMOUSE_DOWN &&\r
586                                 event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN )\r
587                         {\r
588                                 setFocus(focusCandidate);\r
589                         }\r
590                         else if ( FocusFlags & EFF_SET_ON_RMOUSE_DOWN &&\r
591                                 event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN )\r
592                         {\r
593                                 setFocus(focusCandidate);\r
594                         }\r
595                         else if ( FocusFlags & EFF_SET_ON_MOUSE_OVER &&\r
596                                 event.MouseInput.Event == EMIE_MOUSE_MOVED )\r
597                         {\r
598                                 setFocus(focusCandidate);\r
599                         }\r
600                 }\r
601 \r
602                 // sending input to focus\r
603                 if (Focus && Focus->OnEvent(event))\r
604                         return true;\r
605 \r
606                 // focus could have died in last call\r
607                 if (!Focus && Hovered)\r
608                 {\r
609                         return Hovered->OnEvent(event);\r
610                 }\r
611 \r
612                 break;\r
613         case EET_KEY_INPUT_EVENT:\r
614                 {\r
615                         if (Focus && Focus->OnEvent(event))\r
616                                 return true;\r
617 \r
618                         // For keys we handle the event before changing focus to give elements the chance for catching the TAB\r
619                         // Send focus changing event\r
620                         if (FocusFlags & EFF_SET_ON_TAB &&\r
621                                 event.EventType == EET_KEY_INPUT_EVENT &&\r
622                                 event.KeyInput.PressedDown &&\r
623                                 event.KeyInput.Key == KEY_TAB)\r
624                         {\r
625                                 IGUIElement *next = getNextElement(event.KeyInput.Shift, event.KeyInput.Control);\r
626                                 if (next && next != Focus)\r
627                                 {\r
628                                         if (setFocus(next))\r
629                                                 return true;\r
630                                 }\r
631                         }\r
632                 }\r
633                 break;\r
634         default:\r
635                 break;\r
636         } // end switch\r
637 \r
638         return false;\r
639 }\r
640 \r
641 \r
642 //! returns the current gui skin\r
643 IGUISkin* CGUIEnvironment::getSkin() const\r
644 {\r
645         return CurrentSkin;\r
646 }\r
647 \r
648 \r
649 //! Sets a new GUI Skin\r
650 void CGUIEnvironment::setSkin(IGUISkin* skin)\r
651 {\r
652         if (CurrentSkin==skin)\r
653                 return;\r
654 \r
655         if (CurrentSkin)\r
656                 CurrentSkin->drop();\r
657 \r
658         CurrentSkin = skin;\r
659 \r
660         if (CurrentSkin)\r
661                 CurrentSkin->grab();\r
662 }\r
663 \r
664 \r
665 //! Creates a new GUI Skin based on a template.\r
666 /** \return Returns a pointer to the created skin.\r
667 If you no longer need the skin, you should call IGUISkin::drop().\r
668 See IReferenceCounted::drop() for more information. */\r
669 IGUISkin* CGUIEnvironment::createSkin(EGUI_SKIN_TYPE type)\r
670 {\r
671         IGUISkin* skin = new CGUISkin(type, Driver);\r
672 \r
673         IGUIFont* builtinfont = getBuiltInFont();\r
674         IGUIFontBitmap* bitfont = 0;\r
675         if (builtinfont && builtinfont->getType() == EGFT_BITMAP)\r
676                 bitfont = (IGUIFontBitmap*)builtinfont;\r
677 \r
678         IGUISpriteBank* bank = 0;\r
679         skin->setFont(builtinfont);\r
680 \r
681         if (bitfont)\r
682                 bank = bitfont->getSpriteBank();\r
683 \r
684         skin->setSpriteBank(bank);\r
685 \r
686         return skin;\r
687 }\r
688 \r
689 \r
690 //! Returns the default element factory which can create all built in elements\r
691 IGUIElementFactory* CGUIEnvironment::getDefaultGUIElementFactory() const\r
692 {\r
693         return getGUIElementFactory(0);\r
694 }\r
695 \r
696 \r
697 //! Adds an element factory to the gui environment.\r
698 /** Use this to extend the gui environment with new element types which it should be\r
699 able to create automatically, for example when loading data from xml files. */\r
700 void CGUIEnvironment::registerGUIElementFactory(IGUIElementFactory* factoryToAdd)\r
701 {\r
702         if (factoryToAdd)\r
703         {\r
704                 factoryToAdd->grab();\r
705                 GUIElementFactoryList.push_back(factoryToAdd);\r
706         }\r
707 }\r
708 \r
709 \r
710 //! Returns amount of registered scene node factories.\r
711 u32 CGUIEnvironment::getRegisteredGUIElementFactoryCount() const\r
712 {\r
713         return GUIElementFactoryList.size();\r
714 }\r
715 \r
716 \r
717 //! Returns a scene node factory by index\r
718 IGUIElementFactory* CGUIEnvironment::getGUIElementFactory(u32 index) const\r
719 {\r
720         if (index < GUIElementFactoryList.size())\r
721                 return GUIElementFactoryList[index];\r
722         else\r
723                 return 0;\r
724 }\r
725 \r
726 \r
727 //! adds a GUI Element using its name\r
728 IGUIElement* CGUIEnvironment::addGUIElement(const c8* elementName, IGUIElement* parent)\r
729 {\r
730         IGUIElement* node=0;\r
731 \r
732         if (!parent)\r
733                 parent = this;\r
734 \r
735         for (s32 i=GUIElementFactoryList.size()-1; i>=0 && !node; --i)\r
736                 node = GUIElementFactoryList[i]->addGUIElement(elementName, parent);\r
737 \r
738 \r
739         return node;\r
740 }\r
741 \r
742 \r
743 //! Saves the current gui into a file.\r
744 //! \param filename: Name of the file .\r
745 bool CGUIEnvironment::saveGUI(const io::path& filename, IGUIElement* start)\r
746 {\r
747         io::IWriteFile* file = FileSystem->createAndWriteFile(filename);\r
748         if (!file)\r
749         {\r
750                 return false;\r
751         }\r
752 \r
753         bool ret = saveGUI(file, start);\r
754         file->drop();\r
755         return ret;\r
756 }\r
757 \r
758 \r
759 //! Saves the current gui into a file.\r
760 bool CGUIEnvironment::saveGUI(io::IWriteFile* file, IGUIElement* start)\r
761 {\r
762         if (!file)\r
763         {\r
764                 return false;\r
765         }\r
766 \r
767         io::IXMLWriter* writer = FileSystem->createXMLWriter(file);\r
768         if (!writer)\r
769         {\r
770                 return false;\r
771         }\r
772 \r
773         writer->writeXMLHeader();\r
774         writeGUIElement(writer, start ? start : this);\r
775         writer->drop();\r
776 \r
777         return true;\r
778 }\r
779 \r
780 \r
781 //! Loads the gui. Note that the current gui is not cleared before.\r
782 //! \param filename: Name of the file.\r
783 bool CGUIEnvironment::loadGUI(const io::path& filename, IGUIElement* parent)\r
784 {\r
785         io::IReadFile* read = FileSystem->createAndOpenFile(filename);\r
786         if (!read)\r
787         {\r
788                 os::Printer::log("Unable to open gui file", filename, ELL_ERROR);\r
789                 return false;\r
790         }\r
791 \r
792         bool ret = loadGUI(read, parent);\r
793         read->drop();\r
794 \r
795         return ret;\r
796 }\r
797 \r
798 \r
799 //! Loads the gui. Note that the current gui is not cleared before.\r
800 bool CGUIEnvironment::loadGUI(io::IReadFile* file, IGUIElement* parent)\r
801 {\r
802         if (!file)\r
803         {\r
804                 os::Printer::log("Unable to open GUI file", ELL_ERROR);\r
805                 return false;\r
806         }\r
807 \r
808         io::IXMLReader* reader = FileSystem->createXMLReader(file);\r
809         if (!reader)\r
810         {\r
811                 os::Printer::log("GUI is not a valid XML file", file->getFileName(), ELL_ERROR);\r
812                 return false;\r
813         }\r
814 \r
815         // read file\r
816         while(reader->read())\r
817         {\r
818                 readGUIElement(reader, parent);\r
819         }\r
820 \r
821         // finish up\r
822 \r
823         reader->drop();\r
824         return true;\r
825 }\r
826 \r
827 \r
828 //! reads an element\r
829 void CGUIEnvironment::readGUIElement(io::IXMLReader* reader, IGUIElement* node)\r
830 {\r
831         if (!reader)\r
832                 return;\r
833 \r
834         io::EXML_NODE nodeType = reader->getNodeType();\r
835 \r
836         if (nodeType == io::EXN_NONE || nodeType == io::EXN_UNKNOWN || nodeType == io::EXN_ELEMENT_END)\r
837                 return;\r
838 \r
839         IGUIElement* deferedNode = 0;\r
840         if (!wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName()))\r
841         {\r
842                 // GuiEnvironment always must be this as it would serialize into a wrong element otherwise.\r
843                 // So we use the given node next time\r
844                 if ( node && node != this )\r
845                         deferedNode = node;\r
846                 node = this; // root\r
847         }\r
848         else if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()))\r
849         {\r
850                 // find node type and create it\r
851                 const core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE);\r
852 \r
853                 node = addGUIElement(attrName.c_str(), node);\r
854 \r
855                 if (!node)\r
856                         os::Printer::log("Could not create GUI element of unknown type", attrName.c_str());\r
857         }\r
858 \r
859         // read attributes\r
860 \r
861         while(reader->read())\r
862         {\r
863                 bool endreached = false;\r
864 \r
865                 switch (reader->getNodeType())\r
866                 {\r
867                 case io::EXN_ELEMENT_END:\r
868                         if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT,  reader->getNodeName()) ||\r
869                                 !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName()))\r
870                         {\r
871                                 endreached = true;\r
872                         }\r
873                         break;\r
874                 case io::EXN_ELEMENT:\r
875                         if (!wcscmp(L"attributes", reader->getNodeName()))\r
876                         {\r
877                                 // read attributes\r
878                                 io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver);\r
879                                 attr->read(reader, true);\r
880 \r
881                                 if (node)\r
882                                         node->deserializeAttributes(attr);\r
883 \r
884                                 attr->drop();\r
885                         }\r
886                         else\r
887                         if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) ||\r
888                                 !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName()))\r
889                         {\r
890                                 if ( deferedNode )\r
891                                         readGUIElement(reader, deferedNode);\r
892                                 else\r
893                                         readGUIElement(reader, node);\r
894                         }\r
895                         else\r
896                         {\r
897                                 os::Printer::log("Found unknown element in irrlicht GUI file",\r
898                                                 core::stringc(reader->getNodeName()).c_str());\r
899                         }\r
900 \r
901                         break;\r
902                 default:\r
903                         break;\r
904                 }\r
905 \r
906                 if (endreached)\r
907                         break;\r
908         }\r
909 }\r
910 \r
911 \r
912 //! writes an element\r
913 void CGUIEnvironment::writeGUIElement(io::IXMLWriter* writer, IGUIElement* node)\r
914 {\r
915         if (!writer || !node )\r
916                 return;\r
917 \r
918         const wchar_t* name = 0;\r
919 \r
920         // write properties\r
921 \r
922         io::IAttributes* attr = FileSystem->createEmptyAttributes();\r
923         node->serializeAttributes(attr);\r
924 \r
925         // all gui elements must have at least one attribute\r
926         // if they have nothing then we ignore them.\r
927         if (attr->getAttributeCount() != 0)\r
928         {\r
929                 if (node == this)\r
930                 {\r
931                         name = IRR_XML_FORMAT_GUI_ENV;\r
932                         writer->writeElement(name, false);\r
933                 }\r
934                 else\r
935                 {\r
936                         name = IRR_XML_FORMAT_GUI_ELEMENT;\r
937                         writer->writeElement(name, false, IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE,\r
938                                 core::stringw(node->getTypeName()).c_str());\r
939                 }\r
940 \r
941                 writer->writeLineBreak();\r
942 \r
943                 attr->write(writer);\r
944         }\r
945 \r
946         // write children\r
947 \r
948         core::list<IGUIElement*>::ConstIterator it = node->getChildren().begin();\r
949         for (; it != node->getChildren().end(); ++it)\r
950         {\r
951                 if (!(*it)->isSubElement())\r
952                 {\r
953                         writer->writeLineBreak();\r
954                         writeGUIElement(writer, (*it));\r
955                 }\r
956         }\r
957 \r
958         // write closing brace if required\r
959         if (attr->getAttributeCount() != 0)\r
960         {\r
961                 writer->writeClosingTag(name);\r
962                 writer->writeLineBreak();\r
963         }\r
964 \r
965         attr->drop();\r
966 }\r
967 \r
968 \r
969 //! Writes attributes of the environment\r
970 void CGUIEnvironment::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const\r
971 {\r
972         IGUISkin* skin = getSkin();\r
973 \r
974         if (skin)\r
975         {\r
976                 out->addEnum("Skin", getSkin()->getType(), GUISkinTypeNames);\r
977                 skin->serializeAttributes(out, options);\r
978         }\r
979 }\r
980 \r
981 \r
982 //! Reads attributes of the environment\r
983 void CGUIEnvironment::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)\r
984 {\r
985         if (in->existsAttribute("Skin"))\r
986         {\r
987                 IGUISkin *skin = getSkin();\r
988 \r
989                 EGUI_SKIN_TYPE t = (EGUI_SKIN_TYPE) in->getAttributeAsEnumeration("Skin",GUISkinTypeNames);\r
990                 if ( !skin || t != skin->getType())\r
991                 {\r
992                         skin = createSkin(t);\r
993                         setSkin(skin);\r
994                         skin->drop();\r
995                 }\r
996 \r
997                 skin = getSkin();\r
998 \r
999                 if (skin)\r
1000                 {\r
1001                         skin->deserializeAttributes(in, options);\r
1002                 }\r
1003 \r
1004         }\r
1005 \r
1006         RelativeRect = AbsoluteRect =\r
1007                         core::rect<s32>(Driver ? core::dimension2di(Driver->getScreenSize()) : core::dimension2d<s32>(0,0));\r
1008 }\r
1009 \r
1010 \r
1011 //! adds a button. The returned pointer must not be dropped.\r
1012 IGUIButton* CGUIEnvironment::addButton(const core::rect<s32>& rectangle, IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext)\r
1013 {\r
1014         IGUIButton* button = new CGUIButton(this, parent ? parent : this, id, rectangle);\r
1015         if (text)\r
1016                 button->setText(text);\r
1017 \r
1018         if ( tooltiptext )\r
1019                 button->setToolTipText ( tooltiptext );\r
1020 \r
1021         button->drop();\r
1022         return button;\r
1023 }\r
1024 \r
1025 \r
1026 //! adds a window. The returned pointer must not be dropped.\r
1027 IGUIWindow* CGUIEnvironment::addWindow(const core::rect<s32>& rectangle, bool modal,\r
1028                 const wchar_t* text, IGUIElement* parent, s32 id)\r
1029 {\r
1030         parent = parent ? parent : this;\r
1031 \r
1032         IGUIWindow* win = new CGUIWindow(this, parent, id, rectangle);\r
1033         if (text)\r
1034                 win->setText(text);\r
1035         win->drop();\r
1036 \r
1037         if (modal)\r
1038         {\r
1039                 // Careful, don't just set the modal as parent above. That will mess up the focus (and is hard to change because we have to be very\r
1040                 // careful not to get virtual function call, like OnEvent, in the window.\r
1041                 CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1);\r
1042                 modalScreen->drop();\r
1043                 modalScreen->addChild(win);\r
1044         }\r
1045 \r
1046         return win;\r
1047 }\r
1048 \r
1049 \r
1050 //! adds a modal screen. The returned pointer must not be dropped.\r
1051 IGUIElement* CGUIEnvironment::addModalScreen(IGUIElement* parent)\r
1052 {\r
1053         parent = parent ? parent : this;\r
1054 \r
1055         IGUIElement *win = new CGUIModalScreen(this, parent, -1);\r
1056         win->drop();\r
1057 \r
1058         return win;\r
1059 }\r
1060 \r
1061 \r
1062 //! Adds a message box.\r
1063 IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t* text,\r
1064         bool modal, s32 flag, IGUIElement* parent, s32 id, video::ITexture* image)\r
1065 {\r
1066         if (!CurrentSkin)\r
1067                 return 0;\r
1068 \r
1069         parent = parent ? parent : this;\r
1070 \r
1071         core::rect<s32> rect;\r
1072         core::dimension2d<u32> screenDim, msgBoxDim;\r
1073 \r
1074         screenDim.Width = parent->getAbsolutePosition().getWidth();\r
1075         screenDim.Height = parent->getAbsolutePosition().getHeight();\r
1076         msgBoxDim.Width = 2;\r
1077         msgBoxDim.Height = 2;\r
1078 \r
1079         rect.UpperLeftCorner.X = (screenDim.Width - msgBoxDim.Width) / 2;\r
1080         rect.UpperLeftCorner.Y = (screenDim.Height - msgBoxDim.Height) / 2;\r
1081         rect.LowerRightCorner.X = rect.UpperLeftCorner.X + msgBoxDim.Width;\r
1082         rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + msgBoxDim.Height;\r
1083 \r
1084         IGUIWindow* win = new CGUIMessageBox(this, caption, text, flag,\r
1085                 parent, id, rect, image);\r
1086         win->drop();\r
1087 \r
1088         if (modal)\r
1089         {\r
1090                 // Careful, don't just set the modal as parent above. That will mess up the focus (and is hard to change because we have to be very\r
1091                 // careful not to get virtual function call, like OnEvent, in the CGUIMessageBox.\r
1092                 CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1);\r
1093                 modalScreen->drop();\r
1094                 modalScreen->addChild( win );\r
1095         }\r
1096 \r
1097 \r
1098         return win;\r
1099 }\r
1100 \r
1101 \r
1102 //! adds a scrollbar. The returned pointer must not be dropped.\r
1103 IGUIScrollBar* CGUIEnvironment::addScrollBar(bool horizontal, const core::rect<s32>& rectangle, IGUIElement* parent, s32 id)\r
1104 {\r
1105         IGUIScrollBar* bar = new CGUIScrollBar(horizontal, this, parent ? parent : this, id, rectangle);\r
1106         bar->drop();\r
1107         return bar;\r
1108 }\r
1109 \r
1110 //! Adds a table to the environment\r
1111 IGUITable* CGUIEnvironment::addTable(const core::rect<s32>& rectangle, IGUIElement* parent, s32 id, bool drawBackground)\r
1112 {\r
1113         CGUITable* b = new CGUITable(this, parent ? parent : this, id, rectangle, true, drawBackground, false);\r
1114         b->drop();\r
1115         return b;\r
1116 }\r
1117 \r
1118         //! Adds an element to display the information from the Irrlicht profiler\r
1119 IGUIProfiler* CGUIEnvironment::addProfilerDisplay(const core::rect<s32>& rectangle, IGUIElement* parent, s32 id)\r
1120 {\r
1121         CGUIProfiler* p = new CGUIProfiler(this, parent ? parent : this, id, rectangle, NULL);\r
1122         p->drop();\r
1123         return p;\r
1124 }\r
1125 \r
1126 //! Adds an image element.\r
1127 IGUIImage* CGUIEnvironment::addImage(video::ITexture* image, core::position2d<s32> pos,\r
1128         bool useAlphaChannel, IGUIElement* parent, s32 id, const wchar_t* text)\r
1129 {\r
1130         core::dimension2d<s32> sz(0,0);\r
1131         if (image)\r
1132                 sz = core::dimension2d<s32>(image->getOriginalSize());\r
1133 \r
1134         IGUIImage* img = new CGUIImage(this, parent ? parent : this,\r
1135                 id, core::rect<s32>(pos, sz));\r
1136 \r
1137         if (text)\r
1138                 img->setText(text);\r
1139 \r
1140         if (useAlphaChannel)\r
1141                 img->setUseAlphaChannel(true);\r
1142 \r
1143         if (image)\r
1144                 img->setImage(image);\r
1145 \r
1146         img->drop();\r
1147         return img;\r
1148 }\r
1149 \r
1150 \r
1151 //! adds an image. The returned pointer must not be dropped.\r
1152 IGUIImage* CGUIEnvironment::addImage(const core::rect<s32>& rectangle, IGUIElement* parent, s32 id, const wchar_t* text, bool useAlphaChannel)\r
1153 {\r
1154         IGUIImage* img = new CGUIImage(this, parent ? parent : this,\r
1155                 id, rectangle);\r
1156 \r
1157         if (text)\r
1158                 img->setText(text);\r
1159 \r
1160         if ( useAlphaChannel )\r
1161                 img->setUseAlphaChannel(true);\r
1162 \r
1163         img->drop();\r
1164         return img;\r
1165 }\r
1166 \r
1167 \r
1168 //! adds an mesh viewer. The returned pointer must not be dropped.\r
1169 IGUIMeshViewer* CGUIEnvironment::addMeshViewer(const core::rect<s32>& rectangle, IGUIElement* parent, s32 id, const wchar_t* text)\r
1170 {\r
1171         IGUIMeshViewer* v = new CGUIMeshViewer(this, parent ? parent : this,\r
1172                 id, rectangle);\r
1173 \r
1174         if (text)\r
1175                 v->setText(text);\r
1176 \r
1177         v->drop();\r
1178         return v;\r
1179 }\r
1180 \r
1181 \r
1182 //! adds a checkbox\r
1183 IGUICheckBox* CGUIEnvironment::addCheckBox(bool checked, const core::rect<s32>& rectangle, IGUIElement* parent, s32 id, const wchar_t* text)\r
1184 {\r
1185         IGUICheckBox* b = new CGUICheckBox(checked, this,\r
1186                 parent ? parent : this , id , rectangle);\r
1187 \r
1188         if (text)\r
1189                 b->setText(text);\r
1190 \r
1191         b->drop();\r
1192         return b;\r
1193 }\r
1194 \r
1195 \r
1196 //! adds a list box\r
1197 IGUIListBox* CGUIEnvironment::addListBox(const core::rect<s32>& rectangle,\r
1198                                         IGUIElement* parent, s32 id, bool drawBackground)\r
1199 {\r
1200         IGUIListBox* b = new CGUIListBox(this, parent ? parent : this, id, rectangle,\r
1201                 true, drawBackground, false);\r
1202 \r
1203         if (CurrentSkin && CurrentSkin->getSpriteBank())\r
1204         {\r
1205                 b->setSpriteBank(CurrentSkin->getSpriteBank());\r
1206         }\r
1207         else if (getBuiltInFont() && getBuiltInFont()->getType() == EGFT_BITMAP)\r
1208         {\r
1209                 b->setSpriteBank( ((IGUIFontBitmap*)getBuiltInFont())->getSpriteBank());\r
1210         }\r
1211 \r
1212         b->drop();\r
1213         return b;\r
1214 }\r
1215 \r
1216 //! adds a tree view\r
1217 IGUITreeView* CGUIEnvironment::addTreeView(const core::rect<s32>& rectangle,\r
1218                                          IGUIElement* parent, s32 id,\r
1219                                          bool drawBackground,\r
1220                                          bool scrollBarVertical, bool scrollBarHorizontal)\r
1221 {\r
1222         IGUITreeView* b = new CGUITreeView(this, parent ? parent : this, id, rectangle,\r
1223                 true, drawBackground, scrollBarVertical, scrollBarHorizontal);\r
1224 \r
1225         b->setIconFont ( getBuiltInFont () );\r
1226         b->drop();\r
1227         return b;\r
1228 }\r
1229 \r
1230 //! adds a file open dialog. The returned pointer must not be dropped.\r
1231 IGUIFileOpenDialog* CGUIEnvironment::addFileOpenDialog(const wchar_t* title,\r
1232                                 bool modal, IGUIElement* parent, s32 id,\r
1233                                 bool restoreCWD, io::path::char_type* startDir)\r
1234 {\r
1235         parent = parent ? parent : this;\r
1236 \r
1237         IGUIFileOpenDialog* d = new CGUIFileOpenDialog(title, this, parent, id,\r
1238                         restoreCWD, startDir);\r
1239         d->drop();\r
1240 \r
1241         if (modal)\r
1242         {\r
1243                 // Careful, don't just set the modal as parent above. That will mess up the focus (and is hard to change because we have to be very\r
1244                 // careful not to get virtual function call, like OnEvent, in the window.\r
1245                 CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1);\r
1246                 modalScreen->drop();\r
1247                 modalScreen->addChild(d);\r
1248         }\r
1249 \r
1250         return d;\r
1251 }\r
1252 \r
1253 \r
1254 //! adds a color select dialog. The returned pointer must not be dropped.\r
1255 IGUIColorSelectDialog* CGUIEnvironment::addColorSelectDialog(const wchar_t* title,\r
1256                                 bool modal, IGUIElement* parent, s32 id)\r
1257 {\r
1258         parent = parent ? parent : this;\r
1259 \r
1260         IGUIColorSelectDialog* d = new CGUIColorSelectDialog( title,\r
1261                         this, parent, id);\r
1262         d->drop();\r
1263 \r
1264         if (modal)\r
1265         {\r
1266                 // Careful, don't just set the modal as parent above. That will mess up the focus (and is hard to change because we have to be very\r
1267                 // careful not to get virtual function call, like OnEvent, in the window.\r
1268                 CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1);\r
1269                 modalScreen->drop();\r
1270                 modalScreen->addChild(d);\r
1271         }\r
1272 \r
1273         return d;\r
1274 }\r
1275 \r
1276 \r
1277 //! adds a static text. The returned pointer must not be dropped.\r
1278 IGUIStaticText* CGUIEnvironment::addStaticText(const wchar_t* text,\r
1279                                 const core::rect<s32>& rectangle,\r
1280                                 bool border, bool wordWrap,\r
1281                                 IGUIElement* parent, s32 id, bool background)\r
1282 {\r
1283         IGUIStaticText* d = new CGUIStaticText(text, border, this,\r
1284                         parent ? parent : this, id, rectangle, background);\r
1285 \r
1286         d->setWordWrap(wordWrap);\r
1287         d->drop();\r
1288 \r
1289         return d;\r
1290 }\r
1291 \r
1292 \r
1293 //! Adds an edit box. The returned pointer must not be dropped.\r
1294 IGUIEditBox* CGUIEnvironment::addEditBox(const wchar_t* text,\r
1295                         const core::rect<s32>& rectangle, bool border,\r
1296                         IGUIElement* parent, s32 id)\r
1297 {\r
1298         IGUIEditBox* d = new CGUIEditBox(text, border, this,\r
1299                         parent ? parent : this, id, rectangle);\r
1300 \r
1301         d->drop();\r
1302         return d;\r
1303 }\r
1304 \r
1305 \r
1306 //! Adds a spin box to the environment\r
1307 IGUISpinBox* CGUIEnvironment::addSpinBox(const wchar_t* text,\r
1308                                          const core::rect<s32> &rectangle,\r
1309                                          bool border,IGUIElement* parent, s32 id)\r
1310 {\r
1311         IGUISpinBox* d = new CGUISpinBox(text, border,this,\r
1312                 parent ? parent : this, id, rectangle);\r
1313 \r
1314         d->drop();\r
1315         return d;\r
1316 }\r
1317 \r
1318 \r
1319 //! Adds a tab control to the environment.\r
1320 IGUITabControl* CGUIEnvironment::addTabControl(const core::rect<s32>& rectangle,\r
1321         IGUIElement* parent, bool fillbackground, bool border, s32 id)\r
1322 {\r
1323         IGUITabControl* t = new CGUITabControl(this, parent ? parent : this,\r
1324                 rectangle, fillbackground, border, id);\r
1325         t->drop();\r
1326         return t;\r
1327 }\r
1328 \r
1329 \r
1330 //! Adds tab to the environment.\r
1331 IGUITab* CGUIEnvironment::addTab(const core::rect<s32>& rectangle,\r
1332         IGUIElement* parent, s32 id)\r
1333 {\r
1334         IGUITab* t = new CGUITab(this, parent ? parent : this,\r
1335                 rectangle, id);\r
1336         t->drop();\r
1337         return t;\r
1338 }\r
1339 \r
1340 \r
1341 //! Adds a context menu to the environment.\r
1342 IGUIContextMenu* CGUIEnvironment::addContextMenu(const core::rect<s32>& rectangle,\r
1343         IGUIElement* parent, s32 id)\r
1344 {\r
1345         IGUIContextMenu* c = new CGUIContextMenu(this,\r
1346                 parent ? parent : this, id, rectangle, true);\r
1347         c->drop();\r
1348         return c;\r
1349 }\r
1350 \r
1351 \r
1352 //! Adds a menu to the environment.\r
1353 IGUIContextMenu* CGUIEnvironment::addMenu(IGUIElement* parent, s32 id)\r
1354 {\r
1355         if (!parent)\r
1356                 parent = this;\r
1357 \r
1358         IGUIContextMenu* c = new CGUIMenu(this,\r
1359                 parent, id, core::rect<s32>(0,0,\r
1360                                 parent->getAbsolutePosition().getWidth(),\r
1361                                 parent->getAbsolutePosition().getHeight()));\r
1362 \r
1363         c->drop();\r
1364         return c;\r
1365 }\r
1366 \r
1367 \r
1368 //! Adds a toolbar to the environment. It is like a menu is always placed on top\r
1369 //! in its parent, and contains buttons.\r
1370 IGUIToolBar* CGUIEnvironment::addToolBar(IGUIElement* parent, s32 id)\r
1371 {\r
1372         if (!parent)\r
1373                 parent = this;\r
1374 \r
1375         IGUIToolBar* b = new CGUIToolBar(this, parent, id, core::rect<s32>(0,0,10,10));\r
1376         b->drop();\r
1377         return b;\r
1378 }\r
1379 \r
1380 \r
1381 //! Adds an element for fading in or out.\r
1382 IGUIInOutFader* CGUIEnvironment::addInOutFader(const core::rect<s32>* rectangle, IGUIElement* parent, s32 id)\r
1383 {\r
1384         core::rect<s32> rect;\r
1385 \r
1386         if (rectangle)\r
1387                 rect = *rectangle;\r
1388         else if (Driver)\r
1389                 rect = core::rect<s32>(core::dimension2di(Driver->getScreenSize()));\r
1390 \r
1391         if (!parent)\r
1392                 parent = this;\r
1393 \r
1394         IGUIInOutFader* fader = new CGUIInOutFader(this, parent, id, rect);\r
1395         fader->drop();\r
1396         return fader;\r
1397 }\r
1398 \r
1399 \r
1400 //! Adds a combo box to the environment.\r
1401 IGUIComboBox* CGUIEnvironment::addComboBox(const core::rect<s32>& rectangle,\r
1402         IGUIElement* parent, s32 id)\r
1403 {\r
1404         IGUIComboBox* t = new CGUIComboBox(this, parent ? parent : this,\r
1405                 id, rectangle);\r
1406         t->drop();\r
1407         return t;\r
1408 }\r
1409 \r
1410 \r
1411 //! returns the font\r
1412 IGUIFont* CGUIEnvironment::getFont(const io::path& filename)\r
1413 {\r
1414         // search existing font\r
1415 \r
1416         SFont f;\r
1417         f.NamedPath.setPath(filename);\r
1418 \r
1419         s32 index = Fonts.binary_search(f);\r
1420         if (index != -1)\r
1421                 return Fonts[index].Font;\r
1422 \r
1423         // font doesn't exist, attempt to load it\r
1424 \r
1425         // does the file exist?\r
1426 \r
1427         if (!FileSystem->existFile(filename))\r
1428         {\r
1429                 os::Printer::log("Could not load font because the file does not exist", f.NamedPath.getPath(), ELL_ERROR);\r
1430                 return 0;\r
1431         }\r
1432 \r
1433         IGUIFont* ifont=0;\r
1434         io::IXMLReader *xml = FileSystem->createXMLReader(filename );\r
1435         if (xml)\r
1436         {\r
1437                 // this is an XML font, but we need to know what type\r
1438                 EGUI_FONT_TYPE t = EGFT_CUSTOM;\r
1439 \r
1440                 bool found=false;\r
1441                 while(!found && xml->read())\r
1442                 {\r
1443                         if (xml->getNodeType() == io::EXN_ELEMENT)\r
1444                         {\r
1445                                 if (core::stringw(L"font") == xml->getNodeName())\r
1446                                 {\r
1447                                         if (core::stringw(L"vector") == xml->getAttributeValue(L"type"))\r
1448                                         {\r
1449                                                 t = EGFT_VECTOR;\r
1450                                                 found=true;\r
1451                                         }\r
1452                                         else if (core::stringw(L"bitmap") == xml->getAttributeValue(L"type"))\r
1453                                         {\r
1454                                                 t = EGFT_BITMAP;\r
1455                                                 found=true;\r
1456                                         }\r
1457                                         else found=true;\r
1458                                 }\r
1459                         }\r
1460                 }\r
1461 \r
1462                 if (t==EGFT_BITMAP)\r
1463                 {\r
1464                         CGUIFont* font = new CGUIFont(this, filename);\r
1465                         ifont = (IGUIFont*)font;\r
1466 \r
1467                         // load the font\r
1468                         io::path directory;\r
1469                         core::splitFilename(filename, &directory);\r
1470                         if (!font->load(xml, directory))\r
1471                         {\r
1472                                 font->drop();\r
1473                                 font  = 0;\r
1474                                 ifont = 0;\r
1475                         }\r
1476                 }\r
1477                 else if (t==EGFT_VECTOR)\r
1478                 {\r
1479                         // todo: vector fonts\r
1480                         os::Printer::log("Unable to load font, XML vector fonts are not supported yet", f.NamedPath, ELL_ERROR);\r
1481 \r
1482                         //CGUIFontVector* font = new CGUIFontVector(Driver);\r
1483                         //ifont = (IGUIFont*)font;\r
1484                         //if (!font->load(xml))\r
1485                 }\r
1486                 xml->drop();\r
1487         }\r
1488 \r
1489 \r
1490         if (!ifont)\r
1491         {\r
1492 \r
1493                 CGUIFont* font = new CGUIFont(this, f.NamedPath.getPath() );\r
1494                 ifont = (IGUIFont*)font;\r
1495                 if (!font->load(f.NamedPath.getPath()))\r
1496                 {\r
1497                         font->drop();\r
1498                         return 0;\r
1499                 }\r
1500         }\r
1501 \r
1502         // add to fonts.\r
1503 \r
1504         f.Font = ifont;\r
1505         Fonts.push_back(f);\r
1506 \r
1507         return ifont;\r
1508 }\r
1509 \r
1510 \r
1511 //! add an externally loaded font\r
1512 IGUIFont* CGUIEnvironment::addFont(const io::path& name, IGUIFont* font)\r
1513 {\r
1514         if (font)\r
1515         {\r
1516                 SFont f;\r
1517                 f.NamedPath.setPath(name);\r
1518                 s32 index = Fonts.binary_search(f);\r
1519                 if (index != -1)\r
1520                         return Fonts[index].Font;\r
1521                 f.Font = font;\r
1522                 Fonts.push_back(f);\r
1523                 font->grab();\r
1524         }\r
1525         return font;\r
1526 }\r
1527 \r
1528 //! remove loaded font\r
1529 void CGUIEnvironment::removeFont(IGUIFont* font)\r
1530 {\r
1531         if ( !font )\r
1532                 return;\r
1533         for ( u32 i=0; i<Fonts.size(); ++i )\r
1534         {\r
1535                 if ( Fonts[i].Font == font )\r
1536                 {\r
1537                         Fonts[i].Font->drop();\r
1538                         Fonts.erase(i);\r
1539                         return;\r
1540                 }\r
1541         }\r
1542 }\r
1543 \r
1544 //! returns default font\r
1545 IGUIFont* CGUIEnvironment::getBuiltInFont() const\r
1546 {\r
1547         if (Fonts.empty())\r
1548                 return 0;\r
1549 \r
1550         return Fonts[0].Font;\r
1551 }\r
1552 \r
1553 \r
1554 IGUISpriteBank* CGUIEnvironment::getSpriteBank(const io::path& filename)\r
1555 {\r
1556         // search for the file name\r
1557 \r
1558         SSpriteBank b;\r
1559         b.NamedPath.setPath(filename);\r
1560 \r
1561         s32 index = Banks.binary_search(b);\r
1562         if (index != -1)\r
1563                 return Banks[index].Bank;\r
1564 \r
1565         // we don't have this sprite bank, we should load it\r
1566         if (!FileSystem->existFile(b.NamedPath.getPath()))\r
1567         {\r
1568                 if ( filename != DefaultFontName )\r
1569                 {\r
1570                         os::Printer::log("Could not load sprite bank because the file does not exist", b.NamedPath.getPath(), ELL_DEBUG);\r
1571                 }\r
1572                 return 0;\r
1573         }\r
1574 \r
1575         // todo: load it!\r
1576 \r
1577         return 0;\r
1578 }\r
1579 \r
1580 \r
1581 IGUISpriteBank* CGUIEnvironment::addEmptySpriteBank(const io::path& name)\r
1582 {\r
1583         // no duplicate names allowed\r
1584 \r
1585         SSpriteBank b;\r
1586         b.NamedPath.setPath(name);\r
1587 \r
1588         const s32 index = Banks.binary_search(b);\r
1589         if (index != -1)\r
1590                 return 0;\r
1591 \r
1592         // create a new sprite bank\r
1593 \r
1594         b.Bank = new CGUISpriteBank(this);\r
1595         Banks.push_back(b);\r
1596 \r
1597         return b.Bank;\r
1598 }\r
1599 \r
1600 \r
1601 //! Creates the image list from the given texture.\r
1602 IGUIImageList* CGUIEnvironment::createImageList(  video::ITexture* texture,\r
1603                                         core::dimension2d<s32>  imageSize, bool useAlphaChannel )\r
1604 {\r
1605         CGUIImageList* imageList = new CGUIImageList( Driver );\r
1606         if( !imageList->createImageList( texture, imageSize, useAlphaChannel ) )\r
1607         {\r
1608                 imageList->drop();\r
1609                 return 0;\r
1610         }\r
1611 \r
1612         return imageList;\r
1613 }\r
1614 \r
1615 //! Returns the root gui element.\r
1616 IGUIElement* CGUIEnvironment::getRootGUIElement()\r
1617 {\r
1618         return this;\r
1619 }\r
1620 \r
1621 \r
1622 //! Returns the next element in the tab group starting at the focused element\r
1623 IGUIElement* CGUIEnvironment::getNextElement(bool reverse, bool group)\r
1624 {\r
1625         // start the search at the root of the current tab group\r
1626         IGUIElement *startPos = Focus ? Focus->getTabGroup() : 0;\r
1627         s32 startOrder = -1;\r
1628 \r
1629         // if we're searching for a group\r
1630         if (group && startPos)\r
1631         {\r
1632                 startOrder = startPos->getTabOrder();\r
1633         }\r
1634         else\r
1635         if (!group && Focus && !Focus->isTabGroup())\r
1636         {\r
1637                 startOrder = Focus->getTabOrder();\r
1638                 if (startOrder == -1)\r
1639                 {\r
1640                         // this element is not part of the tab cycle,\r
1641                         // but its parent might be...\r
1642                         IGUIElement *el = Focus;\r
1643                         while (el && el->getParent() && startOrder == -1)\r
1644                         {\r
1645                                 el = el->getParent();\r
1646                                 startOrder = el->getTabOrder();\r
1647                         }\r
1648 \r
1649                 }\r
1650         }\r
1651 \r
1652         if (group || !startPos)\r
1653                 startPos = this; // start at the root\r
1654 \r
1655         // find the element\r
1656         IGUIElement *closest = 0;\r
1657         IGUIElement *first = 0;\r
1658         startPos->getNextElement(startOrder, reverse, group, first, closest, false, (FocusFlags & EFF_CAN_FOCUS_DISABLED) != 0);\r
1659 \r
1660         if (closest)\r
1661                 return closest; // we found an element\r
1662         else if (first)\r
1663                 return first; // go to the end or the start\r
1664         else if (group)\r
1665                 return this; // no group found? root group\r
1666         else\r
1667                 return 0;\r
1668 }\r
1669 \r
1670 void CGUIEnvironment::setFocusBehavior(u32 flags)\r
1671 {\r
1672         FocusFlags = flags;\r
1673 }\r
1674 \r
1675 u32 CGUIEnvironment::getFocusBehavior() const\r
1676 {\r
1677         return FocusFlags;\r
1678 }\r
1679 \r
1680 //! creates an GUI Environment\r
1681 IGUIEnvironment* createGUIEnvironment(io::IFileSystem* fs,\r
1682                                         video::IVideoDriver* Driver,\r
1683                                         IOSOperator* op)\r
1684 {\r
1685         return new CGUIEnvironment(fs, Driver, op);\r
1686 }\r
1687 \r
1688 \r
1689 } // end namespace gui\r
1690 } // end namespace irr\r
1691 \r
1692 #endif // _IRR_COMPILE_WITH_GUI_\r
1693 \r