From 3af48a84d63ae48856da05e4d364988b3f1e8311 Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Sun, 11 Jul 2021 17:57:33 -0400 Subject: [PATCH] Add custom status bar, timer, section headings --- presentation/commands.fnl | 3 ++ presentation/engine.fnl | 60 ++++++++++++++++++++- presentation/slides.fnl | 44 +++++++++------ support/lite/plugins/statusoverride.lua | 12 +++++ vendor/lite/data/plugins/statusoverride.lua | 1 + 5 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 support/lite/plugins/statusoverride.lua create mode 120000 vendor/lite/data/plugins/statusoverride.lua diff --git a/presentation/commands.fnl b/presentation/commands.fnl index 43b3785..87abfaf 100644 --- a/presentation/commands.fnl +++ b/presentation/commands.fnl @@ -24,11 +24,14 @@ "presentation:prev" #(core.active_view:back) "presentation:next-slide" #(core.active_view:next-slide) "presentation:prev-slide" #(core.active_view:prev-slide) + "presentation:toggle-timer" #(core.active_view:toggle-timer) + "presentation:reset-timer" #(core.active_view:reset-timer) }) (keymap.add { "left" "presentation:prev" "right" "presentation:next" "ctrl+left" "presentation:prev-slide" "ctrl+right" "presentation:next-slide" + "alt+t" "presentation:toggle-timer" }) diff --git a/presentation/engine.fnl b/presentation/engine.fnl index 9f23168..e8a23bc 100644 --- a/presentation/engine.fnl +++ b/presentation/engine.fnl @@ -14,19 +14,36 @@ :table (if elem.button (lume.merge style elem) elem) :string (lume.merge style {:text elem}))))) +(fn slides-target [slides] + (var target 0) + (each [_ slide (ipairs slides)] + (each [_ elem (ipairs slide)] + (when elem.target (set target (+ target elem.target))))) + target) + (fn SlideshowView.new [self slides] (SlideshowView.super.new self) (attach-imstate self) (set self.slides slides) + (set self.total-target (slides-target slides)) (set self.imagecache {}) (set self.islide 1) (set self.ielem 0) (set self.cleanup {}) + (self:cleanup-slide) (self:advance)) (fn SlideshowView.cleanup-slide [self] (each [_ f (pairs self.cleanup)] (f)) - (set self.cleanup {})) + (set self.cleanup {}) + (set self.current-target (slides-target (lume.slice self.slides 1 self.islide))) + (set self.sections (icollect [_ slide (ipairs self.slides)] + (let [{: section} (or (lume.match slide #$1.section) {})] section))) + (var isection-current 0) + (set self.islide-to-isection (icollect [_ slide (ipairs self.slides)] + (let [{: section} (or (lume.match slide #$1.section) {})] + (when section (set isection-current (+ isection-current 1))) + isection-current)))) (fn SlideshowView.next-slide [self] (set self.islide (if (>= self.islide (length self.slides)) 1 (+ self.islide 1))) @@ -123,6 +140,47 @@ (each [ielem element (ipairs (. self.slides self.islide)) :until (> ielem self.ielem)] (set y (self:render-element element (self:this-y element y))))) +; timer +(fn SlideshowView.elapsed [self] + (if self.elapsed-time self.elapsed-time + self.start-time (- (system.get_time) self.start-time) + 0)) + +(fn SlideshowView.toggle-timer [self] + (if (= self.start-time nil) + (set self.start-time (system.get_time)) + + (= self.elapsed-time nil) + (set self.elapsed-time (self:elapsed)) + + (do (set self.start-time (- (system.get_time) self.elapsed-time)) + (set self.elapsed-time nil)))) + +(fn SlideshowView.reset-timer [self] + (set self.elapsed-time nil) + (set self.start-time nil)) + +(fn time [seconds] + (let [sign (if (< seconds 0) "-" "") + seconds (math.abs seconds) + m (math.floor (/ seconds 60)) + s (% seconds 60)] + (string.format "%s%d:%02d" sign m s))) + +; status bar +(fn SlideshowView.status_items [self {: separator : separator2}] + (let [full (renderer.font.load "presentation/font/PrintChar21.ttf" (* 14 SCALE)) + thin (renderer.font.load "presentation/font/PRNumber3.ttf" (* 14 SCALE)) + elapsed (self:elapsed) + left [full "\xE2\x8C\xA5 " thin] + right [thin (time (- self.total-target elapsed)) + full " \xE2\x8C\x9B " + thin (time (- self.current-target elapsed))]] + (each [isection section (ipairs self.sections)] + (when (> isection 1) (lume.push left style.dim " > ")) + (lume.push left (if (= isection (. self.islide-to-isection self.islide)) style.text style.dim) section)) + (values left right))) + (fn SlideshowView.get_name [self] "] KFest 2021") SlideshowView diff --git a/presentation/slides.fnl b/presentation/slides.fnl index 60d67f9..d9ce594 100644 --- a/presentation/slides.fnl +++ b/presentation/slides.fnl @@ -78,25 +78,31 @@ "https://bitbucket.org/SpindleyQ/honeylisp" "https://gamemaking.social/@SpindleyQ" "https://twitter.com/SpindleyQ" - {:pause-after true}] + {:pause-after true} + {:target 30 :section :Intro}] [h "Honeylisp is hard to explain" ** "It is an experimental programming environment designed to enable a productive Apple // game development workflow" - "https://fennel-lang.org/"] + "https://fennel-lang.org/" + {:target 30}] [(bgimg "presentation/pics/pete286.jpeg") h "Some Background" - ** "2019: Built a 16-bit MS-DOS game engine, using only retro hardware and software."] + ** "2019: Built a 16-bit MS-DOS game engine, using only retro hardware and software." + " * Driven by a custom Forth interpreter" + {:target 90}] [(bgimg "presentation/pics/ggj2020.jpeg") h "Neut Tower" ** "2020: Created Neut Tower as part of two game jams. * Global Game Jam - One weekend - Feb 2020 - First two rooms -* MS-DOS Game Jam - 1.5 months - April 2020 - 'Shareware Episode 1'"] +* MS-DOS Game Jam - 1.5 months - April 2020 - 'Shareware Episode 1'" + {:target 60}] [(bgimg "presentation/pics/boot-tower.jpeg") {:action #(files.reload :neuttower/game.json)} h "Neu] [ower" ** "A small puzzle adventure game!" "Magic Trick #1" {:action boot-game} - "--== D E M O ==--"] + "--== D E M O ==--" + {:target 300}] [h "How It's Made" ** "Is the Apple ][ running Lisp?" " * Not really?" @@ -104,13 +110,15 @@ " * Sort of!" "Show me some Lisp already! >:/" (openfile :neuttower/level1.fnl {:split :right :line 42}) - " * OK!"] + " * OK!" + {:target 90 :section "How It's Done"}] [h "What is this unholy abomination?" ** "Lisp and Forth?!" {:image "presentation/pics/thinkhard.png" :justify :center} "Not super keen on writing a complicated compiler" " * \"Direct threaded\" inner interpreter" - "Forth allows efficient, composable, interactive code"] + "Forth allows efficient, composable, interactive code" + {:target 60}] [h "Why use Lisp to compile Forth?" ** "\"Immediate words\" can be Fennel functions that generate code!" "Program can be compiled into a rich data structure" @@ -121,7 +129,8 @@ {:button #(vm-eval :hires) :text ":hires"} {:button #(vm-eval 1 2 :+ :.) :text "1 2 :+ :."} {:button #(vm-eval :earthquake) :text ":earthquake"} - {:pause-after true}] + {:pause-after true} + {:target 180}] [h "Explain this voodoo!" ** "Directly inspired by Dagen Brock's 2016 KFest talk on GSPlus" "Ended up using MAME - Lua plugin system exposes EVERYTHING" @@ -129,13 +138,15 @@ "1. What if I could poke my program directly into an emulator's memory?" "2. What if I could preserve the current runtime state but rewrite the code?" " ... even if the data has moved?" - "3. What if I could interactively try out new code while my game was running?"] + "3. What if I could interactively try out new code while my game was running?" + {:target 60}] [h "Wait WTF Is An Assembler" ** "It's just converting mnemonics to bytes, right?" {:image "presentation/pics/assembly-markup.png" :justify :center :pause-after true} "Whoooops, actually the hard part is converting labels to addresses" "Zero-page instructions are a different size, which messes up data layout!" - "Initial pass is needed to gather all symbols to determine sizes"] + "Initial pass is needed to gather all symbols to determine sizes" + {:target 60}] [h "The Tools" ** {:image "presentation/pics/retro-game-dev-quote.png" :justify :center :pause-after true} {:action #(files.reload :neuttower/game.json)} @@ -150,14 +161,16 @@ "Full-screen bitmap editor" (openview #(ScreenEditView :neuttower/title.screen) {:pause-after true}) (openfile :presentation/slides.fnl {:split :right :line 133}) - "Presentation viewer"] + "Presentation viewer" + {:target 300 :section "Tooling"}] [h "Editing Editors With My Editor" ** "lite is a small, highly-extensible text editor written in Lua" "Lua provides a very dynamic environment" (openview #(MapEditView)) (openfile :editor/mapedit.fnl {:split :right :line 235}) "Downside:" - {:image "presentation/pics/bsod.png" :justify :center :pause-after true}] + {:image "presentation/pics/bsod.png" :justify :center :pause-after true} + {:target 180}] [(bgimg "presentation/pics/bitsy.png") {:action #(files.reload :bitsy/game.json)} h "8-Bitsy" @@ -165,9 +178,10 @@ {:action boot-game} "Spring Lisp Game Jam - 10 days to hack" "Could I make my tools a little less... programmer-y?" - (openview #(MapEditView) {:pause-after true})] + (openview #(MapEditView) {:pause-after true}) + {:target 180 :section "Branching Out"}] [h "Thanks!" - (openfile :neuttower/level6.fnl {:split :right :line 153}) + (openfile :neuttower/level6.fnl {:split :right :line 164}) ** "Questions?" (np **) {:topPadding 128} "Jeremy Penner" @@ -176,7 +190,7 @@ "https://bitbucket.org/SpindleyQ/honeylisp" "https://gamemaking.social/@SpindleyQ" "https://twitter.com/SpindleyQ" - {:pause-after true}] + {:pause-after true :section "Thanks!"}] ]) ; [h "Step 5: Running on Hardware" diff --git a/support/lite/plugins/statusoverride.lua b/support/lite/plugins/statusoverride.lua new file mode 100644 index 0000000..aa93e31 --- /dev/null +++ b/support/lite/plugins/statusoverride.lua @@ -0,0 +1,12 @@ +local core = require "core" + +local get_items = core.status_view.get_items + +core.status_view.get_items = function (self) + if core.active_view and core.active_view.status_items then + return core.active_view:status_items(self) + else + return get_items(self) + end +end + diff --git a/vendor/lite/data/plugins/statusoverride.lua b/vendor/lite/data/plugins/statusoverride.lua new file mode 120000 index 0000000..8313d75 --- /dev/null +++ b/vendor/lite/data/plugins/statusoverride.lua @@ -0,0 +1 @@ +../../../../support/lite/plugins/statusoverride.lua \ No newline at end of file