mirror of https://github.com/odrling/Aegisub
752 lines
24 KiB
C++
752 lines
24 KiB
C++
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
|
// 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
|
|
//
|
|
|
|
|
|
////////////
|
|
// Includes
|
|
#include "ass_dialogue.h"
|
|
#include "ass_override.h"
|
|
#include <wx/tokenzr.h>
|
|
#include <wx/log.h>
|
|
|
|
|
|
////////////////////// AssOverrideParameter //////////////////////
|
|
///////////////
|
|
// Constructor
|
|
AssOverrideParameter::AssOverrideParameter () {
|
|
classification = PARCLASS_NORMAL;
|
|
ommited = false;
|
|
}
|
|
|
|
|
|
//////////////
|
|
// Destructor
|
|
AssOverrideParameter::~AssOverrideParameter () {
|
|
DeleteValue();
|
|
}
|
|
|
|
|
|
////////
|
|
// Copy
|
|
void AssOverrideParameter::CopyFrom (const AssOverrideParameter ¶m) {
|
|
switch(param.GetType()) {
|
|
case VARDATA_INT: SetInt(param.AsInt()); break;
|
|
case VARDATA_FLOAT: SetFloat(param.AsFloat()); break;
|
|
case VARDATA_TEXT: SetText(param.AsText()); break;
|
|
case VARDATA_BOOL: SetBool(param.AsBool()); break;
|
|
case VARDATA_COLOUR: SetColour(param.AsColour()); break;
|
|
case VARDATA_BLOCK: SetBlock(param.AsBlock()); break;
|
|
default: DeleteValue();
|
|
}
|
|
classification = param.classification;
|
|
ommited = param.ommited;
|
|
}
|
|
|
|
void AssOverrideParameter::operator= (const AssOverrideParameter ¶m) {
|
|
CopyFrom(param);
|
|
}
|
|
|
|
|
|
////////////////////// AssDialogueBlockOverride //////////////////////
|
|
///////////////
|
|
// Constructor
|
|
AssDialogueBlockOverride::AssDialogueBlockOverride () {
|
|
}
|
|
|
|
|
|
//////////////
|
|
// Destructor
|
|
AssDialogueBlockOverride::~AssDialogueBlockOverride () {
|
|
for (size_t i=0;i<Tags.size();i++) {
|
|
delete Tags[i];
|
|
}
|
|
Tags.clear();
|
|
}
|
|
|
|
|
|
/////////////
|
|
// Read tags
|
|
void AssDialogueBlockOverride::ParseTags () {
|
|
// Clear current vector
|
|
for (size_t i=0;i<Tags.size();i++) {
|
|
delete Tags[i];
|
|
}
|
|
Tags.clear();
|
|
|
|
// Fix parenthesis matching
|
|
while (text.Freq(_T('(')) > text.Freq(_T(')'))) {
|
|
text += _T(")");
|
|
}
|
|
|
|
// Initialize tokenizer
|
|
wxStringTokenizer tkn(text,_T("\\"),wxTOKEN_RET_EMPTY_ALL);
|
|
wxString curTag;
|
|
if (text.StartsWith(_T("\\"))) curTag = _T("\\");
|
|
|
|
while (tkn.HasMoreTokens()) {
|
|
//curTag will always start with a backslash after first loop - see end of loop
|
|
curTag += tkn.GetNextToken();
|
|
if (curTag == _T("\\")) continue;
|
|
|
|
// Check for parenthesis matching
|
|
while (curTag.Freq(_T('(')) > curTag.Freq(_T(')'))) {
|
|
if (!tkn.HasMoreTokens()) {
|
|
wxLogWarning(_T("Unmatched parenthesis! Line contents: ") + parent->Text);
|
|
break;
|
|
}
|
|
curTag << _T("\\") << tkn.GetNextToken();
|
|
}
|
|
|
|
AssOverrideTag *newTag = new AssOverrideTag;
|
|
newTag->SetText(curTag);
|
|
Tags.push_back(newTag);
|
|
|
|
curTag = _T("\\");
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////
|
|
// Get Text representation
|
|
wxString AssDialogueBlockOverride::GetText () {
|
|
text = _T("");
|
|
for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) {
|
|
text += (*cur)->ToString();
|
|
}
|
|
return text;
|
|
}
|
|
|
|
|
|
///////////////////////////////////
|
|
// Process parameters via callback
|
|
void AssDialogueBlockOverride::ProcessParameters(void (*callback)(wxString,int,AssOverrideParameter *,void *),void *userData) {
|
|
AssOverrideTag *curTag;
|
|
AssOverrideParameter *curPar;
|
|
|
|
// Find tags
|
|
for (std::vector<AssOverrideTag*>::iterator cur=Tags.begin();cur!=Tags.end();cur++) {
|
|
int n = 0;
|
|
curTag = *cur;
|
|
|
|
// Find parameters
|
|
for (std::vector<AssOverrideParameter*>::iterator curParam=curTag->Params.begin();curParam!=curTag->Params.end();curParam++) {
|
|
curPar = *curParam;
|
|
|
|
if (curPar->GetType() != VARDATA_NONE && curPar->ommited == false) {
|
|
// Do callback
|
|
(*callback)(curTag->Name,n,curPar,userData);
|
|
|
|
// Go recursive if it's a block parameter
|
|
//if (curPar->classification == VARDATA_BLOCK) {
|
|
if (curPar->GetType() == VARDATA_BLOCK) {
|
|
curPar->AsBlock()->ProcessParameters(callback,userData);
|
|
}
|
|
}
|
|
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////// AssOverrideParamProto //////////////////////////
|
|
///////////////
|
|
// Constructor
|
|
AssOverrideParamProto::AssOverrideParamProto (VariableDataType _type,int opt,ASS_ParameterClass classi) {
|
|
type = _type;
|
|
optional = opt;
|
|
classification = classi;
|
|
}
|
|
|
|
|
|
//////////////
|
|
// Destructor
|
|
AssOverrideParamProto::~AssOverrideParamProto() {
|
|
}
|
|
|
|
|
|
///////////////////////// AssOverrideTagProto //////////////////////////
|
|
///////////////
|
|
// Static vars
|
|
std::list<AssOverrideTagProto> AssOverrideTagProto::proto;
|
|
bool AssOverrideTagProto::loaded = false;
|
|
|
|
|
|
///////////////
|
|
// Constructor
|
|
AssOverrideTagProto::AssOverrideTagProto() {
|
|
}
|
|
|
|
|
|
//////////////
|
|
// Destructor
|
|
AssOverrideTagProto::~AssOverrideTagProto() {
|
|
}
|
|
|
|
|
|
///////////////////
|
|
// Load prototypes
|
|
void AssOverrideTagProto::LoadProtos () {
|
|
if (loaded) return;
|
|
loaded = true;
|
|
|
|
// \alpha
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\alpha");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT));
|
|
|
|
// \bord<depth>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\bord");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
|
|
|
|
// \shad<depth>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\shad");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
|
|
|
|
// \fade(<a1>,<a2>,<a3>,<t1>,<t2>,<t3>,<t4>)
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fade");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START));
|
|
|
|
// \move(<x1>,<y1>,<x2>,<y2>[,<t1>,<t2>])
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\move");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_6,PARCLASS_RELATIVE_TIME_START));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_6,PARCLASS_RELATIVE_TIME_START));
|
|
|
|
// \clip(<x1>,<y1>,<x2>,<y2>)
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\clip");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y));
|
|
|
|
// \clip([<scale>,]<some drawings>)
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\clip");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_2,PARCLASS_NORMAL));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_DRAWING));
|
|
|
|
// \fscx<percent>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fscx");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_RELATIVE_SIZE_X));
|
|
|
|
// \fscy<percent>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fscy");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_RELATIVE_SIZE_Y));
|
|
|
|
// \pos(<x>,<y>)
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\pos");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y));
|
|
|
|
// \org(<x>,<y>)
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\org");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_X));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y));
|
|
|
|
// \pbo<y>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\pbo");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_POS_Y));
|
|
|
|
// \fad(<t1>,<t2>)
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fad");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_START));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_RELATIVE_TIME_END));
|
|
|
|
// \fsp<pixels>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fsp");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
|
|
|
|
// \frx<degrees>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\frx");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \fry<degrees>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fry");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \frz<degrees>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\frz");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \fr<degrees>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fr");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \1c&H<bbggrr>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\1c");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \2c&H<bbggrr>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\2c");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \3c&H<bbggrr>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\3c");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \4c&H<bbggrr>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\4c");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \1a&H<aa>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\1a");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \2a&H<aa>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\2a");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \3a&H<aa>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\3a");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \4a&H<aa>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\4a");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \fe<charset>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fe");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \ko<duration>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\ko");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE));
|
|
|
|
// \kf<duration>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\kf");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE));
|
|
|
|
// \be<0/1>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\be");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_BOOL,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \fn<name>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fn");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \fs<size>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\fs");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,NOT_OPTIONAL,PARCLASS_ABSOLUTE_SIZE));
|
|
|
|
// \an<alignment>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\an");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \c&H<bbggrr>&
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\c");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \b<0/1/weight>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\b");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_1,PARCLASS_NORMAL));
|
|
proto.back().params.back().defaultValue.SetBool(false);
|
|
|
|
// \i<0/1>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\i");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL));
|
|
proto.back().params.back().defaultValue.SetBool(false);
|
|
|
|
// \u<0/1>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\u");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL));
|
|
proto.back().params.back().defaultValue.SetBool(false);
|
|
|
|
// \s<0/1>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\s");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_BOOL,OPTIONAL_1,PARCLASS_NORMAL));
|
|
proto.back().params.back().defaultValue.SetBool(false);
|
|
|
|
// \a<alignment>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\a");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \k<duration>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\k");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE));
|
|
|
|
// \K<duration>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\K");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_KARAOKE));
|
|
|
|
// \q<0-3>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\q");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \p<n>
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\p");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
|
|
// \r[<name>]
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\r");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_TEXT,OPTIONAL_1,PARCLASS_NORMAL));
|
|
|
|
// \t([<t1>,<t2>,][<accel>,]<style modifiers>)
|
|
proto.push_back(AssOverrideTagProto());
|
|
proto.back().name = _T("\\t");
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_3 | OPTIONAL_4,PARCLASS_RELATIVE_TIME_START));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_INT,OPTIONAL_3 | OPTIONAL_4,PARCLASS_RELATIVE_TIME_START));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_FLOAT,OPTIONAL_2 | OPTIONAL_4,PARCLASS_NORMAL));
|
|
proto.back().params.push_back(AssOverrideParamProto(VARDATA_BLOCK,NOT_OPTIONAL,PARCLASS_NORMAL));
|
|
}
|
|
|
|
|
|
//////////////////////// AssOverrideTag //////////////////////////
|
|
///////////////
|
|
// Constructor
|
|
AssOverrideTag::AssOverrideTag () {
|
|
valid = false;
|
|
}
|
|
|
|
|
|
//////////////
|
|
// Destructor
|
|
AssOverrideTag::~AssOverrideTag () {
|
|
Clear();
|
|
}
|
|
|
|
|
|
/////////
|
|
// Clear
|
|
void AssOverrideTag::Clear() {
|
|
for (std::vector<AssOverrideParameter*>::iterator cur=Params.begin();cur!=Params.end();cur++) {
|
|
delete *cur;
|
|
}
|
|
Params.clear();
|
|
valid = false;
|
|
}
|
|
|
|
|
|
////////////////////////////
|
|
// Parses text and sets tag
|
|
void AssOverrideTag::SetText (wxString text) {
|
|
// Determine name
|
|
Name = _T("");
|
|
AssOverrideTagProto *proto;
|
|
for (std::list<AssOverrideTagProto>::iterator cur=AssOverrideTagProto::proto.begin();cur!=AssOverrideTagProto::proto.end();cur++) {
|
|
proto = &(*cur);
|
|
if (text.Left(proto->name.length()) == proto->name) {
|
|
Name = proto->name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Set tag name
|
|
if (!Name.empty()) {
|
|
ParseParameters(text.Mid(Name.length()));
|
|
valid = true;
|
|
}
|
|
|
|
// Junk tag
|
|
else {
|
|
Name = text;
|
|
valid = false;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////
|
|
// Checks if it is valid
|
|
bool AssOverrideTag::IsValid() {
|
|
return valid;
|
|
}
|
|
|
|
|
|
/////////////////////
|
|
// Parses parameters
|
|
void AssOverrideTag::ParseParameters(wxString text) {
|
|
// Clear first
|
|
Clear();
|
|
|
|
// text is all text following the name until the next \ or the end of the override block
|
|
|
|
// Tokenize text, attempting to find all parameters
|
|
wxArrayString paramList;
|
|
wxString work;
|
|
|
|
{
|
|
if (text.IsEmpty() || text[0] != _T('(')) {
|
|
// There's just one (or none at all) parameter (because there's no parantheses)
|
|
// This means text is all our parameters
|
|
paramList.Add(text.Trim(true).Trim(false));
|
|
// Only using goto here to avoid yet another nested block (keeps the code cleaner!)
|
|
goto end_tokenizing;
|
|
}
|
|
|
|
// Ok, so there are parantheses used here, so there may be more than one parameter
|
|
// Enter fullscale parsing!
|
|
size_t i = 0, textlen = text.Length();
|
|
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;
|
|
while (i < textlen && parDepth > 0) {
|
|
if (text[i] == _T('(')) parDepth++;
|
|
if (text[i] == _T(')')) parDepth--;
|
|
// parDepth 1 is where we start, and the tag-level we're interested in parsing on
|
|
if (text[i] == _T(',') && parDepth == 1) break;
|
|
if (parDepth < 0) {
|
|
wxLogWarning(_T("Unmatched parenthesis near '%s'!\nTag-parsing incomplete."), text.SubString(i, 10).c_str());
|
|
goto end_tokenizing;
|
|
}
|
|
if (parDepth == 0) {
|
|
// We just ate the paranthesis ending this parameter block
|
|
// Make sure it doesn't get included in the parameter text
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
// i now points to the first character not member of this parameter
|
|
work = text.SubString(start, i-1);
|
|
work.Trim(true).Trim(false);
|
|
paramList.Add(work);
|
|
//wxLogDebug(_T("Got parameter: %s"), work.c_str());
|
|
}
|
|
|
|
if (i+1 < textlen) {
|
|
// There's some additional garbage after the parantheses
|
|
// Just add it in for completeness
|
|
paramList.Add(text.Mid(i+1));
|
|
}
|
|
}
|
|
// This label is only gone to from inside the previous block, if the tokenizing needs to end early
|
|
end_tokenizing:
|
|
|
|
int curPar = 0;
|
|
size_t totalPars = paramList.GetCount();
|
|
|
|
// Get optional parameters flag
|
|
ASS_ParameterOptional parsFlag = OPTIONAL_0;
|
|
switch (totalPars) {
|
|
case 1: parsFlag = OPTIONAL_1; break;
|
|
case 2: parsFlag = OPTIONAL_2; break;
|
|
case 3: parsFlag = OPTIONAL_3; break;
|
|
case 4: parsFlag = OPTIONAL_4; break;
|
|
case 5: parsFlag = OPTIONAL_5; break;
|
|
case 6: parsFlag = OPTIONAL_6; break;
|
|
case 7: parsFlag = OPTIONAL_7; break;
|
|
}
|
|
|
|
// Find prototype
|
|
bool clipOnce = true;
|
|
AssOverrideTagProto *proto = NULL;
|
|
for (std::list<AssOverrideTagProto>::iterator cur=AssOverrideTagProto::proto.begin();cur!=AssOverrideTagProto::proto.end();cur++) {
|
|
if (Name == (*cur).name) {
|
|
if (Name == _T("\\clip") && totalPars != 4 && clipOnce) {
|
|
clipOnce = false;
|
|
continue;
|
|
}
|
|
proto = &(*cur);
|
|
break;
|
|
}
|
|
}
|
|
if (proto == NULL) {
|
|
throw _T("Couldn't find tag prototype while parsing.");
|
|
}
|
|
|
|
// Get parameters
|
|
size_t n=0;
|
|
wxString curtok = _T("");
|
|
if (curPar < (signed)totalPars) {
|
|
curtok = paramList[curPar];
|
|
curPar++;
|
|
}
|
|
|
|
// For each parameter
|
|
while (n < proto->params.size()) {
|
|
AssOverrideParamProto *curproto = &proto->params[n];
|
|
bool isDefault = false;
|
|
n++;
|
|
|
|
// Create parameter
|
|
AssOverrideParameter *newparam = new AssOverrideParameter;
|
|
|
|
// Check if it's optional and not set (set to default)
|
|
if (!(curproto->optional & parsFlag)) {
|
|
if (curproto->defaultValue.GetType() != VARDATA_NONE) {
|
|
isDefault = true;
|
|
newparam->CopyFrom(curproto->defaultValue);
|
|
}
|
|
newparam->ommited = true;
|
|
// This parameter doesn't really count against the number of parsed parameters,
|
|
// since it's left out. Don't count it.
|
|
curPar--;
|
|
}
|
|
|
|
if (isDefault == false) {
|
|
wxChar firstChar = curtok[0];
|
|
bool notAuto4 = firstChar != _T('!') && firstChar != _T('$') && firstChar != _T('%');
|
|
|
|
// Determine parameter type and set value
|
|
switch (curproto->type) {
|
|
case VARDATA_INT: {
|
|
if (notAuto4) {
|
|
long temp = 0;
|
|
curtok.ToLong(&temp);
|
|
newparam->SetInt(temp);
|
|
}
|
|
else newparam->SetText(curtok);
|
|
break;
|
|
}
|
|
case VARDATA_FLOAT: {
|
|
if (notAuto4) {
|
|
double temp = 0.0;
|
|
curtok.ToDouble(&temp);
|
|
newparam->SetFloat(temp);
|
|
}
|
|
else newparam->SetText(curtok);
|
|
break;
|
|
}
|
|
case VARDATA_TEXT: {
|
|
newparam->SetText(curtok);
|
|
break;
|
|
}
|
|
case VARDATA_BOOL: {
|
|
if (notAuto4) {
|
|
long temp = false;
|
|
curtok.ToLong(&temp);
|
|
newparam->SetBool(temp != 0);
|
|
}
|
|
else newparam->SetText(curtok);
|
|
break;
|
|
}
|
|
case VARDATA_BLOCK: {
|
|
AssDialogueBlockOverride *temp = new AssDialogueBlockOverride;
|
|
temp->text = curtok;
|
|
temp->ParseTags();
|
|
newparam->SetBlock(temp);
|
|
break;
|
|
}
|
|
default: break;
|
|
}
|
|
|
|
// Get next actual parameter
|
|
if (curPar < (signed)totalPars) {
|
|
// Unless this parameter was omitted (in which case the token shouldn't be eaten)
|
|
if (!newparam->ommited) {
|
|
curtok = paramList[curPar];
|
|
}
|
|
curPar++;
|
|
}
|
|
else curtok = _T("");
|
|
}
|
|
|
|
// Add to list
|
|
newparam->classification = curproto->classification;
|
|
Params.push_back(newparam);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////
|
|
// Get string
|
|
wxString AssOverrideTag::ToString() {
|
|
// Start with name
|
|
wxString result = Name;
|
|
|
|
// Determine if it needs parentheses
|
|
bool parenthesis = false;
|
|
if (Name == _T("\\t") || Name == _T("\\pos") || Name == _T("\\fad") || Name == _T("\\org") || Name == _T("\\clip") || Name == _T("\\move") || Name == _T("\\fade")) parenthesis = true;
|
|
if (parenthesis) result += _T("(");
|
|
|
|
// Add parameters
|
|
int n = 0;
|
|
for (std::vector<AssOverrideParameter*>::iterator cur=Params.begin();cur!=Params.end();cur++) {
|
|
if ((*cur)->GetType() != VARDATA_NONE && (*cur)->ommited == false) {
|
|
result += (*cur)->AsText();
|
|
result += _T(",");
|
|
n++;
|
|
}
|
|
}
|
|
if (n > 0) result = result.Left(result.Length()-1);
|
|
|
|
// Finish
|
|
if (parenthesis) result += _T(")");
|
|
return result;
|
|
}
|