1# -*- coding: utf-8 -*-
2#
3# animated label widget demo (called by 'widget')
4#
5# based on Tcl/Tk8.5a2 widget demos
6
7# toplevel widget が存在すれば削除する
8if defined?($anilabel_demo) && $anilabel_demo
9  $anilabel_demo.destroy
10  $anilabel_demo = nil
11end
12
13# demo 用の toplevel widget を生成
14$anilabel_demo = TkToplevel.new {|w|
15  title("Animated Label Demonstration")
16  iconname("anilabel")
17  positionWindow(w)
18}
19
20base_frame = TkFrame.new($anilabel_demo).pack(:fill=>:both, :expand=>true)
21
22# label 生成
23msg = TkLabel.new(base_frame) {
24  font $font
25  wraplength '4i'
26  justify 'left'
27  text "下には4つのアニメーションラベルが表示されています。左側にあるラベルは、内部のテキストメッセージをスクロールしたように見せることで動きを付けています。右側のラベルは、表示するイメージを変化させることで動きを与えています。"
28}
29msg.pack('side'=>'top')
30
31# frame 生成
32TkFrame.new(base_frame) {|frame|
33  TkButton.new(frame) {
34    #text '了解'
35    text '閉じる'
36    command proc{
37      tmppath = $anilabel_demo
38      $anilabel_demo = nil
39      tmppath.destroy
40    }
41  }.pack('side'=>'left', 'expand'=>'yes')
42
43  TkButton.new(frame) {
44    text 'コード参照'
45    command proc{showCode 'anilabel'}
46  }.pack('side'=>'left', 'expand'=>'yes')
47
48}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
49
50# label demo 用フレーム生成
51f_left = TkLabelFrame.new(base_frame,  :text=>'Scrolling Texts')
52f_right = TkLabelFrame.new(base_frame, :text=>'GIF Image')
53Tk.pack(f_left, f_right, 'side'=>'left', 'expand'=>'yes', 'fill'=>'both',
54        'padx'=>10, 'pady'=>10)
55
56# animated label
57class AnimatedTextLabel < TkLabel
58  def initialize(*args)
59    super(*args)
60    @timer = TkTimer.new{ _animation_callback }
61    @timer.loop_exec = -1
62    # bind('Destroy'){ @timer.stop }
63    @btag = TkBindTag.new('Destroy'){ @timer.stop }
64    self.bindtags_unshift(@btag)
65  end
66
67  def _animation_callback()
68    txt = self.text
69    self.text = (txt[1..-1] << txt[0])
70  end
71  private :_animation_callback
72
73  def start(interval)
74    @timer.set_interval(interval)
75    @timer.start
76  end
77
78  def stop
79    @timer.stop
80  end
81end
82
83# animated image
84class AnimatedImageLabel < AnimatedTextLabel
85  def initialize(*args)
86    super(*args)
87    @destroy_image = false
88    @btag.bind_append('Destroy'){
89      if @destroy_image
90        begin
91          self.image.delete
92        rescue
93        end
94      end
95    }
96  end
97  attr_accessor :destroy_image
98
99  def _animation_callback()
100    img = self.image
101
102    fmt = img.format
103    if fmt.kind_of?(Array)
104      if fmt[1].kind_of?(Hash)
105        # fmt == ['GIF', {'index'=>idx}]
106        idx = fmt[1]['index']
107      else
108        # fmt == ['GIF', '-index', idx]  :: Ruby1.8.2 returns this.
109        idx = fmt[2]
110      end
111    elsif fmt.kind_of?(String) && fmt =~ /GIF -index (\d+)/
112      idx = $1.to_i
113    else
114      idx = -1
115    end
116
117    begin
118      img.format("GIF -index #{idx + 1}")
119    rescue => e
120      img.format("GIF -index 0")
121    end
122  end
123  private :_animation_callback
124end
125
126# label ������
127l1 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:ridge,
128                           :font=>{:family=>'Courier', :size=>10})
129l2 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:groove,
130                           :font=>{:family=>'Courier', :size=>10})
131l3 = AnimatedTextLabel.new(f_left, :borderwidth=>4, :relief=>:flat,
132                           :font=>{:family=>'Courier', :size=>10}, :width=>18)
133Tk.pack(l1, l2, l3,
134        :side=>:top, :expand=>true, :anchor=>:w, :padx=>10, :pady=>10)
135
136limg = AnimatedImageLabel.new(f_right, :borderwidth=>0)
137limg.pack(:side=>:top, :expand=>true, :padx=>10, :pady=>10)
138
139# base64-encoded animated GIF file
140tclPowerdData = <<EOD
141    R0lGODlhKgBAAPQAAP//////zP//AP/MzP/Mmf/MAP+Zmf+ZZv+ZAMz//8zM
142    zMyZmcyZZsxmZsxmAMwzAJnMzJmZzJmZmZlmmZlmZplmM5kzM2aZzGZmzGZm
143    mWZmZmYzZmYzMzNmzDMzZgAzmSH+IE1hZGUgd2l0aCBHSU1QIGJ5IExARGVt
144    YWlsbHkuY29tACH5BAVkAAEALAAAAAAqAEAAAAX+YCCOZEkyTKM2jOm66yPP
145    dF03bx7YcuHIDkGBR7SZeIyhTID4FZ+4Es8nQyCe2EeUNJ0peY2s9mi7PhAM
146    ngEAMGRbUpvzSxskLh1J+Hkg134OdDIDEB+GHxtYMEQMTjMGEYeGFoomezaC
147    DZGSHFmLXTQKkh8eNQVpZ2afmDQGHaOYSoEyhhcklzVmMpuHnaZmDqiGJbg0
148    qFqvh6UNAwB7VA+OwydEjgujkgrPNhbTI8dFvNgEYcHcHx0lB1kX2IYeA2G6
149    NN0YfkXJ2BsAMuAzHB9cZMk3qoEbRzUACsRCUBK5JxsC3iMiKd8GN088SIyT
150    0RAFSROyeEg38caDiB/+JEgqxsODrZJ1BkT0oHKSmI0ceQxo94HDpg0qsuDk
151    UmRAMgu8OgwQ+uIJgUMVeGXA+IQkzEeHGvD8cIGlDXsLiRjQ+EHroQhea7xY
152    8IQBSgYYDi1IS+OFBCgaDMGVS3fGi5BPJpBaENdQ0EomKGD56IHwO39EXiSC
153    Ysgxor5+Xfgq0qByYUpiXmwuoredB2aYH4gWWda0B7SeNENpEJHC1ghi+pS4
154    AJpIAwWvKPBi+8YEht5EriEqpFfMlhEdkBNpx0HUhwypx5T4IB1MBg/Ws2sn
155    wV3MSQOkzI8fUd48Aw3dOZto71x85hHtHijYv18Gf/3GqCdDCXHNoICBobSo
156    IqBqJLyCoH8JPrLgdh88CKCFD0CGmAiGYPgffwceZh6FC2ohIIklnkhehTNY
157    4CIHHGzgwYw01ujBBhvAqKOLLq5AAk9kuSPkkKO40NB+h1gnypJIIvkBf09a
158    N5QIRz5p5ZJXJpmlIVhOGQA2TmIJZZhKKmmll2BqyWSXWUrZpQtpatlmk1c2
159    KaWRHeTZEJF8SqLDn/hhsOeQgBbqAh6DGqronxeARUIIACH5BAUeAAAALAUA
160    LgAFAAUAAAUM4CeKz/OV5YmqaRkCACH5BAUeAAEALAUALgAKAAUAAAUUICCK
161    z/OdJVCaa7p+7aOWcDvTZwgAIfkEBR4AAQAsCwAuAAkABQAABRPgA4zP95zA
162    eZqoWqqpyqLkZ38hACH5BAUKAAEALAcALgANAA4AAAU7ICA+jwiUJEqeKau+
163    r+vGaTmac63v/GP9HM7GQyx+jsgkkoRUHJ3Qx0cK/VQVTKtWwbVKn9suNunc
164    WkMAIfkEBQoAAAAsBwA3AAcABQAABRGgIHzk842j+Yjlt5KuO8JmCAAh+QQF
165    CgAAACwLADcABwAFAAAFEeAnfN9TjqP5oOWziq05lmUIACH5BAUKAAAALA8A
166    NwAHAAUAAAUPoPCJTymS3yiQj4qOcPmEACH5BAUKAAAALBMANwAHAAUAAAUR
167    oCB+z/MJX2o+I2miKimiawgAIfkEBQoAAAAsFwA3AAcABQAABRGgIHzfY47j
168    Q4qk+aHl+pZmCAAh+QQFCgAAACwbADcABwAFAAAFEaAgfs/zCV9qPiNJouo7
169    ll8IACH5BAUKAAAALB8ANwADAAUAAAUIoCB8o0iWZggAOw==
170EOD
171
172l1.text('* Slow Animation *').start(300)
173l2.text('* Fast Animation *').start(80)
174l3.text('This is a longer scrolling text in a widget that will not show the whole message at once. ').start(150)
175
176limg.destroy_image = true
177limg.image(TkPhotoImage.new(:format=>'GIF', :data=>tclPowerdData)).start(100)
178