Merge branch 'main' into beta

This commit is contained in:
David Capello 2022-09-28 16:20:03 -03:00
commit 88594bfa0e
34 changed files with 244 additions and 124 deletions

View File

@ -83,6 +83,10 @@ On Arch:
sudo pacman -S gcc clang libc++ cmake ninja libx11 libxcursor mesa-libgl fontconfig
On SUSE:
sudo zypper install gcc-c++ clang libc++-devel libc++abi-devel cmake ninja libX11-devel libXcursor-devel libXi-devel Mesa-libGL-devel fontconfig-devel
# Compiling
1. [Get Aseprite code](#get-the-source-code), put it in a folder like

View File

@ -1136,7 +1136,7 @@
</menu>
<menu id="slice_popup_menu">
<item command="SliceProperties" text="@.properties" grou="slice_popup_properties" />
<item command="SliceProperties" text="@.properties" group="slice_popup_properties" />
<item command="RemoveSlice" text="@.delete" group="slice_popup_delete" />
</menu>

View File

@ -510,6 +510,7 @@
<option id="resize_scale" type="double" default="1" />
<option id="area" type="std::string" />
<option id="layer" type="std::string" />
<option id="layer_index" type="int" default ="-1" />
<option id="frame_tag" type="std::string" />
<option id="ani_dir" type="doc::AniDir" default="doc::AniDir::FORWARD" />
<option id="apply_pixel_ratio" type="bool" default="false" />
@ -537,6 +538,7 @@
<option id="ignore_empty" type="bool" default="false" />
<option id="open_generated" type="bool" default="false" />
<option id="layer" type="std::string" />
<option id="layer_index" type="int" default ="-1" />
<option id="frame_tag" type="std::string" />
<option id="split_layers" type="bool" default="false" />
<option id="split_tags" type="bool" default="false" />

View File

@ -1,5 +1,5 @@
<!-- Aseprite -->
<!-- Copyright (C) 2020-2021 Igara Studio S.A. -->
<!-- Copyright (C) 2020-2022 Igara Studio S.A. -->
<gui>
<vbox id="dynamics">
<hbox>
@ -16,16 +16,16 @@
<item text="@.velocity" tooltip="@.velocity_tooltip" tooltip_dir="bottom" />
<item text="@.size" tooltip="@.size_tooltip" tooltip_dir="right" />
<item text="" maxheight="1" />
<item text="" maxheight="1" />
<item text="" minheight="1" maxheight="1" />
<item text="" minheight="1" maxheight="1" />
<item text="@.angle" tooltip="@.angle_tooltip" tooltip_dir="right" />
<item text="" maxheight="1" />
<item text="" maxheight="1" />
<item text="" minheight="1" maxheight="1" />
<item text="" minheight="1" maxheight="1" />
<item text="@.gradient" tooltip="@.gradient_tooltip" tooltip_dir="right" />
<item text="" maxheight="1" />
<item text="" maxheight="1" />
<item text="" minheight="1" maxheight="1" />
<item text="" minheight="1" maxheight="1" />
</buttonset>
</hbox>

2
laf

@ -1 +1 @@
Subproject commit f9760fd243ff25b85f12e8b368a699aa222671ba
Subproject commit b4ca9e2a0946c2ecb1efdf3ecb01888f350e3e26

View File

@ -160,6 +160,7 @@ Doc* generate_sprite_sheet_from_params(
const SpriteSheetDataFormat dataFormat = params.dataFormat();
const std::string filenameFormat = params.filenameFormat();
const std::string layerName = params.layer();
const int layerIndex = params.layerIndex();
const std::string tagName = params.tag();
const int borderPadding = std::clamp(params.borderPadding(), 0, 100);
const int shapePadding = std::clamp(params.shapePadding(), 0, 100);
@ -192,13 +193,16 @@ Doc* generate_sprite_sheet_from_params(
// If the user choose to render selected layers only, we can
// temporaly make them visible and hide the other ones.
RestoreVisibleLayers layersVisibility;
calculate_visible_layers(site, layerName, layersVisibility);
calculate_visible_layers(site, layerName, layerIndex, layersVisibility);
SelectedLayers selLayers;
if (layerName != kSelectedLayers) {
// TODO add a getLayerByName
int i = sprite->allLayersCount();
for (const Layer* layer : sprite->allLayers()) {
if (layer->name() == layerName) {
i--;
if (layer->name() == layerName && layerIndex == -1 ||
layer->name() == layerName && layerIndex == i) {
selLayers.insert(const_cast<Layer*>(layer));
break;
}
@ -376,7 +380,7 @@ public:
source()->setSelectedItemIndex(int(kSource_Tilesets));
fill_layers_combobox(
m_sprite, layers(), params.layer());
m_sprite, layers(), params.layer(), params.layerIndex());
fill_frames_combobox(
m_sprite, frames(), params.tag());
@ -533,6 +537,7 @@ public:
params.ignoreEmpty (ignoreEmptyValue());
params.openGenerated (openGeneratedValue());
params.layer (layerValue());
params.layerIndex (layerIndex());
params.tag (tagValue());
params.splitLayers (splitLayersValue());
params.splitTags (splitTagsValue());
@ -720,6 +725,11 @@ private:
return layers()->getValue();
}
int layerIndex() const {
int i = layers()->getSelectedItemIndex() - kLayersComboboxExtraInitialItems;
return i < 0 ? -1 : i;
}
std::string tagValue() const {
return frames()->getValue();
}
@ -1234,6 +1244,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
if (!params.ignoreEmpty.isSet()) params.ignoreEmpty( defPref.spriteSheet.ignoreEmpty());
if (!params.openGenerated.isSet()) params.openGenerated( defPref.spriteSheet.openGenerated());
if (!params.layer.isSet()) params.layer( defPref.spriteSheet.layer());
if (!params.layerIndex.isSet()) params.layerIndex( defPref.spriteSheet.layerIndex());
if (!params.tag.isSet()) params.tag( defPref.spriteSheet.frameTag());
if (!params.splitLayers.isSet()) params.splitLayers( defPref.spriteSheet.splitLayers());
if (!params.splitTags.isSet()) params.splitTags( defPref.spriteSheet.splitTags());
@ -1281,6 +1292,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
docPref.spriteSheet.ignoreEmpty (params.ignoreEmpty());
docPref.spriteSheet.openGenerated (params.openGenerated());
docPref.spriteSheet.layer (params.layer());
docPref.spriteSheet.layerIndex (params.layerIndex());
docPref.spriteSheet.frameTag (params.tag());
docPref.spriteSheet.splitLayers (params.splitLayers());
docPref.spriteSheet.splitTags (params.splitTags());

View File

@ -40,6 +40,12 @@ struct ExportSpriteSheetParams : public NewParams {
Param<bool> mergeDuplicates { this, false, "mergeDuplicates" };
Param<bool> openGenerated { this, false, "openGenerated" };
Param<std::string> layer { this, std::string(), "layer" };
// TODO The layerIndex parameter is for internal use only, layers
// are counted in the same order as they are displayed in the
// Timeline or in the Export Sprite Sheet combobox. But this
// index is different to the one specified in the .aseprite
// file spec (where layers are counted from bottom to top).
Param<int> layerIndex { this, -1, "_layerIndex" };
Param<std::string> tag { this, std::string(), "tag" };
Param<bool> splitLayers { this, false, "splitLayers" };
Param<bool> splitTags { this, false, "splitTags" };

View File

@ -217,23 +217,23 @@ protected:
switch (m_tiled) {
case TiledMode::NONE:
render.renderImage(m_doublebuf.get(), m_render.get(), m_pal, x, y,
255, BlendMode::NORMAL);
255, doc::BlendMode::NORMAL);
break;
case TiledMode::X_AXIS:
for (u=x-w; u<displaySize.w+w; u+=w)
render.renderImage(m_doublebuf.get(), m_render.get(), m_pal, u, y,
255, BlendMode::NORMAL);
255, doc::BlendMode::NORMAL);
break;
case TiledMode::Y_AXIS:
for (v=y-h; v<displaySize.h+h; v+=h)
render.renderImage(m_doublebuf.get(), m_render.get(), m_pal, x, v,
255, BlendMode::NORMAL);
255, doc::BlendMode::NORMAL);
break;
case TiledMode::BOTH:
for (v=y-h; v<displaySize.h+h; v+=h)
for (u=x-w; u<displaySize.w+w; u+=w)
render.renderImage(m_doublebuf.get(), m_render.get(), m_pal, u, v,
255, BlendMode::NORMAL);
255, doc::BlendMode::NORMAL);
break;
}

View File

@ -153,7 +153,7 @@ private:
return name()->text();
}
BlendMode blendModeValue() const {
doc::BlendMode blendModeValue() const {
BlendModeItem* item = dynamic_cast<BlendModeItem*>(mode()->getSelectedItem());
if (item)
return item->mode();
@ -232,7 +232,7 @@ private:
std::string newName = nameValue();
int newOpacity = opacityValue();
const doc::UserData newUserData = m_userDataView.userData();
BlendMode newBlendMode = blendModeValue();
doc::BlendMode newBlendMode = blendModeValue();
if ((count > 1) ||
(count == 1 && m_layer && (newName != m_layer->name() ||

View File

@ -349,6 +349,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
Doc* doc = context->activeDocument();
std::string outputFilename = params().filename();
std::string layers = kAllLayers;
int layersIndex = -1;
std::string frames = kAllFrames;
bool applyPixelRatio = false;
double scale = params().scale();
@ -422,6 +423,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
win.savePref();
layers = win.layersValue();
layersIndex = win.layersIndex();
frames = win.framesValue();
scale = win.resizeValue();
params().slice(win.areaValue()); // Set slice
@ -481,6 +483,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
// Selected layers to export
calculate_visible_layers(site,
layers,
layersIndex,
layersVisibility);
// m_selFrames is not empty if fromFrame/toFrame parameters are

View File

@ -41,6 +41,8 @@
#include <sstream>
#include <string>
#include "base/log.h"
namespace app {
namespace {
@ -368,7 +370,6 @@ void Extension::uninstall(const DeletePluginPref delPref)
// Remove all files inside the extension path
uninstallFiles(m_path, delPref);
ASSERT(!base::is_directory(m_path) || delPref == DeletePluginPref::kNo);
m_isEnabled = false;
m_isInstalled = false;
@ -422,7 +423,13 @@ void Extension::uninstallFiles(const std::string& path,
for (const auto& dir : installedDirs) {
TRACE("EXT: Deleting directory '%s'\n", dir.c_str());
base::remove_directory(dir);
try {
base::remove_directory(dir);
}
catch (const std::exception& ex) {
LOG(ERROR, "RECO: Extension subdirectory cannot be removed, it's not empty.\n"
" Error: %s\n", ex.what());
}
}
// Delete __info.json file if it does exist (e.g. maybe the
@ -435,8 +442,15 @@ void Extension::uninstallFiles(const std::string& path,
}
TRACE("EXT: Deleting extension directory '%s'\n", path.c_str());
if (!hasPrefFile)
base::remove_directory(path);
if (!hasPrefFile) {
try {
base::remove_directory(path);
}
catch (const std::exception& ex) {
LOG(ERROR, "RECO: Extension directory cannot be removed, it's not empty.\n"
" Error: %s\n", ex.what());
}
}
#else // The following code delete the whole "path",
// we prefer the __info.json approach.

View File

@ -1213,7 +1213,7 @@ bool BmpFormat::onSave(FileOp *fop)
+ biSizeImage); // image data
}
else {
biSizeImage = (w*3 + filler) * h;
biSizeImage = (w*bpp/8 + filler) * h;
if (withAlpha)
bfSize = BV3INFOHEADERSIZE +
OS2FILEHEADERSIZE + biSizeImage; // header + image data

View File

@ -128,12 +128,7 @@ public:
// Opacity is set to 255 when InkType=Simple in ToolLoopBase()
if (loop->getOpacity() == 255 &&
// The trace policy is "overlap" when the dynamics has
// a gradient between FG <-> BG
//
// TODO this trace policy is configured in
// ToolLoopBase() ctor, is there a better place?
loop->getTracePolicy() != TracePolicy::Overlap) {
loop->getDynamics().gradient == DynamicSensor::Static) {
color_t color = loop->getPrimaryColor();
switch (loop->sprite()->pixelFormat()) {

View File

@ -94,8 +94,9 @@ void ButtonSet::Item::onPaint(ui::PaintEvent& ev)
bool isLastRow = (info.row+info.vspan >= info.grid_rows);
if (m_icon || isLastRow) {
textRc.y -= 1*guiscale();
textRc.y -= 2*guiscale();
iconRc.y -= 1*guiscale();
if (isLastRow && info.row > 0) iconRc.y -= 2*guiscale();
}
if (!gfx::is_transparent(bgColor()))

View File

@ -110,7 +110,7 @@ void DrawingState::initToolLoop(Editor* editor,
(previewLayer &&
previewLayer->isImage() ?
static_cast<LayerImage*>(m_toolLoop->getLayer())->blendMode():
BlendMode::NEG_BW)); // To preview the selection ink we use the negative black & white blender
doc::BlendMode::NEG_BW)); // To preview the selection ink we use the negative black & white blender
ASSERT(!m_toolLoopManager->isCanceled());

View File

@ -112,15 +112,12 @@ public:
m_g->drawLine(color, a, b);
}
void drawRectXor(const gfx::Rect& rc) override {
void drawRect(gfx::Color color, const gfx::Rect& rc) override {
gfx::Rect rc2 = m_editor->editorToScreen(rc);
gfx::Rect bounds = m_editor->bounds();
rc2.x -= bounds.x;
rc2.y -= bounds.y;
m_g->setDrawMode(Graphics::DrawMode::Xor);
m_g->drawRect(gfx::rgba(255, 255, 255), rc2);
m_g->setDrawMode(Graphics::DrawMode::Solid);
m_g->drawRect(color, rc2);
}
void fillRect(gfx::Color color, const gfx::Rect& rc) override {
@ -1033,12 +1030,11 @@ void Editor::drawMask(Graphics* g)
auto& segs = m_document->maskBoundaries();
segs.createPathIfNeeeded();
CheckeredDrawMode checkered(g, m_antsOffset,
gfx::rgba(0, 0, 0, 255),
gfx::rgba(255, 255, 255, 255));
os::Paint paint;
paint.style(os::Paint::Stroke);
paint.color(gfx::rgba(0, 0, 0));
ui::Paint paint;
paint.style(ui::Paint::Stroke);
set_checkered_paint_mode(paint, m_antsOffset,
gfx::rgba(0, 0, 0, 255),
gfx::rgba(255, 255, 255, 255));
// We translate the path instead of applying a matrix to the
// ui::Graphics so the "checkered" pattern is not scaled too.
@ -1333,12 +1329,14 @@ void Editor::drawCelHGuide(ui::Graphics* g,
// Vertical guide to touch the horizontal line
{
CheckeredDrawMode checkered(g, 0, color, gfx::ColorNone);
ui::Paint paint;
ui::set_checkered_paint_mode(paint, 0, color, gfx::ColorNone);
paint.color(color);
if (scrY < scrCmpBounds.y)
g->drawVLine(color, dottedX, scrCelBounds.y, scrCmpBounds.y - scrCelBounds.y);
g->drawVLine(dottedX, scrCelBounds.y, scrCmpBounds.y - scrCelBounds.y, paint);
else if (scrY > scrCmpBounds.y2())
g->drawVLine(color, dottedX, scrCmpBounds.y2(), scrCelBounds.y2() - scrCmpBounds.y2());
g->drawVLine(dottedX, scrCmpBounds.y2(), scrCelBounds.y2() - scrCmpBounds.y2(), paint);
}
auto text = fmt::format("{}px", ABS(sprX2 - sprX1));
@ -1359,12 +1357,14 @@ void Editor::drawCelVGuide(ui::Graphics* g,
// Horizontal guide to touch the vertical line
{
CheckeredDrawMode checkered(g, 0, color, gfx::ColorNone);
ui::Paint paint;
ui::set_checkered_paint_mode(paint, 0, color, gfx::ColorNone);
paint.color(color);
if (scrX < scrCmpBounds.x)
g->drawHLine(color, scrCelBounds.x, dottedY, scrCmpBounds.x - scrCelBounds.x);
g->drawHLine(scrCelBounds.x, dottedY, scrCmpBounds.x - scrCelBounds.x, paint);
else if (scrX > scrCmpBounds.x2())
g->drawHLine(color, scrCmpBounds.x2(), dottedY, scrCelBounds.x2() - scrCmpBounds.x2());
g->drawHLine(scrCmpBounds.x2(), dottedY, scrCelBounds.x2() - scrCmpBounds.x2(), paint);
}
auto text = fmt::format("{}px", ABS(sprY2 - sprY1));
@ -1409,7 +1409,7 @@ void Editor::flashCurrentLayer()
ExtraCelRef extraCel(new ExtraCel);
extraCel->setType(render::ExtraType::OVER_COMPOSITE);
extraCel->setBlendMode(BlendMode::NEG_BW);
extraCel->setBlendMode(doc::BlendMode::NEG_BW);
m_document->setExtraCel(extraCel);
m_flashing = Flashing::WithFlashExtraCel;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2020-2022 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -39,7 +39,7 @@ namespace app {
virtual Editor* getEditor() = 0;
virtual ui::Graphics* getGraphics() = 0;
virtual void drawLine(gfx::Color color, int x1, int y1, int x2, int y2) = 0;
virtual void drawRectXor(const gfx::Rect& rc) = 0;
virtual void drawRect(gfx::Color color, const gfx::Rect& rc) = 0;
virtual void fillRect(gfx::Color color, const gfx::Rect& rc) = 0;
};

View File

@ -566,7 +566,7 @@ void SelectBoxState::postRenderDecorator(EditorPostRender* render)
}
if (hasFlag(Flags::QuickBox)) {
render->drawRectXor(rc);
render->drawRect(gfx::rgba(255, 255, 255), rc);
}
}

View File

@ -53,7 +53,7 @@ ExportFileWindow::ExportFileWindow(const Doc* doc)
// Default export configuration
setResizeScale(m_docPref.saveCopy.resizeScale());
fill_area_combobox(m_doc->sprite(), area(), m_docPref.saveCopy.area());
fill_layers_combobox(m_doc->sprite(), layers(), m_docPref.saveCopy.layer());
fill_layers_combobox(m_doc->sprite(), layers(), m_docPref.saveCopy.layer(), m_docPref.saveCopy.layerIndex());
fill_frames_combobox(m_doc->sprite(), frames(), m_docPref.saveCopy.frameTag());
fill_anidir_combobox(anidir(), m_docPref.saveCopy.aniDir());
pixelRatio()->setSelected(m_docPref.saveCopy.applyPixelRatio());
@ -100,6 +100,7 @@ void ExportFileWindow::savePref()
m_docPref.saveCopy.resizeScale(resizeValue());
m_docPref.saveCopy.area(areaValue());
m_docPref.saveCopy.layer(layersValue());
m_docPref.saveCopy.layerIndex(layersIndex());
m_docPref.saveCopy.aniDir(aniDirValue());
m_docPref.saveCopy.frameTag(framesValue());
m_docPref.saveCopy.applyPixelRatio(applyPixelRatio());
@ -128,6 +129,12 @@ std::string ExportFileWindow::layersValue() const
return layers()->getValue();
}
int ExportFileWindow::layersIndex() const
{
int i = layers()->getSelectedItemIndex() - kLayersComboboxExtraInitialItems;
return i < 0 ? -1 : i;
}
std::string ExportFileWindow::framesValue() const
{
return frames()->getValue();

View File

@ -30,6 +30,7 @@ namespace app {
double resizeValue() const;
std::string areaValue() const;
std::string layersValue() const;
int layersIndex() const;
std::string framesValue() const;
doc::AniDir aniDirValue() const;
bool applyPixelRatio() const;

View File

@ -87,7 +87,7 @@ void fill_area_combobox(const doc::Sprite* sprite, ui::ComboBox* area, const std
}
}
void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer)
void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer, const int defLayerIndex)
{
int i = layers->addItem("Visible layers");
dynamic_cast<ui::ListItem*>(layers->getItem(i))->setValue(kAllLayers);
@ -97,11 +97,16 @@ void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const
if (defLayer == kSelectedLayers)
layers->setSelectedItemIndex(i);
assert(layers->getItemCount() == kLayersComboboxExtraInitialItems);
static_assert(kLayersComboboxExtraInitialItems == 2,
"Update kLayersComboboxExtraInitialItems value to match the number of initial items in layers combobox");
doc::LayerList layersList = sprite->allLayers();
for (auto it=layersList.rbegin(), end=layersList.rend(); it!=end; ++it) {
doc::Layer* layer = *it;
i = layers->addItem(new LayerListItem(layer));
if (defLayer == layer->name())
if (defLayer == layer->name() && defLayerIndex == -1 ||
defLayer == layer->name() && defLayerIndex == i-kLayersComboboxExtraInitialItems)
layers->setSelectedItemIndex(i);
}
}
@ -142,6 +147,7 @@ void fill_anidir_combobox(ui::ComboBox* anidir, doc::AniDir defAnidir)
void calculate_visible_layers(const Site& site,
const std::string& layersValue,
const int layersIndex,
RestoreVisibleLayers& layersVisibility)
{
if (layersValue == kSelectedLayers) {
@ -154,10 +160,13 @@ void calculate_visible_layers(const Site& site,
layersVisibility.showLayer(const_cast<Layer*>(site.layer()));
}
}
else if (layersValue != kAllFrames) {
else if (layersValue != kAllLayers) {
int i = site.sprite()->allLayersCount();
// TODO add a getLayerByName
for (doc::Layer* layer : site.sprite()->allLayers()) {
if (layer->name() == layersValue) {
i--;
if (layer->name() == layersValue && layersIndex == -1 ||
layer->name() == layersValue && layersIndex == i) {
layersVisibility.showLayer(layer);
break;
}

View File

@ -46,6 +46,8 @@ namespace app {
doc::Slice* m_slice;
};
constexpr const int kLayersComboboxExtraInitialItems = 2;
class LayerListItem : public ui::ListItem {
public:
LayerListItem(doc::Layer* layer);
@ -64,12 +66,13 @@ namespace app {
};
void fill_area_combobox(const doc::Sprite* sprite, ui::ComboBox* area, const std::string& defArea);
void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer);
void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer, const int defLayerIndex);
void fill_frames_combobox(const doc::Sprite* sprite, ui::ComboBox* frames, const std::string& defFrame);
void fill_anidir_combobox(ui::ComboBox* anidir, doc::AniDir defAnidir);
void calculate_visible_layers(const Site& site,
const std::string& layersValue,
const int layersIndex,
RestoreVisibleLayers& layersVisibility);
doc::Tag* calculate_selected_frames(const Site& site,

View File

@ -974,10 +974,12 @@ void PaletteView::onPaint(ui::PaintEvent& ev)
IntersectClip clip(g, clipR);
if (clip) {
CheckeredDrawMode checkered(g, getMarchingAntsOffset(),
gfx::rgba(0, 0, 0, 255),
gfx::rgba(255, 255, 255, 255));
g->drawRect(gfx::rgba(0, 0, 0), box);
ui::Paint paint;
paint.style(ui::Paint::Stroke);
ui::set_checkered_paint_mode(paint, getMarchingAntsOffset(),
gfx::rgba(0, 0, 0, 255),
gfx::rgba(255, 255, 255, 255));
g->drawRect(box, paint);
}
}
}
@ -1310,8 +1312,11 @@ int PaletteView::findExactIndex(const app::Color& color) const
{
switch (color.getType()) {
case Color::MaskType:
return (current_editor ? current_editor->sprite()->transparentColor(): -1);
case Color::MaskType: {
if (current_editor && current_editor->sprite()->pixelFormat() == IMAGE_INDEXED)
return current_editor->sprite()->transparentColor();
return currentPalette()->findMaskColor();
}
case Color::RgbType:
case Color::HsvType:

View File

@ -2069,11 +2069,12 @@ void Timeline::drawClipboardRange(ui::Graphics* g)
IntersectClip clip(g, getRangeClipBounds(clipboard_range));
if (clip) {
CheckeredDrawMode checkered(g, m_offset_count,
gfx::rgba(0, 0, 0, 255),
gfx::rgba(255, 255, 255, 255));
g->drawRect(gfx::rgba(0, 0, 0),
getRangeBounds(clipboard_range));
ui::Paint paint;
paint.style(ui::Paint::Stroke);
ui::set_checkered_paint_mode(paint, m_offset_count,
gfx::rgba(0, 0, 0, 255),
gfx::rgba(255, 255, 255, 255));
g->drawRect(getRangeBounds(clipboard_range), paint);
}
}

View File

@ -232,7 +232,7 @@ void Clipboard::setData(Image* image,
}
// Copy non-tilemap images to the native clipboard
else {
color_t oldMask;
color_t oldMask = 0;
if (image) {
oldMask = image->maskColor();
if (!image_source_is_transparent)

View File

@ -35,6 +35,7 @@ add_library(ui-lib
move_region.cpp
overlay.cpp
overlay_manager.cpp
paint.cpp
paint_event.cpp
panel.cpp
popup_window.cpp

View File

@ -116,23 +116,6 @@ gfx::Matrix Graphics::matrix() const
return m_surface->matrix();
}
void Graphics::setDrawMode(DrawMode mode, int param,
const gfx::Color a,
const gfx::Color b)
{
switch (mode) {
case DrawMode::Solid:
m_surface->setDrawMode(os::DrawMode::Solid);
break;
case DrawMode::Xor:
m_surface->setDrawMode(os::DrawMode::Xor);
break;
case DrawMode::Checkered:
m_surface->setDrawMode(os::DrawMode::Checkered, param, a, b);
break;
}
}
gfx::Color Graphics::getPixel(int x, int y)
{
os::SurfaceLock lock(m_surface.get());
@ -147,6 +130,14 @@ void Graphics::putPixel(gfx::Color color, int x, int y)
m_surface->putPixel(color, m_dx+x, m_dy+y);
}
void Graphics::drawHLine(int x, int y, int w, const Paint& paint)
{
dirty(gfx::Rect(m_dx+x, m_dy+y, w, 1));
os::SurfaceLock lock(m_surface.get());
m_surface->drawRect(gfx::Rect(m_dx+x, m_dy+y, w, 1), paint);
}
void Graphics::drawHLine(gfx::Color color, int x, int y, int w)
{
dirty(gfx::Rect(m_dx+x, m_dy+y, w, 1));
@ -157,6 +148,14 @@ void Graphics::drawHLine(gfx::Color color, int x, int y, int w)
m_surface->drawRect(gfx::Rect(m_dx+x, m_dy+y, w, 1), paint);
}
void Graphics::drawVLine(int x, int y, int h, const Paint& paint)
{
dirty(gfx::Rect(m_dx+x, m_dy+y, 1, h));
os::SurfaceLock lock(m_surface.get());
m_surface->drawRect(gfx::Rect(m_dx+x, m_dy+y, 1, h), paint);
}
void Graphics::drawVLine(gfx::Color color, int x, int y, int h)
{
dirty(gfx::Rect(m_dx+x, m_dy+y, 1, h));
@ -319,6 +318,7 @@ void Graphics::drawSurfaceNine(os::Surface* surface,
const gfx::Rect& src,
const gfx::Rect& center,
const gfx::Rect& dst,
const bool drawCenter,
const ui::Paint* paint)
{
gfx::Rect displacedDst(m_dx+dst.x, m_dy+dst.y, dst.w, dst.h);
@ -326,7 +326,7 @@ void Graphics::drawSurfaceNine(os::Surface* surface,
os::SurfaceLock lockSrc(surface);
os::SurfaceLock lockDst(m_surface.get());
m_surface->drawSurfaceNine(surface, src, center, displacedDst, paint);
m_surface->drawSurfaceNine(surface, src, center, displacedDst, drawCenter, paint);
}
void Graphics::blit(os::Surface* srcSurface, int srcx, int srcy, int dstx, int dsty, int w, int h)

View File

@ -16,8 +16,8 @@
#include "gfx/rect.h"
#include "gfx/size.h"
#include "os/font.h"
#include "os/paint.h"
#include "os/surface.h"
#include "ui/paint.h"
#include <memory>
#include <string>
@ -34,19 +34,11 @@ namespace os {
}
namespace ui {
using os::Paint; // Define ui::Paint = os::Paint
class Display;
// Class to render a widget in the screen.
class Graphics {
public:
enum class DrawMode {
Solid,
Xor,
Checkered,
};
Graphics(Display* display, const os::SurfaceRef& surface, int dx, int dy);
~Graphics();
@ -70,14 +62,12 @@ namespace ui {
void restore();
gfx::Matrix matrix() const;
void setDrawMode(DrawMode mode, int param = 0,
const gfx::Color a = gfx::ColorNone,
const gfx::Color b = gfx::ColorNone);
gfx::Color getPixel(int x, int y);
void putPixel(gfx::Color color, int x, int y);
void drawHLine(int x, int y, int w, const Paint& paint);
void drawHLine(gfx::Color color, int x, int y, int w);
void drawVLine(int x, int y, int h, const Paint& paint);
void drawVLine(gfx::Color color, int x, int y, int h);
void drawLine(gfx::Color color, const gfx::Point& a, const gfx::Point& b);
void drawPath(gfx::Path& path, const Paint& paint);
@ -94,7 +84,7 @@ namespace ui {
const gfx::Rect& srcRect,
const gfx::Rect& dstRect,
const os::Sampling& sampling,
const ui::Paint* paint);
const Paint* paint);
void drawRgbaSurface(os::Surface* surface, int x, int y);
void drawRgbaSurface(os::Surface* surface, int srcx, int srcy, int dstx, int dsty, int w, int h);
void drawColoredRgbaSurface(os::Surface* surface, gfx::Color color, int x, int y);
@ -103,6 +93,7 @@ namespace ui {
const gfx::Rect& src,
const gfx::Rect& center,
const gfx::Rect& dst,
const bool drawCenter,
const Paint* paint = nullptr);
void blit(os::Surface* src, int srcx, int srcy, int dstx, int dsty, int w, int h);
@ -195,24 +186,6 @@ namespace ui {
DISABLE_COPYING(IntersectClip);
};
class CheckeredDrawMode {
public:
CheckeredDrawMode(Graphics* g, int param,
const gfx::Color a,
const gfx::Color b) : m_graphics(g) {
m_graphics->setDrawMode(Graphics::DrawMode::Checkered, param, a, b);
}
~CheckeredDrawMode() {
m_graphics->setDrawMode(Graphics::DrawMode::Solid);
}
private:
Graphics* m_graphics;
DISABLE_COPYING(CheckeredDrawMode);
};
typedef std::shared_ptr<Graphics> GraphicsPtr;
} // namespace ui

53
src/ui/paint.cpp Normal file
View File

@ -0,0 +1,53 @@
// Aseprite UI Library
// Copyright (C) 2022 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ui/paint.h"
#include "base/exception.h"
#if LAF_SKIA
#include "include/core/SkBitmap.h"
#endif
namespace ui {
void set_checkered_paint_mode(Paint& paint,
const int param,
const gfx::Color a,
const gfx::Color b)
{
#if LAF_SKIA
SkPaint& skPaint = paint.skPaint();
skPaint.setBlendMode(SkBlendMode::kSrcOver);
SkBitmap bitmap;
if (!bitmap.tryAllocPixels(
SkImageInfo::MakeN32(8, 8, kOpaque_SkAlphaType))) {
throw base::Exception("Cannot create temporary Skia surface");
}
{
SkPMColor A = SkPreMultiplyARGB(gfx::geta(a), gfx::getr(a), gfx::getg(a), gfx::getb(a));
SkPMColor B = SkPreMultiplyARGB(gfx::geta(b), gfx::getr(b), gfx::getg(b), gfx::getb(b));
int offset = 7 - (param & 7);
for (int y=0; y<8; y++)
for (int x=0; x<8; x++)
*bitmap.getAddr32(x, y) = (((x+y+offset)&7) < 4 ? B: A);
}
sk_sp<SkShader> shader(
bitmap.makeShader(SkTileMode::kRepeat,
SkTileMode::kRepeat,
SkSamplingOptions()));
skPaint.setShader(shader);
#endif
}
} // namespace ui

27
src/ui/paint.h Normal file
View File

@ -0,0 +1,27 @@
// Aseprite UI Library
// Copyright (C) 2022 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef UI_PAINT_H_INCLUDED
#define UI_PAINT_H_INCLUDED
#pragma once
#include "base/disable_copying.h"
#include "gfx/color.h"
#include "os/paint.h"
namespace ui {
using os::Paint;
using os::BlendMode;
void set_checkered_paint_mode(Paint& paint,
const int param,
const gfx::Color a,
const gfx::Color b);
} // namespace ui
#endif

View File

@ -757,9 +757,7 @@ void Theme::drawSlices(Graphics* g, os::Surface* sheet,
{
Paint paint;
paint.color(color);
if (!drawCenter)
paint.setFlags(Paint::kNineWithoutCenter);
g->drawSurfaceNine(sheet, sprite, slices, rc, &paint);
g->drawSurfaceNine(sheet, sprite, slices, rc, drawCenter, &paint);
}
// static

View File

@ -179,6 +179,7 @@ void View::updateView(const bool restoreScrollPos)
}
if (Widget* child = attachedWidget()) {
(void)child;
updateAttachedWidgetBounds(viewScroll());
ASSERT(child->bounds().w >= viewportBounds().w);
ASSERT(child->bounds().h >= viewportBounds().h);

View File

@ -1022,11 +1022,15 @@ void Widget::getTextIconInfo(
void Widget::setMinSize(const gfx::Size& sz)
{
ASSERT(sz.w <= m_maxSize.w);
ASSERT(sz.h <= m_maxSize.h);
m_minSize = sz;
}
void Widget::setMaxSize(const gfx::Size& sz)
{
ASSERT(sz.w >= m_minSize.w);
ASSERT(sz.h >= m_minSize.h);
m_maxSize = sz;
}

@ -1 +1 @@
Subproject commit 1e1a58dfed29f5905fca14391959c04949fc037a
Subproject commit fb3d9be28cfd4551de949bb5b8c44b1d6e2aec9b