Example (altered Example No. 5)
Code: Select all
/** Example 005 User Interface
This tutorial shows how to use the built in User Interface of
the Irrlicht Engine. It will give a brief overview and show
how to create and use windows, buttons, scroll bars, static
texts, and list boxes.
As always, we include the header files, and use the irrlicht
namespaces. We also store a pointer to the Irrlicht device,
a counter variable for changing the creation position of a window,
and a pointer to a listbox.
*/
#include <irrlicht.h>
#include "driverChoice.h"
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif
// Declare a structure to hold some context for the event receiver so that it
// has it available inside its OnEvent() method.
struct SAppContext
{
IrrlichtDevice *device;
s32 counter;
IGUIListBox* listbox;
};
#include "CGUIEventDispatcher.h"
class MyEvents
{
public:
MyEvents(SAppContext & context)
{
Context = context;
env = Context.device->getGUIEnvironment();
}
bool onTransparentChanged(const irr::SEvent::SGUIEvent& event)
{
s32 pos = ((IGUIScrollBar*)event.Caller)->getPos();
for (u32 i=0; i<EGDC_COUNT ; ++i)
{
SColor col = env->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
col.setAlpha(pos);
env->getSkin()->setColor((EGUI_DEFAULT_COLOR)i, col);
}
}
bool onNewWindow(const irr::SEvent::SGUIEvent& event)
{
Context.listbox->addItem(L"Window created");
Context.counter += 30;
if (Context.counter > 200)
Context.counter = 0;
IGUIWindow* window = env->addWindow(
rect<s32>(100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter),
false, // modal?
L"Test window");
env->addStaticText(L"Please close me",
rect<s32>(35,35,140,50),
true, // border?
false, // wordwrap?
window);
return true;
}
bool onQuit(const irr::SEvent::SGUIEvent& event)
{
Context.device->closeDevice();
}
bool onFileOpenButton(const irr::SEvent::SGUIEvent& event)
{
Context.listbox->addItem(L"File open");
env->addFileOpenDialog(L"Please choose a file.");
return true;
}
IGUIEnvironment* env;
SAppContext Context;
};
bool onQuit(const irr::SEvent::SGUIEvent& event)
{
printf("Pressed close button\n");
return false;
}
/*
Ok, now for the more interesting part. First, create the Irrlicht device. As in
some examples before, we ask the user which driver he wants to use for this
example:
*/
int main()
{
// ask user for driver
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
if (driverType==video::EDT_COUNT)
return 1;
// create device and exit if creation failed
IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(640, 480));
if (device == 0)
return 1; // could not create selected driver.
/* The creation was successful, now we set the event receiver and
store pointers to the driver and to the gui environment. */
device->setWindowCaption(L"Irrlicht Engine - User Interface Demo");
device->setResizable(true);
video::IVideoDriver* driver = device->getVideoDriver();
IGUIEnvironment* env = device->getGUIEnvironment();
/*
To make the font a little bit nicer, we load an external font
and set it as the new default font in the skin.
To keep the standard font for tool tip text, we set it to
the built-in font.
*/
IGUISkin* skin = env->getSkin();
IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
if (font)
skin->setFont(font);
skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP);
/*
We add three buttons. The first one closes the engine. The second
creates a window and the third opens a file open dialog. The third
parameter is the id of the button, with which we can easily identify
the button in the event receiver.
*/
irr::gui::IGUIElement* quitButton = env->addButton(rect<s32>(10,240,110,240 + 32), 0, -1,
L"Quit", L"Exits Program");
irr::gui::IGUIElement* newWindowButton = env->addButton(rect<s32>(10,280,110,280 + 32), 0, -1,
L"New Window", L"Launches a new Window");
irr::gui::IGUIElement* fileopenButton = env->addButton(rect<s32>(10,320,110,320 + 32), 0, -1,
L"File Open", L"Opens a file");
/*
Now, we add a static text and a scrollbar, which modifies the
transparency of all gui elements. We set the maximum value of
the scrollbar to 255, because that's the maximal value for
a color value.
Then we create an other static text and a list box.
*/
env->addStaticText(L"Transparent Control:", rect<s32>(150,20,350,40), true);
IGUIScrollBar* scrollbar = env->addScrollBar(true,
rect<s32>(150, 45, 350, 60), 0, -1);
scrollbar->setMax(255);
// set scrollbar position to alpha value of an arbitrary element
scrollbar->setPos(env->getSkin()->getColor(EGDC_WINDOW).getAlpha());
env->addStaticText(L"Logging ListBox:", rect<s32>(50,110,250,130), true);
IGUIListBox * listbox = env->addListBox(rect<s32>(50, 140, 250, 210));
env->addEditBox(L"Editable Text", rect<s32>(350, 80, 550, 100));
// Store the appropriate data in a context structure.
SAppContext context;
context.device = device;
context.counter = 0;
context.listbox = listbox;
// Then create the event receiver, giving it that context structure.
MyEvents receiver(context);
CGUIEventDispatcher dispatcher;
//you can also bind simple functions
dispatcher.bind(quitButton, onQuit, irr::gui::EGET_BUTTON_CLICKED);
//Button clicks
dispatcher.bind(quitButton, &receiver, &MyEvents::onQuit, irr::gui::EGET_BUTTON_CLICKED);
dispatcher.bind(newWindowButton, &receiver, &MyEvents::onNewWindow, irr::gui::EGET_BUTTON_CLICKED);
dispatcher.bind(fileopenButton, &receiver, &MyEvents::onFileOpenButton, irr::gui::EGET_BUTTON_CLICKED);
//Scrollbar changed
dispatcher.bind(scrollbar, &receiver, &MyEvents::onTransparentChanged, irr::gui::EGET_SCROLL_BAR_CHANGED);
// And tell the device to use our custom event receiver.
device->setEventReceiver(&dispatcher);
/*
And at last, we create a nice Irrlicht Engine logo in the top left corner.
*/
env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"),
position2d<int>(10,10));
/*
That's all, we only have to draw everything.
*/
while(device->run() && driver)
if (device->isWindowActive())
{
driver->beginScene(true, true, SColor(0,200,200,200));
env->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
Code: Select all
#ifndef CGUIEVENTDISPATCHER_H
#define CGUIEVENTDISPATCHER_H
#include <IEventReceiver.h>
#include <irrArray.h>
#include <irrList.h>
class CGUIEventDispatcher : public irr::IEventReceiver
{
public:
/** Default constructor */
CGUIEventDispatcher();
/** Default destructor */
virtual ~CGUIEventDispatcher();
virtual bool OnEvent(const irr::SEvent& event);
bool bind(irr::gui::IGUIElement* element, bool (*func)(const irr::SEvent::SGUIEvent&), irr::gui::EGUI_EVENT_TYPE type = irr::gui::EGET_COUNT);
template<class T>
bool bind(irr::gui::IGUIElement* element, T* c, bool (T::*func)(const irr::SEvent::SGUIEvent&), irr::gui::EGUI_EVENT_TYPE type = irr::gui::EGET_COUNT)
{
Storage::Iterator it = Bindings.begin();
while(it != Bindings.end())
{
if ((*it) == element && (*it).checkClass(c))
return false;
else if ((*it) == element)
{
(*it).Data.push_back(new CMethodHandle<T>(c, func, type));
return true;
}
++it;
}
Pair p;
p.Key = element;
p.Data.push_back(new CMethodHandle<T>(c, func, type));
Bindings.push_back(p);
return true;
}
void unbind(irr::gui::IGUIElement* element);
void unbind(irr::gui::IGUIElement* element, bool (*func)(const irr::SEvent::SGUIEvent&));
template<class T>
void unbind(irr::gui::IGUIElement* element, T* c)
{
Storage::Iterator it = Bindings.begin();
while(it != Bindings.end())
{
if ((*it) == element)
{
bool r = (*it).releaseClass(c);
return;
}
++it;
}
}
template<class T>
void unbind(T* c)
{
Storage::Iterator it = Bindings.begin();
while(it != Bindings.end())
{
bool r = (*it).releaseClass(c);
++it;
}
}
protected:
typedef bool (*FuncHandle)(const irr::SEvent::SGUIEvent&);
struct IHandle
{
IHandle(irr::gui::EGUI_EVENT_TYPE type = irr::gui::EGET_COUNT)
{
EventType = type;
}
virtual ~IHandle(void){};
virtual bool call(const irr::SEvent::SGUIEvent& event) = 0;
virtual bool checkFunc(FuncHandle f) const = 0;
virtual bool checkClass(void* c) const = 0;
virtual const irr::gui::EGUI_EVENT_TYPE& getType(void)const{return EventType;}
irr::gui::EGUI_EVENT_TYPE EventType;
};
struct CFunctionHandle : IHandle
{
CFunctionHandle(FuncHandle f, irr::gui::EGUI_EVENT_TYPE type): IHandle(type), Func(f)
{}
bool call(const irr::SEvent::SGUIEvent& event)
{
if (getType() == irr::gui::EGET_COUNT || getType() == event.EventType)
return Func(event);
return false;
}
bool checkFunc(FuncHandle f) const
{
return f == Func;
}
bool checkClass(void* c) const
{
return false;
}
FuncHandle Func;
};
template<class T>
struct CMethodHandle : IHandle
{
typedef bool (T::*MethodHandle)(const irr::SEvent::SGUIEvent&);
CMethodHandle(T* c, MethodHandle f, irr::gui::EGUI_EVENT_TYPE type): IHandle(type),Func(f), Class(c)
{
}
bool call(const irr::SEvent::SGUIEvent& event)
{
if (getType() == irr::gui::EGET_COUNT || getType() == event.EventType)
return (Class->*Func)(event);
return false;
}
bool checkFunc(FuncHandle f) const
{
return false;
}
bool checkClass(void* c) const
{
return Class == c;
}
MethodHandle Func;
T* Class;
};
typedef irr::core::array<IHandle*> Link;
struct Pair
{
Pair(void) : Key(0){}
Pair (const Pair& other)
{
*this = other;
}
Pair& operator= (const Pair& other)
{
Key = other.Key;
Data = other.Data;
return *this;
}
bool operator==(const irr::gui::IGUIElement* key)
{
return Key == key;
}
bool call(const irr::SEvent::SGUIEvent& event)
{
for (irr::u32 i=0;i<Data.size();++i)
{
if (Data[i]->call(event))
return true;
}
return false;
}
bool checkFunc(FuncHandle f)
{
for (irr::u32 i=0;i<Data.size();++i)
{
if (Data[i]->checkFunc(f))
return true;
}
return false;
}
bool checkClass(void* c)
{
for (irr::u32 i=0;i<Data.size();++i)
{
if (Data[i]->checkClass(c))
return true;
}
return false;
}
bool releaseFunc(FuncHandle f)
{
for (irr::u32 i=0;i<Data.size();++i)
{
if (Data[i]->checkFunc(f))
{
delete Data[i];
Data.erase(i);
return true;
}
}
return false;
}
bool releaseClass(void* c)
{
for (irr::u32 i=0;i<Data.size();++i)
{
if (Data[i]->checkClass(c))
{
delete Data[i];
Data.erase(i);
return true;
}
}
return false;
}
void releaseHandle(void)
{
for (irr::u32 i=0;i<Data.size();++i)
{
delete Data[i];
}
Data.clear();
}
irr::gui::IGUIElement* Key;
Link Data;
};
typedef irr::core::list<Pair> Storage;
Storage Bindings;
private:
};
#endif // CGUIEVENTDISPATCHER_H
Code: Select all
/*
Copyright (C) 2011 Daniel Sudmann
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Daniel Sudmann suddani@googlemail.com
*/
#include "CGUIEventDispatcher.h"
CGUIEventDispatcher::CGUIEventDispatcher()
{
//ctor
}
CGUIEventDispatcher::~CGUIEventDispatcher()
{
//dtor
}
bool CGUIEventDispatcher::OnEvent(const irr::SEvent& event)
{
if (event.EventType == irr::EET_GUI_EVENT)
{
irr::gui::IGUIElement* caller = event.GUIEvent.Caller;
Storage::Iterator it = Bindings.begin();
while(it != Bindings.end())
{
if ((*it) == caller)
return (*it).call(event.GUIEvent);
++it;
}
}
return false;
}
bool CGUIEventDispatcher::bind(irr::gui::IGUIElement* element, bool (*func)(const irr::SEvent::SGUIEvent&), irr::gui::EGUI_EVENT_TYPE type)
{
Storage::Iterator it = Bindings.begin();
while(it != Bindings.end())
{
if ((*it) == element && (*it).checkFunc(func))
return false;
else if ((*it) == element)
{
(*it).Data.push_back(new CFunctionHandle(func, type));
return true;
}
++it;
}
Pair p;
p.Key = element;
p.Data.push_back(new CFunctionHandle(func, type));
Bindings.push_back(p);
return true;
}
void CGUIEventDispatcher::unbind(irr::gui::IGUIElement* element)
{
Storage::Iterator it = Bindings.begin();
while(it != Bindings.end())
{
if ((*it) == element)
{
(*it).releaseHandle();
Bindings.erase(it);
return;
}
++it;
}
}
void CGUIEventDispatcher::unbind(irr::gui::IGUIElement* element, bool (*func)(const irr::SEvent::SGUIEvent&))
{
Storage::Iterator it = Bindings.begin();
while(it != Bindings.end())
{
if ((*it) == element)
{
bool r = (*it).releaseFunc(func);
return;
}
++it;
}
}