diff --git a/src/app/app_brushes.cpp b/src/app/app_brushes.cpp index a328ca2826..dc1b5c3f95 100644 --- a/src/app/app_brushes.cpp +++ b/src/app/app_brushes.cpp @@ -190,6 +190,7 @@ AppBrushes::AppBrushes() } } m_userBrushesFilename = fn; + m_lastSlotDeletedIndex = 0xffff; } AppBrushes::~AppBrushes() @@ -225,7 +226,9 @@ void AppBrushes::removeBrushSlot(slot_id slot) { --slot; if (slot >= 0 && slot < (int)m_slots.size()) { - m_slots[slot] = BrushSlot(); + + m_slots.erase(m_slots.begin() + slot); + m_lastSlotDeletedIndex = slot + 1; // the first slot_id is 1 // Erase empty trailing slots while (!m_slots.empty() && diff --git a/src/app/app_brushes.h b/src/app/app_brushes.h index 586c68d773..0400781207 100644 --- a/src/app/app_brushes.h +++ b/src/app/app_brushes.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2021 Igara Studio S.A. +// Copyright (C) 2021-2023 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of @@ -42,6 +42,11 @@ namespace app { void unlockBrushSlot(slot_id slot); bool isBrushSlotLocked(slot_id slot) const; + const int getlastDeletedSlotIndex() { + return m_lastSlotDeletedIndex; + } + void resetDeletedSlotIndex() { m_lastSlotDeletedIndex = 0xffff; } + obs::signal ItemsChange; private: @@ -52,6 +57,7 @@ namespace app { doc::Brushes m_standard; BrushSlots m_slots; std::string m_userBrushesFilename; + int m_lastSlotDeletedIndex; }; } // namespace app diff --git a/src/app/commands/cmd_keyboard_shortcuts.cpp b/src/app/commands/cmd_keyboard_shortcuts.cpp index 679c76e716..1573d69606 100644 --- a/src/app/commands/cmd_keyboard_shortcuts.cpp +++ b/src/app/commands/cmd_keyboard_shortcuts.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2022 Igara Studio S.A. +// Copyright (C) 2018-2023 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -50,8 +50,6 @@ #include #include -#define KEYBOARD_FILENAME_EXTENSION "aseprite-keys" - namespace app { using namespace skin; diff --git a/src/app/ui/brush_popup.cpp b/src/app/ui/brush_popup.cpp index c50066908f..b48c983d02 100644 --- a/src/app/ui/brush_popup.cpp +++ b/src/app/ui/brush_popup.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018-2022 Igara Studio S.A. +// Copyright (C) 2018-2023 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of @@ -19,6 +19,7 @@ #include "app/modules/gui.h" #include "app/modules/palettes.h" #include "app/pref/preferences.h" +#include "app/resource_finder.h" #include "app/tools/tool.h" #include "app/ui/app_menuitem.h" #include "app/ui/button_set.h" @@ -411,9 +412,13 @@ void BrushPopup::regenerate(ui::Display* display, m_customBrushes->setTriggerOnMouseUp(true); int slot = 0; + int lastDeletedSlotIndex = App::instance()->brushes().getlastDeletedSlotIndex(); for (const auto& brush : brushSlots) { ++slot; + if (slot >= lastDeletedSlotIndex) + KeyboardShortcuts::instance()->replaceCustomBrushShortcut(slot); + // Get shortcut std::string shortcut; { @@ -422,8 +427,10 @@ void BrushPopup::regenerate(ui::Display* display, params.set("slot", base::convert_to(slot).c_str()); KeyPtr key = KeyboardShortcuts::instance()->command( CommandId::ChangeBrush(), params); - if (key && !key->accels().empty()) + if (key && !key->accels().empty()) { shortcut = key->accels().front().toString(); + key->originalKeyToUserDefinedKey(); + } } m_customBrushes->addItem(new SelectBrushItem(brush, slot)); m_customBrushes->addItem(new BrushShortcutItem(shortcut, slot)); @@ -439,6 +446,8 @@ void BrushPopup::regenerate(ui::Display* display, // Resize the window and change the hot region. fit_bounds(display, this, gfx::Rect(pos, sizeHint())); setHotRegion(gfx::Region(boundsOnScreen())); + + App::instance()->brushes().resetDeletedSlotIndex(); } void BrushPopup::onBrushChanges() diff --git a/src/app/ui/context_bar.cpp b/src/app/ui/context_bar.cpp index 1b22d4d0f0..29a0d23dbb 100644 --- a/src/app/ui/context_bar.cpp +++ b/src/app/ui/context_bar.cpp @@ -23,6 +23,7 @@ #include "app/ini_file.h" #include "app/match_words.h" #include "app/pref/preferences.h" +#include "app/resource_finder.h" #include "app/shade.h" #include "app/site.h" #include "app/tools/active_tool.h" @@ -170,6 +171,15 @@ class ContextBar::BrushTypeField : public ButtonSet { rgn |= gfx::Region(this->boundsOnScreen()); m_popupWindow.setHotRegion(rgn); }); + m_popupWindow.Close.connect( + [this]{ + // Save keyboard shortcuts in configuration file + auto globalKeys = KeyboardShortcuts::instance(); + ResourceFinder rf; + rf.includeUserDir("user." KEYBOARD_FILENAME_EXTENSION); + std::string fn = rf.getFirstOrCreateDefault(); + globalKeys->exportFile(fn); + }); } ~BrushTypeField() { diff --git a/src/app/ui/key.h b/src/app/ui/key.h index 814aefe609..6459b5e2e6 100644 --- a/src/app/ui/key.h +++ b/src/app/ui/key.h @@ -152,6 +152,8 @@ namespace app { void reset(); void copyOriginalToUser(); + void copyAddsAndDels(const KeyPtr key); + void originalKeyToUserDefinedKey(); // for KeyType::Command Command* command() const { return m_command; } diff --git a/src/app/ui/keyboard_shortcuts.cpp b/src/app/ui/keyboard_shortcuts.cpp index ab785d8a36..f9fc8fbc17 100644 --- a/src/app/ui/keyboard_shortcuts.cpp +++ b/src/app/ui/keyboard_shortcuts.cpp @@ -538,6 +538,33 @@ void Key::copyOriginalToUser() m_accels.reset(); } +void Key::copyAddsAndDels(const KeyPtr key) { + m_dels.clear(); + auto delsCopy = key->delsKeys(); + for (const auto& kv : delsCopy) + m_dels.emplace_back(kv.first, kv.second); + + m_adds.clear(); + auto addsCopy = key->addsKeys(); + for (const auto& kv : addsCopy) + m_adds.emplace_back(kv.first, kv.second); + + m_accels.reset(); +} + +void Key::originalKeyToUserDefinedKey() +{ + auto addsCopy = m_adds; + m_adds.clear(); + for (const auto& kv : addsCopy) { + if (kv.first == KeySource::Original) + m_adds.emplace_back(KeySource::UserDefined, kv.second); + else + m_adds.emplace_back(kv.first, kv.second); + } + m_accels.reset(); +} + std::string Key::triggerString() const { switch (m_type) { @@ -961,6 +988,67 @@ void KeyboardShortcuts::reset() key->reset(); } +int KeyboardShortcuts::findKeyCommandShortcutIndex( + const char* commandName, + const Params& params, + const KeyContext keyContext) const +{ + Command* command = Commands::instance()->byId(commandName); + int i = 0; + for (KeyPtr& key : m_keys) { + if (key && + key->type() == KeyType::Command && + key->keycontext() == keyContext && + key->command() == command && + key->params() == params) { + return i; + } + i++; + } + return -1; +} + +bool KeyboardShortcuts::deleteKeyCommandShortcut( + const char* commandName, + const Params& params, + const KeyContext keyContext) const +{ + int i = -1; + while (i < 0) { + i = findKeyCommandShortcutIndex(commandName, params, keyContext); + if (i < 0) + return false; + m_keys.erase(m_keys.begin() + i); + i = -1; + } + return true; +} + +void KeyboardShortcuts::replaceCustomBrushShortcut(int slot) +{ + Command* command = Commands::instance()->byId(CommandId::ChangeBrush()); + Params params; + params.set("change", "custom"); + params.set("slot", base::convert_to(slot + 1).c_str()); + KeyPtr nextBrushKey = instance()->command(CommandId::ChangeBrush(), params); + params.set("slot", base::convert_to(slot).c_str()); + + if (nextBrushKey) { + KeyPtr newKey = std::make_shared(command, params, KeyContext::Any); + newKey->copyAddsAndDels(nextBrushKey); + + // Clear all commands/shortcuts related to current slot + deleteKeyCommandShortcut(CommandId::ChangeBrush(), params); + + // Adding new commad/shortcuts to KeyboardShortcuts + m_keys.push_back(newKey); + + return; + } + params.set("slot", base::convert_to(slot).c_str()); + deleteKeyCommandShortcut(CommandId::ChangeBrush(), params); +} + KeyPtr KeyboardShortcuts::command(const char* commandName, const Params& params, const KeyContext keyContext) const diff --git a/src/app/ui/keyboard_shortcuts.h b/src/app/ui/keyboard_shortcuts.h index 6ebe2cc516..3a21a17de2 100644 --- a/src/app/ui/keyboard_shortcuts.h +++ b/src/app/ui/keyboard_shortcuts.h @@ -12,6 +12,8 @@ #include "app/ui/key.h" #include "obs/signal.h" +#define KEYBOARD_FILENAME_EXTENSION "aseprite-keys" + class TiXmlElement; namespace app { @@ -43,6 +45,13 @@ namespace app { void exportFile(const std::string& filename); void reset(); + int findKeyCommandShortcutIndex(const char* commandName, + const Params& params = Params(), + const KeyContext keyContext = KeyContext::Any) const; + bool deleteKeyCommandShortcut(const char* commandName, + const Params& params = Params(), + const KeyContext keyContext = KeyContext::Any) const; + void replaceCustomBrushShortcut(int slot); KeyPtr command(const char* commandName, const Params& params = Params(), const KeyContext keyContext = KeyContext::Any) const;