pe: basic GUI setup

Adds a file browser (selected files are not loaded yet) and a shell
widget with an input system that is still better than the previous
VT-100 emulation scheme (with locked modifiers mainly).

A lot of small things still need to be done to make the UI functional.
This commit is contained in:
Lephenixnoir 2022-11-05 18:25:54 +01:00
parent 4e529b5788
commit fa6aa00dae
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
14 changed files with 480 additions and 169 deletions

View File

@ -1,7 +1,7 @@
include ../../py/mkenv.mk
SH_CFLAGS := -DFX9860G
SH_LDFLAGS := -T fx9860g.ld -lm -lgint-fx -lc -lgint-fx -lgcc
SH_LDFLAGS := -T fx9860g.ld -ljustui-fx -lm -lgint-fx -lc -lgint-fx -lgcc
all: PythonExtra.g1a

View File

@ -1,7 +1,7 @@
include ../../py/mkenv.mk
SH_CFLAGS := -DFXCG50
SH_LDFLAGS := -T fxcg50.ld -lm -lgint-cg -lc -lgint-cg -lgcc
SH_LDFLAGS := -T fxcg50.ld -ljustui-cg -lm -lgint-cg -lc -lgint-cg -lgcc
all: PythonExtra.g3a

View File

@ -16,7 +16,7 @@ SRC_C = \
ports/sh/modgint.c \
ports/sh/modtime.c \
ports/sh/mphalport.c \
ports/sh/shell.c \
ports/sh/widget_shell.c \
shared/readline/readline.c \
shared/runtime/gchelper_generic.c \
shared/runtime/pyexec.c \
@ -25,6 +25,7 @@ SRC_C = \
SRC_QSTR += \
shared/readline/readline.c \
shared/runtime/pyexec.c \
ports/sh/modgint.c \
ports/sh/modtime.c \

View File

@ -11,6 +11,10 @@
#include <string.h>
#include "console.h"
#include "py/mphal.h"
#include "../../shared/readline/readline.h"
#include "keymap.h"
//=== Dynamic console lines ===//
bool console_line_init(console_line_t *line, int prealloc_size)
@ -136,6 +140,7 @@ console_t *console_create(int backlog_size)
cons->lines = NULL;
cons->line_count = 0;
cons->backlog_size = max(backlog_size, PE_CONSOLE_LINE_MAX_LENGTH);
cons->render_needed = true;
if(!console_new_line(cons)) {
free(cons);
return NULL;
@ -157,6 +162,7 @@ bool console_new_line(console_t *cons)
return false;
cons->line_count++;
cons->cursor = 0;
cons->render_needed = true;
/* Routinely clean the backlog every time a line is added. */
// console_clean_backlog(cons);
@ -201,6 +207,7 @@ bool console_write_block_at_cursor(console_t *cons, char const *str, int n)
if(!console_line_insert(last_line, cons->cursor, str, round_size))
return false;
cons->cursor += round_size;
cons->render_needed = true;
if(round_size < n && !console_new_line(cons))
return false;
n -= round_size;
@ -257,12 +264,15 @@ bool console_write_at_cursor(console_t *cons, char const *buf, int n)
cons->cursor += (cons->cursor < last_line->size);
}
}
cons->render_needed = true;
}
return true;
}
void console_render(int x, int y, console_t *cons, int w, int lines)
void console_render(int x, int y, console_t const *cons, int w, int dy,
int lines)
{
int watermark = lines;
@ -277,12 +287,17 @@ void console_render(int x, int y, console_t *cons, int w, int lines)
bool show_cursor = (i == cons->line_count - 1);
if(watermark + line->render_lines > 0)
y = console_line_render(x, y, line, w, PE_CONSOLE_LINE_SPACING,
-watermark, show_cursor ? cons->cursor : -1);
y = console_line_render(x, y, line, w, dy, -watermark,
show_cursor ? cons->cursor : -1);
watermark += line->render_lines;
}
}
void console_clear_render_flag(console_t *cons)
{
cons->render_needed = false;
}
void console_destroy(console_t *cons)
{
for(int i = 0; i < cons->line_count; i++)
@ -290,3 +305,56 @@ void console_destroy(console_t *cons)
free(cons->lines);
free(cons);
}
//=== Input method ===//
/* Features needed to bypass MicroPython's readline:
* Undefined MICROPY_HAL_HAS_VT100
* Multi-line input
- Provide PS1 and PS2
- Auto-indent
- TODO: How is it stored?
* History
- Let's use `MP_STATE_PORT(readline_hist)` for a start
- Keep track of history browsing state
- While at it do the zsh history search, which is goated
- Use readline_push_history()
* Cursor movement (fairly easy)
* Handle special inputs
- ^C, ^D, backspace
- Erase line (^K)
* Autocompletion
- Use mp_repl_autocomplete() which should hook just fine */
int console_key_event_to_char(key_event_t ev)
{
int key = ev.key;
/* (The following meanings are only for non-empty lines) */
/* TODO: Check cons->cursor before triggering them */
if(key == KEY_LEFT && ev.shift)
return CHAR_CTRL_A; /* go-to-start-of-line */
if(key == KEY_LEFT)
return CHAR_CTRL_B; /* go-back-one-char */
if(key == KEY_ACON)
return CHAR_CTRL_C; /* cancel */
if(key == KEY_DEL && !ev.shift)
return 8; /* delete-at-cursor */
if(key == KEY_RIGHT && ev.shift)
return CHAR_CTRL_E; /* go-to-end-of-line */
if(key == KEY_RIGHT)
return CHAR_CTRL_F; /* go-forward-one-char */
if(key == KEY_DEL && ev.shift)
return CHAR_CTRL_K; /* kill from cursor to end-of-line */
if(key == KEY_DOWN)
return CHAR_CTRL_N; /* go to next line in history */
if(key == KEY_UP)
return CHAR_CTRL_P; /* go to previous line in history */
if(key == KEY_EXIT)
return CHAR_CTRL_D; /* eof */
if(key == KEY_EXE)
return '\r';
return keymap_translate(key, ev.shift, ev.alpha);
}

View File

@ -17,19 +17,13 @@
#ifndef __PYTHONEXTRA_CONSOLE_H
#define __PYTHONEXTRA_CONSOLE_H
#include <gint/keyboard.h>
#include <stdbool.h>
/* Maximum line length, to ensure the console can threshold its memory usage
while cleaning only entire lines. Lines longer than this get split. */
#define PE_CONSOLE_LINE_MAX_LENGTH 1024
/* Line spacing in the console */
#ifdef FX9860G
# define PE_CONSOLE_LINE_SPACING 8
#else
# define PE_CONSOLE_LINE_SPACING 13
#endif
//=== Dynamic console lines ===//
typedef struct
@ -84,6 +78,9 @@ typedef struct
/* Cursor position within the last line. */
int cursor;
/* Whether new data has been added and a frame should be rendered. */
bool render_needed;
} console_t;
/* Create a new console with the specified backlog size. */
@ -105,8 +102,18 @@ bool console_write_block_at_cursor(console_t *cons, char const *str, int n);
bool console_write_at_cursor(console_t *cons, char const *str, int n);
/* TODO: Expand this function */
void console_render(int x, int y, console_t *cons, int w, int lines);
void console_render(int x, int y, console_t const *cons, int w, int dy,
int lines);
void console_clear_render_flag(console_t *cons);
void console_destroy(console_t *cons);
//=== Input method ===//
/* Interpret a key event into a terminal input. This is a pretty raw input
method with no shift/alpha lock, kept for legacy as a VT-100-style terminal
emulator. */
int console_key_event_to_char(key_event_t ev);
#endif /* __PYTHONEXTRA_CONSOLE_H */

View File

