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