Add mouse wheel customization for sprite editor

Fix #680, #970, https://community.aseprite.org/t/668
and possibility to change alpha with mouse wheel:
https://github.com/aseprite/aseprite/issues/680#issuecomment-344721509
This commit is contained in:
David Capello 2018-07-19 23:05:14 -03:00
parent f33091dbfa
commit 7740f6a710
17 changed files with 880 additions and 138 deletions

View File

@ -190,6 +190,7 @@ BackgroundFromLayer = Background From Layer
BrightnessContrast = Adjust Brightness/Contrast
Cancel = Cancel Current Operation
CanvasSize = Canvas Size
CelOpacity = Set Cel Opacity to {0} ({1}%)
CelProperties = Cel Properties
ChangeBrush = Change Brush: {0}
ChangeBrush_CustomBrush = Custom Brush #{0}
@ -612,6 +613,14 @@ title = Keyboard Shortcuts
import = &Import
export = &Export
reset = &Reset
section_menus = Menus
section_commands = Commands
section_tools = Tools
section_action_modifiers = Action Modifiers
section_mouse_wheel = Mouse Wheel
default_wheel_behavior = Default
custom_wheel_behavior = Custom
slide_as_wheel = Interpret two fingers slide on Trackpad as mouse wheel
ok = &OK
cancel = &Cancel

View File

@ -7,14 +7,20 @@
<vbox>
<search id="search" magnet="true" />
<view width="80" expansive="true">
<listbox id="section" expansive="true" />
<listbox id="section" expansive="true">
<listitem text="@.section_menus" />
<listitem text="@.section_commands" />
<listitem text="@.section_tools" />
<listitem text="@.section_action_modifiers" />
<listitem text="@.section_mouse_wheel" />
</listbox>
</view>
<separator horizontal="true" />
<button text="@keyboard_shortcuts.import" id="import_button" />
<button text="@keyboard_shortcuts.export" id="export_button" />
<button text="@keyboard_shortcuts.reset" id="reset_button" />
</vbox>
<vbox expansive="true">
<vbox id="lists_placeholder" expansive="true">
<view id="search_view" expansive="true">
<listbox id="search_list" />
</view>
@ -30,6 +36,21 @@
<view id="actions_view" expansive="true">
<listbox id="actions" />
</view>
<vbox id="wheel_section" expansive="true">
<hbox>
<buttonset columns="2" id="wheel_behavior">
<item text="@.default_wheel_behavior" />
<item text="@.custom_wheel_behavior" />
</buttonset>
</hbox>
<check text="@options.wheel_zoom" id="wheel_zoom"
pref="editor.zoom_with_wheel" />
<check text="@options.slide_zoom" id="slide_zoom"
pref="editor.zoom_with_slide" />
<view expansive="true">
<listbox id="wheel_actions" />
</view>
</vbox>
</vbox>
</hbox>
<hbox>

View File

@ -117,8 +117,10 @@
<!-- Editor -->
<vbox id="section_editor">
<separator text="@.section_editor" horizontal="true" />
<check text="@.wheel_zoom" id="wheel_zoom" />
<check text="@.slide_zoom" id="slide_zoom" />
<check text="@.wheel_zoom" id="wheel_zoom"
pref="editor.zoom_with_wheel" />
<check text="@.slide_zoom" id="slide_zoom"
pref="editor.zoom_with_slide" />
<check text="@.zoom_from_center_with_wheel" id="zoom_from_center_with_wheel" />
<check text="@.zoom_from_center_with_keys" id="zoom_from_center_with_keys" />
<check text="@.show_scrollbars" id="show_scrollbars" tooltip="@.show_scrollbars_tooltip" />

View File

@ -175,6 +175,7 @@ if(ENABLE_UI)
commands/cmd_background_from_layer.cpp
commands/cmd_cancel.cpp
commands/cmd_canvas_size.cpp
commands/cmd_cel_opacity.cpp
commands/cmd_cel_properties.cpp
commands/cmd_change_brush.cpp
commands/cmd_change_color.cpp

View File

@ -0,0 +1,112 @@
// Aseprite
// Copyright (C) 2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/app.h"
#include "app/cmd/set_cel_opacity.h"
#include "app/commands/command.h"
#include "app/commands/params.h"
#include "app/context.h"
#include "app/context_access.h"
#include "app/i18n/strings.h"
#include "app/modules/gui.h"
#include "app/transaction.h"
#include "app/ui/timeline/timeline.h"
#include "doc/cel.h"
#include "doc/cels_range.h"
#include "doc/sprite.h"
#include "fmt/format.h"
#include <string>
namespace app {
class CelOpacityCommand : public Command {
public:
CelOpacityCommand();
protected:
bool onNeedsParams() const override { return true; }
void onLoadParams(const Params& params) override;
bool onEnabled(Context* context) override;
void onExecute(Context* context) override;
std::string onGetFriendlyName() const override;
private:
int m_opacity;
};
CelOpacityCommand::CelOpacityCommand()
: Command(CommandId::CelOpacity(), CmdUIOnlyFlag)
{
m_opacity = 255;
}
void CelOpacityCommand::onLoadParams(const Params& params)
{
m_opacity = params.get_as<int>("opacity");
m_opacity = MID(0, m_opacity, 255);
}
bool CelOpacityCommand::onEnabled(Context* context)
{
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
ContextFlags::HasActiveCel);
}
void CelOpacityCommand::onExecute(Context* context)
{
ContextWriter writer(context);
Layer* layer = writer.layer();
Cel* cel = writer.cel();
if (!cel ||
layer->isBackground() ||
!layer->isEditable() ||
cel->opacity() == m_opacity)
return;
{
Transaction transaction(writer.context(), "Set Cel Opacity");
// TODO the range of selected cels should be in app::Site.
DocRange range = App::instance()->timeline()->range();
if (!range.enabled()) {
range.startRange(layer, cel->frame(), DocRange::kCels);
range.endRange(layer, cel->frame());
}
for (Cel* cel : cel->sprite()->uniqueCels(range.selectedFrames())) {
if (range.contains(cel->layer())) {
if (!cel->layer()->isBackground() &&
cel->layer()->isEditable() &&
m_opacity != cel->opacity()) {
transaction.execute(new cmd::SetCelOpacity(cel, m_opacity));
}
}
}
transaction.commit();
}
update_screen_for_document(writer.document());
}
std::string CelOpacityCommand::onGetFriendlyName() const
{
return fmt::format(getBaseFriendlyName(),
m_opacity,
int(100.0 * m_opacity / 255.0));
}
Command* CommandFactory::createCelOpacityCommand()
{
return new CelOpacityCommand;
}
} // namespace app

