1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2021 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU 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  * GSequencer 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/X/editor/ags_automation_edit.h>
21 #include <ags/X/editor/ags_automation_edit_callbacks.h>
22 
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_automation_editor.h>
25 
26 #include <gdk/gdkkeysyms.h>
27 #include <atk/atk.h>
28 
29 #include <cairo.h>
30 #include <math.h>
31 
32 #include <ags/i18n.h>
33 
34 static GType ags_accessible_automation_edit_get_type(void);
35 void ags_automation_edit_class_init(AgsAutomationEditClass *automation_edit);
36 void ags_accessible_automation_edit_class_init(AtkObject *object);
37 void ags_accessible_automation_edit_action_interface_init(AtkActionIface *action);
38 void ags_automation_edit_connectable_interface_init(AgsConnectableInterface *connectable);
39 void ags_automation_edit_init(AgsAutomationEdit *automation_edit);
40 void ags_automation_edit_set_property(GObject *gobject,
41 				      guint prop_id,
42 				      const GValue *value,
43 				      GParamSpec *param_spec);
44 void ags_automation_edit_get_property(GObject *gobject,
45 				      guint prop_id,
46 				      GValue *value,
47 				      GParamSpec *param_spec);
48 void ags_automation_edit_finalize(GObject *gobject);
49 
50 void ags_automation_edit_connect(AgsConnectable *connectable);
51 void ags_automation_edit_disconnect(AgsConnectable *connectable);
52 AtkObject* ags_automation_edit_get_accessible(GtkWidget *widget);
53 
54 gboolean ags_accessible_automation_edit_do_action(AtkAction *action,
55 						  gint i);
56 gint ags_accessible_automation_edit_get_n_actions(AtkAction *action);
57 const gchar* ags_accessible_automation_edit_get_description(AtkAction *action,
58 							    gint i);
59 const gchar* ags_accessible_automation_edit_get_name(AtkAction *action,
60 						     gint i);
61 const gchar* ags_accessible_automation_edit_get_keybinding(AtkAction *action,
62 							   gint i);
63 gboolean ags_accessible_automation_edit_set_description(AtkAction *action,
64 							gint i);
65 gchar* ags_accessible_automation_edit_get_localized_name(AtkAction *action,
66 							 gint i);
67 
68 void ags_automation_edit_get_preferred_width(GtkWidget *widget,
69 					     gint *minimal_width,
70 					     gint *natural_width);
71 void ags_automation_edit_get_preferred_height(GtkWidget *widget,
72 					      gint *minimal_height,
73 					      gint *natural_height);
74 void ags_automation_edit_size_allocate(GtkWidget *widget,
75 				       GtkAllocation *allocation);
76 void ags_automation_edit_show(GtkWidget *widget);
77 void ags_automation_edit_show_all(GtkWidget *widget);
78 
79 gboolean ags_automation_edit_auto_scroll_timeout(GtkWidget *widget);
80 
81 /**
82  * SECTION:ags_automation_edit
83  * @short_description: edit automations
84  * @title: AgsAutomationEdit
85  * @section_id:
86  * @include: ags/X/editor/ags_automation_edit.h
87  *
88  * The #AgsAutomationEdit lets you edit automations.
89  */
90 
91 enum{
92   PROP_0,
93   PROP_CHANNEL_TYPE,
94   PROP_FILENAME,
95   PROP_EFFECT,
96   PROP_CONTROL_SPECIFIER,
97   PROP_CONTROL_NAME,
98   PROP_LOWER,
99   PROP_UPPER,
100   PROP_DEFAULT_VALUE,
101 };
102 
103 static gpointer ags_automation_edit_parent_class = NULL;
104 
105 static GQuark quark_accessible_object = 0;
106 
107 GHashTable *ags_automation_edit_auto_scroll = NULL;
108 
109 GType
ags_automation_edit_get_type(void)110 ags_automation_edit_get_type(void)
111 {
112   static volatile gsize g_define_type_id__volatile = 0;
113 
114   if(g_once_init_enter (&g_define_type_id__volatile)){
115     GType ags_type_automation_edit = 0;
116 
117     static const GTypeInfo ags_automation_edit_info = {
118       sizeof (AgsAutomationEditClass),
119       NULL, /* base_init */
120       NULL, /* base_finalize */
121       (GClassInitFunc) ags_automation_edit_class_init,
122       NULL, /* class_finalize */
123       NULL, /* class_data */
124       sizeof (AgsAutomationEdit),
125       0,    /* n_preallocs */
126       (GInstanceInitFunc) ags_automation_edit_init,
127     };
128 
129     static const GInterfaceInfo ags_connectable_interface_info = {
130       (GInterfaceInitFunc) ags_automation_edit_connectable_interface_init,
131       NULL, /* interface_finalize */
132       NULL, /* interface_data */
133     };
134 
135     ags_type_automation_edit = g_type_register_static(GTK_TYPE_TABLE,
136 						      "AgsAutomationEdit", &ags_automation_edit_info,
137 						      0);
138 
139     g_type_add_interface_static(ags_type_automation_edit,
140 				AGS_TYPE_CONNECTABLE,
141 				&ags_connectable_interface_info);
142 
143     g_once_init_leave(&g_define_type_id__volatile, ags_type_automation_edit);
144   }
145 
146   return g_define_type_id__volatile;
147 }
148 
149 static GType
ags_accessible_automation_edit_get_type(void)150 ags_accessible_automation_edit_get_type(void)
151 {
152   static GType ags_type_accessible_automation_edit = 0;
153 
154   if(!ags_type_accessible_automation_edit){
155     const GTypeInfo ags_accesssible_automation_edit_info = {
156       sizeof(GtkAccessibleClass),
157       NULL,           /* base_init */
158       NULL,           /* base_finalize */
159       (GClassInitFunc) ags_accessible_automation_edit_class_init,
160       NULL,           /* class_finalize */
161       NULL,           /* class_data */
162       sizeof(GtkAccessible),
163       0,             /* n_preallocs */
164       NULL, NULL
165     };
166 
167     static const GInterfaceInfo atk_action_interface_info = {
168       (GInterfaceInitFunc) ags_accessible_automation_edit_action_interface_init,
169       NULL, /* interface_finalize */
170       NULL, /* interface_data */
171     };
172 
173     ags_type_accessible_automation_edit = g_type_register_static(GTK_TYPE_ACCESSIBLE,
174 								 "AgsAccessibleAutomationEdit", &ags_accesssible_automation_edit_info,
175 								 0);
176 
177     g_type_add_interface_static(ags_type_accessible_automation_edit,
178 				ATK_TYPE_ACTION,
179 				&atk_action_interface_info);
180   }
181 
182   return(ags_type_accessible_automation_edit);
183 }
184 
185 
186 void
ags_automation_edit_class_init(AgsAutomationEditClass * automation_edit)187 ags_automation_edit_class_init(AgsAutomationEditClass *automation_edit)
188 {
189   GtkWidgetClass *widget;
190 
191   GObjectClass *gobject;
192 
193   GParamSpec *param_spec;
194 
195   ags_automation_edit_parent_class = g_type_class_peek_parent(automation_edit);
196 
197   /* GObjectClass */
198   gobject = G_OBJECT_CLASS(automation_edit);
199 
200   gobject->set_property = ags_automation_edit_set_property;
201   gobject->get_property = ags_automation_edit_get_property;
202 
203   gobject->finalize = ags_automation_edit_finalize;
204 
205   /* properties */
206   /**
207    * AgsAutomationArea:channel-type:
208    *
209    * The target channel.
210    *
211    * Since: 3.0.0
212    */
213   param_spec = g_param_spec_gtype("channel-type",
214 				  i18n_pspec("assigned channel type"),
215 				  i18n_pspec("The channel type it is assigned with"),
216 				  G_TYPE_NONE,
217 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
218   g_object_class_install_property(gobject,
219 				  PROP_CHANNEL_TYPE,
220 				  param_spec);
221 
222   /**
223    * AgsChannel:filename:
224    *
225    * The assigned #AgsFilename representing this channel.
226    *
227    * Since: 3.0.0
228    */
229   param_spec = g_param_spec_string("filename",
230 				   i18n_pspec("filename assigned with"),
231 				   i18n_pspec("The filename it is assigned with"),
232 				   NULL,
233 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
234   g_object_class_install_property(gobject,
235 				  PROP_FILENAME,
236 				  param_spec);
237 
238   /**
239    * AgsChannel:effect:
240    *
241    * The assigned #AgsEffect representing this channel.
242    *
243    * Since: 3.0.0
244    */
245   param_spec = g_param_spec_string("effect",
246 				   i18n_pspec("effect assigned with"),
247 				   i18n_pspec("The effect name it is assigned with"),
248 				   NULL,
249 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
250   g_object_class_install_property(gobject,
251 				  PROP_EFFECT,
252 				  param_spec);
253 
254   /**
255    * AgsChannel:control-specifier:
256    *
257    * The assigned #AgsControl-Specifier representing this channel.
258    *
259    * Since: 3.0.0
260    */
261   param_spec = g_param_spec_string("control-specifier",
262 				   i18n_pspec("assigned control specifier"),
263 				   i18n_pspec("The control specifier it is assigned with"),
264 				   NULL,
265 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
266   g_object_class_install_property(gobject,
267 				  PROP_CONTROL_SPECIFIER,
268 				  param_spec);
269 
270   /**
271    * AgsChannel:control-name:
272    *
273    * The assigned #AgsControl-Name representing this channel.
274    *
275    * Since: 3.0.0
276    */
277   param_spec = g_param_spec_string("control-name",
278 				   i18n_pspec("displayed control name"),
279 				   i18n_pspec("The control name to display"),
280 				   NULL,
281 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
282   g_object_class_install_property(gobject,
283 				  PROP_CONTROL_NAME,
284 				  param_spec);
285 
286   /**
287    * AgsAutomationEdit:lower:
288    *
289    * The automation edit's lower range.
290    *
291    * Since: 3.0.0
292    */
293   param_spec = g_param_spec_double("lower",
294 				   "lower",
295 				   "The lower of automation edit",
296 				   -G_MAXDOUBLE,
297 				   G_MAXDOUBLE,
298 				   AGS_AUTOMATION_EDIT_DEFAULT_LOWER,
299 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
300   g_object_class_install_property(gobject,
301 				  PROP_LOWER,
302 				  param_spec);
303 
304   /**
305    * AgsAutomationEdit:upper:
306    *
307    * The automation edit's upper range.
308    *
309    * Since: 3.0.0
310    */
311   param_spec = g_param_spec_double("upper",
312 				   "upper",
313 				   "The upper of automation edit",
314 				   -G_MAXDOUBLE,
315 				   G_MAXDOUBLE,
316 				   AGS_AUTOMATION_EDIT_DEFAULT_UPPER,
317 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
318   g_object_class_install_property(gobject,
319 				  PROP_UPPER,
320 				  param_spec);
321 
322   /**
323    * AgsAutomationEdit:default-value:
324    *
325    * The automation edit's default value.
326    *
327    * Since: 3.0.0
328    */
329   param_spec = g_param_spec_double("default-value",
330 				   "default value",
331 				   "The default value of automation edit",
332 				   -G_MAXDOUBLE,
333 				   G_MAXDOUBLE,
334 				   AGS_AUTOMATION_EDIT_DEFAULT_VALUE,
335 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
336   g_object_class_install_property(gobject,
337 				  PROP_DEFAULT_VALUE,
338 				  param_spec);
339 
340   /* GtkWidgetClass */
341   widget = (GtkWidgetClass *) automation_edit;
342 
343 //  widget->get_preferred_width = ags_automation_edit_get_preferred_width;
344   widget->get_preferred_height = ags_automation_edit_get_preferred_height;
345 //  widget->size_allocate = ags_automation_edit_size_allocate;
346 //  widget->draw = ags_automation_edit_draw;
347   widget->show = ags_automation_edit_show;
348   widget->show_all = ags_automation_edit_show_all;
349 }
350 
351 void
ags_accessible_automation_edit_class_init(AtkObject * object)352 ags_accessible_automation_edit_class_init(AtkObject *object)
353 {
354   quark_accessible_object = g_quark_from_static_string("ags-accessible-object");
355 }
356 
357 void
ags_accessible_automation_edit_action_interface_init(AtkActionIface * action)358 ags_accessible_automation_edit_action_interface_init(AtkActionIface *action)
359 {
360   action->do_action = ags_accessible_automation_edit_do_action;
361   action->get_n_actions = ags_accessible_automation_edit_get_n_actions;
362   action->get_description = ags_accessible_automation_edit_get_description;
363   action->get_name = ags_accessible_automation_edit_get_name;
364   action->get_keybinding = ags_accessible_automation_edit_get_keybinding;
365   action->set_description = ags_accessible_automation_edit_set_description;
366   action->get_localized_name = ags_accessible_automation_edit_get_localized_name;
367 }
368 
369 void
ags_automation_edit_connectable_interface_init(AgsConnectableInterface * connectable)370 ags_automation_edit_connectable_interface_init(AgsConnectableInterface *connectable)
371 {
372   connectable->is_ready = NULL;
373   connectable->is_connected = NULL;
374   connectable->connect = ags_automation_edit_connect;
375   connectable->disconnect = ags_automation_edit_disconnect;
376 }
377 
378 void
ags_automation_edit_init(AgsAutomationEdit * automation_edit)379 ags_automation_edit_init(AgsAutomationEdit *automation_edit)
380 {
381   GtkAdjustment *adjustment;
382 
383   AgsApplicationContext *application_context;
384 
385   gdouble gui_scale_factor;
386 
387   application_context = ags_application_context_get_instance();
388 
389   g_object_set(automation_edit,
390 	       "can-focus", FALSE,
391 	       "n-columns", 3,
392 	       "n-rows", 4,
393 	       "homogeneous", FALSE,
394 	       NULL);
395 
396   automation_edit->flags = 0;
397   automation_edit->mode = AGS_AUTOMATION_EDIT_NO_EDIT_MODE;
398 
399   automation_edit->button_mask = 0;
400   automation_edit->key_mask = 0;
401 
402   /* scale factor */
403   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
404 
405   automation_edit->note_offset = 0;
406   automation_edit->note_offset_absolute = 0;
407 
408   automation_edit->point_radius = (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_POINT_RADIUS);
409 
410   automation_edit->scan_width = (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_SCAN_WIDTH);
411   automation_edit->scan_height = (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_SCAN_HEIGHT);
412 
413   automation_edit->control_width = (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_WIDTH);
414   automation_edit->control_height = (guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_HEIGHT);
415 
416   automation_edit->step_count = (guint) (AGS_AUTOMATION_EDIT_DEFAULT_STEP_COUNT);
417 
418   automation_edit->cursor_position_x = AGS_AUTOMATION_EDIT_DEFAULT_CURSOR_POSITION_X;
419   automation_edit->cursor_position_y = AGS_AUTOMATION_EDIT_DEFAULT_CURSOR_POSITION_Y;
420 
421   automation_edit->selected_acceleration_border = AGS_AUTOMATION_EDIT_DEFAULT_SELECTED_ACCELERATION_BORDER;
422 
423   automation_edit->selection_x0 = 0;
424   automation_edit->selection_x1 = 0;
425   automation_edit->selection_y0 = 0;
426   automation_edit->selection_y1 = 0;
427 
428   automation_edit->current_acceleration = NULL;
429 
430   automation_edit->ruler = ags_ruler_new();
431   g_object_set(automation_edit->ruler,
432 	       "height-request", (gint) (gui_scale_factor * AGS_RULER_DEFAULT_HEIGHT),
433 	       "font-size",  (guint) (gui_scale_factor * automation_edit->ruler->font_size),
434 	       "step", (guint) (AGS_RULER_DEFAULT_STEP),
435 	       "large-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_LARGE_STEP),
436 	       "small-step", (guint) (gui_scale_factor * AGS_RULER_DEFAULT_SMALL_STEP),
437 	       "no-show-all", TRUE,
438 	       NULL);
439   gtk_table_attach(GTK_TABLE(automation_edit),
440 		   (GtkWidget *) automation_edit->ruler,
441 		   0, 1,
442 		   0, 1,
443 		   GTK_FILL | GTK_EXPAND, GTK_FILL,
444 		   0, 0);
445 
446   automation_edit->channel_type = G_TYPE_NONE;
447 
448   automation_edit->filename = NULL;
449   automation_edit->effect = NULL;
450 
451   automation_edit->control_specifier = NULL;
452   automation_edit->control_name = NULL;
453 
454   automation_edit->lower = AGS_AUTOMATION_EDIT_DEFAULT_LOWER;
455   automation_edit->upper = AGS_AUTOMATION_EDIT_DEFAULT_UPPER;
456 
457   automation_edit->default_value = AGS_AUTOMATION_EDIT_DEFAULT_VALUE;
458 
459   automation_edit->drawing_area = (GtkDrawingArea *) gtk_drawing_area_new();
460   gtk_widget_set_has_window(automation_edit->drawing_area,
461 			    TRUE);
462   gtk_widget_set_events(GTK_WIDGET (automation_edit->drawing_area), GDK_EXPOSURE_MASK
463 			| GDK_LEAVE_NOTIFY_MASK
464 			| GDK_BUTTON_PRESS_MASK
465 			| GDK_BUTTON_RELEASE_MASK
466 			| GDK_POINTER_MOTION_MASK
467 			| GDK_POINTER_MOTION_HINT_MASK
468 			| GDK_CONTROL_MASK
469 			| GDK_KEY_PRESS_MASK
470 			| GDK_KEY_RELEASE_MASK);
471   gtk_widget_set_can_focus((GtkWidget *) automation_edit->drawing_area,
472 			   TRUE);
473 
474   gtk_table_attach(GTK_TABLE(automation_edit),
475 		   (GtkWidget *) automation_edit->drawing_area,
476 		   0, 1,
477 		   1, 2,
478 		   GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND,
479 		   0, 0);
480 
481   /* vscrollbar */
482   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, automation_edit->control_height, 1.0);
483   automation_edit->vscrollbar = (GtkVScrollbar *) gtk_vscrollbar_new(adjustment);
484   g_object_set(automation_edit->vscrollbar,
485 	       "no-show-all", TRUE,
486 	       NULL);
487   gtk_widget_set_size_request((GtkWidget *) automation_edit->vscrollbar,
488 			      -1, (guint) (gui_scale_factor * AGS_SCALE_DEFAULT_SCALE_HEIGHT));
489   gtk_table_attach(GTK_TABLE(automation_edit),
490 		   (GtkWidget *) automation_edit->vscrollbar,
491 		   1, 2,
492 		   1, 2,
493 		   GTK_FILL, GTK_FILL,
494 		   0, 0);
495 
496   /* hscrollbar */
497   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (gdouble) automation_edit->control_width, 1.0);
498   automation_edit->hscrollbar = (GtkHScrollbar *) gtk_hscrollbar_new(adjustment);
499   g_object_set(automation_edit->hscrollbar,
500 	       "no-show-all", TRUE,
501 	       NULL);
502   gtk_widget_set_size_request((GtkWidget *) automation_edit->hscrollbar,
503 			      -1, -1);
504   gtk_table_attach(GTK_TABLE(automation_edit),
505 		   (GtkWidget *) automation_edit->hscrollbar,
506 		   0, 1,
507 		   2, 3,
508 		   GTK_FILL, GTK_FILL,
509 		   0, 0);
510 
511   /* auto-scroll */
512   if(ags_automation_edit_auto_scroll == NULL){
513     ags_automation_edit_auto_scroll = g_hash_table_new_full(g_direct_hash, g_direct_equal,
514 							    NULL,
515 							    NULL);
516   }
517 
518   g_hash_table_insert(ags_automation_edit_auto_scroll,
519 		      automation_edit, ags_automation_edit_auto_scroll_timeout);
520   g_timeout_add(1000 / 30, (GSourceFunc) ags_automation_edit_auto_scroll_timeout, (gpointer) automation_edit);
521 }
522 
523 void
ags_automation_edit_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)524 ags_automation_edit_set_property(GObject *gobject,
525 				 guint prop_id,
526 				 const GValue *value,
527 				 GParamSpec *param_spec)
528 {
529   AgsAutomationEdit *automation_edit;
530 
531   automation_edit = AGS_AUTOMATION_EDIT(gobject);
532 
533   switch(prop_id){
534   case PROP_CHANNEL_TYPE:
535     {
536       automation_edit->channel_type = g_value_get_gtype(value);
537     }
538     break;
539   case PROP_FILENAME:
540     {
541       gchar *filename;
542 
543       filename = g_value_get_string(value);
544 
545       if(automation_edit->filename == filename){
546 	return;
547       }
548 
549       automation_edit->filename = g_strdup(filename);
550     }
551     break;
552   case PROP_EFFECT:
553     {
554       gchar *effect;
555 
556       effect = g_value_get_string(value);
557 
558       if(automation_edit->effect == effect){
559 	return;
560       }
561 
562       automation_edit->effect = g_strdup(effect);
563     }
564     break;
565   case PROP_CONTROL_SPECIFIER:
566     {
567       gchar *control_specifier;
568 
569       control_specifier = g_value_get_string(value);
570 
571       if(automation_edit->control_specifier == control_specifier){
572 	return;
573       }
574 
575       automation_edit->control_specifier = g_strdup(control_specifier);
576     }
577     break;
578   case PROP_CONTROL_NAME:
579     {
580       gchar *control_name;
581 
582       control_name = g_value_get_string(value);
583 
584       if(automation_edit->control_name == control_name){
585 	return;
586       }
587 
588       automation_edit->control_name = g_strdup(control_name);
589     }
590     break;
591   case PROP_LOWER:
592     {
593       automation_edit->lower = g_value_get_double(value);
594 
595       gtk_widget_queue_draw((GtkWidget *) automation_edit);
596     }
597     break;
598   case PROP_UPPER:
599     {
600       automation_edit->upper = g_value_get_double(value);
601 
602       gtk_widget_queue_draw((GtkWidget *) automation_edit);
603     }
604     break;
605   case PROP_DEFAULT_VALUE:
606     {
607       automation_edit->default_value = g_value_get_double(value);
608 
609       gtk_widget_queue_draw((GtkWidget *) automation_edit);
610     }
611     break;
612   default:
613     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
614     break;
615   }
616 }
617 
618 void
ags_automation_edit_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)619 ags_automation_edit_get_property(GObject *gobject,
620 				 guint prop_id,
621 				 GValue *value,
622 				 GParamSpec *param_spec)
623 {
624   AgsAutomationEdit *automation_edit;
625 
626   automation_edit = AGS_AUTOMATION_EDIT(gobject);
627 
628   switch(prop_id){
629   case PROP_CHANNEL_TYPE:
630     {
631       g_value_set_gtype(value, automation_edit->channel_type);
632     }
633     break;
634   case PROP_FILENAME:
635     {
636       g_value_set_string(value, automation_edit->filename);
637     }
638     break;
639   case PROP_EFFECT:
640     {
641       g_value_set_string(value, automation_edit->effect);
642     }
643     break;
644   case PROP_CONTROL_SPECIFIER:
645     {
646       g_value_set_string(value, automation_edit->control_specifier);
647     }
648     break;
649   case PROP_CONTROL_NAME:
650     {
651       g_value_set_string(value, automation_edit->control_name);
652     }
653     break;
654   case PROP_LOWER:
655     {
656       g_value_set_double(value,
657 			 automation_edit->lower);
658     }
659     break;
660   case PROP_UPPER:
661     {
662       g_value_set_double(value,
663 			 automation_edit->upper);
664     }
665     break;
666   case PROP_DEFAULT_VALUE:
667     {
668       g_value_set_double(value,
669 			 automation_edit->default_value);
670     }
671     break;
672   default:
673     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
674     break;
675   }
676 }
677 
678 void
ags_automation_edit_finalize(GObject * gobject)679 ags_automation_edit_finalize(GObject *gobject)
680 {
681   AgsAutomationEdit *automation_edit;
682 
683   automation_edit = AGS_AUTOMATION_EDIT(gobject);
684 
685   /* remove auto scroll */
686   g_hash_table_remove(ags_automation_edit_auto_scroll,
687 		      automation_edit);
688 
689   /* call parent */
690   G_OBJECT_CLASS(ags_automation_edit_parent_class)->finalize(gobject);
691 }
692 
693 void
ags_automation_edit_connect(AgsConnectable * connectable)694 ags_automation_edit_connect(AgsConnectable *connectable)
695 {
696   AgsAutomationEditor *automation_editor;
697   AgsAutomationEdit *automation_edit;
698 
699   automation_edit = AGS_AUTOMATION_EDIT(connectable);
700 
701   if((AGS_AUTOMATION_EDIT_CONNECTED & (automation_edit->flags)) != 0){
702     return;
703   }
704 
705   automation_edit->flags |= AGS_AUTOMATION_EDIT_CONNECTED;
706 
707   /* drawing area */
708   g_signal_connect(G_OBJECT(automation_edit->drawing_area), "draw",
709 		   G_CALLBACK(ags_automation_edit_draw_callback), (gpointer) automation_edit);
710 
711   g_signal_connect_after((GObject *) automation_edit->drawing_area, "configure_event",
712 			 G_CALLBACK(ags_automation_edit_drawing_area_configure_event), (gpointer) automation_edit);
713 
714   g_signal_connect((GObject *) automation_edit->drawing_area, "button_press_event",
715 		   G_CALLBACK(ags_automation_edit_drawing_area_button_press_event), (gpointer) automation_edit);
716 
717   g_signal_connect((GObject *) automation_edit->drawing_area, "button_release_event",
718 		   G_CALLBACK(ags_automation_edit_drawing_area_button_release_event), (gpointer) automation_edit);
719 
720   g_signal_connect((GObject *) automation_edit->drawing_area, "motion_notify_event",
721 		   G_CALLBACK(ags_automation_edit_drawing_area_motion_notify_event), (gpointer) automation_edit);
722 
723   g_signal_connect((GObject *) automation_edit->drawing_area, "key_press_event",
724 		   G_CALLBACK(ags_automation_edit_drawing_area_key_press_event), (gpointer) automation_edit);
725 
726   g_signal_connect((GObject *) automation_edit->drawing_area, "key_release_event",
727 		   G_CALLBACK(ags_automation_edit_drawing_area_key_release_event), (gpointer) automation_edit);
728 
729   /* scrollbars */
730   g_signal_connect_after((GObject *) automation_edit->vscrollbar, "value-changed",
731 			 G_CALLBACK(ags_automation_edit_vscrollbar_value_changed), (gpointer) automation_edit);
732 
733   g_signal_connect_after((GObject *) automation_edit->hscrollbar, "value-changed",
734 			 G_CALLBACK(ags_automation_edit_hscrollbar_value_changed), (gpointer) automation_edit);
735 }
736 
737 void
ags_automation_edit_disconnect(AgsConnectable * connectable)738 ags_automation_edit_disconnect(AgsConnectable *connectable)
739 {
740   AgsAutomationEditor *automation_editor;
741   AgsAutomationEdit *automation_edit;
742 
743   automation_edit = AGS_AUTOMATION_EDIT(connectable);
744 
745   if((AGS_AUTOMATION_EDIT_CONNECTED & (automation_edit->flags)) == 0){
746     return;
747   }
748 
749   automation_edit->flags &= (~AGS_AUTOMATION_EDIT_CONNECTED);
750 
751   /* drawing area */
752   g_object_disconnect((GObject *) automation_edit->drawing_area,
753 		      "any_signal::draw",
754 		      G_CALLBACK(ags_automation_edit_draw_callback),
755 		      (gpointer) automation_edit,
756 		      "any_signal::configure_event",
757 		      G_CALLBACK(ags_automation_edit_drawing_area_configure_event),
758 		      automation_edit,
759 		      "any_signal::button_press_event",
760 		      G_CALLBACK(ags_automation_edit_drawing_area_button_press_event),
761 		      automation_edit,
762 		      "any_signal::button_release_event",
763 		      G_CALLBACK(ags_automation_edit_drawing_area_button_release_event),
764 		      automation_edit,
765 		      "any_signal::motion_notify_event",
766 		      G_CALLBACK(ags_automation_edit_drawing_area_motion_notify_event),
767 		      automation_edit,
768 		      "any_signal::key_press_event",
769 		      G_CALLBACK(ags_automation_edit_drawing_area_key_press_event),
770 		      automation_edit,
771 		      "any_signal::key_release_event",
772 		      G_CALLBACK(ags_automation_edit_drawing_area_key_release_event),
773 		      automation_edit,
774 		      NULL);
775 
776   /* scrollbars */
777   g_object_disconnect((GObject *) automation_edit->vscrollbar,
778 		      "any_signal::value-changed",
779 		      G_CALLBACK(ags_automation_edit_vscrollbar_value_changed),
780 		      (gpointer) automation_edit,
781 		      NULL);
782 
783   g_object_disconnect((GObject *) automation_edit->hscrollbar,
784 		      "any_signal::value-changed",
785 		      G_CALLBACK(ags_automation_edit_hscrollbar_value_changed),
786 		      (gpointer) automation_edit,
787 		      NULL);
788 }
789 
790 AtkObject*
ags_automation_edit_get_accessible(GtkWidget * widget)791 ags_automation_edit_get_accessible(GtkWidget *widget)
792 {
793   AtkObject* accessible;
794 
795   accessible = g_object_get_qdata(G_OBJECT(widget),
796 				  quark_accessible_object);
797 
798   if(!accessible){
799     accessible = g_object_new(ags_accessible_automation_edit_get_type(),
800 			      NULL);
801 
802     g_object_set_qdata(G_OBJECT(widget),
803 		       quark_accessible_object,
804 		       accessible);
805     gtk_accessible_set_widget(GTK_ACCESSIBLE(accessible),
806 			      widget);
807   }
808 
809   return(accessible);
810 }
811 
812 gboolean
ags_accessible_automation_edit_do_action(AtkAction * action,gint i)813 ags_accessible_automation_edit_do_action(AtkAction *action,
814 					 gint i)
815 {
816   AgsAutomationEdit *automation_edit;
817 
818   GdkEventKey *key_press, *key_release;
819   GdkEventKey *modifier_press, *modifier_release;
820   GdkEventKey *second_level_press, *second_level_release;
821 
822   if(!(i >= 0 && i < 13)){
823     return(FALSE);
824   }
825 
826   automation_edit = (AgsAutomationEdit *) gtk_accessible_get_widget(GTK_ACCESSIBLE(action));
827 
828   key_press = (GdkEventKey *) gdk_event_new(GDK_KEY_PRESS);
829   key_release = (GdkEventKey *) gdk_event_new(GDK_KEY_RELEASE);
830 
831   /* create modifier */
832   modifier_press = (GdkEventKey *) gdk_event_new(GDK_KEY_PRESS);
833   modifier_release = (GdkEventKey *) gdk_event_new(GDK_KEY_RELEASE);
834 
835   modifier_press->keyval =
836     modifier_release->keyval = GDK_KEY_Control_R;
837 
838   /* create second level */
839   second_level_press = (GdkEventKey *) gdk_event_new(GDK_KEY_PRESS);
840   second_level_release = (GdkEventKey *) gdk_event_new(GDK_KEY_RELEASE);
841 
842   second_level_press->keyval =
843     second_level_release->keyval = GDK_KEY_Shift_R;
844 
845   switch(i){
846   case 0:
847     {
848       key_press->keyval =
849 	key_release->keyval = GDK_KEY_Left;
850 
851       /* send event */
852       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
853 		       (GdkEvent *) key_press);
854       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
855 		       (GdkEvent *) key_release);
856     }
857     break;
858   case 1:
859     {
860       key_press->keyval =
861 	key_release->keyval = GDK_KEY_Right;
862 
863       /* send event */
864       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
865 		       (GdkEvent *) key_press);
866       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
867 		       (GdkEvent *) key_release);
868     }
869     break;
870   case 2:
871     {
872       key_press->keyval =
873 	key_release->keyval = GDK_KEY_Up;
874 
875       /* send event */
876       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
877 		       (GdkEvent *) key_press);
878       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
879 		       (GdkEvent *) key_release);
880     }
881     break;
882   case 3:
883     {
884       key_press->keyval =
885 	key_release->keyval = GDK_KEY_Down;
886 
887       /* send event */
888       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
889 		       (GdkEvent *) key_press);
890       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
891 		       (GdkEvent *) key_release);
892     }
893     break;
894   case 4:
895     {
896       key_press->keyval =
897 	key_release->keyval = GDK_KEY_Left;
898 
899       /* send event */
900       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
901 		       (GdkEvent *) second_level_press);
902       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
903 		       (GdkEvent *) key_press);
904       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
905 		       (GdkEvent *) key_release);
906       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
907 		       (GdkEvent *) second_level_release);
908     }
909     break;
910   case 5:
911     {
912       key_press->keyval =
913 	key_release->keyval = GDK_KEY_Right;
914 
915       /* send event */
916       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
917 		       (GdkEvent *) second_level_press);
918       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
919 		       (GdkEvent *) key_press);
920       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
921 		       (GdkEvent *) key_release);
922       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
923 		       (GdkEvent *) second_level_release);
924     }
925     break;
926   case 6:
927     {
928       key_press->keyval =
929 	key_release->keyval = GDK_KEY_Up;
930 
931       /* send event */
932       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
933 		       (GdkEvent *) second_level_press);
934       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
935 		       (GdkEvent *) key_press);
936       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
937 		       (GdkEvent *) key_release);
938       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
939 		       (GdkEvent *) second_level_release);
940     }
941     break;
942   case 7:
943     {
944       key_press->keyval =
945 	key_release->keyval = GDK_KEY_Down;
946 
947       /* send event */
948       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
949 		       (GdkEvent *) second_level_press);
950       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
951 		       (GdkEvent *) key_press);
952       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
953 		       (GdkEvent *) key_release);
954       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
955 		       (GdkEvent *) second_level_release);
956     }
957     break;
958   case 8:
959     {
960       key_press->keyval =
961 	key_release->keyval = GDK_KEY_space;
962 
963       /* send event */
964       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
965 		       (GdkEvent *) key_press);
966       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
967 		       (GdkEvent *) key_release);
968     }
969     break;
970   case 9:
971     {
972       key_press->keyval =
973 	key_release->keyval = GDK_KEY_Delete;
974 
975       /* send event */
976       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
977 		       (GdkEvent *) key_press);
978       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
979 		       (GdkEvent *) key_release);
980     }
981     break;
982   case 10:
983     {
984       key_press->keyval =
985 	key_release->keyval = GDK_KEY_c;
986 
987       /* send event */
988       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
989 		       (GdkEvent *) modifier_press);
990       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
991 		       (GdkEvent *) key_press);
992       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
993 		       (GdkEvent *) key_release);
994       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
995 		       (GdkEvent *) modifier_release);
996     }
997     break;
998   case 11:
999     {
1000       key_press->keyval =
1001 	key_release->keyval = GDK_KEY_x;
1002 
1003       /* send event */
1004       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
1005 		       (GdkEvent *) modifier_press);
1006       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
1007 		       (GdkEvent *) key_press);
1008       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
1009 		       (GdkEvent *) key_release);
1010       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
1011 		       (GdkEvent *) modifier_release);
1012     }
1013     break;
1014   case 12:
1015     {
1016       key_press->keyval =
1017 	key_release->keyval = GDK_KEY_v;
1018 
1019       /* send event */
1020       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
1021 		       (GdkEvent *) modifier_press);
1022       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
1023 		       (GdkEvent *) key_press);
1024       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
1025 		       (GdkEvent *) key_release);
1026       gtk_widget_event((GtkWidget *) automation_edit->drawing_area,
1027 		       (GdkEvent *) modifier_release);
1028     }
1029     break;
1030   }
1031 
1032   return(TRUE);
1033 }
1034 
1035 gint
ags_accessible_automation_edit_get_n_actions(AtkAction * action)1036 ags_accessible_automation_edit_get_n_actions(AtkAction *action)
1037 {
1038   return(13);
1039 }
1040 
1041 const gchar*
ags_accessible_automation_edit_get_description(AtkAction * action,gint i)1042 ags_accessible_automation_edit_get_description(AtkAction *action,
1043 					       gint i)
1044 {
1045   static const gchar *actions[] = {
1046     "move cursor left",
1047     "move cursor right",
1048     "move cursor up",
1049     "move cursor down",
1050     "move cursor relative up",
1051     "move cursor relative down",
1052     "move cursor small left",
1053     "move cursor small right",
1054     "add acceleration",
1055     "remove acceleration",
1056     "copy automation to clipboard",
1057     "cut automation to clipboard",
1058     "paste automation from clipboard",
1059   };
1060 
1061   if(i >= 0 && i < 13){
1062     return(actions[i]);
1063   }else{
1064     return(NULL);
1065   }
1066 }
1067 
1068 const gchar*
ags_accessible_automation_edit_get_name(AtkAction * action,gint i)1069 ags_accessible_automation_edit_get_name(AtkAction *action,
1070 					gint i)
1071 {
1072   static const gchar *actions[] = {
1073     "left",
1074     "right",
1075     "up",
1076     "down",
1077     "small-left",
1078     "small-right",
1079     "relative-up",
1080     "relative-down",
1081     "add",
1082     "remove",
1083     "copy",
1084     "cut",
1085     "paste",
1086   };
1087 
1088   if(i >= 0 && i < 13){
1089     return(actions[i]);
1090   }else{
1091     return(NULL);
1092   }
1093 }
1094 
1095 const gchar*
ags_accessible_automation_edit_get_keybinding(AtkAction * action,gint i)1096 ags_accessible_automation_edit_get_keybinding(AtkAction *action,
1097 					      gint i)
1098 {
1099   static const gchar *actions[] = {
1100     "left",
1101     "right",
1102     "up",
1103     "down",
1104     "Shft+Left",
1105     "Shft+Right",
1106     "Shft+up",
1107     "Schft+down",
1108     "space",
1109     "Del"
1110     "Ctrl+c"
1111     "Ctrl+x",
1112     "Ctrl+v",
1113   };
1114 
1115   if(i >= 0 && i < 13){
1116     return(actions[i]);
1117   }else{
1118     return(NULL);
1119   }
1120 }
1121 
1122 gboolean
ags_accessible_automation_edit_set_description(AtkAction * action,gint i)1123 ags_accessible_automation_edit_set_description(AtkAction *action,
1124 					       gint i)
1125 {
1126   //TODO:JK: implement me
1127 
1128   return(FALSE);
1129 }
1130 
1131 gchar*
ags_accessible_automation_edit_get_localized_name(AtkAction * action,gint i)1132 ags_accessible_automation_edit_get_localized_name(AtkAction *action,
1133 						  gint i)
1134 {
1135   //TODO:JK: implement me
1136 
1137   return(NULL);
1138 }
1139 
1140 void
ags_automation_edit_get_preferred_width(GtkWidget * widget,gint * minimal_width,gint * natural_width)1141 ags_automation_edit_get_preferred_width(GtkWidget *widget,
1142 					gint *minimal_width,
1143 					gint *natural_width)
1144 {
1145   minimal_width =
1146     natural_width = NULL;
1147 }
1148 
1149 void
ags_automation_edit_get_preferred_height(GtkWidget * widget,gint * minimal_height,gint * natural_height)1150 ags_automation_edit_get_preferred_height(GtkWidget *widget,
1151 					 gint *minimal_height,
1152 					 gint *natural_height)
1153 {
1154   AgsApplicationContext *application_context;
1155 
1156   gdouble gui_scale_factor;
1157 
1158   application_context = ags_application_context_get_instance();
1159 
1160   /* scale factor */
1161   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
1162 
1163   minimal_height[0] =
1164     natural_height[0] = (gint) (gui_scale_factor * AGS_SCALE_DEFAULT_SCALE_HEIGHT);
1165 }
1166 
1167 void
ags_automation_edit_size_allocate(GtkWidget * widget,GtkAllocation * allocation)1168 ags_automation_edit_size_allocate(GtkWidget *widget,
1169 				  GtkAllocation *allocation)
1170 {
1171   AgsAutomationEdit *automation_edit;
1172 
1173   GtkAllocation child_allocation;
1174 
1175   GdkWindow *window;
1176 
1177   AgsApplicationContext *application_context;
1178 
1179   gdouble gui_scale_factor;
1180 
1181   automation_edit = AGS_AUTOMATION_EDIT(widget);
1182 
1183   application_context = ags_application_context_get_instance();
1184 
1185   /* scale factor */
1186   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
1187 
1188 //  widget->allocation = *allocation;
1189 
1190 //  widget->allocation.height = (gint) (gui_scale_factor * AGS_SCALE_DEFAULT_SCALE_HEIGHT);
1191   allocation->height = (gint) (gui_scale_factor * AGS_SCALE_DEFAULT_SCALE_HEIGHT);
1192 
1193   child_allocation.x = allocation->x;
1194   child_allocation.y = allocation->y;
1195 
1196   child_allocation.width = allocation->width;
1197   child_allocation.height = (gint) (gui_scale_factor * AGS_SCALE_DEFAULT_SCALE_HEIGHT);
1198 
1199   gtk_widget_size_allocate((GtkWidget *) automation_edit->drawing_area,
1200   			   &child_allocation);
1201 
1202   window = gtk_widget_get_window((GtkWidget *) automation_edit->drawing_area);
1203   gdk_window_move(window,
1204   		  allocation->x, allocation->y);
1205 }
1206 
1207 void
ags_automation_edit_show(GtkWidget * widget)1208 ags_automation_edit_show(GtkWidget *widget)
1209 {
1210   AgsAutomationEdit *automation_edit;
1211 
1212   automation_edit = AGS_AUTOMATION_EDIT(widget);
1213 
1214   /* call parent */
1215   GTK_WIDGET_CLASS(ags_automation_edit_parent_class)->show(widget);
1216 
1217   gtk_widget_show((GtkWidget *) automation_edit->drawing_area);
1218 
1219   if((AGS_AUTOMATION_EDIT_SHOW_RULER & (automation_edit->flags)) != 0){
1220     gtk_widget_show((GtkWidget *) automation_edit->ruler);
1221   }
1222 
1223   if((AGS_AUTOMATION_EDIT_SHOW_VSCROLLBAR & (automation_edit->flags)) != 0){
1224     gtk_widget_show((GtkWidget *) automation_edit->vscrollbar);
1225   }
1226 
1227   if((AGS_AUTOMATION_EDIT_SHOW_HSCROLLBAR & (automation_edit->flags)) != 0){
1228     gtk_widget_show((GtkWidget *) automation_edit->hscrollbar);
1229   }
1230 }
1231 
1232 void
ags_automation_edit_show_all(GtkWidget * widget)1233 ags_automation_edit_show_all(GtkWidget *widget)
1234 {
1235   AgsAutomationEdit *automation_edit;
1236 
1237   automation_edit = AGS_AUTOMATION_EDIT(widget);
1238 
1239   /* call parent */
1240   GTK_WIDGET_CLASS(ags_automation_edit_parent_class)->show_all(widget);
1241 
1242   gtk_widget_show_all((GtkWidget *) automation_edit->drawing_area);
1243 
1244   if((AGS_AUTOMATION_EDIT_SHOW_RULER & (automation_edit->flags)) != 0){
1245     gtk_widget_show((GtkWidget *) automation_edit->ruler);
1246   }
1247 
1248   if((AGS_AUTOMATION_EDIT_SHOW_VSCROLLBAR & (automation_edit->flags)) != 0){
1249     gtk_widget_show((GtkWidget *) automation_edit->vscrollbar);
1250   }
1251 
1252   if((AGS_AUTOMATION_EDIT_SHOW_HSCROLLBAR & (automation_edit->flags)) != 0){
1253     gtk_widget_show((GtkWidget *) automation_edit->hscrollbar);
1254   }
1255 }
1256 
1257 gboolean
ags_automation_edit_auto_scroll_timeout(GtkWidget * widget)1258 ags_automation_edit_auto_scroll_timeout(GtkWidget *widget)
1259 {
1260   if(g_hash_table_lookup(ags_automation_edit_auto_scroll,
1261 			 widget) != NULL){
1262     AgsAutomationEditor *automation_editor;
1263     AgsAutomationEdit *automation_edit;
1264 
1265     GtkAdjustment *hscrollbar_adjustment;
1266 
1267     GObject *output_soundcard;
1268 
1269     double x;
1270 
1271     automation_edit = AGS_AUTOMATION_EDIT(widget);
1272 
1273     if((AGS_AUTOMATION_EDIT_AUTO_SCROLL & (automation_edit->flags)) == 0){
1274       return(TRUE);
1275     }
1276 
1277     automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
1278 									AGS_TYPE_AUTOMATION_EDITOR);
1279 
1280     if(automation_editor->selected_machine == NULL){
1281       return(TRUE);
1282     }
1283 
1284     /* reset offset */
1285     g_object_get(automation_editor->selected_machine->audio,
1286 		 "output-soundcard", &output_soundcard,
1287 		 NULL);
1288 
1289     automation_edit->note_offset = ags_soundcard_get_note_offset(AGS_SOUNDCARD(output_soundcard));
1290     automation_edit->note_offset_absolute = ags_soundcard_get_note_offset_absolute(AGS_SOUNDCARD(output_soundcard));
1291 
1292     /* reset scrollbar */
1293     hscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_edit->hscrollbar));
1294     x = ((automation_edit->note_offset * automation_edit->control_width) / (AGS_AUTOMATION_EDITOR_MAX_CONTROLS * automation_edit->control_width)) * gtk_adjustment_get_upper(hscrollbar_adjustment);
1295 
1296     gtk_range_set_value(GTK_RANGE(automation_edit->hscrollbar),
1297 			x);
1298 
1299     g_object_unref(output_soundcard);
1300 
1301     return(TRUE);
1302   }else{
1303     return(FALSE);
1304   }
1305 }
1306 
1307 void
ags_automation_edit_reset_vscrollbar(AgsAutomationEdit * automation_edit)1308 ags_automation_edit_reset_vscrollbar(AgsAutomationEdit *automation_edit)
1309 {
1310   AgsAutomationEditor *automation_editor;
1311 
1312   GtkAdjustment *adjustment;
1313 
1314   GtkAllocation allocation;
1315 
1316   double varea_height;
1317   gdouble upper, old_upper;
1318 
1319   if(!AGS_IS_AUTOMATION_EDIT(automation_edit)){
1320     return;
1321   }
1322 
1323   automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
1324 								      AGS_TYPE_AUTOMATION_EDITOR);
1325 
1326   if(automation_editor->selected_machine == NULL){
1327     return;
1328   }
1329 
1330   /* adjustment and allocation */
1331   adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_edit->vscrollbar));
1332 
1333   gtk_widget_get_allocation(GTK_WIDGET(automation_edit->drawing_area),
1334 			    &allocation);
1335 
1336   /* upper */
1337   old_upper = gtk_adjustment_get_upper(adjustment);
1338 
1339   varea_height = (automation_edit->step_count * automation_edit->control_height);
1340   upper = varea_height - allocation.height;
1341 
1342   if(upper < 0.0){
1343     upper = 0.0;
1344   }
1345 
1346   gtk_adjustment_set_upper(adjustment,
1347 			   upper);
1348 
1349   /* reset value */
1350   if(old_upper != 0.0){
1351     gtk_adjustment_set_value(adjustment,
1352 			     gtk_adjustment_get_value(adjustment) / old_upper * upper);
1353   }
1354 }
1355 
1356 void
ags_automation_edit_reset_hscrollbar(AgsAutomationEdit * automation_edit)1357 ags_automation_edit_reset_hscrollbar(AgsAutomationEdit *automation_edit)
1358 {
1359   AgsAutomationEditor *automation_editor;
1360   AgsAutomationToolbar *automation_toolbar;
1361 
1362   GtkAdjustment *adjustment;
1363 
1364   AgsApplicationContext *application_context;
1365 
1366   GtkAllocation allocation;
1367 
1368   gdouble gui_scale_factor;
1369   double zoom_factor, zoom;
1370   double zoom_correction;
1371   guint map_width;
1372   gdouble upper, old_upper;
1373 
1374   if(!AGS_IS_AUTOMATION_EDIT(automation_edit)){
1375     return;
1376   }
1377 
1378   automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
1379 								      AGS_TYPE_AUTOMATION_EDITOR);
1380 
1381   if(automation_editor->selected_machine == NULL){
1382     return;
1383   }
1384 
1385   automation_toolbar = automation_editor->automation_toolbar;
1386 
1387   application_context = ags_application_context_get_instance();
1388 
1389   /* scale factor */
1390   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
1391 
1392   /* adjustment and allocation */
1393   adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_edit->hscrollbar));
1394 
1395   gtk_widget_get_allocation(GTK_WIDGET(automation_edit->drawing_area),
1396 			    &allocation);
1397 
1398   /* zoom */
1399   zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom));
1400   zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom) - 2.0);
1401 
1402   /* upper */
1403   old_upper = gtk_adjustment_get_upper(adjustment);
1404 
1405   zoom_correction = 1.0 / 16;
1406 
1407 //  map_width = ((double) AGS_AUTOMATION_EDITOR_MAX_CONTROLS * zoom * zoom_correction);
1408   map_width = ((64.0) * (16.0 * 16.0 * 1200.0) * zoom * zoom_correction);
1409   upper = map_width - allocation.width;
1410 
1411   if(upper < 0.0){
1412     upper = 0.0;
1413   }
1414 
1415   gtk_adjustment_set_upper(adjustment,
1416 			   upper);
1417 
1418   /* ruler */
1419   automation_edit->ruler->factor = zoom_factor;
1420   automation_edit->ruler->precision = zoom;
1421   automation_edit->ruler->scale_precision = 1.0 / zoom;
1422 
1423   gtk_adjustment_set_upper(automation_edit->ruler->adjustment,
1424 			   upper);
1425 
1426   /* reset value */
1427   if(old_upper != 0.0){
1428 #if 0
1429     gtk_adjustment_set_value(adjustment,
1430 			     gtk_adjustment_get_value(adjustment) / old_upper * upper);
1431 #endif
1432   }
1433 }
1434 
1435 void
ags_automation_edit_draw_segment(AgsAutomationEdit * automation_edit,cairo_t * cr)1436 ags_automation_edit_draw_segment(AgsAutomationEdit *automation_edit, cairo_t *cr)
1437 {
1438   AgsAutomationEditor *automation_editor;
1439   AgsAutomationToolbar *automation_toolbar;
1440 
1441   GtkStyleContext *automation_edit_style_context;
1442 
1443   GtkAdjustment *hscrollbar_adjustment;
1444 
1445   AgsApplicationContext *application_context;
1446 
1447   GtkAllocation allocation;
1448 
1449   GdkRGBA *fg_color;
1450   GdkRGBA *bg_color;
1451   GdkRGBA *border_color;
1452 
1453   gdouble gui_scale_factor;
1454   gdouble x_offset;
1455   gdouble translated_ground;
1456   double tact;
1457   gdouble y;
1458   gdouble map_height;
1459   gdouble width, height;
1460   guint control_width;
1461   guint i, j;
1462   guint j_set;
1463 
1464   GValue value = {0,};
1465 
1466   const static double quarter_dashes = {
1467     0.25,
1468   };
1469 
1470   const static double segment_dashes = {
1471     0.5,
1472   };
1473 
1474   if(!AGS_IS_AUTOMATION_EDIT(automation_edit)){
1475     return;
1476   }
1477 
1478   application_context = ags_application_context_get_instance();
1479 
1480   automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
1481 								      AGS_TYPE_AUTOMATION_EDITOR);
1482 
1483   if(automation_editor->selected_machine == NULL){
1484     return;
1485   }
1486 
1487   automation_toolbar = automation_editor->automation_toolbar;
1488 
1489   gtk_widget_get_allocation(GTK_WIDGET(automation_edit->drawing_area),
1490 			    &allocation);
1491 
1492   /* scale factor */
1493   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
1494 
1495   /* dimension and offset */
1496   width = (gdouble) allocation.width;
1497   height = (gdouble) allocation.height;
1498 
1499   hscrollbar_adjustment = gtk_range_get_adjustment(GTK_RANGE(automation_edit->hscrollbar));
1500 
1501   x_offset = gtk_adjustment_get_value(hscrollbar_adjustment);
1502 
1503   y = 0.0;
1504 
1505   /* style context */
1506   automation_edit_style_context = gtk_widget_get_style_context(GTK_WIDGET(automation_edit->drawing_area));
1507 
1508   gtk_style_context_get_property(automation_edit_style_context,
1509 				 "color",
1510 				 GTK_STATE_FLAG_NORMAL,
1511 				 &value);
1512 
1513   fg_color = g_value_dup_boxed(&value);
1514   g_value_unset(&value);
1515 
1516   gtk_style_context_get_property(automation_edit_style_context,
1517 				 "background-color",
1518 				 GTK_STATE_FLAG_NORMAL,
1519 				 &value);
1520 
1521   bg_color = g_value_dup_boxed(&value);
1522   g_value_unset(&value);
1523 
1524   gtk_style_context_get_property(automation_edit_style_context,
1525 				 "border-color",
1526 				 GTK_STATE_FLAG_NORMAL,
1527 				 &value);
1528 
1529   border_color = g_value_dup_boxed(&value);
1530   g_value_unset(&value);
1531 
1532   /* push group */
1533   cairo_push_group(cr);
1534 
1535   /* background */
1536   cairo_set_source_rgba(cr,
1537 			bg_color->red,
1538 			bg_color->green,
1539 			bg_color->blue,
1540 			bg_color->alpha);
1541 
1542   cairo_rectangle(cr, 0.0, y, width, height);
1543   cairo_fill(cr);
1544 
1545   /* border */
1546   cairo_set_source_rgba(cr,
1547 			border_color->red,
1548 			border_color->green,
1549 			border_color->blue,
1550 			border_color->alpha);
1551 
1552   cairo_set_line_width(cr, 1.0);
1553   cairo_rectangle(cr, 0.0, y, width, height);
1554   cairo_stroke(cr);
1555 
1556   cairo_set_line_width(cr, 1.0);
1557 
1558   tact = exp2((double) gtk_combo_box_get_active(automation_toolbar->zoom) - 2.0);
1559 
1560   y = (gdouble) 0.0;
1561 
1562   map_height = (gdouble) height;
1563 
1564   control_width = (gint) (gui_scale_factor * (gdouble) AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_WIDTH) * (tact / (gui_scale_factor * tact));
1565   i = control_width - (guint) x_offset % control_width;
1566 
1567   cairo_set_source_rgba(cr,
1568 			fg_color->red,
1569 			fg_color->blue,
1570 			fg_color->green,
1571 			fg_color->alpha);
1572 
1573   if(i < width &&
1574      tact > 1.0 ){
1575     j_set = ((guint) x_offset / control_width + 1) % ((guint) tact);
1576 
1577     cairo_set_dash(cr,
1578 		   &segment_dashes,
1579 		   1,
1580 		   0.0);
1581 
1582     if(j_set != 0){
1583       j = j_set;
1584       goto ags_automation_edit_draw_segment0;
1585     }
1586   }
1587 
1588   for(; i < width; ){
1589     cairo_set_dash(cr,
1590 		   NULL,
1591 		   0,
1592 		   0.0);
1593 
1594     cairo_move_to(cr, (double) i, y);
1595     cairo_line_to(cr, (double) i, y + height);
1596     cairo_stroke(cr);
1597 
1598     i += control_width;
1599 
1600     cairo_set_dash(cr,
1601 		   &segment_dashes,
1602 		   1,
1603 		   0.0);
1604 
1605     for(j = 1; i < width && j < tact; j++){
1606     ags_automation_edit_draw_segment0:
1607       cairo_move_to(cr, (double) i, y);
1608       cairo_line_to(cr, (double) i, y + height);
1609       cairo_stroke(cr);
1610 
1611       i += control_width;
1612     }
1613   }
1614 
1615   cairo_set_source_rgba(cr,
1616 			fg_color->red,
1617 			fg_color->green,
1618 			fg_color->blue,
1619 			fg_color->alpha);
1620 
1621   /* middle */
1622   if(map_height * 0.5 < height){
1623     cairo_move_to(cr,
1624 		  0.0, y + map_height * 0.5);
1625     cairo_line_to(cr,
1626 		  width, y + map_height * 0.5);
1627     cairo_stroke(cr);
1628   }
1629 
1630   /* set dash */
1631   cairo_set_dash(cr,
1632 		 &quarter_dashes,
1633 		 1,
1634 		 0.0);
1635 
1636   /* lower quarter */
1637   if(map_height * 0.25 < height){
1638     cairo_move_to(cr,
1639 		  0.0, y + map_height * 0.25);
1640     cairo_line_to(cr,
1641 		  width, y + map_height * 0.25);
1642     cairo_stroke(cr);
1643   }
1644 
1645   /* upper quarter */
1646   if(map_height * 0.75 < height){
1647     cairo_move_to(cr,
1648 		  0.0, y + map_height * 0.75);
1649     cairo_line_to(cr,
1650 		  width, y + map_height * 0.75);
1651     cairo_stroke(cr);
1652   }
1653 
1654   /* complete */
1655   cairo_pop_group_to_source(cr);
1656   cairo_paint(cr);
1657 
1658 //  cairo_surface_mark_dirty(cairo_get_target(cr));
1659 
1660   g_boxed_free(GDK_TYPE_RGBA, fg_color);
1661   g_boxed_free(GDK_TYPE_RGBA, bg_color);
1662   g_boxed_free(GDK_TYPE_RGBA, border_color);
1663 }
1664 
1665 void
ags_automation_edit_draw_position(AgsAutomationEdit * automation_edit,cairo_t * cr)1666 ags_automation_edit_draw_position(AgsAutomationEdit *automation_edit, cairo_t *cr)
1667 {
1668   AgsAutomationEditor *automation_editor;
1669   AgsAutomationToolbar *automation_toolbar;
1670 
1671   GtkStyleContext *automation_edit_style_context;
1672 
1673   AgsApplicationContext *application_context;
1674 
1675   GdkRGBA *fg_color_active;
1676 
1677   gdouble gui_scale_factor;
1678   gdouble tact;
1679   guint control_width;
1680   double position;
1681   double x, y;
1682   double width, height;
1683   gboolean height_fits;
1684 
1685   GValue value = {0,};
1686 
1687   if(!AGS_IS_AUTOMATION_EDIT(automation_edit)){
1688     return;
1689   }
1690 
1691   application_context = ags_application_context_get_instance();
1692 
1693   automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
1694 								      AGS_TYPE_AUTOMATION_EDITOR);
1695 
1696   if(automation_editor->selected_machine == NULL){
1697     return;
1698   }
1699 
1700   automation_toolbar = automation_editor->automation_toolbar;
1701 
1702   /* scale factor */
1703   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
1704 
1705   /* style context */
1706   automation_edit_style_context = gtk_widget_get_style_context(GTK_WIDGET(automation_edit->drawing_area));
1707 
1708   gtk_style_context_get_property(automation_edit_style_context,
1709 				 "color",
1710 				 GTK_STATE_FLAG_ACTIVE,
1711 				 &value);
1712 
1713   fg_color_active = g_value_dup_boxed(&value);
1714   g_value_unset(&value);
1715 
1716   tact = exp2((double) gtk_combo_box_get_active(automation_toolbar->zoom) - 2.0);
1717 
1718   /* get offset and dimensions */
1719   control_width = (gint) (gui_scale_factor * (gdouble) AGS_AUTOMATION_EDIT_DEFAULT_CONTROL_WIDTH) * (tact / (gui_scale_factor * tact));
1720 
1721   position = ((double) automation_edit->note_offset) * ((double) control_width);
1722 
1723   y = 0.0;
1724   x = (position) - (gtk_range_get_value(GTK_RANGE(automation_edit->hscrollbar)));
1725 
1726   width = (double) ((guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_FADER_WIDTH));
1727   height = automation_edit->step_count * automation_edit->control_height;
1728 
1729   /* push group */
1730   cairo_push_group(cr);
1731 
1732   /* draw fader */
1733   cairo_set_source_rgba(cr,
1734 			fg_color_active->red,
1735 			fg_color_active->blue,
1736 			fg_color_active->green,
1737 			fg_color_active->alpha);
1738 
1739   cairo_rectangle(cr,
1740 		  (double) x, (double) y,
1741 		  (double) width, (double) height);
1742   cairo_fill(cr);
1743 
1744   /* complete */
1745   cairo_pop_group_to_source(cr);
1746   cairo_paint(cr);
1747 
1748 //cairo_surface_mark_dirty(cairo_get_target(cr));
1749 
1750   g_boxed_free(GDK_TYPE_RGBA, fg_color_active);
1751 }
1752 
1753 void
ags_automation_edit_draw_cursor(AgsAutomationEdit * automation_edit,cairo_t * cr)1754 ags_automation_edit_draw_cursor(AgsAutomationEdit *automation_edit, cairo_t *cr)
1755 {
1756   AgsAutomationEditor *automation_editor;
1757   AgsAutomationToolbar *automation_toolbar;
1758 
1759   GtkStyleContext *automation_edit_style_context;
1760 
1761   AgsApplicationContext *application_context;
1762 
1763   GtkAllocation allocation;
1764 
1765   GdkRGBA *fg_color_focused;
1766 
1767   gdouble gui_scale_factor;
1768   double zoom_factor;
1769   gdouble val, step;
1770   gdouble upper, lower, step_count;
1771   gdouble c_range;
1772   double x, y;
1773   double width, height;
1774 
1775   GValue value = {0,};
1776 
1777   if(!AGS_IS_AUTOMATION_EDIT(automation_edit)){
1778     return;
1779   }
1780 
1781   application_context = ags_application_context_get_instance();
1782 
1783   automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
1784 								      AGS_TYPE_AUTOMATION_EDITOR);
1785 
1786   if(automation_editor->selected_machine == NULL){
1787     return;
1788   }
1789 
1790   automation_toolbar = automation_editor->automation_toolbar;
1791 
1792   /* scale factor */
1793   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
1794 
1795   /* style context */
1796   automation_edit_style_context = gtk_widget_get_style_context(GTK_WIDGET(automation_edit->drawing_area));
1797 
1798   gtk_style_context_get_property(automation_edit_style_context,
1799 				 "color",
1800 				 GTK_STATE_FLAG_FOCUSED,
1801 				 &value);
1802 
1803   fg_color_focused = g_value_dup_boxed(&value);
1804   g_value_unset(&value);
1805 
1806   gtk_widget_get_allocation(GTK_WIDGET(automation_edit->drawing_area),
1807 			    &allocation);
1808 
1809   if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
1810     c_range = (gdouble) ((guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_HEIGHT));
1811   }else{
1812     c_range = automation_edit->upper - automation_edit->lower;
1813   }
1814 
1815   /* zoom */
1816   zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom));
1817 
1818   /* get offset */
1819   x = ((double) automation_edit->cursor_position_x) - (gtk_range_get_value(GTK_RANGE(automation_edit->hscrollbar)) * zoom_factor);
1820 
1821   if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
1822     lower = automation_edit->lower;
1823     upper = automation_edit->upper;
1824 
1825     step_count = ((guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_HEIGHT)) + 1.0;
1826 
1827     val = automation_edit->cursor_position_y;
1828 
1829     y = (step_count - 1) * log(val / lower) / log(upper / lower);
1830   }else{
1831     y = allocation.height - ((((double) automation_edit->cursor_position_y / c_range) * allocation.height) - gtk_range_get_value(GTK_RANGE(automation_edit->vscrollbar)));
1832   }
1833 
1834   width = (double) AGS_AUTOMATION_EDIT_CURSOR_WIDTH;
1835   height = (double) AGS_AUTOMATION_EDIT_CURSOR_HEIGHT;
1836 
1837   /* apply zoom */
1838   x /= zoom_factor;
1839 
1840   /* clip */
1841   if(x < 0.0){
1842     width += x;
1843 
1844     x = 0.0;
1845   }else if(x > allocation.width){
1846     g_boxed_free(GDK_TYPE_RGBA, fg_color_focused);
1847 
1848     return;
1849   }
1850 
1851   if(x + width > allocation.width){
1852     width = ((double) allocation.width) - x;
1853   }
1854 
1855   if(y < 0.0){
1856     height += y;
1857 
1858     y = 0.0;
1859   }else if(y > allocation.height){
1860     g_boxed_free(GDK_TYPE_RGBA, fg_color_focused);
1861 
1862     return;
1863   }
1864 
1865   if(y + height > allocation.height){
1866     height = ((double) allocation.height) - y;
1867   }
1868 
1869   /* push group */
1870   cairo_push_group(cr);
1871 
1872   /* draw cursor */
1873   cairo_set_source_rgba(cr,
1874 			fg_color_focused->red,
1875 			fg_color_focused->blue,
1876 			fg_color_focused->green,
1877 			fg_color_focused->alpha);
1878 
1879   cairo_move_to(cr,
1880 		x, y);
1881   cairo_line_to(cr,
1882 		x + width, y);
1883   cairo_stroke(cr);
1884 
1885   cairo_move_to(cr,
1886 		x, y);
1887   cairo_line_to(cr,
1888 		x, y + height);
1889   cairo_stroke(cr);
1890 
1891   /* complete */
1892   cairo_pop_group_to_source(cr);
1893   cairo_paint(cr);
1894 
1895   //cairo_surface_mark_dirty(cairo_get_target(cr));
1896 
1897   g_boxed_free(GDK_TYPE_RGBA, fg_color_focused);
1898 }
1899 
1900 void
ags_automation_edit_draw_selection(AgsAutomationEdit * automation_edit,cairo_t * cr)1901 ags_automation_edit_draw_selection(AgsAutomationEdit *automation_edit, cairo_t *cr)
1902 {
1903   GtkStyleContext *automation_edit_style_context;
1904 
1905   AgsApplicationContext *application_context;
1906 
1907   GtkAllocation allocation;
1908 
1909   GdkRGBA *fg_color_prelight;
1910 
1911   double x, y;
1912   double width, height;
1913 
1914   GValue value = {0,};
1915 
1916   if(!AGS_IS_AUTOMATION_EDIT(automation_edit)){
1917     return;
1918   }
1919 
1920   application_context = ags_application_context_get_instance();
1921 
1922   /* style context */
1923   automation_edit_style_context = gtk_widget_get_style_context(GTK_WIDGET(automation_edit->drawing_area));
1924 
1925   gtk_style_context_get_property(automation_edit_style_context,
1926 				 "color",
1927 				 GTK_STATE_FLAG_PRELIGHT,
1928 				 &value);
1929 
1930   fg_color_prelight = g_value_dup_boxed(&value);
1931   g_value_unset(&value);
1932 
1933   gtk_widget_get_allocation(GTK_WIDGET(automation_edit->drawing_area),
1934 			    &allocation);
1935 
1936   /* get offset and dimensions */
1937   if(automation_edit->selection_x0 < automation_edit->selection_x1){
1938     x = ((double) automation_edit->selection_x0) - gtk_range_get_value(GTK_RANGE(automation_edit->hscrollbar));
1939     width = ((double) automation_edit->selection_x1 - (double) automation_edit->selection_x0);
1940   }else{
1941     x = ((double) automation_edit->selection_x1) - gtk_range_get_value(GTK_RANGE(automation_edit->hscrollbar));
1942     width = ((double) automation_edit->selection_x0 - (double) automation_edit->selection_x1);
1943   }
1944 
1945   if(automation_edit->selection_y0 < automation_edit->selection_y1){
1946     y = ((double) automation_edit->selection_y0) - gtk_range_get_value(GTK_RANGE(automation_edit->vscrollbar));
1947     height = ((double) automation_edit->selection_y1 - (double) automation_edit->selection_y0);
1948   }else{
1949     y = ((double) automation_edit->selection_y1) - gtk_range_get_value(GTK_RANGE(automation_edit->vscrollbar));
1950     height = ((double) automation_edit->selection_y0 - (double) automation_edit->selection_y1);
1951   }
1952 
1953   /* clip */
1954   if(x < 0.0){
1955     width += x;
1956 
1957     x = 0.0;
1958   }else if(x > allocation.width){
1959     g_boxed_free(GDK_TYPE_RGBA, fg_color_prelight);
1960 
1961     return;
1962   }
1963 
1964   if(x + width > allocation.width){
1965     width = ((double) allocation.width) - x;
1966   }
1967 
1968   if(y < 0.0){
1969     height += y;
1970 
1971     y = 0.0;
1972   }else if(y > allocation.height){
1973     g_boxed_free(GDK_TYPE_RGBA, fg_color_prelight);
1974 
1975     return;
1976   }
1977 
1978   if(y + height > allocation.height){
1979     height = ((double) allocation.height) - y;
1980   }
1981 
1982   /* push group */
1983   cairo_push_group(cr);
1984 
1985   /* draw selection */
1986   cairo_set_source_rgba(cr,
1987 			fg_color_prelight->red,
1988 			fg_color_prelight->blue,
1989 			fg_color_prelight->green,
1990 			1.0 / 3.0);
1991 
1992   cairo_rectangle(cr,
1993 		  x, y,
1994 		  width, height);
1995   cairo_fill(cr);
1996 
1997   /* complete */
1998   cairo_pop_group_to_source(cr);
1999   cairo_paint(cr);
2000 
2001   //cairo_surface_mark_dirty(cairo_get_target(cr));
2002 
2003   g_boxed_free(GDK_TYPE_RGBA, fg_color_prelight);
2004 }
2005 
2006 void
ags_automation_edit_draw_acceleration(AgsAutomationEdit * automation_edit,AgsAcceleration * acceleration_a,AgsAcceleration * acceleration_b,cairo_t * cr,gdouble opacity)2007 ags_automation_edit_draw_acceleration(AgsAutomationEdit *automation_edit,
2008 				      AgsAcceleration *acceleration_a, AgsAcceleration *acceleration_b,
2009 				      cairo_t *cr,
2010 				      gdouble opacity)
2011 {
2012   AgsAutomationEditor *automation_editor;
2013   AgsAutomationToolbar *automation_toolbar;
2014 
2015   GtkStyleContext *automation_edit_style_context;
2016 
2017   AgsApplicationContext *application_context;
2018 
2019   GtkAllocation allocation;
2020 
2021   GdkRGBA *fg_color;
2022   GdkRGBA *fg_color_selected;
2023 
2024   gdouble gui_scale_factor;
2025   double zoom_factor;
2026   double viewport_x, viewport_y;
2027   gdouble val, step;
2028   gdouble upper, lower, step_count;
2029   gdouble c_range;
2030   gint x, y;
2031   gint a_x, b_x;
2032   gdouble a_y, b_y;
2033   double width, height;
2034 
2035   GValue value = {0};
2036 
2037   if(!AGS_IS_AUTOMATION_EDIT(automation_edit) ||
2038      !AGS_IS_ACCELERATION(acceleration_a) ||
2039      cr == NULL){
2040     return;
2041   }
2042 
2043   automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
2044 								      AGS_TYPE_AUTOMATION_EDITOR);
2045 
2046   if(automation_editor->selected_machine == NULL){
2047     return;
2048   }
2049 
2050   application_context = ags_application_context_get_instance();
2051 
2052   automation_toolbar = automation_editor->automation_toolbar;
2053 
2054   /* scale factor */
2055   gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
2056 
2057   /* style context */
2058   automation_edit_style_context = gtk_widget_get_style_context(GTK_WIDGET(automation_edit->drawing_area));
2059 
2060   gtk_style_context_get_property(automation_edit_style_context,
2061 				 "color",
2062 				 GTK_STATE_FLAG_NORMAL,
2063 				 &value);
2064 
2065   fg_color = g_value_dup_boxed(&value);
2066   g_value_unset(&value);
2067 
2068   gtk_style_context_get_property(automation_edit_style_context,
2069 				 "color",
2070 				 GTK_STATE_FLAG_SELECTED,
2071 				 &value);
2072 
2073   fg_color_selected = g_value_dup_boxed(&value);
2074   g_value_unset(&value);
2075 
2076   gtk_widget_get_allocation(GTK_WIDGET(automation_edit->drawing_area),
2077 			    &allocation);
2078 
2079   if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
2080     c_range = (gdouble) ((guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_HEIGHT));
2081   }else{
2082     c_range = automation_edit->upper - automation_edit->lower;
2083   }
2084 
2085   /* zoom */
2086   zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom));
2087 
2088   /* get offset and dimensions */
2089   if(AGS_AUTOMATION_EDITOR_MAX_CONTROLS > allocation.width){
2090     viewport_x = zoom_factor * gtk_range_get_value(GTK_RANGE(automation_edit->hscrollbar));
2091   }else{
2092     viewport_x = 0.0;
2093   }
2094 
2095   viewport_y = gtk_range_get_value(GTK_RANGE(automation_edit->vscrollbar));
2096 
2097   g_object_get(acceleration_a,
2098 	       "x", &a_x,
2099 	       "y", &a_y,
2100 	       NULL);
2101 
2102   x = ((double) a_x) - viewport_x;
2103 
2104   if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
2105     lower = automation_edit->lower;
2106     upper = automation_edit->upper;
2107 
2108     step_count = ((guint) (gui_scale_factor * AGS_AUTOMATION_EDIT_DEFAULT_HEIGHT)) + 1.0;
2109 
2110     val = a_y;
2111 
2112     y = (step_count - 1.0) * log(val / lower) / log(upper / lower);
2113   }else{
2114     y = allocation.height - ((double) a_y / c_range) * allocation.height - viewport_y;
2115   }
2116 
2117   if(acceleration_b != NULL){
2118     g_object_get(acceleration_b,
2119 		 "x", &b_x,
2120 		 NULL);
2121 
2122     width = ((double) b_x - a_x);
2123   }else{
2124     width = ((double) allocation.width) - x;
2125   }
2126 
2127   height = allocation.height - y;
2128 
2129   if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
2130     gdouble tmp;
2131 
2132     tmp = height;
2133 
2134     height = y;
2135     y = tmp;
2136   }
2137 
2138   /* apply zoom */
2139   x /= zoom_factor;
2140 
2141   width /= zoom_factor;
2142 
2143   /* clip */
2144   if(x < 0.0){
2145     if(x + width < 0.0){
2146       g_boxed_free(GDK_TYPE_RGBA, fg_color);
2147       g_boxed_free(GDK_TYPE_RGBA, fg_color_selected);
2148 
2149       return;
2150     }else{
2151       width += x;
2152       x = 0.0;
2153     }
2154   }else if(x > allocation.width){
2155     g_boxed_free(GDK_TYPE_RGBA, fg_color);
2156     g_boxed_free(GDK_TYPE_RGBA, fg_color_selected);
2157 
2158     return;
2159   }
2160 
2161   if(x + width > allocation.width){
2162     width = ((double) allocation.width) - x;
2163   }
2164 
2165   if(acceleration_b == NULL){
2166     width = ((double) allocation.width - x);
2167   }
2168 
2169   if(y < 0.0){
2170     if(y + height < 0.0){
2171       g_boxed_free(GDK_TYPE_RGBA, fg_color);
2172       g_boxed_free(GDK_TYPE_RGBA, fg_color_selected);
2173 
2174       return;
2175     }else{
2176       height += y;
2177       y = 0.0;
2178     }
2179   }else if(y > allocation.height){
2180     g_boxed_free(GDK_TYPE_RGBA, fg_color);
2181     g_boxed_free(GDK_TYPE_RGBA, fg_color_selected);
2182 
2183     return;
2184   }
2185 
2186   if(y + height > allocation.height){
2187     height = ((double) allocation.height) - y;
2188   }
2189 
2190   /* draw acceleration - dot */
2191   cairo_set_source_rgba(cr,
2192 			fg_color->red,
2193 			fg_color->blue,
2194 			fg_color->green,
2195 			opacity * fg_color->alpha);
2196 
2197   cairo_arc(cr,
2198 	    x, y,
2199 	    automation_edit->point_radius,
2200 	    0.0,
2201 	    2.0 * M_PI);
2202 
2203   cairo_stroke(cr);
2204 
2205   /* draw acceleration - area */
2206   cairo_set_source_rgba(cr,
2207 			fg_color->red,
2208 			fg_color->blue,
2209 			fg_color->green,
2210 			opacity * fg_color->alpha);
2211   cairo_rectangle(cr,
2212 		  x, y,
2213 		  width, height);
2214   cairo_fill(cr);
2215 
2216   /* check acceleration selected */
2217   if(ags_acceleration_test_flags(acceleration_a, AGS_ACCELERATION_IS_SELECTED)){
2218     double selected_x, selected_y;
2219     double selected_width, selected_height;
2220 
2221     selected_x = x - automation_edit->selected_acceleration_border;
2222     selected_y = y - automation_edit->selected_acceleration_border;
2223 
2224     selected_width = width + (2.0 * (double) automation_edit->selected_acceleration_border);
2225     selected_height = height + (2.0 * (double) automation_edit->selected_acceleration_border);
2226 
2227     /* clip */
2228     if(selected_x < 0.0){
2229       selected_x = 0.0;
2230     }
2231 
2232     if(selected_x + selected_width > allocation.width){
2233       selected_width = ((double) allocation.width) - selected_x;
2234     }
2235 
2236     if(selected_y < 0.0){
2237       selected_y = 0.0;
2238     }
2239 
2240     if(selected_y + selected_height > allocation.height){
2241       selected_height = ((double) allocation.height) - selected_y;
2242     }
2243 
2244     /* draw selected acceleration - dot */
2245     cairo_set_source_rgba(cr,
2246 			  fg_color_selected->red,
2247 			  fg_color_selected->blue,
2248 			  fg_color_selected->green,
2249 			  opacity / 3.0);
2250 
2251     cairo_arc(cr,
2252 	      selected_x, selected_y,
2253 	      automation_edit->point_radius + (2.0 * (double) automation_edit->selected_acceleration_border),
2254 	      0.0,
2255 	      2.0 * M_PI);
2256 
2257     cairo_stroke(cr);
2258 
2259     /* draw selected acceleration - area */
2260     cairo_rectangle(cr,
2261 		    selected_x, selected_y,
2262 		    selected_width, selected_height);
2263     cairo_fill(cr);
2264   }
2265 
2266   g_boxed_free(GDK_TYPE_RGBA, fg_color);
2267   g_boxed_free(GDK_TYPE_RGBA, fg_color_selected);
2268 }
2269 
2270 void
ags_automation_edit_draw_automation(AgsAutomationEdit * automation_edit,cairo_t * cr)2271 ags_automation_edit_draw_automation(AgsAutomationEdit *automation_edit, cairo_t *cr)
2272 {
2273   AgsAutomationEditor *automation_editor;
2274   AgsNotebook *notebook;
2275 
2276   AgsTimestamp *timestamp;
2277   AgsTimestamp *current_timestamp;
2278 
2279   GtkAllocation allocation;
2280 
2281   GType channel_type;
2282 
2283   GList *start_list_automation, *list_automation;
2284   GList *start_list_acceleration, *list_acceleration;
2285 
2286   gchar *control_name;
2287 
2288   gdouble opacity;
2289   guint x0, x1;
2290   guint offset;
2291   guint line;
2292   gint i;
2293 
2294   if(!AGS_IS_AUTOMATION_EDIT(automation_edit)){
2295     return;
2296   }
2297 
2298   automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
2299 								      AGS_TYPE_AUTOMATION_EDITOR);
2300 
2301   if(automation_editor->selected_machine == NULL){
2302     return;
2303   }
2304 
2305   notebook = NULL;
2306 
2307   if(automation_edit->channel_type == G_TYPE_NONE){
2308     notebook = NULL;
2309   }else if(automation_edit->channel_type == AGS_TYPE_OUTPUT){
2310     notebook = automation_editor->output_notebook;
2311   }else if(automation_edit->channel_type == AGS_TYPE_INPUT){
2312     notebook = automation_editor->input_notebook;
2313   }
2314 
2315   gtk_widget_get_allocation(GTK_WIDGET(automation_edit->drawing_area),
2316 			    &allocation);
2317 
2318   opacity = gtk_spin_button_get_value(automation_editor->automation_toolbar->opacity);
2319 
2320   /* get visisble region */
2321   x0 = gtk_range_get_value(GTK_RANGE(automation_edit->hscrollbar));
2322   x1 = (gtk_range_get_value(GTK_RANGE(automation_edit->hscrollbar)) + allocation.width);
2323 
2324   /* draw automation */
2325   timestamp = ags_timestamp_new();
2326 
2327   timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
2328   timestamp->flags |= AGS_TIMESTAMP_OFFSET;
2329 
2330   g_object_get(automation_editor->selected_machine->audio,
2331 	       "automation", &start_list_automation,
2332 	       NULL);
2333 
2334   timestamp->timer.ags_offset.offset = (guint64) AGS_NOTATION_DEFAULT_OFFSET * floor((double) x0 / (double) AGS_NOTATION_DEFAULT_OFFSET);
2335 
2336   i = 0;
2337 
2338   while(notebook == NULL ||
2339 	(i = ags_notebook_next_active_tab(notebook,
2340 					  i)) != -1){
2341     list_automation = ags_automation_find_near_timestamp_extended(start_list_automation, i,
2342 								  automation_edit->channel_type, automation_edit->control_name,
2343 								  timestamp);
2344 
2345     while(list_automation != NULL){
2346       AgsAutomation *automation;
2347 
2348       GList *start_list_acceleration, *list_acceleration;
2349 
2350       automation = AGS_AUTOMATION(list_automation->data);
2351 
2352       g_object_get(automation,
2353 		   "timestamp", &current_timestamp,
2354 		   "line", &line,
2355 		   "channel-type", &channel_type,
2356 		   "control-name", &control_name,
2357 		   NULL);
2358 
2359       g_object_unref(current_timestamp);
2360 
2361       if(i != line ||
2362 	 channel_type != automation_editor->focused_automation_edit->channel_type ||
2363 	 !g_strcmp0(control_name,
2364 		    automation_editor->focused_automation_edit->control_name) != TRUE ||
2365 	 current_timestamp == NULL){
2366 	list_automation = list_automation->next;
2367 
2368 	continue;
2369       }
2370 
2371       if(ags_timestamp_get_ags_offset(current_timestamp) > x1){
2372 	break;
2373       }
2374 
2375       if(ags_timestamp_get_ags_offset(current_timestamp) + AGS_AUTOMATION_DEFAULT_OFFSET < x0){
2376 	list_automation = list_automation->next;
2377 
2378 	continue;
2379       }
2380 
2381       g_object_get(automation,
2382 		   "acceleration", &start_list_acceleration,
2383 		   NULL);
2384 
2385       list_acceleration = start_list_acceleration;
2386 
2387       while(list_acceleration != NULL){
2388 	ags_automation_edit_draw_acceleration(automation_edit,
2389 					      list_acceleration->data, ((list_acceleration->next != NULL) ? list_acceleration->next->data: NULL),
2390 					      cr,
2391 					      opacity);
2392 
2393 	/* iterate */
2394 	list_acceleration = list_acceleration->next;
2395       }
2396 
2397       g_list_free_full(start_list_acceleration,
2398 		       g_object_unref);
2399 
2400       /* iterate */
2401       list_automation = list_automation->next;
2402     }
2403 
2404     if(notebook == NULL){
2405       break;
2406     }
2407 
2408     i++;
2409   }
2410 
2411   g_list_free_full(start_list_automation,
2412 		   g_object_unref);
2413 }
2414 
2415 void
ags_automation_edit_draw(AgsAutomationEdit * automation_edit,cairo_t * cr)2416 ags_automation_edit_draw(AgsAutomationEdit *automation_edit, cairo_t *cr)
2417 {
2418   AgsAutomationEditor *automation_editor;
2419 
2420   automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) automation_edit,
2421 								      AGS_TYPE_AUTOMATION_EDITOR);
2422 
2423   ags_automation_editor_reset_audio_scrollbar(automation_editor);
2424   ags_automation_editor_reset_output_scrollbar(automation_editor);
2425   ags_automation_editor_reset_input_scrollbar(automation_editor);
2426 
2427   ags_automation_edit_reset_vscrollbar(automation_edit);
2428   ags_automation_edit_reset_hscrollbar(automation_edit);
2429 
2430   /* segment */
2431   ags_automation_edit_draw_segment(automation_edit, cr);
2432 
2433   /* automation */
2434   ags_automation_edit_draw_automation(automation_edit, cr);
2435 
2436   /* edit mode */
2437   switch(automation_edit->mode){
2438   case AGS_AUTOMATION_EDIT_POSITION_CURSOR:
2439     {
2440       ags_automation_edit_draw_cursor(automation_edit, cr);
2441     }
2442     break;
2443   case AGS_AUTOMATION_EDIT_ADD_ACCELERATION:
2444     {
2445       if(automation_edit->current_acceleration != NULL){
2446 	ags_automation_edit_draw_acceleration(automation_edit,
2447 					      automation_edit->current_acceleration, NULL,
2448 					      cr,
2449 					      1.0);
2450 
2451 	cairo_surface_mark_dirty(cairo_get_target(cr));
2452       }
2453     }
2454     break;
2455   case AGS_AUTOMATION_EDIT_SELECT_ACCELERATION:
2456     {
2457       ags_automation_edit_draw_selection(automation_edit, cr);
2458     }
2459     break;
2460   }
2461 
2462   /* fader */
2463   if((AGS_AUTOMATION_EDIT_AUTO_SCROLL & (automation_edit->flags)) != 0){
2464     ags_automation_edit_draw_position(automation_edit, cr);
2465   }
2466 }
2467 
2468 /**
2469  * ags_automation_edit_new:
2470  *
2471  * Create a new #AgsAutomationEdit.
2472  *
2473  * Returns: a new #AgsAutomationEdit
2474  *
2475  * Since: 3.0.0
2476  */
2477 AgsAutomationEdit*
ags_automation_edit_new()2478 ags_automation_edit_new()
2479 {
2480   AgsAutomationEdit *automation_edit;
2481 
2482   automation_edit = (AgsAutomationEdit *) g_object_new(AGS_TYPE_AUTOMATION_EDIT, NULL);
2483 
2484   return(automation_edit);
2485 }
2486