ArdourButton: Pick up initial action sensitivity
[ardour.git] / gtk2_ardour / ardour_button.cc
index e817882a5d114118bfa2916acbfbef73f5b758b4..9aaf31ba766c80c0670eb08bf72074e33beda62f 100644 (file)
@@ -44,7 +44,6 @@
 #define BASELINESTRETCH (1.25)
 #define TRACKHEADERBTNW (3.10)
 
-using namespace Gdk;
 using namespace Gtk;
 using namespace Glib;
 using namespace PBD;
@@ -59,8 +58,11 @@ ArdourButton::Element ArdourButton::just_led_default_elements = ArdourButton::El
 
 ArdourButton::ArdourButton (Element e)
        : _sizing_text("")
+       , _markup (false)
        , _elements (e)
        , _icon (Gtkmm2ext::ArdourIcon::NoIcon)
+       , _icon_render_cb (0)
+       , _icon_render_cb_data (0)
        , _tweaks (Tweaks (0))
        , _char_pixel_width (0)
        , _char_pixel_height (0)
@@ -68,7 +70,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)
@@ -104,7 +106,9 @@ ArdourButton::ArdourButton (Element e)
 
 ArdourButton::ArdourButton (const std::string& str, Element e)
        : _sizing_text("")
+       , _markup (false)
        , _elements (e)
+       , _icon (Gtkmm2ext::ArdourIcon::NoIcon)
        , _tweaks (Tweaks (0))
        , _char_pixel_width (0)
        , _char_pixel_height (0)
@@ -112,7 +116,7 @@ ArdourButton::ArdourButton (const std::string& str, 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)
@@ -172,22 +176,39 @@ 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 (_text == str) {
+       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 ();
@@ -234,8 +255,10 @@ ArdourButton::set_alignment (const float xa, const float ya)
  * ARDOUR_UI_UTILS::render_vector_icon()
  */
 void
-ArdourButton::render (cairo_t* cr, cairo_rectangle_t *)
+ArdourButton::render (Cairo::RefPtr<Cairo::Context> const& ctx, cairo_rectangle_t*)
 {
+       cairo_t* cr = ctx->cobj();
+
        uint32_t text_color;
        uint32_t led_color;
 
@@ -348,9 +371,22 @@ ArdourButton::render (cairo_t* cr, cairo_rectangle_t *)
                gdk_cairo_set_source_pixbuf (cr, _pixbuf->gobj(), x, y);
                cairo_fill (cr);
        }
-       else /* VectorIcons are exclusive to Pixbuf Icons */
-       if (_elements & VectorIcon) {
-               Gtkmm2ext::ArdourIcon::render (cr, _icon, get_width(), get_height(), active_state(), text_color);
+       else /* VectorIcon, IconRenderCallback are exclusive to Pixbuf Icons */
+       if (_elements & (VectorIcon | IconRenderCallback)) {
+               int vw = get_width();
+               int vh = get_height();
+               if (_elements & Menu) {
+                       vw -= _diameter + 4;
+               }
+               if (_elements & VectorIcon) {
+                       Gtkmm2ext::ArdourIcon::render (cr, _icon, vw, vh, active_state(), text_color);
+               } else {
+                       cairo_save (cr);
+                       rounded_function (cr, 0, 0, get_width(), get_height(), corner_radius + 1.5);
+                       cairo_clip (cr);
+                       _icon_render_cb (cr, vw, vh, text_color, _icon_render_cb_data);
+                       cairo_restore (cr);
+               }
        }
 
        const int text_margin = char_pixel_width();
@@ -403,10 +439,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
@@ -415,10 +460,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);
        }
@@ -547,9 +591,9 @@ ArdourButton::on_realize()
        ensure_layout ();
        if (_layout) {
                if (_layout->get_text() != _text) {
-                       _layout->set_text (_text);
+                       set_text_internal ();
+                       queue_resize ();
                }
-               queue_resize ();
        }
 }
 
