ki

package module
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 14, 2018 License: BSD-3-Clause Imports: 20 Imported by: 0

README

goki

Go language (golang) full strength tree structures (ki = tree in Japanese)

Go Report Card GoDoc

Overview

See the Wiki for more docs, discussion, etc.

The Tree is the most powerful data structure in programming, and it underlies all the best tech, such as the WWW (the DOM is a tree structure), scene graphs for 3D and 2D graphics systems, JSON, XML, SVG, filesystems, programs themselves, etc. GoKi provides a powerful tree container type, that can support all of these things just by embedding and extending the Node struct type that implements the Ki (Ki = Tree in Japanese) interface.

Much like LISP (a programming language built around the list data type), the key idea here is to create a comprehensive ecosystem for Go built around Trees (GoKi) -- an awesome, simple programming language with an awesome infrastructure for doing everything you typically need to do with Trees.

The goal of GoKi is to create a minimalist, elegant, and powerful environment (like Go itself) where the tree-based primitives are used to simplify otherwise complex operations. Similar to MATLAB and matricies, you can perform major computational functions using just a few lines of GoKi code. As is always the case in programming, using the right data structure that captures the underlying structure of the problem is essential, and in many cases, that structure is a tree. Of necessity, much existing code incorporates tree structures, but the goal of GoKi is to provide a set of carefully thought-out primitive operations that effectively form a new mental basis set for programming.

For example, GoKi provides functions that traverse the tree in all the relevant ways ("natural" me-first, breadth-first, depth-first, etc) and take a func function argument, so you can easily apply a common operation across the whole tree in a very transparent and self-contained manner, like this:

func (n *MyNode) DoSomethingOnMyTree() {
	n.FuncDownMeFirst(0, nil, func(k Ki, level int, d interface{}) bool {
		mn := KiToMyNode(k)
	    mn.DoSomething()
		...
		return true // return value determines whether tree traversal continues or not
	})
}

Three other core features include:

  • A Signal mechanism that allows nodes to communicate changes and other events to arbitrary lists of other nodes (similar to the signals and slots from Qt).

  • UpdateStart() and UpdateEnd() functions that wrap around code that changes the tree structure or contents -- these automatically and efficiently determine the highest level node that was affected by changes, and only that highest node sends an Updated signal. This allows arbitrarily nested modifications to proceed independently, each wrapped in their own Start / End blocks, with the optimal minimal update signaling automatically computed.

  • ConfigChildren uses a list of types and names and performs a minimal, efficient update of the children of a node to configure them to match (including no changes if already configured accordingly). This is used during loading from JSON, and extensively in the GoGi GUI system to efficiently re-use existing tree elements. There is often complex logic to determine what elements need to be present in a Widget, so separating that out from then configuring the elements that actually are present is very efficient and simplifies the code.

In addition, Ki nodes support a general-purpose Props property map, and the kit package provides a TypeRegistry and an EnumRegistry, along with various reflect utilities, to enable fully-automatic saving / loading of Ki trees from JSON or XML, including converting const int (enum) values to / from strings so those numeric values can change in the code without invalidating existing files.

Ki Nodes can be used as fields in a struct -- they function much like pre-defined Children elements, and all the standard FuncDown* iterators traverse the fields automatically. The Ki Init function automatically names these structs with their field names, and sets the parent to the parent struct.

GoGi Graphical Interface and Gide IDE App

The first and most important application of GoKi is the GoGi graphical interface system, in the gi package, and the Gide IDE built on top of GoGi. The scene graph of Ki elements automatically drives minimal refresh updates, and the signaling framework supports gui event delivery and e.g., the "onclick" event signaling from the Button widget, etc. In short, GoGi provides a complete interactive 2D and 3D GUI environment in native Go, in perhaps the fewest lines of code of any such system. Part of this is the natural elegance of Go, but GoKi enhances that by providing the robust natural primitives needed to express all the GUI functionality. Because GoGi is based around standard CSS styles, SVG rendering, and supports all the major HTML elements, it (will) provide a lightweight, transparent, good-enough-for-many-apps native web browser. This (will) provide an potential alternative to chromium / electron for universal web-app deployment.

