mirror of
https://github.com/buserror/mii_emu.git
synced 2024-11-12 13:06:07 +00:00
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 <buserror@gmail.com>
This commit is contained in:
parent
6c5a52bd15
commit
ad86adfea4
7
Makefile
7
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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 )
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -12,12 +12,17 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <regex.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <glob.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#define MUI_HAS_REGEXP
|
||||
#endif
|
||||
#ifdef MUI_HAS_REGEXP
|
||||
#include <regex.h>
|
||||
#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);
|
||||
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
29
src/mii.c
29
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",
|
||||
|
@ -1,3 +1,10 @@
|
||||
/*
|
||||
* mui_65c02.c
|
||||
*
|
||||
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* mui_65c02.h
|
||||
*
|
||||
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -1,3 +1,10 @@
|
||||
/*
|
||||
* mui_65c02_asm.h
|
||||
*
|
||||
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -1,3 +1,10 @@
|
||||
/*
|
||||
* mii_65c02_disasm.c
|
||||
*
|
||||
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* mii_65c02_disasm.h
|
||||
*
|
||||
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* mui_65c02_ops.h
|
||||
*
|
||||
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.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,
|
||||
|
@ -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"
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -17,8 +17,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bsd_queue.h"
|
||||
#include "c_array.h"
|
||||
#include "mui.h"
|
||||
|
||||
#define MII_PATH_SIZE_MAX 256
|
||||
|
||||
|
@ -23,23 +23,6 @@
|
||||
#include "mii.h"
|
||||
#include "mii_thread.h"
|
||||
|
||||
#include <time.h>
|
||||
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 = {};
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <stdint.h>
|
||||
#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(
|
||||
|
Loading…
Reference in New Issue
Block a user