1 /** \file uifliplist.c
2 * \brief Fliplist menu management
3 *
4 * \author Michael C. Martin <mcmartin@gmail.com>
5 */
6
7 /*
8 * This file is part of VICE, the Versatile Commodore Emulator.
9 * See README for copyright notice.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA.
25 */
26
27
28 #include "vice.h"
29
30 #include "attach.h"
31 #include "fliplist.h"
32 #include "lib.h"
33 #include "util.h"
34 #include "filechooserhelpers.h"
35 #include "ui.h"
36
37 #include "uifliplist.h"
38
ui_fliplist_add_current_cb(GtkWidget * widget,gpointer data)39 void ui_fliplist_add_current_cb(GtkWidget *widget, gpointer data)
40 {
41 int unit = GPOINTER_TO_INT(data);
42 fliplist_add_image(unit);
43 }
44
ui_fliplist_remove_current_cb(GtkWidget * widget,gpointer data)45 void ui_fliplist_remove_current_cb(GtkWidget *widget, gpointer data)
46 {
47 int unit = GPOINTER_TO_INT(data);
48 fliplist_remove(unit, NULL);
49 }
50
ui_fliplist_next_cb(GtkWidget * widget,gpointer data)51 void ui_fliplist_next_cb(GtkWidget *widget, gpointer data)
52 {
53 int unit = GPOINTER_TO_INT(data);
54 fliplist_attach_head(unit, 1);
55 }
56
ui_fliplist_prev_cb(GtkWidget * widget,gpointer data)57 void ui_fliplist_prev_cb(GtkWidget *widget, gpointer data)
58 {
59 int unit = GPOINTER_TO_INT(data);
60 fliplist_attach_head(unit, 0);
61 }
62
ui_fliplist_select_cb(GtkWidget * widget,gpointer data)63 static void ui_fliplist_select_cb(GtkWidget *widget, gpointer data)
64 {
65 int unit = GPOINTER_TO_INT(data) & 0xff;
66 int index = (GPOINTER_TO_INT(data) >> 8) & 0xff;
67 int i;
68 if (index == 0) {
69 fliplist_t list = fliplist_init_iterate(unit);
70 const char *image = fliplist_get_image(list);
71 file_system_attach_disk(unit, image);
72 } else {
73 for (i = 0; i < index; ++i) {
74 fliplist_attach_head(unit, 1);
75 }
76 }
77 }
78
79 /** \brief Fill in a menu with controls for fliplist control.
80 *
81 * Fliplist controls are placed at the end of a menu, after a
82 * separator. Any previously-existing fliplist controls within the
83 * menu will be removed.
84 *
85 * \param menu The menu to be edited.
86 * \param unit The drive unit (8-11) that this menu
87 * will control.
88 * \param separator_count The number of menu separators in the
89 * part of the menu that does not involve
90 * the fliplist.
91 */
ui_populate_fliplist_menu(GtkWidget * menu,int unit,int separator_count)92 void ui_populate_fliplist_menu(GtkWidget *menu, int unit, int separator_count)
93 {
94 const char *fliplist_string;
95 GtkWidget *menu_item;
96 GList *children = gtk_container_get_children(GTK_CONTAINER(menu));
97 GList *child_iter = g_list_first(children);
98 int separators_so_far = 0;
99 while (child_iter) {
100 if (GTK_IS_SEPARATOR_MENU_ITEM(child_iter->data)) {
101 ++separators_so_far;
102 }
103 if (separators_so_far > separator_count) {
104 gtk_container_remove(GTK_CONTAINER(menu), child_iter->data);
105 }
106 child_iter = child_iter->next;
107 }
108 g_list_free(children);
109
110 /* Fliplist controls in GTK2/GNOME are next/previous and then the
111 * full list of entries within it. For GTK3 we only show these if
112 * the fliplist isn't empty for this drive. */
113 /* TODO: Add/Remove current image to/from fliplist should really
114 * be here too. */
115 fliplist_string = fliplist_get_next(unit);
116 if (fliplist_string) {
117 char buf[128];
118 char *basename = NULL;
119 fliplist_t fliplist_iterator;
120 int index;
121 gtk_container_add(GTK_CONTAINER(menu), gtk_separator_menu_item_new());
122 util_fname_split(fliplist_string, NULL, &basename);
123 snprintf(buf, 128, "Next: %s", basename ? basename : fliplist_string);
124 lib_free(basename);
125 basename = NULL;
126 buf[127] = 0;
127 menu_item = gtk_menu_item_new_with_label(buf);
128 g_signal_connect(menu_item, "activate", G_CALLBACK(ui_fliplist_next_cb), GINT_TO_POINTER(unit));
129 gtk_container_add(GTK_CONTAINER(menu), menu_item);
130 fliplist_string = fliplist_get_prev(unit);
131 if (fliplist_string) {
132 util_fname_split(fliplist_string, NULL, &basename);
133 snprintf(buf, 128, "Previous: %s", basename ? basename : fliplist_string);
134 lib_free(basename);
135 basename = NULL;
136 buf[127] = 0;
137 menu_item = gtk_menu_item_new_with_label(buf);
138 g_signal_connect(menu_item, "activate", G_CALLBACK(ui_fliplist_prev_cb), GINT_TO_POINTER(unit));
139 gtk_container_add(GTK_CONTAINER(menu), menu_item);
140 }
141 gtk_container_add(GTK_CONTAINER(menu), gtk_separator_menu_item_new());
142 fliplist_iterator = fliplist_init_iterate(unit);
143 index = 0;
144 while (fliplist_iterator) {
145 fliplist_string = fliplist_get_image(fliplist_iterator);
146 util_fname_split(fliplist_string, NULL, &basename);
147 menu_item = gtk_menu_item_new_with_label(basename ? basename : fliplist_string);
148 lib_free(basename);
149 basename = NULL;
150 g_signal_connect(menu_item, "activate", G_CALLBACK(ui_fliplist_select_cb), GINT_TO_POINTER(unit+(index << 8)));
151 gtk_container_add(GTK_CONTAINER(menu), menu_item);
152 fliplist_iterator = fliplist_next_iterate(unit);
153 ++index;
154 }
155 }
156 }
157
fliplist_load_response(GtkWidget * widget,gint response_id,gpointer user_data)158 static void fliplist_load_response(GtkWidget *widget, gint response_id, gpointer user_data)
159 {
160 int unit = GPOINTER_TO_INT(user_data);
161 gchar *filename;
162 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
163 if (response_id == GTK_RESPONSE_ACCEPT) {
164 /* TODO: read autoattach out of an extra widget. */
165 /* TODO: Autoattach looks slightly buggy in fliplist.c */
166 fliplist_load_list(unit, filename, 0);
167 }
168 gtk_widget_destroy(widget);
169 }
170
171 /** \brief Create and show the "load fliplist" dialog.
172 *
173 * \param parent Widget that sent the event
174 * \param data Drive to load fliplist to, or FLIPLIST_ALL_UNITS
175 */
ui_fliplist_load_callback(GtkWidget * parent,gpointer data)176 void ui_fliplist_load_callback(GtkWidget *parent, gpointer data)
177 {
178 GtkWidget *dialog;
179 unsigned int unit = (unsigned int)GPOINTER_TO_INT(data);
180 if (unit != FLIPLIST_ALL_UNITS && (unit < 8 || unit > 11)) {
181 return;
182 }
183 dialog = gtk_file_chooser_dialog_new(
184 "Select flip list file",
185 ui_get_active_window(),
186 GTK_FILE_CHOOSER_ACTION_OPEN,
187 /* buttons */
188 "Open", GTK_RESPONSE_ACCEPT,
189 "Cancel", GTK_RESPONSE_REJECT,
190 NULL, NULL);
191 /* TODO: add a separate "extra widget" that will let the user
192 * select autoattach */
193 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),
194 create_file_chooser_filter(file_chooser_filter_fliplist, FALSE));
195 g_signal_connect(dialog, "response", G_CALLBACK(fliplist_load_response), data);
196 gtk_widget_show_all(dialog);
197 }
198
fliplist_save_response(GtkWidget * widget,gint response_id,gpointer user_data)199 static void fliplist_save_response(GtkWidget *widget, gint response_id, gpointer user_data)
200 {
201 int unit = GPOINTER_TO_INT(user_data);
202 gchar *filename;
203 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
204 if (response_id == GTK_RESPONSE_ACCEPT) {
205 fliplist_save_list(unit, filename);
206 }
207 gtk_widget_destroy(widget);
208 }
209
210 /** \brief Create and show the "save fliplist" dialog.
211 *
212 * \param parent Widget that sent the event
213 * \param data Drive to save fliplist from, or FLIPLIST_ALL_UNITS
214 */
ui_fliplist_save_callback(GtkWidget * parent,gpointer data)215 void ui_fliplist_save_callback(GtkWidget *parent, gpointer data)
216 {
217 GtkWidget *dialog;
218 unsigned int unit = (unsigned int)GPOINTER_TO_INT(data);
219 if (unit != FLIPLIST_ALL_UNITS && (unit < 8 || unit > 11)) {
220 return;
221 }
222 dialog = gtk_file_chooser_dialog_new(
223 "Select flip list file",
224 ui_get_active_window(),
225 GTK_FILE_CHOOSER_ACTION_SAVE,
226 /* buttons */
227 "Save", GTK_RESPONSE_ACCEPT,
228 "Cancel", GTK_RESPONSE_REJECT,
229 NULL, NULL);
230 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),
231 create_file_chooser_filter(file_chooser_filter_fliplist, FALSE));
232 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
233 g_signal_connect(dialog, "response", G_CALLBACK(fliplist_save_response), data);
234 gtk_widget_show_all(dialog);
235 }
236