Add touch magnify event to support OS X trackpad gesture

This commit is contained in:
David Capello 2016-02-18 13:58:45 -03:00
parent ef4a4822da
commit 15e10ad9f6
12 changed files with 165 additions and 33 deletions

View File

@ -361,6 +361,12 @@ void Editor::setZoom(const render::Zoom& zoom)
m_zoom = zoom;
notifyZoomChanged();
}
else {
// Just copy the zoom as the internal "Zoom::m_internalScale"
// value might be different and we want to keep this value updated
// for better zooming experience in StateWithWheelBehavior.
m_zoom = zoom;
}
}
void Editor::setDefaultScroll()
@ -1273,6 +1279,13 @@ bool Editor::onProcessMessage(Message* msg)
}
break;
case kTouchMagnifyMessage:
if (m_sprite) {
EditorStatePtr holdState(m_state);
return m_state->onTouchMagnify(this, static_cast<TouchMessage*>(msg));
}
break;
case kKeyDownMessage:
if (m_sprite) {
EditorStatePtr holdState(m_state);
@ -1488,9 +1501,9 @@ void Editor::setZoomAndCenterInMouse(const Zoom& zoom,
padding.x - (screenPos.x-vp.x) + zoom.apply(spritePos.x+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.x)),
padding.y - (screenPos.y-vp.y) + zoom.apply(spritePos.y+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.y)));
if ((m_zoom != zoom) || (screenPos != view->viewScroll())) {
setZoom(zoom);
setZoom(zoom);
if ((m_zoom != zoom) || (screenPos != view->viewScroll())) {
updateEditor();
setEditorScroll(scrollPos);
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -18,8 +18,9 @@ namespace gfx {
}
namespace ui {
class MouseMessage;
class KeyMessage;
class MouseMessage;
class TouchMessage;
}
namespace app {
@ -85,6 +86,9 @@ namespace app {
// Called when the user moves the mouse wheel over the editor.
virtual bool onMouseWheel(Editor* editor, ui::MouseMessage* msg) { return false; }
// Called when the user wants to zoom in/out using a pinch gesture in the trackpad.
virtual bool onTouchMagnify(Editor* editor, ui::TouchMessage* msg) { return false; }
// Called each time the mouse changes its position so we can set an
// appropiated cursor depending on the new coordinates of the mouse
// pointer.

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -36,7 +36,7 @@ enum WHEEL_ACTION { WHEEL_NONE,
bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
{
int dz = msg->wheelDelta().x + msg->wheelDelta().y;
double dz = msg->wheelDelta().x + msg->wheelDelta().y;
WHEEL_ACTION wheelAction = WHEEL_NONE;
bool scrollBigSteps = false;
@ -79,7 +79,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
if (ColorBar::instance()->getFgColor().getType() == app::Color::IndexType) {
int lastIndex = get_current_palette()->size()-1;
newIndex = ColorBar::instance()->getFgColor().getIndex() + dz;
newIndex = ColorBar::instance()->getFgColor().getIndex() + int(dz);
newIndex = MID(0, newIndex, lastIndex);
}
ColorBar::instance()->setFgColor(app::Color::fromIndex(newIndex));
@ -92,7 +92,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
if (ColorBar::instance()->getBgColor().getType() == app::Color::IndexType) {
int lastIndex = get_current_palette()->size()-1;
newIndex = ColorBar::instance()->getBgColor().getIndex() + dz;
newIndex = ColorBar::instance()->getBgColor().getIndex() + int(dz);
newIndex = MID(0, newIndex, lastIndex);
}
ColorBar::instance()->setBgColor(app::Color::fromIndex(newIndex));
@ -102,27 +102,25 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
case WHEEL_FRAME:
{
Command* command = CommandsModule::instance()->getCommandByName
((dz < 0) ? CommandId::GotoNextFrame:
CommandId::GotoPreviousFrame);
((dz < 0.0) ? CommandId::GotoNextFrame:
CommandId::GotoPreviousFrame);
if (command)
UIContext::instance()->executeCommand(command);
}
break;
case WHEEL_ZOOM: {
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
render::Zoom zoom = editor->zoom();
zoom = render::Zoom::fromLinearScale(zoom.linearScale() - dz);
if (editor->zoom() != zoom) {
bool center = Preferences::instance().editor.zoomFromCenterWithWheel();
editor->setZoomAndCenterInMouse(
zoom, mouseMsg->position(),
(center ? Editor::ZoomBehavior::CENTER:
Editor::ZoomBehavior::MOUSE));
if (msg->preciseWheel()) {
dz /= 1.5;
if (dz < -1.0) dz = -1.0;
else if (dz > 1.0) dz = 1.0;
}
zoom = render::Zoom::fromLinearScale(zoom.linearScale() - int(dz));
setZoom(editor, zoom, msg->position());
break;
}
@ -139,10 +137,10 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
gfx::Rect vp = view->viewportBounds();
if (wheelAction == WHEEL_HSCROLL) {
delta.x = dz * vp.w;
delta.x = int(dz * vp.w);
}
else {
delta.y = dz * vp.h;
delta.y = int(dz * vp.h);
}
if (scrollBigSteps) {
@ -162,4 +160,26 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
return true;
}
bool StateWithWheelBehavior::onTouchMagnify(Editor* editor, ui::TouchMessage* msg)
{
render::Zoom zoom = editor->zoom();
zoom = render::Zoom::fromScale(
zoom.internalScale() + zoom.internalScale() * msg->magnification());
setZoom(editor, zoom, msg->position());
return true;
}
void StateWithWheelBehavior::setZoom(Editor* editor,
const render::Zoom& zoom,
const gfx::Point& mousePos)
{
bool center = Preferences::instance().editor.zoomFromCenterWithWheel();
editor->setZoomAndCenterInMouse(
zoom, mousePos,
(center ? Editor::ZoomBehavior::CENTER:
Editor::ZoomBehavior::MOUSE));
}
} // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -11,11 +11,18 @@
#include "app/ui/editor/editor_state.h"
namespace render {
class Zoom;
}
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;
private:
void setZoom(Editor* editor, const render::Zoom& zoom, const gfx::Point& mousePos);
};
} // namespace app

View File

@ -34,6 +34,15 @@ static int scales[][2] = {
static int scales_size = sizeof(scales) / sizeof(scales[0]);
Zoom::Zoom(int num, int den)
: m_num(num)
, m_den(den)
{
ASSERT(m_num > 0);
ASSERT(m_den > 0);
m_internalScale = scale();
}
void Zoom::in()
{
int i = linearScale();
@ -41,6 +50,7 @@ void Zoom::in()
++i;
m_num = scales[i][0];
m_den = scales[i][1];
m_internalScale = scale();
}
}
@ -51,6 +61,7 @@ void Zoom::out()
--i;
m_num = scales[i][0];
m_den = scales[i][1];
m_internalScale = scale();
}
}
@ -69,7 +80,9 @@ int Zoom::linearScale() const
// static
Zoom Zoom::fromScale(double scale)
{
return fromLinearScale(findClosestLinearScale(scale));
Zoom zoom = fromLinearScale(findClosestLinearScale(scale));
zoom.m_internalScale = scale;
return zoom;
}
// static

View File

@ -14,13 +14,16 @@ namespace render {
class Zoom {
public:
Zoom(int num, int den)
: m_num(num), m_den(den) {
ASSERT(m_num > 0);
ASSERT(m_den > 0);
Zoom(int num, int den);
double scale() const {
return static_cast<double>(m_num) / static_cast<double>(m_den);
}
double scale() const { return static_cast<double>(m_num) / static_cast<double>(m_den); }
// This value isn't used in operator==() or operator!=()
double internalScale() const {
return m_internalScale;
}
template<typename T>
T apply(T x) const {
@ -72,6 +75,9 @@ namespace render {
int m_num;
int m_den;
// Internal scale value used for precise zooming purposes.
double m_internalScale;
};
} // namespace render

View File

@ -1,5 +1,5 @@
// SHE library
// Copyright (C) 2012-2015 David Capello
// Copyright (C) 2012-2016 David Capello
//
// This source file is ditributed under a BSD-like license, please
// read LICENSE.txt for more information.
@ -35,6 +35,7 @@ namespace she {
MouseDoubleClick,
KeyDown,
KeyUp,
TouchMagnify,
};
enum MouseButton {
@ -67,6 +68,7 @@ namespace she {
gfx::Point wheelDelta() const { return m_wheelDelta; }
bool preciseWheel() const { return m_preciseWheel; }
MouseButton button() const { return m_button; }
double magnification() const { return m_magnification; }
void setType(Type type) { m_type = type; }
void setDisplay(Display* display) { m_display = display; }
@ -80,6 +82,7 @@ namespace she {
void setWheelDelta(const gfx::Point& delta) { m_wheelDelta = delta; }
void setPreciseWheel(bool precise) { m_preciseWheel = precise; }
void setButton(MouseButton button) { m_button = button; }
void setMagnification(double magnification) { m_magnification = magnification; }
private:
Type m_type;
@ -93,6 +96,7 @@ namespace she {
gfx::Point m_wheelDelta;
bool m_preciseWheel;
MouseButton m_button;
double m_magnification;
};
} // namespace she

View File

@ -1,5 +1,5 @@
// SHE library
// Copyright (C) 2015 David Capello
// Copyright (C) 2015-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -370,6 +370,17 @@ bool is_key_pressed(KeyScancode scancode)
queue_event(ev);
}
- (void)magnifyWithEvent:(NSEvent*)event
{
Event ev;
ev.setType(Event::TouchMagnify);
ev.setMagnification(event.magnification);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setModifiers(get_modifiers_from_nsevent(event));
queue_event(ev);
}
- (void)cursorUpdate:(NSEvent*)event
{
[self updateCurrentCursor];

View File

@ -380,6 +380,16 @@ void Manager::generateMessagesFromSheEvents()
sheEvent.preciseWheel());
break;
}
case she::Event::TouchMagnify: {
_internal_set_mouse_position(sheEvent.position());
handleTouchMagnify(sheEvent.position(),
sheEvent.modifiers(),
sheEvent.magnification());
break;
}
}
}
@ -479,6 +489,24 @@ void Manager::handleMouseWheel(const gfx::Point& mousePos,
wheelDelta, preciseWheel));
}
void Manager::handleTouchMagnify(const gfx::Point& mousePos,
const KeyModifiers modifiers,
const double magnification)
{
Widget* widget = (capture_widget ? capture_widget: mouse_widget);
if (widget) {
Message* msg = new TouchMessage(
kTouchMagnifyMessage,
modifiers,
mousePos,
magnification);
msg->addRecipient(widget);
enqueueMessage(msg);
}
}
// Handles Z order: Send the window to top (only when you click in a
// window that aren't the desktop).
void Manager::handleWindowZOrder()
@ -1222,6 +1250,7 @@ void Manager::pumpQueue()
"kMouseMoveMessage",
"kSetCursorMessage",
"kMouseWheelMessage",
"kTouchMagnifyMessage",
};
const char* string =
(msg->type() >= kOpenMessage &&

View File

@ -123,6 +123,9 @@ namespace ui {
void handleMouseDoubleClick(const gfx::Point& mousePos, MouseButtons mouseButtons, KeyModifiers modifiers);
void handleMouseWheel(const gfx::Point& mousePos, MouseButtons mouseButtons, KeyModifiers modifiers,
const gfx::Point& wheelDelta, bool preciseWheel);
void handleTouchMagnify(const gfx::Point& mousePos,
const KeyModifiers modifiers,
const double magnification);
void handleWindowZOrder();
void pumpQueue();

View File

@ -1,5 +1,5 @@
// Aseprite UI Library
// Copyright (C) 2001-2013, 2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -129,6 +129,25 @@ namespace ui {
bool m_preciseWheel;
};
class TouchMessage : public Message {
public:
TouchMessage(MessageType type,
KeyModifiers modifiers,
const gfx::Point& pos,
double magnification)
: Message(type, modifiers),
m_pos(pos),
m_magnification(magnification) {
}
const gfx::Point& position() const { return m_pos; }
double magnification() const { return m_magnification; }
private:
gfx::Point m_pos; // Mouse position
double m_magnification;
};
class TimerMessage : public Message {
public:
TimerMessage(int count, Timer* timer)

View File

@ -1,5 +1,5 @@
// Aseprite UI Library
// Copyright (C) 2001-2013, 2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -38,6 +38,9 @@ namespace ui {
kSetCursorMessage, // A widget needs to setup the mouse cursor.
kMouseWheelMessage, // User moves the wheel.
// Touch related messages.
kTouchMagnifyMessage,
// TODO Drag'n'drop messages...
// k...DndMessage