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 ()
136 Cairo::RefPtr<Cairo::Pattern>
137 FastMeter::generate_meter_pattern (
138 int width, int height, int *clr, float *stp, int styleflags, bool horiz)
142 const double soft = 3.0 / (double) height;
143 const double offs = -1.0 / (double) height;
145 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
148 Cairo coordinate space goes downwards as y value goes up, so invert
149 knee-based positions by using (1.0 - y)
152 UINT_TO_RGBA (clr[9], &r, &g, &b, &a); // top/clip
153 cairo_pattern_add_color_stop_rgb (pat, 0.0,
154 r/255.0, g/255.0, b/255.0);
156 knee = offs + stp[3] / 115.0f; // -0dB
158 UINT_TO_RGBA (clr[8], &r, &g, &b, &a);
159 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
160 r/255.0, g/255.0, b/255.0);
162 UINT_TO_RGBA (clr[7], &r, &g, &b, &a);
163 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
164 r/255.0, g/255.0, b/255.0);
166 knee = offs + stp[2]/ 115.0f; // -3dB || -2dB
168 UINT_TO_RGBA (clr[6], &r, &g, &b, &a);
169 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
170 r/255.0, g/255.0, b/255.0);
172 UINT_TO_RGBA (clr[5], &r, &g, &b, &a);
173 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
174 r/255.0, g/255.0, b/255.0);
176 knee = offs + stp[1] / 115.0f; // -9dB
178 UINT_TO_RGBA (clr[4], &r, &g, &b, &a);
179 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
180 r/255.0, g/255.0, b/255.0);
182 UINT_TO_RGBA (clr[3], &r, &g, &b, &a);
183 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
184 r/255.0, g/255.0, b/255.0);
186 knee = offs + stp[0] / 115.0f; // -18dB
188 UINT_TO_RGBA (clr[2], &r, &g, &b, &a);
189 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee,
190 r/255.0, g/255.0, b/255.0);
192 UINT_TO_RGBA (clr[1], &r, &g, &b, &a);
193 cairo_pattern_add_color_stop_rgb (pat, 1.0 - knee + soft,
194 r/255.0, g/255.0, b/255.0);
196 UINT_TO_RGBA (clr[0], &r, &g, &b, &a); // bottom
197 cairo_pattern_add_color_stop_rgb (pat, 1.0,
198 r/255.0, g/255.0, b/255.0);
200 if ((styleflags & 1) && !no_rgba_overlay) {
201 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
202 cairo_pattern_add_color_stop_rgba (shade_pattern, 0, 0.0, 0.0, 0.0, 0.15);
203 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.4, 1.0, 1.0, 1.0, 0.05);
204 cairo_pattern_add_color_stop_rgba (shade_pattern, 1, 0.0, 0.0, 0.0, 0.25);
206 cairo_surface_t* surface;
208 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
209 tc = cairo_create (surface);
210 cairo_set_source (tc, pat);
211 cairo_rectangle (tc, 0, 0, width, height);
213 cairo_pattern_destroy (pat);
215 cairo_set_source (tc, shade_pattern);
216 cairo_rectangle (tc, 0, 0, width, height);
218 cairo_pattern_destroy (shade_pattern);
220 if (styleflags & 2) { // LED stripes
222 cairo_set_line_width(tc, 1.0);
223 cairo_set_source_rgba(tc, .0, .0, .0, 0.4);
224 //cairo_set_operator (tc, CAIRO_OPERATOR_SOURCE);
225 for (float y=0.5; y < height; y+= 2.0) {
226 cairo_move_to(tc, 0, y);
227 cairo_line_to(tc, width, y);
233 pat = cairo_pattern_create_for_surface (surface);
235 cairo_surface_destroy (surface);
239 cairo_surface_t* surface;
241 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
242 tc = cairo_create (surface);
245 cairo_matrix_init_rotate (&m, -M_PI/2.0);
246 cairo_matrix_translate (&m, -height, 0);
247 cairo_pattern_set_matrix (pat, &m);
248 cairo_set_source (tc, pat);
249 cairo_rectangle (tc, 0, 0, height, width);
251 cairo_pattern_destroy (pat);
252 pat = cairo_pattern_create_for_surface (surface);
254 cairo_surface_destroy (surface);
256 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
262 Cairo::RefPtr<Cairo::Pattern>
263 FastMeter::generate_meter_background (
264 int width, int height, int *clr, bool shade, bool horiz)
266 guint8 r0,g0,b0,r1,g1,b1,a;
268 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, height);
270 UINT_TO_RGBA (clr[0], &r0, &g0, &b0, &a);
271 UINT_TO_RGBA (clr[1], &r1, &g1, &b1, &a);
273 cairo_pattern_add_color_stop_rgb (pat, 0.0,
274 r1/255.0, g1/255.0, b1/255.0);
276 cairo_pattern_add_color_stop_rgb (pat, 1.0,
277 r0/255.0, g0/255.0, b0/255.0);
279 if (shade && !no_rgba_overlay) {
280 cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0);
281 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.0, 1.0, 1.0, 1.0, 0.15);
282 cairo_pattern_add_color_stop_rgba (shade_pattern, 0.6, 0.0, 0.0, 0.0, 0.10);
283 cairo_pattern_add_color_stop_rgba (shade_pattern, 1.0, 1.0, 1.0, 1.0, 0.20);
285 cairo_surface_t* surface;
287 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
288 tc = cairo_create (surface);
289 cairo_set_source (tc, pat);
290 cairo_rectangle (tc, 0, 0, width, height);
292 cairo_set_source (tc, shade_pattern);
293 cairo_rectangle (tc, 0, 0, width, height);
296 cairo_pattern_destroy (pat);
297 cairo_pattern_destroy (shade_pattern);
299 pat = cairo_pattern_create_for_surface (surface);
302 cairo_surface_destroy (surface);
306 cairo_surface_t* surface;
308 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, height, width);
309 tc = cairo_create (surface);
312 cairo_matrix_init_rotate (&m, -M_PI/2.0);
313 cairo_matrix_translate (&m, -height, 0);
314 cairo_pattern_set_matrix (pat, &m);
315 cairo_set_source (tc, pat);
316 cairo_rectangle (tc, 0, 0, height, width);
318 cairo_pattern_destroy (pat);
319 pat = cairo_pattern_create_for_surface (surface);
321 cairo_surface_destroy (surface);
324 Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
329 Cairo::RefPtr<Cairo::Pattern>
330 FastMeter::request_vertical_meter(
331 int width, int height, int *clr, float *stp, int styleflags)
333 height = max(height, min_pattern_metric_size);
334 height = min(height, max_pattern_metric_size);
336 const Pattern10MapKey key (width, height,
337 stp[0], stp[1], stp[2], stp[3],
338 clr[0], clr[1], clr[2], clr[3],
339 clr[4], clr[5], clr[6], clr[7],
340 clr[8], clr[9], styleflags);
342 Pattern10Map::iterator i;
343 if ((i = vm_pattern_cache.find (key)) != vm_pattern_cache.end()) {
346 // TODO flush pattern cache if it gets too large
348 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
349 width, height, clr, stp, styleflags, false);
350 vm_pattern_cache[key] = p;
355 Cairo::RefPtr<Cairo::Pattern>
356 FastMeter::request_vertical_background(
357 int width, int height, int *bgc, bool shade)
359 height = max(height, min_pattern_metric_size);
360 height = min(height, max_pattern_metric_size);
363 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
364 PatternBgMap::iterator i;
365 if ((i = vb_pattern_cache.find (key)) != vb_pattern_cache.end()) {
368 // TODO flush pattern cache if it gets too large
370 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
371 width, height, bgc, shade, false);
372 vb_pattern_cache[key] = p;
377 Cairo::RefPtr<Cairo::Pattern>
378 FastMeter::request_horizontal_meter(
379 int width, int height, int *clr, float *stp, int styleflags)
381 width = max(width, min_pattern_metric_size);
382 width = min(width, max_pattern_metric_size);
384 const Pattern10MapKey key (width, height,
385 stp[0], stp[1], stp[2], stp[3],
386 clr[0], clr[1], clr[2], clr[3],
387 clr[4], clr[5], clr[6], clr[7],
388 clr[8], clr[9], styleflags);
390 Pattern10Map::iterator i;
391 if ((i = hm_pattern_cache.find (key)) != hm_pattern_cache.end()) {
394 // TODO flush pattern cache if it gets too large
396 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_pattern (
397 height, width, clr, stp, styleflags, true);
399 hm_pattern_cache[key] = p;
403 Cairo::RefPtr<Cairo::Pattern>
404 FastMeter::request_horizontal_background(
405 int width, int height, int *bgc, bool shade)
407 width = max(width, min_pattern_metric_size);
408 width = min(width, max_pattern_metric_size);
411 const PatternBgMapKey key (width, height, bgc[0], bgc[1], shade);
412 PatternBgMap::iterator i;
413 if ((i = hb_pattern_cache.find (key)) != hb_pattern_cache.end()) {
416 // TODO flush pattern cache if it gets too large
418 Cairo::RefPtr<Cairo::Pattern> p = generate_meter_background (
419 height, width, bgc, shade, true);
421 hb_pattern_cache[key] = p;
429 FastMeter::set_hold_count (long val)
443 FastMeter::on_size_request (GtkRequisition* req)
445 if (orientation == Vertical) {
446 vertical_size_request (req);
448 horizontal_size_request (req);
453 FastMeter::vertical_size_request (GtkRequisition* req)
455 req->height = request_height;
456 req->height = max(req->height, min_pattern_metric_size);
457 req->height = min(req->height, max_pattern_metric_size);
460 req->width = request_width;
464 FastMeter::horizontal_size_request (GtkRequisition* req)
466 req->width = request_width;
467 req->width = max(req->width, min_pattern_metric_size);
468 req->width = min(req->width, max_pattern_metric_size);
471 req->height = request_height;
475 FastMeter::on_size_allocate (Gtk::Allocation &alloc)
477 if (orientation == Vertical) {
478 vertical_size_allocate (alloc);
480 horizontal_size_allocate (alloc);
486 FastMeter::vertical_size_allocate (Gtk::Allocation &alloc)
488 if (alloc.get_width() != request_width) {
489 alloc.set_width (request_width);
492 int h = alloc.get_height();
493 h = max (h, min_pattern_metric_size + 2);
494 h = min (h, max_pattern_metric_size + 2);
496 if (h != alloc.get_height()) {
497 alloc.set_height (h);
500 if (pixheight != h) {
501 fgpattern = request_vertical_meter (request_width, h, _clr, _stp, _styleflags);
502 bgpattern = request_vertical_background (request_width, h, highlight ? _bgh : _bgc, highlight);
504 pixwidth = request_width - 2;
507 DrawingArea::on_size_allocate (alloc);
511 FastMeter::horizontal_size_allocate (Gtk::Allocation &alloc)
513 if (alloc.get_height() != request_height) {
514 alloc.set_height (request_height);
517 int w = alloc.get_width();
518 w = max (w, min_pattern_metric_size + 2);
519 w = min (w, max_pattern_metric_size + 2);
521 if (w != alloc.get_width()) {
526 fgpattern = request_horizontal_meter (w, request_height, _clr, _stp, _styleflags);
527 bgpattern = request_horizontal_background (w, request_height, highlight ? _bgh : _bgc, highlight);
529 pixheight = request_height - 2;
532 DrawingArea::on_size_allocate (alloc);
536 FastMeter::on_expose_event (GdkEventExpose* ev)
538 if (orientation == Vertical) {
539 return vertical_expose (ev);
541 return horizontal_expose (ev);
546 FastMeter::vertical_expose (GdkEventExpose* ev)
548 Glib::RefPtr<Gdk::Window> win = get_window ();
550 GdkRectangle intersection;
551 GdkRectangle background;
553 cairo_t* cr = gdk_cairo_create (get_window ()->gobj());
555 cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
558 cairo_set_source_rgb (cr, 0, 0, 0); // black
559 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
562 top_of_meter = (gint) floor (pixheight * current_level);
564 /* reset the height & origin of the rect that needs to show the pixbuf
567 pixrect.height = top_of_meter;
568 pixrect.y = 1 + pixheight - top_of_meter;
572 background.width = pixrect.width;
573 background.height = pixheight - top_of_meter;
575 if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) {
576 cairo_set_source (cr, bgpattern->cobj());
577 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
581 if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) {
582 // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
583 cairo_set_source (cr, fgpattern->cobj());
584 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
591 last_peak_rect.x = 1;
592 last_peak_rect.width = pixwidth;
593 last_peak_rect.y = max(1, 1 + pixheight - (gint) floor (pixheight * current_peak));
594 if (bright_hold || (_styleflags & 2)) {
595 last_peak_rect.height = max(0, min(3, pixheight - last_peak_rect.y - 1 ));
597 last_peak_rect.height = max(0, min(2, pixheight - last_peak_rect.y - 1 ));
600 cairo_set_source (cr, fgpattern->cobj());
601 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
603 if (bright_hold && !no_rgba_overlay) {
604 cairo_fill_preserve (cr);
605 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
610 last_peak_rect.width = 0;
611 last_peak_rect.height = 0;
620 FastMeter::horizontal_expose (GdkEventExpose* ev)
622 Glib::RefPtr<Gdk::Window> win = get_window ();
624 GdkRectangle intersection;
625 GdkRectangle background;
627 cairo_t* cr = gdk_cairo_create (get_window ()->gobj());
629 cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
632 cairo_set_source_rgb (cr, 0, 0, 0); // black
633 rounded_rectangle (cr, 0, 0, pixwidth + 2, pixheight + 2, 2);
636 right_of_meter = (gint) floor (pixwidth * current_level);
638 /* reset the height & origin of the rect that needs to show the pixbuf
641 pixrect.width = right_of_meter;
643 background.x = 1 + right_of_meter;
645 background.width = pixwidth - right_of_meter;
646 background.height = pixheight;
648 if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) {
649 cairo_set_source (cr, bgpattern->cobj());
650 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
654 if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) {
655 cairo_set_source (cr, fgpattern->cobj());
656 cairo_rectangle (cr, intersection.x, intersection.y, intersection.width, intersection.height);
663 last_peak_rect.y = 1;
664 last_peak_rect.height = pixheight;
665 const int xpos = floor (pixwidth * current_peak);
666 if (bright_hold || (_styleflags & 2)) {
667 last_peak_rect.width = min(3, xpos );
669 last_peak_rect.width = min(2, xpos );
671 last_peak_rect.x = 1 + max(0, xpos - last_peak_rect.width);
673 cairo_set_source (cr, fgpattern->cobj());
674 cairo_rectangle (cr, last_peak_rect.x, last_peak_rect.y, last_peak_rect.width, last_peak_rect.height);
676 if (bright_hold && !no_rgba_overlay) {
677 cairo_fill_preserve (cr);
678 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.3);
683 last_peak_rect.width = 0;
684 last_peak_rect.height = 0;
693 FastMeter::set (float lvl, float peak)
695 float old_level = current_level;
696 float old_peak = current_peak;
698 if (pixwidth <= 0 || pixheight <=0) return;
701 if (lvl >= current_peak) {
703 hold_state = hold_cnt;
706 if (hold_state > 0) {
707 if (--hold_state == 0) {
720 if (current_level == old_level && current_peak == old_peak && (hold_state == 0 || peak != -1)) {
724 Glib::RefPtr<Gdk::Window> win;
726 if ((win = get_window()) == 0) {
731 if (orientation == Vertical) {
732 queue_vertical_redraw (win, old_level);
734 queue_horizontal_redraw (win, old_level);
739 FastMeter::queue_vertical_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
743 gint new_top = (gint) floor (pixheight * current_level);
746 rect.width = pixwidth;
747 rect.height = new_top;
748 rect.y = 1 + pixheight - new_top;
750 if (current_level > old_level) {
751 /* colored/pixbuf got larger, just draw the new section */
752 /* rect.y stays where it is because of X coordinates */
753 /* height of invalidated area is between new.y (smaller) and old.y
755 X coordinates just make my brain hurt.
757 rect.height = pixrect.y - rect.y;
759 /* it got smaller, compute the difference */
760 /* rect.y becomes old.y (the smaller value) */
762 /* rect.height is the old.y (smaller) minus the new.y (larger)
764 rect.height = pixrect.height - rect.height;
767 GdkRegion* region = 0;
770 if (rect.height != 0) {
772 /* ok, first region to draw ... */
774 region = gdk_region_rectangle (&rect);
778 /* redraw the last place where the last peak hold bar was;
779 the next expose will draw the new one whether its part of
780 expose region or not.
783 if (last_peak_rect.width * last_peak_rect.height != 0) {
785 region = gdk_region_new ();
788 gdk_region_union_with_rect (region, &last_peak_rect);
791 if (hold_state && current_peak > 0) {
793 region = gdk_region_new ();
797 rect.y = max(1, 1 + pixheight - (gint) floor (pixheight * current_peak));
798 if (bright_hold || (_styleflags & 2)) {
799 rect.height = max(0, min(3, pixheight - last_peak_rect.y -1 ));
801 rect.height = max(0, min(2, pixheight - last_peak_rect.y -1 ));
803 rect.width = pixwidth;
804 gdk_region_union_with_rect (region, &rect);
808 gdk_window_invalidate_region (win->gobj(), region, true);
811 gdk_region_destroy(region);
817 FastMeter::queue_horizontal_redraw (const Glib::RefPtr<Gdk::Window>& win, float old_level)
821 gint new_right = (gint) floor (pixwidth * current_level);
823 rect.height = pixheight;
826 if (current_level > old_level) {
827 rect.x = 1 + pixrect.width;
828 /* colored/pixbuf got larger, just draw the new section */
829 rect.width = new_right - pixrect.width;
831 /* it got smaller, compute the difference */
832 rect.x = 1 + new_right;
833 /* rect.height is the old.x (smaller) minus the new.x (larger) */
834 rect.width = pixrect.width - new_right;
837 GdkRegion* region = 0;
840 if (rect.height != 0) {
842 /* ok, first region to draw ... */
844 region = gdk_region_rectangle (&rect);
848 /* redraw the last place where the last peak hold bar was;
849 the next expose will draw the new one whether its part of
850 expose region or not.
853 if (last_peak_rect.width * last_peak_rect.height != 0) {
855 region = gdk_region_new ();
858 gdk_region_union_with_rect (region, &last_peak_rect);
861 if (hold_state && current_peak > 0) {
863 region = gdk_region_new ();
867 rect.height = pixheight;
868 const int xpos = floor (pixwidth * current_peak);
869 if (bright_hold || (_styleflags & 2)) {
870 rect.width = min(3, xpos);
872 rect.width = min(2, xpos);
874 rect.x = 1 + max(0, xpos - rect.width);
875 gdk_region_union_with_rect (region, &rect);
879 gdk_window_invalidate_region (win->gobj(), region, true);
882 gdk_region_destroy(region);
888 FastMeter::set_highlight (bool onoff)
890 if (highlight == onoff) {
894 if (orientation == Vertical) {
895 bgpattern = request_vertical_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);
897 bgpattern = request_horizontal_background (pixwidth + 2, pixheight + 2, highlight ? _bgh : _bgc, highlight);