rbhex-core 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/CHANGELOG +2000 -0
  4. data/LICENSE +56 -0
  5. data/README.md +44 -0
  6. data/examples/abasiclist.rb +179 -0
  7. data/examples/alpmenu.rb +50 -0
  8. data/examples/app.sample +19 -0
  9. data/examples/atree.rb +100 -0
  10. data/examples/bline.rb +136 -0
  11. data/examples/common/file.rb +45 -0
  12. data/examples/data/README.markdown +9 -0
  13. data/examples/data/brew.txt +38 -0
  14. data/examples/data/color.2 +37 -0
  15. data/examples/data/gemlist.txt +60 -0
  16. data/examples/data/lotr.txt +12 -0
  17. data/examples/data/ports.txt +136 -0
  18. data/examples/data/table.txt +37 -0
  19. data/examples/data/tasks.csv +88 -0
  20. data/examples/data/tasks.txt +27 -0
  21. data/examples/data/todo.txt +10 -0
  22. data/examples/data/todo.txt.bak +10 -0
  23. data/examples/data/todocsv.csv +28 -0
  24. data/examples/data/unix1.txt +21 -0
  25. data/examples/data/unix2.txt +11 -0
  26. data/examples/dbdemo.rb +502 -0
  27. data/examples/dirtree.rb +94 -0
  28. data/examples/newtabbedwindow.rb +100 -0
  29. data/examples/newtesttabp.rb +92 -0
  30. data/examples/tabular.rb +146 -0
  31. data/examples/tasks.rb +178 -0
  32. data/examples/term2.rb +84 -0
  33. data/examples/testbuttons.rb +296 -0
  34. data/examples/testcombo.rb +102 -0
  35. data/examples/testfields.rb +195 -0
  36. data/examples/testkeypress.rb +72 -0
  37. data/examples/testlistbox.rb +170 -0
  38. data/examples/testmessagebox.rb +140 -0
  39. data/examples/testprogress.rb +116 -0
  40. data/examples/testree.rb +106 -0
  41. data/examples/testwsshortcuts.rb +66 -0
  42. data/examples/testwsshortcuts2.rb +128 -0
  43. data/lib/rbhex.rb +6 -0
  44. data/lib/rbhex/core/docs/index.txt +73 -0
  45. data/lib/rbhex/core/include/action.rb +80 -0
  46. data/lib/rbhex/core/include/actionmanager.rb +49 -0
  47. data/lib/rbhex/core/include/appmethods.rb +214 -0
  48. data/lib/rbhex/core/include/bordertitle.rb +48 -0
  49. data/lib/rbhex/core/include/chunk.rb +203 -0
  50. data/lib/rbhex/core/include/io.rb +553 -0
  51. data/lib/rbhex/core/include/listbindings.rb +74 -0
  52. data/lib/rbhex/core/include/listcellrenderer.rb +140 -0
  53. data/lib/rbhex/core/include/listeditable.rb +317 -0
  54. data/lib/rbhex/core/include/listscrollable.rb +663 -0
  55. data/lib/rbhex/core/include/listselectable.rb +271 -0
  56. data/lib/rbhex/core/include/multibuffer.rb +83 -0
  57. data/lib/rbhex/core/include/orderedhash.rb +77 -0
  58. data/lib/rbhex/core/include/ractionevent.rb +73 -0
  59. data/lib/rbhex/core/include/rchangeevent.rb +27 -0
  60. data/lib/rbhex/core/include/rhistory.rb +95 -0
  61. data/lib/rbhex/core/include/rinputdataevent.rb +47 -0
  62. data/lib/rbhex/core/include/vieditable.rb +172 -0
  63. data/lib/rbhex/core/include/widgetmenu.rb +66 -0
  64. data/lib/rbhex/core/system/colormap.rb +165 -0
  65. data/lib/rbhex/core/system/keyboard.rb +150 -0
  66. data/lib/rbhex/core/system/keydefs.rb +30 -0
  67. data/lib/rbhex/core/system/ncurses.rb +236 -0
  68. data/lib/rbhex/core/system/panel.rb +162 -0
  69. data/lib/rbhex/core/system/window.rb +913 -0
  70. data/lib/rbhex/core/util/ansiparser.rb +119 -0
  71. data/lib/rbhex/core/util/app.rb +1228 -0
  72. data/lib/rbhex/core/util/basestack.rb +410 -0
  73. data/lib/rbhex/core/util/bottomline.rb +1859 -0
  74. data/lib/rbhex/core/util/colorparser.rb +77 -0
  75. data/lib/rbhex/core/util/focusmanager.rb +31 -0
  76. data/lib/rbhex/core/util/padreader.rb +192 -0
  77. data/lib/rbhex/core/util/rcommandwindow.rb +604 -0
  78. data/lib/rbhex/core/util/rdialogs.rb +574 -0
  79. data/lib/rbhex/core/util/viewer.rb +149 -0
  80. data/lib/rbhex/core/util/widgetshortcuts.rb +506 -0
  81. data/lib/rbhex/core/version.rb +5 -0
  82. data/lib/rbhex/core/widgets/applicationheader.rb +103 -0
  83. data/lib/rbhex/core/widgets/box.rb +58 -0
  84. data/lib/rbhex/core/widgets/divider.rb +310 -0
  85. data/lib/rbhex/core/widgets/keylabelprinter.rb +194 -0
  86. data/lib/rbhex/core/widgets/rcombo.rb +253 -0
  87. data/lib/rbhex/core/widgets/rcontainer.rb +415 -0
  88. data/lib/rbhex/core/widgets/rlink.rb +30 -0
  89. data/lib/rbhex/core/widgets/rlist.rb +696 -0
  90. data/lib/rbhex/core/widgets/rmenu.rb +958 -0
  91. data/lib/rbhex/core/widgets/rmenulink.rb +22 -0
  92. data/lib/rbhex/core/widgets/rmessagebox.rb +387 -0
  93. data/lib/rbhex/core/widgets/rprogress.rb +118 -0
  94. data/lib/rbhex/core/widgets/rtabbedpane.rb +634 -0
  95. data/lib/rbhex/core/widgets/rtabbedwindow.rb +70 -0
  96. data/lib/rbhex/core/widgets/rtextarea.rb +960 -0
  97. data/lib/rbhex/core/widgets/rtextview.rb +739 -0
  98. data/lib/rbhex/core/widgets/rtree.rb +768 -0
  99. data/lib/rbhex/core/widgets/rwidget.rb +3277 -0
  100. data/lib/rbhex/core/widgets/scrollbar.rb +143 -0
  101. data/lib/rbhex/core/widgets/statusline.rb +113 -0
  102. data/lib/rbhex/core/widgets/tabular.rb +264 -0
  103. data/lib/rbhex/core/widgets/tabularwidget.rb +1142 -0
  104. data/lib/rbhex/core/widgets/textpad.rb +995 -0
  105. data/lib/rbhex/core/widgets/tree/treecellrenderer.rb +150 -0
  106. data/lib/rbhex/core/widgets/tree/treemodel.rb +428 -0
  107. data/rbhex-core.gemspec +32 -0
  108. metadata +172 -0
