2 Copyright (C) 2003-2016 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 <gtkmm2ext/utils.h>
31 #include <gtkmm2ext/rgb_macros.h>
33 #include "canvas/canvas.h"
34 #include "gtkmm2ext/colors.h"
35 #include "canvas/meter.h"
39 using namespace ArdourCanvas;
40 using namespace Gtkmm2ext;
42 int Meter::min_pattern_metric_size = 16;
43 int Meter::max_pattern_metric_size = 1024;
44 bool Meter::no_rgba_overlay = false;
46 Meter::Pattern10Map Meter::vm_pattern_cache;
47 Meter::PatternBgMap Meter::vb_pattern_cache;
49 Meter::Pattern10Map Meter::hm_pattern_cache;
50 Meter::PatternBgMap Meter::hb_pattern_cache;
52 Meter::Meter (Item* parent, 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,
65 , _styleflags(styleflags)
74 init (clr0, clr1, clr2, clr3, clr4, clr5, clr6, clr7, clr8, clr9, bgc0, bgc1, bgh0, bgh1, stp0, stp1, stp2, stp3, dimen, len);
77 Meter::Meter (Canvas* canvas, long hold, unsigned long dimen, Orientation o, int len,
78 int clr0, int clr1, int clr2, int clr3,
79 int clr4, int clr5, int clr6, int clr7,
83 float stp0, float stp1,
84 float stp2, float stp3,
90 , _styleflags(styleflags)
99 init (clr0, clr1, clr2, clr3, clr4, clr5, clr6, clr7, clr8, clr9, bgc0, bgc1, bgh0, bgh1, stp0, stp1, stp2, stp3, dimen, len);
103 Meter::init (int clr0, int clr1, int clr2, int clr3,
104 int clr4, int clr5, int clr6, int clr7,
108 float stp0, float stp1,
109 float stp2, float stp3,
113 last_peak_rect.width = 0;
114 last_peak_rect.height = 0;
115 last_peak_rect.x = 0;
116 last_peak_rect.y = 0;
118 no_rgba_overlay = ! Glib::getenv("NO_METER_SHADE").empty();
146 if (orientation == Vertical) {
149 fgpattern = vertical_meter_pattern (pixwidth + 2, pixheight + 2, _clr, _stp, _styleflags);
150 bgpattern = vertical_background (pixwidth + 2, pixheight + 2, _bgc, false);
154 fgpattern = horizontal_meter_pattern (pixwidth + 2, pixheight + 2, _clr, _stp, _styleflags);
155 bgpattern = horizontal_background (pixwidth + 2, pixheight + 2, _bgc, false);
158 pixrect.height = pixheight;
161 if (orientation == Vertical) {
162 pixrect.width = pixwidth;
163 pixrect.y = pixheight; /* bottom of meter, so essentially "show zero" */
165 pixrect.width = 0; /* right of meter, so essentially "show zero" */
171 Meter::compute_bounding_box () const
174 _bounding_box = Rect ();
175 _bounding_box_dirty = false;
179 Rect r (0, 0, pixwidth + 2, pixheight + 2);
181 _bounding_box_dirty = false;
190 Meter::flush_pattern_cache () {
191 hb_pattern_cache.clear();
192 hm_pattern_cache.clear();
193 vb_pattern_cache.clear();
194 vm_pattern_cache.clear();
197 Cairo::RefPtr<Cairo::Pattern>
198 Meter::generate_meter_pattern (int width, int height, int *clr, float *stp, int styleflags, bool horiz)
202 const double soft = 3.0 / (double) height;
203 const double offs = -1.0 / (double) height;
205 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
208 Cairo coordinate space goes downwards as y value goes up, so invert
209 knee-based positions by using (1.0 - y)
212 UINT_TO_RGBA (clr[9], &r, &g, &b, &a); // top/clip
213 cairo_pattern_add_color_stop_rgb (pat, 0.0,
214 r/255.0, g/255.0, b/255.0);
216 knee = offs + stp[3] / 115.0f; // -0dB
218 UINT_TO_RGBA (clr[8], &r, &g, &b, &a);
219 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
220 r/255.0, g/255.0, b/255.0);
222 UINT_TO_RGBA (clr[7], &r, &g, &b, &a);
223 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
224 r/255.0, g/255.0, b/255.0);
226 knee = offs + stp[2]/ 115.0f; // -3dB || -2dB
228 UINT_TO_RGBA (clr[6], &r, &g, &b, &a);
229 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
230 r/255.0, g/255.0, b/255.0);
232 UINT_TO_RGBA (clr[5], &r, &g, &b, &a);
233 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
234 r/255.0, g/255.0, b/255.0);
236 knee = offs + stp[1] / 115.0f; // -9dB
238 UINT_TO_RGBA (clr[4], &r, &g, &b, &a);
239 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
240 r/255.0, g/255.0, b/255.0);
242 UINT_TO_RGBA (clr[3], &r, &g, &b, &a);
243 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
244 r/255.0, g/255.0, b/255.0);
246 knee = offs + stp[0] / 115.0f; // -18dB
248 UINT_TO_RGBA (clr[2], &r, &g, &b, &a);
249 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
250 r/255.0, g/255.0, b/255.0);
252 UINT_TO_RGBA (clr[1], &r, &g, &b, &a);
253 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
254 r/255.0, g/255.0, b/255.0);
256 UINT_TO_RGBA (clr[0], &r, &g, &b, &a); // bottom
257 cairo_pattern_add_color_stop_rgb (pat, 1.0,
258 r/255.0, g/255.0, b/255.0);
260 if ((styleflags & 1) && !no_rgba_overlay) {
261 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
262 cairo_pattern_add_color_stop_rgba (shade_pattern, 0, 0.0, 0.0, 0.0, 0.15);
263 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.4, 1.0, 1.0, 1.0, 0.05);
264 cairo_pattern_add_color_stop_rgba (shade_pattern, 1, 0.0, 0.0, 0.0, 0.25);
266 cairo_surface_t* surface;
268 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
269 tc = cairo_create (surface);
270 cairo_set_source (tc, pat);
271 cairo_rectangle (tc, 0, 0, width, height);
273 cairo_pattern_destroy (pat);
275 cairo_set_source (tc, shade_pattern);
276 cairo_rectangle (tc, 0, 0, width, height);
278 cairo_pattern_destroy (shade_pattern);
280 if (styleflags & 2) { // LED stripes
282 cairo_set_line_width(tc, 1.0);
283 cairo_set_source_rgba(tc, .0, .0, .0, 0.4);
284 //cairo_set_operator (tc, CAIRO_OPERATOR_SOURCE);
285 for (int i = 0; float y = 0.5 + i * 2.0; ++i) {
289 cairo_move_to(tc, 0, y);
290 cairo_line_to(tc, width, y);
296 pat = cairo_pattern_create_for_surface (surface);
298 cairo_surface_destroy (surface);
302 cairo_surface_t* surface;
304 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
305 tc = cairo_create (surface);
308 cairo_matrix_init_rotate (&m, -M_PI/2.0);
309 cairo_matrix_translate (&m, -height, 0);
310 cairo_pattern_set_matrix (pat, &m);
311 cairo_set_source (tc, pat);
312 cairo_rectangle (tc, 0, 0, height, width);
314 cairo_pattern_destroy (pat);
315 pat = cairo_pattern_create_for_surface (surface);
317 cairo_surface_destroy (surface);
319 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
325 Cairo::RefPtr<Cairo::Pattern>
326 Meter::generate_meter_background (int width, int height, int *clr, bool shade, bool horiz)
328 guint8 r0,g0,b0,r1,g1,b1,a;
330 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
332 UINT_TO_RGBA (clr[0], &r0, &g0, &b0, &a);
333 UINT_TO_RGBA (clr[1], &r1, &g1, &b1, &a);
335 cairo_pattern_add_color_stop_rgb (pat, 0.0,
336 r1/255.0, g1/255.0, b1/255.0);
338 cairo_pattern_add_color_stop_rgb (pat, 1.0,
339 r0/255.0, g0/255.0, b0/255.0);
341 if (shade && !no_rgba_overlay) {
342 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
343 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.0, 1.0, 1.0, 1.0, 0.15);
344 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.6, 0.0, 0.0, 0.0, 0.10);
345 cairo_pattern_add_color_stop_rgba (shade_pattern, 1.0, 1.0, 1.0, 1.0, 0.20);
347 cairo_surface_t* surface;
349 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
350 tc = cairo_create (surface);
351 cairo_set_source (tc, pat);
352 cairo_rectangle (tc, 0, 0, width, height);
354 cairo_set_source (tc, shade_pattern);
355 cairo_rectangle (tc, 0, 0, width, height);
358 cairo_pattern_destroy (pat);
359 cairo_pattern_destroy (shade_pattern);
361 pat = cairo_pattern_create_for_surface (surface);
364 cairo_surface_destroy (surface);
368 cairo_surface_t* surface;
370 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
371 tc = cairo_create (surface);
374 cairo_matrix_init_rotate (&m, -M_PI/2.0);
375 cairo_matrix_translate (&m, -height, 0);
376 cairo_pattern_set_matrix (pat, &m);
377 cairo_set_source (tc, pat);
378 cairo_rectangle (tc, 0, 0, height, width);
380 cairo_pattern_destroy (pat);
381 pat = cairo_pattern_create_for_surface (surface);
383 cairo_surface_destroy (surface);
386 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
391 Cairo::RefPtr<Cairo::Pattern>
392 Meter::vertical_meter_pattern (int width, int height, int *clr, float *stp, int styleflags)
394 height = max(height, min_pattern_metric_size);
395 height = min(height, max_pattern_metric_size);
397 const Pattern10MapKey key (width, height,
398 stp[0], stp[1], stp[2], stp[3],
399 clr[0], clr[1], clr[2], clr[3],
400 clr[4], clr[5], clr[6], clr[7],
401 clr[8], clr[9], styleflags);
403 Pattern10Map::iterator i;
404 if ((i = vm_pattern_cache.find (key)) != vm_pattern_cache.end()) {
407 // TODO flush pattern cache if it gets too large
409 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (width, height, clr, stp, styleflags, false);
410 vm_pattern_cache[key] = p;
415 Cairo::RefPtr<Cairo::Pattern>
416 Meter::vertical_background (int width, int height, int *bgc, bool shade)
418 height = max(height, min_pattern_metric_size);
419 height = min(height, max_pattern_metric_size);
422 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
423 PatternBgMap::iterator i;
425 if ((i = vb_pattern_cache.find (key)) != vb_pattern_cache.end()) {
428 // TODO flush pattern cache if it gets too large
430 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (width, height, bgc, shade, false);
431 vb_pattern_cache[key] = p;
436 Cairo::RefPtr<Cairo::Pattern>
437 Meter::horizontal_meter_pattern (int width, int height, int *clr, float *stp, int styleflags)
439 width = max(width, min_pattern_metric_size);
440 width = min(width, max_pattern_metric_size);
442 const Pattern10MapKey key (width, height,
443 stp[0], stp[1], stp[2], stp[3],
444 clr[0], clr[1], clr[2], clr[3],
445 clr[4], clr[5], clr[6], clr[7],
446 clr[8], clr[9], styleflags);
448 Pattern10Map::iterator i;
449 if ((i = hm_pattern_cache.find (key)) != hm_pattern_cache.end()) {
452 // TODO flush pattern cache if it gets too large
454 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (height, width, clr, stp, styleflags, true);
456 hm_pattern_cache[key] = p;
460 Cairo::RefPtr<Cairo::Pattern>
461 Meter::horizontal_background (int width, int height, int *bgc, bool shade)
463 width = max(width, min_pattern_metric_size);
464 width = min(width, max_pattern_metric_size);
467 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
468 PatternBgMap::iterator i;
469 if ((i = hb_pattern_cache.find (key)) != hb_pattern_cache.end()) {
472 // TODO flush pattern cache if it gets too large
474 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (height, width, bgc, shade, true);
476 hb_pattern_cache[key] = p;
482 Meter::set_hold_count (long val)
496 Meter::render (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
498 if (orientation == Vertical) {
499 return vertical_expose (area, context);
501 return horizontal_expose (area, context);
506 Meter::vertical_expose (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
509 Cairo::RectangleInt background;
510 Cairo::RectangleInt area_r;
512 /* convert expose area back to item coordinate space */
513 Rect area2 = window_to_item (area);
517 area_r.width = area2.width();
518 area_r.height = area2.height();
520 context->set_source_rgb (0, 0, 0); // black
521 rounded_rectangle (context, 0, 0, pixwidth + 2, pixheight + 2, 2);
524 top_of_meter = (gint) floor (pixheight * current_level);
526 /* reset the height & origin of the rect that needs to show the meter pattern
528 pixrect.height = top_of_meter;
530 /* X/cairo coordinates; y grows down so y origin of pixrect (pattern
531 fill area) is the TOP of the pattern area, which we compute like this:
534 - go to bottom of meter (pixheight)
535 - back up by current meter height (top_of_meter)
537 pixrect.y = 1 + pixheight - top_of_meter;
541 background.width = pixrect.width;
542 background.height = pixheight - top_of_meter;
544 /* translate so that item coordinates match window coordinates */
546 origin = item_to_window (origin);
547 context->translate (origin.x, origin.y);
549 Cairo::RefPtr<Cairo::Region> r1 = Cairo::Region::create (area_r);
550 r1->intersect (background);
553 Cairo::RectangleInt i (r1->get_extents ());
554 context->set_source (bgpattern);
555 context->rectangle (i.x, i.y, i.width, i.height);
559 Cairo::RefPtr<Cairo::Region> r2 = Cairo::Region::create (area_r);
560 r2->intersect (pixrect);
563 // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
564 Cairo::RectangleInt i (r2->get_extents ());
565 context->set_source (fgpattern);
566 context->rectangle (i.x, i.y, i.width, i.height);
573 last_peak_rect.x = 1;
574 last_peak_rect.width = pixwidth;
575 last_peak_rect.y = max(1, 1 + pixheight - (int) floor (pixheight * current_peak));
576 if (_styleflags & 2) { // LED stripes
577 last_peak_rect.y = max(0, (last_peak_rect.y & (~1)));
579 if (bright_hold || (_styleflags & 2)) {
580 last_peak_rect.height = max(0, min(3, pixheight - last_peak_rect.y - 1 ));
582 last_peak_rect.height = max(0, min(2, pixheight - last_peak_rect.y - 1 ));
585 context->set_source (fgpattern);
586 context->rectangle (last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
588 if (bright_hold && !no_rgba_overlay) {
589 context->fill_preserve ();
590 context->set_source_rgba (1.0, 1.0, 1.0, 0.3);
595 last_peak_rect.width = 0;
596 last_peak_rect.height = 0;
599 context->translate (-origin.x, -origin.y);
603 Meter::horizontal_expose (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
606 Cairo::RectangleInt background;
607 Cairo::RectangleInt area_r;
609 /* convert expose area back to item coordinate space */
610 Rect area2 = window_to_item (area);
612 /* create a Cairo object so that we can use intersect and Region */
615 area_r.width = area2.width();
616 area_r.height = area2.height();
618 /* draw the edge (rounded corners) */
619 context->set_source_rgb (0, 0, 0); // black
620 rounded_rectangle (context, 0, 0, pixwidth + 2, pixheight + 2, 2);
623 /* horizontal meter extends from left to right. Compute the right edge */
624 right_of_meter = (gint) floor (pixwidth * current_level);
626 /* reset the width the rect that needs to show the pattern of the meter */
627 pixrect.width = right_of_meter;
629 /* compute a rect for the part of the meter that is all background */
630 background.x = 1 + right_of_meter;
632 background.width = pixwidth - right_of_meter;
633 background.height = pixheight;
635 /* translate so that item coordinates match window coordinates */
637 origin = item_to_window (origin);
638 context->translate (origin.x, origin.y);
640 Cairo::RefPtr<Cairo::Region> r;
642 r = Cairo::Region::create (area_r);
643 r->intersect (background);
646 /* draw the background part */
647 Cairo::RectangleInt i (r->get_extents ());
648 context->set_source (bgpattern);
649 context->rectangle (i.x, i.y, i.width, i.height);
654 r = Cairo::Region::create (area_r);
655 r->intersect (pixrect);
658 // draw the part of the meter image that we need.
659 Cairo::RectangleInt i (r->get_extents ());
661 context->set_source (fgpattern);
662 context->rectangle (i.x, i.y, i.width, i.height);
669 last_peak_rect.y = 1;
670 last_peak_rect.height = pixheight;
671 const int xpos = floor (pixwidth * current_peak);
672 if (bright_hold || (_styleflags & 2)) {
673 last_peak_rect.width = min(3, xpos );
675 last_peak_rect.width = min(2, xpos );
677 last_peak_rect.x = 1 + max(0, xpos - last_peak_rect.width);
679 context->set_source (fgpattern);
680 context->rectangle (last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
682 if (bright_hold && !no_rgba_overlay) {
683 context->fill_preserve ();
684 context->set_source_rgba (1.0, 1.0, 1.0, 0.3);
689 last_peak_rect.width = 0;
690 last_peak_rect.height = 0;
693 context->translate (-origin.x, -origin.y);
697 Meter::set (float lvl, float peak)
699 float old_level = current_level;
700 float old_peak = current_peak;
702 if (pixwidth <= 0 || pixheight <=0) return;
705 if (lvl >= current_peak) {
707 hold_state = hold_cnt;
710 if (hold_state > 0) {
711 if (--hold_state == 0) {
724 const float pixscale = (orientation == Vertical) ? pixheight : pixwidth;
725 #define PIX(X) floor(pixscale * (X))
726 if (PIX(current_level) == PIX(old_level) && PIX(current_peak) == PIX(old_peak) && (hold_state == 0 || peak != -1)) {
730 if (orientation == Vertical) {
731 queue_vertical_redraw (old_level);
733 queue_horizontal_redraw (old_level);
738 Meter::queue_vertical_redraw (float old_level)
740 Cairo::RectangleInt rect;
742 gint new_height = (gint) floor (pixheight * current_level);
744 /* this is the nominal area that needs to be filled by the meter
749 rect.width = pixwidth;
751 /* compute new top of meter (rect.y) by starting at one (border
752 * offset), go down the full height of the meter (X/Cairo coordinates
753 * grow down) to get to the bottom coordinate, then back up by the
754 * height of the patterned area.
756 rect.y = 1 + pixheight - new_height;
757 /* remember: height extends DOWN thanks to X/Cairo */
758 rect.height = new_height;
760 /* now lets optimize redrawing by figuring out which part needs to be
761 actually redrawn (i.e. re-use the last drawn state).
764 if (current_level > old_level) {
765 /* filled area got taller, just draw the new section */
767 /* rect.y (new y origin) is smaller or equal to pixrect.y (old
768 * y origin) because the top of the meter is higher (X/Cairo:
769 * coordinates grow down).
771 * Leave rect.y alone, and recompute the height to be just the
772 * difference between the new bottom and the top of the previous
775 * The old pattern area extended DOWN from pixrect.y to
776 * pixrect.y + pixrect.height.
778 * The new pattern area extends DOWN from rect.y to
779 * rect.y + rect.height
781 * The area needing to be drawn is the difference between the
782 * old top (pixrect.y) and the new top (rect.y)
784 rect.height = pixrect.y - rect.y;
786 /* it got smaller, compute the difference */
787 /* rect.y becomes old.y (the smaller value) */
789 /* rect.height is the old.y (smaller) minus the new.y (larger)
791 rect.height = pixrect.height - rect.height;
794 Cairo::RefPtr<Cairo::Region> region;
797 if (rect.height != 0) {
799 /* ok, first region to draw ... */
801 region = Cairo::Region::create (rect);
805 /* redraw the last place where the last peak hold bar was;
806 the next expose will draw the new one whether its part of
807 expose region or not.
810 if (last_peak_rect.width * last_peak_rect.height != 0) {
812 region = Cairo::Region::create ();
815 region->do_union (last_peak_rect);
818 if (hold_state && current_peak > 0) {
820 region = Cairo::Region::create ();
824 rect.y = max(1, 1 + pixheight - (int) floor (pixheight * current_peak));
825 if (_styleflags & 2) { // LED stripes
826 rect.y = max(0, (rect.y & (~1)));
828 if (bright_hold || (_styleflags & 2)) {
829 rect.height = max(0, min(3, pixheight - last_peak_rect.y -1 ));
831 rect.height = max(0, min(2, pixheight - last_peak_rect.y -1 ));
833 rect.width = pixwidth;
834 region->do_union (rect);
838 if (visible() && _bounding_box && _canvas) {
839 Cairo::RectangleInt iri = region->get_extents();
840 Rect ir (iri.x, iri.y, iri.x + iri.width, iri.y + iri.height);
841 _canvas->request_redraw (item_to_window (ir));
847 Meter::queue_horizontal_redraw (float old_level)
849 Cairo::RectangleInt rect;
851 gint new_right = (gint) floor (pixwidth * current_level);
853 rect.height = pixheight;
856 if (current_level > old_level) {
857 rect.x = 1 + pixrect.width;
858 /* colored/pixbuf got larger, just draw the new section */
859 rect.width = new_right - pixrect.width;
861 /* it got smaller, compute the difference */
862 rect.x = 1 + new_right;
863 /* rect.height is the old.x (smaller) minus the new.x (larger) */
864 rect.width = pixrect.width - new_right;
867 Cairo::RefPtr<Cairo::Region> region;
870 if (rect.height != 0) {
872 /* ok, first region to draw ... */
874 region = Cairo::Region::create (rect);
878 /* redraw the last place where the last peak hold bar was;
879 the next expose will draw the new one whether its part of
880 expose region or not.
883 if (last_peak_rect.width * last_peak_rect.height != 0) {
885 region = Cairo::Region::create ();
888 region->do_union (last_peak_rect);
891 if (hold_state && current_peak > 0) {
893 region = Cairo::Region::create ();
897 rect.height = pixheight;
898 const int xpos = floor (pixwidth * current_peak);
899 if (bright_hold || (_styleflags & 2)) {
900 rect.width = min(3, xpos);
902 rect.width = min(2, xpos);
904 rect.x = 1 + max(0, xpos - rect.width);
905 region->do_union (rect);
909 if (visible() && _bounding_box && _canvas) {
910 Cairo::RectangleInt iri = region->get_extents();
911 Rect ir (iri.x, iri.y, iri.x + iri.width, iri.y + iri.height);
912 _canvas->request_redraw (item_to_window (ir));
918 Meter::set_highlight (bool onoff)
920 if (highlight == onoff) {
924 if (orientation == Vertical) {
925 bgpattern = vertical_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);
927 bgpattern = horizontal_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);