From 959831f4ef5a3e797f576c3de08cd65032c997ad Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 18:54:10 +1000 Subject: Remove damned ancient DOS line endings from Irrlicht. Hopefully I did not go overboard. --- .../source/Irrlicht/CGUIEnvironment.cpp | 3316 ++++++++++---------- 1 file changed, 1658 insertions(+), 1658 deletions(-) (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CGUIEnvironment.cpp') diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CGUIEnvironment.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CGUIEnvironment.cpp index bf3fa86..aad2d19 100644 --- a/libraries/irrlicht-1.8/source/Irrlicht/CGUIEnvironment.cpp +++ b/libraries/irrlicht-1.8/source/Irrlicht/CGUIEnvironment.cpp @@ -1,1658 +1,1658 @@ - -// 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" - -#ifdef _IRR_COMPILE_WITH_GUI_ - -#include "IVideoDriver.h" - -#include "CGUISkin.h" -#include "CGUIButton.h" -#include "CGUIWindow.h" -#include "CGUIScrollBar.h" -#include "CGUIFont.h" -#include "CGUISpriteBank.h" -#include "CGUIImage.h" -#include "CGUIMeshViewer.h" -#include "CGUICheckBox.h" -#include "CGUIListBox.h" -#include "CGUITreeView.h" -#include "CGUIImageList.h" -#include "CGUIFileOpenDialog.h" -#include "CGUIColorSelectDialog.h" -#include "CGUIStaticText.h" -#include "CGUIEditBox.h" -#include "CGUISpinBox.h" -#include "CGUIInOutFader.h" -#include "CGUIMessageBox.h" -#include "CGUIModalScreen.h" -#include "CGUITabControl.h" -#include "CGUIContextMenu.h" -#include "CGUIComboBox.h" -#include "CGUIMenu.h" -#include "CGUIToolBar.h" -#include "CGUITable.h" - -#include "CDefaultGUIElementFactory.h" -#include "IWriteFile.h" -#include "IXMLWriter.h" - -#include "BuiltInFont.h" -#include "os.h" - -namespace irr -{ -namespace gui -{ - -const wchar_t* IRR_XML_FORMAT_GUI_ENV = L"irr_gui"; -const wchar_t* IRR_XML_FORMAT_GUI_ELEMENT = L"element"; -const wchar_t* IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE = L"type"; - -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(core::position2d(0,0), 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) -{ - if (Driver) - Driver->grab(); - - if (FileSystem) - FileSystem->grab(); - - if (Operator) - Operator->grab(); - - #ifdef _DEBUG - IGUIEnvironment::setDebugName("CGUIEnvironment"); - #endif - - // gui factory - IGUIElementFactory* factory = new CDefaultGUIElementFactory(this); - registerGUIElementFactory(factory); - factory->drop(); - - 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() -{ - 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(); - - // remove all factories - 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() -{ - io::IReadFile* file = io::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. Did you compile without the BMP loader?", ELL_ERROR); - font->drop(); - file->drop(); - return; - } - - SFont f; - f.NamedPath.setPath(DefaultFontName); - f.Font = font; - Fonts.push_back(f); - - file->drop(); -} - - -//! draws all gui elements -void CGUIEnvironment::drawAll() -{ - if (Driver) - { - core::dimension2d dim(Driver->getScreenSize()); - if (AbsoluteRect.LowerRightCorner.X != dim.Width || - AbsoluteRect.LowerRightCorner.Y != dim.Height) - { - // resize gui environment - DesiredRect.LowerRightCorner = dim; - AbsoluteClippingRect = DesiredRect; - AbsoluteRect = DesiredRect; - updateAbsolutePosition(); - } - } - - // make sure tooltip is always on top - if (ToolTip.Element) - bringToFront(ToolTip.Element); - - draw(); - OnPostRender ( os::Timer::getTime () ); -} - - -//! sets the focus to an element -bool CGUIEnvironment::setFocus(IGUIElement* element) -{ - if (Focus == element) - { - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return false; - } - - // GUI Environment should not get the focus - 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(); - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - 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(); - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - 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)) - { - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return false; - } - } - if (Focus) - { - Focus->drop(); - Focus = 0; - } - - return true; -} - - -//! Returns if the element has focus -bool CGUIEnvironment::hasFocus(IGUIElement* element) const -{ - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return (element == Focus); -} - - -//! 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; - } - - // get the root's children in case the root changes in future - const core::list& children = getRootGUIElement()->getChildren(); - - while (!children.empty()) - (*children.getLast())->remove(); -} - - -//! 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); - } - - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - 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::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 (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) - if ( (Hovered && Hovered != Focus) || !Focus ) - { - setFocus(Hovered); - } - - // sending input to focus - if (Focus && Focus->OnEvent(event)) - return true; - - // focus could have died in last call - if (!Focus && Hovered) - { - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - 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 - if (event.EventType == EET_KEY_INPUT_EVENT && - 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; - default: - break; - } // end switch - - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - 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; -} - - -//! Returns the default element factory which can create all built in elements -IGUIElementFactory* CGUIEnvironment::getDefaultGUIElementFactory() const -{ - return getGUIElementFactory(0); -} - - -//! Adds an element factory to the gui environment. -/** Use this to extend the gui environment with new element types which it should be -able to create automaticly, for example when loading data from xml files. */ -void CGUIEnvironment::registerGUIElementFactory(IGUIElementFactory* factoryToAdd) -{ - if (factoryToAdd) - { - factoryToAdd->grab(); - GUIElementFactoryList.push_back(factoryToAdd); - } -} - - -//! Returns amount of registered scene node factories. -u32 CGUIEnvironment::getRegisteredGUIElementFactoryCount() const -{ - return GUIElementFactoryList.size(); -} - - -//! Returns a scene node factory by index -IGUIElementFactory* CGUIEnvironment::getGUIElementFactory(u32 index) const -{ - if (index < GUIElementFactoryList.size()) - return GUIElementFactoryList[index]; - else - return 0; -} - - -//! adds a GUI Element using its name -IGUIElement* CGUIEnvironment::addGUIElement(const c8* elementName, IGUIElement* parent) -{ - IGUIElement* node=0; - - if (!parent) - parent = this; - - for (s32 i=GUIElementFactoryList.size()-1; i>=0 && !node; --i) - node = GUIElementFactoryList[i]->addGUIElement(elementName, parent); - - - return node; -} - - -//! Saves the current gui into a file. -//! \param filename: Name of the file . -bool CGUIEnvironment::saveGUI(const io::path& filename, IGUIElement* start) -{ - io::IWriteFile* file = FileSystem->createAndWriteFile(filename); - if (!file) - { - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return false; - } - - bool ret = saveGUI(file, start); - file->drop(); - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return ret; -} - - -//! Saves the current gui into a file. -bool CGUIEnvironment::saveGUI(io::IWriteFile* file, IGUIElement* start) -{ - if (!file) - { - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return false; - } - - io::IXMLWriter* writer = FileSystem->createXMLWriter(file); - if (!writer) - { - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return false; - } - - writer->writeXMLHeader(); - writeGUIElement(writer, start ? start : this); - writer->drop(); - - return true; -} - - -//! Loads the gui. Note that the current gui is not cleared before. -//! \param filename: Name of the file. -bool CGUIEnvironment::loadGUI(const io::path& filename, IGUIElement* parent) -{ - io::IReadFile* read = FileSystem->createAndOpenFile(filename); - if (!read) - { - os::Printer::log("Unable to open gui file", filename, ELL_ERROR); - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return false; - } - - bool ret = loadGUI(read, parent); - read->drop(); - - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return ret; -} - - -//! Loads the gui. Note that the current gui is not cleared before. -bool CGUIEnvironment::loadGUI(io::IReadFile* file, IGUIElement* parent) -{ - if (!file) - { - os::Printer::log("Unable to open GUI file", ELL_ERROR); - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return false; - } - - io::IXMLReader* reader = FileSystem->createXMLReader(file); - if (!reader) - { - os::Printer::log("GUI is not a valid XML file", file->getFileName(), ELL_ERROR); - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return false; - } - - // read file - while(reader->read()) - { - readGUIElement(reader, parent); - } - - // finish up - - reader->drop(); - return true; -} - - -//! reads an element -void CGUIEnvironment::readGUIElement(io::IXMLReader* reader, IGUIElement* node) -{ - if (!reader) - return; - - io::EXML_NODE nodeType = reader->getNodeType(); - - if (nodeType == io::EXN_NONE || nodeType == io::EXN_UNKNOWN || nodeType == io::EXN_ELEMENT_END) - return; - - IGUIElement* deferedNode = 0; - if (!wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) - { - // GuiEnvironment always must be this as it would serialize into a wrong element otherwise. - // So we use the given node next time - if ( node && node != this ) - deferedNode = node; - node = this; // root - } - else if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName())) - { - // find node type and create it - const core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE); - - node = addGUIElement(attrName.c_str(), node); - - if (!node) - os::Printer::log("Could not create GUI element of unknown type", attrName.c_str()); - } - - // read attributes - - while(reader->read()) - { - bool endreached = false; - - switch (reader->getNodeType()) - { - case io::EXN_ELEMENT_END: - if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || - !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) - { - endreached = true; - } - break; - case io::EXN_ELEMENT: - if (!wcscmp(L"attributes", reader->getNodeName())) - { - // read attributes - io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); - attr->read(reader, true); - - if (node) - node->deserializeAttributes(attr); - - attr->drop(); - } - else - if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || - !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) - { - if ( deferedNode ) - readGUIElement(reader, deferedNode); - else - readGUIElement(reader, node); - } - else - { - os::Printer::log("Found unknown element in irrlicht GUI file", - core::stringc(reader->getNodeName()).c_str()); - } - - break; - default: - break; - } - - if (endreached) - break; - } -} - - -//! writes an element -void CGUIEnvironment::writeGUIElement(io::IXMLWriter* writer, IGUIElement* node) -{ - if (!writer || !node ) - return; - - const wchar_t* name = 0; - - // write properties - - io::IAttributes* attr = FileSystem->createEmptyAttributes(); - node->serializeAttributes(attr); - - // all gui elements must have at least one attribute - // if they have nothing then we ignore them. - if (attr->getAttributeCount() != 0) - { - if (node == this) - { - name = IRR_XML_FORMAT_GUI_ENV; - writer->writeElement(name, false); - } - else - { - name = IRR_XML_FORMAT_GUI_ELEMENT; - writer->writeElement(name, false, IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE, - core::stringw(node->getTypeName()).c_str()); - } - - writer->writeLineBreak(); - writer->writeLineBreak(); - - attr->write(writer); - writer->writeLineBreak(); - } - - // write children - - core::list::ConstIterator it = node->getChildren().begin(); - for (; it != node->getChildren().end(); ++it) - { - if (!(*it)->isSubElement()) - writeGUIElement(writer, (*it)); - } - - // write closing brace if required - if (attr->getAttributeCount() != 0) - { - writer->writeClosingTag(name); - writer->writeLineBreak(); - writer->writeLineBreak(); - } - - attr->drop(); -} - - -//! Writes attributes of the environment -void CGUIEnvironment::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const -{ - IGUISkin* skin = getSkin(); - - if (skin) - { - out->addEnum("Skin", getSkin()->getType(), GUISkinTypeNames); - skin->serializeAttributes(out, options); - } -} - - -//! Reads attributes of the environment -void CGUIEnvironment::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) -{ - if (in->existsAttribute("Skin")) - { - IGUISkin *skin = getSkin(); - - EGUI_SKIN_TYPE t = (EGUI_SKIN_TYPE) in->getAttributeAsEnumeration("Skin",GUISkinTypeNames); - if ( !skin || t != skin->getType()) - { - skin = createSkin(t); - setSkin(skin); - skin->drop(); - } - - skin = getSkin(); - - if (skin) - { - skin->deserializeAttributes(in, options); - } - - } - - RelativeRect = AbsoluteRect = - core::rect(core::position2d(0,0), - Driver ? core::dimension2di(Driver->getScreenSize()) : core::dimension2d(0,0)); -} - - -//! 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 window. The returned pointer must not be dropped. -IGUIWindow* CGUIEnvironment::addWindow(const core::rect& rectangle, bool modal, - const wchar_t* text, IGUIElement* parent, s32 id) -{ - parent = parent ? parent : this; - - IGUIWindow* win = new CGUIWindow(this, parent, id, rectangle); - if (text) - win->setText(text); - win->drop(); - - if (modal) - { - // 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 - // careful not to get virtual function call, like OnEvent, in the window. - CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); - modalScreen->drop(); - modalScreen->addChild(win); - } - - return win; -} - - -//! adds a modal screen. The returned pointer must not be dropped. -IGUIElement* CGUIEnvironment::addModalScreen(IGUIElement* parent) -{ - parent = parent ? parent : this; - - IGUIElement *win = new CGUIModalScreen(this, parent, -1); - win->drop(); - - return win; -} - - -//! Adds a message box. -IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t* text, - bool modal, s32 flag, IGUIElement* parent, s32 id, video::ITexture* image) -{ - if (!CurrentSkin) - return 0; - - parent = parent ? parent : this; - - core::rect rect; - core::dimension2d screenDim, msgBoxDim; - - screenDim.Width = parent->getAbsolutePosition().getWidth(); - screenDim.Height = parent->getAbsolutePosition().getHeight(); - msgBoxDim.Width = 2; - msgBoxDim.Height = 2; - - rect.UpperLeftCorner.X = (screenDim.Width - msgBoxDim.Width) / 2; - rect.UpperLeftCorner.Y = (screenDim.Height - msgBoxDim.Height) / 2; - rect.LowerRightCorner.X = rect.UpperLeftCorner.X + msgBoxDim.Width; - rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + msgBoxDim.Height; - - IGUIWindow* win = new CGUIMessageBox(this, caption, text, flag, - parent, id, rect, image); - win->drop(); - - if (modal) - { - // 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 - // careful not to get virtual function call, like OnEvent, in the CGUIMessageBox. - CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); - modalScreen->drop(); - modalScreen->addChild( win ); - } - - - return win; -} - - -//! 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 a table to the environment -IGUITable* CGUIEnvironment::addTable(const core::rect& rectangle, IGUIElement* parent, s32 id, bool drawBackground) -{ - CGUITable* b = new CGUITable(this, parent ? parent : this, id, rectangle, true, drawBackground, false); - b->drop(); - return b; -} - - -//! 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 an mesh viewer. The returned pointer must not be dropped. -IGUIMeshViewer* CGUIEnvironment::addMeshViewer(const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text) -{ - IGUIMeshViewer* v = new CGUIMeshViewer(this, parent ? parent : this, - id, rectangle); - - if (text) - v->setText(text); - - v->drop(); - return v; -} - - -//! 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 tree view -IGUITreeView* CGUIEnvironment::addTreeView(const core::rect& rectangle, - IGUIElement* parent, s32 id, - bool drawBackground, - bool scrollBarVertical, bool scrollBarHorizontal) -{ - IGUITreeView* b = new CGUITreeView(this, parent ? parent : this, id, rectangle, - true, drawBackground, scrollBarVertical, scrollBarHorizontal); - - b->setIconFont ( getBuiltInFont () ); - 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; - - IGUIFileOpenDialog* d = new CGUIFileOpenDialog(title, this, parent, id, - restoreCWD, startDir); - d->drop(); - - if (modal) - { - // 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 - // careful not to get virtual function call, like OnEvent, in the window. - CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); - modalScreen->drop(); - modalScreen->addChild(d); - } - - return d; -} - - -//! adds a color select dialog. The returned pointer must not be dropped. -IGUIColorSelectDialog* CGUIEnvironment::addColorSelectDialog(const wchar_t* title, - bool modal, IGUIElement* parent, s32 id) -{ - parent = parent ? parent : this; - - IGUIColorSelectDialog* d = new CGUIColorSelectDialog( title, - this, parent, id); - d->drop(); - - if (modal) - { - // 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 - // careful not to get virtual function call, like OnEvent, in the window. - CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); - modalScreen->drop(); - modalScreen->addChild(d); - } - - 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 spin box to the environment -IGUISpinBox* CGUIEnvironment::addSpinBox(const wchar_t* text, - const core::rect &rectangle, - bool border,IGUIElement* parent, s32 id) -{ - IGUISpinBox* d = new CGUISpinBox(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(-1, this, parent ? parent : this, - rectangle, id); - t->drop(); - return t; -} - - -//! Adds a context menu to the environment. -IGUIContextMenu* CGUIEnvironment::addContextMenu(const core::rect& rectangle, - IGUIElement* parent, s32 id) -{ - IGUIContextMenu* c = new CGUIContextMenu(this, - parent ? parent : this, id, rectangle, true); - c->drop(); - return c; -} - - -//! Adds a menu to the environment. -IGUIContextMenu* CGUIEnvironment::addMenu(IGUIElement* parent, s32 id) -{ - if (!parent) - parent = this; - - IGUIContextMenu* c = new CGUIMenu(this, - parent, id, core::rect(0,0, - parent->getAbsolutePosition().getWidth(), - parent->getAbsolutePosition().getHeight())); - - c->drop(); - return c; -} - - -//! Adds a toolbar to the environment. It is like a menu is always placed on top -//! in its parent, and contains buttons. -IGUIToolBar* CGUIEnvironment::addToolBar(IGUIElement* parent, s32 id) -{ - if (!parent) - parent = this; - - IGUIToolBar* b = new CGUIToolBar(this, parent, id, core::rect(0,0,10,10)); - b->drop(); - return b; -} - - -//! Adds an element for fading in or out. -IGUIInOutFader* CGUIEnvironment::addInOutFader(const core::rect* rectangle, IGUIElement* parent, s32 id) -{ - core::rect rect; - - if (rectangle) - rect = *rectangle; - else if (Driver) - rect = core::rect(core::position2d(0,0), core::dimension2di(Driver->getScreenSize())); - - if (!parent) - parent = this; - - IGUIInOutFader* fader = new CGUIInOutFader(this, parent, id, rect); - fader->drop(); - return fader; -} - - -//! 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; - io::IXMLReader *xml = FileSystem->createXMLReader(filename ); - if (xml) - { - // this is an XML font, but we need to know what type - EGUI_FONT_TYPE t = EGFT_CUSTOM; - - bool found=false; - while(!found && xml->read()) - { - if (xml->getNodeType() == io::EXN_ELEMENT) - { - if (core::stringw(L"font") == xml->getNodeName()) - { - if (core::stringw(L"vector") == xml->getAttributeValue(L"type")) - { - t = EGFT_VECTOR; - found=true; - } - else if (core::stringw(L"bitmap") == xml->getAttributeValue(L"type")) - { - t = EGFT_BITMAP; - found=true; - } - else found=true; - } - } - } - - if (t==EGFT_BITMAP) - { - CGUIFont* font = new CGUIFont(this, filename); - ifont = (IGUIFont*)font; - // change working directory, for loading textures - io::path workingDir = FileSystem->getWorkingDirectory(); - FileSystem->changeWorkingDirectoryTo(FileSystem->getFileDir(f.NamedPath.getPath())); - - // load the font - if (!font->load(xml)) - { - font->drop(); - font = 0; - ifont = 0; - } - // change working dir back again - FileSystem->changeWorkingDirectoryTo( workingDir ); - } - else if (t==EGFT_VECTOR) - { - // todo: vector fonts - os::Printer::log("Unable to load font, XML vector fonts are not supported yet", f.NamedPath, ELL_ERROR); - - //CGUIFontVector* font = new CGUIFontVector(Driver); - //ifont = (IGUIFont*)font; - //if (!font->load(xml)) - } - xml->drop(); - } - - - 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); - - 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; -} - - -//! 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 - -#endif // _IRR_COMPILE_WITH_GUI_ - + +// 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" + +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IVideoDriver.h" + +#include "CGUISkin.h" +#include "CGUIButton.h" +#include "CGUIWindow.h" +#include "CGUIScrollBar.h" +#include "CGUIFont.h" +#include "CGUISpriteBank.h" +#include "CGUIImage.h" +#include "CGUIMeshViewer.h" +#include "CGUICheckBox.h" +#include "CGUIListBox.h" +#include "CGUITreeView.h" +#include "CGUIImageList.h" +#include "CGUIFileOpenDialog.h" +#include "CGUIColorSelectDialog.h" +#include "CGUIStaticText.h" +#include "CGUIEditBox.h" +#include "CGUISpinBox.h" +#include "CGUIInOutFader.h" +#include "CGUIMessageBox.h" +#include "CGUIModalScreen.h" +#include "CGUITabControl.h" +#include "CGUIContextMenu.h" +#include "CGUIComboBox.h" +#include "CGUIMenu.h" +#include "CGUIToolBar.h" +#include "CGUITable.h" + +#include "CDefaultGUIElementFactory.h" +#include "IWriteFile.h" +#include "IXMLWriter.h" + +#include "BuiltInFont.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +const wchar_t* IRR_XML_FORMAT_GUI_ENV = L"irr_gui"; +const wchar_t* IRR_XML_FORMAT_GUI_ELEMENT = L"element"; +const wchar_t* IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE = L"type"; + +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(core::position2d(0,0), 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) +{ + if (Driver) + Driver->grab(); + + if (FileSystem) + FileSystem->grab(); + + if (Operator) + Operator->grab(); + + #ifdef _DEBUG + IGUIEnvironment::setDebugName("CGUIEnvironment"); + #endif + + // gui factory + IGUIElementFactory* factory = new CDefaultGUIElementFactory(this); + registerGUIElementFactory(factory); + factory->drop(); + + 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() +{ + 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(); + + // remove all factories + 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() +{ + io::IReadFile* file = io::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. Did you compile without the BMP loader?", ELL_ERROR); + font->drop(); + file->drop(); + return; + } + + SFont f; + f.NamedPath.setPath(DefaultFontName); + f.Font = font; + Fonts.push_back(f); + + file->drop(); +} + + +//! draws all gui elements +void CGUIEnvironment::drawAll() +{ + if (Driver) + { + core::dimension2d dim(Driver->getScreenSize()); + if (AbsoluteRect.LowerRightCorner.X != dim.Width || + AbsoluteRect.LowerRightCorner.Y != dim.Height) + { + // resize gui environment + DesiredRect.LowerRightCorner = dim; + AbsoluteClippingRect = DesiredRect; + AbsoluteRect = DesiredRect; + updateAbsolutePosition(); + } + } + + // make sure tooltip is always on top + if (ToolTip.Element) + bringToFront(ToolTip.Element); + + draw(); + OnPostRender ( os::Timer::getTime () ); +} + + +//! sets the focus to an element +bool CGUIEnvironment::setFocus(IGUIElement* element) +{ + if (Focus == element) + { + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return false; + } + + // GUI Environment should not get the focus + 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(); + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + 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(); + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + 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)) + { + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return false; + } + } + if (Focus) + { + Focus->drop(); + Focus = 0; + } + + return true; +} + + +//! Returns if the element has focus +bool CGUIEnvironment::hasFocus(IGUIElement* element) const +{ + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return (element == Focus); +} + + +//! 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; + } + + // get the root's children in case the root changes in future + const core::list& children = getRootGUIElement()->getChildren(); + + while (!children.empty()) + (*children.getLast())->remove(); +} + + +//! 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); + } + + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + 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::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 (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) + if ( (Hovered && Hovered != Focus) || !Focus ) + { + setFocus(Hovered); + } + + // sending input to focus + if (Focus && Focus->OnEvent(event)) + return true; + + // focus could have died in last call + if (!Focus && Hovered) + { + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + 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 + if (event.EventType == EET_KEY_INPUT_EVENT && + 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; + default: + break; + } // end switch + + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + 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; +} + + +//! Returns the default element factory which can create all built in elements +IGUIElementFactory* CGUIEnvironment::getDefaultGUIElementFactory() const +{ + return getGUIElementFactory(0); +} + + +//! Adds an element factory to the gui environment. +/** Use this to extend the gui environment with new element types which it should be +able to create automaticly, for example when loading data from xml files. */ +void CGUIEnvironment::registerGUIElementFactory(IGUIElementFactory* factoryToAdd) +{ + if (factoryToAdd) + { + factoryToAdd->grab(); + GUIElementFactoryList.push_back(factoryToAdd); + } +} + + +//! Returns amount of registered scene node factories. +u32 CGUIEnvironment::getRegisteredGUIElementFactoryCount() const +{ + return GUIElementFactoryList.size(); +} + + +//! Returns a scene node factory by index +IGUIElementFactory* CGUIEnvironment::getGUIElementFactory(u32 index) const +{ + if (index < GUIElementFactoryList.size()) + return GUIElementFactoryList[index]; + else + return 0; +} + + +//! adds a GUI Element using its name +IGUIElement* CGUIEnvironment::addGUIElement(const c8* elementName, IGUIElement* parent) +{ + IGUIElement* node=0; + + if (!parent) + parent = this; + + for (s32 i=GUIElementFactoryList.size()-1; i>=0 && !node; --i) + node = GUIElementFactoryList[i]->addGUIElement(elementName, parent); + + + return node; +} + + +//! Saves the current gui into a file. +//! \param filename: Name of the file . +bool CGUIEnvironment::saveGUI(const io::path& filename, IGUIElement* start) +{ + io::IWriteFile* file = FileSystem->createAndWriteFile(filename); + if (!file) + { + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return false; + } + + bool ret = saveGUI(file, start); + file->drop(); + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return ret; +} + + +//! Saves the current gui into a file. +bool CGUIEnvironment::saveGUI(io::IWriteFile* file, IGUIElement* start) +{ + if (!file) + { + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return false; + } + + io::IXMLWriter* writer = FileSystem->createXMLWriter(file); + if (!writer) + { + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return false; + } + + writer->writeXMLHeader(); + writeGUIElement(writer, start ? start : this); + writer->drop(); + + return true; +} + + +//! Loads the gui. Note that the current gui is not cleared before. +//! \param filename: Name of the file. +bool CGUIEnvironment::loadGUI(const io::path& filename, IGUIElement* parent) +{ + io::IReadFile* read = FileSystem->createAndOpenFile(filename); + if (!read) + { + os::Printer::log("Unable to open gui file", filename, ELL_ERROR); + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return false; + } + + bool ret = loadGUI(read, parent); + read->drop(); + + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return ret; +} + + +//! Loads the gui. Note that the current gui is not cleared before. +bool CGUIEnvironment::loadGUI(io::IReadFile* file, IGUIElement* parent) +{ + if (!file) + { + os::Printer::log("Unable to open GUI file", ELL_ERROR); + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return false; + } + + io::IXMLReader* reader = FileSystem->createXMLReader(file); + if (!reader) + { + os::Printer::log("GUI is not a valid XML file", file->getFileName(), ELL_ERROR); + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return false; + } + + // read file + while(reader->read()) + { + readGUIElement(reader, parent); + } + + // finish up + + reader->drop(); + return true; +} + + +//! reads an element +void CGUIEnvironment::readGUIElement(io::IXMLReader* reader, IGUIElement* node) +{ + if (!reader) + return; + + io::EXML_NODE nodeType = reader->getNodeType(); + + if (nodeType == io::EXN_NONE || nodeType == io::EXN_UNKNOWN || nodeType == io::EXN_ELEMENT_END) + return; + + IGUIElement* deferedNode = 0; + if (!wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + // GuiEnvironment always must be this as it would serialize into a wrong element otherwise. + // So we use the given node next time + if ( node && node != this ) + deferedNode = node; + node = this; // root + } + else if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName())) + { + // find node type and create it + const core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE); + + node = addGUIElement(attrName.c_str(), node); + + if (!node) + os::Printer::log("Could not create GUI element of unknown type", attrName.c_str()); + } + + // read attributes + + while(reader->read()) + { + bool endreached = false; + + switch (reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || + !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + endreached = true; + } + break; + case io::EXN_ELEMENT: + if (!wcscmp(L"attributes", reader->getNodeName())) + { + // read attributes + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + attr->read(reader, true); + + if (node) + node->deserializeAttributes(attr); + + attr->drop(); + } + else + if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || + !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + if ( deferedNode ) + readGUIElement(reader, deferedNode); + else + readGUIElement(reader, node); + } + else + { + os::Printer::log("Found unknown element in irrlicht GUI file", + core::stringc(reader->getNodeName()).c_str()); + } + + break; + default: + break; + } + + if (endreached) + break; + } +} + + +//! writes an element +void CGUIEnvironment::writeGUIElement(io::IXMLWriter* writer, IGUIElement* node) +{ + if (!writer || !node ) + return; + + const wchar_t* name = 0; + + // write properties + + io::IAttributes* attr = FileSystem->createEmptyAttributes(); + node->serializeAttributes(attr); + + // all gui elements must have at least one attribute + // if they have nothing then we ignore them. + if (attr->getAttributeCount() != 0) + { + if (node == this) + { + name = IRR_XML_FORMAT_GUI_ENV; + writer->writeElement(name, false); + } + else + { + name = IRR_XML_FORMAT_GUI_ELEMENT; + writer->writeElement(name, false, IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE, + core::stringw(node->getTypeName()).c_str()); + } + + writer->writeLineBreak(); + writer->writeLineBreak(); + + attr->write(writer); + writer->writeLineBreak(); + } + + // write children + + core::list::ConstIterator it = node->getChildren().begin(); + for (; it != node->getChildren().end(); ++it) + { + if (!(*it)->isSubElement()) + writeGUIElement(writer, (*it)); + } + + // write closing brace if required + if (attr->getAttributeCount() != 0) + { + writer->writeClosingTag(name); + writer->writeLineBreak(); + writer->writeLineBreak(); + } + + attr->drop(); +} + + +//! Writes attributes of the environment +void CGUIEnvironment::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IGUISkin* skin = getSkin(); + + if (skin) + { + out->addEnum("Skin", getSkin()->getType(), GUISkinTypeNames); + skin->serializeAttributes(out, options); + } +} + + +//! Reads attributes of the environment +void CGUIEnvironment::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + if (in->existsAttribute("Skin")) + { + IGUISkin *skin = getSkin(); + + EGUI_SKIN_TYPE t = (EGUI_SKIN_TYPE) in->getAttributeAsEnumeration("Skin",GUISkinTypeNames); + if ( !skin || t != skin->getType()) + { + skin = createSkin(t); + setSkin(skin); + skin->drop(); + } + + skin = getSkin(); + + if (skin) + { + skin->deserializeAttributes(in, options); + } + + } + + RelativeRect = AbsoluteRect = + core::rect(core::position2d(0,0), + Driver ? core::dimension2di(Driver->getScreenSize()) : core::dimension2d(0,0)); +} + + +//! 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 window. The returned pointer must not be dropped. +IGUIWindow* CGUIEnvironment::addWindow(const core::rect& rectangle, bool modal, + const wchar_t* text, IGUIElement* parent, s32 id) +{ + parent = parent ? parent : this; + + IGUIWindow* win = new CGUIWindow(this, parent, id, rectangle); + if (text) + win->setText(text); + win->drop(); + + if (modal) + { + // 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 + // careful not to get virtual function call, like OnEvent, in the window. + CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); + modalScreen->drop(); + modalScreen->addChild(win); + } + + return win; +} + + +//! adds a modal screen. The returned pointer must not be dropped. +IGUIElement* CGUIEnvironment::addModalScreen(IGUIElement* parent) +{ + parent = parent ? parent : this; + + IGUIElement *win = new CGUIModalScreen(this, parent, -1); + win->drop(); + + return win; +} + + +//! Adds a message box. +IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t* text, + bool modal, s32 flag, IGUIElement* parent, s32 id, video::ITexture* image) +{ + if (!CurrentSkin) + return 0; + + parent = parent ? parent : this; + + core::rect rect; + core::dimension2d screenDim, msgBoxDim; + + screenDim.Width = parent->getAbsolutePosition().getWidth(); + screenDim.Height = parent->getAbsolutePosition().getHeight(); + msgBoxDim.Width = 2; + msgBoxDim.Height = 2; + + rect.UpperLeftCorner.X = (screenDim.Width - msgBoxDim.Width) / 2; + rect.UpperLeftCorner.Y = (screenDim.Height - msgBoxDim.Height) / 2; + rect.LowerRightCorner.X = rect.UpperLeftCorner.X + msgBoxDim.Width; + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + msgBoxDim.Height; + + IGUIWindow* win = new CGUIMessageBox(this, caption, text, flag, + parent, id, rect, image); + win->drop(); + + if (modal) + { + // 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 + // careful not to get virtual function call, like OnEvent, in the CGUIMessageBox. + CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); + modalScreen->drop(); + modalScreen->addChild( win ); + } + + + return win; +} + + +//! 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 a table to the environment +IGUITable* CGUIEnvironment::addTable(const core::rect& rectangle, IGUIElement* parent, s32 id, bool drawBackground) +{ + CGUITable* b = new CGUITable(this, parent ? parent : this, id, rectangle, true, drawBackground, false); + b->drop(); + return b; +} + + +//! 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 an mesh viewer. The returned pointer must not be dropped. +IGUIMeshViewer* CGUIEnvironment::addMeshViewer(const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text) +{ + IGUIMeshViewer* v = new CGUIMeshViewer(this, parent ? parent : this, + id, rectangle); + + if (text) + v->setText(text); + + v->drop(); + return v; +} + + +//! 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 tree view +IGUITreeView* CGUIEnvironment::addTreeView(const core::rect& rectangle, + IGUIElement* parent, s32 id, + bool drawBackground, + bool scrollBarVertical, bool scrollBarHorizontal) +{ + IGUITreeView* b = new CGUITreeView(this, parent ? parent : this, id, rectangle, + true, drawBackground, scrollBarVertical, scrollBarHorizontal); + + b->setIconFont ( getBuiltInFont () ); + 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; + + IGUIFileOpenDialog* d = new CGUIFileOpenDialog(title, this, parent, id, + restoreCWD, startDir); + d->drop(); + + if (modal) + { + // 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 + // careful not to get virtual function call, like OnEvent, in the window. + CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); + modalScreen->drop(); + modalScreen->addChild(d); + } + + return d; +} + + +//! adds a color select dialog. The returned pointer must not be dropped. +IGUIColorSelectDialog* CGUIEnvironment::addColorSelectDialog(const wchar_t* title, + bool modal, IGUIElement* parent, s32 id) +{ + parent = parent ? parent : this; + + IGUIColorSelectDialog* d = new CGUIColorSelectDialog( title, + this, parent, id); + d->drop(); + + if (modal) + { + // 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 + // careful not to get virtual function call, like OnEvent, in the window. + CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); + modalScreen->drop(); + modalScreen->addChild(d); + } + + 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 spin box to the environment +IGUISpinBox* CGUIEnvironment::addSpinBox(const wchar_t* text, + const core::rect &rectangle, + bool border,IGUIElement* parent, s32 id) +{ + IGUISpinBox* d = new CGUISpinBox(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(-1, this, parent ? parent : this, + rectangle, id); + t->drop(); + return t; +} + + +//! Adds a context menu to the environment. +IGUIContextMenu* CGUIEnvironment::addContextMenu(const core::rect& rectangle, + IGUIElement* parent, s32 id) +{ + IGUIContextMenu* c = new CGUIContextMenu(this, + parent ? parent : this, id, rectangle, true); + c->drop(); + return c; +} + + +//! Adds a menu to the environment. +IGUIContextMenu* CGUIEnvironment::addMenu(IGUIElement* parent, s32 id) +{ + if (!parent) + parent = this; + + IGUIContextMenu* c = new CGUIMenu(this, + parent, id, core::rect(0,0, + parent->getAbsolutePosition().getWidth(), + parent->getAbsolutePosition().getHeight())); + + c->drop(); + return c; +} + + +//! Adds a toolbar to the environment. It is like a menu is always placed on top +//! in its parent, and contains buttons. +IGUIToolBar* CGUIEnvironment::addToolBar(IGUIElement* parent, s32 id) +{ + if (!parent) + parent = this; + + IGUIToolBar* b = new CGUIToolBar(this, parent, id, core::rect(0,0,10,10)); + b->drop(); + return b; +} + + +//! Adds an element for fading in or out. +IGUIInOutFader* CGUIEnvironment::addInOutFader(const core::rect* rectangle, IGUIElement* parent, s32 id) +{ + core::rect rect; + + if (rectangle) + rect = *rectangle; + else if (Driver) + rect = core::rect(core::position2d(0,0), core::dimension2di(Driver->getScreenSize())); + + if (!parent) + parent = this; + + IGUIInOutFader* fader = new CGUIInOutFader(this, parent, id, rect); + fader->drop(); + return fader; +} + + +//! 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; + io::IXMLReader *xml = FileSystem->createXMLReader(filename ); + if (xml) + { + // this is an XML font, but we need to know what type + EGUI_FONT_TYPE t = EGFT_CUSTOM; + + bool found=false; + while(!found && xml->read()) + { + if (xml->getNodeType() == io::EXN_ELEMENT) + { + if (core::stringw(L"font") == xml->getNodeName()) + { + if (core::stringw(L"vector") == xml->getAttributeValue(L"type")) + { + t = EGFT_VECTOR; + found=true; + } + else if (core::stringw(L"bitmap") == xml->getAttributeValue(L"type")) + { + t = EGFT_BITMAP; + found=true; + } + else found=true; + } + } + } + + if (t==EGFT_BITMAP) + { + CGUIFont* font = new CGUIFont(this, filename); + ifont = (IGUIFont*)font; + // change working directory, for loading textures + io::path workingDir = FileSystem->getWorkingDirectory(); + FileSystem->changeWorkingDirectoryTo(FileSystem->getFileDir(f.NamedPath.getPath())); + + // load the font + if (!font->load(xml)) + { + font->drop(); + font = 0; + ifont = 0; + } + // change working dir back again + FileSystem->changeWorkingDirectoryTo( workingDir ); + } + else if (t==EGFT_VECTOR) + { + // todo: vector fonts + os::Printer::log("Unable to load font, XML vector fonts are not supported yet", f.NamedPath, ELL_ERROR); + + //CGUIFontVector* font = new CGUIFontVector(Driver); + //ifont = (IGUIFont*)font; + //if (!font->load(xml)) + } + xml->drop(); + } + + + 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); + + 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; +} + + +//! 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 + +#endif // _IRR_COMPILE_WITH_GUI_ + -- cgit v1.1