2006-01-16 22:02:54 +01:00
|
|
|
// 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
|
2006-12-23 04:55:00 +01:00
|
|
|
#include "setup.h"
|
2006-01-16 22:02:54 +01:00
|
|
|
#include "ass_dialogue.h"
|
|
|
|
#include "ass_override.h"
|
|
|
|
#include "vfr.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include <fstream>
|
|
|
|
#include <wx/tokenzr.h>
|
2006-12-23 04:55:00 +01:00
|
|
|
#if USE_FEXTRACKER == 1
|
2006-03-05 20:14:42 +01:00
|
|
|
#include "../FexTrackerSource/FexTracker.h"
|
|
|
|
#include "../FexTrackerSource/FexMovement.h"
|
2006-02-26 03:49:38 +01:00
|
|
|
#endif
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-02-27 05:18:00 +01:00
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
////////////////////// AssDialogue //////////////////////
|
|
|
|
// Constructs AssDialogue
|
|
|
|
AssDialogue::AssDialogue() {
|
2006-12-23 04:55:00 +01:00
|
|
|
#if USE_FEXTRACKER == 1
|
2006-01-28 20:48:35 +01:00
|
|
|
Tracker = 0;
|
2006-01-29 16:08:51 +01:00
|
|
|
Movement = 0;
|
2006-02-26 03:49:38 +01:00
|
|
|
#endif
|
2006-01-28 20:48:35 +01:00
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
group = _T("[Events]");
|
|
|
|
|
|
|
|
Valid = true;
|
|
|
|
Start.SetMS(0);
|
|
|
|
End.SetMS(5000);
|
|
|
|
StartMS = 0;
|
|
|
|
Layer = 0;
|
|
|
|
MarginR = MarginL = MarginV = 0;
|
|
|
|
Text = _T("");
|
|
|
|
Style = _T("Default");
|
|
|
|
Actor = _T("");
|
|
|
|
Effect = _T("");
|
|
|
|
Comment = false;
|
|
|
|
|
|
|
|
UpdateData();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AssDialogue::AssDialogue(wxString _data,bool IsSSA) {
|
2006-12-23 04:55:00 +01:00
|
|
|
#if USE_FEXTRACKER == 1
|
2006-01-28 20:48:35 +01:00
|
|
|
Tracker = 0;
|
2006-01-29 16:08:51 +01:00
|
|
|
Movement = 0;
|
2006-02-26 03:49:38 +01:00
|
|
|
#endif
|
2006-01-28 20:48:35 +01:00
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
group = _T("[Events]");
|
2006-02-27 03:23:50 +01:00
|
|
|
Valid = Parse(_data,IsSSA);
|
2006-01-16 22:02:54 +01:00
|
|
|
if (!Valid) {
|
|
|
|
throw _T("Failed parsing line.");
|
|
|
|
}
|
|
|
|
UpdateData();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////
|
|
|
|
// Destructor
|
|
|
|
AssDialogue::~AssDialogue () {
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////
|
|
|
|
// Clear
|
|
|
|
void AssDialogue::Clear () {
|
2006-02-21 04:13:35 +01:00
|
|
|
ClearBlocks();
|
2006-12-23 04:55:00 +01:00
|
|
|
#if USE_FEXTRACKER == 1
|
2006-01-29 16:08:51 +01:00
|
|
|
if( Tracker )
|
|
|
|
{
|
|
|
|
delete Tracker;
|
|
|
|
Tracker = 0;
|
|
|
|
}
|
|
|
|
if( Movement )
|
|
|
|
{
|
|
|
|
DeleteMovement( Movement );
|
|
|
|
Movement = 0;
|
|
|
|
}
|
2006-02-26 03:49:38 +01:00
|
|
|
#endif
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-21 04:13:35 +01:00
|
|
|
////////////////
|
|
|
|
// Clear blocks
|
|
|
|
void AssDialogue::ClearBlocks() {
|
|
|
|
using std::vector;
|
|
|
|
for (vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur++) {
|
|
|
|
delete *cur;
|
|
|
|
}
|
|
|
|
Blocks.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
//////////////////
|
|
|
|
// Parse ASS Data
|
2006-02-27 03:23:50 +01:00
|
|
|
bool AssDialogue::Parse(wxString rawData, bool IsSSA) {
|
2006-01-16 22:02:54 +01:00
|
|
|
size_t pos = 0;
|
|
|
|
wxString temp;
|
|
|
|
|
|
|
|
// Get type
|
2006-02-27 03:23:50 +01:00
|
|
|
if (rawData.substr(pos,9) == _T("Dialogue:")) {
|
2006-01-16 22:02:54 +01:00
|
|
|
Comment = false;
|
|
|
|
pos = 10;
|
|
|
|
}
|
2006-02-27 03:23:50 +01:00
|
|
|
else if (rawData.substr(pos,8) == _T("Comment:")) {
|
2006-01-16 22:02:54 +01:00
|
|
|
Comment = true;
|
|
|
|
pos = 9;
|
|
|
|
}
|
|
|
|
else return false;
|
2006-02-27 03:23:50 +01:00
|
|
|
wxStringTokenizer tkn(rawData.Mid(pos),_T(","),wxTOKEN_RET_EMPTY_ALL);
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// Get layer number
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
temp = tkn.GetNextToken().Trim(false).Trim(true);
|
|
|
|
if (IsSSA) Layer = 0;
|
|
|
|
else {
|
|
|
|
long templ;
|
|
|
|
temp.ToLong(&templ);
|
|
|
|
Layer = templ;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get start time
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
Start.ParseASS(tkn.GetNextToken());
|
|
|
|
StartMS = Start.GetMS();
|
|
|
|
|
|
|
|
// Get end time
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
End.ParseASS(tkn.GetNextToken());
|
|
|
|
|
|
|
|
// Get style
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
Style = tkn.GetNextToken();
|
|
|
|
Style.Trim(true);
|
|
|
|
Style.Trim(false);
|
|
|
|
|
|
|
|
// Get actor
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
Actor = tkn.GetNextToken();
|
|
|
|
Actor.Trim(true);
|
|
|
|
Actor.Trim(false);
|
|
|
|
|
|
|
|
// Get left margin
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
SetMarginString(tkn.GetNextToken().Trim(false).Trim(true),1);
|
|
|
|
|
|
|
|
// Get right margin
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
SetMarginString(tkn.GetNextToken().Trim(false).Trim(true),2);
|
|
|
|
|
|
|
|
// Get vertical margin
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
SetMarginString(tkn.GetNextToken().Trim(false).Trim(true),3);
|
|
|
|
|
|
|
|
// Get effect
|
|
|
|
if (!tkn.HasMoreTokens()) return false;
|
|
|
|
Effect = tkn.GetNextToken();
|
|
|
|
Effect.Trim(true);
|
|
|
|
Effect.Trim(false);
|
|
|
|
|
2006-12-23 04:55:00 +01:00
|
|
|
#if USE_FEXTRACKER == 1
|
2006-03-03 20:00:47 +01:00
|
|
|
if( Effect.BeforeFirst(':')==_T("FexMovement") )
|
|
|
|
{
|
|
|
|
if( Movement ) DeleteMovement( Movement );
|
|
|
|
Movement = CreateMovement();
|
2006-03-05 19:50:45 +01:00
|
|
|
LoadMovement( Movement, Effect.AfterFirst(':').c_str() );
|
2006-03-03 20:00:47 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
// Get text
|
|
|
|
Text = tkn.GetNextToken();
|
|
|
|
while (tkn.HasMoreTokens()) {
|
|
|
|
Text += _T(",");
|
|
|
|
Text += tkn.GetNextToken();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-27 05:18:00 +01:00
|
|
|
/////////////
|
|
|
|
// Make data
|
|
|
|
wxString AssDialogue::MakeData() {
|
2006-01-16 22:02:54 +01:00
|
|
|
// Prepare
|
2006-02-27 03:23:50 +01:00
|
|
|
wxString final = _T("");
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-02-27 03:23:50 +01:00
|
|
|
// Write all final
|
|
|
|
if (Comment) final += _T("Comment: ");
|
|
|
|
else final += _T("Dialogue: ");
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-02-27 03:23:50 +01:00
|
|
|
final += wxString::Format(_T("%01i"),Layer);
|
|
|
|
final += _T(",");
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-02-27 03:23:50 +01:00
|
|
|
final += Start.GetASSFormated() + _T(",");
|
|
|
|
final += End.GetASSFormated() + _T(",");
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
Style.Replace(_T(","),_T(";"));
|
|
|
|
Actor.Replace(_T(","),_T(";"));
|
2006-02-27 03:23:50 +01:00
|
|
|
final += Style + _T(",");
|
|
|
|
final += Actor + _T(",");
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2006-02-27 03:23:50 +01:00
|
|
|
final += GetMarginString(1);
|
|
|
|
final += _T(",");
|
|
|
|
final += GetMarginString(2);
|
|
|
|
final += _T(",");
|
|
|
|
final += GetMarginString(3);
|
|
|
|
final += _T(",");
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
Effect.Replace(_T(","),_T(";"));
|
2006-02-27 03:23:50 +01:00
|
|
|
final += Effect + _T(",");
|
|
|
|
final += Text;
|
2006-02-27 05:18:00 +01:00
|
|
|
return final;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////
|
|
|
|
// Update AssDialogue's data line
|
|
|
|
void AssDialogue::UpdateData () {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////
|
|
|
|
// Get entry data
|
|
|
|
const wxString AssDialogue::GetEntryData() {
|
|
|
|
return MakeData();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////
|
|
|
|
// Set entry data
|
|
|
|
void AssDialogue::SetEntryData(wxString newData) {
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////
|
|
|
|
// Get SSA version of Dialogue
|
|
|
|
wxString AssDialogue::GetSSAText () {
|
|
|
|
// Prepare
|
|
|
|
wxString work = _T("");
|
|
|
|
|
|
|
|
// Write all work
|
|
|
|
if (Comment) work += _T("Comment: ");
|
|
|
|
else work += _T("Dialogue: ");
|
|
|
|
|
|
|
|
work += _T("Marked=0,");
|
|
|
|
|
|
|
|
work += Start.GetASSFormated() + _T(",");
|
|
|
|
work += End.GetASSFormated() + _T(",");
|
|
|
|
|
|
|
|
Style.Replace(_T(","),_T(";"));
|
|
|
|
Actor.Replace(_T(","),_T(";"));
|
|
|
|
work += Style + _T(",");
|
|
|
|
work += Actor + _T(",");
|
|
|
|
|
|
|
|
work += GetMarginString(1);
|
|
|
|
work += _T(",");
|
|
|
|
work += GetMarginString(2);
|
|
|
|
work += _T(",");
|
|
|
|
work += GetMarginString(3);
|
|
|
|
work += _T(",");
|
|
|
|
|
|
|
|
Effect.Replace(_T(","),_T(";"));
|
|
|
|
work += Effect + _T(",");
|
|
|
|
work += Text;
|
|
|
|
|
|
|
|
return work;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////
|
|
|
|
// Parse SRT tags
|
|
|
|
// --------------
|
|
|
|
// Yea, I convert to ASS tags, then parse that. So sue me.
|
|
|
|
void AssDialogue::ParseSRTTags () {
|
|
|
|
// Search and replace
|
|
|
|
size_t total = 0;
|
|
|
|
total += Text.Replace(_T("<i>"),_T("{\\i1}"));
|
|
|
|
total += Text.Replace(_T("</i>"),_T("{\\i0}"));
|
|
|
|
total += Text.Replace(_T("<b>"),_T("{\\b1}"));
|
|
|
|
total += Text.Replace(_T("</b>"),_T("{\\b0}"));
|
|
|
|
total += Text.Replace(_T("<u>"),_T("{\\u1}"));
|
|
|
|
total += Text.Replace(_T("</u>"),_T("{\\u0}"));
|
|
|
|
total += Text.Replace(_T("<s>"),_T("{\\s1}"));
|
|
|
|
total += Text.Replace(_T("</s>"),_T("{\\s0}"));
|
|
|
|
|
|
|
|
// Process <font> tag
|
|
|
|
wxString work = Text;
|
|
|
|
work.UpperCase();
|
|
|
|
size_t pos_open = 0;
|
|
|
|
size_t pos_close = 0;
|
|
|
|
size_t pos = 0;
|
|
|
|
size_t end = 0;
|
|
|
|
size_t start = 0;
|
|
|
|
bool isOpen;
|
|
|
|
|
|
|
|
// Iterate
|
|
|
|
pos_open = work.find(_T("<FONT"),0);
|
|
|
|
pos_close = work.find(_T("</FONT"),0);
|
|
|
|
while (pos_open != wxString::npos || pos_close != wxString::npos) {
|
|
|
|
// Determine if it's an open or close tag
|
|
|
|
if (pos_open < pos_close) {
|
|
|
|
start = pos_open;
|
|
|
|
isOpen = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
start = pos_close;
|
|
|
|
isOpen = false;
|
|
|
|
}
|
|
|
|
end = work.find(_T(">"),start)+1;
|
|
|
|
//if (end == wxString::npos) continue;
|
|
|
|
|
|
|
|
// Open tag
|
|
|
|
if (isOpen) {
|
|
|
|
wxString replaced = _T("");
|
|
|
|
|
|
|
|
// Color tag
|
|
|
|
if ((pos = work.find(_T("COLOR=\""),start)) != wxString::npos) {
|
|
|
|
if (pos < end) {
|
|
|
|
pos += 7;
|
|
|
|
size_t end_tag = Text.find(_T("\""),pos);
|
|
|
|
if (end_tag != wxString::npos) {
|
|
|
|
if (end_tag-pos == 7) {
|
|
|
|
replaced += _T("{\\c&H");
|
|
|
|
replaced += work.substr(pos+5,2);
|
|
|
|
replaced += work.substr(pos+3,2);
|
|
|
|
replaced += work.substr(pos+1,2);
|
|
|
|
replaced += _T("&}");
|
|
|
|
total++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Face tag
|
|
|
|
if ((pos = work.find(_T("FACE=\""),start)) != wxString::npos) {
|
|
|
|
if (pos < end) {
|
|
|
|
pos += 6;
|
|
|
|
size_t end_tag = work.find(_T("\""),pos);
|
|
|
|
if (end_tag != wxString::npos) {
|
|
|
|
replaced += _T("{\\fn");
|
|
|
|
replaced += work.substr(pos,end_tag-pos);
|
|
|
|
replaced += _T("}");
|
|
|
|
total++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Size tag
|
|
|
|
if ((pos = work.find(_T("SIZE=\""),start)) != wxString::npos) {
|
|
|
|
if (pos < end) {
|
|
|
|
pos += 6;
|
|
|
|
size_t end_tag = Text.find(_T("\""),pos);
|
|
|
|
if (end_tag != wxString::npos) {
|
|
|
|
replaced += _T("{\\fs");
|
|
|
|
replaced += work.substr(pos,end_tag-pos);
|
|
|
|
replaced += _T("}");
|
|
|
|
total++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Replace whole tag
|
|
|
|
Text = Text.substr(0,start) + replaced + Text.substr(end);
|
|
|
|
total++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close tag
|
|
|
|
else {
|
|
|
|
// Find if it's italic, bold, underline, and strikeout
|
|
|
|
wxString prev = Text.Left(start);
|
|
|
|
bool isItalic=false,isBold=false,isUnder=false,isStrike=false;
|
|
|
|
if (CountMatches(prev,_T("{\\i1}")) > CountMatches(prev,_T("{\\i0}"))) isItalic = true;
|
|
|
|
if (CountMatches(prev,_T("{\\b1}")) > CountMatches(prev,_T("{\\b0}"))) isBold = true;
|
|
|
|
if (CountMatches(prev,_T("{\\u1}")) > CountMatches(prev,_T("{\\u0}"))) isUnder = true;
|
|
|
|
if (CountMatches(prev,_T("{\\s1}")) > CountMatches(prev,_T("{\\s0}"))) isStrike = true;
|
|
|
|
|
|
|
|
// Generate new tag, by reseting and then restoring flags
|
|
|
|
wxString replaced = _T("{\\r");
|
|
|
|
if (isItalic) replaced += _T("\\i1");
|
|
|
|
if (isBold) replaced += _T("\\b1");
|
|
|
|
if (isUnder) replaced += _T("\\u1");
|
|
|
|
if (isStrike) replaced += _T("\\s1");
|
|
|
|
replaced += _T("}");
|
|
|
|
|
|
|
|
// Replace
|
|
|
|
Text = Text.substr(0,start) + replaced + Text.substr(end);
|
|
|
|
total++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get next
|
|
|
|
work = Text;
|
|
|
|
work.UpperCase();
|
|
|
|
pos_open = work.find(_T("<FONT"),0);
|
|
|
|
pos_close = work.find(_T("</FONT"),0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove double tagging
|
|
|
|
Text.Replace(_T("}{"),_T(""));
|
|
|
|
|
|
|
|
// Update all stuff
|
2006-02-21 04:13:35 +01:00
|
|
|
//if (total > 0) UpdateText();
|
2006-01-16 22:02:54 +01:00
|
|
|
UpdateData();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////
|
|
|
|
// Parse ASS tags
|
|
|
|
void AssDialogue::ParseASSTags () {
|
|
|
|
// Clear blocks
|
2006-02-21 04:13:35 +01:00
|
|
|
ClearBlocks();
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// Is drawing?
|
|
|
|
int drawingLevel = 0;
|
|
|
|
|
|
|
|
// Loop through
|
|
|
|
const size_t len = Text.size();
|
|
|
|
size_t cur = 0;
|
|
|
|
size_t end = 0;
|
|
|
|
while (cur < len) {
|
|
|
|
// Overrides block
|
|
|
|
if (Text[cur] == '{') {
|
|
|
|
// Get contents of block
|
|
|
|
wxString work;
|
|
|
|
end = Text.find(_T("}"),cur);
|
|
|
|
if (end == wxString::npos) {
|
|
|
|
work = Text.substr(cur);
|
|
|
|
end = len;
|
|
|
|
}
|
|
|
|
else work = Text.substr(cur,end-cur);
|
|
|
|
work = Text.substr(cur+1,end-cur-1);
|
|
|
|
|
|
|
|
// Create block
|
|
|
|
AssDialogueBlockOverride *block = new AssDialogueBlockOverride;
|
|
|
|
block->parent = this;
|
|
|
|
block->text = work;
|
|
|
|
block->ParseTags();
|
|
|
|
Blocks.push_back(block);
|
|
|
|
|
|
|
|
// Look for \p in block
|
|
|
|
std::vector<AssOverrideTag*>::iterator curTag;
|
|
|
|
for (curTag = block->Tags.begin();curTag != block->Tags.end();curTag++) {
|
|
|
|
AssOverrideTag *tag = *curTag;
|
|
|
|
if (tag->Name == _T("\\p")) {
|
|
|
|
drawingLevel = tag->Params.at(0)->AsInt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increase
|
|
|
|
cur = end+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Plain-text/drawing block
|
|
|
|
else {
|
|
|
|
wxString work;
|
|
|
|
end = Text.find(_T("{"),cur);
|
|
|
|
if (end == wxString::npos) {
|
|
|
|
work = Text.substr(cur);
|
|
|
|
end = len;
|
|
|
|
}
|
|
|
|
else work = Text.substr(cur,end-cur);
|
|
|
|
|
|
|
|
// Plain-text
|
|
|
|
if (drawingLevel == 0) {
|
|
|
|
AssDialogueBlockPlain *block = new AssDialogueBlockPlain;
|
|
|
|
block->text = work;
|
|
|
|
Blocks.push_back(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Drawing
|
|
|
|
else {
|
|
|
|
AssDialogueBlockDrawing *block = new AssDialogueBlockDrawing;
|
|
|
|
block->text = work;
|
|
|
|
block->Scale = drawingLevel;
|
|
|
|
Blocks.push_back(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Empty line, make an empty block
|
|
|
|
if (len == 0) {
|
|
|
|
AssDialogueBlockPlain *block = new AssDialogueBlockPlain;
|
|
|
|
block->text = _T("");
|
|
|
|
Blocks.push_back(block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////
|
|
|
|
// Strip tags
|
|
|
|
void AssDialogue::StripTags () {
|
|
|
|
using std::list;
|
|
|
|
using std::vector;
|
2006-02-21 04:13:35 +01:00
|
|
|
ParseASSTags();
|
2006-01-16 22:02:54 +01:00
|
|
|
vector<AssDialogueBlock*>::iterator next;
|
|
|
|
for (vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur=next) {
|
|
|
|
next = cur;
|
|
|
|
next++;
|
2006-10-20 00:53:06 +02:00
|
|
|
// FIXME: doesn't this crash when there's too many override blocks in one line?
|
2006-01-16 22:02:54 +01:00
|
|
|
if ((*cur)->type == BLOCK_OVERRIDE) {
|
|
|
|
delete *cur;
|
|
|
|
Blocks.erase(cur);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
UpdateText();
|
|
|
|
UpdateData();
|
2006-02-21 04:13:35 +01:00
|
|
|
ClearBlocks();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////
|
|
|
|
// Convert tags to SRT
|
|
|
|
// -------------------
|
|
|
|
// TODO: Improve this code
|
|
|
|
//
|
|
|
|
void AssDialogue::ConvertTagsToSRT () {
|
|
|
|
// Setup
|
|
|
|
using std::list;
|
|
|
|
using std::vector;
|
|
|
|
AssDialogueBlockOverride* curBlock;
|
|
|
|
AssDialogueBlockPlain *curPlain;
|
|
|
|
AssOverrideTag* curTag;
|
|
|
|
wxString final = _T("");
|
|
|
|
bool isItalic=false,isBold=false,isUnder=false,isStrike=false;
|
|
|
|
bool temp;
|
|
|
|
|
|
|
|
// Iterate through blocks
|
2006-02-21 04:13:35 +01:00
|
|
|
ParseASSTags();
|
2006-01-16 22:02:54 +01:00
|
|
|
for (size_t i=0;i<Blocks.size();i++) {
|
|
|
|
curBlock = AssDialogueBlock::GetAsOverride(Blocks.at(i));
|
|
|
|
if (curBlock) {
|
|
|
|
// Iterate through overrides
|
|
|
|
for (size_t j=0;j<curBlock->Tags.size();j++) {
|
|
|
|
curTag = curBlock->Tags.at(j);
|
|
|
|
if (curTag->IsValid()) {
|
|
|
|
// Italics
|
|
|
|
if (curTag->Name == _T("\\i")) {
|
|
|
|
temp = curTag->Params.at(0)->AsBool();
|
|
|
|
if (temp && !isItalic) {
|
|
|
|
isItalic = true;
|
|
|
|
final += _T("<i>");
|
|
|
|
}
|
|
|
|
if (!temp && isItalic) {
|
|
|
|
isItalic = false;
|
|
|
|
final += _T("</i>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Underline
|
|
|
|
if (curTag->Name == _T("\\u")) {
|
|
|
|
temp = curTag->Params.at(0)->AsBool();
|
|
|
|
if (temp && !isUnder) {
|
|
|
|
isUnder = true;
|
|
|
|
final += _T("<u>");
|
|
|
|
}
|
|
|
|
if (!temp && isUnder) {
|
|
|
|
isUnder = false;
|
|
|
|
final += _T("</u>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Strikeout
|
|
|
|
if (curTag->Name == _T("\\s")) {
|
|
|
|
temp = curTag->Params.at(0)->AsBool();
|
|
|
|
if (temp && !isStrike) {
|
|
|
|
isStrike = true;
|
|
|
|
final += _T("<s>");
|
|
|
|
}
|
|
|
|
if (!temp && isStrike) {
|
|
|
|
isStrike = false;
|
|
|
|
final += _T("</s>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bold
|
|
|
|
if (curTag->Name == _T("\\b")) {
|
|
|
|
temp = curTag->Params.at(0)->AsBool();
|
|
|
|
if (temp && !isBold) {
|
|
|
|
isBold = true;
|
|
|
|
final += _T("<b>");
|
|
|
|
}
|
|
|
|
if (!temp && isBold) {
|
|
|
|
isBold = false;
|
|
|
|
final += _T("</b>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Plain text
|
|
|
|
else {
|
|
|
|
curPlain = AssDialogueBlock::GetAsPlain(Blocks.at(i));
|
|
|
|
if (curPlain) {
|
|
|
|
final += curPlain->GetText();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Text = final;
|
|
|
|
UpdateData();
|
2006-02-21 04:13:35 +01:00
|
|
|
ClearBlocks();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////
|
|
|
|
// Updates text from tags
|
|
|
|
void AssDialogue::UpdateText () {
|
|
|
|
using std::vector;
|
|
|
|
Text = _T("");
|
|
|
|
for (vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur++) {
|
|
|
|
if ((*cur)->type == BLOCK_OVERRIDE) {
|
|
|
|
Text += _T("{");
|
|
|
|
Text += (*cur)->GetText();
|
|
|
|
Text += _T("}");
|
|
|
|
}
|
|
|
|
else Text += (*cur)->GetText();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////
|
|
|
|
// Sets margin from a string
|
|
|
|
void AssDialogue::SetMarginString(const wxString origvalue,int which) {
|
|
|
|
// Make it numeric
|
|
|
|
wxString strvalue = origvalue;
|
|
|
|
if (!strvalue.IsNumber()) {
|
|
|
|
strvalue = _T("");
|
|
|
|
for (size_t i=0;i<origvalue.Length();i++) {
|
|
|
|
if (origvalue.Mid(i,1).IsNumber()) {
|
|
|
|
strvalue += origvalue.Mid(i,1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get value
|
|
|
|
long value;
|
|
|
|
strvalue.ToLong(&value);
|
|
|
|
|
|
|
|
// Cap it
|
|
|
|
if (value < 0) value = 0;
|
|
|
|
if (value > 9999) value = 9999;
|
|
|
|
|
|
|
|
// Assign
|
|
|
|
switch (which) {
|
|
|
|
case 1: MarginL = value; break;
|
|
|
|
case 2: MarginR = value; break;
|
|
|
|
case 3: MarginV = value; break;
|
|
|
|
default: throw _T("Invalid margin");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////
|
|
|
|
// Gets string for margin
|
2006-12-30 15:31:41 +01:00
|
|
|
wxString AssDialogue::GetMarginString(int which,bool pad) {
|
2006-01-16 22:02:54 +01:00
|
|
|
int value;
|
|
|
|
switch (which) {
|
|
|
|
case 1: value = MarginL; break;
|
|
|
|
case 2: value = MarginR; break;
|
|
|
|
case 3: value = MarginV; break;
|
|
|
|
default: throw _T("Invalid margin");
|
|
|
|
}
|
2006-12-30 15:31:41 +01:00
|
|
|
if (pad) return wxString::Format(_T("%04i"),value);
|
|
|
|
else return wxString::Format(_T("%i"),value);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////
|
|
|
|
// Process parameters via callback
|
|
|
|
void AssDialogue::ProcessParameters(void (*callback)(wxString tagName,int par_n,AssOverrideParameter *param,void *userData),void *userData) {
|
|
|
|
// Apply for all override blocks
|
|
|
|
AssDialogueBlockOverride *curBlock;
|
2006-02-21 04:13:35 +01:00
|
|
|
//ParseASSTags();
|
2006-01-16 22:02:54 +01:00
|
|
|
for (std::vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur++) {
|
|
|
|
if ((*cur)->type == BLOCK_OVERRIDE) {
|
|
|
|
curBlock = static_cast<AssDialogueBlockOverride*> (*cur);
|
|
|
|
curBlock->ProcessParameters(callback,userData);
|
|
|
|
}
|
|
|
|
}
|
2006-02-21 04:13:35 +01:00
|
|
|
//ClearBlocks();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////
|
|
|
|
// Checks if two lines collide
|
|
|
|
bool AssDialogue::CollidesWith(AssDialogue *target) {
|
|
|
|
if (!target) return false;
|
|
|
|
int a = Start.GetMS();
|
|
|
|
int b = End.GetMS();
|
|
|
|
int c = target->Start.GetMS();
|
|
|
|
int d = target->End.GetMS();
|
|
|
|
return ((a < c) ? (c < b) : (a < d));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-27 10:07:08 +01:00
|
|
|
/////////
|
|
|
|
// Clone
|
|
|
|
AssEntry *AssDialogue::Clone() {
|
|
|
|
// Create clone
|
|
|
|
AssDialogue *final = new AssDialogue();
|
|
|
|
|
|
|
|
// Copy data
|
|
|
|
final->group = group;
|
|
|
|
final->StartMS = StartMS;
|
|
|
|
final->Valid = Valid;
|
|
|
|
final->Actor = Actor;
|
|
|
|
final->Comment = Comment;
|
|
|
|
final->Effect = Effect;
|
|
|
|
final->End = End;
|
|
|
|
final->Layer = Layer;
|
|
|
|
final->MarginL = MarginL;
|
|
|
|
final->MarginR = MarginR;
|
|
|
|
final->MarginV = MarginV;
|
|
|
|
final->Start = Start;
|
|
|
|
final->StartMS = final->StartMS;
|
|
|
|
final->Style = Style;
|
|
|
|
final->Text = Text;
|
|
|
|
final->SetEntryData(GetEntryData());
|
|
|
|
|
|
|
|
// Return
|
|
|
|
return final;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
////////////////////// AssDialogueBlock //////////////////////
|
|
|
|
///////////////
|
|
|
|
// Constructor
|
|
|
|
AssDialogueBlock::AssDialogueBlock () {
|
|
|
|
type = BLOCK_BASE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////
|
|
|
|
// Destructor
|
|
|
|
AssDialogueBlock::~AssDialogueBlock () {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////
|
|
|
|
// Returns as a plain block
|
|
|
|
// ----------------------
|
|
|
|
// If it isn't a plain block, returns NULL
|
|
|
|
AssDialogueBlockPlain *AssDialogueBlock::GetAsPlain(AssDialogueBlock *base) {
|
|
|
|
if (!base) return NULL;
|
|
|
|
if (base->type == BLOCK_PLAIN) {
|
|
|
|
return static_cast<AssDialogueBlockPlain*> (base);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////
|
|
|
|
// Returns as an override block
|
|
|
|
// ----------------------------
|
|
|
|
// If it isn't an override block, returns NULL
|
|
|
|
AssDialogueBlockOverride *AssDialogueBlock::GetAsOverride(AssDialogueBlock *base) {
|
|
|
|
if (!base) return NULL;
|
|
|
|
if (base->type == BLOCK_OVERRIDE) {
|
|
|
|
return static_cast<AssDialogueBlockOverride*> (base);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////
|
|
|
|
// Returns as a drawing block
|
|
|
|
// ----------------------------
|
|
|
|
// If it isn't an drawing block, returns NULL
|
|
|
|
AssDialogueBlockDrawing *AssDialogueBlock::GetAsDrawing(AssDialogueBlock *base) {
|
|
|
|
if (!base) return NULL;
|
|
|
|
if (base->type == BLOCK_DRAWING) {
|
|
|
|
return static_cast<AssDialogueBlockDrawing*> (base);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////// AssDialogueBlockPlain //////////////////////
|
|
|
|
///////////////
|
|
|
|
// Constructor
|
|
|
|
AssDialogueBlockPlain::AssDialogueBlockPlain () {
|
|
|
|
type = BLOCK_PLAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////
|
|
|
|
// Return the text
|
|
|
|
wxString AssDialogueBlockPlain::GetText() {
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////// AssDialogueBlockDrawing //////////////////////
|
|
|
|
///////////////
|
|
|
|
// Constructor
|
|
|
|
AssDialogueBlockDrawing::AssDialogueBlockDrawing () {
|
|
|
|
type = BLOCK_DRAWING;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////
|
|
|
|
// Return the text
|
|
|
|
wxString AssDialogueBlockDrawing::GetText() {
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////
|
|
|
|
// Multiply coordinates
|
|
|
|
void AssDialogueBlockDrawing::MultiplyCoords(double x,double y) {
|
|
|
|
// HACK: Implement a proper parser ffs!!
|
|
|
|
wxStringTokenizer tkn(GetText(),_T(" "),wxTOKEN_DEFAULT);
|
|
|
|
wxString cur;
|
|
|
|
wxString final;
|
|
|
|
bool isX = true;
|
|
|
|
long temp;
|
|
|
|
|
|
|
|
// Process tokens
|
|
|
|
while (tkn.HasMoreTokens()) {
|
|
|
|
cur = tkn.GetNextToken().Lower();
|
|
|
|
|
|
|
|
// Number, process it
|
|
|
|
if (cur.IsNumber()) {
|
|
|
|
// Multiply it
|
|
|
|
cur.ToLong(&temp);
|
|
|
|
if (isX) temp = temp*x + 0.5;
|
|
|
|
else temp = temp*y + 0.5;
|
|
|
|
|
|
|
|
// Write back to list
|
|
|
|
final += wxString::Format(_T("%i "),temp);
|
|
|
|
|
|
|
|
// Toggle X/Y
|
|
|
|
isX = !isX;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Text
|
|
|
|
else {
|
|
|
|
if (cur == _T("m") || cur == _T("n") || cur == _T("l") || cur == _T("b") || cur == _T("s") || cur == _T("p") || cur == _T("c")) isX = true;
|
|
|
|
final += cur + _T(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write back final
|
|
|
|
final = final.Left(final.Length()-1);
|
|
|
|
text = final;
|
|
|
|
}
|