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>
24 #if !defined(__APPLE__)
34 calf_tube_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
36 g_assert(CALF_IS_TUBE(widget
));
38 CalfTube
*self
= CALF_TUBE(widget
);
39 GdkWindow
*window
= widget
->window
;
40 GtkStyle
*style
= gtk_widget_get_style(widget
);
41 cairo_t
*c
= gdk_cairo_create(GDK_DRAWABLE(window
));
43 int ox
= 4, oy
= 4, inner
= 1, pad
;
44 int sx
= widget
->allocation
.width
- (ox
* 2), sy
= widget
->allocation
.height
- (oy
* 2);
46 if( self
->cache_surface
== NULL
) {
47 // looks like its either first call or the widget has been resized.
48 // create the cache_surface.
49 cairo_surface_t
*window_surface
= cairo_get_target( c
);
50 self
->cache_surface
= cairo_surface_create_similar( window_surface
,
52 widget
->allocation
.width
,
53 widget
->allocation
.height
);
55 // And render the meterstuff again.
56 cairo_t
*cache_cr
= cairo_create( self
->cache_surface
);
57 // theme background for reduced width and round borders
58 // if(widget->style->bg_pixmap[0] == NULL) {
59 gdk_cairo_set_source_color(cache_cr
,&style
->bg
[GTK_STATE_NORMAL
]);
61 // gdk_cairo_set_source_pixbuf(cache_cr, GDK_PIXBUF(widget->style->bg_pixmap[0]), widget->allocation.x, widget->allocation.y + 20);
63 cairo_paint(cache_cr
);
67 cairo_rectangle(cache_cr
, pad
, pad
, sx
+ ox
* 2 - pad
* 2, sy
+ oy
* 2 - pad
* 2);
68 cairo_set_source_rgb(cache_cr
, 0, 0, 0);
73 cairo_rectangle(cache_cr
, pad
, pad
, sx
+ ox
* 2 - pad
* 2, sy
+ oy
* 2 - pad
* 2);
74 cairo_pattern_t
*pat2
= cairo_pattern_create_linear (0, 0, 0, sy
+ oy
* 2 - pad
* 2);
75 cairo_pattern_add_color_stop_rgba (pat2
, 0, 0.23, 0.23, 0.23, 1);
76 cairo_pattern_add_color_stop_rgba (pat2
, 0.5, 0, 0, 0, 1);
77 cairo_set_source (cache_cr
, pat2
);
79 cairo_pattern_destroy(pat2
);
81 cairo_rectangle(cache_cr
, ox
, oy
, sx
, sy
);
82 cairo_set_source_rgb (cache_cr
, 0, 0, 0);
85 cairo_surface_t
*image
;
86 switch(self
->direction
) {
92 image
= cairo_image_surface_create_from_png (PKGLIBDIR
"tubeV1.png");
95 image
= cairo_image_surface_create_from_png (PKGLIBDIR
"tubeV2.png");
105 image
= cairo_image_surface_create_from_png (PKGLIBDIR
"tubeH1.png");
108 image
= cairo_image_surface_create_from_png (PKGLIBDIR
"tubeH2.png");
113 cairo_set_source_surface (cache_cr
, image
, widget
->allocation
.width
/ 2 - sx
/ 2 + inner
, widget
->allocation
.height
/ 2 - sy
/ 2 + inner
);
114 cairo_paint (cache_cr
);
115 cairo_surface_destroy (image
);
116 cairo_destroy( cache_cr
);
119 cairo_set_source_surface( c
, self
->cache_surface
, 0,0 );
124 gettimeofday(&tv
, 0);
125 long time
= tv
.tv_sec
* 1000 * 1000 + tv
.tv_usec
;
128 float value_orig
= self
->value
> 1.f
? 1.f
: self
->value
;
129 value_orig
= value_orig
< 0.f
? 0.f
: value_orig
;
132 float s
= ((float)(time
- self
->last_falltime
) / 1000000.0);
133 float m
= self
->last_falloff
* s
* 2.5;
134 self
->last_falloff
-= m
;
136 if(value_orig
> self
->last_falloff
) {
137 self
->last_falloff
= value_orig
;
139 value
= self
->last_falloff
;
140 self
->last_falltime
= time
;
141 self
->falling
= self
->last_falloff
> 0.000001;
142 cairo_pattern_t
*pat
;
144 switch(self
->direction
) {
147 cairo_arc(c
, ox
+ sx
* 0.5, oy
+ sy
* 0.2, sx
, 0, 2 * M_PI
);
148 pat
= cairo_pattern_create_radial (ox
+ sx
* 0.5, oy
+ sy
* 0.2, 3, ox
+ sx
* 0.5, oy
+ sy
* 0.2, sx
);
153 cairo_arc(c
, ox
+ sx
* 0.8, oy
+ sy
* 0.5, sy
, 0, 2 * M_PI
);
154 pat
= cairo_pattern_create_radial (ox
+ sx
* 0.8, oy
+ sy
* 0.5, 3, ox
+ sx
* 0.8, oy
+ sy
* 0.5, sy
);
157 cairo_pattern_add_color_stop_rgba (pat
, 0, 1, 1, 1, value
);
158 cairo_pattern_add_color_stop_rgba (pat
, 0.3, 1, 0.8, 0.3, value
* 0.4);
159 cairo_pattern_add_color_stop_rgba (pat
, 0.31, 0.9, 0.5, 0.1, value
* 0.5);
160 cairo_pattern_add_color_stop_rgba (pat
, 1, 0.0, 0.2, 0.7, 0);
161 cairo_set_source (c
, pat
);
164 switch(self
->direction
) {
167 cairo_arc(c
, ox
+ sx
* 0.5, oy
+ sy
* 0.75, sx
/ 2, 0, 2 * M_PI
);
168 pat
= cairo_pattern_create_radial (ox
+ sx
* 0.5, oy
+ sy
* 0.75, 2, ox
+ sx
* 0.5, oy
+ sy
* 0.75, sx
/ 2);
173 cairo_arc(c
, ox
+ sx
* 0.25, oy
+ sy
* 0.5, sy
/ 2, 0, 2 * M_PI
);
174 pat
= cairo_pattern_create_radial (ox
+ sx
* 0.25, oy
+ sy
* 0.5, 2, ox
+ sx
* 0.25, oy
+ sy
* 0.5, sy
/ 2);
177 cairo_pattern_add_color_stop_rgba (pat
, 0, 1, 1, 1, value
);
178 cairo_pattern_add_color_stop_rgba (pat
, 0.3, 1, 0.8, 0.3, value
* 0.4);
179 cairo_pattern_add_color_stop_rgba (pat
, 0.31, 0.9, 0.5, 0.1, value
* 0.5);
180 cairo_pattern_add_color_stop_rgba (pat
, 1, 0.0, 0.2, 0.7, 0);
181 cairo_set_source (c
, pat
);
188 calf_tube_size_request (GtkWidget
*widget
,
189 GtkRequisition
*requisition
)
191 g_assert(CALF_IS_TUBE(widget
));
193 CalfTube
*self
= CALF_TUBE(widget
);
194 switch(self
->direction
) {
198 widget
->requisition
.width
= 82;
199 widget
->requisition
.height
= 130;
203 widget
->requisition
.width
= 130;
204 widget
->requisition
.height
= 210;
212 widget
->requisition
.width
= 130;
213 widget
->requisition
.height
= 82;
217 widget
->requisition
.width
= 210;
218 widget
->requisition
.height
= 130;
226 calf_tube_size_allocate (GtkWidget
*widget
,
227 GtkAllocation
*allocation
)
229 g_assert(CALF_IS_TUBE(widget
));
230 CalfTube
*tube
= CALF_TUBE(widget
);
232 GtkWidgetClass
*parent_class
= (GtkWidgetClass
*) g_type_class_peek_parent( CALF_TUBE_GET_CLASS( tube
) );
234 parent_class
->size_allocate( widget
, allocation
);
236 if( tube
->cache_surface
)
237 cairo_surface_destroy( tube
->cache_surface
);
238 tube
->cache_surface
= NULL
;
242 calf_tube_class_init (CalfTubeClass
*klass
)
244 // GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
245 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
246 widget_class
->expose_event
= calf_tube_expose
;
247 widget_class
->size_request
= calf_tube_size_request
;
248 widget_class
->size_allocate
= calf_tube_size_allocate
;
252 calf_tube_init (CalfTube
*self
)
254 GtkWidget
*widget
= GTK_WIDGET(self
);
255 GTK_WIDGET_SET_FLAGS (GTK_WIDGET(self
), GTK_CAN_FOCUS
);
256 switch(self
->direction
) {
260 widget
->requisition
.width
= 82;
261 widget
->requisition
.height
= 130;
265 widget
->requisition
.width
= 130;
266 widget
->requisition
.height
= 210;
274 widget
->requisition
.width
= 130;
275 widget
->requisition
.height
= 82;
279 widget
->requisition
.width
= 210;
280 widget
->requisition
.height
= 130;
285 self
->falling
= false;
286 self
->cache_surface
= NULL
;
292 GtkWidget
*widget
= GTK_WIDGET( g_object_new (CALF_TYPE_TUBE
, NULL
));
296 extern void calf_tube_set_value(CalfTube
*tube
, float value
)
298 if (value
!= tube
->value
or tube
->falling
)
301 gtk_widget_queue_draw(GTK_WIDGET(tube
));
306 calf_tube_get_type (void)
308 static GType type
= 0;
311 static const GTypeInfo type_info
= {
312 sizeof(CalfTubeClass
),
313 NULL
, /* base_init */
314 NULL
, /* base_finalize */
315 (GClassInitFunc
)calf_tube_class_init
,
316 NULL
, /* class_finalize */
317 NULL
, /* class_data */
320 (GInstanceInitFunc
)calf_tube_init
323 for (int i
= 0; ; i
++) {
324 char *name
= g_strdup_printf("CalfTube%u%d",
325 ((unsigned int)(intptr_t)calf_tube_class_init
) >> 16, i
);
326 if (g_type_from_name(name
)) {
330 type
= g_type_register_static( GTK_TYPE_DRAWING_AREA
,