Detecting when a popupmenu disappears when mouse clicked out

Just starting out? Need help? Post your questions and find answers here.
dougmo52usr
User
User
Posts: 55
Joined: Mon Jul 18, 2016 6:43 pm

Detecting when a popupmenu disappears when mouse clicked out

Post by dougmo52usr »

Running PureBasic 5.42 LTS (Linux - x64). When an item in a popupmenu is clicked, a #PB_Event_Menu is sent and I can then process the selection and free the menu in the handler. But suppose I click outside the menu and it disappears with no selection made. How can I detect this situation and take action to cleanup? I don't see such an event, or a way to query if the menu is hidden.
wombats
Enthusiast
Enthusiast
Posts: 664
Joined: Thu Dec 29, 2011 5:03 pm

Re: Detecting when a popupmenu disappears when mouse clicked

Post by wombats »

You should be able to put the cleanup code directly after DisplayPopupMenu(), I think.
dougmo52usr
User
User
Posts: 55
Joined: Mon Jul 18, 2016 6:43 pm

Re: Detecting when a popupmenu disappears when mouse clicked

Post by dougmo52usr »

if I do this:
Debug("Before DisplayPopupMenu")
DisplayPopupMenu(NetworkMenu,WindowID(Window_0))
Debug("After DisplayPopupMenu")
both debug messages go out with the menu still visible. So DisplayPopupMenu returns immediately after displaying the menu, not after it is released.

I am hoping to create a reasonable emulation of the win32api TrackPopupMenu. I can get close except for the case when no selection is made and the menu is hidden by clicking outside. The fact that the menu knows to disappear means someone somewhere is getting an event.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Detecting when a popupmenu disappears when mouse clicked

Post by Dude »

dougmo52usr wrote:Running PureBasic 5.42 LTS (Linux - x64)
I only know how to do it on Windows, but that doesn't help if you're on Linux.

Does Linux have a way to know the foreground window, like Windows can? If so, try storing the foreground window handle before opening the menu, and then when a new window becomes foreground which isn't due to a menu event, then your app will know something other than the menu has been clicked (meaning the menu will be closed).

For those interested, here is the Windows method:

Code: Select all

Global menuopen

Procedure Callback(hWnd,Message,wParam,lParam)
  result=#PB_ProcessPureBasicEvents
  If Message=#WM_INITMENUPOPUP
    If menuopen=0
      menuopen=wParam
      Debug "opened"
    EndIf
  ElseIf Message=#WM_UNINITMENUPOPUP
    If wParam=menuopen
      menuopen=0
      Debug "closed"
    EndIf
  EndIf
  ProcedureReturn result
EndProcedure

