Multiple EventReceivers ?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Airslash
Posts: 17
Joined: Wed Jan 16, 2008 2:35 pm

Multiple EventReceivers ?

Post by Airslash »

Is it possible to add Multiple eventrecievers to the Irrlicht device instead of one ? I'm kinda against the idea to have 1 reciever handle every possible event.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Re: Multiple EventReceivers ?

Post by rogerborg »

Airslash wrote:Is it possible to add Multiple eventrecievers to the Irrlicht device instead of one ?
No.

I'm kinda against the idea to have 1 reciever handle every possible event.
I'm going to go out on a limb and guess that what offends you is the idea of one function handling all events, not one instance of a class.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
radical-dev
Posts: 45
Joined: Thu Apr 24, 2008 7:54 pm
Location: Wickede, Germany

Post by radical-dev »

You can set a new EventReceiver with IrrlichtDevice->setEventReceiver().

So you can write a Eventreceiver for every Gamestate your app has for example. But it can only work one at a time.
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Post by christianclavet »

You can use the magic search button of the forum! :D I've resolved that problem first by getting some info there. The answer is there. There is a way to handle multiple event receiver. Search the forum.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

christianclavet wrote:There is a way to handle multiple event receiver. Search the forum.
All of the 'solutions' that I can find are variations on registering one event receiver that passes events on to other objects. This is not the same as "add[ing] multiple event receivers to the Irrlicht device", although it does allow splitting the event handling logic up. But so would having one event receiver class with multiple functions that each handle a subset of events.

Sorry if I seem lecturish, but this just seems so trivial and obvious that I'm astonished that anyone put any time in to 'solving' it.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
CuteAlien
Admin
Posts: 9736
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

rogerborg wrote:Sorry if I seem lecturish, but this just seems so trivial and obvious that I'm astonished that anyone put any time in to 'solving' it.
Come on - you know that many people use Irrlicht to learn programming. Don't you remember anymore how it's been to learn the basic concepts, like what's the sense of this "function" thingy?.

And yeah, I also only posted the simple solutions so far - those are just the first step, but can get a beginner already quite far. Like http://irrlicht.sourceforge.net/phpBB2/ ... highlight=.
Better solutions include callbacks or functors, might even need some additional hacks within the engine and are just way more tricky to explain.

Just for fun I'll try to explain the basic idea behind the system I'm using here. I care mostly about gui-events and I'm using a functor system for that.

- The first step is a global system to register events like the one posted in the link above.

- The second step is that all my gui-elements are combined in a custom Window class which is itself derived from an IEventReceiver. Those classes register themself in the base constructor at the global system, so that each derived Window has it's own OnEvent which just can be used by overloading. For each dialog in my game I have my own derived Window class.

- The third step is that I use OnEvent only for the non-gui events as typing endless case-switch stuff is too much work for a large gui system. So instead I am using a custom functor system where I can register functions per event and per ID. In my Window base class the OnEvent filters out Gui-events and searchs for matching functors and executes those.

My functor class looks like that:

Code: Select all

#ifndef _EVENT_FUNCTOR_H
#define _EVENT_FUNCTOR_H

namespace irr
{
	struct SEvent;
}

class IEventFunctor : public irr::IUnknown
{
public:
    virtual ~IEventFunctor() {}
	virtual bool CallEvent(const irr::SEvent &event_) = 0;
};

// general functor for irrlicht events
template <class T>
class EventFunctor : public IEventFunctor
{
public:
    EventFunctor(T* obj_, bool (T::* fpt_)(const irr::SEvent &event_))
    {
        mObj = obj_;
        mFunctionPtr = fpt_;
    }
    virtual ~EventFunctor() {}
    virtual bool CallEvent(const irr::SEvent &event_)
    {
        return (*mObj.*mFunctionPtr)(event_);
    }

private:
    bool (T::*  mFunctionPtr)(const irr::SEvent &event_);
    T*          mObj;
};

// Restrict the functor to gui events of the type set in mGuiEventType
class GuiEventFunctor
{
public:
	GuiEventFunctor(IEventFunctor* func_, irr::gui::EGUI_EVENT_TYPE type_) 
		: mFunctor(func_), mGuiEventType(type_) 
	{ 
		if ( mFunctor )
			mFunctor->grab(); 
	}

	GuiEventFunctor(const GuiEventFunctor& f)
		: mFunctor(0), mGuiEventType( irr::gui::EGUI_EVENT_TYPE(0) ) 
	{
		*this = f;
	}

	virtual ~GuiEventFunctor()
	{
		if ( mFunctor )
			mFunctor->drop();
	}

	GuiEventFunctor& operator=(const GuiEventFunctor& f)
	{
		mFunctor = f.mFunctor;
		mFunctor->grab();
		mGuiEventType = f.mGuiEventType;
		return *this;
	}

	IEventFunctor*				mFunctor;
	irr::gui::EGUI_EVENT_TYPE	mGuiEventType;
};

#endif // _EVENT_FUNCTOR_H
As you can (or can't) see they contain the object and function which is used for the callback and the GuiEventFunctor is specialized to filter for a certain eventtype.

Then my basewindow contains a map which maps between the element-id for which we get the event and the functors which should be called. Like:

Code: Select all

    typedef std::multimap<int, GuiEventFunctor> GuiEventFunctorMultiMap;
    GuiEventFunctorMultiMap mGuiEventFunctors;
And each time I get now a GUI-Event in my OnEvent in my Window base class I search for corresponding functors to call:

Code: Select all

// call either all functors which are registered for this event or until one returns true
typedef GuiEventFunctorMultiMap::const_iterator CI;
std::pair<CI,CI> foundFunctors = mGuiEventFunctors.equal_range(event_.GUIEvent.Caller->getID());
for ( CI it=foundFunctors.first; it!=foundFunctors.second; ++it )
{
	if ( it->second.mGuiEventType == event_.GUIEvent.EventType )
	{
		if ( it->second.mFunctor->CallEvent(event_) )
			return true;
	}
}
- The fourth step includes some modification to Irrlicht, so I can use names instead of ID's as from a certain size of the project on (like more than one dialog...) ID's get too confusing.

- The fifth step includes loading from the elements from xml, indentifying them by name and adding functors as event handlers. In the end it looks like that when I add an button:

Code: Select all

ADD_EVENT_HANDLER("buttonOK", EGET_BUTTON_CLICKED, MyDialog, OnOK );
Step 4 and 5 include a lot more code, but that's just too much for posting in a thread now. I'll plan to clean that up some day (which means mostly creating some patches) and will post it then on some site. But not sure when I'll find time for that.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Airslash
Posts: 17
Joined: Wed Jan 16, 2008 2:35 pm

Post by Airslash »

Cheers for the tips , it does put me in a certain direction to continue my work.

yes i'm against the "solution" that one method handles several things. Each method in my programs/projects should handle just that what it stands for, nothing more and nothing less.

Makes it complicated at some points but in the end it's definitly worth it for me, because I managed to program given a certain system.

I'm currently more tempted to just split the class in several subclasses, and throw custom Exceptions or something similar (or just invoke other methods) to get the desired result that I need.
Post Reply