From ad86adfea4b9e253d20fd2e451bca7f2c677ce19 Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Sun, 4 Feb 2024 09:09:28 +0000 Subject: [PATCH] Mostly libmui changes + Updated libmui + Typehead in the standard file dialog + More documentation in the header file + Made regexp optional, added a new way to specify suffix list Signed-off-by: Michel Pollet --- Makefile | 7 ++- libmui/Makefile | 2 +- libmui/mui/cg.c | 3 +- libmui/mui/mui.c | 32 +++++++++- libmui/mui/mui.h | 83 +++++++++++++++++++++----- libmui/mui/mui_cdef_listbox.c | 87 ++++++++++++++++++++++----- libmui/mui/mui_stdfile.c | 108 +++++++++++++++++++++++++++++----- libmui/tests/ui_tests.c | 6 +- src/mii.c | 29 +++++++-- src/mii_65c02.c | 7 +++ src/mii_65c02.h | 8 +++ src/mii_65c02_asm.h | 7 +++ src/mii_65c02_disasm.c | 7 +++ src/mii_65c02_disasm.h | 8 +++ src/mii_65c02_ops.h | 8 +++ src/mii_sw.h | 7 ++- src/mii_video.c | 65 ++++++++++++++------ ui_gl/mii_emu_gl.c | 6 +- ui_gl/mii_mui_1mb.c | 3 +- ui_gl/mii_mui_2dsk.c | 3 +- ui_gl/mii_mui_loadbin.c | 3 +- ui_gl/mii_mui_settings.h | 3 +- ui_gl/mii_thread.c | 19 +----- ui_gl/mii_thread.h | 8 +-- 24 files changed, 410 insertions(+), 109 deletions(-) diff --git a/Makefile b/Makefile index 4582b4f..1d21c6f 100644 --- a/Makefile +++ b/Makefile @@ -91,11 +91,12 @@ VPATH += test # Base test without the UI, for performance testing $(BIN)/mii_test : $(TEST_OBJ) $(BIN)/mii_test : $(OBJ)/mii_test.o $(OBJ)/mii_mish.o -$(OBJ)/mii_test.o : CFLAGS += -O0 -Og +$(OBJ)/mii_test.o : CFLAGS := -O0 -Og ${filter-out -O%, $(CFLAGS)} -$(OBJ)/mii_cpu_test.o : CFLAGS += -O0 -Og +$(OBJ)/mii_cpu_test.o : CFLAGS := -O0 -Og ${filter-out -O%, $(CFLAGS)} $(BIN)/mii_cpu_test : $(OBJ)/mii_cpu_test.o $(TEST_OBJ) +# Assembler for the 6502 $(BIN)/mii_asm : $(OBJ)/mii_asm.o $(TEST_OBJ) ifeq ($(V),1) @@ -105,7 +106,7 @@ Q := @ endif $(OBJ)/%.o : %.c | $(OBJ) - @echo " CC " ${filter -O%, $(CPPFLAGS) $(CFLAGS)} " $<" + @echo " CC" ${filter -O%, $(CPPFLAGS) $(CFLAGS)} "$<" $(Q)$(CC) -MMD $(CPPFLAGS) $(CFLAGS) -c -o $@ $< $(BIN)/% : | $(BIN) diff --git a/libmui/Makefile b/libmui/Makefile index 0a6bb9c..877564f 100644 --- a/libmui/Makefile +++ b/libmui/Makefile @@ -72,7 +72,7 @@ $(LIB)/ui_tests.so : $(OBJ)/ui_tests.o $(LIB)/libmui.a | $(O) $(BIN)/mui_playground : $(OBJ)/mui_playground.o $(LIB)/libmui.a $(OBJ)/%.o : %.c | $(OBJ) - @echo " CC " ${filter -O%, $(CPPFLAGS) $(CFLAGS)} " $<" + @echo " CC" ${filter -O%, $(CPPFLAGS) $(CFLAGS)} "$<" $(Q)$(CC) -MMD $(CPPFLAGS) $(CFLAGS) -c -o $@ $< $(BIN)/% : | $(BIN) diff --git a/libmui/mui/cg.c b/libmui/mui/cg.c index 35fac43..6e85e33 100644 --- a/libmui/mui/cg.c +++ b/libmui/mui/cg.c @@ -151,7 +151,8 @@ void cg_matrix_multiply(struct cg_matrix_t * m, struct cg_matrix_t * m1, struct t.tx += m1->ty * m2->c; t.ty += m1->tx * m2->b; } - memcpy(m, &t, sizeof(struct cg_matrix_t)); + *m = t; +// memcpy(m, &t, sizeof(struct cg_matrix_t)); } void cg_matrix_invert(struct cg_matrix_t * m) diff --git a/libmui/mui/mui.c b/libmui/mui/mui.c index 584d17f..e19a205 100644 --- a/libmui/mui/mui.c +++ b/libmui/mui/mui.c @@ -18,8 +18,12 @@ void mui_init( mui_t *ui) { + // do NOT clear we rely on screen_size being set, this is temporary we'll + // eventually use an 'option' struct to pass that sort of data (and the + // colors) //memset(ui, 0, sizeof(*ui)); - ui->clear_color = MUI_COLOR(0xccccccff); + ui->color.clear = MUI_COLOR(0xccccccff); + ui->color.highlight = MUI_COLOR(0xd6fcc0ff); TAILQ_INIT(&ui->windows); TAILQ_INIT(&ui->zombies); TAILQ_INIT(&ui->fonts); @@ -95,9 +99,9 @@ mui_draw( mui_drawable_clip_push_region(dr, §); pixman_image_fill_boxes( - ui->clear_color.value ? PIXMAN_OP_SRC : PIXMAN_OP_CLEAR, + ui->color.clear.value ? PIXMAN_OP_SRC : PIXMAN_OP_CLEAR, mui_drawable_get_pixman(dr), - &PIXMAN_COLOR(ui->clear_color), 1, (pixman_box32_t*)&desk); + &PIXMAN_COLOR(ui->color.clear), 1, (pixman_box32_t*)&desk); pixman_region32_fini(§); pixman_region32_fini(&done); @@ -228,6 +232,28 @@ mui_timer_register( return 0; } +mui_time_t +mui_timer_reset( + struct mui_t * ui, + uint8_t id, + mui_timer_p cb, + mui_time_t delay) +{ + if (id >= MUI_TIMER_COUNT) + return 0; + if (!(ui->timer.map & (1 << id)) || + ui->timer.timers[id].cb != cb) + return 0; + mui_time_t res = 0; + uint64_t now = mui_get_time(); + if (ui->timer.timers[id].when > now) + res = ui->timer.timers[id].when - now; + ui->timer.timers[id].when = now + delay; + if (delay == 0) + ui->timer.map &= ~(1 << id); + return res; +} + void mui_timers_run( mui_t *ui ) diff --git a/libmui/mui/mui.h b/libmui/mui/mui.h index 9b8d732..26340b9 100644 --- a/libmui/mui/mui.h +++ b/libmui/mui/mui.h @@ -216,7 +216,7 @@ typedef bool (*mui_wdef_p)( struct mui_window_t * win, uint8_t what, void * param); -enum { +enum mui_cdef_e { MUI_CDEF_INIT = 0, MUI_CDEF_DISPOSE, MUI_CDEF_DRAW, @@ -308,6 +308,16 @@ DECLARE_C_ARRAY(mui_region_t, mui_clip_stack, 2); * image, AND also the context for the 'cg' vectorial library. * Furthermore it keeps track of a stack of clipping rectangles, and is able * to 'sync' the current clipping area for either (or both) cg and libpixman. + * + * Important note: the cg vectorial library coordinate system is placed on the + * space *between* pixels, ie, if you moveto(1,1) and draw a line down, you + * will light up pixels in columns zero AND one. This differs significantly from + * for example, pixman that is uses pixel coordinates on hard pixels. + * It's worth remembering as if you draw for example around the border of a + * control, it will very likely be 'clipped' somewhat because half the pixels + * are technically outside the control bounding/clipping rectangle. + * You can easily adjust for this by adding 0.5 to the coordinates, if you + * require it. */ typedef struct mui_drawable_t { mui_pixmap_t pix; // *has* to be first in struct @@ -604,7 +614,7 @@ DECLARE_C_ARRAY(mui_menu_item_t, mui_menu_items, 2, bool read_only; ); IMPLEMENT_C_ARRAY(mui_menu_items); -enum { +enum mui_menubar_action_e { // parameter is a mui_menu_item_t* for the first item of the menu, // this is exactly the parameter passed to add_simple() // you can use this to disable/enable menu items etc @@ -658,14 +668,14 @@ enum mui_control_type_e { MUI_CONTROL_POPUP, }; -enum { +enum mui_button_style_e { MUI_BUTTON_STYLE_NORMAL = 0, MUI_BUTTON_STYLE_DEFAULT = 1, MUI_BUTTON_STYLE_RADIO, MUI_BUTTON_STYLE_CHECKBOX, }; -enum { +enum mui_control_state_e { MUI_CONTROL_STATE_NORMAL = 0, MUI_CONTROL_STATE_HOVER, MUI_CONTROL_STATE_CLICKED, @@ -673,7 +683,7 @@ enum { MUI_CONTROL_STATE_COUNT }; -enum { +enum mui_control_action_e { MUI_CONTROL_ACTION_NONE = 0, MUI_CONTROL_ACTION_VALUE_CHANGED = FCC('c','v','a','l'), MUI_CONTROL_ACTION_CLICKED = FCC('c','l','k','d'), @@ -854,14 +864,42 @@ enum mui_std_action_e { MUI_STDF_ACTION_SELECT = FCC('s','t','d','s'), MUI_STDF_ACTION_CANCEL = FCC('s','t','d','c'), }; +enum mui_std_flags_e { + // 'pattern' is a GNU extended regexp applied to filenames. + MUI_STDF_FLAG_REGEXP = (1 << 0), + // don't use the 'pref_directory', load, or same preference files + MUI_STDF_FLAG_NOPREF = (1 << 1), +}; +/* + * Standard file dialog related + * + * Presents a standard 'get' file dialog, with optional prompt, regexp and + * start path. The return value is a pointer to a window, you can add your own + * 'action' function to get MUI_STDF_ACTION_* events. + * Once in the action function, you can call mui_stdfile_get_selected_path() + * to get the selected path, and free it when done. + * NOTE: The dialog does not auto-close, your own action function should close + * the dialog using mui_window_dispose(). + * + * The dialog will attempt to remember the last directory used *for this + * particular pattern* and will use it as the default start path when called + * again. This is optional, it requires a mui->pref_directory to be set. + * You can also disable this feature by setting the MUI_STDF_FLAG_NOPREF flag. + * + * + 'pattern' is a regular expression to filter the files, or NULL for no + * filter. + * + if 'start_path' is NULL, the $HOME directory is used. + * + 'where' is the location of the dialog, (0,0) will center it. + */ mui_window_t * mui_stdfile_get( struct mui_t * ui, c2_pt_t where, const char * prompt, - const char * regexp, - const char * start_path ); + const char * pattern, + const char * start_path, + uint16_t flags ); // return the curently selected pathname -- caller must free() it char * mui_stdfile_get_selected_path( @@ -870,7 +908,7 @@ mui_stdfile_get_selected_path( /* * Alert dialog */ -enum { +enum mui_alert_flag_e { MUI_ALERT_FLAG_OK = (1 << 0), MUI_ALERT_FLAG_CANCEL = (1 << 1), @@ -893,7 +931,7 @@ mui_alert( const char * message, uint16_t flags ); -enum { +enum mui_time_e { MUI_TIME_RES = 1, MUI_TIME_SECOND = 1000000, MUI_TIME_MS = (MUI_TIME_SECOND/1000), @@ -901,20 +939,22 @@ enum { mui_time_t mui_get_time(); +#define MUI_TIMER_COUNT 64 + typedef struct mui_timer_group_t { uint64_t map; struct { mui_time_t when; mui_timer_p cb; void * param; - } timers[64]; + } timers[MUI_TIMER_COUNT]; } mui_timer_group_t; /* * Register 'cb' to be called after 'delay'. Returns a timer id (0 to 63) - * or 0xff if no timer is available. The timer function cb can return 0 for a one - * shot timer, or another delay that will be added to the current stamp for a further - * call of the timer. + * or 0xff if no timer is available. The timer function cb can return 0 for a + * one shot timer, or another delay that will be added to the current stamp + * for a further call of the timer. * 'param' will be also passed to the timer callback. */ uint8_t @@ -923,10 +963,25 @@ mui_timer_register( mui_timer_p cb, void * param, uint32_t delay); +/* + * Reset timer 'id' if 'cb' matches what was registered. Set a new delay, + * or cancel the timer if delay is 0. + * Returns the time that was left on the timer, or 0 if the timer was + * not found. + */ +mui_time_t +mui_timer_reset( + struct mui_t * ui, + uint8_t id, + mui_timer_p cb, + mui_time_t delay); typedef struct mui_t { c2_pt_t screen_size; - mui_color_t clear_color; + struct { + mui_color_t clear; + mui_color_t highlight; + } color; uint16_t modifier_keys; int draw_debug; // this is the sum of all the window's dirty regions, inc moved windows etc diff --git a/libmui/mui/mui_cdef_listbox.c b/libmui/mui/mui_cdef_listbox.c index 564f427..e5c79d7 100644 --- a/libmui/mui/mui_cdef_listbox.c +++ b/libmui/mui/mui_cdef_listbox.c @@ -24,6 +24,13 @@ typedef struct mui_listbox_control_t { mui_ldef_p ldef; // to handle double-click mui_time_t last_click; + // typehead search related + struct { + uint8_t enabled; + uint8_t timer; + char buf[32]; + uint8_t index; + } typehead; } mui_listbox_control_t; extern const mui_control_color_t mui_control_color[MUI_CONTROL_STATE_COUNT]; @@ -56,7 +63,7 @@ mui_listbox_draw( mui_font_t * icons = mui_font_find(win->ui, "icon_small"); mui_font_t * main = mui_font_find(win->ui, "main"); - mui_color_t highlight = MUI_COLOR(0xd6fcc0ff); + mui_color_t highlight = win->ui->color.highlight; for (unsigned int ii = top_element; ii < lb->elems.count && ii < bottom_element; ii++) { @@ -85,13 +92,70 @@ mui_listbox_draw( mui_drawable_clip_pop(dr); } +/* mui_timer used to 'cancel' the typehead if a certain delay has lapsed */ +static mui_time_t +mui_listbox_typehead_timer( + struct mui_t * mui, + mui_time_t now, + void * param) +{ + mui_listbox_control_t *lb = param; + lb->typehead.enabled = 0; + lb->typehead.timer = 0xff; + lb->typehead.index = 0; +// printf("typehead: cancelled\n"); + return 0; +} + +static int32_t +mui_listbox_typehead( + mui_listbox_control_t *lb, + mui_event_t * ev) +{ + if (ev->key.key < 32 || ev->key.key > 127) + return false; + if (!lb->typehead.enabled) { + lb->typehead.enabled = 1; + lb->typehead.index = 0; + lb->typehead.timer = mui_timer_register( + lb->control.win->ui, + mui_listbox_typehead_timer, + lb, MUI_TIME_MS * 1000); + } + // add character to the current prefix + if (lb->typehead.index < sizeof(lb->typehead.buf) - 1) + lb->typehead.buf[lb->typehead.index++] = ev->key.key; + lb->typehead.buf[lb->typehead.index] = 0; +// printf("typehead: %d '%s'\n", lb->typehead.index, lb->typehead.buf); + // reset cancel timer + mui_timer_reset(lb->control.win->ui, + lb->typehead.timer, mui_listbox_typehead_timer, + MUI_TIME_MS * 1000); + // we do the lookup twice, once with the case sensitive test, and if + // that find something that matches, we're good. If not, try to match + // the prefix in a non-case sensitive way in case the user doesn't know + // what he wants... + for (unsigned int ii = 0; ii < lb->elems.count; ii++) { + mui_listbox_elem_t *e = &lb->elems.e[ii]; + if (strncmp(e->elem, lb->typehead.buf, lb->typehead.index) == 0) + return ii - lb->control.value; + } + for (unsigned int ii = 0; ii < lb->elems.count; ii++) { + mui_listbox_elem_t *e = &lb->elems.e[ii]; + if (strncasecmp(e->elem, lb->typehead.buf, lb->typehead.index) == 0) + return ii - lb->control.value; + } +// printf("typehead: no match\n"); + return 0; +} + static bool mui_listbox_key( mui_control_t * c, mui_event_t * ev) { mui_listbox_control_t *lb = (mui_listbox_control_t *)c; - printf("%s key: %d\n", __func__, ev->key.key); +// printf("%s key: %d '%c'\n", __func__, ev->key.key, ev->key.key); c2_rect_t f = c->frame; c2_rect_offset(&f, -f.l, -f.t); uint32_t page_size = (c2_rect_height(&f) / lb->elem_height)-1; @@ -99,6 +163,8 @@ mui_listbox_key( int delta = 0; if (ev->modifiers & (MUI_MODIFIER_SUPER | MUI_MODIFIER_CTRL)) return false; + if (isalpha(ev->key.key)) + delta = mui_listbox_typehead(lb, ev); switch (ev->key.key) { case MUI_KEY_UP: delta = -1; break; case MUI_KEY_DOWN: delta = 1; break; @@ -121,17 +187,16 @@ mui_listbox_key( -e.t + (c->value * lb->elem_height)); c2_rect_t w = f; c2_rect_offset(&w, 0, lb->scroll); - printf(" e:%s f:%s\n", c2_rect_as_str(&e), c2_rect_as_str(&w)); +// printf(" e:%s f:%s\n", c2_rect_as_str(&e), c2_rect_as_str(&w)); if (e.b > w.b) { lb->scroll = (e.b - c2_rect_height(&c->frame)); - printf(" over %d\n", lb->scroll); + // printf(" over %d\n", lb->scroll); } if (e.t < w.t) lb->scroll = e.t; - printf(" scroll:%d\n", lb->scroll); +// printf(" scroll:%d\n", lb->scroll); mui_control_set_value(lb->scrollbar, lb->scroll); mui_control_inval(c); -// mui_control_inval(lb->scrollbar); mui_control_action(c, MUI_CONTROL_ACTION_VALUE_CHANGED, &lb->elems.e[nsel]); return true; @@ -177,15 +242,7 @@ mui_cdef_event( } return true; } break; - case MUI_EVENT_KEYUP: { // ignore keydowns - if (ev->key.key == 13) { - if (!lb->elems.e[c->value].disabled) { - mui_control_action(c, - MUI_CONTROL_ACTION_SELECT, - &lb->elems.e[c->value]); - } - return true; - } + case MUI_EVENT_KEYUP: { if (mui_listbox_key(c, ev)) return true; } break; diff --git a/libmui/mui/mui_stdfile.c b/libmui/mui/mui_stdfile.c index 9aafd6c..1082904 100644 --- a/libmui/mui/mui_stdfile.c +++ b/libmui/mui/mui_stdfile.c @@ -12,12 +12,17 @@ #include #include #include -#include #include #include #include #include +#ifdef __linux__ +#define MUI_HAS_REGEXP +#endif +#ifdef MUI_HAS_REGEXP +#include +#endif #include "mui.h" #include "c2_geometry.h" @@ -27,16 +32,24 @@ DECLARE_C_ARRAY(char*, string_array, 2); IMPLEMENT_C_ARRAY(string_array); +#define MUI_STDF_MAX_SUFFIX 16 + typedef struct mui_stdfile_t { mui_window_t win; mui_control_t * ok, *cancel, *home, *root; mui_control_t * listbox, *popup; char * pref_file; // pathname we put last path used char * re_pattern; + struct { + char s[16]; + uint32_t hash; + } suffix[MUI_STDF_MAX_SUFFIX]; char * current_path; char * selected_path; - regex_t re; string_array_t pop_path; +#ifdef MUI_HAS_REGEXP + regex_t re; +#endif } mui_stdfile_t; enum { @@ -66,6 +79,24 @@ _mui_stdfile_sort_cb( return strcmp(ea->elem, eb->elem); } +static uint32_t +mui_hash_nocase( + const char * inString ) +{ + if (!inString) + return 0; + /* Described http://papa.bretmulvey.com/post/124027987928/hash-functions */ + const uint32_t p = 16777619; + uint32_t hash = 0x811c9dc5; + while (*inString) + hash = (hash ^ tolower(*inString++)) * p; + hash += hash << 13; + hash ^= hash >> 7; + hash += hash << 3; + hash ^= hash >> 17; + hash += hash << 5; + return hash; +} static int _mui_stdfile_populate( mui_stdfile_t * std, @@ -139,10 +170,35 @@ _mui_stdfile_populate( stat(full_path, &st); free(full_path); mui_listbox_elem_t e = {}; - // usr the regex to filter file names - if (std->re_pattern) { - if (!S_ISDIR(st.st_mode) && regexec(&std->re, ent->d_name, 0, NULL, 0)) - e.disabled = 1; + + // default to disable, unless we find a reason to enable + e.disabled = S_ISDIR(st.st_mode) ? 0 : 1; + // use the regex (if any) to filter file names + if (e.disabled && std->re_pattern) { +#ifdef MUI_HAS_REGEXP + if (regexec(&std->re, ent->d_name, 0, NULL, 0) == 0) + e.disabled = 0; +#endif + } + // handle case when no regexp is set, and no suffixes was set, this + // we enable all the files by default. + if (e.disabled && !std->re_pattern) + e.disabled = std->suffix[0].s[0] ? 1 : 0; + // handle the case we have a list of dot suffixes to filter + if (e.disabled) { + char *suf = strrchr(ent->d_name, '.'); + if (std->suffix[0].s[0] && suf) { + suf++; + uint32_t hash = mui_hash_nocase(suf); + for (int i = 0; i < MUI_STDF_MAX_SUFFIX && + std->suffix[i].s[0]; i++) { + if (hash == std->suffix[i].hash && + !strcasecmp(suf, std->suffix[i].s)) { + e.disabled = 0; + break; + } + } + } } e.elem = strdup(ent->d_name); if (S_ISDIR(st.st_mode)) @@ -268,11 +324,12 @@ _mui_stdfile_control_action( mui_window_t * mui_stdfile_get( - struct mui_t * ui, - c2_pt_t where, - const char * prompt, - const char * regexp, - const char * start_path ) + struct mui_t * ui, + c2_pt_t where, + const char * prompt, + const char * pattern, + const char * start_path, + uint16_t flags ) { c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 700, 400); if (where.x == 0 && where.y == 0) @@ -285,9 +342,10 @@ mui_stdfile_get( prompt, sizeof(mui_stdfile_t)); mui_window_set_action(w, _mui_stdfile_window_action, NULL); mui_stdfile_t *std = (mui_stdfile_t *)w; - if (regexp) { - std->re_pattern = strdup(regexp); - int re = regcomp(&std->re, std->re_pattern, REG_EXTENDED); + if (pattern && *pattern && (flags & MUI_STDF_FLAG_REGEXP)) { +#ifdef MUI_HAS_REGEXP + std->re_pattern = strdup(pattern); + int re = regcomp(&std->re, std->re_pattern, REG_EXTENDED|REG_ICASE); if (re) { char * msg = NULL; asprintf(&msg, "%s\n%s", std->re_pattern, @@ -299,6 +357,26 @@ mui_stdfile_get( free(std->re_pattern); std->re_pattern = NULL; } +#else + printf("%s: Regexp not supported\n", __func__); +#endif + } else if (pattern && *pattern) { + char * dup = strdup(pattern); + char * w = dup; + char * suf; + int di = 0; + while ((suf = strsep(&w, ",")) != NULL) { + if (!*suf) + continue; + if (di >= MUI_STDF_MAX_SUFFIX) { + printf("%s Too many suffixes, ignoring: %s\n", __func__, suf); + break; + } + uint32_t hash = mui_hash_nocase(suf); + snprintf(std->suffix[di].s, sizeof(std->suffix[di].s), "%s", suf); + std->suffix[di].hash = hash; + di++; + } } mui_control_t * c = NULL; c2_rect_t cf; @@ -349,7 +427,7 @@ mui_stdfile_get( mui_control_set_action(c, _mui_stdfile_control_action, std); } int dopop = 1; // populate to start_path by default - if (ui->pref_directory) { + if (!(flags & MUI_STDF_FLAG_NOPREF) && ui->pref_directory) { uint32_t hash = std->re_pattern ? mui_hash(std->re_pattern) : 0; asprintf(&std->pref_file, "%s/std_path_%04x", ui->pref_directory, hash); printf("%s pref file: %s\n", __func__, std->pref_file); diff --git a/libmui/tests/ui_tests.c b/libmui/tests/ui_tests.c index 7f07b5e..e801b87 100644 --- a/libmui/tests/ui_tests.c +++ b/libmui/tests/ui_tests.c @@ -187,8 +187,8 @@ _init( mui_stdfile_get(ui, C2_PT(0, 0), "Select image for SmartPort card", - "\\.(hdv|po|2mg)$", - getenv("HOME")); + "hdv,po,2mg", + getenv("HOME"), 0); #endif return g; @@ -233,4 +233,4 @@ mui_plug_t mui_plug = { .dispose = _dispose, .draw = _draw, .event = _event, -}; \ No newline at end of file +}; diff --git a/src/mii.c b/src/mii.c index db1f4f9..52f90a1 100644 --- a/src/mii.c +++ b/src/mii.c @@ -322,6 +322,18 @@ mii_access_soft_switches( *byte = on; } } break; +/* + SATHER-SATHER-SATHER-SATHER-SATHER-SATHER-SATHER-SATHER-SATHER-SATHER + + Writing to high RAM is enabled when the HRAMWRT' soft switch is reset. + The controlling MPU program must set the PRE-WRITE soft switch before + it can reset HRAMWRT'. PRE-WRITE is set in the by odd read access ub the + C08X range. It is reset by even read access or any write access in the + $C08X range. + HRAMWRT' is reset by odd read access in the $C08X range when PRE-WRITE is + set. It is set by even acce.ss in the $C08X range. Any other type of access + causes HRAMWRT' to hold its current state. +*/ case 0xc080 ... 0xc08f: { res = true; uint8_t mode = addr & 0x0f; @@ -329,16 +341,25 @@ mii_access_soft_switches( static const int read_modes[4] = { 1, 0, 0, 1, }; uint8_t rd = read_modes[mode & 3]; uint8_t wr = write_modes[mode & 3]; + + if (write) { + SW_SETSTATE(mii, BSRPREWRITE, 0); + } else { + SW_SETSTATE(mii, BSRPREWRITE, mode & 1); + } + // if (SW_GETSTATE(mii, BSRPREWRITE)) + // ; SW_SETSTATE(mii, BSRWRITE, wr); SW_SETSTATE(mii, BSRREAD, rd); - SW_SETSTATE(mii, BSRPAGE2, !(mode & 0x08)); + SW_SETSTATE(mii, BSRPAGE2, !(mode & 0x08)); // A3 mii->mem_dirty = 1; // mii->trace_cpu = 1; // mii->state = MII_STOPPED; if (unlikely(mii->trace_cpu)) - printf("%04x: BSR mode addr %04x:%02x read:%s write:%s %s altzp:%02x\n", - mii->cpu.PC, addr, - mode, + printf("%04x: BSR mode %c%04x pre:%d read:%s write:%s %s altzp:%02x\n", + mii->cpu.PC, write ? 'W' : 'R', + addr, + SW_GETSTATE(mii, BSRPREWRITE), rd ? "BSR" : "ROM", wr ? "BSR" : "ROM", SW_GETSTATE(mii, BSRPAGE2) ? "page2" : "page1", diff --git a/src/mii_65c02.c b/src/mii_65c02.c index 6eadea0..74bb4f0 100644 --- a/src/mii_65c02.c +++ b/src/mii_65c02.c @@ -1,3 +1,10 @@ +/* + * mui_65c02.c + * + * Copyright (C) 2023 Michel Pollet + * + * SPDX-License-Identifier: MIT + */ #include #include diff --git a/src/mii_65c02.h b/src/mii_65c02.h index 1db6bfc..ba401ad 100644 --- a/src/mii_65c02.h +++ b/src/mii_65c02.h @@ -1,3 +1,11 @@ +/* + * mui_65c02.h + * + * Copyright (C) 2023 Michel Pollet + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include diff --git a/src/mii_65c02_asm.h b/src/mii_65c02_asm.h index 72b7dec..41dc30a 100644 --- a/src/mii_65c02_asm.h +++ b/src/mii_65c02_asm.h @@ -1,3 +1,10 @@ +/* + * mui_65c02_asm.h + * + * Copyright (C) 2023 Michel Pollet + * + * SPDX-License-Identifier: MIT + */ #pragma once #include diff --git a/src/mii_65c02_disasm.c b/src/mii_65c02_disasm.c index bcf71cb..45e3c8e 100644 --- a/src/mii_65c02_disasm.c +++ b/src/mii_65c02_disasm.c @@ -1,3 +1,10 @@ +/* + * mii_65c02_disasm.c + * + * Copyright (C) 2023 Michel Pollet + * + * SPDX-License-Identifier: MIT + */ #include #include diff --git a/src/mii_65c02_disasm.h b/src/mii_65c02_disasm.h index f32fa9e..43230a2 100644 --- a/src/mii_65c02_disasm.h +++ b/src/mii_65c02_disasm.h @@ -1,3 +1,11 @@ +/* + * mii_65c02_disasm.h + * + * Copyright (C) 2023 Michel Pollet + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include diff --git a/src/mii_65c02_ops.h b/src/mii_65c02_ops.h index 73ca68d..c0abd6c 100644 --- a/src/mii_65c02_ops.h +++ b/src/mii_65c02_ops.h @@ -1,3 +1,11 @@ +/* + * mui_65c02_ops.h + * + * Copyright (C) 2023 Michel Pollet + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include diff --git a/src/mii_sw.h b/src/mii_sw.h index f2dab00..c74cda7 100644 --- a/src/mii_sw.h +++ b/src/mii_sw.h @@ -78,10 +78,11 @@ enum { B_BSRWRITE = (12), B_BSRREAD = (13), B_BSRPAGE2 = (14), - B_SWDHIRES = (15), + B_BSRPREWRITE = (15), + B_SWDHIRES = (16), // this is no 'real' softwitch, but a bit to mention a card has // it's secondary rom online in pages c800-cfff - B_SLOTAUXROM = (16), + B_SLOTAUXROM = (17), M_SW80STORE = (1 << B_SW80STORE), M_SWALTCHARSET = (1 << B_SWALTCHARSET), @@ -98,6 +99,7 @@ enum { M_BSRWRITE = (1 << B_BSRWRITE), M_BSRREAD = (1 << B_BSRREAD), M_BSRPAGE2 = (1 << B_BSRPAGE2), + M_BSRPREWRITE = (1 << B_BSRPREWRITE), M_SWDHIRES = (1 << B_SWDHIRES), M_SLOTAUXROM = (1 << B_SLOTAUXROM), }; @@ -121,6 +123,7 @@ static const char __unused__ *mii_sw_names[] = { "BSRWRITE", "BSRREAD", "BSRPAGE2", + "BSRPREWRITE", "DHIRES", "AUXROMON", NULL, diff --git a/src/mii_video.c b/src/mii_video.c index 3ca8bf5..2c922fe 100644 --- a/src/mii_video.c +++ b/src/mii_video.c @@ -41,7 +41,7 @@ enum { */ typedef struct mii_color_t { uint32_t rgb; - uint8_t l; + uint32_t l : 8, index : 8; } mii_color_t; #define HI_LUMA(r,g,b) \ @@ -61,22 +61,22 @@ typedef struct mii_color_t { * Well not really, it is just ONE interpreation of many, we could possibly * make some sort of color lookup table to allow switching them on the fly? */ -#define C_BLACK HI_RGB(0x00, 0x00, 0x00) // black -#define C_PURPLE HI_RGB(0xff, 0x44, 0xfd) // purple -#define C_GREEN HI_RGB(0x14, 0xf5, 0x3c) // green -#define C_BLUE HI_RGB(0x14, 0xcf, 0xfd) // blue -#define C_ORANGE HI_RGB(0xff, 0x6a, 0x3c) // orange -#define C_WHITE HI_RGB(0xff, 0xff, 0xff) // white -#define C_MAGENTA HI_RGB(0xe3, 0x1e, 0x60) // magenta -#define C_DARKBLUE HI_RGB(0x60, 0x4e, 0xbd) // dark blue -#define C_DARKGREEN HI_RGB(0x00, 0xa3, 0x60) // dark green -#define C_GRAY1 HI_RGB(0x9c, 0x9c, 0x9c) // gray 1 -#define C_GRAY2 HI_RGB(0x9c, 0x9c, 0x9c) // gray 2 -#define C_LIGHTBLUE HI_RGB(0xd0, 0xc3, 0xff) // light blue -#define C_BROWN HI_RGB(0x60, 0x72, 0x03) // brown -#define C_PINK HI_RGB(0xff, 0xa0, 0xd0) // pink -#define C_YELLOW HI_RGB(0xd0, 0xdd, 0x8d) // yellow -#define C_AQUA HI_RGB(0x72, 0xff, 0xd0) // aqua +#define C_BLACK HI_RGB(0x00, 0x00, 0x00) +#define C_PURPLE HI_RGB(0xff, 0x44, 0xfd) +#define C_GREEN HI_RGB(0x14, 0xf5, 0x3c) +#define C_BLUE HI_RGB(0x14, 0xcf, 0xfd) +#define C_ORANGE HI_RGB(0xff, 0x6a, 0x3c) +#define C_WHITE HI_RGB(0xff, 0xff, 0xff) +#define C_MAGENTA HI_RGB(0xe3, 0x1e, 0x60) +#define C_DARKBLUE HI_RGB(0x60, 0x4e, 0xbd) +#define C_DARKGREEN HI_RGB(0x00, 0xa3, 0x60) +#define C_GRAY1 HI_RGB(0x9c, 0x9c, 0x9c) +#define C_GRAY2 HI_RGB(0x9c, 0x9c, 0x9c) +#define C_LIGHTBLUE HI_RGB(0xd0, 0xc3, 0xff) +#define C_BROWN HI_RGB(0x60, 0x72, 0x03) +#define C_PINK HI_RGB(0xff, 0xa0, 0xd0) +#define C_YELLOW HI_RGB(0xd0, 0xdd, 0x8d) +#define C_AQUA HI_RGB(0x72, 0xff, 0xd0) // this is not an official color, just 'my' interpretation of an amber screen #define C_AMBER HI_RGB(0xfd, 0xcf, 0x14) // amber @@ -126,6 +126,7 @@ static inline uint8_t reverse8(uint8_t b) { b = (b & 0b10101010) >> 1 | (b & 0b01010101) << 1; return b; } +// Used for DHRES decoding static inline uint8_t reverse4(uint8_t b) { b = (b & 0b0001) << 3 | (b & 0b0010) << 1 | (b & 0b0100) >> 1 | (b & 0b1000) >> 3; @@ -461,8 +462,31 @@ mii_video_init( { mii->video.timer_id = mii_timer_register(mii, mii_video_timer_cb, NULL, MII_VIDEO_H_CYCLES, __func__); + // start the DHRES in color + mii_bank_t * main = &mii->bank[MII_BANK_MAIN]; + mii_bank_poke(main, SWAN3_REGISTER, 1); } +/* given a RGB color r,g,b, print a table of 16 RGB colors that are graded + from luminance 0 to 1 in that particular shade of color. +*/ +void +mii_video_print_color_table( + uint32_t rgb) +{ + uint8_t b = (rgb >> 16) & 0xff; + uint8_t g = (rgb >> 8) & 0xff; + uint8_t r = (rgb >> 0) & 0xff; + uint8_t l = HI_LUMA(r, g, b); + printf("// LUMA %d start color %02x %02x %02x\n{ ", l, r, g, b); + for (int i = 0; i < 16; i++) { + uint8_t ll = (l * i) / 15; + uint8_t rr = (r * ll) / l; + uint8_t gg = (g * ll) / l; + uint8_t bb = (b * ll) / l; + printf("%01x: %02x %02x %02x\n", i, rr, gg, bb); + } +} static void @@ -471,7 +495,7 @@ _mii_mish_video( int argc, const char * argv[]) { - mii_t * mii = param; +// mii_t * mii = param; if (!argv[1] || !strcmp(argv[1], "list")) { for (int i = 0; i < 16; i++) { @@ -482,6 +506,11 @@ _mii_mish_video( } return; } + if (!strcmp(argv[1], "gradient")) { + mii_video_print_color_table(lores_colors[0][1].rgb); + + return; + } } #include "mish.h" diff --git a/ui_gl/mii_emu_gl.c b/ui_gl/mii_emu_gl.c index ed7100e..56a336d 100644 --- a/ui_gl/mii_emu_gl.c +++ b/ui_gl/mii_emu_gl.c @@ -877,7 +877,7 @@ mii_x11_reload_config( mii_reset(mii, true); /* start the CPU/emulator thread */ - ui->cpu_thread = mii_thread_start(mii); + ui->cpu_thread = mii_threads_start(mii); } mii_x11_t g_mii = {}; @@ -932,7 +932,7 @@ main( mii_x11_init(ui); mui_t * mui = &ui->video.mui; // to move to a function later mui_init(mui); - mui->clear_color.value = 0; + mui->color.clear.value = 0; asprintf(&mui->pref_directory, "%s/.local/share/mii", getenv("HOME")); mii_mui_menus_init((mii_mui_t*)ui); @@ -957,7 +957,7 @@ main( mii_config_open_slots_dialog(&ui->video); } /* start the CPU/emulator thread */ - ui->cpu_thread = mii_thread_start(mii); + ui->cpu_thread = mii_threads_start(mii); while (mii->state != MII_INIT) { /* Input */ diff --git a/ui_gl/mii_mui_1mb.c b/ui_gl/mii_mui_1mb.c index 115cf1a..15de653 100644 --- a/ui_gl/mii_mui_1mb.c +++ b/ui_gl/mii_mui_1mb.c @@ -204,7 +204,8 @@ _mii_1mb_action_cb( C2_PT(0, 0), "Select a file (Exactly 1MB in size)", "\\.(po|hdv|bin|rom)$", - getenv("HOME")); + getenv("HOME"), + MUI_STDF_FLAG_REGEXP); mui_window_set_action(w, _mii_1mb_stdfile_cb, m); } break; case MII_1MB_USE_BIN: diff --git a/ui_gl/mii_mui_2dsk.c b/ui_gl/mii_mui_2dsk.c index e596ac0..781f700 100644 --- a/ui_gl/mii_mui_2dsk.c +++ b/ui_gl/mii_mui_2dsk.c @@ -143,7 +143,8 @@ _mii_2dsk_action_cb( m->drive_kind == MII_2DSK_SMARTPORT ? "\\.(po|hdv|2mg)$" : "\\.(dsk)$", - getenv("HOME")); + getenv("HOME"), + MUI_STDF_FLAG_REGEXP); mui_window_set_action(w, _mii_2dsk_stdfile_cb, m); } } break; diff --git a/ui_gl/mii_mui_loadbin.c b/ui_gl/mii_mui_loadbin.c index 2578579..bc60472 100644 --- a/ui_gl/mii_mui_loadbin.c +++ b/ui_gl/mii_mui_loadbin.c @@ -89,7 +89,8 @@ _mii_loadbin_action_cb( C2_PT(0, 0), "Select a .bin file to run", "\\.(bin|rom)$", - getenv("HOME")); + getenv("HOME"), + MUI_STDF_FLAG_REGEXP); mui_window_set_action(w, _mii_loadbin_stdfile_cb, m); } break; } diff --git a/ui_gl/mii_mui_settings.h b/ui_gl/mii_mui_settings.h index 011e7fe..14a5db0 100644 --- a/ui_gl/mii_mui_settings.h +++ b/ui_gl/mii_mui_settings.h @@ -17,8 +17,7 @@ #include -#include "bsd_queue.h" -#include "c_array.h" +#include "mui.h" #define MII_PATH_SIZE_MAX 256 diff --git a/ui_gl/mii_thread.c b/ui_gl/mii_thread.c index 768928b..520b920 100644 --- a/ui_gl/mii_thread.c +++ b/ui_gl/mii_thread.c @@ -23,23 +23,6 @@ #include "mii.h" #include "mii_thread.h" -#include -typedef uint64_t mii_time_t; -enum { - MII_TIME_RES = 1, - MII_TIME_SECOND = 1000000, - MII_TIME_MS = (MII_TIME_SECOND/1000), -}; -mii_time_t -mii_get_time() -{ - struct timespec tim; - clock_gettime(CLOCK_MONOTONIC_RAW, &tim); - uint64_t time = ((uint64_t)tim.tv_sec) * (1000000 / MII_TIME_RES) + - tim.tv_nsec / (1000 * MII_TIME_RES); - return time; -} - static float default_fps = 60; mii_th_fifo_t signal_fifo; @@ -229,7 +212,7 @@ mii_thread_joystick( #endif pthread_t -mii_thread_start( +mii_threads_start( mii_t *mii) { const mii_th_fifo_t zero = {}; diff --git a/ui_gl/mii_thread.h b/ui_gl/mii_thread.h index 1e34de3..157e22a 100644 --- a/ui_gl/mii_thread.h +++ b/ui_gl/mii_thread.h @@ -11,7 +11,7 @@ #include #include "fifo_declare.h" -enum { +enum mii_th_state_e { SIGNAL_RESET, SIGNAL_STOP, SIGNAL_STEP, @@ -19,8 +19,8 @@ enum { }; typedef struct mii_th_signal_t { - uint8_t cmd; - uint8_t data; + uint8_t cmd; + uint8_t data; } mii_th_signal_t; DECLARE_FIFO(mii_th_signal_t, mii_th_fifo, 16); @@ -29,7 +29,7 @@ DEFINE_FIFO(mii_th_signal_t, mii_th_fifo); struct mii_t; pthread_t -mii_thread_start( +mii_threads_start( struct mii_t *mii); struct mii_th_fifo_t* mii_thread_get_fifo(