···44open Nottui_main
55open Lwd_infix
6677-(*------ Internal/Private----*)
88-module Internal = struct
99- let neutral_grav = Gravity.make ~h:`Neutral ~v:`Neutral
1010-1111- module W = Nottui_widgets
1212-1313- (** Truncate a string to a given length, adding an ellipsis if truncated. *)
1414- let truncate_string len str =
1515- if String.length str > len
1616- then if len <= 3 then "" else String.sub str 0 (len - 3) ^ "..."
1717- else str
1818- ;;
1919-2020- (** top border*)
2121- let outline_top attr w label =
2222- let chr x = I.uchar attr (Uchar.of_int x) 1 1 in
2323- let hbar = I.uchar attr (Uchar.of_int 0x2500) w 1
2424- and label = if label |> I.width > w - 2 then I.empty else label |> I.hpad 2 0
2525- and a, b = chr 0x256d, chr 0x256e in
2626- I.zcat [ label; I.hcat [ a; hbar; b ]; label ]
2727- ;;
2828-2929- (** bottom border*)
3030- let outline_bot attr w label =
3131- let chr x = I.uchar attr (Uchar.of_int x) 1 1 in
3232- let hbar = I.uchar attr (Uchar.of_int 0x2500) w 1 in
3333- let label =
3434- if label |> I.width > w - 2
3535- then I.empty
3636- else label |> I.hpad (w - (label |> I.width |> ( + ) 1)) 0
3737- in
3838- let c, d = chr 0x256f, chr 0x2570 in
3939- I.zcat [ label; I.hcat [ d; hbar; c ] ]
4040- ;;
4141-4242- let make_label max_width label_str =
4343- I.strf " %s " (truncate_string (max_width - 2) label_str)
4444- ;;
4545-4646- (** Internal function for rendering a border box with known dimensions and padding.*)
4747- let border_box_intern
4848- ?(border_attr = A.empty)
4949- ?(label_top = I.empty)
5050- ?(label_bottom = I.empty)
5151- ~w
5252- ~h
5353- ~pad
5454- ~pad_w
5555- ~pad_h
5656- input
5757- =
5858- (*can't go below 1 internal width or things get weird*)
5959- let h = if pad_h < 1 then Int.max h 1 else h in
6060- let w = if pad_w < 1 then Int.max w 1 else w in
6161- (* this is a weird quirk, but we have to be careful of runaway size expansion.
6262- If we increase the width of the space by making the vbar longer than the input ui element it will be able to expand to fill that space.
6363- That will then increase the vbar and increase the height etc etc untill the max height is reached*)
6464- let vbar =
6565- I.uchar border_attr (Uchar.of_int 0x2502) 1 (h + (pad_h * 2))
6666- |> Ui.atom
6767- |> Ui.resize ~h:0
6868- in
6969- Ui.vcat
7070- [ outline_top border_attr w label_top |> Ui.atom |> Ui.resize ~w:0
7171- ; Ui.hcat
7272- [ vbar
7373- ; I.void pad_w 1 |> Ui.atom
7474- ; Ui.vcat
7575- [ I.void 1 pad_h |> Ui.atom
7676- ; input |> Ui.resize ~pad
7777- ; I.void 1 pad_h |> Ui.atom
7878- ]
7979- ; I.void pad_w 1 |> Ui.atom
8080- ; vbar
8181- ]
8282- ; outline_bot border_attr w label_bottom |> Ui.atom |> Ui.resize ~w:0
8383- ]
8484- ;;
8585-end
8686-8787-open Internal
8888-897let with_border_attr
9090- ?(pad = neutral_grav)
88+ ?(pad = Gravity.make ~h:`Neutral ~v:`Neutral)
919 ?(pad_w = 2)
9210 ?(pad_h = 1)
9311 ?label_top
···9513 get_border
9614 input
9715 =
9898- let size = Lwd.var (0, 0) in
9999- let layout_width = Lwd.var 0 in
100100- let input =
101101- let$ input = input in
102102- (*We need this later to determine the max with*)
103103- layout_width $= (input |> Ui.layout_width);
104104- input
105105- (*This lets us tell the input to be a flexible size*)
106106- |> Ui.size_sensor (fun ~w ~h -> if Lwd.peek size <> (w, h) then Lwd.set size (w, h))
107107- in
108108- (*This is original width and height of the input before padding or anything *)
109109- let$ o_w, o_h = Lwd.get size
110110- and$ input = input
111111- and$ border_attr = get_border in
112112- let w, h = o_w + (pad_w * 2), o_h in
113113- let h = h in
114114- let bbox =
115115- border_box_intern
116116- ~border_attr
117117- ?label_top:(label_top |> Option.map (make_label (w - 2)))
118118- ?label_bottom:(label_bottom |> Option.map (make_label (w - 2)))
119119- (* ~label_bottom:(if has_focus then I.strf "focused" else I.strf "unfocused") *)
120120- ~w
121121- ~h
122122- ~pad
123123- ~pad_w
124124- ~pad_h
125125- input
126126- in
127127- (*If we want the input to be shrinkable we make it expandable, set it's width to something small and then set a max width for the whole box*)
128128- bbox
1616+ Lwd.map2 input get_border ~f:(fun ui attr ->
1717+ ui
1818+ |> Ui.resize ~pad
1919+ |> Ui.border ~pad_w ~pad_h ?label_top ?label_bottom ~attr)
12920;;
1302113122let focusable
13223 ?pad
133133- ?pad_w
134134- ?pad_h
2424+ ?(pad_w = 2)
2525+ ?(pad_h = 1)
13526 ?label_top
13627 ?label_bottom
13728 ?(border_attr = A.empty)
138138- ?(focus_attr = A.fg A.blue)
2929+ ?(focus_attr = (A.fg A.blue))
3030+ ?style
3131+ ?(focus_style=Ui.Border.unicode_bold)
13932 ?(focus = Focus.make ())
14033 ?(on_key = fun _ -> `Unhandled)
14134 input
14235 =
143143- let input =
144144- input
145145- |> Lwd.map2 (focus |> Focus.status) ~f:(fun focus ui ->
146146- ui |> Ui.keyboard_area ~focus on_key)
147147- in
148148- with_border_attr
149149- ?pad
150150- ?pad_w
151151- ?pad_h
152152- ?label_top
153153- ?label_bottom
154154- (let$ focus = Focus.status focus in
155155- if Focus.has_focus focus then focus_attr else border_attr)
156156- input
3636+ let focus_status = Focus.status focus in
3737+ let$ ui = input
3838+ and$ focus_status = Focus.status focus in
3939+ ui
4040+ |> Ui.keyboard_area ~focus:focus_status on_key
4141+ |> Ui.resize ?pad
4242+ |> Ui.border
4343+ ~pad_w
4444+ ~pad_h
4545+ ?label_top
4646+ ?label_bottom
4747+ ~attr:border_attr
4848+ ~focus_attr:(focus_attr)
4949+ ?style
5050+ ~focus_style
15751;;
15852159159-let box ?pad ?pad_w ?pad_h ?label_top ?label_bottom ?(border_attr = A.empty) input =
160160- with_border_attr
161161- ?pad
162162- ?pad_w
163163- ?pad_h
164164- ?label_top
165165- ?label_bottom
166166- (border_attr |> Lwd.pure)
167167- input
5353+let box
5454+ ?pad
5555+ ?pad_w
5656+ ?pad_h
5757+ ?label_top
5858+ ?label_bottom
5959+ ?(border_attr = A.empty)
6060+ ?focus_attr
6161+ ?style
6262+ ?focus_style
6363+ input
6464+ =
6565+ Lwd.map input ~f:(fun ui ->
6666+ ui
6767+ |> Ui.resize ?pad
6868+ |> Ui.border
6969+ ?pad_w
7070+ ?pad_h
7171+ ?label_top
7272+ ?label_bottom
7373+ ~attr:border_attr
7474+ ?focus_attr
7575+ ?style
7676+ ?focus_style)
16877;;
1697817079let static
171171- ?(pad = neutral_grav)
8080+ ?(pad = Gravity.make ~h:`Neutral ~v:`Neutral)
17281 ?(pad_w = 2)
17382 ?(pad_h = 1)
17483 ?label_top
···17685 ?(border_attr = A.empty)
17786 ui
17887 =
179179- let Ui.{ w; h; _ } = Ui.layout_spec ui in
180180- Internal.border_box_intern
181181- ~w
182182- ~h
183183- ~pad
184184- ~pad_w
185185- ~pad_h
186186- ?label_top
187187- ?label_bottom
188188- ~border_attr
189189- ui
8888+ ui
8989+ |> Ui.resize ~pad
9090+ |> Ui.border
9191+ ~pad_w
9292+ ~pad_h
9393+ ?label_top
9494+ ?label_bottom
9595+ ~attr:border_attr
19096;;
+5-23
forks/nottui/lib/nottui/widgets/border_box.mli
···1010 -> Nottui_main.ui Lwd.t
11111212(** Creates a bordered box around the given [input] widget. This box will change colour when focused
1313-1414-1513 @param pad The padding around the input widget within the border box.
1614 @param pad_w The horizontal padding around the input widget.
1715 @param pad_h The vertical padding around the input widget.
···3028 -> ?label_bottom:string
3129 -> ?border_attr:Notty.attr
3230 -> ?focus_attr:Notty.attr
3131+ -> ?style:Nottui_main.Ui.Border.style
3232+ -> ?focus_style:Nottui_main.Ui.Border.style
3333 -> ?focus:Nottui_main.Focus.handle
3434 -> ?on_key:(Nottui_main.Ui.key -> Nottui_main.Ui.may_handle)
3535 -> Nottui_main.ui Lwd.t
···5454 -> ?label_top:string
5555 -> ?label_bottom:string
5656 -> ?border_attr:Notty.attr
5757+ -> ?focus_attr:Notty.attr
5858+ -> ?style:Nottui_main.Ui.Border.style
5959+ -> ?focus_style:Nottui_main.Ui.Border.style
5760 -> Nottui_main.ui Lwd.t
5861 -> Nottui_main.ui Lwd.t
59626060-(** Creates a bordered box around the given [input]. The input must have a static sive ans this doesn't adjust the s .
6161- @param scaling
6262- Controls how the input widget is sized within the border box. Can be:
6363- - [`Static] - The input widget is not resized.
6464- - [`Expand sw] - The input widget is allowed to expand to fill the available space, with a stretch width [sw].
6565- - [`Shrinkable (min_width, sw)] - The input widget is allowed to shrink to a minimum width of [min_width], and expand with a stretch width [sw].
6666- @param pad The padding around the input widget within the border box.
6767- @param pad_w The horizontal padding around the input widget.
6868- @param pad_h The vertical padding around the input widget.
6969- @param label An optional label to display within the border box.
7070- @param input The input widget to be bordered.
7171- @param border_attr Style for the border, defaults to [A.empty]. *)
7272-val static
7373- : ?pad:Nottui_main.gravity
7474- -> ?pad_w:int
7575- -> ?pad_h:int
7676- -> ?label_top:Notty.image
7777- -> ?label_bottom:Notty.image
7878- -> ?border_attr:Notty.attr
7979- -> Nottui_main.ui
8080- -> Nottui_main.ui