mupen64plus-oldsvn/main/gui_gtk/cheatdialog.c
2008-10-05 20:48:15 +00:00

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);
}