Compare commits

...

8 Commits

Author SHA1 Message Date
Ben Loftis ca744cd94a tooltips: append 'Lock' to Solo Safe menu-item, to match mixer-strip button 2022-06-17 11:08:04 -05:00
Ben Loftis 1965e90c24 tooltips: enumerate the various modifiers for mute, solo, scenes
TODO: monitor buttons, maybe more
2022-06-17 11:07:58 -05:00
Ben Loftis fd9a76073b modifiers: add momentary_push_name (for tooltips) 2022-06-17 11:07:58 -05:00
Ben Loftis 9a6533c382 modifiers: unconditionally show the solo context menu
* accessing solo-isolate from the context menu is the preferred way
* some route_uis (like track headers) do not have solo isolate buttons
2022-06-17 11:07:58 -05:00
Ben Loftis 88888237ac modifiers: remove shortcut for solo isolate
* you should not be able to invisibly change a solo 'mode' from a modified click

* we want to use shift+click for momentary operation, anyway
2022-06-17 11:07:58 -05:00
Ben Loftis a92af7768d modifiers: implement is_momentary_push_event for momentary buttons (gtk2 part) 2022-06-17 11:07:58 -05:00
Ben Loftis 12e703414d modifiers: make a new abstraction for momentary-click, instead of button_2 (lib part)
is_button2_event()  was used to detect the user's desire for a
  momentary-click on some buttons (mute, solo, mixer scenes)

is_momentary_push_event() disambiguates this action from is_button2_event()

for the special case of momentary, we can drop the workarounds for
  the lack of middle-mouse buttons on Mac, and instead just use
  shift+left-click on all platforms.
2022-06-17 11:07:49 -05:00
Ben Loftis 71833911a4 modifiers: publish button2_name (for use in tooltips) 2022-06-17 10:52:06 -05:00
5 changed files with 66 additions and 33 deletions

View File

