ki

package
v0.0.0-...-5f41422 Latest Latest
Warning

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

Go to latest
Published: Jul 29, 2018 License: BSD-3-Clause Imports: 18 Imported by: 0

README

ki

Part of the GoKi Go language (golang) full strength tree structure system (ki = tree in Japanese)

package ki -- core Ki interface (ki.go) and Node struct (node.go), plus other supporting players.

THIS IS ARCHIVED -- active version at: https://github.com/goki

A Ki tree is recursively composed of Ki Node structs, in a one-Parent / multiple-Child structure. The typical use is to embed Node in other structs that then implement specific tree-based functionality. See other packages in GoKi for examples, and top-level README in GoKi for overall motivation and design.

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.

Go Language (golang) Notes (esp for people coming from C++)

general summary: https://github.com/golang/go/wiki/GoForCPPProgrammers

Naming Conventions

https://golang.org/doc/effective_go.html#names

  • Don't use Get* -- just use the name itself, when a "getter" is necessary

  • Do use Set* -- setter + field name -- this is convention in Qt too

  • Uppercase all Fields in general -- Strongly prefer to just deal with the fields directly without having to go through a getter method, and we want embedded objects and anyone else to be able to access those fields, and they also need to be saved / loaded through JSON, etc

  • Above means that there can be conflicts for any interfaces that need to provide access to those fields, if you also want to export the fields in the struct implementation. You have to be creative in coming up with different but equally sensible names in both the interface and the implementer.

  • Delete instead of Remove Iface for interface{}

  • Unless it is a one-liner converter to a given type or value like Stringer, it can be challenging to name an interface and a base type for that interface differently.

    • The Interface should generally be given priority, and have the cleaner name. Base types are only typed relatively rarely at start of structs that embed them, so they are less important.
    • One not-so-good idea: Add a capital I at the end of an interface when it is designed for derived types of a given base, e.g., EventI for structs that embed type Event -- I couldn't find anything about this in searching but somehow it doesn't seem like the "Go" way..
  • It IS ok to have types and fields / members of the same name! So EventType() EventType is perfectly valid and that's a relief :)

  • It is hard to remember, but important, that everything will be prefixed by the package name for users of the package, so don't put a redundant prefix on anything

  • Use AsType() for methods that give you that give you that concrete type from a struct (where it isn't a conversion, just selecting that view of it)

Enums (const int)
  • Use plural for enum type, instead of using a "Type" suffix -- e.g., NodeSignals instead of NodeSignalType, and in general use a consistent prefix for all enum values: NodeSignalAdded etc

  • my version of gp generate stringer utility generates conversions back from string to given type: https://github.com/rcoreilly/stringer

  • ki.EnumRegister (kit.AddEnum) -- see kit/types.go -- adds a lot of important functionality to enums

Struct structure

  • 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.

Interfaces, Embedded types

  • In C++ terms, an interface in go creates a virtual table -- anytime you need virtual functions, you must create an interface.

    • I was confused about the nature of inheritance in Go for a long time, in part because the Go folks like to emphasize the idea that there is no inheritance in Go, and in general like to emphasize the differences from C++. In fact, through anonymous embedding, you can inherit base-class definitions of interface methods, and selectively override (redefine) the ones you want to change for the sub-class, no problem! The only thing that is actually missing is an automatic conversion of a derived class to a base class, which is probably actually a good thing -- you always need to know what type of thing you have. But, the interface pointer actually does always know what type of thing it is, so if we keep a "This" interface pointer around on the struct, we can always call the proper derived versions of any interface methods. Basically, you can really get all the functionality of C++ in Go that you want, no problem, plus all the flexibility of a more polymorphic system!
    • An interface is the only way to create an equivalence class of types -- otherwise Go is strict about dealing with each struct in terms of the actual type it is, even if it embeds a common base type.
  • Anonymous embedding a type at the start of a struct gives transparent access to the embedded types (and so on for the embedded types of that type), so it looks like inheritance in C++, but critically those inherited methods are not virtual in any way, and you must explicitly convert a given "derived" type into its base type -- you cannot do something like: bt := derived.(*BaseType) to get the base type from a derived object -- it will just complain that derived is its actual type, not a base type. Although this seems like a really easy thing to fix in Go that would support derived types, it would require a (little bit expensive) dynamic (runtime) traversal of the reflect type info. Those methods are avail in package kit as TypeEmbeds to check if one type embeds another, and EmbededStruct to get an embedded struct out of a struct that embeds it (at any level of depth). In general it is much better to provide an explicit interface method to provide access to embedded structs that serve as base-types for a given level of functionality. Or provide access to everything you might need via the interface, but just giving the base struct is typically much easier.

  • Although the derived types have direct access to members and methods of embedded types, at any level of depth of embedding, the reflect system presents each embedded type as a single field as it is declared in the actual code. Thus, you have to recursively traverse these embedded structs -- methods to flatten these field lists out by calling a given function on each field in turn are provided in kit embed.go: FlatFieldsTypeFun and FlatFieldsValueFun

  • The Ki / Node framework may be seen as antithetical to the Go way of doing things, and it is at first glance more similar to C++ paradigms where a common base type is used to provide a comprehensive set of common functionality (e.g., the QObject in Qt). However, Go also makes extensive use of special base types with considerable special, powerful functionality, in the form of slices and maps. A Tree is likewise a kind of universal container object, and the only way to provide an appropriate general interface for it is by embedding a base type with the relevant functionality.

    • You still have all the critical Go interface mix-and-match power: Any number of polymorphic interfaces can be implemented on top of the basic Ki tree structure, and multiple different anonymous embedded types can be used, so there is still none of the C++ rigidity and awkwardness of dealing with multiple inheritance, etc.
    • The Ki interface itself is NOT designed to be implemented more than once -- there should be no reason to do so -- and all of the functionality that it does implement is fully interdependent and would not be sensibly separated into smaller interfaces. Every attempt was made to separate out dissociable elements such as the Ptr, Slice, and Signal, and all the separate more general-purpose type management functionality in kit
    • The Node object maintains its own Ki interface pointer in the This field -- another seeming C++ throwback, which has turned out to be absolutely essential to getting the whole enterprise to work. First, an interface type is automatically a pointer, so even though it is declared as a Ki type, it is automatically a pointer to the struct. Most importantly, this Ki pointer retains the true underlying identity of the struct, in whatever context it is being used -- by contrast, when you call any method with a specific receiver type, the struct becomes only that type, and loses all memory of its "true" underlying type. For example, if you try to call another interface-based function within a given receiver-defined function, you'll only get the interface function for that specific type, not the one for the "true" underlying type. Therefore, you need to call ob.This.Function() to get the one defined for the full type of the object. This is probably the functionality most people would expect, especially coming from the world of C++ virtual functions.

interface{} type: universal Variant

Go makes extensive use of the interface{} type which is effectively a built-in universal Variant type in Qt http://doc.qt.io/qt-5/qvariant.html -- you use type switches or conversions or the reflect system to figure out what kind of thing it actually is -- extremely powerful yet not very dangerous it seems.

Closures & anonymous functions

It is very convenient to use anonymous functions directly in the FuncDown (etc) and Signal Connect cases, but for performance reasons, it is important to be careful about capturing local variables from the parent function, thereby creating a closure, which creates a local stack to represent those variables. In the case of FunDown / FunUp etc, the impact is minimized because the function is ONLY used during the lifetime of the outer function. However, for Signal Connect, the function is itself saved and used later, so using a closure there creates extra memory overhead for each time the connection is created. Thus, it is generally better to avoid capturing local variables in such functions -- typically all the relevant info can be made available in the recv, send, sig, and data args for the connection function.

Notes on things that would perhaps be nice to change about Go..

As the docs state, you really have to use it for a while to appreciate all of the design decisions in the language, so these are very preliminary and subject to later reconsideration..

  • Reference arg type -- the receiver arg (the "this" pointer in C++) has automagical ability to either be a pointer or a value depending on the function declaration, but other args do NOT have this flexibility. It means that the caller has to do a little bit of extra work adding a & or not where necessary. The counter-argument is presumably that this means that the caller KNOWS that by passing a pointer, the value of the arg will be changed, and that is probably a good thing. The same point could be made for the receiver arg, but there I suppose the syntax would have been a bit clunky and confusing.

TODO

  • what about Kind == reflect.Interface fields in structs -- should they be set to zero? probably..
  • XML IO -- first pass done, but more should be in attr instead of full elements
  • FindChildRecursive functions?
  • port to better logging for buried errors, with debug mode: https://github.com/sirupsen/logrus

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.

  • Garbage collection is performed at optimized point at end of updates after tree objects have been destroyed (and all pointers reset), minimizing impact and need for unplanned GC interruptions.

Index

Constants

This section is empty.

Variables

View Source
var DelMgr = Deleted{}

DelMgr is the manager of all deleted items

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

set this to true to automatically print out a trace of the signals as they are sent

View Source
var SignalTraceString *string

set this to a string to receive trace in a string that can be compared for testing otherwise just goes to stdout

View Source
var UseJsonIter bool = false

use this to switch between using standard json vs. faster jsoniter right now jsoniter does not continue with the MarshalIndent beyond first level, even when called specifically in the Slice code

Functions

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

Types

type Connection

type Connection struct {
	// node that will receive the signal
	Recv Ki
	// function on the receiver node that will receive the signal
	Func RecvFunc
}

Connection represents one connection between a signal and a receiving Ki and function to call

func (*Connection) SendSig

func (con *Connection) SendSig(sender Ki, sig int64, data interface{})

SendSig sends the signal over this connection

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 (
	// this 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

	// Mask for node updates
	NodeUpdateFlagsMask = (1 << uint32(NodeAdded)) | (1 << uint32(NodeCopied)) | (1 << uint32(NodeMoved))

	// Mask for child updates
	ChildUpdateFlagsMask = (1 << uint32(ChildAdded)) | (1 << uint32(ChildMoved)) | (1 << uint32(ChildDeleted)) | (1 << uint32(ChildrenDeleted))

	// Mask for structural changes update flags
	StruUpdateFlagsMask = NodeUpdateFlagsMask | ChildUpdateFlagsMask | (1 << uint32(NodeDeleted))

	// Mask for non-structural, value-only changes update flags
	ValUpdateFlagsMask = (1 << uint32(FieldUpdated)) | (1 << uint32(PropUpdated))

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

func StringToFlags

func StringToFlags(s string) (Flags, error)

func (Flags) String

func (i Flags) String() string

type Func

type Func func(ki 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)

	// New creates a new object of this type -- MUST be defined for each
	// new type instance -- can also set any essential default values when
	// creating, but the Go style is to use 0 initial values wherever possible
	// -- do NOT call Init() on it as that will happen automatically later
	New() Ki

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

	// 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

	// ThisOk -- a simpler check for parent access routines where the parent
	// .This pointer may be validly not set yet -- returns false if .This is
	// nil
	ThisOk() bool

	// 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 EmbeddedStruct to
	// get the embedded struct of that type from this node
	TypeEmbeds(t reflect.Type) bool

	// EmbeddedStruct 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.EmbeddedStruct for a generic interface{} version
	EmbeddedStruct(t reflect.Type) Ki

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

	// HasParent returns true if this node has a parent at any level above it
	// that is the given node
	HasParent(par Ki) bool

	// Child returns the child at given index -- supports negative indexes to
	// access from end of slice (-1 = last child, etc) -- returns nil if no
	// children or index is invalid -- use IsValidIndex when unsure -- use
	// Children()[idx] for fast direct access when index is known to be valid
	Child(idx int) Ki

	// Children returns the slice of children (Node.Kids) -- this can be
	// modified directly (e.g., sort, reorder) but Add* / Delete* functions
	// should be used to ensure proper tracking
	Children() Slice

	// IsValidIndex checks whether the given index is a valid index into
	// children, within range of 0..len-1 -- see ki.Slice.ValidIndex for
	// version that transforms negative numbers into indicies from end of
	// slice, and has explicit error messages
	IsValidIndex(idx int) bool

	// 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()

	// Flag returns the bit flags for this node -- use bitflag package to
	// manipulate flags -- see Flags type for standard values used in Ki Node
	// -- can be extended from FlagsN up to 64 bit capacity
	Flags() *int64

	// SetFlagMu provides a mutex-locked bit flag update -- use this whenever
	// there might be concurrent access
	SetFlagMu(flag ...int)

	// SetFlagState provides a mutex-locked bit flag update -- use this
	// whenever there might be concurrent access
	SetFlagStateMu(on bool, flag ...int)

	// ClearFlag provides a mutex-locked bit flag update -- use this whenever
	// there might be concurrent access
	ClearFlagMu(flag ...int)

	// 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

	// IsUpdatingMu checks if node is currently updating, protected by flag mutex
	IsUpdatingMu() 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 -- if inherit, then checks all
	// parents too -- if typ then checks property on type as well (and on
	// embedded types if inherit is true) -- returns nil if not set
	Prop(key string, inherit, typ bool) interface{}

	// DeleteProp deletes property key, safely
	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 is ok -- always
	// grows automatically anyway)
	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

	// 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 -- 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

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

	// Index 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 -1 if we don't have a parent
	Index() int

	// 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

	// MoveChild moves child from one position to another in the list of
	// children (see also corresponding Slice method)
	MoveChild(from, to int) error

	// 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)

	// ChildIndexByFunc returns index of child based on match function (true
	// for match, false for not) -- startIdx arg allows for optimized
	// bidirectional search if you have an idea where it might be -- can be
	// key speedup for large lists
	ChildIndexByFunc(startIdx int, match func(ki Ki) bool) int

	// ChildIndex returns index of child -- startIdx arg allows for optimized
	// bidirectional search if you have an idea where it might be -- can be
	// key speedup for large lists
	ChildIndex(kid Ki, startIdx int) int

	// ChildIndexByName returns index of child from name -- startIdx arg
	// allows for optimized bidirectional search if you have an idea where it
	// might be -- can be key speedup for large lists
	ChildIndexByName(name string, startIdx int) int

	// ChildIndexByUniqueName returns index of child from unique name --
	// startIdx arg allows for optimized bidirectional search if you have an
	// idea where it might be -- can be key speedup for large lists
	ChildIndexByUniqueName(name string, startIdx int) int

	// ChildIndexByType returns index of child by type -- if embeds is true,
	// then it looks for any type that embeds the given type at any level of
	// anonymous embedding -- startIdx arg allows for optimized bidirectional
	// search if you have an idea where it might be -- can be key speedup for
	// large lists
	ChildIndexByType(t reflect.Type, embeds bool, startIdx int) int

	// ChildByName returns child from name -- startIdx arg allows for
	// optimized search if you have an idea where it might be -- can be key
	// speedup for large lists
	ChildByName(name string, startIdx int) Ki

	// ChildByType returns child from type (any of types given) -- returns nil
	// if not found -- if embeds is true, then it looks for any type that
	// embeds the given type at any level of anonymous embedding -- startIdx
	// arg allows for optimized bidirectional search if you have an idea where
	// it might be -- can be key speedup for large lists
	ChildByType(t reflect.Type, embeds bool, startIdx int) Ki

	// ParentByName returns parent by name -- returns nil if not found
	ParentByName(name string) Ki

	// ParentByType returns parent by type (any of types given) -- returns nil
	// 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

	// KiFieldByName returns field Ki element by name -- returns nil if not found
	KiFieldByName(name string) Ki

	// DeleteChildAtIndex deletes child at given 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)

	// DeletChild deletes child node -- 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
	DeleteChild(child Ki, destroy bool)

	// DeleteChildByName deletes child node by name -- returns child -- 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
	DeleteChildByName(name string, destroy bool) Ki

	// 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()

	// 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 chlidren -- 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)

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

	// 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()) -- returns nil if not found
	FindPathUnique(path string) Ki

	// 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)
	//
	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 -- no other Ki point.  Signal connections are
	// NOT copied (todo: revisit).  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()

	// SaveJSON saves the tree to a JSON-encoded byte string -- wraps
	// MarshalJSON
	SaveJSON(indent bool) ([]byte, error)

	// SaveJSONToFile saves the tree to a JSON-encoded file
	SaveJSONToFile(filename string) error

	// LoadJSON loads the tree from a JSON-encoded byte string -- wraps
	// UnmarshalJSON and calls UnmarshalPost to recover pointers from paths
	LoadJSON(b []byte) error

	// SaveJSONFromFile loads the tree from a JSON-encoded file
	LoadJSONFromFile(filename string) error

	// SaveXML saves the tree to an XML-encoded byte string
	SaveXML(indent bool) ([]byte, error)

	// LoadXML loads the tree from an XML-encoded byte string, calls
	// UnmarshalPost to recover pointers from paths
	LoadXML(b []byte) error

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

	// UnmarshallPost 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

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     `` /* 228-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 */
	This     Ki         `` /* 259-byte string literal not displayed */
	FlagMu   sync.Mutex `copy:"-" json:"-" xml:"-" view:"-" desc:"mutex protecting flag updates"`
	// 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 GoGr 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

func (*Node) ChildByName

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

func (*Node) ChildByType

func (n *Node) ChildByType(t reflect.Type, embeds bool, startIdx int) Ki

func (*Node) ChildIndex

func (n *Node) ChildIndex(kid Ki, startIdx int) int

func (*Node) ChildIndexByFunc

func (n *Node) ChildIndexByFunc(startIdx int, match func(ki Ki) bool) int

func (*Node) ChildIndexByName

func (n *Node) ChildIndexByName(name string, startIdx int) int

func (*Node) ChildIndexByType

func (n *Node) ChildIndexByType(t reflect.Type, embeds bool, startIdx int) int

func (*Node) ChildIndexByUniqueName

func (n *Node) ChildIndexByUniqueName(name string, startIdx int) int

func (*Node) Children

func (n *Node) Children() Slice

func (*Node) ClearFlagMu

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

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)

func (*Node) DeleteChildAtIndex

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

func (*Node) DeleteChildByName

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

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) EmbeddedStruct