@ -14,13 +14,33 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/fs.h>
#include <justui/jscene.h>
#include <justui/jlabel.h>
#include <justui/jfkeys.h>
#include <justui/jfileselect.h>
#include <justui/jpainted.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "console.h"
#include "shell.h"
#include "widget_shell.h"
//---
#include "py/mphal.h"
#include "py/repl.h"
#include "genhdr/mpversion.h"
#ifdef FX9860G
#define _(fx, cg) (fx)
#else
#define _(fx, cg) (cg)
#endif
static ssize_t stdouterr_write(void *data, void const *buf, size_t size)
{
@ -36,9 +56,33 @@ fs_descriptor_type_t stdouterr_type = {
.close = NULL,
};
/* The global terminal. */
console_t *pe_shell_console;
static bool strendswith(char const *str, char const *suffix)
{
size_t l1 = strlen(str);
size_t l2 = strlen(suffix);
return l1 >= l2 && strcmp(str + l1 - l2, suffix) == 0;
}
static bool py_file_filter(struct dirent const *ent)
{
if(!jfileselect_default_filter(ent))
return false;
if(ent->d_type == DT_REG && !strendswith(ent->d_name, ".py"))
return false;
return true;
}
int main(int argc, char **argv)
{
pe_shell_init();
//=== Init sequence ===//
pe_shell_console = console_create(8192);
/* Set up standard streams */
close(STDOUT_FILENO);
@ -68,13 +112,70 @@ int main(int argc, char **argv)
// * (keep the OS heap for normal malloc())
mp_init();
// Start a normal REPL; will exit when ctrl-D is entered on a blank line.
pyexec_friendly_repl();
/* Run REPL manually */
pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
pyexec_event_repl_init();
//=== GUI setup ===//
jscene *scene = jscene_create_fullscreen(NULL);
jlabel *title = jlabel_create("PythonExtra", scene);
jwidget *stack = jwidget_create(scene);
jfkeys *fkeys = jfkeys_create("/FILES;/SHELL;;;;", scene);
(void)fkeys;
jwidget_set_background(title, C_BLACK);
jlabel_set_text_color(title, C_WHITE);
jwidget_set_stretch(title, 1, 0, false);
jwidget_set_padding(title, _(1, 3), _(2, 6), _(1, 3), _(2, 6));
jlayout_set_vbox(scene)->spacing = _(1, 3);
jlayout_set_stack(stack);
jwidget_set_padding(stack, 0, 6, 0, 6);
jwidget_set_stretch(stack, 1, 1, false);
/* Filesystem tab */
jfileselect *fileselect = jfileselect_create(stack);
jfileselect_set_filter(fileselect, py_file_filter);
jfileselect_set_show_file_size(fileselect, true);
jwidget_set_stretch(fileselect, 1, 1, false);
/* Shell tab */
widget_shell *shell = widget_shell_create(pe_shell_console, stack);
widget_shell_set_line_spacing(shell, _(1, 3));
jwidget_set_stretch(shell, 1, 1, false);
/* Initial state */
jfileselect_browse(fileselect, "/");
jscene_show_and_focus(scene, fileselect);
//=== Event handling ===//
while(1) {
jevent e = jscene_run(scene);
if(e.type == JSCENE_PAINT) {
dclear(C_WHITE);
jscene_render(scene);
dupdate();
}
if(e.type != JWIDGET_KEY || e.key.type == KEYEV_UP)
continue;
int key = e.key.key;
if(key == KEY_F1)
jscene_show_and_focus(scene, fileselect);
if(key == KEY_F2)
jscene_show_and_focus(scene, shell);
}
//=== Deinitialization ===//
// Deinitialise the runtime.
gc_sweep_all();
mp_deinit();
pe_shell_deinit();
console_destroy(pe_shell_console);
return 0;
}

View File

@ -13,7 +13,6 @@
#include "py/objtuple.h"
#include <gint/display.h>
#include <gint/keyboard.h>
#include "shell.h"
#define FUN_0(NAME) \
MP_DEFINE_CONST_FUN_OBJ_0(modgint_ ## NAME ## _obj, modgint_ ## NAME)

View File

@ -21,6 +21,7 @@
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE)
#define MICROPY_REPL_EVENT_DRIVEN (1)
/* Other features that we select against MICROPY_CONFIG_ROM_LEVEL */
#define MICROPY_PY_FSTRINGS (1) /* in EXTRA_FEATURES */

View File

@ -5,9 +5,7 @@
//---------------------------------------------------------------------------//
#include "py/mphal.h"
#include "../../shared/readline/readline.h"
#include "keymap.h"
#include "shell.h"
#include "console.h"
#include <gint/display.h>
#include <gint/keyboard.h>
#include <unistd.h>
@ -16,33 +14,7 @@ int mp_hal_stdin_rx_chr(void)
{
while(1) {
key_event_t ev = getkey();
int key = ev.key;
/* (The following meanings are only for non-empty lines) */
/* TODO: Check cons->cursor before triggering them */
if(key == KEY_LEFT && ev.shift)
return CHAR_CTRL_A; /* go-to-start-of-line */
if(key == KEY_LEFT)
return CHAR_CTRL_B; /* go-back-one-char */
if(key == KEY_ACON)
return CHAR_CTRL_C; /* cancel */
if(key == KEY_DEL && !ev.shift)
return 8; /* delete-at-cursor */
if(key == KEY_RIGHT && ev.shift)
return CHAR_CTRL_E; /* go-to-end-of-line */
if(key == KEY_RIGHT)
return CHAR_CTRL_F; /* go-forward-one-char */
if(key == KEY_DEL && ev.shift)
return CHAR_CTRL_K; /* kill from cursor to end-of-line */
if(key == KEY_DOWN)
return CHAR_CTRL_N; /* go to next line in history */
if(key == KEY_UP)
return CHAR_CTRL_P; /* go to previous line in history */
if(key == KEY_EXE)
return '\r';
uint32_t code_point = keymap_translate(key, ev.shift, ev.alpha);
int code_point = console_key_event_to_char(ev);
if(code_point != 0)
return code_point;
}
@ -52,6 +24,4 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len)
{
int r = write(STDOUT_FILENO, str, len);
(void)r;
pe_shell_schedule_update();
}

View File

@ -1,69 +1,18 @@
//---------------------------------------------------------------------------//
// ____ PythonExtra //
//.-'`_ o `;__, A community port of MicroPython for CASIO calculators. //
//.-'` `---` ' License: MIT (except some files; see LICENSE) //
//---------------------------------------------------------------------------//
#include "shell.h"
#include <gint/timer.h>
#include <gint/display.h>
/* The global terminal. */
console_t *pe_shell_console;
/* Timer handle for the refresh clock. */
static int pe_shell_timer = -1;
/* Whether there is new shell data to be shown on the next frame. */
static bool pe_shell_update = true;
static void pe_shell_draw(void)
{
dclear(C_WHITE);
#ifdef FX9860G
int rows = 8;
console_render(1, 1, pe_shell_console, DWIDTH-2, rows);
#else
dprint(3, 3, C_BLACK, "PythonExtra, very much WIP :)");
dline(2, 16, DWIDTH-3, 16, C_BLACK);
int rows = 12;
console_render(3, 20, pe_shell_console, DWIDTH-6, rows);
int y = 20 + PE_CONSOLE_LINE_SPACING * rows;
dline(2, y, DWIDTH-3, y, C_BLACK);
#endif
dupdate();
}
static int pe_shell_timer_handler(void)
{
if(pe_shell_update) {
pe_shell_draw();
pe_shell_update = false;
}
return TIMER_CONTINUE;
}
void pe_shell_schedule_update(void)
{
pe_shell_update = true;
}
// The shell consists of a terminal-emulating `console_t` along with some input
// UI. During execution, the shell is redrawn only (1) when new data is printed
// or requested, and (2) a fixed refresh timer hits. Condition 1 avoids
// needless updates for non-printing programs, while condition 2 prevents
// performance issues for sequences that print one character at a time (which
// is quite common even within MicroPython builtins).
//
// If the built-in function gint.dupdate() is used, the shell also hands over
// display updates to "graphics mode", where only manual dupdate() calls push
// the VRAM. Switching to graphics mode cancels any scheduled shell updates.
// Graphics mode is exited once a new shell update is explicity scheduled,
// typically by a call to print() or input().
/* TODO: Port graphics mode over to the JustUI setup */
void pe_shell_graphics_mode(void)
{
pe_shell_update = false;
}
void pe_shell_init(void)
{
pe_shell_console = console_create(8192);
pe_shell_timer = timer_configure(TIMER_ANY, 1000000 / PE_SHELL_FPS,
GINT_CALL(pe_shell_timer_handler));
timer_start(pe_shell_timer);
}
void pe_shell_deinit(void)
{
timer_stop(pe_shell_timer);
console_destroy(pe_shell_console);
// pe_shell_update = false;
}

View File

@ -1,51 +0,0 @@
//---------------------------------------------------------------------------//
// ____ PythonExtra //
//.-'`_ o `;__, A community port of MicroPython for CASIO calculators. //
//.-'` `---` ' License: MIT (except some files; see LICENSE) //
//---------------------------------------------------------------------------//
// pe.shell: Shell integration
//
// This header covers application-integration aspects of the shell. For the
// implementation of the console itself (input, escape sequences, etc). see
// <console.h> instead.
//
// The shell consists of a terminal-emulating `console_t` along with some input
// UI. During execution, the shell is redrawn only (1) when new data is printed
// or requested, and (2) a fixed refresh timer hits. Condition 1 avoids
// needless updates for non-printing programs, while condition 2 prevents
// performance issues for sequences that print one character at a time (which
// is quite common even within MicroPython builtins).
//
// If the built-in function gint.dupdate() is used, the shell also hands over
// display updates to "graphics mode", where only manual dupdate() calls push
// the VRAM. Switching to graphics mode cancels any scheduled shell updates.
// Graphics mode is exited once a new shell update is explicity scheduled,
// typically by a call to print() or input().
//---
#ifndef __PYTHONEXTRA_SHELL_H
#define __PYTHONEXTRA_SHELL_H
#include "console.h"
/* Shell frame frequency, ie. cap on the number of shell redraws per second. */
#define PE_SHELL_FPS 30
/* The terminal. */
extern console_t *pe_shell_console;
/* Schedule a redraw of the shell interface at the next shell frame. This is
called whenever data is printed into the shell or input() is used. The
scheduled redraw might be canceled by switching to graphics mode before the
frame timer fires. */
void pe_shell_schedule_update(void);
/* Switch to graphics mode. This cancels pending shell updates. */
void pe_shell_graphics_mode(void);
//=== Internal functions ===//
void pe_shell_init(void);
void pe_shell_deinit(void);
#endif /* __PYTHONEXTRA_SHELL_H */

219
ports/sh/widget_shell.c Normal file
View File

@ -0,0 +1,219 @@
//---------------------------------------------------------------------------//
// ____ PythonExtra //
//.-'`_ o `;__, A community port of MicroPython for CASIO calculators. //
//.-'` `---` ' License: MIT (except some files; see LICENSE) //
//---------------------------------------------------------------------------//
#include "widget_shell.h"
#include <justui/jwidget-api.h>
#include <gint/timer.h>
#include <stdlib.h>
/* Type identified for widget_shell */
static int widget_shell_id = -1;
//=== Modifier states ===//
enum {
MOD_IDLE, /* Not active */
MOD_INSTANT, /* Instant-loaded but not yet used */
MOD_INSTANT_USED, /* Instant-loaded and has been used */
MOD_LOCKED, /* Locked */
MOD_LOCKED_INSTANT, /* Locked and instant-loaded but not used */
MOD_LOCKED_INSTANT_USED, /* Locked and instant-loaded and used */
};
/* Handle a key press/release for a modifier */
static int mod_down(int state)
{
if(state == MOD_IDLE)
return MOD_INSTANT;
if(state == MOD_LOCKED)
return MOD_LOCKED_INSTANT;
return state;
}
static int mod_up(int state)
{
if(state == MOD_INSTANT)
return MOD_LOCKED;
if(state == MOD_INSTANT_USED)
return MOD_IDLE;
if(state == MOD_LOCKED_INSTANT)
return MOD_IDLE;
if(state == MOD_LOCKED_INSTANT_USED)
return MOD_LOCKED;
return state;
}
/* Handle a press for another key */
static int mod_down_other(int state)
{
if(state == MOD_INSTANT)
return MOD_INSTANT_USED;
if(state == MOD_LOCKED_INSTANT)
return MOD_LOCKED_INSTANT_USED;
return state;
}
/* Whether a modifier is active */
static bool mod_active(int state)
{
return state == MOD_LOCKED || state == MOD_INSTANT
|| state == MOD_INSTANT_USED;
}
//=== Shell widget ===//
static int widget_shell_timer_handler(void *s0)
{
widget_shell *s = s0;
if(s->console && s->console->render_needed)
s->widget.update = true;
return TIMER_CONTINUE;
}
widget_shell *widget_shell_create(console_t *console, void *parent)
{
if(widget_shell_id < 0)
return NULL;
widget_shell *s = malloc(sizeof *s);
if(!s)
return NULL;
s->timer_id = timer_configure(TIMER_ANY, 1000000 / WIDGET_SHELL_FPS,
GINT_CALL(widget_shell_timer_handler, (void *)s));
if(s->timer_id < 0) {
free(s);
return NULL;
}
jwidget_init(&s->widget, widget_shell_id, parent);
s->console = console;
s->font = dfont_default();
s->color = C_BLACK;
s->line_spacing = 0;
s->lines = 0;
s->shift = MOD_IDLE;
s->alpha = MOD_IDLE;
timer_start(s->timer_id);
return s;
}
void widget_shell_set_text_color(widget_shell *s, int color)
{
s->color = color;
s->widget.update = 1;
}
void widget_shell_set_font(widget_shell *s, font_t const *font)
{
s->font = font ? font : dfont_default();
s->widget.dirty = 1;
}
void widget_shell_set_line_spacing(widget_shell *s, int line_spacing)
{
s->line_spacing = line_spacing;
s->widget.dirty = 1;
}
//---
// Polymorphic widget operations
//---
static void widget_shell_poly_csize(void *s0)
{
widget_shell *s = s0;
int row_height = s->font->line_height;
int base_rows = 4;
s->widget.w = DWIDTH / 2;
s->widget.h = row_height * base_rows + s->line_spacing * (base_rows - 1);
}
static void widget_shell_poly_layout(void *s0)
{
widget_shell *s = s0;
int ch = jwidget_content_height(s);
int line_height = s->font->line_height + s->line_spacing;
s->lines = ch / line_height;
}
static void widget_shell_poly_render(void *s0, int x, int y)
{
widget_shell *s = s0;
int line_height = s->font->line_height + s->line_spacing;
font_t const *old_font = dfont(s->font);
console_render(x, y, s->console, jwidget_content_width(s), line_height,
s->lines);
console_clear_render_flag(s->console);
dfont(old_font);
}
static bool widget_shell_poly_event(void *s0, jevent e)
{
widget_shell *s = s0;
if(e.type != JWIDGET_KEY)
return false;
key_event_t ev = e.key;
if(ev.key == KEY_SHIFT) {
s->shift = ev.type == KEYEV_UP ? mod_up(s->shift) : mod_down(s->shift);
return true;
}
if(ev.key == KEY_ALPHA) {
s->alpha = ev.type == KEYEV_UP ? mod_up(s->alpha) : mod_down(s->alpha);
return true;
}
if(ev.type == KEYEV_UP)
return false;
ev.mod = true;
ev.shift = mod_active(s->shift);
ev.alpha = mod_active(s->alpha);
s->shift = mod_down_other(s->shift);
s->alpha = mod_down_other(s->alpha);
/* TODO: Handle input events better in the shell widget! */
int c = console_key_event_to_char(ev);
/* TODO: Can widget_shell_poly_event please not call into MicroPython? */
if(c != 0) {
pyexec_event_repl_process_char(c);
return true;
}
return false;
}
static void widget_shell_poly_destroy(void *s0)
{
widget_shell *s = s0;
timer_stop(s->timer_id);
}
/* widget_shell type definition */
static jwidget_poly type_widget_shell = {
.name = "widget_shell",
.csize = widget_shell_poly_csize,
.layout = widget_shell_poly_layout,
.render = widget_shell_poly_render,
.event = widget_shell_poly_event,
.destroy = widget_shell_poly_destroy,
};
__attribute__((constructor))
static void j_register_widget_shell(void)
{
widget_shell_id = j_register_widget(&type_widget_shell, "jwidget");
}

48
ports/sh/widget_shell.h Normal file
View File

@ -0,0 +1,48 @@
//---------------------------------------------------------------------------//
// ____ PythonExtra //
//.-'`_ o `;__, A community port of MicroPython for CASIO calculators. //
//.-'` `---` ' License: MIT (except some files; see LICENSE) //
//---------------------------------------------------------------------------//
// pe.widget_shell: JustUI widget for the shell
#ifndef __PYTHONEXTRA_WIDGET_SHELL_H
#define __PYTHONEXTRA_WIDGET_SHELL_H
#include <justui/defs.h>
#include <justui/jwidget.h>
#include <gint/display.h>
#include "console.h"
/* widget_shell: Multi-line Python shell input */
typedef struct {
jwidget widget;
/* Corresponding console */
console_t *console;
/* Rendering font */
font_t const *font;
/* Text color */
uint16_t color;
/* Extra line spacing */
int8_t line_spacing;
/* Internal information */
int timer_id;
uint16_t lines;
int shift, alpha;
} widget_shell;
/* Update frequency, ie. cap on the number of shell redraws per second. */
#define WIDGET_SHELL_FPS 30
/* widget_shell_create(): Create a shell widget tied to a console */
widget_shell *widget_shell_create(console_t *console, void *parent);
/* Trivial properties */
void widget_shell_set_text_color(widget_shell *shell, int color);
void widget_shell_set_font(widget_shell *shell, font_t const *font);
void widget_shell_set_line_spacing(widget_shell *shell, int line_spacing);
#endif /* __PYTHONEXTRA_WIDGET_SHELL_H */

View File

@ -400,7 +400,6 @@ STATIC int pyexec_friendly_repl_process_char(int c) {
return 0;
} else if (ret == CHAR_CTRL_B) {
// reset friendly REPL
mp_hal_stdout_tx_str("\r\n");
mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);
mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE);
mp_hal_stdout_tx_str("\r\n");