1#
2#  tktextframe.rb : a sample of TkComposite
3#
4#                         by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
5#
6require 'tk'
7
8module Tk::ScrollbarComposite
9  include TkComposite
10
11  def component_construct_keys
12    # If a component requires options for construction,
13    # return an Array of option-keys.
14    []
15  end
16  private :component_construct_keys
17
18  def create_component(keys={})
19    # This method must return the created component widget.
20  end
21  private :create_component
22
23  def component_delegates
24    # if want to override defalut option-methods or delegates,
25    # please define here.
26  end
27  private :component_delegates
28
29  def define_delegates
30    # option methods for scrollbars
31    option_methods([:scrollbarwidth, :get_scrollbarwidth])
32
33    # set receiver widgets for configure methods (with alias)
34    delegate_alias('scrollbarrelief', 'relief', @h_scroll, @v_scroll)
35    delegate_alias('framebackground', 'background',
36                   @frame, @h_scroll, @v_scroll)
37    delegate_alias('activeframebackground', 'activebackground',
38                   @h_scroll, @v_scroll)
39
40    # set receiver widgets for configure methods
41    delegate('DEFAULT', @component)
42    delegate('troughcolor', @h_scroll, @v_scroll)
43    delegate('repeatdelay', @h_scroll, @v_scroll)
44    delegate('repeatinterval', @h_scroll, @v_scroll)
45    delegate('borderwidth', @frame)
46    delegate('relief', @frame)
47
48    component_delegates
49  end
50  private :define_delegates
51
52  DEFAULT_VSCROLL = true
53  DEFAULT_HSCROLL = true
54
55  def initialize_composite(keys={})
56    keys = _symbolkey2str(keys)
57
58    # create scrollbars
59    @v_scroll = TkScrollbar.new(@frame, 'orient'=>'vertical')
60    @h_scroll = TkScrollbar.new(@frame, 'orient'=>'horizontal')
61
62    # create a component
63    construct_keys = {}
64    ((component_construct_keys.map{|k| k.to_s}) & keys.keys).each{|k|
65      construct_keys[k] = keys.delete(k)
66    }
67
68    # create a component (the component must be scrollable)
69    @component = create_component(construct_keys)
70
71    # set default receiver of method calls
72    @path = @component.path
73
74    # assign scrollbars
75    @component.xscrollbar(@h_scroll)
76    @component.yscrollbar(@v_scroll)
77
78    # allignment
79    TkGrid.rowconfigure(@frame, 0, 'weight'=>1, 'minsize'=>0)
80    TkGrid.columnconfigure(@frame, 0, 'weight'=>1, 'minsize'=>0)
81    @component.grid('row'=>0, 'column'=>0, 'sticky'=>'news')
82
83    # scrollbars ON
84    vscroll(keys.delete('vscroll'){self.class::DEFAULT_VSCROLL})
85    hscroll(keys.delete('hscroll'){self.class::DEFAULT_HSCROLL})
86
87    # do configure
88    define_delegates
89
90    # do configure
91    configure keys unless keys.empty?
92  end
93  private :initialize_composite
94
95  # get/set width of scrollbar
96  def get_scrollbarwidth
97    @v_scroll.width
98  end
99  def set_scrollbarwidth(width)
100    @v_scroll.width(width)
101    @h_scroll.width(width)
102  end
103  alias :scrollbarwidth :set_scrollbarwidth
104
105  def hook_vscroll_on(*args); end
106  def hook_vscroll_off(*args); end
107  def hook_hscroll_on(*args); end
108  def hook_hscroll_off(*args); end
109  private :hook_vscroll_on,:hook_vscroll_off,:hook_hscroll_on,:hook_hscroll_off
110
111  # vertical scrollbar : ON/OFF
112  def vscroll(mode, *args)
113    st = TkGrid.info(@v_scroll)
114    if mode && st.size == 0 then
115      @v_scroll.grid('row'=>0, 'column'=>1, 'sticky'=>'ns')
116      hook_vscroll_on(*args)
117    elsif !mode && st.size != 0 then
118      @v_scroll.ungrid
119      hook_vscroll_off(*args)
120    end
121    self
122  end
123
124  # horizontal scrollbar : ON/OFF
125  def hscroll(mode, *args)
126    st = TkGrid.info(@h_scroll)
127    if mode && st.size == 0 then
128      @h_scroll.grid('row'=>1, 'column'=>0, 'sticky'=>'ew')
129      hook_hscroll_on(*args)
130    elsif !mode && st.size != 0 then
131      @h_scroll.ungrid
132      hook_hscroll_off(*args)
133    end
134    self
135  end
136end
137
138################################################
139
140class TkTextFrame < TkText
141  include Tk::ScrollbarComposite
142
143  # def component_construct_keys; []; end
144  # private :component_construct_keys
145
146  def create_component(keys={})
147    # keys has options which are listed by component_construct_keys method.
148    @text = TkText.new(@frame, 'wrap'=>'none')
149    @text.configure(keys) unless keys.empty?
150
151    # option methods for component
152    option_methods(
153       [:textbackground, nil, :textbg_info],
154       :textborderwidth,
155       :textrelief
156    )
157
158    # return the created componet
159    @text
160  end
161  private :create_component
162
163  # def component_delegates; end
164  # private :component_delegates
165
166  def hook_hscroll_on(wrap_mode=nil)
167    if wrap_mode
168      wrap wrap_mode
169    else
170      wrap 'none'  # => self.wrap('none')
171    end
172  end
173  def hook_hscroll_off(wrap_mode)
174    wrap wrap_mode  # => self.wrap(wrap_mode)
175  end
176  def hscroll(mode, wrap_mode="char")
177    super
178  end
179
180  # set background color of text widget
181  def textbackground(color = nil)
182    if color
183      @text.background(color)
184    else
185      @text.background
186    end
187  end
188
189  def textbg_info
190    info = @text.configinfo(:background)
191    if TkComm::GET_CONFIGINFO_AS_ARRAY
192      info[0] = 'textbackground'
193      info
194    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
195      {'textbackground' => info['background']}
196    end
197  end
198
199  # get/set borderwidth of text widget
200  def set_textborderwidth(width)
201    @text.borderwidth(width)
202  end
203  def get_textborderwidth
204    @text.borderwidth
205  end
206  def textborderwidth(width = nil)
207    if width
208      set_textborderwidth(width)
209    else
210      get_textborderwidth
211    end
212  end
213
214  # set relief of text widget
215  def textrelief(type)
216    @text.relief(type)
217  end
218end
219
220################################################
221# test
222################################################
223if __FILE__ == $0
224  TkLabel.new(:text=>'TkTextFrame is an example of Tk::ScrollbarComposite module.').pack
225  f = TkFrame.new.pack('fill'=>'x')
226  #t = TkTextFrame.new.pack
227  t = TkTextFrame.new(:textborderwidth=>3,
228                      :textrelief=>:ridge,
229                      :scrollbarrelief=>:ridge).pack
230  p t.configinfo
231  TkButton.new(f, 'text'=>'vscr OFF',
232               'command'=>proc{t.vscroll(false)}).pack('side'=>'right')
233  TkButton.new(f, 'text'=>'vscr ON',
234               'command'=>proc{t.vscroll(true)}).pack('side'=>'right')
235  TkButton.new(f, 'text'=>'hscr ON',
236               'command'=>proc{t.hscroll(true)}).pack('side'=>'left')
237  TkButton.new(f, 'text'=>'hscr OFF',
238               'command'=>proc{t.hscroll(false)}).pack('side'=>'left')
239
240  ############################################
241
242  # Tk.default_widget_set = :Ttk
243
244  TkFrame.new.pack(:pady=>10)
245  TkLabel.new(:text=>'The following is another example of Tk::ScrollbarComposite module.').pack
246
247  #----------------------------------
248  class ScrListbox < TkListbox
249    include Tk::ScrollbarComposite
250
251    DEFAULT_HSCROLL = false
252
253    def create_component(keys={})
254      TkListbox.new(@frame, keys)
255    end
256    private :create_component
257  end
258  #----------------------------------
259
260  f = TkFrame.new.pack(:pady=>5)
261  lbox = ScrListbox.new(f).pack(:side=>:left)
262  lbox.value = %w(aa bb cc dd eeeeeeeeeeeeeeeeeeeeeeeeee ffffffffff gg hh ii jj kk ll mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm nn oo pp qq)
263  fb = TkFrame.new(f).pack(:expand=>true, :fill=>:y, :padx=>5)
264  TkButton.new(fb, 'text'=>'lbox hscr OFF',
265               'command'=>proc{lbox.hscroll(false)}).pack(:side=>:bottom,
266                                                          :fill=>:x)
267  TkButton.new(fb, 'text'=>'lbox hscr ON',
268               'command'=>proc{lbox.hscroll(true)}).pack(:side=>:bottom,
269                                                          :fill=>:x)
270  TkFrame.new(fb).pack(:pady=>5, :side=>:bottom)
271  TkButton.new(fb, 'text'=>'lbox vscr OFF',
272               'command'=>proc{lbox.vscroll(false)}).pack(:side=>:bottom,
273                                                          :fill=>:x)
274  TkButton.new(fb, 'text'=>'lbox vscr ON',
275               'command'=>proc{lbox.vscroll(true)}).pack(:side=>:bottom,
276                                                          :fill=>:x)
277
278  ############################################
279
280  Tk.mainloop
281end
282