1# search.rb
2#
3# This demonstration script creates a collection of widgets that
4# allow you to load a file into a text widget, then perform searches
5# on that file.
6#
7# Text Search widget demo (called by 'widget')
8#
9
10# textLoadFile --
11# This method below loads a file into a text widget, discarding
12# the previous contents of the widget. Tags for the old widget are
13# not affected, however.
14#
15# Arguments:
16# w -           The window into which to load the file.  Must be a
17#               text widget.
18# file -        The name of the file to load.  Must be readable.
19
20def textLoadFile(w,file)
21  w.delete('1.0', 'end')
22  f = open(file, 'r')
23  while(!f.eof?)
24    w.insert('end', f.read(1000))
25  end
26  f.close
27end
28
29# textSearch --
30# Search for all instances of a given string in a text widget and
31# apply a given tag to each instance found.
32#
33# Arguments:
34# w -           The window in which to search.  Must be a text widget.
35# string -      The string to search for.  The search is done using
36#               exact matching only;  no special characters.
37# tag -         Tag to apply to each instance of a matching string.
38
39def textSearch(w, string, tag)
40  tag.remove('0.0', 'end')
41  return if string == ""
42  cur = '1.0'
43  loop {
44    cur, len = w.search_with_length(string, cur, 'end')
45    break if cur == ""
46    tag.add(cur, "#{cur} + #{len} char")
47    cur = w.index("#{cur} + #{len} char")
48  }
49end
50
51# textToggle --
52# This method is invoked repeatedly to invoke two commands at
53# periodic intervals.  It normally reschedules itself after each
54# execution but if an error occurs (e.g. because the window was
55# deleted) then it doesn't reschedule itself.
56#
57# Arguments:
58# cmd1 -        Command to execute when method is called.
59# sleep1 -      Ms to sleep after executing cmd1 before executing cmd2.
60# cmd2 -        Command to execute in the *next* invocation of this method.
61# sleep2 -      Ms to sleep after executing cmd2 before executing cmd1 again.
62
63def textToggle(cmd1,sleep1,cmd2,sleep2)
64  sleep_list = [sleep2, sleep1]
65  TkAfter.new(proc{sleep = sleep_list.shift; sleep_list.push(sleep); sleep},
66              -1, cmd1, cmd2).start(sleep1)
67end
68
69# toplevel widget
70if defined?($search_demo) && $search_demo
71  $search_demo.destroy
72  $search_demo = nil
73end
74
75# demo toplevel widget
76$search_demo = TkToplevel.new {|w|
77  title("Text Demonstration - Search and Highlight")
78  iconname("search")
79  positionWindow(w)
80}
81
82base_frame = TkFrame.new($search_demo).pack(:fill=>:both, :expand=>true)
83
84# frame
85$search_buttons = TkFrame.new(base_frame) {|frame|
86  TkButton.new(frame) {
87    text 'Dismiss'
88    command proc{
89      tmppath = $search_demo
90      $search_demo = nil
91      tmppath.destroy
92    }
93  }.pack('side'=>'left', 'expand'=>'yes')
94
95  TkButton.new(frame) {
96    text 'Show Code'
97    command proc{showCode 'search'}
98  }.pack('side'=>'left', 'expand'=>'yes')
99}
100$search_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
101
102# frame
103TkFrame.new(base_frame) {|f|
104  TkLabel.new(f, 'text'=>'File name:',
105              'width'=>13, 'anchor'=>'w').pack('side'=>'left')
106  $search_fileName = TkVariable.new
107  TkEntry.new(f, 'width'=>40,
108              'textvariable'=>$search_fileName) {
109    pack('side'=>'left')
110    bind('Return', proc{textLoadFile($search_text, $search_fileName.value)
111                        $search_string_entry.focus})
112    focus
113  }
114  TkButton.new(f, 'text'=>'Load File',
115               'command'=>proc{textLoadFile($search_text,
116                                            $search_fileName.value)})\
117  .pack('side'=>'left', 'pady'=>5, 'padx'=>10)
118}.pack('side'=>'top', 'fill'=>'x')
119
120TkFrame.new(base_frame) {|f|
121  TkLabel.new(f, 'text'=>'Search string:',
122              'width'=>13, 'anchor'=>'w').pack('side'=>'left')
123  $search_searchString = TkVariable.new
124  $search_string_entry = TkEntry.new(f, 'width'=>40,
125                                     'textvariable'=>$search_searchString) {
126    pack('side'=>'left')
127    bind('Return', proc{textSearch($search_text, $search_searchString.value,
128                                   $search_Tag)})
129  }
130  TkButton.new(f, 'text'=>'Highlight',
131               'command'=>proc{textSearch($search_text,
132                                          $search_searchString.value,
133                                          $search_Tag)}) {
134    pack('side'=>'left', 'pady'=>5, 'padx'=>10)
135  }
136}.pack('side'=>'top', 'fill'=>'x')
137
138$search_text = TkText.new(base_frame, 'setgrid'=>true, 'wrap'=>'word') {|t|
139  $search_Tag = TkTextTag.new(t)
140  TkScrollbar.new(base_frame, 'command'=>proc{|*args| t.yview(*args)}) {|sc|
141    t.yscrollcommand(proc{|first,last| sc.set first,last})
142    pack('side'=>'right', 'fill'=>'y')
143  }
144  pack('expand'=>'yes', 'fill'=>'both')
145}
146
147# Set up display styles for text highlighting.
148
149if TkWinfo.depth($search_demo) > 1
150  textToggle(proc{
151               $search_Tag.configure('background'=>'#ce5555',
152                                     'foreground'=>'white')
153             },
154             800,
155             proc{
156               $search_Tag.configure('background'=>'', 'foreground'=>'')
157             },
158             200 )
159else
160  textToggle(proc{
161               $search_Tag.configure('background'=>'black',
162                                     'foreground'=>'white')
163             },
164             800,
165             proc{
166               $search_Tag.configure('background'=>'', 'foreground'=>'')
167             },
168             200 )
169end
170$search_text.insert('1.0', "\
171This window demonstrates how to use the tagging facilities in text \
172widgets to implement a searching mechanism.  First, type a file name \
173in the top entry, then type <Return> or click on \"Load File\".  Then \
174type a string in the lower entry and type <Return> or click on \
175\"Load File\".  This will cause all of the instances of the string to \
176be tagged with the tag \"search\", and it will arrange for the tag\'s \
177display attributes to change to make all of the strings blink.")
178$search_text.insert('end', "\
179The current directory to load a file is \"#{Dir.pwd}\".\
180")
181$search_text.set_insert '0.0'
182
183$search_fileName.value = ''
184$search_searchString.value = ''
185
186$search_text.width = 60
187$search_text.height = 20
188