rbcurse-core 0.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.
Files changed (94) hide show
  1. data/README.md +69 -0
  2. data/VERSION +1 -0
  3. data/examples/abasiclist.rb +151 -0
  4. data/examples/alpmenu.rb +46 -0
  5. data/examples/app.sample +17 -0
  6. data/examples/atree.rb +100 -0
  7. data/examples/common/file.rb +45 -0
  8. data/examples/data/README.markdown +9 -0
  9. data/examples/data/brew.txt +38 -0
  10. data/examples/data/color.2 +37 -0
  11. data/examples/data/gemlist.txt +60 -0
  12. data/examples/data/lotr.txt +12 -0
  13. data/examples/data/ports.txt +136 -0
  14. data/examples/data/table.txt +37 -0
  15. data/examples/data/tasks.csv +88 -0
  16. data/examples/data/tasks.txt +27 -0
  17. data/examples/data/todo.txt +10 -0
  18. data/examples/data/todocsv.csv +28 -0
  19. data/examples/data/unix1.txt +21 -0
  20. data/examples/data/unix2.txt +11 -0
  21. data/examples/dbdemo.rb +487 -0
  22. data/examples/dirtree.rb +90 -0
  23. data/examples/newtabbedwindow.rb +100 -0
  24. data/examples/newtesttabp.rb +92 -0
  25. data/examples/tabular.rb +132 -0
  26. data/examples/tasks.rb +167 -0
  27. data/examples/term2.rb +83 -0
  28. data/examples/testkeypress.rb +72 -0
  29. data/examples/testlistbox.rb +158 -0
  30. data/examples/testmessagebox.rb +140 -0
  31. data/examples/testree.rb +106 -0
  32. data/examples/testwsshortcuts.rb +66 -0
  33. data/examples/testwsshortcuts2.rb +127 -0
  34. data/lib/rbcurse.rb +8 -0
  35. data/lib/rbcurse/core/docs/index.txt +73 -0
  36. data/lib/rbcurse/core/include/action.rb +40 -0
  37. data/lib/rbcurse/core/include/appmethods.rb +112 -0
  38. data/lib/rbcurse/core/include/bordertitle.rb +41 -0
  39. data/lib/rbcurse/core/include/chunk.rb +182 -0
  40. data/lib/rbcurse/core/include/io.rb +953 -0
  41. data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
  42. data/lib/rbcurse/core/include/listeditable.rb +317 -0
  43. data/lib/rbcurse/core/include/listscrollable.rb +590 -0
  44. data/lib/rbcurse/core/include/listselectable.rb +264 -0
  45. data/lib/rbcurse/core/include/multibuffer.rb +83 -0
  46. data/lib/rbcurse/core/include/orderedhash.rb +77 -0
  47. data/lib/rbcurse/core/include/ractionevent.rb +67 -0
  48. data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
  49. data/lib/rbcurse/core/include/rhistory.rb +62 -0
  50. data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
  51. data/lib/rbcurse/core/include/vieditable.rb +170 -0
  52. data/lib/rbcurse/core/system/colormap.rb +163 -0
  53. data/lib/rbcurse/core/system/keyboard.rb +150 -0
  54. data/lib/rbcurse/core/system/keydefs.rb +30 -0
  55. data/lib/rbcurse/core/system/ncurses.rb +218 -0
  56. data/lib/rbcurse/core/system/panel.rb +162 -0
  57. data/lib/rbcurse/core/system/window.rb +901 -0
  58. data/lib/rbcurse/core/util/ansiparser.rb +117 -0
  59. data/lib/rbcurse/core/util/app.rb +1235 -0
  60. data/lib/rbcurse/core/util/basestack.rb +407 -0
  61. data/lib/rbcurse/core/util/bottomline.rb +1850 -0
  62. data/lib/rbcurse/core/util/colorparser.rb +71 -0
  63. data/lib/rbcurse/core/util/focusmanager.rb +31 -0
  64. data/lib/rbcurse/core/util/padreader.rb +189 -0
  65. data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
  66. data/lib/rbcurse/core/util/rdialogs.rb +619 -0
  67. data/lib/rbcurse/core/util/viewer.rb +149 -0
  68. data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
  69. data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
  70. data/lib/rbcurse/core/widgets/box.rb +58 -0
  71. data/lib/rbcurse/core/widgets/divider.rb +310 -0
  72. data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
  73. data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
  74. data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
  75. data/lib/rbcurse/core/widgets/rlink.rb +30 -0
  76. data/lib/rbcurse/core/widgets/rlist.rb +723 -0
  77. data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
  78. data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
  79. data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
  80. data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
  81. data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
  82. data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
  83. data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
  84. data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
  85. data/lib/rbcurse/core/widgets/rtree.rb +787 -0
  86. data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
  87. data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
  88. data/lib/rbcurse/core/widgets/statusline.rb +94 -0
  89. data/lib/rbcurse/core/widgets/tabular.rb +264 -0
  90. data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
  91. data/lib/rbcurse/core/widgets/textpad.rb +516 -0
  92. data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
  93. data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
  94. metadata +156 -0
