Compare commits
38 Commits
memes
...
5c11183217
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c11183217 | |||
| 2ec6426fe5 | |||
| 0df5884a88 | |||
| 6948a65a97 | |||
| bba26b9c0f | |||
| fcf528275b | |||
| d53f6687e5 | |||
| d46c1de49d | |||
| f0c5556450 | |||
| 97730899c6 | |||
| 18daf83c1c | |||
| dfef26fcf5 | |||
| 048ea0eab4 | |||
| 3509930195 | |||
| b1ac36ce3e | |||
| a12db025e0 | |||
| 5c10f3860a | |||
| a64fcbb010 | |||
| 7baa6f3648 | |||
| af92f03706 | |||
| cb263b5758 | |||
| 44879eb947 | |||
| 49bddb6365 | |||
| b5d846b35d | |||
| 60c83c608a | |||
| 58ec73972b | |||
| b705c598ff | |||
| 9d1ccb93b5 | |||
| 3fc8125d42 | |||
| 3b09bb1c11 | |||
| 281351371d | |||
| fec4249d9f | |||
| 65aa7ff901 | |||
| 39193ff253 | |||
| 399280d9c4 | |||
| 6a484c3a06 | |||
| 7460b8f793 | |||
| c40e725978 |
@ -1 +0,0 @@
|
|||||||
profile = compact
|
|
||||||
205
backend.ml
Normal file
205
backend.ml
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
module F = Fmt
|
||||||
|
|
||||||
|
module Key = struct
|
||||||
|
type special =
|
||||||
|
[ `Enter
|
||||||
|
| `Escape
|
||||||
|
| `Tab
|
||||||
|
| `Arrow of [`Up | `Down | `Left | `Right]
|
||||||
|
| `Function of int
|
||||||
|
| `Page of [`Up | `Down]
|
||||||
|
| `Home
|
||||||
|
| `End
|
||||||
|
| `Insert
|
||||||
|
| `Delete
|
||||||
|
| `Backspace ]
|
||||||
|
|
||||||
|
(** Type of key code. *)
|
||||||
|
type code =
|
||||||
|
[`Uchar of Uchar.t (** A unicode character. *) | special]
|
||||||
|
|
||||||
|
type keystate =
|
||||||
|
{ctrl: bool; meta: bool; shift: bool; super: bool; code: code}
|
||||||
|
|
||||||
|
module KeyS = struct
|
||||||
|
type t = keystate
|
||||||
|
|
||||||
|
let compare = compare
|
||||||
|
end
|
||||||
|
|
||||||
|
module Bind = struct
|
||||||
|
(* parts stolen from lambda-term/src/lTerm_{edit,key}.ml{,i} *)
|
||||||
|
module S = Zed_input.Make (KeyS)
|
||||||
|
|
||||||
|
type 'a t = 'a list S.t
|
||||||
|
type 'a resolver = 'a list S.resolver
|
||||||
|
type 'a result = 'a list S.result
|
||||||
|
|
||||||
|
type 'a state =
|
||||||
|
{ mutable bindings: 'a t
|
||||||
|
; mutable state: 'a result
|
||||||
|
; mutable last_keyseq: keystate list
|
||||||
|
; mutable last_actions: 'a list }
|
||||||
|
|
||||||
|
type mods = Ctrl | Meta | Super | Shift
|
||||||
|
type key = C of char | U of code
|
||||||
|
|
||||||
|
let keystate_of_mods ks m =
|
||||||
|
List.fold_left
|
||||||
|
(fun ks m ->
|
||||||
|
match m with
|
||||||
|
| Meta -> {ks with meta= true}
|
||||||
|
| Ctrl -> {ks with ctrl= true}
|
||||||
|
| Super -> {ks with super= true}
|
||||||
|
| Shift -> {ks with shift= true} )
|
||||||
|
ks m
|
||||||
|
|
||||||
|
let add events action bindings =
|
||||||
|
let events =
|
||||||
|
List.map
|
||||||
|
(fun (m, k) ->
|
||||||
|
keystate_of_mods
|
||||||
|
{ meta= false
|
||||||
|
; ctrl= false
|
||||||
|
; super= false
|
||||||
|
; shift= false
|
||||||
|
; code=
|
||||||
|
( match k with
|
||||||
|
| C c -> `Uchar (Uchar.of_char c)
|
||||||
|
| U c -> c ) }
|
||||||
|
m )
|
||||||
|
events in
|
||||||
|
S.add events action bindings
|
||||||
|
|
||||||
|
let default_resolver b = S.resolver [S.pack (fun x -> x) b]
|
||||||
|
|
||||||
|
let get_resolver result default =
|
||||||
|
match result with S.Continue r -> r | _ -> default
|
||||||
|
|
||||||
|
let init bindings =
|
||||||
|
{bindings; state= S.Rejected; last_keyseq= []; last_actions= []}
|
||||||
|
|
||||||
|
let resolve = S.resolve
|
||||||
|
let empty = S.empty
|
||||||
|
|
||||||
|
type action =
|
||||||
|
| Custom of (unit -> unit)
|
||||||
|
| CustomLwt of (unit -> unit Lwt.t)
|
||||||
|
| Zed of Zed_edit.action
|
||||||
|
|
||||||
|
let resolve_events (state : 'a state) events =
|
||||||
|
List.flatten
|
||||||
|
(List.filter_map
|
||||||
|
(fun e ->
|
||||||
|
match e with
|
||||||
|
| `Key (`Press, (k : keystate)) -> (
|
||||||
|
( match state.state with
|
||||||
|
| Continue _ -> ()
|
||||||
|
| _ -> state.last_keyseq <- [] ) ;
|
||||||
|
state.state <-
|
||||||
|
resolve k
|
||||||
|
(get_resolver state.state
|
||||||
|
(default_resolver state.bindings) ) ;
|
||||||
|
state.last_keyseq <- k :: state.last_keyseq ;
|
||||||
|
match state.state with
|
||||||
|
| Accepted a ->
|
||||||
|
state.last_actions <- a ;
|
||||||
|
Some a
|
||||||
|
| Rejected ->
|
||||||
|
state.last_actions <- [] ;
|
||||||
|
None
|
||||||
|
| _ -> None )
|
||||||
|
| _ -> None )
|
||||||
|
events )
|
||||||
|
|
||||||
|
let actions_of_events (state : action state) events =
|
||||||
|
List.flatten
|
||||||
|
(List.filter_map
|
||||||
|
(fun e ->
|
||||||
|
match e with
|
||||||
|
| `Key (`Press, (k : keystate)) -> (
|
||||||
|
( match state.state with
|
||||||
|
| Continue _ -> ()
|
||||||
|
| _ -> state.last_keyseq <- [] ) ;
|
||||||
|
state.state <-
|
||||||
|
resolve k
|
||||||
|
(get_resolver state.state
|
||||||
|
(default_resolver state.bindings) ) ;
|
||||||
|
state.last_keyseq <- k :: state.last_keyseq ;
|
||||||
|
match state.state with
|
||||||
|
| Accepted a ->
|
||||||
|
state.last_actions <- a ;
|
||||||
|
Some a
|
||||||
|
| Rejected ->
|
||||||
|
state.last_actions <- [] ;
|
||||||
|
None
|
||||||
|
| _ -> None )
|
||||||
|
| _ -> None )
|
||||||
|
events )
|
||||||
|
|
||||||
|
let process bindstate events =
|
||||||
|
Lwt_list.iter_s
|
||||||
|
(function
|
||||||
|
| Custom f -> Lwt.return (f ())
|
||||||
|
| CustomLwt f -> f ()
|
||||||
|
| Zed _ -> Lwt.return_unit )
|
||||||
|
(actions_of_events bindstate events)
|
||||||
|
end
|
||||||
|
|
||||||
|
(* stolen from lambda-term/src/lTerm_{edit,key}.ml{,i} *)
|
||||||
|
let string_of_code = function
|
||||||
|
| `Uchar ch ->
|
||||||
|
if Uchar.is_char ch then F.str "Char '%c'" (Uchar.to_char ch)
|
||||||
|
else F.str "Char 0x%02x" (Uchar.to_int ch)
|
||||||
|
| `Enter -> "Enter"
|
||||||
|
| `Escape -> "Escape"
|
||||||
|
| `Tab -> "Tab"
|
||||||
|
| `Arrow `Up -> "Up"
|
||||||
|
| `Arrow `Down -> "Down"
|
||||||
|
| `Arrow `Left -> "Left"
|
||||||
|
| `Arrow `Right -> "Right"
|
||||||
|
| `Function i -> F.str "F%d" i
|
||||||
|
| `Page `Up -> "Page Up"
|
||||||
|
| `Page `Down -> "Page Down"
|
||||||
|
| `Home -> "Home"
|
||||||
|
| `End -> "End"
|
||||||
|
| `Insert -> "Insert"
|
||||||
|
| `Delete -> "Delete"
|
||||||
|
| `Backspace -> "Backspace"
|
||||||
|
|
||||||
|
let to_string key =
|
||||||
|
Printf.sprintf
|
||||||
|
"{ control = %B; meta = %B; shift = %B; super = %B; code = %s }"
|
||||||
|
key.ctrl key.meta key.shift key.super
|
||||||
|
(string_of_code key.code)
|
||||||
|
|
||||||
|
let to_string_compact key =
|
||||||
|
let buffer = Buffer.create 32 in
|
||||||
|
if key.ctrl then Buffer.add_string buffer "Ctrl-" ;
|
||||||
|
if key.meta then Buffer.add_string buffer "Meta-" ;
|
||||||
|
if key.shift then Buffer.add_string buffer "Shift-" ;
|
||||||
|
if key.super then Buffer.add_string buffer "Super-" ;
|
||||||
|
( match key.code with
|
||||||
|
| `Uchar ch ->
|
||||||
|
let code = Uchar.to_int ch in
|
||||||
|
if Uchar.is_char ch then
|
||||||
|
match Uchar.to_char ch with
|
||||||
|
| ( 'a' .. 'z'
|
||||||
|
| 'A' .. 'Z'
|
||||||
|
| '0' .. '9'
|
||||||
|
| '_' | '(' | ')' | '[' | ']' | '{' | '}' | '#' | '~'
|
||||||
|
| '&' | '$' | '*' | '%' | '!' | '?' | ',' | ';' | ':'
|
||||||
|
| '/' | '\\' | '.' | '@' | '=' | '+' | '-' ) as ch ->
|
||||||
|
Buffer.add_char buffer ch
|
||||||
|
| ' ' -> Buffer.add_string buffer "space"
|
||||||
|
| _ -> Printf.bprintf buffer "U+%02x" code
|
||||||
|
else if code <= 0xffff then
|
||||||
|
Printf.bprintf buffer "U+%04x" code
|
||||||
|
else Printf.bprintf buffer "U+%06x" code
|
||||||
|
| `Page `Down -> Buffer.add_string buffer "pgup"
|
||||||
|
| `Page `Up -> Buffer.add_string buffer "pgdn"
|
||||||
|
| code ->
|
||||||
|
Buffer.add_string buffer
|
||||||
|
(String.lowercase_ascii (string_of_code code)) ) ;
|
||||||
|
Buffer.contents buffer
|
||||||
|
end
|
||||||
7
backend_js.ml
Normal file
7
backend_js.ml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
include Backend
|
||||||
|
|
||||||
|
module Keycode = struct
|
||||||
|
open Js_of_ocaml
|
||||||
|
|
||||||
|
type t = Dom_html.Keyboard_code.t
|
||||||
|
end
|
||||||
438
backend_sdl.ml
Normal file
438
backend_sdl.ml
Normal file
@ -0,0 +1,438 @@
|
|||||||
|
module Key = struct
|
||||||
|
let sdlkey_map = Hashtbl.create 1024
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let aa (x : int) (y : Key.code) = Hashtbl.add sdlkey_map x y in
|
||||||
|
aa return `Enter ;
|
||||||
|
aa escape `Escape ;
|
||||||
|
aa backspace `Backspace ;
|
||||||
|
aa tab `Tab ;
|
||||||
|
aa f1 (`Function 1) ;
|
||||||
|
aa f2 (`Function 2) ;
|
||||||
|
aa f3 (`Function 3) ;
|
||||||
|
aa f4 (`Function 4) ;
|
||||||
|
aa f5 (`Function 5) ;
|
||||||
|
aa f6 (`Function 6) ;
|
||||||
|
aa f7 (`Function 7) ;
|
||||||
|
aa f8 (`Function 8) ;
|
||||||
|
aa f9 (`Function 9) ;
|
||||||
|
aa f10 (`Function 10) ;
|
||||||
|
aa f11 (`Function 11) ;
|
||||||
|
aa f12 (`Function 12) ;
|
||||||
|
aa insert `Insert ;
|
||||||
|
aa delete `Delete ;
|
||||||
|
aa home `Home ;
|
||||||
|
aa kend `End ;
|
||||||
|
aa pageup (`Page `Up) ;
|
||||||
|
aa pagedown (`Page `Down) ;
|
||||||
|
aa right (`Arrow `Right) ;
|
||||||
|
aa left (`Arrow `Left) ;
|
||||||
|
aa down (`Arrow `Down) ;
|
||||||
|
aa up (`Arrow `Up)
|
||||||
|
|
||||||
|
let key_of_sdlkey ev =
|
||||||
|
let (kc : Sdl.keycode) =
|
||||||
|
Sdl.Event.get ev Sdl.Event.keyboard_keycode
|
||||||
|
land lnot Sdl.K.scancode_mask in
|
||||||
|
match (Hashtbl.find_opt sdlkey_map kc, Uchar.is_valid kc) with
|
||||||
|
| Some s, _ -> Some s
|
||||||
|
| None, true -> Some (`Uchar (Uchar.of_int kc))
|
||||||
|
| None, false -> None
|
||||||
|
|
||||||
|
let event_of_sdlevent ev : t option =
|
||||||
|
match Sdl.Event.enum (Sdl.Event.get ev Sdl.Event.typ) with
|
||||||
|
| (`Key_down | `Key_up) as d -> (
|
||||||
|
match key_of_sdlkey ev with
|
||||||
|
| None -> None
|
||||||
|
| Some code ->
|
||||||
|
let km = Sdl.Event.get ev Sdl.Event.keyboard_keymod in
|
||||||
|
Some
|
||||||
|
(`Key
|
||||||
|
( ( match d with
|
||||||
|
| _
|
||||||
|
when Sdl.Event.get ev Sdl.Event.keyboard_repeat > 1
|
||||||
|
->
|
||||||
|
`Repeat
|
||||||
|
| `Key_up -> `Release
|
||||||
|
| _ -> `Press )
|
||||||
|
, { code
|
||||||
|
; ctrl= km land Sdl.Kmod.ctrl > 0
|
||||||
|
; meta= km land Sdl.Kmod.alt > 0
|
||||||
|
; super= km land Sdl.Kmod.gui > 0
|
||||||
|
; shift= km land Sdl.Kmod.shift > 0 } ) ) )
|
||||||
|
| `Mouse_motion ->
|
||||||
|
let x, y = snd (Tsdl.Sdl.get_mouse_state ()) in
|
||||||
|
Some (`Mouse (V2.v (float x) (float y)))
|
||||||
|
| `Quit -> Some `Quit
|
||||||
|
(* Unhandled events *)
|
||||||
|
| `Text_editing -> Some (`Unknown "`Text_editing")
|
||||||
|
| `Text_input -> Some (`Unknown "`Text_input")
|
||||||
|
| `App_did_enter_background ->
|
||||||
|
Some (`Unknown "`App_did_enter_background")
|
||||||
|
| `App_did_enter_foreground ->
|
||||||
|
Some (`Unknown "`App_did_enter_foreground ")
|
||||||
|
| `App_low_memory -> Some (`Unknown "`App_low_memory ")
|
||||||
|
| `App_terminating -> Some (`Unknown "`App_terminating ")
|
||||||
|
| `App_will_enter_background ->
|
||||||
|
Some (`Unknown "`App_will_enter_background ")
|
||||||
|
| `App_will_enter_foreground ->
|
||||||
|
Some (`Unknown "`App_will_enter_foreground ")
|
||||||
|
| `Clipboard_update -> Some (`Unknown "`Clipboard_update ")
|
||||||
|
| `Controller_axis_motion ->
|
||||||
|
Some (`Unknown "`Controller_axis_motion ")
|
||||||
|
| `Controller_button_down ->
|
||||||
|
Some (`Unknown "`Controller_button_down ")
|
||||||
|
| `Controller_button_up -> Some (`Unknown "`Controller_button_up ")
|
||||||
|
| `Controller_device_added ->
|
||||||
|
Some (`Unknown "`Controller_device_added ")
|
||||||
|
| `Controller_device_remapped ->
|
||||||
|
Some (`Unknown "`Controller_device_remapped ")
|
||||||
|
| `Controller_device_removed ->
|
||||||
|
Some (`Unknown "`Controller_device_removed ")
|
||||||
|
| `Dollar_gesture -> Some (`Unknown "`Dollar_gesture ")
|
||||||
|
| `Dollar_record -> Some (`Unknown "`Dollar_record ")
|
||||||
|
| `Drop_file -> Some (`Unknown "`Drop_file ")
|
||||||
|
| `Finger_down -> Some (`Unknown "`Finger_down")
|
||||||
|
| `Finger_motion -> Some (`Unknown "`Finger_motion ")
|
||||||
|
| `Finger_up -> Some (`Unknown "`Finger_up ")
|
||||||
|
| `Joy_axis_motion -> Some (`Unknown "`Joy_axis_motion ")
|
||||||
|
| `Joy_ball_motion -> Some (`Unknown "`Joy_ball_motion ")
|
||||||
|
| `Joy_button_down -> Some (`Unknown "`Joy_button_down ")
|
||||||
|
| `Joy_button_up -> Some (`Unknown "`Joy_button_up ")
|
||||||
|
| `Joy_device_added -> Some (`Unknown "`Joy_device_added ")
|
||||||
|
| `Joy_device_removed -> Some (`Unknown "`Joy_device_removed ")
|
||||||
|
| `Joy_hat_motion -> Some (`Unknown "`Joy_hat_motion ")
|
||||||
|
| `Mouse_button_down -> Some (`Unknown "`Mouse_button_down ")
|
||||||
|
| `Mouse_button_up -> Some (`Unknown "`Mouse_button_up")
|
||||||
|
| `Mouse_wheel -> Some (`Unknown "`Mouse_wheel ")
|
||||||
|
| `Multi_gesture -> Some (`Unknown "`Multi_gesture")
|
||||||
|
| `Sys_wm_event -> Some (`Unknown "`Sys_wm_event ")
|
||||||
|
| `Unknown e -> Some (`Unknown (Format.sprintf "`Unknown %d" e))
|
||||||
|
| `User_event -> Some (`Unknown "`User_event ")
|
||||||
|
| `Display_event -> Some (`Unknown "`Display_event ")
|
||||||
|
| `Sensor_update -> Some (`Unknown "`Sensor_update ")
|
||||||
|
| `Window_event -> Some (`Unknown "`Window_event ")
|
||||||
|
|
||||||
|
let key_up : Sdl.keycode = 0x40000052
|
||||||
|
let key_down : Sdl.keycode = 0x40000051
|
||||||
|
let key_left : Sdl.keycode = 0x40000050
|
||||||
|
let key_right : Sdl.keycode = 0x4000004f
|
||||||
|
end
|
||||||
|
|
||||||
|
module Display = struct
|
||||||
|
open Tgles2
|
||||||
|
open Tsdl
|
||||||
|
open Gg
|
||||||
|
open Wall
|
||||||
|
module I = Image
|
||||||
|
module P = Path
|
||||||
|
|
||||||
|
let ( >>>= ) x f =
|
||||||
|
match x with Ok a -> f a | Error _ as result -> result
|
||||||
|
|
||||||
|
let get_result = function
|
||||||
|
| Ok x -> x
|
||||||
|
| Error (`Msg msg) -> failwith msg
|
||||||
|
|
||||||
|
(* current window state to be passed to window renderer *)
|
||||||
|
type state =
|
||||||
|
{ box: box2
|
||||||
|
(* This is cannonically box within which the next element should draw *)
|
||||||
|
; time: float
|
||||||
|
; wall: Wall.renderer }
|
||||||
|
|
||||||
|
(* the box2 here is cannonically the place the returner drew
|
||||||
|
(the Wall.image extents) *)
|
||||||
|
type image = box2 * Wall.image
|
||||||
|
type pane = state -> state * image
|
||||||
|
type actor = (Event.events -> pane Lwt.t) ref
|
||||||
|
|
||||||
|
let pane_empty s =
|
||||||
|
(s, (Box2.of_pts (Box2.o s.box) (Box2.o s.box), Image.empty))
|
||||||
|
|
||||||
|
type frame =
|
||||||
|
{ sdl_win: Sdl.window
|
||||||
|
; gl: Sdl.gl_context
|
||||||
|
; wall: Wall.renderer
|
||||||
|
; mutable last_pane: pane
|
||||||
|
; mutable quit: bool
|
||||||
|
; mutable fullscreen: bool }
|
||||||
|
|
||||||
|
let ticks () = Int32.to_float (Sdl.get_ticks ()) /. 1000.
|
||||||
|
|
||||||
|
let on_failure ~cleanup result =
|
||||||
|
(match result with Ok _ -> () | Error _ -> cleanup ()) ;
|
||||||
|
result
|
||||||
|
|
||||||
|
let video_initialized = lazy (Sdl.init Sdl.Init.video)
|
||||||
|
|
||||||
|
let make_frame ?(title = "komm") ~w ~h () =
|
||||||
|
Lazy.force video_initialized
|
||||||
|
>>>= fun () ->
|
||||||
|
Sdl.create_window ~w ~h title
|
||||||
|
Sdl.Window.(
|
||||||
|
opengl + allow_highdpi + resizable (*+ input_grabbed*))
|
||||||
|
>>>= fun sdl_win ->
|
||||||
|
Sdl.set_window_title sdl_win title ;
|
||||||
|
ignore (Sdl.gl_set_swap_interval (-1)) ;
|
||||||
|
ignore (Sdl.gl_set_attribute Sdl.Gl.stencil_size 1) ;
|
||||||
|
on_failure
|
||||||
|
( Sdl.gl_create_context sdl_win
|
||||||
|
>>>= fun gl ->
|
||||||
|
let wall =
|
||||||
|
Wall.Renderer.create ~antialias:true ~stencil_strokes:true ()
|
||||||
|
in
|
||||||
|
Ok
|
||||||
|
{ sdl_win
|
||||||
|
; gl
|
||||||
|
; wall
|
||||||
|
; quit= false
|
||||||
|
; fullscreen= false
|
||||||
|
; last_pane= pane_empty } )
|
||||||
|
~cleanup:(fun () -> Sdl.destroy_window sdl_win)
|
||||||
|
|
||||||
|
let handle_frame_events frame events =
|
||||||
|
List.iter
|
||||||
|
(fun (e : Event.t) ->
|
||||||
|
match e with
|
||||||
|
| `Quit -> frame.quit <- true
|
||||||
|
| `Fullscreen a ->
|
||||||
|
frame.fullscreen <- a ;
|
||||||
|
ignore (Sdl.show_cursor (not frame.fullscreen) : _ result) ;
|
||||||
|
ignore
|
||||||
|
( Sdl.set_window_fullscreen frame.sdl_win
|
||||||
|
( if frame.fullscreen then
|
||||||
|
Sdl.Window.fullscreen_desktop
|
||||||
|
else Sdl.Window.windowed )
|
||||||
|
: _ result )
|
||||||
|
| _ -> () )
|
||||||
|
events
|
||||||
|
|
||||||
|
let draw_pane frame pane =
|
||||||
|
let width, height = Sdl.gl_get_drawable_size frame.sdl_win in
|
||||||
|
let _, (_, image) =
|
||||||
|
pane
|
||||||
|
{ box= Box2.v (P2.v 0. 0.) (P2.v (float width) (float height))
|
||||||
|
; time= ticks ()
|
||||||
|
; wall= frame.wall } in
|
||||||
|
Sdl.gl_make_current frame.sdl_win frame.gl
|
||||||
|
>>>= fun () ->
|
||||||
|
Gl.viewport 0 0 width height ;
|
||||||
|
Gl.clear_color 0.0 0.0 0.0 1.0 ;
|
||||||
|
Gl.(
|
||||||
|
clear
|
||||||
|
(color_buffer_bit lor depth_buffer_bit lor stencil_buffer_bit)) ;
|
||||||
|
Gl.enable Gl.blend ;
|
||||||
|
Gl.blend_func_separate Gl.one Gl.src_alpha Gl.one
|
||||||
|
Gl.one_minus_src_alpha ;
|
||||||
|
Gl.enable Gl.cull_face_enum ;
|
||||||
|
Gl.disable Gl.depth_test ;
|
||||||
|
let width = float width and height = float height in
|
||||||
|
Wall.Renderer.render frame.wall ~width ~height image ;
|
||||||
|
Sdl.gl_swap_window frame.sdl_win ;
|
||||||
|
Ok ()
|
||||||
|
|
||||||
|
let rec get_events () : Event.t list =
|
||||||
|
(* create and fill event list *)
|
||||||
|
let ev = Sdl.Event.create () in
|
||||||
|
if Sdl.poll_event (Some ev) then
|
||||||
|
match Event.event_of_sdlevent ev with
|
||||||
|
| Some e -> get_events () @ [e]
|
||||||
|
| None -> get_events ()
|
||||||
|
else []
|
||||||
|
|
||||||
|
let successful_actor = ref (fun _ -> Lwt.return pane_empty)
|
||||||
|
|
||||||
|
let display_frame frame (actor : actor) =
|
||||||
|
let events = get_events () in
|
||||||
|
handle_frame_events frame events ;
|
||||||
|
if List.length events > 0 then (
|
||||||
|
(* recompute the actor definition with the new events to return a new pane *)
|
||||||
|
( try
|
||||||
|
!actor events
|
||||||
|
>|= fun p ->
|
||||||
|
successful_actor := !actor ;
|
||||||
|
p
|
||||||
|
with e ->
|
||||||
|
F.epr
|
||||||
|
"Display.display_frame (!actor events) failed with:@. %s \
|
||||||
|
@."
|
||||||
|
(Printexc.to_string e) ;
|
||||||
|
actor := !successful_actor ;
|
||||||
|
!actor events )
|
||||||
|
>>= fun p ->
|
||||||
|
frame.last_pane <- p ;
|
||||||
|
(* call draw_pane because we should redraw now that we have updated *)
|
||||||
|
ignore (draw_pane frame frame.last_pane) ;
|
||||||
|
Lwt.return_unit )
|
||||||
|
else Lwt.return_unit
|
||||||
|
|
||||||
|
let run frame actor () =
|
||||||
|
let frame = get_result frame in
|
||||||
|
Sdl.show_window frame.sdl_win ;
|
||||||
|
let rec loop () =
|
||||||
|
Lwt.pause () (* seems required for the irc connection to work *)
|
||||||
|
>>= fun () ->
|
||||||
|
Lwt_unix.sleep 0.030
|
||||||
|
>>= fun () ->
|
||||||
|
display_frame frame actor
|
||||||
|
>>= fun () ->
|
||||||
|
if not frame.quit then loop () else Lwt.return_unit in
|
||||||
|
Lwt_main.run (loop ()) ;
|
||||||
|
print_endline "quit" ;
|
||||||
|
Sdl.hide_window frame.sdl_win ;
|
||||||
|
Sdl.gl_delete_context frame.gl ;
|
||||||
|
Sdl.destroy_window frame.sdl_win ;
|
||||||
|
Sdl.quit () ;
|
||||||
|
()
|
||||||
|
|
||||||
|
let gray ?(a = 1.0) v = Color.v v v v a
|
||||||
|
|
||||||
|
module FontCache = Map.Make (String)
|
||||||
|
|
||||||
|
let font_cache = ref FontCache.empty
|
||||||
|
|
||||||
|
let load_font name =
|
||||||
|
match FontCache.find_opt name !font_cache with
|
||||||
|
| Some font -> font
|
||||||
|
| None -> (
|
||||||
|
let ic = open_in_bin name in
|
||||||
|
let dim = in_channel_length ic in
|
||||||
|
let fd = Unix.descr_of_in_channel ic in
|
||||||
|
let buffer =
|
||||||
|
Unix.map_file fd Bigarray.int8_unsigned Bigarray.c_layout
|
||||||
|
false [|dim|]
|
||||||
|
|> Bigarray.array1_of_genarray in
|
||||||
|
let offset = List.hd (Stb_truetype.enum buffer) in
|
||||||
|
match Stb_truetype.init buffer offset with
|
||||||
|
| None -> assert false
|
||||||
|
| Some font ->
|
||||||
|
font_cache := FontCache.add name font !font_cache ;
|
||||||
|
font )
|
||||||
|
|
||||||
|
let font_icons = lazy (load_font "fonts/entypo.ttf")
|
||||||
|
let font_sans = lazy (load_font "fonts/Roboto-Regular.ttf")
|
||||||
|
let font_sans_bold = lazy (load_font "fonts/Roboto-Bold.ttf")
|
||||||
|
let font_sans_light = lazy (load_font "fonts/Roboto-Light.ttf")
|
||||||
|
let font_sans_italic = lazy (load_font "fonts/Roboto-Italic.ttf")
|
||||||
|
|
||||||
|
let font_sans_bold_italic =
|
||||||
|
lazy (load_font "fonts/Roboto-BoldItalic.ttf")
|
||||||
|
|
||||||
|
let font_serif =
|
||||||
|
lazy (load_font "fonts/ScheherazadeNew-Regular.ttf")
|
||||||
|
|
||||||
|
let font_serif_bold =
|
||||||
|
lazy (load_font "fonts/ScheherazadeNew-Bold.ttf")
|
||||||
|
|
||||||
|
let font_mono = lazy (load_font "fonts/static/RobotoMono-Regular")
|
||||||
|
|
||||||
|
let font_mono_bold =
|
||||||
|
lazy (load_font "fonts/static/RobotoMono-Regular")
|
||||||
|
|
||||||
|
let font_mono_light =
|
||||||
|
lazy (load_font "fonts/static/RobotoMono-Regular")
|
||||||
|
|
||||||
|
let font_emoji = lazy (load_font "fonts/NotoEmoji-Regular.ttf")
|
||||||
|
|
||||||
|
let str_of_box b =
|
||||||
|
Printf.sprintf "(ox:%0.1f oy:%0.1f ex%0.1f ey%0.1f)" (Box2.ox b)
|
||||||
|
(Box2.oy b) (Box2.maxx b) (Box2.maxy b)
|
||||||
|
|
||||||
|
let draw_label text b =
|
||||||
|
let f =
|
||||||
|
Wall_text.Font.make ~size:(Box2.h b) (Lazy.force font_sans)
|
||||||
|
in
|
||||||
|
( Box2.v (Box2.o b)
|
||||||
|
(P2.v (Wall_text.Font.text_width f text) (Box2.h b))
|
||||||
|
, I.paint
|
||||||
|
(Paint.color (gray ~a:0.5 1.0))
|
||||||
|
Wall_text.(
|
||||||
|
simple_text f ~valign:`BASELINE ~halign:`LEFT ~x:(Box2.ox b)
|
||||||
|
~y:(Box2.oy b +. (Box2.h b *. 0.75))
|
||||||
|
text) )
|
||||||
|
|
||||||
|
let fill_box c b =
|
||||||
|
( b
|
||||||
|
, I.paint (Paint.color c)
|
||||||
|
( I.fill_path
|
||||||
|
@@ fun t ->
|
||||||
|
P.rect t ~x:(Box2.ox b) ~y:(Box2.oy b) ~w:(Box2.w b)
|
||||||
|
~h:(Box2.h b) ) )
|
||||||
|
|
||||||
|
let draw_filled_box c (s : state) = (s, fill_box c s.box)
|
||||||
|
|
||||||
|
let path_box c b (s : state) =
|
||||||
|
( s
|
||||||
|
, ( b
|
||||||
|
, I.paint (Paint.color c)
|
||||||
|
( I.stroke_path (Outline.make ())
|
||||||
|
@@ fun t ->
|
||||||
|
P.rect t ~x:(Box2.ox b) ~y:(Box2.oy b) ~w:(Box2.w b)
|
||||||
|
~h:(Box2.h b) ) ) )
|
||||||
|
|
||||||
|
let path_circle c b (s : state) =
|
||||||
|
( s
|
||||||
|
, ( b
|
||||||
|
, I.paint (Paint.color c)
|
||||||
|
( I.stroke_path (Outline.make ())
|
||||||
|
@@ fun t ->
|
||||||
|
P.circle t ~cx:(Box2.midx b) ~cy:(Box2.midy b)
|
||||||
|
~r:(Box2.w b /. 2.) ) ) )
|
||||||
|
|
||||||
|
(** Display.state.box as supplied to a widget defines the allowed drawing area for the widget.
|
||||||
|
This way basic widgets will just expand to the full area of a box, while other widgets can have
|
||||||
|
the express purpose of limiting the size of an object in a larger system of limitations.
|
||||||
|
|
||||||
|
Panes return a tuple: (state, (box, image))
|
||||||
|
state is the updated state, where state.box is always
|
||||||
|
- the top left corner of the box the pane drew in, and
|
||||||
|
- the bottom right corner of the state.box that was passed in
|
||||||
|
box is the area the widget actually drew in (or wants to sort of "use")
|
||||||
|
image is the Wall.image to compose with other panes and draw to the display
|
||||||
|
*)
|
||||||
|
|
||||||
|
let simple_text f text (s : state) =
|
||||||
|
let fm = Wall_text.Font.font_metrics f in
|
||||||
|
let font_height = fm.ascent -. fm.descent +. fm.line_gap in
|
||||||
|
let tm = Wall_text.Font.text_measure f text in
|
||||||
|
let br_pt =
|
||||||
|
P2.v (Box2.ox s.box +. tm.width) (Box2.oy s.box +. font_height)
|
||||||
|
in
|
||||||
|
let bextent = Box2.of_pts (Box2.o s.box) br_pt in
|
||||||
|
(* let _, (_, redbox) = path_box Color.red bextent s in*)
|
||||||
|
( {s with box= Box2.of_pts (Box2.br_pt bextent) (Box2.max s.box)}
|
||||||
|
, ( bextent
|
||||||
|
, (* I.stack redbox *)
|
||||||
|
I.paint
|
||||||
|
(Paint.color (gray ~a:0.5 1.0))
|
||||||
|
Wall_text.(
|
||||||
|
simple_text f ~valign:`BASELINE ~halign:`LEFT
|
||||||
|
~x:(Box2.ox s.box)
|
||||||
|
~y:(Box2.oy s.box +. fm.ascent)
|
||||||
|
text) ) )
|
||||||
|
|
||||||
|
let pane_box next_point_func (subpanes : pane list) (so : state) =
|
||||||
|
let sr, (br, ir) =
|
||||||
|
List.fold_left
|
||||||
|
(fun (sp, (bp, ip)) (pane : pane) ->
|
||||||
|
(* uses br to hold max extent of boxes *)
|
||||||
|
let sr, (br, ir) = pane sp in
|
||||||
|
(* draw the pane *)
|
||||||
|
let _, (_, irb) = path_box Color.blue br sr in
|
||||||
|
(* draw the box around the pane *)
|
||||||
|
( { sr with
|
||||||
|
box= Box2.of_pts (next_point_func br) (Box2.max sp.box)
|
||||||
|
}
|
||||||
|
, ( Box2.of_pts (Box2.o bp)
|
||||||
|
(P2.v
|
||||||
|
(max (Box2.maxx br) (Box2.maxx bp))
|
||||||
|
(max (Box2.maxy br) (Box2.maxy bp)) )
|
||||||
|
, Image.seq [ip; irb; ir] ) ) )
|
||||||
|
( so
|
||||||
|
, (Box2.of_pts (Box2.o so.box) (Box2.o so.box), Image.empty)
|
||||||
|
)
|
||||||
|
subpanes in
|
||||||
|
let _, (_, redbox) = path_box Color.red br sr in
|
||||||
|
(sr, (br, Image.stack redbox ir))
|
||||||
|
end
|
||||||
122
boot_js.ml
Normal file
122
boot_js.ml
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
open Js_of_ocaml
|
||||||
|
open Lwt.Infix
|
||||||
|
module NVG = Graphv_webgl
|
||||||
|
|
||||||
|
let _ =
|
||||||
|
Logs.set_reporter (Human.Logs_reporter.console_reporter ());
|
||||||
|
Logs.set_level (Some Debug)
|
||||||
|
|
||||||
|
module Log = (val Logs.src_log Logs.default : Logs.LOG)
|
||||||
|
|
||||||
|
(* This scales the canvas to match the DPI of the window,
|
||||||
|
it prevents blurriness when rendering to the canvas *)
|
||||||
|
let scale_canvas (canvas : Dom_html.canvasElement Js.t) =
|
||||||
|
let dpr = Dom_html.window##.devicePixelRatio in
|
||||||
|
let rect = canvas##getBoundingClientRect in
|
||||||
|
let width = rect##.right -. rect##.left in
|
||||||
|
let height = rect##.bottom -. rect##.top in
|
||||||
|
canvas##.width := width *. dpr |> int_of_float;
|
||||||
|
canvas##.height := height *. dpr |> int_of_float;
|
||||||
|
let width =
|
||||||
|
Printf.sprintf "%dpx" (int_of_float width) |> Js.string
|
||||||
|
in
|
||||||
|
let height =
|
||||||
|
Printf.sprintf "%dpx" (int_of_float height) |> Js.string
|
||||||
|
in
|
||||||
|
canvas##.style##.width := width;
|
||||||
|
canvas##.style##.height := height
|
||||||
|
|
||||||
|
let webgl_initialize canvas =
|
||||||
|
scale_canvas canvas;
|
||||||
|
(* Graphv requires a stencil buffer to work properly *)
|
||||||
|
let attrs = WebGL.defaultContextAttributes in
|
||||||
|
attrs##.stencil := Js._true;
|
||||||
|
match
|
||||||
|
WebGL.getContextWithAttributes canvas attrs |> Js.Opt.to_option
|
||||||
|
with
|
||||||
|
| None ->
|
||||||
|
print_endline "Sorry your browser does not support WebGL";
|
||||||
|
raise Exit
|
||||||
|
| Some ctx -> ctx
|
||||||
|
|
||||||
|
let graphv_initialize webgl_ctx =
|
||||||
|
let open NVG in
|
||||||
|
let vg =
|
||||||
|
create
|
||||||
|
~flags:CreateFlags.(antialias lor stencil_strokes)
|
||||||
|
webgl_ctx
|
||||||
|
in
|
||||||
|
(* File in this case is actually the CSS font name *)
|
||||||
|
Text.create vg ~name:"sans" ~file:"sans" |> ignore;
|
||||||
|
webgl_ctx##clearColor 0.3 0.3 0.32 1.;
|
||||||
|
vg
|
||||||
|
|
||||||
|
let request_animation_frame () =
|
||||||
|
let t, s = Lwt.wait () in
|
||||||
|
let (_ : Dom_html.animation_frame_request_id) =
|
||||||
|
Dom_html.window##requestAnimationFrame
|
||||||
|
(Js.wrap_callback (fun (time : float) -> Lwt.wakeup s time))
|
||||||
|
in
|
||||||
|
t
|
||||||
|
|
||||||
|
let render_stream canvas webgl_ctx vg
|
||||||
|
(render : NVG.t -> ?time:float -> Gg.p2 -> Human.I.t -> unit) :
|
||||||
|
Human.I.t Lwt_stream.t -> unit Lwt.t =
|
||||||
|
Lwt_stream.iter_n (fun i ->
|
||||||
|
request_animation_frame () >>= fun time ->
|
||||||
|
webgl_ctx##clear
|
||||||
|
(webgl_ctx##._COLOR_BUFFER_BIT_
|
||||||
|
lor webgl_ctx##._DEPTH_BUFFER_BIT_
|
||||||
|
lor webgl_ctx##._STENCIL_BUFFER_BIT_);
|
||||||
|
let device_ratio = Dom_html.window##.devicePixelRatio in
|
||||||
|
NVG.begin_frame vg ~width:canvas##.width ~height:canvas##.height
|
||||||
|
~device_ratio;
|
||||||
|
NVG.Transform.scale vg ~x:device_ratio ~y:device_ratio;
|
||||||
|
render vg ~time Gg.P2.o i;
|
||||||
|
NVG.end_frame vg;
|
||||||
|
Lwt.return_unit)
|
||||||
|
|
||||||
|
open Human
|
||||||
|
|
||||||
|
let _ =
|
||||||
|
let canvas =
|
||||||
|
Js.Unsafe.coerce (Dom_html.getElementById_exn "canvas")
|
||||||
|
in
|
||||||
|
let webgl_ctx = webgl_initialize canvas in
|
||||||
|
let vg = graphv_initialize webgl_ctx in
|
||||||
|
let open Js_of_ocaml_lwt.Lwt_js_events in
|
||||||
|
let open Nottui in
|
||||||
|
let gravity_pad = Gravity.make ~h:`Negative ~v:`Negative in
|
||||||
|
let gravity_crop = Gravity.make ~h:`Positive ~v:`Negative in
|
||||||
|
let body = Lwd.var (Lwd.pure Ui.empty) in
|
||||||
|
let wm = Widgets.window_manager (Lwd.join (Lwd.get body)) in
|
||||||
|
Nav.test_pull () >>= fun test_store ->
|
||||||
|
let ui = Widgets.(h_node_area (test_store, [ [] ])) in
|
||||||
|
let root =
|
||||||
|
Lwd.set body
|
||||||
|
(Lwd.map ~f:(Ui.resize ~pad:gravity_pad ~crop:gravity_crop) ui);
|
||||||
|
Widgets.window_manager_view wm
|
||||||
|
in
|
||||||
|
|
||||||
|
let events, push_event = Lwt_stream.create () in
|
||||||
|
let images =
|
||||||
|
Human.Nottui_lwt.render vg
|
||||||
|
~size:(Gg.P2.v canvas##.width canvas##.height)
|
||||||
|
events root
|
||||||
|
in
|
||||||
|
async (fun () ->
|
||||||
|
render_stream canvas webgl_ctx vg
|
||||||
|
(fun vg ?(time = 0.) p i ->
|
||||||
|
let _ = time in
|
||||||
|
Log.debug (fun m ->
|
||||||
|
m "Drawing image: p=%a n=%a" Gg.V2.pp p
|
||||||
|
(I.Draw.pp ~attr:A.dark)
|
||||||
|
i);
|
||||||
|
let p' = I.Draw.node vg A.dark p i in
|
||||||
|
Logs.debug (fun m ->
|
||||||
|
m "Drawing finished: p'=%a" Gg.V2.pp p'))
|
||||||
|
images);
|
||||||
|
buffered_loop (make_event Dom_html.Event.keydown) Dom_html.document
|
||||||
|
(fun ev _ ->
|
||||||
|
Lwt.return
|
||||||
|
@@ push_event (Some (`Keys [ Event_js.evt_of_jskey ev ])))
|
||||||
7
cors_proxy.sh
Executable file
7
cors_proxy.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ ! -f /tmp/key.pem ]; then
|
||||||
|
echo Creating key
|
||||||
|
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout /tmp/key.pem -out /tmp/cert.pem -batch
|
||||||
|
fi
|
||||||
|
|
||||||
|
npx http-server --cors -S -P https://gitea.departmentofinter.net --log-ip -c-1 -C /tmp/cert.pem -K /tmp/key.pem
|
||||||
94
dune
94
dune
@ -1,78 +1,30 @@
|
|||||||
(env
|
(env
|
||||||
(dev
|
(dev (flags (:standard -warn-error -A))
|
||||||
(flags (:standard -warn-error -A))))
|
(js_of_ocaml (flags --no-inline --pretty --source-map-inline --debug-info)
|
||||||
|
(build_runtime_flags --no-inline --pretty --source-map-inline --debug-info)
|
||||||
(library
|
(link_flags --source-map-inline))))
|
||||||
(name human)
|
|
||||||
(modes byte)
|
|
||||||
(modules human)
|
|
||||||
(libraries
|
|
||||||
topinf
|
|
||||||
lwt_ppx
|
|
||||||
tsdl
|
|
||||||
tgls.tgles2
|
|
||||||
wall
|
|
||||||
zed
|
|
||||||
lambda-term
|
|
||||||
irmin-unix
|
|
||||||
nottui
|
|
||||||
nottui-pretty
|
|
||||||
uuseg.string
|
|
||||||
uutf
|
|
||||||
uucp
|
|
||||||
ocaml-compiler-libs.common
|
|
||||||
ocaml-compiler-libs.bytecomp
|
|
||||||
ocaml-compiler-libs.toplevel))
|
|
||||||
|
|
||||||
|
|
||||||
(executable
|
(executable
|
||||||
(name irc)
|
(name boot_js)
|
||||||
(modes byte)
|
(modes byte js)
|
||||||
(modules irc)
|
(preprocess (pps js_of_ocaml-ppx))
|
||||||
|
|
||||||
|
(modules boot_js human)
|
||||||
(libraries
|
(libraries
|
||||||
human
|
|
||||||
lwt
|
|
||||||
fmt
|
fmt
|
||||||
topinf
|
logs
|
||||||
lwt_ppx
|
graphv_webgl
|
||||||
irc-client
|
js_of_ocaml-lwt
|
||||||
irc-client-lwt
|
digestif.ocaml
|
||||||
irc-client-unix
|
checkseum.ocaml
|
||||||
irc-client-tls
|
irmin.mem
|
||||||
nottui-lwt
|
git
|
||||||
nottui-pretty
|
irmin-git
|
||||||
|
cohttp-lwt-jsoo
|
||||||
|
mimic
|
||||||
|
uri
|
||||||
|
zed
|
||||||
|
gg
|
||||||
|
lwd
|
||||||
))
|
))
|
||||||
|
|
||||||
(executable
|
|
||||||
(name boot)
|
|
||||||
(modes byte)
|
|
||||||
(modules boot)
|
|
||||||
(link_flags (-linkall))
|
|
||||||
(libraries
|
|
||||||
lwt_ppx
|
|
||||||
lambda-term
|
|
||||||
topinf))
|
|
||||||
|
|
||||||
(library
|
|
||||||
(name topinf)
|
|
||||||
(modes byte)
|
|
||||||
(modules topinf)
|
|
||||||
(libraries
|
|
||||||
fmt
|
|
||||||
tsdl
|
|
||||||
tgls.tgles2
|
|
||||||
wall
|
|
||||||
zed
|
|
||||||
lambda-term
|
|
||||||
irmin-unix
|
|
||||||
nottui
|
|
||||||
nottui-pretty
|
|
||||||
nottui-lwt
|
|
||||||
uuseg
|
|
||||||
irc-client
|
|
||||||
irc-client-lwt
|
|
||||||
irc-client-unix
|
|
||||||
irc-client-tls
|
|
||||||
ocaml-compiler-libs.common
|
|
||||||
ocaml-compiler-libs.bytecomp
|
|
||||||
ocaml-compiler-libs.toplevel))
|
|
||||||
|
|||||||
@ -1,3 +1,2 @@
|
|||||||
(lang dune 2.8)
|
(lang dune 3.4)
|
||||||
(name komm)
|
(name boot)
|
||||||
(wrapped_executables false)
|
|
||||||
|
|||||||
35
index.html
Normal file
35
index.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<canvas id='canvas'></canvas>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script
|
||||||
|
type='text/javascript'
|
||||||
|
defer
|
||||||
|
src='_build/default/boot_js.bc.js'>
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
44
notes.org
Normal file
44
notes.org
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
* mvp todo
|
||||||
|
|
||||||
|
|
||||||
|
** toplevel repl in js_of_ocaml
|
||||||
|
** git pull from gitea.departmentofinter.net/console/boot
|
||||||
|
** git push to gitea.departmentofinter.net/console/boot
|
||||||
|
** execute a git file execution in top level
|
||||||
|
** display arbitrary git file from pulled repo
|
||||||
|
** edit arbitrary file with common emacs bindings
|
||||||
|
*** move left and right by character
|
||||||
|
*** move up and down by line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* other todo
|
||||||
|
*** yank (to clipboard) next char
|
||||||
|
*** move left and right by word and sentance
|
||||||
|
*** region select
|
||||||
|
|
||||||
|
|
||||||
|
* principles?
|
||||||
|
an "anywhere" programming environment
|
||||||
|
|
||||||
|
* 221211
|
||||||
|
ok you got the scroll box mostly working so next:
|
||||||
|
** fix the scroll jump bugs
|
||||||
|
** setup better keybindings
|
||||||
|
** fix cursor and active focus indicators
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* 221210 -
|
||||||
|
** need to resolve the issue with the ui.t Resize type.
|
||||||
|
this is an issue with the direction of the determination of the .height and .width fields of Ui.t
|
||||||
|
|
||||||
|
currently you were planning to combine update_sensors and update_size
|
||||||
|
|
||||||
|
in the original nottui.ml library, are Ui.t.w and Ui.t.h determined from the top down orbottom up?
|
||||||
|
the bottom up, becahse they are chars
|
||||||
|
|
||||||
|
|
||||||
37
unicom.org
Normal file
37
unicom.org
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
UNICOM
|
||||||
|
|
||||||
|
unifying tools for thought and commmunication
|
||||||
|
|
||||||
|
At the top level is a kind of "trace" that connects all the tools together
|
||||||
|
and records the exact use of all the tools in a session. Traces are the only
|
||||||
|
kind of document in the system, and are basically written by a user when
|
||||||
|
they interact with the system. Users can store, retrieve, view, and modify
|
||||||
|
traces as a way of controlling system state, retrieving history, and sharing
|
||||||
|
information?
|
||||||
|
|
||||||
|
|
||||||
|
tools for thought:
|
||||||
|
- todo lists
|
||||||
|
- personal journal
|
||||||
|
- calendar
|
||||||
|
- calculator/spreadsheet
|
||||||
|
- health, fitness, finance data tracking, analysis
|
||||||
|
- Integrated Development Environment [for development/configuration of all these tools]
|
||||||
|
|
||||||
|
|
||||||
|
tools for communication:
|
||||||
|
- collaborative documents
|
||||||
|
video / .txt file
|
||||||
|
- content discovery,display,labeling?
|
||||||
|
twitter / netflix / books
|
||||||
|
- direct messages
|
||||||
|
sms / email
|
||||||
|
- group messages
|
||||||
|
private (chat) / private (irc,twitter)
|
||||||
|
- audio/music production
|
||||||
|
sound driver / DAW
|
||||||
|
- cad
|
||||||
|
KiCad / OpenSCAD
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user