popovers

Mac OSX specific forum
mrbungle
Enthusiast
Enthusiast
Posts: 111
Joined: Wed Dec 30, 2020 3:18 am

popovers

Post by mrbungle »

i'm new to PB on the mac. the examples in this forum are great. thank you for sharing the tips. does someone have suggestions for how to implement popover menus? for example, when clicking on a status item, showing a popover anchored to the status bar similar to programs like itsycal: https://www.mowglii.com/itsycal/

thank you in advance.
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: popovers

Post by TI-994A »

mrbungle wrote:...how to implement popover menus? for example, when clicking on a status item, showing a popover anchored to the status bar...
In PureBasic, that's known as the system tray, and it's implemented as follows:

Code: Select all

Enumeration
  #mainWindow
  #sysTrayIcon
  #sysTrayMenu
EndEnumeration

LoadImage(#sysTrayIcon, #PB_Compiler_Home + "examples/sources/Data/Drive.bmp")
wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
OpenWindow(#mainWindow, 0, 0, 600, 400, "SysTray Example", wFlags)
AddSysTrayIcon(#sysTrayIcon, WindowID(#MainWindow), ImageID(#sysTrayIcon))
SysTrayIconToolTip(#sysTrayIcon, "My PureBasic Application")   ;hover text

CreatePopupMenu(#sysTrayMenu)
MenuItem(0, "SysTray Menu 1")
MenuItem(1, "SysTray Menu 2")
MenuItem(2, "SysTray Menu 3")

Repeat   
  
  Select WaitWindowEvent()
      
    Case #PB_Event_CloseWindow     
      appQuit = #True
      
    Case #PB_Event_SysTray      
      If EventType() = #PB_EventType_LeftClick
        DisplayPopupMenu(#sysTrayMenu, WindowID(#mainWindow))
      EndIf
      
  EndSelect
  
Until appQuit
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
mrbungle
Enthusiast
Enthusiast
Posts: 111
Joined: Wed Dec 30, 2020 3:18 am

Re: popovers

Post by mrbungle »

thank you for your response! i'm familiar with the systray function but was thinking of the genuine function to flush windows against the menu bar and the status menu like with itsycal in my example. purebasic supports the menu capability but i assume it requires some direct cocoa interface?
User avatar
mk-soft
Always Here
Always Here
Posts: 5313
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: popovers

Post by mk-soft »

You can define the position of popup menu ...

Code: Select all

Enumeration
  #mainWindow
  #sysTrayIcon
  #sysTrayMenu
EndEnumeration

LoadImage(#sysTrayIcon, #PB_Compiler_Home + "examples/sources/Data/Drive.bmp")
wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
OpenWindow(#mainWindow, 0, 0, 600, 400, "SysTray Example", wFlags)
AddSysTrayIcon(#sysTrayIcon, WindowID(#MainWindow), ImageID(#sysTrayIcon))
SysTrayIconToolTip(#sysTrayIcon, "My PureBasic Application")   ;hover text

CreatePopupMenu(#sysTrayMenu)
MenuItem(0, "SysTray Menu 1")
MenuItem(1, "SysTray Menu 2")
MenuItem(2, "SysTray Menu 3")

Repeat   
  
  Select WaitWindowEvent()
      
    Case #PB_Event_CloseWindow     
      appQuit = #True
      
    Case #PB_Event_SysTray      
      If EventType() = #PB_EventType_LeftClick
        DisplayPopupMenu(#sysTrayMenu, WindowID(#mainWindow), DesktopMouseX() - 30, 30)
      EndIf
      
  EndSelect
  
Until appQuit
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mrbungle
Enthusiast
Enthusiast
Posts: 111
Joined: Wed Dec 30, 2020 3:18 am

Re: popovers

Post by mrbungle »

Thank you again! I hadn't released the desktopX and Y functions combined with a borderless window could simulate a popover.

is it safe to assume that with some cocoa wizardry using one of the examples posted in this forum i could intercept the menu bar click (status menu) and then display a popover window? i really want to draw the content for my app inside a window so i can rely on gadgets and images to display the information i need.
User avatar
mk-soft
Always Here
Always Here
Posts: 5313
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: popovers

Post by mk-soft »

You don't need cocoa :wink:

Update

Code: Select all

Enumeration Windows
  #mainWindow
  #popupWindow
EndEnumeration

Enumeration Gadgets
  #popupContainer
  #popupButtonExit
EndEnumeration

Enumeration MenuBars
  ;
EndEnumeration

Enumeration MenuItems
  ;
EndEnumeration

Enumeration SysTrays
  #sysTrayIcon
EndEnumeration

Procedure PopOverWindow()
  Protected mouse_x, x, y, dx, dy, cnt
  
  dx = 200
  dy = 400
  
  cnt = ExamineDesktops()
  
  mouse_x = DesktopMouseX()
  x = mouse_x - dx / 2
  y = 30
  
  If (x + dx) >= DesktopWidth(0)
    x = DesktopWidth(0) - dx - 10
  EndIf
  
  If OpenWindow(#popupWindow, x, y, dx, dy, "PopOver", #PB_Window_BorderLess)
    StickyWindow(#popupWindow, #True)
    ContainerGadget(#popupContainer, 0, 0, dx, dy, #PB_Container_Single)
    ;{
    ButtonGadget(#popupButtonExit, dx / 2 - 40, dy - 40, 80, 30, "Close")
    ;}
    CloseGadgetList()
  EndIf
EndProcedure

LoadImage(#sysTrayIcon, #PB_Compiler_Home + "examples/sources/Data/Drive.bmp")
wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
OpenWindow(#mainWindow, 0, 0, 600, 400, "SysTray Example", wFlags)
AddSysTrayIcon(#sysTrayIcon, WindowID(#MainWindow), ImageID(#sysTrayIcon))
SysTrayIconToolTip(#sysTrayIcon, "My PureBasic Application")   ;hover text

Repeat   
  
  Select WaitWindowEvent()
      
    Case #PB_Event_CloseWindow     
      appQuit = #True
      
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #popupButtonExit
          ;TODO
          CloseWindow(#popupWindow)
          
      EndSelect
      
    Case #PB_Event_SysTray      
      If EventType() = #PB_EventType_LeftClick
        If Not IsWindow(#popupWindow)
          PopOverWindow()
        EndIf
        
      EndIf
      
  EndSelect
  
Until appQuit
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: popovers

Post by TI-994A »

mrbungle wrote:...thinking of the genuine function to flush windows against the menu bar and the status menu like with itsycal in my example...
Image

Image

Image

Instead of the NSPopover, this example utilises a transparent PNG to create a custom-shaped window which can be positioned as required and used as a dialog. Visually more interesting.

Code: Select all

; this example automatically downloads a PNG image from DropBox

InitNetwork()
UsePNGImageDecoder()

Enumeration
  #mainWindow  
  #popupWindow
  #sysTrayIcon  
  #sysTrayIconImage
  #popupWindowShape
  #popupWindowClose
  #popupWindowCheck1
  #popupWindowCheck2  
EndEnumeration

;downloading popup window image from DropBox
If FileSize(GetTemporaryDirectory() + "customPop.png") < 1
  ReceiveHTTPFile("https://www.dropbox.com/s/3im9yuvv0u932kn/customPop.png?dl=1",
                  GetTemporaryDirectory() + "customPop.png")
EndIf

LoadImage(#popupWindowShape, GetTemporaryDirectory() + "customPop.png")
LoadImage(#sysTrayIconImage, #PB_Compiler_Home + "examples/sources/Data/Drive.bmp")

Procedure popupWindow() 
  
  ExamineDesktops()
    
  popWidth = ImageWidth(#popupWindowShape)
  popHeight = ImageHeight(#popupWindowShape)
  popX = DesktopMouseX()- (popWidth / 2)
  popY = 0
 
  If (popX + popWidth) >= DesktopWidth(0) : popX = DesktopWidth(0) - popWidth - 10 : EndIf
   
  OpenWindow(#popupWindow, popX, popY, popWidth, popHeight, "", #PB_Window_BorderLess)    
  StickyWindow(#popupWindow, #True)
  
  popupWindowShape = CocoaMessage(0, 0, "NSColor colorWithPatternImage:", ImageID(#popupWindowShape))
  CocoaMessage(0, WindowID(#popupWindow), "setOpaque:", #NO)
  CocoaMessage(0, WindowID(#popupWindow), "setHasShadow:", #YES)  
  CocoaMessage(0, WindowID(#popupWindow), "setBackgroundColor:", popupWindowShape)               
    
  CheckBoxGadget(#popupWindowCheck1, 60, 65, 80, 20, "Option 1")
  CheckBoxGadget(#popupWindowCheck2, 60, 85, 80, 20, "Option 2")
  ButtonGadget(#popupWindowClose, 60, 105, 80, 20, "DONE")
  
EndProcedure

wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
OpenWindow(#mainWindow, 0, 0, 400, 200, "Custom SysTray Example", wFlags)
AddSysTrayIcon(#sysTrayIcon, WindowID(#MainWindow), ImageID(#sysTrayIconImage))
SysTrayIconToolTip(#sysTrayIcon, "My PureBasic Application")   ;hover text

Repeat   
      
  Select WaitWindowEvent()
      
    Case #PB_Event_CloseWindow           
      appQuit = #True
      
    Case #PB_Event_Gadget            
      Select EventGadget()          
        Case #popupWindowClose               
          CloseWindow(#popupWindow)                    
      EndSelect
      
    Case #PB_Event_SysTray           
      If EventType() = #PB_EventType_LeftClick        
        If Not IsWindow(#popupWindow)          
          popupWindow()          
        EndIf        
      EndIf
      
  EndSelect
  
Until appQuit
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
mrbungle
Enthusiast
Enthusiast
Posts: 111
Joined: Wed Dec 30, 2020 3:18 am

Re: popovers

Post by mrbungle »

this is great! thank you!
mrbungle
Enthusiast
Enthusiast
Posts: 111
Joined: Wed Dec 30, 2020 3:18 am

Re: popovers

Post by mrbungle »

Your examples were really helpful and have given me some ideas. I did notice that these custom popover windows don't seem to work on a second monitor. is there something special i need to do to force it to display on my other monitor?

Thank you for all of your help and generosity!
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: popovers

Post by TI-994A »

mrbungle wrote:...these custom popover windows don't seem to work on a second monitor...
The examples didn't factor in multiple desktops. The calculation ensuring that the pop-up window does not exceed the desktop bounds utilises only the metrics of the primary desktop. Removing that condition solves the multiple-desktop issue. Just a two-line change to the popupWindow() procedure, like so:

Code: Select all

Procedure popupWindow()
 
  ExamineDesktops()
   
  popWidth = ImageWidth(#popupWindowShape)
  popHeight = ImageHeight(#popupWindowShape)
  popX = DesktopMouseX()- (popWidth / 2)

  ; [1] ###################
  ; change the popY value
    popY = DesktopMouseY()
  ; #######################
  
  ; [2] #####################################################################################
  ; remove this line that validates the popX position against the primary desktop width
  ; If (popX + popWidth) >= DesktopWidth(0) : popX = DesktopWidth(0) - popWidth - 10 : EndIf 
  ; #########################################################################################
   
  OpenWindow(#popupWindow, popX, popY, popWidth, popHeight, "", #PB_Window_BorderLess)   
  StickyWindow(#popupWindow, #True)
 
  popupWindowShape = CocoaMessage(0, 0, "NSColor colorWithPatternImage:", ImageID(#popupWindowShape))
  CocoaMessage(0, WindowID(#popupWindow), "setOpaque:", #NO)
  CocoaMessage(0, WindowID(#popupWindow), "setHasShadow:", #YES) 
  CocoaMessage(0, WindowID(#popupWindow), "setBackgroundColor:", popupWindowShape)               
   
  CheckBoxGadget(#popupWindowCheck1, 60, 65, 80, 20, "Option 1")
  CheckBoxGadget(#popupWindowCheck2, 60, 85, 80, 20, "Option 2")
  ButtonGadget(#popupWindowClose, 60, 105, 80, 20, "DONE")
 
EndProcedure
Note, however, in the unlikely event that the position and width of the pop-up window causes it to exceed the desktop bounds, it will still be displayed, but cropped from view. Some desktop-metric checks should be included to prevent this.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
mrbungle
Enthusiast
Enthusiast
Posts: 111
Joined: Wed Dec 30, 2020 3:18 am

Re: popovers

Post by mrbungle »

Thank you again! This should be obvious to me but it wasn't. I had removed the Desktop(0) code before and it didn't work. I guess this is due to how coordinates are treated across multiple displays where the Y value assumes the primary display and the desktopY value is relative to the currently active display?
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: popovers

Post by TI-994A »

mrbungle wrote:...how coordinates are treated across multiple displays where the Y value assumes the primary display and the desktopY value is relative to the currently active display?
Yes. A primary desktop with a 1920 x 1080 display begins at coordinate 0, 0, and ends at 1919, 1079.

If there is a secondary desktop arranged to the right, it will have a starting X coordinate of 1920 (the width of the primary desktop), but not necessarily a Y coordinate of 0. This is because the secondary desktop can be aligned at different heights by the OS.

Similarly, if the second desktop with a 1280 x 1024 display is arranged to the left, it will have a starting X coordinate of -1280 (the width of the secondary desktop).

So, in left/right display arrangements, the X coordinates are relative to the primary desktop, but the Y coordinates are dependent on the arrangement of the desktops by the OS. But in top/bottom display arrangements, the coordinate rule is flipped.

Image
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
mrbungle
Enthusiast
Enthusiast
Posts: 111
Joined: Wed Dec 30, 2020 3:18 am

Re: popovers

Post by mrbungle »

Ah. That makes sense. Appreciate the time and the explanation!
Post Reply