/*
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
*/
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using Yarn.Markup;
using Yarn.Unity;
#nullable enable
///
/// An attribute marker processor that uses a to
/// apply TextMeshPro styling tags to a line.
///
/// This marker processor registers itself as a handler for markers
/// whose name is equal to the name of a style in the given palette. For
/// example, if the palette defines a style named "happy", this marker processor
/// will process tags in a Yarn line named [happy] by inserting the
/// appropriate TextMeshProp style tags defined for the "happy" style.
public sealed class PaletteMarkerProcessor : Yarn.Unity.ReplacementMarkupHandler
{
///
/// The to use when applying styles.
///
[Tooltip("The MarkupPalette to use when applying styles.")]
public MarkupPalette? palette;
///
/// The line provider to register this markup processor with.
///
[Tooltip("The LineProviderBehaviour to register this markup processor with.")]
public LineProviderBehaviour? lineProvider;
///
///
/// Processes a replacement marker by applying the style from the given
/// palette.
///
/// The marker to process.
/// A StringBuilder to build the styled text in.
/// An optional list of child attributes to
/// apply, but this is ignored for TextMeshPro styles.
/// The locale code to use when formatting the style.
/// A list of markup diagnostics if there are any errors, otherwise an empty list.
public override ReplacementMarkerResult ProcessReplacementMarker(MarkupAttribute marker, StringBuilder childBuilder, List childAttributes, string localeCode)
{
if (palette == null)
{
var error = new List() {
new LineParser.MarkupDiagnostic($"can't apply palette for marker {marker.Name}, because a palette was not set")
};
return new ReplacementMarkerResult(error, 0);
}
if (palette.PaletteForMarker(marker.Name, out var format))
{
var childrenLength = childBuilder.Length;
childBuilder.Insert(0, format.Start);
childBuilder.Append(format.End);
// finally we need to know if we have to offset the markers
// most of the time we won't have to do anything
if (format.MarkerOffset != 0)
{
// we now need to move any children attributes down by however many characters were added to the front
// this is only the case if visible glyphs were added
// as in for example adding to the front doesn't add any visible glyphs so won't need to offset anything
// and because markers are all 0-offset relative to parents
for (int i = 0; i < childAttributes.Count; i++)
{
childAttributes[i] = childAttributes[i].Shift(format.MarkerOffset);
}
}
// finally we need to calculate the number of invisible characters we added
// which is the difference between the new and original string lengths - the total number of visible characters inserted
// we don't care WHERE those visible characters were added, just that they were
// we can't just use the marker offset because that only worries about visible elements added at the front of the string
// most of the time this is just gonna be 0 anyways and you don't have to think about it
return new ReplacementMarkerResult(childBuilder.Length - childrenLength - format.TotalVisibleCharacterCount);
}
var diagnostics = new List() { new LineParser.MarkupDiagnostic($"was unable to find a matching sprite for {marker.Name}") };
return new ReplacementMarkerResult(diagnostics, 0);
}
///
/// Called by Unity when this script is enabled to register itself with .
///
private void Start()
{
if (palette == null)
{
return;
}
if (palette.BasicMarkers.Count == 0)
{
return;
}
if (lineProvider == null)
{
var runner = DialogueRunner.FindRunner(this);
if (runner == null)
{
Debug.LogWarning("Was unable to find a dialogue runner, unable to register the markup palettes.");
return;
}
lineProvider = (LineProviderBehaviour)runner.LineProvider;
}
foreach (var marker in palette.BasicMarkers)
{
lineProvider.RegisterMarkerProcessor(marker.Marker, this);
}
foreach (var marker in palette.CustomMarkers)
{
lineProvider.RegisterMarkerProcessor(marker.Marker, this);
}
}
}