func (n *Node) EmbeddedStruct(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

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) GoFuncDownWait

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

func (*Node) GoFuncFields

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

func (*Node) HasChildren

func (n *Node) HasChildren() bool

func (*Node) HasParent

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

func (*Node) Index

func (n *Node) Index() int

func (*Node) Init

func (n *Node) Init(this Ki)

func (*Node) InitName

func (n *Node) InitName(ki 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) IsUpdatingMu

func (n *Node) IsUpdatingMu() bool

func (*Node) IsValidIndex

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

func (*Node) KiFieldByName

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

func (*Node) LoadJSON

func (n *Node) LoadJSON(b []byte) error

func (*Node) LoadJSONFromFile

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

func (*Node) LoadXML

func (n *Node) LoadXML(b []byte) error

func (*Node) MoveChild

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

func (*Node) Name

func (n *Node) Name() string

func (*Node) New

func (n *Node) New() Ki

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) Parent

func (n *Node) Parent() Ki

func (*Node) ParentAllChildren

func (n *Node) ParentAllChildren()

func (*Node) ParentByName

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

func (*Node) ParentByType

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

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, inherit, typ bool) interface{}

func (*Node) Properties

func (n *Node) Properties() Props

func (*Node) Root

func (n *Node) Root() Ki

func (*Node) SaveJSON

