package cview

import (
	
	
	
	

	
)

// Tree navigation events.
const (
	treeNone int = iota
	treeHome
	treeEnd
	treeUp
	treeDown
	treePageUp
	treePageDown
	treeScrollUp   // Move without changing the selection, even when off screen.
	treeScrollDown // Move without changing the selection, even when off screen.
)

// TreeNode represents one node in a tree view.
type TreeNode struct {
	// The reference object.
	reference interface{}

	// This node's child nodes.
	children []*TreeNode

	// The item's text.
	text string

	bold      bool
	underline bool

	// The text color.
	color tcell.Color

	highlighted bool

	// Whether or not this node can be focused and selected.
	selectable bool

	// Whether or not this node's children should be displayed.
	expanded bool

	// The additional horizontal indent of this node's text.
	indent int

	// An optional function which is called when the user focuses this node.
	focused func()

	// An optional function which is called when the user selects this node.
	selected func()

	// Temporary member variables.
	parent    *TreeNode // The parent node (nil for the root).
	level     int       // The hierarchy level (0 for the root, 1 for its children, and so on).
	graphicsX int       // The x-coordinate of the left-most graphics rune.
	textX     int       // The x-coordinate of the first rune of the text.

	sync.RWMutex
}

// NewTreeNode returns a new tree node.
func ( string) *TreeNode {
	return &TreeNode{
		text:  ,
		color: Styles.PrimaryTextColor,
		// TODO config
		indent:     2,
		expanded:   true,
		selectable: true,
	}
}

// Walk traverses this node's subtree in depth-first, pre-order (NLR) order and
// calls the provided callback function on each traversed node (which includes
// this node) with the traversed node and its parent node (nil for this node).
// The callback returns whether traversal should continue with the traversed
// node's child nodes (true) or not recurse any deeper (false).
func ( *TreeNode) ( func(,  *TreeNode,  int) bool) {
	// n.RLock()
	// defer n.RUnlock()

	.walk()
}

func ( *TreeNode) () *TreeNode {
	.RLock()
	defer .RUnlock()

	return .parent
}

// TODO rewrite
func ( *TreeNode) ( func(
	,  *TreeNode,  int) bool) {

	type  struct {
		     *TreeNode
		    int
		 int
		   *TreeNode
	}
	.RLock()
	 := []*{{: , : .level, : .parent}}
	.RUnlock()

	// Process nodes and collect them
	var  []*

	for len() > 0 {
		// Pop the top node and process it
		 := [len()-1]
		 = [:len()-1]

		 = append(, )

		..RLock()

		// Add children in reverse order
		 := ..children

		for  := len() - 1;  >= 0; -- {
			 := []
			 = append(, &{
				:     ,
				:    . + 1,
				: len(.children),
				:   .,
			})
		}
		..RUnlock()
	}

	 = 

	for  := 0;  < len(); ++ {
		 := []
		if !(., ., .) {
			if . == 0 {
				continue
			}

			 := false
			// scroll to the next node with same level
			for  :=  + .;  < len(); ++ {
				if []. <= . {
					 =  - 1
					 = true
					break
				}
			}

			// tail
			if ! {
				 = len() - 1
			}
		}
	}
}

// SetReference allows you to store a reference of any type in this node. This
// will allow you to establish a mapping between the TreeView hierarchy and your
// internal tree structure.
func ( *TreeNode) ( interface{}) {
	.Lock()
	defer .Unlock()

	.reference = 
}

// GetReference returns this node's reference object.
func ( *TreeNode) () interface{} {
	.RLock()
	defer .RUnlock()

	return .reference
}

// SetChildren sets this node's child nodes.
func ( *TreeNode) ( []*TreeNode) {
	.Lock()
	defer .Unlock()

	.children = 
}

// TODO support #FFFFFF
var styleRegex = regexp.MustCompile(`\[([a-zA-Z:-]*)\]`)

// VisibleLength returns the visible length of the node's text, without style tags.
func ( *TreeNode) () int {
	 := .GetText()
	 := styleRegex.ReplaceAllString(, "")
	return len()
}

