]>
Commit | Line | Data |
---|---|---|
f10d5b06 AG |
1 | # incremental search panel |
2 | # based on code from gitk, Copyright (C) Paul Mackerras | |
3 | ||
4 | class searchbar { | |
5 | ||
6 | field w | |
7 | field ctext | |
8 | ||
9 | field searchstring {} | |
10 | field casesensitive 1 | |
11 | field searchdirn -forwards | |
12 | ||
13 | field smarktop | |
14 | field smarkbot | |
15 | ||
16 | constructor new {i_w i_text args} { | |
17 | set w $i_w | |
18 | set ctext $i_text | |
19 | ||
20 | frame $w | |
21 | label $w.l -text [mc Find:] | |
22 | button $w.bn -text [mc Next] -command [cb find_next] | |
23 | button $w.bp -text [mc Prev] -command [cb find_prev] | |
24 | checkbutton $w.cs -text [mc Case-Sensitive] \ | |
25 | -variable ${__this}::casesensitive -command [cb _incrsearch] | |
26 | entry $w.ent -textvariable ${__this}::searchstring -background lightgreen | |
27 | pack $w.l -side left | |
28 | pack $w.cs -side right | |
29 | pack $w.bp -side right | |
30 | pack $w.bn -side right | |
31 | pack $w.ent -side left -expand 1 -fill x | |
32 | ||
33 | eval grid conf $w -sticky we $args | |
34 | grid remove $w | |
35 | ||
36 | trace add variable searchstring write [cb _incrsearch_cb] | |
37 | ||
38 | bind $w <Destroy> [cb delete_this] | |
39 | return $this | |
40 | } | |
41 | ||
42 | method show {} { | |
43 | if {![winfo ismapped $w]} { | |
44 | grid $w | |
45 | } | |
46 | focus -force $w.ent | |
47 | } | |
48 | ||
49 | method hide {} { | |
50 | if {[winfo ismapped $w]} { | |
51 | focus $ctext | |
52 | grid remove $w | |
53 | } | |
54 | } | |
55 | ||
56 | method _get_new_anchor {} { | |
57 | # use start of selection if it is visible, | |
58 | # or the bounds of the visible area | |
59 | set top [$ctext index @0,0] | |
60 | set bottom [$ctext index @0,[winfo height $ctext]] | |
61 | set sel [$ctext tag ranges sel] | |
62 | if {$sel ne {}} { | |
63 | set spos [lindex $sel 0] | |
64 | if {[lindex $spos 0] >= [lindex $top 0] && | |
65 | [lindex $spos 0] <= [lindex $bottom 0]} { | |
66 | return $spos | |
67 | } | |
68 | } | |
69 | if {$searchdirn eq "-forwards"} { | |
70 | return $top | |
71 | } else { | |
72 | return $bottom | |
73 | } | |
74 | } | |
75 | ||
76 | method _get_wrap_anchor {dir} { | |
77 | if {$dir eq "-forwards"} { | |
78 | return 1.0 | |
79 | } else { | |
80 | return end | |
81 | } | |
82 | } | |
83 | ||
84 | method _do_search {start {mlenvar {}} {dir {}} {endbound {}}} { | |
85 | set cmd [list $ctext search] | |
86 | if {$mlenvar ne {}} { | |
87 | upvar $mlenvar mlen | |
88 | lappend cmd -count mlen | |
89 | } | |
90 | if {!$casesensitive} { | |
91 | lappend cmd -nocase | |
92 | } | |
93 | if {$dir eq {}} { | |
94 | set dir $searchdirn | |
95 | } | |
96 | lappend cmd $dir -- $searchstring | |
97 | if {$endbound ne {}} { | |
98 | set here [eval $cmd [list $start] [list $endbound]] | |
99 | } else { | |
100 | set here [eval $cmd [list $start]] | |
101 | if {$here eq {}} { | |
102 | set here [eval $cmd [_get_wrap_anchor $this $dir]] | |
103 | } | |
104 | } | |
105 | return $here | |
106 | } | |
107 | ||
108 | method _incrsearch_cb {name ix op} { | |
109 | after idle [cb _incrsearch] | |
110 | } | |
111 | ||
112 | method _incrsearch {} { | |
113 | $ctext tag remove found 1.0 end | |
114 | if {[catch {$ctext index anchor}]} { | |
115 | $ctext mark set anchor [_get_new_anchor $this] | |
116 | } | |
117 | if {$searchstring ne {}} { | |
118 | set here [_do_search $this anchor mlen] | |
119 | if {$here ne {}} { | |
120 | $ctext see $here | |
121 | $ctext tag remove sel 1.0 end | |
122 | $ctext tag add sel $here "$here + $mlen c" | |
123 | $w.ent configure -background lightgreen | |
124 | _set_marks $this 1 | |
125 | } else { | |
126 | $w.ent configure -background lightpink | |
127 | } | |
128 | } | |
129 | } | |
130 | ||
131 | method find_prev {} { | |
132 | find_next $this -backwards | |
133 | } | |
134 | ||
135 | method find_next {{dir -forwards}} { | |
136 | focus $w.ent | |
137 | $w.ent icursor end | |
138 | set searchdirn $dir | |
139 | $ctext mark unset anchor | |
140 | if {$searchstring ne {}} { | |
141 | set start [_get_new_anchor $this] | |
142 | if {$dir eq "-forwards"} { | |
143 | set start "$start + 1c" | |
144 | } | |
145 | set match [_do_search $this $start mlen] | |
146 | $ctext tag remove sel 1.0 end | |
147 | if {$match ne {}} { | |
148 | $ctext see $match | |
149 | $ctext tag add sel $match "$match + $mlen c" | |
150 | } | |
151 | } | |
152 | } | |
153 | ||
154 | method _mark_range {first last} { | |
155 | set mend $first.0 | |
156 | while {1} { | |
157 | set match [_do_search $this $mend mlen -forwards $last.end] | |
158 | if {$match eq {}} break | |
159 | set mend "$match + $mlen c" | |
160 | $ctext tag add found $match $mend | |
161 | } | |
162 | } | |
163 | ||
164 | method _set_marks {doall} { | |
165 | set topline [lindex [split [$ctext index @0,0] .] 0] | |
166 | set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0] | |
167 | if {$doall || $botline < $smarktop || $topline > $smarkbot} { | |
168 | # no overlap with previous | |
169 | _mark_range $this $topline $botline | |
170 | set smarktop $topline | |
171 | set smarkbot $botline | |
172 | } else { | |
173 | if {$topline < $smarktop} { | |
174 | _mark_range $this $topline [expr {$smarktop-1}] | |
175 | set smarktop $topline | |
176 | } | |
177 | if {$botline > $smarkbot} { | |
178 | _mark_range $this [expr {$smarkbot+1}] $botline | |
179 | set smarkbot $botline | |
180 | } | |
181 | } | |
182 | } | |
183 | ||
184 | method scrolled {} { | |
185 | if {$searchstring ne {}} { | |
186 | after idle [cb _set_marks 0] | |
187 | } | |
188 | } | |
189 | ||
190 | } |