1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 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/widget/ags_ruler.h>
21 
22 #include <pango/pango.h>
23 
24 #ifndef __APPLE__
25 #include <pango/pangofc-fontmap.h>
26 #endif
27 
28 #include <math.h>
29 
30 void ags_ruler_class_init(AgsRulerClass *ruler);
31 void ags_ruler_init(AgsRuler *ruler);
32 void ags_ruler_set_property(GObject *gobject,
33 			    guint prop_id,
34 			    const GValue *value,
35 			    GParamSpec *param_spec);
36 void ags_ruler_get_property(GObject *gobject,
37 			    guint prop_id,
38 			    GValue *value,
39 			    GParamSpec *param_spec);
40 void ags_ruler_show(GtkWidget *widget);
41 
42 void ags_ruler_realize(GtkWidget *widget);
43 void ags_ruler_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
44 void ags_ruler_get_preferred_height(GtkWidget *widget,
45 				    gint *minimal_height,
46 				    gint *natural_height);
47 
48 void ags_ruler_send_configure(AgsRuler *ruler);
49 
50 gboolean ags_ruler_draw(AgsRuler *ruler, cairo_t *cr);
51 
52 /**
53  * SECTION:ags_ruler
54  * @short_description: A ruler widget
55  * @title: AgsRuler
56  * @section_id:
57  * @include: ags/widget/ags_ruler.h
58  *
59  * #AgsRuler is a widget representing a #GtkAdjustment.
60  */
61 
62 enum{
63   PROP_0,
64   PROP_STEP,
65   PROP_LARGE_STEP,
66   PROP_SMALL_STEP,
67   PROP_ADJUSTMENT,
68   PROP_FONT_SIZE,
69 };
70 
71 static gpointer ags_ruler_parent_class = NULL;
72 
73 GType
ags_ruler_get_type()74 ags_ruler_get_type()
75 {
76   static volatile gsize g_define_type_id__volatile = 0;
77 
78   if(g_once_init_enter (&g_define_type_id__volatile)){
79     GType ags_type_ruler = 0;
80 
81     static const GTypeInfo ags_ruler_info = {
82       sizeof(AgsRulerClass),
83       NULL, /* base_init */
84       NULL, /* base_finalize */
85       (GClassInitFunc) ags_ruler_class_init,
86       NULL, /* class_finalize */
87       NULL, /* class_data */
88       sizeof(AgsRuler),
89       0,    /* n_preallocs */
90       (GInstanceInitFunc) ags_ruler_init,
91     };
92 
93     ags_type_ruler = g_type_register_static(GTK_TYPE_WIDGET,
94 					    "AgsRuler", &ags_ruler_info,
95 					    0);
96 
97     g_once_init_leave(&g_define_type_id__volatile, ags_type_ruler);
98   }
99 
100   return g_define_type_id__volatile;
101 }
102 
103 void
ags_ruler_class_init(AgsRulerClass * ruler)104 ags_ruler_class_init(AgsRulerClass *ruler)
105 {
106   GObjectClass *gobject;
107   GtkWidgetClass *widget;
108   GParamSpec *param_spec;
109 
110   ags_ruler_parent_class = g_type_class_peek_parent(ruler);
111 
112   /* GObjectClass */
113   gobject = (GObjectClass *) ruler;
114 
115   gobject->set_property = ags_ruler_set_property;
116   gobject->get_property = ags_ruler_get_property;
117 
118   /* GtkWidgetClass */
119   widget = (GtkWidgetClass *) ruler;
120 
121   widget->realize = ags_ruler_realize;
122   widget->size_allocate = ags_ruler_size_allocate;
123   widget->get_preferred_height = ags_ruler_get_preferred_height;
124   widget->draw = ags_ruler_draw;
125   widget->show = ags_ruler_show;
126 
127   /* properties */
128   /**
129    * AgsRuler:font-size:
130    *
131    * The font size.
132    *
133    * Since: 3.6.15
134    */
135   param_spec = g_param_spec_uint("font-size",
136 				 "font size",
137 				 "The font size",
138 				 0,
139 				 G_MAXUINT,
140 				 AGS_RULER_FONT_SIZE,
141 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
142   g_object_class_install_property(gobject,
143 				  PROP_FONT_SIZE,
144 				  param_spec);
145 
146   /**
147    * AgsRuler:adjustment:
148    *
149    * The adjustment.
150    *
151    * Since: 3.0.0
152    */
153   param_spec = g_param_spec_object("adjustment",
154 				   "assigned adjustment",
155 				   "The adjustment it is assigned with",
156 				   G_TYPE_OBJECT,
157 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
158   g_object_class_install_property(gobject,
159 				  PROP_ADJUSTMENT,
160 				  param_spec);
161 
162   /**
163    * AgsRuler:step:
164    *
165    * The step's width.
166    *
167    * Since: 3.0.0
168    */
169   param_spec = g_param_spec_uint("step",
170 				 "step",
171 				 "The width of a step",
172 				 0,
173 				 G_MAXUINT,
174 				 AGS_RULER_DEFAULT_STEP,
175 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
176   g_object_class_install_property(gobject,
177 				  PROP_STEP,
178 				  param_spec);
179 
180   /**
181    * AgsRuler:large-step:
182    *
183    * The large step's width.
184    *
185    * Since: 3.0.0
186    */
187   param_spec = g_param_spec_uint("large-step",
188 				 "large step",
189 				 "The width of a large step",
190 				 0,
191 				 G_MAXUINT,
192 				 AGS_RULER_DEFAULT_LARGE_STEP,
193 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
194   g_object_class_install_property(gobject,
195 				  PROP_LARGE_STEP,
196 				  param_spec);
197 
198   /**
199    * AgsRuler:small-step:
200    *
201    * The small step's width.
202    *
203    * Since: 3.0.0
204    */
205   param_spec = g_param_spec_uint("small-step",
206 				 "small step",
207 				 "The width of a small step",
208 				 0,
209 				 G_MAXUINT,
210 				 AGS_RULER_DEFAULT_SMALL_STEP,
211 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
212   g_object_class_install_property(gobject,
213 				  PROP_SMALL_STEP,
214 				  param_spec);
215 }
216 
217 void
ags_ruler_init(AgsRuler * ruler)218 ags_ruler_init(AgsRuler *ruler)
219 {
220   g_object_set(G_OBJECT(ruler),
221   	       "app-paintable", TRUE,
222   	       NULL);
223 
224   ruler->flags = 0;
225 
226   ruler->font_size = AGS_RULER_FONT_SIZE;
227 
228   ruler->adjustment = NULL;
229 
230   ruler->step = AGS_RULER_DEFAULT_STEP;
231   ruler->large_step = AGS_RULER_DEFAULT_LARGE_STEP;
232   ruler->small_step = AGS_RULER_DEFAULT_SMALL_STEP;
233 
234   ruler->factor = 16.0;
235   ruler->precision = 1.0;
236   ruler->scale_precision = 1.0;
237 }
238 
239 
240 void
ags_ruler_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)241 ags_ruler_set_property(GObject *gobject,
242 		       guint prop_id,
243 		       const GValue *value,
244 		       GParamSpec *param_spec)
245 {
246   AgsRuler *ruler;
247 
248   ruler = AGS_RULER(gobject);
249 
250   switch(prop_id){
251   case PROP_FONT_SIZE:
252   {
253     ruler->font_size = g_value_get_uint(value);
254   }
255   break;
256   case PROP_STEP:
257   {
258     ruler->step = g_value_get_uint(value);
259   }
260   break;
261   case PROP_LARGE_STEP:
262   {
263     ruler->large_step = g_value_get_uint(value);
264   }
265   break;
266   case PROP_SMALL_STEP:
267   {
268     ruler->small_step = g_value_get_uint(value);
269   }
270   break;
271   case PROP_ADJUSTMENT:
272     {
273       GtkAdjustment *adjustment;
274 
275       adjustment = (GtkAdjustment *) g_value_get_object(value);
276 
277       if(ruler->adjustment == adjustment)
278 	return;
279 
280       if(ruler->adjustment != NULL){
281 	g_object_unref(G_OBJECT(ruler->adjustment));
282       }
283 
284       if(adjustment != NULL){
285 	g_object_ref(G_OBJECT(adjustment));
286       }
287 
288       ruler->adjustment = adjustment;
289     }
290     break;
291   default:
292     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
293     break;
294   }
295 }
296 
297 void
ags_ruler_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)298 ags_ruler_get_property(GObject *gobject,
299 		       guint prop_id,
300 		       GValue *value,
301 		       GParamSpec *param_spec)
302 {
303   AgsRuler *ruler;
304 
305   ruler = AGS_RULER(gobject);
306 
307   switch(prop_id){
308   case PROP_FONT_SIZE:
309   {
310     g_value_set_uint(value, ruler->font_size);
311   }
312   break;
313   case PROP_STEP:
314   {
315     g_value_set_uint(value, ruler->step);
316   }
317   break;
318   case PROP_LARGE_STEP:
319   {
320     g_value_set_uint(value, ruler->large_step);
321   }
322   break;
323   case PROP_SMALL_STEP:
324   {
325     g_value_set_uint(value, ruler->small_step);
326   }
327   break;
328   case PROP_ADJUSTMENT:
329   {
330     g_value_set_object(value, ruler->adjustment);
331   }
332   break;
333   default:
334     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
335     break;
336   }
337 }
338 
339 void
ags_ruler_realize(GtkWidget * widget)340 ags_ruler_realize(GtkWidget *widget)
341 {
342   AgsRuler *ruler;
343 
344   GdkWindow *window;
345 
346   GtkAllocation allocation;
347   GdkWindowAttr attributes;
348 
349   gint attributes_mask;
350   gint border_left, border_top;
351 
352   g_return_if_fail(widget != NULL);
353   g_return_if_fail(AGS_IS_RULER(widget));
354 
355   ruler = AGS_RULER(widget);
356 
357 //  GTK_WIDGET_CLASS(ags_ruler_parent_class)->realize(widget);
358 
359   gtk_widget_set_realized(widget, TRUE);
360 
361   gtk_widget_get_allocation(widget,
362 			    &allocation);
363 
364   /*  */
365   attributes.window_type = GDK_WINDOW_CHILD;
366 
367   attributes.x = allocation.x;
368   attributes.y = allocation.y;
369   attributes.width = allocation.width;
370   attributes.height = allocation.height;
371 
372   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
373 
374   attributes.wclass = GDK_INPUT_OUTPUT;
375   attributes.visual = gtk_widget_get_visual(widget);
376   attributes.event_mask = gtk_widget_get_events(widget);
377   attributes.event_mask |= (GDK_EXPOSURE_MASK |
378                             GDK_BUTTON_PRESS_MASK |
379                             GDK_BUTTON_RELEASE_MASK |
380                             GDK_BUTTON1_MOTION_MASK |
381                             GDK_BUTTON3_MOTION_MASK |
382                             GDK_POINTER_MOTION_HINT_MASK |
383                             GDK_POINTER_MOTION_MASK |
384                             GDK_ENTER_NOTIFY_MASK |
385                             GDK_LEAVE_NOTIFY_MASK);
386 
387   window = gdk_window_new(gtk_widget_get_parent_window(widget),
388 			  &attributes, attributes_mask);
389 
390   gtk_widget_register_window(widget, window);
391   gtk_widget_set_window(widget, window);
392 
393   ags_ruler_send_configure(ruler);
394 }
395 
396 void
ags_ruler_size_allocate(GtkWidget * widget,GtkAllocation * allocation)397 ags_ruler_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
398 {
399   AgsRuler *ruler;
400 
401   g_return_if_fail(AGS_IS_RULER(widget));
402   g_return_if_fail(allocation != NULL);
403 
404   ruler = AGS_RULER(widget);
405 
406   gtk_widget_set_allocation(widget, allocation);
407 
408   if(gtk_widget_get_realized(widget)){
409     gdk_window_move_resize(gtk_widget_get_window(widget),
410 			   allocation->x, allocation->y,
411 			   allocation->width, allocation->height);
412 
413     ags_ruler_send_configure(ruler);
414   }
415 }
416 
417 void
ags_ruler_send_configure(AgsRuler * ruler)418 ags_ruler_send_configure(AgsRuler *ruler)
419 {
420   GtkAllocation allocation;
421   GtkWidget *widget;
422   GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
423 
424   widget = GTK_WIDGET(ruler);
425   gtk_widget_get_allocation(widget, &allocation);
426 
427   event->configure.window = g_object_ref(gtk_widget_get_window (widget));
428   event->configure.send_event = TRUE;
429   event->configure.x = allocation.x;
430   event->configure.y = allocation.y;
431   event->configure.width = allocation.width;
432   event->configure.height = allocation.height;
433 
434   gtk_widget_event(widget, event);
435   gdk_event_free(event);
436 }
437 
438 void
ags_ruler_show(GtkWidget * widget)439 ags_ruler_show(GtkWidget *widget)
440 {
441   GTK_WIDGET_CLASS(ags_ruler_parent_class)->show(widget);
442 }
443 
444 void
ags_ruler_get_preferred_height(GtkWidget * widget,gint * minimal_height,gint * natural_height)445 ags_ruler_get_preferred_height(GtkWidget *widget,
446 			       gint *minimal_height,
447 			       gint *natural_height)
448 {
449   gint height_request;
450 
451   height_request = -1;
452 
453   g_object_get(widget,
454 	       "height-request", &height_request,
455 	       NULL);
456 
457   if(height_request != -1){
458     minimal_height[0] =
459       natural_height[0] = height_request;
460   }else{
461     minimal_height[0] =
462       natural_height[0] = (gint) AGS_RULER_DEFAULT_HEIGHT;
463   }
464 }
465 
466 /**
467  * ags_ruler_draw:
468  * @ruler an #AgsRuler
469  *
470  * draws the widget
471  */
472 gboolean
ags_ruler_draw(AgsRuler * ruler,cairo_t * cr)473 ags_ruler_draw(AgsRuler *ruler, cairo_t *cr)
474 {
475   GtkWidget *widget;
476 
477   GtkAllocation allocation;
478 
479   gchar *font_name;
480 
481   gdouble tact_factor, zoom_factor;
482   gdouble tact;
483 
484   guint offset;
485   guint step;
486   guint x0;
487   guint z;
488   guint i, i_stop;
489 
490   widget = GTK_WIDGET(ruler);
491 
492 //  GTK_WIDGET_CLASS(ags_ruler_parent_class)->draw(widget, cr);
493 
494   g_object_get(gtk_settings_get_default(),
495 	       "gtk-font-name", &font_name,
496 	       NULL);
497 
498   gtk_widget_get_allocation(widget,
499 			    &allocation);
500 
501   //  cairo_surface_flush(cairo_get_target(cr));
502   cairo_push_group(cr);
503 
504   /* calculate base step */
505   tact = ruler->precision;
506 
507   step = ruler->step * 0.25 * ruler->factor * ruler->precision;
508 
509   /* draw bg */
510   cairo_set_source_rgba(cr,
511 			0.0,
512 			0.0,
513 			0.125,
514 			1.0);
515   cairo_rectangle(cr,
516 		  0.0, 0.0,
517 		  (double) allocation.width, (double) allocation.height);
518   cairo_fill(cr);
519 
520   cairo_set_source_rgba(cr,
521 			1.0,
522 			1.0,
523 			1.0,
524 			1.0);
525   cairo_set_line_width(cr,
526 		       1.25);
527 
528   /* draw scale */
529   offset = (gtk_adjustment_get_value(ruler->adjustment) * step);
530   x0 = offset % step;
531 
532   z = (guint) floor((offset - x0) / step);
533 
534   i_stop = (guint) ceil((double) (allocation.width + (step + x0)) / (double) step);
535 
536   for(i = 0; i < i_stop; i++, z++){
537     cairo_move_to(cr,
538 		  (double) (i * step - x0),
539 		  (double) (allocation.height));
540 
541     if(tact < 1.0){
542       PangoLayout *layout;
543       PangoFontDescription *desc;
544 
545       PangoRectangle ink_rect, logical_rect;
546 
547       gchar *text;
548 
549       text = g_strdup_printf("%u",
550 			     (guint) ((gdouble) z / tact));
551 
552       layout = pango_cairo_create_layout(cr);
553       pango_layout_set_text(layout,
554 			    text,
555 			    -1);
556       desc = pango_font_description_from_string(font_name);
557       pango_font_description_set_size(desc,
558 				      ruler->font_size * PANGO_SCALE);
559       pango_layout_set_font_description(layout,
560 					desc);
561       pango_font_description_free(desc);
562 
563       pango_layout_get_extents(layout,
564 			       &ink_rect,
565 			       &logical_rect);
566 
567       /* draw large step */
568       cairo_set_line_width(cr,
569 			   1.75);
570 
571       cairo_line_to(cr,
572 		    (double) (i * step - x0),
573 		    (double) (allocation.height - ruler->large_step));
574 
575       /* draw scale step */
576       cairo_move_to(cr,
577 		    (double) (i * step - x0),
578 		    (double) (allocation.height - ruler->large_step - (ruler->font_size + AGS_RULER_FREE_SPACE)));
579 
580       pango_cairo_show_layout(cr,
581 			      layout);
582 
583       g_object_unref(layout);
584 
585       g_free(text);
586     }else{
587       if(z % (guint) floor(tact) == 0){
588 	PangoLayout *layout;
589 	PangoFontDescription *desc;
590 
591 	PangoRectangle ink_rect, logical_rect;
592 
593 	gchar *text;
594 
595 	text = g_strdup_printf("%u",
596 			       (guint) ((gdouble) z / tact));
597 
598 	layout = pango_cairo_create_layout(cr);
599 	pango_layout_set_text(layout,
600 			      text,
601 			      -1);
602 	desc = pango_font_description_from_string(font_name);
603 	pango_font_description_set_size(desc,
604 					ruler->font_size * PANGO_SCALE);
605 	pango_layout_set_font_description(layout,
606 					  desc);
607 	pango_font_description_free(desc);
608 
609 	pango_layout_get_extents(layout,
610 				 &ink_rect,
611 				 &logical_rect);
612 
613 	/* draw large step */
614 	cairo_set_line_width(cr,
615 			     1.75);
616 
617 	cairo_line_to(cr,
618 		      (double) (i * step - x0),
619 		      (double) (allocation.height - ruler->large_step));
620 
621 	/* draw scale step */
622 	cairo_move_to(cr,
623 		      (double) (i * step - x0),
624 		      (double) (allocation.height - ruler->large_step - (ruler->font_size + AGS_RULER_FREE_SPACE)));
625 
626 	pango_cairo_show_layout(cr,
627 				layout);
628 
629 	g_object_unref(layout);
630 
631 	g_free(text);
632       }else{
633 	/* draw small step */
634 	cairo_set_line_width(cr,
635 			     1.25);
636 
637 	cairo_line_to(cr,
638 		      (double) (i * step - x0),
639 		      (double) (allocation.height - ruler->small_step));
640       }
641     }
642 
643     cairo_stroke(cr);
644   }
645 
646   g_free(font_name);
647 
648   cairo_pop_group_to_source(cr);
649   cairo_paint(cr);
650 
651 //  cairo_surface_mark_dirty(cairo_get_target(cr));
652 
653   return(FALSE);
654 }
655 
656 /**
657  * ags_ruler_get_font_size:
658  * @ruler: the #AgsRuler
659  *
660  * Get font size of @ruler.
661  *
662  * Returns: the font size
663  *
664  * Since: 3.6.15
665  */
666 guint
ags_ruler_get_font_size(AgsRuler * ruler)667 ags_ruler_get_font_size(AgsRuler *ruler)
668 {
669   guint font_size;
670 
671   if(!AGS_IS_RULER(ruler)){
672     return(0);
673   }
674 
675   g_object_get(ruler,
676 	       "font-size", &font_size,
677 	       NULL);
678 
679   return(font_size);
680 }
681 
682 /**
683  * ags_ruler_set_font_size:
684  * @ruler: the #AgsRuler
685  * @font_size: the font size
686  *
687  * Set font size of @ruler.
688  *
689  * Since: 3.6.15
690  */
691 void
ags_ruler_set_font_size(AgsRuler * ruler,guint font_size)692 ags_ruler_set_font_size(AgsRuler *ruler,
693 		   guint font_size)
694 {
695   if(!AGS_IS_RULER(ruler)){
696     return;
697   }
698 
699   g_object_set(ruler,
700 	       "font-size", font_size,
701 	       NULL);
702 }
703 
704 /**
705  * ags_ruler_get_step:
706  * @ruler: the #AgsRuler
707  *
708  * Get step of @ruler.
709  *
710  * Returns: the step
711  *
712  * Since: 3.2.0
713  */
714 guint
ags_ruler_get_step(AgsRuler * ruler)715 ags_ruler_get_step(AgsRuler *ruler)
716 {
717   guint step;
718 
719   if(!AGS_IS_RULER(ruler)){
720     return(0);
721   }
722 
723   g_object_get(ruler,
724 	       "step", &step,
725 	       NULL);
726 
727   return(step);
728 }
729 
730 /**
731  * ags_ruler_set_step:
732  * @ruler: the #AgsRuler
733  * @step: the step
734  *
735  * Set step of @ruler.
736  *
737  * Since: 3.2.0
738  */
739 void
ags_ruler_set_step(AgsRuler * ruler,guint step)740 ags_ruler_set_step(AgsRuler *ruler,
741 		   guint step)
742 {
743   if(!AGS_IS_RULER(ruler)){
744     return;
745   }
746 
747   g_object_set(ruler,
748 	       "step", step,
749 	       NULL);
750 }
751 
752 /**
753  * ags_ruler_get_large_step:
754  * @ruler: the #AgsRuler
755  *
756  * Get large step of @ruler.
757  *
758  * Returns: the large step
759  *
760  * Since: 3.2.0
761  */
762 guint
ags_ruler_get_large_step(AgsRuler * ruler)763 ags_ruler_get_large_step(AgsRuler *ruler)
764 {
765   guint large_step;
766 
767   if(!AGS_IS_RULER(ruler)){
768     return(0);
769   }
770 
771   g_object_get(ruler,
772 	       "large-step", &large_step,
773 	       NULL);
774 
775   return(large_step);
776 }
777 
778 /**
779  * ags_ruler_set_large_step:
780  * @ruler: the #AgsRuler
781  * @large_step: the large step
782  *
783  * Set large step of @ruler.
784  *
785  * Since: 3.2.0
786  */
787 void
ags_ruler_set_large_step(AgsRuler * ruler,guint large_step)788 ags_ruler_set_large_step(AgsRuler *ruler,
789 			 guint large_step)
790 {
791   if(!AGS_IS_RULER(ruler)){
792     return;
793   }
794 
795   g_object_set(ruler,
796 	       "large-step", large_step,
797 	       NULL);
798 }
799 
800 /**
801  * ags_ruler_get_small_step:
802  * @ruler: the #AgsRuler
803  *
804  * Get small step of @ruler.
805  *
806  * Returns: the small step
807  *
808  * Since: 3.2.0
809  */
810 guint
ags_ruler_get_small_step(AgsRuler * ruler)811 ags_ruler_get_small_step(AgsRuler *ruler)
812 {
813   guint small_step;
814 
815   if(!AGS_IS_RULER(ruler)){
816     return(0);
817   }
818 
819   g_object_get(ruler,
820 	       "small-step", &small_step,
821 	       NULL);
822 
823   return(small_step);
824 }
825 
826 /**
827  * ags_ruler_set_small_step:
828  * @ruler: the #AgsRuler
829  * @small_step: the small step
830  *
831  * Set small step of @ruler.
832  *
833  * Since: 3.2.0
834  */
835 void
ags_ruler_set_small_step(AgsRuler * ruler,guint small_step)836 ags_ruler_set_small_step(AgsRuler *ruler,
837 			 guint small_step)
838 {
839   if(!AGS_IS_RULER(ruler)){
840     return;
841   }
842 
843   g_object_set(ruler,
844 	       "small-step", small_step,
845 	       NULL);
846 }
847 
848 /**
849  * ags_ruler_get_adjustment:
850  * @ruler: the #AgsRuler
851  *
852  * Get adjustment of @ruler.
853  *
854  * Returns: (transfer full): the #GtkAdjustment
855  *
856  * Since: 3.2.0
857  */
858 GtkAdjustment*
ags_ruler_get_adjustment(AgsRuler * ruler)859 ags_ruler_get_adjustment(AgsRuler *ruler)
860 {
861   GtkAdjustment *adjustment;
862 
863   if(!AGS_IS_RULER(ruler)){
864     return(NULL);
865   }
866 
867   g_object_get(ruler,
868 	       "adjustment", &adjustment,
869 	       NULL);
870 
871   return(adjustment);
872 }
873 
874 /**
875  * ags_ruler_set_adjustment:
876  * @ruler: the #AgsRuler
877  * @adjustment: (transfer none): the #GtkAdjustment
878  *
879  * Set adjustment of @ruler.
880  *
881  * Since: 3.2.0
882  */
883 void
ags_ruler_set_adjustment(AgsRuler * ruler,GtkAdjustment * adjustment)884 ags_ruler_set_adjustment(AgsRuler *ruler,
885 			 GtkAdjustment *adjustment)
886 {
887   if(!AGS_IS_RULER(ruler)){
888     return;
889   }
890 
891   g_object_set(ruler,
892 	       "adjustment", adjustment,
893 	       NULL);
894 }
895 
896 /**
897  * ags_ruler_new:
898  *
899  * Create a new instance of #AgsRuler
900  *
901  * Returns: the new #AgsRuler
902  *
903  * Since: 3.0.0
904  */
905 AgsRuler*
ags_ruler_new()906 ags_ruler_new()
907 {
908   AgsRuler *ruler;
909   GtkAdjustment *adjustment;
910 
911   adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.1, 0.0);
912 
913   ruler = (AgsRuler *) g_object_new(AGS_TYPE_RULER,
914 				    "adjustment", adjustment,
915 				    NULL);
916 
917   return(ruler);
918 }
919