1 /*
2  * Copyright (C) 2019-2020 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 /**
21  * \file
22  *
23  * Digital meter used for displaying Position,
24  * BPM, etc.
25  */
26 
27 #ifndef __GUI_WIDGETS_DIGITAL_METER_H__
28 #define __GUI_WIDGETS_DIGITAL_METER_H__
29 
30 #include <stdbool.h>
31 
32 #include "audio/transport.h"
33 #include "utils/types.h"
34 
35 #include <gtk/gtk.h>
36 
37 #define DIGITAL_METER_WIDGET_TYPE \
38   (digital_meter_widget_get_type ())
39 G_DECLARE_FINAL_TYPE (
40   DigitalMeterWidget,
41   digital_meter_widget,
42   Z, DIGITAL_METER_WIDGET,
43   GtkDrawingArea)
44 
45 typedef enum NoteLength NoteLength;
46 typedef enum NoteType NoteType;
47 typedef struct Position Position;
48 
49 /**
50  * @addtogroup widgets
51  *
52  * @{
53  */
54 
55 typedef enum DigitalMeterType
56 {
57   DIGITAL_METER_TYPE_BPM,
58   DIGITAL_METER_TYPE_POSITION,
59   DIGITAL_METER_TYPE_TIMESIG,
60   DIGITAL_METER_TYPE_NOTE_TYPE,
61   DIGITAL_METER_TYPE_NOTE_LENGTH,
62 } DigitalMeterType;
63 
64 typedef struct SnapGrid SnapGrid;
65 
66 typedef struct _DigitalMeterWidget
67 {
68   GtkDrawingArea           parent_instance;
69 
70   DigitalMeterType         type;
71 
72   bool                     is_transport;
73 
74   GtkGestureDrag *         drag;
75   double                   last_y;
76   double                   last_x;
77   int                      height_start_pos;
78   int                      height_end_pos;
79 
80   /* ========= BPM ========= */
81   /* for BPM */
82   int                      num_part_start_pos;
83   int                      num_part_end_pos;
84   int                      dec_part_start_pos;
85   int                      dec_part_end_pos;
86 
87   /** Used when changing the BPM. */
88   bpm_t                    bpm_at_start;
89 
90   /** Used during update. */
91   bpm_t                    last_set_bpm;
92 
93   /** Flag to update BPM. */
94   bool                     update_num;
95   /** Flag to update BPM decimal. */
96   bool                     update_dec;
97 
98   /* ========= BPM end ========= */
99 
100   /* ========= position ========= */
101 
102   int                      bars_start_pos;
103   int                      bars_end_pos;
104   int                      beats_start_pos;
105   int                      beats_end_pos;
106   int                      sixteenths_start_pos;
107   int                      sixteenths_end_pos;
108   int                      ticks_start_pos;
109   int                      ticks_end_pos;
110 
111   /** Update flags. */
112   int                      update_bars;
113   int                      update_beats;
114   int                      update_sixteenths;
115   int                      update_ticks;
116 
117   /* ========= position end ========= */
118 
119   /* ========= time ========= */
120 
121   /** For time. */
122   int                      minutes_start_pos;
123   int                      minutes_end_pos;
124   int                      seconds_start_pos;
125   int                      seconds_end_pos;
126   int                      ms_start_pos;
127   int                      ms_end_pos;
128 
129   /** Update flags. */
130   int                      update_minutes;
131   int                      update_seconds;
132   int                      update_ms;
133 
134   /* ========= time end ========= */
135 
136   /* for note length/type */
137   NoteLength *             note_length;
138   NoteType *               note_type;
139   int                      update_note_length; ///< flag to update note length
140   int                      start_note_length; ///< start note length
141   int                      update_note_type; ///< flag to update note type
142   int                      start_note_type; ///< start note type
143 
144   /* for time sig */
145   int                      update_timesig_top;
146   /* ebeat unit */
147   int                      update_timesig_bot;
148 
149   /** Used when changing the time signature. */
150   int                      beats_per_bar_at_start;
151   int                      beat_unit_at_start;
152 
153   /* ---------- FOR POSITION ---------------- */
154   void *     obj;
155 
156   /** Getter for Position. */
157   void       (*getter)(void*, Position*);
158   /** Setter for Position. */
159   void       (*setter)(void*, Position*);
160   /** Function to call on drag begin. */
161   void       (*on_drag_begin)(void*);
162   /** Function to call on drag end. */
163   void       (*on_drag_end)(void*);
164 
165   /* ----------- position end --------------- */
166 
167   /** Draw line above the meter or not. */
168   int        draw_line;
169 
170   /** Caption to show above, NULL to not show. */
171   char *     caption;
172 
173   /** Cached layouts for drawing text. */
174   PangoLayout * caption_layout;
175   PangoLayout * seg7_layout;
176   PangoLayout * normal_layout;
177 } DigitalMeterWidget;
178 
179 /**
180  * Creates a digital meter with the given type (
181  * bpm or position).
182  */
183 DigitalMeterWidget *
184 digital_meter_widget_new (
185   DigitalMeterType  type,
186   NoteLength *      note_length,
187   NoteType *        note_type,
188   const char *      caption);
189 
190 
191 #define digital_meter_widget_new_for_position( \
192   obj,drag_begin,getter,setter,drag_end,caption) \
193   _digital_meter_widget_new_for_position ( \
194     (void *) obj, \
195     (void (*) (void *)) drag_begin, \
196     (void (*) (void *, Position *)) getter, \
197     (void (*) (void *, Position *)) setter, \
198     (void (*) (void *)) drag_end, \
199     caption)
200 
201 /**
202  * Creates a digital meter for an arbitrary position.
203  *
204  * @param obj The object to call the get/setters with.
205  *
206  *   E.g. Region.
207  * @param get_val The getter func to get the position,
208  *   passing the obj and the position to save to.
209  * @param set_val The setter function to set the
210  *   position.
211  * @param drag_begin Function to call when
212  *   starting the action.
213  * @parram drag_end Function to call when ending
214  *   the action.
215  */
216 DigitalMeterWidget *
217 _digital_meter_widget_new_for_position(
218   void * obj,
219   void (*drag_begin)(void *),
220   void (*get_val)(void *, Position *),
221   void (*set_val)(void *, Position *),
222   void (*drag_end)(void *),
223   const char * caption);
224 
225 void
226 digital_meter_set_draw_line (
227   DigitalMeterWidget * self,
228   int                  draw_line);
229 
230 /**
231  * @}
232  */
233 
234 #endif
235