mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
yag's doc sprint (#4)
documented everything (except NodeDB) in the classes/ folder Reviewed-on: https://codeberg.org/Eroax/Re-DotDeck/pulls/4 Co-authored-by: Lera Elvoé <yagich@poto.cafe> Co-committed-by: Lera Elvoé <yagich@poto.cafe>
This commit is contained in:
parent
2264890113
commit
b36bdaf71c
7 changed files with 207 additions and 11 deletions
|
@ -1,7 +1,13 @@
|
|||
class_name Deck
|
||||
## A deck/graph with nodes.
|
||||
##
|
||||
## A container for [DeckNode]s, managing connections between them.
|
||||
|
||||
## The [DeckNode]s that belong to this deck. The key is the node's id, the value
|
||||
## is the [DeckNode] instance.
|
||||
var nodes: Dictionary
|
||||
|
||||
## The list of [DeckType] for easy port creation.
|
||||
enum Types{
|
||||
ERROR = -1,
|
||||
BOOL,
|
||||
|
@ -11,7 +17,7 @@ enum Types{
|
|||
DICTIONARY,
|
||||
}
|
||||
|
||||
|
||||
## A dictionary mapping [enum Types] to [DeckType] subclasses.
|
||||
static var type_assoc: Dictionary = {
|
||||
Types.ERROR: DeckType.DeckTypeError,
|
||||
Types.BOOL: DeckType.DeckTypeBool,
|
||||
|
@ -21,27 +27,47 @@ static var type_assoc: Dictionary = {
|
|||
Types.DICTIONARY: DeckType.DeckTypeDictionary,
|
||||
}
|
||||
|
||||
## A map of variables set on this deck.
|
||||
var variable_stack: Dictionary = {}
|
||||
## The path to save this deck on the file system.
|
||||
var save_path: String = ""
|
||||
|
||||
var is_group: bool = false
|
||||
var groups: Dictionary = {} #Dictionary[String -> Deck.id, Deck]
|
||||
## List of groups belonging to this deck, in the format of[br]
|
||||
## [code]Dictionary[String -> Deck.id, Deck][/code]
|
||||
var groups: Dictionary = {}
|
||||
## A unique identifier for this deck.
|
||||
var id: String = ""
|
||||
## The parent deck of this deck, if this is a group.
|
||||
var _belonging_to: Deck # for groups
|
||||
## The ID of this group's input node. Used only if [member is_group] is [code]true[/code].
|
||||
var group_input_node: String
|
||||
## The ID of this group's input node. Used only if [member is_group] is [code]true[/code].
|
||||
var group_output_node: String
|
||||
## The ID of the group node this group is represented by, contained in this deck's parent deck.
|
||||
## Used only if [member is_group] is [code]true[/code].
|
||||
## @experimental
|
||||
var group_node: String
|
||||
|
||||
## Emitted when a node has been added to this deck.
|
||||
signal node_added(node: DeckNode)
|
||||
## Emitted when a node has been removed from this deck.
|
||||
signal node_removed(node: DeckNode)
|
||||
|
||||
|
||||
## Instantiate a node by its' [member DeckNode.node_type] and add it to this deck.[br]
|
||||
## See [method add_node_inst] for parameter descriptions.
|
||||
func add_node_type(type: String, assign_id: String = "", assign_to_self: bool = true) -> DeckNode:
|
||||
var node_inst: DeckNode = NodeDB.instance_node(type)
|
||||
|
||||
return add_node_inst(node_inst, assign_id, assign_to_self)
|
||||
|
||||
|
||||
## Add a [DeckNode] instance to this deck.[br]
|
||||
## If [param assign_id] is empty, the node will get its' ID (re-)assigned.
|
||||
## Otherwise, it will be assigned to be that value.[br]
|
||||
## If [param assign_to_self] is [code]true[/code], the node's
|
||||
## [member DeckNode._belonging_to] property will be set to [code]self[/code].
|
||||
func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool = true) -> DeckNode:
|
||||
if assign_to_self:
|
||||
node._belonging_to = self
|
||||
|
@ -58,10 +84,12 @@ func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool
|
|||
return node
|
||||
|
||||
|
||||
## Get a node belonging to this deck by its' ID.
|
||||
func get_node(uuid: String) -> DeckNode:
|
||||
return nodes.get(uuid)
|
||||
|
||||
|
||||
## Attempt to connect two nodes. Returns [code]true[/code] if the connection succeeded.
|
||||
func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_output_port: int, to_input_port: int) -> bool:
|
||||
# first, check that we can do the type conversion.
|
||||
var type_a: Types = from_node.get_output_ports()[from_output_port].type
|
||||
|
@ -77,6 +105,7 @@ func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_output_port: int
|
|||
return true
|
||||
|
||||
|
||||
## Remove a connection from two nodes.
|
||||
func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_output_port: int, to_input_port: int) -> void:
|
||||
var hash = {to_node._id: to_input_port}.hash()
|
||||
|
||||
|
@ -84,10 +113,12 @@ func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_output_port:
|
|||
to_node.remove_incoming_connection(to_input_port)
|
||||
|
||||
|
||||
## Returns true if this deck has no nodes and no variables.
|
||||
func is_empty() -> bool:
|
||||
return nodes.is_empty() && variable_stack.is_empty()
|
||||
|
||||
|
||||
## Remove a node from this deck.
|
||||
func remove_node(uuid: String) -> void:
|
||||
var node = nodes.get(uuid)
|
||||
nodes.erase(uuid)
|
||||
|
@ -95,6 +126,9 @@ func remove_node(uuid: String) -> void:
|
|||
node_removed.emit(node)
|
||||
|
||||
|
||||
## Group the [param nodes_to_group] into a new deck and return it.
|
||||
## Returns [code]null[/code] on failure.[br]
|
||||
## Adds a group node to this deck, and adds group input and output nodes in the group.
|
||||
func group_nodes(nodes_to_group: Array) -> Deck:
|
||||
if nodes_to_group.is_empty():
|
||||
return null
|
||||
|
@ -151,10 +185,12 @@ func group_nodes(nodes_to_group: Array) -> Deck:
|
|||
return group
|
||||
|
||||
|
||||
## Get a group belonging to this deck by its ID.
|
||||
func get_group(uuid: String) -> Deck:
|
||||
return groups.get(uuid)
|
||||
|
||||
|
||||
## Returns a [Dictionary] representation of this deck.
|
||||
func to_dict(with_meta: bool = true) -> Dictionary:
|
||||
var inner := {
|
||||
"nodes": {},
|
||||
|
@ -183,6 +219,7 @@ func to_dict(with_meta: bool = true) -> Dictionary:
|
|||
return d
|
||||
|
||||
|
||||
## Create a new deck from a [Dictionary] representation, such as one created by [method to_dict].
|
||||
static func from_dict(data: Dictionary, path: String = "") -> Deck:
|
||||
var deck := Deck.new()
|
||||
deck.save_path = path
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
class_name DeckHolder
|
||||
## @experimental
|
||||
## A static class holding references to all decks opened in the current session.
|
||||
|
||||
|
||||
## List of decks opened this session.
|
||||
static var decks: Array[Deck]
|
||||
|
||||
|
||||
## Returns a new empty deck and assigns a new random ID to it.
|
||||
static func add_empty_deck() -> Deck:
|
||||
var deck := Deck.new()
|
||||
DeckHolder.decks.append(deck)
|
||||
|
@ -12,6 +15,7 @@ static func add_empty_deck() -> Deck:
|
|||
return deck
|
||||
|
||||
|
||||
## Opens a deck from the [param path].
|
||||
static func open_deck_from_file(path: String) -> Deck:
|
||||
var f := FileAccess.open(path, FileAccess.READ)
|
||||
if f.get_error() != OK:
|
||||
|
@ -23,5 +27,6 @@ static func open_deck_from_file(path: String) -> Deck:
|
|||
return deck
|
||||
|
||||
|
||||
## Unloads a deck.
|
||||
static func close_deck(deck: Deck) -> void:
|
||||
DeckHolder.decks.erase(deck)
|
||||
|
|
|
@ -1,25 +1,44 @@
|
|||
class_name DeckNode
|
||||
## A node in a [Deck].
|
||||
##
|
||||
## Nodes are the essential building block of a [Deck] graph. They can have connections between ports
|
||||
## and send data through them.
|
||||
|
||||
## The name initially shown to a renderer.
|
||||
var name: String
|
||||
|
||||
## [code]Dictionary[int -> output port, Array[Dictionary[String -> DeckNode#_id, int -> input port]]]
|
||||
## A map of outgoing connections from this node, in the format[br]
|
||||
## [code]Dictionary[int -> output port, Array[Dictionary[String -> DeckNode#_id, int -> input port]]][/code]
|
||||
var outgoing_connections: Dictionary
|
||||
## [code]Dictionary[int -> input port, [Dictionary[String -> DeckNode#_id, int -> output port]]
|
||||
## A map of incoming connections to this node, in the format[br]
|
||||
## [code]Dictionary[int -> input port, [Dictionary[String -> DeckNode#_id, int -> output port]][/code]
|
||||
var incoming_connections: Dictionary
|
||||
|
||||
## A list of [Port]s on this node.
|
||||
var ports: Array[Port]
|
||||
|
||||
## The deck this node belongs to.
|
||||
var _belonging_to: Deck
|
||||
## A unique identifier for this node.
|
||||
var _id: String
|
||||
## The type of this node, used for instantiation.
|
||||
var node_type: String
|
||||
|
||||
## The description of this node, shown to the user by a renderer.
|
||||
var description: String
|
||||
## A list of aliases for this node, used by search.
|
||||
var aliases: Array[String]
|
||||
## The category of this node. Must be snake_case. This is additional data which
|
||||
## a renderer can optionally show to the user.
|
||||
var category: String
|
||||
## Controls whether this node should appear in [SearchProvider].
|
||||
var appears_in_search: bool = true
|
||||
|
||||
## A list of additional properties to save when this node is saved.
|
||||
var props_to_serialize: Array[StringName]
|
||||
|
||||
## The position of this node relative to the parent graph.
|
||||
## Only used by renderers.
|
||||
var position: Dictionary = {"x": 0.0, "y": 0.0}
|
||||
|
||||
enum PortType{
|
||||
|
@ -28,28 +47,40 @@ enum PortType{
|
|||
VIRTUAL, ## Virtual port type (no slot on left [i]or[/i] right).
|
||||
}
|
||||
|
||||
## Emitted when this node has been moved.
|
||||
signal position_updated(new_position: Dictionary)
|
||||
## Emitted when a port has been added.
|
||||
signal port_added(port: int)
|
||||
## Emitted when a port has been removed.
|
||||
signal port_removed(port: int)
|
||||
## Emitted when a port or multiple ports have been updated (added or removed).
|
||||
signal ports_updated()
|
||||
## Emitted when a connection from this node has been added.
|
||||
signal outgoing_connection_added(from_port: int)
|
||||
## Emitted when a connection from this node has been removed.
|
||||
signal outgoing_connection_removed(from_port: int)
|
||||
## Emitted when a connection to this node has been added.
|
||||
signal incoming_connection_added(from_port: int)
|
||||
## Emitted when a connection to this node has been removed.
|
||||
signal incoming_connection_removed(from_port: int)
|
||||
|
||||
|
||||
## Add an input port to this node. Usually only used at initialization.
|
||||
func add_input_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
||||
add_port(type, label, PortType.INPUT, get_input_ports().size(), descriptor)
|
||||
|
||||
|
||||
## Add an output port to this node. Usually only used at initialization.
|
||||
func add_output_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
||||
add_port(type, label, PortType.OUTPUT, get_output_ports().size(), descriptor)
|
||||
|
||||
|
||||
## Add a virtual port to this node. Usually only used at initialization.
|
||||
func add_virtual_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
||||
add_port(type, label, PortType.VIRTUAL, get_virtual_ports().size(), descriptor)
|
||||
|
||||
|
||||
## Add a port to this node. Usually only used at initialization.
|
||||
func add_port(type: Deck.Types, label: String, port_type: PortType, index_of_type: int, descriptor: String = "") -> void:
|
||||
var port := Port.new(type, label, ports.size(), port_type, index_of_type, descriptor)
|
||||
ports.append(port)
|
||||
|
@ -57,6 +88,7 @@ func add_port(type: Deck.Types, label: String, port_type: PortType, index_of_typ
|
|||
ports_updated.emit()
|
||||
|
||||
|
||||
## Remove a port from this node.
|
||||
func remove_port(port_idx: int) -> void:
|
||||
outgoing_connections.erase(port_idx)
|
||||
incoming_connections.erase(port_idx)
|
||||
|
@ -64,6 +96,7 @@ func remove_port(port_idx: int) -> void:
|
|||
port_removed.emit(port_idx)
|
||||
|
||||
|
||||
## Send data to all outgoing connections on port [param from_output_port].
|
||||
func send(from_output_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
if outgoing_connections.get(from_output_port) == null:
|
||||
return
|
||||
|
@ -76,10 +109,12 @@ func send(from_output_port: int, data: DeckType, extra_data: Array = []) -> void
|
|||
get_node(node)._receive(connection[node], data, extra_data)
|
||||
|
||||
|
||||
## Virtual function that's called when this node receives data from another node's [method send] call.
|
||||
func _receive(to_input_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
pass
|
||||
|
||||
|
||||
## @deprecated
|
||||
func add_outgoing_connection_to_port(output_port: int, to_node: String, to_input_port: int) -> void:
|
||||
add_outgoing_connection(
|
||||
get_global_port_idx_from_output(output_port),
|
||||
|
@ -88,6 +123,8 @@ func add_outgoing_connection_to_port(output_port: int, to_node: String, to_input
|
|||
)
|
||||
|
||||
|
||||
## Add a connection from the output port at [param from_port] to [param to_node]'s input port
|
||||
## at [param to_port].
|
||||
func add_outgoing_connection(from_port: int, to_node: String, to_port: int) -> void:
|
||||
var port_connections: Array = outgoing_connections.get(from_port, [])
|
||||
port_connections.append({to_node: to_port})
|
||||
|
@ -96,12 +133,17 @@ func add_outgoing_connection(from_port: int, to_node: String, to_port: int) -> v
|
|||
outgoing_connection_added.emit(from_port)
|
||||
|
||||
|
||||
## Add an incoming connection from [param from_node]'s output port at [param from_port] to this node's
|
||||
## input port at [param to_port].
|
||||
func add_incoming_connection(to_port: int, from_node: String, from_port: int) -> void:
|
||||
var connection := {from_node: from_port}
|
||||
incoming_connections[to_port] = connection
|
||||
incoming_connection_added.emit(to_port)
|
||||
|
||||
|
||||
## Request a value from an incoming connection on this node's input port at [param on_port].
|
||||
## Returns [code]null[/code] if no incoming connection exists on that port.
|
||||
## The connected node may also return [code]null[/code].
|
||||
func request_value(on_port: int) -> Variant:
|
||||
if !incoming_connections.has(on_port):
|
||||
return null
|
||||
|
@ -111,11 +153,14 @@ func request_value(on_port: int) -> Variant:
|
|||
return node._value_request(connection.values()[0])
|
||||
|
||||
|
||||
# override this
|
||||
## Virtual function that's called when this node has been requested a value from the output port
|
||||
## at [param from_port].
|
||||
func _value_request(from_port: int) -> Variant:
|
||||
return null
|
||||
|
||||
|
||||
## Remove an outgoing connection from this node.
|
||||
## Does [b]not[/b] remove the other node's incoming connection equivalent.
|
||||
func remove_outgoing_connection(from_port: int, connection_hash: int) -> void:
|
||||
var port_connections: Array = (outgoing_connections.get(from_port, []) as Array).duplicate(true)
|
||||
if port_connections.is_empty():
|
||||
|
@ -138,15 +183,19 @@ func remove_outgoing_connection(from_port: int, connection_hash: int) -> void:
|
|||
outgoing_connection_removed.emit(from_port)
|
||||
|
||||
|
||||
## Remove an incoming connection to this node on the input port at [param to_port].
|
||||
## Does [b]not[/b] remove the other node's outgoing connection equivalent.
|
||||
func remove_incoming_connection(to_port: int) -> void:
|
||||
incoming_connections.erase(to_port)
|
||||
incoming_connection_removed.emit(to_port)
|
||||
|
||||
|
||||
## @deprecated
|
||||
func remove_outgoing_connection_from_port(output_port: int, connection_hash: int) -> void:
|
||||
remove_outgoing_connection(get_global_port_idx_from_output(output_port), connection_hash)
|
||||
|
||||
|
||||
## Returns a list of all input ports.
|
||||
func get_input_ports() -> Array[Port]:
|
||||
return ports.filter(
|
||||
func(port: Port) -> bool:
|
||||
|
@ -154,6 +203,7 @@ func get_input_ports() -> Array[Port]:
|
|||
)
|
||||
|
||||
|
||||
## Returns a list of all output ports.
|
||||
func get_output_ports() -> Array[Port]:
|
||||
return ports.filter(
|
||||
func(port: Port) -> bool:
|
||||
|
@ -161,6 +211,7 @@ func get_output_ports() -> Array[Port]:
|
|||
)
|
||||
|
||||
|
||||
## Returns a list of all virtual ports.
|
||||
func get_virtual_ports() -> Array[Port]:
|
||||
return ports.filter(
|
||||
func(port: Port) -> bool:
|
||||
|
@ -168,6 +219,7 @@ func get_virtual_ports() -> Array[Port]:
|
|||
)
|
||||
|
||||
|
||||
## Returns the global port index from the input port index at [param idx].
|
||||
func get_global_port_idx_from_input(idx: int) -> int:
|
||||
if get_input_ports().size() > idx:
|
||||
return get_input_ports()[idx].index
|
||||
|
@ -175,6 +227,7 @@ func get_global_port_idx_from_input(idx: int) -> int:
|
|||
return -1
|
||||
|
||||
|
||||
## Returns the global port index from the output port index at [param idx].
|
||||
func get_global_port_idx_from_output(idx: int) -> int:
|
||||
if get_output_ports().size() > idx:
|
||||
return get_output_ports()[idx].index
|
||||
|
@ -182,6 +235,7 @@ func get_global_port_idx_from_output(idx: int) -> int:
|
|||
return -1
|
||||
|
||||
|
||||
## Returns the global port index from the virtual port index at [param idx].
|
||||
func get_global_port_idx_from_virtual(idx: int) -> int:
|
||||
if get_virtual_ports().size() > idx:
|
||||
return get_virtual_ports()[idx].index
|
||||
|
@ -189,44 +243,52 @@ func get_global_port_idx_from_virtual(idx: int) -> int:
|
|||
return -1
|
||||
|
||||
|
||||
## Get a port's local index from the global port index at [param idx].
|
||||
func get_port_type_idx_from_global(idx: int) -> int:
|
||||
return ports[idx].index_of_type
|
||||
|
||||
|
||||
## Returns the amount of outgoing connections on output port at [param port].
|
||||
func get_outgoing_connection_count(port: int) -> int:
|
||||
return (outgoing_connections[port] as Array).size()
|
||||
|
||||
|
||||
## @deprecated
|
||||
func get_outgoing_connection_count_on_output(port: int) -> int:
|
||||
return get_outgoing_connection_count(get_global_port_idx_from_output(port))
|
||||
|
||||
|
||||
## Returns [code]true[/code] if the node has an incoming connection in input port at [param port].
|
||||
func has_incoming_connection(port: int) -> bool:
|
||||
return incoming_connections.has(port)
|
||||
|
||||
|
||||
## @deprecated
|
||||
func has_incoming_connection_on_input(port: int) -> bool:
|
||||
return has_incoming_connection(get_global_port_idx_from_input(port))
|
||||
|
||||
|
||||
## Returns the list of all ports.
|
||||
func get_all_ports() -> Array[Port]:
|
||||
return ports
|
||||
|
||||
|
||||
## Get a sibling node by its' ID.
|
||||
func get_node(uuid: String) -> DeckNode:
|
||||
return _belonging_to.get_node(uuid)
|
||||
|
||||
|
||||
# override this to do setup before connections are loaded but after props were set
|
||||
## Virtual function that's called during deserialization before connections are loaded in.
|
||||
func _pre_connection() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# override this to do extra setup after it's done loading from dictionary
|
||||
## Virtual function that's called after the node has been deserialized.
|
||||
func _post_load() -> void:
|
||||
pass
|
||||
|
||||
|
||||
## Returns a [Dictionary] representation of this node.
|
||||
func to_dict(with_meta: bool = true) -> Dictionary:
|
||||
var d := {
|
||||
"_id": _id,
|
||||
|
@ -254,5 +316,6 @@ func to_dict(with_meta: bool = true) -> Dictionary:
|
|||
return d
|
||||
|
||||
|
||||
## Returns the node's [member position] as a [Vector2].
|
||||
func position_as_vector2() -> Vector2:
|
||||
return Vector2(position.x, position.y)
|
||||
|
|
|
@ -1,14 +1,30 @@
|
|||
class_name Port
|
||||
## A data type representing a port of a [DeckNode].
|
||||
##
|
||||
## Ports are used for connections between [DeckNode]s and can contain data that is passed between
|
||||
## them on a node.
|
||||
|
||||
## The type index of this port.
|
||||
var type: Deck.Types
|
||||
## The label of this port. Used by the renderer to display. How it's displayed depends on the renderer
|
||||
## and the [member descriptor].
|
||||
var label: String
|
||||
## Hints to the renderer on how to display this port.[br]
|
||||
## Can be either one of these: [code]button textfield spinbox slider textblock codeblock checkbox singlechoice multichoice[/code].[br]
|
||||
## Additional descriptor properties can be specified after the type, delimited by a colon ([code]:[/code]).[br]
|
||||
## @experimental
|
||||
var descriptor: String
|
||||
## A callback to get this port's value. Intended usage is by renderers that show an input field of some kind.
|
||||
var value_callback: Callable
|
||||
|
||||
## The type of this port (input, output or virtual)
|
||||
var port_type: DeckNode.PortType
|
||||
## The local index of this port.
|
||||
var index_of_type: int
|
||||
## The global index of this port.
|
||||
var index: int
|
||||
|
||||
## The value of this port.
|
||||
var value: Variant: set = set_value
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
class_name SearchProvider
|
||||
|
||||
## A class facilitating the searching of nodes.
|
||||
##
|
||||
## Allows a renderer or subscribing client to search for nodes registered in NodeDB, optionally with filters.
|
||||
|
||||
## A list of all filters that can be applied to a search string.
|
||||
static var filters: Array[Filter] = [
|
||||
# favorites filter. will only show nodes marked as favorite. syntax: "#f"
|
||||
Filter.new(
|
||||
|
@ -40,6 +45,7 @@ static var filters: Array[Filter] = [
|
|||
]
|
||||
|
||||
|
||||
## Performs a search for nodes. Filters can be provided directly in the search [param term].
|
||||
static func search(term: String) -> Array[NodeDB.NodeDescriptor]:
|
||||
var res: Array[NodeDB.NodeDescriptor] = []
|
||||
|
||||
|
@ -75,6 +81,10 @@ static func search(term: String) -> Array[NodeDB.NodeDescriptor]:
|
|||
return filtered_res
|
||||
|
||||
|
||||
## A filter that can be applied to a search term in [SearchProvider].
|
||||
##
|
||||
## Filters have a set of functions that are run by the [SearchProvider]
|
||||
## to determine if any items should be removed from the final match list.
|
||||
class Filter:
|
||||
## Return [code]true[/code] if this filter should be applied to the search.[br]
|
||||
## [code]Callable(search_string: String) -> bool[/code]
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
class_name DeckType
|
||||
## Base class for defining the types that can be used on a [Port].
|
||||
|
||||
var _value: Variant
|
||||
var _success: bool = true
|
||||
|
||||
|
||||
## Returns [code]true[/code] if the type is valid and can be used.
|
||||
func is_valid() -> bool:
|
||||
return _success
|
||||
|
||||
|
@ -16,11 +18,17 @@ func set_value(new_value: Variant) -> void:
|
|||
_value = new_value
|
||||
|
||||
|
||||
## Virtual function. Used to convert [param other] to the overriding class' type.
|
||||
static func from(other: DeckType):
|
||||
return null
|
||||
|
||||
|
||||
## Generic Error type.
|
||||
##
|
||||
## Always returns [code]null[/code] as the value, and [code]false[/code] as success.[br]
|
||||
## Always returns a new [DeckType.DeckTypeError] on conversion from any other type.
|
||||
class DeckTypeError extends DeckType:
|
||||
## An optional error message.
|
||||
var error_message: String
|
||||
|
||||
|
||||
|
@ -35,11 +43,16 @@ class DeckTypeError extends DeckType:
|
|||
return DeckTypeError.new()
|
||||
|
||||
|
||||
## Numeric type. Corresponds to the JSON number type, so only supports the float primitive type.
|
||||
class DeckTypeNumeric extends DeckType:
|
||||
func _init(value: float = 0.0) -> void:
|
||||
_value = value
|
||||
|
||||
|
||||
## Converts either a [DeckType.DeckTypeString] or [DeckType.DeckTypeBool] to numeric.
|
||||
## In the case of [DeckType.DeckTypeBool], [code]1.0[/code] is used for [code]true[/code],
|
||||
## [code]0.0[/code] for [code]false[/code].[br]
|
||||
## In the case of [DeckType.DeckTypeString], converts to String if it is a valid number
|
||||
## or [DeckType.DeckTypeError] otherwise.
|
||||
static func from(other: DeckType):
|
||||
if other is DeckTypeNumeric:
|
||||
return other
|
||||
|
@ -65,6 +78,7 @@ class DeckTypeNumeric extends DeckType:
|
|||
return err
|
||||
|
||||
|
||||
## String type. Corresponds to the JSON string type. Any type can be converted to String.
|
||||
class DeckTypeString extends DeckType:
|
||||
func _init(value: String = "") -> void:
|
||||
_value = value
|
||||
|
@ -78,11 +92,17 @@ class DeckTypeString extends DeckType:
|
|||
inst._value = var_to_str(other.get_value())
|
||||
|
||||
|
||||
## Boolean type. Corresponds to the JSON bool type.
|
||||
class DeckTypeBool extends DeckType:
|
||||
func _init(value: bool = false) -> void:
|
||||
_value = value
|
||||
|
||||
|
||||
## Converts either [DeckType.DeckTypeNumeric], [DeckType.DeckTypeDictionary] or [DeckType.DeckTypeArray]
|
||||
## to a boolean.[br]
|
||||
## In the case of [DeckType.DeckTypeNumeric], the resulting value will be [code]false[/code]
|
||||
## if the value is a zero value ([code]0.0[/code] and [code]-0.0[/code]), [code]true[/code] otherwise.[br]
|
||||
## In the case of [DeckType.DeckTypeDictionary] or [DeckType.DeckTypeArray],
|
||||
## the resulting value will be [code]true[/code] if the container is not empty.
|
||||
static func from(other: DeckType):
|
||||
if other is DeckTypeBool:
|
||||
return other
|
||||
|
@ -98,11 +118,14 @@ class DeckTypeBool extends DeckType:
|
|||
return inst
|
||||
|
||||
|
||||
## Array type. Corresponds to the JSON Array type.
|
||||
class DeckTypeArray extends DeckType:
|
||||
func _init(value: Array = []) -> void:
|
||||
_value = value
|
||||
|
||||
|
||||
## Arrays can only be converted from a string in the format
|
||||
## [code]"["foo", 2, "bar"][/code].
|
||||
static func from(other: DeckType):
|
||||
if other is DeckTypeString:
|
||||
var inst := DeckTypeArray.new()
|
||||
|
@ -114,11 +137,14 @@ class DeckTypeArray extends DeckType:
|
|||
return err
|
||||
|
||||
|
||||
## Dictionary class. Corresponds to the JSON Object type.
|
||||
class DeckTypeDictionary extends DeckType:
|
||||
func _init(value: Dictionary = {}) -> void:
|
||||
_value = value
|
||||
|
||||
|
||||
## Dictionaries can only be converted from a string in the format
|
||||
## [code]{"key": "value"}[/code].
|
||||
static func from(other: DeckType):
|
||||
if other is DeckTypeString:
|
||||
var inst := DeckTypeDictionary.new()
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
extends MarginContainer
|
||||
class_name AddNodeMenu
|
||||
|
||||
## A menu for adding nodes with a search bar.
|
||||
|
||||
@onready var search_line_edit: LineEdit = %SearchLineEdit
|
||||
@onready var scroll_content_container: VBoxContainer = %ScrollContentContainer
|
||||
@onready var scroll_container: ScrollContainer = $VBoxContainer/ScrollContainer
|
||||
|
||||
## The categories currently shown in the menu.
|
||||
var categories: Dictionary = {} # Dictionary[String, Category]
|
||||
## A list of categories to remember the collapsed state of so they remain collapsed when the search list is rebuilt.
|
||||
var collapsed_categories: Array[String]
|
||||
|
||||
## Emitted when a node is selected either by clicking on it or pressing [constant @GlobalScope.KEY_ENTER] while the [member search_line_edit] is focused.
|
||||
signal node_selected(type: String)
|
||||
|
||||
|
||||
|
@ -15,6 +20,7 @@ func _ready() -> void:
|
|||
search("")
|
||||
|
||||
|
||||
## Add a new category to the menu.
|
||||
func add_category(category_name: String) -> void:
|
||||
var c := Category.new(category_name.capitalize())
|
||||
categories[category_name] = c
|
||||
|
@ -30,11 +36,13 @@ func add_category(category_name: String) -> void:
|
|||
)
|
||||
|
||||
|
||||
## Add an item to a category.
|
||||
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)
|
||||
|
||||
|
||||
## Wrapper around [method add_category_item] and [method add_category]. Adds an item to a [param category], creating the category if it doesn't exist yet.
|
||||
func add_item(category: String, item: String, tooltip: String = "", favorite: bool = false) -> void:
|
||||
if !categories.has(category):
|
||||
add_category(category)
|
||||
|
@ -42,15 +50,18 @@ func add_item(category: String, item: String, tooltip: String = "", favorite: bo
|
|||
add_category_item(category, item, tooltip, favorite)
|
||||
|
||||
|
||||
## Get a [AddNodeMenu.Category] node by its' identifier.
|
||||
func get_category(category: String) -> Category:
|
||||
return categories[category]
|
||||
|
||||
|
||||
## Focus the search bar and select all its' text.
|
||||
func focus_search_bar() -> void:
|
||||
search_line_edit.select_all()
|
||||
search_line_edit.grab_focus()
|
||||
|
||||
|
||||
## Searches for a node using [SearchProvider] and puts the results as items.
|
||||
func search(text: String) -> void:
|
||||
scroll_content_container.get_children().map(func(c: Node): c.queue_free())
|
||||
categories.clear()
|
||||
|
@ -69,6 +80,7 @@ func search(text: String) -> void:
|
|||
get_category(categories.keys()[0]).highlight_item(0)
|
||||
|
||||
|
||||
## Callback for [member search_line_edit]'s input events. Handles highlighting items when navigating with up/down arrow keys.
|
||||
func _on_search_line_edit_gui_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("ui_down"):
|
||||
var category: Category
|
||||
|
@ -123,6 +135,7 @@ func _on_search_line_edit_gui_input(event: InputEvent) -> void:
|
|||
scroll_container.ensure_control_visible(category.get_child(item - 1))
|
||||
|
||||
|
||||
## Callback for [member search_line_edit]. Handles emitting [signal node_selected]
|
||||
func _on_search_line_edit_text_submitted(_new_text: String) -> void:
|
||||
var category: Category
|
||||
for i: String in categories:
|
||||
|
@ -139,15 +152,22 @@ func _on_category_collapse_toggled(collapsed: bool, category: String) -> void:
|
|||
else:
|
||||
collapsed_categories.erase(category)
|
||||
|
||||
|
||||
## A collapsible item menu.
|
||||
##
|
||||
## An analog to [Tree] and [ItemList] made with nodes. Allows collapsing its
|
||||
## children [AddNodeMenu.CategoryItem] nodes and highlighting them.[br]
|
||||
## [b]Note:[/b] only one [AddNodeMenu.CategoryItem] can be highlighted at any time.
|
||||
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
|
||||
|
||||
## Emitted when a child item has been pressed.
|
||||
signal item_pressed(item: int)
|
||||
## Emitted when a child item's favorite button has been pressed.
|
||||
signal item_favorite_button_toggled(item: int, toggled: bool)
|
||||
## Emitted when the category's collapsed state has been toggled.
|
||||
signal collapse_toggled(collapsed: bool)
|
||||
|
||||
|
||||
|
@ -171,6 +191,7 @@ class Category extends VBoxContainer:
|
|||
collapse_button.toggled.connect(set_collapsed)
|
||||
|
||||
|
||||
## If [param collapsed] is [code]true[/code], collapses the category, hiding its children.
|
||||
func set_collapsed(collapsed: bool) -> void:
|
||||
collapse_button.icon = COLLAPSE_ICON_COLLAPSED if collapsed else COLLAPSE_ICON
|
||||
collapse_button.set_pressed_no_signal(collapsed)
|
||||
|
@ -178,6 +199,7 @@ class Category extends VBoxContainer:
|
|||
c.visible = !collapsed
|
||||
|
||||
|
||||
## Add an item to the category.
|
||||
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(
|
||||
|
@ -191,38 +213,46 @@ class Category extends VBoxContainer:
|
|||
add_child(item)
|
||||
|
||||
|
||||
## Set an item's metadata at index [param item].
|
||||
func set_item_metadata(item: int, key: StringName, metadata: Variant) -> void:
|
||||
get_child(item).set_meta(key, metadata)
|
||||
|
||||
|
||||
## Retrieve an item's metadata at index [param item].
|
||||
func get_item_metadata(item: int, key: StringName) -> Variant:
|
||||
return get_child(item).get_meta(key)
|
||||
|
||||
|
||||
## Get the amount of items in this category.
|
||||
func get_item_count() -> int:
|
||||
return get_child_count()
|
||||
|
||||
|
||||
## Toggle an item at index [param item]'s favorite state.
|
||||
func set_item_favorite(item:int, favorite: bool) -> void:
|
||||
var _item := get_child(item) as CategoryItem
|
||||
_item.set_favorite(favorite)
|
||||
|
||||
|
||||
## Returns [code]true[/code] if the item at [param item] is marked as favorite.
|
||||
func is_item_favorite(item: int) -> bool:
|
||||
var _item := get_child(item) as CategoryItem
|
||||
return _item.is_favorite()
|
||||
|
||||
|
||||
## Highlight item at index [item], and unhighlight all other items.
|
||||
func highlight_item(item: int) -> void:
|
||||
for c: CategoryItem in get_children():
|
||||
c.set_highlighted(c.get_index() == item)
|
||||
|
||||
|
||||
## Unhighlight all items.
|
||||
func unhighlight_all() -> void:
|
||||
for c: CategoryItem in get_children():
|
||||
c.set_highlighted(false)
|
||||
|
||||
|
||||
## Returns the index of the currently highlighted item. Returns [code]-1[/code] if no item is highlighted in this category.
|
||||
func get_highlighted_item() -> int:
|
||||
for c: CategoryItem in get_children():
|
||||
if c.is_highlighted:
|
||||
|
@ -231,11 +261,15 @@ class Category extends VBoxContainer:
|
|||
return -1
|
||||
|
||||
|
||||
## Represents an item in a [AddNodeMenu.Category].
|
||||
##
|
||||
## A selectable and highlightable category item with a favorite button.
|
||||
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
|
||||
|
||||
## The stylebox to use if this item is highlighted.
|
||||
var highlighted_stylebox := StyleBoxFlat.new()
|
||||
|
||||
var is_highlighted: bool
|
||||
|
@ -244,7 +278,9 @@ class CategoryItem extends HBoxContainer:
|
|||
var name_button: Button
|
||||
var panel: PanelContainer
|
||||
|
||||
## Emitted when this item has been pressed.
|
||||
signal pressed
|
||||
## Emitted when this item's [member fav_button] has been pressed.
|
||||
signal favorite_toggled(toggled: bool)
|
||||
|
||||
|
||||
|
@ -289,15 +325,18 @@ class CategoryItem extends HBoxContainer:
|
|||
add_child(panel)
|
||||
|
||||
|
||||
## Toggle this item's favorite state.
|
||||
func set_favorite(favorite: bool) -> void:
|
||||
fav_button.icon = FAVORITE_ICON if favorite else NON_FAVORITE_ICON
|
||||
fav_button.set_pressed_no_signal(favorite)
|
||||
|
||||
|
||||
## Returns [code]true[/code] if this item is marked as favorite.
|
||||
func is_favorite() -> bool:
|
||||
return fav_button.icon == FAVORITE_ICON
|
||||
|
||||
|
||||
## Toggle this item's highlighted state.
|
||||
func set_highlighted(highlighted: bool) -> void:
|
||||
is_highlighted = highlighted
|
||||
if highlighted:
|
||||
|
|
Loading…
Reference in a new issue