mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-16 10:20:50 +00:00
lua: Add app.drawWithTool() function
This commit is contained in:
parent
79601567c5
commit
1cb5949e9b
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -23,9 +23,14 @@
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/script/security.h"
|
||||
#include "app/site.h"
|
||||
#include "app/tools/active_tool.h"
|
||||
#include "app/tools/tool_box.h"
|
||||
#include "app/tools/tool_loop.h"
|
||||
#include "app/tools/tool_loop_manager.h"
|
||||
#include "app/tx.h"
|
||||
#include "app/ui/doc_view.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/tool_loop_impl.h"
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/fs.h"
|
||||
@ -185,6 +190,71 @@ int App_refresh(lua_State* L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int App_drawWithTool(lua_State* L)
|
||||
{
|
||||
#ifdef ENABLE_UI
|
||||
// First argument must be a table
|
||||
if (!lua_istable(L, 1))
|
||||
return luaL_error(L, "app.drawWithTool() must be called with a table as its first argument");
|
||||
|
||||
auto ctx = App::instance()->context();
|
||||
Doc* doc = ctx->activeDocument();
|
||||
if (!doc)
|
||||
return luaL_error(L, "there is no active document to draw with the tool");
|
||||
|
||||
// Select tool by name
|
||||
tools::Tool* tool = App::instance()->activeToolManager()->activeTool();
|
||||
tools::Ink* ink = App::instance()->activeToolManager()->activeInk();
|
||||
int type = lua_getfield(L, 1, "tool");
|
||||
if (type == LUA_TSTRING) {
|
||||
const char* toolId = lua_tostring(L, -1);
|
||||
tool = App::instance()->toolBox()->getToolById(toolId);
|
||||
ink = tool->getInk(0);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Default color is the active fgColor
|
||||
app::Color color = Preferences::instance().colorBar.fgColor();
|
||||
type = lua_getfield(L, 1, "color");
|
||||
if (type != LUA_TNIL)
|
||||
color = convert_args_into_color(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Do the tool loop
|
||||
type = lua_getfield(L, 1, "points");
|
||||
if (type == LUA_TTABLE) {
|
||||
std::unique_ptr<tools::ToolLoop> loop(
|
||||
create_tool_loop_for_script(ctx, tool, ink, color));
|
||||
tools::ToolLoopManager manager(loop.get());
|
||||
tools::Pointer lastPointer;
|
||||
bool first = true;
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
gfx::Point pt = convert_args_into_point(L, -1);
|
||||
|
||||
tools::Pointer pointer(pt, tools::Pointer::Button::Left);
|
||||
if (first) {
|
||||
first = false;
|
||||
manager.prepareLoop(pointer);
|
||||
manager.pressButton(pointer);
|
||||
}
|
||||
else {
|
||||
manager.movement(pointer);
|
||||
}
|
||||
lastPointer = pointer;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
if (!first)
|
||||
manager.releaseButton(lastPointer);
|
||||
|
||||
loop->commitOrRollback();
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int App_get_activeSprite(lua_State* L)
|
||||
{
|
||||
app::Context* ctx = App::instance()->context();
|
||||
@ -430,6 +500,7 @@ const luaL_Reg App_methods[] = {
|
||||
{ "redo", App_redo },
|
||||
{ "alert", App_alert },
|
||||
{ "refresh", App_refresh },
|
||||
{ "drawWithTool", App_drawWithTool },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
|
@ -98,23 +98,21 @@ protected:
|
||||
doc::color_t m_secondaryColor;
|
||||
|
||||
public:
|
||||
ToolLoopBase(Editor* editor,
|
||||
Layer* layer,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
ToolLoopBase(Editor* editor, Site site,
|
||||
tools::Tool* tool, tools::Ink* ink,
|
||||
tools::Controller* controller,
|
||||
Doc* document,
|
||||
const BrushRef& brush,
|
||||
tools::ToolLoop::Button button,
|
||||
const app::Color& fgColor,
|
||||
const app::Color& bgColor)
|
||||
: m_editor(editor)
|
||||
, m_tool(tool)
|
||||
, m_brush(App::instance()->contextBar()->activeBrush(m_tool, ink))
|
||||
, m_brush(brush)
|
||||
, m_oldPatternOrigin(m_brush->patternOrigin())
|
||||
, m_document(document)
|
||||
, m_sprite(editor->sprite())
|
||||
, m_layer(layer)
|
||||
, m_frame(editor->frame())
|
||||
, m_document(site.document())
|
||||
, m_sprite(site.sprite())
|
||||
, m_layer(site.layer())
|
||||
, m_frame(site.frame())
|
||||
, m_rgbMap(nullptr)
|
||||
, m_docPref(Preferences::instance().document(m_document))
|
||||
, m_toolPref(Preferences::instance().tool(m_tool))
|
||||
@ -229,7 +227,10 @@ public:
|
||||
int getOpacity() override { return m_opacity; }
|
||||
int getTolerance() override { return m_tolerance; }
|
||||
bool getContiguous() override { return m_contiguous; }
|
||||
tools::ToolLoopModifiers getModifiers() override { return m_editor->getToolLoopModifiers(); }
|
||||
tools::ToolLoopModifiers getModifiers() override {
|
||||
return m_editor ? m_editor->getToolLoopModifiers():
|
||||
tools::ToolLoopModifiers::kNone;
|
||||
}
|
||||
filters::TiledMode getTiledMode() override { return m_docPref.tiled.mode(); }
|
||||
bool getGridVisible() override { return m_docPref.show.grid(); }
|
||||
bool getSnapToGrid() override { return m_docPref.grid.snap(); }
|
||||
@ -278,6 +279,9 @@ public:
|
||||
}
|
||||
|
||||
void updateDirtyArea(const gfx::Region& dirtyArea) override {
|
||||
if (!m_editor)
|
||||
return;
|
||||
|
||||
// This is necessary here so the "on sprite crosshair" is hidden,
|
||||
// we update screen pixels with the new sprite, and then we show
|
||||
// the crosshair saving the updated pixels. It fixes problems with
|
||||
@ -290,11 +294,12 @@ public:
|
||||
}
|
||||
|
||||
void updateStatusBar(const char* text) override {
|
||||
StatusBar::instance()->setStatusText(0, text);
|
||||
if (auto statusBar = StatusBar::instance())
|
||||
statusBar->setStatusText(0, text);
|
||||
}
|
||||
|
||||
gfx::Point statusBarPositionOffset() override {
|
||||
return -m_editor->mainTilePosition();
|
||||
return (m_editor ? -m_editor->mainTilePosition(): gfx::Point(0, 0));
|
||||
}
|
||||
|
||||
render::DitheringMatrix getDitheringMatrix() override {
|
||||
@ -327,25 +332,19 @@ class ToolLoopImpl : public ToolLoopBase {
|
||||
|
||||
public:
|
||||
ToolLoopImpl(Editor* editor,
|
||||
Layer* layer,
|
||||
Site site,
|
||||
Context* context,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
tools::Controller* controller,
|
||||
Doc* document,
|
||||
const BrushRef& brush,
|
||||
tools::ToolLoop::Button button,
|
||||
const app::Color& fgColor,
|
||||
const app::Color& bgColor,
|
||||
const bool saveLastPoint)
|
||||
: ToolLoopBase(editor,
|
||||
layer,
|
||||
tool,
|
||||
ink,
|
||||
controller,
|
||||
document,
|
||||
button,
|
||||
fgColor,
|
||||
bgColor)
|
||||
: ToolLoopBase(editor, site,
|
||||
tool, ink, controller, brush,
|
||||
button, fgColor, bgColor)
|
||||
, m_context(context)
|
||||
, m_canceled(false)
|
||||
, m_transaction(m_context,
|
||||
@ -360,8 +359,6 @@ public:
|
||||
, m_floodfillSrcImage(nullptr)
|
||||
, m_saveLastPoint(saveLastPoint)
|
||||
{
|
||||
ASSERT(m_context->activeDocument() == m_editor->document());
|
||||
|
||||
if (m_pointShape->isFloodFill()) {
|
||||
// Prepare a special image for floodfill when it's configured to
|
||||
// stop using all visible layers.
|
||||
@ -393,8 +390,7 @@ public:
|
||||
}
|
||||
|
||||
m_expandCelCanvas = new ExpandCelCanvas(
|
||||
editor->getSite(),
|
||||
layer,
|
||||
site, site.layer(),
|
||||
m_docPref.tiled.mode(),
|
||||
m_transaction,
|
||||
ExpandCelCanvas::Flags(
|
||||
@ -567,7 +563,7 @@ tools::ToolLoop* create_tool_loop(
|
||||
if (!tool || !ink)
|
||||
return nullptr;
|
||||
|
||||
Layer* layer;
|
||||
Site site = editor->getSite();
|
||||
|
||||
// For selection tools, we can use any layer (even without layers at
|
||||
// all), so we specify a nullptr here as the active layer. This is
|
||||
@ -580,10 +576,10 @@ tools::ToolLoop* create_tool_loop(
|
||||
// image/pixels to stop the flood-fill algorithm.
|
||||
if (ink->isSelection() &&
|
||||
!tool->getPointShape(button != tools::Pointer::Left ? 1: 0)->isFloodFill()) {
|
||||
layer = nullptr;
|
||||
site.layer(nullptr);
|
||||
}
|
||||
else {
|
||||
layer = editor->layer();
|
||||
Layer* layer = site.layer();
|
||||
if (!layer) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, "There is no active layer");
|
||||
@ -639,14 +635,12 @@ tools::ToolLoop* create_tool_loop(
|
||||
(controller->isFreehand() ||
|
||||
convertLineToFreehand));
|
||||
|
||||
ASSERT(context->activeDocument() == editor->document());
|
||||
return new ToolLoopImpl(
|
||||
editor, layer, context,
|
||||
tool,
|
||||
ink,
|
||||
controller,
|
||||
editor->document(),
|
||||
toolLoopButton,
|
||||
fg, bg,
|
||||
editor, site, context,
|
||||
tool, ink, controller,
|
||||
App::instance()->contextBar()->activeBrush(tool, ink),
|
||||
toolLoopButton, fg, bg,
|
||||
saveLastPoint);
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
@ -655,6 +649,40 @@ tools::ToolLoop* create_tool_loop(
|
||||
}
|
||||
}
|
||||
|
||||
tools::ToolLoop* create_tool_loop_for_script(
|
||||
Context* context,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
const app::Color& color)
|
||||
{
|
||||
ASSERT(tool);
|
||||
ASSERT(ink);
|
||||
|
||||
Site site = context->activeSite();
|
||||
if (!site.layer())
|
||||
return nullptr;
|
||||
|
||||
try {
|
||||
tools::ToolLoop::Button toolLoopButton = tools::ToolLoop::Left;
|
||||
tools::Controller* controller = tool->getController(toolLoopButton);
|
||||
BrushRef brush;
|
||||
if (App::instance()->contextBar())
|
||||
brush = App::instance()->contextBar()->activeBrush(tool, ink);
|
||||
if (!brush)
|
||||
brush = BrushRef(new Brush(BrushType::kCircleBrushType, 1, 0));
|
||||
|
||||
return new ToolLoopImpl(
|
||||
nullptr, site, context,
|
||||
tool, ink, controller,
|
||||
brush,
|
||||
toolLoopButton, color, color, false);
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
Console::showException(ex);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// For preview
|
||||
|
||||
@ -666,20 +694,14 @@ public:
|
||||
Editor* editor,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
Doc* document,
|
||||
const app::Color& fgColor,
|
||||
const app::Color& bgColor,
|
||||
Image* image,
|
||||
const gfx::Point& celOrigin)
|
||||
: ToolLoopBase(editor,
|
||||
editor->layer(),
|
||||
tool,
|
||||
ink,
|
||||
tool->getController(tools::ToolLoop::Left),
|
||||
document,
|
||||
tools::ToolLoop::Left,
|
||||
fgColor,
|
||||
bgColor)
|
||||
: ToolLoopBase(editor, editor->getSite(),
|
||||
tool, ink, tool->getController(tools::ToolLoop::Left),
|
||||
App::instance()->contextBar()->activeBrush(tool, ink),
|
||||
tools::ToolLoop::Left, fgColor, bgColor)
|
||||
, m_image(image)
|
||||
{
|
||||
m_celOrigin = celOrigin;
|
||||
@ -750,10 +772,7 @@ tools::ToolLoop* create_tool_loop_preview(
|
||||
// Create the new tool loop
|
||||
try {
|
||||
return new PreviewToolLoopImpl(
|
||||
editor,
|
||||
tool,
|
||||
ink,
|
||||
editor->document(),
|
||||
editor, tool, ink,
|
||||
fg, bg, image, celOrigin);
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -17,10 +18,13 @@ namespace doc {
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Color;
|
||||
class Context;
|
||||
class Editor;
|
||||
|
||||
namespace tools {
|
||||
class Ink;
|
||||
class Tool;
|
||||
class ToolLoop;
|
||||
}
|
||||
|
||||
@ -30,6 +34,12 @@ namespace app {
|
||||
const tools::Pointer::Button button,
|
||||
const bool convertLineToFreehand);
|
||||
|
||||
tools::ToolLoop* create_tool_loop_for_script(
|
||||
Context* context,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
const app::Color& color);
|
||||
|
||||
tools::ToolLoop* create_tool_loop_preview(
|
||||
Editor* editor,
|
||||
doc::Image* image,
|
||||
|
Loading…
x
Reference in New Issue
Block a user