diff --git a/contrib/mii-icon-64.h b/contrib/mii-icon-64.h index 7af920c..d22b188 100644 --- a/contrib/mii-icon-64.h +++ b/contrib/mii-icon-64.h @@ -1,5 +1,8 @@ /* this file is auto-generated by icon-convert-tcc.c */ -static const unsigned long mii_icon64[] = { +#define MII_ICON64_SIZE 4098 +extern const unsigned long mii_icon64[MII_ICON64_SIZE]; +#ifdef MII_ICON64_DEFINE +const unsigned long mii_icon64[MII_ICON64_SIZE] = { 64,64, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -578,3 +581,4 @@ static const unsigned long mii_icon64[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; +#endif diff --git a/libmui/Makefile b/libmui/Makefile index 877564f..cf0dea2 100644 --- a/libmui/Makefile +++ b/libmui/Makefile @@ -59,6 +59,7 @@ $(LIB)/ui_tests.so : $(OBJ)/mii_mui_slots.o $(LIB)/ui_tests.so : $(OBJ)/mii_mui_loadbin.o $(LIB)/ui_tests.so : $(OBJ)/mii_mui_1mb.o $(LIB)/ui_tests.so : $(OBJ)/mii_mui_2dsk.o +$(LIB)/ui_tests.so : $(OBJ)/mii_mui_about.o # use a .temp file, otherwise the playground tries to reload before the file # is fully written, and it fails. diff --git a/libmui/mui/cg.c b/libmui/mui/cg.c index 6e85e33..44a4e7e 100644 --- a/libmui/mui/cg.c +++ b/libmui/mui/cg.c @@ -1009,6 +1009,7 @@ static struct cg_rle_t * cg_rle_intersection(struct cg_rle_t * a, struct cg_rle_ struct cg_span_t * a_end = a_spans + a->spans.size; struct cg_span_t * b_spans = b->spans.data; struct cg_span_t * b_end = b_spans + b->spans.size; + int overflow = 0; while((a_spans < a_end) && (b_spans < b_end)) { if(b_spans->y > a_spans->y) @@ -1040,6 +1041,24 @@ static struct cg_rle_t * cg_rle_intersection(struct cg_rle_t * a, struct cg_rle_ if(len) { struct cg_span_t * span = result->spans.data + result->spans.size; + if (result->spans.size >= result->spans.capacity) + { + /* This is a workaround, I've had a case where the size + overflows by quite a bit. See note at the end of this + function. In any case this doesn't hurt, and it prevents + a crash in this situation. + Not familiar enough with the codebase to know if this + is a bug or not. */ + #if 0 + printf("cg_array_ensure detected overflow!!\na:%d b:%d r:%d/%d (len %d)\n", + a->spans.size, b->spans.size, + result->spans.size, + result->spans.capacity, len); + #endif + cg_array_ensure(result->spans, result->spans.size + 1); + span = result->spans.data + result->spans.size; + overflow = 1; + } span->x = x; span->len = len; span->y = a_spans->y; @@ -1079,7 +1098,15 @@ static struct cg_rle_t * cg_rle_intersection(struct cg_rle_t * a, struct cg_rle_ result->y = y1; result->w = x2 - x1; result->h = y2 - y1 + 1; - + if (overflow) { + /* I have a case which displays this + cg_rle_intersection detected overflow!! + a:960 b:524 r:1098/4096 + printf("cg_rle_intersection detected overflow!!\n\ta:%d b:%d r:%d/%d\n", + a->spans.size, b->spans.size, + result->spans.size, result->spans.capacity); + */ + } return result; } diff --git a/libmui/mui/mui.h b/libmui/mui/mui.h index 26340b9..5319b3d 100644 --- a/libmui/mui/mui.h +++ b/libmui/mui/mui.h @@ -458,7 +458,7 @@ mui_font_textbox( mui_color_t color, uint16_t flags ); -DECLARE_C_ARRAY(stb_ttc_g*, mui_glyph_array, 8, int x, y, w; ); +DECLARE_C_ARRAY(unsigned int, mui_glyph_array, 8, int x, y, w; ); DECLARE_C_ARRAY(mui_glyph_array_t, mui_glyph_line_array, 8); /* @@ -522,6 +522,15 @@ typedef struct mui_window_t { /* * Window related */ +/* + * This is the main function to create a window. The + * * 'wdef' is the window definition (or NULL for a default window). + * see mui_wdef_p for the callback definition. + * * 'layer' layer to put it in (default to zero for normal windows) + * * 'instance_size' zero (for default) or the size of the window instance + * object that is returned, you can therefore have your own custom field + * attached to a window. + */ mui_window_t * mui_window_create( struct mui_t * ui, diff --git a/libmui/mui/mui_cdef_buttons.c b/libmui/mui/mui_cdef_buttons.c index 183a840..07b448b 100644 --- a/libmui/mui/mui_cdef_buttons.c +++ b/libmui/mui/mui_cdef_buttons.c @@ -127,7 +127,9 @@ mui_check_rad_draw( } mui_font_textbox(main, dr, title, c->title, 0, - mui_control_color[0].text, + c->state == MUI_CONTROL_STATE_DISABLED ? + mui_control_color[c->state].text : + mui_control_color[0].text, MUI_TEXT_ALIGN_MIDDLE); mui_drawable_clip_pop(dr); } diff --git a/libmui/mui/mui_font.c b/libmui/mui/mui_font.c index 606881d..58f6107 100644 --- a/libmui/mui/mui_font.c +++ b/libmui/mui/mui_font.c @@ -64,7 +64,7 @@ mui_font_from_mem( f->size = size; stb_ttc_LoadFont(&f->ttc, font_data, font_size); TAILQ_INSERT_TAIL(&ui->fonts, f, self); - printf("%s: Loaded font %s:%d\n", __func__, name, size); +// printf("%s: Loaded font %s:%d\n", __func__, name, size); return f; } @@ -73,7 +73,7 @@ void mui_font_init( mui_t *ui) { - printf("%s: Loading fonts\n", __func__); +// printf("%s: Loading fonts\n", __func__); mui_font_from_mem(ui, "main", 28, mui_main_font_data, mui_main_font_size); mui_font_from_mem(ui, "icon_large", 96, @@ -241,7 +241,7 @@ mui_font_measure( break; } line->w += gc->advance; - mui_glyph_array_push(line, gc); + mui_glyph_array_push(line, gc->index); }; } while (text[ch] && ch < text_len); int bh = 0; @@ -308,7 +308,8 @@ mui_font_measure_draw( mui_glyph_array_t * line = &lines->e[li]; int xpos = 0;//where.x / scale; for (int ci = 0; ci < (int)line->count; ci++) { - stb_ttc_g *gc = line->e[ci]; + unsigned int cache_index = line->e[ci]; + stb_ttc_g *gc = &ttc->glyph[cache_index]; // int pxpos = gc->x0 + ((xpos + gc->lsb) * scale); int pxpos = gc->x0 + ((xpos + 0) * scale); diff --git a/libmui/mui/mui_stdfile.c b/libmui/mui/mui_stdfile.c index 1082904..3b004b7 100644 --- a/libmui/mui/mui_stdfile.c +++ b/libmui/mui/mui_stdfile.c @@ -240,7 +240,6 @@ _mui_stdfile_window_action( for (int i = 0; i < (int)std->pop_path.count; i++) free(std->pop_path.e[i]); std->pop_path.count = 0; - } break; } return 0; diff --git a/libmui/mui/mui_window.c b/libmui/mui/mui_window.c index bfcf94d..b0115e9 100644 --- a/libmui/mui/mui_window.c +++ b/libmui/mui/mui_window.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "mui_priv.h" #include "cg.h" @@ -127,7 +128,6 @@ mui_window_create( TAILQ_INIT(&w->zombies); STAILQ_INIT(&w->actions); pixman_region32_init(&w->inval); - TAILQ_INSERT_HEAD(&ui->windows, w, self); mui_window_select(w); // place it in it's own layer mui_font_t * main = mui_font_find(ui, "main"); @@ -351,8 +351,8 @@ mui_window_inval( pixman_region32_reset(&win->inval, (pixman_box32_t*)&frame); forward = frame; - mui_window_t * w; - TAILQ_FOREACH(w, &win->ui->windows, self) { + mui_window_t * w, *save; + TAILQ_FOREACH_SAFE(w, &win->ui->windows, self, save) { if (w == win || !c2_rect_intersect_rect(&w->frame, &forward)) continue; pixman_region32_union_rect(&w->inval, &w->inval, @@ -381,8 +381,8 @@ mui_window_front( { if (!ui) return NULL; - mui_window_t * w; - TAILQ_FOREACH_REVERSE(w, &ui->windows, windows, self) { + mui_window_t * w, *save; + TAILQ_FOREACH_REVERSE_SAFE(w, &ui->windows, windows, self, save) { if (w->flags.hidden) continue; if (w->flags.layer < MUI_WINDOW_MENUBAR_LAYER) diff --git a/libmui/mui/stb_ttc.h b/libmui/mui/stb_ttc.h index 6d828be..69f332d 100644 --- a/libmui/mui/stb_ttc.h +++ b/libmui/mui/stb_ttc.h @@ -41,6 +41,7 @@ typedef struct stb_ttc_measure { * scales in one cache. */ typedef struct stb_ttc_g { + unsigned int index; // index in global table unsigned int intscale; // for comparison purpose float scale; unsigned int glyph; @@ -296,6 +297,7 @@ stb_ttc__ScaledGlyphGetCache( .glyph = glyph, .index = ttc->g_count }; + gc.index = ttc->g_count; ttc->g_count++; unsigned int hash = glyph + (glyph * gc.intscale); diff --git a/libmui/tests/ui_tests.c b/libmui/tests/ui_tests.c index e801b87..0bc5db9 100644 --- a/libmui/tests/ui_tests.c +++ b/libmui/tests/ui_tests.c @@ -176,6 +176,7 @@ _init( // mii_mui_load_1mbrom(g->ui, &g_machine_conf.slot[0].conf.rom1mb); // mii_mui_load_2dsk(g->ui, // &g_machine_conf.slot[0].conf.disk2, MII_2DSK_DISKII); + mii_mui_about(g->ui); #if 0 mui_alert(ui, C2_PT(0,0), "Testing one Two", @@ -183,7 +184,7 @@ _init( "This operation cannot be cancelled.", MUI_ALERT_WARN); #endif -#if 1 +#if 0 mui_stdfile_get(ui, C2_PT(0, 0), "Select image for SmartPort card", @@ -233,4 +234,4 @@ mui_plug_t mui_plug = { .dispose = _dispose, .draw = _draw, .event = _event, -}; +}; \ No newline at end of file diff --git a/src/drivers/mii_disk2.c b/src/drivers/mii_disk2.c index a34e552..ffc9940 100644 --- a/src/drivers/mii_disk2.c +++ b/src/drivers/mii_disk2.c @@ -239,12 +239,31 @@ _mii_disk2_command( if (param) *(int *)param = 2; break; - case MII_SLOT_DRIVE_LOAD ... MII_SLOT_DRIVE_LOAD + 2 - 1: + case MII_SLOT_DRIVE_WP ... MII_SLOT_DRIVE_WP + 2 - 1: { + int drive = cmd - MII_SLOT_DRIVE_WP; + int *wp = param; + if (wp) { + printf("Drive %d WP: 0x%x set %s\n", drive, + c->floppy[drive].write_protected, + *wp ? "ON" : "OFF"); + c->floppy[drive].write_protected = + (c->floppy[drive].write_protected & + ~(MII_FLOPPY_WP_MANUAL))| + (*wp ? MII_FLOPPY_WP_MANUAL : 0); + } + } break; + case MII_SLOT_DRIVE_LOAD ... MII_SLOT_DRIVE_LOAD + 2 - 1: { int drive = cmd - MII_SLOT_DRIVE_LOAD; - const char *filename = param; + const char *pathname = param; mii_dd_file_t *file = NULL; - if (filename && *filename) { - file = mii_dd_file_load(&mii->dd, filename, O_RDWR); + if (pathname && *pathname) { + if (c->drive[drive].file && + !strcmp(c->drive[drive].file->pathname, pathname)) { + printf("%s D%d Same file, not reloading\n", + __func__, drive); + return 0; + } + file = mii_dd_file_load(&mii->dd, pathname, O_RDWR); if (!file) return -1; } @@ -252,7 +271,7 @@ _mii_disk2_command( mii_floppy_init(&c->floppy[drive]); mii_dd_drive_load(&c->drive[drive], file); mii_floppy_load(&c->floppy[drive], file); - break; + } break; } return 0; } diff --git a/src/format/mii_floppy.h b/src/format/mii_floppy.h index b060804..1220248 100644 --- a/src/format/mii_floppy.h +++ b/src/format/mii_floppy.h @@ -16,6 +16,10 @@ // track containing random bits #define MII_FLOPPY_RANDOM_TRACK_ID 35 +/* + * Reasons for write protect. Ie checkbox in the UI, or file format + * doesn't support writes, or the file has no write permissions. + */ enum { MII_FLOPPY_WP_MANUAL = (1 << 0), // write protect by the user MII_FLOPPY_WP_RO_FILE = (1 << 1), // file is read only diff --git a/src/mii_slot.h b/src/mii_slot.h index cda9ba5..58732b1 100644 --- a/src/mii_slot.h +++ b/src/mii_slot.h @@ -77,6 +77,7 @@ mii_slot_drv_find( enum { MII_SLOT_DRIVE_COUNT = 0x01, MII_SLOT_DRIVE_LOAD = 0x20, // + drive index 0...n + MII_SLOT_DRIVE_WP = 0x30, // + drive index 0...n MII_SLOT_SSC_SET_TTY = 0x10, // param is a pathname, or NULL for a pty }; diff --git a/ui_gl/mii_emu_gl.c b/ui_gl/mii_emu_gl.c index f9cd00f..cdb0b22 100644 --- a/ui_gl/mii_emu_gl.c +++ b/ui_gl/mii_emu_gl.c @@ -25,9 +25,10 @@ #include "mii_thread.h" #include "mii_mui.h" -#include "mii-icon-64.h" #include "minipt.h" #include "miigl_counter.h" +#define MII_ICON64_DEFINE +#include "mii-icon-64.h" /* * Note: This *assumes* that the GL implementation has support for non-power-of-2 @@ -348,7 +349,10 @@ mii_x11_init( } { Atom net_wm_icon_atom = XInternAtom(ui->dpy, "_NET_WM_ICON", False); - XChangeProperty(ui->dpy, ui->win, net_wm_icon_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)mii_icon64, sizeof(mii_icon64) / sizeof(mii_icon64[0])); + XChangeProperty(ui->dpy, ui->win, net_wm_icon_atom, XA_CARDINAL, + 32, PropModeReplace, + (unsigned char *)mii_icon64, + sizeof(mii_icon64) / sizeof(mii_icon64[0])); XFlush(ui->dpy); } XMapWindow(ui->dpy, ui->win); @@ -808,12 +812,15 @@ mii_ui_reconfigure_slot( (void*)config->slot[i].conf.smartport.drive[1].disk); } break; case MII_SLOT_DRIVER_DISK2: { - mii_slot_command(mii, slot, - MII_SLOT_DRIVE_LOAD, - (void*)config->slot[i].conf.disk2.drive[0].disk); - mii_slot_command(mii, slot, - MII_SLOT_DRIVE_LOAD + 1, - (void*)config->slot[i].conf.disk2.drive[1].disk); + for (int di = 0; di < 2; di++) { + mii_slot_command(mii, slot, + MII_SLOT_DRIVE_LOAD + di, + (void*)config->slot[i].conf.disk2.drive[di].disk); + int wp = config->slot[i].conf.disk2.drive[di].wp; + mii_slot_command(mii, slot, + MII_SLOT_DRIVE_WP + di, + (void*)&wp); + } } break; case MII_SLOT_DRIVER_ROM1MB: { mii_slot_command(mii, slot, diff --git a/ui_gl/mii_loadbin.c b/ui_gl/mii_loadbin.c new file mode 100644 index 0000000..a4ead0f --- /dev/null +++ b/ui_gl/mii_loadbin.c @@ -0,0 +1,56 @@ +/* + * mii_loadbin.c + * + * Copyright (C) 2023 Michel Pollet + * + * SPDX-License-Identifier: MIT + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "mii.h" +#include "mii_bank.h" +#include "mii_mui_settings.h" + + +typedef struct mii_loadbin_t { + mii_t * mii; + pthread_t thread; + + mii_loadbin_conf_t conf; +} mii_loadbin_t; + +static mii_loadbin_t * _mii_loadbin = NULL; + +static void * +mii_thread_loadbin( + void *arg) +{ + + return NULL; +} + +mii_loadbin_t * +mii_loadbin_start( + struct mii_t *mii, + struct mii_loadbin_conf_t *conf) +{ + mii_loadbin_t * res = NULL; + if (_mii_loadbin) { + return _mii_loadbin; + } + _mii_loadbin = res = calloc(1, sizeof(*res)); + res->mii = mii; + res->conf = *conf; + + pthread_create(&res->thread, NULL, mii_thread_loadbin, res); + + return res; +} diff --git a/ui_gl/mii_mui_1mb.c b/ui_gl/mii_mui_1mb.c index 4ba56a2..abf51b8 100644 --- a/ui_gl/mii_mui_1mb.c +++ b/ui_gl/mii_mui_1mb.c @@ -247,9 +247,7 @@ mii_mui_load_1mbrom( c2_rect_offset(&wpos, (ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2), (ui->screen_size.y * 0.4) - (c2_rect_height(&wpos) / 2)); - w = mui_window_create(mui, - wpos, - NULL, MUI_WINDOW_LAYER_MODAL, + w = mui_window_create(mui, wpos, NULL, MUI_WINDOW_LAYER_MODAL, "1MB ROM Card File", sizeof(mii_mui_1mb_t)); mui_window_set_id(w, MII_1MB_WINDOW_ID); diff --git a/ui_gl/mii_mui_2dsk.c b/ui_gl/mii_mui_2dsk.c index fecb414..20d8cca 100644 --- a/ui_gl/mii_mui_2dsk.c +++ b/ui_gl/mii_mui_2dsk.c @@ -5,7 +5,7 @@ * * SPDX-License-Identifier: MIT */ - +#define _GNU_SOURCE #include #include #include @@ -22,6 +22,8 @@ enum { MII_2DSK_CANCEL = FCC('c','a','n','c'), MII_2DSK_SELECT1 = FCC('s','e','l','1'), MII_2DSK_SELECT2 = FCC('s','e','l','2'), + MII_2DSK_WP1 = FCC('w','p','1',' '), + MII_2DSK_WP2 = FCC('w','p','2',' '), }; typedef struct mii_mui_2dsk_t { @@ -30,39 +32,177 @@ typedef struct mii_mui_2dsk_t { mui_control_t * load; uint32_t selecting; struct { - mui_control_t *icon, *fname, *button; + mui_control_t *icon, *fname, *button, *wp, *warning; } drive[2]; mii_2dsk_conf_t * dst; mii_2dsk_conf_t config; } mii_mui_2dsk_t; +#include +#include +#include + +typedef struct mii_floppy_check_t { + char * error; + char * warning; + int file_ro; + int file_ro_format; +} mii_floppy_check_t; + +#define NIB_SIZE 232960; +#define DSK_SIZE 143360; + +// TODO move that to some common place +void +_size_string( + size_t s, + char *out, + int out_size, + uint16_t flags); + +static int +_mii_floppy_check_file( + const char * path, + mii_floppy_check_t * out) +{ + char *filename = basename((char*)path); + + out->file_ro = 0; + out->file_ro_format = 0; + out->error = NULL; + out->warning = NULL; + + struct stat st; + if (stat(path, &st) < 0) { + asprintf(&out->error, "'%s': %s", filename, strerror(errno)); + return -1; + } + // has to have one + char * suffix = strrchr(path, '.'); + if (!suffix) { + asprintf(&out->error, "'%s' has no extension.", filename); + return -1; + } + int want_size = 0; + int iswoz = 0; + if (!strcasecmp(suffix, ".nib")) { + out->file_ro_format = 1; + } else if (!strcasecmp(suffix, ".dsk")) { + out->file_ro_format = 1; + } else if (!strcasecmp(suffix, ".woz") || + !strcasecmp(suffix, ".woz1") || + !strcasecmp(suffix, ".woz2")) { + out->file_ro = 0; + out->file_ro_format = 0; + iswoz = 1; + } else { + asprintf(&out->error, "'%s' has an unknown extension.", filename); + return -1; + } + if (out->error) + return -1; + if (want_size && st.st_size != want_size) { + char stt[64]; + long delta = want_size - st.st_size; + _size_string(delta < 0 ? -delta : delta, stt, sizeof(stt)-2, 1); + strcpy(stt + strlen(stt), "B"); + asprintf(&out->error, + "File '%s' is the wrong size, %s too %s.", + filename, + stt, delta < 0 ? "big" : "small"); + return -1; + } + if (out->error) + return -1; + int fd = open(path, O_RDWR, 0); + if (fd < 0) { + fd = open(path, O_RDONLY, 0); + if (fd < 0) { + asprintf(&out->error, "'%s': %s", filename, strerror(errno)); + return -1; + } else + out->file_ro = 1; + } + if (iswoz) { + // check the woz header + uint8_t header[4]; + if (read(fd, header, sizeof(header)) != sizeof(header)) { + asprintf(&out->error, + "'%s': could not check WOZ header. Invalid file?", + filename); + close(fd); + return -1; + } + if (memcmp(header, "WOZ1", 4) != 0 && memcmp(header, "WOZ2", 4) != 0) { + asprintf(&out->error, + "'%s' is not detected as a valid WOZ file.", + filename); + close(fd); + return -1; + } + } + close(fd); + if (out->file_ro_format && !out->warning) { + asprintf(&out->warning, "%s format is Read Only.", suffix); + } + if (out->file_ro && !out->warning) { + asprintf(&out->warning, "File lacks write permissions."); + } + return 0; +} + + static void mii_mui_2dsk_load_conf( mii_mui_2dsk_t * m, mii_2dsk_conf_t * config) { - int ok = 0; + int ok = 1; for (int i = 0; i < 2; i++) { if (config->drive[i].disk[0]) { ok = 1; + mii_floppy_check_t check = {}; + if (_mii_floppy_check_file(config->drive[i].disk, &check) < 0) { + mui_alert(m->win.ui, C2_PT(0,0), + "Invalid Disk Image", + check.error, MUI_ALERT_FLAG_OK); + free(check.error); + ok = 0; + } + config->drive[i].ro_file = check.file_ro; + config->drive[i].ro_format = check.file_ro_format; mui_control_set_state(m->drive[i].fname, MUI_CONTROL_STATE_NORMAL); char *dup = strdup(config->drive[i].disk); mui_control_set_title(m->drive[i].fname, basename(dup)); free(dup); mui_control_set_state(m->drive[i].icon, MUI_CONTROL_STATE_NORMAL); mui_control_set_title(m->drive[i].button, "Eject"); + if (check.warning) { + mui_control_set_title(m->drive[i].warning, check.warning); + mui_control_set_state(m->drive[i].wp, MUI_CONTROL_STATE_DISABLED); + free(check.warning); + } else { + mui_control_set_title(m->drive[i].warning, ""); + mui_control_set_state(m->drive[i].wp, MUI_CONTROL_STATE_NORMAL); + } } else { + config->drive[i].ro_file = config->drive[i].ro_format = 0; mui_control_set_state(m->drive[i].fname, MUI_CONTROL_STATE_DISABLED); mui_control_set_title(m->drive[i].fname, "Click \"Select\" to pick a file"); mui_control_set_state(m->drive[i].icon, MUI_CONTROL_STATE_DISABLED); mui_control_set_title(m->drive[i].button, "Select…"); + mui_control_set_state(m->drive[i].wp, MUI_CONTROL_STATE_NORMAL); + mui_control_set_title(m->drive[i].warning, ""); } + mui_control_set_value(m->drive[i].wp, + (config->drive[i].wp || config->drive[i].ro_file || + config->drive[i].ro_format) ? 1 : 0); } if (ok) mui_control_set_state(m->load, MUI_CONTROL_STATE_NORMAL); -// else -// mui_control_set_state(m->load, MUI_CONTROL_STATE_DISABLED); + else + mui_control_set_state(m->load, MUI_CONTROL_STATE_DISABLED); } static int @@ -80,8 +220,9 @@ _mii_2dsk_stdfile_cb( printf("%s select %s\n", __func__, path); strncpy(m->config.drive[idx].disk, path, sizeof(m->config.drive[idx].disk)-1); - mii_mui_2dsk_load_conf(m, &m->config); + free(path); mui_window_dispose(w); + mii_mui_2dsk_load_conf(m, &m->config); } break; case MUI_STDF_ACTION_CANCEL: printf("%s cancel\n", __func__); @@ -148,6 +289,11 @@ _mii_2dsk_action_cb( mui_window_set_action(w, _mii_2dsk_stdfile_cb, m); } } break; + case MII_2DSK_WP1: + case MII_2DSK_WP2: { + int idx = uid == MII_2DSK_WP1 ? 0 : 1; + m->config.drive[idx].wp = mui_control_get_value(c); + } break; } break; } @@ -169,18 +315,19 @@ mii_mui_load_2dsk( return w; } c2_pt_t where = {}; - c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 640, 275); - if (where.x == 0 && where.y == 0) - c2_rect_offset(&wpos, - (ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2), - (ui->screen_size.y * 0.4) - (c2_rect_height(&wpos) / 2)); - char label[128]; - sprintf(label, "Select Files for %s 1&2 (Slot %d)", + c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 640, 355); + c2_rect_offset(&wpos, + (ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2), + (ui->screen_size.y * 0.45) - (c2_rect_height(&wpos) / 2)); + + char *label; + asprintf(&label, "Select Files for %s 1&2 (Slot %d)", drive_kind == MII_2DSK_SMARTPORT ? "SmartPort" : "Disk II", config->slot_id + 1); - w = mui_window_create(mui, - wpos, NULL, 0, label, + w = mui_window_create(mui, wpos, NULL, MUI_WINDOW_LAYER_MODAL, + label, sizeof(mii_mui_2dsk_t)); + free(label); mui_window_set_id(w, MII_2DSK_WINDOW_ID); mii_mui_2dsk_t * m = (mii_mui_2dsk_t*)w; m->drive_kind = drive_kind; @@ -235,9 +382,21 @@ mii_mui_load_2dsk( MII_2DSK_SELECT1 : MII_2DSK_SELECT2); c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, '1' + i); - c2_rect_bottom_of(&cp, cp.b, margin * 0.2); + c2_rect_bottom_of(&cf, cp.b, margin * 0.4); + cf.l = cp.l + (margin * 0.7); + cf.r = cf.l + 200; + m->drive[i].wp = c = mui_button_new(w, + cf, MUI_BUTTON_STYLE_CHECKBOX, + "Write Protect", + i == 0 ? MII_2DSK_WP1 : MII_2DSK_WP2); + c2_rect_right_of(&cf, cf.r, margin * 0.5); + cf.r = c2_rect_width(&w->frame) - margin * 1.2; + m->drive[i].warning = c = mui_textbox_new(w, cf, + "", NULL, + MUI_TEXT_ALIGN_MIDDLE|MUI_TEXT_ALIGN_RIGHT); + c2_rect_bottom_of(&cp, cp.b + (base_size * 2), margin * 0.2); } - c2_rect_bottom_of(&cp, cp.t, margin * 0.8); + c2_rect_top_of(&cp, cp.t, margin * 3.5); cp.l = margin * 4; cp.r = c2_rect_width(&w->frame) - margin * 4; c = mui_separator_new(w, cp); @@ -251,6 +410,7 @@ mii_mui_load_2dsk( m->dst = config; m->config = *config; mii_mui_2dsk_load_conf(m, config); + return w; } diff --git a/ui_gl/mii_mui_about.c b/ui_gl/mii_mui_about.c new file mode 100644 index 0000000..ba047c4 --- /dev/null +++ b/ui_gl/mii_mui_about.c @@ -0,0 +1,90 @@ +/* + * mui_mui_about.c + * + * Copyright (C) 2023 Michel Pollet + * + * SPDX-License-Identifier: MIT + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "mui.h" +#include "mii-icon-64.h" + + + +enum { + MII_ABOUT_WINDOW_ID = FCC('a','b','o','t'), + MII_ABOUT_OK = FCC('O','K','!',' '), +}; + +typedef struct mii_mui_about_t { + mui_window_t win; +} mii_mui_about_t; + + +static int +_mii_about_action_cb( + mui_control_t * c, + void * cb_param, // mii_mui_about_t + uint32_t what, + void * param) // not used +{ + printf("%s %4.4s\n", __func__, (char*)&what); + mii_mui_about_t * m = cb_param; + uint32_t uid = mui_control_get_uid(c); + + switch (what) { + case MUI_CONTROL_ACTION_SELECT: + printf("%s control %4.4s\n", __func__, (char*)&uid); + switch (uid) { + case MII_ABOUT_OK: { + // save the config + mui_window_dispose(&m->win); + } break; + } + break; + } + return 0; +} + +struct mui_window_t * +mii_mui_about( + struct mui_t *mui ) +{ + mui_t *ui = mui; + float base_size = mui_font_find(ui, "main")->size; + float margin = base_size * 0.7; + mui_window_t *w = mui_window_get_by_id(mui, MII_ABOUT_WINDOW_ID); + if (w) { + mui_window_select(w); + return w; + } + c2_pt_t where = {}; + c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 560, 240); + if (where.x == 0 && where.y == 0) + c2_rect_offset(&wpos, + (ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2), + (ui->screen_size.y * 0.4) - (c2_rect_height(&wpos) / 2)); + w = mui_window_create(mui, wpos, NULL, MUI_WINDOW_LAYER_MODAL, + "About the MII " MUI_GLYPH_IIE " Emulator", + sizeof(mii_mui_about_t)); + mui_window_set_id(w, MII_ABOUT_WINDOW_ID); + mii_mui_about_t * m = (mii_mui_about_t*)w; + + mui_control_t * c = NULL; + c2_rect_t cf; + cf = C2_RECT_WH(0, 0, base_size * 4, base_size * 1.4); + c2_rect_left_of(&cf, c2_rect_width(&w->content), margin); + c2_rect_top_of(&cf, c2_rect_height(&w->content), margin); + c = mui_button_new(w, + cf, MUI_BUTTON_STYLE_DEFAULT, + "OK", MII_ABOUT_OK); + c->key_equ = MUI_KEY_EQU(0, 13); + + return w; +} + diff --git a/ui_gl/mii_mui_settings.c b/ui_gl/mii_mui_settings.c index b74ed8b..a0aed3c 100644 --- a/ui_gl/mii_mui_settings.c +++ b/ui_gl/mii_mui_settings.c @@ -252,10 +252,14 @@ mii_emu_save( config->slot[i].conf.disk2.drive[0].disk); sprintf(label, "%lu", config->slot[i].conf.disk2.drive[0].flags); mii_config_set(cf, section, "flags0", label); + mii_config_set(cf, section, "wp0", + config->slot[i].conf.disk2.drive[0].wp ? "1" : "0"); mii_config_set(cf, section, "image1", config->slot[i].conf.disk2.drive[1].disk); sprintf(label, "%lu", config->slot[i].conf.disk2.drive[1].flags); mii_config_set(cf, section, "flags1", label); + mii_config_set(cf, section, "wp1", + config->slot[i].conf.disk2.drive[1].wp ? "1" : "0"); break; case MII_SLOT_DRIVER_SUPERSERIAL: mii_config_set(cf, section, "device", @@ -384,4 +388,4 @@ mii_emu_load( } } return 0; -} +} \ No newline at end of file diff --git a/ui_gl/mii_mui_settings.h b/ui_gl/mii_mui_settings.h index 62ecc5f..83883a7 100644 --- a/ui_gl/mii_mui_settings.h +++ b/ui_gl/mii_mui_settings.h @@ -141,6 +141,9 @@ struct mui_window_t * mii_mui_load_1mbrom( struct mui_t *mui, mii_1mb_conf_t *config); +struct mui_window_t * +mii_mui_about( + struct mui_t *mui ); enum mii_mui_2dsk_e { MII_2DSK_DISKII = 0, diff --git a/utils/icon-convert-tcc.c b/utils/icon-convert-tcc.c index d03cbcd..ba5d3fa 100644 --- a/utils/icon-convert-tcc.c +++ b/utils/icon-convert-tcc.c @@ -57,7 +57,11 @@ int main() { } fprintf(f, "/* this file is auto-generated by icon-convert-tcc.c */\n"); // fprintf(f, "#include \n"); - fprintf(f, "static const unsigned long mii_icon%d[] = {\n", w); + fprintf(f, "#define MII_ICON%d_SIZE %d\n", w, (w * h + 2)); + fprintf(f, "extern const unsigned long mii_icon%d[MII_ICON%d_SIZE];\n", w, w); + fprintf(f, "#ifdef MII_ICON%d_DEFINE\n", w); + fprintf(f, "const unsigned long mii_icon%d[MII_ICON%d_SIZE] = {\n", + w, w); fprintf(f, "\t%d,%d,\n", w, h); for (int y = 0; y < h; y++) { fprintf(f, "\t"); @@ -74,6 +78,7 @@ int main() { fprintf(f, "\n"); } fprintf(f, "};\n"); + fprintf(f, "#endif\n"); fclose(f); free(pixels); }