Canvas/control - screen position for NSMenu ?

Hi,

I have a custom control which opens a context menu at the controls location. The custom control (canvas) may be nested or even just placed in a window.
I thought instead of calculation every container’s top/lef it might be easier to use a declare.

Is there an easy way to get the x,y of the canvas ?

canvas.left and canvas.top???

screen position is not x.left or x.top.
The other thing is if the control is embedded in a container it only get’s the origins relating to the embedded container.
I am basically looking for a declare. I think I’ll go for NSWindow “convertRectToScreen:”

Why not use ConstructContextualMenu and ContextualMenuAction?

Check https://forum.xojo.com/28916-control-position-on-container/0

It’s a pulldown menu control that’s open its menu on mouseDown/Up() at a specific location. not on right click.

Use the x, y from the mousedown ?

Not a Declare and maybe not 100% perfect but I’m currently using this extend:

Function scrnPosTopLeft(Extends cvs As Canvas) As Integer()
  
  // Returns Actual Screen Positions
  Dim cTop, cLeft As Integer
  cTop = cvs.Top
  cLeft = cvs.Left
  
  // Loop up
  Dim mWindow As Window = cvs.Window
  While mWindow IsA ContainerControl
    cTop = cTop + mWindow.Top
    cLeft = cLeft + mWindow.Left
    mWindow = ContainerControl(mWindow).Window
  Wend
  
  // Add 
  cTop = cTop + mWindow.Top
  cLeft = cLeft+ mWindow.Left
  
  // What Screen are we on?
  Dim thisScreen As Integer
  For i As Integer = 0 To ScreenCount - 1
    If cLeft >= Screen(i).Left And cLeft < Screen(i).Left + Screen(i).Width And cTop >= Screen(i).Top And cTop < Screen(i).Top + Screen(i).Height Then
      thisScreen = i
      Exit for i
    End If
  Next
  
  // Adjust for active Screen
  If cLeft >= Screen(thisScreen).Left Then
    cLeft = cLeft - Screen(thisScreen).Left
  End If
  If cTop >= Screen(thisScreen).Top Then
    cTop = cTop - Screen(thisScreen).Top
  End If
  
  Dim topLeft() As Integer = Array(cTop, cLeft)
  
  Return topLeft
End Function

[code]Function MouseDown(X As Integer, Y As Integer) As Boolean
dim trueleft, trueTop as integer
TrueLeft = self.TrueWindow.MouseX-X
TrueTop = self.TrueWindow.MouseY-Y

system.DebugLog str(trueleft)+" "+str(truetop)
End Function
[/code]

Hi folks,

I was peeking and poking with some declares and got it almost right but wasn’t able to get the correct x,y
if you move the window to a different screen.

Thanks for all suggestion.

It’s true the most reliable and easiest way is for my problem is to use x,y from mouseDown
and System.MouseX/Y as I’ll have a contextmenu open on a mouseDown event so basically Michal’s way with some
adjustments so that the selected menuitem is centered (assuming OSX)

https://www.dropbox.com/s/f6pcgak51805msb/CanvasPositionOnScreen.xojo_binary_project?dl=0

#Edit:
I have added further tweaks so the popup opens correctly and the mouse gets move to the selected index.

Hmm well, speaking of menuitem. Is is possible to get the NSMenu somehow ?

[code]Declare Function menu Lib “Cocoa” Selector “menu” (NSMenuItem As Ptr) As Ptr

Dim NSMenuItemPtr As Ptr = Ptr(result.Handle(MenuItem.HandleType.CocoaNSMenuItem)) // The NSMenuItem
Dim NSMenuPtr As Ptr = menu(NSMenuItemPtr) // The XOJMenu, a subclass of NSMenu[/code]

[quote=240481:@Eli Ott][code]Declare Function menu Lib “Cocoa” Selector “menu” (NSMenuItem As Ptr) As Ptr

Dim NSMenuItemPtr As Ptr = Ptr(result.Handle(MenuItem.HandleType.CocoaNSMenuItem)) // The NSMenuItem
Dim NSMenuPtr As Ptr = menu(NSMenuItemPtr) // The XOJMenu, a subclass of NSMenu[/code][/quote]

Thanks Eli. Getting the NSMenu from the popup result answers the question.

I have spent some time to understand the NSMenu/NSMenuItem since I wanted to write a custom popup
control which behaves like the OSX popup button. There are two options for the custom control in terms of the menu location:
for a pulldown menu: opens the menu beneath the control less 5 pixel
for a popup: center the selected item within the control

[code]Private Sub handlePopUp()
if self.captions.Ubound>-1 then
// some declares
declare function menu Lib CocoaLib selector “menu” (obj_id as Ptr) as Ptr
declare sub setMinimumWidth Lib CocoaLib selector “setMinimumWidth:” (obj_id as Ptr, v as CGFloat)
declare function popUpMenuPositioningItem lib CocoaLib selector “popUpMenuPositioningItem:atLocation:inView:” _
(obj_id as Ptr, item as Ptr, location as NSPoint, view as Ptr) as Boolean
declare function indexOfItem Lib CocoaLib selector “indexOfItem:” (obj_id as Ptr, m as ptr) as integer
declare function highlightedItem lib CocoaLib selector “highlightedItem” (obj_id as Ptr) as Ptr
declare function size Lib CocoaLib selector “size” (obj_id as Ptr) as NSSize

// get the xojo menuitem
dim base as MenuItem=self.makePopup()
dim firstItem as ptr = ptr(base.Item(0).Handle(MenuItem.HandleType.CocoaNSMenuItem))
dim menuRef as ptr = menu( firstItem )
// stretch menu width to the control
setMinimumWidth(menuRef, self.Width)

// Note: NSMakePoint is a convenience method
// Note to calculate the menuitem height for the centered selection, we use size() declare that returns the total height/width of the menu divided by the menuitem count that equals 18 or 19 pixel.

dim hasSelection as Boolean
select case self.ButtonType
case CustomButton1.Type.PopUp
  hasSelection = popUpMenuPositioningItem(menuRef, _
  ptr(base.Item(self.mlistIndex).Handle(MenuItem.HandleType.CocoaNSMenuItem)), _
  NSMakePoint(0, ((size(menuRef).height/base.Count-1)+me.Height)/2 ), _
   ptr(me.handle) )
case CustomButton1.Type.PullDown
  hasSelection = popUpMenuPositioningItem(menuRef, nil, NSMakePoint(0,-5), ptr(me.handle))
end select

if hasSelection then
  dim hitItem as ptr = highlightedItem(menuRef)
  if hitItem<>nil then
    self.mlistIndex=indexOfItem( menuRef, hitItem )
    self.caption = self.captions(self.mlistIndex)
  end if
end if

end if
End Sub[/code]