mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-29 19:20:09 +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"?>
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018-2021 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2022 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<!-- Keyboard shortcuts -->
|
||||
@ -639,6 +639,10 @@
|
||||
<key action="RightMouseButton" />
|
||||
</actions>
|
||||
|
||||
<drag>
|
||||
<key action="BrushSize" vector="4.0,0.0" shortcut="Ctrl+Alt" />
|
||||
</drag>
|
||||
|
||||
</keyboard>
|
||||
|
||||
<menus>
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Aseprite
|
||||
# Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
# Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
# Copyright (C) 2016-2018 David Capello
|
||||
|
||||
[advanced_mode]
|
||||
@ -846,9 +846,14 @@ section_commands = Commands
|
||||
section_tools = Tools
|
||||
section_action_modifiers = Action Modifiers
|
||||
section_mouse_wheel = Mouse Wheel
|
||||
section_drag_value = Drag Value
|
||||
default_wheel_behavior = Default
|
||||
custom_wheel_behavior = Custom
|
||||
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
|
||||
cancel = &Cancel
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2022 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2016 David Capello -->
|
||||
<gui>
|
||||
<window id="keyboard_shortcuts" text="@keyboard_shortcuts.title">
|
||||
@ -15,6 +15,7 @@
|
||||
<listitem text="@.section_tools" />
|
||||
<listitem text="@.section_action_modifiers" />
|
||||
<listitem text="@.section_mouse_wheel" />
|
||||
<listitem text="@.section_drag_value" />
|
||||
</listbox>
|
||||
</view>
|
||||
<separator horizontal="true" />
|
||||
@ -53,6 +54,52 @@
|
||||
<listbox id="wheel_actions" />
|
||||
</view>
|
||||
</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>
|
||||
</splitter>
|
||||
<hbox>
|
||||
|
@ -343,6 +343,7 @@ if(ENABLE_UI)
|
||||
ui/dynamics_popup.cpp
|
||||
ui/editor/brush_preview.cpp
|
||||
ui/editor/delayed_mouse_move.cpp
|
||||
ui/editor/dragging_value_state.cpp
|
||||
ui/editor/drawing_state.cpp
|
||||
ui/editor/editor.cpp
|
||||
ui/editor/editor_observers.cpp
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/pi.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "base/split_string.h"
|
||||
#include "base/string.h"
|
||||
@ -506,14 +507,19 @@ private:
|
||||
};
|
||||
|
||||
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
|
||||
// TODO Merge with CanvasSizeWindow::Dir
|
||||
enum class Dir { NW, N, NE, W, C, E, SW, S, SE };
|
||||
|
||||
public:
|
||||
KeyboardShortcutsWindow(app::KeyboardShortcuts& keys,
|
||||
MenuKeys& menuKeys,
|
||||
const std::string& searchText)
|
||||
const std::string& searchText,
|
||||
int& curSection)
|
||||
: m_keys(keys)
|
||||
, m_menuKeys(menuKeys)
|
||||
, m_searchChange(false)
|
||||
, m_wasDefault(false) {
|
||||
, m_wasDefault(false)
|
||||
, m_curSection(curSection) {
|
||||
setAutoRemap(false);
|
||||
|
||||
m_listBoxes.push_back(menus());
|
||||
@ -521,6 +527,7 @@ public:
|
||||
m_listBoxes.push_back(tools());
|
||||
m_listBoxes.push_back(actions());
|
||||
m_listBoxes.push_back(wheelActions());
|
||||
m_listBoxes.push_back(dragActions());
|
||||
|
||||
#ifdef __APPLE__ // Zoom sliding two fingers option only on macOS
|
||||
slideZoom()->setVisible(true);
|
||||
@ -544,6 +551,9 @@ public:
|
||||
|
||||
search()->Change.connect([this]{ onSearchChange(); });
|
||||
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(); });
|
||||
exportButton()->Click.connect([this]{ onExport(); });
|
||||
resetButton()->Click.connect([this]{ onReset(); });
|
||||
@ -573,6 +583,7 @@ private:
|
||||
deleteList(tools());
|
||||
deleteList(actions());
|
||||
deleteList(wheelActions());
|
||||
deleteList(dragActions());
|
||||
}
|
||||
|
||||
void fillAllLists() {
|
||||
@ -592,11 +603,13 @@ private:
|
||||
|
||||
fillToolsList(tools(), App::instance()->toolBox());
|
||||
fillWheelActionsList();
|
||||
fillDragActionsList();
|
||||
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::Tool ||
|
||||
key->type() == KeyType::Quicktool ||
|
||||
key->type() == KeyType::WheelAction) {
|
||||
key->type() == KeyType::WheelAction ||
|
||||
key->type() == KeyType::DragAction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -636,7 +649,7 @@ private:
|
||||
tools()->sortItems();
|
||||
actions()->sortItems();
|
||||
|
||||
section()->selectIndex(0);
|
||||
section()->selectIndex(m_curSection);
|
||||
updateViews();
|
||||
}
|
||||
|
||||
@ -730,6 +743,19 @@ private:
|
||||
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() {
|
||||
const bool isDefault = isDefaultWheelBehavior();
|
||||
if (isDefault)
|
||||
@ -741,7 +767,7 @@ private:
|
||||
std::string searchText = search()->text();
|
||||
|
||||
if (searchText.empty())
|
||||
section()->selectIndex(0);
|
||||
section()->selectIndex(m_curSection);
|
||||
else {
|
||||
fillSearchList(searchText);
|
||||
section()->selectChild(nullptr);
|
||||
@ -758,14 +784,48 @@ private:
|
||||
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() {
|
||||
int s = section()->getSelectedIndex();
|
||||
if (s >= 0)
|
||||
m_curSection = s;
|
||||
|
||||
searchView()->setVisible(s < 0);
|
||||
menusView()->setVisible(s == 0);
|
||||
commandsView()->setVisible(s == 1);
|
||||
toolsView()->setVisible(s == 2);
|
||||
actionsView()->setVisible(s == 3);
|
||||
wheelSection()->setVisible(s == 4);
|
||||
dragSection()->setVisible(s == 5);
|
||||
|
||||
if (m_headerItem.parent())
|
||||
m_headerItem.parent()->removeChild(&m_headerItem);
|
||||
@ -868,12 +928,51 @@ private:
|
||||
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;
|
||||
MenuKeys& m_menuKeys;
|
||||
std::vector<ListBox*> m_listBoxes;
|
||||
bool m_searchChange;
|
||||
bool m_wasDefault;
|
||||
HeaderItem m_headerItem;
|
||||
int& m_curSection;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
@ -905,6 +1004,8 @@ void KeyboardShortcutsCommand::onLoadParams(const Params& params)
|
||||
|
||||
void KeyboardShortcutsCommand::onExecute(Context* context)
|
||||
{
|
||||
static int curSection = 0;
|
||||
|
||||
app::KeyboardShortcuts* globalKeys = app::KeyboardShortcuts::instance();
|
||||
app::KeyboardShortcuts keys;
|
||||
keys.setKeys(*globalKeys, true);
|
||||
@ -919,7 +1020,7 @@ void KeyboardShortcutsCommand::onExecute(Context* context)
|
||||
// KeyboardShortcutsCommand instance (so m_search will be "")
|
||||
// TODO Seeing this, we need a complete new way to handle UI commands execution
|
||||
std::string neededSearchCopy = m_search;
|
||||
KeyboardShortcutsWindow window(keys, menuKeys, neededSearchCopy);
|
||||
KeyboardShortcutsWindow window(keys, menuKeys, neededSearchCopy, curSection);
|
||||
|
||||
ui::Display* mainDisplay = Manager::getDefault()->display();
|
||||
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/ui/app_menuitem.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/editor.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);
|
||||
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()) {
|
||||
if (resizeCelBounds(editor).contains(mouseScreenPos))
|
||||
editor->showMouseCursor(kSizeSECursor);
|
||||
@ -498,16 +485,7 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
if (editor->canDraw()) {
|
||||
editor->showBrushPreview(mouseScreenPos);
|
||||
}
|
||||
// Forbidden
|
||||
else {
|
||||
editor->showMouseCursor(kForbiddenCursor);
|
||||
}
|
||||
|
||||
return true;
|
||||
return StateWithWheelBehavior::onSetCursor(editor, mouseScreenPos);
|
||||
}
|
||||
|
||||
bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||
@ -515,6 +493,15 @@ bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||
if (Preferences::instance().editor.straightLinePreview() &&
|
||||
checkStartDrawingStraightLine(editor, nullptr, nullptr))
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -33,10 +33,41 @@
|
||||
#include "ui/system.h"
|
||||
#include "ui/theme.h"
|
||||
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
|
||||
case WheelAction::None:
|
||||
@ -117,15 +167,15 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
|
||||
case WheelAction::FgColor: {
|
||||
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);
|
||||
ColorBar::instance()->setFgColor(app::Color::fromIndex(newIndex));
|
||||
changeFgColor(app::Color::fromIndex(newIndex));
|
||||
break;
|
||||
}
|
||||
|
||||
case WheelAction::BgColor: {
|
||||
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);
|
||||
ColorBar::instance()->setBgColor(app::Color::fromIndex(newIndex));
|
||||
break;
|
||||
@ -134,7 +184,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
case WheelAction::FgTile: {
|
||||
auto tilesView = ColorBar::instance()->getTilesView();
|
||||
int lastIndex = tilesView->tileset()->size()-1;
|
||||
int newIndex = ColorBar::instance()->getFgTile() + int(dz);
|
||||
int newIndex = initialFgTileIndex() + int(dz);
|
||||
newIndex = base::clamp(newIndex, 0, lastIndex);
|
||||
ColorBar::instance()->setFgTile(newIndex);
|
||||
break;
|
||||
@ -143,29 +193,39 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
case WheelAction::BgTile: {
|
||||
auto tilesView = ColorBar::instance()->getTilesView();
|
||||
int lastIndex = tilesView->tileset()->size()-1;
|
||||
int newIndex = ColorBar::instance()->getBgTile() + int(dz);
|
||||
int newIndex = initialBgTileIndex() + int(dz);
|
||||
newIndex = base::clamp(newIndex, 0, lastIndex);
|
||||
ColorBar::instance()->setBgTile(newIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
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)
|
||||
command = Commands::instance()->byId(CommandId::GotoNextFrame());
|
||||
else if (dz > 0.0)
|
||||
command = Commands::instance()->byId(CommandId::GotoPreviousFrame());
|
||||
frame_t frame = initialFrame(editor) + deltaFrame;
|
||||
frame_t nframes = editor->sprite()->totalFrames();
|
||||
while (frame < 0)
|
||||
frame += nframes;
|
||||
while (frame >= nframes)
|
||||
frame -= nframes;
|
||||
|
||||
if (command)
|
||||
UIContext::instance()->executeCommand(command);
|
||||
editor->setFrame(frame);
|
||||
break;
|
||||
}
|
||||
|
||||
case WheelAction::Zoom: {
|
||||
render::Zoom zoom = editor->zoom();
|
||||
render::Zoom zoom = initialZoom(editor);
|
||||
|
||||
if (msg->preciseWheel()) {
|
||||
if (preciseWheel) {
|
||||
dz /= 1.5;
|
||||
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));
|
||||
|
||||
setZoom(editor, zoom, msg->position());
|
||||
setZoom(editor, zoom, position);
|
||||
break;
|
||||
}
|
||||
|
||||
case WheelAction::HScroll:
|
||||
case WheelAction::VScroll: {
|
||||
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();
|
||||
|
||||
if (wheelAction == WheelAction::HScroll) {
|
||||
@ -211,7 +271,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
|
||||
brush.size(
|
||||
base::clamp(
|
||||
int(brush.size()+dz),
|
||||
int(initialBrushSize()+dz),
|
||||
// If we use the "static const int" member directly here,
|
||||
// we'll get a linker error (when compiling without
|
||||
// optimizations) because we should need to define the
|
||||
@ -226,7 +286,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
ToolPreferences::Brush& brush =
|
||||
Preferences::instance().tool(tool).brush;
|
||||
|
||||
int angle = brush.angle()+dz;
|
||||
int angle = initialBrushAngle()+dz;
|
||||
while (angle < 0)
|
||||
angle += 180;
|
||||
angle %= 181;
|
||||
@ -236,7 +296,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
}
|
||||
|
||||
case WheelAction::ToolSameGroup: {
|
||||
tools::Tool* tool = getActiveTool();
|
||||
const tools::Tool* tool = m_groupTool;
|
||||
|
||||
auto toolBox = App::instance()->toolBox();
|
||||
std::vector<tools::Tool*> tools;
|
||||
@ -249,12 +309,13 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
auto end = tools.end();
|
||||
auto it = std::find(begin, end, tool);
|
||||
if (it != end) {
|
||||
if (dz < 0) {
|
||||
int i = std::round(dz);
|
||||
while (i++ < 0) {
|
||||
if (it == begin)
|
||||
it = end;
|
||||
--it;
|
||||
}
|
||||
else {
|
||||
while (i-- > 0) {
|
||||
++it;
|
||||
if (it == end)
|
||||
it = begin;
|
||||
@ -266,43 +327,60 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
}
|
||||
|
||||
case WheelAction::ToolOtherGroup: {
|
||||
tools::Tool* tool = getActiveTool();
|
||||
tools::Tool* tool = initialTool();
|
||||
|
||||
auto toolBox = App::instance()->toolBox();
|
||||
auto begin = toolBox->begin_group();
|
||||
auto end = toolBox->end_group();
|
||||
auto it = std::find(begin, end, tool->getGroup());
|
||||
if (it != end) {
|
||||
if (dz < 0) {
|
||||
int i = std::round(dz);
|
||||
while (i++ < 0) {
|
||||
if (it == begin)
|
||||
it = end;
|
||||
--it;
|
||||
}
|
||||
else {
|
||||
while (i-- > 0) {
|
||||
++it;
|
||||
if (it == end)
|
||||
it = begin;
|
||||
}
|
||||
ToolBar::instance()->selectToolGroup(*it);
|
||||
m_groupTool = getActiveTool();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WheelAction::Layer: {
|
||||
Command* command = nullptr;
|
||||
if (dz < 0.0)
|
||||
command = Commands::instance()->byId(CommandId::GotoNextLayer());
|
||||
else if (dz > 0.0)
|
||||
command = Commands::instance()->byId(CommandId::GotoPreviousLayer());
|
||||
if (command)
|
||||
UIContext::instance()->executeCommand(command);
|
||||
int deltaLayer = 0;
|
||||
if (preciseWheel) {
|
||||
if (dz < 0.0)
|
||||
deltaLayer = +1;
|
||||
else if (dz > 0.0)
|
||||
deltaLayer = -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
case WheelAction::InkOpacity: {
|
||||
int opacity = initialInkOpacity(editor);
|
||||
adjust_value(preciseWheel, dz, opacity, 0, 255);
|
||||
|
||||
tools::Tool* tool = getActiveTool();
|
||||
auto& toolPref = Preferences::instance().tool(tool);
|
||||
int opacity = toolPref.opacity();
|
||||
opacity = base::clamp(int(opacity+dz*255/10), 0, 255);
|
||||
toolPref.opacity(opacity);
|
||||
break;
|
||||
}
|
||||
@ -314,8 +392,8 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
site.layer()->isEditable()) {
|
||||
Command* command = Commands::instance()->byId(CommandId::LayerOpacity());
|
||||
if (command) {
|
||||
int opacity = static_cast<doc::LayerImage*>(site.layer())->opacity();
|
||||
opacity = base::clamp(int(opacity+dz*255/10), 0, 255);
|
||||
int opacity = initialLayerOpacity(editor);
|
||||
adjust_value(preciseWheel, dz, opacity, 0, 255);
|
||||
|
||||
Params params;
|
||||
params.set("opacity",
|
||||
@ -334,8 +412,9 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
site.cel()) {
|
||||
Command* command = Commands::instance()->byId(CommandId::CelOpacity());
|
||||
if (command) {
|
||||
int opacity = site.cel()->opacity();
|
||||
opacity = base::clamp(int(opacity+dz*255/10), 0, 255);
|
||||
int opacity = initialCelOpacity(editor);
|
||||
adjust_value(preciseWheel, dz, opacity, 0, 255);
|
||||
|
||||
Params params;
|
||||
params.set("opacity",
|
||||
base::convert_to<std::string>(opacity).c_str());
|
||||
@ -348,12 +427,12 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
case WheelAction::Alpha: {
|
||||
disableQuickTool();
|
||||
|
||||
ColorBar* colorBar = ColorBar::instance();
|
||||
Color c = colorBar->getFgColor();
|
||||
Color c = initialFgColor();
|
||||
int a = c.getAlpha();
|
||||
a = base::clamp(int(a+dz*255/10), 0, 255);
|
||||
adjust_value(preciseWheel, dz, a, 0, 255);
|
||||
c.setAlpha(a);
|
||||
colorBar->setFgColor(c);
|
||||
|
||||
changeFgColor(c);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -362,20 +441,26 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
case WheelAction::HslLightness: {
|
||||
disableQuickTool();
|
||||
|
||||
ColorBar* colorBar = ColorBar::instance();
|
||||
Color c = colorBar->getFgColor();
|
||||
Color c = initialFgColor();
|
||||
double
|
||||
h = c.getHslHue(),
|
||||
s = c.getHslSaturation(),
|
||||
l = c.getHslLightness();
|
||||
switch (wheelAction) {
|
||||
case WheelAction::HslHue: h = h+dz*10.0; break;
|
||||
case WheelAction::HslSaturation: s = s+dz/10.0; break;
|
||||
case WheelAction::HslLightness: l = l+dz/10.0; break;
|
||||
case WheelAction::HslHue:
|
||||
adjust_hue(preciseWheel, dz, h, 0.0, 360.0);
|
||||
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),
|
||||
base::clamp(l, 0.0, 1.0)));
|
||||
|
||||
changeFgColor(Color::fromHsl(base::clamp(h, 0.0, 360.0),
|
||||
base::clamp(s, 0.0, 1.0),
|
||||
base::clamp(l, 0.0, 1.0)));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -384,26 +469,30 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
case WheelAction::HsvValue: {
|
||||
disableQuickTool();
|
||||
|
||||
ColorBar* colorBar = ColorBar::instance();
|
||||
Color c = colorBar->getFgColor();
|
||||
Color c = initialFgColor();
|
||||
double
|
||||
h = c.getHsvHue(),
|
||||
s = c.getHsvSaturation(),
|
||||
v = c.getHsvValue();
|
||||
switch (wheelAction) {
|
||||
case WheelAction::HsvHue: h = h+dz*10.0; break;
|
||||
case WheelAction::HsvSaturation: s = s+dz/10.0; break;
|
||||
case WheelAction::HsvValue: v = v+dz/10.0; break;
|
||||
case WheelAction::HsvHue:
|
||||
adjust_hue(preciseWheel, dz, h, 0.0, 360.0);
|
||||
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),
|
||||
base::clamp(v, 0.0, 1.0)));
|
||||
|
||||
changeFgColor(Color::fromHsv(base::clamp(h, 0.0, 360.0),
|
||||
base::clamp(s, 0.0, 1.0),
|
||||
base::clamp(v, 0.0, 1.0)));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StateWithWheelBehavior::onTouchMagnify(Editor* editor, ui::TouchMessage* msg)
|
||||
@ -416,6 +505,49 @@ bool StateWithWheelBehavior::onTouchMagnify(Editor* editor, ui::TouchMessage* ms
|
||||
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,
|
||||
const render::Zoom& zoom,
|
||||
const gfx::Point& mousePos)
|
||||
@ -428,13 +560,120 @@ void StateWithWheelBehavior::setZoom(Editor* editor,
|
||||
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();
|
||||
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();
|
||||
if (atm->quickTool()) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -8,7 +9,12 @@
|
||||
#define APP_UI_STATE_WITH_WHEEL_BEHAVIOR_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/color.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 {
|
||||
class Zoom;
|
||||
@ -22,12 +28,45 @@ namespace app {
|
||||
|
||||
class StateWithWheelBehavior : public EditorState {
|
||||
public:
|
||||
virtual bool onMouseWheel(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onTouchMagnify(Editor* editor, ui::TouchMessage* msg) override;
|
||||
StateWithWheelBehavior();
|
||||
|
||||
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:
|
||||
void setZoom(Editor* editor, const render::Zoom& zoom, const gfx::Point& mousePos);
|
||||
tools::Tool* getActiveTool();
|
||||
void disableQuickTool();
|
||||
tools::Tool* getActiveTool() const;
|
||||
void disableQuickTool() const;
|
||||
|
||||
mutable doc::LayerList m_browsableLayers;
|
||||
tools::Tool* m_groupTool;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -12,6 +12,7 @@
|
||||
#include "app/commands/params.h"
|
||||
#include "app/ui/key_context.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/vector2d.h"
|
||||
#include "ui/accelerator.h"
|
||||
|
||||
#include <memory>
|
||||
@ -40,6 +41,7 @@ namespace app {
|
||||
Quicktool,
|
||||
Action,
|
||||
WheelAction,
|
||||
DragAction,
|
||||
};
|
||||
|
||||
// TODO This should be called "KeyActionModifier" or something similar
|
||||
@ -101,6 +103,11 @@ namespace app {
|
||||
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 {
|
||||
public:
|
||||
Key(Command* command, const Params& params,
|
||||
@ -109,6 +116,7 @@ namespace app {
|
||||
explicit Key(const KeyAction action,
|
||||
const KeyContext keyContext);
|
||||
explicit Key(const WheelAction action);
|
||||
static KeyPtr MakeDragAction(WheelAction dragAction);
|
||||
|
||||
KeyType type() const { return m_type; }
|
||||
const ui::Accelerators& accels() const {
|
||||
@ -142,8 +150,11 @@ namespace app {
|
||||
tools::Tool* tool() const { return m_tool; }
|
||||
// for KeyType::Action
|
||||
KeyAction action() const { return m_action; }
|
||||
// for KeyType::WheelAction
|
||||
// for KeyType::WheelAction / KeyType::DragAction
|
||||
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;
|
||||
|
||||
@ -158,16 +169,12 @@ namespace app {
|
||||
// for KeyType::Command
|
||||
Command* m_command;
|
||||
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;
|
||||
typedef std::vector<KeyPtr> Keys;
|
||||
tools::Tool* m_tool; // for KeyType::Tool or Quicktool
|
||||
KeyAction m_action; // for KeyType::Action
|
||||
WheelAction m_wheelAction; // for KeyType::WheelAction / DragAction
|
||||
DragVector m_dragVector; // for KeyType::DragAction
|
||||
};
|
||||
|
||||
std::string convertKeyContextToUserFriendlyString(KeyContext keyContext);
|
||||
|
||||
|
@ -22,9 +22,11 @@
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/tool.h"
|
||||
#include "app/tools/tool_box.h"
|
||||
#include "app/ui/key.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "app/xml_document.h"
|
||||
#include "app/xml_exception.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/message.h"
|
||||
|
||||
@ -81,35 +83,37 @@ namespace {
|
||||
{ NULL , app::KeyContext::Any }
|
||||
};
|
||||
|
||||
using Vec = app::DragVector;
|
||||
|
||||
static struct {
|
||||
const char* name;
|
||||
const char* userfriendly;
|
||||
app::WheelAction action;
|
||||
Vec vector;
|
||||
} wheel_actions[] = {
|
||||
{ "Zoom" , "Zoom" , app::WheelAction::Zoom },
|
||||
{ "VScroll" , "Scroll: Vertically" , app::WheelAction::VScroll },
|
||||
{ "HScroll" , "Scroll: Horizontally" , app::WheelAction::HScroll },
|
||||
{ "FgColor" , "Color: Foreground Palette Entry" , app::WheelAction::FgColor },
|
||||
{ "BgColor" , "Color: Background Palette Entry" , app::WheelAction::BgColor },
|
||||
{ "FgTile" , "Tile: Foreground Tile Entry" , app::WheelAction::FgTile },
|
||||
{ "BgTile" , "Tile: Background Tile Entry" , app::WheelAction::BgTile },
|
||||
{ "Frame" , "Change Frame" , app::WheelAction::Frame },
|
||||
{ "BrushSize" , "Change Brush Size" , app::WheelAction::BrushSize },
|
||||
{ "BrushAngle" , "Change Brush Angle" , app::WheelAction::BrushAngle },
|
||||
{ "ToolSameGroup" , "Change Tool (same group)" , app::WheelAction::ToolSameGroup },
|
||||
{ "ToolOtherGroup" , "Change Tool" , app::WheelAction::ToolOtherGroup },
|
||||
{ "Layer" , "Change Layer" , app::WheelAction::Layer },
|
||||
{ "InkOpacity" , "Change Ink Opacity" , app::WheelAction::InkOpacity },
|
||||
{ "LayerOpacity" , "Change Layer Opacity" , app::WheelAction::LayerOpacity },
|
||||
{ "CelOpacity" , "Change Cel Opacity" , app::WheelAction::CelOpacity },
|
||||
{ "Alpha" , "Color: Alpha" , app::WheelAction::Alpha },
|
||||
{ "HslHue" , "Color: HSL Hue" , app::WheelAction::HslHue },
|
||||
{ "HslSaturation", "Color: HSL Saturation" , app::WheelAction::HslSaturation },
|
||||
{ "HslLightness" , "Color: HSL Lightness" , app::WheelAction::HslLightness },
|
||||
{ "HsvHue" , "Color: HSV Hue" , app::WheelAction::HsvHue },
|
||||
{ "HsvSaturation", "Color: HSV Saturation" , app::WheelAction::HsvSaturation },
|
||||
{ "HsvValue" , "Color: HSV Value" , app::WheelAction::HsvValue },
|
||||
{ nullptr , nullptr , app::WheelAction::None }
|
||||
{ "" , "" , Vec(0.0, 0.0) },
|
||||
{ "Zoom" , "Zoom" , Vec(8.0, 0.0) },
|
||||
{ "VScroll" , "Scroll: Vertically" , Vec(4.0, 0.0) },
|
||||
{ "HScroll" , "Scroll: Horizontally" , Vec(4.0, 0.0) },
|
||||
{ "FgColor" , "Color: Foreground Palette Entry" , Vec(8.0, 0.0) },
|
||||
{ "BgColor" , "Color: Background Palette Entry" , Vec(8.0, 0.0) },
|
||||
{ "FgTile" , "Tile: Foreground Tile Entry" , Vec(8.0, 0.0) },
|
||||
{ "BgTile" , "Tile: Background Tile Entry" , Vec(8.0, 0.0) },
|
||||
{ "Frame" , "Change Frame" , Vec(16.0, 0.0) },
|
||||
{ "BrushSize" , "Change Brush Size" , Vec(4.0, 0.0) },
|
||||
{ "BrushAngle" , "Change Brush Angle" , Vec(-4.0, 0.0) },
|
||||
{ "ToolSameGroup" , "Change Tool (same group)" , Vec(8.0, 0.0) },
|
||||
{ "ToolOtherGroup" , "Change Tool" , Vec(0.0, -8.0) },
|
||||
{ "Layer" , "Change Layer" , Vec(0.0, 8.0) },
|
||||
{ "InkOpacity" , "Change Ink Opacity" , Vec(0.0, 1.0) },
|
||||
{ "LayerOpacity" , "Change Layer Opacity" , Vec(0.0, 1.0) },
|
||||
{ "CelOpacity" , "Change Cel Opacity" , Vec(0.0, 1.0) },
|
||||
{ "Alpha" , "Color: Alpha" , Vec(4.0, 0.0) },
|
||||
{ "HslHue" , "Color: HSL Hue" , Vec(1.0, 0.0) },
|
||||
{ "HslSaturation", "Color: HSL Saturation" , Vec(4.0, 0.0) },
|
||||
{ "HslLightness" , "Color: HSL Lightness" , Vec(0.0, 4.0) },
|
||||
{ "HsvHue" , "Color: HSV Hue" , Vec(1.0, 0.0) },
|
||||
{ "HsvSaturation", "Color: HSV Saturation" , Vec(4.0, 0.0) },
|
||||
{ "HsvValue" , "Color: HSV Value" , Vec(0.0, 4.0) },
|
||||
};
|
||||
|
||||
const char* get_shortcut(TiXmlElement* elem) {
|
||||
@ -140,11 +144,13 @@ namespace {
|
||||
}
|
||||
|
||||
std::string get_user_friendly_string_for_wheelaction(app::WheelAction wheelAction) {
|
||||
for (int c=0; wheel_actions[c].name; ++c) {
|
||||
if (wheelAction == wheel_actions[c].action)
|
||||
return wheel_actions[c].userfriendly;
|
||||
int c = int(wheelAction);
|
||||
if (c >= int(app::WheelAction::First) &&
|
||||
c <= int(app::WheelAction::Last)) {
|
||||
return wheel_actions[c].userfriendly;
|
||||
}
|
||||
return std::string();
|
||||
else
|
||||
return std::string();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
@ -169,20 +175,22 @@ namespace base {
|
||||
}
|
||||
|
||||
template<> app::WheelAction convert_to(const std::string& from) {
|
||||
app::WheelAction action = app::WheelAction::None;
|
||||
for (int c=0; wheel_actions[c].name; ++c) {
|
||||
for (int c=int(app::WheelAction::First);
|
||||
c<=int(app::WheelAction::Last); ++c) {
|
||||
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) {
|
||||
for (int c=0; wheel_actions[c].name; ++c) {
|
||||
if (from == wheel_actions[c].action)
|
||||
return wheel_actions[c].name;
|
||||
int c = int(from);
|
||||
if (c >= int(app::WheelAction::First) &&
|
||||
c <= int(app::WheelAction::Last)) {
|
||||
return wheel_actions[c].name;
|
||||
}
|
||||
return "";
|
||||
else
|
||||
return std::string();
|
||||
}
|
||||
|
||||
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,
|
||||
const KeySource source,
|
||||
KeyboardShortcuts& globalKeys)
|
||||
@ -411,6 +429,7 @@ std::string Key::triggerString() const
|
||||
return get_user_friendly_string_for_keyaction(m_action,
|
||||
m_keycontext);
|
||||
case KeyType::WheelAction:
|
||||
case KeyType::DragAction:
|
||||
return get_user_friendly_string_for_wheelaction(m_wheelAction);
|
||||
}
|
||||
return "Unknown";
|
||||
@ -633,6 +652,45 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
}
|
||||
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)
|
||||
@ -654,6 +712,7 @@ void KeyboardShortcuts::exportFile(const std::string& filename)
|
||||
TiXmlElement quicktools("quicktools");
|
||||
TiXmlElement actions("actions");
|
||||
TiXmlElement wheel("wheel");
|
||||
TiXmlElement drag("drag");
|
||||
|
||||
keyboard.SetAttribute("version", XML_KEYBOARD_FILE_VERSION);
|
||||
|
||||
@ -662,12 +721,14 @@ void KeyboardShortcuts::exportFile(const std::string& filename)
|
||||
exportKeys(quicktools, KeyType::Quicktool);
|
||||
exportKeys(actions, KeyType::Action);
|
||||
exportKeys(wheel, KeyType::WheelAction);
|
||||
exportKeys(drag, KeyType::DragAction);
|
||||
|
||||
keyboard.InsertEndChild(commands);
|
||||
keyboard.InsertEndChild(tools);
|
||||
keyboard.InsertEndChild(quicktools);
|
||||
keyboard.InsertEndChild(actions);
|
||||
keyboard.InsertEndChild(wheel);
|
||||
keyboard.InsertEndChild(drag);
|
||||
|
||||
TiXmlDeclaration declaration("1.0", "utf-8", "");
|
||||
doc->InsertEndChild(declaration);
|
||||
@ -731,7 +792,16 @@ void KeyboardShortcuts::exportAccel(TiXmlElement& parent, const Key* key, const
|
||||
|
||||
case KeyType::WheelAction:
|
||||
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;
|
||||
}
|
||||
|
||||
@ -827,6 +897,20 @@ KeyPtr KeyboardShortcuts::wheelAction(WheelAction wheelAction)
|
||||
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,
|
||||
const KeyContext keyContext,
|
||||
const Key* newKey)
|
||||
@ -837,7 +921,12 @@ void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
||||
// Tools can contain the same keyboard shortcut
|
||||
(key->type() != KeyType::Tool ||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -921,7 +1010,6 @@ WheelAction KeyboardShortcuts::getWheelActionFromMouseMessage(const KeyContext c
|
||||
{
|
||||
WheelAction wheelAction = WheelAction::None;
|
||||
const ui::Accelerator* bestAccel = nullptr;
|
||||
KeyPtr bestKey;
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::WheelAction &&
|
||||
key->keycontext() == context) {
|
||||
@ -936,6 +1024,22 @@ WheelAction KeyboardShortcuts::getWheelActionFromMouseMessage(const KeyContext c
|
||||
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
|
||||
{
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
@ -958,15 +1062,31 @@ void KeyboardShortcuts::clearMouseWheelKeys()
|
||||
|
||||
void KeyboardShortcuts::addMissingMouseWheelKeys()
|
||||
{
|
||||
for (int wheelAction=int(WheelAction::First);
|
||||
wheelAction<=int(WheelAction::Last); ++wheelAction) {
|
||||
for (int action=int(WheelAction::First);
|
||||
action<=int(WheelAction::Last); ++action) {
|
||||
// Wheel actions
|
||||
auto it = std::find_if(
|
||||
m_keys.begin(), m_keys.end(),
|
||||
[wheelAction](const KeyPtr& key) -> bool {
|
||||
return key->wheelAction() == (WheelAction)wheelAction;
|
||||
[action](const KeyPtr& key) -> bool {
|
||||
return
|
||||
key->type() == KeyType::WheelAction &&
|
||||
key->wheelAction() == (WheelAction)action;
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -51,6 +51,7 @@ namespace app {
|
||||
KeyPtr action(const KeyAction action,
|
||||
const KeyContext keyContext = KeyContext::Any);
|
||||
KeyPtr wheelAction(const WheelAction action);
|
||||
KeyPtr dragAction(const WheelAction action);
|
||||
|
||||
void disableAccel(const ui::Accelerator& accel,
|
||||
const KeyContext keyContext,
|
||||
@ -62,6 +63,8 @@ namespace app {
|
||||
KeyAction getCurrentActionModifiers(KeyContext context);
|
||||
WheelAction getWheelActionFromMouseMessage(const KeyContext context,
|
||||
const ui::Message* msg);
|
||||
Keys getDragActionsFromKeyMessage(const KeyContext context,
|
||||
const ui::Message* msg);
|
||||
bool hasMouseWheelCustomization() const;
|
||||
void clearMouseWheelKeys();
|
||||
void addMissingMouseWheelKeys();
|
||||
|
Loading…
x
Reference in New Issue
Block a user