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 #include "audio/channel.h"
21 #include "audio/chord_track.h"
22 #include "audio/region.h"
23 #include "audio/track.h"
24 #include "gui/backend/piano_roll.h"
25 #include "gui/widgets/arranger.h"
26 #include "gui/widgets/bot_dock_edge.h"
27 #include "gui/widgets/center_dock.h"
28 #include "gui/widgets/clip_editor.h"
29 #include "gui/widgets/clip_editor_inner.h"
30 #include "gui/widgets/color_area.h"
31 #include "gui/widgets/main_window.h"
32 #include "gui/widgets/midi_arranger.h"
33 #include "gui/widgets/midi_editor_space.h"
34 #include "gui/widgets/midi_modifier_arranger.h"
35 #include "gui/widgets/midi_note.h"
36 #include "gui/widgets/editor_ruler.h"
37 #include "gui/widgets/piano_roll_keys.h"
38 #include "gui/widgets/ruler.h"
39 #include "project.h"
40 #include "utils/gtk.h"
41 #include "utils/math.h"
42 #include "utils/resources.h"
43 #include "zrythm_app.h"
44
45 #include <glib/gi18n.h>
46
G_DEFINE_TYPE(MidiEditorSpaceWidget,midi_editor_space_widget,GTK_TYPE_BOX)47 G_DEFINE_TYPE (
48 MidiEditorSpaceWidget, midi_editor_space_widget,
49 GTK_TYPE_BOX)
50
51 static void
52 on_midi_modifier_changed (
53 GtkComboBox *widget,
54 MidiEditorSpaceWidget * self)
55 {
56 piano_roll_set_midi_modifier (
57 PIANO_ROLL,
58 gtk_combo_box_get_active (widget));
59 }
60
61 /**
62 * Links scroll windows after all widgets have been
63 * initialized.
64 */
65 static void
link_scrolls(MidiEditorSpaceWidget * self)66 link_scrolls (
67 MidiEditorSpaceWidget * self)
68 {
69 /* link note keys v scroll to arranger v scroll */
70 if (self->piano_roll_keys_scroll)
71 {
72 gtk_scrolled_window_set_vadjustment (
73 self->piano_roll_keys_scroll,
74 gtk_scrolled_window_get_vadjustment (
75 GTK_SCROLLED_WINDOW (
76 self->arranger_scroll)));
77 }
78
79 /* link ruler h scroll to arranger h scroll */
80 if (MW_CLIP_EDITOR_INNER->ruler_scroll)
81 {
82 gtk_scrolled_window_set_hadjustment (
83 MW_CLIP_EDITOR_INNER->ruler_scroll,
84 gtk_scrolled_window_get_hadjustment (
85 GTK_SCROLLED_WINDOW (
86 self->arranger_scroll)));
87 }
88
89 /* link modifier arranger h scroll to arranger h scroll */
90 if (self->modifier_arranger_scroll)
91 {
92 gtk_scrolled_window_set_hadjustment (
93 self->modifier_arranger_scroll,
94 gtk_scrolled_window_get_hadjustment (
95 GTK_SCROLLED_WINDOW (
96 self->arranger_scroll)));
97 }
98
99 }
100
101 static int
on_scroll(GtkWidget * widget,GdkEventScroll * event,MidiEditorSpaceWidget * self)102 on_scroll (
103 GtkWidget * widget,
104 GdkEventScroll * event,
105 MidiEditorSpaceWidget * self)
106 {
107 if (event->state & GDK_CONTROL_MASK &&
108 event->state & GDK_SHIFT_MASK)
109 {
110 midi_arranger_handle_vertical_zoom_scroll (
111 MW_MIDI_ARRANGER, event);
112 }
113
114 return TRUE;
115 }
116
117 /*static void*/
118 /*scroll_to_mid_note (*/
119 /*MidiEditorSpaceWidget * self)*/
120 /*{*/
121 /*}*/
122
123 void
midi_editor_space_widget_refresh(MidiEditorSpaceWidget * self)124 midi_editor_space_widget_refresh (
125 MidiEditorSpaceWidget * self)
126 {
127 piano_roll_keys_widget_refresh (
128 self->piano_roll_keys);
129
130 /* relink scrolls */
131 link_scrolls (self);
132
133 /* setup combo box */
134 gtk_combo_box_set_active (
135 GTK_COMBO_BOX (
136 self->midi_modifier_chooser),
137 PIANO_ROLL->midi_modifier);
138 }
139
140 void
midi_editor_space_widget_update_size_group(MidiEditorSpaceWidget * self,int visible)141 midi_editor_space_widget_update_size_group (
142 MidiEditorSpaceWidget * self,
143 int visible)
144 {
145 clip_editor_inner_widget_add_to_left_of_ruler_sizegroup (
146 MW_CLIP_EDITOR_INNER,
147 GTK_WIDGET (self->midi_vel_chooser_box),
148 visible);
149 clip_editor_inner_widget_add_to_left_of_ruler_sizegroup (
150 MW_CLIP_EDITOR_INNER,
151 GTK_WIDGET (self->midi_notes_box),
152 visible);
153 }
154
155 void
midi_editor_space_widget_setup(MidiEditorSpaceWidget * self)156 midi_editor_space_widget_setup (
157 MidiEditorSpaceWidget * self)
158 {
159 if (self->arranger)
160 {
161 arranger_widget_setup (
162 Z_ARRANGER_WIDGET (self->arranger),
163 ARRANGER_WIDGET_TYPE_MIDI,
164 SNAP_GRID_EDITOR);
165 gtk_widget_show_all (
166 GTK_WIDGET (self->arranger));
167 }
168 if (self->modifier_arranger)
169 {
170 arranger_widget_setup (
171 Z_ARRANGER_WIDGET (self->modifier_arranger),
172 ARRANGER_WIDGET_TYPE_MIDI_MODIFIER,
173 SNAP_GRID_EDITOR);
174 gtk_widget_show_all (
175 GTK_WIDGET (self->modifier_arranger));
176 }
177
178 piano_roll_keys_widget_setup (
179 self->piano_roll_keys);
180
181 midi_editor_space_widget_refresh (self);
182
183 /* scroll to note in middle */
184 GtkAdjustment * adj =
185 gtk_scrolled_window_get_vadjustment (
186 self->arranger_scroll);
187 double lower =
188 gtk_adjustment_get_lower (adj);
189 double upper =
190 gtk_adjustment_get_upper (adj);
191 gtk_adjustment_set_value (
192 adj,
193 lower + (upper - lower) / 2.0);
194 }
195
196 static void
midi_editor_space_widget_init(MidiEditorSpaceWidget * self)197 midi_editor_space_widget_init (
198 MidiEditorSpaceWidget * self)
199 {
200 g_type_ensure (PIANO_ROLL_KEYS_WIDGET_TYPE);
201
202 gtk_widget_init_template (GTK_WIDGET (self));
203
204 self->arranger->type =
205 ARRANGER_WIDGET_TYPE_MIDI;
206 self->modifier_arranger->type =
207 ARRANGER_WIDGET_TYPE_MIDI_MODIFIER;
208
209 self->arranger_and_keys_vsize_group =
210 gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
211 gtk_size_group_add_widget (
212 self->arranger_and_keys_vsize_group,
213 GTK_WIDGET (self->arranger));
214 gtk_size_group_add_widget (
215 self->arranger_and_keys_vsize_group,
216 GTK_WIDGET (self->piano_roll_keys));
217
218 /* setup signals */
219 g_signal_connect (
220 G_OBJECT(self->midi_modifier_chooser),
221 "changed",
222 G_CALLBACK (on_midi_modifier_changed), self);
223 /*g_signal_connect (*/
224 /*G_OBJECT (self->piano_roll_keys_box),*/
225 /*"size-allocate",*/
226 /*G_CALLBACK (on_keys_box_size_allocate), self);*/
227 g_signal_connect (
228 G_OBJECT(self), "scroll-event",
229 G_CALLBACK (on_scroll), self);
230 }
231
232 static void
midi_editor_space_widget_class_init(MidiEditorSpaceWidgetClass * _klass)233 midi_editor_space_widget_class_init (
234 MidiEditorSpaceWidgetClass * _klass)
235 {
236 GtkWidgetClass * klass = GTK_WIDGET_CLASS (_klass);
237 resources_set_class_template (
238 klass,
239 "midi_editor_space.ui");
240
241 #define BIND_CHILD(x) \
242 gtk_widget_class_bind_template_child ( \
243 klass, \
244 MidiEditorSpaceWidget, \
245 x)
246
247 BIND_CHILD (midi_modifier_chooser);
248 BIND_CHILD (piano_roll_keys_scroll);
249 BIND_CHILD (piano_roll_keys_viewport);
250 BIND_CHILD (piano_roll_keys);
251 BIND_CHILD (midi_arranger_velocity_paned);
252 BIND_CHILD (arranger_scroll);
253 BIND_CHILD (arranger_viewport);
254 BIND_CHILD (arranger);
255 BIND_CHILD (modifier_arranger_scroll);
256 BIND_CHILD (modifier_arranger_viewport);
257 BIND_CHILD (modifier_arranger);
258 BIND_CHILD (midi_notes_box);
259 BIND_CHILD (midi_vel_chooser_box);
260 }
261