Merge branch 'master' into beta

This commit is contained in:
David Capello 2020-08-06 10:46:32 -03:00
commit 4e08d12f28
27 changed files with 178 additions and 72 deletions

View File

@ -636,6 +636,7 @@
<separator id="scripts_menu_separator" />
<menu id="scripts_menu" text="@.file_scripts" group="file_scripts">
<item command="OpenScriptFolder" text="@.file_open_script_folder" />
<item command="Refresh" text="@.file_rescan_script_folder" />
</menu>
<separator group="file_app" />
<item command="Exit" text="@.file_exit" />

View File

@ -28,6 +28,8 @@
<value id="NONE" value="0" />
<value id="EDGES" value="1" />
<value id="FULL" value="2" />
<value id="FULLALL" value="3" />
<value id="FULLNEDGES" value="4" />
</enum>
<enum id="BgType">
<value id="CHECKED_16x16" value="0" />

View File

@ -806,6 +806,7 @@ file_export_sprite_sheet = &Export Sprite Sheet
file_repeat_last_export = Repeat &Last Export
file_scripts = Scri&pts
file_open_script_folder = &Open Scripts Folder
file_rescan_script_folder = &Rescan Scripts Folder
file_exit = E&xit
edit = &Edit
edit_undo = &Undo
@ -1185,8 +1186,10 @@ simple_crosshair = Simple Crosshair
crosshair_on_sprite = Crosshair on Sprite
brush_preview = Brush Preview:
brush_preview_none = None
brush_preview_edges = Brush Edges
brush_preview_full = Full Real-time Brush Preview
brush_preview_edges = Edges Only
brush_preview_full = Full Preview
brush_preview_fullall = Full Preview with All Tools
brush_preview_fullnedges = Full Preview and Edges
cursor_color_type = Crosshair && Brush Edges Color:
cursor_neg_bw = Negative Black and White
cursor_specific_color = Specific Color

View File

@ -292,6 +292,8 @@
<listitem text="@.brush_preview_none" value="0" />
<listitem text="@.brush_preview_edges" value="1" />
<listitem text="@.brush_preview_full" value="2" />
<listitem text="@.brush_preview_fullall" value="3" />
<listitem text="@.brush_preview_fullnedges" value="4" />
</combobox>
<label text="@.cursor_color_type" />

2
laf

@ -1 +1 @@
Subproject commit ab08b047defdd3390e3aaa55a02c6a10225496ac
Subproject commit c6a00f92ff4f073864db99e48c415997381cd88a

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -108,10 +109,13 @@ void AddCel::removeCel(Layer* layer, Cel* cel)
ev.sprite(layer->sprite());
ev.layer(layer);
ev.cel(cel);
doc->notify_observers<DocEvent&>(&DocObserver::onRemoveCel, ev);
doc->notify_observers<DocEvent&>(&DocObserver::onBeforeRemoveCel, ev);
static_cast<LayerImage*>(layer)->removeCel(cel);
layer->incrementVersion();
doc->notify_observers<DocEvent&>(&DocObserver::onAfterRemoveCel, ev);
delete cel;
}

View File

@ -230,6 +230,11 @@ private:
}
// DocObserver impl
void onBeforeRemoveCel(DocEvent& ev) override {
if (m_cel == ev.cel())
setCel(m_document, nullptr);
}
void onCelOpacityChange(DocEvent& ev) override {
if (m_cel == ev.cel())
updateFromCel();

View File

@ -10,7 +10,10 @@
#endif
#include "app/app.h"
#include "app/app_menus.h"
#include "app/commands/command.h"
#include "app/ui/main_menu_bar.h"
#include "app/ui/main_window.h"
#include "app/ui/status_bar.h"
#include "fmt/format.h"
#include "ui/scale.h"
@ -40,8 +43,15 @@ RefreshCommand::RefreshCommand()
void RefreshCommand::onExecute(Context* context)
{
// Reload menus (mainly to reload the File > Scripts menu)
//AppMenus::instance()->reload();
App::instance()->mainWindow()->getMenuBar()->reload();
// Reload theme
ui::set_theme(ui::get_theme(),
ui::guiscale());
// Redraw screen
app_refresh_screen();
// Print memory information

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -21,7 +22,10 @@ Command::Command(const char* id, CommandFlags flags)
{
std::string strId = "commands.";
strId += this->id();
m_friendlyName = Strings::instance()->translate(strId.c_str());
if (auto s = Strings::instance())
m_friendlyName = s->translate(strId.c_str());
else
m_friendlyName = strId;
}
Command::~Command()

View File

@ -357,7 +357,7 @@ void Param<filters::ColorCurve>::fromLua(lua_State* L, int index)
template<>
void Param<tools::InkType>::fromLua(lua_State* L, int index)
{
script::get_value_from_lua<tools::InkType>(L, index);
setValue(script::get_value_from_lua<tools::InkType>(L, index));
}
template<>

View File

@ -148,7 +148,11 @@ void Context::executeCommand(Command* command, const Params& params)
try {
m_flags.update(this);
#if 0
// params.empty() can be empty when we call the command from Lua
// with a table.
ASSERT(!command->needsParams() || !params.empty());
#endif
command->loadParams(params);

View File

@ -40,7 +40,8 @@ namespace app {
// removed, and the sprite's total number of frames is modified.
virtual void onRemoveFrame(DocEvent& ev) { }
virtual void onRemoveTag(DocEvent& ev) { }
virtual void onRemoveCel(DocEvent& ev) { }
virtual void onBeforeRemoveCel(DocEvent& ev) { }
virtual void onAfterRemoveCel(DocEvent& ev) { }
virtual void onRemoveSlice(DocEvent& ev) { }
virtual void onSpriteSizeChanged(DocEvent& ev) { }

View File

@ -153,6 +153,8 @@ public:
stroke[0] = m_first;
stroke[1] = pt;
bool isoAngle = false;
if ((int(loop->getModifiers()) & int(ToolLoopModifiers::kSquareAspect))) {
int dx = stroke[1].x - m_first.x;
int dy = stroke[1].y - m_first.y;
@ -173,6 +175,7 @@ public:
else if (angle < 36.0) {
stroke[1].x = m_first.x + SGN(dx)*maxsize;
stroke[1].y = m_first.y + SGN(dy)*maxsize/2;
isoAngle = true;
}
// Snap at 45
else if (angle < 54.0) {
@ -183,6 +186,7 @@ public:
else if (angle < 72.0) {
stroke[1].x = m_first.x + SGN(dx)*maxsize/2;
stroke[1].y = m_first.y + SGN(dy)*maxsize;
isoAngle = true;
}
// Snap vertically
else {
@ -207,8 +211,8 @@ public:
else if ((int(loop->getModifiers()) & int(ToolLoopModifiers::kFromCenter))) {
int rx = stroke[1].x - m_first.x;
int ry = stroke[1].y - m_first.y;
stroke[0].x = m_first.x - rx;
stroke[0].y = m_first.y - ry;
stroke[0].x = m_first.x - rx + (isoAngle && ABS(rx) > ABS(ry) ? SGN(rx)*(rx & 1): 0);
stroke[0].y = m_first.y - ry + (isoAngle && ABS(rx) < ABS(ry) ? SGN(ry)*(ry & 1): 0);
stroke[1].x = m_first.x + rx;
stroke[1].y = m_first.y + ry;
}

View File

@ -127,7 +127,8 @@ doc::AlgoLineWithAlgoPixel Intertwine::getLineAlgo(ToolLoop* loop,
const Stroke::Pt& b)
{
bool needsFixForLineBrush = false;
if (loop->getBrush()->type() == kLineBrushType) {
if ((loop->getBrush()->type() == kLineBrushType) &&
(a.size > 1.0 || b.size > 1.0)) {
if ((a.angle != 0.0f || b.angle != 0.0f) &&
(a.angle != b.angle)) {
needsFixForLineBrush = true;

View File

@ -428,7 +428,7 @@ void DocView::onAddCel(DocEvent& ev)
UIContext::instance()->notifyActiveSiteChanged();
}
void DocView::onRemoveCel(DocEvent& ev)
void DocView::onAfterRemoveCel(DocEvent& ev)
{
// This can happen when we apply a filter that clear the whole cel
// and then the cel is removed in a background/job

View File

@ -78,7 +78,7 @@ namespace app {
void onRemoveFrame(DocEvent& ev) override;
void onTagChange(DocEvent& ev) override;
void onAddCel(DocEvent& ev) override;
void onRemoveCel(DocEvent& ev) override;
void onAfterRemoveCel(DocEvent& ev) override;
void onTotalFramesChanged(DocEvent& ev) override;
void onLayerRestacked(DocEvent& ev) override;

View File

@ -149,7 +149,7 @@ void BrushPreview::show(const gfx::Point& screenPos)
(ink->isEffect()) ||
// or when the brush color is transparent and we are not in the background layer
(!ink->isShading() &&
(layer && !layer->isBackground()) &&
(layer && layer->isTransparent()) &&
((sprite->pixelFormat() == IMAGE_INDEXED && brush_color == mask_index) ||
(sprite->pixelFormat() == IMAGE_RGB && rgba_geta(brush_color) == 0) ||
(sprite->pixelFormat() == IMAGE_GRAYSCALE && graya_geta(brush_color) == 0))))) {
@ -160,6 +160,8 @@ void BrushPreview::show(const gfx::Point& screenPos)
}
bool showPreview = false;
bool showPreviewWithEdges = false;
bool cancelEdges = false;
auto brushPreview = pref.cursor.brushPreview();
if (!m_editor->docPref().show.brushPreview())
brushPreview = app::gen::BrushPreview::NONE;
@ -172,7 +174,20 @@ void BrushPreview::show(const gfx::Point& screenPos)
m_type = BRUSH_BOUNDARIES;
break;
case app::gen::BrushPreview::FULL:
case app::gen::BrushPreview::FULLALL:
case app::gen::BrushPreview::FULLNEDGES:
showPreview = m_editor->getState()->requireBrushPreview();
switch (brushPreview) {
case app::gen::BrushPreview::FULLALL:
if (showPreview)
m_type = CROSSHAIR;
cancelEdges = true;
break;
case app::gen::BrushPreview::FULLNEDGES:
if (showPreview)
showPreviewWithEdges = true;
break;
}
break;
}
@ -183,6 +198,8 @@ void BrushPreview::show(const gfx::Point& screenPos)
// layer) we don't show the brush preview temporally.
if (showPreview && m_editor->isExtraCelLocked()) {
showPreview = false;
showPreviewWithEdges = false;
cancelEdges = false;
m_type |= BRUSH_BOUNDARIES;
}
@ -195,9 +212,12 @@ void BrushPreview::show(const gfx::Point& screenPos)
// For cursor type 'bounds' we have to generate cursor boundaries
if (m_type & BRUSH_BOUNDARIES) {
if (brush->type() != kImageBrushType)
showPreview = false;
generateBoundaries();
showPreview = showPreviewWithEdges;
if (cancelEdges)
m_type &= ~BRUSH_BOUNDARIES;
}
if (m_type & BRUSH_BOUNDARIES)
generateBoundaries();
// Draw pixel/brush preview
if (showPreview) {

View File

@ -159,6 +159,7 @@ Editor::Editor(Doc* document, EditorFlags flags)
, m_aniSpeed(1.0)
, m_isPlaying(false)
, m_showGuidesThisCel(nullptr)
, m_showAutoCelGuides(false)
, m_tagFocusBand(-1)
{
if (!m_renderEngine)
@ -875,8 +876,7 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
}
// Draw active layer/cel edges
bool showGuidesThisCel = this->showAutoCelGuides();
if ((m_docPref.show.layerEdges() || showGuidesThisCel) &&
if ((m_docPref.show.layerEdges() || m_showAutoCelGuides) &&
// Show layer edges only on "standby" like states where brush
// preview is shown (e.g. with this we avoid to showing the
// edges in states like DrawingState, etc.).
@ -887,9 +887,10 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
g, cel,
color_utils::color_for_ui(Preferences::instance().guides.layerEdgesColor()));
if (showGuidesThisCel &&
m_showGuidesThisCel != cel)
if (m_showAutoCelGuides &&
m_showGuidesThisCel != cel) {
drawCelGuides(g, cel, m_showGuidesThisCel);
}
}
}
@ -1764,6 +1765,9 @@ bool Editor::onProcessMessage(Message* msg)
case kMouseLeaveMessage:
m_brushPreview.hide();
StatusBar::instance()->showDefaultText();
// Hide autoguides
updateAutoCelGuides(nullptr);
break;
case kMouseDownMessage:
@ -2149,7 +2153,7 @@ void Editor::onBeforeRemoveLayer(DocEvent& ev)
setLayer(layerToSelect);
}
void Editor::onRemoveCel(DocEvent& ev)
void Editor::onBeforeRemoveCel(DocEvent& ev)
{
m_showGuidesThisCel = nullptr;
}
@ -2774,22 +2778,21 @@ void Editor::invalidateIfActive()
invalidate();
}
bool Editor::showAutoCelGuides()
{
return
(getCurrentEditorInk()->isCelMovement() &&
m_docPref.show.autoGuides() &&
m_customizationDelegate &&
int(m_customizationDelegate->getPressedKeyAction(KeyContext::MoveTool) & KeyAction::AutoSelectLayer));
}
void Editor::updateAutoCelGuides(ui::Message* msg)
{
Cel* oldShowGuidesThisCel = m_showGuidesThisCel;
bool oldShowAutoCelGuides = m_showAutoCelGuides;
m_showAutoCelGuides = (
msg &&
getCurrentEditorInk()->isCelMovement() &&
m_docPref.show.autoGuides() &&
m_customizationDelegate &&
int(m_customizationDelegate->getPressedKeyAction(KeyContext::MoveTool) & KeyAction::AutoSelectLayer));
// Check if the user is pressing the Ctrl or Cmd key on move
// tool to show automatic guides.
if (showAutoCelGuides() &&
if (m_showAutoCelGuides &&
m_state->requireBrushPreview()) {
ui::MouseMessage* mouseMsg = dynamic_cast<ui::MouseMessage*>(msg);
@ -2805,8 +2808,10 @@ void Editor::updateAutoCelGuides(ui::Message* msg)
m_showGuidesThisCel = nullptr;
}
if (m_showGuidesThisCel != oldShowGuidesThisCel)
if (m_showGuidesThisCel != oldShowGuidesThisCel ||
m_showAutoCelGuides != oldShowAutoCelGuides) {
invalidate();
}
}
// static

View File

@ -320,7 +320,7 @@ namespace app {
void onExposeSpritePixels(DocEvent& ev) override;
void onSpritePixelRatioChanged(DocEvent& ev) override;
void onBeforeRemoveLayer(DocEvent& ev) override;
void onRemoveCel(DocEvent& ev) override;
void onBeforeRemoveCel(DocEvent& ev) override;
void onAddTag(DocEvent& ev) override;
void onRemoveTag(DocEvent& ev) override;
void onRemoveSlice(DocEvent& ev) override;
@ -436,6 +436,7 @@ namespace app {
// The Cel that is above the mouse if the Ctrl (or Cmd) key is
// pressed (move key).
Cel* m_showGuidesThisCel;
bool m_showAutoCelGuides;
// Focused tag band. Used by the Timeline to save/restore the
// focused tag band for each sprite/editor.

View File

@ -5,6 +5,8 @@
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#define MOVPIXS_TRACE(...) // TRACE(__VA_ARGS__)
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -174,7 +176,7 @@ void MovingPixelsState::onEditorGotFocus(Editor* editor)
EditorState::LeaveAction MovingPixelsState::onLeaveState(Editor* editor, EditorState* newState)
{
TRACE("MOVPIXS: onLeaveState\n");
MOVPIXS_TRACE("MOVPIXS: onLeaveState\n");
ASSERT(m_pixelsMovement);
ASSERT(editor == m_editor);
@ -489,9 +491,23 @@ bool MovingPixelsState::onKeyUp(Editor* editor, KeyMessage* msg)
bool MovingPixelsState::onUpdateStatusBar(Editor* editor)
{
MOVPIXS_TRACE("MOVPIXS: onUpdateStatusBar (%p)\n", m_pixelsMovement.get());
ASSERT(m_pixelsMovement);
ASSERT(editor == m_editor);
// We've received a crash report where this is nullptr when
// MovingPixelsState::onLeaveState() generates a general update
// notification (notifyGeneralUpdate()) just after the
// m_pixelsMovement is deleted with removePixelsMovement(). The
// general update signals a scroll update in the view which will ask
// for the status bar content again (Editor::notifyScrollChanged).
//
// We weren't able to reproduce this scenario anyway (which should
// be visible with the ASSERT() above).
if (!m_pixelsMovement)
return false;
const Transformation& transform(getTransformation(editor));
gfx::Size imageSize = m_pixelsMovement->getInitialImageSize();
@ -532,7 +548,7 @@ void MovingPixelsState::onBeforeCommandExecution(CommandExecutionEvent& ev)
{
Command* command = ev.command();
TRACE("MOVPIXS: onBeforeCommandExecution %s\n", command->id().c_str());
MOVPIXS_TRACE("MOVPIXS: onBeforeCommandExecution %s\n", command->id().c_str());
// If the command is for other editor, we don't drop pixels.
if (!isActiveEditor())
@ -743,7 +759,7 @@ void MovingPixelsState::setTransparentColor(bool opaque, const app::Color& color
void MovingPixelsState::dropPixels()
{
TRACE("MOVPIXS: dropPixels\n");
MOVPIXS_TRACE("MOVPIXS: dropPixels\n");
// Just change to default state (StandbyState generally). We'll
// receive an onLeaveState() event after this call.

View File

@ -641,9 +641,10 @@ again:
}
#endif
// does it not have extension? ...we should add the extension
// Does it not have extension? ...we should add the extension
// selected in the filetype combo-box
if (!buf.empty() && base::get_file_extension(buf).empty()) {
if (m_type == FileSelectorType::Save &&
!buf.empty() && base::get_file_extension(buf).empty()) {
buf += '.';
buf += getSelectedExtension();
}

View File

@ -483,10 +483,10 @@ void PreviewEditorWindow::destroyDocView()
void PreviewEditorWindow::adjustPlayingTag()
{
Editor* editor = m_relatedEditor;
Editor* miniEditor = m_docView->editor();
if (!editor || !m_docView)
return;
ASSERT(editor);
ASSERT(miniEditor);
Editor* miniEditor = m_docView->editor();
if (miniEditor->isPlaying()) {
doc::Tag* tag = editor

View File

@ -42,7 +42,10 @@ namespace app {
}
}
ctx->executeCommandFromMenuOrShortcut(&m_cmd, params);
if (ctx->isUIAvailable())
ctx->executeCommandFromMenuOrShortcut(&m_cmd, params);
else
ctx->executeCommand(&m_cmd, params);
// Future decision for other files in the CLI
auto d = m_cmd.seqDecision();

View File

@ -39,6 +39,22 @@ bool AsepriteDecoder::decode()
return false;
}
if (header.depth != 32 &&
header.depth != 16 &&
header.depth != 8) {
delegate()->error(
fmt::format("Invalid color depth {0}",
header.depth));
return false;
}
if (header.width < 1 || header.height < 1) {
delegate()->error(
fmt::format("Invalid sprite size {0}x{1}",
header.width, header.height));
return false;
}
// Create the new sprite
std::unique_ptr<doc::Sprite> sprite(
new doc::Sprite(doc::ImageSpec(header.depth == 32 ? doc::ColorMode::RGB:

View File

@ -1,5 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2019 Igara Studio S.A.
// Copyright (c) 2019-2020 Igara Studio S.A.
// Copyright (c) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
@ -9,6 +9,7 @@
#include "config.h"
#endif
#include "base/debug.h"
#include "doc/algo.h"
#include "doc/algorithm/polygon.h"

View File

@ -518,30 +518,7 @@ void Manager::handleMouseMove(const gfx::Point& mousePos,
const PointerType pointerType,
const float pressure)
{
// Get the list of widgets to send mouse messages.
mouse_widgets_list.clear();
broadcastMouseMessage(mouse_widgets_list);
// Get the widget under the mouse
Widget* widget = nullptr;
for (auto mouseWidget : mouse_widgets_list) {
widget = mouseWidget->pick(mousePos);
if (widget) {
// Get the first ancestor of the picked widget that doesn't
// ignore mouse events.
while (widget && widget->hasFlags(IGNORE_MOUSE))
widget = widget->parent();
break;
}
}
// Fixup "mouse" flag
if (widget != mouse_widget) {
if (!widget)
freeMouse();
else
setMouse(widget);
}
updateMouseWidgets(mousePos);
// Send the mouse movement message
Widget* dst = (capture_widget ? capture_widget: mouse_widget);
@ -683,6 +660,34 @@ void Manager::handleWindowZOrder()
setFocus(mouse_widget);
}
void Manager::updateMouseWidgets(const gfx::Point& mousePos)
{
// Get the list of widgets to send mouse messages.
mouse_widgets_list.clear();
broadcastMouseMessage(mouse_widgets_list);
// Get the widget under the mouse
Widget* widget = nullptr;
for (auto mouseWidget : mouse_widgets_list) {
widget = mouseWidget->pick(mousePos);
if (widget) {
// Get the first ancestor of the picked widget that doesn't
// ignore mouse events.
while (widget && widget->hasFlags(IGNORE_MOUSE))
widget = widget->parent();
break;
}
}
// Fixup "mouse" flag
if (widget != mouse_widget) {
if (!widget)
freeMouse();
else
setMouse(widget);
}
}
void Manager::dispatchMessages()
{
// Send messages in the queue (mouse/key/timer/etc. events) This
@ -1103,9 +1108,7 @@ void Manager::_openWindow(Window* window)
// Update mouse widget (as it can be a widget below the
// recently opened window).
Widget* widget = pick(ui::get_mouse_position());
if (widget)
setMouse(widget);
updateMouseWidgets(ui::get_mouse_position());
}
void Manager::_closeWindow(Window* window, bool redraw_background)
@ -1160,9 +1163,7 @@ void Manager::_closeWindow(Window* window, bool redraw_background)
// Update mouse widget (as it can be a widget below the
// recently closed window).
Widget* widget = pick(ui::get_mouse_position());
if (widget)
setMouse(widget);
updateMouseWidgets(ui::get_mouse_position());
redrawState = RedrawState::AWindowHasJustBeenClosed;
}

View File

@ -145,6 +145,7 @@ namespace ui {
const KeyModifiers modifiers,
const double magnification);
void handleWindowZOrder();
void updateMouseWidgets(const gfx::Point& mousePos);
int pumpQueue();
bool sendMessageToWidget(Message* msg, Widget* widget);