1 /*
2  * Copyright (C) 2018-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 Zrythm.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 /**
21  * \file
22  *
23  * User Interface utils.
24  *
25  */
26 
27 #ifndef __UTILS_UI_H__
28 #define __UTILS_UI_H__
29 
30 #include <stdbool.h>
31 
32 #include "utils/localization.h"
33 
34 #include <gtk/gtk.h>
35 
36 typedef struct Position Position;
37 typedef struct Port Port;
38 
39 /**
40  * @addtogroup utils
41  *
42  * @{
43  */
44 
45 #define UI_MAX_CURSORS 400
46 
47 #define UI_CACHES (zrythm_app->ui_caches)
48 #define UI_COLORS (&UI_CACHES->colors)
49 
50 /* FIXME remove these and use theme */
51 #define UI_COLOR_DARK_TEXT "#323232"
52 #define UI_COLOR_BRIGHT_TEXT "#cdcdcd"
53 #define UI_COLOR_YELLOW "#F9CA1B"
54 #define UI_COLOR_PURPLE "#9D3955"
55 #define UI_COLOR_BUTTON_NORMAL "#343434"
56 #define UI_COLOR_BUTTON_HOVER "#444444"
57 #define UI_COLOR_RECORD_CHECKED "#ED2939"
58 #define UI_COLOR_RECORD_ACTIVE "#FF2400"
59 
60 #define UI_DELETE_ICON_NAME "z-edit-delete"
61 
62 static const GdkRGBA UI_COLOR_BLACK = {
63   0, 0, 0, 1
64 };
65 
66 typedef enum UiDetail
67 {
68   UI_DETAIL_HIGH,
69   UI_DETAIL_NORMAL,
70   UI_DETAIL_LOW,
71   UI_DETAIL_ULTRA_LOW,
72 } UiDetail;
73 
74 static const char * ui_detail_str[] =
75 {
76   __("High"),
77   __("Normal"),
78   __("Low"),
79   __("Ultra Low"),
80 };
81 
82 static inline const char *
ui_detail_to_string(UiDetail detail)83 ui_detail_to_string (
84   UiDetail detail)
85 {
86   return ui_detail_str[detail];
87 }
88 
89 /**
90  * Commonly used UI colors.
91  */
92 typedef struct UiColors
93 {
94   GdkRGBA       dark_text;
95   GdkRGBA       dark_orange;
96   GdkRGBA       bright_orange;
97   GdkRGBA       bright_text;
98   GdkRGBA       matcha;
99   GdkRGBA       bright_green;
100   GdkRGBA       darkish_green;
101   GdkRGBA       prefader_send;
102   GdkRGBA       postfader_send;
103   GdkRGBA       record_active;
104   GdkRGBA       record_checked;
105   GdkRGBA       solo_active;
106   GdkRGBA       solo_checked;
107   GdkRGBA       fader_fill_start;
108   GdkRGBA       fader_fill_end;
109   GdkRGBA       highlight_scale_bg;
110   GdkRGBA       highlight_chord_bg;
111   GdkRGBA       highlight_bass_bg;
112   GdkRGBA       highlight_both_bg;
113   GdkRGBA       highlight_scale_fg;
114   GdkRGBA       highlight_chord_fg;
115   GdkRGBA       highlight_bass_fg;
116   GdkRGBA       highlight_both_fg;
117 } UiColors;
118 
119 /**
120  * Specification for a cursor.
121  *
122  * Used for caching.
123  */
124 typedef struct UiCursor
125 {
126   char        name[400];
127   GdkCursor * cursor;
128   GdkPixbuf * pixbuf;
129   int         offset_x;
130   int         offset_y;
131 } UiCursor;
132 
133 /**
134  * Caches.
135  */
136 typedef struct UiCaches
137 {
138   UiColors      colors;
139   UiCursor      cursors[UI_MAX_CURSORS];
140   int           num_cursors;
141 } UiCaches;
142 
143 /**
144  * Space on the edges to show resize cursors
145  */
146 #define UI_RESIZE_CURSOR_SPACE 8
147 
148 /*
149  * Drag n Drop related.
150  * Gtk target entries.
151  */
152 
153 /** Plugin descriptor, used to instantiate plugins.
154  */
155 #define TARGET_ENTRY_PLUGIN_DESCR "PLUGIN_DESCR"
156 
157 /** For SupportedFile pointers. */
158 #define TARGET_ENTRY_SUPPORTED_FILE "SUPPORTED_FILE"
159 
160 /** Plugin ID, used to move/copy plugins. */
161 #define TARGET_ENTRY_PLUGIN "PLUGIN"
162 
163 /* File path. Not used at the moment. */
164 #define TARGET_ENTRY_FILE_PATH "FILE_PATH"
165 
166 /** URI list. */
167 #define TARGET_ENTRY_URI_LIST "text/uri-list"
168 
169 /**
170  * Track target entry.
171  *
172  * This is just the identifier. The
173  * TracklistSelections will be used.
174  */
175 #define TARGET_ENTRY_TRACK "TRACK"
176 
177 /**
178  * Chord descriptor target entry.
179  */
180 #define TARGET_ENTRY_CHORD_DESCR "CHORD_DESCR"
181 
182 /* */
183 #define TARGET_ENTRY_TL_SELECTIONS \
184   "TL_SELECTIONS"
185 
186 #define GET_ATOM(x) \
187   gdk_atom_intern (x, 1)
188 
189 #define ui_add_widget_tooltip(widget,txt) \
190   gtk_widget_set_tooltip_text ( \
191     GTK_WIDGET (widget), txt)
192 
193 #define ui_set_hover_status_bar_signals(w,t) \
194   g_signal_connect ( \
195     G_OBJECT (w), "enter-notify-event", \
196     G_CALLBACK ( \
197       ui_on_motion_set_status_bar_text_cb), \
198     g_strdup (t)); \
199   g_signal_connect ( \
200     G_OBJECT(w), "leave-notify-event", \
201     G_CALLBACK ( \
202       ui_on_motion_set_status_bar_text_cb), \
203     g_strdup (t));
204 
205 /**
206  * Shows the notification when idle.
207  *
208  * This should be called from threads other than GTK main
209  * thread.
210  */
211 #define ui_show_notification_idle(msg) \
212   char * text = g_strdup (msg); \
213   g_message (msg); \
214   g_idle_add ((GSourceFunc) ui_show_notification_idle_func, \
215               (void *) text); \
216   g_free (text)
217 
218 #define ui_is_widget_revealed(widget) \
219   (gtk_widget_get_allocated_height ( \
220      GTK_WIDGET (widget)) > 1 || \
221    gtk_widget_get_allocated_width ( \
222      GTK_WIDGET (widget)) > 1)
223 
224 /**
225  * Used in handlers to get the state mask.
226  */
227 GdkModifierType
228 ui_get_state_mask (
229   GtkGesture * gesture);
230 
231 /**
232  * Various cursor states to be shared.
233  */
234 typedef enum UiCursorState
235 {
236   UI_CURSOR_STATE_DEFAULT,
237   UI_CURSOR_STATE_RESIZE_L,
238   UI_CURSOR_STATE_REPEAT_L,
239   UI_CURSOR_STATE_RESIZE_R,
240   UI_CURSOR_STATE_REPEAT_R,
241   UI_CURSOR_STATE_RESIZE_UP,
242 } UiCursorState;
243 
244 /**
245  * Various overlay actions to be shared.
246  */
247 typedef enum UiOverlayAction
248 {
249   UI_OVERLAY_ACTION_NONE,
250   UI_OVERLAY_ACTION_CREATING_RESIZING_R,
251   UI_OVERLAY_ACTION_CREATING_MOVING,
252   UI_OVERLAY_ACTION_RESIZING_L,
253   UI_OVERLAY_ACTION_RESIZING_L_LOOP,
254   UI_OVERLAY_ACTION_RESIZING_L_FADE,
255   UI_OVERLAY_ACTION_RESIZING_R,
256   UI_OVERLAY_ACTION_RESIZING_R_LOOP,
257   UI_OVERLAY_ACTION_RESIZING_R_FADE,
258   UI_OVERLAY_ACTION_RESIZING_UP,
259   UI_OVERLAY_ACTION_RESIZING_UP_FADE_IN,
260   UI_OVERLAY_ACTION_RESIZING_UP_FADE_OUT,
261   UI_OVERLAY_ACTION_STRETCHING_L,
262   UI_OVERLAY_ACTION_STRETCHING_R,
263 
264   UI_OVERLAY_ACTION_AUDITIONING,
265 
266   /**
267    * Auto-filling in edit mode.
268    *
269    * @note This is also used for the pencil tool in
270    *   velocity and automation editors.
271    */
272   UI_OVERLAY_ACTION_AUTOFILLING,
273 
274   /** Erasing. */
275   UI_OVERLAY_ACTION_ERASING,
276   UI_OVERLAY_ACTION_STARTING_ERASING,
277 
278   /**
279    * To be set in drag_start.
280    */
281   UI_OVERLAY_ACTION_STARTING_MOVING,
282   UI_OVERLAY_ACTION_STARTING_MOVING_COPY,
283   UI_OVERLAY_ACTION_STARTING_MOVING_LINK,
284   UI_OVERLAY_ACTION_MOVING,
285   UI_OVERLAY_ACTION_MOVING_COPY,
286   UI_OVERLAY_ACTION_MOVING_LINK,
287   UI_OVERLAY_ACTION_STARTING_CHANGING_CURVE,
288   UI_OVERLAY_ACTION_CHANGING_CURVE,
289 
290   /**
291    * To be set in drag_start.
292    *
293    * Useful to check if nothing was clicked.
294    */
295   UI_OVERLAY_ACTION_STARTING_SELECTION,
296   UI_OVERLAY_ACTION_SELECTING,
297 
298   /** Like selecting but it auto deletes whatever
299    * touches the selection. */
300   UI_OVERLAY_ACTION_STARTING_DELETE_SELECTION,
301   UI_OVERLAY_ACTION_DELETE_SELECTING,
302 
303   UI_OVERLAY_ACTION_STARTING_RAMP,
304   UI_OVERLAY_ACTION_RAMPING,
305   UI_OVERLAY_ACTION_CUTTING,
306 
307   UI_OVERLAY_ACTION_RENAMING,
308   NUM_UI_OVERLAY_ACTIONS,
309 } UiOverlayAction;
310 
311 /**
312  * Various overlay actions to be shared.
313  */
314 static const char * ui_overlay_strings[] =
315   {
316     "NONE",
317     "RESIZING_R",
318     "MOVING",
319     "RESIZING_L",
320     "RESIZING_L_LOOP",
321     "RESIZING_L_FADE",
322     "RESIZING_R",
323     "RESIZING_R_LOOP",
324     "RESIZING_R_FADE",
325     "RESIZING_UP",
326     "RESIZING_UP_FADE_IN",
327     "RESIZING_UP_FADE_OUT",
328     "STRETCHING_L",
329     "STRETCHING_R",
330     "AUDITIONING",
331     "AUTOFILLING",
332     "ERASING",
333     "STARTING_ERASING",
334     "STARTING_MOVING",
335     "STARTING_MOVING_COPY",
336     "STARTING_MOVING_LINK",
337     "MOVING",
338     "MOVING_COPY",
339     "MOVING_LINK",
340     "STARTING_CHANGING_CURVE",
341     "CHANGING_CURVE",
342     "STARTING_SELECTION",
343     "SELECTING",
344     "STARTING_DELETE_SELECTION",
345     "DELETE_SELECTING",
346     "STARTING_RAMP",
347     "RAMPING",
348     "CUTTING",
349     "RENAMING",
350     "INVALID",
351   };
352 
353 static inline const char *
ui_get_overlay_action_string(UiOverlayAction action)354 ui_get_overlay_action_string (
355   UiOverlayAction action)
356 {
357   return ui_overlay_strings[action];
358 }
359 
360 /**
361  * Dragging modes for widgets that have click&drag.
362  */
363 typedef enum UiDragMode
364 {
365   /** Value is wherever the cursor is. */
366   UI_DRAG_MODE_CURSOR,
367 
368   /** Value is changed based on the offset. */
369   UI_DRAG_MODE_RELATIVE,
370 
371   /** Value is changed based on the offset, times
372    * a multiplier. */
373   UI_DRAG_MODE_RELATIVE_WITH_MULTIPLIER,
374 } UiDragMode;
375 
376 void
377 ui_set_pointer_cursor (
378   GtkWidget * widget);
379 
380 #define ui_set_pencil_cursor(widget) \
381   ui_set_cursor_from_icon_name ( \
382     GTK_WIDGET (widget), \
383     "pencil", 3, 18);
384 
385 #define ui_set_brush_cursor(widget) \
386   ui_set_cursor_from_icon_name ( \
387     GTK_WIDGET (widget), \
388     "draw-brush", 3, 18);
389 
390 #define ui_set_cut_clip_cursor(widget) \
391   ui_set_cursor_from_icon_name ( \
392     GTK_WIDGET (widget), \
393     "cut-tool", 9, 6);
394 
395 #define ui_set_eraser_cursor(widget) \
396   ui_set_cursor_from_icon_name ( \
397     GTK_WIDGET (widget), \
398     "draw-eraser", 3, 6);
399 
400 #define ui_set_line_cursor(widget) \
401   ui_set_cursor_from_icon_name ( \
402     GTK_WIDGET (widget), \
403     "draw-line", 3, 6);
404 
405 #define ui_set_speaker_cursor(widget) \
406   ui_set_cursor_from_icon_name ( \
407     GTK_WIDGET (widget), \
408     "audio-volume-high", 3, 6);
409 
410 #define ui_set_hand_cursor(widget) \
411   ui_set_cursor_from_icon_name ( \
412     GTK_WIDGET (widget), \
413     "transform-move", 10, 10);
414 
415 #define ui_set_left_resize_cursor(widget) \
416   ui_set_cursor_from_icon_name ( \
417     GTK_WIDGET (widget), \
418     "object-resize-left", 0, 10);
419 
420 #define ui_set_left_stretch_cursor(widget) \
421   ui_set_cursor_from_icon_name ( \
422     GTK_WIDGET (widget), \
423     "object-stretch-left", 0, 10);
424 
425 #define ui_set_left_resize_loop_cursor(widget) \
426   ui_set_cursor_from_icon_name ( \
427     GTK_WIDGET (widget), \
428     "object-resize-loop-left", 0, 10);
429 
430 #define ui_set_right_resize_cursor(widget) \
431   ui_set_cursor_from_icon_name ( \
432     GTK_WIDGET (widget), \
433     "object-resize-right", 15, 10);
434 
435 #define ui_set_right_stretch_cursor(widget) \
436   ui_set_cursor_from_icon_name ( \
437     GTK_WIDGET (widget), \
438     "object-stretch-right", 15, 10);
439 
440 #define ui_set_right_resize_loop_cursor(widget) \
441   ui_set_cursor_from_icon_name ( \
442     GTK_WIDGET (widget), \
443     "object-resize-loop-right", 15, 10);
444 
445 #define ui_set_fade_in_cursor(widget) \
446   ui_set_cursor_from_icon_name ( \
447     GTK_WIDGET (widget), \
448     "fade-in", 11, 11);
449 
450 #define ui_set_fade_out_cursor(widget) \
451   ui_set_cursor_from_icon_name ( \
452     GTK_WIDGET (widget), \
453     "fade-out", 11, 11);
454 
455 /**
456  * Sets cursor from icon name.
457  */
458 void
459 ui_set_cursor_from_icon_name (
460   GtkWidget *  widget,
461   const char * name,
462   int          offset_x,
463   int          offset_y);
464 
465 /**
466  * Sets cursor from standard cursor name.
467  */
468 void
469 ui_set_cursor_from_name (
470   GtkWidget *  widget,
471   const char * name);
472 
473 gboolean
474 ui_on_motion_set_status_bar_text_cb (
475   GtkWidget * widget,
476   GdkEvent *  event,
477   char *      text);
478 
479 /**
480  * Shows a popup message of the given type with the
481  * given message.
482  */
483 void
484 ui_show_message_full (
485   GtkWindow *    parent_window,
486   GtkMessageType type,
487   const char *   format,
488   ...) G_GNUC_PRINTF (3, 4);
489 
490 /**
491  * Wrapper to show error message so that no casting
492  * of the window is needed on the caller side.
493  */
494 #define ui_show_error_message(win, msg) \
495     ui_show_message_full ( \
496       win ? GTK_WINDOW (win) : NULL, \
497       GTK_MESSAGE_ERROR, \
498       "%s", msg);
499 
500 /**
501  * Type can be GTK_MESSAGE_ERROR, etc.
502  */
503 #define ui_show_message_printf(win,type,fmt,...) \
504   ui_show_message_full ( \
505     win ? GTK_WINDOW (win) : NULL, \
506     type, fmt, __VA_ARGS__)
507 
508 /**
509  * Returns if \ref rect is hit or not by the
510  * given coordinate.
511  *
512  * @param check_x Check x-axis for match.
513  * @param check_y Check y-axis for match.
514  * @param x x in parent space.
515  * @param y y in parent space.
516  * @param x_padding Padding to add to the x
517  *   of the object when checking if hit.
518  *   The bigger the padding the more space the
519  *   child will have to get hit.
520  * @param y_padding Padding to add to the y
521  *   of the object when checking if hit.
522  *   The bigger the padding the more space the
523  *   child will have to get hit.
524  */
525 bool
526 ui_is_point_in_rect_hit (
527   GdkRectangle * rect,
528   const bool     check_x,
529   const bool     check_y,
530   double         x,
531   double         y,
532   double         x_padding,
533   double         y_padding);
534 
535 /**
536  * Returns if the child is hit or not by the
537  * coordinates in parent.
538  *
539  * @param check_x Check x-axis for match.
540  * @param check_y Check y-axis for match.
541  * @param x x in parent space.
542  * @param y y in parent space.
543  * @param x_padding Padding to add to the x
544  *   of the object when checking if hit.
545  *   The bigger the padding the more space the
546  *   child will have to get hit.
547  * @param y_padding Padding to add to the y
548  *   of the object when checking if hit.
549  *   The bigger the padding the more space the
550  *   child will have to get hit.
551  */
552 int
553 ui_is_child_hit (
554   GtkWidget * parent,
555   GtkWidget *    child,
556   const int            check_x,
557   const int            check_y,
558   const double         x,
559   const double         y,
560   const double         x_padding,
561   const double         y_padding);
562 
563 /**
564  * Returns the matching hit child, or NULL.
565  */
566 GtkWidget *
567 ui_get_hit_child (
568   GtkContainer * parent,
569   double         x, ///< x in parent space
570   double         y, ///< y in parent space
571   GType          type); ///< type to look for
572 
573 UiDetail
574 ui_get_detail_level (void);
575 
576 /**
577  * Converts from pixels to position.
578  *
579  * Only works with positive numbers. Negatives will
580  * be clamped at 0. If a negative is needed, pass
581  * the abs to this function and then change the
582  * sign.
583  *
584  * @param has_padding Whether @ref px contains
585  *   padding.
586  */
587 NONNULL
588 void
589 ui_px_to_pos_timeline (
590   double     px,
591   Position * pos,
592   bool       has_padding);
593 
594 /**
595  * Converts from pixels to frames.
596  *
597  * Returns the frames.
598  *
599  * @param has_padding Whether then given px contains
600  *   padding.
601  */
602 long
603 ui_px_to_frames_timeline (
604   double px,
605   int    has_padding);
606 
607 /**
608  * Converts from pixels to frames.
609  *
610  * Returns the frames.
611  *
612  * @param has_padding Whether then given px contains
613  *   padding.
614  */
615 long
616 ui_px_to_frames_editor (
617   double px,
618   int    has_padding);
619 
620 /**
621  * Converts position to px, optionally adding the
622  * ruler padding.
623  */
624 NONNULL
625 int
626 ui_pos_to_px_timeline (
627   Position * pos,
628   int        use_padding);
629 
630 /**
631  * Converts position to px, optionally adding the ruler
632  * padding.
633  */
634 NONNULL
635 int
636 ui_pos_to_px_editor (
637   Position * pos,
638   bool       use_padding);
639 
640 /**
641  * Converts from pixels to position.
642  *
643  * Only works with positive numbers. Negatives will
644  * be clamped at 0. If a negative is needed, pass
645  * the abs to this function and then change the
646  * sign.
647  *
648  * @param has_padding Whether @ref px contains
649  *   padding.
650  */
651 NONNULL
652 void
653 ui_px_to_pos_editor (
654   double     px,
655   Position * pos,
656   bool       has_padding);
657 
658 /**
659  * Converts RGB to hex string.
660  */
661 void
662 ui_rgb_to_hex (
663   double red,
664   double green,
665   double blue,
666   char * buf);
667 
668 void
669 ui_gdk_rgba_to_hex (
670   GdkRGBA * color,
671   char *    buf);
672 
673 /**
674  * Shows a notification in the revealer.
675  */
676 void
677 ui_show_notification (const char * msg);
678 
679 /**
680  * Show notification from non-GTK threads.
681  *
682  * This should be used internally. Use the
683  * ui_show_notification_idle macro instead.
684  */
685 int
686 ui_show_notification_idle_func (char * msg);
687 
688 /**
689  * Returns the modifier type (state mask) from the
690  * given gesture.
691  */
692 void
693 ui_get_modifier_type_from_gesture (
694   GtkGestureSingle * gesture,
695   GdkModifierType *  state_mask); ///< return value
696 
697 /**
698  * Sets up a combo box to have a selection of
699  * languages.
700  */
701 void
702 ui_setup_language_combo_box (
703   GtkComboBox * language);
704 
705 /**
706  * Sets up an audio backends combo box.
707  */
708 void
709 ui_setup_audio_backends_combo_box (
710   GtkComboBox * cb);
711 
712 /**
713  * Sets up a MIDI backends combo box.
714  */
715 void
716 ui_setup_midi_backends_combo_box (
717   GtkComboBox * cb);
718 
719 /**
720  * Sets up a pan algorithm combo box.
721  */
722 void
723 ui_setup_pan_algo_combo_box (
724   GtkComboBox * cb);
725 
726 /**
727  * Sets up a pan law combo box.
728  */
729 void
730 ui_setup_pan_law_combo_box (
731   GtkComboBox * cb);
732 
733 /**
734  * Sets up a pan law combo box.
735  */
736 void
737 ui_setup_buffer_size_combo_box (
738   GtkComboBox * cb);
739 
740 /**
741  * Sets up a pan law combo box.
742  */
743 void
744 ui_setup_samplerate_combo_box (
745   GtkComboBox * cb);
746 
747 /**
748  * Sets up a pan law combo box.
749  */
750 void
751 ui_setup_device_name_combo_box (
752   GtkComboBoxText * cb);
753 
754 /**
755  * Sets up the VST paths entry.
756  */
757 void
758 ui_setup_vst_paths_entry (
759   GtkEntry * entry);
760 
761 /**
762  * Updates the the VST paths in the gsettings from
763  * the text in the entry.
764  */
765 void
766 ui_update_vst_paths_from_entry (
767   GtkEntry * entry);
768 
769 /**
770  * Returns the "a locale for the language you have
771  * selected..." text based on the given language.
772  *
773  * Must be free'd by caller.
774  */
775 char *
776 ui_get_locale_not_available_string (
777   LocalizationLanguage lang);
778 
779 /**
780  * Returns the contrasting color (variation of
781  * black or white) based on if the given color is
782  * dark enough or not.
783  *
784  * @param src The source color.
785  * @param dest The desination color to write to.
786  */
787 void
788 ui_get_contrast_color (
789   GdkRGBA * src,
790   GdkRGBA * dest);
791 
792 /**
793  * Returns the color in-between two colors.
794  *
795  * @param transition How far to transition (0.5 for
796  *   half).
797  */
798 void
799 ui_get_mid_color (
800   GdkRGBA * dest,
801   const GdkRGBA * c1,
802   const GdkRGBA * c2,
803   const double    transition);
804 
805 /**
806  * Returns if the 2 rectangles overlay.
807  */
808 NONNULL
809 PURE
810 static inline bool
ui_rectangle_overlap(const GdkRectangle * const rect1,const GdkRectangle * const rect2)811 ui_rectangle_overlap (
812   const GdkRectangle * const rect1,
813   const GdkRectangle * const rect2)
814 {
815   /* if one rect is on the side of the other */
816   if (rect1->x > rect2->x + rect2->width ||
817       rect2->x > rect1->x + rect1->width)
818     return false;
819 
820   /* if one rect is above the other */
821   if (rect1->y > rect2->y + rect2->height ||
822       rect2->y > rect1->y + rect1->height)
823     return false;
824 
825   return true;
826 }
827 
828 /**
829  * Gets the color the widget should be.
830  *
831  * @param color The original color.
832  * @param is_selected Whether the widget is supposed
833  *   to be selected or not.
834  */
835 void
836 ui_get_arranger_object_color (
837   GdkRGBA *    color,
838   const bool   is_hovered,
839   const bool   is_selected,
840   const bool   is_transient,
841   const bool   is_muted);
842 
843 /**
844  * Gets a draggable value as a normalized value
845  * between 0 and 1.
846  *
847  * @param size Widget size (either width or height).
848  * @param start_px Px at start of drag.
849  * @param cur_px Current px.
850  * @param last_px Px during last call.
851  */
852 double
853 ui_get_normalized_draggable_value (
854   double       size,
855   double       cur_val,
856   double       start_px,
857   double       cur_px,
858   double       last_px,
859   double       multiplier,
860   UiDragMode   mode);
861 
862 /**
863  * All purpose menuitem callback for binding MIDI
864  * CC to a port.
865  *
866  * An action will be performed if bound.
867  */
868 void
869 ui_bind_midi_cc_item_activate_cb (
870   GtkMenuItem * menuitem,
871   Port *        port);
872 
873 UiCaches *
874 ui_caches_new (void);
875 
876 void
877 ui_caches_free (
878   UiCaches * self);
879 
880 /**
881  * @}
882  */
883 
884 #endif
885