forked from mia/Aegisub
aa506bfe40
1. svn mv OverLua SSATool athenasub avisynth_prs kanamemo \ motiontracker prs traydict unit_test vsfilter devel/ * See r2749 for full description. Originally committed to SVN as r2755.
305 lines
12 KiB
C#
305 lines
12 KiB
C#
/*
|
|
SSATool - A collection of utilities for Advanced Substation Alpha
|
|
Copyright (C) 2007 Dan Donovan
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; ONLY under version 2
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Drawing;
|
|
|
|
namespace SSATool {
|
|
public enum LineType {
|
|
dialogue,
|
|
comment,
|
|
style,
|
|
other,
|
|
error
|
|
}
|
|
public class DialogueLine : ICloneable {
|
|
public TimeSpan start, end;
|
|
public Style style;
|
|
public string actor, effect;
|
|
public string text;
|
|
public int marginl, marginr, margint, marginb;
|
|
public int layer;
|
|
public bool marked;
|
|
|
|
public override string ToString() {
|
|
string retStr = String.Format("Dialogue: {0},{1},{2},{3},{4},{5:D4},{6:D4},{7:D4},{8}{9},{10}",
|
|
(Form1.sver==4)?("Marked="+(this.marked?"1":"0")):this.layer.ToString(Util.nfi),
|
|
Util.TimeSpanSSA(this.start,false,1),
|
|
Util.TimeSpanSSA(this.end,true,1),
|
|
this.style.name, this.actor,
|
|
this.marginl, this.marginr, this.margint,
|
|
((Form1.sver == 6) ? this.marginb.ToString(Util.nfi).PadLeft(4, '0') + "," : String.Empty),
|
|
this.effect,this.text);
|
|
return retStr;
|
|
}
|
|
|
|
public Object Clone() {
|
|
return this.MemberwiseClone(); // A shallow memberwise-clone is fine
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return just the text of the line without any SSA
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string JustText {
|
|
get {
|
|
string justtext = string.Empty;
|
|
char[] linechar = this.text.ToCharArray();
|
|
bool inCode = false;
|
|
for (int charindex = 0; charindex != this.text.Length; charindex+=1) {
|
|
if (linechar[charindex] == '{') inCode = true;
|
|
else if (linechar[charindex] == '}') inCode = false;
|
|
else if (!inCode) justtext = justtext + linechar[charindex];
|
|
}
|
|
return justtext;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the margin of this line, taking overrides into account
|
|
/// </summary>
|
|
/// <returns>The margin as a rectangle</returns>
|
|
public RectangleF GetMargin() {
|
|
int Marginl = (this.marginl==0)?this.style.marginl:this.marginl;
|
|
int Margint = (this.margint==0)?this.style.margint:this.margint;
|
|
int Marginb = (this.marginb==0)?this.style.marginb:this.marginb;
|
|
int Marginr = (this.marginr==0)?this.style.marginr:this.marginr;
|
|
int Height = Form1.ResY - (Margint+Marginb);
|
|
int Width = Form1.ResX - (Marginl+Marginr);
|
|
return new RectangleF(Marginl, Margint, Width, Height);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find the bounding rectangle of an area of the line
|
|
/// </summary>
|
|
/// <param name="startIndex"></param>
|
|
/// <param name="length"></param>
|
|
/// <returns>The bounding rectangle</returns>
|
|
public RectangleF GetRect(int startIndex, int length) {
|
|
Graphics graphics = Form1.listSSAg;
|
|
StringFormat format = new System.Drawing.StringFormat();
|
|
CharacterRange[] ranges = { new CharacterRange(startIndex, length) };
|
|
Region[] regions = new Region[1];
|
|
RectangleF margin, rect;
|
|
margin = this.GetMargin();
|
|
format.SetMeasurableCharacterRanges(ranges);
|
|
int align = this.style.scrAlignment;
|
|
switch (align&3) {
|
|
case 1:
|
|
format.LineAlignment = StringAlignment.Near;
|
|
break;
|
|
case 2:
|
|
format.LineAlignment = StringAlignment.Center;
|
|
break;
|
|
default:
|
|
format.LineAlignment = StringAlignment.Far;
|
|
break;
|
|
}
|
|
switch (align&12) {
|
|
case 0:
|
|
format.Alignment = StringAlignment.Far;
|
|
break;
|
|
case 4:
|
|
format.Alignment = StringAlignment.Near;
|
|
break;
|
|
default:
|
|
format.Alignment = StringAlignment.Center;
|
|
break;
|
|
}
|
|
|
|
|
|
regions = graphics.MeasureCharacterRanges(this.JustText, this.style.GetFont(), margin, format);
|
|
rect = regions[0].GetBounds(graphics);
|
|
rect = new RectangleF(margin.X+rect.X, margin.Y+rect.Y, rect.Width, rect.Height);
|
|
return rect;
|
|
}
|
|
|
|
public static DialogueLine ParseLine(string theLine, LineType lt) {
|
|
try {
|
|
DialogueLine retLine = new DialogueLine();
|
|
char[] linechar = theLine.ToCharArray();
|
|
string buff = String.Empty;
|
|
int pos = 0;
|
|
bool neg = false;
|
|
for (int index = (Form1.sver == 4) ? 17 : 9; index != linechar.Length; index+=1) {
|
|
if ((pos<9||pos==9&&Form1.sver==6) && linechar[index].Equals(',')) {
|
|
switch (pos) {
|
|
case 0:
|
|
if (Form1.sver == 4) retLine.marked = linechar[index - 1].Equals('1');
|
|
else retLine.layer = int.Parse(buff, Util.cfi);
|
|
break;
|
|
case 1:
|
|
if (neg) retLine.start = TimeSpan.Parse(buff.Replace("-", String.Empty)).Negate();
|
|
else retLine.start = TimeSpan.Parse(buff);
|
|
break;
|
|
case 2:
|
|
if (neg) retLine.end = TimeSpan.Parse(buff.Replace("-", String.Empty)).Negate();
|
|
else retLine.end = TimeSpan.Parse(buff);
|
|
break;
|
|
case 3:
|
|
retLine.style = Form1.styleColl.Find(delegate(Style s) { return s.Equals(buff); });
|
|
if (retLine.style == null) retLine.style = new Style(buff);
|
|
break;
|
|
case 4:
|
|
retLine.actor = buff;
|
|
break;
|
|
case 5:
|
|
retLine.marginl = int.Parse(buff, Util.cfi);
|
|
break;
|
|
case 6:
|
|
retLine.marginr = int.Parse(buff, Util.cfi);
|
|
break;
|
|
case 7:
|
|
retLine.margint = int.Parse(buff, Util.cfi);
|
|
break;
|
|
case 8:
|
|
if (Form1.sver < 6) retLine.effect = buff;
|
|
else retLine.marginb = int.Parse(buff, Util.cfi);
|
|
break;
|
|
case 9:
|
|
retLine.effect = buff;
|
|
break;
|
|
}
|
|
pos += 1;
|
|
buff = string.Empty;
|
|
neg = false;
|
|
}
|
|
else if ((pos != 0 || char.IsDigit(linechar[index])) && (pos == 3 || pos == 4 || pos >= 8 || !char.IsWhiteSpace(linechar[index]))) {
|
|
buff += linechar[index];
|
|
neg = neg || (linechar[index] == '-');
|
|
}
|
|
}
|
|
retLine.text = buff;
|
|
return retLine;
|
|
} catch {
|
|
throw new FormatException();
|
|
}
|
|
}
|
|
public DialogueLine() { }
|
|
public DialogueLine(TimeSpan StartTime, TimeSpan EndTime, Style Style) {
|
|
start = StartTime;
|
|
end = EndTime;
|
|
style = Style;
|
|
}
|
|
public DialogueLine(string Text) {
|
|
text = Text;
|
|
}
|
|
public DialogueLine(Style Style, string Text) : this(Text) {
|
|
style = Style;
|
|
}
|
|
}
|
|
public class Line : IEquatable<Line>, ICloneable {
|
|
public LineType lineType;
|
|
public object line;
|
|
public bool enabled, selected;
|
|
|
|
public Line() {
|
|
this.enabled = true;
|
|
}
|
|
|
|
public static LineType getLineType(string theLine) {
|
|
if (theLine.Length > 20 && String.Compare(theLine.Substring(0, 9), "dialogue:", true, Util.cfi) == 0)
|
|
return LineType.dialogue;
|
|
else if (theLine.Length > 8 && String.Compare(theLine.Substring(0, 8), "comment:", true, Util.cfi) == 0)
|
|
return LineType.comment;
|
|
else if (theLine.Length > 20 && String.Compare(theLine.Substring(0, 6), "style:", true, Util.cfi) == 0)
|
|
return LineType.style;
|
|
else
|
|
return LineType.other;
|
|
}
|
|
public static Line ParseLine(string inStr) {
|
|
Line l = new Line();
|
|
l.lineType = getLineType(inStr);
|
|
switch (l.lineType) {
|
|
case LineType.dialogue:
|
|
try {
|
|
l.line = DialogueLine.ParseLine(inStr, LineType.dialogue);
|
|
} catch {
|
|
l.lineType = LineType.error;
|
|
l.line = inStr;
|
|
}
|
|
break;
|
|
case LineType.style:
|
|
try {
|
|
Style s = Style.ParseStyle(inStr);
|
|
l.line = s;
|
|
Form1.styleColl.Add(s);
|
|
} catch {
|
|
l.lineType = LineType.error;
|
|
l.line = inStr;
|
|
}
|
|
break;
|
|
default:
|
|
if (inStr.Length > 8 && String.Compare(inStr.Substring(0, 7), "playres", true, Util.cfi) == 0) {
|
|
switch (inStr.ToCharArray()[7]) {
|
|
case 'x':
|
|
case 'X':
|
|
Form1.ResX = int.Parse(inStr.Substring(9, inStr.Length - 9), Util.cfi);
|
|
|
|
break;
|
|
case 'y':
|
|
case 'Y':
|
|
Form1.ResY = int.Parse(inStr.Substring(9, inStr.Length - 9), Util.cfi);
|
|
break;
|
|
}
|
|
}
|
|
else if (inStr.Length > 10 && String.Compare(inStr.Substring(0, 10), "scripttype", true, Util.cfi) == 0) {
|
|
//TODO: Improve this detection
|
|
inStr = inStr.TrimEnd();
|
|
if (inStr.EndsWith("+=1")) Form1.sver = 6;
|
|
else if (inStr.EndsWith("+")) Form1.sver = 5;
|
|
else Form1.sver = 4;
|
|
}
|
|
l.line = inStr;
|
|
break;
|
|
}
|
|
return l;
|
|
}
|
|
|
|
bool System.IEquatable<Line>.Equals(Line line) {
|
|
return this.line==line.line;
|
|
}
|
|
|
|
public override int GetHashCode() {
|
|
return base.GetHashCode();
|
|
}
|
|
|
|
public Object Clone() {
|
|
Line retLine = new Line();
|
|
retLine.enabled = this.enabled;
|
|
retLine.lineType = this.lineType;
|
|
if (this.lineType == LineType.dialogue)
|
|
retLine.line = ((DialogueLine)line).Clone();
|
|
else if (this.lineType == LineType.style)
|
|
retLine.line = ((Style)line).Clone();
|
|
else
|
|
retLine.line = this.line;
|
|
|
|
return retLine;
|
|
}
|
|
|
|
public override string ToString() {
|
|
return line.ToString();
|
|
}
|
|
|
|
}
|
|
}
|