@@ -0,0 +1,70 @@
1
+ =begin
2
+ * Name: newtabbedwindow.rb
3
+ * Description : This is a window that contains a tabbedpane (NewTabbedPane). This for situation
4
+ when you want to pop up a setup/configuration type of tabbed pane.
5
+ See examples/newtabbedwindow.rb for an example of usage, and test2.rb
6
+ which calls it from the menu (Options2 item).
7
+ In a short while, I will deprecate the existing complex TabbedPane and use this
8
+ in the lib/rbhex dir.
9
+ * Author: rkumar (http://github.com/rkumar/rbcurse/)
10
+ * Date: 22.10.11 - 20:35
11
+ * License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
12
+ * Last update: 2013-04-01 13:42
13
+
14
+ == CHANGES
15
+ == TODO
16
+ =end
17
+ require 'rbhex'
18
+ require 'rbhex/core/widgets/rtabbedpane'
19
+ require 'rbhex/core/widgets/rcontainer'
20
+
21
+ include RubyCurses
22
+ module RubyCurses
23
+ class TabbedWindow
24
+ attr_reader :tabbed_pane
25
+ # The given block is passed to the TabbedPane
26
+ # The given dimensions are used to create the window.
27
+ # The TabbedPane is placed at 0,0 and fills the window.
28
+ def initialize config={}, &block
29
+
30
+ h = config.fetch(:height, 0)
31
+ w = config.fetch(:width, 0)
32
+ t = config.fetch(:row, 0)
33
+ l = config.fetch(:col, 0)
34
+ @window = VER::Window.new :height => h, :width => w, :top => t, :left => l
35
+ @form = Form.new @window
36
+ config[:row] = config[:col] = 0
37
+ @tabbed_pane = TabbedPane.new @form, config , &block
38
+ end
39
+ # returns button index
40
+ # Call this after instantiating the window
41
+ def run
42
+ @form.repaint
43
+ @window.wrefresh
44
+ return handle_keys
45
+ end
46
+ # returns button index
47
+ private
48
+ def handle_keys
49
+ buttonindex = catch(:close) do
50
+ while((ch = @window.getchar()) != FFI::NCurses::KEY_F10 )
51
+ break if ch == ?\C-q.getbyte(0)
52
+ begin
53
+ @form.handle_key(ch)
54
+ @window.wrefresh
55
+ rescue => err
56
+ $log.debug( err) if err
57
+ $log.debug(err.backtrace.join("\n")) if err
58
+ textdialog ["Error in TabbedWindow: #{err} ", *err.backtrace], :title => "Exception"
59
+ $error_message.value = ""
60
+ ensure
61
+ end
62
+
63
+ end # while loop
64
+ end # close
65
+ $log.debug "XXX: CALLER GOT #{buttonindex} "
66
+ @window.destroy
67
+ return buttonindex
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,960 @@
1
+ =begin
2
+ * Name: TextArea
3
+ * Description Editable text area
4
+ * Author: rkumar (arunachalesha)
5
+ 2009-12-26 14:43 buffered version of rtextarea.rb. See BUFFERED
6
+ * major change: 2010-02-12 13:34 simplifying the buffer stuff.
7
+ * see FIXME of textview for some common issues to look at.
8
+ * removed many edit functions to listeditable - 2010-03-12 10:16
9
+
10
+ Todo:
11
+ * shoud we store path, so a save can be done
12
+ --------
13
+ * Date: 2008-11-14 23:43
14
+ * License:
15
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
16
+
17
+ =end
18
+ require 'logger'
19
+ require 'rbhex'
20
+ require 'rbhex/core/include/listscrollable'
21
+ require 'rbhex/core/include/rinputdataevent'
22
+ require 'rbhex/core/include/listeditable'
23
+ require 'rbhex/core/include/bordertitle'
24
+
25
+ #include Ncurses # FFI 2011-09-8
26
+ include RubyCurses
27
+ module RubyCurses
28
+ extend self
29
+
30
+ ## a multiline text editing widget
31
+ # TODO - giving data to user - adding newlines, and withog adding.
32
+ # - respect newlines for incoming data
33
+ # we need a set_text method, passing nil or blank clears
34
+ # current way is not really good. remove_all sucks.
35
+ # TODO don't set maxlen if nil. compute it as a local in methods. Else splitpane will not
36
+ # work correctly.
37
+ class TextArea < Widget
38
+ include ListScrollable
39
+ # NOTE: common editing functions moved to listeditable
40
+ include ListEditable
41
+ #dsl_accessor :title
42
+ #dsl_accessor :title_attrib # bold, reverse, normal
43
+ #dsl_accessor :footer_attrib # bold, reverse, normal added 2009-12-26 18:25 was this missing or delib
44
+ dsl_accessor :list # the array of data to be sent by user
45
+ dsl_accessor :maxlen # max display length of a row/line
46
+ attr_reader :toprow
47
+ dsl_accessor :auto_scroll # boolean, keeps view at end as data is inserted.
48
+ dsl_accessor :print_footer
49
+ dsl_accessor :editable # allow editing
50
+ #dsl_accessor :suppress_borders # added 2010-02-12 12:21 values true or false
51
+ attr_accessor :overwrite_mode # boolean: insert or overwrite, default false.
52
+
53
+ def initialize form = nil, config={}, &block
54
+ @focusable = true
55
+ @editable = true
56
+ @row = 0
57
+ @col = 0
58
+ @curpos = 0
59
+ @list = []
60
+ @suppress_borders = false
61
+ @row_offset = @col_offset = 1 # for cursor display on first entry, so not positioned on border
62
+ @_events ||= []
63
+ @_events.push :CHANGE
64
+ super
65
+ @orig_col = @col
66
+ # this does result in a blank line if we insert after creating. That's required at
67
+ # present if we wish to only insert
68
+ if @list.empty?
69
+ # @list << "\r" # removed this on 2009-02-15 17:25 lets see how it goes
70
+ end
71
+ @content_rows = @list.length
72
+ @win = @graphic # 2009-12-26 14:54 BUFFERED replace form.window with graphic
73
+ # 2010-01-10 19:35 compute locally if not set
74
+ install_keys
75
+ init_vars
76
+ bordertitle_init
77
+ init_actions
78
+ end
79
+ def init_vars
80
+ @repaint_required = true
81
+ @repaint_footer_required = true # 2010-01-23 22:41
82
+ @toprow = @current_index = @pcol = 0
83
+ @repaint_all=true
84
+ @row_offset = @col_offset = 0 if @suppress_borders
85
+ @longest_line = 0
86
+ # if borders used, reduce 2 from width else 0
87
+ @internal_width = 2
88
+ @internal_width = 2 if @suppress_borders # WHAT THE !!!! It should be zero
89
+ bind_key(?\M-w, :kill_ring_save)
90
+ bind_key(?\C-y, :yank)
91
+ bind_key(?\M-y, :yank_pop)
92
+ bind_key(?\M-\C-w, :append_next_kill)
93
+ map_keys
94
+ end
95
+ def rowcol
96
+ # $log.debug "textarea rowcol : #{@row+@row_offset+@winrow}, #{@col+@col_offset}"
97
+ return @row+@row_offset, @col+@col_offset
98
+ end
99
+ ##
100
+ # this avoids wrapping. Better to use the <<.
101
+ def Oinsert off0, *data
102
+ @list.insert off0, *data
103
+ # fire_handler :CHANGE, self # 2008-12-09 14:56 NOT SURE
104
+ end
105
+ # private
106
+ def wrap_text(txt, col = @maxlen)
107
+ col ||= @width - @internal_width
108
+ #$log.debug "inside wrap text for :#{txt}"
109
+ txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,
110
+ "\\1\\3\n")
111
+ end
112
+ ##
113
+ # trying to wrap and insert
114
+ def insert off0, data
115
+ _maxlen = @maxlen || @width - @internal_width
116
+ if data.length > _maxlen
117
+ data = wrap_text data
118
+ # $log.debug "after wrap text done :#{data}"
119
+ data = data.split("\n")
120
+ data[-1] << "\r" #XXXX
121
+ data.each do |row|
122
+ @list.insert off0, row
123
+ off0 += 1
124
+ end
125
+ else
126
+ data << "\r" if data[-1,1] != "\r" #XXXX
127
+ @list.insert off0, data
128
+ end
129
+ # expecting array !!
130
+ #data.each do |row|
131
+ #@list.insert off0, row
132
+ #off0 += 1
133
+ #end
134
+ #$log.debug " AFTER INSERT: #{@list}"
135
+ end
136
+ ##
137
+ # wraps line sent in if longer than _maxlen
138
+ # Typically a line is sent in. We wrap and put a hard return at end.
139
+ def << data
140
+ # if width if nil, either set it, or add this to a container that sets it before calling this method
141
+ _maxlen = @maxlen || @width - @internal_width
142
+ if data.length > _maxlen
143
+ #$log.debug "wrapped append for #{data}"
144
+ data = wrap_text data
145
+ #$log.debug "after wrap text for :#{data}"
146
+ data = data.split("\n")
147
+ # 2009-01-01 22:24 the \n was needed so we would put a space at time of writing.
148
+ # we need a soft return so a space can be added when pushing down.
149
+ # commented off 2008-12-28 21:59
150
+ #data.each {|line| @list << line+"\n"}
151
+ data.each {|line| @list << line}
152
+ @list[-1] << "\r" #XXXX
153
+ else
154
+ #$log.debug "normal append for #{data}"
155
+ data << "\r" if data[-1,1] != "\r" #XXXX
156
+ @list << data
157
+ end
158
+ set_modified # added 2009-03-07 18:29
159
+ goto_end if @auto_scroll
160
+ self
161
+ end
162
+ def wrap_para line=@current_index
163
+ line ||= 0
164
+ l=[]
165
+ while true
166
+ if @list[line].nil? or @list[line]=="" or @list[line]==13 #"\r"
167
+ break
168
+ end
169
+ #$log.debug "lastchar #{@list[line][-1]}, appending: #{@list[line]}]"
170
+ t = @list[line]
171
+ l << t.strip
172
+ @list.delete_at line
173
+ break if t[-1]==13 # "\r"
174
+ # line += 1
175
+ end
176
+ str=l.join(" ")
177
+ #$log.debug " sending insert : #{str}."
178
+ insert line, str
179
+ end
180
+ ##
181
+ # private
182
+ def OLDprint_borders
183
+ window = @graphic # 2009-12-26 14:54 BUFFERED
184
+ @color_pair = get_color($datacolor) # 2011-09-28 V1.3.1
185
+ bordercolor = @border_color || @color_pair
186
+ borderatt = @border_attrib || Ncurses::A_NORMAL
187
+ #color = $datacolor
188
+ #window.print_border @row, @col, @height, @width, color
189
+ window.print_border @row, @col, @height-1, @width, bordercolor, borderatt
190
+ print_title
191
+ =begin
192
+ hline = "+%s+" % [ "-"*(width-((1)*2)) ]
193
+ hline2 = "|%s|" % [ " "*(width-((1)*2)) ]
194
+ window.printstring( row=startrow, col=startcol, hline, color)
195
+ print_title
196
+ (startrow+1).upto(startrow+height-1) do |row|
197
+ window.printstring(row, col=startcol, hline2, color)
198
+ end
199
+ window.printstring(startrow+height, col=startcol, hline, color)
200
+ =end
201
+
202
+ end
203
+ # private
204
+ def OLDprint_title
205
+ # truncate title if longer than width
206
+ return unless @title
207
+ @color_pair ||= get_color($datacolor)
208
+ _title = @title
209
+ if @title.length > @width - 2
210
+ _title = @title[0..@width-2]
211
+ end
212
+ @graphic.printstring( @row, @col+(@width-_title.length)/2, _title, @color_pair, @title_attrib) unless @title.nil?
213
+ end
214
+ # text_area print footer
215
+ def print_foot
216
+ @footer_attrib ||= Ncurses::A_REVERSE
217
+ footer = "R: #{@current_index+1}, C: #{@curpos}, #{@list.length} lines "
218
+ #$log.debug " print_foot calling printstring with #{@row} + #{@height} -1, #{@col}+2"
219
+ # changed 2010-01-02 19:31 BUFFERED we were exceeding 1
220
+ #@graphic.printstring( @row + @height, @col+2, footer, $datacolor, @footer_attrib)
221
+ @graphic.printstring( @row + @height-1, @col+2, footer, @color_pair || $datacolor, @footer_attrib)
222
+ @repaint_footer_required = false
223
+ end
224
+ ### FOR scrollable ###
225
+ def get_content
226
+ @list
227
+ end
228
+ #
229
+ # sets content of textarea. I don't know why this was not existing all this while
230
+ # Name to be consistent with textview. Okay, this does not wrap the words, we assume
231
+ # its short enough. FIXME. Avoid using currently till i firm this.
232
+ # NOTE: does not wrap, and does not trigger events
233
+ # Added on 2011-10-10
234
+ # @since 1.4.0
235
+ # @param [String, Array] String is an existing filename, Array is content to be replaced
236
+ # Added config for compatibility with textview
237
+ def set_content lines, config={}
238
+ case lines
239
+ when String
240
+ if File.exists? lines
241
+ lines = File.open(lines,"r").readlines
242
+ else
243
+ raise "set_content String param should be a filename"
244
+ end
245
+ when Array
246
+ else
247
+ raise "Don't know how to handle data in set_content: #{lines.class} "
248
+ end
249
+ @list.replace lines
250
+ @repaint_required = true
251
+ end
252
+ #alias :text :set_content
253
+ # set text
254
+ # Added for consistency with other widgets
255
+ def text(*val)
256
+ if val.empty?
257
+ return @list
258
+ end
259
+ set_content(*val)
260
+ self
261
+ end
262
+ def text=(val)
263
+ return unless val # added 2010-11-17 20:11, dup will fail on nil
264
+ set_content(val)
265
+ end
266
+ def get_window
267
+ @graphic
268
+ end
269
+ ### FOR scrollable ###
270
+ def repaint # textarea
271
+ #return unless @repaint_required # 2010-02-12 19:08 TRYING - won't let footer print if only col move
272
+ paint if @repaint_required
273
+ print_foot if @print_footer && !@suppress_borders && (@repaint_footer_required || @repaint_required)
274
+ end
275
+ def getvalue
276
+ @list
277
+ end
278
+
279
+ def map_keys
280
+ return if @keys_mapped
281
+ @key_map = :both # get both vim and emacs keys
282
+ require 'rbhex/core/include/listbindings'
283
+ bindings
284
+ #
285
+ # There's one issue, if using vim keys, most of them won't
286
+ # work in text area. So you will need emacs keys in text area.
287
+
288
+ # moved to listbin
289
+ #bind_key(Ncurses::KEY_LEFT){ cursor_backward }
290
+ #bind_key(Ncurses::KEY_RIGHT){ cursor_forward }
291
+ #bind_key(Ncurses::KEY_UP){ ret = up; get_window.ungetch(KEY_BTAB) if ret == :NO_PREVIOUS_ROW }
292
+ # the next was irritating if user wanted to add a row ! 2011-10-10
293
+ ##bind_key(Ncurses::KEY_DOWN){ ret = down ; get_window.ungetch(KEY_TAB) if ret == :NO_NEXT_ROW }
294
+ #bind_key(Ncurses::KEY_DOWN){ ret = down ; }
295
+
296
+ bind_key(KEY_BACKSPACE){ delete_prev_char if @editable }
297
+ bind_key(KEY_BSPACE){ delete_prev_char if @editable}
298
+ bind_key(?\M-d, :delete_word)
299
+ bind_key(?\M-f, :forward_word)
300
+
301
+ # earlier 330
302
+ bind_key(FFI::NCurses::KEY_DC, 'delete current char'){ delete_curr_char if @editable }
303
+ bind_key(?\C-k, 'kill line'){ kill_line }
304
+ bind_key(?\C-_, 'undo'){ undo }
305
+ bind_key(?\C-r, 'redo') { text_redo }
306
+ #bind_key(27){ set_buffer @original_value }
307
+ #bind_key([?\C-x, ?e], :edit_external)
308
+ #bind_key([?\C-x, ?\C-s], :saveas)
309
+ @keys_mapped = true
310
+ end
311
+ # mimicking emacs behavior of C-k.
312
+ # delete entire line if at start, else delete till eol
313
+ def kill_line
314
+ # i'ved added curpos == 0 since emacs deletes a line if cursor is at 0
315
+ # Earlier behavior was based on alpine which leaves a blank line
316
+ if @editable
317
+ if @buffer.chomp == "" || @curpos == 0
318
+ delete_line
319
+ else
320
+ delete_eol
321
+ end
322
+ end
323
+ end
324
+
325
+ # textarea
326
+ def handle_key ch
327
+ @current_key = ch # I need some funcs to know what key they were mapped to
328
+ @buffer = @list[@current_index]
329
+ if @buffer.nil? and @list.length == 0
330
+ ## 2009-10-04 22:39
331
+ # what this newline does is , if we use << to append, data is appended
332
+ # to second line
333
+ @list << "\n" # changed space to newline so wrapping puts a line.
334
+ @current_index = 0 ; ## added 2009-10-04 21:47
335
+ @buffer = @list[@current_index]
336
+ end
337
+ ## 2009-10-04 20:48 i think the next line was resulting in a hang if buffer nil
338
+ # in sqlc on pressing Clear.
339
+ # if buffer is nil and user wants to enter something -- added UNHANDLED
340
+ return :UNHANDLED if @buffer.nil?
341
+ #$log.debug "TA: before: curpos #{@curpos} blen: #{@buffer.length}"
342
+ # on any line if the cursor is ahead of buffer length, ensure its on last position
343
+ # what if the buffer is somehow gt maxlen ??
344
+ if @curpos > @buffer.length
345
+ addcol(@buffer.length-@curpos)+1
346
+ @curpos = @buffer.length
347
+ end
348
+ #$log.debug "TA: after : curpos #{@curpos} blen: #{@buffer.length}, w: #{@width} max #{@maxlen}"
349
+
350
+ #NOTE C-d being used for del what of scroll !!
351
+ case ch
352
+ when KEY_ENTER, KEY_RETURN, FFI::NCurses::KEY_ENTER # numeric enter
353
+ insert_break
354
+ #when ?\C-u.getbyte(0)
355
+ ## since textareas are editable we use a control key to increase
356
+ ## multiplier. Series is 4 16 64
357
+ #@multiplier = (@multiplier == 0 ? 4 : @multiplier *= 4)
358
+ #return 0
359
+ else
360
+ #$log.debug(" textarea ch #{ch}")
361
+ ret = putc ch
362
+ if ret == :UNHANDLED
363
+ # check for bindings, these cannot override above keys since placed at end
364
+ ret = process_key ch, self
365
+ #$log.debug "TA process_key #{ch} got ret #{ret} in #{@name} "
366
+ return :UNHANDLED if ret == :UNHANDLED
367
+ end
368
+ end
369
+ set_form_row
370
+ set_form_col # testing 2008-12-26 19:37
371
+ $multiplier = 0 # reset only if key handled
372
+ return 0
373
+ end
374
+ # this is broken, delete_buffer could be a line or a string or array of lines
375
+ def undo_delete
376
+ # added 2008-11-27 12:43 paste delete buffer into insertion point
377
+ return if @delete_buffer.nil?
378
+ $log.warn "undo_delete is broken! perhaps cannot be used . textarea 347 "
379
+ # FIXME - can be an array
380
+ case @delete_buffer
381
+ when Array
382
+ # we need to unroll array, and it could be lines not just a string
383
+ str = @delete_buffer.first
384
+ else
385
+ str = @delete_buffer
386
+ end
387
+ @buffer.insert @curpos, str
388
+ set_modified
389
+ fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :INSERT, @current_index, @delete_buffer) # 2008-12-24 18:34
390
+ end
391
+ # FIXME - fire event not correct, not undo'ing correctly, check row and also slash r append
392
+ def insert_break
393
+ return -1 unless @editable
394
+ # insert a blank row and append rest of this line to cursor
395
+ $log.debug "ENTER PRESSED at #{@curpos}, on row #{@current_index}"
396
+ @delete_buffer = (delete_eol || "")
397
+ @list[@current_index] << "\r"
398
+ $log.debug "DELETE BUFFER #{@delete_buffer}"
399
+ @list.insert @current_index+1, @delete_buffer
400
+ @curpos = 0
401
+ down
402
+ col = @orig_col + @col_offset
403
+ setrowcol @row+1, col
404
+ # FIXME maybe this should be insert line since line inserted, not just data, undo will delete it
405
+ fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :INSERT_LINE, @current_index, @delete_buffer) # 2008-12-24 18:34
406
+ end
407
+ # set cursor on correct column
408
+ def set_form_col col1=@curpos
409
+ @curpos = col1
410
+ @cols_panned ||= 0
411
+ cursor_bounds_check
412
+
413
+ ## added win_col on 2009-12-28 20:21 for embedded forms BUFFERED TRYING OUT
414
+ win_col = 0 # 2010-02-07 23:19 new cursor stuff
415
+ #col = win_col + @orig_col + @col_offset + @curpos
416
+ #col = win_col + @orig_col + @col_offset + @curpos + @cols_panned
417
+ # 2010-01-14 13:31 changed orig_col to col for embedded forms, splitpanes.
418
+ col = win_col + @col + @col_offset + @curpos + @cols_panned
419
+ $log.debug "sfc: wc:#{win_col} col:#{@col}, coff:#{@col_offset}. cp:#{@curpos} colsp:#{@cols_panned} . "
420
+ #@form.setrowcol @form.row, col # added 2009-12-29 18:50 BUFFERED
421
+ $log.debug " TA calling setformrow col nil, #{col} "
422
+ setrowcol nil, col # added 2009-12-29 18:50 BUFFERED
423
+ @repaint_footer_required = true
424
+ end
425
+ def cursor_bounds_check
426
+ max = buffer_len()
427
+ @curpos = max if @curpos > max # check 2008-12-27 00:02
428
+ end
429
+ def buffer_len
430
+ @list[@current_index].nil? ? 0 : @list[@current_index].chomp().length
431
+ end
432
+ def do_current_row # :yields current row
433
+ yield @list[@current_index]
434
+ @buffer = @list[@current_index]
435
+ end
436
+ ##
437
+ # FIXME : if cursor at end of last line then forward takes cursor to start
438
+ # of last line (same line), should stop there.
439
+ def cursor_forward num=1
440
+ #$log.debug "next char cp #{@curpos}, #{@buffer.length}. wi: #{@width}"
441
+ #$log.debug "next char cp ll and ci #{@list.length}, #{@current_index}"
442
+ #if @curpos < @width and @curpos < maxlen-1 # else it will do out of box
443
+ return if at_eol? and at_last_line?
444
+ repeatm {
445
+ if @curpos < buffer_len()
446
+ @curpos += 1
447
+ addcol 1
448
+ else # trying this out 2008-12-26 20:18
449
+ @curpos = 0
450
+ down 1 # if not then multipler will trigger there too
451
+ end
452
+ cursor_bounds_check
453
+ }
454
+ end
455
+ ## added 2009-10-04 22:13
456
+ # returns whether cursor is at end of line
457
+ def at_eol?
458
+ if @curpos+1== @list[@current_index].length
459
+ return true
460
+ end
461
+ return false
462
+ end
463
+ ## added 2009-10-04 22:13
464
+ # returns whether at last line (required so that forward does not go to start)
465
+ def at_last_line?
466
+ return true if @list.length == @current_index + 1
467
+ return false
468
+ end
469
+ # FIXME : these 2 only require the footer to be repainted not everything
470
+ # We should be able to manage that. We need a repaint_footer_required.
471
+ # Setting repaint_required really slows performance when one presses the right arrow key
472
+ # since a repaint is happenign repeatedly for each key.
473
+ def addcol num
474
+ # @repaint_required = true # added 2010-01-15 23:59, so that footer is updated, sucks!
475
+ @repaint_footer_required = true # 2010-01-23 22:41
476
+ my_win = @form || @parent_component.form # 2010-02-12 12:51
477
+ my_win.addcol num
478
+ end
479
+ def addrowcol row,col
480
+ #@repaint_required = true # added 2010-01-15 23:59
481
+ @repaint_footer_required = true # 2010-01-23 22:41
482
+ my_win = @form || @parent_component.form # 2010-02-12 12:51
483
+ my_win.addrowcol row, col
484
+ end
485
+ ## 2009-10-04 23:01 taken care that you can't go back at start of textarea
486
+ # it was going onto border
487
+ def cursor_backward
488
+ #$log.debug "back char cp ll and ci #{@list.length}, #{@current_index}"
489
+ #$log.debug "back char cb #{@curpos}, #{@buffer.length}. wi: #{@width}"
490
+ return if @curpos == 0 and @current_index == 0 # added 2009-10-04 23:02
491
+ repeatm {
492
+ if @curpos > 0
493
+ @curpos -= 1
494
+ addcol -1
495
+ else # trying this out 2008-12-26 20:18
496
+ ret = up
497
+ cursor_eol if ret != -1
498
+ end
499
+ }
500
+ end
501
+ # private
502
+ # when backspace pressed in position zero if the previous line is filled we may have to bring
503
+ # down the last word and join, rather than go up
504
+ # FIXME : make logic simple. Append entire line to above line. Then go to maxlen if not a space,
505
+ # reverse to find last space. Lop off all after space and replace this line with that balance.
506
+ # UNDO and REDO has to work in this case too. FIXME bare in mind handlers when doing this
507
+ def join_to_prev_line
508
+ return -1 unless @editable
509
+ return if @current_index == 0
510
+ oldcurpos = @curpos
511
+ oldprow = @current_index
512
+ prev = @list[@current_index-1].chomp
513
+ prevlen = prev.length
514
+ # 2008-12-26 21:37 delete previous line if nothing there. This moves entire buffer up.
515
+ if prevlen == 0
516
+ delete_line @current_index-1
517
+ up
518
+ return
519
+ end
520
+ _maxlen = @maxlen || @width - @internal_width
521
+ space_left = _maxlen - prevlen
522
+ # prev line is full exit
523
+ return if space_left == 0
524
+
525
+ # get last space, if none, return
526
+ blank_found = @buffer.rindex(' ', space_left)
527
+ return unless blank_found # no word in the space i can carry up.
528
+ # get string for carrying up
529
+ carry_up = @buffer[0..blank_found]
530
+ result = @list[@current_index-1].chomp! # this has to be undone too.
531
+ @list[@current_index-1] << carry_up
532
+ #$log.debug "carry up: #{carry_up} prevrow:#{@list[@current_index -1]}"
533
+ # remove from curr line
534
+ @list[@current_index].slice!(0..carry_up.length-1)
535
+ $log.debug "carry up: #{carry_up} currrow:#{@list[@current_index]}"
536
+ #@list[@current_index] ||= ""
537
+ up
538
+ addrowcol -1,0
539
+ @curpos = prevlen
540
+ # if result not nil, then we need that to be recorded FIXME
541
+ fire_handler :CHANGE, InputDataEvent.new(oldcurpos,oldcurpos+carry_up.length, self, :DELETE, oldprow, carry_up)
542
+ fire_handler :CHANGE, InputDataEvent.new(prevlen,prevlen+carry_up.length, self, :INSERT, oldprow-1, carry_up)
543
+
544
+ ## BUG. carry full words up, or if no space then bring down last word of prev lien and join with first
545
+ #carry_up = words_in_length @buffer, space_left #@buffer[0..space_left] # XXX
546
+ #if carry_up.nil?
547
+ ## carry down last word
548
+ #prev_wd = remove_last_word @current_index-1
549
+ ## 2010-01-14 18:26 check added else crashing if C-h pressed with no data in line
550
+ #if !prev_wd.nil?
551
+ #@buffer.insert 0, prev_wd
552
+ #@curpos = prev_wd.length
553
+ #$log.debug " carry up nil! prev_wd (#{prev_wd}) len:#{prev_wd.length}"
554
+ #fire_handler :CHANGE, InputDataEvent.new(0,prev_wd.length, self, :INSERT, oldprow, prev_wd) # 2008-12-26 23:07
555
+ #end
556
+ #else
557
+ #$log.debug " carrying up #{carry_up.length} #{carry_up}, space: #{space_left}"
558
+ #@list[@current_index-1]=prev + carry_up
559
+ #space_left2 = @buffer[(carry_up.length+1)..-1]
560
+ #@list[@current_index]=space_left2 #if !space_left2.nil?
561
+ #@list[@current_index] ||= ""
562
+ #up
563
+ #addrowcol -1,0
564
+ #@curpos = prevlen
565
+ #fire_handler :CHANGE, InputDataEvent.new(oldcurpos,carry_up.length, self, :DELETE, oldprow, carry_up) # 2008-12-24 18:34
566
+ #fire_handler :CHANGE, InputDataEvent.new(prevlen,carry_up.length, self, :INSERT, oldprow-1, carry_up) # 2008-12-24 18:34
567
+ #end
568
+ ## FIXME -- can;t have a naked for reference here.
569
+ ##@form.col = @orig_col + @col_offset + @curpos
570
+ col1 = @orig_col + @col_offset + @curpos
571
+ setrowcol nil, col1 # 2010-02-12 13:09 RFED16
572
+
573
+ # $log.debug "carry up: nil" if carry_up.nil?
574
+ # $log.debug "listrow nil " if @list[@current_index].nil?
575
+ # $log.debug "carry up: #{carry_up} prow:#{@list[@current_index]}"
576
+ end
577
+ # private
578
+ # when backspace pressed in position zero if the previous line is filled we may have to bring
579
+ # down the last word and join, rather than go up
580
+ # FIXME : make logic simple. Append entire line to above line. Then go to maxlen if not a space,
581
+ # reverse to find last space. Lop off all after space and replace this line with that balance.
582
+ # UNDO and REDO has to work in this case too. FIXME bare in mind handlers when doing this
583
+ def old_join_to_prev_line
584
+ return -1 unless @editable
585
+ return if @current_index == 0
586
+ oldcurpos = @curpos
587
+ oldprow = @current_index
588
+ prev = @list[@current_index-1].chomp
589
+ prevlen = prev.length
590
+ # 2008-12-26 21:37 delete previous line if nothing there. This moves entire buffer up.
591
+ if prevlen == 0
592
+ delete_line @current_index-1
593
+ up
594
+ return
595
+ end
596
+ _maxlen = @maxlen || @width - @internal_width
597
+ space_left = _maxlen - prev.length
598
+ # BUG. carry full words up, or if no space then bring down last word of prev lien and join with first
599
+ carry_up = words_in_length @buffer, space_left #@buffer[0..space_left] # XXX
600
+ if carry_up.nil?
601
+ # carry down last word
602
+ prev_wd = remove_last_word @current_index-1
603
+ # 2010-01-14 18:26 check added else crashing if C-h pressed with no data in line
604
+ if !prev_wd.nil?
605
+ @buffer.insert 0, prev_wd
606
+ @curpos = prev_wd.length
607
+ $log.debug " carry up nil! prev_wd (#{prev_wd}) len:#{prev_wd.length}"
608
+ fire_handler :CHANGE, InputDataEvent.new(0,prev_wd.length, self, :INSERT, oldprow, prev_wd) # 2008-12-26 23:07
609
+ end
610
+ else
611
+ $log.debug " carrying up #{carry_up.length} #{carry_up}, space: #{space_left}"
612
+ @list[@current_index-1]=prev + carry_up
613
+ space_left2 = @buffer[(carry_up.length+1)..-1]
614
+ @list[@current_index]=space_left2 #if !space_left2.nil?
615
+ @list[@current_index] ||= ""
616
+ up
617
+ addrowcol -1,0
618
+ @curpos = prevlen
619
+ fire_handler :CHANGE, InputDataEvent.new(oldcurpos,carry_up.length, self, :DELETE, oldprow, carry_up) # 2008-12-24 18:34
620
+ fire_handler :CHANGE, InputDataEvent.new(prevlen,carry_up.length, self, :INSERT, oldprow-1, carry_up) # 2008-12-24 18:34
621
+ end
622
+ # FIXME -- can;t have a naked for reference here.
623
+ #@form.col = @orig_col + @col_offset + @curpos
624
+ col1 = @orig_col + @col_offset + @curpos
625
+ setrowcol nil, col1 # 2010-02-12 13:09 RFED16
626
+
627
+ # $log.debug "carry up: nil" if carry_up.nil?
628
+ # $log.debug "listrow nil " if @list[@current_index].nil?
629
+ # $log.debug "carry up: #{carry_up} prow:#{@list[@current_index]}"
630
+ end
631
+ ##
632
+ # return as many words as fit into len for carrying up..
633
+ # actually there is a case of when the next char (len+1) is a white space or word boundary. XXX
634
+ def words_in_length buff, len
635
+ return nil if len == 0
636
+ str = buff[0..len]
637
+ ix = str.rindex(/\s/)
638
+ $log.debug " str #{str} len #{len} ix #{ix} , buff #{buff}~"
639
+ return nil if ix.nil?
640
+ ix = ix > 0 ? ix - 1 : ix
641
+ $log.debug " str[]:#{str[0..ix]}~ len #{len} ix #{ix} , buff #{buff}~"
642
+ return str[0..ix]
643
+ end
644
+ # push the last word from given line to next
645
+ # I have modified it to push all words that are exceeding maxlen.
646
+ # This was needed for if i push 10 chars to next line, and the last word is less then the line will
647
+ # exceed. So i must push as many words as exceed length.
648
+ # 2010-09-07 22:31 this must not return nil, or previous will crash. This happens if no space in line.
649
+ def push_last_word lineno=@current_index
650
+ _maxlen = @maxlen || @width - @internal_width
651
+ #lastspace = @buffer.rindex(" ")
652
+ #lastspace = @list[lineno].rindex(/ \w/)
653
+ line = @list[lineno]
654
+ line = @list[lineno][0.._maxlen+1] if line.length > _maxlen
655
+ lastspace = line.rindex(/ \w/)
656
+ $log.debug " PUSH:2 #{lastspace},#{line},"
657
+ # fix to ensure something returned 2010-09-07 22:40
658
+ lastspace = _maxlen-1 unless lastspace # added 2010-09-07 22:29 XXXX
659
+
660
+ if !lastspace.nil?
661
+ lastchars = @list[lineno][lastspace+1..-1]
662
+ @list[lineno] = @list[lineno][0..lastspace]
663
+ $log.debug "PUSH_LAST:ls:#{lastspace},lw:#{lastchars},lc:#{lastchars[-1]},:#{@list[lineno]}$"
664
+ if lastchars[-1,1] == "\r" or @list[lineno+1].nil?
665
+ # open a new line and keep the 10 at the end.
666
+ append_row lineno, lastchars
667
+ else
668
+ # check for soft tab \n - NO EVEN THIS LOGIC IS WRONG.
669
+ #if lastchars[-1,1] == "\n"
670
+ if lastchars[-1,1] != ' ' and @list[lineno+1][0,1] !=' '
671
+ #@list[lineno+1].insert 0, lastchars + ' '
672
+ insert_wrap lineno+1, 0, lastchars + ' '
673
+ else
674
+ #@list[lineno+1].insert 0, lastchars
675
+ insert_wrap lineno+1, 0, lastchars
676
+ end
677
+ end
678
+ return lastchars, lastspace
679
+ end
680
+ return nil
681
+ end
682
+ ##
683
+ # this attempts to recursively insert into a row, seeing that any stuff exceeding is pushed down further.
684
+ # Yes, it should check for a para end and insert. Currently it could add to next para.
685
+ def insert_wrap lineno, pos, lastchars
686
+ _maxlen = @maxlen || @width - @internal_width
687
+ @list[lineno].insert pos, lastchars
688
+ len = @list[lineno].length
689
+ if len > _maxlen
690
+ push_last_word lineno #- sometime i may push down 10 chars but the last word is less
691
+ end
692
+ end
693
+ ##
694
+ # add one char. careful, i shoved a string in yesterday.
695
+ def putch char
696
+ _maxlen = @maxlen || @width - @internal_width
697
+ @buffer ||= @list[@current_index]
698
+ return -1 if !@editable #or @buffer.length >= _maxlen
699
+ #if @chars_allowed != nil # remove useless functionality
700
+ #return if char.match(@chars_allowed).nil?
701
+ #end
702
+ raise "putch expects only one char" if char.length != 1
703
+ oldcurpos = @curpos
704
+ #$log.debug "putch : pr:#{@current_index}, cp:#{@curpos}, char:#{char}, lc:#{@buffer[-1]}, buf:(#{@buffer})"
705
+ if @overwrite_mode
706
+ @buffer[@curpos] = char
707
+ else
708
+ @buffer.insert(@curpos, char)
709
+ end
710
+ @curpos += 1
711
+ #$log.debug "putch INS: cp:#{@curpos}, max:#{_maxlen}, buf:(#{@buffer.length})"
712
+ if @curpos-1 > _maxlen or @buffer.length()-1 > _maxlen
713
+ lastchars, lastspace = push_last_word @current_index
714
+ #$log.debug "last sapce #{lastspace}, lastchars:#{lastchars},lc:#{lastchars[-1]}, #{@list[@current_index]} "
715
+ ## wrap on word XX If last char is 10 then insert line
716
+ @buffer = @list[@current_index]
717
+ if @curpos-1 > _maxlen or @curpos-1 > @buffer.length()-1
718
+ ret = down
719
+ # keep the cursor in the same position in the string that was pushed down.
720
+ @curpos = oldcurpos - lastspace #lastchars.length # 0
721
+ end
722
+ end
723
+ set_form_row
724
+ @buffer = @list[@current_index]
725
+ set_form_col
726
+ @modified = true
727
+ fire_handler :CHANGE, InputDataEvent.new(oldcurpos,@curpos, self, :INSERT, @current_index, char) # 2008-12-24 18:34
728
+ @repaint_required = true
729
+ 0
730
+ end
731
+ # removes and returns last word in given line number, or nil if no whitespace
732
+ def remove_last_word lineno
733
+ @list[lineno].chomp!
734
+ line=@list[lineno]
735
+ lastspace = line.rindex(" ")
736
+ if !lastspace.nil?
737
+ lastchars = line[lastspace+1..-1]
738
+ @list[lineno].slice!(lastspace..-1)
739
+ $log.debug " remove_last: lastspace #{lastspace},#{lastchars},#{@list[lineno]}"
740
+ fire_handler :CHANGE, InputDataEvent.new(lastspace,lastchars.length, self, :DELETE, lineno, lastchars) # 2008-12-26 23:06
741
+ return lastchars
742
+ end
743
+ return nil
744
+ end
745
+
746
+ def putc c
747
+ if c >= 32 and c <= 126
748
+ begin
749
+ ret = putch c.chr
750
+ rescue => ex
751
+ # this does not prevent entry, it prevents updating
752
+ # often comes here if error in event block, not our fault
753
+ Ncurses.beep
754
+ $log.debug " ERROR IN PUTCH RTEXTAREA "
755
+ $log.debug( ex) if ex
756
+ $log.debug(ex.backtrace.join("\n")) if ex
757
+ end
758
+ if ret == 0
759
+ # addcol 1
760
+ set_modified
761
+ return 0
762
+ end
763
+ end
764
+ return :UNHANDLED
765
+ end
766
+ # move up one char from next row to current, used when deleting in a line
767
+ # should not be called if line ends in "\r"
768
+ def move_char_up
769
+ @list[@current_index] << @list[@current_index+1].slice!(0)
770
+ delete_line(@current_index+1) if next_line().length==0
771
+ end
772
+ # tries to move up as many as possible
773
+ # should not be called if line ends in "\r"
774
+ def move_chars_up
775
+ oldprow = @current_index
776
+ oldcurpos = @curpos
777
+ _maxlen = @maxlen || @width - @internal_width
778
+ space_left = _maxlen - @buffer.length
779
+ can_move = [space_left, next_line.length].min
780
+ carry_up = @list[@current_index+1].slice!(0, can_move)
781
+ @list[@current_index] << carry_up
782
+ delete_line(@current_index+1) if next_line().length==0
783
+ fire_handler :CHANGE, InputDataEvent.new(oldcurpos,oldcurpos+can_move, self, :INSERT, oldprow, carry_up) # 2008-12-24 18:34
784
+ end
785
+ ## returns next line, does not move to it,
786
+ def next_line
787
+ @list[@current_index+1]
788
+ end
789
+ def current_line
790
+ @list[@current_index]
791
+ end
792
+ def do_relative_row num
793
+ yield @list[@current_index+num]
794
+ end
795
+ def set_modified tf=true
796
+ @modified = tf
797
+ @repaint_required = tf
798
+ @repaint_footer_required = tf
799
+ # 2010-01-14 22:45 putting a check for form, so not necessary to have form set when appending data
800
+ @form.modified = true if tf and !@form.nil?
801
+ end
802
+ def cursor_eol
803
+ _maxlen = @maxlen || @width - @internal_width
804
+ $log.error "ERROR !!! bufferlen gt _maxlen #{@buffer.length}, #{_maxlen}" if @buffer.length > _maxlen
805
+ set_form_col current_line().chomp().length() #-1 needs to be one ahead 2011-10-10 TRYING OUT XXX
806
+ end
807
+ def cursor_bol
808
+ set_form_col 0
809
+ end
810
+ #def to_s this was just annoying in debugs
811
+ def get_text
812
+ l = getvalue
813
+ str = ""
814
+ old = " "
815
+ l.each_with_index do |line, i|
816
+ tmp = line.gsub("\n","")
817
+ tmp.gsub!("\r", "\n")
818
+ if old[-1,1] !~ /\s/ and tmp[0,1] !~ /\s/
819
+ str << " "
820
+ end
821
+ str << tmp
822
+ old = tmp
823
+ end
824
+ str
825
+ end
826
+ #alias :get_text :to_s
827
+ ## ---- for listscrollable ---- ##
828
+ def scrollatrow
829
+ if @suppress_borders
830
+ @height - 1
831
+ else
832
+ @height - 3
833
+ end
834
+ end
835
+ def row_count
836
+ @list.size
837
+ end
838
+ def paint
839
+ # not sure where to put this, once for all or repeat 2010-02-12 RFED16
840
+ #my_win = @form? @form.window : @target_window
841
+ #$log.warn "neither form not target window given!!! TA paint 751" unless my_win
842
+ raise "Height or width nil h:#{@height} , w: #{@width} " if @height.nil? || @width.nil?
843
+ print_borders if (@suppress_borders == false && @repaint_all) # do this once only, unless everything changes
844
+ rc = row_count
845
+ _maxlen = @maxlen || @width-@internal_width # TODO fix in other branches remove ||=
846
+ $log.debug " #{@name} textarea repaint width is #{@width}, height is #{@height} , maxlen #{_maxlen}/ #{@maxlen}, #{@graphic.name} "
847
+ tm = get_content
848
+ tr = @toprow
849
+ acolor = get_color $datacolor
850
+ h = scrollatrow()
851
+ r,c = rowcol
852
+ @longest_line = @width # _maxlen scroll uses width not maxlen
853
+ $log.debug " TA:::: #{tr} , #{h}, r #{r} c #{c} "
854
+ 0.upto(h) do |hh|
855
+ crow = tr+hh
856
+ if crow < rc
857
+ #focussed = @current_index == crow ? true : false
858
+ #selected = is_row_selected crow
859
+ content = tm[crow].chomp rescue ""
860
+ content.gsub!(/\t/, ' ') # don't display tab
861
+ content.gsub!(/[^[:print:]]/, '') # don't display non print characters
862
+ if !content.nil?
863
+ if content.length > _maxlen # only show _maxlen
864
+ @longest_line = content.length if content.length > @longest_line
865
+ ## added nil check since we are allowing scrolling in listscrollable anyway 2013-03-06 - 00:14
866
+ content = content[@pcol..@pcol+_maxlen-1] || " "
867
+ else
868
+ ## added nil check since we are allowing scrolling in listscrollable anyway
869
+ content = content[@pcol..-1] || " "
870
+ end
871
+ end
872
+ #renderer = get_default_cell_renderer_for_class content.class.to_s
873
+ #renderer = cell_renderer()
874
+ #renderer.repaint @form.window, r+hh, c+(colix*11), content, focussed, selected
875
+ #renderer.repaint @form.window, r+hh, c, content, focussed, selected
876
+ @graphic.printstring r+hh, c, "%-*s" % [@width-@internal_width,content], acolor, @attr
877
+ if @search_found_ix == tr+hh
878
+ if !@find_offset.nil?
879
+ @graphic.mvchgat(y=r+hh, x=c+@find_offset, @find_offset1-@find_offset, Ncurses::A_NORMAL, $reversecolor, nil)
880
+ end
881
+ end
882
+
883
+ else
884
+ # clear rows
885
+ # TODO the spaces string can be stored once outside loop
886
+ @graphic.printstring r+hh, c, " " * (@width-@internal_width), acolor,@attr
887
+ end
888
+ end
889
+ show_caret_func
890
+
891
+ @table_changed = false
892
+ @repaint_required = false
893
+ @repaint_footer_required = true # 2010-01-23 22:41
894
+ @repaint_all = false # added 2010-01-14 for redrawing everything
895
+ end
896
+ def ask_search_forward
897
+ regex = get_string("Enter regex to search", 20, @last_regex||"")
898
+ ix = _find_next regex, @current_index
899
+ if ix.nil?
900
+ alert("No matching data for: #{regex}")
901
+ else
902
+ set_focus_on(ix)
903
+ set_form_col @find_offset
904
+ end
905
+ end
906
+ def undo
907
+ if @undo_handler
908
+ @undo_handler.undo
909
+ else
910
+ undo_delete
911
+ end
912
+ end
913
+ def text_redo
914
+ return unless @undo_handler
915
+ @undo_handler.redo
916
+ end
917
+
918
+ def edit_external
919
+ require 'rbhex/core/include/appmethods'
920
+ require 'tempfile'
921
+ f = Tempfile.new("rbhex")
922
+ l = self.text
923
+ l.each { |line| f.puts line }
924
+ fp = f.path
925
+ f.flush
926
+
927
+ editor = ENV['EDITOR'] || 'vi'
928
+ vimp = %x[which #{editor}].chomp
929
+ ret = shell_out "#{vimp} #{fp}"
930
+ if ret
931
+ lines = File.open(f,'r').readlines
932
+ set_content(lines, :content_type => @old_content_type)
933
+ end
934
+ end
935
+ def saveas name=nil, config={}
936
+ unless name
937
+ name = rb_gets "File to save as: "
938
+ return if name.nil? || name == ""
939
+ end
940
+ exists = File.exists? name
941
+ if exists # need to prompt
942
+ return unless rb_confirm("Overwrite existing file? ")
943
+ end
944
+ l = getvalue
945
+ File.open(name, "w"){ |f|
946
+ l.each { |line| f.puts line }
947
+ #l.each { |line| f.write line.gsub(/\r/,"\n") }
948
+ }
949
+ rb_puts "#{name} written."
950
+ end
951
+
952
+ def init_actions
953
+ editor = ENV['EDITOR'] || 'vi'
954
+ am = action_manager()
955
+ am.add_action(Action.new("&Edit in #{editor} ") { edit_external })
956
+ am.add_action(Action.new("&Saveas") { saveas() } )
957
+ end
958
+ end # class textarea
959
+ ##
960
+ end # modul