Add Import Sprite Sheet padding (fix #78)

This commit is contained in:
Gaspar Capello 2019-01-21 15:16:32 -03:00 committed by David Capello
parent 67e0da478d
commit d4607e889b
6 changed files with 364 additions and 71 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2018 Igara Studio S.A. --> <!-- Copyright (C) 2018-2019 Igara Studio S.A. -->
<!-- Copyright (C) 2014-2018 David Capello --> <!-- Copyright (C) 2014-2018 David Capello -->
<preferences> <preferences>
@ -436,6 +436,7 @@
<section id="import_sprite_sheet"> <section id="import_sprite_sheet">
<option id="type" type="app::SpriteSheetType" default="app::SpriteSheetType::Rows" /> <option id="type" type="app::SpriteSheetType" default="app::SpriteSheetType::Rows" />
<option id="bounds" type="gfx::Rect" default="gfx::Rect(0, 0, 0, 0)" /> <option id="bounds" type="gfx::Rect" default="gfx::Rect(0, 0, 0, 0)" />
<option id="padding_bounds" type="gfx::Size" default="gfx::Size(0, 0)" />
<option id="partial_tiles" type="bool" default="false" /> <option id="partial_tiles" type="bool" default="false" />
</section> </section>
<section id="preview" text="Preview"> <section id="preview" text="Preview">

View File

@ -1,5 +1,5 @@
# Aseprite # Aseprite
# Copyright (C) 2018 Igara Studio S.A. # Copyright (C) 2018-2019 Igara Studio S.A.
# Copyright (C) 2016-2018 David Capello # Copyright (C) 2016-2018 David Capello
[advanced_mode] [advanced_mode]
@ -624,6 +624,8 @@ x = X:
y = Y: y = Y:
width = Width: width = Width:
height = Height: height = Height:
horizontal_padding = Horizontal:
vertical_padding = Vertical:
partial_tiles = Include partial tiles at bottom/right edges partial_tiles = Include partial tiles at bottom/right edges
import = &Import import = &Import
cancel = &Cancel cancel = &Cancel

View File

@ -1,34 +1,49 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2019 by Igara Studio S.A. -->
<!-- Copyright (C) 2001-2018 by David Capello --> <!-- Copyright (C) 2001-2018 by David Capello -->
<gui> <gui>
<window id="import_sprite_sheet" text="@.title"> <window id="import_sprite_sheet" text="@.title">
<grid columns="4"> <vbox>
<button id="select_file" text="@.select_file" cell_hspan="4" /> <grid columns="4">
<button id="select_file" text="@.select_file" cell_hspan="4" />
<label text="@.type" /> <label text="@.type" />
<combobox id="sheet_type" cell_hspan="3" /> <combobox id="sheet_type" cell_hspan="3" />
<label text="@.x" /> <separator text="Tiles:" horizontal="true" cell_hspan="4" />
<expr id="x" text="0" />
<label text="@.y" /> <label text="@.x" />
<expr id="y" text="0" /> <expr id="x" text="0" />
<label text="@.width" /> <label text="@.y" />
<expr id="width" text="16" /> <expr id="y" text="0" />
<label text="@.height" /> <label text="@.width" />
<expr id="height" text="16" /> <expr id="width" text="16" />
<check id="partial_tiles" text="@.partial_tiles" cell_hspan="4" /> <label text="@.height" />
<expr id="height" text="16" />
<hbox cell_hspan="4"> <separator text="Padding:" horizontal="true" cell_hspan="4" />
<boxfiller />
<hbox> <label text="@.horizontal_padding" />
</hbox> <expr id="horizontal_padding" text="0" />
<button id="import" text="@.import" minwidth="60" magnet="true" cell_align="center" closewindow="true" /> <label text="" cell_hspan="2" />
<button id="cancel" text="@.cancel" minwidth="60" cell_align="center" closewindow="true" />
</hbox> <label text="@.vertical_padding" />
</grid> <expr id="vertical_padding" text="0" />
<label text="" cell_hspan="2" />
<check id="partial_tiles" text="@.partial_tiles" cell_hspan="4" />
<hbox cell_hspan="4">
<boxfiller />
<hbox>
</hbox>
<button id="import" text="@.import" minwidth="60" magnet="true" cell_align="center" closewindow="true" />
<button id="cancel" text="@.cancel" minwidth="60" cell_align="center" closewindow="true" />
</hbox>
</grid>
</vbox>
</window> </window>
</gui> </gui>

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -73,6 +74,9 @@ public:
y()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this)); y()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
width()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this)); width()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
height()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this)); height()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
horizontalPadding()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
verticalPadding()->Change.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
partialTiles()->Click.connect(base::Bind<void>(&ImportSpriteSheetWindow::onEntriesChange, this));
selectFile()->Click.connect(base::Bind<void>(&ImportSpriteSheetWindow::onSelectFile, this)); selectFile()->Click.connect(base::Bind<void>(&ImportSpriteSheetWindow::onSelectFile, this));
remapWindow(); remapWindow();
@ -113,6 +117,10 @@ public:
return m_rect; return m_rect;
} }
gfx::Size paddingThickness() const {
return m_padding;
}
protected: protected:
void onSheetTypeChange() { void onSheetTypeChange() {
@ -144,16 +152,31 @@ protected:
std::max<int>(1, h)); std::max<int>(1, h));
} }
gfx::Size getPaddingFromEntries() {
int padW = horizontalPadding()->textInt();
int padH = verticalPadding()->textInt();
if (padW < 0)
padW = 0;
if (padH < 0)
padH = 0;
return gfx::Size(padW, padH);
}
void onEntriesChange() { void onEntriesChange() {
m_rect = getRectFromEntries(); m_rect = getRectFromEntries();
m_padding = getPaddingFromEntries();
// Redraw new rulers position // Redraw new rulers position
if (m_editor) { if (m_editor) {
EditorStatePtr state = m_editor->getState(); EditorStatePtr state = m_editor->getState();
if (SelectBoxState* boxState = dynamic_cast<SelectBoxState*>(state.get())) { SelectBoxState* boxState = dynamic_cast<SelectBoxState*>(state.get());
boxState->setBoxBounds(m_rect); boxState->setBoxBounds(m_rect);
m_editor->invalidate(); boxState->setPaddingBounds(m_padding);
} if (partialTilesValue())
boxState->setFlag(SelectBoxState::Flags::IncludePartialTiles);
else
boxState->clearFlag(SelectBoxState::Flags::IncludePartialTiles);
m_editor->invalidate();
} }
} }
@ -184,6 +207,16 @@ protected:
height()->setTextf("%d", m_rect.h); height()->setTextf("%d", m_rect.h);
} }
void onChangePadding(const gfx::Size& padding) override {
m_padding = padding;
if (padding.w < 0)
m_padding.w = 0;
if (padding.h < 0)
m_padding.h = 0;
horizontalPadding()->setTextf("%d", m_padding.w);
verticalPadding()->setTextf("%d", m_padding.h);
}
std::string onGetContextBarHelp() override { std::string onGetContextBarHelp() override {
return "Select bounds to identify sprite frames"; return "Select bounds to identify sprite frames";
} }
@ -218,9 +251,11 @@ private:
sheetType()->setSelectedItemIndex((int)app::SpriteSheetType::Rows-1); sheetType()->setSelectedItemIndex((int)app::SpriteSheetType::Rows-1);
gfx::Rect defBounds = m_docPref->importSpriteSheet.bounds(); gfx::Rect defBounds = m_docPref->importSpriteSheet.bounds();
gfx::Size defPaddingBounds = m_docPref->importSpriteSheet.paddingBounds();
if (defBounds.isEmpty()) if (defBounds.isEmpty())
defBounds = m_docPref->grid.bounds(); defBounds = m_docPref->grid.bounds();
onChangeRectangle(defBounds); onChangeRectangle(defBounds);
onChangePadding(defPaddingBounds);
partialTiles()->setSelected(m_docPref->importSpriteSheet.partialTiles()); partialTiles()->setSelected(m_docPref->importSpriteSheet.partialTiles());
onEntriesChange(); onEntriesChange();
@ -232,13 +267,17 @@ private:
if (m_document && !m_editor) { if (m_document && !m_editor) {
m_rect = getRectFromEntries(); m_rect = getRectFromEntries();
m_padding = getPaddingFromEntries();
m_editor = current_editor; m_editor = current_editor;
m_editorState.reset( m_editorState.reset(
new SelectBoxState( new SelectBoxState(
this, m_rect, this, m_rect,
SelectBoxState::Flags( SelectBoxState::Flags(
int(SelectBoxState::Flags::Rulers) | int(SelectBoxState::Flags::Rulers) |
int(SelectBoxState::Flags::Grid)))); int(SelectBoxState::Flags::Grid) |
int(SelectBoxState::Flags::DarkOutside) |
int(SelectBoxState::Flags::PaddingRulers)
)));
m_editor->setState(m_editorState); m_editor->setState(m_editorState);
updateGridState(); updateGridState();
@ -249,7 +288,8 @@ private:
if (!m_editorState) if (!m_editorState)
return; return;
int flags = int(SelectBoxState::Flags::Rulers); int flags = (int)static_cast<SelectBoxState*>(m_editorState.get())->getFlags();
flags = flags & ~((int)SelectBoxState::Flags::HGrid | (int)SelectBoxState::Flags::VGrid);
switch (sheetTypeValue()) { switch (sheetTypeValue()) {
case SpriteSheetType::Horizontal: case SpriteSheetType::Horizontal:
flags |= int(SelectBoxState::Flags::HGrid); flags |= int(SelectBoxState::Flags::HGrid);
@ -279,6 +319,7 @@ private:
Editor* m_editor; Editor* m_editor;
EditorStatePtr m_editorState; EditorStatePtr m_editorState;
gfx::Rect m_rect; gfx::Rect m_rect;
gfx::Size m_padding;
// True if the user has been opened the file (instead of selecting // True if the user has been opened the file (instead of selecting
// the current document). // the current document).
@ -311,6 +352,7 @@ void ImportSpriteSheetCommand::onExecute(Context* context)
Doc* document = window.document(); Doc* document = window.document();
DocumentPreferences* docPref = window.docPref(); DocumentPreferences* docPref = window.docPref();
gfx::Rect frameBounds = window.frameBounds(); gfx::Rect frameBounds = window.frameBounds();
gfx::Size padThickness = window.paddingThickness();
bool partialTiles = window.partialTilesValue(); bool partialTiles = window.partialTilesValue();
auto sheetType = window.sheetTypeValue(); auto sheetType = window.sheetTypeValue();
@ -337,25 +379,25 @@ void ImportSpriteSheetCommand::onExecute(Context* context)
switch (sheetType) { switch (sheetType) {
case app::SpriteSheetType::Horizontal: case app::SpriteSheetType::Horizontal:
for (int x=frameBounds.x; x+frameBounds.w<=widthStop; x += frameBounds.w) { for (int x=frameBounds.x; x+frameBounds.w<=widthStop; x+=frameBounds.w+padThickness.w) {
tileRects.push_back(gfx::Rect(x, frameBounds.y, frameBounds.w, frameBounds.h)); tileRects.push_back(gfx::Rect(x, frameBounds.y, frameBounds.w, frameBounds.h));
} }
break; break;
case app::SpriteSheetType::Vertical: case app::SpriteSheetType::Vertical:
for (int y=frameBounds.y; y+frameBounds.h<=heightStop; y += frameBounds.h) { for (int y=frameBounds.y; y+frameBounds.h<=heightStop; y+=frameBounds.h+padThickness.h) {
tileRects.push_back(gfx::Rect(frameBounds.x, y, frameBounds.w, frameBounds.h)); tileRects.push_back(gfx::Rect(frameBounds.x, y, frameBounds.w, frameBounds.h));
} }
break; break;
case app::SpriteSheetType::Rows: case app::SpriteSheetType::Rows:
for (int y=frameBounds.y; y+frameBounds.h<=heightStop; y += frameBounds.h) { for (int y=frameBounds.y; y+frameBounds.h<=heightStop; y+=frameBounds.h+padThickness.h) {
for (int x=frameBounds.x; x+frameBounds.w<=widthStop; x += frameBounds.w) { for (int x=frameBounds.x; x+frameBounds.w<=widthStop; x+=frameBounds.w+padThickness.w) {
tileRects.push_back(gfx::Rect(x, y, frameBounds.w, frameBounds.h)); tileRects.push_back(gfx::Rect(x, y, frameBounds.w, frameBounds.h));
} }
} }
break; break;
case app::SpriteSheetType::Columns: case app::SpriteSheetType::Columns:
for (int x=frameBounds.x; x+frameBounds.w<=sprite->width(); x += frameBounds.w) { for (int x=frameBounds.x; x+frameBounds.w<=widthStop; x+=frameBounds.w+padThickness.w) {
for (int y=frameBounds.y; y+frameBounds.h<=sprite->height(); y += frameBounds.h) { for (int y=frameBounds.y; y+frameBounds.h<=heightStop; y+=frameBounds.h+padThickness.h) {
tileRects.push_back(gfx::Rect(x, y, frameBounds.w, frameBounds.h)); tileRects.push_back(gfx::Rect(x, y, frameBounds.w, frameBounds.h));
} }
} }
@ -422,6 +464,7 @@ void ImportSpriteSheetCommand::onExecute(Context* context)
docPref->importSpriteSheet.type(sheetType); docPref->importSpriteSheet.type(sheetType);
docPref->importSpriteSheet.bounds(frameBounds); docPref->importSpriteSheet.bounds(frameBounds);
docPref->importSpriteSheet.partialTiles(partialTiles); docPref->importSpriteSheet.partialTiles(partialTiles);
docPref->importSpriteSheet.paddingBounds(padThickness);
} }
} }
catch (...) { catch (...) {

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -29,12 +30,16 @@ using namespace ui;
SelectBoxState::SelectBoxState(SelectBoxDelegate* delegate, const gfx::Rect& rc, Flags flags) SelectBoxState::SelectBoxState(SelectBoxDelegate* delegate, const gfx::Rect& rc, Flags flags)
: m_delegate(delegate) : m_delegate(delegate)
, m_rulers(4) , m_rulers((int(flags) & int(Flags::PaddingRulers))? 6: 4)
, m_rulersDragAlign(0) , m_rulersDragAlign(0)
, m_selectingBox(false) , m_selectingBox(false)
, m_flags(flags) , m_flags(flags)
{ {
setBoxBounds(rc); setBoxBounds(rc);
if (hasFlag(Flags::PaddingRulers)) {
gfx::Size padding(0, 0);
setPaddingBounds(padding);
}
} }
SelectBoxState::~SelectBoxState() SelectBoxState::~SelectBoxState()
@ -43,18 +48,33 @@ SelectBoxState::~SelectBoxState()
contextBar->updateForActiveTool(); contextBar->updateForActiveTool();
} }
SelectBoxState::Flags SelectBoxState::getFlags()
{
return m_flags;
}
void SelectBoxState::setFlags(Flags flags) void SelectBoxState::setFlags(Flags flags)
{ {
m_flags = flags; m_flags = flags;
} }
void SelectBoxState::setFlag(Flags flag)
{
m_flags = Flags(int(flag) | int(m_flags));
}
void SelectBoxState::clearFlag(Flags flag)
{
m_flags = Flags(~(int(flag)) & int(m_flags));
}
gfx::Rect SelectBoxState::getBoxBounds() const gfx::Rect SelectBoxState::getBoxBounds() const
{ {
int x1 = std::min(m_rulers[V1].position(), m_rulers[V2].position()); int x1 = std::min(m_rulers[V1].position(), m_rulers[V2].position());
int y1 = std::min(m_rulers[H1].position(), m_rulers[H2].position()); int y1 = std::min(m_rulers[H1].position(), m_rulers[H2].position());
int x2 = std::max(m_rulers[V1].position(), m_rulers[V2].position()); int x2 = std::max(m_rulers[V1].position(), m_rulers[V2].position());
int y2 = std::max(m_rulers[H1].position(), m_rulers[H2].position()); int y2 = std::max(m_rulers[H1].position(), m_rulers[H2].position());
return gfx::Rect(x1, y1, x2 - x1, y2 - y1); return gfx::Rect(x1, y1, x2-x1, y2-y1);
} }
void SelectBoxState::setBoxBounds(const gfx::Rect& box) void SelectBoxState::setBoxBounds(const gfx::Rect& box)
@ -65,6 +85,26 @@ void SelectBoxState::setBoxBounds(const gfx::Rect& box)
m_rulers[V2] = Ruler(Ruler::Vertical, box.x+box.w); m_rulers[V2] = Ruler(Ruler::Vertical, box.x+box.w);
} }
// Get and Set Padding for Import Sprite Sheet box state
gfx::Size SelectBoxState::getPaddingBounds() const
{
ASSERT(hasFlag(Flags::PaddingRulers));
int w = m_rulers[PV].position() - m_rulers[V2].position();
int h = m_rulers[PH].position() - m_rulers[H2].position();
if (w < 0)
w = 0;
if (h < 0)
h = 0;
return gfx::Size(w, h);
}
void SelectBoxState::setPaddingBounds(const gfx::Size& padding)
{
ASSERT(hasFlag(Flags::PaddingRulers));
m_rulers[PH] = Ruler(Ruler::Horizontal, m_rulers[H2].position() + padding.h);
m_rulers[PV] = Ruler(Ruler::Vertical, m_rulers[V2].position() + padding.w);
}
void SelectBoxState::onEnterState(Editor* editor) void SelectBoxState::onEnterState(Editor* editor)
{ {
StandbyState::onEnterState(editor); StandbyState::onEnterState(editor);
@ -178,8 +218,11 @@ bool SelectBoxState::onMouseMove(Editor* editor, MouseMessage* msg)
} }
if (used) { if (used) {
if (m_delegate) if (m_delegate) {
m_delegate->onChangeRectangle(getBoxBounds()); m_delegate->onChangeRectangle(getBoxBounds());
if (hasFlag(Flags::PaddingRulers))
m_delegate->onChangePadding(getPaddingBounds());
}
editor->invalidate(); editor->invalidate();
return true; return true;
@ -250,47 +293,220 @@ void SelectBoxState::postRenderDecorator(EditorPostRender* render)
const gfx::Color gridColor = skin::SkinTheme::instance()->colors.selectBoxGrid(); const gfx::Color gridColor = skin::SkinTheme::instance()->colors.selectBoxGrid();
const gfx::Point mainOffset = editor->mainTilePosition(); const gfx::Point mainOffset = editor->mainTilePosition();
gfx::Rect rc = getBoxBounds(); gfx::Rect rc = getBoxBounds();
gfx::Size padding;
if (hasFlag(Flags::PaddingRulers))
padding = getPaddingBounds();
rc.offset(mainOffset); rc.offset(mainOffset);
sp.offset(mainOffset); sp.offset(mainOffset);
// With black shadow? // With black shadow?
if (hasFlag(Flags::DarkOutside)) { if (hasFlag(Flags::DarkOutside)) {
const gfx::Color dark = doc::rgba(0, 0, 0, 128); if (hasFlag(Flags::PaddingRulers)) {
// Top band const gfx::Color dark = doc::rgba(0, 0, 0, 128);
if (rc.y > vp.y) // Top band
render->fillRect(dark, gfx::Rect(vp.x, vp.y, vp.w, rc.y-vp.y)); if (rc.y > vp.y)
// Bottom band render->fillRect(dark, gfx::Rect(vp.x, vp.y, vp.w, rc.y-vp.y));
if (rc.y2() < vp.y2()) // Left band
render->fillRect(dark, gfx::Rect(vp.x, rc.y2(), vp.w, vp.y2()-rc.y2())); if (rc.x > vp.x)
// Left band render->fillRect(dark, gfx::Rect(vp.x, rc.y, rc.x-vp.x, vp.y2()-rc.y));
if (rc.x > vp.x) if (hasFlag(Flags::VGrid)) {
render->fillRect(dark, gfx::Rect(vp.x, rc.y, rc.x-vp.x, rc.h)); // Bottom band
// Right band if (sp.y2() < vp.y2())
if (rc.x2() < vp.x2()) render->fillRect(dark, gfx::Rect(rc.x, sp.y2(), vp.x2()-rc.x, vp.y2()-sp.y2()));
render->fillRect(dark, gfx::Rect(rc.x2(), rc.y, vp.x2()-rc.x2(), rc.h)); // Right band
} if (hasFlag(Flags::HGrid)) {
// VGrid Active, HGrid Active:
if (sp.x2() < vp.x2())
render->fillRect(dark, gfx::Rect(sp.x2(), rc.y, vp.x2()-sp.x2(), sp.y2()-rc.y));
}
else {
// Just VGrid Active, HGrid disabled:
if (rc.x2() < vp.x2())
render->fillRect(dark, gfx::Rect(rc.x2(), rc.y, vp.x2()-rc.x2(), sp.y2()-rc.y));
}
}
else {
if (hasFlag(Flags::HGrid)) {
// Just HGrid Active, VGrid disabled
// Bottom band
if (rc.y2() < vp.y2())
render->fillRect(dark, gfx::Rect(rc.x, rc.y2(), vp.x2()-rc.x, vp.y2()-rc.y2()));
// Right band
if (sp.x2() < vp.x2())
render->fillRect(dark, gfx::Rect(sp.x2(), rc.y, vp.x2()-sp.x2(), rc.h));
}
}
if (hasFlag(Flags::Grid)) { // Draw vertical dark padding big bands
if (rc.w > 0) { if (hasFlag(Flags::VGrid) && hasFlag(Flags::HGrid)) {
for (int x=rc.x+rc.w*2; x<=sp.x+sp.w; x+=rc.w) std::vector<int> padXTips;
render->drawLine(gridColor, x, rc.y, x, sp.y+sp.h); std::vector<int> padYTips;
if (rc.w > 0) {
for (int x=rc.x+rc.w; x<=sp.x+sp.w; x+=(rc.w+padding.w)) {
if (x + padding.w > sp.x2())
render->fillRect(dark, gfx::Rect(x, rc.y, sp.x2()-x, sp.h-rc.y));
else
render->fillRect(dark, gfx::Rect(x, rc.y, padding.w, sp.h-rc.y));
padXTips.push_back(x);
}
}
if (rc.h > 0) {
// Draw horizontal dark chopped padding bands (to complete the dark grid)
for (int y=rc.y+rc.h; y<=sp.y+sp.h; y+=(rc.h+padding.h)) {
for (const int& padXTip : padXTips) {
if (y+padding.h > sp.y2())
render->fillRect(dark, gfx::Rect(padXTip-rc.w, y, rc.w, sp.y2()-y));
else
render->fillRect(dark, gfx::Rect(padXTip-rc.w, y, rc.w, padding.h));
}
if (!padXTips.empty()) {
if (padXTips.back() + padding.w < sp.x2()) {
if (y + padding.h > sp.y2())
render->fillRect(dark, gfx::Rect(padXTips.back() + padding.w, y,
sp.x2() - padXTips.back() - padding.w,
sp.y2() - y));
else
render->fillRect(dark, gfx::Rect(padXTips.back() + padding.w, y,
sp.x2() - padXTips.back() - padding.w,
padding.h));
}
}
padYTips.push_back(y);
}
}
// Draw chopped dark rectangles to ban partial tiles
if (!hasFlag(Flags::IncludePartialTiles)) {
if (!padXTips.empty() && !padYTips.empty()) {
if (padXTips.back() + padding.w < sp.x2()) {
for (const int& padYTip : padYTips)
render->fillRect(dark, gfx::Rect(padXTips.back() + padding.w, padYTip - rc.h,
sp.x2() - padXTips.back() - padding.w, rc.h));
if (padYTips.back() + padding.h < sp.y2()) {
render->fillRect(dark, gfx::Rect(padXTips.back() + padding.w,
padYTips.back() + padding.h,
sp.x2() - padXTips.back() - padding.w,
sp.y2() - padYTips.back() - padding.h));
}
}
if (padYTips.back() + padding.h < sp.y2()) {
for (const int& padXTip : padXTips)
render->fillRect(dark, gfx::Rect(padXTip - rc.w, padYTips.back() + padding.h,
rc.w, sp.y2() - padYTips.back() - padding.h));
}
}
}
}
else if (hasFlag(Flags::HGrid)) {
if (rc.w > 0) {
int lastX = 0;
for (int x=rc.x+rc.w; x<=sp.x+sp.w; x+=rc.w+padding.w) {
if (x + padding.w > sp.x2())
render->fillRect(dark, gfx::Rect(x, rc.y, sp.x2()-x, rc.h));
else
render->fillRect(dark, gfx::Rect(x, rc.y, padding.w, rc.h));
lastX = x;
}
if (!hasFlag(Flags::IncludePartialTiles) && (lastX > 0)) {
if (lastX + padding.w < sp.x2())
render->fillRect(dark, gfx::Rect(lastX + padding.w, rc.y,
sp.x2() - lastX - padding.w, rc.h));
}
}
}
else if (hasFlag(Flags::VGrid)) {
if (rc.h > 0) {
int lastY = 0;
for (int y=rc.y+rc.h; y<=sp.y+sp.h; y+=rc.h+padding.h) {
if (y + padding.h > sp.y2())
render->fillRect(dark, gfx::Rect(rc.x, y, rc.w, sp.y2()-y));
else
render->fillRect(dark, gfx::Rect(rc.x, y, rc.w, padding.h));
lastY = y;
}
if (!hasFlag(Flags::IncludePartialTiles) && (lastY > 0)) {
if (lastY + padding.h < sp.y2())
render->fillRect(dark, gfx::Rect(rc.x, lastY + padding.h,
rc.w, sp.y2() - lastY - padding.h));
}
}
}
} }
else {
// Draw dark zones when SelectBoxState is a simple box
const gfx::Color dark = doc::rgba(0, 0, 0, 128);
// Top band
if (rc.y > vp.y)
render->fillRect(dark, gfx::Rect(vp.x, vp.y, vp.w, rc.y-vp.y));
// Bottom band
if (rc.y2() < vp.y2())
render->fillRect(dark, gfx::Rect(vp.x, rc.y2(), vp.w, vp.y2()-rc.y2()));
// Left band
if (rc.x > vp.x)
render->fillRect(dark, gfx::Rect(vp.x, rc.y, rc.x-vp.x, rc.h));
// Right band
if (rc.x2() < vp.x2())
render->fillRect(dark, gfx::Rect(rc.x2(), rc.y, vp.x2()-rc.x2(), rc.h));
}
}
// Draw the grid rulers when padding is posible (i.e. Flag::PaddingRulers=true)
if (hasFlag(Flags::PaddingRulers)) {
if (hasFlag(Flags::HGrid) && hasFlag(Flags::VGrid)) {
if (rc.w > 0 && padding.w == 0) {
for (int x=rc.x+rc.w*2+padding.w; x<=sp.x+sp.w; x+=rc.w+padding.w)
render->drawLine(gridColor, x, rc.y, x, sp.y2());
for (int x=rc.x+rc.w+padding.w; x<=sp.x+sp.w; x+=rc.w+padding.w)
render->drawLine(gridColor, x, rc.y, x, sp.y2());
}
if (rc.h > 0) { if (rc.h > 0 && padding.h == 0) {
for (int y=rc.y+rc.h*2; y<=sp.y+sp.h; y+=rc.h) for (int y=rc.y+rc.h*2+padding.h; y<=sp.y+sp.h; y+=rc.h+padding.h)
render->drawLine(gridColor, rc.x, y, sp.x+sp.w, y); render->drawLine(gridColor, rc.x, y, sp.x2(), y);
for (int y=rc.y+rc.h+padding.h; y<=sp.y+sp.h; y+=rc.h+padding.h)
render->drawLine(gridColor, rc.x, y, sp.x2(), y);
}
}
else if (hasFlag(Flags::HGrid)) {
if (rc.w > 0 && padding.w == 0) {
for (int x=rc.x+rc.w*2+padding.w; x<=sp.x+sp.w; x+=rc.w+padding.w)
render->drawLine(gridColor, x, rc.y, x, rc.y2());
for (int x=rc.x+rc.w+padding.w; x<=sp.x+sp.w; x+=rc.w+padding.w)
render->drawLine(gridColor, x, rc.y, x, rc.y2());
}
}
else if (hasFlag(Flags::VGrid)) {
if (rc.h > 0 && padding.h == 0) {
for (int y=rc.y+rc.h*2+padding.h; y<=sp.y+sp.h; y+=rc.h+padding.h)
render->drawLine(gridColor, rc.x, y, rc.x2(), y);
for (int y=rc.y+rc.h+padding.h; y<=sp.y+sp.h; y+=rc.h+padding.h)
render->drawLine(gridColor, rc.x, y, rc.x2(), y);
}
} }
} }
else if (hasFlag(Flags::HGrid)) { else {
if (rc.w > 0) { // Draw the grid rulers when padding is not posible (i.e. Flag::PaddingRulers=false)
for (int x=rc.x+rc.w*2; x<=sp.x+sp.w; x+=rc.w) if (hasFlag(Flags::Grid)) {
render->drawLine(gridColor, x, rc.y, x, rc.y+rc.h); if (rc.w > 0) {
for (int x=rc.x+rc.w*2; x<=sp.x+sp.w; x+=rc.w)
render->drawLine(gridColor, x, rc.y, x, sp.y+sp.h);
}
if (rc.h > 0) {
for (int y=rc.y+rc.h*2; y<=sp.y+sp.h; y+=rc.h)
render->drawLine(gridColor, rc.x, y, sp.x+sp.w, y);
}
} }
} else if (hasFlag(Flags::HGrid)) {
else if (hasFlag(Flags::VGrid)) { if (rc.w > 0) {
if (rc.h > 0) { for (int x=rc.x+rc.w*2; x<=sp.x+sp.w; x+=rc.w)
for (int y=rc.y+rc.h*2; y<=sp.y+sp.h; y+=rc.h) render->drawLine(gridColor, x, rc.y, x, rc.y+rc.h);
render->drawLine(gridColor, rc.x, y, rc.x+rc.w, y); }
}
else if (hasFlag(Flags::VGrid)) {
if (rc.h > 0) {
for (int y=rc.y+rc.h*2; y<=sp.y+sp.h; y+=rc.h)
render->drawLine(gridColor, rc.x, y, rc.x+rc.w, y);
}
} }
} }
@ -338,7 +554,7 @@ int SelectBoxState::hitTestRulers(Editor* editor,
ASSERT(H2 == 1); ASSERT(H2 == 1);
ASSERT(V1 == 2); ASSERT(V1 == 2);
ASSERT(V2 == 3); ASSERT(V2 == 3);
int aligns[] = { TOP, BOTTOM, LEFT, RIGHT }; int aligns[] = { TOP, BOTTOM, LEFT, RIGHT, BOTTOM, RIGHT };
int align = 0; int align = 0;
if (updateMovingRulers) if (updateMovingRulers)
@ -360,7 +576,7 @@ int SelectBoxState::hitTestRulers(Editor* editor,
align = LEFT | TOP | RIGHT | BOTTOM; align = LEFT | TOP | RIGHT | BOTTOM;
if (updateMovingRulers) { if (updateMovingRulers) {
// Add all rulers // Add all rulers
for (int i=0; i<4; ++i) for (int i=0; i<m_rulers.size(); ++i)
m_movingRulers.push_back(i); m_movingRulers.push_back(i);
} }
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -11,6 +12,7 @@
#include "app/ui/editor/editor_decorator.h" #include "app/ui/editor/editor_decorator.h"
#include "app/ui/editor/ruler.h" #include "app/ui/editor/ruler.h"
#include "app/ui/editor/standby_state.h" #include "app/ui/editor/standby_state.h"
#include "gfx/fwd.h"
#include "ui/cursor_type.h" #include "ui/cursor_type.h"
#include "ui/mouse_buttons.h" #include "ui/mouse_buttons.h"
@ -26,6 +28,7 @@ namespace app {
// Called each time the selected box is modified (e.g. rulers are // Called each time the selected box is modified (e.g. rulers are
// moved). // moved).
virtual void onChangeRectangle(const gfx::Rect& rect) { } virtual void onChangeRectangle(const gfx::Rect& rect) { }
virtual void onChangePadding(const gfx::Size& padding) { }
// Called only in QUICKBOX mode, when the user released the mouse // Called only in QUICKBOX mode, when the user released the mouse
// button. // button.
@ -38,7 +41,7 @@ namespace app {
class SelectBoxState : public StandbyState class SelectBoxState : public StandbyState
, public EditorDecorator { , public EditorDecorator {
enum { H1, H2, V1, V2 }; enum { H1, H2, V1, V2, PH, PV };
public: public:
enum class Flags { enum class Flags {
@ -59,6 +62,12 @@ namespace app {
// Select the box as in selection tool, drawing a boxu // Select the box as in selection tool, drawing a boxu
QuickBox = 16, QuickBox = 16,
// Adding 2 rules more for padding. Used in Import Sprite Sheet render
PaddingRulers = 32,
// Include Partial Tiles at the end of the sprite? Used in Import Sprite Sheet render
IncludePartialTiles = 64
}; };
SelectBoxState(SelectBoxDelegate* delegate, SelectBoxState(SelectBoxDelegate* delegate,
@ -66,12 +75,19 @@ namespace app {
Flags flags); Flags flags);
~SelectBoxState(); ~SelectBoxState();
Flags getFlags();
void setFlags(Flags flags); void setFlags(Flags flags);
void setFlag(Flags flag);
void clearFlag(Flags flag);
// Returns the bounding box arranged by the rulers. // Returns the bounding box arranged by the rulers.
gfx::Rect getBoxBounds() const; gfx::Rect getBoxBounds() const;
void setBoxBounds(const gfx::Rect& rc); void setBoxBounds(const gfx::Rect& rc);
// Get & Set the size of the padding rulers during Import Sprite Sheet Dialog
gfx::Size getPaddingBounds() const;
void setPaddingBounds(const gfx::Size& padding);
// EditorState overrides // EditorState overrides
virtual void onEnterState(Editor* editor) override; virtual void onEnterState(Editor* editor) override;
virtual void onBeforePopState(Editor* editor) override; virtual void onBeforePopState(Editor* editor) override;