Merge branch 'main' into beta

This commit is contained in:
David Capello 2022-01-06 17:44:43 -03:00
commit ab3bf31c6a
17 changed files with 386 additions and 143 deletions

View File

@ -1,5 +1,5 @@
<!-- Aseprite -->
<!-- Copyright (C) 2018-2021 Igara Studio S.A. -->
<!-- Copyright (C) 2018-2022 Igara Studio S.A. -->
<!-- Copyright (C) 2018 David Capello -->
<gui i18nwarnings="false">
<window id="about" text="About Aseprite">
@ -25,7 +25,7 @@
</hbox>
<separator horizontal="true" />
<hbox>
<label text="Copyright (C) 2001-2021" />
<label text="Copyright (C) 2001-2022" />
<link text="Igara Studio S.A." url="https://www.igarastudio.com/" />
</hbox>
<link text="https://www.aseprite.org/" url="https://www.aseprite.org/" />

View File

@ -1,5 +1,5 @@
# Aseprite
# Copyright (C) 2018-2021 Igara Studio S.A.
# Copyright (C) 2018-2022 Igara Studio S.A.
# Copyright (C) 2001-2018 David Capello
# Generate a ui::Widget for each widget in a XML file
@ -342,6 +342,7 @@ if(ENABLE_UI)
ui/drop_down_button.cpp
ui/dynamics_popup.cpp
ui/editor/brush_preview.cpp
ui/editor/delayed_mouse_move.cpp
ui/editor/drawing_state.cpp
ui/editor/editor.cpp
ui/editor/editor_observers.cpp

View 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

