142 lines
3.7 KiB
GDScript
142 lines
3.7 KiB
GDScript
@tool
|
|
class_name AdvancedRichText extends RichTextLabel
|
|
|
|
@export_multiline var userText:String = "" # The text the user is asking for
|
|
@export_multiline var _finalText:String = "" # The final text after processing (translation, wrapping, etc.)
|
|
|
|
@export var _newLineIndexes:Array[int] = [] # The indexes of where each line starts in finalText
|
|
@export var _lines:PackedStringArray = [];
|
|
|
|
# Hides the original RichTextLabel text property
|
|
func _set(property: StringName, value) -> bool:
|
|
if property == "text":
|
|
userText = value
|
|
_recalcText()
|
|
return true
|
|
elif property == "richtextlabel_text":
|
|
text = value
|
|
return true
|
|
return false
|
|
|
|
func _get(property: StringName):
|
|
if property == "text":
|
|
return userText
|
|
elif property == "richtextlabel_text":
|
|
return text
|
|
return null
|
|
|
|
@export var translate:bool = true:
|
|
set(value):
|
|
translate = value
|
|
_recalcText()
|
|
get():
|
|
return translate
|
|
|
|
@export var smartWrap:bool = true:
|
|
set(value):
|
|
smartWrap = value
|
|
_recalcText()
|
|
get():
|
|
return smartWrap
|
|
|
|
@export var maxLines:int = -1:
|
|
set(value):
|
|
maxLines = value
|
|
_recalcText()
|
|
get():
|
|
return maxLines
|
|
|
|
@export var startLine:int = 0:
|
|
set(value):
|
|
startLine = value
|
|
_recalcText()
|
|
get():
|
|
return startLine
|
|
|
|
# Returns count of characters that can be displayed, assuming visible_chars = -1
|
|
func getCharactersDisplayedCount() -> int:
|
|
# Count characters
|
|
var count = 0
|
|
var lineCount = min(startLine + maxLines, _lines.size()) - startLine
|
|
for i in range(startLine, startLine + lineCount):
|
|
count += _lines[i].length()
|
|
if lineCount > 1:
|
|
count += lineCount - 1 # Add newlines
|
|
return count
|
|
|
|
func getFinalText() -> String:
|
|
return _finalText
|
|
|
|
func getTotalLineCount() -> int:
|
|
return _lines.size()
|
|
|
|
func _enter_tree() -> void:
|
|
self.threaded = false;
|
|
|
|
func _recalcText() -> void:
|
|
_lines.clear()
|
|
|
|
if userText.is_empty():
|
|
self.richtextlabel_text = ""
|
|
return
|
|
|
|
# Translate if needed
|
|
var textTranslated = userText
|
|
if self.translate:
|
|
textTranslated = tr(textTranslated)
|
|
|
|
# Replace input bb tags.
|
|
var regex = RegEx.new()
|
|
regex.compile(r"\[input action=(.*?)\](.*?)\[/input\]")
|
|
var inputIconText = textTranslated
|
|
for match in regex.search_all(textTranslated):
|
|
var action = match.get_string(1).to_lower()
|
|
var height:int = get_theme_font_size("normal_font_size")
|
|
var img_tag = "[img height=%d valign=center,center]res://ui/input/%s.tres[/img]" % [ height, action ]
|
|
inputIconText = inputIconText.replace(match.get_string(0), img_tag)
|
|
|
|
# Perform smart wrapping
|
|
var wrappedText = inputIconText
|
|
if smartWrap:
|
|
var unwrappedText = wrappedText.strip_edges()
|
|
|
|
self.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART;
|
|
self.richtextlabel_text = unwrappedText
|
|
self.visible_characters = -1;
|
|
self.fit_content = false;
|
|
_newLineIndexes = [];
|
|
|
|
# Determine where the wrapped newlines are
|
|
var line = 0;
|
|
var wasNewLine = false;
|
|
for i in range(0, self.richtextlabel_text.length()):
|
|
var tLine = self.get_character_line(i);
|
|
if tLine == line:
|
|
wasNewLine = false
|
|
if self.richtextlabel_text[i] == "\n":
|
|
wasNewLine = true
|
|
continue;
|
|
if !wasNewLine:
|
|
_newLineIndexes.append(i);
|
|
line = tLine;
|
|
|
|
# Create fake pre-wrapped text.
|
|
wrappedText = "";
|
|
for i in range(0, self.richtextlabel_text.length()):
|
|
if _newLineIndexes.find(i) != -1 and i != 0:
|
|
wrappedText += "\n";
|
|
wrappedText += self.richtextlabel_text[i];
|
|
|
|
# Handle max and start line(s)
|
|
var maxText = wrappedText
|
|
if maxLines > 0:
|
|
_lines = maxText.split("\n", true);
|
|
var selectedLines = [];
|
|
for i in range(startLine, min(startLine + maxLines, _lines.size())):
|
|
selectedLines.append(_lines[i]);
|
|
maxText = "\n".join(selectedLines);
|
|
|
|
_finalText = maxText
|
|
self.richtextlabel_text = maxText
|
|
print("Updated text")
|