From 812bf10f6beda1beb483c199353fe7c2864b5026 Mon Sep 17 00:00:00 2001 From: Jowan-Spooner <42868150+Jowan-Spooner@users.noreply.github.com> Date: Wed, 10 Jan 2024 18:37:31 +0100 Subject: [PATCH] Multiple fixes (#2013) - fixes #2008 - fixes #2007 - fixes #2003 - partially adresses #1995 - also cleans up character and timeline resource scripts --- addons/dialogic/Editor/Events/BranchEnd.gd | 4 +- .../VisualEditor/timeline_editor_visual.gd | 6 +- .../Base_TextBubble/text_bubble_base.tscn | 13 +- .../Layer_VN_Choices/vn_choice_layer.tscn | 2 +- .../Layer_VN_Textbox/vn_textbox_layer.tscn | 52 ++++---- addons/dialogic/Resources/character.gd | 32 ++--- addons/dialogic/Resources/timeline.gd | 120 ++++++------------ 7 files changed, 94 insertions(+), 135 deletions(-) diff --git a/addons/dialogic/Editor/Events/BranchEnd.gd b/addons/dialogic/Editor/Events/BranchEnd.gd index 45ba445c4..a5ddd0687 100644 --- a/addons/dialogic/Editor/Events/BranchEnd.gd +++ b/addons/dialogic/Editor/Events/BranchEnd.gd @@ -9,7 +9,7 @@ var parent_node : Control = null var end_control :Control = null # Indent -var indent_size := 15 +var indent_size := 22 var current_indent_level := 1 func _ready() -> void: @@ -51,7 +51,7 @@ func update_hidden_events_indicator(hidden_events_count:int = 0) -> void: ## Called by the visual timeline editor func set_indent(indent: int) -> void: - $Indent.custom_minimum_size = Vector2(indent_size * indent, 0) + $Indent.custom_minimum_size = Vector2(indent_size * indent*DialogicUtil.get_editor_scale(), 0) $Indent.visible = indent != 0 current_indent_level = indent queue_redraw() diff --git a/addons/dialogic/Editor/TimelineEditor/VisualEditor/timeline_editor_visual.gd b/addons/dialogic/Editor/TimelineEditor/VisualEditor/timeline_editor_visual.gd index 43fe5cd86..aa998b3a3 100644 --- a/addons/dialogic/Editor/TimelineEditor/VisualEditor/timeline_editor_visual.gd +++ b/addons/dialogic/Editor/TimelineEditor/VisualEditor/timeline_editor_visual.gd @@ -904,7 +904,11 @@ func _on_event_popup_menu_index_pressed(index:int) -> void: offset_blocks_by_index(selected_items, +1) elif index == 8: - var events_indexed := get_events_indexed([item]) + var events_indexed : Dictionary + if item in selected_items: + events_indexed = get_events_indexed(selected_items) + else: + events_indexed = get_events_indexed([item]) TimelineUndoRedo.create_action("[D] Deleting 1 event.") TimelineUndoRedo.add_do_method(delete_events_indexed.bind(events_indexed)) TimelineUndoRedo.add_undo_method(add_events_indexed.bind(events_indexed)) diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.tscn index 3889b3216..312c47185 100644 --- a/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.tscn +++ b/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.tscn @@ -22,15 +22,16 @@ anchors_preset = 2 anchor_top = 1.0 anchor_bottom = 1.0 offset_left = 13.0 -offset_top = -210.0 -offset_right = 647.0 +offset_top = -227.0 +offset_right = 836.0 offset_bottom = -16.0 grow_vertical = 0 bbcode_enabled = true text = "This is a fallback bubble, that is not actually connected to any character. In game use the following code to add speech bubbles to a character: [color=darkgray] -var layout = Dialogic.start(@timeline_path) -layout.register_character(@character_resource, @node) +var layout = Dialogic.start(timeline_path) +layout.register_character(character_resource, node) [/color] -[color=lightblue]@character_resource[/color] should be a loaded DialogicCharacter (a .dtl file) -[color=lightblue]@node[/color] should be the 2D node the bubble should point at." +[color=lightblue]@character_resource[/color] should be a loaded DialogicCharacter (a .dch file). +[color=lightblue]@node[/color] should be the 2D node the bubble should point at. + -> E.g. [color=darkgray]layout.register_character(load(\"res://path/to/my/character.dch\"), $BubbleMarker)" diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.tscn index c5e345855..75482d9e0 100644 --- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.tscn +++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.tscn @@ -8,7 +8,7 @@ [sub_resource type="AudioStream" id="AudioStream_pe27w"] -[node name="VN_Choice_Layer" type="Control"] +[node name="VN_ChoiceLayer" type="Control"] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.tscn index 263440079..f8f8e4203 100644 --- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.tscn +++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.tscn @@ -16,7 +16,7 @@ length = 0.001 tracks/0/type = "value" tracks/0/imported = false tracks/0/enabled = true -tracks/0/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:position") +tracks/0/path = NodePath("Anchor/AnimationParent:position") tracks/0/interp = 1 tracks/0/loop_wrap = true tracks/0/keys = { @@ -28,7 +28,7 @@ tracks/0/keys = { tracks/1/type = "value" tracks/1/imported = false tracks/1/enabled = true -tracks/1/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:rotation") +tracks/1/path = NodePath("Anchor/AnimationParent:rotation") tracks/1/interp = 1 tracks/1/loop_wrap = true tracks/1/keys = { @@ -40,7 +40,7 @@ tracks/1/keys = { tracks/2/type = "value" tracks/2/imported = false tracks/2/enabled = true -tracks/2/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:scale") +tracks/2/path = NodePath("Anchor/AnimationParent:scale") tracks/2/interp = 1 tracks/2/loop_wrap = true tracks/2/keys = { @@ -52,7 +52,7 @@ tracks/2/keys = { tracks/3/type = "value" tracks/3/imported = false tracks/3/enabled = true -tracks/3/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:modulate") +tracks/3/path = NodePath("Anchor/AnimationParent:modulate") tracks/3/interp = 1 tracks/3/loop_wrap = true tracks/3/keys = { @@ -64,7 +64,7 @@ tracks/3/keys = { tracks/4/type = "bezier" tracks/4/imported = false tracks/4/enabled = true -tracks/4/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel:rotation") +tracks/4/path = NodePath("Anchor/AnimationParent/Sizer/DialogTextPanel:rotation") tracks/4/interp = 1 tracks/4/loop_wrap = true tracks/4/keys = { @@ -79,7 +79,7 @@ length = 0.4 tracks/0/type = "bezier" tracks/0/imported = false tracks/0/enabled = true -tracks/0/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel:rotation") +tracks/0/path = NodePath("Anchor/AnimationParent/Sizer/DialogTextPanel:rotation") tracks/0/interp = 1 tracks/0/loop_wrap = true tracks/0/keys = { @@ -94,7 +94,7 @@ length = 0.7 tracks/0/type = "value" tracks/0/imported = false tracks/0/enabled = true -tracks/0/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:position") +tracks/0/path = NodePath("Anchor/AnimationParent:position") tracks/0/interp = 2 tracks/0/loop_wrap = true tracks/0/keys = { @@ -106,7 +106,7 @@ tracks/0/keys = { tracks/1/type = "value" tracks/1/imported = false tracks/1/enabled = true -tracks/1/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:modulate") +tracks/1/path = NodePath("Anchor/AnimationParent:modulate") tracks/1/interp = 1 tracks/1/loop_wrap = true tracks/1/keys = { @@ -118,7 +118,7 @@ tracks/1/keys = { tracks/2/type = "value" tracks/2/imported = false tracks/2/enabled = true -tracks/2/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:rotation") +tracks/2/path = NodePath("Anchor/AnimationParent:rotation") tracks/2/interp = 1 tracks/2/loop_wrap = true tracks/2/keys = { @@ -130,7 +130,7 @@ tracks/2/keys = { tracks/3/type = "value" tracks/3/imported = false tracks/3/enabled = true -tracks/3/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:scale") +tracks/3/path = NodePath("Anchor/AnimationParent:scale") tracks/3/interp = 1 tracks/3/loop_wrap = true tracks/3/keys = { @@ -146,7 +146,7 @@ length = 0.3 tracks/0/type = "value" tracks/0/imported = false tracks/0/enabled = true -tracks/0/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:position") +tracks/0/path = NodePath("Anchor/AnimationParent:position") tracks/0/interp = 2 tracks/0/loop_wrap = true tracks/0/keys = { @@ -158,7 +158,7 @@ tracks/0/keys = { tracks/1/type = "value" tracks/1/imported = false tracks/1/enabled = true -tracks/1/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:rotation") +tracks/1/path = NodePath("Anchor/AnimationParent:rotation") tracks/1/interp = 2 tracks/1/loop_wrap = true tracks/1/keys = { @@ -170,7 +170,7 @@ tracks/1/keys = { tracks/2/type = "value" tracks/2/imported = false tracks/2/enabled = true -tracks/2/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:scale") +tracks/2/path = NodePath("Anchor/AnimationParent:scale") tracks/2/interp = 2 tracks/2/loop_wrap = true tracks/2/keys = { @@ -182,7 +182,7 @@ tracks/2/keys = { tracks/3/type = "value" tracks/3/imported = false tracks/3/enabled = true -tracks/3/path = NodePath("DialogicTextAnchor/DialogTextAnimationParent:modulate") +tracks/3/path = NodePath("Anchor/AnimationParent:modulate") tracks/3/interp = 1 tracks/3/loop_wrap = true tracks/3/keys = { @@ -202,7 +202,7 @@ _data = { [sub_resource type="FontVariation" id="FontVariation_v8y64"] -[node name="VN_Textbox_Layer" type="Control"] +[node name="VN_TextboxLayer" type="Control"] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -224,7 +224,7 @@ libraries = { autoplay = "RESET" script = ExtResource("2_xy7a2") -[node name="DialogicTextAnchor" type="Control" parent="."] +[node name="Anchor" type="Control" parent="."] layout_mode = 1 anchors_preset = 7 anchor_left = 0.5 @@ -234,7 +234,7 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 0 -[node name="DialogTextAnimationParent" type="Control" parent="DialogicTextAnchor"] +[node name="AnimationParent" type="Control" parent="Anchor"] layout_mode = 1 anchors_preset = 7 anchor_left = 0.5 @@ -245,7 +245,7 @@ grow_horizontal = 2 grow_vertical = 0 mouse_filter = 2 -[node name="Sizer" type="Control" parent="DialogicTextAnchor/DialogTextAnimationParent"] +[node name="Sizer" type="Control" parent="Anchor/AnimationParent"] unique_name_in_owner = true layout_mode = 1 anchors_preset = 7 @@ -259,7 +259,7 @@ offset_right = 150.0 grow_horizontal = 2 grow_vertical = 0 -[node name="DialogTextPanel" type="PanelContainer" parent="DialogicTextAnchor/DialogTextAnimationParent/Sizer"] +[node name="DialogTextPanel" type="PanelContainer" parent="Anchor/AnimationParent/Sizer"] unique_name_in_owner = true self_modulate = Color(0.00784314, 0.00784314, 0.00784314, 0.843137) custom_minimum_size = Vector2(300, 50) @@ -273,7 +273,7 @@ mouse_filter = 2 theme_override_styles/panel = ExtResource("3_ssa84") metadata/_edit_layout_mode = 1 -[node name="DialogicNode_DialogText" type="RichTextLabel" parent="DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel" node_paths=PackedStringArray("textbox_root")] +[node name="DialogicNode_DialogText" type="RichTextLabel" parent="Anchor/AnimationParent/Sizer/DialogTextPanel" node_paths=PackedStringArray("textbox_root")] unique_name_in_owner = true layout_mode = 2 mouse_filter = 1 @@ -288,12 +288,12 @@ visible_characters_behavior = 1 script = ExtResource("3_4634k") textbox_root = NodePath("..") -[node name="DialogicNode_TypeSounds" type="AudioStreamPlayer" parent="DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel/DialogicNode_DialogText"] +[node name="DialogicNode_TypeSounds" type="AudioStreamPlayer" parent="Anchor/AnimationParent/Sizer/DialogTextPanel/DialogicNode_DialogText"] unique_name_in_owner = true script = ExtResource("4_ma5mw") play_every_character = 0 -[node name="NextIndicator" type="Control" parent="DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel"] +[node name="NextIndicator" type="Control" parent="Anchor/AnimationParent/Sizer/DialogTextPanel"] unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 8 @@ -303,7 +303,7 @@ show_on_questions = true texture = ExtResource("6_uch03") metadata/_edit_layout_mode = 1 -[node name="AutoAdvanceProgressbar" type="ProgressBar" parent="DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel"] +[node name="AutoAdvanceProgressbar" type="ProgressBar" parent="Anchor/AnimationParent/Sizer/DialogTextPanel"] unique_name_in_owner = true modulate = Color(1, 1, 1, 0.188235) custom_minimum_size = Vector2(0, 10) @@ -315,11 +315,11 @@ value = 0.5 show_percentage = false script = ExtResource("6_07xym") -[node name="NameLabelHolder" type="Control" parent="DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel"] +[node name="NameLabelHolder" type="Control" parent="Anchor/AnimationParent/Sizer/DialogTextPanel"] layout_mode = 2 mouse_filter = 2 -[node name="NameLabelPanel" type="PanelContainer" parent="DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel/NameLabelHolder"] +[node name="NameLabelPanel" type="PanelContainer" parent="Anchor/AnimationParent/Sizer/DialogTextPanel/NameLabelHolder"] unique_name_in_owner = true self_modulate = Color(0.00784314, 0.00784314, 0.00784314, 0.843137) layout_mode = 1 @@ -331,7 +331,7 @@ metadata/_edit_layout_mode = 1 metadata/_edit_use_custom_anchors = true metadata/_edit_group_ = true -[node name="DialogicNode_NameLabel" type="Label" parent="DialogicTextAnchor/DialogTextAnimationParent/Sizer/DialogTextPanel/NameLabelHolder/NameLabelPanel" node_paths=PackedStringArray("name_label_root")] +[node name="DialogicNode_NameLabel" type="Label" parent="Anchor/AnimationParent/Sizer/DialogTextPanel/NameLabelHolder/NameLabelPanel" node_paths=PackedStringArray("name_label_root")] unique_name_in_owner = true layout_mode = 2 theme_override_colors/font_color = Color(1, 1, 1, 1) diff --git a/addons/dialogic/Resources/character.gd b/addons/dialogic/Resources/character.gd index 012fcbaad..8327b2d1c 100644 --- a/addons/dialogic/Resources/character.gd +++ b/addons/dialogic/Resources/character.gd @@ -3,20 +3,23 @@ extends Resource class_name DialogicCharacter -@export var display_name:String = "" -@export var nicknames:Array = [] +## Resource that represents a character in dialog. +## Manages/contains portraits, custom info and translation of characters. -@export var color:Color = Color() -@export var description:String = "" +@export var display_name := "" +@export var nicknames := [] -@export var scale:float = 1.0 -@export var offset:Vector2 = Vector2() -@export var mirror:bool = false +@export var color := Color() +@export var description := "" -@export var default_portrait:String = "" -@export var portraits:Dictionary = {} +@export var scale := 1.0 +@export var offset := Vector2() +@export var mirror := false -@export var custom_info:Dictionary = {} +@export var default_portrait := "" +@export var portraits := {} + +@export var custom_info := {} ## All valid properties that can be accessed by their translation. enum TranslatedProperties { @@ -24,17 +27,12 @@ enum TranslatedProperties { NICKNAMES, } -var _translation_id: String = "" - -func __get_property_list() -> Array: - return [] +var _translation_id := "" func _to_string() -> String: return "[{name}:{id}]".format({"name":get_character_name(), "id":get_instance_id()}) -func _hide_script_from_inspector() -> bool: - return true ## This is automatically called, no need to use this. func add_translation_id() -> String: @@ -45,6 +43,7 @@ func add_translation_id() -> String: func remove_translation_id() -> void: _translation_id = "" + ## Checks [param property] and matches it to a translation key. ## ## Undefined behaviour if an invalid integer is passed. @@ -123,6 +122,7 @@ func get_character_name() -> String: else: return "UnnamedCharacter" + ## Returns the info of the given portrait. ## Uses the default portrait if the given portrait doesn't exist. func get_portrait_info(portrait_name:String) -> Dictionary: diff --git a/addons/dialogic/Resources/timeline.gd b/addons/dialogic/Resources/timeline.gd index 4108502ab..5bfdf8433 100644 --- a/addons/dialogic/Resources/timeline.gd +++ b/addons/dialogic/Resources/timeline.gd @@ -2,95 +2,49 @@ extends Resource class_name DialogicTimeline +## Resource that defines a list of events. +## It can store them as text and load them from text too. -var events:Array = []: - get: - return events - set(value): - emit_changed() - notify_property_list_changed() - events = value - -var events_processed:bool = false - - -func get_event(index): - if index >= len(events): - return null - return events[index] - - -func _set(property, value): - if str(property).begins_with("event/"): - var event_idx:int = str(property).split("/", true, 2)[1].to_int() - if event_idx < events.size(): - events[event_idx] = value - else: - events.insert(event_idx, value) - - emit_changed() - notify_property_list_changed() - - return false - - -func _get(property): - if str(property).begins_with("event/"): - var event_idx:int = str(property).split("/", true, 2)[1].to_int() - if event_idx < len(events): - return events[event_idx] - return true - - -func _init() -> void: - events = [] - resource_name = get_class() +var events: Array = [] +var events_processed: bool = false +## Method used for printing timeline resources identifiably func _to_string() -> String: return "[DialogicTimeline:{file}]".format({"file":resource_path}) -func _get_property_list() -> Array: - var p : Array = [] - var usage = PROPERTY_USAGE_SCRIPT_VARIABLE - usage |= PROPERTY_USAGE_NO_EDITOR - usage |= PROPERTY_USAGE_EDITOR # Comment this line to hide events from editor - if events != null: - for event_idx in events.size(): - p.append( - { - "name":"event/{idx}".format({"idx":event_idx}), - "type":TYPE_OBJECT, - "usage":PROPERTY_USAGE_DEFAULT|PROPERTY_USAGE_SCRIPT_VARIABLE - } - ) - return p +## Helper method +func get_event(index:int) -> Variant: + if index >= len(events): + return null + return events[index] +## Parses the lines as seperate events and insert them in an array, +## so they can be converted to DialogicEvent's when processed later func from_text(text:String) -> void: - # Parse the lines as seperate events and insert them in an array, so they can be converted to DialogicEvent's when processed later - events = text.split('\n', true) events_processed = false +## Stores all events in their text format and returns them as a string func as_text() -> String: - var result:String = "" + var result: String = "" if events_processed: var indent := 0 for idx in range(0, len(events)): var event = events[idx] - if event['event_name'] == 'End Branch': + if event.event_name == 'End Branch': indent -= 1 continue if event != null: for i in event.empty_lines_above: result += "\t".repeat(indent)+"\n" - result += "\t".repeat(indent)+event['event_node_as_text'].replace('\n', "\n"+"\t".repeat(indent)) + "\n" + result += "\t".repeat(indent)+event.event_node_as_text.replace('\n', "\n"+"\t".repeat(indent)) + "\n" if event.can_contain_events: indent += 1 if indent < 0: @@ -104,6 +58,7 @@ func as_text() -> String: return result.strip_edges() +## Method that loads all the event resources from the strings, if it wasn't done before func process() -> void: if typeof(events[0]) == TYPE_STRING: events_processed = false @@ -118,46 +73,46 @@ func process() -> void: var end_event := DialogicEndBranchEvent.new() var prev_indent := "" - var _events := [] + var processed_events := [] # this is needed to add an end branch event even to empty conditions/choices var prev_was_opener := false var lines := events var idx := -1 - var empty_lines = 0 + var empty_lines := 0 while idx < len(lines)-1: idx += 1 # make sure we are using the string version, in case this was already converted - var line: String = "" + var line := "" if typeof(lines[idx]) == TYPE_STRING: line = lines[idx] else: - line = lines[idx]['event_node_as_text'] + line = lines[idx].event_node_as_text - # ignore empty lines, but record them in @empty_lines + ## Ignore empty lines, but record them in @empty_lines var line_stripped :String = line.strip_edges(true, false) if line_stripped.is_empty(): empty_lines += 1 continue - ## Add an end event if the indent is smaller then previously - var indent :String= line.substr(0,len(line)-len(line_stripped)) + var indent: String = line.substr(0,len(line)-len(line_stripped)) if len(indent) < len(prev_indent): for i in range(len(prev_indent)-len(indent)): - _events.append(end_event.duplicate()) - # Add an end event if the indent is the same but the previous was an opener - # (so for example choice that is empty) + processed_events.append(end_event.duplicate()) + ## Add an end event if the indent is the same but the previous was an opener + ## (so for example choice that is empty) if prev_was_opener and len(indent) <= len(prev_indent): - _events.append(end_event.duplicate()) + processed_events.append(end_event.duplicate()) + prev_indent = indent ## Now we process the event into a resource ## by checking on each event if it recognizes this string - var event_content :String = line_stripped - var event :Variant + var event_content: String = line_stripped + var event: DialogicEvent for i in event_cache: if i._test_event_string(event_content): event = i.duplicate() @@ -169,9 +124,9 @@ func process() -> void: idx += 1 if idx == len(lines): break - var following_line :String = lines[idx] - var following_line_stripped :String = following_line.strip_edges(true, false) - var following_line_indent :String = following_line.substr(0,len(following_line)-len(following_line_stripped)) + var following_line: String = lines[idx] + var following_line_stripped: String = following_line.strip_edges(true, false) + var following_line_indent: String = following_line.substr(0,len(following_line)-len(following_line_stripped)) if following_line_stripped.is_empty(): break if following_line_indent != indent: @@ -180,16 +135,15 @@ func process() -> void: event_content += "\n"+following_line_stripped event._load_from_string(event_content) - event['event_node_as_text'] = event_content + event.event_node_as_text = event_content - _events.append(event) + processed_events.append(event) prev_was_opener = event.can_contain_events empty_lines = 0 - if !prev_indent.is_empty(): for i in range(len(prev_indent)): - _events.append(end_event.duplicate()) + processed_events.append(end_event.duplicate()) - events = _events + events = processed_events events_processed = true