1 /*
2 * Copyright (C) 2018-2019 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of Zrythm
5 *
6 * Zrythm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Zrythm is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 /**
21 * \file
22 *
23 * Timeline background inheriting from arranger_bg.
24 */
25
26 #include "zrythm.h"
27 #include "audio/automation_track.h"
28 #include "audio/automation_tracklist.h"
29 #include "audio/channel.h"
30 #include "audio/instrument_track.h"
31 #include "audio/router.h"
32 #include "audio/track.h"
33 #include "audio/tracklist.h"
34 #include "audio/transport.h"
35 #include "gui/widgets/arranger.h"
36 #include "gui/widgets/automation_point.h"
37 #include "gui/widgets/center_dock.h"
38 #include "gui/widgets/main_window.h"
39 #include "gui/widgets/ruler.h"
40 #include "gui/widgets/timeline_arranger.h"
41 #include "gui/widgets/timeline_bg.h"
42 #include "gui/widgets/timeline_panel.h"
43 #include "gui/widgets/timeline_ruler.h"
44 #include "gui/widgets/track.h"
45 #include "gui/widgets/tracklist.h"
46 #include "project.h"
47 #include "settings/settings.h"
48 #include "utils/cairo.h"
49
50 #include <gtk/gtk.h>
51
G_DEFINE_TYPE(TimelineBgWidget,timeline_bg_widget,ARRANGER_BG_WIDGET_TYPE)52 G_DEFINE_TYPE (
53 TimelineBgWidget,
54 timeline_bg_widget,
55 ARRANGER_BG_WIDGET_TYPE)
56
57 /**
58 * To be called by the arranger bg during drawing.
59 */
60 void
61 timeline_bg_widget_draw (
62 TimelineBgWidget * self,
63 cairo_t * cr,
64 GdkRectangle * rect)
65 {
66 ArrangerBgWidgetPrivate * prv =
67 arranger_bg_widget_get_private (
68 Z_ARRANGER_BG_WIDGET (self));
69
70 /* handle horizontal drawing for tracks */
71 GtkWidget * tw_widget;
72 gint track_start_offset;
73 Track * track;
74 TrackWidget * tw;
75 int line_y, i, j;
76 int is_unpinned_timeline =
77 prv->arranger ==
78 (ArrangerWidget *) (MW_TIMELINE);
79 int is_pinned_timeline =
80 prv->arranger ==
81 (ArrangerWidget *) (MW_PINNED_TIMELINE);
82 for (i = 0; i < TRACKLIST->num_tracks; i++)
83 {
84 track = TRACKLIST->tracks[i];
85
86 /* skip tracks in the other timeline (pinned/
87 * non-pinned) */
88 if (!track->visible ||
89 (is_unpinned_timeline &&
90 track->pinned) ||
91 (is_pinned_timeline &&
92 !track->pinned))
93 continue;
94
95 /* draw line below widget */
96 tw = track->widget;
97 if (!GTK_IS_WIDGET (tw))
98 continue;
99 tw_widget = (GtkWidget *) tw;
100
101 int full_track_height =
102 track_get_full_visible_height (track);
103
104 gtk_widget_translate_coordinates (
105 tw_widget,
106 GTK_WIDGET (
107 is_pinned_timeline ?
108 MW_TRACKLIST->pinned_box :
109 MW_TRACKLIST->unpinned_box),
110 0, 0, NULL, &track_start_offset);
111
112 line_y =
113 track_start_offset + full_track_height;
114
115 if (line_y >= rect->y &&
116 line_y < rect->y + rect->height)
117 {
118 z_cairo_draw_horizontal_line (
119 cr, line_y - rect->y, 0,
120 rect->width, 1.0);
121 }
122
123 int total_height = track->main_height;
124
125 #define OFFSET_PLUS_TOTAL_HEIGHT \
126 (track_start_offset + total_height)
127
128 /* --- draw lanes --- */
129
130 if (track->lanes_visible)
131 {
132 for (j = 0; j < track->num_lanes; j++)
133 {
134 TrackLane * lane = track->lanes[j];
135
136 /* horizontal line above lane */
137 if (OFFSET_PLUS_TOTAL_HEIGHT >
138 rect->y &&
139 OFFSET_PLUS_TOTAL_HEIGHT <
140 rect->y + rect->height)
141 {
142 z_cairo_draw_horizontal_line (
143 cr,
144 OFFSET_PLUS_TOTAL_HEIGHT -
145 rect->y,
146 0, rect->width, 0.4);
147 }
148
149 total_height += lane->height;
150 }
151 }
152
153 /* --- draw automation related stuff --- */
154
155 /* skip tracks without visible automation */
156 if (!track->automation_visible)
157 continue;
158
159 AutomationTracklist * atl =
160 track_get_automation_tracklist (track);
161 if (atl)
162 {
163 AutomationTrack * at;
164 for (j = 0; j < atl->num_ats; j++)
165 {
166 at = atl->ats[j];
167
168 if (!at->created || !at->visible)
169 continue;
170
171 /* horizontal line above automation
172 * track */
173 if (OFFSET_PLUS_TOTAL_HEIGHT >
174 rect->y &&
175 OFFSET_PLUS_TOTAL_HEIGHT <
176 rect->y + rect->height)
177 {
178 z_cairo_draw_horizontal_line (
179 cr,
180 OFFSET_PLUS_TOTAL_HEIGHT -
181 rect->y,
182 0, rect->width, 0.2);
183 }
184
185 float normalized_val =
186 automation_track_get_normalized_val_at_pos (
187 at, PLAYHEAD);
188 if (normalized_val < 0.f)
189 normalized_val =
190 automatable_real_val_to_normalized (
191 at->automatable,
192 automatable_get_val (
193 at->automatable));
194
195 int y_px =
196 automation_track_get_y_px_from_normalized_val (
197 at,
198 normalized_val);
199
200 /* line at current val */
201 cairo_set_source_rgba (
202 cr,
203 track->color.red,
204 track->color.green,
205 track->color.blue,
206 0.3);
207 cairo_set_line_width (cr, 1);
208 cairo_move_to (
209 cr, 0,
210 (OFFSET_PLUS_TOTAL_HEIGHT + y_px) -
211 rect->y);
212 cairo_line_to (
213 cr, rect->width,
214 (OFFSET_PLUS_TOTAL_HEIGHT + y_px) -
215 rect->y);
216 cairo_stroke (cr);
217
218 /* show shade under the line */
219 /*cairo_set_source_rgba (*/
220 /*cr,*/
221 /*track->color.red,*/
222 /*track->color.green,*/
223 /*track->color.blue,*/
224 /*0.06);*/
225 /*cairo_rectangle (*/
226 /*cr,*/
227 /*0,*/
228 /*(OFFSET_PLUS_TOTAL_HEIGHT + y_px) -*/
229 /*rect->y,*/
230 /*rect->width,*/
231 /*at->height - y_px);*/
232 /*cairo_fill (cr);*/
233
234 total_height += at->height;
235 }
236 }
237 }
238 }
239
240 /*static gboolean*/
241 /*on_motion (TimelineBgWidget * self,*/
242 /*GdkEventMotion *event)*/
243 /*{*/
244 /*return FALSE;*/
245 /*}*/
246
247 TimelineBgWidget *
timeline_bg_widget_new(RulerWidget * ruler,ArrangerWidget * arranger)248 timeline_bg_widget_new (
249 RulerWidget * ruler,
250 ArrangerWidget * arranger)
251 {
252 TimelineBgWidget * self =
253 g_object_new (TIMELINE_BG_WIDGET_TYPE,
254 NULL);
255
256 ARRANGER_BG_WIDGET_GET_PRIVATE (self);
257 ab_prv->ruler = ruler;
258 ab_prv->arranger = arranger;
259
260 return self;
261 }
262
263 static void
timeline_bg_widget_class_init(TimelineBgWidgetClass * _klass)264 timeline_bg_widget_class_init (
265 TimelineBgWidgetClass * _klass)
266 {
267 }
268
269 static void
timeline_bg_widget_init(TimelineBgWidget * self)270 timeline_bg_widget_init (TimelineBgWidget *self )
271 {
272 gtk_widget_add_events (
273 GTK_WIDGET (self),
274 GDK_ALL_EVENTS_MASK);
275 }
276