mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-10 03:44:16 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
1f4e3bcd11
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -65,6 +65,7 @@ public:
|
||||
private:
|
||||
|
||||
void onChange() {
|
||||
stopPreview();
|
||||
m_filter.setBrightness(m_brightness.getValue() / 100.0);
|
||||
m_filter.setContrast(m_contrast.getValue() / 100.0);
|
||||
restartPreview();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -55,6 +55,8 @@ public:
|
||||
protected:
|
||||
|
||||
void onCurveChange() {
|
||||
stopPreview();
|
||||
|
||||
// The color curve in the filter is the same refereced by the
|
||||
// editor. But anyway, we have to re-set the same curve in the
|
||||
// filter to regenerate the map used internally by the filter
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -136,6 +136,8 @@ private:
|
||||
std::shared_ptr<ConvolutionMatrix> matrix = m_stock.getByName(selected->text().c_str());
|
||||
Target newTarget = matrix->getDefaultTarget();
|
||||
|
||||
stopPreview();
|
||||
|
||||
m_filter.setMatrix(matrix);
|
||||
|
||||
setNewTarget(newTarget);
|
||||
|
@ -81,6 +81,12 @@ private:
|
||||
newSize.w = base::clamp(newSize.w, 1, 100);
|
||||
newSize.h = base::clamp(newSize.h, 1, 100);
|
||||
|
||||
// If we had a previous filter preview running in the background,
|
||||
// we explicitly request it be stopped. Otherwise, changing the
|
||||
// size of the filter would cause a race condition on
|
||||
// MedianFilter::m_channel field.
|
||||
stopPreview();
|
||||
|
||||
m_filter.setSize(newSize.w, newSize.h);
|
||||
restartPreview();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -95,6 +95,8 @@ private:
|
||||
}
|
||||
|
||||
void onChangeMode() {
|
||||
stopPreview();
|
||||
|
||||
Preferences::instance().hueSaturation.mode(mode());
|
||||
m_filter.setMode(mode());
|
||||
m_sliders.setColorType(isHsl() ?
|
||||
@ -105,6 +107,8 @@ private:
|
||||
}
|
||||
|
||||
void onChangeControls() {
|
||||
stopPreview();
|
||||
|
||||
m_sliders.syncRelHsvHslSliders();
|
||||
|
||||
if (isHsl()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -137,21 +137,26 @@ private:
|
||||
}
|
||||
|
||||
void onColorChange(const app::Color& color) {
|
||||
stopPreview();
|
||||
m_filter.color(color);
|
||||
restartPreview();
|
||||
}
|
||||
|
||||
void onBgColorChange(const app::Color& color) {
|
||||
stopPreview();
|
||||
m_filter.bgColor(color);
|
||||
restartPreview();
|
||||
}
|
||||
|
||||
void onPlaceChange(OutlineFilter::Place place) {
|
||||
stopPreview();
|
||||
m_filter.place(place);
|
||||
restartPreview();
|
||||
}
|
||||
|
||||
void onMatrixTypeChange() {
|
||||
stopPreview();
|
||||
|
||||
OutlineFilter::Matrix matrix = OutlineFilter::Matrix::None;
|
||||
switch (m_panel.outlineType()->selectedItem()) {
|
||||
case CIRCLE: matrix = OutlineFilter::Matrix::Circle; break;
|
||||
@ -165,6 +170,8 @@ private:
|
||||
}
|
||||
|
||||
void onMatrixPixelChange(const int index) {
|
||||
stopPreview();
|
||||
|
||||
int matrix = (int)m_filter.matrix();
|
||||
matrix ^= (1 << (8-index));
|
||||
m_filter.matrix((OutlineFilter::Matrix)matrix);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -101,16 +101,19 @@ public:
|
||||
private:
|
||||
|
||||
void onFromChange(const app::Color& color) {
|
||||
stopPreview();
|
||||
m_filter.setFrom(color);
|
||||
restartPreview();
|
||||
}
|
||||
|
||||
void onToChange(const app::Color& color) {
|
||||
stopPreview();
|
||||
m_filter.setTo(color);
|
||||
restartPreview();
|
||||
}
|
||||
|
||||
void onToleranceChange() {
|
||||
stopPreview();
|
||||
m_filter.setTolerance(m_toleranceSlider->getValue());
|
||||
restartPreview();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -40,7 +41,7 @@ namespace app {
|
||||
bool doModal();
|
||||
|
||||
// Starts (or restart) the preview procedure. You should call this
|
||||
// method each time the user modifies parameters of the Filter.
|
||||
// method after the user modifies parameters of the Filter.
|
||||
void restartPreview();
|
||||
|
||||
protected:
|
||||
@ -61,9 +62,11 @@ namespace app {
|
||||
// mode overriding this method.
|
||||
virtual void setupTiledMode(TiledMode tiledMode) { }
|
||||
|
||||
private:
|
||||
// Stops the filter preview background thread, you should call
|
||||
// this before you modify the parameters of the Filter.
|
||||
void stopPreview();
|
||||
|
||||
private:
|
||||
const char* m_cfgSection;
|
||||
FilterManagerImpl* m_filterMgr;
|
||||
ui::Box m_hbox;
|
||||
|
@ -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.
|
||||
@ -10,6 +10,6 @@
|
||||
|
||||
// Increment this value if the scripting API is modified between two
|
||||
// released Aseprite versions.
|
||||
#define API_VERSION 16
|
||||
#define API_VERSION 17
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -138,7 +138,8 @@ app::Color Color_new(lua_State* L, int index)
|
||||
|
||||
// Convert { index } into a Color
|
||||
if (lua_getfield(L, index, "index") != LUA_TNIL) {
|
||||
color = app::Color::fromIndex(lua_tonumber(L, -1));
|
||||
int i = lua_tointeger(L, -1);
|
||||
color = app::Color::fromIndex(i);
|
||||
lua_pop(L, 1);
|
||||
return color;
|
||||
}
|
||||
@ -296,7 +297,7 @@ int Color_get_gray(lua_State* L)
|
||||
int Color_get_index(lua_State* L)
|
||||
{
|
||||
auto color = get_obj<app::Color>(L, 1);
|
||||
lua_pushnumber(L, color->getIndex());
|
||||
lua_pushinteger(L, color->getIndex());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -376,6 +376,8 @@ int Sprite_deleteLayer(lua_State* L)
|
||||
}
|
||||
}
|
||||
if (layer) {
|
||||
if (sprite != layer->sprite())
|
||||
return luaL_error(L, "the layer doesn't belong to the sprite");
|
||||
Tx tx;
|
||||
tx(new cmd::RemoveLayer(layer));
|
||||
tx.commit();
|
||||
@ -502,11 +504,11 @@ int Sprite_newCel(lua_State* L)
|
||||
int Sprite_deleteCel(lua_State* L)
|
||||
{
|
||||
auto sprite = get_docobj<Sprite>(L, 1);
|
||||
(void)sprite; // unused
|
||||
|
||||
auto cel = may_get_docobj<doc::Cel>(L, 2);
|
||||
if (!cel) {
|
||||
if (auto layer = may_get_docobj<doc::Layer>(L, 2)) {
|
||||
if (sprite != layer->sprite())
|
||||
return luaL_error(L, "the layer doesn't belong to the sprite");
|
||||
doc::frame_t frame = get_frame_number_from_arg(L, 3);
|
||||
if (layer->isImage())
|
||||
cel = static_cast<doc::LayerImage*>(layer)->cel(frame);
|
||||
@ -549,6 +551,8 @@ int Sprite_deleteTag(lua_State* L)
|
||||
tag = sprite->tags().getByName(tagName);
|
||||
}
|
||||
if (tag) {
|
||||
if (sprite != tag->owner()->sprite())
|
||||
return luaL_error(L, "the tag doesn't belong to the sprite");
|
||||
Tx tx;
|
||||
tx(new cmd::RemoveTag(sprite, tag));
|
||||
tx.commit();
|
||||
@ -583,6 +587,8 @@ int Sprite_deleteSlice(lua_State* L)
|
||||
slice = sprite->slices().getByName(sliceName);
|
||||
}
|
||||
if (slice) {
|
||||
if (sprite != slice->owner()->sprite())
|
||||
return luaL_error(L, "the slice doesn't belong to the sprite");
|
||||
Tx tx;
|
||||
tx(new cmd::RemoveSlice(sprite, slice));
|
||||
tx.commit();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -160,10 +160,12 @@ bool ColorShades::onProcessMessage(ui::Message* msg)
|
||||
break;
|
||||
|
||||
case ui::kMouseUpMessage: {
|
||||
auto button = static_cast<ui::MouseMessage*>(msg)->button();
|
||||
|
||||
if (m_click == ClickWholeShade) {
|
||||
setSelected(true);
|
||||
|
||||
ClickEvent ev(static_cast<ui::MouseMessage*>(msg)->button());
|
||||
ClickEvent ev(button);
|
||||
Click(ev);
|
||||
|
||||
closeWindow();
|
||||
@ -180,9 +182,18 @@ bool ColorShades::onProcessMessage(ui::Message* msg)
|
||||
m_dragIndex = -1;
|
||||
invalidate();
|
||||
|
||||
ClickEvent ev(button);
|
||||
Click(ev);
|
||||
|
||||
// Relayout the context bar if we have removed an entry.
|
||||
if (m_hotIndex < 0)
|
||||
//
|
||||
// TODO it looks like this should be handled in some kind of
|
||||
// Change() event in the ColorBar
|
||||
if (m_hotIndex < 0 &&
|
||||
parent() &&
|
||||
parent()->parent()) {
|
||||
parent()->parent()->layout();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasCapture())
|
||||
|
@ -60,6 +60,12 @@ void DelayedMouseMove::onMouseUp(const ui::MouseMessage* msg)
|
||||
commitMouseMove();
|
||||
}
|
||||
|
||||
void DelayedMouseMove::stopTimer()
|
||||
{
|
||||
if (m_timer.isRunning())
|
||||
m_timer.stop();
|
||||
}
|
||||
|
||||
void DelayedMouseMove::commitMouseMove()
|
||||
{
|
||||
if (m_timer.isRunning())
|
||||
|
@ -50,6 +50,11 @@ namespace app {
|
||||
bool onMouseMove(const ui::MouseMessage* msg);
|
||||
void onMouseUp(const ui::MouseMessage* msg);
|
||||
|
||||
// Forces stopping the timer so we don't receive a Tick event in
|
||||
// case that we've just removed/delete some structure that is
|
||||
// needed in onCommitMouseMove().
|
||||
void stopTimer();
|
||||
|
||||
const gfx::PointF& spritePos() const;
|
||||
|
||||
private:
|
||||
|
@ -400,6 +400,11 @@ bool MovingPixelsState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
void MovingPixelsState::onCommitMouseMove(Editor* editor,
|
||||
const gfx::PointF& spritePos)
|
||||
{
|
||||
ASSERT(m_pixelsMovement);
|
||||
|
||||
if (!m_pixelsMovement->isDragging())
|
||||
return;
|
||||
|
||||
m_pixelsMovement->setFastMode(true);
|
||||
|
||||
// Get the customization for the pixels movement (snap to grid, angle snap, etc.).
|
||||
@ -857,6 +862,10 @@ void MovingPixelsState::removeAsEditorObserver()
|
||||
|
||||
void MovingPixelsState::removePixelsMovement()
|
||||
{
|
||||
// Avoid receiving a onCommitMouseMove() message when
|
||||
// m_pixelsMovement is already nullptr.
|
||||
m_delayedMouseMove.stopTimer();
|
||||
|
||||
m_pixelsMovement.reset();
|
||||
m_ctxConn.disconnect();
|
||||
m_opaqueConn.disconnect();
|
||||
|
@ -375,13 +375,22 @@ void MainWindow::onResize(ui::ResizeEvent& ev)
|
||||
{
|
||||
app::gen::MainWindow::onResize(ev);
|
||||
|
||||
ui::Display* display = this->display();
|
||||
if ((display) &&
|
||||
(display->scale()*ui::guiscale() > 2) &&
|
||||
(!m_scalePanic) &&
|
||||
(display->size().w / ui::guiscale() < 320 ||
|
||||
display->size().h / ui::guiscale() < 260)) {
|
||||
showNotification(m_scalePanic = new ScreenScalePanic);
|
||||
os::Window* nativeWindow = (display() ? display()->nativeWindow(): nullptr);
|
||||
if (nativeWindow && nativeWindow->screen()) {
|
||||
const int scale = nativeWindow->scale()*ui::guiscale();
|
||||
|
||||
// We can check for the available workarea to know that the user
|
||||
// can resize the window to its full size and there will be enough
|
||||
// room to display some common dialogs like (for example) the
|
||||
// Preferences dialog.
|
||||
if ((scale > 2) &&
|
||||
(!m_scalePanic)) {
|
||||
const gfx::Size wa = nativeWindow->screen()->workarea().size();
|
||||
if ((wa.w / scale < 256 ||
|
||||
wa.h / scale < 256)) {
|
||||
showNotification(m_scalePanic = new ScreenScalePanic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,18 +144,19 @@ void render_rgba_radial_gradient(
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is no vector defining the gradient (just one point),
|
||||
// the "gradient" will be just "c0"
|
||||
if (p0 == p1) {
|
||||
img->clear(c0);
|
||||
return;
|
||||
}
|
||||
|
||||
base::Vector2d<double>
|
||||
u(p0.x, p0.y),
|
||||
v(p1.x, p1.y), w;
|
||||
w = (v - u) / 2;
|
||||
|
||||
// If there is no vector defining the gradient (just one point),
|
||||
// the "gradient" will be just a solid color ("c1")
|
||||
if (std::fabs(w.x) <= 0.000001 ||
|
||||
std::fabs(w.y) <= 0.000001) {
|
||||
img->clear(c1);
|
||||
return;
|
||||
}
|
||||
|
||||
// As we use non-premultiplied RGB values, we need correct RGB
|
||||
// values on each stop. So in case that one color has alpha=0
|
||||
// (complete transparent), use the RGB values of the
|
||||
|
Loading…
x
Reference in New Issue
Block a user