pe: show shell modifier state in GUI

This commit is contained in:
Lephenixnoir 2022-11-06 17:08:17 +01:00
parent 404d69aea4
commit 6c2aa39e56
Signed by untrusted user: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
11 changed files with 108 additions and 28 deletions

View File

@ -16,7 +16,6 @@ Most of the code is in `ports/sh` and is shared between the platforms.
Bugs to fix:
- Fix not world switching during filesystem accesses (very unstable)
- Fix console line spacing being hardcoded instead of using font data
- Fix the console not garbage collecting its lines (enable and test the feature)
Python features:
@ -28,7 +27,6 @@ Python features:
UI:
- Shell escapes: move cursor, history
- Better input system in the shell
- Use [JustUI](/Lephenixnoir/JustUI) to get a file browser (already available)
- Add an option for fixed-width font which also sets $COLUMNS properly so that
MicroPython paginates (requires better getenv/setenv support in fxlib)
- Use [unicode-fonts](/Lephenixnoir/unicode-fonts) to provide Unicode support

View File

@ -3,7 +3,9 @@ include ../../py/mkenv.mk
SH_CFLAGS := -DFX9860G
SH_LDFLAGS := -T fx9860g.ld -ljustui-fx -lm -lgint-fx -lc -lgint-fx -lgcc
SH_ASSETS := img_fkeys_main.png font_5x7.png font_4x4.png font_4x6.png
SH_ASSETS := \
img_fkeys_main.png img_modifier_states.png \
font_5x7.png font_4x4.png font_4x6.png
SH_METADATA := fxconv-metadata.txt
SH_CONVFLAGS := --fx

View File

@ -1,8 +1,9 @@
*.png:
img_*.png:
type: bopti-image
name_regex: (.*)\.png \1
font_*.png:
name_regex: (.*)\.png \1
type: font
charset: print
grid.padding: 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@ -3,8 +3,8 @@ include ../../py/mkenv.mk
SH_CFLAGS := -DFXCG50
SH_LDFLAGS := -T fxcg50.ld -ljustui-cg -lm -lgint-cg -lc -lgint-cg -lgcc
SH_ASSETS :=
SH_METADATA :=
SH_ASSETS := img_modifier_states.png
SH_METADATA := fxconv-metadata.txt
SH_CONVFLAGS := --cg
all: PythonExtra.g3a

View File

@ -0,0 +1,4 @@
img_*.png:
type: bopti-image
name_regex: (.*)\.png \1
profile: p4

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

View File

@ -339,14 +339,12 @@ int console_key_event_to_char(key_event_t ev)
return CHAR_CTRL_B; /* go-back-one-char */
if(key == KEY_ACON)
return CHAR_CTRL_C; /* cancel */
if(key == KEY_DEL && !ev.shift)
if(key == KEY_DEL)
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)

View File

