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,41 @@
1
+ # I am moving the common title and border printing stuff into
2
+ # a separate module.
3
+ module BorderTitle
4
+ dsl_accessor :suppress_borders #to_print_borders
5
+ dsl_accessor :border_attrib, :border_color
6
+ dsl_accessor :title #set this on top
7
+ dsl_accessor :title_attrib #bold, reverse, normal
8
+ dsl_accessor :border_attrib, :border_color #
9
+
10
+ def bordertitle_init
11
+ @row_offset = @col_offset = 0 if @suppress_borders
12
+ @internal_width = 1 if @suppress_borders
13
+ end
14
+ # why the dash does it reduce height by one.
15
+ def print_borders
16
+ raise ArgumentError, "Graphic not set" unless @graphic
17
+ width = @width
18
+ height = @height-1
19
+ window = @graphic
20
+ startcol = @col
21
+ startrow = @row
22
+ @color_pair = get_color($datacolor)
23
+ bordercolor = @border_color || @color_pair
24
+ borderatt = @border_attrib || Ncurses::A_NORMAL
25
+ window.print_border startrow, startcol, height, width, bordercolor, borderatt
26
+ print_title
27
+ end
28
+ def print_title
29
+ return unless @title
30
+ raise "#{self} needs width" unless @width
31
+ @color_pair ||= get_color($datacolor) # should we not use this ??? XXX
32
+ #$log.debug " print_title #{@row}, #{@col}, #{@width} "
33
+ # check title.length and truncate if exceeds width
34
+ _title = @title
35
+ if @title.length > @width - 2
36
+ _title = @title[0..@width-2]
37
+ end
38
+ @graphic.printstring( @row, @col+(@width-_title.length)/2, _title, @color_pair, @title_attrib) unless @title.nil?
39
+ end
40
+
41
+ end
@@ -0,0 +1,182 @@
1
+ # ------------------------------------------------------------ #
2
+ # File: chunk.rb
3
+ # Description:
4
+ # Author: rkumar http://github.com/rkumar/rbcurse/
5
+ # Date: 07.11.11 - 12:31
6
+ # Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
7
+ # Last update: use ,,L
8
+ # ------------------------------------------------------------ #
9
+ #
10
+
11
+ module Chunks
12
+ extend self
13
+ class Chunk
14
+
15
+ # color_pair of associated text
16
+ # text to print
17
+ # attribute of associated text
18
+ #attr_accessor :color, :text, :attrib
19
+ attr_reader :chunk
20
+
21
+ def initialize color, text, attrib
22
+ @chunk = [ color, text, attrib ]
23
+ #@color = color
24
+ #@text = text
25
+ #@attrib = attrib
26
+ end
27
+ def color
28
+ @chunk[0]
29
+ end
30
+ def text
31
+ @chunk[1]
32
+ end
33
+ def attrib
34
+ @chunk[2]
35
+ end
36
+ end
37
+
38
+ # consists of an array of chunks and corresponds to a line
39
+ # to be printed.
40
+ class ChunkLine
41
+
42
+ # an array of chunks
43
+ attr_reader :chunks
44
+
45
+ def initialize arr=nil
46
+ @chunks = arr.nil? ? Array.new : arr
47
+ end
48
+ def <<(chunk)
49
+ raise ArgumentError, "Chunk object expected. Received #{chunk.class} " unless chunk.is_a? Chunk
50
+ @chunks << chunk
51
+ end
52
+ alias :add :<<
53
+ def each &block
54
+ @chunks.each &block
55
+ end
56
+
57
+ # returns length of text in chunks
58
+ def row_length
59
+ result = 0
60
+ @chunks.each { |e| result += e.text.length }
61
+ return result
62
+ end
63
+ alias :length :row_length
64
+ alias :size :row_length
65
+
66
+ # return a Chunkline containing only the text for the range requested
67
+ def substring start, size
68
+ end
69
+ def to_s
70
+ result = ""
71
+ @chunks.each { |e| result << e.text }
72
+ result
73
+ end
74
+ end
75
+ class ColorParser
76
+ def initialize cp
77
+ color_parser cp
78
+ @color_pair = $datacolor
79
+ @attrib = FFI::NCurses::A_NORMAL
80
+ @color_array = [:white]
81
+ @bgcolor_array = [:black]
82
+ @attrib_array = [@attrib]
83
+ @color_pair_array = [@color_pair]
84
+ @color = :white
85
+ @bgcolor = :black
86
+ end
87
+ #
88
+ # Takes a formatted string and converts the parsed parts to chunks.
89
+ #
90
+ # @param [String] takes the entire line or string and breaks into an array of chunks
91
+ # @yield chunk if block
92
+ # @return [ChunkLine] # [Array] array of chunks
93
+ # @since 1.4.1 2011-11-3 experimental, can change
94
+ public
95
+ def convert_to_chunk s, colorp=$datacolor, att=FFI::NCurses::A_NORMAL
96
+ #require 'rbcurse/core/include/chunk'
97
+
98
+ @color_parser ||= get_default_color_parser()
99
+ ## defaults
100
+ color_pair = @color_pair
101
+ attrib = @attrib
102
+ #res = []
103
+ res = ChunkLine.new
104
+ color = @color
105
+ bgcolor = @bgcolor
106
+ # stack the values, so when user issues "/end" we can pop earlier ones
107
+
108
+ @color_parser.parse_format(s) do |p|
109
+ case p
110
+ when Array
111
+ ## got color / attrib info, this starts a new span
112
+
113
+ #color, bgcolor, attrib = *p
114
+ lc, lb, la = *p
115
+ if la
116
+ @attrib = get_attrib la
117
+ end
118
+ if lc || lb
119
+ @color = lc ? lc : @color_array.last
120
+ @bgcolor = lb ? lb : @bgcolor_array.last
121
+ @color_array << @color
122
+ @bgcolor_array << @bgcolor
123
+ @color_pair = get_color($datacolor, @color, @bgcolor)
124
+ end
125
+ @color_pair_array << @color_pair
126
+ @attrib_array << @attrib
127
+ #$log.debug "XXX: CHUNK start #{color_pair} , #{attrib} :: c:#{lc} b:#{lb} "
128
+ #$log.debug "XXX: CHUNK start arr #{@color_pair_array} :: #{@attrib_array} "
129
+
130
+ when :endcolor
131
+
132
+ # end the current (last) span
133
+ @color_pair_array.pop
134
+ @color_pair = @color_pair_array.last
135
+ @attrib_array.pop
136
+ @attrib = @attrib_array.last
137
+ #$log.debug "XXX: CHUNK end #{color_pair} , #{attrib} "
138
+ #$log.debug "XXX: CHUNK end arr #{@color_pair_array} :: #{@attrib_array} "
139
+ when :reset # ansi has this
140
+ # end all previous colors
141
+ @color_pair = $datacolor # @color_pair_array.first
142
+ @color_pair_array = [@color_pair]
143
+ @attrib = FFI::NCurses::A_NORMAL #@attrib_array.first
144
+ @attrib_array = [@attrib]
145
+ @bgcolor_array = [@bgcolor_array.first]
146
+ @color_array = [@color_array.first]
147
+
148
+ when String
149
+
150
+ ## create the chunk
151
+ $log.debug "XXX: CHUNK using on #{p} : #{@color_pair} , #{@attrib} "
152
+
153
+ #chunk = [color_pair, p, attrib]
154
+ chunk = Chunk.new @color_pair, p, @attrib
155
+ if block_given?
156
+ yield chunk
157
+ else
158
+ res << chunk
159
+ end
160
+ end
161
+ end # parse
162
+ return res unless block_given?
163
+ end
164
+ def get_default_color_parser
165
+ require 'rbcurse/core/util/colorparser'
166
+ @color_parser || DefaultColorParser.new
167
+ end
168
+ # supply with a color parser, if you supplied formatted text
169
+ public
170
+ def color_parser f
171
+ $log.debug "XXX: color_parser setting in CP to #{f} "
172
+ if f == :tmux
173
+ @color_parser = get_default_color_parser()
174
+ elsif f == :ansi
175
+ require 'rbcurse/core/util/ansiparser'
176
+ @color_parser = AnsiParser.new
177
+ else
178
+ @color_parser = f
179
+ end
180
+ end
181
+ end # class
182
+ end
@@ -0,0 +1,953 @@
1
+ #*******************************************************
2
+ # Some common io routines for getting data or putting
3
+ # at some point
4
+ # Arunachalesha
5
+ # 2010-03-06 12:10
6
+ # Some are outdated.
7
+ # Current are:
8
+ # * rbgetstr (and those it calls)
9
+ # * display_cmenu and create_mitem
10
+ #*******************************************************#
11
+ ##
12
+ # added RK 2010-11-02 18:11 so can be used in widgets too
13
+ # maybe can be removed from app, if accessible there too.
14
+ require 'forwardable'
15
+ require 'rbcurse/core/util/bottomline'
16
+ #$terminal = RubyCurses::Bottomline.new
17
+ #$terminal.name = "$terminal io.rb"
18
+ #module Kernel
19
+ #extend Forwardable
20
+ #def_delegators :$terminal, :agree, :ask, :choose, :say
21
+ #end
22
+ #$tt.window = @window; $tt.message_row = @message_row # <<-- TODO somewhere
23
+ module Io
24
+
25
+ # from which line to print in footer_win
26
+ LINEONE = 1
27
+ FOOTER_COLOR_PAIR = 6
28
+ MAIN_WINDOW_COLOR_PAIR = 5
29
+ ERROR_COLOR_PAIR = 7
30
+
31
+
32
+ def __create_footer_window h = 2 , w = Ncurses.COLS, t = Ncurses.LINES-2, l = 0
33
+ ewin = VER::Window.new(h, w , t, l)
34
+ end
35
+ # complex version of get_string that allows for trappng of control character
36
+ # such as C-c and C-h and TAB for completion
37
+ # validints contains int codes not chars.
38
+ # NOTE: change. C-g was help key in alpine but abort key in emacs. C-c sometimes
39
+ # crashes app, so i am using C-g as abort. Help on M-h
40
+ # TODO We should put a field there, make it visible and mv it to after the prompt
41
+ # and handle all editing events on it.
42
+ # @return status_code, string (0 if okay, 7 if help asked for, -1 for abort
43
+ #def rbgetstr(win, r, c, prompt, maxlen, default, labels, validints=[], helptext="")
44
+ # 2011-11-27 I have replaced the getting of chars with a field
45
+ # Still need to handle tab-completion, can do that with horizlist !! YEAHHH !!!
46
+ def rbgetstr(nolongerused, r, c, prompt, maxlen, config={})
47
+ begin
48
+ win = __create_footer_window
49
+ form = Form.new win
50
+ r = 0; c = 1;
51
+ default = config[:default] || ""
52
+ displen = config[:display_length] || maxlen
53
+ prompt = "#{prompt} [#{default}]: " unless default
54
+ field = Field.new form, :row => r, :col => c, :maxlen => maxlen, :default => default, :label => prompt,
55
+ :display_length => displen
56
+ #require 'rbcurse/core/include/rhistory'
57
+ #field.extend(FieldHistory)
58
+ #field.history_config :row => FFI::NCurses.LINES-12
59
+ #field.history %w[ jim john jack ruby jane jill just testing ]
60
+ form.repaint
61
+ win.wrefresh
62
+ prevchar = 0
63
+ entries = nil
64
+ while ((ch = win.getchar()) != 999)
65
+ break if ch == 10 || ch == 13
66
+ return -1, nil if ch == ?\C-c.getbyte(0) || ch == ?\C-g.getbyte(0)
67
+ #if ch == ?\M-h.getbyte(0) # HELP KEY
68
+ #helptext = config[:helptext] || "No help provided"
69
+ #color = $datacolor
70
+ #print_help(win, r, c, color, helptext)
71
+ ## this will come over our text
72
+ #end
73
+ # TODO tab completion and help_text print on F1
74
+ # that field objects can extend, same for tab completion and gmail completion
75
+ if ch == KEY_TAB
76
+ if config
77
+ str = field.text
78
+ if prevchar == 9
79
+ if !entries.nil? && !entries.empty?
80
+ str = entries.delete_at(0)
81
+ end
82
+ else
83
+ tabc = config[:tab_completion] unless tabc
84
+ next unless tabc
85
+ entries = tabc.call(str)
86
+ $log.debug " tab got #{entries} "
87
+ str = entries.delete_at(0) unless entries.nil? || entries.empty?
88
+ end
89
+ if str
90
+ field.text = str
91
+ field.set_form_col # shit why are we doign this, text sets curpos to 0
92
+ end
93
+ form.repaint
94
+ win.wrefresh
95
+ end
96
+
97
+ # tab_completion
98
+ # if previous char was not tab, execute tab_completion_proc and push first entry
99
+ # else push the next entry
100
+ elsif ch == KEY_F1
101
+ helptext = config[:helptext] || "No help provided. C-c/C-g aborts. <TAB> completion. Alt-h history. C-a/e"
102
+ print_status_message helptext
103
+ end
104
+ prevchar = ch
105
+ form.handle_key ch
106
+ win.wrefresh
107
+ end
108
+ rescue => err
109
+ Ncurses.beep
110
+ $log.error "EXP in rbgetsr #{err} "
111
+ $log.error(err.backtrace.join("\n"))
112
+ ensure
113
+ win.destroy if win
114
+ end
115
+ return 0, field.text
116
+ end
117
+ def originalrbgetstr(nolongerused, r, c, prompt, maxlen, config={})
118
+ #win ||= @target_window
119
+ win = __create_footer_window
120
+ $log.debug " inside io.rb rbgetstr #{win} r:#{r} c:#{c} p:#{prompt} m:#{maxlen} #{win.name} "
121
+ r = 0; c = 1;
122
+ ins_mode = false
123
+ default = config[:default] || ""
124
+ prompt = "#{prompt} [#{default}]: " unless default
125
+ len = prompt.length
126
+
127
+ # clear the area of len+maxlen
128
+ color = $datacolor
129
+ str = default
130
+ #clear_this win, r, c, color, len+maxlen+1
131
+ print_this(win, prompt+str, color, r, c)
132
+ len = prompt.length + str.length
133
+ #x mylabels=["^G~Help ", "^C~Cancel"]
134
+ #x mylabels += labels if !labels.nil?
135
+ begin
136
+ Ncurses.noecho(); # FFI RK 2011-09-11 seems this was causing issue of writing on top
137
+ #x print_key_labels( 0, 0, mylabels)
138
+ #curpos = 0
139
+ curpos = str.length
140
+ prevchar = 0
141
+ entries = nil
142
+ #win.mvwgetnstr(LINEONE-3,askstr.length,yn,maxlen)
143
+ while true
144
+ #ch=win.mvwgetch(r, len) # get to right of prompt - WHY NOT WORKING ???
145
+ ch=win.getchar()
146
+ $log.debug "io.rb rbgetstr got ch:#{ch}, #{win} , str:#{str}, len: #{len} "
147
+ case ch
148
+ when 3 # -1 # C-c
149
+ return -1, nil
150
+ when ?\C-g.getbyte(0) # ABORT
151
+ return -1, nil
152
+ when 10, 13 # hits ENTER
153
+ break
154
+ when ?\C-h.getbyte(0), ?\C-?.getbyte(0), KEY_BSPACE, 263 # delete previous character/backspace
155
+ # currently hitting C-h is giving 263 instead of 8
156
+ len -= 1 if len > prompt.length
157
+ curpos -= 1 if curpos > 0
158
+ str.slice!(curpos)
159
+ clear_this win, r, c, color, len+maxlen+1
160
+ #print_this(win, prompt+str, color, r, c)
161
+ when 330 # delete character on cursor
162
+ #len -= 1 if len > prompt.length
163
+ #curpos -= 1 if curpos > 0
164
+ str.slice!(curpos) #rescue next
165
+ clear_this win, r, c, color, len+maxlen+1
166
+ when ?\M-h.getbyte(0) # HELP KEY
167
+ #x print_footer_help(helptext)
168
+ helptext = config[:helptext] || "No help provided"
169
+ print_help(win, r, c, color, helptext)
170
+ return 7, nil
171
+ when KEY_LEFT
172
+ curpos -= 1 if curpos > 0
173
+ len -= 1 if len > prompt.length
174
+ win.wmove r, c+len # since getchar is not going back on del and bs
175
+ win.wrefresh # FFI 2011-09-19 otherwise not showing
176
+ next
177
+ when KEY_RIGHT
178
+ if curpos < str.length
179
+ curpos += 1 #if curpos < str.length
180
+ len += 1
181
+ win.wmove r, c+len # since getchar is not going back on del and bs
182
+ win.wrefresh # FFI 2011-09-19 otherwise not showing
183
+ end
184
+ next
185
+ when ?\C-a.getbyte(0)
186
+ #olen = str.length
187
+ #clear_this win, r, c, color, len+maxlen+1
188
+ #clear_line len+maxlen+1, @prompt_length
189
+ len -= curpos
190
+ curpos = 0
191
+ win.move r, c+len # since getchar is not going back on del and bs
192
+ win.wrefresh # FFI 2011-09-19 otherwise not showing
193
+ when ?\C-e.getbyte(0)
194
+ olen = str.length
195
+ len += (olen - curpos)
196
+ curpos = olen
197
+ #clear_line len+maxlen+1, @prompt_length
198
+ win.move r, c+len # since getchar is not going back on del and bs
199
+ win.wrefresh # FFI 2011-09-19 otherwise not showing
200
+ when ?\M-i.getbyte(0)
201
+ ins_mode = !ins_mode
202
+ next
203
+ when KEY_TAB # TAB
204
+ # this is where we can use the horizlist !!! TODO when he tabs !!!
205
+ if config
206
+ if prevchar == 9
207
+ if !entries.nil? and !entries.empty?
208
+ str = entries.delete_at(0)
209
+ end
210
+ else
211
+ tabc = config[:tab_completion] unless tabc
212
+ next unless tabc
213
+ entries = tabc.call(str)
214
+ $log.debug " tab got #{entries} "
215
+ str = entries.delete_at(0) unless entries.nil? or entries.empty?
216
+ end
217
+ end
218
+ else
219
+ #if validints.include?ch
220
+ #print_status("Found in validints")
221
+ #return ch, nil
222
+ #else
223
+ if ch < 0 || ch > 255
224
+ Ncurses.beep
225
+ next
226
+ end
227
+ # if control char, beep
228
+ if ch.chr =~ /[[:cntrl:]]/
229
+ Ncurses.beep
230
+ next
231
+ end
232
+ # we need to trap KEY_LEFT and RIGHT and what of UP for history ?
233
+ #end
234
+ #str << ch.chr
235
+ if ins_mode
236
+ str[curpos] = ch.chr
237
+ else
238
+ str.insert(curpos, ch.chr)
239
+ end
240
+ len += 1
241
+ curpos += 1
242
+ break if str.length > maxlen
243
+ end
244
+ print_this(win, prompt+str, color, r, c)
245
+ win.wmove r, c+len # more for arrow keys, curpos may not be end
246
+ win.wrefresh
247
+ prevchar = ch
248
+ end
249
+ str = default if str == ""
250
+ ensure
251
+ Ncurses.noecho();
252
+ win.destroy # now that we created a window 2011-11-26
253
+ #x restore_application_key_labels # must be done after using print_key_labels
254
+ end
255
+ return 0, str
256
+ end
257
+
258
+ # This is just experimental, trying out tab_completion
259
+ # Prompt user for a file name, allowing him to tab to complete filenames
260
+ # @param [String] label to print before field
261
+ # @param [Fixnum] max length of field
262
+ # @return [String] filename or blank if user cancelled
263
+ def get_file prompt, maxlen=70 #:nodoc:
264
+ tabc = Proc.new {|str| Dir.glob(str +"*") }
265
+ config={}; config[:tab_completion] = tabc
266
+ config[:default] = "test"
267
+ ret, str = rbgetstr(nil,0,0, prompt, maxlen, config)
268
+ #$log.debug " get_file returned #{ret} , #{str} "
269
+ return "" if ret != 0
270
+ return str
271
+ end
272
+ def clear_this win, r, c, color, len
273
+ print_this(win, "%-*s" % [len," "], color, r, c)
274
+ end
275
+ def print_help(win, r, c, color, helptext)
276
+ print_this(win, "%-*s" % [helptext.length+2," "], color, r, c)
277
+ print_this(win, "%s" % helptext, color, r, c)
278
+ sleep(5)
279
+ end
280
+ # @table_width is a constant in caller based on which we decide where to show
281
+ # key_labels and error messages.
282
+ # WHEN WE CREATE A PANEL BWLOW we can do away wit that. FIXME XXX
283
+ # return true for y, false for n
284
+ # e.g.
285
+ # <code>
286
+ # ret = @main.askyesno(nil, "Are you sure you wish to proceed?")
287
+ # </code>
288
+ # 2008-10-09 18:27 added call to print_footer_help
289
+ def askyesno(win, askstr, default = "N", helptext="Helptext for this question")
290
+ win ||= @footer_win
291
+ askstr = "#{askstr} [#{default}]: "
292
+ len = askstr.length
293
+
294
+ clear_error # 2008-10-13 20:26
295
+ print_this(win, askstr, 4, LINEONE, 0)
296
+ labels=["?~Help "," ~ ", "N~No ", "Y~Yes "]
297
+ print_key_labels( 0, 0, labels)
298
+ win.refresh
299
+ #Ncurses.echo();
300
+ yn=''
301
+ #win.mvwgetnstr(Ncurses.LINES-3,askstr.length,yn,maxlen)
302
+ while true
303
+ ch=win.mvwgetch(LINEONE,askstr.length)
304
+ if ch < 0 || ch > 255
305
+ next
306
+ end
307
+ yn = ch.chr
308
+ yn = default if yn == '' or ch == 10 # KEY_ENTER
309
+ yn.downcase!
310
+ break if yn =~/[yn]/
311
+ if yn == '?'
312
+ print_footer_help(helptext)
313
+ print_key_labels( 0, 0, labels)
314
+ next
315
+ end
316
+ Ncurses.beep
317
+ end
318
+ #Ncurses.noecho();
319
+ clear_error # 2008-11-06 19:27
320
+ restore_application_key_labels # must be done after using print_key_labels
321
+ win.refresh
322
+ return yn == 'y'
323
+ end
324
+
325
+ # return y or n or c
326
+
327
+ def askyesnocancel(win, askstr, default = "N")
328
+ win ||= @footer_win
329
+ askstr = "#{askstr} [#{default}]: "
330
+ len = askstr.length
331
+
332
+ clear_error # 2008-10-13 20:26
333
+ print_this(win, askstr, 4, LINEONE, 0)
334
+ labels=["N~No ", "Y~Yes ","C~Cancel"," ~ "]
335
+ print_key_labels( 0, 0, labels)
336
+ win.refresh
337
+ yn=''
338
+ #win.mvwgetnstr(LINEONE,askstr.length,yn,maxlen)
339
+ while true
340
+ ch=win.mvwgetch(LINEONE,askstr.length)
341
+ yn = ch.chr
342
+ yn = default if yn == '' or ch == 10 # KEY_ENTER
343
+ yn.downcase!
344
+ break if yn =~/[ync]/
345
+ Ncurses.beep
346
+ end
347
+ restore_application_key_labels # must be done after using print_key_labels
348
+ return yn
349
+ end
350
+
351
+ # return single digit from given choices
352
+ # e.g.
353
+ # <code>
354
+ # labels=["N~No ", "Y~Yes ","C~Cancel"," ~ ","S~SurpiseMe","G~GoAway! "]
355
+ # ret = @main.askchoice(nil, "Are you sure you wish to proceed?","N",labels,"NYCSG")
356
+ # @main.clear_error
357
+ # </code>
358
+
359
+ def askchoice(win, askstr, default, labels, validchars, config={})
360
+ win ||= @footer_win
361
+ askstr = "#{askstr} [#{default}]: "
362
+ len = askstr.length
363
+ helptext = config.fetch("helptext", "No helptext provided for this action")
364
+
365
+ clear_error # 2008-10-13 20:26
366
+ print_this(win, askstr, 4, LINEONE, 0)
367
+ #labels=["N~No ", "Y~Yes ","C~Cancel"," ~ "]
368
+ print_key_labels( 0, 0, labels)
369
+ yn=''
370
+ validchars.downcase!
371
+ #win.mvwgetnstr(LINEONE-3,askstr.length,yn,maxlen)
372
+ while true
373
+ ch=win.mvwgetch(LINEONE,askstr.length)
374
+ yn = ch.chr
375
+ # 2008-10-31 18:08
376
+ if ch == ?\C-g or yn == '?'
377
+ print_footer_help(helptext)
378
+ print_key_labels( 0, 0, labels)
379
+ next
380
+ end
381
+ yn = default if yn == '' or ch == 10 # KEY_ENTER
382
+ yn.downcase!
383
+ break if validchars.include?yn
384
+ Ncurses.beep
385
+ end
386
+ restore_application_key_labels # must be done after using print_key_labels
387
+ return yn
388
+ end
389
+ def get_string(win, askstr, maxlen=20, default="", labels=nil )
390
+ win ||= @footer_win
391
+ askstr = "#{askstr} [#{default}]: "
392
+ len = askstr.length
393
+
394
+ clear_error # 2008-11-06 19:25
395
+ print_this(win, askstr, 4, LINEONE, 0)
396
+ #labels=["N~No ", "Y~Yes ","C~Cancel"," ~ "]
397
+ mylabels = ["^G~Help ", "^C~Cancel"]
398
+ mylabels = (mylabels + labels) if !labels.nil?
399
+
400
+ print_key_labels( 0, 0, mylabels)
401
+ Ncurses.echo();
402
+ yn=''
403
+ begin
404
+ Signal.trap("INT"){ return nil }
405
+ win.mvwgetnstr(LINEONE,askstr.length,yn,maxlen)
406
+ rescue
407
+ yn=''
408
+ ensure
409
+ Ncurses.noecho();
410
+ clear_error # 2008-11-02 11:51
411
+ restore_application_key_labels # must be done after using print_key_labels
412
+ end
413
+ yn = default if yn == "" # 2008-10-31 18:59
414
+ return yn
415
+ end
416
+
417
+
418
+ ##
419
+ # prints given text to window, in color at x and y coordinates
420
+ # @param [Window] window to write to
421
+ # @param [String] text to print
422
+ # @param [int] color pair such as $datacolor or $promptcolor
423
+ # @param [int] x row
424
+ # @param [int] y col
425
+ # @see Window#printstring
426
+ # Consider using Window#printstring
427
+ def print_this(win, text, color, x, y)
428
+ if !win
429
+ raise "win nil in print_this"
430
+ end
431
+ #$log.debug " printthis #{win} , #{text} , #{x} , #{y} "
432
+ color=Ncurses.COLOR_PAIR(color);
433
+ win.attron(color);
434
+ #win.mvprintw(x, y, "%-40s" % text);
435
+ win.mvprintw(x, y, "%s" % text);
436
+ win.attroff(color);
437
+ win.refresh
438
+ end
439
+ # prints error in footer_win only
440
+ def print_error(text)
441
+ clear_error
442
+ print_in_middle(@footer_win, LINEONE, 10, 80, text, Ncurses.COLOR_PAIR(ERROR_COLOR_PAIR))
443
+ end
444
+ # prints status in footer_win only
445
+ def print_status(text)
446
+ text = text[text.length-80..-1] if text.length > 80
447
+ print_error(text)
448
+ end
449
+ # clear previous error, call inside getch loop after each ch.
450
+ def clear_error
451
+ print_this(@footer_win, "%-*s" % [Ncurses.COLS," "], 5, LINEONE, 0)
452
+ end
453
+ # This is only for the menu program, in which we print current action/menu string in the
454
+ # key labels below.
455
+ # Its a dirty hack edpending on:
456
+ # * String CurRow present in key labels
457
+ # * field_init_proc called this method to set it.
458
+ def print_action(text)
459
+ print_this(@footer_win, " %-10s" % ("["+text+"]"), FOOTER_COLOR_PAIR, @action_posy, @action_posx)
460
+ end
461
+
462
+ # the old historical program which prints a string in middle of whereever
463
+ # thanks to this i was using stdscr which must never be used
464
+
465
+ def print_in_middle(win, starty, startx, width, string, color)
466
+ if(win == nil)
467
+ raise "window is nil"
468
+ end
469
+ x = Array.new
470
+ y = Array.new
471
+ Ncurses.getyx(win, y, x);
472
+ if(startx != 0)
473
+ x[0] = startx;
474
+ end
475
+ if(starty != 0)
476
+ y[0] = starty;
477
+ end
478
+ if(width == 0)
479
+ width = 80;
480
+ end
481
+ length = string.length;
482
+ temp = (width - length)/ 2;
483
+ x[0] = startx + temp.floor;
484
+ win.attron(color);
485
+ win.mvprintw(y[0], x[0], "%s", string);
486
+ win.attroff(color);
487
+ win.refresh();
488
+ end
489
+ # splits that bad hack array into even and odd arrays
490
+ # and prints on last 2 lines
491
+
492
+ def print_key_labels(posy, posx, arr)
493
+ ## paint so-called key bindings from key_labels
494
+ posx = 0
495
+ even = []
496
+ odd = []
497
+ arr.each_index { |i|
498
+ if i % 2 == 0
499
+ even << arr[i]
500
+ else
501
+ odd << arr[i]
502
+ end
503
+ }
504
+ posy = LINEONE+1
505
+ print_key_labels_row(posy, posx, even)
506
+ posy = LINEONE+2
507
+ print_key_labels_row(posy, posx, odd)
508
+ # 2008-09-29 21:58
509
+ @footer_win.wrefresh # needed else secod row not shown after askchoice XXX
510
+ end
511
+
512
+ def print_key_labels_row(posy, posx, arr)
513
+ #clear first
514
+ my_form_win = @footer_win
515
+ # first clear the line
516
+ print_this(my_form_win, "%-*s" % [Ncurses.COLS," "], FOOTER_COLOR_PAIR, posy, 0)
517
+ padding = 8
518
+ padding = 4 if arr.length > 5
519
+ padding = 0 if arr.length > 7
520
+ arr.each_index { |i|
521
+ kl = arr[i].split('~')
522
+ if kl[0].strip !="" # don't print that white blank space for fillers
523
+ color_pair=2
524
+ my_form_win.attron(Ncurses.COLOR_PAIR(color_pair))
525
+ my_form_win.mvprintw(posy, posx, "%s" % kl[0] );
526
+ my_form_win.attroff(Ncurses.COLOR_PAIR(color_pair))
527
+ end
528
+ color_pair=FOOTER_COLOR_PAIR
529
+ posx = posx + kl[0].length
530
+ my_form_win.attron(Ncurses.COLOR_PAIR(color_pair))
531
+ lab = sprintf(" %s %*s" , kl[1], padding, " ");
532
+ # hack
533
+ if kl[1].strip == "CurRow"
534
+ @action_posx = posx
535
+ @action_posy = posy
536
+ end
537
+ my_form_win.mvprintw(posy, posx, lab)
538
+ my_form_win.attroff(Ncurses.COLOR_PAIR(color_pair))
539
+ posx = posx + lab.length
540
+ }
541
+ end
542
+
543
+ # since it must always be @header_win, we should remove the first param
544
+ # why should user have any direct access to those 2 windows.
545
+ def old_print_header(win, htext, posy = 0, posx = 0)
546
+ win.attron(Ncurses.COLOR_PAIR(6))
547
+ win.mvprintw(posy, posx, "%-*s" % [Ncurses.COLS, htext] );
548
+ win.attroff(Ncurses.COLOR_PAIR(6))
549
+ end
550
+ def print_header(htext, posy = 0, posx = 0)
551
+ win = @header_win
552
+ win.attron(Ncurses.COLOR_PAIR(6))
553
+ win.mvprintw(posy, posx, "%-*s" % [Ncurses.COLS, htext] );
554
+ win.attroff(Ncurses.COLOR_PAIR(6))
555
+ end
556
+
557
+ # since it must always be @header_win, we should remove the first param
558
+ # why should user have any direct access to those 2 windows.
559
+ def old_print_top_right(win, htext)
560
+ hlen = htext.length
561
+ win.attron(Ncurses.COLOR_PAIR(6))
562
+ win.mvprintw(0, Ncurses.COLS-hlen, htext );
563
+ win.attroff(Ncurses.COLOR_PAIR(6))
564
+ #win.refresh
565
+ end
566
+ def print_top_right(htext)
567
+ hlen = htext.length
568
+ win = @header_win
569
+ win.attron(Ncurses.COLOR_PAIR(6))
570
+ win.mvprintw(0, Ncurses.COLS-hlen, htext );
571
+ win.attroff(Ncurses.COLOR_PAIR(6))
572
+ #win.refresh
573
+ end
574
+ # prints labels defined by user in the DSL.
575
+ #
576
+ # Array of labels with:
577
+ #
578
+ # * position = [y,x] i.e, row, column
579
+ # * text = "label text"
580
+ # * color_pair = 6 (optional, default 6)
581
+
582
+ def print_screen_labels(my_form_win, labelarr)
583
+ table_width = @table_width || Ncurses.LINES-1
584
+ return if labelarr.nil?
585
+ labelarr.each{ |lhash|
586
+ posy, posx = lhash["position"]
587
+ posy = table_width + posy if posy < 0
588
+ posx = Ncurses.COLS + posy if posx < 0
589
+
590
+ text = lhash["text"]
591
+ color_pair = lhash["color_pair"] || 6
592
+ my_form_win.attron(Ncurses.COLOR_PAIR(color_pair))
593
+ my_form_win.mvprintw(posy, posx, "%-s" % text );
594
+ my_form_win.attroff(Ncurses.COLOR_PAIR(color_pair))
595
+ }
596
+ end
597
+
598
+ @deprecated
599
+ def print_headers(form_hash)
600
+ header = form_hash["header"]
601
+ header_top_left = form_hash["header_top_left"] || ""
602
+ header_top_center = form_hash["header_top_center"] || ""
603
+ header_top_right = form_hash["header_top_right"] || ""
604
+ posy = 0
605
+ posx = 0
606
+ htext = " <APP NAME> <VERSION> MAIN MENU"
607
+
608
+ posy, posx, htext = header if !header.nil?
609
+ print_header(htext + " %15s " % header_top_left + " %20s" % header_top_center , posy, posx)
610
+ print_top_right(header_top_right)
611
+ @header_win.wrefresh();
612
+ end
613
+
614
+
615
+ # 2008-10-09 18:27 askyesno and ask_string can be passed some text
616
+ # to be popped up when a user enters ?
617
+ @deprecated
618
+ def print_footer_help(helptext)
619
+ print_this(@footer_win, "%-*s" % [Ncurses.COLS," "], 6, LINEONE+1, 0)
620
+ print_this(@footer_win, "%-*s" % [Ncurses.COLS," "], 6, LINEONE+2, 0)
621
+ print_this(@footer_win, "%s" % helptext, 6, LINEONE+1, 0)
622
+ sleep(5)
623
+ end
624
+ def print_help_page(filename = "TODO")
625
+ #require 'panelreader' obsolete used FORN and fiELD
626
+ #tp = PanelReader.new()
627
+ #tp.view_file(filename)
628
+
629
+ end
630
+ #def newaskyesno(win, askstr, default = "N", helptext="Helptext for this question")
631
+ ##
632
+ # user may pass in actions for each key along with other config values in config hash.
633
+ # config can contain default, helptext, labels and 'y', 'n'
634
+ @deprecated
635
+ def newaskyesno(win, askstr, config = {})
636
+ win ||= @footer_win
637
+ default = config.fetch("default", "N")
638
+ helptext = config.fetch("helptext", "This is helptext for this action")
639
+ askstr = "#{askstr} [#{default}]: "
640
+ len = askstr.length
641
+
642
+ clear_error # 2008-10-13 20:26
643
+ print_this(win, askstr, 4, LINEONE, 0)
644
+ labels=config.fetch("labels", ["?~Help "," ~ ", "N~No ", "Y~Yes "])
645
+ print_key_labels( 0, 0, labels)
646
+ win.refresh
647
+ yn=''
648
+ #win.mvwgetnstr(Ncurses.LINES-3,askstr.length,yn,maxlen)
649
+ while true
650
+ ch=win.mvwgetch(LINEONE,askstr.length)
651
+ if ch < 0 || ch > 255
652
+ next
653
+ end
654
+ yn = ch.chr
655
+ yn = default if yn == '' or ch == 10 # KEY_ENTER
656
+ yn.downcase!
657
+ break if yn =~/[yn]/
658
+ if yn == '?'
659
+ print_footer_help(helptext)
660
+ print_key_labels( 0, 0, labels)
661
+ next
662
+ end
663
+ Ncurses.beep
664
+ end # while
665
+
666
+ begin
667
+ config[yn].call if config.include? yn
668
+ ensure
669
+ restore_application_key_labels # must be done after using print_key_labels
670
+ win.refresh
671
+ end
672
+
673
+ return yn == 'y'
674
+ end
675
+
676
+ #
677
+ # warn user: currently flashes and places error in log file
678
+ # experimental, may change interface later
679
+ # it does not say anything on screen
680
+ # @param [String] text of error/warning to put in log
681
+ # @since 1.1.5
682
+ def warn string
683
+ $log.warn string
684
+ Ncurses.beep
685
+ end
686
+
687
+ #def add_item hotkey, label, desc,action
688
+ #
689
+ ## A *simple* way of creating menus that will appear in a single row.
690
+ # This copies the menu at the bottom of "most" upon pressing ":".
691
+ # hotkey is the key to invoke an item (a single digit letter)
692
+ #
693
+ # label is an action name
694
+ #
695
+ # desc is a description displayed after an item is chosen. Usually, its like:
696
+ #+ "Folding has been enabled" or "Searches will now be case sensitive"
697
+ #
698
+ # action may be a Proc or a symbol which will be called if item selected
699
+ #+ action may be another menu, so recursive menus can be built, but each
700
+ #+ should fit in a line, its a simple system.
701
+
702
+ CMenuItem = Struct.new( :hotkey, :label, :desc, :action )
703
+
704
+
705
+ ## An encapsulated form of yesterday's Most Menu
706
+ # It keeps the internals away from the user.
707
+ # Its not really OOP in the sense that the PromptMenu is not a MenuItem. That's how it is in
708
+ # our Menu system, and that led to a lot of painful coding (at least for me). This is quite
709
+ # simple. A submenu contains a PromptMenu in its action object and is evaluated in a switch.
710
+ # A recursive loop handles submenus.
711
+ #
712
+ # Prompting of menu options with suboptions etc.
713
+ # A block of code or symbol or proc is executed for any leaf node
714
+ # This allows us to define different menus for different objects on the screen, and not have to map
715
+ # all kinds of control keys for operations, and have the user remember them. Only one key invokes the menu
716
+ # and the rest are ordinary characters.
717
+ #
718
+ # == Example
719
+ # menu = PromptMenu.new self do
720
+ # item :s, :goto_start
721
+ # item :b, :goto_bottom
722
+ # item :r, :scroll_backward
723
+ # item :l, :scroll_forward
724
+ # submenu :m, "submenu" do
725
+ # item :p, :goto_last_position
726
+ # item :r, :scroll_backward
727
+ # item :l, :scroll_forward
728
+ # end
729
+ # end
730
+ # menu.display @form.window, $error_message_row, $error_message_col, $datacolor #, menu
731
+
732
+ class PromptMenu
733
+ include Io
734
+ attr_reader :text
735
+ attr_reader :options
736
+ def initialize caller, text="Choose:", &block
737
+ @caller = caller
738
+ @text = text
739
+ @options = []
740
+ instance_eval &block if block_given?
741
+ end
742
+ def add *menuitem
743
+ item = nil
744
+ case menuitem.first
745
+ when CMenuItem
746
+ item = menuitem.first
747
+ @options << item
748
+ else
749
+ case menuitem.size
750
+ when 4
751
+ item = CMenuItem.new(*menuitem.flatten)
752
+ when 2
753
+ # if user only sends key and symbol
754
+ menuitem[3] = menuitem[1]
755
+ item = CMenuItem.new(*menuitem.flatten)
756
+ end
757
+ @options << item
758
+ end
759
+ return item
760
+ end
761
+ alias :item :add
762
+ def create_mitem *args
763
+ item = CMenuItem.new(*args.flatten)
764
+ end
765
+ # create the whole thing using a MenuTree which has minimal information.
766
+ # It uses a hotkey and a code only. We are supposed to resolve the display text
767
+ # and actual proc from the caller using this code.
768
+ def menu_tree mt, pm = self
769
+ mt.each_pair { |ch, code|
770
+ if code.is_a? RubyCurses::MenuTree
771
+ item = pm.add(ch, code.value, "")
772
+ current = PromptMenu.new @caller, code.value
773
+ item.action = current
774
+ menu_tree code, current
775
+ else
776
+ item = pm.add(ch, code.to_s, "", code)
777
+ end
778
+ }
779
+ end
780
+ #
781
+ # To allow a more rubyesque way of defining menus and submenus
782
+ def submenu key, label, &block
783
+ item = CMenuItem.new(key, label)
784
+ @options << item
785
+ item.action = PromptMenu.new @caller, label, &block
786
+ end
787
+ #
788
+ # Display prompt_menu in columns using commandwindow
789
+ # This is an improved way of showing the "most" like menu. The earlier
790
+ # format would only print in one row.
791
+ #
792
+ def display_columns config={}
793
+ prompt = config[:prompt] || "Choose: "
794
+ require 'rbcurse/core/util/rcommandwindow'
795
+ layout = { :height => 5, :width => Ncurses.COLS-1, :top => Ncurses.LINES-6, :left => 0 }
796
+ rc = CommandWindow.new nil, :layout => layout, :box => true, :title => config[:title] || "Menu"
797
+ w = rc.window
798
+ r = 4
799
+ c = 1
800
+ color = $datacolor
801
+ begin
802
+ menu = @options
803
+ $log.debug " DISP MENU "
804
+ ret = 0
805
+ len = 80
806
+ while true
807
+ h = {}
808
+ valid = []
809
+ labels = []
810
+ menu.each{ |item|
811
+ hk = item.hotkey.to_s
812
+ labels << "%c. %s " % [ hk, item.label ]
813
+ h[hk] = item
814
+ valid << hk
815
+ }
816
+ #$log.debug " valid are #{valid} "
817
+ color = $datacolor
818
+ #print_this(win, str, color, r, c)
819
+ rc.display_menu labels, :indexing => :custom
820
+ ch=w.getchar()
821
+ rc.clear
822
+ #$log.debug " got ch #{ch} "
823
+ next if ch < 0 or ch > 255
824
+ if ch == 3 || ch == ?\C-g.getbyte(0)
825
+ clear_this w, r, c, color, len
826
+ print_this(w, "Aborted.", color, r,c)
827
+ break
828
+ end
829
+ ch = ch.chr
830
+ index = valid.index ch
831
+ if index.nil?
832
+ clear_this w, r, c, color, len
833
+ print_this(w, "Not valid. Valid are #{valid}. C-c/C-g to abort.", color, r,c)
834
+ sleep 1
835
+ next
836
+ end
837
+ #$log.debug " index is #{index} "
838
+ item = h[ch]
839
+ desc = item.desc
840
+ #desc ||= "Could not find desc for #{ch} "
841
+ desc ||= ""
842
+ clear_this w, r, c, color, len
843
+ print_this(w, desc, color, r,c)
844
+ action = item.action
845
+ case action
846
+ #when Array
847
+ when PromptMenu
848
+ # submenu
849
+ menu = action.options
850
+ title = rc.title
851
+ rc.title title +" => " + action.text # set title of window to submenu
852
+ when Proc
853
+ ret = action.call
854
+ break
855
+ when Symbol
856
+ if @caller.respond_to?(action, true)
857
+ $log.debug "XXX: IO caller responds to action #{action} "
858
+ ret = @caller.send(action)
859
+ elsif @caller.respond_to?(:execute_this, true)
860
+ ret = @caller.send(:execute_this, action)
861
+ else
862
+ alert "PromptMenu: unidentified action #{action} for #{@caller.class} "
863
+ raise "PromptMenu: unidentified action #{action} for #{@caller.class} "
864
+ end
865
+
866
+ break
867
+ else
868
+ $log.debug " Unidentified flying class #{action.class} "
869
+ break
870
+ end
871
+ end # while
872
+ ensure
873
+ rc.destroy
874
+ rc = nil
875
+ end
876
+ end
877
+ alias :display_new :display_columns
878
+
879
+ # Display the top level menu and accept user input
880
+ # Calls actions or symbols upon selection, or traverses submenus
881
+ # @return retvalue of last call or send, or 0
882
+ # @param win window
883
+ # @param r, c row and col to display on
884
+ # @param color text color (use $datacolor if in doubt)
885
+ # @see display_new - it presents in a much better manner
886
+ # and is not restricted to one row. Avoid this.
887
+ def display win, r, c, color
888
+ # FIXME use a oneline window, user should not have to give all this crap.
889
+ # What about panning if we can;t fit, should we use horiz list to show ?
890
+ menu = @options
891
+ $log.debug " DISP MENU "
892
+ ret = 0
893
+ while true
894
+ str = @text.dup
895
+ h = {}
896
+ valid = []
897
+ menu.each{ |item|
898
+ hk = item.hotkey.to_s
899
+ str << "(%c) %s " % [ hk, item.label ]
900
+ h[hk] = item
901
+ valid << hk
902
+ }
903
+ #$log.debug " valid are #{valid} "
904
+ color = $datacolor
905
+ print_this(win, str, color, r, c)
906
+ ch=win.getchar()
907
+ #$log.debug " got ch #{ch} "
908
+ next if ch < 0 or ch > 255
909
+ if ch == 3 || ch == ?\C-g.getbyte(0)
910
+ clear_this win, r, c, color, str.length
911
+ print_this(win, "Aborted.", color, r,c)
912
+ break
913
+ end
914
+ ch = ch.chr
915
+ index = valid.index ch
916
+ if index.nil?
917
+ clear_this win, r, c, color, str.length
918
+ print_this(win, "Not valid. Valid are #{valid}", color, r,c)
919
+ sleep 1
920
+ next
921
+ end
922
+ #$log.debug " index is #{index} "
923
+ item = h[ch]
924
+ desc = item.desc
925
+ #desc ||= "Could not find desc for #{ch} "
926
+ desc ||= ""
927
+ clear_this win, r, c, color, str.length
928
+ print_this(win, desc, color, r,c)
929
+ action = item.action
930
+ case action
931
+ #when Array
932
+ when PromptMenu
933
+ # submenu
934
+ menu = action.options
935
+ str = "%s: " % action.text
936
+ when Proc
937
+ ret = action.call
938
+ break
939
+ when Symbol
940
+ ret = @caller.send(action)
941
+ break
942
+ else
943
+ $log.debug " Unidentified flying class #{action.class} "
944
+ break
945
+ end
946
+ end # while
947
+ return ret # ret val of last send or call
948
+ end
949
+ end # class PromptMenu
950
+
951
+ ### ADD HERE ###
952
+
953
+ end # module