Page 1 of 1
popovers
Posted: Wed Jan 06, 2021 4:43 am
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.
Re: popovers
Posted: Wed Jan 06, 2021 6:16 am
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
Re: popovers
Posted: Wed Jan 06, 2021 4:00 pm
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?
Re: popovers
Posted: Wed Jan 06, 2021 9:10 pm
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
Re: popovers
Posted: Fri Jan 08, 2021 12:27 am
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.
Re: popovers
Posted: Fri Jan 08, 2021 10:18 am
by mk-soft
You don't need cocoa
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
Re: popovers
Posted: Fri Jan 08, 2021 2:08 pm
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...
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
Re: popovers
Posted: Sat Jan 09, 2021 5:20 pm
by mrbungle
this is great! thank you!
Re: popovers
Posted: Tue Jan 19, 2021 4:01 pm
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!
Re: popovers
Posted: Wed Jan 20, 2021 3:49 am
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.
Re: popovers
Posted: Wed Jan 20, 2021 5:21 am
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?
Re: popovers
Posted: Wed Jan 20, 2021 8:04 am
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.

Re: popovers
Posted: Wed Jan 20, 2021 3:02 pm
by mrbungle
Ah. That makes sense. Appreciate the time and the explanation!