// GetText returns this node's text.
func ( *TreeNode) () string {
	.RLock()
	defer .RUnlock()

	return .text
}

// GetChildren returns this node's children.
func ( *TreeNode) () []*TreeNode {
	.RLock()
	defer .RUnlock()

	return .children
}

// ClearChildren removes all child nodes from this node.
func ( *TreeNode) () {
	.Lock()
	defer .Unlock()

	.children = nil
}

// AddChild adds a new child node to this node.
func ( *TreeNode) ( *TreeNode) {
	.Lock()
	defer .Unlock()

	.children = append(.children, )
	for ,  := range .children {
		.parent = 
	}
}

// SetSelectable sets a flag indicating whether this node can be focused and
// selected by the user.
func ( *TreeNode) ( bool) {
	.Lock()
	defer .Unlock()

	.selectable = 
}

// RemoveChild removes a child node from this node. If the child node cannot be
// found, nothing happens.
func ( *TreeNode) ( *TreeNode) bool {
	for ,  := range .children {
		if  ==  {
			.children = append(.children[:], .children[+1:]...)
			return true
		}
	}
	return false
}

// SetFocusedFunc sets the function which is called when the user navigates to
// this node.
//
// This function is also called when the user selects this node.
func ( *TreeNode) ( func()) {
	.Lock()
	defer .Unlock()

	.focused = 
}

// SetSelectedFunc sets a function which is called when the user selects this
// node by hitting Enter when it is focused.
func ( *TreeNode) ( func()) {
	.Lock()
	defer .Unlock()

	.selected = 
}

// SetExpanded sets whether or not this node's child nodes should be displayed.
func ( *TreeNode) ( bool) {
	.Lock()
	defer .Unlock()

	.expanded = 
}

// Expand makes the child nodes of this node appear.
func ( *TreeNode) () {
	.Lock()
	defer .Unlock()

	.expanded = true
}

// Collapse makes the child nodes of this node disappear.
func ( *TreeNode) () {
	.Lock()
	defer .Unlock()

	.expanded = false
}

// ExpandAll expands this node and all descendent nodes.
func ( *TreeNode) () {
	.Walk(func(,  *TreeNode,  int) bool {
		.Lock()
		defer .Unlock()

		.expanded = true
		return true
	})
}

// CollapseAll collapses this node and all descendent nodes.
func ( *TreeNode) () {
	.Walk(func(,  *TreeNode,  int) bool {
		.Lock()
		defer .Unlock()

		.expanded = false
		return true
	})
}

// IsExpanded returns whether the child nodes of this node are visible.
func ( *TreeNode) () bool {
	.RLock()
	defer .RUnlock()

	return .expanded
}

// SetText sets the node's text which is displayed.
func ( *TreeNode) ( string) {
	.Lock()
	defer .Unlock()

	.text = 
}

func ( *TreeNode) ( bool) {
	.Lock()
	defer .Unlock()

	.bold = 
}

func ( *TreeNode) ( bool) {
	.Lock()
	defer .Unlock()

	.underline = 
}

// GetColor returns the node's color.
func ( *TreeNode) () tcell.Color {
	.RLock()
	defer .RUnlock()

	return .color
}

// SetColor sets the node's text color.
func ( *TreeNode) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.color = 
}

func ( *TreeNode) () bool {
	.RLock()
	defer .RUnlock()

	return .highlighted
}

func ( *TreeNode) ( bool) {
	.Lock()
	defer .Unlock()

	.highlighted = 
}

// SetIndent sets an additional indentation for this node's text. A value of 0
// keeps the text as far left as possible with a minimum of line graphics. Any
// value greater than that moves the text to the right.
func ( *TreeNode) ( int) {
	.Lock()
	defer .Unlock()

	.indent = 
}

func ( *TreeNode) () int {
	.Lock()
	defer .Unlock()

	return .indent
}

