Cairn · module

Cairn.Layout.Grid

lean/Cairn/Layout/Grid.lean

Grids: the theorems

About Cairn.Grid (Cairn/UI/Grid.lean), for every box size and every number of cards. The first four are about the arithmetic alone and are proved in Cairn/UI/Grid.lean itself, which apps link, so a claim can cite them; the last three are about the layout pass and are here.

  • Columns (columns_pos, columns_fits, le_columns, not_fits_succ): at least one, and the most cards of the minimum width that fit with their gaps. When one fits, every card is at least that wide unless the rows had to shrink to fit the height (minW_le_widthShare).
  • Aspect (cardH_aspect): a card's height is its width at the aspect ratio plus the caption whenever the box is tall enough for the captions.
  • Inside (cell_inside): every card's rect is inside the box.
  • Reading order (cell_before): a later card is in a lower row, or in the same row to the right; so no two cards overlap (cell_disjoint, rects_pairwise).
  • Layout (cells_rects): laid out by the ordinary pass, Grid.node's cells land exactly on Grid.rects, wherever the parent puts the grid; its controls are the cards' in the order of the items, at every size (node_controls).
  • Hit testing (hitTarget_cell): a point in card i's rect hits what card i alone would hit: no other card can take it.

Imports Cairn.UI.Grid, Cairn.Layout.Rigid

Order

Definitions 3

def

Cairn.Grid.cellItem

lean/Cairn/Layout/Grid.lean:93
cellItem (w h : Nat) : Layout.Item

What a cell offers its row: fixed on both axes at the card's size.

def

Cairn.Grid.rowRect

lean/Cairn/Layout/Grid.lean:105
rowRect (g : Grid) (x y : Int) (W H n q : Nat) : Rect

Where row q goes, for a grid whose rect starts at (x, y).

def

Cairn.Grid.cells

lean/Cairn/Layout/Grid.lean:110
cells (l : Laid) : List Laid

The cells of a laid-out grid: its rows' children, in order.

Theorems 27

theorem

Cairn.Grid.chunksAux_flatten

provedlean/Cairn/Layout/Grid.lean:31
chunksAux_flatten {α : Type} (c : Nat) (hc : 1 ≤ c) (fuel : Nat) (xs : List α) :
  xs.length ≤ fuel → (chunksAux c fuel xs).flatten = xs
theorem

Cairn.Grid.chunks_flatten

provedlean/Cairn/Layout/Grid.lean:42
chunks_flatten {α : Type} (c : Nat) (hc : 1 ≤ c) (xs : List α) :
  (chunks c xs).flatten = xs

Chunks keep the order: the rows, read one after another, are the items.

theorem

Cairn.Grid.Line.go_uniform

provedlean/Cairn/Layout/Grid.lean:49
go_uniform (ln : Layout.Line) (it : Layout.Item) (a b gap : Nat)
  (hsp : ∀ (i : Nat), ln.spacing i = ↑gap)
  (hm : Layout.Item.mainSizing ln.horiz it = Sizing.fixed a)
  (hc : Layout.Item.crossSizing ln.horiz it = Sizing.fixed b) (hal : ln.align = Align.start)
  (its : List Layout.Item) :
  (∀ (x : Layout.Item), x ∈ its → x = it) →
    ∀ (i j : Nat) (pos : Int),
      ln.go i j pos its =
        List.map (fun q => Layout.mkRect ln.horiz (pos + ↑(q * (a + gap))) (↑a) ln.c0 ↑b)
          (List.range its.length)

A line of identical items, each fixed on both axes, with constant spacing and start alignment: item q starts q pitches along.

theorem

Cairn.Grid.lineRects_uniform

provedlean/Cairn/Layout/Grid.lean:70
lineRects_uniform (hz : Bool) (st : Style) (content : Rect)
  (items : List Layout.Item) (it : Layout.Item) (a b : Nat) (hj : st.justify = Align.start)
  (hal : st.align = Align.start) (hm : Layout.Item.mainSizing hz it = Sizing.fixed a)
  (hc : Layout.Item.crossSizing hz it = Sizing.fixed b)
  (hx : ∀ (x : Layout.Item), x ∈ items → x = it) :
  Layout.lineRects hz st content items =
    List.map
      (fun q =>
        Layout.mkRect hz
          ((if hz = true then content.x else content.y) + ↑(q * (a + st.gap))) (↑a)
          (if hz = true then content.y else content.x) ↑b)
      (List.range items.length)
theorem

Cairn.Grid.arrangeList_zipWith

provedlean/Cairn/Layout/Grid.lean:82
arrangeList_zipWith (m : TextMetrics) (c : Rect) (rs : List Rect)
  (ss : List Layout.Sized) :
  rs.length = ss.length →
    Layout.arrangeList m c rs ss = List.zipWith (Layout.arrange m c) rs ss
theorem

Cairn.Grid.cellNode_item

provedlean/Cairn/Layout/Grid.lean:95
cellNode_item (m : TextMetrics) (aw : Int) (w h : Nat) (k : Node) :
  (Layout.measure m aw (cellNode w h k)).item = cellItem w h
theorem

Cairn.Grid.rowNode_item

provedlean/Cairn/Layout/Grid.lean:100
rowNode_item (g : Grid) (m : TextMetrics) (aw : Int) (W H n : Nat)
  (cells : List Node) :
  (Layout.measure m aw (g.rowNode W H n cells)).item =
    cellItem (g.usedW W H n) (g.cardH W H n)
theorem

Cairn.Grid.row_rects

provedlean/Cairn/Layout/Grid.lean:114
row_rects (g : Grid) (m : TextMetrics) (aw : Int) (clip : Rect) (x y : Int)
  (W H n q : Nat) (row : List Node)
  (hrow : ∀ (k : Node), k ∈ row → ∃ c, k = cellNode (g.cardW W H n) (g.cardH W H n) c)
  (hlen : row.length ≤ g.columns W) :
  List.map Laid.rect
      (Layout.arrange m clip (g.rowRect x y W H n q)
          (Layout.measure m aw (g.rowNode W H n row))).children =
    List.map (g.cell x y W H n) (List.range' (q * g.columns W) row.length)

A row of at most columns cells, laid out at row q's rect: its cells land on cell (q * columns + k).

theorem

Cairn.Grid.chunksAux_length_le

provedlean/Cairn/Layout/Grid.lean:147
chunksAux_length_le {α : Type} (c : Nat) (hc : 1 ≤ c) (fuel : Nat)
  (xs row : List α) :
  row ∈ chunksAux c fuel xs → row.length ≤ c ∧ ∀ (k : α), k ∈ row → k ∈ xs
theorem

Cairn.Grid.rows_rects

provedlean/Cairn/Layout/Grid.lean:160
rows_rects (g : Grid) (m : TextMetrics) (aw : Int) (clip : Rect) (x y : Int)
  (W H n fuel : Nat) (ys : List Node) (q0 : Nat) :
  ys.length ≤ fuel →
    (∀ (k : Node), k ∈ ys → ∃ c, k = cellNode (g.cardW W H n) (g.cardH W H n) c) →
      List.flatMap (fun l => List.map Laid.rect l.children)
          (List.zipWith
            (fun q row =>
              Layout.arrange m clip (g.rowRect x y W H n q)
                (Layout.measure m aw (g.rowNode W H n row)))
            (List.range' q0 (chunksAux (g.columns W) fuel ys).length)
            (chunksAux (g.columns W) fuel ys)) =
        List.map (g.cell x y W H n) (List.range' (q0 * g.columns W) ys.length)

Rows laid out from row q0 on: their cells land on cell (q0 * columns) onward.

theorem

Cairn.Grid.chunks_mem

provedlean/Cairn/Layout/Grid.lean:191
chunks_mem {α : Type} (c : Nat) (hc : 1 ≤ c) (xs row : List α)
  (h : row ∈ chunks c xs) : row.length ≤ c ∧ ∀ (k : α), k ∈ row → k ∈ xs
theorem

Cairn.Grid.node_children

provedlean/Cairn/Layout/Grid.lean:196
node_children (g : Grid) {α : Type} (m : TextMetrics) (aw : Int) (clip r : Rect)
  (W H : Nat) (card : Nat → Nat → α → Node) (xs : List α) :
  (Layout.arrange m clip r (Layout.measure m aw (g.node W H card xs))).children =
    List.zipWith
      (fun q row =>
        Layout.arrange m clip (g.rowRect r.x r.y W H xs.length q)
          (Layout.measure m (Layout.innerAvail (g.style W H xs.length) aw)
            (g.rowNode W H xs.length row)))
      (List.range' 0
        (chunks (g.columns W)
            (List.map
              (fun x =>
                cellNode (g.cardW W H xs.length) (g.cardH W H xs.length)
                  (card (g.cardW W H xs.length) (g.cardH W H xs.length) x))
              xs)).length)
      (chunks (g.columns W)
        (List.map
          (fun x =>
            cellNode (g.cardW W H xs.length) (g.cardH W H xs.length)
              (card (g.cardW W H xs.length) (g.cardH W H xs.length) x))
          xs))

The grid laid out in r: its children are its rows, each laid out at its row's rect.

theorem

Cairn.Grid.cells_rects

provedlean/Cairn/Layout/Grid.lean:228
cells_rects (g : Grid) {α : Type} (m : TextMetrics) (aw : Int) (clip r : Rect)
  (W H : Nat) (card : Nat → Nat → α → Node) (xs : List α) :
  List.map Laid.rect
      (cells (Layout.arrange m clip r (Layout.measure m aw (g.node W H card xs)))) =
    g.rects r.x r.y W H xs.length

The cells land on Grid.rects. Laid out by the ordinary layout pass, wherever its parent puts it, the grid's cells are exactly rects at the grid's origin, in order.

theorem

Cairn.Grid.flatMap_flatten'

provedlean/Cairn/Layout/Grid.lean:248
flatMap_flatten' {α β : Type} (f : α → List β) (L : List (List α)) :
  List.flatMap f L.flatten = List.flatMap (fun l => List.flatMap f l) L
theorem

Cairn.Grid.flatMap_congr'

provedlean/Cairn/Layout/Grid.lean:254
flatMap_congr' {α β : Type} {f g : α → List β} {l : List α} :
  (∀ (x : α), x ∈ l → f x = g x) → List.flatMap f l = List.flatMap g l
theorem

Cairn.Grid.controlsList_eq

provedlean/Cairn/Layout/Grid.lean:261
controlsList_eq (ks : List Node) :
  Node.controlsList ks = List.flatMap Node.controls ks
theorem

Cairn.Grid.node_controls

provedlean/Cairn/Layout/Grid.lean:267
node_controls (g : Grid) {α : Type} (W H : Nat) (card : Nat → Nat → α → Node)
  (xs : List α) :
  (g.node W H card xs).controls =
    List.flatMap
      (fun x => (card (g.cardW W H xs.length) (g.cardH W H xs.length) x).controls) xs

Stable order: the grid's controls are its cards' controls, in the order of the items, whatever the box's size; resizing moves cards but never reorders them.

theorem

Cairn.Grid.mem_zipWith'

provedlean/Cairn/Layout/Grid.lean:278
mem_zipWith' {α β γ : Type} {f : α → β → γ} {c : γ} {as : List α} {bs : List β} :
  c ∈ List.zipWith f as bs → ∃ a, a ∈ as ∧ ∃ b, b ∈ bs ∧ c = f a b
theorem

Cairn.Grid.mem_arrangeList'

provedlean/Cairn/Layout/Grid.lean:289
mem_arrangeList' (m : TextMetrics) (c : Rect) {rs : List Rect}
  {ss : List Layout.Sized} {x : Laid} :
  x ∈ Layout.arrangeList m c rs ss → ∃ r s, s ∈ ss ∧ x = Layout.arrange m c r s
theorem

Cairn.Grid.hitsList_eq

provedlean/Cairn/Layout/Grid.lean:306
hitsList_eq (o : Option Runtime.Target) (ls : List Laid) :
  Runtime.hitsList o ls = List.flatMap (Runtime.hitsOf o) ls
theorem

Cairn.Grid.arrange_clipWithin

provedlean/Cairn/Layout/Grid.lean:311
arrange_clipWithin (m : TextMetrics) (C : Rect) (s : Layout.Sized) (r : Rect) :
  Laid.Everywhere (fun l => ∀ (p : Point), l.clip.contains p = true → C.contains p = true)
    (Layout.arrange m C r s)

Every clip in a laid-out subtree lies within the clip it was laid out in.

theorem

Cairn.Grid.hits_within

provedlean/Cairn/Layout/Grid.lean:328
hits_within {C : Rect} {l : Laid}
  (hE :
    Laid.Everywhere (fun l => ∀ (p : Point), l.clip.contains p = true → C.contains p = true)
      l)
  (o : Option Runtime.Target) (e : Runtime.Hit) (p : Point) :
  e ∈ Runtime.hitsOf o l → e.visible.contains p = true → C.contains p = true

A hit entry of such a subtree contains only points of that clip.

theorem

Cairn.Grid.cellNode_hits

provedlean/Cairn/Layout/Grid.lean:354
cellNode_hits (m : TextMetrics) (aw : Int) (clip q : Rect) (w h : Nat) (k : Node)
  (e : Runtime.Hit) (p : Point) :
  e ∈ Runtime.hitsOf none (Layout.arrange m clip q (Layout.measure m aw (cellNode w h k))) →
    e.visible.contains p = true → q.contains p = true

A cell's hit entries contain only points of its rect: it clips its card.

theorem

Cairn.Grid.node_hits

provedlean/Cairn/Layout/Grid.lean:366
node_hits (g : Grid) {α : Type} (m : TextMetrics) (aw : Int) (clip r : Rect)
  (W H : Nat) (card : Nat → Nat → α → Node) (xs : List α) :
  have l := Layout.arrange m clip r (Layout.measure m aw (g.node W H card xs));
  Runtime.hitsOf none l = List.flatMap (Runtime.hitsOf none) (cells l) ∧
    ∀ (k : Laid),
      k ∈ cells l →
        ∀ (e : Runtime.Hit) (p : Point),
          e ∈ Runtime.hitsOf none k → e.visible.contains p = true → k.rect.contains p = true

The grid's hit entries are its cells', in order: the grid and its rows paint nothing.

theorem

Cairn.Grid.find?_flatMap_only

provedlean/Cairn/Layout/Grid.lean:407
find?_flatMap_only {β : Type} (Ls : List β) (f : β → List Runtime.Hit)
  (q : Runtime.Hit → Bool) (i : Nat) (hi : i < Ls.length)
  (h :
    ∀ (j : Nat) (hj : j < Ls.length),
      j ≠ i → ∀ (e : Runtime.Hit), e ∈ f Ls[j] → q e = false) :
  List.find? q (List.flatMap f Ls).reverse = List.find? q (f Ls[i]).reverse

If only the i-th list's entries can satisfy q, the topmost of the concatenation that does is the i-th's.

theorem

Cairn.Grid.cells_length

provedlean/Cairn/Layout/Grid.lean:438
cells_length (g : Grid) {α : Type} (m : TextMetrics) (aw : Int) (clip r : Rect)
  (W H : Nat) (card : Nat → Nat → α → Node) (xs : List α) :
  (cells (Layout.arrange m clip r (Layout.measure m aw (g.node W H card xs)))).length =
    xs.length
theorem

Cairn.Grid.hitTarget_cell

provedlean/Cairn/Layout/Grid.lean:448
hitTarget_cell (g : Grid) {α : Type} (m : TextMetrics) (aw : Int) (clip r : Rect)
  (W H : Nat) (card : Nat → Nat → α → Node) (xs : List α) (i : Nat) (hi : i < xs.length)
  (p : Point) (hp : (g.cell r.x r.y W H xs.length i).contains p = true) :
  ∃ k,
    (cells (Layout.arrange m clip r (Layout.measure m aw (g.node W H card xs))))[i]? =
        some k ∧
      k.rect = g.cell r.x r.y W H xs.length i ∧
        Runtime.hitTarget
            (Layout.arrange m clip r (Layout.measure m aw (g.node W H card xs))) p =
          Runtime.hitTarget k p

Hit testing finds the cell's controls. A point in card i's rect hits exactly what card i's cell alone would hit: no other card can take it, and it answers with a control of that cell or nothing.