Page 1 of 1

Force a menu to close

Posted: Thu Feb 06, 2014 10:44 am
by RichardL
Good morning,
I would like to force a standard Windows menu to close when the mouse cursor leaves it, instead of waiting for the user to click somewhere else. So far I have detected the mouse has left the menu but cannot find out how to close the menu.

Code: Select all

Procedure WinCallback(hwnd, uMsg, wParam, lParam)
   Select uMsg
       Case #WM_MENUSELECT
          If wParam & $FFFF = #MF_DISABLED   And lParam =  MenuID(MenuWm)
           ; Close the menu
          EndIf


etc
etc
Would someone kindly point me in the right direction?
Thanks
RichardL

Re: Force a menu to close

Posted: Thu Feb 06, 2014 10:49 am
by Bisonte
maybe simulate a left mouseclick to the actual coursorpos ?

Re: Force a menu to close

Posted: Thu Feb 06, 2014 11:31 am
by PB

Re: Force a menu to close

Posted: Thu Feb 06, 2014 11:53 am
by RichardL
Gentlemen,
Thanks for your replies.
1. Whoops! I found that my code triggers when the menu opens as well as when it closes... so its NBG at present! :oops:
2. I tried PB's approach and it behaves similarly.

Code: Select all

Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
  Select uMsg
    Case #WM_ENTERIDLE
      GetCursorPos_(cpt.POINT)
      If WindowFromPoint_(PeekQ(cpt))=hwnd
        EndMenu_()
      EndIf
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure


OpenWindow(0,0,0,320,240,"Select menu then move mouse right",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,50,"Hello")

CreateMenu(0,WindowID(0))

MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")

SetWindowCallback(@WindowCallback())

Repeat
  EventID = WaitWindowEvent()

  
  
Until EventID = #PB_Event_CloseWindow
Any more suggestions would be welcomed!
RichardL

