rbcurse 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. data/Makefile +21 -0
  2. data/Manifest.txt +6 -0
  3. data/README.markdown +6 -4
  4. data/TODO +372 -0
  5. data/TODO2.txt +121 -0
  6. data/VERSION +1 -1
  7. data/examples/README.txt +67 -0
  8. data/examples/abasiclist.rb +33 -0
  9. data/examples/alpmenu.rb +42 -0
  10. data/examples/app.rb +859 -0
  11. data/examples/app.sample +17 -0
  12. data/examples/appdirtree.rb +74 -0
  13. data/examples/appemail.rb +191 -0
  14. data/examples/appemaillb.rb +308 -0
  15. data/examples/appgcompose.rb +315 -0
  16. data/examples/atree.rb +64 -0
  17. data/examples/common/file.rb +40 -0
  18. data/examples/common/rmail.rb +257 -0
  19. data/examples/data.txt +683 -0
  20. data/examples/data/README.markdown +9 -0
  21. data/examples/data/brew.txt +38 -0
  22. data/examples/data/color.2 +37 -0
  23. data/examples/data/gemlist.txt +60 -0
  24. data/examples/data/lotr.txt +12 -0
  25. data/examples/data/ports.txt +136 -0
  26. data/examples/data/tasks.txt +27 -0
  27. data/examples/data/todocsv.csv +28 -0
  28. data/examples/data/unix1.txt +21 -0
  29. data/examples/data/unix2.txt +11 -0
  30. data/examples/dbdemo.rb +495 -0
  31. data/examples/deprecated/appgmail.rb +952 -0
  32. data/examples/deprecated/splitp.rb +56 -0
  33. data/examples/deprecated/testscrolllb.rb +86 -0
  34. data/examples/deprecated/testscrollp.rb +88 -0
  35. data/examples/deprecated/testscrollta.rb +80 -0
  36. data/examples/deprecated/testscrolltable.rb +165 -0
  37. data/examples/deprecated/testsplit.rb +87 -0
  38. data/examples/deprecated/testsplit2.rb +123 -0
  39. data/examples/deprecated/testsplit3.rb +215 -0
  40. data/examples/deprecated/testsplit3_1.rb +244 -0
  41. data/examples/deprecated/testsplit3a.rb +215 -0
  42. data/examples/deprecated/testsplit3b.rb +237 -0
  43. data/examples/deprecated/testsplitta.rb +148 -0
  44. data/examples/deprecated/testsplittv.rb +142 -0
  45. data/examples/deprecated/testsplittvv.rb +144 -0
  46. data/examples/deprecated/testtpane.rb +215 -0
  47. data/examples/deprecated/testtpane2.rb +145 -0
  48. data/examples/deprecated/testtpanetable.rb +203 -0
  49. data/examples/dirtree.rb +88 -0
  50. data/examples/experimental/resultsetdemo.rb +280 -0
  51. data/examples/experimental/testmform.rb +35 -0
  52. data/examples/experimental/testscroller.rb +117 -0
  53. data/examples/experimental/teststackflow.rb +111 -0
  54. data/examples/menu1.rb +112 -0
  55. data/examples/multispl.rb +86 -0
  56. data/examples/newmessagebox.rb +131 -0
  57. data/examples/newtabbedwindow.rb +100 -0
  58. data/examples/newtesttabp.rb +121 -0
  59. data/examples/qdfilechooser.rb +68 -0
  60. data/examples/rfe.rb +1239 -0
  61. data/examples/rfe_renderer.rb +121 -0
  62. data/examples/sqlc.rb +454 -0
  63. data/examples/sqlm.rb +437 -0
  64. data/examples/sqlt.rb +408 -0
  65. data/examples/status.txt +68 -0
  66. data/examples/table1.rb +24 -0
  67. data/examples/term2.rb +84 -0
  68. data/examples/test1.rb +239 -0
  69. data/examples/test2.rb +674 -0
  70. data/examples/testapp.rb +44 -0
  71. data/examples/testapp2.rb +58 -0
  72. data/examples/testchars.rb +137 -0
  73. data/examples/testcombo.rb +91 -0
  74. data/examples/testkeypress.rb +66 -0
  75. data/examples/testlistbox.rb +113 -0
  76. data/examples/testmenu.rb +101 -0
  77. data/examples/testmulticomp.rb +70 -0
  78. data/examples/testmulticontainer.rb +94 -0
  79. data/examples/testmultispl.rb +199 -0
  80. data/examples/testree.rb +106 -0
  81. data/examples/testtable.rb +264 -0
  82. data/examples/testtabp.rb +107 -0
  83. data/examples/testtodo.rb +584 -0
  84. data/examples/testvimsplit.rb +112 -0
  85. data/examples/testwsshortcuts.rb +64 -0
  86. data/examples/testwsshortcuts2.rb +126 -0
  87. data/examples/todo.db +0 -0
  88. data/examples/todo.yml +191 -0
  89. data/examples/viewtodo.rb +574 -0
  90. data/lib/rbcurse/deprecated/README.markdown +12 -0
  91. data/lib/rbcurse/deprecated/rpad.rb +375 -0
  92. data/lib/rbcurse/deprecated/rscrollpane.rb +512 -0
  93. data/lib/rbcurse/deprecated/rsplitpane.rb +894 -0
  94. data/lib/rbcurse/deprecated/rsplitpane2.rb +1009 -0
  95. data/lib/rbcurse/deprecated/rviewport.rb +204 -0
  96. data/lib/rbcurse/deprecated/widgets/mapper.rb +130 -0
  97. data/lib/rbcurse/deprecated/widgets/rmessagebox.rb +348 -0
  98. data/lib/rbcurse/deprecated/widgets/rtabbedpane.rb +1158 -0
  99. data/lib/rbcurse/deprecated/widgets/rtabbedwindow.rb +167 -0
  100. data/lib/rbcurse/deprecated/widgets/scrollable.rb +301 -0
  101. data/lib/rbcurse/deprecated/widgets/stdscrwindow.rb +309 -0
  102. data/lib/ver/keyboard2.rb +170 -0
  103. data/test/test_rbcurse.rb +0 -0
  104. metadata +131 -9
