11# ABSTRACT: A viewer/browser for a Volatile::Tree
22
3- use Terminal::Widgets::Widget;
4- use Terminal::Widgets::Scrollable;
3+ use Terminal::Widgets::Events;
4+ use Terminal::Widgets::SpanStyle;
5+ use Terminal::Widgets::SpanBuffer;
56use Terminal::Widgets::Focusable;
67use Terminal::Widgets::Volatile::Tree;
78
@@ -53,28 +54,34 @@ my class DisplayParent does DisplayNode {
5354
5455
5556class Terminal::Widgets::Viewer::Tree
56- is Terminal::Widgets::Widget
57- does Terminal::Widgets::Scrollable
57+ does Terminal::Widgets::SpanBuffer
5858 does Terminal::Widgets::Focusable {
5959 has VTree::Node $ . root ;
6060 has DisplayParent $ . display-root is built(False );
61+ has & . process-click ;
6162
6263 # Keep root and display-root in sync
6364 method set-root (VTree::Node: D $ ! root ) { self ! remap-root }
6465 method ! remap-root () {
6566 $ ! display-root = DisplayParent. new (data => $ ! root , depth => 0 );
6667 }
6768
68- method draw-content ( ) {
69+ method span-line-chunk ( UInt : D $ start , UInt : D $ wanted ) {
6970 my @ lines = self . node-lines($ ! display-root );
70- . note for @ lines ;
71+ my $ count = @ lines . elems ;
72+ my $ end = $ start + $ wanted - 1 ;
73+
74+ self . set-y-max($ count );
75+
76+ $ count > $ end ?? @ lines [$ start .. $ end ]
77+ !! @ lines [$ start .. * ]
7178 }
7279
7380 # | Displayable lines for a given node
7481 method node-lines ($ node ) {
7582 my $ is-parent = $ node ~~ DisplayParent;
76- my $ first-line = self . prefix-string($ node )
77- ~ self . node-content($ node );
83+ my $ first-line = [ self . prefix-string($ node ),
84+ self . node-content($ node ) ] ;
7885
7986 $ is-parent ?? ($ first-line ,
8087 $ node . children. map ({ self . node-lines($ _ ). Slip })). flat
@@ -83,14 +90,14 @@ class Terminal::Widgets::Viewer::Tree
8390
8491 # | Prefix for first line of a given node
8592 method prefix-string ($ node ) {
86- ' ' x $ node . depth
87- ~ ($ node ~~ DisplayParent ?? self . arrows()[+ $ node . expanded] !! ' ' )
88- ~ ' '
93+ span( ' ' , ' ' x $ node . depth
94+ ~ ($ node ~~ DisplayParent ?? self . arrows()[+ $ node . expanded] !! ' ' )
95+ ~ ' ' )
8996 }
9097
9198 # | Displayed content for a given node itself, not including children
9299 method node-content ($ node ) {
93- $ node . data. short-name
100+ span( ' ' , $ node . data. short-name)
94101 }
95102
96103 # | Arrow glyphs for given terminal capabilities
@@ -102,4 +109,36 @@ class Terminal::Widgets::Viewer::Tree
102109
103110 $ caps . best-symbol-choice(% arrows )
104111 }
112+
113+ method line-to-display-node ($ line ) {
114+ # XXXX: TEMP HACK
115+ $ . display-root
116+ }
117+
118+ multi method handle-event (Terminal::Widgets::Events::MouseEvent: D
119+ $ event where !*. mouse. pressed, AtTarget) {
120+ # Take focus even if clicked on framing instead of content area
121+ self . toplevel. focus-on(self );
122+
123+ # If enabled and within content area, move cursor and process click
124+ if $ . enabled {
125+ my ($ x , $ y , $ w , $ h ) = $ event . relative-to-content-area(self );
126+
127+ if 0 <= $ x < $ w && 0 <= $ y < $ h {
128+ my $ clicked-line = $ . y-scroll + $ y ;
129+ my $ node = self . line-to-display-node($ clicked-line );
130+
131+ if $ node ~~ DisplayParent {
132+ $ node . toggle-expanded;
133+ self . set-y-max($ . display-root . branch-size);
134+ self . refresh-for-scroll;
135+ }
136+
137+ $ _ ($ node ) with & ! process-click ;
138+ }
139+ }
140+
141+ # Refresh even if outside content area because of focus state change
142+ self . full-refresh;
143+ }
105144}
0 commit comments