Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added formatParse to FlxText: t.text="show $green text$ between dollar s... #1229

Merged
merged 8 commits into from
Jul 18, 2014
134 changes: 134 additions & 0 deletions flixel/text/FlxText.hx
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,135 @@ class FlxText extends FlxSprite
super.destroy();
}

/**
* Applies formats to text between marker strings, then removes those markers
*
* Usage: t.text="show $green text$ between dollar-signs"; t.formatParse([greenFormat],["$"]);
*
* Even works for complex nested formats like this:
* t.text="HEY_BUDDY_@WHAT@_$IS_$_GOING@ON$?$@"; t.formatParse([yellowFormat,greenFormat],["$","@"]);
*
* @param formats the FlxTextFormat's you want to selectively apply
* @param markers corresponding marker strings, such as "@" or "$" (rarely used single-characters recommended)
*/

public function formatParse(formats:Array<FlxTextFormat>, markers:Array<String>):Void
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when formats.length != markers.length or one of the two contains null entries?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The former issue could be avoided by abstracting the format and its marker into an object:

typedef FormatMarkerPair = 
{
   format:FlxTextFormat,
   marker:String
}

That would mean an Array<FormatMarkerPair> is used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a crash. Let me throw in some explicit errors if that's the case. formats.length should always == markers.length or else user intent is ambiguous.

If the case of one of the entries being null:

  • If a marker is null, right now the corresponding format is probably ignored
  • If a format is null, a crash will probably happen

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can put in some checks and errors, but just thought:

What if the formats.length and markers.length are 0, or both are null? Should it:

  • Throw an error (what's the point of running this if it would do nothing?)
  • Do nothing (not even call clearFormats()) ?
  • Call clearFormats(), then return immediately?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... I guess in flixel there are actually very few functions that guard against null errors, so it wouldn't make too much sense to prevent that here.

In the case of both arrays having length 0, nothing should happen I think.

{
clearFormats(); //start with default formatting

var range_starts:Array<Int> = [];
var range_ends:Array<Int> = [];
var markersToApply:Array<String> = [];
var formatsToApply:Array<FlxTextFormat> = [];

var theText:String = text; //so we can process this and trash it as much as we want

var i:Int = 0;
var formatUses:Int;
for (marker in markers)
{
var start:Bool = false;
formatUses = 0;
if (theText.indexOf(marker) != -1) //if this marker is present
{
for (charIndex in 0...theText.length) //inspect each character
{
var char:String = theText.charAt(charIndex);
if (char == marker) //it's one of the markers
{
if (!start) //we're outside of a format block
{
start = true; //start a format block
range_starts.push(charIndex);
if (formatUses == 0)
{
formatsToApply.push(formats[i]);
}
else
{
formatsToApply.push(formats[i].clone()); //clone the format object if it's used twice (otherwise it doesn't work correctly)
}
markersToApply.push(markers[i]);
formatUses++;
}
else
{
start = false;
range_ends.push(charIndex); //end a format block
}
}
}
if (start)
{
range_ends.push(-1); //we ended with an unclosed block, mark it as infinite
}
}
i++;
}

//Remove all of the markers in the string
for (marker in markers)
{
while (theText.indexOf(marker) != -1)
{
theText = StringTools.replace(theText, marker, "");
}
}

//Adjust all the ranges to reflect the removed markers
for (i in 0...range_starts.length)
{
//Consider each range start
var delIndex:Int = range_starts[i];

var markerLength:Int = markersToApply[i].length;

//Any start or end index that is HIGHER than this must be subtracted by one markerLength
for (j in 0...range_starts.length)
{
if (range_starts[j] > delIndex)
{
range_starts[j] -= markerLength;
}
if (range_ends[j] > delIndex)
{
range_ends[j] -= markerLength;
}
}

//Consider each range end
delIndex = range_ends[i];

//Any start or end index that is HIGHER than this must be subtracted by one markerLength
for (j in 0...range_starts.length)
{
if (range_starts[j] > delIndex)
{
range_starts[j] -= markerLength;
}
if (range_ends[j] > delIndex)
{
range_ends[j] -= markerLength;
}
}
}

//Apply the new text
text = theText;

//Apply each format selectively to the given range
for (i in 0...range_starts.length)
{
addFormat(formatsToApply[i], range_starts[i], range_ends[i]);
}

//Clean up arrays created for this function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary, these are not going to be around after this function has finished anyway.

FlxArrayUtil.clearArray(markersToApply);
FlxArrayUtil.clearArray(range_starts);
FlxArrayUtil.clearArray(range_ends);
FlxArrayUtil.clearArray(formatsToApply);
}

/**
* Adds another format to this FlxText
*
Expand Down Expand Up @@ -960,6 +1089,11 @@ class FlxTextFormat implements IFlxDestroyable
borderColor = BorderColor == null ? FlxColor.TRANSPARENT : BorderColor;
}

public function clone():FlxTextFormat
{
return new FlxTextFormat(format.color, format.bold, format.italic, borderColor, start, end);
}

public function destroy():Void
{
format = null;
Expand Down