diff options
-rw-r--r-- | 080display.cc | 91 | ||||
-rw-r--r-- | 081print.mu | 59 | ||||
-rw-r--r-- | 100trace_browser.cc | 10 | ||||
-rw-r--r-- | cannot_write_tests_for | 10 | ||||
-rw-r--r-- | edit/001-editor.mu | 2 | ||||
-rw-r--r-- | edit/002-typing.mu | 7 | ||||
-rw-r--r-- | edit/004-programming-environment.mu | 31 | ||||
-rw-r--r-- | edit/005-sandbox.mu | 27 | ||||
-rw-r--r-- | edit/006-sandbox-copy.mu | 2 | ||||
-rw-r--r-- | edit/007-sandbox-delete.mu | 2 | ||||
-rw-r--r-- | edit/008-sandbox-edit.mu | 2 | ||||
-rw-r--r-- | edit/009-sandbox-test.mu | 2 | ||||
-rw-r--r-- | edit/010-sandbox-trace.mu | 2 | ||||
-rw-r--r-- | sandbox/001-editor.mu | 2 | ||||
-rw-r--r-- | sandbox/002-typing.mu | 7 | ||||
-rw-r--r-- | sandbox/004-programming-environment.mu | 26 | ||||
-rw-r--r-- | sandbox/005-sandbox.mu | 33 | ||||
-rw-r--r-- | sandbox/006-sandbox-copy.mu | 2 | ||||
-rw-r--r-- | sandbox/007-sandbox-delete.mu | 2 | ||||
-rw-r--r-- | sandbox/008-sandbox-edit.mu | 2 | ||||
-rw-r--r-- | sandbox/009-sandbox-test.mu | 2 | ||||
-rw-r--r-- | sandbox/010-sandbox-trace.mu | 2 | ||||
-rw-r--r-- | termbox/termbox.c | 156 | ||||
-rw-r--r-- | termbox/termbox.h | 36 |
24 files changed, 402 insertions, 115 deletions
diff --git a/080display.cc b/080display.cc index 691b6a00..847d114c 100644 --- a/080display.cc +++ b/080display.cc @@ -7,6 +7,7 @@ :(before "End Globals") int Display_row = 0; int Display_column = 0; +bool Autodisplay = true; :(before "End Includes") #define CHECK_SCREEN \ @@ -37,7 +38,6 @@ case OPEN_CONSOLE: { :(before "End Primitive Recipe Implementations") case OPEN_CONSOLE: { tb_init(); - tb_clear(); Display_row = Display_column = 0; int width = tb_width(); int height = tb_height(); @@ -84,6 +84,21 @@ case CLEAR_DISPLAY: { } :(before "End Primitive Recipe Declarations") +SYNC_DISPLAY, +:(before "End Primitive Recipe Numbers") +put(Recipe_ordinal, "sync-display", SYNC_DISPLAY); +:(before "End Primitive Recipe Checks") +case SYNC_DISPLAY: { + break; +} +:(before "End Primitive Recipe Implementations") +case SYNC_DISPLAY: { + CHECK_SCREEN; + tb_sync(); + break; +} + +:(before "End Primitive Recipe Declarations") PRINT_CHARACTER_TO_DISPLAY, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "print-character-to-display", PRINT_CHARACTER_TO_DISPLAY); @@ -118,7 +133,7 @@ case PRINT_CHARACTER_TO_DISPLAY: { int height = (h >= 0) ? h : 0; int width = (w >= 0) ? w : 0; int c = ingredients.at(0).at(0); - int color = TB_WHITE; + int color = TB_BLACK; if (SIZE(ingredients) > 1) { color = ingredients.at(1).at(0); } @@ -133,6 +148,7 @@ case PRINT_CHARACTER_TO_DISPLAY: { Display_column = 0; ++Display_row; tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); } break; } @@ -141,6 +157,7 @@ case PRINT_CHARACTER_TO_DISPLAY: { tb_change_cell(Display_column-1, Display_row, ' ', color, bg_color); --Display_column; tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); } break; } @@ -148,6 +165,7 @@ case PRINT_CHARACTER_TO_DISPLAY: { ++Display_column; tb_set_cursor(Display_column, Display_row); } + if (Autodisplay) tb_present(); break; } @@ -194,6 +212,7 @@ case MOVE_CURSOR_ON_DISPLAY: { Display_row = ingredients.at(0).at(0); Display_column = ingredients.at(1).at(0); tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); break; } @@ -213,6 +232,7 @@ case MOVE_CURSOR_DOWN_ON_DISPLAY: { if (Display_row < height-1) { ++Display_row; tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); } break; } @@ -231,6 +251,7 @@ case MOVE_CURSOR_UP_ON_DISPLAY: { if (Display_row > 0) { --Display_row; tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); } break; } @@ -251,6 +272,7 @@ case MOVE_CURSOR_RIGHT_ON_DISPLAY: { if (Display_column < width-1) { ++Display_column; tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); } break; } @@ -269,6 +291,7 @@ case MOVE_CURSOR_LEFT_ON_DISPLAY: { if (Display_column > 0) { --Display_column; tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); } break; } @@ -284,6 +307,7 @@ void move_cursor_to_start_of_next_line_on_display() { else Display_row = 0; Display_column = 0; tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); } :(before "End Primitive Recipe Declarations") @@ -318,6 +342,67 @@ case DISPLAY_HEIGHT: { break; } +:(before "End Primitive Recipe Declarations") +HIDE_CURSOR_ON_DISPLAY, +:(before "End Primitive Recipe Numbers") +put(Recipe_ordinal, "hide-cursor-on-display", HIDE_CURSOR_ON_DISPLAY); +:(before "End Primitive Recipe Checks") +case HIDE_CURSOR_ON_DISPLAY: { + break; +} +:(before "End Primitive Recipe Implementations") +case HIDE_CURSOR_ON_DISPLAY: { + CHECK_SCREEN; + tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR); + break; +} + +:(before "End Primitive Recipe Declarations") +SHOW_CURSOR_ON_DISPLAY, +:(before "End Primitive Recipe Numbers") +put(Recipe_ordinal, "show-cursor-on-display", SHOW_CURSOR_ON_DISPLAY); +:(before "End Primitive Recipe Checks") +case SHOW_CURSOR_ON_DISPLAY: { + break; +} +:(before "End Primitive Recipe Implementations") +case SHOW_CURSOR_ON_DISPLAY: { + CHECK_SCREEN; + tb_set_cursor(Display_row, Display_column); + break; +} + +:(before "End Primitive Recipe Declarations") +HIDE_DISPLAY, +:(before "End Primitive Recipe Numbers") +put(Recipe_ordinal, "hide-display", HIDE_DISPLAY); +:(before "End Primitive Recipe Checks") +case HIDE_DISPLAY: { + break; +} +:(before "End Primitive Recipe Implementations") +case HIDE_DISPLAY: { + CHECK_SCREEN; + Autodisplay = false; + break; +} + +:(before "End Primitive Recipe Declarations") +SHOW_DISPLAY, +:(before "End Primitive Recipe Numbers") +put(Recipe_ordinal, "show-display", SHOW_DISPLAY); +:(before "End Primitive Recipe Checks") +case SHOW_DISPLAY: { + break; +} +:(before "End Primitive Recipe Implementations") +case SHOW_DISPLAY: { + CHECK_SCREEN; + Autodisplay = true; + tb_present(); + break; +} + //:: Keyboard/mouse management :(before "End Primitive Recipe Declarations") @@ -441,6 +526,7 @@ case CLEAR_LINE_ON_DISPLAY: { tb_change_cell(x, Display_row, ' ', TB_WHITE, TB_BLACK); } tb_set_cursor(Display_column, Display_row); + if (Autodisplay) tb_present(); break; } @@ -466,5 +552,6 @@ case CLEAR_DISPLAY_FROM: { tb_change_cell(column, row, ' ', TB_WHITE, TB_BLACK); } } + if (Autodisplay) tb_present(); break; } diff --git a/081print.mu b/081print.mu index 1d3bf8dc..487696c5 100644 --- a/081print.mu +++ b/081print.mu @@ -50,6 +50,13 @@ def clear-screen screen:&:screen -> screen:&:screen [ *screen <- put *screen, cursor-column:offset, 0 ] +def sync-screen screen:&:screen -> screen:&:screen [ + local-scope + load-ingredients + return-if screen # do nothing for fake screens + sync-display +] + def fake-screen-is-empty? screen:&:screen -> result:bool [ local-scope load-ingredients @@ -101,27 +108,15 @@ def print screen:&:screen, c:char -> screen:&:screen [ row:num <- get *screen, cursor-row:offset row <- round row legal?:bool <- greater-or-equal row, 0 - { - break-if legal? - row <- copy 0 - } + return-unless legal? legal? <- lesser-than row, height - { - break-if legal? - row <- subtract height, 1 - } + return-unless legal? column:num <- get *screen, cursor-column:offset column <- round column legal? <- greater-or-equal column, 0 - { - break-if legal? - column <- copy 0 - } + return-unless legal? legal? <- lesser-than column, width - { - break-if legal? - column <- subtract width, 1 - } + return-unless legal? #? $print [print-character (], row, [, ], column, [): ], c, 10/newline # special-case: newline { @@ -609,6 +604,38 @@ def screen-height screen:&:screen -> height:num [ height <- display-height ] +def hide-cursor screen:&:screen -> screen:&:screen [ + local-scope + load-ingredients + return-if screen # fake screen; do nothing + # real screen + hide-cursor-on-display +] + +def show-cursor screen:&:screen -> screen:&:screen [ + local-scope + load-ingredients + return-if screen # fake screen; do nothing + # real screen + show-cursor-on-display +] + +def hide-screen screen:&:screen -> screen:&:screen [ + local-scope + load-ingredients + return-if screen # fake screen; do nothing + # real screen + hide-display +] + +def show-screen screen:&:screen -> screen:&:screen [ + local-scope + load-ingredients + return-if screen # fake screen; do nothing + # real screen + show-display +] + def print screen:&:screen, s:text -> screen:&:screen [ local-scope load-ingredients diff --git a/100trace_browser.cc b/100trace_browser.cc index ffa66b41..42a4d848 100644 --- a/100trace_browser.cc +++ b/100trace_browser.cc @@ -276,6 +276,7 @@ bool start_search_editor(search_direction dir) { tb_change_cell(col, bottom_screen_line, '/', TB_WHITE, TB_BLACK); ++col; tb_set_cursor(col, bottom_screen_line); + tb_present(); string pattern; while (true) { int key = read_key(); @@ -293,21 +294,25 @@ bool start_search_editor(search_direction dir) { if (col > /*slash*/1) { --col; tb_set_cursor(col, bottom_screen_line); + tb_present(); } } else if (key == TB_KEY_ARROW_RIGHT) { if (col-/*slash*/1 < SIZE(pattern)) { ++col; tb_set_cursor(col, bottom_screen_line); + tb_present(); } } else if (key == TB_KEY_HOME || key == TB_KEY_CTRL_A) { col = /*skip slash*/1; tb_set_cursor(col, bottom_screen_line); + tb_present(); } else if (key == TB_KEY_END || key == TB_KEY_CTRL_E) { col = SIZE(pattern)+/*skip slash*/1; tb_set_cursor(col, bottom_screen_line); + tb_present(); } else if (key == TB_KEY_BACKSPACE || key == TB_KEY_BACKSPACE2) { if (col > /*slash*/1) { @@ -325,6 +330,7 @@ bool start_search_editor(search_direction dir) { tb_change_cell(SIZE(pattern)+/*skip slash*/1, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); } tb_set_cursor(col, bottom_screen_line); + tb_present(); } } else if (key == TB_KEY_CTRL_K) { @@ -333,6 +339,7 @@ bool start_search_editor(search_direction dir) { for (int x = col; x < old_pattern_size+/*slash*/1; ++x) tb_change_cell(x, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); tb_set_cursor(col, bottom_screen_line); + tb_present(); } else if (key == TB_KEY_CTRL_U) { int old_pattern_size = SIZE(pattern); @@ -342,6 +349,7 @@ bool start_search_editor(search_direction dir) { for (int x = SIZE(pattern)+/*slash*/1; x < old_pattern_size+/*skip slash*/1; ++x) tb_change_cell(x, bottom_screen_line, ' ', TB_WHITE, TB_BLACK); tb_set_cursor(/*start of pattern skipping slash*/1, bottom_screen_line); + tb_present(); } else if (key < 128) { // ascii only // update pattern @@ -352,6 +360,7 @@ bool start_search_editor(search_direction dir) { tb_change_cell(x, bottom_screen_line, pattern.at(x-/*slash*/1), TB_WHITE, TB_BLACK); ++col; tb_set_cursor(col, bottom_screen_line); + tb_present(); } } } @@ -435,6 +444,7 @@ void render() { render_line(screen_row, "~", /*cursor_line?*/false); // move cursor back to display row at the end tb_set_cursor(0, Display_row); + tb_present(); } int lines_hidden(int screen_row) { diff --git a/cannot_write_tests_for b/cannot_write_tests_for index 1bd9ce3c..444aafd5 100644 --- a/cannot_write_tests_for +++ b/cannot_write_tests_for @@ -1,12 +1,14 @@ 0. main's ingredients 1. assertion failures or errors inside scenarios 2. screen background color -3. more touch event types -4. sandbox isolation -5. errors in reading/writing files (missing directory, others?) -6. has-more-events? +3. has-more-events? +4. hide/show screen +5. more touch event types +6. sandbox isolation +7. errors in reading/writing files (missing directory, others?) termbox issues are implementation-specific and not worth testing: + whether we clear junk from other processes latency in interpreting low-level escape characters calls to update-cursor are currently duplicated: diff --git a/edit/001-editor.mu b/edit/001-editor.mu index a6dde85b..d81278ae 100644 --- a/edit/001-editor.mu +++ b/edit/001-editor.mu @@ -6,8 +6,10 @@ def main text:text [ local-scope load-ingredients open-console + hide-screen 0/screen e:&:editor <- new-editor text, 0/left, 5/right render 0/screen, e + show-screen 0/screen wait-for-event 0/console close-console ] diff --git a/edit/002-typing.mu b/edit/002-typing.mu index d5120f2f..4f704f0d 100644 --- a/edit/002-typing.mu +++ b/edit/002-typing.mu @@ -266,17 +266,10 @@ def editor-render screen:&:screen, editor:&:editor -> screen:&:screen, editor:&: left:num <- get *editor, left:offset right:num <- get *editor, right:offset row:num, column:num <- render screen, editor - screen-height:num <- screen-height screen - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-line-until screen, right row <- add row, 1 - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? draw-horizontal screen, row, left, right, 9480/horizontal-dotted row <- add row, 1 - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-screen-from screen, row, left, left, right ] diff --git a/edit/004-programming-environment.mu b/edit/004-programming-environment.mu index ba626cb4..597e6900 100644 --- a/edit/004-programming-environment.mu +++ b/edit/004-programming-environment.mu @@ -96,6 +96,7 @@ def event-loop screen:&:screen, console:&:console, env:&:environment, resources: } # if it's not global and not a touch event, send to appropriate editor { + hide-screen screen sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset { break-if sandbox-in-focus? @@ -115,6 +116,7 @@ def event-loop screen:&:screen, console:&:console, env:&:environment, resources: screen <- render-all screen, env, render } screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + show-screen screen } loop } @@ -393,6 +395,7 @@ def render-all screen:&:screen, env:&:environment, {render-editor: (recipe (addr local-scope load-ingredients trace 10, [app], [render all] + hide-screen screen # top menu trace 11, [app], [render top menu] width:num <- screen-width screen @@ -416,6 +419,8 @@ def render-all screen:&:screen, env:&:environment, {render-editor: (recipe (addr current-sandbox:&:editor <- get *env, current-sandbox:offset sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + # + show-screen screen ] def render-recipes screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ @@ -427,19 +432,12 @@ def render-recipes screen:&:screen, env:&:environment, {render-editor: (recipe ( left:num <- get *recipes, left:offset right:num <- get *recipes, right:offset row:num, column:num, screen <- call render-editor, screen, recipes - screen-height:num <- screen-height screen - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-line-until screen, right row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? <render-recipe-components-end> # draw dotted line after recipes draw-horizontal screen, row, left, right, 9480/horizontal-dotted row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? clear-screen-from screen, row, left, left, right ] @@ -451,18 +449,11 @@ def render-sandbox-side screen:&:screen, env:&:environment, {render-editor: (rec left:num <- get *current-sandbox, left:offset right:num <- get *current-sandbox, right:offset row:num, column:num, screen, current-sandbox <- call render-editor, screen, current-sandbox - screen-height:num <- screen-height screen - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-line-until screen, right row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? # draw solid line after code (you'll see why in later layers) draw-horizontal screen, row, left, right row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? clear-screen-from screen, row, left, left, right ] @@ -483,6 +474,18 @@ def update-cursor screen:&:screen, recipes:&:editor, current-sandbox:&:editor, s screen <- move-cursor screen, cursor-row, cursor-column ] +# ctrl-l - redraw screen (just in case it printed junk somehow) + +after <global-type> [ + { + redraw-screen?:bool <- equal c, 12/ctrl-l + break-unless redraw-screen? + screen <- render-all screen, env:&:environment, render + sync-screen screen + loop +next-event + } +] + # ctrl-n - switch focus # todo: test this diff --git a/edit/005-sandbox.mu b/edit/005-sandbox.mu index fed2c806..5f08554d 100644 --- a/edit/005-sandbox.mu +++ b/edit/005-sandbox.mu @@ -245,26 +245,19 @@ def! render-sandbox-side screen:&:screen, env:&:environment, {render-editor: (re row:num, column:num <- copy 1, 0 left:num <- get *current-sandbox, left:offset right:num <- get *current-sandbox, right:offset - screen-height:num <- screen-height screen # render sandbox editor render-from:num <- get *env, render-from:offset { render-current-sandbox?:bool <- equal render-from, -1 break-unless render-current-sandbox? row, column, screen, current-sandbox <- call render-editor, screen, current-sandbox - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-screen-from screen, row, column, left, right row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? } # render sandboxes draw-horizontal screen, row, left, right sandbox:&:sandbox <- get *env, sandbox:offset row, screen <- render-sandboxes screen, sandbox, left, right, row, render-from - space-left? <- lesser-than row, screen-height - return-unless space-left? clear-rest-of-screen screen, row, left, right ] @@ -280,22 +273,16 @@ def render-sandboxes screen:&:screen, sandbox:&:sandbox, left:num, right:num, ro break-if hidden? # render sandbox menu row <- add row, 1 - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? screen <- move-cursor screen, row, left screen <- render-sandbox-menu screen, idx, left, right # save menu row so we can detect clicks to it later *sandbox <- put *sandbox, starting-row-on-screen:offset, row # render sandbox contents row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? screen <- move-cursor screen, row, left sandbox-data:text <- get *sandbox, data:offset row, screen <- render-code screen, sandbox-data, left, right, row *sandbox <- put *sandbox, code-ending-row-on-screen:offset, row - space-left? <- lesser-than row, screen-height - return-unless space-left? # render sandbox warnings, screen or response, in that order sandbox-response:text <- get *sandbox, response:offset <render-sandbox-results> @@ -311,8 +298,8 @@ def render-sandboxes screen:&:screen, sandbox:&:sandbox, left:num, right:num, ro row, screen <- render-text screen, sandbox-response, left, right, 245/grey, row } +render-sandbox-end - space-left? <- lesser-than row, screen-height - return-unless space-left? + at-bottom?:bool <- greater-or-equal row, screen-height + return-if at-bottom? # draw solid line after sandbox draw-horizontal screen, row, left, right } @@ -324,8 +311,6 @@ def render-sandboxes screen:&:screen, sandbox:&:sandbox, left:num, right:num, ro <end-render-sandbox-reset-hidden> } # draw next sandbox - space-left? <- lesser-than row, screen-height - return-unless space-left? next-sandbox:&:sandbox <- get *sandbox, next-sandbox:offset next-idx:num <- add idx, 1 row, screen <- render-sandboxes screen, next-sandbox, left, right, row, render-from, next-idx @@ -426,8 +411,6 @@ def render-text screen:&:screen, s:text, left:num, right:num, color:num, row:num column <- add column, 1 loop } - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? was-at-left?:bool <- equal column, left clear-line-until screen, right { @@ -508,8 +491,6 @@ def render-code screen:&:screen, s:text, left:num, right:num, row:num -> row:num column <- add column, 1 loop } - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? was-at-left?:bool <- equal column, left clear-line-until screen, right { @@ -990,8 +971,10 @@ after <global-keypress> [ render-from <- add render-from, 1 *env <- put *env, render-from:offset, render-from } + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + show-screen screen loop +next-event } ] @@ -1020,8 +1003,10 @@ after <global-keypress> [ break-if at-beginning? render-from <- subtract render-from, 1 *env <- put *env, render-from:offset, render-from + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + show-screen screen loop +next-event } ] diff --git a/edit/006-sandbox-copy.mu b/edit/006-sandbox-copy.mu index d3f82e88..9df5e625 100644 --- a/edit/006-sandbox-copy.mu +++ b/edit/006-sandbox-copy.mu @@ -128,8 +128,10 @@ after <global-touch> [ break-unless copy? copy?, env <- try-copy-sandbox click-row, env break-unless copy? + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + show-screen screen loop +next-event } ] diff --git a/edit/007-sandbox-delete.mu b/edit/007-sandbox-delete.mu index 5167b038..4fa3c37d 100644 --- a/edit/007-sandbox-delete.mu +++ b/edit/007-sandbox-delete.mu @@ -72,8 +72,10 @@ after <global-touch> [ break-unless delete? delete?, env <- try-delete-sandbox click-row, env break-unless delete? + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + show-screen screen loop +next-event } ] diff --git a/edit/008-sandbox-edit.mu b/edit/008-sandbox-edit.mu index 2d591ad6..dd5c1bb9 100644 --- a/edit/008-sandbox-edit.mu +++ b/edit/008-sandbox-edit.mu @@ -111,8 +111,10 @@ after <global-touch> [ break-unless edit? edit?, env <- try-edit-sandbox click-row, env break-unless edit? + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + show-screen screen loop +next-event } ] diff --git a/edit/009-sandbox-test.mu b/edit/009-sandbox-test.mu index badd795b..023015ed 100644 --- a/edit/009-sandbox-test.mu +++ b/edit/009-sandbox-test.mu @@ -130,8 +130,10 @@ after <global-touch> [ # toggle its expected-response, and save session sandbox <- toggle-expected-response sandbox save-sandboxes env, resources + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + show-screen screen loop +next-event } ] diff --git a/edit/010-sandbox-trace.mu b/edit/010-sandbox-trace.mu index 8088577a..66a321d6 100644 --- a/edit/010-sandbox-trace.mu +++ b/edit/010-sandbox-trace.mu @@ -200,8 +200,10 @@ after <global-touch> [ x:bool <- get *sandbox, display-trace?:offset x <- not x *sandbox <- put *sandbox, display-trace?:offset, x + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + show-screen screen loop +next-event } ] diff --git a/sandbox/001-editor.mu b/sandbox/001-editor.mu index a6dde85b..d81278ae 100644 --- a/sandbox/001-editor.mu +++ b/sandbox/001-editor.mu @@ -6,8 +6,10 @@ def main text:text [ local-scope load-ingredients open-console + hide-screen 0/screen e:&:editor <- new-editor text, 0/left, 5/right render 0/screen, e + show-screen 0/screen wait-for-event 0/console close-console ] diff --git a/sandbox/002-typing.mu b/sandbox/002-typing.mu index d5120f2f..4f704f0d 100644 --- a/sandbox/002-typing.mu +++ b/sandbox/002-typing.mu @@ -266,17 +266,10 @@ def editor-render screen:&:screen, editor:&:editor -> screen:&:screen, editor:&: left:num <- get *editor, left:offset right:num <- get *editor, right:offset row:num, column:num <- render screen, editor - screen-height:num <- screen-height screen - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-line-until screen, right row <- add row, 1 - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? draw-horizontal screen, row, left, right, 9480/horizontal-dotted row <- add row, 1 - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-screen-from screen, row, left, left, right ] diff --git a/sandbox/004-programming-environment.mu b/sandbox/004-programming-environment.mu index 2dca181d..917ea957 100644 --- a/sandbox/004-programming-environment.mu +++ b/sandbox/004-programming-environment.mu @@ -79,6 +79,7 @@ def event-loop screen:&:screen, console:&:console, env:&:environment, resources: } # not global and not a touch event { + hide-screen screen render?:bool <- handle-keyboard-event screen, current-sandbox, e:event break-unless render? # try to batch up rendering if there are more events queued up @@ -89,6 +90,9 @@ def event-loop screen:&:screen, console:&:console, env:&:environment, resources: break-unless render-all-on-no-more-events? screen <- render-all screen, env, render } + +finish-event + screen <- update-cursor screen, current-sandbox, env + show-screen screen } loop } @@ -194,6 +198,7 @@ def render-all screen:&:screen, env:&:environment, {render-editor: (recipe (addr local-scope load-ingredients trace 10, [app], [render all] + hide-screen screen # top menu trace 11, [app], [render top menu] width:num <- screen-width screen @@ -209,6 +214,8 @@ def render-all screen:&:screen, env:&:environment, {render-editor: (recipe (addr # current-sandbox:&:editor <- get *env, current-sandbox:offset screen <- update-cursor screen, current-sandbox, env + # + show-screen screen ] # replaced in a later layer @@ -219,18 +226,11 @@ def render-sandbox-side screen:&:screen, env:&:environment, {render-editor: (rec left:num <- get *current-sandbox, left:offset right:num <- get *current-sandbox, right:offset row:num, column:num, screen, current-sandbox <- call render-editor, screen, current-sandbox - screen-height:num <- screen-height screen - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-line-until screen, right row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? # draw solid line after code (you'll see why in later layers) draw-horizontal screen, row, left, right row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? clear-screen-from screen, row, left, left, right ] @@ -242,3 +242,15 @@ def update-cursor screen:&:screen, current-sandbox:&:editor, env:&:environment - cursor-column:num <- get *current-sandbox, cursor-column:offset screen <- move-cursor screen, cursor-row, cursor-column ] + +# ctrl-l - redraw screen (just in case it printed junk somehow) + +after <global-type> [ + { + redraw-screen?:bool <- equal c, 12/ctrl-l + break-unless redraw-screen? + screen <- render-all screen, env:&:environment, render + sync-screen screen + loop +next-event + } +] diff --git a/sandbox/005-sandbox.mu b/sandbox/005-sandbox.mu index 06262d72..e9500797 100644 --- a/sandbox/005-sandbox.mu +++ b/sandbox/005-sandbox.mu @@ -234,26 +234,19 @@ def! render-sandbox-side screen:&:screen, env:&:environment, {render-editor: (re row:num, column:num <- copy 1, 0 left:num <- get *current-sandbox, left:offset right:num <- get *current-sandbox, right:offset - screen-height:num <- screen-height screen # render sandbox editor render-from:num <- get *env, render-from:offset { render-current-sandbox?:bool <- equal render-from, -1 break-unless render-current-sandbox? row, column, screen, current-sandbox <- call render-editor, screen, current-sandbox - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? clear-screen-from screen, row, column, left, right row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? } # render sandboxes draw-horizontal screen, row, left, right sandbox:&:sandbox <- get *env, sandbox:offset row, screen <- render-sandboxes screen, sandbox, left, right, row, render-from, 0, env - space-left? <- lesser-than row, screen-height - return-unless space-left? clear-rest-of-screen screen, row, left, right ] @@ -270,22 +263,16 @@ def render-sandboxes screen:&:screen, sandbox:&:sandbox, left:num, right:num, ro break-if hidden? # render sandbox menu row <- add row, 1 - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? screen <- move-cursor screen, row, left screen <- render-sandbox-menu screen, idx, left, right # save menu row so we can detect clicks to it later *sandbox <- put *sandbox, starting-row-on-screen:offset, row # render sandbox contents row <- add row, 1 - space-left? <- lesser-than row, screen-height - return-unless space-left? screen <- move-cursor screen, row, left sandbox-data:text <- get *sandbox, data:offset row, screen <- render-code screen, sandbox-data, left, right, row *sandbox <- put *sandbox, code-ending-row-on-screen:offset, row - space-left? <- lesser-than row, screen-height - return-unless space-left? # render sandbox warnings, screen or response, in that order sandbox-response:text <- get *sandbox, response:offset <render-sandbox-results> @@ -301,8 +288,8 @@ def render-sandboxes screen:&:screen, sandbox:&:sandbox, left:num, right:num, ro row, screen <- render-text screen, sandbox-response, left, right, 245/grey, row } +render-sandbox-end - space-left? <- lesser-than row, screen-height - return-unless space-left? + at-bottom?:bool <- greater-or-equal row, screen-height + return-if at-bottom? # draw solid line after sandbox draw-horizontal screen, row, left, right } @@ -314,8 +301,6 @@ def render-sandboxes screen:&:screen, sandbox:&:sandbox, left:num, right:num, ro <end-render-sandbox-reset-hidden> } # draw next sandbox - space-left? <- lesser-than row, screen-height - return-unless space-left? next-sandbox:&:sandbox <- get *sandbox, next-sandbox:offset next-idx:num <- add idx, 1 row, screen <- render-sandboxes screen, next-sandbox, left, right, row, render-from, next-idx, env @@ -416,8 +401,6 @@ def render-text screen:&:screen, s:text, left:num, right:num, color:num, row:num column <- add column, 1 loop } - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? was-at-left?:bool <- equal column, left clear-line-until screen, right { @@ -483,8 +466,6 @@ def render-code screen:&:screen, s:text, left:num, right:num, row:num -> row:num column <- add column, 1 loop } - space-left?:bool <- lesser-than row, screen-height - return-unless space-left? was-at-left?:bool <- equal column, left clear-line-until screen, right { @@ -812,9 +793,10 @@ after <global-keypress> [ render-from <- add render-from, 1 *env <- put *env, render-from:offset, render-from } + hide-screen screen screen <- render-sandbox-side screen, env, render - screen <- update-cursor screen, current-sandbox, env - loop +next-event + show-screen screen + jump +finish-event } ] @@ -840,9 +822,10 @@ after <global-keypress> [ break-if at-beginning? render-from <- subtract render-from, 1 *env <- put *env, render-from:offset, render-from + hide-screen screen screen <- render-sandbox-side screen, env, render - screen <- update-cursor screen, current-sandbox, env - loop +next-event + show-screen screen + jump +finish-event } ] diff --git a/sandbox/006-sandbox-copy.mu b/sandbox/006-sandbox-copy.mu index 4835f02e..995f4c7c 100644 --- a/sandbox/006-sandbox-copy.mu +++ b/sandbox/006-sandbox-copy.mu @@ -140,8 +140,10 @@ after <global-touch> [ break-unless copy? copy?, env <- try-copy-sandbox click-row, env break-unless copy? + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, current-sandbox, env + show-screen screen loop +next-event } ] diff --git a/sandbox/007-sandbox-delete.mu b/sandbox/007-sandbox-delete.mu index 107c861c..ddfbf692 100644 --- a/sandbox/007-sandbox-delete.mu +++ b/sandbox/007-sandbox-delete.mu @@ -69,8 +69,10 @@ after <global-touch> [ break-unless delete? delete?, env <- try-delete-sandbox click-row, env break-unless delete? + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, current-sandbox, env + show-screen screen loop +next-event } ] diff --git a/sandbox/008-sandbox-edit.mu b/sandbox/008-sandbox-edit.mu index ec4fd578..cb19ebc4 100644 --- a/sandbox/008-sandbox-edit.mu +++ b/sandbox/008-sandbox-edit.mu @@ -111,8 +111,10 @@ after <global-touch> [ break-unless edit? edit?, env <- try-edit-sandbox click-row, env break-unless edit? + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, current-sandbox, env + show-screen screen loop +next-event } ] diff --git a/sandbox/009-sandbox-test.mu b/sandbox/009-sandbox-test.mu index 1c24bcb8..d7b8ed62 100644 --- a/sandbox/009-sandbox-test.mu +++ b/sandbox/009-sandbox-test.mu @@ -132,8 +132,10 @@ after <global-touch> [ # toggle its expected-response, and save session sandbox <- toggle-expected-response sandbox save-sandboxes env, resources + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, current-sandbox, env + show-screen screen loop +next-event } ] diff --git a/sandbox/010-sandbox-trace.mu b/sandbox/010-sandbox-trace.mu index 27f2915a..f81d4151 100644 --- a/sandbox/010-sandbox-trace.mu +++ b/sandbox/010-sandbox-trace.mu @@ -190,8 +190,10 @@ after <global-touch> [ x:bool <- get *sandbox, display-trace?:offset x <- not x *sandbox <- put *sandbox, display-trace?:offset, x + hide-screen screen screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, current-sandbox, env + show-screen screen loop +next-event } ] diff --git a/termbox/termbox.c b/termbox/termbox.c index 6a22f109..36c9496a 100644 --- a/termbox/termbox.c +++ b/termbox/termbox.c @@ -23,10 +23,20 @@ extern int wcwidth (wchar_t); #include "output.inl" #include "input.inl" +struct cellbuf { + int width; + int height; + struct tb_cell *cells; +}; + +#define CELL(buf, x, y) (buf)->cells[(y) * (buf)->width + (x)] +#define IS_CURSOR_HIDDEN(cx, cy) (cx == -1 || cy == -1) #define LAST_COORD_INIT -1 static struct termios orig_tios; +static struct cellbuf back_buffer; +static struct cellbuf front_buffer; static struct bytebuffer output_buffer; static struct bytebuffer input_buffer; @@ -47,6 +57,11 @@ static uint16_t foreground = TB_WHITE; static void write_cursor(int x, int y); static void write_sgr(uint16_t fg, uint16_t bg); +static void cellbuf_init(struct cellbuf *buf, int width, int height); +static void cellbuf_resize(struct cellbuf *buf, int width, int height); +static void cellbuf_clear(struct cellbuf *buf); +static void cellbuf_free(struct cellbuf *buf); + static void update_size(void); static void update_term_size(void); static void send_attr(uint16_t fg, uint16_t bg); @@ -104,9 +119,14 @@ int tb_init(void) bytebuffer_puts(&output_buffer, funcs[T_ENTER_KEYPAD]); bytebuffer_puts(&output_buffer, funcs[T_ENTER_MOUSE]); bytebuffer_puts(&output_buffer, funcs[T_ENTER_BRACKETED_PASTE]); - bytebuffer_flush(&output_buffer, inout); + send_clear(); update_term_size(); + cellbuf_init(&back_buffer, termw, termh); + cellbuf_init(&front_buffer, termw, termh); + cellbuf_clear(&back_buffer); + cellbuf_clear(&front_buffer); + return 0; } @@ -126,6 +146,8 @@ void tb_shutdown(void) close(winch_fds[0]); close(winch_fds[1]); + cellbuf_free(&back_buffer); + cellbuf_free(&front_buffer); bytebuffer_free(&output_buffer); bytebuffer_free(&input_buffer); termw = termh = -1; @@ -136,21 +158,88 @@ int tb_is_active(void) return termw != -1; } +static void tb_repaint(bool force) { + int x,y,w,i; + struct tb_cell *back, *front; + + assert(termw != -1); + + /* invalidate cursor position */ + lastx = LAST_COORD_INIT; + lasty = LAST_COORD_INIT; + + if (buffer_size_change_request) { + update_size(); + buffer_size_change_request = 0; + } + + for (y = 0; y < front_buffer.height; ++y) { + for (x = 0; x < front_buffer.width; ) { + back = &CELL(&back_buffer, x, y); + front = &CELL(&front_buffer, x, y); + w = wcwidth(back->ch); + if (w < 1) w = 1; + if (!force && memcmp(back, front, sizeof(struct tb_cell)) == 0) { + x += w; + continue; + } + memcpy(front, back, sizeof(struct tb_cell)); + send_attr(back->fg, back->bg); + if (w > 1 && x >= front_buffer.width - (w - 1)) { + // Not enough room for wide ch, so send spaces + for (i = x; i < front_buffer.width; ++i) { + send_char(i, y, ' '); + } + } else { + send_char(x, y, back->ch); + for (i = 1; i < w; ++i) { + front = &CELL(&front_buffer, x + i, y); + front->ch = 0; + front->fg = back->fg; + front->bg = back->bg; + } + } + x += w; + } + } + if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y)) + write_cursor(cursor_x, cursor_y); + bytebuffer_flush(&output_buffer, inout); +} + +void tb_present(void) +{ + tb_repaint(false); +} + +void tb_sync(void) +{ + tb_repaint(true); +} + void tb_set_cursor(int cx, int cy) { assert(termw != -1); cursor_x = cx; cursor_y = cy; - write_cursor(cursor_x, cursor_y); - bytebuffer_flush(&output_buffer, inout); + if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y)) + write_cursor(cursor_x, cursor_y); } void tb_change_cell(int x, int y, uint32_t ch, uint16_t fg, uint16_t bg) { assert(termw != -1); - send_attr(fg, bg); - send_char(x, y, ch); - bytebuffer_flush(&output_buffer, inout); + if ((unsigned)x >= (unsigned)back_buffer.width) + return; + if ((unsigned)y >= (unsigned)back_buffer.height) + return; + struct tb_cell c = {ch, fg, bg}; + CELL(&back_buffer, x, y) = c; +} + +struct tb_cell *tb_cell_buffer() +{ + return back_buffer.cells; } int tb_poll_event(struct tb_event *event) @@ -187,7 +276,7 @@ void tb_clear(void) update_size(); buffer_size_change_request = 0; } - send_clear(); + cellbuf_clear(&back_buffer); } void tb_set_clear_attributes(uint16_t fg, uint16_t bg) @@ -236,6 +325,56 @@ static void write_sgr(uint16_t fg, uint16_t bg) { WRITE_LITERAL("m"); } +static void cellbuf_init(struct cellbuf *buf, int width, int height) +{ + buf->cells = (struct tb_cell*)malloc(sizeof(struct tb_cell) * width * height); + assert(buf->cells); + buf->width = width; + buf->height = height; +} + +static void cellbuf_resize(struct cellbuf *buf, int width, int height) +{ + if (buf->width == width && buf->height == height) + return; + + int oldw = buf->width; + int oldh = buf->height; + struct tb_cell *oldcells = buf->cells; + + cellbuf_init(buf, width, height); + cellbuf_clear(buf); + + int minw = (width < oldw) ? width : oldw; + int minh = (height < oldh) ? height : oldh; + int i; + + for (i = 0; i < minh; ++i) { + struct tb_cell *csrc = oldcells + (i * oldw); + struct tb_cell *cdst = buf->cells + (i * width); + memcpy(cdst, csrc, sizeof(struct tb_cell) * minw); + } + + free(oldcells); +} + +static void cellbuf_clear(struct cellbuf *buf) +{ + int i; + int ncells = buf->width * buf->height; + + for (i = 0; i < ncells; ++i) { + buf->cells[i].ch = ' '; + buf->cells[i].fg = foreground; + buf->cells[i].bg = background; + } +} + +static void cellbuf_free(struct cellbuf *buf) +{ + free(buf->cells); +} + static void get_term_size(int *w, int *h) { struct winsize sz; @@ -329,6 +468,9 @@ static void sigwinch_handler(int xxx) static void update_size(void) { update_term_size(); + cellbuf_resize(&back_buffer, termw, termh); + cellbuf_resize(&front_buffer, termw, termh); + cellbuf_clear(&front_buffer); send_clear(); } diff --git a/termbox/termbox.h b/termbox/termbox.h index 97e3f524..c6cda6e1 100644 --- a/termbox/termbox.h +++ b/termbox/termbox.h @@ -9,12 +9,18 @@ extern "C" { /*** 1. Controlling the screen. */ /* The screen is a 2D array of cells. */ +struct tb_cell { + uint32_t ch; /* unicode character */ + uint16_t fg; /* foreground color (0-255) and attributes */ + uint16_t bg; /* background color (0-255) and attributes */ +}; -/* Names for some colors. */ +/* Names for some colors in tb_cell.fg and tb_cell.bg. */ #define TB_BLACK 232 #define TB_WHITE 255 -/* Some attributes of screen cells that can be combined with colors using bitwise-OR. */ +/* Colors in tb_cell can be combined using bitwise-OR with multiple + * of the following attributes. */ #define TB_BOLD 0x0100 #define TB_UNDERLINE 0x0200 #define TB_REVERSE 0x0400 @@ -38,14 +44,34 @@ int tb_is_active(void); int tb_width(void); int tb_height(void); -/* Clear the screen. */ +/* Update the screen with internal state. Most methods below modify just the + * internal state of the screen. Changes won't be visible until you call + * tb_present(). */ +void tb_present(void); + +/* Variant of tb_present() that always refreshes the entire screen. */ +void tb_sync(void); + +/* Returns a pointer to the internal screen state: a 1D array of cells in + * raster order. You'll need to call tb_width() and tb_height() for the + * array's dimensions. The array stays valid until tb_clear() or tb_present() + * are called. */ +struct tb_cell *tb_cell_buffer(); + +/* Clear the internal screen state using either TB_DEFAULT or the + * color/attributes set by tb_set_clear_attributes(). */ void tb_clear(void); void tb_set_clear_attributes(uint16_t fg, uint16_t bg); -/* Move the cursor. Upper-left character is (0, 0). */ +/* Move the cursor. Upper-left character is (0, 0). + */ void tb_set_cursor(int cx, int cy); +/* To hide the cursor, call tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR). + * Cursor starts out hidden. */ +#define TB_HIDE_CURSOR -1 -/* Modify a specific cell of the screen. */ +/* Modify a specific cell of the screen. Don't forget to call tb_present() to + * commit your changes. */ void tb_change_cell(int x, int y, uint32_t ch, uint16_t fg, uint16_t bg); /*** 2. Controlling keyboard events. */ |