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.
- data/CHANGELOG +126 -0
- data/Manifest.txt +53 -20
- data/README.markdown +423 -0
- data/Rakefile +3 -1
- data/examples/keytest.rb +177 -0
- data/examples/mpad2.rb +156 -0
- data/examples/newtesttabp.rb +121 -0
- data/examples/rfe.rb +48 -10
- data/examples/rfe_renderer.rb +4 -4
- data/examples/rvimsplit.rb +376 -0
- data/examples/sqlc.rb +97 -106
- data/examples/sqlm.rb +446 -0
- data/examples/test1.rb +4 -4
- data/examples/test2.rb +12 -12
- data/examples/testchars.rb +140 -0
- data/examples/testkeypress.rb +9 -4
- data/examples/testmulticomp.rb +72 -0
- data/examples/testscroller.rb +136 -0
- data/examples/testscrolllb.rb +86 -0
- data/examples/testscrollp.rb +87 -0
- data/examples/testscrollta.rb +80 -0
- data/examples/testscrolltable.rb +166 -0
- data/examples/testsplit.rb +87 -0
- data/examples/testsplit2.rb +123 -0
- data/examples/testsplit3.rb +215 -0
- data/examples/testsplit3_1.rb +244 -0
- data/examples/testsplit3a.rb +215 -0
- data/examples/testsplit3b.rb +237 -0
- data/examples/testsplitta.rb +148 -0
- data/examples/testsplittv.rb +142 -0
- data/examples/testsplittvv.rb +144 -0
- data/examples/testtable.rb +1 -1
- data/examples/testtabp.rb +3 -2
- data/examples/testtestw.rb +69 -0
- data/examples/testtodo.rb +5 -3
- data/examples/testtpane.rb +203 -0
- data/examples/testtpane2.rb +145 -0
- data/examples/testtpanetable.rb +199 -0
- data/examples/viewtodo.rb +5 -3
- data/lib/rbcurse.rb +1 -1
- data/lib/rbcurse/celleditor.rb +2 -2
- data/lib/rbcurse/colormap.rb +5 -5
- data/lib/rbcurse/defaultlistselectionmodel.rb +3 -3
- data/lib/rbcurse/io.rb +663 -0
- data/lib/rbcurse/listeditable.rb +306 -0
- data/lib/rbcurse/listkeys.rb +15 -15
- data/lib/rbcurse/listscrollable.rb +168 -27
- data/lib/rbcurse/mapper.rb +35 -13
- data/lib/rbcurse/rchangeevent.rb +28 -0
- data/lib/rbcurse/rform.rb +845 -0
- data/lib/rbcurse/rlistbox.rb +144 -34
- data/lib/rbcurse/rmessagebox.rb +10 -5
- data/lib/rbcurse/rmulticontainer.rb +325 -0
- data/lib/rbcurse/rmultitextview.rb +306 -0
- data/lib/rbcurse/rscrollform.rb +369 -0
- data/lib/rbcurse/rscrollpane.rb +511 -0
- data/lib/rbcurse/rsplitpane.rb +820 -0
- data/lib/rbcurse/rtabbedpane.rb +737 -109
- data/lib/rbcurse/rtabbedwindow.rb +326 -0
- data/lib/rbcurse/rtable.rb +220 -64
- data/lib/rbcurse/rtextarea.rb +340 -181
- data/lib/rbcurse/rtextview.rb +237 -101
- data/lib/rbcurse/rviewport.rb +203 -0
- data/lib/rbcurse/rwidget.rb +919 -95
- data/lib/rbcurse/scrollable.rb +7 -7
- data/lib/rbcurse/selectable.rb +4 -4
- data/lib/rbcurse/table/tablecellrenderer.rb +3 -0
- data/lib/rbcurse/undomanager.rb +181 -0
- data/lib/rbcurse/vieditable.rb +100 -0
- data/lib/ver/window.rb +471 -21
- metadata +66 -22
- data/README.txt +0 -312
- data/examples/testd.db +0 -0
- 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
|