mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 13:21:34 +00:00
Merge b24bf1db7616b43d390a9ee11bbc50af6172c8b7 into be6d2251aad2e0a609f63ce8c7e46fefa858ded1
This commit is contained in:
commit
ac4f6df599
@ -1696,7 +1696,7 @@ allow_load_lib_access = &Allow Load External Library
|
||||
give_full_access = Give Script Full &Access
|
||||
stop_script = &Stop Script
|
||||
|
||||
[select_accelerator]
|
||||
[select_shortcut]
|
||||
title = Keyboard Shortcut
|
||||
key = Key:
|
||||
clear = Clear
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2025 by Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2016 by David Capello -->
|
||||
<gui>
|
||||
<window id="select_accelerator" text="@.title">
|
||||
<window id="select_shortcut" text="@.title">
|
||||
<vbox expansive="true">
|
||||
<grid columns="3">
|
||||
<label text="@.key" />
|
@ -1,5 +1,5 @@
|
||||
# Aseprite
|
||||
# Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
# Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
# Copyright (C) 2001-2018 David Capello
|
||||
|
||||
# Generate a ui::Widget for each widget in a XML file
|
||||
@ -667,7 +667,7 @@ target_sources(app-lib PRIVATE
|
||||
ui/rgbmap_algorithm_selector.cpp
|
||||
ui/sampling_selector.cpp
|
||||
ui/search_entry.cpp
|
||||
ui/select_accelerator.cpp
|
||||
ui/select_shortcut.cpp
|
||||
ui/selection_mode_field.cpp
|
||||
ui/skin/font_data.cpp
|
||||
ui/skin/skin_part.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -116,8 +116,8 @@ bool can_call_global_shortcut(const AppMenuItem::Native* native)
|
||||
native->keyContext == KeyboardShortcuts::instance()->getCurrentKeyContext());
|
||||
}
|
||||
|
||||
// TODO this should be on "she" library (or we should use
|
||||
// os::Shortcut instead of ui::Accelerators)
|
||||
// TODO this should be on laf-os library (or we should use
|
||||
// os::Shortcut instead of ui::Shortcuts)
|
||||
int from_scancode_to_unicode(KeyScancode scancode)
|
||||
{
|
||||
static int map[] = {
|
||||
@ -284,19 +284,19 @@ void destroy_menu_item(ui::Widget* item)
|
||||
|
||||
os::Shortcut get_os_shortcut_from_key(const Key* key)
|
||||
{
|
||||
if (key && !key->accels().empty()) {
|
||||
const ui::Accelerator& accel = key->accels().front();
|
||||
if (key && !key->shortcuts().empty()) {
|
||||
const ui::Shortcut& shortcut = key->shortcuts().front();
|
||||
|
||||
#if LAF_MACOS
|
||||
// Shortcuts with spacebar as modifier do not work well in macOS
|
||||
// (they will be called when the space bar is unpressed too).
|
||||
if ((accel.modifiers() & ui::kKeySpaceModifier) == ui::kKeySpaceModifier)
|
||||
if ((shortcut.modifiers() & ui::kKeySpaceModifier) == ui::kKeySpaceModifier)
|
||||
return os::Shortcut();
|
||||
#endif
|
||||
|
||||
return os::Shortcut(
|
||||
(accel.unicodeChar() ? accel.unicodeChar() : from_scancode_to_unicode(accel.scancode())),
|
||||
accel.modifiers());
|
||||
return os::Shortcut((shortcut.unicodeChar() ? shortcut.unicodeChar() :
|
||||
from_scancode_to_unicode(shortcut.scancode())),
|
||||
shortcut.modifiers());
|
||||
}
|
||||
else
|
||||
return os::Shortcut();
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -54,11 +55,11 @@ void AdvancedModeCommand::onExecute(Context* context)
|
||||
|
||||
if (oldMode == MainWindow::NormalMode && pref.advancedMode.showAlert()) {
|
||||
KeyPtr key = KeyboardShortcuts::instance()->command(this->id().c_str());
|
||||
if (!key->accels().empty()) {
|
||||
if (!key->shortcuts().empty()) {
|
||||
app::gen::AdvancedMode window;
|
||||
|
||||
window.warningLabel()->setTextf("You can go back pressing \"%s\" key.",
|
||||
key->accels().front().toString().c_str());
|
||||
key->shortcuts().front().toString().c_str());
|
||||
|
||||
window.openWindowInForeground();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -23,7 +23,7 @@
|
||||
#include "app/ui/app_menuitem.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/search_entry.h"
|
||||
#include "app/ui/select_accelerator.h"
|
||||
#include "app/ui/select_shortcut.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/fs.h"
|
||||
@ -151,7 +151,7 @@ public:
|
||||
, m_keyOrig(key ? new Key(*key) : nullptr)
|
||||
, m_menuitem(menuitem)
|
||||
, m_level(level)
|
||||
, m_hotAccel(-1)
|
||||
, m_hotShortcut(-1)
|
||||
, m_lockButtons(false)
|
||||
, m_headerItem(headerItem)
|
||||
{
|
||||
@ -204,45 +204,45 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void onChangeAccel(int index)
|
||||
void onChangeShortcut(int index)
|
||||
{
|
||||
LockButtons lock(this);
|
||||
Accelerator origAccel = m_key->accels()[index];
|
||||
SelectAccelerator window(origAccel, m_key->keycontext(), m_keys);
|
||||
Shortcut origShortcut = m_key->shortcuts()[index];
|
||||
SelectShortcut window(origShortcut, m_key->keycontext(), m_keys);
|
||||
window.openWindowInForeground();
|
||||
|
||||
if (window.isModified()) {
|
||||
m_key->disableAccel(origAccel, KeySource::UserDefined);
|
||||
if (!window.accel().isEmpty())
|
||||
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
|
||||
m_key->disableShortcut(origShortcut, KeySource::UserDefined);
|
||||
if (!window.shortcut().isEmpty())
|
||||
m_key->add(window.shortcut(), KeySource::UserDefined, m_keys);
|
||||
}
|
||||
|
||||
this->window()->layout();
|
||||
}
|
||||
|
||||
void onDeleteAccel(int index)
|
||||
void onDeleteShortcut(int index)
|
||||
{
|
||||
LockButtons lock(this);
|
||||
// We need to create a copy of the accelerator because
|
||||
// Key::disableAccel() will modify the accels() collection itself.
|
||||
ui::Accelerator accel = m_key->accels()[index];
|
||||
// We need to create a copy of the shortcut because
|
||||
// Key::disableShortcut() will modify the shortcuts() collection itself.
|
||||
ui::Shortcut shortcut = m_key->shortcuts()[index];
|
||||
|
||||
if (ui::Alert::show(Strings::alerts_delete_shortcut(accel.toString())) != 1)
|
||||
if (ui::Alert::show(Strings::alerts_delete_shortcut(shortcut.toString())) != 1)
|
||||
return;
|
||||
|
||||
m_key->disableAccel(accel, KeySource::UserDefined);
|
||||
m_key->disableShortcut(shortcut, KeySource::UserDefined);
|
||||
window()->layout();
|
||||
}
|
||||
|
||||
void onAddAccel()
|
||||
void onAddShortcut()
|
||||
{
|
||||
LockButtons lock(this);
|
||||
ui::Accelerator accel;
|
||||
SelectAccelerator window(accel, m_key ? m_key->keycontext() : KeyContext::Any, m_keys);
|
||||
ui::Shortcut shortcut;
|
||||
SelectShortcut window(shortcut, m_key ? m_key->keycontext() : KeyContext::Any, m_keys);
|
||||
window.openWindowInForeground();
|
||||
|
||||
if ((window.isModified()) ||
|
||||
// We can assign a "None" accelerator to mouse wheel actions
|
||||
// We can assign a "None" shortcut to mouse wheel actions
|
||||
(m_key && m_key->type() == KeyType::WheelAction && window.isOK())) {
|
||||
if (!m_key) {
|
||||
ASSERT(m_menuitem);
|
||||
@ -256,7 +256,7 @@ private:
|
||||
m_menuKeys[m_menuitem] = m_key;
|
||||
}
|
||||
|
||||
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
|
||||
m_key->add(window.shortcut(), KeySource::UserDefined, m_keys);
|
||||
}
|
||||
|
||||
this->window()->layout();
|
||||
@ -273,8 +273,8 @@ private:
|
||||
size.w = std::max(size.w, w);
|
||||
}
|
||||
|
||||
if (m_key && !m_key->accels().empty()) {
|
||||
size_t combos = m_key->accels().size();
|
||||
if (m_key && !m_key->shortcuts().empty()) {
|
||||
size_t combos = m_key->shortcuts().size();
|
||||
if (combos > 1)
|
||||
size.h *= combos;
|
||||
}
|
||||
@ -315,7 +315,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
if (m_key && !m_key->accels().empty()) {
|
||||
if (m_key && !m_key->shortcuts().empty()) {
|
||||
if (m_key->keycontext() != KeyContext::Any) {
|
||||
g->drawText(convertKeyContextToUserFriendlyString(m_key->keycontext()),
|
||||
fg,
|
||||
@ -324,13 +324,14 @@ private:
|
||||
}
|
||||
|
||||
const int dh = th + 4 * guiscale();
|
||||
IntersectClip clip(g,
|
||||
gfx::Rect(keyXPos, y, contextXPos - keyXPos, dh * m_key->accels().size()));
|
||||
IntersectClip clip(
|
||||
g,
|
||||
gfx::Rect(keyXPos, y, contextXPos - keyXPos, dh * m_key->shortcuts().size()));
|
||||
if (clip) {
|
||||
int i = 0;
|
||||
for (const Accelerator& accel : m_key->accels()) {
|
||||
if (i != m_hotAccel || !m_changeButton) {
|
||||
g->drawText(getAccelText(accel), fg, bg, gfx::Point(keyXPos, y));
|
||||
for (const Shortcut& shortcut : m_key->shortcuts()) {
|
||||
if (i != m_hotShortcut || !m_changeButton) {
|
||||
g->drawText(getShortcutText(shortcut), fg, bg, gfx::Point(keyXPos, y));
|
||||
}
|
||||
y += dh;
|
||||
++i;
|
||||
@ -361,40 +362,41 @@ private:
|
||||
gfx::Rect bounds = this->bounds();
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
|
||||
const Accelerators* accels = (m_key ? &m_key->accels() : NULL);
|
||||
const Shortcuts* shortcuts = (m_key ? &m_key->shortcuts() : NULL);
|
||||
int y = bounds.y;
|
||||
int dh = textSize().h + 4 * guiscale();
|
||||
int maxi = (accels && accels->size() > 1 ? accels->size() : 1);
|
||||
int maxi = (shortcuts && shortcuts->size() > 1 ? shortcuts->size() : 1);
|
||||
|
||||
auto theme = SkinTheme::get(this);
|
||||
|
||||
for (int i = 0; i < maxi; ++i, y += dh) {
|
||||
int w = font()->textLength(
|
||||
(accels && i < (int)accels->size() ? getAccelText((*accels)[i]) : std::string()));
|
||||
int w = font()->textLength((shortcuts && i < (int)shortcuts->size() ?
|
||||
getShortcutText((*shortcuts)[i]) :
|
||||
std::string()));
|
||||
gfx::Rect itemBounds(bounds.x + m_headerItem->keyXPos(), y, w, dh);
|
||||
itemBounds = itemBounds.enlarge(
|
||||
gfx::Border(4 * guiscale(), 0, 6 * guiscale(), 1 * guiscale()));
|
||||
|
||||
if (accels && i < (int)accels->size() && mouseMsg->position().y >= itemBounds.y &&
|
||||
if (shortcuts && i < (int)shortcuts->size() && mouseMsg->position().y >= itemBounds.y &&
|
||||
mouseMsg->position().y < itemBounds.y + itemBounds.h) {
|
||||
if (m_hotAccel != i) {
|
||||
m_hotAccel = i;
|
||||
if (m_hotShortcut != i) {
|
||||
m_hotShortcut = i;
|
||||
|
||||
m_changeConn = obs::connection();
|
||||
m_changeButton.reset(new Button(""));
|
||||
m_changeConn = m_changeButton->Click.connect([this, i] { onChangeAccel(i); });
|
||||
m_changeConn = m_changeButton->Click.connect([this, i] { onChangeShortcut(i); });
|
||||
m_changeButton->setStyle(theme->styles.miniButton());
|
||||
addChild(m_changeButton.get());
|
||||
|
||||
m_deleteConn = obs::connection();
|
||||
m_deleteButton.reset(new Button(""));
|
||||
m_deleteConn = m_deleteButton->Click.connect([this, i] { onDeleteAccel(i); });
|
||||
m_deleteConn = m_deleteButton->Click.connect([this, i] { onDeleteShortcut(i); });
|
||||
m_deleteButton->setStyle(theme->styles.miniButton());
|
||||
addChild(m_deleteButton.get());
|
||||
|
||||
m_changeButton->setBgColor(gfx::ColorNone);
|
||||
m_changeButton->setBounds(itemBounds);
|
||||
m_changeButton->setText(getAccelText((*accels)[i]));
|
||||
m_changeButton->setText(getShortcutText((*shortcuts)[i]));
|
||||
|
||||
const char* label = "x";
|
||||
m_deleteButton->setBgColor(gfx::ColorNone);
|
||||
@ -411,7 +413,7 @@ private:
|
||||
if (i == 0 && !m_addButton && (!m_menuitem || m_menuitem->getCommand())) {
|
||||
m_addConn = obs::connection();
|
||||
m_addButton.reset(new Button(""));
|
||||
m_addConn = m_addButton->Click.connect([this] { onAddAccel(); });
|
||||
m_addConn = m_addButton->Click.connect([this] { onAddShortcut(); });
|
||||
m_addButton->setStyle(theme->styles.miniButton());
|
||||
addChild(m_addButton.get());
|
||||
|
||||
@ -452,16 +454,16 @@ private:
|
||||
m_addButton->setVisible(false);
|
||||
}
|
||||
|
||||
m_hotAccel = -1;
|
||||
m_hotShortcut = -1;
|
||||
}
|
||||
|
||||
std::string getAccelText(const Accelerator& accel) const
|
||||
std::string getShortcutText(const Shortcut& shortcut) const
|
||||
{
|
||||
if (m_key && m_key->type() == KeyType::WheelAction && accel.isEmpty()) {
|
||||
if (m_key && m_key->type() == KeyType::WheelAction && shortcut.isEmpty()) {
|
||||
return Strings::keyboard_shortcuts_default_action();
|
||||
}
|
||||
else {
|
||||
return accel.toString();
|
||||
return shortcut.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -471,14 +473,14 @@ private:
|
||||
KeyPtr m_keyOrig;
|
||||
AppMenuItem* m_menuitem;
|
||||
int m_level;
|
||||
ui::Accelerators m_newAccels;
|
||||
ui::Shortcuts m_newShortcuts;
|
||||
std::shared_ptr<ui::Button> m_changeButton;
|
||||
std::shared_ptr<ui::Button> m_deleteButton;
|
||||
std::shared_ptr<ui::Button> m_addButton;
|
||||
obs::scoped_connection m_changeConn;
|
||||
obs::scoped_connection m_deleteConn;
|
||||
obs::scoped_connection m_addConn;
|
||||
int m_hotAccel;
|
||||
int m_hotShortcut;
|
||||
bool m_lockButtons;
|
||||
HeaderItem* m_headerItem;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -164,10 +164,10 @@ void NewBrushCommand::createBrush(const Site& site, const Mask* mask)
|
||||
params.set("change", "custom");
|
||||
params.set("slot", base::convert_to<std::string>(slot).c_str());
|
||||
KeyPtr key = KeyboardShortcuts::instance()->command(CommandId::ChangeBrush(), params);
|
||||
if (key && !key->accels().empty()) {
|
||||
if (key && !key->shortcuts().empty()) {
|
||||
std::string tooltip;
|
||||
tooltip += Strings::new_brush_shortcut() + " ";
|
||||
tooltip += key->accels().front().toString();
|
||||
tooltip += key->shortcuts().front().toString();
|
||||
StatusBar::instance()->showTip(2000, tooltip);
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +94,7 @@ protected:
|
||||
void onInitTheme(InitThemeEvent& ev) override;
|
||||
LayoutIO* onGetLayoutIO() override { return this; }
|
||||
void onNewDisplayConfiguration(Display* display) override;
|
||||
bool onEnqueueMouseDown(MouseMessage* mouseMsg) override;
|
||||
|
||||
// LayoutIO implementation
|
||||
std::string loadLayout(Widget* widget) override;
|
||||
@ -678,6 +679,23 @@ void CustomizedGuiManager::onNewDisplayConfiguration(Display* display)
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomizedGuiManager::onEnqueueMouseDown(MouseMessage* mouseMsg)
|
||||
{
|
||||
ASSERT(mouseMsg->type() == kMouseDownMessage);
|
||||
|
||||
// If there is no modal window running...
|
||||
App* app = App::instance();
|
||||
if (app && getForegroundWindow() == app->mainWindow()) {
|
||||
// Process a mouse button as a shortcut.
|
||||
if (processKey(mouseMsg)) {
|
||||
// Don't enqueue this message
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CustomizedGuiManager::processKey(Message* msg)
|
||||
{
|
||||
App* app = App::instance();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -19,9 +19,9 @@
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "os/menus.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/menu.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/shortcut.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
@ -138,8 +138,8 @@ void AppMenuItem::onSizeHint(SizeHintEvent& ev)
|
||||
|
||||
size.h = +textHeight() + border().height();
|
||||
|
||||
if (m_key && !m_key->accels().empty()) {
|
||||
size.w += font()->textLength(m_key->accels().front().toString());
|
||||
if (m_key && !m_key->shortcuts().empty()) {
|
||||
size.w += font()->textLength(m_key->shortcuts().front().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -431,8 +431,8 @@ void BrushPopup::regenerate(ui::Display* display, const gfx::Point& pos)
|
||||
params.set("change", "custom");
|
||||
params.set("slot", base::convert_to<std::string>(slot).c_str());
|
||||
KeyPtr key = KeyboardShortcuts::instance()->command(CommandId::ChangeBrush(), params);
|
||||
if (key && !key->accels().empty())
|
||||
shortcut = key->accels().front().toString();
|
||||
if (key && !key->shortcuts().empty())
|
||||
shortcut = key->shortcuts().front().toString();
|
||||
}
|
||||
m_customBrushes->addItem(new SelectBrushItem(brush, slot));
|
||||
m_customBrushes->addItem(new BrushShortcutItem(shortcut, slot));
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -41,10 +41,10 @@
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/menu.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/shortcut.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/view.h"
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -13,7 +13,7 @@
|
||||
#include "app/ui/key_context.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/vector2d.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/shortcut.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
@ -106,7 +106,7 @@ inline KeyAction operator&(KeyAction a, KeyAction b)
|
||||
class Key;
|
||||
using KeyPtr = std::shared_ptr<Key>;
|
||||
using Keys = std::vector<KeyPtr>;
|
||||
using KeySourceAccelList = std::vector<std::pair<KeySource, ui::Accelerator>>;
|
||||
using KeySourceShortcutList = std::vector<std::pair<KeySource, ui::Shortcut>>;
|
||||
using DragVector = base::Vector2d<double>;
|
||||
|
||||
class Key {
|
||||
@ -119,29 +119,28 @@ public:
|
||||
static KeyPtr MakeDragAction(WheelAction dragAction);
|
||||
|
||||
KeyType type() const { return m_type; }
|
||||
const ui::Accelerators& accels() const;
|
||||
const KeySourceAccelList addsKeys() const { return m_adds; }
|
||||
const KeySourceAccelList delsKeys() const { return m_dels; }
|
||||
const ui::Shortcuts& shortcuts() const;
|
||||
const KeySourceShortcutList addsKeys() const { return m_adds; }
|
||||
const KeySourceShortcutList delsKeys() const { return m_dels; }
|
||||
|
||||
void add(const ui::Accelerator& accel, const KeySource source, KeyboardShortcuts& globalKeys);
|
||||
const ui::Accelerator* isPressed(const ui::Message* msg,
|
||||
const KeyboardShortcuts& globalKeys,
|
||||
const KeyContext keyContext) const;
|
||||
const ui::Accelerator* isPressed(const ui::Message* msg,
|
||||
const KeyboardShortcuts& globalKeys) const;
|
||||
void add(const ui::Shortcut& shortcut, const KeySource source, KeyboardShortcuts& globalKeys);
|
||||
const ui::Shortcut* isPressed(const ui::Message* msg,
|
||||
const KeyboardShortcuts& globalKeys,
|
||||
const KeyContext keyContext) const;
|
||||
const ui::Shortcut* isPressed(const ui::Message* msg, const KeyboardShortcuts& globalKeys) const;
|
||||
bool isPressed() const;
|
||||
bool isLooselyPressed() const;
|
||||
bool isCommandListed() const;
|
||||
|
||||
bool hasAccel(const ui::Accelerator& accel) const;
|
||||
bool hasUserDefinedAccels() const;
|
||||
bool hasShortcut(const ui::Shortcut& shortcut) const;
|
||||
bool hasUserDefinedShortcuts() const;
|
||||
|
||||
// The KeySource indicates from where the key was disabled
|
||||
// (e.g. if it was removed from an extension-defined file, or from
|
||||
// user-defined).
|
||||
void disableAccel(const ui::Accelerator& accel, const KeySource source);
|
||||
void disableShortcut(const ui::Shortcut& shortcut, const KeySource source);
|
||||
|
||||
// Resets user accelerators to the original & extension-defined ones.
|
||||
// Resets user shortcuts to the original & extension-defined ones.
|
||||
void reset();
|
||||
|
||||
void copyOriginalToUser();
|
||||
@ -164,11 +163,11 @@ public:
|
||||
|
||||
private:
|
||||
KeyType m_type;
|
||||
KeySourceAccelList m_adds;
|
||||
KeySourceAccelList m_dels;
|
||||
// Final list of accelerators after processing the
|
||||
KeySourceShortcutList m_adds;
|
||||
KeySourceShortcutList m_dels;
|
||||
// Final list of shortcuts after processing the
|
||||
// addition/deletion of extension-defined & user-defined keys.
|
||||
mutable std::unique_ptr<ui::Accelerators> m_accels;
|
||||
mutable std::unique_ptr<ui::Shortcuts> m_shortcuts;
|
||||
KeyContext m_keycontext;
|
||||
|
||||
// for KeyType::Command
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -28,8 +28,8 @@
|
||||
#include "app/xml_document.h"
|
||||
#include "app/xml_exception.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/shortcut.h"
|
||||
|
||||
#include "tinyxml2.h"
|
||||
|
||||
@ -244,13 +244,13 @@ std::string get_user_friendly_string_for_wheelaction(app::WheelAction wheelActio
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void erase_accel(app::KeySourceAccelList& kvs,
|
||||
const app::KeySource source,
|
||||
const ui::Accelerator& accel)
|
||||
void erase_shortcut(app::KeySourceShortcutList& kvs,
|
||||
const app::KeySource source,
|
||||
const ui::Shortcut& shortcut)
|
||||
{
|
||||
for (auto it = kvs.begin(); it != kvs.end();) {
|
||||
auto& kv = *it;
|
||||
if (kv.first == source && kv.second == accel) {
|
||||
if (kv.first == source && kv.second == shortcut) {
|
||||
it = kvs.erase(it);
|
||||
}
|
||||
else
|
||||
@ -258,7 +258,7 @@ void erase_accel(app::KeySourceAccelList& kvs,
|
||||
}
|
||||
}
|
||||
|
||||
void erase_accels(app::KeySourceAccelList& kvs, const app::KeySource source)
|
||||
void erase_shortcuts(app::KeySourceShortcutList& kvs, const app::KeySource source)
|
||||
{
|
||||
for (auto it = kvs.begin(); it != kvs.end();) {
|
||||
auto& kv = *it;
|
||||
@ -436,92 +436,93 @@ KeyPtr Key::MakeDragAction(WheelAction dragAction)
|
||||
return k;
|
||||
}
|
||||
|
||||
const ui::Accelerators& Key::accels() const
|
||||
const ui::Shortcuts& Key::shortcuts() const
|
||||
{
|
||||
if (!m_accels) {
|
||||
m_accels = std::make_unique<ui::Accelerators>();
|
||||
if (!m_shortcuts) {
|
||||
m_shortcuts = std::make_unique<ui::Shortcuts>();
|
||||
|
||||
// Add default keys
|
||||
for (const auto& kv : m_adds) {
|
||||
if (kv.first == KeySource::Original)
|
||||
m_accels->add(kv.second);
|
||||
m_shortcuts->add(kv.second);
|
||||
}
|
||||
|
||||
// Delete/add extension-defined keys
|
||||
for (const auto& kv : m_dels) {
|
||||
if (kv.first == KeySource::ExtensionDefined)
|
||||
m_accels->remove(kv.second);
|
||||
m_shortcuts->remove(kv.second);
|
||||
else {
|
||||
ASSERT(kv.first != KeySource::Original);
|
||||
}
|
||||
}
|
||||
for (const auto& kv : m_adds) {
|
||||
if (kv.first == KeySource::ExtensionDefined)
|
||||
m_accels->add(kv.second);
|
||||
m_shortcuts->add(kv.second);
|
||||
}
|
||||
|
||||
// Delete/add user-defined keys
|
||||
for (const auto& kv : m_dels) {
|
||||
if (kv.first == KeySource::UserDefined)
|
||||
m_accels->remove(kv.second);
|
||||
m_shortcuts->remove(kv.second);
|
||||
}
|
||||
for (const auto& kv : m_adds) {
|
||||
if (kv.first == KeySource::UserDefined)
|
||||
m_accels->add(kv.second);
|
||||
m_shortcuts->add(kv.second);
|
||||
}
|
||||
}
|
||||
return *m_accels;
|
||||
return *m_shortcuts;
|
||||
}
|
||||
|
||||
void Key::add(const ui::Accelerator& accel, const KeySource source, KeyboardShortcuts& globalKeys)
|
||||
void Key::add(const ui::Shortcut& shortcut, const KeySource source, KeyboardShortcuts& globalKeys)
|
||||
{
|
||||
m_adds.emplace_back(source, accel);
|
||||
m_accels.reset();
|
||||
m_adds.emplace_back(source, shortcut);
|
||||
m_shortcuts.reset();
|
||||
|
||||
// Remove the accelerator from other commands
|
||||
// Remove the shortcut from other commands
|
||||
if (source == KeySource::ExtensionDefined || source == KeySource::UserDefined) {
|
||||
erase_accel(m_dels, source, accel);
|
||||
erase_shortcut(m_dels, source, shortcut);
|
||||
|
||||
globalKeys.disableAccel(accel, source, m_keycontext, this);
|
||||
globalKeys.disableShortcut(shortcut, source, m_keycontext, this);
|
||||
}
|
||||
}
|
||||
|
||||
const ui::Accelerator* Key::isPressed(const Message* msg,
|
||||
const KeyboardShortcuts& globalKeys,
|
||||
const KeyContext keyContext) const
|
||||
const ui::Shortcut* Key::isPressed(const Message* msg,
|
||||
const KeyboardShortcuts& globalKeys,
|
||||
const KeyContext keyContext) const
|
||||
{
|
||||
if (auto keyMsg = dynamic_cast<const KeyMessage*>(msg)) {
|
||||
for (const Accelerator& accel : accels()) {
|
||||
if (accel.isPressed(keyMsg->modifiers(), keyMsg->scancode(), keyMsg->unicodeChar()) &&
|
||||
for (const Shortcut& shortcut : shortcuts()) {
|
||||
if (shortcut.isPressed(keyMsg->modifiers(), keyMsg->scancode(), keyMsg->unicodeChar()) &&
|
||||
(m_keycontext == KeyContext::Any || m_keycontext == keyContext)) {
|
||||
return &accel;
|
||||
return &shortcut;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto mouseMsg = dynamic_cast<const MouseMessage*>(msg)) {
|
||||
for (const Accelerator& accel : accels()) {
|
||||
if ((accel.modifiers() == mouseMsg->modifiers()) &&
|
||||
for (const Shortcut& shortcut : shortcuts()) {
|
||||
if ((shortcut.modifiers() == mouseMsg->modifiers()) &&
|
||||
(shortcut.mouseButton() == mouseMsg->button()) &&
|
||||
(m_keycontext == KeyContext::Any ||
|
||||
// TODO we could have multiple mouse wheel key-context,
|
||||
// like "sprite editor" context, or "timeline" context,
|
||||
// etc.
|
||||
m_keycontext == KeyContext::MouseWheel)) {
|
||||
return &accel;
|
||||
return &shortcut;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ui::Accelerator* Key::isPressed(const Message* msg, const KeyboardShortcuts& globalKeys) const
|
||||
const ui::Shortcut* Key::isPressed(const Message* msg, const KeyboardShortcuts& globalKeys) const
|
||||
{
|
||||
return isPressed(msg, globalKeys, globalKeys.getCurrentKeyContext());
|
||||
}
|
||||
|
||||
bool Key::isPressed() const
|
||||
{
|
||||
for (const Accelerator& accel : this->accels()) {
|
||||
if (accel.isPressed())
|
||||
for (const Shortcut& shortcut : this->shortcuts()) {
|
||||
if (shortcut.isPressed())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -529,8 +530,8 @@ bool Key::isPressed() const
|
||||
|
||||
bool Key::isLooselyPressed() const
|
||||
{
|
||||
for (const Accelerator& accel : this->accels()) {
|
||||
if (accel.isLooselyPressed())
|
||||
for (const Shortcut& shortcut : this->shortcuts()) {
|
||||
if (shortcut.isLooselyPressed())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -541,12 +542,12 @@ bool Key::isCommandListed() const
|
||||
return type() == KeyType::Command && command()->isListed(params());
|
||||
}
|
||||
|
||||
bool Key::hasAccel(const ui::Accelerator& accel) const
|
||||
bool Key::hasShortcut(const ui::Shortcut& shortcut) const
|
||||
{
|
||||
return accels().has(accel);
|
||||
return shortcuts().has(shortcut);
|
||||
}
|
||||
|
||||
bool Key::hasUserDefinedAccels() const
|
||||
bool Key::hasUserDefinedShortcuts() const
|
||||
{
|
||||
for (const auto& kv : m_adds) {
|
||||
if (kv.first == KeySource::UserDefined)
|
||||
@ -555,37 +556,37 @@ bool Key::hasUserDefinedAccels() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Key::disableAccel(const ui::Accelerator& accel, const KeySource source)
|
||||
void Key::disableShortcut(const ui::Shortcut& shortcut, const KeySource source)
|
||||
{
|
||||
// It doesn't make sense that the default keyboard shortcuts file
|
||||
// (gui.xml) removes some accelerator.
|
||||
// (gui.xml) removes some shortcut.
|
||||
ASSERT(source != KeySource::Original);
|
||||
|
||||
erase_accel(m_adds, source, accel);
|
||||
erase_accel(m_dels, source, accel);
|
||||
erase_shortcut(m_adds, source, shortcut);
|
||||
erase_shortcut(m_dels, source, shortcut);
|
||||
|
||||
m_dels.emplace_back(source, accel);
|
||||
m_accels.reset();
|
||||
m_dels.emplace_back(source, shortcut);
|
||||
m_shortcuts.reset();
|
||||
}
|
||||
|
||||
void Key::reset()
|
||||
{
|
||||
erase_accels(m_adds, KeySource::UserDefined);
|
||||
erase_accels(m_dels, KeySource::UserDefined);
|
||||
m_accels.reset();
|
||||
erase_shortcuts(m_adds, KeySource::UserDefined);
|
||||
erase_shortcuts(m_dels, KeySource::UserDefined);
|
||||
m_shortcuts.reset();
|
||||
}
|
||||
|
||||
void Key::copyOriginalToUser()
|
||||
{
|
||||
// Erase all user-defined keys
|
||||
erase_accels(m_adds, KeySource::UserDefined);
|
||||
erase_accels(m_dels, KeySource::UserDefined);
|
||||
erase_shortcuts(m_adds, KeySource::UserDefined);
|
||||
erase_shortcuts(m_dels, KeySource::UserDefined);
|
||||
|
||||
// Then copy all original & extension-defined keys as user-defined
|
||||
auto copy = m_adds;
|
||||
for (const auto& kv : copy)
|
||||
m_adds.emplace_back(KeySource::UserDefined, kv.second);
|
||||
m_accels.reset();
|
||||
m_shortcuts.reset();
|
||||
}
|
||||
|
||||
std::string Key::triggerString() const
|
||||
@ -693,21 +694,21 @@ void KeyboardShortcuts::importFile(XMLElement* rootElement, KeySource source)
|
||||
// add the keyboard shortcut to the command
|
||||
KeyPtr key = this->command(command_name, params, keycontext);
|
||||
if (key && command_key) {
|
||||
Accelerator accel(command_key);
|
||||
Shortcut shortcut(command_key);
|
||||
|
||||
if (!removed) {
|
||||
key->add(accel, source, *this);
|
||||
key->add(shortcut, source, *this);
|
||||
|
||||
// Add the shortcut to the menuitems with this command
|
||||
// (this is only visual, the
|
||||
// "CustomizedGuiManager::onProcessMessage" is the only
|
||||
// one that process keyboard shortcuts)
|
||||
if (key->accels().size() == 1) {
|
||||
if (key->shortcuts().size() == 1) {
|
||||
AppMenus::instance()->applyShortcutToMenuitemsWithCommand(command, params, key);
|
||||
}
|
||||
}
|
||||
else
|
||||
key->disableAccel(accel, source);
|
||||
key->disableShortcut(shortcut, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -729,12 +730,12 @@ void KeyboardShortcuts::importFile(XMLElement* rootElement, KeySource source)
|
||||
KeyPtr key = this->tool(tool);
|
||||
if (key && tool_key) {
|
||||
LOG(VERBOSE, "KEYS: Shortcut for tool %s: %s\n", tool_id, tool_key);
|
||||
Accelerator accel(tool_key);
|
||||
Shortcut shortcut(tool_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source, *this);
|
||||
key->add(shortcut, source, *this);
|
||||
else
|
||||
key->disableAccel(accel, source);
|
||||
key->disableShortcut(shortcut, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -755,12 +756,12 @@ void KeyboardShortcuts::importFile(XMLElement* rootElement, KeySource source)
|
||||
KeyPtr key = this->quicktool(tool);
|
||||
if (key && tool_key) {
|
||||
LOG(VERBOSE, "KEYS: Shortcut for quicktool %s: %s\n", tool_id, tool_key);
|
||||
Accelerator accel(tool_key);
|
||||
Shortcut shortcut(tool_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source, *this);
|
||||
key->add(shortcut, source, *this);
|
||||
else
|
||||
key->disableAccel(accel, source);
|
||||
key->disableShortcut(shortcut, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -791,12 +792,12 @@ void KeyboardShortcuts::importFile(XMLElement* rootElement, KeySource source)
|
||||
action_id,
|
||||
(keycontextstr ? keycontextstr : "Any"),
|
||||
action_key);
|
||||
Accelerator accel(action_key);
|
||||
Shortcut shortcut(action_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source, *this);
|
||||
key->add(shortcut, source, *this);
|
||||
else
|
||||
key->disableAccel(accel, source);
|
||||
key->disableShortcut(shortcut, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -817,12 +818,12 @@ void KeyboardShortcuts::importFile(XMLElement* rootElement, KeySource source)
|
||||
KeyPtr key = this->wheelAction(action);
|
||||
if (key && action_key) {
|
||||
LOG(VERBOSE, "KEYS: Shortcut for wheel action %s: %s\n", action_id, action_key);
|
||||
Accelerator accel(action_key);
|
||||
Shortcut shortcut(action_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source, *this);
|
||||
key->add(shortcut, source, *this);
|
||||
else
|
||||
key->disableAccel(accel, source);
|
||||
key->disableShortcut(shortcut, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -854,12 +855,12 @@ void KeyboardShortcuts::importFile(XMLElement* rootElement, KeySource source)
|
||||
}
|
||||
|
||||
LOG(VERBOSE, "KEYS: Shortcut for drag action %s: %s\n", action_id, action_key);
|
||||
Accelerator accel(action_key);
|
||||
Shortcut shortcut(action_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source, *this);
|
||||
key->add(shortcut, source, *this);
|
||||
else
|
||||
key->disableAccel(accel, source);
|
||||
key->disableShortcut(shortcut, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -904,24 +905,24 @@ void KeyboardShortcuts::exportFile(const std::string& filename)
|
||||
void KeyboardShortcuts::exportKeys(XMLElement* parent, KeyType type)
|
||||
{
|
||||
for (KeyPtr& key : m_keys) {
|
||||
// Save only user defined accelerators.
|
||||
// Save only user defined shortcuts.
|
||||
if (key->type() != type)
|
||||
continue;
|
||||
|
||||
for (const auto& kv : key->delsKeys())
|
||||
if (kv.first == KeySource::UserDefined)
|
||||
exportAccel(parent, key.get(), kv.second, true);
|
||||
exportShortcut(parent, key.get(), kv.second, true);
|
||||
|
||||
for (const auto& kv : key->addsKeys())
|
||||
if (kv.first == KeySource::UserDefined)
|
||||
exportAccel(parent, key.get(), kv.second, false);
|
||||
exportShortcut(parent, key.get(), kv.second, false);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::exportAccel(XMLElement* parent,
|
||||
const Key* key,
|
||||
const ui::Accelerator& accel,
|
||||
bool removed)
|
||||
void KeyboardShortcuts::exportShortcut(XMLElement* parent,
|
||||
const Key* key,
|
||||
const ui::Shortcut& shortcut,
|
||||
bool removed)
|
||||
{
|
||||
XMLElement* elem = parent->InsertNewChildElement("key");
|
||||
|
||||
@ -964,7 +965,7 @@ void KeyboardShortcuts::exportAccel(XMLElement* parent,
|
||||
break;
|
||||
}
|
||||
|
||||
elem->SetAttribute("shortcut", accel.toString().c_str());
|
||||
elem->SetAttribute("shortcut", shortcut.toString().c_str());
|
||||
|
||||
if (removed)
|
||||
elem->SetAttribute("removed", "true");
|
||||
@ -1062,20 +1063,20 @@ KeyPtr KeyboardShortcuts::dragAction(const WheelAction dragAction) const
|
||||
return key;
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
||||
const KeySource source,
|
||||
const KeyContext keyContext,
|
||||
const Key* newKey)
|
||||
void KeyboardShortcuts::disableShortcut(const ui::Shortcut& shortcut,
|
||||
const KeySource source,
|
||||
const KeyContext keyContext,
|
||||
const Key* newKey)
|
||||
{
|
||||
for (KeyPtr& key : m_keys) {
|
||||
if (key.get() != newKey && key->keycontext() == keyContext && key->hasAccel(accel) &&
|
||||
if (key.get() != newKey && key->keycontext() == keyContext && key->hasShortcut(shortcut) &&
|
||||
// Tools can contain the same keyboard shortcut
|
||||
(key->type() != KeyType::Tool || newKey == nullptr || newKey->type() != KeyType::Tool) &&
|
||||
// DragActions can share the same keyboard shortcut (e.g. to
|
||||
// change different values using different DragVectors)
|
||||
(key->type() != KeyType::DragAction || newKey == nullptr ||
|
||||
newKey->type() != KeyType::DragAction)) {
|
||||
key->disableAccel(accel, source);
|
||||
key->disableShortcut(shortcut, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1168,12 +1169,12 @@ WheelAction KeyboardShortcuts::getWheelActionFromMouseMessage(const KeyContext c
|
||||
const ui::Message* msg)
|
||||
{
|
||||
WheelAction wheelAction = WheelAction::None;
|
||||
const ui::Accelerator* bestAccel = nullptr;
|
||||
const ui::Shortcut* bestShortcut = nullptr;
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::WheelAction && key->keycontext() == context) {
|
||||
const ui::Accelerator* accel = key->isPressed(msg, *this);
|
||||
if ((accel) && (!bestAccel || bestAccel->modifiers() < accel->modifiers())) {
|
||||
bestAccel = accel;
|
||||
const ui::Shortcut* shortcut = key->isPressed(msg, *this);
|
||||
if ((shortcut) && (!bestShortcut || bestShortcut->modifiers() < shortcut->modifiers())) {
|
||||
bestShortcut = shortcut;
|
||||
wheelAction = key->wheelAction();
|
||||
}
|
||||
}
|
||||
@ -1188,8 +1189,8 @@ Keys KeyboardShortcuts::getDragActionsFromKeyMessage(const KeyContext context,
|
||||
Keys keys;
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::DragAction) {
|
||||
const ui::Accelerator* accel = key->isPressed(msg, *this);
|
||||
if (accel) {
|
||||
const ui::Shortcut* shortcut = key->isPressed(msg, *this);
|
||||
if (shortcut) {
|
||||
keys.push_back(key);
|
||||
}
|
||||
}
|
||||
@ -1200,7 +1201,7 @@ Keys KeyboardShortcuts::getDragActionsFromKeyMessage(const KeyContext context,
|
||||
bool KeyboardShortcuts::hasMouseWheelCustomization() const
|
||||
{
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::WheelAction && key->hasUserDefinedAccels())
|
||||
if (key->type() == KeyType::WheelAction && key->hasUserDefinedShortcuts())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -1245,38 +1246,38 @@ void KeyboardShortcuts::setDefaultMouseWheelKeys(const bool zoomWithWheel)
|
||||
|
||||
KeyPtr key;
|
||||
key = std::make_shared<Key>(WheelAction::Zoom);
|
||||
key->add(Accelerator(zoomWithWheel ? kKeyNoneModifier : kKeyCtrlModifier, kKeyNil, 0),
|
||||
key->add(Shortcut(zoomWithWheel ? kKeyNoneModifier : kKeyCtrlModifier, kKeyNil, 0),
|
||||
KeySource::Original,
|
||||
*this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
if (!zoomWithWheel) {
|
||||
key = std::make_shared<Key>(WheelAction::VScroll);
|
||||
key->add(Accelerator(kKeyNoneModifier, kKeyNil, 0), KeySource::Original, *this);
|
||||
key->add(Shortcut(kKeyNoneModifier, kKeyNil, 0), KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
}
|
||||
|
||||
key = std::make_shared<Key>(WheelAction::HScroll);
|
||||
key->add(Accelerator(kKeyShiftModifier, kKeyNil, 0), KeySource::Original, *this);
|
||||
key->add(Shortcut(kKeyShiftModifier, kKeyNil, 0), KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
key = std::make_shared<Key>(WheelAction::FgColor);
|
||||
key->add(Accelerator(kKeyAltModifier, kKeyNil, 0), KeySource::Original, *this);
|
||||
key->add(Shortcut(kKeyAltModifier, kKeyNil, 0), KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
key = std::make_shared<Key>(WheelAction::BgColor);
|
||||
key->add(Accelerator((KeyModifiers)(kKeyAltModifier | kKeyShiftModifier), kKeyNil, 0),
|
||||
key->add(Shortcut((KeyModifiers)(kKeyAltModifier | kKeyShiftModifier), kKeyNil, 0),
|
||||
KeySource::Original,
|
||||
*this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
if (zoomWithWheel) {
|
||||
key = std::make_shared<Key>(WheelAction::BrushSize);
|
||||
key->add(Accelerator(kKeyCtrlModifier, kKeyNil, 0), KeySource::Original, *this);
|
||||
key->add(Shortcut(kKeyCtrlModifier, kKeyNil, 0), KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
key = std::make_shared<Key>(WheelAction::Frame);
|
||||
key->add(Accelerator((KeyModifiers)(kKeyCtrlModifier | kKeyShiftModifier), kKeyNil, 0),
|
||||
key->add(Shortcut((KeyModifiers)(kKeyCtrlModifier | kKeyShiftModifier), kKeyNil, 0),
|
||||
KeySource::Original,
|
||||
*this);
|
||||
m_keys.push_back(key);
|
||||
@ -1321,9 +1322,9 @@ std::string key_tooltip(const char* str, const app::Key* key)
|
||||
std::string res;
|
||||
if (str)
|
||||
res += str;
|
||||
if (key && !key->accels().empty()) {
|
||||
if (key && !key->shortcuts().empty()) {
|
||||
res += " (";
|
||||
res += key->accels().front().toString();
|
||||
res += key->shortcuts().front().toString();
|
||||
res += ")";
|
||||
}
|
||||
return res;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -53,10 +53,10 @@ public:
|
||||
KeyPtr wheelAction(const WheelAction action) const;
|
||||
KeyPtr dragAction(const WheelAction action) const;
|
||||
|
||||
void disableAccel(const ui::Accelerator& accel,
|
||||
const KeySource source,
|
||||
const KeyContext keyContext,
|
||||
const Key* newKey);
|
||||
void disableShortcut(const ui::Shortcut& shortcut,
|
||||
const KeySource source,
|
||||
const KeyContext keyContext,
|
||||
const Key* newKey);
|
||||
|
||||
KeyContext getCurrentKeyContext() const;
|
||||
bool getCommandFromKeyMessage(const ui::Message* msg, Command** command, Params* params);
|
||||
@ -77,10 +77,10 @@ public:
|
||||
|
||||
private:
|
||||
void exportKeys(tinyxml2::XMLElement* parent, KeyType type);
|
||||
void exportAccel(tinyxml2::XMLElement* parent,
|
||||
const Key* key,
|
||||
const ui::Accelerator& accel,
|
||||
bool removed);
|
||||
void exportShortcut(tinyxml2::XMLElement* parent,
|
||||
const Key* key,
|
||||
const ui::Shortcut& shortcut,
|
||||
bool removed);
|
||||
|
||||
mutable Keys m_keys;
|
||||
};
|
||||
|
@ -1,202 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// 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/ui/select_accelerator.h"
|
||||
|
||||
#include "app/ui/key.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "obs/signal.h"
|
||||
#include "ui/entry.h"
|
||||
#include "ui/message.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
class SelectAccelerator::KeyField : public ui::Entry {
|
||||
public:
|
||||
KeyField(const Accelerator& accel) : ui::Entry(256, "")
|
||||
{
|
||||
setTranslateDeadKeys(false);
|
||||
setExpansive(true);
|
||||
setFocusMagnet(true);
|
||||
setAccel(accel);
|
||||
}
|
||||
|
||||
void setAccel(const Accelerator& accel)
|
||||
{
|
||||
m_accel = accel;
|
||||
updateText();
|
||||
}
|
||||
|
||||
obs::signal<void(const ui::Accelerator*)> AccelChange;
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(Message* msg) override
|
||||
{
|
||||
switch (msg->type()) {
|
||||
case kKeyDownMessage:
|
||||
if (hasFocus() && !isReadOnly()) {
|
||||
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
|
||||
if (!keymsg->scancode() && keymsg->unicodeChar() < 32)
|
||||
break;
|
||||
|
||||
KeyModifiers modifiers = keymsg->modifiers();
|
||||
|
||||
if (keymsg->scancode() == kKeySpace)
|
||||
modifiers = (KeyModifiers)(modifiers & ~kKeySpaceModifier);
|
||||
|
||||
m_accel = Accelerator(
|
||||
modifiers,
|
||||
keymsg->scancode(),
|
||||
keymsg->unicodeChar() > 32 ? std::tolower(keymsg->unicodeChar()) : 0);
|
||||
|
||||
// Convert the accelerator to a string, and parse it
|
||||
// again. Just to obtain the exact accelerator we'll read
|
||||
// when we import the gui.xml file or an .aseprite-keys file.
|
||||
m_accel = Accelerator(m_accel.toString());
|
||||
|
||||
updateText();
|
||||
|
||||
AccelChange(&m_accel);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Entry::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void updateText()
|
||||
{
|
||||
setText(
|
||||
Accelerator(kKeyNoneModifier, m_accel.scancode(), m_accel.unicodeChar()).toString().c_str());
|
||||
}
|
||||
|
||||
Accelerator m_accel;
|
||||
};
|
||||
|
||||
SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel,
|
||||
const KeyContext keyContext,
|
||||
const KeyboardShortcuts& currentKeys)
|
||||
: m_keyField(new KeyField(accel))
|
||||
, m_keyContext(keyContext)
|
||||
, m_currentKeys(currentKeys)
|
||||
, m_accel(accel)
|
||||
, m_ok(false)
|
||||
, m_modified(false)
|
||||
{
|
||||
updateModifiers();
|
||||
updateAssignedTo();
|
||||
|
||||
keyPlaceholder()->addChild(m_keyField);
|
||||
|
||||
alt()->Click.connect([this] { onModifierChange(kKeyAltModifier, alt()); });
|
||||
cmd()->Click.connect([this] { onModifierChange(kKeyCmdModifier, cmd()); });
|
||||
ctrl()->Click.connect([this] { onModifierChange(kKeyCtrlModifier, ctrl()); });
|
||||
shift()->Click.connect([this] { onModifierChange(kKeyShiftModifier, shift()); });
|
||||
space()->Click.connect([this] { onModifierChange(kKeySpaceModifier, space()); });
|
||||
win()->Click.connect([this] { onModifierChange(kKeyWinModifier, win()); });
|
||||
|
||||
m_keyField->AccelChange.connect(&SelectAccelerator::onAccelChange, this);
|
||||
clearButton()->Click.connect([this] { onClear(); });
|
||||
okButton()->Click.connect([this] { onOK(); });
|
||||
cancelButton()->Click.connect([this] { onCancel(); });
|
||||
|
||||
addChild(&m_tooltipManager);
|
||||
}
|
||||
|
||||
void SelectAccelerator::onModifierChange(KeyModifiers modifier, CheckBox* checkbox)
|
||||
{
|
||||
bool state = (checkbox->isSelected());
|
||||
KeyModifiers modifiers = m_accel.modifiers();
|
||||
KeyScancode scancode = m_accel.scancode();
|
||||
int unicodeChar = m_accel.unicodeChar();
|
||||
|
||||
modifiers = (KeyModifiers)((modifiers & ~modifier) | (state ? modifier : 0));
|
||||
if (modifiers == kKeySpaceModifier && scancode == kKeySpace)
|
||||
modifiers = kKeyNoneModifier;
|
||||
|
||||
m_accel = Accelerator(modifiers, scancode, unicodeChar);
|
||||
|
||||
m_keyField->setAccel(m_accel);
|
||||
m_keyField->requestFocus();
|
||||
updateAssignedTo();
|
||||
}
|
||||
|
||||
void SelectAccelerator::onAccelChange(const ui::Accelerator* accel)
|
||||
{
|
||||
m_accel = *accel;
|
||||
updateModifiers();
|
||||
updateAssignedTo();
|
||||
}
|
||||
|
||||
void SelectAccelerator::onClear()
|
||||
{
|
||||
m_accel = Accelerator(kKeyNoneModifier, kKeyNil, 0);
|
||||
|
||||
m_keyField->setAccel(m_accel);
|
||||
updateModifiers();
|
||||
updateAssignedTo();
|
||||
|
||||
m_keyField->requestFocus();
|
||||
}
|
||||
|
||||
void SelectAccelerator::onOK()
|
||||
{
|
||||
m_ok = true;
|
||||
m_modified = (m_origAccel != m_accel);
|
||||
closeWindow(NULL);
|
||||
}
|
||||
|
||||
void SelectAccelerator::onCancel()
|
||||
{
|
||||
closeWindow(NULL);
|
||||
}
|
||||
|
||||
void SelectAccelerator::updateModifiers()
|
||||
{
|
||||
alt()->setSelected(m_accel.modifiers() & kKeyAltModifier ? true : false);
|
||||
ctrl()->setSelected(m_accel.modifiers() & kKeyCtrlModifier ? true : false);
|
||||
shift()->setSelected(m_accel.modifiers() & kKeyShiftModifier ? true : false);
|
||||
space()->setSelected(m_accel.modifiers() & kKeySpaceModifier ? true : false);
|
||||
#if __APPLE__
|
||||
win()->setVisible(false);
|
||||
cmd()->setSelected(m_accel.modifiers() & kKeyCmdModifier ? true : false);
|
||||
#else
|
||||
#if __linux__
|
||||
win()->setText(kWinKeyName);
|
||||
m_tooltipManager.addTooltipFor(
|
||||
win(),
|
||||
"Also known as Windows key, logo key,\ncommand key, or system key.",
|
||||
TOP);
|
||||
#endif
|
||||
win()->setSelected(m_accel.modifiers() & kKeyWinModifier ? true : false);
|
||||
cmd()->setVisible(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SelectAccelerator::updateAssignedTo()
|
||||
{
|
||||
std::string res = "None";
|
||||
|
||||
for (const KeyPtr& key : m_currentKeys) {
|
||||
if (key->keycontext() == m_keyContext && key->hasAccel(m_accel)) {
|
||||
res = key->triggerString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assignedTo()->setText(res);
|
||||
}
|
||||
|
||||
} // namespace app
|
221
src/app/ui/select_shortcut.cpp
Normal file
221
src/app/ui/select_shortcut.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// 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/ui/select_shortcut.h"
|
||||
|
||||
#include "app/ui/key.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "obs/signal.h"
|
||||
#include "ui/entry.h"
|
||||
#include "ui/message.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
class SelectShortcut::KeyField : public ui::Entry {
|
||||
public:
|
||||
KeyField(const Shortcut& shortcut) : ui::Entry(256, "")
|
||||
{
|
||||
setTranslateDeadKeys(false);
|
||||
setExpansive(true);
|
||||
setFocusMagnet(true);
|
||||
setShortcut(shortcut);
|
||||
}
|
||||
|
||||
void setShortcut(const Shortcut& shortcut)
|
||||
{
|
||||
m_shortcut = shortcut;
|
||||
updateText();
|
||||
}
|
||||
|
||||
obs::signal<void(const ui::Shortcut*)> ShortcutChange;
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(Message* msg) override
|
||||
{
|
||||
switch (msg->type()) {
|
||||
case kKeyDownMessage:
|
||||
if (hasFocus() && !isReadOnly()) {
|
||||
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
|
||||
if (!keymsg->scancode() && keymsg->unicodeChar() < 32)
|
||||
break;
|
||||
|
||||
KeyModifiers modifiers = keymsg->modifiers();
|
||||
|
||||
if (keymsg->scancode() == kKeySpace)
|
||||
modifiers = (KeyModifiers)(modifiers & ~kKeySpaceModifier);
|
||||
|
||||
setAndParseShortcut(
|
||||
Shortcut(modifiers,
|
||||
keymsg->scancode(),
|
||||
keymsg->unicodeChar() > 32 ? std::tolower(keymsg->unicodeChar()) : 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case kMouseDownMessage:
|
||||
if (!isReadOnly()) {
|
||||
auto* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
const KeyModifiers modifiers = mouseMsg->modifiers();
|
||||
|
||||
setAndParseShortcut(Shortcut(modifiers, mouseMsg->button()));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Entry::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void setAndParseShortcut(const Shortcut& shortcut)
|
||||
{
|
||||
// Convert the shortcut to a string, and parse it
|
||||
// again. Just to obtain the exact shortcut we'll read
|
||||
// when we import the gui.xml file or an .aseprite-keys file.
|
||||
m_shortcut = Shortcut(shortcut.toString());
|
||||
|
||||
updateText();
|
||||
|
||||
ShortcutChange(&m_shortcut);
|
||||
}
|
||||
|
||||
void updateText()
|
||||
{
|
||||
Shortcut tmp = m_shortcut;
|
||||
tmp.removeModifiers();
|
||||
setText(tmp.toString());
|
||||
}
|
||||
|
||||
Shortcut m_shortcut;
|
||||
};
|
||||
|
||||
SelectShortcut::SelectShortcut(const ui::Shortcut& shortcut,
|
||||
const KeyContext keyContext,
|
||||
const KeyboardShortcuts& currentKeys)
|
||||
: m_keyField(new KeyField(shortcut))
|
||||
, m_keyContext(keyContext)
|
||||
, m_currentKeys(currentKeys)
|
||||
, m_shortcut(shortcut)
|
||||
, m_ok(false)
|
||||
, m_modified(false)
|
||||
{
|
||||
updateModifiers();
|
||||
updateAssignedTo();
|
||||
|
||||
keyPlaceholder()->addChild(m_keyField);
|
||||
|
||||
alt()->Click.connect([this] { onModifierChange(kKeyAltModifier, alt()); });
|
||||
cmd()->Click.connect([this] { onModifierChange(kKeyCmdModifier, cmd()); });
|
||||
ctrl()->Click.connect([this] { onModifierChange(kKeyCtrlModifier, ctrl()); });
|
||||
shift()->Click.connect([this] { onModifierChange(kKeyShiftModifier, shift()); });
|
||||
space()->Click.connect([this] { onModifierChange(kKeySpaceModifier, space()); });
|
||||
win()->Click.connect([this] { onModifierChange(kKeyWinModifier, win()); });
|
||||
|
||||
m_keyField->ShortcutChange.connect(&SelectShortcut::onShortcutChange, this);
|
||||
clearButton()->Click.connect([this] { onClear(); });
|
||||
okButton()->Click.connect([this] { onOK(); });
|
||||
cancelButton()->Click.connect([this] { onCancel(); });
|
||||
|
||||
addChild(&m_tooltipManager);
|
||||
}
|
||||
|
||||
void SelectShortcut::onModifierChange(KeyModifiers modifier, CheckBox* checkbox)
|
||||
{
|
||||
bool state = (checkbox->isSelected());
|
||||
KeyModifiers modifiers = m_shortcut.modifiers();
|
||||
KeyScancode scancode = m_shortcut.scancode();
|
||||
int unicodeChar = m_shortcut.unicodeChar();
|
||||
MouseButton mouseButton = m_shortcut.mouseButton();
|
||||
|
||||
modifiers = (KeyModifiers)((modifiers & ~modifier) | (state ? modifier : 0));
|
||||
if (modifiers == kKeySpaceModifier && scancode == kKeySpace)
|
||||
modifiers = kKeyNoneModifier;
|
||||
|
||||
if (mouseButton != kButtonNone)
|
||||
m_shortcut = Shortcut(modifiers, mouseButton);
|
||||
else
|
||||
m_shortcut = Shortcut(modifiers, scancode, unicodeChar);
|
||||
|
||||
m_keyField->setShortcut(m_shortcut);
|
||||
m_keyField->requestFocus();
|
||||
updateAssignedTo();
|
||||
}
|
||||
|
||||
void SelectShortcut::onShortcutChange(const ui::Shortcut* shortcut)
|
||||
{
|
||||
m_shortcut = *shortcut;
|
||||
updateModifiers();
|
||||
updateAssignedTo();
|
||||
}
|
||||
|
||||
void SelectShortcut::onClear()
|
||||
{
|
||||
m_shortcut = Shortcut(kKeyNoneModifier, kKeyNil, 0);
|
||||
|
||||
m_keyField->setShortcut(m_shortcut);
|
||||
updateModifiers();
|
||||
updateAssignedTo();
|
||||
|
||||
m_keyField->requestFocus();
|
||||
}
|
||||
|
||||
void SelectShortcut::onOK()
|
||||
{
|
||||
m_ok = true;
|
||||
m_modified = (m_origShortcut != m_shortcut);
|
||||
closeWindow(NULL);
|
||||
}
|
||||
|
||||
void SelectShortcut::onCancel()
|
||||
{
|
||||
closeWindow(NULL);
|
||||
}
|
||||
|
||||
void SelectShortcut::updateModifiers()
|
||||
{
|
||||
alt()->setSelected(m_shortcut.modifiers() & kKeyAltModifier ? true : false);
|
||||
ctrl()->setSelected(m_shortcut.modifiers() & kKeyCtrlModifier ? true : false);
|
||||
shift()->setSelected(m_shortcut.modifiers() & kKeyShiftModifier ? true : false);
|
||||
space()->setSelected(m_shortcut.modifiers() & kKeySpaceModifier ? true : false);
|
||||
#if __APPLE__
|
||||
win()->setVisible(false);
|
||||
cmd()->setSelected(m_shortcut.modifiers() & kKeyCmdModifier ? true : false);
|
||||
#else
|
||||
#if __linux__
|
||||
win()->setText(kWinKeyName);
|
||||
m_tooltipManager.addTooltipFor(
|
||||
win(),
|
||||
"Also known as Windows key, logo key,\ncommand key, or system key.",
|
||||
TOP);
|
||||
#endif
|
||||
win()->setSelected(m_shortcut.modifiers() & kKeyWinModifier ? true : false);
|
||||
cmd()->setVisible(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SelectShortcut::updateAssignedTo()
|
||||
{
|
||||
std::string res = "None";
|
||||
|
||||
for (const KeyPtr& key : m_currentKeys) {
|
||||
if (key->keycontext() == m_keyContext && key->hasShortcut(m_shortcut)) {
|
||||
res = key->triggerString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assignedTo()->setText(res);
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -1,35 +1,36 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_SELECT_ACCELERATOR_H_INCLUDED
|
||||
#define APP_UI_SELECT_ACCELERATOR_H_INCLUDED
|
||||
#ifndef APP_UI_SELECT_SHORTCUT_H_INCLUDED
|
||||
#define APP_UI_SELECT_SHORTCUT_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/key_context.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/shortcut.h"
|
||||
#include "ui/tooltips.h"
|
||||
|
||||
#include "select_accelerator.xml.h"
|
||||
#include "select_shortcut.xml.h"
|
||||
|
||||
namespace app {
|
||||
class KeyboardShortcuts;
|
||||
|
||||
class SelectAccelerator : public app::gen::SelectAccelerator {
|
||||
class SelectShortcut : public app::gen::SelectShortcut {
|
||||
public:
|
||||
SelectAccelerator(const ui::Accelerator& accelerator,
|
||||
const KeyContext keyContext,
|
||||
const KeyboardShortcuts& currentKeys);
|
||||
SelectShortcut(const ui::Shortcut& shortcut,
|
||||
const KeyContext keyContext,
|
||||
const KeyboardShortcuts& currentKeys);
|
||||
|
||||
bool isOK() const { return m_ok; }
|
||||
bool isModified() const { return m_modified; }
|
||||
const ui::Accelerator& accel() const { return m_accel; }
|
||||
const ui::Shortcut& shortcut() const { return m_shortcut; }
|
||||
|
||||
private:
|
||||
void onModifierChange(ui::KeyModifiers modifier, ui::CheckBox* checkbox);
|
||||
void onAccelChange(const ui::Accelerator* accel);
|
||||
void onShortcutChange(const ui::Shortcut* shortcut);
|
||||
void onClear();
|
||||
void onOK();
|
||||
void onCancel();
|
||||
@ -42,8 +43,8 @@ private:
|
||||
KeyField* m_keyField;
|
||||
KeyContext m_keyContext;
|
||||
const KeyboardShortcuts& m_currentKeys;
|
||||
ui::Accelerator m_origAccel;
|
||||
ui::Accelerator m_accel;
|
||||
ui::Shortcut m_origShortcut;
|
||||
ui::Shortcut m_shortcut;
|
||||
bool m_ok;
|
||||
bool m_modified;
|
||||
};
|
@ -1470,13 +1470,13 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
|
||||
}
|
||||
// Draw the keyboard shortcut
|
||||
else if (AppMenuItem* appMenuItem = dynamic_cast<AppMenuItem*>(widget)) {
|
||||
if (appMenuItem->key() && !appMenuItem->key()->accels().empty()) {
|
||||
if (appMenuItem->key() && !appMenuItem->key()->shortcuts().empty()) {
|
||||
int old_align = appMenuItem->align();
|
||||
|
||||
pos = bounds;
|
||||
pos.w -= widget->childSpacing() / 4;
|
||||
|
||||
std::string buf = appMenuItem->key()->accels().front().toString();
|
||||
std::string buf = appMenuItem->key()->shortcuts().front().toString();
|
||||
|
||||
widget->setAlign(RIGHT | MIDDLE);
|
||||
drawText(g, buf.c_str(), fg, ColorNone, widget, pos, widget->align(), 0);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -534,9 +534,9 @@ public:
|
||||
|
||||
// Tool shortcut
|
||||
KeyPtr key = KeyboardShortcuts::instance()->tool(tool);
|
||||
if (key && !key->accels().empty()) {
|
||||
if (key && !key->shortcuts().empty()) {
|
||||
add(theme->parts.iconKey(), true);
|
||||
m_indicators->addTextIndicator(key->accels().front().toString().c_str());
|
||||
m_indicators->addTextIndicator(key->shortcuts().front().toString().c_str());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -110,11 +110,11 @@ std::string AniControls::getTooltipFor(int index) const
|
||||
tooltip = cmd->friendlyName();
|
||||
|
||||
KeyPtr key = KeyboardShortcuts::instance()->command(cmd->id().c_str());
|
||||
if (!key || key->accels().empty())
|
||||
if (!key || key->shortcuts().empty())
|
||||
key = KeyboardShortcuts::instance()->command(cmd->id().c_str(), Params(), KeyContext::Normal);
|
||||
if (key && !key->accels().empty()) {
|
||||
if (key && !key->shortcuts().empty()) {
|
||||
tooltip += "\n\n" + Strings::ani_controls_shortcut() + " ";
|
||||
tooltip += key->accels().front().toString();
|
||||
tooltip += key->shortcuts().front().toString();
|
||||
}
|
||||
|
||||
if (index == ACTION_PLAY) {
|
||||
|
@ -571,9 +571,9 @@ void ToolBar::openTipWindow(int group_index, Tool* tool)
|
||||
|
||||
// Tool shortcut
|
||||
KeyPtr key = KeyboardShortcuts::instance()->tool(tool);
|
||||
if (key && !key->accels().empty()) {
|
||||
if (key && !key->shortcuts().empty()) {
|
||||
tooltip += "\n\n";
|
||||
tooltip += Strings::tools_shortcut(key->accels().front().toString());
|
||||
tooltip += Strings::tools_shortcut(key->shortcuts().front().toString());
|
||||
}
|
||||
}
|
||||
else if (group_index == PreviewVisibilityIndex) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Aseprite UI Library
|
||||
# Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
# Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
# Copyright (C) 2001-2018 David Capello
|
||||
|
||||
if(WIN32)
|
||||
@ -7,7 +7,6 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
add_library(ui-lib
|
||||
accelerator.cpp
|
||||
alert.cpp
|
||||
app_state.cpp
|
||||
box.cpp
|
||||
@ -44,6 +43,7 @@ add_library(ui-lib
|
||||
scroll_bar.cpp
|
||||
scroll_helper.cpp
|
||||
separator.cpp
|
||||
shortcut.cpp
|
||||
size_hint_event.cpp
|
||||
slider.cpp
|
||||
splitter.cpp
|
||||
|
@ -1,64 +0,0 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2013, 2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#define TEST_GUI
|
||||
#include "tests/app_test.h"
|
||||
|
||||
using namespace ui;
|
||||
|
||||
TEST(Accelerator, Parser)
|
||||
{
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyF1, '\0'), Accelerator("F1"));
|
||||
EXPECT_EQ(Accelerator(kKeyAltModifier, kKeyQ, 'q'), Accelerator("Alt+Q"));
|
||||
EXPECT_EQ(Accelerator(kKeyCtrlModifier, kKeyQ, 'q'), Accelerator("Ctrl+Q"));
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyMinus, '-'), Accelerator("-"));
|
||||
EXPECT_EQ(Accelerator(kKeyShiftModifier, kKeyMinus, '-'), Accelerator("Shift+-"));
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyEquals, '='), Accelerator("="));
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyNil, '+'), Accelerator("+"));
|
||||
EXPECT_EQ(Accelerator(kKeyShiftModifier, kKeyNil, '+'), Accelerator("Shift++"));
|
||||
EXPECT_EQ(Accelerator(kKeyCtrlModifier, kKeyNil, '+'), Accelerator("Ctrl++"));
|
||||
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyMinusPad, 0), Accelerator("Minus Pad"));
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyMinusPad, 0), Accelerator("- Pad"));
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyPlusPad, 0), Accelerator("Plus Pad"));
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyPlusPad, 0), Accelerator("+ Pad"));
|
||||
EXPECT_EQ(Accelerator(kKeyCtrlModifier, kKeyPlusPad, 0), Accelerator("Ctrl++ Pad"));
|
||||
}
|
||||
|
||||
TEST(Accelerator, ToString)
|
||||
{
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyF1, '\0').toString(), Accelerator("F1").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyAltModifier, kKeyQ, 'q').toString(), Accelerator("Alt+Q").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyCtrlModifier, kKeyQ, 'q').toString(), Accelerator("Ctrl+Q").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyMinus, '-').toString(), Accelerator("-").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyShiftModifier, kKeyMinus, '-').toString(),
|
||||
Accelerator("Shift+-").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyEquals, '=').toString(), Accelerator("=").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyNil, '+').toString(), Accelerator("+").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyShiftModifier, kKeyNil, '+').toString(),
|
||||
Accelerator("Shift++").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyCtrlModifier, kKeyNil, '+').toString(),
|
||||
Accelerator("Ctrl++").toString());
|
||||
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyMinusPad, 0).toString(),
|
||||
Accelerator("Minus Pad").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyMinusPad, 0).toString(),
|
||||
Accelerator("- Pad").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyPlusPad, 0).toString(),
|
||||
Accelerator("Plus Pad").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyNoneModifier, kKeyPlusPad, 0).toString(),
|
||||
Accelerator("+ Pad").toString());
|
||||
EXPECT_EQ(Accelerator(kKeyCtrlModifier, kKeyPlusPad, 0).toString(),
|
||||
Accelerator("Ctrl++ Pad").toString());
|
||||
|
||||
EXPECT_EQ("- Pad", Accelerator(kKeyNoneModifier, kKeyMinusPad, 0).toString());
|
||||
EXPECT_EQ("- Pad", Accelerator("Minus Pad").toString());
|
||||
EXPECT_EQ("- Pad", Accelerator("- Pad").toString());
|
||||
|
||||
EXPECT_EQ("+ Pad", Accelerator(kKeyNoneModifier, kKeyPlusPad, 0).toString());
|
||||
EXPECT_EQ("+ Pad", Accelerator("Plus Pad").toString());
|
||||
EXPECT_EQ("+ Pad", Accelerator("+ Pad").toString());
|
||||
}
|
@ -646,16 +646,20 @@ void Manager::handleMouseDown(Display* display,
|
||||
if (!handleWindowZOrder())
|
||||
return;
|
||||
|
||||
enqueueMessage(newMouseMessage(kMouseDownMessage,
|
||||
display,
|
||||
(capture_widget ? capture_widget : mouse_widget),
|
||||
mousePos,
|
||||
pointerType,
|
||||
mouseButton,
|
||||
modifiers,
|
||||
gfx::Point(0, 0),
|
||||
false,
|
||||
pressure));
|
||||
std::unique_ptr<MouseMessage> mouseMsg(
|
||||
newMouseMessage(kMouseDownMessage,
|
||||
display,
|
||||
(capture_widget ? capture_widget : mouse_widget),
|
||||
mousePos,
|
||||
pointerType,
|
||||
mouseButton,
|
||||
modifiers,
|
||||
gfx::Point(0, 0),
|
||||
false,
|
||||
pressure));
|
||||
|
||||
if (onEnqueueMouseDown(mouseMsg.get()))
|
||||
enqueueMessage(mouseMsg.release());
|
||||
}
|
||||
|
||||
void Manager::handleMouseUp(Display* display,
|
||||
@ -1834,6 +1838,11 @@ void Manager::onNewDisplayConfiguration(Display* display)
|
||||
container->flushRedraw();
|
||||
}
|
||||
|
||||
bool Manager::onEnqueueMouseDown(MouseMessage* mouseMsg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Manager::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
int w = 0, h = 0;
|
||||
@ -2280,16 +2289,16 @@ Widget* Manager::findMagneticWidget(Widget* widget)
|
||||
}
|
||||
|
||||
// static
|
||||
Message* Manager::newMouseMessage(MessageType type,
|
||||
Display* display,
|
||||
Widget* widget,
|
||||
const gfx::Point& mousePos,
|
||||
PointerType pointerType,
|
||||
MouseButton button,
|
||||
KeyModifiers modifiers,
|
||||
const gfx::Point& wheelDelta,
|
||||
bool preciseWheel,
|
||||
float pressure)
|
||||
MouseMessage* Manager::newMouseMessage(MessageType type,
|
||||
Display* display,
|
||||
Widget* widget,
|
||||
const gfx::Point& mousePos,
|
||||
PointerType pointerType,
|
||||
MouseButton button,
|
||||
KeyModifiers modifiers,
|
||||
const gfx::Point& wheelDelta,
|
||||
bool preciseWheel,
|
||||
float pressure)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// Convert Ctrl+left click -> right-click
|
||||
@ -2300,14 +2309,14 @@ Message* Manager::newMouseMessage(MessageType type,
|
||||
}
|
||||
#endif
|
||||
|
||||
Message* msg = new MouseMessage(type,
|
||||
pointerType,
|
||||
button,
|
||||
modifiers,
|
||||
mousePos,
|
||||
wheelDelta,
|
||||
preciseWheel,
|
||||
pressure);
|
||||
auto* msg = new MouseMessage(type,
|
||||
pointerType,
|
||||
button,
|
||||
modifiers,
|
||||
mousePos,
|
||||
wheelDelta,
|
||||
preciseWheel,
|
||||
pressure);
|
||||
|
||||
if (display)
|
||||
msg->setDisplay(display);
|
||||
|
@ -146,6 +146,7 @@ protected:
|
||||
void onInitTheme(InitThemeEvent& ev) override;
|
||||
virtual LayoutIO* onGetLayoutIO();
|
||||
virtual void onNewDisplayConfiguration(Display* display);
|
||||
virtual bool onEnqueueMouseDown(MouseMessage* mouseMsg);
|
||||
|
||||
private:
|
||||
void generateSetCursorMessage(Display* display,
|
||||
@ -202,16 +203,16 @@ private:
|
||||
static Widget* findLowestCommonAncestor(Widget* a, Widget* b);
|
||||
static bool someParentIsFocusStop(Widget* widget);
|
||||
static Widget* findMagneticWidget(Widget* widget);
|
||||
static Message* newMouseMessage(MessageType type,
|
||||
Display* display,
|
||||
Widget* widget,
|
||||
const gfx::Point& mousePos,
|
||||
PointerType pointerType,
|
||||
MouseButton button,
|
||||
KeyModifiers modifiers,
|
||||
const gfx::Point& wheelDelta = gfx::Point(0, 0),
|
||||
bool preciseWheel = false,
|
||||
float pressure = 0.0f);
|
||||
static MouseMessage* newMouseMessage(MessageType type,
|
||||
Display* display,
|
||||
Widget* widget,
|
||||
const gfx::Point& mousePos,
|
||||
PointerType pointerType,
|
||||
MouseButton button,
|
||||
KeyModifiers modifiers,
|
||||
const gfx::Point& wheelDelta = gfx::Point(0, 0),
|
||||
bool preciseWheel = false,
|
||||
float pressure = 0.0f);
|
||||
void broadcastKeyMsg(Message* msg);
|
||||
|
||||
static Manager* m_defaultManager;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -9,7 +9,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/shortcut.h"
|
||||
|
||||
#include "base/debug.h"
|
||||
#include "base/replace_string.h"
|
||||
@ -144,21 +144,24 @@ int scancode_to_string_size = sizeof(scancode_to_string) / sizeof(scancode_to_st
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
Accelerator::Accelerator() : m_modifiers(kKeyNoneModifier), m_scancode(kKeyNil), m_unicodeChar(0)
|
||||
Shortcut::Shortcut()
|
||||
{
|
||||
}
|
||||
|
||||
Accelerator::Accelerator(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
|
||||
Shortcut::Shortcut(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
|
||||
: m_modifiers(modifiers)
|
||||
, m_scancode(scancode)
|
||||
, m_unicodeChar(unicodeChar)
|
||||
{
|
||||
}
|
||||
|
||||
Accelerator::Accelerator(const std::string& str)
|
||||
: m_modifiers(kKeyNoneModifier)
|
||||
, m_scancode(kKeyNil)
|
||||
, m_unicodeChar(0)
|
||||
Shortcut::Shortcut(KeyModifiers modifiers, MouseButton mouseButton)
|
||||
: m_modifiers(modifiers)
|
||||
, m_mouseButton(mouseButton)
|
||||
{
|
||||
}
|
||||
|
||||
Shortcut::Shortcut(const std::string& str)
|
||||
{
|
||||
// Special case: plus sign
|
||||
if (str == "+") {
|
||||
@ -272,21 +275,31 @@ Accelerator::Accelerator(const std::string& str)
|
||||
m_scancode = kKeyDelPad;
|
||||
else if (tok == "enter pad")
|
||||
m_scancode = kKeyEnterPad;
|
||||
else if (tok == "left mouse button")
|
||||
m_mouseButton = kButtonLeft;
|
||||
else if (tok == "right mouse button")
|
||||
m_mouseButton = kButtonRight;
|
||||
else if (tok == "middle mouse button")
|
||||
m_mouseButton = kButtonMiddle;
|
||||
else if (tok == "x1 mouse button")
|
||||
m_mouseButton = kButtonX1;
|
||||
else if (tok == "x2 mouse button")
|
||||
m_mouseButton = kButtonX2;
|
||||
}
|
||||
}
|
||||
|
||||
bool Accelerator::operator==(const Accelerator& other) const
|
||||
bool Shortcut::operator==(const Shortcut& other) const
|
||||
{
|
||||
// TODO improve this, avoid conversion to std::string
|
||||
return toString() == other.toString();
|
||||
}
|
||||
|
||||
bool Accelerator::isEmpty() const
|
||||
bool Shortcut::isEmpty() const
|
||||
{
|
||||
return (m_modifiers == kKeyNoneModifier && m_scancode == kKeyNil && m_unicodeChar == 0);
|
||||
}
|
||||
|
||||
std::string Accelerator::toString() const
|
||||
std::string Shortcut::toString() const
|
||||
{
|
||||
std::string buf;
|
||||
|
||||
@ -313,21 +326,34 @@ std::string Accelerator::toString() const
|
||||
wideUnicodeChar.push_back((wchar_t)std::toupper(m_unicodeChar));
|
||||
buf += base::to_utf8(wideUnicodeChar);
|
||||
}
|
||||
else if (m_scancode > 0 && m_scancode < scancode_to_string_size && scancode_to_string[m_scancode])
|
||||
else if (m_scancode > 0 && m_scancode < scancode_to_string_size &&
|
||||
scancode_to_string[m_scancode]) {
|
||||
buf += scancode_to_string[m_scancode];
|
||||
else if (!buf.empty() && buf[buf.size() - 1] == '+')
|
||||
}
|
||||
// Mouse button
|
||||
else if (m_mouseButton != kButtonNone) {
|
||||
switch (m_mouseButton) {
|
||||
case kButtonLeft: buf += "Left Mouse Button"; break;
|
||||
case kButtonRight: buf += "Right Mouse Button"; break;
|
||||
case kButtonMiddle: buf += "Middle Mouse Button"; break;
|
||||
case kButtonX1: buf += "X1 Mouse Button"; break;
|
||||
case kButtonX2: buf += "X2 Mouse Button"; break;
|
||||
}
|
||||
}
|
||||
else if (!buf.empty() && buf[buf.size() - 1] == '+') {
|
||||
buf.erase(buf.size() - 1);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool Accelerator::isPressed(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const
|
||||
bool Shortcut::isPressed(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const
|
||||
{
|
||||
return ((scancode && *this == Accelerator(modifiers, scancode, 0)) ||
|
||||
(unicodeChar && *this == Accelerator(modifiers, kKeyNil, unicodeChar)));
|
||||
return ((scancode && *this == Shortcut(modifiers, scancode, 0)) ||
|
||||
(unicodeChar && *this == Shortcut(modifiers, kKeyNil, unicodeChar)));
|
||||
}
|
||||
|
||||
bool Accelerator::isPressed() const
|
||||
bool Shortcut::isPressed() const
|
||||
{
|
||||
os::SystemRef sys = os::System::instance();
|
||||
if (!sys)
|
||||
@ -336,7 +362,7 @@ bool Accelerator::isPressed() const
|
||||
KeyModifiers pressedModifiers = sys->keyModifiers();
|
||||
|
||||
// Check if this shortcut is only
|
||||
if (m_scancode == kKeyNil && m_unicodeChar == 0)
|
||||
if (m_scancode == kKeyNil && m_unicodeChar == 0 && m_mouseButton == kButtonNone)
|
||||
return (m_modifiers == pressedModifiers);
|
||||
|
||||
// Compare with all pressed scancodes
|
||||
@ -349,7 +375,7 @@ bool Accelerator::isPressed() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Accelerator::isLooselyPressed() const
|
||||
bool Shortcut::isLooselyPressed() const
|
||||
{
|
||||
os::SystemRef sys = os::System::instance();
|
||||
if (!sys)
|
||||
@ -361,7 +387,7 @@ bool Accelerator::isLooselyPressed() const
|
||||
return false;
|
||||
|
||||
// Check if this shortcut is only
|
||||
if (m_scancode == kKeyNil && m_unicodeChar == 0)
|
||||
if (m_scancode == kKeyNil && m_unicodeChar == 0 && m_mouseButton == kButtonNone)
|
||||
return true;
|
||||
|
||||
// Compare with all pressed scancodes
|
||||
@ -378,22 +404,22 @@ bool Accelerator::isLooselyPressed() const
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Accelerators
|
||||
// Shortcuts
|
||||
|
||||
bool Accelerators::has(const Accelerator& accel) const
|
||||
bool Shortcuts::has(const Shortcut& shortcut) const
|
||||
{
|
||||
return (std::find(begin(), end(), accel) != end());
|
||||
return (std::find(begin(), end(), shortcut) != end());
|
||||
}
|
||||
|
||||
void Accelerators::add(const Accelerator& accel)
|
||||
void Shortcuts::add(const Shortcut& shortcut)
|
||||
{
|
||||
if (!has(accel))
|
||||
m_list.push_back(accel);
|
||||
if (!has(shortcut))
|
||||
m_list.push_back(shortcut);
|
||||
}
|
||||
|
||||
void Accelerators::remove(const Accelerator& accel)
|
||||
void Shortcuts::remove(const Shortcut& shortcut)
|
||||
{
|
||||
auto it = std::find(begin(), end(), accel);
|
||||
auto it = std::find(begin(), end(), shortcut);
|
||||
if (it != end())
|
||||
m_list.erase(it);
|
||||
}
|
@ -1,29 +1,31 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef UI_ACCELERATOR_H_INCLUDED
|
||||
#define UI_ACCELERATOR_H_INCLUDED
|
||||
#ifndef UI_SHORTCUT_H_INCLUDED
|
||||
#define UI_SHORTCUT_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "ui/keys.h"
|
||||
#include "ui/mouse_button.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ui/keys.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
extern const char* kWinKeyName;
|
||||
|
||||
// TODO rename this class to Shortcut
|
||||
class Accelerator {
|
||||
class Shortcut {
|
||||
public:
|
||||
Accelerator();
|
||||
Accelerator(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
|
||||
// Convert string like "Ctrl+Q" or "Alt+X" into an accelerator.
|
||||
explicit Accelerator(const std::string& str);
|
||||
Shortcut();
|
||||
Shortcut(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
|
||||
Shortcut(KeyModifiers modifiers, MouseButton mouseButton);
|
||||
// Convert string like "Ctrl+Q" or "Alt+X" into an shortcut.
|
||||
explicit Shortcut(const std::string& str);
|
||||
|
||||
bool isEmpty() const;
|
||||
std::string toString() const;
|
||||
@ -38,23 +40,26 @@ public:
|
||||
// modifiers are allowed too).
|
||||
bool isLooselyPressed() const;
|
||||
|
||||
bool operator==(const Accelerator& other) const;
|
||||
bool operator!=(const Accelerator& other) const { return !operator==(other); }
|
||||
bool operator==(const Shortcut& other) const;
|
||||
bool operator!=(const Shortcut& other) const { return !operator==(other); }
|
||||
|
||||
KeyModifiers modifiers() const { return m_modifiers; }
|
||||
KeyScancode scancode() const { return m_scancode; }
|
||||
int unicodeChar() const { return m_unicodeChar; }
|
||||
MouseButton mouseButton() const { return m_mouseButton; }
|
||||
|
||||
void removeModifiers() { m_modifiers = kKeyNoneModifier; }
|
||||
|
||||
private:
|
||||
KeyModifiers m_modifiers;
|
||||
KeyScancode m_scancode;
|
||||
int m_unicodeChar;
|
||||
KeyModifiers m_modifiers = kKeyNoneModifier;
|
||||
KeyScancode m_scancode = kKeyNil;
|
||||
int m_unicodeChar = 0;
|
||||
MouseButton m_mouseButton = kButtonNone;
|
||||
};
|
||||
|
||||
// TODO rename this class to Shortcuts
|
||||
class Accelerators {
|
||||
class Shortcuts {
|
||||
public:
|
||||
typedef std::vector<Accelerator> List;
|
||||
typedef std::vector<Shortcut> List;
|
||||
typedef List::iterator iterator;
|
||||
typedef List::const_iterator const_iterator;
|
||||
|
||||
@ -66,16 +71,16 @@ public:
|
||||
bool empty() const { return m_list.empty(); }
|
||||
std::size_t size() const { return m_list.size(); }
|
||||
|
||||
const ui::Accelerator& front() const { return m_list.front(); }
|
||||
const ui::Shortcut& front() const { return m_list.front(); }
|
||||
|
||||
const ui::Accelerator& operator[](int index) const { return m_list[index]; }
|
||||
const ui::Shortcut& operator[](int index) const { return m_list[index]; }
|
||||
|
||||
ui::Accelerator& operator[](int index) { return m_list[index]; }
|
||||
ui::Shortcut& operator[](int index) { return m_list[index]; }
|
||||
|
||||
void clear() { m_list.clear(); }
|
||||
bool has(const Accelerator& accel) const;
|
||||
void add(const Accelerator& accel);
|
||||
void remove(const Accelerator& accel);
|
||||
bool has(const Shortcut& shortcut) const;
|
||||
void add(const Shortcut& shortcut);
|
||||
void remove(const Shortcut& shortcut);
|
||||
|
||||
private:
|
||||
List m_list;
|
59
src/ui/shortcut_ui_tests.cpp
Normal file
59
src/ui/shortcut_ui_tests.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#define TEST_GUI
|
||||
#include "tests/app_test.h"
|
||||
|
||||
using namespace ui;
|
||||
|
||||
TEST(Shortcut, Parser)
|
||||
{
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyF1, '\0'), Shortcut("F1"));
|
||||
EXPECT_EQ(Shortcut(kKeyAltModifier, kKeyQ, 'q'), Shortcut("Alt+Q"));
|
||||
EXPECT_EQ(Shortcut(kKeyCtrlModifier, kKeyQ, 'q'), Shortcut("Ctrl+Q"));
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyMinus, '-'), Shortcut("-"));
|
||||
EXPECT_EQ(Shortcut(kKeyShiftModifier, kKeyMinus, '-'), Shortcut("Shift+-"));
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyEquals, '='), Shortcut("="));
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyNil, '+'), Shortcut("+"));
|
||||
EXPECT_EQ(Shortcut(kKeyShiftModifier, kKeyNil, '+'), Shortcut("Shift++"));
|
||||
EXPECT_EQ(Shortcut(kKeyCtrlModifier, kKeyNil, '+'), Shortcut("Ctrl++"));
|
||||
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyMinusPad, 0), Shortcut("Minus Pad"));
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyMinusPad, 0), Shortcut("- Pad"));
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyPlusPad, 0), Shortcut("Plus Pad"));
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyPlusPad, 0), Shortcut("+ Pad"));
|
||||
EXPECT_EQ(Shortcut(kKeyCtrlModifier, kKeyPlusPad, 0), Shortcut("Ctrl++ Pad"));
|
||||
}
|
||||
|
||||
TEST(Shortcut, ToString)
|
||||
{
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyF1, '\0').toString(), Shortcut("F1").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyAltModifier, kKeyQ, 'q').toString(), Shortcut("Alt+Q").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyCtrlModifier, kKeyQ, 'q').toString(), Shortcut("Ctrl+Q").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyMinus, '-').toString(), Shortcut("-").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyShiftModifier, kKeyMinus, '-').toString(), Shortcut("Shift+-").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyEquals, '=').toString(), Shortcut("=").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyNil, '+').toString(), Shortcut("+").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyShiftModifier, kKeyNil, '+').toString(), Shortcut("Shift++").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyCtrlModifier, kKeyNil, '+').toString(), Shortcut("Ctrl++").toString());
|
||||
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyMinusPad, 0).toString(),
|
||||
Shortcut("Minus Pad").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyMinusPad, 0).toString(), Shortcut("- Pad").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyPlusPad, 0).toString(), Shortcut("Plus Pad").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyNoneModifier, kKeyPlusPad, 0).toString(), Shortcut("+ Pad").toString());
|
||||
EXPECT_EQ(Shortcut(kKeyCtrlModifier, kKeyPlusPad, 0).toString(),
|
||||
Shortcut("Ctrl++ Pad").toString());
|
||||
|
||||
EXPECT_EQ("- Pad", Shortcut(kKeyNoneModifier, kKeyMinusPad, 0).toString());
|
||||
EXPECT_EQ("- Pad", Shortcut("Minus Pad").toString());
|
||||
EXPECT_EQ("- Pad", Shortcut("- Pad").toString());
|
||||
|
||||
EXPECT_EQ("+ Pad", Shortcut(kKeyNoneModifier, kKeyPlusPad, 0).toString());
|
||||
EXPECT_EQ("+ Pad", Shortcut("Plus Pad").toString());
|
||||
EXPECT_EQ("+ Pad", Shortcut("+ Pad").toString());
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
#define UI_UI_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/app_state.h"
|
||||
#include "ui/base.h"
|
||||
@ -57,6 +56,7 @@
|
||||
#include "ui/scroll_bar.h"
|
||||
#include "ui/scroll_helper.h"
|
||||
#include "ui/separator.h"
|
||||
#include "ui/shortcut.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/slider.h"
|
||||
#include "ui/splitter.h"
|
||||
|
Loading…
x
Reference in New Issue
Block a user