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 #include "audio/track.h"
21 #include "gui/widgets/dialogs/object_color_chooser_dialog.h"
22 #include "gui/widgets/color_area.h"
23 #include "gui/widgets/main_window.h"
24 #include "gui/widgets/track.h"
25 #include "gui/widgets/track_top_grid.h"
26 #include "utils/cairo.h"
27 #include "utils/color.h"
28 #include "utils/ui.h"
29 #include "zrythm_app.h"
30
31 #include <glib/gi18n.h>
32 #include <gtk/gtk.h>
33
G_DEFINE_TYPE(ColorAreaWidget,color_area_widget,GTK_TYPE_DRAWING_AREA)34 G_DEFINE_TYPE (
35 ColorAreaWidget, color_area_widget,
36 GTK_TYPE_DRAWING_AREA)
37
38 /**
39 * Draws the color picker.
40 */
41 static int
42 color_area_draw_cb (
43 GtkWidget * widget,
44 cairo_t * cr,
45 ColorAreaWidget * self)
46 {
47 if (self->redraw)
48 {
49 GtkStyleContext * context =
50 gtk_widget_get_style_context (widget);
51
52 int width =
53 gtk_widget_get_allocated_width (widget);
54 int height =
55 gtk_widget_get_allocated_height (widget);
56
57 self->cached_cr =
58 cairo_create (self->cached_surface);
59 z_cairo_reset_caches (
60 &self->cached_cr,
61 &self->cached_surface, width,
62 height, cr);
63
64 gtk_render_background (
65 context, self->cached_cr, 0, 0,
66 width, height);
67
68 GdkRGBA color;
69 if (self->type == COLOR_AREA_TYPE_TRACK)
70 {
71 Track * track = self->track;
72 if (track_is_enabled (track))
73 {
74 color = self->track->color;
75 }
76 else
77 {
78 color.red = 0.5;
79 color.green = 0.5;
80 color.blue = 0.5;
81 }
82 }
83 else
84 color = self->color;
85
86 if (self->hovered)
87 {
88 color_brighten_default (&color);
89 }
90
91 cairo_rectangle (
92 self->cached_cr, 0, 0, width, height);
93 gdk_cairo_set_source_rgba (
94 self->cached_cr, &color);
95 cairo_fill (self->cached_cr);
96
97 /* show track icon */
98 if (self->type == COLOR_AREA_TYPE_TRACK)
99 {
100 Track * track = self->track;
101
102 /* draw each parent */
103 GPtrArray * parents =
104 g_ptr_array_sized_new (8);
105 track_add_folder_parents (
106 track, parents, false);
107
108 size_t len = parents->len + 1;
109 for (size_t i = 0; i < parents->len; i++)
110 {
111 Track * parent_track =
112 g_ptr_array_index (parents, i);
113
114 double start_y =
115 ((double) i /
116 (double) len) *
117 (double) height;
118 double h =
119 (double) height /
120 (double) len;
121
122 cairo_rectangle (
123 self->cached_cr,
124 0, start_y, width, h);
125 color = parent_track->color;
126 if (self->hovered)
127 color_brighten_default (&color);
128 gdk_cairo_set_source_rgba (
129 self->cached_cr, &color);
130 cairo_fill (self->cached_cr);
131 }
132 g_ptr_array_unref (parents);
133
134 /*TRACK_WIDGET_GET_PRIVATE (*/
135 /*self->track->widget);*/
136
137 /*if (tw_prv->icon)*/
138 /*{*/
139 /*cairo_surface_t * surface =*/
140 /*gdk_cairo_surface_create_from_pixbuf (*/
141 /*tw_prv->icon, 0, NULL);*/
142
143 /*GdkRGBA c2, c3;*/
144 /*ui_get_contrast_color (*/
145 /*color, &c2);*/
146 /*ui_get_contrast_color (*/
147 /*&c2, &c3);*/
148
149 /*[> add shadow in the back <]*/
150 /*cairo_set_source_rgba (*/
151 /*self->cached_cr, c3.red,*/
152 /*c3.green, c3.blue, 0.4);*/
153 /*cairo_mask_surface(*/
154 /*self->cached_cr, surface, 2, 2);*/
155 /*cairo_fill(self->cached_cr);*/
156
157 /*[> add main icon <]*/
158 /*cairo_set_source_rgba (*/
159 /*self->cached_cr, c2.red, c2.green, c2.blue, 1);*/
160 /*[>cairo_set_source_surface (<]*/
161 /*[>self->cached_cr, surface, 1, 1);<]*/
162 /*cairo_mask_surface(*/
163 /*self->cached_cr, surface, 1, 1);*/
164 /*cairo_fill (self->cached_cr);*/
165 /*}*/
166 }
167 self->redraw = 0;
168 }
169
170 cairo_set_source_surface (
171 cr, self->cached_surface, 0, 0);
172 cairo_paint (cr);
173
174 return FALSE;
175 }
176
177 static void
multipress_pressed(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,ColorAreaWidget * self)178 multipress_pressed (
179 GtkGestureMultiPress * gesture,
180 gint n_press,
181 gdouble x,
182 gdouble y,
183 ColorAreaWidget * self)
184 {
185 if (n_press == 1 && self->track)
186 {
187 ObjectColorChooserDialogWidget * color_chooser =
188 object_color_chooser_dialog_widget_new_for_track (
189 self->track);
190 object_color_chooser_dialog_widget_run (
191 color_chooser);
192 }
193 }
194
195 static void
color_area_widget_on_size_allocate(GtkWidget * widget,GdkRectangle * allocation,ColorAreaWidget * self)196 color_area_widget_on_size_allocate (
197 GtkWidget *widget,
198 GdkRectangle *allocation,
199 ColorAreaWidget * self)
200 {
201 self->redraw = true;
202 }
203
204 static gboolean
on_motion(GtkWidget * widget,GdkEventMotion * event,ColorAreaWidget * self)205 on_motion (
206 GtkWidget * widget,
207 GdkEventMotion * event,
208 ColorAreaWidget * self)
209 {
210 if (event->type == GDK_ENTER_NOTIFY)
211 {
212 self->hovered = true;
213 gtk_widget_queue_draw (GTK_WIDGET (self));
214 self->redraw = true;
215 }
216 else if (event->type == GDK_LEAVE_NOTIFY)
217 {
218 self->hovered = false;
219 gtk_widget_queue_draw (GTK_WIDGET (self));
220 self->redraw = true;
221 }
222
223 return FALSE;
224 }
225
226 /**
227 * Creates a generic color widget using the given
228 * color pointer.
229 */
230 void
color_area_widget_setup_generic(ColorAreaWidget * self,GdkRGBA * color)231 color_area_widget_setup_generic (
232 ColorAreaWidget * self,
233 GdkRGBA * color)
234 {
235 self->color = *color;
236 }
237
238 /**
239 * Creates a ColorAreaWidget for use inside
240 * TrackWidget implementations.
241 */
242 void
color_area_widget_setup_track(ColorAreaWidget * self,Track * track)243 color_area_widget_setup_track (
244 ColorAreaWidget * self,
245 Track * track)
246 {
247 self->track = track;
248 self->type = COLOR_AREA_TYPE_TRACK;
249 self->redraw = true;
250
251 g_message (
252 "setting up track %s for %p", track->name, self);
253 }
254
255 /**
256 * Changes the color.
257 *
258 * Track types don't need to do this since the
259 * color is read directly from the Track.
260 */
261 void
color_area_widget_set_color(ColorAreaWidget * self,GdkRGBA * color)262 color_area_widget_set_color (
263 ColorAreaWidget * self,
264 GdkRGBA * color)
265 {
266 self->color = *color;
267
268 gtk_widget_queue_draw (GTK_WIDGET (self));
269 self->redraw = true;
270 }
271
272 static void
color_area_widget_init(ColorAreaWidget * self)273 color_area_widget_init (ColorAreaWidget * self)
274 {
275 /* make able to notify */
276 gtk_widget_add_events (
277 GTK_WIDGET (self),
278 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
279 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
280
281 GtkGestureMultiPress * mp =
282 GTK_GESTURE_MULTI_PRESS (
283 gtk_gesture_multi_press_new (
284 GTK_WIDGET (self)));
285 g_signal_connect (
286 G_OBJECT (mp), "pressed",
287 G_CALLBACK (multipress_pressed), self);
288 g_signal_connect (
289 G_OBJECT (self), "size-allocate",
290 G_CALLBACK (color_area_widget_on_size_allocate),
291 self);
292 g_signal_connect (
293 G_OBJECT (self), "draw",
294 G_CALLBACK (color_area_draw_cb), self);
295 g_signal_connect (
296 G_OBJECT (self), "enter-notify-event",
297 G_CALLBACK (on_motion), self);
298 g_signal_connect (
299 G_OBJECT (self), "leave-notify-event",
300 G_CALLBACK (on_motion), self);
301 self->redraw = true;
302 }
303
304 static void
color_area_widget_class_init(ColorAreaWidgetClass * _klass)305 color_area_widget_class_init (
306 ColorAreaWidgetClass * _klass)
307 {
308 GtkWidgetClass * klass = GTK_WIDGET_CLASS (_klass);
309 gtk_widget_class_set_css_name (
310 klass, "color-area");
311 }
312