1 /*  Cheat Support for PCSX-Reloaded
2  *  Copyright (C) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdint.h>
23 
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtk.h>
26 
27 #include "Linux.h"
28 
29 #include "../libpcsxcore/cheat.h"
30 #include "../libpcsxcore/psxmem.h"
31 
32 static GtkBuilder *builder;
33 GtkWidget *CheatListDlg = NULL;
34 GtkWidget *CheatSearchDlg = NULL;
35 
LoadCheatListItems(int index)36 static void LoadCheatListItems(int index) {
37 	GtkListStore *store = gtk_list_store_new(2, G_TYPE_BOOLEAN, G_TYPE_STRING);
38 	GtkTreeIter iter;
39 	GtkWidget *widget;
40 
41 	int i;
42 
43 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "GtkCList_Cheat"));
44 
45 	for (i = 0; i < NumCheats; i++) {
46 		gtk_list_store_append(store, &iter);
47 		gtk_list_store_set(store, &iter, 0, Cheats[i].Enabled, 1, Cheats[i].Descr, -1);
48 	}
49 
50 	gtk_tree_view_set_model(GTK_TREE_VIEW(widget), GTK_TREE_MODEL(store));
51 	g_object_unref(G_OBJECT(store));
52 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(widget), 1);
53 	gtk_widget_show(widget);
54 
55 	if (index >= NumCheats) {
56 		index = NumCheats - 1;
57 	}
58 
59 	if (index >= 0) {
60 		GtkTreePath *path;
61 		GtkTreeSelection *sel;
62 
63 		path = gtk_tree_path_new_from_indices(index, -1);
64 		sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
65 
66 		gtk_tree_selection_select_path(sel, path);
67 		gtk_tree_path_free(path);
68 	}
69 }
70 
CheatList_TreeSelectionChanged(GtkTreeSelection * selection,gpointer user_data)71 static void CheatList_TreeSelectionChanged(GtkTreeSelection *selection, gpointer user_data) {
72 	GtkTreeIter iter;
73 	GtkTreeModel *model;
74 	GtkTreePath *path;
75 
76 	gboolean selected;
77 	int i;
78 
79 	selected = gtk_tree_selection_get_selected(selection, &model, &iter);
80 
81 	if (selected) {
82 		path = gtk_tree_model_get_path(model, &iter);
83 		i = *gtk_tree_path_get_indices(path);
84 		gtk_tree_path_free(path);
85 
86 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "editbutton1")), TRUE);
87 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "delbutton1")), TRUE);
88 	} else {
89 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "editbutton1")), FALSE);
90 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "delbutton1")), FALSE);
91 	}
92 
93 	gtk_widget_set_sensitive (GTK_WIDGET(gtk_builder_get_object(builder, "savebutton1")), NumCheats);
94 }
95 
OnCheatListDlg_AddClicked(GtkWidget * widget,gpointer user_data)96 static void OnCheatListDlg_AddClicked(GtkWidget *widget, gpointer user_data) {
97 	GtkWidget *dlg;
98 	GtkWidget *box, *scroll, *label, *descr_edit, *code_edit;
99 
100 	dlg = gtk_dialog_new_with_buttons(_("Add New Cheat"), GTK_WINDOW(CheatListDlg),
101 		GTK_DIALOG_MODAL, "_Cancel", GTK_RESPONSE_CANCEL,
102 		"_OK", GTK_RESPONSE_ACCEPT, NULL);
103 
104 	gtk_window_set_default_size(GTK_WINDOW(dlg), 350, 350);
105 
106 	box = GTK_WIDGET(gtk_dialog_get_content_area(GTK_DIALOG(dlg)));
107 
108 	label = gtk_label_new(_("Cheat Description:"));
109 	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
110 	gtk_widget_show(label);
111 
112 	descr_edit = gtk_entry_new();
113 	gtk_box_pack_start(GTK_BOX(box), descr_edit, FALSE, FALSE, 5);
114 	gtk_widget_show(descr_edit);
115 
116 	label = gtk_label_new(_("Cheat Code:"));
117 	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
118 	gtk_widget_show(label);
119 
120 	code_edit = gtk_text_view_new();
121 	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(code_edit), GTK_WRAP_CHAR);
122 
123 	scroll = gtk_scrolled_window_new(NULL, NULL);
124 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
125 		GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
126 
127 	gtk_container_add(GTK_CONTAINER(scroll), code_edit);
128 	gtk_widget_show(code_edit);
129 
130 	gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 5);
131 	gtk_widget_show(scroll);
132 
133 	gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
134 
135 	gtk_widget_show_all(dlg);
136 
137 	while (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) {
138 		GtkTextBuffer *b = gtk_text_view_get_buffer(GTK_TEXT_VIEW(code_edit));
139 		GtkTextIter s, e;
140 		char *codetext;
141 
142 		gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(b), &s, &e);
143 		codetext = strdup(gtk_text_buffer_get_text(GTK_TEXT_BUFFER(b), &s, &e, FALSE));
144 
145 		if (AddCheat(gtk_entry_get_text(GTK_ENTRY(descr_edit)), codetext) != 0) {
146 			SysErrorMessage(_("Error"), _("Invalid cheat code!"));
147 			continue;
148 		}
149 
150 		LoadCheatListItems(NumCheats - 1);
151 		free(codetext);
152 		break;
153 	}
154 
155 	gtk_widget_destroy(dlg);
156 }
157 
OnCheatListDlg_EditClicked(GtkWidget * widget,gpointer user_data)158 static void OnCheatListDlg_EditClicked(GtkWidget *widget, gpointer user_data) {
159 	GtkWidget *dlg;
160 	GtkWidget *box, *scroll, *label, *descr_edit, *code_edit;
161 	GtkTreeIter iter;
162 	GtkTreeModel *model;
163 	GtkTreePath *path;
164 
165 	gboolean selected;
166 	int index, i;
167 	char buf[8192];
168 	char *p = buf;
169 
170 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "GtkCList_Cheat"));
171 
172 	selected = gtk_tree_selection_get_selected(
173 		gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)),
174 		&model, &iter);
175 
176 	if (!selected) {
177 		return;
178 	}
179 
180 	path = gtk_tree_model_get_path(model, &iter);
181 	index = *gtk_tree_path_get_indices(path);
182 	gtk_tree_path_free(path);
183 
184 	dlg = gtk_dialog_new_with_buttons(_("Edit Cheat"), GTK_WINDOW(CheatListDlg),
185 		GTK_DIALOG_MODAL, "_Cancel", GTK_RESPONSE_CANCEL,
186 		"_OK", GTK_RESPONSE_ACCEPT, NULL);
187 
188 	gtk_window_set_default_size(GTK_WINDOW(dlg), 350, 350);
189 
190 	box = GTK_WIDGET(gtk_dialog_get_content_area(GTK_DIALOG(dlg)));
191 
192 	label = gtk_label_new(_("Cheat Description:"));
193 	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
194 	gtk_widget_show(label);
195 
196 	descr_edit = gtk_entry_new();
197 	gtk_entry_set_text(GTK_ENTRY(descr_edit), Cheats[index].Descr);
198 	gtk_box_pack_start(GTK_BOX(box), descr_edit, FALSE, FALSE, 5);
199 	gtk_widget_show(descr_edit);
200 
201 	label = gtk_label_new(_("Cheat Code:"));
202 	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
203 	gtk_widget_show(label);
204 
205 	code_edit = gtk_text_view_new();
206 
207 	for (i = Cheats[index].First; i < Cheats[index].First + Cheats[index].n; i++) {
208 		sprintf(p, "%.8X %.4X\n", CheatCodes[i].Addr, CheatCodes[i].Val);
209 		p += 14;
210 		*p = '\0';
211 	}
212 
213 	gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(code_edit)),
214 		buf, -1);
215 
216 	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(code_edit), GTK_WRAP_CHAR);
217 
218 	scroll = gtk_scrolled_window_new(NULL, NULL);
219 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
220 		GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
221 
222 	gtk_container_add(GTK_CONTAINER(scroll), code_edit);
223 	gtk_widget_show(code_edit);
224 
225 	gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 5);
226 	gtk_widget_show(scroll);
227 
228 	gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
229 
230 	gtk_widget_show_all(dlg);
231 
232 	if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) {
233 		GtkTextBuffer *b = gtk_text_view_get_buffer(GTK_TEXT_VIEW(code_edit));
234 		GtkTextIter s, e;
235 		char *codetext;
236 
237 		gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(b), &s, &e);
238 		codetext = strdup(gtk_text_buffer_get_text(GTK_TEXT_BUFFER(b), &s, &e, FALSE));
239 
240 		if (EditCheat(index, gtk_entry_get_text(GTK_ENTRY(descr_edit)), codetext) != 0) {
241 			SysErrorMessage(_("Error"), _("Invalid cheat code!"));
242 		}
243 
244 		LoadCheatListItems(index);
245 
246 		free(codetext);
247 	}
248 
249 	gtk_widget_destroy(dlg);
250 }
251 
OnCheatListDlg_DelClicked(GtkWidget * widget,gpointer user_data)252 static void OnCheatListDlg_DelClicked(GtkWidget *widget, gpointer user_data) {
253 	GtkTreeIter iter;
254 	GtkTreeModel *model;
255 	GtkTreePath *path;
256 
257 	gboolean selected;
258 	int i = -1;
259 
260 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "GtkCList_Cheat"));
261 
262 	selected = gtk_tree_selection_get_selected(
263 		gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)),
264 		&model, &iter);
265 
266 	if (selected) {
267 		path = gtk_tree_model_get_path(model, &iter);
268 		i = *gtk_tree_path_get_indices(path);
269 		gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
270 		gtk_tree_path_free(path);
271 
272 		RemoveCheat(i);
273 	}
274 }
275 
OnCheatListDlg_EnableToggled(GtkCellRendererToggle * cell,gchar * path_str,gpointer user_data)276 static void OnCheatListDlg_EnableToggled(GtkCellRendererToggle *cell, gchar *path_str, gpointer user_data) {
277 	GtkWidget *widget;
278 	GtkTreeModel *model;
279 	GtkTreePath *path;
280 	GtkTreeIter  iter;
281 	gboolean fixed;
282 
283 	widget = GTK_WIDGET(gtk_builder_get_object (builder, "GtkCList_Cheat"));
284 	model = gtk_tree_view_get_model (GTK_TREE_VIEW(widget));
285 	path = gtk_tree_path_new_from_string (path_str);
286 
287 	gtk_tree_model_get_iter (model, &iter, path);
288 	gtk_tree_model_get (model, &iter, 0, &fixed, -1);
289 
290 	fixed ^= 1;
291 
292 	int i = atoi(path_str);
293 	assert(i >= 0 && i < NumCheats);
294 
295 	Cheats[i].Enabled = fixed;
296 
297 	gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, fixed, -1);
298 	gtk_tree_path_free (path);
299 }
300 
301 // last chosen filename is kept in here
302 gchar *cheat_last_filename = NULL;
303 
304 const gchar* file_filter_all = NULL;
305 
OnCheatListDlg_OpenClicked(GtkWidget * widget,gpointer user_data)306 static void OnCheatListDlg_OpenClicked(GtkWidget *widget, gpointer user_data) {
307 	GtkWidget *chooser;
308 	gchar *filename;
309 
310 	GtkFileFilter *filter;
311 
312 	chooser = gtk_file_chooser_dialog_new (_("Open Cheat File"),
313 		NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL,
314 		"_OK", GTK_RESPONSE_OK, NULL);
315 
316 	filename = g_build_filename(getenv("HOME"), CHEATS_DIR, NULL);
317 	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), filename);
318 	//gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(chooser), filename);
319 	g_free(filename);
320 
321 	filter = gtk_file_filter_new ();
322 	gtk_file_filter_add_pattern (filter, all_extension_cht);
323 	gtk_file_filter_set_name (filter, _("PCSXR Cheat Code Files (*.cht)"));
324 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
325 
326 	filter = gtk_file_filter_new ();
327 	gtk_file_filter_add_pattern (filter, "*");
328 	gtk_file_filter_set_name (filter, file_filter_all);
329 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
330 
331 	if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) {
332 		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
333 		gtk_widget_destroy (GTK_WIDGET (chooser));
334 		while (gtk_events_pending()) gtk_main_iteration();
335 	} else {
336 		gtk_widget_destroy (GTK_WIDGET (chooser));
337 		while (gtk_events_pending()) gtk_main_iteration();
338 		return;
339 	}
340 
341 	LoadCheats(filename);
342 
343 	g_free(cheat_last_filename);
344 	cheat_last_filename = g_path_get_basename(filename);
345 
346 	g_free(filename);
347 
348 	LoadCheatListItems(-1);
349 }
350 
OnCheatListDlg_SaveClicked(GtkWidget * widget,gpointer user_data)351 static void OnCheatListDlg_SaveClicked(GtkWidget *widget, gpointer user_data) {
352 	GtkWidget *chooser;
353 	gchar *filename, *filename2=NULL;
354 	GtkFileFilter *filter;
355 
356 	chooser = gtk_file_chooser_dialog_new(_("Save Cheat File"),
357 		NULL, GTK_FILE_CHOOSER_ACTION_SAVE, "_Cancel", GTK_RESPONSE_CANCEL,
358 		"_OK", GTK_RESPONSE_OK, NULL);
359 
360 	filename = g_build_filename(getenv("HOME"), CHEATS_DIR, NULL);
361 	gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), filename);
362 
363 	// Use game code as default filename, otherwise remember what user selected
364 	if (!cheat_last_filename) {
365 		cheat_last_filename = get_cdrom_label_id(dot_extension_cht);
366 	}
367 	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser), cheat_last_filename);
368 
369 	g_free(filename);
370 
371 	filter = gtk_file_filter_new();
372 	gtk_file_filter_add_pattern(filter, all_extension_cht);
373 	gtk_file_filter_set_name(filter, _("PCSXR Cheat Code Files (*.cht)"));
374 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
375 
376 	filter = gtk_file_filter_new();
377 	gtk_file_filter_add_pattern(filter, "*");
378 	gtk_file_filter_set_name(filter, file_filter_all);
379 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
380 
381 	if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) {
382 		filename = filename2 = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
383 	if (!g_str_has_suffix(filename, dot_extension_cht) // add extension if cht filter chosen and filename doesn't end with .cht
384 			&& strcmp(file_filter_all, gtk_file_filter_get_name(
385 				gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(chooser)))) != 0) {
386 		filename = g_strdup_printf ("%s%s", filename2, dot_extension_cht);
387 	} else {
388 		filename2 = NULL;
389 	}
390 
391 		gtk_widget_destroy (GTK_WIDGET(chooser));
392 		while (gtk_events_pending()) gtk_main_iteration();
393 	} else {
394 		gtk_widget_destroy (GTK_WIDGET(chooser));
395 		while (gtk_events_pending()) gtk_main_iteration();
396 		return;
397 	}
398 
399 	SaveCheats(filename);
400 
401 	g_free(cheat_last_filename);
402 	cheat_last_filename = g_path_get_basename(filename);
403 
404 	g_free(filename);
405 	g_free(filename2);
406 }
407 
OnCheatListDlg_CloseClicked()408 static void OnCheatListDlg_CloseClicked() {
409 	gtk_widget_destroy(CheatListDlg);
410 	CheatListDlg = NULL;
411 	//g_free(lastfilename);
412 	//lastfilename = NULL;
413 }
414 
415 // run the cheat list dialog
RunCheatListDialog()416 void RunCheatListDialog() {
417 	GtkWidget *widget;
418 	GtkTreeSelection *treesel;
419 	GtkTreeViewColumn *column;
420 	GtkCellRenderer *renderer;
421 
422 	file_filter_all = _("All Files (*.*)");
423 
424 	builder = gtk_builder_new();
425 
426 	if (!gtk_builder_add_from_resource(builder, "/org/pcsxr/gui/pcsxr.ui", NULL)) {
427 		g_warning("Error: interface could not be loaded!");
428 		return;
429 	}
430 
431 	CheatListDlg = GTK_WIDGET(gtk_builder_get_object(builder, "CheatListDlg"));
432 
433 	gtk_window_set_title(GTK_WINDOW(CheatListDlg), _("Cheat Codes"));
434 	gtk_widget_show (CheatListDlg);
435 
436 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "GtkCList_Cheat"));
437 
438 	// column for enable
439 	renderer = gtk_cell_renderer_toggle_new();
440 	column = gtk_tree_view_column_new_with_attributes(_("Enable"),
441 		renderer, "active", 0, NULL);
442 	gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column);
443 
444 	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(OnCheatListDlg_EnableToggled), 0);
445 
446 	// column for description
447 	renderer = gtk_cell_renderer_text_new();
448 	column = gtk_tree_view_column_new_with_attributes(_("Description"),
449 		renderer, "text", 1, NULL);
450 	gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column);
451 
452 	LoadCheatListItems(-1);
453 
454 	treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
455 	gtk_tree_selection_set_mode(treesel, GTK_SELECTION_SINGLE);
456 	g_signal_connect_data(G_OBJECT (treesel), "changed",
457 						  G_CALLBACK (CheatList_TreeSelectionChanged),
458 						  NULL, NULL, G_CONNECT_AFTER);
459 
460 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "addbutton1"));
461 	g_signal_connect_data(G_OBJECT(widget), "clicked",
462 			G_CALLBACK(OnCheatListDlg_AddClicked), builder, NULL, G_CONNECT_AFTER);
463 
464 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "editbutton1"));
465 	g_signal_connect_data(G_OBJECT(widget), "clicked",
466 			G_CALLBACK(OnCheatListDlg_EditClicked), builder, NULL, G_CONNECT_AFTER);
467 
468 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "delbutton1"));
469 	g_signal_connect_data(G_OBJECT(widget), "clicked",
470 			G_CALLBACK(OnCheatListDlg_DelClicked), builder, NULL, G_CONNECT_AFTER);
471 
472 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "loadbutton1"));
473 	g_signal_connect_data(G_OBJECT(widget), "clicked",
474 			G_CALLBACK(OnCheatListDlg_OpenClicked), builder, NULL, G_CONNECT_AFTER);
475 
476 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "savebutton1"));
477 	g_signal_connect_data(G_OBJECT(widget), "clicked",
478 			G_CALLBACK(OnCheatListDlg_SaveClicked), builder, NULL, G_CONNECT_AFTER);
479 
480 	// Setup a handler for when Close or Cancel is clicked
481 	g_signal_connect_data(G_OBJECT(CheatListDlg), "response",
482 			G_CALLBACK(OnCheatListDlg_CloseClicked), builder, (GClosureNotify)g_object_unref, G_CONNECT_AFTER);
483 
484 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "savebutton1")), NumCheats);
485 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "editbutton1")), FALSE);
486 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "delbutton1")), FALSE);
487 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "editbutton1")), FALSE);
488 }
489 
490 ///////////////////////////////////////////////////////////////////////////////
491 
492 #define SEARCH_EQUALVAL				0
493 #define SEARCH_NOTEQUALVAL			1
494 #define SEARCH_RANGE				2
495 #define SEARCH_INCBY				3
496 #define SEARCH_DECBY				4
497 #define SEARCH_INC					5
498 #define SEARCH_DEC					6
499 #define SEARCH_DIFFERENT			7
500 #define SEARCH_NOCHANGE				8
501 
502 #define SEARCHTYPE_8BIT				0
503 #define SEARCHTYPE_16BIT			1
504 #define SEARCHTYPE_32BIT			2
505 
506 #define SEARCHBASE_DEC				0
507 #define SEARCHBASE_HEX				1
508 
509 static char current_search			= SEARCH_EQUALVAL;
510 static char current_searchtype		= SEARCHTYPE_8BIT;
511 static char current_searchbase		= SEARCHBASE_DEC;
512 static uint32_t current_valuefrom	= 0;
513 static uint32_t current_valueto		= 0;
514 
515 // update the cheat search dialog
UpdateCheatSearchDialog()516 static void UpdateCheatSearchDialog() {
517 	char			buf[256];
518 	int				i;
519 	u32				addr;
520 	GtkListStore	*store = gtk_list_store_new(1, G_TYPE_STRING);
521 	GtkTreeIter		iter;
522 	GtkWidget		*widget;
523 
524 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "GtkCList_Result"));
525 
526 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(builder, "combo_searchfor")), current_search);
527 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(builder, "combo_datatype")), current_searchtype);
528 	gtk_combo_box_set_active(GTK_COMBO_BOX(gtk_builder_get_object(builder, "combo_database")), current_searchbase);
529 
530 	if (current_searchbase == SEARCHBASE_DEC) {
531 		sprintf(buf, "%u", current_valuefrom);
532 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_value")), buf);
533 		sprintf(buf, "%u", current_valueto);
534 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_valueto")), buf);
535 	}
536 	else {
537 		sprintf(buf, "%X", current_valuefrom);
538 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_value")), buf);
539 		sprintf(buf, "%X", current_valueto);
540 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_valueto")), buf);
541 	}
542 
543 	if (current_search == SEARCH_RANGE) {
544 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "label_valueto")));
545 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "entry_valueto")));
546 	}
547 	else {
548 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "label_valueto")));
549 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "entry_valueto")));
550 	}
551 
552 	if (current_search >= SEARCH_INC) {
553 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "entry_value")), FALSE);
554 	}
555 	else {
556 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "entry_value")), TRUE);
557 	}
558 
559 	if (current_search >= SEARCH_INCBY && prevM == NULL) {
560 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_start")), FALSE);
561 	}
562 	else {
563 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_start")), TRUE);
564 	}
565 
566 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_freeze")), FALSE);
567 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_modify")), FALSE);
568 	gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_copy")), FALSE);
569 
570 	if (prevM != NULL) {
571 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "combo_datatype")), FALSE);
572 
573 		if (NumSearchResults > 100) {
574 			// too many results to be shown
575 			gtk_list_store_append(store, &iter);
576 			gtk_list_store_set(store, &iter, 0, _("Too many addresses found."), -1);
577 			gtk_widget_set_sensitive(widget, FALSE);
578 		}
579 		else {
580 			for (i = 0; i < NumSearchResults; i++) {
581 				addr = SearchResults[i];
582 
583 				switch (current_searchtype) {
584 					case SEARCHTYPE_8BIT:
585 						sprintf(buf, _("%.8X    Current: %u (%.2X), Previous: %u (%.2X)"),
586 							addr, PSXMu8(addr), PSXMu8(addr), PrevMu8(addr), PrevMu8(addr));
587 						break;
588 
589 					case SEARCHTYPE_16BIT:
590 						sprintf(buf, _("%.8X    Current: %u (%.4X), Previous: %u (%.4X)"),
591 							addr, PSXMu16(addr), PSXMu16(addr), PrevMu16(addr), PrevMu16(addr));
592 						break;
593 
594 					case SEARCHTYPE_32BIT:
595 						sprintf(buf, _("%.8X    Current: %u (%.8X), Previous: %u (%.8X)"),
596 							addr, PSXMu32(addr), PSXMu32(addr), PrevMu32(addr), PrevMu32(addr));
597 						break;
598 
599 					default:
600 						assert(FALSE); // impossible
601 						break;
602 				}
603 
604 				gtk_list_store_append(store, &iter);
605 				gtk_list_store_set(store, &iter, 0, buf, -1);
606 			}
607 			gtk_widget_set_sensitive(widget, TRUE);
608 		}
609 
610 		sprintf(buf, _("Founded Addresses: %d"), NumSearchResults);
611 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "label_resultsfound")), buf);
612 	}
613 	else {
614 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "combo_datatype")), TRUE);
615 		gtk_widget_set_sensitive(widget, FALSE);
616 
617 		gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "label_resultsfound")),
618 			_("Enter the values and start your search."));
619 	}
620 
621 	gtk_tree_view_set_model(GTK_TREE_VIEW(widget), GTK_TREE_MODEL(store));
622 	g_object_unref(G_OBJECT(store));
623 	gtk_widget_show(widget);
624 }
625 
626 // get the current selected result index in the list
GetSelectedResultIndex()627 static int GetSelectedResultIndex() {
628 	GtkTreeSelection	*selection;
629 	GtkTreeIter			iter;
630 	GtkTreeModel		*model;
631 	GtkTreePath			*path;
632 	gboolean			selected;
633 	int					i;
634 
635 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtk_builder_get_object(builder, "GtkCList_Result")));
636 	selected = gtk_tree_selection_get_selected(selection, &model, &iter);
637 
638 	if (!selected) {
639 		return -1;
640 	}
641 
642 	path = gtk_tree_model_get_path(model, &iter);
643 	i = *gtk_tree_path_get_indices(path);
644 	gtk_tree_path_free(path);
645 
646 	assert(i < NumSearchResults);
647 	return i;
648 }
649 
650 // add cheat code to freeze the value
OnCheatSearchDlg_FreezeClicked(GtkWidget * widget,gpointer user_data)651 static void OnCheatSearchDlg_FreezeClicked(GtkWidget *widget, gpointer user_data) {
652 	GtkWidget	   *dlg;
653 	GtkWidget	   *box, *hbox, *label, *descr_edit, *value_edit;
654 	char			buf[256];
655 	u32				addr, val = 0;
656 
657 	addr = SearchResults[GetSelectedResultIndex()];
658 
659 	dlg = gtk_dialog_new_with_buttons(_("Freeze value"), GTK_WINDOW(CheatListDlg),
660 		GTK_DIALOG_MODAL, "_OK", GTK_RESPONSE_ACCEPT,
661 		"_Cancel", GTK_RESPONSE_CANCEL, NULL);
662 
663 	box = GTK_WIDGET(gtk_dialog_get_content_area(GTK_DIALOG(dlg)));
664 
665 	label = gtk_label_new(_("Description:"));
666 	gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 5);
667 	gtk_widget_show(label);
668 
669 	descr_edit = gtk_entry_new();
670 	gtk_box_pack_start(GTK_BOX(box), descr_edit, FALSE, FALSE, 10);
671 	gtk_widget_show(descr_edit);
672 
673 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
674 	gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 15);
675 
676 	label = gtk_label_new(_("Value:"));
677 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
678 	gtk_widget_show(label);
679 
680 	value_edit = gtk_entry_new();
681 	gtk_box_pack_start(GTK_BOX(hbox), value_edit, FALSE, FALSE, 10);
682 	gtk_widget_show(value_edit);
683 
684 	switch (current_searchtype) {
685 		case SEARCHTYPE_8BIT:
686 			val = PSXMu8(addr);
687 			break;
688 
689 		case SEARCHTYPE_16BIT:
690 			val = PSXMu16(addr);
691 			break;
692 
693 		case SEARCHTYPE_32BIT:
694 			val = PSXMu32(addr);
695 			break;
696 
697 		default:
698 			assert(FALSE); // should not reach here
699 			break;
700 	}
701 
702 	sprintf(buf, "%u", val);
703 	gtk_entry_set_text(GTK_ENTRY(value_edit), buf);
704 
705 	sprintf(buf, "%.8X", addr);
706 	gtk_entry_set_text(GTK_ENTRY(descr_edit), buf);
707 
708 	gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
709 	gtk_widget_show_all(dlg);
710 
711 	if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) {
712 		val = 0;
713 		sscanf(gtk_entry_get_text(GTK_ENTRY(value_edit)), "%u", &val);
714 
715 		switch (current_searchtype) {
716 			case SEARCHTYPE_8BIT:
717 				if (val > (u32)0xFF) {
718 					val = 0xFF;
719 				}
720 				sprintf(buf, "%.8X %.4X", (addr & 0x1FFFFF) | (CHEAT_CONST8 << 24), val);
721 				break;
722 
723 			case SEARCHTYPE_16BIT:
724 				if (val > (u32)0xFFFF) {
725 					val = 0xFFFF;
726 				}
727 				sprintf(buf, "%.8X %.4X", (addr & 0x1FFFFF) | (CHEAT_CONST16 << 24), val);
728 				break;
729 
730 			case SEARCHTYPE_32BIT:
731 				sprintf(buf, "%.8X %.4X\n%.8X %.4X",
732 					(addr & 0x1FFFFF) | (CHEAT_CONST16 << 24), val & 0xFFFF,
733 					((addr + 2) & 0x1FFFFF) | (CHEAT_CONST16 << 24), ((val & 0xFFFF0000) >> 16) & 0xFFFF);
734 				break;
735 
736 			default:
737 				assert(FALSE); // should not reach here
738 				break;
739 		}
740 
741 		if (AddCheat(gtk_entry_get_text(GTK_ENTRY(descr_edit)), buf) == 0) {
742 			Cheats[NumCheats - 1].Enabled = 1;
743 		}
744 	}
745 
746 	gtk_widget_destroy(dlg);
747 }
748 
749 // modify the value on the fly
OnCheatSearchDlg_ModifyClicked(GtkWidget * widget,gpointer user_data)750 static void OnCheatSearchDlg_ModifyClicked(GtkWidget *widget, gpointer user_data) {
751 	GtkWidget	   *dlg;
752 	GtkWidget	   *box, *hbox, *label, *value_edit;
753 	char			buf[256];
754 	u32				addr, val = 0;
755 
756 	addr = SearchResults[GetSelectedResultIndex()];
757 
758 	dlg = gtk_dialog_new_with_buttons(_("Modify value"), GTK_WINDOW(CheatListDlg),
759 		GTK_DIALOG_MODAL, "_OK", GTK_RESPONSE_ACCEPT,
760 		"_Cancel", GTK_RESPONSE_CANCEL, NULL);
761 
762 	box = GTK_WIDGET(gtk_dialog_get_content_area(GTK_DIALOG(dlg)));
763 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
764 	gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 5);
765 
766 	label = gtk_label_new(_("New value:"));
767 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
768 	gtk_widget_show(label);
769 
770 	value_edit = gtk_entry_new();
771 	gtk_box_pack_start(GTK_BOX(hbox), value_edit, FALSE, FALSE, 10);
772 	gtk_widget_show(value_edit);
773 
774 	switch (current_searchtype) {
775 		case SEARCHTYPE_8BIT:
776 			val = PSXMu8(addr);
777 			break;
778 
779 		case SEARCHTYPE_16BIT:
780 			val = PSXMu16(addr);
781 			break;
782 
783 		case SEARCHTYPE_32BIT:
784 			val = PSXMu32(addr);
785 			break;
786 
787 		default:
788 			assert(FALSE); // should not reach here
789 			break;
790 	}
791 
792 	sprintf(buf, "%u", val);
793 	gtk_entry_set_text(GTK_ENTRY(value_edit), buf);
794 
795 	gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
796 	gtk_widget_show_all(dlg);
797 
798 	if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) {
799 		val = 0;
800 		sscanf(gtk_entry_get_text(GTK_ENTRY(value_edit)), "%u", &val);
801 
802 		switch (current_searchtype) {
803 			case SEARCHTYPE_8BIT:
804 				if (val > 0xFF) {
805 					val = 0xFF;
806 				}
807 				psxMemWrite8(addr, (u8)val);
808 				break;
809 
810 			case SEARCHTYPE_16BIT:
811 				if (val > 0xFFFF) {
812 					val = 0xFFFF;
813 				}
814 				psxMemWrite16(addr, (u16)val);
815 				break;
816 
817 			case SEARCHTYPE_32BIT:
818 				psxMemWrite32(addr, (u32)val);
819 				break;
820 
821 			default:
822 				assert(FALSE); // should not reach here
823 				break;
824 		}
825 
826 		UpdateCheatSearchDialog();
827 	}
828 
829 	gtk_widget_destroy(dlg);
830 }
831 
832 // copy the selected address to clipboard
OnCheatSearchDlg_CopyClicked(GtkWidget * widget,gpointer user_data)833 static void OnCheatSearchDlg_CopyClicked(GtkWidget *widget, gpointer user_data) {
834 	int			i;
835 	char		buf[9];
836 
837 	i = GetSelectedResultIndex();
838 	assert(i != -1);
839 
840 	sprintf(buf, "%8X", SearchResults[i]);
841 	buf[8] = '\0';
842 
843 	gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), buf, 8);
844 }
845 
846 // preform the search
OnCheatSearchDlg_SearchClicked(GtkWidget * widget,gpointer user_data)847 static void OnCheatSearchDlg_SearchClicked(GtkWidget *widget, gpointer user_data) {
848 	current_search = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(builder, "combo_searchfor")));
849 	current_searchtype = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(builder, "combo_datatype")));
850 	current_searchbase = gtk_combo_box_get_active(GTK_COMBO_BOX(gtk_builder_get_object(builder, "combo_database")));
851 	current_valuefrom = 0;
852 	current_valueto = 0;
853 
854 	if (current_searchbase == SEARCHBASE_DEC) {
855 		sscanf(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_value"))), "%u", &current_valuefrom);
856 		sscanf(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_valueto"))), "%u", &current_valueto);
857 	}
858 	else {
859 		sscanf(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_value"))), "%x", &current_valuefrom);
860 		sscanf(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_valueto"))), "%x", &current_valueto);
861 	}
862 
863 	switch (current_searchtype) {
864 		case SEARCHTYPE_8BIT:
865 			if (current_valuefrom > (u32)0xFF) {
866 				current_valuefrom = 0xFF;
867 			}
868 			if (current_valueto > (u32)0xFF) {
869 				current_valueto = 0xFF;
870 			}
871 			break;
872 
873 		case SEARCHTYPE_16BIT:
874 			if (current_valuefrom > (u32)0xFFFF) {
875 				current_valuefrom = 0xFFFF;
876 			}
877 			if (current_valueto > (u32)0xFFFF) {
878 				current_valueto = 0xFFFF;
879 			}
880 			break;
881 	}
882 
883 	if (current_search == SEARCH_RANGE && current_valuefrom > current_valueto) {
884 		u32 t = current_valuefrom;
885 		current_valuefrom = current_valueto;
886 		current_valueto = t;
887 	}
888 
889 	switch (current_search) {
890 		case SEARCH_EQUALVAL:
891 			switch (current_searchtype) {
892 				case SEARCHTYPE_8BIT:
893 					CheatSearchEqual8((u8)current_valuefrom);
894 					break;
895 
896 				case SEARCHTYPE_16BIT:
897 					CheatSearchEqual16((u16)current_valuefrom);
898 					break;
899 
900 				case SEARCHTYPE_32BIT:
901 					CheatSearchEqual32((u32)current_valuefrom);
902 					break;
903 			}
904 			break;
905 
906 		case SEARCH_NOTEQUALVAL:
907 			switch (current_searchtype) {
908 				case SEARCHTYPE_8BIT:
909 					CheatSearchNotEqual8((u8)current_valuefrom);
910 					break;
911 
912 				case SEARCHTYPE_16BIT:
913 					CheatSearchNotEqual16((u16)current_valuefrom);
914 					break;
915 
916 				case SEARCHTYPE_32BIT:
917 					CheatSearchNotEqual32((u32)current_valuefrom);
918 					break;
919 			}
920 			break;
921 
922 		case SEARCH_RANGE:
923 			switch (current_searchtype) {
924 				case SEARCHTYPE_8BIT:
925 					CheatSearchRange8((u8)current_valuefrom, (u8)current_valueto);
926 					break;
927 
928 				case SEARCHTYPE_16BIT:
929 					CheatSearchRange16((u16)current_valuefrom, (u16)current_valueto);
930 					break;
931 
932 				case SEARCHTYPE_32BIT:
933 					CheatSearchRange32((u32)current_valuefrom, (u32)current_valueto);
934 					break;
935 			}
936 			break;
937 
938 		case SEARCH_INCBY:
939 			switch (current_searchtype) {
940 				case SEARCHTYPE_8BIT:
941 					CheatSearchIncreasedBy8((u8)current_valuefrom);
942 					break;
943 
944 				case SEARCHTYPE_16BIT:
945 					CheatSearchIncreasedBy16((u16)current_valuefrom);
946 					break;
947 
948 				case SEARCHTYPE_32BIT:
949 					CheatSearchIncreasedBy32((u32)current_valuefrom);
950 					break;
951 			}
952 			break;
953 
954 		case SEARCH_DECBY:
955 			switch (current_searchtype) {
956 				case SEARCHTYPE_8BIT:
957 					CheatSearchDecreasedBy8((u8)current_valuefrom);
958 					break;
959 
960 				case SEARCHTYPE_16BIT:
961 					CheatSearchDecreasedBy16((u16)current_valuefrom);
962 					break;
963 
964 				case SEARCHTYPE_32BIT:
965 					CheatSearchDecreasedBy32((u32)current_valuefrom);
966 					break;
967 			}
968 			break;
969 
970 		case SEARCH_INC:
971 			switch (current_searchtype) {
972 				case SEARCHTYPE_8BIT:
973 					CheatSearchIncreased8();
974 					break;
975 
976 				case SEARCHTYPE_16BIT:
977 					CheatSearchIncreased16();
978 					break;
979 
980 				case SEARCHTYPE_32BIT:
981 					CheatSearchIncreased32();
982 					break;
983 			}
984 			break;
985 
986 		case SEARCH_DEC:
987 			switch (current_searchtype) {
988 				case SEARCHTYPE_8BIT:
989 					CheatSearchDecreased8();
990 					break;
991 
992 				case SEARCHTYPE_16BIT:
993 					CheatSearchDecreased16();
994 					break;
995 
996 				case SEARCHTYPE_32BIT:
997 					CheatSearchDecreased32();
998 					break;
999 			}
1000 			break;
1001 
1002 		case SEARCH_DIFFERENT:
1003 			switch (current_searchtype) {
1004 				case SEARCHTYPE_8BIT:
1005 					CheatSearchDifferent8();
1006 					break;
1007 
1008 				case SEARCHTYPE_16BIT:
1009 					CheatSearchDifferent16();
1010 					break;
1011 
1012 				case SEARCHTYPE_32BIT:
1013 					CheatSearchDifferent32();
1014 					break;
1015 			}
1016 			break;
1017 
1018 		case SEARCH_NOCHANGE:
1019 			switch (current_searchtype) {
1020 				case SEARCHTYPE_8BIT:
1021 					CheatSearchNoChange8();
1022 					break;
1023 
1024 				case SEARCHTYPE_16BIT:
1025 					CheatSearchNoChange16();
1026 					break;
1027 
1028 				case SEARCHTYPE_32BIT:
1029 					CheatSearchNoChange32();
1030 					break;
1031 			}
1032 			break;
1033 
1034 		default:
1035 			assert(FALSE); // not possible
1036 			break;
1037 	}
1038 
1039 	UpdateCheatSearchDialog();
1040 }
1041 
1042 // restart the search
OnCheatSearchDlg_RestartClicked(GtkWidget * widget,gpointer user_data)1043 static void OnCheatSearchDlg_RestartClicked(GtkWidget *widget, gpointer user_data) {
1044 	FreeCheatSearchResults();
1045 	FreeCheatSearchMem();
1046 
1047 	current_search = SEARCH_EQUALVAL;
1048 	current_searchtype = SEARCHTYPE_8BIT;
1049 	current_searchbase = SEARCHBASE_DEC;
1050 	current_valuefrom = 0;
1051 	current_valueto = 0;
1052 
1053 	UpdateCheatSearchDialog();
1054 }
1055 
1056 // close the cheat search window
OnCheatSearchDlg_CloseClicked(GtkWidget * widget,gpointer user_data)1057 static void OnCheatSearchDlg_CloseClicked(GtkWidget *widget, gpointer user_data) {
1058 	gtk_widget_destroy(CheatSearchDlg);
1059 	CheatSearchDlg = NULL;
1060 }
1061 
OnCheatSearchDlg_SearchForChanged(GtkWidget * widget,gpointer user_data)1062 static void OnCheatSearchDlg_SearchForChanged(GtkWidget *widget, gpointer user_data) {
1063 	if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) == SEARCH_RANGE) {
1064 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "label_valueto")));
1065 		gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "entry_valueto")));
1066 	}
1067 	else {
1068 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "label_valueto")));
1069 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "entry_valueto")));
1070 	}
1071 
1072 	if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) >= SEARCH_INC) {
1073 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "entry_value")), FALSE);
1074 	}
1075 	else {
1076 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "entry_value")), TRUE);
1077 	}
1078 
1079 	if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) >= SEARCH_INCBY && prevM == NULL) {
1080 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_start")), FALSE);
1081 	}
1082 	else {
1083 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_start")), TRUE);
1084 	}
1085 }
1086 
OnCheatSearchDlg_DataBaseChanged(GtkWidget * widget,gpointer user_data)1087 static void OnCheatSearchDlg_DataBaseChanged(GtkWidget *widget, gpointer user_data) {
1088 	u32				val;
1089 	char			buf[256];
1090 
1091 	if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) == SEARCHBASE_DEC) {
1092 		val = 0;
1093 		sscanf(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_value"))), "%x", &val);
1094 		sprintf(buf, "%u", val);
1095 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_value")), buf);
1096 
1097 		val = 0;
1098 		sscanf(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_valueto"))), "%x", &val);
1099 		sprintf(buf, "%u", val);
1100 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_valueto")), buf);
1101 	}
1102 	else {
1103 		val = 0;
1104 		sscanf(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_value"))), "%u", &val);
1105 		sprintf(buf, "%X", val);
1106 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_value")), buf);
1107 
1108 		val = 0;
1109 		sscanf(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_valueto"))), "%u", &val);
1110 		sprintf(buf, "%X", val);
1111 		gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "entry_valueto")), buf);
1112 	}
1113 }
1114 
CheatSearch_TreeSelectionChanged(GtkTreeSelection * selection,gpointer user_data)1115 static void CheatSearch_TreeSelectionChanged(GtkTreeSelection *selection, gpointer user_data) {
1116 	if (GetSelectedResultIndex() != -1) {
1117 		// If a row was selected, we can now enable some of the disabled widgets
1118 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_freeze")), TRUE);
1119 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_modify")), TRUE);
1120 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_copy")), TRUE);
1121 	} else {
1122 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_freeze")), FALSE);
1123 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_modify")), FALSE);
1124 		gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "btn_copy")), FALSE);
1125 	}
1126 }
1127 
1128 // run the cheat search dialog
RunCheatSearchDialog()1129 void RunCheatSearchDialog() {
1130 	GtkWidget *widget;
1131 	GtkCellRenderer *renderer;
1132 	GtkTreeSelection *treesel;
1133 	GtkTreeViewColumn *column;
1134 
1135 	builder = gtk_builder_new();
1136 
1137 	if (!gtk_builder_add_from_resource(builder, "/org/pcsxr/gui/pcsxr.ui", NULL)) {
1138 		g_warning("Error: interface could not be loaded!");
1139 		return;
1140 	}
1141 
1142 	CheatSearchDlg = GTK_WIDGET(gtk_builder_get_object(builder, "CheatSearchDlg"));
1143 
1144 	gtk_window_set_title(GTK_WINDOW(CheatSearchDlg), _("Cheat Search"));
1145 	gtk_widget_show (CheatSearchDlg);
1146 
1147 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "GtkCList_Result"));
1148 
1149 	renderer = gtk_cell_renderer_text_new ();
1150 	column = gtk_tree_view_column_new_with_attributes(_("Search Results"),
1151 		renderer, "text", 0, NULL);
1152 	gtk_tree_view_append_column(GTK_TREE_VIEW(widget), column);
1153 
1154 	treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
1155 	gtk_tree_selection_set_mode (treesel, GTK_SELECTION_SINGLE);
1156 	g_signal_connect_data(G_OBJECT(treesel), "changed",
1157 						  G_CALLBACK(CheatSearch_TreeSelectionChanged),
1158 						  NULL, NULL, G_CONNECT_AFTER);
1159 
1160 	UpdateCheatSearchDialog();
1161 
1162 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "btn_freeze"));
1163 	g_signal_connect_data(G_OBJECT(widget), "clicked",
1164 		G_CALLBACK(OnCheatSearchDlg_FreezeClicked), builder, NULL, G_CONNECT_AFTER);
1165 
1166 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "btn_modify"));
1167 	g_signal_connect_data(G_OBJECT(widget), "clicked",
1168 		G_CALLBACK(OnCheatSearchDlg_ModifyClicked), builder, NULL, G_CONNECT_AFTER);
1169 
1170 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "btn_copy"));
1171 	g_signal_connect_data(G_OBJECT(widget), "clicked",
1172 		G_CALLBACK(OnCheatSearchDlg_CopyClicked), builder, NULL, G_CONNECT_AFTER);
1173 
1174 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "btn_start"));
1175 	g_signal_connect_data(G_OBJECT(widget), "clicked",
1176 		G_CALLBACK(OnCheatSearchDlg_SearchClicked), builder, NULL, G_CONNECT_AFTER);
1177 
1178 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "btn_restart"));
1179 	g_signal_connect_data(G_OBJECT(widget), "clicked",
1180 		G_CALLBACK(OnCheatSearchDlg_RestartClicked), builder, NULL, G_CONNECT_AFTER);
1181 
1182 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "combo_searchfor"));
1183 	g_signal_connect_data(G_OBJECT(widget), "changed",
1184 		G_CALLBACK(OnCheatSearchDlg_SearchForChanged), builder, NULL, G_CONNECT_AFTER);
1185 
1186 	widget = GTK_WIDGET(gtk_builder_get_object(builder, "combo_database"));
1187 	g_signal_connect_data(G_OBJECT(widget), "changed",
1188 		G_CALLBACK(OnCheatSearchDlg_DataBaseChanged), builder, NULL, G_CONNECT_AFTER);
1189 
1190 	g_signal_connect_data(G_OBJECT(CheatSearchDlg), "response",
1191 		G_CALLBACK(OnCheatSearchDlg_CloseClicked), builder, (GClosureNotify)g_object_unref, G_CONNECT_AFTER);
1192 }
1193