1// Package popup draws the tooltips and menus that interactive modules ask for
2// with control lines (see module.ParseControl). A Host owns at most one popup:
3// an xdg_popup on the bar's layer surface, drawn by a nefergui renderer of its
4// own.
5package popup
6
7import (
8 "math"
9
10 "github.com/bnema/neferclient"
11)
12
13// Size limits of a popup, in logical pixels.
14const (
15 MaxMenuWidth = 480
16 MaxTooltipWidth = 360
17 // MaxHeight is the tallest popup; a taller menu scrolls.
18 MaxHeight = 600
19)
20
21// CellRect is the logical-pixel rectangle of width cells starting at cell
22// start of a row of cellW-physical-pixel cells on a surface of the given
23// scale, rounded outward, height pixels high.
24func CellRect(start, width, cellW int, scale float64, height int32) neferclient.Rect {
25 const eps = 1e-9
26 x0 := int32(math.Floor(float64(start)*float64(cellW)/scale + eps))
27 x1 := int32(math.Ceil(float64(start+width)*float64(cellW)/scale - eps))
28 return neferclient.Rect{X: x0, Y: 0, Width: x1 - x0, Height: height}
29}
30
31// Anchor is the rectangle a popup attaches to: the cells col .. col+width-1
32// of a module whose shown cells start at spanStart and number spanWidth. The
33// request is clamped to the shown cells. It reports false when col lies
34// outside them.
35func Anchor(spanStart, spanWidth, col, width, cellW int, scale float64, height int32) (neferclient.Rect, bool) {
36 if col < 0 || col >= spanWidth || width <= 0 || cellW <= 0 || !(scale > 0) {
37 return neferclient.Rect{}, false
38 }
39 width = min(width, spanWidth-col)
40 return CellRect(spanStart+col, width, cellW, scale, height), true
41}
42
43// Edge is the anchor edge and the gravity that put a popup on the free side of
44// a bar: below a bar at the top, above a bar at the bottom.
45func Edge(bottomBar bool) neferclient.PopupEdge {
46 if bottomBar {
47 return neferclient.EdgeTop
48 }
49 return neferclient.EdgeBottom
50}
51
52// Clamp rounds a measured size up to whole pixels and limits the height to
53// MaxHeight; scroll reports that the content is taller than that.
54func Clamp(w, h float64) (cw, ch int32, scroll bool) {
55 cw = int32(math.Ceil(max(w, 1)))
56 if h > MaxHeight {
57 return cw, MaxHeight, true
58 }
59 return cw, int32(math.Ceil(max(h, 1))), false
60}
61
62// Placement is where a popup of the given size goes for an anchor.
63func Placement(anchor neferclient.Rect, bottomBar bool, w, h int32) neferclient.PopupPlacement {
64 e := Edge(bottomBar)
65 return neferclient.PopupPlacement{
66 Anchor: anchor, Edge: e, Gravity: e,
67 Adjust: neferclient.AdjustSlideX | neferclient.AdjustFlipY | neferclient.AdjustResizeY,
68 Width: w, Height: h,
69 }
70}