mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-05 18:40:37 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
4cfb3cfa3f
63
.clang-tidy
63
.clang-tidy
@ -1,4 +1,65 @@
|
||||
#
|
||||
# Disabled or configured checks:
|
||||
#
|
||||
# bugprone-easily-swappable-parameters: We have a lot of functions
|
||||
# with (int, int) or (string, string) so it does't make sense to enable
|
||||
# this option.
|
||||
#
|
||||
# readability-braces-around-statements: We use a lot of:
|
||||
# if (cond)
|
||||
# stmt;
|
||||
# else
|
||||
# stmt;
|
||||
# and there is no way to allow this with this check.
|
||||
#
|
||||
# readability-function-cognitive-complexity: We have this disabled
|
||||
# temporarily, but it'd be nice to enable this with a high threshold
|
||||
# in the future.
|
||||
#
|
||||
# readability-identifier-length: We use a lot of short names like x,
|
||||
# y, w, h so we prefer to remove this.
|
||||
#
|
||||
# readability-magic-numbers: We use a lot of magic numbers like 8, 16,
|
||||
# 24 for masks like 0xFF00, etc.
|
||||
#
|
||||
# readability-isolate-declaration: We use multiple declarations
|
||||
# several times (e.g. int x, y, etc.)
|
||||
#
|
||||
# readability-uppercase-literal-suffix: We use a lot of 0.0f, but in a
|
||||
# future we might enable this.
|
||||
#
|
||||
# readability-named-parameter: We prefer misc-unused-parameters to
|
||||
# remove a parameter name that is not used.
|
||||
#
|
||||
# misc-use-anonymous-namespace: We use anonymous namespaces or static
|
||||
# functions indifferently.
|
||||
#
|
||||
# misc-non-private-member-variables-in-classes: We use structs with
|
||||
# all public members in some cases.
|
||||
#
|
||||
---
|
||||
Checks: 'clang-analyzer-*'
|
||||
Checks: >
|
||||
-*,
|
||||
bugprone-*,
|
||||
clang-analyzer-*,
|
||||
concurrency-*,
|
||||
misc-*,
|
||||
performance-*,
|
||||
portability-*,
|
||||
readability-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-misc-use-anonymous-namespace,
|
||||
-readability-braces-around-statements,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-identifier-length,
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-named-parameter,
|
||||
-readability-uppercase-literal-suffix
|
||||
WarningsAsErrors: ''
|
||||
CheckOptions:
|
||||
- key: readability-implicit-bool-conversion.AllowPointerConditions
|
||||
value: true
|
||||
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
||||
value: true
|
||||
...
|
||||
|
32
.github/workflows/clang_tidy.yml
vendored
Normal file
32
.github/workflows/clang_tidy.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: Clang Tidy Diff
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.cpp'
|
||||
- '**.h'
|
||||
- '.github/workflows/clang_tidy.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: ZedThree/clang-tidy-review@v0.14.0
|
||||
id: review
|
||||
with:
|
||||
build_dir: build
|
||||
config_file: .clang-tidy
|
||||
split_workflow: true
|
||||
apt_packages: |
|
||||
libc++-dev, libc++abi-dev, libpixman-1-dev,
|
||||
libfreetype6-dev, libharfbuzz-dev, zlib1g-dev, libx11-dev,
|
||||
libxcursor-dev, libxi-dev, libgl1-mesa-dev
|
||||
cmake_command: |
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DLAF_BACKEND=none -DCMAKE_EXPORT_COMPILE_COMMANDS=on
|
||||
- uses: ZedThree/clang-tidy-review/upload@v0.14.0
|
||||
id: upload-review
|
18
.github/workflows/clang_tidy_post.yml
vendored
Normal file
18
.github/workflows/clang_tidy_post.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: Post Clang Tidy Comments
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Clang Tidy Diff"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
checks: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
post-comments:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: ZedThree/clang-tidy-review/post@v0.14.0
|
||||
with:
|
||||
token: ${{ secrets.CLANG_TIDY_TOKEN }}
|
Binary file not shown.
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 57 KiB |
BIN
data/icons/ase20.png
Normal file
BIN
data/icons/ase20.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 207 B |
BIN
data/icons/ase28.png
Normal file
BIN
data/icons/ase28.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 263 B |
@ -126,9 +126,12 @@ at least.
|
||||
|
||||
### Old palette chunk (0x0004)
|
||||
|
||||
Ignore this chunk if you find the new palette chunk (0x2019) Aseprite
|
||||
v1.1 saves both chunks 0x0004 and 0x2019 just for backward
|
||||
compatibility.
|
||||
Ignore this chunk if you find the new palette chunk (0x2019). Aseprite
|
||||
v1.1 saves both chunks (0x0004 and 0x2019) just for backward
|
||||
compatibility. Aseprite v1.3.5 writes this chunk if the palette
|
||||
doesn't have alpha channel and contains 256 colors or less (because
|
||||
this chunk is smaller), in other case the new palette chunk (0x2019)
|
||||
will be used (and the old one is not saved anymore).
|
||||
|
||||
WORD Number of packets
|
||||
+ For each packet
|
||||
|
@ -776,7 +776,10 @@ if(ENABLE_UPDATER)
|
||||
endif()
|
||||
|
||||
if(ENABLE_STEAM)
|
||||
add_definitions(-DENABLE_STEAM)
|
||||
# We need the ENABLE_STEAM flag in main module too so AppOptions are
|
||||
# equal in both modules, app-lib and main (that's why this flag is
|
||||
# marked as PUBLIC).
|
||||
target_compile_definitions(app-lib PUBLIC -DENABLE_STEAM)
|
||||
target_link_libraries(app-lib steam-lib)
|
||||
endif()
|
||||
|
||||
|
@ -328,6 +328,11 @@ int App::initialize(const AppOptions& options)
|
||||
app_configure_drm();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_STEAM
|
||||
if (options.noInApp())
|
||||
m_inAppSteam = false;
|
||||
#endif
|
||||
|
||||
// Load modules
|
||||
m_modules = std::make_unique<Modules>(createLogInDesktop, preferences());
|
||||
m_legacy = std::make_unique<LegacyModules>(isGui() ? REQUIRE_INTERFACE: 0);
|
||||
@ -511,9 +516,18 @@ void App::run()
|
||||
|
||||
// Initialize Steam API
|
||||
#ifdef ENABLE_STEAM
|
||||
steam::SteamAPI steam;
|
||||
if (steam.initialized())
|
||||
os::System::instance()->activateApp();
|
||||
std::unique_ptr<steam::SteamAPI> steam;
|
||||
if (m_inAppSteam) {
|
||||
steam = std::make_unique<steam::SteamAPI>();
|
||||
if (steam->isInitialized())
|
||||
os::System::instance()->activateApp();
|
||||
}
|
||||
else {
|
||||
// We tried to load the Steam SDK without calling
|
||||
// SteamAPI_InitSafe() to check if we could run the program
|
||||
// without "in game" indication but still capturing screenshots
|
||||
// on Steam, and that wasn't the case.
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) || defined(ENABLE_DEVMODE)
|
||||
@ -707,24 +721,21 @@ Workspace* App::workspace() const
|
||||
{
|
||||
if (m_mainWindow)
|
||||
return m_mainWindow->getWorkspace();
|
||||
else
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ContextBar* App::contextBar() const
|
||||
{
|
||||
if (m_mainWindow)
|
||||
return m_mainWindow->getContextBar();
|
||||
else
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Timeline* App::timeline() const
|
||||
{
|
||||
if (m_mainWindow)
|
||||
return m_mainWindow->getTimeline();
|
||||
else
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Preferences& App::preferences() const
|
||||
@ -853,8 +864,7 @@ PixelFormat app_get_current_pixel_format()
|
||||
Doc* doc = ctx->activeDocument();
|
||||
if (doc)
|
||||
return doc->sprite()->pixelFormat();
|
||||
else
|
||||
return IMAGE_RGB;
|
||||
return IMAGE_RGB;
|
||||
}
|
||||
|
||||
int app_get_color_to_clear_layer(Layer* layer)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -142,6 +142,9 @@ namespace app {
|
||||
std::unique_ptr<LegacyModules> m_legacy;
|
||||
bool m_isGui;
|
||||
bool m_isShell;
|
||||
#ifdef ENABLE_STEAM
|
||||
bool m_inAppSteam = true;
|
||||
#endif
|
||||
std::unique_ptr<MainWindow> m_mainWindow;
|
||||
base::paths m_files;
|
||||
#ifdef ENABLE_UI
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -79,6 +79,9 @@ AppOptions::AppOptions(int argc, const char* argv[])
|
||||
, m_exportTileset(m_po.add("export-tileset").description("Export only tilesets from visible tilemap layers"))
|
||||
, m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done"))
|
||||
, m_debug(m_po.add("debug").description("Extreme verbose mode and\ncopy log to desktop"))
|
||||
#ifdef ENABLE_STEAM
|
||||
, m_noInApp(m_po.add("noinapp").description("Disable \"in game\" visibility on Steam\nDoesn't count playtime"))
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
, m_disableWintab(m_po.add("disable-wintab").description("Don't load wintab32.dll library"))
|
||||
#endif
|
||||
@ -121,6 +124,13 @@ bool AppOptions::hasExporterParams() const
|
||||
m_po.enabled(m_sheet);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_STEAM
|
||||
bool AppOptions::noInApp() const
|
||||
{
|
||||
return m_po.enabled(m_noInApp);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
bool AppOptions::disableWintab() const
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -95,6 +95,9 @@ public:
|
||||
const Option& exportTileset() const { return m_exportTileset; }
|
||||
|
||||
bool hasExporterParams() const;
|
||||
#ifdef ENABLE_STEAM
|
||||
bool noInApp() const;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
bool disableWintab() const;
|
||||
#endif
|
||||
@ -166,6 +169,9 @@ private:
|
||||
|
||||
Option& m_verbose;
|
||||
Option& m_debug;
|
||||
#ifdef ENABLE_STEAM
|
||||
Option& m_noInApp;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
Option& m_disableWintab;
|
||||
#endif
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -8,7 +9,6 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/modules/gui.h"
|
||||
@ -49,7 +49,7 @@ bool LayerVisibilityCommand::onChecked(Context* context)
|
||||
return false;
|
||||
|
||||
SelectedLayers selLayers;
|
||||
auto range = App::instance()->timeline()->range();
|
||||
DocRange range = context->activeSite().range();
|
||||
if (range.enabled()) {
|
||||
selLayers = range.selectedLayers();
|
||||
}
|
||||
@ -67,24 +67,25 @@ bool LayerVisibilityCommand::onChecked(Context* context)
|
||||
void LayerVisibilityCommand::onExecute(Context* context)
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
Doc* doc = writer.document();
|
||||
SelectedLayers selLayers;
|
||||
auto range = App::instance()->timeline()->range();
|
||||
DocRange range = context->activeSite().range();
|
||||
if (range.enabled()) {
|
||||
selLayers = range.selectedLayers();
|
||||
}
|
||||
else {
|
||||
selLayers.insert(writer.layer());
|
||||
}
|
||||
|
||||
bool anyVisible = false;
|
||||
for (auto layer : selLayers) {
|
||||
if (layer->isVisible())
|
||||
anyVisible = true;
|
||||
}
|
||||
for (auto layer : selLayers) {
|
||||
layer->setVisible(!anyVisible);
|
||||
}
|
||||
|
||||
update_screen_for_document(writer.document());
|
||||
const bool newState = !anyVisible;
|
||||
for (auto layer : selLayers)
|
||||
doc->setLayerVisibilityWithNotifications(layer, newState);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createLayerVisibilityCommand()
|
||||
|
@ -151,7 +151,7 @@ void FilterWorker::run()
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
if (m_done && m_filterMgr->isTransaction())
|
||||
m_filterMgr->commitTransaction();
|
||||
else
|
||||
@ -180,7 +180,7 @@ void FilterWorker::run()
|
||||
//
|
||||
void FilterWorker::reportProgress(float progress)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
m_pos = progress;
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ bool FilterWorker::isCancelled()
|
||||
{
|
||||
bool cancelled;
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
cancelled = (m_cancelled || m_abort);
|
||||
|
||||
return cancelled;
|
||||
@ -209,7 +209,7 @@ void FilterWorker::applyFilterInBackground()
|
||||
m_filterMgr->applyToTarget();
|
||||
|
||||
// Mark the work as 'done'.
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
m_done = true;
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
@ -224,7 +224,7 @@ void FilterWorker::applyFilterInBackground()
|
||||
// every 100 milliseconds).
|
||||
void FilterWorker::onMonitoringTick()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_alert) {
|
||||
m_alert->setProgress(m_pos);
|
||||
|
@ -48,8 +48,7 @@ namespace app {
|
||||
auto it = m_params.find(name);
|
||||
if (it != m_params.end())
|
||||
return it->second;
|
||||
else
|
||||
return std::string();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void operator|=(const Params& params) {
|
||||
|
@ -193,6 +193,16 @@ color_t Doc::bgColor(Layer* layer) const
|
||||
return layer->sprite()->transparentColor();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Modifications with notifications
|
||||
|
||||
void Doc::setLayerVisibilityWithNotifications(Layer* layer, const bool visible)
|
||||
{
|
||||
notifyBeforeLayerVisibilityChange(layer, visible);
|
||||
layer->setVisible(visible);
|
||||
notifyAfterLayerVisibilityChange(layer);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Notifications
|
||||
|
||||
@ -244,6 +254,20 @@ void Doc::notifyLayerMergedDown(Layer* srcLayer, Layer* targetLayer)
|
||||
notify_observers<DocEvent&>(&DocObserver::onLayerMergedDown, ev);
|
||||
}
|
||||
|
||||
void Doc::notifyBeforeLayerVisibilityChange(Layer* layer, bool newState)
|
||||
{
|
||||
DocEvent ev(this);
|
||||
ev.layer(layer);
|
||||
notify_observers<DocEvent&, bool>(&DocObserver::onBeforeLayerVisibilityChange, ev, newState);
|
||||
}
|
||||
|
||||
void Doc::notifyAfterLayerVisibilityChange(Layer* layer)
|
||||
{
|
||||
DocEvent ev(this);
|
||||
ev.layer(layer);
|
||||
notify_observers<DocEvent&>(&DocObserver::onAfterLayerVisibilityChange, ev);
|
||||
}
|
||||
|
||||
void Doc::notifyCelMoved(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame)
|
||||
{
|
||||
DocEvent ev(this);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -107,6 +107,14 @@ namespace app {
|
||||
|
||||
os::ColorSpaceRef osColorSpace() const { return m_osColorSpace; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Modifications with notifications
|
||||
|
||||
// Use this function to change the layer visibility and notify all
|
||||
// DocObservers about this change (e.g. so the Editor can be
|
||||
// invalidated/redrawn, MovingPixelsState can drop pixels, etc.)
|
||||
void setLayerVisibilityWithNotifications(Layer* layer, const bool visible);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Notifications
|
||||
|
||||
@ -116,6 +124,8 @@ namespace app {
|
||||
void notifySpritePixelsModified(Sprite* sprite, const gfx::Region& region, frame_t frame);
|
||||
void notifyExposeSpritePixels(Sprite* sprite, const gfx::Region& region);
|
||||
void notifyLayerMergedDown(Layer* srcLayer, Layer* targetLayer);
|
||||
void notifyBeforeLayerVisibilityChange(Layer* layer, bool newState);
|
||||
void notifyAfterLayerVisibilityChange(Layer* layer);
|
||||
void notifyCelMoved(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame);
|
||||
void notifyCelCopied(Layer* fromLayer, frame_t fromFrame, Layer* toLayer, frame_t toFrame);
|
||||
void notifySelectionChanged();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -97,6 +97,10 @@ namespace app {
|
||||
// The collapsed/expanded flag of a specific layer changed.
|
||||
virtual void onLayerCollapsedChanged(DocEvent& ev) { }
|
||||
|
||||
// The visibility flag of a specific layer is going to change/changed.
|
||||
virtual void onBeforeLayerVisibilityChange(DocEvent& ev, bool newState) { }
|
||||
virtual void onAfterLayerVisibilityChange(DocEvent& ev) { }
|
||||
|
||||
// The tileset was remapped (e.g. when tiles are re-ordered).
|
||||
virtual void onRemapTileset(DocEvent& ev, const doc::Remap& remap) { }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -355,7 +355,7 @@ bool AseFormat::onSave(FileOp* fop)
|
||||
|
||||
bool require_new_palette_chunk = false;
|
||||
for (Palette* pal : sprite->getPalettes()) {
|
||||
if (pal->size() != 256 || pal->hasAlpha()) {
|
||||
if (pal->size() > 256 || pal->hasAlpha()) {
|
||||
require_new_palette_chunk = true;
|
||||
break;
|
||||
}
|
||||
@ -393,9 +393,12 @@ bool AseFormat::onSave(FileOp* fop)
|
||||
ase_file_write_palette_chunk(f, &frame_header,
|
||||
pal, palFrom, palTo);
|
||||
}
|
||||
|
||||
// Write color chunk for backward compatibility only
|
||||
ase_file_write_color2_chunk(f, &frame_header, pal);
|
||||
else {
|
||||
// Use old color chunk only when the palette has 256 or less
|
||||
// colors, and we don't need the alpha channel (as this chunk
|
||||
// is smaller than the new palette chunk).
|
||||
ase_file_write_color2_chunk(f, &frame_header, pal);
|
||||
}
|
||||
}
|
||||
|
||||
// Write extra chunks in the first frame
|
||||
@ -676,6 +679,7 @@ static void ase_file_write_color2_chunk(FILE* f, dio::AsepriteFrameHeader* frame
|
||||
|
||||
// First packet
|
||||
fputc(0, f); // skip 0 colors
|
||||
ASSERT(pal->size() <= 256); // For >256 we use the palette chunk
|
||||
fputc(pal->size() == 256 ? 0: pal->size(), f); // number of colors
|
||||
for (c=0; c<pal->size(); c++) {
|
||||
color = pal->getEntry(c);
|
||||
@ -1692,8 +1696,12 @@ static void ase_ungroup_all(LayerGroup* group)
|
||||
|
||||
for (Layer* child : list) {
|
||||
if (child->isGroup()) {
|
||||
ase_ungroup_all(static_cast<LayerGroup*>(child));
|
||||
group->removeLayer(child);
|
||||
auto* childGroup = static_cast<LayerGroup*>(child);
|
||||
ase_ungroup_all(childGroup);
|
||||
group->removeLayer(childGroup);
|
||||
|
||||
ASSERT(childGroup->layersCount() == 0);
|
||||
delete childGroup;
|
||||
}
|
||||
else if (group != root) {
|
||||
// Create a new name adding all group layer names
|
||||
@ -1711,11 +1719,6 @@ static void ase_ungroup_all(LayerGroup* group)
|
||||
root->addLayer(child);
|
||||
}
|
||||
}
|
||||
|
||||
if (group != root) {
|
||||
ASSERT(group->layersCount() == 0);
|
||||
delete group;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1122,13 +1122,13 @@ void FileOp::operate(IFileOpProgress* progress)
|
||||
void FileOp::done()
|
||||
{
|
||||
// Finally done.
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
m_done = true;
|
||||
}
|
||||
|
||||
void FileOp::stop()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
if (!m_done)
|
||||
m_stop = true;
|
||||
}
|
||||
@ -1443,7 +1443,7 @@ void FileOp::setError(const char *format, ...)
|
||||
|
||||
// Concatenate the new error
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
// Add a newline char automatically if it's needed
|
||||
if (!m_error.empty() && m_error.back() != '\n')
|
||||
m_error.push_back('\n');
|
||||
@ -1455,7 +1455,7 @@ void FileOp::setIncompatibilityError(const std::string& msg)
|
||||
{
|
||||
// Concatenate the new error
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
// Add a newline char automatically if it's needed
|
||||
if (!m_incompatibilityError.empty() && m_incompatibilityError.back() != '\n')
|
||||
m_incompatibilityError.push_back('\n');
|
||||
@ -1465,7 +1465,7 @@ void FileOp::setIncompatibilityError(const std::string& msg)
|
||||
|
||||
void FileOp::setProgress(double progress)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
|
||||
if (isSequence()) {
|
||||
m_progress =
|
||||
@ -1494,7 +1494,7 @@ double FileOp::progress() const
|
||||
{
|
||||
double progress;
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
progress = m_progress;
|
||||
}
|
||||
return progress;
|
||||
@ -1506,7 +1506,7 @@ bool FileOp::isDone() const
|
||||
{
|
||||
bool done;
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
done = m_done;
|
||||
}
|
||||
return done;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -329,7 +329,9 @@ int Layer_set_isEditable(lua_State* L)
|
||||
int Layer_set_isVisible(lua_State* L)
|
||||
{
|
||||
auto layer = get_docobj<Layer>(L, 1);
|
||||
layer->setVisible(lua_toboolean(L, 2));
|
||||
const bool newState = lua_toboolean(L, 2);
|
||||
Doc* doc = static_cast<Doc*>(layer->sprite()->document());
|
||||
doc->setLayerVisibilityWithNotifications(layer, newState);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ Task::~Task()
|
||||
|
||||
void Task::run(base::task::func_t&& func)
|
||||
{
|
||||
std::lock_guard lock(m_token_mutex);
|
||||
const std::lock_guard lock(m_token_mutex);
|
||||
m_task.on_execute(std::move(func));
|
||||
m_token = &m_task.start(tasks_pool);
|
||||
}
|
||||
|
@ -34,29 +34,27 @@ namespace app {
|
||||
}
|
||||
|
||||
bool canceled() const {
|
||||
std::lock_guard lock(m_token_mutex);
|
||||
const std::lock_guard lock(m_token_mutex);
|
||||
if (m_token)
|
||||
return m_token->canceled();
|
||||
else
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
float progress() const {
|
||||
std::lock_guard lock(m_token_mutex);
|
||||
const std::lock_guard lock(m_token_mutex);
|
||||
if (m_token)
|
||||
return m_token->progress();
|
||||
else
|
||||
return 0.0f;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
std::lock_guard lock(m_token_mutex);
|
||||
const std::lock_guard lock(m_token_mutex);
|
||||
if (m_token)
|
||||
m_token->cancel();
|
||||
}
|
||||
|
||||
void set_progress(float progress) {
|
||||
std::lock_guard lock(m_token_mutex);
|
||||
const std::lock_guard lock(m_token_mutex);
|
||||
if (m_token)
|
||||
m_token->set_progress(progress);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
|
||||
~Worker() {
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
if (m_fop)
|
||||
m_fop->stop();
|
||||
}
|
||||
@ -57,7 +57,7 @@ public:
|
||||
}
|
||||
|
||||
void stop() const {
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
if (m_fop)
|
||||
m_fop->stop();
|
||||
}
|
||||
@ -67,7 +67,7 @@ public:
|
||||
}
|
||||
|
||||
void updateProgress() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
if (m_item.fileitem && m_item.fop) {
|
||||
double progress = m_item.fop->progress();
|
||||
if (progress > m_item.fileitem->getThumbnailProgress())
|
||||
@ -80,7 +80,7 @@ private:
|
||||
ASSERT(!m_fop);
|
||||
try {
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
m_fop = m_item.fop;
|
||||
ASSERT(m_fop);
|
||||
}
|
||||
@ -167,7 +167,7 @@ private:
|
||||
0, 0, 0, 0, thumbnailImage->width(), thumbnailImage->height());
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
m_item.fileitem->setThumbnail(thumbnail);
|
||||
}
|
||||
}
|
||||
@ -191,13 +191,13 @@ private:
|
||||
// Reset the m_item (first the fileitem so this worker is not
|
||||
// associated to this fileitem anymore, and then the FileOp).
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
m_item.fileitem = nullptr;
|
||||
}
|
||||
|
||||
m_fop->done();
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
const std::lock_guard lock(m_mutex);
|
||||
m_item.fop = nullptr;
|
||||
delete m_fop;
|
||||
m_fop = nullptr;
|
||||
@ -212,7 +212,7 @@ private:
|
||||
bool success = true;
|
||||
while (success) {
|
||||
{
|
||||
std::lock_guard lock(m_mutex); // To access m_item
|
||||
const std::lock_guard lock(m_mutex); // To access m_item
|
||||
success = m_queue.try_pop(m_item);
|
||||
}
|
||||
if (success)
|
||||
@ -253,7 +253,7 @@ ThumbnailGenerator::ThumbnailGenerator()
|
||||
|
||||
bool ThumbnailGenerator::checkWorkers()
|
||||
{
|
||||
std::lock_guard lock(m_workersAccess);
|
||||
const std::lock_guard lock(m_workersAccess);
|
||||
bool doingWork = (!m_workers.empty());
|
||||
|
||||
for (WorkerList::iterator
|
||||
@ -339,14 +339,14 @@ void ThumbnailGenerator::stopAllWorkers()
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_workersAccess);
|
||||
const std::lock_guard lock(m_workersAccess);
|
||||
for (const auto& worker : m_workers)
|
||||
worker->stop();
|
||||
}
|
||||
|
||||
void ThumbnailGenerator::startWorker()
|
||||
{
|
||||
std::lock_guard lock(m_workersAccess);
|
||||
const std::lock_guard lock(m_workersAccess);
|
||||
if (m_workers.size() < m_maxWorkers) {
|
||||
m_workers.push_back(std::make_unique<Worker>(m_remainingItems));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -23,7 +23,7 @@ namespace app {
|
||||
|
||||
// Wrapper to create a new transaction or get the current
|
||||
// transaction in the context.
|
||||
class Tx {
|
||||
class [[nodiscard]] Tx {
|
||||
public:
|
||||
enum LockAction {
|
||||
DocIsLocked, // The doc is locked to be written
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -478,7 +478,16 @@ void DocView::onTotalFramesChanged(DocEvent& ev)
|
||||
|
||||
void DocView::onLayerRestacked(DocEvent& ev)
|
||||
{
|
||||
m_editor->invalidate();
|
||||
if (hasContentInActiveFrame(ev.layer()))
|
||||
m_editor->invalidate();
|
||||
}
|
||||
|
||||
void DocView::onAfterLayerVisibilityChange(DocEvent& ev)
|
||||
{
|
||||
// If there is no cel for this layer in the current frame, there is
|
||||
// no need to redraw the editor
|
||||
if (hasContentInActiveFrame(ev.layer()))
|
||||
m_editor->invalidate();
|
||||
}
|
||||
|
||||
void DocView::onTilesetChanged(DocEvent& ev)
|
||||
@ -653,4 +662,19 @@ void DocView::onCancel(Context* ctx)
|
||||
}
|
||||
}
|
||||
|
||||
bool DocView::hasContentInActiveFrame(const doc::Layer* layer) const
|
||||
{
|
||||
if (!layer)
|
||||
return false;
|
||||
else if (layer->cel(m_editor->frame()))
|
||||
return true;
|
||||
else if (layer->isGroup()) {
|
||||
for (const doc::Layer* child : static_cast<const doc::LayerGroup*>(layer)->layers()) {
|
||||
if (hasContentInActiveFrame(child))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -15,6 +15,10 @@
|
||||
#include "app/ui/workspace_view.h"
|
||||
#include "ui/box.h"
|
||||
|
||||
namespace doc {
|
||||
class Layer;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class View;
|
||||
}
|
||||
@ -86,6 +90,7 @@ namespace app {
|
||||
void onAfterRemoveCel(DocEvent& ev) override;
|
||||
void onTotalFramesChanged(DocEvent& ev) override;
|
||||
void onLayerRestacked(DocEvent& ev) override;
|
||||
void onAfterLayerVisibilityChange(DocEvent& ev) override;
|
||||
void onTilesetChanged(DocEvent& ev) override;
|
||||
|
||||
// InputChainElement impl
|
||||
@ -105,6 +110,8 @@ namespace app {
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
|
||||
private:
|
||||
bool hasContentInActiveFrame(const doc::Layer* layer) const;
|
||||
|
||||
Type m_type;
|
||||
Doc* m_document;
|
||||
ui::View* m_view;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -96,8 +96,9 @@ void DrawingState::initToolLoop(Editor* editor,
|
||||
// For selection inks we don't use a "the selected layer" for
|
||||
// preview purposes, because we want the selection feedback to be at
|
||||
// the top of all layers.
|
||||
Layer* previewLayer = (m_toolLoop->getInk()->isSelection() ? nullptr:
|
||||
m_toolLoop->getLayer());
|
||||
Layer* previewLayer = (m_toolLoop->getInk()->isSelection() ||
|
||||
m_toolLoop->getInk()->isSlice() ?
|
||||
nullptr : m_toolLoop->getLayer());
|
||||
|
||||
// Prepare preview image (the destination image will be our preview
|
||||
// in the tool-loop time, so we can see what we are drawing)
|
||||
|
@ -2438,6 +2438,12 @@ void Editor::onRemoveSlice(DocEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::onBeforeLayerVisibilityChange(DocEvent& ev, bool newState)
|
||||
{
|
||||
if (m_state)
|
||||
m_state->onBeforeLayerVisibilityChange(this, ev.layer(), newState);
|
||||
}
|
||||
|
||||
void Editor::setCursor(const gfx::Point& mouseDisplayPos)
|
||||
{
|
||||
Rect vp = View::getView(this)->viewportBounds();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -351,6 +351,7 @@ namespace app {
|
||||
void onAddTag(DocEvent& ev) override;
|
||||
void onRemoveTag(DocEvent& ev) override;
|
||||
void onRemoveSlice(DocEvent& ev) override;
|
||||
void onBeforeLayerVisibilityChange(DocEvent& ev, bool newState) override;
|
||||
|
||||
// ActiveToolObserver impl
|
||||
void onActiveToolChange(tools::Tool* tool) override;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -26,6 +26,7 @@ namespace ui {
|
||||
}
|
||||
|
||||
namespace doc {
|
||||
class Layer;
|
||||
class Tag;
|
||||
}
|
||||
|
||||
@ -145,6 +146,11 @@ namespace app {
|
||||
// collection.
|
||||
virtual void onBeforeRemoveLayer(Editor* editor) { }
|
||||
|
||||
// Called when the visibility of a specific layer is changed.
|
||||
virtual void onBeforeLayerVisibilityChange(Editor* editor,
|
||||
doc::Layer* layer,
|
||||
bool newState) { }
|
||||
|
||||
private:
|
||||
DISABLE_COPYING(EditorState);
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -578,6 +578,25 @@ bool MovingPixelsState::acceptQuickTool(tools::Tool* tool)
|
||||
tool->getInk(0)->isZoom());
|
||||
}
|
||||
|
||||
void MovingPixelsState::onBeforeLayerVisibilityChange(Editor* editor,
|
||||
doc::Layer* layer,
|
||||
bool newState)
|
||||
{
|
||||
if (!isActiveDocument())
|
||||
return;
|
||||
|
||||
// If the layer visibility of any selected layer changes, we just
|
||||
// drop the pixels (it's the easiest way to avoid modifying hidden
|
||||
// pixels).
|
||||
if (m_pixelsMovement) {
|
||||
const Site& site = m_pixelsMovement->site();
|
||||
if (site.layer() == layer ||
|
||||
site.range().contains(layer)) {
|
||||
dropPixels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Before executing any command, we drop the pixels (go back to standby).
|
||||
void MovingPixelsState::onBeforeCommandExecution(CommandExecutionEvent& ev)
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,7 +21,7 @@
|
||||
#include "ui/timer.h"
|
||||
|
||||
namespace doc {
|
||||
class Image;
|
||||
class Layer;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
@ -54,35 +54,37 @@ namespace app {
|
||||
void updateTransformation(const Transformation& t);
|
||||
|
||||
// EditorState
|
||||
virtual void onEnterState(Editor* editor) override;
|
||||
virtual void onEditorGotFocus(Editor* editor) override;
|
||||
virtual LeaveAction onLeaveState(Editor* editor, EditorState* newState) override;
|
||||
virtual void onActiveToolChange(Editor* editor, tools::Tool* tool) override;
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) override;
|
||||
virtual bool acceptQuickTool(tools::Tool* tool) override;
|
||||
virtual bool requireBrushPreview() override { return false; }
|
||||
void onEnterState(Editor* editor) override;
|
||||
void onEditorGotFocus(Editor* editor) override;
|
||||
LeaveAction onLeaveState(Editor* editor, EditorState* newState) override;
|
||||
void onActiveToolChange(Editor* editor, tools::Tool* tool) override;
|
||||
bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
bool onUpdateStatusBar(Editor* editor) override;
|
||||
bool acceptQuickTool(tools::Tool* tool) override;
|
||||
bool requireBrushPreview() override { return false; }
|
||||
void onBeforeLayerVisibilityChange(Editor* editor, doc::Layer* layer, bool newState) override;
|
||||
|
||||
|
||||
// EditorObserver
|
||||
virtual void onDestroyEditor(Editor* editor) override;
|
||||
virtual void onBeforeFrameChanged(Editor* editor) override;
|
||||
virtual void onBeforeLayerChanged(Editor* editor) override;
|
||||
void onDestroyEditor(Editor* editor) override;
|
||||
void onBeforeFrameChanged(Editor* editor) override;
|
||||
void onBeforeLayerChanged(Editor* editor) override;
|
||||
|
||||
// TimelineObserver
|
||||
virtual void onBeforeRangeChanged(Timeline* timeline) override;
|
||||
void onBeforeRangeChanged(Timeline* timeline) override;
|
||||
|
||||
// ContextBarObserver
|
||||
virtual void onDropPixels(ContextBarObserver::DropAction action) override;
|
||||
void onDropPixels(ContextBarObserver::DropAction action) override;
|
||||
|
||||
// PixelsMovementDelegate
|
||||
virtual void onPivotChange() override;
|
||||
void onPivotChange() override;
|
||||
|
||||
virtual Transformation getTransformation(Editor* editor) override;
|
||||
Transformation getTransformation(Editor* editor) override;
|
||||
|
||||
private:
|
||||
// DelayedMouseMoveDelegate impl
|
||||
|
@ -787,9 +787,10 @@ void PixelsMovement::stampImage(bool finalStamp)
|
||||
cels.push_back(currentCel);
|
||||
}
|
||||
|
||||
if (currentCel && currentCel->layer() &&
|
||||
if (currentCel &&
|
||||
currentCel->layer() &&
|
||||
currentCel->layer()->isImage() &&
|
||||
!currentCel->layer()->isEditableHierarchy()) {
|
||||
!currentCel->layer()->canEditPixels()) {
|
||||
Transformation initialCelPos(gfx::Rect(m_initialMask0->bounds()), m_currentData.cornerThick());
|
||||
redrawExtraImage(&initialCelPos);
|
||||
stampExtraCelImage();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -75,6 +75,8 @@ namespace app {
|
||||
const Mask* mask,
|
||||
const char* operationName);
|
||||
|
||||
const Site& site() { return m_site; }
|
||||
|
||||
HandleType handle() const { return m_handle; }
|
||||
bool canHandleFrameChange() const { return m_canHandleFrameChange; }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -452,8 +452,8 @@ protected:
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// For drawing
|
||||
|
||||
class ToolLoopImpl : public ToolLoopBase,
|
||||
public EditorObserver {
|
||||
class ToolLoopImpl final : public ToolLoopBase,
|
||||
public EditorObserver {
|
||||
Context* m_context;
|
||||
bool m_filled;
|
||||
bool m_previewFilled;
|
||||
@ -517,6 +517,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// 'isSelectionPreview = true' if the intention is to show a preview
|
||||
// of Selection tools or Slice tool.
|
||||
const bool isSelectionPreview = m_ink->isSelection() || m_ink->isSlice();
|
||||
m_expandCelCanvas.reset(new ExpandCelCanvas(
|
||||
site, m_layer,
|
||||
m_docPref.tiled.mode(),
|
||||
@ -530,10 +533,10 @@ public:
|
||||
(m_layer->isTilemap() &&
|
||||
site.tilemapMode() == TilemapMode::Pixels &&
|
||||
site.tilesetMode() == TilesetMode::Manual &&
|
||||
!m_ink->isSelection() ? ExpandCelCanvas::TilesetPreview:
|
||||
ExpandCelCanvas::None) |
|
||||
(m_ink->isSelection() ? ExpandCelCanvas::SelectionPreview:
|
||||
ExpandCelCanvas::None))));
|
||||
!isSelectionPreview ? ExpandCelCanvas::TilesetPreview:
|
||||
ExpandCelCanvas::None) |
|
||||
(isSelectionPreview ? ExpandCelCanvas::SelectionPreview:
|
||||
ExpandCelCanvas::None))));
|
||||
|
||||
if (!m_floodfillSrcImage)
|
||||
m_floodfillSrcImage = const_cast<Image*>(getSrcImage());
|
||||
@ -555,7 +558,7 @@ public:
|
||||
m_sprayWidth = m_toolPref.spray.width();
|
||||
m_spraySpeed = m_toolPref.spray.speed();
|
||||
|
||||
if (m_ink->isSelection()) {
|
||||
if (isSelectionPreview) {
|
||||
m_useMask = false;
|
||||
}
|
||||
else {
|
||||
@ -563,7 +566,7 @@ public:
|
||||
}
|
||||
|
||||
// Start with an empty mask if the user is selecting with "default selection mode"
|
||||
if (m_ink->isSelection() &&
|
||||
if (isSelectionPreview &&
|
||||
(!m_document->isMaskVisible() ||
|
||||
(int(getModifiers()) & int(tools::ToolLoopModifiers::kReplaceSelection)))) {
|
||||
Mask emptyMask;
|
||||
@ -592,6 +595,9 @@ public:
|
||||
m_editor->remove_observer(this);
|
||||
#endif
|
||||
|
||||
// getSrcImage() is a virtual member function but ToolLoopImpl is
|
||||
// marked as final to avoid not calling a derived version from
|
||||
// this destructor.
|
||||
if (m_floodfillSrcImage != getSrcImage())
|
||||
delete m_floodfillSrcImage;
|
||||
}
|
||||
@ -954,7 +960,7 @@ tools::ToolLoop* create_tool_loop_for_script(
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
|
||||
class PreviewToolLoopImpl : public ToolLoopBase {
|
||||
class PreviewToolLoopImpl final : public ToolLoopBase {
|
||||
Image* m_image;
|
||||
|
||||
public:
|
||||
|
@ -110,7 +110,7 @@ namespace app {
|
||||
if (it != m_styles.end())
|
||||
return it->second;
|
||||
else
|
||||
return nullptr;
|
||||
return getDefaultStyle();
|
||||
}
|
||||
|
||||
SkinPartPtr getPartById(const std::string& id) const {
|
||||
|
@ -696,7 +696,9 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
bool newVisibleState = !allLayersVisible();
|
||||
for (Layer* topLayer : m_sprite->root()->layers()) {
|
||||
if (topLayer->isVisible() != newVisibleState) {
|
||||
topLayer->setVisible(newVisibleState);
|
||||
m_document->setLayerVisibilityWithNotifications(
|
||||
topLayer, newVisibleState);
|
||||
|
||||
if (topLayer->isGroup())
|
||||
regenRows = true;
|
||||
}
|
||||
@ -825,11 +827,11 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
for (Row& row : m_rows) {
|
||||
Layer* l = row.layer();
|
||||
if (l->hasFlags(LayerFlags::Internal_WasVisible)) {
|
||||
l->setVisible(true);
|
||||
m_document->setLayerVisibilityWithNotifications(l, true);
|
||||
l->switchFlags(LayerFlags::Internal_WasVisible, false);
|
||||
}
|
||||
else {
|
||||
l->setVisible(false);
|
||||
m_document->setLayerVisibilityWithNotifications(l, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -838,7 +840,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
for (Row& row : m_rows) {
|
||||
Layer* l = row.layer();
|
||||
l->switchFlags(LayerFlags::Internal_WasVisible, l->isVisible());
|
||||
l->setVisible(false);
|
||||
m_document->setLayerVisibilityWithNotifications(l, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2016,6 +2018,14 @@ void Timeline::onLayerCollapsedChanged(DocEvent& ev)
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Timeline::onAfterLayerVisibilityChange(DocEvent& ev)
|
||||
{
|
||||
layer_t layerIdx = getLayerIndex(ev.layer());
|
||||
if (layerIdx >= 0)
|
||||
invalidateRect(getPartBounds(Hit(PART_ROW_EYE_ICON, layerIdx))
|
||||
.offset(origin()));
|
||||
}
|
||||
|
||||
void Timeline::onStateChanged(Editor* editor)
|
||||
{
|
||||
m_aniControls.updateUsingEditor(editor);
|
||||
@ -4475,12 +4485,10 @@ void Timeline::setLayerVisibleFlag(const layer_t l, const bool state)
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
bool redrawEditors = false;
|
||||
bool regenRows = false;
|
||||
|
||||
if (layer->isVisible() != state) {
|
||||
layer->setVisible(state);
|
||||
redrawEditors = true;
|
||||
m_document->setLayerVisibilityWithNotifications(layer, state);
|
||||
|
||||
// Regenerate rows because might change the flag of the children
|
||||
// (the flag is propagated to the children in m_inheritedFlags).
|
||||
@ -4493,9 +4501,8 @@ void Timeline::setLayerVisibleFlag(const layer_t l, const bool state)
|
||||
layer = layer->parent();
|
||||
while (layer) {
|
||||
if (!layer->isVisible()) {
|
||||
layer->setVisible(true);
|
||||
m_document->setLayerVisibilityWithNotifications(layer, true);
|
||||
regenRows = true;
|
||||
redrawEditors = true;
|
||||
}
|
||||
layer = layer->parent();
|
||||
}
|
||||
@ -4506,9 +4513,6 @@ void Timeline::setLayerVisibleFlag(const layer_t l, const bool state)
|
||||
regenerateRows();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
if (redrawEditors)
|
||||
m_document->notifyGeneralUpdate();
|
||||
}
|
||||
|
||||
void Timeline::setLayerEditableFlag(const layer_t l, const bool state)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -163,6 +163,7 @@ namespace app {
|
||||
void onTagChange(DocEvent& ev) override;
|
||||
void onTagRename(DocEvent& ev) override;
|
||||
void onLayerCollapsedChanged(DocEvent& ev) override;
|
||||
void onAfterLayerVisibilityChange(DocEvent& ev) override;
|
||||
|
||||
// app::Context slots.
|
||||
void onBeforeCommandExecution(CommandExecutionEvent& ev);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -45,14 +45,34 @@ Layer* candidate_if_layer_is_deleted(
|
||||
bool layer_is_locked(Editor* editor)
|
||||
{
|
||||
Layer* layer = editor->layer();
|
||||
if (layer && !layer->isEditableHierarchy()) {
|
||||
if (!layer)
|
||||
return false;
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
if (auto statusBar = StatusBar::instance())
|
||||
auto statusBar = StatusBar::instance();
|
||||
#endif
|
||||
|
||||
if (!layer->isVisibleHierarchy()) {
|
||||
#ifdef ENABLE_UI
|
||||
if (statusBar) {
|
||||
statusBar->showTip(
|
||||
1000, fmt::format(Strings::statusbar_tips_layer_locked(), layer->name()));
|
||||
1000, fmt::format(Strings::statusbar_tips_layer_x_is_hidden(),
|
||||
layer->name()));
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!layer->isEditableHierarchy()) {
|
||||
#ifdef ENABLE_UI
|
||||
if (statusBar) {
|
||||
statusBar->showTip(
|
||||
1000, fmt::format(Strings::statusbar_tips_layer_locked(), layer->name()));
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef __ASEPRITE_CONFIG_H
|
||||
#ifdef ASEPRITE_CONFIG_H_INCLUDED
|
||||
#error You cannot use config.h two times
|
||||
#endif
|
||||
|
||||
#define __ASEPRITE_CONFIG_H
|
||||
#define ASEPRITE_CONFIG_H_INCLUDED
|
||||
|
||||
// In MSVC
|
||||
#ifdef _MSC_VER
|
||||
|
@ -75,8 +75,7 @@ namespace doc {
|
||||
Image* originalImage() const {
|
||||
if (m_backupImage)
|
||||
return m_backupImage.get();
|
||||
else
|
||||
return m_image.get();
|
||||
return m_image.get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -53,13 +53,11 @@ namespace doc {
|
||||
if (rgba_geta(a) == 0) {
|
||||
if (rgba_geta(b) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (rgba_geta(b) == 0)
|
||||
return false;
|
||||
else
|
||||
return a == b;
|
||||
}
|
||||
if (rgba_geta(b) == 0)
|
||||
return false;
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
|
||||
@ -98,13 +96,11 @@ namespace doc {
|
||||
if (graya_geta(a) == 0) {
|
||||
if (graya_geta(b) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (graya_geta(b) == 0)
|
||||
return false;
|
||||
else
|
||||
return a == b;
|
||||
}
|
||||
if (graya_geta(b) == 0)
|
||||
return false;
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2022 Igara Studio S.A.
|
||||
// Copyright (c) 2022-2024 Igara Studio S.A.
|
||||
// Copyright (c) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -72,14 +72,12 @@ namespace doc {
|
||||
T* operator*() {
|
||||
if (m_it != m_end)
|
||||
return m_it->value();
|
||||
else
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
T* operator->() {
|
||||
if (m_it != m_end)
|
||||
return m_it->value();
|
||||
else
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
private:
|
||||
iterator m_it, m_next;
|
||||
@ -154,8 +152,7 @@ namespace doc {
|
||||
it->value() &&
|
||||
frame >= it->frame())
|
||||
return it->value();
|
||||
else
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
iterator begin() { return m_keys.begin(); }
|
||||
@ -185,15 +182,13 @@ namespace doc {
|
||||
frame_t fromFrame() const {
|
||||
if (!m_keys.empty())
|
||||
return m_keys.front().frame();
|
||||
else
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
frame_t toFrame() const {
|
||||
if (!m_keys.empty())
|
||||
return m_keys.back().frame();
|
||||
else
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Range range(const frame_t from,
|
||||
|
@ -53,7 +53,7 @@ const ObjectId Object::id() const
|
||||
// The first time the ID is request, we store the object in the
|
||||
// "objects" hash table.
|
||||
if (!m_id) {
|
||||
std::lock_guard lock(g_mutex);
|
||||
const std::lock_guard lock(g_mutex);
|
||||
m_id = ++newId;
|
||||
objects.insert(std::make_pair(m_id, const_cast<Object*>(this)));
|
||||
}
|
||||
@ -62,7 +62,7 @@ const ObjectId Object::id() const
|
||||
|
||||
void Object::setId(ObjectId id)
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
const std::lock_guard lock(g_mutex);
|
||||
|
||||
if (m_id) {
|
||||
auto it = objects.find(m_id);
|
||||
@ -101,7 +101,7 @@ void Object::setVersion(ObjectVersion version)
|
||||
|
||||
Object* get_object(ObjectId id)
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
const std::lock_guard lock(g_mutex);
|
||||
auto it = objects.find(id);
|
||||
if (it != objects.end())
|
||||
return it->second;
|
||||
|
@ -73,8 +73,7 @@ namespace doc {
|
||||
ASSERT(i >= 0);
|
||||
if (i >= 0 && i < size())
|
||||
return m_colors[i];
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
color_t getEntry(int i) const {
|
||||
return entry(i);
|
||||
|
@ -435,7 +435,8 @@ bool Playback::decrementRepeat(const frame_t frameDelta)
|
||||
PLAY_TRACE(" Repeat tag", tag->name(), " frame=", m_frame,
|
||||
"repeat=", m_playing.back()->repeat,
|
||||
"forward=", m_playing.back()->forward);
|
||||
return true;
|
||||
// Tag has only 1 frame, then don't move the playback cue.
|
||||
return tag->frames() > 1;
|
||||
}
|
||||
else {
|
||||
// Remove tag from played
|
||||
|
@ -282,6 +282,48 @@ TEST(Playback, SimplePingPong3)
|
||||
EXPECT_FALSE(play.isStopped());
|
||||
}
|
||||
|
||||
TEST(Playback, SimplePingPong4)
|
||||
{
|
||||
// A
|
||||
// <>
|
||||
// 0
|
||||
|
||||
Tag* a = make_tag("A", 0, 0, AniDir::PING_PONG, 1);
|
||||
auto sprite = make_sprite(1, { a });
|
||||
|
||||
Playback play(sprite.get(), 0, Playback::Mode::PlayAll);
|
||||
expect_frames(play, {0,0});
|
||||
EXPECT_TRUE(play.isStopped());
|
||||
}
|
||||
|
||||
TEST(Playback, SimplePingPong5)
|
||||
{
|
||||
// A
|
||||
// <>
|
||||
// 0
|
||||
|
||||
Tag* a = make_tag("A", 0, 0, AniDir::PING_PONG, 3);
|
||||
auto sprite = make_sprite(1, { a });
|
||||
|
||||
Playback play(sprite.get(), 0, Playback::Mode::PlayAll);
|
||||
expect_frames(play, {0,0,0,0});
|
||||
EXPECT_TRUE(play.isStopped());
|
||||
}
|
||||
|
||||
TEST(Playback, SimplePingPong6)
|
||||
{
|
||||
// A
|
||||
// <>
|
||||
// 0
|
||||
|
||||
Tag* a = make_tag("A", 0, 0, AniDir::PING_PONG, 0);
|
||||
auto sprite = make_sprite(1, { a });
|
||||
|
||||
Playback play(sprite.get(), 0, Playback::Mode::PlayAll);
|
||||
expect_frames(play, {0,0,0});
|
||||
EXPECT_TRUE(play.isStopped());
|
||||
}
|
||||
|
||||
TEST(Playback, SimplePingPong3Repeats)
|
||||
{
|
||||
// A
|
||||
@ -297,6 +339,7 @@ TEST(Playback, SimplePingPong3Repeats)
|
||||
EXPECT_FALSE(play.isStopped());
|
||||
}
|
||||
|
||||
|
||||
TEST(Playback, TagOneFrame)
|
||||
{
|
||||
// A
|
||||
|
@ -54,8 +54,7 @@ namespace doc {
|
||||
//ASSERT(index >= 0 && index < size());
|
||||
if (index >= 0 && index < size())
|
||||
return m_map[index];
|
||||
else
|
||||
return index; // No remap
|
||||
return index; // No remap
|
||||
}
|
||||
|
||||
void merge(const Remap& other);
|
||||
|
@ -9,7 +9,6 @@
|
||||
#define DOC_TAG_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "doc/anidir.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/object.h"
|
||||
|
@ -84,8 +84,7 @@ namespace doc {
|
||||
ImageRef get(const tile_index ti) const {
|
||||
if (ti >= 0 && ti < size())
|
||||
return m_tiles[ti].image;
|
||||
else
|
||||
return ImageRef(nullptr);
|
||||
return ImageRef(nullptr);
|
||||
}
|
||||
void set(const tile_index ti,
|
||||
const ImageRef& image);
|
||||
@ -93,8 +92,7 @@ namespace doc {
|
||||
UserData& getTileData(const tile_index ti) const {
|
||||
if (ti >= 0 && ti < size())
|
||||
return const_cast<UserData&>(m_tiles[ti].data);
|
||||
else
|
||||
return kNoUserData;
|
||||
return kNoUserData;
|
||||
}
|
||||
void setTileData(const tile_index ti,
|
||||
const UserData& userData);
|
||||
|
@ -38,8 +38,7 @@ namespace doc {
|
||||
Tileset* get(const tileset_index tsi) const {
|
||||
if (tsi < size())
|
||||
return m_tilesets[tsi];
|
||||
else
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
tileset_index getIndex(const Tileset *tileset) {
|
||||
|
@ -52,17 +52,13 @@ namespace fixmath {
|
||||
errno = ERANGE;
|
||||
return -0x7FFFFFFF;
|
||||
}
|
||||
else
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
if ((x > 0) && (y > 0)) {
|
||||
errno = ERANGE;
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
else
|
||||
return result;
|
||||
if ((x > 0) && (y > 0)) {
|
||||
errno = ERANGE;
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline fixed fixsub(fixed x, fixed y) {
|
||||
@ -73,17 +69,13 @@ namespace fixmath {
|
||||
errno = ERANGE;
|
||||
return -0x7FFFFFFF;
|
||||
}
|
||||
else
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
if ((x > 0) && (y < 0)) {
|
||||
errno = ERANGE;
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
else
|
||||
return result;
|
||||
if ((x > 0) && (y < 0)) {
|
||||
errno = ERANGE;
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline fixed fixmul(fixed x, fixed y) {
|
||||
@ -95,16 +87,14 @@ namespace fixmath {
|
||||
errno = ERANGE;
|
||||
return (x < 0) ? -0x7FFFFFFF : 0x7FFFFFFF;
|
||||
}
|
||||
else
|
||||
return ftofix(fixtof(x) / fixtof(y));
|
||||
return ftofix(fixtof(x) / fixtof(y));
|
||||
}
|
||||
|
||||
inline int fixfloor(fixed x) {
|
||||
/* (x >> 16) is not portable */
|
||||
if (x >= 0)
|
||||
return (x >> 16);
|
||||
else
|
||||
return ~((~x) >> 16);
|
||||
return ~((~x) >> 16);
|
||||
}
|
||||
|
||||
inline int fixceil(fixed x) {
|
||||
|
@ -21,12 +21,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "Comments", "https://www.aseprite.org/"
|
||||
VALUE "CompanyName", "Igara Studio S.A."
|
||||
VALUE "FileDescription", "Aseprite - Animated sprites editor & pixel art tool"
|
||||
VALUE "FileDescription", "Aseprite"
|
||||
VALUE "FileVersion", "1,3,0,0"
|
||||
VALUE "InternalName", "aseprite"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2001-2024 Igara Studio S.A."
|
||||
VALUE "OriginalFilename", "aseprite.exe"
|
||||
VALUE "ProductName", "ASEPRITE"
|
||||
VALUE "ProductName", "Aseprite"
|
||||
VALUE "ProductVersion", "1,3,0,0"
|
||||
END
|
||||
END
|
||||
|
@ -72,10 +72,9 @@ namespace render {
|
||||
|
||||
if (n == 2)
|
||||
return D2[i*2 + j];
|
||||
else
|
||||
return
|
||||
+ 4*Dn(i%(n/2), j%(n/2), n/2)
|
||||
+ Dn(i/(n/2), j/(n/2), 2);
|
||||
return
|
||||
+ 4*Dn(i%(n/2), j%(n/2), n/2)
|
||||
+ Dn(i/(n/2), j/(n/2), 2);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -76,16 +76,14 @@ namespace render {
|
||||
inline int Zoom::remove(int x) const {
|
||||
if (x < 0)
|
||||
return (x * m_den / m_num) - 1;
|
||||
else
|
||||
return (x * m_den / m_num);
|
||||
return (x * m_den / m_num);
|
||||
}
|
||||
|
||||
inline int Zoom::removeCeiling(int x) const {
|
||||
int v = x * m_den;
|
||||
if (x < 0)
|
||||
return (v / m_num);
|
||||
else
|
||||
return (v / m_num) + (v % m_num != 0);
|
||||
return (v / m_num) + (v % m_num != 0);
|
||||
}
|
||||
|
||||
inline gfx::Rect Zoom::apply(const gfx::Rect& r) const {
|
||||
|
@ -134,7 +134,7 @@ public:
|
||||
unloadLib();
|
||||
}
|
||||
|
||||
bool initialized() const {
|
||||
bool isInitialized() const {
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
@ -239,7 +239,7 @@ SteamAPI* SteamAPI::instance()
|
||||
}
|
||||
|
||||
SteamAPI::SteamAPI()
|
||||
: m_impl(new Impl)
|
||||
: m_impl(std::make_unique<Impl>())
|
||||
{
|
||||
ASSERT(g_instance == nullptr);
|
||||
g_instance = this;
|
||||
@ -247,15 +247,13 @@ SteamAPI::SteamAPI()
|
||||
|
||||
SteamAPI::~SteamAPI()
|
||||
{
|
||||
delete m_impl;
|
||||
|
||||
ASSERT(g_instance == this);
|
||||
g_instance = nullptr;
|
||||
}
|
||||
|
||||
bool SteamAPI::initialized() const
|
||||
bool SteamAPI::isInitialized() const
|
||||
{
|
||||
return m_impl->initialized();
|
||||
return m_impl->isInitialized();
|
||||
}
|
||||
|
||||
void SteamAPI::runCallbacks()
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Steam Wrapper
|
||||
// Copyright (c) 2020 Igara Studio S.A.
|
||||
// Copyright (c) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (c) 2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -9,6 +9,8 @@
|
||||
#define STEAM_STEAM_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace steam {
|
||||
|
||||
class SteamAPI {
|
||||
@ -18,7 +20,7 @@ public:
|
||||
SteamAPI();
|
||||
~SteamAPI();
|
||||
|
||||
bool initialized() const;
|
||||
bool isInitialized() const;
|
||||
void runCallbacks();
|
||||
|
||||
bool writeScreenshot(void* rgbBuffer,
|
||||
@ -27,7 +29,7 @@ public:
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
Impl* m_impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace steam
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -125,6 +125,9 @@ Grid::Info Grid::getChildInfo(Widget* child)
|
||||
|
||||
void Grid::setStyle(Style* style)
|
||||
{
|
||||
ASSERT(style);
|
||||
if (!style)
|
||||
style = Theme::getDefaultStyle();
|
||||
Widget::setStyle(style);
|
||||
setGap(style->gap());
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define UI_PAINT_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "gfx/color.h"
|
||||
#include "os/paint.h"
|
||||
|
||||
|
@ -142,6 +142,9 @@ Theme::~Theme()
|
||||
set_theme(nullptr, guiscale());
|
||||
}
|
||||
|
||||
// static
|
||||
ui::Style Theme::m_defaultStyle(nullptr);
|
||||
|
||||
void Theme::regenerateTheme()
|
||||
{
|
||||
set_mouse_cursor(kNoCursor);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -141,6 +141,8 @@ namespace ui {
|
||||
static void drawTextBox(Graphics* g, const Widget* textbox,
|
||||
int* w, int* h, gfx::Color bg, gfx::Color fg);
|
||||
|
||||
static ui::Style* getDefaultStyle() { return &m_defaultStyle; }
|
||||
|
||||
protected:
|
||||
virtual void onRegenerateTheme() = 0;
|
||||
|
||||
@ -165,6 +167,8 @@ namespace ui {
|
||||
gfx::Size& sizeHint,
|
||||
gfx::Border& borderHint,
|
||||
gfx::Rect& textHint, int& textAlign);
|
||||
|
||||
static ui::Style m_defaultStyle;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
@ -199,7 +199,9 @@ void Widget::setTheme(Theme* theme)
|
||||
void Widget::setStyle(Style* style)
|
||||
{
|
||||
assert_ui_thread();
|
||||
|
||||
ASSERT(style);
|
||||
if (!style)
|
||||
style = Theme::getDefaultStyle();
|
||||
m_style = style;
|
||||
m_border = m_theme->calcBorder(this, style);
|
||||
m_bgColor = m_theme->calcBgColor(this, style);
|
||||
|
@ -142,8 +142,7 @@ namespace ui {
|
||||
gfx::Color bgColor() const {
|
||||
if (gfx::geta(m_bgColor) == 0 && m_parent)
|
||||
return m_parent->bgColor();
|
||||
else
|
||||
return m_bgColor;
|
||||
return m_bgColor;
|
||||
}
|
||||
|
||||
// Sets the background color of the widget
|
||||
|
@ -8,9 +8,7 @@
|
||||
#define UPDATER_USER_AGENT_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
namespace updater {
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
-- Copyright (C) 2023 Igara Studio S.A.
|
||||
-- Copyright (C) 2023-2024 Igara Studio S.A.
|
||||
--
|
||||
-- This file is released under the terms of the MIT license.
|
||||
-- Read LICENSE.txt for more information.
|
||||
@ -8,7 +8,11 @@
|
||||
--
|
||||
dofile('./test_utils.lua')
|
||||
|
||||
do
|
||||
-- You can use this code to fill file-tests-props.aseprite properties,
|
||||
-- but we did this just one time in the past, now we want to check
|
||||
-- that we can read the properties correctly from the file, e.g. to
|
||||
-- check the correct endianness of the platform.
|
||||
if false then
|
||||
local spr = Sprite{ fromFile="sprites/file-tests-props.aseprite" }
|
||||
|
||||
-- Set sprite custom properties
|
||||
@ -16,6 +20,7 @@ do
|
||||
spr.properties.b = 1
|
||||
spr.properties.c = "hi"
|
||||
spr.properties.d = 2.3
|
||||
spr.properties.e = 8.123456e-12
|
||||
spr.properties("ext").a = {"one", "two", "three"}
|
||||
-- Set layer custom properties
|
||||
spr.layers[2].properties.a = "i'm the layer 3"
|
||||
@ -24,11 +29,11 @@ do
|
||||
spr.layers[1].tileset.properties.a = "i'm a tilemap"
|
||||
spr.layers[1].tileset.properties.b = 11
|
||||
spr.layers[1].tileset.properties("ext").a = "text from extension"
|
||||
-- Create some tiles with properties
|
||||
local tile = spr:newTile(spr.layers[1].tileset, 1)
|
||||
-- Set tiles custom properties
|
||||
local tile = spr.layers[1].tileset:tile(1)
|
||||
tile.properties.a = 320
|
||||
tile.properties.b = 330
|
||||
tile = spr:newTile(spr.layers[1].tileset, 2)
|
||||
tile = spr.layers[1].tileset:tile(2)
|
||||
tile.properties.a = 640
|
||||
tile.properties.b = 650
|
||||
-- Set tags custom properties
|
||||
@ -42,19 +47,25 @@ do
|
||||
spr.slices[1].properties = {a=Point(3,4), b=Size(10,20)}
|
||||
spr.slices[1].properties("ext", {a=Rectangle(10,20,30,40)})
|
||||
|
||||
spr:saveAs("sprites/file-tests-props.aseprite")
|
||||
spr:close()
|
||||
end
|
||||
|
||||
do
|
||||
-- Test load/save file (and keep the properties intact)
|
||||
local spr = Sprite{ fromFile="sprites/file-tests-props.aseprite" }
|
||||
assert(#spr.properties == 5)
|
||||
spr:saveAs("_test_userdata_codec_1.aseprite")
|
||||
spr:close()
|
||||
|
||||
local origSpr = Sprite{ fromFile="sprites/file-tests-props.aseprite" }
|
||||
spr = Sprite{ fromFile="_test_userdata_codec_1.aseprite" }
|
||||
assert_sprites_eq(origSpr, spr)
|
||||
origSpr:close()
|
||||
assert(#spr.properties == 4)
|
||||
local spr = Sprite{ fromFile="_test_userdata_codec_1.aseprite" }
|
||||
assert(#spr.properties == 5)
|
||||
assert(#spr.properties("ext") == 1)
|
||||
assert(spr.properties.a == true)
|
||||
assert(spr.properties.b == 1)
|
||||
assert(spr.properties.c == "hi")
|
||||
assert(spr.properties.d == 2.3)
|
||||
assert(spr.properties.e == 8.123456e-12)
|
||||
assert(spr.properties("ext").a[1] == "one")
|
||||
assert(spr.properties("ext").a[2] == "two")
|
||||
assert(spr.properties("ext").a[3] == "three")
|
||||
|
@ -28,10 +28,11 @@
|
||||
* `4f-index-4x4.aseprite`: Indexed, 4 frames, 1 layer, mask color set
|
||||
to index 0.
|
||||
* `file-tests-props.aseprite`: Indexed, 64x64, 6 frames, 4 layers (one
|
||||
of them is a tilemap), 13 cels, 1 tag.
|
||||
of them is a tilemap), 13 cels, 1 tag, pre-defined user data
|
||||
properties of all kinds in several sprite elements.
|
||||
* `slices.aseprite`: Indexed, 4x4, background layer, 2 slices.
|
||||
* `slices-moving.aseprite`: Indexed, 4x4, 1 linked cel in 4 frames,
|
||||
background layer, 1 slice with 4 keyframes (each keyframe with a
|
||||
different position/size).
|
||||
* `2x2tilemap2x2tile.aseprite`: RGB, 6x6, 2x2 tilemap layer, 5 tiles tileset,
|
||||
2x2 tile size, 1 frame.
|
||||
2x2 tile size, 1 frame.
|
||||
|
Binary file not shown.
2
third_party/json11
vendored
2
third_party/json11
vendored
@ -1 +1 @@
|
||||
Subproject commit e5868fff1fc5128077ed7699bdaa20ae47c47eca
|
||||
Subproject commit 92ba6ce0fa1f1c8fd8783b6930b52539b3861888
|
Loading…
x
Reference in New Issue
Block a user