From e6eee86a91684f263e460eb42bd532ac4beb13c2 Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Sat, 25 Dec 2021 13:26:00 -0600 Subject: [PATCH] Move repl / inspector to new imgui * make views pin scrolling to bottom * support multiline labels (no wordwrap yet) * always expand groups (don't clear after populating form) --- editor/imgui.fnl | 21 +++++++++------- editor/repl.fnl | 15 ++++++------ editor/replview.fnl | 44 +++++++++++++--------------------- inspector/init.fnl | 58 +++++++++++++++++---------------------------- 4 files changed, 59 insertions(+), 79 deletions(-) diff --git a/editor/imgui.fnl b/editor/imgui.fnl index 69f5e43..8c704f4 100644 --- a/editor/imgui.fnl +++ b/editor/imgui.fnl @@ -27,7 +27,9 @@ :view self} (or ?overrides {}))) (fn view.end-scroll [self {: y : h}] - (set self.scrollheight (- (+ y (or h 0) style.padding.y) (+ self.position.y style.padding.y (- self.scroll.y))))) + (let [pin-to-bottom (>= self.scroll.to.y (- self.scrollheight self.size.y))] + (set self.scrollheight (- (+ y (or h 0) style.padding.y) (+ self.position.y style.padding.y (- self.scroll.y)))) + (when pin-to-bottom (set self.scroll.to.y (- self.scrollheight self.size.y))))) (fn view.draw [self] (set self.cursor nil) (self.__index.draw self) @@ -127,7 +129,10 @@ (fn [form coord-key size-key] (let [coord-group (. group coord-key) size-group (. group size-key) coord-form (. form coord-key) size-form (. form size-key)] - (if (= coord-group nil) ; container takes on the size of its first item + (if (= size-form nil) ; tried to add an unsized value to the group, ignore + nil + + (= coord-group nil) ; container takes on the size of its first item (do (tset group coord-key coord-form) (tset group size-key size-form)) @@ -146,9 +151,7 @@ (update-dimensions ?form) (table.unpack result)) [:table form] (update-dimensions form) - [:nil] (do (lume.extend orig-form group) - (lume.clear group) - orig-form))))) + [:nil] (lume.extend orig-form group))))) (fn horiz-wrapper [{:x orig-x :w orig-w}] (fn [{: x : y : w : h : xpad : ypad &as form} overrides] @@ -164,14 +167,16 @@ (and (active? view tag) (= view.imstate.left :released) (mouse-inside x y w h))) (fn label [form text] - (let [{: x : y : w : h : halign : valign : font : color} + (let [(_ newlines) (text:gsub "\n" "\n") + text-height (fn [font] (* (font:get_height) (+ newlines 1))) + {: x : y : w : h : halign : valign : font : color} (with-style form :w #($1.font:get_width text) - :h #($1.font:get_height) + :h #(text-height $1.font) :halign :left :valign :center) x (match halign :left x :center (+ x (/ (- w (font:get_width text)) 2)) :right (+ x w (- (font:get_width text)))) - y (match valign :top y :center (+ y (/ (- h (font:get_height)) 2)) :bottom (+ y h (- (font:get_height))))] + y (match valign :top y :center (+ y (/ (- h (text-height font)) 2)) :bottom (+ y h (- (text-height font))))] (renderer.draw_text font text x y color))) (fn textbutton [form label] diff --git a/editor/repl.fnl b/editor/repl.fnl index 90cd3f1..b84bca6 100644 --- a/editor/repl.fnl +++ b/editor/repl.fnl @@ -2,23 +2,22 @@ (local fennel (require :lib.fennel)) (local style (require :core.style)) (local lume (require :lib.lume)) -(local {: textbutton} (util.require :editor.imstate)) +(local {: textbutton : under : group-wrapper} (util.require :editor.imgui)) (local {: inspect} (util.require :inspector)) (local repl (util.hot-table ...)) -(fn repl.inspector [{: vals : states} view x y] - (var h 0) - (each [i v (ipairs vals)] - (set h (+ h (inspect (. states i) v view x (+ y h) view.size.x)))) - (+ h style.padding.y)) +(fn repl.inspector [{: w &as form} {: vals : states}] + (let [g (group-wrapper form)] + (each [i v (ipairs vals)] + (g #(inspect $...) (under (g) {: w}) (. states i) v)) + (g))) (fn repl.notify [listeners line] (each [_ listener (ipairs listeners)] (listener:append line))) (fn repl.mk-result [vals] - (local inspector #(repl.inspector $...)) - {:draw inspector : vals :states (icollect [_ (ipairs vals)] {})}) + {:draw repl.inspector : vals :states (icollect [_ (ipairs vals)] {})}) (fn repl.run [{: listeners}] (fennel.repl {:readChunk coroutine.yield diff --git a/editor/replview.fnl b/editor/replview.fnl index 62027e5..134ad54 100644 --- a/editor/replview.fnl +++ b/editor/replview.fnl @@ -1,5 +1,5 @@ (local util (require :lib.util)) -(local {: attach-imstate : textbox : textbutton : mouse-inside} (util.require :editor.imstate)) +(local {: attach-imstate : textbox : textbutton : label : under : reform : group-wrapper : mouse-inside} (util.require :editor.imgui)) (local View (require :core.view)) (local style (require :core.style)) @@ -25,44 +25,34 @@ (fn ReplView.append [self line] (table.insert self.log line)) -(fn ReplView.draw-cmd [{: cmd} view x y iline] - (renderer.draw_text style.font cmd x y style.text) - (when (mouse-inside x y view.size.x (style.font:get_height)) - (when (textbutton view :X (+ x view.size.x -35) y) +(fn ReplView.draw-cmd [{: x : y : w : view &as form} {: cmd} iline] + (label form cmd) + (when (mouse-inside x y w form.h) + (when (textbutton (reform form {:x (+ x w -35) :into {}}) :X) (table.remove view.log iline) (table.remove view.log iline)) - (when (textbutton view :! (+ x view.size.x -60) y) - (view:submit cmd))) - (+ (style.font:get_height) style.padding.y)) + (when (textbutton (reform form {:x (+ x w -60) :into {}}) :!) + (view:submit cmd)))) (fn ReplView.submit [self ?cmd] (local cmd (or ?cmd self.cmd)) (when (= ?cmd nil) (set self.cmd "")) - (self:append {:draw #(self.draw-cmd $...) : cmd}) + (self:append {:draw self.draw-cmd : cmd}) (self.conn:submit cmd)) (fn ReplView.draw [self] (self:draw_background style.background) (self:draw_scrollbar) - (var x (- self.position.x self.scroll.x)) - (var y (- self.position.y self.scroll.y)) - (var rendered-h 0) - - ; todo: cache sizes and avoid drawing if offscreen? - ; note: then offscreen items can't be focussed without further effort - ; todo: draw line numbers - (each [i line (ipairs self.log)] - (let [h (line:draw self x y i)] - (set y (+ y h)) - (set rendered-h (+ rendered-h h)))) - - (set self.cmd (textbox self :command self.cmd x y self.size.x)) - - (local pin-to-bottom (>= self.scroll.to.y (- self.scrollheight self.size.y))) - (set self.scrollheight (+ rendered-h (style.font:get_height) 4)) - (when pin-to-bottom - (set self.scroll.to.y (- self.scrollheight self.size.y)))) + (let [{: w &as form} (self:form) + g (group-wrapper form)] + ; todo: cache sizes and avoid drawing if offscreen? + ; note: then offscreen items can't be focussed without further effort + ; todo: draw line numbers + (each [i line (ipairs self.log)] + (g line.draw (under (g) {: w}) line i)) + (set self.cmd (g textbox (under (g) {: w :tag :command}) self.cmd)) + (self:end-scroll (g)))) (fn ReplView.get_name [self] self.title) diff --git a/inspector/init.fnl b/inspector/init.fnl index 9d83900..3aa475c 100644 --- a/inspector/init.fnl +++ b/inspector/init.fnl @@ -1,7 +1,7 @@ (local util (require :lib.util)) (local style (require :core.style)) (local {: defmulti : defmethod} (util.require :lib.multimethod)) -(local {: textbutton} (util.require :editor.imstate)) +(local {: textbutton : label : under : right-of : reform : group-wrapper } (util.require :editor.imgui)) (local inspector (util.hot-table ...)) @@ -15,7 +15,7 @@ best-inspector) (set inspector.inspect - (defmulti (fn [state value view x y w] + (defmulti (fn [form state value] (when (= state.inspector nil) (set state.inspector (inspector.best-inspector value))) state.inspector) :inspect ...)) @@ -26,43 +26,29 @@ (tset inspector.inspectors name {: predicate : priority :inspector inspect-func}) (defmethod inspector.inspect name inspect-func)) -(fn inspector.text-height [text ?font] - (let [font (or ?font style.code_font) - (_ newlines) (text:gsub "\n" "\n")] - (* (font:get_height) (+ newlines 1)))) - -(fn inspector.draw-text [font text x y color] - (renderer.draw_text font text x y color) - (inspector.text-height text)) - -(inspector.register :default 0 #true (fn [state value view x y w] - (inspector.draw-text style.code_font (fv value) x y style.text))) +(inspector.register :default 0 #true (fn [form state value] + (label (reform form {:font style.code_font}) (fv value)))) (inspector.register :table 10 #(and (= (type $1) :table) (not= (next $1) nil)) - (fn [state tbl view x y w] - (local font style.code_font) - (var h 0) - ; todo: state assumes an .inspector key - ; todo: inspector swapping - ; todo: edit in place? - (fn get-kstate [tbl k state] - (when (= nil state.keys) (set state.keys {})) - (when (= nil (?. state.keys k)) - (util.nested-tset state [:keys k] {:collapsed (= (type (. tbl k)) :table) :children {}})) - (. state.keys k)) - (each [k v (pairs tbl)] - (let [kstate (get-kstate tbl k state) - kstr (fv k) - wk (font:get_width kstr) - xoffset (+ wk style.padding.x) - toggle-collapse (textbutton view kstr x (+ y h)) - hv (if kstate.collapsed - (inspector.draw-text font "..." (+ x xoffset) (+ y h) style.syntax.comment) - (inspector.inspect kstate.children v view (+ x xoffset) (+ y h) (- w xoffset)))] - (when toggle-collapse (set kstate.collapsed (not kstate.collapsed))) - (set h (+ h hv style.padding.y)))) - h)) + (fn [form state tbl] + (let [get-kstate (fn [tbl k state] + (when (= nil state.keys) (set state.keys {})) + (when (= nil (?. state.keys k)) + (util.nested-tset state [:keys k] {:collapsed (= (type (. tbl k)) :table) :children {}})) + (. state.keys k)) + g (group-wrapper form)] + (each [k v (pairs tbl)] + (let [kstate (get-kstate tbl k state)] + ; todo: state assumes an .inspector key + ; todo: inspector swapping + ; todo: edit in place? + (when (g textbutton (under form {:font style.code_font}) (fv k)) + (set kstate.collapsed (not kstate.collapsed))) + (if kstate.collapsed + (g label (right-of form {:color style.syntax.comment :into {}}) "...") + (g #(inspector.inspect $...) (right-of form {:into {}}) kstate.children v)) + (g)))))) inspector.hot