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