rbcurse 0.1.3 → 1.1.1

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 (74) hide show
  1. data/CHANGELOG +126 -0
  2. data/Manifest.txt +53 -20
  3. data/README.markdown +423 -0
  4. data/Rakefile +3 -1
  5. data/examples/keytest.rb +177 -0
  6. data/examples/mpad2.rb +156 -0
  7. data/examples/newtesttabp.rb +121 -0
  8. data/examples/rfe.rb +48 -10
  9. data/examples/rfe_renderer.rb +4 -4
  10. data/examples/rvimsplit.rb +376 -0
  11. data/examples/sqlc.rb +97 -106
  12. data/examples/sqlm.rb +446 -0
  13. data/examples/test1.rb +4 -4
  14. data/examples/test2.rb +12 -12
  15. data/examples/testchars.rb +140 -0
  16. data/examples/testkeypress.rb +9 -4
  17. data/examples/testmulticomp.rb +72 -0
  18. data/examples/testscroller.rb +136 -0
  19. data/examples/testscrolllb.rb +86 -0
  20. data/examples/testscrollp.rb +87 -0
  21. data/examples/testscrollta.rb +80 -0
  22. data/examples/testscrolltable.rb +166 -0
  23. data/examples/testsplit.rb +87 -0
  24. data/examples/testsplit2.rb +123 -0
  25. data/examples/testsplit3.rb +215 -0
  26. data/examples/testsplit3_1.rb +244 -0
  27. data/examples/testsplit3a.rb +215 -0
  28. data/examples/testsplit3b.rb +237 -0
  29. data/examples/testsplitta.rb +148 -0
  30. data/examples/testsplittv.rb +142 -0
  31. data/examples/testsplittvv.rb +144 -0
  32. data/examples/testtable.rb +1 -1
  33. data/examples/testtabp.rb +3 -2
  34. data/examples/testtestw.rb +69 -0
  35. data/examples/testtodo.rb +5 -3
  36. data/examples/testtpane.rb +203 -0
  37. data/examples/testtpane2.rb +145 -0
  38. data/examples/testtpanetable.rb +199 -0
  39. data/examples/viewtodo.rb +5 -3
  40. data/lib/rbcurse.rb +1 -1
  41. data/lib/rbcurse/celleditor.rb +2 -2
  42. data/lib/rbcurse/colormap.rb +5 -5
  43. data/lib/rbcurse/defaultlistselectionmodel.rb +3 -3
  44. data/lib/rbcurse/io.rb +663 -0
  45. data/lib/rbcurse/listeditable.rb +306 -0
  46. data/lib/rbcurse/listkeys.rb +15 -15
  47. data/lib/rbcurse/listscrollable.rb +168 -27
  48. data/lib/rbcurse/mapper.rb +35 -13
  49. data/lib/rbcurse/rchangeevent.rb +28 -0
  50. data/lib/rbcurse/rform.rb +845 -0
  51. data/lib/rbcurse/rlistbox.rb +144 -34
  52. data/lib/rbcurse/rmessagebox.rb +10 -5
  53. data/lib/rbcurse/rmulticontainer.rb +325 -0
  54. data/lib/rbcurse/rmultitextview.rb +306 -0
  55. data/lib/rbcurse/rscrollform.rb +369 -0
  56. data/lib/rbcurse/rscrollpane.rb +511 -0
  57. data/lib/rbcurse/rsplitpane.rb +820 -0
  58. data/lib/rbcurse/rtabbedpane.rb +737 -109
  59. data/lib/rbcurse/rtabbedwindow.rb +326 -0
  60. data/lib/rbcurse/rtable.rb +220 -64
  61. data/lib/rbcurse/rtextarea.rb +340 -181
  62. data/lib/rbcurse/rtextview.rb +237 -101
  63. data/lib/rbcurse/rviewport.rb +203 -0
  64. data/lib/rbcurse/rwidget.rb +919 -95
  65. data/lib/rbcurse/scrollable.rb +7 -7
  66. data/lib/rbcurse/selectable.rb +4 -4
  67. data/lib/rbcurse/table/tablecellrenderer.rb +3 -0
  68. data/lib/rbcurse/undomanager.rb +181 -0
  69. data/lib/rbcurse/vieditable.rb +100 -0
  70. data/lib/ver/window.rb +471 -21
  71. metadata +66 -22
  72. data/README.txt +0 -312
  73. data/examples/testd.db +0 -0
  74. data/examples/todocsv.csv +0 -28
