package miaou-core
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Miaou core/widgets (no drivers, no SDL)
Install
dune-project
Dependency
Authors
Maintainers
Sources
v0.5.2.tar.gz
md5=60a3b9f181f24572a06a9492532bfdda
sha512=fcc35a275066be2900e6201782faf47503076fa4640f08cf78067835a6f447b74613009e55b2ac799adb7ca46f1bffa261fc5971753f2cc3c6bef327511c7ef6
doc/src/miaou_widgets_layout/spinner_widget.ml.html
Source file spinner_widget.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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157(*****************************************************************************) (* *) (* SPDX-License-Identifier: MIT *) (* Copyright (c) 2025 Nomadic Labs <contact@nomadic-labs.com> *) (* Copyright (c) 2026 Mathias Bourgoin <mathias.bourgoin@atacama.tech> *) (* *) (*****************************************************************************) module Clock = Miaou_interfaces.Clock (** Spinner style variants *) type style = | Dots (** Classic braille dot spinner: ⠋ ⠙ ⠹ ⠸ ... *) | Blocks (** Animated blocks with gradient: ■ ■ ■ ■ ■ ■ (moving highlight) *) (** Direction for block animation *) type direction = Left | Right (** Glyph style for blocks *) type glyph = Square | Circle | Dot (* State *) type t = { idx : int; label : string option; width : int; style : style; blocks_count : int; direction : direction; glyph : glyph; } let open_centered ?label ?(width = 60) ?(style = Dots) ?(blocks_count = 5) ?(direction = Right) ?(glyph = Square) () = { idx = 0; label; width; style; blocks_count = max 2 blocks_count; direction; glyph; } let tick t = {t with idx = t.idx + 1} let set_label t lbl = {t with label = lbl} let set_style t style = {t with style} (* Dots style frames *) let frames_dots_unicode = [|"⠋"; "⠙"; "⠹"; "⠸"; "⠼"; "⠴"; "⠦"; "⠧"; "⠇"; "⠏"|] let frames_dots_ascii = [|"|"; "/"; "-"; "\\"|] (* Legacy aliases for backward compatibility *) let frames_unicode = frames_dots_unicode let frames_ascii = frames_dots_ascii (* Frames per second for time-based animation *) let spinner_fps = 10.0 (** Compute the frame index. When the Clock capability is available the index is derived from elapsed wall-clock time so that the rotation speed is consistent regardless of TPS. Falls back to the counter-based [t.idx] otherwise. *) let frame_index t frame_count = match Clock.get () with | Some c -> let elapsed = c.elapsed () in int_of_float (elapsed *. spinner_fps) mod frame_count | None -> t.idx mod frame_count (** Color gradient for blocks - from bright to dim (blue tones) *) let gradient_colors = [|75; 68; 67; 60; 240|] (** Glyphs by size: large (lead), medium, small, tiny, dim *) let size_glyphs_square_unicode = [|"■"; "▪"; "•"; "·"; "·"|] let size_glyphs_circle_unicode = [|"●"; "○"; "•"; "·"; "·"|] let size_glyphs_dot_unicode = [|"•"; "∙"; "·"; "·"; "·"|] let size_glyphs_ascii = [|"#"; "o"; "."; "."; "."|] (** Render the blocks animation with gradient and size progression. Shows glyphs that shrink from the lead: ■ ▪ • · · The lead block is largest/brightest, trail gets smaller and dimmer. *) let render_blocks_glyph ~prefer_ascii ~blocks_count ~direction ~glyph frame_idx = let module W = Miaou_widgets_display.Widgets in let glyphs = if prefer_ascii then size_glyphs_ascii else match glyph with | Square -> size_glyphs_square_unicode | Circle -> size_glyphs_circle_unicode | Dot -> size_glyphs_dot_unicode in (* The highlight position moves across the blocks *) let highlight_pos = frame_idx mod blocks_count in let buf = Buffer.create (blocks_count * 8) in for i = 0 to blocks_count - 1 do (* Calculate distance from highlight, taking direction into account *) let pos = match direction with Right -> i | Left -> blocks_count - 1 - i in (* Distance considers the trail behind the highlight (wrapping) *) let raw_dist = let d = highlight_pos - pos in if d < 0 then d + blocks_count else d in (* Map distance to size and color *) let idx = min raw_dist (Array.length gradient_colors - 1) in let color = gradient_colors.(idx) in let char = glyphs.(min idx (Array.length glyphs - 1)) in Buffer.add_string buf (W.fg color char) done ; Buffer.contents buf let render_with_backend backend t = let prefer_ascii = Miaou_widgets_display.Widgets.prefer_ascii ~backend () in match t.style with | Blocks -> let frame_idx = frame_index t t.blocks_count in let blocks = render_blocks_glyph ~prefer_ascii ~blocks_count:t.blocks_count ~direction:t.direction ~glyph:t.glyph frame_idx in let label = match t.label with None -> "" | Some s -> " " ^ s in blocks ^ label | Dots -> let frames = if prefer_ascii then frames_ascii else frames_unicode in let frame_count = Array.length frames in let glyph = frames.(frame_index t frame_count) in let label = match t.label with None -> "" | Some s -> " " ^ s in let content = Printf.sprintf "%s%s" glyph label in let v = Miaou_helpers.Helpers.visible_chars_count content in if v <= t.width then content else let idx = Miaou_helpers.Helpers.visible_byte_index_of_pos content t.width in String.sub content 0 idx let render ?(backend : Miaou_widgets_display.Widgets.backend = Miaou_widgets_display.Widgets.get_backend ()) t = render_with_backend backend t let () = Miaou_registry.register ~name:"spinner" ~mli:[%blob "spinner_widget.mli"] ()
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>