@@ -0,0 +1,901 @@
1
+ # ----------------------------------------------------------------------------- #
2
+ # File: window.rb
3
+ # Description: A wrapper over window
4
+ # Author: rkumar http://github.com/rkumar/rbcurse/
5
+ # Date: Around for a long time
6
+ # License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
7
+ # Last update: use ,,L
8
+ #
9
+ # == CHANGED
10
+ # removed Pad and Subwin to lib/ver/rpad.rb - hopefully I've seen the last of both
11
+ #
12
+ # == TODO
13
+ # strip and remove cruft. Now that I've stopped using pad, can we remove
14
+ # the prv_printstring nonsense.
15
+ # ----------------------------------------------------------------------------- #
16
+ #
17
+ require 'rbcurse/core/system/ncurses'
18
+ require 'rbcurse/core/system/panel'
19
+ require 'rbcurse/core/include/chunk'
20
+ # this is since often windows are declared with 0 height or width and this causes
21
+ # crashes in the most unlikely places. This prevceents me from having to write ternary
22
+ # e.g.
23
+ # @layout[:width].ifzero(FFI::NCurses::LINES-2)
24
+ class Fixnum
25
+ def ifzero v
26
+ return self if self != 0
27
+ return v
28
+ end
29
+ end
30
+
31
+ module VER
32
+ class Window
33
+ attr_reader :width, :height, :top, :left
34
+ attr_accessor :layout # hash containing hwtl
35
+ attr_reader :panel # reader requires so he can del it in end
36
+ attr_reader :window_type # window or pad to distinguish 2009-11-02 23:11
37
+ attr_accessor :name # more for debugging log files. 2010-02-02 19:58
38
+ attr_accessor :modified # has it been modified and may need a refresh
39
+ #attr_reader :bottomline # experimental here 2010-11-03 22:19
40
+
41
+ # @param [Array, Hash] window coordinates (ht, w, top, left)
42
+ # or
43
+ # @param [int, int, int, int] window coordinates (ht, w, top, left)
44
+ # 2011-09-21 allowing array, or 4 ints, in addition to hash @since 1.3.1
45
+ def initialize(*args)
46
+
47
+ case args.size
48
+ when 1
49
+ case args[0]
50
+ when Array, Hash
51
+ layout = args[0]
52
+ else
53
+ raise ArgumentError, "Window expects 4 ints, array of 4 ints, or Hash in constructor"
54
+ end
55
+ when 4
56
+ layout = { :height => args[0], :width => args[1], :top => args[2], :left => args[3] }
57
+ end
58
+
59
+ @visible = true
60
+ reset_layout(layout)
61
+
62
+ #$log.debug "XXX:WINDOW got h #{@height}, w #{@width}, t #{@top}, l #{@left} "
63
+
64
+ @height = FFI::NCurses.LINES if @height == 0 # 2011-11-14 added since tired of checking for zero
65
+ @width = FFI::NCurses.COLS if @width == 0
66
+
67
+ @window = FFI::NCurses.newwin(@height, @width, @top, @left) # added FFI 2011-09-6
68
+ @panel = Ncurses::Panel.new(@window) # added FFI 2011-09-6
69
+ #$error_message_row = $status_message_row = Ncurses.LINES-1
70
+ $error_message_row ||= Ncurses.LINES-1
71
+ $error_message_col ||= 1 # ask (bottomline) uses 0 as default so you can have mismatch. XXX
72
+ $status_message ||= RubyCurses::Variable.new # in case not an App
73
+ init_vars
74
+
75
+
76
+ end
77
+ def init_vars
78
+ @window_type = :WINDOW
79
+ Ncurses::keypad(@window, true)
80
+ @stack = []
81
+ @name ||="#{self}"
82
+ @modified = true
83
+ $catch_alt_digits ||= false # is this where is should put globals ? 2010-03-14 14:00 XXX
84
+ end
85
+ ##
86
+ # this is an alternative constructor
87
+ def self.root_window(layout = { :height => 0, :width => 0, :top => 0, :left => 0 })
88
+ #VER::start_ncurses
89
+ @layout = layout
90
+ @window = Window.new(@layout)
91
+ @window.name = "Window::ROOTW"
92
+ @window.wrefresh
93
+ Ncurses::Panel.update_panels
94
+ return @window
95
+ end
96
+ # 2009-10-13 12:24
97
+ # not used as yet
98
+ # this is an alternative constructor
99
+ # created if you don't want to create a hash first
100
+ # 2011-09-21 V1.3.1 You can now send an array to Window constructor
101
+ def self.create_window(h=0, w=0, t=0, l=0)
102
+ layout = { :height => h, :width => w, :top => t, :left => l }
103
+ @window = Window.new(layout)
104
+ return @window
105
+ end
106
+
107
+ def resize_with(layout)
108
+ $log.debug " DARN ! This awready duz a resize!! if h or w or even top or left changed!!! XXX"
109
+ reset_layout(layout)
110
+ #@window.wresize(height, width)
111
+ wresize(height, width)
112
+ #FFI::NCurses.wresize(@window,height, width)
113
+ # this is dicey since we often change top and left in pads only for panning !! XXX
114
+ #@window.mvwin(top, left)
115
+ mvwin(top, left)
116
+ #FFI::NCurses.mvwin(@window, top, left)
117
+ end
118
+
119
+ %w[width height top left].each do |side|
120
+ eval(
121
+ "def #{side}=(n)
122
+ return if n == #{side}
123
+ @layout[:#{side}] = n
124
+ resize_with @layout
125
+ end"
126
+ )
127
+ end
128
+ # ADDED DUE TO FFI
129
+ def wrefresh
130
+ Ncurses.wrefresh(@window)
131
+ end
132
+ def delwin # 2011-09-7
133
+ Ncurses.delwin(@window)
134
+ end
135
+ def attron *args
136
+ FFI::NCurses.wattron @window, *args
137
+ end
138
+ def attroff *args
139
+ FFI::NCurses.wattroff @window, *args
140
+ end
141
+ #
142
+ # ## END FFI
143
+
144
+ def resize
145
+ resize_with(@layout)
146
+ end
147
+
148
+ # Ncurses
149
+
150
+ def pos
151
+ return y, x
152
+ end
153
+
154
+ def y
155
+ Ncurses.getcury(@window)
156
+ end
157
+
158
+ def x
159
+ Ncurses.getcurx(@window)
160
+ end
161
+
162
+ def x=(n) move(y, n) end
163
+ def y=(n) move(n, x) end
164
+
165
+ #def move(y, x)
166
+ #return unless @visible
167
+ ## Log.debug([y, x] => caller[0,4])
168
+ ##@window.wmove(y, x) # bombing since ffi-ncurses 0.4.0 (maybe it was never called
169
+ ##earlier. was crashing in appemail.rb testchoose.
170
+ #wmove y,x # can alias it
171
+ #end
172
+ # since include FFI is taking over, i need to force it here. not going into
173
+ # method_missing
174
+ def wmove y,x
175
+ #Ncurses.wmove @window, y, x
176
+ FFI::NCurses.wmove @window, y, x
177
+ end
178
+ alias :move :wmove
179
+
180
+ # while moving from ncurses-ruby to FFI need to pass window pointer
181
+ # for w methods as well as mvw - NOT COMING HERE due to include FFI
182
+ def OLDmethod_missing(meth, *args)
183
+ $log.debug " WWWW method missing #{meth} "
184
+ if meth[0,1]=="w" || meth[0,3] == "mvw"
185
+ $log.debug " WWWW method missing #{meth} adding window in call "
186
+ #return @window.send(meth, @window, *args)
187
+ return FFI::NCurses.send(meth, @window, *args)
188
+ else
189
+ end
190
+ if @window
191
+ if @window.respond_to? meth
192
+ @window.send(meth, *args)
193
+ else
194
+ FFI::NCurses.send( meth, *args)
195
+ end
196
+ else
197
+ FFI::NCurses.send( meth, *args)
198
+ end
199
+ end
200
+
201
+ def method_missing(name, *args)
202
+ name = name.to_s
203
+ if (name[0,2] == "mv")
204
+ test_name = name.dup
205
+ test_name[2,0] = "w" # insert "w" after"mv"
206
+ if (FFI::NCurses.respond_to?(test_name))
207
+ return FFI::NCurses.send(test_name, @window, *args)
208
+ end
209
+ end
210
+ test_name = "w" + name
211
+ if (FFI::NCurses.respond_to?(test_name))
212
+ return FFI::NCurses.send(test_name, @window, *args)
213
+ end
214
+ FFI::NCurses.send(name, @window, *args)
215
+ end
216
+ def respond_to?(name)
217
+ name = name.to_s
218
+ if (name[0,2] == "mv" && FFI::NCurses.respond_to?("mvw" + name[2..-1]))
219
+ return true
220
+ end
221
+ FFI::NCurses.respond_to?("w" + name) || FFI::NCurses.respond_to?(name)
222
+ end
223
+
224
+ # NOTE: many of these methods using width will not work since root windows width
225
+ # is 0
226
+ def print(string, width = width)
227
+ return unless visible?
228
+ w = width == 0? Ncurses.COLS : width
229
+ waddnstr(string.to_s, w) # changed 2011 dts
230
+ end
231
+
232
+ # NOTE: many of these methods using width will not work since root windows width
233
+ # is 0
234
+ def print_yx(string, y = 0, x = 0)
235
+ w = width == 0? Ncurses.COLS : width
236
+ mvwaddnstr(y, x, string, w) # changed 2011 dts
237
+ end
238
+
239
+ # NOTE: many of these methods using width will not work since root windows width
240
+ # is 0
241
+ def print_empty_line
242
+ return unless visible?
243
+ w = width == 0? Ncurses.COLS : width
244
+ printw(' ' * w)
245
+ end
246
+
247
+ # NOTE: many of these methods using width will not work since root windows width
248
+ # is 0
249
+ def print_line(string)
250
+ w = width == 0? Ncurses.COLS : width
251
+ print(string.ljust(w))
252
+ end
253
+
254
+ # returns the actual width in case you've used a root window
255
+ # which returns a 0 for wid and ht
256
+ #
257
+ def actual_width
258
+ width == 0? Ncurses.COLS : width
259
+ end
260
+
261
+ #
262
+ # returns the actual ht in case you've used a root window
263
+ # which returns a 0 for wid and ht
264
+ #
265
+ def actual_height
266
+ height == 0? Ncurses.LINES : height
267
+ end
268
+
269
+ # NOTE: many of these methods using width will not work since root windows width
270
+ # is 0
271
+ # Previously this printed a chunk as a full line, I've modified it to print on
272
+ # one line. This can be used for running text.
273
+ def show_colored_chunks(chunks, defcolor = nil, defattr = nil)
274
+ return unless visible?
275
+ chunks.each do |chunk| #|color, chunk, attrib|
276
+ case chunk
277
+ when Chunks::Chunk
278
+ color = chunk.color
279
+ attrib = chunk.attrib
280
+ text = chunk.text
281
+ when Array
282
+ # for earlier demos that used an array
283
+ color = chunk[0]
284
+ attrib = chunk[2]
285
+ text = chunk[1]
286
+ end
287
+
288
+ color ||= defcolor
289
+ attrib ||= defattr
290
+
291
+ cc, bg = ColorMap.get_colors_for_pair color
292
+ $log.debug "XXX: CHUNK window #{text}, cp #{color} , attrib #{attrib}. #{cc}, #{bg} "
293
+ color_set(color,nil) if color
294
+ wattron(attrib) if attrib
295
+ print(text)
296
+ wattroff(attrib) if attrib
297
+ end
298
+ end
299
+
300
+ def puts(*strings)
301
+ print(strings.join("\n") << "\n")
302
+ end
303
+
304
+ def _refresh
305
+ return unless visible?
306
+ @window.refresh
307
+ end
308
+
309
+ def wnoutrefresh
310
+ return unless visible?
311
+ @window.wnoutrefresh
312
+ end
313
+
314
+ def color=(color)
315
+ @color = color
316
+ @window.color_set(color, nil)
317
+ end
318
+
319
+ def highlight_line(color, y, x, max)
320
+ @window.mvchgat(y, x, max, Ncurses::A_NORMAL, color, nil)
321
+ end
322
+
323
+ def ungetch(ch)
324
+ Ncurses.ungetch(ch)
325
+ end
326
+
327
+ def getch
328
+ #c = @window.getch
329
+ c = Ncurses.getch
330
+ #if c == Ncurses::KEY_RESIZE
331
+
332
+ rescue Interrupt => ex
333
+ 3 # is C-c
334
+ end
335
+
336
+ # 2011-09-23 @since 1.3.1
337
+ # Added more combinations here. These 2 are just indicative
338
+ SPECIAL_KEYS = {
339
+ [27, 79, 50, 81] => 20014, # 'F14',
340
+ [27, 79, 50, 82] => 20015 # 'F15',
341
+ }
342
+
343
+ # returns control, alt, alt+ctrl, alt+control+shift, F1 .. etc
344
+ # ALT combinations also send a 27 before the actual key
345
+ # Please test with above combinations before using on your terminal
346
+ # added by rkumar 2008-12-12 23:07
347
+ # 2011-09-23 Redone Control-left, right, and Shift-F5..F10.
348
+ # Checking for quick press of Alt-Sh-O followed by Alt or printable char
349
+ # Checking for quick press of Alt-[ followed by Alt or printable char
350
+ # I attempted keeping a hash of combination arrays but it fails in the above
351
+ # 2 cases, so abandoned.
352
+ def getchar
353
+ while 1
354
+ ch = getch
355
+ $log.debug "window getchar() GOT: #{ch}" if ch != -1
356
+ sf = @stack.first
357
+ if ch == -1
358
+ # the returns escape 27 if no key followed it, so its SLOW if you want only esc
359
+ if @stack.first == 27
360
+ #$log.debug " -1 stack sizze #{@stack.size}: #{@stack.inspect}, ch #{ch}"
361
+ case @stack.size
362
+ when 1
363
+ @stack.clear
364
+ return 27
365
+ when 2 # basically a ALT-O, or alt-[ (79 or 91) this will be really slow since it waits for -1
366
+ ch = 128 + @stack.last
367
+ $log.warn "XXX: WARN #{ch} CLEARING stack #{@stack} "
368
+ @stack.clear
369
+ return ch
370
+ else
371
+ # check up a hash of special keys
372
+ ret = SPECIAL_KEYS(@stack)
373
+ return ret if ret
374
+ $log.warn "INVALID UNKNOWN KEY: SHOULD NOT COME HERE getchar():#{@stack}"
375
+ end
376
+ end
377
+ # possibly a 49 left over from M3-1
378
+ unless @stack.empty?
379
+ if @stack.size == 1
380
+ @stack.clear
381
+ return sf
382
+ end
383
+ $log.warn "something on stack getchar(): #{@stack} "
384
+ end
385
+ # comemnt after testing keys since this will be called a lot, even stack.clear is called a lot
386
+ $log.warn "ERROR CLEARING STACK WITH STUFF ON IT getchar():#{@stack}" if ($log.debug? && !@stack.empty?)
387
+ @stack.clear
388
+ next
389
+ end # -1
390
+ # this is the ALT combination
391
+ if @stack.first == 27
392
+ # experimental. 2 escapes in quick succession to make exit faster
393
+ if @stack.size == 1 && ch == 27
394
+ @stack.clear
395
+ return ch
396
+ end
397
+ # possible F1..F3 on xterm-color
398
+ if ch == 79 || ch == 91
399
+ #$log.debug " got 27, #{ch}, waiting for one more"
400
+ @stack << ch
401
+ next
402
+ end
403
+ #$log.debug "stack SIZE #{@stack.size}, #{@stack.inspect}, ch: #{ch}"
404
+ if @stack == [27,79]
405
+ # xterm-color
406
+ case ch
407
+ when 80
408
+ ch = FFI::NCurses::KEY_F1
409
+ when 81
410
+ ch = FFI::NCurses::KEY_F2
411
+ when 82
412
+ ch = FFI::NCurses::KEY_F3
413
+ when 83
414
+ ch = FFI::NCurses::KEY_F4
415
+ #when 27 # another alt-char following Alt-Sh-O
416
+ else
417
+ ## iterm2 uses these for HOME END num keyboard keys
418
+ @stack.clear
419
+ #@stack << ch # earlier we pushed this but it could be of use
420
+ #return 128 + 79
421
+ return 128 + 79 + ch
422
+
423
+ end
424
+ @stack.clear
425
+ return ch
426
+ elsif @stack == [27, 91]
427
+ # XXX 27, 91 also is Alt-[
428
+ if ch == 90
429
+ @stack.clear
430
+ return KEY_BTAB # backtab
431
+ elsif ch == 53 || ch == 50 || ch == 51
432
+ # control left, right and shift function
433
+ @stack << ch
434
+ next
435
+ elsif ch == 27 # another alt-char immediately after Alt-[
436
+ $log.debug "getchar in 27, will return 128+91 " if $log.debug?
437
+ @stack.clear
438
+ @stack << ch
439
+ return 128 + 91
440
+ else
441
+ $log.debug "getchar in other, will return 128+91: #{ch} " if $log.debug?
442
+ # other cases Alt-[ followed by some char or key - merge with previous
443
+ @stack.clear
444
+ @stack << ch
445
+ return 128 + 91
446
+ end
447
+ elsif @stack == [27, 91, 53]
448
+ if ch == 68
449
+ @stack.clear
450
+ return C_LEFT # control-left
451
+ elsif ch == 67
452
+ @stack.clear
453
+ return C_RIGHT # -control-rt
454
+ end
455
+ elsif @stack == [27, 91, 51]
456
+ if ch == 49 && getch()== 126
457
+ @stack.clear
458
+ return 20009 # sh_f9
459
+ end
460
+ elsif @stack == [27, 91, 50]
461
+ if ch == 50 && getch()== 126
462
+ @stack.clear
463
+ return 20010 # sh-F10
464
+ end
465
+ if ch == 57 && getch()== 126
466
+ @stack.clear
467
+ return 20008 # sh-F8
468
+ elsif ch == 56 && getch()== 126
469
+ @stack.clear
470
+ return 20007 # sh-F7
471
+ elsif ch == 54 && getch()== 126
472
+ @stack.clear
473
+ return 20006 # sh-F6
474
+ elsif ch == 53 && getch()== 126
475
+ @stack.clear
476
+ return 20005 # sh-F5
477
+ end
478
+ end
479
+ # the usual Meta combos. (alt) - this is screwing it up, just return it in some way
480
+ ch = 128 + ch
481
+ @stack.clear
482
+ return ch
483
+ end # stack.first == 27
484
+ # append a 27 to stack, actually one can use a flag too
485
+ if ch == 27
486
+ @stack << 27
487
+ next
488
+ end
489
+ return ch
490
+ end # while
491
+ end # def
492
+
493
+ # doesn't seem to work, clears first line, not both
494
+ def clear
495
+ # return unless visible?
496
+ move 0, 0
497
+ puts *Array.new(height){ ' ' * (width - 1) }
498
+ end
499
+
500
+ # setup and reset
501
+
502
+ ## allow user to send an array
503
+ # I am tired of the hash layout (taken from ver).
504
+ def reset_layout(layout)
505
+ case layout
506
+ when Array
507
+ $log.error "NIL in window constructor" if layout.include? nil
508
+ raise ArgumentError, "Nil in window constructor" if layout.include? nil
509
+ @height, @width, @top, @left = *layout
510
+ raise ArgumentError, "Nil in window constructor" if @top.nil? || @left.nil?
511
+
512
+ @layout = { :height => @height, :width => @width, :top => @top, :left => @top }
513
+ when Hash
514
+ @layout = layout
515
+
516
+ [:height, :width, :top, :left].each do |name|
517
+ instance_variable_set("@#{name}", layout_value(name))
518
+ end
519
+ end
520
+ end
521
+
522
+ # removed ref to default_for since giving error in FFI 2011-09-8
523
+ def layout_value(name)
524
+ value = @layout[name]
525
+ default = default_for(name)
526
+
527
+ value = value.call(default) if value.respond_to?(:call)
528
+ return (value || default).to_i
529
+ end
530
+
531
+ # this gives error since stdscr is only a pointer at this time
532
+ def default_for(name)
533
+ case name
534
+ when :height, :top
535
+ #Ncurses.stdscr.getmaxy(stdscr)
536
+ FFI::NCurses.LINES
537
+ when :width, :left
538
+ #Ncurses.stdscr.getmaxx(stdscr)
539
+ FFI::NCurses.COLS
540
+ else
541
+ 0
542
+ end
543
+ end
544
+
545
+ # Ncurses panel
546
+
547
+ def hide
548
+ #return unless visible? # added 2011-10-14 these 2 are not behaving properly
549
+ Ncurses::Panel.hide_panel @panel.pointer
550
+ #Ncurses.refresh # wnoutrefresh
551
+ Ncurses::Panel.update_panels # added so below window does not need to do this 2011-10-1
552
+ @visible = false
553
+ end
554
+
555
+ def show
556
+ #return if visible? # added 2011-10-14 these 2 are not behaving properly
557
+ Ncurses::Panel.show_panel @panel.pointer
558
+ #Ncurses.refresh # wnoutrefresh
559
+ Ncurses::Panel.update_panels # added so below window does not need to do this 2011-10-1
560
+ @visible = true
561
+ end
562
+
563
+ def on_top
564
+ Ncurses::Panel.top_panel @panel.pointer
565
+ wnoutrefresh
566
+ end
567
+
568
+ def visible?
569
+ @visible
570
+ end
571
+
572
+ ##
573
+ # destroy window, panel and any pads that were requested
574
+ #
575
+ def destroy
576
+ # typically the ensure block should have this
577
+
578
+ $log.debug "win destroy start"
579
+
580
+ Ncurses::Panel.del_panel(@panel.pointer) if @panel
581
+ delwin() if @window
582
+ Ncurses::Panel.update_panels # added so below window does not need to do this 2011-10-1
583
+
584
+ # destroy any pads that were created by widgets using get_pad
585
+ @pads.each { |pad|
586
+ FFI::NCurses.delwin(pad) if pad
587
+ pad = nil
588
+ } if @pads
589
+ $log.debug "win destroy end"
590
+ end
591
+
592
+ #
593
+ # 2011-11-13 since 1.4.1
594
+ # Widgets can get window to create a pad for them. This way when the window
595
+ # is destroyed, it will delete all the pads. A widget wold not be able to do this.
596
+ # The destroy method of the widget will be called.
597
+ def get_pad content_row, content_cols
598
+ pad = FFI::NCurses.newpad(content_rows, content_cols)
599
+ @pads ||= []
600
+ @pads << pad
601
+ end
602
+
603
+ #
604
+ # Allows user to send data as normal string or chunks for printing
605
+ # An array is assumed to be a chunk containing color and attrib info
606
+ #
607
+ def printstring_or_chunks(r,c,content, color, att = Ncurses::A_NORMAL)
608
+ if content.is_a? String
609
+ printstring(r,c,content, color, att)
610
+ elsif content.is_a? Chunks::ChunkLine
611
+ $log.debug "XXX: using chunkline"
612
+ wmove r, c
613
+ a = get_attrib att
614
+ show_colored_chunks content, color, a
615
+ elsif content.is_a? Array
616
+ # several chunks in one row - NOTE Very experimental may change
617
+ if content[0].is_a? Array
618
+ $log.warn "XXX: WARNING outdated should send in a chunkline"
619
+ wmove r, c
620
+ a = get_attrib att
621
+ show_colored_chunks content, color, a
622
+ else
623
+ # a single row chunk - NOTE Very experimental may change
624
+ text = content[1].dup
625
+ printstring r, c, text, content[0] || color, content[2] || att
626
+ end
627
+ end
628
+ end
629
+ #
630
+ # prints a string formatted in our new experimental coloring format
631
+ # taken from tmux. Currently, since i have chunks workings, i convert
632
+ # to chunks and use the existing print function. This could change.
633
+ # An example of a formatted string is:
634
+ # s="#[fg=green]testing chunks #[fg=yellow, bg=red, bold]yellow #[reverse] reverseme \
635
+ # #[normal]normal#[bg = black]just yellow#[fg=blue],blue now #[underline] underlined text"
636
+ # Ideally I should push and pop colors which the shell does not do with ansi terminal sequences.
637
+ # That way i can have a line in red,
638
+ # with some word in yellow, and then the line continues in red.
639
+ #
640
+ def printstring_formatted(r,c,content, color, att = Ncurses::A_NORMAL)
641
+ att = get_attrib att unless att.is_a? Fixnum
642
+ chunkline = convert_to_chunk(content, color, att)
643
+ printstring_or_chunks r,c, chunkline, color, att
644
+ end # print
645
+ #
646
+ # print a formatted line right aligned
647
+ # c (col) is ignored and calculated based on width and unformatted string length
648
+ #
649
+ def printstring_formatted_right(r,c,content, color, att = Ncurses::A_NORMAL)
650
+ clean = content.gsub /#\[[^\]]*\]/,'' # clean out all markup
651
+ c = actual_width() - clean.length
652
+ printstring_formatted(r,c,content, color, att )
653
+ end
654
+
655
+ private
656
+ def get_default_color_parser
657
+ require 'rbcurse/core/util/colorparser'
658
+ @color_parser || DefaultColorParser.new
659
+ end
660
+ # supply with a color parser, if you supplied formatted text
661
+ public
662
+ def color_parser f
663
+ $log.debug "XXX: color_parser setting in window to #{f} "
664
+ if f == :tmux
665
+ @color_parser = get_default_color_parser()
666
+ else
667
+ @color_parser = f
668
+ end
669
+ end
670
+ #
671
+ # Takes a formatted string and converts the parsed parts to chunks.
672
+ #
673
+ # @param [String] takes the entire line or string and breaks into an array of chunks
674
+ # @yield chunk if block
675
+ # @return [ChunkLine] # [Array] array of chunks
676
+ # @since 1.4.1 2011-11-3 experimental, can change
677
+ public
678
+ def convert_to_chunk s, colorp=$datacolor, att=FFI::NCurses::A_NORMAL
679
+ unless @color_parser
680
+ @color_parser = get_default_color_parser()
681
+ @converter = Chunks::ColorParser.new @color_parser
682
+ end
683
+ @converter.convert_to_chunk s, colorp, att
684
+ end
685
+
686
+ ##
687
+ # prints a string at row, col, with given color and attribute
688
+ # added by rk 2008-11-29 19:01
689
+ # I usually use this, not the others ones here
690
+ # @param r - row
691
+ # @param c - col
692
+ # @param string - text to print
693
+ # @param color - color pair
694
+ # @ param att - ncurses attribute: normal, bold, reverse, blink,
695
+ # underline
696
+ public
697
+ def printstring(r,c,string, color, att = Ncurses::A_NORMAL)
698
+ raise "Nil passed to peintstring row:#{r}, col:#{c}, #{color} " if r.nil? || c.nil? || color.nil?
699
+ #raise "Zero or less passed to printstring row:#{r}, col:#{c} " if $log.debug? && (r <=0 || c <=0)
700
+ prv_printstring(r,c,string, color, att )
701
+ end
702
+
703
+ ## name changed from printstring to prv_prinstring
704
+ def prv_printstring(r,c,string, color, att = Ncurses::A_NORMAL)
705
+
706
+ #$log.debug " #{@name} inside window printstring r #{r} c #{c} #{string} "
707
+ if att.nil?
708
+ att = Ncurses::A_NORMAL
709
+ else
710
+ att = get_attrib att
711
+ end
712
+ #att = att.downcase.to_sym if att.is_a? String
713
+ #case att
714
+ #when :normal
715
+ #att = Ncurses::A_NORMAL
716
+ #when :underline
717
+ #att = Ncurses::A_UNDERLINE
718
+ #when :bold
719
+ #att = Ncurses::A_BOLD
720
+ #when :reverse
721
+ #att = Ncurses::A_REVERSE
722
+ #when :dim
723
+ #att = Ncurses::A_DIM
724
+ #when :blink
725
+ #att = Ncurses::A_BLINK # unlikely to work
726
+ #end
727
+
728
+ wattron(Ncurses.COLOR_PAIR(color) | att)
729
+ mvwprintw(r, c, "%s", :string, string);
730
+ wattroff(Ncurses.COLOR_PAIR(color) | att)
731
+ end
732
+ # @deprecated
733
+ def print_error_message text=$error_message.get_value
734
+ alert text
735
+ end
736
+ # added by rk 2008-11-29 19:01
737
+ # @deprecated. use global method of same name in rdialog
738
+ def print_status_message text=$status_message
739
+ #VER::print_status_message text
740
+ alert text
741
+ end
742
+ # added by rk 2008-11-29 19:01
743
+ # Since these methods write directly to window they are not advised
744
+ # since clearing previous message we don't know how much to clear.
745
+ # Best to map error_message to a label.
746
+ # 2010-09-13 00:22 WE should not use these any longer.
747
+ # Application should create a label and map a Variable named
748
+ # $errormessage to it. We should only update the Variable
749
+ def DEPRECATED_print_error_message text=$error_message.get_value
750
+ r = $error_message_row || Ncurses.LINES-1
751
+ c = $error_message_col || (Ncurses.COLS-text.length)/2
752
+
753
+ $log.debug "got ERROR MESSAGE #{text} row #{r} "
754
+ clear_error r, $datacolor
755
+ printstring r, c, text, color = $promptcolor
756
+ $error_message_clear_pending = true
757
+ end
758
+ # added by rk 2008-11-29 19:01
759
+ # @deprecated. use global method of same name
760
+ def DEPRECATED_print_status_message text=$status_message
761
+ r = $status_message_row || Ncurses.LINES-1
762
+ clear_error r, $datacolor
763
+ # print it in centre
764
+ printstring r, (Ncurses.COLS-text.length)/2, text, color = $promptcolor
765
+ end
766
+ # Clear error message printed
767
+ # I am not only clearing if something was printed. This is since
768
+ # certain small forms like TabbedForm top form throw an error on printstring.
769
+ # @deprecated
770
+ def clear_error r = $error_message_row, color = $datacolor
771
+ return unless $error_message_clear_pending
772
+ c = $error_message_col || (Ncurses.COLS-text.length)/2
773
+ sz = $error_message_size || Ncurses.COLS
774
+ printstring(r, c, "%-*s" % [sz, " "], color)
775
+ $error_message_clear_pending = false
776
+ end
777
+ ##
778
+ # NOTE : FOR MESSAGEBOXES ONLY !!!!
779
+ def print_border_mb row, col, height, width, color, attr
780
+ # the next is for xterm-256
781
+ att = get_attrib attr
782
+ len = width
783
+ len = Ncurses.COLS-0 if len == 0
784
+ # print a bar across the screen
785
+ #attron(Ncurses.COLOR_PAIR(color) | att)
786
+ # this works for newmessagebox but not for old one.
787
+ # Even now in some cases some black shows through, if the widget is printing spaces
788
+ # such as field or textview on a messagebox.
789
+ (row-1).upto(row+height-1) do |r|
790
+ mvwhline(r, col, 1, len)
791
+ end
792
+ #attroff(Ncurses.COLOR_PAIR(color) | att)
793
+
794
+ mvwaddch row, col, Ncurses::ACS_ULCORNER
795
+ mvwhline( row, col+1, Ncurses::ACS_HLINE, width-6)
796
+ mvwaddch row, col+width-5, Ncurses::ACS_URCORNER
797
+ mvwvline( row+1, col, Ncurses::ACS_VLINE, height-4)
798
+
799
+ mvwaddch row+height-3, col, Ncurses::ACS_LLCORNER
800
+ mvwhline(row+height-3, col+1, Ncurses::ACS_HLINE, width-6)
801
+ mvwaddch row+height-3, col+width-5, Ncurses::ACS_LRCORNER
802
+ mvwvline( row+1, col+width-5, Ncurses::ACS_VLINE, height-4)
803
+ end
804
+ ##
805
+ # prints a border around a widget, CLEARING the area.
806
+ # If calling with a pad, you would typically use 0,0, h-1, w-1.
807
+ def print_border row, col, height, width, color, att=Ncurses::A_NORMAL
808
+ raise "height needs to be supplied." if height.nil?
809
+ raise "width needs to be supplied." if width.nil?
810
+ att ||= Ncurses::A_NORMAL
811
+
812
+ $log.debug " inside window print_border r #{row} c #{col} h #{height} w #{width} "
813
+
814
+ # 2009-11-02 00:45 made att nil for blanking out
815
+ # FIXME - in tabbedpanes this clears one previous line ??? XXX when using a textarea/view
816
+ # when using a pad this calls pads printstring which again reduces top and left !!! 2010-01-26 23:53
817
+ ww=width-2
818
+ (row+1).upto(row+height-1) do |r|
819
+ prv_printstring( r, col+1," "*ww , color, att)
820
+ end
821
+ prv_print_border_only row, col, height, width, color, att
822
+ end
823
+ def print_border_only row, col, height, width, color, att=Ncurses::A_NORMAL
824
+ prv_print_border_only row, col, height, width, color, att
825
+ end
826
+
827
+
828
+ ## print just the border, no cleanup
829
+ #+ Earlier, we would clean up. Now in some cases, i'd like
830
+ #+ to print border over what's been done.
831
+ # XXX this reduces 1 from width but not height !!! FIXME
832
+ def prv_print_border_only row, col, height, width, color, att=Ncurses::A_NORMAL
833
+ if att.nil?
834
+ att = Ncurses::A_NORMAL
835
+ else
836
+ att = get_attrib att
837
+ end
838
+ wattron(Ncurses.COLOR_PAIR(color) | att)
839
+ mvwaddch row, col, Ncurses::ACS_ULCORNER
840
+ mvwhline( row, col+1, Ncurses::ACS_HLINE, width-2)
841
+ mvwaddch row, col+width-1, Ncurses::ACS_URCORNER
842
+ mvwvline( row+1, col, Ncurses::ACS_VLINE, height-1)
843
+
844
+ mvwaddch row+height-0, col, Ncurses::ACS_LLCORNER
845
+ mvwhline(row+height-0, col+1, Ncurses::ACS_HLINE, width-2)
846
+ mvwaddch row+height-0, col+width-1, Ncurses::ACS_LRCORNER
847
+ mvwvline( row+1, col+width-1, Ncurses::ACS_VLINE, height-1)
848
+ wattroff(Ncurses.COLOR_PAIR(color) | att)
849
+ end
850
+ # This used to return an Ncurses window object, and you could call methods on it
851
+ # Now it returns a FFI::NCurses.window pointer which you cannot call methods on.
852
+ # You have to pass it to FFI::NCurses.<method>
853
+ def get_window; @window; end
854
+ def to_s; @name || self; end
855
+ # use in place of mvwhline if your widget could be using a pad or window
856
+ def rb_mvwhline row, col, char, width
857
+ mvwhline row, col, char, width
858
+ end
859
+ # use in place of mvwvline if your widget could be using a pad or window
860
+ def rb_mvwvline row, col, char, width
861
+ mvwvline row, col, char, width
862
+ end
863
+ # use in place of mvaddch if your widget could be using a pad or window
864
+ def rb_mvaddch row, col, char
865
+ mvaddch row, col, char
866
+ end
867
+ def close_command *args, &block
868
+ @close_command ||= []
869
+ @close_args ||= []
870
+ @close_command << block
871
+ @close_args << args
872
+ end
873
+ alias :command :close_command
874
+
875
+ # set a single command to confirm whether window shoud close or not
876
+ # Block should return true or false for closing or not
877
+ def confirm_close_command *args, &block
878
+ @confirm_close_command = block
879
+ @confirm_close_args = args
880
+ end
881
+
882
+ # need a way of lettign user decide whether he wishes to close
883
+ # in which case we return false. However, there could be several commands
884
+ # mapped. how do we know which is the one that has this authority
885
+ def fire_close_handler
886
+ if @confirm_close_command
887
+ comm = @confirm_close_command
888
+ ret = comm.call(self, *@confirm_close_args)
889
+ return ret unless ret # only return if false returned
890
+ end
891
+ if @close_command
892
+ @close_command.each_with_index do |comm, ix|
893
+ comm.call(self, *@close_args[ix]) if comm
894
+ end
895
+ end
896
+ @close_command = nil
897
+ @close_args = nil
898
+ return true
899
+ end
900
+ end
901
+ end