mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-06 06:50:07 +00:00
Add option to simulate mouse wheel using key shortcut+drag mouse (fix #3195)
Now we can change several values (zoom, brush size, etc.) pressing a keyboard shortcuts and dragging the mouse in a specific vector direction (DragVector). It allows the modification of one, two, or even more parameters at the same time (e.g. X axis to change the brush size, Y axis the alpha value of the ink).
This commit is contained in:
parent
7e1d3832f0
commit
4ce2d1a340
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- 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 -->
|
||||||
<gui>
|
<gui>
|
||||||
<!-- Keyboard shortcuts -->
|
<!-- Keyboard shortcuts -->
|
||||||
@ -639,6 +639,10 @@
|
|||||||
<key action="RightMouseButton" />
|
<key action="RightMouseButton" />
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
|
<drag>
|
||||||
|
<key action="BrushSize" vector="4.0,0.0" shortcut="Ctrl+Alt" />
|
||||||
|
</drag>
|
||||||
|
|
||||||
</keyboard>
|
</keyboard>
|
||||||
|
|
||||||
<menus>
|
<menus>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Aseprite
|
# Aseprite
|
||||||
# Copyright (C) 2018-2021 Igara Studio S.A.
|
# Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
# Copyright (C) 2016-2018 David Capello
|
# Copyright (C) 2016-2018 David Capello
|
||||||
|
|
||||||
[advanced_mode]
|
[advanced_mode]
|
||||||
@ -846,9 +846,14 @@ section_commands = Commands
|
|||||||
section_tools = Tools
|
section_tools = Tools
|
||||||
section_action_modifiers = Action Modifiers
|
section_action_modifiers = Action Modifiers
|
||||||
section_mouse_wheel = Mouse Wheel
|
section_mouse_wheel = Mouse Wheel
|
||||||
|
section_drag_value = Drag Value
|
||||||
default_wheel_behavior = Default
|
default_wheel_behavior = Default
|
||||||
custom_wheel_behavior = Custom
|
custom_wheel_behavior = Custom
|
||||||
slide_as_wheel = Interpret two fingers slide on Trackpad as mouse wheel
|
slide_as_wheel = Interpret two fingers slide on Trackpad as mouse wheel
|
||||||
|
drag_angle = Angle:
|
||||||
|
drag_angle_tooltip = Direction of the mouse to indicate an increment of the value
|
||||||
|
drag_distance = Distance:
|
||||||
|
drag_distance_tooltip = Number of pixels for mouse movement to increment/decrement one unit
|
||||||
ok = &OK
|
ok = &OK
|
||||||
cancel = &Cancel
|
cancel = &Cancel
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!-- Aseprite -->
|
<!-- Aseprite -->
|
||||||
<!-- Copyright (C) 2018 Igara Studio S.A. -->
|
<!-- Copyright (C) 2018-2022 Igara Studio S.A. -->
|
||||||
<!-- Copyright (C) 2001-2016 David Capello -->
|
<!-- Copyright (C) 2001-2016 David Capello -->
|
||||||
<gui>
|
<gui>
|
||||||
<window id="keyboard_shortcuts" text="@keyboard_shortcuts.title">
|
<window id="keyboard_shortcuts" text="@keyboard_shortcuts.title">
|
||||||
@ -15,6 +15,7 @@
|
|||||||
<listitem text="@.section_tools" />
|
<listitem text="@.section_tools" />
|
||||||
<listitem text="@.section_action_modifiers" />
|
<listitem text="@.section_action_modifiers" />
|
||||||
<listitem text="@.section_mouse_wheel" />
|
<listitem text="@.section_mouse_wheel" />
|
||||||
|
<listitem text="@.section_drag_value" />
|
||||||
</listbox>
|
</listbox>
|
||||||
</view>
|
</view>
|
||||||
<separator horizontal="true" />
|
<separator horizontal="true" />
|
||||||
@ -53,6 +54,52 @@
|
|||||||
<listbox id="wheel_actions" />
|
<listbox id="wheel_actions" />
|
||||||
</view>
|
</view>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
<vbox id="drag_section" expansive="true">
|
||||||
|
<view expansive="true">
|
||||||
|
<listbox id="drag_actions" />
|
||||||
|
</view>
|
||||||
|
<separator horizontal="true" />
|
||||||
|
<hbox>
|
||||||
|
<vbox>
|
||||||
|
<label text="@.drag_angle" />
|
||||||
|
</vbox>
|
||||||
|
<buttonset columns="3" id="drag_angle">
|
||||||
|
<item icon="canvas_nw"
|
||||||
|
tooltip="@.drag_angle_tooltip"
|
||||||
|
tooltip_dir="bottom" />
|
||||||
|
<item icon="canvas_n"
|
||||||
|
tooltip="@.drag_angle_tooltip"
|
||||||
|
tooltip_dir="bottom" />
|
||||||
|
<item icon="canvas_ne"
|
||||||
|
tooltip="@.drag_angle_tooltip"
|
||||||
|
tooltip_dir="bottom" />
|
||||||
|
<item icon="canvas_w"
|
||||||
|
tooltip="@.drag_angle_tooltip"
|
||||||
|
tooltip_dir="right" />
|
||||||
|
<item />
|
||||||
|
<item icon="canvas_e"
|
||||||
|
tooltip="@.drag_angle_tooltip"
|
||||||
|
tooltip_dir="left" />
|
||||||
|
<item icon="canvas_sw"
|
||||||
|
tooltip="@.drag_angle_tooltip"
|
||||||
|
tooltip_dir="top" />
|
||||||
|
<item icon="canvas_s"
|
||||||
|
tooltip="@.drag_angle_tooltip"
|
||||||
|
tooltip_dir="top" />
|
||||||
|
<item icon="canvas_se"
|
||||||
|
tooltip="@.drag_angle_tooltip"
|
||||||
|
tooltip_dir="top" />
|
||||||
|
</buttonset>
|
||||||
|
<vbox>
|
||||||
|
<label text="@.drag_distance" />
|
||||||
|
</vbox>
|
||||||
|
<vbox>
|
||||||
|
<slider min="1" max="100" id="drag_distance" cell_align="horizontal" width="128"
|
||||||
|
tooltip="@.drag_distance_tooltip"
|
||||||
|
tooltip_dir="bottom" />
|
||||||
|
</vbox>
|
||||||
|
</hbox>
|
||||||
|
</vbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
</splitter>
|
</splitter>
|
||||||
<hbox>
|
<hbox>
|
||||||
|
@ -343,6 +343,7 @@ if(ENABLE_UI)
|
|||||||
ui/dynamics_popup.cpp
|
ui/dynamics_popup.cpp
|
||||||
ui/editor/brush_preview.cpp
|
ui/editor/brush_preview.cpp
|
||||||
ui/editor/delayed_mouse_move.cpp
|
ui/editor/delayed_mouse_move.cpp
|
||||||
|
ui/editor/dragging_value_state.cpp
|
||||||
ui/editor/drawing_state.cpp
|
ui/editor/drawing_state.cpp
|
||||||
ui/editor/editor.cpp
|
ui/editor/editor.cpp
|
||||||
ui/editor/editor_observers.cpp
|
ui/editor/editor_observers.cpp
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "app/ui/separator_in_view.h"
|
#include "app/ui/separator_in_view.h"
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
#include "base/fs.h"
|
#include "base/fs.h"
|
||||||
|
#include "base/pi.h"
|
||||||
#include "base/scoped_value.h"
|
#include "base/scoped_value.h"
|
||||||
#include "base/split_string.h"
|
#include "base/split_string.h"
|
||||||
#include "base/string.h"
|
#include "base/string.h"
|
||||||
@ -506,14 +507,19 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
|
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
|
||||||
|
// TODO Merge with CanvasSizeWindow::Dir
|
||||||
|
enum class Dir { NW, N, NE, W, C, E, SW, S, SE };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KeyboardShortcutsWindow(app::KeyboardShortcuts& keys,
|
KeyboardShortcutsWindow(app::KeyboardShortcuts& keys,
|
||||||
MenuKeys& menuKeys,
|
MenuKeys& menuKeys,
|
||||||
const std::string& searchText)
|
const std::string& searchText,
|
||||||
|
int& curSection)
|
||||||
: m_keys(keys)
|
: m_keys(keys)
|
||||||
, m_menuKeys(menuKeys)
|
, m_menuKeys(menuKeys)
|
||||||
, m_searchChange(false)
|
, m_searchChange(false)
|
||||||
, m_wasDefault(false) {
|
, m_wasDefault(false)
|
||||||
|
, m_curSection(curSection) {
|
||||||
setAutoRemap(false);
|
setAutoRemap(false);
|
||||||
|
|
||||||
m_listBoxes.push_back(menus());
|
m_listBoxes.push_back(menus());
|
||||||
@ -521,6 +527,7 @@ public:
|
|||||||
m_listBoxes.push_back(tools());
|
m_listBoxes.push_back(tools());
|
||||||
m_listBoxes.push_back(actions());
|
m_listBoxes.push_back(actions());
|
||||||
m_listBoxes.push_back(wheelActions());
|
m_listBoxes.push_back(wheelActions());
|
||||||
|
m_listBoxes.push_back(dragActions());
|
||||||
|
|
||||||
#ifdef __APPLE__ // Zoom sliding two fingers option only on macOS
|
#ifdef __APPLE__ // Zoom sliding two fingers option only on macOS
|
||||||
slideZoom()->setVisible(true);
|
slideZoom()->setVisible(true);
|
||||||
@ -544,6 +551,9 @@ public:
|
|||||||
|
|
||||||
search()->Change.connect([this]{ onSearchChange(); });
|
search()->Change.connect([this]{ onSearchChange(); });
|
||||||
section()->Change.connect([this]{ onSectionChange(); });
|
section()->Change.connect([this]{ onSectionChange(); });
|
||||||
|
dragActions()->Change.connect([this]{ onDragActionsChange(); });
|
||||||
|
dragAngle()->ItemChange.connect([this]{ onDragVectorChange(); });
|
||||||
|
dragDistance()->Change.connect([this]{ onDragVectorChange(); });
|
||||||
importButton()->Click.connect([this]{ onImport(); });
|
importButton()->Click.connect([this]{ onImport(); });
|
||||||
exportButton()->Click.connect([this]{ onExport(); });
|
exportButton()->Click.connect([this]{ onExport(); });
|
||||||
resetButton()->Click.connect([this]{ onReset(); });
|
resetButton()->Click.connect([this]{ onReset(); });
|
||||||
@ -573,6 +583,7 @@ private:
|
|||||||
deleteList(tools());
|
deleteList(tools());
|
||||||
deleteList(actions());
|
deleteList(actions());
|
||||||
deleteList(wheelActions());
|
deleteList(wheelActions());
|
||||||
|
deleteList(dragActions());
|
||||||
}
|
}
|
||||||
|
|
||||||
void fillAllLists() {
|
void fillAllLists() {
|
||||||
@ -592,11 +603,13 @@ private:
|
|||||||
|
|
||||||
fillToolsList(tools(), App::instance()->toolBox());
|
fillToolsList(tools(), App::instance()->toolBox());
|
||||||
fillWheelActionsList();
|
fillWheelActionsList();
|
||||||
|
fillDragActionsList();
|
||||||
|
|
||||||
for (const KeyPtr& key : m_keys) {
|
for (const KeyPtr& key : m_keys) {
|
||||||
if (key->type() == KeyType::Tool ||
|
if (key->type() == KeyType::Tool ||
|
||||||
key->type() == KeyType::Quicktool ||
|
key->type() == KeyType::Quicktool ||
|
||||||
key->type() == KeyType::WheelAction) {
|
key->type() == KeyType::WheelAction ||
|
||||||
|
key->type() == KeyType::DragAction) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,7 +649,7 @@ private:
|
|||||||
tools()->sortItems();
|
tools()->sortItems();
|
||||||
actions()->sortItems();
|
actions()->sortItems();
|
||||||
|
|
||||||
section()->selectIndex(0);
|
section()->selectIndex(m_curSection);
|
||||||
updateViews();
|
updateViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,6 +743,19 @@ private:
|
|||||||
wheelActions()->sortItems();
|
wheelActions()->sortItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fillDragActionsList() {
|
||||||
|
deleteList(dragActions());
|
||||||
|
for (const KeyPtr& key : m_keys) {
|
||||||
|
if (key->type() == KeyType::DragAction) {
|
||||||
|
KeyItem* keyItem = new KeyItem(
|
||||||
|
m_keys, m_menuKeys, key->triggerString(), key,
|
||||||
|
nullptr, 0, &m_headerItem);
|
||||||
|
dragActions()->addChild(keyItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dragActions()->sortItems();
|
||||||
|
}
|
||||||
|
|
||||||
void onWheelZoomChange() {
|
void onWheelZoomChange() {
|
||||||
const bool isDefault = isDefaultWheelBehavior();
|
const bool isDefault = isDefaultWheelBehavior();
|
||||||
if (isDefault)
|
if (isDefault)
|
||||||
@ -741,7 +767,7 @@ private:
|
|||||||
std::string searchText = search()->text();
|
std::string searchText = search()->text();
|
||||||
|
|
||||||
if (searchText.empty())
|
if (searchText.empty())
|
||||||
section()->selectIndex(0);
|
section()->selectIndex(m_curSection);
|
||||||
else {
|
else {
|
||||||
fillSearchList(searchText);
|
fillSearchList(searchText);
|
||||||
section()->selectChild(nullptr);
|
section()->selectChild(nullptr);
|
||||||
@ -758,14 +784,48 @@ private:
|
|||||||
updateViews();
|
updateViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onDragActionsChange() {
|
||||||
|
auto key = selectedDragActionKey();
|
||||||
|
if (!key)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int angle = 180 * key->dragVector().angle() / PI;
|
||||||
|
|
||||||
|
ui::Widget* oldFocus = manager()->getFocus();
|
||||||
|
dragAngle()->setSelectedItem((int)angleToDir(angle));
|
||||||
|
if (oldFocus)
|
||||||
|
oldFocus->requestFocus();
|
||||||
|
|
||||||
|
dragDistance()->setValue(key->dragVector().magnitude());
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDragVectorChange() {
|
||||||
|
auto key = selectedDragActionKey();
|
||||||
|
if (!key)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto v = key->dragVector();
|
||||||
|
double a = dirToAngle((Dir)dragAngle()->selectedItem()).angle();
|
||||||
|
double m = dragDistance()->getValue();
|
||||||
|
v.x = m * std::cos(a);
|
||||||
|
v.y = m * std::sin(a);
|
||||||
|
if (std::fabs(v.x) < 0.00001) v.x = 0.0;
|
||||||
|
if (std::fabs(v.y) < 0.00001) v.y = 0.0;
|
||||||
|
key->setDragVector(v);
|
||||||
|
}
|
||||||
|
|
||||||
void updateViews() {
|
void updateViews() {
|
||||||
int s = section()->getSelectedIndex();
|
int s = section()->getSelectedIndex();
|
||||||
|
if (s >= 0)
|
||||||
|
m_curSection = s;
|
||||||
|
|
||||||
searchView()->setVisible(s < 0);
|
searchView()->setVisible(s < 0);
|
||||||
menusView()->setVisible(s == 0);
|
menusView()->setVisible(s == 0);
|
||||||
commandsView()->setVisible(s == 1);
|
commandsView()->setVisible(s == 1);
|
||||||
toolsView()->setVisible(s == 2);
|
toolsView()->setVisible(s == 2);
|
||||||
actionsView()->setVisible(s == 3);
|
actionsView()->setVisible(s == 3);
|
||||||
wheelSection()->setVisible(s == 4);
|
wheelSection()->setVisible(s == 4);
|
||||||
|
dragSection()->setVisible(s == 5);
|
||||||
|
|
||||||
if (m_headerItem.parent())
|
if (m_headerItem.parent())
|
||||||
m_headerItem.parent()->removeChild(&m_headerItem);
|
m_headerItem.parent()->removeChild(&m_headerItem);
|
||||||
@ -868,12 +928,51 @@ private:
|
|||||||
return app::gen::KeyboardShortcuts::onProcessMessage(msg);
|
return app::gen::KeyboardShortcuts::onProcessMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyPtr selectedDragActionKey() {
|
||||||
|
auto item = dragActions()->getSelectedChild();
|
||||||
|
if (KeyItem* keyItem = dynamic_cast<KeyItem*>(item)) {
|
||||||
|
KeyPtr key = keyItem->key();
|
||||||
|
if (key && key->type() == KeyType::DragAction)
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dir angleToDir(int angle) {
|
||||||
|
if (angle >= -1*45/2 && angle < 1*45/2) return Dir::E;
|
||||||
|
if (angle >= 1*45/2 && angle < 3*45/2) return Dir::NE;
|
||||||
|
if (angle >= 3*45/2 && angle < 5*45/2) return Dir::N;
|
||||||
|
if (angle >= 5*45/2 && angle < 7*45/2) return Dir::NW;
|
||||||
|
if ((angle >= 7*45/2 && angle <= 180) ||
|
||||||
|
(angle >= -180 && angle <= -7*45/2)) return Dir::W;
|
||||||
|
if (angle > -7*45/2 && angle <= -5*45/2) return Dir::SW;
|
||||||
|
if (angle > -5*45/2 && angle <= -3*45/2) return Dir::S;
|
||||||
|
if (angle > -3*45/2 && angle <= -1*45/2) return Dir::SE;
|
||||||
|
return Dir::C;
|
||||||
|
}
|
||||||
|
|
||||||
|
DragVector dirToAngle(Dir dir) {
|
||||||
|
switch (dir) {
|
||||||
|
case Dir::NW: return DragVector(-1, +1);
|
||||||
|
case Dir::N: return DragVector( 0, +1);
|
||||||
|
case Dir::NE: return DragVector(+1, +1);
|
||||||
|
case Dir::W: return DragVector(-1, 0);
|
||||||
|
case Dir::C: return DragVector( 0, 0);
|
||||||
|
case Dir::E: return DragVector(+1, 0);
|
||||||
|
case Dir::SW: return DragVector(-1, -1);
|
||||||
|
case Dir::S: return DragVector( 0, -1);
|
||||||
|
case Dir::SE: return DragVector(+1, -1);
|
||||||
|
}
|
||||||
|
return DragVector();
|
||||||
|
}
|
||||||
|
|
||||||
app::KeyboardShortcuts& m_keys;
|
app::KeyboardShortcuts& m_keys;
|
||||||
MenuKeys& m_menuKeys;
|
MenuKeys& m_menuKeys;
|
||||||
std::vector<ListBox*> m_listBoxes;
|
std::vector<ListBox*> m_listBoxes;
|
||||||
bool m_searchChange;
|
bool m_searchChange;
|
||||||
bool m_wasDefault;
|
bool m_wasDefault;
|
||||||
HeaderItem m_headerItem;
|
HeaderItem m_headerItem;
|
||||||
|
int& m_curSection;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@ -905,6 +1004,8 @@ void KeyboardShortcutsCommand::onLoadParams(const Params& params)
|
|||||||
|
|
||||||
void KeyboardShortcutsCommand::onExecute(Context* context)
|
void KeyboardShortcutsCommand::onExecute(Context* context)
|
||||||
{
|
{
|
||||||
|
static int curSection = 0;
|
||||||
|
|
||||||
app::KeyboardShortcuts* globalKeys = app::KeyboardShortcuts::instance();
|
app::KeyboardShortcuts* globalKeys = app::KeyboardShortcuts::instance();
|
||||||
app::KeyboardShortcuts keys;
|
app::KeyboardShortcuts keys;
|
||||||
keys.setKeys(*globalKeys, true);
|
keys.setKeys(*globalKeys, true);
|
||||||
@ -919,7 +1020,7 @@ void KeyboardShortcutsCommand::onExecute(Context* context)
|
|||||||
// KeyboardShortcutsCommand instance (so m_search will be "")
|
// KeyboardShortcutsCommand instance (so m_search will be "")
|
||||||
// TODO Seeing this, we need a complete new way to handle UI commands execution
|
// TODO Seeing this, we need a complete new way to handle UI commands execution
|
||||||
std::string neededSearchCopy = m_search;
|
std::string neededSearchCopy = m_search;
|
||||||
KeyboardShortcutsWindow window(keys, menuKeys, neededSearchCopy);
|
KeyboardShortcutsWindow window(keys, menuKeys, neededSearchCopy, curSection);
|
||||||
|
|
||||||
ui::Display* mainDisplay = Manager::getDefault()->display();
|
ui::Display* mainDisplay = Manager::getDefault()->display();
|
||||||
ui::fit_bounds(mainDisplay, &window,
|
ui::fit_bounds(mainDisplay, &window,
|
||||||
|
144
src/app/ui/editor/dragging_value_state.cpp
Normal file
144
src/app/ui/editor/dragging_value_state.cpp
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
// 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/ui/editor/dragging_value_state.h"
|
||||||
|
|
||||||
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "base/clamp.h"
|
||||||
|
#include "ui/display.h"
|
||||||
|
#include "ui/message.h"
|
||||||
|
#include "ui/scale.h"
|
||||||
|
#include "ui/system.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
using namespace ui;
|
||||||
|
|
||||||
|
DraggingValueState::DraggingValueState(Editor* editor, const Keys& keys)
|
||||||
|
: m_keys(keys)
|
||||||
|
, m_initialPos(editor->display()->nativeWindow()->pointFromScreen(ui::get_mouse_position()))
|
||||||
|
, m_initialFgColor(StateWithWheelBehavior::initialFgColor())
|
||||||
|
, m_initialBgColor(StateWithWheelBehavior::initialBgColor())
|
||||||
|
, m_initialFgTileIndex(StateWithWheelBehavior::initialFgTileIndex())
|
||||||
|
, m_initialBgTileIndex(StateWithWheelBehavior::initialBgTileIndex())
|
||||||
|
, m_initialBrushSize(StateWithWheelBehavior::initialBrushSize())
|
||||||
|
, m_initialBrushAngle(StateWithWheelBehavior::initialBrushAngle())
|
||||||
|
, m_initialScroll(StateWithWheelBehavior::initialScroll(editor))
|
||||||
|
, m_initialZoom(StateWithWheelBehavior::initialZoom(editor))
|
||||||
|
, m_initialFrame(StateWithWheelBehavior::initialFrame(editor))
|
||||||
|
, m_initialInkOpacity(StateWithWheelBehavior::initialInkOpacity(editor))
|
||||||
|
, m_initialCelOpacity(StateWithWheelBehavior::initialCelOpacity(editor))
|
||||||
|
, m_initialLayerOpacity(StateWithWheelBehavior::initialLayerOpacity(editor))
|
||||||
|
, m_initialTool(StateWithWheelBehavior::initialTool())
|
||||||
|
{
|
||||||
|
if (!editor->hasCapture())
|
||||||
|
editor->captureMouse();
|
||||||
|
|
||||||
|
// As StateWithWheelBehavior::initialLayer() fills browsableLayers()
|
||||||
|
// we will only fill it if it's necessary (there is a key that
|
||||||
|
// triggers WheelAction::Layer)
|
||||||
|
for (const KeyPtr& key : m_keys) {
|
||||||
|
if (key->wheelAction() == WheelAction::Layer) {
|
||||||
|
m_initialLayer = StateWithWheelBehavior::initialLayer(editor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DraggingValueState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DraggingValueState::onMouseUp(Editor* editor, MouseMessage* msg)
|
||||||
|
{
|
||||||
|
editor->backToPreviousState();
|
||||||
|
editor->releaseMouse();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DraggingValueState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||||
|
{
|
||||||
|
m_fgColor = m_initialFgColor;
|
||||||
|
|
||||||
|
for (const KeyPtr& key : m_keys) {
|
||||||
|
const gfx::Point delta = (msg->position() - m_initialPos);
|
||||||
|
const DragVector deltaV(delta.x, delta.y);
|
||||||
|
const DragVector invDragVector(key->dragVector().x,
|
||||||
|
-key->dragVector().y);
|
||||||
|
const double threshold = invDragVector.magnitude();
|
||||||
|
|
||||||
|
DragVector v = deltaV.projectOn(invDragVector);
|
||||||
|
double dz = v.magnitude();
|
||||||
|
{
|
||||||
|
if (threshold > 0)
|
||||||
|
dz /= threshold;
|
||||||
|
auto dot = invDragVector * v;
|
||||||
|
dz *= SGN(dot);
|
||||||
|
|
||||||
|
bool preciseWheel = true;
|
||||||
|
if (key->wheelAction() == WheelAction::Zoom ||
|
||||||
|
key->wheelAction() == WheelAction::Frame ||
|
||||||
|
key->wheelAction() == WheelAction::Layer) {
|
||||||
|
preciseWheel = false;
|
||||||
|
dz = -dz; // Invert value for zoom only so the vector is
|
||||||
|
// pointing to the direction to increase zoom
|
||||||
|
|
||||||
|
// TODO we should change the direction of the wheel
|
||||||
|
// information from the laf layer
|
||||||
|
}
|
||||||
|
|
||||||
|
processWheelAction(editor,
|
||||||
|
key->wheelAction(),
|
||||||
|
msg->position(),
|
||||||
|
delta,
|
||||||
|
dz,
|
||||||
|
false, // scrollBigSteps=false
|
||||||
|
preciseWheel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_fgColor != m_initialFgColor)
|
||||||
|
StateWithWheelBehavior::changeFgColor(m_fgColor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DraggingValueState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||||
|
{
|
||||||
|
return StateWithWheelBehavior::onSetCursor(editor, mouseScreenPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DraggingValueState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DraggingValueState::onKeyUp(Editor* editor, KeyMessage* msg)
|
||||||
|
{
|
||||||
|
if (editor->hasCapture())
|
||||||
|
editor->releaseMouse();
|
||||||
|
editor->backToPreviousState();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DraggingValueState::onUpdateStatusBar(Editor* editor)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DraggingValueState::changeFgColor(Color c)
|
||||||
|
{
|
||||||
|
m_fgColor = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
77
src/app/ui/editor/dragging_value_state.h
Normal file
77
src/app/ui/editor/dragging_value_state.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2022 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_UI_EDITOR_DRAGGING_VALUE_STATE_H_INCLUDED
|
||||||
|
#define APP_UI_EDITOR_DRAGGING_VALUE_STATE_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "app/ui/editor/state_with_wheel_behavior.h"
|
||||||
|
#include "app/ui/key.h"
|
||||||
|
#include "gfx/point.h"
|
||||||
|
#include "render/zoom.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class DraggingValueState : public StateWithWheelBehavior {
|
||||||
|
public:
|
||||||
|
DraggingValueState(Editor* editor, const Keys& keys);
|
||||||
|
|
||||||
|
bool isTemporalState() const override { return true; }
|
||||||
|
bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||||
|
bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||||
|
bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||||
|
bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||||
|
bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||||
|
bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||||
|
bool onUpdateStatusBar(Editor* editor) override;
|
||||||
|
|
||||||
|
bool requireBrushPreview() override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Color initialFgColor() const override { return m_fgColor; }
|
||||||
|
Color initialBgColor() const override { return m_initialBgColor; }
|
||||||
|
int initialFgTileIndex() const override { return m_initialFgTileIndex; }
|
||||||
|
int initialBgTileIndex() const override { return m_initialBgTileIndex; }
|
||||||
|
int initialBrushSize() override { return m_initialBrushSize; }
|
||||||
|
int initialBrushAngle() override { return m_initialBrushAngle; }
|
||||||
|
gfx::Point initialScroll(Editor* editor) const override { return m_initialScroll; }
|
||||||
|
render::Zoom initialZoom(Editor* editor) const override { return m_initialZoom; }
|
||||||
|
doc::frame_t initialFrame(Editor* editor) const override { return m_initialFrame; }
|
||||||
|
doc::layer_t initialLayer(Editor* editor) const override { return m_initialLayer; }
|
||||||
|
int initialInkOpacity(Editor* editor) const override { return m_initialInkOpacity; }
|
||||||
|
int initialCelOpacity(Editor* editor) const override { return m_initialCelOpacity; }
|
||||||
|
int initialLayerOpacity(Editor* editor) const override { return m_initialLayerOpacity; }
|
||||||
|
tools::Tool* initialTool() const override { return m_initialTool; }
|
||||||
|
void changeFgColor(Color c) override;
|
||||||
|
|
||||||
|
Keys m_keys;
|
||||||
|
gfx::Point m_initialPos;
|
||||||
|
|
||||||
|
Color m_initialFgColor;
|
||||||
|
Color m_initialBgColor;
|
||||||
|
int m_initialFgTileIndex;
|
||||||
|
int m_initialBgTileIndex;
|
||||||
|
int m_initialBrushSize;
|
||||||
|
int m_initialBrushAngle;
|
||||||
|
gfx::Point m_initialScroll;
|
||||||
|
render::Zoom m_initialZoom;
|
||||||
|
doc::frame_t m_initialFrame;
|
||||||
|
doc::layer_t m_initialLayer;
|
||||||
|
int m_initialInkOpacity;
|
||||||
|
int m_initialCelOpacity;
|
||||||
|
int m_initialLayerOpacity;
|
||||||
|
tools::Tool* m_initialTool;
|
||||||
|
|
||||||
|
// Used to allow multiple modifications to the same initial FG
|
||||||
|
// color (m_initialFgColor), e.g. when multiples Key will change
|
||||||
|
// different elements of the color (e.g. Value and Saturation) at
|
||||||
|
// the same time with different DragVectors/axes.
|
||||||
|
Color m_fgColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif // APP_UI_EDITOR_ZOOMING_STATE_H_INCLUDED
|
@ -27,6 +27,7 @@
|
|||||||
#include "app/tools/tool.h"
|
#include "app/tools/tool.h"
|
||||||
#include "app/ui/app_menuitem.h"
|
#include "app/ui/app_menuitem.h"
|
||||||
#include "app/ui/doc_view.h"
|
#include "app/ui/doc_view.h"
|
||||||
|
#include "app/ui/editor/dragging_value_state.h"
|
||||||
#include "app/ui/editor/drawing_state.h"
|
#include "app/ui/editor/drawing_state.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
#include "app/ui/editor/editor_customization_delegate.h"
|
#include "app/ui/editor/editor_customization_delegate.h"
|
||||||
@ -435,20 +436,6 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
|||||||
editor->showBrushPreview(mouseScreenPos);
|
editor->showBrushPreview(mouseScreenPos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (ink->isEyedropper()) {
|
|
||||||
editor->showMouseCursor(
|
|
||||||
kCustomCursor, theme->cursors.eyedropper());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ink->isZoom()) {
|
|
||||||
editor->showMouseCursor(
|
|
||||||
kCustomCursor, theme->cursors.magnifier());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ink->isScrollMovement()) {
|
|
||||||
editor->showMouseCursor(kScrollCursor);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ink->isCelMovement()) {
|
else if (ink->isCelMovement()) {
|
||||||
if (resizeCelBounds(editor).contains(mouseScreenPos))
|
if (resizeCelBounds(editor).contains(mouseScreenPos))
|
||||||
editor->showMouseCursor(kSizeSECursor);
|
editor->showMouseCursor(kSizeSECursor);
|
||||||
@ -498,16 +485,7 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw
|
return StateWithWheelBehavior::onSetCursor(editor, mouseScreenPos);
|
||||||
if (editor->canDraw()) {
|
|
||||||
editor->showBrushPreview(mouseScreenPos);
|
|
||||||
}
|
|
||||||
// Forbidden
|
|
||||||
else {
|
|
||||||
editor->showMouseCursor(kForbiddenCursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
|
bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||||
@ -515,6 +493,15 @@ bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
|
|||||||
if (Preferences::instance().editor.straightLinePreview() &&
|
if (Preferences::instance().editor.straightLinePreview() &&
|
||||||
checkStartDrawingStraightLine(editor, nullptr, nullptr))
|
checkStartDrawingStraightLine(editor, nullptr, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
Keys keys = KeyboardShortcuts::instance()
|
||||||
|
->getDragActionsFromKeyMessage(KeyContext::MouseWheel, msg);
|
||||||
|
if (!keys.empty()) {
|
||||||
|
EditorStatePtr newState(new DraggingValueState(editor, keys));
|
||||||
|
editor->setState(newState);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -33,10 +33,41 @@
|
|||||||
#include "ui/system.h"
|
#include "ui/system.h"
|
||||||
#include "ui/theme.h"
|
#include "ui/theme.h"
|
||||||
|
|
||||||
|
#include "app/tools/ink.h"
|
||||||
|
#include "app/ui/skin/skin_theme.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
using namespace ui;
|
using namespace ui;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline void adjust_value(bool preciseWheel, double dz, T& v, T min, T max)
|
||||||
|
{
|
||||||
|
if (preciseWheel)
|
||||||
|
v = base::clamp<T>(T(v+dz), min, max);
|
||||||
|
else
|
||||||
|
v = base::clamp<T>(T(v+dz*max/T(10)), min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline void adjust_hue(bool preciseWheel, double dz, T& v, T min, T max)
|
||||||
|
{
|
||||||
|
if (preciseWheel)
|
||||||
|
v = base::clamp<T>(T(v+dz), min, max);
|
||||||
|
else
|
||||||
|
v = base::clamp<T>(T(v+dz*T(10)), min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void adjust_unit(bool preciseWheel, double dz, double& v)
|
||||||
|
{
|
||||||
|
v = base::clamp<double>(v+(preciseWheel ? dz/100.0: dz/25.0), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
StateWithWheelBehavior::StateWithWheelBehavior()
|
||||||
|
: m_groupTool(initialTool())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||||
{
|
{
|
||||||
gfx::Point delta = msg->wheelDelta();
|
gfx::Point delta = msg->wheelDelta();
|
||||||
@ -109,6 +140,25 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processWheelAction(editor,
|
||||||
|
wheelAction,
|
||||||
|
msg->position(),
|
||||||
|
delta,
|
||||||
|
dz,
|
||||||
|
scrollBigSteps,
|
||||||
|
msg->preciseWheel());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateWithWheelBehavior::processWheelAction(
|
||||||
|
Editor* editor,
|
||||||
|
WheelAction wheelAction,
|
||||||
|
const gfx::Point& position,
|
||||||
|
gfx::Point delta,
|
||||||
|
double dz,
|
||||||
|
bool scrollBigSteps,
|
||||||
|
bool preciseWheel)
|
||||||
|
{
|
||||||
switch (wheelAction) {
|
switch (wheelAction) {
|
||||||
|
|
||||||
case WheelAction::None:
|
case WheelAction::None:
|
||||||
@ -117,15 +167,15 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
|
|
||||||
case WheelAction::FgColor: {
|
case WheelAction::FgColor: {
|
||||||
int lastIndex = get_current_palette()->size()-1;
|
int lastIndex = get_current_palette()->size()-1;
|
||||||
int newIndex = ColorBar::instance()->getFgColor().getIndex() + int(dz);
|
int newIndex = initialFgColor().getIndex() + int(dz);
|
||||||
newIndex = base::clamp(newIndex, 0, lastIndex);
|
newIndex = base::clamp(newIndex, 0, lastIndex);
|
||||||
ColorBar::instance()->setFgColor(app::Color::fromIndex(newIndex));
|
changeFgColor(app::Color::fromIndex(newIndex));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WheelAction::BgColor: {
|
case WheelAction::BgColor: {
|
||||||
int lastIndex = get_current_palette()->size()-1;
|
int lastIndex = get_current_palette()->size()-1;
|
||||||
int newIndex = ColorBar::instance()->getBgColor().getIndex() + int(dz);
|
int newIndex = initialBgColor().getIndex() + int(dz);
|
||||||
newIndex = base::clamp(newIndex, 0, lastIndex);
|
newIndex = base::clamp(newIndex, 0, lastIndex);
|
||||||
ColorBar::instance()->setBgColor(app::Color::fromIndex(newIndex));
|
ColorBar::instance()->setBgColor(app::Color::fromIndex(newIndex));
|
||||||
break;
|
break;
|
||||||
@ -134,7 +184,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
case WheelAction::FgTile: {
|
case WheelAction::FgTile: {
|
||||||
auto tilesView = ColorBar::instance()->getTilesView();
|
auto tilesView = ColorBar::instance()->getTilesView();
|
||||||
int lastIndex = tilesView->tileset()->size()-1;
|
int lastIndex = tilesView->tileset()->size()-1;
|
||||||
int newIndex = ColorBar::instance()->getFgTile() + int(dz);
|
int newIndex = initialFgTileIndex() + int(dz);
|
||||||
newIndex = base::clamp(newIndex, 0, lastIndex);
|
newIndex = base::clamp(newIndex, 0, lastIndex);
|
||||||
ColorBar::instance()->setFgTile(newIndex);
|
ColorBar::instance()->setFgTile(newIndex);
|
||||||
break;
|
break;
|
||||||
@ -143,29 +193,39 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
case WheelAction::BgTile: {
|
case WheelAction::BgTile: {
|
||||||
auto tilesView = ColorBar::instance()->getTilesView();
|
auto tilesView = ColorBar::instance()->getTilesView();
|
||||||
int lastIndex = tilesView->tileset()->size()-1;
|
int lastIndex = tilesView->tileset()->size()-1;
|
||||||
int newIndex = ColorBar::instance()->getBgTile() + int(dz);
|
int newIndex = initialBgTileIndex() + int(dz);
|
||||||
newIndex = base::clamp(newIndex, 0, lastIndex);
|
newIndex = base::clamp(newIndex, 0, lastIndex);
|
||||||
ColorBar::instance()->setBgTile(newIndex);
|
ColorBar::instance()->setBgTile(newIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WheelAction::Frame: {
|
case WheelAction::Frame: {
|
||||||
Command* command = nullptr;
|
frame_t deltaFrame = 0;
|
||||||
|
if (preciseWheel) {
|
||||||
|
if (dz < 0.0)
|
||||||
|
deltaFrame = +1;
|
||||||
|
else if (dz > 0.0)
|
||||||
|
deltaFrame = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
deltaFrame = -dz;
|
||||||
|
}
|
||||||
|
|
||||||
if (dz < 0.0)
|
frame_t frame = initialFrame(editor) + deltaFrame;
|
||||||
command = Commands::instance()->byId(CommandId::GotoNextFrame());
|
frame_t nframes = editor->sprite()->totalFrames();
|
||||||
else if (dz > 0.0)
|
while (frame < 0)
|
||||||
command = Commands::instance()->byId(CommandId::GotoPreviousFrame());
|
frame += nframes;
|
||||||
|
while (frame >= nframes)
|
||||||
|
frame -= nframes;
|
||||||
|
|
||||||
if (command)
|
editor->setFrame(frame);
|
||||||
UIContext::instance()->executeCommand(command);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WheelAction::Zoom: {
|
case WheelAction::Zoom: {
|
||||||
render::Zoom zoom = editor->zoom();
|
render::Zoom zoom = initialZoom(editor);
|
||||||
|
|
||||||
if (msg->preciseWheel()) {
|
if (preciseWheel) {
|
||||||
dz /= 1.5;
|
dz /= 1.5;
|
||||||
if (dz < -1.0) dz = -1.0;
|
if (dz < -1.0) dz = -1.0;
|
||||||
else if (dz > 1.0) dz = 1.0;
|
else if (dz > 1.0) dz = 1.0;
|
||||||
@ -173,16 +233,16 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
|
|
||||||
zoom = render::Zoom::fromLinearScale(zoom.linearScale() - int(dz));
|
zoom = render::Zoom::fromLinearScale(zoom.linearScale() - int(dz));
|
||||||
|
|
||||||
setZoom(editor, zoom, msg->position());
|
setZoom(editor, zoom, position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WheelAction::HScroll:
|
case WheelAction::HScroll:
|
||||||
case WheelAction::VScroll: {
|
case WheelAction::VScroll: {
|
||||||
View* view = View::getView(editor);
|
View* view = View::getView(editor);
|
||||||
gfx::Point scroll = view->viewScroll();
|
gfx::Point scroll = initialScroll(editor);
|
||||||
|
|
||||||
if (!msg->preciseWheel()) {
|
if (!preciseWheel) {
|
||||||
gfx::Rect vp = view->viewportBounds();
|
gfx::Rect vp = view->viewportBounds();
|
||||||
|
|
||||||
if (wheelAction == WheelAction::HScroll) {
|
if (wheelAction == WheelAction::HScroll) {
|
||||||
@ -211,7 +271,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
|
|
||||||
brush.size(
|
brush.size(
|
||||||
base::clamp(
|
base::clamp(
|
||||||
int(brush.size()+dz),
|
int(initialBrushSize()+dz),
|
||||||
// If we use the "static const int" member directly here,
|
// If we use the "static const int" member directly here,
|
||||||
// we'll get a linker error (when compiling without
|
// we'll get a linker error (when compiling without
|
||||||
// optimizations) because we should need to define the
|
// optimizations) because we should need to define the
|
||||||
@ -226,7 +286,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
ToolPreferences::Brush& brush =
|
ToolPreferences::Brush& brush =
|
||||||
Preferences::instance().tool(tool).brush;
|
Preferences::instance().tool(tool).brush;
|
||||||
|
|
||||||
int angle = brush.angle()+dz;
|
int angle = initialBrushAngle()+dz;
|
||||||
while (angle < 0)
|
while (angle < 0)
|
||||||
angle += 180;
|
angle += 180;
|
||||||
angle %= 181;
|
angle %= 181;
|
||||||
@ -236,7 +296,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WheelAction::ToolSameGroup: {
|
case WheelAction::ToolSameGroup: {
|
||||||
tools::Tool* tool = getActiveTool();
|
const tools::Tool* tool = m_groupTool;
|
||||||
|
|
||||||
auto toolBox = App::instance()->toolBox();
|
auto toolBox = App::instance()->toolBox();
|
||||||
std::vector<tools::Tool*> tools;
|
std::vector<tools::Tool*> tools;
|
||||||
@ -249,12 +309,13 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
auto end = tools.end();
|
auto end = tools.end();
|
||||||
auto it = std::find(begin, end, tool);
|
auto it = std::find(begin, end, tool);
|
||||||
if (it != end) {
|
if (it != end) {
|
||||||
if (dz < 0) {
|
int i = std::round(dz);
|
||||||
|
while (i++ < 0) {
|
||||||
if (it == begin)
|
if (it == begin)
|
||||||
it = end;
|
it = end;
|
||||||
--it;
|
--it;
|
||||||
}
|
}
|
||||||
else {
|
while (i-- > 0) {
|
||||||
++it;
|
++it;
|
||||||
if (it == end)
|
if (it == end)
|
||||||
it = begin;
|
it = begin;
|
||||||
@ -266,43 +327,60 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WheelAction::ToolOtherGroup: {
|
case WheelAction::ToolOtherGroup: {
|
||||||
tools::Tool* tool = getActiveTool();
|
tools::Tool* tool = initialTool();
|
||||||
|
|
||||||
auto toolBox = App::instance()->toolBox();
|
auto toolBox = App::instance()->toolBox();
|
||||||
auto begin = toolBox->begin_group();
|
auto begin = toolBox->begin_group();
|
||||||
auto end = toolBox->end_group();
|
auto end = toolBox->end_group();
|
||||||
auto it = std::find(begin, end, tool->getGroup());
|
auto it = std::find(begin, end, tool->getGroup());
|
||||||
if (it != end) {
|
if (it != end) {
|
||||||
if (dz < 0) {
|
int i = std::round(dz);
|
||||||
|
while (i++ < 0) {
|
||||||
if (it == begin)
|
if (it == begin)
|
||||||
it = end;
|
it = end;
|
||||||
--it;
|
--it;
|
||||||
}
|
}
|
||||||
else {
|
while (i-- > 0) {
|
||||||
++it;
|
++it;
|
||||||
if (it == end)
|
if (it == end)
|
||||||
it = begin;
|
it = begin;
|
||||||
}
|
}
|
||||||
ToolBar::instance()->selectToolGroup(*it);
|
ToolBar::instance()->selectToolGroup(*it);
|
||||||
|
m_groupTool = getActiveTool();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WheelAction::Layer: {
|
case WheelAction::Layer: {
|
||||||
Command* command = nullptr;
|
int deltaLayer = 0;
|
||||||
if (dz < 0.0)
|
if (preciseWheel) {
|
||||||
command = Commands::instance()->byId(CommandId::GotoNextLayer());
|
if (dz < 0.0)
|
||||||
else if (dz > 0.0)
|
deltaLayer = +1;
|
||||||
command = Commands::instance()->byId(CommandId::GotoPreviousLayer());
|
else if (dz > 0.0)
|
||||||
if (command)
|
deltaLayer = -1;
|
||||||
UIContext::instance()->executeCommand(command);
|
}
|
||||||
|
else {
|
||||||
|
deltaLayer = -dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LayerList& layers = browsableLayers(editor);
|
||||||
|
layer_t layer = initialLayer(editor) + deltaLayer;
|
||||||
|
layer_t nlayers = layers.size();
|
||||||
|
while (layer < 0)
|
||||||
|
layer += nlayers;
|
||||||
|
while (layer >= nlayers)
|
||||||
|
layer -= nlayers;
|
||||||
|
|
||||||
|
editor->setLayer(layers[layer]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WheelAction::InkOpacity: {
|
case WheelAction::InkOpacity: {
|
||||||
|
int opacity = initialInkOpacity(editor);
|
||||||
|
adjust_value(preciseWheel, dz, opacity, 0, 255);
|
||||||
|
|
||||||
tools::Tool* tool = getActiveTool();
|
tools::Tool* tool = getActiveTool();
|
||||||
auto& toolPref = Preferences::instance().tool(tool);
|
auto& toolPref = Preferences::instance().tool(tool);
|
||||||
int opacity = toolPref.opacity();
|
|
||||||
opacity = base::clamp(int(opacity+dz*255/10), 0, 255);
|
|
||||||
toolPref.opacity(opacity);
|
toolPref.opacity(opacity);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -314,8 +392,8 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
site.layer()->isEditable()) {
|
site.layer()->isEditable()) {
|
||||||
Command* command = Commands::instance()->byId(CommandId::LayerOpacity());
|
Command* command = Commands::instance()->byId(CommandId::LayerOpacity());
|
||||||
if (command) {
|
if (command) {
|
||||||
int opacity = static_cast<doc::LayerImage*>(site.layer())->opacity();
|
int opacity = initialLayerOpacity(editor);
|
||||||
opacity = base::clamp(int(opacity+dz*255/10), 0, 255);
|
adjust_value(preciseWheel, dz, opacity, 0, 255);
|
||||||
|
|
||||||
Params params;
|
Params params;
|
||||||
params.set("opacity",
|
params.set("opacity",
|
||||||
@ -334,8 +412,9 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
site.cel()) {
|
site.cel()) {
|
||||||
Command* command = Commands::instance()->byId(CommandId::CelOpacity());
|
Command* command = Commands::instance()->byId(CommandId::CelOpacity());
|
||||||
if (command) {
|
if (command) {
|
||||||
int opacity = site.cel()->opacity();
|
int opacity = initialCelOpacity(editor);
|
||||||
opacity = base::clamp(int(opacity+dz*255/10), 0, 255);
|
adjust_value(preciseWheel, dz, opacity, 0, 255);
|
||||||
|
|
||||||
Params params;
|
Params params;
|
||||||
params.set("opacity",
|
params.set("opacity",
|
||||||
base::convert_to<std::string>(opacity).c_str());
|
base::convert_to<std::string>(opacity).c_str());
|
||||||
@ -348,12 +427,12 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
case WheelAction::Alpha: {
|
case WheelAction::Alpha: {
|
||||||
disableQuickTool();
|
disableQuickTool();
|
||||||
|
|
||||||
ColorBar* colorBar = ColorBar::instance();
|
Color c = initialFgColor();
|
||||||
Color c = colorBar->getFgColor();
|
|
||||||
int a = c.getAlpha();
|
int a = c.getAlpha();
|
||||||
a = base::clamp(int(a+dz*255/10), 0, 255);
|
adjust_value(preciseWheel, dz, a, 0, 255);
|
||||||
c.setAlpha(a);
|
c.setAlpha(a);
|
||||||
colorBar->setFgColor(c);
|
|
||||||
|
changeFgColor(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,20 +441,26 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
case WheelAction::HslLightness: {
|
case WheelAction::HslLightness: {
|
||||||
disableQuickTool();
|
disableQuickTool();
|
||||||
|
|
||||||
ColorBar* colorBar = ColorBar::instance();
|
Color c = initialFgColor();
|
||||||
Color c = colorBar->getFgColor();
|
|
||||||
double
|
double
|
||||||
h = c.getHslHue(),
|
h = c.getHslHue(),
|
||||||
s = c.getHslSaturation(),
|
s = c.getHslSaturation(),
|
||||||
l = c.getHslLightness();
|
l = c.getHslLightness();
|
||||||
switch (wheelAction) {
|
switch (wheelAction) {
|
||||||
case WheelAction::HslHue: h = h+dz*10.0; break;
|
case WheelAction::HslHue:
|
||||||
case WheelAction::HslSaturation: s = s+dz/10.0; break;
|
adjust_hue(preciseWheel, dz, h, 0.0, 360.0);
|
||||||
case WheelAction::HslLightness: l = l+dz/10.0; break;
|
break;
|
||||||
|
case WheelAction::HslSaturation:
|
||||||
|
adjust_unit(preciseWheel, dz, s);
|
||||||
|
break;
|
||||||
|
case WheelAction::HslLightness:
|
||||||
|
adjust_unit(preciseWheel, dz, l);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
colorBar->setFgColor(Color::fromHsl(base::clamp(h, 0.0, 360.0),
|
|
||||||
base::clamp(s, 0.0, 1.0),
|
changeFgColor(Color::fromHsl(base::clamp(h, 0.0, 360.0),
|
||||||
base::clamp(l, 0.0, 1.0)));
|
base::clamp(s, 0.0, 1.0),
|
||||||
|
base::clamp(l, 0.0, 1.0)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,26 +469,30 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
case WheelAction::HsvValue: {
|
case WheelAction::HsvValue: {
|
||||||
disableQuickTool();
|
disableQuickTool();
|
||||||
|
|
||||||
ColorBar* colorBar = ColorBar::instance();
|
Color c = initialFgColor();
|
||||||
Color c = colorBar->getFgColor();
|
|
||||||
double
|
double
|
||||||
h = c.getHsvHue(),
|
h = c.getHsvHue(),
|
||||||
s = c.getHsvSaturation(),
|
s = c.getHsvSaturation(),
|
||||||
v = c.getHsvValue();
|
v = c.getHsvValue();
|
||||||
switch (wheelAction) {
|
switch (wheelAction) {
|
||||||
case WheelAction::HsvHue: h = h+dz*10.0; break;
|
case WheelAction::HsvHue:
|
||||||
case WheelAction::HsvSaturation: s = s+dz/10.0; break;
|
adjust_hue(preciseWheel, dz, h, 0.0, 360.0);
|
||||||
case WheelAction::HsvValue: v = v+dz/10.0; break;
|
break;
|
||||||
|
case WheelAction::HsvSaturation:
|
||||||
|
adjust_unit(preciseWheel, dz, s);
|
||||||
|
break;
|
||||||
|
case WheelAction::HsvValue:
|
||||||
|
adjust_unit(preciseWheel, dz, v);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
colorBar->setFgColor(Color::fromHsv(base::clamp(h, 0.0, 360.0),
|
|
||||||
base::clamp(s, 0.0, 1.0),
|
changeFgColor(Color::fromHsv(base::clamp(h, 0.0, 360.0),
|
||||||
base::clamp(v, 0.0, 1.0)));
|
base::clamp(s, 0.0, 1.0),
|
||||||
|
base::clamp(v, 0.0, 1.0)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StateWithWheelBehavior::onTouchMagnify(Editor* editor, ui::TouchMessage* msg)
|
bool StateWithWheelBehavior::onTouchMagnify(Editor* editor, ui::TouchMessage* msg)
|
||||||
@ -416,6 +505,49 @@ bool StateWithWheelBehavior::onTouchMagnify(Editor* editor, ui::TouchMessage* ms
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StateWithWheelBehavior::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||||
|
{
|
||||||
|
tools::Ink* ink = editor->getCurrentEditorInk();
|
||||||
|
auto theme = skin::SkinTheme::get(editor);
|
||||||
|
|
||||||
|
if (ink) {
|
||||||
|
// If the current tool change selection (e.g. rectangular marquee, etc.)
|
||||||
|
if (ink->isSelection()) {
|
||||||
|
editor->showBrushPreview(mouseScreenPos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ink->isEyedropper()) {
|
||||||
|
editor->showMouseCursor(
|
||||||
|
kCustomCursor, theme->cursors.eyedropper());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ink->isZoom()) {
|
||||||
|
editor->showMouseCursor(
|
||||||
|
kCustomCursor, theme->cursors.magnifier());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ink->isScrollMovement()) {
|
||||||
|
editor->showMouseCursor(kScrollCursor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ink->isCelMovement()) {
|
||||||
|
editor->showMouseCursor(kMoveCursor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
if (editor->canDraw()) {
|
||||||
|
editor->showBrushPreview(mouseScreenPos);
|
||||||
|
}
|
||||||
|
// Forbidden
|
||||||
|
else {
|
||||||
|
editor->showMouseCursor(kForbiddenCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void StateWithWheelBehavior::setZoom(Editor* editor,
|
void StateWithWheelBehavior::setZoom(Editor* editor,
|
||||||
const render::Zoom& zoom,
|
const render::Zoom& zoom,
|
||||||
const gfx::Point& mousePos)
|
const gfx::Point& mousePos)
|
||||||
@ -428,13 +560,120 @@ void StateWithWheelBehavior::setZoom(Editor* editor,
|
|||||||
Editor::ZoomBehavior::MOUSE));
|
Editor::ZoomBehavior::MOUSE));
|
||||||
}
|
}
|
||||||
|
|
||||||
tools::Tool* StateWithWheelBehavior::getActiveTool()
|
Color StateWithWheelBehavior::initialFgColor() const
|
||||||
|
{
|
||||||
|
return ColorBar::instance()->getFgColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
Color StateWithWheelBehavior::initialBgColor() const
|
||||||
|
{
|
||||||
|
return ColorBar::instance()->getBgColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
int StateWithWheelBehavior::initialFgTileIndex() const
|
||||||
|
{
|
||||||
|
return ColorBar::instance()->getFgTile();
|
||||||
|
}
|
||||||
|
|
||||||
|
int StateWithWheelBehavior::initialBgTileIndex() const
|
||||||
|
{
|
||||||
|
return ColorBar::instance()->getBgTile();
|
||||||
|
}
|
||||||
|
|
||||||
|
int StateWithWheelBehavior::initialBrushSize()
|
||||||
|
{
|
||||||
|
tools::Tool* tool = getActiveTool();
|
||||||
|
ToolPreferences::Brush& brush =
|
||||||
|
Preferences::instance().tool(tool).brush;
|
||||||
|
|
||||||
|
return brush.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int StateWithWheelBehavior::initialBrushAngle()
|
||||||
|
{
|
||||||
|
tools::Tool* tool = getActiveTool();
|
||||||
|
ToolPreferences::Brush& brush =
|
||||||
|
Preferences::instance().tool(tool).brush;
|
||||||
|
|
||||||
|
return brush.angle();
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Point StateWithWheelBehavior::initialScroll(Editor* editor) const
|
||||||
|
{
|
||||||
|
View* view = View::getView(editor);
|
||||||
|
return view->viewScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
render::Zoom StateWithWheelBehavior::initialZoom(Editor* editor) const
|
||||||
|
{
|
||||||
|
return editor->zoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
doc::frame_t StateWithWheelBehavior::initialFrame(Editor* editor) const
|
||||||
|
{
|
||||||
|
return editor->frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
doc::layer_t StateWithWheelBehavior::initialLayer(Editor* editor) const
|
||||||
|
{
|
||||||
|
return doc::find_layer_index(browsableLayers(editor), editor->layer());
|
||||||
|
}
|
||||||
|
|
||||||
|
int StateWithWheelBehavior::initialInkOpacity(Editor* editor) const
|
||||||
|
{
|
||||||
|
tools::Tool* tool = getActiveTool();
|
||||||
|
auto& toolPref = Preferences::instance().tool(tool);
|
||||||
|
return toolPref.opacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
int StateWithWheelBehavior::initialCelOpacity(Editor* editor) const
|
||||||
|
{
|
||||||
|
doc::Layer* layer = editor->layer();
|
||||||
|
if (layer &&
|
||||||
|
layer->isImage() &&
|
||||||
|
layer->isEditable()) {
|
||||||
|
if (Cel* cel = layer->cel(editor->frame()))
|
||||||
|
return cel->opacity();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int StateWithWheelBehavior::initialLayerOpacity(Editor* editor) const
|
||||||
|
{
|
||||||
|
doc::Layer* layer = editor->layer();
|
||||||
|
if (layer &&
|
||||||
|
layer->isImage() &&
|
||||||
|
layer->isEditable()) {
|
||||||
|
return static_cast<doc::LayerImage*>(layer)->opacity();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tools::Tool* StateWithWheelBehavior::initialTool() const
|
||||||
|
{
|
||||||
|
return getActiveTool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateWithWheelBehavior::changeFgColor(Color c)
|
||||||
|
{
|
||||||
|
ColorBar::instance()->setFgColor(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
tools::Tool* StateWithWheelBehavior::getActiveTool() const
|
||||||
{
|
{
|
||||||
disableQuickTool();
|
disableQuickTool();
|
||||||
return App::instance()->activeToolManager()->activeTool();
|
return App::instance()->activeToolManager()->activeTool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateWithWheelBehavior::disableQuickTool()
|
const doc::LayerList& StateWithWheelBehavior::browsableLayers(Editor* editor) const
|
||||||
|
{
|
||||||
|
if (m_browsableLayers.empty())
|
||||||
|
m_browsableLayers = editor->sprite()->allBrowsableLayers();
|
||||||
|
return m_browsableLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateWithWheelBehavior::disableQuickTool() const
|
||||||
{
|
{
|
||||||
auto atm = App::instance()->activeToolManager();
|
auto atm = App::instance()->activeToolManager();
|
||||||
if (atm->quickTool()) {
|
if (atm->quickTool()) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2016 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -8,7 +9,12 @@
|
|||||||
#define APP_UI_STATE_WITH_WHEEL_BEHAVIOR_H_INCLUDED
|
#define APP_UI_STATE_WITH_WHEEL_BEHAVIOR_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "app/color.h"
|
||||||
#include "app/ui/editor/editor_state.h"
|
#include "app/ui/editor/editor_state.h"
|
||||||
|
#include "app/ui/key.h"
|
||||||
|
#include "doc/frame.h"
|
||||||
|
#include "doc/layer.h"
|
||||||
|
#include "doc/layer_list.h"
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
class Zoom;
|
class Zoom;
|
||||||
@ -22,12 +28,45 @@ namespace app {
|
|||||||
|
|
||||||
class StateWithWheelBehavior : public EditorState {
|
class StateWithWheelBehavior : public EditorState {
|
||||||
public:
|
public:
|
||||||
virtual bool onMouseWheel(Editor* editor, ui::MouseMessage* msg) override;
|
StateWithWheelBehavior();
|
||||||
virtual bool onTouchMagnify(Editor* editor, ui::TouchMessage* msg) override;
|
|
||||||
|
bool onMouseWheel(Editor* editor, ui::MouseMessage* msg) override;
|
||||||
|
bool onTouchMagnify(Editor* editor, ui::TouchMessage* msg) override;
|
||||||
|
bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void processWheelAction(Editor* editor,
|
||||||
|
WheelAction wheelAction,
|
||||||
|
const gfx::Point& position,
|
||||||
|
gfx::Point delta,
|
||||||
|
double dz,
|
||||||
|
bool scrollBigSteps,
|
||||||
|
bool preciseWheel);
|
||||||
|
const doc::LayerList& browsableLayers(Editor* editor) const;
|
||||||
|
|
||||||
|
virtual Color initialFgColor() const;
|
||||||
|
virtual Color initialBgColor() const;
|
||||||
|
virtual int initialFgTileIndex() const;
|
||||||
|
virtual int initialBgTileIndex() const;
|
||||||
|
virtual int initialBrushSize();
|
||||||
|
virtual int initialBrushAngle();
|
||||||
|
virtual gfx::Point initialScroll(Editor* editor) const;
|
||||||
|
virtual render::Zoom initialZoom(Editor* editor) const;
|
||||||
|
virtual doc::frame_t initialFrame(Editor* editor) const;
|
||||||
|
virtual doc::layer_t initialLayer(Editor* editor) const;
|
||||||
|
virtual int initialInkOpacity(Editor* editor) const;
|
||||||
|
virtual int initialCelOpacity(Editor* editor) const;
|
||||||
|
virtual int initialLayerOpacity(Editor* editor) const;
|
||||||
|
virtual tools::Tool* initialTool() const;
|
||||||
|
virtual void changeFgColor(Color c);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setZoom(Editor* editor, const render::Zoom& zoom, const gfx::Point& mousePos);
|
void setZoom(Editor* editor, const render::Zoom& zoom, const gfx::Point& mousePos);
|
||||||
tools::Tool* getActiveTool();
|
tools::Tool* getActiveTool() const;
|
||||||
void disableQuickTool();
|
void disableQuickTool() const;
|
||||||
|
|
||||||
|
mutable doc::LayerList m_browsableLayers;
|
||||||
|
tools::Tool* m_groupTool;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -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
|
||||||
@ -12,6 +12,7 @@
|
|||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/ui/key_context.h"
|
#include "app/ui/key_context.h"
|
||||||
#include "base/convert_to.h"
|
#include "base/convert_to.h"
|
||||||
|
#include "base/vector2d.h"
|
||||||
#include "ui/accelerator.h"
|
#include "ui/accelerator.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -40,6 +41,7 @@ namespace app {
|
|||||||
Quicktool,
|
Quicktool,
|
||||||
Action,
|
Action,
|
||||||
WheelAction,
|
WheelAction,
|
||||||
|
DragAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO This should be called "KeyActionModifier" or something similar
|
// TODO This should be called "KeyActionModifier" or something similar
|
||||||
@ -101,6 +103,11 @@ namespace app {
|
|||||||
return KeyAction(int(a) & int(b));
|
return KeyAction(int(a) & int(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Key;
|
||||||
|
using KeyPtr = std::shared_ptr<Key>;
|
||||||
|
using Keys = std::vector<KeyPtr>;
|
||||||
|
using DragVector = base::Vector2d<double>;
|
||||||
|
|
||||||
class Key {
|
class Key {
|
||||||
public:
|
public:
|
||||||
Key(Command* command, const Params& params,
|
Key(Command* command, const Params& params,
|
||||||
@ -109,6 +116,7 @@ namespace app {
|
|||||||
explicit Key(const KeyAction action,
|
explicit Key(const KeyAction action,
|
||||||
const KeyContext keyContext);
|
const KeyContext keyContext);
|
||||||
explicit Key(const WheelAction action);
|
explicit Key(const WheelAction action);
|
||||||
|
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 {
|
||||||
@ -142,8 +150,11 @@ namespace app {
|
|||||||
tools::Tool* tool() const { return m_tool; }
|
tools::Tool* tool() const { return m_tool; }
|
||||||
// for KeyType::Action
|
// for KeyType::Action
|
||||||
KeyAction action() const { return m_action; }
|
KeyAction action() const { return m_action; }
|
||||||
// for KeyType::WheelAction
|
// for KeyType::WheelAction / KeyType::DragAction
|
||||||
WheelAction wheelAction() const { return m_wheelAction; }
|
WheelAction wheelAction() const { return m_wheelAction; }
|
||||||
|
// for KeyType::DragAction
|
||||||
|
DragVector dragVector() const { return m_dragVector; }
|
||||||
|
void setDragVector(const DragVector& v) { m_dragVector = v; }
|
||||||
|
|
||||||
std::string triggerString() const;
|
std::string triggerString() const;
|
||||||
|
|
||||||
@ -158,16 +169,12 @@ namespace app {
|
|||||||
// for KeyType::Command
|
// for KeyType::Command
|
||||||
Command* m_command;
|
Command* m_command;
|
||||||
Params m_params;
|
Params m_params;
|
||||||
// for KeyType::Tool or Quicktool
|
|
||||||
tools::Tool* m_tool;
|
|
||||||
// for KeyType::Action
|
|
||||||
KeyAction m_action;
|
|
||||||
// for KeyType::WheelAction
|
|
||||||
WheelAction m_wheelAction;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::shared_ptr<Key> KeyPtr;
|
tools::Tool* m_tool; // for KeyType::Tool or Quicktool
|
||||||
typedef std::vector<KeyPtr> Keys;
|
KeyAction m_action; // for KeyType::Action
|
||||||
|
WheelAction m_wheelAction; // for KeyType::WheelAction / DragAction
|
||||||
|
DragVector m_dragVector; // for KeyType::DragAction
|
||||||
|
};
|
||||||
|
|
||||||
std::string convertKeyContextToUserFriendlyString(KeyContext keyContext);
|
std::string convertKeyContextToUserFriendlyString(KeyContext keyContext);
|
||||||
|
|
||||||
|
@ -22,9 +22,11 @@
|
|||||||
#include "app/tools/ink.h"
|
#include "app/tools/ink.h"
|
||||||
#include "app/tools/tool.h"
|
#include "app/tools/tool.h"
|
||||||
#include "app/tools/tool_box.h"
|
#include "app/tools/tool_box.h"
|
||||||
|
#include "app/ui/key.h"
|
||||||
#include "app/ui_context.h"
|
#include "app/ui_context.h"
|
||||||
#include "app/xml_document.h"
|
#include "app/xml_document.h"
|
||||||
#include "app/xml_exception.h"
|
#include "app/xml_exception.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
#include "ui/accelerator.h"
|
#include "ui/accelerator.h"
|
||||||
#include "ui/message.h"
|
#include "ui/message.h"
|
||||||
|
|
||||||
@ -81,35 +83,37 @@ namespace {
|
|||||||
{ NULL , app::KeyContext::Any }
|
{ NULL , app::KeyContext::Any }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Vec = app::DragVector;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* userfriendly;
|
const char* userfriendly;
|
||||||
app::WheelAction action;
|
Vec vector;
|
||||||
} wheel_actions[] = {
|
} wheel_actions[] = {
|
||||||
{ "Zoom" , "Zoom" , app::WheelAction::Zoom },
|
{ "" , "" , Vec(0.0, 0.0) },
|
||||||
{ "VScroll" , "Scroll: Vertically" , app::WheelAction::VScroll },
|
{ "Zoom" , "Zoom" , Vec(8.0, 0.0) },
|
||||||
{ "HScroll" , "Scroll: Horizontally" , app::WheelAction::HScroll },
|
{ "VScroll" , "Scroll: Vertically" , Vec(4.0, 0.0) },
|
||||||
{ "FgColor" , "Color: Foreground Palette Entry" , app::WheelAction::FgColor },
|
{ "HScroll" , "Scroll: Horizontally" , Vec(4.0, 0.0) },
|
||||||
{ "BgColor" , "Color: Background Palette Entry" , app::WheelAction::BgColor },
|
{ "FgColor" , "Color: Foreground Palette Entry" , Vec(8.0, 0.0) },
|
||||||
{ "FgTile" , "Tile: Foreground Tile Entry" , app::WheelAction::FgTile },
|
{ "BgColor" , "Color: Background Palette Entry" , Vec(8.0, 0.0) },
|
||||||
{ "BgTile" , "Tile: Background Tile Entry" , app::WheelAction::BgTile },
|
{ "FgTile" , "Tile: Foreground Tile Entry" , Vec(8.0, 0.0) },
|
||||||
{ "Frame" , "Change Frame" , app::WheelAction::Frame },
|
{ "BgTile" , "Tile: Background Tile Entry" , Vec(8.0, 0.0) },
|
||||||
{ "BrushSize" , "Change Brush Size" , app::WheelAction::BrushSize },
|
{ "Frame" , "Change Frame" , Vec(16.0, 0.0) },
|
||||||
{ "BrushAngle" , "Change Brush Angle" , app::WheelAction::BrushAngle },
|
{ "BrushSize" , "Change Brush Size" , Vec(4.0, 0.0) },
|
||||||
{ "ToolSameGroup" , "Change Tool (same group)" , app::WheelAction::ToolSameGroup },
|
{ "BrushAngle" , "Change Brush Angle" , Vec(-4.0, 0.0) },
|
||||||
{ "ToolOtherGroup" , "Change Tool" , app::WheelAction::ToolOtherGroup },
|
{ "ToolSameGroup" , "Change Tool (same group)" , Vec(8.0, 0.0) },
|
||||||
{ "Layer" , "Change Layer" , app::WheelAction::Layer },
|
{ "ToolOtherGroup" , "Change Tool" , Vec(0.0, -8.0) },
|
||||||
{ "InkOpacity" , "Change Ink Opacity" , app::WheelAction::InkOpacity },
|
{ "Layer" , "Change Layer" , Vec(0.0, 8.0) },
|
||||||
{ "LayerOpacity" , "Change Layer Opacity" , app::WheelAction::LayerOpacity },
|
{ "InkOpacity" , "Change Ink Opacity" , Vec(0.0, 1.0) },
|
||||||
{ "CelOpacity" , "Change Cel Opacity" , app::WheelAction::CelOpacity },
|
{ "LayerOpacity" , "Change Layer Opacity" , Vec(0.0, 1.0) },
|
||||||
{ "Alpha" , "Color: Alpha" , app::WheelAction::Alpha },
|
{ "CelOpacity" , "Change Cel Opacity" , Vec(0.0, 1.0) },
|
||||||
{ "HslHue" , "Color: HSL Hue" , app::WheelAction::HslHue },
|
{ "Alpha" , "Color: Alpha" , Vec(4.0, 0.0) },
|
||||||
{ "HslSaturation", "Color: HSL Saturation" , app::WheelAction::HslSaturation },
|
{ "HslHue" , "Color: HSL Hue" , Vec(1.0, 0.0) },
|
||||||
{ "HslLightness" , "Color: HSL Lightness" , app::WheelAction::HslLightness },
|
{ "HslSaturation", "Color: HSL Saturation" , Vec(4.0, 0.0) },
|
||||||
{ "HsvHue" , "Color: HSV Hue" , app::WheelAction::HsvHue },
|
{ "HslLightness" , "Color: HSL Lightness" , Vec(0.0, 4.0) },
|
||||||
{ "HsvSaturation", "Color: HSV Saturation" , app::WheelAction::HsvSaturation },
|
{ "HsvHue" , "Color: HSV Hue" , Vec(1.0, 0.0) },
|
||||||
{ "HsvValue" , "Color: HSV Value" , app::WheelAction::HsvValue },
|
{ "HsvSaturation", "Color: HSV Saturation" , Vec(4.0, 0.0) },
|
||||||
{ nullptr , nullptr , app::WheelAction::None }
|
{ "HsvValue" , "Color: HSV Value" , Vec(0.0, 4.0) },
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* get_shortcut(TiXmlElement* elem) {
|
const char* get_shortcut(TiXmlElement* elem) {
|
||||||
@ -140,11 +144,13 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string get_user_friendly_string_for_wheelaction(app::WheelAction wheelAction) {
|
std::string get_user_friendly_string_for_wheelaction(app::WheelAction wheelAction) {
|
||||||
for (int c=0; wheel_actions[c].name; ++c) {
|
int c = int(wheelAction);
|
||||||
if (wheelAction == wheel_actions[c].action)
|
if (c >= int(app::WheelAction::First) &&
|
||||||
return wheel_actions[c].userfriendly;
|
c <= int(app::WheelAction::Last)) {
|
||||||
|
return wheel_actions[c].userfriendly;
|
||||||
}
|
}
|
||||||
return std::string();
|
else
|
||||||
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@ -169,20 +175,22 @@ namespace base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<> app::WheelAction convert_to(const std::string& from) {
|
template<> app::WheelAction convert_to(const std::string& from) {
|
||||||
app::WheelAction action = app::WheelAction::None;
|
for (int c=int(app::WheelAction::First);
|
||||||
for (int c=0; wheel_actions[c].name; ++c) {
|
c<=int(app::WheelAction::Last); ++c) {
|
||||||
if (from == wheel_actions[c].name)
|
if (from == wheel_actions[c].name)
|
||||||
return wheel_actions[c].action;
|
return (app::WheelAction)c;
|
||||||
}
|
}
|
||||||
return action;
|
return app::WheelAction::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> std::string convert_to(const app::WheelAction& from) {
|
template<> std::string convert_to(const app::WheelAction& from) {
|
||||||
for (int c=0; wheel_actions[c].name; ++c) {
|
int c = int(from);
|
||||||
if (from == wheel_actions[c].action)
|
if (c >= int(app::WheelAction::First) &&
|
||||||
return wheel_actions[c].name;
|
c <= int(app::WheelAction::Last)) {
|
||||||
|
return wheel_actions[c].name;
|
||||||
}
|
}
|
||||||
return "";
|
else
|
||||||
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> app::KeyContext convert_to(const std::string& from) {
|
template<> app::KeyContext convert_to(const std::string& from) {
|
||||||
@ -291,6 +299,16 @@ Key::Key(const WheelAction wheelAction)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
KeyPtr Key::MakeDragAction(WheelAction dragAction)
|
||||||
|
{
|
||||||
|
KeyPtr k(new Key(dragAction));
|
||||||
|
k->m_type = KeyType::DragAction;
|
||||||
|
k->m_keycontext = KeyContext::Any;
|
||||||
|
k->m_dragVector = wheel_actions[(int)dragAction].vector;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
void Key::add(const ui::Accelerator& accel,
|
void Key::add(const ui::Accelerator& accel,
|
||||||
const KeySource source,
|
const KeySource source,
|
||||||
KeyboardShortcuts& globalKeys)
|
KeyboardShortcuts& globalKeys)
|
||||||
@ -411,6 +429,7 @@ std::string Key::triggerString() const
|
|||||||
return get_user_friendly_string_for_keyaction(m_action,
|
return get_user_friendly_string_for_keyaction(m_action,
|
||||||
m_keycontext);
|
m_keycontext);
|
||||||
case KeyType::WheelAction:
|
case KeyType::WheelAction:
|
||||||
|
case KeyType::DragAction:
|
||||||
return get_user_friendly_string_for_wheelaction(m_wheelAction);
|
return get_user_friendly_string_for_wheelaction(m_wheelAction);
|
||||||
}
|
}
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
@ -633,6 +652,45 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
}
|
}
|
||||||
xmlKey = xmlKey->NextSiblingElement();
|
xmlKey = xmlKey->NextSiblingElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load special keyboard shortcuts to simulate mouse wheel actions
|
||||||
|
// <keyboard><drag><key>
|
||||||
|
xmlKey = handle
|
||||||
|
.FirstChild("drag")
|
||||||
|
.FirstChild("key").ToElement();
|
||||||
|
while (xmlKey) {
|
||||||
|
const char* action_id = xmlKey->Attribute("action");
|
||||||
|
const char* action_key = get_shortcut(xmlKey);
|
||||||
|
bool removed = bool_attr(xmlKey, "removed", false);
|
||||||
|
|
||||||
|
if (action_id) {
|
||||||
|
WheelAction action = base::convert_to<WheelAction, std::string>(action_id);
|
||||||
|
if (action != WheelAction::None) {
|
||||||
|
KeyPtr key = this->dragAction(action);
|
||||||
|
if (key && action_key) {
|
||||||
|
if (auto vector_str = xmlKey->Attribute("vector")) {
|
||||||
|
double x, y = 0.0;
|
||||||
|
// Parse a string like "double,double"
|
||||||
|
x = std::strtod(vector_str, (char**)&vector_str);
|
||||||
|
if (vector_str && *vector_str == ',') {
|
||||||
|
++vector_str;
|
||||||
|
y = std::strtod(vector_str, nullptr);
|
||||||
|
}
|
||||||
|
key->setDragVector(DragVector(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(VERBOSE, "KEYS: Shortcut for drag action %s: %s\n", action_id, action_key);
|
||||||
|
Accelerator accel(action_key);
|
||||||
|
|
||||||
|
if (!removed)
|
||||||
|
key->add(accel, source, *this);
|
||||||
|
else
|
||||||
|
key->disableAccel(accel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmlKey = xmlKey->NextSiblingElement();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardShortcuts::importFile(const std::string& filename, KeySource source)
|
void KeyboardShortcuts::importFile(const std::string& filename, KeySource source)
|
||||||
@ -654,6 +712,7 @@ void KeyboardShortcuts::exportFile(const std::string& filename)
|
|||||||
TiXmlElement quicktools("quicktools");
|
TiXmlElement quicktools("quicktools");
|
||||||
TiXmlElement actions("actions");
|
TiXmlElement actions("actions");
|
||||||
TiXmlElement wheel("wheel");
|
TiXmlElement wheel("wheel");
|
||||||
|
TiXmlElement drag("drag");
|
||||||
|
|
||||||
keyboard.SetAttribute("version", XML_KEYBOARD_FILE_VERSION);
|
keyboard.SetAttribute("version", XML_KEYBOARD_FILE_VERSION);
|
||||||
|
|
||||||
@ -662,12 +721,14 @@ void KeyboardShortcuts::exportFile(const std::string& filename)
|
|||||||
exportKeys(quicktools, KeyType::Quicktool);
|
exportKeys(quicktools, KeyType::Quicktool);
|
||||||
exportKeys(actions, KeyType::Action);
|
exportKeys(actions, KeyType::Action);
|
||||||
exportKeys(wheel, KeyType::WheelAction);
|
exportKeys(wheel, KeyType::WheelAction);
|
||||||
|
exportKeys(drag, KeyType::DragAction);
|
||||||
|
|
||||||
keyboard.InsertEndChild(commands);
|
keyboard.InsertEndChild(commands);
|
||||||
keyboard.InsertEndChild(tools);
|
keyboard.InsertEndChild(tools);
|
||||||
keyboard.InsertEndChild(quicktools);
|
keyboard.InsertEndChild(quicktools);
|
||||||
keyboard.InsertEndChild(actions);
|
keyboard.InsertEndChild(actions);
|
||||||
keyboard.InsertEndChild(wheel);
|
keyboard.InsertEndChild(wheel);
|
||||||
|
keyboard.InsertEndChild(drag);
|
||||||
|
|
||||||
TiXmlDeclaration declaration("1.0", "utf-8", "");
|
TiXmlDeclaration declaration("1.0", "utf-8", "");
|
||||||
doc->InsertEndChild(declaration);
|
doc->InsertEndChild(declaration);
|
||||||
@ -731,7 +792,16 @@ void KeyboardShortcuts::exportAccel(TiXmlElement& parent, const Key* key, const
|
|||||||
|
|
||||||
case KeyType::WheelAction:
|
case KeyType::WheelAction:
|
||||||
elem.SetAttribute("action",
|
elem.SetAttribute("action",
|
||||||
base::convert_to<std::string>(key->wheelAction()).c_str());
|
base::convert_to<std::string>(key->wheelAction()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KeyType::DragAction:
|
||||||
|
elem.SetAttribute("action",
|
||||||
|
base::convert_to<std::string>(key->wheelAction()));
|
||||||
|
elem.SetAttribute("vector",
|
||||||
|
fmt::format("{},{}",
|
||||||
|
key->dragVector().x,
|
||||||
|
key->dragVector().y));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,6 +897,20 @@ KeyPtr KeyboardShortcuts::wheelAction(WheelAction wheelAction)
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyPtr KeyboardShortcuts::dragAction(WheelAction dragAction)
|
||||||
|
{
|
||||||
|
for (KeyPtr& key : m_keys) {
|
||||||
|
if (key->type() == KeyType::DragAction &&
|
||||||
|
key->wheelAction() == dragAction) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyPtr key = Key::MakeDragAction(dragAction);
|
||||||
|
m_keys.push_back(key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
||||||
const KeyContext keyContext,
|
const KeyContext keyContext,
|
||||||
const Key* newKey)
|
const Key* newKey)
|
||||||
@ -837,7 +921,12 @@ void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
|||||||
// Tools can contain the same keyboard shortcut
|
// Tools can contain the same keyboard shortcut
|
||||||
(key->type() != KeyType::Tool ||
|
(key->type() != KeyType::Tool ||
|
||||||
newKey == nullptr ||
|
newKey == nullptr ||
|
||||||
newKey->type() != KeyType::Tool)) {
|
newKey->type() != KeyType::Tool) &&
|
||||||
|
// DragActions can share the same keyboard shortcut (e.g. to
|
||||||
|
// change different values using different DragVectors)
|
||||||
|
(key->type() != KeyType::DragAction ||
|
||||||
|
newKey == nullptr ||
|
||||||
|
newKey->type() != KeyType::DragAction)) {
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -921,7 +1010,6 @@ WheelAction KeyboardShortcuts::getWheelActionFromMouseMessage(const KeyContext c
|
|||||||
{
|
{
|
||||||
WheelAction wheelAction = WheelAction::None;
|
WheelAction wheelAction = WheelAction::None;
|
||||||
const ui::Accelerator* bestAccel = nullptr;
|
const ui::Accelerator* bestAccel = nullptr;
|
||||||
KeyPtr bestKey;
|
|
||||||
for (const KeyPtr& key : m_keys) {
|
for (const KeyPtr& key : m_keys) {
|
||||||
if (key->type() == KeyType::WheelAction &&
|
if (key->type() == KeyType::WheelAction &&
|
||||||
key->keycontext() == context) {
|
key->keycontext() == context) {
|
||||||
@ -936,6 +1024,22 @@ WheelAction KeyboardShortcuts::getWheelActionFromMouseMessage(const KeyContext c
|
|||||||
return wheelAction;
|
return wheelAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keys KeyboardShortcuts::getDragActionsFromKeyMessage(const KeyContext context,
|
||||||
|
const ui::Message* msg)
|
||||||
|
{
|
||||||
|
KeyPtr bestKey = nullptr;
|
||||||
|
Keys keys;
|
||||||
|
for (const KeyPtr& key : m_keys) {
|
||||||
|
if (key->type() == KeyType::DragAction) {
|
||||||
|
const ui::Accelerator* accel = key->isPressed(msg, *this);
|
||||||
|
if (accel) {
|
||||||
|
keys.push_back(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
bool KeyboardShortcuts::hasMouseWheelCustomization() const
|
bool KeyboardShortcuts::hasMouseWheelCustomization() const
|
||||||
{
|
{
|
||||||
for (const KeyPtr& key : m_keys) {
|
for (const KeyPtr& key : m_keys) {
|
||||||
@ -958,15 +1062,31 @@ void KeyboardShortcuts::clearMouseWheelKeys()
|
|||||||
|
|
||||||
void KeyboardShortcuts::addMissingMouseWheelKeys()
|
void KeyboardShortcuts::addMissingMouseWheelKeys()
|
||||||
{
|
{
|
||||||
for (int wheelAction=int(WheelAction::First);
|
for (int action=int(WheelAction::First);
|
||||||
wheelAction<=int(WheelAction::Last); ++wheelAction) {
|
action<=int(WheelAction::Last); ++action) {
|
||||||
|
// Wheel actions
|
||||||
auto it = std::find_if(
|
auto it = std::find_if(
|
||||||
m_keys.begin(), m_keys.end(),
|
m_keys.begin(), m_keys.end(),
|
||||||
[wheelAction](const KeyPtr& key) -> bool {
|
[action](const KeyPtr& key) -> bool {
|
||||||
return key->wheelAction() == (WheelAction)wheelAction;
|
return
|
||||||
|
key->type() == KeyType::WheelAction &&
|
||||||
|
key->wheelAction() == (WheelAction)action;
|
||||||
});
|
});
|
||||||
if (it == m_keys.end()) {
|
if (it == m_keys.end()) {
|
||||||
KeyPtr key = std::make_shared<Key>((WheelAction)wheelAction);
|
KeyPtr key = std::make_shared<Key>((WheelAction)action);
|
||||||
|
m_keys.push_back(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drag actions
|
||||||
|
it = std::find_if(
|
||||||
|
m_keys.begin(), m_keys.end(),
|
||||||
|
[action](const KeyPtr& key) -> bool {
|
||||||
|
return
|
||||||
|
key->type() == KeyType::DragAction &&
|
||||||
|
key->wheelAction() == (WheelAction)action;
|
||||||
|
});
|
||||||
|
if (it == m_keys.end()) {
|
||||||
|
KeyPtr key = Key::MakeDragAction((WheelAction)action);
|
||||||
m_keys.push_back(key);
|
m_keys.push_back(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020 Igara Studio S.A.
|
// Copyright (C) 2020-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
|
||||||
@ -51,6 +51,7 @@ namespace app {
|
|||||||
KeyPtr action(const KeyAction action,
|
KeyPtr action(const KeyAction action,
|
||||||
const KeyContext keyContext = KeyContext::Any);
|
const KeyContext keyContext = KeyContext::Any);
|
||||||
KeyPtr wheelAction(const WheelAction action);
|
KeyPtr wheelAction(const WheelAction action);
|
||||||
|
KeyPtr dragAction(const WheelAction action);
|
||||||
|
|
||||||
void disableAccel(const ui::Accelerator& accel,
|
void disableAccel(const ui::Accelerator& accel,
|
||||||
const KeyContext keyContext,
|
const KeyContext keyContext,
|
||||||
@ -62,6 +63,8 @@ namespace app {
|
|||||||
KeyAction getCurrentActionModifiers(KeyContext context);
|
KeyAction getCurrentActionModifiers(KeyContext context);
|
||||||
WheelAction getWheelActionFromMouseMessage(const KeyContext context,
|
WheelAction getWheelActionFromMouseMessage(const KeyContext context,
|
||||||
const ui::Message* msg);
|
const ui::Message* msg);
|
||||||
|
Keys getDragActionsFromKeyMessage(const KeyContext context,
|
||||||
|
const ui::Message* msg);
|
||||||
bool hasMouseWheelCustomization() const;
|
bool hasMouseWheelCustomization() const;
|
||||||
void clearMouseWheelKeys();
|
void clearMouseWheelKeys();
|
||||||
void addMissingMouseWheelKeys();
|
void addMissingMouseWheelKeys();
|
||||||
|
Loading…
Reference in New Issue
Block a user