mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-30 22:21:12 +00:00
Change scripting language to Lua
This commit is contained in:
parent
70629d6f89
commit
4fe66f2ffb
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -51,9 +51,6 @@
|
||||
[submodule "third_party/benchmark"]
|
||||
path = third_party/benchmark
|
||||
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"]
|
||||
path = third_party/giflib
|
||||
url = https://github.com/aseprite/giflib.git
|
||||
@ -63,3 +60,6 @@
|
||||
[submodule "third_party/tinyexpr"]
|
||||
path = third_party/tinyexpr
|
||||
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" />
|
||||
<!--menu text="Scripts">
|
||||
<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>
|
||||
</menu-->
|
||||
<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))
|
||||
}
|
||||
}
|
17
data/scripts/white_to_alpha.lua
Normal file
17
data/scripts/white_to_alpha.lua
Normal file
@ -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.
|
||||
```
|
||||
|
||||
# [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
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
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" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS 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.
|
||||
```
|
||||
|
||||
# [pixman](http://www.pixman.org/)
|
||||
|
@ -115,11 +115,6 @@ add_subdirectory(ft)
|
||||
add_subdirectory(she)
|
||||
add_subdirectory(ui)
|
||||
|
||||
if(ENABLE_SCRIPTING)
|
||||
add_subdirectory(script)
|
||||
add_definitions(-DENABLE_SCRIPTING)
|
||||
endif()
|
||||
|
||||
if(ENABLE_UPDATER)
|
||||
add_subdirectory(updater)
|
||||
endif()
|
||||
|
@ -140,6 +140,7 @@ endif()
|
||||
|
||||
set(scripting_files)
|
||||
if(ENABLE_SCRIPTING)
|
||||
add_definitions(-DENABLE_SCRIPTING)
|
||||
set(scripting_files_ui)
|
||||
if(ENABLE_UI)
|
||||
set(scripting_files_ui
|
||||
@ -149,10 +150,10 @@ if(ENABLE_SCRIPTING)
|
||||
set(scripting_files
|
||||
commands/cmd_run_script.cpp
|
||||
script/app_object.cpp
|
||||
script/app_scripting.cpp
|
||||
script/console_object.cpp
|
||||
script/engine.cpp
|
||||
script/image_class.cpp
|
||||
script/pixel_color_class.cpp
|
||||
script/luacpp.cpp
|
||||
script/pixel_color_object.cpp
|
||||
script/point_class.cpp
|
||||
script/rectangle_class.cpp
|
||||
script/selection_class.cpp
|
||||
@ -595,7 +596,7 @@ target_link_libraries(app-lib
|
||||
tinyexpr)
|
||||
|
||||
if(ENABLE_SCRIPTING)
|
||||
target_link_libraries(app-lib script-lib)
|
||||
target_link_libraries(app-lib lua lauxlib lualib)
|
||||
endif()
|
||||
|
||||
if(ENABLE_UPDATER)
|
||||
|
@ -70,9 +70,8 @@
|
||||
#include <memory>
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
#include "app/script/app_scripting.h"
|
||||
#include "app/script/engine.h"
|
||||
#include "app/shell.h"
|
||||
#include "script/engine_delegate.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_STEAM
|
||||
@ -353,7 +352,7 @@ void App::run()
|
||||
// Start shell to execute scripts.
|
||||
if (m_isShell) {
|
||||
script::StdoutEngineDelegate delegate;
|
||||
AppScripting engine(&delegate);
|
||||
script::Engine engine(&delegate);
|
||||
engine.printLastResult();
|
||||
Shell shell;
|
||||
shell.run(engine);
|
||||
|
@ -27,8 +27,7 @@
|
||||
#include "doc/sprite.h"
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
#include "app/script/app_scripting.h"
|
||||
#include "script/engine_delegate.h"
|
||||
#include "app/script/engine.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
@ -128,7 +127,7 @@ void DefaultCliDelegate::execScript(const std::string& filename)
|
||||
{
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
script::StdoutEngineDelegate delegate;
|
||||
AppScripting engine(&delegate);
|
||||
script::Engine engine(&delegate);
|
||||
if (!engine.evalFile(filename))
|
||||
throw std::runtime_error("Error executing script");
|
||||
#endif
|
||||
|
@ -16,9 +16,8 @@
|
||||
#include "app/commands/params.h"
|
||||
#include "app/console.h"
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/script/app_scripting.h"
|
||||
#include "app/script/engine.h"
|
||||
#include "base/fs.h"
|
||||
#include "script/engine_delegate.h"
|
||||
#include "ui/manager.h"
|
||||
|
||||
#include <cstdio>
|
||||
@ -67,7 +66,7 @@ void RunScriptCommand::onLoadParams(const Params& params)
|
||||
void RunScriptCommand::onExecute(Context* context)
|
||||
{
|
||||
ConsoleEngineDelegate delegate;
|
||||
AppScripting engine(&delegate);
|
||||
script::Engine engine(&delegate);
|
||||
engine.evalFile(m_filename);
|
||||
|
||||
ui::Manager::getDefault()->invalidate();
|
||||
|
@ -13,154 +13,155 @@
|
||||
#include "app/commands/params.h"
|
||||
#include "app/context.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/tx.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
void App_open(script::ContextHandle handle)
|
||||
int App_open(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
const char* filename = ctx.requireString(1);
|
||||
const char* filename = luaL_checkstring(L, 1);
|
||||
|
||||
app::Context* appCtx = App::instance()->context();
|
||||
Doc* oldDoc = appCtx->activeDocument();
|
||||
app::Context* ctx = App::instance()->context();
|
||||
Doc* oldDoc = ctx->activeDocument();
|
||||
|
||||
Command* openCommand =
|
||||
Commands::instance()->byId(CommandId::OpenFile());
|
||||
Params params;
|
||||
params.set("filename", filename);
|
||||
appCtx->executeCommand(openCommand, params);
|
||||
ctx->executeCommand(openCommand, params);
|
||||
|
||||
Doc* newDoc = appCtx->activeDocument();
|
||||
Doc* newDoc = ctx->activeDocument();
|
||||
if (newDoc != oldDoc)
|
||||
push_sprite(ctx, newDoc->sprite());
|
||||
push_ptr(L, newDoc->sprite());
|
||||
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* appCtx = App::instance()->context();
|
||||
if (appCtx && appCtx->isUIAvailable()) {
|
||||
app::Context* ctx = App::instance()->context();
|
||||
if (ctx && ctx->isUIAvailable()) {
|
||||
Command* exitCommand =
|
||||
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);
|
||||
if (ctx.isCallable(1)) {
|
||||
int top = lua_gettop(L);
|
||||
int nresults = 0;
|
||||
if (lua_isfunction(L, 1)) {
|
||||
Tx tx; // Create a new transaction so it exists in the whole
|
||||
// duration of the argument function call.
|
||||
ctx.copy(1);
|
||||
ctx.call(0);
|
||||
tx.commit();
|
||||
lua_pushvalue(L, -1);
|
||||
if (lua_pcall(L, 0, LUA_MULTRET, 0) == LUA_OK)
|
||||
tx.commit();
|
||||
nresults = lua_gettop(L) - top;
|
||||
}
|
||||
else
|
||||
ctx.pushUndefined();
|
||||
return nresults;
|
||||
}
|
||||
|
||||
void App_undo(script::ContextHandle handle)
|
||||
int App_undo(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
app::Context* appCtx = App::instance()->context();
|
||||
if (appCtx) {
|
||||
app::Context* ctx = App::instance()->context();
|
||||
if (ctx) {
|
||||
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* appCtx = App::instance()->context();
|
||||
if (appCtx) {
|
||||
app::Context* ctx = App::instance()->context();
|
||||
if (ctx) {
|
||||
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* appCtx = App::instance()->context();
|
||||
Doc* doc = appCtx->activeDocument();
|
||||
app::Context* ctx = App::instance()->context();
|
||||
Doc* doc = ctx->activeDocument();
|
||||
if (doc)
|
||||
push_sprite(ctx, doc->sprite());
|
||||
push_ptr(L, doc->sprite());
|
||||
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* appCtx = App::instance()->context();
|
||||
Site site = appCtx->activeSite();
|
||||
app::Context* ctx = App::instance()->context();
|
||||
Site site = ctx->activeSite();
|
||||
if (site.image())
|
||||
push_image(ctx, site.image());
|
||||
push_ptr(L, site.image());
|
||||
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* appCtx = App::instance()->context();
|
||||
Site site = appCtx->activeSite();
|
||||
push_site(ctx, site);
|
||||
app::Context* ctx = App::instance()->context();
|
||||
Site site = ctx->activeSite();
|
||||
push_obj(L, site);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void App_get_pixelColor(script::ContextHandle handle)
|
||||
int App_get_version(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
ctx.newObject("PixelColor", nullptr, nullptr);
|
||||
lua_pushstring(L, VERSION);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void App_get_version(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
ctx.pushString(VERSION);
|
||||
}
|
||||
|
||||
const script::FunctionEntry App_methods[] = {
|
||||
{ "open", App_open, 1 },
|
||||
{ "exit", App_exit, 0 },
|
||||
{ "transaction", App_transaction, 1 },
|
||||
{ "undo", App_undo, 0 },
|
||||
{ "redo", App_redo, 0 },
|
||||
{ nullptr, nullptr, 0 }
|
||||
const luaL_Reg App_methods[] = {
|
||||
{ "open", App_open },
|
||||
{ "exit", App_exit },
|
||||
{ "transaction", App_transaction },
|
||||
{ "undo", App_undo },
|
||||
{ "redo", App_redo },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const script::PropertyEntry App_props[] = {
|
||||
const Property App_properties[] = {
|
||||
{ "activeSprite", App_get_activeSprite, nullptr },
|
||||
{ "activeImage", App_get_activeImage, nullptr },
|
||||
{ "pixelColor", App_get_pixelColor, nullptr },
|
||||
{ "version", App_get_version, nullptr },
|
||||
{ "site", App_get_site, nullptr },
|
||||
{ nullptr, nullptr, 0 }
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void register_app_object(script::Context& ctx)
|
||||
DEF_MTNAME(App);
|
||||
|
||||
void register_app_object(lua_State* L)
|
||||
{
|
||||
ctx.pushGlobalObject();
|
||||
ctx.registerObject(-1, "app", App_methods, App_props);
|
||||
ctx.pop();
|
||||
REG_CLASS(L, App);
|
||||
REG_CLASS_PROPERTIES(L, App);
|
||||
|
||||
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
|
||||
|
@ -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
|
162
src/app/script/engine.cpp
Normal file
162
src/app/script/engine.cpp
Normal file
@ -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
|
72
src/app/script/engine.h
Normal file
72
src/app/script/engine.h
Normal file
@ -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
|
||||
// Copyright (C) 2015-2017 David Capello
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -8,95 +8,78 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/luacpp.h"
|
||||
#include "doc/image.h"
|
||||
#include "script/engine.h"
|
||||
#include "doc/primitives.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTag = "Image";
|
||||
|
||||
void Image_new(script::ContextHandle handle)
|
||||
int Image_new(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
ctx.pushNull(); // TODO
|
||||
lua_pushnil(L); // TODO
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Image_putPixel(script::ContextHandle handle)
|
||||
int Image_putPixel(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto image = (doc::Image*)ctx.toUserData(0, kTag);
|
||||
int x = ctx.requireInt(1);
|
||||
int y = ctx.requireInt(2);
|
||||
doc::color_t color = ctx.requireUInt(3);
|
||||
|
||||
if (image) {
|
||||
image->putPixel(x, y, color);
|
||||
}
|
||||
|
||||
ctx.pushUndefined();
|
||||
auto image = get_ptr<doc::Image>(L, 1);
|
||||
const int x = lua_tointeger(L, 2);
|
||||
const int y = lua_tointeger(L, 3);
|
||||
const doc::color_t color = lua_tointeger(L, 4);
|
||||
doc::put_pixel(image, x, y, color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Image_getPixel(script::ContextHandle handle)
|
||||
int Image_getPixel(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto image = (doc::Image*)ctx.toUserData(0, kTag);
|
||||
int x = ctx.requireInt(1);
|
||||
int y = ctx.requireInt(2);
|
||||
|
||||
if (image) {
|
||||
doc::color_t color = image->getPixel(x, y);
|
||||
ctx.pushUInt(color);
|
||||
}
|
||||
else
|
||||
ctx.pushUndefined();
|
||||
const auto image = get_ptr<doc::Image>(L, 1);
|
||||
const int x = lua_tointeger(L, 2);
|
||||
const int y = lua_tointeger(L, 3);
|
||||
const doc::color_t color = doc::get_pixel(image, x, y);
|
||||
lua_pushinteger(L, color);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Image_get_width(script::ContextHandle handle)
|
||||
int Image_get_width(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto image = (doc::Image*)ctx.toUserData(0, kTag);
|
||||
if (image)
|
||||
ctx.pushInt(image->width());
|
||||
else
|
||||
ctx.pushUndefined();
|
||||
const auto image = get_ptr<doc::Image>(L, 1);
|
||||
lua_pushinteger(L, image->width());
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Image_get_height(script::ContextHandle handle)
|
||||
int Image_get_height(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto image = (doc::Image*)ctx.toUserData(0, kTag);
|
||||
if (image)
|
||||
ctx.pushInt(image->height());
|
||||
else
|
||||
ctx.pushUndefined();
|
||||
const auto image = get_ptr<doc::Image>(L, 1);
|
||||
lua_pushinteger(L, image->height());
|
||||
return 1;
|
||||
}
|
||||
|
||||
const script::FunctionEntry Image_methods[] = {
|
||||
{ "getPixel", Image_getPixel, 2 },
|
||||
{ "putPixel", Image_putPixel, 3 },
|
||||
{ nullptr, nullptr, 0 }
|
||||
const luaL_Reg Image_methods[] = {
|
||||
{ "getPixel", Image_getPixel },
|
||||
{ "putPixel", Image_putPixel },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const script::PropertyEntry Image_props[] = {
|
||||
const Property Image_properties[] = {
|
||||
{ "width", Image_get_width, nullptr },
|
||||
{ "height", Image_get_height, nullptr },
|
||||
{ nullptr, nullptr, 0 }
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // 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,
|
||||
Image_new, 0,
|
||||
Image_methods, Image_props);
|
||||
}
|
||||
|
||||
void push_image(script::Context& ctx, doc::Image* image)
|
||||
{
|
||||
ctx.newObject(kTag, image, nullptr);
|
||||
using doc::Image;
|
||||
REG_CLASS(L, Image);
|
||||
REG_CLASS_NEW(L, Image);
|
||||
REG_CLASS_PROPERTIES(L, Image);
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
86
src/app/script/luacpp.cpp
Normal file
86
src/app/script/luacpp.cpp
Normal file
@ -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
|
118
src/app/script/luacpp.h
Normal file
118
src/app/script/luacpp.h
Normal file
@ -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
|
99
src/app/script/pixel_color_object.cpp
Normal file
99
src/app/script/pixel_color_object.cpp
Normal file
@ -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
|
||||
// Copyright (C) 2017 David Capello
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -8,111 +8,96 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/luacpp.h"
|
||||
#include "gfx/point.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTag = "Point";
|
||||
|
||||
void Point_finalize(script::ContextHandle handle, void* data)
|
||||
gfx::Point Point_new(lua_State* L, int index)
|
||||
{
|
||||
auto pt = (gfx::Point*)data;
|
||||
delete pt;
|
||||
}
|
||||
|
||||
void Point_new(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto pt = new gfx::Point(0, 0);
|
||||
|
||||
gfx::Point pt(0, 0);
|
||||
// Copy other rectangle
|
||||
if (ctx.isUserData(1, kTag)) {
|
||||
auto pt2 = (gfx::Point*)ctx.toUserData(1, kTag);
|
||||
*pt = *pt2;
|
||||
if (auto pt2 = may_get_obj<gfx::Point>(L, index)) {
|
||||
pt = *pt2;
|
||||
}
|
||||
// Convert { x, y } into a Point
|
||||
else if (ctx.isObject(1)) {
|
||||
ctx.getProp(1, "x");
|
||||
ctx.getProp(1, "y");
|
||||
pt->x = ctx.toInt(-2);
|
||||
pt->y = ctx.toInt(-1);
|
||||
ctx.pop(2);
|
||||
else if (lua_istable(L, index)) {
|
||||
lua_getfield(L, index, "x");
|
||||
lua_getfield(L, index, "y");
|
||||
pt.x = lua_tointeger(L, -2);
|
||||
pt.y = lua_tointeger(L, -1);
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
else if (ctx.isNumber(1)) {
|
||||
pt->x = ctx.toInt(1);
|
||||
pt->y = ctx.toInt(2);
|
||||
else {
|
||||
pt.x = lua_tointeger(L, index);
|
||||
pt.y = lua_tointeger(L, index+1);
|
||||
}
|
||||
|
||||
ctx.newObject(kTag, pt, Point_finalize);
|
||||
return pt;
|
||||
}
|
||||
|
||||
void Point_get_x(script::ContextHandle handle)
|
||||
int Point_new(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
|
||||
ASSERT(pt);
|
||||
ctx.pushInt(pt->x);
|
||||
push_obj(L, Point_new(L, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Point_get_y(script::ContextHandle handle)
|
||||
int Point_get_x(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
|
||||
ctx.pushInt(pt->y);
|
||||
const auto pt = get_obj<gfx::Point>(L, 1);
|
||||
lua_pushinteger(L, pt->x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Point_set_x(script::ContextHandle handle)
|
||||
int Point_get_y(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
|
||||
ASSERT(pt);
|
||||
pt->x = ctx.toInt(1);
|
||||
const auto pt = get_obj<gfx::Point>(L, 1);
|
||||
lua_pushinteger(L, pt->y);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Point_set_y(script::ContextHandle handle)
|
||||
int Point_set_x(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto pt = (gfx::Point*)ctx.toUserData(0, kTag);
|
||||
pt->y = ctx.toInt(1);
|
||||
auto pt = get_obj<gfx::Point>(L, 1);
|
||||
pt->x = lua_tointeger(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const script::FunctionEntry Point_methods[] = {
|
||||
{ nullptr, nullptr, 0 }
|
||||
int Point_set_y(lua_State* L)
|
||||
{
|
||||
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 },
|
||||
{ "y", Point_get_y, Point_set_y },
|
||||
{ nullptr, nullptr, 0 }
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // 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,
|
||||
Point_new, 3,
|
||||
Point_methods,
|
||||
Point_props);
|
||||
using gfx::Point;
|
||||
REG_CLASS(L, Point);
|
||||
REG_CLASS_NEW(L, Point);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
return Point_new(L, index);
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -8,151 +8,132 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/luacpp.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTag = "Rectangle";
|
||||
|
||||
void Rectangle_finalize(script::ContextHandle handle, void* data)
|
||||
gfx::Rect Rectangle_new(lua_State* L, int index)
|
||||
{
|
||||
auto rc = (gfx::Rect*)data;
|
||||
delete rc;
|
||||
}
|
||||
|
||||
void Rectangle_new(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = new gfx::Rect(0, 0, 0, 0);
|
||||
|
||||
gfx::Rect rc(0, 0, 0, 0);
|
||||
// Copy other rectangle
|
||||
if (ctx.isUserData(1, kTag)) {
|
||||
auto rc2 = (gfx::Rect*)ctx.toUserData(1, kTag);
|
||||
*rc = *rc2;
|
||||
if (auto rc2 = may_get_obj<gfx::Rect>(L, index)) {
|
||||
rc = *rc2;
|
||||
}
|
||||
// Convert { x, y, width, height } into a Rectangle
|
||||
else if (ctx.isObject(1)) {
|
||||
ctx.getProp(1, "x");
|
||||
ctx.getProp(1, "y");
|
||||
ctx.getProp(1, "width");
|
||||
ctx.getProp(1, "height");
|
||||
rc->x = ctx.toInt(-4);
|
||||
rc->y = ctx.toInt(-3);
|
||||
rc->w = ctx.toInt(-2);
|
||||
rc->h = ctx.toInt(-1);
|
||||
ctx.pop(4);
|
||||
else if (lua_istable(L, index)) {
|
||||
lua_getfield(L, index, "x");
|
||||
lua_getfield(L, index, "y");
|
||||
lua_getfield(L, index, "width");
|
||||
lua_getfield(L, index, "height");
|
||||
rc.x = lua_tointeger(L, -4);
|
||||
rc.y = lua_tointeger(L, -3);
|
||||
rc.w = lua_tointeger(L, -2);
|
||||
rc.h = lua_tointeger(L, -1);
|
||||
lua_pop(L, 4);
|
||||
}
|
||||
else if (ctx.isNumber(1)) {
|
||||
rc->x = ctx.toInt(1);
|
||||
rc->y = ctx.toInt(2);
|
||||
rc->w = ctx.toInt(3);
|
||||
rc->h = ctx.toInt(4);
|
||||
else {
|
||||
rc.x = lua_tointeger(L, index);
|
||||
rc.y = lua_tointeger(L, index+1);
|
||||
rc.w = lua_tointeger(L, index+2);
|
||||
rc.h = lua_tointeger(L, index+3);
|
||||
}
|
||||
|
||||
ctx.newObject(kTag, rc, Rectangle_finalize);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Rectangle_get_x(script::ContextHandle handle)
|
||||
int Rectangle_new(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
||||
ASSERT(rc);
|
||||
ctx.pushInt(rc->x);
|
||||
push_obj(L, Rectangle_new(L, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Rectangle_get_y(script::ContextHandle handle)
|
||||
int Rectangle_get_x(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
||||
ctx.pushInt(rc->y);
|
||||
const auto rc = get_obj<gfx::Rect>(L, 1);
|
||||
lua_pushinteger(L, rc->x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Rectangle_get_width(script::ContextHandle handle)
|
||||
int Rectangle_get_y(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
||||
ASSERT(rc);
|
||||
ctx.pushInt(rc->w);
|
||||
const auto rc = get_obj<gfx::Rect>(L, 1);
|
||||
lua_pushinteger(L, rc->y);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Rectangle_get_height(script::ContextHandle handle)
|
||||
int Rectangle_get_width(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
||||
ASSERT(rc);
|
||||
ctx.pushInt(rc->h);
|
||||
const auto rc = get_obj<gfx::Rect>(L, 1);
|
||||
lua_pushinteger(L, rc->w);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Rectangle_set_x(script::ContextHandle handle)
|
||||
int Rectangle_get_height(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
||||
ASSERT(rc);
|
||||
rc->x = ctx.toInt(1);
|
||||
const auto rc = get_obj<gfx::Rect>(L, 1);
|
||||
lua_pushinteger(L, rc->h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Rectangle_set_y(script::ContextHandle handle)
|
||||
int Rectangle_set_x(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
||||
rc->y = ctx.toInt(1);
|
||||
auto rc = get_obj<gfx::Rect>(L, 1);
|
||||
rc->x = lua_tointeger(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Rectangle_set_width(script::ContextHandle handle)
|
||||
int Rectangle_set_y(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
||||
ASSERT(rc);
|
||||
rc->w = ctx.toInt(1);
|
||||
auto rc = get_obj<gfx::Rect>(L, 1);
|
||||
rc->y = lua_tointeger(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Rectangle_set_height(script::ContextHandle handle)
|
||||
int Rectangle_set_width(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto rc = (gfx::Rect*)ctx.toUserData(0, kTag);
|
||||
ASSERT(rc);
|
||||
rc->h = ctx.toInt(1);
|
||||
auto rc = get_obj<gfx::Rect>(L, 1);
|
||||
rc->w = lua_tointeger(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const script::FunctionEntry Rectangle_methods[] = {
|
||||
{ nullptr, nullptr, 0 }
|
||||
int Rectangle_set_height(lua_State* L)
|
||||
{
|
||||
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 },
|
||||
{ "y", Rectangle_get_y, Rectangle_set_y },
|
||||
{ "width", Rectangle_get_width, Rectangle_set_width },
|
||||
{ "height", Rectangle_get_height, Rectangle_set_height },
|
||||
{ nullptr, nullptr, 0 }
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // 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,
|
||||
Rectangle_new, 3,
|
||||
Rectangle_methods,
|
||||
Rectangle_props);
|
||||
using Rectangle = gfx::Rect;
|
||||
REG_CLASS(L, Rectangle);
|
||||
REG_CLASS_NEW(L, Rectangle);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
return Rectangle_new(L, index);
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
@ -11,20 +11,19 @@
|
||||
#include "app/cmd/deselect_mask.h"
|
||||
#include "app/cmd/set_mask.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/tx.h"
|
||||
#include "doc/mask.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTag = "Selection";
|
||||
|
||||
struct SelectionObject {
|
||||
Mask* mask;
|
||||
Sprite* sprite;
|
||||
@ -32,29 +31,35 @@ struct SelectionObject {
|
||||
: mask(mask)
|
||||
, sprite(sprite) {
|
||||
}
|
||||
SelectionObject(SelectionObject&& that)
|
||||
: mask(that.mask)
|
||||
, sprite(that.sprite) {
|
||||
that.mask = nullptr;
|
||||
that.sprite = nullptr;
|
||||
}
|
||||
~SelectionObject() {
|
||||
if (!sprite && 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;
|
||||
delete obj;
|
||||
push_obj(L, SelectionObject(new Mask, nullptr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Selection_new(script::ContextHandle handle)
|
||||
int Selection_gc(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
ctx.newObject(kTag, new SelectionObject(new Mask, nullptr), Selection_finalize);
|
||||
get_obj<SelectionObject>(L, 1)->~SelectionObject();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Selection_deselect(script::ContextHandle handle)
|
||||
int Selection_deselect(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
|
||||
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
|
||||
auto obj = get_obj<SelectionObject>(L, 1);
|
||||
if (obj) {
|
||||
if (obj->sprite) {
|
||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||
@ -69,114 +74,101 @@ void Selection_deselect(script::ContextHandle handle)
|
||||
obj->mask->clear();
|
||||
}
|
||||
}
|
||||
ctx.pushUndefined();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Selection_select(script::ContextHandle handle)
|
||||
int Selection_select(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
|
||||
gfx::Rect bounds = convert_args_into_rectangle(ctx);
|
||||
gfx::Rect bounds = convert_args_into_rect(L, 2);
|
||||
if (bounds.isEmpty())
|
||||
return Selection_deselect(L);
|
||||
|
||||
if (obj) {
|
||||
if (bounds.isEmpty()) {
|
||||
Selection_deselect(handle);
|
||||
return;
|
||||
auto obj = get_obj<SelectionObject>(L, 1);
|
||||
if (obj->sprite) {
|
||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||
ASSERT(doc);
|
||||
|
||||
Mask newMask;
|
||||
newMask.replace(bounds);
|
||||
|
||||
Tx tx;
|
||||
tx(new cmd::SetMask(doc, &newMask));
|
||||
tx.commit();
|
||||
}
|
||||
else {
|
||||
obj->mask->replace(bounds);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Selection_selectAll(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<SelectionObject>(L, 1);
|
||||
if (obj->sprite) {
|
||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||
|
||||
Mask newMask;
|
||||
newMask.replace(obj->sprite->bounds());
|
||||
|
||||
Tx tx;
|
||||
tx(new cmd::SetMask(doc, &newMask));
|
||||
tx.commit();
|
||||
}
|
||||
else {
|
||||
gfx::Rect bounds = obj->mask->bounds();
|
||||
if (!bounds.isEmpty())
|
||||
obj->mask->replace(bounds);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Selection_get_bounds(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<SelectionObject>(L, 1);
|
||||
if (obj->sprite) {
|
||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||
if (doc->isMaskVisible()) {
|
||||
push_obj(L, doc->mask()->bounds());
|
||||
}
|
||||
else {
|
||||
if (obj->sprite) {
|
||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||
ASSERT(doc);
|
||||
|
||||
Mask newMask;
|
||||
newMask.replace(bounds);
|
||||
|
||||
Tx tx;
|
||||
tx(new cmd::SetMask(doc, &newMask));
|
||||
tx.commit();
|
||||
}
|
||||
else {
|
||||
obj->mask->replace(bounds);
|
||||
}
|
||||
else { // Empty rectangle
|
||||
push_obj(L, gfx::Rect(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
ctx.pushUndefined();
|
||||
}
|
||||
|
||||
void Selection_selectAll(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
|
||||
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
|
||||
if (obj) {
|
||||
if (obj->sprite) {
|
||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||
|
||||
Mask newMask;
|
||||
newMask.replace(obj->sprite->bounds());
|
||||
|
||||
Tx tx;
|
||||
tx(new cmd::SetMask(doc, &newMask));
|
||||
tx.commit();
|
||||
}
|
||||
else {
|
||||
gfx::Rect bounds = obj->mask->bounds();
|
||||
if (!bounds.isEmpty())
|
||||
obj->mask->replace(bounds);
|
||||
}
|
||||
else {
|
||||
push_obj(L, obj->mask->bounds());
|
||||
}
|
||||
ctx.pushUndefined();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Selection_get_bounds(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto obj = (SelectionObject*)ctx.toUserData(0, kTag);
|
||||
if (obj) {
|
||||
if (obj->sprite) {
|
||||
Doc* doc = static_cast<Doc*>(obj->sprite->document());
|
||||
if (doc->isMaskVisible()) {
|
||||
push_new_rectangle(ctx, doc->mask()->bounds());
|
||||
}
|
||||
else { // Empty rectangle
|
||||
push_new_rectangle(ctx, gfx::Rect(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
else {
|
||||
push_new_rectangle(ctx, obj->mask->bounds());
|
||||
}
|
||||
}
|
||||
else
|
||||
ctx.pushUndefined();
|
||||
}
|
||||
|
||||
const script::FunctionEntry Selection_methods[] = {
|
||||
{ "deselect", Selection_deselect, 1 },
|
||||
{ "select", Selection_select, 4 },
|
||||
{ "selectAll", Selection_selectAll, 0 },
|
||||
{ nullptr, nullptr, 0 }
|
||||
const luaL_Reg Selection_methods[] = {
|
||||
{ "deselect", Selection_deselect },
|
||||
{ "select", Selection_select },
|
||||
{ "selectAll", Selection_selectAll },
|
||||
{ "__gc", Selection_gc },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const script::PropertyEntry Selection_props[] = {
|
||||
const Property Selection_properties[] = {
|
||||
{ "bounds", Selection_get_bounds, nullptr },
|
||||
{ nullptr, nullptr, 0 }
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // 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,
|
||||
Selection_new, 3,
|
||||
Selection_methods,
|
||||
Selection_props);
|
||||
using Selection = SelectionObject;
|
||||
REG_CLASS(L, Selection);
|
||||
REG_CLASS_NEW(L, Selection);
|
||||
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,
|
||||
new SelectionObject(nullptr, sprite),
|
||||
Selection_finalize);
|
||||
push_obj(L, SelectionObject(nullptr, sprite));
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
@ -8,64 +8,54 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/app_scripting.h"
|
||||
#include "app/script/engine.h"
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/site.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTag = "Site";
|
||||
|
||||
void Site_finalize(script::ContextHandle handle, void* data)
|
||||
int Site_get_sprite(lua_State* L)
|
||||
{
|
||||
auto site = (app::Site*)data;
|
||||
delete site;
|
||||
}
|
||||
|
||||
void Site_get_sprite(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto site = (app::Site*)ctx.toUserData(0, kTag);
|
||||
auto site = get_obj<Site>(L, 1);
|
||||
if (site->sprite())
|
||||
push_sprite(ctx, site->sprite());
|
||||
push_ptr(L, site->sprite());
|
||||
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 = (app::Site*)ctx.toUserData(0, kTag);
|
||||
auto site = get_obj<Site>(L, 1);
|
||||
if (site->image())
|
||||
push_image(ctx, site->image());
|
||||
push_ptr(L, site->image());
|
||||
else
|
||||
ctx.pushNull();
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const script::FunctionEntry Site_methods[] = {
|
||||
{ nullptr, nullptr, 0 }
|
||||
const luaL_Reg Site_methods[] = {
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const script::PropertyEntry Site_props[] = {
|
||||
const Property Site_properties[] = {
|
||||
{ "sprite", Site_get_sprite, nullptr },
|
||||
{ "image", Site_get_image, nullptr },
|
||||
{ nullptr, nullptr, 0 }
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // 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,
|
||||
nullptr, 0,
|
||||
Site_methods,
|
||||
Site_props);
|
||||
}
|
||||
|
||||
void push_site(script::Context& ctx, app::Site& site)
|
||||
{
|
||||
ctx.newObject(kTag, new app::Site(site), Site_finalize);
|
||||
REG_CLASS(L, Site);
|
||||
REG_CLASS_PROPERTIES(L, Site);
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -8,113 +8,100 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/luacpp.h"
|
||||
#include "gfx/size.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTag = "Size";
|
||||
|
||||
void Size_finalize(script::ContextHandle handle, void* data)
|
||||
gfx::Size Size_new(lua_State* L, int index)
|
||||
{
|
||||
auto sz = (gfx::Size*)data;
|
||||
delete sz;
|
||||
}
|
||||
|
||||
void Size_new(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sz = new gfx::Size(0, 0);
|
||||
|
||||
gfx::Size sz(0, 0);
|
||||
// Copy other size
|
||||
if (ctx.isUserData(1, kTag)) {
|
||||
auto sz2 = (gfx::Size*)ctx.toUserData(1, kTag);
|
||||
*sz = *sz2;
|
||||
if (auto sz2 = may_get_obj<gfx::Size>(L, index)) {
|
||||
sz = *sz2;
|
||||
}
|
||||
// Convert { width, height } into a Size
|
||||
else if (ctx.isObject(1)) {
|
||||
ctx.getProp(1, "width");
|
||||
ctx.getProp(1, "height");
|
||||
sz->w = ctx.toInt(-2);
|
||||
sz->h = ctx.toInt(-1);
|
||||
ctx.pop(4);
|
||||
else if (lua_istable(L, index)) {
|
||||
lua_getfield(L, index, "width");
|
||||
lua_getfield(L, index, "height");
|
||||
sz.w = lua_tointeger(L, -2);
|
||||
sz.h = lua_tointeger(L, -1);
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
else if (ctx.isNumber(1)) {
|
||||
sz->w = ctx.toInt(1);
|
||||
sz->h = ctx.toInt(2);
|
||||
else {
|
||||
sz.w = lua_tointeger(L, index);
|
||||
sz.h = lua_tointeger(L, index+1);
|
||||
}
|
||||
|
||||
ctx.newObject(kTag, sz, Size_finalize);
|
||||
return sz;
|
||||
}
|
||||
|
||||
void Size_get_width(script::ContextHandle handle)
|
||||
int Size_new(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
|
||||
ASSERT(sz);
|
||||
ctx.pushInt(sz->w);
|
||||
push_obj(L, Size_new(L, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Size_get_height(script::ContextHandle handle)
|
||||
int Size_get_width(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
|
||||
const auto sz = get_obj<gfx::Size>(L, 1);
|
||||
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);
|
||||
auto sz = (gfx::Size*)ctx.toUserData(0, kTag);
|
||||
const auto sz = get_obj<gfx::Size>(L, 1);
|
||||
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 = (gfx::Size*)ctx.toUserData(0, kTag);
|
||||
auto sz = get_obj<gfx::Size>(L, 1);
|
||||
ASSERT(sz);
|
||||
sz->h = ctx.toInt(1);
|
||||
sz->w = lua_tointeger(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const script::FunctionEntry Size_methods[] = {
|
||||
{ nullptr, nullptr, 0 }
|
||||
int Size_set_height(lua_State* L)
|
||||
{
|
||||
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 },
|
||||
{ "height", Size_get_height, Size_set_height },
|
||||
{ nullptr, nullptr, 0 }
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // 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,
|
||||
Size_new, 3,
|
||||
Size_methods,
|
||||
Size_props);
|
||||
using gfx::Size;
|
||||
REG_CLASS(L, Size);
|
||||
REG_CLASS_NEW(L, Size);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
return Size_new(L, index);
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
@ -16,7 +16,8 @@
|
||||
#include "app/doc.h"
|
||||
#include "app/doc_api.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/transaction.h"
|
||||
#include "app/tx.h"
|
||||
@ -24,80 +25,70 @@
|
||||
#include "doc/mask.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTag = "Sprite";
|
||||
|
||||
void Sprite_new(script::ContextHandle handle)
|
||||
int Sprite_new(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
int w = ctx.requireInt(1);
|
||||
int h = ctx.requireInt(2);
|
||||
int colorMode = (ctx.isUndefined(3) ? IMAGE_RGB: ctx.requireInt(3));
|
||||
const int w = lua_tointeger(L, 1);
|
||||
const int h = lua_tointeger(L, 2);
|
||||
const int colorMode = (lua_isnone(L, 3) ? IMAGE_RGB: lua_tointeger(L, 3));
|
||||
|
||||
std::unique_ptr<Sprite> sprite(
|
||||
Sprite::createBasicSprite((doc::PixelFormat)colorMode, w, h, 256));
|
||||
std::unique_ptr<Doc> doc(new Doc(sprite.get()));
|
||||
sprite.release();
|
||||
|
||||
app::Context* appCtx = App::instance()->context();
|
||||
doc->setContext(appCtx);
|
||||
app::Context* ctx = App::instance()->context();
|
||||
doc->setContext(ctx);
|
||||
|
||||
ctx.newObject(kTag, doc->sprite(), nullptr);
|
||||
push_ptr(L, doc->sprite());
|
||||
doc.release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Sprite_resize(script::ContextHandle handle)
|
||||
int Sprite_resize(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
Sprite* sprite = (Sprite*)ctx.toUserData(0, kTag);
|
||||
gfx::Size size = convert_args_into_size(ctx);
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
const gfx::Size size = convert_args_into_size(L, 2);
|
||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||
Tx tx;
|
||||
DocApi(doc, tx).setSpriteSize(doc->sprite(), size.w, size.h);
|
||||
tx.commit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sprite) {
|
||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||
int Sprite_crop(lua_State* L)
|
||||
{
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||
gfx::Rect bounds;
|
||||
|
||||
// Use mask bounds
|
||||
if (lua_isnone(L, 2)) {
|
||||
if (doc->isMaskVisible())
|
||||
bounds = doc->mask()->bounds();
|
||||
else
|
||||
bounds = sprite->bounds();
|
||||
}
|
||||
else {
|
||||
bounds = convert_args_into_rect(L, 2);
|
||||
}
|
||||
|
||||
if (!bounds.isEmpty()) {
|
||||
Tx tx;
|
||||
DocApi(doc, tx).setSpriteSize(doc->sprite(), size.w, size.h);
|
||||
DocApi(doc, tx).cropSprite(sprite, bounds);
|
||||
tx.commit();
|
||||
}
|
||||
ctx.pushUndefined();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sprite_crop(script::ContextHandle handle)
|
||||
int Sprite_save(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
||||
if (sprite) {
|
||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||
gfx::Rect bounds;
|
||||
|
||||
// Use mask bounds
|
||||
if (ctx.isUndefined(1)) {
|
||||
if (doc->isMaskVisible())
|
||||
bounds = doc->mask()->bounds();
|
||||
else
|
||||
bounds = sprite->bounds();
|
||||
}
|
||||
else {
|
||||
bounds = convert_args_into_rectangle(ctx);
|
||||
}
|
||||
|
||||
if (!bounds.isEmpty()) {
|
||||
Tx tx;
|
||||
DocApi(doc, tx).cropSprite(sprite, bounds);
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
ctx.pushUndefined();
|
||||
}
|
||||
|
||||
void Sprite_save(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
if (sprite) {
|
||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||
app::Context* appCtx = App::instance()->context();
|
||||
@ -106,16 +97,13 @@ void Sprite_save(script::ContextHandle handle)
|
||||
Commands::instance()->byId(CommandId::SaveFile());
|
||||
appCtx->executeCommand(saveCommand);
|
||||
}
|
||||
|
||||
ctx.pushUndefined();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sprite_saveAs(script::ContextHandle handle)
|
||||
int Sprite_saveAs(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
||||
const char* fn = ctx.requireString(1);
|
||||
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
const char* fn = luaL_checkstring(L, 2);
|
||||
if (fn && sprite) {
|
||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||
app::Context* appCtx = App::instance()->context();
|
||||
@ -128,16 +116,13 @@ void Sprite_saveAs(script::ContextHandle handle)
|
||||
doc->setFilename(fn);
|
||||
appCtx->executeCommand(saveCommand, params);
|
||||
}
|
||||
|
||||
ctx.pushUndefined();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sprite_saveCopyAs(script::ContextHandle handle)
|
||||
int Sprite_saveCopyAs(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
||||
const char* fn = ctx.requireString(1);
|
||||
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
const char* fn = luaL_checkstring(L, 2);
|
||||
if (fn && sprite) {
|
||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||
app::Context* appCtx = App::instance()->context();
|
||||
@ -150,16 +135,13 @@ void Sprite_saveCopyAs(script::ContextHandle handle)
|
||||
params.set("filename", fn);
|
||||
appCtx->executeCommand(saveCommand, params);
|
||||
}
|
||||
|
||||
ctx.pushUndefined();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sprite_loadPalette(script::ContextHandle handle)
|
||||
int Sprite_loadPalette(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
||||
const char* fn = ctx.toString(1);
|
||||
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
const char* fn = luaL_checkstring(L, 2);
|
||||
if (fn && sprite) {
|
||||
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||
std::unique_ptr<doc::Palette> palette(load_palette(fn));
|
||||
@ -170,100 +152,94 @@ void Sprite_loadPalette(script::ContextHandle handle)
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
|
||||
ctx.pushUndefined();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sprite_get_filename(script::ContextHandle handle)
|
||||
int Sprite_get_filename(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
||||
ctx.pushString(sprite->document()->filename().c_str());
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
lua_pushstring(L, 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 = (doc::Sprite*)ctx.toUserData(0, kTag);
|
||||
ctx.pushInt(sprite->width());
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
lua_pushinteger(L, sprite->width());
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Sprite_set_width(script::ContextHandle handle)
|
||||
int Sprite_get_height(lua_State* L)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sprite = (Sprite*)ctx.toUserData(0, kTag);
|
||||
const int width = ctx.requireInt(1);
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
lua_pushinteger(L, sprite->height());
|
||||
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(new cmd::SetSpriteSize(sprite,
|
||||
width, sprite->height()));
|
||||
tx(new cmd::SetSpriteSize(sprite, width, sprite->height()));
|
||||
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 = (doc::Sprite*)ctx.toUserData(0, kTag);
|
||||
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);
|
||||
auto sprite = get_ptr<Sprite>(L, 1);
|
||||
const int height = lua_tointeger(L, 2);
|
||||
Tx tx;
|
||||
tx(new cmd::SetSpriteSize(sprite,
|
||||
sprite->width(), height));
|
||||
tx(new cmd::SetSpriteSize(sprite, sprite->width(), height));
|
||||
tx.commit();
|
||||
ctx.pushUndefined();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sprite_get_colorMode(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto sprite = (doc::Sprite*)ctx.toUserData(0, kTag);
|
||||
ctx.pushInt(sprite->pixelFormat());
|
||||
}
|
||||
|
||||
void Sprite_get_selection(script::ContextHandle handle)
|
||||
{
|
||||
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 luaL_Reg Sprite_methods[] = {
|
||||
{ "resize", Sprite_resize },
|
||||
{ "crop", Sprite_crop },
|
||||
{ "save", Sprite_save },
|
||||
{ "saveAs", Sprite_saveAs },
|
||||
{ "saveCopyAs", Sprite_saveCopyAs },
|
||||
{ "loadPalette", Sprite_loadPalette },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const script::PropertyEntry Sprite_props[] = {
|
||||
const Property Sprite_properties[] = {
|
||||
{ "filename", Sprite_get_filename, nullptr },
|
||||
{ "width", Sprite_get_width, Sprite_set_width },
|
||||
{ "height", Sprite_get_height, Sprite_set_height },
|
||||
{ "colorMode", Sprite_get_colorMode, nullptr },
|
||||
{ "selection", Sprite_get_selection, nullptr },
|
||||
{ nullptr, nullptr, 0 }
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // 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,
|
||||
Sprite_new, 3,
|
||||
Sprite_methods, Sprite_props);
|
||||
}
|
||||
|
||||
void push_sprite(script::Context& ctx, Sprite* sprite)
|
||||
{
|
||||
ctx.newObject(kTag, sprite, nullptr);
|
||||
using doc::Sprite;
|
||||
REG_CLASS(L, Sprite);
|
||||
REG_CLASS_NEW(L, Sprite);
|
||||
REG_CLASS_PROPERTIES(L, Sprite);
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
@ -31,10 +31,10 @@ Shell::~Shell()
|
||||
|
||||
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;
|
||||
while (std::getline(std::cin, line)) {
|
||||
engine.eval(line);
|
||||
engine.evalCode(line);
|
||||
}
|
||||
std::cout << "Done\n";
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -12,11 +12,10 @@
|
||||
#error ENABLE_SCRIPTING must be defined
|
||||
#endif
|
||||
|
||||
namespace script {
|
||||
class Engine;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
class Engine;
|
||||
}
|
||||
|
||||
class Shell {
|
||||
public:
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -63,7 +63,7 @@ protected:
|
||||
|
||||
DevConsoleView::DevConsoleView()
|
||||
: 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_entry(new CommmandEntry)
|
||||
, m_engine(this)
|
||||
@ -137,7 +137,7 @@ bool DevConsoleView::onProcessMessage(Message* msg)
|
||||
void DevConsoleView::onExecuteCommand(const std::string& cmd)
|
||||
{
|
||||
m_engine.printLastResult();
|
||||
m_engine.eval(cmd);
|
||||
m_engine.evalCode(cmd);
|
||||
}
|
||||
|
||||
void DevConsoleView::onConsolePrint(const char* text)
|
||||
|
@ -12,10 +12,9 @@
|
||||
#error ENABLE_SCRIPTING must be defined
|
||||
#endif
|
||||
|
||||
#include "app/script/app_scripting.h"
|
||||
#include "app/script/engine.h"
|
||||
#include "app/ui/tabs.h"
|
||||
#include "app/ui/workspace_view.h"
|
||||
#include "script/engine_delegate.h"
|
||||
#include "ui/box.h"
|
||||
#include "ui/label.h"
|
||||
#include "ui/textbox.h"
|
||||
@ -57,7 +56,7 @@ namespace app {
|
||||
ui::HBox m_bottomBox;
|
||||
ui::Label m_label;
|
||||
CommmandEntry* m_entry;
|
||||
AppScripting m_engine;
|
||||
script::Engine m_engine;
|
||||
};
|
||||
|
||||
} // 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();
|
||||
}
|
||||
|
||||
void dispose() override {
|
||||
delete this;
|
||||
}
|
||||
|
||||
void activateApp() override {
|
||||
// Do nothing
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ public:
|
||||
}
|
||||
|
||||
void dispose() override {
|
||||
set_instance(nullptr);
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
@ -28,4 +28,9 @@ System* instance()
|
||||
return g_system;
|
||||
}
|
||||
|
||||
void set_instance(System* system)
|
||||
{
|
||||
g_system = system;
|
||||
}
|
||||
|
||||
} // namespace she
|
||||
|
@ -82,6 +82,7 @@ namespace she {
|
||||
|
||||
System* create_system();
|
||||
System* instance();
|
||||
void set_instance(System* system);
|
||||
|
||||
} // namespace she
|
||||
|
||||
|
71
third_party/CMakeLists.txt
vendored
71
third_party/CMakeLists.txt
vendored
@ -140,36 +140,47 @@ if(ENABLE_BENCHMARKS)
|
||||
add_subdirectory(benchmark)
|
||||
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
|
||||
add_library(tinyexpr tinyexpr/tinyexpr.c)
|
||||
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)
|
||||
|
1
third_party/lua
vendored
Submodule
1
third_party/lua
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit f59e6a93c0ad38a27a420e51abf8f13d962446b5
|
1
third_party/mujs
vendored
1
third_party/mujs
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 34cb61711fe29934dfa82ab55ea59ed85ae62642
|
Loading…
x
Reference in New Issue
Block a user