Added footsteps, new tree, various other tweaks
This commit is contained in:
284
addons/proton_scatter/src/documentation/documentation.gd
Normal file
284
addons/proton_scatter/src/documentation/documentation.gd
Normal file
@@ -0,0 +1,284 @@
|
||||
@tool
|
||||
extends PopupPanel
|
||||
|
||||
|
||||
# Formats and displays the DocumentationData provided by other parts of the addon
|
||||
# TODO: Adjust title font size based on the editor font size / scaling
|
||||
|
||||
|
||||
const DocumentationInfo = preload("./documentation_info.gd")
|
||||
const SpecialPages = preload("./pages/special_pages.gd")
|
||||
|
||||
var _pages := {}
|
||||
var _items := {}
|
||||
var _categories_roots := {}
|
||||
|
||||
var _modifiers_root: TreeItem
|
||||
|
||||
var _edited_text: String
|
||||
var _accent_color := Color.CORNFLOWER_BLUE
|
||||
var _editor_scale := 1.0
|
||||
var _header_size := 20
|
||||
var _sub_header_size := 16
|
||||
|
||||
var _populated := false
|
||||
|
||||
|
||||
@onready var tree: Tree = $HSplitContainer/Tree
|
||||
@onready var label: RichTextLabel = $HSplitContainer/RichTextLabel
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
tree.create_item() # Create tree root
|
||||
tree.hide_root = true
|
||||
tree.item_selected.connect(_on_item_selected)
|
||||
|
||||
add_page(SpecialPages.get_scatter_documentation(), tree.create_item())
|
||||
add_page(SpecialPages.get_item_documentation(), tree.create_item())
|
||||
add_page(SpecialPages.get_shape_documentation(), tree.create_item())
|
||||
add_page(SpecialPages.get_cache_documentation(), tree.create_item())
|
||||
|
||||
_modifiers_root = tree.create_item()
|
||||
add_page(SpecialPages.get_modifiers_documentation(), _modifiers_root)
|
||||
|
||||
_populate()
|
||||
|
||||
|
||||
# Fed from the StackPanel scene, before the ready function
|
||||
func set_editor_plugin(editor_plugin: EditorPlugin) -> void:
|
||||
if not editor_plugin:
|
||||
return
|
||||
|
||||
var editor_interface := editor_plugin.get_editor_interface()
|
||||
var editor_settings := editor_interface.get_editor_settings()
|
||||
|
||||
_accent_color = editor_settings.get("interface/theme/accent_color")
|
||||
_editor_scale = editor_interface.get_editor_scale()
|
||||
|
||||
|
||||
func show_page(page_name: String) -> void:
|
||||
if not page_name in _items:
|
||||
return
|
||||
|
||||
var item: TreeItem = _items[page_name]
|
||||
item.select(0)
|
||||
popup_centered(Vector2i(900, 600))
|
||||
|
||||
|
||||
# Generate a formatted string from the DocumentationInfo input.
|
||||
# This string will be stored and later displayed in the RichTextLabel so we
|
||||
# we don't have to regenerate it everytime we look at another page.
|
||||
func add_page(info: DocumentationInfo, item: TreeItem = null) -> void:
|
||||
if not item:
|
||||
var root: TreeItem = _get_or_create_tree_root(info.get_category())
|
||||
item = tree.create_item(root)
|
||||
|
||||
item.set_text(0, info.get_title())
|
||||
|
||||
_begin_formatting()
|
||||
|
||||
# Page title
|
||||
_format_title(info.get_title())
|
||||
|
||||
# Paragraphs
|
||||
for p in info.get_paragraphs():
|
||||
_format_paragraph(p)
|
||||
|
||||
# Parameters
|
||||
if not info.get_parameters().is_empty():
|
||||
_format_subtitle("Parameters")
|
||||
|
||||
for p in info.get_parameters():
|
||||
_format_parameter(p)
|
||||
|
||||
# Warnings
|
||||
if not info.get_warnings().is_empty():
|
||||
_format_subtitle("Warnings")
|
||||
|
||||
for w in info.get_warnings():
|
||||
_format_warning(w)
|
||||
|
||||
_pages[item] = _get_formatted_text()
|
||||
_items[info.get_title()] = item
|
||||
|
||||
|
||||
func _populate():
|
||||
if _populated: # Already generated the documentation pages
|
||||
return
|
||||
|
||||
var path = _get_root_folder() + "/src/modifiers/"
|
||||
var result := {}
|
||||
_discover_modifiers_recursive(path, result)
|
||||
|
||||
var names := result.keys()
|
||||
names.sort()
|
||||
|
||||
for n in names:
|
||||
var info = result[n]
|
||||
add_page(info)
|
||||
|
||||
_populated = true
|
||||
|
||||
|
||||
func _discover_modifiers_recursive(path, result) -> void:
|
||||
var dir = DirAccess.open(path)
|
||||
dir.list_dir_begin()
|
||||
var path_root = dir.get_current_dir() + "/"
|
||||
|
||||
while true:
|
||||
var file = dir.get_next()
|
||||
if file == "":
|
||||
break
|
||||
if file == "base_modifier.gd":
|
||||
continue
|
||||
if dir.current_is_dir():
|
||||
_discover_modifiers_recursive(path_root + file, result)
|
||||
continue
|
||||
if not file.ends_with(".gd") and not file.ends_with(".gdc"):
|
||||
continue
|
||||
|
||||
var full_path = path_root + file
|
||||
var script = load(full_path)
|
||||
if not script or not script.can_instantiate():
|
||||
print("Error: Failed to load script ", file)
|
||||
continue
|
||||
|
||||
var modifier = script.new()
|
||||
|
||||
var info: DocumentationInfo = modifier.documentation
|
||||
info.set_title(modifier.display_name)
|
||||
info.set_category(modifier.category)
|
||||
if modifier.use_edge_data:
|
||||
info.add_warning(
|
||||
"This modifier uses edge data (represented by the blue lines
|
||||
on the Scatter node). These edges are usually locked to the
|
||||
local XZ plane, (except for the Path shape when they are
|
||||
NOT closed). If you can't see these lines, make sure to have at
|
||||
least one Shape crossing the ProtonScatter local XZ plane.",
|
||||
1)
|
||||
|
||||
if modifier.deprecated:
|
||||
info.add_warning(
|
||||
"This modifier has been deprecated. It won't receive any updates
|
||||
and will be deleted in a future update.",
|
||||
2)
|
||||
|
||||
result[modifier.display_name] = info
|
||||
|
||||
dir.list_dir_end()
|
||||
|
||||
|
||||
func _get_root_folder() -> String:
|
||||
var script: Script = get_script()
|
||||
var path: String = script.get_path().get_base_dir()
|
||||
var folders = path.right(-6) # Remove the res://
|
||||
var tokens = folders.split('/')
|
||||
return "res://" + tokens[0] + "/" + tokens[1]
|
||||
|
||||
|
||||
func _get_or_create_tree_root(root_name: String) -> TreeItem:
|
||||
if root_name in _categories_roots:
|
||||
return _categories_roots[root_name]
|
||||
|
||||
var root = tree.create_item(_modifiers_root)
|
||||
root.set_text(0, root_name)
|
||||
root.set_selectable(0, false)
|
||||
_categories_roots[root_name] = root
|
||||
return root
|
||||
|
||||
|
||||
func _begin_formatting() -> void:
|
||||
_edited_text = ""
|
||||
|
||||
|
||||
func _get_formatted_text() -> String:
|
||||
return _edited_text
|
||||
|
||||
|
||||
func _format_title(text: String) -> void:
|
||||
_edited_text += "[font_size=" + var_to_str(_header_size * _editor_scale) + "]"
|
||||
_edited_text += "[color=" + _accent_color.to_html() + "]"
|
||||
_edited_text += "[center][b]"
|
||||
_edited_text += text
|
||||
_edited_text += "[/b][/center]"
|
||||
_edited_text += "[/color]"
|
||||
_edited_text += "[/font_size]"
|
||||
_format_line_break(2)
|
||||
|
||||
|
||||
func _format_subtitle(text: String) -> void:
|
||||
_edited_text += "[font_size=" + var_to_str(_header_size * _editor_scale) + "]"
|
||||
_edited_text += "[color=" + _accent_color.to_html() + "]"
|
||||
_edited_text += "[b]" + text + "[/b]"
|
||||
_edited_text += "[/color]"
|
||||
_edited_text += "[/font_size]"
|
||||
_format_line_break(2)
|
||||
|
||||
|
||||
func _format_line_break(count := 1) -> void:
|
||||
for i in count:
|
||||
_edited_text += "\n"
|
||||
|
||||
|
||||
func _format_paragraph(text: String) -> void:
|
||||
_edited_text += "[p]" + text + "[/p]"
|
||||
_format_line_break(2)
|
||||
|
||||
|
||||
func _format_parameter(p) -> void:
|
||||
var root_folder = _get_root_folder()
|
||||
|
||||
_edited_text += "[indent]"
|
||||
|
||||
if not p.type.is_empty():
|
||||
var file_name = p.type.to_lower() + ".svg"
|
||||
_edited_text += "[img]" + root_folder + "/icons/types/" + file_name + "[/img] "
|
||||
|
||||
_edited_text += "[b]" + p.name + "[/b] "
|
||||
|
||||
match p.cost:
|
||||
1:
|
||||
_edited_text += "[img]" + root_folder + "/icons/arrow_log.svg[/img]"
|
||||
2:
|
||||
_edited_text += "[img]" + root_folder + "/icons/arrow_linear.svg[/img]"
|
||||
3:
|
||||
_edited_text += "[img]" + root_folder + "/icons/arrow_exp.svg[/img]"
|
||||
|
||||
_format_line_break(2)
|
||||
_edited_text += "[indent]" + p.description + "[/indent]"
|
||||
_format_line_break(2)
|
||||
|
||||
for warning in p.warnings:
|
||||
if not warning.text.is_empty():
|
||||
_format_warning(warning)
|
||||
|
||||
_edited_text += "[/indent]"
|
||||
|
||||
|
||||
func _format_warning(w, indent := true) -> void:
|
||||
if indent:
|
||||
_edited_text += "[indent]"
|
||||
|
||||
var color := "Darkgray"
|
||||
match w.importance:
|
||||
1:
|
||||
color = "yellow"
|
||||
2:
|
||||
color = "red"
|
||||
|
||||
_edited_text += "[color=" + color + "][i]" + w.text + "[/i][/color]\n"
|
||||
|
||||
if indent:
|
||||
_edited_text += "[/indent]"
|
||||
|
||||
_format_line_break(1)
|
||||
|
||||
|
||||
func _on_item_selected() -> void:
|
||||
var selected: TreeItem = tree.get_selected()
|
||||
|
||||
if _pages.has(selected):
|
||||
var text: String = _pages[selected]
|
||||
label.set_text(text)
|
||||
else:
|
||||
label.set_text("[center] Under construction [/center]")
|
||||
Reference in New Issue
Block a user