Code Map

  • kit package: kit.Types TypeRegistry provides name-to-type map for looking up types by name, and types can have default properties. kit.Enums EnumRegistry provides enum (const int) <-> string conversion, including bitflag enums. Also has robust generic ki.ToInt ki.ToFloat etc converters from interface{} to specific type, for processing properties, and several utilties in embeds.go for managing embedded structure types (e.g., ``TypeEmbedschecks if one type embeds another, andEmbeddedStructreturns the embedded struct from a given struct, providing flexible access to elements of an embedded type hierarchy -- there are also methods for navigating the flattened list of all embedded fields within a struct). Also has akit.Type` struct that supports saving / loading of type information using type names.

  • bitflag package: simple bit flag setting, checking, and clearing methods that take bit position args as ints (from const int eunum iota's) and do the bit shifting from there

  • ki.go = Ki interface for all major tree node functionality.

  • slice.go = ki.Slice []Ki supports saving / loading of Ki objects in a slice, by recording the size and types of elements in the slice -- requires ki.Types type registry to lookup types by name.

  • props.go = ki.Props map[string]interface{} supports saving / loading of property values using actual struct types and named const int enums, using the kit type registries. Used for CSS styling in GoGi.

  • signal.go = Signal that calls function on a receiver Ki objects that have been previously Connected to the signal -- also supports signal type so the same signal sender can send different types of signals over the same connection -- used for signaling changes in tree structure, and more general tree updating signals.

  • ptr.go = ki.Ptr struct that supports saving / loading of pointers using paths.

Status and TODO

Status: as of 11/2018, it is stable and feature-complete, supporting the full Gide app!

Documentation

Overview

Package Ki provides the base element of GoKi Trees: Ki = Tree in Japanese, and "Key" in English -- powerful tree structures supporting scenegraphs, programs, parsing, etc.

The Node struct that implements the Ki interface, which can be used as an embedded type (or a struct field) in other structs to provide core tree functionality, including:

  • Parent / Child Tree structure -- each Node can ONLY have one parent. Node struct's can also have Node fields -- these are functionally like fixed auto-named children.

  • Paths for locating Nodes within the hierarchy -- key for many use-cases, including ability to convert pointers to/from strings for IO and robust deep copy and move functions. The path separator is / for children and . for fields.

  • Apply a function across nodes up or down a tree (natural "me first", breadth-first, depth-first) -- very flexible for tree walking.

  • Generalized I/O -- can Save and Load the Tree as JSON, XML, etc -- including pointers which are saved using paths and automatically cached-out after loading -- enums also bidirectionally convertable to strings using enum type registry in kit package.

  • Robust deep copy, clone, move of nodes, with automatic pointer updating.

  • Signal sending and receiving between Nodes (simlar to Qt Signals / Slots) -- setup connections once and then emit signals to all receivers when relevant event happens.

  • Robust state updating -- wrap updates in UpdateStart / End, and signals are blocked until the final end, at the highest affected level in the tree, at which point a single update signal is sent -- automatically gives the minimal update.

  • Properties (as a string-keyed map) with property inheritance, including type-level properties via kit type registry.

Index

Constants

This section is empty.

Variables

View Source
var DelMgr = Deleted{}

DelMgr is the manager of all deleted items

View Source
var JSONTypePrefix = []byte("{\"ki.RootType\": ")

JSONTypePrefix is the first thing output in a ki tree JSON output file, specifying the type of the root node of the ki tree -- this info appears all on one { } bracketed line at the start of the file, and can also be used to identify the file as a ki tree JSON file

View Source
var JSONTypeSuffix = []byte("}\n")

JSONTypeSuffix is just the } and \n at the end of the prefix line

View Source
var KiT_Flags = kit.Enums.AddEnum(FlagsN, true, nil) // true = bitflags
View Source
var KiT_Node = kit.Types.AddType(&Node{}, nil)

must register all new types so type names can be looked up by name -- also props

View Source
var KiT_Props = kit.Types.AddType(&Props{}, PropsProps)
View Source
var KiT_Ptr = kit.Types.AddType(&Ptr{}, nil)
View Source
var KiT_Signal = kit.Types.AddType(&Signal{}, nil)
View Source
var PropsProps = Props{
	"basic-type": true,
}
View Source
var SignalTrace bool = false

SignalTrace can be set to true to automatically print out a trace of the signals as they are sent

View Source
var SignalTraceString *string

SignalTraceString can be set to a string that will then accumulate the trace of signals sent, for use in testing -- otherwise the trace just goes to stdout

View Source
var UniquifyPreserveNameLimit = 100

UniquifyPreserveNameLimit is the number of children below which a more expensive approach is taken to uniquify the names to guarantee unique paths, which preserves the original name wherever possible -- formatting of index assumes this limit is less than 1000

Functions

func CopyProps

func CopyProps(dest *map[string]interface{}, src map[string]interface{}, copySubProps bool)

CopyProps copies properties from source to destination map. If copySubProps is true, then any values that are Props or PropSlice are copied too *dest can be nil, in which case it is created.

func DecodeXMLCharData

func DecodeXMLCharData(d *xml.Decoder) (val string, err error)

read char data..

func DecodeXMLCharEl

func DecodeXMLCharEl(d *xml.Decoder) (name, val string, err error)

read a start / chardata / end sequence of 3 elements, returning name, val

func DecodeXMLEndEl

func DecodeXMLEndEl(d *xml.Decoder, start xml.StartElement) error

read an end element

func DecodeXMLStartEl

func DecodeXMLStartEl(d *xml.Decoder) (start xml.StartElement, err error)

read a start element token

func FlatFieldsValueFunc

func FlatFieldsValueFunc(stru interface{}, fun func(stru interface{}, typ reflect.Type, field reflect.StructField, fieldVal reflect.Value) bool) bool

Node version of this function from kit/embeds.go

func IsKi

func IsKi(typ reflect.Type) bool

IsKi returns true if the given type implements the Ki interface at any level of embedded structure.

func KiType

func KiType() reflect.Type

KiType returns a Ki reflect.Type, suitable for checking for Type.Implements.

func SliceDeleteAtIndex

func SliceDeleteAtIndex(sl *[]Ki, idx int) bool

SliceDeleteAtIndex deletes item at index -- does not do any further management deleted item -- optimized version for avoiding memory leaks. returns false if index is invalid.

func SliceIndexByFunc

func SliceIndexByFunc(sl *[]Ki, startIdx int, match func(k Ki) bool) (int, bool)

SliceIndexByFunc finds index of item based on match function (which must return true for a find match, false for not). Returns false if not found. startIdx arg allows for optimized bidirectional find if you have an idea where it might be -- can be key speedup for large lists -- pass -1 to start in the middle (good default)

func SliceIndexByName

func SliceIndexByName(sl *[]Ki, name string, startIdx int) (int, bool)

SliceIndexByName returns index of first element that has given name, false if not found. See IndexOf for info on startIdx

func SliceIndexByType

func SliceIndexByType(sl *[]Ki, t reflect.Type, embeds bool, startIdx int) (int, bool)

SliceIndexByType returns index of element that either is that type or embeds that type, false if not found. See IndexOf for info on startIdx.

func SliceIndexByUniqueName

func SliceIndexByUniqueName(sl *[]Ki, name string, startIdx int) (int, bool)

SliceIndexByUniqueName returns index of first element that has given unique name, false if not found. See IndexOf for info on startIdx.

func SliceIndexOf

func SliceIndexOf(sl *[]Ki, kid Ki, startIdx int) (int, bool)

SliceIndexOf returns index of element in list, false if not there. startIdx arg allows for optimized bidirectional find if you have an idea where it might be -- can be key speedup for large lists -- pass -1 to start in the middle (good default).

func SliceInsert

func SliceInsert(sl *[]Ki, k Ki, idx int)

SliceInsert item at index -- does not do any parent updating etc -- use Ki/Node method unless you know what you are doing.

func SliceIsValidIndex

func SliceIsValidIndex(sl *[]Ki, idx int) bool

SliceIsValidIndex checks whether the given index is a valid index into slice, within range of 0..len-1.

func SliceMove

func SliceMove(sl *[]Ki, from, to int) bool

SliceMove moves element from one position to another. Returns false if either index is invalid.

Types

type BlankProp

type BlankProp struct{}

BlankProp is an empty property, for when there isn't any need for the value

type Deleted

type Deleted struct {
	Dels []Ki
	Mu   sync.Mutex
}

Deleted manages all the deleted Ki elements, that are destined to then be destroyed, without having an additional pointer on the Ki object

func (*Deleted) Add

func (dm *Deleted) Add(kis ...Ki)

Add the Ki elements to the deleted list

func (*Deleted) DestroyDeleted

func (dm *Deleted) DestroyDeleted()

type Flags

type Flags int32

Flags are bit flags for efficient core state of nodes -- see bitflag package for using these ordinal values to manipulate bit flag field.

const (
	// IsField indicates a node is a field in its parent node, not a child in children.
	IsField Flags = iota

	// Updating flag is set at UpdateStart and cleared if we were the first
	// updater at UpdateEnd.
	Updating

	// OnlySelfUpdate means that the UpdateStart / End logic only applies to
	// this node in isolation, not to its children -- useful for a parent node
	// that has a different functional role than its children.
	OnlySelfUpdate

	// NodeAdded means a node was added to new parent.
	NodeAdded

	// NodeCopied means node was copied from other node.
	NodeCopied

	// NodeMoved means node was moved in the tree, or to a new tree.
	NodeMoved

	// NodeDeleted means this node has been deleted.
	NodeDeleted

	// NodeDestroyed means this node has been destroyed -- do not trigger any
	// more update signals on it.
	NodeDestroyed

	// ChildAdded means one or more new children were added to the node.
	ChildAdded

	// ChildMoved means one or more children were moved within the node.
	ChildMoved

	// ChildDeleted means one or more children were deleted from the node.
	ChildDeleted

	// ChildrenDeleted means all children were deleted.
	ChildrenDeleted

	// FieldUpdated means a field was updated.
	FieldUpdated

	// PropUpdated means a property was set.
	PropUpdated

	// FlagsN is total number of flags used by base Ki Node -- can extend from
	// here up to 64 bits.
	FlagsN

	// NodeUpdateFlagsMask is a mask for all node updates.
	NodeUpdateFlagsMask = (1 << uint32(NodeAdded)) | (1 << uint32(NodeCopied)) | (1 << uint32(NodeMoved))

	// ChildUpdateFlagsMask is a mask for all child updates.
	ChildUpdateFlagsMask = (1 << uint32(ChildAdded)) | (1 << uint32(ChildMoved)) | (1 << uint32(ChildDeleted)) | (1 << uint32(ChildrenDeleted))

	// StruUpdateFlagsMask is a mask for all structural changes update flags.
	StruUpdateFlagsMask = NodeUpdateFlagsMask | ChildUpdateFlagsMask | (1 << uint32(NodeDeleted))

	// ValUpdateFlagsMask is a mask for all non-structural, value-only changes update flags.
	ValUpdateFlagsMask = (1 << uint32(FieldUpdated)) | (1 << uint32(PropUpdated))

	// UpdateFlagsMask is a Mask for all the update flags -- destroyed is
	// excluded b/c otherwise it would get cleared.
	UpdateFlagsMask = StruUpdateFlagsMask | ValUpdateFlagsMask
)

func (*Flags) FromString

func (i *Flags) FromString(s string) error

func (Flags) String

func (i Flags) String() string

type Func

type Func func(k Ki, level int, data interface{}) bool

Func is a function to call on ki objects walking the tree -- return bool = false means don't continue processing this branch of the tree, but other branches can continue.

type Ki

type Ki interface {
	// Init initializes the node -- automatically called during Add/Insert
	// Child -- sets the This pointer for this node as a Ki interface (pass
	// pointer to node as this arg) -- Go cannot always access the true
	// underlying type for structs using embedded Ki objects (when these objs
	// are receivers to methods) so we need a This interface pointer that
	// guarantees access to the Ki interface in a way that always reveals the
	// underlying type (e.g., in reflect calls).  Calls Init on Ki fields
	// within struct, sets their names to the field name, and sets us as their
	// parent.
	Init(this Ki)

	// InitName initializes this node and set its name -- used for root nodes
	// which don't otherwise have their This pointer set (otherwise typically
	// happens in Add, Insert Child).
	InitName(this Ki, name string)

	// This returns the Ki interface that guarantees access to the Ki
	// interface in a way that always reveals the underlying type
	// (e.g., in reflect calls).  Returns nil if node is nil,
	// has been destroyed, or is improperly constructed.
	This() Ki

	// ThisCheck checks that the This pointer is set and issues a warning to
	// log if not -- returns error if not set -- called when nodes are added
	// and inserted.
	ThisCheck() error

	// Type returns the underlying struct type of this node
	// (reflect.TypeOf(This).Elem()).
	Type() reflect.Type

	// TypeEmbeds tests whether this node is of the given type, or it embeds
	// that type at any level of anonymous embedding -- use Embed to get the
	// embedded struct of that type from this node.
	TypeEmbeds(t reflect.Type) bool

	// Embed returns the embedded struct of given type from this node (or nil
	// if it does not embed that type, or the type is not a Ki type -- see
	// kit.Embed for a generic interface{} version.
	Embed(t reflect.Type) Ki

	// Name returns the user-defined name of the object (Node.Nm), for finding
	// elements, generating paths, IO, etc -- allows generic GUI / Text / Path
	// / etc representation of Trees.
	Name() string

	// UniqueName returns a name that is guaranteed to be non-empty and unique
	// within the children of this node (Node.UniqueNm), but starts with Name
	// or parents name if Name is empty -- important for generating unique
	// paths to definitively locate a given node in the tree (see PathUnique,
	// FindPathUnique).
	UniqueName() string

	// SetName sets the name of this node, and its unique name based on this
	// name, such that all names are unique within list of siblings of this
	// node (somewhat expensive but important, unless you definitely know that
	// the names are unique -- see SetNameRaw).  Does nothing if name is
	// already set to that value -- returns false in that case.  Does NOT
	// wrap in UpdateStart / End.
	SetName(name string) bool

	// SetNameRaw just sets the name and doesn't update the unique name --
	// only use if also/ setting unique names in some other way that is
	// guaranteed to be unique.
	SetNameRaw(name string)

	// SetUniqueName sets the unique name of this node based on given name
	// string -- does not do any further testing that the name is indeed
	// unique -- should generally only be used by UniquifyNames.
	SetUniqueName(name string)

	// UniquifyNames ensures all of my children have unique, non-empty names
	// -- duplicates are named sequentially _1, _2 etc, and empty names get a
	// name based on my name or my type name.
	UniquifyNames()

	// Parent returns the parent of this Ki (Node.Par) -- Ki has strict
	// one-parent, no-cycles structure -- see SetParent.
	Parent() Ki

	// SetParent just sets parent of node (and inherits update count from
	// parent, to keep consistent) -- does NOT remove from existing parent --
	// use Add / Insert / Delete Child functions properly move or delete nodes.
	SetParent(parent Ki)

	// IsRoot tests if this node is the root node -- checks Parent = nil.
	IsRoot() bool

	// Root returns the root object of this tree (the node with a nil parent).
	Root() Ki

	// FieldRoot returns the field root object for this node -- the node that
	// owns the branch of the tree rooted in one of its fields -- i.e., the
	// first non-Field parent node after the first Field parent node -- can be
	// nil if no such thing exists for this node.
	FieldRoot() Ki

	// IndexInParent returns our index within our parent object -- caches the
	// last value and uses that for an optimized search so subsequent calls
	// are typically quite fast.  Returns false if we don't have a parent.
	IndexInParent() (int, bool)

	// ParentLevel finds a given potential parent node recursively up the
	// hierarchy, returning level above current node that the parent was
	// found, and -1 if not found.
	ParentLevel(par Ki) int

	// HasParent checks if given node is a parent of this one (i.e.,
	// ParentLevel(par) != -1).
	HasParent(par Ki) bool

	// ParentByName finds first parent recursively up hierarchy that matches
	// given name -- returns false if not found.
	ParentByName(name string) (Ki, bool)

	// ParentByType finds parent recursively up hierarchy, by type, and
	// returns false if not found. If embeds is true, then it looks for any
	// type that embeds the given type at any level of anonymous embedding.
	ParentByType(t reflect.Type, embeds bool) (Ki, bool)

	// KiFieldByName returns field Ki element by name -- returns false if not found.
	KiFieldByName(name string) (Ki, bool)

	// HasChildren tests whether this node has children (i.e., non-terminal).
	HasChildren() bool

	// Children returns a pointer to the slice of children (Node.Kids) -- use
	// methods on ki.Slice for further ways to access (ByName, ByType, etc).
	// Slice can be modified directly (e.g., sort, reorder) but Add* / Delete*
	// methods on parent node should be used to ensure proper tracking.
	Children() *Slice

	// Child returns the child at given index -- false if index is invalid.
	// See methods on ki.Slice for more ways to acces.
	Child(idx int) (Ki, bool)

	// KnownChild returns the child at given index without checking index --
	// use when index is known to be good.
	KnownChild(idx int) Ki

	// ChildByName returns first element that has given name, false if not
	// found. startIdx arg allows for optimized bidirectional find if you have
	// an idea where it might be -- can be key speedup for large lists -- pass
	// -1 to start in the middle (good default).
	ChildByName(name string, startIdx int) (Ki, bool)

	// KnownChildByName returns first element that has given name, without
	// returning the bool check value -- use when named element is known to
	// exist, and will be directly converted to another type, so the multiple
	// return values are cumbersome.  nil is returned if it actually does not
	// exist. See ChildByName for info on startIdx.
	KnownChildByName(name string, startIdx int) Ki

	// Path returns path to this node from Root(), using regular user-given
	// Name's (may be empty or non-unique), with nodes separated by / and
	// fields by . -- only use for informational purposes.
	Path() string

	// PathUnique returns path to this node from Root(), using unique names,
	// with nodes separated by / and fields by . -- suitable for reliably
	// finding this node.
	PathUnique() string

	// PathFrom returns path to this node from given parent node, using
	// regular user-given Name's (may be empty or non-unique), with nodes
	// separated by / and fields by . -- only use for informational purposes.
	PathFrom(par Ki) string

	// PathFromUnique returns path to this node from given parent node, using
	// unique names, with nodes separated by / and fields by . -- suitable for
	// reliably finding this node.
	PathFromUnique(par Ki) string

	// FindPathUnique returns Ki object at given unique path, starting from
	// this node (e.g., Root()) -- if this node is not the root, then the path
	// to this node is subtracted from the start of the path.  returns false if
	// not found.
	FindPathUnique(path string) (Ki, bool)

	// SetChildType sets the ChildType used as a default type for creating new
	// children -- as a property called ChildType --ensures that the type is a
	// Ki type, and errors if not.
	SetChildType(t reflect.Type) error

	// AddChild adds a new child at end of children list -- if child is in an
	// existing tree, it is removed from that parent, and a NodeMoved signal
	// is emitted for the child -- UniquifyNames is called after adding to
	// ensure name is unique (assumed to already have a name).
	AddChild(kid Ki) error

	// InsertChild adds a new child at given position in children list -- if
	// child is in an existing tree, it is removed from that parent, and a
	// NodeMoved signal is emitted for the child -- UniquifyNames is called
	// after adding to ensure name is unique (assumed to already have a name).
	InsertChild(kid Ki, at int) error

	// NewOfType creates a new child of given type -- if nil, uses ChildType,
	// else uses the same type as this struct.
	NewOfType(typ reflect.Type) Ki

	// AddNewChild creates a new child of given type -- if nil, uses
	// ChildType, else type of this struct -- and add at end of children list
	// -- assigns name (can be empty) and enforces UniqueName.
	AddNewChild(typ reflect.Type, name string) Ki

	// InsertNewChild creates a new child of given type -- if nil, uses
	// ChildType, else type of this struct -- and add at given position in
	// children list -- assigns name (can be empty) and enforces UniqueName.
	InsertNewChild(typ reflect.Type, at int, name string) Ki

	// InsertNewChildUnique adds a new child at given position in children
	// list, and gives it a name, using SetNameRaw and SetUniqueName for the
	// name -- only when names are known to be unique (faster).
	InsertNewChildUnique(typ reflect.Type, at int, name string) Ki

	// SetChild sets child at given index to be the given item -- if name is
	// non-empty then it sets the name of the child as well -- just calls Init
	// (or InitName) on the child, and SetParent -- does NOT uniquify the
	// names -- this is for high-volume child creation -- call UniquifyNames
	// afterward if needed, but better to ensure that names are unique up front.
	SetChild(kid Ki, idx int, name string) error

	// MoveChild moves child from one position to another in the list of
	// children (see also corresponding Slice method).  Returns false if
	// either index is invalid.
	MoveChild(from, to int) bool

	// SetNChildren ensures that there are exactly n children, deleting any
	// extra, and creating any new ones, using AddNewChild with given type and
	// naming according to nameStubX where X is the index of the child.
	//
	// IMPORTANT: returns whether any modifications were made (mods) AND if
	// that is true, the result from the corresponding UpdateStart call --
	// UpdateEnd is NOT called, allowing for further subsequent updates before
	// you call UpdateEnd(updt)
	//
	// Note that this does not ensure existing children are of given type, or
	// change their names, or call UniquifyNames -- use ConfigChildren for
	// those cases -- this function is for simpler cases where a parent uses
	// this function consistently to manage children all of the same type.
	SetNChildren(n int, typ reflect.Type, nameStub string) (mods, updt bool)

	// ConfigChildren configures children according to given list of
	// type-and-name's -- attempts to have minimal impact relative to existing
	// items that fit the type and name constraints (they are moved into the
	// corresponding positions), and any extra children are removed, and new
	// ones added, to match the specified config.  If uniqNm, then names
	// represent UniqueNames (this results in Name == UniqueName for created
	// children).
	//
	// IMPORTANT: returns whether any modifications were made (mods) AND if
	// that is true, the result from the corresponding UpdateStart call --
	// UpdateEnd is NOT called, allowing for further subsequent updates before
	// you call UpdateEnd(updt).
	ConfigChildren(config kit.TypeAndNameList, uniqNm bool) (mods, updt bool)

	// DeleteChildAtIndex deletes child at given index (returns false for
	// invalid index) -- if child's parent = this node, then will call
	// SetParent(nil), so to transfer to another list, set new parent first --
	// destroy will add removed child to deleted list, to be destroyed later
	// -- otherwise child remains intact but parent is nil -- could be
	// inserted elsewhere.
	DeleteChildAtIndex(idx int, destroy bool) bool

	// DeleteChild deletes child node, returning false if not found in
	// Children.  If child's parent = this node, then will call
	// SetParent(nil), so to transfer to another list, set new parent
	// first. See DeleteChildAtIndex for destroy info.
	DeleteChild(child Ki, destroy bool) bool

	// DeleteChildByName deletes child node by name -- returns child, false
	// if not found -- if child's parent = this node, then will call
	// SetParent(nil), so to transfer to another list, set new parent first.
	// See DeleteChildAtIndex for destroy info.
	DeleteChildByName(name string, destroy bool) (Ki, bool)

	// DeleteChildren deletes all children nodes -- destroy will add removed
	// children to deleted list, to be destroyed later -- otherwise children
	// remain intact but parent is nil -- could be inserted elsewhere, but you
	// better have kept a slice of them before calling this.
	DeleteChildren(destroy bool)

	// Delete deletes this node from its parent children list -- destroy will
	// add removed child to deleted list, to be destroyed later -- otherwise
	// child remains intact but parent is nil -- could be inserted elsewhere.
	Delete(destroy bool)

	// Destroy calls DisconnectAll to cut all pointers and signal connections,
	// and remove all children and their childrens-children, etc.
	Destroy()

	// Flag returns an atomically safe copy of the bit flags for this node --
	// can use bitflag package to check lags.
	// See Flags type for standard values used in Ki Node --
	// can be extended from FlagsN up to 64 bit capacity.
	// Note that we must always use atomic access as *some* things need to be atomic,
	// and with bits, that means that *all* access needs to be atomic,
	// as you cannot atomically update just a single bit.
	Flags() int64

	// HasFlag checks if flag is set
	// using atomic, safe for concurrent access
	HasFlag(flag int) bool

	// HasAnyFlag checks if *any* of a set of flags is set (logical OR)
	// using atomic, safe for concurrent access
	HasAnyFlag(flag ...int) bool

	// HasAllFlags checks if *all* of a set of flags is set (logical AND)
	// using atomic, safe for concurrent access
	HasAllFlags(flag ...int) bool

	// SetFlag sets the given flag(s)
	// using atomic, safe for concurrent access
	SetFlag(flag ...int)

	// SetFlagState sets the given flag(s) to given state
	// using atomic, safe for concurrent access
	SetFlagState(on bool, flag ...int)

	// SetFlagMask sets the given flags as a mask
	// using atomic, safe for concurrent access
	SetFlagMask(mask int64)

	// ClearFlag clears the given flag(s)
	// using atomic, safe for concurrent access
	ClearFlag(flag ...int)

	// ClearFlagMask clears the given flags as a bitmask
	// using atomic, safe for concurrent access
	ClearFlagMask(mask int64)

	// IsField checks if this is a field on a parent struct (via IsField
	// Flag), as opposed to a child in Children -- Ki nodes can be added as
	// fields to structs and they are automatically parented and named with
	// field name during Init function -- essentially they function as fixed
	// children of the parent struct, and are automatically included in
	// FuncDown* traversals, etc -- see also FunFields.
	IsField() bool

	// IsUpdating checks if node is currently updating.
	IsUpdating() bool

	// OnlySelfUpdate checks if this node only applies UpdateStart / End logic
	// to itself, not its children (which is the default) (via Flag of same
	// name) -- useful for a parent node that has a different function than
	// its children.
	OnlySelfUpdate() bool

	// SetOnlySelfUpdate sets the OnlySelfUpdate flag -- see OnlySelfUpdate
	// method and flag.
	SetOnlySelfUpdate()

	// IsDeleted checks if this node has just been deleted (within last update
	// cycle), indicated by the NodeDeleted flag which is set when the node is
	// deleted, and is cleared at next UpdateStart call.
	IsDeleted() bool

	// IsDestroyed checks if this node has been destroyed -- the NodeDestroyed
	// flag is set at start of Destroy function -- the Signal Emit process
	// checks for destroyed receiver nodes and removes connections to them
	// automatically -- other places where pointers to potentially destroyed
	// nodes may linger should also check this flag and reset those pointers.
	IsDestroyed() bool

	// Properties (Node.Props) tell the GoGi GUI or other frameworks operating
	// on Trees about special features of each node -- functions below support
	// inheritance up Tree -- see kit convert.go for robust convenience
	// methods for converting interface{} values to standard types.
	Properties() *Props

	// SetProp sets given property key to value val -- initializes property
	// map if nil.
	SetProp(key string, val interface{})

	// SetProps sets a whole set of properties, and optionally sets the
	// updated flag and triggers an UpdateSig.
	SetProps(props Props, update bool)

	// SetPropUpdate sets given property key to value val, with update
	// notification (sets PropUpdated and emits UpdateSig) so other nodes
	// receiving update signals from this node can update to reflect these
	// changes.
	SetPropUpdate(key string, val interface{})

	// SetPropChildren sets given property key to value val for all Children.
	SetPropChildren(key string, val interface{})

	// Prop gets property value from key.
	Prop(key string) (interface{}, bool)

	// KnownProp gets property value from key that is known to exist --
	// returns nil if it actually doesn't -- less cumbersome for conversions.
	KnownProp(key string) interface{}

	// PropInherit gets property value from key with options for inheriting
	// property from parents and / or type-level properties.  If inherit, then
	// checks all parents.  If typ then checks property on type as well
	// (registered via KiT type registry).  Returns false if not set anywhere.
	PropInherit(key string, inherit, typ bool) (interface{}, bool)

	// DeleteProp deletes property key on this node.
	DeleteProp(key string)

	// DeleteAllProps deletes all properties on this node -- just makes a new
	// Props map -- can specify the capacity of the new map (0 means set to
	// nil instead of making a new one -- most efficient if potentially no
	// properties will be set).
	DeleteAllProps(cap int)

	// CopyPropsFrom copies our properties from another node -- if deep then
	// does a deep copy -- otherwise copied map just points to same values in
	// the original map (and we don't reset our map first -- call
	// DeleteAllProps to do that -- deep copy uses gob encode / decode --
	// usually not needed).
	CopyPropsFrom(from Ki, deep bool) error

	// PropTag returns the name to look for in type properties, for types
	// that are valid options for values that can be set in Props.  For example
	// in GoGi, it is "style-props" which is then set for all types that can
	// be used in a style (colors, enum options, etc)
	PropTag() string

	// FuncFields calls function on all Ki fields within this node.
	FuncFields(level int, data interface{}, fun Func)

	// GoFuncFields calls concurrent goroutine function on all Ki fields
	// within this node.
	GoFuncFields(level int, data interface{}, fun Func)

	// FuncUp calls function on given node and all the way up to its parents,
	// and so on -- sequentially all in current go routine (generally
	// necessary for going up, which is typicaly quite fast anyway) -- level
	// is incremented after each step (starts at 0, goes up), and passed to
	// function -- returns false if fun aborts with false, else true.
	FuncUp(level int, data interface{}, fun Func) bool

	// FuncUpParent calls function on parent of node and all the way up to its
	// parents, and so on -- sequentially all in current go routine (generally
	// necessary for going up, which is typicaly quite fast anyway) -- level
	// is incremented after each step (starts at 0, goes up), and passed to
	// function -- returns false if fun aborts with false, else true.
	FuncUpParent(level int, data interface{}, fun Func) bool

	// FuncDownMeFirst calls function on this node (MeFirst) and then call
	// FuncDownMeFirst on all the children -- sequentially all in current go
	// routine -- level var is incremented before calling children -- if fun
	// returns false then any further traversal of that branch of the tree is
	// aborted, but other branches continue -- i.e., if fun on current node
	// returns false, then returns false and children are not processed
	// further -- this is the fastest, most natural form of traversal.
	FuncDownMeFirst(level int, data interface{}, fun Func) bool

	// FuncDownDepthFirst calls FuncDownDepthFirst on all children, then calls
	// function on this node -- sequentially all in current go routine --
	// level var is incremented before calling children -- runs
	// doChildTestFunc on each child first to determine if it should process
	// that child, and if that returns true, then it calls FuncDownDepthFirst
	// on that child.
	FuncDownDepthFirst(level int, data interface{}, doChildTestFunc Func, fun Func)

	// FuncDownBreadthFirst calls function on all children, then calls
	// FuncDownBreadthFirst on all the children -- does NOT call on first node
	// where this method is first called, due to nature of recursive logic --
	// level var is incremented before calling children -- if fun returns
	// false then any further traversal of that branch of the tree is aborted,
	// but other branches can continue.
	FuncDownBreadthFirst(level int, data interface{}, fun Func)

	// GoFuncDown calls concurrent goroutine function on given node and all
	// the way down to its children, and so on -- does not wait for completion
	// of the go routines -- returns immediately.
	GoFuncDown(level int, data interface{}, fun Func)

	// NodeSignal returns the main signal for this node that is used for
	// update, child signals.
	NodeSignal() *Signal

	// UpdateStart should be called when starting to modify the tree (state or
	// structure) -- returns whether this node was first to set the Updating
	// flag (if so, all children have their Updating flag set -- pass the
	// result to UpdateEnd -- automatically determines the highest level
	// updated, within the normal top-down updating sequence -- can be called
	// multiple times at multiple levels -- it is essential to ensure that all
	// such Start's have an End!  Usage:
	//
	//   updt := n.UpdateStart()
	//   ... code
	//   n.UpdateEnd(updt)
	// or
	//   updt := n.UpdateStart()
	//   defer n.UpdateEnd(updt)
	//   ... code
	UpdateStart() bool

	// UpdateEnd should be called when done updating after an UpdateStart, and
	// passed the result of the UpdateStart call -- if this is true, the
	// NodeSignalUpdated signal will be emitted and the Updating flag will be
	// cleared, and DestroyDeleted called -- otherwise it is a no-op.
	UpdateEnd(updt bool)

	// UpdateEndNoSig is just like UpdateEnd except it does not emit a
	// NodeSignalUpdated signal -- use this for situations where updating is
	// already known to be in progress and the signal would be redundant.
	UpdateEndNoSig(updt bool)

	// UpdateSig just emits a NodeSignalUpdated if the Updating flag is not
	// set -- use this to trigger an update of a given node when there aren't
	// any structural changes and you don't need to prevent any lower-level
	// updates -- much more efficient than a pair of UpdateStart /
	// UpdateEnd's.  Returns true if an update signal was sent.
	UpdateSig() bool

	// UpdateReset resets Updating flag for this node and all children -- in
	// case they are out-of-sync due to more complex tree maninpulations --
	// only call at a known point of non-updating.
	UpdateReset()

	// Disconnect disconnects node -- reset all ptrs to nil, and
	// DisconnectAll() signals -- e.g., for freeing up all connnections so
	// node can be destroyed and making GC easier.
	Disconnect()

	// DisconnectAll disconnects all the way from me down the tree.
	DisconnectAll()

	// SetField sets given field name to given value, using very robust
	// conversion routines to e.g., convert from strings to numbers, and
	// vice-versa, automatically -- returns true if successfully set --
	// wrapped in UpdateStart / End and sets the FieldUpdated flag.
	SetField(field string, val interface{}) bool

	// SetFieldDown sets given field name to given value, all the way down the
	// tree from me -- wrapped in UpdateStart / End.
	SetFieldDown(field string, val interface{})

	// SetFieldUp sets given field name to given value, all the way up the
	// tree from me -- wrapped in UpdateStart / End.
	SetFieldUp(field string, val interface{})

	// FieldByName returns field value by name (can be any type of field --
	// see KiFieldByName for Ki fields) -- returns nil if not found.
	FieldByName(field string) interface{}

	// FieldTag returns given field tag for that field, or empty string if not
	// set.
	FieldTag(field, tag string) string

	// CopyFrom another Ki node.  The Ki copy function recreates the entire
	// tree in the copy, duplicating children etc.  It is very efficient by
	// using the ConfigChildren method which attempts to preserve any existing
	// nodes in the destination if they have the same name and type -- so a
	// copy from a source to a target that only differ minimally will be
	// minimally destructive.  Only copies to same types are supported.
	// Pointers (Ptr) are copied by saving the current UniquePath and then
	// SetPtrsFmPaths is called.  Signal connections are NOT copied.  No other
	// Ki pointers are copied, and the field tag copy:"-" can be added for any
	// other fields that should not be copied (unexported, lower-case fields
	// are not copyable).
	//
	// When nodes are copied from one place to another within the same overall
	// tree, paths are updated so that pointers to items within the copied
	// sub-tree are updated to the new location there (i.e., the path to the
	// old loation is replaced with that of the new destination location),
	// whereas paths outside of the copied location are not changed and point
	// as before.  See also MoveTo function for moving nodes to other parts of
	// the tree.  Sequence of functions is: GetPtrPaths on from, CopyFromRaw,
	// UpdtPtrPaths, then SetPtrsFmPaths.
	CopyFrom(from Ki) error

	// Clone creates and returns a deep copy of the tree from this node down.
	// Any pointers within the cloned tree will correctly point within the new
	// cloned tree (see Copy info).
	Clone() Ki

	// CopyFromRaw performs a raw copy that just does the deep copy of the
	// bits and doesn't do anything with pointers.
	CopyFromRaw(from Ki) error

	// GetPtrPaths gets all Ptr path strings -- walks the tree down from
	// current node and calls GetPath on all Ptr fields -- this is called
	// prior to copying / moving.
	GetPtrPaths()

	// UpdatePtrPaths updates Ptr paths, replacing any occurrence of oldPath with
	// newPath, optionally only at the start of the path (typically true) --
	// for all nodes down from this one.
	UpdatePtrPaths(oldPath, newPath string, startOnly bool)

	// SetPtrsFmPaths walks the tree down from current node and calls
	// PtrFromPath on all Ptr fields found -- called after Copy, Unmarshal* to
	// recover pointers after entire structure is in place -- see
	// UnmarshalPost.
	SetPtrsFmPaths()

	// WriteJSON writes the tree to an io.Writer, using MarshalJSON -- also
	// saves a critical starting record that allows file to be loaded de-novo
	// and recreate the proper root type for the tree.
	WriteJSON(writer io.Writer, indent bool) error

	// SaveJSON saves the tree to a JSON-encoded file, using WriteJSON.
	SaveJSON(filename string) error

	// ReadJSON reads and unmarshals tree starting at this node, from a
	// JSON-encoded byte stream via io.Reader.  First element in the stream
	// must be of same type as this node -- see ReadNewJSON function to
	// construct a new tree.  Uses ConfigureChildren to minimize changes from
	// current tree relative to loading one -- wraps UnmarshalJSON and calls
	// UnmarshalPost to recover pointers from paths.
	ReadJSON(reader io.Reader) error

	// OpenJSON opens file over this tree from a JSON-encoded file -- see
	// ReadJSON for details, and OpenNewJSON for opening an entirely new tree.
	OpenJSON(filename string) error

	// WriteXML writes the tree to an XML-encoded byte string over io.Writer
	// using MarshalXML.
	WriteXML(writer io.Writer, indent bool) error

	// ReadXML reads the tree from an XML-encoded byte string over io.Reader, calls
	// UnmarshalPost to recover pointers from paths.
	ReadXML(reader io.Reader) error

	// ParentAllChildren walks the tree down from current node and call
	// SetParent on all children -- needed after an Unmarshal.
	ParentAllChildren()

	// UnmarshalPost must be called after an Unmarshal -- calls
	// SetPtrsFmPaths and ParentAllChildren.
	UnmarshalPost()
}

The Ki interface provides the core functionality for the GoKi tree -- insipred by Qt QObject in specific and every other Tree everywhere in general.

NOTE: The inability to have a field and a method of the same name makes it so you either have to use private fields in a struct that implements this interface (lowercase) or we have to use different names in the struct vs. interface. We want to export and use the direct fields, which are easy to use, so we have different synonyms.

Other key issues with the Ki design / Go: * All interfaces are implicitly pointers: this is why you have to pass args with & address of.

func NewOfType

func NewOfType(typ reflect.Type) Ki

NewOfType makes a new Ki struct of given type -- must be a Ki type -- will return nil if not.

func OpenNewJSON

func OpenNewJSON(filename string) (Ki, error)

OpenNewJSON opens a new Ki tree from a JSON-encoded file, using type information at start of file to create an object of the proper type

func ReadNewJSON

func ReadNewJSON(reader io.Reader) (Ki, error)

ReadNewJSON reads a new Ki tree from a JSON-encoded byte string, using type information at start of file to create an object of the proper type

type Node

type Node struct {
	Nm       string `copy:"-" label:"Name" desc:"Ki.Name() user-supplied name of this node -- can be empty or non-unique"`
	UniqueNm string `` /* 219-byte string literal not displayed */
	Flag     int64  `copy:"-" json:"-" xml:"-" view:"-" desc:"bit flags for internal node state"`
	Props    Props  `` /* 135-byte string literal not displayed */
	Par      Ki     `` /* 154-byte string literal not displayed */
	Kids     Slice  `` /* 217-byte string literal not displayed */
	NodeSig  Signal `` /* 225-byte string literal not displayed */
	Ths      Ki     `` /* 379-byte string literal not displayed */
	// contains filtered or unexported fields
}

The Node implements the Ki interface and provides the core functionality for the GoKi tree -- use the Node as an embedded struct or as a struct field -- the embedded version supports full JSON save / load.

The desc: key for fields is used by the GoGi GUI viewer for help / tooltip info -- add these to all your derived struct's fields. See relevant docs for other such tags controlling a wide range of GUI and other functionality -- Ki makes extensive use of such tags.

func (*Node) AddChild

func (n *Node) AddChild(kid Ki) error

func (*Node) AddChildCheck

func (n *Node) AddChildCheck(kid Ki) error

check if it is safe to add child -- it cannot be a parent of us -- prevent loops!

func (*Node) AddChildImpl

func (n *Node) AddChildImpl(kid Ki) error

func (*Node) AddNewChild

func (n *Node) AddNewChild(typ reflect.Type, name string) Ki

func (*Node) Child

func (n *Node) Child(idx int) (Ki, bool)

func (*Node) ChildByName

func (n *Node) ChildByName(name string, startIdx int) (Ki, bool)

func (*Node) Children

func (n *Node) Children() *Slice

func (*Node) ClearFlag

func (n *Node) ClearFlag(flag ...int)

func (*Node) ClearFlagMask

func (n *Node) ClearFlagMask(mask int64)

func (*Node) Clone

func (n *Node) Clone() Ki

func (*Node) ConfigChildren

func (n *Node) ConfigChildren(config kit.TypeAndNameList, uniqNm bool) (mods, updt bool)

func (*Node) CopyFieldsFrom

func (n *Node) CopyFieldsFrom(to interface{}, from interface{})

copy from primary fields of from to to, recursively following anonymous embedded structs

func (*Node) CopyFrom

func (n *Node) CopyFrom(from Ki) error

func (*Node) CopyFromRaw

func (n *Node) CopyFromRaw(from Ki) error

func (*Node) CopyMakeChildrenFrom

func (n *Node) CopyMakeChildrenFrom(from Ki)

use ConfigChildren to recreate source children

func (*Node) CopyPropsFrom

func (n *Node) CopyPropsFrom(from Ki, deep bool) error

func (*Node) Delete

func (n *Node) Delete(destroy bool)

func (*Node) DeleteAllProps

func (n *Node) DeleteAllProps(cap int)

func (*Node) DeleteChild

func (n *Node) DeleteChild(child Ki, destroy bool) bool

func (*Node) DeleteChildAtIndex

func (n *Node) DeleteChildAtIndex(idx int, destroy bool) bool

func (*Node) DeleteChildByName

func (n *Node) DeleteChildByName(name string, destroy bool) (Ki, bool)

func (*Node) DeleteChildren

func (n *Node) DeleteChildren(destroy bool)

func (*Node) DeleteProp

func (n *Node) DeleteProp(key string)

func (*Node) Destroy

func (n *Node) Destroy()

func (*Node) Disconnect

func (n *Node) Disconnect()

func (*Node) DisconnectAll

func (n *Node) DisconnectAll()

func (*Node) Embed

func (n *Node) Embed(t reflect.Type) Ki

func (*Node) FieldByName

func (n *Node) FieldByName(field string) interface{}

func (*Node) FieldRoot

func (n *Node) FieldRoot() Ki

func (*Node) FieldTag

func (n *Node) FieldTag(field, tag string) string

func (*Node) Fields

func (n *Node) Fields() []uintptr

func (*Node) FindPathUnique

func (n *Node) FindPathUnique(path string) (Ki, bool)

func (*Node) Flags

func (n *Node) Flags() int64

func (*Node) FuncDownBreadthFirst

func (n *Node) FuncDownBreadthFirst(level int, data interface{}, fun Func)

func (*Node) FuncDownDepthFirst

func (n *Node) FuncDownDepthFirst(level int, data interface{}, doChildTestFunc Func, fun Func)

func (*Node) FuncDownMeFirst

func (n *Node) FuncDownMeFirst(level int, data interface{}, fun Func) bool

func (*Node) FuncFields

func (n *Node) FuncFields(level int, data interface{}, fun Func)

func (*Node) FuncUp

func (n *Node) FuncUp(level int, data interface{}, fun Func) bool

func (*Node) FuncUpParent

func (n *Node) FuncUpParent(level int, data interface{}, fun Func) bool

func (*Node) GetPtrPaths

func (n *Node) GetPtrPaths()

func (*Node) GoFuncDown

func (n *Node) GoFuncDown(level int, data interface{}, fun Func)

func (*Node) GoFuncFields

func (n *Node) GoFuncFields(level int, data interface{}, fun Func)

func (*Node) HasAllFlags

func (n *Node) HasAllFlags(flag ...int) bool

func (*Node) HasAnyFlag

func (n *Node) HasAnyFlag(flag ...int) bool

func (*Node) HasChildren

func (n *Node) HasChildren() bool

func (*Node) HasFlag

func (n *Node) HasFlag(flag int) bool

func (*Node) HasParent

func (n *Node) HasParent(par Ki) bool

func (*Node) IndexInParent

func (n *Node) IndexInParent() (int, bool)

func (*Node) Init

func (n *Node) Init(this Ki)

func (*Node) InitName

func (n *Node) InitName(k Ki, name string)

func (*Node) InsertChild

func (n *Node) InsertChild(kid Ki, at int) error

func (*Node) InsertChildImpl

func (n *Node) InsertChildImpl(kid Ki, at int) error

func (*Node) InsertNewChild

func (n *Node) InsertNewChild(typ reflect.Type, at int, name string) Ki

func (*Node) InsertNewChildUnique

func (n *Node) InsertNewChildUnique(typ reflect.Type, at int, name string) Ki

func (*Node) IsDeleted

func (n *Node) IsDeleted() bool

func (*Node) IsDestroyed

func (n *Node) IsDestroyed() bool

func (*Node) IsField

func (n *Node) IsField() bool

func (*Node) IsRoot

func (n *Node) IsRoot() bool

func (*Node) IsUpdating

func (n *Node) IsUpdating() bool

func (*Node) IsValidIndex

func (n *Node) IsValidIndex(idx int) bool

func (*Node) KiFieldByName

func (n *Node) KiFieldByName(name string) (Ki, bool)

func (*Node) KnownChild

func (n *Node) KnownChild(idx int) Ki

func (*Node) KnownChildByName

func (n *Node) KnownChildByName(name string, startIdx int) Ki

func (*Node) KnownProp

func (n *Node) KnownProp(key string) interface{}

func (*Node) MoveChild

func (n *Node) MoveChild(from, to int) bool

func (*Node) Name

func (n *Node) Name() string

func (*Node) NewOfType

func (n *Node) NewOfType(typ reflect.Type) Ki

func (*Node) NodeSignal

func (n *Node) NodeSignal() *Signal

func (*Node) OnlySelfUpdate

func (n *Node) OnlySelfUpdate() bool

func (*Node) OpenJSON

func (n *Node) OpenJSON(filename string) error

func (*Node) Parent

func (n *Node) Parent() Ki

func (*Node) ParentAllChildren

func (n *Node) ParentAllChildren()

func (*Node) ParentByName

func (n *Node) ParentByName(name string) (Ki, bool)

func (*Node) ParentByType

func (n *Node) ParentByType(t reflect.Type, embeds bool) (Ki, bool)

func (*Node) ParentLevel

func (n *Node) ParentLevel(par Ki) int

func (*Node) Path

func (n *Node) Path() string

func (*Node) PathFrom

func (n *Node) PathFrom(par Ki) string

func (*Node) PathFromUnique

func (n *Node) PathFromUnique(par Ki) string

func (*Node) PathUnique

func (n *Node) PathUnique() string

func (*Node) Prop

func (n *Node) Prop(key string) (interface{}, bool)

func (*Node) PropInherit

func (n *Node) PropInherit(key string, inherit, typ bool) (interface{}, bool)

func (*Node) PropTag

func (n *Node) PropTag() string

func (*Node) Properties

func (n *Node) Properties() *Props

func (*Node) ReadJSON

func (n *Node) ReadJSON(reader io.Reader) error

func (*Node) ReadXML

func (n *Node) ReadXML(reader io.Reader) error

func (*Node) Root

func (n *Node) Root() Ki

func (*Node) SaveJSON

func (n *Node) SaveJSON(filename string) error

func (*Node) SetChild

func (n *Node) SetChild(kid Ki, idx int, name string) error

func (*Node) SetChildType

func (n *Node) SetChildType(t reflect.Type) error

func (*Node) SetField

func (n *Node) SetField(field string, val interface{}) bool

func (*Node) SetFieldDown

func (n *Node) SetFieldDown(field string, val interface{})

func (*Node) SetFieldUp

func (n *Node) SetFieldUp(field string, val interface{})

func (*Node) SetFlag

func (n *Node) SetFlag(flag ...int)

func (*Node) SetFlagMask

func (n *Node) SetFlagMask(mask int64)

func (*Node) SetFlagState

func (n *Node) SetFlagState(on bool, flag ...int)

func (*Node) SetNChildren

func (n *Node) SetNChildren(trgn int, typ reflect.Type, nameStub string) (mods, updt bool)

func (*Node) SetName

func (n *Node) SetName(name string) bool

set name and unique name, ensuring unique name is unique..

func (*Node) SetNameRaw

func (n *Node) SetNameRaw(name string)

func (*Node) SetOnlySelfUpdate

func (n *Node) SetOnlySelfUpdate()

func (*Node) SetParent

func (n *Node) SetParent(parent Ki)

func (*Node) SetProp

func (n *Node) SetProp(key string, val interface{})

func (*Node) SetPropChildren

func (n *Node) SetPropChildren(key string, val interface{})

func (*Node) SetPropUpdate

func (n *Node) SetPropUpdate(key string, val interface{})

func (*Node) SetProps

func (n *Node) SetProps(props Props, update bool)

func (*Node) SetPtrsFmPaths

func (n *Node) SetPtrsFmPaths()

func (*Node) SetUniqueName

func (n *Node) SetUniqueName(name string)

func (Node) String

func (n Node) String() string

String implements the fmt.stringer interface -- returns the PathUnique of the node

func (*Node) This

func (n *Node) This() Ki

func (*Node) ThisCheck

func (n *Node) ThisCheck() error

func (*Node) Type

func (n *Node) Type() reflect.Type

func (*Node) TypeEmbeds

func (n *Node) TypeEmbeds(t reflect.Type) bool

func (*Node) UniqueName

func (n *Node) UniqueName() string

func (*Node) UniquifyNames

func (n *Node) UniquifyNames()

UniquifyNames makes sure that the names are unique -- the "deluxe" version preserves the regular User-given name but is relatively expensive (creates a map), so is only used below a certain size (UniquifyPreserveNameLimit = 100), above which the index is appended, guaranteeing uniqueness at the cost of making paths longer and less user-friendly

func (*Node) UnmarshalPost

func (n *Node) UnmarshalPost()

func (*Node) UpdateEnd

func (n *Node) UpdateEnd(updt bool)

func (*Node) UpdateEndNoSig

func (n *Node) UpdateEndNoSig(updt bool)

func (*Node) UpdatePtrPaths

func (n *Node) UpdatePtrPaths(oldPath, newPath string, startOnly bool)

func (*Node) UpdateReset

func (n *Node) UpdateReset()

func (*Node) UpdateSig

func (n *Node) UpdateSig() bool

func (*Node) UpdateStart

func (n *Node) UpdateStart() bool

func (*Node) WriteJSON

func (n *Node) WriteJSON(writer io.Writer, indent bool) error

func (*Node) WriteXML

func (n *Node) WriteXML(writer io.Writer, indent bool) error

type NodeSignals

type NodeSignals int64

NodeSignals are signals that a Ki node sends about updates to the tree structure using the NodeSignal (convert sig int64 to NodeSignals to get the stringer name).

const (
	// NodeSignalNil is a nil signal value
	NodeSignalNil NodeSignals = iota

	// NodeSignalUpdated indicates that the node was updated -- the node Flags
	// accumulate the specific changes made since the last update signal --
	// these flags are sent in the signal data -- strongly recommend using
	// that instead of the flags, which can be subsequently updated by the
	// time a signal is processed
	NodeSignalUpdated

	// NodeSignalDeleting indicates that the node is being deleted from its
	// parent children list -- this is not blocked by Updating status and is
	// delivered immediately
	NodeSignalDeleting

	// NodeSignalDestroying indicates that the node is about to be destroyed
	// -- this is a second pass after removal from parent -- all of its
	// children and Ki fields will be destroyed too -- not blocked by updating
	// status and delivered immediately
	NodeSignalDestroying

	NodeSignalsN
)

Standard signal types sent by ki.Node on its NodeSig for tree state changes

func (*NodeSignals) FromString

func (i *NodeSignals) FromString(s string) error

func (NodeSignals) String

func (i NodeSignals) String() string

type PropSlice

type PropSlice []PropStruct

PropSlice is a slice of PropStruct, for when order is important within a subset of properties (maps do not retain order) -- can set the value of a property to a PropSlice to create an ordered list of property values.

func SliceProps

func SliceProps(pr map[string]interface{}, key string) (PropSlice, bool)

SliceProps returns a value that contains a PropSlice, or nil and false if it doesn't exist or isn't a PropSlice

func SliceTypeProps

func SliceTypeProps(pr map[string]interface{}, key string) (PropSlice, bool)

SliceTypeProps returns a value that contains a PropSlice, or nil and false if it doesn't exist or isn't a PropSlice -- for TypeProps, uses locking

func (*PropSlice) CopyFrom

func (dest *PropSlice) CopyFrom(src PropSlice, copySubProps bool)

CopyFrom copies properties from source to destination propslice. If copySubProps is true, then any values that are Props or PropSlice are copied too *dest can be nil, in which case it is created.

type PropStruct

type PropStruct struct {
	Name  string
	Value interface{}
}

PropStruct is a struct of Name and Value, for use in a PropSlice to hold properties that require order information (maps do not retain any order)

type Props

type Props map[string]interface{}

Props is the type used for holding generic properties -- the actual Go type is a mouthful and not very gui-friendly, and we need some special json methods

func SubProps

func SubProps(pr map[string]interface{}, key string) (Props, bool)

SubProps returns a value that contains another props, or nil and false if it doesn't exist or isn't a Props

func SubTypeProps

func SubTypeProps(pr map[string]interface{}, key string) (Props, bool)

SubTypeProps returns a value that contains another props, or nil and false if it doesn't exist or isn't a Props -- for TypeProps, uses locking

func (*Props) CopyFrom

func (dest *Props) CopyFrom(src map[string]interface{}, copySubProps bool)

CopyFrom copies properties from source to receiver destination map. If copySubProps is true, then any values that are Props or PropSlice are copied too *dest can be nil, in which case it is created.

func (Props) MarshalJSON

func (p Props) MarshalJSON() ([]byte, error)

MarshalJSON saves the type information for each struct used in props, as a separate key with the __type: prefix -- this allows the Unmarshal to create actual types

func (*Props) UnmarshalJSON

func (p *Props) UnmarshalJSON(b []byte) error

UnmarshalJSON parses the type information in the map to restore actual objects -- this is super inefficient and really needs a native parser, but props are likely to be relatively small

type Ptr

type Ptr struct {
	Ptr  Ki `json:"-" xml:"-"`
	Path string
}

Ptr provides JSON marshal / unmarshal via saved PathUnique

func (*Ptr) GetPath

func (k *Ptr) GetPath()

GetPath updates the Path field with the current path to the pointer

func (Ptr) MarshalJSON

func (k Ptr) MarshalJSON() ([]byte, error)

MarshalJSON gets the current path and saves only the Path directly as value of this struct

func (Ptr) MarshalXML

func (k Ptr) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML getes the current path and saves it

func (*Ptr) PtrFmPath

func (k *Ptr) PtrFmPath(root Ki) bool

PtrFromPath finds and sets the Ptr value based on the current Path string -- returns true if pointer is found and non-nil

func (*Ptr) Reset

func (k *Ptr) Reset()

reset the pointer to nil, and the path to empty

func (*Ptr) UnmarshalJSON

func (k *Ptr) UnmarshalJSON(b []byte) error

UnarshalJSON loads the Path string directly from saved value -- KiNode must call SetPtrsFmPaths to actually update the pointers, based on the root object in the tree from which trees were generated, after all the initial loading has completed and the structure is all in place

func (*Ptr) UnmarshalXML

func (k *Ptr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML loads the Path string directly from saved value -- KiNode must call SetPtrsFmPaths to actually update the pointers, based on the root object in the tree from which trees were generated, after all the initial loading has completed and the structure is all in place

func (*Ptr) UpdatePath

func (k *Ptr) UpdatePath(oldPath, newPath string, startOnly bool)

UpdatePath replaces any occurrence of oldPath with newPath, optionally only at the start of the path (typically true)

type RecvFunc

type RecvFunc func(recv, send Ki, sig int64, data interface{})

RecvFunc is a receiver function type for signals -- gets the full connection information and signal, data as specified by the sender. It is good practice to avoid closures in these functions, which can be numerous and have a long lifetime, by converting the recv, send into their known types and referring to them directly

type Signal

type Signal struct {
	Cons map[Ki]RecvFunc `view:"-" json:"-" xml:"-" desc:"map of receivers and their functions"`
	Mu   sync.RWMutex    `` /* 132-byte string literal not displayed */
}

Signal implements general signal passing between Ki objects, like Qt's Signal / Slot system.

This design pattern separates three different factors: * when to signal that something has happened * who should receive that signal * what should the receiver do in response to the signal

Keeping these three things entirely separate greatly simplifies the overall logic.

A receiver connects in advance to a given signal on a sender to receive its signals -- these connections are typically established in an initialization step. There can be multiple different signals on a given sender, and to make more efficient use of signal connections, the sender can also send an int64 signal value that further discriminates the nature of the event, as documented in the code associated with the sender (typically an enum is used). Furthermore, arbitrary data as an interface{} can be passed as well.

The Signal uses a map indexed by the receiver pointer to hold the connections -- this means that there can only be one such connection per receiver, and the order of signal emission to different receiveres will be random.

Typically an inline anonymous closure receiver function is used to keep all the relevant code in one place. Due to the typically long-standing nature of these connections, it is more efficient to avoid capturing external variables, and rely instead on appropriately interpreting the sent argument values. e.g.:

send := sender.EmbeddedStruct(KiT_SendType).(*SendType)

is guaranteed to result in a usable pointer to the sender of known type at least SendType, in a case where that sender might actually embed that SendType (otherwise if it is known to be of a given type, just directly converting as such is fine)

func (*Signal) Connect

func (s *Signal) Connect(recv Ki, fun RecvFunc)

Connect attaches a new receiver and function to the signal -- only one such connection per receiver can be made, so any existing connection to that receiver will be overwritten

func (*Signal) ConnectOnly

func (s *Signal) ConnectOnly(recv Ki, fun RecvFunc)

ConnectOnly first deletes any existing connections and then attaches a new receiver to the signal

func (*Signal) Disconnect

func (s *Signal) Disconnect(recv Ki)

Disconnect disconnects (deletes) the connection for a given receiver

func (*Signal) DisconnectAll

func (s *Signal) DisconnectAll()

DisconnectAll removes all connections

func (*Signal) Emit

func (s *Signal) Emit(sender Ki, sig int64, data interface{})

Emit sends the signal across all the connections to the receivers -- sequentially but in random order due to the randomization of map iteration

func (*Signal) EmitFiltered

func (s *Signal) EmitFiltered(sender Ki, sig int64, data interface{}, filtFun SignalFilterFunc)

EmitFiltered calls function on each potential receiver, and only sends signal if function returns true

func (*Signal) EmitGo

func (s *Signal) EmitGo(sender Ki, sig int64, data interface{})

EmitGo is the concurrent version of Emit -- sends the signal across all the connections to the receivers as separate goroutines

func (*Signal) EmitGoFiltered

func (s *Signal) EmitGoFiltered(sender Ki, sig int64, data interface{}, filtFun SignalFilterFunc)

EmitGoFiltered is the concurrent version of EmitFiltered -- calls function on each potential receiver, and only sends signal if function returns true (filtering is sequential iteration over receivers)

func (*Signal) EmitTrace

func (s *Signal) EmitTrace(sender Ki, sig int64, data interface{})

EmitTrace records a trace of signal being emitted

func (*Signal) SendSig

func (s *Signal) SendSig(recv, sender Ki, sig int64, data interface{})

SendSig sends a signal to one given receiver -- receiver must already be connected so that its receiving function is available

type SignalFilterFunc

type SignalFilterFunc func(recv Ki) bool

SignalFilterFunc is the function type for filtering signals before they are sent -- returns false to prevent sending, and true to allow sending

type Slice

type Slice []Ki

Slice is just a slice of ki elements: []Ki, providing methods for accessing elements in the slice, and JSON marshal / unmarshal with encoding of underlying types

func (*Slice) Config

func (sl *Slice) Config(n Ki, config kit.TypeAndNameList, uniqNm bool) (mods, updt bool)

Config is a major work-horse routine for minimally-destructive reshaping of a tree structure to fit a target configuration, specified in terms of a type-and-name list. If the node is != nil, then it has UpdateStart / End logic applied to it, only if necessary, as indicated by mods, updt return values.

func (*Slice) DeleteAtIndex

func (sl *Slice) DeleteAtIndex(idx int) bool

DeleteAtIndex deletes item at index -- does not do any further management deleted item -- optimized version for avoiding memory leaks. returns false if index is invalid.

func (*Slice) Elem

func (sl *Slice) Elem(idx int) (Ki, bool)

Elem returns element at index, returning false if invalid index

func (*Slice) ElemByName

func (sl *Slice) ElemByName(name string, startIdx int) (Ki, bool)

ElemByName returns first element that has given name, false if not found. See IndexOf for info on startIdx.

func (*Slice) ElemByType

func (sl *Slice) ElemByType(t reflect.Type, embeds bool, startIdx int) (Ki, bool)

ElemByType returns index of element that either is that type or embeds that type, false if not found. See IndexOf for info on startIdx.

func (*Slice) ElemByUniqueName

func (sl *Slice) ElemByUniqueName(name string, startIdx int) (Ki, bool)

ElemByUniqueName returns index of first element that has given unique name, false if not found. See IndexOf for info on startIdx.

func (*Slice) ElemFromEnd

func (sl *Slice) ElemFromEnd(idx int) (Ki, bool)

ElemFromEnd returns element at index from end of slice (0 = last element, 1 = 2nd to last, etc), returning false if invalid index

func (*Slice) IndexByFunc

func (sl *Slice) IndexByFunc(startIdx int, match func(k Ki) bool) (int, bool)

IndexByFunc finds index of item based on match function (which must return true for a find match, false for not). Returns false if not found. startIdx arg allows for optimized bidirectional find if you have an idea where it might be -- can be key speedup for large lists -- pass -1 to start in the middle (good default)

func (*Slice) IndexByName

func (sl *Slice) IndexByName(name string, startIdx int) (int, bool)

IndexByName returns index of first element that has given name, false if not found. See IndexOf for info on startIdx

func (*Slice) IndexByType

func (sl *Slice) IndexByType(t reflect.Type, embeds bool, startIdx int) (int, bool)

IndexByType returns index of element that either is that type or embeds that type, false if not found. See IndexOf for info on startIdx.

func (*Slice) IndexByUniqueName

func (sl *Slice) IndexByUniqueName(name string, startIdx int) (int, bool)

IndexByUniqueName returns index of first element that has given unique name, false if not found. See IndexOf for info on startIdx.

func (*Slice) IndexOf

func (sl *Slice) IndexOf(kid Ki, startIdx int) (int, bool)

IndexOf returns index of element in list, false if not there. startIdx arg allows for optimized bidirectional find if you have an idea where it might be -- can be key speedup for large lists -- pass -1 to start in the middle (good default).

func (*Slice) Insert

func (sl *Slice) Insert(k Ki, idx int)

Insert item at index -- does not do any parent updating etc -- use Ki/Node method unless you know what you are doing.

func (Slice) IsValidIndex

func (sl Slice) IsValidIndex(idx int) bool

IsValidIndex checks whether the given index is a valid index into slice, within range of 0..len-1.

func (*Slice) KnownElemByName

func (sl *Slice) KnownElemByName(name string, startIdx int) Ki

KnownElemByName returns first element that has given name, without returning the bool check value -- when named element is known to exist, and will be directly converted to another type, so the multiple return values are cumbersome. nil is returned if it actually does not exist. See IndexOf for info on startIdx.

func (Slice) MarshalJSON

func (sl Slice) MarshalJSON() ([]byte, error)

MarshalJSON saves the length and type, name information for each object in a slice, as a separate struct-like record at the start, followed by the structs for each element in the slice -- this allows the Unmarshal to first create all the elements and then load them

func (Slice) MarshalXML

func (sl Slice) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML saves the length and type information for each object in a slice, as a separate struct-like record at the start, followed by the structs for each element in the slice -- this allows the Unmarshal to first create all the elements and then load them

func (*Slice) Move

func (sl *Slice) Move(from, to int) bool

Move element from one position to another. Returns false if either index is invalid.

func (*Slice) NameToIndexMap

func (sl *Slice) NameToIndexMap() map[string]int

NameToINdexMap returns a Name to Index map for faster lookup when needing to do a lot of name lookups on same fixed slice.

func (*Slice) TypeAndNames

func (sl *Slice) TypeAndNames() kit.TypeAndNameList

TypeAndNames returns a kit.TypeAndNameList of elements in the slice -- useful for Ki ConfigChildren.

func (*Slice) TypeAndUniqueNames

func (sl *Slice) TypeAndUniqueNames() kit.TypeAndNameList

TypeAndUniqueNames returns a kit.TypeAndNameList of elements in the slice using UniqueNames -- useful for Ki ConfigChildren.

func (*Slice) UniqueNameToIndexMap

func (sl *Slice) UniqueNameToIndexMap() map[string]int

UniqueNameToIndexMap returns a UniqueName to Index map for faster lookup when needing to do a lot of name lookups on same fixed slice.

func (*Slice) UnmarshalJSON

func (sl *Slice) UnmarshalJSON(b []byte) error

UnmarshalJSON parses the length and type information for each object in the slice, creates the new slice with those elements, and then loads based on the remaining bytes which represent each element

func (*Slice) UnmarshalXML

func (sl *Slice) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalJSON parses the length and type information for each object in the slice, creates the new slice with those elements, and then loads based on the remaining bytes which represent each element

Directories

Path Synopsis
Package atomctr implements basic atomic int64 counter, used e.g., for update counter on Ki Node
Package atomctr implements basic atomic int64 counter, used e.g., for update counter on Ki Node
package bitflag provides simple bit flag setting, checking, and clearing methods that take bit position args as ints (from const int eunum iota's) and do the bit shifting from there -- although a tiny bit slower, the convenience of maintaining ordinal lists of bit positions greatly outweighs that cost -- see kit type registry for further enum management functions
package bitflag provides simple bit flag setting, checking, and clearing methods that take bit position args as ints (from const int eunum iota's) and do the bit shifting from there -- although a tiny bit slower, the convenience of maintaining ordinal lists of bit positions greatly outweighs that cost -- see kit type registry for further enum management functions
package floats provides a standard Floater interface and all the std math functions defined on Floater types.
package floats provides a standard Floater interface and all the std math functions defined on Floater types.
package ints provides a standard Inter interface and basic functions defined on Inter types that support core things like Max, Min, Abs.
package ints provides a standard Inter interface and basic functions defined on Inter types that support core things like Max, Min, Abs.
Package kit provides various reflect type functions for GoKi system, including: * kit.TypeRegistry (types.go) for associating string names with reflect.Type values, to allow dynamic marshaling of structs, and also bidirectional string conversion of const int iota (enum) types.
Package kit provides various reflect type functions for GoKi system, including: * kit.TypeRegistry (types.go) for associating string names with reflect.Type values, to allow dynamic marshaling of structs, and also bidirectional string conversion of const int iota (enum) types.
package nptime provides a non-pointer version of the time.Time struct that does not have the location pointer information that time.Time has, which is more efficient from a memory management perspective, in cases where you have a lot of time values being kept: https://segment.com/blog/allocation-efficiency-in-high-performance-go-services/
package nptime provides a non-pointer version of the time.Time struct that does not have the location pointer information that time.Time has, which is more efficient from a memory management perspective, in cases where you have a lot of time values being kept: https://segment.com/blog/allocation-efficiency-in-high-performance-go-services/

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL