rbcurse 0.1.3 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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