# 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. Note this is a pGUI-specific add-on, there is no equivalent C routine that I am aware of. 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.
pwa/p2js: | Supported.
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, can be {}. The last <= 3rd element is a sequence of children, or 0 to indicate a leaf node. Elements 4 and above can contain application-specific data, ignored by this routine. Each element of children is either a string to represent a leaf node or a sequence of length>=2 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. There cannot be any (ignored) application-specifc data on shorthand forms, ie 4 out of 6 entries in the table below. 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[,appdata]} | a leaf node with zero or more attributes. Note the 0 is not optional, even without appdata.
{"string",sequence children} | a branch node with no attributes, each element of children (if any) is a node.
{"string",sequence evennvseq,sequence children[,appdata]} | a branch node with (potentially empty) lists of attributes and 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 IupFlatTree. 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. Note this routine is (now) targetted squarely at IupTreeView, which is based on IupFlatTree on the desktop, and rewritten in pGUI.js for use in the browser, although it was originally written way back when only IupTree existed. In theory it should work on all four. 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 | IupSetCallback, Icallback, IupTree