@ -4116,7 +4116,7 @@ Mixer_UI::scene_button_press (GdkEventButton* ev, int idx)
popup_scene_menu (ev, idx);
} else if (Keyboard::is_delete_event (ev)) {
clear_mixer_scene (idx, true);
} else if (Keyboard::is_button2_event (ev)) {
} else if (Keyboard::is_momentary_push_event (ev)) {
/* momentary */
delete _mixer_scene_release; // .. or keep existing?
_mixer_scene_release = new MixerScene (*_session);
@ -4174,13 +4174,11 @@ Mixer_UI::update_scene_buttons ()
if (scn && !scn->empty()) {
ArdourButton* b = _mixer_scene_buttons[idx];
ArdourWidgets::set_tooltip (b, _("Click to recall this mixer scene\n"
#ifdef __APPLE__
"Middle-Click (or Ctrl+Alt click) for momentary restore\n"
#else
"Middle-Click for momentary restore\n"
#endif
"Right-Click for context menu"));
ArdourWidgets::set_tooltip (b, string_compose(
_("Click to recall this mixer scene\n"
"%1 for Momentary Restore\n"
"Right-Click for Context menu")
, Keyboard::button2_name() ) );
l->set_text (scn->name());
all_unset = false;
} else {

View File

@ -1669,7 +1669,7 @@ RecorderUI::InputPort::monitor_press (GdkEventButton* ev)
if (Keyboard::is_context_menu_event (ev)) {
return false;
}
if (ev->button != 1 && !Keyboard::is_button2_event (ev)) {
if (ev->button != 1 && !Keyboard::is_momentary_push_event (ev)) {
return false;
}
@ -1677,7 +1677,7 @@ RecorderUI::InputPort::monitor_press (GdkEventButton* ev)
Session* s = AudioEngine::instance()->session ();
assert (s);
if (Keyboard::is_button2_event (ev)) {
if (Keyboard::is_momentary_push_event (ev)) {
/* momentary */
_solo_release = new SoloMuteRelease (mp.monitoring (_port_name));
}

View File

@ -207,7 +207,13 @@ RouteUI::init ()
mute_button = manage (new ArdourButton);
mute_button->set_name ("mute button");
UI::instance()->set_tip (mute_button, _("Mute this track"), "");
std::string tip = string_compose( _("Mute this track\n"
"%1+Click to Override Group\n"
"%1+%3+Click to toggle ALL tracks\n"
"%4 for Momentary mute\n"
"Right-Click for Context menu")
, Keyboard::primary_modifier_short_name(), Keyboard::secondary_modifier_short_name(), Keyboard::tertiary_modifier_short_name(), Keyboard::button2_name() );
UI::instance()->set_tip (mute_button, tip.c_str(), "");
solo_button = manage (new ArdourButton);
solo_button->set_name ("solo button");
@ -216,7 +222,12 @@ RouteUI::init ()
rec_enable_button = manage (new ArdourButton);
rec_enable_button->set_name ("record enable button");
rec_enable_button->set_icon (ArdourIcon::RecButton);
UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
tip = string_compose( _("Enable Recording on this track\n"
"%1+Click to Override group\n"
"%1+%3+Click to toggle ALL tracks\n"
"Right-Click for Context menu")
, Keyboard::primary_modifier_short_name(), Keyboard::secondary_modifier_short_name(), Keyboard::tertiary_modifier_short_name(), Keyboard::button2_name() );
UI::instance()->set_tip (rec_enable_button, tip.c_str(), "");
if (UIConfiguration::instance().get_blink_rec_arm()) {
rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
@ -475,7 +486,7 @@ RouteUI::mute_press (GdkEventButton* ev)
} else {
if (Keyboard::is_button2_event (ev)) {
if (Keyboard::is_momentary_push_event (ev)) {
// button2-click is "momentary"
_mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
@ -635,19 +646,15 @@ RouteUI::solo_press(GdkEventButton* ev)
if (Keyboard::is_context_menu_event (ev)) {
if (! (solo_isolated_led && solo_isolated_led->get_visible()) ||
! (solo_safe_led && solo_safe_led->get_visible())) {
if (solo_menu == 0) {
build_solo_menu ();
}
solo_menu->popup (1, ev->time);
if (solo_menu == 0) {
build_solo_menu ();
}
solo_menu->popup (1, ev->time);
} else {
if (Keyboard::is_button2_event (ev)) {
if (Keyboard::is_momentary_push_event (ev)) {
// button2-click is "momentary"
_solo_release = new SoloMuteRelease (_route->self_soloed());
@ -679,13 +686,7 @@ RouteUI::solo_press(GdkEventButton* ev)
DisplaySuspender ds;
_route->solo_control()->set_value (1.0, Controllable::NoGroup);
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
// shift-click: toggle solo isolated status
_route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
delete _solo_release;
_solo_release = 0;
/* } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) { do not explicitly implement Tertiary Modifier; this is the default for Momentary */
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
@ -787,7 +788,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
if (is_track() && rec_enable_button) {
if (Keyboard::is_button2_event (ev)) {
if (Keyboard::is_momentary_push_event (ev)) {
//rec arm does not have a momentary mode
return false;
@ -1427,7 +1428,7 @@ RouteUI::build_solo_menu (void)
solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
check->show_all();
check = new Gtk::CheckMenuItem(_("Solo Safe"));
check = new Gtk::CheckMenuItem(_("Solo Safe (Locked)"));
check->set_active (_route->solo_safe_control()->solo_safe());
check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
items.push_back (CheckMenuElem(*check));
@ -2006,12 +2007,25 @@ void
RouteUI::update_solo_button ()
{
set_button_names ();
std::string tip;
if (Config->get_solo_control_is_listen_control()) {
UI::instance()->set_tip (solo_button, _("Listen to this track"), "");
tip = string_compose( _("Listen to this track\n"
"%1+Click to Override Group\n"
"%1+%3+Click to toggle ALL tracks\n"
"%4 for Momentary listen\n"
"Right-Click for Context menu")
, Keyboard::primary_modifier_short_name(), Keyboard::secondary_modifier_short_name(), Keyboard::tertiary_modifier_short_name(), Keyboard::button2_name() );
} else {
UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
tip = string_compose( _("Solo this track\n"
"%1+Click to Override Group\n"
"%1+%2+Click for Exclusive solo\n"
"%1+%3+Click to toggle ALL tracks\n"
"%4 for Momentary solo\n"
"Right-Click for Context menu")
, Keyboard::primary_modifier_short_name(), Keyboard::secondary_modifier_short_name(), Keyboard::tertiary_modifier_short_name(), Keyboard::button2_name() );
}
UI::instance()->set_tip (solo_button, tip.c_str());
}
void

View File

@ -78,6 +78,9 @@ class LIBGTKMM2EXT_API Keyboard : public sigc::trackable, PBD::Stateful
static const char* tertiary_modifier_name ();
static const char* level4_modifier_name ();
static const char* button2_name ();
static const char* momentary_push_name ();
static const char* primary_modifier_short_name ();
static const char* secondary_modifier_short_name ();
static const char* tertiary_modifier_short_name ();
@ -161,6 +164,7 @@ class LIBGTKMM2EXT_API Keyboard : public sigc::trackable, PBD::Stateful
static bool is_insert_note_event (GdkEventButton*);
static bool is_context_menu_event (GdkEventButton*);
static bool is_button2_event (GdkEventButton*);
static bool is_momentary_push_event (GdkEventButton*);
static Keyboard& the_keyboard() { return *_the_keyboard; }
@ -207,6 +211,7 @@ class LIBGTKMM2EXT_API Keyboard : public sigc::trackable, PBD::Stateful
static guint snap_mod;
static guint snap_delta_mod;
static guint button2_modifiers;
static guint momentary_push_modifiers;
static Gtk::Window* current_window;
static std::string user_keybindings_path;
static bool can_save_keybindings;

View File

@ -71,12 +71,16 @@ guint Keyboard::Level4Modifier = GDK_MOD1_MASK; // Alt/Option
guint Keyboard::CopyModifier = GDK_CONTROL_MASK; // Control
guint Keyboard::RangeSelectModifier = GDK_SHIFT_MASK;
guint Keyboard::button2_modifiers = Keyboard::SecondaryModifier|Keyboard::Level4Modifier;
guint Keyboard::momentary_push_modifiers = Keyboard::TertiaryModifier;
const char* Keyboard::primary_modifier_name() { return _("Command"); }
const char* Keyboard::secondary_modifier_name() { return _("Control"); }
const char* Keyboard::tertiary_modifier_name() { return S_("Key|Shift"); }
const char* Keyboard::level4_modifier_name() { return _("Option"); }
const char* Keyboard::button2_name() { return _("Middle Click (or Ctrl+Alt+Click)"); }
const char* Keyboard::momentary_push_name() { return _("Shift+Click (or Middle-Click)"); }
const char* Keyboard::primary_modifier_short_name() { return _("Cmd"); }
const char* Keyboard::secondary_modifier_short_name() { return _("Ctrl"); }
const char* Keyboard::tertiary_modifier_short_name() { return S_("Key|Shift"); }
@ -94,12 +98,16 @@ guint Keyboard::Level4Modifier = GDK_MOD4_MASK|GDK_SUPER_MASK; // Mod4/Windows
guint Keyboard::CopyModifier = GDK_CONTROL_MASK;
guint Keyboard::RangeSelectModifier = GDK_SHIFT_MASK;
guint Keyboard::button2_modifiers = 0; /* not used */
guint Keyboard::momentary_push_modifiers = Keyboard::TertiaryModifier;
const char* Keyboard::primary_modifier_name() { return _("Control"); }
const char* Keyboard::secondary_modifier_name() { return _("Alt"); }
const char* Keyboard::tertiary_modifier_name() { return S_("Key|Shift"); }
const char* Keyboard::level4_modifier_name() { return _("Windows"); }
const char* Keyboard::button2_name() { return _("Middle-Click"); }
const char* Keyboard::momentary_push_name() { return _("Middle-Click (or Shift+Click)"); }
const char* Keyboard::primary_modifier_short_name() { return _("Ctrl"); }
const char* Keyboard::secondary_modifier_short_name() { return _("Alt"); }
const char* Keyboard::tertiary_modifier_short_name() { return S_("Key|Shift"); }
@ -542,6 +550,14 @@ Keyboard::is_button2_event (GdkEventButton* ev)
#endif
}
bool
Keyboard::is_momentary_push_event (GdkEventButton* ev)
{
return (is_button2_event(ev)) ||
((ev->button == 1) &&
((ev->state & RelevantModifierKeyMask) == Keyboard::momentary_push_modifiers));
}
bool
Keyboard::is_delete_event (GdkEventButton *ev)
{