Add ShowMenu command so the user can customize Alt+top level menu mnemonic shortcuts (#3239)

master
David Capello 2022-04-12 21:16:44 -03:00
parent 3645afd9a2
commit b4d3692927
9 changed files with 137 additions and 18 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Aseprite -->
<!-- Copyright (C) 2018-2021 Igara Studio S.A. -->
<!-- Copyright (C) 2018-2022 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2018 David Capello -->
<gui>
<!-- Keyboard shortcuts -->
@ -8,6 +8,16 @@
<!-- Keyboard shortcuts for commands (menu options) -->
<commands>
<!-- Top-level menu access -->
<key command="ShowMenu" shortcut="Alt+F"><param name="menu" value="file_menu" /></key>
<key command="ShowMenu" shortcut="Alt+E"><param name="menu" value="edit_menu" /></key>
<key command="ShowMenu" shortcut="Alt+S"><param name="menu" value="sprite_menu" /></key>
<key command="ShowMenu" shortcut="Alt+L"><param name="menu" value="layer_menu" /></key>
<key command="ShowMenu" shortcut="Alt+R"><param name="menu" value="frame_menu" /></key>
<key command="ShowMenu" shortcut="Alt+T"><param name="menu" value="select_menu" /></key>
<key command="ShowMenu" shortcut="Alt+V"><param name="menu" value="view_menu" /></key>
<key command="ShowMenu" shortcut="Alt+H"><param name="menu" value="help_menu" /></key>
<!-- File -->
<key command="NewFile" shortcut="Ctrl+N" mac="Cmd+N" />
<key command="OpenFile" shortcut="Ctrl+O" mac="Cmd+O" />
@ -614,7 +624,7 @@
<menus>
<!-- main bar menu -->
<menu id="main_menu">
<menu text="@.file">
<menu text="@.file" id="file_menu">
<item command="NewFile" text="@.file_new" group="file_new" />
<item command="OpenFile" text="@.file_open" group="file_open" />
<menu text="@.file_open_recent" group="file_recent">
@ -643,7 +653,7 @@
<separator group="file_app" />
<item command="Exit" text="@.file_exit" />
</menu>
<menu text="@.edit">
<menu text="@.edit" id="edit_menu">
<item command="Undo" text="@.edit_undo" />
<item command="Redo" text="@.edit_redo" />
<item command="UndoHistory" text="@.edit_undo_history" group="edit_undo" />
@ -743,7 +753,7 @@
<item command="KeyboardShortcuts" text="@.edit_keyboard_shortcuts" />
<item command="Options" text="@.edit_preferences" />
</menu>
<menu text="@.sprite">
<menu text="@.sprite" id="sprite_menu">
<item command="SpriteProperties" text="@.sprite_properties" group="sprite_properties" />
<menu text="@.sprite_color_mode" group="sprite_color">
<item command="ChangePixelFormat" text="@.sprite_color_mode_rgb">
@ -790,7 +800,7 @@
<item command="CropSprite" text="@.sprite_crop" />
<item command="AutocropSprite" text="@.sprite_trim" group="sprite_crop" />
</menu>
<menu text="@.layer">
<menu text="@.layer" id="layer_menu">
<item command="LayerProperties" text="@.layer_properties" />
<item command="LayerVisibility" text="@.layer_visible" />
<item command="LayerLock" text="@.layer_lock_layers" />
@ -825,7 +835,7 @@
<param name="visibleOnly" value="true" />
</item>
</menu>
<menu text="@.frame">
<menu text="@.frame" id="frame_menu">
<item command="FrameProperties" text="@.frame_properties">
<param name="frame" value="current" />
</item>
@ -867,7 +877,7 @@
</item>
<item command="ReverseFrames" text="@.frame_reverse_frames" group="cel_frames" />
</menu>
<menu text="@.select">
<menu text="@.select" id="select_menu">
<item command="MaskAll" text="@.select_all" />
<item command="DeselectMask" text="@.select_deselect" />
<item command="ReselectMask" text="@.select_reselect" />
@ -889,7 +899,7 @@
<item command="LoadMask" text="@.select_load_from_file" />
<item command="SaveMask" text="@.select_save_to_file" group="select_files" />
</menu>
<menu text="@.view">
<menu text="@.view" id="view_menu">
<item command="DuplicateView" text="@.view_duplicate_view" group="view_new" />
<separator />
<item command="ShowExtras" text="@.view_show_extras" />

View File

@ -1,5 +1,5 @@
# Aseprite
# Copyright (C) 2018-2021 Igara Studio S.A.
# Copyright (C) 2018-2022 Igara Studio S.A.
# Copyright (C) 2016-2018 David Capello
[advanced_mode]
@ -433,6 +433,7 @@ ShowDynamics = Show Dynamics
ShowExtras = Show Extras
ShowGrid = Show Grid
ShowLayerEdges = Show Layer Edges
ShowMenu = Show Menu: {0}
ShowOnionSkin = Show Onion Skin
ShowPaletteOptions = Show Palette Options
ShowPalettePresets = Show Palette Presets

View File

@ -304,6 +304,7 @@ if(ENABLE_UI)
commands/filters/filter_target_buttons.cpp
commands/filters/filter_window.cpp
commands/screenshot.cpp
commands/show_menu.cpp
file_selector.cpp
modules/editors.cpp
modules/gfx.cpp

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2021 Igara Studio S.A.
// Copyright (C) 2018-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -145,6 +145,7 @@ FOR_EACH_COMMAND(ShowBrushPreview)
FOR_EACH_COMMAND(ShowExtras)
FOR_EACH_COMMAND(ShowGrid)
FOR_EACH_COMMAND(ShowLayerEdges)
FOR_EACH_COMMAND(ShowMenu)
FOR_EACH_COMMAND(ShowOnionSkin)
FOR_EACH_COMMAND(ShowPixelGrid)
FOR_EACH_COMMAND(ShowSelectionEdges)

View File

@ -0,0 +1,83 @@
// Aseprite
// Copyright (C) 2022 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/app_menus.h"
#include "app/commands/command.h"
#include "app/commands/new_params.h"
#include "app/context.h"
#include "app/i18n/strings.h"
#include "fmt/format.h"
namespace app {
struct ShowMenuParams : public NewParams {
Param<std::string> menu { this, "", "menu" };
};
class ShowMenuCommand : public CommandWithNewParams<ShowMenuParams> {
public:
ShowMenuCommand();
protected:
bool onNeedsParams() const override { return true; }
void onExecute(Context* ctx) override;
std::string onGetFriendlyName() const override;
MenuItem* findMenuItem() const;
void openSubmenuById(Menu* menu, const std::string& id);
};
ShowMenuCommand::ShowMenuCommand()
: CommandWithNewParams<ShowMenuParams>(CommandId::ShowMenu(), CmdUIOnlyFlag)
{
}
void ShowMenuCommand::onExecute(Context* ctx)
{
if (!ctx->isUIAvailable())
return;
if (MenuItem* menuitem = findMenuItem())
menuitem->openSubmenu();
}
std::string ShowMenuCommand::onGetFriendlyName() const
{
std::string name;
if (MenuItem* menuitem = findMenuItem())
name = menuitem->text();
else
name = params().menu();
return fmt::format(Strings::commands_ShowMenu(), name);
}
MenuItem* ShowMenuCommand::findMenuItem() const
{
std::string id = params().menu();
if (id.empty())
return nullptr;
if (AppMenus* menus = AppMenus::instance()) {
if (Menu* root = menus->getRootMenu()) {
if (auto menuitem = root->findItemById(id.c_str())) {
if (menuitem->type() == ui::kMenuItemWidget)
return static_cast<MenuItem*>(menuitem);
}
}
}
return nullptr;
}
Command* CommandFactory::createShowMenuCommand()
{
return new ShowMenuCommand;
}
} // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A
// Copyright (C) 2020-2022 Igara Studio S.A
// Copyright (C) 2001-2015 David Capello
//
// This program is distributed under the terms of
@ -18,6 +18,9 @@
namespace app {
MainMenuBar::MainMenuBar()
// We process Alt+mnemonics with ShowMenu commands (instead of the
// integrated method in ui::MenuBox::onProcessMessage()).
: MenuBar(MenuBar::ProcessTopLevelShortcuts::kNo)
{
Extensions& extensions = App::instance()->extensions();

View File

@ -546,12 +546,10 @@ void MainWindow::configureWorkspaceLayout()
if (os::instance()->menus() == nullptr ||
pref.general.showMenuBar()) {
if (!m_menuBar->parent())
menuBarPlaceholder()->insertChild(0, m_menuBar);
m_menuBar->resetMaxSize();
}
else {
if (m_menuBar->parent())
menuBarPlaceholder()->removeChild(m_menuBar);
m_menuBar->setMaxSize(gfx::Size(0, 0));
}
m_menuBar->setVisible(normal);

View File

@ -193,8 +193,9 @@ MenuBox::~MenuBox()
bool MenuBar::m_expandOnMouseover = false;
MenuBar::MenuBar()
MenuBar::MenuBar(ProcessTopLevelShortcuts processShortcuts)
: MenuBox(kMenuBarWidget)
, m_processTopLevelShortcuts(processShortcuts == ProcessTopLevelShortcuts::kYes)
{
createBase();
}
@ -273,6 +274,12 @@ void MenuItem::setSubmenu(Menu* menu)
}
}
void MenuItem::openSubmenu()
{
if (auto menu = static_cast<Menu*>(parent()))
menu->highlightItem(this, true, true, true);
}
bool MenuItem::isHighlighted() const
{
return m_highlighted;
@ -574,7 +581,8 @@ bool MenuBox::onProcessMessage(Message* msg)
// Check for ALT+some underlined letter
if (((this->type() == kMenuBoxWidget) && (msg->modifiers() == kKeyNoneModifier || // <-- Inside menu-boxes we can use letters without Alt modifier pressed
msg->modifiers() == kKeyAltModifier)) ||
((this->type() == kMenuBarWidget) && (msg->modifiers() == kKeyAltModifier))) {
((this->type() == kMenuBarWidget) && (msg->modifiers() == kKeyAltModifier) &&
static_cast<MenuBar*>(this)->processTopLevelShortcuts())) {
auto keymsg = static_cast<KeyMessage*>(msg);
selected = check_for_letter(menu, keymsg);
if (selected) {

View File

@ -93,12 +93,22 @@ namespace ui {
class MenuBar : public MenuBox {
public:
MenuBar();
enum class ProcessTopLevelShortcuts { kNo, kYes };
MenuBar(ProcessTopLevelShortcuts processShortcuts);
bool processTopLevelShortcuts() const {
return m_processTopLevelShortcuts;
}
static bool expandOnMouseover();
static void setExpandOnMouseover(bool state);
private:
// True if we should open top-level menus with Alt+mnemonic (this
// flag is not used by Aseprite), top-level menus are opened with
// the ShowMenu command now.
bool m_processTopLevelShortcuts;
static bool m_expandOnMouseover;
};
@ -110,6 +120,10 @@ namespace ui {
Menu* getSubmenu();
void setSubmenu(Menu* submenu);
// Open the submenu of this menu item (the menu item should be
// positioned in a correct position on the screen).
void openSubmenu();
bool isHighlighted() const;
void setHighlighted(bool state);