@ -42,9 +42,11 @@
#ifdef FX9860G
extern bopti_image_t const img_fkeys_main;
extern bopti_image_t const img_modifier_states;
extern font_t const font_4x4, font_4x6, font_5x7;
#define _(fx, cg) (fx)
#else
extern bopti_image_t const img_modifier_states;
#define _(fx, cg) (cg)
#endif
@ -179,9 +181,26 @@ int main(int argc, char **argv)
while(1) {
jevent e = jscene_run(scene);
if(e.type == WIDGET_SHELL_MOD_CHANGED)
scene->widget.update = true;
if(e.type == JSCENE_PAINT) {
dclear(C_WHITE);
jscene_render(scene);
/* Render shell modifiers above the scene in a convenient spot */
int shift, alpha, layer;
bool instant;
widget_shell_get_modifiers(shell, &shift, &alpha);
widget_shell_modifier_info(shift, alpha, &layer, &instant);
int icon = 2 * layer + !instant;
#ifdef FX9860G
dsubimage(118, 58, &img_modifier_states, 9*icon+1, 1, 8, 6,
DIMAGE_NONE);
#else
dsubimage(377, 207, &img_modifier_states, 16*icon, 0, 15, 14,
DIMAGE_NONE);
#endif
dupdate();
}

View File

@ -12,18 +12,11 @@
/* Type identified for widget_shell */
static int widget_shell_id = -1;
/* Events */
uint16_t WIDGET_SHELL_MOD_CHANGED;
//=== 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)
{
@ -60,6 +53,11 @@ static bool mod_active(int state)
return state == MOD_LOCKED || state == MOD_INSTANT
|| state == MOD_INSTANT_USED;
}
/* Whether a modifier is in an instant mode */
static bool mod_instant(int state)
{
return state != MOD_IDLE && state != MOD_LOCKED;
}
//=== Shell widget ===//
@ -123,6 +121,23 @@ void widget_shell_set_line_spacing(widget_shell *s, int line_spacing)
s->widget.dirty = 1;
}
void widget_shell_get_modifiers(widget_shell *s, int *shift, int *alpha)
{
if(shift)
*shift = s->shift;
if(alpha)
*alpha = s->alpha;
}
void widget_shell_modifier_info(int shift, int alpha,
int *layer, bool *instant)
{
if(layer)
*layer = mod_active(shift) + 2 * mod_active(alpha);
if(instant)
*instant = mod_instant(shift) || mod_instant(alpha);
}
//---
// Polymorphic widget operations
//---
@ -158,6 +173,26 @@ static void widget_shell_poly_render(void *s0, int x, int y)
dfont(old_font);
}
static void widget_shell_update_mod(widget_shell *s, key_event_t ev)
{
int *mod = (ev.key == KEY_SHIFT) ? &s->shift : &s->alpha;
int new_mod = (ev.type == KEYEV_UP) ? mod_up(*mod) : mod_down(*mod);
if(new_mod != *mod)
jwidget_emit(s, (jevent){ .type = WIDGET_SHELL_MOD_CHANGED });
*mod = new_mod;
}
static void widget_shell_use_mods(widget_shell *s)
{
int new_shift = mod_down_other(s->shift);
int new_alpha = mod_down_other(s->alpha);
if(new_shift != s->shift || new_alpha != s->alpha)
jwidget_emit(s, (jevent){ .type = WIDGET_SHELL_MOD_CHANGED });
s->shift = new_shift;
s->alpha = new_alpha;
}
static bool widget_shell_poly_event(void *s0, jevent e)
{
widget_shell *s = s0;
@ -166,12 +201,8 @@ static bool widget_shell_poly_event(void *s0, jevent e)
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);
if(ev.key == KEY_SHIFT || ev.key == KEY_ALPHA) {
widget_shell_update_mod(s, ev);
return true;
}
@ -181,9 +212,7 @@ static bool widget_shell_poly_event(void *s0, jevent e)
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);
widget_shell_use_mods(s);
/* TODO: Handle input events better in the shell widget! */
int c = console_key_event_to_char(ev);
@ -216,4 +245,5 @@ __attribute__((constructor))
static void j_register_widget_shell(void)
{
widget_shell_id = j_register_widget(&type_widget_shell, "jwidget");
WIDGET_SHELL_MOD_CHANGED = j_register_event();
}

View File

@ -32,6 +32,17 @@
#include <gint/display.h>
#include "console.h"
/* 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 */
};
/* widget_shell: Multi-line Python shell input */
typedef struct {
jwidget widget;
@ -53,6 +64,9 @@ typedef struct {
} widget_shell;
/* Event IDs */
extern uint16_t WIDGET_SHELL_MOD_CHANGED;
/* Update frequency, ie. cap on the number of shell redraws per second. */
#define WIDGET_SHELL_FPS 30
@ -64,4 +78,18 @@ 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);
/* Get current modifier states */
void widget_shell_get_modifiers(widget_shell *shell, int *shift, int *alpha);
/* Turn a pair of shift/alpha modifiers into a more presentable form:
- The *current layer* which shows currently active modifiers:
0: Normal
1: Shifted (SHIFT)
2: Lowercase (ALPHA)
3: Uppercase (SHIFT+ALPHA)
- The *instant* boolean which is set when one of the modifiers is in
instant mode. This is the case when either SHIFT or ALPHA is pressed. */
void widget_shell_modifier_info(int shift, int alpha,
int *layer, bool *instant);
#endif /* __PYTHONEXTRA_WIDGET_SHELL_H */