Class: Teek::UI::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/teek/ui/node.rb

Overview

A single element of the retained-mode tree - a widget, layout container, reactive var, or deferred build-time op (the categories from the architecture doc; this class itself is generic across all of them). Plain Ruby, no Tk: constructible, mutable, and traversable with no interpreter, which is what makes the tree headless-testable.

key is this node's stable identity - the explicit name if given, else whatever the owning Document assigns. realized stays nil for the whole build phase; a realizer fills it in later with a live handle.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type:, name: nil, key: nil, opts: {}, scope: Scope::TOP_LEVEL, document: nil) ⇒ Node

Returns a new instance of Node.

Parameters:

  • type (Symbol)

    node kind, e.g. :button, :column, :var

  • name (Symbol, nil) (defaults to: nil)

    explicit stable name, for addressing (+ui+)

  • key (String, nil) (defaults to: nil)

    stable identity; defaults to +name+'s string form

  • opts (Hash) (defaults to: {})

    widget/node options as plain Ruby values

  • scope (Scope) (defaults to: Scope::TOP_LEVEL)

    the component scope this node was built in - Scope::TOP_LEVEL (the default) for a build that never calls WidgetDSL#component

  • document (Document, nil) (defaults to: nil)

    back-reference to the owning Document - set by Document#create; nil for a raw Node.new built directly (headless tests, mostly). Lets Handle#destroy! unregister a destroyed node's own name(s) without every caller needing to thread a Document reference through by hand.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/teek/ui/node.rb', line 34

def initialize(type:, name: nil, key: nil, opts: {}, scope: Scope::TOP_LEVEL, document: nil)
  @type = type
  @name = name
  @key = key || name&.to_s
  @opts = opts
  @children = []
  @layout = nil
  @events = []
  @realized = nil
  @parent = nil
  @scope = scope
  @document = document
  @lazy = false
  @pending_destroy = false
end

Instance Attribute Details

#childrenObject (readonly)

Returns the value of attribute children.



18
19
20
# File 'lib/teek/ui/node.rb', line 18

def children
  @children
end

#documentObject (readonly)

Returns the value of attribute document.



18
19
20
# File 'lib/teek/ui/node.rb', line 18

def document
  @document
end

#eventsObject (readonly)

Returns the value of attribute events.



18
19
20
# File 'lib/teek/ui/node.rb', line 18

def events
  @events
end

#keyObject

Returns the value of attribute key.



19
20
21
# File 'lib/teek/ui/node.rb', line 19

def key
  @key
end

#layoutObject

Returns the value of attribute layout.



19
20
21
# File 'lib/teek/ui/node.rb', line 19

def layout
  @layout
end

#lazy=(value) ⇒ Object (writeonly)

Sets the attribute lazy

Parameters:

  • value

    the value to set the attribute lazy to.



20
21
22
# File 'lib/teek/ui/node.rb', line 20

def lazy=(value)
  @lazy = value
end

#nameObject (readonly)

Returns the value of attribute name.



18
19
20
# File 'lib/teek/ui/node.rb', line 18

def name
  @name
end

#optsObject (readonly)

Returns the value of attribute opts.



18
19
20
# File 'lib/teek/ui/node.rb', line 18

def opts
  @opts
end

#parentObject

Returns the value of attribute parent.



18
19
20
# File 'lib/teek/ui/node.rb', line 18

def parent
  @parent
end

#pending_destroy=(value) ⇒ Object (writeonly)

Sets the attribute pending_destroy

Parameters:

  • value

    the value to set the attribute pending_destroy to.



20
21
22
# File 'lib/teek/ui/node.rb', line 20

def pending_destroy=(value)
  @pending_destroy = value
end

#realizedObject

Returns the value of attribute realized.



19
20
21
# File 'lib/teek/ui/node.rb', line 19

def realized
  @realized
end

#scopeObject (readonly)

Returns the value of attribute scope.



18
19
20
# File 'lib/teek/ui/node.rb', line 18

def scope
  @scope
end

#typeObject (readonly)

Returns the value of attribute type.



18
19
20
# File 'lib/teek/ui/node.rb', line 18

def type
  @type
end

Instance Method Details

