1#
2#  tkextlib/bwidget/listbox.rb
3#                               by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
4#
5
6require 'tk'
7require 'tk/canvas'
8require 'tkextlib/bwidget.rb'
9
10module Tk
11  module BWidget
12    class ListBox < TkWindow
13      # is NOT a subclass of a listbox widget class.
14      # because it constructed on a canvas widget.
15
16      class Item < TkObject
17      end
18    end
19  end
20end
21
22class Tk::BWidget::ListBox
23  include TkItemConfigMethod
24  include Scrollable
25
26  TkCommandNames = ['ListBox'.freeze].freeze
27  WidgetClassName = 'ListBox'.freeze
28  WidgetClassNames[WidgetClassName] ||= self
29
30  class Event_for_Items < TkEvent::Event
31    def self._get_extra_args_tbl
32      [
33        TkComm.method(:string)   # item idenfier
34      ]
35    end
36  end
37
38  def __boolval_optkeys
39    super() << 'autofocus' << 'dragenabled' << 'dropenabled' << 'selectfill'
40  end
41  private :__boolval_optkeys
42
43  def tagid(tag)
44    if tag.kind_of?(Tk::BWidget::ListBox::Item)
45      tag.id
46    else
47      # tag
48      _get_eval_string(tag)
49    end
50  end
51
52  #def imagebind(*args)
53  #  _bind_for_event_class(Event_for_Items, [path, 'bindImage'], *args)
54  #  self
55  #end
56  def imagebind(context, *args)
57    #if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
58    if TkComm._callback_entry?(args[0]) || !block_given?
59      cmd = args.shift
60    else
61      cmd = Proc.new
62    end
63    _bind_for_event_class(Event_for_Items, [path, 'bindImage'],
64                          context, cmd, *args)
65    self
66  end
67
68  #def imagebind_append(*args)
69  #  _bind_append_for_event_class(Event_for_Items, [path, 'bindImage'], *args)
70  #  self
71  #end
72  def imagebind_append(context, *args)
73    #if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
74    if TkComm._callback_entry?(args[0]) || !block_given?
75      cmd = args.shift
76    else
77      cmd = Proc.new
78    end
79    _bind_append_for_event_class(Event_for_Items, [path, 'bindImage'],
80                                 context, cmd, *args)
81    self
82  end
83
84  def imagebind_remove(*args)
85    _bind_remove_for_event_class(Event_for_Items, [path, 'bindImage'], *args)
86    self
87  end
88
89  def imagebindinfo(*args)
90    _bindinfo_for_event_class(Event_for_Items, [path, 'bindImage'], *args)
91  end
92
93  #def textbind(*args)
94  #  _bind_for_event_class(Event_for_Items, [path, 'bindText'], *args)
95  #  self
96  #end
97  def textbind(context, *args)
98    #if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
99    if TkComm._callback_entry?(args[0]) || !block_given?
100      cmd = args.shift
101    else
102      cmd = Proc.new
103    end
104    _bind_for_event_class(Event_for_Items, [path, 'bindText'],
105                          context, cmd, *args)
106    self
107  end
108
109  #def textbind_append(*args)
110  #  _bind_append_for_event_class(Event_for_Items, [path, 'bindText'], *args)
111  #  self
112  #end
113  def textbind_append(context, *args)
114    #if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
115    if TkComm._callback_entry?(args[0]) || !block_given?
116      cmd = args.shift
117    else
118      cmd = Proc.new
119    end
120    _bind_append_for_event_class(Event_for_Items, [path, 'bindText'],
121                                 context, cmd, *args)
122    self
123  end
124
125  def textbind_remove(*args)
126    _bind_remove_for_event_class(Event_for_Items, [path, 'bindText'], *args)
127    self
128  end
129
130  def textbindinfo(*args)
131    _bindinfo_for_event_class(Event_for_Items, [path, 'bindText'], *args)
132  end
133
134  def delete(*args)
135    tk_send('delete', *args)
136    self
137  end
138
139  def edit(item, text, *args)
140    tk_send('edit', tagid(item), text, *args)
141    self
142  end
143
144  def exist?(item)
145    bool(tk_send('exists', tagid(item)))
146  end
147
148  def index(item)
149    num_or_str(tk_send('index', tagid(item)))
150  end
151
152  def insert(idx, item, keys={})
153    tk_send('insert', idx, tagid(item), *hash_kv(keys))
154    self
155  end
156
157  def get_item(idx)
158    tk_send('items', idx)
159  end
160
161  def items(first=None, last=None)
162    list(tk_send('items', first, last))
163  end
164
165  def move(item, idx)
166    tk_send('move', tagid(item), idx)
167    self
168  end
169
170  def reorder(neworder)
171    tk_send('reorder', neworder)
172    self
173  end
174
175  def see(item)
176    tk_send('see', tagid(item))
177    self
178  end
179
180  def selection_clear
181    tk_send_without_enc('selection', 'clear')
182    self
183  end
184
185  def selection_set(*args)
186    tk_send_without_enc('selection', 'set',
187                        *(args.collect{|item| tagid(item)}))
188    self
189  end
190
191  def selection_add(*args)
192    tk_send_without_enc('selection', 'add',
193                        *(args.collect{|item| tagid(item)}))
194    self
195  end
196
197  def selection_remove(*args)
198    tk_send_without_enc('selection', 'remove',
199                        *(args.collect{|item| tagid(item)}))
200    self
201  end
202
203  def selection_get(*args)
204    simplelist(tk_send_without_enc('selection', 'get')).collect{|item|
205      Tk::BWidget::ListBox::Item.id2obj(self, item)
206    }
207  end
208end
209
210class Tk::BWidget::ListBox::Item
211  include TkTreatTagFont
212
213  ListItem_TBL = TkCore::INTERP.create_table
214
215  (ListItem_ID = ['bw:item'.freeze, TkUtil.untrust('00000')]).instance_eval{
216    @mutex = Mutex.new
217    def mutex; @mutex; end
218    freeze
219  }
220
221  TkCore::INTERP.init_ip_env{
222    ListItem_TBL.mutex.synchronize{ ListItem_TBL.clear }
223  }
224
225  def self.id2obj(lbox, id)
226    lpath = lbox.path
227    ListItem_TBL.mutex.synchronize{
228      if ListItem_TBL[lpath]
229        ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id
230      else
231        id
232      end
233    }
234  end
235
236  def initialize(lbox, *args)
237    if lbox.kind_of?(Tk::BWidget::ListBox)
238      @listbox = lbox
239    else
240      fail RuntimeError,
241        "expect Tk::BWidget::ListBox or Tk::BWidget::ListBox::Item for 1st argument"
242    end
243
244    if args[-1].kind_of?(Hash)
245      keys = _symbolkey2str(args.pop)
246    else
247      keys = {}
248    end
249
250    index = keys.delete('index')
251    unless args.empty?
252      index = args.shift
253    end
254    index = 'end' unless index
255
256    unless args.empty?
257      fail RuntimeError, 'too much arguments'
258    end
259
260    @lpath = @listbox.path
261
262    if keys.key?('itemname')
263      @path = @id = keys.delete('itemname')
264    else
265      ListItem_ID.mutex.synchronize{
266        @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_)
267        ListItem_ID[1].succ!
268      }
269    end
270
271    ListItem_TBL.mutex.synchronize{
272      ListItem_TBL[@id] = self
273      ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath]
274      ListItem_TBL[@lpath][@id] = self
275    }
276
277    @listbox.insert(index, @id, keys)
278  end
279
280  def listbox
281    @listbox
282  end
283
284  def id
285    @id
286  end
287
288  def [](key)
289    cget(key)
290  end
291
292  def []=(key, val)
293    configure(key, val)
294    val
295  end
296
297  def cget_tkstring(key)
298    @listbox.itemcget_tkstring(@id, key)
299  end
300  def cget(key)
301    @listbox.itemcget(@id, key)
302  end
303  def cget_strict(key)
304    @listbox.itemcget_strict(@id, key)
305  end
306
307  def configure(key, val=None)
308    @listbox.itemconfigure(@id, key, val)
309  end
310
311  def configinfo(key=nil)
312    @listbox.itemconfiginfo(@id, key)
313  end
314
315  def current_configinfo(key=nil)
316    @listbox.current_itemconfiginfo(@id, key)
317  end
318
319  def delete
320    @listbox.delete(@id)
321    self
322  end
323
324  def edit(*args)
325    @listbox.edit(@id, *args)
326    self
327  end
328
329  def exist?
330    @listbox.exist?(@id)
331  end
332
333  def index
334    @listbox.index(@id)
335  end
336
337  def move(index)
338    @listbox.move(@id, index)
339  end
340
341  def see
342    @listbox.see(@id)
343  end
344
345  def selection_add
346    @listbox.selection_add(@id)
347  end
348
349  def selection_remove
350    @listbox.selection_remove(@id)
351  end
352
353  def selection_set
354    @listbox.selection_set(@id)
355  end
356
357  def selection_toggle
358    @listbox.selection_toggle(@id)
359  end
360end
361
362