rbhex-core 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/CHANGELOG +2000 -0
- data/LICENSE +56 -0
- data/README.md +44 -0
- data/examples/abasiclist.rb +179 -0
- data/examples/alpmenu.rb +50 -0
- data/examples/app.sample +19 -0
- data/examples/atree.rb +100 -0
- data/examples/bline.rb +136 -0
- data/examples/common/file.rb +45 -0
- data/examples/data/README.markdown +9 -0
- data/examples/data/brew.txt +38 -0
- data/examples/data/color.2 +37 -0
- data/examples/data/gemlist.txt +60 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/ports.txt +136 -0
- data/examples/data/table.txt +37 -0
- data/examples/data/tasks.csv +88 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/data/todo.txt +10 -0
- data/examples/data/todo.txt.bak +10 -0
- data/examples/data/todocsv.csv +28 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/data/unix2.txt +11 -0
- data/examples/dbdemo.rb +502 -0
- data/examples/dirtree.rb +94 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +146 -0
- data/examples/tasks.rb +178 -0
- data/examples/term2.rb +84 -0
- data/examples/testbuttons.rb +296 -0
- data/examples/testcombo.rb +102 -0
- data/examples/testfields.rb +195 -0
- data/examples/testkeypress.rb +72 -0
- data/examples/testlistbox.rb +170 -0
- data/examples/testmessagebox.rb +140 -0
- data/examples/testprogress.rb +116 -0
- data/examples/testree.rb +106 -0
- data/examples/testwsshortcuts.rb +66 -0
- data/examples/testwsshortcuts2.rb +128 -0
- data/lib/rbhex.rb +6 -0
- data/lib/rbhex/core/docs/index.txt +73 -0
- data/lib/rbhex/core/include/action.rb +80 -0
- data/lib/rbhex/core/include/actionmanager.rb +49 -0
- data/lib/rbhex/core/include/appmethods.rb +214 -0
- data/lib/rbhex/core/include/bordertitle.rb +48 -0
- data/lib/rbhex/core/include/chunk.rb +203 -0
- data/lib/rbhex/core/include/io.rb +553 -0
- data/lib/rbhex/core/include/listbindings.rb +74 -0
- data/lib/rbhex/core/include/listcellrenderer.rb +140 -0
- data/lib/rbhex/core/include/listeditable.rb +317 -0
- data/lib/rbhex/core/include/listscrollable.rb +663 -0
- data/lib/rbhex/core/include/listselectable.rb +271 -0
- data/lib/rbhex/core/include/multibuffer.rb +83 -0
- data/lib/rbhex/core/include/orderedhash.rb +77 -0
- data/lib/rbhex/core/include/ractionevent.rb +73 -0
- data/lib/rbhex/core/include/rchangeevent.rb +27 -0
- data/lib/rbhex/core/include/rhistory.rb +95 -0
- data/lib/rbhex/core/include/rinputdataevent.rb +47 -0
- data/lib/rbhex/core/include/vieditable.rb +172 -0
- data/lib/rbhex/core/include/widgetmenu.rb +66 -0
- data/lib/rbhex/core/system/colormap.rb +165 -0
- data/lib/rbhex/core/system/keyboard.rb +150 -0
- data/lib/rbhex/core/system/keydefs.rb +30 -0
- data/lib/rbhex/core/system/ncurses.rb +236 -0
- data/lib/rbhex/core/system/panel.rb +162 -0
- data/lib/rbhex/core/system/window.rb +913 -0
- data/lib/rbhex/core/util/ansiparser.rb +119 -0
- data/lib/rbhex/core/util/app.rb +1228 -0
- data/lib/rbhex/core/util/basestack.rb +410 -0
- data/lib/rbhex/core/util/bottomline.rb +1859 -0
- data/lib/rbhex/core/util/colorparser.rb +77 -0
- data/lib/rbhex/core/util/focusmanager.rb +31 -0
- data/lib/rbhex/core/util/padreader.rb +192 -0
- data/lib/rbhex/core/util/rcommandwindow.rb +604 -0
- data/lib/rbhex/core/util/rdialogs.rb +574 -0
- data/lib/rbhex/core/util/viewer.rb +149 -0
- data/lib/rbhex/core/util/widgetshortcuts.rb +506 -0
- data/lib/rbhex/core/version.rb +5 -0
- data/lib/rbhex/core/widgets/applicationheader.rb +103 -0
- data/lib/rbhex/core/widgets/box.rb +58 -0
- data/lib/rbhex/core/widgets/divider.rb +310 -0
- data/lib/rbhex/core/widgets/keylabelprinter.rb +194 -0
- data/lib/rbhex/core/widgets/rcombo.rb +253 -0
- data/lib/rbhex/core/widgets/rcontainer.rb +415 -0
- data/lib/rbhex/core/widgets/rlink.rb +30 -0
- data/lib/rbhex/core/widgets/rlist.rb +696 -0
- data/lib/rbhex/core/widgets/rmenu.rb +958 -0
- data/lib/rbhex/core/widgets/rmenulink.rb +22 -0
- data/lib/rbhex/core/widgets/rmessagebox.rb +387 -0
- data/lib/rbhex/core/widgets/rprogress.rb +118 -0
- data/lib/rbhex/core/widgets/rtabbedpane.rb +634 -0
- data/lib/rbhex/core/widgets/rtabbedwindow.rb +70 -0
- data/lib/rbhex/core/widgets/rtextarea.rb +960 -0
- data/lib/rbhex/core/widgets/rtextview.rb +739 -0
- data/lib/rbhex/core/widgets/rtree.rb +768 -0
- data/lib/rbhex/core/widgets/rwidget.rb +3277 -0
- data/lib/rbhex/core/widgets/scrollbar.rb +143 -0
- data/lib/rbhex/core/widgets/statusline.rb +113 -0
- data/lib/rbhex/core/widgets/tabular.rb +264 -0
- data/lib/rbhex/core/widgets/tabularwidget.rb +1142 -0
- data/lib/rbhex/core/widgets/textpad.rb +995 -0
- data/lib/rbhex/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/rbhex/core/widgets/tree/treemodel.rb +428 -0
- data/rbhex-core.gemspec +32 -0
- metadata +172 -0
|
@@ -0,0 +1,739 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
* Name: TextView
|
|
3
|
+
* Description View text in this widget.
|
|
4
|
+
* Author: rkumar (arunachalesha)
|
|
5
|
+
* file created 2009-01-08 15:23
|
|
6
|
+
* major change: 2010-02-10 19:43 simplifying the buffer stuff.
|
|
7
|
+
TODO
|
|
8
|
+
* border, and footer could be objects (classes) at some future stage.
|
|
9
|
+
--------
|
|
10
|
+
* License:
|
|
11
|
+
Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
|
12
|
+
|
|
13
|
+
=end
|
|
14
|
+
require 'logger'
|
|
15
|
+
require 'rbhex'
|
|
16
|
+
require 'rbhex/core/include/listscrollable'
|
|
17
|
+
require 'rbhex/core/include/bordertitle'
|
|
18
|
+
require 'forwardable'
|
|
19
|
+
|
|
20
|
+
include RubyCurses
|
|
21
|
+
module RubyCurses
|
|
22
|
+
extend self
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# A viewable read only box. Can scroll.
|
|
26
|
+
# Intention is to be able to change content dynamically - the entire list.
|
|
27
|
+
# Use set_content to set content, or just update the list attrib
|
|
28
|
+
# TODO -
|
|
29
|
+
# - goto line - DONE
|
|
30
|
+
class TextView < Widget
|
|
31
|
+
include ListScrollable
|
|
32
|
+
extend Forwardable
|
|
33
|
+
#dsl_accessor :height # height of viewport cmmented on 2010-01-09 19:29 since widget has method
|
|
34
|
+
#dsl_accessor :title # set this on top
|
|
35
|
+
#dsl_accessor :title_attrib # bold, reverse, normal
|
|
36
|
+
dsl_accessor :footer_attrib # bold, reverse, normal
|
|
37
|
+
dsl_accessor :list # the array of data to be sent by user
|
|
38
|
+
dsl_accessor :maxlen # max len to be displayed
|
|
39
|
+
attr_reader :toprow # the toprow in the view (offsets are 0)
|
|
40
|
+
# painting the footer does slow down cursor painting slightly if one is moving cursor fast
|
|
41
|
+
dsl_accessor :print_footer
|
|
42
|
+
attr_reader :current_index
|
|
43
|
+
dsl_accessor :sanitization_required
|
|
44
|
+
|
|
45
|
+
def initialize form = nil, config={}, &block
|
|
46
|
+
@focusable = true
|
|
47
|
+
@editable = false
|
|
48
|
+
@sanitization_required = true
|
|
49
|
+
@suppress_borders = false
|
|
50
|
+
@row_offset = @col_offset = 1
|
|
51
|
+
@row = 0
|
|
52
|
+
@col = 0
|
|
53
|
+
@show_focus = false # don't highlight row under focus
|
|
54
|
+
@list = []
|
|
55
|
+
map_keys
|
|
56
|
+
super
|
|
57
|
+
# ideally this should have been 2 to take care of borders, but that would break
|
|
58
|
+
# too much stuff !
|
|
59
|
+
@win = @graphic
|
|
60
|
+
|
|
61
|
+
@_events.push :CHANGE # thru vieditable
|
|
62
|
+
@_events << :PRESS # new, in case we want to use this for lists and allow ENTER
|
|
63
|
+
@_events << :ENTER_ROW # new, should be there in listscrollable ??
|
|
64
|
+
install_keys # do something about this nonsense FIXME
|
|
65
|
+
bordertitle_init
|
|
66
|
+
init_vars
|
|
67
|
+
init_actions
|
|
68
|
+
end
|
|
69
|
+
def init_vars #:nodoc:
|
|
70
|
+
@curpos = @pcol = @toprow = @current_index = 0
|
|
71
|
+
@repaint_all=true
|
|
72
|
+
@repaint_required=true
|
|
73
|
+
@widget_scrolled = true
|
|
74
|
+
## 2010-02-10 20:20 RFED16 taking care if no border requested
|
|
75
|
+
@row_offset = @col_offset = 0 if @suppress_borders == true
|
|
76
|
+
# added 2010-02-11 15:11 RFED16 so we don't need a form.
|
|
77
|
+
$error_message_row ||= 23
|
|
78
|
+
$error_message_col ||= 1
|
|
79
|
+
# currently i scroll right only if current line is longer than display width, i should use
|
|
80
|
+
# longest line on screen.
|
|
81
|
+
@longest_line = 0 # the longest line printed on this page, used to determine if scrolling shd work
|
|
82
|
+
@internal_width = 2
|
|
83
|
+
@internal_width = 0 if @suppress_borders # NOTE bordertitle says 1
|
|
84
|
+
|
|
85
|
+
@search_found_ix = nil # so old searches don't get highlighted
|
|
86
|
+
end
|
|
87
|
+
def map_keys
|
|
88
|
+
require 'rbhex/core/include/listbindings'
|
|
89
|
+
bindings()
|
|
90
|
+
#bind_key([?\C-x, ?\C-s], :saveas)
|
|
91
|
+
#bind_key([?\C-x, ?e], :edit_external)
|
|
92
|
+
bind_key(32, 'scroll forward'){ scroll_forward() }
|
|
93
|
+
# have placedhere so multi-bufer can override BS to prev buffer
|
|
94
|
+
bind_keys([KEY_BACKSPACE,KEY_BSPACE,KEY_DELETE], :cursor_backward)
|
|
95
|
+
#bind_key(?r) { getstr("Enter a word: ") } if $log.debug?
|
|
96
|
+
#bind_key(?m, :disp_menu) if $log.debug?
|
|
97
|
+
end
|
|
98
|
+
##
|
|
99
|
+
# send in a list
|
|
100
|
+
# e.g. set_content File.open("README.txt","r").readlines
|
|
101
|
+
# set wrap at time of passing :WRAP_NONE :WRAP_WORD
|
|
102
|
+
# XXX if we widen the textview later, as in a vimsplit that data
|
|
103
|
+
# will sti1ll be wrapped at this width !!
|
|
104
|
+
# 2011-12-3 changed wrap to hash, so we can use content_type :ansi, :tmux
|
|
105
|
+
def set_content list, config = {} #wrap = :WRAP_NONE
|
|
106
|
+
@content_type = config[:content_type]
|
|
107
|
+
_title = config[:title]
|
|
108
|
+
self.title = _title if _title
|
|
109
|
+
if @content_type
|
|
110
|
+
formatted_text list, @content_type
|
|
111
|
+
return
|
|
112
|
+
end
|
|
113
|
+
# please note that content type is lost once formatted text does it's work
|
|
114
|
+
@wrap_policy = config[:wrap]
|
|
115
|
+
if list.is_a? String
|
|
116
|
+
if @wrap_policy == :WRAP_WORD
|
|
117
|
+
data = wrap_text list
|
|
118
|
+
@list = data.split("\n")
|
|
119
|
+
else
|
|
120
|
+
@list = list.split("\n")
|
|
121
|
+
end
|
|
122
|
+
elsif list.is_a? Array
|
|
123
|
+
if @wrap_policy == :WRAP_WORD
|
|
124
|
+
data = wrap_text list.join(" ")
|
|
125
|
+
@list = data.split("\n")
|
|
126
|
+
else
|
|
127
|
+
@list = list
|
|
128
|
+
end
|
|
129
|
+
else
|
|
130
|
+
raise "set_content expects Array not #{list.class}"
|
|
131
|
+
end
|
|
132
|
+
init_vars
|
|
133
|
+
end
|
|
134
|
+
# for consistency with other objects that respect text
|
|
135
|
+
#alias :text :set_content
|
|
136
|
+
def text(*val)
|
|
137
|
+
if val.empty?
|
|
138
|
+
return @list
|
|
139
|
+
end
|
|
140
|
+
set_content(*val)
|
|
141
|
+
self
|
|
142
|
+
end
|
|
143
|
+
def text=(val)
|
|
144
|
+
return unless val # added 2010-11-17 20:11, dup will fail on nil
|
|
145
|
+
set_content(val)
|
|
146
|
+
end
|
|
147
|
+
def formatted_text text, fmt
|
|
148
|
+
require 'rbhex/core/include/chunk'
|
|
149
|
+
@formatted_text = text
|
|
150
|
+
@color_parser = fmt
|
|
151
|
+
remove_all
|
|
152
|
+
end
|
|
153
|
+
#def <<(line); @list << line; @widget_scrolled = true; end
|
|
154
|
+
def_delegators :@list, :include?, :each, :values, :size
|
|
155
|
+
%w[ insert clear delete_at []= << ].each { |e|
|
|
156
|
+
eval %{
|
|
157
|
+
def #{e}(*args)
|
|
158
|
+
@list.send(:#{e}, *args)
|
|
159
|
+
@widget_scrolled = true
|
|
160
|
+
@repaint_required = true
|
|
161
|
+
end
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
alias :append :<<
|
|
165
|
+
|
|
166
|
+
def remove_all
|
|
167
|
+
@list = []
|
|
168
|
+
init_vars
|
|
169
|
+
@repaint_required = true
|
|
170
|
+
end
|
|
171
|
+
## display this row on top
|
|
172
|
+
def top_row(*val) #:nodoc:
|
|
173
|
+
if val.empty?
|
|
174
|
+
@toprow
|
|
175
|
+
else
|
|
176
|
+
@toprow = val[0] || 0
|
|
177
|
+
end
|
|
178
|
+
@repaint_required = true
|
|
179
|
+
end
|
|
180
|
+
## ---- for listscrollable ---- ##
|
|
181
|
+
def scrollatrow #:nodoc:
|
|
182
|
+
if @suppress_borders
|
|
183
|
+
@height - 1 # should be 2 FIXME but erasing lower line. see appemail
|
|
184
|
+
else
|
|
185
|
+
@height - 3
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
def row_count
|
|
189
|
+
@list.length
|
|
190
|
+
end
|
|
191
|
+
##
|
|
192
|
+
# returns row of first match of given regex (or nil if not found)
|
|
193
|
+
def find_first_match regex #:nodoc:
|
|
194
|
+
@list.each_with_index do |row, ix|
|
|
195
|
+
return ix if !row.match(regex).nil?
|
|
196
|
+
end
|
|
197
|
+
return nil
|
|
198
|
+
end
|
|
199
|
+
## returns the position where cursor was to be positioned by default
|
|
200
|
+
# It may no longer work like that.
|
|
201
|
+
def rowcol #:nodoc:
|
|
202
|
+
return @row+@row_offset, @col+@col_offset
|
|
203
|
+
end
|
|
204
|
+
def wrap_text(txt, col = @maxlen) #:nodoc:
|
|
205
|
+
col ||= @width-@internal_width
|
|
206
|
+
#$log.debug "inside wrap text for :#{txt}"
|
|
207
|
+
txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,
|
|
208
|
+
"\\1\\3\n")
|
|
209
|
+
end
|
|
210
|
+
def print_foot #:nodoc:
|
|
211
|
+
@footer_attrib ||= Ncurses::A_REVERSE
|
|
212
|
+
footer = "R: #{@current_index+1}, C: #{@curpos+@pcol}, #{@list.length} lines "
|
|
213
|
+
$log.debug " print_foot calling printstring with #{@row} + #{@height} -1, #{@col}+2"
|
|
214
|
+
@graphic.printstring( @row + @height -1 , @col+2, footer, @color_pair || $datacolor, @footer_attrib)
|
|
215
|
+
@repaint_footer_required = false # 2010-01-23 22:55
|
|
216
|
+
end
|
|
217
|
+
### FOR scrollable ###
|
|
218
|
+
def get_content
|
|
219
|
+
@list
|
|
220
|
+
end
|
|
221
|
+
def get_window #:nodoc:
|
|
222
|
+
@graphic
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def repaint # textview :nodoc:
|
|
226
|
+
#$log.debug "TEXTVIEW repaint r c #{@row}, #{@col}, key: #{$current_key}, reqd #{@repaint_required} "
|
|
227
|
+
|
|
228
|
+
#return unless @repaint_required # 2010-02-12 19:08 TRYING - won't let footer print for col move
|
|
229
|
+
# TRYING OUT dangerous 2011-10-13
|
|
230
|
+
@repaint_required = false
|
|
231
|
+
@repaint_required = true if @widget_scrolled || @pcol != @old_pcol || @record_changed || @property_changed
|
|
232
|
+
|
|
233
|
+
paint if @repaint_required
|
|
234
|
+
|
|
235
|
+
@repaint_footer_required = true if @oldrow != @current_index # 2011-10-15
|
|
236
|
+
print_foot if @print_footer && !@suppress_borders && @repaint_footer_required
|
|
237
|
+
end
|
|
238
|
+
# this sucks and should not be used but is everywhere, should
|
|
239
|
+
# use text()
|
|
240
|
+
def getvalue
|
|
241
|
+
@list
|
|
242
|
+
end
|
|
243
|
+
def current_value
|
|
244
|
+
@list[@current_index]
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# determine length of row since we have chunks now.
|
|
248
|
+
# Since chunk implements length, so not required except for the old
|
|
249
|
+
# cases of demos that use an array.
|
|
250
|
+
def row_length
|
|
251
|
+
case @buffer
|
|
252
|
+
when String
|
|
253
|
+
@buffer.length
|
|
254
|
+
when Chunks::ChunkLine
|
|
255
|
+
return @buffer.length
|
|
256
|
+
when Array
|
|
257
|
+
# this is for those old cases like rfe.rb which sent in an array
|
|
258
|
+
# (before we moved to chunks)
|
|
259
|
+
# line is an array of arrays
|
|
260
|
+
if @buffer[0].is_a? Array
|
|
261
|
+
result = 0
|
|
262
|
+
@buffer.each {|e| result += e[1].length }
|
|
263
|
+
return result
|
|
264
|
+
end
|
|
265
|
+
# line is one single chunk
|
|
266
|
+
return @buffer[1].length
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
# textview
|
|
270
|
+
# NOTE: i think this should return if list is nil or empty. No need to put
|
|
271
|
+
#
|
|
272
|
+
# stuff into buffer and continue. will trouble other classes that extend.
|
|
273
|
+
def handle_key ch #:nodoc:
|
|
274
|
+
$log.debug " textview got ch #{ch} "
|
|
275
|
+
@old_pcol = @pcol
|
|
276
|
+
@buffer = @list[@current_index]
|
|
277
|
+
if @buffer.nil? && row_count == 0
|
|
278
|
+
@list << "\r"
|
|
279
|
+
@buffer = @list[@current_index]
|
|
280
|
+
end
|
|
281
|
+
return if @buffer.nil?
|
|
282
|
+
#$log.debug " before: curpos #{@curpos} blen: #{row_length}"
|
|
283
|
+
if @curpos > row_length #@buffer.length
|
|
284
|
+
addcol((row_length-@curpos)+1)
|
|
285
|
+
@curpos = row_length
|
|
286
|
+
set_form_col
|
|
287
|
+
end
|
|
288
|
+
# We can improve later
|
|
289
|
+
case ch
|
|
290
|
+
when KEY_UP, ?k.getbyte(0)
|
|
291
|
+
#select_prev_row
|
|
292
|
+
ret = up
|
|
293
|
+
# next removed as very irritating, can be configured if required 2011-11-2
|
|
294
|
+
#get_window.ungetch(KEY_BTAB) if ret == :NO_PREVIOUS_ROW
|
|
295
|
+
check_curpos
|
|
296
|
+
|
|
297
|
+
when KEY_DOWN, ?j.getbyte(0)
|
|
298
|
+
ret = down
|
|
299
|
+
# This should be configurable, or only if all rows are visible
|
|
300
|
+
#get_window.ungetch(KEY_TAB) if ret == :NO_NEXT_ROW
|
|
301
|
+
check_curpos
|
|
302
|
+
#when KEY_LEFT, ?h.getbyte(0)
|
|
303
|
+
#cursor_backward
|
|
304
|
+
#when KEY_RIGHT, ?l.getbyte(0)
|
|
305
|
+
#cursor_forward
|
|
306
|
+
when ?\C-a.getbyte(0) #, ?0.getbyte(0)
|
|
307
|
+
# take care of data that exceeds maxlen by scrolling and placing cursor at start
|
|
308
|
+
@repaint_required = true if @pcol > 0 # tried other things but did not work
|
|
309
|
+
set_form_col 0
|
|
310
|
+
@pcol = 0
|
|
311
|
+
when ?\C-e.getbyte(0), ?$.getbyte(0)
|
|
312
|
+
# take care of data that exceeds maxlen by scrolling and placing cursor at end
|
|
313
|
+
# This use to actually pan the screen to actual end of line, but now somewhere
|
|
314
|
+
# it only goes to end of visible screen, set_form probably does a sanity check
|
|
315
|
+
blen = row_length # @buffer.rstrip.length FIXME
|
|
316
|
+
set_form_col blen
|
|
317
|
+
when KEY_ENTER, FFI::NCurses::KEY_ENTER
|
|
318
|
+
#fire_handler :PRESS, self
|
|
319
|
+
fire_action_event
|
|
320
|
+
when ?0.getbyte(0)..?9.getbyte(0)
|
|
321
|
+
# FIXME the assumption here was that if numbers are being entered then a 0 is a number
|
|
322
|
+
# not a beg-of-line command.
|
|
323
|
+
# However, after introducing universal_argument, we can enters numbers using C-u and then press another
|
|
324
|
+
# C-u to stop. In that case a 0 should act as a command, even though multiplier has been set
|
|
325
|
+
if ch == ?0.getbyte(0) and $multiplier == 0
|
|
326
|
+
# copy of C-a - start of line
|
|
327
|
+
@repaint_required = true if @pcol > 0 # tried other things but did not work
|
|
328
|
+
set_form_col 0
|
|
329
|
+
@pcol = 0
|
|
330
|
+
return 0
|
|
331
|
+
end
|
|
332
|
+
# storing digits entered so we can multiply motion actions
|
|
333
|
+
$multiplier *= 10 ; $multiplier += (ch-48)
|
|
334
|
+
return 0
|
|
335
|
+
when ?\C-c.getbyte(0)
|
|
336
|
+
$multiplier = 0
|
|
337
|
+
return 0
|
|
338
|
+
else
|
|
339
|
+
# check for bindings, these cannot override above keys since placed at end
|
|
340
|
+
begin
|
|
341
|
+
ret = process_key ch, self
|
|
342
|
+
rescue => err
|
|
343
|
+
$log.error " TEXTVIEW ERROR #{err} "
|
|
344
|
+
$log.debug(err.backtrace.join("\n"))
|
|
345
|
+
textdialog [err.to_s, *err.backtrace], :title => "Exception"
|
|
346
|
+
end
|
|
347
|
+
return :UNHANDLED if ret == :UNHANDLED
|
|
348
|
+
end
|
|
349
|
+
$multiplier = 0 # you must reset if you've handled a key. if unhandled, don't reset since parent could use
|
|
350
|
+
set_form_row
|
|
351
|
+
return 0 # added 2010-01-12 22:17 else down arrow was going into next field
|
|
352
|
+
end
|
|
353
|
+
# newly added to check curpos when moving up or down
|
|
354
|
+
def check_curpos #:nodoc:
|
|
355
|
+
@buffer = @list[@current_index]
|
|
356
|
+
# if the cursor is ahead of data in this row then move it back
|
|
357
|
+
if @pcol+@curpos > row_length
|
|
358
|
+
addcol((@pcol+row_length-@curpos)+1)
|
|
359
|
+
@curpos = row_length
|
|
360
|
+
maxlen = (@maxlen || @width-@internal_width)
|
|
361
|
+
|
|
362
|
+
# even this row is gt maxlen, i.e., scrolled right
|
|
363
|
+
if @curpos > maxlen
|
|
364
|
+
@pcol = @curpos - maxlen
|
|
365
|
+
@curpos = maxlen-1
|
|
366
|
+
else
|
|
367
|
+
# this row is within maxlen, make scroll 0
|
|
368
|
+
@pcol=0
|
|
369
|
+
end
|
|
370
|
+
set_form_col
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
# set cursor on correct column tview
|
|
374
|
+
def set_form_col col1=@curpos #:nodoc:
|
|
375
|
+
@cols_panned ||= 0
|
|
376
|
+
@pad_offset ||= 0 # added 2010-02-11 21:54 since padded widgets get an offset.
|
|
377
|
+
@curpos = col1
|
|
378
|
+
maxlen = @maxlen || @width-@internal_width
|
|
379
|
+
#@curpos = maxlen if @curpos > maxlen
|
|
380
|
+
if @curpos > maxlen
|
|
381
|
+
@pcol = @curpos - maxlen
|
|
382
|
+
@curpos = maxlen - 1
|
|
383
|
+
@repaint_required = true # this is required so C-e can pan screen
|
|
384
|
+
else
|
|
385
|
+
@pcol = 0
|
|
386
|
+
end
|
|
387
|
+
# the rest only determines cursor placement
|
|
388
|
+
win_col = 0 # 2010-02-07 23:19 new cursor stuff
|
|
389
|
+
col2 = win_col + @col + @col_offset + @curpos + @cols_panned + @pad_offset
|
|
390
|
+
$log.debug "TV SFC #{@name} setting c to #{col2} #{win_col} #{@col} #{@col_offset} #{@curpos} "
|
|
391
|
+
#@form.setrowcol @form.row, col
|
|
392
|
+
setrowcol nil, col2
|
|
393
|
+
@repaint_footer_required = true
|
|
394
|
+
end
|
|
395
|
+
def cursor_forward #:nodoc:
|
|
396
|
+
maxlen = @maxlen || @width-@internal_width
|
|
397
|
+
repeatm {
|
|
398
|
+
if @curpos < @width and @curpos < maxlen-1 # else it will do out of box
|
|
399
|
+
@curpos += 1
|
|
400
|
+
addcol 1
|
|
401
|
+
else
|
|
402
|
+
@pcol += 1 if @pcol <= row_length
|
|
403
|
+
end
|
|
404
|
+
}
|
|
405
|
+
set_form_col
|
|
406
|
+
#@repaint_required = true
|
|
407
|
+
@repaint_footer_required = true # 2010-01-23 22:41
|
|
408
|
+
end
|
|
409
|
+
def addcol num #:nodoc:
|
|
410
|
+
#@repaint_required = true
|
|
411
|
+
@repaint_footer_required = true # 2010-01-23 22:41
|
|
412
|
+
if @form
|
|
413
|
+
@form.addcol num
|
|
414
|
+
else
|
|
415
|
+
@parent_component.form && @parent_component.form.addcol(num)
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
def addrowcol row,col #:nodoc:
|
|
419
|
+
#@repaint_required = true
|
|
420
|
+
@repaint_footer_required = true # 2010-01-23 22:41
|
|
421
|
+
if @form
|
|
422
|
+
@form.addrowcol row, col
|
|
423
|
+
else
|
|
424
|
+
@parent_component.form.addrowcol num
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
def cursor_backward #:nodoc:
|
|
428
|
+
repeatm {
|
|
429
|
+
if @curpos > 0
|
|
430
|
+
@curpos -= 1
|
|
431
|
+
set_form_col
|
|
432
|
+
#addcol -1
|
|
433
|
+
elsif @pcol > 0
|
|
434
|
+
@pcol -= 1
|
|
435
|
+
end
|
|
436
|
+
}
|
|
437
|
+
#@repaint_required = true
|
|
438
|
+
@repaint_footer_required = true # 2010-01-23 22:41
|
|
439
|
+
end
|
|
440
|
+
# gives offset of next line, does not move
|
|
441
|
+
# @deprecated
|
|
442
|
+
def next_line #:nodoc:
|
|
443
|
+
@list[@current_index+1]
|
|
444
|
+
end
|
|
445
|
+
# @deprecated
|
|
446
|
+
def do_relative_row num #:nodoc:
|
|
447
|
+
raise "unused will be removed"
|
|
448
|
+
yield @list[@current_index+num]
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
# supply with a color parser, if you supplied formatted text
|
|
452
|
+
def color_parser f
|
|
453
|
+
$log.debug "XXX: parser setting color_parser to #{f} "
|
|
454
|
+
#@window.color_parser f
|
|
455
|
+
@color_parser = f
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
## NOTE: earlier print_border was called only once in constructor, but when
|
|
461
|
+
##+ a window is resized, and destroyed, then this was never called again, so the
|
|
462
|
+
##+ border would not be seen in splitpane unless the width coincided exactly with
|
|
463
|
+
##+ what is calculated in divider_location.
|
|
464
|
+
def paint #:nodoc:
|
|
465
|
+
|
|
466
|
+
$log.debug "XXX TEXTVIEW repaint HAPPENING #{@current_index} "
|
|
467
|
+
my_win = nil
|
|
468
|
+
if @form
|
|
469
|
+
my_win = @form.window
|
|
470
|
+
else
|
|
471
|
+
my_win = @target_window
|
|
472
|
+
end
|
|
473
|
+
@graphic = my_win unless @graphic
|
|
474
|
+
if @formatted_text
|
|
475
|
+
$log.debug "XXX: INSIDE FORMATTED TEXT "
|
|
476
|
+
|
|
477
|
+
# I don't want to do this in 20 places and then have to change
|
|
478
|
+
# it and retest. Let me push it to util.
|
|
479
|
+
l = RubyCurses::Utils.parse_formatted_text(@color_parser,
|
|
480
|
+
@formatted_text)
|
|
481
|
+
|
|
482
|
+
#cp = Chunks::ColorParser.new @color_parser
|
|
483
|
+
#l = []
|
|
484
|
+
#@formatted_text.each { |e| l << cp.convert_to_chunk(e) }
|
|
485
|
+
|
|
486
|
+
@old_content_type = @content_type
|
|
487
|
+
text(l)
|
|
488
|
+
@formatted_text = nil
|
|
489
|
+
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
print_borders if (@suppress_borders == false && @repaint_all) # do this once only, unless everything changes
|
|
493
|
+
rc = row_count
|
|
494
|
+
maxlen = @maxlen || @width-@internal_width
|
|
495
|
+
#$log.debug " #{@name} textview repaint width is #{@width}, height is #{@height} , maxlen #{maxlen}/ #{@maxlen}, #{@graphic.name} roff #{@row_offset} coff #{@col_offset}"
|
|
496
|
+
tm = get_content
|
|
497
|
+
tr = @toprow
|
|
498
|
+
acolor = get_color $datacolor
|
|
499
|
+
h = scrollatrow()
|
|
500
|
+
r,c = rowcol
|
|
501
|
+
@longest_line = @width-@internal_width #maxlen
|
|
502
|
+
0.upto(h) do |hh|
|
|
503
|
+
crow = tr+hh
|
|
504
|
+
if crow < rc
|
|
505
|
+
#focussed = @current_index == crow ? true : false
|
|
506
|
+
#selected = is_row_selected crow
|
|
507
|
+
content = tm[crow]
|
|
508
|
+
# next call modified string. you may wanna dup the string.
|
|
509
|
+
# rlistbox does
|
|
510
|
+
# scrolling fails if you do not dup, since content gets truncated
|
|
511
|
+
if content.is_a? String
|
|
512
|
+
content = content.dup
|
|
513
|
+
sanitize(content) if @sanitization_required
|
|
514
|
+
truncate content
|
|
515
|
+
@graphic.printstring r+hh, c, "%-*s" % [@width-@internal_width,content],
|
|
516
|
+
acolor, @attr
|
|
517
|
+
elsif content.is_a? Chunks::ChunkLine
|
|
518
|
+
# clear the line first
|
|
519
|
+
@graphic.printstring r+hh, c, " "* (@width-@internal_width),
|
|
520
|
+
acolor, @attr
|
|
521
|
+
# move back
|
|
522
|
+
@graphic.wmove r+hh, c
|
|
523
|
+
# either we have to loop through and put in default color and attr
|
|
524
|
+
# or pass it to show_col
|
|
525
|
+
a = get_attrib @attrib
|
|
526
|
+
# FIXME this does not clear till the eol
|
|
527
|
+
@graphic.show_colored_chunks content, acolor, a, @width-@internal_width, @pcol
|
|
528
|
+
elsif content.is_a? Chunks::Chunk
|
|
529
|
+
raise "TODO chunk in textview"
|
|
530
|
+
elsif content.is_a? Array
|
|
531
|
+
# several chunks in one row - NOTE Very experimental may change
|
|
532
|
+
if content[0].is_a? Array
|
|
533
|
+
# clearing the line since colored_chunks does not yet XXX FIXME if possible
|
|
534
|
+
@graphic.printstring r+hh, c, " "* (@width-@internal_width),
|
|
535
|
+
acolor, @attr
|
|
536
|
+
@graphic.wmove r+hh, c
|
|
537
|
+
# either we have to loop through and put in default color and attr
|
|
538
|
+
# or pass it to show_col
|
|
539
|
+
a = get_attrib @attrib
|
|
540
|
+
# FIXME this does not clear till the eol
|
|
541
|
+
# # NOTE 2013-03-08 - 17:37 pls add width to avoid overflow
|
|
542
|
+
@graphic.show_colored_chunks content, acolor, a, @width-@internal_width
|
|
543
|
+
#@graphic.show_colored_chunks content, acolor, a
|
|
544
|
+
else
|
|
545
|
+
# a single row chunk - NOTE Very experimental may change
|
|
546
|
+
text = content[1].dup
|
|
547
|
+
sanitize(text) if @sanitization_required
|
|
548
|
+
truncate text
|
|
549
|
+
@graphic.printstring r+hh, c, "%-*s" % [@width-@internal_width,text],
|
|
550
|
+
content[0] || acolor, content[2] || @attr
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
# highlighting search results.
|
|
555
|
+
if @search_found_ix == tr+hh
|
|
556
|
+
if !@find_offset.nil?
|
|
557
|
+
# handle exceed bounds, and if scrolling
|
|
558
|
+
if @find_offset1 < maxlen+@pcol and @find_offset > @pcol
|
|
559
|
+
@graphic.mvchgat(y=r+hh, x=c+@find_offset-@pcol, @find_offset1-@find_offset, Ncurses::A_NORMAL, $reversecolor, nil)
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
else
|
|
565
|
+
# clear rows
|
|
566
|
+
@graphic.printstring r+hh, c, " " * (@width-@internal_width), acolor,@attr
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
@repaint_required = false
|
|
572
|
+
@repaint_footer_required = true
|
|
573
|
+
@repaint_all = false
|
|
574
|
+
# 2011-10-15
|
|
575
|
+
@widget_scrolled = false
|
|
576
|
+
@record_changed = false
|
|
577
|
+
@property_changed = false
|
|
578
|
+
@old_pcol = @pcol
|
|
579
|
+
|
|
580
|
+
end
|
|
581
|
+
# takes a block, this way anyone extending this class can just pass a block to do his job
|
|
582
|
+
# This modifies the string
|
|
583
|
+
def sanitize content #:nodoc:
|
|
584
|
+
|
|
585
|
+
if content.is_a? String
|
|
586
|
+
content.chomp!
|
|
587
|
+
# trying out since gsub giving #<ArgumentError: invalid byte sequence in UTF-8> 2011-09-11
|
|
588
|
+
|
|
589
|
+
content.replace(content.encode("ASCII-8BIT", :invalid => :replace, :undef => :replace, :replace => "?")) if content.respond_to?(:encode)
|
|
590
|
+
content.gsub!(/[\t\n\r]/, ' ') # don't display tab or newlines
|
|
591
|
+
content.gsub!(/[^[:print:]]/, '') # don't display non print characters
|
|
592
|
+
else
|
|
593
|
+
content
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
# returns only the visible portion of string taking into account display length
|
|
597
|
+
# and horizontal scrolling. MODIFIES STRING
|
|
598
|
+
def truncate content #:nodoc:
|
|
599
|
+
_maxlen = @maxlen || @width-@internal_width
|
|
600
|
+
_maxlen = @width-@internal_width if _maxlen > @width-@internal_width # take care of decrease in width
|
|
601
|
+
if !content.nil?
|
|
602
|
+
if content.length > _maxlen # only show maxlen
|
|
603
|
+
@longest_line = content.length if content.length > @longest_line
|
|
604
|
+
#content = content[@pcol..@pcol+maxlen-1]
|
|
605
|
+
content.replace(content[@pcol..@pcol+_maxlen-1] || "")
|
|
606
|
+
else
|
|
607
|
+
if @pcol > 0
|
|
608
|
+
content.replace(content[@pcol..-1] || "")
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
content
|
|
613
|
+
end
|
|
614
|
+
## this is just a test of prompting user for a string
|
|
615
|
+
#+ as an alternative to the dialog.
|
|
616
|
+
def getstr prompt, maxlen=80 #:nodoc:
|
|
617
|
+
tabc = Proc.new {|str| Dir.glob(str +"*") }
|
|
618
|
+
config={}; config[:tab_completion] = tabc
|
|
619
|
+
config[:default] = "test"
|
|
620
|
+
config[:display_length] = 11
|
|
621
|
+
$log.debug " inside getstr before call "
|
|
622
|
+
ret, str = rbgetstr(@form.window, @row+@height-1, @col+1, prompt, maxlen, config)
|
|
623
|
+
$log.debug " rbgetstr returned #{ret} ,#{str}."
|
|
624
|
+
return "" if ret != 0
|
|
625
|
+
return str
|
|
626
|
+
end
|
|
627
|
+
##
|
|
628
|
+
# dynamically load a module and execute init method.
|
|
629
|
+
# Hopefully, we can get behavior like this such as vieditable or multibuffers
|
|
630
|
+
def load_module requirename, includename
|
|
631
|
+
require "rbhex/#{requirename}"
|
|
632
|
+
extend Object.const_get("#{includename}")
|
|
633
|
+
send("#{requirename}_init") #if respond_to? "#{includename}_init"
|
|
634
|
+
end
|
|
635
|
+
# on pressing ENTER we send user some info, the calling program
|
|
636
|
+
# would bind :PRESS
|
|
637
|
+
#--
|
|
638
|
+
# FIXME we can create this once and reuse
|
|
639
|
+
#++
|
|
640
|
+
def fire_action_event
|
|
641
|
+
return if @list.nil? || @list.size == 0
|
|
642
|
+
require 'rbhex/core/include/ractionevent'
|
|
643
|
+
aev = TextActionEvent.new self, :PRESS, current_value().to_s, @current_index, @curpos
|
|
644
|
+
fire_handler :PRESS, aev
|
|
645
|
+
end
|
|
646
|
+
# called by listscrollable, used by scrollbar ENTER_ROW
|
|
647
|
+
def on_enter_row arow
|
|
648
|
+
fire_handler :ENTER_ROW, self
|
|
649
|
+
@repaint_required = true
|
|
650
|
+
end
|
|
651
|
+
# added 2010-09-30 18:48 so standard with other components, esp on enter
|
|
652
|
+
# NOTE: the on_enter repaint required causes this to be repainted 2 times
|
|
653
|
+
# if its the first object, once with the entire form, then with on_enter.
|
|
654
|
+
def on_enter
|
|
655
|
+
if @list.nil? || @list.size == 0
|
|
656
|
+
Ncurses.beep
|
|
657
|
+
return :UNHANDLED
|
|
658
|
+
end
|
|
659
|
+
on_enter_row @current_index
|
|
660
|
+
set_form_row
|
|
661
|
+
@repaint_required = true
|
|
662
|
+
super
|
|
663
|
+
true
|
|
664
|
+
end
|
|
665
|
+
def pipe_file
|
|
666
|
+
# TODO ask process name from user
|
|
667
|
+
output = pipe_output 'munpack', @list
|
|
668
|
+
if output && !output.empty?
|
|
669
|
+
set_content output
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
# returns array of lines after running command on string passed
|
|
673
|
+
# TODO: need to close pipe other's we'll have a process lying
|
|
674
|
+
# around forever.
|
|
675
|
+
def pipe_output (pipeto, str)
|
|
676
|
+
case str
|
|
677
|
+
when String
|
|
678
|
+
#str = str.split "\n"
|
|
679
|
+
# okay
|
|
680
|
+
when Array
|
|
681
|
+
str = str.join "\n"
|
|
682
|
+
end
|
|
683
|
+
#pipeto = '/usr/sbin/sendmail -t'
|
|
684
|
+
#pipeto = %q{mail -s "my title" rahul}
|
|
685
|
+
if pipeto != nil # i was taking pipeto from a hash, so checking
|
|
686
|
+
proc = IO.popen(pipeto, "w+")
|
|
687
|
+
proc.puts str
|
|
688
|
+
proc.close_write
|
|
689
|
+
proc.readlines
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
def saveas name=nil, config={}
|
|
693
|
+
unless name
|
|
694
|
+
name = rb_gets "File to save as: "
|
|
695
|
+
return if name.nil? || name == ""
|
|
696
|
+
end
|
|
697
|
+
exists = File.exists? name
|
|
698
|
+
if exists # need to prompt
|
|
699
|
+
return unless rb_confirm("Overwrite existing file? ")
|
|
700
|
+
end
|
|
701
|
+
l = getvalue
|
|
702
|
+
File.open(name, "w"){ |f|
|
|
703
|
+
l.each { |line| f.puts line }
|
|
704
|
+
#l.each { |line| f.write line.gsub(/\r/,"\n") }
|
|
705
|
+
}
|
|
706
|
+
rb_puts "#{name} written."
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
# edit content of textview in EDITOR and bring back
|
|
710
|
+
# NOTE: does not maintain content_type, so if you edit ansi text,
|
|
711
|
+
# it will come back in as normal text
|
|
712
|
+
def edit_external
|
|
713
|
+
require 'rbhex/core/include/appmethods'
|
|
714
|
+
require 'tempfile'
|
|
715
|
+
f = Tempfile.new("rbhex")
|
|
716
|
+
l = self.text
|
|
717
|
+
l.each { |line| f.puts line }
|
|
718
|
+
fp = f.path
|
|
719
|
+
f.flush
|
|
720
|
+
|
|
721
|
+
editor = ENV['EDITOR'] || 'vi'
|
|
722
|
+
vimp = %x[which #{editor}].chomp
|
|
723
|
+
ret = shell_out "#{vimp} #{fp}"
|
|
724
|
+
if ret
|
|
725
|
+
lines = File.open(f,'r').readlines
|
|
726
|
+
set_content(lines, :content_type => @old_content_type)
|
|
727
|
+
end
|
|
728
|
+
end
|
|
729
|
+
def init_actions
|
|
730
|
+
editor = ENV['EDITOR'] || 'vi'
|
|
731
|
+
am = action_manager()
|
|
732
|
+
am.add_action( Action.new("&Edit in #{editor} ") { edit_external } )
|
|
733
|
+
am.add_action( Action.new("&Saveas") { saveas() })
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
end # class textview
|
|
738
|
+
|
|
739
|
+
end # modul
|