Cairn · module

Cairn.Layout.Proofs

lean/Cairn/Layout/Proofs.lean

Layout theorems

The headline is Cairn.Layout.facts: for every valid metrics, window and view, layout satisfies Facts. The pieces:

Each local fact is proved for a single arrange step and lifted to the whole tree by arrange_everywhere, the one induction over the nested Sized tree.

Imports Cairn.Layout.Facts

Order

Definitions 7

def

Cairn.Layout.Sized.controls

lean/Cairn/Layout/Proofs.lean:23
controls : Sized → List Control
def

Cairn.Layout.Sized.controlsList

lean/Cairn/Layout/Proofs.lean:27
controlsList : List Sized → List Control
def

Cairn.Layout.mainStart

lean/Cairn/Layout/Proofs.lean:304
mainStart (h : Bool) (r : Rect) : Int

Start of a rect along the main axis.

def

Cairn.Layout.mainPairs

lean/Cairn/Layout/Proofs.lean:529
mainPairs (h : Bool) (its : List Item) (rs : List Rect) : List (Sizing × Int)

Each child's main-axis sizing paired with its main-axis length.

def

Cairn.Layout.crossStart

lean/Cairn/Layout/Proofs.lean:714
crossStart (h : Bool) (r : Rect) : Int

Start and length of a rect across the main axis.

def

Cairn.Layout.crossOf

lean/Cairn/Layout/Proofs.lean:715
crossOf (h : Bool) (r : Rect) : Int
def

Cairn.Layout.spSum

lean/Cairn/Layout/Proofs.lean:728
spSum (sp : Nat → Int) : Nat → Nat → Int

sp i + sp (i+1) + … + sp (i+n-1).

Theorems 117

theorem

Cairn.Layout.paraLines_controls

provedlean/Cairn/Layout/Proofs.lean:33
paraLines_controls (m : TextMetrics) (ts : TextStyle) (wr : Wrap) (aw : Int)
  (s : String) : Sized.controlsList (paraLines m ts wr aw s) = []

A wrapped text's lines are text, so they have no controls.

theorem

Cairn.Layout.measure_controls

provedlean/Cairn/Layout/Proofs.lean:43
measure_controls (m : TextMetrics) (aw : Int) (n : Node) :
  (measure m aw n).controls = n.controls
theorem

Cairn.Layout.measureList_controls

provedlean/Cairn/Layout/Proofs.lean:51
measureList_controls (m : TextMetrics) (aw : Int) (ns : List Node) :
  Sized.controlsList (measureList m aw ns) = Node.controlsList ns
theorem

Cairn.Layout.arrange_controls

provedlean/Cairn/Layout/Proofs.lean:60
arrange_controls (m : TextMetrics) (s : Sized) (c r : Rect) :
  (arrange m c r s).controls = s.controls
theorem

Cairn.Layout.arrangeList_controls

provedlean/Cairn/Layout/Proofs.lean:66
arrangeList_controls (m : TextMetrics) (ss : List Sized) (c : Rect)
  (rs : List Rect) : Laid.controlsList (arrangeList m c rs ss) = Sized.controlsList ss
theorem

Cairn.Layout.layout_controls

provedlean/Cairn/Layout/Proofs.lean:80
layout_controls (m : TextMetrics) (w : Size) (n : Node) :
  (layout m w n).controls = n.controls

Controls preserved. The controls of the laid-out tree, in paint order, are exactly the controls of the view: none lost, none invented, none reordered.

theorem

Cairn.Layout.arrange_rect

provedlean/Cairn/Layout/Proofs.lean:86
arrange_rect (m : TextMetrics) (c r : Rect) (s : Sized) :
  (arrange m c r s).rect = r
theorem

Cairn.Layout.arrange_clip

provedlean/Cairn/Layout/Proofs.lean:90
arrange_clip (m : TextMetrics) (c r : Rect) (s : Sized) :
  (arrange m c r s).clip = c
theorem

Cairn.Layout.arrange_sizings

provedlean/Cairn/Layout/Proofs.lean:94
arrange_sizings (m : TextMetrics) (c r : Rect) (s : Sized) :
  (arrange m c r s).sizings = s.sizings
theorem

Cairn.Layout.arrange_children_box

provedlean/Cairn/Layout/Proofs.lean:98
arrange_children_box (m : TextMetrics) (c r : Rect) (st : Style)
  (ctl : Option Control) (sz : Size) (kids : List Sized) :
  (arrange m c r (Sized.box st ctl sz kids)).children =
    arrangeList m (innerClip st c r) (childRects st r (List.map Sized.item kids)) kids
theorem

Cairn.Layout.arrange_children_nil

provedlean/Cairn/Layout/Proofs.lean:104
arrange_children_nil (m : TextMetrics) (c r : Rect) (s : Sized)
  (h :
    ∀ (st : Style) (ctl : Option Control) (sz : Size) (kids : List Sized),
      s ≠ Sized.box st ctl sz kids) :
  (arrange m c r s).children = []
theorem

Cairn.Layout.arrangeList_clip

provedlean/Cairn/Layout/Proofs.lean:111
arrangeList_clip (m : TextMetrics) (c : Rect) (rs : List Rect)
  (ss : List Sized) (k : Laid) : k ∈ arrangeList m c rs ss → k.clip = c
theorem

Cairn.Layout.arrangeList_length

