EVENT_MENUACTION should return the event source

BlitzMax Forums/MaxGUI Module/EVENT_MENUACTION should return the event source

JoshK(Posted 2006) [#1]
I suggest that EVENT_MENUACTION events return the menu gadget used as the event source value.


Markus Rauch(Posted 2006) [#2]
I think also


Dreamora(Posted 2006) [#3]
Agreed.
Would definititely solve some problems with dynamic menues.


Brucey(Posted 2007) [#4]
Spooky... I just stumbled across this today after porting an app from GTK to Mac and now to Win32...

...and it breaks on win32 because event.source is Null...

I would say that this is a Bug then... no?


Fabian.(Posted 2007) [#5]
If you change something in the win32maxgui module, you should be able to get your apps working.
However, before you do any changes you should syncmds, since my line numbers refer to the latest version.
Change in mod/brl.mod/win32maxgui.mod/win32gui/win32hwnd.cpp
lines 15 to 21
from
extern "C"{
void brl_event_EmitEvent( BBObject *event );
BBObject *brl_maxgui_HotKeyEvent( int key,int mods,int owner );
void brl_win32maxgui_EmitWin32OSEvent( HWND hwnd,UINT msg,WPARAM wp,LPARAM lp,void *source );
}
to
extern "C"{
void brl_event_EmitEvent( BBObject *event );
BBObject *brl_maxgui_HotKeyEvent( int key,int mods,int owner );
void brl_win32maxgui_EmitWin32OSEvent( HWND hwnd,UINT msg,WPARAM wp,LPARAM lp,void *source );
int brl_win32maxgui_bb_GetMenuTag(int id);
BBObject* brl_win32maxgui_bb_GetMenuSource(int id);
}
lines 133 to 141
from
	case WM_COMMAND:
		if( !lp ){
			if( wp>100 ){
				bbPostWin32GuiEvent( BBEVENT_MENUACTION,0,wp-100,0,0,0,&bbNullObject );
			}
			return 0;
		}
		src=findHwnd( (HWND)lp );
		break;
to
	case WM_COMMAND:
		if( !lp ){
			if( wp>100 ){
				bbPostWin32GuiEvent( BBEVENT_MENUACTION,0,brl_win32maxgui_bb_GetMenuTag(wp-100),0,0,0,brl_win32maxgui_bb_GetMenuSource(wp-100) );
			}
			return 0;
		}
		src=findHwnd( (HWND)lp );
		break;
in mod/brl.mod/win32maxgui.mod/win32gui.bmx
lines 321 to 329
from
	Method CreateGadget:TGadget(gadgetclass,label$,x,y,w,h,group:TGadget,style)
		Local	gadget:TWin32Gadget
		Local	wgroup:TWin32Gadget
		Local	hgroup
		Local	g,name$
		
		If Not group group=Desktop
		wgroup=TWin32Gadget(group)
		hgroup=wgroup.handle
to
	Method CreateGadget:TGadget(gadgetclass,label$,x,y,w,h,group:TGadget,style)
		Local	gadget:TWin32Gadget
		Local	wgroup:TWin32Gadget
		Local	hgroup
		Local	g,name$,tag
		
		If Not group group=Desktop
		wgroup=TWin32Gadget(group)
		hgroup=wgroup.handle
lines 367 to 384
from
			Case GADGET_MENUITEM
				If wgroup And wgroup.class=GADGET_WINDOW
					hgroup=bbWindowMenu(TWin32Gadget(group).handle)
				EndIf
				If wgroup And wgroup.class=GADGET_DESKTOP
					hgroup=0
				EndIf
				g=bbCreateMenu(label,style,hgroup)
			Case GADGET_NODE	
				Throw "chunks"
			Case GADGET_CANVAS
				g=bbCreatePanel(x,y,w,h,hgroup,style|4)
		End Select
		gadget=TWin32Gadget.Create(gadgetclass,g,wgroup)
		gadget.name=name
		Return gadget
to
			Case GADGET_MENUITEM
				If wgroup And wgroup.class=GADGET_WINDOW
					hgroup=bbWindowMenu(TWin32Gadget(group).handle)
				EndIf
				If wgroup And wgroup.class=GADGET_DESKTOP
					hgroup=0
				EndIf
				tag=bb_SetMenuTag(style)
				g=bbCreateMenu(label,tag,hgroup)
			Case GADGET_NODE	
				Throw "chunks"
			Case GADGET_CANVAS
				g=bbCreatePanel(x,y,w,h,hgroup,style|4)
		End Select
		gadget=TWin32Gadget.Create(gadgetclass,g,wgroup)
		If gadgetclass=GADGET_MENUITEM bb_SetMenuSource tag,gadget
		gadget.name=name
		Return gadget
lines 514 to 526
from
	Method SetHotKey(key,modifier)
		Local ev:TEvent
		If hotkey RemoveHotKey hotkey
		Select class
		Case GADGET_MENUITEM
			bbSetMenuHotKey handle,key,modifier	'decorates name only
			ev=CreateEvent( EVENT_MENUACTION,Null,bbMenuTag(handle) )
			hotkey=SetHotKeyEvent(key,modifier,ev,findowner())
		Default
			ev=CreateEvent( EVENT_GADGETACTION,Self )
			hotkey=SetHotKeyEvent(key,modifier,ev,findowner())
		End Select
	End Method
to
	Method SetHotKey(key,modifier)
		Local ev:TEvent
		If hotkey RemoveHotKey hotkey
		Select class
		Case GADGET_MENUITEM
			bbSetMenuHotKey handle,key,modifier	'decorates name only
			ev=CreateEvent( EVENT_MENUACTION,Self,bb_GetMenuTag(bbMenuTag(handle)) )
			hotkey=SetHotKeyEvent(key,modifier,ev,findowner())
		Default
			ev=CreateEvent( EVENT_GADGETACTION,Self )
			hotkey=SetHotKeyEvent(key,modifier,ev,findowner())
		End Select
	End Method
lines 528 to 540
from
	Method Free()
		Local	kid:TGadget
		
		If parent
			parent.kids.Remove Self
			parent=Null
		EndIf
		
		For kid=EachIn kids
			kid.Free
		Next
to
	Method Free()
		Local	kid:TGadget

		If class=GADGET_MENUITEM and handle bb_UnsetMenuTag bbMenuTag(handle)
		
		If parent
			parent.kids.Remove Self
			parent=Null
		EndIf
		
		For kid=EachIn kids
			kid.Free
		Next
lines 958 to 984
from
Function PostWin32GuiEvent( id,handle,data,mods,x,y,extra:Object ) 'nodebug
	Local source:TWin32Gadget=TWin32GUIDriver.GadgetFromHandle( handle )
' update local dimensions
	If id=EVENT_WINDOWSIZE And source source.UpdateSize		
	If id=EVENT_WINDOWMOVE And source source.UpdatePos	
' fill in extra field for treeview and list gadget events
	If id=EVENT_MENUACTION extra=TWin32Gadget.popupextra
	If source
		Select source.class
			Case GADGET_TREEVIEW 
'				data=TWin32GUIDriver.GadgetFromHandle( data )	'integer handle
				extra=TWin32GUIDriver.GadgetFromHandle( data )	'actual TGadget
			Case GADGET_LISTBOX,GADGET_TABBER,GADGET_TOOLBAR,GADGET_COMBOBOX
				If data>-1 
					extra=source.ItemExtra(data)
					Local flags=source.ItemFlags(data)
					If flags&GADGETITEM_TOGGLE source.SelectItem(data,2)
				EndIf
		End Select
	EndIf
' post it to MaxGui
	PostGuiEvent id,source,data,mods,x,y,extra
End Function
to
Function PostWin32GuiEvent( id,handle,data,mods,x,y,extra:Object ) 'nodebug
	Local source:TWin32Gadget=TWin32GUIDriver.GadgetFromHandle( handle ),evsource:TGadget
' update local dimensions
	If id=EVENT_WINDOWSIZE And source source.UpdateSize		
	If id=EVENT_WINDOWMOVE And source source.UpdatePos	
' fill in extra field for treeview and list gadget events
	If id=EVENT_MENUACTION
		evsource=TGadget(extra)
		extra=TWin32Gadget.popupextra
	EndIf
	If source
		Select source.class
			Case GADGET_TREEVIEW 
'				data=TWin32GUIDriver.GadgetFromHandle( data )	'integer handle
				extra=TWin32GUIDriver.GadgetFromHandle( data )	'actual TGadget
			Case GADGET_LISTBOX,GADGET_TABBER,GADGET_TOOLBAR,GADGET_COMBOBOX
				If data>-1 
					extra=source.ItemExtra(data)
					Local flags=source.ItemFlags(data)
					If flags&GADGETITEM_TOGGLE source.SelectItem(data,2)
				EndIf
		End Select
	EndIf
' post it to MaxGui
	If Not evsource evsource=source
	PostGuiEvent id,evsource,data,mods,x,y,extra
End Function

Global bb_MenuTags:Tbb_MenuTag
Global bb_StartSearch

Type Tbb_MenuTag
	Field Prev:Tbb_MenuTag
	Field Succ:Tbb_MenuTag
	Field GUITag
	Field UserTag
	Field Source:Object
EndType

Function bb_SetMenuTag ( UserTag )
  While bb__Find(bb_StartSearch)
    bb_StartSearch:+1
  Wend
  Local tag:Tbb_MenuTag=New Tbb_MenuTag
  tag.Succ=bb_MenuTags
  tag.GUITag=bb_StartSearch
  bb_StartSearch:+1
  bb_StartSearch:&$0FFF
  tag.UserTag=UserTag
  If bb_MenuTags bb_MenuTags.Prev=tag
  bb_MenuTags=tag
  Return tag.GUITag
EndFunction

Function bb_SetMenuSource ( GUITag , Source:Object )
  bb__Find(GUITag).Source=Source
EndFunction

Function bb_GetMenuTag ( GUITag )
  Return bb__Find(GUITag).UserTag
EndFunction

Function bb_GetMenuSource:Object ( GUITag )
  Return bb__Find(GUITag).Source
EndFunction

Function bb_UnsetMenuTag ( GUITag )
  Local tag:Tbb_MenuTag=bb__Find(GUITag)
  If tag=bb_MenuTags bb_MenuTags=tag.Succ
  If tag.Succ tag.Succ.Prev=tag.Prev
  If tag.Prev tag.Prev.Succ=tag.Succ
EndFunction

Function bb__Find:Tbb_MenuTag ( GUITag )
  Local tag:Tbb_MenuTag = bb_MenuTags
  While tag
    If tag.GUITag=GUITag Return tag
    tag=tag.Succ
  Wend
EndFunction
I tested and it seems to work with these changes. However they'll get overwritten as soon as you syncmod the next time.
If this really behaves different on Mac/Win32 I'd say it's a bug.


Fabian.(Posted 2007) [#6]
@BRL, if you want to, you can include these changes in your offical modules on the modserver. I think this could help many developers to write their code easier.


SebHoll(Posted 2007) [#7]
Seconded - I never really understood why menus had to be operated using CONSTANTS as oppose to EventSource()...


Fabian.(Posted 2007) [#8]
Thanks for seconding - how could you create dynamic menus if you have to use constant integer values to identify your menus? This is indeed a missing feature on Windows.

@Brucey: Can you confirm that this behaviour is different on Mac and Windows? If so, I'd like to post this as bug report.


Brucey(Posted 2007) [#9]
On Mac the following code generates the MenuAction event :
PostGuiEvent( BBEVENT_MENUACTION,sender,[sender tag],0,0,0,0 );

Note the second field, which is the "source".
Which turned out to be rather useful - until I tried running it on Windows :-)


Fabian.(Posted 2007) [#10]
Thanks, I posted a bug report here.