2006-01-16 22:02:54 +01:00
|
|
|
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
2010-06-24 03:24:43 +02:00
|
|
|
// Copyright (c) 2010, Thomas Goyne <plorkyeran@aegisub.org>
|
2006-01-16 22:02:54 +01:00
|
|
|
// 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.
|
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// Aegisub Project http://www.aegisub.org/
|
|
|
|
|
|
|
|
/// @file ass_override.cpp
|
|
|
|
/// @brief Parse and modify ASSA style overrides
|
|
|
|
/// @ingroup subs_storage
|
|
|
|
///
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2009-01-04 07:31:48 +01:00
|
|
|
#include "config.h"
|
|
|
|
|
2010-06-09 01:21:39 +02:00
|
|
|
#include <libaegisub/log.h>
|
|
|
|
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "ass_dialogue.h"
|
|
|
|
#include "ass_override.h"
|
2012-12-10 23:19:28 +01:00
|
|
|
#include "compat.h"
|
2010-06-24 03:24:43 +02:00
|
|
|
#include "utils.h"
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2012-12-07 17:06:03 +01:00
|
|
|
#include <boost/algorithm/string/join.hpp>
|
|
|
|
#include <boost/range/adaptor/filtered.hpp>
|
|
|
|
#include <boost/range/adaptor/transformed.hpp>
|
|
|
|
#include <functional>
|
|
|
|
#include <wx/log.h>
|
|
|
|
#include <wx/tokenzr.h>
|
|
|
|
|
|
|
|
using namespace boost::adaptors;
|
|
|
|
|
2012-12-10 23:19:28 +01:00
|
|
|
AssOverrideParameter::AssOverrideParameter(VariableDataType type, AssParameterClass classification)
|
|
|
|
: type(type)
|
|
|
|
, classification(classification)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
AssOverrideParameter::AssOverrideParameter(AssOverrideParameter&& o)
|
|
|
|
: value(std::move(o.value))
|
|
|
|
, block(std::move(o.block))
|
|
|
|
, type(o.type)
|
|
|
|
, classification(o.classification)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
AssOverrideParameter::~AssOverrideParameter() {
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> wxString AssOverrideParameter::Get<wxString>() const {
|
|
|
|
if (omitted) throw agi::InternalError("AssOverrideParameter::Get() called on omitted parameter", 0);
|
|
|
|
if (block.get()) {
|
|
|
|
wxString str(block->GetText());
|
|
|
|
str.Replace("{", "");
|
|
|
|
str.Replace("}", "");
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> int AssOverrideParameter::Get<int>() const {
|
|
|
|
long v = 0;
|
|
|
|
Get<wxString>().ToLong(&v);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> double AssOverrideParameter::Get<double>() const {
|
|
|
|
double v = 0;
|
|
|
|
Get<wxString>().ToDouble(&v);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> float AssOverrideParameter::Get<float>() const {
|
|
|
|
return Get<double>();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> bool AssOverrideParameter::Get<bool>() const {
|
|
|
|
return Get<int>() != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> agi::Color AssOverrideParameter::Get<agi::Color>() const {
|
|
|
|
return from_wx(Get<wxString>());
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> AssDialogueBlockOverride *AssOverrideParameter::Get<AssDialogueBlockOverride*>() const {
|
|
|
|
if (!block.get()) {
|
|
|
|
block.reset(new AssDialogueBlockOverride(Get<wxString>()));
|
|
|
|
block->ParseTags();
|
|
|
|
}
|
|
|
|
return block.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> void AssOverrideParameter::Set<wxString>(wxString new_value) {
|
|
|
|
omitted = false;
|
|
|
|
value = new_value;
|
|
|
|
block.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> void AssOverrideParameter::Set<int>(int new_value) {
|
|
|
|
Set(wxString::Format("%d", new_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> void AssOverrideParameter::Set<double>(double new_value) {
|
|
|
|
Set(wxString::Format("%g", new_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<> void AssOverrideParameter::Set<bool>(bool new_value) {
|
|
|
|
Set<int>(new_value);
|
|
|
|
}
|
|
|
|
|
2012-12-10 00:40:28 +01:00
|
|
|
namespace {
|
|
|
|
/// The parameter is absent unless the total number of parameters is the
|
|
|
|
/// indicated number. Note that only arguments not at the end need to be marked
|
|
|
|
/// as optional; this is just to know which parameters to skip when there are
|
|
|
|
/// earlier optional arguments
|
|
|
|
enum AssParameterOptional {
|
|
|
|
NOT_OPTIONAL = 0xFF,
|
|
|
|
OPTIONAL_1 = 0x01,
|
|
|
|
OPTIONAL_2 = 0x02,
|
|
|
|
OPTIONAL_3 = 0x04,
|
|
|
|
OPTIONAL_4 = 0x08,
|
|
|
|
OPTIONAL_5 = 0x10,
|
|
|
|
OPTIONAL_6 = 0x20,
|
|
|
|
OPTIONAL_7 = 0x40
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Prototype of a single override parameter
|
|
|
|
struct AssOverrideParamProto {
|
|
|
|
/// ASS_ParameterOptional
|
|
|
|
int optional;
|
|
|
|
|
|
|
|
/// Type of this parameter
|
|
|
|
VariableDataType type;
|
|
|
|
|
|
|
|
/// Semantic type of this parameter
|
|
|
|
AssParameterClass classification;
|
|
|
|
|
|
|
|
AssOverrideParamProto (VariableDataType type, int opt=NOT_OPTIONAL, AssParameterClass classi=PARCLASS_NORMAL);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct AssOverrideTagProto {
|
|
|
|
/// Name of the tag, with slash
|
|
|
|
wxString name;
|
|
|
|
/// Parameters to this tag
|
|
|
|
std::vector<AssOverrideParamProto> params;
|
|
|
|
typedef std::vector<AssOverrideTagProto>::iterator iterator;
|
|
|
|
|
|
|
|
/// @brief Add a parameter to this tag prototype
|
|
|
|
/// @param type Data type of the parameter
|
|
|
|
/// @param classi Semantic type of the parameter
|
|
|
|
/// @param opt Situations in which this parameter is present
|
|
|
|
void AddParam(VariableDataType type, AssParameterClass classi = PARCLASS_NORMAL, int opt = NOT_OPTIONAL);
|
|
|
|
/// @brief Convenience function for single-argument tags
|
|
|
|
/// @param name Name of the tag, with slash
|
|
|
|
/// @param type Data type of the parameter
|
|
|
|
/// @param classi Semantic type of the parameter
|
|
|
|
/// @param opt Situations in which this parameter is present
|
|
|
|
void Set(wxString name, VariableDataType type, AssParameterClass classi = PARCLASS_NORMAL, int opt = NOT_OPTIONAL);
|
|
|
|
};
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
|
2012-12-09 17:06:10 +01:00
|
|
|
AssOverrideParamProto::AssOverrideParamProto(VariableDataType type, int opt, AssParameterClass classi)
|
2010-08-02 22:25:29 +02:00
|
|
|
: optional(opt)
|
|
|
|
, type(type)
|
2010-06-24 03:24:43 +02:00
|
|
|
, classification(classi)
|
|
|
|
{
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2012-10-12 03:52:36 +02:00
|
|
|
void AssOverrideTagProto::AddParam(VariableDataType type, AssParameterClass classi, int opt) {
|
2012-11-28 16:35:26 +01:00
|
|
|
params.emplace_back(type, opt, classi);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2012-11-28 16:35:26 +01:00
|
|
|
|
2012-10-12 03:52:36 +02:00
|
|
|
void AssOverrideTagProto::Set(wxString newName, VariableDataType type, AssParameterClass classi, int opt) {
|
2010-06-24 03:24:43 +02:00
|
|
|
name = newName;
|
2012-11-28 16:35:26 +01:00
|
|
|
params.emplace_back(type, opt, classi);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2010-06-24 03:24:43 +02:00
|
|
|
static std::vector<AssOverrideTagProto> proto;
|
|
|
|
static void load_protos() {
|
|
|
|
static bool loaded = false;
|
2006-01-16 22:02:54 +01:00
|
|
|
if (loaded) return;
|
|
|
|
loaded = true;
|
|
|
|
|
2010-06-04 05:07:58 +02:00
|
|
|
proto.resize(56);
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
// Longer tag names must appear before shorter tag names
|
|
|
|
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[0].Set("\\alpha", VARDATA_TEXT); // \alpha
|
|
|
|
proto[++i].Set("\\bord", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \bord<depth>
|
|
|
|
proto[++i].Set("\\xbord", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \xbord<depth>
|
|
|
|
proto[++i].Set("\\ybord", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \ybord<depth>
|
|
|
|
proto[++i].Set("\\shad", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \shad<depth>
|
|
|
|
proto[++i].Set("\\xshad", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \xshad<depth>
|
|
|
|
proto[++i].Set("\\yshad", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \yshad<depth>
|
2012-03-25 06:05:06 +02:00
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
// \fade(<a1>,<a2>,<a3>,<t1>,<t2>,<t3>,<t4>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\fade";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_INT);
|
|
|
|
proto[i].AddParam(VARDATA_INT);
|
|
|
|
proto[i].AddParam(VARDATA_INT);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// \move(<x1>,<y1>,<x2>,<y2>[,<t1>,<t2>])
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\move";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_X);
|
|
|
|
proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_Y);
|
|
|
|
proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_X);
|
|
|
|
proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_Y);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
|
2010-06-04 05:07:58 +02:00
|
|
|
|
|
|
|
// If these are rearranged, keep rect clip and vector clip adjacent in this order
|
2006-01-16 22:02:54 +01:00
|
|
|
// \clip(<x1>,<y1>,<x2>,<y2>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\clip";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// \clip([<scale>,]<some drawings>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\clip";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_NORMAL,OPTIONAL_2);
|
|
|
|
proto[i].AddParam(VARDATA_TEXT,PARCLASS_DRAWING);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2008-09-10 18:13:54 +02:00
|
|
|
// \iclip(<x1>,<y1>,<x2>,<y2>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\iclip";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
|
2008-09-10 18:13:54 +02:00
|
|
|
|
|
|
|
// \iclip([<scale>,]<some drawings>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\iclip";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_NORMAL,OPTIONAL_2);
|
|
|
|
proto[i].AddParam(VARDATA_TEXT,PARCLASS_DRAWING);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[++i].Set("\\fscx", VARDATA_FLOAT,PARCLASS_RELATIVE_SIZE_X); // \fscx<percent>
|
|
|
|
proto[++i].Set("\\fscy", VARDATA_FLOAT,PARCLASS_RELATIVE_SIZE_Y); // \fscy<percent>
|
2006-01-16 22:02:54 +01:00
|
|
|
// \pos(<x>,<y>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\pos";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_X);
|
|
|
|
proto[i].AddParam(VARDATA_FLOAT,PARCLASS_ABSOLUTE_POS_Y);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// \org(<x>,<y>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\org";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_X);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[++i].Set("\\pbo", VARDATA_INT,PARCLASS_ABSOLUTE_POS_Y); // \pbo<y>
|
2006-01-16 22:02:54 +01:00
|
|
|
// \fad(<t1>,<t2>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\fad";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_END);
|
|
|
|
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[++i].Set("\\fsp", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \fsp<pixels>
|
|
|
|
proto[++i].Set("\\frx", VARDATA_FLOAT); // \frx<degrees>
|
|
|
|
proto[++i].Set("\\fry", VARDATA_FLOAT); // \fry<degrees>
|
|
|
|
proto[++i].Set("\\frz", VARDATA_FLOAT); // \frz<degrees>
|
|
|
|
proto[++i].Set("\\fr", VARDATA_FLOAT); // \fr<degrees>
|
|
|
|
proto[++i].Set("\\fax", VARDATA_FLOAT); // \fax<factor>
|
|
|
|
proto[++i].Set("\\fay", VARDATA_FLOAT); // \fay<factor>
|
|
|
|
proto[++i].Set("\\1c", VARDATA_TEXT); // \1c&H<bbggrr>&
|
|
|
|
proto[++i].Set("\\2c", VARDATA_TEXT); // \2c&H<bbggrr>&
|
|
|
|
proto[++i].Set("\\3c", VARDATA_TEXT); // \3c&H<bbggrr>&
|
|
|
|
proto[++i].Set("\\4c", VARDATA_TEXT); // \4c&H<bbggrr>&
|
|
|
|
proto[++i].Set("\\1a", VARDATA_TEXT); // \1a&H<aa>&
|
|
|
|
proto[++i].Set("\\2a", VARDATA_TEXT); // \2a&H<aa>&
|
|
|
|
proto[++i].Set("\\3a", VARDATA_TEXT); // \3a&H<aa>&
|
|
|
|
proto[++i].Set("\\4a", VARDATA_TEXT); // \4a&H<aa>&
|
|
|
|
proto[++i].Set("\\fe", VARDATA_TEXT); // \fe<charset>
|
|
|
|
proto[++i].Set("\\ko", VARDATA_INT,PARCLASS_KARAOKE); // \ko<duration>
|
|
|
|
proto[++i].Set("\\kf", VARDATA_INT,PARCLASS_KARAOKE); // \kf<duration>
|
|
|
|
proto[++i].Set("\\be", VARDATA_INT); // \be<strength>
|
|
|
|
proto[++i].Set("\\blur", VARDATA_FLOAT); // \blur<strength>
|
|
|
|
proto[++i].Set("\\fn", VARDATA_TEXT); // \fn<name>
|
|
|
|
proto[++i].Set("\\fs+", VARDATA_FLOAT); // \fs+<size>
|
|
|
|
proto[++i].Set("\\fs-", VARDATA_FLOAT); // \fs-<size>
|
|
|
|
proto[++i].Set("\\fs", VARDATA_FLOAT,PARCLASS_ABSOLUTE_SIZE); // \fs<size>
|
|
|
|
proto[++i].Set("\\an", VARDATA_INT); // \an<alignment>
|
|
|
|
proto[++i].Set("\\c", VARDATA_TEXT); // \c&H<bbggrr>&
|
|
|
|
proto[++i].Set("\\b", VARDATA_INT); // \b<0/1/weight>
|
|
|
|
proto[++i].Set("\\i", VARDATA_BOOL); // \i<0/1>
|
|
|
|
proto[++i].Set("\\u", VARDATA_BOOL); // \u<0/1>
|
|
|
|
proto[++i].Set("\\s", VARDATA_BOOL); // \s<0/1>
|
|
|
|
proto[++i].Set("\\a", VARDATA_INT); // \a<alignment>
|
|
|
|
proto[++i].Set("\\k", VARDATA_INT,PARCLASS_KARAOKE); // \k<duration>
|
|
|
|
proto[++i].Set("\\K", VARDATA_INT,PARCLASS_KARAOKE); // \K<duration>
|
|
|
|
proto[++i].Set("\\q", VARDATA_INT); // \q<0-3>
|
|
|
|
proto[++i].Set("\\p", VARDATA_INT); // \p<n>
|
|
|
|
proto[++i].Set("\\r", VARDATA_TEXT); // \r[<name>]
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// \t([<t1>,<t2>,][<accel>,]<style modifiers>)
|
2010-06-04 05:07:58 +02:00
|
|
|
i++;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto[i].name = "\\t";
|
2010-06-24 03:24:43 +02:00
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START,OPTIONAL_3 | OPTIONAL_4);
|
|
|
|
proto[i].AddParam(VARDATA_INT,PARCLASS_RELATIVE_TIME_START,OPTIONAL_3 | OPTIONAL_4);
|
|
|
|
proto[i].AddParam(VARDATA_FLOAT,PARCLASS_NORMAL,OPTIONAL_2 | OPTIONAL_4);
|
|
|
|
proto[i].AddParam(VARDATA_BLOCK);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2010-06-24 03:24:43 +02:00
|
|
|
std::vector<wxString> tokenize(const wxString &text) {
|
|
|
|
std::vector<wxString> paramList;
|
2010-06-04 05:07:58 +02:00
|
|
|
paramList.reserve(6);
|
2006-01-29 23:46:18 +01:00
|
|
|
|
2012-12-10 00:40:28 +01:00
|
|
|
if (text.empty())
|
2010-06-24 03:24:43 +02:00
|
|
|
return paramList;
|
2012-12-10 00:40:28 +01:00
|
|
|
|
2011-09-28 21:43:11 +02:00
|
|
|
if (text[0] != '(') {
|
2010-06-24 03:24:43 +02:00
|
|
|
// There's just one parameter (because there's no parentheses)
|
|
|
|
// This means text is all our parameters
|
|
|
|
wxString param(text);
|
|
|
|
paramList.push_back(param.Trim(true).Trim(false));
|
|
|
|
return paramList;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ok, so there are parentheses used here, so there may be more than one parameter
|
|
|
|
// Enter fullscale parsing!
|
|
|
|
size_t i = 0, textlen = text.size();
|
|
|
|
size_t start = 0;
|
|
|
|
int parDepth = 1;
|
|
|
|
while (i < textlen && parDepth > 0) {
|
|
|
|
// Just skip until next ',' or ')', whichever comes first
|
|
|
|
// (Next ')' is achieved when parDepth == 0)
|
|
|
|
start = ++i;
|
2006-01-29 23:46:18 +01:00
|
|
|
while (i < textlen && parDepth > 0) {
|
2010-06-24 03:24:43 +02:00
|
|
|
wxChar c = text[i];
|
|
|
|
// parDepth 1 is where we start, and the tag-level we're interested in parsing on
|
2011-09-28 21:43:11 +02:00
|
|
|
if (c == ',' && parDepth == 1) break;
|
|
|
|
if (c == '(') parDepth++;
|
|
|
|
else if (c == ')') {
|
2010-06-24 03:24:43 +02:00
|
|
|
parDepth--;
|
|
|
|
if (parDepth < 0) {
|
2011-09-28 21:43:48 +02:00
|
|
|
wxLogWarning("Unmatched parenthesis near '%s'!\nTag-parsing incomplete.", text.SubString(i, 10));
|
2010-06-24 03:24:43 +02:00
|
|
|
return paramList;
|
|
|
|
}
|
|
|
|
else if (parDepth == 0) {
|
|
|
|
// We just ate the parenthesis ending this parameter block
|
|
|
|
// Make sure it doesn't get included in the parameter text
|
|
|
|
break;
|
2006-01-29 23:46:18 +01:00
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2010-06-24 03:24:43 +02:00
|
|
|
i++;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2010-06-24 03:24:43 +02:00
|
|
|
// i now points to the first character not member of this parameter
|
|
|
|
paramList.push_back(text.SubString(start, i-1).Trim(true).Trim(false));
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2010-06-24 03:24:43 +02:00
|
|
|
|
|
|
|
if (i+1 < textlen) {
|
|
|
|
// There's some additional garbage after the parentheses
|
|
|
|
// Just add it in for completeness
|
|
|
|
paramList.push_back(text.Mid(i+1));
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2010-06-24 03:24:43 +02:00
|
|
|
return paramList;
|
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2012-12-10 00:40:28 +01:00
|
|
|
void parse_parameters(AssOverrideTag *tag, const wxString &text, AssOverrideTagProto::iterator proto_it) {
|
|
|
|
tag->Clear();
|
2010-06-24 03:24:43 +02:00
|
|
|
|
|
|
|
// Tokenize text, attempting to find all parameters
|
|
|
|
std::vector<wxString> paramList = tokenize(text);
|
|
|
|
size_t totalPars = paramList.size();
|
|
|
|
|
|
|
|
int parsFlag = 1 << (totalPars - 1); // Get optional parameters flag
|
2011-12-26 23:20:49 +01:00
|
|
|
// vector (i)clip is the second clip proto_ittype in the list
|
2012-12-10 00:40:28 +01:00
|
|
|
if ((tag->Name == "\\clip" || tag->Name == "\\iclip") && totalPars != 4) {
|
2011-12-26 23:20:49 +01:00
|
|
|
++proto_it;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2006-01-17 08:52:18 +01:00
|
|
|
|
2010-06-24 03:24:43 +02:00
|
|
|
unsigned curPar = 0;
|
2012-11-04 04:53:03 +01:00
|
|
|
for (auto& curproto : proto_it->params) {
|
2006-01-16 22:02:54 +01:00
|
|
|
// Create parameter
|
2012-12-10 23:19:28 +01:00
|
|
|
tag->Params.emplace_back(curproto.type, curproto.classification);
|
2012-12-10 00:40:28 +01:00
|
|
|
AssOverrideParameter *newparam = &tag->Params.back();
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2010-06-24 03:24:43 +02:00
|
|
|
// Check if it's optional and not present
|
2012-12-09 19:36:13 +01:00
|
|
|
if (!(curproto.optional & parsFlag) || curPar >= totalPars)
|
2010-06-24 03:24:43 +02:00
|
|
|
continue;
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2012-12-10 23:19:28 +01:00
|
|
|
tag->Params.back().Set(paramList[curPar++]);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-10 00:40:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// From ass_dialogue.h
|
|
|
|
AssDialogueBlockOverride::~AssDialogueBlockOverride() {
|
|
|
|
delete_clear(Tags);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssDialogueBlockOverride::ParseTags() {
|
|
|
|
delete_clear(Tags);
|
|
|
|
|
|
|
|
wxStringTokenizer tkn(text, "\\", wxTOKEN_STRTOK);
|
|
|
|
wxString curTag;
|
|
|
|
if (text.StartsWith("\\")) curTag = "\\";
|
|
|
|
|
|
|
|
while (tkn.HasMoreTokens()) {
|
|
|
|
curTag += tkn.GetNextToken();
|
|
|
|
|
|
|
|
// Check for parenthesis matching for \t
|
2012-12-10 23:19:28 +01:00
|
|
|
while (curTag.Freq('(') > curTag.Freq(')') && tkn.HasMoreTokens())
|
2012-12-10 00:40:28 +01:00
|
|
|
curTag << "\\" << tkn.GetNextToken();
|
|
|
|
|
|
|
|
Tags.push_back(new AssOverrideTag(curTag));
|
|
|
|
|
|
|
|
curTag = "\\";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void AssDialogueBlockOverride::AddTag(wxString const& tag) {
|
|
|
|
Tags.push_back(new AssOverrideTag(tag));
|
|
|
|
}
|
|
|
|
|
|
|
|
static wxString tag_str(AssOverrideTag *t) { return *t; }
|
|
|
|
wxString AssDialogueBlockOverride::GetText() {
|
|
|
|
text = "{" + join(Tags | transformed(tag_str), wxString()) + "}";
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssDialogueBlockOverride::ProcessParameters(ProcessParametersCallback callback, void *userData) {
|
|
|
|
for (auto tag : Tags) {
|
|
|
|
for (auto& par : tag->Params) {
|
2012-12-10 23:19:28 +01:00
|
|
|
if (par.omitted) continue;
|
2012-12-10 00:40:28 +01:00
|
|
|
|
|
|
|
callback(tag->Name, &par, userData);
|
|
|
|
|
|
|
|
// Go recursive if it's a block parameter
|
|
|
|
if (par.GetType() == VARDATA_BLOCK)
|
|
|
|
par.Get<AssDialogueBlockOverride*>()->ProcessParameters(callback, userData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AssOverrideTag::AssOverrideTag() : valid(false) { }
|
|
|
|
AssOverrideTag::AssOverrideTag(wxString text) {
|
|
|
|
SetText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssOverrideTag::Clear() {
|
|
|
|
Params.clear();
|
|
|
|
Params.reserve(6);
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AssOverrideTag::SetText(const wxString &text) {
|
|
|
|
load_protos();
|
|
|
|
for (AssOverrideTagProto::iterator cur = proto.begin(); cur != proto.end(); ++cur) {
|
|
|
|
if (text.StartsWith(cur->name)) {
|
|
|
|
Name = cur->name;
|
|
|
|
parse_parameters(this, text.Mid(Name.length()), cur);
|
|
|
|
valid = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Junk tag
|
|
|
|
Name = text;
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
|
2012-12-09 17:29:02 +01:00
|
|
|
static wxString param_str(AssOverrideParameter const& p) { return p.Get<wxString>(); }
|
2012-03-20 01:39:10 +01:00
|
|
|
AssOverrideTag::operator wxString() const {
|
2006-01-16 22:02:54 +01:00
|
|
|
wxString result = Name;
|
|
|
|
|
2006-01-29 23:46:18 +01:00
|
|
|
// Determine if it needs parentheses
|
2012-12-07 17:12:35 +01:00
|
|
|
bool parentheses = Params.size() > 1;
|
2011-09-28 21:43:11 +02:00
|
|
|
if (parentheses) result += "(";
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// Add parameters
|
2012-12-07 17:06:03 +01:00
|
|
|
result += join(Params
|
2012-12-10 23:19:28 +01:00
|
|
|
| filtered([](AssOverrideParameter const& p) { return !p.omitted; } )
|
2012-12-07 17:06:03 +01:00
|
|
|
| transformed(param_str),
|
|
|
|
wxS(","));
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2011-09-28 21:43:11 +02:00
|
|
|
if (parentheses) result += ")";
|
2006-01-16 22:02:54 +01:00
|
|
|
return result;
|
|
|
|
}
|