1 /** \file uivsidmenu.c
2 * \brief Native GTK3 menus for the SID player, vsid
3 *
4 * \author Marcus Sutton <loggedoubt@gmail.com>
5 * \author Bas Wassink <b.wassink@ziggo.nl>
6 */
7
8 /*
9 * $VICERES PSIDKeepEnv vsid
10 * $VICERES MainCPU_TRACE vsid
11 * $VICERES DoCoreDump vsid
12 */
13
14 /*
15 * This file is part of VICE, the Versatile Commodore Emulator.
16 * See README for copyright notice.
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
31 * 02111-1307 USA.
32 *
33 */
34
35
36 #include "vice.h"
37
38 #include <stdlib.h>
39 #include <gtk/gtk.h>
40
41 #include "debug.h"
42 #include "lib.h"
43 #include "machine.h"
44 #include "psid.h"
45 #include "ui.h"
46 #include "uiabout.h"
47 #include "uicmdline.h"
48 #include "uicommands.h"
49 #include "uicompiletimefeatures.h"
50 #include "uidebug.h"
51 #include "uimedia.h"
52 #include "uimenu.h"
53 #include "uimonarch.h"
54 #include "uisettings.h"
55 #include "uisidattach.h"
56 #include "uismartattach.h"
57 #include "uivsidmenu.h"
58
59
60 /*
61 * The following are translation unit local so we can create functions that
62 * modify menu contents or even functions that alter the top bar itself.
63 */
64
65
66 /** \brief Main menu bar widget
67 *
68 * Contains the submenus on the menu main bar
69 *
70 * This one lives until ui_exit() or thereabouts
71 */
72 static GtkWidget *main_menu_bar = NULL;
73
74
75 /** \brief File submenu
76 */
77 static GtkWidget *file_submenu = NULL;
78
79
80 /** \brief Tune submenu
81 */
82 static GtkWidget *tune_submenu = NULL;
83
84
85 /** \brief Settings submenu
86 */
87 static GtkWidget *settings_submenu = NULL;
88
89
90 #ifdef DEBUG
91 /** \brief Debug submenu, only available when --enable-debug was specified
92 */
93 static GtkWidget *debug_submenu = NULL;
94 #endif
95
96
97 /** \brief Help submenu
98 */
99 static GtkWidget *help_submenu = NULL;
100
101
102 /** \brief List of items in the tune submenu
103 */
104 static GSList *tune_submenu_group = NULL;
105
106
107 /** \brief File->Reset submenu
108 */
109 static ui_menu_item_t reset_submenu[] = {
110 { "Soft reset", UI_MENU_TYPE_ITEM_ACTION,
111 "reset-soft", ui_machine_reset_callback, GINT_TO_POINTER(MACHINE_RESET_MODE_SOFT),
112 GDK_KEY_F9, VICE_MOD_MASK },
113 { "Hard reset", UI_MENU_TYPE_ITEM_ACTION,
114 "reset-hard", ui_machine_reset_callback, GINT_TO_POINTER(MACHINE_RESET_MODE_HARD),
115 GDK_KEY_F12, VICE_MOD_MASK },
116
117 UI_MENU_TERMINATOR
118 };
119
120
121 /** \brief 'File' menu
122 */
123 static ui_menu_item_t file_menu[] = {
124 { "Load PSID file ...", UI_MENU_TYPE_ITEM_ACTION,
125 "load-psid", uisidattach_show_dialog, NULL,
126 GDK_KEY_L, VICE_MOD_MASK },
127
128 UI_MENU_SEPARATOR,
129
130 /* XXX: this item might need its own dialog that only
131 * contains sound recording options
132 */
133 { "Record sound file ...", UI_MENU_TYPE_ITEM_ACTION,
134 "sound-save", uimedia_dialog_show, NULL,
135 GDK_KEY_R, VICE_MOD_MASK | GDK_SHIFT_MASK },
136
137 { "Stop sound recording", UI_MENU_TYPE_ITEM_ACTION,
138 "sound-stop", (void *)uimedia_stop_recording, NULL,
139 GDK_KEY_S, VICE_MOD_MASK | GDK_SHIFT_MASK },
140
141 UI_MENU_SEPARATOR,
142
143 /* monitor */
144 { "Activate monitor", UI_MENU_TYPE_ITEM_ACTION,
145 "monitor", ui_monitor_activate_callback, NULL,
146 #ifdef MACOSX_SUPPORT
147 /* use Command-Option-M on Mac */
148 GDK_KEY_M, VICE_MOD_MASK | GDK_MOD1_MASK
149 #else
150 GDK_KEY_H, VICE_MOD_MASK
151 #endif
152 },
153
154 UI_MENU_SEPARATOR,
155
156 { "Reset", UI_MENU_TYPE_SUBMENU,
157 NULL, NULL, reset_submenu,
158 0, 0 },
159
160 UI_MENU_SEPARATOR,
161
162 { "Exit player", UI_MENU_TYPE_ITEM_ACTION,
163 "exit", ui_close_callback, NULL,
164 GDK_KEY_Q, VICE_MOD_MASK },
165
166 UI_MENU_TERMINATOR
167 };
168
169
170 /** \brief 'Tune' menu
171 */
172 #if 0
173 static ui_menu_item_t tune_menu[] = {
174
175 UI_MENU_TERMINATOR
176 };
177 #endif
178
179
180 /** \brief 'Settings' menu
181 */
182 static ui_menu_item_t settings_menu[] = {
183 /* XXX: this item should perhaps be removed and its functionality
184 * added to the settings dialog
185 */
186 { "Override PSID settings", UI_MENU_TYPE_ITEM_CHECK,
187 "psid-keep-env", (void *)(ui_toggle_resource), (void *)"PSIDKeepEnv",
188 0, 0 },
189
190 UI_MENU_SEPARATOR,
191
192 /* the settings dialog */
193 { "Settings ...", UI_MENU_TYPE_ITEM_ACTION,
194 "settings", (void *)ui_settings_dialog_create, NULL,
195 GDK_KEY_O, VICE_MOD_MASK },
196
197 UI_MENU_TERMINATOR
198 };
199
200
201 /** \brief 'Debug' menu items
202 */
203 #ifdef DEBUG
204 static ui_menu_item_t debug_menu[] = {
205 { "Trace mode ...", UI_MENU_TYPE_ITEM_ACTION,
206 "tracemode", uidebug_trace_mode_callback, NULL,
207 0, 0 },
208
209 UI_MENU_SEPARATOR,
210
211 { "Main CPU trace", UI_MENU_TYPE_ITEM_CHECK,
212 "trace-maincpu", (void *)(ui_toggle_resource), (void *)"MainCPU_TRACE",
213 0, 0 },
214
215 UI_MENU_SEPARATOR,
216
217
218 { "Autoplay playback frames ...", UI_MENU_TYPE_ITEM_ACTION,
219 "playframes", uidebug_playback_frames_callback, NULL,
220 0, 0 },
221 { "Save core dump", UI_MENU_TYPE_ITEM_CHECK,
222 "coredump", (void *)(ui_toggle_resource), (void *)"DoCoreDump",
223 0, 0 },
224
225 UI_MENU_TERMINATOR
226 };
227 #endif
228
229
230 /** \brief 'Help' menu items
231 */
232 static ui_menu_item_t help_menu[] = {
233 { "Browse manual", UI_MENU_TYPE_ITEM_ACTION,
234 "manual", ui_open_manual_callback, NULL,
235 0, 0 },
236 { "Command line options ...", UI_MENU_TYPE_ITEM_ACTION,
237 "cmdline", uicmdline_dialog_show, NULL,
238 0, 0 },
239 { "Compile time features ...", UI_MENU_TYPE_ITEM_ACTION,
240 "features", uicompiletimefeatures_dialog_show, NULL,
241 0, 0 },
242 { "About VICE", UI_MENU_TYPE_ITEM_ACTION,
243 "about", ui_about_dialog_callback, NULL,
244 0, 0 },
245
246 UI_MENU_TERMINATOR
247 };
248
249 /** \brief Play a tune when selected with the Tune menu
250 *
251 * \return void
252 */
select_tune_from_menu(GtkMenuItem * menuitem,gpointer user_data)253 static void select_tune_from_menu(GtkMenuItem *menuitem,
254 gpointer user_data) {
255 int tune;
256
257 if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) {
258 return;
259 }
260 tune = GPOINTER_TO_INT(user_data);
261 psid_init_driver();
262 machine_play_psid(tune);
263 machine_trigger_reset(MACHINE_RESET_MODE_SOFT);
264 }
265
266
267 /** \brief Remove each of the old menu items before adding the new ones
268 *
269 * \return void
270 */
remove_item_from_menu(GtkWidget * widget,gpointer data)271 static void remove_item_from_menu (GtkWidget *widget, gpointer data) {
272 gtk_widget_destroy(widget);
273 }
274
275 /** \brief Create the tune menu when a new PSID is loaded
276 *
277 * \return void
278 */
ui_vsid_tune_menu_set_tune_count(int count)279 void ui_vsid_tune_menu_set_tune_count(int count) {
280 GtkWidget *item = NULL;
281 long i;
282 char *buf;
283
284 gtk_container_foreach(GTK_CONTAINER(tune_submenu), remove_item_from_menu, NULL);
285 for (i = count; i >0; i--) {
286 buf = lib_msprintf("Tune %s%d", i < 10 ? "_" :"", i);
287 item = gtk_radio_menu_item_new_with_mnemonic_from_widget (GTK_RADIO_MENU_ITEM(item), buf);
288 lib_free(buf);
289 gtk_widget_show(item);
290 g_signal_connect(
291 item,
292 "activate",
293 G_CALLBACK(select_tune_from_menu),
294 GINT_TO_POINTER(i));
295 gtk_menu_shell_prepend(GTK_MENU_SHELL(tune_submenu), item);
296 }
297 tune_submenu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
298 }
299
300
301 /** \brief Ensure the correct menu element is selected when the current tune is changed by anything other than the menu
302 *
303 * \return void
304 */
ui_vsid_tune_set_tune_current(int count)305 void ui_vsid_tune_set_tune_current(int count) {
306 if (tune_submenu_group) {
307 gpointer nth_item = g_slist_nth_data(tune_submenu_group, (guint)count - 1);
308 if (nth_item) {
309 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM (nth_item), TRUE);
310 }
311 }
312 }
313
314 /** \brief Create the top menu bar with standard submenus
315 *
316 * \return GtkMenuBar
317 */
ui_vsid_menu_bar_create(void)318 GtkWidget *ui_vsid_menu_bar_create(void)
319 {
320 GtkWidget *menu_bar;
321
322 /* create the top menu bar */
323 menu_bar = gtk_menu_bar_new();
324
325 /* create the top-level 'File' menu */
326 file_submenu = ui_menu_submenu_create(menu_bar, "File");
327
328 /* create the top-level 'Tune' menu */
329 tune_submenu = ui_menu_submenu_create(menu_bar, "Tune");
330
331 /* create the top-level 'Settings' menu */
332 settings_submenu = ui_menu_submenu_create(menu_bar, "Settings");
333
334 #ifdef DEBUG
335 /* create the top-level 'Debug' menu (when --enable-debug is used) */
336 debug_submenu = ui_menu_submenu_create(menu_bar, "Debug");
337 #endif
338
339 /* create the top-level 'Help' menu */
340 help_submenu = ui_menu_submenu_create(menu_bar, "Help");
341
342
343 /* add items to the File menu */
344 ui_menu_add(file_submenu, file_menu);
345
346 #if 0
347 /* TODO: add items to the Tune menu */
348 ui_menu_add(tune_submenu, tune_menu);
349 #endif
350
351 /* add items to the Settings menu */
352 ui_menu_add(settings_submenu, settings_menu);
353
354 #ifdef DEBUG
355 /* add items to the Debug menu */
356 ui_menu_add(debug_submenu, debug_menu);
357 #endif
358
359 /* add items to the Help menu */
360 ui_menu_add(help_submenu, help_menu);
361
362 main_menu_bar = menu_bar; /* XXX: do I need g_object_ref()/g_object_unref()
363 for this */
364 return menu_bar;
365 }
366