Cairn · module

Cairn.Layout.Bridge

lean/Cairn/Layout/Bridge.lean

From layout facts to the runtime's LayoutFacts

The runtime's pressable theorems (Cairn.Runtime.hitTest_center, click_center_presses) take Cairn.Runtime.LayoutFacts laid t: the control's visible rect is nonempty and a pointer at its centre reaches it. This file proves that every control of layout m w n satisfies it, given four conditions an app can check about its view (Pressable):

  1. It fits. In every container, padding is non-negative, each child is no larger than the content box, and in a row or column the children plus gaps fit along the main axis (Fits). This is where the minimum window size comes in. A box that clips and holds only text is exempt: its text may overflow (a long title, a label under unusual metrics), but the clip keeps everything it paints inside its rect, and text has no controls.
  2. The root is inside the window.
  3. Stacks keep controls on top. In a stack, only the last child may contain controls (StackTop): earlier children are backgrounds that later ones paint over.
  4. Controls are leaves for hit testing. A box with a control has no controls below it (ControlLeaf), so a label inside a button routes to the button.

Then every control whose rect is nonempty is pressable at its centre (layoutFacts_of_pressable), and indeed at every point of its visible rect (reaches_of_pressable).

Imports Cairn.Layout.Proofs, Cairn.UI.Hit

Order

Structures 1

structure

Cairn.Layout.Pressable

lean/Cairn/Layout/Bridge.lean:65
Pressable (w : Size) (l : Laid) : Prop

What an app shows about its laid-out view so that every control in it is pressable.

Fields
rootInside : l.rect.inside (windowRect w)
fits : Laid.Everywhere Fits l
stackTop : Laid.Everywhere StackTop l
controlLeaf : Laid.Everywhere ControlLeaf l

Definitions 9

def

Cairn.Laid.isText

lean/Cairn/Layout/Bridge.lean:31
isText : Laid → Bool
def

Cairn.Layout.Fits

lean/Cairn/Layout/Bridge.lean:39
Fits : Laid → Prop

The children of this container fit in its content box, and its padding is non-negative; or it clips and its children are text, which may overflow it; or it scrolls, its padding is non-negative and its children fit across its axis (along it they may run past the box: the scroll box clips them).

def

Cairn.Layout.StackTop

lean/Cairn/Layout/Bridge.lean:55
StackTop : Laid → Prop

In a stack, only the last child may contain controls.

def

Cairn.Layout.ControlLeaf

lean/Cairn/Layout/Bridge.lean:60
ControlLeaf : Laid → Prop

A box with a control has no controls below it.

def

Cairn.Layout.Good

lean/Cairn/Layout/Bridge.lean:191
Good (l : Laid) : Prop

Everything the argument uses at one node.

def

Cairn.Layout.ReachesIn

lean/Cairn/Layout/Bridge.lean:304
ReachesIn (hs : List Runtime.Hit) (t : Runtime.Target) (p : Point) : Prop

Reaches, for any list of hit entries.

def

Cairn.Layout.NoScroll

lean/Cairn/Layout/Bridge.lean:379
NoScroll : Laid → Prop

A box that doesn't scroll (text and fields never do).

def

Cairn.Layout.Sized.scrolls

lean/Cairn/Layout/Bridge.lean:385
scrolls : Sized → Bool

Whether a measured view has a scroll box anywhere in it.

def

Cairn.Layout.Sized.scrollsList

lean/Cairn/Layout/Bridge.lean:388
scrollsList : List Sized → Bool

Theorems 43

theorem

Cairn.Layout.Rect.contains_iff

provedlean/Cairn/Layout/Bridge.lean:73
contains_iff (r : Rect) (p : Point) :
  r.contains p = true ↔ r.x ≤ p.x ∧ p.x < r.x + r.w ∧ r.y ≤ p.y ∧ p.y < r.y + r.h
theorem

Cairn.Layout.Rect.inter_contains_left