@@ -0,0 +1,306 @@
1
+ =begin
2
+ * Name: MultiTextView
3
+ * Description View text in this widget for multiple files
4
+ * This differs from multicontainer in that since all components are textviews, so they
5
+ * are all gauranteed to be non-editable and thus we can map many more keys.
6
+ * MultiContainer can only map Ctrl and Alt (Meta) keys.
7
+ * Author: rkumar (arunachalesha)
8
+ * file created 2010-03-11 08:05
9
+ --------
10
+ * License:
11
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
12
+
13
+ =end
14
+ require 'rubygems'
15
+ require 'ncurses'
16
+ require 'logger'
17
+ require 'rbcurse'
18
+ require 'rbcurse/rtextview'
19
+ require 'rbcurse/listscrollable'
20
+
21
+ include Ncurses
22
+ include RubyCurses
23
+ module RubyCurses
24
+ extend self
25
+
26
+ ##
27
+ # A viewable read only box. Can scroll.
28
+ # Extends TextView with ability to load more than one file or content
29
+ # and switch between files (buffers).
30
+ # NOTE: ideally, i should be able to dynamically add this functionality to either Textview
31
+ # or TextArea or even ListBox or Table someday. Should then be a Module rather than a class.
32
+ class MultiTextView < TextView
33
+ include ListScrollable
34
+
35
+ def initialize form = nil, config={}, &block
36
+
37
+ super
38
+ @bmanager = BufferManager.new self
39
+
40
+ end
41
+ def init_vars
42
+ super
43
+ bind_key(?:, :buffer_menu)
44
+ bind_key(?e, :file_edit)
45
+ bind_key([?\C-x, ?f], :file_edit)
46
+ bind_key([?\C-x, ?k], :buffer_delete)
47
+ bind_key([?\C-x, ?\C-b], :buffers_list)
48
+ # easily cycle using p. n is used for next search.
49
+ bind_key(?p, :buffer_previous)
50
+ end
51
+ ## returns current buffer
52
+ # @return [RBuffer] current buffer
53
+ def current_buffer
54
+ @bmanager.current
55
+ end
56
+ ##
57
+ # send in a list
58
+ # e.g. set_content File.open("README.txt","r").readlines
59
+ # set wrap at time of passing :WRAP_NONE :WRAP_WORD
60
+ # @see add (add takes a title too which is required here)
61
+ def set_content list, wrap = :WRAP_NONE
62
+ ret = super
63
+ # buff = @bmanager.add_content @list
64
+ return ret
65
+ end
66
+ # multi-textview
67
+ def handle_key ch
68
+ # put list as current list and buffer too then super
69
+ #@current_buffer = @bmanager.current
70
+ #@list = @current_buffer.list
71
+ @buffer = @list[@current_index]
72
+ #@buffer = @bmanager.current
73
+ ret = super
74
+ # check for any keys not handled and check our own ones
75
+ return ret #
76
+ end
77
+ ## prompt user for a filename to read in
78
+ def getfilename prompt="Enter filename: ", maxlen=90
79
+ tabc = Proc.new {|str| Dir.glob(str +"*") }
80
+ config={}; config[:tab_completion] = tabc
81
+ #config[:default] = "defaulT"
82
+ $log.debug " inside getstr before call #{$error_message_row} + #{$error_message_col} "
83
+ #ret, str = rbgetstr(@form.window, @row+@height-1, @col+1, prompt, maxlen, config)
84
+ ret, str = rbgetstr(@form.window, $error_message_row, $error_message_col, prompt, maxlen, config)
85
+ $log.debug " rbgetstr returned #{ret} , #{str} "
86
+ return "" if ret != 0
87
+ return str
88
+ end
89
+ # this is just a test of the simple "most" menu
90
+ # can use this for next, prev, first, last, new, delete, overwrite etc
91
+ def buffer_menu
92
+ menu = PromptMenu.new self
93
+ menu.add(menu.create_mitem( 'e', "edit a file", "opened file ", :file_edit ))
94
+ menu.add(menu.create_mitem( 'o', "overwrite file", "opened a file ", :file_overwrite ))
95
+ menu.add(menu.create_mitem( 'l', "list buffers", "list buffers ", :buffers_list ))
96
+ item = menu.create_mitem( 'b', "Buffer Options", "Buffer Options" )
97
+ menu1 = PromptMenu.new( self, "Buffer Options")
98
+ menu1.add(menu1.create_mitem( 'n', "Next", "Switched to next buffer", :buffer_next ))
99
+ menu1.add(menu1.create_mitem( 'p', "Prev", "Switched to previous buffer", :buffer_previous ))
100
+ menu1.add(menu1.create_mitem( 'f', "First", "Switched to first buffer", :buffer_first ))
101
+ menu1.add(menu1.create_mitem( 'l', "Last", "Switched to last buffer", :buffer_last ))
102
+ menu1.add(menu1.create_mitem( 'd', "Delete", "Deleted buffer", :buffer_delete ))
103
+ item.action = menu1
104
+ menu.add(item)
105
+ # how do i know what's available. the application or window should know where to place
106
+ menu.display @form.window, $error_message_row, $error_message_col, $datacolor #, menu
107
+ end
108
+
109
+ %w[next previous first last].each do |pos|
110
+ eval(
111
+ "def _buffer_#{pos}
112
+ @current_buffer = @bmanager.#{pos}
113
+ set_current_buffer
114
+ end"
115
+ )
116
+ end
117
+
118
+ def buffer_next
119
+ perror "No other buffer" and return if @bmanager.size < 2
120
+
121
+ @current_buffer = @bmanager.next
122
+ set_current_buffer
123
+ end
124
+ def buffer_previous
125
+ perror "No other buffer" and return if @bmanager.size < 2
126
+
127
+ @current_buffer = @bmanager.previous
128
+ $log.debug " buffer_prev got #{@current_buffer} "
129
+ set_current_buffer
130
+ end
131
+ def buffer_first
132
+ @current_buffer = @bmanager.first
133
+ $log.debug " buffer_first got #{@current_buffer} "
134
+ set_current_buffer
135
+ end
136
+ def buffer_last
137
+ @current_buffer = @bmanager.last
138
+ $log.debug " buffer_last got #{@current_buffer} "
139
+ set_current_buffer
140
+ end
141
+ def buffer_delete
142
+ if @bmanager.size > 1
143
+ @bmanager.delete_at
144
+ @current_buffer = @bmanager.previous
145
+ set_current_buffer
146
+ else
147
+ perror "Only one buffer. Cannot delete."
148
+ end
149
+ end
150
+ def buffers_list
151
+ menu = PromptMenu.new self
152
+ @bmanager.each_with_index{ |b, ix|
153
+ aproc = Proc.new { buffer_at(ix) }
154
+ name = b.title
155
+ num = ix + 1
156
+ menu.add(menu.create_mitem( num.to_s, name, "Switched to buffer #{ix}", aproc ))
157
+ }
158
+ menu.display @form.window, $error_message_row, $error_message_col, $datacolor
159
+ end
160
+ # prompts user for filename and opens in buffer
161
+ # Like vim's :e
162
+ def file_edit
163
+ file = getfilename()
164
+ $log.debug " got file_edit: #{file} "
165
+ return if file == ""
166
+ add file, file
167
+ end
168
+ # load a file into the textview.
169
+ # This is the preferred method since it lets us add a title too
170
+ # Shucks, this misses wrap_style which the other one has
171
+ # @param [String] filename
172
+ def add file, title
173
+ begin
174
+ @current_buffer = @bmanager.add file, title
175
+ $log.debug " file edit got cb : #{@current_buffer} "
176
+ set_current_buffer
177
+ rescue => err
178
+ $error_message = "Error: #{err} "
179
+ @form.window.print_error_message
180
+ Ncurses.beep
181
+ return -1
182
+ end
183
+ end
184
+ def buffer_at index
185
+ @current_buffer = @bmanager.element_at index
186
+ $log.debug " buffer_last got #{@current_buffer} "
187
+ set_current_buffer
188
+ end
189
+ def set_current_buffer
190
+ @current_index = @current_buffer.current_index
191
+ @curpos = @current_buffer.curpos
192
+ @title = @current_buffer.title
193
+ @list = @current_buffer.list
194
+ end
195
+ def perror errmess=$error_message
196
+ @form.window.print_error_message errmess
197
+ end
198
+ end # class multitextview
199
+ ##
200
+ # Handles multiple buffers, navigation, maintenance etc
201
+ # Instantiated at startup of MultiTextView
202
+ #
203
+ class BufferManager
204
+ include Enumerable
205
+ def initialize source
206
+ @source = source
207
+ @buffers = [] # contains RBuffer
208
+ @counter = 0
209
+ # for each buffer i need to store data, current_index (row), curpos (col offset) and title (filename).
210
+ end
211
+ def element_at index
212
+ @buffers[index]
213
+ end
214
+ def each
215
+ @buffers.each {|k| yield(k)}
216
+ end
217
+ ##
218
+ # @return [RBuffer] current buffer/file
219
+ ##
220
+ def current
221
+ @buffers[@counter]
222
+ end
223
+ ##
224
+ # Would have liked to just return next buffer and not get lost in details of caller
225
+ #
226
+ # @return [RBuffer] next buffer/file
227
+ ##
228
+ def next
229
+ @counter += 1
230
+ @counter = 0 if @counter >= @buffers.size
231
+ @buffers[@counter]
232
+ end
233
+ ##
234
+ # @return [RBuffer] previous buffer/file
235
+ ##
236
+ def previous
237
+ $log.debug " previous bs: #{@buffers.size}, #{@counter} "
238
+ @counter -= 1
239
+ return last() if @counter < 0
240
+ $log.debug " previous ctr #{@counter} "
241
+ @buffers[@counter]
242
+ end
243
+ def first
244
+ @counter = 0
245
+ @buffers[@counter]
246
+ end
247
+ def last
248
+ @counter = @buffers.size - 1
249
+ @buffers[@counter]
250
+ end
251
+ ##
252
+ def delete_at index=@counter
253
+ @buffers.delete_at index
254
+ end
255
+ def delete_by_name name
256
+ @buffers.delete_if {|b| b.filename == name }
257
+ end
258
+ def insert filename, position, title=nil
259
+ # read up file
260
+ list = @source.set_content File.open(filename,"r").readlines
261
+ # set new RBuffer
262
+ title = filename unless title
263
+ raise "invalid value for list, Should be an array #{list.class} " unless list.is_a? Array
264
+ anew = RBuffer.new(list, 0, 0, filename, title)
265
+ #@buffers << anew
266
+ @buffers.insert position, anew
267
+ @counter = position
268
+ return anew
269
+ end
270
+ def add filename, title=nil
271
+ insert filename, @buffers.size, title
272
+ end
273
+ def insert_content str, position, title="UNTitled"
274
+ case str
275
+ when String
276
+ # put str into list
277
+ @source.set_content str
278
+ list = @list
279
+ when Array
280
+ list = str
281
+ end
282
+ anew = RBuffer.new(list, 0, 0, "", title)
283
+ #@buffers << anew
284
+ @buffers.insert position, anew
285
+ @counter = position
286
+ return anew
287
+ end
288
+ # add content (array or str) to buffer list as a new buffer
289
+ def add_content str, title="UNtitled"
290
+ $log.debug " inside BUFFER MANAGER "
291
+ insert_content str, @buffers.size, title
292
+ end
293
+ def size
294
+ @buffers.size
295
+ end
296
+ alias :count :size
297
+ def index buff
298
+ return @buffers.index
299
+ end
300
+ end
301
+ RBuffer = Struct.new(:list, :current_index, :curpos, :filename, :title) do
302
+ def xxx
303
+ end
304
+ end
305
+
306
+ end # modul
@@ -0,0 +1,369 @@
1
+ =begin
2
+ * Name: ScrollForm - a form that can take more than the screen and focus only on what's visible
3
+ * This class originated in TabbedPane for the top button form which only scrolls
4
+ * horizontally and uses objects that have a ht of 1. Here we have to deal with
5
+ * large objects and vertical scrolling.
6
+ * Description:
7
+ * Author: rkumar
8
+
9
+ --------
10
+ * Date: 2010-03-16 11:32
11
+ * License:
12
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
13
+
14
+
15
+ NOTE:
16
+ There are going to be tricky cases we have to deal with such as objects that start in the viewable
17
+ area but finish outside, or vice versa.
18
+
19
+ What if we wish some static text to be displayed at top or bottom of ScrollForm
20
+ =end
21
+ require 'rubygems'
22
+ require 'ncurses'
23
+ require 'logger'
24
+ require 'rbcurse'
25
+
26
+ include Ncurses
27
+ include RubyCurses
28
+ module RubyCurses
29
+ extend self
30
+ class ScrollForm < RubyCurses::Form
31
+ # the pad prints from this col to window
32
+ attr_accessor :pmincol # advance / scroll columns
33
+ # the pad prints from this row to window, usually 0
34
+ attr_accessor :pminrow # advance / scroll rows (vertically)
35
+ attr_accessor :display_w # width of screen display
36
+ attr_accessor :display_h # ht of screen display
37
+ attr_accessor :row_offset, :col_offset
38
+ attr_accessor :scroll_unit # by how much should be scroll
39
+ attr_reader :orig_top, :orig_left
40
+ attr_reader :window
41
+ attr_accessor :name
42
+ attr_reader :cols_panned, :rows_panned
43
+ def initialize win, &block
44
+ @target_window = win
45
+ super
46
+ @pminrow = @pmincol = 0
47
+ @row_offset = @col_offset = 0
48
+ @scroll_unit = 3
49
+ @cols_panned = @rows_panned = 0
50
+ @repaint_all = true
51
+
52
+ # take display dimensions from window. It is safe to override immediately after form creation
53
+ @display_h = win.height
54
+ @display_w = win.width
55
+ @display_h = (Ncurses.LINES - win.top - 2) if @display_h == 0
56
+ @display_w = (Ncurses.COLS - win.left - 2) if @display_w == 0
57
+
58
+ init_vars
59
+ end
60
+ def init_vars
61
+ bind_key(?\M-h, :scroll_left)
62
+ bind_key(?\M-l, :scroll_right)
63
+ bind_key(?\M-n, :scroll_down)
64
+ bind_key(?\M-p, :scroll_up)
65
+ end
66
+ def should_print_border flag=true
67
+ @print_border_flag = flag
68
+ @row_offset = @col_offset = 1
69
+ end
70
+ # This is how we set size of pad and where it prints on screen
71
+ # This is all that's needed after constructor.
72
+ # @param [Fixnum] t top (row on screen to print pad on)
73
+ # @param [Fixnum] l left (col on screen to print)
74
+ # @param [Fixnum] h height (how many lines in Pad, usually more that screens actual height)
75
+ # @param [Fixnum] w width (how many cols in Pad, often more than screens width)
76
+ #
77
+ def set_pad_dimensions(t, l, h, w )
78
+ @pad_h = h
79
+ @pad_w = w
80
+ @top = @orig_top = t
81
+ @left = @orig_left = l
82
+ create_pad
83
+ end
84
+ ##
85
+ # create a pad to work on.
86
+ # XXX We reuse window, which is already the main window
87
+ # So if we try creating pad later, then old external window is used.
88
+ # However, many methods in superclass operate on window so we needed to overwrite. What do i do ?
89
+ private
90
+ def create_pad
91
+ raise "Pad already created" if @pad
92
+ r = @top
93
+ c = @left
94
+ layout = { :height => @pad_h, :width => @pad_w, :top => r, :left => c }
95
+ @window = VER::Pad.create_with_layout(layout)
96
+
97
+ @window.name = "Pad::ScrollPad" # 2010-02-02 20:01
98
+ @name = "Form::ScrollForm"
99
+ @pad = @window
100
+ return @window
101
+ end
102
+ public
103
+ def scroll_right
104
+ s = @scroll_unit + $multiplier
105
+ $log.debug " scroll_right #{s} m: #{$multiplier} "
106
+ $multiplier = 0
107
+ return false if !validate_scroll_col(@pmincol + s)
108
+ @pmincol += s # some check is required or we'll crash
109
+ @cols_panned -= s
110
+ $log.debug " handled ch M-l in ScrollForm"
111
+ @window.modified = true
112
+ return 0
113
+ end
114
+ ##
115
+ # validate fails once unit + mult > 1. Then it won't go further
116
+ # unit should be one by default.
117
+ def scroll_left
118
+ s = @scroll_unit + $multiplier
119
+ $log.debug " scroll_left #{s} m: #{$multiplier} "
120
+ $multiplier = 0
121
+ #return false if !validate_scroll_col(@pmincol - s)
122
+ if !validate_scroll_col(@pmincol - s)
123
+ @pmincol = 0
124
+ @cols_panned = 0
125
+ else
126
+ @pmincol -= s # some check is required or we'll crash
127
+ @cols_panned += s
128
+ end
129
+ @window.modified = true
130
+ return 0
131
+ end
132
+ def scroll_down
133
+ s = @scroll_unit + $multiplier; $multiplier = 0
134
+ return false if !validate_scroll_row(@pminrow + s)
135
+ @pminrow += s # some check is required or we'll crash
136
+ @rows_panned -= s
137
+ @window.modified = true
138
+ #@repaint_all = true
139
+ return 0
140
+ end
141
+ def scroll_up
142
+ s = @scroll_unit + $multiplier; $multiplier = 0
143
+ $log.debug " scroll_up #{s} "
144
+ #return false if !validate_scroll_row(@pminrow - s)
145
+ if !validate_scroll_row(@pminrow - s)
146
+ @pminrow = 0
147
+ @rows_panned = 0
148
+ $log.debug " !valid #{@pminrow} "
149
+ else
150
+ @pminrow -= s # some check is required or we'll crash
151
+ @rows_panned += s
152
+ $log.debug " valid #{@pminrow} "
153
+ end
154
+ @window.modified = true
155
+ #@repaint_all = true
156
+ return 0
157
+ end
158
+ # print a border on the main window, just for kicks
159
+ def print_border
160
+ $log.debug " SCROLL print_border ..."
161
+ #@window.print_border_only(@top-@rows_panned, @left+@cols_panned, @display_h, @display_w, $datacolor)
162
+ @target_window.print_border_only(@top, @left, @display_h, @display_w+1, $datacolor)
163
+ end
164
+ def print_footer
165
+ footer = "Lines %d-%d (%d) Cols %d-%d (%d) " % [ @pminrow, @pminrow + @display_h, @orig_top + @pad_h, @pmincol, @pmincol + @display_w, @orig_left + @pad_w ]
166
+ @target_window.printstring(@top +@display_h, @left + 3, footer, $datacolor)
167
+ end
168
+ # XXX what if we want a static area at bottom ?
169
+ # maybe we should rename targetwindow to window
170
+ # and window to pad
171
+ # super may need target window
172
+ def repaint
173
+ print_border if @repaint_all and @print_border_flag
174
+ print_footer
175
+ $log.debug " scrollForm repaint calling parent #{@row} #{@col}+ #{@cols_panned} #{@col_offset} "
176
+ super
177
+ prefresh
178
+ _print_more_data_marker true
179
+ _print_more_columns_marker true
180
+ #$log.debug " @target_window.wmove #{@row+@rows_panned+@row_offset}, #{@col+@cols_panned+@col_offset} "
181
+ @target_window.wmove @row+@rows_panned+@row_offset, @col+@cols_panned+@col_offset
182
+ @window.modified = false
183
+ @repaint_all = false
184
+ end
185
+ ## refresh pad onto window
186
+ # I am now copying onto main window, else prefresh has funny effects
187
+ def prefresh
188
+ ## reduce so we don't go off in top+h and top+w
189
+ $log.debug " start ret = @buttonpad.prefresh( #{@pminrow} , #{@pmincol} , #{@top} , #{@left} , top + #{@display_h} left + #{@display_w} ) "
190
+ if @pminrow + @display_h > @orig_top + @pad_h
191
+ $log.debug " if #{@pminrow} + #{@display_h} > #{@orig_top} +#{@pad_h} "
192
+ $log.debug " ERROR 1 "
193
+ #return -1
194
+ end
195
+ if @pmincol + @display_w > @orig_left + @pad_w
196
+ $log.debug " if #{@pmincol} + #{@display_w} > #{@orig_left} +#{@pad_w} "
197
+ $log.debug " ERROR 2 "
198
+ return -1
199
+ end
200
+ # actually if there is a change in the screen, we may still need to allow update
201
+ # but ensure that size does not exceed
202
+ if @top + @display_h > @orig_top + @pad_h
203
+ $log.debug " if #{@top} + #{@display_h} > #{@orig_top} +#{@pad_h} "
204
+ $log.debug " ERROR 3 "
205
+ return -1
206
+ end
207
+ if @left + @display_w > @orig_left + @pad_w
208
+ $log.debug " if #{@left} + #{@display_w} > #{@orig_left} +#{@pad_w} "
209
+ $log.debug " ERROR 4 "
210
+ return -1
211
+ end
212
+ # maybe we should use copywin to copy onto @target_window
213
+ $log.debug " ret = @window.prefresh( #{@pminrow} , #{@pmincol} , #{@top} , #{@left} , #{@top} + #{@display_h}, #{@left} + #{@display_w} ) "
214
+ omit = 0
215
+ # this works but if want to avoid copying border
216
+ #ret = @window.prefresh(@pminrow, @pmincol, @top+@row_offset, @left+@col_offset, @top + @display_h - @row_offset , @left + @display_w - @col_offset)
217
+ #
218
+ ## Haha , we are back to the old notorious copywin which has given mankind
219
+ # so much grief that it should be removed in the next round of creation.
220
+ ret = @window.copywin(@target_window.get_window, @pminrow, @pmincol, @top+@row_offset, @left+@col_offset,
221
+ @top + @display_h - @row_offset , @left + @display_w - @col_offset, 0)
222
+
223
+ $log.debug " copywin ret = #{ret} "
224
+ end
225
+ private
226
+ def validate_scroll_row minrow
227
+ return false if minrow < 0
228
+ if minrow + @display_h > @orig_top + @pad_h
229
+ $log.debug " if #{minrow} + #{@display_h} > #{@orig_top} +#{@pad_h} "
230
+ $log.debug " ERROR 1 "
231
+ return false
232
+ end
233
+ return true
234
+ end
235
+ def validate_scroll_col mincol
236
+ return false if mincol < 0
237
+ if mincol + @display_w > @orig_left + @pad_w
238
+ $log.debug " if #{mincol} + #{@display_w} > #{@orig_left} +#{@pad_w} "
239
+ $log.debug " ERROR 2 "
240
+ return false
241
+ end
242
+ return true
243
+ end
244
+ # when tabbing through buttons, we need to account for all that panning/scrolling goin' on
245
+ # this is typically called by putchar or putc in editable components like field.
246
+ # XXX DELETE THIS IS SUPPOSE
247
+ def OLDsetrowcol r, c
248
+ $log.debug " SCROLL setrowcol #{r}, #{c} + #{@cols_panned}"
249
+ # aha ! here's where i can check whether the cursor is falling off the viewable area
250
+ cc = nil
251
+ rr = nil
252
+ if c
253
+ cc = c #+ @cols_panned
254
+ if c+@cols_panned < @orig_left
255
+ # this essentially means this widget (button) is not in view, its off to the left
256
+ $log.debug " setrowcol OVERRIDE #{c} #{@cols_panned} < #{@orig_left} "
257
+ $log.debug " aborting settrow col for now"
258
+ return
259
+ end
260
+ if c+@cols_panned > @orig_left + @display_w
261
+ # this essentially means this button is not in view, its off to the right
262
+ $log.debug " setrowcol OVERRIDE #{c} #{@cols_panned} > #{@orig_left} + #{@display_w} "
263
+ $log.debug " aborting settrow col for now"
264
+ return
265
+ end
266
+ end
267
+ if r
268
+ rr = r+@rows_panned
269
+ end
270
+ super rr, cc
271
+ end
272
+ public
273
+ def add_widget w
274
+ super
275
+ $log.debug " inside add_widget #{w.name} pad w #{@pad_w} #{w.col}, #{@pad_h} "
276
+ if w.col >= @pad_w
277
+ @pad_w += 10 # XXX currently just a guess value, we need length and maybe some extra
278
+ @window.wresize(@pad_h, @pad_w) if @pad
279
+ end
280
+ if w.row >= @pad_h
281
+ @pad_h += 10 # XXX currently just a guess value, we need length and maybe some extra
282
+ $log.debug " SCROLL add_widget ..."
283
+ @window.wresize(@pad_h, @pad_w) if @pad
284
+ end
285
+ end
286
+ ## Is a component visible, typically used to prevent traversal into the field
287
+ # @returns [true, false] false if components has scrolled off
288
+ def visible? component
289
+ r, c = component.rowcol
290
+ return false if c+@cols_panned < @orig_left
291
+ return false if c+@cols_panned > @orig_left + @display_w
292
+ # XXX TODO for rows UNTESTED for rows
293
+ return false if r + @rows_panned < @orig_top
294
+ return false if r + @rows_panned > @orig_top + @display_h
295
+
296
+ return true
297
+ end
298
+ # returns index of first visible component. Currently using column index
299
+ # I am doing this for horizontal scrolling presently
300
+ # @return [index, -1] -1 if none visible, else index/offset
301
+ def first_visible_component_index
302
+ @widgets.each_with_index do |w, ix|
303
+ return ix if visible?(w) and focusable?(w)
304
+ end
305
+ return -1
306
+ end
307
+ def last_visible_component_index
308
+ ret = -1
309
+ @widgets.each_with_index do |w, ix|
310
+ ret = ix if visible?(w) and focusable?(w)
311
+ end
312
+ return ret
313
+ end
314
+ def req_first_field
315
+ index = first_visible_component_index
316
+ ret = select_field(index)
317
+ return ret
318
+ end
319
+ def req_last_field
320
+ select_field(last_visible_component_index)
321
+ end
322
+ def focusable?(w)
323
+ w.focusable and visible?(w)
324
+ end
325
+
326
+ # XXX needs to be called from repaint and print_border
327
+ # @param [boolean] should marker be printed or not
328
+ def _print_more_data_marker tf
329
+ tf = false
330
+ # the bottom marker meaning there's more data below
331
+ if @pminrow + @display_h < @pad_h
332
+ tf = true
333
+ end
334
+ marker = tf ? Ncurses::ACS_CKBOARD : Ncurses::ACS_VLINE
335
+ h = @display_h; w = @display_w
336
+ r = @orig_top
337
+ c = @orig_left
338
+ $log.debug " more data #{r+h-1}, #{c+w-1} : row #{r} h #{h} w #{w} col #{c} "
339
+ @target_window.mvwaddch r+h-1, c+w-0, marker
340
+ # the top marker to show that there is data above
341
+ marker = @pminrow > 0 ? Ncurses::ACS_CKBOARD : Ncurses::ACS_VLINE
342
+ @target_window.mvwaddch r+1, c+w-0, marker
343
+ end
344
+
345
+ # XXX needs to be called from repaint and print_border
346
+ # @param [boolean] should marker be printed or not
347
+ def _print_more_columns_marker tf
348
+ tf = false
349
+ if @pmincol + @display_w < @pad_w
350
+ tf = true
351
+ end
352
+ marker = tf ? Ncurses::ACS_CKBOARD : Ncurses::ACS_HLINE
353
+ h = @display_h; w = @display_w
354
+ r = @orig_top
355
+ c = @orig_left
356
+ @target_window.mvwaddch r+h, c+w-2, marker
357
+ #
358
+ # show if columns to left or not
359
+ marker = @pmincol > 0 ? Ncurses::ACS_CKBOARD : Ncurses::ACS_HLINE
360
+ @target_window.mvwaddch r+h, c+1, marker
361
+ end
362
+ end # class ScrollF
363
+
364
+ # the return of the prodigals
365
+ # The Expanding Heart
366
+ # The coming together of all those who were
367
+
368
+
369
+ end # module