Treeview with reactive checkboxes
Posted: Thu Aug 20, 2015 6:51 pm
This is a multi-OS demo for a treeview with reactive checkboxes (basically a manual version of Windows "auto-3state" flag, which Mac and Linux dont have). So by reactive I mean "typical expected treeview-with-checkboxes behavior", where when you click a Rootnode all of its Subnodes will be Checked/Unchecked (and just its Subnodes - not Subnodes of other Rootnodes), or if you click a Subnode then its parent Rootnode will be set to Checked/Unchecked/Inbetween depending on the overall status of all its Subnodes.
This is working well in Windows and Linux, but isn't quite right in Mac
... the main reason for that is that although the PB docs state that the user can only set to Checked/Unchecked (and only programatically set Inbetween), THIS IS NOT THE CASE ON MAC, WHERE THE USER CAN SET ALL THREE STATES! Im not quite sure how to address this issue - if a solution can't be found perhaps we might have to not use the #PB_TREE_THREESTATE flag and just have it as two-state for Mac, although you can't use the root node to indicate partially-checked then with the Inbetween style.
This is working well in Windows and Linux, but isn't quite right in Mac

Code: Select all
#Dlg1 = 0
#Tree1 = 1
Procedure FillTreeWithDemoItems()
lTreeItem.l = 0
For lRootNode = 1 To 3
AddGadgetItem (#Tree1, -1, "Root " + Str(lRootNode) + " <TreeItem index "+Str(lTreeItem)+">", 0, 0)
lTreeItem + 1
For lSubNode = 1 To 4
AddGadgetItem (#Tree1, -1, "Subnode " + Str(lSubNode) + " of Root " + Str(lRootNode) + " <TreeItem index "+Str(lTreeItem)+">", 0, 1)
SetGadgetItemData(#Tree1, lTreeItem, lTreeItem - lSubNode) ;ItemData = the RootNode id of this SubNode <- IMPORTANT! (youll probably get rid of this Procedure, but ensure you still use SetGadgetItemData to set the RootNode id of each Subnode you add)
lTreeItem + 1
Next
SetGadgetItemState(#Tree1,lTreeItem - lSubNode,#PB_Tree_Expanded) ;expand the node now we've finished adding to it
Next lRootNode
EndProcedure
Procedure SetTreeSubnodes(Tree, TreeRootNode, NewState, lastitem.l=0) ;Set all subnodes of root node TreeRootNode to NewState
If lastitem.l=0: lastitem = CountGadgetItems(Tree) - 1: EndIf
If lastitem <= TreeRootNode+1: ProcedureReturn: EndIf
For nexttreeitem = TreeRootNode+1 To lastitem
level = GetGadgetItemAttribute(Tree, nexttreeitem, #PB_Tree_SubLevel)
If level = 0: Break: EndIf
SetGadgetItemState(Tree, nexttreeitem, NewState)
Next nexttreeitem
EndProcedure
Procedure SetRootNode(Tree, TreeSubnode, lastitem.l=0) ;Scans all subnodes of a root node and then sets the root node state to Checked/Inbetween/Unchecked depending on overall status of subnode states
If lastitem.l=0: lastitem = CountGadgetItems(Tree) - 1: EndIf
If lastitem <= TreeSubnode+1: ProcedureReturn: EndIf
nuncheck = 0: nchecked = 0
RootNode = GetGadgetItemData(Tree, TreeSubnode)
For nexttreeitem = RootNode+1 To lastitem
level = GetGadgetItemAttribute(Tree, nexttreeitem, #PB_Tree_SubLevel)
If level = 0: Break: EndIf
If GetGadgetItemState(Tree, nexttreeitem) & #PB_Tree_Checked ;& not =, as its part of a mask
nchecked + 1
Else
nuncheck + 1
EndIf
Next nexttreeitem
If nchecked > 0 And nuncheck = 0
SetGadgetItemState(Tree, RootNode, #PB_Tree_Checked)
ElseIf nchecked > 0 And nuncheck > 0
SetGadgetItemState(Tree, RootNode, #PB_Tree_Inbetween)
Else
SetGadgetItemState(Tree, RootNode, 0) ;Unchecked
EndIf
EndProcedure
Procedure TreeItemClicked(TreeItem)
level = GetGadgetItemAttribute(#Tree1, TreeItem, #PB_Tree_SubLevel)
lastitem = CountGadgetItems(#Tree1) - 1
If level = 0 ;RootNode clicked
SetTreeSubnodes(#Tree1, TreeItem, GetGadgetItemState(#Tree1, TreeItem))
Else ;SubNode clicked
SetRootNode(#Tree1, TreeItem)
EndIf
EndProcedure
Procedure Tree1Proc(EventType)
If eventType = #PB_EventType_Change ;_Change and _LeftClick both seem to work, but _LeftClick sometimes 'skips' when we click too fast, whereas Change doesnt have that problem
TreeItemClicked ( GetGadgetState(#Tree1) )
EndIf
EndProcedure
Procedure Dlg1_Events(event)
Select event
Case #PB_Event_CloseWindow
ProcedureReturn #False
Case #PB_Event_Gadget
Select EventGadget()
Case #Tree1
Tree1Proc(EventType())
EndSelect
EndSelect
ProcedureReturn #True
EndProcedure
OpenWindow(#Dlg1, x, y, 570, 320, "Treeview Checked Nodes Demo", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_WindowCentered)
TreeGadget(#Tree1, 0, 0, 570, 320, #PB_Tree_CheckBoxes | #PB_Tree_ThreeState)
FillTreeWithDemoItems()
Repeat
Event = WaitWindowEvent()
EventWindow = EventWindow()
Select Event
Case #PB_Event_CloseWindow
CloseWindow(EventWindow)
If EventWindow= #Dlg1: End: EndIf
EndSelect
Select EventWindow
Case #Dlg1
Dlg1_Events(Event)
EndSelect
ForEver