1 /** \file videopalettewidget.c
2 * \brief Widget to select palette
3 *
4 * \author Bas Wassink <b.wassink@ziggo.nl>
5 */
6
7 /*
8 * FIXME: Note sure x64dtv here:
9 *
10 * $VICERES CrtcPaletteFile xpet xcbm2
11 * $VICERES CrtcExternalPaelette xpet xcbm2
12 * $VICEREs TEDPaletteFile xplus4
13 * $VICERES TEDExternalPalette xplu4
14 * $VICERES VDCPaletteFile x128
15 * $VICERES VDCExternalPalette x128
16 * $VICERES VICPaletteFile xvic
17 * $VICERES VICExternalPalette xvic
18 * $VICERES VICIIPaletteFile x64 x64sc xscpu64 xd64tv xcbm5x0
19 * $VICERES VICIIExternalPalette x64 x64sc xscpu64 xd64tv xcbm5x0
20 */
21
22 /*
23 * This file is part of VICE, the Versatile Commodore Emulator.
24 * See README for copyright notice.
25 *
26 * This program is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published by
28 * the Free Software Foundation; either version 2 of the License, or
29 * (at your option) any later version.
30 *
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
35 *
36 * You should have received a copy of the GNU General Public License
37 * along with this program; if not, write to the Free Software
38 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
39 * 02111-1307 USA.
40 *
41 */
42
43 #include "vice.h"
44
45 #include <gtk/gtk.h>
46 #include <string.h>
47
48 #include "debug_gtk3.h"
49 #include "widgethelpers.h"
50 #include "openfiledialog.h"
51 #include "resources.h"
52 #include "palette.h"
53
54 #include "videopalettewidget.h"
55
56
57 /** \brief video chip prefix, used to construct proper resource names
58 */
59 static const char *chip_prefix = NULL;
60
61
62 static GtkWidget *radio_internal = NULL;
63 static GtkWidget *radio_external = NULL;
64 static GtkWidget *combo_external = NULL;
65 static GtkWidget *button_custom = NULL;
66
67
68 /** \brief Handler for the "toggled" events of the internal/external radios
69 *
70 * \param[in] radio Internal/External radio button
71 * \param[in] data setting (bool)
72 */
on_internal_toggled(GtkWidget * radio,gpointer data)73 static void on_internal_toggled(GtkWidget *radio, gpointer data)
74 {
75 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio))) {
76 resources_set_int_sprintf("%sExternalPalette", GPOINTER_TO_INT(data),
77 chip_prefix);
78 }
79 }
80
81
82 /** \brief Handler for the "changed" event of the palettes combo box
83 *
84 * \param[in] combo combo box
85 * \param[in] user_data extra event data (unused)
86 */
on_combo_changed(GtkComboBox * combo,gpointer user_data)87 static void on_combo_changed(GtkComboBox *combo, gpointer user_data)
88 {
89 #ifdef HAVE_DEBUG_GTK3UI
90 int index = gtk_combo_box_get_active(combo);
91 #endif
92 const char *id = gtk_combo_box_get_active_id(combo);
93
94 debug_gtk3("got combo index %d, id '%s'.", index, id);
95 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_external), TRUE);
96 resources_set_string_sprintf("%sPaletteFile", id, chip_prefix);
97 resources_set_int_sprintf("%sExternalPalette", 1, chip_prefix);
98
99 }
100
101
102 /** \brief Handler for the "clicked" event of the "browse ..." button
103 *
104 * Opens a custom palette file and adds the file name to the combo box.
105 *
106 * \param[in] button browse button (unused)
107 * \param[in] user_data extra event data (unused)
108 */
on_browse_clicked(GtkButton * button,gpointer user_data)109 static void on_browse_clicked(GtkButton *button, gpointer user_data)
110 {
111 gchar *filename;
112 const char *flist[] = { "*.vpl", NULL };
113
114 filename = vice_gtk3_open_file_dialog("Open palette file",
115 "Palette files", flist, NULL);
116 if (filename != NULL) {
117 debug_gtk3("got palette file '%s'.", filename);
118 resources_set_string_sprintf("%sPaletteFile", filename, chip_prefix);
119
120 /* add to combo box */
121 gtk_combo_box_text_insert(GTK_COMBO_BOX_TEXT(combo_external), 0,
122 filename, filename);
123 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_external), 0);
124
125 g_free(filename);
126 }
127 }
128
129
130 /** \brief Create combo box with available palettes for the current chip
131 *
132 * If the file in the resource "${chip}PaletteFile" doesn't match any of the
133 * palette files provided by VICE, it is assumed to be a user-defined custom
134 * palette and inserted at the top of the combo box.
135 *
136 * \return GtkComboBoxText
137 */
create_combo_box(void)138 static GtkWidget *create_combo_box(void)
139 {
140 GtkWidget *combo;
141 int index;
142 palette_info_t *list;
143 int row;
144 const char *current;
145 gboolean found = FALSE;
146
147 if (resources_get_string_sprintf("%sPaletteFile",
148 ¤t, chip_prefix) < 0) {
149 current = NULL;
150 }
151
152 row = 0;
153 list = palette_get_info_list();
154 combo = gtk_combo_box_text_new();
155 for (index = 0; list[index].chip != NULL; index++) {
156 if (strcmp(list[index].chip, chip_prefix) == 0) {
157 /* got a valid entry */
158 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(combo),
159 list[index].file, list[index].name);
160 if (current != NULL && strcmp(list[index].file, current) == 0) {
161 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), row);
162 found = TRUE;
163 }
164 row++;
165 }
166 }
167
168 /* if we didn't find `current` in the list of VICE palette files, add it as
169 * a custom user-defined file */
170 if ((!found) && current != NULL) {
171 gtk_combo_box_text_insert(GTK_COMBO_BOX_TEXT(combo), 0, current, current);
172 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
173 }
174
175 g_signal_connect(combo, "changed", G_CALLBACK(on_combo_changed), NULL);
176 return combo;
177 }
178
179
180 /** \brief Create "browse ..." button to select a palette file
181 *
182 * \return GtkButton
183 */
create_browse_button(void)184 static GtkWidget *create_browse_button(void)
185 {
186 GtkWidget *button;
187
188 button = gtk_button_new_with_label("Browse ...");
189 g_signal_connect(button, "clicked", G_CALLBACK(on_browse_clicked), NULL);
190 return button;
191 }
192
193
194 /** \brief Create video palette widget
195 *
196 * \param[in] chip chip name (used as prefix for resources)
197 *
198 * \return GtkGrid
199 */
video_palette_widget_create(const char * chip)200 GtkWidget *video_palette_widget_create(const char *chip)
201 {
202 GtkWidget *grid;
203 GSList *group = NULL;
204 int external;
205
206 chip_prefix = chip;
207
208 resources_get_int_sprintf("%sExternalPalette", &external, chip);
209 debug_gtk3("%sExternalPalette is %s.", chip, external ? "ON" : "OFF");
210
211 grid = vice_gtk3_grid_new_spaced_with_label(-1, -1, "Palette settings", 4);
212
213 radio_internal = gtk_radio_button_new_with_label(group, "Internal");
214 g_object_set(radio_internal, "margin-left", 16, NULL);
215 radio_external = gtk_radio_button_new_with_label(group, "External");
216 gtk_radio_button_join_group(
217 GTK_RADIO_BUTTON(radio_external),
218 GTK_RADIO_BUTTON(radio_internal));
219
220 combo_external = create_combo_box();
221 gtk_widget_set_hexpand(combo_external, TRUE);
222 button_custom = create_browse_button();
223
224 gtk_grid_attach(GTK_GRID(grid), radio_internal, 0, 1, 1, 1);
225 gtk_grid_attach(GTK_GRID(grid), radio_external, 1, 1, 1, 1);
226 gtk_grid_attach(GTK_GRID(grid), combo_external, 2, 1, 1, 1);
227 gtk_grid_attach(GTK_GRID(grid), button_custom, 3, 1, 1, 1);
228
229 if (external) {
230 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_external), TRUE);
231 } else {
232 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_internal), TRUE);
233 }
234
235 g_signal_connect(radio_internal, "toggled",
236 G_CALLBACK(on_internal_toggled), GINT_TO_POINTER(0));
237 g_signal_connect(radio_external, "toggled",
238 G_CALLBACK(on_internal_toggled), GINT_TO_POINTER(1));
239
240 gtk_widget_show_all(grid);
241 return grid;
242 }
243