X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_button.cc;h=c1626e6aad693c4fcb669d9182354946acc87083;hb=c3d8967870f4a973945e6e6c723bbd8c24ad76eb;hp=1c2862926fde5d40e0dd1960277d9ca9039ccc08;hpb=5509165935855323d0827ce0e41b9b8be965e695;p=ardour.git diff --git a/gtk2_ardour/ardour_button.cc b/gtk2_ardour/ardour_button.cc index 1c2862926f..c1626e6aad 100644 --- a/gtk2_ardour/ardour_button.cc +++ b/gtk2_ardour/ardour_button.cc @@ -24,6 +24,7 @@ #include #include "pbd/compose.h" +#include "pbd/controllable.h" #include "pbd/error.h" #include "pbd/stacktrace.h" @@ -31,16 +32,14 @@ #include "gtkmm2ext/rgb_macros.h" #include "gtkmm2ext/gui_thread.h" -#include "ardour/rc_configuration.h" // for widget prelight preference - #include "canvas/utils.h" #include "canvas/colors.h" #include "ardour_button.h" -#include "ardour_ui.h" -#include "global_signals.h" +#include "tooltips.h" +#include "ui_config.h" -#include "i18n.h" +#include "pbd/i18n.h" #define BASELINESTRETCH (1.25) #define TRACKHEADERBTNW (3.10) @@ -49,6 +48,7 @@ using namespace Gdk; using namespace Gtk; using namespace Glib; using namespace PBD; +using namespace ARDOUR_UI_UTILS; using std::max; using std::min; using namespace std; @@ -58,8 +58,10 @@ ArdourButton::Element ArdourButton::led_default_elements = ArdourButton::Element ArdourButton::Element ArdourButton::just_led_default_elements = ArdourButton::Element (ArdourButton::Edge|ArdourButton::Body|ArdourButton::Indicator); ArdourButton::ArdourButton (Element e) - : _elements (e) - , _icon (ArdourButton::NoIcon) + : _sizing_text("") + , _markup (false) + , _elements (e) + , _icon (Gtkmm2ext::ArdourIcon::NoIcon) , _tweaks (Tweaks (0)) , _char_pixel_width (0) , _char_pixel_height (0) @@ -67,7 +69,7 @@ ArdourButton::ArdourButton (Element e) , _text_width (0) , _text_height (0) , _diameter (0) - , _corner_radius (2.5) + , _corner_radius (3.5) , _corner_mask (0xf) , _angle(0) , _xalign(.5) @@ -96,16 +98,24 @@ ArdourButton::ArdourButton (Element e) , _update_colors (true) , _pattern_height (0) { - ARDOUR_UI_UTILS::ColorsChanged.connect (sigc::mem_fun (*this, &ArdourButton::color_handler)); + UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &ArdourButton::color_handler)); + /* This is not provided by gtkmm */ + signal_grab_broken_event().connect (sigc::mem_fun (*this, &ArdourButton::on_grab_broken_event)); } ArdourButton::ArdourButton (const std::string& str, Element e) - : _elements (e) + : _sizing_text("") + , _markup (false) + , _elements (e) + , _icon (Gtkmm2ext::ArdourIcon::NoIcon) , _tweaks (Tweaks (0)) + , _char_pixel_width (0) + , _char_pixel_height (0) + , _char_avg_pixel_width (0) , _text_width (0) , _text_height (0) , _diameter (0) - , _corner_radius (2.5) + , _corner_radius (3.5) , _corner_mask (0xf) , _angle(0) , _xalign(.5) @@ -135,8 +145,10 @@ ArdourButton::ArdourButton (const std::string& str, Element e) , _pattern_height (0) { set_text (str); - ARDOUR_UI_UTILS::ColorsChanged.connect (sigc::mem_fun (*this, &ArdourButton::color_handler)); - ARDOUR_UI_UTILS::DPIReset.connect (sigc::mem_fun (*this, &ArdourButton::on_name_changed)); + UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &ArdourButton::color_handler)); + UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ArdourButton::on_name_changed)); + /* This is not provided by gtkmm */ + signal_grab_broken_event().connect (sigc::mem_fun (*this, &ArdourButton::on_grab_broken_event)); } ArdourButton::~ArdourButton() @@ -163,19 +175,57 @@ ArdourButton::set_layout_font (const Pango::FontDescription& fd) if (_layout) { _layout->set_font_description (fd); queue_resize (); + _char_pixel_width = 0; + _char_pixel_height = 0; + } +} + +void +ArdourButton::set_text_internal () { + assert (_layout); + if (_markup) { + _layout->set_markup (_text); + } else { + _layout->set_text (_text); } } void -ArdourButton::set_text (const std::string& str) +ArdourButton::set_text (const std::string& str, bool markup) { + if (!(_elements & Text)) { + return; + } + if (_text == str && _markup == markup) { + return; + } + _text = str; + _markup = markup; if (!is_realized()) { return; } ensure_layout (); if (_layout && _layout->get_text() != _text) { - _layout->set_text (_text); + set_text_internal (); + /* on_size_request() will fill in _text_width/height + * so queue it even if _sizing_text != "" */ + queue_resize (); + } +} + +void +ArdourButton::set_sizing_text (const std::string& str) +{ + if (_sizing_text == str) { + return; + } + _sizing_text = str; + if (!is_realized()) { + return; + } + ensure_layout (); + if (_layout) { queue_resize (); } } @@ -193,14 +243,23 @@ ArdourButton::set_alignment (const float xa, const float ya) _yalign = ya; } + +/* 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() + */ void ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) { uint32_t text_color; uint32_t led_color; - const double dpiscale = ARDOUR_UI::config()->get_font_scale () / 102400.; - const double corner_radius = std::max(2.0, _corner_radius * dpiscale); + const float corner_radius = std::max(2.f, _corner_radius * UIConfiguration::instance().get_ui_scale()); if (_update_colors) { set_colors (); @@ -275,7 +334,7 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) } //show the "convex" or "concave" gradient - if (!_flat_buttons) { + if (!_flat_buttons && (_elements & Body)==Body) { if ( active_state() == Gtkmm2ext::ExplicitActive && ( !((_elements & Indicator)==Indicator) || use_custom_led_color) ) { //concave cairo_set_source (cr, concave_pattern); @@ -288,13 +347,6 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) } } -#define VECTORICONSTROKEFILL(fillalpha) \ - cairo_set_line_width(cr, 1.5); \ - cairo_set_source_rgba (cr, 0, 0, 0, 1.0); \ - cairo_stroke_preserve(cr); \ - 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); @@ -317,310 +369,14 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) 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; - 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) { - cairo_set_source_rgba (cr, .95, .1, .1, 1.); - } else { - cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f - } - cairo_fill_preserve(cr); - cairo_set_source_rgba (cr, .0, .0, .0, .5); - cairo_set_line_width(cr, 1); - cairo_stroke(cr); - - cairo_save(cr); - cairo_set_source_rgba (cr, .15, .07, .07, 1.0); - - cairo_rotate (cr, -.5 * M_PI); - cairo_move_to(cr, 0, 0); - cairo_arc (cr, 0, 0, r *.85, -slit, slit); - cairo_line_to(cr, 0, 0); - cairo_close_path(cr); - - cairo_fill(cr); - cairo_rotate (cr, 2. * M_PI / 3.); - - cairo_move_to(cr, 0, 0); - cairo_arc (cr, 0, 0, r *.85, -slit, slit); - cairo_line_to(cr, 0, 0); - cairo_close_path(cr); - cairo_fill(cr); - - cairo_rotate (cr, 2. * M_PI / 3.); - cairo_move_to(cr, 0, 0); - cairo_arc (cr, 0, 0, r *.85, -slit, slit); - cairo_line_to(cr, 0, 0); - cairo_close_path(cr); - cairo_fill(cr); - - cairo_restore(cr); - - cairo_arc (cr, 0, 0, r * .3, 0, 2 * M_PI); - if (active_state() == Gtkmm2ext::ExplicitActive) - cairo_set_source_rgba (cr, .95, .1, .1, 1.); - else - cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f - cairo_fill(cr); - cairo_set_source_rgba (cr, .0, .0, .0, 1.0); - cairo_arc (cr, 0, 0, r *.15, 0, 2 * M_PI); // hole in the middle - cairo_fill(cr); - - cairo_restore(cr); - } - else if ((_elements & VectorIcon) && _icon == RecButton) { - const double x = get_width() * .5; - const double y = get_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) - cairo_set_source_rgba (cr, .95, .1, .1, 1.); - else - cairo_set_source_rgba (cr, .95, .44, .44, 1.); // #f46f6f - cairo_fill_preserve(cr); - cairo_set_source_rgba (cr, .0, .0, .0, .8); - 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; - const double o = .5 + std::min(x, y) * .4; - ArdourCanvas::set_source_rgba (cr, text_color); - cairo_set_line_width(cr, 1); - cairo_move_to(cr, x-o, y-o); - cairo_line_to(cr, x+o, y+o); - cairo_move_to(cr, x+o, y-o); - 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; - - const double y0 = get_height() * .25; - const double y1= get_height() * .75; - - const double ym= get_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; - - ArdourCanvas::set_source_rgba (cr, text_color); - cairo_set_line_width(cr, 1); - - // left + right - cairo_move_to(cr, x0, y0); - cairo_line_to(cr, x0, y1); - cairo_move_to(cr, x1, y0); - cairo_line_to(cr, x1, y1); - - // horiz center line - cairo_move_to(cr, x0, ym); - cairo_line_to(cr, x1, ym); - - // arrow left - cairo_move_to(cr, x0, ym); - cairo_line_to(cr, xa0, ya0); - cairo_move_to(cr, x0, ym); - cairo_line_to(cr, xa0, ya1); - - // arrow right - cairo_move_to(cr, x1, ym); - cairo_line_to(cr, xa1, ya0); - cairo_move_to(cr, x1, ym); - 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; - const double r = std::min(x, y) * .75; - ArdourCanvas::set_source_rgba (cr, text_color); - cairo_set_line_width(cr, 1); - cairo_arc (cr, x, y, r, 0, 2 * M_PI); - cairo_stroke(cr); - - // pins equally spaced 45deg - cairo_arc (cr, x, y * 0.5, r * .15, 0, 2 * M_PI); - cairo_fill(cr); - cairo_arc (cr, x * 0.5, y, r * .15, 0, 2 * M_PI); - cairo_fill(cr); - cairo_arc (cr, x * 1.5, y, r * .15, 0, 2 * M_PI); - cairo_fill(cr); - // .5 + .5 * .5 * sin(45deg), 1.5 - .5 * .5 * cos(45deg) - cairo_arc (cr, x * 0.677, y * .677, r * .15, 0, 2 * M_PI); - cairo_fill(cr); - cairo_arc (cr, x * 1.323, y * .677, r * .15, 0, 2 * M_PI); - cairo_fill(cr); - - // bottom notch - cairo_arc (cr, x, y+r, r * .28, 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()); - cairo_rectangle (cr, - (get_width() - wh) * .5 + wh * .25, - (get_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; - - const float tri = ceil(.577 * wh); // 1/sqrt(3) - - cairo_move_to (cr, x + wh * .5, y); - cairo_line_to (cr, x - wh * .5, y - tri); - cairo_line_to (cr, x - wh * .5, y + tri); - cairo_close_path (cr); - - 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(); - cairo_rectangle (cr, - xc - wh, yh *.2, - wh * 2, yh *.4); - VECTORICONSTROKEFILL(0.8); - - cairo_arc (cr, xc, yh *.75, wh, 0, 2 * M_PI); - VECTORICONSTROKEFILL(0.8); - } - else if ((_elements & VectorIcon) && (_icon == TransportStart || _icon == TransportEnd || _icon == 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; - wh *= .18; - const float tri = ceil(.577 * wh * 2); // 1/sqrt(3) - - const float ln = std::min (get_width(), get_height()) * .07; - - if (_icon == TransportStart || _icon == TransportRange) { - cairo_rectangle (cr, - x - wh - ln, y - tri * 1.7, - ln * 2, tri * 3.4); - - VECTORICONSTROKEFILL(1.0); - } - - if (_icon == TransportEnd || _icon == TransportRange) { - cairo_rectangle (cr, - x + wh - ln, y - tri * 1.7, - ln * 2, tri * 3.4); - - VECTORICONSTROKEFILL(1.0); - } - - if (_icon == TransportStart) { - cairo_move_to (cr, x - wh, y); - cairo_line_to (cr, x + wh, y - tri); - cairo_line_to (cr, x + wh, y + tri); - } else { - cairo_move_to (cr, x + wh, y); - cairo_line_to (cr, x - wh, y - tri); - cairo_line_to (cr, x - wh, y + tri); + if (_elements & VectorIcon) { + int vw = get_width(); + int vh = get_height(); + if (_elements & Menu) { + vw -= _diameter + 4; } - - cairo_close_path (cr); - VECTORICONSTROKEFILL(1.0); + Gtkmm2ext::ArdourIcon::render (cr, _icon, vw, vh, active_state(), text_color); } - else if ((_elements & VectorIcon) && _icon == TransportLoop) { - const double x = get_width() * .5; - const double y = get_height() * .5; - const double r = std::min(x, y); - - cairo_arc (cr, x, y, r * .6, 0, 2 * M_PI); - cairo_arc_negative (cr, x, y, r * .3, 2 * M_PI, 0); - - VECTORICONSTROKEFILL(1.0); -#define ARCARROW(rad, ang) \ - x + (rad) * sin((ang) * 2.0 * M_PI), y + (rad) * cos((ang) * 2.0 * M_PI) - - cairo_move_to (cr, ARCARROW(r * .30, .72)); - cairo_line_to (cr, ARCARROW(r * .08, .72)); - cairo_line_to (cr, ARCARROW(r * .54, .60)); - cairo_line_to (cr, ARCARROW(r * .73, .72)); - cairo_line_to (cr, ARCARROW(r * .60, .72)); - - cairo_set_source_rgba (cr, 0, 0, 0, 1.0); - cairo_stroke_preserve(cr); - cairo_close_path (cr); - cairo_set_source_rgba (cr, 1, 1, 1, 1.0); - cairo_fill(cr); -#undef ARCARROW - } - else if ((_elements & VectorIcon) && _icon == TransportMetronom) { - const double x = get_width() * .5; - const double y = get_height() * .5; - const double wh = std::min(x, y); - const double h = wh * .8; - const double w = wh * .5; - const double lw = w * .25; - - cairo_rectangle (cr, - x - w * .7, y + h * .25, - w * 1.4, lw); - - VECTORICONSTROKEFILL(1.0); - - cairo_move_to (cr, x - w, y + h); - cairo_line_to (cr, x + w, y + h); - cairo_line_to (cr, x + w * .35, y - h); - cairo_line_to (cr, x - w * .35, y - h); - cairo_line_to (cr, x - w, y + h); - - cairo_move_to (cr, x - w + lw, y + h -lw); - cairo_line_to (cr, x - w * .35 + lw, y - h + lw); - cairo_line_to (cr, x + w * .35 - lw, y - h + lw); - cairo_line_to (cr, x + w - lw, y + h -lw); - cairo_line_to (cr, x - w + lw, y + h -lw); - - VECTORICONSTROKEFILL(1.0); - - // ddx = .70 w = .75 * .5 wh = .375 wh - // ddy = .75 h - lw = .75 * .8 wh - wh .5 * .2 = .5 wh - // ang = (ddx/ddy): - // -> angle = atan (ang) = atan (375 / .5) ~= 36deg - const double dx = lw * .2; // 1 - cos(tan^-1(ang)) - const double dy = lw * .4; // 1 - sin(tan^-1(ang)) - cairo_move_to (cr, x - w * .3 , y + h * .25 + lw * .5); - cairo_line_to (cr, x - w + dx , y - h + lw + dy); - cairo_line_to (cr, x - w + lw , y - h + lw); - cairo_line_to (cr, x - w * .3 + lw, y + h * .25 + lw * .5); - cairo_close_path (cr); - - VECTORICONSTROKEFILL(1.0); - - cairo_rectangle (cr, - x - w * .7, y + h * .25, - w * 1.4, lw); - cairo_fill(cr); - } - else if (_elements & VectorIcon) { - // missing icon - assert(0); - } -#undef VECTORICONSTROKEFILL const int text_margin = char_pixel_width(); // Text, if any @@ -672,10 +428,19 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) ww = get_width(); wh = get_height(); - cairo_save (cr); - cairo_rotate(cr, _angle * M_PI / 180.0); + cairo_matrix_t m1; + cairo_get_matrix (cr, &m1); + cairo_matrix_t m2 = m1; + m2.x0 = 0; + m2.y0 = 0; + cairo_set_matrix (cr, &m2); + + if (_angle) { + cairo_rotate(cr, _angle * M_PI / 180.0); + } + cairo_device_to_user(cr, &ww, &wh); - xa = (ww - _text_width) * _xalign; + xa = text_margin + (ww - _text_width - 2 * text_margin) * _xalign; ya = (wh - _text_height) * _yalign; /* quick hack for left/bottom alignment at -90deg @@ -684,10 +449,9 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) */ if (_xalign < 0) xa = ceil(.5 + (ww * fabs(_xalign) + text_margin)); - cairo_move_to (cr, xa, ya); + cairo_move_to (cr, xa + m1.x0, ya + m1.y0); pango_cairo_update_layout(cr, _layout->gobj()); pango_cairo_show_layout (cr, _layout->gobj()); - cairo_restore (cr); } cairo_restore (cr); } @@ -740,12 +504,12 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) //black ring cairo_set_source_rgb (cr, 0, 0, 0); - cairo_arc (cr, 0, 0, _diameter * .5 - 1 * dpiscale, 0, 2 * M_PI); + cairo_arc (cr, 0, 0, _diameter * .5 - 1 * UIConfiguration::instance().get_ui_scale(), 0, 2 * M_PI); cairo_fill(cr); //led color ArdourCanvas::set_source_rgba (cr, led_color); - cairo_arc (cr, 0, 0, _diameter * .5 - 3 * dpiscale, 0, 2 * M_PI); + cairo_arc (cr, 0, 0, _diameter * .5 - 3 * UIConfiguration::instance().get_ui_scale(), 0, 2 * M_PI); cairo_fill(cr); cairo_restore (cr); @@ -754,13 +518,13 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *) // a transparent overlay to indicate insensitivity if ((visual_state() & Gtkmm2ext::Insensitive)) { rounded_function (cr, 0, 0, get_width(), get_height(), corner_radius); - uint32_t ins_color = ARDOUR_UI::config()->color ("gtk_background"); + uint32_t ins_color = UIConfiguration::instance().color ("gtk_background"); ArdourCanvas::set_source_rgb_a (cr, ins_color, 0.6); cairo_fill (cr); } // if requested, show hovering - if (ARDOUR_UI::config()->get_widget_prelight() + if (UIConfiguration::instance().get_widget_prelight() && !((visual_state() & Gtkmm2ext::Insensitive))) { if (_hovering) { rounded_function (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius); @@ -814,9 +578,11 @@ ArdourButton::on_realize() { CairoWidget::on_realize (); ensure_layout (); - if (_layout && _layout->get_text() != _text) { - _layout->set_text (_text); - queue_resize (); + if (_layout) { + if (_layout->get_text() != _text) { + set_text_internal (); + queue_resize (); + } } } @@ -827,19 +593,55 @@ ArdourButton::on_size_request (Gtk::Requisition* req) CairoWidget::on_size_request (req); if (_diameter == 0) { - const float newdia = rint (11. * ARDOUR_UI::config()->get_font_scale () / 102400.); + const float newdia = rintf (11.f * UIConfiguration::instance().get_ui_scale()); if (_diameter != newdia) { _pattern_height = 0; _diameter = newdia; } } - if ((_elements & Text) && !_text.empty()) { - // if _layout does not exist, char_pixel_height() creates it, - req->height = std::max(req->height, (int) ceil(char_pixel_height() * BASELINESTRETCH + 1.0)); + if (_elements & Text) { + + ensure_layout(); + set_text_internal (); + + /* render() needs the size of the displayed text */ _layout->get_pixel_size (_text_width, _text_height); - req->width += rint(1.75 * char_pixel_width()); // padding - req->width += _text_width; + + if (_tweaks & OccasionalText) { + + /* size should not change based on presence or absence + * of text. + */ + + } else { //if (!_text.empty() || !_sizing_text.empty()) { + + req->height = std::max(req->height, (int) ceil(char_pixel_height() * BASELINESTRETCH + 1.0)); + req->width += rint(1.75 * char_pixel_width()); // padding + + if (!_sizing_text.empty()) { + _layout->set_text (_sizing_text); /* use sizing text */ + } + + int sizing_text_width = 0, sizing_text_height = 0; + _layout->get_pixel_size (sizing_text_width, sizing_text_height); + + req->width += sizing_text_width; + + if (!_sizing_text.empty()) { + set_text_internal (); /* restore display text */ + } + } + + /* XXX hack (surprise). Deal with two common rotation angles */ + + if (_angle == 90 || _angle == 270) { + /* do not swap text width or height because we rely on + these being the un-rotated values in ::render() + */ + swap (req->width, req->height); + } + } else { _text_width = 0; _text_height = 0; @@ -861,7 +663,7 @@ ArdourButton::on_size_request (Gtk::Requisition* req) if (_elements & VectorIcon) { assert(!(_elements & Text)); - const int wh = std::max (rint (TRACKHEADERBTNW * char_avg_pixel_width()), ceil (char_pixel_height() * BASELINESTRETCH + 1.)); + const int wh = std::max (6., std::max (rint (TRACKHEADERBTNW * char_avg_pixel_width()), ceil (char_pixel_height() * BASELINESTRETCH + 1.))); req->width += wh; req->height = std::max(req->height, wh); } @@ -881,7 +683,7 @@ ArdourButton::on_size_request (Gtk::Requisition* req) req->width = req->height; if (req->height < req->width) req->height = req->width; - } else if (_text_width > 0 && !(_elements & (Menu | Indicator))) { + } else if (_sizing_text.empty() && _text_width > 0 && !(_elements & Menu)) { // properly centered text for those elements that are centered // (no sub-pixel offset) if ((req->width - _text_width) & 1) { ++req->width; } @@ -900,33 +702,40 @@ void ArdourButton::set_colors () { _update_colors = false; - if (_fixed_colors_set) { + + if (_fixed_colors_set == 0x3) { return; } + std::string name = get_name(); bool failed = false; - fill_active_color = ARDOUR_UI::config()->color (string_compose ("%1: fill active", name), &failed); - if (failed) { - fill_active_color = ARDOUR_UI::config()->color ("generic button: fill active"); + if (!(_fixed_colors_set & 0x1)) { + fill_active_color = UIConfiguration::instance().color (string_compose ("%1: fill active", name), &failed); + if (failed) { + fill_active_color = UIConfiguration::instance().color ("generic button: fill active"); + } } - fill_inactive_color = ARDOUR_UI::config()->color (string_compose ("%1: fill", name), &failed); - if (failed) { - fill_inactive_color = ARDOUR_UI::config()->color ("generic button: fill"); + + if (!(_fixed_colors_set & 0x2)) { + fill_inactive_color = UIConfiguration::instance().color (string_compose ("%1: fill", name), &failed); + if (failed) { + fill_inactive_color = UIConfiguration::instance().color ("generic button: fill"); + } } text_active_color = ArdourCanvas::contrasting_text_color (fill_active_color); text_inactive_color = ArdourCanvas::contrasting_text_color (fill_inactive_color); - led_active_color = ARDOUR_UI::config()->color (string_compose ("%1: led active", name), &failed); + led_active_color = UIConfiguration::instance().color (string_compose ("%1: led active", name), &failed); if (failed) { - led_active_color = ARDOUR_UI::config()->color ("generic button: led active"); + led_active_color = UIConfiguration::instance().color ("generic button: led active"); } /* The inactive color for the LED is just a fairly dark version of the * active color. */ - + ArdourCanvas::HSV inactive (led_active_color); inactive.v = 0.35; @@ -940,13 +749,18 @@ ArdourButton::set_colors () */ void ArdourButton::set_fixed_colors (const uint32_t color_active, const uint32_t color_inactive) { - _fixed_colors_set = true; + set_active_color (color_active); + set_inactive_color (color_inactive); +} - fill_active_color = color_active; - fill_inactive_color = color_inactive; +void ArdourButton::set_active_color (const uint32_t color) +{ + _fixed_colors_set |= 0x1; + + fill_active_color = color; unsigned char r, g, b, a; - UINT_TO_RGBA(color_active, &r, &g, &b, &a); + UINT_TO_RGBA(color, &r, &g, &b, &a); double white_contrast = (max (double(r), 255.) - min (double(r), 255.)) + (max (double(g), 255.) - min (double(g), 255.)) + @@ -960,14 +774,24 @@ void ArdourButton::set_fixed_colors (const uint32_t color_active, const uint32_t RGBA_TO_UINT(255, 255, 255, 255) : /* use white */ RGBA_TO_UINT( 0, 0, 0, 255); /* use black */ + /* XXX what about led colors ? */ + CairoWidget::set_dirty (); +} + +void ArdourButton::set_inactive_color (const uint32_t color) +{ + _fixed_colors_set |= 0x2; + + fill_inactive_color = color; - UINT_TO_RGBA(color_inactive, &r, &g, &b, &a); + unsigned char r, g, b, a; + UINT_TO_RGBA(color, &r, &g, &b, &a); - white_contrast = (max (double(r), 255.) - min (double(r), 255.)) + + double white_contrast = (max (double(r), 255.) - min (double(r), 255.)) + (max (double(g), 255.) - min (double(g), 255.)) + (max (double(b), 255.) - min (double(b), 255.)); - black_contrast = (max (double(r), 0.) - min (double(r), 0.)) + + double black_contrast = (max (double(r), 0.) - min (double(r), 0.)) + (max (double(g), 0.) - min (double(g), 0.)) + (max (double(b), 0.) - min (double(b), 0.)); @@ -1023,7 +847,7 @@ ArdourButton::set_led_left (bool yn) bool ArdourButton::on_button_press_event (GdkEventButton *ev) { - focus_handler (); + focus_handler (this); if (ev->button == 1 && (_elements & Indicator) && _led_rect && _distinct_led_click) { if (ev->x >= _led_rect->x && ev->x < _led_rect->x + _led_rect->width && @@ -1058,7 +882,7 @@ ArdourButton::on_button_release_event (GdkEventButton *ev) if (ev->button == 1 && _hovering && (_elements & Indicator) && _led_rect && _distinct_led_click) { if (ev->x >= _led_rect->x && ev->x < _led_rect->x + _led_rect->width && ev->y >= _led_rect->y && ev->y < _led_rect->y + _led_rect->height) { - signal_led_clicked(); /* EMIT SIGNAL */ + signal_led_clicked(ev); /* EMIT SIGNAL */ return true; } } @@ -1175,6 +999,11 @@ ArdourButton::on_style_changed (const RefPtr&) { _update_colors = true; CairoWidget::set_dirty (); + _char_pixel_width = 0; + _char_pixel_height = 0; + if (is_realized()) { + queue_resize (); + } } void @@ -1221,6 +1050,7 @@ ArdourButton::setup_led_rect () void ArdourButton::set_image (const RefPtr& img) { + _elements = (ArdourButton::Element) (_elements & ~ArdourButton::Text); _pixbuf = img; if (is_realized()) { queue_resize (); @@ -1284,7 +1114,7 @@ ArdourButton::on_enter_notify_event (GdkEventCrossing* ev) { _hovering = (_elements & Inactive) ? false : true; - if (ARDOUR_UI::config()->get_widget_prelight()) { + if (UIConfiguration::instance().get_widget_prelight()) { CairoWidget::set_dirty (); } @@ -1296,13 +1126,23 @@ ArdourButton::on_leave_notify_event (GdkEventCrossing* ev) { _hovering = false; - if (ARDOUR_UI::config()->get_widget_prelight()) { + if (UIConfiguration::instance().get_widget_prelight()) { CairoWidget::set_dirty (); } return CairoWidget::on_leave_notify_event (ev); } +bool +ArdourButton::on_grab_broken_event(GdkEventGrabBroken* grab_broken_event) { + /* Our implicit grab due to a button_press was broken by another grab: + * the button will not get any button_release event if the mouse leaves + * while the grab is taken, so unpress ourselves */ + _grabbed = false; + CairoWidget::set_dirty (); + return true; +} + void ArdourButton::set_tweaks (Tweaks t) { @@ -1384,7 +1224,7 @@ ArdourButton::recalc_char_pixel_geometry () // NB. this is not static, since the geometry is different // depending on the font used. int w, h; - std::string x = _("ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + std::string x = _("@ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); _layout->set_text (x); _layout->get_pixel_size (w, h); _char_pixel_height = std::max(4, h); @@ -1393,7 +1233,7 @@ ArdourButton::recalc_char_pixel_geometry () Glib::ustring gx(x); _char_avg_pixel_width = w / (float)gx.size(); _char_pixel_width = std::max(4, (int) ceil (_char_avg_pixel_width)); - _layout->set_text (_text); + set_text_internal (); /* restore display text */ } void @@ -1410,7 +1250,7 @@ void ArdourButton::action_tooltip_changed () { string str = _action->property_tooltip().get_value(); - ARDOUR_UI::instance()->set_tip (*this, str); + set_tooltip (*this, str); } void @@ -1428,9 +1268,10 @@ ArdourButton::add_elements (Element e) } void -ArdourButton::set_icon (Icon i) +ArdourButton::set_icon (Gtkmm2ext::ArdourIcon::Icon i) { _icon = i; + _elements = (ArdourButton::Element) ((_elements | ArdourButton::VectorIcon) & ~ArdourButton::Text); CairoWidget::set_dirty (); }