Page 1 of 2

Bug? Focused window ruins EGET_MENU_ITEM event?

Posted: Mon May 09, 2011 2:36 pm
by Virror
I ran across something strange while playing around with a Table and a ContextMenu. Strange thing is that EGET_MENU_ITEM works very well, until i select something from the Table, then i stop getting EGET_MENU_ITEM events. Also, are EGET_MENU_ITEM not working with sub-menus?

Posted: Mon May 09, 2011 2:50 pm
by Digan
Maybe elements of the ContextMenu and elements of tables have the equal ID?

Posted: Mon May 09, 2011 3:00 pm
by Virror
I have tried to create all menus and elements with different ids, but same problem.

Posted: Mon May 09, 2011 3:24 pm
by CuteAlien
I don't know about such a bug so far.

It would help if you could post code which I can use to reproduce the problem (it's easier for you to do this, as you can start with a reproducible bug, while I would have to go on a wild hunt writing examples until I might or might not run in a problem and often people here see the problem anyway as soon as they see the code).

Posted: Mon May 09, 2011 7:52 pm
by Virror
Hmm, realized that it happens when the window the table is in has focus, not only when an item is selected. Currently i do this:

Code: Select all

if(event.GUIEvent.Caller == contextMenu)
		{
			if(event.GUIEvent.EventType == EGET_MENU_ITEM_SELECTED)
			{
				switch(contextMenu->getSelectedItem())
				{
Maybe it cant be done that way when i have focus on a window? Wrong event caller?

And, why cant i get event on a submenu? Is it not possible?

Edit code for Gui creation:

Code: Select all

	// Inventory
	IGUIWindow * inventoryWindow = irrGui->addWindow(rect<s32>(674, 100, 994, 600), false, L"Inventory");
	inventoryWindow->setVisible(false);
	irrGui->addStaticText(L"Equipment",rect<s32>(10, 30, 310, 45),false,true,inventoryWindow);
	IGUITable * equipmentTree = irrGui->addTable(rect<s32>(10, 45, 310, 75),inventoryWindow, -1, false);
	equipmentTree->addColumn(L"Body part");
	equipmentTree->addColumn(L"Item");
	equipmentTree->addColumn(L"Weight");
	equipmentTree->setColumnWidth(0,78);
	equipmentTree->setColumnWidth(1,170);
	equipmentTree->addRow(0);
	equipmentTree->setCellText(0,0,L"Hand:");
	irrGui->addStaticText(L"Items",rect<s32>(10, 85, 310, 100),false,true,inventoryWindow);
	IGUITable * invTree = irrGui->addTable(rect<s32>(10, 100, 310, 470),inventoryWindow, -1, false);
	invTree->addColumn(L"Item");
	invTree->addColumn(L"Weight");
	invTree->setColumnWidth(0,248);
	irrGui->addStaticText(L"Total weight: 2.0kg / 100kg",rect<s32>(10, 480, 310, 495),false,true,inventoryWindow);
	// Contex menu
	IGUIContextMenu * contextMenu = irrGui->addContextMenu((rect<s32>(0,0,0,0)),0,30);
	contextMenu->setCloseHandling(ECMC_HIDE);
	contextMenu->addItem(L"Equip",11);
	u32 craftMenu = contextMenu->addItem(L"Craft",12, true, true);
	contextMenu->getSubMenu(craftMenu)->addItem(L"Stone axe",15);
	contextMenu->getSubMenu(craftMenu)->addItem(L"Stone hammer",16);
	contextMenu->addItem(L"Drop",13);
	contextMenu->addItem(L"Examine",14);
	contextMenu->setVisible(false);
	irrGui->removeFocus(irrGui->getFocus());
	contextMenu->setItemEnabled(0, false);
	contextMenu->setItemEnabled(1, false);
	contextMenu->setItemEnabled(2, false);
	contextMenu->setItemEnabled(3, false);

Posted: Mon May 09, 2011 9:12 pm
by CuteAlien
The idea behind posting code is to make it reproducible for others to get the bug. Setting windows invisible, putting the context-menu on 0,0,0,0 (which makes it obviously not visible), making it invisible additionally - well - really not sure what exactly you want me to look at.

I suspect you make it visible again at some other part of your application and maybe do resize it, etc... but well, I'm not able to look at your monitor - so really - I have no idea.

I've adapted your code a little bit so it compiles at least - so please take that as a starting-point and show us how to reproduce the problems exactly. It would also be nice if you remove every line that's not needed to show the bug.

So slightly reworked code that shows the Window and context-menu:

Code: Select all

#include <irrlicht.h>
#include <iostream>

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

struct SAppContext
{
	IrrlichtDevice * device;
	IGUIContextMenu * contextMenu;
};


class MyEventReceiver : public IEventReceiver
{
public:
	MyEventReceiver(SAppContext & context) : Context(context) { }

	virtual bool OnEvent(const SEvent& event)
	{
		if (event.EventType == EET_GUI_EVENT)
		{
			if ( event.GUIEvent.Caller == Context.contextMenu )
			{
				 if(event.GUIEvent.EventType == EGET_MENU_ITEM_SELECTED) 
					 std::cout << "item selected: " << Context.contextMenu->getSelectedItem() << std::endl;
			}
		}

		return false;
	}

private:
	SAppContext & Context;
};


int main()
{
	video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
	IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(1024, 768));
	if (device == 0)
		return 1; // could not create selected driver.

	video::IVideoDriver* driver = device->getVideoDriver();
	IGUIEnvironment* irrGui = device->getGUIEnvironment();
	
	IGUIWindow * inventoryWindow = irrGui->addWindow(rect<s32>(674, 100, 994, 600), false, L"Inventory");
//	inventoryWindow->setVisible(false); 
	irrGui->addStaticText(L"Equipment",rect<s32>(10, 30, 310, 45),false,true,inventoryWindow);
	IGUITable * equipmentTree = irrGui->addTable(rect<s32>(10, 45, 310, 75),inventoryWindow, -1, false);
	equipmentTree->addColumn(L"Body part");
	equipmentTree->addColumn(L"Item");
	equipmentTree->addColumn(L"Weight");
	equipmentTree->setColumnWidth(0,78);
	equipmentTree->setColumnWidth(1,170);
	equipmentTree->addRow(0);
	equipmentTree->setCellText(0,0,L"Hand:");
	irrGui->addStaticText(L"Items",rect<s32>(10, 85, 310, 100),false,true,inventoryWindow);
	IGUITable * invTree = irrGui->addTable(rect<s32>(10, 100, 310, 470),inventoryWindow, -1, false);
	invTree->addColumn(L"Item");
	invTree->addColumn(L"Weight");
	invTree->setColumnWidth(0,248);
	irrGui->addStaticText(L"Total weight: 2.0kg / 100kg",rect<s32>(10, 480, 310, 495),false,true,inventoryWindow);
	// Contex menu
	IGUIContextMenu * contextMenu = irrGui->addContextMenu((rect<s32>(0,0,100,30)),0,30);
	contextMenu->setCloseHandling(ECMC_HIDE);
	contextMenu->addItem(L"Equip",11);
	u32 craftMenu = contextMenu->addItem(L"Craft",12, true, true);
	contextMenu->getSubMenu(craftMenu)->addItem(L"Stone axe",15);
	contextMenu->getSubMenu(craftMenu)->addItem(L"Stone hammer",16);
	contextMenu->addItem(L"Drop",13);
	contextMenu->addItem(L"Examine",14);
//   contextMenu->setVisible(false);
//	irrGui->removeFocus(irrGui->getFocus());
	contextMenu->setItemEnabled(0, false);
	contextMenu->setItemEnabled(1, false);
	contextMenu->setItemEnabled(2, false);
	contextMenu->setItemEnabled(3, false);	
	
	SAppContext context;
	context.device = device;
	context.contextMenu = contextMenu;
	MyEventReceiver receiver(context);
	device->setEventReceiver(&receiver);
	

	while(device->run() && driver)
	{
		if (device->isWindowActive())
		{
			driver->beginScene(true, true, SColor(0,200,200,200));
	
			irrGui->drawAll();
		
			driver->endScene();
		}
	}

	device->drop();

	return 0;
}

Posted: Mon May 09, 2011 9:25 pm
by Virror
Hehe, sorry about that. Here comes better code i hope:

Creating menu:

Code: Select all

IGUIContextMenu * contextMenu = irrGui->addContextMenu((rect<s32>(0,0,0,0)),0,30);
contextMenu->addItem(L"Equip",11);
u32 craftMenu = contextMenu->addItem(L"Craft",12, true, true);
contextMenu->getSubMenu(craftMenu)->addItem(L"Stone axe",15);
contextMenu->getSubMenu(craftMenu)->addItem(L"Stone hammer",16);
contextMenu->addItem(L"Drop",13);
contextMenu->addItem(L"Examine",14);
Event handler:

Code: Select all

bool EventReceiver::OnEvent(const SEvent& event)
{
   ....
   else if(event.EventType == EET_GUI_EVENT)
	{
        ....
        else if(event.GUIEvent.Caller == contextMenu)
		{
			if(event.GUIEvent.EventType == EGET_MENU_ITEM_SELECTED)
			{
				switch(contextMenu->getSelectedItem())
				{
					case 0:	// Equip
This works great, until i focus the inventory window, thats the window i click in to create the context menu. Code:

Creating window and table:

Code: Select all

IGUIWindow * inventoryWindow = irrGui->addWindow(rect<s32>(674, 100, 994, 600), false, L"Inventory");
IGUITable * equipmentTree = irrGui->addTable(rect<s32>(10, 45, 310, 75),inventoryWindow, -1, false);
Event that runs on right-click. To only show menu when clicking on table and to extract index of table:

Code: Select all

void EventReceiver::EventRightDown(const SEvent& event)	//Item list
{
	rightButtonDown = true;
	if(0 != invTree->getElementFromPoint(vector2d<s32>(event.MouseInput.X, event.MouseInput.Y)))
	{
		int pos = event.MouseInput.Y - invTree->getAbsolutePosition().UpperLeftCorner.Y;
		int index = pos / 15 - 1;
		if(index >= 0 && index < myPlayer->getInvCount())
		{
			contextMenu->setRelativePosition(vector2d<s32>(event.MouseInput.X, event.MouseInput.Y));
			contextMenu->setVisible(true);
			irrGui->setFocus(contextMenu);
			irrDevice->getCursorControl()->setVisible(true);
			camera->setInputReceiverEnabled(false);
			myPlayer->setClickedItem(myPlayer->GetItem(index));
			myPlayer->setSelectedItem(myPlayer->GetItem(invTree->getSelected()));
			if(myPlayer->getClickedItem() != myPlayer->getSelectedItem() &&
				myPlayer->getClickedItem()->getType() == IT_COMPONENT &&
				myPlayer->getSelectedItem()->getType() == IT_COMPONENT)
			{//Rest just selects what menus to enable
As soon as this window gets focus, the EGET_MENU_ITEM_SELECTED event stops for some reason. It Works if i focus another window, just not the same as i click in.

Posted: Mon May 09, 2011 9:55 pm
by hybrid
Ehh, no. Compilable code means 'copy all and press compile'. You only show some code fragments. If chosen wisely, this can be enough. But as you were already told that the problem is not that easily visible, you have to provide moree if you really need some help. Just take your *full code* and remove methods and code parts until the problem does not appear anymore. Go back one step and clean up other places of your code the same way. If you cannot find any code fragment which can be removed, post the code here.

Posted: Mon May 09, 2011 10:02 pm
by CuteAlien
Hybrid was faster than me ;-) But a note about event-handling in Irrlicht: mouse-events are always going to the focused element.

Posted: Mon May 09, 2011 10:27 pm
by Virror
Sure thing, will look at it tomorrow. But not one has still not answered my question about events from sub-menus. Are they possible and if, how will they be indexed?

Posted: Mon May 09, 2011 11:07 pm
by CuteAlien
EGET_MENU_ITEM_SELECTED also works for sub-menus. You get the menu in Caller and the item with getSelectedItem. Notice that you can pass custom command-id's to menu-items, which is often needed when you work with dynamic menues to identify the items easy.

Posted: Tue May 10, 2011 9:31 am
by Virror
Ok, here we go again : )
This time its code that should be copy-paste-compilable : p

Still same issue, when window is focused, i cant get anymore EGET_MENU_ITEM_SELECTED events. Also i would be greatful if someone showed me an example on how the get the submenu here give event.

Code: Select all

#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

#include <irrlicht.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

class EventReceiver :
	public IEventReceiver
{
public:

	EventReceiver::EventReceiver(IGUIContextMenu * newContextMenu, IGUIEnvironment * myGui)
	{
		contextMenu = newContextMenu;
		irrGui = myGui;
	}

	bool EventReceiver::OnEvent(const SEvent& event)
	{
		if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
		{
			if(event.EventType == EET_MOUSE_INPUT_EVENT)
			{
				contextMenu->setRelativePosition(vector2d<s32>(event.MouseInput.X, event.MouseInput.Y));
				contextMenu->setVisible(true);
				irrGui->setFocus(contextMenu);
				return true;
			}
		}
		else if(event.EventType == EET_GUI_EVENT)
		{
			if(event.GUIEvent.Caller == contextMenu)
			{
				if(event.GUIEvent.EventType == EGET_MENU_ITEM_SELECTED)
				{
					switch(contextMenu->getSelectedItem())
					{
						case 0:
							break;

						case 1:
							break;

						case 2:
							break;
					}
					return true;
				}
			}
		}
		return false;
	}

private:
	IGUIContextMenu * contextMenu;
	IGUIEnvironment * irrGui;
};

int main()
{
	IrrlichtDevice * irrDevice = createDevice(EDT_DIRECT3D9, dimension2d<u32>(1024,768));
	IGUIEnvironment* irrGui = irrDevice->getGUIEnvironment();
	IVideoDriver * irrVideo = irrDevice->getVideoDriver();
	ISceneManager* irrScene = irrDevice->getSceneManager();
	//Gui
	IGUIWindow * inventoryWindow = irrGui->addWindow(rect<s32>(674, 100, 994, 600), false, L"Inventory");
	IGUITable * invTree = irrGui->addTable(rect<s32>(10, 100, 310, 470),inventoryWindow, -1, false);
	invTree->addColumn(L"Item");
	invTree->addRow(0);
	invTree->setCellText(0,0,L"Cell");

	IGUIContextMenu * contextMenu = irrGui->addContextMenu((rect<s32>(0,0,0,0)),0,30);
	contextMenu->setCloseHandling(ECMC_HIDE);
	contextMenu->addItem(L"Equip",11);
	u32 craftMenu = contextMenu->addItem(L"Craft",12, true, true);
	contextMenu->getSubMenu(craftMenu)->addItem(L"Stone axe",15);
	contextMenu->getSubMenu(craftMenu)->addItem(L"Stone hammer",16);
	contextMenu->addItem(L"Drop",13);
	contextMenu->addItem(L"Examine",14);
	contextMenu->setVisible(false);

	EventReceiver receiver(contextMenu, irrGui);
	irrDevice->setEventReceiver(&receiver);

	// Main loop
	while(irrDevice->run()) 
	{
		irrVideo->beginScene(true, true, SColor(0,0,0,0));
		irrScene->drawAll();
		irrGui->drawAll();      
		irrVideo->endScene();
	}
	irrDevice->drop();
    return 0;
}
[/code]

Posted: Tue May 10, 2011 11:19 am
by CuteAlien
I'm still at work, but on a quick view I see 2 problems. The first one is simply that it's not nice checking for MouseInput.Event before checking for event.EventType, you should do this the other way round (you don't know if you have a valid MouseInput before you check for EET_MOUSE_INPUT_EVENT).

The other problem is that you return true which marks the event as handled and so it will not be further processed. So the Irrlicht gui never receives the EMIE_RMOUSE_PRESSED_DOWN events. Try returning false instead.

Posted: Tue May 10, 2011 11:25 am
by Virror
Hehe, the first point is very valid ; )
Did no notice that, very bad practice. But i see now in my original code that i do it right there.

About the other issue, i will test and see.

Edit: I think i found the issue, the problems seems to be that the contextMenu is created behind the inventory, so when inventory is focused the keypresses don't hit the menu, but the window instead. Not sure how to fix this though, the "bringToFront" function don't seem to do the trick...

Posted: Tue May 10, 2011 12:55 pm
by CuteAlien
bringToFront works relative to other childs which have the same parent. Not sure if you still use the same test-case (where it doesn't seem to have a parent, so it should work), but in general you should give context-menus no parent except the gui-environment itself to make sure a bringToFront on them brings them really to the top.