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_navigation/tabs_widget.ml.html
Source file tabs_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(*****************************************************************************) (* *) (* SPDX-License-Identifier: MIT *) (* Copyright (c) 2025 Nomadic Labs <contact@nomadic-labs.com> *) (* *) (*****************************************************************************) [@@@warning "-32-34-37-69"] module W = Miaou_widgets_display.Widgets module Helpers = Miaou_helpers.Helpers type tab = {id : string; label : string} type t = {tabs : tab list; selected : int} let clamp idx len = if len = 0 then 0 else max 0 (min (len - 1) idx) let tab ~id ~label = {id; label} let id t = t.id let label t = t.label let make tabs = let tabs = List.filter (fun t -> String.length t.label > 0) tabs |> List.map (fun t -> {id = t.id; label = t.label}) in {tabs; selected = clamp 0 (List.length tabs)} let current t = match List.nth_opt t.tabs t.selected with Some x -> Some x | None -> None let move t dir = let len = List.length t.tabs in if len = 0 then t else let next = match dir with | `Left -> (t.selected - 1 + len) mod len | `Right -> (t.selected + 1) mod len | `First -> 0 | `Last -> len - 1 in {t with selected = next} let select t ~id = let rec find i = function | [] -> t.selected | x :: xs -> if String.equal x.id id then i else find (i + 1) xs in let len = List.length t.tabs in let idx = clamp (find 0 t.tabs) len in {t with selected = idx} let handle_event ?(bubble_unhandled = false) t ~key = match Miaou_core.Keys.of_string key with | Some Miaou_core.Keys.Left -> (move t `Left, `Handled) | Some Miaou_core.Keys.Right -> (move t `Right, `Handled) | Some Miaou_core.Keys.Home -> (move t `First, `Handled) | Some Miaou_core.Keys.End -> (move t `Last, `Handled) | _ -> ( (* Check for mouse click to select tab *) match Miaou_helpers.Mouse.parse_click key with | Some {col; _} -> ( (* Calculate which tab was clicked based on column position. Each tab is: " label " (padded) + "|" separator. Separator is 1 visible char. *) let rec find_tab idx pos tabs = match tabs with | [] -> None | tab :: rest -> let tab_width = String.length tab.label + 2 in (* " label " *) let sep_width = if rest = [] then 0 else 1 in (* "|" *) let total = tab_width + sep_width in if col >= pos && col < pos + tab_width then Some idx else find_tab (idx + 1) (pos + total) rest in match find_tab 0 1 t.tabs with | Some idx -> ({t with selected = idx}, `Handled) | None -> (t, if bubble_unhandled then `Bubble else `Handled)) | None -> (t, if bubble_unhandled then `Bubble else `Handled)) let handle_key t ~key = let t, _ = handle_event t ~key in t let render t ~focus = let pad s = if String.length s = 0 then s else Printf.sprintf " %s " s in let highlight s = if focus then W.bold s else s in let rendered = List.mapi (fun i tab -> if i = t.selected then highlight (pad tab.label) else W.dim (pad tab.label)) t.tabs in match rendered with | [] -> "" | _ -> Helpers.concat_with_sep (W.dim "|") rendered
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>