func (n *Node) SaveJSON(indent bool) ([]byte, error)

func (*Node) SaveJSONToFile

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

func (*Node) SaveXML

func (n *Node) SaveXML(indent bool) ([]byte, 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) SetFlagMu

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

func (*Node) SetFlagStateMu

func (n *Node) SetFlagStateMu(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)

set parent of node -- does not remove from existing parent -- use Add / Insert / Delete

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

fmt.stringer interface -- basic indented tree representation

func (*Node) ThisCheck

func (n *Node) ThisCheck() error

func (*Node) ThisOk

func (n *Node) ThisOk() bool

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()

make sure that the names are unique -- n^2 ish

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

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 StringToNodeSignals

func StringToNodeSignals(s string) (NodeSignals, error)

func (NodeSignals) String

func (i NodeSignals) String() string

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

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

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 []Connection
}

Signal structure -- add one of these to your struct for each signal a node can emit

func (*Signal) Connect

func (sig *Signal) Connect(recv Ki, fun RecvFunc) error

Connect attaches a new receiver to the signal -- checks to make sure connection does not already exist -- error if not ok

func (*Signal) ConnectOnly

func (sig *Signal) ConnectOnly(recv Ki, fun RecvFunc) error

ConnectOnly first deletes any existing connections and then attaches a new receiver to the signal -- checks to make sure connection does not already exist -- error if not ok

