2 * Custom controls (line graph, knob).
3 * Copyright (C) 2007-2010 Krzysztof Foltman, Torben Hohn, Markus Schmidt
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #include <gtk/gtkrange.h>
23 #include <calf/giface.h>
24 #include <calf/custom_ctl.h>
25 #include <gdk/gdkkeysyms.h>
33 #include <calf/drawingutils.h>
35 using namespace calf_plugins
;
39 ///////////////////////////////////////// meter scale ///////////////////////////////////////////////
42 calf_meter_scale_new()
44 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_METER_SCALE
, NULL
));
45 //CalfMeterScale *self = CALF_METER_SCALE(widget);
49 calf_meter_scale_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
51 g_assert(CALF_IS_METER_SCALE(widget
));
52 CalfMeterScale
*ms
= CALF_METER_SCALE(widget
);
53 if (gtk_widget_is_drawable (widget
)) {
55 GdkWindow
*window
= widget
->window
;
56 cairo_t
*cr
= gdk_cairo_create(GDK_DRAWABLE(window
));
57 cairo_text_extents_t extents
;
59 double ox
= widget
->allocation
.x
;
60 double oy
= widget
->allocation
.y
;
61 double sx
= widget
->allocation
.width
;
62 double sy
= widget
->allocation
.height
;
63 double width
= widget
->allocation
.width
;
64 double height
= widget
->allocation
.height
;
65 double xthick
= widget
->style
->xthickness
;
66 double text_w
= 0, bar_x
= 0, bar_width
= 0, bar_y
= 0;
73 cairo_rectangle(cr
, ox
, oy
, sx
, sy
);
77 cairo_select_font_face(cr
, "cairo:sans-serif", CAIRO_FONT_SLANT_NORMAL
, CAIRO_FONT_WEIGHT_NORMAL
);
78 cairo_set_font_size(cr
, 8);
79 cairo_text_extents(cr
, "-88.88", &extents
);
80 text_w
= extents
.width
;
82 switch(ms
->position
) {
86 bar_width
= width
- 2 * xthick
;
91 bar_width
= width
- text_w
- 2 * xthick
- 2 * text_m
;
96 bar_width
= width
- 2 * xthick
;
100 bar_x
= ox
+ xthick
+ text_w
+ 2 * text_m
;
101 bar_width
= width
- text_w
- 2 * xthick
- 2 * text_m
;
113 bar_y
= oy
+ dot_s
+ dot_m
+ extents
.height
;
114 dot_y
= oy
+ dot_s
/ 2;
118 bar_y
= oy
+ height
- dot_s
- dot_m
- extents
.height
+ extents
.y_bearing
;
119 dot_y
= oy
+ height
- dot_s
/ 2;
123 bar_y
= oy
+ height
/ 2 - extents
.y_bearing
/ 2;
124 dot_y
= oy
+ height
- dot_s
/ 2;
125 dot_y2
= oy
+ dot_s
/ 2;
129 const unsigned int s
= ms
->marker
.size();
130 get_fg_color(widget
, NULL
, &r
, &g
, &b
);
131 cairo_set_source_rgb(cr
, r
, g
, b
);
132 for (unsigned int i
= 0; i
< s
; i
++) {
133 double val
= log10(1 + ms
->marker
[i
] * 9);
135 cairo_arc(cr
, bar_x
+ bar_width
* val
, dot_y
, dot_s
/ 2, 0, 2*M_PI
);
139 cairo_arc(cr
, bar_x
+ bar_width
* val
, dot_y2
, dot_s
/ 2, 0, 2*M_PI
);
143 if (val
< 1.0 / 32768.0)
144 snprintf(str
, sizeof(str
), "-inf");
146 snprintf(str
, sizeof(str
), "%.f", amp2dB(ms
->marker
[i
]));
147 cairo_text_extents(cr
, str
, &extents
);
149 std::min(ox
+ width
, std::max(ox
, bar_x
+ bar_width
* val
- extents
.width
/ 2)), bar_y
);
150 cairo_show_text(cr
, str
);
158 calf_meter_scale_size_request (GtkWidget
*widget
,
159 GtkRequisition
*requisition
)
161 g_assert(CALF_IS_METER_SCALE(widget
));
162 CalfMeterScale
*self
= CALF_METER_SCALE(widget
);
164 double ythick
= widget
->style
->ythickness
;
165 double text_h
= 8; // FIXME: Pango layout should be used here
169 requisition
->height
= ythick
*2 + text_h
+ (dot_m
+ dot_s
) * (self
->dots
== 3 ? 2 : 1);
173 calf_meter_scale_class_init (CalfMeterScaleClass
*klass
)
175 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
176 widget_class
->expose_event
= calf_meter_scale_expose
;
177 widget_class
->size_request
= calf_meter_scale_size_request
;
181 calf_meter_scale_init (CalfMeterScale
*self
)
183 GtkWidget
*widget
= GTK_WIDGET(self
);
184 gtk_widget_set_has_window(widget
, FALSE
);
185 widget
->requisition
.width
= 40;
186 widget
->requisition
.height
= 12;
187 self
->mode
= VU_STANDARD
;
193 calf_meter_scale_get_type (void)
195 static GType type
= 0;
197 static const GTypeInfo type_info
= {
198 sizeof(CalfMeterScaleClass
),
199 NULL
, /* base_init */
200 NULL
, /* base_finalize */
201 (GClassInitFunc
)calf_meter_scale_class_init
,
202 NULL
, /* class_finalize */
203 NULL
, /* class_data */
204 sizeof(CalfMeterScale
),
206 (GInstanceInitFunc
)calf_meter_scale_init
209 for (int i
= 0; ; i
++) {
210 char *name
= g_strdup_printf("CalfMeterScale%u%d",
211 ((unsigned int)(intptr_t)calf_meter_scale_class_init
) >> 16, i
);
212 if (g_type_from_name(name
)) {
216 type
= g_type_register_static(GTK_TYPE_DRAWING_AREA
,
228 ///////////////////////////////////////// phase graph ///////////////////////////////////////////////
231 calf_phase_graph_draw_background(GtkWidget
*widget
, cairo_t
*ctx
, int sx
, int sy
, int ox
, int oy
, float radius
, float bevel
)
233 int cx
= ox
+ sx
/ 2;
234 int cy
= oy
+ sy
/ 2;
236 display_background(widget
, ctx
, 0, 0, sx
, sy
, ox
, oy
, radius
, bevel
);
237 cairo_set_source_rgb(ctx
, 0.35, 0.4, 0.2);
238 cairo_select_font_face(ctx
, "Sans", CAIRO_FONT_SLANT_NORMAL
, CAIRO_FONT_WEIGHT_NORMAL
);
239 cairo_set_font_size(ctx
, 9);
240 cairo_text_extents_t te
;
242 cairo_text_extents (ctx
, "M", &te
);
243 cairo_move_to (ctx
, cx
+ 5, oy
+ 12);
244 cairo_show_text (ctx
, "M");
246 cairo_text_extents (ctx
, "S", &te
);
247 cairo_move_to (ctx
, ox
+ 5, cy
- 5);
248 cairo_show_text (ctx
, "S");
250 cairo_text_extents (ctx
, "L", &te
);
251 cairo_move_to (ctx
, ox
+ 18, oy
+ 12);
252 cairo_show_text (ctx
, "L");
254 cairo_text_extents (ctx
, "R", &te
);
255 cairo_move_to (ctx
, ox
+ sx
- 22, oy
+ 12);
256 cairo_show_text (ctx
, "R");
258 cairo_set_line_width(ctx
, 1);
260 cairo_move_to(ctx
, ox
, oy
+ sy
* 0.5);
261 cairo_line_to(ctx
, ox
+ sx
, oy
+ sy
* 0.5);
264 cairo_move_to(ctx
, ox
+ sx
* 0.5, oy
);
265 cairo_line_to(ctx
, ox
+ sx
* 0.5, oy
+ sy
);
268 cairo_set_source_rgba(ctx
, 0, 0, 0, 0.2);
269 cairo_move_to(ctx
, ox
, oy
);
270 cairo_line_to(ctx
, ox
+ sx
, oy
+ sy
);
273 cairo_move_to(ctx
, ox
, oy
+ sy
);
274 cairo_line_to(ctx
, ox
+ sx
, oy
);
278 calf_phase_graph_copy_surface(cairo_t
*ctx
, cairo_surface_t
*source
, int x
= 0, int y
= 0, float fade
= 1.f
)
280 // copy a surface to a cairo context
282 cairo_set_source_surface(ctx
, source
, x
, y
);
284 float rnd
= (float)rand() / (float)RAND_MAX
/ 100;
285 cairo_paint_with_alpha(ctx
, fade
* 0.35 + 0.05 + rnd
);
292 calf_phase_graph_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
294 g_assert(CALF_IS_PHASE_GRAPH(widget
));
295 CalfPhaseGraph
*pg
= CALF_PHASE_GRAPH(widget
);
300 int width
= widget
->allocation
.width
;
301 int height
= widget
->allocation
.height
;
302 int ox
= widget
->style
->xthickness
;
303 int oy
= widget
->style
->ythickness
;
304 int sx
= width
- ox
* 2;
305 int sy
= height
- oy
* 2;
306 int x
= widget
->allocation
.x
;
307 int y
= widget
->allocation
.y
;
312 int cx
= ox
+ sx
/ 2;
313 int cy
= oy
+ sy
/ 2;
316 gtk_widget_style_get(widget
, "border-radius", &radius
, "bevel", &bevel
, NULL
);
318 // some values as pointers for the audio plug-in call
319 float * phase_buffer
= 0;
323 bool use_fade
= true;
327 // cairo initialization stuff
328 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(widget
->window
));
332 if( pg
->background
== NULL
) {
333 // looks like its either first call or the widget has been resized.
334 // create the background surface (stolen from line graph)...
335 pg
->background
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, width
, height
);
336 pg
->cache
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, width
, height
);
338 // ...and draw some bling bling onto it...
339 ctx_back
= cairo_create(pg
->background
);
340 calf_phase_graph_draw_background(widget
, ctx_back
, sx
, sy
, ox
, oy
, radius
, bevel
);
341 // ...and copy it to the cache
342 ctx_cache
= cairo_create(pg
->cache
);
343 calf_phase_graph_copy_surface(ctx_cache
, pg
->background
, 0, 0, 1);
345 ctx_back
= cairo_create(pg
->background
);
346 ctx_cache
= cairo_create(pg
->cache
);
349 pg
->source
->get_phase_graph(&phase_buffer
, &length
, &mode
, &use_fade
,
350 &fade
, &accuracy
, &display
);
352 // process some values set by the plug-in
354 accuracy
= 12 - accuracy
;
356 cairo_rectangle(ctx_cache
, ox
, oy
, sx
, sy
);
357 cairo_clip(ctx_cache
);
359 calf_phase_graph_copy_surface(ctx_cache
, pg
->background
, 0, 0, use_fade
? fade
: 1);
362 cairo_rectangle(ctx_cache
, ox
, oy
, sx
, sy
);
363 cairo_clip(ctx_cache
);
364 cairo_set_source_rgba(ctx_cache
, 0.35, 0.4, 0.2, 1);
366 for(int i
= 0; i
< length
; i
+= accuracy
) {
367 float l
= phase_buffer
[i
];
368 float r
= phase_buffer
[i
+ 1];
369 if(l
== 0.f
and r
== 0.f
) continue;
370 else if(r
== 0.f
and l
> 0.f
) _a
= M_PI
/ 2.f
;
371 else if(r
== 0.f
and l
< 0.f
) _a
= 3.f
*M_PI
/ 2.f
;
372 else _a
= pg
->_atan(l
/ r
, l
, r
);
373 double _R
= sqrt(pow(l
, 2) + pow(r
, 2));
375 float x_
= (-1.f
)*_R
* cos(_a
);
376 float y_
= _R
* sin(_a
);
377 // mask the cached values
381 cairo_rectangle (ctx_cache
, x_
* rad
+ cx
, y_
* rad
+ cy
, 1, 1);
385 cairo_rectangle (ctx_cache
, x_
* rad
+ cx
- 0.25, y_
* rad
+ cy
- 0.25, 1.5, 1.5);
389 cairo_rectangle (ctx_cache
, x_
* rad
+ cx
- 0.5, y_
* rad
+ cy
- 0.5, 2, 2);
393 if(i
== 0) cairo_move_to(ctx_cache
,
394 x_
* rad
+ cx
, y_
* rad
+ cy
);
395 else cairo_line_to(ctx_cache
,
396 x_
* rad
+ cx
, y_
* rad
+ cy
);
400 if(i
== 0) cairo_move_to(ctx_cache
,
401 x_
* rad
+ cx
, y_
* rad
+ cy
);
402 else cairo_line_to(ctx_cache
,
403 x_
* rad
+ cx
, y_
* rad
+ cy
);
412 cairo_fill(ctx_cache
);
415 cairo_fill(ctx_cache
);
418 cairo_set_line_width(ctx_cache
, 0.5);
419 cairo_stroke(ctx_cache
);
424 calf_phase_graph_copy_surface(c
, pg
->cache
, x
, y
);
427 cairo_destroy(ctx_back
);
428 cairo_destroy(ctx_cache
);
429 // printf("exposed %p %dx%d %d+%d\n", widget->window, event->area.x, event->area.y, event->area.width, event->area.height);
434 calf_phase_graph_size_request (GtkWidget
*widget
,
435 GtkRequisition
*requisition
)
437 g_assert(CALF_IS_PHASE_GRAPH(widget
));
438 // CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
442 calf_phase_graph_size_allocate (GtkWidget
*widget
,
443 GtkAllocation
*allocation
)
445 g_assert(CALF_IS_PHASE_GRAPH(widget
));
446 CalfPhaseGraph
*lg
= CALF_PHASE_GRAPH(widget
);
448 GtkWidgetClass
*parent_class
= (GtkWidgetClass
*) g_type_class_peek_parent( CALF_PHASE_GRAPH_GET_CLASS( lg
) );
451 cairo_surface_destroy(lg
->background
);
452 lg
->background
= NULL
;
454 widget
->allocation
= *allocation
;
455 GtkAllocation
&a
= widget
->allocation
;
456 if (a
.width
> a
.height
) {
457 a
.x
+= (a
.width
- a
.height
) / 2;
460 if (a
.width
< a
.height
) {
461 a
.y
+= (a
.height
- a
.width
) / 2;
464 parent_class
->size_allocate(widget
, &a
);
468 calf_phase_graph_class_init (CalfPhaseGraphClass
*klass
)
470 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
471 widget_class
->expose_event
= calf_phase_graph_expose
;
472 widget_class
->size_request
= calf_phase_graph_size_request
;
473 widget_class
->size_allocate
= calf_phase_graph_size_allocate
;
474 gtk_widget_class_install_style_property(
475 widget_class
, g_param_spec_float("border-radius", "Border Radius", "Generate round edges",
476 0, 24, 4, GParamFlags(G_PARAM_READWRITE
)));
477 gtk_widget_class_install_style_property(
478 widget_class
, g_param_spec_float("bevel", "Bevel", "Bevel the object",
479 -2, 2, 0.2, GParamFlags(G_PARAM_READWRITE
)));
483 calf_phase_graph_unrealize (GtkWidget
*widget
, CalfPhaseGraph
*pg
)
486 cairo_surface_destroy(pg
->background
);
487 pg
->background
= NULL
;
491 calf_phase_graph_init (CalfPhaseGraph
*self
)
493 GtkWidget
*widget
= GTK_WIDGET(self
);
494 widget
->requisition
.width
= 40;
495 widget
->requisition
.height
= 40;
496 self
->background
= NULL
;
497 gtk_widget_set_has_window(widget
, FALSE
);
498 g_signal_connect(GTK_OBJECT(widget
), "unrealize", G_CALLBACK(calf_phase_graph_unrealize
), (gpointer
)self
);
502 calf_phase_graph_new()
504 return GTK_WIDGET(g_object_new (CALF_TYPE_PHASE_GRAPH
, NULL
));
508 calf_phase_graph_get_type (void)
510 static GType type
= 0;
512 static const GTypeInfo type_info
= {
513 sizeof(CalfPhaseGraphClass
),
514 NULL
, /* base_init */
515 NULL
, /* base_finalize */
516 (GClassInitFunc
)calf_phase_graph_class_init
,
517 NULL
, /* class_finalize */
518 NULL
, /* class_data */
519 sizeof(CalfPhaseGraph
),
521 (GInstanceInitFunc
)calf_phase_graph_init
524 GTypeInfo
*type_info_copy
= new GTypeInfo(type_info
);
526 for (int i
= 0; ; i
++) {
527 //const char *name = "CalfPhaseGraph";
528 char *name
= g_strdup_printf("CalfPhaseGraph%u%d", ((unsigned int)(intptr_t)calf_phase_graph_class_init
) >> 16, i
);
529 if (g_type_from_name(name
)) {
533 type
= g_type_register_static( GTK_TYPE_DRAWING_AREA
,
545 ///////////////////////////////////////// toggle ///////////////////////////////////////////////
548 calf_toggle_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
550 g_assert(CALF_IS_TOGGLE(widget
));
551 CalfToggle
*self
= CALF_TOGGLE(widget
);
552 if (!self
->toggle_image
)
554 float off
= floor(.5 + gtk_range_get_value(GTK_RANGE(widget
)));
555 float pw
= gdk_pixbuf_get_width(self
->toggle_image
);
556 float ph
= gdk_pixbuf_get_height(self
->toggle_image
);
557 float wcx
= widget
->allocation
.x
+ widget
->allocation
.width
/ 2;
558 float wcy
= widget
->allocation
.y
+ widget
->allocation
.height
/ 2;
561 float sy
= off
* ph
/ 2;
564 gdk_draw_pixbuf(GDK_DRAWABLE(widget
->window
), widget
->style
->fg_gc
[0],
565 self
->toggle_image
, 0, sy
, x
, y
, pw
, ph
/ 2, GDK_RGB_DITHER_NORMAL
, 0, 0);
570 calf_toggle_size_request (GtkWidget
*widget
,
571 GtkRequisition
*requisition
)
573 g_assert(CALF_IS_TOGGLE(widget
));
574 requisition
->width
= widget
->style
->xthickness
;
575 requisition
->height
= widget
->style
->ythickness
;
579 calf_toggle_button_press (GtkWidget
*widget
, GdkEventButton
*event
)
581 g_assert(CALF_IS_TOGGLE(widget
));
582 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(widget
));
583 if (gtk_range_get_value(GTK_RANGE(widget
)) == adj
->lower
)
585 gtk_range_set_value(GTK_RANGE(widget
), adj
->upper
);
587 gtk_range_set_value(GTK_RANGE(widget
), adj
->lower
);
593 calf_toggle_key_press (GtkWidget
*widget
, GdkEventKey
*event
)
595 switch(event
->keyval
)
600 return calf_toggle_button_press(widget
, NULL
);
606 calf_toggle_class_init (CalfToggleClass
*klass
)
608 // GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
609 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
610 widget_class
->expose_event
= calf_toggle_expose
;
611 widget_class
->size_request
= calf_toggle_size_request
;
612 widget_class
->button_press_event
= calf_toggle_button_press
;
613 widget_class
->key_press_event
= calf_toggle_key_press
;
617 calf_toggle_init (CalfToggle
*self
)
619 GtkWidget
*widget
= GTK_WIDGET(self
);
620 GTK_WIDGET_SET_FLAGS (GTK_WIDGET(self
), GTK_CAN_FOCUS
);
621 widget
->requisition
.width
= 30;
622 widget
->requisition
.height
= 20;
627 calf_toggle_set_size (CalfToggle
*self
, int size
)
630 GtkWidget
*widget
= GTK_WIDGET(self
);
632 sprintf(name
, "%s_%d\n", gtk_widget_get_name(widget
), size
);
633 gtk_widget_set_name(widget
, name
);
634 gtk_widget_queue_resize(widget
);
637 calf_toggle_set_pixbuf (CalfToggle
*self
, GdkPixbuf
*pixbuf
)
639 GtkWidget
*widget
= GTK_WIDGET(self
);
640 self
->toggle_image
= pixbuf
;
641 gtk_widget_queue_resize(widget
);
647 GtkAdjustment
*adj
= (GtkAdjustment
*)gtk_adjustment_new(0, 0, 1, 1, 0, 0);
648 return calf_toggle_new_with_adjustment(adj
);
651 static gboolean
calf_toggle_value_changed(gpointer obj
)
653 GtkWidget
*widget
= (GtkWidget
*)obj
;
654 CalfToggle
*self
= CALF_TOGGLE(widget
);
655 float sx
= self
->size
? self
->size
: 1.f
/ 3.f
* 2.f
;
656 float sy
= self
->size
? self
->size
: 1;
657 gtk_widget_queue_draw_area(widget
,
658 widget
->allocation
.x
- sx
* 2,
659 widget
->allocation
.y
- sy
* 3,
665 GtkWidget
*calf_toggle_new_with_adjustment(GtkAdjustment
*_adjustment
)
667 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TOGGLE
, NULL
));
669 gtk_range_set_adjustment(GTK_RANGE(widget
), _adjustment
);
670 g_signal_connect(GTK_OBJECT(widget
), "value-changed", G_CALLBACK(calf_toggle_value_changed
), widget
);
676 calf_toggle_get_type (void)
678 static GType type
= 0;
681 static const GTypeInfo type_info
= {
682 sizeof(CalfToggleClass
),
683 NULL
, /* base_init */
684 NULL
, /* base_finalize */
685 (GClassInitFunc
)calf_toggle_class_init
,
686 NULL
, /* class_finalize */
687 NULL
, /* class_data */
690 (GInstanceInitFunc
)calf_toggle_init
693 for (int i
= 0; ; i
++) {
694 char *name
= g_strdup_printf("CalfToggle%u%d",
695 ((unsigned int)(intptr_t)calf_toggle_class_init
) >> 16, i
);
696 if (g_type_from_name(name
)) {
700 type
= g_type_register_static( GTK_TYPE_RANGE
,
711 ///////////////////////////////////////// frame ///////////////////////////////////////////////
715 calf_frame_new(const char *label
)
717 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_FRAME
, NULL
));
718 CalfFrame
*self
= CALF_FRAME(widget
);
719 gtk_frame_set_label(GTK_FRAME(self
), label
);
723 calf_frame_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
725 g_assert(CALF_IS_FRAME(widget
));
726 if (gtk_widget_is_drawable (widget
)) {
728 GdkWindow
*window
= widget
->window
;
729 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
730 cairo_text_extents_t extents
;
732 int ox
= widget
->allocation
.x
;
733 int oy
= widget
->allocation
.y
;
734 int sx
= widget
->allocation
.width
;
735 int sy
= widget
->allocation
.height
;
738 gtk_widget_style_get(widget
, "border-radius", &rad
, NULL
);
740 double pad
= widget
->style
->xthickness
;
747 cairo_rectangle(c
, ox
, oy
, sx
, sy
);
751 const gchar
*lab
= gtk_frame_get_label(GTK_FRAME(widget
));
753 cairo_select_font_face(c
, "Sans",
754 CAIRO_FONT_SLANT_NORMAL
,
755 CAIRO_FONT_WEIGHT_NORMAL
);
756 cairo_set_font_size(c
, size
);
758 cairo_text_extents(c
, lab
, &extents
);
760 double lw
= extents
.width
+ txp
* 2.;
762 cairo_set_line_width(c
, 1.);
764 cairo_move_to(c
, ox
+ rad
+ txp
+ m
, oy
+ size
- 2 + m
);
765 get_text_color(widget
, NULL
, &r
, &g
, &b
);
766 cairo_set_source_rgb(c
, r
, g
, b
);
767 cairo_show_text(c
, lab
);
768 get_fg_color(widget
, NULL
, &r
, &g
, &b
);
769 cairo_set_source_rgb(c
, r
, g
, b
);
772 cairo_move_to(c
, ox
+ m
, oy
+ pad
+ rad
+ m
);
773 cairo_arc (c
, ox
+ rad
+ m
, oy
+ rad
+ pad
+ m
, rad
, 1 * M_PI
, 1.5 * M_PI
);
775 cairo_move_to(c
, ox
+ rad
+ lw
+ m
, oy
+ pad
+ m
);
776 cairo_line_to(c
, ox
+ sx
- rad
- m
, oy
+ pad
+ m
);
778 cairo_arc (c
, ox
+ sx
- rad
- m
, oy
+ rad
+ pad
+ m
, rad
, 1.5 * M_PI
, 2 * M_PI
);
780 cairo_line_to(c
, ox
+ sx
- m
, oy
+ sy
- rad
- m
);
782 cairo_arc (c
, ox
+ sx
- rad
- m
, oy
+ sy
- rad
- m
, rad
, 0 * M_PI
, 0.5 * M_PI
);
784 cairo_line_to(c
, ox
+ rad
+ m
, oy
+ sy
- m
);
786 cairo_arc (c
, ox
+ rad
+ m
, oy
+ sy
- rad
- m
, rad
, 0.5 * M_PI
, 1 * M_PI
);
788 cairo_line_to(c
, ox
+ m
, oy
+ rad
+ pad
+ m
);
793 if (gtk_bin_get_child(GTK_BIN(widget
))) {
794 gtk_container_propagate_expose(GTK_CONTAINER(widget
),
795 gtk_bin_get_child(GTK_BIN(widget
)),
802 calf_frame_class_init (CalfFrameClass
*klass
)
804 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
805 widget_class
->expose_event
= calf_frame_expose
;
806 gtk_widget_class_install_style_property(
807 widget_class
, g_param_spec_float("border-radius", "Border Radius", "Generate round edges",
808 0, 24, 4, GParamFlags(G_PARAM_READWRITE
)));
812 calf_frame_init (CalfFrame
*self
)
814 GtkWidget
*widget
= GTK_WIDGET(self
);
815 widget
->requisition
.width
= 40;
816 widget
->requisition
.height
= 40;
820 calf_frame_get_type (void)
822 static GType type
= 0;
824 static const GTypeInfo type_info
= {
825 sizeof(CalfFrameClass
),
826 NULL
, /* base_init */
827 NULL
, /* base_finalize */
828 (GClassInitFunc
)calf_frame_class_init
,
829 NULL
, /* class_finalize */
830 NULL
, /* class_data */
833 (GInstanceInitFunc
)calf_frame_init
836 for (int i
= 0; ; i
++) {
837 //const char *name = "CalfFrame";
838 char *name
= g_strdup_printf("CalfFrame%u%d",
839 ((unsigned int)(intptr_t)calf_frame_class_init
) >> 16, i
);
840 if (g_type_from_name(name
)) {
844 type
= g_type_register_static(GTK_TYPE_FRAME
,
855 ///////////////////////////////////////// combo box ///////////////////////////////////////////////
857 //#define GTK_COMBO_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxPrivate))
862 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_COMBOBOX
, NULL
));
863 GtkCellRenderer
*column
= gtk_cell_renderer_text_new();
864 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget
), column
, TRUE
);
865 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(widget
), column
,
871 calf_combobox_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
873 g_assert(CALF_IS_COMBOBOX(widget
));
875 if (gtk_widget_is_drawable (widget
)) {
877 int padx
= widget
->style
->xthickness
;
878 int pady
= widget
->style
->ythickness
;
880 GtkComboBox
*cb
= GTK_COMBO_BOX(widget
);
881 CalfCombobox
*ccb
= CALF_COMBOBOX(widget
);
882 GdkWindow
*window
= widget
->window
;
883 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
885 GtkTreeModel
*model
= gtk_combo_box_get_model(cb
);
888 if (gtk_combo_box_get_active_iter (cb
, &iter
))
889 gtk_tree_model_get (model
, &iter
, 0, &lab
, -1);
893 int x
= widget
->allocation
.x
;
894 int y
= widget
->allocation
.y
;
895 int sx
= widget
->allocation
.width
;
896 int sy
= widget
->allocation
.height
;
900 create_rectangle(c
, x
, y
, sx
, sy
, 0);
903 gtk_widget_get_pointer(widget
, &mx
, &my
);
904 if (mx
>= 0 and mx
< sx
and my
>= 0 and my
< sy
)
909 gtk_widget_style_get(widget
, "border-radius", &radius
, "bevel", &bevel
, NULL
);
910 display_background(widget
, c
, x
, y
, sx
- padx
* 2, sy
- pady
* 2, padx
, pady
, radius
, bevel
, g_ascii_isspace(lab
[0]) ? 0 : 1, 4, hover
? 0.5 : 0, hover
? 0.1 : 0.25);
913 gtk_container_propagate_expose (GTK_CONTAINER (widget
),
914 GTK_BIN (widget
)->child
, event
);
918 int pw
= gdk_pixbuf_get_width(ccb
->arrow
);
919 int ph
= gdk_pixbuf_get_height(ccb
->arrow
);
920 gdk_draw_pixbuf(GDK_DRAWABLE(window
), widget
->style
->fg_gc
[0],
922 x
+ sx
- padx
- pw
, y
+ (sy
- ph
) / 2, pw
, ph
,
923 GDK_RGB_DITHER_NORMAL
, 0, 0);
933 calf_combobox_set_arrow (CalfCombobox
*self
, GdkPixbuf
*arrow
)
939 calf_combobox_class_init (CalfComboboxClass
*klass
)
941 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
942 widget_class
->expose_event
= calf_combobox_expose
;
943 gtk_widget_class_install_style_property(
944 widget_class
, g_param_spec_float("border-radius", "Border Radius", "Generate round edges",
945 0, 24, 4, GParamFlags(G_PARAM_READWRITE
)));
946 gtk_widget_class_install_style_property(
947 widget_class
, g_param_spec_float("bevel", "Bevel", "Bevel the object",
948 -2, 2, 0.2, GParamFlags(G_PARAM_READWRITE
)));
952 calf_combobox_init (CalfCombobox
*self
)
954 GtkWidget
*widget
= GTK_WIDGET(self
);
955 widget
->requisition
.width
= 40;
956 widget
->requisition
.height
= 20;
960 calf_combobox_get_type (void)
962 static GType type
= 0;
964 static const GTypeInfo type_info
= {
965 sizeof(CalfComboboxClass
),
966 NULL
, /* base_init */
967 NULL
, /* base_finalize */
968 (GClassInitFunc
)calf_combobox_class_init
,
969 NULL
, /* class_finalize */
970 NULL
, /* class_data */
971 sizeof(CalfCombobox
),
973 (GInstanceInitFunc
)calf_combobox_init
976 for (int i
= 0; ; i
++) {
977 //const char *name = "CalfCombobox";
978 char *name
= g_strdup_printf("CalfCombobox%u%d",
979 ((unsigned int)(intptr_t)calf_combobox_class_init
) >> 16, i
);
980 if (g_type_from_name(name
)) {
984 type
= g_type_register_static(GTK_TYPE_COMBO_BOX
,
996 ///////////////////////////////////////// notebook ///////////////////////////////////////////////
998 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
999 struct _GtkNotebookPage
1002 GtkWidget
*tab_label
;
1003 GtkWidget
*menu_label
;
1004 GtkWidget
*last_focus_child
; /* Last descendant of the page that had focus */
1006 guint default_menu
: 1; /* If true, we create the menu label ourself */
1007 guint default_tab
: 1; /* If true, we create the tab label ourself */
1011 guint reorderable
: 1;
1012 guint detachable
: 1;
1014 /* if true, the tab label was visible on last allocation; we track this so
1015 * that we know to redraw the tab area if a tab label was hidden then shown
1016 * without changing position */
1017 guint tab_allocated_visible
: 1;
1019 GtkRequisition requisition
;
1020 GtkAllocation allocation
;
1022 gulong mnemonic_activate_signal
;
1023 gulong notify_visible_handler
;
1029 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_NOTEBOOK
, NULL
));
1033 calf_notebook_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1035 g_assert(CALF_IS_NOTEBOOK(widget
));
1037 GtkNotebook
*notebook
= GTK_NOTEBOOK(widget
);
1038 CalfNotebook
*nb
= CALF_NOTEBOOK(widget
);
1040 if (gtk_widget_is_drawable (widget
)) {
1042 GdkWindow
*window
= widget
->window
;
1043 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
1044 cairo_pattern_t
*pat
= NULL
;
1046 int x
= widget
->allocation
.x
;
1047 int y
= widget
->allocation
.y
;
1048 int sx
= widget
->allocation
.width
;
1049 int sy
= widget
->allocation
.height
;
1050 int tx
= widget
->style
->xthickness
;
1051 int ty
= widget
->style
->ythickness
;
1053 int bh
= lh
+ 2 * ty
;
1057 gtk_widget_style_get(widget
, "background-alpha", &alpha
, NULL
);
1059 cairo_rectangle(c
, x
, y
, sx
, sy
);
1064 if (notebook
->show_tabs
) {
1065 GtkNotebookPage
*page
;
1069 gtk_widget_style_get(widget
, "tab-overlap", &sp
, NULL
);
1071 pages
= notebook
->children
;
1075 page
= GTK_NOTEBOOK_PAGE (pages
);
1076 pages
= pages
->next
;
1077 if (page
->tab_label
->window
== event
->window
&&
1078 gtk_widget_is_drawable (page
->tab_label
)) {
1079 int lx
= page
->tab_label
->allocation
.x
;
1080 int lw
= page
->tab_label
->allocation
.width
;
1082 // fix the labels position
1083 page
->tab_label
->allocation
.y
= y
+ ty
;
1084 page
->tab_label
->allocation
.height
= lh
;
1086 // draw tab background
1087 cairo_rectangle(c
, lx
- tx
, y
, lw
+ 2 * tx
, bh
);
1088 get_base_color(widget
, NULL
, &r
, &g
, &b
);
1089 cairo_set_source_rgba(c
, r
,g
,b
, page
!= notebook
->cur_page
? alpha
/ 2 : alpha
);
1092 if (page
== notebook
->cur_page
) {
1094 get_bg_color(widget
, NULL
, &r
, &g
, &b
);
1095 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 2, lw
+ 2 * tx
- 4, 2);
1096 cairo_set_source_rgb(c
, r
, g
, b
);
1099 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 1, lw
+ 2 * tx
- 4, 1);
1100 cairo_set_source_rgba(c
, 0,0,0,0.5);
1103 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 4, lw
+ 2 * tx
- 4, 1);
1104 cairo_set_source_rgba(c
, 1,1,1,0.3);
1109 gtk_container_propagate_expose (GTK_CONTAINER (notebook
), page
->tab_label
, event
);
1117 get_base_color(widget
, NULL
, &r
, &g
, &b
);
1118 cairo_rectangle(c
, x
, y
+ add
, sx
, sy
- add
);
1119 cairo_set_source_rgba(c
, r
, g
, b
, alpha
);
1123 cairo_rectangle(c
, x
+ 0.5, y
+ add
+ 0.5, sx
- 1, sy
- add
- 1);
1124 pat
= cairo_pattern_create_linear(x
, y
+ add
, x
, y
+ sy
- add
);
1125 cairo_pattern_add_color_stop_rgba(pat
, 0, 0, 0, 0, 0.3);
1126 cairo_pattern_add_color_stop_rgba(pat
, 0.5, 0.5, 0.5, 0.5, 0);
1127 cairo_pattern_add_color_stop_rgba(pat
, 1, 1, 1, 1, 0.2);
1128 cairo_set_source (c
, pat
);
1129 cairo_set_line_width(c
, 1);
1130 cairo_stroke_preserve(c
);
1132 int sw
= gdk_pixbuf_get_width(nb
->screw
);
1133 int sh
= gdk_pixbuf_get_height(nb
->screw
);
1137 gdk_cairo_set_source_pixbuf(c
, nb
->screw
, x
, y
+ add
);
1138 cairo_fill_preserve(c
);
1139 gdk_cairo_set_source_pixbuf(c
, nb
->screw
, x
+ sx
- sw
, y
+ add
);
1140 cairo_fill_preserve(c
);
1141 gdk_cairo_set_source_pixbuf(c
, nb
->screw
, x
, y
+ sy
- sh
);
1142 cairo_fill_preserve(c
);
1143 gdk_cairo_set_source_pixbuf(c
, nb
->screw
, x
+ sx
- sh
, y
+ sy
- sh
);
1144 cairo_fill_preserve(c
);
1146 // propagate expose to all children
1147 if (notebook
->cur_page
)
1148 gtk_container_propagate_expose (GTK_CONTAINER (notebook
),
1149 notebook
->cur_page
->child
,
1152 cairo_pattern_destroy(pat
);
1160 calf_notebook_set_pixbuf (CalfNotebook
*self
, GdkPixbuf
*image
)
1162 self
->screw
= image
;
1163 gtk_widget_queue_draw(GTK_WIDGET(self
));
1167 calf_notebook_class_init (CalfNotebookClass
*klass
)
1169 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1170 widget_class
->expose_event
= calf_notebook_expose
;
1171 gtk_widget_class_install_style_property(
1172 widget_class
, g_param_spec_float("background-alpha", "Alpha Background", "Alpha of background",
1173 0.0, 1.0, 0.5, GParamFlags(G_PARAM_READWRITE
)));
1177 calf_notebook_init (CalfNotebook
*self
)
1179 //GtkWidget *widget = GTK_WIDGET(self);
1183 calf_notebook_get_type (void)
1185 static GType type
= 0;
1187 static const GTypeInfo type_info
= {
1188 sizeof(CalfNotebookClass
),
1189 NULL
, /* base_init */
1190 NULL
, /* base_finalize */
1191 (GClassInitFunc
)calf_notebook_class_init
,
1192 NULL
, /* class_finalize */
1193 NULL
, /* class_data */
1194 sizeof(CalfNotebook
),
1195 0, /* n_preallocs */
1196 (GInstanceInitFunc
)calf_notebook_init
1199 for (int i
= 0; ; i
++) {
1200 //const char *name = "CalfNotebook";
1201 char *name
= g_strdup_printf("CalfNotebook%u%d",
1202 ((unsigned int)(intptr_t)calf_notebook_class_init
) >> 16, i
);
1203 if (g_type_from_name(name
)) {
1207 type
= g_type_register_static(GTK_TYPE_NOTEBOOK
,
1218 ///////////////////////////////////////// fader ///////////////////////////////////////////////
1220 void calf_fader_set_layout(GtkWidget
*widget
)
1222 GtkRange
*range
= GTK_RANGE(widget
);
1223 CalfFader
*fader
= CALF_FADER(widget
);
1224 CalfFaderLayout l
= fader
->layout
;
1228 gtk_range_get_range_rect(range
, &t
);
1229 gtk_range_get_slider_range(range
, &sstart
, &send
);
1231 int hor
= fader
->horizontal
;
1233 gtk_widget_style_get(widget
, "slider-length", &slength
, NULL
);
1236 l
.x
= widget
->allocation
.x
+ t
.x
;
1237 l
.y
= widget
->allocation
.y
+ t
.y
;
1238 l
.w
= t
.width
; //widget->allocation.width;
1239 l
.h
= t
.height
; //widget->allocation.height;
1242 l
.iw
= gdk_pixbuf_get_width(fader
->image
);
1243 l
.ih
= gdk_pixbuf_get_height(fader
->image
);
1245 // first screw layout
1246 l
.s1w
= hor
? slength
: gdk_pixbuf_get_width(fader
->image
);
1247 l
.s1h
= !hor
? slength
: gdk_pixbuf_get_height(fader
->image
);
1253 // second screw layout
1256 l
.s2x1
= hor
? l
.iw
- 3 * l
.s2w
: 0;
1257 l
.s2y1
= !hor
? l
.ih
- 3 * l
.s2h
: 0;
1258 l
.s2x2
= hor
? l
.w
- l
.s2w
+ l
.x
: l
.x
;
1259 l
.s2y2
= !hor
? l
.h
- l
.s2h
+ l
.y
: l
.y
;
1264 l
.t1x1
= hor
? l
.iw
- 2 * l
.s2w
: 0;
1265 l
.t1y1
= !hor
? l
.ih
- 2 * l
.s2h
: 0;
1270 l
.t2x1
= hor
? l
.iw
- l
.s2w
: 0;
1271 l
.t2y1
= !hor
? l
.ih
- l
.s2h
: 0;
1274 l
.sw
= hor
? l
.iw
- 4 * l
.s1w
: l
.ih
;
1275 l
.sh
= !hor
? l
.ih
- 4 * l
.s1h
: l
.iw
;
1276 l
.sx1
= hor
? l
.s1w
: 0;
1277 l
.sy1
= !hor
? l
.s1h
: 0;
1278 l
.sx2
= hor
? l
.s1w
+ l
.x
: l
.x
;
1279 l
.sy2
= !hor
? l
.s1h
+ l
.y
: l
.y
;
1280 l
.sw2
= hor
? l
.w
- 2 * l
.s1w
: l
.iw
;
1281 l
.sh2
= !hor
? l
.h
- 2 * l
.s1h
: l
.ih
;
1287 calf_fader_new(const int horiz
= 0, const int size
= 2, const double min
= 0, const double max
= 1, const double step
= 0.1)
1292 adj
= gtk_adjustment_new (min
, min
, max
, step
, 10 * step
, 0);
1294 if (fabs (step
) >= 1.0 || step
== 0.0)
1297 digits
= std::min(5, abs((gint
) floor (log10 (fabs (step
)))));
1299 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_FADER
, NULL
));
1300 CalfFader
*self
= CALF_FADER(widget
);
1302 GTK_RANGE(widget
)->orientation
= horiz
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
;
1303 gtk_range_set_adjustment(GTK_RANGE(widget
), GTK_ADJUSTMENT(adj
));
1304 gtk_scale_set_digits(GTK_SCALE(widget
), digits
);
1307 self
->horizontal
= horiz
;
1313 static bool calf_fader_hover(GtkWidget
*widget
)
1315 CalfFader
*fader
= CALF_FADER(widget
);
1318 gtk_widget_get_pointer(GTK_WIDGET(widget
), &mx
, &my
);
1320 GtkRange
*range
= GTK_RANGE(widget
);
1321 GdkRectangle trough
;
1323 gtk_range_get_range_rect(range
, &trough
);
1324 gtk_range_get_slider_range(range
, &sstart
, &send
);
1326 int hor
= fader
->horizontal
;
1328 int x1
= hor
? sstart
: trough
.x
;
1329 int x2
= hor
? send
: trough
.x
+ trough
.width
;
1330 int y1
= !hor
? sstart
: trough
.y
;
1331 int y2
= !hor
? send
: trough
.y
+ trough
.height
;
1333 return mx
>= x1
and mx
<= x2
and my
>= y1
and my
<= y2
;
1335 static void calf_fader_check_hover_change(GtkWidget
*widget
)
1337 CalfFader
*fader
= CALF_FADER(widget
);
1338 bool hover
= calf_fader_hover(widget
);
1339 if (hover
!= fader
->hover
)
1340 gtk_widget_queue_draw(widget
);
1341 fader
->hover
= hover
;
1344 calf_fader_motion (GtkWidget
*widget
, GdkEventMotion
*event
)
1346 calf_fader_check_hover_change(widget
);
1351 calf_fader_enter (GtkWidget
*widget
, GdkEventCrossing
*event
)
1353 calf_fader_check_hover_change(widget
);
1358 calf_fader_leave (GtkWidget
*widget
, GdkEventCrossing
*event
)
1360 CALF_FADER(widget
)->hover
= false;
1361 gtk_widget_queue_draw(widget
);
1365 calf_fader_allocate (GtkWidget
*widget
, GtkAllocation
*allocation
)
1367 calf_fader_set_layout(widget
);
1370 calf_fader_request (GtkWidget
*widget
, GtkAllocation
*request
)
1372 calf_fader_set_layout(widget
);
1375 calf_fader_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1377 g_assert(CALF_IS_FADER(widget
));
1378 if (gtk_widget_is_drawable (widget
)) {
1380 GdkWindow
*window
= widget
->window
;
1381 GtkScale
*scale
= GTK_SCALE(widget
);
1382 GtkRange
*range
= GTK_RANGE(widget
);
1383 CalfFader
*fader
= CALF_FADER(widget
);
1384 CalfFaderLayout l
= fader
->layout
;
1385 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
1386 int horiz
= fader
->horizontal
;
1387 cairo_rectangle(c
, l
.x
, l
.y
, l
.w
, l
.h
);
1391 double r0
= range
->adjustment
->upper
- range
->adjustment
->lower
;
1392 double v0
= range
->adjustment
->value
- range
->adjustment
->lower
;
1393 if ((horiz
and gtk_range_get_inverted(range
))
1394 or (!horiz
and gtk_range_get_inverted(range
)))
1396 int vp
= v0
/ r0
* (horiz
? l
.w
- l
.s1w
: l
.h
- l
.s1h
);
1398 l
.t1x2
= l
.t2x2
= horiz
? l
.x
+ vp
: l
.x
;
1399 l
.t1y2
= l
.t2y2
= !horiz
? l
.y
+ vp
: l
.y
;
1401 GdkPixbuf
*i
= fader
->image
;
1404 cairo_rectangle(c
, l
.s1x2
, l
.s1y2
, l
.s1w
, l
.s1h
);
1405 gdk_cairo_set_source_pixbuf(c
, i
, l
.s1x2
- l
.s1x1
, l
.s1y2
- l
.s1y1
);
1409 cairo_rectangle(c
, l
.s2x2
, l
.s2y2
, l
.s2w
, l
.s2h
);
1410 gdk_cairo_set_source_pixbuf(c
, i
, l
.s2x2
- l
.s2x1
, l
.s2y2
- l
.s2y1
);
1416 while (x
< l
.sx2
+ l
.sw2
) {
1417 cairo_rectangle(c
, x
, l
.sy2
, std::min(l
.sx2
+ l
.sw2
- x
, l
.sw
), l
.sh2
);
1418 gdk_cairo_set_source_pixbuf(c
, i
, x
- l
.sx1
, l
.sy2
- l
.sy1
);
1424 while (y
< l
.sy2
+ l
.sh2
) {
1425 cairo_rectangle(c
, l
.sx2
, y
, l
.sw2
, std::min(l
.sy2
+ l
.sh2
- y
, l
.sh
));
1426 gdk_cairo_set_source_pixbuf(c
, i
, l
.sx2
- l
.sx1
, y
- l
.sy1
);
1433 if (fader
->hover
or widget
->state
== GTK_STATE_ACTIVE
) {
1434 cairo_rectangle(c
, l
.t1x2
, l
.t1y2
, l
.t1w
, l
.t1h
);
1435 gdk_cairo_set_source_pixbuf(c
, i
, l
.t1x2
- l
.t1x1
, l
.t1y2
- l
.t1y1
);
1437 cairo_rectangle(c
, l
.t2x2
, l
.t2y2
, l
.t2w
, l
.t2h
);
1438 gdk_cairo_set_source_pixbuf(c
, i
, l
.t2x2
- l
.t2x1
, l
.t2y2
- l
.t2y1
);
1444 if (scale
->draw_value
) {
1445 PangoLayout
*layout
;
1447 layout
= gtk_scale_get_layout (scale
);
1448 gtk_scale_get_layout_offsets (scale
, &_x
, &_y
);
1449 gtk_paint_layout (widget
->style
, window
, GTK_STATE_NORMAL
, FALSE
, NULL
,
1450 widget
, horiz
? "hscale" : "vscale", _x
, _y
, layout
);
1459 calf_fader_set_pixbuf (CalfFader
*self
, GdkPixbuf
*image
)
1461 GtkWidget
*widget
= GTK_WIDGET(self
);
1462 self
->image
= image
;
1463 gtk_widget_queue_resize(widget
);
1467 calf_fader_class_init (CalfFaderClass
*klass
)
1469 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1470 widget_class
->expose_event
= calf_fader_expose
;
1474 calf_fader_init (CalfFader
*self
)
1476 GtkWidget
*widget
= GTK_WIDGET(self
);
1477 widget
->requisition
.width
= 40;
1478 widget
->requisition
.height
= 40;
1480 gtk_signal_connect(GTK_OBJECT(widget
), "motion-notify-event", GTK_SIGNAL_FUNC (calf_fader_motion
), NULL
);
1481 gtk_signal_connect(GTK_OBJECT(widget
), "enter-notify-event", GTK_SIGNAL_FUNC (calf_fader_enter
), NULL
);
1482 gtk_signal_connect(GTK_OBJECT(widget
), "leave-notify-event", GTK_SIGNAL_FUNC (calf_fader_leave
), NULL
);
1483 gtk_signal_connect(GTK_OBJECT(widget
), "size-allocate", GTK_SIGNAL_FUNC (calf_fader_allocate
), NULL
);
1484 gtk_signal_connect(GTK_OBJECT(widget
), "size-request", GTK_SIGNAL_FUNC (calf_fader_request
), NULL
);
1488 calf_fader_get_type (void)
1490 static GType type
= 0;
1492 static const GTypeInfo type_info
= {
1493 sizeof(CalfFaderClass
),
1494 NULL
, /* base_init */
1495 NULL
, /* base_finalize */
1496 (GClassInitFunc
)calf_fader_class_init
,
1497 NULL
, /* class_finalize */
1498 NULL
, /* class_data */
1500 0, /* n_preallocs */
1501 (GInstanceInitFunc
)calf_fader_init
1504 for (int i
= 0; ; i
++) {
1505 char *name
= g_strdup_printf("CalfFader%u%d",
1506 ((unsigned int)(intptr_t)calf_fader_class_init
) >> 16, i
);
1507 if (g_type_from_name(name
)) {
1511 type
= g_type_register_static(GTK_TYPE_SCALE
,
1523 ///////////////////////////////////////// button ///////////////////////////////////////////////
1526 calf_button_new(const gchar
*label
)
1528 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_BUTTON
, NULL
));
1529 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1533 calf_button_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1535 g_assert(CALF_IS_BUTTON(widget
) || CALF_IS_TOGGLE_BUTTON(widget
) || CALF_IS_RADIO_BUTTON(widget
));
1537 if (gtk_widget_is_drawable (widget
)) {
1539 GdkWindow
*window
= widget
->window
;
1540 GtkWidget
*child
= GTK_BIN (widget
)->child
;
1541 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
1543 int x
= widget
->allocation
.x
;
1544 int y
= widget
->allocation
.y
;
1545 int sx
= widget
->allocation
.width
;
1546 int sy
= widget
->allocation
.height
;
1547 int ox
= widget
->style
->xthickness
;
1548 int oy
= widget
->style
->ythickness
;
1549 int bx
= x
+ ox
+ 1;
1550 int by
= y
+ oy
+ 1;
1551 int bw
= sx
- 2 * ox
- 2;
1552 int bh
= sy
- 2 * oy
- 2;
1555 float radius
, bevel
, inset
;
1558 cairo_rectangle(c
, x
, y
, sx
, sy
);
1561 get_bg_color(widget
, NULL
, &r
, &g
, &b
);
1562 gtk_widget_style_get(widget
, "border-radius", &radius
, "bevel", &bevel
, "inset", &inset
, NULL
);
1563 gtk_widget_style_get(widget
, "inner-border", &border
, NULL
);
1566 draw_bevel(c
, x
, y
, sx
, sy
, radius
, inset
*-1);
1569 create_rectangle(c
, x
+ ox
, y
+ oy
, sx
- ox
* 2, sy
- oy
* 2, std::max(0.f
, radius
- ox
));
1570 cairo_set_source_rgba(c
, 0, 0, 0, 0.6);
1574 create_rectangle(c
, bx
, by
, bw
, bh
, std::max(0.f
, radius
- ox
- 1));
1575 cairo_set_source_rgb(c
, r
, g
, b
);
1577 draw_bevel(c
, bx
, by
, bw
, bh
, std::max(0.f
, radius
- ox
- 1), bevel
);
1580 if (CALF_IS_TOGGLE_BUTTON(widget
) or CALF_IS_RADIO_BUTTON(widget
)) {
1583 gtk_widget_style_get(widget
, "indicator", &pinh
, NULL
);
1584 get_text_color(widget
, NULL
, &r
, &g
, &b
);
1586 if (widget
->state
== GTK_STATE_PRELIGHT
)
1587 gtk_widget_style_get(widget
, "alpha-prelight", &a
, NULL
);
1588 else if (widget
->state
== GTK_STATE_ACTIVE
)
1589 gtk_widget_style_get(widget
, "alpha-active", &a
, NULL
);
1591 gtk_widget_style_get(widget
, "alpha-normal", &a
, NULL
);
1592 cairo_rectangle(c
, x
+ sx
- border
->right
- ox
+ pinm
, y
+ sy
/ 2 - pinh
/ 2,
1593 border
->right
- pinm
* 2 - ox
, pinh
);
1594 cairo_set_source_rgba(c
, r
, g
, b
, a
);
1599 gtk_container_propagate_expose (GTK_CONTAINER (widget
), child
, event
);
1605 calf_button_class_init (CalfButtonClass
*klass
)
1607 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1608 widget_class
->expose_event
= calf_button_expose
;
1609 gtk_widget_class_install_style_property(
1610 widget_class
, g_param_spec_float("border-radius", "Border Radius", "Generate round edges",
1611 0, 24, 4, GParamFlags(G_PARAM_READWRITE
)));
1612 gtk_widget_class_install_style_property(
1613 widget_class
, g_param_spec_float("bevel", "Bevel", "Bevel the object",
1614 -2, 2, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1615 gtk_widget_class_install_style_property(
1616 widget_class
, g_param_spec_float("alpha-normal", "Alpha Normal", "Alpha of ring in normal state",
1617 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1618 gtk_widget_class_install_style_property(
1619 widget_class
, g_param_spec_float("alpha-prelight", "Alpha Prelight", "Alpha of ring in prelight state",
1620 0.0, 1.0, 1.0, GParamFlags(G_PARAM_READWRITE
)));
1621 gtk_widget_class_install_style_property(
1622 widget_class
, g_param_spec_float("alpha-active", "Alpha Active", "Alpha of ring in active state",
1623 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1624 gtk_widget_class_install_style_property(
1625 widget_class
, g_param_spec_float("inset", "Inset", "Amount of inset effect",
1626 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1630 calf_button_init (CalfButton
*self
)
1632 GtkWidget
*widget
= GTK_WIDGET(self
);
1633 widget
->requisition
.width
= 40;
1634 widget
->requisition
.height
= 20;
1638 calf_button_get_type (void)
1640 static GType type
= 0;
1642 static const GTypeInfo type_info
= {
1643 sizeof(CalfButtonClass
),
1644 NULL
, /* base_init */
1645 NULL
, /* base_finalize */
1646 (GClassInitFunc
)calf_button_class_init
,
1647 NULL
, /* class_finalize */
1648 NULL
, /* class_data */
1650 0, /* n_preallocs */
1651 (GInstanceInitFunc
)calf_button_init
1654 for (int i
= 0; ; i
++) {
1655 //const char *name = "CalfButton";
1656 char *name
= g_strdup_printf("CalfButton%u%d",
1657 ((unsigned int)(intptr_t)calf_button_class_init
) >> 16, i
);
1658 if (g_type_from_name(name
)) {
1662 type
= g_type_register_static(GTK_TYPE_BUTTON
,
1674 ///////////////////////////////////////// toggle button ///////////////////////////////////////////////
1677 calf_toggle_button_new(const gchar
*label
)
1679 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TOGGLE_BUTTON
, NULL
));
1680 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1685 calf_toggle_button_class_init (CalfToggleButtonClass
*klass
)
1687 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1688 widget_class
->expose_event
= calf_button_expose
;
1689 gtk_widget_class_install_style_property(
1690 widget_class
, g_param_spec_float("border-radius", "Border Radius", "Generate round edges",
1691 0, 24, 4, GParamFlags(G_PARAM_READWRITE
)));
1692 gtk_widget_class_install_style_property(
1693 widget_class
, g_param_spec_float("bevel", "Bevel", "Bevel the object",
1694 -2, 2, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1695 gtk_widget_class_install_style_property(
1696 widget_class
, g_param_spec_float("alpha-normal", "Alpha Normal", "Alpha of ring in normal state",
1697 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1698 gtk_widget_class_install_style_property(
1699 widget_class
, g_param_spec_float("alpha-prelight", "Alpha Prelight", "Alpha of ring in prelight state",
1700 0.0, 1.0, 1.0, GParamFlags(G_PARAM_READWRITE
)));
1701 gtk_widget_class_install_style_property(
1702 widget_class
, g_param_spec_float("alpha-active", "Alpha Active", "Alpha of ring in active state",
1703 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1704 gtk_widget_class_install_style_property(
1705 widget_class
, g_param_spec_float("inset", "Inset", "Amount of inset effect",
1706 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1707 gtk_widget_class_install_style_property(
1708 widget_class
, g_param_spec_int("indicator", "Indicator", "Height of indicator",
1709 0, 20, 3, GParamFlags(G_PARAM_READWRITE
)));
1713 calf_toggle_button_init (CalfToggleButton
*self
)
1715 GtkWidget
*widget
= GTK_WIDGET(self
);
1716 widget
->requisition
.width
= 40;
1717 widget
->requisition
.height
= 20;
1721 calf_toggle_button_get_type (void)
1723 static GType type
= 0;
1725 static const GTypeInfo type_info
= {
1726 sizeof(CalfToggleButtonClass
),
1727 NULL
, /* base_init */
1728 NULL
, /* base_finalize */
1729 (GClassInitFunc
)calf_toggle_button_class_init
,
1730 NULL
, /* class_finalize */
1731 NULL
, /* class_data */
1732 sizeof(CalfToggleButton
),
1733 0, /* n_preallocs */
1734 (GInstanceInitFunc
)calf_toggle_button_init
1737 for (int i
= 0; ; i
++) {
1738 //const char *name = "CalfToggleButton";
1739 char *name
= g_strdup_printf("CalfToggleButton%u%d",
1740 ((unsigned int)(intptr_t)calf_toggle_button_class_init
) >> 16, i
);
1741 if (g_type_from_name(name
)) {
1745 type
= g_type_register_static(GTK_TYPE_TOGGLE_BUTTON
,
1756 ///////////////////////////////////////// radio button ///////////////////////////////////////////////
1759 calf_radio_button_new(const gchar
*label
)
1761 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_RADIO_BUTTON
, NULL
));
1762 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1767 calf_radio_button_class_init (CalfRadioButtonClass
*klass
)
1769 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1770 widget_class
->expose_event
= calf_button_expose
;
1771 gtk_widget_class_install_style_property(
1772 widget_class
, g_param_spec_float("border-radius", "Border Radius", "Generate round edges",
1773 0, 24, 4, GParamFlags(G_PARAM_READWRITE
)));
1774 gtk_widget_class_install_style_property(
1775 widget_class
, g_param_spec_float("bevel", "Bevel", "Bevel the object",
1776 -2, 2, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1777 gtk_widget_class_install_style_property(
1778 widget_class
, g_param_spec_float("alpha-normal", "Alpha Normal", "Alpha of ring in normal state",
1779 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1780 gtk_widget_class_install_style_property(
1781 widget_class
, g_param_spec_float("alpha-prelight", "Alpha Prelight", "Alpha of ring in prelight state",
1782 0.0, 1.0, 1.0, GParamFlags(G_PARAM_READWRITE
)));
1783 gtk_widget_class_install_style_property(
1784 widget_class
, g_param_spec_float("alpha-active", "Alpha Active", "Alpha of ring in active state",
1785 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1786 gtk_widget_class_install_style_property(
1787 widget_class
, g_param_spec_float("inset", "Inset", "Amount of inset effect",
1788 0.0, 1.0, 0.2, GParamFlags(G_PARAM_READWRITE
)));
1789 gtk_widget_class_install_style_property(
1790 widget_class
, g_param_spec_int("indicator", "Indicator", "Height of indicator",
1791 0, 20, 3, GParamFlags(G_PARAM_READWRITE
)));
1795 calf_radio_button_init (CalfRadioButton
*self
)
1797 GtkWidget
*widget
= GTK_WIDGET(self
);
1798 widget
->requisition
.width
= 40;
1799 widget
->requisition
.height
= 20;
1803 calf_radio_button_get_type (void)
1805 static GType type
= 0;
1807 static const GTypeInfo type_info
= {
1808 sizeof(CalfRadioButtonClass
),
1809 NULL
, /* base_init */
1810 NULL
, /* base_finalize */
1811 (GClassInitFunc
)calf_radio_button_class_init
,
1812 NULL
, /* class_finalize */
1813 NULL
, /* class_data */
1814 sizeof(CalfRadioButton
),
1815 0, /* n_preallocs */
1816 (GInstanceInitFunc
)calf_radio_button_init
1819 for (int i
= 0; ; i
++) {
1820 //const char *name = "CalfRadioButton";
1821 char *name
= g_strdup_printf("CalfRadioButton%u%d",
1822 ((unsigned int)(intptr_t)calf_radio_button_class_init
) >> 16, i
);
1823 if (g_type_from_name(name
)) {
1827 type
= g_type_register_static(GTK_TYPE_RADIO_BUTTON
,
1838 ///////////////////////////////////////// tap button ///////////////////////////////////////////////
1841 calf_tap_button_new()
1843 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TAP_BUTTON
, NULL
));
1848 calf_tap_button_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1850 g_assert(CALF_IS_TAP_BUTTON(widget
));
1851 CalfTapButton
*self
= CALF_TAP_BUTTON(widget
);
1853 if (!self
->image
[self
->state
])
1856 int width
= gdk_pixbuf_get_width(self
->image
[0]);
1857 int height
= gdk_pixbuf_get_height(self
->image
[0]);
1858 int x
= widget
->allocation
.x
+ widget
->allocation
.width
/ 2 - width
/ 2;
1859 int y
= widget
->allocation
.y
+ widget
->allocation
.height
/ 2 - height
/ 2;
1861 gdk_draw_pixbuf(GDK_DRAWABLE(widget
->window
),
1862 widget
->style
->fg_gc
[0],
1863 self
->image
[self
->state
],
1870 GDK_RGB_DITHER_NORMAL
, 0, 0);
1875 calf_tap_button_set_pixbufs (CalfTapButton
*self
, GdkPixbuf
*image1
, GdkPixbuf
*image2
, GdkPixbuf
*image3
)
1877 GtkWidget
*widget
= GTK_WIDGET(self
);
1878 self
->image
[0] = image1
;
1879 self
->image
[1] = image2
;
1880 self
->image
[2] = image3
;
1881 widget
->requisition
.width
= gdk_pixbuf_get_width(self
->image
[0]);
1882 widget
->requisition
.height
= gdk_pixbuf_get_height(self
->image
[0]);
1883 gtk_widget_queue_resize(widget
);
1887 calf_tap_button_size_request (GtkWidget
*widget
,
1888 GtkRequisition
*requisition
)
1890 g_assert(CALF_IS_TAP_BUTTON(widget
));
1891 requisition
->width
= 70;
1892 requisition
->height
= 70;
1895 calf_tap_button_class_init (CalfTapButtonClass
*klass
)
1897 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1898 widget_class
->expose_event
= calf_tap_button_expose
;
1899 widget_class
->size_request
= calf_tap_button_size_request
;
1902 calf_tap_button_init (CalfTapButton
*self
)
1908 calf_tap_button_get_type (void)
1910 static GType type
= 0;
1912 static const GTypeInfo type_info
= {
1913 sizeof(CalfTapButtonClass
),
1914 NULL
, /* base_init */
1915 NULL
, /* base_finalize */
1916 (GClassInitFunc
)calf_tap_button_class_init
,
1917 NULL
, /* class_finalize */
1918 NULL
, /* class_data */
1919 sizeof(CalfTapButton
),
1920 0, /* n_preallocs */
1921 (GInstanceInitFunc
)calf_tap_button_init
1924 for (int i
= 0; ; i
++) {
1925 char *name
= g_strdup_printf("CalfTapButton%u%d",
1926 ((unsigned int)(intptr_t)calf_tap_button_class_init
) >> 16, i
);
1927 if (g_type_from_name(name
)) {
1931 type
= g_type_register_static(GTK_TYPE_BUTTON
,
1943 ///////////////////////////////////////// tuner ///////////////////////////////////////////////
1945 static void calf_tuner_create_dot(cairo_t
*ctx
, int dots
, int dot
, float rad
)
1948 cairo_rotate(ctx
, dot
* M_PI
/ (dots
* 8) * 2);
1949 cairo_move_to(ctx
, 0, -rad
);
1950 cairo_line_to(ctx
, 0, 0);
1956 calf_tuner_draw_background( GtkWidget
*widget
, cairo_t
*ctx
, int sx
, int sy
, int ox
, int oy
)
1960 int x0
= ox
+ 0.025;
1961 int x1
= ox
+ sx
- 0.025;
1963 int dots
= a
* 0.5 / (dw
+ dm
);
1964 float rad
= sqrt(2.f
) / 2.f
* a
;
1965 int cx
= ox
+ sx
/ 2;
1966 int cy
= ox
+ sy
/ 2;
1967 int ccy
= cy
- sy
/ 3 + rad
;
1969 display_background(widget
, ctx
, 0, 0, sx
, sy
, ox
, oy
);
1973 cairo_rectangle(ctx
, ox
* 2, oy
* 2, sx
- 2 * ox
, sy
- 2 * oy
);
1976 cairo_set_source_rgba(ctx
, 0.35, 0.4, 0.2, 0.3);
1977 cairo_set_line_width(ctx
, dw
);
1978 cairo_translate(ctx
, cx
, ccy
);
1980 for(int i
= 2; i
< dots
+ 2; i
++) {
1981 calf_tuner_create_dot(ctx
, dots
, i
, rad
);
1983 for(int i
= -2; i
> -dots
- 2; i
--) {
1984 calf_tuner_create_dot(ctx
, dots
, i
, rad
);
1986 cairo_set_line_width(ctx
, dw
* 3);
1987 calf_tuner_create_dot(ctx
, dots
, 0, rad
);
1990 static void calf_tuner_draw_dot(cairo_t
* ctx
, float cents
, int sx
, int sy
, int ox
, int oy
)
1992 cairo_rectangle(ctx
, ox
* 2, oy
* 2, sx
- 2 * ox
, sy
- 2 * oy
);
1997 int x0
= ox
+ 0.025;
1998 int x1
= ox
+ sx
- 0.025;
2000 int dots
= a
* 0.5 / (dw
+ dm
);
2001 int dot
= cents
* 2.f
* dots
;
2002 float rad
= sqrt(2.f
) / 2.f
* a
;
2003 int cx
= ox
+ sx
/ 2;
2004 int cy
= ox
+ sy
/ 2;
2005 int ccy
= cy
- sy
/ 3 + rad
;
2007 int sign
= (dot
> 0) - (dot
< 0);
2008 int marg
= dot
? sign
: 0;
2010 cairo_set_source_rgba(ctx
, 0.35, 0.4, 0.2, 0.9);
2011 cairo_translate(ctx
, cx
, ccy
);
2012 cairo_set_line_width(ctx
, dw
* (dot
? 1 : 3));
2013 calf_tuner_create_dot(ctx
, dots
, dot
+ marg
, rad
);
2018 calf_tuner_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
2020 g_assert(CALF_IS_TUNER(widget
));
2021 CalfTuner
*tuner
= CALF_TUNER(widget
);
2023 //printf("%d %f\n", tuner->note, tuner->cents);
2027 int sx
= widget
->allocation
.width
- ox
* 2, sy
= widget
->allocation
.height
- oy
* 2;
2030 float fsize
= fpt
* sy
/ 25; // 9pt @ 25px height
2032 // cairo initialization stuff
2033 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(widget
->window
));
2036 if( tuner
->background
== NULL
) {
2037 // looks like its either first call or the widget has been resized.
2038 // create the background surface (stolen from line graph)...
2039 cairo_surface_t
*window_surface
= cairo_get_target(c
);
2040 tuner
->background
= cairo_surface_create_similar(window_surface
,
2041 CAIRO_CONTENT_COLOR
,
2042 widget
->allocation
.width
,
2043 widget
->allocation
.height
);
2045 // ...and draw some bling bling onto it...
2046 ctx_back
= cairo_create(tuner
->background
);
2047 calf_tuner_draw_background(widget
, ctx_back
, sx
, sy
, ox
, oy
);
2049 ctx_back
= cairo_create(tuner
->background
);
2052 cairo_set_source_surface(c
, cairo_get_target(ctx_back
), 0, 0);
2055 calf_tuner_draw_dot(c
, tuner
->cents
/ 100, sx
, sy
, ox
, oy
);
2057 static const char notenames
[] = "C\0\0C#\0D\0\0D#\0E\0\0F\0\0F#\0G\0\0G#\0A\0\0A#\0B\0\0";
2058 const char * note
= notenames
+ (tuner
->note
% 12) * 3;
2059 int oct
= int(tuner
->note
/ 12) - 2;
2060 cairo_set_source_rgba(c
, 0.35, 0.4, 0.2, 0.9);
2061 cairo_text_extents_t te
;
2064 cairo_select_font_face(c
, "Sans", CAIRO_FONT_SLANT_NORMAL
, CAIRO_FONT_WEIGHT_BOLD
);
2065 cairo_set_font_size(c
, fsize
);
2066 cairo_text_extents (c
, note
, &te
);
2067 cairo_move_to (c
, ox
+ marg
- te
.x_bearing
, oy
+ marg
- te
.y_bearing
);
2068 cairo_show_text (c
, note
);
2071 sprintf(octn
, "%d", oct
);
2072 cairo_set_font_size(c
, fsize
/ 2);
2073 cairo_text_extents (c
, octn
, &te
);
2074 cairo_show_text(c
, octn
);
2076 cairo_set_font_size(c
, fsize
/ 4);
2077 cairo_select_font_face(c
, "Sans", CAIRO_FONT_SLANT_NORMAL
, CAIRO_FONT_WEIGHT_NORMAL
);
2078 const char * mnotet
= "MIDI Note: ";
2080 sprintf(mnotev
, "%d", tuner
->note
);
2081 const char * centst
= "Cents: ";
2083 sprintf(centsv
, "%.4f", tuner
->cents
);
2085 // calc text extents
2086 cairo_text_extents (c
, mnotet
, &te
);
2088 cairo_text_extents (c
, "999", &te
);
2090 cairo_text_extents (c
, centst
, &te
);
2092 cairo_text_extents (c
, "-9.9999", &te
);
2094 float xb
= te
.x_bearing
;
2096 float tw
= std::max(ctw
, mtw
);
2097 float vw
= std::max(cvw
, mvw
);
2100 cairo_move_to(c
, ox
+ sx
- tw
- vw
- marg
* 2, oy
+ marg
- te
.y_bearing
);
2101 cairo_show_text(c
, mnotet
);
2102 cairo_move_to(c
, ox
+ sx
- vw
- xb
- marg
, oy
+ marg
- te
.y_bearing
);
2103 cairo_show_text(c
, mnotev
);
2105 cairo_move_to(c
, ox
+ sx
- tw
- vw
- marg
* 2, oy
+ marg
+ te
.height
+ 5 - te
.y_bearing
);
2106 cairo_show_text(c
, centst
);
2107 cairo_move_to(c
, ox
+ sx
- vw
- xb
- marg
, oy
+ marg
+ te
.height
+ 5 - te
.y_bearing
);
2108 cairo_show_text(c
, centsv
);
2112 cairo_destroy(ctx_back
);
2117 calf_tuner_size_request (GtkWidget
*widget
,
2118 GtkRequisition
*requisition
)
2120 g_assert(CALF_IS_TUNER(widget
));
2121 // CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
2125 calf_tuner_size_allocate (GtkWidget
*widget
,
2126 GtkAllocation
*allocation
)
2128 g_assert(CALF_IS_TUNER(widget
));
2129 CalfTuner
*lg
= CALF_TUNER(widget
);
2132 cairo_surface_destroy(lg
->background
);
2133 lg
->background
= NULL
;
2135 widget
->allocation
= *allocation
;
2139 calf_tuner_class_init (CalfTunerClass
*klass
)
2141 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
2142 widget_class
->expose_event
= calf_tuner_expose
;
2143 widget_class
->size_request
= calf_tuner_size_request
;
2144 widget_class
->size_allocate
= calf_tuner_size_allocate
;
2148 calf_tuner_unrealize (GtkWidget
*widget
, CalfTuner
*tuner
)
2150 if( tuner
->background
)
2151 cairo_surface_destroy(tuner
->background
);
2152 tuner
->background
= NULL
;
2156 calf_tuner_init (CalfTuner
*self
)
2158 GtkWidget
*widget
= GTK_WIDGET(self
);
2159 widget
->requisition
.width
= 40;
2160 widget
->requisition
.height
= 40;
2161 self
->background
= NULL
;
2162 g_signal_connect(GTK_OBJECT(widget
), "unrealize", G_CALLBACK(calf_tuner_unrealize
), (gpointer
)self
);
2168 return GTK_WIDGET(g_object_new (CALF_TYPE_TUNER
, NULL
));
2172 calf_tuner_get_type (void)
2174 static GType type
= 0;
2176 static const GTypeInfo type_info
= {
2177 sizeof(CalfTunerClass
),
2178 NULL
, /* base_init */
2179 NULL
, /* base_finalize */
2180 (GClassInitFunc
)calf_tuner_class_init
,
2181 NULL
, /* class_finalize */
2182 NULL
, /* class_data */
2184 0, /* n_preallocs */
2185 (GInstanceInitFunc
)calf_tuner_init
2188 GTypeInfo
*type_info_copy
= new GTypeInfo(type_info
);
2190 for (int i
= 0; ; i
++) {
2191 char *name
= g_strdup_printf("CalfTuner%u%d", ((unsigned int)(intptr_t)calf_tuner_class_init
) >> 16, i
);
2192 if (g_type_from_name(name
)) {
2196 type
= g_type_register_static( GTK_TYPE_DRAWING_AREA
,