mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 13:21:34 +00:00
Merge 5570559c34da972fea97cc93d16c78ba06f825b1 into 9378f44191ecf4afd4dda27ab54b77aec0097eea
This commit is contained in:
commit
d9b1d66b8a
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2025 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2014-2018 David Capello -->
|
||||
<preferences>
|
||||
|
||||
@ -522,6 +522,7 @@
|
||||
<option id="mode" type="SymmetryMode" default="SymmetryMode::NONE" />
|
||||
<option id="x_axis" type="double" default="0" />
|
||||
<option id="y_axis" type="double" default="0" />
|
||||
<option id="button_flags" type="int" default="0" />
|
||||
</section>
|
||||
<section id="grid" canforce="true">
|
||||
<option id="snap" type="bool" default="false" />
|
||||
|
@ -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
|
||||
@ -1530,14 +1530,10 @@ public:
|
||||
|
||||
DocumentPreferences& docPref = Preferences::instance().document(doc);
|
||||
|
||||
at(0)->setSelected(
|
||||
int(docPref.symmetry.mode()) & int(app::gen::SymmetryMode::HORIZONTAL) ? true : false);
|
||||
at(1)->setSelected(
|
||||
int(docPref.symmetry.mode()) & int(app::gen::SymmetryMode::VERTICAL) ? true : false);
|
||||
at(2)->setSelected(
|
||||
int(docPref.symmetry.mode()) & int(app::gen::SymmetryMode::RIGHT_DIAG) ? true : false);
|
||||
at(3)->setSelected(
|
||||
int(docPref.symmetry.mode()) & int(app::gen::SymmetryMode::LEFT_DIAG) ? true : false);
|
||||
at(0)->setSelected(docPref.symmetry.buttonFlags() & int(app::gen::SymmetryMode::HORIZONTAL));
|
||||
at(1)->setSelected(docPref.symmetry.buttonFlags() & int(app::gen::SymmetryMode::VERTICAL));
|
||||
at(2)->setSelected(docPref.symmetry.buttonFlags() & int(app::gen::SymmetryMode::RIGHT_DIAG));
|
||||
at(3)->setSelected(docPref.symmetry.buttonFlags() & int(app::gen::SymmetryMode::LEFT_DIAG));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1551,75 +1547,29 @@ private:
|
||||
|
||||
DocumentPreferences& docPref = Preferences::instance().document(doc);
|
||||
|
||||
auto oldMode = docPref.symmetry.mode();
|
||||
int mode = 0;
|
||||
int buttonFlags = 0;
|
||||
if (at(0)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::HORIZONTAL);
|
||||
buttonFlags |= int(app::gen::SymmetryMode::HORIZONTAL);
|
||||
if (at(1)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::VERTICAL);
|
||||
buttonFlags |= int(app::gen::SymmetryMode::VERTICAL);
|
||||
if (at(2)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::RIGHT_DIAG);
|
||||
buttonFlags |= int(app::gen::SymmetryMode::RIGHT_DIAG);
|
||||
if (at(3)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::LEFT_DIAG);
|
||||
buttonFlags |= int(app::gen::SymmetryMode::LEFT_DIAG);
|
||||
|
||||
// Non sense symmetries filter:
|
||||
// - H + 1Diag
|
||||
// - V + 1Diag
|
||||
// - H + V + 1Diag
|
||||
const bool HorV = (mode & int(app::gen::SymmetryMode::HORIZONTAL)) ||
|
||||
(mode & int(app::gen::SymmetryMode::VERTICAL));
|
||||
const bool HxorV = !(mode & int(app::gen::SymmetryMode::HORIZONTAL)) !=
|
||||
!(mode & int(app::gen::SymmetryMode::VERTICAL));
|
||||
const bool RDxorLD = !(mode & int(app::gen::SymmetryMode::RIGHT_DIAG)) !=
|
||||
!(mode & int(app::gen::SymmetryMode::LEFT_DIAG));
|
||||
if (oldMode == gen::SymmetryMode::HORIZONTAL || oldMode == gen::SymmetryMode::VERTICAL ||
|
||||
oldMode == gen::SymmetryMode::BOTH) {
|
||||
if (HorV && RDxorLD) {
|
||||
mode = int(app::gen::SymmetryMode::ALL);
|
||||
at(0)->setSelected(true);
|
||||
at(1)->setSelected(true);
|
||||
at(2)->setSelected(true);
|
||||
at(3)->setSelected(true);
|
||||
}
|
||||
}
|
||||
else if (oldMode == gen::SymmetryMode::ALL) {
|
||||
if (HxorV) {
|
||||
mode = int(app::gen::SymmetryMode::BOTH_DIAG);
|
||||
at(0)->setSelected(false);
|
||||
at(1)->setSelected(false);
|
||||
}
|
||||
else if (RDxorLD) {
|
||||
mode = int(app::gen::SymmetryMode::BOTH);
|
||||
at(2)->setSelected(false);
|
||||
at(3)->setSelected(false);
|
||||
}
|
||||
}
|
||||
else if ((oldMode == gen::SymmetryMode::RIGHT_DIAG || oldMode == gen::SymmetryMode::LEFT_DIAG ||
|
||||
oldMode == gen::SymmetryMode::BOTH_DIAG) &&
|
||||
HorV) {
|
||||
mode = int(app::gen::SymmetryMode::ALL);
|
||||
at(0)->setSelected(true);
|
||||
at(1)->setSelected(true);
|
||||
at(2)->setSelected(true);
|
||||
at(3)->setSelected(true);
|
||||
}
|
||||
// Non sense symmetries filter end
|
||||
const bool forceAllMode = ((buttonFlags & int(app::gen::SymmetryMode::HORIZONTAL)) ||
|
||||
(buttonFlags & int(app::gen::SymmetryMode::VERTICAL))) &&
|
||||
((buttonFlags & int(app::gen::SymmetryMode::RIGHT_DIAG)) ||
|
||||
(buttonFlags & int(app::gen::SymmetryMode::LEFT_DIAG)));
|
||||
|
||||
if (at(0)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::HORIZONTAL);
|
||||
if (at(1)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::VERTICAL);
|
||||
if (at(2)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::RIGHT_DIAG);
|
||||
if (at(3)->isSelected())
|
||||
mode |= int(app::gen::SymmetryMode::LEFT_DIAG);
|
||||
|
||||
if (app::gen::SymmetryMode(mode) != docPref.symmetry.mode()) {
|
||||
docPref.symmetry.mode(app::gen::SymmetryMode(mode));
|
||||
// Redraw symmetry rules
|
||||
if (buttonFlags != docPref.symmetry.buttonFlags()) {
|
||||
docPref.symmetry.mode(forceAllMode ? app::gen::SymmetryMode::ALL :
|
||||
app::gen::SymmetryMode(buttonFlags));
|
||||
docPref.symmetry.buttonFlags(buttonFlags);
|
||||
doc->notifyGeneralUpdate();
|
||||
}
|
||||
else if (at(4)->isSelected()) {
|
||||
|
||||
if (at(4)->isSelected()) {
|
||||
auto* item = at(4);
|
||||
|
||||
gfx::Rect bounds = item->bounds();
|
||||
|
@ -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
|
||||
@ -831,6 +831,85 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g,
|
||||
m_docPref.grid.forceSection();
|
||||
}
|
||||
m_docPref.show.grid.forceDirtyFlag();
|
||||
|
||||
// Symmetry mode
|
||||
if (isActive() && (m_flags & Editor::kShowSymmetryLine) &&
|
||||
Preferences::instance().symmetryMode.enabled()) {
|
||||
const int mode = int(m_docPref.symmetry.mode());
|
||||
const gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color());
|
||||
const gfx::Color semiTransparentColor =
|
||||
gfx::rgba(rgba_getr(color), rgba_getg(color), rgba_getb(color), rgba_geta(color) / 4);
|
||||
const int symmetryButtonFlags = m_docPref.symmetry.buttonFlags();
|
||||
const double x = int(m_proj.applyX<double>(m_docPref.symmetry.xAxis()));
|
||||
const double y = int(m_proj.applyY<double>(m_docPref.symmetry.yAxis()));
|
||||
|
||||
if (mode & int(app::gen::SymmetryMode::HORIZONTAL) && x > 0) {
|
||||
g->drawVLine(symmetryButtonFlags & int(app::gen::SymmetryMode::HORIZONTAL) ?
|
||||
color :
|
||||
semiTransparentColor,
|
||||
enclosingRect.x + x,
|
||||
enclosingRect.y,
|
||||
enclosingRect.h);
|
||||
}
|
||||
if (mode & int(app::gen::SymmetryMode::VERTICAL) && y > 0) {
|
||||
g->drawHLine(symmetryButtonFlags & int(app::gen::SymmetryMode::VERTICAL) ?
|
||||
color :
|
||||
semiTransparentColor,
|
||||
enclosingRect.x,
|
||||
enclosingRect.y + y,
|
||||
enclosingRect.w);
|
||||
}
|
||||
if (mode & int(app::gen::SymmetryMode::RIGHT_DIAG)) {
|
||||
// Bottom point intersection:
|
||||
gfx::Point bottomLeft(
|
||||
enclosingRect.x + x + m_proj.turnYinTermsOfX<int>(y - enclosingRect.h),
|
||||
enclosingRect.y2());
|
||||
if (bottomLeft.x < enclosingRect.x) {
|
||||
// Left intersection
|
||||
bottomLeft.y = enclosingRect.y2() +
|
||||
m_proj.turnXinTermsOfY<int>(bottomLeft.x - enclosingRect.x);
|
||||
bottomLeft.x = enclosingRect.x;
|
||||
}
|
||||
// Top intersection
|
||||
gfx::Point topRight(enclosingRect.x + x + m_proj.turnYinTermsOfX<int>(y),
|
||||
enclosingRect.y);
|
||||
if (enclosingRect.x2() < topRight.x) {
|
||||
// Right intersection
|
||||
topRight.y = enclosingRect.y +
|
||||
m_proj.applyY<int>(m_proj.removeX<int>(topRight.x - enclosingRect.x2()));
|
||||
topRight.x = enclosingRect.x2();
|
||||
}
|
||||
g->drawLine(symmetryButtonFlags & int(app::gen::SymmetryMode::RIGHT_DIAG) ?
|
||||
color :
|
||||
semiTransparentColor,
|
||||
bottomLeft,
|
||||
topRight);
|
||||
}
|
||||
if (mode & int(app::gen::SymmetryMode::LEFT_DIAG)) {
|
||||
// Bottom point intersection:
|
||||
gfx::Point bottomRight(
|
||||
enclosingRect.x + x + m_proj.turnYinTermsOfX<int>(enclosingRect.h - y),
|
||||
enclosingRect.y2());
|
||||
if (enclosingRect.x2() < bottomRight.x) {
|
||||
// Left intersection
|
||||
bottomRight.y = enclosingRect.y2() +
|
||||
m_proj.turnXinTermsOfY<int>(enclosingRect.x2() - bottomRight.x);
|
||||
bottomRight.x = enclosingRect.x2();
|
||||
}
|
||||
// Top intersection
|
||||
gfx::Point topLeft(enclosingRect.x + x - m_proj.turnYinTermsOfX<int>(y), enclosingRect.y);
|
||||
if (topLeft.x < enclosingRect.x) {
|
||||
// Right intersection
|
||||
topLeft.y = enclosingRect.y + m_proj.turnXinTermsOfY<int>(enclosingRect.x - topLeft.x);
|
||||
topLeft.x = enclosingRect.x;
|
||||
}
|
||||
g->drawLine(symmetryButtonFlags & int(app::gen::SymmetryMode::LEFT_DIAG) ?
|
||||
color :
|
||||
semiTransparentColor,
|
||||
topLeft,
|
||||
bottomRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -907,86 +986,6 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
|
||||
if (m_docPref.show.slices())
|
||||
drawSlices(g);
|
||||
|
||||
// Symmetry mode
|
||||
if (isActive() && (m_flags & Editor::kShowSymmetryLine) &&
|
||||
Preferences::instance().symmetryMode.enabled()) {
|
||||
int mode = int(m_docPref.symmetry.mode());
|
||||
if (mode & int(app::gen::SymmetryMode::HORIZONTAL)) {
|
||||
double x = m_docPref.symmetry.xAxis();
|
||||
if (x > 0) {
|
||||
gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color());
|
||||
g->drawVLine(
|
||||
color,
|
||||
spriteRect.x + m_proj.applyX(mainTilePosition().x) + int(m_proj.applyX<double>(x)),
|
||||
enclosingRect.y,
|
||||
enclosingRect.h);
|
||||
}
|
||||
}
|
||||
if (mode & int(app::gen::SymmetryMode::VERTICAL)) {
|
||||
double y = m_docPref.symmetry.yAxis();
|
||||
if (y > 0) {
|
||||
gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color());
|
||||
g->drawHLine(
|
||||
color,
|
||||
enclosingRect.x,
|
||||
spriteRect.y + m_proj.applyY(mainTilePosition().y) + int(m_proj.applyY<double>(y)),
|
||||
enclosingRect.w);
|
||||
}
|
||||
}
|
||||
if (mode & int(app::gen::SymmetryMode::RIGHT_DIAG)) {
|
||||
double y = m_docPref.symmetry.yAxis();
|
||||
double x = m_docPref.symmetry.xAxis();
|
||||
gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color());
|
||||
// Bottom point intersection:
|
||||
gfx::Point bottomLeft(
|
||||
enclosingRect.x + m_proj.applyY(mainTilePosition().x) + int(m_proj.applyX<double>(x)) -
|
||||
(enclosingRect.h - m_proj.applyY(mainTilePosition().y) - int(m_proj.applyY<double>(y))),
|
||||
enclosingRect.y2());
|
||||
if (bottomLeft.x < enclosingRect.x) {
|
||||
// Left intersection
|
||||
bottomLeft.y = enclosingRect.y2() - enclosingRect.x + bottomLeft.x;
|
||||
bottomLeft.x = enclosingRect.x;
|
||||
}
|
||||
// Top intersection
|
||||
gfx::Point topRight(enclosingRect.x + m_proj.applyY(mainTilePosition().x) +
|
||||
int(m_proj.applyX<double>(x)) + m_proj.applyY(mainTilePosition().y) +
|
||||
int(m_proj.applyY<double>(y)),
|
||||
enclosingRect.y);
|
||||
if (enclosingRect.x2() < topRight.x) {
|
||||
// Right intersection
|
||||
topRight.y = enclosingRect.y + topRight.x - enclosingRect.x2();
|
||||
topRight.x = enclosingRect.x2();
|
||||
}
|
||||
g->drawLine(color, bottomLeft, topRight);
|
||||
}
|
||||
if (mode & int(app::gen::SymmetryMode::LEFT_DIAG)) {
|
||||
double y = m_docPref.symmetry.yAxis();
|
||||
double x = m_docPref.symmetry.xAxis();
|
||||
gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color());
|
||||
// Bottom point intersection:
|
||||
gfx::Point bottomRight(
|
||||
enclosingRect.x + m_proj.applyY(mainTilePosition().x) + int(m_proj.applyX<double>(x)) +
|
||||
(enclosingRect.h - m_proj.applyY(mainTilePosition().y) - int(m_proj.applyX<double>(y))),
|
||||
enclosingRect.y2());
|
||||
if (enclosingRect.x2() < bottomRight.x) {
|
||||
// Left intersection
|
||||
bottomRight.y = enclosingRect.y2() - bottomRight.x + enclosingRect.x2();
|
||||
bottomRight.x = enclosingRect.x2();
|
||||
}
|
||||
// Top intersection
|
||||
gfx::Point topLeft(enclosingRect.x + m_proj.applyY(mainTilePosition().x) +
|
||||
int(m_proj.applyX<double>(x)) - m_proj.applyY(mainTilePosition().y) -
|
||||
int(m_proj.applyY<double>(y)),
|
||||
enclosingRect.y);
|
||||
if (topLeft.x < enclosingRect.x) {
|
||||
// Right intersection
|
||||
topLeft.y = enclosingRect.y + enclosingRect.x - topLeft.x;
|
||||
topLeft.x = enclosingRect.x;
|
||||
}
|
||||
g->drawLine(color, topLeft, bottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw active layer/cel edges
|
||||
if ((m_docPref.show.layerEdges() || m_showAutoCelGuides) &&
|
||||
// Show layer edges and possibly cel guides only on states that
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Render Library
|
||||
// Copyright (c) 2020 Igara Studio S.A.
|
||||
// Copyright (c) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (c) 2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -70,6 +70,20 @@ public:
|
||||
return T(m_zoom.removeCeiling(y)) / T(m_pixelRatio.h);
|
||||
}
|
||||
|
||||
// Used in 'editor.cpp' to do some math between x,y values.
|
||||
// Useful for calculating diagonal symmetry axis positions when pixel ratio is other than 1:1
|
||||
template<typename T>
|
||||
T turnXinTermsOfY(T x) const
|
||||
{
|
||||
return x * T(m_pixelRatio.h) / T(m_pixelRatio.w);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T turnYinTermsOfX(T y) const
|
||||
{
|
||||
return y * T(m_pixelRatio.w) / T(m_pixelRatio.h);
|
||||
}
|
||||
|
||||
gfx::Rect apply(const gfx::Rect& r) const
|
||||
{
|
||||
int u = applyX(r.x);
|
||||
|
Loading…
x
Reference in New Issue
Block a user