func (*Signal) Disconnect

func (sig *Signal) Disconnect(recv Ki, fun RecvFunc) bool

Disconnect all connections for receiver and/or function if they exist in our list -- can pass nil for either (or both) to match only on one or the other -- both nil means disconnect from all, but more efficient to use DisconnectAll

func (*Signal) DisconnectAll

func (sig *Signal) DisconnectAll()

Disconnect 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 -- sequential

func (*Signal) EmitFiltered

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

EmitFiltered calls function on each item only sends signal if function returns true

func (*Signal) EmitGo

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

EmitGo concurrent version -- sends the signal across all the connections to the receivers

func (*Signal) EmitGoFiltered

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

EmitGoFiltered calls function on each item only sends signal if function returns true -- concurrent version

func (*Signal) EmitTrace

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

EmitTrace records a trace of signal being emitted

func (*Signal) FindConnectionIndex

func (sig *Signal) FindConnectionIndex(recv Ki, fun RecvFunc) int

Find any existing signal connection for given recv and fun

type SignalFilterFunc

type SignalFilterFunc func(ki Ki, idx int, con *Connection) 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 provides JSON marshal / unmarshal with encoding of underlying types

func (*Slice) Config

func (k *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 (k *Slice) DeleteAtIndex(idx int) error

DeleteAtIndex deletes item at index -- does not do any further management deleted item -- optimized version for avoiding memory leaks

func (*Slice) Elem

func (k *Slice) Elem(idx int) Ki

Elem returns element at index, using ValidIndex supporting negative indexing from back of list -- returns nil if index is invalid -- use ValidIndex or IsValidIndex directly to test if unsure

func (*Slice) Index

func (k *Slice) Index(kid Ki, startIdx int) int

Index returns index of element in list or -1 if not there

func (*Slice) IndexByFunc

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

IndexByFunc finds index of item based on match function (true for find, false for not) -- startIdx arg allows for optimized bidirectional find if you have an idea where it might be -- can be key speedup for large lists

func (*Slice) IndexByName

func (k *Slice) IndexByName(name string, startIdx int) int

IndexByName returns index of first element that has given name -- startIdx arg allows for optimized bidirectional search if you have an idea where it might be -- can be key speedup for large lists

func (*Slice) IndexByType

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

IndexByType returns index of element that either is that type or embeds that type -- startIdx arg allows for optimized bidirectional search if you have an idea where it might be -- can be key speedup for large lists

func (*Slice) IndexByUniqueName

func (k *Slice) IndexByUniqueName(name string, startIdx int) int

IndexByUniqueName returns index of first element that has given unique name -- startIdx arg allows for optimized bidirectional search if you have an idea where it might be -- can be key speedup for large lists

func (*Slice) Insert

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

Insert item at index

func (Slice) IsValidIndex

func (k Slice) IsValidIndex(idx int) bool

IsValidIndex checks whether the given index is a valid index into slice, within range of 0..len-1 -- see ValidIndex for version that transforms negative numbers into indicies from end of slice, and has explicit error messages

func (Slice) MarshalJSON

func (k 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 (k 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 (k *Slice) Move(from, to int) error

Move element from one position to another

func (*Slice) NameToIndexMap

func (k *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 (k *Slice) TypeAndNames() kit.TypeAndNameList

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

func (*Slice) TypeAndUniqueNames

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

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

func (*Slice) UniqueNameToIndexMap

func (k *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 (k *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 (k *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

func (Slice) ValidIndex

func (k Slice) ValidIndex(idx int) (int, error)

ValidIndex returns a valid index given length of slice -- also supports access from the back of the slice using negative numbers -- -1 = last item, -2 = second to last, etc

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 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.

Jump to

Keyboard shortcuts

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