1# RCS: @(#) $Id: treectrl.tcl,v 1.41 2009/04/18 20:39:54 treectrl Exp $
2
3bind TreeCtrl <Motion> {
4    TreeCtrl::CursorCheck %W %x %y
5    TreeCtrl::MotionInHeader %W %x %y
6}
7bind TreeCtrl <Leave> {
8    TreeCtrl::CursorCancel %W
9    TreeCtrl::MotionInHeader %W
10}
11bind TreeCtrl <ButtonPress-1> {
12    TreeCtrl::ButtonPress1 %W %x %y
13}
14bind TreeCtrl <Double-ButtonPress-1> {
15    TreeCtrl::DoubleButton1 %W %x %y
16}
17bind TreeCtrl <Button1-Motion> {
18    TreeCtrl::Motion1 %W %x %y
19}
20bind TreeCtrl <ButtonRelease-1> {
21    TreeCtrl::Release1 %W %x %y
22}
23bind TreeCtrl <Shift-ButtonPress-1> {
24    set TreeCtrl::Priv(buttonMode) normal
25    TreeCtrl::BeginExtend %W [%W item id {nearest %x %y}]
26}
27# Command-click should provide a discontinuous selection on OSX
28switch -- [tk windowingsystem] {
29    "aqua" { set modifier Command }
30    default { set modifier Control }
31}
32bind TreeCtrl <$modifier-ButtonPress-1> {
33    set TreeCtrl::Priv(buttonMode) normal
34    TreeCtrl::BeginToggle %W [%W item id {nearest %x %y}]
35}
36bind TreeCtrl <Button1-Leave> {
37    TreeCtrl::Leave1 %W %x %y
38}
39bind TreeCtrl <Button1-Enter> {
40    TreeCtrl::Enter1 %W %x %y
41}
42
43bind TreeCtrl <KeyPress-Up> {
44    TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W active -1]
45}
46bind TreeCtrl <Shift-KeyPress-Up> {
47    TreeCtrl::Extend %W above
48}
49bind TreeCtrl <KeyPress-Down> {
50    TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W active 1]
51}
52bind TreeCtrl <Shift-KeyPress-Down> {
53    TreeCtrl::Extend %W below
54}
55bind TreeCtrl <KeyPress-Left> {
56    if {[%W cget -orient] eq "vertical" && [%W cget -wrap] eq ""} {
57	%W item collapse [%W item id active]
58    } else {
59	TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W active -1]
60    }
61}
62bind TreeCtrl <Shift-KeyPress-Left> {
63    TreeCtrl::Extend %W left
64}
65bind TreeCtrl <Control-KeyPress-Left> {
66    %W xview scroll -1 pages
67}
68bind TreeCtrl <KeyPress-Right> {
69    if {[%W cget -orient] eq "vertical" && [%W cget -wrap] eq ""} {
70	%W item expand [%W item id active]
71    } else {
72	TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W active 1]
73    }
74}
75bind TreeCtrl <Shift-KeyPress-Right> {
76    TreeCtrl::Extend %W right
77}
78bind TreeCtrl <Control-KeyPress-Right> {
79    %W xview scroll 1 pages
80}
81bind TreeCtrl <KeyPress-Prior> {
82    %W yview scroll -1 pages
83    if {[%W item id {nearest 0 0}] ne ""} {
84	%W activate {nearest 0 0}
85    }
86}
87bind TreeCtrl <KeyPress-Next> {
88    %W yview scroll 1 pages
89    if {[%W item id {nearest 0 0}] ne ""} {
90	%W activate {nearest 0 0}
91    }
92}
93bind TreeCtrl <Control-KeyPress-Prior> {
94    %W xview scroll -1 pages
95}
96bind TreeCtrl <Control-KeyPress-Next> {
97    %W xview scroll 1 pages
98}
99bind TreeCtrl <KeyPress-Home> {
100    %W xview moveto 0
101}
102bind TreeCtrl <KeyPress-End> {
103    %W xview moveto 1
104}
105bind TreeCtrl <Control-KeyPress-Home> {
106    TreeCtrl::SetActiveItem %W [%W item id {first visible state enabled}]
107}
108bind TreeCtrl <Shift-Control-KeyPress-Home> {
109    TreeCtrl::DataExtend %W [%W item id {first visible state enabled}]
110}
111bind TreeCtrl <Control-KeyPress-End> {
112    TreeCtrl::SetActiveItem %W [%W item id {last visible state enabled}]
113}
114bind TreeCtrl <Shift-Control-KeyPress-End> {
115    TreeCtrl::DataExtend %W [%W item id {last visible state enabled}]
116}
117bind TreeCtrl <<Copy>> {
118    if {[string equal [selection own -displayof %W] "%W"]} {
119	clipboard clear -displayof %W
120	clipboard append -displayof %W [selection get -displayof %W]
121    }
122}
123bind TreeCtrl <KeyPress-space> {
124    TreeCtrl::BeginSelect %W [%W item id active]
125}
126bind TreeCtrl <KeyPress-Select> {
127    TreeCtrl::BeginSelect %W [%W item id active]
128}
129bind TreeCtrl <Control-Shift-KeyPress-space> {
130    TreeCtrl::BeginExtend %W [%W item id active]
131}
132bind TreeCtrl <Shift-KeyPress-Select> {
133    TreeCtrl::BeginExtend %W [%W item id active]
134}
135bind TreeCtrl <KeyPress-Escape> {
136    TreeCtrl::Cancel %W
137}
138bind TreeCtrl <Control-KeyPress-slash> {
139    TreeCtrl::SelectAll %W
140}
141bind TreeCtrl <Control-KeyPress-backslash> {
142    if {[string compare [%W cget -selectmode] "browse"]} {
143	%W selection clear
144    }
145}
146
147bind TreeCtrl <KeyPress-plus> {
148    %W item expand [%W item id active]
149}
150bind TreeCtrl <KeyPress-minus> {
151    %W item collapse [%W item id active]
152}
153bind TreeCtrl <KeyPress-Return> {
154    %W item toggle [%W item id active]
155}
156
157
158# Additional Tk bindings that aren't part of the Motif look and feel:
159
160bind TreeCtrl <ButtonPress-2> {
161    TreeCtrl::ScanMark %W %x %y
162}
163bind TreeCtrl <Button2-Motion> {
164    TreeCtrl::ScanDrag %W %x %y
165}
166
167if {$tcl_platform(platform) eq "windows"} {
168    bind TreeCtrl <Control-ButtonPress-3> {
169	TreeCtrl::ScanMark %W %x %y
170    }
171    bind TreeCtrl <Control-Button3-Motion> {
172	TreeCtrl::ScanDrag %W %x %y
173    }
174}
175
176# MouseWheel
177if {[string equal "x11" [tk windowingsystem]]} {
178    # Support for mousewheels on Linux/Unix commonly comes through mapping
179    # the wheel to the extended buttons.  If you have a mousewheel, find
180    # Linux configuration info at:
181    #	http://www.inria.fr/koala/colas/mouse-wheel-scroll/
182    bind TreeCtrl <4> {
183	if {!$tk_strictMotif} {
184	    %W yview scroll -5 units
185	}
186    }
187    bind TreeCtrl <5> {
188	if {!$tk_strictMotif} {
189	    %W yview scroll 5 units
190	}
191    }
192} elseif {[string equal [tk windowingsystem] "aqua"]} {
193    bind TreeCtrl <MouseWheel> {
194	%W yview scroll [expr {- (%D)}] units
195    }
196} else {
197    bind TreeCtrl <MouseWheel> {
198	%W yview scroll [expr {- (%D / 120) * 4}] units
199    }
200}
201
202namespace eval ::TreeCtrl {
203    variable Priv
204    array set Priv {
205	prev {}
206    }
207
208    if {[info procs ::lassign] eq ""} {
209	proc lassign {values args} {
210	    uplevel 1 [list foreach $args [linsert $values end {}] break]
211	    lrange $values [llength $args] end
212	}
213    }
214}
215
216# Retrieve filelist bindings from this dir
217source [file join [file dirname [info script]] filelist-bindings.tcl]
218
219# ::TreeCtrl::ColumnCanResizeLeft --
220#
221# Return 1 if the given column should be resized by the left edge.
222#
223# Arguments:
224# w		The treectrl widget.
225# column	The column.
226
227proc ::TreeCtrl::ColumnCanResizeLeft {w column} {
228    if {[$w column cget $column -lock] eq "right"} {
229	if {[$w column compare $column == "first visible lock right"]} {
230	    return 1
231	}
232	if {[$w column compare $column == "last visible lock right"]} {
233	    return 1
234	}
235    }
236    return 0
237}
238
239# ::TreeCtrl::ColumnCanMoveHere --
240#
241# Return 1 if the given column can be moved before another.
242#
243# Arguments:
244# w		The treectrl widget.
245# column	The column.
246# before	The column to place 'column' before.
247
248proc ::TreeCtrl::ColumnCanMoveHere {w column before} {
249    if {[$w column compare $column == $before] ||
250	    ([$w column order $column] == [$w column order $before] - 1)} {
251	return 0
252    }
253    set lock [$w column cget $column -lock]
254    return [expr {[$w column compare $before >= "first lock $lock"] &&
255	[$w column compare $before <= "last lock $lock next"]}]
256}
257
258# ::TreeCtrl::ColumnsBbox --
259#
260# Returns the bounding box of an area of the header.  The [bbox] command
261# can't be used if the items area is completely obscured. [BUG 2355369]
262#
263# Arguments:
264# w		The treectrl widget.
265# area		left, content or right
266
267proc ::TreeCtrl::ColumnsBbox {w area} {
268    if {[$w bbox header] eq ""} return
269    scan [$w bbox header] "%d %d %d %d" x1 y1 x2 y2
270
271    # If the items area is not obscured then use the [bbox] command.
272    if {[$w bbox $area] ne ""} {
273	scan [$w bbox $area] "%d %d %d %d" x1 dummy x2 dummy
274	return "$x1 $y1 $x2 $y2"
275    }
276
277    set contentLeft $x1
278    if {[$w column id "last visible lock left"] ne ""} {
279	scan [$w column bbox "last visible lock left"] "%d %d %d %d" a b c d
280	set contentLeft $c
281    } elseif {$area eq "left"} {
282	return ""
283    }
284
285    set contentRight $x2
286    if {[$w column id "first visible lock right"] ne ""} {
287	scan [$w column bbox "first visible lock right"] "%d %d %d %d" a b c d
288	set contentRight $a
289    } elseif {$area eq "right"} {
290	return ""
291    }
292
293    switch -- $area {
294	left { set result "$x1 $y1 $contentLeft $y2" }
295	content { set result "$contentLeft $y1 $contentRight $y2" }
296	right { set result "$contentRight $y1 $x2 $y2" }
297    }
298    return $result
299}
300
301# ::TreeCtrl::ColumnDragFindBefore --
302#
303# This is called when dragging a column header. The result is 1 if the given
304# coordinates are near a column header before which the dragged column can
305# be moved.
306#
307# Arguments:
308# w		The treectrl widget.
309# x		Window x-coord.
310# y		Window y-coord.
311# dragColumn	The column being dragged.
312# indColumn_	Out: what to set -indicatorcolumn to.
313# indSide_	Out: what to set -indicatorside to.
314
315proc ::TreeCtrl::ColumnDragFindBefore {w x y dragColumn indColumn_ indSide_} {
316    upvar $indColumn_ indColumn
317    upvar $indSide_ indSide
318
319    switch -- [$w column cget $dragColumn -lock] {
320	left {set area left}
321	none {set area content}
322	right {set area right}
323    }
324
325# BUG 2355369
326#    scan [$w bbox $area] "%d %d %d %d" minX y1 maxX y2
327    scan [ColumnsBbox $w $area] "%d %d %d %d" minX y1 maxX y2
328    if {$x < $minX} {
329	set x $minX
330    }
331    if {$x >= $maxX} {
332	set x [expr {$maxX - 1}]
333    }
334    set id [$w identify $x $y]
335    if {[lindex $id 0] ne "header"} {
336	return 0
337    }
338    set indColumn [lindex $id 1]
339    set before $indColumn
340    set prev [$w column id "$dragColumn prev visible"]
341    set next [$w column id "$dragColumn next visible"]
342    if {[$w column compare $indColumn == "tail"]} {
343	set indSide left
344    } elseif {$prev ne "" && [$w column compare $prev == $indColumn]} {
345	set indSide left
346    } elseif {$next ne "" && [$w column compare $next == $indColumn]} {
347	set before [$w column id "$indColumn next visible"]
348	set indSide right
349    } else {
350	scan [$w column bbox $indColumn] "%d %d %d %d" x1 y1 x2 y2
351	if {$x < $x1 + ($x2 - $x1) / 2} {
352	    set indSide left
353	} else {
354	    set before [$w column id "$indColumn next visible"]
355	    set indSide right
356	}
357    }
358    return [ColumnCanMoveHere $w $dragColumn $before]
359}
360
361# ::TreeCtrl::CursorAction --
362#
363# If the given point is at the left or right edge of a resizable column, the
364# result is "column resize C". If the given point is in a header with -button
365# TRUE, the result is "column button C".
366#
367# Arguments:
368# w		The treectrl widget.
369# x		Window coord of pointer.
370# y		Window coord of pointer.
371
372proc ::TreeCtrl::CursorAction {w x y} {
373    variable Priv
374    set id [$w identify $x $y]
375
376    if {[lindex $id 0] eq "header"} {
377	set column [lindex $id 1]
378	set side [lindex $id 2]
379	if {$side eq "left"} {
380	    if {[$w column compare $column == tail]} {
381		set column2 [$w column id "last visible lock none"]
382		if {$column2 ne "" && [$w column cget $column2 -resize]} {
383		    return "column resize $column2"
384		}
385		# Can't -resize or -button the tail column
386		return ""
387	    }
388	    if {[ColumnCanResizeLeft $w $column]} {
389		if {[$w column cget $column -resize]} {
390		    return "column resize $column"
391		}
392	    } else {
393		# Resize the previous column
394		set lock [$w column cget $column -lock]
395		if {[$w column compare $column != "first visible lock $lock"]} {
396		    set column2 [$w column id "$column prev visible"]
397		    if {[$w column cget $column2 -resize]} {
398			return "column resize $column2"
399		    }
400		}
401	    }
402	} elseif {$side eq "right"} {
403	    if {![ColumnCanResizeLeft $w $column]} {
404		if {[$w column cget $column -resize]} {
405		    return "column resize $column"
406		}
407	    }
408	}
409	if {[$w column compare $column == "tail"]} {
410	    # nothing
411	} elseif {[$w column cget $column -button]} {
412	    return "column button $column"
413	}
414    }
415    return ""
416}
417
418# ::TreeCtrl::CursorCheck --
419#
420# Sees if the given pointer coordinates are near the edge of a resizable
421# column in the header. If so and the treectrl's cursor is not already
422# set to sb_h_double_arrow, then the current cursor is saved and changed
423# to sb_h_double_arrow, and an [after] callback to CursorCheckAux is
424# scheduled.
425#
426# Arguments:
427# w		The treectrl widget.
428# x		Window coord of pointer.
429# y		Window coord of pointer.
430
431proc ::TreeCtrl::CursorCheck {w x y} {
432    variable Priv
433    set action [CursorAction $w $x $y]
434    if {[lindex $action 1] ne "resize"} {
435	CursorCancel $w
436	return
437    }
438    set cursor sb_h_double_arrow
439    if {$cursor ne [$w cget -cursor]} {
440	if {![info exists Priv(cursor,$w)]} {
441	    set Priv(cursor,$w) [$w cget -cursor]
442	}
443	$w configure -cursor $cursor
444    }
445    if {[info exists Priv(cursor,afterId,$w)]} {
446	after cancel $Priv(cursor,afterId,$w)
447    }
448    set Priv(cursor,afterId,$w) [after 150 [list TreeCtrl::CursorCheckAux $w]]
449    return
450}
451
452# ::TreeCtrl::CursorCheckAux --
453#
454# Get's the location of the pointer and calls CursorCheck if the treectrl's
455# cursor was previously set to sb_h_double_arrow.
456#
457# Arguments:
458# w		The treectrl widget.
459
460proc ::TreeCtrl::CursorCheckAux {w} {
461    variable Priv
462    set x [winfo pointerx $w]
463    set y [winfo pointery $w]
464    if {[info exists Priv(cursor,$w)]} {
465	set x [expr {$x - [winfo rootx $w]}]
466	set y [expr {$y - [winfo rooty $w]}]
467	CursorCheck $w $x $y
468    }
469    return
470}
471
472# ::TreeCtrl::CursorCancel --
473#
474# Restores the treectrl's cursor if it was changed to sb_h_double_arrow.
475# Cancels any pending [after] callback to CursorCheckAux.
476#
477# Arguments:
478# w		The treectrl widget.
479
480proc ::TreeCtrl::CursorCancel {w} {
481    variable Priv
482    if {[info exists Priv(cursor,$w)]} {
483	$w configure -cursor $Priv(cursor,$w)
484	unset Priv(cursor,$w)
485    }
486    if {[info exists Priv(cursor,afterId,$w)]} {
487	after cancel $Priv(cursor,afterId,$w)
488	unset Priv(cursor,afterId,$w)
489    }
490    return
491}
492
493# ::TreeCtrl::MotionInHeader --
494#
495# This procedure updates the active/normal states of columns as the pointer
496# moves in and out of column headers. Typically this results in visual
497# feedback by changing the appearance of the headers.
498#
499# Arguments:
500# w		The treectrl widget.
501# args		x y coords if the pointer is in the window, or an empty list.
502
503proc ::TreeCtrl::MotionInHeader {w args} {
504    variable Priv
505    if {[llength $args]} {
506	set x [lindex $args 0]
507	set y [lindex $args 1]
508	set action [CursorAction $w $x $y]
509    } else {
510	set action ""
511    }
512    if {[info exists Priv(inheader,$w)]} {
513	set prevColumn $Priv(inheader,$w)
514    } else {
515	set prevColumn ""
516    }
517    set column ""
518    if {[lindex $action 0] eq "column"} {
519	set column [lindex $action 2]
520    }
521    if {$column ne $prevColumn} {
522	if {$prevColumn ne ""} {
523	    $w column configure $prevColumn -state normal
524	}
525	if {$column ne ""} {
526	    $w column configure $column -state active
527	    set Priv(inheader,$w) $column
528	} else {
529	    unset Priv(inheader,$w)
530	}
531    }
532    return
533}
534
535# ::TreeCtrl::ButtonPress1 --
536#
537# Handle <ButtonPress-1> event.
538#
539# Arguments:
540# w		The treectrl widget.
541# x		Window x coord.
542# y		Window y coord.
543
544proc ::TreeCtrl::ButtonPress1 {w x y} {
545    variable Priv
546    focus $w
547
548    set id [$w identify $x $y]
549    if {$id eq ""} {
550	return
551    }
552
553    if {[lindex $id 0] eq "item"} {
554	lassign $id where item arg1 arg2
555	if {$arg1 eq "button"} {
556	    $w item toggle $item
557	    return
558	} elseif {$arg1 eq "line"} {
559	    $w item toggle $arg2
560	    return
561	}
562    }
563    set Priv(buttonMode) ""
564    if {[lindex $id 0] eq "header"} {
565	set action [CursorAction $w $x $y]
566	if {[lindex $action 1] eq "resize"} {
567	    set column [lindex $action 2]
568	    set Priv(buttonMode) resize
569	    set Priv(column) $column
570	    set Priv(x) $x
571	    set Priv(y) $y
572	    set Priv(width) [$w column width $column]
573	    return
574	}
575	set column [lindex $id 1]
576	if {[lindex $action 1] eq "button"} {
577	    set Priv(buttonMode) header
578	    $w column configure $column -state pressed
579	} else {
580	    if {[$w column compare $column == "tail"]} return
581	    if {![$w column dragcget -enable]} return
582	    set Priv(buttonMode) dragColumnWait
583	}
584	set Priv(column) $column
585	set Priv(columnDrag,x) $x
586	set Priv(columnDrag,y) $y
587	return
588    }
589    set item [lindex $id 1]
590    if {![$w item enabled $item]} {
591	return
592    }
593
594    # If the initial mouse-click is in a locked column, restrict scrolling
595    # to the vertical.
596    scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2
597    if {$x >= $x1 && $x < $x2} {
598	set Priv(autoscan,direction,$w) xy
599    } else {
600	set Priv(autoscan,direction,$w) y
601    }
602
603    set Priv(buttonMode) normal
604    BeginSelect $w $item
605    return
606}
607
608# ::TreeCtrl::DoubleButtonPress1 --
609#
610# Handle <Double-ButtonPress-1> event.
611#
612# Arguments:
613# w		The treectrl widget.
614# x		Window x coord.
615# y		Window y coord.
616
617proc ::TreeCtrl::DoubleButton1 {w x y} {
618
619    set id [$w identify $x $y]
620    if {$id eq ""} {
621	return
622    }
623    if {[lindex $id 0] eq "item"} {
624	lassign $id where item arg1 arg2
625	if {$arg1 eq "button"} {
626	    $w item toggle $item
627	    return
628	} elseif {$arg1 eq "line"} {
629	    $w item toggle $arg2
630	    return
631	}
632    }
633    if {[lindex $id 0] eq "header"} {
634	set action [CursorAction $w $x $y]
635	# Double-click between columns to set default column width
636	if {[lindex $action 1] eq "resize"} {
637	    set column [lindex $action 2]
638	    $w column configure $column -width ""
639	    CursorCheck $w $x $y
640	    MotionInHeader $w $x $y
641	} else {
642	    ButtonPress1 $w $x $y
643	}
644    }
645    return
646}
647
648# ::TreeCtrl::Motion1 --
649#
650# Handle <Button1-Motion> event.
651#
652# Arguments:
653# w		The treectrl widget.
654# x		Window x coord.
655# y		Window y coord.
656
657proc ::TreeCtrl::Motion1 {w x y} {
658    variable Priv
659    if {![info exists Priv(buttonMode)]} return
660    switch $Priv(buttonMode) {
661	header {
662	    set id [$w identify $x $y]
663	    if {![string match "header $Priv(column)*" $id]} {
664		if {[$w column cget $Priv(column) -state] eq "pressed"} {
665		    $w column configure $Priv(column) -state normal
666		}
667	    } else {
668		if {[$w column cget $Priv(column) -state] ne "pressed"} {
669		    $w column configure $Priv(column) -state pressed
670		}
671		if {[$w column dragcget -enable] &&
672		    (abs($Priv(columnDrag,x) - $x) > 4)} {
673		    $w column dragconfigure \
674			-imagecolumn $Priv(column) \
675			-imageoffset [expr {$x - $Priv(columnDrag,x)}]
676		    set Priv(buttonMode) dragColumn
677		    TryEvent $w ColumnDrag begin [list C $Priv(column)]
678		}
679	    }
680	}
681	dragColumnWait {
682	    if {(abs($Priv(columnDrag,x) - $x) > 4)} {
683		$w column dragconfigure \
684		    -imagecolumn $Priv(column) \
685		    -imageoffset [expr {$x - $Priv(columnDrag,x)}]
686		set Priv(buttonMode) dragColumn
687		TryEvent $w ColumnDrag begin [list C $Priv(column)]
688	    }
689	}
690	dragColumn {
691	    scan [$w bbox header] "%d %d %d %d" x1 y1 x2 y2
692	    if {$y < $y1 - 30 || $y >= $y2 + 30} {
693		set inside 0
694	    } else {
695		set inside 1
696	    }
697	    if {$inside && ([$w column dragcget -imagecolumn] eq "")} {
698		$w column dragconfigure -imagecolumn $Priv(column)
699	    } elseif {!$inside && ([$w column dragcget -imagecolumn] ne "")} {
700		$w column dragconfigure -imagecolumn "" -indicatorcolumn ""
701	    }
702	    if {$inside} {
703		$w column dragconfigure -imageoffset [expr {$x - $Priv(columnDrag,x)}]
704		if {[ColumnDragFindBefore $w $x $Priv(columnDrag,y) $Priv(column) indColumn indSide]} {
705		    $w column dragconfigure -indicatorcolumn $indColumn \
706			-indicatorside $indSide
707		} else {
708		    $w column dragconfigure -indicatorcolumn ""
709		}
710	    }
711	    if {[$w column cget $Priv(column) -lock] eq "none"} {
712		ColumnDragScrollCheck $w $x $y
713	    }
714	}
715	normal {
716	    set Priv(x) $x
717	    set Priv(y) $y
718	    SelectionMotion $w [$w item id [list nearest $x $y]]
719	    set Priv(autoscan,command,$w) {SelectionMotion %T [%T item id "nearest %x %y"]}
720	    AutoScanCheck $w $x $y
721	}
722	resize {
723	    if {[ColumnCanResizeLeft $w $Priv(column)]} {
724		set width [expr {$Priv(width) + $Priv(x) - $x}]
725	    } else {
726		set width [expr {$Priv(width) + $x - $Priv(x)}]
727	    }
728	    set minWidth [$w column cget $Priv(column) -minwidth]
729	    set maxWidth [$w column cget $Priv(column) -maxwidth]
730	    if {$minWidth eq ""} {
731		set minWidth 0
732	    }
733	    if {$width < $minWidth} {
734		set width $minWidth
735	    }
736	    if {($maxWidth ne "") && ($width > $maxWidth)} {
737		set width $maxWidth
738	    }
739	    if {$width == 0} {
740		incr width
741	    }
742	    switch -- [$w cget -columnresizemode] {
743		proxy {
744		    scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2
745		    if {[ColumnCanResizeLeft $w $Priv(column)]} {
746			# Use "ne" because -columnproxy could be ""
747			if {$x ne [$w cget -columnproxy]} {
748			    $w configure -columnproxy $x
749			}
750		    } else {
751			if {($x1 + $width - 1) ne [$w cget -columnproxy]} {
752			    $w configure -columnproxy [expr {$x1 + $width - 1}]
753			}
754		    }
755		}
756		realtime {
757		    if {[$w column cget $Priv(column) -width] != $width} {
758			$w column configure $Priv(column) -width $width
759		    }
760		}
761	    }
762	}
763    }
764    return
765}
766
767# ::TreeCtrl::Leave1 --
768#
769# Handle <Button1-Leave> event.
770#
771# Arguments:
772# w		The treectrl widget.
773# x		Window x coord.
774# y		Window y coord.
775
776proc ::TreeCtrl::Leave1 {w x y} {
777    variable Priv
778    if {![info exists Priv(buttonMode)]} return
779    switch $Priv(buttonMode) {
780	header {
781	    if {[$w column cget $Priv(column) -state] eq "pressed"} {
782		$w column configure $Priv(column) -state normal
783	    }
784	}
785    }
786    return
787}
788
789# ::TreeCtrl::Enter1 --
790#
791# Handle <Button1-Enter> event.
792#
793# Arguments:
794# w		The treectrl widget.
795# x		Window x coord.
796# y		Window y coord.
797
798proc ::TreeCtrl::Enter1 {w x y} {
799    variable Priv
800    if {![info exists Priv(buttonMode)]} return
801    switch $Priv(buttonMode) {
802	default {}
803    }
804    return
805}
806
807# ::TreeCtrl::Release1 --
808#
809# Handle <ButtonRelease-1> event.
810#
811# Arguments:
812# w		The treectrl widget.
813# x		Window x coord.
814# y		Window y coord.
815
816proc ::TreeCtrl::Release1 {w x y} {
817    variable Priv
818    if {![info exists Priv(buttonMode)]} return
819    switch $Priv(buttonMode) {
820	header {
821	    if {[$w column cget $Priv(column) -state] eq "pressed"} {
822		$w column configure $Priv(column) -state active
823		TryEvent $w Header invoke [list C $Priv(column)]
824	    }
825	}
826	dragColumn {
827	    AutoScanCancel $w
828	    $w column configure $Priv(column) -state normal
829	    if {[$w column dragcget -imagecolumn] ne ""} {
830		set visible 1
831	    } else {
832		set visible 0
833	    }
834	    set column [$w column dragcget -indicatorcolumn]
835	    $w column dragconfigure -imagecolumn "" -indicatorcolumn ""
836	    if {$visible && ($column ne "")} {
837		set side [$w column dragcget -indicatorside]
838		if {$side eq "right"} {
839		    set column [$w column id "$column next visible"]
840		}
841		TryEvent $w ColumnDrag receive [list C $Priv(column) b $column]
842	    }
843	    set id [$w identify $x $y]
844	    if {[lindex $id 0] eq "header"} {
845		set column [lindex $id 1]
846		if {($column ne "") && [$w column compare $column != "tail"]} {
847		    if {[$w column cget $column -button]} {
848			$w column configure $column -state active
849		    }
850		}
851	    }
852	    TryEvent $w ColumnDrag end [list C $Priv(column)]
853	}
854	normal {
855	    AutoScanCancel $w
856	    set nearest [$w item id [list nearest $x $y]]
857	    if {$nearest ne ""} {
858		$w activate $nearest
859	    }
860set Priv(prev) ""
861	}
862	resize {
863	    if {[$w cget -columnproxy] ne ""} {
864		scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2
865		if {[ColumnCanResizeLeft $w $Priv(column)]} {
866		    set width [expr {$x2 - [$w cget -columnproxy]}]
867		} else {
868		    set width [expr {[$w cget -columnproxy] - $x1 + 1}]
869		}
870		$w configure -columnproxy {}
871		$w column configure $Priv(column) -width $width
872	    }
873	    CursorCheck $w $x $y
874	}
875    }
876    unset Priv(buttonMode)
877    return
878}
879
880# ::TreeCtrl::BeginSelect --
881#
882# This procedure is typically invoked on button-1 presses.  It begins
883# the process of making a selection in the treectrl.  Its exact behavior
884# depends on the selection mode currently in effect for the treectrl.
885#
886# Arguments:
887# w		The treectrl widget.
888# item		The item for the selection operation (typically the
889#		one under the pointer).
890
891proc ::TreeCtrl::BeginSelect {w item} {
892    variable Priv
893    if {$item eq ""} return
894    if {[string equal [$w cget -selectmode] "multiple"]} {
895	if {[$w selection includes $item]} {
896	    $w selection clear $item
897	} else {
898	    $w selection add $item
899	}
900    } else {
901	$w selection anchor $item
902	$w selection modify $item all
903	set Priv(selection) {}
904	set Priv(prev) $item
905    }
906    return
907}
908
909# ::TreeCtrl::SelectionMotion --
910#
911# This procedure is called to process mouse motion events while
912# button 1 is down.  It may move or extend the selection, depending
913# on the treectrl's selection mode.
914#
915# Arguments:
916# w		The treectrl widget.
917# item-		The item under the pointer.
918
919proc ::TreeCtrl::SelectionMotion {w item} {
920    variable Priv
921
922    if {$item eq ""} return
923    if {$item eq $Priv(prev)} return
924    if {![$w item enabled $item]} return
925
926    switch [$w cget -selectmode] {
927	browse {
928	    $w selection modify $item all
929	    set Priv(prev) $item
930	}
931	extended {
932	    set i $Priv(prev)
933	    set select {}
934	    set deselect {}
935	    if {$i eq ""} {
936		set i $item
937		lappend select $item
938		set hack [$w item compare $item == anchor]
939	    } else {
940		set hack 0
941	    }
942	    if {[$w selection includes anchor] || $hack} {
943		set deselect [concat $deselect [$w item range $i $item]]
944		set select [concat $select [$w item range anchor $item]]
945	    } else {
946		set deselect [concat $deselect [$w item range $i $item]]
947		set deselect [concat $deselect [$w item range anchor $item]]
948	    }
949	    if {![info exists Priv(selection)]} {
950		set Priv(selection) [$w selection get]
951	    }
952	    while {[$w item compare $i < $item] && [$w item compare $i < anchor]} {
953		if {[lsearch $Priv(selection) $i] >= 0} {
954		    lappend select $i
955		}
956		set i [$w item id "$i next visible"]
957	    }
958	    while {[$w item compare $i > $item] && [$w item compare $i > anchor]} {
959		if {[lsearch $Priv(selection) $i] >= 0} {
960		    lappend select $i
961		}
962		set i [$w item id "$i prev visible"]
963	    }
964	    set Priv(prev) $item
965	    $w selection modify $select $deselect
966	}
967    }
968    return
969}
970
971# ::TreeCtrl::BeginExtend --
972#
973# This procedure is typically invoked on shift-button-1 presses.  It
974# begins the process of extending a selection in the treectrl.  Its
975# exact behavior depends on the selection mode currently in effect
976# for the treectrl.
977#
978# Arguments:
979# w		The treectrl widget.
980# item-		The item for the selection operation (typically the
981#		one under the pointer).
982
983proc ::TreeCtrl::BeginExtend {w item} {
984    if {[string equal [$w cget -selectmode] "extended"]} {
985	if {[$w selection includes anchor]} {
986	    SelectionMotion $w $item
987	} else {
988	    # No selection yet; simulate the begin-select operation.
989	    BeginSelect $w $item
990	}
991    }
992    return
993}
994
995# ::TreeCtrl::BeginToggle --
996#
997# This procedure is typically invoked on control-button-1 presses.  It
998# begins the process of toggling a selection in the treectrl.  Its
999# exact behavior depends on the selection mode currently in effect
1000# for the treectrl.
1001#
1002# Arguments:
1003# w		The treectrl widget.
1004# item		The item for the selection operation (typically the
1005#		one under the pointer).
1006
1007proc ::TreeCtrl::BeginToggle {w item} {
1008    variable Priv
1009    if {$item eq ""} return
1010    if {[string equal [$w cget -selectmode] "extended"]} {
1011	set Priv(selection) [$w selection get]
1012	set Priv(prev) $item
1013	$w selection anchor $item
1014	if {[$w selection includes $item]} {
1015	    $w selection clear $item
1016	} else {
1017	    $w selection add $item
1018	}
1019    }
1020    return
1021}
1022
1023# ::TreeCtrl::AutoScanCheck --
1024#
1025# Sees if the given pointer coords are outside the content area of the
1026# treectrl (ie, not including borders or column headers) or within
1027# -scrollmargin distance of the edges of the content area. If so and
1028# auto-scanning is not already in progress, then the window is scrolled
1029# and an [after] callback to AutoScanCheckAux is scheduled.
1030#
1031# Arguments:
1032# w		The treectrl widget.
1033# x		Window x coord.
1034# y		Window y coord.
1035
1036proc ::TreeCtrl::AutoScanCheck {w x y} {
1037    variable Priv
1038    scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2
1039    set margin [winfo pixels $w [$w cget -scrollmargin]]
1040    if {![info exists Priv(autoscan,direction,$w)]} {
1041	set Priv(autoscan,direction,$w) xy
1042    }
1043    set scrollX [string match *x* $Priv(autoscan,direction,$w)]
1044    set scrollY [string match *y* $Priv(autoscan,direction,$w)]
1045    if {($scrollX && (($x < $x1 + $margin) || ($x >= $x2 - $margin))) ||
1046	($scrollY && (($y < $y1 + $margin) || ($y >= $y2 - $margin)))} {
1047	if {[info exists Priv(autoscan,afterId,$w)]} return
1048	if {$scrollY && $y >= $y2 - $margin} {
1049	    $w yview scroll 1 units
1050	    set delay [$w cget -yscrolldelay]
1051	} elseif {$scrollY && $y < $y1 + $margin} {
1052	    $w yview scroll -1 units
1053	    set delay [$w cget -yscrolldelay]
1054	} elseif {$scrollX && $x >= $x2 - $margin} {
1055	    $w xview scroll 1 units
1056	    set delay [$w cget -xscrolldelay]
1057	} elseif {$scrollX && $x < $x1 + $margin} {
1058	    $w xview scroll -1 units
1059	    set delay [$w cget -xscrolldelay]
1060	}
1061	set count [scan $delay "%d %d" d1 d2]
1062	if {[info exists Priv(autoscan,scanning,$w)]} {
1063	    if {$count == 2} {
1064		set delay $d2
1065	    }
1066	} else {
1067	    if {$count == 2} {
1068		set delay $d1
1069	    }
1070	    set Priv(autoscan,scanning,$w) 1
1071	}
1072	if {$Priv(autoscan,command,$w) ne ""} {
1073	    set command [string map [list %T $w %x $x %y $y] $Priv(autoscan,command,$w)]
1074	    eval $command
1075	}
1076	set Priv(autoscan,afterId,$w) [after $delay [list TreeCtrl::AutoScanCheckAux $w]]
1077	return
1078    }
1079    AutoScanCancel $w
1080    return
1081}
1082
1083# ::TreeCtrl::AutoScanCheckAux --
1084#
1085# Gets the location of the pointer and calls AutoScanCheck.
1086#
1087# Arguments:
1088# w		The treectrl widget.
1089
1090proc ::TreeCtrl::AutoScanCheckAux {w} {
1091    variable Priv
1092    # Not quite sure how this can happen
1093    if {![info exists Priv(autoscan,afterId,$w)]} return
1094    unset Priv(autoscan,afterId,$w)
1095    set x [winfo pointerx $w]
1096    set y [winfo pointery $w]
1097    set x [expr {$x - [winfo rootx $w]}]
1098    set y [expr {$y - [winfo rooty $w]}]
1099    AutoScanCheck $w $x $y
1100    return
1101}
1102
1103# ::TreeCtrl::AutoScanCancel --
1104#
1105# Cancels any pending [after] callback to AutoScanCheckAux.
1106#
1107# Arguments:
1108# w		The treectrl widget.
1109
1110proc ::TreeCtrl::AutoScanCancel {w} {
1111    variable Priv
1112    if {[info exists Priv(autoscan,afterId,$w)]} {
1113	after cancel $Priv(autoscan,afterId,$w)
1114	unset Priv(autoscan,afterId,$w)
1115    }
1116    unset -nocomplain Priv(autoscan,scanning,$w)
1117    return
1118}
1119
1120# ::TreeCtrl::ColumnDragScrollCheck --
1121#
1122# Sees if the given pointer coords are outside the left or right edges of
1123# the content area of the treectrl (ie, not including borders). If so and
1124# auto-scanning is not already in progress, then the window is scrolled
1125# horizontally and the column drag-image is repositioned, and an [after]
1126# callback to ColumnDragScrollCheckAux is scheduled.
1127#
1128# Arguments:
1129# w		The treectrl widget.
1130# x		Window coord of pointer.
1131# y		Window coord of pointer.
1132
1133proc ::TreeCtrl::ColumnDragScrollCheck {w x y} {
1134    variable Priv
1135
1136# BUG 2355369
1137#    scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2
1138    scan [ColumnsBbox $w content] "%d %d %d %d" x1 y1 x2 y2
1139
1140    if {($x < $x1) || ($x >= $x2)} {
1141	if {![info exists Priv(autoscan,afterId,$w)]} {
1142	    set bbox1 [$w column bbox $Priv(column)]
1143	    if {$x >= $x2} {
1144		$w xview scroll 1 units
1145	    } else {
1146		$w xview scroll -1 units
1147	    }
1148	    set bbox2 [$w column bbox $Priv(column)]
1149	    if {[lindex $bbox1 0] != [lindex $bbox2 0]} {
1150		incr Priv(columnDrag,x) [expr {[lindex $bbox2 0] - [lindex $bbox1 0]}]
1151		$w column dragconfigure -imageoffset [expr {$x - $Priv(columnDrag,x)}]
1152
1153		if {[ColumnDragFindBefore $w $x $Priv(columnDrag,y) $Priv(column) indColumn indSide]} {
1154		    $w column dragconfigure -indicatorcolumn $indColumn \
1155			-indicatorside $indSide
1156		} else {
1157		    $w column dragconfigure -indicatorcolumn ""
1158		}
1159	    }
1160	    set Priv(autoscan,afterId,$w) [after 50 [list TreeCtrl::ColumnDragScrollCheckAux $w]]
1161	}
1162	return
1163    }
1164    AutoScanCancel $w
1165    return
1166}
1167
1168# ::TreeCtrl::ColumnDragScrollCheckAux --
1169#
1170# Gets the location of the pointer and calls ColumnDragScrollCheck.
1171#
1172# Arguments:
1173# w		The treectrl widget.
1174
1175proc ::TreeCtrl::ColumnDragScrollCheckAux {w} {
1176    variable Priv
1177    # Not quite sure how this can happen
1178    if {![info exists Priv(autoscan,afterId,$w)]} return
1179    unset Priv(autoscan,afterId,$w)
1180    set x [winfo pointerx $w]
1181    set y [winfo pointery $w]
1182    set x [expr {$x - [winfo rootx $w]}]
1183    set y [expr {$y - [winfo rooty $w]}]
1184    ColumnDragScrollCheck $w $x $y
1185    return
1186}
1187
1188# ::TreeCtrl::UpDown --
1189#
1190# Returns the id of an item above or below the given item that the active
1191# item could be set to. If the given item isn't visible, the first visible
1192# enabled item is returned. An attempt is made to choose an item in the
1193# same column over repeat calls; this gives a better result if some rows
1194# have less items than others. Only enabled items are considered.
1195#
1196# Arguments:
1197# w		The treectrl widget.
1198# item		Item to move from, typically the active item.
1199# n		+1 to move down, -1 to move up.
1200
1201proc ::TreeCtrl::UpDown {w item n} {
1202    variable Priv
1203    set rnc [$w item rnc $item]
1204    if {$rnc eq ""} {
1205	return [$w item id {first visible state enabled}]
1206    }
1207    scan $rnc "%d %d" row col
1208    set Priv(keyNav,row,$w) [expr {$row + $n}]
1209    if {![info exists Priv(keyNav,rnc,$w)] || $rnc ne $Priv(keyNav,rnc,$w)} {
1210	set Priv(keyNav,col,$w) $col
1211    }
1212    set item2 [$w item id "rnc $Priv(keyNav,row,$w) $Priv(keyNav,col,$w)"]
1213    if {[$w item compare $item == $item2]} {
1214	set Priv(keyNav,row,$w) $row
1215	if {![$w item enabled $item2]} {
1216	    return ""
1217	}
1218    } else {
1219	set Priv(keyNav,rnc,$w) [$w item rnc $item2]
1220	if {![$w item enabled $item2]} {
1221	    return [UpDown $w $item2 $n]
1222	}
1223    }
1224    return $item2
1225}
1226
1227# ::TreeCtrl::LeftRight --
1228#
1229# Returns the id of an item left or right of the given item that the active
1230# item could be set to. If the given item isn't visible, the first visible
1231# enabled item is returned. An attempt is made to choose an item in the
1232# same row over repeat calls; this gives a better result if some columns
1233# have less items than others. Only enabled items are considered.
1234#
1235# Arguments:
1236# w		The treectrl widget.
1237# item		Item to move from, typically the active item.
1238# n		+1 to move right, -1 to move left.
1239
1240proc ::TreeCtrl::LeftRight {w item n} {
1241    variable Priv
1242    set rnc [$w item rnc $item]
1243    if {$rnc eq ""} {
1244	return [$w item id {first visible state enabled}]
1245    }
1246    scan $rnc "%d %d" row col
1247    set Priv(keyNav,col,$w) [expr {$col + $n}]
1248    if {![info exists Priv(keyNav,rnc,$w)] || $rnc ne $Priv(keyNav,rnc,$w)} {
1249	set Priv(keyNav,row,$w) $row
1250    }
1251    set item2 [$w item id "rnc $Priv(keyNav,row,$w) $Priv(keyNav,col,$w)"]
1252    if {[$w item compare $item == $item2]} {
1253	set Priv(keyNav,col,$w) $col
1254	if {![$w item enabled $item2]} {
1255	    return ""
1256	}
1257    } else {
1258	set Priv(keyNav,rnc,$w) [$w item rnc $item2]
1259	if {![$w item enabled $item2]} {
1260	    return [LeftRight $w $item2 $n]
1261	}
1262    }
1263    return $item2
1264}
1265
1266# ::TreeCtrl::SetActiveItem --
1267#
1268# Sets the active item, scrolls it into view, and makes it the only selected
1269# item. If -selectmode is extended, makes the active item the anchor of any
1270# future extended selection.
1271#
1272# Arguments:
1273# w		The treectrl widget.
1274# item		The new active item, or "".
1275
1276proc ::TreeCtrl::SetActiveItem {w item} {
1277    if {$item eq ""} return
1278    $w activate $item
1279    $w see active
1280    $w selection modify active all
1281    switch [$w cget -selectmode] {
1282	extended {
1283	    $w selection anchor active
1284	    set Priv(prev) [$w item id active]
1285	    set Priv(selection) {}
1286	}
1287    }
1288    return
1289}
1290
1291# ::TreeCtrl::Extend --
1292#
1293# Does nothing unless we're in extended selection mode;  in this
1294# case it moves the location cursor (active item) up, down, left or
1295# right, and extends the selection to that point.
1296#
1297# Arguments:
1298# w		The treectrl widget.
1299# dir		up, down, left or right
1300
1301proc ::TreeCtrl::Extend {w dir} {
1302    variable Priv
1303    if {[string compare [$w cget -selectmode] "extended"]} {
1304	return
1305    }
1306    if {![info exists Priv(selection)]} {
1307	$w selection add active
1308	set Priv(selection) [$w selection get]
1309    }
1310    switch -- $dir {
1311	above { set item [UpDown $w active -1] }
1312	below { set item [UpDown $w active 1] }
1313	left { set item [LeftRight $w active -1] }
1314	right { set item [LeftRight $w active 1] }
1315    }
1316    if {$item eq ""} return
1317    $w activate $item
1318    $w see active
1319    SelectionMotion $w [$w item id active]
1320    return
1321}
1322
1323# ::TreeCtrl::DataExtend
1324#
1325# This procedure is called for key-presses such as Shift-KEndData.
1326# If the selection mode isn't multiple or extended then it does nothing.
1327# Otherwise it moves the active item and, if we're in
1328# extended mode, extends the selection to that point.
1329#
1330# Arguments:
1331# w		The treectrl widget.
1332# item		Item to become new active item.
1333
1334proc ::TreeCtrl::DataExtend {w item} {
1335    if {$item eq ""} return
1336    set mode [$w cget -selectmode]
1337    if {[string equal $mode "extended"]} {
1338	$w activate $item
1339	$w see $item
1340        if {[$w selection includes anchor]} {
1341	    SelectionMotion $w $item
1342	}
1343    } elseif {[string equal $mode "multiple"]} {
1344	$w activate $item
1345	$w see $item
1346    }
1347    return
1348}
1349
1350# ::TreeCtrl::Cancel
1351#
1352# This procedure is invoked to cancel an extended selection in
1353# progress.  If there is an extended selection in progress, it
1354# restores all of the items between the active one and the anchor
1355# to their previous selection state.
1356#
1357# Arguments:
1358# w		The treectrl widget.
1359
1360proc ::TreeCtrl::Cancel w {
1361    variable Priv
1362    if {[string compare [$w cget -selectmode] "extended"]} {
1363	return
1364    }
1365    set first [$w item id anchor]
1366    set last $Priv(prev)
1367    if { [string equal $last ""] } {
1368	# Not actually doing any selection right now
1369	return
1370    }
1371    if {[$w item compare $first > $last]} {
1372	set tmp $first
1373	set first $last
1374	set last $tmp
1375    }
1376    $w selection clear $first $last
1377    while {[$w item compare $first <= $last]} {
1378	if {[lsearch $Priv(selection) $first] >= 0} {
1379	    $w selection add $first
1380	}
1381	set first [$w item id "$first next visible"]
1382    }
1383    return
1384}
1385
1386# ::TreeCtrl::SelectAll
1387#
1388# This procedure is invoked to handle the "select all" operation.
1389# For single and browse mode, it just selects the active item.
1390# Otherwise it selects everything in the widget.
1391#
1392# Arguments:
1393# w		The treectrl widget.
1394
1395proc ::TreeCtrl::SelectAll w {
1396    set mode [$w cget -selectmode]
1397    if {[string equal $mode "single"] || [string equal $mode "browse"]} {
1398	$w selection modify active all
1399    } else {
1400	$w selection add all
1401    }
1402    return
1403}
1404
1405# ::TreeCtrl::MarqueeBegin --
1406#
1407# Shows the selection rectangle at the given coords.
1408#
1409# Arguments:
1410# w		The treectrl widget.
1411# x		Window coord of pointer.
1412# y		Window coord of pointer.
1413
1414proc ::TreeCtrl::MarqueeBegin {w x y} {
1415    set x [$w canvasx $x]
1416    set y [$w canvasy $y]
1417    $w marquee coords $x $y $x $y
1418    $w marquee configure -visible yes
1419    return
1420}
1421
1422# ::TreeCtrl::MarqueeUpdate --
1423#
1424# Resizes the selection rectangle.
1425#
1426# Arguments:
1427# w		The treectrl widget.
1428# x		Window coord of pointer.
1429# y		Window coord of pointer.
1430
1431proc ::TreeCtrl::MarqueeUpdate {w x y} {
1432    set x [$w canvasx $x]
1433    set y [$w canvasy $y]
1434    $w marquee corner $x $y
1435    return
1436}
1437
1438# ::TreeCtrl::MarqueeEnd --
1439#
1440# Hides the selection rectangle.
1441#
1442# Arguments:
1443# w		The treectrl widget.
1444# x		Window coord of pointer.
1445# y		Window coord of pointer.
1446
1447proc ::TreeCtrl::MarqueeEnd {w x y} {
1448    $w marquee configure -visible no
1449    return
1450}
1451
1452# ::TreeCtrl::ScanMark --
1453#
1454# Marks the start of a possible scan drag operation.
1455#
1456# Arguments:
1457# w		The treectrl widget.
1458# x		Window coord of pointer.
1459# y		Window coord of pointer.
1460
1461proc ::TreeCtrl::ScanMark {w x y} {
1462    variable Priv
1463    $w scan mark $x $y
1464    set Priv(x) $x
1465    set Priv(y) $y
1466    set Priv(mouseMoved) 0
1467    return
1468}
1469
1470# ::TreeCtrl::ScanDrag --
1471#
1472# Performs a scan drag if the mouse moved.
1473#
1474# Arguments:
1475# w		The treectrl widget.
1476# x		Window coord of pointer.
1477# y		Window coord of pointer.
1478
1479proc ::TreeCtrl::ScanDrag {w x y} {
1480    variable Priv
1481    if {![info exists Priv(x)]} { set Priv(x) $x }
1482    if {![info exists Priv(y)]} { set Priv(y) $y }
1483    if {($x != $Priv(x)) || ($y != $Priv(y))} {
1484	set Priv(mouseMoved) 1
1485    }
1486    if {[info exists Priv(mouseMoved)] && $Priv(mouseMoved)} {
1487	$w scan dragto $x $y
1488    }
1489    return
1490}
1491
1492# ::TreeCtrl::TryEvent --
1493#
1494# This procedure is used to cause a treectrl to generate a dynamic event.
1495# If the treectrl doesn't have the event defined (because you didn't call
1496# the [notify install] command) nothing happens. TreeCtrl::PercentsCmd is
1497# used to perform %-substitution on any scripts bound to the event.
1498#
1499# Arguments:
1500# T		The treectrl widget.
1501# event		Name of event.
1502# detail	Name of detail or "".
1503# charMap	%-char substitution list (even number of elements).
1504
1505proc ::TreeCtrl::TryEvent {T event detail charMap} {
1506    if {[lsearch -exact [$T notify eventnames] $event] == -1} return
1507    if {$detail ne ""} {
1508	if {[lsearch -exact [$T notify detailnames $event] $detail] == -1} return
1509	$T notify generate <$event-$detail> $charMap "::TreeCtrl::PercentsCmd $T"
1510    } else {
1511	$T notify generate <$event> $charMap "::TreeCtrl::PercentsCmd $T"
1512    }
1513    return
1514}
1515
1516# ::TreeCtrl::PercentsCmd --
1517#
1518# This command is passed to [notify generate] to perform %-substitution on
1519# scripts bound to dynamic events. It supports the same set of substitution
1520# characters as the built-in static events (plus any event-specific chars).
1521#
1522# Arguments:
1523# T		The treectrl widget.
1524# char		%-char to be replaced in bound scripts.
1525# object	Same arg passed to [notify bind].
1526# event		Name of event.
1527# detail	Name of detail or "".
1528# charMap	%-char substitution list (even number of elements).
1529
1530proc ::TreeCtrl::PercentsCmd {T char object event detail charMap} {
1531    if {$detail ne ""} {
1532	set pattern <$event-$detail>
1533    } else {
1534	set pattern <$event>
1535    }
1536    switch -- $char {
1537	d { return $detail }
1538	e { return $event }
1539	P { return $pattern }
1540	W { return $object }
1541	T { return $T }
1542	? {
1543	    array set map $charMap
1544	    array set map [list T $T W $object P $pattern e $event d $detail]
1545	    return [array get map]
1546	}
1547	default {
1548	    array set map [list $char $char]
1549	    array set map $charMap
1550	    return $map($char)
1551	}
1552    }
1553    return
1554}
1555
1556namespace eval TreeCtrl {
1557catch {
1558    foreach theme [ttk::style theme names] {
1559	ttk::style theme settings $theme {
1560	    ttk::style configure TreeCtrlHeading -relief raised -font TkHeadingFont
1561	    ttk::style map TreeCtrlHeading -relief {
1562		pressed sunken
1563	    }
1564	}
1565    }
1566}
1567}
1568