2 Copyright (C) 2003-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 #include <gdkmm/rectangle.h>
31 #include <gtkmm2ext/fastmeter.h>
32 #include <gtkmm2ext/utils.h>
34 #define UINT_TO_RGB(u,r,g,b) { (*(r)) = ((u)>>16)&0xff; (*(g)) = ((u)>>8)&0xff; (*(b)) = (u)&0xff; }
35 #define UINT_TO_RGBA(u,r,g,b,a) { UINT_TO_RGB(((u)>>8),r,g,b); (*(a)) = (u)&0xff; }
39 using namespace Gtkmm2ext;
42 int FastMeter::min_pattern_metric_size = 16;
43 int FastMeter::max_pattern_metric_size = 1024;
44 bool FastMeter::no_rgba_overlay = false;
46 FastMeter::Pattern10Map FastMeter::vm_pattern_cache;
47 FastMeter::PatternBgMap FastMeter::vb_pattern_cache;
49 FastMeter::Pattern10Map FastMeter::hm_pattern_cache;
50 FastMeter::PatternBgMap FastMeter::hb_pattern_cache;
52 FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o, int len,
53 int clr0, int clr1, int clr2, int clr3,
54 int clr4, int clr5, int clr6, int clr7,
58 float stp0, float stp1,
59 float stp2, float stp3,
64 , _styleflags(styleflags)
73 last_peak_rect.width = 0;
74 last_peak_rect.height = 0;
78 no_rgba_overlay = ! Glib::getenv("NO_METER_SHADE").empty();
102 set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
110 if (orientation == Vertical) {
113 fgpattern = request_vertical_meter(pixwidth + 2, pixheight + 2, _clr, _stp, _styleflags);
114 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, _bgc, false);
119 fgpattern = request_horizontal_meter(pixwidth + 2, pixheight + 2, _clr, _stp, _styleflags);
120 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, _bgc, false);
123 pixrect.width = pixwidth;
124 pixrect.height = pixheight;
126 request_width = pixrect.width + 2;
127 request_height= pixrect.height + 2;
132 FastMeter::~FastMeter ()
137 FastMeter::flush_pattern_cache () {
138 Pattern10Map::iterator i1;
139 PatternBgMap::iterator ib;
140 for (ib = hb_pattern_cache.begin(); ib != hb_pattern_cache.end(); ++ib) {
141 hb_pattern_cache.erase(ib);
143 for (i1 = hm_pattern_cache.begin(); i1 != hm_pattern_cache.end(); ++i1) {
144 hm_pattern_cache.erase(i1);
146 for (ib = vb_pattern_cache.begin(); ib != vb_pattern_cache.end(); ++ib) {
147 vb_pattern_cache.erase(ib);
149 for (i1 = vm_pattern_cache.begin(); i1 != vm_pattern_cache.end(); ++i1) {
150 vm_pattern_cache.erase(i1);
154 Cairo::RefPtr<Cairo::Pattern>
155 FastMeter::generate_meter_pattern (
156 int width, int height, int *clr, float *stp, int styleflags, bool horiz)
160 const double soft = 3.0 / (double) height;
161 const double offs = -1.0 / (double) height;
163 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
166 Cairo coordinate space goes downwards as y value goes up, so invert
167 knee-based positions by using (1.0 - y)
170 UINT_TO_RGBA (clr[9], &r, &g, &b, &a); // top/clip
171 cairo_pattern_add_color_stop_rgb (pat, 0.0,
172 r/255.0, g/255.0, b/255.0);
174 knee = offs + stp[3] / 115.0f; // -0dB
176 UINT_TO_RGBA (clr[8], &r, &g, &b, &a);
177 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
178 r/255.0, g/255.0, b/255.0);
180 UINT_TO_RGBA (clr[7], &r, &g, &b, &a);
181 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
182 r/255.0, g/255.0, b/255.0);
184 knee = offs + stp[2]/ 115.0f; // -3dB || -2dB
186 UINT_TO_RGBA (clr[6], &r, &g, &b, &a);
187 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
188 r/255.0, g/255.0, b/255.0);
190 UINT_TO_RGBA (clr[5], &r, &g, &b, &a);
191 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
192 r/255.0, g/255.0, b/255.0);
194 knee = offs + stp[1] / 115.0f; // -9dB
196 UINT_TO_RGBA (clr[4], &r, &g, &b, &a);
197 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
198 r/255.0, g/255.0, b/255.0);
200 UINT_TO_RGBA (clr[3], &r, &g, &b, &a);
201 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
202 r/255.0, g/255.0, b/255.0);
204 knee = offs + stp[0] / 115.0f; // -18dB
206 UINT_TO_RGBA (clr[2], &r, &g, &b, &a);
207 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
208 r/255.0, g/255.0, b/255.0);
210 UINT_TO_RGBA (clr[1], &r, &g, &b, &a);
211 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
212 r/255.0, g/255.0, b/255.0);
214 UINT_TO_RGBA (clr[0], &r, &g, &b, &a); // bottom
215 cairo_pattern_add_color_stop_rgb (pat, 1.0,
216 r/255.0, g/255.0, b/255.0);
218 if ((styleflags & 1) && !no_rgba_overlay) {
219 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
220 cairo_pattern_add_color_stop_rgba (shade_pattern, 0, 0.0, 0.0, 0.0, 0.15);
221 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.4, 1.0, 1.0, 1.0, 0.05);
222 cairo_pattern_add_color_stop_rgba (shade_pattern, 1, 0.0, 0.0, 0.0, 0.25);
224 cairo_surface_t* surface;
226 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
227 tc = cairo_create (surface);
228 cairo_set_source (tc, pat);
229 cairo_rectangle (tc, 0, 0, width, height);
231 cairo_pattern_destroy (pat);
233 cairo_set_source (tc, shade_pattern);
234 cairo_rectangle (tc, 0, 0, width, height);
236 cairo_pattern_destroy (shade_pattern);
238 if (styleflags & 2) { // LED stripes
240 cairo_set_line_width(tc, 1.0);
241 cairo_set_source_rgba(tc, .0, .0, .0, 0.4);
242 //cairo_set_operator (tc, CAIRO_OPERATOR_SOURCE);
243 for (int i = 0; float y = 0.5 + i * 2.0; ++i) {
247 cairo_move_to(tc, 0, y);
248 cairo_line_to(tc, width, y);
254 pat = cairo_pattern_create_for_surface (surface);
256 cairo_surface_destroy (surface);
260 cairo_surface_t* surface;
262 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
263 tc = cairo_create (surface);
266 cairo_matrix_init_rotate (&m, -M_PI/2.0);
267 cairo_matrix_translate (&m, -height, 0);
268 cairo_pattern_set_matrix (pat, &m);
269 cairo_set_source (tc, pat);
270 cairo_rectangle (tc, 0, 0, height, width);
272 cairo_pattern_destroy (pat);
273 pat = cairo_pattern_create_for_surface (surface);
275 cairo_surface_destroy (surface);
277 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
283 Cairo::RefPtr<Cairo::Pattern>
284 FastMeter::generate_meter_background (
285 int width, int height, int *clr, bool shade, bool horiz)
287 guint8 r0,g0,b0,r1,g1,b1,a;
289 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
291 UINT_TO_RGBA (clr[0], &r0, &g0, &b0, &a);
292 UINT_TO_RGBA (clr[1], &r1, &g1, &b1, &a);
294 cairo_pattern_add_color_stop_rgb (pat, 0.0,
295 r1/255.0, g1/255.0, b1/255.0);
297 cairo_pattern_add_color_stop_rgb (pat, 1.0,
298 r0/255.0, g0/255.0, b0/255.0);
300 if (shade && !no_rgba_overlay) {
301 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
302 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.0, 1.0, 1.0, 1.0, 0.15);
303 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.6, 0.0, 0.0, 0.0, 0.10);
304 cairo_pattern_add_color_stop_rgba (shade_pattern, 1.0, 1.0, 1.0, 1.0, 0.20);
306 cairo_surface_t* surface;
308 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
309 tc = cairo_create (surface);
310 cairo_set_source (tc, pat);
311 cairo_rectangle (tc, 0, 0, width, height);
313 cairo_set_source (tc, shade_pattern);
314 cairo_rectangle (tc, 0, 0, width, height);
317 cairo_pattern_destroy (pat);
318 cairo_pattern_destroy (shade_pattern);
320 pat = cairo_pattern_create_for_surface (surface);
323 cairo_surface_destroy (surface);
327 cairo_surface_t* surface;
329 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
330 tc = cairo_create (surface);
333 cairo_matrix_init_rotate (&m, -M_PI/2.0);
334 cairo_matrix_translate (&m, -height, 0);
335 cairo_pattern_set_matrix (pat, &m);
336 cairo_set_source (tc, pat);
337 cairo_rectangle (tc, 0, 0, height, width);
339 cairo_pattern_destroy (pat);
340 pat = cairo_pattern_create_for_surface (surface);
342 cairo_surface_destroy (surface);
345 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
350 Cairo::RefPtr<Cairo::Pattern>
351 FastMeter::request_vertical_meter(
352 int width, int height, int *clr, float *stp, int styleflags)
354 height = max(height, min_pattern_metric_size);
355 height = min(height, max_pattern_metric_size);
357 const Pattern10MapKey key (width, height,
358 stp[0], stp[1], stp[2], stp[3],
359 clr[0], clr[1], clr[2], clr[3],
360 clr[4], clr[5], clr[6], clr[7],
361 clr[8], clr[9], styleflags);
363 Pattern10Map::iterator i;
364 if ((i = vm_pattern_cache.find (key)) != vm_pattern_cache.end()) {
367 // TODO flush pattern cache if it gets too large
369 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
370 width, height, clr, stp, styleflags, false);
371 vm_pattern_cache[key] = p;
376 Cairo::RefPtr<Cairo::Pattern>
377 FastMeter::request_vertical_background(
378 int width, int height, int *bgc, bool shade)
380 height = max(height, min_pattern_metric_size);
381 height = min(height, max_pattern_metric_size);
384 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
385 PatternBgMap::iterator i;
386 if ((i = vb_pattern_cache.find (key)) != vb_pattern_cache.end()) {
389 // TODO flush pattern cache if it gets too large
391 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
392 width, height, bgc, shade, false);
393 vb_pattern_cache[key] = p;
398 Cairo::RefPtr<Cairo::Pattern>
399 FastMeter::request_horizontal_meter(
400 int width, int height, int *clr, float *stp, int styleflags)
402 width = max(width, min_pattern_metric_size);
403 width = min(width, max_pattern_metric_size);
405 const Pattern10MapKey key (width, height,
406 stp[0], stp[1], stp[2], stp[3],
407 clr[0], clr[1], clr[2], clr[3],
408 clr[4], clr[5], clr[6], clr[7],
409 clr[8], clr[9], styleflags);
411 Pattern10Map::iterator i;
412 if ((i = hm_pattern_cache.find (key)) != hm_pattern_cache.end()) {
415 // TODO flush pattern cache if it gets too large
417 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
418 height, width, clr, stp, styleflags, true);
420 hm_pattern_cache[key] = p;
424 Cairo::RefPtr<Cairo::Pattern>
425 FastMeter::request_horizontal_background(
426 int width, int height, int *bgc, bool shade)
428 width = max(width, min_pattern_metric_size);
429 width = min(width, max_pattern_metric_size);
432 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
433 PatternBgMap::iterator i;
434 if ((i = hb_pattern_cache.find (key)) != hb_pattern_cache.end()) {
437 // TODO flush pattern cache if it gets too large
439 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
440 height, width, bgc, shade, true);
442 hb_pattern_cache[key] = p;
450 FastMeter::set_hold_count (long val)
464 FastMeter::on_size_request (GtkRequisition* req)
466 if (orientation == Vertical) {
467 vertical_size_request (req);
469 horizontal_size_request (req);
474 FastMeter::vertical_size_request (GtkRequisition* req)
476 req->height = request_height;
477 req->height = max(req->height, min_pattern_metric_size);
478 req->height = min(req->height, max_pattern_metric_size);
481 req->width = request_width;
485 FastMeter::horizontal_size_request (GtkRequisition* req)
487 req->width = request_width;
488 req->width = max(req->width, min_pattern_metric_size);
489 req->width = min(req->width, max_pattern_metric_size);
492 req->height = request_height;
496 FastMeter::on_size_allocate (Gtk::Allocation &alloc)
498 if (orientation == Vertical) {
499 vertical_size_allocate (alloc);
501 horizontal_size_allocate (alloc);
507 FastMeter::vertical_size_allocate (Gtk::Allocation &alloc)
509 if (alloc.get_width() != request_width) {
510 alloc.set_width (request_width);
513 int h = alloc.get_height();
514 h = max (h, min_pattern_metric_size + 2);
515 h = min (h, max_pattern_metric_size + 2);
517 if (h != alloc.get_height()) {
518 alloc.set_height (h);
521 if (pixheight != h) {
522 fgpattern = request_vertical_meter (request_width, h, _clr, _stp, _styleflags);
523 bgpattern = request_vertical_background (request_width, h, highlight ? _bgh : _bgc, highlight);
525 pixwidth = request_width - 2;
528 CairoWidget::on_size_allocate (alloc);
532 FastMeter::horizontal_size_allocate (Gtk::Allocation &alloc)
534 if (alloc.get_height() != request_height) {
535 alloc.set_height (request_height);
538 int w = alloc.get_width();
539 w = max (w, min_pattern_metric_size + 2);
540 w = min (w, max_pattern_metric_size + 2);
542 if (w != alloc.get_width()) {
547 fgpattern = request_horizontal_meter (w, request_height, _clr, _stp, _styleflags);
548 bgpattern = request_horizontal_background (w, request_height, highlight ? _bgh : _bgc, highlight);
550 pixheight = request_height - 2;
553 CairoWidget::on_size_allocate (alloc);
557 FastMeter::render (cairo_t* cr, cairo_rectangle_t* area)
559 if (orientation == Vertical) {
560 return vertical_expose (cr, area);
562 return horizontal_expose (cr, area);
567 FastMeter::vertical_expose (cairo_t* cr, cairo_rectangle_t* area)
570 GdkRectangle intersection;
571 GdkRectangle background;
572 GdkRectangle eventarea;
574 cairo_set_source_rgb (cr, 0, 0, 0); // black
575 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
578 top_of_meter = (gint) floor (pixheight * current_level);
580 /* reset the height & origin of the rect that needs to show the pixbuf
583 pixrect.height = top_of_meter;
584 pixrect.y = 1 + pixheight - top_of_meter;
588 background.width = pixrect.width;
589 background.height = pixheight - top_of_meter;
591 eventarea.x = area->x;
592 eventarea.y = area->y;
593 eventarea.width = area->width;
594 eventarea.height = area->height;
596 if (gdk_rectangle_intersect (&background, &eventarea, &intersection)) {
597 cairo_set_source (cr, bgpattern->cobj());
598 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
602 if (gdk_rectangle_intersect (&pixrect, &eventarea, &intersection)) {
603 // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
604 cairo_set_source (cr, fgpattern->cobj());
605 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
612 last_peak_rect.x = 1;
613 last_peak_rect.width = pixwidth;
614 last_peak_rect.y = max(1, 1 + pixheight - (int) floor (pixheight * current_peak));
615 if (_styleflags & 2) { // LED stripes
616 last_peak_rect.y = max(0, (last_peak_rect.y & (~1)));
618 if (bright_hold || (_styleflags & 2)) {
619 last_peak_rect.height = max(0, min(3, pixheight - last_peak_rect.y - 1 ));
621 last_peak_rect.height = max(0, min(2, pixheight - last_peak_rect.y - 1 ));
624 cairo_set_source (cr, fgpattern->cobj());
625 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
627 if (bright_hold && !no_rgba_overlay) {
628 cairo_fill_preserve (cr);
629 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
634 last_peak_rect.width = 0;
635 last_peak_rect.height = 0;
640 FastMeter::horizontal_expose (cairo_t* cr, cairo_rectangle_t* area)
643 GdkRectangle intersection;
644 GdkRectangle background;
645 GdkRectangle eventarea;
647 cairo_set_source_rgb (cr, 0, 0, 0); // black
648 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
651 right_of_meter = (gint) floor (pixwidth * current_level);
653 /* reset the height & origin of the rect that needs to show the pixbuf
656 pixrect.width = right_of_meter;
658 background.x = 1 + right_of_meter;
660 background.width = pixwidth - right_of_meter;
661 background.height = pixheight;
663 eventarea.x = area->x;
664 eventarea.y = area->y;
665 eventarea.width = area->width;
666 eventarea.height = area->height;
668 if (gdk_rectangle_intersect (&background, &eventarea, &intersection)) {
669 cairo_set_source (cr, bgpattern->cobj());
670 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
674 if (gdk_rectangle_intersect (&pixrect, &eventarea, &intersection)) {
675 cairo_set_source (cr, fgpattern->cobj());
676 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
683 last_peak_rect.y = 1;
684 last_peak_rect.height = pixheight;
685 const int xpos = floor (pixwidth * current_peak);
686 if (bright_hold || (_styleflags & 2)) {
687 last_peak_rect.width = min(3, xpos );
689 last_peak_rect.width = min(2, xpos );
691 last_peak_rect.x = 1 + max(0, xpos - last_peak_rect.width);
693 cairo_set_source (cr, fgpattern->cobj());
694 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
696 if (bright_hold && !no_rgba_overlay) {
697 cairo_fill_preserve (cr);
698 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
703 last_peak_rect.width = 0;
704 last_peak_rect.height = 0;
709 FastMeter::set (float lvl, float peak)
711 float old_level = current_level;
712 float old_peak = current_peak;
714 if (pixwidth <= 0 || pixheight <=0) return;
717 if (lvl >= current_peak) {
719 hold_state = hold_cnt;
722 if (hold_state > 0) {
723 if (--hold_state == 0) {
736 const float pixscale = (orientation == Vertical) ? pixheight : pixwidth;
737 #define PIX(X) floor(pixscale * (X))
738 if (PIX(current_level) == PIX(old_level) && PIX(current_peak) == PIX(old_peak) && (hold_state == 0 || peak != -1)) {
742 Glib::RefPtr<Gdk::Window> win;
744 if ((win = get_window()) == 0) {
749 if (orientation == Vertical) {
750 queue_vertical_redraw (win, old_level);
752 queue_horizontal_redraw (win, old_level);
757 FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
761 gint new_top = (gint) floor (pixheight * current_level);
764 rect.width = pixwidth;
765 rect.height = new_top;
766 rect.y = 1 + pixheight - new_top;
768 if (current_level > old_level) {
769 /* colored/pixbuf got larger, just draw the new section */
770 /* rect.y stays where it is because of X coordinates */
771 /* height of invalidated area is between new.y (smaller) and old.y
773 X coordinates just make my brain hurt.
775 rect.height = pixrect.y - rect.y;
777 /* it got smaller, compute the difference */
778 /* rect.y becomes old.y (the smaller value) */
780 /* rect.height is the old.y (smaller) minus the new.y (larger)
782 rect.height = pixrect.height - rect.height;
785 GdkRegion* region = 0;
788 if (rect.height != 0) {
790 /* ok, first region to draw ... */
792 region = gdk_region_rectangle (&rect);
796 /* redraw the last place where the last peak hold bar was;
797 the next expose will draw the new one whether its part of
798 expose region or not.
801 if (last_peak_rect.width * last_peak_rect.height != 0) {
803 region = gdk_region_new ();
806 gdk_region_union_with_rect (region, &last_peak_rect);
809 if (hold_state && current_peak > 0) {
811 region = gdk_region_new ();
815 rect.y = max(1, 1 + pixheight - (int) floor (pixheight * current_peak));
816 if (_styleflags & 2) { // LED stripes
817 rect.y = max(0, (rect.y & (~1)));
819 if (bright_hold || (_styleflags & 2)) {
820 rect.height = max(0, min(3, pixheight - last_peak_rect.y -1 ));
822 rect.height = max(0, min(2, pixheight - last_peak_rect.y -1 ));
824 rect.width = pixwidth;
825 gdk_region_union_with_rect (region, &rect);
829 gdk_window_invalidate_region (win->gobj(), region, true);
832 gdk_region_destroy(region);
838 FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
842 gint new_right = (gint) floor (pixwidth * current_level);
844 rect.height = pixheight;
847 if (current_level > old_level) {
848 rect.x = 1 + pixrect.width;
849 /* colored/pixbuf got larger, just draw the new section */
850 rect.width = new_right - pixrect.width;
852 /* it got smaller, compute the difference */
853 rect.x = 1 + new_right;
854 /* rect.height is the old.x (smaller) minus the new.x (larger) */
855 rect.width = pixrect.width - new_right;
858 GdkRegion* region = 0;
861 if (rect.height != 0) {
863 /* ok, first region to draw ... */
865 region = gdk_region_rectangle (&rect);
869 /* redraw the last place where the last peak hold bar was;
870 the next expose will draw the new one whether its part of
871 expose region or not.
874 if (last_peak_rect.width * last_peak_rect.height != 0) {
876 region = gdk_region_new ();
879 gdk_region_union_with_rect (region, &last_peak_rect);
882 if (hold_state && current_peak > 0) {
884 region = gdk_region_new ();
888 rect.height = pixheight;
889 const int xpos = floor (pixwidth * current_peak);
890 if (bright_hold || (_styleflags & 2)) {
891 rect.width = min(3, xpos);
893 rect.width = min(2, xpos);
895 rect.x = 1 + max(0, xpos - rect.width);
896 gdk_region_union_with_rect (region, &rect);
900 gdk_window_invalidate_region (win->gobj(), region, true);
903 gdk_region_destroy(region);
909 FastMeter::set_highlight (bool onoff)
911 if (highlight == onoff) {
915 if (orientation == Vertical) {
916 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);
918 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);