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