provedlean/Cairn/Layout/Bridge.lean:77
inter_contains_left {a b : Rect} {p : Point}
  (h : (a.inter b).contains p = true) : a.contains p = true
theorem

Cairn.Layout.Rect.inter_contains_right

provedlean/Cairn/Layout/Bridge.lean:82
inter_contains_right {a b : Rect} {p : Point}
  (h : (a.inter b).contains p = true) : b.contains p = true
theorem

Cairn.Layout.Rect.contains_of_inside

provedlean/Cairn/Layout/Bridge.lean:87
contains_of_inside {r o : Rect} {p : Point} (hi : r.inside o)
  (h : r.contains p = true) : o.contains p = true
theorem

Cairn.Layout.Rect.inset_inside

provedlean/Cairn/Layout/Bridge.lean:91
inset_inside (r : Rect) {i : Insets} (ht : 0 ≤ i.top) (hr : 0 ≤ i.right)
  (hb : 0 ≤ i.bottom) (hl : 0 ≤ i.left) : (r.inset i).inside r
theorem

Cairn.Layout.Rect.inside_inter

provedlean/Cairn/Layout/Bridge.lean:96
inside_inter {r a b : Rect} (ha : r.inside a) (hb : r.inside b) :
  r.inside (a.inter b)
theorem

Cairn.Layout.Rect.inter_of_inside

provedlean/Cairn/Layout/Bridge.lean:100
inter_of_inside {r c : Rect} (h : r.inside c) (hw : 0 ≤ r.w)
  (hh : 0 ≤ r.h) : r.inter c = r
theorem

Cairn.Layout.Rect.disjoint_contains

provedlean/Cairn/Layout/Bridge.lean:106
disjoint_contains {a b : Rect} {p : Point} (hd : a.disjoint b)
  (ha : a.contains p = true) (hb : b.contains p = true) : False
theorem

Cairn.Layout.hitsList_append

provedlean/Cairn/Layout/Bridge.lean:112
hitsList_append (o : Option Runtime.Target) (a b : List Laid) :
  Runtime.hitsList o (a ++ b) = Runtime.hitsList o a ++ Runtime.hitsList o b
theorem

Cairn.Layout.mem_hitsList

provedlean/Cairn/Layout/Bridge.lean:118
mem_hitsList {o : Option Runtime.Target} {h : Runtime.Hit} {ls : List Laid} :
  h ∈ Runtime.hitsList o ls → ∃ k, k ∈ ls ∧ h ∈ Runtime.hitsOf o k
theorem

Cairn.Layout.mem_targetsList_split

provedlean/Cairn/Layout/Bridge.lean:128
mem_targetsList_split {t : Runtime.Target} {ls : List Laid} :
  t ∈ Runtime.targetsList ls → ∃ pre k post, ls = pre ++ k :: post ∧ t ∈ Runtime.targetsOf k
theorem

Cairn.Layout.targetsOf_controls

provedlean/Cairn/Layout/Bridge.lean:139
targetsOf_controls (l : Laid) :
  List.map (fun x => x.control) (Runtime.targetsOf l) = l.controls
theorem

Cairn.Layout.targetsList_controls

provedlean/Cairn/Layout/Bridge.lean:145
targetsList_controls (ls : List Laid) :
  List.map (fun x => x.control) (Runtime.targetsList ls) = Laid.controlsList ls
theorem

Cairn.Layout.targetsOf_eq_nil

provedlean/Cairn/Layout/Bridge.lean:153
targetsOf_eq_nil {l : Laid} (h : l.controls = []) : Runtime.targetsOf l = []
theorem

Cairn.Layout.targetsList_eq_nil

provedlean/Cairn/Layout/Bridge.lean:156
targetsList_eq_nil {ls : List Laid} (h : Laid.controlsList ls = []) :
  Runtime.targetsList ls = []
theorem

Cairn.Layout.mem_targetsOf_box