// TreeView displays tree structures. A tree consists of nodes (TreeNode
// objects) where each node has zero or more child nodes and exactly one parent
// node (except for the root node which has no parent node).
//
// The SetRoot() function is used to specify the root of the tree. Other nodes
// are added locally to the root node or any of its descendents. See the
// TreeNode documentation for details on node attributes. (You can use
// SetReference() to store a reference to nodes of your own tree structure.)
//
// Nodes can be focused by calling SetCurrentNode(). The user can navigate the
// selection or the tree by using the following keys:
//
//   - j, down arrow, right arrow: Move (the selection) down by one node.
//   - k, up arrow, left arrow: Move (the selection) up by one node.
//   - g, home: Move (the selection) to the top.
//   - G, end: Move (the selection) to the bottom.
//   - Ctrl-F, page down: Move (the selection) down by one page.
//   - Ctrl-B, page up: Move (the selection) up by one page.
//
// Selected nodes can trigger the "selected" callback when the user hits Enter.
//
// The root node corresponds to level 0, its children correspond to level 1,
// their children to level 2, and so on. Per default, the first level that is
// displayed is 0, i.e. the root node. You can call SetTopLevel() to hide
// levels.
//
// If graphics are turned on (see SetGraphics()), lines indicate the tree's
// hierarchy. Alternative (or additionally), you can set different prefixes
// using SetPrefixes() for different levels, for example to display hierarchical
// bullet point lists.
type TreeView struct {
	*Box

	// The root node.
	root *TreeNode

	// The currently focused node or nil if no node is focused.
	currentNode *TreeNode

	// The movement to be performed during the call to Draw(), one of the
	// constants defined above.
	movement int

	// The number of nodes to move down or up, when movement is treeMove,
	// excluding non-selectable nodes for selection movement, including them for
	// scrolling.
	step int

	// The top hierarchical level shown. (0 corresponds to the root level.)
	topLevel int

	// Strings drawn before the nodes, based on their level.
	prefixes [][]byte

	// Vertical scroll offset.
	offsetY int

	// If set to true, all node texts will be aligned horizontally.
	align bool

	// If set to true, the tree structure is drawn using lines.
	graphics bool

	highlightColor *tcell.Color

	// The text color for selected items.
	selectedTextColor *tcell.Color

	// The background color for selected items.
	selectedBackgroundColor *tcell.Color

	// The color of the lines.
	graphicsColor tcell.Color

	// Visibility of the scroll bar.
	scrollBarVisibility ScrollBarVisibility

	// The scroll bar color.
	scrollBarColor tcell.Color

	// An optional function called when the focused tree item changes.
	changed func(node *TreeNode)

	// An optional function called when a tree item is selected.
	selected func(node *TreeNode)

	// An optional function called when the user moves away from this primitive.
	done func(key tcell.Key)

	// The visible nodes, top-down, as set by process().
	nodes []*TreeNode

	// Temporarily set to true while we know that the tree has not changed and
	// therefore does not need to be reprocessed.
	// TODO
	stableNodes bool

	sync.RWMutex
}

// NewTreeView returns a new tree view.
func () *TreeView {
	return &TreeView{
		Box:                 NewBox(),
		scrollBarVisibility: ScrollBarAuto,
		graphics:            true,
		graphicsColor:       Styles.GraphicsColor,
		scrollBarColor:      Styles.ScrollBarColor,
	}
}

// SetRoot sets the root node of the tree.
func ( *TreeView) ( *TreeNode) {
	.Lock()
	defer .Unlock()

	.root = 
}

// GetRoot returns the root node of the tree. If no such node was previously
// set, nil is returned.
func ( *TreeView) () *TreeNode {
	.RLock()
	defer .RUnlock()

	return .root
}

// SetCurrentNode focuses a node and scrolls into viewport or, when provided with nil,
// clears focus.
//
// This function does NOT trigger the "changed" callback.
func ( *TreeView) ( *TreeNode) {
	.Lock()
	defer .Unlock()

	.currentNode = 
	if .currentNode.focused != nil {
		.Unlock()
		.currentNode.focused()
		.Lock()
	}

	.scrollCurrentIntoView(true)
}

// ScrollCurrentIntoView scroll the current node into view. [soft] keeps the selection in the middle.
func ( *TreeView) ( bool) {
	.Lock()
	defer .Unlock()

	.scrollCurrentIntoView()
}

