forked from Lephenixnoir/PythonExtra
pe: show shell modifier state in GUI
This commit is contained in:
parent
404d69aea4
commit
6c2aa39e56
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 |
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue