3 * Copyright (C) 2010-2012 Markus Schmidt and others
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
22 #include <calf/ctl_tube.h>
23 #include <cairo/cairo.h>
32 calf_tube_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
34 g_assert(CALF_IS_TUBE(widget
));
36 CalfTube
*self
= CALF_TUBE(widget
);
37 GdkWindow
*window
= widget
->window
;
38 GtkStyle
*style
= gtk_widget_get_style(widget
);
39 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
41 int ox
= 4, oy
= 4, inner
= 1, pad
;
42 int sx
= widget
->allocation
.width
- (ox
* 2), sy
= widget
->allocation
.height
- (oy
* 2);
44 if( self
->cache_surface
== NULL
) {
45 // looks like its either first call or the widget has been resized.
46 // create the cache_surface.
47 cairo_surface_t
*window_surface
= cairo_get_target( c
);
48 self
->cache_surface
= cairo_surface_create_similar( window_surface
,
50 widget
->allocation
.width
,
51 widget
->allocation
.height
);
53 // And render the meterstuff again.
54 cairo_t
*cache_cr
= cairo_create( self
->cache_surface
);
55 // theme background for reduced width and round borders
56 // if(widget->style->bg_pixmap[0] == NULL) {
57 gdk_cairo_set_source_color(cache_cr
,&style
->bg
[GTK_STATE_NORMAL
]);
59 // gdk_cairo_set_source_pixbuf(cache_cr, GDK_PIXBUF(widget->style->bg_pixmap[0]), widget->allocation.x, widget->allocation.y + 20);
61 cairo_paint(cache_cr
);
65 cairo_rectangle(cache_cr
, pad
, pad
, sx
+ ox
* 2 - pad
* 2, sy
+ oy
* 2 - pad
* 2);
66 cairo_set_source_rgb(cache_cr
, 0, 0, 0);
71 cairo_rectangle(cache_cr
, pad
, pad
, sx
+ ox
* 2 - pad
* 2, sy
+ oy
* 2 - pad
* 2);
72 cairo_pattern_t
*pat2
= cairo_pattern_create_linear (0, 0, 0, sy
+ oy
* 2 - pad
* 2);
73 cairo_pattern_add_color_stop_rgba (pat2
, 0, 0.23, 0.23, 0.23, 1);
74 cairo_pattern_add_color_stop_rgba (pat2
, 0.5, 0, 0, 0, 1);
75 cairo_set_source (cache_cr
, pat2
);
77 cairo_pattern_destroy(pat2
);
79 cairo_rectangle(cache_cr
, ox
, oy
, sx
, sy
);
80 cairo_set_source_rgb (cache_cr
, 0, 0, 0);
83 cairo_surface_t
*image
;
84 switch(self
->direction
) {
90 image
= cairo_image_surface_create_from_png (PKGLIBDIR
"tubeV1.png");
93 image
= cairo_image_surface_create_from_png (PKGLIBDIR
"tubeV2.png");
103 image
= cairo_image_surface_create_from_png (PKGLIBDIR
"tubeH1.png");
106 image
= cairo_image_surface_create_from_png (PKGLIBDIR
"tubeH2.png");
111 cairo_set_source_surface (cache_cr
, image
, widget
->allocation
.width
/ 2 - sx
/ 2 + inner
, widget
->allocation
.height
/ 2 - sy
/ 2 + inner
);
112 cairo_paint (cache_cr
);
113 cairo_surface_destroy (image
);
114 cairo_destroy( cache_cr
);
117 cairo_set_source_surface( c
, self
->cache_surface
, 0,0 );
122 gettimeofday(&tv
, 0);
123 long time
= tv
.tv_sec
* 1000 * 1000 + tv
.tv_usec
;
126 float value_orig
= self
->value
> 1.f
? 1.f
: self
->value
;
127 value_orig
= value_orig
< 0.f
? 0.f
: value_orig
;
130 float s
= ((float)(time
- self
->last_falltime
) / 1000000.0);
131 float m
= self
->last_falloff
* s
* 2.5;
132 self
->last_falloff
-= m
;
134 if(value_orig
> self
->last_falloff
) {
135 self
->last_falloff
= value_orig
;
137 value
= self
->last_falloff
;
138 self
->last_falltime
= time
;
139 self
->falling
= self
->last_falloff
> 0.000001;
140 cairo_pattern_t
*pat
;
142 switch(self
->direction
) {
145 cairo_arc(c
, ox
+ sx
* 0.5, oy
+ sy
* 0.2, sx
, 0, 2 * M_PI
);
146 pat
= cairo_pattern_create_radial (ox
+ sx
* 0.5, oy
+ sy
* 0.2, 3, ox
+ sx
* 0.5, oy
+ sy
* 0.2, sx
);
151 cairo_arc(c
, ox
+ sx
* 0.8, oy
+ sy
* 0.5, sy
, 0, 2 * M_PI
);
152 pat
= cairo_pattern_create_radial (ox
+ sx
* 0.8, oy
+ sy
* 0.5, 3, ox
+ sx
* 0.8, oy
+ sy
* 0.5, sy
);
155 cairo_pattern_add_color_stop_rgba (pat
, 0, 1, 1, 1, value
);
156 cairo_pattern_add_color_stop_rgba (pat
, 0.3, 1, 0.8, 0.3, value
* 0.4);
157 cairo_pattern_add_color_stop_rgba (pat
, 0.31, 0.9, 0.5, 0.1, value
* 0.5);
158 cairo_pattern_add_color_stop_rgba (pat
, 1, 0.0, 0.2, 0.7, 0);
159 cairo_set_source (c
, pat
);
162 switch(self
->direction
) {
165 cairo_arc(c
, ox
+ sx
* 0.5, oy
+ sy
* 0.75, sx
/ 2, 0, 2 * M_PI
);
166 pat
= cairo_pattern_create_radial (ox
+ sx
* 0.5, oy
+ sy
* 0.75, 2, ox
+ sx
* 0.5, oy
+ sy
* 0.75, sx
/ 2);
171 cairo_arc(c
, ox
+ sx
* 0.25, oy
+ sy
* 0.5, sy
/ 2, 0, 2 * M_PI
);
172 pat
= cairo_pattern_create_radial (ox
+ sx
* 0.25, oy
+ sy
* 0.5, 2, ox
+ sx
* 0.25, oy
+ sy
* 0.5, sy
/ 2);
175 cairo_pattern_add_color_stop_rgba (pat
, 0, 1, 1, 1, value
);
176 cairo_pattern_add_color_stop_rgba (pat
, 0.3, 1, 0.8, 0.3, value
* 0.4);
177 cairo_pattern_add_color_stop_rgba (pat
, 0.31, 0.9, 0.5, 0.1, value
* 0.5);
178 cairo_pattern_add_color_stop_rgba (pat
, 1, 0.0, 0.2, 0.7, 0);
179 cairo_set_source (c
, pat
);
186 calf_tube_size_request (GtkWidget
*widget
,
187 GtkRequisition
*requisition
)
189 g_assert(CALF_IS_TUBE(widget
));
191 CalfTube
*self
= CALF_TUBE(widget
);
192 switch(self
->direction
) {
196 widget
->requisition
.width
= 82;
197 widget
->requisition
.height
= 130;
201 widget
->requisition
.width
= 130;
202 widget
->requisition
.height
= 210;
210 widget
->requisition
.width
= 130;
211 widget
->requisition
.height
= 82;
215 widget
->requisition
.width
= 210;
216 widget
->requisition
.height
= 130;
224 calf_tube_size_allocate (GtkWidget
*widget
,
225 GtkAllocation
*allocation
)
227 g_assert(CALF_IS_TUBE(widget
));
228 CalfTube
*tube
= CALF_TUBE(widget
);
230 GtkWidgetClass
*parent_class
= (GtkWidgetClass
*) g_type_class_peek_parent( CALF_TUBE_GET_CLASS( tube
) );
232 parent_class
->size_allocate( widget
, allocation
);
234 if( tube
->cache_surface
)
235 cairo_surface_destroy( tube
->cache_surface
);
236 tube
->cache_surface
= NULL
;
240 calf_tube_class_init (CalfTubeClass
*klass
)
242 // GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
243 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
244 widget_class
->expose_event
= calf_tube_expose
;
245 widget_class
->size_request
= calf_tube_size_request
;
246 widget_class
->size_allocate
= calf_tube_size_allocate
;
250 calf_tube_init (CalfTube
*self
)
252 GtkWidget
*widget
= GTK_WIDGET(self
);
253 GTK_WIDGET_SET_FLAGS (GTK_WIDGET(self
), GTK_CAN_FOCUS
);
254 switch(self
->direction
) {
258 widget
->requisition
.width
= 82;
259 widget
->requisition
.height
= 130;
263 widget
->requisition
.width
= 130;
264 widget
->requisition
.height
= 210;
272 widget
->requisition
.width
= 130;
273 widget
->requisition
.height
= 82;
277 widget
->requisition
.width
= 210;
278 widget
->requisition
.height
= 130;
283 self
->falling
= false;
284 self
->cache_surface
= NULL
;
290 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TUBE
, NULL
));
294 extern void calf_tube_set_value(CalfTube
*tube
, float value
)
296 if (value
!= tube
->value
or tube
->falling
)
299 gtk_widget_queue_draw(GTK_WIDGET(tube
));
304 calf_tube_get_type (void)
306 static GType type
= 0;
309 static const GTypeInfo type_info
= {
310 sizeof(CalfTubeClass
),
311 NULL
, /* base_init */
312 NULL
, /* base_finalize */
313 (GClassInitFunc
)calf_tube_class_init
,
314 NULL
, /* class_finalize */
315 NULL
, /* class_data */
318 (GInstanceInitFunc
)calf_tube_init
321 for (int i
= 0; ; i
++) {
322 char *name
= g_strdup_printf("CalfTube%u%d",
323 ((unsigned int)(intptr_t)calf_tube_class_init
) >> 16, i
);
324 if (g_type_from_name(name
)) {
328 type
= g_type_register_static( GTK_TYPE_DRAWING_AREA
,