func ( *TreeView) ( bool) {
	// scroll into view
	 := slices.Index(.nodes, .currentNode)
	, , ,  := .GetInnerRect()
	// correct
	 = max(-1, 0)

	if .offsetY >  {
		 := min(.offsetY, )
		.offsetY = 
	} else if .offsetY+ <  {
		 := max(.offsetY, )
		if  {
			.offsetY =  - /2
		} else {
			.offsetY = 
		}
	}
}

// GetCurrentNode returns the currently selected node or nil of no node is
// currently selected.
func ( *TreeView) () *TreeNode {
	.RLock()
	defer .RUnlock()

	return .currentNode
}

// GetPath returns all nodes located on the path from the root to the given
// node, including the root and the node itself. If there is no root node, nil
// is returned. If there are multiple paths to the node, a random one is chosen
// and returned.
func ( *TreeView) ( *TreeNode) []*TreeNode {
	if .root == nil {
		return nil
	}

	var  func( *TreeNode,  []*TreeNode) []*TreeNode
	 = func( *TreeNode,  []*TreeNode) []*TreeNode {
		if  ==  {
			return 
		}

		for ,  := range .children {
			 := make([]*TreeNode, len(), len()+1)
			copy(, )
			if  := (, append(, ));  != nil {
				return 
			}
		}

		return nil
	}

	return (.root, []*TreeNode{.root})
}

// SetTopLevel sets the first tree level that is visible with 0 referring to the
// root, 1 to the root's child nodes, and so on. Nodes above the top level are
// not displayed.
func ( *TreeView) ( int) {
	.Lock()
	defer .Unlock()

	.topLevel = 
}

// SetPrefixes defines the strings drawn before the nodes' texts. This is a
// slice of strings where each element corresponds to a node's hierarchy level,
// i.e. 0 for the root, 1 for the root's children, and so on (levels will
// cycle).
//
// For example, to display a hierarchical list with bullet points:
//
//	treeView.SetGraphics(false).
//	  SetPrefixes([]string{"* ", "- ", "x "})
func ( *TreeView) ( []string) {
	.Lock()
	defer .Unlock()

	.prefixes = make([][]byte, len())
	for  := range  {
		.prefixes[] = []byte([])
	}
}

// SetAlign controls the horizontal alignment of the node texts. If set to true,
// all texts except that of top-level nodes will be placed in the same column.
// If set to false, they will indent with the hierarchy.
func ( *TreeView) ( bool) {
	.Lock()
	defer .Unlock()

	.align = 
}

// SetGraphics sets a flag which determines whether or not line graphics are
// drawn to illustrate the tree's hierarchy.
func ( *TreeView) ( bool) {
	.Lock()
	defer .Unlock()

	.graphics = 
}

func ( *TreeView) ( tcell.Color) {
	.Lock()
	defer .Unlock()
	.highlightColor = &
}

// SetSelectedTextColor sets the text color of selected items.
func ( *TreeView) ( tcell.Color) {
	.Lock()
	defer .Unlock()
	.selectedTextColor = &
}

// SetSelectedBackgroundColor sets the background color of selected items.
func ( *TreeView) ( tcell.Color) {
	.Lock()
	defer .Unlock()
	.selectedBackgroundColor = &
}

// SetGraphicsColor sets the colors of the lines used to draw the tree structure.
func ( *TreeView) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.graphicsColor = 
}

// SetScrollBarVisibility specifies the display of the scroll bar.
func ( *TreeView) ( ScrollBarVisibility) {
	.Lock()
	defer .Unlock()

	.scrollBarVisibility = 
}

// SetScrollBarColor sets the color of the scroll bar.
func ( *TreeView) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.scrollBarColor = 
}

// SetChangedFunc sets the function which is called when the user navigates to
// a new tree node.
func ( *TreeView) ( func( *TreeNode)) {
	.Lock()
	defer .Unlock()

	.changed = 
}

// SetSelectedFunc sets the function which is called when the user selects a
// node by pressing Enter on the current selection.
func ( *TreeView) ( func( *TreeNode)) {
	.Lock()
	defer .Unlock()

	.selected = 
}

