4
* $Id: swapfilegui.c,v 1.70.2.5 2002/01/16 21:08:02 richi Exp $
6
* Copyright (C) 2001 Richard Guenther, Johannes Hirche, Alexander Ehlert
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31
#include <xmlmemory.h>
34
#include "glame_types.h"
36
#include "gltreeitem.h"
37
#include "waveeditgui.h"
39
#include "util/glame_gui_utils.h"
40
#include "clipboard.h"
41
#include "timeline/timeline.h"
43
#include "network_utils.h"
44
#include "importexport.h"
45
#include "swapfilegui.h"
48
/* GUI is single threaded, so we may have some global state.
51
static SwapfileGui *active_swapfilegui = NULL;
54
/* Forward declarations. */
55
static int click_cb(GtkWidget *item, GdkEventButton *event,
57
static void copyselected_cb(GtkWidget *menu, GlameTreeItem *item);
58
static void linkselected_cb(GtkWidget *menu, GlameTreeItem *item);
59
static void mergeparent_cb(GtkWidget *menu, GlameTreeItem *item);
60
static void flatten_cb(GtkWidget *menu, GlameTreeItem *item);
61
static void addgroup_cb(GtkWidget *menu, GlameTreeItem *item);
62
static void addclipboard_cb(GtkWidget *menu, GlameTreeItem *item);
63
static void addfile_cb(GtkWidget *menu, GlameTreeItem *item);
64
static void addstereo_cb(GtkWidget *menu, GlameTreeItem *item);
65
static void edit_cb(GtkWidget *menu, GlameTreeItem *item);
66
static void timeline_cb(GtkWidget *menu, GlameTreeItem *item);
67
static void import_cb(GtkWidget *menu, GlameTreeItem *item);
68
static void export_cb(GtkWidget *menu, GlameTreeItem *item);
69
static void delete_cb(GtkWidget *menu, GlameTreeItem *item);
70
static void handle_grp(glsig_handler_t *handler, long sig, va_list va);
71
static void group_cb(GtkWidget *menu, GlameTreeItem *item);
73
static GnomeUIInfo dummy1_menu[] = {
76
static GnomeUIInfo dummy2_menu[] = {
80
static GnomeUIInfo group_menu_data[] = {
81
GNOMEUIINFO_SEPARATOR,
82
GNOMEUIINFO_ITEM(N_("Edit"), NULL, edit_cb, NULL),
83
GNOMEUIINFO_ITEM(N_("Timeline"), NULL, timeline_cb, NULL),
84
GNOMEUIINFO_SEPARATOR,
85
GNOMEUIINFO_ITEM(N_("Delete"), NULL, delete_cb, NULL),
86
GNOMEUIINFO_SEPARATOR,
87
GNOMEUIINFO_ITEM(N_("Add group"), NULL, addgroup_cb, NULL),
88
GNOMEUIINFO_ITEM(N_("Add clipboard"), NULL, addclipboard_cb, NULL),
89
GNOMEUIINFO_ITEM(N_("Add mono wave"), NULL, addfile_cb, NULL),
90
GNOMEUIINFO_ITEM(N_("Add stereo wave"), NULL, addstereo_cb, NULL),
91
GNOMEUIINFO_ITEM(N_("Link selected"), NULL, linkselected_cb, NULL),
92
GNOMEUIINFO_ITEM(N_("Copy selected"), NULL, copyselected_cb, NULL),
93
GNOMEUIINFO_SEPARATOR,
94
GNOMEUIINFO_ITEM(N_("Merge with parent"), NULL, mergeparent_cb, NULL),
95
GNOMEUIINFO_ITEM(N_("Flatten"), NULL, flatten_cb, NULL),
96
GNOMEUIINFO_SEPARATOR,
97
GNOMEUIINFO_SUBTREE(N_("Apply operation"), dummy1_menu),
98
GNOMEUIINFO_SEPARATOR,
99
GNOMEUIINFO_ITEM(N_("Import..."), NULL, import_cb, NULL),
100
GNOMEUIINFO_ITEM(N_("Export..."), NULL, export_cb, NULL),
101
GNOMEUIINFO_SEPARATOR,
104
#define GROUP_MENU_ADDGROUP_INDEX 6
105
#define GROUP_MENU_ADDCLIPBOARD_INDEX 7
106
#define GROUP_MENU_ADDMONO_INDEX 8
107
#define GROUP_MENU_ADDSTEREO_INDEX 9
108
#define GROUP_MENU_APPLYOP_INDEX 16
109
#define GROUP_MENU_IMPORT_INDEX 18
110
static GnomeUIInfo file_menu_data[] = {
111
GNOMEUIINFO_SEPARATOR,
112
GNOMEUIINFO_ITEM(N_("Edit"), NULL, edit_cb, NULL),
113
GNOMEUIINFO_SEPARATOR,
114
GNOMEUIINFO_ITEM(N_("Delete"), NULL, delete_cb, NULL),
115
GNOMEUIINFO_SEPARATOR,
116
GNOMEUIINFO_ITEM(N_("Group"), NULL, group_cb, NULL),
117
GNOMEUIINFO_SEPARATOR,
118
GNOMEUIINFO_SUBTREE(N_("Apply operation"), dummy2_menu),
119
GNOMEUIINFO_SEPARATOR,
120
GNOMEUIINFO_ITEM(N_("Export..."), NULL, export_cb, NULL),
121
GNOMEUIINFO_SEPARATOR,
124
#define FILE_MENU_APPLYOP_INDEX 7
127
static void edit_tree_label_cb(GtkEntry* entry, GlameTreeItem* item)
129
char *text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
130
/* Unlock accelerators. HACK(?) */
131
gtk_signal_handler_unblock(GTK_OBJECT(active_swapfilegui->app),
132
active_swapfilegui->accel_handler);
133
gtk_container_remove(GTK_CONTAINER(item), GTK_WIDGET(entry));
134
gtk_widget_destroy(GTK_WIDGET(entry));
136
gpsm_item_set_label(item->item, text);
140
void edit_tree_label(GlameTreeItem * item)
145
/* Deselect item and replace GtkLabel with GtkEntry. */
146
gtk_tree_item_deselect(GTK_TREE_ITEM(item));
147
label = GTK_WIDGET((g_list_first(gtk_container_children(GTK_CONTAINER(item))))->data);
148
gtk_container_remove(GTK_CONTAINER(item), label);
149
entry = gtk_entry_new();
150
gtk_entry_set_text(GTK_ENTRY(entry), gpsm_item_label(item->item));
151
gtk_signal_connect(GTK_OBJECT(entry), "activate",
152
(GtkSignalFunc)edit_tree_label_cb, item);
153
gtk_widget_show(entry);
154
gtk_container_add(GTK_CONTAINER(item), entry);
155
gtk_container_check_resize(GTK_CONTAINER(item));
156
gtk_widget_grab_focus(GTK_WIDGET(entry));
157
/* Block accelerators. HACK(?) */
158
gtk_signal_handler_block(GTK_OBJECT(active_swapfilegui->app),
159
active_swapfilegui->accel_handler);
162
static void deselect_all(SwapfileGui *gui)
169
while ((selected = GTK_TREE_SELECTION(gui->tree))) {
170
GlameTreeItem *i = GLAME_TREE_ITEM(selected->data);
171
gtk_tree_unselect_child(i->tree, GTK_WIDGET(i));
175
/* Menu event - Apply operation. */
176
static void applyop_cb(GtkWidget *bla, plugin_t *plugin)
178
gpsm_item_t *item = active_swapfilegui->active_item->item;
179
int (*operation)(gpsm_item_t *, long, long);
181
if (!(operation = plugin_query(plugin, PLUGIN_GPSMOP))) {
182
DPRINTF("No such operation %s\n", plugin_name(plugin));
185
DPRINTF("Executing operation %s on %s [%li, %li[\n",
186
plugin_name(plugin), gpsm_item_label(item),
187
(long)0, (long)gpsm_item_hsize(item));
189
if (operation(item, 0, gpsm_item_hsize(item)) == -1)
190
gnome_dialog_run_and_close(GNOME_DIALOG(
191
gnome_error_dialog(_("Error executing"))));
193
DPRINTF("%s finished.\n", plugin_name(plugin));
194
deselect_all(active_swapfilegui);
197
/* Somehow only select "operations" */
198
static int choose_ops(plugin_t *plugin)
200
/* Only use filters, hide Import */
201
if (!plugin_query(plugin, PLUGIN_GPSMOP)
202
|| strcmp(plugin_name(plugin), "import") == 0)
208
static int click_cb(GtkWidget *item, GdkEventButton *event,
211
GlameTreeItem *i = GLAME_TREE_ITEM(item);
212
GtkWidget *menu, *op_menu;
214
if (event->button == 1
215
&& event->type == GDK_2BUTTON_PRESS) {
220
if (event->button != 3
221
|| event->type != GDK_BUTTON_PRESS)
224
if (GPSM_ITEM_IS_SWFILE(i->item)) {
225
menu = gnome_popup_menu_new(file_menu_data);
226
op_menu = GTK_WIDGET(glame_gui_build_plugin_menu(choose_ops, applyop_cb));
227
gtk_widget_show(GTK_WIDGET(op_menu));
228
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_menu_data[FILE_MENU_APPLYOP_INDEX].widget), GTK_WIDGET(op_menu));
230
} else if (GPSM_ITEM_IS_GRP(i->item)) {
231
menu = gnome_popup_menu_new(group_menu_data);
232
op_menu = GTK_WIDGET(glame_gui_build_plugin_menu(choose_ops, applyop_cb));
233
gtk_widget_show(GTK_WIDGET(op_menu));
234
gtk_menu_item_set_submenu(GTK_MENU_ITEM(group_menu_data[GROUP_MENU_APPLYOP_INDEX].widget), GTK_WIDGET(op_menu));
235
gtk_widget_set_sensitive(group_menu_data[GROUP_MENU_ADDGROUP_INDEX].widget,
236
gpsm_grp_is_vbox((gpsm_grp_t *)i->item) ? TRUE : FALSE);
237
gtk_widget_set_sensitive(group_menu_data[GROUP_MENU_ADDCLIPBOARD_INDEX].widget,
238
gpsm_grp_is_vbox((gpsm_grp_t *)i->item) ? TRUE : FALSE);
239
gtk_widget_set_sensitive(group_menu_data[GROUP_MENU_ADDMONO_INDEX].widget,
240
gpsm_grp_is_vbox((gpsm_grp_t *)i->item) ? TRUE : FALSE);
241
gtk_widget_set_sensitive(group_menu_data[GROUP_MENU_ADDSTEREO_INDEX].widget,
242
gpsm_grp_is_vbox((gpsm_grp_t *)i->item) ? TRUE : FALSE);
243
gtk_widget_set_sensitive(group_menu_data[GROUP_MENU_IMPORT_INDEX].widget,
244
gpsm_grp_is_vbox((gpsm_grp_t *)i->item) || gpsm_grp_is_hbox((gpsm_grp_t *)i->item) ? TRUE : FALSE);
248
gnome_popup_menu_do_popup(menu, NULL, NULL, event, i);
252
/* Copy (COW, new swapfiles) all selected items as childs of the
254
static void copyselected_cb(GtkWidget *menu, GlameTreeItem *item)
258
if (!GPSM_ITEM_IS_GRP(item->item))
261
selected = GTK_TREE_SELECTION(glame_tree_item_parent(item));
263
GlameTreeItem *i = GLAME_TREE_ITEM(selected->data);
266
/* Dont allow copying myself into myself. */
267
if (item->item == i->item)
270
if (GPSM_ITEM_IS_SWFILE(i->item))
271
copy = (gpsm_item_t *)gpsm_swfile_cow((gpsm_swfile_t *)i->item);
272
else if (GPSM_ITEM_IS_GRP(i->item))
273
copy = (gpsm_item_t *)gpsm_grp_cow((gpsm_grp_t *)i->item);
276
if (gpsm_grp_is_vbox((gpsm_grp_t *)item->item))
277
gpsm_vbox_insert((gpsm_grp_t *)item->item, copy,
278
0, gpsm_item_vsize(item->item));
279
else if (gpsm_grp_is_hbox((gpsm_grp_t *)item->item))
280
gpsm_hbox_insert((gpsm_grp_t *)item->item, copy,
281
gpsm_item_hsize(item->item), 0);
283
gnome_dialog_run_and_close(GNOME_DIALOG(
284
gnome_error_dialog(_("Cannot place item into irregular group"))));
285
gpsm_item_destroy(copy);
290
selected = g_list_next(selected);
293
deselect_all(active_swapfilegui);
296
/* Link (just new items, same swapfile name) all selected items as
297
* childs of the current item. */
298
static void linkselected_cb(GtkWidget *menu, GlameTreeItem *item)
302
if (!GPSM_ITEM_IS_GRP(item->item))
305
selected = GTK_TREE_SELECTION(glame_tree_item_parent(item));
307
GlameTreeItem *i = GLAME_TREE_ITEM(selected->data);
310
/* Dont allow copying myself into myself. */
311
if (item->item == i->item)
314
if (GPSM_ITEM_IS_SWFILE(i->item))
315
copy = (gpsm_item_t *)gpsm_swfile_link((gpsm_swfile_t *)i->item);
316
else if (GPSM_ITEM_IS_GRP(i->item))
317
copy = (gpsm_item_t *)gpsm_grp_link((gpsm_grp_t *)i->item);
320
if (gpsm_grp_is_vbox((gpsm_grp_t *)item->item))
321
gpsm_vbox_insert((gpsm_grp_t *)item->item, copy,
322
0, gpsm_item_vsize(item->item));
323
else if (gpsm_grp_is_hbox((gpsm_grp_t *)item->item))
324
gpsm_hbox_insert((gpsm_grp_t *)item->item, copy,
325
gpsm_item_hsize(item->item), 0);
327
gnome_dialog_run_and_close(GNOME_DIALOG(
328
gnome_error_dialog(_("Cannot place item into irregular group"))));
329
gpsm_item_destroy(copy);
334
selected = g_list_next(selected);
336
deselect_all(active_swapfilegui);
339
/* Move all items in this group one level up in the tree
340
* (and delete the group itself). */
341
static void mergeparent_cb(GtkWidget *menu, GlameTreeItem *item)
343
struct glame_list_head *dummy;
344
gpsm_grp_t *group, *parent;
346
long group_hpos, group_vpos;
348
if (!GPSM_ITEM_IS_GRP(item->item))
350
deselect_all(active_swapfilegui);
352
group = (gpsm_grp_t *)item->item;
353
parent = gpsm_item_parent(group);
354
group_hpos = gpsm_item_hposition(group);
355
group_vpos = gpsm_item_vposition(group);
356
gpsm_item_remove((gpsm_item_t *)group);
358
gpsm_grp_safe_foreach_item(group, dummy, i) {
360
hpos = gpsm_item_hposition(i) + group_hpos;
361
vpos = gpsm_item_vposition(i) + group_vpos;
363
gpsm_item_place(parent, i, hpos, vpos);
365
gpsm_item_destroy((gpsm_item_t *)group);
368
/* Flatten the group using gpsm_flatten and replace it with the
369
* flattened group. */
370
static void flatten_cb(GtkWidget *menu, GlameTreeItem *item)
372
gpsm_grp_t *group, *parent;
376
if (!GPSM_ITEM_IS_GRP(item->item))
380
/* Flatten the active group. */
381
if (!(group = gpsm_flatten(old))) {
382
DPRINTF("gpsm_flatten failed!?\n");
386
/* Destroy the active group and insert the flattened one. */
387
parent = gpsm_item_parent(old);
388
hpos = gpsm_item_hposition(old);
389
vpos = gpsm_item_vposition(old);
390
gpsm_item_destroy(old);
391
gpsm_item_place(parent, (gpsm_item_t *)group, hpos, vpos);
392
deselect_all(active_swapfilegui);
395
/* Append an empty mono wave (without group) to the current vbox. */
396
static void addfile_cb(GtkWidget *menu, GlameTreeItem *item)
398
gpsm_swfile_t *swfile;
401
if (!GPSM_ITEM_IS_GRP(item->item)
402
|| !gpsm_grp_is_vbox((gpsm_grp_t *)item->item))
405
/* Create new gpsm swfile and insert it. */
406
swfile = gpsm_newswfile(_("Unnamed"));
407
gpsm_vbox_insert((gpsm_grp_t *)item->item,
408
(gpsm_item_t *)swfile,
409
0, gpsm_item_vsize(item->item));
411
/* Expand the parent widget. */
412
gtk_tree_item_expand(GTK_TREE_ITEM(item));
414
/* Find out which widget it got and open an edit field. */
415
grpw = glame_tree_find_gpsm_item(GTK_OBJECT(item), (gpsm_item_t *)swfile);
417
edit_tree_label(grpw);
418
deselect_all(active_swapfilegui);
421
/* Append an empty stereo wave (with group) to the current vbox. */
422
static void addstereo_cb(GtkWidget *menu, GlameTreeItem *item)
424
gpsm_swfile_t *left, *right;
428
if (!GPSM_ITEM_IS_GRP(item->item)
429
|| !gpsm_grp_is_vbox((gpsm_grp_t *)item->item))
432
/* Create new group and two gpsm swfiles and insert it. */
433
grp = gpsm_newgrp(_("Unnamed"));
434
left = gpsm_newswfile(_("left"));
435
gpsm_swfile_set_position(left, FILTER_PIPEPOS_LEFT);
436
right = gpsm_newswfile(_("right"));
437
gpsm_swfile_set_position(right, FILTER_PIPEPOS_RIGHT);
438
gpsm_vbox_insert(grp, (gpsm_item_t *)left, 0, 0);
439
gpsm_vbox_insert(grp, (gpsm_item_t *)right, 0, 1);
440
gpsm_vbox_insert((gpsm_grp_t *)item->item,
442
0, gpsm_item_vsize(item->item));
444
/* Expand the parent widget. */
445
gtk_tree_item_expand(GTK_TREE_ITEM(item));
447
/* Find out which widget it got and open an edit field. */
448
grpw = glame_tree_find_gpsm_item(GTK_OBJECT(item), (gpsm_item_t *)grp);
450
edit_tree_label(grpw);
451
deselect_all(active_swapfilegui);
454
static void group_cb(GtkWidget *menu, GlameTreeItem *item)
456
gpsm_grp_t *grp, *parent;
462
if (!GPSM_ITEM_IS_SWFILE(item->item))
465
/* Create new gpsm group, move item into it and re-insert
466
* it at old item position. */
467
parent = gpsm_item_parent(item->item);
468
tree = GTK_OBJECT(item->tree);
469
grp = gpsm_newgrp(gpsm_item_label(item->item));
471
hpos = gpsm_item_hposition(it);
472
vpos = gpsm_item_vposition(it);
473
gpsm_item_remove(it);
474
gpsm_item_place(grp, it, 0, 0);
475
gpsm_item_place(parent, (gpsm_item_t *)grp, hpos, vpos);
477
/* Find out which widget it got and open an edit field. */
478
grpw = glame_tree_find_gpsm_item(GTK_OBJECT(tree), (gpsm_item_t *)grp);
480
edit_tree_label(grpw);
481
deselect_all(active_swapfilegui);
484
static void addgroup_cb(GtkWidget *menu, GlameTreeItem *item)
489
if (!GPSM_ITEM_IS_GRP(item->item)
490
|| !gpsm_grp_is_vbox((gpsm_grp_t *)item->item))
493
/* Create new gpsm group. */
494
grp = gpsm_newgrp(_("Unnamed"));
495
gpsm_vbox_insert((gpsm_grp_t *)item->item, (gpsm_item_t *)grp,
496
0, gpsm_item_vsize(item->item));
498
/* Expand the parent widget. */
499
gtk_tree_item_expand(GTK_TREE_ITEM(item));
501
/* Find out which widget it got and open an edit field. */
502
grpw = glame_tree_find_gpsm_item(GTK_OBJECT(item), (gpsm_item_t *)grp);
504
edit_tree_label(grpw);
505
deselect_all(active_swapfilegui);
508
static void addclipboard_cb(GtkWidget *menu, GlameTreeItem *item)
513
if (!GPSM_ITEM_IS_GRP(item->item)
514
|| !gpsm_grp_is_vbox((gpsm_grp_t *)item->item))
517
/* Create new gpsm group. */
518
if (!(grp = clipboard_get())) {
519
gnome_dialog_run_and_close(GNOME_DIALOG(
520
gnome_error_dialog(_("Clipboard is empty"))));
523
gpsm_vbox_insert((gpsm_grp_t *)item->item, (gpsm_item_t *)grp,
524
0, gpsm_item_vsize(item->item));
526
/* Expand the parent widget. */
527
gtk_tree_item_expand(GTK_TREE_ITEM(item));
529
/* Find out which widget it got and open an edit field. */
530
grpw = glame_tree_find_gpsm_item(GTK_OBJECT(item), (gpsm_item_t *)grp);
532
edit_tree_label(grpw);
533
deselect_all(active_swapfilegui);
536
static void delete_cb(GtkWidget *menu, GlameTreeItem *item)
540
deselect_all(active_swapfilegui);
541
if (!(deleted = gpsm_find_grp_label(gpsm_root(), NULL, GPSM_GRP_DELETED_LABEL))) {
542
deleted = gpsm_newgrp(GPSM_GRP_DELETED_LABEL);
543
gpsm_item_place(gpsm_root(), (gpsm_item_t *)deleted,
544
0, GPSM_GRP_DELETED_VPOS);
545
} else if ((gpsm_item_t *)deleted == item->item) {
546
gpsm_item_destroy((gpsm_item_t *)deleted);
549
gpsm_item_place(deleted, item->item,
550
0, gpsm_item_vsize(deleted));
553
static void edit_cb(GtkWidget *menu, GlameTreeItem *item)
557
we = glame_waveedit_gui_new(gpsm_item_label(item->item), item->item);
559
gnome_dialog_run_and_close(GNOME_DIALOG(
560
gnome_error_dialog(_("Cannot open wave editor"))));
563
gtk_quit_add_destroy(1, GTK_OBJECT(we));
564
gtk_widget_show_all(GTK_WIDGET(we));
565
deselect_all(active_swapfilegui);
568
static void timeline_cb(GtkWidget *menu, GlameTreeItem *item)
570
static int warning_shown = 0;
573
tl = glame_timeline_new_with_window(gpsm_item_label(item->item),
574
(gpsm_grp_t *)item->item);
576
gnome_dialog_run_and_close(GNOME_DIALOG(
577
gnome_error_dialog(_("Cannot open timeline"))));
580
gtk_quit_add_destroy(1, GTK_OBJECT(tl));
581
gtk_widget_show_all(tl);
582
deselect_all(active_swapfilegui);
583
if (!warning_shown) {
584
gnome_dialog_run_and_close(GNOME_DIALOG(
585
gnome_warning_dialog_parented(_("The timeline is highly experimental\nand may cause unexpected effects\nwithin other parts of GLAME.\nBe warned."), GTK_WINDOW(tl))));
590
void changeString_cb(GtkEditable *wid, char *returnbuffer)
592
strncpy(returnbuffer, gtk_editable_get_chars(wid, 0, -1), 100);
594
static void export_cb(GtkWidget *menu, GlameTreeItem *item)
596
glame_export_dialog(item->item, NULL);
597
deselect_all(active_swapfilegui);
600
static void import_cb(GtkWidget *menu, GlameTreeItem *item)
602
gpsm_item_t *imported;
604
imported = glame_import_dialog(NULL);
608
if (gpsm_grp_is_vbox((gpsm_grp_t *)item->item)
609
&& gpsm_vbox_insert((gpsm_grp_t *)item->item, imported,
610
0, gpsm_item_vsize(item->item)) == 0)
612
if (gpsm_grp_is_hbox((gpsm_grp_t *)item->item)
613
&& gpsm_hbox_insert((gpsm_grp_t *)item->item, imported,
614
gpsm_item_hsize(item->item), 0) == 0)
617
gnome_dialog_run_and_close(GNOME_DIALOG(gnome_error_dialog(
618
_("Cannot place imported wave"))));
619
gpsm_item_destroy(imported);
624
* Drag & Drop state-machine.
625
* FIXME: better grab/release the pointer
627
extern GtkWidget *glame_appbar;
628
static void drag_start_stop_cb(GtkWidget *widget, GdkEventButton *event,
631
static GlameTreeItem *drag_widget = NULL;
632
static int mode = -1;
633
static int cursor_type = -1;
634
static GdkCursor *cursor = NULL;
635
GdkEventButton *bevent = (GdkEventButton *)event;
636
GdkEventCrossing *cevent = (GdkEventCrossing *)event;
637
gpsm_item_t *source, *dest;
640
if (event->type == GDK_BUTTON_PRESS) {
641
if (bevent->button != 1)
644
/* drag&drop start */
647
if (bevent->state & GDK_SHIFT_MASK) {
648
DPRINTF("SHIFT modifier\n");
650
gnome_appbar_push(GNOME_APPBAR(glame_appbar),
651
_("Drop into hbox"));
652
} else if (bevent->state & GDK_CONTROL_MASK) {
653
DPRINTF("CTRL modifier\n");
655
gnome_appbar_push(GNOME_APPBAR(glame_appbar),
656
_("Drop into vbox"));
658
DPRINTF("illegal modifier\n");
659
return; /* modifier not valid */
663
} else if (event->type == GDK_BUTTON_RELEASE) {
664
if (bevent->button != 1)
669
return; /* spurious event - ignore */
670
gnome_appbar_pop(GNOME_APPBAR(glame_appbar));
673
gdk_window_set_cursor(GTK_WIDGET(active_swapfilegui)->window, NULL);
674
gdk_cursor_destroy(cursor);
677
if (drag_widget == item)
680
source = drag_widget->item;
682
DPRINTF("drag&drop: %s on %s\n",
683
gpsm_item_label(drag_widget->item),
684
gpsm_item_label(item->item));
687
/* Mode 1 - hbox insertion either before
688
* dropped item or at tail (if dropped
690
if (GPSM_ITEM_IS_GRP(dest)) {
691
if (gpsm_hbox_insert((gpsm_grp_t *)dest, source,
692
gpsm_item_hsize(dest), 0) == -1)
693
DPRINTF("insertion failed\n");
695
if (gpsm_hbox_insert(gpsm_item_parent(dest), source,
696
gpsm_item_hposition(dest), 0) == -1)
697
DPRINTF("insertion failed\n");
699
} else if (mode == 2) {
700
/* Mode 2 - vbox insertion either before
701
* dropped item or at tail (if dropped
703
if (GPSM_ITEM_IS_GRP(dest)) {
704
if (gpsm_vbox_insert((gpsm_grp_t *)dest, source,
705
0, gpsm_item_vsize(dest)) == -1)
706
DPRINTF("insertion failed\n");
708
if (gpsm_vbox_insert(gpsm_item_parent(dest), source,
709
0, gpsm_item_vposition(dest)) == -1)
710
DPRINTF("insertion failed\n");
717
} else if (event->type == GDK_LEAVE_NOTIFY
718
&& ((GdkEventCrossing *)event)->mode == GDK_CROSSING_NORMAL) {
719
/* active_swapfilegui->active_item = NULL; */
721
} else if (event->type == GDK_ENTER_NOTIFY) {
723
active_swapfilegui->active_item = item;
724
if ((!drag_widget || !(cevent->state & GDK_BUTTON1_MASK))
727
gdk_window_set_cursor(GTK_WIDGET(active_swapfilegui)->window, NULL);
728
gdk_cursor_destroy(cursor);
736
if (GPSM_ITEM_IS_GRP(item->item))
737
parent = (gpsm_grp_t *)item->item;
739
parent = gpsm_item_parent(item->item);
740
if ((mode == 1 && !gpsm_grp_is_hbox(parent))
741
|| (mode == 2 && !gpsm_grp_is_vbox(parent)))
744
if (cursor_type == ok)
750
c = gdk_cursor_new(GDK_HAND2);
751
gdk_window_set_cursor(GTK_WIDGET(active_swapfilegui)->window, c);
753
gdk_cursor_destroy(cursor);
757
c = gdk_cursor_new(GDK_CIRCLE);
758
gdk_window_set_cursor(GTK_WIDGET(active_swapfilegui)->window, c);
760
gdk_cursor_destroy(cursor);
767
static void handle_swfile(glsig_handler_t *handler, long sig, va_list va)
770
case GPSM_SIG_ITEM_CHANGED: {
771
GlameTreeItem *itemw = GLAME_TREE_ITEM(glsig_handler_private(handler));
774
GLSIGH_GETARGS1(va, item);
775
if (itemw->item != item)
776
DERROR("Wrong itemw->item");
778
/* Update the item widget. */
779
glame_tree_item_update(GLAME_TREE_ITEM(itemw));
783
DPRINTF("Unhandled signal in swfile handler (%li)\n", sig);
787
static void handle_grp_add_treeitem(GtkObject *tree, gpsm_item_t *item)
789
GlameTreeItem *itemw, *nextw;
793
|| !(GPSM_ITEM_IS_SWFILE(item) || GPSM_ITEM_IS_GRP(item)))
796
/* Construct the item widget and register signal handlers
797
* to the new item. */
798
itemw = GLAME_TREE_ITEM(glame_tree_item_new(item));
799
if (GPSM_ITEM_IS_GRP(item)) {
800
itemw->handler = glsig_add_handler(
801
gpsm_item_emitter(item),
802
GPSM_SIG_GRP_NEWITEM|GPSM_SIG_GRP_REMOVEITEM|GPSM_SIG_ITEM_CHANGED,
804
/* drag&drop handlers */
805
gtk_signal_connect(GTK_OBJECT(itemw), "button_press_event",
806
(GtkSignalFunc)drag_start_stop_cb, itemw);
807
gtk_signal_connect(GTK_OBJECT(itemw), "button_release_event",
808
(GtkSignalFunc)drag_start_stop_cb, itemw);
809
gtk_signal_connect(GTK_OBJECT(itemw), "enter_notify_event",
810
(GtkSignalFunc)drag_start_stop_cb, itemw);
811
gtk_signal_connect(GTK_OBJECT(itemw), "leave_notify_event",
812
(GtkSignalFunc)drag_start_stop_cb, itemw);
813
} else if (GPSM_ITEM_IS_SWFILE(item)) {
814
itemw->handler = glsig_add_handler(
815
gpsm_item_emitter(item), GPSM_SIG_ITEM_CHANGED,
816
handle_swfile, itemw);
817
/* drag&drop handlers */
818
gtk_signal_connect(GTK_OBJECT(itemw), "button_press_event",
819
(GtkSignalFunc)drag_start_stop_cb, itemw);
820
gtk_signal_connect(GTK_OBJECT(itemw), "button_release_event",
821
(GtkSignalFunc)drag_start_stop_cb, itemw);
822
gtk_signal_connect(GTK_OBJECT(itemw), "enter_notify_event",
823
(GtkSignalFunc)drag_start_stop_cb, itemw);
824
gtk_signal_connect(GTK_OBJECT(itemw), "leave_notify_event",
825
(GtkSignalFunc)drag_start_stop_cb, itemw);
828
/* Register gtk handlers and append the item widget. */
829
gtk_signal_connect_after(GTK_OBJECT(itemw), "button_press_event",
830
(GtkSignalFunc)click_cb,(gpointer)NULL);
832
/* Look where we want to add the item (match gpsm list order). */
833
if (!gpsm_item_parent(item)
834
|| !(next = gpsm_grp_next(gpsm_item_parent(item), item))
835
|| !(nextw = glame_tree_find_gpsm_item(tree, next)))
836
glame_tree_append(tree, itemw);
838
glame_tree_insert(tree, itemw,
839
gtk_tree_child_position(
840
nextw->tree, GTK_WIDGET(nextw)));
842
glame_tree_item_update(itemw);
844
/* If item is a group we need to recurse down the items. */
845
if (GPSM_ITEM_IS_GRP(item)) {
847
gpsm_grp_foreach_item(item, it)
848
handle_grp_add_treeitem(GTK_OBJECT(itemw), it);
851
gtk_widget_show(GTK_WIDGET(itemw));
853
static void handle_grp(glsig_handler_t *handler, long sig, va_list va)
856
case GPSM_SIG_ITEM_CHANGED: {
857
GlameTreeItem *itemw = GLAME_TREE_ITEM(glsig_handler_private(handler));
860
GLSIGH_GETARGS1(va, item);
861
if (itemw->item != item)
862
DERROR("Wrong itemw->item");
864
/* Update the item widget. */
865
glame_tree_item_update(GLAME_TREE_ITEM(itemw));
868
case GPSM_SIG_GRP_REMOVEITEM: {
869
GtkObject *tree = GTK_OBJECT(glsig_handler_private(handler));
870
GlameTreeItem *itemw;
874
GLSIGH_GETARGS2(va, group, item);
876
/* Remove the item widget, if it is still there. */
877
if ((itemw = glame_tree_find_gpsm_item(tree, item)))
878
glame_tree_remove(GLAME_TREE_ITEM(itemw));
880
/* Note, that our signal handler will be deleted by
881
* the widgets destroy method. (hopefully gtk is sane here) */
885
case GPSM_SIG_GRP_NEWITEM: {
886
GtkObject *tree = GTK_OBJECT(glsig_handler_private(handler));
890
GLSIGH_GETARGS2(va, group, item);
891
if (GLAME_IS_TREE_ITEM(tree)
892
&& GLAME_TREE_ITEM(tree)->item != (gpsm_item_t *)group)
893
DERROR("Wrong tree->item");
895
/* Insert item (and subitems, if necessary). */
896
handle_grp_add_treeitem(tree, item);
901
DPRINTF("Unhandled signal in grp handler (%li)\n", sig);
905
static void handle_enterleave(GtkWidget *tree, GdkEventCrossing *event,
906
SwapfileGui *swapfile)
908
if (event->type == GDK_ENTER_NOTIFY)
909
active_swapfilegui = swapfile;
914
* Externally visible API and the SwapfileGui object (with guile access).
917
static SCM gls_swapfilegui_root_item()
919
if (!active_swapfilegui)
921
return gpsmitem2scm((gpsm_item_t *)active_swapfilegui->root);
924
static SCM gls_swapfilegui_active_item()
926
if (!active_swapfilegui)
928
if (!active_swapfilegui->active_item)
929
return gpsmitem2scm((gpsm_item_t *)active_swapfilegui->root);
930
return gpsmitem2scm((gpsm_item_t *)active_swapfilegui->active_item->item);
933
static SCM gls_swapfilegui_selected_items()
936
SCM s_items = SCM_LIST0;
937
if (!active_swapfilegui)
939
selected = GTK_TREE_SELECTION(active_swapfilegui->tree);
941
GlameTreeItem *i = GLAME_TREE_ITEM(selected->data);
942
s_items = gh_cons(gpsmitem2scm(i->item), s_items);
943
selected = g_list_next(selected);
948
void glame_swapfilegui_init()
950
gh_new_procedure0_0("swapfilegui-root-item",
951
gls_swapfilegui_root_item);
952
gh_new_procedure0_0("swapfilegui-active-item",
953
gls_swapfilegui_active_item);
954
gh_new_procedure0_0("swapfilegui-selected-items",
955
gls_swapfilegui_selected_items);
958
static void swapfile_gui_destroy(GtkObject *object)
960
SwapfileGui *swapfile = SWAPFILE_GUI(object);
961
GtkEventBox* parent_class;
962
parent_class = gtk_type_class(GTK_TYPE_EVENT_BOX);
963
GTK_OBJECT_CLASS(parent_class)->destroy(GTK_OBJECT(swapfile));
964
if (swapfile->gpsm_handler)
965
glsig_delete_handler(swapfile->gpsm_handler);
968
static void swapfile_gui_class_init(SwapfileGuiClass *class)
970
GtkObjectClass *object_class;
971
object_class = GTK_OBJECT_CLASS(class);
972
object_class->destroy = swapfile_gui_destroy;
975
static void swapfile_gui_init(SwapfileGui *swapfile)
977
swapfile->gpsm_handler = NULL;
978
swapfile->root = NULL;
979
swapfile->tree = NULL;
980
swapfile->active_item = NULL;
981
swapfile->accel_handler = 0;
982
swapfile->app = NULL;
985
GtkType swapfile_gui_get_type(void)
987
static GtkType swapfile_gui_type = 0;
989
if (!swapfile_gui_type){
990
GtkTypeInfo swapfile_gui_info = {
993
sizeof(SwapfileGuiClass),
994
(GtkClassInitFunc)swapfile_gui_class_init,
995
(GtkObjectInitFunc)swapfile_gui_init,
996
NULL,NULL,(GtkClassInitFunc)NULL,};
997
swapfile_gui_type = gtk_type_unique(
998
GTK_TYPE_EVENT_BOX, &swapfile_gui_info);
999
gtk_type_set_chunk_alloc(swapfile_gui_type, 8);
1002
return swapfile_gui_type;
1005
SwapfileGui *glame_swapfile_widget_new(gpsm_grp_t *root)
1007
SwapfileGui *swapfile;
1013
/* Create the toplevel objects. */
1014
swapfile = SWAPFILE_GUI(gtk_type_new(swapfile_gui_get_type()));
1015
swapfile->root = root;
1016
swapfile->tree = gtk_tree_new();
1017
gtk_container_add(GTK_CONTAINER(swapfile), swapfile->tree);
1018
gtk_tree_set_view_mode(GTK_TREE(swapfile->tree), GTK_TREE_VIEW_LINE);
1019
gtk_tree_set_view_lines(GTK_TREE(swapfile->tree), TRUE);
1020
gtk_tree_set_selection_mode(GTK_TREE(swapfile->tree),
1021
GTK_SELECTION_MULTIPLE);
1024
MULTIPLE -- multiple
1028
/* Add the root group and cause "newitem" signals to be sent
1030
swapfile->gpsm_handler = glsig_add_handler(gpsm_item_emitter(root),
1031
GPSM_SIG_GRP_NEWITEM|GPSM_SIG_GRP_REMOVEITEM,
1032
handle_grp, swapfile->tree);
1034
/* Track the active swapfilegui via enter/leave events. */
1035
gtk_signal_connect(GTK_OBJECT(swapfile), "enter_notify_event",
1036
(GtkSignalFunc)handle_enterleave, swapfile);
1038
/* Add all existing childs of the root group to the tree. */
1039
gpsm_grp_foreach_item(root, item)
1040
handle_grp_add_treeitem(GTK_OBJECT(swapfile->tree), item);
1042
gtk_widget_show(swapfile->tree);
1043
active_swapfilegui = swapfile;