// Copyright (C) 2002-2012 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CGUIEnvironment.h" #include "IVideoDriver.h" #include "CGUISkin.h" #include "CGUIButton.h" #include "CGUIScrollBar.h" #include "CGUIFont.h" #include "CGUISpriteBank.h" #include "CGUIImage.h" #include "CGUICheckBox.h" #include "CGUIListBox.h" #include "CGUIImageList.h" #include "CGUIFileOpenDialog.h" #include "CGUIStaticText.h" #include "CGUIEditBox.h" #include "CGUITabControl.h" #include "CGUIComboBox.h" #include "IWriteFile.h" #ifdef IRR_ENABLE_BUILTIN_FONT #include "BuiltInFont.h" #endif #include "os.h" namespace irr { namespace gui { const io::path CGUIEnvironment::DefaultFontName = "#DefaultFont"; //! constructor CGUIEnvironment::CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* driver, IOSOperator* op) : IGUIElement(EGUIET_ROOT, 0, 0, 0, core::rect(driver ? core::dimension2d(driver->getScreenSize()) : core::dimension2d(0,0))), Driver(driver), Hovered(0), HoveredNoSubelement(0), Focus(0), LastHoveredMousePos(0,0), CurrentSkin(0), FileSystem(fs), UserReceiver(0), Operator(op), FocusFlags(EFF_SET_ON_LMOUSE_DOWN|EFF_SET_ON_TAB) { if (Driver) Driver->grab(); if (FileSystem) FileSystem->grab(); if (Operator) Operator->grab(); #ifdef _DEBUG IGUIEnvironment::setDebugName("CGUIEnvironment"); #endif loadBuiltInFont(); IGUISkin* skin = createSkin( gui::EGST_WINDOWS_METALLIC ); setSkin(skin); skin->drop(); //set tooltip default ToolTip.LastTime = 0; ToolTip.EnterTime = 0; ToolTip.LaunchTime = 1000; ToolTip.RelaunchTime = 500; ToolTip.Element = 0; // environment is root tab group Environment = this; setTabGroup(true); } //! destructor CGUIEnvironment::~CGUIEnvironment() { clearDeletionQueue(); if ( HoveredNoSubelement && HoveredNoSubelement != this ) { HoveredNoSubelement->drop(); HoveredNoSubelement = 0; } if (Hovered && Hovered != this) { Hovered->drop(); Hovered = 0; } if (Focus) { Focus->drop(); Focus = 0; } if (ToolTip.Element) { ToolTip.Element->drop(); ToolTip.Element = 0; } // drop skin if (CurrentSkin) { CurrentSkin->drop(); CurrentSkin = 0; } u32 i; // delete all sprite banks for (i=0; idrop(); // delete all fonts for (i=0; idrop(); if (Operator) { Operator->drop(); Operator = 0; } if (FileSystem) { FileSystem->drop(); FileSystem = 0; } if (Driver) { Driver->drop(); Driver = 0; } } void CGUIEnvironment::loadBuiltInFont() { #ifdef IRR_ENABLE_BUILTIN_FONT io::IReadFile* file = FileSystem->createMemoryReadFile(BuiltInFontData, BuiltInFontDataSize, DefaultFontName, false); CGUIFont* font = new CGUIFont(this, DefaultFontName ); if (!font->load(file)) { os::Printer::log("Error: Could not load built-in Font.", ELL_ERROR); font->drop(); file->drop(); return; } SFont f; f.NamedPath.setPath(DefaultFontName); f.Font = font; Fonts.push_back(f); file->drop(); #endif } //! draws all gui elements void CGUIEnvironment::drawAll(bool useScreenSize) { if (useScreenSize && Driver) { core::dimension2d dim(Driver->getScreenSize()); if (AbsoluteRect.LowerRightCorner.X != dim.Width || AbsoluteRect.UpperLeftCorner.X != 0 || AbsoluteRect.LowerRightCorner.Y != dim.Height || AbsoluteRect.UpperLeftCorner.Y != 0 ) { setRelativePosition(core::recti(0,0,dim.Width, dim.Height)); } } // make sure tooltip is always on top if (ToolTip.Element) bringToFront(ToolTip.Element); draw(); OnPostRender ( os::Timer::getTime () ); clearDeletionQueue(); } //! sets the focus to an element bool CGUIEnvironment::setFocus(IGUIElement* element) { if (Focus == element) { return false; } // GUI Environment should just reset the focus to 0 if (element == this) element = 0; // stop element from being deleted if (element) element->grab(); // focus may change or be removed in this call IGUIElement *currentFocus = 0; if (Focus) { currentFocus = Focus; currentFocus->grab(); SEvent e; e.EventType = EET_GUI_EVENT; e.GUIEvent.Caller = Focus; e.GUIEvent.Element = element; e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST; if (Focus->OnEvent(e)) { if (element) element->drop(); currentFocus->drop(); return false; } currentFocus->drop(); currentFocus = 0; } if (element) { currentFocus = Focus; if (currentFocus) currentFocus->grab(); // send focused event SEvent e; e.EventType = EET_GUI_EVENT; e.GUIEvent.Caller = element; e.GUIEvent.Element = Focus; e.GUIEvent.EventType = EGET_ELEMENT_FOCUSED; if (element->OnEvent(e)) { if (element) element->drop(); if (currentFocus) currentFocus->drop(); return false; } } if (currentFocus) currentFocus->drop(); if (Focus) Focus->drop(); // element is the new focus so it doesn't have to be dropped Focus = element; return true; } //! returns the element with the focus IGUIElement* CGUIEnvironment::getFocus() const { return Focus; } //! returns the element last known to be under the mouse cursor IGUIElement* CGUIEnvironment::getHovered() const { return Hovered; } //! removes the focus from an element bool CGUIEnvironment::removeFocus(IGUIElement* element) { if (Focus && Focus==element) { SEvent e; e.EventType = EET_GUI_EVENT; e.GUIEvent.Caller = Focus; e.GUIEvent.Element = 0; e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST; if (Focus->OnEvent(e)) { return false; } } if (Focus) { Focus->drop(); Focus = 0; } return true; } //! Returns whether the element has focus bool CGUIEnvironment::hasFocus(const IGUIElement* element, bool checkSubElements) const { if (element == Focus) return true; if ( !checkSubElements || !element ) return false; IGUIElement* f = Focus; while ( f && f->isSubElement() ) { f = f->getParent(); if ( f == element ) return true; } return false; } //! returns the current video driver video::IVideoDriver* CGUIEnvironment::getVideoDriver() const { return Driver; } //! returns the current file system io::IFileSystem* CGUIEnvironment::getFileSystem() const { return FileSystem; } //! returns a pointer to the OS operator IOSOperator* CGUIEnvironment::getOSOperator() const { return Operator; } //! clear all GUI elements void CGUIEnvironment::clear() { // Remove the focus if (Focus) { Focus->drop(); Focus = 0; } if (Hovered && Hovered != this) { Hovered->drop(); Hovered = 0; } if ( HoveredNoSubelement && HoveredNoSubelement != this) { HoveredNoSubelement->drop(); HoveredNoSubelement = 0; } getRootGUIElement()->removeAllChildren(); } //! called by ui if an event happened. bool CGUIEnvironment::OnEvent(const SEvent& event) { bool ret = false; if (UserReceiver && (event.EventType != EET_MOUSE_INPUT_EVENT) && (event.EventType != EET_KEY_INPUT_EVENT) && (event.EventType != EET_GUI_EVENT || event.GUIEvent.Caller != this)) { ret = UserReceiver->OnEvent(event); } return ret; } // void CGUIEnvironment::OnPostRender( u32 time ) { // launch tooltip if ( ToolTip.Element == 0 && HoveredNoSubelement && HoveredNoSubelement != this && (time - ToolTip.EnterTime >= ToolTip.LaunchTime || (time - ToolTip.LastTime >= ToolTip.RelaunchTime && time - ToolTip.LastTime < ToolTip.LaunchTime)) && HoveredNoSubelement->getToolTipText().size() && getSkin() && getSkin()->getFont(EGDF_TOOLTIP) ) { core::rect pos; pos.UpperLeftCorner = LastHoveredMousePos; core::dimension2du dim = getSkin()->getFont(EGDF_TOOLTIP)->getDimension(HoveredNoSubelement->getToolTipText().c_str()); dim.Width += getSkin()->getSize(EGDS_TEXT_DISTANCE_X)*2; dim.Height += getSkin()->getSize(EGDS_TEXT_DISTANCE_Y)*2; pos.UpperLeftCorner.Y -= dim.Height+1; pos.LowerRightCorner.Y = pos.UpperLeftCorner.Y + dim.Height-1; pos.LowerRightCorner.X = pos.UpperLeftCorner.X + dim.Width; pos.constrainTo(getAbsolutePosition()); ToolTip.Element = addStaticText(HoveredNoSubelement->getToolTipText().c_str(), pos, true, true, this, -1, true); ToolTip.Element->setOverrideColor(getSkin()->getColor(EGDC_TOOLTIP)); ToolTip.Element->setBackgroundColor(getSkin()->getColor(EGDC_TOOLTIP_BACKGROUND)); ToolTip.Element->setOverrideFont(getSkin()->getFont(EGDF_TOOLTIP)); ToolTip.Element->setSubElement(true); ToolTip.Element->grab(); s32 textHeight = ToolTip.Element->getTextHeight(); pos = ToolTip.Element->getRelativePosition(); pos.LowerRightCorner.Y = pos.UpperLeftCorner.Y + textHeight; ToolTip.Element->setRelativePosition(pos); } if (ToolTip.Element && ToolTip.Element->isVisible() ) // (isVisible() check only because we might use visibility for ToolTip one day) { ToolTip.LastTime = time; // got invisible or removed in the meantime? if ( !HoveredNoSubelement || !HoveredNoSubelement->isVisible() || !HoveredNoSubelement->getParent() ) // got invisible or removed in the meantime? { ToolTip.Element->remove(); ToolTip.Element->drop(); ToolTip.Element = 0; } } IGUIElement::OnPostRender ( time ); } void CGUIEnvironment::addToDeletionQueue(IGUIElement* element) { if (!element) return; element->grab(); DeletionQueue.push_back(element); } void CGUIEnvironment::clearDeletionQueue() { if (DeletionQueue.empty()) return; for (u32 i=0; iremove(); DeletionQueue[i]->drop(); } DeletionQueue.clear(); } // void CGUIEnvironment::updateHoveredElement(core::position2d mousePos) { IGUIElement* lastHovered = Hovered; IGUIElement* lastHoveredNoSubelement = HoveredNoSubelement; LastHoveredMousePos = mousePos; Hovered = getElementFromPoint(mousePos); if ( ToolTip.Element && Hovered == ToolTip.Element ) { // When the mouse is over the ToolTip we remove that so it will be re-created at a new position. // Note that ToolTip.EnterTime does not get changed here, so it will be re-created at once. ToolTip.Element->remove(); ToolTip.Element->drop(); ToolTip.Element = 0; // Get the real Hovered Hovered = getElementFromPoint(mousePos); } // for tooltips we want the element itself and not some of it's subelements HoveredNoSubelement = Hovered; while ( HoveredNoSubelement && HoveredNoSubelement->isSubElement() ) { HoveredNoSubelement = HoveredNoSubelement->getParent(); } if (Hovered && Hovered != this) Hovered->grab(); if ( HoveredNoSubelement && HoveredNoSubelement != this) HoveredNoSubelement->grab(); if (Hovered != lastHovered) { SEvent event; event.EventType = EET_GUI_EVENT; if (lastHovered) { event.GUIEvent.Caller = lastHovered; event.GUIEvent.Element = 0; event.GUIEvent.EventType = EGET_ELEMENT_LEFT; lastHovered->OnEvent(event); } if ( Hovered ) { event.GUIEvent.Caller = Hovered; event.GUIEvent.Element = Hovered; event.GUIEvent.EventType = EGET_ELEMENT_HOVERED; Hovered->OnEvent(event); } } if ( lastHoveredNoSubelement != HoveredNoSubelement ) { if (ToolTip.Element) { ToolTip.Element->remove(); ToolTip.Element->drop(); ToolTip.Element = 0; } if ( HoveredNoSubelement ) { u32 now = os::Timer::getTime(); ToolTip.EnterTime = now; } } if (lastHovered && lastHovered != this) lastHovered->drop(); if (lastHoveredNoSubelement && lastHoveredNoSubelement != this) lastHoveredNoSubelement->drop(); } //! This sets a new event receiver for gui events. Usually you do not have to //! use this method, it is used by the internal engine. void CGUIEnvironment::setUserEventReceiver(IEventReceiver* evr) { UserReceiver = evr; } //! posts an input event to the environment bool CGUIEnvironment::postEventFromUser(const SEvent& event) { switch(event.EventType) { case EET_GUI_EVENT: { // hey, why is the user sending gui events..? } break; case EET_MOUSE_INPUT_EVENT: updateHoveredElement(core::position2d(event.MouseInput.X, event.MouseInput.Y)); if ( Hovered != Focus ) { IGUIElement * focusCandidate = Hovered; // Only allow enabled elements to be focused (unless EFF_CAN_FOCUS_DISABLED is set) if ( Hovered && !Hovered->isEnabled() && !(FocusFlags & EFF_CAN_FOCUS_DISABLED)) focusCandidate = NULL; // we still remove focus from the active element // Please don't merge this into a single if clause, it's easier to debug the way it is if (FocusFlags & EFF_SET_ON_LMOUSE_DOWN && event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN ) { setFocus(focusCandidate); } else if ( FocusFlags & EFF_SET_ON_RMOUSE_DOWN && event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN ) { setFocus(focusCandidate); } else if ( FocusFlags & EFF_SET_ON_MOUSE_OVER && event.MouseInput.Event == EMIE_MOUSE_MOVED ) { setFocus(focusCandidate); } } // sending input to focus if (Focus && Focus->OnEvent(event)) return true; // focus could have died in last call if (!Focus && Hovered) { return Hovered->OnEvent(event); } break; case EET_KEY_INPUT_EVENT: { if (Focus && Focus->OnEvent(event)) return true; // For keys we handle the event before changing focus to give elements the chance for catching the TAB // Send focus changing event // CAREFUL when changing - there's an identical check in CGUIModalScreen::OnEvent if (FocusFlags & EFF_SET_ON_TAB && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_TAB) { IGUIElement *next = getNextElement(event.KeyInput.Shift, event.KeyInput.Control); if (next && next != Focus) { if (setFocus(next)) return true; } } } break; case EET_STRING_INPUT_EVENT: if (Focus && Focus->OnEvent(event)) return true; break; default: break; } // end switch return false; } //! returns the current gui skin IGUISkin* CGUIEnvironment::getSkin() const { return CurrentSkin; } //! Sets a new GUI Skin void CGUIEnvironment::setSkin(IGUISkin* skin) { if (CurrentSkin==skin) return; if (CurrentSkin) CurrentSkin->drop(); CurrentSkin = skin; if (CurrentSkin) CurrentSkin->grab(); } //! Creates a new GUI Skin based on a template. /** \return Returns a pointer to the created skin. If you no longer need the skin, you should call IGUISkin::drop(). See IReferenceCounted::drop() for more information. */ IGUISkin* CGUIEnvironment::createSkin(EGUI_SKIN_TYPE type) { IGUISkin* skin = new CGUISkin(type, Driver); IGUIFont* builtinfont = getBuiltInFont(); IGUIFontBitmap* bitfont = 0; if (builtinfont && builtinfont->getType() == EGFT_BITMAP) bitfont = (IGUIFontBitmap*)builtinfont; IGUISpriteBank* bank = 0; skin->setFont(builtinfont); if (bitfont) bank = bitfont->getSpriteBank(); skin->setSpriteBank(bank); return skin; } //! adds a button. The returned pointer must not be dropped. IGUIButton* CGUIEnvironment::addButton(const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext) { IGUIButton* button = new CGUIButton(this, parent ? parent : this, id, rectangle); if (text) button->setText(text); if ( tooltiptext ) button->setToolTipText ( tooltiptext ); button->drop(); return button; } //! adds a scrollbar. The returned pointer must not be dropped. IGUIScrollBar* CGUIEnvironment::addScrollBar(bool horizontal, const core::rect& rectangle, IGUIElement* parent, s32 id) { IGUIScrollBar* bar = new CGUIScrollBar(horizontal, this, parent ? parent : this, id, rectangle); bar->drop(); return bar; } //! Adds an image element. IGUIImage* CGUIEnvironment::addImage(video::ITexture* image, core::position2d pos, bool useAlphaChannel, IGUIElement* parent, s32 id, const wchar_t* text) { core::dimension2d sz(0,0); if (image) sz = core::dimension2d(image->getOriginalSize()); IGUIImage* img = new CGUIImage(this, parent ? parent : this, id, core::rect(pos, sz)); if (text) img->setText(text); if (useAlphaChannel) img->setUseAlphaChannel(true); if (image) img->setImage(image); img->drop(); return img; } //! adds an image. The returned pointer must not be dropped. IGUIImage* CGUIEnvironment::addImage(const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text, bool useAlphaChannel) { IGUIImage* img = new CGUIImage(this, parent ? parent : this, id, rectangle); if (text) img->setText(text); if ( useAlphaChannel ) img->setUseAlphaChannel(true); img->drop(); return img; } //! adds a checkbox IGUICheckBox* CGUIEnvironment::addCheckBox(bool checked, const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text) { IGUICheckBox* b = new CGUICheckBox(checked, this, parent ? parent : this , id , rectangle); if (text) b->setText(text); b->drop(); return b; } //! adds a list box IGUIListBox* CGUIEnvironment::addListBox(const core::rect& rectangle, IGUIElement* parent, s32 id, bool drawBackground) { IGUIListBox* b = new CGUIListBox(this, parent ? parent : this, id, rectangle, true, drawBackground, false); if (CurrentSkin && CurrentSkin->getSpriteBank()) { b->setSpriteBank(CurrentSkin->getSpriteBank()); } else if (getBuiltInFont() && getBuiltInFont()->getType() == EGFT_BITMAP) { b->setSpriteBank( ((IGUIFontBitmap*)getBuiltInFont())->getSpriteBank()); } b->drop(); return b; } //! adds a file open dialog. The returned pointer must not be dropped. IGUIFileOpenDialog* CGUIEnvironment::addFileOpenDialog(const wchar_t* title, bool modal, IGUIElement* parent, s32 id, bool restoreCWD, io::path::char_type* startDir) { parent = parent ? parent : this; if (modal) return nullptr; IGUIFileOpenDialog* d = new CGUIFileOpenDialog(title, this, parent, id, restoreCWD, startDir); d->drop(); return d; } //! adds a static text. The returned pointer must not be dropped. IGUIStaticText* CGUIEnvironment::addStaticText(const wchar_t* text, const core::rect& rectangle, bool border, bool wordWrap, IGUIElement* parent, s32 id, bool background) { IGUIStaticText* d = new CGUIStaticText(text, border, this, parent ? parent : this, id, rectangle, background); d->setWordWrap(wordWrap); d->drop(); return d; } //! Adds an edit box. The returned pointer must not be dropped. IGUIEditBox* CGUIEnvironment::addEditBox(const wchar_t* text, const core::rect& rectangle, bool border, IGUIElement* parent, s32 id) { IGUIEditBox* d = new CGUIEditBox(text, border, this, parent ? parent : this, id, rectangle); d->drop(); return d; } //! Adds a tab control to the environment. IGUITabControl* CGUIEnvironment::addTabControl(const core::rect& rectangle, IGUIElement* parent, bool fillbackground, bool border, s32 id) { IGUITabControl* t = new CGUITabControl(this, parent ? parent : this, rectangle, fillbackground, border, id); t->drop(); return t; } //! Adds tab to the environment. IGUITab* CGUIEnvironment::addTab(const core::rect& rectangle, IGUIElement* parent, s32 id) { IGUITab* t = new CGUITab(this, parent ? parent : this, rectangle, id); t->drop(); return t; } //! Adds a combo box to the environment. IGUIComboBox* CGUIEnvironment::addComboBox(const core::rect& rectangle, IGUIElement* parent, s32 id) { IGUIComboBox* t = new CGUIComboBox(this, parent ? parent : this, id, rectangle); t->drop(); return t; } //! returns the font IGUIFont* CGUIEnvironment::getFont(const io::path& filename) { // search existing font SFont f; f.NamedPath.setPath(filename); s32 index = Fonts.binary_search(f); if (index != -1) return Fonts[index].Font; // font doesn't exist, attempt to load it // does the file exist? if (!FileSystem->existFile(filename)) { os::Printer::log("Could not load font because the file does not exist", f.NamedPath.getPath(), ELL_ERROR); return 0; } IGUIFont* ifont=0; #if 0 { CGUIFont* font = new CGUIFont(this, filename); ifont = (IGUIFont*)font; // load the font io::path directory; core::splitFilename(filename, &directory); if (!font->load(xml, directory)) { font->drop(); font = 0; ifont = 0; } } #endif if (!ifont) { CGUIFont* font = new CGUIFont(this, f.NamedPath.getPath() ); ifont = (IGUIFont*)font; if (!font->load(f.NamedPath.getPath())) { font->drop(); return 0; } } // add to fonts. f.Font = ifont; Fonts.push_back(f); return ifont; } //! add an externally loaded font IGUIFont* CGUIEnvironment::addFont(const io::path& name, IGUIFont* font) { if (font) { SFont f; f.NamedPath.setPath(name); s32 index = Fonts.binary_search(f); if (index != -1) return Fonts[index].Font; f.Font = font; Fonts.push_back(f); font->grab(); } return font; } //! remove loaded font void CGUIEnvironment::removeFont(IGUIFont* font) { if ( !font ) return; for ( u32 i=0; idrop(); Fonts.erase(i); return; } } } //! returns default font IGUIFont* CGUIEnvironment::getBuiltInFont() const { if (Fonts.empty()) return 0; return Fonts[0].Font; } IGUISpriteBank* CGUIEnvironment::getSpriteBank(const io::path& filename) { // search for the file name SSpriteBank b; b.NamedPath.setPath(filename); s32 index = Banks.binary_search(b); if (index != -1) return Banks[index].Bank; // we don't have this sprite bank, we should load it if (!FileSystem->existFile(b.NamedPath.getPath())) { if ( filename != DefaultFontName ) { os::Printer::log("Could not load sprite bank because the file does not exist", b.NamedPath.getPath(), ELL_DEBUG); } return 0; } // todo: load it! return 0; } IGUISpriteBank* CGUIEnvironment::addEmptySpriteBank(const io::path& name) { // no duplicate names allowed SSpriteBank b; b.NamedPath.setPath(name); const s32 index = Banks.binary_search(b); if (index != -1) return 0; // create a new sprite bank b.Bank = new CGUISpriteBank(this); Banks.push_back(b); return b.Bank; } //! Creates the image list from the given texture. IGUIImageList* CGUIEnvironment::createImageList( video::ITexture* texture, core::dimension2d imageSize, bool useAlphaChannel ) { CGUIImageList* imageList = new CGUIImageList( Driver ); if( !imageList->createImageList( texture, imageSize, useAlphaChannel ) ) { imageList->drop(); return 0; } return imageList; } //! Returns the root gui element. IGUIElement* CGUIEnvironment::getRootGUIElement() { return this; } //! Returns the next element in the tab group starting at the focused element IGUIElement* CGUIEnvironment::getNextElement(bool reverse, bool group) { // start the search at the root of the current tab group IGUIElement *startPos = Focus ? Focus->getTabGroup() : 0; s32 startOrder = -1; // if we're searching for a group if (group && startPos) { startOrder = startPos->getTabOrder(); } else if (!group && Focus && !Focus->isTabGroup()) { startOrder = Focus->getTabOrder(); if (startOrder == -1) { // this element is not part of the tab cycle, // but its parent might be... IGUIElement *el = Focus; while (el && el->getParent() && startOrder == -1) { el = el->getParent(); startOrder = el->getTabOrder(); } } } if (group || !startPos) startPos = this; // start at the root // find the element IGUIElement *closest = 0; IGUIElement *first = 0; startPos->getNextElement(startOrder, reverse, group, first, closest, false, (FocusFlags & EFF_CAN_FOCUS_DISABLED) != 0); if (closest) return closest; // we found an element else if (first) return first; // go to the end or the start else if (group) return this; // no group found? root group else return 0; } void CGUIEnvironment::setFocusBehavior(u32 flags) { FocusFlags = flags; } u32 CGUIEnvironment::getFocusBehavior() const { return FocusFlags; } //! creates an GUI Environment IGUIEnvironment* createGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* Driver, IOSOperator* op) { return new CGUIEnvironment(fs, Driver, op); } } // end namespace gui } // end namespace irr