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.
29 #include "gtkmm2ext/utils.h"
30 #include "widgets/fastmeter.h"
32 #define UINT_TO_RGB(u,r,g,b) { (*(r)) = ((u)>>16)&0xff; (*(g)) = ((u)>>8)&0xff; (*(b)) = (u)&0xff; }
33 #define UINT_TO_RGBA(u,r,g,b,a) { UINT_TO_RGB(((u)>>8),r,g,b); (*(a)) = (u)&0xff; }
37 using namespace Gtkmm2ext;
38 using namespace ArdourWidgets;
41 int FastMeter::min_pattern_metric_size = 16;
42 int FastMeter::max_pattern_metric_size = 1024;
43 bool FastMeter::no_rgba_overlay = false;
45 FastMeter::Pattern10Map FastMeter::vm_pattern_cache;
46 FastMeter::PatternBgMap FastMeter::vb_pattern_cache;
48 FastMeter::Pattern10Map FastMeter::hm_pattern_cache;
49 FastMeter::PatternBgMap FastMeter::hb_pattern_cache;
51 FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o, int len,
52 int clr0, int clr1, int clr2, int clr3,
53 int clr4, int clr5, int clr6, int clr7,
57 float stp0, float stp1,
58 float stp2, float stp3,
63 , _styleflags(styleflags)
72 last_peak_rect.width = 0;
73 last_peak_rect.height = 0;
77 no_rgba_overlay = ! Glib::getenv("NO_METER_SHADE").empty();
101 set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
109 if (orientation == Vertical) {
112 fgpattern = request_vertical_meter(pixwidth + 2, pixheight + 2, _clr, _stp, _styleflags);
113 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, _bgc, false);
118 fgpattern = request_horizontal_meter(pixwidth + 2, pixheight + 2, _clr, _stp, _styleflags);
119 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, _bgc, false);
122 pixrect.width = pixwidth;
123 pixrect.height = pixheight;
125 request_width = pixrect.width + 2;
126 request_height= pixrect.height + 2;
131 FastMeter::~FastMeter ()
136 FastMeter::flush_pattern_cache () {
137 hb_pattern_cache.clear();
138 hm_pattern_cache.clear();
139 vb_pattern_cache.clear();
140 vm_pattern_cache.clear();
143 Cairo::RefPtr<Cairo::Pattern>
144 FastMeter::generate_meter_pattern (
145 int width, int height, int *clr, float *stp, int styleflags, bool horiz)
149 const double soft = 3.0 / (double) height;
150 const double offs = -1.0 / (double) height;
152 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
155 Cairo coordinate space goes downwards as y value goes up, so invert
156 knee-based positions by using (1.0 - y)
159 UINT_TO_RGBA (clr[9], &r, &g, &b, &a); // top/clip
160 cairo_pattern_add_color_stop_rgb (pat, 0.0,
161 r/255.0, g/255.0, b/255.0);
163 knee = offs + stp[3] / 115.0f; // -0dB
165 UINT_TO_RGBA (clr[8], &r, &g, &b, &a);
166 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
167 r/255.0, g/255.0, b/255.0);
169 UINT_TO_RGBA (clr[7], &r, &g, &b, &a);
170 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
171 r/255.0, g/255.0, b/255.0);
173 knee = offs + stp[2]/ 115.0f; // -3dB || -2dB
175 UINT_TO_RGBA (clr[6], &r, &g, &b, &a);
176 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
177 r/255.0, g/255.0, b/255.0);
179 UINT_TO_RGBA (clr[5], &r, &g, &b, &a);
180 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
181 r/255.0, g/255.0, b/255.0);
183 knee = offs + stp[1] / 115.0f; // -9dB
185 UINT_TO_RGBA (clr[4], &r, &g, &b, &a);
186 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
187 r/255.0, g/255.0, b/255.0);
189 UINT_TO_RGBA (clr[3], &r, &g, &b, &a);
190 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
191 r/255.0, g/255.0, b/255.0);
193 knee = offs + stp[0] / 115.0f; // -18dB
195 UINT_TO_RGBA (clr[2], &r, &g, &b, &a);
196 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
197 r/255.0, g/255.0, b/255.0);
199 UINT_TO_RGBA (clr[1], &r, &g, &b, &a);
200 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
201 r/255.0, g/255.0, b/255.0);
203 UINT_TO_RGBA (clr[0], &r, &g, &b, &a); // bottom
204 cairo_pattern_add_color_stop_rgb (pat, 1.0,
205 r/255.0, g/255.0, b/255.0);
207 if ((styleflags & 1) && !no_rgba_overlay) {
208 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
209 cairo_pattern_add_color_stop_rgba (shade_pattern, 0, 0.0, 0.0, 0.0, 0.15);
210 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.4, 1.0, 1.0, 1.0, 0.05);
211 cairo_pattern_add_color_stop_rgba (shade_pattern, 1, 0.0, 0.0, 0.0, 0.25);
213 cairo_surface_t* surface;
215 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
216 tc = cairo_create (surface);
217 cairo_set_source (tc, pat);
218 cairo_rectangle (tc, 0, 0, width, height);
220 cairo_pattern_destroy (pat);
222 cairo_set_source (tc, shade_pattern);
223 cairo_rectangle (tc, 0, 0, width, height);
225 cairo_pattern_destroy (shade_pattern);
227 if (styleflags & 2) { // LED stripes
229 cairo_set_line_width(tc, 1.0);
230 cairo_set_source_rgba(tc, .0, .0, .0, 0.4);
231 //cairo_set_operator (tc, CAIRO_OPERATOR_SOURCE);
232 for (int i = 0; float y = 0.5 + i * 2.0; ++i) {
236 cairo_move_to(tc, 0, y);
237 cairo_line_to(tc, width, y);
243 pat = cairo_pattern_create_for_surface (surface);
245 cairo_surface_destroy (surface);
249 cairo_surface_t* surface;
251 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
252 tc = cairo_create (surface);
255 cairo_matrix_init_rotate (&m, -M_PI/2.0);
256 cairo_matrix_translate (&m, -height, 0);
257 cairo_pattern_set_matrix (pat, &m);
258 cairo_set_source (tc, pat);
259 cairo_rectangle (tc, 0, 0, height, width);
261 cairo_pattern_destroy (pat);
262 pat = cairo_pattern_create_for_surface (surface);
264 cairo_surface_destroy (surface);
266 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
272 Cairo::RefPtr<Cairo::Pattern>
273 FastMeter::generate_meter_background (
274 int width, int height, int *clr, bool shade, bool horiz)
276 guint8 r0,g0,b0,r1,g1,b1,a;
278 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
280 UINT_TO_RGBA (clr[0], &r0, &g0, &b0, &a);
281 UINT_TO_RGBA (clr[1], &r1, &g1, &b1, &a);
283 cairo_pattern_add_color_stop_rgb (pat, 0.0,
284 r1/255.0, g1/255.0, b1/255.0);
286 cairo_pattern_add_color_stop_rgb (pat, 1.0,
287 r0/255.0, g0/255.0, b0/255.0);
289 if (shade && !no_rgba_overlay) {
290 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
291 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.0, 1.0, 1.0, 1.0, 0.15);
292 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.6, 0.0, 0.0, 0.0, 0.10);
293 cairo_pattern_add_color_stop_rgba (shade_pattern, 1.0, 1.0, 1.0, 1.0, 0.20);
295 cairo_surface_t* surface;
297 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
298 tc = cairo_create (surface);
299 cairo_set_source (tc, pat);
300 cairo_rectangle (tc, 0, 0, width, height);
302 cairo_set_source (tc, shade_pattern);
303 cairo_rectangle (tc, 0, 0, width, height);
306 cairo_pattern_destroy (pat);
307 cairo_pattern_destroy (shade_pattern);
309 pat = cairo_pattern_create_for_surface (surface);
312 cairo_surface_destroy (surface);
316 cairo_surface_t* surface;
318 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
319 tc = cairo_create (surface);
322 cairo_matrix_init_rotate (&m, -M_PI/2.0);
323 cairo_matrix_translate (&m, -height, 0);
324 cairo_pattern_set_matrix (pat, &m);
325 cairo_set_source (tc, pat);
326 cairo_rectangle (tc, 0, 0, height, width);
328 cairo_pattern_destroy (pat);
329 pat = cairo_pattern_create_for_surface (surface);
331 cairo_surface_destroy (surface);
334 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
339 Cairo::RefPtr<Cairo::Pattern>
340 FastMeter::request_vertical_meter(
341 int width, int height, int *clr, float *stp, int styleflags)
343 height = max(height, min_pattern_metric_size);
344 height = min(height, max_pattern_metric_size);
346 const Pattern10MapKey key (width, height,
347 stp[0], stp[1], stp[2], stp[3],
348 clr[0], clr[1], clr[2], clr[3],
349 clr[4], clr[5], clr[6], clr[7],
350 clr[8], clr[9], styleflags);
352 Pattern10Map::iterator i;
353 if ((i = vm_pattern_cache.find (key)) != vm_pattern_cache.end()) {
356 // TODO flush pattern cache if it gets too large
358 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
359 width, height, clr, stp, styleflags, false);
360 vm_pattern_cache[key] = p;
365 Cairo::RefPtr<Cairo::Pattern>
366 FastMeter::request_vertical_background(
367 int width, int height, int *bgc, bool shade)
369 height = max(height, min_pattern_metric_size);
370 height = min(height, max_pattern_metric_size);
373 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
374 PatternBgMap::iterator i;
375 if ((i = vb_pattern_cache.find (key)) != vb_pattern_cache.end()) {
378 // TODO flush pattern cache if it gets too large
380 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
381 width, height, bgc, shade, false);
382 vb_pattern_cache[key] = p;
387 Cairo::RefPtr<Cairo::Pattern>
388 FastMeter::request_horizontal_meter(
389 int width, int height, int *clr, float *stp, int styleflags)
391 width = max(width, min_pattern_metric_size);
392 width = min(width, max_pattern_metric_size);
394 const Pattern10MapKey key (width, height,
395 stp[0], stp[1], stp[2], stp[3],
396 clr[0], clr[1], clr[2], clr[3],
397 clr[4], clr[5], clr[6], clr[7],
398 clr[8], clr[9], styleflags);
400 Pattern10Map::iterator i;
401 if ((i = hm_pattern_cache.find (key)) != hm_pattern_cache.end()) {
404 // TODO flush pattern cache if it gets too large
406 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
407 height, width, clr, stp, styleflags, true);
409 hm_pattern_cache[key] = p;
413 Cairo::RefPtr<Cairo::Pattern>
414 FastMeter::request_horizontal_background(
415 int width, int height, int *bgc, bool shade)
417 width = max(width, min_pattern_metric_size);
418 width = min(width, max_pattern_metric_size);
421 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
422 PatternBgMap::iterator i;
423 if ((i = hb_pattern_cache.find (key)) != hb_pattern_cache.end()) {
426 // TODO flush pattern cache if it gets too large
428 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
429 height, width, bgc, shade, true);
431 hb_pattern_cache[key] = p;
439 FastMeter::set_hold_count (long val)
453 FastMeter::on_size_request (GtkRequisition* req)
455 if (orientation == Vertical) {
456 vertical_size_request (req);
458 horizontal_size_request (req);
463 FastMeter::vertical_size_request (GtkRequisition* req)
465 req->height = request_height;
466 req->height = max(req->height, min_pattern_metric_size);
467 req->height = min(req->height, max_pattern_metric_size);
470 req->width = request_width;
474 FastMeter::horizontal_size_request (GtkRequisition* req)
476 req->width = request_width;
477 req->width = max(req->width, min_pattern_metric_size);
478 req->width = min(req->width, max_pattern_metric_size);
481 req->height = request_height;
485 FastMeter::on_size_allocate (Gtk::Allocation &alloc)
487 if (orientation == Vertical) {
488 vertical_size_allocate (alloc);
490 horizontal_size_allocate (alloc);
496 FastMeter::vertical_size_allocate (Gtk::Allocation &alloc)
498 if (alloc.get_width() != request_width) {
499 alloc.set_width (request_width);
502 int h = alloc.get_height();
503 h = max (h, min_pattern_metric_size + 2);
504 h = min (h, max_pattern_metric_size + 2);
506 if (h != alloc.get_height()) {
507 alloc.set_height (h);
510 if (pixheight != h) {
511 fgpattern = request_vertical_meter (request_width, h, _clr, _stp, _styleflags);
512 bgpattern = request_vertical_background (request_width, h, highlight ? _bgh : _bgc, highlight);
514 pixwidth = request_width - 2;
517 CairoWidget::on_size_allocate (alloc);
521 FastMeter::horizontal_size_allocate (Gtk::Allocation &alloc)
523 if (alloc.get_height() != request_height) {
524 alloc.set_height (request_height);
527 int w = alloc.get_width();
528 w = max (w, min_pattern_metric_size + 2);
529 w = min (w, max_pattern_metric_size + 2);
531 if (w != alloc.get_width()) {
536 fgpattern = request_horizontal_meter (w, request_height, _clr, _stp, _styleflags);
537 bgpattern = request_horizontal_background (w, request_height, highlight ? _bgh : _bgc, highlight);
539 pixheight = request_height - 2;
542 CairoWidget::on_size_allocate (alloc);
546 FastMeter::render (Cairo::RefPtr<Cairo::Context> const& ctx, cairo_rectangle_t* area)
548 if (orientation == Vertical) {
549 return vertical_expose (ctx->cobj(), area);
551 return horizontal_expose (ctx->cobj(), area);
556 FastMeter::vertical_expose (cairo_t* cr, cairo_rectangle_t* area)
559 GdkRectangle intersection;
560 GdkRectangle background;
561 GdkRectangle eventarea;
563 cairo_set_source_rgb (cr, 0, 0, 0); // black
564 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
567 top_of_meter = (gint) floor (pixheight * current_level);
569 /* reset the height & origin of the rect that needs to show the pixbuf
572 pixrect.height = top_of_meter;
573 pixrect.y = 1 + pixheight - top_of_meter;
577 background.width = pixrect.width;
578 background.height = pixheight - top_of_meter;
580 eventarea.x = area->x;
581 eventarea.y = area->y;
582 eventarea.width = area->width;
583 eventarea.height = area->height;
585 if (gdk_rectangle_intersect (&background, &eventarea, &intersection)) {
586 cairo_set_source (cr, bgpattern->cobj());
587 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
591 if (gdk_rectangle_intersect (&pixrect, &eventarea, &intersection)) {
592 // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
593 cairo_set_source (cr, fgpattern->cobj());
594 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
601 last_peak_rect.x = 1;
602 last_peak_rect.width = pixwidth;
603 last_peak_rect.y = max(1, 1 + pixheight - (int) floor (pixheight * current_peak));
604 if (_styleflags & 2) { // LED stripes
605 last_peak_rect.y = max(0, (last_peak_rect.y & (~1)));
607 if (bright_hold || (_styleflags & 2)) {
608 last_peak_rect.height = max(0, min(3, pixheight - last_peak_rect.y - 1 ));
610 last_peak_rect.height = max(0, min(2, pixheight - last_peak_rect.y - 1 ));
613 cairo_set_source (cr, fgpattern->cobj());
614 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
616 if (bright_hold && !no_rgba_overlay) {
617 cairo_fill_preserve (cr);
618 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
623 last_peak_rect.width = 0;
624 last_peak_rect.height = 0;
629 FastMeter::horizontal_expose (cairo_t* cr, cairo_rectangle_t* area)
632 GdkRectangle intersection;
633 GdkRectangle background;
634 GdkRectangle eventarea;
636 cairo_set_source_rgb (cr, 0, 0, 0); // black
637 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
640 right_of_meter = (gint) floor (pixwidth * current_level);
642 /* reset the height & origin of the rect that needs to show the pixbuf
645 pixrect.width = right_of_meter;
647 background.x = 1 + right_of_meter;
649 background.width = pixwidth - right_of_meter;
650 background.height = pixheight;
652 eventarea.x = area->x;
653 eventarea.y = area->y;
654 eventarea.width = area->width;
655 eventarea.height = area->height;
657 if (gdk_rectangle_intersect (&background, &eventarea, &intersection)) {
658 cairo_set_source (cr, bgpattern->cobj());
659 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
663 if (gdk_rectangle_intersect (&pixrect, &eventarea, &intersection)) {
664 cairo_set_source (cr, fgpattern->cobj());
665 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
672 last_peak_rect.y = 1;
673 last_peak_rect.height = pixheight;
674 const int xpos = floor (pixwidth * current_peak);
675 if (bright_hold || (_styleflags & 2)) {
676 last_peak_rect.width = min(3, xpos );
678 last_peak_rect.width = min(2, xpos );
680 last_peak_rect.x = 1 + max(0, xpos - last_peak_rect.width);
682 cairo_set_source (cr, fgpattern->cobj());
683 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
685 if (bright_hold && !no_rgba_overlay) {
686 cairo_fill_preserve (cr);
687 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
692 last_peak_rect.width = 0;
693 last_peak_rect.height = 0;
698 FastMeter::set (float lvl, float peak)
700 float old_level = current_level;
701 float old_peak = current_peak;
703 if (pixwidth <= 0 || pixheight <=0) return;
706 if (lvl >= current_peak && lvl > 0) {
708 hold_state = hold_cnt;
711 if (hold_state > 0) {
712 if (--hold_state == 0) {
725 const float pixscale = (orientation == Vertical) ? pixheight : pixwidth;
726 #define PIX(X) floor(pixscale * (X))
727 if (PIX(current_level) == PIX(old_level) && PIX(current_peak) == PIX(old_peak) && (hold_state == 0 || peak != -1)) {
731 Glib::RefPtr<Gdk::Window> win;
733 if (! (win = get_window())) {
738 if (orientation == Vertical) {
739 queue_vertical_redraw (win, old_level);
741 queue_horizontal_redraw (win, old_level);
746 FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
750 gint new_top = (gint) floor (pixheight * current_level);
753 rect.width = pixwidth;
754 rect.height = new_top;
755 rect.y = 1 + pixheight - new_top;
757 if (current_level > old_level) {
758 /* colored/pixbuf got larger, just draw the new section */
759 /* rect.y stays where it is because of X coordinates */
760 /* height of invalidated area is between new.y (smaller) and old.y
762 X coordinates just make my brain hurt.
764 rect.height = pixrect.y - rect.y;
766 /* it got smaller, compute the difference */
767 /* rect.y becomes old.y (the smaller value) */
769 /* rect.height is the old.y (smaller) minus the new.y (larger)
771 rect.height = pixrect.height - rect.height;
774 GdkRegion* region = 0;
777 if (rect.height != 0) {
779 /* ok, first region to draw ... */
781 region = gdk_region_rectangle (&rect);
785 /* redraw the last place where the last peak hold bar was;
786 the next expose will draw the new one whether its part of
787 expose region or not.
790 if (last_peak_rect.width * last_peak_rect.height != 0) {
792 region = gdk_region_new ();
795 gdk_region_union_with_rect (region, &last_peak_rect);
798 if (hold_state && current_peak > 0) {
800 region = gdk_region_new ();
804 rect.y = max(1, 1 + pixheight - (int) floor (pixheight * current_peak));
805 if (_styleflags & 2) { // LED stripes
806 rect.y = max(0, (rect.y & (~1)));
808 if (bright_hold || (_styleflags & 2)) {
809 rect.height = max(0, min(3, pixheight - last_peak_rect.y -1 ));
811 rect.height = max(0, min(2, pixheight - last_peak_rect.y -1 ));
813 rect.width = pixwidth;
814 gdk_region_union_with_rect (region, &rect);
818 gdk_window_invalidate_region (win->gobj(), region, true);
821 gdk_region_destroy(region);
827 FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
831 gint new_right = (gint) floor (pixwidth * current_level);
833 rect.height = pixheight;
836 if (current_level > old_level) {
837 rect.x = 1 + pixrect.width;
838 /* colored/pixbuf got larger, just draw the new section */
839 rect.width = new_right - pixrect.width;
841 /* it got smaller, compute the difference */
842 rect.x = 1 + new_right;
843 /* rect.height is the old.x (smaller) minus the new.x (larger) */
844 rect.width = pixrect.width - new_right;
847 GdkRegion* region = 0;
850 if (rect.height != 0) {
852 /* ok, first region to draw ... */
854 region = gdk_region_rectangle (&rect);
858 /* redraw the last place where the last peak hold bar was;
859 the next expose will draw the new one whether its part of
860 expose region or not.
863 if (last_peak_rect.width * last_peak_rect.height != 0) {
865 region = gdk_region_new ();
868 gdk_region_union_with_rect (region, &last_peak_rect);
871 if (hold_state && current_peak > 0) {
873 region = gdk_region_new ();
877 rect.height = pixheight;
878 const int xpos = floor (pixwidth * current_peak);
879 if (bright_hold || (_styleflags & 2)) {
880 rect.width = min(3, xpos);
882 rect.width = min(2, xpos);
884 rect.x = 1 + max(0, xpos - rect.width);
885 gdk_region_union_with_rect (region, &rect);
889 gdk_window_invalidate_region (win->gobj(), region, true);
892 gdk_region_destroy(region);
898 FastMeter::set_highlight (bool onoff)
900 if (highlight == onoff) {
904 if (orientation == Vertical) {
905 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);
907 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);