Skip to content

Commit

Permalink
Fixed the logic for triggering a TreeView's "changed" callback, allow…
Browse files Browse the repository at this point in the history
…ing it to be triggered for calls to SetCurrentNode(), too.
  • Loading branch information
rivo committed Mar 25, 2023
1 parent becbc92 commit 87723e5
Showing 1 changed file with 25 additions and 23 deletions.
48 changes: 25 additions & 23 deletions treeview.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ type TreeView struct {
// The currently selected node or nil if no node is selected.
currentNode *TreeNode

// The last note that was selected or nil of there is no such node.
lastNode *TreeNode

// The movement to be performed during the call to Draw(), one of the
// constants defined above.
movement int
Expand Down Expand Up @@ -346,8 +349,8 @@ func (t *TreeView) GetRoot() *TreeNode {
// selection will be changed to the top-most selectable and visible node.
//
// This function does NOT trigger the "changed" callback because the actual node
// that will be selected is not known until the tree is drawn. That is also when
// the "changed" callback will be triggered.
// that will be selected is not known until the tree is drawn. Triggering the
// "changed" callback is thus deferred until the next call to [TreeView.Draw].
func (t *TreeView) SetCurrentNode(node *TreeNode) *TreeView {
t.currentNode = node
return t
Expand Down Expand Up @@ -404,8 +407,8 @@ func (t *TreeView) SetGraphicsColor(color tcell.Color) *TreeView {
return t
}

// SetChangedFunc sets the function which is called when the user navigates to
// a new tree node.
// SetChangedFunc sets the function which is called when the currently selected
// node changes, for example when the user navigates to a new tree node.
func (t *TreeView) SetChangedFunc(handler func(node *TreeNode)) *TreeView {
t.changed = handler
return t
Expand Down Expand Up @@ -458,9 +461,9 @@ func (t *TreeView) Move(offset int) *TreeView {
}

// process builds the visible tree, populates the "nodes" slice, and processes
// pending movement actions. Set "drawingAfter" to true if you know that [Draw]
// will be called immediately after this function (to avoid having [Draw] call
// it again).
// pending movement actions. Set "drawingAfter" to true if you know that
// [TreeView.Draw] will be called immediately after this function (to avoid
// having [TreeView.Draw] call it again).
func (t *TreeView) process(drawingAfter bool) {
t.stableNodes = drawingAfter
_, _, _, height := t.GetInnerRect()
Expand Down Expand Up @@ -544,53 +547,46 @@ func (t *TreeView) process(drawingAfter bool) {
// Process selection. (Also trigger events if necessary.)
if selectedIndex >= 0 {
// Move the selection.
newSelectedIndex := selectedIndex
switch t.movement {
case treeMove:
for t.step < 0 { // Going up.
index := newSelectedIndex
index := selectedIndex
for index > 0 {
index--
if t.nodes[index].selectable {
newSelectedIndex = index
selectedIndex = index
break
}
}
t.step++
}
for t.step > 0 { // Going down.
index := newSelectedIndex
index := selectedIndex
for index < len(t.nodes)-1 {
index++
if t.nodes[index].selectable {
newSelectedIndex = index
selectedIndex = index
break
}
}
t.step--
}
case treeParent:
if parentSelectedIndex >= 0 {
newSelectedIndex = parentSelectedIndex
selectedIndex = parentSelectedIndex
}
case treeChild:
index := newSelectedIndex
index := selectedIndex
for index < len(t.nodes)-1 {
index++
if t.nodes[index].selectable && t.nodes[index].parent == t.nodes[selectedIndex] {
newSelectedIndex = index
selectedIndex = index
}
}
}
t.step = 0
t.currentNode = t.nodes[newSelectedIndex]
if newSelectedIndex != selectedIndex {
t.movement = treeNone
if t.changed != nil {
t.changed(t.currentNode)
}
}
selectedIndex = newSelectedIndex
t.currentNode = t.nodes[selectedIndex]
t.movement = treeNone

// Move selection into viewport.
if t.movement != treeScroll {
Expand All @@ -616,6 +612,12 @@ func (t *TreeView) process(drawingAfter bool) {
t.currentNode = nil
}
}

// Trigger "changed" callback.
if t.changed != nil && t.currentNode != nil && t.currentNode != t.lastNode {
t.changed(t.currentNode)
}
t.lastNode = t.currentNode
}

// Draw draws this primitive onto the screen.
Expand Down

0 comments on commit 87723e5

Please sign in to comment.