IupTreeAddNodes

Definition: include pGUI.e

IupTreeAddNodes(Ihandle tree, sequence tree_nodes, integer id=-1)
Description: Populates a tree from a nested sequence of branches and leaves.

tree: The result of some previous invocation of IupTree().
tree_nodes: a nested collection of nodes (see examples below).
id: A unique userid for deferred loading of sub-trees (see below).

This routine does not return a value. It will rudely terminate in error should tree_nodes not conform to the required format, or if unique userids cannot be found, etc.
Notes: A tree is represented by a nested collection of nodes (see example below).
A node is a string (leaf node) or a sequence of length 2 or 3:
  • The first element is a string description.
  • If length is 3 the second is an even-length set of attribute name/value pairs.
  • The last element is a sequence of children, or 0 to indicate a leaf node.
Each element of children is either a string to represent a leaf node or a sequence of length 2 or 3 as above. Note that if the top-level node of a (/the entire) tree is a single string, it represents a single leaf node with no attributes, and no branches.

The rules to remember are:
if you have attributes on a leaf node, it must have a third element of 0, and:
if a branch has no children it must still have a {} to represent that.
Should you see leaf nodes such as "STATE" and "COLLAPSED", or similar attribute names/values, suspect a missing 0 or {}.

The following table lists the permitted nodes. Note that the entire tree is always represented by a single node, albeit an arbitrarily nested one.

Node Description
"string" a leaf node with no attributes.
{"string"} ditto.
{"string",0} ditto.
{"string",sequence evennvseq,0} a leaf node with attributes.
{"string",sequence children} a branch node with no attributes, each element of children is a node.
{"string",sequence evennvseq,sequence children} a branch node with attributes and a (potentially empty) list of children.

 
Every odd element in any even-length set of attributes should be an attribute that accepts an id, ie one from the Nodes or Images section of the Attributes table as shown in the documentation for IupTree. The even elements are strings, except for "USERDATA" which requires a positive integer, intended to be an index into some application-specific table. Note that setting custom attributes proved problematical and therefore attempts to do so now trigger a fatal error. If someone gets such things working, outside of IupTreeAddNodes, via IupTreeGetId and friends, then I’ll take another look.

In practice, a node can also be a sequence of length 1, which represents a leaf node in the same way that a plain string does. The fact that a leaf node with no attributes can be represented in three different ways is a simple consequence of making the recursive structure easier to use, rather than a deliberate design decision to complicate matters.

Performance note: For large trees it would normally be prudent to create all branches collapsed and empty, and populate them when the branch is expanded. If you have seen Windows Explorer take forever to load a single directory (such as the Recycle Bin), imagine what it would be like if it pre-loaded every directory on your entire system before displaying anything. Obvously you might also want to auto-expand the top-level node, and have that auto-populated, and perhaps repeat that down to some target.

To defer load, you must specify {"STATE","COLLAPSED","USERDATA",7} where 7 is some unique userid for the branch, and create a "dummy" entry (to get a '+' shown), and lastly invoke IupTreeAddNodes() inside branchopen_cb, specifying said unique userid, as per demo\pGUI\sample.exw and as reproduced below.
Example Snippets taken from demo\pGUI\sample.exw:
-- This shows how to defer-load nodes on expand/demand:
-- Obviuously would probably be more dynamically set in a real app,
-- and of course elements can be more than plain-string leaf nodes,
-- with daisy-chains of unique userids to control things properly.
-- (7 is plucked out of the air, matches the 7 in tree_nodes below)
-- (also feel free to use xxx[7]!=0 instead of find(7,toload)!=0..)

sequence {toload,tolkids} = columnize({{7,{"equilateral",
                                           "isoceles",
                                           "scalenus"}},
--                                     {8,{"some",      -- (works just fine, if)
--                                         "other",     -- (8 uncommented below)
--                                         "branch"}},
                                      })

function branchopen_cb(Ihandle tree, integer id)
    integer userid = IupTreeGetUserId(tree,id),
            k = find(userid,toload)
    if k!=0 then -- (deferred load rqd for this node)
        -- first kill off "dummy" (which ensured a '+'):
        IupSetAttributeId(tree,"DELNODE",id,"CHILDREN")
        sequence children = tolkids[k]
        IupTreeAddNodes(tree, children, userid)
        -- finally remove load from the to-do lists:
        toload[k..k] = {}
        tolkids[k..k] = {}
    end if
    return IUP_DEFAULT;
end function

        sequence tree_nodes = {"Figures",               -- (branch with 5 children)
--                             {"STATE","COLLAPSED"},   --  (works fine, btw)
                               {"Other",                -- (leaf)
--                              {"triangle",            -- (branch with 3 children)
--                               {"STATE","COLLAPSED"},
--                               {"equilateral",
--                                "isoceles",
--                                "scalenus",
--                               }},
                                {"triangle",            -- (branch with 3 children)
                                 {"STATE","COLLAPSED","USERDATA",7},
                                 {"dummy"}},            -- (ensures we get a '+')
                                {"parallelogram",       -- (branch with 2 children)
                                 {"square",
                                  {"diamond",
                                   {"COLOR","92 92 255","TITLEFONT","Courier, 8"},
                                   0}   -- (nb: this is a leaf, non-optional here)
                                 }},
                                "2D",                   -- (leaf)
--                              {"2D"},                 -- (same)
--                              {"2D",0},               -- (same)
--                              {"2D",{},0},            -- (same)
                                {"3D",{}},              -- (branch, empty)
--                              {"4D",                  -- (works just fine, if)
--                                                      -- (8 uncommented above)
--                               {"STATE","COLLAPSED","USERDATA",8},
--                               {"dummy"}}             -- (branch, deferred load)
                               }
                              }
        IupSetCallback(tree, "BRANCHOPEN_CB",  Icallback("branchopen_cb"));
        IupTreeAddNodes(tree, tree_nodes)

The output does differ slightly, in diamond and 2D (just run demo\pGUI\sample.exw if at all worried about that), but otherwise it should be fairly similar to (an image I already had):



Note that USERDATA is generally useful for other purposes, and would normally be allocated sequentially on that basis, hence the "plucked out of the air" aspect: if you need to defer-load three nodes, avoid thinking that you must use {1,2,3}.
See also IupTree