1# RCS: @(#) $Id: filelist-bindings.tcl,v 1.28 2010/03/21 20:47:06 treectrl Exp $
2
3bind TreeCtrlFileList <Double-ButtonPress-1> {
4    TreeCtrl::FileListEditCancel %W
5    TreeCtrl::DoubleButton1 %W %x %y
6    break
7}
8bind TreeCtrlFileList <Control-ButtonPress-1> {
9    set TreeCtrl::Priv(selectMode) toggle
10    TreeCtrl::FileListButton1 %W %x %y
11    break
12}
13bind TreeCtrlFileList <Shift-ButtonPress-1> {
14    set TreeCtrl::Priv(selectMode) add
15    TreeCtrl::FileListButton1 %W %x %y
16    break
17}
18bind TreeCtrlFileList <ButtonPress-1> {
19    set TreeCtrl::Priv(selectMode) set
20    TreeCtrl::FileListButton1 %W %x %y
21    break
22}
23bind TreeCtrlFileList <Button1-Motion> {
24    TreeCtrl::FileListMotion1 %W %x %y
25    break
26}
27bind TreeCtrlFileList <Button1-Leave> {
28    TreeCtrl::FileListLeave1 %W %x %y
29    break
30}
31bind TreeCtrlFileList <ButtonRelease-1> {
32    TreeCtrl::FileListRelease1 %W %x %y
33    break
34}
35
36## Bindings for the Entry widget used for editing
37
38# Accept edit when we lose the focus
39bind TreeCtrlEntry <FocusOut> {
40    if {[winfo ismapped %W]} {
41	TreeCtrl::EditClose [winfo parent %W] entry 1 0
42    }
43}
44
45# Accept edit on <Return>
46bind TreeCtrlEntry <KeyPress-Return> {
47    TreeCtrl::EditClose [winfo parent %W] entry 1 1
48    break
49}
50
51# Cancel edit on <Escape>, use break as we are doing a "closing" action
52# and don't want that propagated upwards
53bind TreeCtrlEntry <KeyPress-Escape> {
54    TreeCtrl::EditClose [winfo parent %W] entry 0 1
55    break
56}
57
58## Bindings for the Text widget used for editing
59
60# Accept edit when we lose the focus
61bind TreeCtrlText <FocusOut> {
62    if {[winfo ismapped %W]} {
63	TreeCtrl::EditClose [winfo parent %W] text 1 0
64    }
65}
66
67# Accept edit on <Return>
68bind TreeCtrlText <KeyPress-Return> {
69    TreeCtrl::EditClose [winfo parent %W] text 1 1
70    break
71}
72
73# Cancel edit on <Escape>, use break as we are doing a "closing" action
74# and don't want that propagated upwards
75bind TreeCtrlText <KeyPress-Escape> {
76    TreeCtrl::EditClose [winfo parent %W] text 0 1
77    break
78}
79
80namespace eval TreeCtrl {
81    variable Priv
82
83    # Number of milliseconds after clicking a selected item before the Edit
84    # widget appears.
85    set Priv(edit,delay) 500
86
87    # Try to deal with people importing ttk::entry into the global namespace;
88    # we want tk::entry
89    if {[llength [info commands ::tk::entry]]} {
90	set Priv(entryCmd) ::tk::entry
91    } else {
92	set Priv(entryCmd) ::entry
93    }
94}
95
96# ::TreeCtrl::IsSensitive
97#
98# Returns 1 if the given window coordinates are over an element that should
99# respond to mouse clicks.  The list of elements that respond to mouse clicks
100# is set by calling ::TreeCtrl::SetSensitive.
101#
102# Arguments:
103# T		The treectrl widget.
104# x		Window coord of pointer.
105# y		Window coord of pointer.
106
107proc ::TreeCtrl::IsSensitive {T x y} {
108    variable Priv
109    set id [$T identify $x $y]
110    if {[lindex $id 0] ne "item" || [llength $id] != 6} {
111	return 0
112    }
113    lassign $id where item arg1 arg2 arg3 arg4
114    if {![$T item enabled $item]} {
115	return 0
116    }
117    foreach list $Priv(sensitive,$T) {
118	set eList [lassign $list C S]
119	if {[$T column compare $arg2 != $C]} continue
120	if {[$T item style set $item $C] ne $S} continue
121	if {[lsearch -exact $eList $arg4] == -1} continue
122	return 1
123    }
124    return 0
125}
126
127# ::TreeCtrl::FileListButton1
128#
129# Handle <ButtonPress-1>.
130#
131# Arguments:
132# T		The treectrl widget.
133# x		Window coord of pointer.
134# y		Window coord of pointer.
135
136proc ::TreeCtrl::FileListButton1 {T x y} {
137    variable Priv
138    focus $T
139    set id [$T identify $x $y]
140    set marquee 0
141    set Priv(buttonMode) ""
142    foreach e {text entry} {
143	if {[winfo exists $T.$e] && [winfo ismapped $T.$e]} {
144	    EditClose $T $e 1 0
145	}
146    }
147    FileListEditCancel $T
148    # Click outside any item
149    if {$id eq ""} {
150	set marquee 1
151
152    # Click in header
153    } elseif {[lindex $id 0] eq "header"} {
154	ButtonPress1 $T $x $y
155
156    # Click in item
157    } else {
158	lassign $id where item arg1 arg2 arg3 arg4
159	switch $arg1 {
160	    button -
161	    line {
162		ButtonPress1 $T $x $y
163	    }
164	    column {
165		if {[IsSensitive $T $x $y]} {
166		    set Priv(drag,motion) 0
167		    set Priv(drag,click,x) $x
168		    set Priv(drag,click,y) $y
169		    set Priv(drag,x) [$T canvasx $x]
170		    set Priv(drag,y) [$T canvasy $y]
171		    set Priv(drop) ""
172		    set Priv(drag,wasSel) [$T selection includes $item]
173		    set Priv(drag,C) $arg2
174		    set Priv(drag,E) $arg4
175		    $T activate $item
176		    if {$Priv(selectMode) eq "add"} {
177			BeginExtend $T $item
178		    } elseif {$Priv(selectMode) eq "toggle"} {
179			BeginToggle $T $item
180		    } elseif {![$T selection includes $item]} {
181			BeginSelect $T $item
182		    }
183
184		    # Changing the selection might change the list
185		    if {[$T item id $item] eq ""} return
186
187		    # Click selected item to drag
188		    if {[$T selection includes $item]} {
189			set Priv(buttonMode) drag
190		    }
191		} else {
192		    set marquee 1
193		}
194	    }
195	}
196    }
197    if {$marquee} {
198	set Priv(buttonMode) marquee
199	if {$Priv(selectMode) ne "set"} {
200	    set Priv(selection) [$T selection get]
201	} else {
202	    $T selection clear
203	    set Priv(selection) {}
204	}
205	MarqueeBegin $T $x $y
206    }
207    return
208}
209
210# ::TreeCtrl::FileListMotion1
211#
212# Override default <Button1-Motion> to handle "drag" and "marquee".
213#
214# Arguments:
215# T		The treectrl widget.
216# x		Window coord of pointer.
217# y		Window coord of pointer.
218
219proc ::TreeCtrl::FileListMotion1 {T x y} {
220    variable Priv
221    if {![info exists Priv(buttonMode)]} return
222    switch $Priv(buttonMode) {
223	"drag" -
224	"marquee" {
225	    set Priv(autoscan,command,$T) {FileListMotion %T %x %y}
226	    AutoScanCheck $T $x $y
227	    FileListMotion $T $x $y
228	}
229	default {
230	    Motion1 $T $x $y
231	}
232    }
233    return
234}
235
236# ::TreeCtrl::FileListMotion
237#
238# Handle <Button1-Motion>.
239#
240# Arguments:
241# T		The treectrl widget.
242# x		Window coord of pointer.
243# y		Window coord of pointer.
244
245proc ::TreeCtrl::FileListMotion {T x y} {
246    variable Priv
247    if {![info exists Priv(buttonMode)]} return
248    switch $Priv(buttonMode) {
249	"marquee" {
250	    MarqueeUpdate $T $x $y
251	    set select $Priv(selection)
252	    set deselect {}
253
254	    # Check items covered by the marquee
255	    foreach list [$T marque identify] {
256		set item [lindex $list 0]
257		if {![$T item enabled $item]} continue
258
259		# Check covered columns in this item
260		foreach sublist [lrange $list 1 end] {
261		    set column [lindex $sublist 0]
262		    set ok 0
263
264		    # Check covered elements in this column
265		    foreach E [lrange $sublist 1 end] {
266			foreach sList $Priv(sensitive,$T) {
267			    set sEList [lassign $sList sC sS]
268			    if {[$T column compare $column != $sC]} continue
269			    if {[$T item style set $item $sC] ne $sS} continue
270			    if {[lsearch -exact $sEList $E] == -1} continue
271			    set ok 1
272			    break
273			}
274		    }
275		    # Some sensitive elements in this column are covered
276		    if {$ok} {
277
278			# Toggle selected status
279			if {$Priv(selectMode) eq "toggle"} {
280			    set i [lsearch -exact $Priv(selection) $item]
281			    if {$i == -1} {
282				lappend select $item
283			    } else {
284				set i [lsearch -exact $select $item]
285				set select [lreplace $select $i $i]
286			    }
287			} else {
288			    lappend select $item
289			}
290		    }
291		}
292	    }
293	    $T selection modify $select all
294	}
295	"drag" {
296	    if {!$Priv(drag,motion)} {
297		# Detect initial mouse movement
298		if {(abs($x - $Priv(drag,click,x)) <= 4) &&
299		    (abs($y - $Priv(drag,click,y)) <= 4)} return
300
301		set Priv(selection) [$T selection get]
302		set Priv(drop) ""
303		$T dragimage clear
304		# For each selected item, add some elements to the dragimage
305		foreach I $Priv(selection) {
306		    foreach list $Priv(dragimage,$T) {
307			set EList [lassign $list C S]
308			if {[$T item style set $I $C] eq $S} {
309			    eval $T dragimage add $I $C $EList
310			}
311		    }
312		}
313		set Priv(drag,motion) 1
314		TryEvent $T Drag begin {}
315	    }
316
317	    # Find the element under the cursor
318	    set drop ""
319	    set id [$T identify $x $y]
320	    if {[IsSensitive $T $x $y]} {
321		set item [lindex $id 1]
322		# If the item is not in the pre-drag selection
323		# (i.e. not being dragged) and it is a directory,
324		# see if we can drop on it
325		if {[lsearch -exact $Priv(selection) $item] == -1} {
326		    if {[$T item order $item -visible] < $Priv(DirCnt,$T)} {
327			set drop $item
328			# We can drop if dragged item isn't an ancestor
329			foreach item2 $Priv(selection) {
330			    if {[$T item isancestor $item2 $item]} {
331				set drop ""
332				break
333			    }
334			}
335		    }
336		}
337	    }
338
339	    # Select the directory under the cursor (if any) and deselect
340	    # the previous drop-directory (if any)
341	    $T selection modify $drop $Priv(drop)
342	    set Priv(drop) $drop
343
344	    # Show the dragimage in its new position
345if {0 && [$T dragimage cget -style] ne ""} {
346    set x [$T canvasx $x]
347    set y [$T canvasy $y]
348} else {
349	    set x [expr {[$T canvasx $x] - $Priv(drag,x)}]
350	    set y [expr {[$T canvasy $y] - $Priv(drag,y)}]
351}
352	    $T dragimage offset $x $y
353	    $T dragimage configure -visible yes
354	}
355	default {
356	    Motion1 $T $x $y
357	}
358    }
359    return
360}
361
362# ::TreeCtrl::FileListLeave1
363#
364# Handle <Button1-Leave>.
365#
366# Arguments:
367# T		The treectrl widget.
368# x		Window coord of pointer.
369# y		Window coord of pointer.
370
371proc ::TreeCtrl::FileListLeave1 {T x y} {
372    variable Priv
373    # This gets called when I click the mouse on Unix, and buttonMode is unset
374    if {![info exists Priv(buttonMode)]} return
375    switch $Priv(buttonMode) {
376	default {
377	    Leave1 $T $x $y
378	}
379    }
380    return
381}
382
383# ::TreeCtrl::FileListRelease1
384#
385# Handle <Button1-Release>.
386#
387# Arguments:
388# T		The treectrl widget.
389# x		Window coord of pointer.
390# y		Window coord of pointer.
391
392proc ::TreeCtrl::FileListRelease1 {T x y} {
393    variable Priv
394    if {![info exists Priv(buttonMode)]} return
395    switch $Priv(buttonMode) {
396	"marquee" {
397	    AutoScanCancel $T
398	    MarqueeEnd $T $x $y
399	}
400	"drag" {
401	    AutoScanCancel $T
402
403	    # Some dragging occurred
404	    if {$Priv(drag,motion)} {
405		$T dragimage configure -visible no
406		if {$Priv(drop) ne ""} {
407		    $T selection modify {} $Priv(drop)
408		    TryEvent $T Drag receive \
409			[list I $Priv(drop) l $Priv(selection)]
410		}
411		TryEvent $T Drag end {}
412	    } elseif {$Priv(selectMode) eq "toggle"} {
413		# don't rename
414
415		# Clicked/released a selected item, but didn't drag
416	    } elseif {$Priv(drag,wasSel)} {
417		set I [$T item id active]
418		set C $Priv(drag,C)
419		set E $Priv(drag,E)
420		set S [$T item style set $I $C]
421		set ok 0
422		foreach list $Priv(edit,$T) {
423		    set eEList [lassign $list eC eS]
424		    if {[$T column compare $C != $eC]} continue
425		    if {$S ne $eS} continue
426		    if {[lsearch -exact $eEList $E] == -1} continue
427		    set ok 1
428		    break
429		}
430		if {$ok} {
431		    FileListEditCancel $T
432		    set Priv(editId,$T) \
433			[after $Priv(edit,delay) [list ::TreeCtrl::FileListEdit $T $I $C $E]]
434		}
435	    }
436	}
437	default {
438	    Release1 $T $x $y
439	}
440    }
441    set Priv(buttonMode) ""
442    return
443}
444
445# ::TreeCtrl::FileListEdit
446#
447# Displays an Entry or Text widget to allow the user to edit the specified
448# text element.
449#
450# Arguments:
451# T		The treectrl widget.
452# I		Item.
453# C		Column.
454# E		Element.
455
456proc ::TreeCtrl::FileListEdit {T I C E} {
457    variable Priv
458    array unset Priv editId,$T
459
460    set lines [$T item element cget $I $C $E -lines]
461    if {$lines eq ""} {
462	set lines [$T element cget $E -lines]
463    }
464
465    # Scroll item into view
466    $T see $I ; update
467
468    # Multi-line edit
469    if {$lines ne "1"} {
470	scan [$T item bbox $I $C] "%d %d %d %d" x1 y1 x2 y2
471	set S [$T item style set $I $C]
472	set padx [$T style layout $S $E -padx]
473	if {[llength $padx] == 2} {
474	    lassign $padx padw pade
475	} else {
476	    set pade [set padw $padx]
477	}
478	foreach E2 [$T style elements $S] {
479	    if {[lsearch -exact [$T style layout $S $E2 -union] $E] == -1} continue
480	    foreach option {-padx -ipadx} {
481		set pad [$T style layout $S $E2 $option]
482		if {[llength $pad] == 2} {
483		    incr padw [lindex $pad 0]
484		    incr pade [lindex $pad 1]
485		} else {
486		    incr padw $pad
487		    incr pade $pad
488		}
489	    }
490	}
491	TextExpanderOpen $T $I $C $E [expr {$x2 - $x1 - $padw - $pade}]
492
493    # Single-line edit
494    } else {
495	EntryExpanderOpen $T $I $C $E
496    }
497
498    TryEvent $T Edit begin [list I $I C $C E $E]
499
500    return
501}
502
503# ::TreeCtrl::FileListEditCancel
504#
505# Aborts any scheduled display of the text-edit widget.
506#
507# Arguments:
508# T		The treectrl widget.
509
510proc ::TreeCtrl::FileListEditCancel {T} {
511    variable Priv
512    if {[info exists Priv(editId,$T)]} {
513	after cancel $Priv(editId,$T)
514	array unset Priv editId,$T
515    }
516    return
517}
518
519# ::TreeCtrl::SetDragImage
520#
521# Specifies the list of elements that should be added to the dragimage.
522#
523# Arguments:
524# T		The treectrl widget.
525# listOfLists	{{column style element ...} {column style element ...}}
526
527proc ::TreeCtrl::SetDragImage {T listOfLists} {
528    variable Priv
529    foreach list $listOfLists {
530	set elements [lassign $list column style]
531	if {[$T column id $column] eq ""} {
532	    error "column \"$column\" doesn't exist"
533	}
534	if {[lsearch -exact [$T style names] $style] == -1} {
535	    error "style \"$style\" doesn't exist"
536	}
537	foreach element $elements {
538	    if {[lsearch -exact [$T element names] $element] == -1} {
539		error "element \"$element\" doesn't exist"
540	    }
541	}
542    }
543    set Priv(dragimage,$T) $listOfLists
544    return
545}
546
547# ::TreeCtrl::SetEditable
548#
549# Specifies the list of text elements that can be edited.
550#
551# Arguments:
552# T		The treectrl widget.
553# listOfLists	{{column style element ...} {column style element ...}}
554
555proc ::TreeCtrl::SetEditable {T listOfLists} {
556    variable Priv
557    foreach list $listOfLists {
558	set elements [lassign $list column style]
559	if {[$T column id $column] eq ""} {
560	    error "column \"$column\" doesn't exist"
561	}
562	if {[lsearch -exact [$T style names] $style] == -1} {
563	    error "style \"$style\" doesn't exist"
564	}
565	foreach element $elements {
566	    if {[lsearch -exact [$T element names] $element] == -1} {
567		error "element \"$element\" doesn't exist"
568	    }
569	    if {[$T element type $element] ne "text"} {
570		error "element \"$element\" is not of type \"text\""
571	    }
572	}
573    }
574    set Priv(edit,$T) $listOfLists
575    return
576}
577
578# ::TreeCtrl::SetSensitive
579#
580# Specifies the list of elements that respond to mouse clicks.
581#
582# Arguments:
583# T		The treectrl widget.
584# listOfLists	{{column style element ...} {column style element ...}}
585
586proc ::TreeCtrl::SetSensitive {T listOfLists} {
587    variable Priv
588    foreach list $listOfLists {
589	set elements [lassign $list column style]
590	if {[$T column id $column] eq ""} {
591	    error "column \"$column\" doesn't exist"
592	}
593	if {[lsearch -exact [$T style names] $style] == -1} {
594	    error "style \"$style\" doesn't exist"
595	}
596	foreach element $elements {
597	    if {[lsearch -exact [$T element names] $element] == -1} {
598		error "element \"$element\" doesn't exist"
599	    }
600	}
601    }
602    set Priv(sensitive,$T) $listOfLists
603    return
604}
605
606# ::TreeCtrl::EntryOpen
607#
608# Display a ::tk::entry so the user can edit the specified text element.
609#
610# Arguments:
611# T		The treectrl widget.
612# item		Item.
613# column	Column.
614# element	Element.
615
616proc ::TreeCtrl::EntryOpen {T item column element} {
617
618    variable Priv
619
620    set Priv(entry,$T,item) $item
621    set Priv(entry,$T,column) $column
622    set Priv(entry,$T,element) $element
623    set Priv(entry,$T,focus) [focus]
624
625    # Get window coords of the Element
626    scan [$T item bbox $item $column $element] "%d %d" x y
627
628    # Get the font used by the Element
629    set font [$T item element perstate $item $column $element -font]
630    if {$font eq ""} {
631	set font [$T cget -font]
632    }
633
634    # Get the text used by the Element. Could check master Element too.
635    set text [$T item element cget $item $column $element -text]
636
637    # Create the Entry widget if needed
638    set e $T.entry
639    if {[winfo exists $e]} {
640	$e delete 0 end
641    } else {
642	$Priv(entryCmd) $e -borderwidth 1 -relief solid -highlightthickness 0
643	bindtags $e [linsert [bindtags $e] 1 TreeCtrlEntry]
644    }
645
646    # Pesky MouseWheel
647    $T notify bind $e <Scroll> { TreeCtrl::EditClose %T entry 0 1 }
648
649    $e configure -font $font
650    $e insert end $text
651    $e selection range 0 end
652
653    set ebw [$e cget -borderwidth]
654    set ex [expr {$x - $ebw - 1}]
655    place $e -x $ex -y [expr {$y - $ebw - 1}] -bordermode outside
656
657    # Make the Entry as wide as the text plus "W" but keep it within the
658    # TreeCtrl borders
659    set width [font measure $font ${text}W]
660    set width [expr {$width + ($ebw + 1) * 2}]
661    scan [$T contentbox] "%d %d %d %d" left top right bottom
662    if {$ex + $width > $right} {
663	set width [expr {$right - $ex}]
664    }
665    scan [$T item bbox $item $column] "%d %d %d %d" left top right bottom
666    if {$ex + $width > $right} {
667	set width [expr {$right - $ex}]
668    }
669    place configure $e -width $width
670
671    focus $e
672
673    return
674}
675
676# ::TreeCtrl::EntryExpanderOpen
677#
678# Display a ::tk::entry so the user can edit the specified text element.
679# Like EntryOpen, but Entry widget expands/shrinks during typing.
680#
681# Arguments:
682# T		The treectrl widget.
683# item		Item.
684# column	Column.
685# element	Element.
686
687proc ::TreeCtrl::EntryExpanderOpen {T item column element} {
688
689    variable Priv
690
691    set Priv(entry,$T,item) $item
692    set Priv(entry,$T,column) $column
693    set Priv(entry,$T,element) $element
694    set Priv(entry,$T,focus) [focus]
695
696    # Get window coords of the Element
697    scan [$T item bbox $item $column $element] "%d %d" x y
698
699    # Get the font used by the Element
700    set font [$T item element perstate $item $column $element -font]
701    if {$font eq ""} {
702	set font [$T cget -font]
703    }
704
705    set Priv(entry,$T,font) $font
706
707    # Get the text used by the Element. Could check master Element too.
708    set text [$T item element cget $item $column $element -text]
709
710    # Create the Entry widget if needed
711    set e $T.entry
712    if {[winfo exists $e]} {
713	$e delete 0 end
714    } else {
715	$Priv(entryCmd) $e -borderwidth 1 -highlightthickness 0 \
716	    -selectborderwidth 0 -relief solid
717	bindtags $e [linsert [bindtags $e] 1 TreeCtrlEntry]
718
719	# Resize as user types
720	bind $e <KeyPress> {
721	    after idle [list TreeCtrl::EntryExpanderKeypress [winfo parent %W]]
722	}
723    }
724
725    # Pesky MouseWheel
726    $T notify bind $e <Scroll> { TreeCtrl::EditClose %T entry 0 1 }
727
728    $e configure -font $font -background [$T cget -background]
729    $e insert end $text
730    $e selection range 0 end
731
732    set ebw [$e cget -borderwidth]
733    set ex [expr {$x - $ebw - 1}]
734    place $e -x $ex -y [expr {$y - $ebw - 1}] \
735	-bordermode outside
736
737    # Make the Entry as wide as the text plus "W" but keep it within the
738    # TreeCtrl borders
739    set width [font measure $font ${text}W]
740    set width [expr {$width + ($ebw + 1) * 2}]
741    scan [$T contentbox] "%d %d %d %d" left top right bottom
742    if {$ex + $width > $right} {
743	set width [expr {$right - $ex}]
744    }
745    place configure $e -width $width
746
747    focus $e
748
749    return
750}
751
752# ::TreeCtrl::EditClose
753#
754# Hides the text-edit widget and restores the focus if needed.
755# Generates <Edit-accept> and <Edit-end> events as needed.
756#
757# Arguments:
758# T		The treectrl widget.
759# type		"entry" or "text".
760# accept	0/1: should an <Edit-accept> event be generated.
761# refocus	0/1: should the focus be restored to what it was before editing.
762
763proc ::TreeCtrl::EditClose {T type accept {refocus 0}} {
764    variable Priv
765
766    set w $T.$type
767    # We need the double-idle to get winfo ismapped to report properly
768    # so this don't get the FocusOut following Escape immediately
769    update idletasks
770    place forget $w
771    focus $T
772    update idletasks
773
774    if {$accept} {
775	if {$type eq "entry"} {
776	    set t [$w get]
777	} else {
778	    set t [$w get 1.0 end-1c]
779	}
780	TryEvent $T Edit accept \
781	    [list I $Priv($type,$T,item) C $Priv($type,$T,column) \
782		 E $Priv($type,$T,element) t $t]
783    }
784
785    $T notify unbind $w <Scroll>
786
787    TryEvent $T Edit end \
788	[list I $Priv($type,$T,item) C $Priv($type,$T,column) \
789	     E $Priv($type,$T,element)]
790
791    if {$refocus} {
792	focus $Priv($type,$T,focus)
793    }
794
795    return
796}
797
798# ::TreeCtrl::EntryExpanderKeypress
799#
800# Maintains the width of the text-edit widget during typing.
801#
802# Arguments:
803# T		The treectrl widget.
804
805proc ::TreeCtrl::EntryExpanderKeypress {T} {
806
807    variable Priv
808
809    set font $Priv(entry,$T,font)
810    set text [$T.entry get]
811    set ebw [$T.entry cget -borderwidth]
812    set ex [winfo x $T.entry]
813
814    set width [font measure $font ${text}W]
815    set width [expr {$width + ($ebw + 1) * 2}]
816
817    scan [$T contentbox] "%d %d %d %d" left top right bottom
818    if {$ex + $width > $right} {
819	set width [expr {$right - $ex}]
820    }
821
822    place configure $T.entry -width $width
823
824    return
825}
826
827# ::TreeCtrl::TextOpen
828#
829# Display a ::tk::text so the user can edit the specified text element.
830#
831# Arguments:
832# T		The treectrl widget.
833# item		Item.
834# column	Column.
835# element	Element.
836# width		unused.
837# height	unused.
838
839proc ::TreeCtrl::TextOpen {T item column element {width 0} {height 0}} {
840    variable Priv
841
842    set Priv(text,$T,item) $item
843    set Priv(text,$T,column) $column
844    set Priv(text,$T,element) $element
845    set Priv(text,$T,focus) [focus]
846
847    # Get window coords of the Element
848    scan [$T item bbox $item $column $element] "%d %d %d %d" x1 y1 x2 y2
849
850    # Get the font used by the Element
851    set font [$T item element perstate $item $column $element -font]
852    if {$font eq ""} {
853	set font [$T cget -font]
854    }
855
856    # Get the text used by the Element. Could check master Element too.
857    set text [$T item element cget $item $column $element -text]
858
859    set justify [$T element cget $element -justify]
860    if {$justify eq ""} {
861	set justify left
862    }
863
864    set wrap [$T element cget $element -wrap]
865    if {$wrap eq ""} {
866	set wrap word
867    }
868
869    # Create the Text widget if needed
870    set w $T.text
871    if {[winfo exists $w]} {
872	$w delete 1.0 end
873    } else {
874	text $w -borderwidth 1 -highlightthickness 0 -relief solid
875	bindtags $w [linsert [bindtags $w] 1 TreeCtrlText]
876    }
877
878    # Pesky MouseWheel
879    $T notify bind $w <Scroll> { TreeCtrl::EditClose %T text 0 1 }
880
881    $w tag configure TAG -justify $justify
882    $w configure -font $font -background [$T cget -background] -wrap $wrap
883    $w insert end $text
884    $w tag add sel 1.0 end
885    $w tag add TAG 1.0 end
886
887    set tbw [$w cget -borderwidth]
888    set tx [expr {$x1 - $tbw - 1}]
889    place $w -x $tx -y [expr {$y1 - $tbw - 1}] \
890	-width [expr {$x2 - $x1 + ($tbw + 1) * 2}] \
891	-height [expr {$y2 - $y1 + ($tbw + 1) * 2}] \
892	-bordermode outside
893
894    focus $w
895
896    return
897}
898
899# ::TreeCtrl::TextExpanderOpen
900#
901# Display a ::tk::text so the user can edit the specified text element.
902# Like TextOpen, but Text widget expands/shrinks during typing.
903#
904# Arguments:
905# T		The treectrl widget.
906# item		Item.
907# column	Column.
908# element	Element.
909# width		Width of the text element.
910
911proc ::TreeCtrl::TextExpanderOpen {T item column element width} {
912
913    variable Priv
914
915    set Priv(text,$T,item) $item
916    set Priv(text,$T,column) $column
917    set Priv(text,$T,element) $element
918    set Priv(text,$T,focus) [focus]
919
920    # Get window coords of the Element
921    scan [$T item bbox $item $column $element] "%d %d %d %d" x1 y1 x2 y2
922
923    set Priv(text,$T,center) [expr {$x1 + ($x2 - $x1) / 2}]
924
925    # Get the font used by the Element
926    set font [$T item element perstate $item $column $element -font]
927    if {$font eq ""} {
928	set font [$T cget -font]
929    }
930
931    # Get the text used by the Element. Could check master Element too.
932    set text [$T item element cget $item $column $element -text]
933
934    set justify [$T element cget $element -justify]
935    if {$justify eq ""} {
936	set justify left
937    }
938
939    set wrap [$T element cget $element -wrap]
940    if {$wrap eq ""} {
941	set wrap word
942    }
943
944    # Create the Text widget if needed
945    set w $T.text
946    if {[winfo exists $w]} {
947	$w delete 1.0 end
948    } else {
949	text $w -borderwidth 1 -highlightthickness 0 \
950	    -selectborderwidth 0 -relief solid
951	bindtags $w [linsert [bindtags $w] 1 TreeCtrlText]
952
953	# Resize as user types
954	bind $w <KeyPress> {
955	    after idle TreeCtrl::TextExpanderKeypress [winfo parent %W]
956	}
957    }
958
959    # Pesky MouseWheel
960    $T notify bind $w <Scroll> { TreeCtrl::EditClose %T text 0 1 }
961
962    $w tag configure TAG -justify $justify
963    $w configure -font $font -background [$T cget -background] -wrap $wrap
964    $w insert end $text
965    $w tag add sel 1.0 end
966    $w tag add TAG 1.0 end
967
968    set Priv(text,$T,font) $font
969    set Priv(text,$T,justify) $justify
970    set Priv(text,$T,width) $width
971
972    scan [textlayout $font $text -justify $justify -width $width] \
973	"%d %d" width height
974
975    set tbw [$w cget -borderwidth]
976    incr tbw
977    place $w -x [expr {$x1 - $tbw}] -y [expr {$y1 - $tbw}] \
978	-width [expr {$width + $tbw * 2}] \
979	-height [expr {$height + $tbw * 2}] \
980	-bordermode outside
981
982    focus $w
983
984    return
985}
986
987# ::TreeCtrl::TextExpanderKeypress
988#
989# Maintains the size of the text-edit widget during typing.
990#
991# Arguments:
992# T		The treectrl widget.
993
994proc ::TreeCtrl::TextExpanderKeypress {T} {
995
996    variable Priv
997
998    set font $Priv(text,$T,font)
999    set justify $Priv(text,$T,justify)
1000    set width $Priv(text,$T,width)
1001    set center $Priv(text,$T,center)
1002
1003    set text [$T.text get 1.0 end-1c]
1004
1005    scan [textlayout $font $text -justify $justify -width $width] \
1006	"%d %d" width height
1007
1008    set tbw [$T.text cget -borderwidth]
1009    incr tbw
1010    place configure $T.text \
1011	-x [expr {$center - ($width + $tbw * 2) / 2}] \
1012	-width [expr {$width + $tbw * 2}] \
1013	-height [expr {$height + $tbw * 2}]
1014
1015    $T.text tag add TAG 1.0 end
1016
1017    return
1018}
1019
1020