diff --git a/src/ui/alert.cpp b/src/ui/alert.cpp index 4bfb360fc..6bab0e458 100644 --- a/src/ui/alert.cpp +++ b/src/ui/alert.cpp @@ -111,7 +111,12 @@ void Alert::addSeparator() void Alert::addButton(const std::string& text) { auto button = new Button(text); - button->processMnemonicFromText(); + + // Process the mnemonic next to & character and "false" means that + // the mnemonic letter can be used without Alt or Command key + // modifiers. + button->processMnemonicFromText('&', false); + button->setMinSize(gfx::Size(60*guiscale(), 0)); m_buttons.push_back(button); diff --git a/src/ui/button.cpp b/src/ui/button.cpp index 2c52fe2be..36e062659 100644 --- a/src/ui/button.cpp +++ b/src/ui/button.cpp @@ -80,8 +80,11 @@ bool ButtonBase::onProcessMessage(Message* msg) KeyScancode scancode = keymsg->scancode(); if (isEnabled() && isVisible()) { - bool mnemonicPressed = - ((msg->altPressed() || msg->cmdPressed()) && + const bool mnemonicPressed = + (mnemonic() && + (!mnemonicRequiresModifiers() || + msg->altPressed() || + msg->cmdPressed()) && isMnemonicPressed(keymsg)); // For kButtonWidget diff --git a/src/ui/widget.cpp b/src/ui/widget.cpp index 65bafa8c6..32ea74a54 100644 --- a/src/ui/widget.cpp +++ b/src/ui/widget.cpp @@ -1503,12 +1503,18 @@ gfx::Point Widget::mousePosInDisplay() const return display()->nativeWindow()->pointFromScreen(get_mouse_position()); } -void Widget::setMnemonic(int mnemonic) +void Widget::setMnemonic(const int mnemonic, + const bool requireModifiers) { - m_mnemonic = mnemonic; + static_assert((kMnemonicCharMask & kMnemonicModifiersMask) == 0); + ASSERT((mnemonic & kMnemonicModifiersMask) == 0); + m_mnemonic = + (mnemonic & kMnemonicCharMask) | + (requireModifiers ? kMnemonicModifiersMask: 0); } -void Widget::processMnemonicFromText(int escapeChar) +void Widget::processMnemonicFromText(const int escapeChar, + const bool requireModifiers) { // Avoid calling setText() when the widget doesn't have the HAS_TEXT flag if (!hasText()) @@ -1526,7 +1532,7 @@ void Widget::processMnemonicFromText(int escapeChar) break; // Ill-formed string (it ends with escape character) } else if (chr != escapeChar) { - setMnemonic(chr); + setMnemonic(chr, requireModifiers); } } newText.push_back(chr); diff --git a/src/ui/widget.h b/src/ui/widget.h index c3d6541f0..260e501e8 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -372,14 +372,23 @@ namespace ui { // Returns lower-case letter that represet the mnemonic of the widget // (the underscored character, i.e. the letter after & symbol). - int mnemonic() const { return m_mnemonic; } - void setMnemonic(int mnemonic); + int mnemonic() const { + return (m_mnemonic & kMnemonicCharMask); + } + bool mnemonicRequiresModifiers() const { + return (m_mnemonic & kMnemonicModifiersMask ? true: false); + } + void setMnemonic(const int mnemonic, + const bool requireModifiers); // Assigns mnemonic from the character preceded by the given // escapeChar ('&' by default). - void processMnemonicFromText(int escapeChar = '&'); + void processMnemonicFromText(const int escapeChar = '&', + const bool requireModifiers = true); - // Returns true if the mnemonic character is pressed. + // Returns true if the mnemonic character is pressed (without modifiers). + // TODO maybe we can add check for modifiers now that this + // information is included in the Widget bool isMnemonicPressed(const ui::KeyMessage* keyMsg) const; // Signals @@ -437,7 +446,14 @@ namespace ui { Widget* m_parent; // Who is the parent? int m_parentIndex; // Location/index of this widget in the parent's Widget::m_children vector gfx::Size* m_sizeHint; - int m_mnemonic; // Keyboard shortcut to access this widget like Alt+mnemonic + + // Keyboard shortcut to access this widget like Alt+mnemonic. If + // kMnemonicModifiersMask bit is zero, it means that the mnemonic + // can be used without Alt or Command key modifiers (useful for + // buttons in ui::Alert). + static constexpr int kMnemonicCharMask = 0x7f; + static constexpr int kMnemonicModifiersMask = 0x80; + int m_mnemonic; // Widget size limits gfx::Size m_minSize, m_maxSize;