View File

@ -44,6 +44,7 @@
#include "keyboard_shortcuts.xml.h"
#include <algorithm>
#include <set>
#define KEYBOARD_FILENAME_EXTENSION "aseprite-keys"
@ -186,6 +187,8 @@ public:
private:
void onAccelChange(const Accelerator& accel);
void onChangeAccel(int index) {
LockButtons lock(this);
Accelerator origAccel = m_key->accels()[index];
@ -193,6 +196,8 @@ private:
window.openWindowInForeground();
if (window.isModified()) {
onAccelChange(window.accel());
m_key->disableAccel(origAccel);
if (!window.accel().isEmpty())
m_key->add(window.accel(), KeySource::UserDefined);
@ -223,7 +228,9 @@ private:
SelectAccelerator window(accel, m_key ? m_key->keycontext(): KeyContext::Any);
window.openWindowInForeground();
if (window.isModified()) {
if ((window.isModified()) ||
// We can assign a "None" accelerator to mouse wheel actions
(m_key && m_key->type() == KeyType::WheelAction && window.isOK())) {
if (!m_key) {
ASSERT(m_menuitem);
if (!m_menuitem)
@ -236,6 +243,7 @@ private:
m_menuitem->setKey(m_key);
}
onAccelChange(window.accel());
m_key->add(window.accel(), KeySource::UserDefined);
}
@ -245,7 +253,7 @@ private:
void onSizeHint(SizeHintEvent& ev) override {
gfx::Size size = textSize();
size.w = size.w + border().width();
size.h = size.h + border().height() + 4*guiscale();
size.h = size.h + border().height() + 6*guiscale();
if (m_key && m_key->keycontext() != KeyContext::Any) {
int w =
@ -291,8 +299,9 @@ private:
{
int x = bounds.x + m_level*16 * guiscale();
IntersectClip clip(g, gfx::Rect(x, y, keyXPos - x, th));
if (clip)
if (clip) {
g->drawUIText(text(), fg, bg, gfx::Point(x, y), 0);
}
}
if (m_key && !m_key->accels().empty()) {
@ -311,7 +320,7 @@ private:
for (const Accelerator& accel : m_key->accels()) {
if (i != m_hotAccel || !m_changeButton) {
g->drawText(
accel.toString(), fg, bg,
getAccelText(accel), fg, bg,
gfx::Point(keyXPos, y));
}
y += dh;
@ -336,6 +345,9 @@ private:
}
case kMouseMoveMessage: {
if (!isEnabled())
break;
gfx::Rect bounds = this->bounds();
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
@ -346,7 +358,7 @@ private:
for (int i=0; i<maxi; ++i, y += dh) {
int w = Graphics::measureUITextLength(
(accels && i < (int)accels->size() ? (*accels)[i].toString().c_str(): ""),
(accels && i < (int)accels->size() ? getAccelText((*accels)[i]).c_str(): ""),
font());
gfx::Rect itemBounds(bounds.x + m_headerItem->keyXPos(), y, w, dh);
itemBounds = itemBounds.enlarge(
@ -375,7 +387,7 @@ private:
m_changeButton->setBgColor(gfx::ColorNone);
m_changeButton->setBounds(itemBounds);
m_changeButton->setText((*accels)[i].toString());
m_changeButton->setText(getAccelText((*accels)[i]));
const char* label = "x";
m_deleteButton->setBgColor(gfx::ColorNone);
@ -436,6 +448,16 @@ private:
m_hotAccel = -1;
}
std::string getAccelText(const Accelerator& accel) const {
if (m_key && m_key->type() == KeyType::WheelAction &&
accel.isEmpty()) {
return "(Default Action)";
}
else {
return accel.toString();
}
}
KeyPtr m_key;
KeyPtr m_keyOrig;
AppMenuItem* m_menuitem;
@ -455,18 +477,42 @@ private:
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
public:
KeyboardShortcutsWindow(const std::string& searchText)
: m_searchChange(false) {
: m_searchChange(false)
, m_wasDefault(false) {
setAutoRemap(false);
section()->addChild(new ListItem("Menus"));
section()->addChild(new ListItem("Commands"));
section()->addChild(new ListItem("Tools"));
section()->addChild(new ListItem("Action Modifiers"));
m_listBoxes.push_back(menus());
m_listBoxes.push_back(commands());
m_listBoxes.push_back(tools());
m_listBoxes.push_back(actions());
m_listBoxes.push_back(wheelActions());
#ifdef __APPLE__ // Zoom sliding two fingers option only on macOS
slideZoom()->setVisible(true);
#else
slideZoom()->setVisible(false);
#endif
wheelBehavior()->setSelectedItem(
app::KeyboardShortcuts::instance()->hasMouseWheelCustomization() ? 1: 0);
if (isDefaultWheelBehavior()) {
m_wheelKeys = app::KeyboardShortcuts::instance()
->getDefaultMouseWheelTable(wheelZoom()->isSelected());
m_wasDefault = true;
}
else {
for (const KeyPtr& key : *app::KeyboardShortcuts::instance()) {
if (key->type() == KeyType::WheelAction)
m_wheelKeys.push_back(std::make_shared<Key>(*key));
}
}
updateSlideZoomText();
addMissingWheelKeys();
onWheelBehaviorChange();
wheelBehavior()->ItemChange.connect(base::Bind<void>(&KeyboardShortcutsWindow::onWheelBehaviorChange, this));
wheelZoom()->Click.connect(base::Bind<void>(&KeyboardShortcutsWindow::onWheelZoomChange, this));
search()->Change.connect(base::Bind<void>(&KeyboardShortcutsWindow::onSearchChange, this));
section()->Change.connect(base::Bind<void>(&KeyboardShortcutsWindow::onSectionChange, this));
@ -492,6 +538,25 @@ public:
}
}
const Keys& wheelKeys() {
return m_wheelKeys;
}
bool isDefaultWheelBehavior() {
return (wheelBehavior()->selectedItem() == 0);
}
void disableWheelKey(const Accelerator& accel) {
for (KeyPtr& key : m_wheelKeys) {
for (int i=0; i<key->accels().size(); ++i) {
if (key->accels()[i] == accel) {
key->disableAccel(accel);
break;
}
}
}
}
private:
void deleteAllKeyItems() {
deleteList(searchList());
@ -499,6 +564,7 @@ private:
deleteList(commands());
deleteList(tools());
deleteList(actions());
deleteList(wheelActions());
ASSERT(m_allKeyItems.empty());
}
@ -511,7 +577,8 @@ private:
for (const KeyPtr& key : *app::KeyboardShortcuts::instance()) {
if (key->type() == KeyType::Tool ||
key->type() == KeyType::Quicktool) {
key->type() == KeyType::Quicktool ||
key->type() == KeyType::WheelAction) {
continue;
}
@ -552,6 +619,8 @@ private:
tools()->sortItems();
actions()->sortItems();
fillWheelActionsList();
section()->selectIndex(0);
updateViews();
}
@ -599,6 +668,9 @@ private:
keyItem->menuitem(), 0,
&m_headerItem);
if (!item->isEnabled())
copyItem->setEnabled(false);
m_allKeyItems.push_back(copyItem);
searchList()->addChild(copyItem);
}
@ -608,6 +680,51 @@ private:
}
}
void onWheelBehaviorChange() {
const bool isDefault = isDefaultWheelBehavior();
wheelActions()->setEnabled(!isDefault);
wheelZoom()->setVisible(isDefault);
if (isDefault) {
m_wheelKeys = app::KeyboardShortcuts::instance()
->getDefaultMouseWheelTable(wheelZoom()->isSelected());
m_wasDefault = true;
}
else if (m_wasDefault) {
m_wasDefault = false;
for (KeyPtr& key : m_wheelKeys)
key->copyOriginalToUser();
}
updateSlideZoomText();
addMissingWheelKeys();
fillWheelActionsList();
updateViews();
}
void updateSlideZoomText() {
slideZoom()->setText(
isDefaultWheelBehavior() ?
Strings::options_slide_zoom():
Strings::keyboard_shortcuts_slide_as_wheel());
}
void fillWheelActionsList() {
deleteList(wheelActions());
for (const KeyPtr& key : m_wheelKeys) {
KeyItem* keyItem = new KeyItem(
key->triggerString(), key, nullptr, 0, &m_headerItem);
wheelActions()->addChild(keyItem);
}
wheelActions()->sortItems();
}
void onWheelZoomChange() {
const bool isDefault = isDefaultWheelBehavior();
if (isDefault)
onWheelBehaviorChange();
}
void onSearchChange() {
base::ScopedValue<bool> flag(m_searchChange, true, false);
std::string searchText = search()->text();
@ -637,6 +754,7 @@ private:
commandsView()->setVisible(s == 1);
toolsView()->setVisible(s == 2);
actionsView()->setVisible(s == 3);
wheelSection()->setVisible(s == 4);
if (m_headerItem.parent())
m_headerItem.parent()->removeChild(&m_headerItem);
@ -645,7 +763,7 @@ private:
else
m_listBoxes[s]->insertChild(0, &m_headerItem);
layout();
listsPlaceholder()->layout();
}
void onImport() {
@ -662,7 +780,6 @@ private:
filename.front(), KeySource::UserDefined);
fillAllLists();
layout();
}
void onExport() {
@ -682,7 +799,7 @@ private:
void onReset() {
if (ui::Alert::show(Strings::alerts_restore_all_shortcuts()) == 1) {
app::KeyboardShortcuts::instance()->reset();
layout();
listsPlaceholder()->layout();
}
}
@ -725,12 +842,39 @@ private:
}
}
// Adds missing WhellAction in m_wheelKeys
void addMissingWheelKeys() {
for (int wheelAction=int(WheelAction::First);
wheelAction<=int(WheelAction::Last); ++wheelAction) {
auto it = std::find_if(
m_wheelKeys.begin(), m_wheelKeys.end(),
[wheelAction](const KeyPtr& key) -> bool {
return key->wheelAction() == (WheelAction)wheelAction;
});
if (it == m_wheelKeys.end()) {
KeyPtr key = std::make_shared<Key>((WheelAction)wheelAction);
m_wheelKeys.push_back(key);
}
}
}
std::vector<ListBox*> m_listBoxes;
std::vector<KeyItem*> m_allKeyItems;
bool m_searchChange;
bool m_wasDefault;
HeaderItem m_headerItem;
Keys m_wheelKeys;
};
void KeyItem::onAccelChange(const Accelerator& accel)
{
if (m_key && m_key->type() == KeyType::WheelAction) {
auto window = dynamic_cast<KeyboardShortcutsWindow*>(this->window());
if (window)
window->disableWheelKey(accel);
}
}
} // anonymous namespace
class KeyboardShortcutsCommand : public Command {
@ -778,6 +922,26 @@ void KeyboardShortcutsCommand::onExecute(Context* context)
if (window.closer() == window.ok()) {
KeyboardShortcuts::instance()->UserChange();
// Save preferences in widgets that are bound to options automatically
{
Message* msg = new Message(kSavePreferencesMessage);
msg->setPropagateToChildren(msg);
window.sendMessage(msg);
}
if (window.isDefaultWheelBehavior()) {
for (KeyPtr& key : *KeyboardShortcuts::instance()) {
if (key->type() == KeyType::WheelAction)
key->reset();
}
}
else {
for (const KeyPtr& srcKey : window.wheelKeys()) {
KeyPtr dstKey = KeyboardShortcuts::instance()->wheelAction(srcKey->wheelAction());
*dstKey = *srcKey;
}
}
// Save keyboard shortcuts in configuration file
{
ResourceFinder rf;

View File

@ -315,13 +315,7 @@ public:
rightClickBehavior()->addItem("Lasso");
rightClickBehavior()->setSelectedItemIndex((int)m_pref.editor.rightClickMode());
// Zoom with Scroll Wheel
wheelZoom()->setSelected(m_pref.editor.zoomWithWheel());
// Zoom sliding two fingers
#if __APPLE__
slideZoom()->setSelected(m_pref.editor.zoomWithSlide());
#else
#ifndef __APPLE__ // Zoom sliding two fingers option only on macOS
slideZoom()->setVisible(false);
#endif
@ -434,10 +428,6 @@ public:
m_pref.editor.autoScroll(autoScroll()->isSelected());
m_pref.editor.straightLinePreview(straightLinePreview()->isSelected());
m_pref.eyedropper.discardBrush(discardBrush()->isSelected());
m_pref.editor.zoomWithWheel(wheelZoom()->isSelected());
#if __APPLE__
m_pref.editor.zoomWithSlide(slideZoom()->isSelected());
#endif
m_pref.editor.rightClickMode(static_cast<app::gen::RightClickMode>(rightClickBehavior()->getSelectedItemIndex()));
m_pref.cursor.paintingCursorType(static_cast<app::gen::PaintingCursorType>(paintingCursorType()->getSelectedItemIndex()));
m_pref.cursor.cursorColor(cursorColor()->getColor());

View File

@ -24,6 +24,7 @@ FOR_EACH_COMMAND(BackgroundFromLayer)
FOR_EACH_COMMAND(BrightnessContrast)
FOR_EACH_COMMAND(Cancel)
FOR_EACH_COMMAND(CanvasSize)
FOR_EACH_COMMAND(CelOpacity)
FOR_EACH_COMMAND(CelProperties)
FOR_EACH_COMMAND(ChangeBrush)
FOR_EACH_COMMAND(ChangeColor)

View File

@ -12,11 +12,19 @@
#include "app/app.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/modules/palettes.h"
#include "app/pref/preferences.h"
#include "app/site.h"
#include "app/tools/active_tool.h"
#include "app/tools/tool_box.h"
#include "app/ui/color_bar.h"
#include "app/ui/editor/editor.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/toolbar.h"
#include "app/ui_context.h"
#include "base/string.h"
#include "doc/layer.h"
#include "doc/palette.h"
#include "ui/message.h"
#include "ui/theme.h"
@ -25,95 +33,96 @@ namespace app {
using namespace ui;
enum WHEEL_ACTION { WHEEL_NONE,
WHEEL_ZOOM,
WHEEL_VSCROLL,
WHEEL_HSCROLL,
WHEEL_FG,
WHEEL_BG,
WHEEL_FRAME };
bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
{
gfx::Point delta = msg->wheelDelta();
double dz = delta.x + delta.y;
WHEEL_ACTION wheelAction = WHEEL_NONE;
WheelAction wheelAction = WheelAction::None;
bool scrollBigSteps = false;
// Alt+mouse wheel changes the fg/bg colors
if (msg->altPressed()) {
if (msg->shiftPressed())
wheelAction = WHEEL_BG;
if (KeyboardShortcuts::instance()->hasMouseWheelCustomization()) {
if (!Preferences::instance().editor.zoomWithSlide() && msg->preciseWheel())
wheelAction = WheelAction::VScroll;
else
wheelAction = WHEEL_FG;
wheelAction = KeyboardShortcuts::instance()
->getWheelActionFromMouseMessage(KeyContext::MouseWheel, msg);
}
// Normal behavior: mouse wheel zooms If the message is from a
// precise wheel i.e. a trackpad/touch-like device, we scroll by
// default.
else if (Preferences::instance().editor.zoomWithWheel() && !msg->preciseWheel()) {
if (msg->ctrlPressed())
wheelAction = WHEEL_FRAME;
else if (delta.x != 0 || msg->shiftPressed())
wheelAction = WHEEL_HSCROLL;
else
wheelAction = WHEEL_ZOOM;
}
// Zoom sliding two fingers
else if (Preferences::instance().editor.zoomWithSlide() && msg->preciseWheel()) {
if (msg->ctrlPressed())
wheelAction = WHEEL_FRAME;
else if (std::abs(delta.x) > std::abs(delta.y)) {
delta.y = 0;
dz = delta.x;
wheelAction = WHEEL_HSCROLL;
}
else if (msg->shiftPressed()) {
delta.x = 0;
dz = delta.y;
wheelAction = WHEEL_VSCROLL;
}
else {
delta.x = 0;
dz = delta.y;
wheelAction = WHEEL_ZOOM;
}
}
// For laptops, it's convenient to that Ctrl+wheel zoom (because
// it's the "pinch" gesture).
// Default behavior
// TODO replace this code using KeyboardShortcuts::getDefaultMouseWheelTable()
else {
if (msg->ctrlPressed())
wheelAction = WHEEL_ZOOM;
else if (delta.x != 0 || msg->shiftPressed())
wheelAction = WHEEL_HSCROLL;
else
wheelAction = WHEEL_VSCROLL;
// Alt+mouse wheel changes the fg/bg colors
if (msg->altPressed()) {
if (msg->shiftPressed())
wheelAction = WheelAction::BgColor;
else
wheelAction = WheelAction::FgColor;
}
// Normal behavior: mouse wheel zooms If the message is from a
// precise wheel i.e. a trackpad/touch-like device, we scroll by
// default.
else if (Preferences::instance().editor.zoomWithWheel() && !msg->preciseWheel()) {
if (msg->ctrlPressed())
wheelAction = WheelAction::Frame;
else if (delta.x != 0 || msg->shiftPressed())
wheelAction = WheelAction::HScroll;
else
wheelAction = WheelAction::Zoom;
}
// Zoom sliding two fingers
else if (Preferences::instance().editor.zoomWithSlide() && msg->preciseWheel()) {
if (msg->ctrlPressed())
wheelAction = WheelAction::Frame;
else if (std::abs(delta.x) > std::abs(delta.y)) {
delta.y = 0;
dz = delta.x;
wheelAction = WheelAction::HScroll;
}
else if (msg->shiftPressed()) {
delta.x = 0;
dz = delta.y;
wheelAction = WheelAction::VScroll;
}
else {
delta.x = 0;
dz = delta.y;
wheelAction = WheelAction::Zoom;
}
}
// For laptops, it's convenient to that Ctrl+wheel zoom (because
// it's the "pinch" gesture).
else {
if (msg->ctrlPressed())
wheelAction = WheelAction::Zoom;
else if (delta.x != 0 || msg->shiftPressed())
wheelAction = WheelAction::HScroll;
else
wheelAction = WheelAction::VScroll;
}
}
switch (wheelAction) {
case WHEEL_NONE:
case WheelAction::None:
// Do nothing
break;
case WHEEL_FG:
{
int lastIndex = get_current_palette()->size()-1;
int newIndex = ColorBar::instance()->getFgColor().getIndex() + int(dz);
newIndex = MID(0, newIndex, lastIndex);
ColorBar::instance()->setFgColor(app::Color::fromIndex(newIndex));
}
case WheelAction::FgColor: {
int lastIndex = get_current_palette()->size()-1;
int newIndex = ColorBar::instance()->getFgColor().getIndex() + int(dz);
newIndex = MID(0, newIndex, lastIndex);
ColorBar::instance()->setFgColor(app::Color::fromIndex(newIndex));
break;
}
case WHEEL_BG:
{
int lastIndex = get_current_palette()->size()-1;
int newIndex = ColorBar::instance()->getBgColor().getIndex() + int(dz);
newIndex = MID(0, newIndex, lastIndex);
ColorBar::instance()->setBgColor(app::Color::fromIndex(newIndex));
}
case WheelAction::BgColor: {
int lastIndex = get_current_palette()->size()-1;
int newIndex = ColorBar::instance()->getBgColor().getIndex() + int(dz);
newIndex = MID(0, newIndex, lastIndex);
ColorBar::instance()->setBgColor(app::Color::fromIndex(newIndex));
break;
}
case WHEEL_FRAME: {
case WheelAction::Frame: {
Command* command = nullptr;
if (dz < 0.0)
@ -126,7 +135,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
break;
}
case WHEEL_ZOOM: {
case WheelAction::Zoom: {
render::Zoom zoom = editor->zoom();
if (msg->preciseWheel()) {
@ -141,15 +150,15 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
break;
}
case WHEEL_HSCROLL:
case WHEEL_VSCROLL: {
case WheelAction::HScroll:
case WheelAction::VScroll: {
View* view = View::getView(editor);
gfx::Point scroll = view->viewScroll();
if (!msg->preciseWheel()) {
gfx::Rect vp = view->viewportBounds();
if (wheelAction == WHEEL_HSCROLL) {
if (wheelAction == WheelAction::HScroll) {
delta.x = int(dz * vp.w);
}
else {
@ -168,6 +177,191 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
break;
}
case WheelAction::BrushSize: {
tools::Tool* tool = App::instance()->activeToolManager()->activeTool();
ToolPreferences::Brush& brush =
Preferences::instance().tool(tool).brush;
brush.size(MID(doc::Brush::kMinBrushSize,
brush.size()+dz,
doc::Brush::kMaxBrushSize));
break;
}
case WheelAction::BrushAngle: {
tools::Tool* tool = App::instance()->activeToolManager()->activeTool();
ToolPreferences::Brush& brush =
Preferences::instance().tool(tool).brush;
int angle = brush.angle()+dz;
while (angle < 0)
angle += 180;
angle %= 181;
brush.angle(MID(0, angle, 180));
break;
}
case WheelAction::ToolSameGroup: {
tools::Tool* tool = App::instance()->activeToolManager()->selectedTool();
auto toolBox = App::instance()->toolBox();
std::vector<tools::Tool*> tools;
for (tools::Tool* t : *toolBox) {
if (tool->getGroup() == t->getGroup())
tools.push_back(t);
}
auto begin = tools.begin();
auto end = tools.end();
auto it = std::find(begin, end, tool);
if (it != end) {
if (dz < 0) {
if (it == begin)
it = end;
--it;
}
else {
++it;
if (it == end)
it = begin;
}
if (tool != *it)
ToolBar::instance()->selectTool(*it);
}
break;
}
case WheelAction::ToolOtherGroup: {
tools::Tool* tool = App::instance()->activeToolManager()->selectedTool();
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) {
if (it == begin)
it = end;
--it;
}
else {
++it;
if (it == end)
it = begin;
}
ToolBar::instance()->selectToolGroup(*it);
}
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);
break;
}
case WheelAction::InkOpacity: {
tools::Tool* tool = App::instance()->activeToolManager()->activeTool();
auto& toolPref = Preferences::instance().tool(tool);
int opacity = toolPref.opacity();
opacity = MID(0, opacity+dz*255/10, 255);
toolPref.opacity(opacity);
break;
}
case WheelAction::LayerOpacity: {
Site site = UIContext::instance()->activeSite();
if (site.layer() &&
site.layer()->isImage() &&
site.layer()->isEditable()) {
Command* command = Commands::instance()->byId(CommandId::LayerOpacity());
if (command) {
int opacity = static_cast<doc::LayerImage*>(site.layer())->opacity();
opacity = MID(0, opacity+dz*255/10, 255);
Params params;
params.set("opacity",
base::convert_to<std::string>(opacity).c_str());
UIContext::instance()->executeCommand(command, params);
}
}
break;
}
case WheelAction::CelOpacity: {
Site site = UIContext::instance()->activeSite();
if (site.layer() &&
site.layer()->isImage() &&
site.layer()->isEditable() &&
site.cel()) {
Command* command = Commands::instance()->byId(CommandId::CelOpacity());
if (command) {
int opacity = site.cel()->opacity();
opacity = MID(0, opacity+dz*255/10, 255);
Params params;
params.set("opacity",
base::convert_to<std::string>(opacity).c_str());
UIContext::instance()->executeCommand(command, params);
}
}
break;
}
case WheelAction::Alpha: {
ColorBar* colorBar = ColorBar::instance();
Color c = colorBar->getFgColor();
int a = c.getAlpha();
a = MID(0, a+dz*255/10, 255);
c.setAlpha(a);
colorBar->setFgColor(c);
break;
}
case WheelAction::HslHue:
case WheelAction::HslSaturation:
case WheelAction::HslLightness: {
ColorBar* colorBar = ColorBar::instance();
Color c = colorBar->getFgColor();
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;
}
colorBar->setFgColor(Color::fromHsl(MID(0.0, h, 360.0),
MID(0.0, s, 1.0),
MID(0.0, l, 1.0)));
break;
}
case WheelAction::HsvHue:
case WheelAction::HsvSaturation:
case WheelAction::HsvValue: {
ColorBar* colorBar = ColorBar::instance();
Color c = colorBar->getFgColor();
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;
}
colorBar->setFgColor(Color::fromHsv(MID(0.0, h, 360.0),
MID(0.0, s, 1.0),
MID(0.0, v, 1.0)));
break;
}
}
return true;

View File

@ -37,6 +37,7 @@ namespace app {
Tool,
Quicktool,
Action,
WheelAction,
};
// TODO This should be called "KeyActionModifier" or something similar
@ -61,6 +62,35 @@ namespace app {
RotateShape = 0x00010000,
};
enum class WheelAction {
None,
Zoom,
VScroll,
HScroll,
FgColor,
BgColor,
Frame,
BrushSize,
BrushAngle,
ToolSameGroup,
ToolOtherGroup,
Layer,
InkOpacity,
LayerOpacity,
CelOpacity,
Alpha,
HslHue,
HslSaturation,
HslLightness,
HsvHue,
HsvSaturation,
HsvValue,
// Range
First = Zoom,
Last = HsvValue,
};
inline KeyAction operator&(KeyAction a, KeyAction b) {
return KeyAction(int(a) & int(b));
}
@ -70,6 +100,7 @@ namespace app {
Key(Command* command, const Params& params, KeyContext keyContext);
Key(KeyType type, tools::Tool* tool);
explicit Key(KeyAction action);
explicit Key(WheelAction action);
KeyType type() const { return m_type; }
const ui::Accelerators& accels() const {
@ -80,7 +111,7 @@ namespace app {
const ui::Accelerators& userRemovedAccels() const { return m_userRemoved; }
void add(const ui::Accelerator& accel, KeySource source);
bool isPressed(ui::Message* msg) const;
bool isPressed(const ui::Message* msg) const;
bool isPressed() const;
bool isLooselyPressed() const;
@ -90,6 +121,8 @@ namespace app {
// Resets user accelerators to the original ones.
void reset();
void copyOriginalToUser();
// for KeyType::Command
Command* command() const { return m_command; }
const Params& params() const { return m_params; }
@ -98,6 +131,8 @@ namespace app {
tools::Tool* tool() const { return m_tool; }
// for KeyType::Action
KeyAction action() const { return m_action; }
// for KeyType::WheelAction
WheelAction wheelAction() const { return m_wheelAction; }
std::string triggerString() const;
@ -116,6 +151,8 @@ namespace app {
tools::Tool* m_tool;
// for KeyType::Action
KeyAction m_action;
// for KeyType::WheelAction
WheelAction m_wheelAction;
};
typedef std::shared_ptr<Key> KeyPtr;
@ -131,6 +168,9 @@ namespace base {
template<> app::KeyAction convert_to(const std::string& from);
template<> std::string convert_to(const app::KeyAction& from);
template<> app::WheelAction convert_to(const std::string& from);
template<> std::string convert_to(const app::WheelAction& from);
} // namespace base
#endif

View File

@ -20,6 +20,7 @@ namespace app {
MoveTool,
FreehandTool,
ShapeTool,
MouseWheel,
};
} // namespace app

View File

@ -54,8 +54,36 @@ namespace {
{ NULL , NULL , app::KeyAction::None }
};
const char* get_shortcut(TiXmlElement* elem)
{
static struct {
const char* name;
const char* userfriendly;
app::WheelAction action;
} 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 },
{ "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 }
};
const char* get_shortcut(TiXmlElement* elem) {
const char* shortcut = NULL;
#ifdef _WIN32
@ -72,13 +100,20 @@ namespace {
return shortcut;
}
std::string get_user_friendly_string_for_keyaction(app::KeyAction action)
{
std::string get_user_friendly_string_for_keyaction(app::KeyAction action) {
for (int c=0; actions[c].name; ++c) {
if (action == actions[c].action)
return actions[c].userfriendly;
}
return "";
return std::string();
}
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;
}
return std::string();
}
} // anonymous namespace
@ -87,12 +122,10 @@ namespace base {
template<> app::KeyAction convert_to(const std::string& from) {
app::KeyAction action = app::KeyAction::None;
for (int c=0; actions[c].name; ++c) {
if (from == actions[c].name)
return actions[c].action;
}
return action;
}
@ -104,6 +137,23 @@ namespace base {
return "";
}
template<> app::WheelAction convert_to(const std::string& from) {
app::WheelAction action = app::WheelAction::None;
for (int c=0; wheel_actions[c].name; ++c) {
if (from == wheel_actions[c].name)
return wheel_actions[c].action;
}
return action;
}
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;
}
return "";
}
} // namespace base
namespace app {
@ -178,6 +228,15 @@ Key::Key(KeyAction action)
}
}
Key::Key(WheelAction wheelAction)
: m_type(KeyType::WheelAction)
, m_useUsers(false)
, m_keycontext(KeyContext::MouseWheel)
, m_action(KeyAction::None)
, m_wheelAction(wheelAction)
{
}
void Key::add(const ui::Accelerator& accel, KeySource source)
{
Accelerators* accels = &m_accels;
@ -200,20 +259,31 @@ void Key::add(const ui::Accelerator& accel, KeySource source)
accels->add(accel);
}
bool Key::isPressed(Message* msg) const
bool Key::isPressed(const Message* msg) const
{
ASSERT(dynamic_cast<KeyMessage*>(msg) != NULL);
for (const Accelerator& accel : accels()) {
if (accel.isPressed(msg->modifiers(),
static_cast<KeyMessage*>(msg)->scancode(),
static_cast<KeyMessage*>(msg)->unicodeChar()) &&
(m_keycontext == KeyContext::Any ||
m_keycontext == KeyboardShortcuts::instance()->getCurrentKeyContext())) {
return true;
if (auto keyMsg = dynamic_cast<const KeyMessage*>(msg)) {
for (const Accelerator& accel : accels()) {
if (accel.isPressed(keyMsg->modifiers(),
keyMsg->scancode(),
keyMsg->unicodeChar()) &&
(m_keycontext == KeyContext::Any ||
m_keycontext == KeyboardShortcuts::instance()->getCurrentKeyContext())) {
return true;
}
}
}
else if (auto mouseMsg = dynamic_cast<const MouseMessage*>(msg)) {
for (const Accelerator& accel : accels()) {
if ((accel.modifiers() == mouseMsg->modifiers()) &&
(m_keycontext == KeyContext::Any ||
// TODO we could have multiple mouse wheel key-context,
// like "sprite editor" context, or "timeline" context,
// etc.
m_keycontext == KeyContext::MouseWheel)) {
return true;
}
}
}
return false;
}
@ -260,6 +330,13 @@ void Key::reset()
m_useUsers = false;
}
void Key::copyOriginalToUser()
{
m_users = m_accels;
m_userRemoved.clear();
m_useUsers = true;
}
std::string Key::triggerString() const
{
switch (m_type) {
@ -275,6 +352,8 @@ std::string Key::triggerString() const
}
case KeyType::Action:
return get_user_friendly_string_for_keyaction(m_action);
case KeyType::WheelAction:
return get_user_friendly_string_for_wheelaction(m_wheelAction);
}
return "Unknown";
}
@ -370,7 +449,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
}
// Load keyboard shortcuts for tools
// <gui><keyboard><tools><key>
// <keyboard><tools><key>
xmlKey = handle
.FirstChild("tools")
.FirstChild("key").ToElement();
@ -398,7 +477,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
}
// Load keyboard shortcuts for quicktools
// <gui><keyboard><quicktools><key>
// <keyboard><quicktools><key>
xmlKey = handle
.FirstChild("quicktools")
.FirstChild("key").ToElement();
@ -426,22 +505,52 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
}
// Load special keyboard shortcuts for sprite editor customization
// <gui><keyboard><spriteeditor>
// <keyboard><actions><key>
xmlKey = handle
.FirstChild("actions")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* tool_action = xmlKey->Attribute("action");
const char* tool_key = get_shortcut(xmlKey);
const char* action_id = xmlKey->Attribute("action");
const char* action_key = get_shortcut(xmlKey);
bool removed = bool_attr_is_true(xmlKey, "removed");
if (tool_action) {
KeyAction action = base::convert_to<KeyAction, std::string>(tool_action);
if (action_id) {
KeyAction action = base::convert_to<KeyAction, std::string>(action_id);
if (action != KeyAction::None) {
KeyPtr key = this->action(action);
if (key && tool_key) {
LOG(VERBOSE) << "KEYS: Shortcut for action " << tool_action << ": " << tool_key << "\n";
Accelerator accel(tool_key);
if (key && action_key) {
LOG(VERBOSE) << "KEYS: Shortcut for action " << action_id
<< ": " << action_key << "\n";
Accelerator accel(action_key);
if (!removed)
key->add(accel, source);
else
key->disableAccel(accel);
}
}
}
xmlKey = xmlKey->NextSiblingElement();
}
// Load special keyboard shortcuts for mouse wheel customization
// <keyboard><wheel><key>
xmlKey = handle
.FirstChild("wheel")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* action_id = xmlKey->Attribute("action");
const char* action_key = get_shortcut(xmlKey);
bool removed = bool_attr_is_true(xmlKey, "removed");
if (action_id) {
WheelAction action = base::convert_to<WheelAction, std::string>(action_id);
if (action != WheelAction::None) {
KeyPtr key = this->wheelAction(action);
if (key && action_key) {
LOG(VERBOSE) << "KEYS: Shortcut for wheel action " << action_id
<< ": " << action_key << "\n";
Accelerator accel(action_key);
if (!removed)
key->add(accel, source);
@ -472,6 +581,7 @@ void KeyboardShortcuts::exportFile(const std::string& filename)
TiXmlElement tools("tools");
TiXmlElement quicktools("quicktools");
TiXmlElement actions("actions");
TiXmlElement wheel("wheel");
keyboard.SetAttribute("version", XML_KEYBOARD_FILE_VERSION);
@ -479,11 +589,13 @@ void KeyboardShortcuts::exportFile(const std::string& filename)
exportKeys(tools, KeyType::Tool);
exportKeys(quicktools, KeyType::Quicktool);
exportKeys(actions, KeyType::Action);
exportKeys(wheel, KeyType::WheelAction);
keyboard.InsertEndChild(commands);
keyboard.InsertEndChild(tools);
keyboard.InsertEndChild(quicktools);
keyboard.InsertEndChild(actions);
keyboard.InsertEndChild(wheel);
TiXmlDeclaration declaration("1.0", "utf-8", "");
doc->InsertEndChild(declaration);
@ -540,6 +652,11 @@ void KeyboardShortcuts::exportAccel(TiXmlElement& parent, const Key* key, const
elem.SetAttribute("action",
base::convert_to<std::string>(key->action()).c_str());
break;
case KeyType::WheelAction:
elem.SetAttribute("action",
base::convert_to<std::string>(key->wheelAction()).c_str());
break;
}
elem.SetAttribute("shortcut", accel.toString().c_str());
@ -618,6 +735,20 @@ KeyPtr KeyboardShortcuts::action(KeyAction action)
return key;
}
KeyPtr KeyboardShortcuts::wheelAction(WheelAction wheelAction)
{
for (KeyPtr& key : m_keys) {
if (key->type() == KeyType::WheelAction &&
key->wheelAction() == wheelAction) {
return key;
}
}
KeyPtr key = std::make_shared<Key>(wheelAction);
m_keys.push_back(key);
return key;
}
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
const KeyContext keyContext,
const Key* newKey)
@ -646,7 +777,7 @@ KeyContext KeyboardShortcuts::getCurrentKeyContext()
return KeyContext::Normal;
}
bool KeyboardShortcuts::getCommandFromKeyMessage(Message* msg, Command** command, Params* params)
bool KeyboardShortcuts::getCommandFromKeyMessage(const Message* msg, Command** command, Params* params)
{
for (KeyPtr& key : m_keys) {
if (key->type() == KeyType::Command && key->isPressed(msg)) {
@ -685,7 +816,7 @@ KeyAction KeyboardShortcuts::getCurrentActionModifiers(KeyContext context)
{
KeyAction flags = KeyAction::None;
for (KeyPtr& key : m_keys) {
for (const KeyPtr& key : m_keys) {
if (key->type() == KeyType::Action &&
key->keycontext() == context &&
key->isLooselyPressed()) {
@ -696,6 +827,64 @@ KeyAction KeyboardShortcuts::getCurrentActionModifiers(KeyContext context)
return flags;
}
WheelAction KeyboardShortcuts::getWheelActionFromMouseMessage(const KeyContext context,
const ui::Message* msg)
{
for (const KeyPtr& key : m_keys) {
if (key->type() == KeyType::WheelAction &&
key->keycontext() == context &&
key->isPressed(msg))
return key->wheelAction();
}
return WheelAction::None;
}
bool KeyboardShortcuts::hasMouseWheelCustomization() const
{
for (const KeyPtr& key : m_keys) {
if (key->type() == KeyType::WheelAction &&
!key->userAccels().empty())
return true;
}
return false;
}
Keys KeyboardShortcuts::getDefaultMouseWheelTable(const bool zoomWithWheel) const
{
Keys keys;
KeyPtr key;
key = std::make_shared<Key>(WheelAction::Zoom);
key->add(Accelerator(zoomWithWheel ? kKeyNoneModifier: kKeyCtrlModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
if (!zoomWithWheel) {
key = std::make_shared<Key>(WheelAction::VScroll);
key->add(Accelerator(kKeyNoneModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
}
key = std::make_shared<Key>(WheelAction::HScroll);
key->add(Accelerator(kKeyShiftModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
key = std::make_shared<Key>(WheelAction::FgColor);
key->add(Accelerator(kKeyAltModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
key = std::make_shared<Key>(WheelAction::BgColor);
key->add(Accelerator((KeyModifiers)(kKeyAltModifier | kKeyShiftModifier), kKeyNil, 0), KeySource::Original);
keys.push_back(key);
if (zoomWithWheel) {
key = std::make_shared<Key>(WheelAction::Frame);
key->add(Accelerator(kKeyCtrlModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
}
return keys;
}
std::string key_tooltip(const char* str, const app::Key* key)
{
std::string res;

View File

@ -40,15 +40,20 @@ namespace app {
KeyPtr tool(tools::Tool* tool);
KeyPtr quicktool(tools::Tool* tool);
KeyPtr action(KeyAction action);
KeyPtr wheelAction(WheelAction action);
void disableAccel(const ui::Accelerator& accel,
const KeyContext keyContext,
const Key* newKey);
KeyContext getCurrentKeyContext();
bool getCommandFromKeyMessage(ui::Message* msg, Command** command, Params* params);
bool getCommandFromKeyMessage(const ui::Message* msg, Command** command, Params* params);
tools::Tool* getCurrentQuicktool(tools::Tool* currentTool);
KeyAction getCurrentActionModifiers(KeyContext context);
WheelAction getWheelActionFromMouseMessage(const KeyContext context,
const ui::Message* msg);
bool hasMouseWheelCustomization() const;
Keys getDefaultMouseWheelTable(const bool zoomWithWheel) const;
// Generated when the tooltips are modified by the user.
// Useful to regenerate tooltips with shortcuts.

View File

@ -89,6 +89,7 @@ SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel, KeyContext ke
: m_keyField(new KeyField(accel))
, m_keyContext(keyContext)
, m_accel(accel)
, m_ok(false)
, m_modified(false)
{
updateModifiers();
@ -149,6 +150,7 @@ void SelectAccelerator::onClear()
void SelectAccelerator::onOK()
{
m_ok = true;
m_modified = (m_origAccel != m_accel);
closeWindow(NULL);
}

View File

@ -20,6 +20,7 @@ namespace app {
public:
SelectAccelerator(const ui::Accelerator& accelerator, KeyContext keyContext);
bool isOK() const { return m_ok; }
bool isModified() const { return m_modified; }
const ui::Accelerator& accel() const { return m_accel; }
@ -39,6 +40,7 @@ namespace app {
KeyContext m_keyContext;
ui::Accelerator m_origAccel;
ui::Accelerator m_accel;
bool m_ok;
bool m_modified;
};

View File

@ -564,6 +564,14 @@ void ToolBar::selectTool(Tool* tool)
invalidate();
}
void ToolBar::selectToolGroup(tools::ToolGroup* toolGroup)
{
ASSERT(toolGroup);
ASSERT(m_selectedInGroup[toolGroup]);
if (m_selectedInGroup[toolGroup])
selectTool(m_selectedInGroup[toolGroup]);
}
void ToolBar::onClosePopup()
{
closeTipWindow();

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -43,8 +43,9 @@ namespace app {
bool isToolVisible(tools::Tool* tool);
void selectTool(tools::Tool* tool);
void selectToolGroup(tools::ToolGroup* toolGroup);
void openTipWindow(tools::ToolGroup* tool_group, tools::Tool* tool);
void openTipWindow(tools::ToolGroup* toolGroup, tools::Tool* tool);
void closeTipWindow();
protected: