Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
popover_location and window title bars
-
I'm noticing that present()'ing a view with style = 'popover' doesn't seem to take the window title bar into account when popover_location is specified.
I could be getting this wrong, but I'm trying to show the popover with its little arrow pointing at the icon-only button from which it is spawned. The view that button is in is a ui.View presented with style="sheet" on top of the main ui.View of my app. I don't add the popover view as a subview of anything, and even if I do add it as a subview of the sheet, it still shows up in the "wrong" place.
First, I tested where popover_location = (0,0) placed the arrow, and that appears to be the top-left of the sheet view. Not the upper-left of the screen. So I figured the coordinates were in the space of the current key window, which in this case is the sheet view. So I tried to get the position of the icon button in coordinates which would be correct for the sheet by doing:
pos = iconButton.center
pos = ui.convert_point(pos, parentView, None)
pos = ui.convert_point(pos, None, sheetView)the idea there was to take the center of the button, which is in parent coordinates, and convert it to screen coordinates, then convert from screen coordinates to coordinates in the sheetView coordinates, but that places it too high, I have to add a value which accounts for the sheetView title bar height for when it's displayed as a sheet in order to get the right placement. So that leaves me with 2 questions:
- Is there a way to get the title bar height programmatically? Right now I'm just hardcoding a number.
- Is there a correct way to get the popover_location value which will properly take into account the title bar? The sheetView has no superview() when presented, so I have no way of directly converting the center of the iconButton to a position in the presented sheet window...but perhaps there is a way I'm unaware of.
-
@shinyformica, no time to look at this deeper now, and no iPad, but did you try @JonB’s view browser to look at the objc views for the popover?
-
popover works funny in sheet mode. The popover is with respect to the containing viewwrapper's superview, not the window. This might be different on iPhone.
On iPad, this works:
pt=v.objc_instance.convertPoint_toView_(CGPoint(b.center.x, b.center.y), v.objc_instance.superview())where b is the button, v is root sheet. if b is several levels down, you'd convert to v first.
See the sheet viewheirarchy with viewbrowser -- the highlighted view is v, note it has nonzero y.
i am not sure if there is a reliable way to detect "sheet"... though i recall a thread about this.
-
@shinyformica I answer obviously too late 😢
import ui from objc_util import * def GetTitleBarHeight(ui_view): vo = ObjCInstance(ui_view) def UpViews(v): sv = v.superview() if sv._get_objc_classname().startswith(b'UINavigation'): return sv.superview() nv = UpViews(sv) if nv: return nv def DownViews(v): for sv in v.subviews(): if sv._get_objc_classname().startswith(b'UINavigationBar'): return sv nb = DownViews(sv) if nb: return nb nv = UpViews(vo) nb = DownViews(nv) if nb: h = nb.size().height else: h = 10 # should be 50, set 10 just for testing return h mv = ui.View() mv.name = 'main view' mv.background_color = 'white' mv.present('full_screen') v = ui.View() v.name = 'view' v.frame = (0,0,500,500) b = ui.Button() b.frame = (20,20,80,80) b.image = ui.Image.named('typb:Grid') def b_action(sender): pv = ui.View() pv.name = 'popover' pv.frame = (0,0,200,200) x = sender.x + sender.width/2 y = sender.superview.titlebar_height + sender.y + sender.height/2 pv.present('popover',popover_location = (x,y)) b.action = b_action v.add_subview(b) v.present('sheet',title_bar_color='yellow') v.titlebar_height = GetTitleBarHeight(v)
-
@JonB said:
pt=v.objc_instance.convertPoint_toView_(CGPoint(b.center.x, b.center.y), v.objc_instance.superview())
Good, good stuff! Works like a charm - I have to do a double conversion, as you mentioned, from the parent of the button to the top-level view which is presented as a sheet:
def popoverPoint(topView, sourceView, pos): import objc_util x,y = pos srcobjc = sourceView.objc_instance topobjc = topView.objc_instance p = srcobjc.convertPoint_toView_(objc_util.CGPoint(x,y), topobjc) p = topobjc.convertPoint_toView_(p, topobjc.superview()) return (p.x,p.y)
-
You actually should be able to go direct from srcobj to topobjc.superview(). ConvertPoint is associative ..
As long as the coords you pass in are in the frame of the object you call convertPoint on, you are good to go.
Out of curiosity... Are you creating a "help" overlay? One of my many unfinished projects was a menu system with a "help" button that popped up hints when touching a button, or perhaps long tapping a button shows help for that button.
-
@JonB true enough...double conversion isn't necessary, was just writing fast...here's a simplified version:
def popoverPoint(topView, sourceView, pos): import objc_util x,y = pos srcobjc = sourceView.objc_instance topobjc = topView.objc_instance p = srcobjc.convertPoint_toView_(objc_util.CGPoint(x,y), topobjc.superview()) return (p.x,p.y)
This is a popup to display a list of options to the user, so the popover has a TableView subview, and tapping an item in that view dismisses the popover. Working nicely now that it shows up where expected.