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