Merge pull request #252 from rakslice/gtk2_gui_cdrom

GTK2 GUIs: Add management of cdrom prefs entries in the volumes list
This commit is contained in:
kanjitalk755 2025-01-23 14:22:28 +09:00 committed by GitHub
commit 618419ff0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 903 additions and 80 deletions

View File

@ -30,6 +30,7 @@
#include <net/if_arp.h>
#include <cerrno>
#include <fstream>
#include "user_strings.h"
#include "version.h"
@ -56,6 +57,8 @@ static void create_serial_pane(GtkWidget *top);
static void create_memory_pane(GtkWidget *top);
static void create_jit_pane(GtkWidget *top);
static void read_settings(void);
static void add_volume_entry_with_type(const char * filename, bool cdrom);
static void add_volume_entry_guessed(const char * filename);
/*
@ -69,8 +72,11 @@ static void read_settings(void);
#endif
struct opt_desc {
opt_desc(int l, GCallback f, GtkWidget **s=NULL) : label_id(l), func(f), save_ref(s) {}
int label_id;
GtkSignalFunc func;
GtkWidget ** save_ref;
};
struct combo_desc {
@ -176,6 +182,9 @@ static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *bu
gtk_widget_show(button);
g_signal_connect_object(button, "clicked", buttons->func, NULL, (GConnectFlags) 0);
gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
if (buttons->save_ref) {
*(buttons->save_ref) = button;
}
buttons++;
}
return bb;
@ -534,14 +543,46 @@ bool PrefsEditor(void)
*/
static GtkWidget *volume_list, *w_extfs;
static int selected_volume;
static GtkListStore *volume_list_model;
static GtkWidget *volume_remove_button;
// Volume in list selected
static void cl_selected(GtkWidget *list, int row, int column)
{
selected_volume = row;
// Volume list selection changed
static void cl_selected(GtkTreeSelection * selection, gpointer user_data) {
if (selection) {
bool have_selection = gtk_tree_selection_get_selected(selection, NULL, NULL);
gtk_widget_set_sensitive(GTK_WIDGET(volume_remove_button), have_selection);
}
}
// Process proposed drop
gboolean volume_list_drag_motion (GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, guint time,
gpointer user_data)
{
GtkTreePath *path;
GtkTreeViewDropPosition pos;
// Don't allow tree-style drops onto, only list-style drops between
if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(volume_list), x,y, &path, &pos)) {
switch (pos) {
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(volume_list), path, GTK_TREE_VIEW_DROP_AFTER);
break;
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(volume_list), path, GTK_TREE_VIEW_DROP_BEFORE);
break;
case GTK_TREE_VIEW_DROP_BEFORE:
case GTK_TREE_VIEW_DROP_AFTER:
// these are ok, no change
break;
}
gdk_drag_status(drag_context, drag_context->suggested_action, time);
return TRUE;
}
return FALSE;
}
// Something dropped on volume list
static void drag_data_received(GtkWidget *list, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data,
guint info, guint time, gpointer user_data)
@ -559,7 +600,36 @@ static void drag_data_received(GtkWidget *list, GdkDragContext *drag_context, gi
gchar * filename = g_filename_from_uri(*uri, NULL, NULL);
if (filename) {
gtk_clist_append(GTK_CLIST(volume_list), &filename);
add_volume_entry_guessed(filename);
// figure out where in the list they dropped
GtkTreePath *path;
GtkTreeViewDropPosition pos;
if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(volume_list), x,y, &path, &pos)) {
GtkTreeIter dest_iter;
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(volume_list_model), &dest_iter, path)) {
// Find the item we just added and put it in place
GtkTreeIter last;
GtkTreeIter cur;
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(volume_list_model), &cur)) {
do {
last = cur;
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &cur));
}
switch (pos) {
case GTK_TREE_VIEW_DROP_AFTER:
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
gtk_list_store_move_after(volume_list_model, &last, &dest_iter);
break;
case GTK_TREE_VIEW_DROP_BEFORE:
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
gtk_list_store_move_before(volume_list_model, &last, &dest_iter);
break;
}
}
}
g_free(filename);
}
}
@ -572,7 +642,7 @@ static void cb_add_volume_response (GtkWidget *chooser, int response)
if (response == GTK_RESPONSE_ACCEPT)
{
char *file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
gtk_clist_append(GTK_CLIST(volume_list), &file);
add_volume_entry_guessed(file);
}
gtk_widget_destroy(chooser);
}
@ -603,7 +673,8 @@ static void cb_create_volume_response (GtkWidget *chooser, int response, GtkEntr
fprintf(stderr, "Could not create %s (%s)\n", file, strerror(errno));
} else {
ftruncate(fd, disk_size * 1024 * 1024);
gtk_clist_append(GTK_CLIST(volume_list), &file);
// A created empty volume is always a new disk
add_volume_entry_with_type(file, false);
}
}
gtk_widget_destroy (chooser);
@ -660,7 +731,13 @@ static void cb_create_volume (GSimpleAction *action, GVariant *parameter, gpoint
// "Remove Volume" button clicked
static void cb_remove_volume(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(volume_list));
if (sel) {
GtkTreeIter row;
if (gtk_tree_selection_get_selected(sel, NULL, &row)) {
gtk_list_store_remove(volume_list_model, &row);
}
}
}
// "Boot From" selected
@ -678,58 +755,240 @@ static void tb_nocdrom(GtkWidget *widget)
PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
}
// Data source for the volumes list
enum {
VOLUME_LIST_FILENAME = 0,
VOLUME_LIST_CDROM,
VOLUME_LIST_SIZE_DESC,
NUM_VOLUME_LIST_FIELDS
};
static void init_volume_model() {
volume_list_model = gtk_list_store_new(NUM_VOLUME_LIST_FIELDS,
G_TYPE_STRING, // filename
G_TYPE_BOOLEAN, // is CD-ROM
G_TYPE_STRING // size desc
);
}
static void toggle_cdrom_val(GtkTreeIter *row) {
gboolean cdrom;
gtk_tree_model_get(GTK_TREE_MODEL(volume_list_model), row,
VOLUME_LIST_CDROM, &cdrom,
-1);
cdrom = !cdrom;
gtk_list_store_set(volume_list_model, row,
VOLUME_LIST_CDROM, cdrom,
-1);
}
// Read settings from widgets and set preferences
static void read_volumes_settings(void)
{
while (PrefsFindString("disk"))
PrefsRemoveItem("disk");
while (PrefsFindString("cdrom"))
PrefsRemoveItem("cdrom");
for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
char *str;
gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
PrefsAddString("disk", str);
GtkTreeModel * m = GTK_TREE_MODEL(volume_list_model);
GtkTreeIter row;
if (gtk_tree_model_get_iter_first(m, &row)) {
do {
GValue filename = G_VALUE_INIT, is_cdrom = G_VALUE_INIT;
gtk_tree_model_get_value(m, &row, VOLUME_LIST_FILENAME, &filename);
gtk_tree_model_get_value(m, &row, VOLUME_LIST_CDROM, &is_cdrom);
D(bug("handling %d: %s\n", g_value_get_boolean(&is_cdrom), g_value_get_string(&filename)));
const char * pref_name = g_value_get_boolean(&is_cdrom) ? "cdrom": "disk";
PrefsAddString(pref_name, g_value_get_string(&filename));
g_value_unset(&filename);
g_value_unset(&is_cdrom);
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &row));
}
PrefsReplaceString("extfs", get_file_entry_path(w_extfs));
}
// Gets the size of the volume as a pretty string
static const char* get_file_size (const char * filename)
{
std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary);
if (in.is_open()) {
uint64_t size = in.tellg();
in.close();
char *sizestr = g_format_size_full(size, G_FORMAT_SIZE_IEC_UNITS);
return sizestr;
}
else
{
return "Not Found";
}
}
static bool volume_in_list(const char * filename) {
bool found = false;
GtkTreeModel * m = GTK_TREE_MODEL(volume_list_model);
GtkTreeIter row;
if (gtk_tree_model_get_iter_first(m, &row)) {
do {
GValue cur_filename = G_VALUE_INIT;
gtk_tree_model_get_value(m, &row, VOLUME_LIST_FILENAME, &cur_filename);
if (strcmp(g_value_get_string(&cur_filename), filename) == 0) {
found = true;
}
g_value_unset(&cur_filename);
if (found) break;
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &row));
}
return found;
}
// Add a volume file as the given type
static void add_volume_entry_with_type(const char * filename, bool cdrom) {
if (volume_in_list(filename)) return;
GtkTreeIter row;
gtk_list_store_append(GTK_LIST_STORE(volume_list_model), &row);
// set the values for the new row
gtk_list_store_set(GTK_LIST_STORE(volume_list_model), &row,
VOLUME_LIST_FILENAME, filename,
VOLUME_LIST_CDROM, cdrom,
VOLUME_LIST_SIZE_DESC, get_file_size(filename),
-1);
}
static bool has_file_ext (const char * str, const char *ext)
{
char *file_ext = g_utf8_strrchr(str, 255, '.');
if (!file_ext)
return 0;
return (g_strcmp0(file_ext, ext) == 0);
}
static bool guess_if_file_is_cdrom(const char * volume) {
return has_file_ext(volume, ".iso") ||
#ifdef BINCUE
has_file_ext(volume, ".cue") ||
#endif
has_file_ext(volume, ".toast");
}
// Add a volume file and guess the type
static void add_volume_entry_guessed(const char * filename) {
add_volume_entry_with_type(filename, guess_if_file_is_cdrom(filename));
}
// CD-ROM checkbox changed
static void cb_cdrom (GtkCellRendererToggle *cell, char *path_str, gpointer data)
{
GtkTreeIter iter;
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL(volume_list_model), &iter, path)) {
toggle_cdrom_val(&iter);
}
gtk_tree_path_free (path);
}
// Create "Volumes" pane
static void create_volumes_pane(GtkWidget *top)
{
GtkWidget *box, *scroll;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
box = make_pane(top, STR_VOLUMES_PANE_TITLE);
scroll = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_show(scroll);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
volume_list = gtk_clist_new(1);
init_volume_model();
volume_list = gtk_tree_view_new();
gtk_tree_view_set_model(GTK_TREE_VIEW(volume_list), GTK_TREE_MODEL(volume_list_model));
gtk_widget_show(volume_list);
gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
g_signal_connect(volume_list, "select_row", G_CALLBACK(cl_selected), NULL);
gtk_tree_view_set_reorderable(GTK_TREE_VIEW(volume_list), true);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_LOCATION));
gtk_tree_view_column_set_expand(column, true);
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(column, renderer, TRUE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "text", VOLUME_LIST_FILENAME);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_CDROM));
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_toggle_new();
g_signal_connect (renderer, "toggled",
G_CALLBACK (cb_cdrom), NULL);
gtk_tree_view_column_set_alignment(column, 0.5);
gtk_tree_view_column_pack_start(column, renderer, TRUE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "active", VOLUME_LIST_CDROM);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_SIZE));
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(column, renderer, FALSE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "text", VOLUME_LIST_SIZE_DESC);
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(volume_list));
g_signal_connect(sel, "changed", G_CALLBACK(cl_selected), NULL);
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
// also support volume files dragged onto the list from outside
gtk_drag_dest_add_uri_targets(volume_list);
// add a drop handler to get dropped files; don't supersede the drop handler for reordering
gtk_signal_connect_after(GTK_OBJECT(volume_list), "drag_data_received", GTK_SIGNAL_FUNC(drag_data_received), NULL);
// process proposed drops to limit drop locations
gtk_signal_connect(GTK_OBJECT(volume_list), "drag-motion", GTK_SIGNAL_FUNC(volume_list_drag_motion), NULL);
char *str;
int32 index = 0;
while ((str = const_cast<char *>(PrefsFindString("disk", index++))) != NULL)
gtk_clist_append(GTK_CLIST(volume_list), &str);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
int32 index;
const char * types[] = {"disk", "cdrom", NULL};
for (const char ** type = types; *type != NULL; type++) {
index = 0;
while ((str = const_cast<char *>(PrefsFindString(*type, index))) != NULL) {
bool is_cdrom = strcmp(*type, "cdrom") == 0;
add_volume_entry_with_type(str, is_cdrom);
index++;
}
}
gtk_container_add(GTK_CONTAINER(scroll), volume_list);
gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
selected_volume = 0;
static const opt_desc buttons[] = {
{STR_ADD_VOLUME_BUTTON, G_CALLBACK(cb_add_volume)},
{STR_CREATE_VOLUME_BUTTON, G_CALLBACK(cb_create_volume)},
{STR_REMOVE_VOLUME_BUTTON, G_CALLBACK(cb_remove_volume)},
{STR_REMOVE_VOLUME_BUTTON, G_CALLBACK(cb_remove_volume), &volume_remove_button},
{0, NULL},
};
make_button_box(box, 0, buttons);
gtk_widget_set_sensitive(volume_remove_button, FALSE);
make_separator(box);
w_extfs = make_file_entry(box, STR_EXTFS_CTRL, "extfs", true);

