Now a single click will not enable the range, using Shift+click or
dragging the mouse will enable the range of multiple
layers/frames/cels by default (but there are new options to go back to
the previous behavior or customize this behavior in an extensive way).
Regression added in 056073b3f1 in the
custom file selector. Every time you saved a new sprite the dialog
started at the root path (e.g. Desktop) instead of the last used
directory.
Now each tool has independent 'dynamic options'. A global configuration
for all tools is also possible via the 'Same in all tools' option.
ALso this fix, solves a regression inserted in:
2cc15cda9e
(bug inserted: stabilizer is always active)
This fix disables the fine control when the transformation doesn't
include rotation, skew and/or fine scaling (so just translating doesn't
allow fine control until we rotate/skew/scaling, this might change in
the future if we add a new anti-aliasing rotation algorithm).
Also this fix improves the regular movement of the selected image.
This patch solves several problems introducing the possibility to
specify a row stride bigger than the width (visible pixels) on each
image row. Useful in case that we want to align the initial pixel
address of each row (if DOC_USE_ALIGNED_PIXELS is defined).
This allows us to use some SIMD intrinsics (e.g. SSE2) for some image
functions in the future (right now implemented only in the new
is_same_image_simd_templ() for is_same_image()).
Anyway to avoid breaking some existing code, by default we'll still
keep the old behavior: row stride bytes = width bytes (so
DOC_USE_ALIGNED_PIXELS is undefined).
A reference to a doc object (Sprite, Layer, Cel, etc.) is done through
its ID in the scripting engine, when we try to access it from a script
that element might be already deleted. Previously we displayed the a
message like "Using a nil 'Cel' object". With this change we show the
traceback and a "Tried to access a deleted 'Cel'" message.
The old impl was using get/put_pixel(), the new slow one is using the
get/put_pixel_fast(), and the new default flip_image() is using just
raw pointers.
Added some utilites like random_image() for testing purposes, and
DOC_DISPATCH_BY_COLOR_MODE() macros to avoid switch/case for each
color mode. In a future these might use generic lambdas.
As Shift+Alt enables the subtract mode, if we touch an editor edges
and receive a MouseEnter message, we cannot update the selection
modifiers with the pressed Alt key because that will start rotating the
rectangular marquee automatically. We've to start rotating only if we
release the Alt key and then press it again (not by just moving the
mouse).
Recent regression introduced in bd91a6430f
when the ordering of MouseEnter/Move/Leave message order was fixed.
It looks like the mouse got captured by the Aseprite window if we
start the Zenity command using the mouse in certain way (e.g. when we
click the Open File link from the Home tab). The same doesn't happen
if we press Ctrl+O or click the File > Open menu.
New json.decode(jsonText) and json.encode(luaTable) functions.
In this way we don't depend on third-party libraries to decode/encode
JSON text which is a quite common task (in tests and export scripts).
The default language (en.ini) has a new "display_name" property, but
probably we should remove it and transform the English language in an
extension (just as the default Aseprite theme).
When we received a MouseEnter/Leave, we were processing those laf-os
events immediately without taking care of all the MouseMove/Down/Up
events in the middle. Now we enqueue all the events as
messages (MouseEnter -> MouseMove/Down/Up -> MouseLeave).
This is important because when we process MouseLeave we are calling
setMouse(nullptr), which resets the mouse widget HAS_MOUSE flag, and
some widgets needs to know if they have the mouse above before the
MouseUp event. With this change we can remove the
Widget::hasMouseOver() function (that was checking the global
ui::get_mouse_position() instead of the HAS_MOUSE flag directly).
Another change was introduced to keep the old behavior now that
hasMouseOver() is not available: the ui::Manager doesn't assign the
HAS_MOUSE flag if the mouse is captured (it only assign the HAS_MOUSE
to the widget with the mouse captured, or to no widget, at least until
the capture is released).
Replaced the App BeforePaintEmptyTilemap event (introduced in
c26351712a) with the new Sprite
AfterAddTile event triggered by draw_image_into_new_tilemap_cel().
This new event handles two cases:
1) When the user paints on an empty tilemap cel, a new tile is
created, so the tile management plugin can handle AfterAddTile
to know the existence of this new tile. (This case was disabled
with fae3c6566c, then handled with
c26351712a, now handled with this
patch).
2) When we copy & paste cels (or drag & drop cels) in the timeline
between layers, if a new tile is created, the AfterAddTile is
called and the plugin can associate tiles with its internal
information (e.g. folders)
Related to: https://github.com/aseprite/Attachment-System/issues/135
Before this fix, when installing dithering matrices if Aseprite
couldn't find the file of some matrix described in the json, Aseprite
would crash (this happened during the installation of an erroneous
dithering matrices extension, and after every reboot of Aseprite).
The cause of the crash was the absence of the MainWindow instance
during the ContextBar creation. When an error occurs, the console is
called, but since MainWindows is not yet available, aseprite crashes.
The Zenity utility is not perfect, there are several issues to improve
the UX, but it's good enough to offer a native file dialog on Linux
without depending on huge dynamic GUI libraries (GTK+, Qt, etc.).
Prior to this fix, there was a spurious movement on a selected image
simply by moving the pivot point. Steps to reproduce it:
- Select a canvas area
- Zoom at 300%
- Make the pivot visible and move it to a negative coordinate
position (less than the origin 0,0)
- If you rotate/skew the image this problem cannot be reproduced
This fixes unnecessary propagation of kKeyDownMessage/kKeyUpMessage
messages across all open editors. The pressed key should be sent to
the active editor or the one with the mouse over it.
We were able to reproduce this putting the black border of the
ColorBar's PaletteView touching its viewport, and changing from Screen
Scaling=200% & UI Scaling=100% to Screen Scaling=100% & UI
Scaling=200% (with the memory sanitizer on).
Fix regression introduced in 24846eae10
using the new RenderPlan structure. We have to include empty/nullptr
cels in the plan to paint the preview image in the selected
layer/frame (the preview image is the one used for the brush preview,
and for the transformation preview when we paste the clipboard content
on the canvas).
This is needed on X11/Linux as we received a lot of mouse events at
the same time when the user drag the mouse. In this way we avoid
restarting the preview and making a high CPU usage just to stop/start
the filter without any kind of UI feedback.
Added FILTER_LOOP_THROUGH_ROW_BEGIN/END macros to simplify some
boilerplate code for each filter.
In this way if processing just one row takes too much time, canceling
the operation is faster.
We can use a thread pool (avoid creating/destroying threads) and we
can continue the same task running when the filter restart (there is
no need to stop/wait and restart, because the filter task keeps
calling the applyStep() function anyway).
Several changes were included:
- Fixes in TextBox widget to show it with proper size hint when it's
outside a viewport
- Added the IncompatFileWindow with a message + link to know how to
update Aseprite and solve the situation
- Moved CannotModifyWhenReadOnlyException from app/doc.h to
app/transaction.h
Given 32ed6622d4, now we could be in a
situation where the sprite is loaded without layers because all layers
are incompatible with the current version. So we have to take care of
this situation in the Timeline UI.
With multiple windows on, if a modal/foreground window like Canvas
Size (which has a special onBroadcastMouseMessage()) were running, and
there was a script dialog also opened on the background, the
non-foreground dialog could receive clicks. This patch fixes this
particular scenario (no other window than the actual foreground window
can receive mouse clicks).
In this way we can completely disable the log of data recovery events.
In a future we might offer a way to log all these events in a log file
(probably included in crash reports).
We've received crash reports where save_xml() throws an Exception()
because the user brushes file cannot be saved (open_file(..., "wb")
returns nlulptr). We're not sure why (probably privileges?) but at
least we fixed the exception.
Added properties needed to know where the mouse position is on the
editor canvas + a method to cancel app.editor:askPoint() from Lua.
Related to aseprite/Attachment-System#102
This is the first attempt to finally implement the require() function
on Lua. The main problem was how to solve conflicts between plugins
that use the same library name. Here we separate each plugin like in a
namespace, so require(name) inside a plugin will save the module in
_LOADED["pluginName/libraryName"] to avoid conflicts with other
libraryName from other plugins.
We receive kMouseMoveMessage as the first message of a multiselect
message in a ListBox when the kMouseDownMessage message is received by
a separator first e.g. if we click a separator from the Recover Files
tab and start dragging the mouse this assert was failing.
Before this the ASSERT(group.items.empty()) in
AppMenus::removeMenuGroup() was failing when a plugin created
subgroups/submenus inside groups.
We have to remove plugins items in the reverse order that they were
added to uninstall them correctly.
An empty cel must be counted as a layer for the z-index ordering, so
the z-index refers to number of layers to move back/front, but number
of non-empty cels in the specific frame.
A this fix, a new issue appears: #3820
We can use:
Image:clear()
Image:clear(color)
Image:clear(rectangle)
Image:clear(rectangle, color)
If the color is not specified it will be the transparent color of the
image.
Co-authored-by: David Capello <david@igara.com>
This is necessary to prevent the manager to invalidate a window whose relayout is not finished. This can happen when a script opens a new window when another is currently opening. For instance a script whose canvas.onpaint handler opens another dialog.
In this way we can use F2 to:
1. Set the Loop section if two or more frames are selected
2. Remove the loop section if only one frame is selected
3. Rename the active layer if the layer is selected (or no frames are selected)
* Now a Cel has a z-index property to change the order of layers per frame
* A new doc::RenderPlan class can calculate the order of cels to be rendered
* z-index is saved as a int16_t in the .aseprite files
* This new field can be set/get from Lua with Cel.zIndex
An initial implementation (not yet ready for production) of the
ShaderRenderer to use SkSL shaders to convert indexed -> RGB, and draw
SkImages directly on SkCanvases (this will enable future GPU
acceleration).
The SimpleRenderer outputs unpremultiplied RGB values when we render
in a transparent background, we have to indicate that to Skia now that
we're compositing os::Surfaces (SkiaSurfaces) directly in this
FullscreenPreview command.
Regression introduced cc7da16691 when
the Console was converted to a non-modal window. If a script prints
something, the console is displayed, then the user can close the
console, and if the script tried to print something else the console
window wasn't displayed again until some other command was
executed (any command that called the Console::Console() constructor
which would create the ConsoleWindow again).
With this fix the console window is recreated/displayed again on the
screen.
This bug was well-known (but I think never reported yet) and probably
the possible source of the #3787 issue.
Renderer::renderCheckeredBackground() function was used only for the
FullscreenPreviewCommand, but now we use
ShaderRenderer::renderCheckeredBackground() to render the background
in the Editor too. So the sprite is painted in a backbuffer and then
composited with the already painted background using
Graphics::drawSurface().
This new renderer uses a shader to paint only the checkered
background. It can be tested only in ENABLE_DEVMODE and pressing F1
key to switch between the renderers (which is a devmode special key
for testing purposes only)
We've changed the Renderer::renderSprite(Image*, ...) member function
to renderSprite(os::Surface*, ...) so we receive the os::Surface
directly to paint the SkCanvas with a SkShader. Probably more
refactors will be needed.
If we start playing from a tag with a repeat field, we'll just play
the tag as many times it says and continue with the regular animation
of the sprite. Users expect the repeat field to be useful with the
default configuration of the program.
Now the equivalent was "{tag}_{frame1}.png", but it looks like a
regression reported here https://community.aseprite.org/t/17253 were
it was possible to just specify the frame number as in "{tag}_1.png"
This menu was accessible right-clicking the Play button in the
Timeline (and in the Preview window, with specific options for the
Preview).
This change includes some changes:
1. Now if a menu <item> in gui.xml doesn't specify a text field, the
text of the command is used (to avoid double translation, the bad
side is that we don't have a mnemonic specified).
2. Menu::showPopup() can be used with submenus from the root menu, to
do this we have to remove the menu item owner temporarily before we
show the menu as popup (see the change in Menu::showPopup())
3. We can specify a special active DocView for commands with
UIContext::SetTargetView, this is used to set the Preview editor as
active view for commands like TogglePlayOnce, etc.
This "undoing" state (introduced in b43f2a3428)
is used in the scripting AppEvents (a ContextObserver) onActiveSiteChange()
impl to trigger a 'sitechange' event for scripts/plugins so they know
if the change was from a undo or from the regular user interaction
(some scripts will add more actions to the transaction if the change
is from the user, not from a undo/redo, or now with this fix,
navigating the history)
This was a source of crashes for the Attachment System when using the
Undo History (e.g. https://github.com/aseprite/Attachment-System/issues/83
+ using the Undo History window)
In some way we prefer to simplify the GraphicsContext class instead of
exposing a new Paint() class (which might be confusing with the
app.useTool() too).
Now BlendMode can be used for GraphicsContext.blendMode and
Layer.blendMode (not all modes are available in both cases).
This reverts commit 3d7c05c8f1.
As creating a new layer was generating a onActiveSiteChange() event,
if a script was listening that event and adding new
actions (e.g. changing the layer properties), the order of cmds was
incorrectly created (e.g. cmd::SetUserDataProperty for the layer, and
then the cmd::AddLayer).
With this change we first add the cmd::AddLayer and then any extra
cmd::SetUserDataProperty (or any other action) that can be added in
the sitechange event.
We've created ev.fromUndo flag to the app 'sitechange' Lua event so
scripts can detect if we are undoing/redoing in a site change event,
and avoid adding new properties/actions when this happens.
And we have added a new exception (CannotModifyWhenUndoingException)
to detect if a new action/cmd is added (incorrectly) when we are
undoing/redoing.
Related to #3720
We were finally able to reproduce #3504 (an assert fail) and it looks
like a bug in the Widget::removeChild() function, where kPaintMessage
messages weren't removed from the queue after the widget is removed
from its parent.
It looks like the std::variant impl doesn't convert from long long to
int64_t type automatically, but we might be wrong. Anyway this patch
does fix this.
We have to copy all missing <style> into the new theme, so these
styles are re-loaded using colors and parts from the new
theme (instead of using the data of the default theme).
The icon/stylus was inverted. We've also moved the icon for each state
to the theme xml (so we don't need to use setIcon() manually anymore
for this button).
As now the BrushType button has an odd number width (15px), it's
better to limit the brush size to an odd number size (9px instead of
10px). In previous versions the BrushType button had an even number
width (16px) so the 10px brush size was correctly centered.
As the "multiple windows" feature is still buggy (#3556) and we've
disabled it by default, it's nice to make this option more visible (in
the General section) so users reliant on this will find the switch
quickly.
It's not safe to listen this event from a script because it can be
called from a background thread. We keep the code for a future
solution (in case that it can be found).
In other case, consider to finally delete this code.
Added a new Dialog{ notitlebar=true } parameter to avoid showing a
title bar explicitly. So we can continue using Dialog() to create
dialogs with the default "Script" title.
Regression introduced in 453d9c2168
Added a Sprite.tileManagementPlugin property for plugins that want to
replace the standard tilemap/tileset interface. This includes a new
external file field in .aseprite files to specify that the sprite
tiles are controlled by a specific plugin.
Once this property is set, the standard tilemap/tileset modes
selectors will disappear and the only way to make then available will
be setting this property to nil/empty string again.
Fix https://github.com/aseprite/Attachment-System/issues/21
We've added an experimental option (enabled by default) to keep the
compressed tileset data when we load/save a .aseprite file to avoid
recompressing each time we save (and only compressing the tileset if
tiles are modified).
This is an attempt to make the save operation faster when we use
sprites with several tilemap layers + large tilesets (many tiles, with
big tiles).
Reference: https://github.com/aseprite/Attachment-System/issues/54
We've tested writing uncompressed tilesets, it's too slow for big
tilesets. Anyway read_raw_image/write_raw_image now support saving
uncompressed tilemaps if necessary in the future.