diff --git a/libs/widgets/ardour_button.cc b/libs/widgets/ardour_button.cc index 663344aed4..a2231b9d83 100644 --- a/libs/widgets/ardour_button.cc +++ b/libs/widgets/ardour_button.cc @@ -397,7 +397,10 @@ ArdourButton::render (Cairo::RefPtr const& ctx, cairo_rectangle_ 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; + x -= _diameter + 4; + } + if (_elements & MetaMenu) { + x -= 2; } cairo_rectangle (cr, x, y, _pixbuf->get_width(), _pixbuf->get_height()); gdk_cairo_set_source_pixbuf (cr, _pixbuf->gobj(), x, y); @@ -410,6 +413,9 @@ ArdourButton::render (Cairo::RefPtr const& ctx, cairo_rectangle_ if (_elements & Menu) { vw -= _diameter + 4; } + if (_elements & MetaMenu) { + vw -= 2; + } if (_elements & Indicator) { vw -= _diameter + .5 * text_margin; if (_led_left) { @@ -459,7 +465,7 @@ ArdourButton::render (Cairo::RefPtr const& ctx, cairo_rectangle_ Gtkmm2ext::set_source_rgba (cr, text_color); const double text_ypos = round ((get_height() - _text_height) * .5); - if (_elements & Menu) { + if ((_elements & (Menu | MetaMenu)) == Menu) { // always left align (dropdown) cairo_move_to (cr, text_margin, text_ypos); pango_cairo_show_layout (cr, _layout->gobj()); @@ -493,6 +499,9 @@ ArdourButton::render (Cairo::RefPtr const& ctx, cairo_rectangle_ } cairo_device_to_user(cr, &ww, &wh); + if (_elements & MetaMenu) { + ww -= _diameter + 6; + } xa = text_margin + (ww - _text_width - 2 * text_margin) * _xalign; ya = (wh - _text_height) * _yalign; @@ -532,6 +541,14 @@ ArdourButton::render (Cairo::RefPtr const& ctx, cairo_rectangle_ cairo_stroke(cr); } + if (_elements & MetaMenu) { + cairo_move_to(cr, get_width() - floor (_diameter) - 5.5 , 1); + cairo_line_to(cr, get_width() - floor (_diameter) - 5.5 , get_height () -1); + cairo_set_source_rgba (cr, 0, 0, 0, 0.8); + cairo_set_line_width(cr, 1); + cairo_stroke(cr); + } + //Indicator LED if ((_elements & ColorBox)==ColorBox) { cairo_save (cr); @@ -748,10 +765,14 @@ ArdourButton::on_size_request (Gtk::Requisition* req) req->height = std::max (req->height, (int) lrint (_diameter) + 4); } - if ((_elements & Menu)) { + if (_elements & Menu) { req->width += _diameter + 4; } + if (_elements & MetaMenu) { + req->width += 2; // seprator line + } + if (_elements & (VectorIcon | IconRenderCallback)) { const int wh = std::max (8., std::max (ceil (TRACKHEADERBTNW * char_avg_pixel_width()), ceil (char_pixel_height() * BASELINESTRETCH + 1.))); req->width += wh; @@ -776,7 +797,7 @@ ArdourButton::on_size_request (Gtk::Requisition* req) req->width = req->height; if (req->height < req->width) req->height = req->width; - } else if (_sizing_texts.empty() && _text_width > 0 && !(_elements & Menu)) { + } else if (_sizing_texts.empty() && _text_width > 0 && ((_elements & (Menu | MetaMenu)) != (Menu | MetaMenu))) { // properly centered text for those elements that are centered // (no sub-pixel offset) if ((req->width - _text_width) & 1) { ++req->width; } diff --git a/libs/widgets/metabutton.cc b/libs/widgets/metabutton.cc index 638b32e34f..503565443d 100644 --- a/libs/widgets/metabutton.cc +++ b/libs/widgets/metabutton.cc @@ -18,7 +18,10 @@ #include "gtkmm2ext/utils.h" +#include "pbd/unwind.h" + #include "widgets/metabutton.h" +#include "widgets/ui_config.h" using namespace Gtk; using namespace std; @@ -26,12 +29,15 @@ using namespace ArdourWidgets; MetaButton::MetaButton () : _active (0) + , _hover_dropdown (false) { _menu.signal_size_request ().connect (sigc::mem_fun (*this, &MetaButton::menu_size_request)); _menu.set_reserve_toggle_size (false); add_elements (default_elements); add_elements (ArdourButton::Menu); + add_elements (ArdourButton::MetaMenu); + add_events (Gdk::POINTER_MOTION_MASK); } MetaButton::~MetaButton () @@ -60,6 +66,7 @@ MetaButton::add_item (std::string const& label, std::string const& menutext, sig items.push_back (MetaElement (label, menutext, cb, sigc::mem_fun (*this, &MetaButton::activate_item))); if (items.size () == 1) { _menu.set_active (0); + update_button (dynamic_cast (&items.back ())); set_text (label); } } @@ -70,10 +77,12 @@ MetaButton::on_button_press_event (GdkEventButton* ev) MetaMenuItem const* current_active = dynamic_cast (_menu.get_active ()); if (ev->type == GDK_BUTTON_PRESS && ev->button == 3) { - Gtkmm2ext::anchored_menu_popup (&_menu, this, current_active ? current_active->menutext () : "", 3, ev->time); + Gtkmm2ext::anchored_menu_popup (&_menu, this, current_active ? current_active->menutext () : "", ev->button, ev->time); } - - if (ev->type == GDK_BUTTON_PRESS && ev->button == 1) { + else if (ev->type == GDK_BUTTON_PRESS && ev->button == 1 && ev->x > (get_width () - _diameter - 7)) { + Gtkmm2ext::anchored_menu_popup (&_menu, this, current_active ? current_active->menutext () : "", ev->button, ev->time); + } + else if (ev->type == GDK_BUTTON_PRESS && ev->button == 1) { if (current_active) { current_active->activate (); } @@ -82,13 +91,30 @@ MetaButton::on_button_press_event (GdkEventButton* ev) return true; } +bool +MetaButton::on_motion_notify_event (GdkEventMotion* ev) +{ + bool hover_dropdown = ev->x > get_width () - _diameter - 7; + if (hover_dropdown != _hover_dropdown) { + _hover_dropdown = hover_dropdown; + CairoWidget::set_dirty (); + } + return false; +} + void MetaButton::activate_item (MetaMenuItem const* e) { - set_text (e->label ()); + update_button (e); e->activate (); } +void +MetaButton::update_button (MetaMenuItem const* e) +{ + set_text (e->label ()); +} + void MetaButton::set_active (std::string const& menulabel) { @@ -100,7 +126,7 @@ MetaButton::set_active (std::string const& menulabel) if (_menu.get_active () != &i) { _menu.set_active (c); } - set_text (dynamic_cast (&i)->label ()); + update_button (dynamic_cast (&i)); set_active_state (Gtkmm2ext::ExplicitActive); _active = c; found = true; @@ -121,9 +147,28 @@ MetaButton::set_index (guint index) for (auto& i : _menu.items ()) { if (c == index) { _menu.set_active (c); - set_text (dynamic_cast (&i)->label ()); + update_button (dynamic_cast (&i)); break; } ++c; } } + +void +MetaButton::render (Cairo::RefPtr const& ctx, cairo_rectangle_t* rect) +{ + { + PBD::Unwinder uw (_hovering, false); + ArdourButton::render (ctx, rect); + } + if (_hovering && UIConfigurationBase::instance().get_widget_prelight()) { + cairo_t* cr = ctx->cobj(); + if (_hover_dropdown) { + Gtkmm2ext::rounded_right_half_rectangle (cr, get_width () - _diameter - 6, 1, _diameter + 5, get_height() - 2, _corner_radius); + } else { + Gtkmm2ext::rounded_left_half_rectangle (cr, 1, 1, get_width() -_diameter - 7 , get_height() - 2, _corner_radius); + } + cairo_set_source_rgba (cr, 0.905, 0.917, 0.925, 0.2); + cairo_fill (cr); + } +} diff --git a/libs/widgets/widgets/ardour_button.h b/libs/widgets/widgets/ardour_button.h index 250e4b305b..28cdf62f81 100644 --- a/libs/widgets/widgets/ardour_button.h +++ b/libs/widgets/widgets/ardour_button.h @@ -39,15 +39,16 @@ class LIBWIDGETS_API ArdourButton : public CairoWidget , public Gtkmm2ext::Activ { public: enum Element { - Edge = 0x1, - Body = 0x2, - Text = 0x4, - Indicator = 0x8, - ColorBox = 0x18, //also sets Indicator - Menu = 0x20, - Inactive = 0x40, // no _action is defined AND state is not used - VectorIcon = 0x80, - IconRenderCallback = 0x100, + Edge = 0x001, + Body = 0x002, + Text = 0x004, + Indicator = 0x008, + ColorBox = 0x018, // also sets Indicator + Menu = 0x020, + MetaMenu = 0x040, + Inactive = 0x080, // no _action is defined AND state is not used + VectorIcon = 0x100, + IconRenderCallback = 0x200, }; typedef void (* rendercallback_t) (cairo_t*, int, int, uint32_t, void*); diff --git a/libs/widgets/widgets/metabutton.h b/libs/widgets/widgets/metabutton.h index 62bf5a785a..1d7c33ebfb 100644 --- a/libs/widgets/widgets/metabutton.h +++ b/libs/widgets/widgets/metabutton.h @@ -45,7 +45,9 @@ public: protected: bool on_button_press_event (GdkEventButton*); + bool on_motion_notify_event (GdkEventMotion*); void menu_size_request (Gtk::Requisition*); + void render (Cairo::RefPtr const&, cairo_rectangle_t*); private: class MetaMenuItem : public Gtk::MenuItem @@ -95,9 +97,11 @@ private: }; void activate_item (MetaMenuItem const*); + void update_button (MetaMenuItem const*); Gtk::Menu _menu; guint _active; + bool _hover_dropdown; }; } // namespace ArdourWidgets