mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
add node menu (#3)
we finally have a way to add nodes from a menu!! lets goooooooo Reviewed-on: https://codeberg.org/Eroax/Re-DotDeck/pulls/3 Co-authored-by: Lera Elvoé <yagich@poto.cafe> Co-committed-by: Lera Elvoé <yagich@poto.cafe>
This commit is contained in:
parent
882d817310
commit
eeb509cae0
24 changed files with 891 additions and 61 deletions
|
@ -15,6 +15,8 @@ var node_type: String
|
||||||
|
|
||||||
var description: String
|
var description: String
|
||||||
var aliases: Array[String]
|
var aliases: Array[String]
|
||||||
|
var category: String
|
||||||
|
var appears_in_search: bool = true
|
||||||
|
|
||||||
var props_to_serialize: Array[StringName]
|
var props_to_serialize: Array[StringName]
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,16 @@ extends Node
|
||||||
|
|
||||||
const BASE_NODE_PATH := "res://classes/deck/nodes/"
|
const BASE_NODE_PATH := "res://classes/deck/nodes/"
|
||||||
const NODE_INDEX_CACHE_PATH := "user://nodes_index.json"
|
const NODE_INDEX_CACHE_PATH := "user://nodes_index.json"
|
||||||
|
const FAVORITE_NODES_PATH := "user://favorite_nodes.json"
|
||||||
|
|
||||||
|
var favorite_nodes: Array[String]
|
||||||
|
|
||||||
# Dictionary[node_type, NodeDescriptor]
|
# Dictionary[node_type, NodeDescriptor]
|
||||||
var nodes: Dictionary = {}
|
var nodes: Dictionary = {}
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
|
load_favorites()
|
||||||
#if load_node_index():
|
#if load_node_index():
|
||||||
#return
|
#return
|
||||||
|
|
||||||
|
@ -23,7 +27,15 @@ func _init() -> void:
|
||||||
func(accum, el) -> void:
|
func(accum, el) -> void:
|
||||||
accum += el
|
accum += el
|
||||||
, "")
|
, "")
|
||||||
var descriptor := NodeDescriptor.new(script_path, node.name, node.description, aliases)
|
var descriptor := NodeDescriptor.new(
|
||||||
|
script_path,
|
||||||
|
node.name,
|
||||||
|
node.node_type,
|
||||||
|
node.description,
|
||||||
|
aliases,
|
||||||
|
node.category,
|
||||||
|
node.appears_in_search,
|
||||||
|
)
|
||||||
nodes[node.node_type] = descriptor
|
nodes[node.node_type] = descriptor
|
||||||
current_file = dir.get_next()
|
current_file = dir.get_next()
|
||||||
|
|
||||||
|
@ -68,28 +80,71 @@ func load_node_index() -> bool:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func set_node_favorite(node_type: String, favorite: bool) -> void:
|
||||||
|
if (favorite && node_type in favorite_nodes) || (!favorite && !(node_type in favorite_nodes)):
|
||||||
|
return
|
||||||
|
|
||||||
|
if favorite:
|
||||||
|
favorite_nodes.append(node_type)
|
||||||
|
else:
|
||||||
|
favorite_nodes.erase(node_type)
|
||||||
|
|
||||||
|
var f := FileAccess.open(FAVORITE_NODES_PATH, FileAccess.WRITE)
|
||||||
|
f.store_string(JSON.stringify(favorite_nodes, "\t"))
|
||||||
|
|
||||||
|
|
||||||
|
func load_favorites() -> void:
|
||||||
|
var f := FileAccess.open(FAVORITE_NODES_PATH, FileAccess.READ)
|
||||||
|
if !f:
|
||||||
|
return
|
||||||
|
var data: Array = JSON.parse_string(f.get_as_text())
|
||||||
|
favorite_nodes.clear()
|
||||||
|
favorite_nodes.assign(data)
|
||||||
|
|
||||||
|
|
||||||
|
func is_node_favorite(node_type: String) -> bool:
|
||||||
|
return node_type in favorite_nodes
|
||||||
|
|
||||||
|
|
||||||
class NodeDescriptor:
|
class NodeDescriptor:
|
||||||
var name: String
|
var name: String
|
||||||
|
var type: String
|
||||||
var description: String
|
var description: String
|
||||||
var aliases: String
|
var aliases: String
|
||||||
|
var category: String
|
||||||
|
var appears_in_search: bool
|
||||||
|
|
||||||
var script_path: String
|
var script_path: String
|
||||||
|
|
||||||
|
|
||||||
func _init(p_script_path: String, p_name: String, p_description: String, p_aliases: String) -> void:
|
func _init(
|
||||||
|
p_script_path: String,
|
||||||
|
p_name: String,
|
||||||
|
p_type: String,
|
||||||
|
p_description: String,
|
||||||
|
p_aliases: String,
|
||||||
|
p_category: String,
|
||||||
|
p_appears_in_search: bool,
|
||||||
|
) -> void:
|
||||||
script_path = p_script_path
|
script_path = p_script_path
|
||||||
|
|
||||||
name = p_name
|
name = p_name
|
||||||
|
type = p_type
|
||||||
description = p_description
|
description = p_description
|
||||||
aliases = p_aliases
|
aliases = p_aliases
|
||||||
|
category = p_category
|
||||||
|
appears_in_search = p_appears_in_search
|
||||||
|
|
||||||
|
|
||||||
func to_dictionary() -> Dictionary:
|
func to_dictionary() -> Dictionary:
|
||||||
var d := {
|
var d := {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
"type": type,
|
||||||
"description": description,
|
"description": description,
|
||||||
"aliases": aliases,
|
"aliases": aliases,
|
||||||
"script_path": script_path
|
"script_path": script_path,
|
||||||
|
"category": category,
|
||||||
|
"appears_in_search": appears_in_search,
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@ -98,7 +153,11 @@ class NodeDescriptor:
|
||||||
var nd := NodeDescriptor.new(
|
var nd := NodeDescriptor.new(
|
||||||
data.get("script_path", ""),
|
data.get("script_path", ""),
|
||||||
data.get("name", ""),
|
data.get("name", ""),
|
||||||
|
data.get("type", ""),
|
||||||
data.get("description", ""),
|
data.get("description", ""),
|
||||||
data.get("aliases", ""))
|
data.get("aliases", ""),
|
||||||
|
data.get("category", ""),
|
||||||
|
data.get("appears_in_search", false),
|
||||||
|
)
|
||||||
|
|
||||||
return nd
|
return nd
|
||||||
|
|
|
@ -5,6 +5,7 @@ func _init() -> void:
|
||||||
name = "Button"
|
name = "Button"
|
||||||
node_type = "button"
|
node_type = "button"
|
||||||
description = "a button"
|
description = "a button"
|
||||||
|
category = "general"
|
||||||
|
|
||||||
add_output_port(
|
add_output_port(
|
||||||
Deck.Types.BOOL,
|
Deck.Types.BOOL,
|
||||||
|
|
|
@ -5,6 +5,7 @@ func _init() -> void:
|
||||||
name = "Get Deck Var"
|
name = "Get Deck Var"
|
||||||
node_type = name.to_snake_case()
|
node_type = name.to_snake_case()
|
||||||
description = "retrieve a deck variable"
|
description = "retrieve a deck variable"
|
||||||
|
category = "general"
|
||||||
|
|
||||||
add_output_port(
|
add_output_port(
|
||||||
Deck.Types.STRING,
|
Deck.Types.STRING,
|
||||||
|
|
|
@ -9,6 +9,7 @@ func _init() -> void:
|
||||||
name = "Group input"
|
name = "Group input"
|
||||||
node_type = "group_input"
|
node_type = "group_input"
|
||||||
props_to_serialize = [&"output_count"]
|
props_to_serialize = [&"output_count"]
|
||||||
|
appears_in_search = false
|
||||||
|
|
||||||
add_output_port(
|
add_output_port(
|
||||||
Deck.Types.STRING,
|
Deck.Types.STRING,
|
||||||
|
|
|
@ -11,6 +11,7 @@ func _init() -> void:
|
||||||
name = "Group"
|
name = "Group"
|
||||||
node_type = "group_node"
|
node_type = "group_node"
|
||||||
props_to_serialize = [&"group_id", &"extra_ports"]
|
props_to_serialize = [&"group_id", &"extra_ports"]
|
||||||
|
appears_in_search = false
|
||||||
|
|
||||||
|
|
||||||
func _pre_connection() -> void:
|
func _pre_connection() -> void:
|
||||||
|
|
|
@ -9,6 +9,7 @@ func _init() -> void:
|
||||||
name = "Group output"
|
name = "Group output"
|
||||||
node_type = "group_output"
|
node_type = "group_output"
|
||||||
props_to_serialize = [&"input_count"]
|
props_to_serialize = [&"input_count"]
|
||||||
|
appears_in_search = false
|
||||||
|
|
||||||
add_input_port(
|
add_input_port(
|
||||||
Deck.Types.STRING,
|
Deck.Types.STRING,
|
||||||
|
|
|
@ -9,6 +9,7 @@ func _init() -> void:
|
||||||
description = "print a value"
|
description = "print a value"
|
||||||
|
|
||||||
props_to_serialize = [&"times_activated"]
|
props_to_serialize = [&"times_activated"]
|
||||||
|
category = "general"
|
||||||
|
|
||||||
add_input_port(
|
add_input_port(
|
||||||
Deck.Types.STRING,
|
Deck.Types.STRING,
|
||||||
|
|
|
@ -5,6 +5,7 @@ func _init() -> void:
|
||||||
name = "Set Deck Var"
|
name = "Set Deck Var"
|
||||||
node_type = name.to_snake_case()
|
node_type = name.to_snake_case()
|
||||||
description = "set deck variable"
|
description = "set deck variable"
|
||||||
|
category = "general"
|
||||||
|
|
||||||
add_input_port(
|
add_input_port(
|
||||||
Deck.Types.STRING,
|
Deck.Types.STRING,
|
||||||
|
|
|
@ -4,6 +4,8 @@ extends DeckNode
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "string_constant"
|
node_type = "string_constant"
|
||||||
name = "String Constant"
|
name = "String Constant"
|
||||||
|
category = "general"
|
||||||
|
|
||||||
add_output_port(
|
add_output_port(
|
||||||
Deck.Types.STRING,
|
Deck.Types.STRING,
|
||||||
"Text",
|
"Text",
|
||||||
|
|
|
@ -4,6 +4,7 @@ extends DeckNode
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "test_interleaved"
|
node_type = "test_interleaved"
|
||||||
name = "Test Interleaved"
|
name = "Test Interleaved"
|
||||||
|
category = "test"
|
||||||
|
|
||||||
for i in 4:
|
for i in 4:
|
||||||
add_output_port(
|
add_output_port(
|
||||||
|
|
99
classes/deck/search_provider.gd
Normal file
99
classes/deck/search_provider.gd
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
class_name SearchProvider
|
||||||
|
|
||||||
|
static var filters: Array[Filter] = [
|
||||||
|
# favorites filter. will only show nodes marked as favorite. syntax: "#f"
|
||||||
|
Filter.new(
|
||||||
|
func(search_string: String) -> bool:
|
||||||
|
return "#f" in search_string,
|
||||||
|
|
||||||
|
func(element: NodeDB.NodeDescriptor, _search_string: String, _pre_strip_string: String) -> bool:
|
||||||
|
return NodeDB.is_node_favorite(element.type),
|
||||||
|
|
||||||
|
func(search_string: String) -> String:
|
||||||
|
return search_string.replace("#f", "")
|
||||||
|
),
|
||||||
|
|
||||||
|
# category filter. will only match nodes that are in a certain category. syntax: "#c category_name"
|
||||||
|
Filter.new(
|
||||||
|
func(search_string: String) -> bool:
|
||||||
|
const p := r"#c\s[\w]+"
|
||||||
|
var r := RegEx.create_from_string(p)
|
||||||
|
var c := r.search(search_string)
|
||||||
|
|
||||||
|
return c != null,
|
||||||
|
|
||||||
|
func(element: NodeDB.NodeDescriptor, _search_string: String, pre_strip_string: String) -> bool:
|
||||||
|
const p := r"#c\s[\w]+"
|
||||||
|
var r := RegEx.create_from_string(p)
|
||||||
|
print("pre: ", pre_strip_string)
|
||||||
|
var c := r.search(pre_strip_string).get_string().split("#c ", false)[0]
|
||||||
|
|
||||||
|
return c.is_subsequence_ofn(element.category),
|
||||||
|
|
||||||
|
func(search_string: String) -> String:
|
||||||
|
const p := r"#c\s[\w]+"
|
||||||
|
var r := RegEx.create_from_string(p)
|
||||||
|
var c := r.search(search_string).get_string()
|
||||||
|
prints("c:", c, "r:", search_string.replace(c, ""))
|
||||||
|
return search_string.replace(c, "")
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
static func search(term: String) -> Array[NodeDB.NodeDescriptor]:
|
||||||
|
var res: Array[NodeDB.NodeDescriptor] = []
|
||||||
|
|
||||||
|
var filters_to_apply := filters.filter(
|
||||||
|
func(f: Filter):
|
||||||
|
return f.should_apply.call(term)
|
||||||
|
)
|
||||||
|
var cleaned_search_string := term
|
||||||
|
# strip string of filter-specific substrings
|
||||||
|
for f: Filter in filters_to_apply:
|
||||||
|
f.pre_strip_string = cleaned_search_string
|
||||||
|
cleaned_search_string = f.strip_string.call(cleaned_search_string)
|
||||||
|
cleaned_search_string = cleaned_search_string.strip_edges()
|
||||||
|
|
||||||
|
for node_type: String in NodeDB.nodes:
|
||||||
|
var nd: NodeDB.NodeDescriptor = NodeDB.nodes[node_type]
|
||||||
|
if !nd.appears_in_search:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var full_search_string := nd.name + nd.aliases
|
||||||
|
if cleaned_search_string.is_subsequence_ofn(full_search_string):
|
||||||
|
res.append(nd)
|
||||||
|
|
||||||
|
# no filters apply, just return the results straight
|
||||||
|
if filters_to_apply.is_empty():
|
||||||
|
return res
|
||||||
|
|
||||||
|
# apply filters
|
||||||
|
var filtered_res: Array[NodeDB.NodeDescriptor] = res.duplicate()
|
||||||
|
for f: Filter in filters_to_apply:
|
||||||
|
filtered_res = filtered_res.filter(f.match_term.bind(cleaned_search_string, f.pre_strip_string))
|
||||||
|
|
||||||
|
return filtered_res
|
||||||
|
|
||||||
|
|
||||||
|
class Filter:
|
||||||
|
## Return [code]true[/code] if this filter should be applied to the search.[br]
|
||||||
|
## [code]Callable(search_string: String) -> bool[/code]
|
||||||
|
var should_apply: Callable
|
||||||
|
|
||||||
|
## Return a [code]bool[/code] if the provided [code]NodeDescriptor[/code]
|
||||||
|
## should be included in the search results array.[br]
|
||||||
|
## [code]Callable(element: NodeDB.NodeDescriptor, search_string: String, pre_strip_string: String) -> bool[/code]
|
||||||
|
var match_term: Callable
|
||||||
|
|
||||||
|
## Return a string that's stripped of this filter's shorthand.
|
||||||
|
## [code]Callable(search_string: String) -> String[/code]
|
||||||
|
var strip_string: Callable
|
||||||
|
|
||||||
|
## The search string as it was before [member strip_string] was called. Useful for filters that use arguments, like the category filter.
|
||||||
|
var pre_strip_string: String
|
||||||
|
|
||||||
|
|
||||||
|
func _init(p_should_apply: Callable, p_match_term: Callable, p_strip_string: Callable) -> void:
|
||||||
|
should_apply = p_should_apply
|
||||||
|
match_term = p_match_term
|
||||||
|
strip_string = p_strip_string
|
306
graph_node_renderer/add_node_menu.gd
Normal file
306
graph_node_renderer/add_node_menu.gd
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
extends MarginContainer
|
||||||
|
class_name AddNodeMenu
|
||||||
|
|
||||||
|
@onready var search_line_edit: LineEdit = %SearchLineEdit
|
||||||
|
@onready var scroll_content_container: VBoxContainer = %ScrollContentContainer
|
||||||
|
@onready var scroll_container: ScrollContainer = $VBoxContainer/ScrollContainer
|
||||||
|
|
||||||
|
var categories: Dictionary = {} # Dictionary[String, Category]
|
||||||
|
var collapsed_categories: Array[String]
|
||||||
|
|
||||||
|
signal node_selected(type: String)
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
search("")
|
||||||
|
|
||||||
|
|
||||||
|
func add_category(category_name: String) -> void:
|
||||||
|
var c := Category.new(category_name.capitalize())
|
||||||
|
categories[category_name] = c
|
||||||
|
scroll_content_container.add_child(c)
|
||||||
|
c.collapse_toggled.connect(_on_category_collapse_toggled.bind(category_name))
|
||||||
|
c.item_pressed.connect(
|
||||||
|
func(item: int):
|
||||||
|
node_selected.emit(c.get_item_metadata(item, "type"))
|
||||||
|
)
|
||||||
|
c.item_favorite_button_toggled.connect(
|
||||||
|
func(item: int, toggled: bool):
|
||||||
|
NodeDB.set_node_favorite(c.get_item_metadata(item, "type"), toggled)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func add_category_item(category: String, item: String, tooltip: String = "", favorite: bool = false) -> void:
|
||||||
|
var c: Category = categories[category]
|
||||||
|
c.add_item(item, tooltip, favorite)
|
||||||
|
|
||||||
|
|
||||||
|
func add_item(category: String, item: String, tooltip: String = "", favorite: bool = false) -> void:
|
||||||
|
if !categories.has(category):
|
||||||
|
add_category(category)
|
||||||
|
|
||||||
|
add_category_item(category, item, tooltip, favorite)
|
||||||
|
|
||||||
|
|
||||||
|
func get_category(category: String) -> Category:
|
||||||
|
return categories[category]
|
||||||
|
|
||||||
|
|
||||||
|
func focus_search_bar() -> void:
|
||||||
|
search_line_edit.select_all()
|
||||||
|
search_line_edit.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
|
func search(text: String) -> void:
|
||||||
|
scroll_content_container.get_children().map(func(c: Node): c.queue_free())
|
||||||
|
categories.clear()
|
||||||
|
|
||||||
|
var search_results := SearchProvider.search(text)
|
||||||
|
if search_results.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
for nd in search_results:
|
||||||
|
add_item(nd.category, nd.name, nd.description, NodeDB.is_node_favorite(nd.type))
|
||||||
|
var c := get_category(nd.category)
|
||||||
|
c.set_item_metadata(c.get_item_count() - 1, "type", nd.type)
|
||||||
|
c.set_item_metadata(c.get_item_count() - 1, "node_descriptor", weakref(nd))
|
||||||
|
c.set_collapsed(nd.category in collapsed_categories)
|
||||||
|
|
||||||
|
get_category(categories.keys()[0]).highlight_item(0)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_search_line_edit_gui_input(event: InputEvent) -> void:
|
||||||
|
if event.is_action_pressed("ui_down"):
|
||||||
|
var category: Category
|
||||||
|
for i: String in categories:
|
||||||
|
var c: Category = categories[i]
|
||||||
|
if c.get_highlighted_item() != -1:
|
||||||
|
category = c
|
||||||
|
break
|
||||||
|
var item := category.get_highlighted_item()
|
||||||
|
if item + 1 == category.get_item_count():
|
||||||
|
# reached the end of items in the current category
|
||||||
|
category.unhighlight_all()
|
||||||
|
|
||||||
|
var nc: Category
|
||||||
|
if category.get_index() + 1 == scroll_content_container.get_child_count():
|
||||||
|
# reached the end, get the first category
|
||||||
|
nc = scroll_content_container.get_child(0)
|
||||||
|
else:
|
||||||
|
# there is another category after this
|
||||||
|
nc = scroll_content_container.get_child(category.get_index() + 1)
|
||||||
|
nc.highlight_item(0)
|
||||||
|
scroll_container.ensure_control_visible(nc.get_child(0))
|
||||||
|
return
|
||||||
|
|
||||||
|
category.highlight_item(item + 1)
|
||||||
|
scroll_container.ensure_control_visible(category.get_child(item + 1))
|
||||||
|
|
||||||
|
if event.is_action_pressed("ui_up"):
|
||||||
|
var category: Category
|
||||||
|
for i: String in categories:
|
||||||
|
var c: Category = categories[i]
|
||||||
|
if c.get_highlighted_item() != -1:
|
||||||
|
category = c
|
||||||
|
break
|
||||||
|
var item := category.get_highlighted_item()
|
||||||
|
if item - 1 == -1:
|
||||||
|
# reached the beginning of items in the current category
|
||||||
|
category.unhighlight_all()
|
||||||
|
|
||||||
|
var nc: Category
|
||||||
|
if category.get_index() - 1 == -1:
|
||||||
|
# reached the beginning, get the last category
|
||||||
|
nc = scroll_content_container.get_child(scroll_content_container.get_child_count() - 1)
|
||||||
|
else:
|
||||||
|
# there is another category before this
|
||||||
|
nc = scroll_content_container.get_child(category.get_index() - 1)
|
||||||
|
nc.highlight_item(nc.get_item_count() - 1)
|
||||||
|
scroll_container.ensure_control_visible(nc.get_child(nc.get_item_count() - 1))
|
||||||
|
return
|
||||||
|
|
||||||
|
category.highlight_item(item - 1)
|
||||||
|
scroll_container.ensure_control_visible(category.get_child(item - 1))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_search_line_edit_text_submitted(_new_text: String) -> void:
|
||||||
|
var category: Category
|
||||||
|
for i: String in categories:
|
||||||
|
var c: Category = categories[i]
|
||||||
|
if c.get_highlighted_item() != -1:
|
||||||
|
category = c
|
||||||
|
break
|
||||||
|
node_selected.emit(category.get_item_metadata(category.get_highlighted_item(), "type"))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_category_collapse_toggled(collapsed: bool, category: String) -> void:
|
||||||
|
if collapsed:
|
||||||
|
collapsed_categories.append(category)
|
||||||
|
else:
|
||||||
|
collapsed_categories.erase(category)
|
||||||
|
|
||||||
|
|
||||||
|
class Category extends VBoxContainer:
|
||||||
|
const COLLAPSE_ICON := preload("res://graph_node_renderer/textures/collapse-icon.svg")
|
||||||
|
const COLLAPSE_ICON_COLLAPSED := preload("res://graph_node_renderer/textures/collapse-icon-collapsed.svg")
|
||||||
|
|
||||||
|
var collapse_button: Button
|
||||||
|
|
||||||
|
signal item_pressed(item: int)
|
||||||
|
signal item_favorite_button_toggled(item: int, toggled: bool)
|
||||||
|
signal collapse_toggled(collapsed: bool)
|
||||||
|
|
||||||
|
|
||||||
|
func _init(p_name: String) -> void:
|
||||||
|
collapse_button = Button.new()
|
||||||
|
collapse_button.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||||
|
collapse_button.icon = COLLAPSE_ICON
|
||||||
|
collapse_button.toggle_mode = true
|
||||||
|
collapse_button.flat = true
|
||||||
|
collapse_button.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
|
collapse_button.text = p_name
|
||||||
|
collapse_button.toggled.connect(
|
||||||
|
func(toggled: bool):
|
||||||
|
collapse_toggled.emit(toggled)
|
||||||
|
)
|
||||||
|
add_child(collapse_button, false, Node.INTERNAL_MODE_FRONT)
|
||||||
|
|
||||||
|
renamed.connect(func():
|
||||||
|
collapse_button.name = name
|
||||||
|
)
|
||||||
|
collapse_button.toggled.connect(set_collapsed)
|
||||||
|
|
||||||
|
|
||||||
|
func set_collapsed(collapsed: bool) -> void:
|
||||||
|
collapse_button.icon = COLLAPSE_ICON_COLLAPSED if collapsed else COLLAPSE_ICON
|
||||||
|
collapse_button.set_pressed_no_signal(collapsed)
|
||||||
|
for c: CategoryItem in get_children():
|
||||||
|
c.visible = !collapsed
|
||||||
|
|
||||||
|
|
||||||
|
func add_item(p_name: String, p_tooltip: String, p_favorite: bool = false) -> void:
|
||||||
|
var item := CategoryItem.new(p_name, p_tooltip, p_favorite)
|
||||||
|
item.favorite_toggled.connect(
|
||||||
|
func(toggled: bool):
|
||||||
|
item_favorite_button_toggled.emit(item.get_index(), toggled)
|
||||||
|
)
|
||||||
|
item.pressed.connect(
|
||||||
|
func():
|
||||||
|
item_pressed.emit(item.get_index())
|
||||||
|
)
|
||||||
|
add_child(item)
|
||||||
|
|
||||||
|
|
||||||
|
func set_item_metadata(item: int, key: StringName, metadata: Variant) -> void:
|
||||||
|
get_child(item).set_meta(key, metadata)
|
||||||
|
|
||||||
|
|
||||||
|
func get_item_metadata(item: int, key: StringName) -> Variant:
|
||||||
|
return get_child(item).get_meta(key)
|
||||||
|
|
||||||
|
|
||||||
|
func get_item_count() -> int:
|
||||||
|
return get_child_count()
|
||||||
|
|
||||||
|
|
||||||
|
func set_item_favorite(item:int, favorite: bool) -> void:
|
||||||
|
var _item := get_child(item) as CategoryItem
|
||||||
|
_item.set_favorite(favorite)
|
||||||
|
|
||||||
|
|
||||||
|
func is_item_favorite(item: int) -> bool:
|
||||||
|
var _item := get_child(item) as CategoryItem
|
||||||
|
return _item.is_favorite()
|
||||||
|
|
||||||
|
|
||||||
|
func highlight_item(item: int) -> void:
|
||||||
|
for c: CategoryItem in get_children():
|
||||||
|
c.set_highlighted(c.get_index() == item)
|
||||||
|
|
||||||
|
|
||||||
|
func unhighlight_all() -> void:
|
||||||
|
for c: CategoryItem in get_children():
|
||||||
|
c.set_highlighted(false)
|
||||||
|
|
||||||
|
|
||||||
|
func get_highlighted_item() -> int:
|
||||||
|
for c: CategoryItem in get_children():
|
||||||
|
if c.is_highlighted:
|
||||||
|
return c.get_index()
|
||||||
|
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryItem extends HBoxContainer:
|
||||||
|
const FAVORITE_ICON := preload("res://graph_node_renderer/textures/favorite-icon.svg")
|
||||||
|
const NON_FAVORITE_ICON := preload("res://graph_node_renderer/textures/non-favorite-icon.svg")
|
||||||
|
const ITEM_MARGIN := 16
|
||||||
|
|
||||||
|
var highlighted_stylebox := StyleBoxFlat.new()
|
||||||
|
|
||||||
|
var is_highlighted: bool
|
||||||
|
|
||||||
|
var fav_button: Button
|
||||||
|
var name_button: Button
|
||||||
|
var panel: PanelContainer
|
||||||
|
|
||||||
|
signal pressed
|
||||||
|
signal favorite_toggled(toggled: bool)
|
||||||
|
|
||||||
|
|
||||||
|
func _init(p_name: String, p_tooltip: String, p_favorite: bool) -> void:
|
||||||
|
fav_button = Button.new()
|
||||||
|
fav_button.icon = FAVORITE_ICON if p_favorite else NON_FAVORITE_ICON
|
||||||
|
fav_button.toggle_mode = true
|
||||||
|
fav_button.set_pressed_no_signal(p_favorite)
|
||||||
|
fav_button.flat = true
|
||||||
|
fav_button.toggled.connect(
|
||||||
|
func(toggled: bool):
|
||||||
|
favorite_toggled.emit(toggled)
|
||||||
|
)
|
||||||
|
fav_button.toggled.connect(set_favorite)
|
||||||
|
|
||||||
|
name_button = Button.new()
|
||||||
|
name_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
name_button.text = p_name
|
||||||
|
name_button.flat = true
|
||||||
|
name_button.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||||
|
name_button.tooltip_text = p_tooltip
|
||||||
|
name_button.pressed.connect(
|
||||||
|
func():
|
||||||
|
pressed.emit()
|
||||||
|
)
|
||||||
|
|
||||||
|
var mc := MarginContainer.new()
|
||||||
|
mc.add_theme_constant_override(&"margin_left", ITEM_MARGIN)
|
||||||
|
|
||||||
|
panel = PanelContainer.new()
|
||||||
|
panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
panel.add_theme_stylebox_override(&"panel", highlighted_stylebox)
|
||||||
|
highlighted_stylebox.bg_color = Color(0.0, 0.0, 0.0, 0.15)
|
||||||
|
panel.self_modulate = Color.TRANSPARENT
|
||||||
|
|
||||||
|
var inner_hb := HBoxContainer.new()
|
||||||
|
inner_hb.add_child(fav_button)
|
||||||
|
inner_hb.add_child(name_button)
|
||||||
|
panel.add_child(inner_hb)
|
||||||
|
|
||||||
|
add_child(mc)
|
||||||
|
add_child(panel)
|
||||||
|
|
||||||
|
|
||||||
|
func set_favorite(favorite: bool) -> void:
|
||||||
|
fav_button.icon = FAVORITE_ICON if favorite else NON_FAVORITE_ICON
|
||||||
|
fav_button.set_pressed_no_signal(favorite)
|
||||||
|
|
||||||
|
|
||||||
|
func is_favorite() -> bool:
|
||||||
|
return fav_button.icon == FAVORITE_ICON
|
||||||
|
|
||||||
|
|
||||||
|
func set_highlighted(highlighted: bool) -> void:
|
||||||
|
is_highlighted = highlighted
|
||||||
|
if highlighted:
|
||||||
|
panel.self_modulate = Color.WHITE
|
||||||
|
else:
|
||||||
|
panel.self_modulate = Color.TRANSPARENT
|
44
graph_node_renderer/add_node_menu.tscn
Normal file
44
graph_node_renderer/add_node_menu.tscn
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
[gd_scene load_steps=2 format=3 uid="uid://dqp08ahaho0q2"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://graph_node_renderer/add_node_menu.gd" id="1_m7f7p"]
|
||||||
|
|
||||||
|
[node name="AddNodeMenu" type="MarginContainer"]
|
||||||
|
offset_right = 436.0
|
||||||
|
offset_bottom = 57.0
|
||||||
|
theme_override_constants/margin_left = 3
|
||||||
|
theme_override_constants/margin_top = 3
|
||||||
|
theme_override_constants/margin_right = 3
|
||||||
|
theme_override_constants/margin_bottom = 3
|
||||||
|
script = ExtResource("1_m7f7p")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="SearchLineEdit" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Search"
|
||||||
|
clear_button_enabled = true
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/ScrollContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_constants/margin_right = 6
|
||||||
|
|
||||||
|
[node name="ScrollContentContainer" type="VBoxContainer" parent="VBoxContainer/ScrollContainer/MarginContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[connection signal="gui_input" from="VBoxContainer/SearchLineEdit" to="." method="_on_search_line_edit_gui_input"]
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/SearchLineEdit" to="." method="search"]
|
||||||
|
[connection signal="text_submitted" from="VBoxContainer/SearchLineEdit" to="." method="_on_search_line_edit_text_submitted"]
|
|
@ -2,6 +2,13 @@ extends GraphEdit
|
||||||
class_name DeckRendererGraphEdit
|
class_name DeckRendererGraphEdit
|
||||||
|
|
||||||
const NODE_SCENE := preload("res://graph_node_renderer/deck_node_renderer_graph_node.tscn")
|
const NODE_SCENE := preload("res://graph_node_renderer/deck_node_renderer_graph_node.tscn")
|
||||||
|
const ADD_NODE_MENU_SCENE := preload("res://graph_node_renderer/add_node_menu.tscn")
|
||||||
|
|
||||||
|
var search_popup_panel: PopupPanel
|
||||||
|
var add_node_menu: AddNodeMenu
|
||||||
|
|
||||||
|
@export var add_node_popup_size: Vector2i = Vector2i(500, 300)
|
||||||
|
var popup_position: Vector2
|
||||||
|
|
||||||
var deck: Deck:
|
var deck: Deck:
|
||||||
set(v):
|
set(v):
|
||||||
|
@ -13,60 +20,13 @@ signal group_enter_requested(group_id: String)
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
var add_button := Button.new()
|
add_node_menu = ADD_NODE_MENU_SCENE.instantiate()
|
||||||
add_button.text = "Button"
|
search_popup_panel = PopupPanel.new()
|
||||||
var add_print := Button.new()
|
search_popup_panel.add_child(add_node_menu)
|
||||||
add_print.text = "Print"
|
search_popup_panel.size = add_node_popup_size
|
||||||
var get_var := Button.new()
|
add_child(search_popup_panel, false, Node.INTERNAL_MODE_BACK)
|
||||||
get_var.text = "Get Var"
|
|
||||||
var set_var := Button.new()
|
|
||||||
set_var.text = "Set Var"
|
|
||||||
var test := Button.new()
|
|
||||||
test.text = "Interleaved"
|
|
||||||
var str_const := Button.new()
|
|
||||||
str_const.text = "String"
|
|
||||||
get_menu_hbox().add_child(add_button)
|
|
||||||
get_menu_hbox().add_child(add_print)
|
|
||||||
get_menu_hbox().add_child(get_var)
|
|
||||||
get_menu_hbox().add_child(set_var)
|
|
||||||
get_menu_hbox().add_child(test)
|
|
||||||
get_menu_hbox().add_child(str_const)
|
|
||||||
|
|
||||||
add_button.pressed.connect(
|
add_node_menu.node_selected.connect(_on_add_node_menu_node_selected)
|
||||||
func():
|
|
||||||
var node := NodeDB.instance_node("button")
|
|
||||||
deck.add_node_inst(node)
|
|
||||||
)
|
|
||||||
|
|
||||||
add_print.pressed.connect(
|
|
||||||
func():
|
|
||||||
var node := NodeDB.instance_node("print")
|
|
||||||
deck.add_node_inst(node)
|
|
||||||
)
|
|
||||||
|
|
||||||
get_var.pressed.connect(
|
|
||||||
func():
|
|
||||||
var node := NodeDB.instance_node("get_deck_var")
|
|
||||||
deck.add_node_inst(node)
|
|
||||||
)
|
|
||||||
|
|
||||||
set_var.pressed.connect(
|
|
||||||
func():
|
|
||||||
var node := NodeDB.instance_node("set_deck_var")
|
|
||||||
deck.add_node_inst(node)
|
|
||||||
)
|
|
||||||
|
|
||||||
test.pressed.connect(
|
|
||||||
func():
|
|
||||||
var node := NodeDB.instance_node("test_interleaved")
|
|
||||||
deck.add_node_inst(node)
|
|
||||||
)
|
|
||||||
|
|
||||||
str_const.pressed.connect(
|
|
||||||
func():
|
|
||||||
var node := NodeDB.instance_node("string_constant")
|
|
||||||
deck.add_node_inst(node)
|
|
||||||
)
|
|
||||||
|
|
||||||
connection_request.connect(attempt_connection)
|
connection_request.connect(attempt_connection)
|
||||||
disconnection_request.connect(attempt_disconnect)
|
disconnection_request.connect(attempt_disconnect)
|
||||||
|
@ -105,6 +65,14 @@ func attempt_disconnect(from_node_name: StringName, from_port: int, to_node_name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func get_node_renderer(node: DeckNode) -> DeckNodeRendererGraphNode:
|
||||||
|
for i: DeckNodeRendererGraphNode in get_children().slice(1):
|
||||||
|
if i.node == node:
|
||||||
|
return i
|
||||||
|
|
||||||
|
return null
|
||||||
|
|
||||||
|
|
||||||
func _on_scroll_offset_changed(offset: Vector2) -> void:
|
func _on_scroll_offset_changed(offset: Vector2) -> void:
|
||||||
deck.set_meta("offset", offset)
|
deck.set_meta("offset", offset)
|
||||||
|
|
||||||
|
@ -210,3 +178,24 @@ func _input(event: InputEvent) -> void:
|
||||||
print("tried to enter group")
|
print("tried to enter group")
|
||||||
group_enter_requested.emit((get_selected_nodes()[0] as DeckNodeRendererGraphNode).node.group_id)
|
group_enter_requested.emit((get_selected_nodes()[0] as DeckNodeRendererGraphNode).node.group_id)
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_popup_request(p_popup_position: Vector2) -> void:
|
||||||
|
var p := get_viewport_rect().position + get_global_mouse_position()
|
||||||
|
p += Vector2(10, 10)
|
||||||
|
var r := Rect2i(p, search_popup_panel.size)
|
||||||
|
search_popup_panel.popup_on_parent(r)
|
||||||
|
add_node_menu.focus_search_bar()
|
||||||
|
popup_position = p_popup_position
|
||||||
|
|
||||||
|
|
||||||
|
func _on_add_node_menu_node_selected(type: String) -> void:
|
||||||
|
var node := NodeDB.instance_node(type) as DeckNode
|
||||||
|
deck.add_node_inst(node)
|
||||||
|
var node_pos := ((scroll_offset + popup_position) / zoom)
|
||||||
|
if snapping_enabled:
|
||||||
|
node_pos = node_pos.snapped(Vector2(snapping_distance, snapping_distance))
|
||||||
|
|
||||||
|
get_node_renderer(node).position_offset = node_pos
|
||||||
|
|
||||||
|
search_popup_panel.hide()
|
||||||
|
|
|
@ -11,4 +11,5 @@ grow_vertical = 2
|
||||||
right_disconnects = true
|
right_disconnects = true
|
||||||
script = ExtResource("1_pojfs")
|
script = ExtResource("1_pojfs")
|
||||||
|
|
||||||
|
[connection signal="popup_request" from="." to="." method="_on_popup_request"]
|
||||||
[connection signal="scroll_offset_changed" from="." to="." method="_on_scroll_offset_changed"]
|
[connection signal="scroll_offset_changed" from="." to="." method="_on_scroll_offset_changed"]
|
||||||
|
|
85
graph_node_renderer/textures/collapse-icon-collapsed.svg
Normal file
85
graph_node_renderer/textures/collapse-icon-collapsed.svg
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333333"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||||
|
sodipodi:docname="collapse-icon-collapsed.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:zoom="23.147924"
|
||||||
|
inkscape:cx="8.9208864"
|
||||||
|
inkscape:cy="7.9920774"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1016"
|
||||||
|
inkscape:window-x="1440"
|
||||||
|
inkscape:window-y="36"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1">
|
||||||
|
<sodipodi:guide
|
||||||
|
position="0,4.2333332"
|
||||||
|
orientation="0,16"
|
||||||
|
id="guide1"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="4.2333332,4.2333332"
|
||||||
|
orientation="16,0"
|
||||||
|
id="guide2"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="4.2333332,0"
|
||||||
|
orientation="0,-16"
|
||||||
|
id="guide3"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="0,0"
|
||||||
|
orientation="-16,0"
|
||||||
|
id="guide4"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<inkscape:grid
|
||||||
|
id="grid4"
|
||||||
|
units="px"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingx="0.26458333"
|
||||||
|
spacingy="0.26458333"
|
||||||
|
empcolor="#0099e5"
|
||||||
|
empopacity="0.30196078"
|
||||||
|
color="#0099e5"
|
||||||
|
opacity="0.14901961"
|
||||||
|
empspacing="4"
|
||||||
|
dotted="false"
|
||||||
|
gridanglex="30"
|
||||||
|
gridanglez="30"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 1.3229241,3.704159 2.910424,2.3812424 1.3229241,1.0583258"
|
||||||
|
id="path4"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,37 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://5gwj26ab5t6s"
|
||||||
|
path="res://.godot/imported/collapse-icon-collapsed.svg-811c248a92d92ca04d781df393765972.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://graph_node_renderer/textures/collapse-icon-collapsed.svg"
|
||||||
|
dest_files=["res://.godot/imported/collapse-icon-collapsed.svg-811c248a92d92ca04d781df393765972.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
85
graph_node_renderer/textures/collapse-icon.svg
Normal file
85
graph_node_renderer/textures/collapse-icon.svg
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333333"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||||
|
sodipodi:docname="collapse-icon.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:zoom="11.573962"
|
||||||
|
inkscape:cx="-3.8448372"
|
||||||
|
inkscape:cy="7.6896745"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1016"
|
||||||
|
inkscape:window-x="1440"
|
||||||
|
inkscape:window-y="36"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1">
|
||||||
|
<sodipodi:guide
|
||||||
|
position="0,4.2333332"
|
||||||
|
orientation="0,16"
|
||||||
|
id="guide1"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="4.2333332,4.2333332"
|
||||||
|
orientation="16,0"
|
||||||
|
id="guide2"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="4.2333332,0"
|
||||||
|
orientation="0,-16"
|
||||||
|
id="guide3"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="0,0"
|
||||||
|
orientation="-16,0"
|
||||||
|
id="guide4"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<inkscape:grid
|
||||||
|
id="grid4"
|
||||||
|
units="px"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingx="0.26458333"
|
||||||
|
spacingy="0.26458333"
|
||||||
|
empcolor="#0099e5"
|
||||||
|
empopacity="0.30196078"
|
||||||
|
color="#0099e5"
|
||||||
|
opacity="0.14901961"
|
||||||
|
empspacing="4"
|
||||||
|
dotted="false"
|
||||||
|
gridanglex="30"
|
||||||
|
gridanglez="30"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 0.79374997,1.5874999 2.1166666,3.1749998 3.4395832,1.5874999"
|
||||||
|
id="path4"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
37
graph_node_renderer/textures/collapse-icon.svg.import
Normal file
37
graph_node_renderer/textures/collapse-icon.svg.import
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://yrjhesfwqp6o"
|
||||||
|
path="res://.godot/imported/collapse-icon.svg-9bebc4e2d470036ab276875c18b86afd.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://graph_node_renderer/textures/collapse-icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/collapse-icon.svg-9bebc4e2d470036ab276875c18b86afd.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
1
graph_node_renderer/textures/favorite-icon.svg
Normal file
1
graph_node_renderer/textures/favorite-icon.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 1.7 5.626 5.797 1 6.895l3.236 3.408-.359 4.673 4.14-1.977 4.157 1.942-.396-4.653L15 6.895l-4.626-1.098z" fill="#e0e0e0"/></svg>
|
After Width: | Height: | Size: 223 B |
37
graph_node_renderer/textures/favorite-icon.svg.import
Normal file
37
graph_node_renderer/textures/favorite-icon.svg.import
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b4qr820crboug"
|
||||||
|
path="res://.godot/imported/favorite-icon.svg-9ed8d8558aa33c9d7305523c2c289a43.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://graph_node_renderer/textures/favorite-icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/favorite-icon.svg-9ed8d8558aa33c9d7305523c2c289a43.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
1
graph_node_renderer/textures/non-favorite-icon.svg
Normal file
1
graph_node_renderer/textures/non-favorite-icon.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 1.725 5.625 5.822 1 6.92l3.236 3.406L3.876 15l4.14-1.977 4.158 1.942-.397-4.652L15 6.92l-4.625-1.098L8 1.725zM8 4l1.658 2.777 3.233.744-2.25 2.301.275 3.155-2.904-1.317L5.119 13l.252-3.168-2.262-2.31 3.233-.745L8 4z" fill="#e0e0e0"/></svg>
|
After Width: | Height: | Size: 335 B |
37
graph_node_renderer/textures/non-favorite-icon.svg.import
Normal file
37
graph_node_renderer/textures/non-favorite-icon.svg.import
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://c3sndmgw0mfpb"
|
||||||
|
path="res://.godot/imported/non-favorite-icon.svg-7d5ddab226c43aa43af383d3db45c122.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://graph_node_renderer/textures/non-favorite-icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/non-favorite-icon.svg-7d5ddab226c43aa43af383d3db45c122.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
Loading…
Reference in a new issue