diff --git a/cheats.h b/cheats.h
index a651a63b..d0688fce 100644
--- a/cheats.h
+++ b/cheats.h
@@ -269,7 +269,7 @@ void S9xDeleteCheatGroup (uint32 index);
bool8 S9xLoadCheatFile (const char *filename);
bool8 S9xSaveCheatFile (const char *filename);
void S9xUpdateCheatsInMemory (void);
-bool8 S9xImportCheatsFromDatabase (const char *filename);
+int S9xImportCheatsFromDatabase(const char *filename);
void S9xCheatsDisable (void);
void S9xCheatsEnable (void);
char *S9xCheatValidate (char *cheat);
diff --git a/cheats2.cpp b/cheats2.cpp
index b232604a..4809ef32 100644
--- a/cheats2.cpp
+++ b/cheats2.cpp
@@ -701,6 +701,32 @@ void S9xUpdateCheatsInMemory (void)
}
}
+static int S9xCheatIsDuplicate (char *name, char *code)
+{
+ unsigned int i;
+
+ for (i = 0; i < Cheat.g.size(); i++)
+ {
+ if (!strcmp (name, Cheat.g[i].name))
+ {
+ char *code_string = S9xCheatGroupToText (i);
+ char *validated = S9xCheatValidate (code);
+
+ if (validated && !strcmp (code_string, validated))
+ {
+ free (code_string);
+ free (validated);
+ return TRUE;
+ }
+
+ free (code_string);
+ free (validated);
+ }
+ }
+
+ return FALSE;
+}
+
static void S9xLoadCheatsFromBMLNode (bml_node *n)
{
unsigned int i;
@@ -725,7 +751,7 @@ static void S9xLoadCheatsFromBMLNode (bml_node *n)
if (bml_find_sub(c, "enabled"))
enabled = true;
- if (desc && code)
+ if (desc && code && !S9xCheatIsDuplicate (desc, code))
{
int index = S9xAddCheatGroup (desc, code);
@@ -878,7 +904,7 @@ void S9xCheatsEnable (void)
}
}
-bool8 S9xImportCheatsFromDatabase (const char *filename)
+int S9xImportCheatsFromDatabase (const char *filename)
{
bml_node *bml;
char sha256_txt[65];
@@ -888,7 +914,7 @@ bool8 S9xImportCheatsFromDatabase (const char *filename)
bml = bml_parse_file (filename);
if (!bml)
- return FALSE;
+ return -1; /* No file */
for (i = 0; i < 32; i++)
{
@@ -909,7 +935,7 @@ bool8 S9xImportCheatsFromDatabase (const char *filename)
{
S9xLoadCheatsFromBMLNode (bml->child[i]);
bml_free_node (bml);
- return TRUE;
+ return 0;
}
}
}
@@ -917,5 +943,5 @@ bool8 S9xImportCheatsFromDatabase (const char *filename)
bml_free_node (bml);
- return FALSE;
+ return -2; /* No codes */
}
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 7bf7fa7e..e1d5d583 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -8,7 +8,7 @@ snes9x_gtk_CXXFLAGS = -fno-exceptions -fno-rtti
endif
noinst_LIBRARIES =
-AM_CPPFLAGS = -I../apu/bapu -I$(top_srcdir) -I.. -DSNES9XLOCALEDIR=\""$(snes9xlocaledir)"\"
+AM_CPPFLAGS = -I../apu/bapu -I$(top_srcdir) -I.. -DDATADIR=\""$(snes9xdatadir)"\" -DSNES9XLOCALEDIR=\""$(snes9xlocaledir)"\"
CLEANFILES = \
src/gtk_snes9x_ui.cpp \
diff --git a/gtk/configure.ac b/gtk/configure.ac
index 336e35a8..07f8c5c9 100644
--- a/gtk/configure.ac
+++ b/gtk/configure.ac
@@ -34,7 +34,10 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE")
AM_GLIB_GNU_GETTEXT
snes9xlocaledir='${prefix}/${DATADIRNAME}/locale'
+snes9xdatadir='${prefix}/${DATADIRNAME}/snes9x'
+
AC_SUBST(snes9xlocaledir)
+AC_SUBST(snes9xdatadir)
AC_ARG_WITH(debug,
[AS_HELP_STRING([--with(out)-debug],
@@ -152,9 +155,9 @@ AC_ARG_WITH(screenshot,
AC_ARG_WITH(gtk3,
[AS_HELP_STRING([--with(out)-gtk3],
- [Build with GTK+ 3 if available (default: without)])],
+ [Build with GTK+ 3 if available (default: with)])],
[],
- [with_gtk3=no])
+ [with_gtk3=yes])
if test yes = "$with_debug" ; then
CFLAGS="$CFLAGS -g"
@@ -499,7 +502,7 @@ echo "Snes9x will build with support for the following:"
echo ""
if test yes = "$GTK3_WARNING" ; then
- echo " GTK+ 3.0 (experimental)"
+ echo " GTK+ 3.0"
else
echo " GTK+ 2.0"
fi
diff --git a/gtk/data/Makefile.am b/gtk/data/Makefile.am
index 72e39cc9..fa7f7ccc 100644
--- a/gtk/data/Makefile.am
+++ b/gtk/data/Makefile.am
@@ -13,6 +13,9 @@ icon32x32_DATA = snes9x_32x32.png
iconscalabledir = $(datadir)/icons/hicolor/scalable/apps
iconscalable_DATA = snes9x.svg
+cheatsdir = $(datadir)/snes9x
+cheats_DATA = ../../data/cheats.bml
+
install-data-hook:
mv -f $(DESTDIR)$(datadir)/icons/hicolor/16x16/apps/snes9x_16x16.png \
$(DESTDIR)$(datadir)/icons/hicolor/16x16/apps/snes9x.png
diff --git a/gtk/src/gtk_cheat.cpp b/gtk/src/gtk_cheat.cpp
index 74c413c4..a1eacf6d 100644
--- a/gtk/src/gtk_cheat.cpp
+++ b/gtk/src/gtk_cheat.cpp
@@ -41,12 +41,37 @@ event_remove_code (GtkButton *button, gpointer data)
((Snes9xCheats *) data)->remove_code ();
}
+static void
+event_search_database (GtkButton *button, gpointer data)
+{
+ ((Snes9xCheats *) data)->search_database ();
+}
+
+static void
+event_delete_all_cheats (GtkButton *button, gpointer data)
+{
+ ((Snes9xCheats *) data)->delete_all_cheats ();
+}
+
static void
event_code_toggled (GtkCellRendererToggle *cell_renderer,
gchar *path,
gpointer data)
{
- ((Snes9xCheats *) data)->toggle_code (path);
+ int enabled = !gtk_cell_renderer_toggle_get_active (cell_renderer);
+
+ ((Snes9xCheats *) data)->toggle_code (path, enabled);
+
+ return;
+}
+
+void
+event_row_activated (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer data)
+{
+ ((Snes9xCheats *) data)->row_activated (path);
return;
}
@@ -60,13 +85,17 @@ Snes9xCheats::Snes9xCheats (void)
{
{ "add_code", G_CALLBACK (event_add_code) },
{ "remove_code", G_CALLBACK (event_remove_code) },
+ { "search_database", G_CALLBACK (event_search_database) },
+ { "delete_all_cheats", G_CALLBACK (event_delete_all_cheats) },
{ NULL, NULL}
};
view = GTK_TREE_VIEW (get_widget ("cheat_treeview"));
+ g_signal_connect (view, "row-activated", G_CALLBACK (event_row_activated), (gpointer) this);
renderer = gtk_cell_renderer_toggle_new ();
+ gtk_cell_renderer_toggle_set_activatable (GTK_CELL_RENDERER_TOGGLE (renderer), TRUE);
gtk_tree_view_insert_column_with_attributes (view,
-1,
"",
@@ -86,6 +115,8 @@ Snes9xCheats::Snes9xCheats (void)
renderer,
"text", COLUMN_DESCRIPTION,
NULL);
+ GtkTreeViewColumn *column = gtk_tree_view_get_column (view, 1);
+ gtk_tree_view_column_set_resizable (column, TRUE);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (view,
@@ -94,6 +125,9 @@ Snes9xCheats::Snes9xCheats (void)
renderer,
"text", COLUMN_CHEAT,
NULL);
+ column = gtk_tree_view_get_column (view, 2);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+
store = gtk_list_store_new (NUM_COLS,
G_TYPE_BOOLEAN,
@@ -182,14 +216,25 @@ void
Snes9xCheats::refresh_tree_view (void)
{
GtkTreeIter iter;
+ unsigned int list_size;
- gtk_list_store_clear (store);
+ list_size = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
+
+ if (Cheat.g.size () == 0)
+ return;
+
+ for (unsigned int i = 0; i < Cheat.g.size() - list_size; i++)
+ gtk_list_store_append (store, &iter);
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
for (unsigned int i = 0; i < Cheat.g.size (); i++)
{
char *str = S9xCheatGroupToText (i);
- gtk_list_store_append (store, &iter);
+ if (i > 0)
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+
gtk_list_store_set (store, &iter,
COLUMN_DESCRIPTION,
!strcmp (Cheat.g [i].name, "") ? _("No description")
@@ -200,7 +245,6 @@ Snes9xCheats::refresh_tree_view (void)
delete[] str;
}
-
return;
}
@@ -228,31 +272,127 @@ void
Snes9xCheats::remove_code (void)
{
int index = get_selected_index ();
+ GtkTreeIter iter;
if (index < 0)
return;
- S9xDeleteCheatGroup (index);
+ gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, NULL, index);
+ gtk_list_store_remove (store, &iter);
- refresh_tree_view ();
+ S9xDeleteCheatGroup (index);
return;
}
void
-Snes9xCheats::toggle_code (const gchar *path)
+Snes9xCheats::delete_all_cheats (void)
{
- int index = get_index_from_path (path);
-
- if (index < 0)
- return;
-
- if (Cheat.g[index].enabled)
- S9xDisableCheatGroup (index);
- else
- S9xEnableCheatGroup (index);
-
- refresh_tree_view ();
+ S9xDeleteCheats ();
+ gtk_list_store_clear (store);
+
+ return;
+}
+
+void
+Snes9xCheats::search_database (void)
+{
+ std::string filename;
+ int result;
+ int reason = 0;
+
+ filename = S9xGetFilename ("cheats.bml", CHEAT_DIR);
+ if (!(result = S9xImportCheatsFromDatabase (filename.c_str ())))
+ {
+ refresh_tree_view ();
+ return;
+ }
+
+ if (result < reason)
+ reason = result;
+
+ char *config_dir = get_config_dir ();
+ filename = std::string (config_dir) + "/cheats.bml";
+ free (config_dir);
+ if (!(result = S9xImportCheatsFromDatabase (filename.c_str ())))
+ {
+ refresh_tree_view ();
+ return;
+ }
+
+ if (result < reason)
+ reason = result;
+
+
+ filename = std::string (DATADIR) + "/cheats.bml";
+ if (!(result = S9xImportCheatsFromDatabase (filename.c_str ())))
+ {
+ refresh_tree_view ();
+ return;
+ }
+
+ if (result < reason)
+ reason = result;
+
+ filename = S9xGetFilename ("cheats.bml", ROM_DIR);
+ if (!(result = S9xImportCheatsFromDatabase (filename.c_str ())))
+ {
+ refresh_tree_view ();
+ return;
+ }
+
+ if (result < reason)
+ reason = result;
+
+ GtkMessageDialog *dialog;
+ GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
+ dialog = GTK_MESSAGE_DIALOG (gtk_message_dialog_new (get_window (),
+ flags,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE,
+ reason == -1 ? _("Couldn't Find Cheats Database") :
+ _("No Matching Game Found")));
+ gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG (dialog),
+ reason == -1 ?
+ _("The database file cheats.bml was not found. It is normally installed with "
+ "Snes9x, but you may also place a custom copy in your configuration or cheats directory.") :
+ _("No matching game was found in the databases. If you are using a non-official "
+ "translation or modified copy, you may be able to find and manually enter the codes."));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+
+ return;
+}
+
+void
+Snes9xCheats::row_activated (GtkTreePath *path)
+{
+ gint *indices = gtk_tree_path_get_indices (path);
+ char *cheat_text;
+
+ cheat_text = S9xCheatGroupToText (indices[0]);
+ set_entry_text ("code_entry", cheat_text);
+ delete[] cheat_text;
+ set_entry_text ("description_entry", Cheat.g[indices[0]].name);
+
+ return;
+}
+
+void
+Snes9xCheats::toggle_code (const gchar *path, int enabled)
+{
+ GtkTreeIter iter;
+ int index = get_index_from_path (path);
+
+ GtkTreePath *treepath = gtk_tree_path_new_from_string (path);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, treepath);
+ gtk_list_store_set (store, &iter, COLUMN_ENABLED, enabled, -1);
+
+ if (enabled)
+ S9xEnableCheatGroup (index);
+ else
+ S9xDisableCheatGroup (index);
+
return;
}
diff --git a/gtk/src/gtk_cheat.h b/gtk/src/gtk_cheat.h
index 8480932c..a8baf94d 100644
--- a/gtk/src/gtk_cheat.h
+++ b/gtk/src/gtk_cheat.h
@@ -15,7 +15,10 @@ class Snes9xCheats : public GtkBuilderWindow
void show (void);
void add_code (void);
void remove_code (void);
- void toggle_code (const gchar *path);
+ void search_database (void);
+ void delete_all_cheats (void);
+ void toggle_code (const gchar *path, int enabled);
+ void row_activated (GtkTreePath *path);
private:
void refresh_tree_view (void);
diff --git a/gtk/src/snes9x.ui b/gtk/src/snes9x.ui
index 99573bda..b468cb8c 100644
--- a/gtk/src/snes9x.ui
+++ b/gtk/src/snes9x.ui
@@ -256,8 +256,8 @@
0.10000000000000001
False