@@ -0,0 +1,12 @@
1
+ == Short Story
2
+
3
+ If you are new here, don't touch anything in this directory.
4
+
5
+ == Long Story
6
+
7
+ This directory contains stuff that was once used, but has since been rewritten in a simpler form.
8
+ Thus, I've replaced this with the simpler form. This still exists for anyone who was using it.
9
+
10
+ Some old stuff was either rather ambitiously rewritten or written awfully like MessageBox. I've got a more sensible version up now. Stuff here will *NOT* be maintained by me anylonger.
11
+
12
+ There's also stuff here that will *NOT* work any longer such as SplitPanes and ScrollPanes. Support for them has been removed from the core (Form, widget and window) since it was complicating the core too much.
@@ -0,0 +1,375 @@
1
+ require 'ver/window'
2
+
3
+ # This contains pad and subwin.
4
+ #
5
+ # 1. IMHO, subwins and derwins are not very stable. Avoid using them. I've tinkered
6
+ # with them quite a bit and given them up.
7
+ # 2. Pads are quite okay, I tried something too complex, and copywin often can give
8
+ # errors, or seg faults. So i've steered away from the Pad class. I may try a simpler
9
+ # less clever pad approach to textview sometime again.
10
+
11
+ module VER
12
+ ##
13
+ # Pad
14
+ # This is EXPERIMENTAL
15
+ # A pad cannot be used interchangeable since some application functions such as wrefresh
16
+ # are illegal. Cannot expect the application to take care.
17
+ # Internally we can make it easier. Mostly a pad is used to map to one portion of the screen.
18
+ # So we allow that to be defined once. Then only start row and col of pad change.
19
+ # Maybe we should check pad coordinates so no errors
20
+ # Also check screen coordinates (if we know)
21
+ # We need padheight and padwidth only to ensure we don't keep recreating.
22
+ # Howevre, when comp's height increases, then decreases, pad height remains larger
23
+ # but we keep printing an extra row in copywin. so Pad needs to maintain comp height
24
+ # and padheight.
25
+ # @since 0.1.3
26
+ # NOTE used only by TabbedPane. If we rewrite without using it in 1.3.1 then scrap.
27
+ # 2011-11-8 Now the new simpler TabbedPane does not use pads.
28
+ # The aim o this class was to act as a replacement for window, making it seamless
29
+ # to use a pad instead
30
+ class Pad < VER::Window
31
+ # top and left correspond to screen's top and left wich will mostly be fixed
32
+ attr_accessor :top, :left
33
+ # start row and col correspond to pad's top and left which will change if scrolling
34
+ attr_accessor :pminrow, :pmincol
35
+ # screen's height and width, now it reflects components height and width
36
+ attr_accessor :sheight, :swidth
37
+ attr_reader :otherwin
38
+ # dimensions the pad was created with, used so we don't keep recreating pad, only if increase.
39
+ attr_reader :padheight, :padwidth
40
+ #attr_accessor :name # more for debugging log files. 2010-02-02 19:58
41
+ def initialize(height, width)
42
+ @visible = true
43
+ # do we set height and width ?? XXX
44
+ @window = Ncurses.newpad(height, width)
45
+ @padheight = height
46
+ @padwidth = width
47
+ @height = height
48
+ @width = width
49
+ @sheight = height
50
+ @swidth = width
51
+ init_vars
52
+ end
53
+ def init_vars
54
+ super
55
+ @top ||= 0; @left ||= 0
56
+ @pmincol ||= 0 # pad will print from this col
57
+ @pminrow ||= 0 # pad will print from this row
58
+ @window_type = :PAD
59
+ @name ||="#{self}"
60
+ $log.debug " PAD constructor #{self} , #{@window} "
61
+ end
62
+ #
63
+ # @param layout is a hash (@see Window.initialize)
64
+ def self.create_with_layout(layout)
65
+ @window = Pad.new(layout[:height], layout[:width])
66
+ @window.reset_layout(layout)
67
+ return @window
68
+ end
69
+ ##
70
+ # increases the pad size, since the widget may have been resized
71
+ # checks that one of ht or width has been increased
72
+ # destroys earlier pad and returns new one
73
+ # Updates sheight and swidth even if reduced so copywin works fine.
74
+ # @param [Fixnum] height to resize to
75
+ # @param [Fixnum] width to resize to
76
+ # @return [Pad]
77
+ # 2009-10-29 23:18
78
+ def resize(ht = 0, w = 0)
79
+ # update sheight and swidth even if reduced, so that pad doesn't overwrite.
80
+ @sheight = ht if ht > 0
81
+ @swidth = w if w > 0
82
+ return if ht < @padheight and w < @padwidth
83
+ @padheight = ht if ht > @padheight
84
+ @padwidth = w if w > @padwidth
85
+ destroy
86
+ $log.debug " L502 resize, creating newpad with #{@padheight} and #{@padwidth} "
87
+ @window = Ncurses.newpad(@padheight, @padwidth)
88
+ $log.debug " L502 resize created #{@window} "
89
+ return @window
90
+ end
91
+ ## used if pad and window are same size only
92
+ # creates a similar sized window
93
+ # assumes window is backed by this pad
94
+ # @param object of Window class
95
+ def self.create_for_window(win)
96
+ # get coordinates for win
97
+ @otherwin = win
98
+ smaxx = win.getmaxx()
99
+ smaxy = win.getmaxy()
100
+ top = win.getminx()
101
+ left = win.getminy()
102
+ sheight = win.height
103
+ swidth = win.width
104
+ # make pad based on size of window
105
+ window = Pad.create_with_layout(layout = { :height => sheight, :width => swidth, :top => top, :left => sleft })
106
+ window.sheight = sheight
107
+ window.swidth = swidth
108
+ return window
109
+
110
+ end
111
+ # top and left correspond to screen's top and left wich will mostly be fixed.
112
+ # In cases where the component may float around, as in Splitpanes second component
113
+ # this would be set using component's row and col.
114
+ def set_screen_row_col top, left=-1
115
+ @top = top
116
+ @left = left unless left < 0
117
+ end
118
+ alias :set_screen_pad_left :set_screen_row_col
119
+
120
+ ## added user setting screens max row and col (e.g splitpanes first component)
121
+ def set_screen_max_row_col mr, mc
122
+ $log.debug "#{@name} set_screen_max_row_col #{mr},#{mc}. earlier #{@screen_maxrow}, #{@screen_maxcol} "
123
+ # added || check on 2010-01-09 18:39 since crashing if mr > sh + top ..
124
+ # I removed the check, since it results in a blank area on screen since the
125
+ # widget has not expanded itself. Without the check it will crash on copywin so you
126
+ # should increase widget size or disallow calling this in this situation.
127
+ if mr > (@sheight + @top -1 -@pminrow)
128
+ $log.warn " ->>> ** set_screen_max_row_col #{mr} > #{@sheight} + #{@top} -1 - #{@pminrow} ** "
129
+ $log.warn " ->>> can result in error in copy_win or in some rows not displaying"
130
+ return # some situations actually require this ...
131
+ end unless mr.nil?
132
+ @screen_maxrow = mr unless mr.nil? # || mr > (@sheight + @top -1 -@pminrow)
133
+ @screen_maxcol = mc unless mc.nil?
134
+ end
135
+ # start row and col correspond to pad's top and left which will change if scrolling
136
+ # However, if we use this as a backing store for subwindows it could remain the same
137
+ def set_pad_top_left top, left=-1
138
+ $log.debug "#{@name} inside set_pad_top_left to #{top} #{left} earlier #{@pminrow}, #{@pmincol}"
139
+ @pminrow = top unless top < 0
140
+ @pmincol = left unless left < 0
141
+ end
142
+ # return screen max row which will be used for writing to window
143
+ # XXX what if user sets/overrides sheight
144
+ def smaxrow
145
+ #$log.debug " ... niside smaxrow #{@sheight} + #{@top} -1 "
146
+ #@sheight + @top -1
147
+ $log.debug "smr: #{@screen_maxrow} ... niside smaxrow #{@sheight} + #{@top} -1 - #{@pminrow}"
148
+ @screen_maxrow || @sheight + @top -1 -@pminrow
149
+ end
150
+ ##
151
+ # return screen max col which will be used for writing to window
152
+ def smaxcol
153
+ #$log.debug " ... niside smaxcol #{@swidth} + #{@left} -1 "
154
+ #@swidth + @left -1
155
+ # $log.debug " ... niside smaxcol #{@swidth} + #{@left} -1 - #{@pmincol} "
156
+ @screen_maxcol || @swidth + @left -1 - @pmincol
157
+ end
158
+ ##
159
+ # specify the window or subwin that the pad is writing to
160
+ # 2010-02-20 22:45 - actually since there are pad methods smaxrow used on otherwin
161
+ # therefor it can only be a Pad !! NOTE
162
+ def set_backing_window win
163
+ @otherwin = win
164
+ # XX should we extract the coordinates and use for printing ??
165
+ # or for setting maxrow and maxcol
166
+ end
167
+ # trying to make things as easy as possible
168
+ # returns -1 if error in prefresh
169
+ def wrefresh
170
+ $log.debug " inside pad's wrefresh #{@window}. minr,minc,top,left,smaxr,c: #{@pminrow}, #{@pmincol}, #{@top} #{@left} #{smaxrow()} #{smaxcol()} self: #{self.name} "
171
+
172
+ # caution, prefresh uses maxrow and maxcol not height and width
173
+ # so we have to add top and less one since we are zero based
174
+ ret = @window.prefresh(@pminrow, @pmincol, @top, @left, smaxrow(), smaxcol())
175
+ $log.warn " WREFRESH returns -1 ERROR - width or height must be exceeding " if ret == -1
176
+ @modified = false
177
+ return ret
178
+ end
179
+ ##
180
+ # copy the window to the pad (assumes we are writing onto win and keeping
181
+ # pad as backup
182
+ # also assuming only one win so, window not passed as param
183
+ # @return return value of copywin which should be 0 (-1 is ERR)
184
+ def copy_pad_to_win
185
+ $log.warn " DEPRECATED copy_pad_to_win" # CLEANUP
186
+ raise "DEPREC copy_pad_to_win deprecated. Will be removed. Let me know if it is needed"
187
+ # check that we don't exceed other windows height/maxrow
188
+ smr = smaxrow()
189
+ # SHIT, this means the otherwin has to be a Pad, cannot be a window
190
+ osw = @otherwin.width
191
+ osh = @otherwin.height
192
+ osh = @height if osh == 0 # root window has 0
193
+ osw = @width if osw == 0 # root window has 0
194
+ osmr = @otherwin.smaxrow() rescue osh # TRYING for windows
195
+ osmc = @otherwin.smaxcol() rescue osw
196
+ if smr >= osmr
197
+ $log.debug " adjusted smr from #{smr} to #{osmr} -1 causing issues in viewfooter"
198
+ smr = osmr-1 # XXX causing issues in viewport, wont print footer with this
199
+ end
200
+ if smr > @sheight + @top -1 -@pminrow # 2010-01-17 13:27
201
+ smr = @sheight + @top -1 -@pminrow
202
+ $log.debug " adjusted smr to #{smr} to prevent crash "
203
+ end
204
+ smc = smaxcol()
205
+ $log.debug " SMC original = #{smc} "
206
+ if smc >= osmc
207
+ smc = osmc-1
208
+ smc = @width # XXX ??? THIS WAS WORKING< but throwing error in viewport case
209
+ smc = [osmc-1, @width].min # yet another hack
210
+ $log.debug " SMC o-1 #{osmc-1} wdth #{@width}, smc #{smc} "
211
+ end
212
+ ### XXX commented out since it doesn't let a comp print fully if widget expanded (splitpane)
213
+ #smc = osw -1 if smc >= osw; # added 2009-11-02 17:01 for tabbedpanes
214
+
215
+ # dang, this is coming up a lot. 2010-01-16 20:34
216
+ # the second scrollpane was one row too large in testsplit3a.rb
217
+ if smr - @top > @padheight
218
+ $log.debug " fixing smr to padheight 2010-01-16 20:35 HOPE THIS DOESNT BREAK ANYTHING"
219
+ smr = @padheight
220
+ end
221
+ @pminrow = 0 if @pminrow < 0
222
+ @pmincol = 0 if @pmincol < 0
223
+ $log.debug " COPYING #{self.name} to #{@otherwin.name} "
224
+ $log.debug " calling copy pad #{@pminrow} #{@pmincol}, #{@top} #{@left}, #{smr} #{smc} self #{self.name} "
225
+ $log.debug " calling copy pad H: #{@height} W: #{@width}, PH #{@padheight} PW #{@padwidth} WIN:#{@window} "
226
+ # $log.debug " -otherwin target copy pad #{@otherwin.pminrow} #{@otherwin.pmincol}, #{@otherwin.top} #{@otherwin.left}, #{osmr} #{osmc} OTHERWIN:#{@otherwin.name} "
227
+ ret="-"
228
+ #if ret == -1
229
+ #x XXX $log.debug " #{ret} otherwin copy pad #{@otherwin.pminrow} #{@otherwin.pmincol}, #{@otherwin.top} #{@otherwin.left}, #{osmr} #{osmc} "
230
+ $log.debug " #{ret} otherwin copy pad H: #{osh} W: #{osw}"
231
+ if @top >= osh
232
+ $log.debug " #{ret} ERROR top exceeds other ht #{@top} H: #{osh} "
233
+ end
234
+ if @left >= osw
235
+ $log.debug " #{ret} ERROR left exceeds other wt #{@left} W: #{osw} "
236
+ end
237
+ if smr >= osh
238
+ $log.debug " #{ret} ERROR smrow exceeds other ht #{smr} H: #{osh} "
239
+ smr = osh() -1 # testing 2010-01-31 21:47 , again 2010-02-05 20:22
240
+ end
241
+ if smc >= osw
242
+ $log.debug " #{ret} ERROR smcol exceeds other wt #{smc} W: #{osw} "
243
+ end
244
+ if smc - @left > @padwidth
245
+ $log.debug " #{ret} ERROR smcol - left exceeds padwidth #{smc}- #{@left} PW: #{@padwidth} "
246
+ end
247
+ if smr - @top > @padheight
248
+ $log.debug " #{ret} ERROR smr - top exceeds padheight #{smr}- #{@top} PH: #{@padheight} "
249
+ end
250
+ ret = @window.copywin(@otherwin.get_window,@pminrow,@pmincol, @top, @left, smr, smc, 0)
251
+ $log.debug " copywin ret #{ret} "
252
+ # 2010-01-11 19:42 one more cause of -1 coming is that padheight (actual height which never
253
+ # changes unless pad increases) or padwidth is smaller than area being printed. Solution: increase
254
+ # buffer by increasing widgets w or h. smc - left should not exceed padwidth. smr-top should not
255
+ # exceed padheight
256
+ #end
257
+ @modified = false
258
+ return ret
259
+ end
260
+ # @deprecated
261
+ def copy_win_to_pad
262
+ $log.warn " DEPRECATED copy_win_to_pad" # CLEANUP 2011-09-29
263
+ raise "DEPREC copy_win_to_pad deprecated. Will be removed. Let me know if it is needed"
264
+ smr = smaxrow()
265
+ if smr >= @window.smaxrow()
266
+ smr = @window.smaxrow()-1
267
+ end
268
+ $log.debug " copy_win_to_pad #{@otherwin.name}, #{@window.name}, pminr:#{@pminrow} pminc:#{@pmincol} top:#{@top} left:#{@left} smr:#{smr} "
269
+ ret = @otherwin.copywin(@window.get_window,@pminrow,@pmincol, @top, @left, smr, smaxcol(), 1)
270
+ @modified = false
271
+ return ret
272
+ end
273
+ ##
274
+ #Used to overwrite the pad onto the screen window
275
+ # A window should have been specified as window to back (@see set_backing_window) or (@see create_with_window)
276
+ def overwrite_window
277
+ return @window.overwrite(@otherwin.get_window)
278
+ end
279
+
280
+ ##
281
+ # convenience method so that pad can use printstring but remove screen's row and col
282
+ # The absolute row and col will be taken into consideration when printing on screen.
283
+ #
284
+ # @param [Fixnum] row row to print on
285
+ # @param [Fixnum] col column to print on
286
+ # @param [String] value to print
287
+ # @param [Fixnum] color - color combination
288
+ # @param [Fixnum, nil] attrib defaults to NORMAL
289
+
290
+ # Pls remove the raise once the program is working, extra line can slow things down
291
+ # Keep it on when testing.
292
+ # If the raise is thrown, it means your object could be positioned higher than it should be,
293
+ # or at some point you have increased top, without increasing the objects row.
294
+ def printstring(row,col,value,color,attrib=Ncurses::A_NORMAL)
295
+ #$log.debug " pad printstring #{row} - #{@top} , #{col} - #{@left} "
296
+ raise "printstring row < top, pls correct code #{row} #{@top}, #{col} #{@left} " if row < @top or col < @left
297
+ #$log.warn "printstring row < top, pls correct code #{row} #{@top} " if row < @top
298
+ super(row - @top, col - @left, value, color, attrib)
299
+ end # printstring
300
+ # convenience method so that pad can use print_border but remove screen's row and col
301
+ # Please note that this requires that buffer have latest top and left.
302
+ def print_border row, col, height, width, color, att=Ncurses::A_NORMAL
303
+ $log.debug " pad printborder #{row} - #{@top} , #{col} - #{@left}, #{height} , #{width} "
304
+ raise "print_border: row < top, pls correct code #{row} #{@top}, #{col} #{@left} " if row < @top or col < @left
305
+ #$log.warn "print_border: row < top, pls correct code #{row} #{@top} " if row < @top
306
+ super(row - @top, col - @left, height, width, color, att)
307
+ end
308
+ def print_border_only row, col, height, width, color, att=Ncurses::A_NORMAL
309
+ $log.debug " pad printborder_only #{row} - #{@top} , #{col} - #{@left}, #{height} , #{width} "
310
+ raise "print_border row < top, pls correct code #{row} #{@top}, #{col} #{@left} " if row < @top or col < @left
311
+ super(row - @top, col - @left, height, width, color, att)
312
+ end
313
+ # use in place of mvwhline if your widget could be using a pad or window
314
+ def rb_mvwhline row, col, char, width
315
+ super(row-@top, col-@left, char, width)
316
+ end
317
+ # use in place of mvwvline if your widget could be using a pad or window
318
+ def rb_mvwvline row, col, char, width
319
+ super(row-@top, col-@left, char, width)
320
+ end
321
+ # use in place of mvaddch if your widget could be using a pad or window
322
+ def rb_mvaddch row, col, char
323
+ super(row-@top, col-@left, char)
324
+ end
325
+ end # class Pad
326
+ #-------------------------------- deprecated stuff ------------------ #
327
+ ##
328
+ # added RK 2009-10-08 23:57 for tabbedpanes
329
+ # THIS IS EXPERIMENTAL -
330
+ # I have not called super in the initializer so any methods you try on subwin
331
+ # that exist in the superclass which use @window will bomb
332
+ # @since 0.1.3 REMOVE UNUSED.
333
+ # @deprecated
334
+ class SubWindow < VER::Window
335
+ attr_reader :width, :height, :top, :left
336
+ attr_accessor :layout
337
+ attr_reader :panel # XXX reader requires so he can del it in end
338
+ attr_reader :subwin #
339
+ attr_reader :parent #
340
+
341
+ def initialize(parent, layout)
342
+ @visible = true
343
+ reset_layout(layout)
344
+
345
+ @parent = parent
346
+ #@subwin = @parent.get_window().derwin(@height, @width, @top, @left)
347
+ @subwin = @parent.get_window().subwin(@height, @width, @top, @left)
348
+ $log.debug "SUBWIN init #{@height} #{@width} #{@top} #{@left} "
349
+ #$log.debug "SUBWIN init #{@subwin.getbegx} #{@subwin.getbegy} #{@top} #{@left} "
350
+ @panel = Ncurses::Panel.new_panel(@subwin)
351
+
352
+ @window = @subwin # makes more mthods available
353
+ init_vars
354
+
355
+ end
356
+ # no need really now
357
+ def reset_layout layout
358
+ @layout = layout # 2010-02-13 22:23
359
+ @height = layout[:height]
360
+ @width = layout[:width]
361
+ @top = layout[:top]
362
+ @left = layout[:left]
363
+ end
364
+ def _destroy
365
+ # typically the ensure block should have this
366
+ # or should window do it for all subwins, or would we want to wait that long ?
367
+ $log.debug "subwin destroy"
368
+
369
+ Ncurses::Panel.del_panel(panel.pointer) if !panel.nil? # FFI
370
+ #@window.delwin(@window) if !@window.nil? # added FFI 2011-09-7
371
+ delwin if !@window.nil? # added FFI 2011-09-7
372
+ end
373
+ end
374
+
375
+ end
@@ -0,0 +1,512 @@
1
+ =begin
2
+ * Name: Scrollpane
3
+ * Description: a scrollable widget allowing user to scroll and view
4
+ parts of underlying object that typically are larger than screen area.
5
+ Mainly, contains a viewport, scrollbars and manages viewport through usage
6
+ of scrollbars.
7
+ Also contains viewport for row and columns.
8
+ * Author: rkumar
9
+ Todo section:
10
+ - add events, property changed etc at least for scrolling - DONE
11
+ SCrollpane normall should listen in to changes in viewport, however Scro calls those very methods
12
+ and what's more, other classes would listen to SCR and not to VP.
13
+ - scrollbars to be classes - shall we avoid over-engineering, and KISS
14
+ - if scrollpane reduced it should also resize, as example inside splitpane.
15
+ * file created 2009-10-27 19:20
16
+ * Added a call to child's set_form_col from set_form_row
17
+ Major changes 2010-02-11 19:51 to simplify version RFED16
18
+ * Still need to clean up this and viewport. make as light as possible
19
+ * If scrolling, no repainting should happen. Scrollpane could get the buffer
20
+ and scroll itself. Or ensure that inner object does not rework...
21
+
22
+ Pass handle_key to child, also repaint refer child.
23
+ Avoid passing to viewport as this would slow down alot.
24
+
25
+ NOTE: if a caller is interested in knowing what scrolling has happened, pls bind to :STATE_CHANGE, you will receive the viewport object. If you find this cumbersome, and wish to know only about scrolling, we can put in a scrolling event and inform of row or col scrolling. Or we can fire a property change with row or col increment.
26
+
27
+
28
+ --------
29
+ * License:
30
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
31
+
32
+ =end
33
+ #require 'rubygems'
34
+ #require 'ncurses'
35
+ require 'logger'
36
+ require 'rbcurse'
37
+ require 'rbcurse/rviewport'
38
+
39
+ #include Ncurses # FFI 2011-09-8
40
+ include RubyCurses
41
+ module RubyCurses
42
+ extend self
43
+
44
+ ##
45
+ # A scrollable box throgh which one can see portions of underlying object
46
+ # such as textarea, table or a form, usually the underlying data is larger
47
+ # than what can be displayed.
48
+
49
+ class ScrollPane < Widget
50
+ # viewport
51
+ # row_viewport
52
+ # column_viewport
53
+ # horizontal scrollbar 0-NONE, 1=ALWAYS, 2=AS_NEEDED
54
+ # vertical scrollbar 0-NONE, 1=ALWAYS, 2=AS_NEEDED
55
+ attr_accessor :cascade_changes # should changes in size go down to child, default false
56
+
57
+ def initialize form, config={}, &block
58
+ @focusable = true
59
+ @editable = false
60
+ #@left_margin = 1
61
+ @row = 0
62
+ @col = 0
63
+ super
64
+ @row_offset = @col_offset = 1
65
+ init_vars
66
+ @_events.push :STATE_CHANGE
67
+ # $log.debug " SCROLLPANE recvs form #{form.name}, #{form.window.name} " unless form.nil?
68
+
69
+
70
+ end
71
+ ##
72
+ # set child component being used in viewport
73
+ # @see set_viewport_view
74
+ def child ch
75
+ if ch != nil
76
+ @child = ch # added 2010-02-11 15:28 we might do away with viewport, setting panned to child
77
+ @child.rows_panned = @child.cols_panned = 0
78
+
79
+ ch.parent_component = self # added 2010-01-13 12:55 so offsets can go down ?
80
+
81
+ @child.should_create_buffer = true
82
+ @form.add_rows += 2 # related to scr_top XXX What if form not set. i cannot keep accumulating
83
+ update_child
84
+ # -3 since we start row +1 to get indented by 1, also we use
85
+ # height -1 in scrollpane, so we need -2 to indent, and one more
86
+ # for row
87
+ set_viewport_view(ch)
88
+ end
89
+ end
90
+ ##
91
+ # update of child's coordinates, needs to be called whenever it
92
+ # changes, so i need to call it before calling child's update
93
+ # FIXME - this is become 2 calls, make it one - becoming expensive
94
+ # if called often
95
+ def update_child
96
+ scr_top = 3 # for Pad, if Pad passed as in SplitPane
97
+ scr_left = 1 # for Pad, if Pad passed as in SplitPane
98
+ if @form.window.window_type == :WINDOW
99
+ scr_top = @row + 1
100
+ scr_left = @col + 1
101
+ @child.row(@row+@row_offset)
102
+ @child.col(@col+@col_offset)
103
+ else
104
+ # PAD case
105
+ @child.row(scr_top)
106
+ @child.col(scr_left)
107
+ end
108
+ @child.set_buffering(:target_window => @target_window || @form.window, :form => @form, :bottom => @height-3, :right => @width-3 )
109
+ @child.set_buffering(:screen_top => scr_top, :screen_left => scr_left)
110
+ # lets set the childs ext offsets
111
+ $log.debug "SCRP #{name} adding (to #{@child.name}) ext_row_off: #{@child.ext_row_offset} += #{@ext_row_offset} +#{@row_offset} "
112
+ $log.debug "SCRP adding ext_col_off: #{@child.ext_col_offset} += #{@ext_col_offset} +#{@col_offset} "
113
+ ## 2010-02-09 18:58 i think we should not put col_offset since the col
114
+ ## of child would take care of that. same for row_offset. XXX
115
+ @child.ext_col_offset += @ext_col_offset + @col + @col_offset - @screen_left # 2010-02-09 19:14
116
+ # added row and col setting to child RFED16 2010-02-17 00:22 as
117
+ # in splitpane. seems we are not using ext_offsets now ? texta
118
+ # and TV are not. and i've commented off from widget
119
+
120
+ $log.debug " #{@child.ext_row_offset} += #{@ext_row_offset} + #{@row} -#{@screen_top} "
121
+ @child.ext_row_offset += @ext_row_offset + @row + @row_offset - @screen_top
122
+ # adding this since child's ht should not be less. or we have a
123
+ # copywin failure
124
+ @child.height ||= @height
125
+ @child.width ||= @width
126
+ if @child.height < @height
127
+ @child.height = @height
128
+ end
129
+ if @child.width < @width
130
+ @child.width = @width
131
+ end
132
+
133
+ end
134
+ def init_vars
135
+ #@curpos = @pcol = @toprow = @current_index = 0
136
+ @hsb_policy = :AS_NEEDED
137
+ @vsb_policy = :AS_NEEDED
138
+ @repaint_required = true
139
+ @repaint_border = true
140
+ @row_outofbounds=0
141
+ @col_outofbounds=0
142
+ @border_width = 2
143
+ @screen_top = 0
144
+ @screen_left = 0
145
+ end
146
+ # set the component to be viewed
147
+ def set_viewport_view ch
148
+ @viewport = Viewport.new nil
149
+ @viewport.set_view ch
150
+ ## this -2 should depend on whether we are putting border/scrollbars or not.
151
+ # -1 added on 2010-02-16 23:35 since we are red 1, and bw
152
+ @viewport.set_view_size(@height-@border_width-0, @width-@border_width-0) # XXX make it one less
153
+ @viewport.cascade_changes = @cascade_changes # added 2010-02-04 18:19
154
+ @viewport.bind(:STATE_CHANGE) { |e| view_state_changed(e) }
155
+ @viewport.bind(:PROPERTY_CHANGE) { |e| view_property_changed(e) }
156
+ end
157
+ # return underlying viewport
158
+ # in order to run some of its methods
159
+ def get_viewport
160
+ return @viewport
161
+ end
162
+ # Directly set the viewport.
163
+ # Usually it is best to use set_viewport_view instead
164
+ def set_viewport vp
165
+ old = @viewport
166
+ @viewport = vp
167
+ fire_property_change "viewport", old, @viewport
168
+ end
169
+ # sets the component to be used as a rowheader TODO
170
+ def set_rowheader_view ch
171
+ old = @rowheader
172
+ @rowheader = Viewport.new
173
+ @rowheader.set_view ch
174
+ fire_property_change "row_header", old, @rowheader
175
+ end
176
+ # sets the component to be used as a column header TODO
177
+ def set_columnheader_view ch
178
+ old = @columnheader
179
+ @columnheader = Viewport.new
180
+ @columnheader.set_view ch
181
+ fire_property_change "column_header", old, @columnheader
182
+ end
183
+ def set_view_size h,w
184
+ # calling the property shoudl uniformally trigger fire_property_change
185
+ @viewport.set_view_size h,w
186
+ #height(h)
187
+ #width(w)
188
+ #fire_handler :PROPERTY_CHANGE, self # XXX should it be an event STATE_CHANGED with details
189
+ end
190
+ ## seems i wrote this only so i could set repaint_required to true
191
+ # However, now that VP calls state changed, that will happen XXX
192
+ def set_view_position r,c
193
+ ret = @viewport.set_view_position r,c
194
+ if ret
195
+ @repaint_required = true if ret
196
+ # fire_property_change("view_position",
197
+ end
198
+ return ret
199
+ end
200
+ # this method is registered with Viewport for changes
201
+ def view_state_changed ev
202
+ fire_handler :STATE_CHANGE, ev #???
203
+ @repaint_required = true
204
+ end
205
+ # this method is registered with Viewport for changes to properties
206
+ def view_property_changed ev
207
+ fire_handler :PROPERTY_CHANGE, ev #???
208
+ @repaint_required = true
209
+ end
210
+ # @return [true, false] false if r,c not changed
211
+ def increment_view_row num
212
+ #x r = @viewport.row() #- @viewport.top_margin
213
+ #x c = @viewport.col() #- @viewport.left_margin
214
+ r, c = @viewport.get_pad_top_left()
215
+ $log.debug " SCR inc viewport currently : r #{r} c #{c} "
216
+ r += num
217
+ ret = set_view_position r, c
218
+ v_scroll_bar if ret
219
+ return ret
220
+ end
221
+ # @return [true, false] false if r,c not changed
222
+ def increment_view_col num
223
+ r, c = @viewport.get_pad_top_left()
224
+ #r = @viewport.row() #- @viewport.top_margin
225
+ #c = @viewport.col() #- @viewport.left_margin
226
+ c += num
227
+ ret = set_view_position r, c
228
+ h_scroll_bar if ret
229
+ return ret
230
+ end
231
+ def repaint # scrollpane
232
+ # viewports child should repaint onto pad
233
+ # viewport then clips
234
+ # this calls viewports refresh from its refresh
235
+ return unless @repaint_required
236
+ if @viewport
237
+ update_child
238
+ $log.debug "SCRP #{@name} calling viewport repaint"
239
+ #@viewport.repaint_all true # 2010-01-16 23:09
240
+ @viewport.repaint_required true # changed 2010-01-19 19:34
241
+ @viewport.repaint # child's repaint should do it on its pad
242
+ $log.debug " #{@name} SCRP scrollpane repaint #{@graphic.name} "
243
+ end
244
+ # TODO this only if major change
245
+ if @repaint_border && @repaint_all # added 2010-01-16 20:15
246
+ #@graphic.wclear
247
+ $log.debug " #{@name} repaint all scroll: r #{@row} c #{@col} h #{@height}-1 w #{@width} "
248
+ bordercolor = @border_color || $datacolor
249
+ borderatt = @border_attrib || Ncurses::A_NORMAL
250
+ # NOTE - should be width-1 print_b reduces one from width, but
251
+ # not height !
252
+
253
+ @graphic.print_border_only(@row, @col, @height-1, @width, bordercolor, borderatt)
254
+ h_scroll_bar
255
+ v_scroll_bar
256
+ #x XXX @viewport.repaint_all(true) unless @viewport.nil? # brought here 2010-01-19 19:34
257
+ #@repaint_border = false # commented off on 2010-01-16 20:15 so repaint_all can have effect
258
+ end
259
+ return if @viewport == nil
260
+ $log.debug "SCRP #{@name} calling viewport to SCRP b2s #{@graphic.name} "
261
+ paint
262
+ end
263
+ def getvalue
264
+ # TODO
265
+ end
266
+ ## handle keys for scrollpane.
267
+ # First hands key to child object
268
+ # If unused, checks to see if it has anything mapped.
269
+ # If not consumed, returns :UNHANDLED, else 0.
270
+ def handle_key ch
271
+ # if this gets key it should just hand it to child
272
+ return :UNHANDLED if @viewport.nil? # added 2010-02-02 12:44
273
+ if @viewport != nil
274
+ $log.debug " calling child handle_key #{ch} "
275
+ ret = @viewport.handle_key ch
276
+ # XXX ret returns 0under normal circumstance, so will next line work ?
277
+ # what i mean is if ret == 0
278
+
279
+ @repaint_required = true if ret == 0 # added 2009-12-27 22:21 BUFFERED
280
+ $log.debug " ... child ret #{ret}"
281
+
282
+
283
+ ## Here's the only option scrollpane has of checking whether the child has
284
+ ##+ exceeded boundary BUFFERED 2009-12-29 23:12
285
+ # TEMPORARILY COMMENTED WHILE TESTING SCROLL UP AND DOWN XXX
286
+ #fr = @form.row
287
+ #fc = @form.col
288
+ #if fr >= @row + @height -2
289
+ #@form.setrowcol @row + @height -2, fc
290
+ #elsif fr < @row
291
+ #@form.setrowcol @row, fc
292
+ #end
293
+ #if fc >= @col + @width -1
294
+ #@form.setrowcol fr, @col + @width -1
295
+ #end
296
+ ##
297
+
298
+ return ret if ret != :UNHANDLED
299
+ end
300
+ ret = 0 # default return value
301
+ ks = keycode_tos(ch)
302
+ $log.debug " scrollpane gets KEY #{ch}, ks #{ks} "
303
+ case ch
304
+ when ?\M-n.getbyte(0)
305
+ ## scroll down one row (unless multiplier set)
306
+ ret = down
307
+ when ?\M-p.getbyte(0)
308
+ ## scroll up one row (unless multiplier set)
309
+ ret = up
310
+ #when ?0.getbyte(0), ?\C-[.getbyte(0)
311
+ #goto_start #start of buffer # cursor_start
312
+ #when ?\C-].getbyte(0)
313
+ #goto_end # end / bottom cursor_end # TODO
314
+ when ?\M-\<.getbyte(0)
315
+ @height.times { up ; }
316
+ when ?\M-\>.getbyte(0)
317
+ @height.times { down ; }
318
+ when KEY_DOWN
319
+ ret = down
320
+ #check_curpos
321
+ when ?\M-h.getbyte(0)
322
+ ## scroll left one position
323
+ repeatm {
324
+ ret = cursor_backward
325
+ @child.cols_panned = @child.cols_panned+1 if ret
326
+ @form.setrowcol @form.row, @form.col+1+@col_outofbounds if ret
327
+ }
328
+ when ?\M-l.getbyte(0)
329
+ ## scroll right one position
330
+ repeatm {
331
+ ret = cursor_forward
332
+ @child.cols_panned = @child.cols_panned-1 if ret
333
+ @form.setrowcol @form.row, @form.col-1+@col_outofbounds if ret
334
+ }
335
+ when KEY_BACKSPACE, KEY_BSPACE
336
+ ret = cursor_backward
337
+ #when ?\C-u.getbyte(0)
338
+ ## multiplier. Series is 4 16 64
339
+ #@multiplier = (@multiplier == 0 ? 4 : @multiplier *= 4)
340
+ #return 0
341
+ when ?\C-c.getbyte(0)
342
+ $multiplier = 0
343
+ return 0
344
+ else
345
+ return :UNHANDLED
346
+ end
347
+ ret = :UNHANDLED if !ret
348
+ $multiplier = 0
349
+ return ret # 0 2010-02-04 18:47 returning ret else repaint is happening when UNHANDLED
350
+ end
351
+ # private
352
+ def _down
353
+ increment_view_row(1)
354
+ end
355
+ # private
356
+ def _up
357
+ increment_view_row(-1)
358
+ end
359
+ def cursor_forward
360
+ increment_view_col(1)
361
+ end
362
+ def cursor_backward
363
+ increment_view_col(-1)
364
+ end
365
+ def down
366
+ ## scroll down one row (currently one only)
367
+ $log.debug " MULT DOWN #{$multiplier} "
368
+ repeatm {
369
+ ret = _down
370
+ return unless ret # 2010-02-04 18:29
371
+ ## we've scrolled down, but we need to keep the cursor where
372
+ ##+ editing actually is. Isn't this too specific to textarea ?
373
+ $log.debug " SCRP setting row to #{@form.row-1} upon scrolling down "
374
+ ## only move up the cursor if its within bounds
375
+ # if @form.row > @row
376
+ @child.rows_panned = @child.rows_panned-1 if ret
377
+ @form.setrowcol @form.row-1+@row_outofbounds, @form.col if ret
378
+ }
379
+ end
380
+ def up
381
+ ## scroll up one row (currently one only)
382
+ repeatm {
383
+ ret = _up
384
+ return unless ret # 2010-02-04 18:29
385
+ $log.debug " SCRP setting row to #{@form.row+1} upon scrolling up R:#{@row} H:#{@height} "
386
+ # if @form.row < @row + @height
387
+ @child.rows_panned = @child.rows_panned+1 if ret
388
+ @form.setrowcol @form.row+1+@row_outofbounds, @form.col if ret
389
+ }
390
+ end
391
+ def on_enter
392
+ #super 2010-01-02 18:53 leading to a stack overflow XXX ???
393
+ set_form_row
394
+ end
395
+ # this is called once externally, on on_enter
396
+ #+ after that its called internally only, which in this case is never
397
+ def set_form_row
398
+ #@form.row = @row + 1 unless @form.nil?
399
+ if @viewport != nil
400
+ #$log.debug " calling scrollpane set_form_row"
401
+ ret = @viewport.child.set_form_row # added 2009-12-27 23:23 BUFFERED
402
+ ret = @viewport.child.set_form_col # added 2010-01-16 21:09
403
+ end
404
+ $log.debug " FORM SCRP #{@form.name} "
405
+ $log.debug "SCRP set_form_row #{@form.row} #{@form.col} "
406
+ end
407
+ ## added 2010-02-09 10:17
408
+ # Sometimes some parent objects may just call this.
409
+ # Would be better if they only called row and row called both ??? or is that less reliable
410
+ # In any case we have to combine this someday!!
411
+ def set_form_col
412
+ #@form.row = @row + 1 unless @form.nil?
413
+ if @viewport != nil
414
+ #$log.debug " calling scrollpane set_form_row"
415
+ ret = @viewport.child.set_form_col # added 2010-01-16 21:09
416
+ end
417
+ $log.debug " FORM SCRP #{@form.name} "
418
+ $log.debug "SCRP set_form_col #{@form.row} #{@form.col} "
419
+ end
420
+
421
+ ## this is called once only, on select_field by form.
422
+ ##+ after that not at all.
423
+ def rowcol
424
+ r1 = @row #+@row_offset
425
+ c1 = @col #+@col_offset
426
+ return r1, c1 if @viewport.nil? # added 2010-02-02 12:41
427
+
428
+ r,c = @viewport.child.rowcol # added 2009-12-28 15:23 BUFFERED
429
+ $log.debug "SCRP rowcol: #{r1} + #{r} , #{c1} + #{c} "
430
+ return r1+r, c1+c
431
+ end
432
+
433
+ def paint
434
+ @repaint_required = false
435
+ @repaint_all = false
436
+ end
437
+ def h_scroll_bar
438
+ return if @viewport.nil?
439
+ sz = (@viewport.width*1.00/@viewport.child().width)*@viewport.width
440
+ #$log.debug " h_scroll_bar sz #{sz}, #{@viewport.width} #{@viewport.child().width}"
441
+ sz = sz.ceil
442
+ return if sz < 1
443
+ start = 1
444
+ start = ((@viewport.col*1.00+@viewport.width)/@viewport.child().width)*@viewport.width
445
+ start -= sz
446
+ start = start.ceil
447
+ # # the problem with next 2 lines is that attributes of border could be overwritten
448
+ # draw horiz line
449
+ r = @row #+ @ext_row_offset # 2010-02-11 11:57 RFED16
450
+ c = @col #+ @ext_col_offset # 2010-02-11 11:57 RFED16
451
+ $log.debug " h_scroll_bar start #{start}, r #{r} c #{c} h:#{@height} "
452
+ @graphic.rb_mvwhline(r+@height-1, c+1, FFI::NCurses::ACS_HLINE, @width-2)
453
+ # draw scroll bar
454
+ #sz.times{ |i| @graphic.mvaddch(r+@height-1, c+start+1+i, FFI::NCurses::ACS_CKBOARD) }
455
+ sz.times{ |i| @graphic.rb_mvaddch(r+@height-1, c+start+1+i, FFI::NCurses::ACS_CKBOARD) }
456
+ end
457
+ def v_scroll_bar
458
+ return if @viewport.nil?
459
+ sz = (@viewport.height*1.00/@viewport.child().height)*@viewport.height
460
+ #$log.debug " v_scroll_bar sz #{sz}, #{@viewport.width} #{@viewport.child().width}"
461
+ sz = sz.ceil
462
+ return if sz < 1
463
+ start = 1
464
+ start = ((@viewport.row*1.00+@viewport.height)/@viewport.child().height)*@viewport.height
465
+ start -= sz
466
+ r = @row #+ @ext_row_offset # 2010-02-11 11:57 RFED16
467
+ c = @col #+ @ext_col_offset # 2010-02-11 11:57 RFED16
468
+ $log.debug " v_scroll_bar start #{start}, col:#{@col} w:#{@width}, r #{r}+1 c #{c}+w-1 "
469
+ start = start.ceil
470
+ # # the problem with next 2 lines is that attributes of border could be overwritten
471
+ # draw verti line
472
+ # this is needed to erase previous bar when shrinking
473
+ #@graphic.mvwvline(r+1,c+@width-1, FFI::NCurses::ACS_VLINE, @height-2)
474
+ @graphic.rb_mvwvline(r+1,c+@width-1, FFI::NCurses::ACS_VLINE, @height-2)
475
+ # draw scroll bar
476
+ #sz.times{ |i| @graphic.mvaddch(r+start+1+i, c+@width-1, FFI::NCurses::ACS_CKBOARD) }
477
+ sz.times{ |i| @graphic.rb_mvaddch(r+start+1+i, c+@width-1, FFI::NCurses::ACS_CKBOARD) }
478
+ end
479
+ # set height
480
+ # a container must pass down changes in size to it's children
481
+ # 2010-02-04 18:06 - i am not sure about this. When viewport is set then it passes down
482
+ # changes to child which user did not intend. Maybe in splitpane it is okay but other cases?
483
+ # Perhaps its okay if scrollpane gets larger than child, not otherwise.
484
+ # added 2010-01-16 23:55
485
+ def height(*val)
486
+ return @height if val.empty?
487
+ oldvalue = @height || 0
488
+ super
489
+ @height = val[0]
490
+ return if @viewport == nil
491
+ delta = @height - oldvalue
492
+ return if delta == 0
493
+ @repaint_required = true
494
+ @viewport.height += delta
495
+ end
496
+ # set width
497
+ # a container must pass down changes in size to it's children
498
+ # added 2010-01-16 23:55
499
+ def width(*val)
500
+ return @width if val.empty?
501
+ oldvalue = @width || 0
502
+ super
503
+ @width = val[0]
504
+ return if @viewport == nil
505
+ delta = @width - oldvalue
506
+ return if delta == 0
507
+ @repaint_required = true
508
+ @viewport.width += delta
509
+ end
510
+
511
+ end # class ScrollPane
512
+ end # module