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 using namespace calf_plugins
;
34 ///////////////////////////////////////// utility functions ///////////////////////////////////////////////
36 void line_graph_background(cairo_t
* c
, int x
, int y
, int sx
, int sy
, int ox
, int oy
, float brightness
, int shadow
, float lights
, float dull
)
38 float br
= brightness
* 0.5 + 0.5;
40 // outer frame (black)
44 c
, pad
+ x
, pad
+ y
, sx
+ ox
* 2 - pad
* 2, sy
+ oy
* 2 - pad
* 2);
45 cairo_set_source_rgb(c
, 0, 0, 0);
51 c
, pad
+ x
, pad
+ y
, sx
+ ox
* 2 - pad
* 2, sy
+ oy
* 2 - pad
* 2);
52 cairo_pattern_t
*pat2
= cairo_pattern_create_linear (
53 x
, y
, x
, y
+ sy
+ oy
* 2 - pad
* 2);
54 cairo_pattern_add_color_stop_rgba (pat2
, 0, 0.23, 0.23, 0.23, 1);
55 cairo_pattern_add_color_stop_rgba (pat2
, 0.33, 0.13, 0.13, 0.13, 1);
56 cairo_pattern_add_color_stop_rgba (pat2
, 0.33, 0.05, 0.05, 0.05, 1);
57 cairo_pattern_add_color_stop_rgba (pat2
, 0.5, 0, 0, 0, 1);
58 cairo_set_source (c
, pat2
);
60 cairo_pattern_destroy(pat2
);
62 cairo_rectangle(c
, x
+ ox
- 1, y
+ oy
- 1, sx
+ 2, sy
+ 2);
63 cairo_set_source_rgb (c
, 0, 0, 0);
66 // inner yellowish screen
67 cairo_pattern_t
*pt
= cairo_pattern_create_linear(x
+ ox
, y
+ oy
, x
+ ox
, y
+ sy
);
68 cairo_pattern_add_color_stop_rgb(pt
, 0.0, br
* 0.71, br
* 0.82, br
* 0.33);
69 cairo_pattern_add_color_stop_rgb(pt
, 1.0, br
* 0.89, br
* 1.00, br
* 0.54);
70 cairo_set_source (c
, pt
);
71 cairo_rectangle(c
, x
+ ox
, y
+ oy
, sx
, sy
);
73 cairo_pattern_destroy(pt
);
77 pt
= cairo_pattern_create_linear(x
+ ox
, y
+ oy
, x
+ ox
, y
+ oy
+ shadow
);
78 cairo_pattern_add_color_stop_rgba(pt
, 0.0, 0,0,0,0.6);
79 cairo_pattern_add_color_stop_rgba(pt
, 1.0, 0,0,0,0);
80 cairo_set_source (c
, pt
);
81 cairo_rectangle(c
, x
+ ox
, y
+ oy
, sx
, shadow
);
83 cairo_pattern_destroy(pt
);
86 pt
= cairo_pattern_create_linear(x
+ ox
, y
+ oy
, x
+ ox
+ (float)shadow
* 0.7, y
+ oy
);
87 cairo_pattern_add_color_stop_rgba(pt
, 0.0, 0,0,0,0.3);
88 cairo_pattern_add_color_stop_rgba(pt
, 1.0, 0,0,0,0);
89 cairo_set_source (c
, pt
);
90 cairo_rectangle(c
, x
+ ox
, y
+ oy
, (float)shadow
* 0.7, sy
);
92 cairo_pattern_destroy(pt
);
95 pt
= cairo_pattern_create_linear(x
+ ox
+ sx
- (float)shadow
* 0.7, y
+ oy
, x
+ ox
+ sx
, y
+ oy
);
96 cairo_pattern_add_color_stop_rgba(pt
, 0.0, 0,0,0,0);
97 cairo_pattern_add_color_stop_rgba(pt
, 1.0, 0,0,0,0.3);
98 cairo_set_source (c
, pt
);
99 cairo_rectangle(c
, x
+ ox
+ sx
- (float)shadow
* 0.7, y
+ oy
, 5, sy
);
101 cairo_pattern_destroy(pt
);
106 pt
= cairo_pattern_create_linear(x
+ ox
, y
+ oy
, x
+ ox
+ sx
/ 2, y
+ oy
);
107 cairo_pattern_add_color_stop_rgba(pt
, 0.0, 0,0,0,dull
);
108 cairo_pattern_add_color_stop_rgba(pt
, 1.0, 0,0,0,0);
109 cairo_set_source (c
, pt
);
110 cairo_rectangle(c
, x
+ ox
, y
+ oy
, sx
/ 2, sy
);
112 cairo_pattern_destroy(pt
);
115 pt
= cairo_pattern_create_linear(x
+ ox
+ sx
/ 2, y
+ oy
, x
+ ox
+ sx
, y
+ oy
);
116 cairo_pattern_add_color_stop_rgba(pt
, 0.0, 0,0,0,0);
117 cairo_pattern_add_color_stop_rgba(pt
, 1.0, 0,0,0,dull
);
118 cairo_set_source (c
, pt
);
119 cairo_rectangle(c
, x
+ ox
+ sx
/ 2, y
+ oy
, sx
/ 2, sy
);
121 cairo_pattern_destroy(pt
);
128 while(light_w
/ div
> 300)
131 cairo_rectangle(c
, x
+ ox
, y
+ oy
, sx
, sy
);
132 for(int i
= 0; i
< div
; i
++) {
133 cairo_pattern_t
*pt
= cairo_pattern_create_radial(
134 x
+ ox
+ w
* i
+ w
/ 2.f
, y
+ oy
, 1,
135 x
+ ox
+ w
* i
+ w
/ 2.f
, y
+ ox
+ sy
* 0.25, w
/ 2.f
);
136 cairo_pattern_add_color_stop_rgba (pt
, 0, 1, 1, 0.8, lights
);
137 cairo_pattern_add_color_stop_rgba (pt
, 1, 0.89, 1.00, 0.45, 0);
138 cairo_set_source (c
, pt
);
139 cairo_fill_preserve(c
);
140 pt
= cairo_pattern_create_radial(
141 x
+ ox
+ w
* i
+ w
/ 2.f
, y
+ oy
+ sy
, 1,
142 x
+ ox
+ w
* i
+ w
/ 2.f
, y
+ ox
+ sy
* 0.75, w
/ 2.f
);
143 cairo_pattern_add_color_stop_rgba (pt
, 0, 1, 1, 0.8, lights
);
144 cairo_pattern_add_color_stop_rgba (pt
, 1, 0.89, 1.00, 0.45, 0);
145 cairo_set_source (c
, pt
);
146 cairo_fill_preserve(c
);
151 ///////////////////////////////////////// phase graph ///////////////////////////////////////////////
154 calf_phase_graph_draw_background( cairo_t
*ctx
, int sx
, int sy
, int ox
, int oy
)
156 int cx
= ox
+ sx
/ 2;
157 int cy
= oy
+ sy
/ 2;
159 line_graph_background(ctx
, 0, 0, sx
, sy
, ox
, oy
);
160 cairo_set_source_rgb(ctx
, 0.35, 0.4, 0.2);
161 cairo_select_font_face(ctx
, "Sans", CAIRO_FONT_SLANT_NORMAL
, CAIRO_FONT_WEIGHT_NORMAL
);
162 cairo_set_font_size(ctx
, 9);
163 cairo_text_extents_t te
;
165 cairo_text_extents (ctx
, "M", &te
);
166 cairo_move_to (ctx
, cx
+ 5, oy
+ 12);
167 cairo_show_text (ctx
, "M");
169 cairo_text_extents (ctx
, "S", &te
);
170 cairo_move_to (ctx
, ox
+ 5, cy
- 5);
171 cairo_show_text (ctx
, "S");
173 cairo_text_extents (ctx
, "L", &te
);
174 cairo_move_to (ctx
, ox
+ 18, oy
+ 12);
175 cairo_show_text (ctx
, "L");
177 cairo_text_extents (ctx
, "R", &te
);
178 cairo_move_to (ctx
, ox
+ sx
- 22, oy
+ 12);
179 cairo_show_text (ctx
, "R");
181 cairo_set_line_width(ctx
, 1);
183 cairo_move_to(ctx
, ox
, oy
+ sy
* 0.5);
184 cairo_line_to(ctx
, ox
+ sx
, oy
+ sy
* 0.5);
187 cairo_move_to(ctx
, ox
+ sx
* 0.5, oy
);
188 cairo_line_to(ctx
, ox
+ sx
* 0.5, oy
+ sy
);
191 cairo_set_source_rgba(ctx
, 0, 0, 0, 0.2);
192 cairo_move_to(ctx
, ox
, oy
);
193 cairo_line_to(ctx
, ox
+ sx
, oy
+ sy
);
196 cairo_move_to(ctx
, ox
, oy
+ sy
);
197 cairo_line_to(ctx
, ox
+ sx
, oy
);
201 calf_phase_graph_copy_surface(cairo_t
*ctx
, cairo_surface_t
*source
, float fade
= 1.f
)
203 // copy a surface to a cairo context
205 cairo_set_source_surface(ctx
, source
, 0, 0);
207 float rnd
= (float)rand() / (float)RAND_MAX
/ 100;
208 cairo_paint_with_alpha(ctx
, fade
* 0.35 + 0.05 + rnd
);
215 calf_phase_graph_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
217 g_assert(CALF_IS_PHASE_GRAPH(widget
));
218 CalfPhaseGraph
*pg
= CALF_PHASE_GRAPH(widget
);
224 int sx
= widget
->allocation
.width
- ox
* 2, sy
= widget
->allocation
.height
- oy
* 2;
228 int cx
= ox
+ sx
/ 2;
229 int cy
= oy
+ sy
/ 2;
231 // some values as pointers for the audio plug-in call
233 float *data
= new float[2 * sx
];
234 float * phase_buffer
= 0;
238 bool use_fade
= true;
242 // cairo initialization stuff
243 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(widget
->window
));
247 if( pg
->background
== NULL
) {
248 // looks like its either first call or the widget has been resized.
249 // create the background surface (stolen from line graph)...
250 cairo_surface_t
*window_surface
= cairo_get_target(c
);
251 pg
->background
= cairo_surface_create_similar(window_surface
,
253 widget
->allocation
.width
,
254 widget
->allocation
.height
);
255 pg
->cache
= cairo_surface_create_similar(window_surface
,
257 widget
->allocation
.width
,
258 widget
->allocation
.height
);
260 // ...and draw some bling bling onto it...
261 ctx_back
= cairo_create(pg
->background
);
262 calf_phase_graph_draw_background(ctx_back
, sx
, sy
, ox
, oy
);
263 // ...and copy it to the cache
264 ctx_cache
= cairo_create(pg
->cache
);
265 calf_phase_graph_copy_surface(ctx_cache
, pg
->background
, 1);
267 ctx_back
= cairo_create(pg
->background
);
268 ctx_cache
= cairo_create(pg
->cache
);
271 pg
->source
->get_phase_graph(&phase_buffer
, &length
, &mode
, &use_fade
,
272 &fade
, &accuracy
, &display
);
274 // process some values set by the plug-in
276 accuracy
= 12 - accuracy
;
278 calf_phase_graph_copy_surface(ctx_cache
, pg
->background
, use_fade
? fade
: 1);
281 cairo_rectangle(ctx_cache
, ox
, oy
, sx
, sy
);
282 cairo_clip(ctx_cache
);
283 cairo_set_source_rgba(ctx_cache
, 0.35, 0.4, 0.2, 1);
285 for(int i
= 0; i
< length
; i
+= accuracy
) {
286 float l
= phase_buffer
[i
];
287 float r
= phase_buffer
[i
+ 1];
288 if(l
== 0.f
and r
== 0.f
) continue;
289 else if(r
== 0.f
and l
> 0.f
) _a
= M_PI
/ 2.f
;
290 else if(r
== 0.f
and l
< 0.f
) _a
= 3.f
*M_PI
/ 2.f
;
291 else _a
= pg
->_atan(l
/ r
, l
, r
);
292 double _R
= sqrt(pow(l
, 2) + pow(r
, 2));
294 float x
= (-1.f
)*_R
* cos(_a
);
295 float y
= _R
* sin(_a
);
296 // mask the cached values
300 cairo_rectangle (ctx_cache
, x
* rad
+ cx
, y
* rad
+ cy
, 1, 1);
304 cairo_rectangle (ctx_cache
, x
* rad
+ cx
- 0.25, y
* rad
+ cy
- 0.25, 1.5, 1.5);
308 cairo_rectangle (ctx_cache
, x
* rad
+ cx
- 0.5, y
* rad
+ cy
- 0.5, 2, 2);
312 if(i
== 0) cairo_move_to(ctx_cache
,
313 x
* rad
+ cx
, y
* rad
+ cy
);
314 else cairo_line_to(ctx_cache
,
315 x
* rad
+ cx
, y
* rad
+ cy
);
319 if(i
== 0) cairo_move_to(ctx_cache
,
320 x
* rad
+ cx
, y
* rad
+ cy
);
321 else cairo_line_to(ctx_cache
,
322 x
* rad
+ cx
, y
* rad
+ cy
);
331 cairo_fill(ctx_cache
);
334 cairo_fill(ctx_cache
);
337 cairo_set_line_width(ctx_cache
, 0.5);
338 cairo_stroke(ctx_cache
);
343 calf_phase_graph_copy_surface(c
, pg
->cache
, 1);
346 cairo_destroy(ctx_back
);
347 cairo_destroy(ctx_cache
);
349 // printf("exposed %p %dx%d %d+%d\n", widget->window, event->area.x, event->area.y, event->area.width, event->area.height);
354 calf_phase_graph_size_request (GtkWidget
*widget
,
355 GtkRequisition
*requisition
)
357 g_assert(CALF_IS_PHASE_GRAPH(widget
));
358 // CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
362 calf_phase_graph_size_allocate (GtkWidget
*widget
,
363 GtkAllocation
*allocation
)
365 g_assert(CALF_IS_PHASE_GRAPH(widget
));
366 CalfPhaseGraph
*lg
= CALF_PHASE_GRAPH(widget
);
368 GtkWidgetClass
*parent_class
= (GtkWidgetClass
*) g_type_class_peek_parent( CALF_PHASE_GRAPH_GET_CLASS( lg
) );
371 cairo_surface_destroy(lg
->background
);
372 lg
->background
= NULL
;
374 widget
->allocation
= *allocation
;
375 GtkAllocation
&a
= widget
->allocation
;
376 if (a
.width
> a
.height
) {
377 a
.x
+= (a
.width
- a
.height
) / 2;
380 if (a
.width
< a
.height
) {
381 a
.y
+= (a
.height
- a
.width
) / 2;
384 parent_class
->size_allocate(widget
, &a
);
388 calf_phase_graph_class_init (CalfPhaseGraphClass
*klass
)
390 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
391 widget_class
->expose_event
= calf_phase_graph_expose
;
392 widget_class
->size_request
= calf_phase_graph_size_request
;
393 widget_class
->size_allocate
= calf_phase_graph_size_allocate
;
397 calf_phase_graph_unrealize (GtkWidget
*widget
, CalfPhaseGraph
*pg
)
400 cairo_surface_destroy(pg
->background
);
401 pg
->background
= NULL
;
405 calf_phase_graph_init (CalfPhaseGraph
*self
)
407 GtkWidget
*widget
= GTK_WIDGET(self
);
408 widget
->requisition
.width
= 40;
409 widget
->requisition
.height
= 40;
410 self
->background
= NULL
;
411 g_signal_connect(GTK_OBJECT(widget
), "unrealize", G_CALLBACK(calf_phase_graph_unrealize
), (gpointer
)self
);
415 calf_phase_graph_new()
417 return GTK_WIDGET(g_object_new (CALF_TYPE_PHASE_GRAPH
, NULL
));
421 calf_phase_graph_get_type (void)
423 static GType type
= 0;
425 static const GTypeInfo type_info
= {
426 sizeof(CalfPhaseGraphClass
),
427 NULL
, /* base_init */
428 NULL
, /* base_finalize */
429 (GClassInitFunc
)calf_phase_graph_class_init
,
430 NULL
, /* class_finalize */
431 NULL
, /* class_data */
432 sizeof(CalfPhaseGraph
),
434 (GInstanceInitFunc
)calf_phase_graph_init
437 GTypeInfo
*type_info_copy
= new GTypeInfo(type_info
);
439 for (int i
= 0; ; i
++) {
440 char *name
= g_strdup_printf("CalfPhaseGraph%u%d", ((unsigned int)(intptr_t)calf_phase_graph_class_init
) >> 16, i
);
441 if (g_type_from_name(name
)) {
445 type
= g_type_register_static( GTK_TYPE_DRAWING_AREA
,
457 ///////////////////////////////////////// toggle ///////////////////////////////////////////////
460 calf_toggle_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
462 g_assert(CALF_IS_TOGGLE(widget
));
464 CalfToggle
*self
= CALF_TOGGLE(widget
);
466 float sx
= self
->size
? self
->size
: 1.f
/ 3.f
* 2.f
;
467 float sy
= self
->size
? self
->size
: 1;
468 int x
= widget
->allocation
.x
+ widget
->allocation
.width
/ 2 - sx
* 15 - sx
* 2;
469 int y
= widget
->allocation
.y
+ widget
->allocation
.height
/ 2 - sy
* 10 - sy
* 3;
471 int height
= sy
* 26;
473 gdk_draw_pixbuf(GDK_DRAWABLE(widget
->window
),
474 widget
->style
->fg_gc
[0],
475 self
->toggle_image
[self
->size
],
477 20 - sy
* 3 + (sy
* 20 + 40) * floor(.5 + gtk_range_get_value(GTK_RANGE(widget
))),
482 GDK_RGB_DITHER_NORMAL
, 0, 0);
487 calf_toggle_size_request (GtkWidget
*widget
,
488 GtkRequisition
*requisition
)
490 g_assert(CALF_IS_TOGGLE(widget
));
492 CalfToggle
*self
= CALF_TOGGLE(widget
);
494 float sx
= self
->size
? self
->size
: 1.f
/ 3.f
* 2.f
;
495 float sy
= self
->size
? self
->size
: 1;
497 requisition
->width
= 30 * sx
;
498 requisition
->height
= 20 * sy
;
502 calf_toggle_button_press (GtkWidget
*widget
, GdkEventButton
*event
)
504 g_assert(CALF_IS_TOGGLE(widget
));
505 GtkAdjustment
*adj
= gtk_range_get_adjustment(GTK_RANGE(widget
));
506 if (gtk_range_get_value(GTK_RANGE(widget
)) == adj
->lower
)
508 gtk_range_set_value(GTK_RANGE(widget
), adj
->upper
);
510 gtk_range_set_value(GTK_RANGE(widget
), adj
->lower
);
516 calf_toggle_key_press (GtkWidget
*widget
, GdkEventKey
*event
)
518 switch(event
->keyval
)
523 return calf_toggle_button_press(widget
, NULL
);
529 calf_toggle_class_init (CalfToggleClass
*klass
)
531 // GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
532 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
533 widget_class
->expose_event
= calf_toggle_expose
;
534 widget_class
->size_request
= calf_toggle_size_request
;
535 widget_class
->button_press_event
= calf_toggle_button_press
;
536 widget_class
->key_press_event
= calf_toggle_key_press
;
540 calf_toggle_init (CalfToggle
*self
)
542 GtkWidget
*widget
= GTK_WIDGET(self
);
543 GTK_WIDGET_SET_FLAGS (GTK_WIDGET(self
), GTK_CAN_FOCUS
);
544 widget
->requisition
.width
= 30;
545 widget
->requisition
.height
= 20;
547 GError
*error
= NULL
;
548 self
->toggle_image
[0] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/toggle0_silver.png", &error
);
549 self
->toggle_image
[1] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/toggle1_silver.png", &error
);
550 self
->toggle_image
[2] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/toggle2_silver.png", &error
);
551 g_assert(self
->toggle_image
!= NULL
);
557 GtkAdjustment
*adj
= (GtkAdjustment
*)gtk_adjustment_new(0, 0, 1, 1, 0, 0);
558 return calf_toggle_new_with_adjustment(adj
);
561 static gboolean
calf_toggle_value_changed(gpointer obj
)
563 GtkWidget
*widget
= (GtkWidget
*)obj
;
564 CalfToggle
*self
= CALF_TOGGLE(widget
);
565 float sx
= self
->size
? self
->size
: 1.f
/ 3.f
* 2.f
;
566 float sy
= self
->size
? self
->size
: 1;
567 gtk_widget_queue_draw_area(widget
,
568 widget
->allocation
.x
- sx
* 2,
569 widget
->allocation
.y
- sy
* 3,
575 GtkWidget
*calf_toggle_new_with_adjustment(GtkAdjustment
*_adjustment
)
577 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TOGGLE
, NULL
));
579 gtk_range_set_adjustment(GTK_RANGE(widget
), _adjustment
);
580 g_signal_connect(GTK_OBJECT(widget
), "value-changed", G_CALLBACK(calf_toggle_value_changed
), widget
);
586 calf_toggle_get_type (void)
588 static GType type
= 0;
591 static const GTypeInfo type_info
= {
592 sizeof(CalfToggleClass
),
593 NULL
, /* base_init */
594 NULL
, /* base_finalize */
595 (GClassInitFunc
)calf_toggle_class_init
,
596 NULL
, /* class_finalize */
597 NULL
, /* class_data */
600 (GInstanceInitFunc
)calf_toggle_init
603 for (int i
= 0; ; i
++) {
604 char *name
= g_strdup_printf("CalfToggle%u%d",
605 ((unsigned int)(intptr_t)calf_toggle_class_init
) >> 16, i
);
606 if (g_type_from_name(name
)) {
610 type
= g_type_register_static( GTK_TYPE_RANGE
,
621 ///////////////////////////////////////// frame ///////////////////////////////////////////////
625 calf_frame_new(const char *label
)
627 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_FRAME
, NULL
));
628 CalfFrame
*self
= CALF_FRAME(widget
);
629 gtk_frame_set_label(GTK_FRAME(self
), label
);
633 calf_frame_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
635 g_assert(CALF_IS_FRAME(widget
));
636 if (gtk_widget_is_drawable (widget
)) {
638 GdkWindow
*window
= widget
->window
;
639 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
640 cairo_text_extents_t extents
;
642 int ox
= widget
->allocation
.x
;
643 int oy
= widget
->allocation
.y
;
644 int sx
= widget
->allocation
.width
;
645 int sy
= widget
->allocation
.height
;
654 cairo_rectangle(c
, ox
, oy
, sx
, sy
);
658 const gchar
*lab
= gtk_frame_get_label(GTK_FRAME(widget
));
660 cairo_select_font_face(c
, "Sans",
661 CAIRO_FONT_SLANT_NORMAL
,
662 CAIRO_FONT_WEIGHT_NORMAL
);
663 cairo_set_font_size(c
, size
);
665 cairo_text_extents(c
, lab
, &extents
);
667 double lw
= extents
.width
+ txp
* 2.;
669 cairo_set_line_width(c
, 1.);
671 cairo_move_to(c
, ox
+ rad
+ txp
+ m
, oy
+ size
- 2 + m
);
672 cairo_set_source_rgb(c
, 0.99,0.99,0.99);
673 cairo_show_text(c
, lab
);
675 cairo_set_source_rgb(c
, 0.9,0.9,0.9);
678 cairo_move_to(c
, ox
+ a
+ m
, oy
+ pad
+ rad
+ a
+ m
);
679 cairo_arc (c
, ox
+ rad
+ a
+ m
, oy
+ rad
+ a
+ pad
+ m
, rad
, 1 * M_PI
, 1.5 * M_PI
);
680 cairo_move_to(c
, ox
+ rad
+ a
+ lw
+ m
, oy
+ a
+ pad
+ m
);
681 cairo_line_to(c
, ox
+ sx
+ a
- rad
- m
- 1, oy
+ a
+ pad
+ m
);
682 cairo_arc (c
, ox
+ sx
- rad
+ a
- 2*m
- 1, oy
+ rad
+ a
+ pad
+ m
, rad
, 1.5 * M_PI
, 2 * M_PI
);
683 cairo_line_to(c
, ox
+ sx
+ a
- 2*m
- 1, oy
+ a
+ sy
- rad
- 2*m
- 1);
685 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
);
687 cairo_line_to(c
, ox
+ a
+ rad
+ m
, oy
+ sy
+ a
- 2*m
- 1);
688 cairo_arc (c
, ox
+ rad
+ a
+ m
, oy
+ sy
- rad
+ a
- 2*m
- 1, rad
, 0.5 * M_PI
, 1 * M_PI
);
689 cairo_line_to(c
, ox
+ a
+ m
, oy
+ a
+ rad
+ pad
+ m
);
694 cairo_set_source_rgb(c
, 0.66,0.66,0.66);
697 cairo_move_to(c
, ox
+ a
+ m
, oy
+ pad
+ rad
+ a
+ m
);
698 cairo_arc (c
, ox
+ rad
+ a
+ m
, oy
+ rad
+ a
+ pad
+ m
, rad
, 1 * M_PI
, 1.5 * M_PI
);
699 cairo_move_to(c
, ox
+ rad
+ a
+ lw
+ m
, oy
+ a
+ pad
+ m
);
701 cairo_line_to(c
, ox
+ sx
+ a
- rad
- m
, oy
+ a
+ pad
+ m
);
702 cairo_arc (c
, ox
+ sx
- rad
+ a
- 2*m
- 1, oy
+ rad
+ a
+ pad
+ m
, rad
, 1.5 * M_PI
, 2 * M_PI
);
703 cairo_line_to(c
, ox
+ sx
+ a
- 2*m
- 1, oy
+ a
+ sy
- rad
- 2*m
);
704 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
);
705 cairo_line_to(c
, ox
+ a
+ rad
+ m
, oy
+ sy
+ a
- 2*m
- 1);
706 cairo_arc (c
, ox
+ rad
+ a
+ m
, oy
+ sy
- rad
+ a
- 2*m
- 1, rad
, 0.5 * M_PI
, 1 * M_PI
);
707 cairo_line_to(c
, ox
+ a
+ m
, oy
+ a
+ rad
+ pad
+ m
);
712 if (gtk_bin_get_child(GTK_BIN(widget
))) {
713 gtk_container_propagate_expose(GTK_CONTAINER(widget
),
714 gtk_bin_get_child(GTK_BIN(widget
)),
721 calf_frame_class_init (CalfFrameClass
*klass
)
723 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
724 widget_class
->expose_event
= calf_frame_expose
;
728 calf_frame_init (CalfFrame
*self
)
730 GtkWidget
*widget
= GTK_WIDGET(self
);
731 widget
->requisition
.width
= 40;
732 widget
->requisition
.height
= 40;
736 calf_frame_get_type (void)
738 static GType type
= 0;
740 static const GTypeInfo type_info
= {
741 sizeof(CalfFrameClass
),
742 NULL
, /* base_init */
743 NULL
, /* base_finalize */
744 (GClassInitFunc
)calf_frame_class_init
,
745 NULL
, /* class_finalize */
746 NULL
, /* class_data */
749 (GInstanceInitFunc
)calf_frame_init
752 for (int i
= 0; ; i
++) {
753 char *name
= g_strdup_printf("CalfFrame%u%d",
754 ((unsigned int)(intptr_t)calf_frame_class_init
) >> 16, i
);
755 if (g_type_from_name(name
)) {
759 type
= g_type_register_static(GTK_TYPE_FRAME
,
770 ///////////////////////////////////////// combo box ///////////////////////////////////////////////
776 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_COMBOBOX
, NULL
));
780 calf_combobox_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
782 g_assert(CALF_IS_COMBOBOX(widget
));
784 if (gtk_widget_is_drawable (widget
)) {
788 GtkTreeModel
*model
= gtk_combo_box_get_model(GTK_COMBO_BOX (widget
));
791 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget
), &iter
))
792 gtk_tree_model_get (model
, &iter
, 0, &lab
, -1);
796 GdkWindow
*window
= widget
->window
;
797 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
799 int x
= widget
->allocation
.x
;
800 int y
= widget
->allocation
.y
;
801 int sx
= widget
->allocation
.width
;
802 int sy
= widget
->allocation
.height
;
806 cairo_rectangle(c
, x
, y
, sx
, sy
);
809 gtk_widget_get_pointer(GTK_WIDGET(widget
), &mx
, &my
);
810 if (mx
>= 0 and mx
< sx
and my
>= 0 and my
< sy
)
813 line_graph_background(c
, x
, y
, sx
- pad
* 2, sy
- pad
* 2, pad
, pad
, g_ascii_isspace(lab
[0]) ? 0 : 1, 4, hover
? 0.5 : 0, hover
? 0.1 : 0.25);
815 cairo_select_font_face(c
, "Sans",
816 CAIRO_FONT_SLANT_NORMAL
,
817 CAIRO_FONT_WEIGHT_NORMAL
);
818 cairo_set_font_size(c
, 12);
820 cairo_move_to(c
, x
+ pad
+ 3, y
+ sy
/ 2 + 5);
821 cairo_set_source_rgb(c
, 0.,0.,0.);
822 cairo_show_text(c
, lab
);
825 cairo_surface_t
*image
;
826 image
= cairo_image_surface_create_from_png(PKGLIBDIR
"combo_arrow.png");
827 cairo_set_source_surface(c
, image
, x
+ sx
- 20, y
+ sy
/ 2 - 5);
828 cairo_rectangle(c
, x
, y
, sx
, sy
);
837 calf_combobox_class_init (CalfComboboxClass
*klass
)
839 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
840 widget_class
->expose_event
= calf_combobox_expose
;
844 calf_combobox_init (CalfCombobox
*self
)
846 GtkWidget
*widget
= GTK_WIDGET(self
);
847 widget
->requisition
.width
= 40;
848 widget
->requisition
.height
= 20;
852 calf_combobox_get_type (void)
854 static GType type
= 0;
856 static const GTypeInfo type_info
= {
857 sizeof(CalfComboboxClass
),
858 NULL
, /* base_init */
859 NULL
, /* base_finalize */
860 (GClassInitFunc
)calf_combobox_class_init
,
861 NULL
, /* class_finalize */
862 NULL
, /* class_data */
863 sizeof(CalfCombobox
),
865 (GInstanceInitFunc
)calf_combobox_init
868 for (int i
= 0; ; i
++) {
869 char *name
= g_strdup_printf("CalfCombobox%u%d",
870 ((unsigned int)(intptr_t)calf_combobox_class_init
) >> 16, i
);
871 if (g_type_from_name(name
)) {
875 type
= g_type_register_static(GTK_TYPE_COMBO_BOX_TEXT
,
887 ///////////////////////////////////////// notebook ///////////////////////////////////////////////
889 #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data)
890 struct _GtkNotebookPage
893 GtkWidget
*tab_label
;
894 GtkWidget
*menu_label
;
895 GtkWidget
*last_focus_child
; /* Last descendant of the page that had focus */
897 guint default_menu
: 1; /* If true, we create the menu label ourself */
898 guint default_tab
: 1; /* If true, we create the tab label ourself */
902 guint reorderable
: 1;
903 guint detachable
: 1;
905 /* if true, the tab label was visible on last allocation; we track this so
906 * that we know to redraw the tab area if a tab label was hidden then shown
907 * without changing position */
908 guint tab_allocated_visible
: 1;
910 GtkRequisition requisition
;
911 GtkAllocation allocation
;
913 gulong mnemonic_activate_signal
;
914 gulong notify_visible_handler
;
920 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_NOTEBOOK
, NULL
));
924 calf_notebook_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
926 g_assert(CALF_IS_NOTEBOOK(widget
));
928 GtkNotebook
*notebook
;
929 notebook
= GTK_NOTEBOOK (widget
);
930 CalfNotebookClass
*klass
= CALF_NOTEBOOK_CLASS(GTK_OBJECT_GET_CLASS(widget
));
932 if (gtk_widget_is_drawable (widget
)) {
934 GdkWindow
*window
= widget
->window
;
935 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
936 cairo_pattern_t
*pat
= NULL
;
938 int x
= widget
->allocation
.x
;
939 int y
= widget
->allocation
.y
;
940 int sx
= widget
->allocation
.width
;
941 int sy
= widget
->allocation
.height
;
942 int tx
= widget
->style
->xthickness
;
943 int ty
= widget
->style
->ythickness
;
945 int bh
= lh
+ 2 * ty
;
947 cairo_rectangle(c
, x
, y
, sx
, sy
);
952 if (notebook
->show_tabs
) {
953 GtkNotebookPage
*page
;
957 gtk_widget_style_get(widget
, "tab-overlap", &sp
, NULL
);
959 pages
= notebook
->children
;
963 page
= GTK_NOTEBOOK_PAGE (pages
);
965 if (page
->tab_label
->window
== event
->window
&&
966 gtk_widget_is_drawable (page
->tab_label
)) {
967 int lx
= page
->tab_label
->allocation
.x
;
968 int lw
= page
->tab_label
->allocation
.width
;
970 // fix the labels position
971 page
->tab_label
->allocation
.y
= y
+ ty
;
972 page
->tab_label
->allocation
.height
= lh
;
974 // draw tab background
975 cairo_rectangle(c
, lx
- tx
, y
, lw
+ 2 * tx
, bh
);
976 cairo_set_source_rgba(c
, 0,0,0, page
!= notebook
->cur_page
? 0.25 : 0.5);
979 if (page
== notebook
->cur_page
) {
981 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 2, lw
+ 2 * tx
- 4, 2);
982 pat
= cairo_pattern_create_radial(lx
+ lw
/ 2, y
+ bh
/ 2, 1, lx
+ lw
/ 2, y
+ bh
/ 2, lw
+ tx
* 2);
983 cairo_pattern_add_color_stop_rgb(pat
, 0, 50. / 255, 1, 1);
984 cairo_pattern_add_color_stop_rgb(pat
, 0.3, 2. / 255, 180. / 255, 1);
985 cairo_pattern_add_color_stop_rgb(pat
, 0.5, 19. / 255, 220. / 255, 1);
986 cairo_pattern_add_color_stop_rgb(pat
, 1, 2. / 255, 120. / 255, 1);
987 cairo_set_source(c
, pat
);
990 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 1, lw
+ 2 * tx
- 4, 1);
991 cairo_set_source_rgba(c
, 0,0,0,0.5);
994 cairo_rectangle(c
, lx
- tx
+ 2, y
+ 4, lw
+ 2 * tx
- 4, 1);
995 cairo_set_source_rgba(c
, 1,1,1,0.3);
1000 gtk_container_propagate_expose (GTK_CONTAINER (notebook
), page
->tab_label
, event
);
1008 cairo_rectangle(c
, x
, y
+ add
, sx
, sy
- add
);
1009 cairo_set_source_rgba(c
, 0,0,0,0.5);
1013 cairo_rectangle(c
, x
+ 0.5, y
+ add
+ 0.5, sx
- 1, sy
- add
- 1);
1014 pat
= cairo_pattern_create_linear(x
, y
+ add
, x
, y
+ sy
- add
);
1015 cairo_pattern_add_color_stop_rgba(pat
, 0, 0, 0, 0, 0.3);
1016 cairo_pattern_add_color_stop_rgba(pat
, 0.5, 0.5, 0.5, 0.5, 0);
1017 cairo_pattern_add_color_stop_rgba(pat
, 1, 1, 1, 1, 0.2);
1018 cairo_set_source (c
, pat
);
1019 cairo_set_line_width(c
, 1);
1020 cairo_stroke_preserve(c
);
1022 int sw
= gdk_pixbuf_get_width(klass
->screw
);
1023 int sh
= gdk_pixbuf_get_height(klass
->screw
);
1026 gdk_cairo_set_source_pixbuf(c
, klass
->screw
, x
, y
+ add
);
1027 cairo_fill_preserve(c
);
1028 gdk_cairo_set_source_pixbuf(c
, klass
->screw
, x
+ sx
- sw
, y
+ add
);
1029 cairo_fill_preserve(c
);
1030 gdk_cairo_set_source_pixbuf(c
, klass
->screw
, x
, y
+ sy
- sh
);
1031 cairo_fill_preserve(c
);
1032 gdk_cairo_set_source_pixbuf(c
, klass
->screw
, x
+ sx
- sh
, y
+ sy
- sh
);
1033 cairo_fill_preserve(c
);
1035 // propagate expose to all children
1036 if (notebook
->cur_page
)
1037 gtk_container_propagate_expose (GTK_CONTAINER (notebook
),
1038 notebook
->cur_page
->child
,
1041 cairo_pattern_destroy(pat
);
1049 calf_notebook_class_init (CalfNotebookClass
*klass
)
1051 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1052 widget_class
->expose_event
= calf_notebook_expose
;
1054 klass
->screw
= gdk_pixbuf_new_from_file (PKGLIBDIR
"screw_black.png", 0);
1058 calf_notebook_init (CalfNotebook
*self
)
1060 //GtkWidget *widget = GTK_WIDGET(self);
1064 calf_notebook_get_type (void)
1066 static GType type
= 0;
1068 static const GTypeInfo type_info
= {
1069 sizeof(CalfNotebookClass
),
1070 NULL
, /* base_init */
1071 NULL
, /* base_finalize */
1072 (GClassInitFunc
)calf_notebook_class_init
,
1073 NULL
, /* class_finalize */
1074 NULL
, /* class_data */
1075 sizeof(CalfNotebook
),
1076 0, /* n_preallocs */
1077 (GInstanceInitFunc
)calf_notebook_init
1080 for (int i
= 0; ; i
++) {
1081 char *name
= g_strdup_printf("CalfNotebook%u%d",
1082 ((unsigned int)(intptr_t)calf_notebook_class_init
) >> 16, i
);
1083 if (g_type_from_name(name
)) {
1087 type
= g_type_register_static(GTK_TYPE_NOTEBOOK
,
1098 ///////////////////////////////////////// fader ///////////////////////////////////////////////
1100 static void calf_fader_set_layout(GtkWidget
*widget
)
1102 GtkRange
*range
= GTK_RANGE(widget
);
1103 CalfFader
*fader
= CALF_FADER(widget
);
1104 CalfFaderLayout layout
= fader
->layout
;
1106 int hor
= fader
->horizontal
;
1109 layout
.x
= widget
->allocation
.x
;
1110 layout
.y
= widget
->allocation
.y
;
1111 layout
.w
= widget
->allocation
.width
;
1112 layout
.h
= widget
->allocation
.height
;
1115 layout
.tx
= range
->range_rect
.x
+ layout
.x
;
1116 layout
.ty
= range
->range_rect
.y
+ layout
.y
;
1117 layout
.tw
= range
->range_rect
.width
;
1118 layout
.th
= range
->range_rect
.height
;
1119 layout
.tc
= hor
? layout
.ty
+ layout
.th
/ 2 : layout
.tx
+ layout
.tw
/ 2;
1122 layout
.scw
= gdk_pixbuf_get_width(fader
->screw
);
1123 layout
.sch
= gdk_pixbuf_get_height(fader
->screw
);
1124 layout
.scx1
= hor
? layout
.tx
: layout
.tc
- layout
.scw
/ 2;
1125 layout
.scy1
= hor
? layout
.tc
- layout
.sch
/ 2 : layout
.ty
;
1126 layout
.scx2
= hor
? layout
.tx
+ layout
.tw
- layout
.scw
: layout
.tc
- layout
.scw
/ 2;
1127 layout
.scy2
= hor
? layout
.tc
- layout
.sch
/ 2 : layout
.ty
+ layout
.th
- layout
.sch
;
1130 layout
.sw
= hor
? layout
.tw
- layout
.scw
* 2 - 2: 2;
1131 layout
.sh
= hor
? 2 : layout
.th
- layout
.sch
* 2 - 2;
1132 layout
.sx
= hor
? layout
.tx
+ layout
.scw
+ 1 : layout
.tc
- 1;
1133 layout
.sy
= hor
? layout
.tc
- 1 : layout
.ty
+ layout
.sch
+ 1;
1136 layout
.slw
= gdk_pixbuf_get_width(fader
->slider
);
1137 layout
.slh
= gdk_pixbuf_get_height(fader
->slider
);
1138 layout
.slx
= fader
->horizontal
? 0 : layout
.tc
- layout
.slw
/ 2;
1139 layout
.sly
= fader
->horizontal
? layout
.tc
- layout
.slh
/ 2 : 0;
1141 //printf("widg %d %d %d %d | trgh %d %d %d %d %d | slid %d %d %d %d | slit %d %d %d %d\n",
1142 //layout.x, layout.y, layout.w, layout.h,
1143 //layout.tx, layout.ty, layout.tw, layout.th, layout.tc,
1144 //layout.slx, layout.sly, layout.slw, layout.slh,
1145 //layout.sx, layout.sy, layout.sw, layout.sh);
1147 fader
->layout
= layout
;
1151 calf_fader_new(const int horiz
= 0, const int size
= 2, const double min
= 0, const double max
= 1, const double step
= 0.1)
1156 adj
= gtk_adjustment_new (min
, min
, max
, step
, 10 * step
, 0);
1158 if (fabs (step
) >= 1.0 || step
== 0.0)
1161 digits
= std::min(5, abs((gint
) floor (log10 (fabs (step
)))));
1163 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_FADER
, NULL
));
1164 CalfFader
*self
= CALF_FADER(widget
);
1166 GTK_RANGE(widget
)->orientation
= horiz
? GTK_ORIENTATION_HORIZONTAL
: GTK_ORIENTATION_VERTICAL
;
1167 gtk_range_set_adjustment(GTK_RANGE(widget
), GTK_ADJUSTMENT(adj
));
1168 gtk_scale_set_digits(GTK_SCALE(widget
), digits
);
1171 self
->horizontal
= horiz
;
1174 gchar
* file
= g_strdup_printf("%sslider%d-%s.png", PKGLIBDIR
, size
, horiz
? "horiz" : "vert");
1175 self
->slider
= gdk_pixbuf_new_from_file (file
, 0);
1176 file
= g_strdup_printf("%sslider%d-%s-prelight.png", PKGLIBDIR
, size
, horiz
? "horiz" : "vert");
1177 self
->sliderpre
= gdk_pixbuf_new_from_file(file
, 0);
1179 self
->screw
= gdk_pixbuf_new_from_file (PKGLIBDIR
"screw_silver.png", 0);
1184 static bool calf_fader_hover(GtkWidget
*widget
)
1186 CalfFader
*fader
= CALF_FADER(widget
);
1187 CalfFaderLayout layout
= fader
->layout
;
1189 gtk_widget_get_pointer(GTK_WIDGET(widget
), &mx
, &my
);
1191 if ((fader
->horizontal
and mx
+ layout
.x
>= layout
.tx
1192 and mx
+ layout
.x
< layout
.tx
+ layout
.tw
1193 and my
+ layout
.y
>= layout
.sly
1194 and my
+ layout
.y
< layout
.sly
+ layout
.slh
)
1195 or (!fader
->horizontal
and mx
+ layout
.x
>= layout
.slx
1196 and mx
+ layout
.x
< layout
.slx
+ layout
.slw
1197 and my
+ layout
.y
>= layout
.ty
1198 and my
+ layout
.y
< layout
.ty
+ layout
.th
))
1202 static void calf_fader_check_hover_change(GtkWidget
*widget
)
1204 CalfFader
*fader
= CALF_FADER(widget
);
1205 bool hover
= calf_fader_hover(widget
);
1206 if (hover
!= fader
->hover
)
1207 gtk_widget_queue_draw(widget
);
1208 fader
->hover
= hover
;
1211 calf_fader_motion (GtkWidget
*widget
, GdkEventMotion
*event
)
1213 calf_fader_check_hover_change(widget
);
1218 calf_fader_enter (GtkWidget
*widget
, GdkEventCrossing
*event
)
1220 calf_fader_check_hover_change(widget
);
1225 calf_fader_leave (GtkWidget
*widget
, GdkEventCrossing
*event
)
1227 CALF_FADER(widget
)->hover
= false;
1228 gtk_widget_queue_draw(widget
);
1232 calf_fader_allocate (GtkWidget
*widget
, GtkAllocation
*allocation
)
1234 calf_fader_set_layout(widget
);
1237 calf_fader_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1239 g_assert(CALF_IS_FADER(widget
));
1240 if (gtk_widget_is_drawable (widget
)) {
1242 GdkWindow
*window
= widget
->window
;
1243 GtkScale
*scale
= GTK_SCALE(widget
);
1244 GtkRange
*range
= GTK_RANGE(widget
);
1245 CalfFader
*fader
= CALF_FADER(widget
);
1246 CalfFaderLayout layout
= fader
->layout
;
1247 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
1249 cairo_rectangle(c
, layout
.x
, layout
.y
, layout
.w
, layout
.h
);
1253 double r
= range
->adjustment
->upper
- range
->adjustment
->lower
;
1254 double v0
= range
->adjustment
->value
- range
->adjustment
->lower
;
1255 if ((fader
->horizontal
and gtk_range_get_inverted(range
))
1256 or (!fader
->horizontal
and gtk_range_get_inverted(range
)))
1258 int vp
= v0
/ r
* (fader
->horizontal
? layout
.w
- layout
.slw
: layout
.h
- layout
.slh
)
1259 + (fader
->horizontal
? layout
.slw
: layout
.slh
) / 2
1260 + (fader
->horizontal
? layout
.x
: layout
.y
);
1261 layout
.slx
= fader
->horizontal
? vp
- layout
.slw
/ 2 : layout
.tc
- layout
.slw
/ 2;
1262 layout
.sly
= fader
->horizontal
? layout
.tc
- layout
.slh
/ 2 : vp
- layout
.slh
/ 2;
1264 cairo_rectangle(c
, layout
.sx
- 1, layout
.sy
- 1, layout
.sw
, layout
.sh
);
1265 cairo_set_source_rgba(c
, 0,0,0, 0.25);
1267 cairo_rectangle(c
, layout
.sx
+ 1, layout
.sy
+ 1, layout
.sw
, layout
.sh
);
1268 cairo_set_source_rgba(c
, 1,1,1, 0.125);
1270 cairo_rectangle(c
, layout
.sx
, layout
.sy
, layout
.sw
, layout
.sh
);
1271 cairo_set_source_rgb(c
, 0,0,0);
1275 cairo_rectangle(c
, layout
.x
, layout
.y
, layout
.w
, layout
.h
);
1276 gdk_cairo_set_source_pixbuf(c
, fader
->screw
, layout
.scx1
, layout
.scy1
);
1277 cairo_fill_preserve(c
);
1278 gdk_cairo_set_source_pixbuf(c
, fader
->screw
, layout
.scx2
, layout
.scy2
);
1279 cairo_fill_preserve(c
);
1282 if (fader
->hover
or gtk_grab_get_current() == widget
)
1283 gdk_cairo_set_source_pixbuf(c
, fader
->sliderpre
, layout
.slx
, layout
.sly
);
1285 gdk_cairo_set_source_pixbuf(c
, fader
->slider
, layout
.slx
, layout
.sly
);
1289 if (scale
->draw_value
) {
1290 PangoLayout
*layout
;
1292 layout
= gtk_scale_get_layout (scale
);
1293 gtk_scale_get_layout_offsets (scale
, &_x
, &_y
);
1294 gtk_paint_layout (widget
->style
, window
, GTK_STATE_NORMAL
, FALSE
, NULL
,
1295 widget
, fader
->horizontal
? "hscale" : "vscale", _x
, _y
, layout
);
1304 calf_fader_class_init (CalfFaderClass
*klass
)
1306 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1307 widget_class
->expose_event
= calf_fader_expose
;
1311 calf_fader_init (CalfFader
*self
)
1313 GtkWidget
*widget
= GTK_WIDGET(self
);
1314 widget
->requisition
.width
= 40;
1315 widget
->requisition
.height
= 40;
1317 gtk_signal_connect(GTK_OBJECT(widget
), "motion-notify-event", GTK_SIGNAL_FUNC (calf_fader_motion
), NULL
);
1318 gtk_signal_connect(GTK_OBJECT(widget
), "enter-notify-event", GTK_SIGNAL_FUNC (calf_fader_enter
), NULL
);
1319 gtk_signal_connect(GTK_OBJECT(widget
), "leave-notify-event", GTK_SIGNAL_FUNC (calf_fader_leave
), NULL
);
1320 gtk_signal_connect(GTK_OBJECT(widget
), "size-allocate", GTK_SIGNAL_FUNC (calf_fader_allocate
), NULL
);
1324 calf_fader_get_type (void)
1326 static GType type
= 0;
1328 static const GTypeInfo type_info
= {
1329 sizeof(CalfFaderClass
),
1330 NULL
, /* base_init */
1331 NULL
, /* base_finalize */
1332 (GClassInitFunc
)calf_fader_class_init
,
1333 NULL
, /* class_finalize */
1334 NULL
, /* class_data */
1336 0, /* n_preallocs */
1337 (GInstanceInitFunc
)calf_fader_init
1340 for (int i
= 0; ; i
++) {
1341 char *name
= g_strdup_printf("CalfFader%u%d",
1342 ((unsigned int)(intptr_t)calf_fader_class_init
) >> 16, i
);
1343 if (g_type_from_name(name
)) {
1347 type
= g_type_register_static(GTK_TYPE_SCALE
,
1359 ///////////////////////////////////////// button ///////////////////////////////////////////////
1362 calf_button_new(const gchar
*label
)
1364 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_BUTTON
, NULL
));
1365 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1369 calf_button_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1371 g_assert(CALF_IS_BUTTON(widget
) || CALF_IS_TOGGLE_BUTTON(widget
) || CALF_IS_RADIO_BUTTON(widget
));
1373 if (gtk_widget_is_drawable (widget
)) {
1377 GdkWindow
*window
= widget
->window
;
1378 GtkWidget
*child
= GTK_BIN (widget
)->child
;
1379 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
1380 cairo_pattern_t
*pat
= NULL
;
1382 int x
= widget
->allocation
.x
;
1383 int y
= widget
->allocation
.y
;
1384 int sx
= widget
->allocation
.width
;
1385 int sy
= widget
->allocation
.height
;
1387 cairo_rectangle(c
, x
, y
, sx
, sy
);
1390 cairo_rectangle(c
, x
, y
, sx
, sy
);
1391 pat
= cairo_pattern_create_radial(x
+ sx
/ 2, y
+ sy
/ 2, 1, x
+ sx
/ 2, y
+ sy
/ 2, sx
/ 2);
1392 switch (gtk_widget_get_state(widget
)) {
1393 case GTK_STATE_NORMAL
:
1395 cairo_pattern_add_color_stop_rgb(pat
, 0.3, 39. / 255, 52. / 255, 87. / 255);
1396 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 6. / 255, 5. / 255, 14. / 255);
1398 case GTK_STATE_PRELIGHT
:
1399 cairo_pattern_add_color_stop_rgb(pat
, 0.3, 19. / 255, 237. / 255, 254. / 255);
1400 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 0. / 255, 45. / 255, 206. / 255);
1402 case GTK_STATE_ACTIVE
:
1403 case GTK_STATE_SELECTED
:
1404 cairo_pattern_add_color_stop_rgb(pat
, 0.0, 19. / 255, 237. / 255, 254. / 255);
1405 cairo_pattern_add_color_stop_rgb(pat
, 0.3, 10. / 255, 200. / 255, 240. / 255);
1406 cairo_pattern_add_color_stop_rgb(pat
, 0.7, 19. / 255, 237. / 255, 254. / 255);
1407 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 2. / 255, 168. / 255, 230. / 255);
1411 cairo_set_source(c
, pat
);
1414 cairo_rectangle(c
, x
+ pad
, y
+ pad
, sx
- pad
* 2, sy
- pad
* 2);
1415 if (CALF_IS_TOGGLE_BUTTON(widget
) or CALF_IS_RADIO_BUTTON(widget
)) {
1416 cairo_new_sub_path (c
);
1417 cairo_rectangle(c
, x
+ sx
- pad
* 2 - 23, y
+ sy
/ 2 - 1, 22, 2);
1418 cairo_set_fill_rule(c
, CAIRO_FILL_RULE_EVEN_ODD
);
1420 pat
= cairo_pattern_create_linear(x
+ pad
, y
+ pad
, x
+ pad
, y
+ sy
- pad
* 2);
1421 cairo_pattern_add_color_stop_rgb(pat
, 0.0, 0.92, 0.92, 0.92);
1422 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 0.70, 0.70, 0.70);
1423 cairo_set_source(c
, pat
);
1426 int _h
= GTK_WIDGET(GTK_BIN(widget
)->child
)->allocation
.height
+ 0;
1427 int _y
= y
+ (sy
- _h
) / 2;
1428 cairo_rectangle(c
, x
+ pad
, _y
, sx
- pad
* 2, _h
);
1429 if (CALF_IS_TOGGLE_BUTTON(widget
) or CALF_IS_RADIO_BUTTON(widget
)) {
1430 cairo_new_sub_path (c
);
1431 cairo_rectangle(c
, x
+ sx
- pad
* 2 - 23, y
+ sy
/ 2 - 1, 22, 2);
1432 cairo_set_fill_rule(c
, CAIRO_FILL_RULE_EVEN_ODD
);
1434 pat
= cairo_pattern_create_linear(x
+ pad
, _y
, x
+ pad
, _y
+ _h
);
1435 cairo_pattern_add_color_stop_rgb(pat
, 1.0, 0.92, 0.92, 0.92);
1436 cairo_pattern_add_color_stop_rgb(pat
, 0.0, 0.70, 0.70, 0.70);
1437 cairo_set_source(c
, pat
);
1441 gtk_container_propagate_expose (GTK_CONTAINER (widget
), child
, event
);
1447 calf_button_class_init (CalfButtonClass
*klass
)
1449 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1450 widget_class
->expose_event
= calf_button_expose
;
1454 calf_button_init (CalfButton
*self
)
1456 GtkWidget
*widget
= GTK_WIDGET(self
);
1457 widget
->requisition
.width
= 40;
1458 widget
->requisition
.height
= 20;
1462 calf_button_get_type (void)
1464 static GType type
= 0;
1466 static const GTypeInfo type_info
= {
1467 sizeof(CalfButtonClass
),
1468 NULL
, /* base_init */
1469 NULL
, /* base_finalize */
1470 (GClassInitFunc
)calf_button_class_init
,
1471 NULL
, /* class_finalize */
1472 NULL
, /* class_data */
1474 0, /* n_preallocs */
1475 (GInstanceInitFunc
)calf_button_init
1478 for (int i
= 0; ; i
++) {
1479 char *name
= g_strdup_printf("CalfButton%u%d",
1480 ((unsigned int)(intptr_t)calf_button_class_init
) >> 16, i
);
1481 if (g_type_from_name(name
)) {
1485 type
= g_type_register_static(GTK_TYPE_BUTTON
,
1497 ///////////////////////////////////////// toggle button ///////////////////////////////////////////////
1500 calf_toggle_button_new(const gchar
*label
)
1502 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TOGGLE_BUTTON
, NULL
));
1503 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1508 calf_toggle_button_class_init (CalfToggleButtonClass
*klass
)
1510 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1511 widget_class
->expose_event
= calf_button_expose
;
1515 calf_toggle_button_init (CalfToggleButton
*self
)
1517 GtkWidget
*widget
= GTK_WIDGET(self
);
1518 widget
->requisition
.width
= 40;
1519 widget
->requisition
.height
= 20;
1523 calf_toggle_button_get_type (void)
1525 static GType type
= 0;
1527 static const GTypeInfo type_info
= {
1528 sizeof(CalfToggleButtonClass
),
1529 NULL
, /* base_init */
1530 NULL
, /* base_finalize */
1531 (GClassInitFunc
)calf_toggle_button_class_init
,
1532 NULL
, /* class_finalize */
1533 NULL
, /* class_data */
1534 sizeof(CalfToggleButton
),
1535 0, /* n_preallocs */
1536 (GInstanceInitFunc
)calf_toggle_button_init
1539 for (int i
= 0; ; i
++) {
1540 char *name
= g_strdup_printf("CalfToggleButton%u%d",
1541 ((unsigned int)(intptr_t)calf_toggle_button_class_init
) >> 16, i
);
1542 if (g_type_from_name(name
)) {
1546 type
= g_type_register_static(GTK_TYPE_TOGGLE_BUTTON
,
1557 ///////////////////////////////////////// radio button ///////////////////////////////////////////////
1560 calf_radio_button_new(const gchar
*label
)
1562 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_RADIO_BUTTON
, NULL
));
1563 gtk_button_set_label(GTK_BUTTON(widget
), label
);
1568 calf_radio_button_class_init (CalfRadioButtonClass
*klass
)
1570 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1571 widget_class
->expose_event
= calf_button_expose
;
1575 calf_radio_button_init (CalfRadioButton
*self
)
1577 GtkWidget
*widget
= GTK_WIDGET(self
);
1578 widget
->requisition
.width
= 40;
1579 widget
->requisition
.height
= 20;
1583 calf_radio_button_get_type (void)
1585 static GType type
= 0;
1587 static const GTypeInfo type_info
= {
1588 sizeof(CalfRadioButtonClass
),
1589 NULL
, /* base_init */
1590 NULL
, /* base_finalize */
1591 (GClassInitFunc
)calf_radio_button_class_init
,
1592 NULL
, /* class_finalize */
1593 NULL
, /* class_data */
1594 sizeof(CalfRadioButton
),
1595 0, /* n_preallocs */
1596 (GInstanceInitFunc
)calf_radio_button_init
1599 for (int i
= 0; ; i
++) {
1600 char *name
= g_strdup_printf("CalfRadioButton%u%d",
1601 ((unsigned int)(intptr_t)calf_radio_button_class_init
) >> 16, i
);
1602 if (g_type_from_name(name
)) {
1606 type
= g_type_register_static(GTK_TYPE_RADIO_BUTTON
,
1617 ///////////////////////////////////////// tap button ///////////////////////////////////////////////
1620 calf_tap_button_new()
1622 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TAP_BUTTON
, NULL
));
1627 calf_tap_button_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
1629 g_assert(CALF_IS_TAP_BUTTON(widget
));
1630 CalfTapButton
*self
= CALF_TAP_BUTTON(widget
);
1632 int x
= widget
->allocation
.x
+ widget
->allocation
.width
/ 2 - 35;
1633 int y
= widget
->allocation
.y
+ widget
->allocation
.height
/ 2 - 35;
1637 gdk_draw_pixbuf(GDK_DRAWABLE(widget
->window
),
1638 widget
->style
->fg_gc
[0],
1639 self
->image
[self
->state
],
1646 GDK_RGB_DITHER_NORMAL
, 0, 0);
1651 calf_tap_button_size_request (GtkWidget
*widget
,
1652 GtkRequisition
*requisition
)
1654 g_assert(CALF_IS_TAP_BUTTON(widget
));
1655 requisition
->width
= 70;
1656 requisition
->height
= 70;
1659 calf_tap_button_class_init (CalfTapButtonClass
*klass
)
1661 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
1662 widget_class
->expose_event
= calf_tap_button_expose
;
1663 widget_class
->size_request
= calf_tap_button_size_request
;
1666 calf_tap_button_init (CalfTapButton
*self
)
1668 GtkWidget
*widget
= GTK_WIDGET(self
);
1669 widget
->requisition
.width
= 70;
1670 widget
->requisition
.height
= 70;
1672 GError
*error
= NULL
;
1673 self
->image
[0] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/tap_inactive.png", &error
);
1674 self
->image
[1] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/tap_prelight.png", &error
);
1675 self
->image
[2] = gdk_pixbuf_new_from_file(PKGLIBDIR
"/tap_active.png", &error
);
1679 calf_tap_button_get_type (void)
1681 static GType type
= 0;
1683 static const GTypeInfo type_info
= {
1684 sizeof(CalfTapButtonClass
),
1685 NULL
, /* base_init */
1686 NULL
, /* base_finalize */
1687 (GClassInitFunc
)calf_tap_button_class_init
,
1688 NULL
, /* class_finalize */
1689 NULL
, /* class_data */
1690 sizeof(CalfTapButton
),
1691 0, /* n_preallocs */
1692 (GInstanceInitFunc
)calf_tap_button_init
1695 for (int i
= 0; ; i
++) {
1696 char *name
= g_strdup_printf("CalfTapButton%u%d",
1697 ((unsigned int)(intptr_t)calf_tap_button_class_init
) >> 16, i
);
1698 if (g_type_from_name(name
)) {
1702 type
= g_type_register_static(GTK_TYPE_BUTTON
,