provedlean/Cairn/Layout/Proofs.lean:125
arrangeList_length (m : TextMetrics) (c : Rect) (rs : List Rect)
  (ss : List Sized) : (arrangeList m c rs ss).length = ss.length
theorem

Cairn.Layout.arrangeList_map

provedlean/Cairn/Layout/Proofs.lean:132
arrangeList_map {α : Type} (m : TextMetrics) (c : Rect)
  (g : Sizing × Sizing → Rect → α) (rs : List Rect) (ss : List Sized) :
  rs.length = ss.length →
    List.map (fun k => g k.sizings k.rect) (arrangeList m c rs ss) =
      List.zipWith (fun s r => g s.sizings r) ss rs

With one rect per child, each child lands in its rect.

theorem

Cairn.Layout.arrangeList_rects

provedlean/Cairn/Layout/Proofs.lean:149
arrangeList_rects (m : TextMetrics) (c : Rect) (rs : List Rect)
  (ss : List Sized) (h : rs.length = ss.length) :
  List.map Laid.rect (arrangeList m c rs ss) = rs
theorem

Cairn.Layout.arrange_everywhere

provedlean/Cairn/Layout/Proofs.lean:170
arrange_everywhere (m : TextMetrics) (P : Laid → Prop) (Q : Rect → Rect → Prop)
  (H :
    ∀ (c r : Rect) (s : Sized),
      Q c r →
        P (arrange m c r s) ∧
          ∀ (k : Laid), k ∈ (arrange m c r s).children → Q k.clip k.rect)
  (s : Sized) (c r : Rect) : Q c r → Laid.Everywhere P (arrange m c r s)

The one induction over the tree. If every arrange step whose clip and rect satisfy Q satisfies P and hands its children clips and rects satisfying Q, then P holds at every node.

theorem

Cairn.Layout.arrangeList_everywhere

provedlean/Cairn/Layout/Proofs.lean:182
arrangeList_everywhere (m : TextMetrics) (P : Laid → Prop)
  (Q : Rect → Rect → Prop)
  (H :
    ∀ (c r : Rect) (s : Sized),
      Q c r →
        P (arrange m c r s) ∧
          ∀ (k : Laid), k ∈ (arrange m c r s).children → Q k.clip k.rect)
  (ss : List Sized) (c : Rect) (rs : List Rect) :
  (∀ (k : Laid), k ∈ arrangeList m c rs ss → Q k.clip k.rect) →
    ∀ (k : Laid), k ∈ arrangeList m c rs ss → Laid.Everywhere P k
theorem

Cairn.Layout.arrange_everywhere'

provedlean/Cairn/Layout/Proofs.lean:199
arrange_everywhere' (m : TextMetrics) (P : Laid → Prop)
  (H : ∀ (c r : Rect) (s : Sized), P (arrange m c r s)) (s : Sized) (c r : Rect) :
  Laid.Everywhere P (arrange m c r s)

The unconditional case.

theorem

Cairn.Layout.Rect.inside_refl

provedlean/Cairn/Layout/Proofs.lean:208
inside_refl (r : Rect) : r.inside r
theorem

Cairn.Layout.Rect.inside_trans

provedlean/Cairn/Layout/Proofs.lean:211
inside_trans {a b c : Rect} (hab : a.inside b) (hbc : b.inside c) :
  a.inside c
theorem

Cairn.Layout.Rect.inter_inside

provedlean/Cairn/Layout/Proofs.lean:214
inter_inside {a : Rect} (b : Rect) (hw : 0 ≤ a.w) (hh : 0 ≤ a.h) :
  (a.inter b).inside a
theorem

Cairn.Layout.Rect.inter_nonneg

provedlean/Cairn/Layout/Proofs.lean:218
inter_nonneg (a b : Rect) : 0 ≤ (a.inter b).w ∧ 0 ≤ (a.inter b).h
theorem

Cairn.Layout.arrange_childClips

provedlean/Cairn/Layout/Proofs.lean:221
arrange_childClips (m : TextMetrics) (c r : Rect) (s : Sized) :
  ChildClips (arrange m c r s)
theorem

Cairn.Layout.arrange_clipInside

provedlean/Cairn/Layout/Proofs.lean:232
arrange_clipInside (m : TextMetrics) (c r : Rect) (s : Sized) (hw : 0 ≤ c.w)
  (hh : 0 ≤ c.h) :
  ClipInside (arrange m c r s) ∧
    ∀ (k : Laid), k ∈ (arrange m c r s).children → 0 ≤ k.clip.w ∧ 0 ≤ k.clip.h
theorem

Cairn.Layout.windowRect_nonneg

provedlean/Cairn/Layout/Proofs.lean:246
windowRect_nonneg (w : Size) : 0 ≤ (windowRect w).w ∧ 0 ≤ (windowRect w).h
theorem

Cairn.Layout.layout_childClips

provedlean/Cairn/Layout/Proofs.lean:249
layout_childClips (m : TextMetrics) (w : Size) (n : Node) :
  Laid.Everywhere ChildClips (layout m w n)
theorem

Cairn.Layout.layout_clipInside

provedlean/Cairn/Layout/Proofs.lean:253
layout_clipInside (m : TextMetrics) (w : Size) (n : Node) :
  Laid.Everywhere ClipInside (layout m w n)
theorem

Cairn.Layout.layout_rootClip

