From ff5b1b0c999b261d04e6e11c479e33c1178d1a10 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 24 May 2015 19:35:45 +0200 Subject: prepare cleanup of ArdourButton rendering --- gtk2_ardour/ardour_button.cc | 406 ++++++++++++++++++++++++------------------- 1 file changed, 228 insertions(+), 178 deletions(-) (limited to 'gtk2_ardour/ardour_button.cc') diff --git a/gtk2_ardour/ardour_button.cc b/gtk2_ardour/ardour_button.cc index 89f19b001e..8d4e9dca3e 100644 --- a/gtk2_ardour/ardour_button.cc +++ b/gtk2_ardour/ardour_button.cc @@ -193,99 +193,23 @@ ArdourButton::set_alignment (const float xa, const float ya) _yalign = ya; } -void -ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) -{ - uint32_t text_color; - uint32_t led_color; - - const float corner_radius = std::max(2.f, _corner_radius * ARDOUR_UI::ui_scale); - - if (_update_colors) { - set_colors (); - } - if (get_height() != _pattern_height) { - build_patterns (); - } - - if ( active_state() == Gtkmm2ext::ExplicitActive ) { - text_color = text_active_color; - led_color = led_active_color; - } else { - text_color = text_inactive_color; - led_color = led_inactive_color; - } - - if (use_custom_led_color) { - led_color = led_custom_color; - } - - void (*rounded_function)(cairo_t*, double, double, double, double, double); - - switch (_corner_mask) { - case 0x1: /* upper left only */ - rounded_function = Gtkmm2ext::rounded_top_left_rectangle; - break; - case 0x2: /* upper right only */ - rounded_function = Gtkmm2ext::rounded_top_right_rectangle; - break; - case 0x3: /* upper only */ - rounded_function = Gtkmm2ext::rounded_top_rectangle; - break; - /* should really have functions for lower right, lower left, - lower only, but for now, we don't - */ - default: - rounded_function = Gtkmm2ext::rounded_rectangle; - } - - // draw edge (filling a rect underneath, rather than stroking a border on top, allows the corners to be lighter-weight. - if ((_elements & (Body|Edge)) == (Body|Edge)) { - rounded_function (cr, 0, 0, get_width(), get_height(), corner_radius + 1.5); - cairo_set_source_rgba (cr, 0, 0, 0, 1); - cairo_fill(cr); - } - // background fill - if ((_elements & Body)==Body) { - rounded_function (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius); - if (active_state() == Gtkmm2ext::ImplicitActive && !((_elements & Indicator)==Indicator)) { - ArdourCanvas::set_source_rgba (cr, fill_inactive_color); - cairo_fill (cr); - } else if ( (active_state() == Gtkmm2ext::ExplicitActive) && !((_elements & Indicator)==Indicator) ) { - //background color - ArdourCanvas::set_source_rgba (cr, fill_active_color); - cairo_fill (cr); - } else { //inactive, or it has an indicator - //background color - ArdourCanvas::set_source_rgba (cr, fill_inactive_color); - } - cairo_fill (cr); - } - - // IMPLICIT ACTIVE: draw a border of the active color - if ((_elements & Body)==Body) { - if (active_state() == Gtkmm2ext::ImplicitActive && !((_elements & Indicator)==Indicator)) { - cairo_set_line_width (cr, 2.0); - rounded_function (cr, 2, 2, get_width() - 4, get_height() - 4, corner_radius-0.5); - ArdourCanvas::set_source_rgba (cr, fill_active_color); - cairo_stroke (cr); - } - } - - //show the "convex" or "concave" gradient - if (!_flat_buttons) { - if ( active_state() == Gtkmm2ext::ExplicitActive && ( !((_elements & Indicator)==Indicator) || use_custom_led_color) ) { - //concave - cairo_set_source (cr, concave_pattern); - Gtkmm2ext::rounded_rectangle (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius); - cairo_fill (cr); - } else { - cairo_set_source (cr, convex_pattern); - Gtkmm2ext::rounded_rectangle (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius); - cairo_fill (cr); - } - } +/* TODO make this a dedicated function elsewhere. + * + * Option 1: + * virtual ArdourButton::render_vector_icon() + * ArdourIconButton::render_vector_icon + * + * Option 2: + * ARDOUR_UI_UTILS::render_vector_icon() + */ +static void +render_vector_icon (cairo_t *cr, + const enum ArdourButton::Icon icon, + const int width, const int height, + const Gtkmm2ext::ActiveState state, + const ArdourCanvas::Color fg_color) +{ #define VECTORICONSTROKEFILL(fillalpha) \ cairo_set_line_width(cr, 1.5); \ @@ -294,40 +218,22 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_set_source_rgba (cr, 1, 1, 1, (fillalpha)); \ cairo_fill(cr); - //Pixbuf, if any - if (_pixbuf) { - double x = rint((get_width() - _pixbuf->get_width()) * .5); - const double y = rint((get_height() - _pixbuf->get_height()) * .5); -#if 0 // DEBUG style (print on hover) - if (_hovering || (_elements & Inactive)) { - printf("%s: p:%dx%d (%dx%d)\n", - get_name().c_str(), - _pixbuf->get_width(), _pixbuf->get_height(), - get_width(), get_height()); - } -#endif - if (_elements & Menu) { - //if this is a DropDown with an icon, then we need to - //move the icon left slightly to accomomodate the arrow - x -= _diameter - 2; - } - cairo_rectangle (cr, x, y, _pixbuf->get_width(), _pixbuf->get_height()); - gdk_cairo_set_source_pixbuf (cr, _pixbuf->gobj(), x, y); - cairo_fill (cr); - } - else /* VectorIcons are exclusive to Pixbuf Icons */ + /* TODO separate these into dedicated class * it may also be efficient to render them only once for every size (image-surface) */ - if ((_elements & VectorIcon) && _icon == RecTapeMode) { - const double x = get_width() * .5; - const double y = get_height() * .5; + switch (icon) { + + case ArdourButton::RecTapeMode: + { + const double x = width * .5; + const double y = height * .5; const double r = std::min(x, y) * .6; const double slit = .11 * M_PI; cairo_save(cr); cairo_translate(cr, x, y); cairo_arc (cr, 0, 0, r, 0, 2 * M_PI); - if (active_state() == Gtkmm2ext::ExplicitActive) { + if (state == Gtkmm2ext::ExplicitActive) { cairo_set_source_rgba (cr, .95, .1, .1, 1.); } else { cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f @@ -365,7 +271,7 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_restore(cr); cairo_arc (cr, 0, 0, r * .3, 0, 2 * M_PI); - if (active_state() == Gtkmm2ext::ExplicitActive) + if (state == Gtkmm2ext::ExplicitActive) cairo_set_source_rgba (cr, .95, .1, .1, 1.); else cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f @@ -376,12 +282,14 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_restore(cr); } - else if ((_elements & VectorIcon) && _icon == RecButton) { - const double x = get_width() * .5; - const double y = get_height() * .5; + break; + case ArdourButton::RecButton: + { + const double x = width * .5; + const double y = height * .5; const double r = std::min(x, y) * .55; cairo_arc (cr, x, y, r, 0, 2 * M_PI); - if (active_state() == Gtkmm2ext::ExplicitActive) + if (state == Gtkmm2ext::ExplicitActive) cairo_set_source_rgba (cr, .95, .1, .1, 1.); else cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f @@ -390,11 +298,13 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_set_line_width(cr, 1); cairo_stroke(cr); } - else if ((_elements & VectorIcon) && _icon == CloseCross) { - const double x = get_width() * .5; - const double y = get_height() * .5; + break; + case ArdourButton::CloseCross: + { + const double x = width * .5; + const double y = height * .5; const double o = .5 + std::min(x, y) * .4; - ArdourCanvas::set_source_rgba (cr, text_color); + ArdourCanvas::set_source_rgba (cr, fg_color); cairo_set_line_width(cr, 1); cairo_move_to(cr, x-o, y-o); cairo_line_to(cr, x+o, y+o); @@ -402,22 +312,24 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_line_to(cr, x-o, y+o); cairo_stroke(cr); } - else if ((_elements & VectorIcon) && _icon == StripWidth) { - const double x0 = get_width() * .2; - const double x1 = get_width() * .8; + break; + case ArdourButton::StripWidth: + { + const double x0 = width * .2; + const double x1 = width * .8; - const double y0 = get_height() * .25; - const double y1= get_height() * .75; + const double y0 = height * .25; + const double y1= height * .75; - const double ym= get_height() * .5; + const double ym= height * .5; // arrow - const double xa0= get_height() * .39; - const double xa1= get_height() * .61; - const double ya0= get_height() * .35; - const double ya1= get_height() * .65; + const double xa0= height * .39; + const double xa1= height * .61; + const double ya0= height * .35; + const double ya1= height * .65; - ArdourCanvas::set_source_rgba (cr, text_color); + ArdourCanvas::set_source_rgba (cr, fg_color); cairo_set_line_width(cr, 1); // left + right @@ -443,11 +355,13 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_line_to(cr, xa1, ya1); cairo_stroke(cr); } - else if ((_elements & VectorIcon) && _icon == DinMidi) { - const double x = get_width() * .5; - const double y = get_height() * .5; + break; + case ArdourButton::DinMidi: + { + const double x = width * .5; + const double y = height * .5; const double r = std::min(x, y) * .75; - ArdourCanvas::set_source_rgba (cr, text_color); + ArdourCanvas::set_source_rgba (cr, fg_color); cairo_set_line_width(cr, 1); cairo_arc (cr, x, y, r, .57 * M_PI, 2.43 * M_PI); cairo_stroke(cr); @@ -469,19 +383,23 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_arc (cr, x, y+r, r * .26, 1.05 * M_PI, 1.95 * M_PI); cairo_stroke(cr); } - else if ((_elements & VectorIcon) && _icon == TransportStop) { - const int wh = std::min (get_width(), get_height()); + break; + case ArdourButton::TransportStop: + { + const int wh = std::min (width, height); cairo_rectangle (cr, - (get_width() - wh) * .5 + wh * .25, - (get_height() - wh) * .5 + wh * .25, + (width - wh) * .5 + wh * .25, + (height - wh) * .5 + wh * .25, wh * .5, wh * .5); VECTORICONSTROKEFILL(0.8); } - else if ((_elements & VectorIcon) && _icon == TransportPlay) { - const int wh = std::min (get_width(), get_height()) * .5; - const double y = get_height() * .5; - const double x = get_width() - wh; + break; + case ArdourButton::TransportPlay: + { + const int wh = std::min (width, height) * .5; + const double y = height * .5; + const double x = width - wh; const float tri = ceil(.577 * wh); // 1/sqrt(3) @@ -492,10 +410,12 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) VECTORICONSTROKEFILL(0.8); } - else if ((_elements & VectorIcon) && _icon == TransportPanic) { - const int wh = std::min (get_width(), get_height()) * .1; - const double xc = get_width() * .5; - const double yh = get_height(); + break; + case ArdourButton::TransportPanic: + { + const int wh = std::min (width, height) * .1; + const double xc = width * .5; + const double yh = height; cairo_rectangle (cr, xc - wh, yh *.19, wh * 2, yh *.41); @@ -504,33 +424,37 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_arc (cr, xc, yh *.75, wh, 0, 2 * M_PI); VECTORICONSTROKEFILL(0.8); } - else if ((_elements & VectorIcon) && (_icon == TransportStart || _icon == TransportEnd || _icon == TransportRange)) { + break; + case ArdourButton::TransportStart: + case ArdourButton::TransportEnd: + case ArdourButton::TransportRange: + { // small play triangle - int wh = std::min (get_width(), get_height()); - const double y = get_height() * .5; - const double x = get_width() - wh * .5; + int wh = std::min (width, height); + const double y = height * .5; + const double x = width - wh * .5; wh *= .18; const float tri = ceil(.577 * wh * 2); // 1/sqrt(3) - const float ln = std::min (get_width(), get_height()) * .07; + const float ln = std::min (width, height) * .07; - if (_icon == TransportStart || _icon == TransportRange) { + if (icon == ArdourButton::TransportStart || icon == ArdourButton::TransportRange) { cairo_rectangle (cr, - x - wh - ln, y - tri * 1.7, - ln * 2, tri * 3.4); + x - wh - ln, y - tri * 1.7, + ln * 2, tri * 3.4); VECTORICONSTROKEFILL(1.0); } - if (_icon == TransportEnd || _icon == TransportRange) { + if (icon == ArdourButton::TransportEnd || icon == ArdourButton::TransportRange) { cairo_rectangle (cr, - x + wh - ln, y - tri * 1.7, - ln * 2, tri * 3.4); + x + wh - ln, y - tri * 1.7, + ln * 2, tri * 3.4); VECTORICONSTROKEFILL(1.0); } - if (_icon == TransportStart) { + if (icon == ArdourButton::TransportStart) { cairo_move_to (cr, x - wh, y); cairo_line_to (cr, x + wh, y - tri); cairo_line_to (cr, x + wh, y + tri); @@ -543,9 +467,11 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_close_path (cr); VECTORICONSTROKEFILL(1.0); } - else if ((_elements & VectorIcon) && _icon == TransportLoop) { - const double x = get_width() * .5; - const double y = get_height() * .5; + break; + case ArdourButton::TransportLoop: + { + const double x = width * .5; + const double y = height * .5; const double r = std::min(x, y); cairo_arc (cr, x, y, r * .62, 0, 2 * M_PI); @@ -568,17 +494,19 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) cairo_fill(cr); #undef ARCARROW } - else if ((_elements & VectorIcon) && _icon == TransportMetronom) { - const double x = get_width() * .5; - const double y = get_height() * .5; + break; + case ArdourButton::TransportMetronom: + { + const double x = width * .5; + const double y = height * .5; const double wh = std::min(x, y); const double h = wh * .85; const double w = wh * .55; const double lw = w * .34; cairo_rectangle (cr, - x - w * .7, y + h * .25, - w * 1.4, lw); + x - w * .7, y + h * .25, + w * 1.4, lw); VECTORICONSTROKEFILL(1.0); @@ -611,15 +539,137 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) VECTORICONSTROKEFILL(1.0); cairo_rectangle (cr, - x - w * .7, y + h * .25, - w * 1.4, lw); + x - w * .7, y + h * .25, + w * 1.4, lw); cairo_fill(cr); } - else if (_elements & VectorIcon) { + break; + default: // missing icon assert(0); - } + } // end case(icon) #undef VECTORICONSTROKEFILL +} + +void +ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) +{ + uint32_t text_color; + uint32_t led_color; + + const float corner_radius = std::max(2.f, _corner_radius * ARDOUR_UI::ui_scale); + + if (_update_colors) { + set_colors (); + } + if (get_height() != _pattern_height) { + build_patterns (); + } + + if ( active_state() == Gtkmm2ext::ExplicitActive ) { + text_color = text_active_color; + led_color = led_active_color; + } else { + text_color = text_inactive_color; + led_color = led_inactive_color; + } + + if (use_custom_led_color) { + led_color = led_custom_color; + } + + void (*rounded_function)(cairo_t*, double, double, double, double, double); + + switch (_corner_mask) { + case 0x1: /* upper left only */ + rounded_function = Gtkmm2ext::rounded_top_left_rectangle; + break; + case 0x2: /* upper right only */ + rounded_function = Gtkmm2ext::rounded_top_right_rectangle; + break; + case 0x3: /* upper only */ + rounded_function = Gtkmm2ext::rounded_top_rectangle; + break; + /* should really have functions for lower right, lower left, + lower only, but for now, we don't + */ + default: + rounded_function = Gtkmm2ext::rounded_rectangle; + } + + // draw edge (filling a rect underneath, rather than stroking a border on top, allows the corners to be lighter-weight. + if ((_elements & (Body|Edge)) == (Body|Edge)) { + rounded_function (cr, 0, 0, get_width(), get_height(), corner_radius + 1.5); + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_fill(cr); + } + + // background fill + if ((_elements & Body)==Body) { + rounded_function (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius); + if (active_state() == Gtkmm2ext::ImplicitActive && !((_elements & Indicator)==Indicator)) { + ArdourCanvas::set_source_rgba (cr, fill_inactive_color); + cairo_fill (cr); + } else if ( (active_state() == Gtkmm2ext::ExplicitActive) && !((_elements & Indicator)==Indicator) ) { + //background color + ArdourCanvas::set_source_rgba (cr, fill_active_color); + cairo_fill (cr); + } else { //inactive, or it has an indicator + //background color + ArdourCanvas::set_source_rgba (cr, fill_inactive_color); + } + cairo_fill (cr); + } + + // IMPLICIT ACTIVE: draw a border of the active color + if ((_elements & Body)==Body) { + if (active_state() == Gtkmm2ext::ImplicitActive && !((_elements & Indicator)==Indicator)) { + cairo_set_line_width (cr, 2.0); + rounded_function (cr, 2, 2, get_width() - 4, get_height() - 4, corner_radius-0.5); + ArdourCanvas::set_source_rgba (cr, fill_active_color); + cairo_stroke (cr); + } + } + + //show the "convex" or "concave" gradient + if (!_flat_buttons) { + if ( active_state() == Gtkmm2ext::ExplicitActive && ( !((_elements & Indicator)==Indicator) || use_custom_led_color) ) { + //concave + cairo_set_source (cr, concave_pattern); + Gtkmm2ext::rounded_rectangle (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius); + cairo_fill (cr); + } else { + cairo_set_source (cr, convex_pattern); + Gtkmm2ext::rounded_rectangle (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius); + cairo_fill (cr); + } + } + + //Pixbuf, if any + if (_pixbuf) { + double x = rint((get_width() - _pixbuf->get_width()) * .5); + const double y = rint((get_height() - _pixbuf->get_height()) * .5); +#if 0 // DEBUG style (print on hover) + if (_hovering || (_elements & Inactive)) { + printf("%s: p:%dx%d (%dx%d)\n", + get_name().c_str(), + _pixbuf->get_width(), _pixbuf->get_height(), + get_width(), get_height()); + } +#endif + if (_elements & Menu) { + //if this is a DropDown with an icon, then we need to + //move the icon left slightly to accomomodate the arrow + x -= _diameter - 2; + } + cairo_rectangle (cr, x, y, _pixbuf->get_width(), _pixbuf->get_height()); + gdk_cairo_set_source_pixbuf (cr, _pixbuf->gobj(), x, y); + cairo_fill (cr); + } + else /* VectorIcons are exclusive to Pixbuf Icons */ + if (_elements & VectorIcon) { + render_vector_icon (cr, _icon, get_width(), get_height(), active_state(), text_color); + } const int text_margin = char_pixel_width(); // Text, if any -- cgit v1.2.3