mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-29 19:20:09 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
ddafa5083e
@ -1142,6 +1142,7 @@ octree = Octree
|
||||
title = Notice
|
||||
description = Do you want to load the following files as an animation?
|
||||
repeat = Do the same for other files
|
||||
duration = Duration
|
||||
agree = &Agree
|
||||
skip = &Skip
|
||||
|
||||
|
@ -8,6 +8,10 @@
|
||||
<view expansive="true" id="view" minwidth="128" minheight="64">
|
||||
<listbox id="files" multiselect="true" />
|
||||
</view>
|
||||
<hbox>
|
||||
<label text="@.duration" />
|
||||
<expr text="0" id="duration" suffix="ms" />
|
||||
</hbox>
|
||||
<separator horizontal="true" />
|
||||
<check id="repeat" text="@.repeat" />
|
||||
<check id="dont_show" text="@general.dont_show" />
|
||||
|
@ -874,32 +874,36 @@ static void read_rle4_compressed_image(FILE *f, Image *image, const BITMAPINFOHE
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t calc_shift(const uint32_t channelMask, int& channelBits)
|
||||
{
|
||||
uint32_t channelShift = 0;
|
||||
uint32_t mask = 0;
|
||||
if (channelMask) {
|
||||
mask = ~channelMask;
|
||||
while (mask & 1) {
|
||||
++channelShift;
|
||||
mask >>= 1;
|
||||
}
|
||||
if (mask) {
|
||||
mask = ~mask;
|
||||
while (mask & 1) {
|
||||
channelBits++;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
channelBits = 32 - channelShift;
|
||||
}
|
||||
else
|
||||
channelBits = 8;
|
||||
return channelShift;
|
||||
}
|
||||
|
||||
static int read_bitfields_image(FILE *f, Image *image, BITMAPINFOHEADER *infoheader,
|
||||
uint32_t rmask, uint32_t gmask, uint32_t bmask,
|
||||
uint32_t amask, bool& withAlpha)
|
||||
{
|
||||
#define CALC_SHIFT(c) \
|
||||
c##shift = 0; \
|
||||
if (c##mask) { \
|
||||
mask = ~c##mask; \
|
||||
while (mask & 1) { \
|
||||
++c##shift; \
|
||||
mask >>= 1; \
|
||||
} \
|
||||
if (mask) { \
|
||||
mask = ~mask; \
|
||||
while (mask & 1) { \
|
||||
c##bits++; \
|
||||
mask >>= 1; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
c##bits = 32 - c##shift; \
|
||||
} \
|
||||
else \
|
||||
c##bits = 8; \
|
||||
|
||||
uint32_t buffer, mask, rshift, gshift, bshift, ashift;
|
||||
uint32_t buffer, rshift, gshift, bshift, ashift;
|
||||
int rbits = 0, gbits = 0, bbits = 0, abits = 0;
|
||||
int i, j, k, line, height, dir, r, g, b, a;
|
||||
int bits_per_pixel;
|
||||
@ -911,10 +915,10 @@ static int read_bitfields_image(FILE *f, Image *image, BITMAPINFOHEADER *infohea
|
||||
height = ABS(height);
|
||||
|
||||
/* calculate shifts */
|
||||
CALC_SHIFT(r);
|
||||
CALC_SHIFT(g);
|
||||
CALC_SHIFT(b);
|
||||
CALC_SHIFT(a);
|
||||
rshift = calc_shift(rmask, rbits);
|
||||
gshift = calc_shift(gmask, gbits);
|
||||
bshift = calc_shift(bmask, bbits);
|
||||
ashift = calc_shift(amask, abits);
|
||||
|
||||
/* calculate bits-per-pixel and bytes-per-pixel */
|
||||
bits_per_pixel = infoheader->biBitCount;
|
||||
|
@ -388,6 +388,18 @@ FileOp* FileOp::createLoadDocumentOperation(Context* context,
|
||||
window.files()->getSelectedChild() != nullptr);
|
||||
});
|
||||
|
||||
window.duration()->setTextf("%d", fop->m_seq.duration);
|
||||
window.duration()->Change.connect(
|
||||
[&]() {
|
||||
fop->m_seq.duration = window.duration()->textInt();
|
||||
// If the animation duration is changed we'll prefer to
|
||||
// agree on loading the sequence if the user press Enter.
|
||||
//
|
||||
// TODO maybe the "Agree" button should be the default
|
||||
// focus magnet in this dialog
|
||||
window.agree()->setFocusMagnet(true);
|
||||
});
|
||||
|
||||
window.openWindowInForeground();
|
||||
|
||||
// Don't show this alert again.
|
||||
@ -836,6 +848,8 @@ void FileOp::operate(IFileOpProgress* progress)
|
||||
#endif
|
||||
}
|
||||
|
||||
m_document->sprite()->setFrameDuration(frame, m_seq.duration);
|
||||
|
||||
++frame;
|
||||
m_seq.progress_offset += m_seq.progress_fraction;
|
||||
}
|
||||
@ -1422,6 +1436,7 @@ FileOp::FileOp(FileOpType type,
|
||||
m_seq.frame = frame_t(0);
|
||||
m_seq.layer = nullptr;
|
||||
m_seq.last_cel = nullptr;
|
||||
m_seq.duration = 100;
|
||||
m_seq.flags = 0;
|
||||
}
|
||||
|
||||
|
@ -314,6 +314,7 @@ namespace app {
|
||||
bool has_alpha;
|
||||
LayerImage* layer;
|
||||
Cel* last_cel;
|
||||
int duration;
|
||||
// Flags after the user choose what to do with the sequence.
|
||||
int flags;
|
||||
} m_seq;
|
||||
|
@ -10,6 +10,6 @@
|
||||
|
||||
// Increment this value if the scripting API is modified between two
|
||||
// released Aseprite versions.
|
||||
#define API_VERSION 19
|
||||
#define API_VERSION 20
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -11,14 +11,18 @@
|
||||
#include "app/app.h"
|
||||
#include "app/context.h"
|
||||
#include "app/doc_range.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/script/docobj.h"
|
||||
#include "app/script/engine.h"
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/site.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/util/range_utils.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/object_ids.h"
|
||||
#include "doc/slice.h"
|
||||
#include "doc/slices.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "doc/tile.h"
|
||||
|
||||
@ -33,9 +37,10 @@ namespace {
|
||||
struct RangeObj { // This is like DocRange but referencing objects with IDs
|
||||
DocRange::Type type;
|
||||
ObjectId spriteId;
|
||||
std::set<ObjectId> layers;
|
||||
doc::SelectedObjects layers;
|
||||
std::vector<frame_t> frames;
|
||||
std::set<ObjectId> cels;
|
||||
doc::SelectedObjects cels;
|
||||
doc::SelectedObjects slices;
|
||||
std::vector<color_t> colors;
|
||||
std::vector<tile_index> tiles;
|
||||
|
||||
@ -88,18 +93,23 @@ struct RangeObj { // This is like DocRange but referencing objects with IDs
|
||||
|
||||
if (site.selectedTiles().picks() > 0)
|
||||
tiles = site.selectedTiles().toVectorOfIndexes();
|
||||
|
||||
slices = site.selectedSlices();
|
||||
}
|
||||
|
||||
Sprite* sprite(lua_State* L) { return check_docobj(L, doc::get<Sprite>(spriteId)); }
|
||||
|
||||
bool contains(const Layer* layer) const {
|
||||
return layers.find(layer->id()) != layers.end();
|
||||
return layers.contains(layer->id());
|
||||
}
|
||||
bool contains(const frame_t frame) const {
|
||||
return std::find(frames.begin(), frames.end(), frame) != frames.end();
|
||||
}
|
||||
bool contains(const Cel* cel) const {
|
||||
return cels.find(cel->id()) != cels.end();
|
||||
return cels.contains(cel->id());
|
||||
}
|
||||
bool contains(const Slice* slice) const {
|
||||
return slices.contains(slice->id());
|
||||
}
|
||||
bool containsColor(const color_t color) const {
|
||||
return (std::find(colors.begin(), colors.end(), color) != colors.end());
|
||||
@ -139,6 +149,9 @@ int Range_contains(lua_State* L)
|
||||
else if (Cel* cel = may_get_docobj<Cel>(L, 2)) {
|
||||
result = obj->contains(cel);
|
||||
}
|
||||
else if (Slice* slice = may_get_docobj<Slice>(L, 2)) {
|
||||
result = obj->contains(slice);
|
||||
}
|
||||
else {
|
||||
frame_t frame = get_frame_number_from_arg(L, 2);
|
||||
result = obj->contains(frame);
|
||||
@ -176,6 +189,13 @@ int Range_clear(lua_State* L)
|
||||
doc::PalettePicks picks;
|
||||
ctx->setSelectedColors(picks);
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
// Empty selected slices in the current editor
|
||||
// TODO add a new function to Context class for this
|
||||
if (current_editor)
|
||||
current_editor->clearSlicesSelection();
|
||||
#endif
|
||||
|
||||
obj->updateFromSite(ctx->activeSite());
|
||||
return 0;
|
||||
}
|
||||
@ -275,6 +295,18 @@ int Range_get_tiles(lua_State* L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Range_get_slices(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<RangeObj>(L, 1);
|
||||
lua_newtable(L);
|
||||
int j = 1;
|
||||
for (auto sliceId : obj->slices) {
|
||||
push_docobj<Slice>(L, sliceId);
|
||||
lua_rawseti(L, -2, j++);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Range_set_layers(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<RangeObj>(L, 1);
|
||||
@ -355,6 +387,29 @@ int Range_set_tiles(lua_State* L)
|
||||
}
|
||||
}
|
||||
ctx->setSelectedTiles(picks);
|
||||
obj->updateFromSite(ctx->activeSite());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Range_set_slices(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<RangeObj>(L, 1);
|
||||
app::Context* ctx = App::instance()->context();
|
||||
|
||||
// TODO we should add support to CLI scripts
|
||||
#ifdef ENABLE_UI
|
||||
if (current_editor) {
|
||||
current_editor->clearSlicesSelection();
|
||||
const int len = luaL_len(L, 2);
|
||||
for (int i = 1; i <= len; i++) {
|
||||
if (lua_geti(L, 2, i) != LUA_TNIL)
|
||||
current_editor->selectSlice(get_docobj<Slice>(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
obj->updateFromSite(ctx->activeSite());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -378,6 +433,7 @@ const Property Range_properties[] = {
|
||||
{ "editableImages", Range_get_editableImages, nullptr },
|
||||
{ "colors", Range_get_colors, Range_set_colors },
|
||||
{ "tiles", Range_get_tiles, Range_set_tiles },
|
||||
{ "slices", Range_get_slices, Range_set_slices },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user