provedlean/Cairn/Layout/Proofs.lean:258
layout_rootClip (m : TextMetrics) (w : Size) (n : Node) :
  (layout m w n).clip = windowRect w
theorem

Cairn.Layout.layout_rootOrigin

provedlean/Cairn/Layout/Proofs.lean:262
layout_rootOrigin (m : TextMetrics) (w : Size) (n : Node) :
  (layout m w n).rect.x = 0 ∧ (layout m w n).rect.y = 0
theorem

Cairn.Layout.cumShare_mono

provedlean/Cairn/Layout/Proofs.lean:268
cumShare_mono {L : Int} (hL : 0 ≤ L) (f : Nat) {a b : Nat} (hab : a ≤ b) :
  cumShare L f a ≤ cumShare L f b
theorem

Cairn.Layout.fillShare_nonneg

provedlean/Cairn/Layout/Proofs.lean:275
fillShare_nonneg {L : Int} (hL : 0 ≤ L) (f j : Nat) : 0 ≤ fillShare L f j
theorem

Cairn.Layout.resolve_nonneg

provedlean/Cairn/Layout/Proofs.lean:279
resolve_nonneg (s : Sizing) (x : Int) : 0 ≤ resolve s x
theorem

Cairn.Layout.mainBase_nonneg

provedlean/Cairn/Layout/Proofs.lean:282
mainBase_nonneg (s : Sizing) (p : Int) : 0 ≤ mainBase s p
theorem

Cairn.Layout.mainSize_nonneg

provedlean/Cairn/Layout/Proofs.lean:285
mainSize_nonneg (h : Bool) {L : Int} (hL : 0 ≤ L) (f j : Nat) (it : Item) :
  0 ≤ mainSize h L f j it
theorem

Cairn.Layout.crossPlace_nonneg

provedlean/Cairn/Layout/Proofs.lean:291
crossPlace_nonneg (al : Align) (c0 : Int) {cc : Int} (hc : 0 ≤ cc) (s : Sizing)
  (p : Int) (b : Bool) : 0 ≤ (crossPlace al c0 cc s p b).snd
theorem

Cairn.Layout.spacing_nonneg

provedlean/Cairn/Layout/Proofs.lean:295
spacing_nonneg (j : Align) (gap : Nat) (free : Int) (k i : Nat) :
  0 ≤ spacing j gap free k i
theorem

Cairn.Layout.mkRect_mainStart

provedlean/Cairn/Layout/Proofs.lean:306
mkRect_mainStart (h : Bool) (p s cp cs : Int) :
  mainStart h (mkRect h p s cp cs) = p
theorem

Cairn.Layout.mkRect_mainOf

provedlean/Cairn/Layout/Proofs.lean:309
mkRect_mainOf (h : Bool) (p s cp cs : Int) : mainOf h (mkRect h p s cp cs) = s
theorem

Cairn.Layout.mkRect_nonneg

provedlean/Cairn/Layout/Proofs.lean:312
mkRect_nonneg (h : Bool) (p s cp cs : Int) (hs : 0 ≤ s) (hcs : 0 ≤ cs) :
  0 ≤ (mkRect h p s cp cs).w ∧ 0 ≤ (mkRect h p s cp cs).h
theorem

Cairn.Layout.Line.go_length

provedlean/Cairn/Layout/Proofs.lean:316
go_length (ln : Line) (its : List Item) (i j : Nat) (pos : Int) :
  (ln.go i j pos its).length = its.length
theorem

Cairn.Layout.Line.go_nonneg

provedlean/Cairn/Layout/Proofs.lean:321
go_nonneg (ln : Line) (hL : 0 ≤ ln.L) (hcc : 0 ≤ ln.cc) (its : List Item)
  (i j : Nat) (pos : Int) (r : Rect) : r ∈ ln.go i j pos its → 0 ≤ r.w ∧ 0 ≤ r.h
theorem

Cairn.Layout.Line.go_lower

provedlean/Cairn/Layout/Proofs.lean:332
go_lower (ln : Line) (hL : 0 ≤ ln.L) (hsp : ∀ (i : Nat), 0 ≤ ln.spacing i)
  (its : List Item) (i j : Nat) (pos : Int) (r : Rect) :
  r ∈ ln.go i j pos its → pos ≤ mainStart ln.horiz r
theorem

Cairn.Layout.Line.go_pairwise

provedlean/Cairn/Layout/Proofs.lean:345
go_pairwise (ln : Line) (hL : 0 ≤ ln.L)
  (hsp : ∀ (i : Nat), 0 ≤ ln.spacing i) (its : List Item) (i j : Nat) (pos : Int) :
  List.Pairwise (fun a b => mainStart ln.horiz a + mainOf ln.horiz a ≤ mainStart ln.horiz b)
    (ln.go i j pos its)

Along the main axis, each child ends before every later child starts.

theorem

Cairn.Layout.disjoint_of_main

provedlean/Cairn/Layout/Proofs.lean:358
disjoint_of_main (h : Bool) {a b : Rect}
  (hab : mainStart h a + mainOf h a ≤ mainStart h b) : a.disjoint b
theorem

Cairn.Layout.leftover_nonneg

provedlean/Cairn/Layout/Proofs.lean:363
leftover_nonneg (h : Bool) (st : Style) (c : Rect) (items : List Item) :
  0 ≤ leftover h st c items
theorem

Cairn.Layout.lineRects_length

provedlean/Cairn/Layout/Proofs.lean:367
lineRects_length (h : Bool) (st : Style) (c : Rect) (items : List Item) :
  (lineRects h st c items).length = items.length
theorem

Cairn.Layout.lineRects_nonneg

provedlean/Cairn/Layout/Proofs.lean:371
lineRects_nonneg (h : Bool) (st : Style) (c : Rect) (items : List Item)
  (r : Rect) : r ∈ lineRects h st c items → 0 ≤ r.w ∧ 0 ≤ r.h
theorem

Cairn.Layout.lineRects_pairwise

provedlean/Cairn/Layout/Proofs.lean:375
lineRects_pairwise (h : Bool) (st : Style) (c : Rect) (items : List Item) :
  List.Pairwise (fun a b => a.disjoint b) (lineRects h st c items)
theorem

Cairn.Rect.scrollBy_w

provedlean/Cairn/Layout/Proofs.lean:382
scrollBy_w (h : Bool) (o : Int) (q : Rect) : (scrollBy h o q).w = q.w
theorem

Cairn.Rect.scrollBy_h

provedlean/Cairn/Layout/Proofs.lean:386
scrollBy_h (h : Bool) (o : Int) (q : Rect) : (scrollBy h o q).h = q.h
theorem

Cairn.Layout.mainOf_scrollBy

