/* gc_n64_usb : Gamecube or N64 controller to USB adapter firmware Copyright (C) 2007-2015 Raphael Assenat 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 . */ #include #include #include #include "gcn64ctl_gui.h" #include "mempak.h" void mpke_syncModel(struct application *app); struct mpkedit_data { struct mempak_structure *mpk; char *filename; int modified; }; struct mpkedit_data *mpkedit_new(struct application *app) { struct mpkedit_data *mpke; mpke = calloc(sizeof(struct mpkedit_data), 1); if (!mpke) { perror("calloc"); return NULL; } mpke->mpk = mempak_new(); if (!mpke->mpk) { free(mpke); return NULL; } return mpke; } void mpkedit_free(struct mpkedit_data *mpke) { if (mpke) { free(mpke); } } int mpke_getSelection(struct application *app) { GET_UI_ELEMENT(GtkTreeView, n64_notes_treeview); GtkTreeSelection *sel = gtk_tree_view_get_selection(n64_notes_treeview); GList *selected; int sel_id = -1; if (!sel) { return -1; } selected = gtk_tree_selection_get_selected_rows(sel, NULL); if (selected && selected->data) { GtkTreePath *path; gint *indices; path = (GtkTreePath*)selected->data; indices = gtk_tree_path_get_indices(path); sel_id = indices[0]; } else { return -1; } if (selected) g_list_free_full(selected, (GDestroyNotify)gtk_tree_path_free); printf("Current selection: %d\n", sel_id); return sel_id; } void mpke_syncTitle(struct application *app) { GET_UI_ELEMENT(GtkWindow, win_mempak_edit); char titlebuf[64]; if (app->mpke->filename) { char *bn = g_path_get_basename(app->mpke->filename); snprintf(titlebuf, sizeof(titlebuf), "N64 Mempak editor - %s%s", bn, app->mpke->modified ? " [MODIFIED]":"" ); g_free(bn); printf("New title: %s\n", titlebuf); gtk_window_set_title(win_mempak_edit, titlebuf); } else { snprintf(titlebuf, sizeof(titlebuf), "N64 Mempak editor%s", app->mpke->modified ? " [NOT SAVED]" : ""); } } void mpke_updateFilename(struct application *app, char *filename) { if (app->mpke->filename) { // The filename always comes from gtk_file_chooser_get_filename g_free(app->mpke->filename); } app->mpke->filename = filename; mpke_syncTitle(app); } void mpke_replaceMpk(struct application *app, mempak_structure_t *mpk, char *filename) { if (app->mpke->mpk) { mempak_free(app->mpke->mpk); } app->mpke->mpk = mpk; mpke_syncModel(app); mpke_updateFilename(app, filename); } void mpke_syncModel(struct application *app) { GET_UI_ELEMENT(GtkListStore, n64_notes); GET_UI_ELEMENT(GtkTreeView, n64_notes_treeview); GET_UI_ELEMENT(GtkStatusbar, mempak_status_bar); int i, res; char statusbuf[64]; gtk_list_store_clear(n64_notes); if (!app->mpke->mpk) { return; } for (i=0; i<16; i++) { GtkTreeIter iter; entry_structure_t note_data; gtk_list_store_append(n64_notes, &iter); res = get_mempak_entry(app->mpke->mpk, i, ¬e_data); if (res) { gtk_list_store_set(n64_notes, &iter, 0, i, 1, "!!ERROR!!", 2, 0, -1); } else { if (note_data.valid) { gtk_list_store_set(n64_notes, &iter, 0, i, 1, note_data.name, 2, note_data.blocks, 3, app->mpke->mpk->note_comments[i], -1); } else { gtk_list_store_set(n64_notes, &iter, 0, i, -1); } } } gtk_tree_view_set_model(n64_notes_treeview, GTK_TREE_MODEL(n64_notes)); snprintf(statusbuf, sizeof(statusbuf), "Blocks used: %d / %d", 123-get_mempak_free_space(app->mpke->mpk), 123); gtk_statusbar_push(mempak_status_bar, gtk_statusbar_get_context_id(mempak_status_bar, "free blocks"), statusbuf); } G_MODULE_EXPORT void mpke_export_note(GtkWidget *win, gpointer data) { struct application *app = data; int selection; GtkWidget *dialog; GtkFileChooser *chooser; GET_UI_ELEMENT(GtkWindow, win_mempak_edit); GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE; GET_UI_ELEMENT(GtkFileFilter, n64_note_filter); int res; selection = mpke_getSelection(app); if (selection <0) { printf("No selection"); return; } if (app->mpke->mpk) { entry_structure_t entry; if (0==get_mempak_entry(app->mpke->mpk, selection, &entry)) { char namebuf[64]; if (!entry.valid) { errorPopup(app, "Please select a non-empty note"); return; } dialog = gtk_file_chooser_dialog_new("Save File", win_mempak_edit, action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL); chooser = GTK_FILE_CHOOSER(dialog); snprintf(namebuf, sizeof(namebuf), "%s.note", entry.name); gtk_file_chooser_set_current_name(chooser, namebuf); gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), n64_note_filter); res = gtk_dialog_run (GTK_DIALOG(dialog)); if (res == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename(chooser); if (mempak_exportNote(app->mpke->mpk, selection, filename)) { errorPopup(app, "Could not export note"); } else { printf("Note saved to %s\n", filename); } } gtk_widget_destroy(dialog); } } } G_MODULE_EXPORT void mpke_insert_note(GtkWidget *win, gpointer data) { struct application *app = data; GtkWidget *dialog; GET_UI_ELEMENT(GtkWindow, win_mempak_edit); GET_UI_ELEMENT(GtkFileFilter, n64_note_filter); GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; int res; dialog = gtk_file_chooser_dialog_new("Load N64 mempak image", win_mempak_edit, action, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), n64_note_filter); res = gtk_dialog_run (GTK_DIALOG(dialog)); if (res == GTK_RESPONSE_ACCEPT) { char *filename; GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog); entry_structure_t entry; int used_note_id; int dst_id; filename = gtk_file_chooser_get_filename(chooser); dst_id = mpke_getSelection(app); if (0 == get_mempak_entry(app->mpke->mpk, dst_id, &entry)) { if (entry.valid) { // Ask confirmation printf("Ask confirmation\n"); } } res = mempak_importNote(app->mpke->mpk, filename, dst_id, &used_note_id); if (res) { switch(res) { default: case -1: errorPopup(app, "Error loading file or inserting note\n"); break; case -2: errorPopup(app, "Not enough free blocks to insert note\n"); break; } } else { // Success app->mpke->modified =1; mpke_syncModel(app); mpke_syncTitle(app); } } gtk_widget_destroy(dialog); } G_MODULE_EXPORT void mpke_new(GtkWidget *win, gpointer data) { struct application *app = data; app->mpke->modified = 0; mpke_replaceMpk(app, mempak_new(), NULL); } G_MODULE_EXPORT void mpke_open(GtkWidget *win, gpointer data) { struct application *app = data; GtkWidget *dialog; GET_UI_ELEMENT(GtkWindow, win_mempak_edit); GET_UI_ELEMENT(GtkFileFilter, n64_mempak_filter); GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; int res; dialog = gtk_file_chooser_dialog_new("Load N64 mempak image", win_mempak_edit, action, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), n64_mempak_filter); res = gtk_dialog_run (GTK_DIALOG(dialog)); if (res == GTK_RESPONSE_ACCEPT) { char *filename; GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog); mempak_structure_t *mpk; filename = gtk_file_chooser_get_filename(chooser); mpk = mempak_loadFromFile(filename); if (mpk) { app->mpke->modified = 0; mpke_replaceMpk(app, mpk, filename); } else { errorPopup(app, "Failed to load mempak"); } } gtk_widget_destroy(dialog); } G_MODULE_EXPORT void mpke_saveas(GtkWidget *win, gpointer data) { struct application *app = data; GtkWidget *dialog; GtkFileChooser *chooser; GET_UI_ELEMENT(GtkWindow, win_mempak_edit); GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE; GET_UI_ELEMENT(GtkFileFilter, n64_mempak_filter); int res; dialog = gtk_file_chooser_dialog_new("Save File", win_mempak_edit, action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL); chooser = GTK_FILE_CHOOSER(dialog); gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), n64_mempak_filter); if (app->mpke->filename) { gchar *bs = g_path_get_basename(app->mpke->filename); gchar *dn = g_path_get_dirname(app->mpke->filename); gtk_file_chooser_set_current_name(chooser, bs); gtk_file_chooser_set_current_folder(chooser, dn); g_free(bs); g_free(dn); } else { gtk_file_chooser_set_current_name(chooser, "mempak.n64"); } res = gtk_dialog_run (GTK_DIALOG(dialog)); if (res == GTK_RESPONSE_ACCEPT) { char *filename; int fmt; filename = gtk_file_chooser_get_filename(chooser); fmt = mempak_getFilenameFormat(filename); if (fmt!= MPK_FORMAT_INVALID) { mempak_saveToFile(app->mpke->mpk, filename, fmt); printf("Saved to %s\n", filename); app->mpke->modified = 0; mpke_updateFilename(app,filename); } else { errorPopup(app, "Unknown file format specified"); } } gtk_widget_destroy(dialog); } G_MODULE_EXPORT void mpke_save(GtkWidget *win, gpointer data) { struct application *app = data; if (!app->mpke->mpk) return; if (!app->mpke->filename) { mpke_saveas(win, data); } else { mempak_saveToFile(app->mpke->mpk, app->mpke->filename, app->mpke->mpk->file_format); app->mpke->modified = 0; mpke_syncTitle(app); } } G_MODULE_EXPORT void mpke_delete(GtkWidget *win, gpointer data) { struct application *app = data; int selection; selection = mpke_getSelection(app); if (selection <0) { printf("No selection"); return; } if (app->mpke->mpk) { entry_structure_t entry; if (0==get_mempak_entry(app->mpke->mpk, selection, &entry)) { delete_mempak_entry(app->mpke->mpk, &entry); mpke_syncModel(app); app->mpke->modified = 1; mpke_syncTitle(app); } } } G_MODULE_EXPORT void n64_note_activated(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) { struct application *app = data; printf("Yo!\n"); } G_MODULE_EXPORT void onMempakWindowShow(GtkWidget *win, gpointer data) { struct application *app = data; mpke_syncModel(app); } mempak_structure_t *mpke_getCurrentMempak(struct application *app) { return app->mpke->mpk; }