// 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; i < Banks.size(); ++i) if (Banks[i].Bank) Banks[i].Bank->drop(); // delete all fonts for (i = 0; i < Fonts.size(); ++i) Fonts[i].Font->drop(); 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; i < DeletionQueue.size(); ++i) { DeletionQueue[i]->remove(); 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; i < Fonts.size(); ++i) { if (Fonts[i].Font == font) { Fonts[i].Font->drop(); 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