lua: Add Brush class and app.useTool{ brush } parameter

This commit is contained in:
David Capello 2019-04-18 22:23:33 -03:00
parent 0bf5d1de30
commit 8a821c83fd
11 changed files with 340 additions and 26 deletions

View File

@ -150,6 +150,7 @@ if(ENABLE_SCRIPTING)
commands/cmd_run_script.cpp
script/app_command_object.cpp
script/app_object.cpp
script/brush_class.cpp
script/cel_class.cpp
script/cels_class.cpp
script/color_class.cpp

View File

@ -29,6 +29,7 @@
#include "app/tools/tool_loop.h"
#include "app/tools/tool_loop_manager.h"
#include "app/tx.h"
#include "app/ui/context_bar.h"
#include "app/ui/doc_view.h"
#include "app/ui/editor/editor.h"
#include "app/ui/editor/tool_loop_impl.h"
@ -287,11 +288,25 @@ int App_useTool(lua_State* L)
color = convert_args_into_color(L, -1);
lua_pop(L, 1);
// Default brush is the active brush in the context bar
BrushRef brush(nullptr);
#ifdef ENABLE_UI
if (App::instance()->isGui() &&
App::instance()->contextBar())
brush = App::instance()->contextBar()->activeBrush(tool, ink);
#endif
type = lua_getfield(L, 1, "brush");
if (type != LUA_TNIL)
brush = get_brush_from_arg(L, -1);
lua_pop(L, 1);
if (!brush)
brush.reset(new Brush(BrushType::kCircleBrushType, 1, 0));
// 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, site, tool, ink, color));
create_tool_loop_for_script(ctx, site, tool, ink, color, brush));
if (!loop)
return luaL_error(L, "cannot draw in the active site");
@ -478,6 +493,27 @@ int App_get_apiVersion(lua_State* L)
return 1;
}
int App_get_activeTool(lua_State* L)
{
tools::Tool* tool = App::instance()->activeToolManager()->activeTool();
push_tool(L, tool);
return 1;
}
int App_get_activeBrush(lua_State* L)
{
#if ENABLE_UI
App* app = App::instance();
if (app->isGui()) {
doc::BrushRef brush = app->contextBar()->activeBrush();
push_brush(L, brush);
return 1;
}
#endif
push_brush(L, doc::BrushRef(new doc::Brush()));
return 1;
}
int App_set_activeSprite(lua_State* L)
{
auto sprite = get_docobj<Sprite>(L, 2);
@ -524,13 +560,6 @@ int App_set_activeImage(lua_State* L)
return 0;
}
int App_get_activeTool(lua_State* L)
{
tools::Tool* tool = App::instance()->activeToolManager()->activeTool();
push_tool(L, tool);
return 1;
}
int App_set_activeTool(lua_State* L)
{
if (auto tool = get_tool_from_arg(L, 2))
@ -538,6 +567,18 @@ int App_set_activeTool(lua_State* L)
return 0;
}
int App_set_activeBrush(lua_State* L)
{
#if ENABLE_UI
if (auto brush = get_brush_from_arg(L, 2)) {
App* app = App::instance();
if (app->isGui())
app->contextBar()->setActiveBrush(brush);
}
#endif
return 0;
}
const luaL_Reg App_methods[] = {
{ "open", App_open },
{ "exit", App_exit },
@ -558,6 +599,7 @@ const Property App_properties[] = {
{ "activeImage", App_get_activeImage, App_set_activeImage },
{ "activeTag", App_get_activeTag, nullptr },
{ "activeTool", App_get_activeTool, App_set_activeTool },
{ "activeBrush", App_get_activeBrush, App_set_activeBrush },
{ "sprites", App_get_sprites, nullptr },
{ "fgColor", App_get_fgColor, App_set_fgColor },
{ "bgColor", App_get_bgColor, App_set_bgColor },

View File

@ -0,0 +1,238 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "doc/brush.h"
#include "doc/image.h"
#include <algorithm>
namespace app {
namespace script {
namespace {
using namespace doc;
struct BrushObj {
BrushRef brush;
BrushObj(const BrushRef& brush)
: brush(brush) {
}
};
BrushRef Brush_new(lua_State* L, int index)
{
BrushRef brush;
if (auto brush2 = may_get_obj<BrushObj>(L, index)) {
ASSERT(brush2->brush);
if (brush2->brush)
brush.reset(new Brush(*brush2->brush));
}
else if (auto image = may_get_image_from_arg(L, index)) {
if (image) {
brush.reset(new Brush(kImageBrushType, 1, 0));
brush->setImage(image, nullptr);
brush->setPattern(BrushPattern::DEFAULT_FOR_SCRIPTS);
}
}
else if (lua_istable(L, index)) {
Image* image = nullptr;
if (lua_getfield(L, index, "image") != LUA_TNIL) {
image = may_get_image_from_arg(L, -1);
}
lua_pop(L, 1);
BrushType type = (image ? BrushType::kImageBrushType:
BrushType::kCircleBrushType);
if (lua_getfield(L, index, "type") != LUA_TNIL)
type = (BrushType)lua_tointeger(L, -1);
lua_pop(L, 1);
int size = 1;
if (lua_getfield(L, index, "size") != LUA_TNIL) {
size = lua_tointeger(L, -1);
size = std::max(1, size);
}
lua_pop(L, 1);
int angle = 0;
if (lua_getfield(L, index, "angle") != LUA_TNIL)
angle = lua_tointeger(L, -1);
lua_pop(L, 1);
brush.reset(new Brush(type, size, angle));
if (image)
brush->setImage(image, nullptr);
if (lua_getfield(L, index, "center") != LUA_TNIL) {
gfx::Point center = convert_args_into_point(L, -1);
brush->setCenter(center);
}
lua_pop(L, 1);
if (lua_getfield(L, index, "pattern") != LUA_TNIL) {
BrushPattern pattern = (BrushPattern)lua_tointeger(L, -1);
brush->setPattern(pattern);
}
else {
brush->setPattern(BrushPattern::DEFAULT_FOR_SCRIPTS);
}
lua_pop(L, 1);
if (lua_getfield(L, index, "patternOrigin") != LUA_TNIL) {
gfx::Point patternOrigin = convert_args_into_point(L, -1);
brush->setPatternOrigin(patternOrigin);
}
lua_pop(L, 1);
}
else {
int size = lua_tointeger(L, index);
size = std::max(1, size);
brush.reset(new Brush(BrushType::kCircleBrushType, size, 0));
brush->setPattern(BrushPattern::DEFAULT_FOR_SCRIPTS);
}
return brush;
}
int Brush_new(lua_State* L)
{
BrushRef brush = Brush_new(L, 1);
if (brush)
push_new<BrushObj>(L, brush);
else
lua_pushnil(L);
return 1;
}
int Brush_gc(lua_State* L)
{
get_obj<BrushObj>(L, 1)->~BrushObj();
return 0;
}
int Brush_setFgColor(lua_State* L)
{
auto obj = get_obj<BrushObj>(L, 1);
if (obj->brush) {
const doc::color_t color = convert_args_into_pixel_color(L, 2);
obj->brush->setImageColor(Brush::ImageColor::MainColor, color);
}
return 0;
}
int Brush_setBgColor(lua_State* L)
{
auto obj = get_obj<BrushObj>(L, 1);
if (obj->brush) {
const doc::color_t color = convert_args_into_pixel_color(L, 2);
obj->brush->setImageColor(Brush::ImageColor::BackgroundColor, color);
}
return 0;
}
int Brush_get_type(lua_State* L)
{
const auto obj = get_obj<BrushObj>(L, 1);
lua_pushinteger(L, (int)obj->brush->type());
return 1;
}
int Brush_get_size(lua_State* L)
{
const auto obj = get_obj<BrushObj>(L, 1);
lua_pushinteger(L, obj->brush->size());
return 1;
}
int Brush_get_angle(lua_State* L)
{
const auto obj = get_obj<BrushObj>(L, 1);
lua_pushinteger(L, obj->brush->angle());
return 1;
}
int Brush_get_image(lua_State* L)
{
const auto obj = get_obj<BrushObj>(L, 1);
if (obj->brush->type() == BrushType::kImageBrushType)
push_image(L, Image::createCopy(obj->brush->image()));
else
lua_pushnil(L);
return 1;
}
int Brush_get_center(lua_State* L)
{
const auto obj = get_obj<BrushObj>(L, 1);
push_obj(L, obj->brush->center());
return 1;
}
int Brush_get_pattern(lua_State* L)
{
const auto obj = get_obj<BrushObj>(L, 1);
lua_pushinteger(L, (int)obj->brush->pattern());
return 1;
}
int Brush_get_patternOrigin(lua_State* L)
{
const auto obj = get_obj<BrushObj>(L, 1);
push_obj(L, obj->brush->patternOrigin());
return 1;
}
const luaL_Reg Brush_methods[] = {
{ "__gc", Brush_gc },
{ "setFgColor", Brush_setFgColor },
{ "setBgColor", Brush_setBgColor },
{ nullptr, nullptr }
};
const Property Brush_properties[] = {
{ "type", Brush_get_type, nullptr },
{ "size", Brush_get_size, nullptr },
{ "angle", Brush_get_angle, nullptr },
{ "image", Brush_get_image, nullptr },
{ "center", Brush_get_center, nullptr },
{ "pattern", Brush_get_pattern, nullptr },
{ "patternOrigin", Brush_get_patternOrigin, nullptr },
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
DEF_MTNAME(BrushObj);
void register_brush_class(lua_State* L)
{
using Brush = BrushObj;
REG_CLASS(L, Brush);
REG_CLASS_NEW(L, Brush);
REG_CLASS_PROPERTIES(L, Brush);
}
void push_brush(lua_State* L, const BrushRef& brush)
{
push_new<BrushObj>(L, brush);
}
BrushRef get_brush_from_arg(lua_State* L, int index)
{
if (auto obj = may_get_obj<BrushObj>(L, index))
return obj->brush;
else
return Brush_new(L, index);
}
} // namespace script
} // namespace app

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2018 David Capello
//
// This program is distributed under the terms of
@ -137,7 +138,7 @@ app::Color Color_new(lua_State* L, int index)
}
// raw color into app color
else if (!lua_isnone(L, index)) {
if (lua_isinteger(L, index) && lua_isnone(L, index+1)) {
if (lua_isinteger(L, index) && (index < 0 || lua_isnone(L, index+1))) {
doc::color_t docColor = lua_tointeger(L, index);
switch (app_get_current_pixel_format()) {
case IMAGE_RGB:
@ -155,7 +156,7 @@ app::Color Color_new(lua_State* L, int index)
break;
}
}
else {
else if (index >= 0) {
color = app::Color::fromRgb(lua_tointeger(L, index),
lua_tointeger(L, index+1),
lua_tointeger(L, index+2),

View File

@ -136,6 +136,7 @@ void register_app_object(lua_State* L);
void register_app_pixel_color_object(lua_State* L);
void register_app_command_object(lua_State* L);
void register_brush_class(lua_State* L);
void register_cel_class(lua_State* L);
void register_cels_class(lua_State* L);
void register_color_class(lua_State* L);
@ -298,7 +299,25 @@ Engine::Engine()
setfield_integer(L, "JSON_ARRAY", DocExporter::JsonArrayDataFormat);
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setglobal(L, "BrushType");
setfield_integer(L, "CIRCLE", doc::kCircleBrushType);
setfield_integer(L, "SQUARE", doc::kSquareBrushType);
setfield_integer(L, "LINE", doc::kLineBrushType);
setfield_integer(L, "IMAGE", doc::kImageBrushType);
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_setglobal(L, "BrushPattern");
setfield_integer(L, "ORIGIN", doc::BrushPattern::ALIGNED_TO_SRC);
setfield_integer(L, "TARGET", doc::BrushPattern::ALIGNED_TO_DST);
setfield_integer(L, "NONE", doc::BrushPattern::PAINT_BRUSH);
lua_pop(L, 1);
// Register classes/prototypes
register_brush_class(L);
register_cel_class(L);
register_cels_class(L);
register_color_class(L);

View File

@ -15,6 +15,7 @@
#include "app/color.h"
#include "app/commands/params.h"
#include "doc/brush.h"
#include "doc/frame.h"
#include "doc/object_ids.h"
#include "gfx/fwd.h"
@ -108,6 +109,7 @@ namespace app {
};
int push_image_iterator_function(lua_State* L, const doc::Image* image, int extraArgIndex);
void push_brush(lua_State* L, const doc::BrushRef& brush);
void push_cel_image(lua_State* L, doc::Cel* cel);
void push_cels(lua_State* L, const doc::ObjectIds& cels);
void push_cels(lua_State* L, doc::Layer* layer);
@ -143,6 +145,7 @@ namespace app {
doc::frame_t get_frame_number_from_arg(lua_State* L, int index);
const doc::Mask* get_mask_from_arg(lua_State* L, int index);
tools::Tool* get_tool_from_arg(lua_State* L, int index);
doc::BrushRef get_brush_from_arg(lua_State* L, int index);
// Used by App.open(), Sprite{ fromFile }, and Image{ fromFile }
enum class LoadSpriteFromFileParam { FullAniAsSprite,

View File

@ -42,7 +42,6 @@
#include "app/ui/status_bar.h"
#include "app/ui_context.h"
#include "app/util/expand_cel_canvas.h"
#include "doc/brush.h"
#include "doc/cel.h"
#include "doc/image.h"
#include "doc/layer.h"
@ -689,7 +688,8 @@ tools::ToolLoop* create_tool_loop_for_script(
const Site& site,
tools::Tool* tool,
tools::Ink* ink,
const app::Color& color)
const app::Color& color,
const doc::BrushRef& brush)
{
ASSERT(tool);
ASSERT(ink);
@ -699,13 +699,6 @@ tools::ToolLoop* create_tool_loop_for_script(
try {
const tools::ToolLoop::Button toolLoopButton = tools::ToolLoop::Left;
tools::Controller* controller = tool->getController(toolLoopButton);
BrushRef brush(nullptr);
#ifdef ENABLE_UI
if (App::instance()->contextBar())
brush = App::instance()->contextBar()->activeBrush(tool, ink);
#endif
if (!brush)
brush = BrushRef(new Brush(BrushType::kCircleBrushType, 1, 0));
return new ToolLoopImpl(
nullptr, site, context,

View File

@ -10,6 +10,7 @@
#pragma once
#include "app/tools/pointer.h"
#include "doc/brush.h"
#include "doc/image_ref.h"
#include "gfx/fwd.h"
@ -40,7 +41,8 @@ namespace app {
const Site& site,
tools::Tool* tool,
tools::Ink* ink,
const app::Color& color);
const app::Color& color,
const doc::BrushRef& brush);
tools::ToolLoop* create_tool_loop_preview(
Editor* editor,

View File

@ -1,5 +1,6 @@
// Aseprite Document Library
// Copyright (c) 2001-2016 David Capello
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -29,7 +30,7 @@ Brush::Brush()
m_type = kCircleBrushType;
m_size = 1;
m_angle = 0;
m_pattern = BrushPattern::DEFAULT;
m_pattern = BrushPattern::DEFAULT_FOR_UI;
m_gen = 0;
regenerate();
@ -40,7 +41,7 @@ Brush::Brush(BrushType type, int size, int angle)
m_type = type;
m_size = size;
m_angle = angle;
m_pattern = BrushPattern::DEFAULT;
m_pattern = BrushPattern::DEFAULT_FOR_UI;
m_gen = 0;
regenerate();
@ -279,6 +280,14 @@ void Brush::setImageColor(ImageColor imageColor, color_t color)
}
}
void Brush::setCenter(const gfx::Point& center)
{
m_center = center;
m_bounds = gfx::Rect(-m_center,
gfx::Size(m_image->width(),
m_image->height()));
}
// Cleans the brush's data (image and region).
void Brush::clean()
{

View File

@ -1,5 +1,6 @@
// Aseprite Document Library
// Copyright (c) 2001-2018 David Capello
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -57,6 +58,7 @@ namespace doc {
void setPatternOrigin(const gfx::Point& patternOrigin) {
m_patternOrigin = patternOrigin;
}
void setCenter(const gfx::Point& center);
private:
void clean();

View File

@ -1,5 +1,6 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 David Capello
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -11,10 +12,13 @@
namespace doc {
enum class BrushPattern {
DEFAULT = 0,
ALIGNED_TO_SRC = 0,
ALIGNED_TO_DST = 1,
PAINT_BRUSH = 2,
DEFAULT = ALIGNED_TO_SRC, // Default for preferences
DEFAULT_FOR_UI = ALIGNED_TO_SRC,
DEFAULT_FOR_SCRIPTS = PAINT_BRUSH,
};
} // namespace doc