mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-30 15:32:38 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
46626bb5ce
24
data/gui.xml
24
data/gui.xml
@ -8,6 +8,16 @@
|
|||||||
|
|
||||||
<!-- Keyboard shortcuts for commands (menu options) -->
|
<!-- Keyboard shortcuts for commands (menu options) -->
|
||||||
<commands>
|
<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 -->
|
<!-- File -->
|
||||||
<key command="NewFile" shortcut="Ctrl+N" mac="Cmd+N" />
|
<key command="NewFile" shortcut="Ctrl+N" mac="Cmd+N" />
|
||||||
<key command="OpenFile" shortcut="Ctrl+O" mac="Cmd+O" />
|
<key command="OpenFile" shortcut="Ctrl+O" mac="Cmd+O" />
|
||||||
@ -648,7 +658,7 @@
|
|||||||
<menus>
|
<menus>
|
||||||
<!-- main bar menu -->
|
<!-- main bar menu -->
|
||||||
<menu id="main_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="NewFile" text="@.file_new" group="file_new" />
|
||||||
<item command="OpenFile" text="@.file_open" group="file_open" />
|
<item command="OpenFile" text="@.file_open" group="file_open" />
|
||||||
<menu text="@.file_open_recent" group="file_recent">
|
<menu text="@.file_open_recent" group="file_recent">
|
||||||
@ -677,7 +687,7 @@
|
|||||||
<separator group="file_app" />
|
<separator group="file_app" />
|
||||||
<item command="Exit" text="@.file_exit" />
|
<item command="Exit" text="@.file_exit" />
|
||||||
</menu>
|
</menu>
|
||||||
<menu text="@.edit">
|
<menu text="@.edit" id="edit_menu">
|
||||||
<item command="Undo" text="@.edit_undo" />
|
<item command="Undo" text="@.edit_undo" />
|
||||||
<item command="Redo" text="@.edit_redo" />
|
<item command="Redo" text="@.edit_redo" />
|
||||||
<item command="UndoHistory" text="@.edit_undo_history" group="edit_undo" />
|
<item command="UndoHistory" text="@.edit_undo_history" group="edit_undo" />
|
||||||
@ -777,7 +787,7 @@
|
|||||||
<item command="KeyboardShortcuts" text="@.edit_keyboard_shortcuts" />
|
<item command="KeyboardShortcuts" text="@.edit_keyboard_shortcuts" />
|
||||||
<item command="Options" text="@.edit_preferences" />
|
<item command="Options" text="@.edit_preferences" />
|
||||||
</menu>
|
</menu>
|
||||||
<menu text="@.sprite">
|
<menu text="@.sprite" id="sprite_menu">
|
||||||
<item command="SpriteProperties" text="@.sprite_properties" group="sprite_properties" />
|
<item command="SpriteProperties" text="@.sprite_properties" group="sprite_properties" />
|
||||||
<menu text="@.sprite_color_mode" group="sprite_color">
|
<menu text="@.sprite_color_mode" group="sprite_color">
|
||||||
<item command="ChangePixelFormat" text="@.sprite_color_mode_rgb">
|
<item command="ChangePixelFormat" text="@.sprite_color_mode_rgb">
|
||||||
@ -824,7 +834,7 @@
|
|||||||
<item command="CropSprite" text="@.sprite_crop" />
|
<item command="CropSprite" text="@.sprite_crop" />
|
||||||
<item command="AutocropSprite" text="@.sprite_trim" group="sprite_crop" />
|
<item command="AutocropSprite" text="@.sprite_trim" group="sprite_crop" />
|
||||||
</menu>
|
</menu>
|
||||||
<menu text="@.layer">
|
<menu text="@.layer" id="layer_menu">
|
||||||
<item command="LayerProperties" text="@.layer_properties" />
|
<item command="LayerProperties" text="@.layer_properties" />
|
||||||
<item command="LayerVisibility" text="@.layer_visible" />
|
<item command="LayerVisibility" text="@.layer_visible" />
|
||||||
<item command="LayerLock" text="@.layer_lock_layers" />
|
<item command="LayerLock" text="@.layer_lock_layers" />
|
||||||
@ -873,7 +883,7 @@
|
|||||||
<param name="visibleOnly" value="true" />
|
<param name="visibleOnly" value="true" />
|
||||||
</item>
|
</item>
|
||||||
</menu>
|
</menu>
|
||||||
<menu text="@.frame">
|
<menu text="@.frame" id="frame_menu">
|
||||||
<item command="FrameProperties" text="@.frame_properties">
|
<item command="FrameProperties" text="@.frame_properties">
|
||||||
<param name="frame" value="current" />
|
<param name="frame" value="current" />
|
||||||
</item>
|
</item>
|
||||||
@ -915,7 +925,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item command="ReverseFrames" text="@.frame_reverse_frames" group="cel_frames" />
|
<item command="ReverseFrames" text="@.frame_reverse_frames" group="cel_frames" />
|
||||||
</menu>
|
</menu>
|
||||||
<menu text="@.select">
|
<menu text="@.select" id="select_menu">
|
||||||
<item command="MaskAll" text="@.select_all" />
|
<item command="MaskAll" text="@.select_all" />
|
||||||
<item command="DeselectMask" text="@.select_deselect" />
|
<item command="DeselectMask" text="@.select_deselect" />
|
||||||
<item command="ReselectMask" text="@.select_reselect" />
|
<item command="ReselectMask" text="@.select_reselect" />
|
||||||
@ -937,7 +947,7 @@
|
|||||||
<item command="LoadMask" text="@.select_load_from_file" />
|
<item command="LoadMask" text="@.select_load_from_file" />
|
||||||
<item command="SaveMask" text="@.select_save_to_file" group="select_files" />
|
<item command="SaveMask" text="@.select_save_to_file" group="select_files" />
|
||||||
</menu>
|
</menu>
|
||||||
<menu text="@.view">
|
<menu text="@.view" id="view_menu">
|
||||||
<item command="DuplicateView" text="@.view_duplicate_view" group="view_new" />
|
<item command="DuplicateView" text="@.view_duplicate_view" group="view_new" />
|
||||||
<separator />
|
<separator />
|
||||||
<item command="ShowExtras" text="@.view_show_extras" />
|
<item command="ShowExtras" text="@.view_show_extras" />
|
||||||
|
@ -475,6 +475,7 @@ ShowDynamics = Show Dynamics
|
|||||||
ShowExtras = Show Extras
|
ShowExtras = Show Extras
|
||||||
ShowGrid = Show Grid
|
ShowGrid = Show Grid
|
||||||
ShowLayerEdges = Show Layer Edges
|
ShowLayerEdges = Show Layer Edges
|
||||||
|
ShowMenu = Show Menu: {0}
|
||||||
ShowOnionSkin = Show Onion Skin
|
ShowOnionSkin = Show Onion Skin
|
||||||
ShowPaletteOptions = Show Palette Options
|
ShowPaletteOptions = Show Palette Options
|
||||||
ShowPalettePresets = Show Palette Presets
|
ShowPalettePresets = Show Palette Presets
|
||||||
@ -1365,6 +1366,7 @@ download_themes = Download Themes
|
|||||||
open_theme_folder = Open &Folder
|
open_theme_folder = Open &Folder
|
||||||
language_extensions = Languages
|
language_extensions = Languages
|
||||||
theme_extensions = Themes
|
theme_extensions = Themes
|
||||||
|
keys_extensions = Keyboard Shortcuts
|
||||||
script_extensions = Scripts
|
script_extensions = Scripts
|
||||||
palette_extensions = Palettes
|
palette_extensions = Palettes
|
||||||
dithering_matrix_extensions = Dithering Matrices
|
dithering_matrix_extensions = Dithering Matrices
|
||||||
|
@ -316,6 +316,7 @@ if(ENABLE_UI)
|
|||||||
commands/filters/filter_target_buttons.cpp
|
commands/filters/filter_target_buttons.cpp
|
||||||
commands/filters/filter_window.cpp
|
commands/filters/filter_window.cpp
|
||||||
commands/screenshot.cpp
|
commands/screenshot.cpp
|
||||||
|
commands/show_menu.cpp
|
||||||
commands/tileset_mode.cpp
|
commands/tileset_mode.cpp
|
||||||
file_selector.cpp
|
file_selector.cpp
|
||||||
modules/editors.cpp
|
modules/editors.cpp
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -16,6 +16,7 @@
|
|||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/console.h"
|
#include "app/console.h"
|
||||||
|
#include "app/extensions.h"
|
||||||
#include "app/gui_xml.h"
|
#include "app/gui_xml.h"
|
||||||
#include "app/i18n/strings.h"
|
#include "app/i18n/strings.h"
|
||||||
#include "app/recent_files.h"
|
#include "app/recent_files.h"
|
||||||
@ -425,10 +426,22 @@ void AppMenus::reload()
|
|||||||
.FirstChild("gui")
|
.FirstChild("gui")
|
||||||
.FirstChild("keyboard").ToElement();
|
.FirstChild("keyboard").ToElement();
|
||||||
|
|
||||||
|
// From a fresh start, load the default keys
|
||||||
KeyboardShortcuts::instance()->clear();
|
KeyboardShortcuts::instance()->clear();
|
||||||
KeyboardShortcuts::instance()->importFile(xmlKey, KeySource::Original);
|
KeyboardShortcuts::instance()->importFile(xmlKey, KeySource::Original);
|
||||||
|
|
||||||
// Load user settings
|
// Load extension-defined keys
|
||||||
|
for (const Extension* ext : App::instance()->extensions()) {
|
||||||
|
if (ext->isEnabled() &&
|
||||||
|
ext->hasKeys()) {
|
||||||
|
for (const auto& kv : ext->keys()) {
|
||||||
|
KeyboardShortcuts::instance()->importFile(
|
||||||
|
kv.second, KeySource::ExtensionDefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load user-defined keys
|
||||||
{
|
{
|
||||||
ResourceFinder rf;
|
ResourceFinder rf;
|
||||||
rf.includeUserDir("user.aseprite-keys");
|
rf.includeUserDir("user.aseprite-keys");
|
||||||
|
@ -60,7 +60,7 @@ using namespace ui;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef std::map<AppMenuItem*, KeyPtr> MenuKeys;
|
using MenuKeys = std::map<AppMenuItem*, KeyPtr>;
|
||||||
|
|
||||||
class HeaderSplitter : public Splitter {
|
class HeaderSplitter : public Splitter {
|
||||||
public:
|
public:
|
||||||
@ -224,7 +224,7 @@ private:
|
|||||||
window.openWindowInForeground();
|
window.openWindowInForeground();
|
||||||
|
|
||||||
if (window.isModified()) {
|
if (window.isModified()) {
|
||||||
m_key->disableAccel(origAccel);
|
m_key->disableAccel(origAccel, KeySource::UserDefined);
|
||||||
if (!window.accel().isEmpty())
|
if (!window.accel().isEmpty())
|
||||||
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
|
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
|
||||||
}
|
}
|
||||||
@ -244,7 +244,7 @@ private:
|
|||||||
accel.toString())) != 1)
|
accel.toString())) != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_key->disableAccel(accel);
|
m_key->disableAccel(accel, KeySource::UserDefined);
|
||||||
window()->layout();
|
window()->layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -93,6 +93,14 @@ void NewFrameCommand::onExecute(Context* context)
|
|||||||
ContextWriter writer(context);
|
ContextWriter writer(context);
|
||||||
Doc* document(writer.document());
|
Doc* document(writer.document());
|
||||||
Sprite* sprite(writer.sprite());
|
Sprite* sprite(writer.sprite());
|
||||||
|
|
||||||
|
#if ENABLE_UI
|
||||||
|
// Show the tooltip feedback only if we are not inside a transaction
|
||||||
|
// (e.g. we can be already in a transaction if we are running in a
|
||||||
|
// Lua script app.transaction()).
|
||||||
|
const bool showTooltip = (document->transaction() == nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
Tx tx(writer.context(), friendlyName());
|
Tx tx(writer.context(), friendlyName());
|
||||||
DocApi api = document->getApi(tx);
|
DocApi api = document->getApi(tx);
|
||||||
@ -169,7 +177,7 @@ void NewFrameCommand::onExecute(Context* context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_UI
|
#ifdef ENABLE_UI
|
||||||
if (context->isUIAvailable()) {
|
if (context->isUIAvailable() && showTooltip) {
|
||||||
update_screen_for_document(document);
|
update_screen_for_document(document);
|
||||||
|
|
||||||
StatusBar::instance()->showTip(
|
StatusBar::instance()->showTip(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -157,6 +157,13 @@ void NewLayerCommand::onExecute(Context* context)
|
|||||||
Sprite* sprite(reader.sprite());
|
Sprite* sprite(reader.sprite());
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
#if ENABLE_UI
|
||||||
|
// Show the tooltip feedback only if we are not inside a transaction
|
||||||
|
// (e.g. we can be already in a transaction if we are running in a
|
||||||
|
// Lua script app.transaction()).
|
||||||
|
const bool showTooltip = (document->transaction() == nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
Doc* pasteDoc = nullptr;
|
Doc* pasteDoc = nullptr;
|
||||||
Scoped destroyPasteDoc(
|
Scoped destroyPasteDoc(
|
||||||
[&pasteDoc, context]{
|
[&pasteDoc, context]{
|
||||||
@ -466,10 +473,9 @@ void NewLayerCommand::onExecute(Context* context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_UI
|
#ifdef ENABLE_UI
|
||||||
if (context->isUIAvailable()) {
|
if (context->isUIAvailable() && showTooltip) {
|
||||||
update_screen_for_document(document);
|
update_screen_for_document(document);
|
||||||
|
|
||||||
StatusBar::instance()->invalidate();
|
|
||||||
StatusBar::instance()->showTip(
|
StatusBar::instance()->showTip(
|
||||||
1000, fmt::format("{} '{}' created",
|
1000, fmt::format("{} '{}' created",
|
||||||
layerPrefix(),
|
layerPrefix(),
|
||||||
|
@ -1374,6 +1374,10 @@ private:
|
|||||||
if (extensionsList()->getItemsCount() > 0)
|
if (extensionsList()->getItemsCount() > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
loadExtensionsByCategory(
|
||||||
|
Extension::Category::Keys,
|
||||||
|
Strings::options_keys_extensions());
|
||||||
|
|
||||||
loadExtensionsByCategory(
|
loadExtensionsByCategory(
|
||||||
Extension::Category::Languages,
|
Extension::Category::Languages,
|
||||||
Strings::options_language_extensions());
|
Strings::options_language_extensions());
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -149,6 +149,7 @@ FOR_EACH_COMMAND(ShowBrushPreview)
|
|||||||
FOR_EACH_COMMAND(ShowExtras)
|
FOR_EACH_COMMAND(ShowExtras)
|
||||||
FOR_EACH_COMMAND(ShowGrid)
|
FOR_EACH_COMMAND(ShowGrid)
|
||||||
FOR_EACH_COMMAND(ShowLayerEdges)
|
FOR_EACH_COMMAND(ShowLayerEdges)
|
||||||
|
FOR_EACH_COMMAND(ShowMenu)
|
||||||
FOR_EACH_COMMAND(ShowOnionSkin)
|
FOR_EACH_COMMAND(ShowOnionSkin)
|
||||||
FOR_EACH_COMMAND(ShowPixelGrid)
|
FOR_EACH_COMMAND(ShowPixelGrid)
|
||||||
FOR_EACH_COMMAND(ShowSelectionEdges)
|
FOR_EACH_COMMAND(ShowSelectionEdges)
|
||||||
|
83
src/app/commands/show_menu.cpp
Normal file
83
src/app/commands/show_menu.cpp
Normal 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
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -116,7 +116,7 @@ const Session::Backups& Session::backups()
|
|||||||
for (auto& item : base::list_files(m_path)) {
|
for (auto& item : base::list_files(m_path)) {
|
||||||
std::string docDir = base::join_path(m_path, item);
|
std::string docDir = base::join_path(m_path, item);
|
||||||
if (base::is_directory(docDir)) {
|
if (base::is_directory(docDir)) {
|
||||||
m_backups.push_back(new Backup(docDir));
|
m_backups.push_back(std::make_shared<Backup>(docDir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,7 +196,7 @@ void Session::removeFromDisk()
|
|||||||
try {
|
try {
|
||||||
// Remove all backups from disk
|
// Remove all backups from disk
|
||||||
Backups baks = backups();
|
Backups baks = backups();
|
||||||
for (Backup* bak : baks)
|
for (const BackupPtr& bak : baks)
|
||||||
deleteBackup(bak);
|
deleteBackup(bak);
|
||||||
|
|
||||||
if (base::is_file(pidFilename()))
|
if (base::is_file(pidFilename()))
|
||||||
@ -285,7 +285,7 @@ Doc* Session::restoreBackupDoc(const std::string& backupDir,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Doc* Session::restoreBackupDoc(Backup* backup,
|
Doc* Session::restoreBackupDoc(const BackupPtr& backup,
|
||||||
base::task_token* t)
|
base::task_token* t)
|
||||||
{
|
{
|
||||||
return restoreBackupDoc(backup->dir(), t);
|
return restoreBackupDoc(backup->dir(), t);
|
||||||
@ -311,7 +311,7 @@ Doc* Session::restoreBackupDocById(const doc::ObjectId id,
|
|||||||
return restoreBackupDoc(docDir, t);
|
return restoreBackupDoc(docDir, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
Doc* Session::restoreBackupRawImages(Backup* backup,
|
Doc* Session::restoreBackupRawImages(const BackupPtr& backup,
|
||||||
const RawImagesAs as,
|
const RawImagesAs as,
|
||||||
base::task_token* t)
|
base::task_token* t)
|
||||||
{
|
{
|
||||||
@ -330,7 +330,7 @@ Doc* Session::restoreBackupRawImages(Backup* backup,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::deleteBackup(Backup* backup)
|
void Session::deleteBackup(const BackupPtr& backup)
|
||||||
{
|
{
|
||||||
auto it = std::find(m_backups.begin(), m_backups.end(), backup);
|
auto it = std::find(m_backups.begin(), m_backups.end(), backup);
|
||||||
ASSERT(it != m_backups.end());
|
ASSERT(it != m_backups.end());
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -38,7 +38,8 @@ namespace crash {
|
|||||||
std::string m_desc;
|
std::string m_desc;
|
||||||
std::string m_fn;
|
std::string m_fn;
|
||||||
};
|
};
|
||||||
typedef std::vector<Backup*> Backups;
|
using BackupPtr = std::shared_ptr<Backup>;
|
||||||
|
using Backups = std::vector<BackupPtr>;
|
||||||
|
|
||||||
Session(RecoveryConfig* config,
|
Session(RecoveryConfig* config,
|
||||||
const std::string& path);
|
const std::string& path);
|
||||||
@ -60,13 +61,13 @@ namespace crash {
|
|||||||
bool saveDocumentChanges(Doc* doc);
|
bool saveDocumentChanges(Doc* doc);
|
||||||
void removeDocument(Doc* doc);
|
void removeDocument(Doc* doc);
|
||||||
|
|
||||||
Doc* restoreBackupDoc(Backup* backup,
|
Doc* restoreBackupDoc(const BackupPtr& backup,
|
||||||
base::task_token* t);
|
base::task_token* t);
|
||||||
Doc* restoreBackupById(const doc::ObjectId id, base::task_token* t);
|
Doc* restoreBackupById(const doc::ObjectId id, base::task_token* t);
|
||||||
Doc* restoreBackupDocById(const doc::ObjectId id, base::task_token* t);
|
Doc* restoreBackupDocById(const doc::ObjectId id, base::task_token* t);
|
||||||
Doc* restoreBackupRawImages(Backup* backup,
|
Doc* restoreBackupRawImages(const BackupPtr& backup,
|
||||||
const RawImagesAs as, base::task_token* t);
|
const RawImagesAs as, base::task_token* t);
|
||||||
void deleteBackup(Backup* backup);
|
void deleteBackup(const BackupPtr& backup);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Doc* restoreBackupDoc(const std::string& backupDir,
|
Doc* restoreBackupDoc(const std::string& backupDir,
|
||||||
|
@ -257,6 +257,12 @@ void Extension::executeExitActions()
|
|||||||
#endif // ENABLE_SCRIPTING
|
#endif // ENABLE_SCRIPTING
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Extension::addKeys(const std::string& id, const std::string& path)
|
||||||
|
{
|
||||||
|
m_keys[id] = path;
|
||||||
|
updateCategory(Category::Keys);
|
||||||
|
}
|
||||||
|
|
||||||
void Extension::addLanguage(const std::string& id, const std::string& path)
|
void Extension::addLanguage(const std::string& id, const std::string& path)
|
||||||
{
|
{
|
||||||
m_languages[id] = path;
|
m_languages[id] = path;
|
||||||
@ -456,8 +462,10 @@ bool Extension::isDefaultTheme() const
|
|||||||
|
|
||||||
void Extension::updateCategory(const Category newCategory)
|
void Extension::updateCategory(const Category newCategory)
|
||||||
{
|
{
|
||||||
if (m_category == Category::None)
|
if (m_category == Category::None ||
|
||||||
|
m_category == Category::Keys) {
|
||||||
m_category = newCategory;
|
m_category = newCategory;
|
||||||
|
}
|
||||||
else if (m_category != newCategory)
|
else if (m_category != newCategory)
|
||||||
m_category = Category::Multiple;
|
m_category = Category::Multiple;
|
||||||
}
|
}
|
||||||
@ -1016,6 +1024,24 @@ Extension* Extensions::loadExtension(const std::string& path,
|
|||||||
|
|
||||||
auto contributes = json["contributes"];
|
auto contributes = json["contributes"];
|
||||||
if (contributes.is_object()) {
|
if (contributes.is_object()) {
|
||||||
|
// Keys
|
||||||
|
auto keys = contributes["keys"];
|
||||||
|
if (keys.is_array()) {
|
||||||
|
for (const auto& key : keys.array_items()) {
|
||||||
|
std::string keyId = key["id"].string_value();
|
||||||
|
std::string keyPath = key["path"].string_value();
|
||||||
|
|
||||||
|
// The path must be always relative to the extension
|
||||||
|
keyPath = base::join_path(path, keyPath);
|
||||||
|
|
||||||
|
LOG("EXT: New keyboard shortcuts '%s' in '%s'\n",
|
||||||
|
keyId.c_str(),
|
||||||
|
keyPath.c_str());
|
||||||
|
|
||||||
|
extension->addKeys(keyId, keyPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Languages
|
// Languages
|
||||||
auto languages = contributes["languages"];
|
auto languages = contributes["languages"];
|
||||||
if (languages.is_array()) {
|
if (languages.is_array()) {
|
||||||
@ -1132,6 +1158,7 @@ Extension* Extensions::loadExtension(const std::string& path,
|
|||||||
|
|
||||||
void Extensions::generateExtensionSignals(Extension* extension)
|
void Extensions::generateExtensionSignals(Extension* extension)
|
||||||
{
|
{
|
||||||
|
if (extension->hasKeys()) KeysChange(extension);
|
||||||
if (extension->hasLanguages()) LanguagesChange(extension);
|
if (extension->hasLanguages()) LanguagesChange(extension);
|
||||||
if (extension->hasThemes()) ThemesChange(extension);
|
if (extension->hasThemes()) ThemesChange(extension);
|
||||||
if (extension->hasPalettes()) PalettesChange(extension);
|
if (extension->hasPalettes()) PalettesChange(extension);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2017-2018 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -37,6 +37,7 @@ namespace app {
|
|||||||
|
|
||||||
enum class Category {
|
enum class Category {
|
||||||
None,
|
None,
|
||||||
|
Keys,
|
||||||
Languages,
|
Languages,
|
||||||
Themes,
|
Themes,
|
||||||
Scripts,
|
Scripts,
|
||||||
@ -93,10 +94,12 @@ namespace app {
|
|||||||
const std::string& displayName() const { return m_displayName; }
|
const std::string& displayName() const { return m_displayName; }
|
||||||
const Category category() const { return m_category; }
|
const Category category() const { return m_category; }
|
||||||
|
|
||||||
|
const ExtensionItems& keys() const { return m_keys; }
|
||||||
const ExtensionItems& languages() const { return m_languages; }
|
const ExtensionItems& languages() const { return m_languages; }
|
||||||
const Themes& themes() const { return m_themes; }
|
const Themes& themes() const { return m_themes; }
|
||||||
const ExtensionItems& palettes() const { return m_palettes; }
|
const ExtensionItems& palettes() const { return m_palettes; }
|
||||||
|
|
||||||
|
void addKeys(const std::string& id, const std::string& path);
|
||||||
void addLanguage(const std::string& id, const std::string& path);
|
void addLanguage(const std::string& id, const std::string& path);
|
||||||
void addTheme(const std::string& id, const std::string& path, const std::string& variant);
|
void addTheme(const std::string& id, const std::string& path, const std::string& variant);
|
||||||
void addPalette(const std::string& id, const std::string& path);
|
void addPalette(const std::string& id, const std::string& path);
|
||||||
@ -113,6 +116,7 @@ namespace app {
|
|||||||
bool canBeDisabled() const;
|
bool canBeDisabled() const;
|
||||||
bool canBeUninstalled() const;
|
bool canBeUninstalled() const;
|
||||||
|
|
||||||
|
bool hasKeys() const { return !m_keys.empty(); }
|
||||||
bool hasLanguages() const { return !m_languages.empty(); }
|
bool hasLanguages() const { return !m_languages.empty(); }
|
||||||
bool hasThemes() const { return !m_themes.empty(); }
|
bool hasThemes() const { return !m_themes.empty(); }
|
||||||
bool hasPalettes() const { return !m_palettes.empty(); }
|
bool hasPalettes() const { return !m_palettes.empty(); }
|
||||||
@ -135,6 +139,7 @@ namespace app {
|
|||||||
void exitScripts();
|
void exitScripts();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ExtensionItems m_keys;
|
||||||
ExtensionItems m_languages;
|
ExtensionItems m_languages;
|
||||||
Themes m_themes;
|
Themes m_themes;
|
||||||
ExtensionItems m_palettes;
|
ExtensionItems m_palettes;
|
||||||
@ -196,6 +201,7 @@ namespace app {
|
|||||||
std::vector<Extension::DitheringMatrixInfo> ditheringMatrices();
|
std::vector<Extension::DitheringMatrixInfo> ditheringMatrices();
|
||||||
|
|
||||||
obs::signal<void(Extension*)> NewExtension;
|
obs::signal<void(Extension*)> NewExtension;
|
||||||
|
obs::signal<void(Extension*)> KeysChange;
|
||||||
obs::signal<void(Extension*)> LanguagesChange;
|
obs::signal<void(Extension*)> LanguagesChange;
|
||||||
obs::signal<void(Extension*)> ThemesChange;
|
obs::signal<void(Extension*)> ThemesChange;
|
||||||
obs::signal<void(Extension*)> PalettesChange;
|
obs::signal<void(Extension*)> PalettesChange;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2018 David Capello
|
// Copyright (C) 2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -12,6 +12,7 @@
|
|||||||
#include "app/cmd/replace_image.h"
|
#include "app/cmd/replace_image.h"
|
||||||
#include "app/cmd/set_cel_opacity.h"
|
#include "app/cmd/set_cel_opacity.h"
|
||||||
#include "app/cmd/set_cel_position.h"
|
#include "app/cmd/set_cel_position.h"
|
||||||
|
#include "app/doc_api.h"
|
||||||
#include "app/script/docobj.h"
|
#include "app/script/docobj.h"
|
||||||
#include "app/script/engine.h"
|
#include "app/script/engine.h"
|
||||||
#include "app/script/luacpp.h"
|
#include "app/script/luacpp.h"
|
||||||
@ -93,6 +94,23 @@ int Cel_get_opacity(lua_State* L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Cel_set_frame(lua_State* L)
|
||||||
|
{
|
||||||
|
const auto cel = get_docobj<Cel>(L, 1);
|
||||||
|
doc::frame_t frame = get_frame_number_from_arg(L, 2);
|
||||||
|
|
||||||
|
if (cel->frame() == frame)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Tx tx;
|
||||||
|
Doc* doc = static_cast<Doc*>(cel->document());
|
||||||
|
DocApi api = doc->getApi(tx);
|
||||||
|
api.moveCel(cel->layer(), cel->frame(),
|
||||||
|
cel->layer(), frame);
|
||||||
|
tx.commit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Cel_set_image(lua_State* L)
|
int Cel_set_image(lua_State* L)
|
||||||
{
|
{
|
||||||
auto cel = get_docobj<Cel>(L, 1);
|
auto cel = get_docobj<Cel>(L, 1);
|
||||||
@ -134,8 +152,8 @@ const luaL_Reg Cel_methods[] = {
|
|||||||
const Property Cel_properties[] = {
|
const Property Cel_properties[] = {
|
||||||
{ "sprite", Cel_get_sprite, nullptr },
|
{ "sprite", Cel_get_sprite, nullptr },
|
||||||
{ "layer", Cel_get_layer, nullptr },
|
{ "layer", Cel_get_layer, nullptr },
|
||||||
{ "frame", Cel_get_frame, nullptr },
|
{ "frame", Cel_get_frame, Cel_set_frame },
|
||||||
{ "frameNumber", Cel_get_frameNumber, nullptr },
|
{ "frameNumber", Cel_get_frameNumber, Cel_set_frame },
|
||||||
{ "image", Cel_get_image, Cel_set_image },
|
{ "image", Cel_get_image, Cel_set_image },
|
||||||
{ "bounds", Cel_get_bounds, nullptr },
|
{ "bounds", Cel_get_bounds, nullptr },
|
||||||
{ "position", Cel_get_position, Cel_set_position },
|
{ "position", Cel_get_position, Cel_set_position },
|
||||||
|
@ -491,7 +491,16 @@ public:
|
|||||||
if (m_controller == nullptr)
|
if (m_controller == nullptr)
|
||||||
m_controller = &m_twoPoints;
|
m_controller = &m_twoPoints;
|
||||||
else if (m_controller == &m_twoPoints) {
|
else if (m_controller == &m_twoPoints) {
|
||||||
m_controller = &m_freehand;
|
if ((int(loop->getModifiers()) & int(ToolLoopModifiers::kSquareAspect))) {
|
||||||
|
// Don't switch to freehand, just continue with lines if we
|
||||||
|
// have the square aspect key pressed (e.g. Ctrl+Shift). In
|
||||||
|
// this way we avoid to paint two straight lines: 1) from the
|
||||||
|
// very beginning, and 2) from the end of the first straight
|
||||||
|
// line to the new "pt".
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_controller = &m_freehand;
|
||||||
|
}
|
||||||
return; // Don't send first pressButton() click to the freehand controller
|
return; // Don't send first pressButton() click to the freehand controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ namespace {
|
|||||||
|
|
||||||
class Item : public ListItem {
|
class Item : public ListItem {
|
||||||
public:
|
public:
|
||||||
Item(crash::Session* session, crash::Session::Backup* backup)
|
Item(crash::Session* session, const crash::Session::BackupPtr& backup)
|
||||||
: m_session(session)
|
: m_session(session)
|
||||||
, m_backup(backup)
|
, m_backup(backup)
|
||||||
, m_task(nullptr) {
|
, m_task(nullptr) {
|
||||||
@ -63,7 +63,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
crash::Session* session() const { return m_session; }
|
crash::Session* session() const { return m_session; }
|
||||||
crash::Session::Backup* backup() const { return m_backup; }
|
const crash::Session::BackupPtr& backup() const { return m_backup; }
|
||||||
|
|
||||||
bool isTaskRunning() const { return m_task != nullptr; }
|
bool isTaskRunning() const { return m_task != nullptr; }
|
||||||
|
|
||||||
@ -111,6 +111,7 @@ public:
|
|||||||
try {
|
try {
|
||||||
// Warning: This is executed from a worker thread
|
// Warning: This is executed from a worker thread
|
||||||
m_session->deleteBackup(m_backup);
|
m_session->deleteBackup(m_backup);
|
||||||
|
m_backup.reset(); // Delete the Backup instance
|
||||||
|
|
||||||
ui::execute_from_ui_thread(
|
ui::execute_from_ui_thread(
|
||||||
[this]{
|
[this]{
|
||||||
@ -138,10 +139,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateText() {
|
void updateText() {
|
||||||
if (!m_task)
|
if (!m_task) {
|
||||||
|
ASSERT(m_backup);
|
||||||
|
if (!m_backup)
|
||||||
|
return;
|
||||||
|
|
||||||
setText(
|
setText(
|
||||||
m_backup->description(
|
m_backup->description(
|
||||||
Preferences::instance().general.showFullPath()));
|
Preferences::instance().general.showFullPath()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -220,7 +226,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
crash::Session* m_session;
|
crash::Session* m_session;
|
||||||
crash::Session::Backup* m_backup;
|
crash::Session::BackupPtr m_backup;
|
||||||
TaskWidget* m_task;
|
TaskWidget* m_task;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,8 +56,8 @@ bool DelayedMouseMove::onMouseMove(const ui::MouseMessage* msg)
|
|||||||
|
|
||||||
void DelayedMouseMove::onMouseUp(const ui::MouseMessage* msg)
|
void DelayedMouseMove::onMouseUp(const ui::MouseMessage* msg)
|
||||||
{
|
{
|
||||||
updateSpritePos(msg);
|
if (updateSpritePos(msg))
|
||||||
commitMouseMove();
|
commitMouseMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DelayedMouseMove::stopTimer()
|
void DelayedMouseMove::stopTimer()
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "ui/accelerator.h"
|
#include "ui/accelerator.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
@ -32,6 +33,7 @@ namespace app {
|
|||||||
|
|
||||||
enum class KeySource {
|
enum class KeySource {
|
||||||
Original,
|
Original,
|
||||||
|
ExtensionDefined,
|
||||||
UserDefined
|
UserDefined
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,10 +109,12 @@ namespace app {
|
|||||||
class Key;
|
class Key;
|
||||||
using KeyPtr = std::shared_ptr<Key>;
|
using KeyPtr = std::shared_ptr<Key>;
|
||||||
using Keys = std::vector<KeyPtr>;
|
using Keys = std::vector<KeyPtr>;
|
||||||
|
using KeySourceAccelList = std::vector<std::pair<KeySource, ui::Accelerator>>;
|
||||||
using DragVector = base::Vector2d<double>;
|
using DragVector = base::Vector2d<double>;
|
||||||
|
|
||||||
class Key {
|
class Key {
|
||||||
public:
|
public:
|
||||||
|
Key(const Key& key);
|
||||||
Key(Command* command, const Params& params,
|
Key(Command* command, const Params& params,
|
||||||
const KeyContext keyContext);
|
const KeyContext keyContext);
|
||||||
Key(const KeyType type, tools::Tool* tool);
|
Key(const KeyType type, tools::Tool* tool);
|
||||||
@ -120,12 +124,9 @@ namespace app {
|
|||||||
static KeyPtr MakeDragAction(WheelAction dragAction);
|
static KeyPtr MakeDragAction(WheelAction dragAction);
|
||||||
|
|
||||||
KeyType type() const { return m_type; }
|
KeyType type() const { return m_type; }
|
||||||
const ui::Accelerators& accels() const {
|
const ui::Accelerators& accels() const;
|
||||||
return (m_useUsers ? m_users: m_accels);
|
const KeySourceAccelList addsKeys() const { return m_adds; }
|
||||||
}
|
const KeySourceAccelList delsKeys() const { return m_dels; }
|
||||||
const ui::Accelerators& origAccels() const { return m_accels; }
|
|
||||||
const ui::Accelerators& userAccels() const { return m_users; }
|
|
||||||
const ui::Accelerators& userRemovedAccels() const { return m_userRemoved; }
|
|
||||||
|
|
||||||
void add(const ui::Accelerator& accel,
|
void add(const ui::Accelerator& accel,
|
||||||
const KeySource source,
|
const KeySource source,
|
||||||
@ -136,9 +137,15 @@ namespace app {
|
|||||||
bool isLooselyPressed() const;
|
bool isLooselyPressed() const;
|
||||||
|
|
||||||
bool hasAccel(const ui::Accelerator& accel) const;
|
bool hasAccel(const ui::Accelerator& accel) const;
|
||||||
void disableAccel(const ui::Accelerator& accel);
|
bool hasUserDefinedAccels() const;
|
||||||
|
|
||||||
// Resets user accelerators to the original ones.
|
// 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);
|
||||||
|
|
||||||
|
// Resets user accelerators to the original & extension-defined ones.
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void copyOriginalToUser();
|
void copyOriginalToUser();
|
||||||
@ -161,10 +168,11 @@ namespace app {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
KeyType m_type;
|
KeyType m_type;
|
||||||
ui::Accelerators m_accels; // Default accelerators (from gui.xml)
|
KeySourceAccelList m_adds;
|
||||||
ui::Accelerators m_users; // User-defined accelerators
|
KeySourceAccelList m_dels;
|
||||||
ui::Accelerators m_userRemoved; // Default accelerators removed by user
|
// Final list of accelerators after processing the
|
||||||
bool m_useUsers;
|
// addition/deletion of extension-defined & user-defined keys.
|
||||||
|
mutable std::unique_ptr<ui::Accelerators> m_accels;
|
||||||
KeyContext m_keycontext;
|
KeyContext m_keycontext;
|
||||||
|
|
||||||
// for KeyType::Command
|
// for KeyType::Command
|
||||||
|
@ -154,6 +154,32 @@ namespace {
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void erase_accel(app::KeySourceAccelList& kvs,
|
||||||
|
const app::KeySource source,
|
||||||
|
const ui::Accelerator& accel) {
|
||||||
|
for (auto it=kvs.begin(); it!=kvs.end(); ) {
|
||||||
|
auto& kv = *it;
|
||||||
|
if (kv.first == source &&
|
||||||
|
kv.second == accel) {
|
||||||
|
it = kvs.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase_accels(app::KeySourceAccelList& kvs,
|
||||||
|
const app::KeySource source) {
|
||||||
|
for (auto it=kvs.begin(); it!=kvs.end(); ) {
|
||||||
|
auto& kv = *it;
|
||||||
|
if (kv.first == source) {
|
||||||
|
it = kvs.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
@ -219,9 +245,38 @@ using namespace ui;
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Key
|
// Key
|
||||||
|
|
||||||
|
Key::Key(const Key& k)
|
||||||
|
: m_type(k.m_type)
|
||||||
|
, m_adds(k.m_adds)
|
||||||
|
, m_dels(k.m_dels)
|
||||||
|
, m_keycontext(k.m_keycontext)
|
||||||
|
{
|
||||||
|
switch (m_type) {
|
||||||
|
case KeyType::Command:
|
||||||
|
m_command = k.m_command;
|
||||||
|
m_params = k.m_params;
|
||||||
|
break;
|
||||||
|
case KeyType::Tool:
|
||||||
|
case KeyType::Quicktool:
|
||||||
|
m_tool = k.m_tool;
|
||||||
|
break;
|
||||||
|
case KeyType::Action:
|
||||||
|
m_action = k.m_action;
|
||||||
|
break;
|
||||||
|
case KeyType::WheelAction:
|
||||||
|
m_action = k.m_action;
|
||||||
|
m_wheelAction = k.m_wheelAction;
|
||||||
|
break;
|
||||||
|
case KeyType::DragAction:
|
||||||
|
m_action = k.m_action;
|
||||||
|
m_wheelAction = k.m_wheelAction;
|
||||||
|
m_dragVector = k.m_dragVector;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Key::Key(Command* command, const Params& params, const KeyContext keyContext)
|
Key::Key(Command* command, const Params& params, const KeyContext keyContext)
|
||||||
: m_type(KeyType::Command)
|
: m_type(KeyType::Command)
|
||||||
, m_useUsers(false)
|
|
||||||
, m_keycontext(keyContext)
|
, m_keycontext(keyContext)
|
||||||
, m_command(command)
|
, m_command(command)
|
||||||
, m_params(params)
|
, m_params(params)
|
||||||
@ -230,7 +285,6 @@ Key::Key(Command* command, const Params& params, const KeyContext keyContext)
|
|||||||
|
|
||||||
Key::Key(const KeyType type, tools::Tool* tool)
|
Key::Key(const KeyType type, tools::Tool* tool)
|
||||||
: m_type(type)
|
: m_type(type)
|
||||||
, m_useUsers(false)
|
|
||||||
, m_keycontext(KeyContext::Any)
|
, m_keycontext(KeyContext::Any)
|
||||||
, m_tool(tool)
|
, m_tool(tool)
|
||||||
{
|
{
|
||||||
@ -239,7 +293,6 @@ Key::Key(const KeyType type, tools::Tool* tool)
|
|||||||
Key::Key(const KeyAction action,
|
Key::Key(const KeyAction action,
|
||||||
const KeyContext keyContext)
|
const KeyContext keyContext)
|
||||||
: m_type(KeyType::Action)
|
: m_type(KeyType::Action)
|
||||||
, m_useUsers(false)
|
|
||||||
, m_keycontext(keyContext)
|
, m_keycontext(keyContext)
|
||||||
, m_action(action)
|
, m_action(action)
|
||||||
{
|
{
|
||||||
@ -293,7 +346,6 @@ Key::Key(const KeyAction action,
|
|||||||
|
|
||||||
Key::Key(const WheelAction wheelAction)
|
Key::Key(const WheelAction wheelAction)
|
||||||
: m_type(KeyType::WheelAction)
|
: m_type(KeyType::WheelAction)
|
||||||
, m_useUsers(false)
|
|
||||||
, m_keycontext(KeyContext::MouseWheel)
|
, m_keycontext(KeyContext::MouseWheel)
|
||||||
, m_action(KeyAction::None)
|
, m_action(KeyAction::None)
|
||||||
, m_wheelAction(wheelAction)
|
, m_wheelAction(wheelAction)
|
||||||
@ -310,28 +362,57 @@ KeyPtr Key::MakeDragAction(WheelAction dragAction)
|
|||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ui::Accelerators& Key::accels() const
|
||||||
|
{
|
||||||
|
if (!m_accels) {
|
||||||
|
m_accels = std::make_unique<ui::Accelerators>();
|
||||||
|
|
||||||
|
// Add default keys
|
||||||
|
for (const auto& kv : m_adds) {
|
||||||
|
if (kv.first == KeySource::Original)
|
||||||
|
m_accels->add(kv.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete/add extension-defined keys
|
||||||
|
for (const auto& kv : m_dels) {
|
||||||
|
if (kv.first == KeySource::ExtensionDefined)
|
||||||
|
m_accels->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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete/add user-defined keys
|
||||||
|
for (const auto& kv : m_dels) {
|
||||||
|
if (kv.first == KeySource::UserDefined)
|
||||||
|
m_accels->remove(kv.second);
|
||||||
|
}
|
||||||
|
for (const auto& kv : m_adds) {
|
||||||
|
if (kv.first == KeySource::UserDefined)
|
||||||
|
m_accels->add(kv.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *m_accels;
|
||||||
|
}
|
||||||
|
|
||||||
void Key::add(const ui::Accelerator& accel,
|
void Key::add(const ui::Accelerator& accel,
|
||||||
const KeySource source,
|
const KeySource source,
|
||||||
KeyboardShortcuts& globalKeys)
|
KeyboardShortcuts& globalKeys)
|
||||||
{
|
{
|
||||||
Accelerators* accels = &m_accels;
|
m_adds.emplace_back(source, accel);
|
||||||
|
m_accels.reset();
|
||||||
if (source == KeySource::UserDefined) {
|
|
||||||
if (!m_useUsers) {
|
|
||||||
m_useUsers = true;
|
|
||||||
m_users = m_accels;
|
|
||||||
}
|
|
||||||
accels = &m_users;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the accelerator from other commands
|
// Remove the accelerator from other commands
|
||||||
if (source == KeySource::UserDefined) {
|
if (source == KeySource::ExtensionDefined ||
|
||||||
globalKeys.disableAccel(accel, m_keycontext, this);
|
source == KeySource::UserDefined) {
|
||||||
m_userRemoved.remove(accel);
|
erase_accel(m_dels, source, accel);
|
||||||
}
|
|
||||||
|
|
||||||
// Add the accelerator
|
globalKeys.disableAccel(accel, source, m_keycontext, this);
|
||||||
accels->add(accel);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ui::Accelerator* Key::isPressed(const Message* msg,
|
const ui::Accelerator* Key::isPressed(const Message* msg,
|
||||||
@ -386,31 +467,47 @@ bool Key::hasAccel(const ui::Accelerator& accel) const
|
|||||||
return accels().has(accel);
|
return accels().has(accel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Key::disableAccel(const ui::Accelerator& accel)
|
bool Key::hasUserDefinedAccels() const
|
||||||
{
|
{
|
||||||
if (!m_useUsers) {
|
for (const auto& kv : m_adds) {
|
||||||
m_useUsers = true;
|
if (kv.first == KeySource::UserDefined)
|
||||||
m_users = m_accels;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_users.remove(accel);
|
void Key::disableAccel(const ui::Accelerator& accel,
|
||||||
|
const KeySource source)
|
||||||
|
{
|
||||||
|
// It doesn't make sense that the default keyboard shortcuts file
|
||||||
|
// (gui.xml) removes some accelerator.
|
||||||
|
ASSERT(source != KeySource::Original);
|
||||||
|
|
||||||
if (m_accels.has(accel))
|
erase_accel(m_adds, source, accel);
|
||||||
m_userRemoved.add(accel);
|
erase_accel(m_dels, source, accel);
|
||||||
|
|
||||||
|
m_dels.emplace_back(source, accel);
|
||||||
|
m_accels.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Key::reset()
|
void Key::reset()
|
||||||
{
|
{
|
||||||
m_users.clear();
|
erase_accels(m_adds, KeySource::UserDefined);
|
||||||
m_userRemoved.clear();
|
erase_accels(m_dels, KeySource::UserDefined);
|
||||||
m_useUsers = false;
|
m_accels.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Key::copyOriginalToUser()
|
void Key::copyOriginalToUser()
|
||||||
{
|
{
|
||||||
m_users = m_accels;
|
// Erase all user-defined keys
|
||||||
m_userRemoved.clear();
|
erase_accels(m_adds, KeySource::UserDefined);
|
||||||
m_useUsers = true;
|
erase_accels(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();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Key::triggerString() const
|
std::string Key::triggerString() const
|
||||||
@ -527,7 +624,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,7 +653,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -584,7 +681,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -619,7 +716,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -647,7 +744,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -686,7 +783,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -744,11 +841,13 @@ void KeyboardShortcuts::exportKeys(TiXmlElement& parent, KeyType type)
|
|||||||
if (key->type() != type)
|
if (key->type() != type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (const ui::Accelerator& accel : key->userRemovedAccels())
|
for (const auto& kv : key->delsKeys())
|
||||||
exportAccel(parent, key.get(), accel, true);
|
if (kv.first == KeySource::UserDefined)
|
||||||
|
exportAccel(parent, key.get(), kv.second, true);
|
||||||
|
|
||||||
for (const ui::Accelerator& accel : key->userAccels())
|
for (const auto& kv : key->addsKeys())
|
||||||
exportAccel(parent, key.get(), accel, false);
|
if (kv.first == KeySource::UserDefined)
|
||||||
|
exportAccel(parent, key.get(), kv.second, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -913,11 +1012,13 @@ KeyPtr KeyboardShortcuts::dragAction(WheelAction dragAction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
||||||
|
const KeySource source,
|
||||||
const KeyContext keyContext,
|
const KeyContext keyContext,
|
||||||
const Key* newKey)
|
const Key* newKey)
|
||||||
{
|
{
|
||||||
for (KeyPtr& key : m_keys) {
|
for (KeyPtr& key : m_keys) {
|
||||||
if (key->keycontext() == keyContext &&
|
if (key.get() != newKey &&
|
||||||
|
key->keycontext() == keyContext &&
|
||||||
key->hasAccel(accel) &&
|
key->hasAccel(accel) &&
|
||||||
// Tools can contain the same keyboard shortcut
|
// Tools can contain the same keyboard shortcut
|
||||||
(key->type() != KeyType::Tool ||
|
(key->type() != KeyType::Tool ||
|
||||||
@ -928,7 +1029,7 @@ void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
|||||||
(key->type() != KeyType::DragAction ||
|
(key->type() != KeyType::DragAction ||
|
||||||
newKey == nullptr ||
|
newKey == nullptr ||
|
||||||
newKey->type() != KeyType::DragAction)) {
|
newKey->type() != KeyType::DragAction)) {
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1045,7 +1146,7 @@ bool KeyboardShortcuts::hasMouseWheelCustomization() const
|
|||||||
{
|
{
|
||||||
for (const KeyPtr& key : m_keys) {
|
for (const KeyPtr& key : m_keys) {
|
||||||
if (key->type() == KeyType::WheelAction &&
|
if (key->type() == KeyType::WheelAction &&
|
||||||
!key->userAccels().empty())
|
key->hasUserDefinedAccels())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -54,6 +54,7 @@ namespace app {
|
|||||||
KeyPtr dragAction(const WheelAction action);
|
KeyPtr dragAction(const WheelAction action);
|
||||||
|
|
||||||
void disableAccel(const ui::Accelerator& accel,
|
void disableAccel(const ui::Accelerator& accel,
|
||||||
|
const KeySource source,
|
||||||
const KeyContext keyContext,
|
const KeyContext keyContext,
|
||||||
const Key* newKey);
|
const Key* newKey);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020 Igara Studio S.A
|
// Copyright (C) 2020-2022 Igara Studio S.A
|
||||||
// Copyright (C) 2001-2015 David Capello
|
// Copyright (C) 2001-2015 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -18,12 +18,17 @@
|
|||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
MainMenuBar::MainMenuBar()
|
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();
|
Extensions& extensions = App::instance()->extensions();
|
||||||
|
|
||||||
m_extScripts =
|
// Reload the main menu if there are changes in keyboard shortcuts
|
||||||
extensions.ScriptsChange.connect(
|
// or scripts when extensions are installed/uninstalled or
|
||||||
[this]{ reload(); });
|
// enabled/disabled.
|
||||||
|
m_extKeys = extensions.KeysChange.connect( [this]{ reload(); });
|
||||||
|
m_extScripts = extensions.ScriptsChange.connect( [this]{ reload(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainMenuBar::reload()
|
void MainMenuBar::reload()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020 Igara Studio S.A
|
// Copyright (C) 2020-2022 Igara Studio S.A
|
||||||
// Copyright (C) 2001-2015 David Capello
|
// Copyright (C) 2001-2015 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -21,6 +21,7 @@ namespace app {
|
|||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
obs::scoped_connection m_extKeys;
|
||||||
obs::scoped_connection m_extScripts;
|
obs::scoped_connection m_extScripts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -553,12 +553,10 @@ void MainWindow::configureWorkspaceLayout()
|
|||||||
|
|
||||||
if (os::instance()->menus() == nullptr ||
|
if (os::instance()->menus() == nullptr ||
|
||||||
pref.general.showMenuBar()) {
|
pref.general.showMenuBar()) {
|
||||||
if (!m_menuBar->parent())
|
m_menuBar->resetMaxSize();
|
||||||
menuBarPlaceholder()->insertChild(0, m_menuBar);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (m_menuBar->parent())
|
m_menuBar->setMaxSize(gfx::Size(0, 0));
|
||||||
menuBarPlaceholder()->removeChild(m_menuBar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_menuBar->setVisible(normal);
|
m_menuBar->setVisible(normal);
|
||||||
|
@ -1328,8 +1328,8 @@ void Manager::_openWindow(Window* window, bool center)
|
|||||||
|
|
||||||
// Broadcast the open message.
|
// Broadcast the open message.
|
||||||
{
|
{
|
||||||
std::unique_ptr<Message> msg(new Message(kOpenMessage));
|
Message msg(kOpenMessage);
|
||||||
window->sendMessage(msg.get());
|
window->sendMessage(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relayout
|
// Relayout
|
||||||
@ -1480,8 +1480,8 @@ void Manager::_closeWindow(Window* window, bool redraw_background)
|
|||||||
|
|
||||||
// Close message.
|
// Close message.
|
||||||
{
|
{
|
||||||
std::unique_ptr<Message> msg(new Message(kCloseMessage));
|
Message msg(kCloseMessage);
|
||||||
window->sendMessage(msg.get());
|
window->sendMessage(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy native window associated with this window's display if needed
|
// Destroy native window associated with this window's display if needed
|
||||||
|
@ -240,8 +240,9 @@ MenuBox::~MenuBox()
|
|||||||
|
|
||||||
bool MenuBar::m_expandOnMouseover = false;
|
bool MenuBar::m_expandOnMouseover = false;
|
||||||
|
|
||||||
MenuBar::MenuBar()
|
MenuBar::MenuBar(ProcessTopLevelShortcuts processShortcuts)
|
||||||
: MenuBox(kMenuBarWidget)
|
: MenuBox(kMenuBarWidget)
|
||||||
|
, m_processTopLevelShortcuts(processShortcuts == ProcessTopLevelShortcuts::kYes)
|
||||||
{
|
{
|
||||||
createBase();
|
createBase();
|
||||||
}
|
}
|
||||||
@ -320,6 +321,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
|
bool MenuItem::isHighlighted() const
|
||||||
{
|
{
|
||||||
return m_highlighted;
|
return m_highlighted;
|
||||||
@ -391,7 +398,7 @@ void Menu::showPopup(const gfx::Point& pos,
|
|||||||
menubox->stopFilteringMouseDown();
|
menubox->stopFilteringMouseDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget* Menu::findItemById(const char* id)
|
Widget* Menu::findItemById(const char* id) const
|
||||||
{
|
{
|
||||||
Widget* result = findChild(id);
|
Widget* result = findChild(id);
|
||||||
if (result)
|
if (result)
|
||||||
@ -623,7 +630,8 @@ bool MenuBox::onProcessMessage(Message* msg)
|
|||||||
// Check for ALT+some underlined letter
|
// Check for ALT+some underlined letter
|
||||||
if (((this->type() == kMenuBoxWidget) && (msg->modifiers() == kKeyNoneModifier || // <-- Inside menu-boxes we can use letters without Alt modifier pressed
|
if (((this->type() == kMenuBoxWidget) && (msg->modifiers() == kKeyNoneModifier || // <-- Inside menu-boxes we can use letters without Alt modifier pressed
|
||||||
msg->modifiers() == kKeyAltModifier)) ||
|
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);
|
auto keymsg = static_cast<KeyMessage*>(msg);
|
||||||
selected = check_for_letter(menu, keymsg);
|
selected = check_for_letter(menu, keymsg);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
|
@ -31,7 +31,7 @@ namespace ui {
|
|||||||
|
|
||||||
void showPopup(const gfx::Point& pos,
|
void showPopup(const gfx::Point& pos,
|
||||||
Display* parentDisplay);
|
Display* parentDisplay);
|
||||||
Widget* findItemById(const char* id);
|
Widget* findItemById(const char* id) const;
|
||||||
|
|
||||||
// Returns the MenuItem that has as submenu this menu.
|
// Returns the MenuItem that has as submenu this menu.
|
||||||
MenuItem* getOwnerMenuItem() {
|
MenuItem* getOwnerMenuItem() {
|
||||||
@ -98,12 +98,22 @@ namespace ui {
|
|||||||
|
|
||||||
class MenuBar : public MenuBox {
|
class MenuBar : public MenuBox {
|
||||||
public:
|
public:
|
||||||
MenuBar();
|
enum class ProcessTopLevelShortcuts { kNo, kYes };
|
||||||
|
|
||||||
|
MenuBar(ProcessTopLevelShortcuts processShortcuts);
|
||||||
|
|
||||||
|
bool processTopLevelShortcuts() const {
|
||||||
|
return m_processTopLevelShortcuts;
|
||||||
|
}
|
||||||
|
|
||||||
static bool expandOnMouseover();
|
static bool expandOnMouseover();
|
||||||
static void setExpandOnMouseover(bool state);
|
static void setExpandOnMouseover(bool state);
|
||||||
|
|
||||||
private:
|
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;
|
static bool m_expandOnMouseover;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,6 +125,10 @@ namespace ui {
|
|||||||
Menu* getSubmenu();
|
Menu* getSubmenu();
|
||||||
void setSubmenu(Menu* submenu);
|
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;
|
bool isHighlighted() const;
|
||||||
void setHighlighted(bool state);
|
void setHighlighted(bool state);
|
||||||
|
|
||||||
|
@ -522,7 +522,7 @@ bool Widget::hasAncestor(Widget* ancestor)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget* Widget::findChild(const char* id)
|
Widget* Widget::findChild(const char* id) const
|
||||||
{
|
{
|
||||||
for (auto child : m_children) {
|
for (auto child : m_children) {
|
||||||
if (child->id() == id)
|
if (child->id() == id)
|
||||||
@ -538,7 +538,7 @@ Widget* Widget::findChild(const char* id)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget* Widget::findSibling(const char* id)
|
Widget* Widget::findSibling(const char* id) const
|
||||||
{
|
{
|
||||||
return window()->findChild(id);
|
return window()->findChild(id);
|
||||||
}
|
}
|
||||||
@ -992,6 +992,17 @@ void Widget::setMaxSize(const gfx::Size& sz)
|
|||||||
m_maxSize = sz;
|
m_maxSize = sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Widget::resetMinSize()
|
||||||
|
{
|
||||||
|
m_minSize = gfx::Size(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::resetMaxSize()
|
||||||
|
{
|
||||||
|
m_maxSize = gfx::Size(std::numeric_limits<int>::max(),
|
||||||
|
std::numeric_limits<int>::max());
|
||||||
|
}
|
||||||
|
|
||||||
void Widget::flushRedraw()
|
void Widget::flushRedraw()
|
||||||
{
|
{
|
||||||
std::queue<Widget*> processing;
|
std::queue<Widget*> processing;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -189,20 +189,20 @@ namespace ui {
|
|||||||
|
|
||||||
bool hasChild(Widget* child);
|
bool hasChild(Widget* child);
|
||||||
bool hasAncestor(Widget* ancestor);
|
bool hasAncestor(Widget* ancestor);
|
||||||
Widget* findChild(const char* id);
|
Widget* findChild(const char* id) const;
|
||||||
|
|
||||||
// Returns a widget in the same window that is located "sibling".
|
// Returns a widget in the same window that is located "sibling".
|
||||||
Widget* findSibling(const char* id);
|
Widget* findSibling(const char* id) const;
|
||||||
|
|
||||||
// Finds a child with the specified ID and dynamic-casts it to type
|
// Finds a child with the specified ID and dynamic-casts it to type
|
||||||
// T.
|
// T.
|
||||||
template<class T>
|
template<class T>
|
||||||
T* findChildT(const char* id) {
|
T* findChildT(const char* id) const {
|
||||||
return dynamic_cast<T*>(findChild(id));
|
return dynamic_cast<T*>(findChild(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
T* findFirstChildByType() {
|
T* findFirstChildByType() const {
|
||||||
for (auto child : m_children) {
|
for (auto child : m_children) {
|
||||||
if (T* specificChild = dynamic_cast<T*>(child))
|
if (T* specificChild = dynamic_cast<T*>(child))
|
||||||
return specificChild;
|
return specificChild;
|
||||||
@ -259,6 +259,8 @@ namespace ui {
|
|||||||
const gfx::Size& maxSize() const { return m_maxSize; }
|
const gfx::Size& maxSize() const { return m_maxSize; }
|
||||||
void setMinSize(const gfx::Size& sz);
|
void setMinSize(const gfx::Size& sz);
|
||||||
void setMaxSize(const gfx::Size& sz);
|
void setMaxSize(const gfx::Size& sz);
|
||||||
|
void resetMinSize();
|
||||||
|
void resetMaxSize();
|
||||||
|
|
||||||
const gfx::Border& border() const { return m_border; }
|
const gfx::Border& border() const { return m_border; }
|
||||||
void setBorder(const gfx::Border& border);
|
void setBorder(const gfx::Border& border);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user