124 lines
3.0 KiB
GDScript
124 lines
3.0 KiB
GDScript
class_name VNTextbox extends PanelContainer
|
|
|
|
const VN_REVEAL_TIME = 0.01
|
|
const VISIBLE_LINES:int = 4
|
|
|
|
var label:RichTextLabel;
|
|
var text:String = ""
|
|
var parsedOutText = ""
|
|
var visibleCharacters:int = 0;
|
|
var revealTimer:float = 0;
|
|
|
|
var lineStarts:Array[int] = [];
|
|
var newlineIndexes:Array[int] = [];
|
|
var wrappedText:String = "";
|
|
var currentLine = 0;
|
|
var currentViewScrolled = true;
|
|
var isSpeedupDown = false;
|
|
var isMoreViews = false;
|
|
var isClosed = true;
|
|
|
|
signal textboxClosing
|
|
|
|
func _ready() -> void:
|
|
label = $MarginContainer/Label
|
|
self.visible = false;
|
|
|
|
func _process(delta: float) -> void:
|
|
if text == "":
|
|
isClosed = true;
|
|
return;
|
|
|
|
if currentViewScrolled:
|
|
if Input.is_action_just_pressed("interact"):
|
|
if isMoreViews:
|
|
visibleCharacters = 0;
|
|
currentLine += VISIBLE_LINES;
|
|
currentViewScrolled = false;
|
|
recalculateWrapping();
|
|
return
|
|
setText("");
|
|
textboxClosing.emit();
|
|
return;
|
|
|
|
if visibleCharacters >= getCountOfCharactersToScrollInView():
|
|
currentViewScrolled = true;
|
|
#print("Scrolled view");
|
|
#if isMoreViews:
|
|
#print("More views");
|
|
return;
|
|
|
|
if Input.is_action_just_pressed("interact"):
|
|
isSpeedupDown = true;
|
|
elif Input.is_action_just_released("interact"):
|
|
isSpeedupDown = false;
|
|
elif !Input.is_action_pressed("interact"):
|
|
isSpeedupDown = false;
|
|
|
|
revealTimer += delta;
|
|
if isSpeedupDown:
|
|
revealTimer += delta;
|
|
|
|
if revealTimer > VN_REVEAL_TIME:
|
|
revealTimer = 0;
|
|
visibleCharacters += 1;
|
|
label.visible_characters = visibleCharacters;
|
|
|
|
func getCountOfCharactersToScrollInView() -> int:
|
|
if lineStarts.size() <= VISIBLE_LINES:
|
|
return wrappedText.length();
|
|
if currentLine + VISIBLE_LINES >= lineStarts.size():
|
|
return wrappedText.length() - lineStarts[currentLine];
|
|
return lineStarts[min(lineStarts.size(), currentLine + VISIBLE_LINES)] - lineStarts[currentLine];
|
|
|
|
func recalculateWrapping():
|
|
# Reset label to default.
|
|
label.advancedText = text;
|
|
label.visible_characters = -1;
|
|
label.fit_content = true;
|
|
isMoreViews = false;
|
|
|
|
# Determine where the wrapped newlines are
|
|
lineStarts = [ 0 ];
|
|
var line = 0;
|
|
var wasNewLine = false;
|
|
for i in range(0, text.length()):
|
|
var tLine = label.get_character_line(i);
|
|
if tLine == line:
|
|
wasNewLine = false
|
|
if text[i] == "\n":
|
|
wasNewLine = true
|
|
continue;
|
|
if !wasNewLine:
|
|
newlineIndexes.append(i);
|
|
lineStarts.append(i);
|
|
line = tLine;
|
|
|
|
# Create fake pre-wrapped text.
|
|
wrappedText = "";
|
|
for i in range(lineStarts[currentLine], text.length()):
|
|
if newlineIndexes.find(i) != -1 and i != lineStarts[currentLine]:
|
|
wrappedText += "\n";
|
|
wrappedText += text[i];
|
|
|
|
label.advancedText = wrappedText;
|
|
label.fit_content = false;
|
|
label.visible_characters = 0;
|
|
|
|
if lineStarts.size() > currentLine + VISIBLE_LINES:
|
|
isMoreViews = true;
|
|
|
|
func setText(text:String) -> void:
|
|
self.text = text;
|
|
if text == "":
|
|
self.visible = false;
|
|
return;
|
|
|
|
isClosed = false;
|
|
revealTimer = 0;
|
|
visibleCharacters = 0;
|
|
currentLine = 0;
|
|
currentViewScrolled = false;
|
|
recalculateWrapping();
|
|
self.visible = true;
|