Proposal: AnchorOp for keeping deferred layouts visible


  • When deferring the layout of a context menu or similar with op.Defer, you don't know where you are relative to the edge of the screen. It's very easy to accidentally display your deferred layout partially or totally off-screen.
  • When laying out widgets like drop-down menus, the choices list should be displayed above or below the menu depending on where it fits better. Similarly, right-click context menus should be shown on the side of the cursor where there is the most screen real-estate available.

Proposal: Introduce an operation (called for these purposes AnchorOp) that defers content aligned to a particular rectangle in the existing layout. The deferred content should be displayed such that one corner of the deferred layout is aligned to one corner of the anchor rectangle. The choice of corner is decided by which corner provides the most space for the deferred content.


  • The anchor area can be implemented simply as the active clip.AreaOp when the AnchorOp is submitted to the operation list.
  • For right-click context menus, the anchor area is a point (rectangle where the min/max are equal to the click position).
  • One possibility would be to make op.Defer gain this behavior by default, as almost all use-cases for op.Defer require anchoring to guard against accidentally displaying off-screen.
  • It may also be useful to add the maximum usable screen dimensions as a field to layout.Context, so deferred content can set its constraints to exactly the size of one (or both) axes of the window. This could take the form of a layout.Anchor API that created a new layout.Context with the original constraints but offset from the original context.

Thanks to Elias, Lucas, and Egon for talking through this with me during the community call office hours! We also discussed an operation that would just nudge content as little as possible until it was entirely on-screen, but anchoring seems like it would produce better results.

Assigned to
1 year, 2 months ago
6 months ago
No labels applied.

~whereswaldon 8 months ago

Anchoring can be modeled in terms of three rectangles:

  • The window frame as the outermost boundary of drawable content
  • The area in which we want to anchor some content
  • The dimensions of the content we want to anchor

The goal of anchoring content is always to ensure that the dimensions of the anchored content fit within the window frame as much as possible, and (secondarily) that the position of the anchored content is as close to the requested positioning as possible with respect to the anchor area.

I think there are a few kinds of positioning that we'd want to take into account:

  • wanting the anchored content to either cover or not cover the anchor area
  • wanting the anchored content to share a corner, edge, or center with the anchor area (if possible)
  • wanting the anchored content to always be aligned on a particular axis (drop-down menus won't want the options to appear beside them instead of above/below them)
  • wanting to bias the anchored content positioning in a particular direction in cases where multiple valid positionings are available.

For instance, right click context menus:

  • will want the anchor area to be a 1x1 pixel rectangle at the location of the right-click
  • will want to cover the anchor area
  • will want corner-to-corner alignment when possible between the anchor area and the menu
  • will want to bias towards the aligning the NW corner in the case of ties

Something like a material design context menu in an app bar has similar constraints:

  • will want the anchor area to be the triggering button's dimensions
  • will want to cover the anchor area
  • will want corner to corner alignment between the menu and the button
  • will want a NE bias for LTR layouts and an NW bias for RTL

A dropdown menu like the HTML select will want:

  • the anchor area is the always-visible portion of the select
  • will not want to cover the anchor area
  • will want to present options vertically above/below itself, but not beside
  • will want corner/corner and/or edge/edge alignment
  • will want to bias towards dropping the anchored content downwards when it fits in both directions
  • will be able to constrain the size of the dropdown area so that it can always fit by taking the window height, subtracting its own height, dividing by two, and constraining the anchored content vertically to that size

A tooltip will want:

  • the anchor area to be the control it describes
  • will not want to cover the anchor area (at least in some design systems, I suppose it can cover it)
  • will want to be centered on an edge relative to the anchor area

I'm uncertain of the best way to describe the relationships between the rectangles in an API, and perhaps this is overly complex. These are just the primary use-cases for anchoring that occur to me.

~jkvatne 6 months ago

I think this could be done very easily if each widget could get two pieces of information: The current screen size and the absolute screen position of the widget. Now I handle this by globaly storing the screen size and mouse position, and using that to show a tool tip and dropdown box. This works well for mouse clicks, but not for keyboard activation. Could this info be put into the Context (gtx)?

~inkeliz 6 months ago*

I think that was mentioned at Community Call. But, since Gio uses "Immediate Mode" such information is "not reliable", far I remember. I'm using similar construction for List, in order to get the current position of the element in the list. :S

~whereswaldon 6 months ago

It's less about unreliable absolute positioning and more about the fact that we support general 2D affine transformations. How do you communicate the absolute screen position when the current drawing canvas has been rotated 45 degrees? However, Elias has been thinking of exposing something along these lines with some specific caveats about transformations. I can't say more now, but we will likely solve this by exposing a way to resolve a position relative to some transform.

Register here or Log in to comment, or comment via email.