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
22 #include <calf/giface.h>
23 #include <calf/custom_ctl.h>
24 #include <gdk/gdkkeysyms.h>
31 #include <calf/drawingutils.h>
33 using namespace calf_plugins
;
36 ///////////////////////////////////////// phase graph ///////////////////////////////////////////////
39 calf_phase_graph_draw_background(GtkWidget
*widget
, cairo_t
*ctx
, int sx
, int sy
, int ox
, int oy
)
44 display_background(widget
, ctx
, 0, 0, sx
, sy
, ox
, oy
);
45 cairo_set_source_rgb(ctx
, 0.35, 0.4, 0.2);
46 cairo_select_font_face(ctx
, "Sans", CAIRO_FONT_SLANT_NORMAL
, CAIRO_FONT_WEIGHT_NORMAL
);
47 cairo_set_font_size(ctx
, 9);
48 cairo_text_extents_t te
;
50 cairo_text_extents (ctx
, "M", &te
);
51 cairo_move_to (ctx
, cx
+ 5, oy
+ 12);
52 cairo_show_text (ctx
, "M");
54 cairo_text_extents (ctx
, "S", &te
);
55 cairo_move_to (ctx
, ox
+ 5, cy
- 5);
56 cairo_show_text (ctx
, "S");
58 cairo_text_extents (ctx
, "L", &te
);
59 cairo_move_to (ctx
, ox
+ 18, oy
+ 12);
60 cairo_show_text (ctx
, "L");
62 cairo_text_extents (ctx
, "R", &te
);
63 cairo_move_to (ctx
, ox
+ sx
- 22, oy
+ 12);
64 cairo_show_text (ctx
, "R");
66 cairo_set_line_width(ctx
, 1);
68 cairo_move_to(ctx
, ox
, oy
+ sy
* 0.5);
69 cairo_line_to(ctx
, ox
+ sx
, oy
+ sy
* 0.5);
72 cairo_move_to(ctx
, ox
+ sx
* 0.5, oy
);
73 cairo_line_to(ctx
, ox
+ sx
* 0.5, oy
+ sy
);
76 cairo_set_source_rgba(ctx
, 0, 0, 0, 0.2);
77 cairo_move_to(ctx
, ox
, oy
);
78 cairo_line_to(ctx
, ox
+ sx
, oy
+ sy
);
81 cairo_move_to(ctx
, ox
, oy
+ sy
);
82 cairo_line_to(ctx
, ox
+ sx
, oy
);
86 calf_phase_graph_copy_surface(cairo_t
*ctx
, cairo_surface_t
*source
, float fade
= 1.f
)
88 // copy a surface to a cairo context
90 cairo_set_source_surface(ctx
, source
, 0, 0);
92 float rnd
= (float)rand() / (float)RAND_MAX
/ 100;
93 cairo_paint_with_alpha(ctx
, fade
* 0.35 + 0.05 + rnd
);
100 calf_phase_graph_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
102 g_assert(CALF_IS_PHASE_GRAPH(widget
));
103 CalfPhaseGraph
*pg
= CALF_PHASE_GRAPH(widget
);
109 int sx
= widget
->allocation
.width
- ox
* 2, sy
= widget
->allocation
.height
- oy
* 2;
113 int cx
= ox
+ sx
/ 2;
114 int cy
= oy
+ sy
/ 2;
116 // some values as pointers for the audio plug-in call
117 float * phase_buffer
= 0;
121 bool use_fade
= true;
125 // cairo initialization stuff
126 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(widget
->window
));
130 if( pg
->background
== NULL
) {
131 // looks like its either first call or the widget has been resized.
132 // create the background surface (stolen from line graph)...
133 cairo_surface_t
*window_surface
= cairo_get_target(c
);
134 pg
->background
= cairo_surface_create_similar(window_surface
,
136 widget
->allocation
.width
,
137 widget
->allocation
.height
);
138 pg
->cache
= cairo_surface_create_similar(window_surface
,
140 widget
->allocation
.width
,
141 widget
->allocation
.height
);
143 // ...and draw some bling bling onto it...
144 ctx_back
= cairo_create(pg
->background
);
145 calf_phase_graph_draw_background(widget
, ctx_back
, sx
, sy
, ox
, oy
);
146 // ...and copy it to the cache
147 ctx_cache
= cairo_create(pg
->cache
);
148 calf_phase_graph_copy_surface(ctx_cache
, pg
->background
, 1);
150 ctx_back
= cairo_create(pg
->background
);
151 ctx_cache
= cairo_create(pg
->cache
);
154 pg
->source
->get_phase_graph(&phase_buffer
, &length
, &mode
, &use_fade
,
155 &fade
, &accuracy
, &display
);
157 // process some values set by the plug-in
159 accuracy
= 12 - accuracy
;
161 calf_phase_graph_copy_surface(ctx_cache
, pg
->background
, use_fade
? fade
: 1);
164 cairo_rectangle(ctx_cache
, ox
, oy
, sx
, sy
);
165 cairo_clip(ctx_cache
);
166 cairo_set_source_rgba(ctx_cache
, 0.35, 0.4, 0.2, 1);
168 for(int i
= 0; i
< length
; i
+= accuracy
) {
169 float l
= phase_buffer
[i
];
170 float r
= phase_buffer
[i
+ 1];
171 if(l
== 0.f
and r
== 0.f
) continue;
172 else if(r
== 0.f
and l
> 0.f
) _a
= M_PI
/ 2.f
;
173 else if(r
== 0.f
and l
< 0.f
) _a
= 3.f
*M_PI
/ 2.f
;
174 else _a
= pg
->_atan(l
/ r
, l
, r
);
175 double _R
= sqrt(pow(l
, 2) + pow(r
, 2));
177 float x
= (-1.f
)*_R
* cos(_a
);
178 float y
= _R
* sin(_a
);
179 // mask the cached values
183 cairo_rectangle (ctx_cache
, x
* rad
+ cx
, y
* rad
+ cy
, 1, 1);
187 cairo_rectangle (ctx_cache
, x
* rad
+ cx
- 0.25, y
* rad
+ cy
- 0.25, 1.5, 1.5);
191 cairo_rectangle (ctx_cache
, x
* rad
+ cx
- 0.5, y
* rad
+ cy
- 0.5, 2, 2);
195 if(i
== 0) cairo_move_to(ctx_cache
,
196 x
* rad
+ cx
, y
* rad
+ cy
);
197 else cairo_line_to(ctx_cache
,
198 x
* rad
+ cx
, y
* rad
+ cy
);
202 if(i
== 0) cairo_move_to(ctx_cache
,
203 x
* rad
+ cx
, y
* rad
+ cy
);
204 else cairo_line_to(ctx_cache
,
205 x
* rad
+ cx
, y
* rad
+ cy
);
214 cairo_fill(ctx_cache
);
217 cairo_fill(ctx_cache
);
220 cairo_set_line_width(ctx_cache
, 0.5);
221 cairo_stroke(ctx_cache
);
226 calf_phase_graph_copy_surface(c
, pg
->cache
, 1);
229 cairo_destroy(ctx_back
);
230 cairo_destroy(ctx_cache
);
231 // printf("exposed %p %dx%d %d+%d\n", widget->window, event->area.x, event->area.y, event->area.width, event->area.height);
236 calf_phase_graph_size_request (GtkWidget
*widget
,
237 GtkRequisition
*requisition
)
239 g_assert(CALF_IS_PHASE_GRAPH(widget
));
240 // CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
244 calf_phase_graph_size_allocate (GtkWidget
*widget
,
245 GtkAllocation
*allocation
)
247 g_assert(CALF_IS_PHASE_GRAPH(widget
));
248 CalfPhaseGraph
*lg
= CALF_PHASE_GRAPH(widget
);
250 GtkWidgetClass
*parent_class
= (GtkWidgetClass
*) g_type_class_peek_parent( CALF_PHASE_GRAPH_GET_CLASS( lg
) );
253 cairo_surface_destroy(lg
->background
);
254 lg
->background
= NULL
;
256 widget
->allocation
= *allocation
;
257 GtkAllocation
&a
= widget
->allocation
;
258 if (a
.width
> a
.height
) {
259 a
.x
+= (a
.width
- a
.height
) / 2;
262 if (a
.width
< a
.height
) {
263 a
.y
+= (a
.height
- a
.width
) / 2;
266 parent_class
->size_allocate(widget
, &a
);
270 calf_phase_graph_class_init (CalfPhaseGraphClass
*klass
)
272 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
273 widget_class
->expose_event
= calf_phase_graph_expose
;
274 widget_class
->size_request
= calf_phase_graph_size_request
;
275 widget_class
->size_allocate
= calf_phase_graph_size_allocate
;
279 calf_phase_graph_unrealize (GtkWidget
*widget
, CalfPhaseGraph
*pg
)
282 cairo_surface_destroy(pg
->background
);
283 pg
->background
= NULL
;
287 calf_phase_graph_init (CalfPhaseGraph
*self
)
289 GtkWidget
*widget
= GTK_WIDGET(self
);
290 widget
->requisition
.width
= 40;
291 widget
->requisition
.height
= 40;
292 self
->background
= NULL
;
293 g_signal_connect(GTK_OBJECT(widget
), "unrealize", G_CALLBACK(calf_phase_graph_unrealize
), (gpointer
)self
);
297 calf_phase_graph_new()
299 return GTK_WIDGET(g_object_new (CALF_TYPE_PHASE_GRAPH
, NULL
));
303 calf_phase_graph_get_type (void)
305 static GType type
= 0;
307 static const GTypeInfo type_info
= {
308 sizeof(CalfPhaseGraphClass
),
309 NULL
, /* base_init */
310 NULL
, /* base_finalize */
311 (GClassInitFunc
)calf_phase_graph_class_init
,
312 NULL
, /* class_finalize */
313 NULL
, /* class_data */
314 sizeof(CalfPhaseGraph
),
316 (GInstanceInitFunc
)calf_phase_graph_init
319 GTypeInfo
*type_info_copy
= new GTypeInfo(type_info
);
321 for (int i
= 0; ; i
++) {
322 char *name
= g_strdup_printf("CalfPhaseGraph%u%d", ((unsigned int)(intptr_t)calf_phase_graph_class_init
) >> 16, i
);
323 if (g_type_from_name(name
)) {
327 type
= g_type_register_static( GTK_TYPE_DRAWING_AREA
,
339 ///////////////////////////////////////// toggle ///////////////////////////////////////////////
342 calf_toggle_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
344 g_assert(CALF_IS_TOGGLE(widget
));
346 CalfToggle
*self
= CALF_TOGGLE(widget
);
348 float sx
= self
->size
? self
->size
: 1.f
/ 3.f
* 2.f
;
349 float sy
= self
->size
? self
->size
: 1;
350 int x
= widget
->allocation
.x
+ widget
->allocation
.width
/ 2 - sx
* 15 - sx
* 2;
351 int y
= widget
->allocation
.y
+ widget
->allocation
.height
/ 2 - sy
* 10 - sy
* 3;
353 int height
= sy
* 26;
355 gdk_draw_pixbuf(GDK_DRAWABLE(widget
->window
),
356 widget
->style
->fg_gc
[0],
357 self
->toggle_image
[self
->size
],
359 20 - sy
* 3 + (sy
* 20 + 40) * floor(.5 + gtk_range_get_value(GTK_RANGE(widget
))),
364 GDK_RGB_DITHER_NORMAL
, 0, 0);
369 calf_toggle_size_request (GtkWidget
*widget
,
370 GtkRequisition
*requisition
)
372 g_assert(CALF_IS_TOGGLE(widget
));
374 CalfToggle
*self
= CALF_TOGGLE(widget
);
376 float sx
= self
->size
? self
->size
: 1.f
/ 3.f
* 2.f
;
377 float sy
= self
->size
? self
->size
: 1;
379 requisition
->width
= 30 * sx
;
380 requisition
->height
= 20 * sy
;
384 calf_toggle_button_press (GtkWidget
*widget
, GdkEventButton
*event
)
386 g_assert(CALF_IS_TOGGLE(widget
));
387 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(widget
));
388 if (gtk_range_get_value(GTK_RANGE(widget
)) == adj
->lower
)
390 gtk_range_set_value(GTK_RANGE(widget
), adj
->upper
);
392 gtk_range_set_value(GTK_RANGE(widget
), adj
->lower
);
398 calf_toggle_key_press (GtkWidget
*widget
, GdkEventKey
*event
)
400 switch(event
->keyval
)
405 return calf_toggle_button_press(widget
, NULL
);
411 calf_toggle_class_init (CalfToggleClass
*klass
)
413 // GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
414 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
415 widget_class
->expose_event
= calf_toggle_expose
;
416 widget_class
->size_request
= calf_toggle_size_request
;
417 widget_class
->button_press_event
= calf_toggle_button_press
;
418 widget_class
->key_press_event
= calf_toggle_key_press
;
422 calf_toggle_init (CalfToggle
*self
)
424 GtkWidget
*widget
= GTK_WIDGET(self
);
425 GTK_WIDGET_SET_FLAGS (GTK_WIDGET(self
), GTK_CAN_FOCUS
);
426 widget
->requisition
.width
= 30;
427 widget
->requisition
.height
= 20;
429 GError
*error
= NULL
;
430 self
->toggle_image
[0] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/toggle0_silver.png", &error
);
431 self
->toggle_image
[1] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/toggle1_silver.png", &error
);
432 self
->toggle_image
[2] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/toggle2_silver.png", &error
);
433 g_assert(self
->toggle_image
!= NULL
);
439 GtkAdjustment
*adj
= (GtkAdjustment
*)gtk_adjustment_new(0, 0, 1, 1, 0, 0);
440 return calf_toggle_new_with_adjustment(adj
);
443 static gboolean
calf_toggle_value_changed(gpointer obj
)
445 GtkWidget
*widget
= (GtkWidget
*)obj
;
446 CalfToggle
*self
= CALF_TOGGLE(widget
);
447 float sx
= self
->size
? self
->size
: 1.f
/ 3.f
* 2.f
;
448 float sy
= self
->size
? self
->size
: 1;
449 gtk_widget_queue_draw_area(widget
,
450 widget
->allocation
.x
- sx
* 2,
451 widget
->allocation
.y
- sy
* 3,
457 GtkWidget
*calf_toggle_new_with_adjustment(GtkAdjustment
*_adjustment
)
459 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TOGGLE
, NULL
));
461 gtk_range_set_adjustment(GTK_RANGE(widget
), _adjustment
);
462 g_signal_connect(GTK_OBJECT(widget
), "value-changed", G_CALLBACK(calf_toggle_value_changed
), widget
);
468 calf_toggle_get_type (void)
470 static GType type
= 0;
473 static const GTypeInfo type_info
= {
474 sizeof(CalfToggleClass
),
475 NULL
, /* base_init */
476 NULL
, /* base_finalize */
477 (GClassInitFunc
)calf_toggle_class_init
,
478 NULL
, /* class_finalize */
479 NULL
, /* class_data */
482 (GInstanceInitFunc
)calf_toggle_init
485 for (int i
= 0; ; i
++) {
486 char *name
= g_strdup_printf("CalfToggle%u%d",
487 ((unsigned int)(intptr_t)calf_toggle_class_init
) >> 16, i
);
488 if (g_type_from_name(name
)) {
492 type
= g_type_register_static( GTK_TYPE_RANGE
,
503 ///////////////////////////////////////// frame ///////////////////////////////////////////////
507 calf_frame_new(const char *label
)
509 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_FRAME
, NULL
));
510 CalfFrame
*self
= CALF_FRAME(widget
);
511 gtk_frame_set_label(GTK_FRAME(self
), label
);
515 calf_frame_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
517 g_assert(CALF_IS_FRAME(widget
));
518 if (gtk_widget_is_drawable (widget
)) {
520 GdkWindow
*window
= widget
->window
;
521 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
522 cairo_text_extents_t extents
;
524 int ox
= widget
->allocation
.x
;
525 int oy
= widget
->allocation
.y
;
526 int sx
= widget
->allocation
.width
;
527 int sy
= widget
->allocation
.height
;
538 cairo_rectangle(c
, ox
, oy
, sx
, sy
);
542 const gchar
*lab
= gtk_frame_get_label(GTK_FRAME(widget
));
544 cairo_select_font_face(c
, "Sans",
545 CAIRO_FONT_SLANT_NORMAL
,
546 CAIRO_FONT_WEIGHT_NORMAL
);
547 cairo_set_font_size(c
, size
);
549 cairo_text_extents(c
, lab
, &extents
);
551 double lw
= extents
.width
+ txp
* 2.;
553 cairo_set_line_width(c
, 1.);
555 cairo_move_to(c
, ox
+ rad
+ txp
+ m
, oy
+ size
- 2 + m
);
556 get_text_color(widget
, NULL
, &r
, &g
, &b
);
557 cairo_set_source_rgb(c
, r
, g
, b
);
558 cairo_show_text(c
, lab
);
559 get_fg_color(widget
, NULL
, &r
, &g
, &b
);
560 cairo_set_source_rgb(c
, r
, g
, b
);
563 cairo_move_to(c
, ox
+ a
+ m
, oy
+ pad
+ rad
+ a
+ m
);
564 cairo_arc (c
, ox
+ rad
+ a
+ m
, oy
+ rad
+ a
+ pad
+ m
, rad
, 1 * M_PI
, 1.5 * M_PI
);
565 cairo_move_to(c
, ox
+ rad
+ a
+ lw
+ m
, oy
+ a
+ pad
+ m
);
566 cairo_line_to(c
, ox
+ sx
+ a
- rad
- m
- 1, oy
+ a
+ pad
+ m
);
567 cairo_arc (c
, ox
+ sx
- rad
+ a
- 2*m
- 1, oy
+ rad
+ a
+ pad
+ m
, rad
, 1.5 * M_PI
, 2 * M_PI
);
568 cairo_line_to(c
, ox
+ sx
+ a
- 2*m
- 1, oy
+ a
+ sy
- rad
- 2*m
- 1);
570 cairo_arc (c
, ox
+ sx
- rad
+ a
- 2*m
- 1, oy
+ sy
- rad
+ a
- 2*m
- 1, rad
, 0 * M_PI
, 0.5 * M_PI
);
572 cairo_line_to(c
, ox
+ a
+ rad
+ m
, oy
+ sy
+ a
- 2*m
- 1);
573 cairo_arc (c
, ox
+ rad
+ a
+ m
, oy
+ sy
- rad
+ a
- 2*m
- 1, rad
, 0.5 * M_PI
, 1 * M_PI
);
574 cairo_line_to(c
, ox
+ a
+ m
, oy
+ a
+ rad
+ pad
+ m
);
579 //cairo_set_source_rgb(c, 0.66,0.66,0.66);
582 //cairo_move_to(c, ox + a + m, oy + pad + rad + a + m);
583 //cairo_arc (c, ox + rad + a + m, oy + rad + a + pad + m, rad, 1 * M_PI, 1.5 * M_PI);
584 //cairo_move_to(c, ox + rad + a + lw + m, oy + a + pad + m);
586 //cairo_line_to(c, ox + sx + a - rad - m, oy + a + pad + m);
587 //cairo_arc (c, ox + sx - rad + a - 2*m - 1, oy + rad + a + pad + m, rad, 1.5 * M_PI, 2 * M_PI);
588 //cairo_line_to(c, ox + sx + a - 2*m - 1, oy + a + sy - rad - 2*m);
589 //cairo_arc (c, ox + sx - rad + a - 2*m - 1, oy + sy - rad + a - 2*m - 1, rad, 0 * M_PI, 0.5 * M_PI);
590 //cairo_line_to(c, ox + a + rad + m, oy + sy + a - 2*m - 1);
591 //cairo_arc (c, ox + rad + a + m, oy + sy - rad + a - 2*m - 1, rad, 0.5 * M_PI, 1 * M_PI);
592 //cairo_line_to(c, ox + a + m, oy + a + rad + pad + m);
597 if (gtk_bin_get_child(GTK_BIN(widget
))) {
598 gtk_container_propagate_expose(GTK_CONTAINER(widget
),
599 gtk_bin_get_child(GTK_BIN(widget
)),
606 calf_frame_class_init (CalfFrameClass
*klass
)
608 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
609 widget_class
->expose_event
= calf_frame_expose
;
613 calf_frame_init (CalfFrame
*self
)
615 GtkWidget
*widget
= GTK_WIDGET(self
);
616 widget
->requisition
.width
= 40;
617 widget
->requisition
.height
= 40;
621 calf_frame_get_type (void)
623 static GType type
= 0;
625 static const GTypeInfo type_info
= {
626 sizeof(CalfFrameClass
),
627 NULL
, /* base_init */
628 NULL
, /* base_finalize */
629 (GClassInitFunc
)calf_frame_class_init
,
630 NULL
, /* class_finalize */
631 NULL
, /* class_data */
634 (GInstanceInitFunc
)calf_frame_init
637 for (int i
= 0; ; i
++) {
638 char *name
= g_strdup_printf("CalfFrame%u%d",
639 ((unsigned int)(intptr_t)calf_frame_class_init
) >> 16, i
);
640 if (g_type_from_name(name
)) {
644 type
= g_type_register_static(GTK_TYPE_FRAME
,
655 ///////////////////////////////////////// combo box ///////////////////////////////////////////////
661 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_COMBOBOX
, NULL
));
662 GtkCellRenderer
*column
= gtk_cell_renderer_text_new();
663 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget
), column
, TRUE
);
664 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(widget
), column
,
670 calf_combobox_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
672 g_assert(CALF_IS_COMBOBOX(widget
));
674 if (gtk_widget_is_drawable (widget
)) {
680 GtkTreeModel
*model
= gtk_combo_box_get_model(GTK_COMBO_BOX (widget
));
683 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget
), &iter
))
684 gtk_tree_model_get (model
, &iter
, 0, &lab
, -1);
688 GdkWindow
*window
= widget
->window
;
689 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
691 int x
= widget
->allocation
.x
;
692 int y
= widget
->allocation
.y
;
693 int sx
= widget
->allocation
.width
;
694 int sy
= widget
->allocation
.height
;
698 create_rectangle(c
, x
, y
, sx
, sy
, 8);
701 gtk_widget_get_pointer(GTK_WIDGET(widget
), &mx
, &my
);
702 if (mx
>= 0 and mx
< sx
and my
>= 0 and my
< sy
)
705 display_background(widget
, c
, x
, y
, sx
- padx
* 2, sy
- pady
* 2, padx
, pady
, g_ascii_isspace(lab
[0]) ? 0 : 1, 4, hover
? 0.5 : 0, hover
? 0.1 : 0.25);
707 cairo_select_font_face(c
, "Sans",
708 CAIRO_FONT_SLANT_NORMAL
,
709 CAIRO_FONT_WEIGHT_NORMAL
);
710 cairo_set_font_size(c
, 12);
712 cairo_move_to(c
, x
+ padx
+ 3, y
+ sy
/ 2 + 5);
714 get_fg_color(widget
, NULL
, &r
, &g
, &b
);
715 cairo_set_source_rgb(c
, r
, g
, b
);
716 cairo_show_text(c
, lab
);
719 cairo_surface_t
*image
;
720 image
= cairo_image_surface_create_from_png(PKGLIBDIR
"combo_arrow.png");
721 cairo_set_source_surface(c
, image
, x
+ sx
- 20, y
+ sy
/ 2 - 5);
722 cairo_rectangle(c
, x
, y
, sx
, sy
);
731 calf_combobox_class_init (CalfComboboxClass
*klass
)
733 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
734 widget_class
->expose_event
= calf_combobox_expose
;
738 calf_combobox_init (CalfCombobox
*self
)
740 GtkWidget
*widget
= GTK_WIDGET(self
);
741 widget
->requisition
.width
= 40;
742 widget
->requisition
.height
= 20;
746 calf_combobox_get_type (void)
748 static GType type
= 0;
750 static const GTypeInfo type_info
= {
751 sizeof(CalfComboboxClass
),
752 NULL
, /* base_init */
753 NULL
, /* base_finalize */
754 (GClassInitFunc
)calf_combobox_class_init
,
755 NULL
, /* class_finalize */
756 NULL
, /* class_data */
757 sizeof(CalfCombobox
),
759 (GInstanceInitFunc
)calf_combobox_init
762 for (int i
= 0; ; i
++) {
763 char *name
= g_strdup_printf("CalfCombobox%u%d",
764 ((unsigned int)(intptr_t)calf_combobox_class_init
) >> 16, i
);
765 if (g_type_from_name(name
)) {
769 type
= g_type_register_static(GTK_TYPE_COMBO_BOX
,
781 ///////////////////////////////////////// notebook ///////////////////////////////////////////////
783 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
784 struct _GtkNotebookPage
787 GtkWidget
*tab_label
;
788 GtkWidget
*menu_label
;
789 GtkWidget
*last_focus_child
; /* Last descendant of the page that had focus */
791 guint default_menu
: 1; /* If true, we create the menu label ourself */
792 guint default_tab
: 1; /* If true, we create the tab label ourself */
796 guint reorderable
: 1;
797 guint detachable
: 1;
799 /* if true, the tab label was visible on last allocation; we track this so
800 * that we know to redraw the tab area if a tab label was hidden then shown
801 * without changing position */
802 guint tab_allocated_visible
: 1;
804 GtkRequisition requisition
;
805 GtkAllocation allocation
;
807 gulong mnemonic_activate_signal
;
808 gulong notify_visible_handler
;
814 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_NOTEBOOK
, NULL
));
818 calf_notebook_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
820 g_assert(CALF_IS_NOTEBOOK(widget
));
822 GtkNotebook
*notebook
;
823 notebook
= GTK_NOTEBOOK (widget
);
824 CalfNotebookClass
*klass
= CALF_NOTEBOOK_CLASS(GTK_OBJECT_GET_CLASS(widget
));
826 if (gtk_widget_is_drawable (widget
)) {
828 GdkWindow
*window
= widget
->window
;
829 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
830 cairo_pattern_t
*pat
= NULL
;
832 int x
= widget
->allocation
.x
;
833 int y
= widget
->allocation
.y
;
834 int sx
= widget
->allocation
.width
;
835 int sy
= widget
->allocation
.height
;
836 int tx
= widget
->style
->xthickness
;
837 int ty
= widget
->style
->ythickness
;
839 int bh
= lh
+ 2 * ty
;
841 cairo_rectangle(c
, x
, y
, sx
, sy
);
846 if (notebook
->show_tabs
) {
847 GtkNotebookPage
*page
;
851 gtk_widget_style_get(widget
, "tab-overlap", &sp
, NULL
);
853 pages
= notebook
->children
;
857 page
= GTK_NOTEBOOK_PAGE (pages
);
859 if (page
->tab_label
->window
== event
->window
&&
860 gtk_widget_is_drawable (page
->tab_label
)) {
861 int lx
= page
->tab_label
->allocation
.x
;
862 int lw
= page
->tab_label
->allocation
.width
;
864 // fix the labels position
865 page
->tab_label
->allocation
.y
= y
+ ty
;
866 page
->tab_label
->allocation
.height
= lh
;
868 // draw tab background
869 cairo_rectangle(c
, lx
- tx
, y
, lw
+ 2 * tx
, bh
);
870 cairo_set_source_rgba(c
, 0,0,0, page
!= notebook
->cur_page
? 0.25 : 0.5);
873 if (page
== notebook
->cur_page
) {
875 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 2, lw
+ 2 * tx
- 4, 2);
876 pat
= cairo_pattern_create_radial(lx
+ lw
/ 2, y
+ bh
/ 2, 1, lx
+ lw
/ 2, y
+ bh
/ 2, lw
+ tx
* 2);
877 cairo_pattern_add_color_stop_rgb(pat
, 0, 50. / 255, 1, 1);
878 cairo_pattern_add_color_stop_rgb(pat
, 0.3, 2. / 255, 180. / 255, 1);
879 cairo_pattern_add_color_stop_rgb(pat
, 0.5, 19. / 255, 220. / 255, 1);
880 cairo_pattern_add_color_stop_rgb(pat
, 1, 2. / 255, 120. / 255, 1);
881 cairo_set_source(c
, pat
);
884 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 1, lw
+ 2 * tx
- 4, 1);
885 cairo_set_source_rgba(c
, 0,0,0,0.5);
888 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 4, lw
+ 2 * tx
- 4, 1);
889 cairo_set_source_rgba(c
, 1,1,1,0.3);
894 gtk_container_propagate_expose (GTK_CONTAINER (notebook
), page
->tab_label
, event
);
902 cairo_rectangle(c
, x
, y
+ add
, sx
, sy
- add
);
903 cairo_set_source_rgba(c
, 0,0,0,0.5);
907 cairo_rectangle(c
, x
+ 0.5, y
+ add
+ 0.5, sx
- 1, sy
- add
- 1);
908 pat
= cairo_pattern_create_linear(x
, y
+ add
, x
, y
+ sy
- add
);
909 cairo_pattern_add_color_stop_rgba(pat
, 0, 0, 0, 0, 0.3);
910 cairo_pattern_add_color_stop_rgba(pat
, 0.5, 0.5, 0.5, 0.5, 0);
911 cairo_pattern_add_color_stop_rgba(pat
, 1, 1, 1, 1, 0.2);
912 cairo_set_source (c
, pat
);
913 cairo_set_line_width(c
, 1);
914 cairo_stroke_preserve(c
);
916 int sw
= gdk_pixbuf_get_width(klass
->screw
);
917 int sh
= gdk_pixbuf_get_height(klass
->screw
);
920 gdk_cairo_set_source_pixbuf(c
, klass
->screw
, x
, y
+ add
);
921 cairo_fill_preserve(c
);
922 gdk_cairo_set_source_pixbuf(c
, klass
->screw
, x
+ sx
- sw
, y
+ add
);
923 cairo_fill_preserve(c
);
924 gdk_cairo_set_source_pixbuf(c
, klass
->screw
, x
, y
+ sy
- sh
);
925 cairo_fill_preserve(c
);
926 gdk_cairo_set_source_pixbuf(c
, klass
->screw
, x
+ sx
- sh
, y
+ sy
- sh
);
927 cairo_fill_preserve(c
);
929 // propagate expose to all children
930 if (notebook
->cur_page
)
931 gtk_container_propagate_expose (GTK_CONTAINER (notebook
),
932 notebook
->cur_page
->child
,
935 cairo_pattern_destroy(pat
);
943 calf_notebook_class_init (CalfNotebookClass
*klass
)
945 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
946 widget_class
->expose_event
= calf_notebook_expose
;
948 klass
->screw
= gdk_pixbuf_new_from_file (PKGLIBDIR
"screw_black.png", 0);
952 calf_notebook_init (CalfNotebook
*self
)
954 //GtkWidget *widget = GTK_WIDGET(self);
958 calf_notebook_get_type (void)
960 static GType type
= 0;
962 static const GTypeInfo type_info
= {
963 sizeof(CalfNotebookClass
),
964 NULL
, /* base_init */
965 NULL
, /* base_finalize */
966 (GClassInitFunc
)calf_notebook_class_init
,
967 NULL
, /* class_finalize */
968 NULL
, /* class_data */
969 sizeof(CalfNotebook
),
971 (GInstanceInitFunc
)calf_notebook_init
974 for (int i
= 0; ; i
++) {
975 char *name
= g_strdup_printf("CalfNotebook%u%d",
976 ((unsigned int)(intptr_t)calf_notebook_class_init
) >> 16, i
);
977 if (g_type_from_name(name
)) {
981 type
= g_type_register_static(GTK_TYPE_NOTEBOOK
,
992 ///////////////////////////////////////// fader ///////////////////////////////////////////////
994 static void calf_fader_set_layout(GtkWidget
*widget
)
996 GtkRange
*range
= GTK_RANGE(widget
);
997 CalfFader
*fader
= CALF_FADER(widget
);
998 CalfFaderLayout layout
= fader
->layout
;
1000 int hor
= fader
->horizontal
;
1003 layout
.x
= widget
->allocation
.x
;
1004 layout
.y
= widget
->allocation
.y
;
1005 layout
.w
= widget
->allocation
.width
;
1006 layout
.h
= widget
->allocation
.height
;
1009 layout
.tx
= range
->range_rect
.x
+ layout
.x
;
1010 layout
.ty
= range
->range_rect
.y
+ layout
.y
;
1011 layout
.tw
= range
->range_rect
.width
;
1012 layout
.th
= range
->range_rect
.height
;
1013 layout
.tc
= hor
? layout
.ty
+ layout
.th
/ 2 : layout
.tx
+ layout
.tw
/ 2;
1016 layout
.scw
= gdk_pixbuf_get_width(fader
->screw
);
1017 layout
.sch
= gdk_pixbuf_get_height(fader
->screw
);
1018 layout
.scx1
= hor
? layout
.tx
: layout
.tc
- layout
.scw
/ 2;
1019 layout
.scy1
= hor
? layout
.tc
- layout
.sch
/ 2 : layout
.ty
;
1020 layout
.scx2
= hor
? layout
.tx
+ layout
.tw
- layout
.scw
: layout
.tc
- layout
.scw
/ 2;
1021 layout
.scy2
= hor
? layout
.tc
- layout
.sch
/ 2 : layout
.ty
+ layout
.th
- layout
.sch
;
1024 layout
.sw
= hor
? layout
.tw
- layout
.scw
* 2 - 2: 2;
1025 layout
.sh
= hor
? 2 : layout
.th
- layout
.sch
* 2 - 2;
1026 layout
.sx
= hor
? layout
.tx
+ layout
.scw
+ 1 : layout
.tc
- 1;
1027 layout
.sy
= hor
? layout
.tc
- 1 : layout
.ty
+ layout
.sch
+ 1;
1030 layout
.slw
= gdk_pixbuf_get_width(fader
->slider
);
1031 layout
.slh
= gdk_pixbuf_get_height(fader
->slider
);
1032 layout
.slx
= fader
->horizontal
? 0 : layout
.tc
- layout
.slw
/ 2;
1033 layout
.sly
= fader
->horizontal
? layout
.tc
- layout
.slh
/ 2 : 0;
1035 //printf("widg %d %d %d %d | trgh %d %d %d %d %d | slid %d %d %d %d | slit %d %d %d %d\n",
1036 //layout.x, layout.y, layout.w, layout.h,
1037 //layout.tx, layout.ty, layout.tw, layout.th, layout.tc,
1038 //layout.slx, layout.sly, layout.slw, layout.slh,
1039 //layout.sx, layout.sy, layout.sw, layout.sh);
1041 fader
->layout
= layout
;
1045 calf_fader_new(const int horiz
= 0, const int size
= 2, const double min
= 0, const double max
= 1, const double step
= 0.1)
1050 adj
= gtk_adjustment_new (min
, min
, max
, step
, 10 * step
, 0);
1052 if (fabs (step
) >= 1.0 || step
== 0.0)
1055 digits
= std::min(5, abs((gint
) floor (log10 (fabs (step
)))));
1057 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_FADER
, NULL
));
1058 CalfFader
*self
= CALF_FADER(widget
);
1060 GTK_RANGE(widget
)->orientation
= horiz
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
;
1061 gtk_range_set_adjustment(GTK_RANGE(widget
), GTK_ADJUSTMENT(adj
));
1062 gtk_scale_set_digits(GTK_SCALE(widget
), digits
);
1065 self
->horizontal
= horiz
;
1068 gchar
* file
= g_strdup_printf("%sslider%d-%s.png", PKGLIBDIR
, size
, horiz
? "horiz" : "vert");
1069 self
->slider
= gdk_pixbuf_new_from_file (file
, 0);
1070 file
= g_strdup_printf("%sslider%d-%s-prelight.png", PKGLIBDIR
, size
, horiz
? "horiz" : "vert");
1071 self
->sliderpre
= gdk_pixbuf_new_from_file(file
, 0);
1073 self
->screw
= gdk_pixbuf_new_from_file (PKGLIBDIR
"screw_silver.png", 0);
1078 static bool calf_fader_hover(GtkWidget
*widget
)
1080 CalfFader
*fader
= CALF_FADER(widget
);
1081 CalfFaderLayout layout
= fader
->layout
;
1083 gtk_widget_get_pointer(GTK_WIDGET(widget
), &mx
, &my
);
1085 if ((fader
->horizontal
and mx
+ layout
.x
>= layout
.tx
1086 and mx
+ layout
.x
< layout
.tx
+ layout
.tw
1087 and my
+ layout
.y
>= layout
.sly
1088 and my
+ layout
.y
< layout
.sly
+ layout
.slh
)
1089 or (!fader
->horizontal
and mx
+ layout
.x
>= layout
.slx
1090 and mx
+ layout
.x
< layout
.slx
+ layout
.slw
1091 and my
+ layout
.y
>= layout
.ty
1092 and my
+ layout
.y
< layout
.ty
+ layout
.th
))
1096 static void calf_fader_check_hover_change(GtkWidget
*widget
)
1098 CalfFader
*fader
= CALF_FADER(widget
);
1099 bool hover
= calf_fader_hover(widget
);
1100 if (hover
!= fader
->hover
)
1101 gtk_widget_queue_draw(widget
);
1102 fader
->hover
= hover
;
1105 calf_fader_motion (GtkWidget
*widget
, GdkEventMotion
*event
)
1107 calf_fader_check_hover_change(widget
);
1112 calf_fader_enter (GtkWidget
*widget
, GdkEventCrossing
*event
)
1114 calf_fader_check_hover_change(widget
);
1119 calf_fader_leave (GtkWidget
*widget
, GdkEventCrossing
*event
)
1121 CALF_FADER(widget
)->hover
= false;
1122 gtk_widget_queue_draw(widget
);
1126 calf_fader_allocate (GtkWidget
*widget
, GtkAllocation
*allocation
)
1128 calf_fader_set_layout(widget
);
1131 calf_fader_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1133 g_assert(CALF_IS_FADER(widget
));
1134 if (gtk_widget_is_drawable (widget
)) {
1136 GdkWindow
*window
= widget
->window
;
1137 GtkScale
*scale
= GTK_SCALE(widget
);
1138 GtkRange
*range
= GTK_RANGE(widget
);
1139 CalfFader
*fader
= CALF_FADER(widget
);
1140 CalfFaderLayout layout
= fader
->layout
;
1141 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
1143 cairo_rectangle(c
, layout
.x
, layout
.y
, layout
.w
, layout
.h
);
1147 double r
= range
->adjustment
->upper
- range
->adjustment
->lower
;
1148 double v0
= range
->adjustment
->value
- range
->adjustment
->lower
;
1149 if ((fader
->horizontal
and gtk_range_get_inverted(range
))
1150 or (!fader
->horizontal
and gtk_range_get_inverted(range
)))
1152 int vp
= v0
/ r
* (fader
->horizontal
? layout
.w
- layout
.slw
: layout
.h
- layout
.slh
)
1153 + (fader
->horizontal
? layout
.slw
: layout
.slh
) / 2
1154 + (fader
->horizontal
? layout
.x
: layout
.y
);
1155 layout
.slx
= fader
->horizontal
? vp
- layout
.slw
/ 2 : layout
.tc
- layout
.slw
/ 2;
1156 layout
.sly
= fader
->horizontal
? layout
.tc
- layout
.slh
/ 2 : vp
- layout
.slh
/ 2;
1158 cairo_rectangle(c
, layout
.sx
- 1, layout
.sy
- 1, layout
.sw
, layout
.sh
);
1159 cairo_set_source_rgba(c
, 0,0,0, 0.25);
1161 cairo_rectangle(c
, layout
.sx
+ 1, layout
.sy
+ 1, layout
.sw
, layout
.sh
);
1162 cairo_set_source_rgba(c
, 1,1,1, 0.125);
1164 cairo_rectangle(c
, layout
.sx
, layout
.sy
, layout
.sw
, layout
.sh
);
1165 cairo_set_source_rgb(c
, 0,0,0);
1169 cairo_rectangle(c
, layout
.x
, layout
.y
, layout
.w
, layout
.h
);
1170 gdk_cairo_set_source_pixbuf(c
, fader
->screw
, layout
.scx1
, layout
.scy1
);
1171 cairo_fill_preserve(c
);
1172 gdk_cairo_set_source_pixbuf(c
, fader
->screw
, layout
.scx2
, layout
.scy2
);
1173 cairo_fill_preserve(c
);
1176 if (fader
->hover
or gtk_grab_get_current() == widget
)
1177 gdk_cairo_set_source_pixbuf(c
, fader
->sliderpre
, layout
.slx
, layout
.sly
);
1179 gdk_cairo_set_source_pixbuf(c
, fader
->slider
, layout
.slx
, layout
.sly
);
1183 if (scale
->draw_value
) {
1184 PangoLayout
*layout
;
1186 layout
= gtk_scale_get_layout (scale
);
1187 gtk_scale_get_layout_offsets (scale
, &_x
, &_y
);
1188 gtk_paint_layout (widget
->style
, window
, GTK_STATE_NORMAL
, FALSE
, NULL
,
1189 widget
, fader
->horizontal
? "hscale" : "vscale", _x
, _y
, layout
);
1198 calf_fader_class_init (CalfFaderClass
*klass
)
1200 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1201 widget_class
->expose_event
= calf_fader_expose
;
1205 calf_fader_init (CalfFader
*self
)
1207 GtkWidget
*widget
= GTK_WIDGET(self
);
1208 widget
->requisition
.width
= 40;
1209 widget
->requisition
.height
= 40;
1211 gtk_signal_connect(GTK_OBJECT(widget
), "motion-notify-event", GTK_SIGNAL_FUNC (calf_fader_motion
), NULL
);
1212 gtk_signal_connect(GTK_OBJECT(widget
), "enter-notify-event", GTK_SIGNAL_FUNC (calf_fader_enter
), NULL
);
1213 gtk_signal_connect(GTK_OBJECT(widget
), "leave-notify-event", GTK_SIGNAL_FUNC (calf_fader_leave
), NULL
);
1214 gtk_signal_connect(GTK_OBJECT(widget
), "size-allocate", GTK_SIGNAL_FUNC (calf_fader_allocate
), NULL
);
1218 calf_fader_get_type (void)
1220 static GType type
= 0;
1222 static const GTypeInfo type_info
= {
1223 sizeof(CalfFaderClass
),
1224 NULL
, /* base_init */
1225 NULL
, /* base_finalize */
1226 (GClassInitFunc
)calf_fader_class_init
,
1227 NULL
, /* class_finalize */
1228 NULL
, /* class_data */
1230 0, /* n_preallocs */
1231 (GInstanceInitFunc
)calf_fader_init
1234 for (int i
= 0; ; i
++) {
1235 char *name
= g_strdup_printf("CalfFader%u%d",
1236 ((unsigned int)(intptr_t)calf_fader_class_init
) >> 16, i
);
1237 if (g_type_from_name(name
)) {
1241 type
= g_type_register_static(GTK_TYPE_SCALE
,
1253 ///////////////////////////////////////// button ///////////////////////////////////////////////
1256 calf_button_new(const gchar
*label
)
1258 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_BUTTON
, NULL
));
1259 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1263 calf_button_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1265 g_assert(CALF_IS_BUTTON(widget
) || CALF_IS_TOGGLE_BUTTON(widget
) || CALF_IS_RADIO_BUTTON(widget
));
1267 if (gtk_widget_is_drawable (widget
)) {
1271 GdkWindow
*window
= widget
->window
;
1272 GtkWidget
*child
= GTK_BIN (widget
)->child
;
1273 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
1274 cairo_pattern_t
*pat
= NULL
;
1276 int x
= widget
->allocation
.x
;
1277 int y
= widget
->allocation
.y
;
1278 int sx
= widget
->allocation
.width
;
1279 int sy
= widget
->allocation
.height
;
1281 cairo_rectangle(c
, x
, y
, sx
, sy
);
1284 cairo_rectangle(c
, x
, y
, sx
, sy
);
1285 pat
= cairo_pattern_create_radial(x
+ sx
/ 2, y
+ sy
/ 2, 1, x
+ sx
/ 2, y
+ sy
/ 2, sx
/ 2);
1286 switch (gtk_widget_get_state(widget
)) {
1287 case GTK_STATE_NORMAL
:
1289 cairo_pattern_add_color_stop_rgb(pat
, 0.3, 39. / 255, 52. / 255, 87. / 255);
1290 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 6. / 255, 5. / 255, 14. / 255);
1292 case GTK_STATE_PRELIGHT
:
1293 cairo_pattern_add_color_stop_rgb(pat
, 0.3, 19. / 255, 237. / 255, 254. / 255);
1294 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 0. / 255, 45. / 255, 206. / 255);
1296 case GTK_STATE_ACTIVE
:
1297 case GTK_STATE_SELECTED
:
1298 cairo_pattern_add_color_stop_rgb(pat
, 0.0, 19. / 255, 237. / 255, 254. / 255);
1299 cairo_pattern_add_color_stop_rgb(pat
, 0.3, 10. / 255, 200. / 255, 240. / 255);
1300 cairo_pattern_add_color_stop_rgb(pat
, 0.7, 19. / 255, 237. / 255, 254. / 255);
1301 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 2. / 255, 168. / 255, 230. / 255);
1305 cairo_set_source(c
, pat
);
1308 cairo_rectangle(c
, x
+ pad
, y
+ pad
, sx
- pad
* 2, sy
- pad
* 2);
1309 if (CALF_IS_TOGGLE_BUTTON(widget
) or CALF_IS_RADIO_BUTTON(widget
)) {
1310 cairo_new_sub_path (c
);
1311 cairo_rectangle(c
, x
+ sx
- pad
* 2 - 23, y
+ sy
/ 2 - 1, 22, 2);
1312 cairo_set_fill_rule(c
, CAIRO_FILL_RULE_EVEN_ODD
);
1314 pat
= cairo_pattern_create_linear(x
+ pad
, y
+ pad
, x
+ pad
, y
+ sy
- pad
* 2);
1315 cairo_pattern_add_color_stop_rgb(pat
, 0.0, 0.92, 0.92, 0.92);
1316 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 0.70, 0.70, 0.70);
1317 cairo_set_source(c
, pat
);
1320 int _h
= GTK_WIDGET(GTK_BIN(widget
)->child
)->allocation
.height
+ 0;
1321 int _y
= y
+ (sy
- _h
) / 2;
1322 cairo_rectangle(c
, x
+ pad
, _y
, sx
- pad
* 2, _h
);
1323 if (CALF_IS_TOGGLE_BUTTON(widget
) or CALF_IS_RADIO_BUTTON(widget
)) {
1324 cairo_new_sub_path (c
);
1325 cairo_rectangle(c
, x
+ sx
- pad
* 2 - 23, y
+ sy
/ 2 - 1, 22, 2);
1326 cairo_set_fill_rule(c
, CAIRO_FILL_RULE_EVEN_ODD
);
1328 pat
= cairo_pattern_create_linear(x
+ pad
, _y
, x
+ pad
, _y
+ _h
);
1329 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 0.92, 0.92, 0.92);
1330 cairo_pattern_add_color_stop_rgb(pat
, 0.0, 0.70, 0.70, 0.70);
1331 cairo_set_source(c
, pat
);
1335 gtk_container_propagate_expose (GTK_CONTAINER (widget
), child
, event
);
1341 calf_button_class_init (CalfButtonClass
*klass
)
1343 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1344 widget_class
->expose_event
= calf_button_expose
;
1348 calf_button_init (CalfButton
*self
)
1350 GtkWidget
*widget
= GTK_WIDGET(self
);
1351 widget
->requisition
.width
= 40;
1352 widget
->requisition
.height
= 20;
1356 calf_button_get_type (void)
1358 static GType type
= 0;
1360 static const GTypeInfo type_info
= {
1361 sizeof(CalfButtonClass
),
1362 NULL
, /* base_init */
1363 NULL
, /* base_finalize */
1364 (GClassInitFunc
)calf_button_class_init
,
1365 NULL
, /* class_finalize */
1366 NULL
, /* class_data */
1368 0, /* n_preallocs */
1369 (GInstanceInitFunc
)calf_button_init
1372 for (int i
= 0; ; i
++) {
1373 char *name
= g_strdup_printf("CalfButton%u%d",
1374 ((unsigned int)(intptr_t)calf_button_class_init
) >> 16, i
);
1375 if (g_type_from_name(name
)) {
1379 type
= g_type_register_static(GTK_TYPE_BUTTON
,
1391 ///////////////////////////////////////// toggle button ///////////////////////////////////////////////
1394 calf_toggle_button_new(const gchar
*label
)
1396 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TOGGLE_BUTTON
, NULL
));
1397 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1402 calf_toggle_button_class_init (CalfToggleButtonClass
*klass
)
1404 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1405 widget_class
->expose_event
= calf_button_expose
;
1409 calf_toggle_button_init (CalfToggleButton
*self
)
1411 GtkWidget
*widget
= GTK_WIDGET(self
);
1412 widget
->requisition
.width
= 40;
1413 widget
->requisition
.height
= 20;
1417 calf_toggle_button_get_type (void)
1419 static GType type
= 0;
1421 static const GTypeInfo type_info
= {
1422 sizeof(CalfToggleButtonClass
),
1423 NULL
, /* base_init */
1424 NULL
, /* base_finalize */
1425 (GClassInitFunc
)calf_toggle_button_class_init
,
1426 NULL
, /* class_finalize */
1427 NULL
, /* class_data */
1428 sizeof(CalfToggleButton
),
1429 0, /* n_preallocs */
1430 (GInstanceInitFunc
)calf_toggle_button_init
1433 for (int i
= 0; ; i
++) {
1434 char *name
= g_strdup_printf("CalfToggleButton%u%d",
1435 ((unsigned int)(intptr_t)calf_toggle_button_class_init
) >> 16, i
);
1436 if (g_type_from_name(name
)) {
1440 type
= g_type_register_static(GTK_TYPE_TOGGLE_BUTTON
,
1451 ///////////////////////////////////////// radio button ///////////////////////////////////////////////
1454 calf_radio_button_new(const gchar
*label
)
1456 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_RADIO_BUTTON
, NULL
));
1457 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1462 calf_radio_button_class_init (CalfRadioButtonClass
*klass
)
1464 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1465 widget_class
->expose_event
= calf_button_expose
;
1469 calf_radio_button_init (CalfRadioButton
*self
)
1471 GtkWidget
*widget
= GTK_WIDGET(self
);
1472 widget
->requisition
.width
= 40;
1473 widget
->requisition
.height
= 20;
1477 calf_radio_button_get_type (void)
1479 static GType type
= 0;
1481 static const GTypeInfo type_info
= {
1482 sizeof(CalfRadioButtonClass
),
1483 NULL
, /* base_init */
1484 NULL
, /* base_finalize */
1485 (GClassInitFunc
)calf_radio_button_class_init
,
1486 NULL
, /* class_finalize */
1487 NULL
, /* class_data */
1488 sizeof(CalfRadioButton
),
1489 0, /* n_preallocs */
1490 (GInstanceInitFunc
)calf_radio_button_init
1493 for (int i
= 0; ; i
++) {
1494 char *name
= g_strdup_printf("CalfRadioButton%u%d",
1495 ((unsigned int)(intptr_t)calf_radio_button_class_init
) >> 16, i
);
1496 if (g_type_from_name(name
)) {
1500 type
= g_type_register_static(GTK_TYPE_RADIO_BUTTON
,
1511 ///////////////////////////////////////// tap button ///////////////////////////////////////////////
1514 calf_tap_button_new()
1516 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TAP_BUTTON
, NULL
));
1521 calf_tap_button_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1523 g_assert(CALF_IS_TAP_BUTTON(widget
));
1524 CalfTapButton
*self
= CALF_TAP_BUTTON(widget
);
1526 int x
= widget
->allocation
.x
+ widget
->allocation
.width
/ 2 - 35;
1527 int y
= widget
->allocation
.y
+ widget
->allocation
.height
/ 2 - 35;
1531 gdk_draw_pixbuf(GDK_DRAWABLE(widget
->window
),
1532 widget
->style
->fg_gc
[0],
1533 self
->image
[self
->state
],
1540 GDK_RGB_DITHER_NORMAL
, 0, 0);
1545 calf_tap_button_size_request (GtkWidget
*widget
,
1546 GtkRequisition
*requisition
)
1548 g_assert(CALF_IS_TAP_BUTTON(widget
));
1549 requisition
->width
= 70;
1550 requisition
->height
= 70;
1553 calf_tap_button_class_init (CalfTapButtonClass
*klass
)
1555 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1556 widget_class
->expose_event
= calf_tap_button_expose
;
1557 widget_class
->size_request
= calf_tap_button_size_request
;
1560 calf_tap_button_init (CalfTapButton
*self
)
1562 GtkWidget
*widget
= GTK_WIDGET(self
);
1563 widget
->requisition
.width
= 70;
1564 widget
->requisition
.height
= 70;
1566 GError
*error
= NULL
;
1567 self
->image
[0] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/tap_inactive.png", &error
);
1568 self
->image
[1] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/tap_prelight.png", &error
);
1569 self
->image
[2] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/tap_active.png", &error
);
1573 calf_tap_button_get_type (void)
1575 static GType type
= 0;
1577 static const GTypeInfo type_info
= {
1578 sizeof(CalfTapButtonClass
),
1579 NULL
, /* base_init */
1580 NULL
, /* base_finalize */
1581 (GClassInitFunc
)calf_tap_button_class_init
,
1582 NULL
, /* class_finalize */
1583 NULL
, /* class_data */
1584 sizeof(CalfTapButton
),
1585 0, /* n_preallocs */
1586 (GInstanceInitFunc
)calf_tap_button_init
1589 for (int i
= 0; ; i
++) {
1590 char *name
= g_strdup_printf("CalfTapButton%u%d",
1591 ((unsigned int)(intptr_t)calf_tap_button_class_init
) >> 16, i
);
1592 if (g_type_from_name(name
)) {
1596 type
= g_type_register_static(GTK_TYPE_BUTTON
,