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 (float y=0.5; y < height; y+= 2.0) {
244 cairo_move_to(tc, 0, y);
245 cairo_line_to(tc, width, y);
251 pat = cairo_pattern_create_for_surface (surface);
253 cairo_surface_destroy (surface);
257 cairo_surface_t* surface;
259 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
260 tc = cairo_create (surface);
263 cairo_matrix_init_rotate (&m, -M_PI/2.0);
264 cairo_matrix_translate (&m, -height, 0);
265 cairo_pattern_set_matrix (pat, &m);
266 cairo_set_source (tc, pat);
267 cairo_rectangle (tc, 0, 0, height, width);
269 cairo_pattern_destroy (pat);
270 pat = cairo_pattern_create_for_surface (surface);
272 cairo_surface_destroy (surface);
274 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
280 Cairo::RefPtr<Cairo::Pattern>
281 FastMeter::generate_meter_background (
282 int width, int height, int *clr, bool shade, bool horiz)
284 guint8 r0,g0,b0,r1,g1,b1,a;
286 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
288 UINT_TO_RGBA (clr[0], &r0, &g0, &b0, &a);
289 UINT_TO_RGBA (clr[1], &r1, &g1, &b1, &a);
291 cairo_pattern_add_color_stop_rgb (pat, 0.0,
292 r1/255.0, g1/255.0, b1/255.0);
294 cairo_pattern_add_color_stop_rgb (pat, 1.0,
295 r0/255.0, g0/255.0, b0/255.0);
297 if (shade && !no_rgba_overlay) {
298 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
299 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.0, 1.0, 1.0, 1.0, 0.15);
300 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.6, 0.0, 0.0, 0.0, 0.10);
301 cairo_pattern_add_color_stop_rgba (shade_pattern, 1.0, 1.0, 1.0, 1.0, 0.20);
303 cairo_surface_t* surface;
305 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
306 tc = cairo_create (surface);
307 cairo_set_source (tc, pat);
308 cairo_rectangle (tc, 0, 0, width, height);
310 cairo_set_source (tc, shade_pattern);
311 cairo_rectangle (tc, 0, 0, width, height);
314 cairo_pattern_destroy (pat);
315 cairo_pattern_destroy (shade_pattern);
317 pat = cairo_pattern_create_for_surface (surface);
320 cairo_surface_destroy (surface);
324 cairo_surface_t* surface;
326 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
327 tc = cairo_create (surface);
330 cairo_matrix_init_rotate (&m, -M_PI/2.0);
331 cairo_matrix_translate (&m, -height, 0);
332 cairo_pattern_set_matrix (pat, &m);
333 cairo_set_source (tc, pat);
334 cairo_rectangle (tc, 0, 0, height, width);
336 cairo_pattern_destroy (pat);
337 pat = cairo_pattern_create_for_surface (surface);
339 cairo_surface_destroy (surface);
342 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
347 Cairo::RefPtr<Cairo::Pattern>
348 FastMeter::request_vertical_meter(
349 int width, int height, int *clr, float *stp, int styleflags)
351 height = max(height, min_pattern_metric_size);
352 height = min(height, max_pattern_metric_size);
354 const Pattern10MapKey key (width, height,
355 stp[0], stp[1], stp[2], stp[3],
356 clr[0], clr[1], clr[2], clr[3],
357 clr[4], clr[5], clr[6], clr[7],
358 clr[8], clr[9], styleflags);
360 Pattern10Map::iterator i;
361 if ((i = vm_pattern_cache.find (key)) != vm_pattern_cache.end()) {
364 // TODO flush pattern cache if it gets too large
366 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
367 width, height, clr, stp, styleflags, false);
368 vm_pattern_cache[key] = p;
373 Cairo::RefPtr<Cairo::Pattern>
374 FastMeter::request_vertical_background(
375 int width, int height, int *bgc, bool shade)
377 height = max(height, min_pattern_metric_size);
378 height = min(height, max_pattern_metric_size);
381 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
382 PatternBgMap::iterator i;
383 if ((i = vb_pattern_cache.find (key)) != vb_pattern_cache.end()) {
386 // TODO flush pattern cache if it gets too large
388 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
389 width, height, bgc, shade, false);
390 vb_pattern_cache[key] = p;
395 Cairo::RefPtr<Cairo::Pattern>
396 FastMeter::request_horizontal_meter(
397 int width, int height, int *clr, float *stp, int styleflags)
399 width = max(width, min_pattern_metric_size);
400 width = min(width, max_pattern_metric_size);
402 const Pattern10MapKey key (width, height,
403 stp[0], stp[1], stp[2], stp[3],
404 clr[0], clr[1], clr[2], clr[3],
405 clr[4], clr[5], clr[6], clr[7],
406 clr[8], clr[9], styleflags);
408 Pattern10Map::iterator i;
409 if ((i = hm_pattern_cache.find (key)) != hm_pattern_cache.end()) {
412 // TODO flush pattern cache if it gets too large
414 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
415 height, width, clr, stp, styleflags, true);
417 hm_pattern_cache[key] = p;
421 Cairo::RefPtr<Cairo::Pattern>
422 FastMeter::request_horizontal_background(
423 int width, int height, int *bgc, bool shade)
425 width = max(width, min_pattern_metric_size);
426 width = min(width, max_pattern_metric_size);
429 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
430 PatternBgMap::iterator i;
431 if ((i = hb_pattern_cache.find (key)) != hb_pattern_cache.end()) {
434 // TODO flush pattern cache if it gets too large
436 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
437 height, width, bgc, shade, true);
439 hb_pattern_cache[key] = p;
447 FastMeter::set_hold_count (long val)
461 FastMeter::on_size_request (GtkRequisition* req)
463 if (orientation == Vertical) {
464 vertical_size_request (req);
466 horizontal_size_request (req);
471 FastMeter::vertical_size_request (GtkRequisition* req)
473 req->height = request_height;
474 req->height = max(req->height, min_pattern_metric_size);
475 req->height = min(req->height, max_pattern_metric_size);
478 req->width = request_width;
482 FastMeter::horizontal_size_request (GtkRequisition* req)
484 req->width = request_width;
485 req->width = max(req->width, min_pattern_metric_size);
486 req->width = min(req->width, max_pattern_metric_size);
489 req->height = request_height;
493 FastMeter::on_size_allocate (Gtk::Allocation &alloc)
495 if (orientation == Vertical) {
496 vertical_size_allocate (alloc);
498 horizontal_size_allocate (alloc);
504 FastMeter::vertical_size_allocate (Gtk::Allocation &alloc)
506 if (alloc.get_width() != request_width) {
507 alloc.set_width (request_width);
510 int h = alloc.get_height();
511 h = max (h, min_pattern_metric_size + 2);
512 h = min (h, max_pattern_metric_size + 2);
514 if (h != alloc.get_height()) {
515 alloc.set_height (h);
518 if (pixheight != h) {
519 fgpattern = request_vertical_meter (request_width, h, _clr, _stp, _styleflags);
520 bgpattern = request_vertical_background (request_width, h, highlight ? _bgh : _bgc, highlight);
522 pixwidth = request_width - 2;
525 CairoWidget::on_size_allocate (alloc);
529 FastMeter::horizontal_size_allocate (Gtk::Allocation &alloc)
531 if (alloc.get_height() != request_height) {
532 alloc.set_height (request_height);
535 int w = alloc.get_width();
536 w = max (w, min_pattern_metric_size + 2);
537 w = min (w, max_pattern_metric_size + 2);
539 if (w != alloc.get_width()) {
544 fgpattern = request_horizontal_meter (w, request_height, _clr, _stp, _styleflags);
545 bgpattern = request_horizontal_background (w, request_height, highlight ? _bgh : _bgc, highlight);
547 pixheight = request_height - 2;
550 CairoWidget::on_size_allocate (alloc);
554 FastMeter::render (cairo_t* cr, cairo_rectangle_t* area)
556 if (orientation == Vertical) {
557 return vertical_expose (cr, area);
559 return horizontal_expose (cr, area);
564 FastMeter::vertical_expose (cairo_t* cr, cairo_rectangle_t* area)
567 GdkRectangle intersection;
568 GdkRectangle background;
569 GdkRectangle eventarea;
571 cairo_set_source_rgb (cr, 0, 0, 0); // black
572 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
575 top_of_meter = (gint) floor (pixheight * current_level);
577 /* reset the height & origin of the rect that needs to show the pixbuf
580 pixrect.height = top_of_meter;
581 pixrect.y = 1 + pixheight - top_of_meter;
585 background.width = pixrect.width;
586 background.height = pixheight - top_of_meter;
588 eventarea.x = area->x;
589 eventarea.y = area->y;
590 eventarea.width = area->width;
591 eventarea.height = area->height;
593 if (gdk_rectangle_intersect (&background, &eventarea, &intersection)) {
594 cairo_set_source (cr, bgpattern->cobj());
595 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
599 if (gdk_rectangle_intersect (&pixrect, &eventarea, &intersection)) {
600 // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
601 cairo_set_source (cr, fgpattern->cobj());
602 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
609 last_peak_rect.x = 1;
610 last_peak_rect.width = pixwidth;
611 last_peak_rect.y = max(1, 1 + pixheight - (int) floor (pixheight * current_peak));
612 if (_styleflags & 2) { // LED stripes
613 last_peak_rect.y = max(0, (last_peak_rect.y & (~1)));
615 if (bright_hold || (_styleflags & 2)) {
616 last_peak_rect.height = max(0, min(3, pixheight - last_peak_rect.y - 1 ));
618 last_peak_rect.height = max(0, min(2, pixheight - last_peak_rect.y - 1 ));
621 cairo_set_source (cr, fgpattern->cobj());
622 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
624 if (bright_hold && !no_rgba_overlay) {
625 cairo_fill_preserve (cr);
626 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
631 last_peak_rect.width = 0;
632 last_peak_rect.height = 0;
637 FastMeter::horizontal_expose (cairo_t* cr, cairo_rectangle_t* area)
640 GdkRectangle intersection;
641 GdkRectangle background;
642 GdkRectangle eventarea;
644 cairo_set_source_rgb (cr, 0, 0, 0); // black
645 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
648 right_of_meter = (gint) floor (pixwidth * current_level);
650 /* reset the height & origin of the rect that needs to show the pixbuf
653 pixrect.width = right_of_meter;
655 background.x = 1 + right_of_meter;
657 background.width = pixwidth - right_of_meter;
658 background.height = pixheight;
660 eventarea.x = area->x;
661 eventarea.y = area->y;
662 eventarea.width = area->width;
663 eventarea.height = area->height;
665 if (gdk_rectangle_intersect (&background, &eventarea, &intersection)) {
666 cairo_set_source (cr, bgpattern->cobj());
667 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
671 if (gdk_rectangle_intersect (&pixrect, &eventarea, &intersection)) {
672 cairo_set_source (cr, fgpattern->cobj());
673 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
680 last_peak_rect.y = 1;
681 last_peak_rect.height = pixheight;
682 const int xpos = floor (pixwidth * current_peak);
683 if (bright_hold || (_styleflags & 2)) {
684 last_peak_rect.width = min(3, xpos );
686 last_peak_rect.width = min(2, xpos );
688 last_peak_rect.x = 1 + max(0, xpos - last_peak_rect.width);
690 cairo_set_source (cr, fgpattern->cobj());
691 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
693 if (bright_hold && !no_rgba_overlay) {
694 cairo_fill_preserve (cr);
695 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
700 last_peak_rect.width = 0;
701 last_peak_rect.height = 0;
706 FastMeter::set (float lvl, float peak)
708 float old_level = current_level;
709 float old_peak = current_peak;
711 if (pixwidth <= 0 || pixheight <=0) return;
714 if (lvl >= current_peak) {
716 hold_state = hold_cnt;
719 if (hold_state > 0) {
720 if (--hold_state == 0) {
733 const float pixscale = (orientation == Vertical) ? pixheight : pixwidth;
734 #define PIX(X) floor(pixscale * (X))
735 if (PIX(current_level) == PIX(old_level) && PIX(current_peak) == PIX(old_peak) && (hold_state == 0 || peak != -1)) {
739 Glib::RefPtr<Gdk::Window> win;
741 if ((win = get_window()) == 0) {
746 if (orientation == Vertical) {
747 queue_vertical_redraw (win, old_level);
749 queue_horizontal_redraw (win, old_level);
754 FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
758 gint new_top = (gint) floor (pixheight * current_level);
761 rect.width = pixwidth;
762 rect.height = new_top;
763 rect.y = 1 + pixheight - new_top;
765 if (current_level > old_level) {
766 /* colored/pixbuf got larger, just draw the new section */
767 /* rect.y stays where it is because of X coordinates */
768 /* height of invalidated area is between new.y (smaller) and old.y
770 X coordinates just make my brain hurt.
772 rect.height = pixrect.y - rect.y;
774 /* it got smaller, compute the difference */
775 /* rect.y becomes old.y (the smaller value) */
777 /* rect.height is the old.y (smaller) minus the new.y (larger)
779 rect.height = pixrect.height - rect.height;
782 GdkRegion* region = 0;
785 if (rect.height != 0) {
787 /* ok, first region to draw ... */
789 region = gdk_region_rectangle (&rect);
793 /* redraw the last place where the last peak hold bar was;
794 the next expose will draw the new one whether its part of
795 expose region or not.
798 if (last_peak_rect.width * last_peak_rect.height != 0) {
800 region = gdk_region_new ();
803 gdk_region_union_with_rect (region, &last_peak_rect);
806 if (hold_state && current_peak > 0) {
808 region = gdk_region_new ();
812 rect.y = max(1, 1 + pixheight - (int) floor (pixheight * current_peak));
813 if (_styleflags & 2) { // LED stripes
814 rect.y = max(0, (rect.y & (~1)));
816 if (bright_hold || (_styleflags & 2)) {
817 rect.height = max(0, min(3, pixheight - last_peak_rect.y -1 ));
819 rect.height = max(0, min(2, pixheight - last_peak_rect.y -1 ));
821 rect.width = pixwidth;
822 gdk_region_union_with_rect (region, &rect);
826 gdk_window_invalidate_region (win->gobj(), region, true);
829 gdk_region_destroy(region);
835 FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
839 gint new_right = (gint) floor (pixwidth * current_level);
841 rect.height = pixheight;
844 if (current_level > old_level) {
845 rect.x = 1 + pixrect.width;
846 /* colored/pixbuf got larger, just draw the new section */
847 rect.width = new_right - pixrect.width;
849 /* it got smaller, compute the difference */
850 rect.x = 1 + new_right;
851 /* rect.height is the old.x (smaller) minus the new.x (larger) */
852 rect.width = pixrect.width - new_right;
855 GdkRegion* region = 0;
858 if (rect.height != 0) {
860 /* ok, first region to draw ... */
862 region = gdk_region_rectangle (&rect);
866 /* redraw the last place where the last peak hold bar was;
867 the next expose will draw the new one whether its part of
868 expose region or not.
871 if (last_peak_rect.width * last_peak_rect.height != 0) {
873 region = gdk_region_new ();
876 gdk_region_union_with_rect (region, &last_peak_rect);
879 if (hold_state && current_peak > 0) {
881 region = gdk_region_new ();
885 rect.height = pixheight;
886 const int xpos = floor (pixwidth * current_peak);
887 if (bright_hold || (_styleflags & 2)) {
888 rect.width = min(3, xpos);
890 rect.width = min(2, xpos);
892 rect.x = 1 + max(0, xpos - rect.width);
893 gdk_region_union_with_rect (region, &rect);
897 gdk_window_invalidate_region (win->gobj(), region, true);
900 gdk_region_destroy(region);
906 FastMeter::set_highlight (bool onoff)
908 if (highlight == onoff) {
912 if (orientation == Vertical) {
913 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);
915 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);