mirror of https://github.com/aseprite/aseprite.git
Compare commits
24 Commits
1cd97d34c6
...
facad518ac
Author | SHA1 | Date |
---|---|---|
|
facad518ac | |
|
194f8424a8 | |
|
debab653fa | |
|
6e9024d54d | |
|
1fa7fd0831 | |
|
ab6b040e83 | |
|
bc312a37b3 | |
|
8db26a384c | |
|
ecc53c7c35 | |
|
3129fda977 | |
|
6cb61fb41e | |
|
aa817a8d2a | |
|
40031f83d8 | |
|
90282dbc40 | |
|
1227f9c49c | |
|
d61ae919ad | |
|
b2b2583176 | |
|
b535212642 | |
|
229a3cdf65 | |
|
b3814ec912 | |
|
e88f3bb413 | |
|
eaa2bdf0af | |
|
57309e5aa5 | |
|
4bb9239f50 |
|
@ -1,9 +0,0 @@
|
|||
Describe your bug report or feature request here
|
||||
...
|
||||
...
|
||||
...
|
||||
|
||||
### Aseprite and System version
|
||||
|
||||
* Aseprite version: version number, installer/portable/Steam/beta/dev/commit-hash
|
||||
* System: Windows/macOS/Linux, version, distribution
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug, triage
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots or a screen recording to help explain your problem.
|
||||
|
||||
**Aseprite & System (please complete the following information):**
|
||||
- Aseprite: [version number, installer/portable/Steam/beta/dev/commit-hash]
|
||||
- System: [Windows/macOS/Linux, version, distribution]
|
||||
- Extensions: [List the extensions you have installed]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for Aseprite
|
||||
title: ''
|
||||
labels: feature, triage
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Did other user suggested a similar idea?**
|
||||
- [ ] No
|
||||
- [ ] Yes/Links to similar ideas
|
||||
> You can try to find a similar feature requests before in:
|
||||
> - GitHub issues: https://github.com/aseprite/aseprite/issues?q=label%3Afeature
|
||||
> - Community site: https://community.aseprite.org/c/features/7
|
||||
> - Steam community: https://steamcommunity.com/app/431730/discussions/1/
|
||||
> In case you find a similar feature request, making a comment there will be useful to give some traction and show interest in the feature.
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
8
build.sh
8
build.sh
|
@ -428,9 +428,17 @@ if [ ! -d "$skia_library_dir" ] ; then
|
|||
skia_url=$(bash laf/misc/skia-url.sh $skia_build)
|
||||
skia_file=$(basename $skia_url)
|
||||
if [ ! -f "$skia_dir/$skia_file" ] ; then
|
||||
if ! command -v curl >/dev/null 2>&1 ; then
|
||||
echo "Error: 'curl' command line tool is not available in PATH"
|
||||
exit 1
|
||||
fi
|
||||
curl --ssl-revoke-best-effort -L -o "$skia_dir/$skia_file" "$skia_url"
|
||||
fi
|
||||
if [ ! -d "$skia_library_dir" ] ; then
|
||||
if ! command -v unzip >/dev/null 2>&1 ; then
|
||||
echo "Error: 'unzip' command line tool is not available in PATH"
|
||||
exit 1
|
||||
fi
|
||||
unzip -n -d "$skia_dir" "$skia_dir/$skia_file"
|
||||
fi
|
||||
else
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
@ -256,12 +256,12 @@
|
|||
<part id="pal_presets" x="160" y="200" w="5" h="5" />
|
||||
<part id="pal_options" x="168" y="200" w="5" h="5" />
|
||||
<part id="pal_resize" x="176" y="200" w="5" h="5" />
|
||||
<part id="debug_continue" x="208" y="240" w="7" h="7" />
|
||||
<part id="debug_pause" x="208" y="247" w="7" h="7" />
|
||||
<part id="debug_step_into" x="222" y="240" w="7" h="7" />
|
||||
<part id="debug_step_over" x="215" y="240" w="7" h="7" />
|
||||
<part id="debug_step_out" x="229" y="240" w="7" h="7" />
|
||||
<part id="debug_breakpoint" x="236" y="240" w="7" h="7" />
|
||||
<part id="debug_continue" x="224" y="240" w="7" h="7" />
|
||||
<part id="debug_pause" x="224" y="247" w="7" h="7" />
|
||||
<part id="debug_step_into" x="238" y="240" w="7" h="7" />
|
||||
<part id="debug_step_over" x="231" y="240" w="7" h="7" />
|
||||
<part id="debug_step_out" x="245" y="240" w="7" h="7" />
|
||||
<part id="debug_breakpoint" x="252" y="240" w="7" h="7" />
|
||||
<part id="selection_replace" x="176" y="160" w="7" h="7" />
|
||||
<part id="selection_add" x="184" y="160" w="7" h="7" />
|
||||
<part id="selection_subtract" x="192" y="160" w="7" h="7" />
|
||||
|
@ -456,6 +456,7 @@
|
|||
<part id="spin_down" x="128" y="259" w="5" h="3" />
|
||||
<part id="right_diagonal_symmetry" x="176" y="240" w="13" h="13" />
|
||||
<part id="left_diagonal_symmetry" x="192" y="240" w="13" h="13" />
|
||||
<part id="point_symmetry" x="208" y="240" w="13" h="13" />
|
||||
</parts>
|
||||
<styles>
|
||||
<style id="box" />
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
@ -252,12 +252,12 @@
|
|||
<part id="pal_presets" x="160" y="200" w="5" h="5" />
|
||||
<part id="pal_options" x="168" y="200" w="5" h="5" />
|
||||
<part id="pal_resize" x="176" y="200" w="5" h="5" />
|
||||
<part id="debug_continue" x="208" y="240" w="7" h="7" />
|
||||
<part id="debug_pause" x="208" y="247" w="7" h="7" />
|
||||
<part id="debug_step_into" x="222" y="240" w="7" h="7" />
|
||||
<part id="debug_step_over" x="215" y="240" w="7" h="7" />
|
||||
<part id="debug_step_out" x="229" y="240" w="7" h="7" />
|
||||
<part id="debug_breakpoint" x="236" y="240" w="7" h="7" />
|
||||
<part id="debug_continue" x="224" y="240" w="7" h="7" />
|
||||
<part id="debug_pause" x="224" y="247" w="7" h="7" />
|
||||
<part id="debug_step_into" x="238" y="240" w="7" h="7" />
|
||||
<part id="debug_step_over" x="231" y="240" w="7" h="7" />
|
||||
<part id="debug_step_out" x="245" y="240" w="7" h="7" />
|
||||
<part id="debug_breakpoint" x="252" y="240" w="7" h="7" />
|
||||
<part id="selection_replace" x="176" y="160" w="7" h="7" />
|
||||
<part id="selection_add" x="184" y="160" w="7" h="7" />
|
||||
<part id="selection_subtract" x="192" y="160" w="7" h="7" />
|
||||
|
@ -452,6 +452,7 @@
|
|||
<part id="spin_down" x="128" y="259" w="5" h="3" />
|
||||
<part id="right_diagonal_symmetry" x="176" y="240" w="13" h="13" />
|
||||
<part id="left_diagonal_symmetry" x="192" y="240" w="13" h="13" />
|
||||
<part id="point_symmetry" x="208" y="240" w="13" h="13" />
|
||||
</parts>
|
||||
<styles>
|
||||
<style id="box" />
|
||||
|
|
|
@ -554,6 +554,9 @@
|
|||
<key command="SymmetryMode">
|
||||
<param name="orientation" value="left_diagonal" />
|
||||
</key>
|
||||
<key command="SymmetryMode">
|
||||
<param name="orientation" value="point" />
|
||||
</key>
|
||||
<key command="AutocropSprite" />
|
||||
<key command="AutocropSprite">
|
||||
<param name="byGrid" value="true" />
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
<value id="RIGHT_DIAG" value="4" />
|
||||
<value id="LEFT_DIAG" value="8" />
|
||||
<value id="BOTH_DIAG" value="12" />
|
||||
<value id="POINT" value="16" />
|
||||
<value id="ALL" value="15" />
|
||||
</enum>
|
||||
<enum id="PaintingCursorType">
|
||||
|
@ -146,6 +147,10 @@
|
|||
<value id="KEEP_AS_IS" value="1" />
|
||||
<value id="RAW_IMAGE" value="2" />
|
||||
</enum>
|
||||
<enum id="CancelSelection">
|
||||
<value id="DISCARD" value="0" />
|
||||
<value id="DESELECT" value="1" />
|
||||
</enum>
|
||||
</types>
|
||||
|
||||
<global>
|
||||
|
@ -325,6 +330,7 @@
|
|||
<option id="force_rotsprite" type="bool" default="false" />
|
||||
<option id="multicel_when_layers_or_frames" type="bool" default="true" />
|
||||
<option id="snap_to_grid" type="bool" default="true" />
|
||||
<option id="cancel_selection" type="CancelSelection" default="CancelSelection::DISCARD" />
|
||||
</section>
|
||||
<section id="quantization">
|
||||
<option id="with_alpha" type="bool" default="true" />
|
||||
|
|
|
@ -554,6 +554,8 @@ amount = Amount:
|
|||
flatten = Merge layers
|
||||
|
||||
[context_bar]
|
||||
discard_changes = Discard Changes
|
||||
deselect = Deselect
|
||||
center = Center
|
||||
fit_screen = Fit Screen
|
||||
back = Back
|
||||
|
@ -582,7 +584,7 @@ pixel_perfect = Pixel-perfect
|
|||
linear_gradient = Linear Gradient
|
||||
radial_gradient = Radial Gradient
|
||||
drop_pixel = Drop pixels here (Enter)
|
||||
cancel_drag = Cancel drag and drop (Esc)
|
||||
cancel_drag = Cancel drag and drop (Esc)\nRight-click: Configure action
|
||||
auto_select_layer = Auto Select Layer
|
||||
all = All
|
||||
none = None
|
||||
|
@ -621,6 +623,14 @@ current_layer = Current Layer
|
|||
first_ref_layer = First Reference Layer
|
||||
pick = Pick:
|
||||
sample = Sample:
|
||||
position_label = P:
|
||||
rotation_label = R:
|
||||
position_x = X Position
|
||||
position_y = Y Position
|
||||
size_width = Width
|
||||
size_height = Height
|
||||
rotation_angle = Angle
|
||||
rotation_skew = Skew
|
||||
|
||||
[convolution_matrix]
|
||||
reload_stock = &Reload Stock
|
||||
|
@ -1944,6 +1954,7 @@ toggle_horizontal = Toggle Horizontal Symmetry
|
|||
toggle_vertical = Toggle Vertical Symmetry
|
||||
toggle_right_diagonal = Toggle 45° Symmetry
|
||||
toggle_left_diagonal = Toggle -45° Symmetry
|
||||
toggle_point = Toggle Point Symmetry
|
||||
show_options = Symmetry Options
|
||||
reset_position = Reset Symmetry to Center
|
||||
reset_position_to_view_center = Reset Symmetry to View Center
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2019-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2019-2025 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2017-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="slice_properties" text="@.title" help="slices#slice-properties">
|
||||
<vbox>
|
||||
<vbox expansive="true">
|
||||
<grid id="properties_grid" columns="3">
|
||||
<label id="label1" text="@.name" />
|
||||
<entry id="name" maxsize="256" magnet="true" cell_align="horizontal" expansive="true" />
|
||||
<button id="user_data" icon="icon_user_data" maxsize="32" tooltip="@.user_data_tooltip" />
|
||||
</grid>
|
||||
<grid columns="2">
|
||||
<separator horizontal="true" cell_hspan="2" />
|
||||
<grid columns="3" expansive="true">
|
||||
<separator horizontal="true" cell_hspan="3" />
|
||||
|
||||
<box />
|
||||
<hbox homogeneous="true">
|
||||
|
@ -20,6 +20,7 @@
|
|||
<label text="@.width" />
|
||||
<label text="@.height" />
|
||||
</hbox>
|
||||
<boxfiller cell_align="horizontal" />
|
||||
|
||||
<label text="@.bounds" />
|
||||
<hbox homogeneous="true">
|
||||
|
@ -28,6 +29,7 @@
|
|||
<expr id="bounds_w" />
|
||||
<expr id="bounds_h" />
|
||||
</hbox>
|
||||
<boxfiller />
|
||||
|
||||
<check text="@.center" id="center" />
|
||||
<hbox homogeneous="true">
|
||||
|
@ -36,16 +38,18 @@
|
|||
<expr id="center_w" />
|
||||
<expr id="center_h" />
|
||||
</hbox>
|
||||
<boxfiller />
|
||||
|
||||
<check text="@.pivot" id="pivot" />
|
||||
<hbox>
|
||||
<expr id="pivot_x" />
|
||||
<expr id="pivot_y" />
|
||||
</hbox>
|
||||
<boxfiller />
|
||||
|
||||
<separator horizontal="true" cell_hspan="2" />
|
||||
|
||||
<hbox cell_hspan="2">
|
||||
<boxfiller cell_align="vertical" cell_hspan="3" />
|
||||
<separator horizontal="true" cell_hspan="3" cell_align="horizontal" />
|
||||
<hbox cell_hspan="3">
|
||||
<boxfiller />
|
||||
<hbox homogeneous="true">
|
||||
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2019-2021 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2019-2025 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2015-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="tag_properties" text="@.title">
|
||||
|
@ -23,13 +23,14 @@
|
|||
<check text="@.repeat" id="limit_repeat" />
|
||||
<vbox id="repeat_placeholder" cell_hspan="2" />
|
||||
</grid>
|
||||
<boxfiller />
|
||||
<grid columns="2">
|
||||
<separator horizontal="true" cell_hspan="2" minwidth="180" />
|
||||
<separator horizontal="true" cell_align="horizontal" cell_hspan="2" minwidth="180" />
|
||||
|
||||
<box horizontal="true" homogeneous="true" cell_hspan="2" cell_align="right">
|
||||
<hbox homogeneous="true" cell_hspan="2" cell_align="right">
|
||||
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
|
||||
<button text="@general.cancel" closewindow="true" />
|
||||
</box>
|
||||
</hbox>
|
||||
</grid>
|
||||
</vbox>
|
||||
</window>
|
||||
|
|
2
laf
2
laf
|
@ -1 +1 @@
|
|||
Subproject commit 8ec4b553f1618f7a4b47cdcf4cfc2663266111ac
|
||||
Subproject commit 01571537bc6002a2e039a66497837365c394d7fa
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -101,12 +101,12 @@ public:
|
|||
|
||||
if (countCels() > 0) {
|
||||
m_userDataView.configureAndSet((m_cel ? m_cel->data()->userData() : UserData()),
|
||||
g_window->propertiesGrid());
|
||||
propertiesGrid());
|
||||
}
|
||||
else if (!m_cel)
|
||||
m_userDataView.setVisible(false, false);
|
||||
|
||||
g_window->expandWindow(gfx::Size(g_window->bounds().w, g_window->sizeHint().h));
|
||||
expandWindow(gfx::Size(bounds().w, sizeHint().h));
|
||||
updateFromCel();
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ private:
|
|||
{
|
||||
if (countCels() > 0) {
|
||||
m_userDataView.toggleVisibility();
|
||||
g_window->expandWindow(gfx::Size(g_window->bounds().w, g_window->sizeHint().h));
|
||||
expandWindow(gfx::Size(bounds().w, sizeHint().h));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -166,7 +166,7 @@ public:
|
|||
m_document->add_observer(this);
|
||||
|
||||
if (countLayers() > 0) {
|
||||
m_userDataView.configureAndSet(m_layer->userData(), g_window->propertiesGrid());
|
||||
m_userDataView.configureAndSet(m_layer->userData(), propertiesGrid());
|
||||
if (m_remapAfterConfigure) {
|
||||
remapWindow();
|
||||
centerWindow();
|
||||
|
@ -368,8 +368,7 @@ private:
|
|||
{
|
||||
if (m_layer) {
|
||||
m_userDataView.toggleVisibility();
|
||||
g_window->remapWindow();
|
||||
manager()->invalidate();
|
||||
expandWindow(gfx::Size(bounds().w, sizeHint().h));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -188,8 +188,7 @@ private:
|
|||
void onToggleUserData()
|
||||
{
|
||||
m_userDataView.toggleVisibility();
|
||||
remapWindow();
|
||||
manager()->invalidate();
|
||||
expandWindow(gfx::Size(bounds().w, sizeHint().h));
|
||||
}
|
||||
|
||||
void onTilesedDuplicated(const Tileset* tilesetClone)
|
||||
|
|
|
@ -48,6 +48,7 @@ std::string SymmetryModeCommand::onGetFriendlyName() const
|
|||
case app::gen::SymmetryMode::VERTICAL: return Strings::symmetry_toggle_vertical();
|
||||
case app::gen::SymmetryMode::RIGHT_DIAG: return Strings::symmetry_toggle_right_diagonal();
|
||||
case app::gen::SymmetryMode::LEFT_DIAG: return Strings::symmetry_toggle_left_diagonal();
|
||||
case app::gen::SymmetryMode::POINT: return Strings::symmetry_toggle_point();
|
||||
default: return Strings::symmetry_toggle();
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +64,8 @@ void SymmetryModeCommand::onLoadParams(const Params& params)
|
|||
m_mode = app::gen::SymmetryMode::RIGHT_DIAG;
|
||||
else if (mode == "left_diagonal")
|
||||
m_mode = app::gen::SymmetryMode::LEFT_DIAG;
|
||||
else if (mode == "point")
|
||||
m_mode = app::gen::SymmetryMode::POINT;
|
||||
else
|
||||
m_mode = app::gen::SymmetryMode::NONE;
|
||||
}
|
||||
|
|
|
@ -1095,6 +1095,9 @@ public:
|
|||
gifframe_t nframes = totalFrames();
|
||||
for (gifframe_t gifFrame = 0; gifFrame < nframes; ++gifFrame) {
|
||||
ASSERT(frame_it != frame_end);
|
||||
if (m_fop->isStop())
|
||||
break;
|
||||
|
||||
frame_t frame = *frame_it;
|
||||
++frame_it;
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
|
||||
// Increment this value if the scripting API is modified between two
|
||||
// released Aseprite versions.
|
||||
#define API_VERSION 34
|
||||
#define API_VERSION 35
|
||||
|
||||
#endif
|
||||
|
|
|
@ -127,12 +127,13 @@ struct Dialog {
|
|||
int showRef = LUA_REFNIL;
|
||||
lua_State* L = nullptr;
|
||||
|
||||
Dialog(const ui::Window::Type windowType, const std::string& title)
|
||||
Dialog(const ui::Window::Type windowType, const std::string& title, bool sizeable)
|
||||
: window(windowType, title)
|
||||
, grid(2, false)
|
||||
, currentGrid(&grid)
|
||||
{
|
||||
window.addChild(&grid);
|
||||
window.setSizeable(sizeable);
|
||||
all_dialogs.push_back(this);
|
||||
}
|
||||
|
||||
|
@ -365,6 +366,7 @@ int Dialog_new(lua_State* L)
|
|||
// Get the title and the type of window (with or without title bar)
|
||||
ui::Window::Type windowType = ui::Window::WithTitleBar;
|
||||
std::string title = "Script";
|
||||
bool sizeable = true;
|
||||
if (lua_isstring(L, 1)) {
|
||||
title = lua_tostring(L, 1);
|
||||
}
|
||||
|
@ -378,9 +380,14 @@ int Dialog_new(lua_State* L)
|
|||
if (type != LUA_TNIL && lua_toboolean(L, -1))
|
||||
windowType = ui::Window::WithoutTitleBar;
|
||||
lua_pop(L, 1);
|
||||
|
||||
type = lua_getfield(L, 1, "resizeable");
|
||||
if (type != LUA_TNIL && !lua_toboolean(L, -1))
|
||||
sizeable = false;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
auto dlg = push_new<Dialog>(L, windowType, title);
|
||||
auto dlg = push_new<Dialog>(L, windowType, title, sizeable);
|
||||
|
||||
// The uservalue of the dialog userdata will contain a table that
|
||||
// stores all the callbacks to handle events. As these callbacks can
|
||||
|
@ -1509,6 +1516,10 @@ int Dialog_modify(lua_State* L)
|
|||
type = lua_getfield(L, 2, "text");
|
||||
if (const char* s = lua_tostring(L, -1)) {
|
||||
widget->setText(s);
|
||||
|
||||
// Re-process mnemonics for buttons
|
||||
if (widget->type() == WidgetType::kButtonWidget)
|
||||
widget->processMnemonicFromText();
|
||||
relayout = true;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
|
|
@ -452,6 +452,7 @@ Engine::Engine() : L(luaL_newstate()), m_delegate(nullptr), m_printLastResult(fa
|
|||
lua_setglobal(L, "FlipType");
|
||||
setfield_integer(L, "HORIZONTAL", doc::algorithm::FlipType::FlipHorizontal);
|
||||
setfield_integer(L, "VERTICAL", doc::algorithm::FlipType::FlipVertical);
|
||||
setfield_integer(L, "DIAGONAL", doc::algorithm::FlipType::FlipDiagonal);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_newtable(L);
|
||||
|
|
|
@ -29,11 +29,16 @@ struct Plugin {
|
|||
|
||||
class PluginCommand : public Command {
|
||||
public:
|
||||
PluginCommand(const std::string& id, const std::string& title, int onclickRef, int onenabledRef)
|
||||
PluginCommand(const std::string& id,
|
||||
const std::string& title,
|
||||
int onclickRef,
|
||||
int onenabledRef,
|
||||
int oncheckedRef)
|
||||
: Command(id.c_str(), CmdUIOnlyFlag)
|
||||
, m_title(title)
|
||||
, m_onclickRef(onclickRef)
|
||||
, m_onenabledRef(onenabledRef)
|
||||
, m_oncheckedRef(oncheckedRef)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -72,28 +77,44 @@ protected:
|
|||
bool onEnabled(Context* context) override
|
||||
{
|
||||
if (m_onenabledRef) {
|
||||
script::Engine* engine = App::instance()->scriptEngine();
|
||||
lua_State* L = engine->luaState();
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, m_onenabledRef);
|
||||
if (lua_pcall(L, 0, 1, 0)) {
|
||||
if (const char* s = lua_tostring(L, -1)) {
|
||||
Console().printf("Error: %s", s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bool ret = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return ret;
|
||||
}
|
||||
return callScriptRef(m_onenabledRef);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onChecked(Context* context) override
|
||||
{
|
||||
if (m_oncheckedRef) {
|
||||
return callScriptRef(m_oncheckedRef);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool callScriptRef(int ref)
|
||||
{
|
||||
ASSERT(ref);
|
||||
script::Engine* engine = App::instance()->scriptEngine();
|
||||
lua_State* L = engine->luaState();
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
if (lua_pcall(L, 0, 1, 0)) {
|
||||
if (const char* s = lua_tostring(L, -1)) {
|
||||
Console().printf("Error: %s", s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bool ret = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_title;
|
||||
int m_onclickRef;
|
||||
int m_onenabledRef;
|
||||
int m_oncheckedRef;
|
||||
};
|
||||
|
||||
void deleteCommandIfExistent(Extension* ext, const std::string& id)
|
||||
|
@ -126,6 +147,7 @@ int Plugin_newCommand(lua_State* L)
|
|||
if (lua_istable(L, 2)) {
|
||||
std::string id, title, group;
|
||||
int onenabledRef = 0;
|
||||
int oncheckedRef = 0;
|
||||
|
||||
lua_getfield(L, 2, "id");
|
||||
if (const char* s = lua_tostring(L, -1)) {
|
||||
|
@ -156,6 +178,14 @@ int Plugin_newCommand(lua_State* L)
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
type = lua_getfield(L, 2, "onchecked");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
oncheckedRef = luaL_ref(L, LUA_REGISTRYINDEX); // does a pop
|
||||
}
|
||||
else {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
type = lua_getfield(L, 2, "onclick");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
int onclickRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
@ -164,7 +194,7 @@ int Plugin_newCommand(lua_State* L)
|
|||
// overwriting a previous registered command)
|
||||
deleteCommandIfExistent(plugin->ext, id);
|
||||
|
||||
auto cmd = new PluginCommand(id, title, onclickRef, onenabledRef);
|
||||
auto cmd = new PluginCommand(id, title, onclickRef, onenabledRef, oncheckedRef);
|
||||
Commands::instance()->add(cmd);
|
||||
plugin->ext->addCommand(id);
|
||||
|
||||
|
@ -172,6 +202,7 @@ int Plugin_newCommand(lua_State* L)
|
|||
if (!group.empty() && App::instance()->isGui()) { // On CLI menus do not make sense
|
||||
if (auto appMenus = AppMenus::instance()) {
|
||||
auto menuItem = std::make_unique<AppMenuItem>(title, id);
|
||||
menuItem->processMnemonicFromText();
|
||||
appMenus->addMenuItemIntoGroup(group, std::move(menuItem));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -457,7 +457,7 @@ int Sprite_newCel(lua_State* L)
|
|||
auto sprite = get_docobj<Sprite>(L, 1);
|
||||
auto layerBase = get_docobj<Layer>(L, 2);
|
||||
if (!layerBase->isImage())
|
||||
return luaL_error(L, "unexpected kinf of layer in Sprite:newCel()");
|
||||
return luaL_error(L, "unexpected kind of layer in Sprite:newCel()");
|
||||
|
||||
frame_t frame = get_frame_number_from_arg(L, 3);
|
||||
if (frame < 0 || frame > sprite->lastFrame())
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -388,6 +388,7 @@ FOR_ENUM(app::gen::TimelinePosition)
|
|||
FOR_ENUM(app::gen::ToGrayAlgorithm)
|
||||
FOR_ENUM(app::gen::WindowColorProfile)
|
||||
FOR_ENUM(app::gen::AlphaRange)
|
||||
FOR_ENUM(app::gen::CancelSelection)
|
||||
FOR_ENUM(app::tools::ColorFromTo)
|
||||
FOR_ENUM(app::tools::DynamicSensor)
|
||||
FOR_ENUM(app::tools::FreehandAlgorithm)
|
||||
|
|
|
@ -73,6 +73,15 @@ void Symmetry::generateStrokes(const Stroke& stroke, Strokes& strokes, ToolLoop*
|
|||
break;
|
||||
}
|
||||
|
||||
case gen::SymmetryMode::POINT: {
|
||||
Stroke strokeTemp;
|
||||
calculateSymmetricalStroke(stroke, strokeTemp, loop, doc::SymmetryIndex::FLIPPED_Y);
|
||||
|
||||
calculateSymmetricalStroke(strokeTemp, stroke2, loop, doc::SymmetryIndex::FLIPPED_XY);
|
||||
strokes.push_back(stroke2);
|
||||
break;
|
||||
}
|
||||
|
||||
case gen::SymmetryMode::ALL: {
|
||||
calculateSymmetricalStroke(stroke, stroke2, loop, doc::SymmetryIndex::FLIPPED_X);
|
||||
strokes.push_back(stroke2);
|
||||
|
@ -175,8 +184,13 @@ gen::SymmetryMode Symmetry::resolveMode(gen::SymmetryMode mode)
|
|||
{
|
||||
return (((int(mode) & int(gen::SymmetryMode::HORIZONTAL)) ||
|
||||
(int(mode) & int(gen::SymmetryMode::VERTICAL))) &&
|
||||
((int(mode) & int(gen::SymmetryMode::RIGHT_DIAG)) ||
|
||||
(int(mode) & int(gen::SymmetryMode::LEFT_DIAG)))) ?
|
||||
((int(mode) & int(gen::SymmetryMode::RIGHT_DIAG)) ||
|
||||
(int(mode) & int(gen::SymmetryMode::LEFT_DIAG)))) ||
|
||||
((int(mode) & int(gen::SymmetryMode::POINT)) &&
|
||||
((int(mode) & int(gen::SymmetryMode::RIGHT_DIAG)) ||
|
||||
(int(mode) & int(gen::SymmetryMode::LEFT_DIAG)) ||
|
||||
(int(mode) & int(gen::SymmetryMode::HORIZONTAL)) ||
|
||||
(int(mode) & int(gen::SymmetryMode::VERTICAL)))) ?
|
||||
gen::SymmetryMode::ALL :
|
||||
mode;
|
||||
}
|
||||
|
|
|
@ -1001,12 +1001,12 @@ public:
|
|||
m_angle.setSuffix("°");
|
||||
m_skew.setSuffix("°");
|
||||
|
||||
addChild(new Label("P:"));
|
||||
addChild(new Label(Strings::context_bar_position_label()));
|
||||
addChild(&m_x);
|
||||
addChild(&m_y);
|
||||
addChild(&m_w);
|
||||
addChild(&m_h);
|
||||
addChild(new Label("R:"));
|
||||
addChild(new Label(Strings::context_bar_rotation_label()));
|
||||
addChild(&m_angle);
|
||||
addChild(&m_skew);
|
||||
|
||||
|
@ -1047,6 +1047,16 @@ public:
|
|||
m_skew.Change.connect([this] { onChangeSkew(); });
|
||||
}
|
||||
|
||||
void setupTooltips(TooltipManager* tooltipManager)
|
||||
{
|
||||
tooltipManager->addTooltipFor(&m_x, Strings::context_bar_position_x(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(&m_y, Strings::context_bar_position_y(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(&m_w, Strings::context_bar_size_width(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(&m_h, Strings::context_bar_size_height(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(&m_angle, Strings::context_bar_rotation_angle(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(&m_skew, Strings::context_bar_rotation_skew(), BOTTOM);
|
||||
}
|
||||
|
||||
void update(const Transformation& t)
|
||||
{
|
||||
auto rc = t.bounds();
|
||||
|
@ -1397,6 +1407,7 @@ public:
|
|||
}
|
||||
|
||||
obs::signal<void(ContextBarObserver::DropAction)> DropPixels;
|
||||
obs::signal<void(ContextBarObserver::DropAction, const gfx::Point&)> ConfigureDropPixels;
|
||||
|
||||
protected:
|
||||
void onItemChange(Item* item) override
|
||||
|
@ -1408,6 +1419,21 @@ protected:
|
|||
case 1: DropPixels(ContextBarObserver::CancelDrag); break;
|
||||
}
|
||||
}
|
||||
|
||||
void onRightClick(Item* item) override
|
||||
{
|
||||
ButtonSet::onRightClick(item);
|
||||
|
||||
const gfx::Rect rc = item->bounds();
|
||||
const gfx::Point pt(rc.x, rc.y2());
|
||||
|
||||
auto action = ContextBarObserver::DropPixels;
|
||||
switch (selectedItem()) {
|
||||
case 0: action = ContextBarObserver::DropPixels; break;
|
||||
case 1: action = ContextBarObserver::CancelDrag; break;
|
||||
}
|
||||
ConfigureDropPixels(action, pt);
|
||||
}
|
||||
};
|
||||
|
||||
class ContextBar::EyedropperField : public HBox {
|
||||
|
@ -1502,7 +1528,7 @@ protected:
|
|||
|
||||
class ContextBar::SymmetryField : public ButtonSet {
|
||||
public:
|
||||
SymmetryField() : ButtonSet(5)
|
||||
SymmetryField() : ButtonSet(6)
|
||||
{
|
||||
setMultiMode(MultiMode::Set);
|
||||
auto theme = SkinTheme::get(this);
|
||||
|
@ -1510,6 +1536,7 @@ public:
|
|||
addItem(theme->parts.verticalSymmetry(), theme->styles.symmetryField());
|
||||
addItem(theme->parts.rightDiagonalSymmetry(), theme->styles.symmetryField());
|
||||
addItem(theme->parts.leftDiagonalSymmetry(), theme->styles.symmetryField());
|
||||
addItem(theme->parts.pointSymmetry(), theme->styles.symmetryField());
|
||||
addItem("...", theme->styles.symmetryOptions());
|
||||
}
|
||||
|
||||
|
@ -1519,7 +1546,8 @@ public:
|
|||
tooltipManager->addTooltipFor(at(1), Strings::symmetry_toggle_vertical(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(at(2), Strings::symmetry_toggle_right_diagonal(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(at(3), Strings::symmetry_toggle_left_diagonal(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(at(4), Strings::symmetry_show_options(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(at(4), Strings::symmetry_toggle_point(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(at(5), Strings::symmetry_show_options(), BOTTOM);
|
||||
}
|
||||
|
||||
void updateWithCurrentDocument()
|
||||
|
@ -1534,6 +1562,7 @@ public:
|
|||
at(1)->setSelected(int(docPref.symmetry.mode()) & int(app::gen::SymmetryMode::VERTICAL));
|
||||
at(2)->setSelected(int(docPref.symmetry.mode()) & int(app::gen::SymmetryMode::RIGHT_DIAG));
|
||||
at(3)->setSelected(int(docPref.symmetry.mode()) & int(app::gen::SymmetryMode::LEFT_DIAG));
|
||||
at(4)->setSelected(int(docPref.symmetry.mode()) & int(app::gen::SymmetryMode::POINT));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1556,14 +1585,16 @@ private:
|
|||
mode |= int(app::gen::SymmetryMode::RIGHT_DIAG);
|
||||
if (at(3)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::LEFT_DIAG);
|
||||
if (at(4)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::POINT);
|
||||
|
||||
if (app::gen::SymmetryMode(mode) != docPref.symmetry.mode()) {
|
||||
docPref.symmetry.mode(app::gen::SymmetryMode(mode));
|
||||
// Redraw symmetry rules
|
||||
doc->notifyGeneralUpdate();
|
||||
}
|
||||
else if (at(4)->isSelected()) {
|
||||
auto* item = at(4);
|
||||
else if (at(5)->isSelected()) {
|
||||
auto* item = at(5);
|
||||
|
||||
gfx::Rect bounds = item->bounds();
|
||||
item->setSelected(false);
|
||||
|
@ -1942,6 +1973,8 @@ ContextBar::ContextBar(TooltipManager* tooltipManager, ColorBar* colorBar)
|
|||
m_keysConn = KeyboardShortcuts::instance()->UserChange.connect(
|
||||
[this, tooltipManager] { setupTooltips(tooltipManager); });
|
||||
m_dropPixelsConn = m_dropPixels->DropPixels.connect(&ContextBar::onDropPixels, this);
|
||||
m_configureDropPixelsConn =
|
||||
m_dropPixels->ConfigureDropPixels.connect(&ContextBar::onConfigureDropPixels, this);
|
||||
|
||||
setActiveBrush(createBrushFromPreferences());
|
||||
|
||||
|
@ -2086,6 +2119,14 @@ void ContextBar::onDropPixels(ContextBarObserver::DropAction action)
|
|||
notify_observers(&ContextBarObserver::onDropPixels, action);
|
||||
}
|
||||
|
||||
void ContextBar::onConfigureDropPixels(ContextBarObserver::DropAction action, const gfx::Point& pt)
|
||||
{
|
||||
notify_observers<ContextBarObserver::DropAction, const gfx::Point&>(
|
||||
&ContextBarObserver::onConfigureDropPixels,
|
||||
action,
|
||||
pt);
|
||||
}
|
||||
|
||||
void ContextBar::updateSliceFields(const Site& site)
|
||||
{
|
||||
if (site.sprite())
|
||||
|
@ -2626,6 +2667,7 @@ void ContextBar::setupTooltips(TooltipManager* tooltipManager)
|
|||
m_dropPixels->setupTooltips(tooltipManager);
|
||||
m_symmetry->setupTooltips(tooltipManager);
|
||||
m_sliceFields->setupTooltips(tooltipManager);
|
||||
m_transformation->setupTooltips(tooltipManager);
|
||||
}
|
||||
|
||||
void ContextBar::registerCommands()
|
||||
|
|
|
@ -129,6 +129,7 @@ private:
|
|||
void onFgOrBgColorChange(doc::Brush::ImageColor imageColor);
|
||||
void onOpacityRangeChange();
|
||||
void onDropPixels(ContextBarObserver::DropAction action);
|
||||
void onConfigureDropPixels(ContextBarObserver::DropAction action, const gfx::Point& pt);
|
||||
void updateSliceFields(const Site& site);
|
||||
|
||||
// ActiveToolObserver impl
|
||||
|
@ -213,6 +214,7 @@ private:
|
|||
obs::scoped_connection m_alphaRangeConn;
|
||||
obs::scoped_connection m_keysConn;
|
||||
obs::scoped_connection m_dropPixelsConn;
|
||||
obs::scoped_connection m_configureDropPixelsConn;
|
||||
obs::scoped_connection m_sizeConn;
|
||||
obs::scoped_connection m_angleConn;
|
||||
obs::scoped_connection m_opacityConn;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -8,6 +9,8 @@
|
|||
#define APP_CONTEXT_BAR_OBSERVER_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/fwd.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class ContextBarObserver {
|
||||
|
@ -16,6 +19,7 @@ public:
|
|||
|
||||
virtual ~ContextBarObserver() {}
|
||||
virtual void onDropPixels(DropAction action) {}
|
||||
virtual void onConfigureDropPixels(DropAction action, const gfx::Point& pt) {}
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -934,6 +934,19 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g,
|
|||
topLeft,
|
||||
bottomRight);
|
||||
}
|
||||
if (mode & int(app::gen::SymmetryMode::POINT)) {
|
||||
int smallestDimension = std::min(enclosingRect.w, enclosingRect.h);
|
||||
g->drawHLine(
|
||||
symmetryButtons & int(app::gen::SymmetryMode::POINT) ? color : semiTransparentColor,
|
||||
enclosingRect.x + x - smallestDimension * 0.10f,
|
||||
enclosingRect.y + y,
|
||||
smallestDimension * 0.10f * 2.0f);
|
||||
g->drawVLine(
|
||||
(symmetryButtons & int(app::gen::SymmetryMode::POINT)) ? color : semiTransparentColor,
|
||||
enclosingRect.x + x,
|
||||
enclosingRect.y + y - smallestDimension * 0.10f,
|
||||
smallestDimension * 0.10f * 2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -22,6 +22,7 @@
|
|||
#include "app/commands/commands.h"
|
||||
#include "app/commands/move_thing.h"
|
||||
#include "app/console.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/tools/ink.h"
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include "fmt/format.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/menu.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/view.h"
|
||||
|
@ -286,9 +288,6 @@ bool MovingPixelsState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||
UIContext* ctx = UIContext::instance();
|
||||
ctx->setActiveView(editor->getDocView());
|
||||
|
||||
ContextBar* contextBar = App::instance()->contextBar();
|
||||
contextBar->updateForMovingPixels(getTransformation(editor));
|
||||
|
||||
// Start scroll loop
|
||||
if (editor->checkForScroll(msg) || editor->checkForZoom(msg))
|
||||
return true;
|
||||
|
@ -442,10 +441,6 @@ void MovingPixelsState::onCommitMouseMove(Editor* editor, const gfx::PointF& spr
|
|||
// 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();
|
||||
}
|
||||
|
||||
|
@ -475,16 +470,13 @@ bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
|
|||
// FineControl now (e.g. if we pressed another modifier key).
|
||||
m_lockedKeyAction = KeyAction::None;
|
||||
|
||||
if (msg->scancode() == kKeyEnter || // TODO make this key customizable
|
||||
msg->scancode() == kKeyEnterPad || msg->scancode() == kKeyEsc) {
|
||||
// TODO make these keys customizable
|
||||
if (msg->scancode() == kKeyEsc) {
|
||||
cancelDrag();
|
||||
return true;
|
||||
}
|
||||
if (msg->scancode() == kKeyEnter || msg->scancode() == kKeyEnterPad) {
|
||||
dropPixels();
|
||||
|
||||
// The escape key drop pixels and deselect the mask.
|
||||
if (msg->scancode() == kKeyEsc) { // TODO make this key customizable
|
||||
Command* cmd = Commands::instance()->byId(CommandId::DeselectMask());
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(cmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -529,6 +521,10 @@ bool MovingPixelsState::onUpdateStatusBar(Editor* editor)
|
|||
const Transformation& transform(getTransformation(editor));
|
||||
gfx::Size imageSize = m_pixelsMovement->getInitialImageSize();
|
||||
|
||||
// Update the context bar along with the status bar
|
||||
ContextBar* contextBar = App::instance()->contextBar();
|
||||
contextBar->updateForMovingPixels(transform);
|
||||
|
||||
int w = int(transform.bounds().w);
|
||||
int h = int(transform.bounds().h);
|
||||
int gcd = base::gcd(w, h);
|
||||
|
@ -796,14 +792,64 @@ void MovingPixelsState::onDropPixels(ContextBarObserver::DropAction action)
|
|||
|
||||
switch (action) {
|
||||
case ContextBarObserver::DropPixels: dropPixels(); break;
|
||||
case ContextBarObserver::CancelDrag: cancelDrag(); break;
|
||||
}
|
||||
}
|
||||
|
||||
case ContextBarObserver::CancelDrag:
|
||||
void MovingPixelsState::cancelDrag()
|
||||
{
|
||||
if (!m_pixelsMovement || m_discarded)
|
||||
return;
|
||||
|
||||
switch (Preferences::instance().selection.cancelSelection()) {
|
||||
case gen::CancelSelection::DISCARD:
|
||||
m_pixelsMovement->discardImage(PixelsMovement::DontCommitChanges);
|
||||
m_discarded = true;
|
||||
|
||||
// Quit from MovingPixelsState, back to standby.
|
||||
m_editor->backToPreviousState();
|
||||
dropPixels();
|
||||
break;
|
||||
|
||||
case gen::CancelSelection::DESELECT: {
|
||||
dropPixels();
|
||||
|
||||
Command* cmd = Commands::instance()->byId(CommandId::DeselectMask());
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovingPixelsState::onConfigureDropPixels(ContextBarObserver::DropAction action,
|
||||
const gfx::Point& pt)
|
||||
{
|
||||
if (!isActiveEditor())
|
||||
return;
|
||||
|
||||
switch (action) {
|
||||
case ContextBarObserver::DropPixels:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case ContextBarObserver::CancelDrag: {
|
||||
Menu menu;
|
||||
|
||||
MenuItem discardChanges(Strings::context_bar_discard_changes());
|
||||
MenuItem deselect(Strings::context_bar_deselect());
|
||||
menu.addChild(&discardChanges);
|
||||
menu.addChild(&deselect);
|
||||
|
||||
auto& opt = Preferences::instance().selection.cancelSelection;
|
||||
discardChanges.setSelected(opt() == gen::CancelSelection::DISCARD);
|
||||
deselect.setSelected(opt() == gen::CancelSelection::DESELECT);
|
||||
|
||||
discardChanges.Click.connect([&opt] { opt(gen::CancelSelection::DISCARD); });
|
||||
deselect.Click.connect([&opt] { opt(gen::CancelSelection::DESELECT); });
|
||||
|
||||
ContextBar* contextBar = App::instance()->contextBar();
|
||||
menu.showPopup(pt, contextBar->display());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -77,6 +77,7 @@ public:
|
|||
|
||||
// ContextBarObserver
|
||||
void onDropPixels(ContextBarObserver::DropAction action) override;
|
||||
void onConfigureDropPixels(ContextBarObserver::DropAction action, const gfx::Point& pt) override;
|
||||
|
||||
// PixelsMovementDelegate
|
||||
void onPivotChange() override;
|
||||
|
@ -95,6 +96,7 @@ private:
|
|||
|
||||
void setTransparentColor(bool opaque, const app::Color& color);
|
||||
void dropPixels();
|
||||
void cancelDrag();
|
||||
|
||||
bool isActiveDocument() const;
|
||||
bool isActiveEditor() const;
|
||||
|
|
|
@ -1030,7 +1030,8 @@ bool StandbyState::Decorator::getSymmetryHandles(Editor* editor, Handles& handle
|
|||
|
||||
if ((int(mode) & int(app::gen::SymmetryMode::HORIZONTAL)) ||
|
||||
(int(mode) & int(app::gen::SymmetryMode::RIGHT_DIAG)) ||
|
||||
(int(mode) & int(app::gen::SymmetryMode::LEFT_DIAG))) {
|
||||
(int(mode) & int(app::gen::SymmetryMode::LEFT_DIAG)) ||
|
||||
(int(mode) & int(app::gen::SymmetryMode::POINT))) {
|
||||
double pos = symmetry.xAxis();
|
||||
gfx::PointF pt1, pt2;
|
||||
|
||||
|
@ -1051,7 +1052,8 @@ bool StandbyState::Decorator::getSymmetryHandles(Editor* editor, Handles& handle
|
|||
|
||||
if ((int(mode) & int(app::gen::SymmetryMode::VERTICAL)) ||
|
||||
(int(mode) & int(app::gen::SymmetryMode::RIGHT_DIAG)) ||
|
||||
(int(mode) & int(app::gen::SymmetryMode::LEFT_DIAG))) {
|
||||
(int(mode) & int(app::gen::SymmetryMode::LEFT_DIAG)) ||
|
||||
(int(mode) & int(app::gen::SymmetryMode::POINT))) {
|
||||
double pos = symmetry.yAxis();
|
||||
gfx::PointF pt1, pt2;
|
||||
|
||||
|
|
|
@ -74,7 +74,11 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||
double dz = delta.x + delta.y;
|
||||
WheelAction wheelAction = WheelAction::None;
|
||||
|
||||
if (KeyboardShortcuts::instance()->hasMouseWheelCustomization()) {
|
||||
if (tools::Tool* quickTool = App::instance()->activeToolManager()->quickTool();
|
||||
quickTool && quickTool->getId() == tools::WellKnownInks::Zoom) {
|
||||
wheelAction = WheelAction::Zoom;
|
||||
}
|
||||
else if (KeyboardShortcuts::instance()->hasMouseWheelCustomization()) {
|
||||
if (!Preferences::instance().editor.zoomWithSlide() && msg->preciseWheel())
|
||||
wheelAction = WheelAction::VScroll;
|
||||
else
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -181,8 +181,7 @@ void SliceWindow::onPivotChange()
|
|||
void SliceWindow::onToggleUserData()
|
||||
{
|
||||
m_userDataView.toggleVisibility();
|
||||
remapWindow();
|
||||
manager()->invalidate();
|
||||
expandWindow(gfx::Size(bounds().w, sizeHint().h));
|
||||
}
|
||||
|
||||
void SliceWindow::onModifyField(ui::Entry* entry, const Mods mods)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -132,8 +132,7 @@ void TagWindow::onRepeatChange()
|
|||
void TagWindow::onToggleUserData()
|
||||
{
|
||||
m_userDataView.toggleVisibility();
|
||||
remapWindow();
|
||||
manager()->invalidate();
|
||||
expandWindow(gfx::Size(bounds().w, sizeHint().h));
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -4576,7 +4576,7 @@ void Timeline::onDrop(ui::DragEvent& e)
|
|||
|
||||
// Determine at which frame and layer the content was dropped on.
|
||||
frame_t frame = m_frame;
|
||||
layer_t layerIndex = getLayerIndex(m_layer);
|
||||
layer_t layerIndex = m_sprite->root()->getLayerIndex(m_layer);
|
||||
InsertionPoint insert = InsertionPoint::BeforeLayer;
|
||||
DroppedOn droppedOn = DroppedOn::Unspecified;
|
||||
TRACE("m_dropRange.type() %d\n", m_dropRange.type());
|
||||
|
@ -4602,7 +4602,7 @@ void Timeline::onDrop(ui::DragEvent& e)
|
|||
break;
|
||||
case Range::kLayers:
|
||||
droppedOn = DroppedOn::Layer;
|
||||
if (m_dropTarget.vhit != DropTarget::VeryBottom) {
|
||||
if (m_dropTarget.vhit != DropTarget::VeryBottom && !m_dropRange.selectedLayers().empty()) {
|
||||
auto* selectedLayer = *m_dropRange.selectedLayers().begin();
|
||||
layerIndex = getLayerIndex(selectedLayer);
|
||||
}
|
||||
|
|
|
@ -597,4 +597,22 @@ void LayerGroup::displaceFrames(frame_t fromThis, frame_t delta)
|
|||
layer->displaceFrames(fromThis, delta);
|
||||
}
|
||||
|
||||
layer_t LayerGroup::getLayerIndex(const Layer* layer, layer_t& index) const
|
||||
{
|
||||
for (Layer* child : this->layers()) {
|
||||
if ((child->isGroup() && static_cast<LayerGroup*>(child)->getLayerIndex(layer, index) != -1) ||
|
||||
(child == layer)) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
layer_t LayerGroup::getLayerIndex(const Layer* layer) const
|
||||
{
|
||||
layer_t index = 0;
|
||||
return this->getLayerIndex(layer, index);
|
||||
}
|
||||
|
||||
} // namespace doc
|
||||
|
|
|
@ -236,9 +236,13 @@ public:
|
|||
|
||||
bool isBrowsable() const override { return isGroup() && isExpanded() && !m_layers.empty(); }
|
||||
|
||||
layer_t getLayerIndex(const Layer* layer) const;
|
||||
|
||||
private:
|
||||
void destroyAllLayers();
|
||||
|
||||
layer_t getLayerIndex(const Layer* layer, layer_t& index) const;
|
||||
|
||||
LayerList m_layers;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite Document Library
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
|
@ -46,24 +46,16 @@ void for_each_mask_pixel(Mask& a, const Mask& b, Func f)
|
|||
|
||||
Mask::Mask() : Object(ObjectType::Mask)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
Mask::Mask(const Mask& mask) : Object(mask)
|
||||
{
|
||||
initialize();
|
||||
copyFrom(&mask);
|
||||
}
|
||||
|
||||
Mask::~Mask()
|
||||
{
|
||||
ASSERT(m_freeze_count == 0);
|
||||
}
|
||||
|
||||
void Mask::initialize()
|
||||
{
|
||||
m_freeze_count = 0;
|
||||
m_bounds = gfx::Rect(0, 0, 0, 0);
|
||||
ASSERT(m_freezes == 0);
|
||||
}
|
||||
|
||||
int Mask::getMemSize() const
|
||||
|
@ -78,17 +70,17 @@ void Mask::setName(const char* name)
|
|||
|
||||
void Mask::freeze()
|
||||
{
|
||||
ASSERT(m_freeze_count >= 0);
|
||||
m_freeze_count++;
|
||||
ASSERT(m_freezes >= 0);
|
||||
m_freezes++;
|
||||
}
|
||||
|
||||
void Mask::unfreeze()
|
||||
{
|
||||
ASSERT(m_freeze_count > 0);
|
||||
m_freeze_count--;
|
||||
ASSERT(m_freezes > 0);
|
||||
m_freezes--;
|
||||
|
||||
// Shrink just in case
|
||||
if (m_freeze_count == 0)
|
||||
if (m_freezes == 0)
|
||||
shrink();
|
||||
}
|
||||
|
||||
|
@ -110,7 +102,7 @@ bool Mask::isRectangular() const
|
|||
|
||||
void Mask::copyFrom(const Mask* sourceMask)
|
||||
{
|
||||
ASSERT(m_freeze_count == 0);
|
||||
ASSERT(m_freezes == 0);
|
||||
|
||||
clear();
|
||||
setName(sourceMask->name().c_str());
|
||||
|
@ -245,10 +237,10 @@ void Mask::intersect(const doc::Mask& mask)
|
|||
|
||||
void Mask::add(const gfx::Rect& bounds)
|
||||
{
|
||||
if (m_freeze_count == 0)
|
||||
if (m_freezes == 0)
|
||||
reserve(bounds);
|
||||
|
||||
// m_bitmap can be nullptr if we have m_freeze_count > 0
|
||||
// m_bitmap can be nullptr if we have m_freezes > 0
|
||||
if (!m_bitmap)
|
||||
return;
|
||||
|
||||
|
@ -490,7 +482,7 @@ void Mask::reserve(const gfx::Rect& bounds)
|
|||
void Mask::shrink()
|
||||
{
|
||||
// If the mask is frozen we avoid the shrinking
|
||||
if (m_freeze_count > 0)
|
||||
if (m_freezes > 0)
|
||||
return;
|
||||
|
||||
#define SHRINK_SIDE(u_begin, u_op, u_final, u_add, v_begin, v_op, v_final, v_add, U, V, var) \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite Document Library
|
||||
// Copyright (c) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (c) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
void unfreeze();
|
||||
|
||||
// Returns true if the mask is frozen (See freeze/unfreeze functions).
|
||||
bool isFrozen() const { return m_freeze_count > 0; }
|
||||
bool isFrozen() const { return m_freezes > 0; }
|
||||
|
||||
// Returns true if the mask is a rectangular region.
|
||||
bool isRectangular() const;
|
||||
|
@ -107,9 +107,7 @@ public:
|
|||
void offsetOrigin(int dx, int dy);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
int m_freeze_count;
|
||||
int m_freezes = 0;
|
||||
std::string m_name; // Mask name
|
||||
gfx::Rect m_bounds; // Region bounds
|
||||
ImageRef m_bitmap; // Bitmapped image mask
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite UI Library
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
@ -87,7 +87,8 @@ void Display::configureBackLayer()
|
|||
layerSurface->width() != displaySurface->width() ||
|
||||
layerSurface->height() != displaySurface->height()) {
|
||||
layerSurface = os::System::instance()->makeSurface(displaySurface->width(),
|
||||
displaySurface->height());
|
||||
displaySurface->height(),
|
||||
displaySurface->colorSpace());
|
||||
layer->setSurface(layerSurface);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 8607be393dfd81614611897a6e3026fe94a3966c
|
||||
Subproject commit d14c2d1764f800d31b51893fb3d1e05d77a9280b
|
Loading…
Reference in New Issue