provedlean/Cairn/Layout/Bridge.lean:159
mem_targetsOf_box {t : Runtime.Target} {r c : Rect} {st : Style}
  {ctl : Option Control} {kids : List Laid}
  (ht : t ∈ Runtime.targetsOf (Laid.box r c st ctl kids)) :
  (∃ k, ctl = some k ∧ t = { node := Laid.box r c st ctl kids, control := k }) ∨
    t ∈ Runtime.targetsList kids
theorem

Cairn.Laid.Everywhere.target

provedlean/Cairn/Layout/Bridge.lean:171
target {P : Laid → Prop} {l : Laid} (hE : Everywhere P l)
  (t : Runtime.Target) : t ∈ Runtime.targetsOf l → P t.node

A fact holding everywhere holds at every control's node.

theorem

Cairn.Layout.Good.child_inside

provedlean/Cairn/Layout/Bridge.lean:197
child_inside {r c : Rect} {st : Style} {ctl : Option Control}
  {kids : List Laid} (hG : Good (Laid.box r c st ctl kids)) (hs : st.scroll = none)
  {k : Laid} (hk : k ∈ kids) (hnt : k.isText = false) : k.rect.inside r

In a container that fits and doesn't scroll (and isn't a clipped box of text), each child's rect is inside the container's rect.

theorem

Cairn.Layout.Good.child_clip

provedlean/Cairn/Layout/Bridge.lean:208
child_clip {r c : Rect} {st : Style} {ctl : Option Control}
  {kids : List Laid} (hG : Good (Laid.box r c st ctl kids)) (hclips : st.clips = true)
  {k : Laid} (hk : k ∈ kids) : k.clip = c.inter r

The clip a clipping box hands its children is its own clip cut down to its rect.

theorem

Cairn.Layout.Good.text_hit

provedlean/Cairn/Layout/Bridge.lean:216
text_hit {r c : Rect} {st : Style} {ctl : Option Control}
  {kids : List Laid} (hG : Good (Laid.box r c st ctl kids)) (hs : st.scroll = none)
  {k : Laid} (hk : k ∈ kids) (ht : k.isText = true) {o : Option Runtime.Target}
  {h : Runtime.Hit} {p : Point} (hh : h ∈ Runtime.hitsOf o k)
  (hc : h.visible.contains p = true) : r.contains p = true

A text child's hits are inside its parent's rect when the parent fits or clips.

theorem

Cairn.Layout.hits_in_clip

provedlean/Cairn/Layout/Bridge.lean:239
hits_in_clip {l : Laid} (hE : Laid.Everywhere ClipInside l)
  (o : Option Runtime.Target) (h : Runtime.Hit) (p : Point) :
  h ∈ Runtime.hitsOf o l → h.visible.contains p = true → l.clip.contains p = true

Every hit entry in a subtree that contains p lies inside the subtree's root clip.

theorem

Cairn.Laid.Everywhere.clipInside

provedlean/Cairn/Layout/Bridge.lean:264
clipInside {l : Laid} (hE : Everywhere Layout.Good l) :
  Everywhere Layout.ClipInside l
theorem

Cairn.Layout.hits_inside

provedlean/Cairn/Layout/Bridge.lean:268
hits_inside {l : Laid} (hE : Laid.Everywhere Good l)
  (o : Option Runtime.Target) (h : Runtime.Hit) (p : Point) :
  h ∈ Runtime.hitsOf o l → h.visible.contains p = true → l.rect.contains p = true

Every hit entry in a subtree that contains p lies inside the subtree's root rect.

theorem

Cairn.Layout.mem_dropLast

provedlean/Cairn/Layout/Bridge.lean:308
mem_dropLast {α : Type} {pre post : List α} {k k' : α} (h : k' ∈ post) :
  k ∈ (pre ++ k :: post).dropLast
theorem

Cairn.Layout.reachesIn_of_good

provedlean/Cairn/Layout/Bridge.lean:318
reachesIn_of_good {l : Laid} (hE : Laid.Everywhere Good l)
  (o : Option Runtime.Target) (t : Runtime.Target) (p : Point) :
  t ∈ Runtime.targetsOf l → t.visible.contains p = true → ReachesIn (Runtime.hitsOf o l) t p

In a tree where every node is Good, a pointer anywhere in a control's visible rect reaches that control.

theorem

Cairn.Layout.paraLines_scrolls

provedlean/Cairn/Layout/Bridge.lean:393
paraLines_scrolls (m : TextMetrics) (ts : TextStyle) (wr : Wrap) (aw : Int)
  (s : String) : Sized.scrollsList (paraLines m ts wr aw s) = false
theorem

Cairn.Layout.measure_scrolls

provedlean/Cairn/Layout/Bridge.lean:402
measure_scrolls (m : TextMetrics) (aw : Int) (n : Node) :
  (measure m aw n).scrolls = n.scrolls
theorem

Cairn.Layout.measureList_scrolls

provedlean/Cairn/Layout/Bridge.lean:411
measureList_scrolls (m : TextMetrics) (aw : Int) (ns : List Node) :
  Sized.scrollsList (measureList m aw ns) = Node.scrollsList ns
theorem

Cairn.Layout.arrange_noScroll

provedlean/Cairn/Layout/Bridge.lean:420
arrange_noScroll (m : TextMetrics) (s : Sized) :
  s.scrolls = false → ∀ (c r : Rect), Laid.Everywhere NoScroll (arrange m c r s)
theorem

Cairn.Layout.arrangeList_noScroll

provedlean/Cairn/Layout/Bridge.lean:432
arrangeList_noScroll (m : TextMetrics) (ss : List Sized) :
  Sized.scrollsList ss = false →
    ∀ (c : Rect) (rs : List Rect) (k : Laid),
      k ∈ arrangeList m c rs ss → Laid.Everywhere NoScroll k
theorem

Cairn.Layout.Node.scrollsList_of_forall

provedlean/Cairn/Layout/Bridge.lean:447
scrollsList_of_forall {ks : List Node} :
  (∀ (k : Node), k ∈ ks → k.scrolls = false) → Node.scrollsList ks = false
theorem

Cairn.Layout.layout_noScroll

provedlean/Cairn/Layout/Bridge.lean:455
layout_noScroll (m : TextMetrics) (w : Size) {n : Node}
  (h : n.scrolls = false) : Laid.Everywhere NoScroll (layout m w n)

A view without scroll boxes lays out without them.

theorem

Cairn.Layout.rect_inside_clip

provedlean/Cairn/Layout/Bridge.lean:462
rect_inside_clip {l : Laid} (hE : Laid.Everywhere Good l)
  (hns : Laid.Everywhere NoScroll l) :
  l.rect.inside l.clip →
    ∀ (t : Runtime.Target), t ∈ Runtime.targetsOf l → t.node.rect.inside t.node.clip

In a tree where every node is Good, no box scrolls and the root is inside its clip, each control's rect is inside its clip. (Under a scroll box a control can be anywhere: only its visible part counts.)

theorem

Cairn.Layout.Rect.contains_inter

provedlean/Cairn/Layout/Bridge.lean:494
contains_inter {a b : Rect} {p : Point} (ha : a.contains p = true)
  (hb : b.contains p = true) : (a.inter b).contains p = true
theorem

Cairn.Layout.Rect.nonempty_of_contains

provedlean/Cairn/Layout/Bridge.lean:499
nonempty_of_contains {r : Rect} {p : Point} (h : r.contains p = true) :
  r.nonempty
theorem

Cairn.Layout.hits_owner_visible

provedlean/Cairn/Layout/Bridge.lean:505
hits_owner_visible {l : Laid} (hE : Laid.Everywhere Good l)
  (o : Option Runtime.Target) (h : Runtime.Hit) (p : Point) :
  h ∈ Runtime.hitsOf o l →
    h.visible.contains p = true →
      h.owner = o ∨ ∃ t, h.owner = some t ∧ t.visible.contains p = true

