mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-26 03:35:23 +00:00
Add Image class to scripting
With this change we introduce SpriteWrap and ImageWrap to keep track of modifications made by the script in one transaction. So we can undo the script action as one simple action.
This commit is contained in:
parent
7f31bbef26
commit
956349f87b
@ -2,7 +2,7 @@
|
||||
// Copyright (C) 2015-2016 by David Capello
|
||||
|
||||
var col = app.pixelColor
|
||||
var img = app.activeSprite
|
||||
var img = app.activeImage
|
||||
|
||||
for (y=0; y<img.height; ++y) {
|
||||
for (x=0; x<img.width; ++x) {
|
||||
|
@ -321,7 +321,10 @@ add_library(app-lib
|
||||
script/app_object.cpp
|
||||
script/app_scripting.cpp
|
||||
script/console_object.cpp
|
||||
script/image_class.cpp
|
||||
script/image_wrap.cpp
|
||||
script/sprite_class.cpp
|
||||
script/sprite_wrap.cpp
|
||||
send_crash.cpp
|
||||
shade.cpp
|
||||
shell.cpp
|
||||
|
@ -19,8 +19,11 @@ namespace app {
|
||||
namespace cmd {
|
||||
|
||||
CopyRegion::CopyRegion(Image* dst, const Image* src,
|
||||
const gfx::Region& region, int dst_dx, int dst_dy)
|
||||
const gfx::Region& region,
|
||||
int dst_dx, int dst_dy,
|
||||
bool alreadyCopied)
|
||||
: WithImage(dst)
|
||||
, m_alreadyCopied(alreadyCopied)
|
||||
{
|
||||
// Create region to save/swap later
|
||||
for (const auto& rc : region) {
|
||||
@ -46,7 +49,8 @@ CopyRegion::CopyRegion(Image* dst, const Image* src,
|
||||
|
||||
void CopyRegion::onExecute()
|
||||
{
|
||||
swap();
|
||||
if (!m_alreadyCopied)
|
||||
swap();
|
||||
}
|
||||
|
||||
void CopyRegion::onUndo()
|
||||
|
@ -22,8 +22,13 @@ namespace cmd {
|
||||
class CopyRegion : public Cmd
|
||||
, public WithImage {
|
||||
public:
|
||||
// If alreadyCopied is false, it means that onExecute() will copy
|
||||
// pixels from src to dst. If it's true, it means that "onExecute"
|
||||
// should do nothing, because modified pixels are alreadt on "dst"
|
||||
// (so we use "src" as the original image).
|
||||
CopyRegion(Image* dst, const Image* src,
|
||||
const gfx::Region& region, int src_dx, int src_dy);
|
||||
const gfx::Region& region, int src_dx, int src_dy,
|
||||
bool alreadyCopied = false);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
@ -37,6 +42,7 @@ namespace cmd {
|
||||
private:
|
||||
void swap();
|
||||
|
||||
bool m_alreadyCopied;
|
||||
gfx::Region m_region;
|
||||
std::stringstream m_stream;
|
||||
};
|
||||
|
@ -11,7 +11,9 @@
|
||||
|
||||
#include "app/script/console_object.h"
|
||||
|
||||
#include "app/script/sprite_class.h"
|
||||
#include "app/document.h"
|
||||
#include "app/script/app_scripting.h"
|
||||
#include "app/script/sprite_wrap.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
@ -29,7 +31,20 @@ script::result_t App_get_activeSprite(script::ContextHandle handle)
|
||||
script::Context ctx(handle);
|
||||
app::Document* doc = UIContext::instance()->activeDocument();
|
||||
if (doc)
|
||||
ctx.pushObject(wrap_sprite(doc), "Sprite");
|
||||
ctx.pushObject(unwrap_engine(ctx)->wrapSprite(doc), "Sprite");
|
||||
else
|
||||
ctx.pushNull();
|
||||
return 1;
|
||||
}
|
||||
|
||||
script::result_t App_get_activeImage(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
app::Document* doc = UIContext::instance()->activeDocument();
|
||||
if (doc) {
|
||||
SpriteWrap* wrap = unwrap_engine(ctx)->wrapSprite(doc);
|
||||
ctx.pushObject(wrap->activeImage(), "Image");
|
||||
}
|
||||
else
|
||||
ctx.pushNull();
|
||||
return 1;
|
||||
@ -55,6 +70,7 @@ const script::FunctionEntry App_methods[] = {
|
||||
};
|
||||
|
||||
const script::PropertyEntry App_props[] = {
|
||||
{ "activeImage", App_get_activeImage, nullptr },
|
||||
{ "activeSprite", App_get_activeSprite, nullptr },
|
||||
{ "pixelColor", App_get_pixelColor, nullptr },
|
||||
{ "version", App_get_version, nullptr },
|
||||
|
@ -11,9 +11,13 @@
|
||||
|
||||
#include "app/script/app_scripting.h"
|
||||
|
||||
#include "app/document.h"
|
||||
#include "app/script/app_object.h"
|
||||
#include "app/script/console_object.h"
|
||||
#include "app/script/image_class.h"
|
||||
#include "app/script/image_wrap.h"
|
||||
#include "app/script/sprite_class.h"
|
||||
#include "app/script/sprite_wrap.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -25,8 +29,51 @@ AppScripting::AppScripting(script::EngineDelegate* delegate)
|
||||
register_console_object(ctx);
|
||||
|
||||
ctx.pushGlobalObject();
|
||||
register_image_class(-1, ctx);
|
||||
register_sprite_class(-1, ctx);
|
||||
|
||||
ctx.pushPointer(this);
|
||||
ctx.setProp(-2, script::kPtrId);
|
||||
|
||||
ctx.pop();
|
||||
}
|
||||
|
||||
SpriteWrap* AppScripting::wrapSprite(app::Document* doc)
|
||||
{
|
||||
auto it = m_sprites.find(doc->id());
|
||||
if (it != m_sprites.end())
|
||||
return it->second;
|
||||
else {
|
||||
auto wrap = new SpriteWrap(doc);
|
||||
m_sprites[doc->id()] = wrap;
|
||||
return wrap;
|
||||
}
|
||||
}
|
||||
|
||||
void AppScripting::onAfterEval(bool err)
|
||||
{
|
||||
// Commit all transactions
|
||||
if (!err) {
|
||||
for (auto& it : m_sprites)
|
||||
it.second->commit();
|
||||
}
|
||||
destroyWrappers();
|
||||
}
|
||||
|
||||
void AppScripting::destroyWrappers()
|
||||
{
|
||||
for (auto& it : m_sprites)
|
||||
delete it.second;
|
||||
m_sprites.clear();
|
||||
}
|
||||
|
||||
AppScripting* unwrap_engine(script::Context& ctx)
|
||||
{
|
||||
ctx.pushGlobalObject();
|
||||
ctx.getProp(-1, script::kPtrId);
|
||||
void* ptr = ctx.getPointer(-1);
|
||||
ctx.pop(2);
|
||||
return (AppScripting*)ptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,19 +5,43 @@
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_SCRIPT_H_INCLUDED
|
||||
#define APP_SCRIPT_H_INCLUDED
|
||||
#ifndef APP_SCRIPTING_H_INCLUDED
|
||||
#define APP_SCRIPTING_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/object_id.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace doc {
|
||||
class Image;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Document;
|
||||
class ImageWrap;
|
||||
class SpriteWrap;
|
||||
|
||||
class AppScripting : public script::Engine {
|
||||
typedef std::map<doc::ObjectId, SpriteWrap*> Sprites;
|
||||
|
||||
public:
|
||||
AppScripting(script::EngineDelegate* delegate);
|
||||
|
||||
SpriteWrap* wrapSprite(app::Document* doc);
|
||||
|
||||
protected:
|
||||
void onAfterEval(bool err) override;
|
||||
|
||||
private:
|
||||
void destroyWrappers();
|
||||
|
||||
Sprites m_sprites;
|
||||
};
|
||||
|
||||
AppScripting* unwrap_engine(script::Context& ctx);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
||||
|
101
src/app/script/image_class.cpp
Normal file
101
src/app/script/image_class.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2015-2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/image_class.h"
|
||||
|
||||
#include "app/script/image_wrap.h"
|
||||
#include "doc/image.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
namespace {
|
||||
|
||||
script::result_t Image_ctor(script::ContextHandle handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
script::result_t Image_putPixel(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
int x = ctx.requireInt(0);
|
||||
int y = ctx.requireInt(1);
|
||||
doc::color_t color = ctx.requireUInt(2);
|
||||
|
||||
auto wrap = (ImageWrap*)ctx.getThis();
|
||||
if (wrap) {
|
||||
wrap->modifyRegion(gfx::Region(gfx::Rect(x, y, 1, 1)));
|
||||
wrap->image()->putPixel(x, y, color);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
script::result_t Image_getPixel(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
int x = ctx.requireInt(0);
|
||||
int y = ctx.requireInt(1);
|
||||
|
||||
auto wrap = (ImageWrap*)ctx.getThis();
|
||||
if (wrap) {
|
||||
doc::color_t color = wrap->image()->getPixel(x, y);
|
||||
ctx.pushUInt(color);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
script::result_t Image_get_width(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto wrap = (ImageWrap*)ctx.getThis();
|
||||
if (wrap) {
|
||||
ctx.pushInt(wrap->image()->width());
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
script::result_t Image_get_height(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
auto wrap = (ImageWrap*)ctx.getThis();
|
||||
if (wrap) {
|
||||
ctx.pushInt(wrap->image()->height());
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
const script::FunctionEntry Image_methods[] = {
|
||||
{ "getPixel", Image_getPixel, 2 },
|
||||
{ "putPixel", Image_putPixel, 3 },
|
||||
{ nullptr, nullptr, 0 }
|
||||
};
|
||||
|
||||
const script::PropertyEntry Image_props[] = {
|
||||
{ "width", Image_get_width, nullptr },
|
||||
{ "height", Image_get_height, nullptr },
|
||||
{ nullptr, nullptr, 0 }
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void register_image_class(script::index_t idx, script::Context& ctx)
|
||||
{
|
||||
ctx.registerClass(idx, "Image", Image_ctor, 0, Image_methods, Image_props);
|
||||
}
|
||||
|
||||
} // namespace app
|
20
src/app/script/image_class.h
Normal file
20
src/app/script/image_class.h
Normal file
@ -0,0 +1,20 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_SCRIPT_IMAGE_CLASS_H_INCLUDED
|
||||
#define APP_SCRIPT_IMAGE_CLASS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "script/engine.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
void register_image_class(script::index_t idx, script::Context& ctx);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
52
src/app/script/image_wrap.cpp
Normal file
52
src/app/script/image_wrap.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/image_wrap.h"
|
||||
|
||||
#include "app/cmd/copy_region.h"
|
||||
#include "app/script/sprite_wrap.h"
|
||||
#include "app/transaction.h"
|
||||
#include "doc/image.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
ImageWrap::ImageWrap(SpriteWrap* sprite, doc::Image* img)
|
||||
: m_sprite(sprite)
|
||||
, m_image(img)
|
||||
, m_backup(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ImageWrap::~ImageWrap()
|
||||
{
|
||||
}
|
||||
|
||||
void ImageWrap::commit()
|
||||
{
|
||||
if (m_modifiedRegion.isEmpty())
|
||||
return;
|
||||
|
||||
sprite()->transaction().execute(
|
||||
new cmd::CopyRegion(m_image,
|
||||
m_backup.get(),
|
||||
m_modifiedRegion, 0, 0,
|
||||
true));
|
||||
}
|
||||
|
||||
void ImageWrap::modifyRegion(const gfx::Region& rgn)
|
||||
{
|
||||
if (!m_backup)
|
||||
m_backup.reset(doc::Image::createCopy(m_image));
|
||||
|
||||
m_modifiedRegion |= rgn;
|
||||
}
|
||||
|
||||
} // namespace app
|
39
src/app/script/image_wrap.h
Normal file
39
src/app/script/image_wrap.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_SCRIPT_IMAGE_WRAP_H_INCLUDED
|
||||
#define APP_SCRIPT_IMAGE_WRAP_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/image.h"
|
||||
#include "doc/image_ref.h"
|
||||
#include "gfx/region.h"
|
||||
|
||||
namespace app {
|
||||
class SpriteWrap;
|
||||
|
||||
class ImageWrap {
|
||||
public:
|
||||
ImageWrap(SpriteWrap* sprite, doc::Image* img);
|
||||
~ImageWrap();
|
||||
|
||||
void commit();
|
||||
|
||||
SpriteWrap* sprite() const { return m_sprite; }
|
||||
doc::Image* image() const { return m_image; }
|
||||
|
||||
void modifyRegion(const gfx::Region& rgn);
|
||||
private:
|
||||
SpriteWrap* m_sprite;
|
||||
doc::Image* m_image;
|
||||
doc::ImageRef m_backup;
|
||||
gfx::Region m_modifiedRegion;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -11,8 +11,11 @@
|
||||
|
||||
#include "app/script/sprite_class.h"
|
||||
|
||||
#include "app/cmd/set_sprite_size.h"
|
||||
#include "app/document.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/script/app_scripting.h"
|
||||
#include "app/script/sprite_wrap.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/document_view.h"
|
||||
#include "app/ui_context.h"
|
||||
@ -20,30 +23,10 @@
|
||||
#include "doc/sprite.h"
|
||||
#include "script/engine.h"
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
namespace app {
|
||||
|
||||
namespace {
|
||||
|
||||
class SpriteInScript {
|
||||
public:
|
||||
SpriteInScript(app::Document* doc)
|
||||
: m_doc(doc) {
|
||||
}
|
||||
|
||||
~SpriteInScript() {
|
||||
}
|
||||
|
||||
app::Document* document() {
|
||||
return m_doc;
|
||||
}
|
||||
|
||||
private:
|
||||
app::Document* m_doc;
|
||||
};
|
||||
|
||||
script::result_t Sprite_ctor(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
@ -58,71 +41,22 @@ script::result_t Sprite_ctor(script::ContextHandle handle)
|
||||
sprite.release();
|
||||
|
||||
doc->setContext(UIContext::instance());
|
||||
ctx.pushThis(wrap_sprite(doc.release()));
|
||||
ctx.pushThis(unwrap_engine(ctx)->wrapSprite(doc.release()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
script::result_t Sprite_putPixel(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
int x = ctx.requireInt(0);
|
||||
int y = ctx.requireInt(1);
|
||||
doc::color_t color = ctx.requireUInt(2);
|
||||
|
||||
Document* doc = (Document*)unwrap_sprite(ctx.getThis());
|
||||
DocumentView* docView = UIContext::instance()->getFirstDocumentView(doc);
|
||||
if (!docView)
|
||||
return 0;
|
||||
|
||||
doc::Site site;
|
||||
docView->getSite(&site);
|
||||
|
||||
int celX, celY;
|
||||
doc::Image* image = site.image(&celX, &celY, nullptr);
|
||||
if (image)
|
||||
image->putPixel(x-celX, y-celY, color);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
script::result_t Sprite_getPixel(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
int x = ctx.requireInt(0);
|
||||
int y = ctx.requireInt(1);
|
||||
|
||||
Document* doc = (Document*)unwrap_sprite(ctx.getThis());
|
||||
DocumentView* docView = UIContext::instance()->getFirstDocumentView(doc);
|
||||
if (!docView)
|
||||
return 0;
|
||||
|
||||
doc::Site site;
|
||||
docView->getSite(&site);
|
||||
|
||||
int celX, celY;
|
||||
doc::Image* image = site.image(&celX, &celY, nullptr);
|
||||
if (image) {
|
||||
doc::color_t color = image->getPixel(x-celX, y-celY);
|
||||
ctx.pushUInt(color);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
script::result_t Sprite_resize(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
int w = ctx.requireInt(0);
|
||||
int h = ctx.requireInt(1);
|
||||
|
||||
Document* doc = (Document*)unwrap_sprite(ctx.getThis());
|
||||
{
|
||||
Transaction transaction(UIContext::instance(), "Script Execution", ModifyDocument);
|
||||
DocumentApi api(doc, transaction);
|
||||
auto wrap = (SpriteWrap*)ctx.getThis();
|
||||
if (wrap) {
|
||||
Document* doc = wrap->document();
|
||||
DocumentApi api(doc, wrap->transaction());
|
||||
api.setSpriteSize(doc->sprite(), w, h);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -136,12 +70,11 @@ script::result_t Sprite_crop(script::ContextHandle handle)
|
||||
int w = ctx.requireInt(2);
|
||||
int h = ctx.requireInt(3);
|
||||
|
||||
Document* doc = (Document*)unwrap_sprite(ctx.getThis());
|
||||
{
|
||||
Transaction transaction(UIContext::instance(), "Script Execution", ModifyDocument);
|
||||
DocumentApi api(doc, transaction);
|
||||
auto wrap = (SpriteWrap*)ctx.getThis();
|
||||
if (wrap) {
|
||||
Document* doc = wrap->document();
|
||||
DocumentApi api(doc, wrap->transaction());
|
||||
api.cropSprite(doc->sprite(), gfx::Rect(x, y, w, h));
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -150,8 +83,8 @@ script::result_t Sprite_crop(script::ContextHandle handle)
|
||||
script::result_t Sprite_get_width(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
Document* doc = (Document*)unwrap_sprite(ctx.getThis());
|
||||
ctx.pushInt(doc->sprite()->width());
|
||||
auto wrap = (SpriteWrap*)ctx.getThis();
|
||||
ctx.pushInt(wrap->sprite()->width());
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -159,16 +92,21 @@ script::result_t Sprite_set_width(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
int w = ctx.requireInt(0);
|
||||
Document* doc = (Document*)unwrap_sprite(ctx.getThis());
|
||||
doc->sprite()->setSize(w, doc->sprite()->height());
|
||||
auto wrap = (SpriteWrap*)ctx.getThis();
|
||||
|
||||
wrap->transaction().execute(
|
||||
new cmd::SetSpriteSize(wrap->sprite(),
|
||||
w,
|
||||
wrap->sprite()->height()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
script::result_t Sprite_get_height(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
Document* doc = (Document*)unwrap_sprite(ctx.getThis());
|
||||
ctx.pushInt(doc->sprite()->height());
|
||||
auto wrap = (SpriteWrap*)ctx.getThis();
|
||||
ctx.pushInt(wrap->sprite()->height());
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -176,14 +114,17 @@ script::result_t Sprite_set_height(script::ContextHandle handle)
|
||||
{
|
||||
script::Context ctx(handle);
|
||||
int h = ctx.requireInt(0);
|
||||
Document* doc = (Document*)unwrap_sprite(ctx.getThis());
|
||||
doc->sprite()->setSize(doc->sprite()->width(), h);
|
||||
auto wrap = (SpriteWrap*)ctx.getThis();
|
||||
|
||||
wrap->transaction().execute(
|
||||
new cmd::SetSpriteSize(wrap->sprite(),
|
||||
wrap->sprite()->width(),
|
||||
h));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const script::FunctionEntry Sprite_methods[] = {
|
||||
{ "getPixel", Sprite_getPixel, 2 },
|
||||
{ "putPixel", Sprite_putPixel, 3 },
|
||||
{ "resize", Sprite_resize, 2 },
|
||||
{ "crop", Sprite_crop, 4 },
|
||||
{ nullptr, nullptr, 0 }
|
||||
@ -197,28 +138,6 @@ const script::PropertyEntry Sprite_props[] = {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
static std::map<doc::ObjectId, SpriteInScript*> g_sprites;
|
||||
|
||||
void* wrap_sprite(app::Document* doc)
|
||||
{
|
||||
auto it = g_sprites.find(doc->id());
|
||||
if (it != g_sprites.end())
|
||||
return it->second;
|
||||
else {
|
||||
SpriteInScript* wrap = new SpriteInScript(doc);
|
||||
g_sprites[doc->id()] = wrap;
|
||||
return wrap;
|
||||
}
|
||||
}
|
||||
|
||||
app::Document* unwrap_sprite(void* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
return ((SpriteInScript*)ptr)->document();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void register_sprite_class(script::index_t idx, script::Context& ctx)
|
||||
{
|
||||
ctx.registerClass(idx, "Sprite", Sprite_ctor, 3, Sprite_methods, Sprite_props);
|
||||
|
@ -12,10 +12,6 @@
|
||||
#include "script/engine.h"
|
||||
|
||||
namespace app {
|
||||
class Document;
|
||||
|
||||
void* wrap_sprite(app::Document* doc);
|
||||
app::Document* unwrap_sprite(void* ptr);
|
||||
|
||||
void register_sprite_class(script::index_t idx, script::Context& ctx);
|
||||
|
||||
|
96
src/app/script/sprite_wrap.cpp
Normal file
96
src/app/script/sprite_wrap.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/sprite_wrap.h"
|
||||
|
||||
#include "app/cmd/set_sprite_size.h"
|
||||
#include "app/document.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/script/image_wrap.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/document_view.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "doc/site.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
SpriteWrap::SpriteWrap(app::Document* doc)
|
||||
: m_doc(doc)
|
||||
, m_view(UIContext::instance()->getFirstDocumentView(m_doc))
|
||||
, m_transaction(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SpriteWrap::~SpriteWrap()
|
||||
{
|
||||
for (auto it : m_images)
|
||||
delete it.second;
|
||||
|
||||
if (m_transaction)
|
||||
delete m_transaction;
|
||||
}
|
||||
|
||||
Transaction& SpriteWrap::transaction()
|
||||
{
|
||||
if (!m_transaction) {
|
||||
m_transaction = new Transaction(UIContext::instance(),
|
||||
"Script Execution",
|
||||
ModifyDocument);
|
||||
}
|
||||
return *m_transaction;
|
||||
}
|
||||
|
||||
void SpriteWrap::commit()
|
||||
{
|
||||
for (auto it : m_images)
|
||||
it.second->commit();
|
||||
|
||||
if (m_transaction) {
|
||||
m_transaction->commit();
|
||||
delete m_transaction;
|
||||
m_transaction = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
app::Document* SpriteWrap::document()
|
||||
{
|
||||
return m_doc;
|
||||
}
|
||||
|
||||
doc::Sprite* SpriteWrap::sprite()
|
||||
{
|
||||
return m_doc->sprite();
|
||||
}
|
||||
|
||||
ImageWrap* SpriteWrap::activeImage()
|
||||
{
|
||||
if (!m_view)
|
||||
return nullptr;
|
||||
|
||||
doc::Site site;
|
||||
m_view->getSite(&site);
|
||||
return wrapImage(site.image());
|
||||
}
|
||||
|
||||
ImageWrap* SpriteWrap::wrapImage(doc::Image* img)
|
||||
{
|
||||
auto it = m_images.find(img->id());
|
||||
if (it != m_images.end())
|
||||
return it->second;
|
||||
else {
|
||||
auto wrap = new ImageWrap(this, img);
|
||||
m_images[img->id()] = wrap;
|
||||
return wrap;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
53
src/app/script/sprite_wrap.h
Normal file
53
src/app/script/sprite_wrap.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_SCRIPT_SPRITE_WRAP_H_INCLUDED
|
||||
#define APP_SCRIPT_SPRITE_WRAP_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/object_id.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace doc {
|
||||
class Image;
|
||||
class Sprite;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Document;
|
||||
class DocumentView;
|
||||
class ImageWrap;
|
||||
class Transaction;
|
||||
|
||||
class SpriteWrap {
|
||||
typedef std::map<doc::ObjectId, ImageWrap*> Images;
|
||||
|
||||
public:
|
||||
SpriteWrap(app::Document* doc);
|
||||
~SpriteWrap();
|
||||
|
||||
void commit();
|
||||
Transaction& transaction();
|
||||
|
||||
app::Document* document();
|
||||
doc::Sprite* sprite();
|
||||
ImageWrap* activeImage();
|
||||
|
||||
ImageWrap* wrapImage(doc::Image* img);
|
||||
|
||||
private:
|
||||
app::Document* m_doc;
|
||||
app::DocumentView* m_view;
|
||||
app::Transaction* m_transaction;
|
||||
|
||||
Images m_images;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -30,6 +30,8 @@ public:
|
||||
|
||||
namespace script {
|
||||
|
||||
const char* kPtrId = "\xFF" "\xFF" "ptr";
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO classes in modules isn't supported yet
|
||||
@ -108,6 +110,11 @@ void Context::pop()
|
||||
duk_pop(m_handle);
|
||||
}
|
||||
|
||||
void Context::pop(index_t count)
|
||||
{
|
||||
duk_pop_n(m_handle, count);
|
||||
}
|
||||
|
||||
void Context::remove(index_t idx)
|
||||
{
|
||||
duk_remove(m_handle, idx);
|
||||
@ -193,6 +200,11 @@ const char* Context::toString(index_t i)
|
||||
return duk_to_string(m_handle, i);
|
||||
}
|
||||
|
||||
void* Context::getPointer(index_t i)
|
||||
{
|
||||
return duk_get_pointer(m_handle, i);
|
||||
}
|
||||
|
||||
bool Context::requireBool(index_t i)
|
||||
{
|
||||
return (duk_require_boolean(m_handle, i) ? true: false);
|
||||
@ -220,7 +232,7 @@ const char* Context::requireString(index_t i)
|
||||
|
||||
void* Context::requireObject(index_t i, const char* className)
|
||||
{
|
||||
duk_get_prop_string(m_handle, i, "\xFF" "\xFF" "ptr");
|
||||
duk_get_prop_string(m_handle, i, kPtrId);
|
||||
void* result = (void*)duk_to_pointer(m_handle, -1);
|
||||
// TODO check pointer type
|
||||
duk_pop(m_handle);
|
||||
@ -276,7 +288,12 @@ void Context::pushThis(void* ptr)
|
||||
{
|
||||
duk_push_this(m_handle);
|
||||
duk_push_pointer(m_handle, ptr);
|
||||
duk_put_prop_string(m_handle, -2, "\xFF" "\xFF" "ptr");
|
||||
duk_put_prop_string(m_handle, -2, kPtrId);
|
||||
}
|
||||
|
||||
void Context::pushPointer(void* ptr)
|
||||
{
|
||||
duk_push_pointer(m_handle, ptr);
|
||||
}
|
||||
|
||||
index_t Context::pushObject()
|
||||
@ -288,7 +305,7 @@ index_t Context::pushObject(void* ptr, const char* className)
|
||||
{
|
||||
index_t obj = duk_push_object(m_handle);
|
||||
duk_push_pointer(m_handle, ptr);
|
||||
duk_put_prop_string(m_handle, obj, "\xFF" "\xFF" "ptr");
|
||||
duk_put_prop_string(m_handle, obj, kPtrId);
|
||||
|
||||
// TODO classes in modules isn't supported yet
|
||||
duk_get_global_string(m_handle, className);
|
||||
@ -395,7 +412,7 @@ void Context::registerClass(index_t idx,
|
||||
void* Context::getThis()
|
||||
{
|
||||
duk_push_this(m_handle);
|
||||
duk_get_prop_string(m_handle, -1, "\xFF" "\xFF" "ptr");
|
||||
duk_get_prop_string(m_handle, -1, kPtrId);
|
||||
void* result = (void*)duk_to_pointer(m_handle, -1);
|
||||
duk_pop_2(m_handle);
|
||||
return result;
|
||||
@ -445,6 +462,8 @@ void Engine::printLastResult()
|
||||
|
||||
void Engine::eval(const std::string& jsCode)
|
||||
{
|
||||
bool errFlag = true;
|
||||
onBeforeEval();
|
||||
try {
|
||||
ContextHandle handle = m_ctx.handle();
|
||||
|
||||
@ -453,18 +472,23 @@ void Engine::eval(const std::string& jsCode)
|
||||
if (m_printLastResult &&
|
||||
!duk_is_null_or_undefined(handle, -1)) {
|
||||
m_delegate->onConsolePrint(duk_safe_to_string(handle, -1));
|
||||
}
|
||||
|
||||
duk_pop(handle);
|
||||
errFlag = false;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::string err = "Error: ";
|
||||
err += ex.what();
|
||||
m_delegate->onConsolePrint(err.c_str());
|
||||
}
|
||||
onAfterEval(errFlag);
|
||||
}
|
||||
|
||||
void Engine::evalFile(const std::string& file)
|
||||
{
|
||||
bool errFlag = true;
|
||||
onBeforeEval();
|
||||
try {
|
||||
ContextHandle handle = m_ctx.handle();
|
||||
|
||||
@ -497,14 +521,17 @@ void Engine::evalFile(const std::string& file)
|
||||
if (m_printLastResult &&
|
||||
!duk_is_null_or_undefined(handle, -1)) {
|
||||
m_delegate->onConsolePrint(duk_safe_to_string(handle, -1));
|
||||
}
|
||||
|
||||
duk_pop(handle);
|
||||
errFlag = false;
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
std::string err = "Error: ";
|
||||
err += ex.what();
|
||||
m_delegate->onConsolePrint(err.c_str());
|
||||
}
|
||||
onAfterEval(errFlag);
|
||||
}
|
||||
|
||||
void Engine::registerModule(Module* module)
|
||||
|
@ -21,6 +21,8 @@ namespace script {
|
||||
typedef struct duk_hthread* ContextHandle;
|
||||
typedef result_t (*Function)(ContextHandle ctx);
|
||||
|
||||
extern const char* kPtrId;
|
||||
|
||||
struct FunctionEntry {
|
||||
const char* id;
|
||||
Function value;
|
||||
@ -48,6 +50,7 @@ namespace script {
|
||||
|
||||
void dump();
|
||||
void pop();
|
||||
void pop(index_t count);
|
||||
void remove(index_t idx);
|
||||
void duplicateTop();
|
||||
|
||||
@ -68,6 +71,7 @@ namespace script {
|
||||
unsigned int getUInt(index_t i);
|
||||
const char* getString(index_t i);
|
||||
const char* toString(index_t i);
|
||||
void* getPointer(index_t i);
|
||||
void* getThis();
|
||||
|
||||
bool hasProp(index_t i, const char* propName);
|
||||
@ -91,6 +95,7 @@ namespace script {
|
||||
void pushString(const char* str);
|
||||
void pushThis();
|
||||
void pushThis(void* ptr);
|
||||
void pushPointer(void* ptr);
|
||||
index_t pushObject();
|
||||
index_t pushObject(void* ptr, const char* className);
|
||||
void pushGlobalObject();
|
||||
@ -134,6 +139,10 @@ namespace script {
|
||||
|
||||
void registerModule(Module* module);
|
||||
|
||||
protected:
|
||||
virtual void onBeforeEval() { }
|
||||
virtual void onAfterEval(bool err) { }
|
||||
|
||||
private:
|
||||
Context m_ctx;
|
||||
EngineDelegate* m_delegate;
|
||||
|
Loading…
x
Reference in New Issue
Block a user