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