1 /*
2 * Copyright (C) 2021 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of Zrythm
5 *
6 * Zrythm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Zrythm is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <time.h>
21 #include <sys/time.h>
22
23 #include "actions/tracklist_selections.h"
24 #include "actions/undoable_action.h"
25 #include "actions/undo_manager.h"
26 #include "audio/master_track.h"
27 #include "audio/meter.h"
28 #include "audio/port_connections_manager.h"
29 #include "audio/track.h"
30 #include "gui/widgets/balance_control.h"
31 #include "gui/widgets/bot_dock_edge.h"
32 #include "gui/widgets/center_dock.h"
33 #include "gui/widgets/folder_channel.h"
34 #include "gui/widgets/color_area.h"
35 #include "gui/widgets/fader_buttons.h"
36 #include "gui/widgets/editable_label.h"
37 #include "gui/widgets/expander_box.h"
38 #include "gui/widgets/meter.h"
39 #include "gui/widgets/mixer.h"
40 #include "gui/widgets/fader.h"
41 #include "gui/widgets/knob.h"
42 #include "gui/widgets/plugin_strip_expander.h"
43 #include "gui/widgets/route_target_selector.h"
44 #include "plugins/lv2_plugin.h"
45 #include "project.h"
46 #include "utils/error.h"
47 #include "utils/flags.h"
48 #include "utils/gtk.h"
49 #include "utils/math.h"
50 #include "utils/resources.h"
51 #include "utils/symap.h"
52 #include "utils/ui.h"
53 #include "zrythm.h"
54 #include "zrythm_app.h"
55
56 #include <gtk/gtk.h>
57
58 #include <glib/gi18n.h>
59
G_DEFINE_TYPE(FolderChannelWidget,folder_channel_widget,GTK_TYPE_EVENT_BOX)60 G_DEFINE_TYPE (
61 FolderChannelWidget, folder_channel_widget,
62 GTK_TYPE_EVENT_BOX)
63
64 static void
65 on_drag_data_received (
66 GtkWidget *widget,
67 GdkDragContext *context,
68 gint x,
69 gint y,
70 GtkSelectionData *data,
71 guint info,
72 guint time,
73 FolderChannelWidget * self)
74 {
75 g_message ("drag data received");
76 Track * this = self->track;
77
78 /* determine if moving or copying */
79 GdkDragAction action =
80 gdk_drag_context_get_selected_action (
81 context);
82
83 int w =
84 gtk_widget_get_allocated_width (widget);
85
86 /* determine position to move to */
87 int pos;
88 if (x < w / 2)
89 {
90 if (this->pos <=
91 MW_MIXER->start_drag_track->pos)
92 pos = this->pos;
93 else
94 {
95 Track * prev =
96 tracklist_get_prev_visible_track (
97 TRACKLIST, this);
98 pos =
99 prev ? prev->pos : this->pos;
100 }
101 }
102 else
103 {
104 if (this->pos >=
105 MW_MIXER->start_drag_track->pos)
106 pos = this->pos;
107 else
108 {
109 Track * next =
110 tracklist_get_next_visible_track (
111 TRACKLIST, this);
112 pos =
113 next ? next->pos : this->pos;
114 }
115 }
116
117 tracklist_selections_select_foldable_children (
118 TRACKLIST_SELECTIONS);
119
120 GError * err = NULL;
121 bool ret;
122 if (action == GDK_ACTION_COPY)
123 {
124 ret =
125 tracklist_selections_action_perform_copy (
126 TRACKLIST_SELECTIONS,
127 PORT_CONNECTIONS_MGR, pos, &err);
128 }
129 else
130 {
131 ret =
132 tracklist_selections_action_perform_move (
133 TRACKLIST_SELECTIONS,
134 PORT_CONNECTIONS_MGR, pos, &err);
135 }
136
137 if (!ret)
138 {
139 HANDLE_ERROR (
140 err, "%s",
141 _("Failed to move or copy track(s)"));
142 }
143 }
144
145 static void
on_drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * data,guint info,guint time,FolderChannelWidget * self)146 on_drag_data_get (
147 GtkWidget *widget,
148 GdkDragContext *context,
149 GtkSelectionData *data,
150 guint info,
151 guint time,
152 FolderChannelWidget * self)
153 {
154 g_debug ("drag data get");
155
156 /* Not really needed since the selections are
157 * used. just send master */
158 gtk_selection_data_set (
159 data,
160 gdk_atom_intern_static_string (
161 TARGET_ENTRY_TRACK),
162 32,
163 (const guchar *) &P_MASTER_TRACK,
164 sizeof (P_MASTER_TRACK));
165 }
166
167 /**
168 * For drag n drop.
169 */
170 static void
on_dnd_drag_begin(GtkWidget * widget,GdkDragContext * context,FolderChannelWidget * self)171 on_dnd_drag_begin (
172 GtkWidget *widget,
173 GdkDragContext *context,
174 FolderChannelWidget * self)
175 {
176 Track * track = self->track;
177 self->selected_in_dnd = 1;
178 MW_MIXER->start_drag_track = track;
179
180 if (self->n_press == 1)
181 {
182 int ctrl = 0, selected = 0;
183
184 ctrl = self->ctrl_held_at_start;
185
186 if (tracklist_selections_contains_track (
187 TRACKLIST_SELECTIONS,
188 track))
189 selected = 1;
190
191 /* no control & not selected */
192 if (!ctrl && !selected)
193 {
194 tracklist_selections_select_single (
195 TRACKLIST_SELECTIONS,
196 track, F_PUBLISH_EVENTS);
197 }
198 else if (!ctrl && selected)
199 { }
200 else if (ctrl && !selected)
201 tracklist_selections_add_track (
202 TRACKLIST_SELECTIONS, track, 1);
203 }
204 }
205
206 /**
207 * Highlights/unhighlights the folder_channels
208 * appropriately.
209 */
210 static void
do_highlight(FolderChannelWidget * self,gint x,gint y)211 do_highlight (
212 FolderChannelWidget * self,
213 gint x,
214 gint y)
215 {
216 /* if we are closer to the start of selection than
217 * the end */
218 int w =
219 gtk_widget_get_allocated_width (
220 GTK_WIDGET (self));
221 if (x < w / 2)
222 {
223 /* highlight left */
224 gtk_drag_highlight (
225 GTK_WIDGET (
226 self->highlight_left_box));
227 gtk_widget_set_size_request (
228 GTK_WIDGET (
229 self->highlight_left_box),
230 2, -1);
231
232 /* unhilight right */
233 gtk_drag_unhighlight (
234 GTK_WIDGET (
235 self->highlight_right_box));
236 gtk_widget_set_size_request (
237 GTK_WIDGET (
238 self->highlight_right_box),
239 -1, -1);
240 }
241 else
242 {
243 /* highlight right */
244 gtk_drag_highlight (
245 GTK_WIDGET (
246 self->highlight_right_box));
247 gtk_widget_set_size_request (
248 GTK_WIDGET (
249 self->highlight_right_box),
250 2, -1);
251
252 /* unhilight left */
253 gtk_drag_unhighlight (
254 GTK_WIDGET (
255 self->highlight_left_box));
256 gtk_widget_set_size_request (
257 GTK_WIDGET (
258 self->highlight_left_box),
259 -1, -1);
260 }
261 }
262
263 static void
on_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,FolderChannelWidget * self)264 on_drag_motion (
265 GtkWidget *widget,
266 GdkDragContext *context,
267 gint x,
268 gint y,
269 guint time,
270 FolderChannelWidget * self)
271 {
272 GdkModifierType mask;
273 z_gtk_widget_get_mask (
274 widget, &mask);
275 if (mask & GDK_CONTROL_MASK)
276 gdk_drag_status (context, GDK_ACTION_COPY, time);
277 else
278 gdk_drag_status (context, GDK_ACTION_MOVE, time);
279
280 do_highlight (self, x, y);
281 }
282
283 static void
on_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time,FolderChannelWidget * self)284 on_drag_leave (
285 GtkWidget * widget,
286 GdkDragContext * context,
287 guint time,
288 FolderChannelWidget * self)
289 {
290 g_message ("on_drag_leave");
291
292 /*do_highlight (self);*/
293 gtk_drag_unhighlight (
294 GTK_WIDGET (self->highlight_left_box));
295 gtk_widget_set_size_request (
296 GTK_WIDGET (self->highlight_left_box),
297 -1, -1);
298 gtk_drag_unhighlight (
299 GTK_WIDGET (self->highlight_right_box));
300 gtk_widget_set_size_request (
301 GTK_WIDGET (self->highlight_right_box),
302 -1, -1);
303 }
304
305 /**
306 * Callback when somewhere in the folder_channel is
307 * pressed.
308 *
309 * Only responsible for setting the tracklist
310 * selection and should not do anything else.
311 */
312 static void
on_whole_folder_channel_press(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,FolderChannelWidget * self)313 on_whole_folder_channel_press (
314 GtkGestureMultiPress *gesture,
315 gint n_press,
316 gdouble x,
317 gdouble y,
318 FolderChannelWidget * self)
319 {
320 self->n_press = n_press;
321
322 GdkModifierType state_mask =
323 ui_get_state_mask (
324 GTK_GESTURE (gesture));
325 self->ctrl_held_at_start =
326 state_mask & GDK_CONTROL_MASK;
327 }
328
329 static void
on_drag_begin(GtkGestureDrag * gesture,gdouble start_x,gdouble start_y,FolderChannelWidget * self)330 on_drag_begin (
331 GtkGestureDrag * gesture,
332 gdouble start_x,
333 gdouble start_y,
334 FolderChannelWidget * self)
335 {
336 self->selected_in_dnd = 0;
337 self->dragged = 0;
338 }
339
340 static void
on_drag_update(GtkGestureDrag * gesture,gdouble offset_x,gdouble offset_y,FolderChannelWidget * self)341 on_drag_update (
342 GtkGestureDrag * gesture,
343 gdouble offset_x,
344 gdouble offset_y,
345 FolderChannelWidget * self)
346 {
347 self->dragged = true;
348 }
349
350 static bool
on_btn_release(GtkWidget * widget,GdkEventButton * event,FolderChannelWidget * self)351 on_btn_release (
352 GtkWidget * widget,
353 GdkEventButton * event,
354 FolderChannelWidget * self)
355 {
356 if (self->dragged || self->selected_in_dnd)
357 return false;
358
359 Track * track = self->track;
360 if (self->n_press == 1)
361 {
362 PROJECT->last_selection =
363 SELECTION_TYPE_TRACKLIST;
364
365 bool ctrl = event->state & GDK_CONTROL_MASK;
366 bool shift = event->state & GDK_SHIFT_MASK;
367 tracklist_selections_handle_click (
368 track, ctrl, shift, self->dragged);
369 }
370
371 return FALSE;
372 }
373
374 static void
refresh_color(FolderChannelWidget * self)375 refresh_color (
376 FolderChannelWidget * self)
377 {
378 Track * track = self->track;
379 color_area_widget_setup_track (
380 self->color_top, track);
381 color_area_widget_set_color (
382 self->color_top, &track->color);
383 color_area_widget_set_color (
384 self->color_left, &track->color);
385 }
386
387 static void
setup_folder_channel_icon(FolderChannelWidget * self)388 setup_folder_channel_icon (
389 FolderChannelWidget * self)
390 {
391 Track * track = self->track;
392 gtk_image_set_from_icon_name (
393 self->icon, track->icon_name,
394 GTK_ICON_SIZE_BUTTON);
395 gtk_widget_set_sensitive (
396 GTK_WIDGET (self->icon),
397 track_is_enabled (track));
398 }
399
400 static void
refresh_name(FolderChannelWidget * self)401 refresh_name (FolderChannelWidget * self)
402 {
403 Track * track = self->track;
404 if (track_is_enabled (track))
405 {
406 gtk_label_set_text (
407 GTK_LABEL (self->name->label), track->name);
408 }
409 else
410 {
411 char * markup =
412 g_strdup_printf (
413 "<span foreground=\"grey\">%s</span>",
414 track->name);
415 gtk_label_set_markup (
416 GTK_LABEL (self->name->label), markup);
417 }
418
419 gtk_label_set_angle (self->name->label, 90);
420 }
421
422 /**
423 * Updates everything on the widget.
424 *
425 * It is reduntant but keeps code organized. Should fix if it causes lags.
426 */
427 void
folder_channel_widget_refresh(FolderChannelWidget * self)428 folder_channel_widget_refresh (
429 FolderChannelWidget * self)
430 {
431 refresh_name (self);
432 refresh_color (self);
433 setup_folder_channel_icon (self);
434 fader_buttons_widget_refresh (
435 self->fader_buttons, self->track);
436
437 #define ICON_NAME_FOLD "fluentui-folder-regular"
438 #define ICON_NAME_FOLD_OPEN "fluentui-folder-open-regular"
439
440 Track * track = self->track;
441 z_gtk_button_set_icon_name (
442 GTK_BUTTON (self->fold_toggle),
443 track->folded ?
444 ICON_NAME_FOLD : ICON_NAME_FOLD_OPEN);
445
446 #undef ICON_NAME_FOLD
447 #undef ICON_NAME_FOLD_OPEN
448
449 g_signal_handler_block (
450 self->fold_toggle,
451 self->fold_toggled_handler_id);
452 gtk_toggle_button_set_active (
453 self->fold_toggle, !track->folded);
454 g_signal_handler_unblock (
455 self->fold_toggle,
456 self->fold_toggled_handler_id);
457
458 if (track_is_selected (track))
459 {
460 /* set selected or not */
461 gtk_widget_set_state_flags (
462 GTK_WIDGET (self),
463 GTK_STATE_FLAG_SELECTED, 0);
464 }
465 else
466 {
467 gtk_widget_unset_state_flags (
468 GTK_WIDGET (self),
469 GTK_STATE_FLAG_SELECTED);
470 }
471 }
472
473 static void
show_context_menu(FolderChannelWidget * self)474 show_context_menu (
475 FolderChannelWidget * self)
476 {
477 GtkWidget *menu;
478 GtkMenuItem *menuitem;
479 menu = gtk_menu_new();
480 Track * track = self->track;
481
482 #define APPEND(mi) \
483 gtk_menu_shell_append ( \
484 GTK_MENU_SHELL (menu), \
485 GTK_WIDGET (menuitem));
486
487 #define ADD_SEPARATOR \
488 menuitem = \
489 GTK_MENU_ITEM ( \
490 gtk_separator_menu_item_new ()); \
491 gtk_widget_set_visible ( \
492 GTK_WIDGET (menuitem), true); \
493 APPEND (menuitem)
494
495 int num_selected =
496 TRACKLIST_SELECTIONS->num_tracks;
497
498 if (num_selected > 0)
499 {
500 char * str;
501
502 if (track->type != TRACK_TYPE_MASTER &&
503 track->type != TRACK_TYPE_CHORD &&
504 track->type != TRACK_TYPE_MARKER &&
505 track->type != TRACK_TYPE_TEMPO)
506 {
507 /* delete track */
508 if (num_selected == 1)
509 str =
510 g_strdup (_("_Delete Track"));
511 else
512 str =
513 g_strdup (_("_Delete Tracks"));
514 menuitem =
515 z_gtk_create_menu_item (
516 str, "edit-delete", F_NO_TOGGLE,
517 "app.delete-selected-tracks");
518 g_free (str);
519 APPEND (menuitem);
520
521 /* duplicate track */
522 if (num_selected == 1)
523 str =
524 g_strdup (_("_Duplicate Track"));
525 else
526 str =
527 g_strdup (_("_Duplicate Tracks"));
528 menuitem =
529 z_gtk_create_menu_item (
530 str, "edit-copy", F_NO_TOGGLE,
531 "app.duplicate-selected-tracks");
532 g_free (str);
533 APPEND (menuitem);
534 }
535
536 menuitem =
537 z_gtk_create_menu_item (
538 num_selected == 1 ?
539 _("Hide Track") :
540 _("Hide Tracks"),
541 "view-hidden", F_NO_TOGGLE,
542 "app.hide-selected-tracks");
543 APPEND (menuitem);
544
545 menuitem =
546 z_gtk_create_menu_item (
547 num_selected == 1 ?
548 _("Pin/Unpin Track") :
549 _("Pin/Unpin Tracks"),
550 "window-pin", F_NO_TOGGLE,
551 "app.pin-selected-tracks");
552 APPEND (menuitem);
553 }
554
555 /* add solo/mute/listen */
556 ADD_SEPARATOR;
557
558 if (tracklist_selections_contains_soloed_track (
559 TRACKLIST_SELECTIONS, F_NO_SOLO))
560 {
561 menuitem =
562 z_gtk_create_menu_item (
563 _("Solo"), "solo", F_NO_TOGGLE,
564 "app.solo-selected-tracks");
565 APPEND (menuitem);
566 }
567 if (tracklist_selections_contains_soloed_track (
568 TRACKLIST_SELECTIONS, F_SOLO))
569 {
570 menuitem =
571 z_gtk_create_menu_item (
572 _("Unsolo"), "unsolo", F_NO_TOGGLE,
573 "app.unsolo-selected-tracks");
574 APPEND (menuitem);
575 }
576
577 if (tracklist_selections_contains_muted_track (
578 TRACKLIST_SELECTIONS, F_NO_MUTE))
579 {
580 menuitem =
581 z_gtk_create_menu_item (
582 _("Mute"), "mute", F_NO_TOGGLE,
583 "app.mute-selected-tracks");
584 APPEND (menuitem);
585 }
586 if (tracklist_selections_contains_muted_track (
587 TRACKLIST_SELECTIONS, F_MUTE))
588 {
589 menuitem =
590 z_gtk_create_menu_item (
591 _("Unmute"), "unmute", F_NO_TOGGLE,
592 "app.unmute-selected-tracks");
593 APPEND (menuitem);
594 }
595
596 if (tracklist_selections_contains_listened_track (
597 TRACKLIST_SELECTIONS, F_NO_LISTEN))
598 {
599 menuitem =
600 z_gtk_create_menu_item (
601 _("Listen"), "listen",
602 F_NO_TOGGLE,
603 "app.listen-selected-tracks");
604 APPEND (menuitem);
605 }
606 if (tracklist_selections_contains_listened_track (
607 TRACKLIST_SELECTIONS, F_LISTEN))
608 {
609 menuitem =
610 z_gtk_create_menu_item (
611 _("Unlisten"), "unlisten",
612 F_NO_TOGGLE,
613 "app.unlisten-selected-tracks");
614 APPEND (menuitem);
615 }
616
617 /* add enable/disable */
618 if (tracklist_selections_contains_enabled_track (
619 TRACKLIST_SELECTIONS, F_ENABLED))
620 {
621 menuitem =
622 z_gtk_create_menu_item (
623 _("Disable"), "offline",
624 F_NO_TOGGLE,
625 "app.disable-selected-tracks");
626 APPEND (menuitem);
627 }
628 else
629 {
630 menuitem =
631 z_gtk_create_menu_item (
632 _("Enable"), "online",
633 F_NO_TOGGLE,
634 "app.enable-selected-tracks");
635 APPEND (menuitem);
636 }
637
638 ADD_SEPARATOR;
639 menuitem =
640 z_gtk_create_menu_item (
641 _("Change color..."), "color-fill",
642 F_NO_TOGGLE, "app.change-track-color");
643 APPEND (menuitem);
644
645 #undef APPEND
646 #undef ADD_SEPARATOR
647
648 gtk_menu_attach_to_widget (
649 GTK_MENU (menu),
650 GTK_WIDGET (self), NULL);
651 gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
652 }
653
654 static void
on_right_click(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,FolderChannelWidget * self)655 on_right_click (
656 GtkGestureMultiPress * gesture,
657 gint n_press,
658 gdouble x,
659 gdouble y,
660 FolderChannelWidget * self)
661 {
662 GdkModifierType state_mask =
663 ui_get_state_mask (GTK_GESTURE (gesture));
664
665 Track * track = self->track;
666 if (!track_is_selected (track))
667 {
668 if (state_mask & GDK_SHIFT_MASK ||
669 state_mask & GDK_CONTROL_MASK)
670 {
671 track_select (
672 track, F_SELECT, 0, 1);
673 }
674 else
675 {
676 track_select (
677 track, F_SELECT, 1, 1);
678 }
679 }
680 if (n_press == 1)
681 {
682 show_context_menu (self);
683 }
684 }
685
686 static void
on_fold_toggled(GtkToggleButton * toggle,FolderChannelWidget * self)687 on_fold_toggled (
688 GtkToggleButton * toggle,
689 FolderChannelWidget * self)
690 {
691 bool folded =
692 !gtk_toggle_button_get_active (toggle);
693
694 track_set_folded (
695 self->track, folded,
696 F_TRIGGER_UNDO, F_AUTO_SELECT,
697 F_PUBLISH_EVENTS);
698 }
699
700 static void
on_destroy(FolderChannelWidget * self)701 on_destroy (
702 FolderChannelWidget * self)
703 {
704 folder_channel_widget_tear_down (self);
705 }
706
707 FolderChannelWidget *
folder_channel_widget_new(Track * track)708 folder_channel_widget_new (
709 Track * track)
710 {
711 FolderChannelWidget * self =
712 g_object_new (FOLDER_CHANNEL_WIDGET_TYPE, NULL);
713 self->track = track;
714
715 setup_folder_channel_icon (self);
716 editable_label_widget_setup (
717 self->name, track,
718 (GenericStringGetter) track_get_name,
719 (GenericStringSetter)
720 track_set_name_with_action);
721
722 self->fold_toggled_handler_id =
723 g_signal_connect (
724 self->fold_toggle, "toggled",
725 G_CALLBACK (on_fold_toggled), self);
726 g_signal_connect (
727 self, "destroy",
728 G_CALLBACK (on_destroy), NULL);
729
730 folder_channel_widget_refresh (self);
731
732 g_object_ref (self);
733
734 self->setup = true;
735
736 return self;
737 }
738
739 /**
740 * Prepare for finalization.
741 */
742 void
folder_channel_widget_tear_down(FolderChannelWidget * self)743 folder_channel_widget_tear_down (
744 FolderChannelWidget * self)
745 {
746 if (self->setup)
747 {
748 g_object_unref (self);
749 self->track->folder_ch_widget = NULL;
750 self->setup = false;
751 }
752 }
753
754 static void
folder_channel_widget_class_init(FolderChannelWidgetClass * _klass)755 folder_channel_widget_class_init (
756 FolderChannelWidgetClass * _klass)
757 {
758 GtkWidgetClass * klass =
759 GTK_WIDGET_CLASS (_klass);
760 resources_set_class_template (
761 klass, "folder_channel.ui");
762 gtk_widget_class_set_css_name (
763 klass, "folder_channel");
764
765 #define BIND_CHILD(x) \
766 gtk_widget_class_bind_template_child ( \
767 klass, FolderChannelWidget, x)
768
769 BIND_CHILD (color_left);
770 BIND_CHILD (color_top);
771 BIND_CHILD (grid);
772 BIND_CHILD (icon_and_name_event_box);
773 BIND_CHILD (name);
774 BIND_CHILD (fader_buttons);
775 BIND_CHILD (icon);
776 BIND_CHILD (fold_toggle);
777 BIND_CHILD (highlight_left_box);
778 BIND_CHILD (highlight_right_box);
779
780 #undef BIND_CHILD
781 }
782
783 static void
folder_channel_widget_init(FolderChannelWidget * self)784 folder_channel_widget_init (
785 FolderChannelWidget * self)
786 {
787 g_type_ensure (FADER_BUTTONS_WIDGET_TYPE);
788 g_type_ensure (COLOR_AREA_WIDGET_TYPE);
789
790 gtk_widget_init_template (GTK_WIDGET (self));
791
792 /* set font sizes */
793 GtkStyleContext * context =
794 gtk_widget_get_style_context (
795 GTK_WIDGET (self->name->label));
796 gtk_style_context_add_class (
797 context, "folder_channel_label");
798 gtk_label_set_max_width_chars (
799 self->name->label, 10);
800
801 char * entry_track = g_strdup (TARGET_ENTRY_TRACK);
802 GtkTargetEntry entries[] = {
803 {
804 entry_track, GTK_TARGET_SAME_APP,
805 symap_map (ZSYMAP, TARGET_ENTRY_TRACK),
806 },
807 };
808
809 /* set as drag source for track */
810 gtk_drag_source_set (
811 GTK_WIDGET (self->icon_and_name_event_box),
812 GDK_BUTTON1_MASK,
813 entries, G_N_ELEMENTS (entries),
814 GDK_ACTION_MOVE | GDK_ACTION_COPY);
815
816 /* set as drag dest for folder_channel (the folder_channel will
817 * be moved based on which half it was dropped in,
818 * left or right) */
819 gtk_drag_dest_set (
820 GTK_WIDGET (self),
821 GTK_DEST_DEFAULT_MOTION |
822 GTK_DEST_DEFAULT_DROP,
823 entries, G_N_ELEMENTS (entries),
824 GDK_ACTION_MOVE | GDK_ACTION_COPY);
825 g_free (entry_track);
826
827 self->mp =
828 GTK_GESTURE_MULTI_PRESS (
829 gtk_gesture_multi_press_new (
830 GTK_WIDGET (self)));
831 self->drag =
832 GTK_GESTURE_DRAG (
833 gtk_gesture_drag_new (
834 GTK_WIDGET (
835 self)));
836
837 gtk_widget_set_hexpand (
838 GTK_WIDGET (self), 0);
839
840 self->right_mouse_mp =
841 GTK_GESTURE_MULTI_PRESS (
842 gtk_gesture_multi_press_new (
843 GTK_WIDGET (self->icon_and_name_event_box)));
844 gtk_gesture_single_set_button (
845 GTK_GESTURE_SINGLE (self->right_mouse_mp),
846 GDK_BUTTON_SECONDARY);
847
848 g_signal_connect (
849 G_OBJECT (self->mp), "pressed",
850 G_CALLBACK (on_whole_folder_channel_press), self);
851 g_signal_connect (
852 G_OBJECT (self->drag), "drag-begin",
853 G_CALLBACK (on_drag_begin), self);
854 g_signal_connect (
855 G_OBJECT (self->drag), "drag-update",
856 G_CALLBACK (on_drag_update), self);
857 g_signal_connect_after (
858 GTK_WIDGET (self->icon_and_name_event_box),
859 "drag-begin",
860 G_CALLBACK(on_dnd_drag_begin), self);
861 g_signal_connect (
862 GTK_WIDGET (self), "drag-data-received",
863 G_CALLBACK(on_drag_data_received), self);
864 g_signal_connect (
865 GTK_WIDGET (self->icon_and_name_event_box),
866 "drag-data-get",
867 G_CALLBACK (on_drag_data_get), self);
868 g_signal_connect (
869 GTK_WIDGET (self), "drag-motion",
870 G_CALLBACK (on_drag_motion), self);
871 g_signal_connect (
872 GTK_WIDGET (self), "drag-leave",
873 G_CALLBACK (on_drag_leave), self);
874 g_signal_connect (
875 GTK_WIDGET (self), "button-release-event",
876 G_CALLBACK (on_btn_release), self);
877 g_signal_connect (
878 G_OBJECT (self->right_mouse_mp), "pressed",
879 G_CALLBACK (on_right_click), self);
880 }
881