@@ -570,7 +614,8 @@ ArdourButton::on_size_request (Gtk::Requisition* req)
        if (_elements & Text) {
 
                ensure_layout();
-               _layout->set_text (_text);
+               set_text_internal ();
+
                /* render() needs the size of the displayed text */
                _layout->get_pixel_size (_text_width, _text_height);
 
@@ -580,7 +625,7 @@ ArdourButton::on_size_request (Gtk::Requisition* req)
                         * of text.
                         */
 
-               } else { //if (!_text.empty() || !_sizing_text.empty()) {
+               } 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
@@ -595,7 +640,7 @@ ArdourButton::on_size_request (Gtk::Requisition* req)
                        req->width += sizing_text_width;
 
                        if (!_sizing_text.empty()) {
-                               _layout->set_text (_text); /* restore display text */
+                               set_text_internal (); /* restore display text */
                        }
                }
 
@@ -627,7 +672,7 @@ ArdourButton::on_size_request (Gtk::Requisition* req)
                req->width += _diameter + 4;
        }
 
-       if (_elements & VectorIcon) {
+       if (_elements & (VectorIcon | IconRenderCallback)) {
                assert(!(_elements & Text));
                const int wh = std::max (6., std::max (rint (TRACKHEADERBTNW * char_avg_pixel_width()), ceil (char_pixel_height() * BASELINESTRETCH + 1.)));
                req->width += wh;
@@ -649,7 +694,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; }
@@ -933,6 +978,7 @@ ArdourButton::set_related_action (RefPtr<Action> act)
        if (_action) {
 
                action_tooltip_changed ();
+               action_sensitivity_changed ();
 
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (_action);
                if (tact) {
@@ -1016,6 +1062,7 @@ ArdourButton::setup_led_rect ()
 void
 ArdourButton::set_image (const RefPtr<Gdk::Pixbuf>& img)
 {
+        _elements = (ArdourButton::Element) (_elements & ~ArdourButton::Text);
        _pixbuf = img;
        if (is_realized()) {
                queue_resize ();
@@ -1062,7 +1109,21 @@ ArdourButton::on_focus_out_event (GdkEventFocus* ev)
 
 bool
 ArdourButton::on_key_release_event (GdkEventKey *ev) {
-       if (_focused &&
+       if (_act_on_release && _focused &&
+                       (ev->keyval == GDK_space || ev->keyval == GDK_Return))
+       {
+               signal_clicked();
+               if (_action) {
+                       _action->activate ();
+               }
+               return true;
+       }
+       return CairoWidget::on_key_release_event (ev);
+}
+
+bool
+ArdourButton::on_key_press_event (GdkEventKey *ev) {
+       if (!_act_on_release && _focused &&
                        (ev->keyval == GDK_space || ev->keyval == GDK_Return))
        {
                signal_clicked();
@@ -1189,7 +1250,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);
@@ -1198,7 +1259,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
@@ -1236,7 +1297,24 @@ void
 ArdourButton::set_icon (Gtkmm2ext::ArdourIcon::Icon i)
 {
        _icon = i;
-       _elements = (ArdourButton::Element) ((_elements | ArdourButton::VectorIcon) & ~ArdourButton::Text);
+       _icon_render_cb = 0;
+       _icon_render_cb_data = 0;
+       _elements = (ArdourButton::Element) ((_elements | VectorIcon) & ~(ArdourButton::Text | IconRenderCallback));
+       CairoWidget::set_dirty ();
+}
+
+void
+ArdourButton::set_icon (rendercallback_t cb, void* d)
+{
+       if (!cb) {
+               _elements = (ArdourButton::Element) ((_elements | ArdourButton::Text) & ~(IconRenderCallback | VectorIcon));
+               _icon_render_cb = 0;
+               _icon_render_cb_data = 0;
+       } else {
+               _elements = (ArdourButton::Element) ((_elements | IconRenderCallback) & ~(ArdourButton::Text | VectorIcon));
+               _icon_render_cb = cb;
+               _icon_render_cb_data = d;
+       }
        CairoWidget::set_dirty ();
 }