terminal user interface to jujutsu. Focused on speed and clarity
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

add borders with focus, padding and titles

Eli Dowling 5a8221af 504d0eea

+366 -18
+268 -12
forks/nottui/lib/nottui/nottui_main.ml
··· 1 1 open Notty 2 2 open Lwd_utils 3 + (* test comment *) 3 4 module Log = (val Logs.src_log (Logs.Src.create "nottui")) 4 5 5 6 module Focus : sig ··· 264 265 end 265 266 266 267 module Ui = struct 268 + (** convinience method to take a str and turn it into a unicode char*) 269 + let make_uchar str = 270 + let a = String.get_utf_8_uchar str 0 in 271 + if a |> Uchar.utf_decode_is_valid 272 + then a |> Uchar.utf_decode_uchar 273 + else failwith "not a unicode string" 274 + ;; 275 + 276 + module Border = struct 277 + type style = 278 + { tl : Uchar.t 279 + ; tr : Uchar.t 280 + ; bl : Uchar.t 281 + ; br : Uchar.t 282 + ; h : Uchar.t 283 + ; v : Uchar.t 284 + } 285 + 286 + let ascii = 287 + { tl = make_uchar "+" 288 + ; tr = make_uchar "+" 289 + ; bl = make_uchar "+" 290 + ; br = make_uchar "+" 291 + ; h = make_uchar "-" 292 + ; v = make_uchar "|" 293 + } 294 + ;; 295 + 296 + let unicode = 297 + { tl = make_uchar "┌" 298 + ; tr = make_uchar "┐" 299 + ; bl = make_uchar "└" 300 + ; br = make_uchar "┘" 301 + ; h = make_uchar "─" 302 + ; v = make_uchar "│" 303 + } 304 + let unicode_double = 305 + { tl = make_uchar "╔" 306 + ; tr = make_uchar "╗" 307 + ; bl = make_uchar "╚" 308 + ; br = make_uchar "╝" 309 + ; h = make_uchar "═" 310 + ; v = make_uchar "║" 311 + } 312 + let unicode_rounded = 313 + { tl = make_uchar "╭" 314 + ; tr = make_uchar "╮" 315 + ; bl = make_uchar "╰" 316 + ; br = make_uchar "╯" 317 + ; h = make_uchar "─" 318 + ; v = make_uchar "│" 319 + } 320 + ;; 321 + 322 + (** Convenience focused styles *) 323 + let unicode_bold = 324 + { tl = make_uchar "┏" 325 + ; tr = make_uchar "┓" 326 + ; bl = make_uchar "┗" 327 + ; br = make_uchar "┛" 328 + ; h = make_uchar "━" 329 + ; v = make_uchar "┃" 330 + } 331 + ;; 332 + end 333 + 334 + type border = 335 + { attr : A.t 336 + ; thick : int 337 + ; pad_w : int (** left/right padding columns *) 338 + ; pad_h : int (** top/bottom padding rows *) 339 + ; style : Border.style 340 + ; focus_attr : A.t option (** attribute when focused, None means use attr *) 341 + ; focus_style : Border.style option (** style when focused, None means use style *) 342 + ; label_top : string option (** Optional text shown in the top border *) 343 + ; label_bottom : string option (** Optional text shown in the bottom border *) 344 + } 345 + 267 346 type mouse_handler = 268 347 x:int 269 348 -> y:int ··· 407 486 { vx : Interval.t 408 487 ; vy : Interval.t 409 488 ; image : image 489 + ; focused : bool (** Whether the UI had focus when this cache was created. This is needed to adjust the bord style based on focus status *) 410 490 } 411 491 412 492 and desc = ··· 422 502 | X of t * t 423 503 | Y of t * t 424 504 | Z of t * t 505 + | Border of t * border 425 506 426 507 let layout_spec t : layout_spec = 427 508 { w = t.w; h = t.h; sw = t.sw; sh = t.sh; mw = t.mw; mh = t.mh } ··· 433 514 let layout_stretch_height t = t.sh 434 515 let layout_max_width t = t.mw 435 516 let layout_max_height t = t.mh 436 - let cache : cache = { vx = Interval.zero; vy = Interval.zero; image = I.empty } 517 + let cache : cache = { vx = Interval.zero; vy = Interval.zero; image = I.empty; focused = false } 437 518 438 519 let empty : t = 439 520 { w = 0 ··· 595 676 let zcat xs = Lwd_utils.reduce pack_z xs 596 677 let has_focus t = Focus.has_focus t.focus 597 678 679 + let border ?(thick = 1) ?pad ?pad_w ?pad_h 680 + ?label_top ?label_bottom 681 + ?(attr = A.empty) ?(style = Border.unicode) 682 + ?focus_attr ?focus_style t = 683 + (* Derive horizontal and vertical pad values *) 684 + let pad_base = match pad with Some p -> p | None -> 0 in 685 + let pad_w = match pad_w with Some pw -> pw | None -> pad_base in 686 + let pad_h = match pad_h with Some ph -> ph | None -> pad_base in 687 + let dw = 2 * (thick + pad_w) in 688 + let dh = 2 * (thick + pad_h) in 689 + { w = t.w + dw 690 + ; h = t.h + dh 691 + ; sw = t.sw 692 + ; sh = t.sh 693 + ; mw = t.mw + dw 694 + ; mh = t.mh + dh 695 + ; flags = t.flags 696 + ; focus = t.focus 697 + ; desc = 698 + Border 699 + ( t 700 + , { attr 701 + ; thick 702 + ; pad_w 703 + ; pad_h 704 + ; style 705 + ; focus_attr 706 + ; focus_style 707 + ; label_top 708 + ; label_bottom 709 + } ) 710 + ; sensor_cache = None 711 + ; cache 712 + } 713 + ;; 714 + 598 715 let rec pp ppf t = 599 716 Format.fprintf 600 717 ppf ··· 627 744 | Focus_area (n, _) -> Format.fprintf ppf "Focus_area (@[%a,@ _@])" pp n 628 745 | Shift_area (n, _, _) -> Format.fprintf ppf "Shift_area (@[%a,@ _@])" pp n 629 746 | Event_filter (n, _) -> Format.fprintf ppf "Event_filter (@[%a,@ _@])" pp n 747 + | Border (n, _) -> Format.fprintf ppf "Border (@[%a,@ _@])" pp n 630 748 | X (a, b) -> Format.fprintf ppf "X (@[%a,@ %a@])" pp a pp b 631 749 | Y (a, b) -> Format.fprintf ppf "Y (@[%a,@ %a@])" pp a pp b 632 750 | Z (a, b) -> Format.fprintf ppf "Z (@[%a,@ %a@])" pp a pp b ··· 646 764 | X (a, b) | Y (a, b) | Z (a, b) -> 647 765 f a; 648 766 f b 649 - ;; 767 + | Border (u, _) -> f u 650 768 end 651 769 652 770 type ui = Ui.t ··· 763 881 let dx, rw = pack ~max:t.mw ~fixed:t.w ~stretch:t.sw sw (h (p1 g)) (h (p2 g)) in 764 882 let dy, rh = pack ~max:t.mh ~fixed:t.h ~stretch:t.sh sh (v (p1 g)) (v (p2 g)) in 765 883 update_sensors (ox + dx) (oy + dy) rw rh mw mh t 884 + | Border (t, b) -> 885 + let shift_x = b.thick + b.pad_w in 886 + let shift_y = b.thick + b.pad_h in 887 + let dw = 2 * shift_x in 888 + let dh = 2 * shift_y in 889 + update_sensors (ox + shift_x) (oy + shift_y) (sw - dw) (sh - dh) (mw - dw) (mh - dh) t 766 890 | Shift_area (t, sx, sy) -> update_sensors (ox - sx) (oy - sy) sw sh mw mh t 767 891 | X (a, b) -> 768 892 let aw, bw = split ~a:a.w ~sa:a.sw ~b:b.w ~sb:b.sw ~mA:a.mw ~mB:b.mw sw in ··· 774 898 update_sensors ox (oy + ah) sw bh mw mh b 775 899 | Z (a, b) -> 776 900 update_sensors ox oy sw sh mw mh a; 777 - update_sensors ox oy sw sh mw mh b) 901 + update_sensors ox oy sw sh mw mh b 902 + ) 778 903 ;; 779 904 780 905 (** goes through all focuses and attempts to resolve any that have changed*) ··· 805 930 match t.desc with 806 931 | Atom _ -> false 807 932 | X (a, b) -> 808 - let aw, bw = split ~a:a.w ~sa:a.sw ~b:b.w ~sb:b.sw ~mA:a.mh ~mB:b.mh sw in 933 + let aw, bw = split ~a:a.w ~sa:a.sw ~b:b.w ~sb:b.sw ~mA:a.mw ~mB:b.mw sw in 809 934 if x - ox < aw then aux ox oy aw sh a else aux (ox + aw) oy bw sh b 810 935 | Y (a, b) -> 811 936 let ah, bh = split ~a:a.h ~sa:a.sh ~b:b.h ~sb:b.sh ~mA:a.mh ~mB:b.mh sh in ··· 829 954 let dx, rw = pack ~max:t.mw ~fixed:t.w ~stretch:t.sw sw (h (p1 g)) (h (p2 g)) in 830 955 let dy, rh = pack ~max:t.mh ~fixed:t.h ~stretch:t.sh sh (v (p1 g)) (v (p2 g)) in 831 956 aux (ox + dx) (oy + dy) rw rh t 832 - | Event_filter (n, f) -> 957 + | Border (t, b) -> 958 + let shift_x = b.thick + b.pad_w in 959 + let shift_y = b.thick + b.pad_h in 960 + let dw = 2 * shift_x in 961 + let dh = 2 * shift_y in 962 + aux (ox + shift_x) (oy + shift_y) (sw - dw) (sh - dh) t 963 + | Event_filter (t, f) -> 833 964 (match f (`Mouse (`Press btn, (x, y), [])) with 834 965 | `Handled -> true 835 - | `Unhandled -> aux ox oy sw sh n 966 + | `Unhandled -> aux ox oy sw sh t 836 967 | `Remap _ -> failwith "Cannot remap mouse events") 837 968 in 838 969 aux 0 0 w h t ··· 881 1012 let same_size w h image = w = I.width image && h = I.height image 882 1013 883 1014 let rec render_node vx1 vy1 vx2 vy2 sw sh t : cache = 1015 + let is_focused = has_focus t in 884 1016 if 885 1017 let cache = t.cache in 886 1018 vx1 >= Interval.fst cache.vx ··· 888 1020 && vx2 <= Interval.snd cache.vx 889 1021 && vy2 <= Interval.snd cache.vy 890 1022 && same_size sw sh cache.image 1023 + && cache.focused = is_focused 891 1024 then t.cache 892 1025 else if vx2 < 0 || vy2 < 0 || sw < vx1 || sh < vy1 893 1026 then ( 894 1027 let vx = Interval.make vx1 vx2 895 1028 and vy = Interval.make vy1 vy2 in 896 - { vx; vy; image = I.void sw sh }) 1029 + { vx; vy; image = I.void sw sh; focused = is_focused }) 897 1030 else ( 898 1031 let cache = 899 1032 match t.desc with ··· 901 1034 { vx = Interval.make 0 sw 902 1035 ; vy = Interval.make 0 sh 903 1036 ; image = resize_canvas sw sh image 1037 + ; focused = is_focused 904 1038 } 905 1039 | Size_sensor (desc, handler) -> 906 1040 handler ~w:sw ~h:sh; ··· 916 1050 let vx = Interval.make vx1 vx2 917 1051 and vy = Interval.make vy1 vy2 in 918 1052 let image = resize_canvas sw sh (I.crop ~l:sx ~t:sy cache.image) in 919 - { vx; vy; image } 1053 + { vx; vy; image; focused = is_focused } 920 1054 | X (a, b) -> 921 1055 let aw, bw = split ~a:a.w ~sa:a.sw ~b:b.w ~sb:b.sw ~mA:a.mw ~mB:b.mw sw in 922 1056 let ca = render_node vx1 vy1 vx2 vy2 aw sh a in ··· 930 1064 (maxi (Interval.fst ca.vy) (Interval.fst cb.vy)) 931 1065 (mini (Interval.snd ca.vy) (Interval.snd cb.vy)) 932 1066 and image = resize_canvas sw sh (I.( <|> ) ca.image cb.image) in 933 - { vx; vy; image } 1067 + { vx; vy; image; focused = is_focused } 934 1068 | Y (a, b) -> 935 1069 let ah, bh = split ~a:a.h ~sa:a.sh ~b:b.h ~sb:b.sh ~mA:a.mh ~mB:b.mh sh in 936 1070 let ca = render_node vx1 vy1 vx2 vy2 sw ah a in ··· 944 1078 (maxi (Interval.fst ca.vy) (Interval.fst cb.vy + ah)) 945 1079 (mini (Interval.snd ca.vy) (Interval.snd cb.vy + ah)) 946 1080 and image = resize_canvas sw sh (I.( <-> ) ca.image cb.image) in 947 - { vx; vy; image } 1081 + { vx; vy; image; focused = is_focused } 948 1082 | Z (a, b) -> 949 1083 let ca = render_node vx1 vy1 vx2 vy2 sw sh a in 950 1084 let cb = render_node vx1 vy1 vx2 vy2 sw sh b in ··· 957 1091 (maxi (Interval.fst ca.vy) (Interval.fst cb.vy)) 958 1092 (mini (Interval.snd ca.vy) (Interval.snd cb.vy)) 959 1093 and image = resize_canvas sw sh (I.( </> ) cb.image ca.image) in 960 - { vx; vy; image } 1094 + { vx; vy; image; focused = is_focused } 1095 + | Border (t, b) -> 1096 + let open Border in 1097 + let open I in 1098 + (*if the border is 0 we just render the content and pad it*) 1099 + if b.thick = 0 1100 + then ( 1101 + let shift_x = b.pad_w in 1102 + let shift_y = b.pad_h in 1103 + let rw = sw - (2 * shift_x) in 1104 + let rh = sh - (2 * shift_y) in 1105 + let c = 1106 + render_node 1107 + (vx1 - shift_x) 1108 + (vy1 - shift_y) 1109 + (vx2 - shift_x) 1110 + (vy2 - shift_y) 1111 + rw 1112 + rh 1113 + t 1114 + in 1115 + let padded_image = 1116 + if b.pad_w = 0 && b.pad_h = 0 1117 + then c.image 1118 + else I.pad ~l:b.pad_w ~t:b.pad_h ~r:b.pad_w ~b:b.pad_h c.image 1119 + in 1120 + { vx = Interval.shift c.vx shift_x 1121 + ; vy = Interval.shift c.vy shift_y 1122 + ; image = resize_canvas sw sh padded_image 1123 + ; focused = is_focused 1124 + }) 1125 + else ( 1126 + let truncate_string len str = 1127 + if String.length str > len then ( 1128 + if len <= 3 then "" else String.sub str 0 (len - 3) ^ "..." 1129 + ) else str 1130 + in 1131 + let make_label max_w txt = 1132 + let txt = truncate_string (max_w - 2) txt in 1133 + I.strf " %s " txt 1134 + in 1135 + (* Determine shifts and inner area size *) 1136 + let shift_x = b.thick + b.pad_w in 1137 + let shift_y = b.thick + b.pad_h in 1138 + 1139 + let rw = sw - 2 * shift_x in 1140 + let rh = sh - 2 * shift_y in 1141 + 1142 + let c = 1143 + render_node 1144 + (vx1 - shift_x) 1145 + (vy1 - shift_y) 1146 + (vx2 - shift_x) 1147 + (vy2 - shift_y) 1148 + rw 1149 + rh 1150 + t 1151 + in 1152 + 1153 + (* Select attributes and style based on focus state *) 1154 + let attr = 1155 + if is_focused then Option.value ~default:b.attr b.focus_attr else b.attr 1156 + in 1157 + let style = 1158 + if is_focused then Option.value ~default:b.style b.focus_style else b.style 1159 + in 1160 + 1161 + (* Total interior dims inside border glyphs (content + padding) *) 1162 + let inner_w = rw + (2 * b.pad_w) in 1163 + let inner_h = rh + (2 * b.pad_h) in 1164 + 1165 + (* border glyph primitives *) 1166 + let horiz = I.uchar attr style.h inner_w 1 in 1167 + let vert h = I.uchar attr style.v 1 h in 1168 + 1169 + (* pad content *) 1170 + let padded_image = 1171 + if b.pad_w = 0 && b.pad_h = 0 then c.image 1172 + else I.pad ~l:b.pad_w ~t:b.pad_h ~r:b.pad_w ~b:b.pad_h c.image 1173 + in 1174 + 1175 + (* Build top border, optionally with label. *) 1176 + let frame_top_base = 1177 + I.(uchar attr style.tl 1 1 <|> horiz <|> uchar attr style.tr 1 1) 1178 + in 1179 + let frame_top = 1180 + match b.label_top with 1181 + | None -> frame_top_base 1182 + | Some txt -> 1183 + let lbl = make_label inner_w txt in 1184 + let lbl = 1185 + if I.width lbl > inner_w - 2 then I.empty else I.hpad 2 0 lbl 1186 + in 1187 + if I.width lbl = 0 then frame_top_base else I.zcat [ lbl; frame_top_base; lbl ] 1188 + in 1189 + 1190 + (* Build bottom border, optionally with label. *) 1191 + let frame_bot_base = 1192 + I.(uchar attr style.bl 1 1 <|> horiz <|> uchar attr style.br 1 1) 1193 + in 1194 + let frame_bot = 1195 + match b.label_bottom with 1196 + | None -> frame_bot_base 1197 + | Some txt -> 1198 + let lbl = make_label inner_w txt in 1199 + let lbl_width = I.width lbl in 1200 + let lbl = 1201 + if lbl_width > inner_w - 2 then I.empty 1202 + else I.hpad (inner_w - lbl_width - 1) 0 lbl 1203 + in 1204 + if I.width lbl = 0 then frame_bot_base else I.zcat [ lbl; frame_bot_base; lbl ] 1205 + in 1206 + 1207 + let frame_mid = I.(vert inner_h <|> padded_image <|> vert inner_h) in 1208 + let frame = I.(frame_top <-> frame_mid <-> frame_bot) in 1209 + 1210 + { vx = Interval.shift c.vx shift_x 1211 + ; vy = Interval.shift c.vy shift_y 1212 + ; image = resize_canvas sw sh frame 1213 + ; focused = is_focused 1214 + }) 961 1215 | Resize (t, g, bg) -> 962 1216 let open Gravity in 963 1217 let dx, rw = pack ~max:t.mw ~fixed:t.w ~stretch:t.sw sw (h (p1 g)) (h (p2 g)) in ··· 967 1221 let image = if bg != A.empty then I.(image </> char bg ' ' sw sh) else image in 968 1222 let vx = Interval.shift c.vx dx in 969 1223 let vy = Interval.shift c.vy dy in 970 - { vx; vy; image } 1224 + { vx; vy; image; focused = is_focused } 971 1225 | Event_filter (t, _f) -> render_node vx1 vy1 vx2 vy2 sw sh t 972 1226 in 973 1227 t.cache <- cache; ··· 1014 1268 | Permanent_sensor (t, _) 1015 1269 | Shift_area (t, _, _) 1016 1270 | Resize (t, _, _) -> iter (t :: tl) 1271 + | Border (t, _) -> iter (t :: tl) 1017 1272 | Event_filter (t, f) -> 1018 1273 (match f (`Key key) with 1019 1274 | `Unhandled -> iter (t :: tl) ··· 1111 1366 if Focus.has_focus a.focus 1112 1367 then dispatch_focus a dir 1113 1368 else dispatch_focus b dir || dispatch_focus a dir 1369 + | Border (t, _) -> dispatch_focus t dir 1114 1370 ;; 1115 1371 1116 1372 let rec dispatch_key st key =
+30
forks/nottui/lib/nottui/nottui_main.mli
··· 107 107 (** Printing UI element *) 108 108 val pp : Format.formatter -> t -> unit 109 109 110 + module Border : sig 111 + type style = { tl:Uchar.t;tr:Uchar.t;bl:Uchar.t;br:Uchar.t;h:Uchar.t;v:Uchar.t } 112 + val ascii : style 113 + val unicode : style 114 + val unicode_double : style 115 + val unicode_rounded : style 116 + val unicode_bold : style 117 + end 118 + 110 119 (** {1 Layout specifications} *) 111 120 112 121 (** The type of layout specifications. ··· 268 277 val permanent_sensor : frame_sensor -> t -> t 269 278 270 279 (** {1 Composite images} *) 280 + 281 + (** Add a border around a UI element. 282 + - [thick]: thickness of the border (default 1). 283 + - [attr]: attributes for the border characters (default empty). 284 + - [style]: the characters to use for drawing the border (default [unicode]). 285 + - [focus_attr]: attributes for the border when focused (default [attr]). 286 + - [focus_style]: border style when focused (default [style]). 287 + bounds, otherwise it is drawn outside, increasing the element's size. *) 288 + val border 289 + : ?thick:int 290 + -> ?pad:int 291 + -> ?pad_w:int 292 + -> ?pad_h:int 293 + -> ?label_top:string 294 + -> ?label_bottom:string 295 + -> ?attr:A.t 296 + -> ?style:Border.style 297 + -> ?focus_attr:A.t 298 + -> ?focus_style:Border.style 299 + -> t 300 + -> t 271 301 272 302 (** Override the layout specification of the ui with provided [w](width), [h](height), 273 303 [sw](stretch width) or [sh](stretch height)
+1 -5
forks/nottui/lib/nottui/widgets/border_box.mli
··· 11 11 12 12 (** Creates a bordered box around the given [input] widget. This box will change colour when focused 13 13 14 - @param scaling 15 - Controls how the input widget is sized within the border box. Can be: 16 - - [`Static] - The input widget is not resized. 17 - - [`Expand sw] - The input widget is allowed to expand to fill the available space, with a stretch width [sw]. 18 - - [`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]. 14 + 19 15 @param pad The padding around the input widget within the border box. 20 16 @param pad_w The horizontal padding around the input widget. 21 17 @param pad_h The vertical padding around the input widget.
+8 -1
jj_tui/widget-test/main.ml
··· 18 18 let w_0 = 19 19 W.hbox 20 20 [ 21 + Ui.border ~thick:2 ~style:Ui.Border.unicode ~label_top:"top" (Ui.vcat [W.string "hi this is a ui element with a\n border"; W.string "hi"])|>Lwd.pure; 22 + Ui.border ~thick:0 ~pad_w:2 ~pad_h:1 ~style:Ui.Border.unicode_double ~label_bottom:"bottom" (Ui.vcat [W.string "hi this is a ui element with a\n border"; W.string "hi"])|>Lwd.pure; 23 + Ui.border ~thick:1 ~style:Ui.Border.unicode_rounded ~label_top:"top" ~label_bottom:"bottom" (Ui.vcat [W.string "hi this is a ui element with a\n border"; W.string "hi"])|>Lwd.pure; 24 + 25 + Ui.border ~focus_attr: (A.fg A.red) ~focus_style:Ui.Border.unicode_double ~thick: 2 ~pad_w:2 ~pad_h:1 ~style:Ui.Border.unicode (Ui.vcat [W.string "hi this is a ui element with a\n border"; W.string "hi"])|>Lwd.pure; 26 + 27 + W.Box.box ~pad_w:2 ~pad_h:1 (Ui.vcat [W.string "hi this is a ui element with an\n old style border box"; W.string "hi"]|>Lwd.pure); 21 28 (* pString " |" *) 22 29 (* ; (let og = *) 23 30 (* Ui.vcat *) ··· 33 40 (* |>$ Ui.resize ~sh:1 ~mh:1000 *) 34 41 (* |> W.size_logger) *) 35 42 (* ; pString "| " *) 36 - test_input 43 + test_input|>$ Ui.border ~focus_attr: (A.fg A.red) ~focus_style:Ui.Border.unicode_double ~thick:1 ~pad:1 ~style:Ui.Border.unicode 37 44 ] 38 45 ;; 39 46
+59
widget-test/main.ml
··· 1 + let test_input= 2 + let inp_var =("hi there",5)|>Lwd.var in 3 + let inp_text= inp_var|>Lwd.get in 4 + 5 + W.edit_field inp_text ~on_change:(fun x->Lwd.set inp_var x) ~on_submit:(fun x->()) 6 + 7 + let test_focused_border = 8 + let focus = Focus.make () in 9 + let content = W.string "Click to focus this border" in 10 + content 11 + |> Lwd.pure 12 + |> Lwd.map ~f:(fun ui -> 13 + ui 14 + |> Ui.keyboard_area ~focus:(Focus.status focus) (fun _ -> `Unhandled) 15 + |> Ui.border 16 + ~thick:1 17 + ~pad_w:2 18 + ~pad_h:1 19 + ~attr:(A.fg A.white) 20 + ~style:Ui.Border.unicode 21 + ~focus_attr:(A.fg A.blue) 22 + ~focus_style:Ui.Border.unicode_bold 23 + |> Ui.mouse_area (fun ~x:_ ~y:_ _ -> 24 + Focus.request focus; 25 + `Handled)) 26 + 27 + let w_0 = 28 + W.vbox 29 + [ 30 + W.hbox 31 + [ 32 + Ui.border ~thick:1 ~style:Ui.Border.unicode (Ui.vcat [W.string "hi this is a ui element with a\n border"; W.string "hi"])|>Lwd.pure; 33 + Ui.border ~thick:1 ~style:Ui.Border.unicode_double (Ui.vcat [W.string "hi this is a ui element with a\n border"; W.string "hi"])|>Lwd.pure; 34 + Ui.border ~thick:0 ~style:Ui.Border.unicode_rounded (Ui.vcat [W.string "hi this is a ui element with a\n border"; W.string "hi"])|>Lwd.pure; 35 + 36 + Ui.border ~thick: 2 ~pad_w:2 ~pad_h:1 ~style:Ui.Border.unicode (Ui.vcat [W.string "hi this is a ui element with a\n border"; W.string "hi"])|>Lwd.pure; 37 + 38 + W.Box.box ~pad_w:2 ~pad_h:1 (Ui.vcat [W.string "hi this is a ui element with an\n old style border box"; W.string "hi"]|>Lwd.pure); 39 + (* pString " |" *) 40 + (* ; (let og = *) 41 + (* Ui.vcat *) 42 + (* [ *) 43 + (* W.string "123456789000000000000000000000000000000000000000000000000000end" *) 44 + (* ; W.string "123456789000000000000000000000000000000000000000000000000000end" *) 45 + (* ] *) 46 + (* in *) 47 + (* og *) 48 + (* |> Lwd.pure *) 49 + (* |> W.Scroll.area *) 50 + (* |> W.Box.box *) 51 + (* |>$ Ui.resize ~sh:1 ~mh:1000 *) 52 + (* |> W.size_logger) *) 53 + (* ; pString "| " *) 54 + test_input|>$ Ui.border ~thick:1 ~pad:1 ~style:Ui.Border.unicode 55 + ] 56 + ; W.string " " |> Lwd.pure 57 + ; W.string "Test focused border (click to focus):" |> Lwd.pure 58 + ; test_focused_border 59 + ]