mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-09 18:44:46 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
ab3bf31c6a
@ -1,5 +1,5 @@
|
|||||||
<!-- Aseprite -->
|
<!-- Aseprite -->
|
||||||
<!-- Copyright (C) 2018-2021 Igara Studio S.A. -->
|
<!-- Copyright (C) 2018-2022 Igara Studio S.A. -->
|
||||||
<!-- Copyright (C) 2018 David Capello -->
|
<!-- Copyright (C) 2018 David Capello -->
|
||||||
<gui i18nwarnings="false">
|
<gui i18nwarnings="false">
|
||||||
<window id="about" text="About Aseprite">
|
<window id="about" text="About Aseprite">
|
||||||
@ -25,7 +25,7 @@
|
|||||||
</hbox>
|
</hbox>
|
||||||
<separator horizontal="true" />
|
<separator horizontal="true" />
|
||||||
<hbox>
|
<hbox>
|
||||||
<label text="Copyright (C) 2001-2021" />
|
<label text="Copyright (C) 2001-2022" />
|
||||||
<link text="Igara Studio S.A." url="https://www.igarastudio.com/" />
|
<link text="Igara Studio S.A." url="https://www.igarastudio.com/" />
|
||||||
</hbox>
|
</hbox>
|
||||||
<link text="https://www.aseprite.org/" url="https://www.aseprite.org/" />
|
<link text="https://www.aseprite.org/" url="https://www.aseprite.org/" />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Aseprite
|
# Aseprite
|
||||||
# Copyright (C) 2018-2021 Igara Studio S.A.
|
# Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
# Copyright (C) 2001-2018 David Capello
|
# Copyright (C) 2001-2018 David Capello
|
||||||
|
|
||||||
# Generate a ui::Widget for each widget in a XML file
|
# Generate a ui::Widget for each widget in a XML file
|
||||||
@ -342,6 +342,7 @@ if(ENABLE_UI)
|
|||||||
ui/drop_down_button.cpp
|
ui/drop_down_button.cpp
|
||||||
ui/dynamics_popup.cpp
|
ui/dynamics_popup.cpp
|
||||||
ui/editor/brush_preview.cpp
|
ui/editor/brush_preview.cpp
|
||||||
|
ui/editor/delayed_mouse_move.cpp
|
||||||
ui/editor/drawing_state.cpp
|
ui/editor/drawing_state.cpp
|
||||||
ui/editor/editor.cpp
|
ui/editor/editor.cpp
|
||||||
ui/editor/editor_observers.cpp
|
ui/editor/editor_observers.cpp
|
||||||
|
95
src/app/ui/editor/delayed_mouse_move.cpp
Normal file
95
src/app/ui/editor/delayed_mouse_move.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// 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/delayed_mouse_move.h"
|
||||||
|
|
||||||
|
#include "app/ui/editor/editor.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
DelayedMouseMove::DelayedMouseMove(DelayedMouseMoveDelegate* delegate,
|
||||||
|
Editor* editor,
|
||||||
|
const int interval)
|
||||||
|
: m_delegate(delegate)
|
||||||
|
, m_editor(editor)
|
||||||
|
, m_timer(interval)
|
||||||
|
, m_spritePos(std::numeric_limits<double>::min(),
|
||||||
|
std::numeric_limits<double>::min())
|
||||||
|
{
|
||||||
|
ASSERT(m_delegate);
|
||||||
|
m_timer.Tick.connect([this] { commitMouseMove(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelayedMouseMove::initSpritePos(const gfx::PointF& pos)
|
||||||
|
{
|
||||||
|
m_spritePos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelayedMouseMove::onMouseDown(const ui::MouseMessage* msg)
|
||||||
|
{
|
||||||
|
updateSpritePos(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DelayedMouseMove::onMouseMove(const ui::MouseMessage* msg)
|
||||||
|
{
|
||||||
|
if (!updateSpritePos(msg))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_timer.isRunning()) {
|
||||||
|
if (m_timer.interval() > 0) {
|
||||||
|
m_timer.start();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Commit immediately
|
||||||
|
commitMouseMove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelayedMouseMove::onMouseUp(const ui::MouseMessage* msg)
|
||||||
|
{
|
||||||
|
updateSpritePos(msg);
|
||||||
|
commitMouseMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelayedMouseMove::commitMouseMove()
|
||||||
|
{
|
||||||
|
if (m_timer.isRunning())
|
||||||
|
m_timer.stop();
|
||||||
|
|
||||||
|
m_delegate->onCommitMouseMove(m_editor, spritePos());
|
||||||
|
}
|
||||||
|
|
||||||
|
const gfx::PointF& DelayedMouseMove::spritePos() const
|
||||||
|
{
|
||||||
|
ASSERT(m_spritePos.x != std::numeric_limits<double>::min() &&
|
||||||
|
m_spritePos.y != std::numeric_limits<double>::min());
|
||||||
|
return m_spritePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DelayedMouseMove::updateSpritePos(const ui::MouseMessage* msg)
|
||||||
|
{
|
||||||
|
// The autoScroll() function controls the "infinite scroll" when we
|
||||||
|
// touch the viewport borders.
|
||||||
|
const gfx::Point mousePos = m_editor->autoScroll(msg, AutoScroll::MouseDir);
|
||||||
|
const gfx::PointF spritePos = m_editor->screenToEditorF(mousePos);
|
||||||
|
|
||||||
|
// Avoid redrawing everything if the position in the canvas didn't
|
||||||
|
// change.
|
||||||
|
if (m_spritePos != spritePos) {
|
||||||
|
m_spritePos = spritePos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
71
src/app/ui/editor/delayed_mouse_move.h
Normal file
71
src/app/ui/editor/delayed_mouse_move.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// 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_DELAYED_MOUSE_MOVE_STATE_H_INCLUDED
|
||||||
|
#define APP_UI_EDITOR_DELAYED_MOUSE_MOVE_STATE_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "app/ui/editor/standby_state.h"
|
||||||
|
#include "ui/timer.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
class MouseMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
class Editor;
|
||||||
|
|
||||||
|
class DelayedMouseMoveDelegate {
|
||||||
|
public:
|
||||||
|
virtual ~DelayedMouseMoveDelegate() { }
|
||||||
|
virtual void onCommitMouseMove(Editor* editor,
|
||||||
|
const gfx::PointF& spritePos) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper class to group several onMouseMove() calls into one
|
||||||
|
// onCommitMouseMove(). Useful in Linux as mouse movement messages
|
||||||
|
// are queued a high speed (so we can group several mouse messages
|
||||||
|
// for tools that use only the last position and have a heavy
|
||||||
|
// calculation per mouse position, e.g. pixel transformations,
|
||||||
|
// drawing with Line, Rectangle, etc.).
|
||||||
|
class DelayedMouseMove {
|
||||||
|
public:
|
||||||
|
// The "interval" is given in milliseconds, and can be zero if we
|
||||||
|
// want to disable the delay between onMouseMove() -> onCommitMouseMove()
|
||||||
|
DelayedMouseMove(DelayedMouseMoveDelegate* delegate,
|
||||||
|
Editor* editor,
|
||||||
|
const int interval);
|
||||||
|
|
||||||
|
// In case the event wasn't started with onMouseDown() we can
|
||||||
|
// initialize the sprite position directly (e.g. starting a line
|
||||||
|
// from last painted point with Shift+click with Pencil tool).
|
||||||
|
void initSpritePos(const gfx::PointF& pos);
|
||||||
|
|
||||||
|
void onMouseDown(const ui::MouseMessage* msg);
|
||||||
|
bool onMouseMove(const ui::MouseMessage* msg);
|
||||||
|
void onMouseUp(const ui::MouseMessage* msg);
|
||||||
|
|
||||||
|
const gfx::PointF& spritePos() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void commitMouseMove();
|
||||||
|
bool updateSpritePos(const ui::MouseMessage* msg);
|
||||||
|
|
||||||
|
DelayedMouseMoveDelegate* m_delegate;
|
||||||
|
Editor* m_editor;
|
||||||
|
ui::Timer m_timer;
|
||||||
|
|
||||||
|
// Position of the mouse in the canvas to avoid redrawing when the
|
||||||
|
// mouse position changes (only we redraw when the canvas position
|
||||||
|
// changes).
|
||||||
|
gfx::PointF m_spritePos;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif // APP_UI_EDITOR_DELAYED_MOUSE_MOVE_STATE_H_INCLUDED
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -42,11 +42,27 @@ namespace app {
|
|||||||
|
|
||||||
using namespace ui;
|
using namespace ui;
|
||||||
|
|
||||||
|
static int get_delay_interval_for_tool_loop(tools::ToolLoop* toolLoop)
|
||||||
|
{
|
||||||
|
if (toolLoop->getTracePolicy() == tools::TracePolicy::Last) {
|
||||||
|
// We use the delayed mouse movement for tools like Line,
|
||||||
|
// Rectangle, etc. (tools that use the last mouse position for its
|
||||||
|
// shape, so we can discard intermediate positions).
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Without delay for freehand-like tools
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DrawingState::DrawingState(Editor* editor,
|
DrawingState::DrawingState(Editor* editor,
|
||||||
tools::ToolLoop* toolLoop,
|
tools::ToolLoop* toolLoop,
|
||||||
const DrawingType type)
|
const DrawingType type)
|
||||||
: m_editor(editor)
|
: m_editor(editor)
|
||||||
, m_type(type)
|
, m_type(type)
|
||||||
|
, m_delayedMouseMove(this, editor,
|
||||||
|
get_delay_interval_for_tool_loop(toolLoop))
|
||||||
, m_toolLoop(toolLoop)
|
, m_toolLoop(toolLoop)
|
||||||
, m_toolLoopManager(new tools::ToolLoopManager(toolLoop))
|
, m_toolLoopManager(new tools::ToolLoopManager(toolLoop))
|
||||||
, m_mouseMoveReceived(false)
|
, m_mouseMoveReceived(false)
|
||||||
@ -64,8 +80,14 @@ DrawingState::~DrawingState()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DrawingState::initToolLoop(Editor* editor,
|
void DrawingState::initToolLoop(Editor* editor,
|
||||||
|
const ui::MouseMessage* msg,
|
||||||
const tools::Pointer& pointer)
|
const tools::Pointer& pointer)
|
||||||
{
|
{
|
||||||
|
if (msg)
|
||||||
|
m_delayedMouseMove.onMouseDown(msg);
|
||||||
|
else
|
||||||
|
m_delayedMouseMove.initSpritePos(gfx::PointF(pointer.point()));
|
||||||
|
|
||||||
Tileset* tileset = m_toolLoop->getDstTileset();
|
Tileset* tileset = m_toolLoop->getDstTileset();
|
||||||
|
|
||||||
// For selection inks we don't use a "the selected layer" for
|
// For selection inks we don't use a "the selected layer" for
|
||||||
@ -130,6 +152,8 @@ bool DrawingState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
m_velocity.velocity());
|
m_velocity.velocity());
|
||||||
m_lastPointer = pointer;
|
m_lastPointer = pointer;
|
||||||
|
|
||||||
|
m_delayedMouseMove.onMouseDown(msg);
|
||||||
|
|
||||||
// Check if this drawing state was started with a Shift+Pencil tool
|
// Check if this drawing state was started with a Shift+Pencil tool
|
||||||
// and now the user pressed the right button to draw the straight
|
// and now the user pressed the right button to draw the straight
|
||||||
// line with the background color.
|
// line with the background color.
|
||||||
@ -159,7 +183,7 @@ bool DrawingState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
// checkStartDrawingStraightLine() with the right-button.
|
// checkStartDrawingStraightLine() with the right-button.
|
||||||
if (recreateLoop && isCanceled) {
|
if (recreateLoop && isCanceled) {
|
||||||
ASSERT(!m_toolLoopManager);
|
ASSERT(!m_toolLoopManager);
|
||||||
checkStartDrawingStraightLine(editor, &pointer);
|
checkStartDrawingStraightLine(editor, msg, &pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -169,7 +193,8 @@ bool DrawingState::onMouseUp(Editor* editor, MouseMessage* msg)
|
|||||||
{
|
{
|
||||||
ASSERT(m_toolLoopManager != NULL);
|
ASSERT(m_toolLoopManager != NULL);
|
||||||
|
|
||||||
tools::Pointer pointer = pointer_from_msg(editor, msg, m_velocity.velocity());
|
m_lastPointer = pointer_from_msg(editor, msg, m_velocity.velocity());
|
||||||
|
m_delayedMouseMove.onMouseUp(msg);
|
||||||
|
|
||||||
// Selection tools with Replace mode are cancelled with a simple click.
|
// Selection tools with Replace mode are cancelled with a simple click.
|
||||||
// ("one point" controller selection tool i.e. the magic wand, and
|
// ("one point" controller selection tool i.e. the magic wand, and
|
||||||
@ -184,8 +209,6 @@ bool DrawingState::onMouseUp(Editor* editor, MouseMessage* msg)
|
|||||||
m_type == DrawingType::SelectTiles ||
|
m_type == DrawingType::SelectTiles ||
|
||||||
(editor->getToolLoopModifiers() != tools::ToolLoopModifiers::kReplaceSelection &&
|
(editor->getToolLoopModifiers() != tools::ToolLoopModifiers::kReplaceSelection &&
|
||||||
editor->getToolLoopModifiers() != tools::ToolLoopModifiers::kIntersectSelection)) {
|
editor->getToolLoopModifiers() != tools::ToolLoopModifiers::kIntersectSelection)) {
|
||||||
m_lastPointer = pointer;
|
|
||||||
|
|
||||||
// Notify the release of the mouse button to the tool loop
|
// Notify the release of the mouse button to the tool loop
|
||||||
// manager. This is the correct way to say "the user finishes the
|
// manager. This is the correct way to say "the user finishes the
|
||||||
// drawing trace correctly".
|
// drawing trace correctly".
|
||||||
@ -207,7 +230,7 @@ bool DrawingState::onMouseUp(Editor* editor, MouseMessage* msg)
|
|||||||
// button, if the Shift key is pressed, the whole ToolLoop starts
|
// button, if the Shift key is pressed, the whole ToolLoop starts
|
||||||
// again.
|
// again.
|
||||||
if (Preferences::instance().editor.straightLinePreview())
|
if (Preferences::instance().editor.straightLinePreview())
|
||||||
checkStartDrawingStraightLine(editor, &pointer);
|
checkStartDrawingStraightLine(editor, msg, &m_lastPointer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -228,19 +251,29 @@ bool DrawingState::onMouseMove(Editor* editor, MouseMessage* msg)
|
|||||||
// Update velocity sensor.
|
// Update velocity sensor.
|
||||||
m_velocity.updateWithDisplayPoint(msg->position());
|
m_velocity.updateWithDisplayPoint(msg->position());
|
||||||
|
|
||||||
// The autoScroll() function controls the "infinite scroll" when we
|
m_lastPointer = tools::Pointer(gfx::Point(m_delayedMouseMove.spritePos()),
|
||||||
// touch the viewport borders.
|
m_velocity.velocity(),
|
||||||
gfx::Point mousePos = editor->autoScroll(msg, AutoScroll::MouseDir);
|
button_from_msg(msg),
|
||||||
handleMouseMovement(
|
msg->pointerType(),
|
||||||
tools::Pointer(editor->screenToEditor(mousePos),
|
msg->pressure());
|
||||||
m_velocity.velocity(),
|
|
||||||
button_from_msg(msg),
|
|
||||||
msg->pointerType(),
|
|
||||||
msg->pressure()));
|
|
||||||
|
|
||||||
|
// Use DelayedMouseMove for tools like line, rectangle, etc. (that
|
||||||
|
// use the only the last mouse position) to filter out rapid mouse
|
||||||
|
// movement.
|
||||||
|
m_delayedMouseMove.onMouseMove(msg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawingState::onCommitMouseMove(Editor* editor,
|
||||||
|
const gfx::PointF& spritePos)
|
||||||
|
{
|
||||||
|
if (m_toolLoop &&
|
||||||
|
m_toolLoopManager &&
|
||||||
|
!m_toolLoopManager->isCanceled()) {
|
||||||
|
handleMouseMovement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DrawingState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
bool DrawingState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||||
{
|
{
|
||||||
if (m_toolLoop->getInk()->isEyedropper()) {
|
if (m_toolLoop->getInk()->isEyedropper()) {
|
||||||
@ -299,12 +332,12 @@ bool DrawingState::onScrollChange(Editor* editor)
|
|||||||
// Update velocity sensor.
|
// Update velocity sensor.
|
||||||
m_velocity.updateWithDisplayPoint(mousePos); // TODO add scroll as velocity?
|
m_velocity.updateWithDisplayPoint(mousePos); // TODO add scroll as velocity?
|
||||||
|
|
||||||
handleMouseMovement(
|
m_lastPointer = tools::Pointer(editor->screenToEditor(mousePos),
|
||||||
tools::Pointer(editor->screenToEditor(mousePos),
|
m_velocity.velocity(),
|
||||||
m_velocity.velocity(),
|
m_lastPointer.button(),
|
||||||
m_lastPointer.button(),
|
tools::Pointer::Type::Unknown,
|
||||||
tools::Pointer::Type::Unknown,
|
0.0f);
|
||||||
0.0f));
|
handleMouseMovement();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -332,14 +365,13 @@ bool DrawingState::getGridBounds(Editor* editor, gfx::Rect& gridBounds)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawingState::handleMouseMovement(const tools::Pointer& pointer)
|
void DrawingState::handleMouseMovement()
|
||||||
{
|
{
|
||||||
m_mouseMoveReceived = true;
|
m_mouseMoveReceived = true;
|
||||||
m_lastPointer = pointer;
|
|
||||||
|
|
||||||
// Notify mouse movement to the tool
|
// Notify mouse movement to the tool
|
||||||
ASSERT(m_toolLoopManager);
|
ASSERT(m_toolLoopManager);
|
||||||
m_toolLoopManager->movement(pointer);
|
m_toolLoopManager->movement(m_lastPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DrawingState::canExecuteCommands()
|
bool DrawingState::canExecuteCommands()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "app/tools/pointer.h"
|
#include "app/tools/pointer.h"
|
||||||
#include "app/tools/velocity.h"
|
#include "app/tools/velocity.h"
|
||||||
|
#include "app/ui/editor/delayed_mouse_move.h"
|
||||||
#include "app/ui/editor/standby_state.h"
|
#include "app/ui/editor/standby_state.h"
|
||||||
#include "obs/connection.h"
|
#include "obs/connection.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -23,7 +24,8 @@ namespace app {
|
|||||||
|
|
||||||
class CommandExecutionEvent;
|
class CommandExecutionEvent;
|
||||||
|
|
||||||
class DrawingState : public StandbyState {
|
class DrawingState : public StandbyState
|
||||||
|
, DelayedMouseMoveDelegate {
|
||||||
public:
|
public:
|
||||||
DrawingState(Editor* editor,
|
DrawingState(Editor* editor,
|
||||||
tools::ToolLoop* loop,
|
tools::ToolLoop* loop,
|
||||||
@ -47,6 +49,7 @@ namespace app {
|
|||||||
virtual bool getGridBounds(Editor* editor, gfx::Rect& gridBounds) override;
|
virtual bool getGridBounds(Editor* editor, gfx::Rect& gridBounds) override;
|
||||||
|
|
||||||
void initToolLoop(Editor* editor,
|
void initToolLoop(Editor* editor,
|
||||||
|
const ui::MouseMessage* msg,
|
||||||
const tools::Pointer& pointer);
|
const tools::Pointer& pointer);
|
||||||
|
|
||||||
// Used to send a movement() to the ToolLoopManager when
|
// Used to send a movement() to the ToolLoopManager when
|
||||||
@ -56,14 +59,19 @@ namespace app {
|
|||||||
void notifyToolLoopModifiersChange(Editor* editor);
|
void notifyToolLoopModifiersChange(Editor* editor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleMouseMovement(const tools::Pointer& pointer);
|
void handleMouseMovement();
|
||||||
bool canExecuteCommands();
|
bool canExecuteCommands();
|
||||||
void onBeforeCommandExecution(CommandExecutionEvent& ev);
|
void onBeforeCommandExecution(CommandExecutionEvent& ev);
|
||||||
void destroyLoopIfCanceled(Editor* editor);
|
void destroyLoopIfCanceled(Editor* editor);
|
||||||
void destroyLoop(Editor* editor);
|
void destroyLoop(Editor* editor);
|
||||||
|
|
||||||
|
// DelayedMouseMoveDelegate impl
|
||||||
|
void onCommitMouseMove(Editor* editor,
|
||||||
|
const gfx::PointF& spritePos) override;
|
||||||
|
|
||||||
Editor* m_editor;
|
Editor* m_editor;
|
||||||
DrawingType m_type;
|
DrawingType m_type;
|
||||||
|
DelayedMouseMove m_delayedMouseMove;
|
||||||
|
|
||||||
// The tool-loop.
|
// The tool-loop.
|
||||||
std::unique_ptr<tools::ToolLoop> m_toolLoop;
|
std::unique_ptr<tools::ToolLoop> m_toolLoop;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -1382,7 +1382,8 @@ void Editor::flashCurrentLayer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Point Editor::autoScroll(MouseMessage* msg, AutoScroll dir)
|
gfx::Point Editor::autoScroll(const ui::MouseMessage* msg,
|
||||||
|
const AutoScroll dir)
|
||||||
{
|
{
|
||||||
gfx::Point mousePos = msg->position();
|
gfx::Point mousePos = msg->position();
|
||||||
if (!Preferences::instance().editor.autoScroll())
|
if (!Preferences::instance().editor.autoScroll())
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -214,7 +214,8 @@ namespace app {
|
|||||||
void updateStatusBar();
|
void updateStatusBar();
|
||||||
|
|
||||||
// Control scroll when cursor goes out of the editor viewport.
|
// Control scroll when cursor goes out of the editor viewport.
|
||||||
gfx::Point autoScroll(ui::MouseMessage* msg, AutoScroll dir);
|
gfx::Point autoScroll(const ui::MouseMessage* msg,
|
||||||
|
const AutoScroll dir);
|
||||||
|
|
||||||
tools::Tool* getCurrentEditorTool() const;
|
tools::Tool* getCurrentEditorTool() const;
|
||||||
tools::Ink* getCurrentEditorInk() const;
|
tools::Ink* getCurrentEditorInk() const;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -53,14 +53,17 @@
|
|||||||
#include "ui/view.h"
|
#include "ui/view.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
using namespace ui;
|
using namespace ui;
|
||||||
|
|
||||||
MovingPixelsState::MovingPixelsState(Editor* editor, MouseMessage* msg, PixelsMovementPtr pixelsMovement, HandleType handle)
|
MovingPixelsState::MovingPixelsState(Editor* editor,
|
||||||
|
MouseMessage* msg,
|
||||||
|
PixelsMovementPtr pixelsMovement,
|
||||||
|
HandleType handle)
|
||||||
: m_pixelsMovement(pixelsMovement)
|
: m_pixelsMovement(pixelsMovement)
|
||||||
|
, m_delayedMouseMove(this, editor, 5)
|
||||||
, m_editor(editor)
|
, m_editor(editor)
|
||||||
, m_observingEditor(false)
|
, m_observingEditor(false)
|
||||||
, m_discarded(false)
|
, m_discarded(false)
|
||||||
@ -277,6 +280,8 @@ bool MovingPixelsState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
ASSERT(m_pixelsMovement);
|
ASSERT(m_pixelsMovement);
|
||||||
ASSERT(editor == m_editor);
|
ASSERT(editor == m_editor);
|
||||||
|
|
||||||
|
m_delayedMouseMove.onMouseDown(msg);
|
||||||
|
|
||||||
// Set this editor as the active one and setup the ContextBar for
|
// Set this editor as the active one and setup the ContextBar for
|
||||||
// moving pixels. This is needed in case that the user is working
|
// moving pixels. This is needed in case that the user is working
|
||||||
// with a couple of Editors, in one is moving pixels and the other
|
// with a couple of Editors, in one is moving pixels and the other
|
||||||
@ -364,6 +369,8 @@ bool MovingPixelsState::onMouseUp(Editor* editor, MouseMessage* msg)
|
|||||||
ASSERT(m_pixelsMovement);
|
ASSERT(m_pixelsMovement);
|
||||||
ASSERT(editor == m_editor);
|
ASSERT(editor == m_editor);
|
||||||
|
|
||||||
|
m_delayedMouseMove.onMouseUp(msg);
|
||||||
|
|
||||||
// Drop the image temporarily in this location (where the user releases the mouse)
|
// Drop the image temporarily in this location (where the user releases the mouse)
|
||||||
m_pixelsMovement->dropImageTemporarily();
|
m_pixelsMovement->dropImageTemporarily();
|
||||||
|
|
||||||
@ -381,81 +388,8 @@ bool MovingPixelsState::onMouseMove(Editor* editor, MouseMessage* msg)
|
|||||||
|
|
||||||
// If there is a button pressed
|
// If there is a button pressed
|
||||||
if (m_pixelsMovement->isDragging()) {
|
if (m_pixelsMovement->isDragging()) {
|
||||||
// Auto-scroll
|
if (m_delayedMouseMove.onMouseMove(msg))
|
||||||
gfx::Point mousePos = editor->autoScroll(msg, AutoScroll::MouseDir);
|
m_renderTimer.start();
|
||||||
|
|
||||||
// Get the position of the mouse in the sprite
|
|
||||||
gfx::PointF spritePos = editor->screenToEditorF(mousePos);
|
|
||||||
|
|
||||||
// Get the customization for the pixels movement (snap to grid, angle snap, etc.).
|
|
||||||
KeyContext keyContext = KeyContext::Normal;
|
|
||||||
switch (m_pixelsMovement->handle()) {
|
|
||||||
case MovePixelsHandle:
|
|
||||||
keyContext = KeyContext::TranslatingSelection;
|
|
||||||
break;
|
|
||||||
case ScaleNWHandle:
|
|
||||||
case ScaleNHandle:
|
|
||||||
case ScaleNEHandle:
|
|
||||||
case ScaleWHandle:
|
|
||||||
case ScaleEHandle:
|
|
||||||
case ScaleSWHandle:
|
|
||||||
case ScaleSHandle:
|
|
||||||
case ScaleSEHandle:
|
|
||||||
keyContext = KeyContext::ScalingSelection;
|
|
||||||
break;
|
|
||||||
case RotateNWHandle:
|
|
||||||
case RotateNEHandle:
|
|
||||||
case RotateSWHandle:
|
|
||||||
case RotateSEHandle:
|
|
||||||
keyContext = KeyContext::RotatingSelection;
|
|
||||||
break;
|
|
||||||
case SkewNHandle:
|
|
||||||
case SkewWHandle:
|
|
||||||
case SkewEHandle:
|
|
||||||
case SkewSHandle:
|
|
||||||
keyContext = KeyContext::ScalingSelection;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelsMovement::MoveModifier moveModifier = PixelsMovement::NormalMovement;
|
|
||||||
KeyAction action = editor->getCustomizationDelegate()
|
|
||||||
->getPressedKeyAction(keyContext);
|
|
||||||
|
|
||||||
if (int(action & KeyAction::SnapToGrid))
|
|
||||||
moveModifier |= PixelsMovement::SnapToGridMovement;
|
|
||||||
|
|
||||||
if (int(action & KeyAction::AngleSnap))
|
|
||||||
moveModifier |= PixelsMovement::AngleSnapMovement;
|
|
||||||
|
|
||||||
if (int(action & KeyAction::MaintainAspectRatio))
|
|
||||||
moveModifier |= PixelsMovement::MaintainAspectRatioMovement;
|
|
||||||
|
|
||||||
if (int(action & KeyAction::ScaleFromCenter))
|
|
||||||
moveModifier |= PixelsMovement::ScaleFromPivot;
|
|
||||||
|
|
||||||
if (int(action & KeyAction::LockAxis))
|
|
||||||
moveModifier |= PixelsMovement::LockAxisMovement;
|
|
||||||
|
|
||||||
if (int(action & KeyAction::FineControl))
|
|
||||||
moveModifier |= PixelsMovement::FineControl;
|
|
||||||
|
|
||||||
m_renderTimer.start();
|
|
||||||
m_pixelsMovement->setFastMode(true);
|
|
||||||
|
|
||||||
// Invalidate handles
|
|
||||||
Decorator* decorator = static_cast<Decorator*>(editor->decorator());
|
|
||||||
TransformHandles* transfHandles = decorator->getTransformHandles(editor);
|
|
||||||
const Transformation& transformation = m_pixelsMovement->getTransformation();
|
|
||||||
transfHandles->invalidateHandles(editor, transformation);
|
|
||||||
|
|
||||||
// Drag the image to that position
|
|
||||||
m_pixelsMovement->moveImage(spritePos, moveModifier);
|
|
||||||
|
|
||||||
// Update context bar and status bar
|
|
||||||
ContextBar* contextBar = App::instance()->contextBar();
|
|
||||||
contextBar->updateForMovingPixels(transformation);
|
|
||||||
|
|
||||||
editor->updateStatusBar();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,6 +397,79 @@ bool MovingPixelsState::onMouseMove(Editor* editor, MouseMessage* msg)
|
|||||||
return StandbyState::onMouseMove(editor, msg);
|
return StandbyState::onMouseMove(editor, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MovingPixelsState::onCommitMouseMove(Editor* editor,
|
||||||
|
const gfx::PointF& spritePos)
|
||||||
|
{
|
||||||
|
m_pixelsMovement->setFastMode(true);
|
||||||
|
|
||||||
|
// Get the customization for the pixels movement (snap to grid, angle snap, etc.).
|
||||||
|
KeyContext keyContext = KeyContext::Normal;
|
||||||
|
switch (m_pixelsMovement->handle()) {
|
||||||
|
case MovePixelsHandle:
|
||||||
|
keyContext = KeyContext::TranslatingSelection;
|
||||||
|
break;
|
||||||
|
case ScaleNWHandle:
|
||||||
|
case ScaleNHandle:
|
||||||
|
case ScaleNEHandle:
|
||||||
|
case ScaleWHandle:
|
||||||
|
case ScaleEHandle:
|
||||||
|
case ScaleSWHandle:
|
||||||
|
case ScaleSHandle:
|
||||||
|
case ScaleSEHandle:
|
||||||
|
keyContext = KeyContext::ScalingSelection;
|
||||||
|
break;
|
||||||
|
case RotateNWHandle:
|
||||||
|
case RotateNEHandle:
|
||||||
|
case RotateSWHandle:
|
||||||
|
case RotateSEHandle:
|
||||||
|
keyContext = KeyContext::RotatingSelection;
|
||||||
|
break;
|
||||||
|
case SkewNHandle:
|
||||||
|
case SkewWHandle:
|
||||||
|
case SkewEHandle:
|
||||||
|
case SkewSHandle:
|
||||||
|
keyContext = KeyContext::ScalingSelection;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelsMovement::MoveModifier moveModifier = PixelsMovement::NormalMovement;
|
||||||
|
KeyAction action = m_editor->getCustomizationDelegate()
|
||||||
|
->getPressedKeyAction(keyContext);
|
||||||
|
|
||||||
|
if (int(action & KeyAction::SnapToGrid))
|
||||||
|
moveModifier |= PixelsMovement::SnapToGridMovement;
|
||||||
|
|
||||||
|
if (int(action & KeyAction::AngleSnap))
|
||||||
|
moveModifier |= PixelsMovement::AngleSnapMovement;
|
||||||
|
|
||||||
|
if (int(action & KeyAction::MaintainAspectRatio))
|
||||||
|
moveModifier |= PixelsMovement::MaintainAspectRatioMovement;
|
||||||
|
|
||||||
|
if (int(action & KeyAction::ScaleFromCenter))
|
||||||
|
moveModifier |= PixelsMovement::ScaleFromPivot;
|
||||||
|
|
||||||
|
if (int(action & KeyAction::LockAxis))
|
||||||
|
moveModifier |= PixelsMovement::LockAxisMovement;
|
||||||
|
|
||||||
|
if (int(action & KeyAction::FineControl))
|
||||||
|
moveModifier |= PixelsMovement::FineControl;
|
||||||
|
|
||||||
|
// Invalidate handles
|
||||||
|
Decorator* decorator = static_cast<Decorator*>(m_editor->decorator());
|
||||||
|
TransformHandles* transfHandles = decorator->getTransformHandles(m_editor);
|
||||||
|
const Transformation& transformation = m_pixelsMovement->getTransformation();
|
||||||
|
transfHandles->invalidateHandles(m_editor, transformation);
|
||||||
|
|
||||||
|
// Drag the image to that position
|
||||||
|
m_pixelsMovement->moveImage(spritePos, moveModifier);
|
||||||
|
|
||||||
|
// Update context bar and status bar
|
||||||
|
ContextBar* contextBar = App::instance()->contextBar();
|
||||||
|
contextBar->updateForMovingPixels(transformation);
|
||||||
|
|
||||||
|
m_editor->updateStatusBar();
|
||||||
|
}
|
||||||
|
|
||||||
bool MovingPixelsState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
bool MovingPixelsState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||||
{
|
{
|
||||||
ASSERT(m_pixelsMovement);
|
ASSERT(m_pixelsMovement);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -10,6 +10,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "app/ui/context_bar_observer.h"
|
#include "app/ui/context_bar_observer.h"
|
||||||
|
#include "app/ui/editor/delayed_mouse_move.h"
|
||||||
#include "app/ui/editor/editor_observer.h"
|
#include "app/ui/editor/editor_observer.h"
|
||||||
#include "app/ui/editor/handle_type.h"
|
#include "app/ui/editor/handle_type.h"
|
||||||
#include "app/ui/editor/pixels_movement.h"
|
#include "app/ui/editor/pixels_movement.h"
|
||||||
@ -32,9 +33,13 @@ namespace app {
|
|||||||
, EditorObserver
|
, EditorObserver
|
||||||
, TimelineObserver
|
, TimelineObserver
|
||||||
, ContextBarObserver
|
, ContextBarObserver
|
||||||
, PixelsMovementDelegate {
|
, PixelsMovementDelegate
|
||||||
|
, DelayedMouseMoveDelegate {
|
||||||
public:
|
public:
|
||||||
MovingPixelsState(Editor* editor, ui::MouseMessage* msg, PixelsMovementPtr pixelsMovement, HandleType handle);
|
MovingPixelsState(Editor* editor,
|
||||||
|
ui::MouseMessage* msg,
|
||||||
|
PixelsMovementPtr pixelsMovement,
|
||||||
|
HandleType handle);
|
||||||
virtual ~MovingPixelsState();
|
virtual ~MovingPixelsState();
|
||||||
|
|
||||||
bool canHandleFrameChange() const {
|
bool canHandleFrameChange() const {
|
||||||
@ -80,6 +85,10 @@ namespace app {
|
|||||||
virtual Transformation getTransformation(Editor* editor) override;
|
virtual Transformation getTransformation(Editor* editor) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// DelayedMouseMoveDelegate impl
|
||||||
|
void onCommitMouseMove(Editor* editor,
|
||||||
|
const gfx::PointF& spritePos) override;
|
||||||
|
|
||||||
void onTransparentColorChange();
|
void onTransparentColorChange();
|
||||||
void onRenderTimer();
|
void onRenderTimer();
|
||||||
|
|
||||||
@ -97,6 +106,7 @@ namespace app {
|
|||||||
|
|
||||||
// Helper member to move/translate selection and pixels.
|
// Helper member to move/translate selection and pixels.
|
||||||
PixelsMovementPtr m_pixelsMovement;
|
PixelsMovementPtr m_pixelsMovement;
|
||||||
|
DelayedMouseMove m_delayedMouseMove;
|
||||||
Editor* m_editor;
|
Editor* m_editor;
|
||||||
bool m_observingEditor;
|
bool m_observingEditor;
|
||||||
|
|
||||||
@ -106,11 +116,6 @@ namespace app {
|
|||||||
|
|
||||||
ui::Timer m_renderTimer;
|
ui::Timer m_renderTimer;
|
||||||
|
|
||||||
// Position of the mouse in the canvas to avoid redrawing when the
|
|
||||||
// mouse position changes (only we redraw when the canvas position
|
|
||||||
// changes).
|
|
||||||
gfx::PointF m_oldSpritePos;
|
|
||||||
|
|
||||||
obs::connection m_ctxConn;
|
obs::connection m_ctxConn;
|
||||||
obs::connection m_opaqueConn;
|
obs::connection m_opaqueConn;
|
||||||
obs::connection m_transparentConn;
|
obs::connection m_transparentConn;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -319,7 +319,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
// Shift+click on Pencil tool starts a line onMouseDown() when the
|
// Shift+click on Pencil tool starts a line onMouseDown() when the
|
||||||
// preview (onKeyDown) is disabled.
|
// preview (onKeyDown) is disabled.
|
||||||
if (!Preferences::instance().editor.straightLinePreview() &&
|
if (!Preferences::instance().editor.straightLinePreview() &&
|
||||||
checkStartDrawingStraightLine(editor, &pointer)) {
|
checkStartDrawingStraightLine(editor, msg, &pointer)) {
|
||||||
// Send first mouse down to draw the straight line and start the
|
// Send first mouse down to draw the straight line and start the
|
||||||
// freehand mode.
|
// freehand mode.
|
||||||
editor->getState()->onMouseDown(editor, msg);
|
editor->getState()->onMouseDown(editor, msg);
|
||||||
@ -334,7 +334,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
if (layerEdges)
|
if (layerEdges)
|
||||||
layerEdgesOption(false);
|
layerEdgesOption(false);
|
||||||
|
|
||||||
startDrawingState(editor,
|
startDrawingState(editor, msg,
|
||||||
DrawingType::Regular,
|
DrawingType::Regular,
|
||||||
pointer);
|
pointer);
|
||||||
|
|
||||||
@ -383,7 +383,7 @@ bool StandbyState::onDoubleClick(Editor* editor, MouseMessage* msg)
|
|||||||
editor->backToPreviousState();
|
editor->backToPreviousState();
|
||||||
|
|
||||||
// Start a tool-loop selecting tiles.
|
// Start a tool-loop selecting tiles.
|
||||||
startDrawingState(editor,
|
startDrawingState(editor, msg,
|
||||||
DrawingType::SelectTiles,
|
DrawingType::SelectTiles,
|
||||||
pointer_from_msg(editor, msg));
|
pointer_from_msg(editor, msg));
|
||||||
return true;
|
return true;
|
||||||
@ -511,7 +511,7 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
|||||||
bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
|
bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||||
{
|
{
|
||||||
if (Preferences::instance().editor.straightLinePreview() &&
|
if (Preferences::instance().editor.straightLinePreview() &&
|
||||||
checkStartDrawingStraightLine(editor, nullptr))
|
checkStartDrawingStraightLine(editor, nullptr, nullptr))
|
||||||
return false;
|
return false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -627,6 +627,7 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
|
|||||||
|
|
||||||
DrawingState* StandbyState::startDrawingState(
|
DrawingState* StandbyState::startDrawingState(
|
||||||
Editor* editor,
|
Editor* editor,
|
||||||
|
const ui::MouseMessage* msg,
|
||||||
const DrawingType drawingType,
|
const DrawingType drawingType,
|
||||||
const tools::Pointer& pointer)
|
const tools::Pointer& pointer)
|
||||||
{
|
{
|
||||||
@ -652,13 +653,13 @@ DrawingState* StandbyState::startDrawingState(
|
|||||||
editor->setState(newState);
|
editor->setState(newState);
|
||||||
|
|
||||||
static_cast<DrawingState*>(newState.get())
|
static_cast<DrawingState*>(newState.get())
|
||||||
->initToolLoop(editor,
|
->initToolLoop(editor, msg, pointer);
|
||||||
pointer);
|
|
||||||
|
|
||||||
return static_cast<DrawingState*>(newState.get());
|
return static_cast<DrawingState*>(newState.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StandbyState::checkStartDrawingStraightLine(Editor* editor,
|
bool StandbyState::checkStartDrawingStraightLine(Editor* editor,
|
||||||
|
const ui::MouseMessage* msg,
|
||||||
const tools::Pointer* pointer)
|
const tools::Pointer* pointer)
|
||||||
{
|
{
|
||||||
// Start line preview with shift key
|
// Start line preview with shift key
|
||||||
@ -668,7 +669,7 @@ bool StandbyState::checkStartDrawingStraightLine(Editor* editor,
|
|||||||
(pointer ? pointer->button(): tools::Pointer::Left);
|
(pointer ? pointer->button(): tools::Pointer::Left);
|
||||||
|
|
||||||
DrawingState* drawingState =
|
DrawingState* drawingState =
|
||||||
startDrawingState(editor,
|
startDrawingState(editor, msg,
|
||||||
DrawingType::LineFreehand,
|
DrawingType::LineFreehand,
|
||||||
tools::Pointer(
|
tools::Pointer(
|
||||||
editor->document()->lastDrawingPoint(),
|
editor->document()->lastDrawingPoint(),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -55,6 +55,7 @@ namespace app {
|
|||||||
protected:
|
protected:
|
||||||
void callEyedropper(Editor* editor, const ui::MouseMessage* msg);
|
void callEyedropper(Editor* editor, const ui::MouseMessage* msg);
|
||||||
bool checkStartDrawingStraightLine(Editor* editor,
|
bool checkStartDrawingStraightLine(Editor* editor,
|
||||||
|
const ui::MouseMessage* msg,
|
||||||
const tools::Pointer* pointer);
|
const tools::Pointer* pointer);
|
||||||
virtual bool canCheckStartDrawingStraightLine() { return true; }
|
virtual bool canCheckStartDrawingStraightLine() { return true; }
|
||||||
|
|
||||||
@ -87,6 +88,7 @@ namespace app {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
DrawingState* startDrawingState(Editor* editor,
|
DrawingState* startDrawingState(Editor* editor,
|
||||||
|
const ui::MouseMessage* msg,
|
||||||
const DrawingType drawingType,
|
const DrawingType drawingType,
|
||||||
const tools::Pointer& pointer);
|
const tools::Pointer& pointer);
|
||||||
void transformSelection(Editor* editor, ui::MouseMessage* msg, HandleType handle);
|
void transformSelection(Editor* editor, ui::MouseMessage* msg, HandleType handle);
|
||||||
|
@ -24,7 +24,7 @@ BEGIN
|
|||||||
VALUE "FileDescription", "Aseprite - Animated sprites editor & pixel art tool"
|
VALUE "FileDescription", "Aseprite - Animated sprites editor & pixel art tool"
|
||||||
VALUE "FileVersion", "1,3,0,0"
|
VALUE "FileVersion", "1,3,0,0"
|
||||||
VALUE "InternalName", "aseprite"
|
VALUE "InternalName", "aseprite"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2001-2021 Igara Studio S.A."
|
VALUE "LegalCopyright", "Copyright (C) 2001-2022 Igara Studio S.A."
|
||||||
VALUE "OriginalFilename", "aseprite.exe"
|
VALUE "OriginalFilename", "aseprite.exe"
|
||||||
VALUE "ProductName", "ASEPRITE"
|
VALUE "ProductName", "ASEPRITE"
|
||||||
VALUE "ProductVersion", "1,3,0,0"
|
VALUE "ProductVersion", "1,3,0,0"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -1154,15 +1154,20 @@ void Manager::removeMessagesForTimer(Timer* timer)
|
|||||||
ASSERT(manager_thread == base::this_thread::native_id());
|
ASSERT(manager_thread == base::this_thread::native_id());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (auto it=msg_queue.begin(); it != msg_queue.end(); ) {
|
for (Message* msg : msg_queue) {
|
||||||
Message* msg = *it;
|
|
||||||
if (msg->type() == kTimerMessage &&
|
if (msg->type() == kTimerMessage &&
|
||||||
static_cast<TimerMessage*>(msg)->timer() == timer) {
|
static_cast<TimerMessage*>(msg)->timer() == timer) {
|
||||||
delete msg;
|
msg->removeRecipient(msg->recipient());
|
||||||
it = msg_queue.erase(it);
|
static_cast<TimerMessage*>(msg)->_resetTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Message* msg : used_msg_queue) {
|
||||||
|
if (msg->type() == kTimerMessage &&
|
||||||
|
static_cast<TimerMessage*>(msg)->timer() == timer) {
|
||||||
|
msg->removeRecipient(msg->recipient());
|
||||||
|
static_cast<TimerMessage*>(msg)->_resetTimer();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1769,8 +1774,9 @@ int Manager::pumpQueue()
|
|||||||
|
|
||||||
// Call Timer::tick() if this is a tick message.
|
// Call Timer::tick() if this is a tick message.
|
||||||
if (msg->type() == kTimerMessage) {
|
if (msg->type() == kTimerMessage) {
|
||||||
ASSERT(static_cast<TimerMessage*>(msg)->timer() != nullptr);
|
// The timer can be nullptr if it was removed with removeMessagesForTimer()
|
||||||
static_cast<TimerMessage*>(msg)->timer()->tick();
|
if (auto timer = static_cast<TimerMessage*>(msg)->timer())
|
||||||
|
timer->tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -192,6 +192,13 @@ namespace ui {
|
|||||||
int count() const { return m_count; }
|
int count() const { return m_count; }
|
||||||
Timer* timer() { return m_timer; }
|
Timer* timer() { return m_timer; }
|
||||||
|
|
||||||
|
// Used by Manager::removeMessagesForTimer() to invalidate the
|
||||||
|
// message. It's like removing the message from the queue, but
|
||||||
|
// without touching the queue in case that we're iterating it
|
||||||
|
// (which can happen if we remove the timer from a kTimerMessage
|
||||||
|
// handler).
|
||||||
|
void _resetTimer() { m_timer = nullptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_count; // Accumulated calls
|
int m_count; // Accumulated calls
|
||||||
Timer* m_timer; // Timer handle
|
Timer* m_timer; // Timer handle
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -57,6 +57,10 @@ void Timer::start()
|
|||||||
{
|
{
|
||||||
assert_ui_thread();
|
assert_ui_thread();
|
||||||
|
|
||||||
|
// Infinite timer? Do nothing.
|
||||||
|
if (m_interval == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
m_lastTick = base::current_tick();
|
m_lastTick = base::current_tick();
|
||||||
if (!m_running) {
|
if (!m_running) {
|
||||||
m_running = true;
|
m_running = true;
|
||||||
@ -109,6 +113,8 @@ void Timer::pollTimers()
|
|||||||
|
|
||||||
for (auto timer : timers) {
|
for (auto timer : timers) {
|
||||||
if (timer && timer->isRunning()) {
|
if (timer && timer->isRunning()) {
|
||||||
|
ASSERT(timer->interval() > 0);
|
||||||
|
|
||||||
int64_t count = ((t - timer->m_lastTick) / timer->m_interval);
|
int64_t count = ((t - timer->m_lastTick) / timer->m_interval);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
timer->m_lastTick += count * timer->m_interval;
|
timer->m_lastTick += count * timer->m_interval;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Aseprite
|
/* Aseprite
|
||||||
Copyright (C) 2020-2021 Igara Studio S.A.
|
Copyright (C) 2020-2022 Igara Studio S.A.
|
||||||
|
|
||||||
This program is distributed under the terms of
|
This program is distributed under the terms of
|
||||||
the End-User License Agreement for Aseprite. */
|
the End-User License Agreement for Aseprite. */
|
||||||
@ -8,7 +8,7 @@
|
|||||||
#include "generated_version.h" /* It defines the VERSION macro */
|
#include "generated_version.h" /* It defines the VERSION macro */
|
||||||
|
|
||||||
#define PACKAGE "Aseprite"
|
#define PACKAGE "Aseprite"
|
||||||
#define COPYRIGHT "Copyright (C) 2001-2021 Igara Studio S.A."
|
#define COPYRIGHT "Copyright (C) 2001-2022 Igara Studio S.A."
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
#if defined(_WIN32) || defined(__APPLE__)
|
||||||
#define HTTP "https"
|
#define HTTP "https"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user