Make Automation4::Script mostly pure abstract and clean up the implementation of LuaScript

Originally committed to SVN as r5640.
This commit is contained in:
Thomas Goyne 2011-09-28 19:48:37 +00:00
parent c09259c93d
commit 492a0d3046
4 changed files with 181 additions and 369 deletions

View File

@ -36,6 +36,8 @@
#include "config.h" #include "config.h"
#include "auto4_base.h"
#ifndef AGI_PRE #ifndef AGI_PRE
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include <tchar.h> #include <tchar.h>
@ -60,7 +62,6 @@
#include "ass_file.h" #include "ass_file.h"
#include "ass_style.h" #include "ass_style.h"
#include "auto4_base.h"
#include "compat.h" #include "compat.h"
#include "dialog_progress.h" #include "dialog_progress.h"
#include "include/aegisub/context.h" #include "include/aegisub/context.h"
@ -497,20 +498,9 @@ namespace Automation4 {
impl->Run(bind(progress_sink_wrapper, task, std::tr1::placeholders::_1, this), prio); impl->Run(bind(progress_sink_wrapper, task, std::tr1::placeholders::_1, this), prio);
} }
// Script // Script
Script::Script(wxString const& filename)
: filename(filename)
/// @brief DOCME
/// @param _filename
///
Script::Script(const wxString &_filename)
: filename(_filename)
, name("")
, description("")
, author("")
, version("")
, loaded(false)
{ {
// copied from auto3 // copied from auto3
include_path.clear(); include_path.clear();
@ -526,90 +516,6 @@ namespace Automation4 {
} }
} }
/// @brief DOCME
///
Script::~Script()
{
for (std::vector<Feature*>::iterator f = features.begin(); f != features.end(); ++f) {
delete *f;
}
}
/// @brief DOCME
/// @return
///
wxString Script::GetPrettyFilename() const
{
wxFileName fn(filename);
return fn.GetFullName();
}
/// @brief DOCME
/// @return
///
const wxString& Script::GetFilename() const
{
return filename;
}
/// @brief DOCME
/// @return
///
const wxString& Script::GetName() const
{
return name;
}
/// @brief DOCME
/// @return
///
const wxString& Script::GetDescription() const
{
return description;
}
/// @brief DOCME
/// @return
///
const wxString& Script::GetAuthor() const
{
return author;
}
/// @brief DOCME
/// @return
///
const wxString& Script::GetVersion() const
{
return version;
}
/// @brief DOCME
/// @return
///
bool Script::GetLoadedState() const
{
return loaded;
}
/// @brief DOCME
/// @return
///
std::vector<Feature*>& Script::GetFeatures()
{
return features;
}
// ScriptManager // ScriptManager
@ -923,18 +829,8 @@ namespace Automation4 {
// UnknownScript // UnknownScript
UnknownScript::UnknownScript(wxString const& filename)
/// @brief DOCME
/// @param filename
///
UnknownScript::UnknownScript(const wxString &filename)
: Script(filename) : Script(filename)
{ {
wxFileName fn(filename);
name = fn.GetName();
description = _("File was not recognized as a script");
loaded = false;
} }
}; };

View File

