rbcurse-core 0.0.0

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