#add_child(node) ⇒ Node

Returns the node just added.

Parameters:

Returns:

  • (Node)

    the node just added



71
72
73
74
75
76
# File 'lib/teek/ui/node.rb', line 71

def add_child(node)
  @children << node
  node.parent = self
  document&.notify(:append, self, node)
  node
end

#display_nameString

A short, human label for this node - its type, plus the explicit name if it has one (e.g. "column" or "column(:ctrl)"). Used by TreeInspector and the build stack's own current_path breadcrumb (WidgetDSL#current_path) - deliberately bare (no leading marker, no "unnamed" filler text) since both of those read as a sequence of these, not a single prose sentence the way Realizer's own private describe does.

Returns:

  • (String)


86
87
88
# File 'lib/teek/ui/node.rb', line 86

def display_name
  name ? "#{type}(:#{name})" : type.to_s
end

#each {|node| ... } ⇒ Enumerator

Depth-first, pre-order traversal of this node and its descendants.

Yield Parameters:

Returns:

  • (Enumerator)

    if no block given



107
108
109
110
111
112
# File 'lib/teek/ui/node.rb', line 107

def each(&block)
  return enum_for(:each) unless block

  block.call(self)
  children.each { |child| child.each(&block) }
end

#lazy?Boolean

Returns whether this node is excluded from the ambient +create+/+link+ tree walk (Realizer#realize, Realizer#realize_subtree)

  • true only for a container built with lazy: true (see WidgetDSL#append_container). A lazy node stays a normal, attached member of the retained tree; it just never gets a real Tk widget until something explicitly realizes it (see Handle#realize!).

Returns:

  • (Boolean)

    whether this node is excluded from the ambient +create+/+link+ tree walk (Realizer#realize, Realizer#realize_subtree)

    • true only for a container built with lazy: true (see WidgetDSL#append_container). A lazy node stays a normal, attached member of the retained tree; it just never gets a real Tk widget until something explicitly realizes it (see Handle#realize!).


57
58
59
# File 'lib/teek/ui/node.rb', line 57

def lazy?
  @lazy
end

#logical_pathString

This node's address, computed purely from the retained tree (name/key + #parent) - no Tk involved, correct before realize. For an ordinary widget this already equals the real Tk path (Realizer#allocate_path walks this identical parent/segment structure); for anything without an independent Tk path of its own (a menu entry, say), an Addressing strategy extends past this with its own marker rather than pretending it's a real one. The other documented exception: a reusable component mounted more than once under the same real parent - Realizer#allocate_path only discovers that repeat (and disambiguates the later mounts' paths) at realize, so this can't predict it ahead of time either. A node that isn't attached anywhere yet (+parent+ nil, and not itself the root) is treated as top-level - the best answer available without a tree to place it in.

Returns:

  • (String)

    e.g. ".", ".toolbar", ".toolbar.save"



129
130
131
132
133
134
# File 'lib/teek/ui/node.rb', line 129

def logical_path
  return '.' if type == :root

  prefix = (parent.nil? || parent.type == :root) ? '.' : "#{parent.logical_path}."
  "#{prefix}#{name || key}"
end

#pending_destroy?Boolean

Returns whether a deferred Handle#destroy! is currently scheduled (via after idle) but hasn't run yet - lets a second destroy! call on the same still-pending handle no-op instead of double-scheduling.

Returns:

  • (Boolean)

    whether a deferred Handle#destroy! is currently scheduled (via after idle) but hasn't run yet - lets a second destroy! call on the same still-pending handle no-op instead of double-scheduling.



65
66
67
# File 'lib/teek/ui/node.rb', line 65

def pending_destroy?
  @pending_destroy
end

#remove_child(node) ⇒ Node

Unlinks node from this node's own children - the symmetric counterpart to #add_child, used by Handle#destroy! so a destroyed node stops being reachable from the retained tree at all (not just Tk-dead - actually gone from children, so a later sibling addition never iterates it, and it becomes collectable once nothing else references it).

Parameters:

Returns:

  • (Node)

    the node just removed



98
99
100
101
102
# File 'lib/teek/ui/node.rb', line 98

def remove_child(node)
  @children.delete(node)
  node.parent = nil
  node
end