1#
2#  tkextlib/blt/component.rb
3#                               by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
4#
5
6require 'tk'
7require 'tkextlib/blt.rb'
8
9module Tk::BLT
10  module PlotComponent
11    include TkItemConfigMethod
12
13    module OptKeys
14      def __item_font_optkeys(id)
15        ['font', 'tickfont', 'titlefont']
16      end
17      private :__item_font_optkeys
18
19      def __item_numstrval_optkeys(id)
20        ['xoffset', 'yoffset']
21      end
22      private :__item_numstrval_optkeys
23
24      def __item_boolval_optkeys(id)
25        ['hide', 'under', 'descending', 'logscale', 'loose', 'showticks',
26          'titlealternate', 'scalesymbols', 'minor', 'raised',
27          'center', 'decoration', 'landscape', 'maxpect']
28      end
29      private :__item_boolval_optkeys
30
31      def __item_strval_optkeys(id)
32        ['text', 'label', 'limits', 'title',
33          'show', 'file', 'maskdata', 'maskfile',
34          'color', 'titlecolor', 'fill', 'outline', 'offdash']
35      end
36      private :__item_strval_optkeys
37
38      def __item_listval_optkeys(id)
39        ['bindtags']
40      end
41      private :__item_listval_optkeys
42
43      def __item_numlistval_optkeys(id)
44        ['dashes', 'majorticks', 'minorticks']
45      end
46      private :__item_numlistval_optkeys
47
48      def __item_tkvariable_optkeys(id)
49        ['variable', 'textvariable', 'colormap', 'fontmap']
50      end
51      private :__item_tkvariable_optkeys
52    end
53
54    include OptKeys
55
56    def __item_cget_cmd(id)
57      if id.kind_of?(Array)
58        # id := [ type, name ]
59        [self.path, id[0], 'cget', id[1]]
60      else
61        [self.path, id, 'cget']
62      end
63    end
64    private :__item_cget_cmd
65
66    def __item_config_cmd(id)
67      if id.kind_of?(Array)
68        # id := [ type, name, ... ]
69        type, *names = id
70        [self.path, type, 'configure'].concat(names)
71      else
72        [self.path, id, 'configure']
73      end
74    end
75    private :__item_config_cmd
76
77    def __item_pathname(id)
78      if id.kind_of?(Array)
79        id = tagid(id[1])
80      end
81      [self.path, id].join(';')
82    end
83    private :__item_pathname
84
85    def axis_cget_tkstring(id, option)
86      ret = itemcget_tkstring(['axis', tagid(id)], option)
87    end
88    def axis_cget(id, option)
89      ret = itemcget(['axis', tagid(id)], option)
90    end
91    def axis_cget_strict(id, option)
92      ret = itemcget_strict(['axis', tagid(id)], option)
93    end
94    def axis_configure(*args)
95      slot = args.pop
96      if slot.kind_of?(Hash)
97        value = None
98        slot = _symbolkey2str(slot)
99        if cmd = slot.delete('command')
100          slot['command'] = proc{|w, tick|
101            cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
102          }
103        end
104      else
105        value = slot
106        slot = args.pop
107        if slot == :command || slot == 'command'
108          cmd = value
109          value = proc{|w, tick|
110            cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
111          }
112        end
113      end
114      id_list = args.flatten.collect!{|id| tagid(id)}.unshift('axis')
115      itemconfigure(id_list, slot, value)
116    end
117    def axis_configinfo(id, slot=nil)
118      itemconfiginfo(['axis', tagid(id)], slot)
119    end
120    def current_axis_configinfo(id, slot=nil)
121      current_itemconfiginfo(['axis', tagid(id)], slot)
122    end
123
124    def crosshairs_cget_tkstring(option)
125      itemcget_tkstring('crosshairs', option)
126    end
127    def crosshairs_cget(option)
128      itemcget('crosshairs', option)
129    end
130    def crosshairs_cget_strict(option)
131      itemcget_strict('crosshairs', option)
132    end
133    def crosshairs_configure(slot, value=None)
134      itemconfigure('crosshairs', slot, value)
135    end
136    def crosshairs_configinfo(slot=nil)
137      itemconfiginfo('crosshairs', slot)
138    end
139    def current_crosshairs_configinfo(slot=nil)
140      current_itemconfiginfo('crosshairs', slot)
141    end
142
143    def element_cget_tkstring(id, option)
144      itemcget_tkstring(['element', tagid(id)], option)
145    end
146    def element_cget(id, option)
147      itemcget(['element', tagid(id)], option)
148    end
149    def element_cget_strict(id, option)
150      itemcget_strict(['element', tagid(id)], option)
151    end
152    def element_configure(*args)
153      slot = args.pop
154      if slot.kind_of?(Hash)
155        value = None
156      else
157        value = slot
158        slot = args.pop
159      end
160      id_list = args.flatten.collect!{|id| tagid(id)}.unshift('element')
161      itemconfigure(id_list, slot, value)
162    end
163    def element_configinfo(id, slot=nil)
164      itemconfiginfo(['element', tagid(id)], slot)
165    end
166    def current_element_configinfo(id, slot=nil)
167      current_itemconfiginfo(['element', tagid(id)], slot)
168    end
169
170    def bar_cget_tkstring(id, option)
171      itemcget_tkstring(['bar', tagid(id)], option)
172    end
173    def bar_cget(id, option)
174      itemcget(['bar', tagid(id)], option)
175    end
176    def bar_cget_strict(id, option)
177      itemcget_strict(['bar', tagid(id)], option)
178    end
179    def bar_configure(*args)
180      slot = args.pop
181      if slot.kind_of?(Hash)
182        value = None
183      else
184        value = slot
185        slot = args.pop
186      end
187      id_list = args.flatten.collect!{|id| tagid(id)}.unshift('bar')
188      itemconfigure(id_list, slot, value)
189    end
190    def bar_configinfo(id, slot=nil)
191      itemconfiginfo(['bar', tagid(id)], slot)
192    end
193    def current_bar_configinfo(id, slot=nil)
194      current_itemconfiginfo(['bar', tagid(id)], slot)
195    end
196
197    def line_cget_tkstring(id, option)
198      itemcget_tkstring(['line', tagid(id)], option)
199    end
200    def line_cget(id, option)
201      itemcget(['line', tagid(id)], option)
202    end
203    def line_cget_strict(id, option)
204      itemcget_strict(['line', tagid(id)], option)
205    end
206    def line_configure(*args)
207      slot = args.pop
208      if slot.kind_of?(Hash)
209        value = None
210      else
211        value = slot
212        slot = args.pop
213      end
214      id_list = args.flatten.collect!{|id| tagid(id)}.unshift('line')
215      itemconfigure(id_list, slot, value)
216    end
217    def line_configinfo(id, slot=nil)
218      itemconfiginfo(['line', tagid(id)], slot)
219    end
220    def current_line_configinfo(id, slot=nil)
221      current_itemconfiginfo(['line', tagid(id)], slot)
222    end
223
224    def gridline_cget_tkstring(option)
225      itemcget_tkstring('grid', option)
226    end
227    def gridline_cget(option)
228      itemcget('grid', option)
229    end
230    def gridline_cget_strict(option)
231      itemcget_strict('grid', option)
232    end
233    def gridline_configure(slot, value=None)
234      itemconfigure('grid', slot, value)
235    end
236    def gridline_configinfo(slot=nil)
237      itemconfiginfo('grid', slot)
238    end
239    def current_gridline_configinfo(slot=nil)
240      current_itemconfiginfo('grid', slot)
241    end
242
243    def legend_cget_tkstring(option)
244      itemcget_tkstring('legend', option)
245    end
246    def legend_cget(option)
247      itemcget('legend', option)
248    end
249    def legend_cget_strict(option)
250      itemcget_strict('legend', option)
251    end
252    def legend_configure(slot, value=None)
253      itemconfigure('legend', slot, value)
254    end
255    def legend_configinfo(slot=nil)
256      itemconfiginfo('legend', slot)
257    end
258    def current_legend_configinfo(slot=nil)
259      current_itemconfiginfo('legend', slot)
260    end
261
262    def pen_cget_tkstring(id, option)
263      itemcget_tkstring(['pen', tagid(id)], option)
264    end
265    def pen_cget(id, option)
266      itemcget(['pen', tagid(id)], option)
267    end
268    def pen_cget_strict(id, option)
269      itemcget_strict(['pen', tagid(id)], option)
270    end
271    def pen_configure(*args)
272      slot = args.pop
273      if slot.kind_of?(Hash)
274        value = None
275      else
276        value = slot
277        slot = args.pop
278      end
279      id_list = args.flatten.collect!{|id| tagid(id)}.unshift('pen')
280      itemconfigure(id_list, slot, value)
281    end
282    def pen_configinfo(id, slot=nil)
283      itemconfiginfo(['pen', tagid(id)], slot)
284    end
285    def current_pen_configinfo(id, slot=nil)
286      current_itemconfiginfo(['pen', tagid(id)], slot)
287    end
288
289    def postscript_cget_tkstring(option)
290      itemcget_tkstring('postscript', option)
291    end
292    def postscript_cget(option)
293      itemcget('postscript', option)
294    end
295    def postscript_cget_strict(option)
296      itemcget_strict('postscript', option)
297    end
298    def postscript_configure(slot, value=None)
299      itemconfigure('postscript', slot, value)
300    end
301    def postscript_configinfo(slot=nil)
302      itemconfiginfo('postscript', slot)
303    end
304    def current_postscript_configinfo(slot=nil)
305      current_itemconfiginfo('postscript', slot)
306    end
307
308    def marker_cget_tkstring(id, option)
309      itemcget_tkstring(['marker', tagid(id)], option)
310    end
311    def marker_cget(id, option)
312      itemcget(['marker', tagid(id)], option)
313    end
314    def marker_cget_strict(id, option)
315      itemcget_strict(['marker', tagid(id)], option)
316    end
317    def marker_configure(*args)
318      slot = args.pop
319      if slot.kind_of?(Hash)
320        value = None
321      else
322        value = slot
323        slot = args.pop
324      end
325      id_list = args.flatten.collect!{|id| tagid(id)}.unshift('marker')
326      itemconfigure(id_list, slot, value)
327    end
328    def marker_configinfo(id, slot=nil)
329      itemconfiginfo(['marker', tagid(id)], slot)
330    end
331    def current_marker_configinfo(id, slot=nil)
332      current_itemconfiginfo(['marker', tagid(id)], slot)
333    end
334
335    alias __itemcget_tkstring itemcget_tkstring
336    alias __itemcget itemcget
337    alias __itemcget_strict itemcget_strict
338    alias __itemconfiginfo itemconfiginfo
339    alias __current_itemconfiginfo current_itemconfiginfo
340    private :__itemcget_tkstring, :__itemcget, :__itemconfiginfo, :__current_itemconfiginfo
341
342    def itemcget_tkstring(tagOrId, option)
343      __itemcget_tkstring(tagid(tagOrId), option)
344    end
345    def itemcget_strict(tagOrId, option)
346      ret = __itemcget(tagid(tagOrId), option)
347      if option == 'bindtags' || option == :bindtags
348        ret.collect{|tag| TkBindTag.id2obj(tag)}
349      else
350        ret
351      end
352    end
353    def itemcget(tagOrId, option)
354      unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
355        itemcget_strict(tagOrId, option)
356      else
357        begin
358          itemcget_strict(tagOrId, option)
359        rescue => e
360          begin
361            if current_itemconfiginfo(tagOrId).has_key?(option.to_s)
362              # error on known option
363              fail e
364            else
365              # unknown option
366              nil
367            end
368          rescue
369            fail e  # tag error
370          end
371        end
372      end
373    end
374    def itemconfiginfo(tagOrId, slot = nil)
375      ret = __itemconfiginfo(tagid(tagOrId), slot)
376
377      if TkComm::GET_CONFIGINFO_AS_ARRAY
378        if slot
379          if slot == 'bindtags' || slot == :bindtags
380            ret[-2] = ret[-2].collect{|tag| TkBindTag.id2obj(tag)}
381            ret[-1] = ret[-1].collect{|tag| TkBindTag.id2obj(tag)}
382          end
383        else
384          if (inf = ret.assoc('bindtags'))
385            inf[-2] = inf[-2].collect{|tag| TkBindTag.id2obj(tag)}
386            inf[-1] = inf[-1].collect{|tag| TkBindTag.id2obj(tag)}
387          end
388        end
389
390      else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
391        if (inf = ret['bindtags'])
392          inf[-2] = inf[-2].collect{|tag| TkBindTag.id2obj(tag)}
393          inf[-1] = inf[-1].collect{|tag| TkBindTag.id2obj(tag)}
394          ret['bindtags'] = inf
395        end
396      end
397
398      ret
399    end
400    def current_itemconfiginfo(tagOrId, slot = nil)
401      ret = __current_itemconfiginfo(tagid(tagOrId), slot)
402
403      if (val = ret['bindtags'])
404        ret['bindtags'] = val.collect{|tag| TkBindTag.id2obj(tag)}
405      end
406
407      ret
408    end
409
410    private :itemcget_tkstring, :itemcget, :itemcget_strict
411    private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
412
413    #################
414
415    class Axis < TkObject
416      (OBJ_ID = ['blt_chart_axis'.freeze, TkUtil.untrust('00000')]).instance_eval{
417        @mutex = Mutex.new
418        def mutex; @mutex; end
419        freeze
420      }
421
422      AxisID_TBL = TkCore::INTERP.create_table
423
424      TkCore::INTERP.init_ip_env{
425        AxisID_TBL.mutex.synchronize{ AxisID_TBL.clear }
426      }
427
428      def self.id2obj(chart, id)
429        cpath = chart.path
430        AxisID_TBL.mutex.synchronize{
431          return id unless AxisID_TBL[cpath]
432          AxisID_TBL[cpath][id]? AxisID_TBL[cpath][id]: id
433        }
434      end
435
436      def self.new(chart, axis=nil, keys={})
437        if axis.kind_of?(Hash)
438          keys = axis
439          axis = nil
440        end
441        if keys
442          keys = _symbolkey2str(keys)
443          not_create = keys.delete('without_creating')
444        else
445          not_create = false
446        end
447
448        obj = nil
449        AxisID_TBL.mutex.synchronize{
450          chart_path = chart.path
451          AxisID_TBL[chart_path] ||= {}
452          if axis && AxisID_TBL[chart_path][axis]
453            obj = AxisID_TBL[chart_path][axis]
454          else
455            (obj = self.allocate).instance_eval{
456              if axis
457                @axis = @id = axis.to_s
458              else
459                OBJ_ID.mutex.synchronize{
460                  @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
461                  OBJ_ID[1].succ!
462                }
463              end
464              @path = @id
465              @parent = @chart = chart
466              @cpath = @chart.path
467              Axis::AxisID_TBL[@cpath][@axis] = self
468              unless not_create
469                tk_call(@chart, 'axis', 'create', @axis, keys)
470                return obj
471              end
472            }
473          end
474        }
475
476        obj.configure(keys) if obj && ! keys.empty?
477        obj
478      end
479
480      def initialize(chart, axis=nil, keys={})
481        # dummy:: not called by 'new' method
482
483        if axis.kind_of?(Hash)
484          keys = axis
485          axis = nil
486        end
487        if axis
488          @axis = @id = axis.to_s
489        else
490          OBJ_ID.mutex.synchronize{
491            @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
492            OBJ_ID[1].succ!
493          }
494        end
495        @path = @id
496        @parent = @chart = chart
497        @cpath = @chart.path
498        # Axis::AxisID_TBL[@cpath][@axis] = self
499        keys = _symbolkey2str(keys)
500        unless keys.delete('without_creating')
501          # @chart.axis_create(@axis, keys)
502          tk_call(@chart, 'axis', 'create', @axis, keys)
503        end
504      end
505
506      def id
507        @id
508      end
509
510      def to_eval
511        @id
512      end
513
514      def cget_tkstring(option)
515        @chart.axis_cget_tkstring(@id, option)
516      end
517      def cget(option)
518        @chart.axis_cget(@id, option)
519      end
520      def cget_strict(option)
521        @chart.axis_cget_strict(@id, option)
522      end
523      def configure(key, value=None)
524        @chart.axis_configure(@id, key, value)
525        self
526      end
527      def configinfo(key=nil)
528        @chart.axis_configinfo(@id, key)
529      end
530      def current_configinfo(key=nil)
531        @chart.current_axis_configinfo(@id, key)
532      end
533
534      def command(cmd=nil, &b)
535        if cmd
536          configure('command', cmd)
537        elsif b
538          configure('command', Proc.new(&b))
539        else
540          cget('command')
541        end
542      end
543
544      def delete
545        @chart.axis_delete(@id)
546        self
547      end
548
549      def invtransform(val)
550        @chart.axis_invtransform(@id, val)
551      end
552
553      def limits
554        @chart.axis_limits(@id)
555      end
556
557      def name
558        @axis
559      end
560
561      def transform(val)
562        @chart.axis_transform(@id, val)
563      end
564
565      def view
566        @chart.axis_view(@id)
567        self
568      end
569
570      def use(name=None) # if @id == xaxis | x2axis | yaxis | y2axis
571        @chart.axis_use(@id, name)
572      end
573
574      def use_as(axis) # axis := xaxis | x2axis | yaxis | y2axis
575        @chart.axis_use(axis, @id)
576      end
577    end
578
579    #################
580
581    class Crosshairs < TkObject
582      CrosshairsID_TBL = TkCore::INTERP.create_table
583
584      TkCore::INTERP.init_ip_env{
585        CrosshairsID_TBL.mutex.synchronize{ CrosshairsID_TBL.clear }
586      }
587
588      def self.new(chart, keys={})
589        obj = nil
590        CrosshairsID_TBL.mutex.synchronize{
591          unless (obj = CrosshairsID_TBL[chart.path])
592            (obj = self.allocate).instance_eval{
593              @parent = @chart = chart
594              @cpath = @chart.path
595              @path = @id = 'crosshairs'
596              Crosshairs::CrosshairsID_TBL[@cpath] = self
597            }
598          end
599        }
600        chart.crosshair_configure(keys) if obj && ! keys.empty?
601        obj
602      end
603
604      def initialize(chart, keys={})
605        # dummy:: not called by 'new' method
606
607        @parent = @chart = chart
608        @cpath = @chart.path
609        # Crosshairs::CrosshairsID_TBL[@cpath] = self
610        @chart.crosshair_configure(keys) unless keys.empty?
611        @path = @id = 'crosshairs'
612      end
613
614      def id
615        @id
616      end
617
618      def to_eval
619        @id
620      end
621
622      def cget_tkstring(option)
623        @chart.crosshair_cget_tkstring(option)
624      end
625      def cget(option)
626        @chart.crosshair_cget(option)
627      end
628      def cget_strict(option)
629        @chart.crosshair_cget_strict(option)
630      end
631      def configure(key, value=None)
632        @chart.crosshair_configure(key, value)
633        self
634      end
635      def configinfo(key=nil)
636        @chart.crosshair_configinfo(key)
637      end
638      def current_configinfo(key=nil)
639        @chart.current_crosshair_configinfo(key)
640      end
641
642      def off
643        @chart.crosshair_off
644        self
645      end
646      def on
647        @chart.crosshair_on
648        self
649      end
650      def toggle
651        @chart.crosshair_toggle
652        self
653      end
654    end
655
656    #################
657
658    class Element < TkObject
659      extend Tk
660      extend TkItemFontOptkeys
661      extend TkItemConfigOptkeys
662
663      extend Tk::BLT::PlotComponent::OptKeys
664
665      ElementTypeName = 'element'
666      ElementTypeToClass = { ElementTypeName=>self }
667
668      ElementID_TBL = TkCore::INTERP.create_table
669
670      TkCore::INTERP.init_ip_env{
671        ElementID_TBL.mutex.synchronize{ ElementID_TBL.clear }
672      }
673
674      (OBJ_ID = ['blt_chart_element'.freeze, TkUtil.untrust('00000')]).instance_eval{
675        @mutex = Mutex.new
676        def mutex; @mutex; end
677        freeze
678      }
679
680      def Element.type2class(type)
681        ElementTypeToClass[type]
682      end
683
684      def Element.id2obj(chart, id)
685        cpath = chart.path
686        ElementID_TBL.mutex.synchronize{
687          return id unless ElementID_TBL[cpath]
688          ElementID_TBL[cpath][id]? ElementID_TBL[cpath][id]: id
689        }
690      end
691
692      def self.new(chart, element=nil, keys={})
693        if element.kind_of?(Hash)
694          keys = element
695          element = nil
696        end
697        if keys
698          keys = _symbolkey2str(keys)
699          not_create = keys.delete('without_creating')
700        else
701          not_create = false
702        end
703
704        obj = nil
705        ElementID_TBL.mutex.synchronize{
706          chart_path = chart.path
707          ElementID_TBL[chart_path] ||= {}
708          if element && ElementID_TBL[chart_path][element]
709            obj = ElementID_TBL[chart_path][element]
710          else
711            (obj = self.allocate).instance_eval{
712              if element
713                @element = @id = element.to_s
714              else
715                OBJ_ID.mutex.synchronize{
716                  @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
717                  OBJ_ID[1].succ!
718                }
719              end
720              @path = @id
721              @parent = @chart = chart
722              @cpath = @chart.path
723              @typename = self.class::ElementTypeName
724              Element::ElementID_TBL[@cpath][@element] = self
725              unless not_create
726                tk_call(@chart, @typename, 'create', @element, keys)
727                return obj
728              end
729            }
730          end
731        }
732
733        obj.configure(keys) if obj && ! keys.empty?
734        obj
735      end
736
737      def initialize(chart, element=nil, keys={})
738        # dummy:: not called by 'new' method
739
740        if element.kind_of?(Hash)
741          keys = element
742          element = nil
743        end
744        if element
745          @element = @id = element.to_s
746        else
747          OBJ_ID.mutex.synchronize{
748            @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
749            OBJ_ID[1].succ!
750          }
751        end
752        @path = @id
753        @parent = @chart = chart
754        @cpath = @chart.path
755        @typename = self.class::ElementTypeName
756        # Element::ElementID_TBL[@cpath][@element] = self
757        keys = _symbolkey2str(keys)
758        unless keys.delete('without_creating')
759          # @chart.element_create(@element, keys)
760          tk_call(@chart, @typename, 'create', @element, keys)
761        end
762      end
763
764      def id
765        @id
766      end
767
768      def to_eval
769        @id
770      end
771
772      def cget_tkstring(option)
773        # @chart.element_cget(@id, option)
774        @chart.__send__(@typename + '_cget_tkstring', @id, option)
775      end
776      def cget(option)
777        # @chart.element_cget(@id, option)
778        @chart.__send__(@typename + '_cget', @id, option)
779      end
780      def cget_strict(option)
781        @chart.__send__(@typename + '_cget_strict', @id, option)
782      end
783      def configure(key, value=None)
784        # @chart.element_configure(@id, key, value)
785        @chart.__send__(@typename + '_configure', @id, key, value)
786        self
787      end
788      def configinfo(key=nil)
789        # @chart.element_configinfo(@id, key)
790        @chart.__send__(@typename + '_configinfo', @id, key)
791      end
792      def current_configinfo(key=nil)
793        # @chart.current_element_configinfo(@id, key)
794        @chart.__send__('current_' << @typename << '_configinfo', @id, key)
795      end
796
797      def activate(*args)
798        @chart.element_activate(@id, *args)
799      end
800
801      def closest(x, y, var, keys={})
802        # @chart.element_closest(x, y, var, @id, keys)
803        @chart.__send__(@typename + '_closest', x, y, var, @id, keys)
804      end
805
806      def deactivate
807        @chart.element_deactivate(@id)
808        self
809      end
810
811      def delete
812        @chart.element_delete(@id)
813        self
814      end
815
816      def exist?
817        @chart.element_exist?(@id)
818      end
819
820      def name
821        @element
822      end
823
824      def type
825        @chart.element_type(@id)
826      end
827    end
828
829    class Bar < Element
830      ElementTypeName = 'bar'.freeze
831      ElementTypeToClass[ElementTypeName] = self
832    end
833    class Line < Element
834      ElementTypeName = 'line'.freeze
835      ElementTypeToClass[ElementTypeName] = self
836    end
837
838    #################
839
840    class GridLine < TkObject
841      GridLineID_TBL = TkCore::INTERP.create_table
842      TkCore::INTERP.init_ip_env{
843        GridLineID_TBL.mutex.synchronize{ GridLineID_TBL.clear }
844      }
845
846      def self.new(chart, keys={})
847        obj = nil
848        GridLineID_TBL.mutex.synchronize{
849          unless (obj = GridLineID_TBL[chart.path])
850            (obj = self.allocate).instance_eval{
851              @parent = @chart = chart
852              @cpath = @chart.path
853              @path = @id = 'grid'
854              GridLine::GridLineID_TBL[@cpath] = self
855            }
856          end
857        }
858        chart.gridline_configure(keys) if obj && ! keys.empty?
859        obj
860      end
861
862      def initialize(chart, keys={})
863        # dummy:: not called by 'new' method
864
865        @parent = @chart = chart
866        @cpath = @chart.path
867        # GridLine::GridLineID_TBL[@cpath] = self
868        @chart.gridline_configure(keys) unless keys.empty?
869        @path = @id = 'grid'
870      end
871
872      def id
873        @id
874      end
875
876      def to_eval
877        @id
878      end
879
880      def cget_tkstring(option)
881        @chart.gridline_cget_tkstring(option)
882      end
883      def cget(option)
884        @chart.gridline_cget(option)
885      end
886      def cget_strict(option)
887        @chart.gridline_cget_strict(option)
888      end
889      def configure(key, value=None)
890        @chart.gridline_configure(key, value)
891        self
892      end
893      def configinfo(key=nil)
894        @chart.gridline_configinfo(key)
895      end
896      def current_configinfo(key=nil)
897        @chart.current_gridline_configinfo(key)
898      end
899
900      def off
901        @chart.gridline_off
902        self
903      end
904      def on
905        @chart.gridline_on
906        self
907      end
908      def toggle
909        @chart.gridline_toggle
910        self
911      end
912    end
913
914    #################
915
916    class Legend < TkObject
917      LegendID_TBL = TkCore::INTERP.create_table
918
919      TkCore::INTERP.init_ip_env{
920        LegendID_TBL.mutex.synchronize{ LegendID_TBL.clear }
921      }
922
923      def self.new(chart, keys={})
924        obj = nil
925        LegenedID_TBL.mutex.synchronize{
926          unless (obj = LegenedID_TBL[chart.path])
927            (obj = self.allocate).instance_eval{
928              @parent = @chart = chart
929              @cpath = @chart.path
930              @path = @id = 'crosshairs'
931              Legend::LegenedID_TBL[@cpath] = self
932            }
933          end
934        }
935        chart.legend_configure(keys) if obj && ! keys.empty?
936        obj
937      end
938
939      def initialize(chart, keys={})
940        # dummy:: not called by 'new' method
941
942        @parent = @chart = chart
943        @cpath = @chart.path
944        # Legend::LegendID_TBL[@cpath] = self
945        @chart.legend_configure(keys) unless keys.empty?
946        @path = @id = 'legend'
947      end
948
949      def id
950        @id
951      end
952
953      def to_eval
954        @id
955      end
956
957      def cget_tkstring(option)
958        @chart.legend_cget_tkstring(option)
959      end
960      def cget(option)
961        @chart.legend_cget(option)
962      end
963      def cget_strict(option)
964        @chart.legend_cget_strict(option)
965      end
966      def configure(key, value=None)
967        @chart.legend_configure(key, value)
968        self
969      end
970      def configinfo(key=nil)
971        @chart.legend_configinfo(key)
972      end
973      def current_configinfo(key=nil)
974        @chart.current_legend_configinfo(key)
975      end
976
977      def activate(*args)
978        @chart.legend_activate(*args)
979      end
980
981      def deactivate(*args)
982        @chart.legend_deactivate(*args)
983      end
984
985      def get(pos, y=nil)
986        @chart.legend_get(pos, y)
987      end
988    end
989
990    #################
991
992    class Pen < TkObject
993      (OBJ_ID = ['blt_chart_pen'.freeze, TkUtil.untrust('00000')]).instance_eval{
994        @mutex = Mutex.new
995        def mutex; @mutex; end
996        freeze
997      }
998
999      PenID_TBL = TkCore::INTERP.create_table
1000
1001      TkCore::INTERP.init_ip_env{
1002        PenID_TBL.mutex.synchronize{ PenID_TBL.clear }
1003      }
1004
1005      def self.id2obj(chart, id)
1006        cpath = chart.path
1007        PenID_TBL.mutex.synchronize{
1008          return id unless PenID_TBL[cpath]
1009          PenID_TBL[cpath][id]? PenID_TBL[cpath][id]: id
1010        }
1011      end
1012
1013      def self.new(chart, pen=nil, keys={})
1014        if pen.kind_of?(Hash)
1015          keys = pen
1016          pen = nil
1017        end
1018        if keys
1019          keys = _symbolkey2str(keys)
1020          not_create = keys.delete('without_creating')
1021        else
1022          not_create = false
1023        end
1024
1025        obj = nil
1026        PenID_TBL.mutex.synchronize{
1027          chart_path = chart.path
1028          PenID_TBL[chart_path] ||= {}
1029          if pen && PenID_TBL[chart_path][pen]
1030            obj = PenID_TBL[chart_path][pen]
1031          else
1032            (obj = self.allocate).instance_eval{
1033              if pen
1034                @pen = @id = pen.to_s
1035              else
1036                OBJ_ID.mutex.synchronize{
1037                  @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
1038                  OBJ_ID[1].succ!
1039                }
1040              end
1041              @path = @id
1042              @parent = @chart = chart
1043              @cpath = @chart.path
1044              Pen::PenID_TBL[@cpath][@pen] = self
1045              unless not_create
1046                tk_call(@chart, 'pen', 'create', @pen, keys)
1047                return obj
1048              end
1049            }
1050          end
1051        }
1052
1053        obj.configure(keys) if obj && ! keys.empty?
1054        obj
1055      end
1056
1057      def initialize(chart, pen=nil, keys={})
1058        if pen.kind_of?(Hash)
1059          keys = pen
1060          pen = nil
1061        end
1062        if pen
1063          @pen = @id = pen.to_s
1064        else
1065          OBJ_ID.mutex.synchronize{
1066            @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
1067            OBJ_ID[1].succ!
1068          }
1069        end
1070        @path = @id
1071        @parent = @chart = chart
1072        @cpath = @chart.path
1073        Pen::PenID_TBL[@cpath][@pen] = self
1074        keys = _symbolkey2str(keys)
1075        unless keys.delete('without_creating')
1076          # @chart.pen_create(@pen, keys)
1077          tk_call(@chart, 'pen', 'create', @pen, keys)
1078        end
1079      end
1080
1081      def id
1082        @id
1083      end
1084
1085      def to_eval
1086        @id
1087      end
1088
1089      def cget_tkstring(option)
1090        @chart.pen_cget_tkstring(@id, option)
1091      end
1092      def cget(option)
1093        @chart.pen_cget(@id, option)
1094      end
1095      def cget_strict(option)
1096        @chart.pen_cget_strict(@id, option)
1097      end
1098      def configure(key, value=None)
1099        @chart.pen_configure(@id, key, value)
1100        self
1101      end
1102      def configinfo(key=nil)
1103        @chart.pen_configinfo(@id, key)
1104      end
1105      def current_configinfo(key=nil)
1106        @chart.current_pen_configinfo(@id, key)
1107      end
1108
1109      def delete
1110        @chart.pen_delete(@id)
1111        self
1112      end
1113
1114      def name
1115        @pen
1116      end
1117    end
1118
1119    #################
1120
1121    class Postscript < TkObject
1122      PostscriptID_TBL = TkCore::INTERP.create_table
1123
1124      TkCore::INTERP.init_ip_env{
1125        PostscriptID_TBL.mutex.synchronize{ PostscriptID_TBL.clear }
1126      }
1127
1128      def self.new(chart, keys={})
1129        obj = nil
1130        PostscriptID_TBL.mutex.synchronize{
1131          unless (obj = PostscriptID_TBL[chart.path])
1132            (obj = self.allocate).instance_eval{
1133              @parent = @chart = chart
1134              @cpath = @chart.path
1135              @path = @id = 'postscript'
1136              Postscript::PostscriptID_TBL[@cpath] = self
1137            }
1138          end
1139        }
1140        chart.postscript_configure(keys) if obj && ! keys.empty?
1141        obj
1142      end
1143
1144      def initialize(chart, keys={})
1145        # dummy:: not called by 'new' method
1146
1147        @parent = @chart = chart
1148        @cpath = @chart.path
1149        # Postscript::PostscriptID_TBL[@cpath] = self
1150        @chart.postscript_configure(keys) unless keys.empty?
1151        @path = @id = 'postscript'
1152      end
1153
1154      def id
1155        @id
1156      end
1157
1158      def to_eval
1159        @id
1160      end
1161
1162      def cget_tkstring(option)
1163        @chart.postscript_cget_tkstring(option)
1164      end
1165      def cget(option)
1166        @chart.postscript_cget(option)
1167      end
1168      def cget_strict(option)
1169        @chart.postscript_cget_strict(option)
1170      end
1171      def configure(key, value=None)
1172        @chart.postscript_configure(key, value)
1173        self
1174      end
1175      def configinfo(key=nil)
1176        @chart.postscript_configinfo(key)
1177      end
1178      def current_configinfo(key=nil)
1179        @chart.current_postscript_configinfo(key)
1180      end
1181
1182      def output(file=nil, keys={})
1183        if file.kind_of?(Hash)
1184          keys = file
1185          file = nil
1186        end
1187
1188        ret = @chart.postscript_output(file, keys)
1189
1190        if file
1191          self
1192        else
1193          ret
1194        end
1195      end
1196    end
1197
1198    #################
1199    class Marker < TkObject
1200      extend Tk
1201      extend TkItemFontOptkeys
1202      extend TkItemConfigOptkeys
1203
1204      extend Tk::BLT::PlotComponent::OptKeys
1205
1206      MarkerTypeName = nil
1207      MarkerTypeToClass = {}
1208      MarkerID_TBL = TkCore::INTERP.create_table
1209
1210      TkCore::INTERP.init_ip_env{
1211        MarkerID_TBL.mutex.synchronize{ MarkerID_TBL.clear }
1212      }
1213
1214      def Marker.type2class(type)
1215        MarkerTypeToClass[type]
1216      end
1217
1218      def Marker.id2obj(chart, id)
1219        cpath = chart.path
1220        MarkerID_TBL.mutex.synchronize{
1221          if MarkerID_TBL[cpath]
1222            MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id
1223          else
1224            id
1225          end
1226        }
1227      end
1228
1229      def self._parse_create_args(keys)
1230        fontkeys = {}
1231        methodkeys = {}
1232        if keys.kind_of? Hash
1233          keys = _symbolkey2str(keys)
1234
1235          __item_font_optkeys(nil).each{|key|
1236            fkey = key.to_s
1237            fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
1238
1239            fkey = "kanji#{key}"
1240            fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
1241
1242            fkey = "latin#{key}"
1243            fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
1244
1245            fkey = "ascii#{key}"
1246            fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
1247          }
1248
1249          __item_optkey_aliases(nil).each{|alias_name, real_name|
1250            alias_name = alias_name.to_s
1251            if keys.has_key?(alias_name)
1252              keys[real_name.to_s] = keys.delete(alias_name)
1253            end
1254          }
1255
1256          __item_methodcall_optkeys(nil).each{|key|
1257            key = key.to_s
1258            methodkeys[key] = keys.delete(key) if keys.key?(key)
1259          }
1260
1261          __item_ruby2val_optkeys(nil).each{|key, method|
1262            key = key.to_s
1263            keys[key] = method.call(keys[key]) if keys.has_key?(key)
1264          }
1265
1266          args = itemconfig_hash_kv(nil, keys)
1267        else
1268          args = []
1269        end
1270
1271        [args, fontkeys, methodkeys]
1272      end
1273      private_class_method :_parse_create_args
1274
1275      def self.create(chart, keys={})
1276        unless self::MarkerTypeName
1277          fail RuntimeError, "#{self} is an abstract class"
1278        end
1279        args, fontkeys, methodkeys = _parse_create_args(keys)
1280        idnum = tk_call_without_enc(chart.path, 'marker', 'create',
1281                                    self::MarkerTypeName, *args)
1282        chart.marker_configure(idnum, fontkeys) unless fontkeys.empty?
1283        chart.marker_configure(idnum, methodkeys) unless methodkeys.empty?
1284        idnum.to_i  # 'item id' is an integer number
1285      end
1286
1287      def self.create_type(chart, type, keys={})
1288        args, fontkeys, methodkeys = _parse_create_args(keys)
1289        idnum = tk_call_without_enc(chart.path, 'marker', 'create',
1290                                    type, *args)
1291        chart.marker_configure(idnum, fontkeys) unless fontkeys.empty?
1292        chart.marker_configure(idnum, methodkeys) unless methodkeys.empty?
1293        id = idnum.to_i  # 'item id' is an integer number
1294        obj = self.allocate
1295        obj.instance_eval{
1296          @parent = @chart = chart
1297          @cpath = chart.path
1298          @id = id
1299          Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{
1300            Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {}
1301            Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self
1302          }
1303        }
1304        obj
1305      end
1306
1307      def initialize(parent, *args)
1308        @parent = @chart = parent
1309        @cpath = parent.path
1310
1311        @path = @id = create_self(*args) # an integer number as 'item id'
1312        Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{
1313          Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {}
1314          Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self
1315        }
1316      end
1317      def create_self(*args)
1318        self.class.create(@chart, *args) # return an integer as 'item id'
1319      end
1320      private :create_self
1321
1322      def id
1323        @id
1324      end
1325
1326      def to_eval
1327        @id
1328      end
1329
1330      def cget_tkstring(option)
1331        @chart.marker_cget_tkstring(@id, option)
1332      end
1333      def cget(option)
1334        @chart.marker_cget(@id, option)
1335      end
1336      def cget_strict(option)
1337        @chart.marker_cget_strict(@id, option)
1338      end
1339      def configure(key, value=None)
1340        @chart.marker_configure(@id, key, value)
1341        self
1342      end
1343      def configinfo(key=nil)
1344        @chart.marker_configinfo(@id, key)
1345      end
1346      def current_configinfo(key=nil)
1347        @chart.current_marker_configinfo(@id, key)
1348      end
1349
1350      def after(target=None)
1351        @chart.marker_after(@id, target)
1352      end
1353
1354      def before(target=None)
1355        @chart.marker_before(@id, target)
1356      end
1357
1358      def delete
1359        @chart.marker_delete(@id)
1360      end
1361
1362      def exist?
1363        @chart.marker_exist(@id)
1364      end
1365
1366      def type
1367        @chart.marker_type(@id)
1368      end
1369    end
1370
1371    class TextMarker < Marker
1372      MarkerTypeName = 'text'.freeze
1373      MarkerTypeToClass[MarkerTypeName] = self
1374    end
1375    class LineMarker < Marker
1376      MarkerTypeName = 'line'.freeze
1377      MarkerTypeToClass[MarkerTypeName] = self
1378    end
1379    class BitmapMarker < Marker
1380      MarkerTypeName = 'bitmap'.freeze
1381      MarkerTypeToClass[MarkerTypeName] = self
1382    end
1383    class ImageMarker < Marker
1384      MarkerTypeName = 'image'.freeze
1385      MarkerTypeToClass[MarkerTypeName] = self
1386    end
1387    class PolygonMarker < Marker
1388      MarkerTypeName = 'polygon'.freeze
1389      MarkerTypeToClass[MarkerTypeName] = self
1390    end
1391    class WindowMarker < Marker
1392      MarkerTypeName = 'window'.freeze
1393      MarkerTypeToClass[MarkerTypeName] = self
1394    end
1395
1396    #################
1397
1398    def __destroy_hook__
1399      Axis::AxisID_TBL.delete(@path)
1400      Crosshairs::CrosshairsID_TBL.delete(@path)
1401      Element::ElementID_TBL.delete(@path)
1402      GridLine::GridLineID_TBL.delete(@path)
1403      Legend::LegendID_TBL.delete(@path)
1404      Pen::PenID_TBL.delete(@path)
1405      Postscript::PostscriptID_TBL.delete(@path)
1406      Marker::MarkerID_TBL.delete(@path)
1407      super()
1408    end
1409
1410    #################
1411
1412    def tagid(tag)
1413      if tag.kind_of?(Axis) ||
1414          tag.kind_of?(Crosshairs) ||
1415          tag.kind_of?(Element) ||
1416          tag.kind_of?(GridLine) ||
1417          tag.kind_of?(Legend) ||
1418          tag.kind_of?(Pen) ||
1419          tag.kind_of?(Postscript) ||
1420          tag.kind_of?(Marker)
1421        tag.id
1422      else
1423        tag  # maybe an Array of configure paramters
1424      end
1425    end
1426
1427    def _component_bind(target, tag, context, *args)
1428      if TkComm._callback_entry?(args[0]) || !block_given?
1429        cmd = args.shift
1430      else
1431        cmd = Proc.new
1432      end
1433      _bind([path, target, 'bind', tagid(tag)], context, cmd, *args)
1434      self
1435    end
1436    def _component_bind_append(target, tag, context, *args)
1437      if TkComm._callback_entry?(args[0]) || !block_given?
1438        cmd = args.shift
1439      else
1440        cmd = Proc.new
1441      end
1442      _bind_append([path, target, 'bind', tagid(tag)], context, cmd, *args)
1443      self
1444    end
1445    def _component_bind_remove(target, tag, context)
1446      _bind_remove([path, target, 'bind', tagid(tag)], context)
1447      self
1448    end
1449    def _component_bindinfo(target, tag, context=nil)
1450      _bindinfo([path, target, 'bind', tagid(tag)], context)
1451    end
1452    private :_component_bind, :_component_bind_append
1453    private :_component_bind_remove, :_component_bindinfo
1454
1455    def axis_bind(tag, context, *args)
1456      _component_bind('axis', tag, context, *args)
1457    end
1458    def axis_bind_append(tag, context, *args)
1459      _component_bind_append('axis', tag, context, *args)
1460    end
1461    def axis_bind_remove(tag, context)
1462      _component_bind_remove('axis', tag, context)
1463    end
1464    def axis_bindinfo(tag, context=nil)
1465      _component_bindinfo('axis', tag, context)
1466    end
1467
1468    def element_bind(tag, context, *args)
1469      _component_bind('element', tag, context, *args)
1470    end
1471    def element_bind_append(tag, context, *args)
1472      _component_bind_append('element', tag, context, *args)
1473    end
1474    def element_bind_remove(tag, context)
1475      _component_bind_remove('element', tag, context)
1476    end
1477    def element_bindinfo(tag, context=nil)
1478      _component_bindinfo('element', tag, context)
1479    end
1480
1481    def bar_bind(tag, context, *args)
1482      _component_bind('bar', tag, context, *args)
1483    end
1484    def bar_bind_append(tag, context, *args)
1485      _component_bind_append('bar', tag, context, *args)
1486    end
1487    def bar_bind_remove(tag, context)
1488      _component_bind_remove('bar', tag, context)
1489    end
1490    def bar_bindinfo(tag, context=nil)
1491      _component_bindinfo('bar', tag, context)
1492    end
1493
1494    def line_bind(tag, context, *args)
1495      _component_bind('line', tag, context, *args)
1496    end
1497    def line_bind_append(tag, context, *args)
1498      _component_bind_append('line', tag, context, *args)
1499    end
1500    def line_bind_remove(tag, context)
1501      _component_bind_remove('line', tag, context)
1502    end
1503    def line_bindinfo(tag, context=nil)
1504      _component_bindinfo('line', tag, context)
1505    end
1506
1507    def legend_bind(tag, context, *args)
1508      _component_bind('legend', tag, context, *args)
1509    end
1510    def legend_bind_append(tag, context, *args)
1511      _component_bind_append('legend', tag, context, *args)
1512    end
1513    def legend_bind_remove(tag, context)
1514      _component_bind_remove('legend', tag, context)
1515    end
1516    def legend_bindinfo(tag, context=nil)
1517      _component_bindinfo('legend', tag, context)
1518    end
1519
1520    def marker_bind(tag, context, *args)
1521      _component_bind('marker', tag, context, *args)
1522    end
1523    def marker_bind_append(tag, context, *args)
1524      _component_bind_append('marker', tag, context, *args)
1525    end
1526    def marker_bind_remove(tag, context)
1527      _component_bind_remove('marker', tag, context)
1528    end
1529    def marker_bindinfo(tag, context=nil)
1530      _component_bindinfo('marker', tag, context)
1531    end
1532
1533    ###################
1534
1535    def axis_create(id=nil, keys={})
1536      # tk_send('axis', 'create', tagid(id), keys)
1537      Tk::BLT::PlotComponent::Axis.new(self, tagid(id), keys)
1538    end
1539    def axis_delete(*ids)
1540      tk_send('axis', 'delete', *(ids.collect{|id| tagid(id)}))
1541      self
1542    end
1543    def axis_invtransform(id, val)
1544      list(tk_send('axis', 'invtransform', tagid(id), val))
1545    end
1546    def axis_limits(id)
1547      list(tk_send('axis', 'limits', tagid(id)))
1548    end
1549    def axis_names(*pats)
1550      simplelist(tk_send('axis', 'names',
1551                         *(pats.collect{|pat| tagid(pat)}))).collect{|axis|
1552        Tk::BLT::PlotComponent::Axis.id2obj(self, axis)
1553      }
1554    end
1555    def axis_transform(id, val)
1556      list(tk_send('axis', 'transform', tagid(id), val))
1557    end
1558    def axis_view(id)
1559      tk_send('axis', 'view', tagid(id))
1560      self
1561    end
1562    def axis_use(id, target=nil)
1563      if target
1564        Tk::BLT::PlotComponent::Axis.id2obj(self,
1565                                            tk_send('axis', 'use',
1566                                                    tagid(id), tagid(target)))
1567      else
1568        Tk::BLT::PlotComponent::Axis.id2obj(self,
1569                                            tk_send('axis', 'use', tagid(id)))
1570      end
1571    end
1572
1573    ###################
1574
1575    def crosshairs_off
1576      tk_send_without_enc('crosshairs', 'off')
1577      self
1578    end
1579    def crosshairs_on
1580      tk_send_without_enc('crosshairs', 'on')
1581      self
1582    end
1583    def crosshairs_toggle
1584      tk_send_without_enc('crosshairs', 'toggle')
1585      self
1586    end
1587
1588    ###################
1589
1590    def element_create(id=nil, keys={})
1591      # tk_send('element', 'create', tagid(id), keys)
1592      Tk::BLT::PlotComponent::Element.new(self, tagid(id), keys)
1593    end
1594    def element_activate(*args)
1595      if args.empty?
1596        list(tk_send('element', 'activate')).collect{|elem|
1597          Tk::BLT::PlotComponent::Element.id2obj(self, elem)
1598        }
1599      else
1600        # id, *indices
1601        id = args.shift
1602        tk_send('element', 'activate', tagid(id), *args)
1603      end
1604    end
1605    def element_closest(x, y, var, *args)
1606      if args[-1].kind_of?(Hash)
1607        keys = args.pop
1608        bool(tk_send('element', 'closest', x, y, var,
1609                     *(hash_kv(keys).concat(args.collect{|id| tagid(id)}))))
1610      else
1611        bool(tk_send('element', 'closest', x, y, var,
1612                     *(args.collect{|id| tagid(id)})))
1613      end
1614    end
1615    def element_deactivate(*ids)
1616      tk_send('element', 'deactivate', *(ids.collect{|id| tagid(id)}))
1617      self
1618    end
1619    def element_delete(*ids)
1620      tk_send('element', 'delete', *(ids.collect{|id| tagid(id)}))
1621      self
1622    end
1623    def element_exist?(id)
1624      bool(tk_send('element', 'exists', tagid(id)))
1625    end
1626    def element_names(*pats)
1627      simplelist(tk_send('element', 'names',
1628                         *(pats.collect{|pat| tagid(pat)}))).collect{|elem|
1629        Tk::BLT::PlotComponent::Element.id2obj(self, elem)
1630      }
1631    end
1632    def element_show(*names)
1633      if names.empty?
1634        simplelist(tk_send('element', 'show'))
1635      else
1636        tk_send('element', 'show', *(names.collect{|n| tagid(n)}))
1637        self
1638      end
1639    end
1640    def element_type(id)
1641      tk_send('element', 'type', tagid(id))
1642    end
1643
1644    ###################
1645
1646    def bar_create(id=nil, keys={})
1647      # tk_send('bar', 'create', tagid(id), keys)
1648      Tk::BLT::PlotComponent::Bar.new(self, tagid(id), keys)
1649    end
1650    alias bar bar_create
1651    def bar_activate(*args)
1652      if args.empty?
1653        list(tk_send('bar', 'activate')).collect{|elem|
1654          Tk::BLT::PlotComponent::Element.id2obj(self, elem)
1655        }
1656      else
1657        # id, *indices
1658        id = args.shift
1659        tk_send('bar', 'activate', tagid(id), *args)
1660      end
1661    end
1662    def bar_closest(x, y, var, *args)
1663      if args[-1].kind_of?(Hash)
1664        keys = args.pop
1665        bool(tk_send('bar', 'closest', x, y, var,
1666                     *(hash_kv(keys).concat(args.collect{|id| tagid(id)}))))
1667      else
1668        bool(tk_send('bar', 'closest', x, y, var,
1669                     *(args.collect{|id| tagid(id)})))
1670      end
1671    end
1672    def bar_deactivate(*ids)
1673      tk_send('bar', 'deactivate', *(ids.collect{|id| tagid(id)}))
1674      self
1675    end
1676    def bar_delete(*ids)
1677      tk_send('bar', 'delete', *(ids.collect{|id| tagid(id)}))
1678      self
1679    end
1680    def bar_exist?(id)
1681      bool(tk_send('bar', 'exists', tagid(id)))
1682    end
1683    def bar_names(*pats)
1684      simplelist(tk_send('bar', 'names',
1685                         *(pats.collect{|pat| tagid(pat)}))).collect{|elem|
1686        Tk::BLT::PlotComponent::Element.id2obj(self, elem)
1687      }
1688    end
1689    def bar_show(*names)
1690      if names.empty?
1691        simplelist(tk_send('bar', 'show'))
1692      else
1693        tk_send('bar', 'show', *(names.collect{|n| tagid(n)}))
1694        self
1695      end
1696    end
1697    def bar_type(id)
1698      tk_send('bar', 'type', tagid(id))
1699    end
1700
1701    ###################
1702
1703    def line_create(id=nil, keys={})
1704      # tk_send('line', 'create', tagid(id), keys)
1705      Tk::BLT::PlotComponent::Line.new(self, tagid(id), keys)
1706    end
1707    alias bar line_create
1708    def line_activate(*args)
1709      if args.empty?
1710        list(tk_send('line', 'activate')).collect{|elem|
1711          Tk::BLT::PlotComponent::Element.id2obj(self, elem)
1712        }
1713      else
1714        # id, *indices
1715        id = args.shift
1716        tk_send('line', 'activate', tagid(id), *args)
1717      end
1718    end
1719    def line_closest(x, y, var, *args)
1720      if args[-1].kind_of?(Hash)
1721        keys = args.pop
1722        bool(tk_send('line', 'closest', x, y, var,
1723                     *(hash_kv(keys).concat(args.collect{|id| tagid(id)}))))
1724      else
1725        bool(tk_send('line', 'closest', x, y, var,
1726                     *(args.collect{|id| tagid(id)})))
1727      end
1728    end
1729    def line_deactivate(*ids)
1730      tk_send('line', 'deactivate', *(ids.collect{|id| tagid(id)}))
1731      self
1732    end
1733    def line_delete(*ids)
1734      tk_send('line', 'delete', *(ids.collect{|id| tagid(id)}))
1735      self
1736    end
1737    def line_exist?(id)
1738      bool(tk_send('line', 'exists', tagid(id)))
1739    end
1740    def line_names(*pats)
1741      simplelist(tk_send('line', 'names',
1742                         *(pats.collect{|pat| tagid(pat)}))).collect{|elem|
1743        Tk::BLT::PlotComponent::Element.id2obj(self, elem)
1744      }
1745    end
1746    def line_show(*names)
1747      if names.empty?
1748        simplelist(tk_send('line', 'show'))
1749      else
1750        tk_send('line', 'show', *(names.collect{|n| tagid(n)}))
1751        self
1752      end
1753    end
1754    def line_type(id)
1755      tk_send('line', 'type', tagid(id))
1756    end
1757
1758    ###################
1759
1760    def gridline_off
1761      tk_send_without_enc('grid', 'off')
1762      self
1763    end
1764    def gridline_on
1765      tk_send_without_enc('grid', 'on')
1766      self
1767    end
1768    def gridline_toggle
1769      tk_send_without_enc('grid', 'toggle')
1770      self
1771    end
1772
1773    ###################
1774
1775    def legend_window_create(parent=nil, keys=nil)
1776      if parent.kind_of?(Hash)
1777        keys = _symbolkey2str(parent)
1778        parent = keys.delete('parent')
1779        widgetname = keys.delete('widgetname')
1780        keys.delete('without_creating')
1781      elsif keys
1782        keys = _symbolkey2str(keys)
1783        widgetname = keys.delete('widgetname')
1784        keys.delete('without_creating')
1785      end
1786
1787      legend = self.class.new(parent, :without_creating=>true,
1788                              :widgetname=>widgetname)
1789      class << legend
1790        def __destroy_hook__
1791          TkCore::INTERP.tk_windows.delete(@path)
1792        end
1793      end
1794
1795      if keys
1796        self.legend_configure(keys.update('position'=>legend))
1797      else
1798        self.legend_configure('position'=>legend)
1799      end
1800      legend
1801    end
1802
1803    def legend_activate(*pats)
1804      list(tk_send('legend', 'activate',
1805                   *(pats.collect{|pat| tagid(pat)}))).collect{|elem|
1806        Tk::BLT::PlotComponent::Element.id2obj(self, elem)
1807      }
1808    end
1809    def legend_deactivate(*pats)
1810      list(tk_send('legend', 'deactivate',
1811                   *(pats.collect{|pat| tagid(pat)}))).collect{|elem|
1812        Tk::BLT::PlotComponent::Element.id2obj(self, elem)
1813      }
1814    end
1815    def legend_get(pos, y=nil)
1816      if y
1817        Tk::BLT::PlotComponent::Element.id2obj(self,
1818                                               tk_send('legend', 'get',
1819                                                       _at(pos, y)))
1820      else
1821        Tk::BLT::PlotComponent::Element.id2obj(self,
1822                                               tk_send('legend', 'get', pos))
1823      end
1824    end
1825
1826    ###################
1827
1828    def pen_create(id=nil, keys={})
1829      # tk_send('pen', 'create', tagid(id), keys)
1830      Tk::BLT::PlotComponent::Pen.new(self, tagid(id), keys)
1831    end
1832    def pen_delete(*ids)
1833      tk_send('pen', 'delete', *(ids.collect{|id| tagid(id)}))
1834      self
1835    end
1836    def pen_names(*pats)
1837      simplelist(tk_send('pen', 'names',
1838                         *(pats.collect{|pat| tagid(pat)}))).collect{|pen|
1839        Tk::BLT::PlotComponent::Pen.id2obj(self, pen)
1840      }
1841    end
1842
1843    ###################
1844
1845    def postscript_output(file=nil, keys={})
1846      if file.kind_of?(Hash)
1847        keys = file
1848        file = nil
1849      end
1850
1851      if file
1852        tk_send('postscript', 'output', file, keys)
1853        self
1854      else
1855        tk_send('postscript', 'output', keys)
1856      end
1857    end
1858
1859    ###################
1860
1861    def marker_create(type, keys={})
1862      case type
1863      when :text, 'text'
1864        Tk::BLT::PlotComponent::TextMarker.new(self, keys)
1865      when :line, 'line'
1866        Tk::BLT::PlotComponent::LineMarker.new(self, keys)
1867      when :bitmap, 'bitmap'
1868        Tk::BLT::PlotComponent::BitmapMarker.new(self, keys)
1869      when :image, 'image'
1870        Tk::BLT::PlotComponent::ImageMarker.new(self, keys)
1871      when :polygon, 'polygon'
1872        Tk::BLT::PlotComponent::PolygonMarker.new(self, keys)
1873      when :window, 'window'
1874        Tk::BLT::PlotComponent::WindowMarker.new(self, keys)
1875      else
1876        if type.kind_of?(Tk::BLT::PlotComponent::Marker)
1877          type.new(self, keys)
1878        else
1879          Tk::BLT::PlotComponent::Marker.create_type(self, type, keys)
1880        end
1881      end
1882    end
1883    def marker_after(id, target=nil)
1884      if target
1885        tk_send_without_enc('marker', 'after', tagid(id), tagid(target))
1886      else
1887        tk_send_without_enc('marker', 'after', tagid(id))
1888      end
1889      self
1890    end
1891    def marker_before(id, target=None)
1892      if target
1893        tk_send_without_enc('marker', 'before', tagid(id), tagid(target))
1894      else
1895        tk_send_without_enc('marker', 'before', tagid(id))
1896      end
1897      self
1898    end
1899    def marker_delete(*ids)
1900      tk_send('marker', 'delete', *(ids.collect{|id| tagid(id)}))
1901      self
1902    end
1903    def marker_exist?(id)
1904      bool(tk_send('marker', 'exists', tagid(id)))
1905    end
1906    def marker_names(*pats)
1907      simplelist(tk_send('marker', 'names',
1908                         *(pats.collect{|pat| tagid(pat)}))).collect{|id|
1909        Tk::BLT::PlotComponent::Marker.id2obj(self, id)
1910      }
1911    end
1912    def marker_type(id)
1913      tk_send('marker', 'type', tagid(id))
1914    end
1915
1916    ###################
1917
1918    def xaxis_cget_tkstring(option)
1919      itemcget_tkstring('xaxis', option)
1920    end
1921    def xaxis_cget(option)
1922      itemcget('xaxis', option)
1923    end
1924    def xaxis_cget_strict(option)
1925      itemcget_strict('xaxis', option)
1926    end
1927    def xaxis_configure(slot, value=None)
1928      if slot.kind_of?(Hash)
1929        slot = _symbolkey2str(slot)
1930        if cmd = slot.delete('command')
1931          slot['command'] = proc{|w, tick|
1932            cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
1933          }
1934        end
1935      elsif slot == :command || slot == 'command'
1936        cmd = value
1937        value = proc{|w, tick|
1938          cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
1939        }
1940      end
1941      itemconfigure('xaxis', slot, value)
1942    end
1943    def xaxis_configinfo(slot=nil)
1944      itemconfiginfo('xaxis', slot)
1945    end
1946    def current_xaxis_configinfo(slot=nil)
1947      current_itemconfiginfo('xaxis', slot)
1948    end
1949    def xaxis_bind(context, *args)
1950      if TkComm._callback_entry?(args[0]) || !block_given?
1951        cmd = args.shift
1952      else
1953        cmd = Proc.new
1954      end
1955      _bind([path, 'xaxis', 'bind'], context, cmd, *args)
1956      self
1957    end
1958    def xaxis_bind_append(context, *args)
1959      if TkComm._callback_entry?(args[0]) || !block_given?
1960        cmd = args.shift
1961      else
1962        cmd = Proc.new
1963      end
1964      _bind_append([path, 'xaxis', 'bind'], context, cmd, *args)
1965      self
1966    end
1967    def xaxis_bind_remove(context)
1968      _bind_remove([path, 'xaxis', 'bind'], context)
1969      self
1970    end
1971    def xaxis_bindinfo(context=nil)
1972      _bindinfo([path, 'xaxis', 'bind'], context)
1973    end
1974    def xaxis_invtransform(val)
1975      list(tk_send('xaxis', 'invtransform', val))
1976    end
1977    def xaxis_limits
1978      list(tk_send('xaxis', 'limits'))
1979    end
1980    def xaxis_transform(val)
1981      list(tk_send('xaxis', 'transform', val))
1982    end
1983    def xaxis_use(target=nil)
1984      if target
1985        Tk::BLT::PlotComponent::Axis.id2obj(self,
1986                                            tk_send('xaxis', 'use',
1987                                                    tagid(target)))
1988      else
1989        Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('xaxis', 'use'))
1990      end
1991    end
1992
1993    def x2axis_cget_tkstring(option)
1994      itemcget_tkstring('x2axis', option)
1995    end
1996    def x2axis_cget(option)
1997      itemcget('x2axis', option)
1998    end
1999    def x2axis_cget_strict(option)
2000      itemcget_strict('x2axis', option)
2001    end
2002    def x2axis_configure(slot, value=None)
2003      if slot.kind_of?(Hash)
2004        slot = _symbolkey2str(slot)
2005        if cmd = slot.delete('command')
2006          slot['command'] = proc{|w, tick|
2007            cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
2008          }
2009        end
2010      elsif slot == :command || slot == 'command'
2011        cmd = value
2012        value = proc{|w, tick|
2013          cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
2014        }
2015      end
2016      itemconfigure('x2axis', slot, value)
2017    end
2018    def x2axis_configinfo(slot=nil)
2019      itemconfiginfo('x2axis', slot)
2020    end
2021    def current_x2axis_configinfo(slot=nil)
2022      current_itemconfiginfo('x2axis', slot)
2023    end
2024    def x2axis_bind(context, *args)
2025      if TkComm._callback_entry?(args[0]) || !block_given?
2026        cmd = args.shift
2027      else
2028        cmd = Proc.new
2029      end
2030      _bind([path, 'x2axis', 'bind'], context, cmd, *args)
2031      self
2032    end
2033    def x2axis_bind_append(context, *args)
2034      if TkComm._callback_entry?(args[0]) || !block_given?
2035        cmd = args.shift
2036      else
2037        cmd = Proc.new
2038      end
2039      _bind_append([path, 'x2axis', 'bind'], context, cmd, *args)
2040      self
2041    end
2042    def x2axis_bind_remove(context)
2043      _bind_remove([path, 'x2axis', 'bind'], context)
2044      self
2045    end
2046    def x2axis_bindinfo(context=nil)
2047      _bindinfo([path, 'x2axis', 'bind'], context)
2048    end
2049    def x2axis_invtransform(val)
2050      list(tk_send('x2axis', 'invtransform', val))
2051    end
2052    def x2axis_limits
2053      list(tk_send('x2axis', 'limits'))
2054    end
2055    def x2axis_transform(val)
2056      list(tk_send('x2axis', 'transform', val))
2057    end
2058    def x2axis_use(target=nil)
2059      if target
2060        Tk::BLT::PlotComponent::Axis.id2obj(self,
2061                                            tk_send('x2axis', 'use',
2062                                                    tagid(target)))
2063      else
2064        Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('x2axis', 'use'))
2065      end
2066    end
2067
2068    def yaxis_cget_tkstring(option)
2069      itemcget_tkstring('yaxis', option)
2070    end
2071    def yaxis_cget(option)
2072      itemcget('yaxis', option)
2073    end
2074    def yaxis_cget_strict(option)
2075      itemcget_strict('yaxis', option)
2076    end
2077    def yaxis_configure(slot, value=None)
2078      if slot.kind_of?(Hash)
2079        slot = _symbolkey2str(slot)
2080        if cmd = slot.delete('command')
2081          slot['command'] = proc{|w, tick|
2082            cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
2083          }
2084        end
2085      elsif slot == :command || slot == 'command'
2086        cmd = value
2087        value = proc{|w, tick|
2088          cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
2089        }
2090      end
2091      itemconfigure('yaxis', slot, value)
2092    end
2093    def yaxis_configinfo(slot=nil)
2094      itemconfiginfo('yaxis', slot)
2095    end
2096    def current_yaxis_configinfo(slot=nil)
2097      current_itemconfiginfo('yaxis', slot)
2098    end
2099    def yaxis_bind(context, *args)
2100      if TkComm._callback_entry?(args[0]) || !block_given?
2101        cmd = args.shift
2102      else
2103        cmd = Proc.new
2104      end
2105      _bind([path, 'yaxis', 'bind'], context, cmd, *args)
2106      self
2107    end
2108    def yaxis_bind_append(context, *args)
2109      if TkComm._callback_entry?(args[0]) || !block_given?
2110        cmd = args.shift
2111      else
2112        cmd = Proc.new
2113      end
2114      _bind_append([path, 'yaxis', 'bind'], context, cmd, *args)
2115      self
2116    end
2117    def yaxis_bind_remove(context)
2118      _bind_remove([path, 'yaxis', 'bind'], context)
2119      self
2120    end
2121    def yaxis_bindinfo(context=nil)
2122      _bindinfo([path, 'yaxis', 'bind'], context)
2123    end
2124    def yaxis_invtransform(val)
2125      list(tk_send('yaxis', 'invtransform', val))
2126    end
2127    def yaxis_limits
2128      list(tk_send('yaxis', 'limits'))
2129    end
2130    def yaxis_transform(val)
2131      list(tk_send('yaxis', 'transform', val))
2132    end
2133    def yaxis_use(target=nil)
2134      if target
2135        Tk::BLT::PlotComponent::Axis.id2obj(self,
2136                                            tk_send('yaxis', 'use',
2137                                                    tagid(target)))
2138      else
2139        Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('yaxis', 'use'))
2140      end
2141    end
2142
2143    def y2axis_cget_tkstring(option)
2144      itemcget_tkstring('y2axis', option)
2145    end
2146    def y2axis_cget(option)
2147      itemcget('y2axis', option)
2148    end
2149    def y2axis_cget_strict(option)
2150      itemcget_strict('y2axis', option)
2151    end
2152    def y2axis_configure(slot, value=None)
2153      if slot.kind_of?(Hash)
2154        slot = _symbolkey2str(slot)
2155        if cmd = slot.delete('command')
2156          slot['command'] = proc{|w, tick|
2157            cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
2158          }
2159        end
2160      elsif slot == :command || slot == 'command'
2161        cmd = value
2162        value = proc{|w, tick|
2163          cmd.call(TkComm.window(w), TkComm.num_or_str(tick))
2164        }
2165      end
2166      itemconfigure('y2axis', slot, value)
2167    end
2168    def y2axis_configinfo(slot=nil)
2169      axis_configinfo('y2axis', slot)
2170    end
2171    def current_y2axis_configinfo(slot=nil)
2172      current_itemconfiginfo('y2axis', slot)
2173    end
2174    def y2axis_bind(context, *args)
2175      if TkComm._callback_entry?(args[0]) || !block_given?
2176        cmd = args.shift
2177      else
2178        cmd = Proc.new
2179      end
2180      _bind([path, 'y2axis', 'bind'], context, cmd, *args)
2181      self
2182    end
2183    def y2axis_bind_append(context, *args)
2184      if TkComm._callback_entry?(args[0]) || !block_given?
2185        cmd = args.shift
2186      else
2187        cmd = Proc.new
2188      end
2189      _bind_append([path, 'y2axis', 'bind'], context, cmd, *args)
2190      self
2191    end
2192    def y2axis_bind_remove(context)
2193      _bind_remove([path, 'y2axis', 'bind'], context)
2194      self
2195    end
2196    def y2axis_bindinfo(context=nil)
2197      _bindinfo([path, 'y2axis', 'bind'], context)
2198    end
2199    def y2axis_invtransform(val)
2200      list(tk_send('y2axis', 'invtransform', val))
2201    end
2202    def y2axis_limits
2203      list(tk_send('y2axis', 'limits'))
2204    end
2205    def y2axis_transform(val)
2206      list(tk_send('y2axis', 'transform', val))
2207    end
2208    def y2axis_use(target=nil)
2209      if target
2210        Tk::BLT::PlotComponent::Axis.id2obj(self,
2211                                            tk_send('y2axis', 'use',
2212                                                    tagid(target)))
2213      else
2214        Tk::BLT::PlotComponent::Axis.id2obj(self, tk_send('y2axis', 'use'))
2215      end
2216    end
2217  end
2218end
2219