Detect a right-click on StringGadget
Detect a right-click on StringGadget
I’ve done searches on this but can’t find any workable (or recent) references for a cross-platform (Windows/OSX anyway) solution. Maybe - surely - this is because later versions of the compiler have the facility and so it’s no longer an issue.
I’m particularly looking to suppress the system menu that pops up on a StringGadget right-click and replace it with something more useful.
Any ideas?
Dave
I’m particularly looking to suppress the system menu that pops up on a StringGadget right-click and replace it with something more useful.
Any ideas?
Dave
Re: Detect a right-click on StringGadget
Search for Shardik's cross platform examples. This is Windows only.
Code: Select all
EnableExplicit
Global.i evWW, SG_CBn
Procedure.i SG_CB(hW, msg, wP, lP)
Protected.i ri
Select msg
Case #WM_CONTEXTMENU
Debug "Context Menu"
Case #WM_RBUTTONDOWN
Debug "RM Click"
Default
ri = CallWindowProc_(SG_CBn, hW, msg, wP, lP)
EndSelect
ProcedureReturn ri
EndProcedure
If OpenWindow(0, 0, 0, 230, 120, "EVENTTYPES EXAMPLE...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
StringGadget(1, 10, 10, 150, 100, "TEST")
SG_CBn = SetWindowLongPtr_(GadgetID(1), #GWL_WNDPROC, @SG_CB())
Repeat
evWW = WaitWindowEvent()
Until evWW = #PB_Event_CloseWindow
EndIf
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Re: Detect a right-click on StringGadget
Nope, I still can’t find anything relevant. There’s a Shardik post for detecting right-click on a ButtonGadget for Windows/Linux. I’m probably searching on the wrong terms. Maybe a separate section for cross-platform examples’d be a good idea.skywalk wrote:Search for Shardik's cross platform examples. This is Windows only.
Having spent the last decade programming in Java, the apparent lack of detectable events in PB takes some getting used to.
Dave.
Re: Detect a right-click on StringGadget
Please take a look into this example for MacOS which uses one callback to suppress the context menu on a right click into a StringGadget and another callback to detect when the right mouse button is down:
Code: Select all
EnableExplicit
Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
"NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")
Procedure SubclassGadget(GadgetID.I, NewClassName.S)
Protected GadgetClass.I = CocoaMessage(0, GadgetID(GadgetID), "class")
Protected NewGadgetClass.I
NewGadgetClass = objc_allocateClassPair_(GadgetClass, NewClassName, 0)
objc_registerClassPair_(NewGadgetClass)
object_setClass_(GadgetID(GadgetID), NewGadgetClass)
ProcedureReturn NewGadgetClass
EndProcedure
ProcedureC ContextMenuCallback(Object.I, Selector.I, TextView.I, Menu.I,
Event.I, Index.I)
; ----- Suppress context menu
ProcedureReturn 0
EndProcedure
ProcedureC RightMouseDownCallback(Object.I, Selector.I, Event.I)
Debug "Right mouse button down detected!"
EndProcedure
Define SubclassedStringGadget.I
OpenWindow(0, 270, 100, 350, 70, "Detect right mouse button down")
StringGadget(0, 80, 25, 170, 20, "")
SetActiveGadget(0)
SubclassedStringGadget = SubclassGadget(0, "SubclassedStringGadget")
class_addMethod_(SubclassedStringGadget, sel_registerName_("rightMouseDown:"),
@RightMouseDownCallback(), "v@:@")
class_addMethod_(SubclassedStringGadget,
sel_registerName_("textView:menu:forEvent:atIndex:"),
@ContextMenuCallback(), "v@:@@@@")
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Re: Detect a right-click on StringGadget
Thanks Shardik,
Your code does everything I need for one StringGadget but, on my particular application, I have 10 StringGadgets. Four of them require a popup-menu to be attached but all of them need the system popup to be suppressed.
Playing around with your code I've stumbled on two problems so far …
a) If I add another StringGadget and duplicate the
code (substituting the appropriate GadgetIDs), the code crashes on:
(line 12) [ERROR] Invalid Memory access
b) the
has no reference to the StringGadget on which it was called so I can’t select the appropriate popup-menu (if any). I guess that, if (a) is resolved, then I could construct a look-up array of GadgetID v. SubclassedStringGadget … but is there an easier way? Or am I missing the blatantly obvious?
Please be gentle, remember I’m just a dumb Java hack.
Dave
Your code does everything I need for one StringGadget but, on my particular application, I have 10 StringGadgets. Four of them require a popup-menu to be attached but all of them need the system popup to be suppressed.
Playing around with your code I've stumbled on two problems so far …
a) If I add another StringGadget and duplicate the
Code: Select all
SubclassedStringGadget = SubclassGadget(0, "SubclassedStringGadget")
class_addMethod_(SubclassedStringGadget, sel_registerName_("rightMouseDown:"),
@RightMouseDownCallback(), "v@:@")
class_addMethod_(SubclassedStringGadget,
sel_registerName_("textView:menu:forEvent:atIndex:"),
@ContextMenuCallback(), "v@:@@@@")
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)
(line 12)
Code: Select all
objc_registerClassPair_(NewGadgetClass)
b) the
Code: Select all
ProcedureC RightMouseDownCallback(Object.I, Selector.I, Event.I)
Debug "Right mouse button down detected!"
EndProcedure
Please be gentle, remember I’m just a dumb Java hack.
Dave
Re: Detect a right-click on StringGadget
Please take a look into the following advanced example which allows to subclass multiple StringGadgets on MacOS. It identifies the number of the StringGadget in the RightMouseDownCallback and displays the number of the right-clicked StringGadget. And it further demonstrates how to display a customized popup menu when right-clicking into the 2nd StringGadget.HarrysLad wrote:Your code does everything I need for one StringGadget but, on my particular application, I have 10 StringGadgets. Four of them require a popup-menu to be attached but all of them need the system popup to be suppressed.
Code: Select all
EnableExplicit
Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
"NSApplication sharedApplication"), "delegate")
Define i.I
Define SubclassedStringGadget.I
Dim StringGadgetID(2) ; Number of StringGadgets - 1
Procedure SubclassGadget(GadgetID.I, NewClassName.S)
Protected GadgetClass.I = CocoaMessage(0, GadgetID(GadgetID), "class")
Protected NewGadgetClass.I
NewGadgetClass = objc_allocateClassPair_(GadgetClass, NewClassName, 0)
objc_registerClassPair_(NewGadgetClass)
object_setClass_(GadgetID(GadgetID), NewGadgetClass)
ProcedureReturn NewGadgetClass
EndProcedure
ProcedureC ContextMenuCallback(Object.I, Selector.I, TextView.I, Menu.I,
Event.I, Index.I)
; ----- Suppress context menu
ProcedureReturn 0
EndProcedure
ProcedureC RightMouseDownCallback(Object.I, Selector.I, Event.I)
Shared StringGadgetID.I()
Protected i.I
For i = 0 To ArraySize(StringGadgetID())
If Object = StringGadgetID(i)
If i = 1
DisplayPopupMenu(0, WindowID(0))
Else
Debug "Right mouse button down on StringGadget " + Str(i + 1)
Break
EndIf
EndIf
Next i
EndProcedure
OpenWindow(0, 270, 100, 350, 130, "Detect right mouse button down")
; ----- Prepare popup menu for StringGadget 2
If CreatePopupMenu(0)
MenuItem(0, "Menu item 1")
MenuItem(1, "Menu item 2")
EndIf
For i = 0 To ArraySize(StringGadgetID())
StringGadgetID(i) = StringGadget(i, 80, 25 + i * 30, 170, 20, "")
SubclassedStringGadget = SubclassGadget(i, "SubclassedStringGadget" + Str(i))
class_addMethod_(SubclassedStringGadget,
sel_registerName_("rightMouseDown:"),
@RightMouseDownCallback(), "v@:@")
class_addMethod_(SubclassedStringGadget,
sel_registerName_("textView:menu:forEvent:atIndex:"),
@ContextMenuCallback(), "v@:@@@@")
Next i
CocoaMessage(0, StringGadgetID(0), "setDelegate:", AppDelegate)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Menu
Debug "Menu item " + Str(EventMenu() + 1) + " was selected"
EndSelect
ForEver
I have tested this cross-platform example successfully on these operating systems with PB 5.43:
- Linux Mint 18 x86 "Sarah" with Cinnamon (GTK 2 and GTK 3)
- MacOS X 10.9.5 (Mavericks)
- MacOS X 10.11.6 (El Capitan)
- Windows XP SP3
- Windows 8.1 x64
Unfortunately it currently doesn't work on MacOS X 10.6.8 (Snow Leopard)!
Code: Select all
EnableExplicit
#Event_StringGadget_RightClick = #PB_Event_FirstCustomValue
#StringGadget = 0
OpenWindow(0, 270, 100, 350, 75,
"Detect right click and suppress context menu")
StringGadget(0, 80, 25, 170, 25, "")
SetActiveGadget(0)
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Linux ; -------------------------------------------------
ProcedureC ButtonPressCallback(*Widget.GtkWidget,
*EventButton.GdkEventButton, UserData.I)
If *EventButton\button = 3
PostEvent(#Event_StringGadget_RightClick)
ProcedureReturn #True
EndIf
EndProcedure
g_signal_connect_(GadgetID(#StringGadget), "button-press-event",
@ButtonPressCallback(), 0)
CompilerCase #PB_OS_MacOS ; -------------------------------------------------
Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
"NSApplication sharedApplication"), "delegate")
Define SubclassedStringGadget.I
ProcedureC ContextMenuCallback(Object.I, Selector.I, TextView.I, Menu.I,
Event.I, Index.I)
ProcedureReturn 0
EndProcedure
ProcedureC RightMouseDownCallback(Object.I, Selector.I, Event.I)
PostEvent(#Event_StringGadget_RightClick)
EndProcedure
SubclassedStringGadget = objc_allocateClassPair_(CocoaMessage(0,
GadgetID(#StringGadget), "class"), "SubclassedStringGadget", 0)
objc_registerClassPair_(SubclassedStringGadget)
object_setClass_(GadgetID(#StringGadget), SubclassedStringGadget)
class_addMethod_(SubclassedStringGadget,
sel_registerName_("rightMouseDown:"),
@RightMouseDownCallback(), "v@:@")
class_addMethod_(SubclassedStringGadget,
sel_registerName_("textView:menu:forEvent:atIndex:"),
@ContextMenuCallback(), "v@:@@@@")
CocoaMessage(0, GadgetID(#StringGadget), "setDelegate:", AppDelegate)
CompilerCase #PB_OS_Windows ; -----------------------------------------------
Define DefaultStringGadgetCallback.I
Procedure CustomStringGadgetCallback(WindowHandle.I, Msg.I, WParam.I,
LParam.I)
Shared DefaultStringGadgetCallback.I
Protected Result.I
If Msg <> #WM_CONTEXTMENU
Result = CallWindowProc_(DefaultStringGadgetCallback, WindowHandle, Msg,
WParam, LParam)
Else
PostEvent(#Event_StringGadget_RightClick)
EndIf
ProcedureReturn Result
EndProcedure
DefaultStringGadgetCallback = SetWindowLongPtr_(GadgetID(#StringGadget),
#GWL_WNDPROC, @CustomStringGadgetCallback())
CompilerEndSelect ; -----------------------------------------------------------
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #Event_StringGadget_RightClick
Debug "Right click into StringGadget detected!"
EndSelect
ForEver
Re: Detect a right-click on StringGadget
Shardik - Thanks again for the code and all of your work.
Unfortunately it gets me no further forward since the first example works for numerous StringGadgets but only under OSX whereas the second example is cross-platform but operates on only one StringGadget. You write that the second example is limited to one StringGadget 'for simplicity’s sake' but I’ve no idea as to how it could be extended to multiple StringGadgets …
Surely this stuff should be in the compiler, not bloating individual apps.
Frankly, I’m beginning to despair of the whole affair.
Dave
Unfortunately it gets me no further forward since the first example works for numerous StringGadgets but only under OSX whereas the second example is cross-platform but operates on only one StringGadget. You write that the second example is limited to one StringGadget 'for simplicity’s sake' but I’ve no idea as to how it could be extended to multiple StringGadgets …
Surely this stuff should be in the compiler, not bloating individual apps.
Frankly, I’m beginning to despair of the whole affair.
Dave
Re: Detect a right-click on StringGadget
I have programmed an advanced example (supporting multiple StringGadgets) which works on MacOS and Windows:
Code: Select all
EnableExplicit
#NumStringGadgets = 3
Enumeration #PB_Event_FirstCustomValue
#Event_StringGadget_RightClick
#Event_StringGadget_RightClick_PopupMenu
EndEnumeration
Define i.I
Dim StringGadgetID.I(#NumStringGadgets - 1)
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS ; -------------------------------------------------
Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
"NSApplication sharedApplication"), "delegate")
ProcedureC ContextMenuCallback(Object.I, Selector.I, TextView.I, Menu.I,
Event.I, Index.I)
; ----- Suppress context menu
ProcedureReturn 0
EndProcedure
ProcedureC RightMouseDownCallback(Object.I, Selector.I, Event.I)
Shared StringGadgetID.I()
Protected i.I
For i = 0 To #NumStringGadgets - 1
If Object = StringGadgetID(i)
If i = 1
PostEvent(#Event_StringGadget_RightClick_PopupMenu, 0, i)
Else
PostEvent(#Event_StringGadget_RightClick, 0, i)
EndIf
Break
EndIf
Next i
EndProcedure
Procedure SubclassGadget(GadgetID.I, NewClassName.S)
Protected GadgetClass.I = CocoaMessage(0, GadgetID(GadgetID), "class")
Protected NewGadgetClass.I
NewGadgetClass = objc_allocateClassPair_(GadgetClass, NewClassName, 0)
objc_registerClassPair_(NewGadgetClass)
object_setClass_(GadgetID(GadgetID), NewGadgetClass)
class_addMethod_(NewGadgetClass,
sel_registerName_("rightMouseDown:"),
@RightMouseDownCallback(), "v@:@")
class_addMethod_(NewGadgetClass,
sel_registerName_("textView:menu:forEvent:atIndex:"),
@ContextMenuCallback(), "v@:@@@@")
EndProcedure
CompilerCase #PB_OS_Windows ; -----------------------------------------------
Define DefaultStringGadgetCallback.I
Procedure CustomStringGadgetCallback(WindowHandle.I, Msg.I, WParam.I,
LParam.I)
Shared DefaultStringGadgetCallback.I
Shared StringGadgetID.I()
Protected i.I
Protected Result.I
If Msg = #WM_CONTEXTMENU
For i = 0 To #NumStringGadgets - 1
If WParam = StringGadgetID(i)
If i = 1
PostEvent(#Event_StringGadget_RightClick_PopupMenu, 0, i)
Else
PostEvent(#Event_StringGadget_RightClick, 0, i)
EndIf
Break
EndIf
Next i
Else
Result = CallWindowProc_(DefaultStringGadgetCallback, WindowHandle,
Msg, WParam, LParam)
EndIf
ProcedureReturn Result
EndProcedure
CompilerEndSelect ; -----------------------------------------------------------
OpenWindow(0, 270, 100, 340, 130, "Detect right mouse button down")
; ----- Prepare popup menu for StringGadget 2
If CreatePopupMenu(0)
MenuItem(0, "Menu item 1")
MenuItem(1, "Menu item 2")
EndIf
For i = 0 To #NumStringGadgets - 1
StringGadgetID(i) = StringGadget(i, 80, 25 + i * 30, 170, 20, "")
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS ; -----------------------------------------------
SubclassGadget(i, "SubclassedStringGadget" + Str(i))
CompilerCase #PB_OS_Windows ; ---------------------------------------------
DefaultStringGadgetCallback = SetWindowLongPtr_(StringGadgetID(i),
#GWL_WNDPROC, @CustomStringGadgetCallback())
CompilerEndSelect ; ---------------------------------------------------------
Next i
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
CocoaMessage(0, StringGadgetID(0), "setDelegate:", AppDelegate)
CompilerEndIf
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Menu
Debug "Menu item " + Str(EventMenu() + 1) + " was selected"
Case #Event_StringGadget_RightClick
Debug "Right mouse button down on StringGadget " + Str(EventGadget() + 1)
Case #Event_StringGadget_RightClick_PopupMenu
DisplayPopupMenu(0, WindowID(0))
EndSelect
ForEver
Re: Detect a right-click on StringGadget
Thanks Shardik for your hard work - that works perfectly.
It took a bit of time and code re-arranging to implement it but all’s well, etc.
This should definitely go in tip the 'tips and tricks' section.
Thanks again. I owe you a pint or two.
Dave
It took a bit of time and code re-arranging to implement it but all’s well, etc.
This should definitely go in tip the 'tips and tricks' section.
Thanks again. I owe you a pint or two.
Dave
Re: Detect a right-click on StringGadget
I am glad that I was able to help you out and that it's now working for you...