package tiny_appkits
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Application engines from scratch: a spreadsheet, rich text, paint, draw, CAD, editors and more
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.6.tar.gz
md5=7c636383d146d30ac6f2fa234a6253c8
sha512=c79f3823c5f8f57e5038eb640d487c61168b84aa07c61999d6622ef9fd0c890e2b03b4c6a7cdbbe9352a49e25dda00ac7bb14693cee8e3d7beeed251351a2af0
doc/src/tiny_appkits.appkit_sheet_view/Sheet_view.ml.html
Source file Sheet_view.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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137(* Claude Code * * Copyright (C) 2026 Yoann Padioleau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * (LGPL) as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. *) (* See Sheet_view.mli *) (*****************************************************************************) (* Types *) (*****************************************************************************) type geometry = { cols : int; rows : int; cell_w : float; cell_h : float; head_w : float; head_h : float; } let default = { cols = 5; rows = 7; cell_w = 104.; cell_h = 28.; head_w = 40.; head_h = 28. } let size g = (g.head_w +. (float_of_int g.cols *. g.cell_w), g.head_h +. (float_of_int g.rows *. g.cell_h)) (*****************************************************************************) (* Where a cell is *) (*****************************************************************************) let cell_box g (b : Widget.box) (col, row) : Widget.box = { Widget.x = Widget.left b +. g.head_w +. (g.cell_w *. (float_of_int col +. 0.5)); y = Widget.top b -. g.head_h -. (g.cell_h *. (float_of_int row +. 0.5)); w = g.cell_w; h = g.cell_h; } let cell_at g (b : Widget.box) (x, y) = let col = int_of_float (Float.floor ((x -. Widget.left b -. g.head_w) /. g.cell_w)) in let row = int_of_float (Float.floor ((Widget.top b -. g.head_h -. y) /. g.cell_h)) in if col >= 0 && col < g.cols && row >= 0 && row < g.rows then Some (col, row) else None (*****************************************************************************) (* Selections *) (*****************************************************************************) let corners ((c1, r1), (c2, r2)) = ((min c1 c2, min r1 r2), (max c1 c2, max r1 r2)) let cells_of selection = let (c1, r1), (c2, r2) = corners selection in List.concat (List.init (r2 - r1 + 1) (fun dr -> List.init (c2 - c1 + 1) (fun dc -> (c1 + dc, r1 + dr)))) let name_of selection = let a, b = corners selection in if a = b then Formula.name_of_cell a else Formula.name_of_cell a ^ ":" ^ Formula.name_of_cell b (*****************************************************************************) (* Drawing *) (*****************************************************************************) (* text where a spreadsheet puts it: numbers against the right edge, * everything else against the left -- VisiCalc's rule, and the reason * a column of figures reads as a column *) let text_in (th : Theme.t) (b : Widget.box) ~right s = let w = Widget.text_width ~size:th.text_size s in let x = if right then Widget.right b -. (th.padding /. 2.) -. (w /. 2.) else Widget.left b +. (th.padding /. 2.) +. (w /. 2.) in Widget.Text (th.text, { b with x; w; h = th.text_size }, s) (* the letters of a column, without the row number a cell's name carries *) let column_letters col = let name = Formula.name_of_cell (col, 0) in String.sub name 0 (String.length name - 1) let draw ?selection g (th : Theme.t) (b : Widget.box) sheet = (* claude: no selection is one outside the sheet, never lit, and no ring *) let shown = selection <> None in let selection = Option.value selection ~default:((-1, -1), (-1, -1)) in let (left_col, top_row), (right_col, bottom_row) = corners selection in let in_selection (c, r) = c >= left_col && c <= right_col && r >= top_row && r <= bottom_row in let head_box col : Widget.box = { (cell_box g b (col, 0)) with y = Widget.top b -. (g.head_h /. 2.); h = g.head_h } in let row_head_box row : Widget.box = { (cell_box g b (0, row)) with x = Widget.left b +. (g.head_w /. 2.); w = g.head_w } in [ Widget.Fill (th.field_face, b) ] @ List.concat (List.init g.cols (fun col -> let box = head_box col in [ Widget.Fill ((if col >= left_col && col <= right_col then th.face_hot else th.face), box); Look.text_at th box (column_letters col); ])) @ List.concat (List.init g.rows (fun row -> let box = row_head_box row in [ Widget.Fill ((if row >= top_row && row <= bottom_row then th.face_hot else th.face), box); Look.text_at th box (string_of_int (row + 1)); ])) @ List.concat (List.init g.rows (fun row -> List.concat (List.init g.cols (fun col -> let box = cell_box g b (col, row) in let v = Sheet.value sheet (col, row) in let number = match v with Sheet.Number _ -> true | _ -> false in let text = Sheet.show v in (* a selection of more than one cell is shaded; one cell is only ringed, below *) (if in_selection (col, row) && fst selection <> snd selection then [ Widget.Fill (th.face_hot, box) ] else []) @ Widget.frame (Color.rgb 225 225 220) 1. box @ if text = "" then [] else [ text_in th box ~right:number text ])))) (* the ring around the whole selection: one rectangle, however many cells it covers *) @ if not shown then [] else let a = cell_box g b (left_col, top_row) and z = cell_box g b (right_col, bottom_row) in Widget.frame th.accent 2. { Widget.x = (Widget.left a +. Widget.right z) /. 2.; y = (Widget.top a +. Widget.bottom z) /. 2.; w = Widget.right z -. Widget.left a; h = Widget.top a -. Widget.bottom z; }
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>