View 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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2021 Igara Studio S.A.
// Copyright (C) 2018-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -42,11 +42,27 @@ namespace app {
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,
tools::ToolLoop* toolLoop,
const DrawingType type)
: m_editor(editor)
, m_type(type)
, m_delayedMouseMove(this, editor,
get_delay_interval_for_tool_loop(toolLoop))
, m_toolLoop(toolLoop)
, m_toolLoopManager(new tools::ToolLoopManager(toolLoop))
, m_mouseMoveReceived(false)
@ -64,8 +80,14 @@ DrawingState::~DrawingState()
}
void DrawingState::initToolLoop(Editor* editor,
const ui::MouseMessage* msg,
const tools::Pointer& pointer)
{
if (msg)
m_delayedMouseMove.onMouseDown(msg);
else
m_delayedMouseMove.initSpritePos(gfx::PointF(pointer.point()));
Tileset* tileset = m_toolLoop->getDstTileset();
// 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_lastPointer = pointer;
m_delayedMouseMove.onMouseDown(msg);
// Check if this drawing state was started with a Shift+Pencil tool
// and now the user pressed the right button to draw the straight
// line with the background color.
@ -159,7 +183,7 @@ bool DrawingState::onMouseDown(Editor* editor, MouseMessage* msg)
// checkStartDrawingStraightLine() with the right-button.
if (recreateLoop && isCanceled) {
ASSERT(!m_toolLoopManager);
checkStartDrawingStraightLine(editor, &pointer);
checkStartDrawingStraightLine(editor, msg, &pointer);
}
return true;
@ -169,7 +193,8 @@ bool DrawingState::onMouseUp(Editor* editor, MouseMessage* msg)
{
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.
// ("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 ||
(editor->getToolLoopModifiers() != tools::ToolLoopModifiers::kReplaceSelection &&
editor->getToolLoopModifiers() != tools::ToolLoopModifiers::kIntersectSelection)) {
m_lastPointer = pointer;
// Notify the release of the mouse button to the tool loop
// manager. This is the correct way to say "the user finishes the
// 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
// again.
if (Preferences::instance().editor.straightLinePreview())
checkStartDrawingStraightLine(editor, &pointer);
checkStartDrawingStraightLine(editor, msg, &m_lastPointer);
return true;
}
@ -228,19 +251,29 @@ bool DrawingState::onMouseMove(Editor* editor, MouseMessage* msg)
// Update velocity sensor.
m_velocity.updateWithDisplayPoint(msg->position());
// The autoScroll() function controls the "infinite scroll" when we
// touch the viewport borders.
gfx::Point mousePos = editor->autoScroll(msg, AutoScroll::MouseDir);
handleMouseMovement(
tools::Pointer(editor->screenToEditor(mousePos),
m_velocity.velocity(),
button_from_msg(msg),
msg->pointerType(),
msg->pressure()));
m_lastPointer = tools::Pointer(gfx::Point(m_delayedMouseMove.spritePos()),
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;
}
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)
{
if (m_toolLoop->getInk()->isEyedropper()) {
@ -299,12 +332,12 @@ bool DrawingState::onScrollChange(Editor* editor)
// Update velocity sensor.
m_velocity.updateWithDisplayPoint(mousePos); // TODO add scroll as velocity?
handleMouseMovement(
tools::Pointer(editor->screenToEditor(mousePos),
m_velocity.velocity(),
m_lastPointer.button(),
tools::Pointer::Type::Unknown,
0.0f));
m_lastPointer = tools::Pointer(editor->screenToEditor(mousePos),
m_velocity.velocity(),
m_lastPointer.button(),
tools::Pointer::Type::Unknown,
0.0f);
handleMouseMovement();
}
return true;
}
@ -332,14 +365,13 @@ bool DrawingState::getGridBounds(Editor* editor, gfx::Rect& gridBounds)
return false;
}
void DrawingState::handleMouseMovement(const tools::Pointer& pointer)
void DrawingState::handleMouseMovement()
{
m_mouseMoveReceived = true;
m_lastPointer = pointer;
// Notify mouse movement to the tool
ASSERT(m_toolLoopManager);
m_toolLoopManager->movement(pointer);
m_toolLoopManager->movement(m_lastPointer);
}
bool DrawingState::canExecuteCommands()

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2019-2022 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -11,6 +11,7 @@
#include "app/tools/pointer.h"
#include "app/tools/velocity.h"
#include "app/ui/editor/delayed_mouse_move.h"
#include "app/ui/editor/standby_state.h"
#include "obs/connection.h"
#include <memory>
@ -23,7 +24,8 @@ namespace app {
class CommandExecutionEvent;
class DrawingState : public StandbyState {
class DrawingState : public StandbyState
, DelayedMouseMoveDelegate {
public:
DrawingState(Editor* editor,
tools::ToolLoop* loop,
@ -47,6 +49,7 @@ namespace app {
virtual bool getGridBounds(Editor* editor, gfx::Rect& gridBounds) override;
void initToolLoop(Editor* editor,
const ui::MouseMessage* msg,
const tools::Pointer& pointer);
// Used to send a movement() to the ToolLoopManager when
@ -56,14 +59,19 @@ namespace app {
void notifyToolLoopModifiersChange(Editor* editor);
private:
void handleMouseMovement(const tools::Pointer& pointer);
void handleMouseMovement();
bool canExecuteCommands();
void onBeforeCommandExecution(CommandExecutionEvent& ev);
void destroyLoopIfCanceled(Editor* editor);
void destroyLoop(Editor* editor);
// DelayedMouseMoveDelegate impl
void onCommitMouseMove(Editor* editor,
const gfx::PointF& spritePos) override;
Editor* m_editor;
DrawingType m_type;
DelayedMouseMove m_delayedMouseMove;
// The tool-loop.
std::unique_ptr<tools::ToolLoop> m_toolLoop;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2021 Igara Studio S.A.
// Copyright (C) 2018-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -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();
if (!Preferences::instance().editor.autoScroll())

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2021 Igara Studio S.A.
// Copyright (C) 2018-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -214,7 +214,8 @@ namespace app {
void updateStatusBar();
// 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::Ink* getCurrentEditorInk() const;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2019-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -53,14 +53,17 @@
#include "ui/view.h"
#include <cstring>
#include <limits>
namespace app {
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_delayedMouseMove(this, editor, 5)
, m_editor(editor)
, m_observingEditor(false)
, m_discarded(false)
@ -277,6 +280,8 @@ bool MovingPixelsState::onMouseDown(Editor* editor, MouseMessage* msg)
ASSERT(m_pixelsMovement);
ASSERT(editor == m_editor);
m_delayedMouseMove.onMouseDown(msg);
// Set this editor as the active one and setup the ContextBar for
// 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
@ -364,6 +369,8 @@ bool MovingPixelsState::onMouseUp(Editor* editor, MouseMessage* msg)
ASSERT(m_pixelsMovement);
ASSERT(editor == m_editor);
m_delayedMouseMove.onMouseUp(msg);
// Drop the image temporarily in this location (where the user releases the mouse)
m_pixelsMovement->dropImageTemporarily();
@ -381,81 +388,8 @@ bool MovingPixelsState::onMouseMove(Editor* editor, MouseMessage* msg)
// If there is a button pressed
if (m_pixelsMovement->isDragging()) {
// Auto-scroll
gfx::Point mousePos = editor->autoScroll(msg, AutoScroll::MouseDir);
// 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();
if (m_delayedMouseMove.onMouseMove(msg))
m_renderTimer.start();
return true;
}
@ -463,6 +397,79 @@ bool MovingPixelsState::onMouseMove(Editor* editor, MouseMessage* 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)
{
ASSERT(m_pixelsMovement);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2019-2022 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -10,6 +10,7 @@
#pragma once
#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/handle_type.h"
#include "app/ui/editor/pixels_movement.h"
@ -32,9 +33,13 @@ namespace app {
, EditorObserver
, TimelineObserver
, ContextBarObserver
, PixelsMovementDelegate {
, PixelsMovementDelegate
, DelayedMouseMoveDelegate {
public:
MovingPixelsState(Editor* editor, ui::MouseMessage* msg, PixelsMovementPtr pixelsMovement, HandleType handle);
MovingPixelsState(Editor* editor,
ui::MouseMessage* msg,
PixelsMovementPtr pixelsMovement,
HandleType handle);
virtual ~MovingPixelsState();
bool canHandleFrameChange() const {
@ -80,6 +85,10 @@ namespace app {
virtual Transformation getTransformation(Editor* editor) override;
private:
// DelayedMouseMoveDelegate impl
void onCommitMouseMove(Editor* editor,
const gfx::PointF& spritePos) override;
void onTransparentColorChange();
void onRenderTimer();
@ -97,6 +106,7 @@ namespace app {
// Helper member to move/translate selection and pixels.
PixelsMovementPtr m_pixelsMovement;
DelayedMouseMove m_delayedMouseMove;
Editor* m_editor;
bool m_observingEditor;
@ -106,11 +116,6 @@ namespace app {
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_opaqueConn;
obs::connection m_transparentConn;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2021 Igara Studio S.A.
// Copyright (C) 2018-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -319,7 +319,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
// Shift+click on Pencil tool starts a line onMouseDown() when the
// preview (onKeyDown) is disabled.
if (!Preferences::instance().editor.straightLinePreview() &&
checkStartDrawingStraightLine(editor, &pointer)) {
checkStartDrawingStraightLine(editor, msg, &pointer)) {
// Send first mouse down to draw the straight line and start the
// freehand mode.
editor->getState()->onMouseDown(editor, msg);
@ -334,7 +334,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
if (layerEdges)
layerEdgesOption(false);
startDrawingState(editor,
startDrawingState(editor, msg,
DrawingType::Regular,
pointer);
@ -383,7 +383,7 @@ bool StandbyState::onDoubleClick(Editor* editor, MouseMessage* msg)
editor->backToPreviousState();
// Start a tool-loop selecting tiles.
startDrawingState(editor,
startDrawingState(editor, msg,
DrawingType::SelectTiles,
pointer_from_msg(editor, msg));
return true;
@ -511,7 +511,7 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
{
if (Preferences::instance().editor.straightLinePreview() &&
checkStartDrawingStraightLine(editor, nullptr))
checkStartDrawingStraightLine(editor, nullptr, nullptr))
return false;
return false;
}
@ -627,6 +627,7 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
DrawingState* StandbyState::startDrawingState(
Editor* editor,
const ui::MouseMessage* msg,
const DrawingType drawingType,
const tools::Pointer& pointer)
{
@ -652,13 +653,13 @@ DrawingState* StandbyState::startDrawingState(
editor->setState(newState);
static_cast<DrawingState*>(newState.get())
->initToolLoop(editor,
pointer);
->initToolLoop(editor, msg, pointer);
return static_cast<DrawingState*>(newState.get());
}
bool StandbyState::checkStartDrawingStraightLine(Editor* editor,
const ui::MouseMessage* msg,
const tools::Pointer* pointer)
{
// Start line preview with shift key
@ -668,7 +669,7 @@ bool StandbyState::checkStartDrawingStraightLine(Editor* editor,
(pointer ? pointer->button(): tools::Pointer::Left);
DrawingState* drawingState =
startDrawingState(editor,
startDrawingState(editor, msg,
DrawingType::LineFreehand,
tools::Pointer(
editor->document()->lastDrawingPoint(),

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2019-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -55,6 +55,7 @@ namespace app {
protected:
void callEyedropper(Editor* editor, const ui::MouseMessage* msg);
bool checkStartDrawingStraightLine(Editor* editor,
const ui::MouseMessage* msg,
const tools::Pointer* pointer);
virtual bool canCheckStartDrawingStraightLine() { return true; }
@ -87,6 +88,7 @@ namespace app {
private:
DrawingState* startDrawingState(Editor* editor,
const ui::MouseMessage* msg,
const DrawingType drawingType,
const tools::Pointer& pointer);
void transformSelection(Editor* editor, ui::MouseMessage* msg, HandleType handle);

View File

@ -24,7 +24,7 @@ BEGIN
VALUE "FileDescription", "Aseprite - Animated sprites editor & pixel art tool"
VALUE "FileVersion", "1,3,0,0"
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 "ProductName", "ASEPRITE"
VALUE "ProductVersion", "1,3,0,0"

View File

@ -1,5 +1,5 @@
// 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
//
// 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());
#endif
for (auto it=msg_queue.begin(); it != msg_queue.end(); ) {
Message* msg = *it;
for (Message* msg : msg_queue) {
if (msg->type() == kTimerMessage &&
static_cast<TimerMessage*>(msg)->timer() == timer) {
delete msg;
it = msg_queue.erase(it);
msg->removeRecipient(msg->recipient());
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.
if (msg->type() == kTimerMessage) {
ASSERT(static_cast<TimerMessage*>(msg)->timer() != nullptr);
static_cast<TimerMessage*>(msg)->timer()->tick();
// The timer can be nullptr if it was removed with removeMessagesForTimer()
if (auto timer = static_cast<TimerMessage*>(msg)->timer())
timer->tick();
}
bool done = false;

View File

@ -1,5 +1,5 @@
// 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
//
// This file is released under the terms of the MIT license.
@ -192,6 +192,13 @@ namespace ui {
int count() const { return m_count; }
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:
int m_count; // Accumulated calls
Timer* m_timer; // Timer handle

View File

@ -1,5 +1,5 @@
// 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
//
// This file is released under the terms of the MIT license.
@ -57,6 +57,10 @@ void Timer::start()
{
assert_ui_thread();
// Infinite timer? Do nothing.
if (m_interval == 0)
return;
m_lastTick = base::current_tick();
if (!m_running) {
m_running = true;
@ -109,6 +113,8 @@ void Timer::pollTimers()
for (auto timer : timers) {
if (timer && timer->isRunning()) {
ASSERT(timer->interval() > 0);
int64_t count = ((t - timer->m_lastTick) / timer->m_interval);
if (count > 0) {
timer->m_lastTick += count * timer->m_interval;

View File

@ -1,5 +1,5 @@
/* 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
the End-User License Agreement for Aseprite. */
@ -8,7 +8,7 @@
#include "generated_version.h" /* It defines the VERSION macro */
#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__)
#define HTTP "https"