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,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