/* * TilEm II * * Copyright (c) 2010-2011 Thibault Duponchelle * Copyright (c) 2010 Benjamin Moody * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include "gui.h" /* Create a frame around the given widget, with a boldface label in the GNOME style */ GtkWidget* new_frame(const gchar* label, GtkWidget* contents) { GtkWidget *frame, *align; char *str; str = g_strconcat("", label, "", NULL); frame = gtk_frame_new(str); g_free(str); g_object_set(gtk_frame_get_label_widget(GTK_FRAME(frame)), "use-markup", TRUE, NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE); align = gtk_alignment_new(0.5, 0.5, 1.0, 1.0); gtk_alignment_set_padding(GTK_ALIGNMENT(align), 6, 0, 12, 0); gtk_widget_show(align); gtk_container_add(GTK_CONTAINER(frame), align); gtk_container_add(GTK_CONTAINER(align), contents); gtk_widget_show(frame); return frame; } /* Get model name (abbreviation) for a TilEm model ID. */ const char * model_to_name(int model) { const TilemHardware **models; int nmodels, i; tilem_get_supported_hardware(&models, &nmodels); for (i = 0; i < nmodels; i++) if (models[i]->model_id == model) return models[i]->name; return NULL; } /* Convert model name to a model ID. */ int name_to_model(const char *name) { char *s; const TilemHardware **models; int nmodels, i, j; s = g_new(char, strlen(name) + 1); for (i = j = 0; name[i]; i++) { if (name[i] == '+') s[j++] = 'p'; else if (name[i] != '-') s[j++] = g_ascii_tolower(name[i]); } s[j] = 0; tilem_get_supported_hardware(&models, &nmodels); for (i = 0; i < nmodels; i++) { if (!strcmp(s, models[i]->name)) { g_free(s); return models[i]->model_id; } } g_free(s); return 0; } /* Convert TilEm model ID to tifiles2 model ID. */ CalcModel model_to_calcmodel(int model) { switch (model) { case TILEM_CALC_TI73: return CALC_TI73; case TILEM_CALC_TI82: return CALC_TI82; case TILEM_CALC_TI83: case TILEM_CALC_TI76: return CALC_TI83; case TILEM_CALC_TI83P: case TILEM_CALC_TI83P_SE: return CALC_TI83P; case TILEM_CALC_TI84P: case TILEM_CALC_TI84P_SE: case TILEM_CALC_TI84P_NSPIRE: return CALC_TI84P; case TILEM_CALC_TI85: return CALC_TI85; case TILEM_CALC_TI86: return CALC_TI86; default: return CALC_NONE; } } /* Convert tifiles2 model ID to TilEm model ID. */ int calcmodel_to_model(CalcModel model) { switch (model) { case CALC_TI73: return TILEM_CALC_TI73; case CALC_TI82: return TILEM_CALC_TI82; case CALC_TI83: return TILEM_CALC_TI83; case CALC_TI83P: return TILEM_CALC_TI83P; case CALC_TI84P: return TILEM_CALC_TI84P; case CALC_TI85: return TILEM_CALC_TI85; case CALC_TI86: return TILEM_CALC_TI86; default: return 0; } } /* Get model ID for a given file. */ int file_to_model(const char *name) { const char *p; TigContent *tig; int model; p = strrchr(name, '.'); if (!p || strlen(p) < 4 || strchr(p, '/') || strchr(p, '\\')) return 0; p++; if (!g_ascii_strcasecmp(p, "prg")) return TILEM_CALC_TI81; if (!g_ascii_strncasecmp(p, "73", 2)) return TILEM_CALC_TI73; if (!g_ascii_strncasecmp(p, "82", 2)) return TILEM_CALC_TI82; if (!g_ascii_strncasecmp(p, "83", 2)) return TILEM_CALC_TI83; if (!g_ascii_strncasecmp(p, "8x", 2)) return TILEM_CALC_TI83P; if (!g_ascii_strncasecmp(p, "85", 2)) return TILEM_CALC_TI85; if (!g_ascii_strncasecmp(p, "86", 2)) return TILEM_CALC_TI86; if (!g_ascii_strcasecmp(p, "tig") || !g_ascii_strcasecmp(p, "zip")) { /* read file and see what tifiles thinks the type is */ tig = tifiles_content_create_tigroup(CALC_NONE, 0); tifiles_file_read_tigroup(name, tig); model = calcmodel_to_model(tig->model); tifiles_content_delete_tigroup(tig); return model; } return 0; } /* Get "base" model for file type support. */ int model_to_base_model(int calc_model) { switch (calc_model) { case TILEM_CALC_TI83: case TILEM_CALC_TI76: return TILEM_CALC_TI83; case TILEM_CALC_TI83P: case TILEM_CALC_TI83P_SE: case TILEM_CALC_TI84P: case TILEM_CALC_TI84P_SE: case TILEM_CALC_TI84P_NSPIRE: return TILEM_CALC_TI83P; default: return calc_model; } } /* Check if calc is compatible with given file type. */ gboolean model_supports_file(int calc_model, int file_model) { calc_model = model_to_base_model(calc_model); file_model = model_to_base_model(file_model); if (file_model == calc_model) return TRUE; if (file_model == TILEM_CALC_TI82 && (calc_model == TILEM_CALC_TI83 || calc_model == TILEM_CALC_TI83P)) return TRUE; if (file_model == TILEM_CALC_TI83 && (calc_model == TILEM_CALC_TI83P)) return TRUE; if (file_model == TILEM_CALC_TI85 && (calc_model == TILEM_CALC_TI86)) return TRUE; return FALSE; } /* A popup which is used to let the user choose the model at startup */ char choose_rom_popup(GtkWidget *parent_window, const char *filename, char default_model) { const TilemHardware **models; GtkWidget *dlg, *vbox, *frame, *btn; GtkToggleButton **btns; char *ids, id = 0; int nmodels, noptions, i, j, defoption = 0, response; dword romsize; char *fn, *msg; tilem_get_supported_hardware(&models, &nmodels); /* determine ROM size for default model */ for (i = 0; i < nmodels; i++) if (models[i]->model_id == default_model) break; g_return_val_if_fail(i < nmodels, 0); romsize = models[i]->romsize; /* all other models with same ROM size are candidates */ noptions = 0; for (i = 0; i < nmodels; i++) { if (models[i]->model_id == default_model) defoption = noptions; if (models[i]->romsize == romsize) noptions++; } if (noptions < 2) /* no choice */ return default_model; dlg = gtk_dialog_new_with_buttons("Select Calculator Type", GTK_WINDOW(parent_window), GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_dialog_set_default_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK); vbox = gtk_vbox_new(TRUE, 0); /* create radio buttons */ btns = g_new(GtkToggleButton*, noptions); ids = g_new(char, noptions); btn = NULL; for (i = j = 0; i < nmodels; i++) { if (models[i]->romsize == romsize) { btn = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(btn), models[i]->desc); btns[j] = GTK_TOGGLE_BUTTON(btn); ids[j] = models[i]->model_id; gtk_box_pack_start(GTK_BOX(vbox), btn, TRUE, TRUE, 3); j++; } } gtk_toggle_button_set_active(btns[defoption], TRUE); fn = g_filename_display_basename(filename); msg = g_strdup_printf("Calculator type for %s:", fn); frame = new_frame(msg, vbox); g_free(fn); g_free(msg); gtk_container_set_border_width(GTK_CONTAINER(frame), 6); gtk_widget_show_all(frame); vbox = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); response = gtk_dialog_run(GTK_DIALOG(dlg)); if (response == GTK_RESPONSE_OK) { for (i = 0; i < noptions; i++) { if (gtk_toggle_button_get_active(btns[i])) { id = ids[i]; break; } } } else { id = 0; } gtk_widget_destroy(dlg); g_free(btns); g_free(ids); return id; } /* Convert UTF-8 to filename encoding. Use ASCII digits in place of subscripts if necessary. If conversion fails utterly, fall back to the UTF-8 name, which is broken but better than nothing. */ char * utf8_to_filename(const char *utf8str) { gchar *result, *ibuf, *obuf, *p; gsize icount, ocount; const gchar **charsets; GIConv ic; gunichar c; if (g_get_filename_charsets(&charsets)) return g_strdup(utf8str); ic = g_iconv_open(charsets[0], "UTF-8"); if (!ic) { g_warning("utf8_to_filename: unsupported charset %s", charsets[0]); return g_strdup(utf8str); } ibuf = (gchar*) utf8str; icount = strlen(utf8str); ocount = icount * 2; /* be generous */ result = obuf = g_new(gchar, ocount + 1); while (g_iconv(ic, &ibuf, &icount, &obuf, &ocount) == (gsize) -1) { if (errno != EILSEQ) { g_warning("utf8_to_filename: error in conversion"); g_free(result); g_iconv_close(ic); return g_strdup(utf8str); } c = g_utf8_get_char(ibuf); if (c >= 0x2080 && c <= 0x2089) *obuf = c - 0x2080 + '0'; else *obuf = '_'; obuf++; ocount--; p = g_utf8_next_char(ibuf); icount -= p - ibuf; ibuf = p; } *obuf = 0; g_iconv_close(ic); return result; } /* Convert UTF-8 to a subset of UTF-8 that is compatible with the locale */ char * utf8_to_restricted_utf8(const char *utf8str) { char *p, *q; p = utf8_to_filename(utf8str); q = g_filename_to_utf8(p, -1, NULL, NULL, NULL); g_free(p); if (q) return q; else return g_strdup(utf8str); } /* Generate default filename (UTF-8) for a variable */ char * get_default_filename(const TilemVarEntry *tve) { GString *str = g_string_new(""); if (tve->slot_str) { g_string_append(str, tve->slot_str); if (tve->name_str && tve->name_str[0]) { g_string_append_c(str, '-'); g_string_append(str, tve->name_str); } } else if (tve->name_str && tve->name_str[0]) { g_string_append(str, tve->name_str); } else { g_string_append(str, "untitled"); } g_string_append_c(str, '.'); g_string_append(str, tve->file_ext); return g_string_free(str, FALSE); }