provedlean/Cairn/Layout/Proofs.lean:390
mainOf_scrollBy (h h' : Bool) (o : Int) (q : Rect) :
  mainOf h (Rect.scrollBy h' o q) = mainOf h q
theorem

Cairn.Rect.scrollBy_disjoint

provedlean/Cairn/Layout/Proofs.lean:394
scrollBy_disjoint (h : Bool) (o : Int) {a b : Rect} (hd : a.disjoint b) :
  (scrollBy h o a).disjoint (scrollBy h o b)
theorem

Cairn.Layout.scrolled_length

provedlean/Cairn/Layout/Proofs.lean:399
scrolled_length (st : Style) (rs : List Rect) :
  (scrolled st rs).length = rs.length
theorem

Cairn.Layout.mem_scrolled

provedlean/Cairn/Layout/Proofs.lean:402
mem_scrolled {st : Style} {rs : List Rect} {q : Rect}
  (hq : q ∈ scrolled st rs) : ∃ q', q' ∈ rs ∧ q.w = q'.w ∧ q.h = q'.h
theorem

Cairn.Layout.scrolled_pairwise

provedlean/Cairn/Layout/Proofs.lean:409
scrolled_pairwise (st : Style) {rs : List Rect}
  (h : List.Pairwise (fun a b => a.disjoint b) rs) :
  List.Pairwise (fun a b => a.disjoint b) (scrolled st rs)
theorem

Cairn.Layout.scrolled_none

provedlean/Cairn/Layout/Proofs.lean:416
scrolled_none {st : Style} (h : st.scroll = none) (rs : List Rect) :
  scrolled st rs = rs
theorem

Cairn.Layout.map_mainOf_scrolled

provedlean/Cairn/Layout/Proofs.lean:420
map_mainOf_scrolled (h : Bool) (st : Style) (rs : List Rect) :
  List.map (mainOf h) (scrolled st rs) = List.map (mainOf h) rs
theorem

Cairn.Layout.placeRects_length

provedlean/Cairn/Layout/Proofs.lean:426
placeRects_length (st : Style) (r : Rect) (items : List Item) :
  (placeRects st r items).length = items.length
theorem

Cairn.Layout.childRects_length

provedlean/Cairn/Layout/Proofs.lean:430
childRects_length (st : Style) (r : Rect) (items : List Item) :
  (childRects st r items).length = items.length
theorem

Cairn.Layout.placeRects_nonneg

provedlean/Cairn/Layout/Proofs.lean:434
placeRects_nonneg (st : Style) (r : Rect) (items : List Item) (q : Rect) :
  q ∈ placeRects st r items → 0 ≤ q.w ∧ 0 ≤ q.h
theorem

Cairn.Layout.childRects_nonneg

provedlean/Cairn/Layout/Proofs.lean:444
childRects_nonneg (st : Style) (r : Rect) (items : List Item) (q : Rect) :
  q ∈ childRects st r items → 0 ≤ q.w ∧ 0 ≤ q.h
theorem

Cairn.Layout.placeRects_line

provedlean/Cairn/Layout/Proofs.lean:450
placeRects_line (st : Style) (r : Rect) (items : List Item)
  (hax : st.axis ≠ Axis.stack) :
  placeRects st r items = lineRects (Axis.horiz st.axis) st (r.inset st.padding) items
theorem

Cairn.Layout.childRects_pairwise

provedlean/Cairn/Layout/Proofs.lean:455
childRects_pairwise (st : Style) (r : Rect) (items : List Item)
  (hax : st.axis ≠ Axis.stack) :
  List.Pairwise (fun a b => a.disjoint b) (childRects st r items)
theorem

Cairn.Layout.kid_rect_mem

provedlean/Cairn/Layout/Proofs.lean:462
kid_rect_mem {m : TextMetrics} {c : Rect} {rs : List Rect} {ss : List Sized}
  (h : rs.length = ss.length) {k : Laid} (hk : k ∈ arrangeList m c rs ss) : k.rect ∈ rs
theorem

Cairn.Layout.arrange_rectNonneg

provedlean/Cairn/Layout/Proofs.lean:467
arrange_rectNonneg (m : TextMetrics) (c r : Rect) (s : Sized) (hw : 0 ≤ r.w)
  (hh : 0 ≤ r.h) :
  RectNonneg (arrange m c r s) ∧
    ∀ (k : Laid), k ∈ (arrange m c r s).children → 0 ≤ k.rect.w ∧ 0 ≤ k.rect.h
theorem

Cairn.Layout.measure_size_nonneg

provedlean/Cairn/Layout/Proofs.lean:479
measure_size_nonneg (m : TextMetrics) (aw : Int) (n : Node) :
  0 ≤ (measure m aw n).size.w ∧ 0 ≤ (measure m aw n).size.h
theorem

Cairn.Layout.layout_rectNonneg

provedlean/Cairn/Layout/Proofs.lean:484
layout_rectNonneg (m : TextMetrics) (w : Size) (n : Node) :
  Laid.Everywhere RectNonneg (layout m w n)
theorem

Cairn.Layout.arrange_siblingsDisjoint

provedlean/Cairn/Layout/Proofs.lean:495
arrange_siblingsDisjoint (m : TextMetrics) (c r : Rect) (s : Sized) :
  SiblingsDisjoint (arrange m c r s)
theorem

Cairn.Layout.layout_siblingsDisjoint

provedlean/Cairn/Layout/Proofs.lean:511
layout_siblingsDisjoint (m : TextMetrics) (w : Size) (n : Node) :
  Laid.Everywhere SiblingsDisjoint (layout m w n)

Siblings disjoint. In every row and column of the laid-out tree, distinct children's rects are disjoint (earlier children end before later ones start on the main axis).

theorem

Cairn.Layout.SiblingsDisjoint.get

provedlean/Cairn/Layout/Proofs.lean:516
get {r c : Rect} {st : Style} {ctl : Option Control}
  {kids : List Laid} (h : SiblingsDisjoint (Laid.box r c st ctl kids))
  (hax : st.axis ≠ Axis.stack) {i j : Nat} (hi : i < kids.length) (hj : j < kids.length)
  (hij : i ≠ j) : kids[i].rect.disjoint kids[j].rect

The index form: children i ≠ j of a row or column have disjoint rects.

theorem

Cairn.Layout.Line.go_fill

provedlean/Cairn/Layout/Proofs.lean:532
go_fill (ln : Line) (its : List Item) (i j : Nat) (pos : Int) :
  (List.map (fun x => x.snd)
          (List.filter (fun x => !x.fst.isFill)
            (mainPairs ln.horiz its (ln.go i j pos its)))).sum =
      baseSum ln.horiz its ∧
    (List.map (fun x => x.snd) (mainPairs ln.horiz its (ln.go i j pos its))).sum =
        baseSum ln.horiz its +
          (cumShare ln.L ln.f (j + fillCount ln.horiz its) - cumShare ln.L ln.f j) ∧
      (((mainPairs ln.horiz its (ln.go i j pos its)).any fun x => x.fst.isFill) = true →
        0 < fillCount ln.horiz its)
theorem

Cairn.Layout.cumShare_full

provedlean/Cairn/Layout/Proofs.lean:573
cumShare_full (L : Int) {f : Nat} (hf : 0 < f) : cumShare L f f = L
theorem

Cairn.Layout.cumShare_zero

provedlean/Cairn/Layout/Proofs.lean:576
cumShare_zero (L : Int) (f : Nat) : cumShare L f 0 = 0
theorem

Cairn.Layout.lineRects_fill

provedlean/Cairn/Layout/Proofs.lean:580
lineRects_fill (h : Bool) (st : Style) (c : Rect) (items : List Item)
  (hany : ((mainPairs h items (lineRects h st c items)).any fun x => x.fst.isFill) = true)
  (hle :
    (List.map (fun x => x.snd)
            (List.filter (fun x => !x.fst.isFill)
              (mainPairs h items (lineRects h st c items)))).sum +
        gaps st.gap items.length ≤
      mainOf h c) :
  (List.map (fun x => x.snd) (mainPairs h items (lineRects h st c items))).sum +
      gaps st.gap items.length =
    mainOf h c

Fill exactness for one line, in terms of its content box.

theorem

Cairn.Layout.mainOf_inset

provedlean/Cairn/Layout/Proofs.lean:597
mainOf_inset (h : Bool) (r : Rect) (p : Insets) :
  mainOf h (r.inset p) = mainOf h r - padMain h p
theorem

Cairn.Layout.arrange_fillExact

provedlean/Cairn/Layout/Proofs.lean:601
arrange_fillExact (m : TextMetrics) (c r : Rect) (s : Sized) :
  FillExact (arrange m c r s)
theorem

Cairn.Layout.layout_fillExact

provedlean/Cairn/Layout/Proofs.lean:640
layout_fillExact (m : TextMetrics) (w : Size) (n : Node) :
  Laid.Everywhere FillExact (layout m w n)

Fill exactness. In every row and column of the laid-out tree with a fill child, if the other children, gaps and padding fit, then children, gaps and padding span the parent exactly along the main axis.

theorem

Cairn.Layout.offAt_eq

provedlean/Cairn/Layout/Proofs.lean:646
offAt_eq (offs : Array Int) {i : Nat} (h : i < offs.size) :
  offAt offs i = offs[i]
theorem

Cairn.Layout.offAt_bounds

provedlean/Cairn/Layout/Proofs.lean:650
offAt_bounds {m : TextMetrics} (hm : m.Valid) (f : Font) (s : String)
  (i : Nat) : 0 ≤ offAt (m.offsets f s) i ∧ offAt (m.offsets f s) i ≤ m.width f s

Under valid metrics every caret offset lies between 0 and the text's width.

theorem

Cairn.Layout.arrange_caretPlaced

provedlean/Cairn/Layout/Proofs.lean:673
arrange_caretPlaced {m : TextMetrics} (hm : m.Valid) (c r : Rect) (s : Sized) :
  CaretPlaced m (arrange m c r s)
theorem

Cairn.Layout.layout_caretPlaced

provedlean/Cairn/Layout/Proofs.lean:691
layout_caretPlaced {m : TextMetrics} (hm : m.Valid) (w : Size) (n : Node) :
  Laid.Everywhere (CaretPlaced m) (layout m w n)

Caret placement. In every field of the laid-out tree, the caret's x is the text origin plus the caret's offset, lies within the text's extent, and lies inside the content box whenever the box is at least a point wide; the selection runs between the offsets of its ends.

theorem

Cairn.TextMetrics.mono_valid

provedlean/Cairn/Layout/Proofs.lean:697
mono_valid : mono.Valid
theorem

Cairn.Layout.mkRect_crossStart

provedlean/Cairn/Layout/Proofs.lean:717
mkRect_crossStart (h : Bool) (p s cp cs : Int) :
  crossStart h (mkRect h p s cp cs) = cp
theorem

Cairn.Layout.mkRect_crossOf

provedlean/Cairn/Layout/Proofs.lean:720
mkRect_crossOf (h : Bool) (p s cp cs : Int) :
  crossOf h (mkRect h p s cp cs) = cs
theorem

Cairn.Layout.crossOf_scrollBy

provedlean/Cairn/Layout/Proofs.lean:723
crossOf_scrollBy (h h' : Bool) (o : Int) (q : Rect) :
  crossOf h (Rect.scrollBy h' o q) = crossOf h q
theorem

Cairn.Layout.spSum_nonneg

provedlean/Cairn/Layout/Proofs.lean:732
spSum_nonneg (sp : Nat → Int) (hsp : ∀ (i : Nat), 0 ≤ sp i) (i n : Nat) :
  0 ≤ spSum sp i n
theorem

Cairn.Layout.spSum_const

provedlean/Cairn/Layout/Proofs.lean:737
spSum_const (sp : Nat → Int) (g : Nat) (hsp : ∀ (i : Nat), sp i = ↑g)
  (i n : Nat) : spSum sp i n = ↑(g * n)
theorem

Cairn.Layout.spSum_tele

provedlean/Cairn/Layout/Proofs.lean:744
spSum_tele (sp : Nat → Int) (g : Nat) (F : Nat → Int)
  (hsp : ∀ (i : Nat), sp i = ↑g + (F (i + 1) - F i)) (i n : Nat) :
  spSum sp i n = ↑(g * n) + (F (i + n) - F i)
theorem

Cairn.Layout.sum_nonneg

provedlean/Cairn/Layout/Proofs.lean:754
sum_nonneg (l : List Int) (h : ∀ (x : Int), x ∈ l → 0 ≤ x) : 0 ≤ l.sum
theorem

Cairn.Layout.Line.go_mainOf_nonneg

provedlean/Cairn/Layout/Proofs.lean:761
go_mainOf_nonneg (ln : Line) (hL : 0 ≤ ln.L) (its : List Item) (i j : Nat)
  (pos : Int) : 0 ≤ (List.map (mainOf ln.horiz) (ln.go i j pos its)).sum
theorem

Cairn.Layout.Line.go_upper

provedlean/Cairn/Layout/Proofs.lean:777
go_upper (ln : Line) (hL : 0 ≤ ln.L) (hsp : ∀ (i : Nat), 0 ≤ ln.spacing i)
  (its : List Item) (i j : Nat) (pos : Int) (r : Rect) :
  r ∈ ln.go i j pos its →
    mainStart ln.horiz r + mainOf ln.horiz r ≤
      pos + (List.map (mainOf ln.horiz) (ln.go i j pos its)).sum +
        spSum ln.spacing i (its.length - 1)

Along the main axis, every child ends by the start plus all lengths and spacings.

theorem

Cairn.Layout.crossPlace_inside

provedlean/Cairn/Layout/Proofs.lean:800
crossPlace_inside (al : Align) (c0 cc : Int) (s : Sizing) (p : Int) (b : Bool)
  (h : (crossPlace al c0 cc s p b).snd ≤ cc) :
  c0 ≤ (crossPlace al c0 cc s p b).fst ∧
    (crossPlace al c0 cc s p b).fst + (crossPlace al c0 cc s p b).snd ≤ c0 + cc
theorem

Cairn.Layout.Line.go_cross

provedlean/Cairn/Layout/Proofs.lean:806
go_cross (ln : Line) (its : List Item) (i j : Nat) (pos : Int)
  (r : Rect) :
  r ∈ ln.go i j pos its →
    crossOf ln.horiz r ≤ ln.cc →
      ln.c0 ≤ crossStart ln.horiz r ∧
        crossStart ln.horiz r + crossOf ln.horiz r ≤ ln.c0 + ln.cc
theorem

Cairn.Layout.mainPairs_snd

provedlean/Cairn/Layout/Proofs.lean:818
mainPairs_snd (h : Bool) (its : List Item) (rs : List Rect) :
  its.length = rs.length →
    List.map (fun x => x.snd) (mainPairs h its rs) = List.map (mainOf h) rs
theorem

Cairn.Layout.lineRects_sum

provedlean/Cairn/Layout/Proofs.lean:835
lineRects_sum (h : Bool) (st : Style) (c : Rect) (items : List Item) :
  (List.map (mainOf h) (lineRects h st c items)).sum =
    if fillCount h items = 0 then baseSum h items
    else baseSum h items + leftover h st c items

The children's main-axis lengths add up to the space the line uses.

theorem

Cairn.Layout.lineRects_inside

provedlean/Cairn/Layout/Proofs.lean:849
lineRects_inside (h : Bool) (st : Style) (c : Rect) (items : List Item)
  (hcross : ∀ (r : Rect), r ∈ lineRects h st c items → crossOf h r ≤ crossOf h c)
  (hfit :
    (List.map (mainOf h) (lineRects h st c items)).sum + gaps st.gap items.length ≤
      mainOf h c)
  (r : Rect) : r ∈ lineRects h st c items → r.inside c
theorem

Cairn.Layout.stackRects_inside

provedlean/Cairn/Layout/Proofs.lean:893
stackRects_inside (st : Style) (c : Rect) (items : List Item)
  (hfit : ∀ (r : Rect), r ∈ stackRects st c items → r.w ≤ c.w ∧ r.h ≤ c.h) (r : Rect) :
  r ∈ stackRects st c items → r.inside c
theorem

Cairn.Layout.arrange_childrenInside

provedlean/Cairn/Layout/Proofs.lean:907
arrange_childrenInside (m : TextMetrics) (c r : Rect) (s : Sized) :
  ChildrenInside (arrange m c r s)
theorem

Cairn.Layout.layout_childrenInside

provedlean/Cairn/Layout/Proofs.lean:949
layout_childrenInside (m : TextMetrics) (w : Size) (n : Node) :
  Laid.Everywhere ChildrenInside (layout m w n)

Children that fit stay inside. In every container of the laid-out tree, if the children fit the content box (in size, and along the main axis with gaps), each child's rect is inside it.

theorem

Cairn.Layout.placeRects_scroll

provedlean/Cairn/Layout/Proofs.lean:955
placeRects_scroll (st : Style) (s : Option Int) (r : Rect)
  (items : List Item) :
  placeRects
      { axis := st.axis, width := st.width, height := st.height, padding := st.padding,
        gap := st.gap, align := st.align, justify := st.justify,
        background := st.background, border := st.border, radius := st.radius,
        clip := st.clip, corner := st.corner, shadow := st.shadow, paint := st.paint,
        image := st.image, scroll := s, scrollRef := st.scrollRef, rows := st.rows,
        menu := st.menu }
      r items =
    placeRects st r items
theorem

Cairn.Layout.childRects_scroll

provedlean/Cairn/Layout/Proofs.lean:961
childRects_scroll {st : Style} {o : Int} (ho : st.scroll = some o) (r : Rect)
  (items : List Item) :
  childRects st r items =
    List.map (Rect.scrollBy (Axis.horiz st.axis) o)
      (childRects
        { axis := st.axis, width := st.width, height := st.height, padding := st.padding,
          gap := st.gap, align := st.align, justify := st.justify,
          background := st.background, border := st.border, radius := st.radius,
          clip := st.clip, corner := st.corner, shadow := st.shadow, paint := st.paint,
          image := st.image, scrollRef := st.scrollRef, rows := st.rows, menu := st.menu }
        r items)

A scroll box's children are where the same box without scroll puts them (placeRects: in a column, one under the other), moved back by the offset along the box's axis.

theorem

Cairn.Layout.arrange_scroll

provedlean/Cairn/Layout/Proofs.lean:970
arrange_scroll (m : TextMetrics) (c r : Rect) {st : Style}
  (ctl : Option Control) (sz : Size) (kids : List Sized) {o : Int}
  (ho : st.scroll = some o) :
  List.map Laid.rect (arrange m c r (Sized.box st ctl sz kids)).children =
    List.map (Rect.scrollBy (Axis.horiz st.axis) o)
      (List.map Laid.rect
        (arrange m c r
            (Sized.box
              { axis := st.axis, width := st.width, height := st.height,
                padding := st.padding, gap := st.gap, align := st.align,
                justify := st.justify, background := st.background, border := st.border,
                radius := st.radius, clip := st.clip, corner := st.corner,
                shadow := st.shadow, paint := st.paint, image := st.image,
                scrollRef := st.scrollRef, rows := st.rows, menu := st.menu }
              ctl sz kids)).children)

Scrolled children. Every child of a scroll box with offset o is laid at the rect the same box gives it when it doesn't scroll, moved back by o along the box's axis: in a column (or a stack), the same x, width and height, and y less o; in a row, x less o.

theorem

Cairn.Layout.measure_scroll

provedlean/Cairn/Layout/Proofs.lean:981
measure_scroll (m : TextMetrics) (aw : Int) (st : Style) (s : Option Int)
  (ctl : Option Control) (kids : List Node) :
  measure m aw
      (Node.box
        { axis := st.axis, width := st.width, height := st.height, padding := st.padding,
          gap := st.gap, align := st.align, justify := st.justify,
          background := st.background, border := st.border, radius := st.radius,
          clip := st.clip, corner := st.corner, shadow := st.shadow, paint := st.paint,
          image := st.image, scroll := s, scrollRef := st.scrollRef, rows := st.rows,
          menu := st.menu }
        ctl kids) =
    Sized.box
      { axis := st.axis, width := st.width, height := st.height, padding := st.padding,
        gap := st.gap, align := st.align, justify := st.justify,
        background := st.background, border := st.border, radius := st.radius,
        clip := st.clip, corner := st.corner, shadow := st.shadow, paint := st.paint,
        image := st.image, scroll := s, scrollRef := st.scrollRef, rows := st.rows,
        menu := st.menu }
      ctl (measure m aw (Node.box st ctl kids)).size (measureList m (innerAvail st aw) kids)

Measuring doesn't read scroll: a box measures the same with any offset, or none.

theorem

Cairn.Layout.scrollBy_column

provedlean/Cairn/Layout/Proofs.lean:989
scrollBy_column (o : Int) (q : Rect) :
  Rect.scrollBy false o q = { x := q.x, y := q.y - o, w := q.w, h := q.h }

In a column, scrolling by o moves a rect up by o and changes nothing else.

theorem

Cairn.Laid.Everywhere.and

provedlean/Cairn/Layout/Proofs.lean:991
and {P Q : Laid → Prop} {l : Laid} (hp : Everywhere P l)
  (hq : Everywhere Q l) : Everywhere (fun x => P x ∧ Q x) l
theorem

Cairn.Laid.Everywhere.imp

provedlean/Cairn/Layout/Proofs.lean:997
imp {P Q : Laid → Prop} {l : Laid} (hp : Everywhere P l)
  (f : ∀ (x : Laid), P x → Q x) : Everywhere Q l
theorem

Cairn.Laid.Everywhere.tails

provedlean/Cairn/Layout/Proofs.lean:1003
tails {P : Laid → Prop} {l : Laid} (hp : Everywhere P l) :
  Everywhere (fun d => Everywhere P d) l

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

theorem

Cairn.Layout.Rect.inter_inside_of_nonempty

provedlean/Cairn/Layout/Proofs.lean:1008
inter_inside_of_nonempty {a b : Rect} (h : (a.inter b).nonempty) :
  (a.inter b).inside b
theorem

Cairn.Layout.Rect.nonempty_of_inside

provedlean/Cairn/Layout/Proofs.lean:1012
nonempty_of_inside {a b : Rect} (hi : a.inside b) (h : a.nonempty) :
  b.nonempty
theorem

Cairn.Layout.clip_inside_everywhere

provedlean/Cairn/Layout/Proofs.lean:1016
clip_inside_everywhere {R : Rect} {l : Laid}
  (hE : Laid.Everywhere ClipInside l) :
  l.clip.inside R → Laid.Everywhere (fun d => d.clip.inside R) l

Clips only shrink going down: below a node whose clip is inside R, every clip is.

theorem

Cairn.Layout.visible_inside_clip

provedlean/Cairn/Layout/Proofs.lean:1023
visible_inside_clip {d : Laid} (h : d.visible.nonempty) :
  d.visible.inside d.clip

A nonempty visible part lies inside the node's clip.

theorem

Cairn.Layout.clipContained_of

provedlean/Cairn/Layout/Proofs.lean:1026
clipContained_of {l : Laid} (hE : Laid.Everywhere ClipInside l)
  (hcc : ChildClips l) : ClipContained l
theorem

Cairn.Layout.layout_clipContained

provedlean/Cairn/Layout/Proofs.lean:1046
layout_clipContained (m : TextMetrics) (w : Size) (n : Node) :
  Laid.Everywhere ClipContained (layout m w n)

Clips hold what is under them. In every box of the laid-out tree that clips, so in every scroll box, every nonempty visible part of every node below it is inside the box's rect.

theorem

Cairn.Layout.facts

provedlean/Cairn/Layout/Proofs.lean:1055
facts {m : TextMetrics} (hm : m.Valid) (w : Size) (n : Node) :
  Facts m w n (layout m w n)

Layout facts. For valid metrics, every window and every view, layout satisfies all of Facts.

theorem

Cairn.Layout.measure_image

provedlean/Cairn/Layout/Proofs.lean:1074
measure_image (m : TextMetrics) (aw : Int) (i : Image) :
  (measure m aw (Node.image i)).size = { w := ↑i.width, h := ↑i.height }

An image's box doesn't depend on its state. Node.image measures at the size the app gave it whether it is loading, loaded at any pixel size, or failed, so nothing around it moves when the pixels arrive or the load fails.

theorem

Cairn.Layout.image_sizings

provedlean/Cairn/Layout/Proofs.lean:1079
image_sizings (m : TextMetrics) (aw : Int) (i : Image) :
  (measure m aw (Node.image i)).sizings = (Sizing.fixed i.width, Sizing.fixed i.height)

An image's size is fixed on both axes, so rows and columns never stretch or shrink it.

theorem

Cairn.Layout.controls_image

provedlean/Cairn/Layout/Proofs.lean:1084
controls_image (i : Image) : (Node.image i).controls = []

An image is no control, in any state.