@ -42,6 +42,7 @@
#include <vector> #include <vector>
#include <wx/dialog.h> #include <wx/dialog.h>
#include <wx/filename.h>
#include <wx/gauge.h> #include <wx/gauge.h>
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/stattext.h> #include <wx/stattext.h>
@ -312,64 +313,40 @@ namespace Automation4 {
ProgressSink(agi::ProgressSink *impl, BackgroundScriptRunner *bsr); ProgressSink(agi::ProgressSink *impl, BackgroundScriptRunner *bsr);
}; };
/// DOCME
/// @class Script
/// @brief DOCME
///
/// DOCME
class Script { class Script {
private:
/// DOCME
wxString filename; wxString filename;
protected: protected:
/// The automation include path, consisting of the user-specified paths
/// DOCME /// along with the script's path
wxString name;
/// DOCME
wxString description;
/// DOCME
wxString author;
/// DOCME
wxString version;
/// DOCME
bool loaded; // is the script properly loaded?
/// DOCME
wxPathList include_path; wxPathList include_path;
Script(wxString const& filename);
/// DOCME
std::vector<Feature*> features;
Script(const wxString &_filename);
public: public:
virtual ~Script(); virtual ~Script() { }
/// Reload this script
virtual void Reload() = 0; virtual void Reload() = 0;
const wxString& GetFilename() const; /// The script's file name with path
wxString GetPrettyFilename() const; wxString GetFilename() const { return filename; }
const wxString& GetName() const; /// The script's file name without path
const wxString& GetDescription() const; wxString GetPrettyFilename() const { return wxFileName(filename).GetFullName(); }
const wxString& GetAuthor() const; /// The script's name. Not required to be unique.
const wxString& GetVersion() const; virtual wxString GetName() const=0;
bool GetLoadedState() const; /// A short description of the script
virtual wxString GetDescription() const=0;
/// The author of the script
virtual wxString GetAuthor() const=0;
/// A version string that should not be used for anything but display
virtual wxString GetVersion() const=0;
/// Did the script load correctly?
virtual bool GetLoadedState() const=0;
std::vector<Feature*>& GetFeatures(); /// Get a list of features provided by this script
virtual std::vector<Feature*> GetFeatures() const=0;
}; };
/// DOCME /// DOCME
/// @class ScriptManager /// @class ScriptManager
/// @brief DOCME /// @brief DOCME
@ -477,11 +454,16 @@ namespace Automation4 {
/// automation engines /// automation engines
class UnknownScript : public Script { class UnknownScript : public Script {
public: public:
UnknownScript(const wxString &filename); UnknownScript(wxString const& filename);
/// @brief DOCME void Reload() { }
///
void Reload() { };
};
wxString GetName() const { return wxFileName(GetFilename()).GetName(); }
wxString GetDescription() const { return _("File was not recognized as a script"); }
wxString GetAuthor() const { return ""; }
wxString GetVersion() const { return ""; }
bool GetLoadedState() const { return false; }
std::vector<Feature*> GetFeatures() const { return std::vector<Feature*>(); }
};
}; };

View File

