From 4b569de80d0cb2b5a567bb6e84ef751444209705 Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Fri, 13 Apr 2007 15:30:57 +0000 Subject: [PATCH] Fixed bug with grid scrollbar not updating. Removed some old, unused auto3 files. Originally committed to SVN as r1073. --- aegisub/auto3/automation.cpp | 1665 --------------------------- aegisub/auto3/automation.h | 159 --- aegisub/auto3/automation_filter.cpp | 293 ----- aegisub/auto3/automation_filter.h | 85 -- aegisub/auto3/automation_gui.cpp | 394 ------- aegisub/auto3/automation_gui.h | 87 -- aegisub/subs_grid.cpp | 1 + 7 files changed, 1 insertion(+), 2683 deletions(-) delete mode 100644 aegisub/auto3/automation.cpp delete mode 100644 aegisub/auto3/automation.h delete mode 100644 aegisub/auto3/automation_filter.cpp delete mode 100644 aegisub/auto3/automation_filter.h delete mode 100644 aegisub/auto3/automation_gui.cpp delete mode 100644 aegisub/auto3/automation_gui.h diff --git a/aegisub/auto3/automation.cpp b/aegisub/auto3/automation.cpp deleted file mode 100644 index 8d25c3d21..000000000 --- a/aegisub/auto3/automation.cpp +++ /dev/null @@ -1,1665 +0,0 @@ -// Copyright (c) 2005, Niels Martin Hansen -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------------- -// -// AEGISUB -// -// Website: http://aegisub.cellosoft.com -// Contact: mailto:zeratul@cellosoft.com -// - - -#include -#include -#include -#include -#include -#include "automation.h" -#include "ass_file.h" -#include "ass_entry.h" -#include "ass_dialogue.h" -#include "ass_style.h" -#include "options.h" -#include "string_codec.h" -#include "vfr.h" - -#ifdef __WINDOWS__ -#include -#include -#else -#include -#include FT_FREETYPE_H -#endif - -extern "C" { -#ifdef HAVE_LUA50_LUA_H -#include -#include -#else -#include -#include -#endif -} - -int L_callfunc(lua_State *L, int nargs, int nresults); - -void L_settable(lua_State *L, int table, wxString &key, lua_Number val); -void L_settable(lua_State *L, int table, wxString &key, wxString val); -void L_settable_bool(lua_State *L, int table, wxString &key, bool val); -void L_settable(lua_State *L, int table, const char *key, lua_Number val); -void L_settable(lua_State *L, int table, const char *key, wxString val); -void L_settable_bool(lua_State *L, int table, const char *key, bool val); -void L_settable_kara(lua_State *L, int table, int index, int duration, wxString &kind, wxString &text, wxString &text_stripped); - -// these two assume the table to get from is on the top of the stack -lua_Number L_gettableN(lua_State *L, const char *key); -wxString L_gettableS(lua_State *L, const char *key); -bool L_gettableB(lua_State *L, const char *key); - - -namespace AutomationHelper { - - // helper functions for the scripts - // expect a pointer to the automation script object to be on the private stack - - - /* - Helper function helper... - Get the AutomationScript object associated with a Lua state. - */ - AutomationScript *GetScriptObject(lua_State *L) - { - lua_pushstring(L, "aegisub"); - lua_rawget(L, LUA_REGISTRYINDEX); - AutomationScript *s = (AutomationScript*)(lua_touserdata(L, -1)); - if (!s) { - lua_pushstring(L, "Unable to retrieve AutomationScript object from the registry. This should never happen!"); - lua_error(L); // never returns - } - lua_pop(L, 1); - return s; - } - - - /* - "Debug hook" function, used for checking if the interpreter has been asked to cancel. - If it has, a Lua error is reported. - */ - void hookfunc(lua_State *L, lua_Debug *ar) - { - AutomationScript *script = GetScriptObject(L); - if (script->force_cancel) { - if (ar->currentline < 0) { - lua_pushstring(L, "Script forcibly terminated at an unknown line"); - } else { - lua_pushstring(L, "Script forcibly terminated at line "); - lua_pushnumber(L, ar->currentline); - lua_concat(L, 2); - } - lua_error(L); - } - } - - - /* - function aegisub.output_debug(text) - - Output text to a debug console. - - @text - String. The text to output. - - Returns: nothing. - */ - int output_debug(lua_State *L) - { - AutomationScript *script = GetScriptObject(L); - - // check we were passed a string - if (lua_gettop(L) < 1) { - // idiot user (nothing on the stack) - lua_pushstring(L, "output_debug called with no arguments"); - lua_error(L); // never returns - - } else if (!lua_isstring(L, -1)) { - // idiot user (didn't pass a string) - lua_pushstring(L, "output_debug called with non string-compatible argument"); - lua_error(L); // never returns - } - - script->OutputDebugString(wxString(lua_tostring(L, 1), wxConvUTF8), true); - - return 0; - } - - - /* - function aegisub.set_status(text) - - Sets the current status-message. (Used for progress-reporting.) - - @text - String. The status message. - - Returns: nothing. - */ - int set_status(lua_State *L) - { - AutomationScript *script = GetScriptObject(L); - - // check we were passed a string - if (lua_gettop(L) < 1) { - // idiot user (nothing on the stack) - lua_pushstring(L, "output_debug called with no arguments"); - lua_error(L); // never returns - - } else if (!lua_isstring(L, -1)) { - // idiot user (didn't pass a string) - lua_pushstring(L, "output_debug called with non string-compatible argument"); - lua_error(L); // never returns - } - - script->OutputDebugString(wxString(lua_tostring(L, 1), wxConvUTF8), false); - - return 0; - } - - - /* - function aegisub.colorstring_to_rgb(colorstring) - - Convert an ASS color-string to a set of RGB values. - - @colorstring - String. The color-string to convert. - - Returns: Four values, all numbers, being the color components in this - order: Red, Green, Blue, Alpha-channel - */ - int colorstring_to_rgb(lua_State *L) - { - if (lua_gettop(L) < 1) { - lua_pushstring(L, "colorstring_to_rgb called without arguments"); - lua_error(L); - } - if (!lua_isstring(L, 1)) { - lua_pushstring(L, "colorstring_to_rgb requires a string type argument"); - lua_error(L); - } - - wxString colorstring(lua_tostring(L, -1), wxConvUTF8); - lua_pop(L, 1); - AssColor rgb; - rgb.ParseASS(colorstring); - lua_pushnumber(L, rgb.r); - lua_pushnumber(L, rgb.g); - lua_pushnumber(L, rgb.b); - lua_pushnumber(L, rgb.a); - return 4; - } - - - /* - function aegisub.report_progress(percent) - - Report the progress of the processing. - - @percent - Number. How much of the data have been processed so far. - - Returns: nothing. - */ - int report_progress(lua_State *L) - { - AutomationScript *script = GetScriptObject(L); - - // check we were passed a string - if (lua_gettop(L) < 1) { - // idiot user (nothing on the stack) - lua_pushstring(L, "report_progress called with no arguments"); - lua_error(L); // never returns - - } else if (!lua_isnumber(L, -1)) { - // idiot user (didn't pass a string) - lua_pushstring(L, "report_progress requires a numeric argument"); - lua_error(L); // never returns - } - - lua_Number p = lua_tonumber(L, -1); - - if (p < 0) p = 0; - if (p > 100) p = 100; - p = (p+100)/3; - script->ReportProgress(p); - - return 0; - } - - - /* - function aegisub.text_extents(style, text) - - Calculate the on-screen pixel size of the given text using the given style. - - @style - Table. A single style definition like those passed to process_lines. - @text - String. The text to calculate the extents for. This should not contain - formatting codes, as they will be treated as part of the text. - - Returns 4 values: - 1: Number. Width of the text, in pixels. - 2: Number. Height of the text, in pixels. - 3: Number. Descent of the text, in pixels. - 4: Number. External leading for the text, in pixels. - */ - int text_extents(lua_State *L) - { - // vars for the result - int resx = 0, resy = 0, resd = 0, resl = 0; - // get the input - // no error checking for the moment - wxString intext(lua_tostring(L, -1), wxConvUTF8); - // leave only style table - lua_settop(L, -2); - - // read out the relevant parts of style - wxString fontname(L_gettableS(L, "fontname")); - double fontsize = L_gettableN(L, "fontsize"); - bool bold = L_gettableB(L, "bold"); - bool italic = L_gettableB(L, "italic"); - bool underline = L_gettableB(L, "underline"); - bool strikeout = L_gettableB(L, "strikeout"); - double scale_x = L_gettableN(L, "scale_x"); - double scale_y = L_gettableN(L, "scale_y"); - int spacing = (int)L_gettableN(L, "spacing"); - int charset = (int)L_gettableN(L, "encoding"); - - wxLogDebug(_T("text_extents for: %s:%f:%d%d%d%d:%f:%f:%d:%d"), fontname.c_str(), fontsize, bold, italic, underline, strikeout, scale_x, scale_y, spacing, charset); - -#ifdef WIN32 - HDC thedc = CreateCompatibleDC(0); - if (!thedc) return 0; - SetMapMode(thedc, MM_TEXT); - - HDC dczero = GetDC(0); - fontsize = -MulDiv((int)(fontsize+0.5), GetDeviceCaps(dczero, LOGPIXELSY), 72); - ReleaseDC(0, dczero); - - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - lf.lfHeight = fontsize; - lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; - lf.lfItalic = italic; - lf.lfUnderline = underline; - lf.lfStrikeOut = strikeout; - lf.lfCharSet = charset; - lf.lfOutPrecision = OUT_TT_PRECIS; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfQuality = ANTIALIASED_QUALITY; - lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; - wcsncpy(lf.lfFaceName, fontname.wc_str(), 32); - - HFONT thefont = CreateFontIndirect(&lf); - if (!thefont) return 0; - SelectObject(thedc, thefont); - - SIZE sz; - size_t thetextlen = intext.length(); - const wchar_t *thetext = intext.wc_str(); - if (spacing) { - resx = 0; - for (unsigned int i = 0; i < thetextlen; i++) { - GetTextExtentPoint32(thedc, &thetext[i], 1, &sz); - resx += sz.cx + spacing; - resy = sz.cy; - } - } else { - GetTextExtentPoint32(thedc, thetext, thetextlen, &sz); - resx = sz.cx; - resy = sz.cy; - } - - // HACKISH FIX! This seems to work, but why? It shouldn't be needed?!? - fontsize = L_gettableN(L, "fontsize"); - resx = (int)(resx * fontsize/resy + 0.5); - resy = (int)(fontsize + 0.5); - - TEXTMETRIC tm; - GetTextMetrics(thedc, &tm); - resd = tm.tmDescent; - resl = tm.tmExternalLeading; - - DeleteObject(thedc); - DeleteObject(thefont); - -#else // not WIN32 - wxMemoryDC thedc; - - // fix fontsize to be 72 DPI - fontsize = -FT_MulDiv((int)(fontsize+0.5), 72, thedc.GetPPI().y); - - // now try to get a font! - // use the font list to get some caching... (chance is the script will need the same font very often) - // USING wxTheFontList SEEMS TO CAUSE BAD LEAKS! - //wxFont *thefont = wxTheFontList->FindOrCreateFont( - wxFont thefont( - fontsize, - wxFONTFAMILY_DEFAULT, - italic ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL, - bold ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL, - underline, - fontname, - wxFONTENCODING_SYSTEM); - thedc.SetFont(thefont); - - if (spacing) { - // If there's inter-character spacing, kerning info must not be used, so calculate width per character - for (unsigned int i = 0; i < intext.length(); i++) { - int a, b, c, d; - thedc.GetTextExtent(intext[i], &a, &b, &c, &d); - resx += a + spacing; - resy = b > resy ? b : resy; - resd = c > resd ? c : resd; - resl = d > resl ? d : resl; - } - } else { - // If the inter-character spacing should be zero, kerning info can (and must) be used, so calculate everything in one go - thedc.GetTextExtent(intext, &resx, &resy, &resd, &resl); - } -#endif // WIN32 - - // Compensate for scaling - resx = (int)(scale_x / 100 * resx + 0.5); - resy = (int)(scale_y / 100 * resy + 0.5); - resd = (int)(scale_y / 100 * resd + 0.5); - resl = (int)(scale_y / 100 * resl + 0.5); - - lua_pushnumber(L, resx); - lua_pushnumber(L, resy); - lua_pushnumber(L, resd); - lua_pushnumber(L, resl); - return 4; - } - - - /* - function aegisub.frame_from_ms(ms) - - Return the video frame-number for the given time. - - @ms - Number. Time in miliseconds to get the frame number for. - - Returns: A number, the frame numer. If there is no framerate data, returns - nil. - */ - int frame_from_ms(lua_State *L) - { - int ms = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - if (VFR_Output.IsLoaded()) { - lua_pushnumber(L, VFR_Output.GetFrameAtTime(ms, true)); - return 1; - } else { - lua_pushnil(L); - return 1; - } - } - - - /* - function aegisub.ms_from_frame(frame) - - Returns the start-time for the given video frame-number. - - @frame - Number. Frame-number to get start-time from. - - Returns: A number, the start-time of the frame. If there is no framerate - data, returns nil. - */ - int ms_from_frame(lua_State *L) - { - int frame = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - if (VFR_Output.IsLoaded()) { - lua_pushnumber(L, VFR_Output.GetTimeAtFrame(frame, true)); - return 1; - } else { - lua_pushnil(L); - return 1; - } - } - - - /* - function include(filename) - - @filename - String. Name of the file to include. - - Returns: Depends on the script included. - */ - int include(lua_State *L) - { - AutomationScript *script = GetScriptObject(L); - - if (!lua_isstring(L, 1)) { - lua_pushstring(L, "First argument to the include function must be a string."); - lua_error(L); - } - wxString fnames(lua_tostring(L, 1), wxConvUTF8); - - wxFileName fname(fnames); - if (fname.GetDirCount() == 0) { - // filename only - fname = script->include_path.FindAbsoluteValidPath(fnames); - } else if (fname.IsRelative()) { - // relative path - wxFileName sfname(script->filename); - fname.MakeAbsolute(sfname.GetPath(true)); - } else { - // absolute path, invalid - lua_pushstring(L, "Filename passed to include seems to have an absolute path, which is not allowed."); - lua_error(L); - } - if (!fname.IsOk() || !fname.FileExists()) { - { - // need to make a new scope here, so the char buffer can go out of scope before lua_error() makes a longjmp - wxCharBuffer errmsg = wxString::Format(_T("The file could not be included, not found. \"%s\""), fnames.c_str()).mb_str(wxConvUTF8); - lua_pushstring(L, errmsg.data()); - } - lua_error(L); - } - - AutomationScriptFile *sfile; - sfile = AutomationScriptFile::CreateFromFile(fname.GetFullPath()); - wxCharBuffer fnamebuf = fname.GetFullName().mb_str(wxConvUTF8); - switch (luaL_loadbuffer(L, sfile->scriptdata, sfile->scriptlen, fnamebuf.data())) { - // FIXME: these should be made into lua_error() things instead... probably - case 0: - // success! - break; - case LUA_ERRSYNTAX: - throw AutomationError(wxString::Format(_T("Lua syntax error: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - break; - case LUA_ERRMEM: - throw AutomationError(wxString::Format(_T("Lua memory allocation error: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - break; - default: - throw AutomationError(wxString::Format(_T("Lua unknown error: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - break; - } - delete sfile; - - // top of stack before the call (correct for the function itself being on stack) - int pretop = lua_gettop(L)-1; - // call the loaded script - lua_call(L, 0, LUA_MULTRET); - // calculate the number of results the script produced - return lua_gettop(L)-pretop; - } - -} - - -/* - Call a Lua function without risking killing the entire program - Just throw a C++ exception instead :) - - Really just a thin wrapper around lua_pcall -*/ -inline int L_callfunc(lua_State *L, int nargs, int nresults) -{ - int res = lua_pcall(L, nargs, nresults, 0); - switch (res) { - case LUA_ERRRUN: - throw AutomationError(wxString::Format(_T("Lua runtime error: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - case LUA_ERRMEM: - throw AutomationError(wxString::Format(_T("Lua memory allocation error: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - case LUA_ERRERR: - // shouldn't happen as an error handling function isn't being used - throw AutomationError(wxString::Format(_T("Lua error calling error handler: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - default: - // success! - return res; - } -} - - -inline void L_settable(lua_State *L, int table, wxString &key, lua_Number val) -{ - L_settable(L, table, key.mb_str(wxConvUTF8), val); -} - -inline void L_settable(lua_State *L, int table, wxString &key, wxString val) -{ - //wxLogMessage(_T("Wrapping adding of string at index '%s': %s"), key, val); - L_settable(L, table, key.mb_str(wxConvUTF8), val); -} - -inline void L_settable_bool(lua_State *L, int table, wxString &key, bool val) -{ - L_settable_bool(L, table, key.mb_str(wxConvUTF8), val); -} - -inline void L_settable(lua_State *L, int table, const char *key, lua_Number val) -{ - lua_pushstring(L, key); - lua_pushnumber(L, val); - if (table > 0 || table < -100) { - lua_settable(L, table); - } else { - lua_settable(L, table-2); - } -} - -inline void L_settable(lua_State *L, int table, const char *key, wxString val) -{ - //wxLogMessage(_T("Adding string at index '%s': %s"), wxString(key, wxConvUTF8), val); - lua_pushstring(L, key); - lua_pushstring(L, val.mb_str(wxConvUTF8)); - if (table > 0 || table < -100) { - lua_settable(L, table); - } else { - lua_settable(L, table-2); - } -} - -inline void L_settable_bool(lua_State *L, int table, const char *key, bool val) -{ - lua_pushstring(L, key); - lua_pushboolean(L, val?1:0); - if (table > 0 || table < -100) { - lua_settable(L, table); - } else { - lua_settable(L, table-2); - } -} - -inline void L_settable_kara(lua_State *L, int table, int index, int duration, wxString &kind, wxString &text, wxString &text_stripped) -{ - lua_newtable(L); - L_settable(L, -1, "duration", duration); - L_settable(L, -1, "kind", kind); - L_settable(L, -1, "text", text); - L_settable(L, -1, "text_stripped", text_stripped); - if (table > 0 || table < -100) { - lua_rawseti(L, table, index); - } else { - lua_rawseti(L, table-1, index); - } -} - - -lua_Number L_gettableN(lua_State *L, const char *key) -{ - lua_pushstring(L, key); - lua_gettable(L, -2); - lua_Number res = lua_tonumber(L, -1); - lua_settop(L, -2); - return res; -} - - -wxString L_gettableS(lua_State *L, const char *key) -{ - lua_pushstring(L, key); - lua_gettable(L, -2); - wxString res(lua_tostring(L, -1), wxConvUTF8); - lua_settop(L, -2); - return res; -} - - -bool L_gettableB(lua_State *L, const char *key) -{ - lua_pushstring(L, key); - lua_gettable(L, -2); - bool res = lua_toboolean(L, -1) != 0; - lua_settop(L, -2); - return res; -} - - - -AutomationError::AutomationError(wxString msg) -: message(msg) -{ - // nothing to do here... -} - - - -wxString AutomationScriptConfiguration::serialize() -{ - wxString result; - for (std::vector::iterator opt = options.begin(); opt != options.end(); opt++) { - switch (opt->kind) { - case COK_TEXT: - case COK_STYLE: - result << wxString::Format(_T("%s:%s|"), opt->name.c_str(), inline_string_encode(opt->value.stringval).c_str()); - break; - case COK_INT: - result << wxString::Format(_T("%s:%d|"), opt->name.c_str(), opt->value.intval); - break; - case COK_FLOAT: - result << wxString::Format(_T("%s:%e|"), opt->name.c_str(), opt->value.floatval); - break; - case COK_BOOL: - result << wxString::Format(_T("%s:%d|"), opt->name.c_str(), opt->value.boolval?1:0); - break; - case COK_COLOUR: - result << wxString::Format(_T("%s:%s|"), opt->name.c_str(), opt->value.colourval.GetASSFormatted(false).c_str()); - break; - default: - // The rest aren't stored - break; - } - } - if (result.Last() == _T('|')) - result.RemoveLast(); - return result; -} - - -void AutomationScriptConfiguration::unserialize(wxString &settings) -{ - //wxLogMessage(_T("Unserializing config string: %s"), settings); - wxStringTokenizer toker(settings, _T("|"), wxTOKEN_STRTOK); - while (toker.HasMoreTokens()) { - // get the parts of this setting - wxString setting = toker.GetNextToken(); - //wxLogMessage(_T("Got token: %s"), setting); - wxString optname = setting.BeforeFirst(_T(':')); - wxString optval = setting.AfterFirst(_T(':')); - //wxLogMessage(_T("Split into: \"%s\" and \"%s\""), optname, optval); - // find the setting in the list loaded from the script - std::vector::iterator opt = options.begin(); - while (opt != options.end() && opt->name != optname) - opt ++; - if (opt != options.end()) { - //wxLogMessage(_T("Found the option!")); - // ok, found the option! - switch (opt->kind) { - case COK_TEXT: - case COK_STYLE: - opt->value.stringval = inline_string_decode(optval); - //wxLogMessage(_T("Decoded string to: %s"), opt->value.stringval); - break; - case COK_INT: - { - long n; - optval.ToLong(&n, 10); - opt->value.intval = n; - } - break; - case COK_FLOAT: - optval.ToDouble(&opt->value.floatval); - break; - case COK_BOOL: - opt->value.boolval = optval == _T("1"); - break; - case COK_COLOUR: - opt->value.colourval.ParseASS(optval); - break; - } - } - } -} - - -void AutomationScriptConfiguration::load_from_lua(lua_State *L) -{ - //wxLogMessage(_T("Loading configuration options from script")); - present = false; - if (!lua_istable(L, -1)) { - return; - } - //wxLogMessage(_T("The script does have config options, good!")); - int i = 1; - while (true) { - // get an element from the array - //wxLogMessage(_T("Getting option %d (stacktop is %d)"), i, lua_gettop(L)); - lua_pushnumber(L, i); - lua_gettable(L, -2); - // check if it was a table - if (!lua_istable(L, -1)) { - //wxLogMessage(_T("Damn! Not an option... breaking out (actual type was %d)"), lua_type(L, -1)); - lua_pop(L, 1); - break; - } - //wxLogMessage(_T("Yay! It was an option, adding another blank option thing to the list")); - // add a new config option and fill it - { - AutomationScriptConfigurationOption opt; - options.push_back(opt); - } - AutomationScriptConfigurationOption &opt = options.back(); - // get the "kind" - lua_pushstring(L, "kind"); - lua_gettable(L, -2); - if (lua_isstring(L, -1)) { - // use C standard lib functions here, as it's probably faster than messing around with unicode - // lua is known to always properly null-terminate strings, and the strings are known to be pure ascii - const char *kind = lua_tostring(L, -1); - if (strcmp(kind, "label") == 0) { - opt.kind = COK_LABEL; - } else if (strcmp(kind, "text") == 0) { - opt.kind = COK_TEXT; - } else if (strcmp(kind, "int") == 0) { - opt.kind = COK_INT; - } else if (strcmp(kind, "float") == 0) { - opt.kind = COK_FLOAT; - } else if (strcmp(kind, "bool") == 0) { - opt.kind = COK_BOOL; - } else if (strcmp(kind, "colour") == 0) { - opt.kind = COK_COLOUR; - } else if (strcmp(kind, "style") == 0) { - opt.kind = COK_STYLE; - } else { - opt.kind = COK_INVALID; - } - } else { - opt.kind = COK_INVALID; - } - //wxLogMessage(_T("Got kind: %d"), opt.kind); - // remove "kind" string from stack again - lua_pop(L, 1); - // no need to check for rest if this one is already deemed invalid - if (opt.kind != COK_INVALID) { - // name - lua_pushstring(L, "name"); - lua_gettable(L, -2); - if (lua_isstring(L, -1)) { - opt.name = wxString(lua_tostring(L, -1), wxConvUTF8); - lua_pop(L, 1); - } else { - lua_pop(L, 1); - // no name means invalid option - opt.kind = COK_INVALID; - goto continue_invalid_option; - } - //wxLogMessage(_T("Got name: %s"), opt.name); - // label - lua_pushstring(L, "label"); - lua_gettable(L, -2); - if (lua_isstring(L, -1)) { - opt.label = wxString(lua_tostring(L, -1), wxConvUTF8); - lua_pop(L, 1); - } else { - lua_pop(L, 1); - // label is also required - opt.kind = COK_INVALID; - goto continue_invalid_option; - } - assert(opt.kind != COK_INVALID); - // hint - lua_pushstring(L, "hint"); - lua_gettable(L, -2); - if (lua_isstring(L, -1)) { - opt.hint = wxString(lua_tostring(L, -1), wxConvUTF8); - } else { - opt.hint = _T(""); - } - lua_pop(L, 1); - // min - lua_pushstring(L, "min"); - lua_gettable(L, -2); - if (lua_isnumber(L, -1)) { - opt.min.isset = true; - opt.min.floatval = lua_tonumber(L, -1); - opt.min.intval = (int)opt.min.floatval; - } else { - opt.min.isset = false; - } - lua_pop(L, 1); - // max - lua_pushstring(L, "max"); - lua_gettable(L, -2); - if (lua_isnumber(L, -1)) { - opt.max.isset = true; - opt.max.floatval = lua_tonumber(L, -1); - opt.max.intval = (int)opt.max.floatval; - } else { - opt.max.isset = false; - } - lua_pop(L, 1); - // default (this is going to kill me) - lua_pushstring(L, "default"); - lua_gettable(L, -2); - switch (opt.kind) { - case COK_LABEL: - // nothing to do, nothing expected - break; - case COK_TEXT: - case COK_STYLE: - // expect it to be a string - if (lua_isstring(L, -1)) { - opt.default_val.stringval = wxString(lua_tostring(L, -1), wxConvUTF8); - } else { - // not a string, baaaad scripter - opt.kind = COK_INVALID; - } - break; - case COK_INT: - case COK_FLOAT: - // expect it to be a number - if (lua_isnumber(L, -1)) { - opt.default_val.floatval = lua_tonumber(L, -1); - opt.default_val.intval = (int)opt.default_val.floatval; - } else { - opt.kind = COK_INVALID; - } - break; - case COK_BOOL: - // expect it to be a bool - if (lua_isboolean(L, -1)) { - opt.default_val.boolval = lua_toboolean(L, -1)!=0; - } else { - opt.kind = COK_INVALID; - } - break; - case COK_COLOUR: - // expect it to be a ass hex colour formatted string - if (lua_isstring(L, -1)) { - opt.default_val.stringval = wxString(lua_tostring(L, -1), wxConvUTF8); - opt.default_val.colourval.ParseASS(opt.default_val.stringval); // and hope this goes well! - } else { - opt.kind = COK_INVALID; - } - break; - } - opt.value = opt.default_val; - lua_pop(L, 1); - } - // so we successfully got an option added, so at least there is a configuration present now - present = true; -continue_invalid_option: - // clean up and prepare for next iteration - lua_pop(L, 1); - i++; - } -} - - -void AutomationScriptConfiguration::store_to_lua(lua_State *L) -{ - // we'll always need a new table, no matter what - lua_newtable(L); - //wxLogMessage(_T("Created table for configuration data (top=%d)"), lua_gettop(L)); - - for (std::vector::iterator opt = options.begin(); opt != options.end(); opt++) { - //wxLogMessage(_T("Storing option named '%s' (top=%d)"), opt->name, lua_gettop(L)); - switch (opt->kind) { - case COK_INVALID: - case COK_LABEL: - //wxLogMessage(_T("Nothing to store")); - break; - - case COK_TEXT: - case COK_STYLE: - //wxLogMessage(_T("Storing string value")); - L_settable(L, -1, opt->name, opt->value.stringval); - break; - - case COK_INT: - //wxLogMessage(_T("Storing int value")); - L_settable(L, -1, opt->name, opt->value.intval); - break; - - case COK_FLOAT: - //wxLogMessage(_T("Storing float value")); - L_settable(L, -1, opt->name, opt->value.floatval); - break; - - case COK_BOOL: - //wxLogMessage(_T("Storing bool value")); - L_settable_bool(L, -1, opt->name, opt->value.boolval); - break; - - case COK_COLOUR: - //wxLogMessage(_T("Storing colourvalue")); - L_settable(L, -1, opt->name, opt->value.colourval.GetASSFormatted(false, false)); - break; - - default: - //wxLogMessage(_T("Felt into default handler?!?")); - break; - } - } - //wxLogMessage(_T("Finished storing configuration data (top=%d)"), lua_gettop(L)); -} - - - -AutomationScript::AutomationScript(AutomationScriptFile *script) -{ - force_cancel = false; - filename = script->filename; - progress_reporter = 0; - debug_reporter = 0; - - // get a lua object - L = lua_open(); - // put a pointer to this object in the registry index - lua_pushstring(L, "aegisub"); - lua_pushlightuserdata(L, this); - lua_rawset(L, LUA_REGISTRYINDEX); - - // set up the cancelling hook, call every 100 instructions - lua_sethook(L, AutomationHelper::hookfunc, LUA_MASKCOUNT, 100); - - // provide some standard libraries - luaopen_base(L); - luaopen_string(L); - luaopen_table(L); - luaopen_math(L); -#ifdef _DEBUG - luaopen_debug(L); -#endif - // but no I/O, OS or debug facilities, those aren't safe - - // disable the dofile() function - lua_pushstring(L, "dofile"); - lua_pushnil(L); - lua_settable(L, LUA_GLOBALSINDEX); - // create an include function better suited aegisub later - // the path object is needed for this - include_path.EnsureFileAccessible(script->filename); - { - wxStringTokenizer toker(Options.AsText(_T("Automation Include Path")), _T("|"), false); - while (toker.HasMoreTokens()) { - wxFileName path(toker.GetNextToken()); - if (!path.IsOk()) continue; - if (path.IsRelative()) continue; - if (!path.DirExists()) continue; - if (include_path.Member(path.GetLongPath())) continue; - include_path.Add(path.GetLongPath()); - } - } - // add the include function to the global environment - lua_pushstring(L, "include"); - lua_pushcfunction(L, AutomationHelper::include); - lua_settable(L, LUA_GLOBALSINDEX); - - // create the "aegisub" table and fill it with some function pointers - // create the table and add it to the global environment - lua_pushstring(L, "aegisub"); - lua_newtable(L); - lua_settable(L, LUA_GLOBALSINDEX); - // get it back onto the stack - lua_pushstring(L, "aegisub"); - lua_gettable(L, LUA_GLOBALSINDEX); - // get the index of the table on the stack - int tabid = lua_gettop(L); - // now register some functions! - lua_pushstring(L, "output_debug"); - lua_pushcfunction(L, AutomationHelper::output_debug); - lua_settable(L, tabid); - lua_pushstring(L, "set_status"); - lua_pushcfunction(L, AutomationHelper::set_status); - lua_settable(L, tabid); - lua_pushstring(L, "report_progress"); - lua_pushcfunction(L, AutomationHelper::report_progress); - lua_settable(L, tabid); - lua_pushstring(L, "colorstring_to_rgb"); - lua_pushcfunction(L, AutomationHelper::colorstring_to_rgb); - lua_settable(L, tabid); - lua_pushstring(L, "text_extents"); - lua_pushcfunction(L, AutomationHelper::text_extents); - lua_settable(L, tabid); - lua_pushstring(L, "frame_from_ms"); - lua_pushcfunction(L, AutomationHelper::frame_from_ms); - lua_settable(L, tabid); - lua_pushstring(L, "ms_from_frame"); - lua_pushcfunction(L, AutomationHelper::ms_from_frame); - lua_settable(L, tabid); - // and no more need for that tabid - lua_settop(L, tabid-1); - - // ok, finally the environment is set up! - // now try to load the script - { - switch (luaL_loadbuffer(L, script->scriptdata, script->scriptlen, "user script")) { - case 0: - // success! - break; - case LUA_ERRSYNTAX: - throw AutomationError(wxString::Format(_T("Lua syntax error: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - break; - case LUA_ERRMEM: - throw AutomationError(wxString::Format(_T("Lua memory allocation error: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - break; - default: - throw AutomationError(wxString::Format(_T("Lua unknown error: %s"), wxString(lua_tostring(L, -1), wxConvUTF8).c_str())); - break; - } - } - // it's loaded and is now a function at the top of the stack - // it doesn't take any arguments and doesn't return anything - // so let's try executing it by calling! - L_callfunc(L, 0, 0); - - // so, the script should be loaded - // now try to get the script data! - // first the version - lua_pushstring(L, "version"); - lua_gettable(L, LUA_GLOBALSINDEX); - if (!lua_isnumber(L, -1)) { - throw AutomationError(wxString(_T("Script error: 'version' value not found or not a number"))); - } - version = lua_tonumber(L, -1); - lua_settop(L, -2); - if (version < 3 || version > 4) { - // invalid version - throw AutomationError(wxString(_T("Script error: 'version' value invalid for this version of Automation"))); - } - // kind - lua_pushstring(L, "kind"); - lua_gettable(L, LUA_GLOBALSINDEX); - if (!lua_isstring(L, -1)) { - throw AutomationError(wxString(_T("Script error: 'kind' value not found or not a string"))); - } - kind = wxString(lua_tostring(L, -1), wxConvUTF8); - lua_settop(L, -2); - // name - lua_pushstring(L, "name"); - lua_gettable(L, LUA_GLOBALSINDEX); - if (!lua_isstring(L, -1)) { - throw AutomationError(wxString(_T("Script error: 'name' value not found or not a string"))); - } - name = wxString(lua_tostring(L, -1), wxConvUTF8); - lua_settop(L, -2); - // description (optional) - lua_pushstring(L, "description"); - lua_gettable(L, LUA_GLOBALSINDEX); - if (lua_isstring(L, -1)) { - description = wxString(lua_tostring(L, -1), wxConvUTF8); - lua_settop(L, -2); - } else { - description = _T(""); - } - // process_lines (just check if it's there, no need to save it anywhere) - lua_pushstring(L, "process_lines"); - lua_gettable(L, LUA_GLOBALSINDEX); - if (!lua_isfunction(L, -1)) { - throw AutomationError(wxString(_T("Script error: No 'process_lines' function provided"))); - } - lua_settop(L, -2); - // configuration (let the config object do all the loading) - lua_pushstring(L, "configuration"); - lua_gettable(L, LUA_GLOBALSINDEX); - //wxLogMessage(_T("Calling configuration.load_from_lua()")); - configuration.load_from_lua(L); - lua_settop(L, -2); - - // done! -} - - -AutomationScript::~AutomationScript() -{ - lua_close(L); -} - - -void AutomationScript::OutputDebugString(wxString str, bool isdebug) -{ - //wxLogMessage(_T("automation message: ") + str); - if (debug_reporter) { - debug_reporter(str, isdebug, this, debug_target); - } - return; -} - -void AutomationScript::ReportProgress(float progress) -{ - //wxLogMessage(wxString::Format(_T("automation progress: %.1f%%"), progress)); - if (progress_reporter) { - progress_reporter(progress, this, progress_target); - } - return; -} - - -int AutomationScript::L_panicfunc(lua_State *L) -{ - wxLogError(_T("Lua produced an error. Attempting to recover.")); - longjmp(AutomationHelper::GetScriptObject(L)->panicjmp, lua_gettop(L)); -} - - -void AutomationScript::process_lines(AssFile *input) -{ - // prepare for panic... - if (int ret = setjmp(panicjmp)) { - wxLogError(wxString::Format(_T("Returned out of Lua environment. Size of stack before: %d"), ret)); -#ifdef _DEBUG - wxLogError( -#else - wxLogFatalError( -#endif - _T("Due to an internal error in the Lua engine, the internal state of Aegisub might have become inconsistent ") - _T("and cannot continue. If you can reproduce this error, please report it to the developers.")); - lua_close(L); - return; - } else { - lua_atpanic(L, AutomationScript::L_panicfunc); - } - - // start by generating lua representations of the data... - // maybe it's safest to start by making plenty of space on the stack - if (!lua_checkstack(L, 100)) { - throw AutomationError(wxString(_T("Lua error: Unable to allocate stack space"))); - } - - OutputDebugString(wxString(_T("Preparing subtitle data"))); - - // first put the function itself on the stack - lua_pushstring(L, "process_lines"); - lua_gettable(L, LUA_GLOBALSINDEX); - - // now put the three arguments on the stack - - // first argument: the metadata table - lua_newtable(L); - L_settable(L, -1, "res_x", input->GetScriptInfoAsInt(_T("PlayResX"))); - L_settable(L, -1, "res_y", input->GetScriptInfoAsInt(_T("PlayResY"))); - - // second and third arguments: styles and events tables - lua_newtable(L); - int styletab = lua_gettop(L); - lua_newtable(L); - int eventtab = lua_gettop(L); - - int numstyles = 0, numevents = 0; - - // fill the styles and events tables - int processed_lines = 1; - for (std::list::iterator i = input->Line.begin(); i != input->Line.end(); i++, processed_lines++) { - - AssEntry *e = *i; - - if (!e->Valid) continue; - - if (e->GetType() == ENTRY_STYLE) { - - AssStyle *style = e->GetAsStyle(e); - - // gonna need a table to put the style data into - lua_newtable(L); - // put the table into index N in the style table - lua_pushvalue(L, -1); - lua_rawseti(L, styletab, numstyles); - // and put it into its named index - lua_pushstring(L, style->name.mb_str(wxConvUTF8)); - lua_pushvalue(L, -2); - lua_settable(L, styletab); - - // so now the table is regged and stuff, put some data into it - L_settable (L, -1, "name", style->name); - L_settable (L, -1, "fontname", style->font); - L_settable (L, -1, "fontsize", style->fontsize); - L_settable (L, -1, "color1", style->primary.GetASSFormatted(true, true)); - L_settable (L, -1, "color2", style->secondary.GetASSFormatted(true, true)); - L_settable (L, -1, "color3", style->outline.GetASSFormatted(true, true)); - L_settable (L, -1, "color4", style->shadow.GetASSFormatted(true, true)); - L_settable_bool(L, -1, "bold", style->bold); - L_settable_bool(L, -1, "italic", style->italic); - L_settable_bool(L, -1, "underline", style->underline); - L_settable_bool(L, -1, "strikeout", style->strikeout); - L_settable (L, -1, "scale_x", style->scalex); - L_settable (L, -1, "scale_y", style->scaley); - L_settable (L, -1, "spacing", style->spacing); - L_settable (L, -1, "angle", style->angle); - L_settable (L, -1, "borderstyle", style->borderstyle); - L_settable (L, -1, "outline", style->outline_w); - L_settable (L, -1, "shadow", style->shadow_w); - L_settable (L, -1, "align", style->alignment); - L_settable (L, -1, "margin_l", style->MarginL); - L_settable (L, -1, "margin_r", style->MarginR); - L_settable (L, -1, "margin_v", style->MarginV); - L_settable (L, -1, "encoding", style->encoding); - - // and get that table off the stack again - lua_settop(L, -2); - - numstyles++; - - } else if (e->group == _T("[Events]")) { - - if (e->GetType() != ENTRY_DIALOGUE) { - - // not a dialogue/comment event - - // start checking for a blank line - wxString entryData = e->GetEntryData(); - if (entryData.IsEmpty()) { - lua_newtable(L); - L_settable(L, -1, "kind", wxString(_T("blank"))); - } else if (entryData[0] == _T(';')) { - // semicolon comment - lua_newtable(L); - L_settable(L, -1, "kind", wxString(_T("scomment"))); - L_settable(L, -1, "text", entryData.Mid(1)); - } else { - // not a blank line and not a semicolon comment - // just skip... - continue; - } - - } else { - - // ok, so it is a dialogue/comment event - // massive handling :( - - lua_newtable(L); - - assert(e->GetType() == ENTRY_DIALOGUE); - - AssDialogue *dia = e->GetAsDialogue(e); - - // kind of line - if (dia->Comment) { - L_settable(L, -1, "kind", wxString(_T("comment"))); - } else { - L_settable(L, -1, "kind", wxString(_T("dialogue"))); - } - - L_settable(L, -1, "layer", dia->Layer); - L_settable(L, -1, "start_time", dia->Start.GetMS()/10); - L_settable(L, -1, "end_time", dia->End.GetMS()/10); - L_settable(L, -1, "style", dia->Style); - L_settable(L, -1, "name", dia->Actor); - L_settable(L, -1, "margin_l", dia->MarginL); - L_settable(L, -1, "margin_r", dia->MarginR); - L_settable(L, -1, "margin_v", dia->MarginV); - L_settable(L, -1, "effect", dia->Effect); - L_settable(L, -1, "text", dia->Text); - - // so that's the easy part - // now for the stripped text and *ugh* the karaoke! - - // prepare for stripped text - wxString text_stripped = _T(""); - L_settable(L, -1, "text_stripped", 0); // dummy item - // prepare karaoke table - lua_newtable(L); - lua_pushstring(L, "karaoke"); - lua_pushvalue(L, -2); - lua_settable(L, -4); - // now the top of the stack is the karaoke table, and it's present in the dialogue table - - int kcount = 0; - int kdur = 0; - wxString kkind = _T(""); - wxString ktext = _T(""); - wxString ktext_stripped = _T(""); - - dia->ParseASSTags(); - for (std::vector::iterator block = dia->Blocks.begin(); block != dia->Blocks.end(); block++) { - - switch ((*block)->type) { - - case BLOCK_BASE: - throw wxString(_T("BLOCK_BASE found processing dialogue blocks. This should never happen.")); - - case BLOCK_PLAIN: - ktext += (*block)->text; - ktext_stripped += (*block)->text; - text_stripped += (*block)->text; - break; - - case BLOCK_DRAWING: - ktext += (*block)->text; - break; - - case BLOCK_OVERRIDE: { - bool brackets_open = false; - std::vector &tags = (*block)->GetAsOverride(*block)->Tags; - - for (std::vector::iterator tag = tags.begin(); tag != tags.end(); tag++) { - - if (!(*tag)->Name.Mid(0,2).CmpNoCase(_T("\\k")) && (*tag)->IsValid()) { - - // it's a karaoke tag - if (brackets_open) { - ktext += _T("}"); - brackets_open = false; - } - L_settable_kara(L, -1, kcount, kdur, kkind, ktext, ktext_stripped); - kcount++; - kdur = (*tag)->Params[0]->AsInt(); // no error checking; this should always be int - kkind = (*tag)->Name.Mid(1); - ktext = _T(""); - ktext_stripped = _T(""); - - } else { - - // it's something else - // don't care if it's a valid tag or not - if (!brackets_open) { - ktext += _T("{"); - brackets_open = true; - } - ktext += (*tag)->ToString(); - - } - - } - - if (brackets_open) { - ktext += _T("}"); - } - - break;} - - } - - } - dia->ClearBlocks(); - - // add the final karaoke block to the table - // (even if there's no karaoke in the line, there's always at least one karaoke block) - // even if the line ends in {\k10} with no text after, an empty block should still be inserted - // (otherwise data are lost) - L_settable_kara(L, -1, kcount, kdur, kkind, ktext, ktext_stripped); - kcount++; - L_settable(L, -1, "n", kcount); // number of syllables in the karaoke - lua_settop(L, -2); // remove karaoke table from the stack again - L_settable(L, -1, "text_stripped", text_stripped); // store the real stripped text - - } - - // now the entry table has been created and placed on top of the stack - // now all that's missing it to insert it into the event table - lua_rawseti(L, eventtab, numevents); - numevents++; - - } else { - // not really a line type automation needs to take care of... ignore it - } - - ReportProgress(100.0f * processed_lines / input->Line.size() / 3); - - } - - // finally add the counter elements to the styles and events tables - lua_pushnumber(L, numstyles); - lua_rawseti(L, styletab, -1); - L_settable(L, eventtab, "n", numevents); - // and let the config object create a table for the @config argument - //wxLogMessage(_T("Calling configuration.store_to_lua()")); - configuration.store_to_lua(L); - - // so now the metadata, styles and events tables are filled with data - // ready to call the processing function! - - OutputDebugString(wxString(_T("Running script for processing"))); - ReportProgress(100.0f/3); - L_callfunc(L, 4, 1); - ReportProgress(200.0f/3); - OutputDebugString(wxString(_T("Reading back data from script"))); - - // phew, survived the call =) - // time to read back the results - - wxLogDebug(_T("Returned from Lua script call")); - - if (!lua_istable(L, -1)) { - throw AutomationError(wxString(_T("The script function did not return a table as expected. Unable to process results. (Nothing was changed.)"))); - } - - // but start by removing all events - { - std::list::iterator cur, next; - next = input->Line.begin(); - while (next != input->Line.end()) { - cur = next++; - if ((*cur)->group == _T("[Events]")) { - wxString temp = (*cur)->GetEntryData(); - if (temp == _T("[Events]")) { - // skip the section header - continue; - } - if ((*cur)->GetType() != ENTRY_DIALOGUE && temp.Mid(0,1) != _T(";") && temp.Trim() != _T("")) { - // skip non-dialogue non-semicolon comment lines (such as Format) - continue; - } - delete (*cur); - input->Line.erase(cur); - } - } - } - - wxLogDebug(_T("Finished removing old events from subtitles")); - - // so anyway, there is a single table on the stack now - // that table contains a lot of events... - // and it ought to contain an "n" key as well, telling how many events - // but be lenient, and don't expect one to be there, but rather count from zero and let it be nil-terminated - // if the "n" key is there, use it as a progress indicator hint, though - int output_line_count; - lua_pushstring(L, "n"); - lua_gettable(L, -2); - if (lua_isnumber(L, -1)) { - output_line_count = (int) lua_tonumber(L, -1); - } else { - // assume number of output lines == number of input lines - output_line_count = processed_lines; - } - lua_settop(L, -2); - - wxLogDebug(_T("Retrieved number of lines in result: %d"), output_line_count); - - // loop through the stack and report back the type of each element - wxLogDebug(_T("Size of Lua stack: %d"), lua_gettop(L)); - for (int si = lua_gettop(L); si > 0; si--) { - wxString type = wxString(lua_typename(L, lua_type(L, si)), wxConvUTF8); - wxLogDebug(_T("Stack index %d, type %s"), si, type.c_str()); - } - wxLogDebug(_T("Stack dump finished")); - - int outline = 0; - int faketime = input->Line.back()->StartMS; - - // If there's nothing at index 0, start at index 1 instead, to support both zero and one based indexing - lua_pushnumber(L, outline); - lua_gettable(L, -2); - if (!lua_istable(L, -1)) { - outline++; - output_line_count++; - } - lua_pop(L, 1); - - while (lua_pushnumber(L, outline), lua_gettable(L, -2), lua_istable(L, -1)) { - // top of the stack is a table, hopefully with an AssEntry in it - - wxLogDebug(_T("Processing output line %d"), outline); - - // start by getting the kind - lua_pushstring(L, "kind"); - lua_gettable(L, -2); - if (!lua_isstring(L, -1)) { - OutputDebugString(wxString::Format(_T("The output data at index %d is mising a valid 'kind' field, and has been skipped"), outline)); - lua_settop(L, -2); - } else { - - wxString kind = wxString(lua_tostring(L, -1), wxConvUTF8).Lower(); - // remove "kind" from stack again - lua_settop(L, -2); - wxLogDebug(_T("Kind of line: %s"), kind.c_str()); - - if (kind == _T("dialogue") || kind == _T("comment")) { - - lua_pushstring(L, "layer"); - lua_gettable(L, -2); - lua_pushstring(L, "start_time"); - lua_gettable(L, -3); - lua_pushstring(L, "end_time"); - lua_gettable(L, -4); - lua_pushstring(L, "style"); - lua_gettable(L, -5); - lua_pushstring(L, "name"); - lua_gettable(L, -6); - lua_pushstring(L, "margin_l"); - lua_gettable(L, -7); - lua_pushstring(L, "margin_r"); - lua_gettable(L, -8); - lua_pushstring(L, "margin_v"); - lua_gettable(L, -9); - lua_pushstring(L, "effect"); - lua_gettable(L, -10); - lua_pushstring(L, "text"); - lua_gettable(L, -11); - - wxLogDebug(_T("Read out all fields for dialogue event")); - - if (lua_isnumber(L, -10) && lua_isnumber(L, -9) && lua_isnumber(L, -8) && - lua_isstring(L, -7) && lua_isstring(L, -6) && lua_isnumber(L, -5) && - lua_isnumber(L, -4) && lua_isnumber(L, -3) && lua_isstring(L, -2) && - lua_isstring(L, -1)) - { - - AssDialogue *e = new AssDialogue(); - e->Layer = (int)lua_tonumber(L, -10); - e->Start.SetMS(10*(int)lua_tonumber(L, -9)); - e->End.SetMS(10*(int)lua_tonumber(L, -8)); - e->Style = wxString(lua_tostring(L, -7), wxConvUTF8); - e->Actor = wxString(lua_tostring(L, -6), wxConvUTF8); - e->MarginL = (int)lua_tonumber(L, -5); - e->MarginR = (int)lua_tonumber(L, -4); - e->MarginV = (int)lua_tonumber(L, -3); - e->Effect = wxString(lua_tostring(L, -2), wxConvUTF8); - e->Text = wxString(lua_tostring(L, -1), wxConvUTF8); - e->Comment = kind == _T("comment"); - lua_settop(L, -11); - e->StartMS = e->Start.GetMS(); - //e->ParseASSTags(); - e->UpdateData(); - input->Line.push_back(e); - wxLogDebug(_T("Produced new dialogue event in output subs")); - - } else { - OutputDebugString(wxString::Format(_T("The output data at index %d (kind '%s') has one or more missing/invalid fields, and has been skipped"), outline, kind.c_str())); - } - - } else if (kind == _T("scomment")) { - - lua_pushstring(L, "text"); - lua_gettable(L, -2); - if (lua_isstring(L, -1)) { - wxString text(lua_tostring(L, -1), wxConvUTF8); - lua_settop(L, -2); - AssEntry *e = new AssEntry(wxString(_T(";")) + text); - e->StartMS = faketime; - input->Line.push_back(e); - wxLogDebug(_T("Produced new semicolon comment in output subs")); - } else { - OutputDebugString(wxString::Format(_T("The output data at index %d (kind 'scomment') is missing a valid 'text' field, and has been skipped"), outline)); - } - - } else if (kind == _T("blank")) { - - AssEntry *e = new AssEntry(_T("")); - e->StartMS = faketime; - input->Line.push_back(e); - wxLogDebug(_T("Produced new blank line in output subs")); - - } else { - OutputDebugString(wxString::Format(_T("The output data at index %d has an invalid value in the 'kind' field, and has been skipped"), outline)); - } - - } - - // remove table again - lua_settop(L, -2); - // progress report - if (outline >= output_line_count) { - ReportProgress(99.9f); - } else { - ReportProgress((200.0f + 100.0f*outline/output_line_count) / 3); - } - - outline++; - - wxLogDebug(_T("Size of Lua stack: %d"), lua_gettop(L)); - - } - - ReportProgress(100); - OutputDebugString(wxString(_T("Script execution complete"))); - return; -} - - - -AutomationScriptFile::~AutomationScriptFile() -{ - // if file had a bom - if (utf8bom) - scriptdata -= 3; - delete scriptdata; -} - -AutomationScriptFile *AutomationScriptFile::CreateFromString(wxString &script) -{ - wxCharBuffer rawscript = script.mb_str(wxConvUTF8); - AutomationScriptFile *res = new AutomationScriptFile(); - res->scriptlen = strlen(rawscript); - res->scriptdata = new char[res->scriptlen]; - res->filename = _T(""); - return res; -} - -AutomationScriptFile *AutomationScriptFile::CreateFromFile(wxString filename) -{ - wxFile file(filename); - if (!file.IsOpened()) { - return 0; - } - - // prepare variables - AutomationScriptFile *res = new AutomationScriptFile(); - res->filename = filename; - res->scriptlen = file.Length(); - res->scriptdata = new char[res->scriptlen]; - // read from file - file.Read(res->scriptdata, res->scriptlen); - // check for UTF-8 BOM - res->utf8bom = ((res->scriptdata[0]&0xFF) == 0xEF) && ((res->scriptdata[1]&0xFF) == 0xBB) && ((res->scriptdata[2]&0xFF) == 0xBF); - if (res->utf8bom) { - // skip it if found - res->scriptdata += 3; - res->scriptlen -= 3; - } - return res; -} - diff --git a/aegisub/auto3/automation.h b/aegisub/auto3/automation.h deleted file mode 100644 index 15d85fddf..000000000 --- a/aegisub/auto3/automation.h +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2005, 2006, Niels Martin Hansen -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------------- -// -// AEGISUB -// -// Website: http://aegisub.cellosoft.com -// Contact: mailto:zeratul@cellosoft.com -// - -extern "C" { -#if HAVE_LUA50_LUA_H -#include -#else -#include -#endif -} - -#include -#include -#include -#include "ass_file.h" -#include "ass_dialogue.h" -#include "ass_override.h" -#include "ass_style.h" - -#include - -#pragma once - - -class AutomationError { -public: - wxString message; - AutomationError(wxString msg); -}; - - -enum AutomationScriptConfigurationOptionKind { - COK_INVALID = 0, - COK_LABEL, - COK_TEXT, - COK_INT, - COK_FLOAT, - COK_BOOL, - COK_COLOUR, - COK_STYLE -}; - -struct AutomationScriptConfigurationOption { - wxString name; - AutomationScriptConfigurationOptionKind kind; - wxString label; - wxString hint; - union { - bool isset; - int intval; - double floatval; - } min, max; - struct { - wxString stringval; - int intval; - double floatval; - bool boolval; - AssColor colourval; - } default_val, value; -}; - -class AutomationScriptConfiguration { -public: - - bool present; // is there any configuration option set at all? - - std::vector options; - - wxString serialize(); // make a string from the option name+value pairs - void unserialize(wxString &settings); // set the option values from a serialized string - - void load_from_lua(lua_State *L); // top of the stack must be a table in the format of the global "configuration" table, or nil; fill the options vector from that table. (the current options vector will be cleared. all values will be set to the defaults.) - void store_to_lua(lua_State *L); // create a process_lines@config style table from the options name:value pairs. after the call, the top of the stack will be such a table. -}; - - -struct AutomationScriptFile { - bool utf8bom; - char *scriptdata; - size_t scriptlen; - wxString filename; - - ~AutomationScriptFile(); - static AutomationScriptFile *CreateFromString(wxString &script); - static AutomationScriptFile *CreateFromFile(wxString filename); -}; - - -class AutomationScript { -protected: - lua_State *L; - jmp_buf panicjmp; - - static int L_panicfunc(lua_State *L); - -public: - AutomationScript(AutomationScriptFile *script); - virtual ~AutomationScript(); - - // Reporting functions. These do nothing in the base class. - // They should be overridden in a derived class. - virtual void OutputDebugString(wxString str, bool isdebug = false); - virtual void ReportProgress(float progress); - - // stuff corresponding to globals in the script - float version; - wxString kind; - wxString name; - wxString description; - AutomationScriptConfiguration configuration; - - // filename the script was loaded from - wxString filename; - // include path for scripts - wxPathList include_path; - - volatile bool force_cancel; - void *progress_target; - void *debug_target; - typedef void (*progress_reporter_t)(float progress, AutomationScript *script, void *target); - typedef void (*debug_reporter_t)(wxString &str, bool isdebug, AutomationScript *script, void *target); - progress_reporter_t progress_reporter; - debug_reporter_t debug_reporter; - - virtual void process_lines(AssFile *input); -}; - diff --git a/aegisub/auto3/automation_filter.cpp b/aegisub/auto3/automation_filter.cpp deleted file mode 100644 index 610d08433..000000000 --- a/aegisub/auto3/automation_filter.cpp +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) 2005, Niels Martin Hansen -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------------- -// -// AEGISUB -// -// Website: http://aegisub.cellosoft.com -// Contact: mailto:zeratul@cellosoft.com -// - -#include "automation_filter.h" -#include -#include -#include -#include -#include -#include -#include -#include "dialog_progress.h" - - -AutomationScriptThread::AutomationScriptThread(AutomationScript *a_script, AssFile *a_subs) -: wxThread(wxTHREAD_JOINABLE), script(a_script), subs(a_subs) -{ - Create(); -} - - -wxThread::ExitCode AutomationScriptThread::Entry() -{ - try { - script->process_lines(subs); - } - catch (AutomationError &e) { - script->OutputDebugString(wxString(_T("Script wrapper: Script produced an exception.")), true); - script->OutputDebugString(wxString::Format(_T("Message was: %s"), e.message.c_str()), true); - script->OutputDebugString(wxString(_T("Script wrapper: Output data are probably unchanged or corrupted.")), true); - } - return 0; -} - - - -AutomationFilterConfigDialog::AutomationFilterConfigDialog(wxWindow *parent, AutomationScriptConfiguration &config) -: wxPanel(parent, wxID_ANY) -{ - wxFlexGridSizer *sizer = new wxFlexGridSizer(2, 5, 5); - - //wxLogMessage(_T("Now going to create %d controls for automation script"), config.options.size()); - - for (std::vector::iterator opt = config.options.begin(); opt != config.options.end(); opt++) { - //wxLogMessage(_T("Creating control for kind: %d"), opt->kind); - if (opt->kind == COK_INVALID) - continue; - - Control control; - control.option = &*opt; - - switch (opt->kind) { - case COK_LABEL: - control.control = new wxStaticText(this, -1, opt->label); - break; - - case COK_TEXT: - control.control = new wxTextCtrl(this, -1, opt->value.stringval); - break; - - case COK_INT: - control.control = new wxSpinCtrl(this, -1); - if (opt->min.isset && opt->max.isset) { - ((wxSpinCtrl*)control.control)->SetRange(opt->min.intval, opt->max.intval); - } else if (opt->min.isset) { - ((wxSpinCtrl*)control.control)->SetRange(opt->min.intval, 0x7fff); - } else if (opt->max.isset) { - ((wxSpinCtrl*)control.control)->SetRange(-0x7fff, opt->max.intval); - } else { - ((wxSpinCtrl*)control.control)->SetRange(-0x7fff, 0x7fff); - } - ((wxSpinCtrl*)control.control)->SetValue(opt->value.intval); - break; - - case COK_FLOAT: - control.control = new wxTextCtrl(this, -1, wxString::Format(_T("%f"), opt->value.floatval)); - break; - - case COK_BOOL: - control.control = new wxCheckBox(this, -1, opt->label); - ((wxCheckBox*)control.control)->SetValue(opt->value.boolval); - break; - - case COK_COLOUR: - // *FIXME* what to do here? - // just put a stupid edit box for now - control.control = new wxTextCtrl(this, -1, opt->value.colourval.GetASSFormatted(false)); - break; - - case COK_STYLE: - control.control = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, AssFile::top->GetStyles()); - ((wxChoice*)control.control)->Insert(_T(""), 0); - break; - - } - - if (opt->kind != COK_LABEL && opt->kind != COK_BOOL) { - control.label = new wxStaticText(this, -1, opt->label); - sizer->Add(control.label, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL); - } else { - control.label = 0; - sizer->AddSpacer(0); - } - control.control->SetToolTip(opt->hint); - sizer->Add(control.control, 1, wxEXPAND); - - controls.push_back(control); - } - - SetSizerAndFit(sizer); -} - - - -AssAutomationFilter::AssAutomationFilter(AutomationScript *a_script) -: script(a_script), dialog(0) -{ - Register(wxString::Format(_T("Automation: %s"), script->name.c_str()), 2000); - if (script->description.IsEmpty()) { - description = wxString::Format(_T("%s\r\n(This Automation script has not provided a description.)"), script->name.c_str()); - } else { - description = script->description; - } - automation_filter_list.push_back(this); -} - - -void AssAutomationFilter::Init() { -} - - -AssAutomationFilter::~AssAutomationFilter() -{ - Unregister(); - automation_filter_list.remove(this); -} - - -static void progress_reporter(float progress, AutomationScript *script, void *dialog) -{ - ((DialogProgress*)dialog)->SetProgress((int)(progress*10), 1000); -} - -static void debug_reporter(wxString &str, bool isdebug, AutomationScript *script, void *dialog) -{ - ((DialogProgress*)dialog)->SetText(str); - if (isdebug) { - wxLogMessage(str); - } -} - - -void AssAutomationFilter::ProcessSubs(AssFile *subs) -{ - AutomationScriptThread thread(script, subs); - - // prepare a progress dialog - DialogProgress *dialog = new DialogProgress(0, script->name, &script->force_cancel, _T(""), 0, 1000); - dialog->Show(); - - // make the script aware of it - script->progress_reporter = progress_reporter; - script->progress_target = dialog; - script->debug_reporter = debug_reporter; - script->debug_target = dialog; - - // run the script - thread.Run(); - thread.Wait(); - - // make sure the dialog won't be touched again - script->progress_reporter = 0; - script->debug_reporter = 0; - delete dialog; -} - - -void AssAutomationFilter::LoadSettings(bool IsDefault) -{ - wxString opthname = wxString::Format(_T("Automation Settings %s"), wxFileName(script->filename).GetFullName().c_str()); - - // if it's an auto export, just read the serialized settings from the ass file - // (does nothing if no settings are serialized) - if (IsDefault) { - wxString serialized = AssFile::top->GetScriptInfo(opthname); - script->configuration.unserialize(serialized); - return; - } - - // if there's no dialog, we can't do anything - if (!dialog) return; - - for (std::vector::iterator ctl = dialog->controls.begin(); ctl != dialog->controls.end(); ctl++) { - switch (ctl->option->kind) { - case COK_TEXT: - ctl->option->value.stringval = ((wxTextCtrl*)ctl->control)->GetValue(); - break; - - case COK_INT: - ctl->option->value.intval = ((wxSpinCtrl*)ctl->control)->GetValue(); - break; - - case COK_FLOAT: - if (!((wxTextCtrl*)ctl->control)->GetValue().ToDouble(&ctl->option->value.floatval)) { - wxLogWarning( - _T("The value entered for field '%s' (%s) could not be converted to a floating-point number. Default value (%f) substituted for the entered value."), - ctl->option->label.c_str(), - ((wxTextCtrl*)ctl->control)->GetValue().c_str(), - ctl->option->default_val.floatval); - ctl->option->value.floatval = ctl->option->default_val.floatval; - } - break; - - case COK_BOOL: - ctl->option->value.boolval = ((wxCheckBox*)ctl->control)->GetValue(); - break; - - case COK_COLOUR: - // *FIXME* needs to be updated to use a proper color control - ctl->option->value.colourval.ParseASS(((wxTextCtrl*)ctl->control)->GetValue()); - break; - - case COK_STYLE: - ctl->option->value.stringval = ((wxChoice*)ctl->control)->GetStringSelection(); - break; - } - } - - // serialize the new settings and save them to the file - AssFile::top->SetScriptInfo(opthname, script->configuration.serialize()); -} - - -wxWindow *AssAutomationFilter::GetConfigDialogWindow(wxWindow *parent) -{ - wxString opthname = wxString::Format(_T("Automation Settings %s"), wxFileName(script->filename).GetFullName().c_str()); - wxString serialized = AssFile::top->GetScriptInfo(opthname); - script->configuration.unserialize(serialized); - - if (script->configuration.present) - return dialog = new AutomationFilterConfigDialog(parent, script->configuration); - else - return 0; -} - - -AutomationScript *AssAutomationFilter::GetScript() -{ - return script; -} - - -const std::list& AssAutomationFilter::GetFilterList() -{ - return AssAutomationFilter::automation_filter_list; -} - - -// static list of loaded automation filters -std::list AssAutomationFilter::automation_filter_list; - diff --git a/aegisub/auto3/automation_filter.h b/aegisub/auto3/automation_filter.h deleted file mode 100644 index 3e3e607fa..000000000 --- a/aegisub/auto3/automation_filter.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2005, Niels Martin Hansen -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------------- -// -// AEGISUB -// -// Website: http://aegisub.cellosoft.com -// Contact: mailto:zeratul@cellosoft.com -// - -#pragma once - -#include "automation.h" -#include "ass_export_filter.h" - - -class AutomationScriptThread : public wxThread { -protected: - AutomationScript *script; - AssFile *subs; -public: - AutomationScriptThread(AutomationScript *a_script, AssFile *a_subs); - wxThread::ExitCode Entry(); -}; - - -class AutomationFilterConfigDialog : public wxPanel { -public: - struct Control { - wxStaticText *label; - wxControl *control; - AutomationScriptConfigurationOption *option; - Control() : label(0), control(0), option(0) {} - }; - std::vector controls; - - AutomationFilterConfigDialog(wxWindow *parent, AutomationScriptConfiguration &config); -}; - - -class AssAutomationFilter : public AssExportFilter { -private: - AutomationScript *script; - AutomationFilterConfigDialog *dialog; - - static std::list automation_filter_list; - void Init(); - -public: - AssAutomationFilter(AutomationScript *a_script); - ~AssAutomationFilter(); - - void ProcessSubs(AssFile *subs); - wxWindow *GetConfigDialogWindow(wxWindow *parent); - void LoadSettings(bool IsDefault); - - AutomationScript *GetScript(); - - static const std::list& GetFilterList(); -}; diff --git a/aegisub/auto3/automation_gui.cpp b/aegisub/auto3/automation_gui.cpp deleted file mode 100644 index 5325abd67..000000000 --- a/aegisub/auto3/automation_gui.cpp +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright (c) 2005, Niels Martin Hansen -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------------- -// -// AEGISUB -// -// Website: http://aegisub.cellosoft.com -// Contact: mailto:zeratul@cellosoft.com -// - -#include -#include -#include -#include -#include -#include "automation_gui.h" -#include "options.h" - - -DialogAutomationManager::DialogAutomationManager(wxWindow *parent, SubtitlesGrid *grid) -: wxDialog(parent, -1, _("Automation Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE, _T("AutoMan")) -{ - subgrid = grid; - - // create main controls - script_list = new wxListView(this, AUTOMAN_SCRIPTLIST, wxDefaultPosition, wxSize(600, 175), wxLC_REPORT|wxLC_SINGLE_SEL); - create_button = new wxButton(this, AUTOMAN_CREATE, _("&Create...")); - add_button = new wxButton(this, AUTOMAN_ADD, _("&Add...")); - remove_button = new wxButton(this, AUTOMAN_REMOVE, _("&Remove")); - test_button = new wxButton(this, AUTOMAN_APPLY, _("&Apply now")); - edit_button = new wxButton(this, AUTOMAN_EDIT, _("&Edit...")); - reload_button = new wxButton(this, AUTOMAN_RELOAD, _("Rel&oad")); - close_button = new wxButton(this, wxID_CLOSE, _("C&lose")); - - // add headers to list view - script_list->InsertColumn(0, _("Script name"), wxLIST_FORMAT_LEFT, 140); - script_list->InsertColumn(1, _("File"), wxLIST_FORMAT_LEFT, 100); - //script_list->InsertColumn(2, _("Flags"), wxLIST_FORMAT_LEFT, 45); - script_list->InsertColumn(2, _("Description"), wxLIST_FORMAT_LEFT, 350); - - // button layout - wxSizer *button_box = new wxBoxSizer(wxHORIZONTAL); - button_box->AddStretchSpacer(2); - button_box->Add(create_button, 0); - button_box->Add(add_button, 0); - button_box->Add(remove_button, 0); - button_box->AddSpacer(10); - button_box->Add(test_button, 0); - button_box->AddSpacer(10); - button_box->Add(edit_button, 0); - button_box->Add(reload_button, 0); - button_box->AddSpacer(10); - button_box->Add(close_button, 0); - button_box->AddStretchSpacer(2); - - // main layout - wxSizer *main_box = new wxBoxSizer(wxVERTICAL); - main_box->Add(script_list, 1, wxEXPAND|wxALL, 5); - main_box->Add(button_box, 0, wxEXPAND|wxALL&~wxTOP, 5); - main_box->SetSizeHints(this); - SetSizer(main_box); - Center(); - - // fill the list view - std::list::const_iterator f = AssAutomationFilter::GetFilterList().begin(); - for (;f != AssAutomationFilter::GetFilterList().end(); ++f) { - AddScriptToList(*f); - } - - UpdateDisplay(); -} - - -DialogAutomationManager::~DialogAutomationManager() -{ -} - - -BEGIN_EVENT_TABLE(DialogAutomationManager,wxDialog) - EVT_BUTTON(AUTOMAN_CREATE,DialogAutomationManager::OnCreate) - EVT_BUTTON(AUTOMAN_ADD,DialogAutomationManager::OnAdd) - EVT_BUTTON(AUTOMAN_REMOVE,DialogAutomationManager::OnRemove) - EVT_BUTTON(AUTOMAN_APPLY,DialogAutomationManager::OnApply) - EVT_BUTTON(AUTOMAN_EDIT,DialogAutomationManager::OnEdit) - EVT_BUTTON(AUTOMAN_RELOAD,DialogAutomationManager::OnReload) - EVT_BUTTON(wxID_CLOSE,DialogAutomationManager::OnClose) - EVT_LIST_ITEM_SELECTED(AUTOMAN_SCRIPTLIST,DialogAutomationManager::OnSelectionChange) - EVT_LIST_ITEM_DESELECTED(AUTOMAN_SCRIPTLIST,DialogAutomationManager::OnSelectionChange) -END_EVENT_TABLE() - - -void DialogAutomationManager::OnCreate(wxCommandEvent &event) -{ - wxString path = Options.AsText(_T("Last open automation path")); - wxString sfnames = wxFileSelector(_("Create Automation script"), path, _T("*.lua"), _T("lua"), _T("Automation Lua scripts (*.lua)|*.lua|All files (*.*)|*.*"), wxSAVE|wxOVERWRITE_PROMPT, this); - if (sfnames.empty()) return; - Options.SetText(_T("Last open automation path"), sfnames); - - wxFileName sfname(sfnames); - - if (sfname.FileExists()) { - if (!wxRemoveFile(sfnames)) { - wxMessageBox(_T("The old file by this name could not be deleted."), _T("Error creating Automation script"), wxOK|wxICON_ERROR, this); - return; - } - } - - wxTextFile file; - file.Create(sfnames); - file.AddLine(_T("-- Aegisub Automation script")); - file.AddLine(_T("")); - file.AddLine(_T("-- You should change these two lines")); - file.AddLine(wxString::Format(_T("name = \"%s\""), sfname.GetName().c_str())); - file.AddLine(_T("description = \"New Automation script\"")); - file.AddLine(_T("")); - file.AddLine(_T("-- Enter the configuration settings here, if needed. Refer to the manual for details")); - file.AddLine(_T("configuration = {}")); - file.AddLine(_T("")); - file.AddLine(_T("-- You should NOT change this line!")); - file.AddLine(_T("version, kind = 3, 'basic_ass'")); - file.AddLine(_T("")); - file.AddLine(_T("-- You should write your script in this function (don't change its name!)")); - file.AddLine(_T("function process_lines(meta, styles, lines, config)")); - file.AddLine(_T("\t-- For now, just return the subtitles as-is, no changes")); - file.AddLine(_T("\treturn lines")); - file.AddLine(_T("end")); - file.AddLine(_T("")); - file.Write(wxTextFileType_None, wxConvUTF8); - file.Close(); - - AutomationScriptFile *sfile = AutomationScriptFile::CreateFromFile(sfnames); - AutomationScript *script = new AutomationScript(sfile); - AssAutomationFilter *filter = new AssAutomationFilter(script); - AddScriptToList(filter); - delete sfile; - - EditScript(script); -} - - -void DialogAutomationManager::OnAdd(wxCommandEvent &event) -{ - wxString path = Options.AsText(_T("Last open automation path")); - wxString sfnames = wxFileSelector(_("Load Automation script"), path, _T("*.lua"), _T("lua"), _T("Automation Lua scripts (*.lua)|*.lua|All files (*.*)|*.*"), wxOPEN|wxFILE_MUST_EXIST, this); - if (sfnames.empty()) return; - Options.SetText(_T("Last open automation path"), sfnames); - - try { - AutomationScriptFile *sfile = AutomationScriptFile::CreateFromFile(sfnames); - AutomationScript *script = new AutomationScript(sfile); - AssAutomationFilter *filter = new AssAutomationFilter(script); - wxString script_settings = subgrid->ass->GetScriptInfo(wxString::Format(_T("Automation Settings %s"), wxFileName(sfnames).GetFullName().c_str())); - script->configuration.unserialize(script_settings); - AddScriptToList(filter); - delete sfile; - } - catch (AutomationError &err) { - wxMessageBox(wxString::Format(_T("Error loading Automation script '%s':\r\n\r\n%s"), sfnames.c_str(), err.message.c_str()), _T("Error loading Automation script"), wxOK | wxICON_ERROR, this); - } - catch (wxString &err) { - wxMessageBox(wxString::Format(_T("Error loading Automation script %s:\r\n\r\n%s"), sfnames.c_str(), err.c_str()), _T("Error loading Automation script"), wxOK|wxICON_ERROR, this); - } - catch (const wchar_t *err) { - wxMessageBox(wxString::Format(_T("Error loading Automation script %s:\r\n\r\n%s"), sfnames.c_str(), err), _T("Error loading Automation script"), wxOK|wxICON_ERROR, this); - } - catch (...) { - wxMessageBox(_T("Unknown error loading Automation script."), _T("Error loading Automation script"), wxOK | wxICON_ERROR, this); - } -} - - -void DialogAutomationManager::OnRemove(wxCommandEvent &event) -{ - // assume only one item can be selected at a time... - // removing multiple scripts might be disasterous (for the user) anyway - // TODO: ask for confirmation if script supports configuration - int selid = script_list->GetFirstSelected(); - AssAutomationFilter *filter = (AssAutomationFilter*)script_list->GetItemData(selid); - script_list->DeleteItem(selid); - AutomationScript *script = filter->GetScript(); - delete filter; - delete script; - UpdateDisplay(); -} - - -void DialogAutomationManager::OnApply(wxCommandEvent &event) -{ - int selid = script_list->GetFirstSelected(); - AssAutomationFilter *filter = (AssAutomationFilter*)script_list->GetItemData(selid); - // Attempt to make a config window, if needed - { - wxDialog *dlg = new wxDialog(this, -1, filter->GetScript()->name, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE, _T("AutomationScriptConfigDlg")); - try { - wxWindow *config_frame = filter->GetConfigDialogWindow(dlg); - if (!config_frame) { - delete dlg; - goto skip_config; - } - wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(config_frame, 0, wxALL, 7); - wxButton *ok = new wxButton(dlg, wxID_OK); - wxButton *cancel = new wxButton(dlg, wxID_CANCEL); - wxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL); - button_sizer->Add(ok, 0, wxALL, 7); - button_sizer->Add(cancel, 0, wxALL&~wxLEFT, 7); - main_sizer->Add(button_sizer, wxALIGN_CENTER); - dlg->SetSizer(main_sizer); - main_sizer->SetSizeHints(dlg); - dlg->Layout(); - switch (dlg->ShowModal()) { - case wxID_OK: - filter->LoadSettings(false); - delete dlg; - break; - case wxID_CANCEL: - delete dlg; - return; - default: - wxLogWarning(_T("Config dialog returned an unexpected value. This shouldn't happen. Please report to a dev.")); - delete dlg; - return; - } - } - catch (...) { - delete dlg; - wxLogError(_T("Error while working on Automation script config dialog. This shouldn't happen. Please report to a dev.")); - return; - } - } -skip_config: - // Now apply script - filter->ProcessSubs(subgrid->ass); - subgrid->LoadFromAss(); - script_list->Select(selid, false); - UpdateDisplay(); -} - - -void DialogAutomationManager::OnEdit(wxCommandEvent &event) -{ - int selid = script_list->GetFirstSelected(); - AssAutomationFilter *filter = (AssAutomationFilter*)script_list->GetItemData(selid); - AutomationScript *script = filter->GetScript(); - EditScript(script); -} - - -void DialogAutomationManager::OnReload(wxCommandEvent &event) -{ - int selid = script_list->GetFirstSelected(); - AssAutomationFilter *filter = (AssAutomationFilter*)script_list->GetItemData(selid); - AutomationScript *script = filter->GetScript(); - wxFileName sfname(script->filename); - if (sfname.FileExists()) { - AutomationScript *newscript; - try { - AutomationScriptFile *sfile = AutomationScriptFile::CreateFromFile(sfname.GetFullPath()); - newscript = new AutomationScript(sfile); - delete sfile; - } - catch (AutomationError &err) { - wxMessageBox(wxString::Format(_T("Error reloading Automation script '%s'.\r\nThe old version has been retained.\r\n\r\n%s"), sfname.GetFullPath().c_str(), err.message.c_str()), _T("Error reloading Automation script"), wxOK | wxICON_ERROR, this); - return; - } - newscript->configuration = script->configuration; - delete filter; - delete script; - AssAutomationFilter *newfilter = new AssAutomationFilter(newscript); - script_list->DeleteItem(selid); - AddScriptToList(newfilter); - script_list->Select(0); - } else { - wxMessageBox(_T("The script file could not be found on disk. If you want to remove the script, please use the Remove button."), _T("Error reloading Automation script"), wxOK|wxICON_EXCLAMATION, this); - } -} - - -void DialogAutomationManager::OnClose(wxCommandEvent &event) -{ - EndModal(0); -} - - -void DialogAutomationManager::OnSelectionChange(wxListEvent &event) -{ - UpdateDisplay(); -} - - -void DialogAutomationManager::UpdateDisplay() -{ - bool script_selected = script_list->GetSelectedItemCount() > 0; - // enable/disable buttons - create_button->Enable(true); - add_button->Enable(true); - remove_button->Enable(script_selected); - test_button->Enable(script_selected); - edit_button->Enable(script_selected); - reload_button->Enable(script_selected); - close_button->Enable(true); -} - - -void DialogAutomationManager::AddScriptToList(AssAutomationFilter *filter) -{ - wxFileName fn(filter->GetScript()->filename); - wxListItem item; - item.SetText(filter->GetScript()->name); - item.SetData(filter); - int i = script_list->InsertItem(item); - script_list->SetItem(i, 1, fn.GetFullName()); - //script_list->SetItem(i, 2, _T("")); // Flags - unused - script_list->SetItem(i, 2, filter->GetScript()->description); -} - -void DialogAutomationManager::EditScript(AutomationScript *script) -{ - if (!script) { - wxMessageBox(_T("DialogAutomationManager::EditScript() called without a valid script object. Sloppy programming? You can probably blame jfs."), _T("Blame Canada!"), wxOK|wxICON_ERROR); - return; - } - - wxFileName sfname(script->filename); - if (!sfname.FileExists()) { - wxMessageBox(_T("The script file \"%s\" does not exist, and thus cannot be edited."), _T("Automation warning"), wxOK|wxICON_WARNING); - return; - } - - wxString editor; - if (!Options.IsDefined(_T("automation script editor")) || wxGetKeyState(WXK_SHIFT)) { - wxMessageBox(_T("You have not selected a script editor yet. Please select your script editor in the next window. It's recommended to use an editor with syntax highlighting for Lua scripts."), _T("Aegisub"), wxOK|wxICON_INFORMATION); -#if defined(__WINDOWS__) - editor = wxFileSelector(_T("Select script editor"), _T(""), _T("C:\\Windows\\Notepad.exe"), _T("exe"), _T("Execatuables (*.exe)|*.exe|All files (*.*)|*.*"), wxOPEN|wxFILE_MUST_EXIST); -#elif defined(__APPLE__) - editor = wxFileSelector(_T("Select script editor"), _T(""), _T("/Applications/TextEdit.app"), _T("app"), _T("Applications (*.app)|*.app|All files (*.*)|*.*"), wxOPEN|wxFILE_MUST_EXIST); -#else - char *env_editor = getenv("EDITOR"); - wxString editor(env_editor ? env_editor : "/usr/bin/gvim", wxConvLocal); - editor = wxFileSelector(_T("Select script editor"), _T(""), editor, _T(""), _T("All files (*)|*"), wxOPEN|wxFILE_MUST_EXIST); -#endif - if (editor.empty()) return; - Options.SetText(_T("automation script editor"), editor); - Options.Save(); - } else { - editor = Options.AsText(_T("automation script editor")); - } - - wxWCharBuffer editorbuf = editor.c_str(), sfnamebuf = sfname.GetFullPath().c_str(); - wchar_t **cmdline = new wchar_t*[5]; -#ifndef __APPLE__ - cmdline[0] = editorbuf.data(); - cmdline[1] = sfnamebuf.data(); - cmdline[2] = 0; -#else - cmdline[0] = _T("/usr/bin/open"); - cmdline[1] = _T("-a"); - cmdline[2] = editorbuf.data(); - cmdline[3] = sfnamebuf.data(); - cmdline[4] = 0; -#endif - long res = wxExecute(cmdline); - delete cmdline; - - if (!res) { - wxMessageBox(_T("Some error occurred trying to launch the external editor. Sorry!"), _T("Automation Error"), wxOK|wxICON_ERROR); - } -} - diff --git a/aegisub/auto3/automation_gui.h b/aegisub/auto3/automation_gui.h deleted file mode 100644 index dcb7f192b..000000000 --- a/aegisub/auto3/automation_gui.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2005, Niels Martin Hansen -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// ----------------------------------------------------------------------------- -// -// AEGISUB -// -// Website: http://aegisub.cellosoft.com -// Contact: mailto:zeratul@cellosoft.com -// - -#pragma once - -#include -#include -#include "subs_grid.h" -#include "automation_filter.h" - - -class DialogAutomationManager : public wxDialog { -private: - wxListView *script_list; - wxButton *create_button; - wxButton *add_button; - wxButton *remove_button; - wxButton *test_button; - wxButton *edit_button; - wxButton *reload_button; - wxButton *close_button; - - SubtitlesGrid *subgrid; - - void OnCreate(wxCommandEvent &event); - void OnAdd(wxCommandEvent &event); - void OnRemove(wxCommandEvent &event); - void OnApply(wxCommandEvent &event); - void OnEdit(wxCommandEvent &event); - void OnReload(wxCommandEvent &event); - void OnClose(wxCommandEvent &event); - void OnSelectionChange(wxListEvent &event); - - void UpdateDisplay(); - void AddScriptToList(AssAutomationFilter *filter); - -public: - DialogAutomationManager(wxWindow *parent, SubtitlesGrid *grid); - ~DialogAutomationManager(); - - static void EditScript(AutomationScript *script); - - DECLARE_EVENT_TABLE() -}; - -enum { - AUTOMAN_SCRIPTLIST = 3200, - AUTOMAN_CREATE, - AUTOMAN_ADD, - AUTOMAN_REMOVE, - AUTOMAN_APPLY, - AUTOMAN_EDIT, - AUTOMAN_RELOAD, - AUTOMAN_CLOSE -}; diff --git a/aegisub/subs_grid.cpp b/aegisub/subs_grid.cpp index eebeec33f..d6951cc70 100644 --- a/aegisub/subs_grid.cpp +++ b/aegisub/subs_grid.cpp @@ -863,6 +863,7 @@ void SubtitlesGrid::InsertLine(AssDialogue *line,int n,bool after,bool update) { if (update) { ass->FlagAsModified(_("line insertion")); CommitChanges(); + AdjustScrollbar(); } }