// SetDoneFunc sets a handler which is called whenever the user presses the
// Escape, Tab, or Backtab key.
func ( *TreeView) ( func( tcell.Key)) {
	.Lock()
	defer .Unlock()

	.done = 
}

// GetScrollOffset returns the number of node rows that were skipped at the top
// of the tree view. Note that when the user navigates the tree view, this value
// is only updated after the tree view has been redrawn.
func ( *TreeView) () int {
	.RLock()
	defer .RUnlock()

	return .offsetY
}

// GetRowCount returns the number of "visible" nodes. This includes nodes which
// fall outside the tree view's box but notably does not include the children
// of collapsed nodes. Note that this value is only up to date after the tree
// view has been drawn.
func ( *TreeView) () int {
	.RLock()
	defer .RUnlock()

	return len(.nodes)
}

// Transform modifies the current selection.
func ( *TreeView) ( Transformation) {
	.Lock()
	defer .Unlock()

	 := false
	switch  {
	case TransformFirstItem:
		.movement = treeHome
	case TransformLastItem:
		.movement = treeEnd
	case TransformPreviousItem:
		.movement = treeUp
		 = true
	case TransformNextItem:
		.movement = treeDown
		 = true
	case TransformPreviousPage:
		.movement = treePageUp
	case TransformNextPage:
		.movement = treePageDown
	}

	.process()
	.scrollCurrentIntoView()
}

// process builds the visible tree, populates the "nodes" slice, and processes
// pending selection actions.
func ( *TreeView) () {
	, , ,  := .GetInnerRect()

	// Determine visible nodes and their placement.
	var ,  int
	.nodes = nil
	 := -1
	 := -1
	if .graphics {
		 = 1
	}

	// walk via the node's lock
	.root.Walk(func(,  *TreeNode,  int) bool {
		.Lock()
		defer .Unlock()

		// Set node attributes.
		if  == nil {
			.level = 0
			.graphicsX = 0
			.textX = 0
		} else {
			.level = .level + 1
			.graphicsX = .textX
			.textX = .graphicsX +  + .indent
		}
		if !.graphics && .align {
			// Without graphics, we align nodes on the first column.
			.textX = 0
		}
		if .level == .topLevel {
			// No graphics for top level nodes.
			.graphicsX = 0
			.textX = 0
		}

		// Add the node to the list.
		if .level >= .topLevel {
			// This node will be visible.
			if .textX >  {
				 = .textX
			}
			if  == .currentNode && .selectable {
				 = len(.nodes)
			}

			// Maybe we want to skip this level.
			if .topLevel == .level && ( < 0 || .graphicsX < ) {
				 = .graphicsX
			}

			.nodes = append(.nodes, )
		}

		// Recurse if desired.
		return .expanded
	})

	// Post-process positions.
	for ,  := range .nodes {
		// If text must align, we correct the positions.
		if .align && .level > .topLevel {
			.textX = 
		}

		// If we skipped levels, shift to the left.
		if  > 0 {
			.graphicsX -= 
			.textX -= 
		}
	}

	// Process selection. (Also trigger events if necessary.)
	if  >= 0 {
		// Move the selection.
		 := 
	:
		switch .movement {
		case treeUp:
			for  > 0 {
				--
				if .nodes[].selectable {
					break 
				}
			}
			 = 
		case treeDown:
			for  < len(.nodes)-1 {
				++
				if .nodes[].selectable {
					break 
				}
			}
			 = 
		case treeHome:
			for  = 0;  < len(.nodes); ++ {
				if .nodes[].selectable {
					break 
				}
			}
			 = 
		case treeEnd:
			for  = len(.nodes) - 1;  >= 0; -- {
				if .nodes[].selectable {
					break 
				}
			}
			 = 
		case treePageDown:
			if + < len(.nodes) {
				 += 
			} else {
				 = len(.nodes) - 1
			}
			for ;  < len(.nodes); ++ {
				if .nodes[].selectable {
					break 
				}
			}
			 = 
		case treePageUp:
			if  >=  {
				 -= 
			} else {
				 = 0
			}
			for ;  >= 0; -- {
				if .nodes[].selectable {
					break 
				}
			}
			 = 
		}
		.currentNode = .nodes[]
		 := false
		if  !=  {
			.movement = treeNone
			 = true
			if .changed != nil {
				.Unlock()
				.changed(.currentNode)
				.Lock()
			}
			if .currentNode.focused != nil {
				.Unlock()
				.currentNode.focused()
				.Lock()
			}
		}
		 = 

		// Move selection into viewport.
		if .movement != treeScrollUp && .movement != treeScrollDown && .movement != treeNone && ! {
			if -.offsetY >=  {
				.offsetY =  -  + 1
			}
			if  < .offsetY {
				.offsetY = 
			}
		}
	} else {
		// If selection is not visible or selectable, select the first candidate.
		if .currentNode != nil {
			for ,  := range .nodes {
				if .selectable {
					 = 
					.currentNode = 
					break
				}
			}
		}
		if  < 0 {
			.currentNode = nil
		}
	}
}