@ -38,8 +38,10 @@
#ifdef WITH_AUTO4_LUA #ifdef WITH_AUTO4_LUA
#include "auto4_lua.h"
#ifndef AGI_PRE #ifndef AGI_PRE
#include <assert.h> #include <cassert>
#include <algorithm> #include <algorithm>
@ -52,17 +54,18 @@
#endif #endif
#include <libaegisub/log.h> #include <libaegisub/log.h>
#include <libaegisub/scoped_ptr.h>
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "ass_override.h" #include "ass_override.h"
#include "ass_style.h" #include "ass_style.h"
#include "auto4_lua.h"
#include "auto4_lua_factory.h" #include "auto4_lua_factory.h"
#include "auto4_lua_scriptreader.h" #include "auto4_lua_scriptreader.h"
#include "main.h" #include "main.h"
#include "standard_paths.h" #include "standard_paths.h"
#include "text_file_reader.h" #include "text_file_reader.h"
#include "utils.h"
#include "video_context.h" #include "video_context.h"
// This must be below the headers above. // This must be below the headers above.
@ -74,13 +77,38 @@
#include <lauxlib.h> #include <lauxlib.h>
#endif #endif
namespace {
void push_value(lua_State *L, lua_CFunction fn) {
lua_pushcfunction(L, fn);
}
void push_value(lua_State *L, int n) {
lua_pushinteger(L, n);
}
void push_value(lua_State *L, double n) {
lua_pushnumber(L, n);
}
template<class T>
void set_field(lua_State *L, const char *name, T value) {
push_value(L, value);
lua_setfield(L, -2, name);
}
wxString get_global_string(lua_State *L, const char *name) {
lua_getglobal(L, name);
wxString ret;
if (lua_isstring(L, -1))
ret = wxString(lua_tostring(L, -1), wxConvUTF8);
lua_pop(L, 1);
return ret;
}
}
/// DOCME
namespace Automation4 { namespace Automation4 {
// LuaStackcheck // LuaStackcheck
//#ifdef _DEBUG
#if 0 #if 0
struct LuaStackcheck { struct LuaStackcheck {
lua_State *L; lua_State *L;
@ -140,35 +168,22 @@ namespace Automation4 {
// LuaScript // LuaScript
LuaScript::LuaScript(wxString const& filename)
/// @brief DOCME
/// @param filename
///
LuaScript::LuaScript(const wxString &filename)
: Script(filename) : Script(filename)
, L(0) , L(0)
{ {
Create(); Create();
} }
/// @brief DOCME
///
LuaScript::~LuaScript() LuaScript::~LuaScript()
{ {
if (L) Destroy(); Destroy();
} }
/// @brief DOCME
///
void LuaScript::Create() void LuaScript::Create()
{ {
Destroy(); Destroy();
loaded = true;
try { try {
// create lua environment // create lua environment
L = lua_open(); L = lua_open();
@ -209,7 +224,7 @@ namespace Automation4 {
lua_settable(L, -3); lua_settable(L, -3);
// Replace the default lua module loader with our utf-8 compatible one // Replace the default lua module loader with our unicode compatible one
lua_getfield(L, -1, "loaders"); lua_getfield(L, -1, "loaders");
lua_pushcfunction(L, LuaModuleLoader); lua_pushcfunction(L, LuaModuleLoader);
lua_rawseti(L, -2, 2); lua_rawseti(L, -2, 2);
@ -229,37 +244,28 @@ namespace Automation4 {
// make "aegisub" table // make "aegisub" table
lua_pushstring(L, "aegisub"); lua_pushstring(L, "aegisub");
lua_newtable(L); lua_newtable(L);
// aegisub.register_macro
lua_pushcfunction(L, LuaFeatureMacro::LuaRegister); set_field(L, "register_macro", LuaFeatureMacro::LuaRegister);
lua_setfield(L, -2, "register_macro"); set_field(L, "register_filter", LuaFeatureFilter::LuaRegister);
// aegisub.register_filter set_field(L, "text_extents", LuaTextExtents);
lua_pushcfunction(L, LuaFeatureFilter::LuaRegister); set_field(L, "frame_from_ms", LuaFrameFromMs);
lua_setfield(L, -2, "register_filter"); set_field(L, "ms_from_frame", LuaMsFromFrame);
// aegisub.text_extents set_field(L, "video_size", LuaVideoSize);
lua_pushcfunction(L, LuaTextExtents); set_field(L, "lua_automation_version", 4);
lua_setfield(L, -2, "text_extents");
// VFR handling
lua_pushcfunction(L, LuaFrameFromMs);
lua_setfield(L, -2, "frame_from_ms");
lua_pushcfunction(L, LuaMsFromFrame);
lua_setfield(L, -2, "ms_from_frame");
lua_pushcfunction(L, LuaVideoSize);
lua_setfield(L, -2, "video_size");
// aegisub.lua_automation_version
lua_pushinteger(L, 4);
lua_setfield(L, -2, "lua_automation_version");
// store aegisub table to globals // store aegisub table to globals
lua_settable(L, LUA_GLOBALSINDEX); lua_settable(L, LUA_GLOBALSINDEX);
_stackcheck.check_stack(0); _stackcheck.check_stack(0);
// load user script // load user script
LuaScriptReader script_reader(GetFilename()); LuaScriptReader script_reader(GetFilename());
if (lua_load(L, script_reader.reader_func, &script_reader, GetPrettyFilename().mb_str(wxConvUTF8))) { if (lua_load(L, script_reader.reader_func, &script_reader, GetPrettyFilename().utf8_str())) {
wxString err(lua_tostring(L, -1), wxConvUTF8); wxString err(lua_tostring(L, -1), wxConvUTF8);
err.Prepend("Error loading Lua script \"" + GetPrettyFilename() + "\":\n\n"); err.Prepend("Error loading Lua script \"" + GetPrettyFilename() + "\":\n\n");
throw ScriptLoadError(STD_STR(err)); throw ScriptLoadError(STD_STR(err));
} }
_stackcheck.check_stack(1); _stackcheck.check_stack(1);
// and execute it // and execute it
// this is where features are registered // this is where features are registered
// don't thread this, as there's no point in it and it seems to break on wx 2.8.3, for some reason // don't thread this, as there's no point in it and it seems to break on wx 2.8.3, for some reason
@ -270,80 +276,49 @@ namespace Automation4 {
throw ScriptLoadError(STD_STR(err)); throw ScriptLoadError(STD_STR(err));
} }
_stackcheck.check_stack(0); _stackcheck.check_stack(0);
lua_getglobal(L, "version"); lua_getglobal(L, "version");
if (lua_isnumber(L, -1)) { if (lua_isnumber(L, -1) && lua_tointeger(L, -1) == 3) {
if (lua_tointeger(L, -1) == 3) {
lua_pop(L, 1); // just to avoid tripping the stackcheck in debug lua_pop(L, 1); // just to avoid tripping the stackcheck in debug
throw ScriptLoadError("Attempted to load an Automation 3 script as an Automation 4 Lua script. Automation 3 is no longer supported."); throw ScriptLoadError("Attempted to load an Automation 3 script as an Automation 4 Lua script. Automation 3 is no longer supported.");
} }
}
lua_getglobal(L, "script_name"); name = get_global_string(L, "script_name");
if (lua_isstring(L, -1)) { description = get_global_string(L, "script_description");
name = wxString(lua_tostring(L, -1), wxConvUTF8); author = get_global_string(L, "script_author");
} else { version = get_global_string(L, "script_version");
if (name.empty())
name = GetPrettyFilename(); name = GetPrettyFilename();
}
lua_getglobal(L, "script_description"); lua_pop(L, 1);
if (lua_isstring(L, -1)) {
description = wxString(lua_tostring(L, -1), wxConvUTF8);
}
lua_getglobal(L, "script_author");
if (lua_isstring(L, -1)) {
author = wxString(lua_tostring(L, -1), wxConvUTF8);
}
lua_getglobal(L, "script_version");
if (lua_isstring(L, -1)) {
version = wxString(lua_tostring(L, -1), wxConvUTF8);
}
lua_pop(L, 5);
// if we got this far, the script should be ready // if we got this far, the script should be ready
_stackcheck.check_stack(0); _stackcheck.check_stack(0);
} }
catch (agi::Exception const& e) { catch (agi::Exception const& e) {
Destroy(); Destroy();
loaded = false;
name = GetPrettyFilename(); name = GetPrettyFilename();
description = e.GetChainedMessage(); description = e.GetChainedMessage();
} }
} }
/// @brief DOCME
/// @return
///
void LuaScript::Destroy() void LuaScript::Destroy()
{ {
// Assume the script object is clean if there's no Lua state // Assume the script object is clean if there's no Lua state
if (!L) return; if (!L) return;
// remove features delete_clear(features);
for (int i = 0; i < (int)features.size(); i++) {
Feature *f = features[i];
delete f;
}
features.clear();
// delete environment
lua_close(L); lua_close(L);
L = 0; L = 0;
loaded = false;
} }
/// @brief DOCME
///
void LuaScript::Reload() void LuaScript::Reload()
{ {
Destroy();
Create(); Create();
} }
/// @brief DOCME
/// @param L
/// @return
///
LuaScript* LuaScript::GetScriptObject(lua_State *L) LuaScript* LuaScript::GetScriptObject(lua_State *L)
{ {
lua_getfield(L, LUA_REGISTRYINDEX, "aegisub"); lua_getfield(L, LUA_REGISTRYINDEX, "aegisub");
@ -352,41 +327,31 @@ namespace Automation4 {
return (LuaScript*)ptr; return (LuaScript*)ptr;
} }
int LuaScript::RegisterFeature(Feature *feature) {
features.push_back(feature);
return features.size() - 1;
}
/// @brief DOCME
/// @param L
/// @return
///
int LuaScript::LuaTextExtents(lua_State *L) int LuaScript::LuaTextExtents(lua_State *L)
{ {
if (!lua_istable(L, 1)) { if (!lua_istable(L, 1))
lua_pushstring(L, "First argument to text_extents must be a table"); return luaL_error(L, "First argument to text_extents must be a table");
lua_error(L);
} if (!lua_isstring(L, 2))
if (!lua_isstring(L, 2)) { return luaL_error(L, "Second argument to text_extents must be a string");
lua_pushstring(L, "Second argument to text_extents must be a string");
lua_error(L);
}
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
AssEntry *et = LuaAssFile::LuaToAssEntry(L); agi::scoped_ptr<AssEntry> et(LuaAssFile::LuaToAssEntry(L));
AssStyle *st = dynamic_cast<AssStyle*>(et); AssStyle *st = dynamic_cast<AssStyle*>(et.get());
lua_pop(L, 1); lua_pop(L, 1);
if (!st) { if (!st)
delete et; // Make sure to delete the "live" pointer return luaL_error(L, "Not a style entry");
lua_pushstring(L, "Not a style entry");
lua_error(L);
}
wxString text(lua_tostring(L, 2), wxConvUTF8); wxString text(lua_tostring(L, 2), wxConvUTF8);
double width, height, descent, extlead; double width, height, descent, extlead;
if (!CalculateTextExtents(st, text, width, height, descent, extlead)) { if (!CalculateTextExtents(st, text, width, height, descent, extlead))
delete st; return luaL_error(L, "Some internal error occurred calculating text_extents");
lua_pushstring(L, "Some internal error occurred calculating text_extents");
lua_error(L);
}
delete st;
lua_pushnumber(L, width); lua_pushnumber(L, width);
lua_pushnumber(L, height); lua_pushnumber(L, height);
@ -417,28 +382,20 @@ namespace Automation4 {
if (wxFileName::FileExists(filename)) { if (wxFileName::FileExists(filename)) {
LuaScriptReader script_reader(filename); LuaScriptReader script_reader(filename);
if (lua_load(L, script_reader.reader_func, &script_reader, filename.utf8_str())) { if (lua_load(L, script_reader.reader_func, &script_reader, filename.utf8_str())) {
lua_pushfstring(L, "Error loading Lua module \"%s\":\n\n%s", filename.utf8_str().data(), lua_tostring(L, -1)); return luaL_error(L, "Error loading Lua module \"%s\":\n\n%s", filename.utf8_str().data(), lua_tostring(L, -1));
lua_error(L);
return lua_gettop(L) - pretop;
} }
} }
} }
return lua_gettop(L) - pretop; return lua_gettop(L) - pretop;
} }
/// @brief DOCME
/// @param L
/// @return
///
int LuaScript::LuaInclude(lua_State *L) int LuaScript::LuaInclude(lua_State *L)
{ {
LuaScript *s = GetScriptObject(L); LuaScript *s = GetScriptObject(L);
if (!lua_isstring(L, 1)) { if (!lua_isstring(L, 1))
lua_pushstring(L, "Argument to include must be a string"); return luaL_error(L, "Argument to include must be a string");
lua_error(L);
return 0;
}
wxString fnames(lua_tostring(L, 1), wxConvUTF8); wxString fnames(lua_tostring(L, 1), wxConvUTF8);
wxFileName fname(fnames); wxFileName fname(fnames);
@ -452,63 +409,42 @@ namespace Automation4 {
} else { } else {
// absolute path, do nothing // absolute path, do nothing
} }
if (!fname.IsOk() || !fname.FileExists()) { if (!fname.IsOk() || !fname.FileExists())
lua_pushfstring(L, "Lua include not found: %s", fnames.mb_str(wxConvUTF8).data()); return luaL_error(L, "Lua include not found: %s", fnames.utf8_str().data());
lua_error(L);
}
LuaScriptReader script_reader(fname.GetFullPath()); LuaScriptReader script_reader(fname.GetFullPath());
if (lua_load(L, script_reader.reader_func, &script_reader, fname.GetFullName().mb_str(wxConvUTF8))) { if (lua_load(L, script_reader.reader_func, &script_reader, fname.GetFullName().utf8_str()))
lua_pushfstring(L, "Error loading Lua include \"%s\":\n\n%s", fname.GetFullPath().mb_str(wxConvUTF8).data(), lua_tostring(L, -1)); return luaL_error(L, "Error loading Lua include \"%s\":\n\n%s", fname.GetFullPath().utf8_str().data(), lua_tostring(L, -1));
lua_error(L);
return 0;
}
int pretop = lua_gettop(L) - 1; // don't count the function value itself int pretop = lua_gettop(L) - 1; // don't count the function value itself
lua_call(L, 0, LUA_MULTRET); lua_call(L, 0, LUA_MULTRET);
return lua_gettop(L) - pretop; return lua_gettop(L) - pretop;
} }
/// @brief DOCME
/// @param L
/// @return
///
int LuaScript::LuaFrameFromMs(lua_State *L) int LuaScript::LuaFrameFromMs(lua_State *L)
{ {
int ms = (int)lua_tonumber(L, -1); int ms = lua_tointeger(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
if (VideoContext::Get()->TimecodesLoaded()) { if (VideoContext::Get()->TimecodesLoaded())
lua_pushnumber(L, VideoContext::Get()->FrameAtTime(ms, agi::vfr::START)); lua_pushnumber(L, VideoContext::Get()->FrameAtTime(ms, agi::vfr::START));
return 1; else
} else {
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
} }
}
/// @brief DOCME
/// @param L
/// @return
///
int LuaScript::LuaMsFromFrame(lua_State *L) int LuaScript::LuaMsFromFrame(lua_State *L)
{ {
int frame = (int)lua_tonumber(L, -1); int frame = lua_tointeger(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
if (VideoContext::Get()->TimecodesLoaded()) { if (VideoContext::Get()->TimecodesLoaded())
lua_pushnumber(L, VideoContext::Get()->TimeAtFrame(frame, agi::vfr::START)); lua_pushnumber(L, VideoContext::Get()->TimeAtFrame(frame, agi::vfr::START));
return 1; else
} else {
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
} }
}
/// @brief DOCME
/// @param L
/// @return
///
int LuaScript::LuaVideoSize(lua_State *L) int LuaScript::LuaVideoSize(lua_State *L)
{ {
VideoContext *ctx = VideoContext::Get(); VideoContext *ctx = VideoContext::Get();
@ -577,10 +513,7 @@ namespace Automation4 {
lua_pop(L, 1); lua_pop(L, 1);
// add the Feature object // add the Feature object
s->features.push_back(this); myid = s->RegisterFeature(this);
// get the index+1 it was pushed into
myid = (int)s->features.size()-1;
// create table with the functions // create table with the functions
// get features table // get features table

View File

@ -271,46 +271,8 @@ namespace Automation4 {
void ThrowError(); void ThrowError();
}; };
/// DOCME
/// @class LuaScript
/// @brief DOCME
///
/// DOCME
class LuaScript : public Script {
friend class LuaFeature;
private:
/// DOCME
lua_State *L;
void Create(); // load script and create internal structures etc.
void Destroy(); // destroy internal structures, unreg features and delete environment
static LuaScript* GetScriptObject(lua_State *L);
static int LuaTextExtents(lua_State *L);
static int LuaInclude(lua_State *L);
static int LuaModuleLoader(lua_State *L);
static int LuaFrameFromMs(lua_State *L);
static int LuaMsFromFrame(lua_State *L);
static int LuaVideoSize(lua_State *L);
public:
LuaScript(const wxString &filename);
virtual ~LuaScript();
virtual void Reload();
};
void LuaThreadedCall(lua_State *L, int nargs, int nresults, wxString const& title, wxWindow *parent, bool can_open_config); void LuaThreadedCall(lua_State *L, int nargs, int nresults, wxString const& title, wxWindow *parent, bool can_open_config);
/// DOCME /// DOCME
/// @class LuaFeatureMacro /// @class LuaFeatureMacro
/// @brief DOCME /// @brief DOCME
@ -334,8 +296,6 @@ namespace Automation4 {
virtual void Process(AssFile *subs, std::vector<int> &selected, int active, wxWindow * const progress_parent); virtual void Process(AssFile *subs, std::vector<int> &selected, int active, wxWindow * const progress_parent);
}; };
/// DOCME /// DOCME
/// @class LuaFeatureFilter /// @class LuaFeatureFilter
/// @brief DOCME /// @brief DOCME
@ -367,4 +327,45 @@ namespace Automation4 {
void ProcessSubs(AssFile *subs, wxWindow *export_dialog); void ProcessSubs(AssFile *subs, wxWindow *export_dialog);
}; };
class LuaScript : public Script {
lua_State *L;
wxString name;
wxString description;
wxString author;
wxString version;
std::vector<Feature*> features;
/// load script and create internal structures etc.
void Create();
/// destroy internal structures, unreg features and delete environment
void Destroy();
static int LuaTextExtents(lua_State *L);
static int LuaInclude(lua_State *L);
static int LuaModuleLoader(lua_State *L);
static int LuaFrameFromMs(lua_State *L);
static int LuaMsFromFrame(lua_State *L);
static int LuaVideoSize(lua_State *L);
public:
LuaScript(const wxString &filename);
~LuaScript();
static LuaScript* GetScriptObject(lua_State *L);
int RegisterFeature(Feature *feature);
// Script implementation
void Reload();
wxString GetName() const { return name; }
wxString GetDescription() const { return description; }
wxString GetAuthor() const { return author; }
wxString GetVersion() const { return version; }
bool GetLoadedState() const { return L != 0; }
std::vector<Feature*> GetFeatures() const { return features; }
};
}; };