Every hit entry in a subtree that contains p belongs to the owner handed down, or to a control whose visible part contains p.

theorem

Cairn.Layout.hitTarget_visible

provedlean/Cairn/Layout/Bridge.lean:543
hitTarget_visible {l : Laid} (hE : Laid.Everywhere Good l) {p : Point}
  {t : Runtime.Target} (h : Runtime.hitTarget l p = some t) : t.visible.contains p = true

In a tree where every node is Good, the hit test answers only with a control whose visible part contains the point.

theorem

Cairn.Layout.layout_good

provedlean/Cairn/Layout/Bridge.lean:558
layout_good {m : TextMetrics} {w : Size} {n : Node}
  (hp : Pressable w (layout m w n)) : Laid.Everywhere Good (layout m w n)
theorem

Cairn.Layout.reaches_of_pressable

provedlean/Cairn/Layout/Bridge.lean:566
reaches_of_pressable {m : TextMetrics} {w : Size} {n : Node}
  (hp : Pressable w (layout m w n)) {t : Runtime.Target}
  (ht : t ∈ Runtime.targets (layout m w n)) {p : Point} (hc : t.visible.contains p = true) :
  Runtime.Reaches (layout m w n) t p

Reaching, from layout. If the view is Pressable, a pointer at any point of a control's visible rect reaches that control.

theorem

Cairn.Layout.layoutFacts_of_pressable

provedlean/Cairn/Layout/Bridge.lean:575
layoutFacts_of_pressable {m : TextMetrics} {w : Size} {n : Node}
  (hp : Pressable w (layout m w n)) {t : Runtime.Target}
  (ht : t ∈ Runtime.targets (layout m w n)) (hne : t.visible.nonempty) :
  Runtime.LayoutFacts (layout m w n) t

The bridge. If the view is Pressable, every control whose visible part (rect ∩ clip) is nonempty satisfies the runtime's LayoutFacts: a pointer at the centre of its visible part reaches it. So Cairn.Runtime.hitTest_center and click_center_presses apply. A control under a scroll box may be partly or wholly scrolled out: it is pressed at the centre of what shows.

theorem

Cairn.Layout.hitTest_center_of_pressable

provedlean/Cairn/Layout/Bridge.lean:581
hitTest_center_of_pressable {m : TextMetrics} {w : Size} {n : Node}
  (hp : Pressable w (layout m w n)) {t : Runtime.Target}
  (ht : t ∈ Runtime.targets (layout m w n)) (hne : t.visible.nonempty) :
  Runtime.hitTest (layout m w n) t.visible.center = some t.control

And so hit testing at the centre of such a control's visible part returns it.

theorem

Cairn.Layout.not_hit_of_hidden

provedlean/Cairn/Layout/Bridge.lean:589
not_hit_of_hidden {m : TextMetrics} {w : Size} {n : Node}
  (hp : Pressable w (layout m w n)) {t : Runtime.Target} (hne : ¬t.visible.nonempty)
  (p : Point) : Runtime.hitTarget (layout m w n) p ≠ some t

Nothing hits what doesn't show. If the view is Pressable, a control whose visible part is empty (scrolled wholly out of its scroll box, say) is the hit at no point.

theorem

Cairn.Layout.visible_eq_rect

provedlean/Cairn/Layout/Bridge.lean:596
visible_eq_rect {m : TextMetrics} {w : Size} {n : Node}
  (hp : Pressable w (layout m w n)) (hns : Laid.Everywhere NoScroll (layout m w n))
  {t : Runtime.Target} (ht : t ∈ Runtime.targets (layout m w n)) : t.visible = t.node.rect

Without scroll boxes, a control's visible part is its whole rect: the root is in the window and every child is inside its parent.