Tutorial 3: A treeview

Step 1: Including the OneSprite Widget libraries

Create a new movie and either attach the "OSW_behaviours", "OSW_Factories" and "OWS_Core" casts to your movie or import the contents to your movie.

Step 2: Create a placeholder bitmap

Create a simple blank bitmap cast member that is the size you want your treeview to be. Position this bitmap on stage at the location you want, then drag the "Proxy.TreeView" behaviour from the 'OWS_behaviours' cast on to the sprite.

Step 3. Configure the Widget

When you attached the behaviour, the GetPropertyDescriptionList dialog will appear. Leave all the settings at their default for now.

Step 4. Create a "TreeviewController" behaviour

Create a new behaviour and add this to the sprite with the treeview behaviour. Call this second behaviour "TreeviewController" or something. The add some lingo like this

on NodeTreeReady (me, sender, id)

  nodeTree = []
  nodeTree.add( [#Label: "Node 1"])
  nodeTree.add( [#Label: "Node 2"])
  nodeTree.add( [#Label: "Node 3"])

  sender.Display(nodeTree)
  sender.addListener(me)

end


on NodeTreeClick (me, sender, args)

  put args

end

When the 'TreeviewController' receives the 'NodeTreeReady' message, it constructs a simple list for the node tree to display and then tells the nodetree to display it. The result will look like this:

Sample Node Tree  - 1 Sample Node Tree - 1

The list that the node tree accepts is a linear list of 'nodes'. Nodes are property lists which describe that node. The simplest node can have a single property - #Label. This determines the text that will appear in the node tree.

Nodes can also have a #children property which is a list of nodes which appear as 'children' of the node. For example:

on NodeTreeReady (me, sender, id)

  nodeTree = []
  nodeTree.add( [#Label: "Node 1"])
  nodeTree.add( [#Label: "Node 2"])
  nodeTree.add( [#Label: "Node 3", #children: [[#Label: "Node 3-1"]]])

  sender.Display(nodeTree)
  sender.addListener(me)

end


on NodeTreeClick (me, sender, args)

  put args

end

The third node now has a child, and the result looks like this:

Sample Node Tree  - 1 Sample Node Tree - 1

The following is a slightly more complex example. This code creates a node tree list of all the casts and members of the current movie.

-- Behaviour 'CastBrowser'

property myNodeTreeRef


on NodeTreeReady (me, sender, id)

  nodeTree = []
  repeat with i = 1 to the number of castlibs
    children = []
    repeat with j =1 to the number of members of castlib i
      whatName = member(j,i).name
      if whatName = "" then whatName = "<no name>"
      aNode = [#Label: whatName]
      children.add(aNode)
    end repeat
    whatName = castlib(i).name
    if whatName = "" then whatName = "<no name>"
    aNode = [#Label: whatName, #Children: Children]
    nodeTree.add(aNode)
  end repeat

  myNodeTreeRef = sender
  myNodeTreeRef.Display(nodeTree)
  myNodeTreeRef.addListener(me)
end

on NodeTreeClick (me, sender, args)
  put "NODE SELECTED: " & args
end

You can also specify a #Icon property for a node. The value should either be the name of a bitmap, a cast member reference or an image object. You can also specify other properties for the node. These extra property/value pairs are returned as parameters when the node is selected.

In this next example, each cast member.type is checked, and a corresponding icon is assigned to the node. The member type is also stored with the node.

-- Behaviour 'CastBrowserWithIcons'
-- treeview of the cast members of the current movie
-- (with icons)

property myNodeTreeRef

on NodeTreeReady (me, sender, id)

  nodeTree = []
  repeat with i = 1 to the number of castlibs
    children = []
    repeat with j =1 to the number of members of castlib i
      aNode = [:]
      aNode[#Label] = member(j,i).name
      if  aNode[#Label] = "" then  aNode[#Label] = "<no name>"
      aNode[#EntryType] = "CastMember"
      if member(j,i).type = #script then
        aNode[#Icon] = string(member(j,i).Scripttype) & "script"
      else
        aNode[#Icon] = string(member(j,i).type)
      end if

      children.add(aNode)


    end repeat
    aNode = [:]
    aNode[#Label] = castlib(i).name
    aNode[#EntryType] = "CastLib"
    aNode[#children] = children
    nodeTree.add(aNode)
  end repeat

  myNodeTreeRef = sender
  myNodeTreeRef.Display(nodeTree)
  myNodeTreeRef.addListener(me)
end

on NodeTreeClick (me, sender, args)
  put "NODE SELECTED: " & args
end

The final example demonstrates how you can change the node tree using the SetNodeValue() and Setchildren() methods. This behaviour creates a 'file browser'. Whenever a directory is clicked and opened, it checks whether the node represents a directory or a file. If it was a directory, it builds a list of the directory's contents and updates the node tree. Whenever a file is clicked and opened, it changes the name of the file to 'opening' (this is just to illustrate how individual nodes in the tree can be updated)

-- Behaviour 'FileBrowser'
-- Uses BuddyAPI to build a 'tree' of files and folders

property myNodeTreeRef


on NodeTreeReady (me, sender, id)

  -- build a 'nodetree' list from the directory contents
  -- starting with the contents of 'the applicationPath'

  nodeTree = []

  -- first, list all the folders
  folders = baFolderList(the applicationPath)
  repeat with aFolder in folders
    nodeTree.add([#Label: aFolder, #EntryType: #Directory, #Children:[]])
  end repeat

  -- second, list all the files
  files = baFileList(the applicationPath, "*")
  repeat with aFile in files
    nodeTree.add([#Label: aFile, #EntryType: #File])
  end repeat

  myNodeTreeRef = sender
  myNodeTreeRef.Display(nodeTree)
  myNodeTreeRef.addListener(me)
end

on NodeTreeClick (me, sender, args)

  put args

  case( args.eventType) of

    #NodeOpened:
      -- a node has been opened

      sep = the last char of the applicationPath
      pathToNode = myNodeTreeRef.GetValueFromPath(args.path)
      pathToOpen = the applicationPath & Implode(sep, pathToNode)

      if args.EntryType = #Directory then
        -- list the contents of this directory
        subFolder = []
        folders = baFolderList(pathToOpen)
        repeat with aFolder in folders
          subFolder.add([#Label: aFolder, #EntryType: #Directory, #Children:[]])
        end repeat

        files = baFileList(pathToOpen, "*")
        repeat with aFile in files
          subFolder.add([#Label: aFile, #EntryType: #File])
        end repeat

        myNodeTreeRef.SetChildren(subFolder, args.path )

      else
        -- example of changing the label
        myNodeTreeRef.SetNodeValue("Opening...", args.path )
      end if

    #NodeClosed:
      sep = the last char of the applicationPath
      pathToNode = myNodeTreeRef.GetValueFromPath(args.path)
      pathToOpen = the applicationPath & Implode(sep, pathToNode)

      if args.EntryType = #Directory then
        -- remove the subfolder of this directory from current tree
        myNodeTreeRef.SetChildren([], args.path )

      else
        -- example of changing the label
        myNodeTreeRef.SetNodeValue("Closing...", args.path )
      end if


  end case

end
First published 09/06/2005