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                 &current, 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