5d85b449aa
Added setDrawBorder to IGUIEditBox and IGUIStaticText. Added setTextAlignment to GUIEditBox and IGUIStaticText, for text justification and vertical alignment. IGUIEditbox now supports multiple lines using setWordWrap and setMultiLine. IGUIElement now calls getter and setter functions when serializing, in case of getter/setter overrides. git-svn-id: http://svn.code.sf.net/p/irrlicht/code/trunk@745 dfc29bdd-3216-0410-991c-e03cc46cb475
1362 lines
30 KiB
C++
1362 lines
30 KiB
C++
|
|
// Copyright (C) 2002-2007 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 "CGUIWindow.h"
|
|
#include "CGUIScrollBar.h"
|
|
#include "CGUIFont.h"
|
|
#include "CGUISpriteBank.h"
|
|
#include "CGUIImage.h"
|
|
#include "CGUIMeshViewer.h"
|
|
#include "CGUICheckBox.h"
|
|
#include "CGUIListBox.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 "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";
|
|
|
|
//! constructor
|
|
CGUIEnvironment::CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* driver, IOSOperator* op)
|
|
: IGUIElement(EGUIET_ELEMENT, 0, 0, 0, core::rect<s32>(core::position2d<s32>(0,0), driver ? driver->getScreenSize() : core::dimension2d<s32>(0,0))),
|
|
Driver(driver), Hovered(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.LaunchTime = 1000;
|
|
ToolTip.Element = 0;
|
|
}
|
|
|
|
|
|
//! destructor
|
|
CGUIEnvironment::~CGUIEnvironment()
|
|
{
|
|
if (Hovered && Hovered != this)
|
|
{
|
|
Hovered->drop();
|
|
Hovered = 0;
|
|
}
|
|
|
|
if (Driver)
|
|
{
|
|
Driver->drop();
|
|
Driver = 0;
|
|
}
|
|
|
|
if (Focus)
|
|
{
|
|
Focus->drop();
|
|
Focus = 0;
|
|
}
|
|
|
|
if (ToolTip.Element)
|
|
{
|
|
ToolTip.Element->drop();
|
|
ToolTip.Element = 0;
|
|
}
|
|
|
|
if (FileSystem)
|
|
{
|
|
FileSystem->drop();
|
|
FileSystem = 0;
|
|
}
|
|
|
|
if (Operator)
|
|
{
|
|
Operator->drop();
|
|
Operator = 0;
|
|
}
|
|
|
|
// drop skin
|
|
if (CurrentSkin)
|
|
{
|
|
CurrentSkin->drop();
|
|
CurrentSkin = 0;
|
|
}
|
|
|
|
// delete all fonts
|
|
u32 i;
|
|
|
|
for (i=0; i<Fonts.size(); ++i)
|
|
Fonts[i].Font->drop();
|
|
|
|
// remove all factories
|
|
for (i=0; i<GUIElementFactoryList.size(); ++i)
|
|
GUIElementFactoryList[i]->drop();
|
|
|
|
}
|
|
|
|
|
|
void CGUIEnvironment::loadBuiltInFont()
|
|
{
|
|
const c8* filename = "#DefaultFont";
|
|
io::IReadFile* file = io::createMemoryReadFile(BuiltInFontData, BuiltInFontDataSize, filename, false);
|
|
|
|
CGUIFont* font = new CGUIFont(this, "#DefaultFont");
|
|
if (!font->load(file))
|
|
{
|
|
os::Printer::log("Error: Could not load built-in Font.", ELL_ERROR);
|
|
font->drop();
|
|
file->drop();
|
|
return;
|
|
}
|
|
|
|
SFont f;
|
|
f.Filename = filename;
|
|
f.Font = font;
|
|
Fonts.push_back(f);
|
|
|
|
file->drop();
|
|
}
|
|
|
|
|
|
|
|
//! draws all gui elements
|
|
void CGUIEnvironment::drawAll()
|
|
{
|
|
if (Driver)
|
|
{
|
|
core::dimension2d<s32> dim = Driver->getScreenSize();
|
|
if (AbsoluteRect.LowerRightCorner.X != dim.Width ||
|
|
AbsoluteRect.LowerRightCorner.Y != dim.Height)
|
|
{
|
|
// resize gui environment
|
|
DesiredRect.LowerRightCorner.X = Driver->getScreenSize().Width;
|
|
DesiredRect.LowerRightCorner.Y = Driver->getScreenSize().Height;
|
|
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
|
|
void CGUIEnvironment::setFocus(IGUIElement* element)
|
|
{
|
|
if (Focus == element)
|
|
return;
|
|
|
|
// GUI Environment should not get the focus
|
|
if (element == this)
|
|
element = 0;
|
|
|
|
removeFocus(Focus);
|
|
|
|
Focus = element;
|
|
|
|
if (Focus)
|
|
{
|
|
Focus->grab();
|
|
|
|
// send focused event
|
|
SEvent e;
|
|
e.EventType = EET_GUI_EVENT;
|
|
e.GUIEvent.Caller = Focus;
|
|
e.GUIEvent.EventType = EGET_ELEMENT_FOCUSED;
|
|
Focus->OnEvent(e);
|
|
}
|
|
}
|
|
|
|
//! returns the element with the focus
|
|
IGUIElement* CGUIEnvironment::getFocus()
|
|
{
|
|
return Focus;
|
|
}
|
|
|
|
|
|
//! removes the focus from an element
|
|
void CGUIEnvironment::removeFocus(IGUIElement* element)
|
|
{
|
|
if (Focus && Focus==element)
|
|
{
|
|
SEvent e;
|
|
e.EventType = EET_GUI_EVENT;
|
|
e.GUIEvent.Caller = Focus;
|
|
e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST;
|
|
Focus->OnEvent(e);
|
|
if (Focus)
|
|
Focus->drop();
|
|
Focus = 0;
|
|
}
|
|
}
|
|
|
|
|
|
//! Returns if the element has focus
|
|
bool CGUIEnvironment::hasFocus(IGUIElement* element)
|
|
{
|
|
bool ret = (element == Focus);
|
|
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
|
|
return ret;
|
|
}
|
|
|
|
|
|
//! returns the current video driver
|
|
video::IVideoDriver* CGUIEnvironment::getVideoDriver()
|
|
{
|
|
return Driver;
|
|
}
|
|
|
|
//! returns the current file system
|
|
io::IFileSystem* CGUIEnvironment::getFileSystem()
|
|
{
|
|
return FileSystem;
|
|
}
|
|
|
|
//! returns the current file system
|
|
IOSOperator* CGUIEnvironment::getOSOperator()
|
|
{
|
|
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;
|
|
}
|
|
|
|
// get the root's children in case the root changes in future
|
|
const core::list<IGUIElement*>& children = getRootGUIElement()->getChildren();
|
|
|
|
while (!children.empty())
|
|
(*children.getLast())->remove();
|
|
}
|
|
|
|
|
|
//! called by ui if an event happened.
|
|
bool CGUIEnvironment::OnEvent(SEvent event)
|
|
{
|
|
if (UserReceiver && event.GUIEvent.Caller != this)
|
|
return UserReceiver->OnEvent(event);
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
*/
|
|
void CGUIEnvironment::OnPostRender( u32 time )
|
|
{
|
|
// check tooltip
|
|
|
|
// launch tooltip
|
|
if ( time - ToolTip.LastTime >= ToolTip.LaunchTime &&
|
|
Hovered && Hovered != this &&
|
|
ToolTip.Element == 0 &&
|
|
Hovered != ToolTip.Element &&
|
|
Hovered->getToolTipText().size() &&
|
|
getSkin() &&
|
|
getSkin()->getFont(EGDF_TOOLTIP)
|
|
)
|
|
{
|
|
core::rect<s32> pos;
|
|
|
|
pos.UpperLeftCorner = LastHoveredMousePos;
|
|
core::dimension2di dim = getSkin()->getFont(EGDF_TOOLTIP)->getDimension(Hovered->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(Hovered->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);
|
|
|
|
}
|
|
|
|
IGUIElement::OnPostRender ( time );
|
|
}
|
|
|
|
/*
|
|
*/
|
|
void CGUIEnvironment::updateHoveredElement(core::position2d<s32> mousePos)
|
|
{
|
|
IGUIElement* lastHovered = Hovered;
|
|
LastHoveredMousePos = mousePos;
|
|
|
|
Hovered = getElementFromPoint(mousePos);
|
|
|
|
if (Hovered)
|
|
{
|
|
u32 now = os::Timer::getTime ();
|
|
|
|
if (Hovered != this)
|
|
Hovered->grab();
|
|
|
|
if (Hovered != lastHovered)
|
|
{
|
|
SEvent event;
|
|
event.EventType = EET_GUI_EVENT;
|
|
|
|
if (lastHovered)
|
|
{
|
|
event.GUIEvent.Caller = lastHovered;
|
|
event.GUIEvent.EventType = EGET_ELEMENT_LEFT;
|
|
lastHovered->OnEvent(event);
|
|
}
|
|
|
|
if ( ToolTip.Element )
|
|
{
|
|
ToolTip.Element->remove();
|
|
ToolTip.Element->drop();
|
|
ToolTip.Element = 0;
|
|
ToolTip.LastTime += 500;
|
|
}
|
|
else
|
|
{
|
|
// boost tooltip generation for relaunch
|
|
if ( now - ToolTip.LastTime < ToolTip.LastTime )
|
|
{
|
|
ToolTip.LastTime += 500;
|
|
}
|
|
else
|
|
{
|
|
ToolTip.LastTime = now;
|
|
}
|
|
}
|
|
|
|
|
|
event.GUIEvent.Caller = Hovered;
|
|
event.GUIEvent.EventType = EGET_ELEMENT_HOVERED;
|
|
Hovered->OnEvent(event);
|
|
}
|
|
}
|
|
|
|
if (lastHovered && lastHovered != this)
|
|
lastHovered->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(SEvent event)
|
|
{
|
|
switch(event.EventType)
|
|
{
|
|
case EET_GUI_EVENT:
|
|
// hey, why is the user sending gui events..?
|
|
break;
|
|
case EET_MOUSE_INPUT_EVENT:
|
|
|
|
// sending input to focus, stopping of focus processed input
|
|
|
|
if (Focus && Focus->OnEvent(event))
|
|
return true;
|
|
|
|
if (!Focus) // focus could have died in last call
|
|
{
|
|
// trying to send input to hovered element
|
|
updateHoveredElement(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
|
|
|
|
if (Hovered && Hovered != this)
|
|
return Hovered->OnEvent(event);
|
|
}
|
|
break;
|
|
case EET_KEY_INPUT_EVENT:
|
|
if (Focus && Focus != this)
|
|
return Focus->OnEvent(event);
|
|
break;
|
|
} // end switch
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
//! returns the current gui skin
|
|
IGUISkin* CGUIEnvironment::getSkin()
|
|
{
|
|
return CurrentSkin;
|
|
}
|
|
|
|
|
|
//! Sets a new GUI Skin
|
|
void CGUIEnvironment::setSkin(IGUISkin* skin)
|
|
{
|
|
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 IUnknown::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()
|
|
{
|
|
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.
|
|
s32 CGUIEnvironment::getRegisteredGUIElementFactoryCount()
|
|
{
|
|
return GUIElementFactoryList.size();
|
|
}
|
|
|
|
//! Returns a scene node factory by index
|
|
IGUIElementFactory* CGUIEnvironment::getGUIElementFactory(s32 index)
|
|
{
|
|
if (index>=0 && index<(int)GUIElementFactoryList.size())
|
|
return GUIElementFactoryList[index];
|
|
|
|
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=0; i<(int)GUIElementFactoryList.size() && !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 c8* filename, IGUIElement* start)
|
|
{
|
|
io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
|
|
if (!file)
|
|
return false;
|
|
|
|
bool ret = saveGUI(file, start);
|
|
file->drop();
|
|
return ret;
|
|
}
|
|
|
|
|
|
//! Saves the current gui into a file.
|
|
bool CGUIEnvironment::saveGUI(io::IWriteFile* file, IGUIElement* start)
|
|
{
|
|
if (!file)
|
|
return false;
|
|
|
|
io::IXMLWriter* writer = FileSystem->createXMLWriter(file);
|
|
if (!writer)
|
|
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 c8* filename, IGUIElement* parent)
|
|
{
|
|
io::IReadFile* read = FileSystem->createAndOpenFile(filename);
|
|
if (!read)
|
|
{
|
|
os::Printer::log("Unable to open gui file", filename, ELL_ERROR);
|
|
return false;
|
|
}
|
|
|
|
bool ret = loadGUI(read, parent);
|
|
read->drop();
|
|
|
|
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);
|
|
return false;
|
|
}
|
|
|
|
io::IXMLReader* reader = FileSystem->createXMLReader(file);
|
|
if (!reader)
|
|
{
|
|
os::Printer::log("GUI is not a valid XML file", file->getFileName(), ELL_ERROR);
|
|
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* parent)
|
|
{
|
|
if (!reader)
|
|
return;
|
|
|
|
gui::IGUIElement* node = 0;
|
|
|
|
if (reader->getNodeType() == io::EXN_NONE)
|
|
reader->read();
|
|
|
|
if (reader->getNodeType() == io::EXN_UNKNOWN)
|
|
reader->read();
|
|
|
|
if (!parent && !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName()))
|
|
{
|
|
node = this; // root
|
|
}
|
|
else if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()))
|
|
{
|
|
// find node type and create it
|
|
core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE);
|
|
|
|
node = addGUIElement(attrName.c_str(), parent);
|
|
|
|
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()))
|
|
{
|
|
readGUIElement(reader, node);
|
|
}
|
|
else
|
|
{
|
|
os::Printer::log("Found unknown element in irrlicht GUI file",
|
|
core::stringc(reader->getNodeName()).c_str());
|
|
}
|
|
|
|
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<IGUIElement*>::Iterator 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)
|
|
{
|
|
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<s32>(core::position2d<s32>(0,0),
|
|
Driver ? Driver->getScreenSize() : core::dimension2d<s32>(0,0));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! adds an button. The returned pointer must not be dropped.
|
|
IGUIButton* CGUIEnvironment::addButton(const core::rect<s32>& 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<s32>& rectangle, bool modal,
|
|
const wchar_t* text, IGUIElement* parent, s32 id)
|
|
{
|
|
parent = parent ? parent : this;
|
|
|
|
if (modal)
|
|
{
|
|
parent = new CGUIModalScreen(this, parent, -1);
|
|
parent->drop();
|
|
}
|
|
|
|
IGUIWindow* win = new CGUIWindow(this, parent, id, rectangle);
|
|
if (text)
|
|
win->setText(text);
|
|
win->drop();
|
|
|
|
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)
|
|
{
|
|
if (!CurrentSkin)
|
|
return 0;
|
|
|
|
parent = parent ? parent : this;
|
|
|
|
core::rect<s32> rect;
|
|
core::dimension2d<s32> screenDim, msgBoxDim;
|
|
|
|
screenDim.Width = parent->getAbsolutePosition().getWidth();
|
|
screenDim.Height = parent->getAbsolutePosition().getHeight();
|
|
msgBoxDim.Width = CurrentSkin->getSize(gui::EGDS_MESSAGE_BOX_WIDTH);
|
|
msgBoxDim.Height = CurrentSkin->getSize(gui::EGDS_MESSAGE_BOX_HEIGHT);
|
|
|
|
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;
|
|
|
|
if (modal)
|
|
{
|
|
parent = new CGUIModalScreen(this, parent, -1);
|
|
parent->drop();
|
|
}
|
|
|
|
IGUIWindow* win = new CGUIMessageBox(this, caption, text, flag,
|
|
parent, id, rect);
|
|
|
|
win->drop();
|
|
return win;
|
|
}
|
|
|
|
|
|
//! adds a scrollbar. The returned pointer must not be dropped.
|
|
IGUIScrollBar* CGUIEnvironment::addScrollBar(bool horizontal, const core::rect<s32>& 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<s32> pos,
|
|
bool useAlphaChannel, IGUIElement* parent, s32 id, const wchar_t* text)
|
|
{
|
|
core::dimension2d<s32> sz(0,0);
|
|
if (image)
|
|
sz = image->getOriginalSize();
|
|
|
|
IGUIImage* img = new CGUIImage(this, parent ? parent : this,
|
|
id, core::rect<s32>(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<s32>& rectangle, IGUIElement* parent, s32 id, const wchar_t* text)
|
|
{
|
|
IGUIImage* img = new CGUIImage(this, parent ? parent : this,
|
|
id, rectangle);
|
|
|
|
if (text)
|
|
img->setText(text);
|
|
|
|
img->drop();
|
|
return img;
|
|
}
|
|
|
|
|
|
//! adds an mesh viewer. The returned pointer must not be dropped.
|
|
IGUIMeshViewer* CGUIEnvironment::addMeshViewer(const core::rect<s32>& 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<s32>& 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<s32>& rectangle,
|
|
IGUIElement* parent, s32 id,
|
|
bool drawBackground)
|
|
{
|
|
IGUIListBox* b = new CGUIListBox(this, parent ? parent : this, id, rectangle,
|
|
true, drawBackground, false);
|
|
|
|
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)
|
|
{
|
|
parent = parent ? parent : this;
|
|
|
|
if (modal)
|
|
{
|
|
parent = new CGUIModalScreen(this, parent, -1);
|
|
parent->drop();
|
|
}
|
|
|
|
IGUIFileOpenDialog* d = new CGUIFileOpenDialog(title, this, parent, id);
|
|
|
|
d->drop();
|
|
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;
|
|
|
|
if (modal)
|
|
{
|
|
parent = new CGUIModalScreen(this, parent, -1);
|
|
parent->drop();
|
|
}
|
|
|
|
IGUIColorSelectDialog* d = new CGUIColorSelectDialog( title,
|
|
this, parent, id);
|
|
|
|
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<s32>& 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<s32>& 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<s32> &rectangle,
|
|
IGUIElement* parent, s32 id)
|
|
{
|
|
IGUISpinBox* d = new CGUISpinBox(text, this, parent ? parent : this, id, rectangle);
|
|
|
|
d->drop();
|
|
return d;
|
|
}
|
|
|
|
|
|
//! Adds a tab control to the environment.
|
|
IGUITabControl* CGUIEnvironment::addTabControl(const core::rect<s32>& 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<s32>& 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<s32>& 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<s32>(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<s32>(0,0,10,10));
|
|
b->drop();
|
|
return b;
|
|
}
|
|
|
|
|
|
|
|
//! Adds an element for fading in or out.
|
|
IGUIInOutFader* CGUIEnvironment::addInOutFader(const core::rect<s32>* rectangle, IGUIElement* parent, s32 id)
|
|
{
|
|
core::rect<s32> rect;
|
|
|
|
if (rectangle)
|
|
rect = *rectangle;
|
|
else
|
|
if (Driver)
|
|
rect = core::rect<s32>(core::position2d<s32>(0,0), 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<s32>& 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 c8* filename)
|
|
{
|
|
// search existing font
|
|
|
|
SFont f;
|
|
IGUIFont* ifont=0;
|
|
if (!filename)
|
|
f.Filename = "";
|
|
else
|
|
f.Filename = filename;
|
|
|
|
f.Filename.make_lower();
|
|
|
|
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.Filename.c_str(), ELL_ERROR);
|
|
return 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(xml->read() && !found)
|
|
{
|
|
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
|
|
core::stringc workingDir = FileSystem->getWorkingDirectory();
|
|
FileSystem->changeWorkingDirectoryTo(FileSystem->getFileDir(f.Filename).c_str());
|
|
|
|
// load the font
|
|
if (!font->load(xml))
|
|
{
|
|
font->drop();
|
|
font = 0;
|
|
ifont = 0;
|
|
}
|
|
// change working dir back again
|
|
FileSystem->changeWorkingDirectoryTo( workingDir.c_str());
|
|
}
|
|
else if (t==EGFT_VECTOR)
|
|
{
|
|
// todo: vector fonts
|
|
os::Printer::log("Unable to load font, XML vector fonts are not supported yet", f.Filename.c_str(), ELL_ERROR);
|
|
|
|
//CGUIFontVector* font = new CGUIFontVector(Driver);
|
|
//ifont = (IGUIFont*)font;
|
|
//if (!font->load(xml))
|
|
}
|
|
xml->drop();
|
|
}
|
|
|
|
|
|
if (!ifont)
|
|
{
|
|
|
|
CGUIFont* font = new CGUIFont(this, f.Filename.c_str());
|
|
ifont = (IGUIFont*)font;
|
|
if (!font->load(f.Filename.c_str()))
|
|
{
|
|
font->drop();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// add to fonts.
|
|
|
|
f.Font = ifont;
|
|
Fonts.push_back(f);
|
|
|
|
return ifont;
|
|
}
|
|
|
|
IGUISpriteBank* CGUIEnvironment::getSpriteBank(const c8* filename)
|
|
{
|
|
// search for the file name
|
|
|
|
SSpriteBank b;
|
|
if (!filename)
|
|
b.Filename = "";
|
|
else
|
|
b.Filename = filename;
|
|
|
|
b.Filename.make_lower();
|
|
|
|
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.Filename.c_str()))
|
|
{
|
|
os::Printer::log("Could not load sprite bank because the file does not exist", filename, ELL_ERROR);
|
|
return 0;
|
|
}
|
|
|
|
// todo: load it!
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
IGUISpriteBank* CGUIEnvironment::addEmptySpriteBank(const c8 *name)
|
|
{
|
|
// no duplicate names allowed
|
|
|
|
SSpriteBank b;
|
|
if (!name)
|
|
b.Filename = "";
|
|
else
|
|
b.Filename = name;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
//! returns default font
|
|
IGUIFont* CGUIEnvironment::getBuiltInFont()
|
|
{
|
|
if (Fonts.empty())
|
|
return 0;
|
|
|
|
return Fonts[0].Font;
|
|
}
|
|
|
|
|
|
|
|
//! Returns the root gui element.
|
|
IGUIElement* CGUIEnvironment::getRootGUIElement()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
|
|
|
|
//! 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
|
|
|