mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2025-04-02 10:52:35 -04:00
786 lines
28 KiB
C
786 lines
28 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Mupen64plus - main_gtk.c *
|
|
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
|
* Copyright (C) 2008 ebenblues *
|
|
* *
|
|
* 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 2 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, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "main_gtk.h"
|
|
#include "cheatdialog.h"
|
|
#include "../cheat.h"
|
|
#include "../translate.h"
|
|
#include "../util.h"
|
|
|
|
/** globals **/
|
|
static GtkWidget *g_CheatView = NULL;
|
|
|
|
// column numbering for cheat code list store
|
|
enum
|
|
{
|
|
ADDRESS_COLUMN,
|
|
VALUE_COLUMN,
|
|
CHEAT_CODE_COLUMN,
|
|
NUM_COLUMNS
|
|
};
|
|
|
|
/** private functions **/
|
|
// user clicked ok button
|
|
static void cb_response(GtkWidget *widget, gint response, gpointer data)
|
|
{
|
|
cheat_write_config();
|
|
gtk_widget_destroy(widget);
|
|
}
|
|
|
|
// user clicked button to add a new cheat code
|
|
static void cb_addCode(GtkWidget *button, GtkTreeView *treeview)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreeSelection *selection;
|
|
|
|
cheat_t *cheat;
|
|
cheat_code_t *cheatcode;
|
|
|
|
// first, get cheat that these codes belong to
|
|
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_CheatView));
|
|
gtk_tree_selection_get_selected(selection, &model, &iter);
|
|
|
|
gtk_tree_model_get(model, &iter, 1, &cheat, -1);
|
|
|
|
// create new cheat code
|
|
cheatcode = cheat_new_cheat_code(cheat);
|
|
|
|
// add new cheat code row to list
|
|
model = gtk_tree_view_get_model(treeview);
|
|
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
|
|
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
|
|
ADDRESS_COLUMN, cheatcode->address,
|
|
VALUE_COLUMN, cheatcode->value,
|
|
CHEAT_CODE_COLUMN, cheatcode,
|
|
-1);
|
|
|
|
// select new row
|
|
selection = gtk_tree_view_get_selection(treeview);
|
|
gtk_tree_selection_select_iter(selection, &iter);
|
|
}
|
|
|
|
// user clicked button to remove a cheat code
|
|
static void cb_removeCode(GtkWidget *button, GtkTreeView *treeview)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreeSelection *selection;
|
|
|
|
cheat_t *cheat;
|
|
cheat_code_t *cheatcode;
|
|
|
|
// first, get cheat that these codes belong to
|
|
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_CheatView));
|
|
gtk_tree_selection_get_selected(selection, &model, &iter);
|
|
|
|
gtk_tree_model_get(model, &iter, 1, &cheat, -1);
|
|
|
|
// get cheat code pointer, then delete row from tree model
|
|
selection = gtk_tree_view_get_selection(treeview);
|
|
if(gtk_tree_selection_get_selected(selection, &model, &iter))
|
|
{
|
|
gtk_tree_model_get(model, &iter, CHEAT_CODE_COLUMN, &cheatcode, -1);
|
|
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
|
|
|
|
// delete cheat code structure
|
|
cheat_delete_cheat_code(cheat, cheatcode);
|
|
}
|
|
|
|
//If there are codes left, select the first one.
|
|
if(gtk_tree_model_get_iter_first(model, &iter))
|
|
gtk_tree_selection_select_iter(selection, &iter);
|
|
}
|
|
|
|
// user edited cheat code (address or value)
|
|
static void cb_editCode(GtkCellRenderer *cell, gchar *path_string, gchar *new_text, GtkTreeView *view)
|
|
{
|
|
GtkTreeModel *model = gtk_tree_view_get_model(view);
|
|
GtkTreeIter iter;
|
|
guint col_num;
|
|
|
|
cheat_code_t *cheatcode;
|
|
|
|
// get column and row information
|
|
gtk_tree_model_get_iter_from_string(model, &iter, path_string);
|
|
col_num = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(cell), "col_num"));
|
|
|
|
// get pointer to cheatcode struct
|
|
gtk_tree_model_get(model, &iter, CHEAT_CODE_COLUMN, &cheatcode, -1);
|
|
|
|
// user edited address cell
|
|
if(col_num == ADDRESS_COLUMN)
|
|
{
|
|
cheatcode->address = strtoumax(new_text, NULL, 16);
|
|
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
|
|
ADDRESS_COLUMN, cheatcode->address,
|
|
-1);
|
|
}
|
|
// user edited value cell
|
|
else
|
|
{
|
|
cheatcode->value = strtoumax(new_text, NULL, 16);
|
|
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
|
|
VALUE_COLUMN, cheatcode->value,
|
|
-1);
|
|
}
|
|
}
|
|
|
|
|
|
// returns tree view of all user cheats
|
|
static GtkWidget *create_cheat_treeview(void)
|
|
{
|
|
GtkWidget *view;
|
|
GtkCellRenderer *rend;
|
|
GtkTreeViewColumn *col;
|
|
GtkTreeStore *model;
|
|
GtkTreeIter romIter,
|
|
cheatIter;
|
|
|
|
list_node_t *romnode,
|
|
*cheatnode;
|
|
rom_cheats_t *romcheat;
|
|
cheat_t *cheat;
|
|
|
|
// model stores either a rom name or cheat name, and a pointer to either the rom_cheat_t or cheat_t struct
|
|
model = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
|
|
|
|
// populate model
|
|
list_foreach(g_Cheats, romnode)
|
|
{
|
|
romcheat = (rom_cheats_t *)romnode->data;
|
|
|
|
// add rom name to tree
|
|
gtk_tree_store_append(model, &romIter, NULL);
|
|
gtk_tree_store_set(model, &romIter,
|
|
0, romcheat->rom_name,
|
|
1, romcheat,
|
|
-1);
|
|
|
|
// add all cheats for this rom as children in the tree
|
|
list_foreach(romcheat->cheats, cheatnode)
|
|
{
|
|
cheat = (cheat_t *)cheatnode->data;
|
|
|
|
gtk_tree_store_append(model, &cheatIter, &romIter);
|
|
gtk_tree_store_set(model, &cheatIter, 0, cheat->name, 1, cheat, -1);
|
|
}
|
|
}
|
|
|
|
// create tree view
|
|
view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
|
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
|
|
|
|
// allows model memory to be freed when tree view is destroyed.
|
|
g_object_unref(model);
|
|
|
|
// only add the string column to the view, the struct pointer is hidden data
|
|
rend = gtk_cell_renderer_text_new();
|
|
col = gtk_tree_view_column_new();
|
|
gtk_tree_view_column_pack_start(col, rend, TRUE);
|
|
// gtk_tree_view_column_set_resizable (col, FALSE);
|
|
gtk_tree_view_column_add_attribute(col, rend, "text", 0);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
|
|
|
return view;
|
|
}
|
|
|
|
// Adds new rom to cheat structures and tree view, and selects it so user can edit it
|
|
static void cb_newRom(GtkButton *button, GtkTreeView *view)
|
|
{
|
|
GtkTreeModel *model = gtk_tree_view_get_model(view);
|
|
GtkTreeIter iter;
|
|
GtkTreeSelection *selection;
|
|
|
|
rom_cheats_t *romcheat = cheat_new_rom();
|
|
romcheat->rom_name = strdup(tr("New Rom"));
|
|
|
|
// add new rom to tree model
|
|
gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
|
|
gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
|
|
0, romcheat->rom_name,
|
|
1, romcheat,
|
|
-1);
|
|
|
|
// select new rom
|
|
selection = gtk_tree_view_get_selection(view);
|
|
gtk_tree_selection_select_iter(selection, &iter);
|
|
}
|
|
|
|
// Adds new cheat to cheat structures and tree view, and selects it so user can edit it
|
|
static void cb_newCheat(GtkButton *button, GtkTreeView *view)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter, selectedIter, parentIter, *romIter;
|
|
GtkTreeSelection *selection;
|
|
GtkTreePath *path;
|
|
|
|
rom_cheats_t *romcheat;
|
|
cheat_t *cheat;
|
|
|
|
selection = gtk_tree_view_get_selection(view);
|
|
|
|
// something should always be selected, but just in case...
|
|
if(gtk_tree_selection_get_selected(selection, &model, &selectedIter))
|
|
{
|
|
|
|
// get pointer to rom iter
|
|
if(gtk_tree_model_iter_parent(model, &parentIter, &selectedIter))
|
|
romIter = &parentIter;
|
|
else
|
|
romIter = &selectedIter;
|
|
|
|
// grab pointer to rom cheat data out of model
|
|
gtk_tree_model_get(model, romIter, 1, &romcheat, -1);
|
|
|
|
// create new cheat
|
|
cheat = cheat_new_cheat(romcheat);
|
|
cheat->name = strdup(tr("New Cheat"));
|
|
|
|
// add new cheat to the tree model
|
|
gtk_tree_store_append(GTK_TREE_STORE(model), &iter, romIter);
|
|
gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
|
|
0, cheat->name,
|
|
1, cheat,
|
|
-1);
|
|
|
|
// expand rom row if it isn't already
|
|
path = gtk_tree_model_get_path(model, romIter);
|
|
gtk_tree_view_expand_row(view, path, FALSE);
|
|
gtk_tree_path_free(path);
|
|
|
|
// select new cheat
|
|
gtk_tree_selection_select_iter(selection, &iter);
|
|
}
|
|
}
|
|
|
|
// Remove currently selected rom/cheat from the tree
|
|
static void cb_delete(GtkButton *button, GtkTreeView *view)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter, parentIter;
|
|
GtkTreeSelection *selection;
|
|
|
|
rom_cheats_t *romcheat = NULL;
|
|
cheat_t *cheat = NULL;
|
|
|
|
selection = gtk_tree_view_get_selection(view);
|
|
|
|
if(gtk_tree_selection_get_selected(selection, &model, &iter))
|
|
{
|
|
// check if we're deleting a rom or cheat
|
|
if(gtk_tree_model_iter_parent(model, &parentIter, &iter))
|
|
{
|
|
// selected item is a cheat
|
|
gtk_tree_model_get(model, &parentIter, 1, &romcheat, -1);
|
|
gtk_tree_model_get(model, &iter, 1, &cheat, -1);
|
|
|
|
if(gui_message(GUI_MESSAGE_CONFIRM,
|
|
tr("Are you sure you want to delete cheat \"%s\"?"),
|
|
cheat->name))
|
|
{
|
|
gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
|
|
cheat_delete_cheat(romcheat, cheat);
|
|
|
|
// set selection to parent rom
|
|
gtk_tree_selection_select_iter(selection, &parentIter);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// selected item is a rom
|
|
gtk_tree_model_get(model, &iter, 1, &romcheat, -1);
|
|
|
|
if(gui_message(GUI_MESSAGE_CONFIRM,
|
|
tr("Are you sure you want to delete rom \"%s\" and all of its cheats?"),
|
|
romcheat->rom_name))
|
|
{
|
|
gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
|
|
cheat_delete_rom(romcheat);
|
|
|
|
//If there any roms are left, set selection to first rom.
|
|
if(gtk_tree_model_get_iter_first(model, &iter))
|
|
gtk_tree_selection_select_iter(selection, &iter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Updates tree model and rom_cheats_t structure with new rom name
|
|
static void cb_romNameChanged(GtkWidget *textbox, GtkTreeSelection *selection)
|
|
{
|
|
gchar *text = gtk_editable_get_chars(GTK_EDITABLE(textbox), 0, -1);
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model;
|
|
|
|
rom_cheats_t *romcheat;
|
|
|
|
// if we're here, something should be selected, but just in case...
|
|
if(gtk_tree_selection_get_selected(selection, &model, &iter))
|
|
{
|
|
gtk_tree_model_get(model, &iter, 1, &romcheat, -1);
|
|
|
|
// change rom name in rom_cheats_t struct
|
|
if(romcheat->rom_name)
|
|
free(romcheat->rom_name);
|
|
romcheat->rom_name = strdup(text);
|
|
|
|
// change rom name in tree model
|
|
gtk_tree_store_set(GTK_TREE_STORE(model), &iter, 0, romcheat->rom_name, -1);
|
|
}
|
|
|
|
g_free(text);
|
|
}
|
|
|
|
// Updates rom_cheats_t structure with new rom crc
|
|
static void cb_crcChanged(GtkWidget *textbox, unsigned int *rom_crc)
|
|
{
|
|
gchar *text = gtk_editable_get_chars(GTK_EDITABLE(textbox), 0, -1);
|
|
*rom_crc = strtoumax(text, NULL, 16);
|
|
g_free(text);
|
|
}
|
|
|
|
// Returns user form to edit rom info.
|
|
static GtkWidget *edit_rom_info_widget(rom_cheats_t *romcheat, GtkTreeSelection *selection)
|
|
{
|
|
int i;
|
|
char crc[9];
|
|
|
|
GtkWidget *label;
|
|
GtkWidget *table;
|
|
GtkWidget *textbox;
|
|
GtkWidget *mainvbox;
|
|
|
|
mainvbox = gtk_vbox_new( 0, FALSE );
|
|
gtk_container_set_border_width( GTK_CONTAINER(mainvbox), 10);
|
|
|
|
table = gtk_table_new( 2, 3, FALSE );
|
|
gtk_table_set_col_spacings( GTK_TABLE(table), 5 );
|
|
gtk_table_set_row_spacings( GTK_TABLE(table), 5 );
|
|
gtk_box_pack_start( GTK_BOX(mainvbox), table, FALSE, FALSE, 0 );
|
|
|
|
// Rom name
|
|
label = gtk_label_new(tr("Name:"));
|
|
gtk_misc_set_alignment( GTK_MISC(label), 1, 0 );
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
|
|
|
|
textbox = gtk_entry_new();
|
|
gtk_widget_set_size_request(textbox, 170, -1);
|
|
if(romcheat->rom_name)
|
|
gtk_editable_insert_text(GTK_EDITABLE(textbox), romcheat->rom_name, strlen(romcheat->rom_name), &i);
|
|
|
|
// connect signal such that as the user changes the Rom name in the textbox, it's updated in the model
|
|
g_signal_connect(textbox, "changed", G_CALLBACK(cb_romNameChanged), selection);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), textbox, 1, 3, 0, 1);
|
|
|
|
// Rom CRC
|
|
label = gtk_label_new(tr("CRC:"));
|
|
gtk_misc_set_alignment( GTK_MISC(label), 1, 0 );
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
|
|
|
|
// CRC1 textbox
|
|
textbox = gtk_entry_new();
|
|
gtk_entry_set_max_length(GTK_ENTRY(textbox), 8);
|
|
gtk_widget_set_size_request(textbox, 85, -1);
|
|
snprintf(crc, 9, "%.8x", romcheat->crc1);
|
|
gtk_entry_set_text(GTK_ENTRY(textbox), crc);
|
|
|
|
// connect signal such that as the user changes the CRC value in the textbox, it's updated in the rom_cheats_t struct
|
|
g_signal_connect(textbox, "changed", G_CALLBACK(cb_crcChanged), &romcheat->crc1);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), textbox, 1, 2, 1, 2);
|
|
|
|
// CRC2 textbox
|
|
textbox = gtk_entry_new();
|
|
gtk_entry_set_max_length(GTK_ENTRY(textbox), 8);
|
|
gtk_widget_set_size_request(textbox, 85, -1);
|
|
snprintf(crc, 9, "%.8x", romcheat->crc2);
|
|
gtk_entry_set_text(GTK_ENTRY(textbox), crc);
|
|
|
|
// connect signal such that as the user changes the CRC value in the textbox, it's updated in the rom_cheats_t struct
|
|
g_signal_connect(textbox, "changed", G_CALLBACK(cb_crcChanged), &romcheat->crc2);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), textbox, 2, 3, 1, 2);
|
|
|
|
return mainvbox;
|
|
}
|
|
|
|
// Updates tree model and cheat_t structure with new cheat name
|
|
static void cb_cheatNameChanged(GtkWidget *textbox, GtkTreeSelection *selection)
|
|
{
|
|
gchar *text = gtk_editable_get_chars(GTK_EDITABLE(textbox), 0, -1);
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model;
|
|
|
|
cheat_t *cheat;
|
|
|
|
// if we're here, something should be selected, but just in case...
|
|
if(gtk_tree_selection_get_selected(selection, &model, &iter))
|
|
{
|
|
gtk_tree_model_get(model, &iter, 1, &cheat, -1);
|
|
|
|
// change cheat name in cheat_t struct
|
|
if(cheat->name)
|
|
free(cheat->name);
|
|
cheat->name = strdup(text);
|
|
|
|
// change rom name in tree model
|
|
gtk_tree_store_set(GTK_TREE_STORE(model), &iter, 0, cheat->name, -1);
|
|
}
|
|
|
|
g_free(text);
|
|
}
|
|
|
|
// user disabled cheat
|
|
static void cb_cheatDisabled(GtkWidget *button, cheat_t *cheat)
|
|
{
|
|
cheat->always_enabled = cheat->enabled = 0;
|
|
}
|
|
|
|
// user enabled cheat for this session only
|
|
static void cb_cheatEnabled(GtkWidget *button, cheat_t *cheat)
|
|
{
|
|
cheat->enabled = 1;
|
|
cheat->always_enabled = 0;
|
|
}
|
|
|
|
// user enabled cheat always
|
|
static void cb_cheatEnabledAlways(GtkWidget *button, cheat_t *cheat)
|
|
{
|
|
cheat->enabled = 0;
|
|
cheat->always_enabled = 1;
|
|
}
|
|
|
|
// function to display cheat codes in hex format
|
|
static void cb_cheat_data_func(GtkTreeViewColumn *col,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
gpointer column)
|
|
{
|
|
unsigned int val;
|
|
char buf[20];
|
|
|
|
// get cell value from model
|
|
gtk_tree_model_get(tree_model, iter, column, &val, -1);
|
|
if(column == ADDRESS_COLUMN)
|
|
snprintf(buf, 20, "%.8x", val);
|
|
else
|
|
snprintf(buf, 20, "%.4x", val);
|
|
|
|
// set cell text to value
|
|
g_object_set(G_OBJECT(cell), "text", buf, NULL);
|
|
}
|
|
|
|
void gtk_tree_view_column_set_width(GtkTreeViewColumn *treeviewcolumn, gint width)
|
|
{
|
|
treeviewcolumn->resized_width = width;
|
|
treeviewcolumn->use_resized_width = TRUE;
|
|
g_object_set(G_OBJECT(treeviewcolumn), "expand", FALSE, NULL);
|
|
}
|
|
|
|
// Returns tree view of all cheat codes for the given cheat
|
|
static GtkWidget *create_cheat_code_treeview(cheat_t *cheat)
|
|
{
|
|
GtkWidget *view;
|
|
GtkCellRenderer *rend;
|
|
GtkTreeViewColumn *col;
|
|
GtkListStore *model;
|
|
GtkTreeIter iter;
|
|
|
|
list_node_t *node;
|
|
cheat_code_t *cheatcode;
|
|
|
|
model = gtk_list_store_new(NUM_COLUMNS,
|
|
G_TYPE_UINT, // address column
|
|
G_TYPE_UINT, // value column
|
|
G_TYPE_POINTER); // hidden pointer to cheat_code_t struct
|
|
|
|
// populate model with cheat codes
|
|
list_foreach(cheat->cheat_codes, node)
|
|
{
|
|
cheatcode = (cheat_code_t *)node->data;
|
|
|
|
// add cheat code to list model
|
|
gtk_list_store_append(model, &iter);
|
|
gtk_list_store_set(model, &iter,
|
|
ADDRESS_COLUMN, cheatcode->address,
|
|
VALUE_COLUMN, cheatcode->value,
|
|
CHEAT_CODE_COLUMN, cheatcode,
|
|
-1);
|
|
}
|
|
|
|
// create tree view
|
|
view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
|
|
|
// allows list memory to be freed when tree view is destroyed
|
|
g_object_unref(model);
|
|
|
|
// address column
|
|
rend = gtk_cell_renderer_text_new();
|
|
// attach column identifier to this renderer
|
|
g_object_set_data(G_OBJECT(rend), "col_num", GUINT_TO_POINTER(ADDRESS_COLUMN));
|
|
// allow user to edit cells
|
|
g_object_set(rend, "editable", TRUE, NULL);
|
|
g_signal_connect(rend, "edited", G_CALLBACK(cb_editCode), GTK_TREE_VIEW(view));
|
|
col = gtk_tree_view_column_new_with_attributes(tr("Address"), rend,
|
|
"text", ADDRESS_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_column_set_cell_data_func(col, rend, cb_cheat_data_func,
|
|
(gpointer)ADDRESS_COLUMN, NULL);
|
|
gtk_tree_view_column_set_width (col, 70);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
|
|
|
// value column
|
|
rend = gtk_cell_renderer_text_new();
|
|
// attach column identifier to this renderer
|
|
g_object_set_data(G_OBJECT(rend), "col_num", GUINT_TO_POINTER(VALUE_COLUMN));
|
|
// allow user to edit cells
|
|
g_object_set(rend, "editable", TRUE, NULL);
|
|
g_signal_connect(rend, "edited", G_CALLBACK(cb_editCode), GTK_TREE_VIEW(view));
|
|
col = gtk_tree_view_column_new_with_attributes(tr("Value"), rend,
|
|
"text", VALUE_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_column_set_cell_data_func(col, rend, cb_cheat_data_func,
|
|
(gpointer)VALUE_COLUMN, NULL);
|
|
gtk_tree_view_column_set_width (col, 40);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
|
|
|
|
return view;
|
|
}
|
|
|
|
// Returns user form to edit a cheat (name, codes)
|
|
static GtkWidget *edit_cheat_widget(cheat_t *cheat, GtkTreeSelection *selection)
|
|
{
|
|
int i;
|
|
|
|
GtkWidget *table;
|
|
GtkWidget *hbox, *buttonvbox, *mainvbox;
|
|
GtkWidget *label;
|
|
GtkWidget *textbox;
|
|
GtkWidget *button;
|
|
GtkWidget *code_treeview;
|
|
GtkWidget *viewport;
|
|
|
|
mainvbox = gtk_vbox_new( 0, FALSE );
|
|
gtk_box_set_spacing(GTK_BOX(mainvbox), 5);
|
|
gtk_container_set_border_width( GTK_CONTAINER(mainvbox), 10);
|
|
|
|
table = gtk_table_new(4, 2, FALSE);
|
|
gtk_table_set_col_spacings( GTK_TABLE(table), 5 );
|
|
gtk_box_pack_start( GTK_BOX(mainvbox), table, FALSE, FALSE, 0 );
|
|
|
|
// Cheat name
|
|
label = gtk_label_new(tr("Name:"));
|
|
gtk_misc_set_alignment( GTK_MISC(label), 1, 0 );
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
|
|
|
|
textbox = gtk_entry_new();
|
|
gtk_widget_set_size_request(textbox, 170, -1);
|
|
if(cheat->name)
|
|
gtk_editable_insert_text(GTK_EDITABLE(textbox), cheat->name, strlen(cheat->name), &i);
|
|
|
|
// connect signal such that as the user changes the cheat name in the textbox, it's updated in the model
|
|
g_signal_connect(textbox, "changed", G_CALLBACK(cb_cheatNameChanged), selection);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), textbox, 1, 2, 0, 1);
|
|
|
|
// Cheat enable
|
|
button = gtk_radio_button_new_with_label(NULL, tr("Disabled"));
|
|
g_signal_connect(button, "toggled", G_CALLBACK(cb_cheatDisabled), cheat);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, 1, 2);
|
|
|
|
button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(button), tr("Enabled (Session)"));
|
|
g_signal_connect(button, "toggled", G_CALLBACK(cb_cheatEnabled), cheat);
|
|
if(cheat->enabled)
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, 2, 3);
|
|
|
|
button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(button), tr("Enabled (Always)"));
|
|
g_signal_connect(button, "toggled", G_CALLBACK(cb_cheatEnabledAlways), cheat);
|
|
if(cheat->always_enabled)
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), button, 1, 2, 3, 4);
|
|
|
|
// create tree view of cheat codes (address/value pairs)
|
|
hbox = gtk_hbox_new(FALSE, 0);
|
|
gtk_box_set_spacing(GTK_BOX(hbox), 10);
|
|
|
|
viewport = gtk_scrolled_window_new(NULL, NULL);
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(viewport),
|
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
|
gtk_box_pack_start(GTK_BOX(hbox), viewport, TRUE, TRUE, 0);
|
|
|
|
code_treeview = create_cheat_code_treeview(cheat);
|
|
gtk_container_add(GTK_CONTAINER(viewport), code_treeview);
|
|
|
|
// create column of add/remove buttons next to cheat codes
|
|
buttonvbox = gtk_vbox_new(FALSE, 0);
|
|
gtk_box_pack_start(GTK_BOX(hbox), buttonvbox, FALSE, FALSE, 0);
|
|
|
|
// add cheat code button
|
|
button = gtk_button_new_from_stock(GTK_STOCK_ADD);
|
|
g_signal_connect(button, "clicked", G_CALLBACK(cb_addCode), code_treeview);
|
|
gtk_box_pack_start(GTK_BOX(buttonvbox), button, FALSE, FALSE, 5);
|
|
|
|
// remove cheat code button
|
|
button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
|
|
g_signal_connect(button, "clicked", G_CALLBACK(cb_removeCode), code_treeview);
|
|
gtk_box_pack_start(GTK_BOX(buttonvbox), button, FALSE, FALSE, 5);
|
|
|
|
gtk_box_pack_start(GTK_BOX(mainvbox), hbox, TRUE, TRUE, 0);
|
|
|
|
return mainvbox;
|
|
}
|
|
|
|
// Update contents of the detail frame with the details of the selected rom or cheat
|
|
static void cb_updateFrame(GtkTreeSelection *selection, GtkWidget *frame)
|
|
{
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkWidget *frame_contents;
|
|
GtkWidget *label;
|
|
|
|
rom_cheats_t *romcheat;
|
|
cheat_t *cheat;
|
|
|
|
// empty current frame contents
|
|
frame_contents = gtk_bin_get_child(GTK_BIN(frame));
|
|
if(frame_contents)
|
|
gtk_widget_destroy(frame_contents);
|
|
|
|
//If there are no cheats, put a label in the frame saying so.
|
|
if(!gtk_tree_selection_get_selected(selection, &model, &iter))
|
|
{
|
|
if(!gtk_tree_model_get_iter_first(model, &iter))
|
|
{
|
|
gtk_frame_set_label(GTK_FRAME(frame), NULL);
|
|
label = gtk_label_new(tr("No cheats found. Click\n \"New Rom\" to begin."));
|
|
frame_contents = label;
|
|
gtk_container_add(GTK_CONTAINER(frame), frame_contents);
|
|
if(GTK_WIDGET_VISIBLE(frame))
|
|
gtk_widget_show_all(frame_contents);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
gtk_tree_selection_select_iter(selection, &iter);
|
|
return; //Don't continue after recursive calling.
|
|
}
|
|
}
|
|
|
|
// depth of 0 means the selected item is a rom
|
|
if(gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 0)
|
|
{
|
|
gtk_frame_set_label(GTK_FRAME(frame), "Edit Rom");
|
|
// grab pointer to rom cheat data out of model
|
|
gtk_tree_model_get(model, &iter, 1, &romcheat, -1);
|
|
frame_contents = edit_rom_info_widget(romcheat, selection);
|
|
}
|
|
// depth of 1 means the selected item is a cheat
|
|
else if(gtk_tree_store_iter_depth(GTK_TREE_STORE(model), &iter) == 1)
|
|
{
|
|
gtk_frame_set_label(GTK_FRAME(frame), "Edit Cheat");
|
|
// grab pointer to cheat data out of model
|
|
gtk_tree_model_get(model, &iter, 1, &cheat, -1);
|
|
frame_contents = edit_cheat_widget(cheat, selection);
|
|
}
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), frame_contents);
|
|
|
|
// if we're being called to update the frame, display the updated frame contents
|
|
if(GTK_WIDGET_VISIBLE(frame))
|
|
gtk_widget_show_all(frame_contents);
|
|
}
|
|
|
|
/** public functions **/
|
|
|
|
// Create and display cheat dialog
|
|
void cb_cheatDialog(GtkWidget *widget)
|
|
{
|
|
// Local Variables
|
|
GtkWidget *dialog;
|
|
GtkWidget *frame;
|
|
GtkWidget *hbox, *vbox;
|
|
GtkWidget *viewport;
|
|
GtkWidget *button;
|
|
|
|
GtkTreeSelection *selection;
|
|
|
|
// Create Dialog Window
|
|
dialog = gtk_dialog_new_with_buttons(tr("Configure Cheats"),
|
|
GTK_WINDOW(g_MainWindow.window),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
gtk_window_set_resizable(GTK_WINDOW(dialog), TRUE);
|
|
gtk_widget_set_size_request(dialog, 510, -1);
|
|
gtk_container_set_border_width( GTK_CONTAINER(dialog), 10 );
|
|
|
|
g_CheatView = create_cheat_treeview();
|
|
|
|
g_signal_connect(dialog, "response", G_CALLBACK(cb_response), g_CheatView);
|
|
|
|
// create scrolled window for tree view
|
|
viewport = gtk_scrolled_window_new(NULL, NULL);
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(viewport),
|
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
|
gtk_widget_set_size_request(viewport, 200, 400);
|
|
gtk_container_add(GTK_CONTAINER(viewport), g_CheatView);
|
|
|
|
// add cheat tree view within viewport to left side of dialog box
|
|
hbox = gtk_hbox_new(FALSE, 10);
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 0);
|
|
gtk_box_pack_start(GTK_BOX(hbox), viewport, FALSE, FALSE, 0);
|
|
|
|
// right side of dialog
|
|
vbox = gtk_vbox_new(FALSE, 10);
|
|
gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 10);
|
|
|
|
// row of add rom, add cheat, remove buttons
|
|
hbox = gtk_hbox_new(FALSE, 10);
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 10);
|
|
|
|
button = gtk_button_new_with_mnemonic(tr("_New Rom"));
|
|
g_signal_connect(button, "clicked", G_CALLBACK(cb_newRom), g_CheatView);
|
|
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
|
|
|
|
button = gtk_button_new_with_mnemonic(tr("New _Cheat"));
|
|
g_signal_connect(button, "clicked", G_CALLBACK(cb_newCheat), g_CheatView);
|
|
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
|
|
|
|
button = gtk_button_new_with_mnemonic(tr("_Delete"));
|
|
g_signal_connect(button, "clicked", G_CALLBACK(cb_delete), g_CheatView);
|
|
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
|
|
|
|
// frame containing detail of selected item in tree view (allows user to edit)
|
|
frame = gtk_frame_new(NULL);
|
|
gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 10);
|
|
|
|
// setup callback such that whenever tree view selection is changed, frame gets updated
|
|
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_CheatView));
|
|
g_signal_connect(selection, "changed", G_CALLBACK(cb_updateFrame), frame);
|
|
|
|
// manually update the frame the first time
|
|
cb_updateFrame(selection, frame);
|
|
|
|
gtk_widget_show_all(dialog);
|
|
}
|
|
|