View File

@ -722,6 +722,14 @@ static bool has_file_ext (GFile *file, const char *ext)
return (g_strcmp0(file_ext, ext) == 0);
}
static bool guess_if_file_is_cdrom(GFile * volume) {
return has_file_ext(volume, ".iso") ||
#ifdef BINCUE
has_file_ext(volume, ".cue") ||
#endif
has_file_ext(volume, ".toast");
}
// User selected a volume to add
static void cb_add_volume_response (GtkFileChooser *chooser, int response)
{
@ -732,7 +740,7 @@ static void cb_add_volume_response (GtkFileChooser *chooser, int response)
gtk_list_store_set (GTK_LIST_STORE(volume_store), &toplevel,
COLUMN_PATH, g_file_get_path(volume),
COLUMN_SIZE, get_file_size(volume),
COLUMN_CDROM, has_file_ext(volume, ".iso"),
COLUMN_CDROM, guess_if_file_is_cdrom(volume),
-1);
g_object_unref(volume);
}

View File

@ -28,6 +28,8 @@
#include <shellapi.h>
#include <fstream>
#include "user_strings.h"
#include "version.h"
#include "cdrom.h"
@ -53,6 +55,9 @@ static void create_ethernet_pane(GtkWidget *top);
static void create_memory_pane(GtkWidget *top);
static void create_jit_pane(GtkWidget *top);
static void read_settings(void);
static void add_volume_entry_with_type(const char * filename, bool cdrom);
static void add_volume_entry_guessed(const char * filename);
static bool volume_in_list(const char * filename);
/*
@ -100,8 +105,11 @@ gchar * tchar_to_g_utf8(const TCHAR * str) {
struct opt_desc {
opt_desc(int l, GCallback f, GtkWidget **s=NULL) : label_id(l), func(f), save_ref(s) {}
int label_id;
GtkSignalFunc func;
GtkWidget ** save_ref;
};
struct combo_desc {
@ -188,6 +196,9 @@ static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *bu
gtk_widget_show(button);
gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL);
gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
if (buttons->save_ref) {
*(buttons->save_ref) = button;
}
buttons++;
}
return bb;
@ -506,6 +517,7 @@ bool PrefsEditor(void)
{
// Create window
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(win), 640, 480); // a little bigger than the default
gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE));
gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL);
gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL);
@ -564,7 +576,8 @@ bool PrefsEditor(void)
static GtkWidget *w_enableextfs, *w_extdrives, *w_cdrom_drive;
static GtkWidget *volume_list;
static int selected_volume;
static GtkListStore *volume_list_model;
static GtkWidget *volume_remove_button;
// Set sensitivity of widgets
static void set_volumes_sensitive(void)
@ -575,10 +588,39 @@ static void set_volumes_sensitive(void)
gtk_widget_set_sensitive(w_cdrom_drive, !no_cdrom);
}
// Volume in list selected
static void cl_selected(GtkWidget *list, int row, int column)
// Volume list selection changed
static void cl_selected(GtkTreeSelection * selection, gpointer user_data) {
if (selection) {
bool have_selection = gtk_tree_selection_get_selected(selection, NULL, NULL);
gtk_widget_set_sensitive(GTK_WIDGET(volume_remove_button), have_selection);
}
}
// Process proposed drop
gboolean volume_list_drag_motion (GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, guint time,
gpointer user_data)
{
selected_volume = row;
GtkTreePath *path;
GtkTreeViewDropPosition pos;
// Don't allow tree-style drops onto, only list-style drops between
if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(volume_list), x,y, &path, &pos)) {
switch (pos) {
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(volume_list), path, GTK_TREE_VIEW_DROP_AFTER);
break;
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(volume_list), path, GTK_TREE_VIEW_DROP_BEFORE);
break;
case GTK_TREE_VIEW_DROP_BEFORE:
case GTK_TREE_VIEW_DROP_AFTER:
// these are ok, no change
break;
}
gdk_drag_status(drag_context, drag_context->suggested_action, time);
return TRUE;
}
return FALSE;
}
// Something dropped on volume list
@ -598,7 +640,36 @@ static void drag_data_received(GtkWidget *list, GdkDragContext *drag_context, gi
gchar * filename = g_filename_from_uri(*uri, NULL, NULL);
if (filename) {
gtk_clist_append(GTK_CLIST(volume_list), &filename);
add_volume_entry_guessed(filename);
// figure out where in the list they dropped
GtkTreePath *path;
GtkTreeViewDropPosition pos;
if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(volume_list), x,y, &path, &pos)) {
GtkTreeIter dest_iter;
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(volume_list_model), &dest_iter, path)) {
// Find the item we just added and put it in place
GtkTreeIter last;
GtkTreeIter cur;
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(volume_list_model), &cur)) {
do {
last = cur;
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &cur));
}
switch (pos) {
case GTK_TREE_VIEW_DROP_AFTER:
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
gtk_list_store_move_after(volume_list_model, &last, &dest_iter);
break;
case GTK_TREE_VIEW_DROP_BEFORE:
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
gtk_list_store_move_before(volume_list_model, &last, &dest_iter);
break;
}
}
}
g_free(filename);
}
}
@ -609,7 +680,7 @@ static void drag_data_received(GtkWidget *list, GdkDragContext *drag_context, gi
static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc)
{
gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req));
gtk_clist_append(GTK_CLIST(volume_list), &file);
add_volume_entry_guessed(file);
gtk_widget_destroy(assoc->req);
delete assoc;
}
@ -624,9 +695,14 @@ static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc)
int fd = _open(file, _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC, _S_IREAD | _S_IWRITE);
if (fd >= 0) {
bool created_ok = false;
if (_chsize(fd, size) == 0)
gtk_clist_append(GTK_CLIST(volume_list), &file);
created_ok = true;
_close(fd);
if (created_ok) {
// A created empty volume is always a new disk
add_volume_entry_with_type(file, false);
}
}
gtk_widget_destroy(GTK_WIDGET(assoc->req));
delete assoc;
@ -669,7 +745,13 @@ static void cb_create_volume(...)
// "Remove Volume" button clicked
static void cb_remove_volume(...)
{
gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(volume_list));
if (sel) {
GtkTreeIter row;
if (gtk_tree_selection_get_selected(sel, NULL, &row)) {
gtk_list_store_remove(volume_list_model, &row);
}
}
}
// "Boot From" selected
@ -711,64 +793,261 @@ static void tb_pollmedia(GtkWidget *widget)
PrefsReplaceBool("pollmedia", GTK_TOGGLE_BUTTON(widget)->active);
}
// Data source for the volumes list
enum {
VOLUME_LIST_FILENAME = 0,
VOLUME_LIST_CDROM,
VOLUME_LIST_SIZE_DESC,
NUM_VOLUME_LIST_FIELDS
};
static void init_volume_model() {
volume_list_model = gtk_list_store_new(NUM_VOLUME_LIST_FIELDS,
G_TYPE_STRING, // filename
G_TYPE_BOOLEAN, // is CD-ROM
G_TYPE_STRING // size desc
);
}
static void toggle_cdrom_val(GtkTreeIter *row) {
gboolean cdrom;
gtk_tree_model_get(GTK_TREE_MODEL(volume_list_model), row,
VOLUME_LIST_CDROM, &cdrom,
-1);
cdrom = !cdrom;
gtk_list_store_set(volume_list_model, row,
VOLUME_LIST_CDROM, cdrom,
-1);
}
// Read settings from widgets and set preferences
static void read_volumes_settings(void)
{
while (PrefsFindString("disk"))
PrefsRemoveItem("disk");
while (PrefsFindString("cdrom"))
PrefsRemoveItem("cdrom");
for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
char *str;
gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
PrefsAddString("disk", str);
GtkTreeModel * m = GTK_TREE_MODEL(volume_list_model);
GtkTreeIter row;
if (gtk_tree_model_get_iter_first(m, &row)) {
do {
GValue filename = G_VALUE_INIT, is_cdrom = G_VALUE_INIT;
gtk_tree_model_get_value(m, &row, VOLUME_LIST_FILENAME, &filename);
gtk_tree_model_get_value(m, &row, VOLUME_LIST_CDROM, &is_cdrom);
//D(bug("handling %d: %s\n", g_value_get_boolean(&is_cdrom), g_value_get_string(&filename)));
const char * pref_name = g_value_get_boolean(&is_cdrom) ? "cdrom": "disk";
PrefsAddString(pref_name, g_value_get_string(&filename));
g_value_unset(&filename);
g_value_unset(&is_cdrom);
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &row));
}
const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_cdrom_drive)->entry));
if (str && strlen(str))
PrefsReplaceString("cdrom", str);
else
PrefsRemoveItem("cdrom");
PrefsReplaceString("extdrives", get_file_entry_path(w_extdrives));
// Add one more cdrom entry if present in the combo
const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_cdrom_drive)->entry));
if (str && strlen(str) && !volume_in_list(str))
PrefsAddString("cdrom", str);
}
// Gets the size of the volume as a pretty string
static const char* get_file_size_str (const char * filename)
{
if (strlen(filename) == 3 && filename[1] == ':' && filename[2] == '\\') {
// e.g. real CD-ROM drive
return "";
}
std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary);
if (in.is_open()) {
uint64_t size = in.tellg();
in.close();
char *sizestr = g_format_size_full(size, G_FORMAT_SIZE_IEC_UNITS);
return sizestr;
}
else
{
return "Not Found";
}
}
static bool volume_in_list(const char * filename) {
bool found = false;
GtkTreeModel * m = GTK_TREE_MODEL(volume_list_model);
GtkTreeIter row;
if (gtk_tree_model_get_iter_first(m, &row)) {
do {
GValue cur_filename = G_VALUE_INIT;
gtk_tree_model_get_value(m, &row, VOLUME_LIST_FILENAME, &cur_filename);
if (strcmp(g_value_get_string(&cur_filename), filename) == 0) {
found = true;
}
g_value_unset(&cur_filename);
if (found) break;
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &row));
}
return found;
}
// Add a volume file as the given type
static void add_volume_entry_with_type(const char * filename, bool cdrom) {
if (volume_in_list(filename)) return;
GtkTreeIter row;
gtk_list_store_append(GTK_LIST_STORE(volume_list_model), &row);
// set the values for the new row
gtk_list_store_set(GTK_LIST_STORE(volume_list_model), &row,
VOLUME_LIST_FILENAME, filename,
VOLUME_LIST_CDROM, cdrom,
VOLUME_LIST_SIZE_DESC, get_file_size_str(filename),
-1);
}
static bool has_file_ext (const char * str, const char *ext)
{
char *file_ext = g_utf8_strrchr(str, 255, '.');
if (!file_ext)
return 0;
return (g_strcmp0(file_ext, ext) == 0);
}
static bool guess_if_file_is_cdrom(const char * volume) {
return has_file_ext(volume, ".iso") ||
#ifdef BINCUE
has_file_ext(volume, ".cue") ||
#endif
has_file_ext(volume, ".toast");
}
// Add a volume file and guess the type
static void add_volume_entry_guessed(const char * filename) {
add_volume_entry_with_type(filename, guess_if_file_is_cdrom(filename));
}
// CD-ROM checkbox changed
static void cb_cdrom (GtkCellRendererToggle *cell, char *path_str, gpointer data)
{
GtkTreeIter iter;
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL(volume_list_model), &iter, path)) {
toggle_cdrom_val(&iter);
}
gtk_tree_path_free (path);
}
static void cb_cdrom_add(...) {
const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_cdrom_drive)->entry));
if (str && strcmp(str, "") != 0) {
if (volume_in_list(str)) return;
add_volume_entry_with_type(str, true);
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(w_cdrom_drive)->entry), "");
}
}
// Create "Volumes" pane
static void create_volumes_pane(GtkWidget *top)
{
GtkWidget *box, *scroll, *menu;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
box = make_pane(top, STR_VOLUMES_PANE_TITLE);
scroll = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_show(scroll);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
volume_list = gtk_clist_new(1);
init_volume_model();
volume_list = gtk_tree_view_new();
gtk_tree_view_set_model(GTK_TREE_VIEW(volume_list), GTK_TREE_MODEL(volume_list_model));
gtk_widget_show(volume_list);
gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL);
gtk_tree_view_set_reorderable(GTK_TREE_VIEW(volume_list), true);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_LOCATION));
gtk_tree_view_column_set_expand(column, true);
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(column, renderer, TRUE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "text", VOLUME_LIST_FILENAME);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_CDROM));
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_toggle_new();
g_signal_connect (renderer, "toggled",
G_CALLBACK (cb_cdrom), NULL);
gtk_tree_view_column_set_alignment(column, 0.5);
gtk_tree_view_column_pack_start(column, renderer, TRUE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "active", VOLUME_LIST_CDROM);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_SIZE));
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(column, renderer, FALSE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "text", VOLUME_LIST_SIZE_DESC);
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(volume_list));
g_signal_connect(sel, "changed", G_CALLBACK(cl_selected), NULL);
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
// also support volume files dragged onto the list from outside
gtk_drag_dest_add_uri_targets(volume_list);
// add a drop handler to get dropped files; don't supersede the drop handler for reordering
gtk_signal_connect_after(GTK_OBJECT(volume_list), "drag_data_received", GTK_SIGNAL_FUNC(drag_data_received), NULL);
// process proposed drops to limit drop locations
gtk_signal_connect(GTK_OBJECT(volume_list), "drag-motion", GTK_SIGNAL_FUNC(volume_list_drag_motion), NULL);
char *str;
int32 index = 0;
while ((str = const_cast<char *>(PrefsFindString("disk", index++))) != NULL)
gtk_clist_append(GTK_CLIST(volume_list), &str);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
int32 index;
const char * types[] = {"disk", "cdrom", NULL};
for (const char ** type = types; *type != NULL; type++) {
index = 0;
while ((str = const_cast<char *>(PrefsFindString(*type, index))) != NULL) {
bool is_cdrom = strcmp(*type, "cdrom") == 0;
add_volume_entry_with_type(str, is_cdrom);
index++;
}
}
gtk_container_add(GTK_CONTAINER(scroll), volume_list);
gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
selected_volume = 0;
static const opt_desc buttons[] = {
{STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)},
{STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)},
{STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)},
{STR_REMOVE_VOLUME_BUTTON, G_CALLBACK(cb_remove_volume), &volume_remove_button},
{0, NULL},
};
make_button_box(box, 0, buttons);
gtk_widget_set_sensitive(volume_remove_button, FALSE);
make_separator(box);
static const opt_desc options[] = {
@ -786,11 +1065,17 @@ static void create_volumes_pane(GtkWidget *top)
make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom));
GList *glist = add_cdrom_names();
str = const_cast<char *>(PrefsFindString("cdrom"));
if (str == NULL)
//str = const_cast<char *>(PrefsFindString("cdrom"));
//if (str == NULL)
str = "";
w_cdrom_drive = make_combobox(box, STR_CDROM_DRIVE_CTRL, str, glist);
GtkWidget * cdrom_hbox = gtk_widget_get_parent(w_cdrom_drive);
GtkWidget * cdrom_add_button = gtk_button_new_with_label("Add");
gtk_widget_show(cdrom_add_button);
gtk_signal_connect_object(GTK_OBJECT(cdrom_add_button), "clicked", GTK_SIGNAL_FUNC(cb_cdrom_add), NULL);
gtk_box_pack_start(GTK_BOX(cdrom_hbox), cdrom_add_button, FALSE, TRUE, 0);
make_checkbox(box, STR_POLLMEDIA_CTRL, "pollmedia", GTK_SIGNAL_FUNC(tb_pollmedia));
make_separator(box);

View File

@ -105,6 +105,9 @@ enum {
STR_VOL_SIZE_CTRL,
STR_VOL_BLOCKSIZE_CTRL,
STR_VOL_FILE_CTRL,
STR_VOL_HEADING_LOCATION,
STR_VOL_HEADING_CDROM,
STR_VOL_HEADING_SIZE,
STR_SCSI_PANE_TITLE = 3300, // SCSI pane
STR_SCSI_ID_0 = 3301,

View File

@ -97,6 +97,9 @@ user_string_def common_strings[] = {
{STR_CREATE_VOLUME_BUTTON, "Create" ELLIPSIS},
{STR_EDIT_VOLUME_BUTTON, "Edit" ELLIPSIS},
{STR_REMOVE_VOLUME_BUTTON, "Remove"},
{STR_VOL_HEADING_LOCATION, "Location"},
{STR_VOL_HEADING_CDROM, "CD-ROM"},
{STR_VOL_HEADING_SIZE, "Size"},
{STR_ADD_VOLUME_PANEL_BUTTON, "Add"},
{STR_CREATE_VOLUME_PANEL_BUTTON, "Create"},
{STR_CDROM_DRIVE_CTRL, "CD-ROM Drive"},

View File

@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "gdk/gdk.h"
#include "sysdeps.h"
#include <gtk/gtk.h>
@ -30,6 +31,7 @@
#include <net/if_arp.h>
#include <cerrno>
#include <fstream>
#include "user_strings.h"
#include "version.h"
@ -56,6 +58,8 @@ static void create_serial_pane(GtkWidget *top);
static void create_memory_pane(GtkWidget *top);
static void create_jit_pane(GtkWidget *top);
static void read_settings(void);
static void add_volume_entry_with_type(const char * filename, bool cdrom);
static void add_volume_entry_guessed(const char * filename);
/*
@ -69,8 +73,11 @@ static void read_settings(void);
#endif
struct opt_desc {
opt_desc(int l, GCallback f, GtkWidget **s=NULL) : label_id(l), func(f), save_ref(s) {}
int label_id;
GCallback func;
GtkWidget ** save_ref;
};
struct combo_desc {
@ -176,6 +183,9 @@ static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *bu
gtk_widget_show(button);
g_signal_connect_object(button, "clicked", buttons->func, NULL, (GConnectFlags) 0);
gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0);
if (buttons->save_ref) {
*(buttons->save_ref) = button;
}
buttons++;
}
return bb;
@ -486,14 +496,46 @@ bool PrefsEditor(void)
*/
static GtkWidget *volume_list, *w_extfs;
static int selected_volume;
static GtkListStore *volume_list_model;
static GtkWidget *volume_remove_button;
// Volume in list selected
static void cl_selected(GtkWidget *list, int row, int column)
{
selected_volume = row;
// Volume list selection changed
static void cl_selected(GtkTreeSelection * selection, gpointer user_data) {
if (selection) {
bool have_selection = gtk_tree_selection_get_selected(selection, NULL, NULL);
gtk_widget_set_sensitive(GTK_WIDGET(volume_remove_button), have_selection);
}
}
// Process proposed drop
gboolean volume_list_drag_motion (GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, guint time,
gpointer user_data)
{
GtkTreePath *path;
GtkTreeViewDropPosition pos;
// Don't allow tree-style drops onto, only list-style drops between
if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(volume_list), x,y, &path, &pos)) {
switch (pos) {
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(volume_list), path, GTK_TREE_VIEW_DROP_AFTER);
break;
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(volume_list), path, GTK_TREE_VIEW_DROP_BEFORE);
break;
case GTK_TREE_VIEW_DROP_BEFORE:
case GTK_TREE_VIEW_DROP_AFTER:
// these are ok, no change
break;
}
gdk_drag_status(drag_context, drag_context->suggested_action, time);
return TRUE;
}
return FALSE;
}
// Something dropped on volume list
static void drag_data_received(GtkWidget *list, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data,
guint info, guint time, gpointer user_data)
@ -511,7 +553,36 @@ static void drag_data_received(GtkWidget *list, GdkDragContext *drag_context, gi
gchar * filename = g_filename_from_uri(*uri, NULL, NULL);
if (filename) {
gtk_clist_append(GTK_CLIST(volume_list), &filename);
add_volume_entry_guessed(filename);
// figure out where in the list they dropped
GtkTreePath *path;
GtkTreeViewDropPosition pos;
if (gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(volume_list), x,y, &path, &pos)) {
GtkTreeIter dest_iter;
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(volume_list_model), &dest_iter, path)) {
// Find the item we just added and put it in place
GtkTreeIter last;
GtkTreeIter cur;
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(volume_list_model), &cur)) {
do {
last = cur;
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &cur));
}
switch (pos) {
case GTK_TREE_VIEW_DROP_AFTER:
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
gtk_list_store_move_after(volume_list_model, &last, &dest_iter);
break;
case GTK_TREE_VIEW_DROP_BEFORE:
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
gtk_list_store_move_before(volume_list_model, &last, &dest_iter);
break;
}
}
}
g_free(filename);
}
}
@ -524,7 +595,7 @@ static void cb_add_volume_response (GtkWidget *chooser, int response)
if (response == GTK_RESPONSE_ACCEPT)
{
char *file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
gtk_clist_append(GTK_CLIST(volume_list), &file);
add_volume_entry_guessed(file);
}
gtk_widget_destroy(chooser);
}
@ -555,7 +626,8 @@ static void cb_create_volume_response (GtkWidget *chooser, int response, GtkEntr
fprintf(stderr, "Could not create %s (%s)\n", file, strerror(errno));
} else {
ftruncate(fd, disk_size * 1024 * 1024);
gtk_clist_append(GTK_CLIST(volume_list), &file);
// A created empty volume is always a new disk
add_volume_entry_with_type(file, false);
}
}
gtk_widget_destroy (chooser);
@ -611,7 +683,13 @@ static void cb_create_volume (GSimpleAction *action, GVariant *parameter, gpoint
// "Remove Volume" button clicked
static void cb_remove_volume(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
gtk_clist_remove(GTK_CLIST(volume_list), selected_volume);
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(volume_list));
if (sel) {
GtkTreeIter row;
if (gtk_tree_selection_get_selected(sel, NULL, &row)) {
gtk_list_store_remove(volume_list_model, &row);
}
}
}
// "Boot From" selected
@ -629,58 +707,239 @@ static void tb_nocdrom(GtkWidget *widget)
PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active);
}
// Data source for the volumes list
enum {
VOLUME_LIST_FILENAME = 0,
VOLUME_LIST_CDROM,
VOLUME_LIST_SIZE_DESC,
NUM_VOLUME_LIST_FIELDS
};
static void init_volume_model() {
volume_list_model = gtk_list_store_new(NUM_VOLUME_LIST_FIELDS,
G_TYPE_STRING, // filename
G_TYPE_BOOLEAN, // is CD-ROM
G_TYPE_STRING // size desc
);
}
static void toggle_cdrom_val(GtkTreeIter *row) {
gboolean cdrom;
gtk_tree_model_get(GTK_TREE_MODEL(volume_list_model), row,
VOLUME_LIST_CDROM, &cdrom,
-1);
cdrom = !cdrom;
gtk_list_store_set(volume_list_model, row,
VOLUME_LIST_CDROM, cdrom,
-1);
}
// Read settings from widgets and set preferences
static void read_volumes_settings(void)
{
while (PrefsFindString("disk"))
PrefsRemoveItem("disk");
while (PrefsFindString("cdrom"))
PrefsRemoveItem("cdrom");
for (int i=0; i<GTK_CLIST(volume_list)->rows; i++) {
char *str;
gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str);
PrefsAddString("disk", str);
GtkTreeModel * m = GTK_TREE_MODEL(volume_list_model);
GtkTreeIter row;
if (gtk_tree_model_get_iter_first(m, &row)) {
do {
GValue filename = G_VALUE_INIT, is_cdrom = G_VALUE_INIT;
gtk_tree_model_get_value(m, &row, VOLUME_LIST_FILENAME, &filename);
gtk_tree_model_get_value(m, &row, VOLUME_LIST_CDROM, &is_cdrom);
D(bug("handling %d: %s\n", g_value_get_boolean(&is_cdrom), g_value_get_string(&filename)));
const char * pref_name = g_value_get_boolean(&is_cdrom) ? "cdrom": "disk";
PrefsAddString(pref_name, g_value_get_string(&filename));
g_value_unset(&filename);
g_value_unset(&is_cdrom);
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &row));
}
PrefsReplaceString("extfs", gtk_entry_get_text(GTK_ENTRY(w_extfs)));
}
// Gets the size of the volume as a pretty string
static const char* get_file_size (const char * filename)
{
std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary);
if (in.is_open()) {
uint64_t size = in.tellg();
in.close();
char *sizestr = g_format_size_full(size, G_FORMAT_SIZE_IEC_UNITS);
return sizestr;
}
else
{
return "Not Found";
}
}
static bool volume_in_list(const char * filename) {
bool found = false;
GtkTreeModel * m = GTK_TREE_MODEL(volume_list_model);
GtkTreeIter row;
if (gtk_tree_model_get_iter_first(m, &row)) {
do {
GValue cur_filename = G_VALUE_INIT;
gtk_tree_model_get_value(m, &row, VOLUME_LIST_FILENAME, &cur_filename);
if (strcmp(g_value_get_string(&cur_filename), filename) == 0) {
found = true;
}
g_value_unset(&cur_filename);
if (found) break;
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(volume_list_model), &row));
}
return found;
}
// Add a volume file as the given type
static void add_volume_entry_with_type(const char * filename, bool cdrom) {
if (volume_in_list(filename)) return;
GtkTreeIter row;
gtk_list_store_append(GTK_LIST_STORE(volume_list_model), &row);
// set the values for the new row
gtk_list_store_set(GTK_LIST_STORE(volume_list_model), &row,
VOLUME_LIST_FILENAME, filename,
VOLUME_LIST_CDROM, cdrom,
VOLUME_LIST_SIZE_DESC, get_file_size(filename),
-1);
}
static bool has_file_ext (const char * str, const char *ext)
{
char *file_ext = g_utf8_strrchr(str, 255, '.');
if (!file_ext)
return 0;
return (g_strcmp0(file_ext, ext) == 0);
}
static bool guess_if_file_is_cdrom(const char * volume) {
return has_file_ext(volume, ".iso") ||
#ifdef BINCUE
has_file_ext(volume, ".cue") ||
#endif
has_file_ext(volume, ".toast");
}
// Add a volume file and guess the type
static void add_volume_entry_guessed(const char * filename) {
add_volume_entry_with_type(filename, guess_if_file_is_cdrom(filename));
}
// CD-ROM checkbox changed
static void cb_cdrom (GtkCellRendererToggle *cell, char *path_str, gpointer data)
{
GtkTreeIter iter;
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL(volume_list_model), &iter, path)) {
toggle_cdrom_val(&iter);
}
gtk_tree_path_free (path);
}
// Create "Volumes" pane
static void create_volumes_pane(GtkWidget *top)
{
GtkWidget *box, *scroll, *menu;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
box = make_pane(top, STR_VOLUMES_PANE_TITLE);
scroll = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_show(scroll);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
volume_list = gtk_clist_new(1);
init_volume_model();
volume_list = gtk_tree_view_new();
gtk_tree_view_set_model(GTK_TREE_VIEW(volume_list), GTK_TREE_MODEL(volume_list_model));
gtk_widget_show(volume_list);
gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE);
gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE);
gtk_clist_set_reorderable(GTK_CLIST(volume_list), true);
g_signal_connect(volume_list, "select_row", G_CALLBACK(cl_selected), NULL);
gtk_tree_view_set_reorderable(GTK_TREE_VIEW(volume_list), true);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_LOCATION));
gtk_tree_view_column_set_expand(column, true);
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(column, renderer, TRUE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "text", VOLUME_LIST_FILENAME);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_CDROM));
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_toggle_new();
g_signal_connect (renderer, "toggled",
G_CALLBACK (cb_cdrom), NULL);
gtk_tree_view_column_set_alignment(column, 0.5);
gtk_tree_view_column_pack_start(column, renderer, TRUE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "active", VOLUME_LIST_CDROM);
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, GetString(STR_VOL_HEADING_SIZE));
gtk_tree_view_append_column(GTK_TREE_VIEW(volume_list), column);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(column, renderer, FALSE);
// connect tree column to model field
gtk_tree_view_column_add_attribute(column, renderer, "text", VOLUME_LIST_SIZE_DESC);
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(volume_list));
g_signal_connect(sel, "changed", G_CALLBACK(cl_selected), NULL);
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
// also support volume files dragged onto the list from outside
gtk_drag_dest_add_uri_targets(volume_list);
// add a drop handler to get dropped files; don't supersede the drop handler for reordering
gtk_signal_connect_after(GTK_OBJECT(volume_list), "drag_data_received", GTK_SIGNAL_FUNC(drag_data_received), NULL);
// process proposed drops to limit drop locations
gtk_signal_connect(GTK_OBJECT(volume_list), "drag-motion", GTK_SIGNAL_FUNC(volume_list_drag_motion), NULL);
char *str;
int32 index = 0;
while ((str = (char *)PrefsFindString("disk", index++)) != NULL)
gtk_clist_append(GTK_CLIST(volume_list), &str);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list);
int32 index;
const char * types[] = {"disk", "cdrom", NULL};
for (const char ** type = types; *type != NULL; type++) {
index = 0;
while ((str = const_cast<char *>(PrefsFindString(*type, index))) != NULL) {
bool is_cdrom = strcmp(*type, "cdrom") == 0;
add_volume_entry_with_type(str, is_cdrom);
index++;
}
}
gtk_container_add(GTK_CONTAINER(scroll), volume_list);
gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0);
selected_volume = 0;
static const opt_desc buttons[] = {
{STR_ADD_VOLUME_BUTTON, G_CALLBACK(cb_add_volume)},
{STR_CREATE_VOLUME_BUTTON, G_CALLBACK(cb_create_volume)},
{STR_REMOVE_VOLUME_BUTTON, G_CALLBACK(cb_remove_volume)},
{STR_REMOVE_VOLUME_BUTTON, G_CALLBACK(cb_remove_volume), &volume_remove_button},
{0, NULL},
};
make_button_box(box, 0, buttons);
gtk_widget_set_sensitive(volume_remove_button, FALSE);
make_separator(box);
w_extfs = make_file_entry(box, STR_EXTFS_CTRL, "extfs", true);

View File

@ -98,6 +98,9 @@ enum {
STR_ADD_VOLUME_TITLE,
STR_CREATE_VOLUME_TITLE,
STR_HARDFILE_SIZE_CTRL,
STR_VOL_HEADING_LOCATION,
STR_VOL_HEADING_CDROM,
STR_VOL_HEADING_SIZE,
// Graphics pane
STR_GRAPHICS_SOUND_PANE_TITLE = 3300,

View File

@ -99,6 +99,9 @@ user_string_def common_strings[] = {
{STR_ADD_VOLUME_BUTTON, "Add" ELLIPSIS},
{STR_CREATE_VOLUME_BUTTON, "Create" ELLIPSIS},
{STR_REMOVE_VOLUME_BUTTON, "Remove"},
{STR_VOL_HEADING_LOCATION, "Location"},
{STR_VOL_HEADING_CDROM, "CD-ROM"},
{STR_VOL_HEADING_SIZE, "Size"},
{STR_ADD_VOLUME_PANEL_BUTTON, "Add"},
{STR_CREATE_VOLUME_PANEL_BUTTON, "Create"},
{STR_CDROM_DRIVE_CTRL, "CD-ROM Drive"},