[aseprite] 157/196: Add Image class to scripting

Tobias Hansen thansen at moszumanska.debian.org
Wed Apr 20 18:50:15 UTC 2016


This is an automated email from the git hooks/post-receive script.

thansen pushed a commit to branch master
in repository aseprite.

commit 956349f87b1e1c5dd0f64cc575755bf89ebd149d
Author: David Capello <davidcapello at gmail.com>
Date:   Wed Apr 6 19:05:06 2016 -0300

    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.
---
 data/scripts/white_to_alpha.js                    |   2 +-
 src/app/CMakeLists.txt                            |   3 +
 src/app/cmd/copy_region.cpp                       |   8 +-
 src/app/cmd/copy_region.h                         |   8 +-
 src/app/script/app_object.cpp                     |  20 ++-
 src/app/script/app_scripting.cpp                  |  47 ++++++++
 src/app/script/app_scripting.h                    |  28 ++++-
 src/app/script/image_class.cpp                    | 101 ++++++++++++++++
 src/app/script/{app_scripting.h => image_class.h} |  11 +-
 src/app/script/image_wrap.cpp                     |  52 ++++++++
 src/app/script/image_wrap.h                       |  39 ++++++
 src/app/script/sprite_class.cpp                   | 141 +++++-----------------
 src/app/script/sprite_class.h                     |   4 -
 src/app/script/sprite_wrap.cpp                    |  96 +++++++++++++++
 src/app/script/sprite_wrap.h                      |  53 ++++++++
 src/script/engine.cpp                             |  35 +++++-
 src/script/engine.h                               |   9 ++
 17 files changed, 523 insertions(+), 134 deletions(-)

diff --git a/data/scripts/white_to_alpha.js b/data/scripts/white_to_alpha.js
index 81eace4..b8ab13d 100644
--- a/data/scripts/white_to_alpha.js
+++ b/data/scripts/white_to_alpha.js
@@ -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) {
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 7234cf9..6688700 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -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
diff --git a/src/app/cmd/copy_region.cpp b/src/app/cmd/copy_region.cpp
index e50f8bc..5a9d550 100644
--- a/src/app/cmd/copy_region.cpp
+++ b/src/app/cmd/copy_region.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()
diff --git a/src/app/cmd/copy_region.h b/src/app/cmd/copy_region.h
index 489abec..84ae13b 100644
--- a/src/app/cmd/copy_region.h
+++ b/src/app/cmd/copy_region.h
@@ -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;
   };
diff --git a/src/app/script/app_object.cpp b/src/app/script/app_object.cpp
index d0ce360..56c7f73 100644
--- a/src/app/script/app_object.cpp
+++ b/src/app/script/app_object.cpp
@@ -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 },
diff --git a/src/app/script/app_scripting.cpp b/src/app/script/app_scripting.cpp
index db8c48b..637fb19 100644
--- a/src/app/script/app_scripting.cpp
+++ b/src/app/script/app_scripting.cpp
@@ -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;
+}
+
 }
diff --git a/src/app/script/app_scripting.h b/src/app/script/app_scripting.h
index ac89a43..b443992 100644
--- a/src/app/script/app_scripting.h
+++ b/src/app/script/app_scripting.h
@@ -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
diff --git a/src/app/script/image_class.cpp b/src/app/script/image_class.cpp
new file mode 100644
index 0000000..8401d4e
--- /dev/null
+++ b/src/app/script/image_class.cpp
@@ -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
diff --git a/src/app/script/app_scripting.h b/src/app/script/image_class.h
similarity index 57%
copy from src/app/script/app_scripting.h
copy to src/app/script/image_class.h
index ac89a43..4630c7c 100644
--- a/src/app/script/app_scripting.h
+++ b/src/app/script/image_class.h
@@ -1,22 +1,19 @@
 // Aseprite
-// Copyright (C) 2001-2016  David Capello
+// 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_H_INCLUDED
-#define APP_SCRIPT_H_INCLUDED
+#ifndef APP_SCRIPT_IMAGE_CLASS_H_INCLUDED
+#define APP_SCRIPT_IMAGE_CLASS_H_INCLUDED
 #pragma once
 
 #include "script/engine.h"
 
 namespace app {
 
-  class AppScripting : public script::Engine {
-  public:
-    AppScripting(script::EngineDelegate* delegate);
-  };
+  void register_image_class(script::index_t idx, script::Context& ctx);
 
 } // namespace app
 
diff --git a/src/app/script/image_wrap.cpp b/src/app/script/image_wrap.cpp
new file mode 100644
index 0000000..9b6828a
--- /dev/null
+++ b/src/app/script/image_wrap.cpp
@@ -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
diff --git a/src/app/script/image_wrap.h b/src/app/script/image_wrap.h
new file mode 100644
index 0000000..50bc030
--- /dev/null
+++ b/src/app/script/image_wrap.h
@@ -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
diff --git a/src/app/script/sprite_class.cpp b/src/app/script/sprite_class.cpp
index 8395861..786aa13 100644
--- a/src/app/script/sprite_class.cpp
+++ b/src/app/script/sprite_class.cpp
@@ -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);
diff --git a/src/app/script/sprite_class.h b/src/app/script/sprite_class.h
index 98ab6e2..5c1ffe0 100644
--- a/src/app/script/sprite_class.h
+++ b/src/app/script/sprite_class.h
@@ -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);
 
diff --git a/src/app/script/sprite_wrap.cpp b/src/app/script/sprite_wrap.cpp
new file mode 100644
index 0000000..cfdbbef
--- /dev/null
+++ b/src/app/script/sprite_wrap.cpp
@@ -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
diff --git a/src/app/script/sprite_wrap.h b/src/app/script/sprite_wrap.h
new file mode 100644
index 0000000..5b4f05c
--- /dev/null
+++ b/src/app/script/sprite_wrap.h
@@ -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
diff --git a/src/script/engine.cpp b/src/script/engine.cpp
index bc54660..eea3c58 100644
--- a/src/script/engine.cpp
+++ b/src/script/engine.cpp
@@ -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)
diff --git a/src/script/engine.h b/src/script/engine.h
index ec9534a..fc6e2a5 100644
--- a/src/script/engine.h
+++ b/src/script/engine.h
@@ -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;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git



More information about the Pkg-games-commits mailing list