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,
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, pixheight, _clr, _stp, _styleflags);
114 bgpattern = request_vertical_background (pixwidth, pixheight, _bgc, false);
119 fgpattern = request_horizontal_meter(pixwidth, pixheight, _clr, _stp, _styleflags);
120 bgpattern = request_horizontal_background (pixwidth, pixheight, _bgc, false);
123 pixrect.width = pixwidth;
124 pixrect.height = pixheight;
126 request_width = pixrect.width;
127 request_height= pixrect.height;
132 FastMeter::~FastMeter ()
137 FastMeter::flush_pattern_cache ()
139 Pattern10Map::iterator i1;
140 PatternBgMap::iterator ib;
142 for (ib = hb_pattern_cache.begin(); ib != hb_pattern_cache.end(); ++ib) {
143 hb_pattern_cache.erase(ib);
146 for (i1 = hm_pattern_cache.begin(); i1 != hm_pattern_cache.end(); ++i1) {
147 hm_pattern_cache.erase(i1);
150 for (ib = vb_pattern_cache.begin(); ib != vb_pattern_cache.end(); ++ib) {
151 vb_pattern_cache.erase(ib);
154 for (i1 = vm_pattern_cache.begin(); i1 != vm_pattern_cache.end(); ++i1) {
155 vm_pattern_cache.erase(i1);
159 Cairo::RefPtr<Cairo::Pattern>
160 FastMeter::generate_meter_pattern (
161 int width, int height, int *clr, float *stp, int styleflags, bool horiz)
165 const double soft = 3.0 / (double) height;
166 const double offs = -1.0 / (double) height;
168 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
171 Cairo coordinate space goes downwards as y value goes up, so invert
172 knee-based positions by using (1.0 - y)
175 UINT_TO_RGBA (clr[9], &r, &g, &b, &a); // top/clip
176 cairo_pattern_add_color_stop_rgb (pat, 0.0,
177 r/255.0, g/255.0, b/255.0);
179 knee = offs + stp[3] / 115.0f; // -0dB
181 UINT_TO_RGBA (clr[8], &r, &g, &b, &a);
182 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
183 r/255.0, g/255.0, b/255.0);
185 UINT_TO_RGBA (clr[7], &r, &g, &b, &a);
186 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
187 r/255.0, g/255.0, b/255.0);
189 knee = offs + stp[2]/ 115.0f; // -3dB || -2dB
191 UINT_TO_RGBA (clr[6], &r, &g, &b, &a);
192 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
193 r/255.0, g/255.0, b/255.0);
195 UINT_TO_RGBA (clr[5], &r, &g, &b, &a);
196 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
197 r/255.0, g/255.0, b/255.0);
199 knee = offs + stp[1] / 115.0f; // -9dB
201 UINT_TO_RGBA (clr[4], &r, &g, &b, &a);
202 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
203 r/255.0, g/255.0, b/255.0);
205 UINT_TO_RGBA (clr[3], &r, &g, &b, &a);
206 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
207 r/255.0, g/255.0, b/255.0);
209 knee = offs + stp[0] / 115.0f; // -18dB
211 UINT_TO_RGBA (clr[2], &r, &g, &b, &a);
212 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
213 r/255.0, g/255.0, b/255.0);
215 UINT_TO_RGBA (clr[1], &r, &g, &b, &a);
216 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
217 r/255.0, g/255.0, b/255.0);
219 UINT_TO_RGBA (clr[0], &r, &g, &b, &a); // bottom
220 cairo_pattern_add_color_stop_rgb (pat, 1.0,
221 r/255.0, g/255.0, b/255.0);
223 if ((styleflags & 1) && !no_rgba_overlay) {
224 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
225 cairo_pattern_add_color_stop_rgba (shade_pattern, 0, 0.0, 0.0, 0.0, 0.15);
226 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.4, 1.0, 1.0, 1.0, 0.05);
227 cairo_pattern_add_color_stop_rgba (shade_pattern, 1, 0.0, 0.0, 0.0, 0.25);
229 cairo_surface_t* surface;
231 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
232 tc = cairo_create (surface);
233 cairo_set_source (tc, pat);
234 cairo_rectangle (tc, 0, 0, width, height);
236 cairo_pattern_destroy (pat);
238 cairo_set_source (tc, shade_pattern);
239 cairo_rectangle (tc, 0, 0, width, height);
241 cairo_pattern_destroy (shade_pattern);
243 if (styleflags & 2) { // LED stripes
245 cairo_set_line_width(tc, 1.0);
246 cairo_set_source_rgba(tc, .0, .0, .0, 0.4);
247 //cairo_set_operator (tc, CAIRO_OPERATOR_SOURCE);
248 for (float y=0.5; y < height; y+= 2.0) {
249 cairo_move_to(tc, 0, y);
250 cairo_line_to(tc, width, y);
256 pat = cairo_pattern_create_for_surface (surface);
258 cairo_surface_destroy (surface);
262 cairo_surface_t* surface;
264 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
265 tc = cairo_create (surface);
268 cairo_matrix_init_rotate (&m, -M_PI/2.0);
269 cairo_matrix_translate (&m, -height, 0);
270 cairo_pattern_set_matrix (pat, &m);
271 cairo_set_source (tc, pat);
272 cairo_rectangle (tc, 0, 0, height, width);
274 cairo_pattern_destroy (pat);
275 pat = cairo_pattern_create_for_surface (surface);
277 cairo_surface_destroy (surface);
279 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
285 Cairo::RefPtr<Cairo::Pattern>
286 FastMeter::generate_meter_background (
287 int width, int height, int *clr, bool shade, bool horiz)
289 guint8 r0,g0,b0,r1,g1,b1,a;
291 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
293 UINT_TO_RGBA (clr[0], &r0, &g0, &b0, &a);
294 UINT_TO_RGBA (clr[1], &r1, &g1, &b1, &a);
296 cairo_pattern_add_color_stop_rgb (pat, 0.0,
297 r1/255.0, g1/255.0, b1/255.0);
299 cairo_pattern_add_color_stop_rgb (pat, 1.0,
300 r0/255.0, g0/255.0, b0/255.0);
302 if (shade && !no_rgba_overlay) {
303 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
304 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.0, 1.0, 1.0, 1.0, 0.15);
305 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.6, 0.0, 0.0, 0.0, 0.10);
306 cairo_pattern_add_color_stop_rgba (shade_pattern, 1.0, 1.0, 1.0, 1.0, 0.20);
308 cairo_surface_t* surface;
310 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
311 tc = cairo_create (surface);
312 cairo_set_source (tc, pat);
313 cairo_rectangle (tc, 0, 0, width, height);
315 cairo_set_source (tc, shade_pattern);
316 cairo_rectangle (tc, 0, 0, width, height);
319 cairo_pattern_destroy (pat);
320 cairo_pattern_destroy (shade_pattern);
322 pat = cairo_pattern_create_for_surface (surface);
325 cairo_surface_destroy (surface);
329 cairo_surface_t* surface;
331 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
332 tc = cairo_create (surface);
335 cairo_matrix_init_rotate (&m, -M_PI/2.0);
336 cairo_matrix_translate (&m, -height, 0);
337 cairo_pattern_set_matrix (pat, &m);
338 cairo_set_source (tc, pat);
339 cairo_rectangle (tc, 0, 0, height, width);
341 cairo_pattern_destroy (pat);
342 pat = cairo_pattern_create_for_surface (surface);
344 cairo_surface_destroy (surface);
347 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
352 Cairo::RefPtr<Cairo::Pattern>
353 FastMeter::request_vertical_meter(
354 int width, int height, int *clr, float *stp, int styleflags)
356 height = max(height, min_pattern_metric_size);
357 height = min(height, max_pattern_metric_size);
359 const Pattern10MapKey key (width, height,
360 stp[0], stp[1], stp[2], stp[3],
361 clr[0], clr[1], clr[2], clr[3],
362 clr[4], clr[5], clr[6], clr[7],
363 clr[8], clr[9], styleflags);
365 Pattern10Map::iterator i;
366 if ((i = vm_pattern_cache.find (key)) != vm_pattern_cache.end()) {
369 // TODO flush pattern cache if it gets too large
371 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
372 width, height, clr, stp, styleflags, false);
373 vm_pattern_cache[key] = p;
378 Cairo::RefPtr<Cairo::Pattern>
379 FastMeter::request_vertical_background(
380 int width, int height, int *bgc, bool /*shade */)
382 height = max(height, min_pattern_metric_size);
383 height = min(height, max_pattern_metric_size);
386 const PatternBgMapKey key (width, height, bgc[0], bgc[1], false);
387 PatternBgMap::iterator i;
388 if ((i = vb_pattern_cache.find (key)) != vb_pattern_cache.end()) {
391 // TODO flush pattern cache if it gets too large
393 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
394 width, height, bgc, false, false);
395 vb_pattern_cache[key] = p;
400 Cairo::RefPtr<Cairo::Pattern>
401 FastMeter::request_horizontal_meter(
402 int width, int height, int *clr, float *stp, int styleflags)
404 width = max(width, min_pattern_metric_size);
405 width = min(width, max_pattern_metric_size);
407 const Pattern10MapKey key (width, height,
408 stp[0], stp[1], stp[2], stp[3],
409 clr[0], clr[1], clr[2], clr[3],
410 clr[4], clr[5], clr[6], clr[7],
411 clr[8], clr[9], styleflags);
413 Pattern10Map::iterator i;
414 if ((i = hm_pattern_cache.find (key)) != hm_pattern_cache.end()) {
417 // TODO flush pattern cache if it gets too large
419 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
420 height, width, clr, stp, styleflags, true);
422 hm_pattern_cache[key] = p;
426 Cairo::RefPtr<Cairo::Pattern>
427 FastMeter::request_horizontal_background(
428 int width, int height, int *bgc, bool /* shade */)
430 width = max(width, min_pattern_metric_size);
431 width = min(width, max_pattern_metric_size);
434 const PatternBgMapKey key (width, height, bgc[0], bgc[1], false);
435 PatternBgMap::iterator i;
436 if ((i = hb_pattern_cache.find (key)) != hb_pattern_cache.end()) {
439 // TODO flush pattern cache if it gets too large
441 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
442 height, width, bgc, false, true);
444 hb_pattern_cache[key] = p;
452 FastMeter::set_hold_count (long val)
466 FastMeter::on_size_request (GtkRequisition* req)
468 if (orientation == Vertical) {
469 vertical_size_request (req);
471 horizontal_size_request (req);
476 FastMeter::vertical_size_request (GtkRequisition* req)
478 req->height = request_height;
479 req->height = max(req->height, min_pattern_metric_size);
480 req->height = min(req->height, max_pattern_metric_size);
483 req->width = request_width;
487 FastMeter::horizontal_size_request (GtkRequisition* req)
489 req->width = request_width;
490 req->width = max(req->width, min_pattern_metric_size);
491 req->width = min(req->width, max_pattern_metric_size);
494 req->height = request_height;
498 FastMeter::on_size_allocate (Gtk::Allocation &alloc)
500 if (orientation == Vertical) {
501 vertical_size_allocate (alloc);
503 horizontal_size_allocate (alloc);
509 FastMeter::vertical_size_allocate (Gtk::Allocation &alloc)
511 if (alloc.get_width() != request_width) {
512 alloc.set_width (request_width);
515 int h = alloc.get_height();
516 h = max (h, min_pattern_metric_size + 2);
517 h = min (h, max_pattern_metric_size + 2);
519 if (h != alloc.get_height()) {
520 alloc.set_height (h);
523 if (pixheight != h) {
524 fgpattern = request_vertical_meter (request_width, h, _clr, _stp, _styleflags);
525 bgpattern = request_vertical_background (request_width, h, highlight ? _bgh : _bgc, false);
527 pixwidth = request_width;
530 CairoWidget::on_size_allocate (alloc);
534 FastMeter::horizontal_size_allocate (Gtk::Allocation &alloc)
536 if (alloc.get_height() != request_height) {
537 alloc.set_height (request_height);
540 int w = alloc.get_width();
541 w = max (w, min_pattern_metric_size + 2);
542 w = min (w, max_pattern_metric_size + 2);
544 if (w != alloc.get_width()) {
549 fgpattern = request_horizontal_meter (w, request_height, _clr, _stp, _styleflags);
550 bgpattern = request_horizontal_background (w, request_height, highlight ? _bgh : _bgc, false);
552 pixheight = request_height;
555 CairoWidget::on_size_allocate (alloc);
559 FastMeter::render (cairo_t* cr, cairo_rectangle_t* area)
561 if (orientation == Vertical) {
562 return vertical_expose (cr, area);
564 return horizontal_expose (cr, area);
569 FastMeter::vertical_expose (cairo_t* cr, cairo_rectangle_t* area)
572 GdkRectangle intersection;
573 GdkRectangle background;
574 GdkRectangle eventarea;
576 //cairo_set_source_rgb (cr, 0, 0, 0); // black
577 //rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
580 top_of_meter = (gint) floor (pixheight * current_level);
582 /* reset the height & origin of the rect that needs to show the pixbuf
585 pixrect.height = top_of_meter;
586 pixrect.y = pixheight - top_of_meter;
590 background.width = pixrect.width;
591 background.height = pixheight - top_of_meter;
593 eventarea.x = area->x;
594 eventarea.y = area->y;
595 eventarea.width = area->width;
596 eventarea.height = area->height;
598 // Switching to CAIRO we would like to draw on the container's bkg.
599 // if (gdk_rectangle_intersect (&background, &eventarea, &intersection)) {
600 // cairo_set_source (cr, bgpattern->cobj());
601 // cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
605 // MEMO: Normaly MATURE OS clips so called invalidated rects itself making APP free of
606 // heavy operations which OS does with graphic HW
608 // NOTE FROM PAUL: GTK does clip already. The invalidated rect isn't the only area
609 // we want to clip to however, which is why this object/class is called FastMeter.
610 // I have left stuff commented out as I found it when I merged from Ardour in August 2014,
611 // but this commenting and the previous MEMO comment represent a misunderstanding
612 // of what this code is doing.
614 // if (gdk_rectangle_intersect (&pixrect, &eventarea, &intersection)) {
615 // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
616 //cairo_set_source (cr, fgpattern->cobj());
617 cairo_set_source_rgba (cr, 0.69, 0.69, 0.69, 1);
618 cairo_rectangle (cr, pixrect.x, pixrect.y, pixrect.width, pixrect.height);
625 last_peak_rect.x = 0;
626 last_peak_rect.width = pixwidth;
627 last_peak_rect.y = max(0, pixheight - (gint) floor (pixheight * current_peak));
628 if (bright_hold || (_styleflags & 2)) {
629 last_peak_rect.height = max(0, min(3, pixheight - last_peak_rect.y ));
631 last_peak_rect.height = max(0, min(2, pixheight - last_peak_rect.y ));
634 cairo_set_source (cr, fgpattern->cobj());
635 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
637 if (bright_hold && !no_rgba_overlay) {
638 cairo_fill_preserve (cr);
639 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
644 last_peak_rect.width = 0;
645 last_peak_rect.height = 0;
650 FastMeter::horizontal_expose (cairo_t* cr, cairo_rectangle_t* area)
654 //cairo_set_source_rgb (cr, 0, 0, 0); // black
655 //rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
658 right_of_meter = (gint) floor (pixwidth * current_level);
660 /* reset the height & origin of the rect that needs to show the pixbuf
663 pixrect.width = right_of_meter;
668 last_peak_rect.y = 1;
669 last_peak_rect.height = pixheight;
670 const int xpos = floor (pixwidth * current_peak);
671 if (bright_hold || (_styleflags & 2)) {
672 last_peak_rect.width = min(3, xpos );
674 last_peak_rect.width = min(2, xpos );
676 last_peak_rect.x = 1 + max(0, xpos - last_peak_rect.width);
678 cairo_set_source (cr, fgpattern->cobj());
679 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
681 if (bright_hold && !no_rgba_overlay) {
682 cairo_fill_preserve (cr);
683 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
688 last_peak_rect.width = 0;
689 last_peak_rect.height = 0;
694 FastMeter::set (float lvl, float peak)
696 float old_level = current_level;
697 float old_peak = current_peak;
699 if (pixwidth <= 0 || pixheight <=0) return;
702 if (lvl >= current_peak) {
704 hold_state = hold_cnt;
707 if (hold_state > 0) {
708 if (--hold_state == 0) {
721 if (current_level == old_level && current_peak == old_peak && (hold_state == 0 || peak != -1)) {
725 Glib::RefPtr<Gdk::Window> win;
727 if ((win = get_window()) == 0) {
732 if (orientation == Vertical) {
733 queue_vertical_redraw (win, old_level);
735 queue_horizontal_redraw (win, old_level);
740 FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
744 gint new_top = (gint) floor (pixheight * current_level);
747 rect.width = pixwidth;
748 rect.height = new_top;
749 rect.y = pixheight - new_top;
751 if (current_level > old_level) {
752 /* colored/pixbuf got larger, just draw the new section */
753 /* rect.y stays where it is because of X coordinates */
754 /* height of invalidated area is between new.y (smaller) and old.y
756 X coordinates just make my brain hurt.
758 rect.height = pixrect.y - rect.y;
760 /* it got smaller, compute the difference */
761 /* rect.y becomes old.y (the smaller value) */
763 /* rect.height is the old.y (smaller) minus the new.y (larger)
765 rect.height = pixrect.height - rect.height;
768 GdkRegion* region = 0;
771 if (rect.height != 0) {
773 /* ok, first region to draw ... */
775 region = gdk_region_rectangle (&rect);
779 /* redraw the last place where the last peak hold bar was;
780 the next expose will draw the new one whether its part of
781 expose region or not.
784 if (last_peak_rect.width * last_peak_rect.height != 0) {
786 region = gdk_region_new ();
789 gdk_region_union_with_rect (region, &last_peak_rect);
792 if (hold_state && current_peak > 0) {
794 region = gdk_region_new ();
798 rect.y = max(1, 1 + pixheight - (gint) floor (pixheight * current_peak));
799 if (bright_hold || (_styleflags & 2)) {
800 rect.height = max(0, min(3, pixheight - last_peak_rect.y -1 ));
802 rect.height = max(0, min(2, pixheight - last_peak_rect.y -1 ));
804 rect.width = pixwidth;
805 gdk_region_union_with_rect (region, &rect);
809 gdk_window_invalidate_region (win->gobj(), region, true);
812 gdk_region_destroy(region);
818 FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
822 gint new_right = (gint) floor (pixwidth * current_level);
824 rect.height = pixheight;
827 if (current_level > old_level) {
828 rect.x = 1 + pixrect.width;
829 /* colored/pixbuf got larger, just draw the new section */
830 rect.width = new_right - pixrect.width;
832 /* it got smaller, compute the difference */
833 rect.x = 1 + new_right;
834 /* rect.height is the old.x (smaller) minus the new.x (larger) */
835 rect.width = pixrect.width - new_right;
838 GdkRegion* region = 0;
841 if (rect.height != 0) {
843 /* ok, first region to draw ... */
845 region = gdk_region_rectangle (&rect);
849 /* redraw the last place where the last peak hold bar was;
850 the next expose will draw the new one whether its part of
851 expose region or not.
854 if (last_peak_rect.width * last_peak_rect.height != 0) {
856 region = gdk_region_new ();
859 gdk_region_union_with_rect (region, &last_peak_rect);
862 if (hold_state && current_peak > 0) {
864 region = gdk_region_new ();
868 rect.height = pixheight;
869 const int xpos = floor (pixwidth * current_peak);
870 if (bright_hold || (_styleflags & 2)) {
871 rect.width = min(3, xpos);
873 rect.width = min(2, xpos);
875 rect.x = 1 + max(0, xpos - rect.width);
876 gdk_region_union_with_rect (region, &rect);
880 gdk_window_invalidate_region (win->gobj(), region, true);
883 gdk_region_destroy(region);
889 FastMeter::set_highlight (bool onoff)
891 if (highlight == onoff) {
895 if (orientation == Vertical) {
896 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, false);
898 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, false);