// Draw draws this primitive onto the screen.
func ( *TreeView) ( tcell.Screen) {
	if !.GetVisible() {
		return
	}

	.Box.Draw()

	.Lock()
	defer .Unlock()

	if .root == nil {
		return
	}

	.process()

	// Scroll the tree.
	, , ,  := .GetInnerRect()
	switch .movement {
	case treeScrollUp:
		.offsetY -=  / 3
	case treeScrollDown:
		.offsetY +=  / 3
	case treeUp:
		.offsetY--
	case treeDown:
		.offsetY++
	case treeHome:
		.offsetY = 0
	case treeEnd:
		.offsetY = len(.nodes)
	case treePageUp:
		.offsetY -= 
	case treePageDown:
		.offsetY += 
	}
	.movement = treeNone

	// Fix invalid offsets.
	if .offsetY >= len(.nodes)- {
		.offsetY = len(.nodes) - 
	}
	if .offsetY < 0 {
		.offsetY = 0
	}

	// Calculate scroll bar position.
	 := len(.nodes)
	 := int(float64() * (float64(.offsetY) / float64(-)))

	// Draw the tree.
	 := 
	for ,  := range .nodes {
		 := false
		func() {
			.Lock()
			defer .Unlock()

			 := tcell.StyleDefault.Background(.backgroundColor).Foreground(.graphicsColor)
			if .highlighted {
				 = .Background(*.highlightColor)
			}
			// Skip invisible parts.
			if  >= + {
				 = true
				return
			}
			if  < .offsetY {
				return
			}

			// Draw the highlight.
			 := ""
			if  > 0 {
				 = strings.Repeat(" ", -1)
			}
			PrintStyle(, []byte(), , , -1, AlignLeft, )

			// Draw the graphics.
			if .graphics {
				// Draw ancestor branches.
				 := .parent
				for  != nil && .parent != nil && .parent.level >= .topLevel {
					if .graphicsX >=  {
						return
					}

					// Draw a branch if this ancestor is not a last child.
					 := len(.parent.children) - 1
					// TODO runtime error: index out of range [-1]
					if  >= 0 && .parent.children[] !=  {
						if -1 >=  && .textX > .graphicsX {
							PrintJoinedSemigraphics(, +.graphicsX, -1, Borders.Vertical, .graphicsColor)
						}
						if  < + {
							.SetContent(+.graphicsX, , Borders.Vertical, nil, )
						}
					}
					 = .parent
				}

				if .textX > .graphicsX && .graphicsX <  {
					// Connect to the node above.
					if -1 >=  && .nodes[-1].graphicsX <= .graphicsX && .nodes[-1].textX > .graphicsX {
						PrintJoinedSemigraphics(, +.graphicsX, -1, Borders.TopLeft, .graphicsColor)
					}

					// Join this node.
					if  < + {
						.SetContent(+.graphicsX, , Borders.BottomLeft, nil, )
						for  := .graphicsX + 1;  < .textX &&  < ; ++ {
							.SetContent(+, , Borders.Horizontal, nil, )
						}
					}
				}
			}

			// Draw the prefix and the text.
			if .textX <  &&  < + {

				// Prefix.
				var  int
				if len(.prefixes) > 0 {
					_,  = PrintStyle(, .prefixes[(.level-.topLevel)%len(.prefixes)], +.textX, , -.textX, AlignLeft, .Foreground(.color))
				}

				// Text.
				if .textX+ <  {
					 := tcell.StyleDefault.Foreground(.color).Bold(.bold).Underline(.underline)
					if  == .currentNode {
						 := .color
						 := .backgroundColor
						if .selectedTextColor != nil {
							 = *.selectedTextColor
						}
						if .selectedBackgroundColor != nil {
							 = *.selectedBackgroundColor
						}
						 = tcell.StyleDefault.Background().Foreground()
					}
					PrintStyle(, []byte(.text), +.textX+, , -.textX-, AlignLeft, )
				}
			}

			// Draw scroll bar.
			RenderScrollBar(, .scrollBarVisibility, +(-1), , , , , -, .hasFocus, .scrollBarColor)

			// Advance.
			++
		}()

		if  {
			break
		}
	}
}

