mirror of
https://github.com/raphnet/gc_n64_usb-v3
synced 2025-01-30 14:50:10 -05:00
Gui work
This commit is contained in:
parent
11d55b085b
commit
b10322a9d2
@ -188,7 +188,7 @@ Author: Raphaël Assénat
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Open mempak editor</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="gtk_widget_show" object="n64_mempak_editor_window" swapped="yes"/>
|
||||
<signal name="activate" handler="gtk_widget_show" object="win_mempak_edit" swapped="yes"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@ -394,6 +394,29 @@ Author: Raphaël Assénat
|
||||
<property name="top_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label11">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Controller type:</property>
|
||||
<property name="justify">right</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_controller_type">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@ -817,8 +840,9 @@ Author: Raphaël Assénat
|
||||
<action-widget response="1">update_cancel_button</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
<object class="GtkWindow" id="n64_mempak_editor_window">
|
||||
<object class="GtkWindow" id="win_mempak_edit">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">N64 Mempak editor</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="attached_to">mainWindow</property>
|
||||
<signal name="delete-event" handler="gtk_widget_hide" swapped="no"/>
|
||||
@ -828,6 +852,7 @@ Author: Raphaël Assénat
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkMenuBar" id="menubar2">
|
||||
@ -896,7 +921,7 @@ Author: Raphaël Assénat
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="gtk_widget_hide" object="n64_mempak_editor_window" swapped="yes"/>
|
||||
<signal name="activate" handler="gtk_widget_hide" object="win_mempak_edit" swapped="yes"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@ -956,6 +981,7 @@ Author: Raphaël Assénat
|
||||
<object class="GtkTreeView" id="n64_notes_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="model">n64_notes</property>
|
||||
<property name="enable_search">False</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
@ -979,6 +1005,7 @@ Author: Raphaël Assénat
|
||||
<object class="GtkTreeViewColumn" id="treeviewcolumn2">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title" translatable="yes">Game Data</property>
|
||||
<property name="expand">True</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cellrenderertext4"/>
|
||||
<attributes>
|
||||
@ -1007,6 +1034,25 @@ Author: Raphaël Assénat
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStatusbar" id="mempak_status_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_start">10</property>
|
||||
<property name="margin_end">10</property>
|
||||
<property name="margin_top">6</property>
|
||||
<property name="margin_bottom">6</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -348,10 +348,12 @@ static void updateGuiFromAdapter(struct application *app)
|
||||
{ CFG_PARAM_INVERT_TRIG, GET_ELEMENT(GtkToggleButton, chkbtn_gc_invert_trig) },
|
||||
{ },
|
||||
};
|
||||
int controller_type;
|
||||
GET_UI_ELEMENT(GtkLabel, label_product_name);
|
||||
GET_UI_ELEMENT(GtkLabel, label_firmware_version);
|
||||
GET_UI_ELEMENT(GtkLabel, label_usb_id);
|
||||
GET_UI_ELEMENT(GtkLabel, label_device_path);
|
||||
GET_UI_ELEMENT(GtkLabel, label_controller_type);
|
||||
int i;
|
||||
struct gcn64_info *info = &app->current_adapter_info;
|
||||
|
||||
@ -389,6 +391,11 @@ static void updateGuiFromAdapter(struct application *app)
|
||||
gtk_label_set_text(label_usb_id, (char*)buf);
|
||||
|
||||
gtk_label_set_text(label_device_path, info->str_path);
|
||||
|
||||
controller_type = gcn64lib_getControllerType(app->current_adapter_handle, 0);
|
||||
gtk_label_set_text(label_controller_type, gcn64lib_controllerName(controller_type));
|
||||
|
||||
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void pollIntervalChanged(GtkWidget *win, gpointer data)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <libgen.h>
|
||||
#include "gcn64ctl_gui.h"
|
||||
#include "mempak.h"
|
||||
|
||||
@ -7,6 +8,8 @@ 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)
|
||||
@ -35,21 +38,89 @@ void mpkedit_free(struct mpkedit_data *mpke)
|
||||
}
|
||||
}
|
||||
|
||||
void mpke_replaceMpk(struct application *app, mempak_structure_t *mpk)
|
||||
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) {
|
||||
@ -76,34 +147,148 @@ void mpke_syncModel(struct application *app)
|
||||
|
||||
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) {
|
||||
errorPopop(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)) {
|
||||
errorPopop(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: errorPopop(app, "Error loading file or inserting note\n"); break;
|
||||
case -2: errorPopop(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;
|
||||
|
||||
mpke_replaceMpk(app, mempak_new());
|
||||
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, n64_mempak_window_editor);
|
||||
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",
|
||||
n64_mempak_window_editor,
|
||||
win_mempak_edit,
|
||||
action,
|
||||
"_Cancel",
|
||||
GTK_RESPONSE_CANCEL,
|
||||
@ -121,7 +306,8 @@ G_MODULE_EXPORT void mpke_open(GtkWidget *win, gpointer data)
|
||||
filename = gtk_file_chooser_get_filename(chooser);
|
||||
mpk = mempak_loadFromFile(filename);
|
||||
if (mpk) {
|
||||
mpke_replaceMpk(app, mpk);
|
||||
app->mpke->modified = 0;
|
||||
mpke_replaceMpk(app, mpk, filename);
|
||||
} else {
|
||||
errorPopop(app, "Failed to load mempak");
|
||||
}
|
||||
@ -132,14 +318,93 @@ G_MODULE_EXPORT void mpke_open(GtkWidget *win, gpointer data)
|
||||
|
||||
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 {
|
||||
errorPopop(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 onMempakWindowShow(GtkWidget *win, gpointer data)
|
||||
|
@ -55,6 +55,7 @@ static int mempak_findFreeNote(mempak_structure_t *mpk, entry_structure_t *entry
|
||||
* \param notefile The filename of the note to load
|
||||
* \param dst_note_id 0-15: (Over)write to specific note, -1: auto (first free)
|
||||
* \param note_id Stores the id of the note that was used
|
||||
* \return -1: Error, -2: Not enough space in mempak
|
||||
*/
|
||||
int mempak_importNote(mempak_structure_t *mpk, const char *notefile, int dst_note_id, int *note_id)
|
||||
{
|
||||
@ -128,7 +129,7 @@ int mempak_importNote(mempak_structure_t *mpk, const char *notefile, int dst_not
|
||||
fprintf(stderr, "Not enough space (note is %d blocks and only %d free blocks in mempak)\n",
|
||||
entry.blocks, free_blocks);
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
data = calloc(1, entry.blocks * MEMPAK_BLOCK_SIZE);
|
||||
|
Loading…
Reference in New Issue
Block a user