~ubuntu-branches/ubuntu/hardy/ruby1.8/hardy-updates

« back to all changes in this revision

Viewing changes to ext/tk/sample/tkcombobox.rb

  • Committer: Bazaar Package Importer
  • Author(s): akira yamada
  • Date: 2007-03-13 22:11:58 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070313221158-h3oql37brlaf2go2
Tags: 1.8.6-1
* new upstream version, 1.8.6.
* libruby1.8 conflicts with libopenssl-ruby1.8 (< 1.8.6) (closes: #410018)
* changed packaging style to cdbs from dbs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
#  tkcombobox.rb : TkAutoScrollbox & TkCombobox
 
3
 
4
#                         by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
 
5
#
 
6
require 'tk'
 
7
 
 
8
class TkAutoScrollbox < TkListbox
 
9
  include TkComposite
 
10
 
 
11
  @@up_bmp = TkBitmapImage.new(:data=><<EOD)
 
12
#define up_arrow_width 9
 
13
#define up_arrow_height 9
 
14
static unsigned char up_arrow_bits[] = {
 
15
   0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7c, 0x00,
 
16
   0x7c, 0x00, 0xfe, 0x00, 0x00, 0x00};
 
17
EOD
 
18
 
 
19
  @@down_bmp = TkBitmapImage.new(:data=><<EOD)
 
20
#define up_arrow_width 9
 
21
#define up_arrow_height 9
 
22
static unsigned char down_arrow_bits[] = {
 
23
   0x00, 0x00, 0xfe, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x38, 0x00,
 
24
   0x10, 0x00, 0x10, 0x00, 0x00, 0x00};
 
25
EOD
 
26
 
 
27
  ############################
 
28
  private
 
29
  ############################
 
30
  def initialize_composite(keys={})
 
31
    keys = _symbolkey2str(keys)
 
32
 
 
33
    @initwait = keys.delete('startwait'){300}
 
34
    @interval = keys.delete('interval'){150}
 
35
    @initwait -= @interval
 
36
    @initwait = 0 if @initwait < 0
 
37
 
 
38
    @lbox = TkListbox.new(@frame, :borderwidth=>0)
 
39
    @path = @lbox.path
 
40
    TkPack.propagate(@lbox, false)
 
41
 
 
42
    @scr = TkScrollbar.new(@frame, :width=>10)
 
43
 
 
44
    @lbox.yscrollcommand(proc{|*args| @scr.set(*args); _config_proc})
 
45
    @scr.command(proc{|*args| @lbox.yview(*args); _config_proc})
 
46
 
 
47
    @up_arrow   = TkLabel.new(@lbox, :image=>@@up_bmp, 
 
48
                              :relief=>:raised, :borderwidth=>1)
 
49
    @down_arrow = TkLabel.new(@lbox, :image=>@@down_bmp, 
 
50
                              :relief=>:raised, :borderwidth=>1)
 
51
 
 
52
    _init_binding
 
53
 
 
54
    @lbox.pack(:side=>:left, :fill=>:both, :expand=>:true)
 
55
 
 
56
    delegate('DEFAULT', @lbox)
 
57
    delegate('background', @frame, @scr)
 
58
    delegate('activebackground', @scr)
 
59
    delegate('troughcolor', @scr)
 
60
    delegate('repeatdelay', @scr)
 
61
    delegate('repeatinterval', @scr)
 
62
    delegate('relief', @frame)
 
63
    delegate('borderwidth', @frame)
 
64
 
 
65
    delegate_alias('arrowrelief', 'relief', @up_arrow, @down_arrow)
 
66
    delegate_alias('arrowborderwidth', 'borderwidth', @up_arrow, @down_arrow)
 
67
 
 
68
    scrollbar(keys.delete('scrollbar')){false}
 
69
 
 
70
    configure keys unless keys.empty?
 
71
  end
 
72
 
 
73
  def _show_up_arrow
 
74
    unless @up_arrow.winfo_mapped?
 
75
      @up_arrow.pack(:side=>:top, :fill=>:x)
 
76
    end
 
77
  end
 
78
 
 
79
  def _show_down_arrow
 
80
    unless @down_arrow.winfo_mapped?
 
81
      @down_arrow.pack(:side=>:bottom, :fill=>:x) 
 
82
    end
 
83
  end
 
84
 
 
85
  def _set_sel(idx)
 
86
      @lbox.activate(idx)
 
87
      @lbox.selection_clear(0, 'end')
 
88
      @lbox.selection_set(idx)
 
89
  end
 
90
 
 
91
  def _check_sel(cidx, tidx = nil, bidx = nil)
 
92
    _set_sel(cidx)
 
93
    unless tidx
 
94
      tidx = @lbox.nearest(0) 
 
95
      tidx += 1 if tidx > 0
 
96
    end
 
97
    unless bidx
 
98
      bidx = @lbox.nearest(10000) 
 
99
      bidx -= 1 if bidx < @lbox.index('end') - 1
 
100
    end
 
101
    if cidx > bidx
 
102
      _set_sel(bidx)
 
103
    end
 
104
    if cidx < tidx
 
105
      _set_sel(tidx)
 
106
    end
 
107
  end
 
108
 
 
109
  def _up_proc
 
110
    cidx = @lbox.curselection[0]
 
111
    idx = @lbox.nearest(0)
 
112
    if idx >= 0
 
113
      @lbox.see(idx - 1)
 
114
      _set_sel(idx)
 
115
      @up_arrow.pack_forget if idx == 1
 
116
      @up_timer.stop if idx == 0
 
117
      _show_down_arrow if @lbox.bbox('end') == []
 
118
    end
 
119
    if cidx && cidx > 0 && (idx == 0 || cidx == @lbox.nearest(10000))
 
120
      _set_sel(cidx - 1)
 
121
    end
 
122
  end
 
123
 
 
124
  def _down_proc
 
125
    cidx = @lbox.curselection[0]
 
126
    eidx = @lbox.index('end') - 1
 
127
    idx = @lbox.nearest(10000)
 
128
    if idx <= eidx
 
129
      @lbox.see(idx + 1)
 
130
      _set_sel(cidx + 1) if cidx < eidx
 
131
      @down_arrow.pack_forget if idx + 1 == eidx
 
132
      @down_timer.stop if idx == eidx
 
133
      _show_up_arrow if @lbox.bbox(0) == []
 
134
    end
 
135
    if cidx && cidx < eidx && (eidx == idx || cidx == @lbox.nearest(0))
 
136
      _set_sel(cidx + 1)
 
137
    end
 
138
  end
 
139
 
 
140
  def _key_UP_proc
 
141
    cidx = @lbox.curselection[0]
 
142
    _set_sel(cidx = @lbox.index('activate')) unless cidx
 
143
    cidx -= 1
 
144
    if cidx == 0
 
145
      @up_arrow.pack_forget
 
146
    elsif cidx == @lbox.nearest(0)
 
147
      @lbox.see(cidx - 1)
 
148
    end
 
149
  end
 
150
 
 
151
  def _key_DOWN_proc
 
152
    cidx = @lbox.curselection[0]
 
153
    _set_sel(cidx = @lbox.index('activate')) unless cidx
 
154
    cidx += 1
 
155
    if cidx == @lbox.index('end') - 1
 
156
      @down_arrow.pack_forget
 
157
    elsif cidx == @lbox.nearest(10000)
 
158
      @lbox.see(cidx + 1)
 
159
    end
 
160
  end
 
161
 
 
162
  def _config_proc
 
163
    if @lbox.size == 0
 
164
      @up_arrow.pack_forget
 
165
      @down_arrow.pack_forget
 
166
      return
 
167
    end
 
168
    tidx = @lbox.nearest(0)
 
169
    bidx = @lbox.nearest(10000)
 
170
    if tidx > 0
 
171
      _show_up_arrow
 
172
      tidx += 1
 
173
    else
 
174
      @up_arrow.pack_forget unless @up_timer.running?
 
175
    end
 
176
    if bidx < @lbox.index('end') - 1
 
177
      _show_down_arrow
 
178
      bidx -= 1
 
179
    else
 
180
      @down_arrow.pack_forget unless @down_timer.running?
 
181
    end
 
182
    cidx = @lbox.curselection[0]
 
183
    _check_sel(cidx, tidx, bidx) if cidx
 
184
  end
 
185
 
 
186
  def _init_binding
 
187
    @up_timer = TkAfter.new(@interval, -1, proc{_up_proc})
 
188
    @down_timer = TkAfter.new(@interval, -1, proc{_down_proc})
 
189
 
 
190
    @up_timer.set_start_proc(@initwait, proc{})
 
191
    @down_timer.set_start_proc(@initwait, proc{})
 
192
 
 
193
    @up_arrow.bind('Enter', proc{@up_timer.start})
 
194
    @up_arrow.bind('Leave', proc{@up_timer.stop if @up_arrow.winfo_mapped?})
 
195
    @down_arrow.bind('Enter', proc{@down_timer.start})
 
196
    @down_arrow.bind('Leave', proc{@down_timer.stop if @down_arrow.winfo_mapped?})
 
197
 
 
198
    @lbox.bind('Configure', proc{_config_proc})
 
199
    @lbox.bind('Enter', proc{|y| _set_sel(@lbox.nearest(y))}, '%y')
 
200
    @lbox.bind('Motion', proc{|y| 
 
201
                 @up_timer.stop if @up_timer.running?
 
202
                 @down_timer.stop if @down_timer.running?
 
203
                 _check_sel(@lbox.nearest(y))
 
204
               }, '%y')
 
205
 
 
206
    @lbox.bind('Up', proc{_key_UP_proc})
 
207
    @lbox.bind('Down', proc{_key_DOWN_proc})
 
208
  end
 
209
 
 
210
  ############################
 
211
  public
 
212
  ############################
 
213
  def scrollbar(mode)
 
214
    if mode
 
215
      @scr.pack(:side=>:right, :fill=>:y)
 
216
    else
 
217
      @scr.pack_forget
 
218
    end
 
219
  end
 
220
end
 
221
 
 
222
################################################
 
223
 
 
224
class TkCombobox < TkEntry
 
225
  include TkComposite
 
226
 
 
227
  @@down_btn_bmp = TkBitmapImage.new(:data=><<EOD)
 
228
#define down_arrow_width 11
 
229
#define down_arrow_height 11
 
230
static unsigned char down_arrow_bits[] = {
 
231
   0x00, 0x00, 0xfe, 0x03, 0xfc, 0x01, 0xfc, 0x01, 0xf8, 0x00, 0xf8, 0x00,
 
232
   0x70, 0x00, 0x70, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00};
 
233
EOD
 
234
 
 
235
  @@up_btn_bmp = TkBitmapImage.new(:data=><<EOD)
 
236
#define up_arrow_width 11
 
237
#define up_arrow_height 11
 
238
static unsigned char up_arrow_bits[] = {
 
239
   0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x70, 0x00, 0x70, 0x00, 0xf8, 0x00,
 
240
   0xf8, 0x00, 0xfc, 0x01, 0xfc, 0x01, 0xfe, 0x03, 0x00, 0x00};
 
241
EOD
 
242
 
 
243
  def _button_proc(dir = true)
 
244
    @btn.relief(:sunken)
 
245
    x = @frame.winfo_rootx
 
246
    y = @frame.winfo_rooty
 
247
    if dir
 
248
      @top.geometry("+#{x}+#{y + @frame.winfo_height}")
 
249
    else
 
250
      @btn.image(@@up_btn_bmp)
 
251
      @top.geometry("+#{x}+#{y - @top.winfo_reqheight}")
 
252
    end
 
253
    @top.deiconify
 
254
    @lst.focus
 
255
 
 
256
    if (idx = values.index(@ent.value))
 
257
      @lst.see(idx - 1)
 
258
      @lst.activate(idx)
 
259
      @lst.selection_set(idx)
 
260
    elsif @lst.size > 0
 
261
      @lst.see(0)
 
262
      @lst.activate(0)
 
263
      @lst.selection_set(0)
 
264
    end
 
265
    @top.grab
 
266
 
 
267
    begin
 
268
      @var.tkwait
 
269
      if (idx = @var.to_i) >= 0
 
270
        @ent.value = @lst.get(idx)
 
271
      end
 
272
      @top.withdraw
 
273
      @btn.relief(:raised)
 
274
      @btn.image(@@down_btn_bmp)
 
275
    rescue
 
276
    ensure
 
277
      begin
 
278
        @top.grab(:release)
 
279
        @ent.focus
 
280
      rescue
 
281
      end
 
282
    end
 
283
  end
 
284
  private :_button_proc
 
285
 
 
286
  def _init_bindings
 
287
    @btn.bind('1', proc{_button_proc(true)})
 
288
    @btn.bind('3', proc{_button_proc(false)})
 
289
 
 
290
    @lst.bind('1', proc{|y| @var.value = @lst.nearest(y)}, '%y')
 
291
    @lst.bind('Return', proc{@var.value = @lst.curselection[0]})
 
292
 
 
293
    cancel = TkVirtualEvent.new('2', '3', 'Escape')
 
294
    @lst.bind(cancel, proc{@var.value = -1})
 
295
  end
 
296
  private :_init_bindings
 
297
 
 
298
  def initialize_composite(keys={})
 
299
    keys = _symbolkey2str(keys)
 
300
 
 
301
    @btn = TkLabel.new(@frame, :relief=>:raised, :borderwidth=>3, 
 
302
                       :image=>@@down_btn_bmp).pack(:side=>:right, 
 
303
                                                    :ipadx=>2, :fill=>:y)
 
304
    @ent = TkEntry.new(@frame).pack(:side=>:left)
 
305
    @path = @ent.path
 
306
 
 
307
    @top = TkToplevel.new(@btn, :borderwidth=>1, :relief=>:raised) {
 
308
      withdraw
 
309
      transient
 
310
      overrideredirect(true)
 
311
    }
 
312
 
 
313
    startwait = keys.delete('startwait'){300}
 
314
    interval = keys.delete('interval'){150}
 
315
    @lst = TkAutoScrollbox.new(@top, 
 
316
                               :startwait=>startwait, 
 
317
                               :interval=>interval).pack(:fill=>:both, 
 
318
                                                         :expand=>true)
 
319
    @ent_list = []
 
320
 
 
321
    @var = TkVariable.new
 
322
 
 
323
    _init_bindings
 
324
 
 
325
    delegate('DEFAULT', @ent)
 
326
    delegate('height', @lst)
 
327
    delegate('relief', @frame)
 
328
    delegate('borderwidth', @frame)
 
329
 
 
330
    delegate('arrowrelief', @lst)
 
331
    delegate('arrowborderwidth', @lst)
 
332
 
 
333
    if mode = keys.delete('scrollbar')
 
334
      scrollbar(mode)
 
335
    end
 
336
 
 
337
    configure keys unless keys.empty?
 
338
  end
 
339
  private :initialize_composite
 
340
 
 
341
  def scrollbar(mode)
 
342
    @lst.scrollbar(mode)
 
343
  end
 
344
 
 
345
  def _reset_width
 
346
    len = @ent.width
 
347
    @lst.get(0, 'end').each{|l| len = l.length if l.length > len}
 
348
    @lst.width(len + 1)
 
349
  end
 
350
  private :_reset_width
 
351
 
 
352
  def add(ent)
 
353
    ent = ent.to_s
 
354
    unless @ent_list.index(ent)
 
355
      @ent_list << ent
 
356
      @lst.insert('end', ent)
 
357
    end
 
358
    _reset_width
 
359
    self
 
360
  end
 
361
 
 
362
  def remove(ent)
 
363
    ent = ent.to_s
 
364
    @ent_list.delete(ent)
 
365
    if idx = @lst.get(0, 'end').index(ent)
 
366
      @lst.delete(idx)
 
367
    end
 
368
    _reset_width
 
369
    self
 
370
  end
 
371
 
 
372
  def values(ary = nil)
 
373
    if ary
 
374
      @lst.delete(0, 'end')
 
375
      @ent_list.clear
 
376
      ary.each{|ent| add(ent)}
 
377
      _reset_width
 
378
      self
 
379
    else
 
380
      @lst.get(0, 'end')
 
381
    end
 
382
  end
 
383
 
 
384
  def see(idx)
 
385
    @lst.see(@lst.index(idx) - 1)
 
386
  end
 
387
 
 
388
  def list_index(idx)
 
389
    @lst.index(idx)
 
390
  end
 
391
end
 
392
 
 
393
 
 
394
################################################
 
395
# test
 
396
################################################
 
397
if __FILE__ == $0
 
398
  v = TkVariable.new
 
399
  e = TkCombobox.new(:height=>7, :scrollbar=>true, :textvariable=>v, 
 
400
                     :arrowrelief=>:flat, :arrowborderwidth=>0, 
 
401
                     :startwait=>400, :interval=>200).pack
 
402
  e.values(%w(aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu))
 
403
  #e.see(e.list_index('end') - 2)
 
404
  e.value = 'cc'
 
405
  TkFrame.new{|f|
 
406
    fnt = TkFont.new('Helvetica 10')
 
407
    TkLabel.new(f, :font=>fnt, :text=>'TkCombobox value :').pack(:side=>:left)
 
408
    TkLabel.new(f, :font=>fnt, :textvariable=>v).pack(:side=>:left)
 
409
  }.pack
 
410
 
 
411
  TkFrame.new(:relief=>:raised, :borderwidth=>2, 
 
412
              :height=>3).pack(:fill=>:x, :expand=>true, :padx=>5, :pady=>3)
 
413
 
 
414
  l = TkAutoScrollbox.new(nil, :relief=>:groove, :borderwidth=>4, 
 
415
                          :width=>20).pack(:fill=>:both, :expand=>true)
 
416
  (0..20).each{|i| l.insert('end', "line #{i}")}
 
417
 
 
418
  TkFrame.new(:relief=>:ridge, :borderwidth=>3){
 
419
    TkButton.new(self, :text=>'ON', 
 
420
                 :command=>proc{l.scrollbar(true)}).pack(:side=>:left)
 
421
    TkButton.new(self, :text=>'OFF', 
 
422
                 :command=>proc{l.scrollbar(false)}).pack(:side=>:right)
 
423
    pack(:fill=>:x)
 
424
  }
 
425
  Tk.mainloop
 
426
end