// SelectNode selects the given node.
func ( *TreeView) ( *TreeNode) {
	if  == nil {
		return
	}

	.Lock()
	defer .Unlock()

	if .selected != nil {
		.selected()
	}
	if .focused != nil {
		.focused()
	}
	if .selected != nil {
		.selected()
	}
}

// InputHandler returns the handler for this primitive.
func ( *TreeView) () func( *tcell.EventKey,  func( Primitive)) {
	return .WrapInputHandler(func( *tcell.EventKey,  func( Primitive)) {
		 := func() {
			.Lock()
			 := .currentNode
			.Unlock()
			if  == nil {
				return
			}

			if .selected != nil {
				.selected()
			}
			if .focused != nil {
				.focused()
			}
			if .selected != nil {
				.selected()
			}
		}

		.Lock()
		defer .Unlock()

		 := false

		// Because the tree is flattened into a list only at drawing time, we also
		// postpone the (selection) movement to drawing time.
		if HitShortcut(, Keys.Cancel, Keys.MovePreviousField, Keys.MoveNextField) {
			if .done != nil {
				.Unlock()
				.done(.Key())
				.Lock()
			}
		} else if HitShortcut(, Keys.MoveFirst, Keys.MoveFirst2) {
			.movement = treeHome
		} else if HitShortcut(, Keys.MoveLast, Keys.MoveLast2) {
			.movement = treeEnd
		} else if HitShortcut(, Keys.MoveUp, Keys.MoveUp2) {
			.movement = treeUp
			 = true
		} else if HitShortcut(, Keys.MoveDown, Keys.MoveDown2) {
			.movement = treeDown
			 = true
		} else if HitShortcut(, Keys.MovePreviousPage) {
			.movement = treePageUp
		} else if HitShortcut(, Keys.MoveNextPage) {
			.movement = treePageDown
		} else if HitShortcut(, Keys.Select, Keys.Select2) {
			.Unlock()
			()
			.Lock()
		}

		.process()
		.scrollCurrentIntoView()
	})
}

// MouseHandler returns the mouse handler for this primitive.
func ( *TreeView) () func(
	 MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive,
) {

	return .WrapMouseHandler(func(
		 MouseAction,  *tcell.EventMouse,  func( Primitive),
	) ( bool,  Primitive) {

		,  := .Position()
		if !.InRect(, ) {
			return false, nil
		}

		switch  {
		case MouseLeftClick:
			, , ,  := .GetInnerRect()
			 -= 
			 += .offsetY
			if  >= 0 &&  < len(.nodes) {
				 := .nodes[]
				if .selectable {
					if .currentNode !=  && .changed != nil {
						.changed()
					}
					if .selected != nil {
						.selected()
					}
					.currentNode = 
				}
			}
			 = true
			()
		case MouseScrollUp:
			.movement = treeScrollUp
			 = true
		case MouseScrollDown:
			.movement = treeScrollDown
			 = true
		}

		return
	})
}