mirror of https://github.com/aseprite/aseprite.git
Change scripting language to Lua
This commit is contained in:
parent
70629d6f89
commit
4fe66f2ffb
|
@ -51,9 +51,6 @@
|
||||||
[submodule "third_party/benchmark"]
|
[submodule "third_party/benchmark"]
|
||||||
path = third_party/benchmark
|
path = third_party/benchmark
|
||||||
url = https://github.com/aseprite/benchmark.git
|
url = https://github.com/aseprite/benchmark.git
|
||||||
[submodule "third_party/mujs"]
|
|
||||||
path = third_party/mujs
|
|
||||||
url = https://github.com/aseprite/mujs.git
|
|
||||||
[submodule "third_party/giflib"]
|
[submodule "third_party/giflib"]
|
||||||
path = third_party/giflib
|
path = third_party/giflib
|
||||||
url = https://github.com/aseprite/giflib.git
|
url = https://github.com/aseprite/giflib.git
|
||||||
|
@ -63,3 +60,6 @@
|
||||||
[submodule "third_party/tinyexpr"]
|
[submodule "third_party/tinyexpr"]
|
||||||
path = third_party/tinyexpr
|
path = third_party/tinyexpr
|
||||||
url = https://github.com/aseprite/tinyexpr.git
|
url = https://github.com/aseprite/tinyexpr.git
|
||||||
|
[submodule "third_party/lua"]
|
||||||
|
path = third_party/lua
|
||||||
|
url = https://github.com/aseprite/lua
|
||||||
|
|
|
@ -668,7 +668,7 @@
|
||||||
<item command="PasteText" text="@.edit_insert_text" />
|
<item command="PasteText" text="@.edit_insert_text" />
|
||||||
<!--menu text="Scripts">
|
<!--menu text="Scripts">
|
||||||
<item command="RunScript" text="Transparency from White Background">
|
<item command="RunScript" text="Transparency from White Background">
|
||||||
<param name="filename" value="white_to_alpha.js" />
|
<param name="filename" value="white_to_alpha.lua" />
|
||||||
</item>
|
</item>
|
||||||
</menu-->
|
</menu-->
|
||||||
<separator />
|
<separator />
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
// Aseprite
|
|
||||||
// Copyright (C) 2015-2017 by David Capello
|
|
||||||
|
|
||||||
var col = app.pixelColor
|
|
||||||
var img = app.activeImage
|
|
||||||
|
|
||||||
for (var y=0; y<img.height; ++y) {
|
|
||||||
for (var x=0; x<img.width; ++x) {
|
|
||||||
var c = img.getPixel(x, y)
|
|
||||||
var v = (col.rgbaR(c)+
|
|
||||||
col.rgbaG(c)+
|
|
||||||
col.rgbaB(c))/3
|
|
||||||
|
|
||||||
img.putPixel(x, y,
|
|
||||||
col.rgba(col.rgbaR(c),
|
|
||||||
col.rgbaG(c),
|
|
||||||
col.rgbaB(c),
|
|
||||||
255-v))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
-- Aseprite
|
||||||
|
-- Copyright (C) 2015-2018 by David Capello
|
||||||
|
|
||||||
|
local pc = app.pixelColor
|
||||||
|
local img = app.activeImage
|
||||||
|
|
||||||
|
for y=0,img.height-1 do
|
||||||
|
for x=0,img.width-1 do
|
||||||
|
local c = img:getPixel(x, y)
|
||||||
|
local r = pc.rgbaR(c)
|
||||||
|
local g = pc.rgbaG(c)
|
||||||
|
local b = pc.rgbaB(c)
|
||||||
|
local a = pc.rgbaA(c)
|
||||||
|
if a > 0 then a = 255 - (r+g+b)/3 end
|
||||||
|
img:putPixel(x, y, pc.rgba(r, g, b, a))
|
||||||
|
end
|
||||||
|
end
|
|
@ -904,24 +904,29 @@ freely, subject to the following restrictions:
|
||||||
distribution.
|
distribution.
|
||||||
```
|
```
|
||||||
|
|
||||||
# [mujs](http://mujs.com/)
|
# [Lua](https://www.lua.org/)
|
||||||
|
|
||||||
```
|
```
|
||||||
ISC License
|
Copyright (C) 1994-2018 Lua.org, PUC-Rio.
|
||||||
|
|
||||||
Copyright (c) 2013, 2017, Artifex Software
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
The above copyright notice and this permission notice shall be
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
included in all copies or substantial portions of the Software.
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
PERFORMANCE OF THIS SOFTWARE.
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
```
|
```
|
||||||
|
|
||||||
# [pixman](http://www.pixman.org/)
|
# [pixman](http://www.pixman.org/)
|
||||||
|
|
|
@ -115,11 +115,6 @@ add_subdirectory(ft)
|
||||||
add_subdirectory(she)
|
add_subdirectory(she)
|
||||||
add_subdirectory(ui)
|
add_subdirectory(ui)
|
||||||
|
|
||||||
if(ENABLE_SCRIPTING)
|
|
||||||
add_subdirectory(script)
|
|
||||||
add_definitions(-DENABLE_SCRIPTING)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(ENABLE_UPDATER)
|
if(ENABLE_UPDATER)
|
||||||
add_subdirectory(updater)
|
add_subdirectory(updater)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -140,6 +140,7 @@ endif()
|
||||||
|
|
||||||
set(scripting_files)
|
set(scripting_files)
|
||||||
if(ENABLE_SCRIPTING)
|
if(ENABLE_SCRIPTING)
|
||||||
|
add_definitions(-DENABLE_SCRIPTING)
|
||||||
set(scripting_files_ui)
|
set(scripting_files_ui)
|
||||||
if(ENABLE_UI)
|
if(ENABLE_UI)
|
||||||
set(scripting_files_ui
|
set(scripting_files_ui
|
||||||
|
@ -149,10 +150,10 @@ if(ENABLE_SCRIPTING)
|
||||||
set(scripting_files
|
set(scripting_files
|
||||||
commands/cmd_run_script.cpp
|
commands/cmd_run_script.cpp
|
||||||
script/app_object.cpp
|
script/app_object.cpp
|
||||||
script/app_scripting.cpp
|
script/engine.cpp
|
||||||
script/console_object.cpp
|
|
||||||
script/image_class.cpp
|
script/image_class.cpp
|
||||||
script/pixel_color_class.cpp
|
script/luacpp.cpp
|
||||||
|
script/pixel_color_object.cpp
|
||||||
script/point_class.cpp
|
script/point_class.cpp
|
||||||
script/rectangle_class.cpp
|
script/rectangle_class.cpp
|
||||||
script/selection_class.cpp
|
script/selection_class.cpp
|
||||||
|
@ -595,7 +596,7 @@ target_link_libraries(app-lib
|
||||||
tinyexpr)
|
tinyexpr)
|
||||||
|
|
||||||
if(ENABLE_SCRIPTING)
|
if(ENABLE_SCRIPTING)
|
||||||
target_link_libraries(app-lib script-lib)
|
target_link_libraries(app-lib lua lauxlib lualib)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_UPDATER)
|
if(ENABLE_UPDATER)
|
||||||
|
|
|
@ -70,9 +70,8 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
#include "app/script/app_scripting.h"
|
#include "app/script/engine.h"
|
||||||
#include "app/shell.h"
|
#include "app/shell.h"
|
||||||
#include "script/engine_delegate.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_STEAM
|
#ifdef ENABLE_STEAM
|
||||||
|
@ -353,7 +352,7 @@ void App::run()
|
||||||
// Start shell to execute scripts.
|
// Start shell to execute scripts.
|
||||||
if (m_isShell) {
|
if (m_isShell) {
|
||||||
script::StdoutEngineDelegate delegate;
|
script::StdoutEngineDelegate delegate;
|
||||||
AppScripting engine(&delegate);
|
script::Engine engine(&delegate);
|
||||||
engine.printLastResult();
|
engine.printLastResult();
|
||||||
Shell shell;
|
Shell shell;
|
||||||
shell.run(engine);
|
shell.run(engine);
|
||||||
|
|
|
@ -27,8 +27,7 @@
|
||||||
#include "doc/sprite.h"
|
#include "doc/sprite.h"
|
||||||
|
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
#include "app/script/app_scripting.h"
|
#include "app/script/engine.h"
|
||||||
#include "script/engine_delegate.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -128,7 +127,7 @@ void DefaultCliDelegate::execScript(const std::string& filename)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
script::StdoutEngineDelegate delegate;
|
script::StdoutEngineDelegate delegate;
|
||||||
AppScripting engine(&delegate);
|
script::Engine engine(&delegate);
|
||||||
if (!engine.evalFile(filename))
|
if (!engine.evalFile(filename))
|
||||||
throw std::runtime_error("Error executing script");
|
throw std::runtime_error("Error executing script");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,9 +16,8 @@
|
||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/console.h"
|
#include "app/console.h"
|
||||||
#include "app/resource_finder.h"
|
#include "app/resource_finder.h"
|
||||||
#include "app/script/app_scripting.h"
|
#include "app/script/engine.h"
|
||||||
#include "base/fs.h"
|
#include "base/fs.h"
|
||||||
#include "script/engine_delegate.h"
|
|
||||||
#include "ui/manager.h"
|
#include "ui/manager.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -67,7 +66,7 @@ void RunScriptCommand::onLoadParams(const Params& params)
|
||||||
void RunScriptCommand::onExecute(Context* context)
|
void RunScriptCommand::onExecute(Context* context)
|
||||||
{
|
{
|
||||||
ConsoleEngineDelegate delegate;
|
ConsoleEngineDelegate delegate;
|
||||||
AppScripting engine(&delegate);
|
script::Engine engine(&delegate);
|
||||||
engine.evalFile(m_filename);
|
engine.evalFile(m_filename);
|
||||||
|
|
||||||
ui::Manager::getDefault()->invalidate();
|
ui::Manager::getDefault()->invalidate();
|
||||||
|
|
|
@ -13,154 +13,155 @@
|
||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/context.h"
|
#include "app/context.h"
|
||||||
#include "app/doc.h"
|
#include "app/doc.h"
|
||||||
#include "app/script/app_scripting.h"
|
#include "app/script/engine.h"
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
#include "app/site.h"
|
#include "app/site.h"
|
||||||
#include "app/site.h"
|
#include "app/site.h"
|
||||||
#include "app/tx.h"
|
#include "app/tx.h"
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void App_open(script::ContextHandle handle)
|
int App_open(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const char* filename = luaL_checkstring(L, 1);
|
||||||
const char* filename = ctx.requireString(1);
|
|
||||||
|
|
||||||
app::Context* appCtx = App::instance()->context();
|
app::Context* ctx = App::instance()->context();
|
||||||
Doc* oldDoc = appCtx->activeDocument();
|
Doc* oldDoc = ctx->activeDocument();
|
||||||
|
|
||||||
Command* openCommand =
|
Command* openCommand =
|
||||||
Commands::instance()->byId(CommandId::OpenFile());
|
Commands::instance()->byId(CommandId::OpenFile());
|
||||||
Params params;
|
Params params;
|
||||||
params.set("filename", filename);
|
params.set("filename", filename);
|
||||||
appCtx->executeCommand(openCommand, params);
|
ctx->executeCommand(openCommand, params);
|
||||||
|
|
||||||
Doc* newDoc = appCtx->activeDocument();
|
Doc* newDoc = ctx->activeDocument();
|
||||||
if (newDoc != oldDoc)
|
if (newDoc != oldDoc)
|
||||||
push_sprite(ctx, newDoc->sprite());
|
push_ptr(L, newDoc->sprite());
|
||||||
else
|
else
|
||||||
ctx.pushNull();
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_exit(script::ContextHandle handle)
|
int App_exit(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
app::Context* ctx = App::instance()->context();
|
||||||
app::Context* appCtx = App::instance()->context();
|
if (ctx && ctx->isUIAvailable()) {
|
||||||
if (appCtx && appCtx->isUIAvailable()) {
|
|
||||||
Command* exitCommand =
|
Command* exitCommand =
|
||||||
Commands::instance()->byId(CommandId::Exit());
|
Commands::instance()->byId(CommandId::Exit());
|
||||||
appCtx->executeCommand(exitCommand);
|
ctx->executeCommand(exitCommand);
|
||||||
}
|
}
|
||||||
ctx.pushUndefined();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_transaction(script::ContextHandle handle)
|
int App_transaction(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
int top = lua_gettop(L);
|
||||||
if (ctx.isCallable(1)) {
|
int nresults = 0;
|
||||||
|
if (lua_isfunction(L, 1)) {
|
||||||
Tx tx; // Create a new transaction so it exists in the whole
|
Tx tx; // Create a new transaction so it exists in the whole
|
||||||
// duration of the argument function call.
|
// duration of the argument function call.
|
||||||
ctx.copy(1);
|
lua_pushvalue(L, -1);
|
||||||
ctx.call(0);
|
if (lua_pcall(L, 0, LUA_MULTRET, 0) == LUA_OK)
|
||||||
tx.commit();
|
tx.commit();
|
||||||
|
nresults = lua_gettop(L) - top;
|
||||||
}
|
}
|
||||||
else
|
return nresults;
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_undo(script::ContextHandle handle)
|
int App_undo(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
app::Context* ctx = App::instance()->context();
|
||||||
app::Context* appCtx = App::instance()->context();
|
if (ctx) {
|
||||||
if (appCtx) {
|
|
||||||
Command* undo = Commands::instance()->byId(CommandId::Undo());
|
Command* undo = Commands::instance()->byId(CommandId::Undo());
|
||||||
appCtx->executeCommand(undo);
|
ctx->executeCommand(undo);
|
||||||
}
|
}
|
||||||
ctx.pushUndefined();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_redo(script::ContextHandle handle)
|
int App_redo(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
app::Context* ctx = App::instance()->context();
|
||||||
app::Context* appCtx = App::instance()->context();
|
if (ctx) {
|
||||||
if (appCtx) {
|
|
||||||
Command* redo = Commands::instance()->byId(CommandId::Redo());
|
Command* redo = Commands::instance()->byId(CommandId::Redo());
|
||||||
appCtx->executeCommand(redo);
|
ctx->executeCommand(redo);
|
||||||
}
|
}
|
||||||
ctx.pushUndefined();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_get_activeSprite(script::ContextHandle handle)
|
int App_get_activeSprite(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
app::Context* ctx = App::instance()->context();
|
||||||
app::Context* appCtx = App::instance()->context();
|
Doc* doc = ctx->activeDocument();
|
||||||
Doc* doc = appCtx->activeDocument();
|
|
||||||
if (doc)
|
if (doc)
|
||||||
push_sprite(ctx, doc->sprite());
|
push_ptr(L, doc->sprite());
|
||||||
else
|
else
|
||||||
ctx.pushNull();
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_get_activeImage(script::ContextHandle handle)
|
int App_get_activeImage(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
app::Context* ctx = App::instance()->context();
|
||||||
app::Context* appCtx = App::instance()->context();
|
Site site = ctx->activeSite();
|
||||||
Site site = appCtx->activeSite();
|
|
||||||
if (site.image())
|
if (site.image())
|
||||||
push_image(ctx, site.image());
|
push_ptr(L, site.image());
|
||||||
else
|
else
|
||||||
ctx.pushNull();
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_get_site(script::ContextHandle handle)
|
int App_get_site(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
app::Context* ctx = App::instance()->context();
|
||||||
app::Context* appCtx = App::instance()->context();
|
Site site = ctx->activeSite();
|
||||||
Site site = appCtx->activeSite();
|
push_obj(L, site);
|
||||||
push_site(ctx, site);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_get_pixelColor(script::ContextHandle handle)
|
int App_get_version(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
lua_pushstring(L, VERSION);
|
||||||
ctx.newObject("PixelColor", nullptr, nullptr);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App_get_version(script::ContextHandle handle)
|
const luaL_Reg App_methods[] = {
|
||||||
{
|
{ "open", App_open },
|
||||||
script::Context ctx(handle);
|
{ "exit", App_exit },
|
||||||
ctx.pushString(VERSION);
|
{ "transaction", App_transaction },
|
||||||
}
|
{ "undo", App_undo },
|
||||||
|
{ "redo", App_redo },
|
||||||
const script::FunctionEntry App_methods[] = {
|
{ nullptr, nullptr }
|
||||||
{ "open", App_open, 1 },
|
|
||||||
{ "exit", App_exit, 0 },
|
|
||||||
{ "transaction", App_transaction, 1 },
|
|
||||||
{ "undo", App_undo, 0 },
|
|
||||||
{ "redo", App_redo, 0 },
|
|
||||||
{ nullptr, nullptr, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const script::PropertyEntry App_props[] = {
|
const Property App_properties[] = {
|
||||||
{ "activeSprite", App_get_activeSprite, nullptr },
|
{ "activeSprite", App_get_activeSprite, nullptr },
|
||||||
{ "activeImage", App_get_activeImage, nullptr },
|
{ "activeImage", App_get_activeImage, nullptr },
|
||||||
{ "pixelColor", App_get_pixelColor, nullptr },
|
|
||||||
{ "version", App_get_version, nullptr },
|
{ "version", App_get_version, nullptr },
|
||||||
{ "site", App_get_site, nullptr },
|
{ "site", App_get_site, nullptr },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void register_app_object(script::Context& ctx)
|
DEF_MTNAME(App);
|
||||||
|
|
||||||
|
void register_app_object(lua_State* L)
|
||||||
{
|
{
|
||||||
ctx.pushGlobalObject();
|
REG_CLASS(L, App);
|
||||||
ctx.registerObject(-1, "app", App_methods, App_props);
|
REG_CLASS_PROPERTIES(L, App);
|
||||||
ctx.pop();
|
|
||||||
|
lua_newtable(L); // Create a table which will be the "app" object
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
luaL_getmetatable(L, get_mtname<App>());
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
lua_setglobal(L, "app");
|
||||||
|
lua_pop(L, 1); // Pop app table
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
// Aseprite
|
|
||||||
// Copyright (C) 2001-2018 David Capello
|
|
||||||
//
|
|
||||||
// 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/app_scripting.h"
|
|
||||||
|
|
||||||
#include "app/doc.h"
|
|
||||||
|
|
||||||
namespace app {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const script::ConstantEntry ColorMode_constants[] = {
|
|
||||||
{ "RGB", double(IMAGE_RGB) },
|
|
||||||
{ "GRAYSCALE", double(IMAGE_GRAYSCALE) },
|
|
||||||
{ "INDEXED", double(IMAGE_INDEXED) },
|
|
||||||
{ nullptr, 0.0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_app_object(script::Context& ctx);
|
|
||||||
void register_console_object(script::Context& ctx);
|
|
||||||
|
|
||||||
void register_image_class(script::index_t idx, script::Context& ctx);
|
|
||||||
void register_pixel_color_class(script::index_t idx, script::Context& ctx);
|
|
||||||
void register_point_class(script::index_t idx, script::Context& ctx);
|
|
||||||
void register_rectangle_class(script::index_t idx, script::Context& ctx);
|
|
||||||
void register_selection_class(script::index_t idx, script::Context& ctx);
|
|
||||||
void register_site_class(script::index_t idx, script::Context& ctx);
|
|
||||||
void register_size_class(script::index_t idx, script::Context& ctx);
|
|
||||||
void register_sprite_class(script::index_t idx, script::Context& ctx);
|
|
||||||
|
|
||||||
AppScripting::AppScripting(script::EngineDelegate* delegate)
|
|
||||||
: script::Engine(delegate)
|
|
||||||
{
|
|
||||||
auto& ctx = context();
|
|
||||||
ctx.setContextUserData(this);
|
|
||||||
|
|
||||||
// Register global objects (app and console)
|
|
||||||
register_app_object(ctx);
|
|
||||||
register_console_object(ctx);
|
|
||||||
|
|
||||||
ctx.pushGlobalObject();
|
|
||||||
|
|
||||||
// Register constants
|
|
||||||
{
|
|
||||||
ctx.newObject();
|
|
||||||
ctx.registerConstants(-1, ColorMode_constants);
|
|
||||||
ctx.setProp(-2, "ColorMode");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register classes/prototypes
|
|
||||||
|
|
||||||
register_image_class(-1, ctx);
|
|
||||||
register_pixel_color_class(-1, ctx);
|
|
||||||
register_point_class(-1, ctx);
|
|
||||||
register_rectangle_class(-1, ctx);
|
|
||||||
register_selection_class(-1, ctx);
|
|
||||||
register_site_class(-1, ctx);
|
|
||||||
register_size_class(-1, ctx);
|
|
||||||
register_sprite_class(-1, ctx);
|
|
||||||
|
|
||||||
ctx.pop(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
AppScripting* get_engine(script::Context& ctx)
|
|
||||||
{
|
|
||||||
return (AppScripting*)ctx.getContextUserData();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
// Aseprite
|
|
||||||
// Copyright (C) 2001-2018 David Capello
|
|
||||||
//
|
|
||||||
// This program is distributed under the terms of
|
|
||||||
// the End-User License Agreement for Aseprite.
|
|
||||||
|
|
||||||
#ifndef APP_SCRIPTING_H_INCLUDED
|
|
||||||
#define APP_SCRIPTING_H_INCLUDED
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef ENABLE_SCRIPTING
|
|
||||||
#error ENABLE_SCRIPTING must be defined
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "doc/object_id.h"
|
|
||||||
#include "gfx/fwd.h"
|
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace doc {
|
|
||||||
class Image;
|
|
||||||
class Sprite;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace app {
|
|
||||||
class Site;
|
|
||||||
|
|
||||||
class AppScripting : public script::Engine {
|
|
||||||
public:
|
|
||||||
AppScripting(script::EngineDelegate* delegate);
|
|
||||||
};
|
|
||||||
|
|
||||||
AppScripting* get_engine(script::Context& ctx);
|
|
||||||
|
|
||||||
void push_image(script::Context& ctx, doc::Image* image);
|
|
||||||
void push_new_point(script::Context& ctx, const gfx::Point& pt);
|
|
||||||
void push_new_rectangle(script::Context& ctx, const gfx::Rect& rc);
|
|
||||||
void push_new_size(script::Context& ctx, const gfx::Size& rc);
|
|
||||||
void push_site(script::Context& ctx, app::Site& site);
|
|
||||||
void push_sprite(script::Context& ctx, doc::Sprite* sprite);
|
|
||||||
void push_sprite_selection(script::Context& ctx, doc::Sprite* sprite);
|
|
||||||
|
|
||||||
gfx::Point convert_args_into_point(script::Context& ctx);
|
|
||||||
gfx::Rect convert_args_into_rectangle(script::Context& ctx);
|
|
||||||
gfx::Size convert_args_into_size(script::Context& ctx);
|
|
||||||
|
|
||||||
} // namespace app
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,74 +0,0 @@
|
||||||
// Aseprite
|
|
||||||
// Copyright (C) 2001-2017 David Capello
|
|
||||||
//
|
|
||||||
// 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/app.h"
|
|
||||||
#include "app/console.h"
|
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace app {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void print(const char* str)
|
|
||||||
{
|
|
||||||
if (str) {
|
|
||||||
std::cout << str << std::endl; // New line + flush
|
|
||||||
|
|
||||||
if (App::instance()->isGui()) {
|
|
||||||
Console().printf("%s\n", str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console_assert(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
if (!ctx.toBool(1))
|
|
||||||
ctx.error(ctx.toString(1));
|
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Console_log(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
std::string output;
|
|
||||||
int top = ctx.top();
|
|
||||||
const char* s;
|
|
||||||
for (int n=1; n<top; ++n) {
|
|
||||||
s = ctx.toString(n);
|
|
||||||
if (s == nullptr)
|
|
||||||
break;
|
|
||||||
if (n > 1)
|
|
||||||
output += " ";
|
|
||||||
output += s;
|
|
||||||
}
|
|
||||||
if (!output.empty())
|
|
||||||
print(output.c_str());
|
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
const script::FunctionEntry Console_methods[] = {
|
|
||||||
{ "assert", Console_assert, 2 },
|
|
||||||
{ "log", Console_log, 1 },
|
|
||||||
{ nullptr, nullptr, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void register_console_object(script::Context& ctx)
|
|
||||||
{
|
|
||||||
ctx.pushGlobalObject();
|
|
||||||
ctx.registerObject(-1, "console", Console_methods, nullptr);
|
|
||||||
ctx.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace app
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2001-2018 David Capello
|
||||||
|
//
|
||||||
|
// 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/app.h"
|
||||||
|
#include "app/console.h"
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
|
#include "base/fstream_path.h"
|
||||||
|
#include "doc/color_mode.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int print(lua_State* L)
|
||||||
|
{
|
||||||
|
std::string output;
|
||||||
|
int n = lua_gettop(L); /* number of arguments */
|
||||||
|
int i;
|
||||||
|
lua_getglobal(L, "tostring");
|
||||||
|
for (i=1; i<=n; i++) {
|
||||||
|
lua_pushvalue(L, -1); // function to be called
|
||||||
|
lua_pushvalue(L, i); // value to print
|
||||||
|
lua_call(L, 1, 1);
|
||||||
|
size_t l;
|
||||||
|
const char* s = lua_tolstring(L, -1, &l); // get result
|
||||||
|
if (s == nullptr)
|
||||||
|
return luaL_error(L, "'tostring' must return a string to 'print'");
|
||||||
|
if (i > 1)
|
||||||
|
output.push_back('\t');
|
||||||
|
output.insert(output.size(), s, l);
|
||||||
|
lua_pop(L, 1); // pop result
|
||||||
|
}
|
||||||
|
if (!output.empty()) {
|
||||||
|
std::printf("%s\n", output.c_str());
|
||||||
|
std::fflush(stdout);
|
||||||
|
if (App::instance()->isGui())
|
||||||
|
Console().printf("%s\n", output.c_str());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void register_app_object(lua_State* L);
|
||||||
|
void register_app_pixel_color_object(lua_State* L);
|
||||||
|
|
||||||
|
void register_image_class(lua_State* L);
|
||||||
|
void register_point_class(lua_State* L);
|
||||||
|
void register_rect_class(lua_State* L);
|
||||||
|
void register_selection_class(lua_State* L);
|
||||||
|
void register_site_class(lua_State* L);
|
||||||
|
void register_size_class(lua_State* L);
|
||||||
|
void register_sprite_class(lua_State* L);
|
||||||
|
|
||||||
|
Engine::Engine(EngineDelegate* delegate)
|
||||||
|
: L(luaL_newstate())
|
||||||
|
, m_delegate(delegate)
|
||||||
|
, m_printLastResult(false)
|
||||||
|
{
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
|
||||||
|
// Standard Lua libraries
|
||||||
|
luaL_requiref(L, LUA_GNAME, luaopen_base, 1);
|
||||||
|
luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1);
|
||||||
|
luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1);
|
||||||
|
luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1);
|
||||||
|
lua_pop(L, 4);
|
||||||
|
|
||||||
|
// Our print() impl
|
||||||
|
lua_register(L, "print", print);
|
||||||
|
|
||||||
|
// Generic code used by metatables
|
||||||
|
run_mt_index_code(L);
|
||||||
|
|
||||||
|
// Register global app object
|
||||||
|
register_app_object(L);
|
||||||
|
register_app_pixel_color_object(L);
|
||||||
|
|
||||||
|
// Register constants
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_setglobal(L, "ColorMode");
|
||||||
|
setfield_integer(L, "RGB", doc::ColorMode::RGB);
|
||||||
|
setfield_integer(L, "GRAYSCALE", doc::ColorMode::GRAYSCALE);
|
||||||
|
setfield_integer(L, "INDEXED", doc::ColorMode::INDEXED);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
// Register classes/prototypes
|
||||||
|
register_image_class(L);
|
||||||
|
register_point_class(L);
|
||||||
|
register_rect_class(L);
|
||||||
|
register_selection_class(L);
|
||||||
|
register_site_class(L);
|
||||||
|
register_size_class(L);
|
||||||
|
register_sprite_class(L);
|
||||||
|
|
||||||
|
// Check that we have a clean start (without dirty in the stack)
|
||||||
|
ASSERT(lua_gettop(L) == top);
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine::~Engine()
|
||||||
|
{
|
||||||
|
lua_close(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::printLastResult()
|
||||||
|
{
|
||||||
|
m_printLastResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Engine::evalCode(const std::string& code,
|
||||||
|
const std::string& filename)
|
||||||
|
{
|
||||||
|
bool ok = true;
|
||||||
|
if (luaL_loadbuffer(L, code.c_str(), code.size(), filename.c_str()) ||
|
||||||
|
lua_pcall(L, 0, 1, 0)) {
|
||||||
|
// Error case
|
||||||
|
std::string err;
|
||||||
|
const char* s = lua_tostring(L, -1);
|
||||||
|
if (s)
|
||||||
|
m_delegate->onConsolePrint(s);
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Code was executed correctly
|
||||||
|
if (m_printLastResult) {
|
||||||
|
if (!lua_isnone(L, -1)) {
|
||||||
|
const char* result = lua_tostring(L, -1);
|
||||||
|
if (result)
|
||||||
|
m_delegate->onConsolePrint(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Engine::evalFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::stringstream buf;
|
||||||
|
{
|
||||||
|
std::ifstream s(FSTREAM_PATH(filename));
|
||||||
|
buf << s.rdbuf();
|
||||||
|
}
|
||||||
|
return evalCode(buf.str(), filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
|
} // namespace app
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2001-2018 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_SCRIPTING_H_INCLUDED
|
||||||
|
#define APP_SCRIPTING_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef ENABLE_SCRIPTING
|
||||||
|
#error ENABLE_SCRIPTING must be defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "doc/object_id.h"
|
||||||
|
#include "gfx/fwd.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
namespace doc {
|
||||||
|
class Image;
|
||||||
|
class Sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
class Site;
|
||||||
|
|
||||||
|
namespace script {
|
||||||
|
|
||||||
|
class EngineDelegate {
|
||||||
|
public:
|
||||||
|
virtual ~EngineDelegate() { }
|
||||||
|
virtual void onConsolePrint(const char* text) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StdoutEngineDelegate : public EngineDelegate {
|
||||||
|
public:
|
||||||
|
void onConsolePrint(const char* text) override {
|
||||||
|
std::printf("%s\n", text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Engine {
|
||||||
|
public:
|
||||||
|
Engine(EngineDelegate* delegate);
|
||||||
|
~Engine();
|
||||||
|
|
||||||
|
void printLastResult();
|
||||||
|
bool evalCode(const std::string& code,
|
||||||
|
const std::string& filename = std::string());
|
||||||
|
bool evalFile(const std::string& filename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
lua_State* L;
|
||||||
|
EngineDelegate* m_delegate;
|
||||||
|
bool m_printLastResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
void push_sprite_selection(lua_State* L, doc::Sprite* sprite);
|
||||||
|
|
||||||
|
gfx::Point convert_args_into_point(lua_State* L, int index);
|
||||||
|
gfx::Rect convert_args_into_rect(lua_State* L, int index);
|
||||||
|
gfx::Size convert_args_into_size(lua_State* L, int index);
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2015-2017 David Capello
|
// Copyright (C) 2015-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
|
@ -8,95 +8,78 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
#include "doc/image.h"
|
#include "doc/image.h"
|
||||||
#include "script/engine.h"
|
#include "doc/primitives.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char* kTag = "Image";
|
int Image_new(lua_State* L)
|
||||||
|
|
||||||
void Image_new(script::ContextHandle handle)
|
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
lua_pushnil(L); // TODO
|
||||||
ctx.pushNull(); // TODO
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image_putPixel(script::ContextHandle handle)
|
int Image_putPixel(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto image = get_ptr<doc::Image>(L, 1);
|
||||||
auto image = (doc::Image*)ctx.toUserData(0, kTag);
|
const int x = lua_tointeger(L, 2);
|
||||||
int x = ctx.requireInt(1);
|
const int y = lua_tointeger(L, 3);
|
||||||
int y = ctx.requireInt(2);
|
const doc::color_t color = lua_tointeger(L, 4);
|
||||||
doc::color_t color = ctx.requireUInt(3);
|
doc::put_pixel(image, x, y, color);
|
||||||
|
return 0;
|
||||||
if (image) {
|
|
||||||
image->putPixel(x, y, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image_getPixel(script::ContextHandle handle)
|
int Image_getPixel(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto image = get_ptr<doc::Image>(L, 1);
|
||||||
auto image = (doc::Image*)ctx.toUserData(0, kTag);
|
const int x = lua_tointeger(L, 2);
|
||||||
int x = ctx.requireInt(1);
|
const int y = lua_tointeger(L, 3);
|
||||||
int y = ctx.requireInt(2);
|
const doc::color_t color = doc::get_pixel(image, x, y);
|
||||||
|
lua_pushinteger(L, color);
|
||||||
if (image) {
|
return 1;
|
||||||
doc::color_t color = image->getPixel(x, y);
|
|
||||||
ctx.pushUInt(color);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image_get_width(script::ContextHandle handle)
|
int Image_get_width(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto image = get_ptr<doc::Image>(L, 1);
|
||||||
auto image = (doc::Image*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, image->width());
|
||||||
if (image)
|
return 1;
|
||||||
ctx.pushInt(image->width());
|
|
||||||
else
|
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image_get_height(script::ContextHandle handle)
|
int Image_get_height(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto image = get_ptr<doc::Image>(L, 1);
|
||||||
auto image = (doc::Image*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, image->height());
|
||||||
if (image)
|
return 1;
|
||||||
ctx.pushInt(image->height());
|
|
||||||
else
|
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const script::FunctionEntry Image_methods[] = {
|
const luaL_Reg Image_methods[] = {
|
||||||
{ "getPixel", Image_getPixel, 2 },
|
{ "getPixel", Image_getPixel },
|
||||||
{ "putPixel", Image_putPixel, 3 },
|
{ "putPixel", Image_putPixel },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
const script::PropertyEntry Image_props[] = {
|
const Property Image_properties[] = {
|
||||||
{ "width", Image_get_width, nullptr },
|
{ "width", Image_get_width, nullptr },
|
||||||
{ "height", Image_get_height, nullptr },
|
{ "height", Image_get_height, nullptr },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void register_image_class(script::index_t idx, script::Context& ctx)
|
DEF_MTNAME(doc::Image);
|
||||||
|
|
||||||
|
void register_image_class(lua_State* L)
|
||||||
{
|
{
|
||||||
ctx.registerClass(idx, kTag,
|
using doc::Image;
|
||||||
Image_new, 0,
|
REG_CLASS(L, Image);
|
||||||
Image_methods, Image_props);
|
REG_CLASS_NEW(L, Image);
|
||||||
}
|
REG_CLASS_PROPERTIES(L, Image);
|
||||||
|
|
||||||
void push_image(script::Context& ctx, doc::Image* image)
|
|
||||||
{
|
|
||||||
ctx.newObject(kTag, image, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2018 David Capello
|
||||||
|
//
|
||||||
|
// 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/luacpp.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
|
static const char* mt_index_code =
|
||||||
|
"__generic_mt_index = function(t, k) "
|
||||||
|
" local mt = getmetatable(t) "
|
||||||
|
" local f = mt[k] "
|
||||||
|
" if f then return f end "
|
||||||
|
" f = mt.__getters[k] "
|
||||||
|
" if f then return f(t) end "
|
||||||
|
" if type(t) == 'table' then return rawget(t, k) end "
|
||||||
|
" error('Field '..tostring(k)..' does not exist')"
|
||||||
|
"end "
|
||||||
|
"__generic_mt_newindex = function(t, k, v) "
|
||||||
|
" local mt = getmetatable(t) "
|
||||||
|
" local f = mt[k] "
|
||||||
|
" if f then return f end "
|
||||||
|
" f = mt.__setters[k] "
|
||||||
|
" if f then return f(t, v) end "
|
||||||
|
" if type(t) == 'table' then return rawset(t, k, v) end "
|
||||||
|
" error('Cannot set field '..tostring(k))"
|
||||||
|
"end";
|
||||||
|
|
||||||
|
void run_mt_index_code(lua_State* L)
|
||||||
|
{
|
||||||
|
luaL_dostring(L, mt_index_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_mt_getters_setters(lua_State* L,
|
||||||
|
const char* tname,
|
||||||
|
const Property* properties)
|
||||||
|
{
|
||||||
|
const int top = lua_gettop(L);
|
||||||
|
|
||||||
|
bool withGetters = false;
|
||||||
|
bool withSetters = false;
|
||||||
|
for (auto p=properties; p->name; ++p) {
|
||||||
|
if (p->getter) withGetters = true;
|
||||||
|
if (p->setter) withSetters = true;
|
||||||
|
}
|
||||||
|
ASSERT(withGetters || withSetters);
|
||||||
|
|
||||||
|
luaL_getmetatable(L, tname);
|
||||||
|
if (withGetters) {
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_setfield(L, -3, "__getters");
|
||||||
|
for (auto p=properties; p->name; ++p) {
|
||||||
|
if (p->getter) {
|
||||||
|
lua_pushcclosure(L, p->getter, 0);
|
||||||
|
lua_setfield(L, -2, p->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
if (withSetters) {
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_setfield(L, -3, "__setters");
|
||||||
|
for (auto p=properties; p->name; ++p) {
|
||||||
|
if (p->setter) {
|
||||||
|
lua_pushcclosure(L, p->setter, 0);
|
||||||
|
lua_setfield(L, -2, p->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
ASSERT(lua_gettop(L) == top);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
|
} // namespace app
|
|
@ -0,0 +1,118 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2018 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_SCRIPT_LUACPP_H_INCLUDED
|
||||||
|
#define APP_SCRIPT_LUACPP_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "lua.h"
|
||||||
|
#include "lualib.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
|
// Some of these auxiliary methods are based on code from the Skia
|
||||||
|
// library (SkLua.cpp file) by Google Inc.
|
||||||
|
|
||||||
|
template <typename T> const char* get_mtname();
|
||||||
|
#define DEF_MTNAME(T) \
|
||||||
|
template <> const char* get_mtname<T>() { \
|
||||||
|
return #T "_Metatable"; \
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args> T* push_new(lua_State* L, Args&&... args) {
|
||||||
|
T* addr = (T*)lua_newuserdata(L, sizeof(T));
|
||||||
|
new (addr) T(std::forward<Args>(args)...);
|
||||||
|
luaL_getmetatable(L, get_mtname<T>());
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void push_obj(lua_State* L, const T& obj) {
|
||||||
|
new (lua_newuserdata(L, sizeof(T))) T(obj);
|
||||||
|
luaL_getmetatable(L, get_mtname<T>());
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void push_obj(lua_State* L, T&& obj) {
|
||||||
|
using RRT = typename std::remove_reference<T>::type;
|
||||||
|
new (lua_newuserdata(L, sizeof(RRT))) RRT(std::move(obj));
|
||||||
|
luaL_getmetatable(L, get_mtname<RRT>());
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T* push_ptr(lua_State* L, T* ptr) {
|
||||||
|
*(T**)lua_newuserdata(L, sizeof(T*)) = ptr;
|
||||||
|
luaL_getmetatable(L, get_mtname<T>());
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T* get_ptr(lua_State* L, int index) {
|
||||||
|
return *(T**)luaL_checkudata(L, index, get_mtname<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T* get_obj(lua_State* L, int index) {
|
||||||
|
return (T*)luaL_checkudata(L, index, get_mtname<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns nil if the index doesn't have the given metatable
|
||||||
|
template <typename T> T* may_get_obj(lua_State* L, int index) {
|
||||||
|
return (T*)luaL_testudata(L, index, get_mtname<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool lua2bool(lua_State* L, int index) {
|
||||||
|
return !!lua_toboolean(L, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void setfield_integer(lua_State* L, const char* key, const T& value) {
|
||||||
|
lua_pushinteger(L, int(value));
|
||||||
|
lua_setfield(L, -2, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define REG_CLASS(L, T) { \
|
||||||
|
luaL_newmetatable(L, get_mtname<T>()); \
|
||||||
|
lua_getglobal(L, "__generic_mt_index"); \
|
||||||
|
lua_setfield(L, -2, "__index"); \
|
||||||
|
lua_getglobal(L, "__generic_mt_newindex"); \
|
||||||
|
lua_setfield(L, -2, "__newindex"); \
|
||||||
|
luaL_setfuncs(L, T##_methods, 0); \
|
||||||
|
lua_pop(L, 1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define REG_CLASS_NEW(L, T) { \
|
||||||
|
lua_pushcfunction(L, T##_new); \
|
||||||
|
lua_setglobal(L, #T); \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Property {
|
||||||
|
const char* name;
|
||||||
|
lua_CFunction getter;
|
||||||
|
lua_CFunction setter;
|
||||||
|
};
|
||||||
|
|
||||||
|
void run_mt_index_code(lua_State* L);
|
||||||
|
void create_mt_getters_setters(lua_State* L,
|
||||||
|
const char* tname,
|
||||||
|
const Property* properties);
|
||||||
|
|
||||||
|
#define REG_CLASS_PROPERTIES(L, T) { \
|
||||||
|
luaL_getmetatable(L, get_mtname<T>()); \
|
||||||
|
create_mt_getters_setters(L, get_mtname<T>(), T##_properties); \
|
||||||
|
lua_pop(L, 1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,101 +0,0 @@
|
||||||
// Aseprite
|
|
||||||
// Copyright (C) 2017 David Capello
|
|
||||||
//
|
|
||||||
// This program is distributed under the terms of
|
|
||||||
// the End-User License Agreement for Aseprite.
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "doc/color.h"
|
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
namespace app {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const char* kTag = "PixelColor";
|
|
||||||
|
|
||||||
void PixelColor_new(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
ctx.pushUndefined(); // Cannot create new pixel colors (just subobject of "app")
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelColor_rgba(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
const int r = ctx.requireUInt(1);
|
|
||||||
const int g = ctx.requireUInt(2);
|
|
||||||
const int b = ctx.requireUInt(3);
|
|
||||||
const int a = (ctx.isUndefined(4) ? 255: ctx.requireUInt(4));
|
|
||||||
ctx.pushUInt(doc::rgba(r, g, b, a));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelColor_rgbaR(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
ctx.pushUInt(doc::rgba_getr(ctx.requireUInt(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelColor_rgbaG(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
ctx.pushUInt(doc::rgba_getg(ctx.requireUInt(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelColor_rgbaB(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
ctx.pushUInt(doc::rgba_getb(ctx.requireUInt(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelColor_rgbaA(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
ctx.pushUInt(doc::rgba_geta(ctx.requireUInt(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelColor_graya(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
int v = ctx.requireUInt(1);
|
|
||||||
int a = (ctx.isUndefined(2) ? 255: ctx.requireUInt(2));
|
|
||||||
ctx.pushUInt(doc::graya(v, a));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelColor_grayaV(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
ctx.pushUInt(doc::graya_getv(ctx.requireUInt(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelColor_grayaA(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
ctx.pushUInt(doc::graya_geta(ctx.requireUInt(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
const script::FunctionEntry PixelColor_methods[] = {
|
|
||||||
{ "rgba", PixelColor_rgba, 4 },
|
|
||||||
{ "rgbaR", PixelColor_rgbaR, 1 },
|
|
||||||
{ "rgbaG", PixelColor_rgbaG, 1 },
|
|
||||||
{ "rgbaB", PixelColor_rgbaB, 1 },
|
|
||||||
{ "rgbaA", PixelColor_rgbaA, 1 },
|
|
||||||
{ "graya", PixelColor_graya, 2 },
|
|
||||||
{ "grayaV", PixelColor_grayaV, 1 },
|
|
||||||
{ "grayaA", PixelColor_grayaA, 1 },
|
|
||||||
{ nullptr, nullptr, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void register_pixel_color_class(script::index_t idx, script::Context& ctx)
|
|
||||||
{
|
|
||||||
ctx.registerClass(idx, kTag,
|
|
||||||
PixelColor_new, 0,
|
|
||||||
PixelColor_methods, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace app
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2017-2018 David Capello
|
||||||
|
//
|
||||||
|
// 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/luacpp.h"
|
||||||
|
#include "doc/color.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int PixelColor_rgba(lua_State* L)
|
||||||
|
{
|
||||||
|
const int r = lua_tointeger(L, 1);
|
||||||
|
const int g = lua_tointeger(L, 2);
|
||||||
|
const int b = lua_tointeger(L, 3);
|
||||||
|
const int a = (lua_isnoneornil(L, 4) ? 255: lua_tointeger(L, 4));
|
||||||
|
lua_pushinteger(L, doc::rgba(r, g, b, a));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PixelColor_rgbaR(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, doc::rgba_getr(lua_tointeger(L, 1)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PixelColor_rgbaG(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, doc::rgba_getg(lua_tointeger(L, 1)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PixelColor_rgbaB(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, doc::rgba_getb(lua_tointeger(L, 1)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PixelColor_rgbaA(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, doc::rgba_geta(lua_tointeger(L, 1)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PixelColor_graya(lua_State* L)
|
||||||
|
{
|
||||||
|
int v = lua_tointeger(L, 1);
|
||||||
|
int a = (lua_isnoneornil(L, 2) ? 255: lua_tointeger(L, 2));
|
||||||
|
lua_pushinteger(L, doc::graya(v, a));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PixelColor_grayaV(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, doc::graya_getv(lua_tointeger(L, 1)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PixelColor_grayaA(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushinteger(L, doc::graya_geta(lua_tointeger(L, 1)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const luaL_Reg PixelColor_methods[] = {
|
||||||
|
{ "rgba", PixelColor_rgba },
|
||||||
|
{ "rgbaR", PixelColor_rgbaR },
|
||||||
|
{ "rgbaG", PixelColor_rgbaG },
|
||||||
|
{ "rgbaB", PixelColor_rgbaB },
|
||||||
|
{ "rgbaA", PixelColor_rgbaA },
|
||||||
|
{ "graya", PixelColor_graya },
|
||||||
|
{ "grayaV", PixelColor_grayaV },
|
||||||
|
{ "grayaA", PixelColor_grayaA },
|
||||||
|
{ nullptr, nullptr }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void register_app_pixel_color_object(lua_State* L)
|
||||||
|
{
|
||||||
|
lua_getglobal(L, "app");
|
||||||
|
lua_newtable(L); // New table for pixelColor
|
||||||
|
lua_pushstring(L, "pixelColor");
|
||||||
|
lua_pushvalue(L, -2); // Copy table
|
||||||
|
lua_rawset(L, -4);
|
||||||
|
luaL_setfuncs(L, PixelColor_methods, 0);
|
||||||
|
lua_pop(L, 2); // Pop table & app global
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
|
} // namespace app
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2017 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
|
@ -8,111 +8,96 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
#include "gfx/point.h"
|
#include "gfx/point.h"
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char* kTag = "Point";
|
gfx::Point Point_new(lua_State* L, int index)
|
||||||
|
|
||||||
void Point_finalize(script::ContextHandle handle, void* data)
|
|
||||||
{
|
{
|
||||||
auto pt = (gfx::Point*)data;
|
gfx::Point pt(0, 0);
|
||||||
delete pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Point_new(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
auto pt = new gfx::Point(0, 0);
|
|
||||||
|
|
||||||
// Copy other rectangle
|
// Copy other rectangle
|
||||||
if (ctx.isUserData(1, kTag)) {
|
if (auto pt2 = may_get_obj<gfx::Point>(L, index)) {
|
||||||
auto pt2 = (gfx::Point*)ctx.toUserData(1, kTag);
|
pt = *pt2;
|
||||||
*pt = *pt2;
|
|
||||||
}
|
}
|
||||||
// Convert { x, y } into a Point
|
// Convert { x, y } into a Point
|
||||||
else if (ctx.isObject(1)) {
|
else if (lua_istable(L, index)) {
|
||||||
ctx.getProp(1, "x");
|
lua_getfield(L, index, "x");
|
||||||
ctx.getProp(1, "y");
|
lua_getfield(L, index, "y");
|
||||||
pt->x = ctx.toInt(-2);
|
pt.x = lua_tointeger(L, -2);
|
||||||
pt->y = ctx.toInt(-1);
|
pt.y = lua_tointeger(L, -1);
|
||||||
ctx.pop(2);
|
lua_pop(L, 2);
|
||||||
}
|
}
|
||||||
else if (ctx.isNumber(1)) {
|
else {
|
||||||
pt->x = ctx.toInt(1);
|
pt.x = lua_tointeger(L, index);
|
||||||
pt->y = ctx.toInt(2);
|
pt.y = lua_tointeger(L, index+1);
|
||||||
}
|
}
|
||||||
|
return pt;
|
||||||
ctx.newObject(kTag, pt, Point_finalize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Point_get_x(script::ContextHandle handle)
|
int Point_new(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
push_obj(L, Point_new(L, 1));
|
||||||
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
|
return 1;
|
||||||
ASSERT(pt);
|
|
||||||
ctx.pushInt(pt->x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Point_get_y(script::ContextHandle handle)
|
int Point_get_x(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto pt = get_obj<gfx::Point>(L, 1);
|
||||||
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, pt->x);
|
||||||
ctx.pushInt(pt->y);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Point_set_x(script::ContextHandle handle)
|
int Point_get_y(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto pt = get_obj<gfx::Point>(L, 1);
|
||||||
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, pt->y);
|
||||||
ASSERT(pt);
|
return 1;
|
||||||
pt->x = ctx.toInt(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Point_set_y(script::ContextHandle handle)
|
int Point_set_x(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto pt = get_obj<gfx::Point>(L, 1);
|
||||||
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
|
pt->x = lua_tointeger(L, 2);
|
||||||
pt->y = ctx.toInt(1);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const script::FunctionEntry Point_methods[] = {
|
int Point_set_y(lua_State* L)
|
||||||
{ nullptr, nullptr, 0 }
|
{
|
||||||
|
auto pt = get_obj<gfx::Point>(L, 1);
|
||||||
|
pt->y = lua_tointeger(L, 2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const luaL_Reg Point_methods[] = {
|
||||||
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
const script::PropertyEntry Point_props[] = {
|
const Property Point_properties[] = {
|
||||||
{ "x", Point_get_x, Point_set_x },
|
{ "x", Point_get_x, Point_set_x },
|
||||||
{ "y", Point_get_y, Point_set_y },
|
{ "y", Point_get_y, Point_set_y },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void register_point_class(script::index_t idx, script::Context& ctx)
|
DEF_MTNAME(gfx::Point);
|
||||||
|
|
||||||
|
void register_point_class(lua_State* L)
|
||||||
{
|
{
|
||||||
ctx.registerClass(idx, kTag,
|
using gfx::Point;
|
||||||
Point_new, 3,
|
REG_CLASS(L, Point);
|
||||||
Point_methods,
|
REG_CLASS_NEW(L, Point);
|
||||||
Point_props);
|
REG_CLASS_PROPERTIES(L, Point);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_new_point(script::Context& ctx, const gfx::Point& pt)
|
gfx::Point convert_args_into_point(lua_State* L, int index)
|
||||||
{
|
{
|
||||||
ctx.newObject(kTag, new gfx::Point(pt), Point_finalize);
|
return Point_new(L, index);
|
||||||
}
|
|
||||||
|
|
||||||
gfx::Point convert_args_into_point(script::Context& ctx)
|
|
||||||
{
|
|
||||||
gfx::Point result;
|
|
||||||
Point_new(ctx.handle());
|
|
||||||
auto pt = (gfx::Point*)ctx.toUserData(-1, kTag);
|
|
||||||
if (pt)
|
|
||||||
result = *pt;
|
|
||||||
ctx.pop(1);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2017 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
|
@ -8,151 +8,132 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
#include "gfx/rect.h"
|
#include "gfx/rect.h"
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char* kTag = "Rectangle";
|
gfx::Rect Rectangle_new(lua_State* L, int index)
|
||||||
|
|
||||||
void Rectangle_finalize(script::ContextHandle handle, void* data)
|
|
||||||
{
|
{
|
||||||
auto rc = (gfx::Rect*)data;
|
gfx::Rect rc(0, 0, 0, 0);
|
||||||
delete rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rectangle_new(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
auto rc = new gfx::Rect(0, 0, 0, 0);
|
|
||||||
|
|
||||||
// Copy other rectangle
|
// Copy other rectangle
|
||||||
if (ctx.isUserData(1, kTag)) {
|
if (auto rc2 = may_get_obj<gfx::Rect>(L, index)) {
|
||||||
auto rc2 = (gfx::Rect*)ctx.toUserData(1, kTag);
|
rc = *rc2;
|
||||||
*rc = *rc2;
|
|
||||||
}
|
}
|
||||||
// Convert { x, y, width, height } into a Rectangle
|
// Convert { x, y, width, height } into a Rectangle
|
||||||
else if (ctx.isObject(1)) {
|
else if (lua_istable(L, index)) {
|
||||||
ctx.getProp(1, "x");
|
lua_getfield(L, index, "x");
|
||||||
ctx.getProp(1, "y");
|
lua_getfield(L, index, "y");
|
||||||
ctx.getProp(1, "width");
|
lua_getfield(L, index, "width");
|
||||||
ctx.getProp(1, "height");
|
lua_getfield(L, index, "height");
|
||||||
rc->x = ctx.toInt(-4);
|
rc.x = lua_tointeger(L, -4);
|
||||||
rc->y = ctx.toInt(-3);
|
rc.y = lua_tointeger(L, -3);
|
||||||
rc->w = ctx.toInt(-2);
|
rc.w = lua_tointeger(L, -2);
|
||||||
rc->h = ctx.toInt(-1);
|
rc.h = lua_tointeger(L, -1);
|
||||||
ctx.pop(4);
|
lua_pop(L, 4);
|
||||||
}
|
}
|
||||||
else if (ctx.isNumber(1)) {
|
else {
|
||||||
rc->x = ctx.toInt(1);
|
rc.x = lua_tointeger(L, index);
|
||||||
rc->y = ctx.toInt(2);
|
rc.y = lua_tointeger(L, index+1);
|
||||||
rc->w = ctx.toInt(3);
|
rc.w = lua_tointeger(L, index+2);
|
||||||
rc->h = ctx.toInt(4);
|
rc.h = lua_tointeger(L, index+3);
|
||||||
}
|
}
|
||||||
|
return rc;
|
||||||
ctx.newObject(kTag, rc, Rectangle_finalize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle_get_x(script::ContextHandle handle)
|
int Rectangle_new(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
push_obj(L, Rectangle_new(L, 1));
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
return 1;
|
||||||
ASSERT(rc);
|
|
||||||
ctx.pushInt(rc->x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle_get_y(script::ContextHandle handle)
|
int Rectangle_get_x(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto rc = get_obj<gfx::Rect>(L, 1);
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, rc->x);
|
||||||
ctx.pushInt(rc->y);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle_get_width(script::ContextHandle handle)
|
int Rectangle_get_y(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto rc = get_obj<gfx::Rect>(L, 1);
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, rc->y);
|
||||||
ASSERT(rc);
|
return 1;
|
||||||
ctx.pushInt(rc->w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle_get_height(script::ContextHandle handle)
|
int Rectangle_get_width(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto rc = get_obj<gfx::Rect>(L, 1);
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, rc->w);
|
||||||
ASSERT(rc);
|
return 1;
|
||||||
ctx.pushInt(rc->h);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle_set_x(script::ContextHandle handle)
|
int Rectangle_get_height(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto rc = get_obj<gfx::Rect>(L, 1);
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, rc->h);
|
||||||
ASSERT(rc);
|
return 1;
|
||||||
rc->x = ctx.toInt(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle_set_y(script::ContextHandle handle)
|
int Rectangle_set_x(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto rc = get_obj<gfx::Rect>(L, 1);
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
rc->x = lua_tointeger(L, 2);
|
||||||
rc->y = ctx.toInt(1);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle_set_width(script::ContextHandle handle)
|
int Rectangle_set_y(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto rc = get_obj<gfx::Rect>(L, 1);
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
rc->y = lua_tointeger(L, 2);
|
||||||
ASSERT(rc);
|
return 0;
|
||||||
rc->w = ctx.toInt(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rectangle_set_height(script::ContextHandle handle)
|
int Rectangle_set_width(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto rc = get_obj<gfx::Rect>(L, 1);
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
rc->w = lua_tointeger(L, 2);
|
||||||
ASSERT(rc);
|
return 0;
|
||||||
rc->h = ctx.toInt(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const script::FunctionEntry Rectangle_methods[] = {
|
int Rectangle_set_height(lua_State* L)
|
||||||
{ nullptr, nullptr, 0 }
|
{
|
||||||
|
auto rc = get_obj<gfx::Rect>(L, 1);
|
||||||
|
rc->h = lua_tointeger(L, 2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const luaL_Reg Rectangle_methods[] = {
|
||||||
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
const script::PropertyEntry Rectangle_props[] = {
|
const Property Rectangle_properties[] = {
|
||||||
{ "x", Rectangle_get_x, Rectangle_set_x },
|
{ "x", Rectangle_get_x, Rectangle_set_x },
|
||||||
{ "y", Rectangle_get_y, Rectangle_set_y },
|
{ "y", Rectangle_get_y, Rectangle_set_y },
|
||||||
{ "width", Rectangle_get_width, Rectangle_set_width },
|
{ "width", Rectangle_get_width, Rectangle_set_width },
|
||||||
{ "height", Rectangle_get_height, Rectangle_set_height },
|
{ "height", Rectangle_get_height, Rectangle_set_height },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void register_rectangle_class(script::index_t idx, script::Context& ctx)
|
DEF_MTNAME(gfx::Rect);
|
||||||
|
|
||||||
|
void register_rect_class(lua_State* L)
|
||||||
{
|
{
|
||||||
ctx.registerClass(idx, kTag,
|
using Rectangle = gfx::Rect;
|
||||||
Rectangle_new, 3,
|
REG_CLASS(L, Rectangle);
|
||||||
Rectangle_methods,
|
REG_CLASS_NEW(L, Rectangle);
|
||||||
Rectangle_props);
|
REG_CLASS_PROPERTIES(L, Rectangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_new_rectangle(script::Context& ctx, const gfx::Rect& rc)
|
gfx::Rect convert_args_into_rect(lua_State* L, int index)
|
||||||
{
|
{
|
||||||
ctx.newObject(kTag, new gfx::Rect(rc), Rectangle_finalize);
|
return Rectangle_new(L, index);
|
||||||
}
|
|
||||||
|
|
||||||
gfx::Rect convert_args_into_rectangle(script::Context& ctx)
|
|
||||||
{
|
|
||||||
gfx::Rect result;
|
|
||||||
Rectangle_new(ctx.handle());
|
|
||||||
auto rc = (gfx::Rect*)ctx.toUserData(-1, kTag);
|
|
||||||
if (rc)
|
|
||||||
result = *rc;
|
|
||||||
ctx.pop(1);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -11,20 +11,19 @@
|
||||||
#include "app/cmd/deselect_mask.h"
|
#include "app/cmd/deselect_mask.h"
|
||||||
#include "app/cmd/set_mask.h"
|
#include "app/cmd/set_mask.h"
|
||||||
#include "app/doc.h"
|
#include "app/doc.h"
|
||||||
#include "app/script/app_scripting.h"
|
#include "app/script/engine.h"
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
#include "app/transaction.h"
|
#include "app/transaction.h"
|
||||||
#include "app/tx.h"
|
#include "app/tx.h"
|
||||||
#include "doc/mask.h"
|
#include "doc/mask.h"
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
using namespace doc;
|
using namespace doc;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char* kTag = "Selection";
|
|
||||||
|
|
||||||
struct SelectionObject {
|
struct SelectionObject {
|
||||||
Mask* mask;
|
Mask* mask;
|
||||||
Sprite* sprite;
|
Sprite* sprite;
|
||||||
|
@ -32,29 +31,35 @@ struct SelectionObject {
|
||||||
: mask(mask)
|
: mask(mask)
|
||||||
, sprite(sprite) {
|
, sprite(sprite) {
|
||||||
}
|
}
|
||||||
|
SelectionObject(SelectionObject&& that)
|
||||||
|
: mask(that.mask)
|
||||||
|
, sprite(that.sprite) {
|
||||||
|
that.mask = nullptr;
|
||||||
|
that.sprite = nullptr;
|
||||||
|
}
|
||||||
~SelectionObject() {
|
~SelectionObject() {
|
||||||
if (!sprite && mask)
|
if (!sprite && mask)
|
||||||
delete mask;
|
delete mask;
|
||||||
}
|
}
|
||||||
|
SelectionObject(const SelectionObject&) = delete;
|
||||||
|
SelectionObject& operator=(const SelectionObject&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Selection_finalize(script::ContextHandle handle, void* data)
|
int Selection_new(lua_State* L)
|
||||||
{
|
{
|
||||||
auto obj = (SelectionObject*)data;
|
push_obj(L, SelectionObject(new Mask, nullptr));
|
||||||
delete obj;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection_new(script::ContextHandle handle)
|
int Selection_gc(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
get_obj<SelectionObject>(L, 1)->~SelectionObject();
|
||||||
ctx.newObject(kTag, new SelectionObject(new Mask, nullptr), Selection_finalize);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection_deselect(script::ContextHandle handle)
|
int Selection_deselect(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto obj = get_obj<SelectionObject>(L, 1);
|
||||||
|
|
||||||
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
if (obj->sprite) {
|
if (obj->sprite) {
|
||||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||||
|
@ -69,21 +74,16 @@ void Selection_deselect(script::ContextHandle handle)
|
||||||
obj->mask->clear();
|
obj->mask->clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.pushUndefined();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection_select(script::ContextHandle handle)
|
int Selection_select(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
gfx::Rect bounds = convert_args_into_rect(L, 2);
|
||||||
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
|
if (bounds.isEmpty())
|
||||||
gfx::Rect bounds = convert_args_into_rectangle(ctx);
|
return Selection_deselect(L);
|
||||||
|
|
||||||
if (obj) {
|
auto obj = get_obj<SelectionObject>(L, 1);
|
||||||
if (bounds.isEmpty()) {
|
|
||||||
Selection_deselect(handle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (obj->sprite) {
|
if (obj->sprite) {
|
||||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||||
ASSERT(doc);
|
ASSERT(doc);
|
||||||
|
@ -98,17 +98,12 @@ void Selection_select(script::ContextHandle handle)
|
||||||
else {
|
else {
|
||||||
obj->mask->replace(bounds);
|
obj->mask->replace(bounds);
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
}
|
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection_selectAll(script::ContextHandle handle)
|
int Selection_selectAll(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto obj = get_obj<SelectionObject>(L, 1);
|
||||||
|
|
||||||
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
|
|
||||||
if (obj) {
|
|
||||||
if (obj->sprite) {
|
if (obj->sprite) {
|
||||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||||
|
|
||||||
|
@ -124,59 +119,56 @@ void Selection_selectAll(script::ContextHandle handle)
|
||||||
if (!bounds.isEmpty())
|
if (!bounds.isEmpty())
|
||||||
obj->mask->replace(bounds);
|
obj->mask->replace(bounds);
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection_get_bounds(script::ContextHandle handle)
|
int Selection_get_bounds(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto obj = get_obj<SelectionObject>(L, 1);
|
||||||
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
|
|
||||||
if (obj) {
|
|
||||||
if (obj->sprite) {
|
if (obj->sprite) {
|
||||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||||
if (doc->isMaskVisible()) {
|
if (doc->isMaskVisible()) {
|
||||||
push_new_rectangle(ctx, doc->mask()->bounds());
|
push_obj(L, doc->mask()->bounds());
|
||||||
}
|
}
|
||||||
else { // Empty rectangle
|
else { // Empty rectangle
|
||||||
push_new_rectangle(ctx, gfx::Rect(0, 0, 0, 0));
|
push_obj(L, gfx::Rect(0, 0, 0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
push_new_rectangle(ctx, obj->mask->bounds());
|
push_obj(L, obj->mask->bounds());
|
||||||
}
|
}
|
||||||
}
|
return 1;
|
||||||
else
|
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const script::FunctionEntry Selection_methods[] = {
|
const luaL_Reg Selection_methods[] = {
|
||||||
{ "deselect", Selection_deselect, 1 },
|
{ "deselect", Selection_deselect },
|
||||||
{ "select", Selection_select, 4 },
|
{ "select", Selection_select },
|
||||||
{ "selectAll", Selection_selectAll, 0 },
|
{ "selectAll", Selection_selectAll },
|
||||||
{ nullptr, nullptr, 0 }
|
{ "__gc", Selection_gc },
|
||||||
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
const script::PropertyEntry Selection_props[] = {
|
const Property Selection_properties[] = {
|
||||||
{ "bounds", Selection_get_bounds, nullptr },
|
{ "bounds", Selection_get_bounds, nullptr },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void register_selection_class(script::index_t idx, script::Context& ctx)
|
DEF_MTNAME(SelectionObject);
|
||||||
|
|
||||||
|
void register_selection_class(lua_State* L)
|
||||||
{
|
{
|
||||||
ctx.registerClass(idx, kTag,
|
using Selection = SelectionObject;
|
||||||
Selection_new, 3,
|
REG_CLASS(L, Selection);
|
||||||
Selection_methods,
|
REG_CLASS_NEW(L, Selection);
|
||||||
Selection_props);
|
REG_CLASS_PROPERTIES(L, Selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_sprite_selection(script::Context& ctx, Sprite* sprite)
|
void push_sprite_selection(lua_State* L, Sprite* sprite)
|
||||||
{
|
{
|
||||||
ctx.newObject(kTag,
|
push_obj(L, SelectionObject(nullptr, sprite));
|
||||||
new SelectionObject(nullptr, sprite),
|
|
||||||
Selection_finalize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -8,64 +8,54 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "app/script/app_scripting.h"
|
#include "app/script/engine.h"
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
#include "app/site.h"
|
#include "app/site.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char* kTag = "Site";
|
int Site_get_sprite(lua_State* L)
|
||||||
|
|
||||||
void Site_finalize(script::ContextHandle handle, void* data)
|
|
||||||
{
|
{
|
||||||
auto site = (app::Site*)data;
|
auto site = get_obj<Site>(L, 1);
|
||||||
delete site;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Site_get_sprite(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
auto site = (app::Site*)ctx.toUserData(0, kTag);
|
|
||||||
if (site->sprite())
|
if (site->sprite())
|
||||||
push_sprite(ctx, site->sprite());
|
push_ptr(L, site->sprite());
|
||||||
else
|
else
|
||||||
ctx.pushNull();
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Site_get_image(script::ContextHandle handle)
|
int Site_get_image(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto site = get_obj<Site>(L, 1);
|
||||||
auto site = (app::Site*)ctx.toUserData(0, kTag);
|
|
||||||
if (site->image())
|
if (site->image())
|
||||||
push_image(ctx, site->image());
|
push_ptr(L, site->image());
|
||||||
else
|
else
|
||||||
ctx.pushNull();
|
lua_pushnil(L);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const script::FunctionEntry Site_methods[] = {
|
const luaL_Reg Site_methods[] = {
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
const script::PropertyEntry Site_props[] = {
|
const Property Site_properties[] = {
|
||||||
{ "sprite", Site_get_sprite, nullptr },
|
{ "sprite", Site_get_sprite, nullptr },
|
||||||
{ "image", Site_get_image, nullptr },
|
{ "image", Site_get_image, nullptr },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void register_site_class(script::index_t idx, script::Context& ctx)
|
DEF_MTNAME(app::Site);
|
||||||
|
|
||||||
|
void register_site_class(lua_State* L)
|
||||||
{
|
{
|
||||||
ctx.registerClass(idx, kTag,
|
REG_CLASS(L, Site);
|
||||||
nullptr, 0,
|
REG_CLASS_PROPERTIES(L, Site);
|
||||||
Site_methods,
|
|
||||||
Site_props);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_site(script::Context& ctx, app::Site& site)
|
|
||||||
{
|
|
||||||
ctx.newObject(kTag, new app::Site(site), Site_finalize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2017 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
|
@ -8,113 +8,100 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
#include "gfx/size.h"
|
#include "gfx/size.h"
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char* kTag = "Size";
|
gfx::Size Size_new(lua_State* L, int index)
|
||||||
|
|
||||||
void Size_finalize(script::ContextHandle handle, void* data)
|
|
||||||
{
|
{
|
||||||
auto sz = (gfx::Size*)data;
|
gfx::Size sz(0, 0);
|
||||||
delete sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Size_new(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
auto sz = new gfx::Size(0, 0);
|
|
||||||
|
|
||||||
// Copy other size
|
// Copy other size
|
||||||
if (ctx.isUserData(1, kTag)) {
|
if (auto sz2 = may_get_obj<gfx::Size>(L, index)) {
|
||||||
auto sz2 = (gfx::Size*)ctx.toUserData(1, kTag);
|
sz = *sz2;
|
||||||
*sz = *sz2;
|
|
||||||
}
|
}
|
||||||
// Convert { width, height } into a Size
|
// Convert { width, height } into a Size
|
||||||
else if (ctx.isObject(1)) {
|
else if (lua_istable(L, index)) {
|
||||||
ctx.getProp(1, "width");
|
lua_getfield(L, index, "width");
|
||||||
ctx.getProp(1, "height");
|
lua_getfield(L, index, "height");
|
||||||
sz->w = ctx.toInt(-2);
|
sz.w = lua_tointeger(L, -2);
|
||||||
sz->h = ctx.toInt(-1);
|
sz.h = lua_tointeger(L, -1);
|
||||||
ctx.pop(4);
|
lua_pop(L, 2);
|
||||||
}
|
}
|
||||||
else if (ctx.isNumber(1)) {
|
else {
|
||||||
sz->w = ctx.toInt(1);
|
sz.w = lua_tointeger(L, index);
|
||||||
sz->h = ctx.toInt(2);
|
sz.h = lua_tointeger(L, index+1);
|
||||||
}
|
}
|
||||||
|
return sz;
|
||||||
ctx.newObject(kTag, sz, Size_finalize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Size_get_width(script::ContextHandle handle)
|
int Size_new(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
push_obj(L, Size_new(L, 1));
|
||||||
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
|
return 1;
|
||||||
ASSERT(sz);
|
|
||||||
ctx.pushInt(sz->w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Size_get_height(script::ContextHandle handle)
|
int Size_get_width(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto sz = get_obj<gfx::Size>(L, 1);
|
||||||
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
|
|
||||||
ASSERT(sz);
|
ASSERT(sz);
|
||||||
ctx.pushInt(sz->h);
|
lua_pushinteger(L, sz->w);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Size_set_width(script::ContextHandle handle)
|
int Size_get_height(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const auto sz = get_obj<gfx::Size>(L, 1);
|
||||||
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
|
|
||||||
ASSERT(sz);
|
ASSERT(sz);
|
||||||
sz->w = ctx.toInt(1);
|
lua_pushinteger(L, sz->h);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Size_set_height(script::ContextHandle handle)
|
int Size_set_width(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sz = get_obj<gfx::Size>(L, 1);
|
||||||
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
|
|
||||||
ASSERT(sz);
|
ASSERT(sz);
|
||||||
sz->h = ctx.toInt(1);
|
sz->w = lua_tointeger(L, 2);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const script::FunctionEntry Size_methods[] = {
|
int Size_set_height(lua_State* L)
|
||||||
{ nullptr, nullptr, 0 }
|
{
|
||||||
|
auto sz = get_obj<gfx::Size>(L, 1);
|
||||||
|
ASSERT(sz);
|
||||||
|
sz->h = lua_tointeger(L, 2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const luaL_Reg Size_methods[] = {
|
||||||
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
const script::PropertyEntry Size_props[] = {
|
const Property Size_properties[] = {
|
||||||
{ "width", Size_get_width, Size_set_width },
|
{ "width", Size_get_width, Size_set_width },
|
||||||
{ "height", Size_get_height, Size_set_height },
|
{ "height", Size_get_height, Size_set_height },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void register_size_class(script::index_t idx, script::Context& ctx)
|
DEF_MTNAME(gfx::Size);
|
||||||
|
|
||||||
|
void register_size_class(lua_State* L)
|
||||||
{
|
{
|
||||||
ctx.registerClass(idx, kTag,
|
using gfx::Size;
|
||||||
Size_new, 3,
|
REG_CLASS(L, Size);
|
||||||
Size_methods,
|
REG_CLASS_NEW(L, Size);
|
||||||
Size_props);
|
REG_CLASS_PROPERTIES(L, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_new_size(script::Context& ctx, const gfx::Size& sz)
|
gfx::Size convert_args_into_size(lua_State* L, int index)
|
||||||
{
|
{
|
||||||
ctx.newObject(kTag, new gfx::Size(sz), Size_finalize);
|
return Size_new(L, index);
|
||||||
}
|
|
||||||
|
|
||||||
gfx::Size convert_args_into_size(script::Context& ctx)
|
|
||||||
{
|
|
||||||
gfx::Size result;
|
|
||||||
Size_new(ctx.handle());
|
|
||||||
auto sz = (gfx::Size*)ctx.toUserData(-1, kTag);
|
|
||||||
if (sz)
|
|
||||||
result = *sz;
|
|
||||||
ctx.pop(1);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
#include "app/doc.h"
|
#include "app/doc.h"
|
||||||
#include "app/doc_api.h"
|
#include "app/doc_api.h"
|
||||||
#include "app/file/palette_file.h"
|
#include "app/file/palette_file.h"
|
||||||
#include "app/script/app_scripting.h"
|
#include "app/script/engine.h"
|
||||||
|
#include "app/script/luacpp.h"
|
||||||
#include "app/site.h"
|
#include "app/site.h"
|
||||||
#include "app/transaction.h"
|
#include "app/transaction.h"
|
||||||
#include "app/tx.h"
|
#include "app/tx.h"
|
||||||
|
@ -24,65 +25,57 @@
|
||||||
#include "doc/mask.h"
|
#include "doc/mask.h"
|
||||||
#include "doc/palette.h"
|
#include "doc/palette.h"
|
||||||
#include "doc/sprite.h"
|
#include "doc/sprite.h"
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char* kTag = "Sprite";
|
int Sprite_new(lua_State* L)
|
||||||
|
|
||||||
void Sprite_new(script::ContextHandle handle)
|
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
const int w = lua_tointeger(L, 1);
|
||||||
int w = ctx.requireInt(1);
|
const int h = lua_tointeger(L, 2);
|
||||||
int h = ctx.requireInt(2);
|
const int colorMode = (lua_isnone(L, 3) ? IMAGE_RGB: lua_tointeger(L, 3));
|
||||||
int colorMode = (ctx.isUndefined(3) ? IMAGE_RGB: ctx.requireInt(3));
|
|
||||||
|
|
||||||
std::unique_ptr<Sprite> sprite(
|
std::unique_ptr<Sprite> sprite(
|
||||||
Sprite::createBasicSprite((doc::PixelFormat)colorMode, w, h, 256));
|
Sprite::createBasicSprite((doc::PixelFormat)colorMode, w, h, 256));
|
||||||
std::unique_ptr<Doc> doc(new Doc(sprite.get()));
|
std::unique_ptr<Doc> doc(new Doc(sprite.get()));
|
||||||
sprite.release();
|
sprite.release();
|
||||||
|
|
||||||
app::Context* appCtx = App::instance()->context();
|
app::Context* ctx = App::instance()->context();
|
||||||
doc->setContext(appCtx);
|
doc->setContext(ctx);
|
||||||
|
|
||||||
ctx.newObject(kTag, doc->sprite(), nullptr);
|
push_ptr(L, doc->sprite());
|
||||||
doc.release();
|
doc.release();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_resize(script::ContextHandle handle)
|
int Sprite_resize(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
Sprite* sprite = (Sprite*)ctx.toUserData(0, kTag);
|
const gfx::Size size = convert_args_into_size(L, 2);
|
||||||
gfx::Size size = convert_args_into_size(ctx);
|
|
||||||
|
|
||||||
if (sprite) {
|
|
||||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||||
Tx tx;
|
Tx tx;
|
||||||
DocApi(doc, tx).setSpriteSize(doc->sprite(), size.w, size.h);
|
DocApi(doc, tx).setSpriteSize(doc->sprite(), size.w, size.h);
|
||||||
tx.commit();
|
tx.commit();
|
||||||
}
|
return 0;
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_crop(script::ContextHandle handle)
|
int Sprite_crop(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
|
||||||
if (sprite) {
|
|
||||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||||
gfx::Rect bounds;
|
gfx::Rect bounds;
|
||||||
|
|
||||||
// Use mask bounds
|
// Use mask bounds
|
||||||
if (ctx.isUndefined(1)) {
|
if (lua_isnone(L, 2)) {
|
||||||
if (doc->isMaskVisible())
|
if (doc->isMaskVisible())
|
||||||
bounds = doc->mask()->bounds();
|
bounds = doc->mask()->bounds();
|
||||||
else
|
else
|
||||||
bounds = sprite->bounds();
|
bounds = sprite->bounds();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bounds = convert_args_into_rectangle(ctx);
|
bounds = convert_args_into_rect(L, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bounds.isEmpty()) {
|
if (!bounds.isEmpty()) {
|
||||||
|
@ -90,14 +83,12 @@ void Sprite_crop(script::ContextHandle handle)
|
||||||
DocApi(doc, tx).cropSprite(sprite, bounds);
|
DocApi(doc, tx).cropSprite(sprite, bounds);
|
||||||
tx.commit();
|
tx.commit();
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_save(script::ContextHandle handle)
|
int Sprite_save(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
|
||||||
if (sprite) {
|
if (sprite) {
|
||||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||||
app::Context* appCtx = App::instance()->context();
|
app::Context* appCtx = App::instance()->context();
|
||||||
|
@ -106,16 +97,13 @@ void Sprite_save(script::ContextHandle handle)
|
||||||
Commands::instance()->byId(CommandId::SaveFile());
|
Commands::instance()->byId(CommandId::SaveFile());
|
||||||
appCtx->executeCommand(saveCommand);
|
appCtx->executeCommand(saveCommand);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_saveAs(script::ContextHandle handle)
|
int Sprite_saveAs(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
const char* fn = luaL_checkstring(L, 2);
|
||||||
const char* fn = ctx.requireString(1);
|
|
||||||
|
|
||||||
if (fn && sprite) {
|
if (fn && sprite) {
|
||||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||||
app::Context* appCtx = App::instance()->context();
|
app::Context* appCtx = App::instance()->context();
|
||||||
|
@ -128,16 +116,13 @@ void Sprite_saveAs(script::ContextHandle handle)
|
||||||
doc->setFilename(fn);
|
doc->setFilename(fn);
|
||||||
appCtx->executeCommand(saveCommand, params);
|
appCtx->executeCommand(saveCommand, params);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_saveCopyAs(script::ContextHandle handle)
|
int Sprite_saveCopyAs(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
const char* fn = luaL_checkstring(L, 2);
|
||||||
const char* fn = ctx.requireString(1);
|
|
||||||
|
|
||||||
if (fn && sprite) {
|
if (fn && sprite) {
|
||||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||||
app::Context* appCtx = App::instance()->context();
|
app::Context* appCtx = App::instance()->context();
|
||||||
|
@ -150,16 +135,13 @@ void Sprite_saveCopyAs(script::ContextHandle handle)
|
||||||
params.set("filename", fn);
|
params.set("filename", fn);
|
||||||
appCtx->executeCommand(saveCommand, params);
|
appCtx->executeCommand(saveCommand, params);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_loadPalette(script::ContextHandle handle)
|
int Sprite_loadPalette(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
const char* fn = luaL_checkstring(L, 2);
|
||||||
const char* fn = ctx.toString(1);
|
|
||||||
|
|
||||||
if (fn && sprite) {
|
if (fn && sprite) {
|
||||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||||
std::unique_ptr<doc::Palette> palette(load_palette(fn));
|
std::unique_ptr<doc::Palette> palette(load_palette(fn));
|
||||||
|
@ -170,100 +152,94 @@ void Sprite_loadPalette(script::ContextHandle handle)
|
||||||
tx.commit();
|
tx.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
ctx.pushUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_get_filename(script::ContextHandle handle)
|
int Sprite_get_filename(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
lua_pushstring(L, sprite->document()->filename().c_str());
|
||||||
ctx.pushString(sprite->document()->filename().c_str());
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_get_width(script::ContextHandle handle)
|
int Sprite_get_width(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, sprite->width());
|
||||||
ctx.pushInt(sprite->width());
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_set_width(script::ContextHandle handle)
|
int Sprite_get_height(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
lua_pushinteger(L, sprite->height());
|
||||||
const int width = ctx.requireInt(1);
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Sprite_get_colorMode(lua_State* L)
|
||||||
|
{
|
||||||
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
|
lua_pushinteger(L, sprite->pixelFormat());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Sprite_get_selection(lua_State* L)
|
||||||
|
{
|
||||||
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
|
push_sprite_selection(L, sprite);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Sprite_set_width(lua_State* L)
|
||||||
|
{
|
||||||
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
|
const int width = lua_tointeger(L, 2);
|
||||||
Tx tx;
|
Tx tx;
|
||||||
tx(new cmd::SetSpriteSize(sprite,
|
tx(new cmd::SetSpriteSize(sprite, width, sprite->height()));
|
||||||
width, sprite->height()));
|
|
||||||
tx.commit();
|
tx.commit();
|
||||||
ctx.pushUndefined();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_get_height(script::ContextHandle handle)
|
int Sprite_set_height(lua_State* L)
|
||||||
{
|
{
|
||||||
script::Context ctx(handle);
|
auto sprite = get_ptr<Sprite>(L, 1);
|
||||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
const int height = lua_tointeger(L, 2);
|
||||||
ctx.pushInt(sprite->height());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sprite_set_height(script::ContextHandle handle)
|
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
|
||||||
const int height = ctx.requireInt(1);
|
|
||||||
Tx tx;
|
Tx tx;
|
||||||
tx(new cmd::SetSpriteSize(sprite,
|
tx(new cmd::SetSpriteSize(sprite, sprite->width(), height));
|
||||||
sprite->width(), height));
|
|
||||||
tx.commit();
|
tx.commit();
|
||||||
ctx.pushUndefined();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite_get_colorMode(script::ContextHandle handle)
|
const luaL_Reg Sprite_methods[] = {
|
||||||
{
|
{ "resize", Sprite_resize },
|
||||||
script::Context ctx(handle);
|
{ "crop", Sprite_crop },
|
||||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
{ "save", Sprite_save },
|
||||||
ctx.pushInt(sprite->pixelFormat());
|
{ "saveAs", Sprite_saveAs },
|
||||||
}
|
{ "saveCopyAs", Sprite_saveCopyAs },
|
||||||
|
{ "loadPalette", Sprite_loadPalette },
|
||||||
void Sprite_get_selection(script::ContextHandle handle)
|
{ nullptr, nullptr }
|
||||||
{
|
|
||||||
script::Context ctx(handle);
|
|
||||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
|
||||||
push_sprite_selection(ctx, sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
const script::FunctionEntry Sprite_methods[] = {
|
|
||||||
{ "resize", Sprite_resize, 2 },
|
|
||||||
{ "crop", Sprite_crop, 4 },
|
|
||||||
{ "save", Sprite_save, 2 },
|
|
||||||
{ "saveAs", Sprite_saveAs, 2 },
|
|
||||||
{ "saveCopyAs", Sprite_saveCopyAs, 2 },
|
|
||||||
{ "loadPalette", Sprite_loadPalette, 1 },
|
|
||||||
{ nullptr, nullptr, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const script::PropertyEntry Sprite_props[] = {
|
const Property Sprite_properties[] = {
|
||||||
{ "filename", Sprite_get_filename, nullptr },
|
{ "filename", Sprite_get_filename, nullptr },
|
||||||
{ "width", Sprite_get_width, Sprite_set_width },
|
{ "width", Sprite_get_width, Sprite_set_width },
|
||||||
{ "height", Sprite_get_height, Sprite_set_height },
|
{ "height", Sprite_get_height, Sprite_set_height },
|
||||||
{ "colorMode", Sprite_get_colorMode, nullptr },
|
{ "colorMode", Sprite_get_colorMode, nullptr },
|
||||||
{ "selection", Sprite_get_selection, nullptr },
|
{ "selection", Sprite_get_selection, nullptr },
|
||||||
{ nullptr, nullptr, 0 }
|
{ nullptr, nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void register_sprite_class(script::index_t idx, script::Context& ctx)
|
DEF_MTNAME(doc::Sprite);
|
||||||
|
|
||||||
|
void register_sprite_class(lua_State* L)
|
||||||
{
|
{
|
||||||
ctx.registerClass(idx, kTag,
|
using doc::Sprite;
|
||||||
Sprite_new, 3,
|
REG_CLASS(L, Sprite);
|
||||||
Sprite_methods, Sprite_props);
|
REG_CLASS_NEW(L, Sprite);
|
||||||
}
|
REG_CLASS_PROPERTIES(L, Sprite);
|
||||||
|
|
||||||
void push_sprite(script::Context& ctx, Sprite* sprite)
|
|
||||||
{
|
|
||||||
ctx.newObject(kTag, sprite, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace script
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -31,10 +31,10 @@ Shell::~Shell()
|
||||||
|
|
||||||
void Shell::run(script::Engine& engine)
|
void Shell::run(script::Engine& engine)
|
||||||
{
|
{
|
||||||
std::cout << "Welcome to " PACKAGE " v" VERSION " interactive console" << std::endl;
|
std::cout << "Welcome to " PACKAGE " v" VERSION " Interactive Console" << std::endl;
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(std::cin, line)) {
|
while (std::getline(std::cin, line)) {
|
||||||
engine.eval(line);
|
engine.evalCode(line);
|
||||||
}
|
}
|
||||||
std::cout << "Done\n";
|
std::cout << "Done\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
|
@ -12,11 +12,10 @@
|
||||||
#error ENABLE_SCRIPTING must be defined
|
#error ENABLE_SCRIPTING must be defined
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace script {
|
|
||||||
class Engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
namespace script {
|
||||||
|
class Engine;
|
||||||
|
}
|
||||||
|
|
||||||
class Shell {
|
class Shell {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
|
@ -63,7 +63,7 @@ protected:
|
||||||
|
|
||||||
DevConsoleView::DevConsoleView()
|
DevConsoleView::DevConsoleView()
|
||||||
: Box(VERTICAL)
|
: Box(VERTICAL)
|
||||||
, m_textBox("Welcome to Aseprite JavaScript Console\n(Experimental)", LEFT)
|
, m_textBox("Welcome to " PACKAGE " v" VERSION " Console\n(Experimental)", LEFT)
|
||||||
, m_label(">")
|
, m_label(">")
|
||||||
, m_entry(new CommmandEntry)
|
, m_entry(new CommmandEntry)
|
||||||
, m_engine(this)
|
, m_engine(this)
|
||||||
|
@ -137,7 +137,7 @@ bool DevConsoleView::onProcessMessage(Message* msg)
|
||||||
void DevConsoleView::onExecuteCommand(const std::string& cmd)
|
void DevConsoleView::onExecuteCommand(const std::string& cmd)
|
||||||
{
|
{
|
||||||
m_engine.printLastResult();
|
m_engine.printLastResult();
|
||||||
m_engine.eval(cmd);
|
m_engine.evalCode(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevConsoleView::onConsolePrint(const char* text)
|
void DevConsoleView::onConsolePrint(const char* text)
|
||||||
|
|
|
@ -12,10 +12,9 @@
|
||||||
#error ENABLE_SCRIPTING must be defined
|
#error ENABLE_SCRIPTING must be defined
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "app/script/app_scripting.h"
|
#include "app/script/engine.h"
|
||||||
#include "app/ui/tabs.h"
|
#include "app/ui/tabs.h"
|
||||||
#include "app/ui/workspace_view.h"
|
#include "app/ui/workspace_view.h"
|
||||||
#include "script/engine_delegate.h"
|
|
||||||
#include "ui/box.h"
|
#include "ui/box.h"
|
||||||
#include "ui/label.h"
|
#include "ui/label.h"
|
||||||
#include "ui/textbox.h"
|
#include "ui/textbox.h"
|
||||||
|
@ -57,7 +56,7 @@ namespace app {
|
||||||
ui::HBox m_bottomBox;
|
ui::HBox m_bottomBox;
|
||||||
ui::Label m_label;
|
ui::Label m_label;
|
||||||
CommmandEntry* m_entry;
|
CommmandEntry* m_entry;
|
||||||
AppScripting m_engine;
|
script::Engine m_engine;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
# Aseprite Scripting Library
|
|
||||||
# Copyright (C) 2015-2017 David Capello
|
|
||||||
|
|
||||||
add_library(script-lib engine.cpp engine_delegate.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(script-lib
|
|
||||||
laf-base
|
|
||||||
mujs)
|
|
|
@ -1,20 +0,0 @@
|
||||||
Copyright (c) 2015-2016 David Capello
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
@ -1,4 +0,0 @@
|
||||||
# Aseprite Scripting Library
|
|
||||||
*Copyright (C) 2015-2017 David Capello*
|
|
||||||
|
|
||||||
> Distributed under [MIT license](LICENSE.txt)
|
|
|
@ -1,460 +0,0 @@
|
||||||
// Aseprite Scripting Library
|
|
||||||
// Copyright (c) 2015-2017 David Capello
|
|
||||||
//
|
|
||||||
// This file is released under the terms of the MIT license.
|
|
||||||
// Read LICENSE.txt for more information.
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "script/engine.h"
|
|
||||||
|
|
||||||
#include "base/convert_to.h"
|
|
||||||
#include "base/exception.h"
|
|
||||||
#include "base/file_handle.h"
|
|
||||||
#include "base/fstream_path.h"
|
|
||||||
#include "base/memory.h"
|
|
||||||
#include "script/engine_delegate.h"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <map>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <mujs/mujs.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace script {
|
|
||||||
|
|
||||||
static const char* stacktrace_js =
|
|
||||||
"Error.prototype.toString = function() {\n"
|
|
||||||
" if (this.stackTrace)\n"
|
|
||||||
" return this.name + ': ' + this.message + this.stackTrace;\n"
|
|
||||||
" return this.name + ': ' + this.message;\n"
|
|
||||||
"}";
|
|
||||||
|
|
||||||
void Context::setContextUserData(void* userData)
|
|
||||||
{
|
|
||||||
js_setcontext(m_handle, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Context::getContextUserData()
|
|
||||||
{
|
|
||||||
return js_getcontext(m_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::error(const char* err)
|
|
||||||
{
|
|
||||||
js_error(m_handle, "%s", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pop()
|
|
||||||
{
|
|
||||||
js_pop(m_handle, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pop(index_t count)
|
|
||||||
{
|
|
||||||
js_pop(m_handle, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::remove(index_t idx)
|
|
||||||
{
|
|
||||||
js_remove(m_handle, idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::duplicateTop()
|
|
||||||
{
|
|
||||||
js_dup(m_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
index_t Context::top()
|
|
||||||
{
|
|
||||||
return js_gettop(m_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::copy(index_t i)
|
|
||||||
{
|
|
||||||
js_copy(m_handle, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::call(index_t args)
|
|
||||||
{
|
|
||||||
js_call(m_handle, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isUndefined(index_t i)
|
|
||||||
{
|
|
||||||
return (js_isundefined(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isNull(index_t i)
|
|
||||||
{
|
|
||||||
return (js_isnull(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isNullOrUndefined(index_t i)
|
|
||||||
{
|
|
||||||
return (js_isnull(m_handle, i) ||
|
|
||||||
js_isundefined(m_handle, i)? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isBool(index_t i)
|
|
||||||
{
|
|
||||||
return (js_isboolean(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isNumber(index_t i)
|
|
||||||
{
|
|
||||||
return (js_isnumber(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isString(index_t i)
|
|
||||||
{
|
|
||||||
return (js_isstring(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isObject(index_t i)
|
|
||||||
{
|
|
||||||
return (js_isobject(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isArray(index_t i)
|
|
||||||
{
|
|
||||||
return (js_isarray(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isCallable(index_t i)
|
|
||||||
{
|
|
||||||
return (js_iscallable(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::isUserData(index_t i, const char* tag)
|
|
||||||
{
|
|
||||||
return (js_isuserdata(m_handle, i, tag) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::toBool(index_t i)
|
|
||||||
{
|
|
||||||
return (js_toboolean(m_handle, i) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
double Context::toNumber(index_t i)
|
|
||||||
{
|
|
||||||
return js_tonumber(m_handle, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Context::toInt(index_t i)
|
|
||||||
{
|
|
||||||
return js_toint32(m_handle, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int Context::toUInt(index_t i)
|
|
||||||
{
|
|
||||||
return js_touint32(m_handle, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Context::toString(index_t i)
|
|
||||||
{
|
|
||||||
return js_tostring(m_handle, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Context::toUserData(index_t i, const char* tag)
|
|
||||||
{
|
|
||||||
return js_touserdata(m_handle, i, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::requireBool(index_t i)
|
|
||||||
{
|
|
||||||
if (js_isboolean(m_handle, i))
|
|
||||||
return true;
|
|
||||||
else {
|
|
||||||
js_typeerror(m_handle, "not a boolean (index %d)\n", i);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double Context::requireNumber(index_t i)
|
|
||||||
{
|
|
||||||
if (js_isnumber(m_handle, i))
|
|
||||||
return js_tonumber(m_handle, i);
|
|
||||||
else {
|
|
||||||
js_typeerror(m_handle, "not a number (index %d)\n", i);
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Context::requireInt(index_t i)
|
|
||||||
{
|
|
||||||
return (int)requireNumber(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int Context::requireUInt(index_t i)
|
|
||||||
{
|
|
||||||
return (unsigned int)requireNumber(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Context::requireString(index_t i)
|
|
||||||
{
|
|
||||||
if (js_isstring(m_handle, i))
|
|
||||||
return js_tostring(m_handle, i);
|
|
||||||
else {
|
|
||||||
js_typeerror(m_handle, "not a string (index %d)\n", i);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Context::requireUserData(index_t i, const char* tag)
|
|
||||||
{
|
|
||||||
if (js_isuserdata(m_handle, i, tag))
|
|
||||||
return js_touserdata(m_handle, i, tag);
|
|
||||||
else {
|
|
||||||
js_typeerror(m_handle, "not a user data (index %d, tag %s)\n", i, tag);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pushUndefined()
|
|
||||||
{
|
|
||||||
js_pushundefined(m_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pushNull()
|
|
||||||
{
|
|
||||||
js_pushnull(m_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pushBool(bool val)
|
|
||||||
{
|
|
||||||
js_pushboolean(m_handle, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pushNumber(double val)
|
|
||||||
{
|
|
||||||
js_pushnumber(m_handle, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pushInt(int val)
|
|
||||||
{
|
|
||||||
js_pushnumber(m_handle, double(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pushUInt(unsigned int val)
|
|
||||||
{
|
|
||||||
js_pushnumber(m_handle, double(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pushString(const char* str)
|
|
||||||
{
|
|
||||||
js_pushstring(m_handle, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::pushGlobalObject()
|
|
||||||
{
|
|
||||||
js_pushglobal(m_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::newObject()
|
|
||||||
{
|
|
||||||
js_newobject(m_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::newObject(const char* className,
|
|
||||||
void* userData,
|
|
||||||
FinalizeFunction finalize)
|
|
||||||
{
|
|
||||||
js_getglobal(m_handle, className); // class
|
|
||||||
js_getproperty(m_handle, -1, "prototype"); // class prototype
|
|
||||||
js_newuserdata(m_handle, className, userData, finalize); // class userdata
|
|
||||||
js_rot2(m_handle); // userdata class
|
|
||||||
js_pop(m_handle, 1); // userdata
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::newUserData(const char* tag,
|
|
||||||
void* userData,
|
|
||||||
FinalizeFunction finalize)
|
|
||||||
{
|
|
||||||
js_newuserdata(m_handle, tag, userData, finalize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::registerConstants(index_t idx,
|
|
||||||
const ConstantEntry* consts)
|
|
||||||
{
|
|
||||||
if (idx < 0)
|
|
||||||
--idx;
|
|
||||||
for (; consts->id; ++consts) {
|
|
||||||
js_pushnumber(m_handle, consts->value);
|
|
||||||
js_defproperty(m_handle, idx, consts->id, JS_DONTENUM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::registerProp(index_t idx,
|
|
||||||
const char* id,
|
|
||||||
Function getter,
|
|
||||||
Function setter)
|
|
||||||
{
|
|
||||||
if (idx < 0)
|
|
||||||
idx -= 2;
|
|
||||||
|
|
||||||
if (getter)
|
|
||||||
js_newcfunction(m_handle, getter,
|
|
||||||
(std::string(id) + ".getter").c_str(), 0);
|
|
||||||
else
|
|
||||||
js_pushnull(m_handle);
|
|
||||||
|
|
||||||
if (setter)
|
|
||||||
js_newcfunction(m_handle, setter,
|
|
||||||
(std::string(id) + ".setter").c_str(), 1);
|
|
||||||
else
|
|
||||||
js_pushnull(m_handle);
|
|
||||||
|
|
||||||
js_defaccessor(m_handle, idx, id, JS_DONTENUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::registerProps(index_t idx, const PropertyEntry* props)
|
|
||||||
{
|
|
||||||
for (int i=0; props[i].id; ++i) {
|
|
||||||
registerProp(idx,
|
|
||||||
props[i].id,
|
|
||||||
props[i].getter,
|
|
||||||
props[i].setter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::registerFunc(index_t idx,
|
|
||||||
const char* id,
|
|
||||||
const Function func,
|
|
||||||
index_t nargs)
|
|
||||||
{
|
|
||||||
js_newcfunction(m_handle, func, id, nargs);
|
|
||||||
js_defproperty(m_handle, idx, id, JS_DONTENUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::registerFuncs(index_t idx, const FunctionEntry* methods)
|
|
||||||
{
|
|
||||||
if (idx < 0)
|
|
||||||
--idx;
|
|
||||||
for (; methods->id; ++methods) {
|
|
||||||
registerFunc(idx,
|
|
||||||
methods->id,
|
|
||||||
methods->value,
|
|
||||||
methods->nargs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::registerObject(index_t idx,
|
|
||||||
const char* id,
|
|
||||||
const FunctionEntry* methods,
|
|
||||||
const PropertyEntry* props)
|
|
||||||
{
|
|
||||||
if (idx < 0)
|
|
||||||
--idx;
|
|
||||||
|
|
||||||
newObject();
|
|
||||||
if (methods) registerFuncs(-1, methods);
|
|
||||||
if (props) registerProps(-1, props);
|
|
||||||
js_defproperty(m_handle, idx, id, JS_DONTENUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::registerClass(index_t idx,
|
|
||||||
const char* id,
|
|
||||||
Function ctorFunc, int ctorNargs,
|
|
||||||
const FunctionEntry* methods,
|
|
||||||
const PropertyEntry* props)
|
|
||||||
{
|
|
||||||
if (idx < 0)
|
|
||||||
idx -= 2;
|
|
||||||
|
|
||||||
js_getglobal(m_handle, "Object");
|
|
||||||
js_getproperty(m_handle, -1, "prototype");
|
|
||||||
js_newuserdata(m_handle, id, nullptr, nullptr);
|
|
||||||
if (methods) registerFuncs(-1, methods);
|
|
||||||
if (props) registerProps(-1, props);
|
|
||||||
js_newcconstructor(m_handle, ctorFunc, ctorFunc, id, ctorNargs);
|
|
||||||
js_defproperty(m_handle, idx, id, JS_DONTENUM);
|
|
||||||
js_pop(m_handle, 1); // pop Object
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Context::hasProp(index_t i, const char* propName)
|
|
||||||
{
|
|
||||||
return (js_hasproperty(m_handle, i, propName) ? true: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::getProp(index_t i, const char* propName)
|
|
||||||
{
|
|
||||||
js_getproperty(m_handle, i, propName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::setProp(index_t i, const char* propName)
|
|
||||||
{
|
|
||||||
js_defproperty(m_handle, i, propName, JS_DONTENUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine::Engine(EngineDelegate* delegate)
|
|
||||||
: m_ctx(js_newstate(NULL, NULL, JS_STRICT))
|
|
||||||
, m_delegate(delegate)
|
|
||||||
, m_printLastResult(false)
|
|
||||||
{
|
|
||||||
// Pre-scripts
|
|
||||||
js_dostring(m_ctx.handle(), stacktrace_js);
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine::~Engine()
|
|
||||||
{
|
|
||||||
js_freestate(m_ctx.handle());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::printLastResult()
|
|
||||||
{
|
|
||||||
m_printLastResult = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Engine::eval(const std::string& jsCode,
|
|
||||||
const std::string& filename)
|
|
||||||
{
|
|
||||||
bool errFlag = true;
|
|
||||||
onBeforeEval();
|
|
||||||
|
|
||||||
ContextHandle handle = m_ctx.handle();
|
|
||||||
|
|
||||||
if (js_ploadstring(handle, filename.c_str(), jsCode.c_str()) == 0) {
|
|
||||||
js_pushundefined(handle);
|
|
||||||
if (js_pcall(handle, 0) == 0) {
|
|
||||||
if (m_printLastResult) {
|
|
||||||
if (!js_isundefined(handle, -1)) {
|
|
||||||
const char* result = js_tostring(handle, -1);
|
|
||||||
if (result)
|
|
||||||
m_delegate->onConsolePrint(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
errFlag = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print error message
|
|
||||||
if (errFlag) {
|
|
||||||
std::string err;
|
|
||||||
const char* s = js_trystring(handle, -1, "Error");
|
|
||||||
if (s)
|
|
||||||
m_delegate->onConsolePrint(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
js_pop(handle, 1);
|
|
||||||
|
|
||||||
onAfterEval(errFlag);
|
|
||||||
return !errFlag;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Engine::evalFile(const std::string& filename)
|
|
||||||
{
|
|
||||||
std::stringstream buf;
|
|
||||||
{
|
|
||||||
std::ifstream s(FSTREAM_PATH(filename));
|
|
||||||
buf << s.rdbuf();
|
|
||||||
}
|
|
||||||
return eval(buf.str(), filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace script
|
|
|
@ -1,165 +0,0 @@
|
||||||
// Aseprite Scripting Library
|
|
||||||
// Copyright (c) 2015-2017 David Capello
|
|
||||||
//
|
|
||||||
// This file is released under the terms of the MIT license.
|
|
||||||
// Read LICENSE.txt for more information.
|
|
||||||
|
|
||||||
#ifndef SCRIPT_ENGINE_H_INCLUDED
|
|
||||||
#define SCRIPT_ENGINE_H_INCLUDED
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
struct js_State;
|
|
||||||
|
|
||||||
namespace script {
|
|
||||||
class Context;
|
|
||||||
class EngineDelegate;
|
|
||||||
|
|
||||||
typedef int result_t;
|
|
||||||
typedef int index_t;
|
|
||||||
typedef js_State* ContextHandle;
|
|
||||||
typedef void (*Function)(ContextHandle);
|
|
||||||
typedef void (*FinalizeFunction)(ContextHandle, void*);
|
|
||||||
|
|
||||||
struct FunctionEntry {
|
|
||||||
const char* id;
|
|
||||||
Function value;
|
|
||||||
index_t nargs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PropertyEntry {
|
|
||||||
const char* id;
|
|
||||||
Function getter;
|
|
||||||
Function setter;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ConstantEntry {
|
|
||||||
const char* id;
|
|
||||||
double value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Module {
|
|
||||||
public:
|
|
||||||
virtual ~Module() { }
|
|
||||||
virtual const char* id() const = 0;
|
|
||||||
virtual int registerModule(Context& ctx) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Context {
|
|
||||||
public:
|
|
||||||
Context(ContextHandle handle) : m_handle(handle) { }
|
|
||||||
|
|
||||||
ContextHandle handle() { return m_handle; }
|
|
||||||
|
|
||||||
void setContextUserData(void* userData);
|
|
||||||
void* getContextUserData();
|
|
||||||
|
|
||||||
void error(const char* err);
|
|
||||||
|
|
||||||
void pop();
|
|
||||||
void pop(index_t count);
|
|
||||||
void remove(index_t idx);
|
|
||||||
void duplicateTop();
|
|
||||||
index_t top();
|
|
||||||
void copy(index_t i);
|
|
||||||
void call(index_t args);
|
|
||||||
|
|
||||||
bool isUndefined(index_t i);
|
|
||||||
bool isNull(index_t i);
|
|
||||||
bool isNullOrUndefined(index_t i);
|
|
||||||
bool isBool(index_t i);
|
|
||||||
bool isNumber(index_t i);
|
|
||||||
bool isString(index_t i);
|
|
||||||
bool isObject(index_t i);
|
|
||||||
bool isArray(index_t i);
|
|
||||||
bool isUserData(index_t i, const char* tag);
|
|
||||||
bool isCallable(index_t i);
|
|
||||||
|
|
||||||
bool toBool(index_t i);
|
|
||||||
double toNumber(index_t i);
|
|
||||||
int toInt(index_t i);
|
|
||||||
unsigned int toUInt(index_t i);
|
|
||||||
const char* toString(index_t i);
|
|
||||||
void* toUserData(index_t i, const char* tag);
|
|
||||||
|
|
||||||
bool hasProp(index_t i, const char* propName);
|
|
||||||
void getProp(index_t i, const char* propName);
|
|
||||||
void setProp(index_t i, const char* propName);
|
|
||||||
|
|
||||||
bool requireBool(index_t i);
|
|
||||||
double requireNumber(index_t i);
|
|
||||||
int requireInt(index_t i);
|
|
||||||
unsigned int requireUInt(index_t i);
|
|
||||||
const char* requireString(index_t i);
|
|
||||||
void* requireUserData(index_t i, const char* tag);
|
|
||||||
|
|
||||||
void pushUndefined();
|
|
||||||
void pushNull();
|
|
||||||
void pushBool(bool val);
|
|
||||||
void pushNumber(double val);
|
|
||||||
void pushInt(int val);
|
|
||||||
void pushUInt(unsigned int val);
|
|
||||||
void pushString(const char* str);
|
|
||||||
void pushGlobalObject();
|
|
||||||
void newObject();
|
|
||||||
void newObject(const char* className,
|
|
||||||
void* userData,
|
|
||||||
FinalizeFunction finalize);
|
|
||||||
void newUserData(const char* tag,
|
|
||||||
void* userData,
|
|
||||||
FinalizeFunction finalize);
|
|
||||||
|
|
||||||
void registerConstants(index_t idx,
|
|
||||||
const ConstantEntry* consts);
|
|
||||||
void registerProp(index_t idx,
|
|
||||||
const char* id,
|
|
||||||
Function getter,
|
|
||||||
Function setter);
|
|
||||||
void registerProps(index_t idx,
|
|
||||||
const PropertyEntry* props);
|
|
||||||
void registerFunc(index_t idx,
|
|
||||||
const char* id,
|
|
||||||
const Function func,
|
|
||||||
index_t nargs);
|
|
||||||
void registerFuncs(index_t idx,
|
|
||||||
const FunctionEntry* methods);
|
|
||||||
void registerObject(index_t idx,
|
|
||||||
const char* id,
|
|
||||||
const FunctionEntry* methods,
|
|
||||||
const PropertyEntry* props);
|
|
||||||
void registerClass(index_t idx,
|
|
||||||
const char* id,
|
|
||||||
Function ctorFunc, int ctorNargs,
|
|
||||||
const FunctionEntry* methods,
|
|
||||||
const PropertyEntry* props);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ContextHandle m_handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Engine {
|
|
||||||
public:
|
|
||||||
Engine(EngineDelegate* delegate);
|
|
||||||
~Engine();
|
|
||||||
|
|
||||||
void printLastResult();
|
|
||||||
bool eval(const std::string& jsCode,
|
|
||||||
const std::string& filename = std::string());
|
|
||||||
bool evalFile(const std::string& filename);
|
|
||||||
|
|
||||||
Context& context() { return m_ctx; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void onBeforeEval() { }
|
|
||||||
virtual void onAfterEval(bool err) { }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Context m_ctx;
|
|
||||||
EngineDelegate* m_delegate;
|
|
||||||
bool m_printLastResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,22 +0,0 @@
|
||||||
// Aseprite Scripting Library
|
|
||||||
// Copyright (c) 2015-2016 David Capello
|
|
||||||
//
|
|
||||||
// This file is released under the terms of the MIT license.
|
|
||||||
// Read LICENSE.txt for more information.
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "script/engine_delegate.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
namespace script {
|
|
||||||
|
|
||||||
void StdoutEngineDelegate::onConsolePrint(const char* text)
|
|
||||||
{
|
|
||||||
std::printf("%s\n", text);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace script
|
|
|
@ -1,26 +0,0 @@
|
||||||
// Aseprite Scripting Library
|
|
||||||
// Copyright (c) 2015-2016 David Capello
|
|
||||||
//
|
|
||||||
// This file is released under the terms of the MIT license.
|
|
||||||
// Read LICENSE.txt for more information.
|
|
||||||
|
|
||||||
#ifndef SCRIPT_ENGINE_DELEGATE_H_INCLUDED
|
|
||||||
#define SCRIPT_ENGINE_DELEGATE_H_INCLUDED
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace script {
|
|
||||||
|
|
||||||
class EngineDelegate {
|
|
||||||
public:
|
|
||||||
virtual ~EngineDelegate() { }
|
|
||||||
virtual void onConsolePrint(const char* text) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StdoutEngineDelegate : public EngineDelegate {
|
|
||||||
public:
|
|
||||||
void onConsolePrint(const char* text) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -134,10 +134,6 @@ public:
|
||||||
allegro_exit();
|
allegro_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() override {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void activateApp() override {
|
void activateApp() override {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() override {
|
void dispose() override {
|
||||||
|
set_instance(nullptr);
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,4 +28,9 @@ System* instance()
|
||||||
return g_system;
|
return g_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_instance(System* system)
|
||||||
|
{
|
||||||
|
g_system = system;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace she
|
} // namespace she
|
||||||
|
|
|
@ -82,6 +82,7 @@ namespace she {
|
||||||
|
|
||||||
System* create_system();
|
System* create_system();
|
||||||
System* instance();
|
System* instance();
|
||||||
|
void set_instance(System* system);
|
||||||
|
|
||||||
} // namespace she
|
} // namespace she
|
||||||
|
|
||||||
|
|
|
@ -140,36 +140,47 @@ if(ENABLE_BENCHMARKS)
|
||||||
add_subdirectory(benchmark)
|
add_subdirectory(benchmark)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# mujs
|
|
||||||
add_library(mujs
|
|
||||||
mujs/jsarray.c
|
|
||||||
mujs/jsboolean.c
|
|
||||||
mujs/jsbuiltin.c
|
|
||||||
mujs/jscompile.c
|
|
||||||
mujs/jsdate.c
|
|
||||||
mujs/jsdtoa.c
|
|
||||||
mujs/jsdump.c
|
|
||||||
mujs/jserror.c
|
|
||||||
mujs/jsfunction.c
|
|
||||||
mujs/jsgc.c
|
|
||||||
mujs/jsintern.c
|
|
||||||
mujs/jslex.c
|
|
||||||
mujs/jsmath.c
|
|
||||||
mujs/jsnumber.c
|
|
||||||
mujs/jsobject.c
|
|
||||||
mujs/json.c
|
|
||||||
mujs/jsparse.c
|
|
||||||
mujs/jsproperty.c
|
|
||||||
mujs/jsregexp.c
|
|
||||||
mujs/jsrun.c
|
|
||||||
mujs/jsstate.c
|
|
||||||
mujs/jsstring.c
|
|
||||||
mujs/jsvalue.c
|
|
||||||
mujs/regexp.c
|
|
||||||
mujs/utf.c
|
|
||||||
mujs/utftype.c)
|
|
||||||
target_include_directories(mujs PUBLIC .)
|
|
||||||
|
|
||||||
# tinyexpr
|
# tinyexpr
|
||||||
add_library(tinyexpr tinyexpr/tinyexpr.c)
|
add_library(tinyexpr tinyexpr/tinyexpr.c)
|
||||||
target_include_directories(tinyexpr PUBLIC tinyexpr)
|
target_include_directories(tinyexpr PUBLIC tinyexpr)
|
||||||
|
|
||||||
|
# lua
|
||||||
|
add_library(lua
|
||||||
|
lua/lapi.c
|
||||||
|
lua/lcode.c
|
||||||
|
lua/lctype.c
|
||||||
|
lua/ldebug.c
|
||||||
|
lua/ldo.c
|
||||||
|
lua/ldump.c
|
||||||
|
lua/lfunc.c
|
||||||
|
lua/lgc.c
|
||||||
|
lua/llex.c
|
||||||
|
lua/lmem.c
|
||||||
|
lua/lobject.c
|
||||||
|
lua/lopcodes.c
|
||||||
|
lua/lparser.c
|
||||||
|
lua/lstate.c
|
||||||
|
lua/lstring.c
|
||||||
|
lua/ltable.c
|
||||||
|
lua/ltm.c
|
||||||
|
lua/lundump.c
|
||||||
|
lua/lvm.c
|
||||||
|
lua/lzio.c
|
||||||
|
lua/ltests.c)
|
||||||
|
add_library(lauxlib lua/lauxlib.c)
|
||||||
|
add_library(lualib
|
||||||
|
lua/lbaselib.c
|
||||||
|
lua/lcorolib.c
|
||||||
|
lua/ldblib.c
|
||||||
|
lua/linit.c
|
||||||
|
lua/liolib.c
|
||||||
|
lua/lmathlib.c
|
||||||
|
lua/loadlib.c
|
||||||
|
lua/loslib.c
|
||||||
|
lua/lstrlib.c
|
||||||
|
lua/ltablib.c
|
||||||
|
lua/lutf8lib.c)
|
||||||
|
target_include_directories(lua PUBLIC lua)
|
||||||
|
target_include_directories(lauxlib PUBLIC lua)
|
||||||
|
target_include_directories(lualib PUBLIC lua)
|
||||||
|
target_link_libraries(lauxlib lua)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit f59e6a93c0ad38a27a420e51abf8f13d962446b5
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 34cb61711fe29934dfa82ab55ea59ed85ae62642
|
|
Loading…
Reference in New Issue