mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-01 10:13:22 +00:00
Merge branch 'master' into beta
This commit is contained in:
commit
289a6ab864
12
README.md
12
README.md
@ -50,12 +50,14 @@ You can ask for help in:
|
||||
|
||||
## Authors
|
||||
|
||||
[Igara Studio](https://www.igarastudio.com/) is developing Aseprite:
|
||||
Aseprite is being developed by [Igara Studio](https://www.igarastudio.com/):
|
||||
|
||||
* [David Capello](https://davidcapello.com/): Lead developer, fixing
|
||||
issues, new features, and user support.
|
||||
* [Gaspar Capello](https://github.com/Gasparoken): Developer, fixing
|
||||
issues and new features.
|
||||
* [David Capello](https://davidcapello.com/): Lead developer,
|
||||
bug fixing & new features in desktop & web, and user support.
|
||||
* [Gaspar Capello](https://github.com/Gasparoken): Developer,
|
||||
bug fixing & new features in desktop, and user support.
|
||||
* [Martin Capello](https://github.com/martincapello): Developer,
|
||||
new store website.
|
||||
|
||||
## Credits
|
||||
|
||||
|
@ -1109,10 +1109,13 @@
|
||||
</item>
|
||||
<separator />
|
||||
<item command="LoadPalette" text="@.load_palette" />
|
||||
<item command="SavePalette" text="@.save_palette" />
|
||||
<item command="LoadPalette" text="@.load_default_palette">
|
||||
<param name="preset" value="default" />
|
||||
</item>
|
||||
<item command="SavePalette" text="@.save_palette" />
|
||||
<item command="SavePalette" text="@.save_palette_as_preset">
|
||||
<param name="saveAsPreset" value="true" />
|
||||
</item>
|
||||
<item command="SavePalette" text="@.save_as_default_palette" group="palette_files">
|
||||
<param name="preset" value="default" />
|
||||
</item>
|
||||
|
@ -364,6 +364,12 @@
|
||||
<option id="bits_per_pixel" type="int" default="0" />
|
||||
<option id="compress" type="bool" default="true" />
|
||||
</section>
|
||||
<section id="css">
|
||||
<option id="show_alert" type="bool" default="true" />
|
||||
<option id="pixel_scale" type="int" default="1" />
|
||||
<option id="with_vars" type="bool" default="false" />
|
||||
<option id="generate_html" type="bool" default="false" />
|
||||
</section>
|
||||
<section id="webp">
|
||||
<option id="show_alert" type="bool" default="true" />
|
||||
<option id="loop" type="bool" default="true" />
|
||||
|
@ -1386,9 +1386,10 @@ ryb_color_wheel = RYB Color Wheel
|
||||
normal_map_color_wheel = Normal Map Color Wheel
|
||||
load_palette = L&oad Palette
|
||||
save_palette = S&ave Palette
|
||||
save_palette_as_preset = Save Palette as Preset
|
||||
load_default_palette = Load Default Palette
|
||||
save_as_default_palette = Save as Default Palette
|
||||
create_palette_from_current_sprite = Create Palette from Current Sprite
|
||||
save_as_default_palette = Save Palette as Default
|
||||
create_palette_from_current_sprite = New Palette from Sprite
|
||||
|
||||
[palette_size]
|
||||
title = Palette Size
|
||||
@ -1541,6 +1542,12 @@ title = TGA Options
|
||||
bits_per_pixel = Bits Per Pixel
|
||||
compress = Compress
|
||||
|
||||
[css_options]
|
||||
title = CSS Options
|
||||
pixel_scale = Pixel Scale
|
||||
with_vars = Use CSS3 Variables
|
||||
generate_html = Generate Sample HTML File
|
||||
|
||||
[timeline_conf]
|
||||
position = Position:
|
||||
left = &Left
|
||||
|
@ -1,17 +1,19 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018-2020 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2021 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018 David Capello -->
|
||||
<gui i18nwarnings="false">
|
||||
<window id="about" text="About Aseprite">
|
||||
<vbox>
|
||||
<label text="" id="title" />
|
||||
<label text="Animated sprite editor && pixel art tool" />
|
||||
<separator text="Authors:" horizontal="true" />
|
||||
<separator text="Developers:" horizontal="true" />
|
||||
<grid columns="2">
|
||||
<link text="David Capello" url="https://twitter.com/davidcapello" />
|
||||
<label text="- Lead developer, graphics && maintainer" />
|
||||
<label text="- Lead developer, new features && bug fixing in desktop && web" />
|
||||
<link text="Gaspar Capello" url="https://twitter.com/Gasparoken" />
|
||||
<label text="- Programmer, bug fixing" />
|
||||
<label text="- Developer, new features && bug fixing in desktop" />
|
||||
<link text="Martin Capello" url="https://twitter.com/martincapell0" />
|
||||
<label text="- Developer, new store website" />
|
||||
|
||||
<separator text="Contributors:" horizontal="true" cell_hspan="2" />
|
||||
<link text="Ilija Melentijevic" url="https://ilkke.net/" />
|
||||
@ -20,14 +22,14 @@
|
||||
<label text="- Default dark theme introduced in v1.3" />
|
||||
|
||||
<hbox cell_hspan="2">
|
||||
<link text="Other Contributors" url="https://www.aseprite.org/contributors/" />
|
||||
<link text="Other Contributors" url="https://www.aseprite.org/contributors/" />
|
||||
<label text="&&" />
|
||||
<link text="Third-Party Projects" url="" id="licenses" />
|
||||
</hbox>
|
||||
</grid>
|
||||
<separator horizontal="true" />
|
||||
<hbox>
|
||||
<label text="Copyright (C) 2001-2020" />
|
||||
<label text="Copyright (C) 2001-2021" />
|
||||
<link text="Igara Studio S.A." url="https://www.igarastudio.com/" />
|
||||
</hbox>
|
||||
<link text="https://www.aseprite.org/" url="https://www.aseprite.org/" />
|
||||
|
25
data/widgets/css_options.xml
Normal file
25
data/widgets/css_options.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018 by Igara Studio S.A. -->
|
||||
<gui>
|
||||
<window id="css_options" text="@.title">
|
||||
<grid columns="2">
|
||||
<label text="@.pixel_scale" />
|
||||
<expr id="pixel_scale" magnet="true" cell_align="horizontal"/>
|
||||
|
||||
<check text="@.with_vars" id="with_vars" cell_hspan="2" />
|
||||
|
||||
<check text="@.generate_html" id="generate_html" cell_hspan="2" />
|
||||
|
||||
<separator horizontal="true" cell_hspan="2" />
|
||||
|
||||
<hbox cell_hspan="2">
|
||||
<check text="@general.dont_show" id="dont_show" tooltip="@general.dont_show_tooltip" />
|
||||
<boxfiller />
|
||||
</hbox>
|
||||
<box horizontal="true" 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>
|
||||
</grid>
|
||||
</window>
|
||||
</gui>
|
@ -440,6 +440,7 @@
|
||||
pref="scripts.show_run_script_alert" />
|
||||
<hbox>
|
||||
<label text="@.image_format_alerts" />
|
||||
<check id="css_options_alert" text="!css" pref="css.show_alert" />
|
||||
<check id="gif_options_alert" text="!gif" pref="gif.show_alert" />
|
||||
<check id="jpeg_options_alert" text="!jpeg" pref="jpeg.show_alert" />
|
||||
<check id="svg_options_alert" text="!svg" pref="svg.show_alert" />
|
||||
|
@ -25,7 +25,7 @@ void global_function(int arg1, int arg2,
|
||||
|
||||
do {
|
||||
...
|
||||
} while (condition);
|
||||
} while (condition);
|
||||
|
||||
switch (condition) {
|
||||
case 1:
|
||||
|
@ -125,6 +125,7 @@ endif()
|
||||
set(file_formats
|
||||
file/ase_format.cpp
|
||||
file/bmp_format.cpp
|
||||
file/css_format.cpp
|
||||
file/fli_format.cpp
|
||||
file/gif_format.cpp
|
||||
file/ico_format.cpp
|
||||
@ -606,7 +607,7 @@ add_library(app-lib
|
||||
tools/pick_ink.cpp
|
||||
tools/point_shape.cpp
|
||||
tools/stroke.cpp
|
||||
tools/symmetries.cpp
|
||||
tools/symmetry.cpp
|
||||
tools/tool_box.cpp
|
||||
tools/tool_loop_manager.cpp
|
||||
tools/velocity.cpp
|
||||
|
@ -124,6 +124,7 @@ namespace app {
|
||||
obs::signal<void()> Exit;
|
||||
obs::signal<void()> PaletteChange;
|
||||
obs::signal<void()> ColorSpaceChange;
|
||||
obs::signal<void()> PalettePresetsChange;
|
||||
|
||||
private:
|
||||
class CoreModules;
|
||||
|
@ -992,6 +992,7 @@ private:
|
||||
advancedModeAlert()->resetWithDefaultValue();
|
||||
invalidFgBgColorAlert()->resetWithDefaultValue();
|
||||
runScriptAlert()->resetWithDefaultValue();
|
||||
cssOptionsAlert()->resetWithDefaultValue();
|
||||
gifOptionsAlert()->resetWithDefaultValue();
|
||||
jpegOptionsAlert()->resetWithDefaultValue();
|
||||
svgOptionsAlert()->resetWithDefaultValue();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -78,7 +78,7 @@ void RemoveLayerCommand::onExecute(Context* context)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sprite->allLayersCount() == 1) {
|
||||
if (sprite->root()->layersCount() == 1) {
|
||||
ui::Alert::show(Strings::alerts_cannot_delete_all_layers());
|
||||
return;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/commands/cmd_set_palette.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/params.h"
|
||||
@ -35,6 +36,7 @@ protected:
|
||||
|
||||
private:
|
||||
std::string m_preset;
|
||||
bool m_saveAsPreset = false;
|
||||
};
|
||||
|
||||
SavePaletteCommand::SavePaletteCommand()
|
||||
@ -45,6 +47,7 @@ SavePaletteCommand::SavePaletteCommand()
|
||||
void SavePaletteCommand::onLoadParams(const Params& params)
|
||||
{
|
||||
m_preset = params.get("preset");
|
||||
m_saveAsPreset = (params.get("saveAsPreset") == "true");
|
||||
}
|
||||
|
||||
void SavePaletteCommand::onExecute(Context* context)
|
||||
@ -58,8 +61,9 @@ void SavePaletteCommand::onExecute(Context* context)
|
||||
else {
|
||||
base::paths exts = get_writable_palette_extensions();
|
||||
base::paths selFilename;
|
||||
std::string initialPath = (m_saveAsPreset ? get_preset_palettes_dir(): "");
|
||||
if (!app::show_file_selector(
|
||||
"Save Palette", "", exts,
|
||||
"Save Palette", initialPath, exts,
|
||||
FileSelectorType::Save, selFilename))
|
||||
return;
|
||||
|
||||
@ -74,6 +78,9 @@ void SavePaletteCommand::onExecute(Context* context)
|
||||
if (!context->activeDocument())
|
||||
set_current_palette(palette, false);
|
||||
}
|
||||
if (m_saveAsPreset) {
|
||||
App::instance()->PalettePresetsChange();
|
||||
}
|
||||
}
|
||||
|
||||
Command* CommandFactory::createSavePaletteCommand()
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -332,18 +332,13 @@ Doc* Session::restoreBackupRawImages(Backup* backup,
|
||||
|
||||
void Session::deleteBackup(Backup* backup)
|
||||
{
|
||||
try {
|
||||
auto it = std::find(m_backups.begin(), m_backups.end(), backup);
|
||||
ASSERT(it != m_backups.end());
|
||||
if (it != m_backups.end())
|
||||
m_backups.erase(it);
|
||||
auto it = std::find(m_backups.begin(), m_backups.end(), backup);
|
||||
ASSERT(it != m_backups.end());
|
||||
if (it != m_backups.end())
|
||||
m_backups.erase(it);
|
||||
|
||||
if (base::is_directory(backup->dir()))
|
||||
deleteDirectory(backup->dir());
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
Console::showException(ex);
|
||||
}
|
||||
if (base::is_directory(backup->dir()))
|
||||
deleteDirectory(backup->dir());
|
||||
}
|
||||
|
||||
void Session::loadPid()
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "doc/palette.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "doc/tag.h"
|
||||
#include "doc/slice.h"
|
||||
#include "os/display.h"
|
||||
#include "os/system.h"
|
||||
#include "ui/system.h"
|
||||
@ -519,6 +520,14 @@ Doc* Doc::duplicate(DuplicateType type) const
|
||||
for (const Tag* tag : sourceSprite->tags())
|
||||
spriteCopy->tags().add(new Tag(*tag));
|
||||
|
||||
// Copy slices
|
||||
for (const Slice *slice : sourceSprite->slices()) {
|
||||
auto sliceCopy = new Slice(*slice);
|
||||
spriteCopy->slices().add(sliceCopy);
|
||||
|
||||
ASSERT(sliceCopy->owner() == &spriteCopy->slices());
|
||||
}
|
||||
|
||||
// Copy color palettes
|
||||
{
|
||||
PalettesList::const_iterator it = sourceSprite->getPalettes().begin();
|
||||
|
303
src/app/file/css_format.cpp
Normal file
303
src/app/file/css_format.cpp
Normal file
@ -0,0 +1,303 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2018-2019 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/console.h"
|
||||
#include "app/context.h"
|
||||
#include "app/doc.h"
|
||||
#include "app/file/file.h"
|
||||
#include "app/file/file_format.h"
|
||||
#include "app/file/format_options.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/cfile.h"
|
||||
#include "base/file_handle.h"
|
||||
#include "base/string.h"
|
||||
#include "doc/doc.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
#include "css_options.xml.h"
|
||||
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace base;
|
||||
|
||||
class CssFormat : public FileFormat {
|
||||
class CssOptions : public FormatOptions {
|
||||
public:
|
||||
CssOptions() : pixelScale(1), gutterSize(0),
|
||||
generateHtml(false),
|
||||
withVars(false) { }
|
||||
int pixelScale;
|
||||
int gutterSize;
|
||||
bool generateHtml;
|
||||
bool withVars;
|
||||
};
|
||||
|
||||
const char* onGetName() const override {
|
||||
return "css";
|
||||
}
|
||||
|
||||
void onGetExtensions(base::paths& exts) const override {
|
||||
exts.push_back("css");
|
||||
}
|
||||
|
||||
dio::FileFormat onGetDioFormat() const override {
|
||||
return dio::FileFormat::CSS_STYLE;
|
||||
}
|
||||
|
||||
int onGetFlags() const override {
|
||||
return
|
||||
FILE_SUPPORT_SAVE |
|
||||
FILE_SUPPORT_RGB |
|
||||
FILE_SUPPORT_RGBA |
|
||||
FILE_SUPPORT_GRAY |
|
||||
FILE_SUPPORT_GRAYA |
|
||||
FILE_SUPPORT_INDEXED |
|
||||
FILE_SUPPORT_SEQUENCES |
|
||||
FILE_SUPPORT_GET_FORMAT_OPTIONS |
|
||||
FILE_SUPPORT_PALETTE_WITH_ALPHA;
|
||||
}
|
||||
|
||||
bool onLoad(FileOp* fop) override;
|
||||
#ifdef ENABLE_SAVE
|
||||
bool onSave(FileOp* fop) override;
|
||||
#endif
|
||||
FormatOptionsPtr onAskUserForFormatOptions(FileOp* fop) override;
|
||||
};
|
||||
|
||||
FileFormat *CreateCssFormat()
|
||||
{
|
||||
return new CssFormat;
|
||||
}
|
||||
|
||||
bool CssFormat::onLoad(FileOp* fop)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SAVE
|
||||
|
||||
bool CssFormat::onSave(FileOp* fop)
|
||||
{
|
||||
const Image* image = fop->sequenceImage();
|
||||
int x, y, c, r, g, b, a, alpha;
|
||||
const auto css_options = std::static_pointer_cast<CssOptions>(fop->formatOptions());
|
||||
FileHandle handle(open_file_with_exception_sync_on_close(fop->filename(), "wb"));
|
||||
FILE* f = handle.get();
|
||||
auto print_color = [f](int r, int g, int b, int a) {
|
||||
if (a == 255) {
|
||||
fprintf(f, "#%02X%02X%02X", r, g, b);
|
||||
}
|
||||
else {
|
||||
fprintf(f, "rgba(%d, %d, %d, %d)", r, g, b, a);
|
||||
}
|
||||
};
|
||||
auto print_shadow_color = [f, css_options, print_color](int x, int y, int r,
|
||||
int g, int b, int a,
|
||||
bool comma = true) {
|
||||
fprintf(f, comma?",\n":"\n");
|
||||
if (css_options->withVars) {
|
||||
fprintf(f, "\tcalc(%d*var(--shadow-mult)) calc(%d*var(--shadow-mult)) var(--blur) var(--spread) ",
|
||||
x, y);
|
||||
}
|
||||
else {
|
||||
int x_loc = x * (css_options->pixelScale + css_options->gutterSize);
|
||||
int y_loc = y * (css_options->pixelScale + css_options->gutterSize);
|
||||
fprintf(f, "%dpx %dpx ", x_loc, y_loc);
|
||||
}
|
||||
print_color(r, g, b, a);
|
||||
};
|
||||
auto print_shadow_index = [f, css_options](int x, int y, int i, bool comma=true) {
|
||||
fprintf(f, comma?",\n":"\n");
|
||||
fprintf(f, "\tcalc(%d*var(--shadow-mult)) calc(%d*var(--shadow-mult)) var(--blur) var(--spread) var(--color-%d)",
|
||||
x, y, i);
|
||||
};
|
||||
if (css_options->withVars) {
|
||||
fprintf(f, ":root {\n"
|
||||
"\t--blur: 0px;\n"
|
||||
"\t--spread: 0px;\n"
|
||||
"\t--pixel-size: %dpx;\n"
|
||||
"\t--gutter-size: %dpx;\n",
|
||||
css_options->pixelScale,
|
||||
css_options->gutterSize);
|
||||
fprintf(f, "\t--shadow-mult: calc(var(--gutter-size) + var(--pixel-size));\n");
|
||||
if (image->pixelFormat() == IMAGE_INDEXED) {
|
||||
for (y = 0; y < 256; y++) {
|
||||
fop->sequenceGetColor(y, &r, &g, &b);
|
||||
fop->sequenceGetAlpha(y, &a);
|
||||
fprintf(f, "\t--color-%d: ", y);
|
||||
print_color(r, g, b, a);
|
||||
fprintf(f, ";\n");
|
||||
}
|
||||
}
|
||||
fprintf(f, "}\n\n");
|
||||
}
|
||||
|
||||
fprintf(f, ".pixel-art {\n");
|
||||
fprintf(f, "\tposition: relative;\n");
|
||||
fprintf(f, "\ttop: 0;\n");
|
||||
fprintf(f, "\tleft: 0;\n");
|
||||
if (css_options->withVars) {
|
||||
fprintf(f, "\theight: var(--pixel-size);\n");
|
||||
fprintf(f, "\twidth: var(--pixel-size);\n");
|
||||
}
|
||||
else {
|
||||
fprintf(f, "\theight: %dpx;\n", css_options->pixelScale);
|
||||
fprintf(f, "\twidth: %dpx;\n", css_options->pixelScale);
|
||||
}
|
||||
fprintf(f, "\tbox-shadow:\n");
|
||||
int num_printed_pixels = 0;
|
||||
switch (image->pixelFormat()) {
|
||||
case IMAGE_RGB: {
|
||||
for (y=0; y<image->height(); y++) {
|
||||
for (x=0; x<image->width(); x++) {
|
||||
c = get_pixel_fast<RgbTraits>(image, x, y);
|
||||
alpha = rgba_geta(c);
|
||||
if (alpha != 0x00) {
|
||||
print_shadow_color(x, y, rgba_getr(c), rgba_getg(c), rgba_getb(c),
|
||||
alpha, num_printed_pixels>0);
|
||||
num_printed_pixels ++;
|
||||
}
|
||||
}
|
||||
fop->setProgress((float)y / (float)(image->height()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_GRAYSCALE: {
|
||||
for (y=0; y<image->height(); y++) {
|
||||
for (x=0; x<image->width(); x++) {
|
||||
c = get_pixel_fast<GrayscaleTraits>(image, x, y);
|
||||
auto v = graya_getv(c);
|
||||
alpha = graya_geta(c);
|
||||
if (alpha != 0x00) {
|
||||
print_shadow_color(x, y, v, v, v, alpha, num_printed_pixels>0);
|
||||
num_printed_pixels ++;
|
||||
}
|
||||
}
|
||||
fop->setProgress((float)y / (float)(image->height()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_INDEXED: {
|
||||
unsigned char image_palette[256][4];
|
||||
for (y=0; !css_options->withVars && y<256; y++) {
|
||||
fop->sequenceGetColor(y, &r, &g, &b);
|
||||
image_palette[y][0] = r;
|
||||
image_palette[y][1] = g;
|
||||
image_palette[y][2] = b;
|
||||
fop->sequenceGetAlpha(y, &a);
|
||||
image_palette[y][3] = a;
|
||||
}
|
||||
color_t mask_color = -1;
|
||||
if (fop->document()->sprite()->backgroundLayer() == NULL ||
|
||||
!fop->document()->sprite()->backgroundLayer()->isVisible()) {
|
||||
mask_color = fop->document()->sprite()->transparentColor();
|
||||
}
|
||||
for (y=0; y<image->height(); y++) {
|
||||
for (x=0; x<image->width(); x++) {
|
||||
c = get_pixel_fast<IndexedTraits>(image, x, y);
|
||||
if (c != mask_color) {
|
||||
if (css_options->withVars) {
|
||||
print_shadow_index(x, y, c, num_printed_pixels>0);
|
||||
}
|
||||
else {
|
||||
print_shadow_color(x, y,
|
||||
image_palette[c][0] & 0xff,
|
||||
image_palette[c][1] & 0xff,
|
||||
image_palette[c][2] & 0xff,
|
||||
image_palette[c][3] & 0xff,
|
||||
num_printed_pixels>0);
|
||||
}
|
||||
num_printed_pixels ++;
|
||||
}
|
||||
}
|
||||
fop->setProgress((float)y / (float)(image->height()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(f, ";\n}\n");
|
||||
if (ferror(f)) {
|
||||
fop->setError("Error writing file.\n");
|
||||
return false;
|
||||
}
|
||||
if (css_options->generateHtml) {
|
||||
std::string html_filepath = fop->filename() + ".html";
|
||||
FileHandle handle(open_file_with_exception_sync_on_close(html_filepath, "wb"));
|
||||
FILE* h = handle.get();
|
||||
fprintf(h,
|
||||
"<html><head><link rel=\"stylesheet\" media=\"all\" "
|
||||
"href=\"%s\"></head><body><div "
|
||||
"class=\"pixel-art\"></div></body></html>",
|
||||
fop->filename().c_str());
|
||||
if (ferror(h)) {
|
||||
fop->setError("Error writing html file.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Shows the CSS configuration dialog.
|
||||
FormatOptionsPtr CssFormat::onAskUserForFormatOptions(FileOp* fop)
|
||||
{
|
||||
auto opts = fop->formatOptionsOfDocument<CssOptions>();
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
if (fop->context() && fop->context()->isUIAvailable()) {
|
||||
try {
|
||||
auto &pref = Preferences::instance();
|
||||
|
||||
if (pref.isSet(pref.css.pixelScale))
|
||||
opts->pixelScale = pref.css.pixelScale();
|
||||
|
||||
if (pref.isSet(pref.css.withVars))
|
||||
opts->withVars = pref.css.withVars();
|
||||
|
||||
if (pref.isSet(pref.css.generateHtml))
|
||||
opts->generateHtml = pref.css.generateHtml();
|
||||
|
||||
if (pref.css.showAlert()) {
|
||||
app::gen::CssOptions win;
|
||||
win.pixelScale()->setTextf("%d", opts->pixelScale);
|
||||
win.withVars()->setSelected(opts->withVars);
|
||||
win.generateHtml()->setSelected(opts->generateHtml);
|
||||
win.openWindowInForeground();
|
||||
|
||||
if (win.closer() == win.ok()) {
|
||||
pref.css.showAlert(!win.dontShow()->isSelected());
|
||||
pref.css.pixelScale((int)win.pixelScale()->textInt());
|
||||
pref.css.withVars(win.withVars()->isSelected());
|
||||
pref.css.generateHtml(win.generateHtml()->isSelected());
|
||||
|
||||
opts->generateHtml = pref.css.generateHtml();
|
||||
opts->withVars = pref.css.withVars();
|
||||
opts->pixelScale = pref.css.pixelScale();
|
||||
}
|
||||
else {
|
||||
opts.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
Console::showException(e);
|
||||
return std::shared_ptr<CssOptions>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return opts;
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -22,6 +22,7 @@ namespace app {
|
||||
|
||||
extern FileFormat* CreateAseFormat();
|
||||
extern FileFormat* CreateBmpFormat();
|
||||
extern FileFormat* CreateCssFormat();
|
||||
extern FileFormat* CreateFliFormat();
|
||||
extern FileFormat* CreateGifFormat();
|
||||
extern FileFormat* CreateIcoFormat();
|
||||
@ -57,6 +58,7 @@ FileFormatsManager::FileFormatsManager()
|
||||
// The first format is the default image format in FileSelector
|
||||
registerFormat(CreateAseFormat());
|
||||
registerFormat(CreateBmpFormat());
|
||||
registerFormat(CreateCssFormat());
|
||||
registerFormat(CreateFliFormat());
|
||||
registerFormat(CreateGifFormat());
|
||||
registerFormat(CreateIcoFormat());
|
||||
|
@ -73,7 +73,10 @@ FileFormat* CreateSvgFormat()
|
||||
return new SvgFormat;
|
||||
}
|
||||
|
||||
bool SvgFormat::onLoad(FileOp* fop) { return false;}
|
||||
bool SvgFormat::onLoad(FileOp* fop)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SAVE
|
||||
|
||||
|
@ -161,12 +161,7 @@ bool set_current_palette(const Palette *_palette, bool forced)
|
||||
std::string get_preset_palette_filename(const std::string& preset,
|
||||
const std::string& dot_extension)
|
||||
{
|
||||
ResourceFinder rf;
|
||||
rf.includeUserDir(base::join_path("palettes", ".").c_str());
|
||||
std::string palettesDir = rf.getFirstOrCreateDefault();
|
||||
|
||||
if (!base::is_directory(palettesDir))
|
||||
base::make_directory(palettesDir);
|
||||
std::string palettesDir = get_preset_palettes_dir();
|
||||
|
||||
return base::join_path(palettesDir, preset + dot_extension);
|
||||
}
|
||||
@ -176,4 +171,16 @@ std::string get_default_palette_preset_name()
|
||||
return "default";
|
||||
}
|
||||
|
||||
std::string get_preset_palettes_dir()
|
||||
{
|
||||
ResourceFinder rf;
|
||||
rf.includeUserDir(base::join_path("palettes", ".").c_str());
|
||||
std::string palettesDir = rf.getFirstOrCreateDefault();
|
||||
|
||||
if (!base::is_directory(palettesDir))
|
||||
base::make_directory(palettesDir);
|
||||
|
||||
return palettesDir;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -33,6 +33,7 @@ namespace app {
|
||||
std::string get_preset_palette_filename(const std::string& preset,
|
||||
const std::string& dot_extension);
|
||||
std::string get_default_palette_preset_name();
|
||||
std::string get_preset_palettes_dir();
|
||||
|
||||
} // namespace app
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -8,6 +8,7 @@
|
||||
#include "app/util/wrap_point.h"
|
||||
|
||||
#include "app/tools/ink.h"
|
||||
#include "doc/algorithm/flip_image.h"
|
||||
#include "render/gradient.h"
|
||||
|
||||
namespace app {
|
||||
@ -61,7 +62,7 @@ class BrushPointShape : public PointShape {
|
||||
bool m_firstPoint;
|
||||
Brush* m_lastBrush;
|
||||
BrushType m_origBrushType;
|
||||
std::shared_ptr<CompressedImage> m_compressedImage;
|
||||
std::array<std::shared_ptr<CompressedImage>, 4> m_compressedImages;
|
||||
// For dynamics
|
||||
DynamicsOptions m_dynamics;
|
||||
bool m_useDynamics;
|
||||
@ -192,9 +193,7 @@ public:
|
||||
// TODO cache compressed images (or remove them completelly)
|
||||
if (m_lastBrush != brush) {
|
||||
m_lastBrush = brush;
|
||||
m_compressedImage.reset(new CompressedImage(brush->image(),
|
||||
brush->maskBitmap(),
|
||||
false));
|
||||
m_compressedImages.fill(nullptr);
|
||||
}
|
||||
|
||||
x += brush->bounds().x;
|
||||
@ -227,7 +226,7 @@ public:
|
||||
|
||||
ink->prepareForPointShape(loop, m_firstPoint, x, y);
|
||||
|
||||
for (auto scanline : *m_compressedImage) {
|
||||
for (auto scanline : getCompressedImage(pt.symmetry)) {
|
||||
int u = x+scanline.x;
|
||||
ink->prepareVForPointShape(loop, y+scanline.y);
|
||||
doInkHline(u, y+scanline.y, u+scanline.w-1, loop);
|
||||
@ -241,6 +240,47 @@ public:
|
||||
area.y += y;
|
||||
}
|
||||
|
||||
private:
|
||||
CompressedImage& getCompressedImage(gen::SymmetryMode symmetryMode) {
|
||||
auto& compressPtr = m_compressedImages[int(symmetryMode)];
|
||||
if (!compressPtr) {
|
||||
switch (symmetryMode) {
|
||||
case gen::SymmetryMode::NONE: {
|
||||
compressPtr.reset(new CompressedImage(m_lastBrush->image(),
|
||||
m_lastBrush->maskBitmap(),
|
||||
false));
|
||||
break;
|
||||
}
|
||||
case gen::SymmetryMode::HORIZONTAL:
|
||||
case gen::SymmetryMode::VERTICAL: {
|
||||
std::unique_ptr<Image> tempImage(Image::createCopy(m_lastBrush->image()));
|
||||
doc::algorithm::FlipType flip =
|
||||
(symmetryMode == gen::SymmetryMode::HORIZONTAL)?
|
||||
doc::algorithm::FlipType::FlipHorizontal:
|
||||
doc::algorithm::FlipType::FlipVertical;
|
||||
doc::algorithm::flip_image(tempImage.get(), tempImage->bounds(), flip);
|
||||
compressPtr.reset(new CompressedImage(tempImage.get(),
|
||||
m_lastBrush->maskBitmap(),
|
||||
false));
|
||||
break;
|
||||
}
|
||||
case gen::SymmetryMode::BOTH: {
|
||||
std::unique_ptr<Image> tempImage(Image::createCopy(m_lastBrush->image()));
|
||||
doc::algorithm::flip_image(tempImage.get(),
|
||||
tempImage->bounds(),
|
||||
doc::algorithm::FlipType::FlipVertical);
|
||||
doc::algorithm::flip_image(tempImage.get(),
|
||||
tempImage->bounds(),
|
||||
doc::algorithm::FlipType::FlipHorizontal);
|
||||
compressPtr.reset(new CompressedImage(tempImage.get(),
|
||||
m_lastBrush->maskBitmap(),
|
||||
false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return *compressPtr;
|
||||
}
|
||||
};
|
||||
|
||||
class FloodFillPointShape : public PointShape {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -9,6 +9,7 @@
|
||||
#define APP_TOOLS_STROKE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/pref/preferences.h"
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
|
||||
@ -25,6 +26,7 @@ namespace app {
|
||||
float size = 0.0f;
|
||||
float angle = 0.0f;
|
||||
float gradient = 0.0f;
|
||||
gen::SymmetryMode symmetry = gen::SymmetryMode::NONE;
|
||||
Pt() { }
|
||||
Pt(const gfx::Point& point) : x(point.x), y(point.y) { }
|
||||
Pt(int x, int y) : x(x), y(y) { }
|
||||
|
@ -1,84 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/tools/symmetries.h"
|
||||
|
||||
#include "app/tools/point_shape.h"
|
||||
#include "app/tools/stroke.h"
|
||||
#include "app/tools/tool_loop.h"
|
||||
#include "doc/brush.h"
|
||||
|
||||
namespace app {
|
||||
namespace tools {
|
||||
|
||||
void HorizontalSymmetry::generateStrokes(const Stroke& mainStroke, Strokes& strokes,
|
||||
ToolLoop* loop)
|
||||
{
|
||||
int brushSize, brushCenter;
|
||||
if (loop->getPointShape()->isFloodFill()) {
|
||||
brushSize = 1;
|
||||
brushCenter = 0;
|
||||
}
|
||||
else {
|
||||
// TODO we should flip the brush center+image+bitmap or just do
|
||||
// the symmetry of all pixels
|
||||
auto brush = loop->getBrush();
|
||||
brushSize = brush->bounds().w;
|
||||
brushCenter = brush->center().x;
|
||||
}
|
||||
|
||||
strokes.push_back(mainStroke);
|
||||
|
||||
Stroke stroke2;
|
||||
for (const auto& pt : mainStroke) {
|
||||
Stroke::Pt pt2 = pt;
|
||||
pt2.x = m_x - ((pt.x-brushCenter) - m_x + 1) - (brushSize - brushCenter - 1);
|
||||
stroke2.addPoint(pt2);
|
||||
}
|
||||
strokes.push_back(stroke2);
|
||||
}
|
||||
|
||||
void VerticalSymmetry::generateStrokes(const Stroke& mainStroke, Strokes& strokes,
|
||||
ToolLoop* loop)
|
||||
{
|
||||
int brushSize, brushCenter;
|
||||
if (loop->getPointShape()->isFloodFill()) {
|
||||
brushSize = 1;
|
||||
brushCenter = 0;
|
||||
}
|
||||
else {
|
||||
auto brush = loop->getBrush();
|
||||
brushSize = brush->bounds().h;
|
||||
brushCenter = brush->center().y;
|
||||
}
|
||||
|
||||
strokes.push_back(mainStroke);
|
||||
|
||||
Stroke stroke2;
|
||||
for (const auto& pt : mainStroke) {
|
||||
Stroke::Pt pt2 = pt;
|
||||
pt2.y = m_y - ((pt.y-brushCenter) - m_y + 1) - (brushSize - brushCenter - 1);
|
||||
stroke2.addPoint(pt2);
|
||||
}
|
||||
strokes.push_back(stroke2);
|
||||
}
|
||||
|
||||
void SymmetryCombo::generateStrokes(const Stroke& mainStroke, Strokes& strokes,
|
||||
ToolLoop* loop)
|
||||
{
|
||||
Strokes strokes0;
|
||||
m_a->generateStrokes(mainStroke, strokes0, loop);
|
||||
for (const Stroke& stroke : strokes0)
|
||||
m_b->generateStrokes(stroke, strokes, loop);
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
} // namespace app
|
@ -1,50 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_TOOLS_SYMMETRIES_H_INCLUDED
|
||||
#define APP_TOOLS_SYMMETRIES_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/tools/stroke.h"
|
||||
#include "app/tools/symmetry.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace app {
|
||||
namespace tools {
|
||||
|
||||
class HorizontalSymmetry : public Symmetry {
|
||||
public:
|
||||
HorizontalSymmetry(double x) : m_x(x) { }
|
||||
void generateStrokes(const Stroke& mainStroke, Strokes& strokes,
|
||||
ToolLoop* loop) override;
|
||||
private:
|
||||
double m_x;
|
||||
};
|
||||
|
||||
class VerticalSymmetry : public Symmetry {
|
||||
public:
|
||||
VerticalSymmetry(double y) : m_y(y) { }
|
||||
void generateStrokes(const Stroke& mainStroke, Strokes& strokes,
|
||||
ToolLoop* loop) override;
|
||||
private:
|
||||
double m_y;
|
||||
};
|
||||
|
||||
class SymmetryCombo : public Symmetry {
|
||||
public:
|
||||
SymmetryCombo(Symmetry* a, Symmetry* b) : m_a(a), m_b(b) { }
|
||||
void generateStrokes(const Stroke& mainStroke, Strokes& strokes,
|
||||
ToolLoop* loop) override;
|
||||
private:
|
||||
std::unique_ptr<tools::Symmetry> m_a;
|
||||
std::unique_ptr<tools::Symmetry> m_b;
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
} // namespace app
|
||||
|
||||
#endif
|
91
src/app/tools/symmetry.cpp
Normal file
91
src/app/tools/symmetry.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/tools/symmetry.h"
|
||||
|
||||
#include "app/tools/point_shape.h"
|
||||
#include "app/tools/tool_loop.h"
|
||||
|
||||
namespace app {
|
||||
namespace tools {
|
||||
|
||||
void Symmetry::generateStrokes(const Stroke& stroke, Strokes& strokes,
|
||||
ToolLoop* loop)
|
||||
{
|
||||
Stroke stroke2;
|
||||
strokes.push_back(stroke);
|
||||
gen::SymmetryMode symmetryMode = loop->getSymmetry()->mode();
|
||||
switch (symmetryMode) {
|
||||
case gen::SymmetryMode::NONE:
|
||||
ASSERT(false);
|
||||
break;
|
||||
|
||||
case gen::SymmetryMode::HORIZONTAL:
|
||||
case gen::SymmetryMode::VERTICAL:
|
||||
calculateSymmetricalStroke(stroke, stroke2, loop, symmetryMode);
|
||||
strokes.push_back(stroke2);
|
||||
break;
|
||||
|
||||
case gen::SymmetryMode::BOTH: {
|
||||
calculateSymmetricalStroke(stroke, stroke2, loop, gen::SymmetryMode::HORIZONTAL);
|
||||
strokes.push_back(stroke2);
|
||||
|
||||
Stroke stroke3;
|
||||
calculateSymmetricalStroke(stroke, stroke3, loop, gen::SymmetryMode::VERTICAL);
|
||||
strokes.push_back(stroke3);
|
||||
|
||||
Stroke stroke4;
|
||||
calculateSymmetricalStroke(stroke3, stroke4, loop, gen::SymmetryMode::BOTH);
|
||||
strokes.push_back(stroke4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Symmetry::calculateSymmetricalStroke(const Stroke& refStroke, Stroke& stroke,
|
||||
ToolLoop* loop, gen::SymmetryMode symmetryMode)
|
||||
{
|
||||
int brushSize, brushCenter;
|
||||
if (loop->getPointShape()->isFloodFill()) {
|
||||
brushSize = 1;
|
||||
brushCenter = 0;
|
||||
}
|
||||
else {
|
||||
// TODO we should flip the brush center+image+bitmap or just do
|
||||
// the symmetry of all pixels
|
||||
auto brush = loop->getBrush();
|
||||
if (symmetryMode == gen::SymmetryMode::HORIZONTAL || symmetryMode == gen::SymmetryMode::BOTH) {
|
||||
brushSize = brush->bounds().w;
|
||||
brushCenter = brush->center().x;
|
||||
}
|
||||
else {
|
||||
brushSize = brush->bounds().h;
|
||||
brushCenter = brush->center().y;
|
||||
}
|
||||
}
|
||||
|
||||
const bool isDynamic = loop->getDynamics().isDynamic();
|
||||
for (const auto& pt : refStroke) {
|
||||
if (isDynamic) {
|
||||
brushSize = pt.size;
|
||||
brushCenter = (brushSize - brushSize % 2) / 2;
|
||||
}
|
||||
Stroke::Pt pt2 = pt;
|
||||
pt2.symmetry = symmetryMode;
|
||||
if (symmetryMode == gen::SymmetryMode::HORIZONTAL || symmetryMode == gen::SymmetryMode::BOTH)
|
||||
pt2.x = 2 * (m_x + brushCenter) - pt2.x - brushSize;
|
||||
else
|
||||
pt2.y = 2 * (m_y + brushCenter) - pt2.y - brushSize;
|
||||
stroke.addPoint(pt2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
} // namespace app
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
// Copyright (C) 2015 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -9,24 +10,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "app/tools/stroke.h"
|
||||
|
||||
#include <vector>
|
||||
#include "app/pref/preferences.h"
|
||||
|
||||
namespace app {
|
||||
namespace tools {
|
||||
namespace tools {
|
||||
|
||||
class ToolLoop;
|
||||
class ToolLoop;
|
||||
|
||||
// This class controls user input.
|
||||
class Symmetry {
|
||||
public:
|
||||
virtual ~Symmetry() { }
|
||||
class Symmetry {
|
||||
public:
|
||||
Symmetry(gen::SymmetryMode symmetryMode, double x, double y)
|
||||
: m_symmetryMode(symmetryMode)
|
||||
, m_x(x)
|
||||
, m_y(y) {
|
||||
}
|
||||
|
||||
// The "stroke" must be relative to the sprite origin.
|
||||
virtual void generateStrokes(const Stroke& stroke, Strokes& strokes, ToolLoop* loop) = 0;
|
||||
};
|
||||
void generateStrokes(const Stroke& stroke, Strokes& strokes, ToolLoop* loop);
|
||||
|
||||
} // namespace tools
|
||||
gen::SymmetryMode mode() const { return m_symmetryMode; }
|
||||
|
||||
private:
|
||||
void calculateSymmetricalStroke(const Stroke& refStroke, Stroke& stroke,
|
||||
ToolLoop* loop, gen::SymmetryMode symmetryMode);
|
||||
|
||||
gen::SymmetryMode m_symmetryMode;
|
||||
double m_x, m_y;
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
} // namespace app
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -16,6 +16,7 @@
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/workspace.h"
|
||||
#include "base/file_handle.h"
|
||||
#include "base/fs.h"
|
||||
@ -572,7 +573,8 @@ WorkspaceView* BrowserView::cloneWorkspaceView()
|
||||
|
||||
void BrowserView::onWorkspaceViewSelected()
|
||||
{
|
||||
// Do nothing
|
||||
if (auto statusBar = StatusBar::instance())
|
||||
statusBar->clearText();
|
||||
}
|
||||
|
||||
bool BrowserView::onCloseView(Workspace* workspace, bool quitting)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/app_menus.h"
|
||||
#include "app/console.h"
|
||||
#include "app/crash/data_recovery.h"
|
||||
#include "app/crash/session.h"
|
||||
#include "app/doc.h"
|
||||
@ -106,19 +107,31 @@ public:
|
||||
|
||||
m_task = new TaskWidget(
|
||||
TaskWidget::kCannotCancel,
|
||||
[this](base::task_token& t){
|
||||
// Warning: This is executed from a worker thread
|
||||
m_session->deleteBackup(m_backup);
|
||||
ui::execute_from_ui_thread(
|
||||
[this]{
|
||||
onDeleteTaskWidget();
|
||||
[this](base::task_token& t) {
|
||||
try {
|
||||
// Warning: This is executed from a worker thread
|
||||
m_session->deleteBackup(m_backup);
|
||||
|
||||
// We cannot use this->deferDelete() here because it looks
|
||||
// like the m_task field can be still in use.
|
||||
setVisible(false);
|
||||
ui::execute_from_ui_thread(
|
||||
[this]{
|
||||
onDeleteTaskWidget();
|
||||
|
||||
updateView();
|
||||
});
|
||||
// We cannot use this->deferDelete() here because it looks
|
||||
// like the m_task field can be still in use.
|
||||
setVisible(false);
|
||||
|
||||
updateView();
|
||||
});
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::string err = ex.what();
|
||||
if (!err.empty()) {
|
||||
ui::execute_from_ui_thread(
|
||||
[err]{
|
||||
Console().printf("Error deleting file: %s", err.c_str());
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
addChild(m_task);
|
||||
updateView();
|
||||
@ -477,6 +490,7 @@ void DataRecoveryView::onDelete()
|
||||
int(items.size()))) != 1)
|
||||
return; // Cancel
|
||||
|
||||
Console console;
|
||||
for (auto item : items)
|
||||
item->deleteBackup();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -248,7 +248,8 @@ WorkspaceView* DocView::cloneWorkspaceView()
|
||||
|
||||
void DocView::onWorkspaceViewSelected()
|
||||
{
|
||||
StatusBar::instance()->showDefaultText(m_document);
|
||||
if (auto statusBar = StatusBar::instance())
|
||||
statusBar->showDefaultText(m_document);
|
||||
}
|
||||
|
||||
void DocView::onClonedFrom(WorkspaceView* from)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -29,7 +29,7 @@
|
||||
#include "app/tools/freehand_algorithm.h"
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/point_shape.h"
|
||||
#include "app/tools/symmetries.h"
|
||||
#include "app/tools/symmetry.h"
|
||||
#include "app/tools/tool.h"
|
||||
#include "app/tools/tool_box.h"
|
||||
#include "app/tools/tool_loop.h"
|
||||
@ -239,27 +239,10 @@ public:
|
||||
|
||||
// Symmetry mode
|
||||
if (Preferences::instance().symmetryMode.enabled()) {
|
||||
switch (m_docPref.symmetry.mode()) {
|
||||
|
||||
case app::gen::SymmetryMode::NONE:
|
||||
ASSERT(m_symmetry == nullptr);
|
||||
break;
|
||||
|
||||
case app::gen::SymmetryMode::HORIZONTAL:
|
||||
m_symmetry.reset(new app::tools::HorizontalSymmetry(m_docPref.symmetry.xAxis()));
|
||||
break;
|
||||
|
||||
case app::gen::SymmetryMode::VERTICAL:
|
||||
m_symmetry.reset(new app::tools::VerticalSymmetry(m_docPref.symmetry.yAxis()));
|
||||
break;
|
||||
|
||||
case app::gen::SymmetryMode::BOTH:
|
||||
m_symmetry.reset(
|
||||
new app::tools::SymmetryCombo(
|
||||
new app::tools::HorizontalSymmetry(m_docPref.symmetry.xAxis()),
|
||||
new app::tools::VerticalSymmetry(m_docPref.symmetry.yAxis())));
|
||||
break;
|
||||
}
|
||||
if (m_docPref.symmetry.mode() != gen::SymmetryMode::NONE)
|
||||
m_symmetry.reset(new tools::Symmetry(m_docPref.symmetry.mode(),
|
||||
m_docPref.symmetry.xAxis(),
|
||||
m_docPref.symmetry.yAxis()));
|
||||
}
|
||||
|
||||
// Ignore opacity for these inks
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -261,9 +261,19 @@ void MainWindow::showHome()
|
||||
m_tabsBar->selectTab(m_homeView);
|
||||
}
|
||||
|
||||
bool MainWindow::isHomeSelected()
|
||||
void MainWindow::showDefaultStatusBar()
|
||||
{
|
||||
return (m_tabsBar->getSelectedTab() == m_homeView && m_homeView);
|
||||
if (DocView* docView = getDocView())
|
||||
m_statusBar->showDefaultText(docView->document());
|
||||
else if (isHomeSelected())
|
||||
m_statusBar->showAbout();
|
||||
else
|
||||
m_statusBar->clearText();
|
||||
}
|
||||
|
||||
bool MainWindow::isHomeSelected() const
|
||||
{
|
||||
return (m_homeView && m_workspace->activeView() == m_homeView);
|
||||
}
|
||||
|
||||
void MainWindow::showBrowser(const std::string& filename)
|
||||
@ -473,12 +483,12 @@ void MainWindow::onTabsContainerDoubleClicked(Tabs* tabs)
|
||||
void MainWindow::onMouseOverTab(Tabs* tabs, TabView* tabView)
|
||||
{
|
||||
// Note: tabView can be NULL
|
||||
if (DocView* docView = dynamic_cast<DocView*>(tabView)) {
|
||||
if (DocView* docView = dynamic_cast<DocView*>(tabView))
|
||||
m_statusBar->showDefaultText(docView->document());
|
||||
}
|
||||
else {
|
||||
else if (tabView)
|
||||
m_statusBar->setStatusText(0, tabView->getTabText());
|
||||
else
|
||||
m_statusBar->showDefaultText();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onMouseLeaveTab()
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -71,9 +71,10 @@ namespace app {
|
||||
void showNotification(INotificationDelegate* del);
|
||||
void showHomeOnOpen();
|
||||
void showHome();
|
||||
bool isHomeSelected();
|
||||
void showDefaultStatusBar();
|
||||
void showDevConsole();
|
||||
void showBrowser(const std::string& filename);
|
||||
bool isHomeSelected() const;
|
||||
|
||||
Mode getMode() const { return m_mode; }
|
||||
void setMode(Mode mode);
|
||||
|
@ -42,6 +42,7 @@ PalettePopup::PalettePopup()
|
||||
addChild(m_popup);
|
||||
|
||||
m_paletteListBox.DoubleClickItem.connect([this]{ onLoadPal(); });
|
||||
m_paletteListBox.FinishLoading.connect([this]{ onSearchChange(); });
|
||||
m_popup->search()->Change.connect([this]{ onSearchChange(); });
|
||||
m_popup->loadPal()->Click.connect([this]{ onLoadPal(); });
|
||||
m_popup->openFolder()->Click.connect([this]{ onOpenFolder(); });
|
||||
|
@ -124,6 +124,9 @@ PalettesListBox::PalettesListBox()
|
||||
m_extPaletteChanges =
|
||||
App::instance()->extensions().PalettesChange.connect(
|
||||
[this]{ reload(); });
|
||||
m_extPresetsChanges =
|
||||
App::instance()->PalettePresetsChange.connect(
|
||||
[this]{ reload(); });
|
||||
}
|
||||
|
||||
doc::Palette* PalettesListBox::selectedPalette()
|
||||
|
@ -34,6 +34,7 @@ namespace app {
|
||||
|
||||
ui::TooltipManager m_tooltips;
|
||||
obs::scoped_connection m_extPaletteChanges;
|
||||
obs::scoped_connection m_extPresetsChanges;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -211,8 +211,10 @@ void ResourcesListBox::onTick()
|
||||
listItem.release();
|
||||
}
|
||||
|
||||
if (m_resourcesLoader->isDone())
|
||||
if (m_resourcesLoader->isDone()) {
|
||||
FinishLoading();
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourcesListBox::stop()
|
||||
|
@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "app/res/resources_loader.h"
|
||||
#include "obs/signal.h"
|
||||
#include "ui/listbox.h"
|
||||
#include "ui/listitem.h"
|
||||
#include "ui/timer.h"
|
||||
@ -43,6 +44,8 @@ class ResourceListItem : public ui::ListItem {
|
||||
|
||||
void reload();
|
||||
|
||||
obs::signal<void()> FinishLoading;
|
||||
|
||||
protected:
|
||||
virtual bool onProcessMessage(ui::Message* msg) override;
|
||||
virtual void onChange() override;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -61,6 +61,40 @@ using namespace gfx;
|
||||
using namespace ui;
|
||||
using namespace doc;
|
||||
|
||||
class StatusBar::AboutStatusBar : public HBox {
|
||||
public:
|
||||
AboutStatusBar()
|
||||
: m_label(fmt::format("{} {} by ", get_app_name(), get_app_version()))
|
||||
, m_link("", "Igara Studio")
|
||||
{
|
||||
m_link.Click.connect(
|
||||
[]{
|
||||
Command* cmd = Commands::instance()->byId(CommandId::About());
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(cmd);
|
||||
});
|
||||
|
||||
addChild(new BoxFiller);
|
||||
addChild(&m_label);
|
||||
addChild(&m_link);
|
||||
addChild(new BoxFiller);
|
||||
|
||||
InitTheme.connect(
|
||||
[this]{
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||
ui::Style* style = theme->styles.workspaceLink();
|
||||
noBorderNoChildSpacing();
|
||||
m_label.setStyle(style);
|
||||
m_link.setStyle(style);
|
||||
m_label.noBorderNoChildSpacing();
|
||||
m_link.noBorderNoChildSpacing();
|
||||
});
|
||||
initTheme();
|
||||
}
|
||||
|
||||
ui::Label m_label;
|
||||
ui::LinkLabel m_link;
|
||||
};
|
||||
|
||||
class StatusBar::Indicators : public HBox {
|
||||
|
||||
class Indicator : public Widget {
|
||||
@ -632,6 +666,7 @@ StatusBar* StatusBar::m_instance = NULL;
|
||||
|
||||
StatusBar::StatusBar(TooltipManager* tooltipManager)
|
||||
: m_timeout(0)
|
||||
, m_about(new AboutStatusBar)
|
||||
, m_indicators(new Indicators)
|
||||
, m_docControls(new HBox)
|
||||
, m_tipwindow(nullptr)
|
||||
@ -642,8 +677,12 @@ StatusBar::StatusBar(TooltipManager* tooltipManager)
|
||||
setDoubleBuffered(true);
|
||||
setFocusStop(true);
|
||||
|
||||
m_about->setExpansive(true);
|
||||
m_about->setVisible(true);
|
||||
m_indicators->setExpansive(true);
|
||||
m_indicators->setVisible(false);
|
||||
m_docControls->setVisible(false);
|
||||
addChild(m_about);
|
||||
addChild(m_indicators);
|
||||
addChild(m_docControls);
|
||||
|
||||
@ -698,6 +737,7 @@ void StatusBar::onSelectedToolChange(tools::Tool* tool)
|
||||
|
||||
void StatusBar::clearText()
|
||||
{
|
||||
showIndicators();
|
||||
setStatusText(1, std::string());
|
||||
}
|
||||
|
||||
@ -706,16 +746,11 @@ void StatusBar::clearText()
|
||||
// details of the main window/docs/etc.
|
||||
void StatusBar::showDefaultText()
|
||||
{
|
||||
if (current_editor) {
|
||||
showDefaultText(current_editor->document());
|
||||
}
|
||||
else if (App::instance()->mainWindow()->isHomeSelected()) {
|
||||
setStatusText(0, fmt::format("-- {} {} by David & Gaspar Capello -- Igara Studio --",
|
||||
get_app_name(), get_app_version()));
|
||||
}
|
||||
else {
|
||||
auto mainWindow = (App::instance() ? App::instance()->mainWindow(): nullptr);
|
||||
if (mainWindow)
|
||||
mainWindow->showDefaultStatusBar();
|
||||
else
|
||||
clearText();
|
||||
}
|
||||
}
|
||||
|
||||
void StatusBar::showDefaultText(Doc* doc)
|
||||
@ -742,18 +777,22 @@ void StatusBar::showDefaultText(Doc* doc)
|
||||
|
||||
void StatusBar::updateFromEditor(Editor* editor)
|
||||
{
|
||||
if (editor)
|
||||
if (editor) {
|
||||
showIndicators();
|
||||
m_zoomEntry->setZoom(editor->zoom());
|
||||
}
|
||||
}
|
||||
|
||||
void StatusBar::showBackupIcon(BackupIcon icon)
|
||||
{
|
||||
showIndicators();
|
||||
m_indicators->showBackupIcon(icon);
|
||||
}
|
||||
|
||||
bool StatusBar::setStatusText(int msecs, const std::string& msg)
|
||||
{
|
||||
if ((base::current_tick() > m_timeout) || (msecs > 0)) {
|
||||
showIndicators();
|
||||
IndicatorsGeneration(m_indicators).add(msg.c_str());
|
||||
m_timeout = base::current_tick() + msecs;
|
||||
return true;
|
||||
@ -795,6 +834,7 @@ void StatusBar::showTip(int msecs, const std::string& msg)
|
||||
void StatusBar::showColor(int msecs, const char* text, const app::Color& color)
|
||||
{
|
||||
if ((base::current_tick() > m_timeout) || (msecs > 0)) {
|
||||
showIndicators();
|
||||
IndicatorsGeneration gen(m_indicators);
|
||||
gen.add(color);
|
||||
if (text)
|
||||
@ -818,7 +858,9 @@ void StatusBar::showTile(int msecs, const char* text, doc::tile_t tile)
|
||||
|
||||
void StatusBar::showTool(int msecs, tools::Tool* tool)
|
||||
{
|
||||
ASSERT(tool != NULL);
|
||||
showIndicators();
|
||||
|
||||
ASSERT(tool != nullptr);
|
||||
IndicatorsGeneration(m_indicators).add(tool);
|
||||
|
||||
m_timeout = base::current_tick() + msecs;
|
||||
@ -946,4 +988,22 @@ void StatusBar::updateSnapToGridWindowPosition()
|
||||
rc.y-m_snapToGridWindow->bounds().h);
|
||||
}
|
||||
|
||||
void StatusBar::showAbout()
|
||||
{
|
||||
if (!m_about->isVisible()) {
|
||||
m_indicators->setVisible(false);
|
||||
m_about->setVisible(true);
|
||||
m_about->layout();
|
||||
}
|
||||
}
|
||||
|
||||
void StatusBar::showIndicators()
|
||||
{
|
||||
if (!m_indicators->isVisible()) {
|
||||
m_about->setVisible(false);
|
||||
m_indicators->setVisible(true);
|
||||
m_indicators->layout();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -56,7 +56,8 @@ namespace app {
|
||||
|
||||
void clearText();
|
||||
void showDefaultText();
|
||||
void showDefaultText(Doc* document);
|
||||
void showDefaultText(Doc* doc);
|
||||
void showAbout();
|
||||
|
||||
bool setStatusText(int msecs, const std::string& text);
|
||||
void showTip(int msecs, const std::string& msg);
|
||||
@ -88,9 +89,14 @@ namespace app {
|
||||
void newFrame();
|
||||
void onChangeZoom(const render::Zoom& zoom);
|
||||
void updateSnapToGridWindowPosition();
|
||||
void showIndicators();
|
||||
|
||||
base::tick_t m_timeout;
|
||||
|
||||
// About text
|
||||
class AboutStatusBar;
|
||||
AboutStatusBar* m_about;
|
||||
|
||||
// Indicators
|
||||
class Indicators;
|
||||
class IndicatorsGeneration;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -100,16 +100,17 @@ void UIContext::setActiveView(DocView* docView)
|
||||
return;
|
||||
|
||||
if (docView) {
|
||||
current_editor = docView->editor();
|
||||
mainWin->getTabsBar()->selectTab(docView);
|
||||
|
||||
if (mainWin->getWorkspace()->activeView() != docView)
|
||||
mainWin->getWorkspace()->setActiveView(docView);
|
||||
|
||||
if (current_editor)
|
||||
current_editor->requestFocus();
|
||||
}
|
||||
|
||||
current_editor = (docView ? docView->editor(): nullptr);
|
||||
|
||||
if (current_editor)
|
||||
current_editor->requestFocus();
|
||||
else
|
||||
current_editor = nullptr;
|
||||
|
||||
mainWin->getPreviewEditor()->updateUsingEditor(current_editor);
|
||||
mainWin->getTimeline()->updateUsingEditor(current_editor);
|
||||
|
@ -141,6 +141,9 @@ FileFormat detect_format_by_file_extension(const std::string& filename)
|
||||
if (ext == "tga")
|
||||
return FileFormat::TARGA_IMAGE;
|
||||
|
||||
if (ext == "css")
|
||||
return FileFormat::CSS_STYLE;
|
||||
|
||||
if (ext == "webp")
|
||||
return FileFormat::WEBP_ANIMATION;
|
||||
|
||||
|
@ -31,6 +31,7 @@ enum class FileFormat {
|
||||
SVG_IMAGE,
|
||||
TARGA_IMAGE,
|
||||
WEBP_ANIMATION,
|
||||
CSS_STYLE,
|
||||
};
|
||||
|
||||
} // namespace dio
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define DOC_KEYFRAMES_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "doc/frame.h"
|
||||
|
||||
#include <vector>
|
||||
@ -111,6 +110,11 @@ namespace doc {
|
||||
|
||||
Keyframes() { }
|
||||
|
||||
Keyframes(const Keyframes& other) {
|
||||
for (const auto& key : other.m_keys)
|
||||
m_keys.push_back(Key(key.frame(), new T(*key.value())));
|
||||
}
|
||||
|
||||
void insert(const frame_t frame, T* value) {
|
||||
auto it = getIterator(frame);
|
||||
if (it == end())
|
||||
@ -189,9 +193,6 @@ namespace doc {
|
||||
|
||||
private:
|
||||
List m_keys;
|
||||
|
||||
// Disable operator=
|
||||
DISABLE_COPYING(Keyframes);
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
@ -42,6 +42,14 @@ Slice::Slice()
|
||||
{
|
||||
}
|
||||
|
||||
Slice::Slice(const Slice& other)
|
||||
: WithUserData(other)
|
||||
, m_owner(nullptr)
|
||||
, m_name(other.m_name)
|
||||
, m_keys(other.m_keys)
|
||||
{
|
||||
}
|
||||
|
||||
Slice::~Slice()
|
||||
{
|
||||
ASSERT(!m_owner);
|
||||
|
@ -55,6 +55,7 @@ namespace doc {
|
||||
typedef List::const_iterator const_iterator;
|
||||
|
||||
Slice();
|
||||
Slice(const Slice& other);
|
||||
~Slice();
|
||||
|
||||
int getMemSize() const override;
|
||||
@ -90,8 +91,6 @@ namespace doc {
|
||||
Slices* m_owner;
|
||||
std::string m_name;
|
||||
List m_keys;
|
||||
|
||||
DISABLE_COPYING(Slice);
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
@ -23,7 +23,7 @@ BEGIN
|
||||
VALUE "FileDescription", "Aseprite - Animated sprites editor & pixel art tool"
|
||||
VALUE "FileVersion", "1,3,0,0"
|
||||
VALUE "InternalName", "aseprite"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2001-2020 Igara Studio S.A."
|
||||
VALUE "LegalCopyright", "Copyright (C) 2001-2021 Igara Studio S.A."
|
||||
VALUE "OriginalFilename", "aseprite.exe"
|
||||
VALUE "ProductName", "ASEPRITE"
|
||||
VALUE "ProductVersion", "1,3,0,0"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -106,7 +106,11 @@ Widget::~Widget()
|
||||
|
||||
void Widget::deferDelete()
|
||||
{
|
||||
manager()->addToGarbage(this);
|
||||
if (auto man = manager())
|
||||
man->addToGarbage(this);
|
||||
else {
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::initTheme()
|
||||
@ -219,7 +223,8 @@ void Widget::setVisible(bool state)
|
||||
}
|
||||
else {
|
||||
if (!hasFlags(HIDDEN)) {
|
||||
manager()->freeWidget(this); // Free from manager
|
||||
if (auto man = manager())
|
||||
man->freeWidget(this); // Free from manager
|
||||
enableFlags(HIDDEN);
|
||||
|
||||
onVisible(false);
|
||||
@ -241,7 +246,8 @@ void Widget::setEnabled(bool state)
|
||||
}
|
||||
else {
|
||||
if (!hasFlags(DISABLED)) {
|
||||
manager()->freeWidget(this); // Free from the manager
|
||||
if (auto man = manager())
|
||||
man->freeWidget(this); // Free from the manager
|
||||
|
||||
enableFlags(DISABLED);
|
||||
invalidate();
|
||||
@ -541,9 +547,8 @@ void Widget::removeChild(WidgetsList::iterator& it)
|
||||
m_children.erase(it);
|
||||
|
||||
// Free from manager
|
||||
Manager* manager = this->manager();
|
||||
if (manager)
|
||||
manager->freeWidget(child);
|
||||
if (auto man = manager())
|
||||
man->freeWidget(child);
|
||||
|
||||
child->m_parent = nullptr;
|
||||
}
|
||||
@ -617,7 +622,8 @@ void Widget::layout()
|
||||
void Widget::loadLayout()
|
||||
{
|
||||
if (!m_id.empty()) {
|
||||
LayoutIO* io = manager()->getLayoutIO();
|
||||
auto man = manager();
|
||||
LayoutIO* io = (man ? man->getLayoutIO(): nullptr);
|
||||
if (io) {
|
||||
std::string layout = io->loadLayout(this);
|
||||
if (!layout.empty()) {
|
||||
@ -636,7 +642,8 @@ void Widget::loadLayout()
|
||||
void Widget::saveLayout()
|
||||
{
|
||||
if (!m_id.empty()) {
|
||||
LayoutIO* io = manager()->getLayoutIO();
|
||||
auto man = manager();
|
||||
LayoutIO* io = (man ? man->getLayoutIO(): nullptr);
|
||||
if (io) {
|
||||
std::stringstream s;
|
||||
SaveLayoutEvent ev(this, s);
|
||||
@ -690,8 +697,8 @@ void Widget::setBoundsQuietly(const gfx::Rect& rc)
|
||||
m_bounds = rc;
|
||||
|
||||
// Remove all paint messages for this widget.
|
||||
if (Manager* manager = this->manager())
|
||||
manager->removeMessagesFor(this, kPaintMessage);
|
||||
if (Manager* man = manager())
|
||||
man->removeMessagesFor(this, kPaintMessage);
|
||||
}
|
||||
|
||||
// TODO Test moving this inside the if (m_bounds != rc) { ... }
|
||||
@ -975,6 +982,8 @@ void Widget::flushRedraw()
|
||||
|
||||
Manager* manager = this->manager();
|
||||
ASSERT(manager);
|
||||
if (!manager)
|
||||
return;
|
||||
|
||||
while (!processing.empty()) {
|
||||
Widget* widget = processing.front();
|
||||
@ -1300,36 +1309,44 @@ void Widget::resetSizeHint()
|
||||
|
||||
void Widget::requestFocus()
|
||||
{
|
||||
manager()->setFocus(this);
|
||||
if (auto man = manager())
|
||||
man->setFocus(this);
|
||||
}
|
||||
|
||||
void Widget::releaseFocus()
|
||||
{
|
||||
if (hasFocus())
|
||||
manager()->freeFocus();
|
||||
if (hasFocus()) {
|
||||
if (auto man = manager())
|
||||
man->freeFocus();
|
||||
}
|
||||
}
|
||||
|
||||
// Captures the mouse to send all the future mouse messsages to the
|
||||
// specified widget (included the kMouseMoveMessage and kSetCursorMessage).
|
||||
void Widget::captureMouse()
|
||||
{
|
||||
if (!manager()->getCapture()) {
|
||||
manager()->setCapture(this);
|
||||
if (auto man = manager()) {
|
||||
if (!man->getCapture()) {
|
||||
man->setCapture(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Releases the capture of the mouse events.
|
||||
void Widget::releaseMouse()
|
||||
{
|
||||
if (manager()->getCapture() == this) {
|
||||
manager()->freeCapture();
|
||||
if (auto man = manager()) {
|
||||
if (man->getCapture() == this) {
|
||||
man->freeCapture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Widget::offerCapture(ui::MouseMessage* mouseMsg, int widget_type)
|
||||
{
|
||||
if (hasCapture()) {
|
||||
Widget* pick = manager()->pick(mouseMsg->position());
|
||||
auto man = manager();
|
||||
Widget* pick = (man ? man->pick(mouseMsg->position()): nullptr);
|
||||
if (pick && pick != this && pick->type() == widget_type) {
|
||||
releaseMouse();
|
||||
|
||||
@ -1340,7 +1357,7 @@ bool Widget::offerCapture(ui::MouseMessage* mouseMsg, int widget_type)
|
||||
mouseMsg->modifiers(),
|
||||
mouseMsg->position());
|
||||
mouseMsg2->setRecipient(pick);
|
||||
manager()->enqueueMessage(mouseMsg2);
|
||||
man->enqueueMessage(mouseMsg2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1601,8 +1618,8 @@ void Widget::offsetWidgets(int dx, int dy)
|
||||
m_bounds.offset(dx, dy);
|
||||
|
||||
// Remove all paint messages for this widget.
|
||||
if (Manager* manager = this->manager())
|
||||
manager->removeMessagesFor(this, kPaintMessage);
|
||||
if (auto man = manager())
|
||||
man->removeMessagesFor(this, kPaintMessage);
|
||||
|
||||
for (auto child : m_children)
|
||||
child->offsetWidgets(dx, dy);
|
||||
|
Loading…
x
Reference in New Issue
Block a user