package oxbow

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file schemes.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
open! Oxbow_core

let rec subdivide ~pick (area : int Rect.canonical) k n =
  if n <= 1
  then [ area ]
  else (
    let win, rest =
      match pick k with
      | `Top ->
        let top = { area with h = max 1 (area.h / 2) } in
        top, { area with y = area.y + top.h; h = area.h - top.h }
      | `Bottom ->
        let bot = { area with h = max 1 (area.h / 2) } in
        { area with y = area.y + bot.h; h = area.h - bot.h }, bot
      | `Left ->
        let left = { area with w = max 1 (area.w / 2) } in
        left, { area with x = area.x + left.w; w = area.w - left.w }
      | `Right ->
        let right = { area with w = max 1 (area.w / 2) } in
        { area with x = area.x + right.w; w = area.w - right.w }, right
    in
    win :: subdivide ~pick rest (k + 1) (n - 1))
;;

let dwindle_pick k = if k mod 2 = 0 then `Top else `Left

let spiral_pick k =
  match k mod 4 with
  | 0 -> `Top
  | 1 -> `Right
  | 2 -> `Bottom
  | _ -> `Left
;;

let diminish_ratio = 0.6

let diminish_heights ~total n =
  let rec go remaining i =
    if i = n - 1
    then [ remaining ]
    else (
      let ideal = Float.of_int remaining *. diminish_ratio |> Int.of_float in
      let reserve = n - 1 - i in
      let h = max 1 (min ideal (remaining - reserve)) in
      h :: go (remaining - h) (i + 1))
  in
  if n <= 0 then [] else go total 0
;;

let column ~x ~w ~y heights =
  List.fold_left_map (fun y h -> y + h, Rect.{ x; y; w; h }) y heights |> snd
;;

let compute ~(params : Params.Tiling.t) ~(usable_area : int Rect.canonical) ~(count : int)
  =
  match count with
  | 0 -> []
  | n ->
    let tiled clients_for =
      let c_count = Int.max 0 (n - params.nmaster) in
      let m_count = Int.max 0 (n - c_count) in
      let w = usable_area.w in
      let mw =
        match m_count, c_count with
        | 0, _ -> 0
        | _, 0 -> w
        | _, _ -> Float.of_int w *. params.mfact |> Int.of_float
      in
      let mh = usable_area.h in
      let cw =
        match m_count, c_count with
        | _, 0 -> 0
        | 0, _ -> w
        | _, _ -> w - mw
      in
      let m_heights = Strip.split ~total:mh ~count:m_count in
      let masters = column ~x:usable_area.x ~w:mw ~y:usable_area.y m_heights in
      let c_area =
        Rect.{ x = usable_area.x + mw; y = usable_area.y; w = cw; h = usable_area.h }
      in
      let clients = clients_for ~c_area ~cw ~c_count in
      masters @ clients
    in
    (match params.scheme with
     | Monocle -> List.init n (fun _ -> usable_area)
     | Deck -> tiled @@ fun ~c_area ~cw:_ ~c_count -> List.init c_count (fun _ -> c_area)
     | Even ->
       tiled
       @@ fun ~c_area ~cw ~c_count ->
       Strip.split ~total:c_area.h ~count:c_count |> column ~x:c_area.x ~w:cw ~y:c_area.y
     | Diminish ->
       tiled
       @@ fun ~c_area ~cw ~c_count ->
       diminish_heights ~total:c_area.h c_count |> column ~x:c_area.x ~w:cw ~y:c_area.y
     | Dwindle ->
       tiled
       @@ fun ~c_area ~cw:_ ~c_count ->
       if c_count = 0 then [] else subdivide ~pick:dwindle_pick c_area 0 c_count
     | Spiral ->
       tiled
       @@ fun ~c_area ~cw:_ ~c_count ->
       if c_count = 0 then [] else subdivide ~pick:spiral_pick c_area 0 c_count)
;;