1 /*
2  * Copyright (C) 2019-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 this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 /**
21  * \file
22  *
23  * GAction actions.
24  */
25 
26 #include "zrythm-config.h"
27 
28 #include "actions/actions.h"
29 #include "actions/arranger_selections.h"
30 #include "actions/undo_manager.h"
31 #include "actions/tracklist_selections.h"
32 #include "actions/range_action.h"
33 #include "audio/audio_function.h"
34 #include "audio/automation_function.h"
35 #include "audio/graph.h"
36 #include "audio/graph_export.h"
37 #include "audio/instrument_track.h"
38 #include "audio/midi.h"
39 #include "audio/midi_function.h"
40 #include "audio/router.h"
41 #include "audio/tempo_track.h"
42 #include "audio/track.h"
43 #include "audio/transport.h"
44 #include "gui/backend/clipboard.h"
45 #include "gui/backend/event.h"
46 #include "gui/backend/event_manager.h"
47 #include "gui/backend/midi_arranger_selections.h"
48 #include "gui/backend/timeline_selections.h"
49 #include "gui/backend/tracklist_selections.h"
50 #include "gui/widgets/arranger.h"
51 #include "gui/widgets/automation_arranger.h"
52 #include "gui/widgets/automation_editor_space.h"
53 #include "gui/widgets/bot_dock_edge.h"
54 #include "gui/widgets/bot_bar.h"
55 #include "gui/widgets/center_dock.h"
56 #include "gui/widgets/channel_slot.h"
57 #include "gui/widgets/chord_arranger.h"
58 #include "gui/widgets/chord_editor_space.h"
59 #include "gui/widgets/clip_editor.h"
60 #include "gui/widgets/clip_editor_inner.h"
61 #include "gui/widgets/dialogs/create_project_dialog.h"
62 #include "gui/widgets/dialogs/about_dialog.h"
63 #include "gui/widgets/dialogs/object_color_chooser_dialog.h"
64 #include "gui/widgets/dialogs/string_entry_dialog.h"
65 #include "gui/widgets/event_viewer.h"
66 #include "gui/widgets/dialogs/export_dialog.h"
67 #include "gui/widgets/file_browser_window.h"
68 #include "gui/widgets/foldable_notebook.h"
69 #include "gui/widgets/header.h"
70 #include "gui/widgets/left_dock_edge.h"
71 #include "gui/widgets/log_viewer.h"
72 #include "gui/widgets/main_window.h"
73 #include "gui/widgets/main_notebook.h"
74 #include "gui/widgets/midi_arranger.h"
75 #include "gui/widgets/midi_modifier_arranger.h"
76 #include "gui/widgets/editor_ruler.h"
77 #include "gui/widgets/midi_editor_space.h"
78 #include "gui/widgets/mixer.h"
79 #include "gui/widgets/preferences.h"
80 #include "gui/widgets/project_assistant.h"
81 #include "gui/widgets/dialogs/quantize_dialog.h"
82 #include "gui/widgets/right_dock_edge.h"
83 #include "gui/widgets/ruler.h"
84 #ifdef HAVE_GUILE
85 #include "gui/widgets/scripting_window.h"
86 #endif
87 #include "gui/widgets/timeline_arranger.h"
88 #include "gui/widgets/timeline_bg.h"
89 #include "gui/widgets/timeline_bot_box.h"
90 #include "gui/widgets/timeline_minimap.h"
91 #include "gui/widgets/timeline_panel.h"
92 #include "gui/widgets/timeline_ruler.h"
93 #include "gui/widgets/toolbox.h"
94 #include "gui/widgets/tracklist.h"
95 #include "plugins/plugin_manager.h"
96 #include "project.h"
97 #include "settings/settings.h"
98 #include "utils/dialogs.h"
99 #include "utils/error.h"
100 #include "utils/flags.h"
101 #include "utils/gtk.h"
102 #include "utils/io.h"
103 #include "utils/localization.h"
104 #include "utils/log.h"
105 #include "utils/resources.h"
106 #include "utils/stack.h"
107 #include "utils/string.h"
108 #include "utils/system.h"
109 #include "zrythm_app.h"
110 
111 #include <gtk/gtk.h>
112 
113 #include <glib/gi18n.h>
114 
115 static GtkWindow * file_browser_window = NULL;
116 
117 #define DEFINE_SIMPLE(x) \
118 void \
119 x ( \
120   GSimpleAction * action, \
121   GVariant *      variant, \
122   gpointer        user_data) \
123 
124 void
actions_set_app_action_enabled(const char * action_name,const bool enabled)125 actions_set_app_action_enabled (
126   const char * action_name,
127   const bool   enabled)
128 {
129   GAction * action =
130     g_action_map_lookup_action (
131       G_ACTION_MAP (zrythm_app), action_name);
132   g_simple_action_set_enabled (
133     G_SIMPLE_ACTION (action), enabled);
134 }
135 
136 void
activate_news(GSimpleAction * action,GVariant * variant,gpointer user_data)137 activate_news (
138   GSimpleAction *action,
139   GVariant      *variant,
140   gpointer       user_data)
141 {
142   gtk_show_uri_on_window (
143     GTK_WINDOW (MAIN_WINDOW),
144     "https://mastodon.social/@zrythm",
145     GDK_CURRENT_TIME, NULL);
146 }
147 
148 void
activate_manual(GSimpleAction * action,GVariant * variant,gpointer user_data)149 activate_manual (
150   GSimpleAction *action,
151   GVariant      *variant,
152   gpointer       user_data)
153 {
154   LocalizationLanguage lang =
155     (LocalizationLanguage)
156     g_settings_get_enum (
157       S_P_UI_GENERAL, "language");
158   const char * lang_code =
159     localization_get_string_code (lang);
160 #ifdef MANUAL_PATH
161   char * path =
162     g_strdup_printf (
163       "file://%s/%s/index.html",
164       MANUAL_PATH, lang_code);
165 #else
166   char * path =
167     g_strdup_printf (
168       "https://manual.zrythm.org/%s/index.html",
169       lang_code);
170 #endif
171   gtk_show_uri_on_window (
172     GTK_WINDOW (MAIN_WINDOW), path, 0, NULL);
173   g_free (path);
174 }
175 
DEFINE_SIMPLE(activate_chat)176 DEFINE_SIMPLE (activate_chat)
177 {
178   gtk_show_uri_on_window (
179     GTK_WINDOW (MAIN_WINDOW),
180     "https://matrix.to/#/#zrythmdaw:matrix.org",
181     0, NULL);
182 }
183 
DEFINE_SIMPLE(activate_donate)184 DEFINE_SIMPLE (activate_donate)
185 {
186   gtk_show_uri_on_window (
187     GTK_WINDOW (MAIN_WINDOW),
188     "https://liberapay.com/Zrythm", 0, NULL);
189 }
190 
DEFINE_SIMPLE(activate_bugreport)191 DEFINE_SIMPLE (activate_bugreport)
192 {
193 #ifdef _WOE32
194   ShellExecute (
195     0, (LPCSTR)"open",
196     (LPCSTR) NEW_ISSUE_URL,
197     0, 0, SW_SHOWNORMAL);
198 #else
199   gtk_show_uri_on_window (
200     GTK_WINDOW (MAIN_WINDOW),
201     NEW_ISSUE_URL,
202     0,
203     NULL);
204 #endif
205 }
206 
DEFINE_SIMPLE(activate_about)207 DEFINE_SIMPLE (activate_about)
208 {
209   GtkDialog * dialog =
210     GTK_DIALOG (
211       about_dialog_widget_new (
212         GTK_WINDOW (MAIN_WINDOW)));
213   gtk_dialog_run (dialog);
214   gtk_widget_destroy (GTK_WIDGET (dialog));
215 }
216 
217 /**
218  * @note This is never called but keep it around
219  * for shortcut window.
220  */
221 void
activate_quit(GSimpleAction * action,GVariant * variant,gpointer user_data)222 activate_quit (
223   GSimpleAction * action,
224   GVariant      * variant,
225   gpointer        user_data)
226 {
227   g_application_quit (G_APPLICATION (user_data));
228 }
229 
230 /**
231  * Show preferences window.
232  */
233 void
activate_preferences(GSimpleAction * action,GVariant * variant,gpointer user_data)234 activate_preferences (
235   GSimpleAction *action,
236   GVariant      *variant,
237   gpointer       user_data)
238 {
239   if (MAIN_WINDOW->preferences_opened)
240     {
241       return;
242     }
243 
244   GtkWindow * preferences_window =
245     GTK_WINDOW (
246       preferences_widget_new ());
247   g_return_if_fail (preferences_window);
248   gtk_window_set_transient_for (
249     preferences_window,
250     (GtkWindow *) MAIN_WINDOW);
251   gtk_widget_show_all (
252     (GtkWidget *) preferences_window);
253   MAIN_WINDOW->preferences_opened = true;
254 }
255 
256 /**
257  * Show log window.
258  */
259 void
activate_log(GSimpleAction * action,GVariant * variant,gpointer user_data)260 activate_log (
261   GSimpleAction *action,
262   GVariant      *variant,
263   gpointer       user_data)
264 {
265   if (!LOG || !LOG->log_filepath)
266     {
267       g_message ("No log file found");
268       return;
269     }
270 
271   const char * cmd[3] = {
272     OPEN_DIR_CMD, LOG->log_filepath, NULL };
273 
274   int ret =
275     system_run_cmd_w_args (
276       cmd, 4000, false, NULL, false);
277   if (ret)
278     {
279       g_warning (
280         "an error occured running %s %s",
281         OPEN_DIR_CMD, LOG->log_filepath);
282     }
283 
284 #if 0
285   if (GTK_IS_WINDOW (LOG->viewer))
286     {
287       gtk_window_present (
288         GTK_WINDOW (LOG->viewer));
289     }
290   else
291     {
292       LOG->viewer = log_viewer_widget_new ();
293       gtk_window_set_transient_for (
294         GTK_WINDOW (LOG->viewer),
295         GTK_WINDOW (MAIN_WINDOW));
296       gtk_widget_set_visible (
297         GTK_WIDGET (LOG->viewer), 1);
298     }
299 #endif
300 
301   if (ZRYTHM_HAVE_UI && MAIN_WINDOW && MW_HEADER)
302     {
303       MW_HEADER->log_has_pending_warnings = false;
304       EVENTS_PUSH (
305         ET_LOG_WARNING_STATE_CHANGED, NULL);
306     }
307 }
308 
309 /**
310  * Show scripting interface.
311  */
312 void
activate_scripting_interface(GSimpleAction * action,GVariant * variant,gpointer user_data)313 activate_scripting_interface (
314   GSimpleAction *action,
315   GVariant      *variant,
316   gpointer       user_data)
317 {
318 #ifdef HAVE_GUILE
319   ScriptingWindowWidget * widget =
320     scripting_window_widget_new ();
321   gtk_window_set_transient_for (
322     GTK_WINDOW (widget),
323     GTK_WINDOW (MAIN_WINDOW));
324   gtk_widget_set_visible (GTK_WIDGET (widget), 1);
325 #else
326   GtkWidget * dialog =
327     gtk_message_dialog_new_with_markup (
328       GTK_WINDOW (MAIN_WINDOW),
329       GTK_DIALOG_MODAL |
330         GTK_DIALOG_DESTROY_WITH_PARENT,
331       GTK_MESSAGE_INFO,
332       GTK_BUTTONS_OK,
333       _("Scripting extensibility with "
334       "<a href=\"%s\">GNU Guile</a> "
335       "is not enabled in your %s "
336       "installation."),
337       "https://www.gnu.org/software/guile",
338       PROGRAM_NAME);
339   gtk_window_set_transient_for (
340     GTK_WINDOW (dialog),
341     GTK_WINDOW (MAIN_WINDOW));
342   gtk_dialog_run (GTK_DIALOG (dialog));
343   gtk_widget_destroy (GTK_WIDGET (dialog));
344 #endif
345 }
346 
347 /**
348  * Activate audition mode.
349  */
350 void
activate_audition_mode(GSimpleAction * action,GVariant * variant,gpointer user_data)351 activate_audition_mode (GSimpleAction *action,
352                       GVariant      *variant,
353                       gpointer       user_data)
354 {
355   P_TOOL = TOOL_AUDITION;
356   EVENTS_PUSH (ET_TOOL_CHANGED, NULL);
357 }
358 
359 /**
360  * Activate select mode.
361  */
362 void
activate_select_mode(GSimpleAction * action,GVariant * variant,gpointer user_data)363 activate_select_mode (GSimpleAction *action,
364                       GVariant      *variant,
365                       gpointer       user_data)
366 {
367   if (P_TOOL == TOOL_SELECT_NORMAL)
368     P_TOOL = TOOL_SELECT_STRETCH;
369   else
370     P_TOOL = TOOL_SELECT_NORMAL;
371   EVENTS_PUSH (ET_TOOL_CHANGED, NULL);
372 }
373 
374 /**
375  * Activate edit mode.
376  */
377 void
activate_edit_mode(GSimpleAction * action,GVariant * variant,gpointer user_data)378 activate_edit_mode (GSimpleAction *action,
379                       GVariant      *variant,
380                       gpointer       user_data)
381 {
382   P_TOOL = TOOL_EDIT;
383   EVENTS_PUSH (ET_TOOL_CHANGED, NULL);
384 }
385 
386 /**
387  * Activate cut mode.
388  */
389 void
activate_cut_mode(GSimpleAction * action,GVariant * variant,gpointer user_data)390 activate_cut_mode (
391   GSimpleAction *action,
392   GVariant      *variant,
393   gpointer       user_data)
394 {
395   P_TOOL = TOOL_CUT;
396   EVENTS_PUSH (ET_TOOL_CHANGED, NULL);
397 }
398 
399 /**
400  * Activate eraser mode.
401  */
402 void
activate_eraser_mode(GSimpleAction * action,GVariant * variant,gpointer user_data)403 activate_eraser_mode (GSimpleAction *action,
404                       GVariant      *variant,
405                       gpointer       user_data)
406 {
407   P_TOOL = TOOL_ERASER;
408   EVENTS_PUSH (ET_TOOL_CHANGED, NULL);
409 }
410 
411 /**
412  * Activate ramp mode.
413  */
414 void
activate_ramp_mode(GSimpleAction * action,GVariant * variant,gpointer user_data)415 activate_ramp_mode (GSimpleAction *action,
416                       GVariant      *variant,
417                       gpointer       user_data)
418 {
419   P_TOOL = TOOL_RAMP;
420   EVENTS_PUSH (ET_TOOL_CHANGED, NULL);
421 }
422 
DEFINE_SIMPLE(activate_zoom_in)423 DEFINE_SIMPLE (activate_zoom_in)
424 {
425   RulerWidget * ruler = NULL;
426   switch (PROJECT->last_selection)
427     {
428     case SELECTION_TYPE_TIMELINE:
429       ruler = MW_RULER;
430       break;
431     case SELECTION_TYPE_EDITOR:
432       ruler = EDITOR_RULER;
433       break;
434     default:
435       return;
436     }
437 
438   ruler_widget_set_zoom_level (
439     ruler,
440     ruler_widget_get_zoom_level (ruler)
441       * RULER_ZOOM_LEVEL_MULTIPLIER);
442 
443   EVENTS_PUSH (ET_RULER_VIEWPORT_CHANGED, ruler);
444 }
445 
DEFINE_SIMPLE(activate_zoom_out)446 DEFINE_SIMPLE (activate_zoom_out)
447 {
448   RulerWidget * ruler = NULL;
449   switch (PROJECT->last_selection)
450     {
451     case SELECTION_TYPE_TIMELINE:
452       ruler = MW_RULER;
453       break;
454     case SELECTION_TYPE_EDITOR:
455       ruler = EDITOR_RULER;
456       break;
457     default:
458       return;
459     }
460 
461   double zoom_level =
462     ruler_widget_get_zoom_level (ruler)
463     / RULER_ZOOM_LEVEL_MULTIPLIER;
464   ruler_widget_set_zoom_level (
465     ruler, zoom_level);
466 
467   EVENTS_PUSH (ET_RULER_VIEWPORT_CHANGED, ruler);
468 }
469 
DEFINE_SIMPLE(activate_best_fit)470 DEFINE_SIMPLE (activate_best_fit)
471 {
472   RulerWidget * ruler = NULL;
473   Position pos;
474   switch (PROJECT->last_selection)
475     {
476     case SELECTION_TYPE_TIMELINE:
477       {
478         ruler = MW_RULER;
479         int total_bars = 0;
480         tracklist_get_total_bars (
481           TRACKLIST, &total_bars);
482         position_set_to_bar (
483           &pos, total_bars);
484       }
485       break;
486 #if 0
487     case SELECTION_TYPE_EDITOR:
488       ruler = EDITOR_RULER;
489       break;
490 #endif
491     default:
492       return;
493     }
494 
495   double total_ticks =
496     position_to_ticks (&pos);
497   GtkScrolledWindow * scroll =
498     ruler_widget_get_parent_scroll (ruler);
499   double allocated_px =
500     (double)
501     gtk_widget_get_allocated_width (
502       GTK_WIDGET (scroll));
503   double buffer_px = allocated_px / 16.0;
504   double needed_px_per_tick =
505     (allocated_px - buffer_px) / total_ticks;
506   double new_zoom_level =
507     ruler_widget_get_zoom_level (ruler) *
508     (needed_px_per_tick / ruler->px_per_tick);
509   ruler_widget_set_zoom_level (
510     ruler, new_zoom_level);
511 
512   EVENTS_PUSH (ET_RULER_VIEWPORT_CHANGED, ruler);
513 }
514 
515 void
activate_original_size(GSimpleAction * action,GVariant * variant,gpointer user_data)516 activate_original_size (GSimpleAction *action,
517                   GVariant      *variant,
518                   gpointer       user_data)
519 {
520   RulerWidget * ruler = NULL;
521   switch (PROJECT->last_selection)
522     {
523     case SELECTION_TYPE_TIMELINE:
524       ruler = MW_RULER;
525       break;
526     case SELECTION_TYPE_EDITOR:
527       ruler = EDITOR_RULER;
528       break;
529     default:
530       return;
531     }
532 
533   ruler_widget_set_zoom_level (ruler, 1.0);
534   EVENTS_PUSH (ET_RULER_VIEWPORT_CHANGED, ruler);
535 }
536 
DEFINE_SIMPLE(activate_loop_selection)537 DEFINE_SIMPLE (activate_loop_selection)
538 {
539   if (PROJECT->last_selection ==
540         SELECTION_TYPE_TIMELINE)
541     {
542       if (!arranger_selections_has_any (
543             (ArrangerSelections *) TL_SELECTIONS))
544         return;
545 
546       Position start, end;
547       arranger_selections_get_start_pos (
548         (ArrangerSelections *) TL_SELECTIONS,
549         &start, F_GLOBAL);
550       arranger_selections_get_end_pos (
551         (ArrangerSelections *) TL_SELECTIONS,
552         &end, F_GLOBAL);
553 
554       position_set_to_pos (
555         &TRANSPORT->loop_start_pos,
556         &start);
557       position_set_to_pos (
558         &TRANSPORT->loop_end_pos,
559         &end);
560 
561       /* FIXME is this needed? */
562       transport_update_positions (
563         TRANSPORT, true);
564 
565       EVENTS_PUSH (
566         ET_TIMELINE_LOOP_MARKER_POS_CHANGED,
567         NULL);
568     }
569 }
570 
571 static void
on_project_new_finish(GtkAssistant * _assistant,gpointer user_data)572 on_project_new_finish (
573   GtkAssistant * _assistant,
574   gpointer       user_data)
575 {
576   g_message (
577     "%s (%s) called", __func__, __FILE__);
578 
579   ProjectAssistantWidget * pa =
580     Z_PROJECT_ASSISTANT_WIDGET (_assistant);
581   ZRYTHM->creating_project = 1;
582   if (user_data) /* if cancel */
583     {
584       gtk_widget_destroy (GTK_WIDGET (_assistant));
585       ZRYTHM->open_filename = NULL;
586     }
587   /* if we are loading a template and template
588    * exists */
589   else if (pa->load_template &&
590            pa->template_selection &&
591            pa->template_selection->
592              filename[0] != '-')
593     {
594       ZRYTHM->open_filename =
595         pa->template_selection->filename;
596       g_message (
597         "Creating project from template: %s",
598         ZRYTHM->open_filename);
599       ZRYTHM->opening_template = 1;
600     }
601   /* if we are loading a project */
602   else if (!pa->load_template &&
603            pa->project_selection)
604     {
605       ZRYTHM->open_filename =
606         pa->project_selection->filename;
607       g_message (
608         "Loading project: %s",
609         ZRYTHM->open_filename);
610       ZRYTHM->creating_project = 0;
611     }
612   /* no selection, load blank project */
613   else
614     {
615       ZRYTHM->open_filename = NULL;
616       g_message (
617         "Creating blank project");
618     }
619 
620   /* if not loading a project, show dialog to
621    * select directory and name */
622   int quit = 0;
623   if (ZRYTHM->creating_project)
624     {
625       CreateProjectDialogWidget * dialog =
626         create_project_dialog_widget_new ();
627 
628       int ret =
629         gtk_dialog_run (GTK_DIALOG (dialog));
630       if (ret != GTK_RESPONSE_OK)
631         quit = 1;
632       gtk_widget_destroy (GTK_WIDGET (dialog));
633 
634       g_message (
635         "%s (%s): creating project %s",
636         __func__, __FILE__,
637         ZRYTHM->create_project_path);
638     }
639 
640   /* FIXME error if the assistant is deleted
641    * here, setting invisible for now, but
642    * eventually must be destroyed */
643   gtk_widget_set_visible (GTK_WIDGET (pa), 0);
644 
645   if (quit)
646     {
647     }
648   else
649     {
650       project_load (
651         ZRYTHM->open_filename,
652         ZRYTHM->opening_template);
653     }
654 }
655 
656 void
activate_new(GSimpleAction * action,GVariant * variant,gpointer user_data)657 activate_new (GSimpleAction *action,
658                   GVariant      *variant,
659                   gpointer       user_data)
660 {
661 #ifdef TRIAL_VER
662   char msg[600];
663   sprintf (
664     msg,
665     _("Creating new projects is disabled. Please "
666     "restart %s to start a new project"),
667     PROGRAM_NAME);
668   ui_show_error_message (
669     MAIN_WINDOW, msg);
670   return;
671 #endif
672 
673   GtkWidget * dialog =
674     gtk_dialog_new_with_buttons (
675       _("Create new project"),
676       GTK_WINDOW (MAIN_WINDOW),
677       GTK_DIALOG_MODAL |
678         GTK_DIALOG_DESTROY_WITH_PARENT,
679       _("Yes"),
680       GTK_RESPONSE_ACCEPT,
681       _("No"),
682       GTK_RESPONSE_REJECT,
683       NULL);
684   GtkWidget * label =
685     gtk_label_new (
686       _("Any unsaved changes to the current "
687         "project will be lost. Continue?"));
688   gtk_widget_set_visible (label, true);
689   GtkWidget * content =
690     gtk_dialog_get_content_area (
691       GTK_DIALOG (dialog));
692   gtk_container_add (
693     GTK_CONTAINER (content), label);
694   int res = gtk_dialog_run (GTK_DIALOG (dialog));
695   gtk_widget_destroy (GTK_WIDGET (dialog));
696   if (res == GTK_RESPONSE_ACCEPT)
697     {
698       ProjectAssistantWidget * pa =
699         project_assistant_widget_new (
700           GTK_WINDOW (MAIN_WINDOW), 1);
701       g_signal_connect (
702         G_OBJECT (pa), "apply",
703         G_CALLBACK (on_project_new_finish), NULL);
704       g_signal_connect (
705         G_OBJECT (pa), "cancel",
706         G_CALLBACK (on_project_new_finish),
707         (void *) 1);
708       gtk_window_present (GTK_WINDOW (pa));
709     }
710 }
711 
712 static int
run_open_dialog(GtkDialog * dialog)713 run_open_dialog (GtkDialog * dialog)
714 {
715   int res = gtk_dialog_run (GTK_DIALOG (dialog));
716   if (res == GTK_RESPONSE_ACCEPT)
717     {
718       GtkFileChooser *chooser =
719         GTK_FILE_CHOOSER (dialog);
720       char * filename =
721         gtk_file_chooser_get_filename (chooser);
722       g_message ("filename %s", filename);
723       res = project_load (filename, 0);
724       g_free (filename);
725     }
726 
727   return res;
728 }
729 
730 void
activate_open(GSimpleAction * action,GVariant * variant,gpointer user_data)731 activate_open (GSimpleAction *action,
732                   GVariant      *variant,
733                   gpointer       user_data)
734 {
735 #ifdef TRIAL_VER
736   ui_show_error_message (
737     MAIN_WINDOW,
738     _("Loading is disabled in the trial version"));
739   return;
740 #endif
741 
742   GtkDialog * dialog =
743     dialogs_get_open_project_dialog (
744       GTK_WINDOW (MAIN_WINDOW));
745 
746   int res = run_open_dialog (dialog);
747   if (res == GTK_RESPONSE_ACCEPT)
748     {
749       char *filename =
750         gtk_file_chooser_get_filename (
751           GTK_FILE_CHOOSER (dialog));
752       project_load (filename, 0);
753     }
754 
755   gtk_widget_destroy (GTK_WIDGET (dialog));
756 }
757 
758 void
activate_save(GSimpleAction * action,GVariant * variant,gpointer user_data)759 activate_save (
760   GSimpleAction *action,
761   GVariant      *variant,
762   gpointer       user_data)
763 {
764 #ifdef TRIAL_VER
765   ui_show_error_message (
766     MAIN_WINDOW,
767     _("Saving is disabled in the trial version"));
768   return;
769 #endif
770 
771   if (!PROJECT->dir ||
772       !PROJECT->title)
773     {
774       activate_save_as (
775         action, variant, user_data);
776       return;
777     }
778   g_message (
779     "project dir: %s", PROJECT->dir);
780 
781   project_save (
782     PROJECT, PROJECT->dir, F_NOT_BACKUP,
783     ZRYTHM_F_NOTIFY, F_NO_ASYNC);
784 }
785 
786 void
activate_save_as(GSimpleAction * action,GVariant * variant,gpointer user_data)787 activate_save_as (
788   GSimpleAction *action,
789   GVariant      *variant,
790   gpointer       user_data)
791 {
792 #ifdef TRIAL_VER
793   ui_show_error_message (
794     MAIN_WINDOW,
795     _("Saving is disabled in the trial version"));
796   return;
797 #endif
798 
799   GtkWidget *dialog;
800   GtkFileChooser *chooser;
801   GtkFileChooserAction _action =
802     GTK_FILE_CHOOSER_ACTION_SAVE;
803   gint res;
804 
805   dialog =
806     gtk_file_chooser_dialog_new (
807       _("Save Project"),
808       GTK_WINDOW (MAIN_WINDOW),
809       _action,
810       _("_Cancel"),
811       GTK_RESPONSE_CANCEL,
812       _("_Save"),
813       GTK_RESPONSE_ACCEPT,
814       NULL);
815   chooser = GTK_FILE_CHOOSER (dialog);
816 
817   gtk_file_chooser_set_do_overwrite_confirmation (
818     chooser, TRUE);
819 
820   char * project_file_path =
821     project_get_path (
822       PROJECT, PROJECT_PATH_PROJECT_FILE, false);
823   char * str =
824     io_path_get_parent_dir (
825       project_file_path);
826   g_free (project_file_path);
827   gtk_file_chooser_select_filename (
828     chooser,
829     str);
830   g_free (str);
831   gtk_file_chooser_set_current_name (
832     chooser, PROJECT->title);
833 
834   res = gtk_dialog_run (GTK_DIALOG (dialog));
835   if (res == GTK_RESPONSE_ACCEPT)
836     {
837       char *filename;
838 
839       filename =
840         gtk_file_chooser_get_filename (chooser);
841       project_save (
842         PROJECT, filename, F_NOT_BACKUP,
843         ZRYTHM_F_NO_NOTIFY, F_NO_ASYNC);
844       g_free (filename);
845     }
846 
847   gtk_widget_destroy (dialog);
848 }
849 
850 void
activate_iconify(GSimpleAction * action,GVariant * variant,gpointer user_data)851 activate_iconify (GSimpleAction *action,
852                   GVariant      *variant,
853                   gpointer       user_data)
854 {
855   gtk_window_iconify (GTK_WINDOW (MAIN_WINDOW));
856 }
857 
858 void
activate_export_as(GSimpleAction * action,GVariant * variant,gpointer user_data)859 activate_export_as (GSimpleAction *action,
860                   GVariant      *variant,
861                   gpointer       user_data)
862 {
863   ExportDialogWidget * export =
864     export_dialog_widget_new ();
865   gtk_window_set_transient_for (
866     GTK_WINDOW (export),
867     GTK_WINDOW (MAIN_WINDOW));
868   gtk_dialog_run (GTK_DIALOG (export));
869   gtk_widget_destroy (GTK_WIDGET (export));
870 }
871 
872 void
activate_export_graph(GSimpleAction * action,GVariant * variant,gpointer user_data)873 activate_export_graph (
874   GSimpleAction *action,
875   GVariant      *variant,
876   gpointer       user_data)
877 {
878 #ifdef HAVE_CGRAPH
879   char * exports_dir =
880     project_get_path (
881       PROJECT, PROJECT_PATH_EXPORTS, false);
882 
883   GtkWidget *dialog, *label, *content_area;
884   GtkDialogFlags flags;
885 
886   // Create the widgets
887   flags = GTK_DIALOG_DESTROY_WITH_PARENT;
888   dialog =
889     gtk_dialog_new_with_buttons (
890       _("Export routing graph"),
891       GTK_WINDOW (MAIN_WINDOW), flags,
892       _("Image (PNG)"), 1,
893       _("Image (SVG)"), 2,
894       _("Dot graph"), 3,
895       NULL);
896   content_area =
897     gtk_dialog_get_content_area (
898       GTK_DIALOG (dialog));
899   char lbl[600];
900   sprintf (
901     lbl,
902     _("The graph will be exported to "
903     "<a href=\"%s\">%s</a>\n"
904     "Please select a format to export as"),
905     exports_dir, exports_dir);
906   label = gtk_label_new (NULL);
907   gtk_label_set_markup (
908     GTK_LABEL (label), lbl);
909   gtk_widget_set_visible (label, true);
910   gtk_label_set_justify (
911     GTK_LABEL (label), GTK_JUSTIFY_CENTER);
912   z_gtk_widget_set_margin (label, 3);
913 
914   g_signal_connect (
915     G_OBJECT (label), "activate-link",
916     G_CALLBACK (z_gtk_activate_dir_link_func),
917     NULL);
918 
919  // Add the label, and show everything we’ve added
920   gtk_container_add (
921     GTK_CONTAINER (content_area), label);
922 
923   int result = gtk_dialog_run (GTK_DIALOG (dialog));
924   const char * filename = NULL;
925   GraphExportType export_type;
926   switch (result)
927     {
928       /* png */
929       case 1:
930         filename = "graph.png";
931         export_type = GRAPH_EXPORT_PNG;
932         break;
933       /* svg */
934       case 2:
935         filename = "graph.svg";
936         export_type = GRAPH_EXPORT_SVG;
937         break;
938       /* dot */
939       case 3:
940         filename = "graph.dot";
941         export_type = GRAPH_EXPORT_DOT;
942         break;
943       default:
944         gtk_widget_destroy (dialog);
945         return;
946     }
947   gtk_widget_destroy (dialog);
948 
949   char * path =
950     g_build_filename (
951       exports_dir, filename, NULL);
952   graph_export_as_simple (export_type, path);
953   g_free (exports_dir);
954   g_free (path);
955 
956   ui_show_notification (_("Graph exported"));
957 #endif
958 }
959 
960 void
activate_properties(GSimpleAction * action,GVariant * variant,gpointer user_data)961 activate_properties (GSimpleAction *action,
962                   GVariant      *variant,
963                   gpointer       user_data)
964 {
965   g_message ("ZOOMING IN");
966 }
967 
DEFINE_SIMPLE(activate_undo)968 DEFINE_SIMPLE (activate_undo)
969 {
970   if (undo_stack_is_empty (
971         UNDO_MANAGER->undo_stack))
972     return;
973 
974   GError * err = NULL;
975   int ret = undo_manager_undo (UNDO_MANAGER, &err);
976   if (ret != 0)
977     {
978       HANDLE_ERROR (
979         err, "%s", _("Failed to undo"));
980     }
981 }
982 
DEFINE_SIMPLE(activate_redo)983 DEFINE_SIMPLE (activate_redo)
984 {
985   if (undo_stack_is_empty (
986         UNDO_MANAGER->redo_stack))
987     return;
988 
989   GError * err = NULL;
990   int ret = undo_manager_redo (UNDO_MANAGER, &err);
991   if (ret != 0)
992     {
993       HANDLE_ERROR (
994         err, "%s", _("Failed to redo"));
995     }
996 
997   EVENTS_PUSH (ET_UNDO_REDO_ACTION_DONE,
998                NULL);
999 }
1000 
1001 void
activate_cut(GSimpleAction * action,GVariant * variant,gpointer user_data)1002 activate_cut (
1003   GSimpleAction *action,
1004   GVariant      *variant,
1005   gpointer       user_data)
1006 {
1007   /* activate copy and then delete the selections */
1008   activate_copy (action, variant, user_data);
1009 
1010   ArrangerSelections * sel =
1011     project_get_arranger_selections_for_last_selection (
1012       PROJECT);
1013 
1014   switch (PROJECT->last_selection)
1015     {
1016     case SELECTION_TYPE_TIMELINE:
1017     case SELECTION_TYPE_EDITOR:
1018       if (sel && arranger_selections_has_any (sel))
1019         {
1020           GError * err = NULL;
1021           bool ret =
1022             arranger_selections_action_perform_delete (
1023               sel, &err);
1024           if (!ret)
1025             {
1026               HANDLE_ERROR (
1027                 err, "%s",
1028                 _("Failed to delete selections"));
1029             }
1030         }
1031       break;
1032     case SELECTION_TYPE_INSERT:
1033     case SELECTION_TYPE_MIDI_FX:
1034       if (mixer_selections_has_any (
1035             MIXER_SELECTIONS))
1036         {
1037           GError * err = NULL;
1038           bool ret =
1039             mixer_selections_action_perform_delete (
1040               MIXER_SELECTIONS,
1041               PORT_CONNECTIONS_MGR,
1042               &err);
1043           if (!ret)
1044             {
1045               HANDLE_ERROR (
1046                 err, "%s",
1047                 _("Failed to delete selections"));
1048             }
1049         }
1050       break;
1051     default:
1052       g_debug ("doing nothing");
1053       break;
1054     }
1055 }
1056 
1057 
1058 void
activate_copy(GSimpleAction * action,GVariant * variant,gpointer user_data)1059 activate_copy (
1060   GSimpleAction *action,
1061   GVariant      *variant,
1062   gpointer       user_data)
1063 {
1064   ArrangerSelections * sel =
1065     project_get_arranger_selections_for_last_selection (
1066       PROJECT);
1067 
1068   switch (PROJECT->last_selection)
1069     {
1070     case SELECTION_TYPE_TIMELINE:
1071     case SELECTION_TYPE_EDITOR:
1072       if (sel)
1073         {
1074           Clipboard * clipboard =
1075             clipboard_new_for_arranger_selections (
1076               sel, F_CLONE);
1077           if (clipboard->timeline_sel)
1078             {
1079               timeline_selections_set_vis_track_indices (
1080                 clipboard->timeline_sel);
1081             }
1082           char * serialized =
1083             yaml_serialize (
1084               clipboard, &clipboard_schema);
1085           g_return_if_fail (serialized);
1086           gtk_clipboard_set_text (
1087             DEFAULT_CLIPBOARD,
1088             serialized, -1);
1089           clipboard_free (clipboard);
1090           g_free (serialized);
1091         }
1092       else
1093         {
1094           g_warning ("no selections to copy");
1095         }
1096       break;
1097     case SELECTION_TYPE_INSERT:
1098     case SELECTION_TYPE_MIDI_FX:
1099       if (mixer_selections_has_any (
1100             MIXER_SELECTIONS))
1101         {
1102           Clipboard * clipboard =
1103             clipboard_new_for_mixer_selections (
1104               MIXER_SELECTIONS, F_CLONE);
1105           char * serialized =
1106             yaml_serialize (
1107               clipboard, &clipboard_schema);
1108           g_return_if_fail (serialized);
1109           gtk_clipboard_set_text (
1110             DEFAULT_CLIPBOARD,
1111             serialized, -1);
1112           clipboard_free (clipboard);
1113           g_free (serialized);
1114         }
1115       break;
1116     default:
1117       g_warning ("not implemented yet");
1118       break;
1119     }
1120 }
1121 
1122 static void
on_clipboard_received(GtkClipboard * gtk_clipboard,const char * text,gpointer data)1123 on_clipboard_received (
1124   GtkClipboard *     gtk_clipboard,
1125   const char *       text,
1126   gpointer           data)
1127 {
1128   if (!text)
1129     return;
1130 
1131   Clipboard * clipboard =
1132     (Clipboard *)
1133     yaml_deserialize (text, &clipboard_schema);
1134   if (!clipboard)
1135     {
1136       g_message (
1137         "invalid clipboard data received:\n%s",
1138         text);
1139       return;
1140     }
1141 
1142   ArrangerSelections * sel = NULL;
1143   MixerSelections * mixer_sel = NULL;
1144   switch (clipboard->type)
1145     {
1146     case CLIPBOARD_TYPE_TIMELINE_SELECTIONS:
1147     case CLIPBOARD_TYPE_MIDI_SELECTIONS:
1148     case CLIPBOARD_TYPE_AUTOMATION_SELECTIONS:
1149     case CLIPBOARD_TYPE_CHORD_SELECTIONS:
1150       sel = clipboard_get_selections (clipboard);
1151       break;
1152     case CLIPBOARD_TYPE_MIXER_SELECTIONS:
1153       mixer_sel = clipboard->mixer_sel;
1154       break;
1155     default:
1156       g_warn_if_reached ();
1157     }
1158 
1159   bool incompatible = false;
1160   if (sel)
1161     {
1162       arranger_selections_post_deserialize (sel);
1163       if (arranger_selections_can_be_pasted (sel))
1164         {
1165           arranger_selections_paste_to_pos (
1166             sel, PLAYHEAD, F_UNDOABLE);
1167         }
1168       else
1169         {
1170           g_message (
1171             "can't paste arranger selections:\n%s",
1172             text);
1173           incompatible = true;
1174         }
1175     }
1176   else if (mixer_sel)
1177     {
1178       ChannelSlotWidget * slot =
1179         MW_MIXER->paste_slot;
1180       mixer_selections_post_deserialize (mixer_sel);
1181       if (mixer_selections_can_be_pasted (
1182             mixer_sel, slot->track->channel,
1183             slot->type, slot->slot_index))
1184         {
1185           mixer_selections_paste_to_slot (
1186             mixer_sel, slot->track->channel,
1187             slot->type, slot->slot_index);
1188         }
1189       else
1190         {
1191           g_message (
1192             "can't paste mixer selections:\n%s",
1193             text);
1194           incompatible = true;
1195         }
1196     }
1197 
1198   if (incompatible)
1199     {
1200       ui_show_notification (
1201         _("Can't paste incompatible data"));
1202     }
1203 
1204   clipboard_free (clipboard);
1205 }
1206 
1207 void
activate_paste(GSimpleAction * action,GVariant * variant,gpointer user_data)1208 activate_paste (
1209   GSimpleAction *action,
1210   GVariant      *variant,
1211   gpointer       user_data)
1212 {
1213   g_message ("paste");
1214   gtk_clipboard_request_text (
1215     DEFAULT_CLIPBOARD,
1216     on_clipboard_received,
1217     NULL);
1218 }
1219 
1220 void
activate_delete(GSimpleAction * simple_action,GVariant * variant,gpointer user_data)1221 activate_delete (
1222   GSimpleAction * simple_action,
1223   GVariant      * variant,
1224   gpointer        user_data)
1225 {
1226   g_message ("%s", __func__);
1227 
1228   ArrangerSelections * sel =
1229     project_get_arranger_selections_for_last_selection (
1230       PROJECT);
1231 
1232   if (sel &&
1233       arranger_selections_has_any (sel) &&
1234       !arranger_selections_contains_undeletable_object (
1235         sel))
1236     {
1237       GError * err = NULL;
1238       bool ret =
1239         arranger_selections_action_perform_delete (
1240           sel, &err);
1241       if (!ret)
1242         {
1243           HANDLE_ERROR (
1244             err, "%s",
1245             _("Failed to delete selections"));
1246         }
1247     }
1248 
1249   switch (PROJECT->last_selection)
1250     {
1251     case SELECTION_TYPE_TRACKLIST:
1252       g_message (
1253         "activating delete selected tracks");
1254       g_action_group_activate_action (
1255         G_ACTION_GROUP (MAIN_WINDOW),
1256         "delete-selected-tracks", NULL);
1257       break;
1258     case SELECTION_TYPE_INSERT:
1259     case SELECTION_TYPE_MIDI_FX:
1260       {
1261         GError * err = NULL;
1262         bool ret =
1263           mixer_selections_action_perform_delete (
1264             MIXER_SELECTIONS,
1265             PORT_CONNECTIONS_MGR,
1266             &err);
1267         if (!ret)
1268           {
1269             HANDLE_ERROR (
1270               err, "%s",
1271               _("Failed to delete plugins"));
1272           }
1273       }
1274       break;
1275     default:
1276       g_warning ("not implemented yet");
1277       break;
1278     }
1279 }
1280 
1281 void
activate_duplicate(GSimpleAction * action,GVariant * variant,gpointer user_data)1282 activate_duplicate (
1283   GSimpleAction *action,
1284   GVariant      *variant,
1285   gpointer       user_data)
1286 {
1287   ArrangerSelections * sel =
1288     project_get_arranger_selections_for_last_selection (
1289       PROJECT);
1290 
1291   if (sel && arranger_selections_has_any (sel))
1292     {
1293       double length =
1294         arranger_selections_get_length_in_ticks (
1295           sel);
1296 
1297       GError * err = NULL;
1298       bool ret =
1299         arranger_selections_action_perform_duplicate (
1300           sel, length, 0, 0, 0, 0, 0,
1301           F_NOT_ALREADY_MOVED, &err);
1302       if (!ret)
1303         {
1304           HANDLE_ERROR (
1305             err, "%s",
1306             _("Failed to duplicate selections"));
1307         }
1308     }
1309 }
1310 
1311 void
activate_clear_selection(GSimpleAction * action,GVariant * variant,gpointer user_data)1312 activate_clear_selection (
1313   GSimpleAction *action,
1314   GVariant      *variant,
1315   gpointer       user_data)
1316 {
1317   ArrangerSelections * sel =
1318     project_get_arranger_selections_for_last_selection (
1319       PROJECT);
1320 
1321   switch (PROJECT->last_selection)
1322     {
1323     case SELECTION_TYPE_TIMELINE:
1324     case SELECTION_TYPE_EDITOR:
1325       if (sel)
1326         {
1327           arranger_selections_clear (
1328             sel, F_NO_FREE, F_PUBLISH_EVENTS);
1329         }
1330       break;
1331     case SELECTION_TYPE_TRACKLIST:
1332       tracklist_select_all (
1333         TRACKLIST, F_NO_SELECT, F_PUBLISH_EVENTS);
1334       break;
1335     case SELECTION_TYPE_INSERT:
1336     case SELECTION_TYPE_MIDI_FX:
1337       {
1338         Track * track =
1339           tracklist_selections_get_lowest_track (
1340             TRACKLIST_SELECTIONS);
1341         g_return_if_fail (
1342           IS_TRACK_AND_NONNULL (track));
1343         if (track_type_has_channel (track->type))
1344           {
1345             Channel * ch =
1346               track_get_channel (track);
1347             PluginSlotType slot_type =
1348               PLUGIN_SLOT_INSERT;
1349             if (PROJECT->last_selection ==
1350                   SELECTION_TYPE_MIDI_FX)
1351               {
1352                 slot_type = PLUGIN_SLOT_MIDI_FX;
1353               }
1354             channel_select_all (
1355               ch, slot_type, F_NO_SELECT);
1356           }
1357       }
1358       break;
1359     default:
1360       g_debug ("%s: doing nothing", __func__);
1361     }
1362 }
1363 
1364 void
activate_select_all(GSimpleAction * action,GVariant * variant,gpointer user_data)1365 activate_select_all (
1366   GSimpleAction *action,
1367   GVariant *variant,
1368   gpointer user_data)
1369 {
1370   ArrangerSelections * sel =
1371     project_get_arranger_selections_for_last_selection (
1372       PROJECT);
1373 
1374   switch (PROJECT->last_selection)
1375     {
1376     case SELECTION_TYPE_TIMELINE:
1377     case SELECTION_TYPE_EDITOR:
1378       if (sel)
1379         {
1380           arranger_selections_select_all (
1381             sel, F_PUBLISH_EVENTS);
1382         }
1383       break;
1384     case SELECTION_TYPE_TRACKLIST:
1385       tracklist_select_all (
1386         TRACKLIST, F_SELECT, F_PUBLISH_EVENTS);
1387       break;
1388     case SELECTION_TYPE_INSERT:
1389     case SELECTION_TYPE_MIDI_FX:
1390       {
1391         Track * track =
1392           tracklist_selections_get_lowest_track (
1393             TRACKLIST_SELECTIONS);
1394         g_return_if_fail (
1395           IS_TRACK_AND_NONNULL (track));
1396         if (track_type_has_channel (track->type))
1397           {
1398             Channel * ch =
1399               track_get_channel (track);
1400             PluginSlotType slot_type =
1401               PLUGIN_SLOT_INSERT;
1402             if (PROJECT->last_selection ==
1403                   SELECTION_TYPE_MIDI_FX)
1404               {
1405                 slot_type = PLUGIN_SLOT_MIDI_FX;
1406               }
1407             channel_select_all (
1408               ch, slot_type, F_SELECT);
1409           }
1410       }
1411       break;
1412     default:
1413       g_debug ("%s: doing nothing", __func__);
1414     }
1415 }
1416 
1417 void
activate_toggle_left_panel(GSimpleAction * action,GVariant * variant,gpointer user_data)1418 activate_toggle_left_panel (
1419   GSimpleAction * action,
1420   GVariant      * variant,
1421   gpointer        user_data)
1422 {
1423   foldable_notebook_widget_toggle_visibility (
1424     MW_LEFT_DOCK_EDGE->inspector_notebook);
1425 }
1426 
1427 void
activate_toggle_right_panel(GSimpleAction * action,GVariant * variant,gpointer user_data)1428 activate_toggle_right_panel (GSimpleAction *action,
1429                   GVariant      *variant,
1430                   gpointer       user_data)
1431 {
1432   foldable_notebook_widget_toggle_visibility (
1433     MW_RIGHT_DOCK_EDGE->right_notebook);
1434 }
1435 
1436 void
activate_toggle_bot_panel(GSimpleAction * action,GVariant * variant,gpointer user_data)1437 activate_toggle_bot_panel (GSimpleAction *action,
1438                   GVariant      *variant,
1439                   gpointer       user_data)
1440 {
1441   foldable_notebook_widget_toggle_visibility (
1442     MW_BOT_DOCK_EDGE->bot_notebook);
1443 }
1444 
1445 /**
1446  * Toggle timeline visibility.
1447  */
1448 void
activate_toggle_top_panel(GSimpleAction * action,GVariant * variant,gpointer user_data)1449 activate_toggle_top_panel (
1450   GSimpleAction *action,
1451   GVariant      *variant,
1452   gpointer       user_data)
1453 {
1454   g_return_if_fail (
1455     MW_CENTER_DOCK && MW_MAIN_NOTEBOOK);
1456   GtkWidget * widget =
1457     (GtkWidget *) MW_MAIN_NOTEBOOK;
1458   gtk_widget_set_visible (
1459     widget, !gtk_widget_get_visible (widget));
1460 }
1461 
1462 void
activate_toggle_status_bar(GSimpleAction * action,GVariant * variant,gpointer user_data)1463 activate_toggle_status_bar (GSimpleAction *action,
1464                   GVariant      *variant,
1465                   gpointer       user_data)
1466 {
1467   gtk_widget_set_visible (
1468     GTK_WIDGET (MW_BOT_BAR),
1469     !gtk_widget_get_visible (
1470       GTK_WIDGET (MW_BOT_BAR)));
1471 }
1472 
1473 void
change_state_piano_roll_drum_mode(GSimpleAction * action,GVariant * value,gpointer user_data)1474 change_state_piano_roll_drum_mode (
1475   GSimpleAction * action,
1476   GVariant *      value,
1477   gpointer        user_data)
1478 {
1479   int enabled = g_variant_get_boolean (value);
1480 
1481   g_simple_action_set_state (action, value);
1482 
1483   Track * tr =
1484     clip_editor_get_track (CLIP_EDITOR);
1485   g_return_if_fail (IS_TRACK_AND_NONNULL (tr));
1486   tr->drum_mode = enabled;
1487 
1488   EVENTS_PUSH (ET_DRUM_MODE_CHANGED, tr);
1489 }
1490 
DEFINE_SIMPLE(activate_fullscreen)1491 DEFINE_SIMPLE (activate_fullscreen)
1492 {
1493   if (MAIN_WINDOW->is_fullscreen)
1494     {
1495       gtk_window_unfullscreen (
1496         GTK_WINDOW (MAIN_WINDOW));
1497     }
1498   else
1499     {
1500       gtk_window_fullscreen (
1501         GTK_WINDOW (MAIN_WINDOW));
1502     }
1503 }
1504 
1505 void
activate_snap_to_grid(GSimpleAction * action,GVariant * _variant,gpointer user_data)1506 activate_snap_to_grid (
1507   GSimpleAction * action,
1508   GVariant      * _variant,
1509   gpointer         user_data)
1510 {
1511   g_return_if_fail (_variant);
1512 
1513   gsize size;
1514   const char * variant =
1515     g_variant_get_string (_variant, &size);
1516   if (string_is_equal (variant, "timeline"))
1517     {
1518       SNAP_GRID_TIMELINE->snap_to_grid =
1519         !SNAP_GRID_TIMELINE->snap_to_grid;
1520       EVENTS_PUSH (
1521         ET_SNAP_GRID_OPTIONS_CHANGED,
1522         SNAP_GRID_TIMELINE);
1523     }
1524   else if (string_is_equal (variant, "editor"))
1525     {
1526       SNAP_GRID_EDITOR->snap_to_grid =
1527         !SNAP_GRID_EDITOR->snap_to_grid;
1528       EVENTS_PUSH (
1529         ET_SNAP_GRID_OPTIONS_CHANGED,
1530         SNAP_GRID_EDITOR);
1531     }
1532   else if (string_is_equal (variant, "global"))
1533     {
1534       if (PROJECT->last_selection ==
1535             SELECTION_TYPE_TIMELINE)
1536         {
1537           GError * err = NULL;
1538           bool ret =
1539             arranger_selections_action_perform_quantize (
1540               (ArrangerSelections *) TL_SELECTIONS,
1541               QUANTIZE_OPTIONS_TIMELINE, &err);
1542           if (!ret)
1543             {
1544               HANDLE_ERROR (
1545                 err, "%s",
1546                 _("Failed to quantize"));
1547             }
1548         }
1549     }
1550   else
1551     {
1552       g_return_if_reached ();
1553     }
1554 }
1555 
1556 void
activate_snap_keep_offset(GSimpleAction * action,GVariant * _variant,gpointer user_data)1557 activate_snap_keep_offset (
1558   GSimpleAction * action,
1559   GVariant *      _variant,
1560   gpointer        user_data)
1561 {
1562   g_return_if_fail (_variant);
1563   gsize size;
1564   const char * variant =
1565     g_variant_get_string (_variant, &size);
1566 
1567   if (string_is_equal (variant, "timeline"))
1568     {
1569       SNAP_GRID_TIMELINE->
1570         snap_to_grid_keep_offset =
1571           !SNAP_GRID_TIMELINE->
1572             snap_to_grid_keep_offset;
1573       EVENTS_PUSH (
1574         ET_SNAP_GRID_OPTIONS_CHANGED,
1575         SNAP_GRID_TIMELINE);
1576     }
1577   else if (string_is_equal (variant, "editor"))
1578     {
1579       SNAP_GRID_EDITOR->snap_to_grid_keep_offset =
1580         !SNAP_GRID_EDITOR->
1581           snap_to_grid_keep_offset;
1582       EVENTS_PUSH (
1583         ET_SNAP_GRID_OPTIONS_CHANGED,
1584         SNAP_GRID_EDITOR);
1585     }
1586   else
1587     g_return_if_reached ();
1588 }
1589 
1590 void
activate_snap_events(GSimpleAction * action,GVariant * _variant,gpointer user_data)1591 activate_snap_events (
1592   GSimpleAction * action,
1593   GVariant *      _variant,
1594   gpointer        user_data)
1595 {
1596   g_return_if_fail (_variant);
1597   gsize size;
1598   const char * variant =
1599     g_variant_get_string (_variant, &size);
1600 
1601   if (string_is_equal (variant, "timeline"))
1602     {
1603       SNAP_GRID_TIMELINE->snap_to_events =
1604         !SNAP_GRID_TIMELINE->snap_to_events;
1605       EVENTS_PUSH (
1606         ET_SNAP_GRID_OPTIONS_CHANGED,
1607         SNAP_GRID_TIMELINE);
1608     }
1609   else if (string_is_equal (variant, "editor"))
1610     {
1611       SNAP_GRID_EDITOR->snap_to_events =
1612         !SNAP_GRID_EDITOR->snap_to_events;
1613       EVENTS_PUSH (
1614         ET_SNAP_GRID_OPTIONS_CHANGED,
1615         SNAP_GRID_EDITOR);
1616     }
1617   else
1618     g_return_if_reached ();
1619 }
1620 
DEFINE_SIMPLE(activate_create_audio_track)1621 DEFINE_SIMPLE (activate_create_audio_track)
1622 {
1623   GError * err = NULL;
1624   bool ret =
1625     track_create_empty_with_action (
1626       TRACK_TYPE_AUDIO, &err);
1627   if (!ret)
1628     {
1629       HANDLE_ERROR (
1630         err, "%s",
1631         _("Failed to create audio track"));
1632     }
1633 }
1634 
DEFINE_SIMPLE(activate_create_midi_track)1635 DEFINE_SIMPLE (activate_create_midi_track)
1636 {
1637   GError * err = NULL;
1638   bool ret =
1639     track_create_empty_with_action (
1640       TRACK_TYPE_MIDI, &err);
1641   if (!ret)
1642     {
1643       HANDLE_ERROR (
1644         err, "%s",
1645         _("Failed to create MIDI track"));
1646     }
1647 }
1648 
DEFINE_SIMPLE(activate_create_audio_bus_track)1649 DEFINE_SIMPLE (activate_create_audio_bus_track)
1650 {
1651   GError * err = NULL;
1652   bool ret =
1653     track_create_empty_with_action (
1654       TRACK_TYPE_AUDIO_BUS, &err);
1655   if (!ret)
1656     {
1657       HANDLE_ERROR (
1658         err, "%s",
1659         _("Failed to create audio FX track"));
1660     }
1661 }
1662 
DEFINE_SIMPLE(activate_create_midi_bus_track)1663 DEFINE_SIMPLE (activate_create_midi_bus_track)
1664 {
1665   GError * err = NULL;
1666   bool ret =
1667     track_create_empty_with_action (
1668       TRACK_TYPE_MIDI_BUS, &err);
1669   if (!ret)
1670     {
1671       HANDLE_ERROR (
1672         err, "%s",
1673         _("Failed to create MIDI FX track"));
1674     }
1675 }
1676 
DEFINE_SIMPLE(activate_create_audio_group_track)1677 DEFINE_SIMPLE (activate_create_audio_group_track)
1678 {
1679   GError * err = NULL;
1680   bool ret =
1681     track_create_empty_with_action (
1682       TRACK_TYPE_AUDIO_GROUP, &err);
1683   if (!ret)
1684     {
1685       HANDLE_ERROR (
1686         err, "%s",
1687         _("Failed to create audio group track"));
1688     }
1689 }
1690 
DEFINE_SIMPLE(activate_create_midi_group_track)1691 DEFINE_SIMPLE (activate_create_midi_group_track)
1692 {
1693   GError * err = NULL;
1694   bool ret =
1695     track_create_empty_with_action (
1696       TRACK_TYPE_MIDI_GROUP, &err);
1697   if (!ret)
1698     {
1699       HANDLE_ERROR (
1700         err, "%s",
1701         _("Failed to create MIDI group track"));
1702     }
1703 }
1704 
DEFINE_SIMPLE(activate_create_folder_track)1705 DEFINE_SIMPLE (activate_create_folder_track)
1706 {
1707   GError * err = NULL;
1708   bool ret =
1709     track_create_empty_with_action (
1710       TRACK_TYPE_FOLDER, &err);
1711   if (!ret)
1712     {
1713       HANDLE_ERROR (
1714         err, "%s",
1715         _("Failed to create folder track"));
1716     }
1717 }
1718 
DEFINE_SIMPLE(activate_duplicate_selected_tracks)1719 DEFINE_SIMPLE (activate_duplicate_selected_tracks)
1720 {
1721   GError * err = NULL;
1722   bool ret =
1723     tracklist_selections_action_perform_copy (
1724     TRACKLIST_SELECTIONS, PORT_CONNECTIONS_MGR,
1725     TRACKLIST_SELECTIONS->tracks[0]->pos + 1,
1726     &err);
1727   if (!ret)
1728     {
1729       HANDLE_ERROR (
1730         err, "%s",
1731         _("Failed to duplicate tracks"));
1732     }
1733 }
1734 
DEFINE_SIMPLE(activate_change_track_color)1735 DEFINE_SIMPLE (activate_change_track_color)
1736 {
1737   ObjectColorChooserDialogWidget * color_chooser =
1738     object_color_chooser_dialog_widget_new_for_tracklist_selections (
1739       TRACKLIST_SELECTIONS);
1740   object_color_chooser_dialog_widget_run (
1741     color_chooser);
1742 }
1743 
DEFINE_SIMPLE(activate_goto_prev_marker)1744 DEFINE_SIMPLE (activate_goto_prev_marker)
1745 {
1746   transport_goto_prev_marker (TRANSPORT);
1747 }
1748 
DEFINE_SIMPLE(activate_goto_next_marker)1749 DEFINE_SIMPLE (activate_goto_next_marker)
1750 {
1751   transport_goto_next_marker (TRANSPORT);
1752 }
1753 
DEFINE_SIMPLE(activate_play_pause)1754 DEFINE_SIMPLE (activate_play_pause)
1755 {
1756   if (TRANSPORT_IS_ROLLING)
1757     {
1758       transport_request_pause (TRANSPORT);
1759       midi_panic_all (1);
1760     }
1761   else if (TRANSPORT_IS_PAUSED)
1762     {
1763       transport_request_roll (TRANSPORT);
1764     }
1765 }
1766 
1767 void
activate_delete_selected_tracks(GSimpleAction * action,GVariant * variant,gpointer user_data)1768 activate_delete_selected_tracks (
1769   GSimpleAction *action,
1770   GVariant      *variant,
1771   gpointer       user_data)
1772 {
1773   g_message ("deleting selected tracks");
1774 
1775   if (tracklist_selections_contains_undeletable_track (
1776         TRACKLIST_SELECTIONS))
1777     {
1778       ui_show_message_printf (
1779         MAIN_WINDOW, GTK_MESSAGE_INFO,
1780         "%s",
1781         _("Cannot delete tracks: selection "
1782         "contains an undeletable track"));
1783       return;
1784     }
1785 
1786   GError * err = NULL;
1787   bool ret =
1788     tracklist_selections_action_perform_delete (
1789       TRACKLIST_SELECTIONS,
1790       PORT_CONNECTIONS_MGR,
1791       &err);
1792   if (!ret)
1793     {
1794       HANDLE_ERROR (
1795         err, "%s", _("Failed to delete tracks"));
1796     }
1797 }
1798 
DEFINE_SIMPLE(activate_hide_selected_tracks)1799 DEFINE_SIMPLE (activate_hide_selected_tracks)
1800 {
1801   g_message ("hiding selected tracks");
1802   tracklist_selections_toggle_visibility (
1803     TRACKLIST_SELECTIONS);
1804 }
1805 
DEFINE_SIMPLE(activate_pin_selected_tracks)1806 DEFINE_SIMPLE (activate_pin_selected_tracks)
1807 {
1808   g_message ("pin/unpinning selected tracks");
1809 
1810   Track * track = TRACKLIST_SELECTIONS->tracks[0];
1811   bool pin = !track_is_pinned (track);
1812 
1813   GError * err = NULL;
1814   bool ret;
1815   if (pin)
1816     {
1817       ret =
1818         tracklist_selections_action_perform_pin (
1819           TRACKLIST_SELECTIONS,
1820           PORT_CONNECTIONS_MGR, &err);
1821     }
1822   else
1823     {
1824       ret =
1825         tracklist_selections_action_perform_unpin (
1826           TRACKLIST_SELECTIONS,
1827           PORT_CONNECTIONS_MGR, &err);
1828     }
1829 
1830   if (!ret)
1831     {
1832       HANDLE_ERROR (
1833         err, "%s", _("Failed to pin/unpin tracks"));
1834     }
1835 }
1836 
DEFINE_SIMPLE(activate_solo_selected_tracks)1837 DEFINE_SIMPLE (activate_solo_selected_tracks)
1838 {
1839   GError * err = NULL;
1840   bool ret =
1841     tracklist_selections_action_perform_edit_solo (
1842       TRACKLIST_SELECTIONS, F_SOLO, &err);
1843   if (!ret)
1844     {
1845       HANDLE_ERROR (
1846         err, "%s", _("Failed to solo tracks"));
1847     }
1848 }
1849 
DEFINE_SIMPLE(activate_unsolo_selected_tracks)1850 DEFINE_SIMPLE (activate_unsolo_selected_tracks)
1851 {
1852   GError * err = NULL;
1853   bool ret =
1854     tracklist_selections_action_perform_edit_solo (
1855       TRACKLIST_SELECTIONS, F_NO_SOLO, &err);
1856   if (!ret)
1857     {
1858       HANDLE_ERROR (
1859         err, "%s", _("Failed to unsolo tracks"));
1860     }
1861 }
1862 
DEFINE_SIMPLE(activate_mute_selected_tracks)1863 DEFINE_SIMPLE (activate_mute_selected_tracks)
1864 {
1865   GError * err = NULL;
1866   bool ret =
1867     tracklist_selections_action_perform_edit_mute (
1868       TRACKLIST_SELECTIONS, F_MUTE, &err);
1869   if (!ret)
1870     {
1871       HANDLE_ERROR (
1872         err, "%s", _("Failed to mute tracks"));
1873     }
1874 }
1875 
DEFINE_SIMPLE(activate_unmute_selected_tracks)1876 DEFINE_SIMPLE (activate_unmute_selected_tracks)
1877 {
1878   GError * err = NULL;
1879   bool ret =
1880     tracklist_selections_action_perform_edit_mute (
1881       TRACKLIST_SELECTIONS, F_NO_MUTE, &err);
1882   if (!ret)
1883     {
1884       HANDLE_ERROR (
1885         err, "%s", _("Failed to unmute tracks"));
1886     }
1887 }
1888 
DEFINE_SIMPLE(activate_listen_selected_tracks)1889 DEFINE_SIMPLE (activate_listen_selected_tracks)
1890 {
1891   GError * err = NULL;
1892   bool ret =
1893     tracklist_selections_action_perform_edit_listen (
1894       TRACKLIST_SELECTIONS, F_LISTEN, &err);
1895   if (!ret)
1896     {
1897       HANDLE_ERROR (
1898         err, "%s", _("Failed to listen tracks"));
1899     }
1900 }
1901 
DEFINE_SIMPLE(activate_unlisten_selected_tracks)1902 DEFINE_SIMPLE (activate_unlisten_selected_tracks)
1903 {
1904   GError * err = NULL;
1905   bool ret =
1906     tracklist_selections_action_perform_edit_listen (
1907       TRACKLIST_SELECTIONS, F_NO_LISTEN, &err);
1908   if (!ret)
1909     {
1910       HANDLE_ERROR (
1911         err, "%s", _("Failed to unlisten tracks"));
1912     }
1913 }
1914 
DEFINE_SIMPLE(activate_enable_selected_tracks)1915 DEFINE_SIMPLE (activate_enable_selected_tracks)
1916 {
1917   GError * err = NULL;
1918   bool ret =
1919     tracklist_selections_action_perform_edit_enable (
1920       TRACKLIST_SELECTIONS, F_ENABLE, &err);
1921   if (!ret)
1922     {
1923       HANDLE_ERROR (
1924         err, "%s", _("Failed to enable tracks"));
1925     }
1926 }
1927 
DEFINE_SIMPLE(activate_disable_selected_tracks)1928 DEFINE_SIMPLE (activate_disable_selected_tracks)
1929 {
1930   GError * err = NULL;
1931   bool ret =
1932     tracklist_selections_action_perform_edit_enable (
1933       TRACKLIST_SELECTIONS, F_NO_ENABLE, &err);
1934   if (!ret)
1935     {
1936       HANDLE_ERROR (
1937         err, "%s", _("Failed to disable tracks"));
1938     }
1939 }
1940 
1941 void
change_state_dim_output(GSimpleAction * action,GVariant * value,gpointer user_data)1942 change_state_dim_output (
1943   GSimpleAction * action,
1944   GVariant *      value,
1945   gpointer        user_data)
1946 {
1947   int dim = g_variant_get_boolean (value);
1948 
1949   g_message ("dim is %d", dim);
1950 
1951   g_simple_action_set_state (action, value);
1952 }
1953 
1954 void
change_state_loop(GSimpleAction * action,GVariant * value,gpointer user_data)1955 change_state_loop (
1956   GSimpleAction * action,
1957   GVariant *      value,
1958   gpointer        user_data)
1959 {
1960   int enabled = g_variant_get_boolean (value);
1961 
1962   g_simple_action_set_state (action, value);
1963 
1964   transport_set_loop (TRANSPORT, enabled);
1965 }
1966 
1967 void
change_state_metronome(GSimpleAction * action,GVariant * value,gpointer user_data)1968 change_state_metronome (
1969   GSimpleAction * action,
1970   GVariant *      value,
1971   gpointer        user_data)
1972 {
1973   bool enabled = g_variant_get_boolean (value);
1974 
1975   g_simple_action_set_state (action, value);
1976 
1977   transport_set_metronome_enabled (
1978     TRANSPORT, enabled);
1979 }
1980 
1981 void
change_state_musical_mode(GSimpleAction * action,GVariant * value,gpointer user_data)1982 change_state_musical_mode (
1983   GSimpleAction * action,
1984   GVariant *      value,
1985   gpointer        user_data)
1986 {
1987   int enabled = g_variant_get_boolean (value);
1988 
1989   g_simple_action_set_state (action, value);
1990 
1991   g_settings_set_boolean (
1992     S_UI, "musical-mode", enabled);
1993 }
1994 
1995 void
change_state_listen_notes(GSimpleAction * action,GVariant * value,gpointer user_data)1996 change_state_listen_notes (
1997   GSimpleAction * action,
1998   GVariant *      value,
1999   gpointer        user_data)
2000 {
2001   int enabled = g_variant_get_boolean (value);
2002 
2003   g_simple_action_set_state (action, value);
2004 
2005   g_settings_set_boolean (
2006     S_UI, "listen-notes", enabled);
2007 }
2008 
2009 static void
do_quantize(const char * variant,bool quick)2010 do_quantize (
2011   const char * variant,
2012   bool         quick)
2013 {
2014   g_debug ("quantize opts: %s", variant);
2015 
2016   if (string_is_equal (variant, "timeline")
2017       ||
2018       (string_is_equal (variant, "global")
2019        && PROJECT->last_selection
2020           == SELECTION_TYPE_TIMELINE))
2021     {
2022       if (quick)
2023         {
2024           GError * err = NULL;
2025           bool ret =
2026             arranger_selections_action_perform_quantize (
2027               (ArrangerSelections *) TL_SELECTIONS,
2028               QUANTIZE_OPTIONS_TIMELINE, &err);
2029           if (!ret)
2030             {
2031               HANDLE_ERROR (
2032                 err, "%s",
2033                 _("Failed to quantize"));
2034             }
2035         }
2036       else
2037         {
2038           QuantizeDialogWidget * quant =
2039             quantize_dialog_widget_new (
2040               QUANTIZE_OPTIONS_TIMELINE);
2041           gtk_window_set_transient_for (
2042             GTK_WINDOW (quant),
2043             GTK_WINDOW (MAIN_WINDOW));
2044           gtk_dialog_run (GTK_DIALOG (quant));
2045           gtk_widget_destroy (GTK_WIDGET (quant));
2046         }
2047     }
2048   else if (string_is_equal (variant, "editor")
2049            ||
2050            (string_is_equal (variant, "global")
2051             && PROJECT->last_selection
2052                == SELECTION_TYPE_EDITOR))
2053     {
2054       if (quick)
2055         {
2056           ArrangerSelections * sel =
2057             clip_editor_get_arranger_selections (
2058               CLIP_EDITOR);
2059           g_return_if_fail (sel);
2060 
2061           GError * err = NULL;
2062           bool ret =
2063             arranger_selections_action_perform_quantize (
2064               sel, QUANTIZE_OPTIONS_EDITOR, &err);
2065           if (!ret)
2066             {
2067               HANDLE_ERROR (
2068                 err, "%s",
2069                 _("Failed to quantize"));
2070             }
2071         }
2072       else
2073         {
2074           QuantizeDialogWidget * quant =
2075             quantize_dialog_widget_new (
2076               QUANTIZE_OPTIONS_EDITOR);
2077           gtk_window_set_transient_for (
2078             GTK_WINDOW (quant),
2079             GTK_WINDOW (MAIN_WINDOW));
2080           gtk_dialog_run (GTK_DIALOG (quant));
2081           gtk_widget_destroy (GTK_WIDGET (quant));
2082         }
2083     }
2084   else
2085     {
2086       ui_show_message_printf (
2087         MAIN_WINDOW, GTK_MESSAGE_WARNING,
2088         _("Must select either the timeline or the "
2089         "editor first. The current selection is "
2090         "%s"),
2091         selection_type_strings[
2092           PROJECT->last_selection].str);
2093     }
2094 }
2095 
2096 void
activate_quick_quantize(GSimpleAction * action,GVariant * _variant,gpointer user_data)2097 activate_quick_quantize (
2098   GSimpleAction *action,
2099   GVariant      * _variant,
2100   gpointer       user_data)
2101 {
2102   g_return_if_fail (_variant);
2103   gsize size;
2104   const char * variant =
2105     g_variant_get_string (_variant, &size);
2106   do_quantize (variant, true);
2107 }
2108 
2109 void
activate_quantize_options(GSimpleAction * action,GVariant * _variant,gpointer user_data)2110 activate_quantize_options (
2111   GSimpleAction *action,
2112   GVariant      *_variant,
2113   gpointer       user_data)
2114 {
2115   g_return_if_fail (_variant);
2116   gsize size;
2117   const char * variant =
2118     g_variant_get_string (_variant, &size);
2119   do_quantize (variant, false);
2120 }
2121 
2122 void
activate_mute_selection(GSimpleAction * action,GVariant * _variant,gpointer user_data)2123 activate_mute_selection (
2124   GSimpleAction *action,
2125   GVariant      *_variant,
2126   gpointer       user_data)
2127 {
2128   g_return_if_fail (_variant);
2129 
2130   gsize size;
2131   const char * variant =
2132     g_variant_get_string (_variant, &size);
2133   ArrangerSelections * sel = NULL;
2134   if (string_is_equal (variant, "timeline"))
2135     {
2136       sel = (ArrangerSelections *) TL_SELECTIONS;
2137     }
2138   else if (string_is_equal (variant, "editor"))
2139     {
2140       sel = (ArrangerSelections *) MA_SELECTIONS;
2141     }
2142   else if (string_is_equal (variant, "global"))
2143     {
2144       sel =
2145         project_get_arranger_selections_for_last_selection (
2146           PROJECT);
2147     }
2148   else
2149     {
2150       g_return_if_reached ();
2151     }
2152 
2153   if (sel)
2154     {
2155       GError * err = NULL;
2156       bool ret =
2157         arranger_selections_action_perform_edit (
2158           sel, NULL,
2159           ARRANGER_SELECTIONS_ACTION_EDIT_MUTE,
2160           F_NOT_ALREADY_EDITED, &err);
2161       if (!ret)
2162         {
2163           HANDLE_ERROR (
2164             err, "%s",
2165             _("Failed to mute selections"));
2166         }
2167     }
2168 
2169   g_message ("mute/unmute selections");
2170 }
2171 
DEFINE_SIMPLE(activate_merge_selection)2172 DEFINE_SIMPLE (activate_merge_selection)
2173 {
2174   g_message ("merge selections activated");
2175 
2176   if (TL_SELECTIONS->num_regions == 0)
2177     {
2178       ui_show_error_message (
2179         MAIN_WINDOW, _("No regions selected"));
2180       return;
2181     }
2182   if (!arranger_selections_all_on_same_lane (
2183         (ArrangerSelections *) TL_SELECTIONS))
2184     {
2185       ui_show_error_message (
2186         MAIN_WINDOW,
2187         _("Selections must be on the same lane"));
2188       return;
2189     }
2190   if (arranger_selections_contains_looped (
2191        (ArrangerSelections *) TL_SELECTIONS))
2192     {
2193       ui_show_error_message (
2194         MAIN_WINDOW,
2195         _("Cannot merge looped regions"));
2196       return;
2197     }
2198   if (TL_SELECTIONS->num_regions == 1)
2199     {
2200       /* nothing to do */
2201       return;
2202     }
2203 
2204   GError * err = NULL;
2205   bool ret =
2206     arranger_selections_action_perform_merge (
2207       (ArrangerSelections *) TL_SELECTIONS, &err);
2208   if (!ret)
2209     {
2210       HANDLE_ERROR (
2211         err, "%s",
2212         _("Failed to merge selections"));
2213     }
2214 }
2215 
2216 void
activate_set_timebase_master(GSimpleAction * action,GVariant * variant,gpointer user_data)2217 activate_set_timebase_master (
2218   GSimpleAction *action,
2219   GVariant      *variant,
2220   gpointer       user_data)
2221 {
2222   g_message ("set time base master");
2223 }
2224 
2225 void
activate_set_transport_client(GSimpleAction * action,GVariant * variant,gpointer user_data)2226 activate_set_transport_client (
2227   GSimpleAction *action,
2228   GVariant      *variant,
2229   gpointer       user_data)
2230 {
2231   g_message ("set transport client");
2232 }
2233 
2234 void
activate_unlink_jack_transport(GSimpleAction * action,GVariant * variant,gpointer user_data)2235 activate_unlink_jack_transport (
2236   GSimpleAction *action,
2237   GVariant      *variant,
2238   gpointer       user_data)
2239 {
2240   g_message ("unlink jack transport");
2241 }
2242 
2243 void
activate_show_file_browser(GSimpleAction * action,GVariant * variant,gpointer user_data)2244 activate_show_file_browser (
2245   GSimpleAction * action,
2246   GVariant *      variant,
2247   gpointer        user_data)
2248 {
2249   if (file_browser_window)
2250     {
2251       gtk_window_close (
2252         file_browser_window);
2253       file_browser_window = FALSE;
2254     }
2255   else
2256     {
2257       file_browser_window =
2258         GTK_WINDOW (
2259           file_browser_window_widget_new ());
2260       g_return_if_fail (file_browser_window);
2261       gtk_window_set_transient_for (
2262         file_browser_window,
2263         (GtkWindow *) MAIN_WINDOW);
2264       gtk_widget_show_all (
2265         (GtkWidget *) file_browser_window);
2266     }
2267 }
2268 
2269 void
activate_toggle_timeline_event_viewer(GSimpleAction * action,GVariant * variant,gpointer user_data)2270 activate_toggle_timeline_event_viewer (
2271   GSimpleAction * action,
2272   GVariant *      variant,
2273   gpointer        user_data)
2274 {
2275   if (!MW_TIMELINE_EVENT_VIEWER)
2276     return;
2277 
2278   int new_visibility =
2279     !gtk_widget_get_visible (
2280        GTK_WIDGET (MW_TIMELINE_EVENT_VIEWER));
2281 
2282   g_settings_set_boolean (
2283     S_UI, "timeline-event-viewer-visible",
2284     new_visibility);
2285   gtk_widget_set_visible (
2286     GTK_WIDGET (MW_TIMELINE_EVENT_VIEWER),
2287     new_visibility);
2288 }
2289 
2290 void
activate_toggle_editor_event_viewer(GSimpleAction * action,GVariant * variant,gpointer user_data)2291 activate_toggle_editor_event_viewer (
2292   GSimpleAction * action,
2293   GVariant *      variant,
2294   gpointer        user_data)
2295 {
2296   if (!MW_EDITOR_EVENT_VIEWER)
2297     return;
2298 
2299   int new_visibility =
2300     !gtk_widget_get_visible (
2301        GTK_WIDGET (MW_EDITOR_EVENT_VIEWER));
2302 
2303   g_settings_set_boolean (
2304     S_UI, "editor-event-viewer-visible",
2305     new_visibility);
2306   gtk_widget_set_visible (
2307     GTK_WIDGET (MW_EDITOR_EVENT_VIEWER),
2308     new_visibility);
2309 }
2310 
DEFINE_SIMPLE(activate_insert_silence)2311 DEFINE_SIMPLE (activate_insert_silence)
2312 {
2313   if (!TRANSPORT->has_range)
2314     return;
2315 
2316   Position start, end;
2317   transport_get_range_pos (
2318     TRANSPORT, true, &start);
2319   transport_get_range_pos (
2320     TRANSPORT, false, &end);
2321 
2322   GError * err = NULL;
2323   bool ret =
2324     range_action_perform_insert_silence (
2325       &start, &end, &err);
2326   if (!ret)
2327     {
2328       HANDLE_ERROR (
2329         err, "%s", _("Failed to insert silence"));
2330     }
2331 }
2332 
DEFINE_SIMPLE(activate_remove_range)2333 DEFINE_SIMPLE (activate_remove_range)
2334 {
2335   if (!TRANSPORT->has_range)
2336     return;
2337 
2338   Position start, end;
2339   transport_get_range_pos (
2340     TRANSPORT, true, &start);
2341   transport_get_range_pos (
2342     TRANSPORT, false, &end);
2343 
2344   GError * err = NULL;
2345   bool ret =
2346     range_action_perform_remove (
2347       &start, &end, &err);
2348   if (!ret)
2349     {
2350       HANDLE_ERROR (
2351         err, "%s",
2352         _("Failed to remove range"));
2353     }
2354 }
2355 
DEFINE_SIMPLE(change_state_timeline_playhead_scroll_edges)2356 DEFINE_SIMPLE (change_state_timeline_playhead_scroll_edges)
2357 {
2358   int enabled = g_variant_get_boolean (variant);
2359 
2360   g_simple_action_set_state (action, variant);
2361 
2362   g_settings_set_boolean (
2363     S_UI, "timeline-playhead-scroll-edges", enabled);
2364 
2365   EVENTS_PUSH (
2366     ET_PLAYHEAD_SCROLL_MODE_CHANGED, NULL);
2367 }
2368 
DEFINE_SIMPLE(change_state_timeline_playhead_follow)2369 DEFINE_SIMPLE (change_state_timeline_playhead_follow)
2370 {
2371   int enabled = g_variant_get_boolean (variant);
2372 
2373   g_simple_action_set_state (action, variant);
2374 
2375   g_settings_set_boolean (
2376     S_UI, "timeline-playhead-follow", enabled);
2377 
2378   EVENTS_PUSH (
2379     ET_PLAYHEAD_SCROLL_MODE_CHANGED, NULL);
2380 }
2381 
DEFINE_SIMPLE(change_state_editor_playhead_scroll_edges)2382 DEFINE_SIMPLE (change_state_editor_playhead_scroll_edges)
2383 {
2384   int enabled = g_variant_get_boolean (variant);
2385 
2386   g_simple_action_set_state (action, variant);
2387 
2388   g_settings_set_boolean (
2389     S_UI, "editor-playhead-scroll-edges", enabled);
2390 
2391   EVENTS_PUSH (
2392     ET_PLAYHEAD_SCROLL_MODE_CHANGED, NULL);
2393 }
2394 
DEFINE_SIMPLE(change_state_editor_playhead_follow)2395 DEFINE_SIMPLE (change_state_editor_playhead_follow)
2396 {
2397   int enabled = g_variant_get_boolean (variant);
2398 
2399   g_simple_action_set_state (action, variant);
2400 
2401   g_settings_set_boolean (
2402     S_UI, "editor-playhead-follow", enabled);
2403 
2404   EVENTS_PUSH (
2405     ET_PLAYHEAD_SCROLL_MODE_CHANGED, NULL);
2406 }
2407 
2408 /**
2409  * Common routine for applying undoable MIDI
2410  * functions.
2411  */
2412 static void
do_midi_func(MidiFunctionType type)2413 do_midi_func (
2414   MidiFunctionType type)
2415 {
2416   ArrangerSelections * sel =
2417     (ArrangerSelections *) MA_SELECTIONS;
2418   if (!arranger_selections_has_any (sel))
2419     {
2420       g_message ("no selections, doing nothing");
2421       return;
2422     }
2423 
2424   GError * err = NULL;
2425   bool ret =
2426     arranger_selections_action_perform_edit_midi_function (
2427       sel, type, &err);
2428   if (!ret)
2429     {
2430       HANDLE_ERROR (
2431         err, "%s",
2432         _("Failed to apply MIDI function"));
2433     }
2434 }
2435 
2436 /**
2437  * Common routine for applying undoable automation
2438  * functions.
2439  */
2440 static void
do_automation_func(AutomationFunctionType type)2441 do_automation_func (
2442   AutomationFunctionType type)
2443 {
2444   ArrangerSelections * sel =
2445     (ArrangerSelections *) AUTOMATION_SELECTIONS;
2446   if (!arranger_selections_has_any (sel))
2447     {
2448       g_message ("no selections, doing nothing");
2449       return;
2450     }
2451 
2452   GError * err = NULL;
2453   bool ret =
2454     arranger_selections_action_perform_edit_automation_function (
2455       sel, type, &err);
2456   if (!ret)
2457     {
2458       HANDLE_ERROR (
2459         err, "%s",
2460         _("Failed to apply automation function"));
2461     }
2462 }
2463 
2464 /**
2465  * Common routine for applying undoable audio
2466  * functions.
2467  *
2468  * @param uri Plugin URI, if applying plugin.
2469  */
2470 static void
do_audio_func(const AudioFunctionType type,const char * uri)2471 do_audio_func (
2472   const AudioFunctionType  type,
2473   const char *             uri)
2474 {
2475   g_return_if_fail (
2476     region_find (&CLIP_EDITOR->region_id));
2477   AUDIO_SELECTIONS->region_id =
2478     CLIP_EDITOR->region_id;
2479   ArrangerSelections * sel =
2480     (ArrangerSelections *) AUDIO_SELECTIONS;
2481   if (!arranger_selections_has_any (sel))
2482     {
2483       g_message ("no selections, doing nothing");
2484       return;
2485     }
2486 
2487   sel = arranger_selections_clone (sel);
2488 
2489   GError * err = NULL;
2490   bool ret;
2491   if (!arranger_selections_validate (sel))
2492     {
2493       goto free_audio_sel_and_return;
2494     }
2495 
2496   zix_sem_wait (&PROJECT->save_sem);
2497 
2498   ret =
2499     arranger_selections_action_perform_edit_audio_function (
2500       sel, type, uri, &err);
2501   if (!ret)
2502     {
2503       HANDLE_ERROR (
2504         err, "%s",
2505         _("Failed to apply automation function"));
2506     }
2507 
2508   zix_sem_post (&PROJECT->save_sem);
2509 
2510 free_audio_sel_and_return:
2511   arranger_selections_free (sel);
2512 }
2513 
DEFINE_SIMPLE(activate_editor_function)2514 DEFINE_SIMPLE (activate_editor_function)
2515 {
2516   size_t size;
2517   const char * str =
2518     g_variant_get_string (variant, &size);
2519 
2520   ZRegion * region =
2521     clip_editor_get_region (CLIP_EDITOR);
2522   if (!region)
2523     return;
2524 
2525   switch (region->id.type)
2526     {
2527     case REGION_TYPE_MIDI:
2528       {
2529         if (string_is_equal (str, "crescendo"))
2530           {
2531             do_midi_func (MIDI_FUNCTION_CRESCENDO);
2532           }
2533         else if (string_is_equal (str, "current"))
2534           {
2535             do_midi_func (
2536               g_settings_get_int (
2537                 S_UI, "midi-function"));
2538           }
2539         else if (string_is_equal (str, "flam"))
2540           {
2541             do_midi_func (MIDI_FUNCTION_FLAM);
2542           }
2543         else if (string_is_equal (str, "flip-horizontal"))
2544           {
2545             do_midi_func (MIDI_FUNCTION_FLIP_HORIZONTAL);
2546           }
2547         else if (string_is_equal (str, "flip-vertical"))
2548           {
2549             do_midi_func (MIDI_FUNCTION_FLIP_VERTICAL);
2550           }
2551         else if (string_is_equal (str, "legato"))
2552           {
2553             do_midi_func (MIDI_FUNCTION_LEGATO);
2554           }
2555         else if (string_is_equal (str, "portato"))
2556           {
2557             do_midi_func (MIDI_FUNCTION_PORTATO);
2558           }
2559         else if (string_is_equal (str, "staccato"))
2560           {
2561             do_midi_func (MIDI_FUNCTION_STACCATO);
2562           }
2563         else if (string_is_equal (str, "strum"))
2564           {
2565             do_midi_func (MIDI_FUNCTION_STRUM);
2566           }
2567         else
2568           {
2569             g_return_if_reached ();
2570           }
2571       }
2572       break;
2573     case REGION_TYPE_AUTOMATION:
2574       {
2575         if (string_is_equal (str, "current"))
2576           {
2577             do_automation_func (
2578               g_settings_get_int (
2579                 S_UI, "automation-function"));
2580           }
2581         else if (string_is_equal (
2582                    str, "flip-horizontal"))
2583           {
2584             do_automation_func (
2585               AUTOMATION_FUNCTION_FLIP_HORIZONTAL);
2586           }
2587         else if (string_is_equal (
2588                    str, "flip-vertical"))
2589           {
2590             do_automation_func (
2591               AUTOMATION_FUNCTION_FLIP_VERTICAL);
2592           }
2593         else
2594           {
2595             g_return_if_reached ();
2596           }
2597       }
2598       break;
2599     case REGION_TYPE_AUDIO:
2600       {
2601         bool done = false;
2602         if (string_is_equal (str, "current"))
2603           {
2604             do_audio_func (
2605               g_settings_get_int (
2606                 S_UI, "audio-function"), NULL);
2607             done = true;
2608           }
2609 
2610         for (int i = AUDIO_FUNCTION_INVERT;
2611              i < AUDIO_FUNCTION_CUSTOM_PLUGIN; i++)
2612           {
2613             char * audio_func_target =
2614               audio_function_get_action_target_for_type (
2615                 i);
2616             if (string_is_equal (
2617                   str, audio_func_target))
2618               do_audio_func (i, NULL);
2619             g_free (audio_func_target);
2620             done = true;
2621           }
2622 
2623         g_return_if_fail (done);
2624       }
2625       break;
2626     default:
2627       break;
2628     }
2629 }
2630 
DEFINE_SIMPLE(activate_editor_function_lv2)2631 DEFINE_SIMPLE (activate_editor_function_lv2)
2632 {
2633   size_t size;
2634   const char * str =
2635     g_variant_get_string (variant, &size);
2636 
2637   ZRegion * region =
2638     clip_editor_get_region (CLIP_EDITOR);
2639   if (!region)
2640     return;
2641 
2642   PluginDescriptor * descr =
2643     plugin_manager_find_plugin_from_uri (
2644       PLUGIN_MANAGER, str);
2645   g_return_if_fail (descr);
2646 
2647   switch (region->id.type)
2648     {
2649     case REGION_TYPE_MIDI:
2650       {
2651       }
2652       break;
2653     case REGION_TYPE_AUDIO:
2654       {
2655         do_audio_func (
2656           AUDIO_FUNCTION_CUSTOM_PLUGIN, str);
2657       }
2658       break;
2659     default:
2660       g_return_if_reached ();
2661       break;
2662     }
2663 }
2664 
DEFINE_SIMPLE(activate_midi_editor_highlighting)2665 DEFINE_SIMPLE (
2666   activate_midi_editor_highlighting)
2667 {
2668   size_t size;
2669   const char * str =
2670     g_variant_get_string (variant, &size);
2671 
2672 #define SET_HIGHLIGHT(txt,hl_type) \
2673   if (string_is_equal (str, txt)) \
2674     { \
2675       piano_roll_set_highlighting ( \
2676         PIANO_ROLL, PR_HIGHLIGHT_##hl_type); \
2677     }
2678 
2679   SET_HIGHLIGHT ("none", NONE);
2680   SET_HIGHLIGHT ("chord", CHORD);
2681   SET_HIGHLIGHT ("scale", SCALE);
2682   SET_HIGHLIGHT ("both", BOTH);
2683 
2684 #undef SET_HIGHLIGHT
2685 }
2686 
DEFINE_SIMPLE(activate_rename_track_or_region)2687 DEFINE_SIMPLE (
2688   activate_rename_track_or_region)
2689 {
2690   if (PROJECT->last_selection ==
2691         SELECTION_TYPE_TIMELINE)
2692     {
2693       g_message ("timeline");
2694       ArrangerSelections * sel =
2695         arranger_widget_get_selections (
2696           MW_TIMELINE);
2697       if (arranger_selections_get_num_objects (
2698             sel) == 1)
2699         {
2700           ArrangerObject * obj =
2701             arranger_selections_get_first_object (
2702               sel);
2703           if (obj->type ==
2704                 ARRANGER_OBJECT_TYPE_REGION)
2705             {
2706               StringEntryDialogWidget * dialog =
2707                 string_entry_dialog_widget_new (
2708                   _("Region name"), obj,
2709                   (GenericStringGetter)
2710                   arranger_object_get_name,
2711                   (GenericStringSetter)
2712                   arranger_object_set_name_with_action);
2713               gtk_widget_show_all (
2714                 GTK_WIDGET (dialog));
2715             }
2716         }
2717     }
2718   else if (PROJECT->last_selection ==
2719              SELECTION_TYPE_TRACKLIST)
2720     {
2721       g_message ("TODO - track");
2722     }
2723 }
2724 
DEFINE_SIMPLE(activate_add_region)2725 DEFINE_SIMPLE (activate_add_region)
2726 {
2727   if (TRACKLIST_SELECTIONS->num_tracks == 0)
2728     return;
2729 
2730   /*Track * track = TRACKLIST_SELECTIONS->tracks[0];*/
2731 
2732   /* TODO add region with default size */
2733 }
2734 
DEFINE_SIMPLE(activate_go_to_start)2735 DEFINE_SIMPLE (activate_go_to_start)
2736 {
2737   Position pos;
2738   position_init (&pos);
2739   transport_set_playhead_pos (
2740     TRANSPORT, &pos);
2741 }
2742 
DEFINE_SIMPLE(activate_input_bpm)2743 DEFINE_SIMPLE (activate_input_bpm)
2744 {
2745   StringEntryDialogWidget * dialog =
2746     string_entry_dialog_widget_new (
2747       _("Please enter a BPM"), P_TEMPO_TRACK,
2748       tempo_track_get_current_bpm_as_str,
2749       tempo_track_set_bpm_from_str);
2750   gtk_widget_show_all (GTK_WIDGET (dialog));
2751   gtk_dialog_run (GTK_DIALOG (dialog));
2752 }
2753 
DEFINE_SIMPLE(activate_tap_bpm)2754 DEFINE_SIMPLE (activate_tap_bpm)
2755 {
2756   ui_show_message_printf (
2757     MAIN_WINDOW, GTK_MESSAGE_WARNING,
2758     "%s", "Not implemented yet");
2759 }
2760 
2761 void
change_state_show_automation_values(GSimpleAction * action,GVariant * value,gpointer user_data)2762 change_state_show_automation_values (
2763   GSimpleAction * action,
2764   GVariant *      value,
2765   gpointer        user_data)
2766 {
2767   int enabled = g_variant_get_boolean (value);
2768 
2769   g_simple_action_set_state (action, value);
2770 
2771   g_settings_set_boolean (
2772     S_UI, "show-automation-values", enabled);
2773 
2774   EVENTS_PUSH (
2775     ET_AUTOMATION_VALUE_VISIBILITY_CHANGED, NULL);
2776 }
2777 
DEFINE_SIMPLE(activate_nudge_selection)2778 DEFINE_SIMPLE (activate_nudge_selection)
2779 {
2780   size_t size;
2781   const char * str =
2782     g_variant_get_string (variant, &size);
2783 
2784   double ticks =
2785     ARRANGER_SELECTIONS_DEFAULT_NUDGE_TICKS;
2786   bool left = string_is_equal (str, "left");
2787   if (left)
2788     ticks = - ticks;
2789 
2790   ArrangerSelections * sel =
2791     project_get_arranger_selections_for_last_selection (
2792       PROJECT);
2793   if (!sel || !arranger_selections_has_any (sel))
2794     return;
2795 
2796   if (sel->type == ARRANGER_SELECTIONS_TYPE_AUDIO)
2797     {
2798       do_audio_func (
2799         left
2800         ? AUDIO_FUNCTION_NUDGE_LEFT
2801         : AUDIO_FUNCTION_NUDGE_RIGHT,
2802         NULL);
2803       return;
2804     }
2805 
2806   Position start_pos;
2807   arranger_selections_get_start_pos (
2808     sel, &start_pos, F_GLOBAL);
2809   if (start_pos.ticks + ticks < 0)
2810     {
2811       g_message ("cannot nudge left");
2812       return;
2813     }
2814 
2815   GError * err = NULL;
2816   bool ret =
2817     arranger_selections_action_perform_move (
2818       sel, ticks, 0, 0, 0, 0, 0,
2819       F_NOT_ALREADY_MOVED, &err);
2820   if (!ret)
2821     {
2822       HANDLE_ERROR (
2823         err, "%s",
2824         _("Failed to move selections"));
2825     }
2826 }
2827