OpenWindow(0,200,200,200,100,"test",#PB_Window_SystemMenu)

ButtonGadget(0,10,10,180,80,"Click to open menu")

CreatePopupMenu(0)
MenuItem(0,"test")

SetWindowCallback(@Callback())

Repeat

  ev=WaitWindowEvent()
  
  If ev=#PB_Event_Gadget
    DisplayPopupMenu(0,WindowID(0))
  EndIf

Until ev=#PB_Event_CloseWindow
dougmo52usr
User
User
Posts: 55
Joined: Mon Jul 18, 2016 6:43 pm

Re: Detecting when a popupmenu disappears when mouse clicked

Post by dougmo52usr »

This seems to emulate some of TrackPopupMenu. That is it displays a popupmenu, waits for the popupmenu to disappear, and returns the id of the clicked item. I prefer to start numbering items at 1 with 0 being menu closed with no selection.

Code: Select all

EnableExplicit

Global MainWind
Global MainMenu
Global PopuMenu
Global Selected
Global ItemText

Enumeration MainMenuIDs
  #EMenuIdPopup1=1
  #EMenuIdPopup2
EndEnumeration

Declare TrackPopupMenu(hMenu)
Declare AppMainWindow()

AppMainWindow()

Procedure AppMainWindow()
  MainWind = OpenWindow(#PB_Any, #PB_Ignore, #PB_Ignore, 250, 200, "TrackPopupMenu example", #PB_Window_SystemMenu | #PB_Window_TitleBar)
  If IsWindow(MainWind)
    ItemText = StringGadget(#PB_Any, 25, 100, 200, 25, #Null$)
    Selected = StringGadget(#PB_Any, 25, 130, 200, 25, #Null$)
    MainMenu = CreateMenu(#PB_Any,WindowID(MainWind))  
    If IsMenu(MainMenu)
      MenuTitle("Main Menu")
      MenuItem(#EMenuIdPopup1,"Popup1")
      MenuItem(#EMenuIdPopup2,"Popup2")
      Protected Event
      Repeat
        Event = WaitWindowEvent()    
        If MainWind = EventWindow() 
          Select Event
            Case #PB_Event_Menu
              PopuMenu = CreatePopupMenu(#PB_Any)
              If IsMenu(PopuMenu)
                Protected ItemId
                For ItemId=1 To 5
                  MenuItem(ItemId,"Popup " + Str(EventMenu()) + " Item " + Str(ItemId))
                Next
                SetGadgetText(Selected,#Null$)
                Protected ItemSelected = TrackPopupMenu(PopuMenu)
                SetGadgetText(Selected,"TrackPopupMenu returned " + Str(ItemSelected))
                If ItemSelected
                  SetGadgetText(ItemText,"Clicked " + GetMenuItemText(PopuMenu,ItemSelected))
                Else
                  SetGadgetText(ItemText,"Clicked outside menu")
                EndIf                
                FreeMenu(PopuMenu)
              EndIf
          EndSelect         
        EndIf 
      Until Event = #PB_Event_CloseWindow ; Quit on any window close
    EndIf
  EndIf
  
EndProcedure

;TrackPopupMenu creates a borderless window and attaches the menu to it.  
;The operation is basically in it's message loop as follows:
; #PB_Event_ActivateWindow    - fired by OpenWindow, DisplayPopupMenu is called
; #PB_Event_DeactivateWindow  - fired by DisplayPopupMenu getting the focus
; #PB_Event_ActivateWindow    - fired by popupmenu disappearance
; #PB_Event_Menu              - fired by menu item selection
Procedure TrackPopupMenu(hMenu)
  ;0 if no menuitem selected
  Protected MenuItemID = 0
  ; fires first #PB_Event_ActivateWindow
  Protected thisWindow = OpenWindow(#PB_Any, DesktopMouseX(),DesktopMouseY(), 1, 1, #Null$, #PB_Window_BorderLess)
  ;If window successfully created
  If IsWindow(thisWindow)
    Protected MenuDisplayed = #False
    Protected Event
    Repeat
      ;if window event comes in
      Event = WaitWindowEvent()   
      ;and it is directed at this window
      If thisWindow = EventWindow() 
        ;process event
        Select Event
          ;if menu item clicked, handle it
          Case #PB_Event_Menu
            MenuItemID = EventMenu()
             ;get this event when:
            ;   1.  OpenWindow is called
            ;   2.  Popup menu disappears
            ;menu will disappear triggering a #PB_Event_ActivateWindow
          Case #PB_Event_ActivateWindow
            ;if menu is not yet displayed, event came from OpenWindow
            If Not MenuDisplayed
              ; display the popupmenu which fires a #PB_Event_DeactivateWindow
              DisplayPopupMenu(hMenu,WindowID(thisWindow),DesktopMouseX(),DesktopMouseY())
            ;otherwise it came from PopupMenu disappearance
            Else
              ;so tell the window to close
              PostEvent(#PB_Event_CloseWindow,thisWindow,0)
            EndIf
          ;fired when menu is shown covering the window
          Case #PB_Event_DeactivateWindow
            ;MenuDisplayed state
            MenuDisplayed = #True
        EndSelect
      EndIf      
    Until Event = #PB_Event_CloseWindow
  EndIf 
  ProcedureReturn MenuItemID
EndProcedure
Post Reply