mirror of
https://github.com/aseprite/aseprite.git
synced 2024-09-02 04:59:24 +00:00
Merge branch '1.0'
Conflicts: data/gui.xml src/config.h src/main/resources_win32.rc
This commit is contained in:
commit
c0078809f7
@ -18,7 +18,8 @@
|
||||
<key command="RepeatLastExport" shortcut="Ctrl+Shift+X" mac="Cmd+Shift+X" />
|
||||
<key command="AdvancedMode" shortcut="F11" />
|
||||
<key command="DeveloperConsole" shortcut="F12" />
|
||||
<key command="Exit" shortcut="Alt+F4" mac="Cmd+Q" />
|
||||
<key command="Exit" win="Ctrl+Q" linux="Ctrl+Q" mac="Cmd+Q" />
|
||||
<key command="Exit" win="Alt+F4" />
|
||||
<key command="Cancel" shortcut="Esc">
|
||||
<param name="type" value="all" />
|
||||
</key>
|
||||
|
@ -82,12 +82,13 @@ private:
|
||||
|
||||
void onChangeAccel(int index) {
|
||||
Accelerator origAccel = m_key->accels()[index];
|
||||
SelectAccelerator window(origAccel);
|
||||
SelectAccelerator window(origAccel, m_key->keycontext());
|
||||
window.openWindowInForeground();
|
||||
|
||||
if (window.isModified()) {
|
||||
m_key->disableAccel(origAccel);
|
||||
m_key->add(window.accel(), KeySource::UserDefined);
|
||||
if (!window.accel().isEmpty())
|
||||
m_key->add(window.accel(), KeySource::UserDefined);
|
||||
}
|
||||
|
||||
getRoot()->layout();
|
||||
@ -106,7 +107,7 @@ private:
|
||||
|
||||
void onAddAccel() {
|
||||
ui::Accelerator accel;
|
||||
SelectAccelerator window(accel);
|
||||
SelectAccelerator window(accel, m_key->keycontext());
|
||||
window.openWindowInForeground();
|
||||
|
||||
if (window.isModified()) {
|
||||
@ -359,8 +360,14 @@ private:
|
||||
fillList(this->menus(), AppMenus::instance()->getRootMenu(), 0);
|
||||
for (Key* key : *app::KeyboardShortcuts::instance()) {
|
||||
std::string text = key->triggerString();
|
||||
if (key->keycontext() == KeyContext::Selection)
|
||||
text += " (w/selection)";
|
||||
switch (key->keycontext()) {
|
||||
case KeyContext::Selection:
|
||||
text = "Selection context: " + text;
|
||||
break;
|
||||
case KeyContext::MovingPixels:
|
||||
text = "Moving pixels context: " + text;
|
||||
break;
|
||||
}
|
||||
KeyItem* keyItem = new KeyItem(text, key, NULL, 0);
|
||||
|
||||
ListBox* listBox = NULL;
|
||||
|
@ -49,9 +49,10 @@ public:
|
||||
Command* clone() const override { return new NewFrameCommand(*this); }
|
||||
|
||||
protected:
|
||||
void onLoadParams(Params* params);
|
||||
bool onEnabled(Context* context);
|
||||
void onExecute(Context* context);
|
||||
void onLoadParams(Params* params) override;
|
||||
bool onEnabled(Context* context) override;
|
||||
void onExecute(Context* context) override;
|
||||
std::string onGetFriendlyName() const override;
|
||||
|
||||
private:
|
||||
Content m_content;
|
||||
@ -106,6 +107,22 @@ void NewFrameCommand::onExecute(Context* context)
|
||||
App::instance()->getMainWindow()->popTimeline();
|
||||
}
|
||||
|
||||
std::string NewFrameCommand::onGetFriendlyName() const
|
||||
{
|
||||
std::string text = "New Frame";
|
||||
|
||||
switch (m_content) {
|
||||
case Content::CurrentFrame:
|
||||
text = "New Frame (duplicated)";
|
||||
break;
|
||||
case Content::EmptyFrame:
|
||||
text = "New Frame (empty)";
|
||||
break;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
Command* CommandFactory::createNewFrameCommand()
|
||||
{
|
||||
return new NewFrameCommand;
|
||||
|
@ -1008,15 +1008,29 @@ void Editor::updateQuicktool()
|
||||
return;
|
||||
}
|
||||
|
||||
tools::Tool* old_quicktool = m_quicktool;
|
||||
tools::Tool* new_quicktool = m_customizationDelegate->getQuickTool(current_tool);
|
||||
|
||||
// Check if the current state accept the given quicktool.
|
||||
if (new_quicktool && !m_state->acceptQuickTool(new_quicktool))
|
||||
return;
|
||||
|
||||
// Hide the drawing cursor with the current tool brush size before
|
||||
// we change the quicktool. In this way we avoid using the
|
||||
// quicktool brush size to clean the current tool cursor.
|
||||
hideDrawingCursor();
|
||||
//
|
||||
// TODO Remove EditorState::regenerateDrawingCursor() creating a
|
||||
// new Document concept of multiple extra cels: we need an extra
|
||||
// cel for the drawing cursor, other for the moving pixels,
|
||||
// etc. In this way we'll not have conflicts between different
|
||||
// uses of the same extra cel.
|
||||
if (m_state->regenerateDrawingCursor())
|
||||
hideDrawingCursor();
|
||||
|
||||
tools::Tool* old_quicktool = m_quicktool;
|
||||
m_quicktool = m_customizationDelegate->getQuickTool(current_tool);
|
||||
m_quicktool = new_quicktool;
|
||||
|
||||
showDrawingCursor();
|
||||
if (m_state->regenerateDrawingCursor())
|
||||
showDrawingCursor();
|
||||
|
||||
// If the tool has changed, we must to update the status bar because
|
||||
// the new tool can display something different in the status bar (e.g. Eyedropper)
|
||||
|
@ -32,6 +32,10 @@ namespace app {
|
||||
class Editor;
|
||||
class EditorDecorator;
|
||||
|
||||
namespace tools {
|
||||
class Tool;
|
||||
}
|
||||
|
||||
// Represents one state of the sprite's editor (Editor class). This
|
||||
// is a base class, a dummy state that ignores all events from the
|
||||
// Editor. Subclasses overrides these methods to customize the
|
||||
@ -103,6 +107,13 @@ namespace app {
|
||||
// drawing cursor.
|
||||
virtual bool requireBrushPreview() { return false; }
|
||||
|
||||
// Returns true if this state accept the given quicktool.
|
||||
virtual bool acceptQuickTool(tools::Tool* tool) { return true; }
|
||||
|
||||
// Returns true if this state supports changing the drawing cursor
|
||||
// extra cel.
|
||||
virtual bool regenerateDrawingCursor() { return true; }
|
||||
|
||||
private:
|
||||
DISABLE_COPYING(EditorState);
|
||||
};
|
||||
|
@ -413,6 +413,16 @@ bool MovingPixelsState::onUpdateStatusBar(Editor* editor)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MovingPixelsState::acceptQuickTool(tools::Tool* tool)
|
||||
{
|
||||
return
|
||||
(!m_pixelsMovement ||
|
||||
tool->getInk(0)->isSelection() ||
|
||||
tool->getInk(0)->isEyedropper() ||
|
||||
tool->getInk(0)->isScrollMovement() ||
|
||||
tool->getInk(0)->isZoom());
|
||||
}
|
||||
|
||||
// Before executing any command, we drop the pixels (go back to standby).
|
||||
void MovingPixelsState::onBeforeCommandExecution(Command* command)
|
||||
{
|
||||
|
@ -58,6 +58,8 @@ namespace app {
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) override;
|
||||
virtual bool acceptQuickTool(tools::Tool* tool) override;
|
||||
virtual bool regenerateDrawingCursor() override { return false; }
|
||||
|
||||
// EditorObserver
|
||||
virtual void onBeforeFrameChanged(Editor* editor) override;
|
||||
|
@ -194,52 +194,51 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Transform selected pixels
|
||||
if (document->isMaskVisible() &&
|
||||
m_decorator->getTransformHandles(editor)) {
|
||||
TransformHandles* transfHandles = m_decorator->getTransformHandles(editor);
|
||||
|
||||
// Get the handle covered by the mouse.
|
||||
HandleType handle = transfHandles->getHandleAtPoint(editor,
|
||||
msg->position(),
|
||||
document->getTransformation());
|
||||
|
||||
if (handle != NoHandle) {
|
||||
int x, y, opacity;
|
||||
Image* image = location.image(&x, &y, &opacity);
|
||||
if (image) {
|
||||
if (!layer->isWritable()) {
|
||||
Alert::show(PACKAGE "<<The layer is locked.||&Close");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Change to MovingPixelsState
|
||||
transformSelection(editor, msg, handle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Move selected pixels
|
||||
if (editor->isInsideSelection() &&
|
||||
currentTool->getInk(0)->isSelection() &&
|
||||
msg->left()) {
|
||||
if (!layer->isWritable()) {
|
||||
Alert::show(PACKAGE "<<The layer is locked.||&Close");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Change to MovingPixelsState
|
||||
transformSelection(editor, msg, MoveHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call the eyedropper command
|
||||
if (clickedInk->isEyedropper()) {
|
||||
onMouseMove(editor, msg);
|
||||
callEyedropper(editor);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (clickedInk->isSelection()) {
|
||||
// Transform selected pixels
|
||||
if (document->isMaskVisible() && m_decorator->getTransformHandles(editor)) {
|
||||
TransformHandles* transfHandles = m_decorator->getTransformHandles(editor);
|
||||
|
||||
// Get the handle covered by the mouse.
|
||||
HandleType handle = transfHandles->getHandleAtPoint(editor,
|
||||
msg->position(),
|
||||
document->getTransformation());
|
||||
|
||||
if (handle != NoHandle) {
|
||||
int x, y, opacity;
|
||||
Image* image = location.image(&x, &y, &opacity);
|
||||
if (image) {
|
||||
if (!layer->isWritable()) {
|
||||
Alert::show(PACKAGE "<<The layer is locked.||&Close");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Change to MovingPixelsState
|
||||
transformSelection(editor, msg, handle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Move selected pixels
|
||||
if (editor->isInsideSelection() && msg->left()) {
|
||||
if (!layer->isWritable()) {
|
||||
Alert::show(PACKAGE "<<The layer is locked.||&Close");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Change to MovingPixelsState
|
||||
transformSelection(editor, msg, MoveHandle);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Start the Tool-Loop
|
||||
if (layer) {
|
||||
tools::ToolLoop* toolLoop = create_tool_loop(editor, context);
|
||||
@ -262,16 +261,8 @@ bool StandbyState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
// We control eyedropper tool from here. TODO move this to another place
|
||||
if (msg->left() || msg->right()) {
|
||||
tools::Ink* clickedInk = editor->getCurrentEditorInk();
|
||||
if (clickedInk->isEyedropper()) {
|
||||
Command* eyedropper_cmd =
|
||||
CommandsModule::instance()->getCommandByName(CommandId::Eyedropper);
|
||||
bool fg = (static_cast<tools::PickInk*>(clickedInk)->target() == tools::PickInk::Fg);
|
||||
|
||||
Params params;
|
||||
params.set("target", fg ? "foreground": "background");
|
||||
|
||||
UIContext::instance()->executeCommand(eyedropper_cmd, ¶ms);
|
||||
}
|
||||
if (clickedInk->isEyedropper())
|
||||
callEyedropper(editor);
|
||||
}
|
||||
|
||||
editor->moveDrawingCursor();
|
||||
@ -560,6 +551,22 @@ void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleT
|
||||
}
|
||||
}
|
||||
|
||||
void StandbyState::callEyedropper(Editor* editor)
|
||||
{
|
||||
tools::Ink* clickedInk = editor->getCurrentEditorInk();
|
||||
if (!clickedInk->isEyedropper())
|
||||
return;
|
||||
|
||||
Command* eyedropper_cmd =
|
||||
CommandsModule::instance()->getCommandByName(CommandId::Eyedropper);
|
||||
bool fg = (static_cast<tools::PickInk*>(clickedInk)->target() == tools::PickInk::Fg);
|
||||
|
||||
Params params;
|
||||
params.set("target", fg ? "foreground": "background");
|
||||
|
||||
UIContext::instance()->executeCommand(eyedropper_cmd, ¶ms);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Decorator
|
||||
|
||||
|
@ -76,6 +76,7 @@ namespace app {
|
||||
|
||||
private:
|
||||
void transformSelection(Editor* editor, ui::MouseMessage* msg, HandleType handle);
|
||||
void callEyedropper(Editor* editor);
|
||||
|
||||
Decorator* m_decorator;
|
||||
};
|
||||
|
@ -39,8 +39,6 @@
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/message.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define XML_KEYBOARD_FILE_VERSION "1"
|
||||
|
||||
namespace {
|
||||
@ -80,6 +78,13 @@ namespace {
|
||||
return shortcut;
|
||||
}
|
||||
|
||||
bool bool_attr_is_true(const TiXmlElement* elem, const char* attribute_name)
|
||||
{
|
||||
const char* value = elem->Attribute(attribute_name);
|
||||
|
||||
return (value != NULL) && (strcmp(value, "true") == 0);
|
||||
}
|
||||
|
||||
std::string get_user_friendly_string_for_keyaction(app::KeyAction action)
|
||||
{
|
||||
for (int c=0; actions[c].name; ++c) {
|
||||
@ -118,6 +123,9 @@ namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Key
|
||||
|
||||
Key::Key(Command* command, const Params* params, KeyContext keyContext)
|
||||
: m_type(KeyType::Command)
|
||||
, m_useUsers(false)
|
||||
@ -141,12 +149,38 @@ Key::Key(KeyAction action)
|
||||
, m_keycontext(KeyContext::Any)
|
||||
, m_action(action)
|
||||
{
|
||||
}
|
||||
|
||||
void Key::setUserAccels(const Accelerators& accels)
|
||||
{
|
||||
m_useUsers = true;
|
||||
m_users = accels;
|
||||
switch (action) {
|
||||
case KeyAction::None:
|
||||
m_keycontext = KeyContext::Any;
|
||||
break;
|
||||
case KeyAction::CopySelection:
|
||||
m_keycontext = KeyContext::MovingPixels;
|
||||
break;
|
||||
case KeyAction::SnapToGrid:
|
||||
m_keycontext = KeyContext::MovingPixels;
|
||||
break;
|
||||
case KeyAction::AngleSnap:
|
||||
m_keycontext = KeyContext::MovingPixels;
|
||||
break;
|
||||
case KeyAction::MaintainAspectRatio:
|
||||
m_keycontext = KeyContext::MovingPixels;
|
||||
break;
|
||||
case KeyAction::LockAxis:
|
||||
m_keycontext = KeyContext::MovingPixels;
|
||||
break;
|
||||
case KeyAction::AddSelection:
|
||||
m_keycontext = KeyContext::Selection;
|
||||
break;
|
||||
case KeyAction::SubtractSelection:
|
||||
m_keycontext = KeyContext::Selection;
|
||||
break;
|
||||
case KeyAction::LeftMouseButton:
|
||||
m_keycontext = KeyContext::Any;
|
||||
break;
|
||||
case KeyAction::RightMouseButton:
|
||||
m_keycontext = KeyContext::Any;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Key::add(const ui::Accelerator& accel, KeySource source)
|
||||
@ -159,11 +193,16 @@ void Key::add(const ui::Accelerator& accel, KeySource source)
|
||||
m_users = m_accels;
|
||||
}
|
||||
accels = &m_users;
|
||||
|
||||
KeyboardShortcuts::instance()->disableAccel(accel);
|
||||
}
|
||||
|
||||
accels->push_back(accel);
|
||||
// Remove the accelerator from other commands
|
||||
if (source == KeySource::UserDefined) {
|
||||
KeyboardShortcuts::instance()->disableAccel(accel, m_keycontext);
|
||||
m_userRemoved.remove(accel);
|
||||
}
|
||||
|
||||
// Add the accelerator
|
||||
accels->add(accel);
|
||||
}
|
||||
|
||||
bool Key::isPressed(Message* msg) const
|
||||
@ -194,7 +233,7 @@ bool Key::checkFromAllegroKeyArray()
|
||||
|
||||
bool Key::hasAccel(const ui::Accelerator& accel) const
|
||||
{
|
||||
return (std::find(accels().begin(), accels().end(), accel) != accels().end());
|
||||
return accels().has(accel);
|
||||
}
|
||||
|
||||
void Key::disableAccel(const ui::Accelerator& accel)
|
||||
@ -204,14 +243,16 @@ void Key::disableAccel(const ui::Accelerator& accel)
|
||||
m_users = m_accels;
|
||||
}
|
||||
|
||||
Accelerators::iterator it = std::find(m_users.begin(), m_users.end(), accel);
|
||||
if (it != m_users.end())
|
||||
m_users.erase(it);
|
||||
m_users.remove(accel);
|
||||
|
||||
if (m_accels.has(accel))
|
||||
m_userRemoved.add(accel);
|
||||
}
|
||||
|
||||
void Key::reset()
|
||||
{
|
||||
m_users.clear();
|
||||
m_userRemoved.clear();
|
||||
m_useUsers = false;
|
||||
}
|
||||
|
||||
@ -235,6 +276,9 @@ std::string Key::triggerString() const
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// KeyboardShortcuts
|
||||
|
||||
KeyboardShortcuts* KeyboardShortcuts::instance()
|
||||
{
|
||||
static KeyboardShortcuts* singleton = NULL;
|
||||
@ -270,6 +314,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* command_name = xmlKey->Attribute("command");
|
||||
const char* command_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
|
||||
if (command_name && command_key) {
|
||||
Command* command = CommandsModule::instance()->getCommandByName(command_name);
|
||||
@ -303,15 +348,21 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
// add the keyboard shortcut to the command
|
||||
Key* key = this->command(command_name, ¶ms, keycontext);
|
||||
if (key) {
|
||||
key->add(Accelerator(command_key), source);
|
||||
Accelerator accel(command_key);
|
||||
|
||||
// Add the shortcut to the menuitems with this
|
||||
// command (this is only visual, the "manager_msg_proc"
|
||||
// is the only one that process keyboard shortcuts)
|
||||
if (key->accels().size() == 1) {
|
||||
AppMenus::instance()->applyShortcutToMenuitemsWithCommand(
|
||||
command, ¶ms, key);
|
||||
if (!removed) {
|
||||
key->add(accel, source);
|
||||
|
||||
// Add the shortcut to the menuitems with this
|
||||
// command (this is only visual, the "manager_msg_proc"
|
||||
// is the only one that process keyboard shortcuts)
|
||||
if (key->accels().size() == 1) {
|
||||
AppMenus::instance()->applyShortcutToMenuitemsWithCommand(
|
||||
command, ¶ms, key);
|
||||
}
|
||||
}
|
||||
else
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -327,6 +378,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* tool_id = xmlKey->Attribute("tool");
|
||||
const char* tool_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
|
||||
if (tool_id && tool_key) {
|
||||
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
|
||||
@ -334,8 +386,14 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
PRINTF(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key);
|
||||
|
||||
Key* key = this->tool(tool);
|
||||
if (key)
|
||||
key->add(Accelerator(tool_key), source);
|
||||
if (key) {
|
||||
Accelerator accel(tool_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source);
|
||||
else
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlKey = xmlKey->NextSiblingElement();
|
||||
@ -349,14 +407,22 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* tool_id = xmlKey->Attribute("tool");
|
||||
const char* tool_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
|
||||
if (tool_id && tool_key) {
|
||||
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
|
||||
if (tool) {
|
||||
PRINTF(" - Shortcut for quicktool `%s': <%s>\n", tool_id, tool_key);
|
||||
|
||||
Key* key = this->quicktool(tool);
|
||||
if (key)
|
||||
key->add(Accelerator(tool_key), source);
|
||||
if (key) {
|
||||
Accelerator accel(tool_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source);
|
||||
else
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlKey = xmlKey->NextSiblingElement();
|
||||
@ -370,6 +436,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* tool_action = xmlKey->Attribute("action");
|
||||
const char* tool_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
|
||||
if (tool_action && tool_key) {
|
||||
PRINTF(" - Shortcut for sprite editor `%s': <%s>\n", tool_action, tool_key);
|
||||
@ -378,8 +445,14 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
|
||||
if (action != KeyAction::None) {
|
||||
Key* key = this->action(action);
|
||||
if (key)
|
||||
key->add(Accelerator(tool_key), source);
|
||||
if (key) {
|
||||
Accelerator accel(tool_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source);
|
||||
else
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlKey = xmlKey->NextSiblingElement();
|
||||
@ -424,41 +497,77 @@ void KeyboardShortcuts::exportKeys(TiXmlElement& parent, KeyType type)
|
||||
{
|
||||
for (Key* key : m_keys) {
|
||||
// Save only user defined accelerators.
|
||||
if (key->type() != type || key->userAccels().empty())
|
||||
if (key->type() != type)
|
||||
continue;
|
||||
|
||||
for (const ui::Accelerator& accel : key->userAccels()) {
|
||||
TiXmlElement elem("key");
|
||||
for (const ui::Accelerator& accel : key->userRemovedAccels())
|
||||
exportAccel(parent, key, accel, true);
|
||||
|
||||
switch (key->type()) {
|
||||
case KeyType::Command:
|
||||
elem.SetAttribute("command", key->command()->short_name());
|
||||
if (key->params()) {
|
||||
for (const auto& param : *key->params()) {
|
||||
if (param.second.empty())
|
||||
continue;
|
||||
for (const ui::Accelerator& accel : key->userAccels())
|
||||
exportAccel(parent, key, accel, false);
|
||||
}
|
||||
}
|
||||
|
||||
TiXmlElement paramElem("param");
|
||||
paramElem.SetAttribute("name", param.first.c_str());
|
||||
paramElem.SetAttribute("value", param.second.c_str());
|
||||
elem.InsertEndChild(paramElem);
|
||||
}
|
||||
}
|
||||
void KeyboardShortcuts::exportAccel(TiXmlElement& parent, Key* key, const ui::Accelerator& accel, bool removed)
|
||||
{
|
||||
TiXmlElement elem("key");
|
||||
|
||||
switch (key->type()) {
|
||||
|
||||
case KeyType::Command: {
|
||||
const char* keycontextStr = NULL;
|
||||
|
||||
elem.SetAttribute("command", key->command()->short_name());
|
||||
|
||||
switch (key->keycontext()) {
|
||||
case KeyContext::Any:
|
||||
// Without "context" attribute
|
||||
break;
|
||||
case KeyType::Tool:
|
||||
case KeyType::Quicktool:
|
||||
elem.SetAttribute("tool", key->tool()->getId().c_str());
|
||||
case KeyContext::Normal:
|
||||
keycontextStr = "Normal";
|
||||
break;
|
||||
case KeyType::Action:
|
||||
elem.SetAttribute("action",
|
||||
base::convert_to<std::string>(key->action()).c_str());
|
||||
case KeyContext::Selection:
|
||||
keycontextStr = "Selection";
|
||||
break;
|
||||
case KeyContext::MovingPixels:
|
||||
keycontextStr = "MovingPixels";
|
||||
break;
|
||||
}
|
||||
|
||||
elem.SetAttribute("shortcut", accel.toString().c_str());
|
||||
parent.InsertEndChild(elem);
|
||||
if (keycontextStr)
|
||||
elem.SetAttribute("context", keycontextStr);
|
||||
|
||||
if (key->params()) {
|
||||
for (const auto& param : *key->params()) {
|
||||
if (param.second.empty())
|
||||
continue;
|
||||
|
||||
TiXmlElement paramElem("param");
|
||||
paramElem.SetAttribute("name", param.first.c_str());
|
||||
paramElem.SetAttribute("value", param.second.c_str());
|
||||
elem.InsertEndChild(paramElem);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyType::Tool:
|
||||
case KeyType::Quicktool:
|
||||
elem.SetAttribute("tool", key->tool()->getId().c_str());
|
||||
break;
|
||||
|
||||
case KeyType::Action:
|
||||
elem.SetAttribute("action",
|
||||
base::convert_to<std::string>(key->action()).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
elem.SetAttribute("shortcut", accel.toString().c_str());
|
||||
|
||||
if (removed)
|
||||
elem.SetAttribute("removed", "true");
|
||||
|
||||
parent.InsertEndChild(elem);
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::reset()
|
||||
@ -531,10 +640,10 @@ Key* KeyboardShortcuts::action(KeyAction action)
|
||||
return key;
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel)
|
||||
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel, KeyContext keyContext)
|
||||
{
|
||||
for (Key* key : m_keys) {
|
||||
if (key->hasAccel(accel))
|
||||
if (key->keycontext() == keyContext && key->hasAccel(accel))
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ namespace app {
|
||||
Any,
|
||||
Normal,
|
||||
Selection,
|
||||
MovingPixels,
|
||||
};
|
||||
|
||||
enum class KeySource {
|
||||
@ -83,8 +84,7 @@ namespace app {
|
||||
}
|
||||
const ui::Accelerators& origAccels() const { return m_accels; }
|
||||
const ui::Accelerators& userAccels() const { return m_users; }
|
||||
|
||||
void setUserAccels(const ui::Accelerators& accels);
|
||||
const ui::Accelerators& userRemovedAccels() const { return m_userRemoved; }
|
||||
|
||||
void add(const ui::Accelerator& accel, KeySource source);
|
||||
bool isPressed(ui::Message* msg) const;
|
||||
@ -109,8 +109,9 @@ namespace app {
|
||||
|
||||
private:
|
||||
KeyType m_type;
|
||||
ui::Accelerators m_accels;
|
||||
ui::Accelerators m_users;
|
||||
ui::Accelerators m_accels; // Default accelerators (from gui.xml)
|
||||
ui::Accelerators m_users; // User-defined accelerators
|
||||
ui::Accelerators m_userRemoved; // Default accelerators removed by user
|
||||
bool m_useUsers;
|
||||
KeyContext m_keycontext;
|
||||
|
||||
@ -149,7 +150,7 @@ namespace app {
|
||||
Key* quicktool(tools::Tool* tool);
|
||||
Key* action(KeyAction action);
|
||||
|
||||
void disableAccel(const ui::Accelerator& accel);
|
||||
void disableAccel(const ui::Accelerator& accel, KeyContext keyContext);
|
||||
|
||||
KeyContext getCurrentKeyContext();
|
||||
bool getCommandFromKeyMessage(ui::Message* msg, Command** command, Params** params);
|
||||
@ -159,6 +160,7 @@ namespace app {
|
||||
KeyboardShortcuts();
|
||||
|
||||
void exportKeys(TiXmlElement& parent, KeyType type);
|
||||
void exportAccel(TiXmlElement& parent, Key* key, const ui::Accelerator& accel, bool removed);
|
||||
|
||||
Keys m_keys;
|
||||
|
||||
|
@ -63,6 +63,12 @@ protected:
|
||||
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);
|
||||
@ -84,8 +90,9 @@ protected:
|
||||
Accelerator m_accel;
|
||||
};
|
||||
|
||||
SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel)
|
||||
SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel, KeyContext keyContext)
|
||||
: m_keyField(new KeyField(accel))
|
||||
, m_keyContext(keyContext)
|
||||
, m_accel(accel)
|
||||
, m_modified(false)
|
||||
{
|
||||
@ -170,7 +177,8 @@ void SelectAccelerator::updateAssignedTo()
|
||||
std::string res = "None";
|
||||
|
||||
for (Key* key : *KeyboardShortcuts::instance()) {
|
||||
if (key->hasAccel(m_accel)) {
|
||||
if (key->keycontext() == m_keyContext &&
|
||||
key->hasAccel(m_accel)) {
|
||||
res = key->triggerString();
|
||||
break;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define APP_UI_SELECT_ACCELERATOR_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "ui/accelerator.h"
|
||||
|
||||
#include "generated_select_accelerator.h"
|
||||
@ -28,7 +29,7 @@ namespace app {
|
||||
|
||||
class SelectAccelerator : public app::gen::SelectAccelerator {
|
||||
public:
|
||||
explicit SelectAccelerator(const ui::Accelerator& accelerator);
|
||||
SelectAccelerator(const ui::Accelerator& accelerator, KeyContext keyContext);
|
||||
|
||||
bool isModified() const { return m_modified; }
|
||||
const ui::Accelerator& accel() const { return m_accel; }
|
||||
@ -45,6 +46,7 @@ namespace app {
|
||||
class KeyField;
|
||||
|
||||
KeyField* m_keyField;
|
||||
KeyContext m_keyContext;
|
||||
ui::Accelerator m_origAccel;
|
||||
ui::Accelerator m_accel;
|
||||
bool m_modified;
|
||||
|
@ -18,11 +18,16 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// #define REPORT_KEYS
|
||||
#define PREPROCESS_KEYS
|
||||
|
||||
namespace ui {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Accelerator
|
||||
|
||||
Accelerator::Accelerator()
|
||||
: m_modifiers(kKeyNoneModifier)
|
||||
, m_scancode(kKeyNil)
|
||||
@ -196,6 +201,8 @@ bool Accelerator::operator==(const Accelerator& other) const
|
||||
return true;
|
||||
else if (m_unicodeChar != 0)
|
||||
return (std::tolower(m_unicodeChar) == std::tolower(other.m_unicodeChar));
|
||||
else // Only comparing modifiers, and they are equal
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -344,11 +351,6 @@ std::string Accelerator::toString() const
|
||||
|
||||
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const
|
||||
{
|
||||
#ifdef REPORT_KEYS
|
||||
char buf[256];
|
||||
std::string buf2;
|
||||
#endif
|
||||
|
||||
// Preprocess the character to be compared with the accelerator
|
||||
#ifdef PREPROCESS_KEYS
|
||||
// Directly scancode
|
||||
@ -410,15 +412,18 @@ bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicod
|
||||
|
||||
if ((m_modifiers == modifiers) &&
|
||||
((m_scancode != kKeyNil && m_scancode == scancode) ||
|
||||
(m_unicodeChar && m_unicodeChar == unicodeChar))) {
|
||||
(m_unicodeChar && m_unicodeChar == unicodeChar) ||
|
||||
(m_scancode == kKeyNil && scancode == kKeyNil && !m_unicodeChar && !unicodeChar))) {
|
||||
#ifdef REPORT_KEYS
|
||||
printf("true\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef REPORT_KEYS
|
||||
printf("false\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@ -438,4 +443,25 @@ bool Accelerator::checkFromAllegroKeyArray() const
|
||||
(m_modifiers == modifiers));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Accelerators
|
||||
|
||||
bool Accelerators::has(const Accelerator& accel) const
|
||||
{
|
||||
return (std::find(begin(), end(), accel) != end());
|
||||
}
|
||||
|
||||
void Accelerators::add(const Accelerator& accel)
|
||||
{
|
||||
if (!has(accel))
|
||||
m_list.push_back(accel);
|
||||
}
|
||||
|
||||
void Accelerators::remove(const Accelerator& accel)
|
||||
{
|
||||
auto it = std::find(begin(), end(), accel);
|
||||
if (it != end())
|
||||
m_list.erase(it);
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
@ -43,7 +43,38 @@ namespace ui {
|
||||
int m_unicodeChar;
|
||||
};
|
||||
|
||||
typedef std::vector<Accelerator> Accelerators;
|
||||
class Accelerators {
|
||||
public:
|
||||
typedef std::vector<Accelerator> List;
|
||||
typedef List::iterator iterator;
|
||||
typedef List::const_iterator const_iterator;
|
||||
|
||||
iterator begin() { return m_list.begin(); }
|
||||
iterator end() { return m_list.end(); }
|
||||
const_iterator begin() const { return m_list.begin(); }
|
||||
const_iterator end() const { return m_list.end(); }
|
||||
|
||||
bool empty() const { return m_list.empty(); }
|
||||
size_t size() const { return m_list.size(); }
|
||||
|
||||
const ui::Accelerator& front() const { return m_list.front(); }
|
||||
|
||||
const ui::Accelerator& operator[](int index) const {
|
||||
return m_list[index];
|
||||
}
|
||||
|
||||
ui::Accelerator& 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);
|
||||
|
||||
private:
|
||||
List m_list;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user