Edited: Button gadget added to show another difficulty. :(

Re: Force a menu to close

Posted: Thu Feb 06, 2014 11:58 am
by PB
I don't get it. You said...

> I would like to force a standard Windows menu to close when the mouse cursor leaves it

...and the link I provided does just that. :shock:

Re: Force a menu to close

Posted: Thu Feb 06, 2014 12:22 pm
by RichardL
@PB
Did you try my version of your code..?
RichardL

Re: Force a menu to close

Posted: Thu Feb 06, 2014 1:56 pm
by PB
> Did you try my version of your code..?

Yes, but it doesn't make the menu appear. Is that your point?

On the other hand, the menu appears with the code I linked,
and that menu auto-closes when the mouse moves off it...
exactly like you requested in your first post.

> Button gadget added to show another difficulty

What exactly is the difficulty with the button? :shock:
It doesn't even do anything. It's just for decoration.

Code quoted below as you posted it:

Code: Select all

Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
  Select uMsg
    Case #WM_ENTERIDLE
      GetCursorPos_(cpt.POINT)
      If WindowFromPoint_(PeekQ(cpt))=hwnd
        EndMenu_()
      EndIf
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

OpenWindow(0,0,0,320,240,"Select menu then move mouse right",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,50,"Hello")

CreateMenu(0,WindowID(0))

MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")

SetWindowCallback(@WindowCallback())

Repeat
  EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow

Re: Force a menu to close

Posted: Thu Feb 06, 2014 3:08 pm
by Shardik
RichardL,

please try this one:

Code: Select all

Procedure WindowCallback(hWnd, Msg, wParam, lParam)
  Static MenuIsOpen
  
  Select Msg
    Case #WM_MENUSELECT
      If lParam = MenuID(0)
        If MenuIsOpen
          MenuIsOpen = #False
          EndMenu_()
        EndIf
      EndIf
    Case #WM_ENTERIDLE
      GetCursorPos_(cpt.POINT)
      
      If WindowFromPoint_(cpt\x | (cpt\y << 32)) = hwnd
        If MenuIsOpen
          MenuIsOpen = #False
          EndMenu_()
        EndIf
      Else
        MenuIsOpen = #True
      EndIf
  EndSelect

  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure


OpenWindow(0,100,100,320,240,"Select menu then move mouse right")
ButtonGadget(1,20,20,200,50,"Hello")

CreateMenu(0,WindowID(0))

MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")

SetWindowCallback(@WindowCallback())

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Re: Force a menu to close

Posted: Thu Feb 06, 2014 3:50 pm
by RichardL
@PB
Oh dear, we seem to be going around in circles... :D :(

My need is for a standard menu, attached to a menu bar, to close when the mouse pointer goes away from the menu.

Your original solution addresses the same need but with a popup menu.
It does not work if there is a gadget under the popup menu; as is almost inevitably the case .

Code: Select all

Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
  Select uMsg
    Case #WM_ENTERIDLE
      GetCursorPos_(cpt.POINT)
      If WindowFromPoint_(PeekQ(cpt))=hwnd
        EndMenu_()
      EndIf
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

OpenWindow(0,0,0,320,240,"Right-click!",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,200,"Test")

CreatePopupMenu(0)

MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")

SetWindowCallback(@WindowCallback())
Repeat
  EventID = WaitWindowEvent()
  If EventID = #WM_RBUTTONDOWN
    DisplayPopupMenu(0,WindowID(0))
  EndIf
Until EventID = #PB_Event_CloseWindow
Neither does it work with a standard menu attached to a menu bar:

Code: Select all

Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
  Select uMsg
    Case #WM_ENTERIDLE
      GetCursorPos_(cpt.POINT)
      If WindowFromPoint_(PeekQ(cpt))=hwnd
        EndMenu_()
      EndIf
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

OpenWindow(0,0,0,320,260,"Select menu then move mouse right",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,200,"Hello")

CreateMenu(0,WindowID(0))
MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")

SetWindowCallback(@WindowCallback())
Repeat
  EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
In this case the callback is being triggered repeatedly and the menu cannot deploy.

@Shardik
Almost perfect.... :D
The only remaining difficulty is that if a user exits with the conventional left mouse button it takes two attempts to get the menu to drop down again.

Re: Force a menu to close

Posted: Thu Feb 06, 2014 4:17 pm
by Shardik
RichardL wrote:Almost perfect.... :D
The only remaining difficulty is that if a user exits with the conventional left mouse button it takes two attempts to get the menu to drop down again.
You may solve this problem by replacing

Code: Select all

If lParam = MenuID(0)
by

Code: Select all

If wParam & $FF = 0
But there exists a 2nd problem with my code example: when leaving Options -> Window... by moving the cursor up onto the button the menu won't be closed... - but I am on it ! :wink:

Re: Force a menu to close

Posted: Thu Feb 06, 2014 4:35 pm
by RASHAD
Good one Shardik

Code: Select all

If WindowFromPoint_(cpt\x | (cpt\y << 32)) = hWnd Or WindowFromPoint_(cpt\x | (cpt\y << 32)) = GadgetID(1)

Re: Force a menu to close

Posted: Thu Feb 06, 2014 4:55 pm
by Shardik
Good one RASHAD... :wink:

But I hope to have found a more general solution (no need to put the fixed GadgetID(1) into the Callback):

Code: Select all

Procedure WindowCallback(hWnd, Msg, wParam, lParam)
  Static MenuIsOpen
  Static LastMenuHandle.I

  Select Msg
    Case #WM_MENUSELECT
      If wParam & $FF = 0
        If MenuIsOpen
          MenuIsOpen = #False
          EndMenu_()
        EndIf
      Else
        If LastMenuHandle <> 0 And LastMenuHandle <> lParam And wParam & $00100000
          MenuIsOpen = #False
          EndMenu_()
        Else
          LastMenuHandle = lParam
        EndIf
      EndIf
    Case #WM_ENTERIDLE
      GetCursorPos_(cpt.POINT)
      
      If WindowFromPoint_(cpt\x | (cpt\y << 32)) = hwnd
        If MenuIsOpen
          MenuIsOpen = #False
          EndMenu_()
        EndIf
      Else
        MenuIsOpen = #True
      EndIf
  EndSelect

  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure


OpenWindow(0,100,100,320,240,"Select menu then move mouse right")
ButtonGadget(1,20,20,200,50,"Hello")

CreateMenu(0,WindowID(0))

MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")

SetWindowCallback(@WindowCallback())

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Re: Force a menu to close

Posted: Fri Feb 07, 2014 3:11 am
by PB
Okay, I was focussed on PopupMenus instead of standard Menus.
Now I see what you're talking about. :) I didn't realize there was
so much of a difference in them.

So, let's try a simpler approach. In your original post, you said that
you can detect when the mouse has left the menu, and all you need
now is a way to close it. This is the code you posted:

Code: Select all

If wParam & $FFFF = #MF_DISABLED   And lParam =  MenuID(MenuWm)
  ; Close the menu
EndIf
Therefore, I would recommend just sending an Escape keypress to close the menu:

Code: Select all

If wParam & $FFFF = #MF_DISABLED   And lParam =  MenuID(MenuWm)
  ; Close the menu
  keybd_event_(#VK_ESCAPE,0,0,0) : keybd_event_(#VK_ESCAPE,0,#KEYEVENTF_KEYUP,0)
EndIf
Does that do the job?

Re: Force a menu to close

Posted: Fri Feb 07, 2014 10:29 pm
by netmaestro

Code: Select all

Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
  Select uMsg
    Case #WM_ENTERIDLE
      GetCursorPos_(cpt.POINT)
      cn$=Space(255)
      GetClassName_(WindowFromPoint_(PeekQ(cpt)), @cn$, 255)
      If cn$ <> "#32768"
        EndMenu_()
      EndIf
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

OpenWindow(0,0,0,320,240,"Right-click!",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,200,"Test")

CreatePopupMenu(0)

MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")

SetWindowCallback(@WindowCallback())
Repeat
  EventID = WaitWindowEvent()
  If EventID = #WM_RBUTTONDOWN
    DisplayPopupMenu(0,WindowID(0))
  EndIf
Until EventID = #PB_Event_CloseWindow