rbcurse-core 0.0.13 → 0.0.14
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.
- data/CHANGELOG +10 -0
- data/VERSION +1 -1
- data/lib/rbcurse.rb +1 -1
- data/lib/rbcurse/core/include/bordertitle.rb +3 -1
- data/lib/rbcurse/core/include/chunk.rb +182 -180
- data/lib/rbcurse/core/include/io.rb +445 -443
- data/lib/rbcurse/core/include/listscrollable.rb +257 -254
- data/lib/rbcurse/core/include/vieditable.rb +153 -151
- data/lib/rbcurse/core/system/colormap.rb +146 -143
- data/lib/rbcurse/core/system/ncurses.rb +1 -1
- data/lib/rbcurse/core/util/ansiparser.rb +95 -93
- data/lib/rbcurse/core/util/colorparser.rb +58 -56
- data/lib/rbcurse/core/util/padreader.rb +151 -149
- data/lib/rbcurse/core/widgets/rlist.rb +6 -2
- data/lib/rbcurse/core/widgets/rtabbedwindow.rb +47 -45
- data/lib/rbcurse/core/widgets/textpad.rb +27 -18
- data/rbcurse-core.gemspec +2 -2
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
**2013-04-01**
|
2
|
+
## 0.0.14 rbcurse-core
|
3
|
+
* added module RubyCurses to various modules that were coming as top layer
|
4
|
+
Things could break !!!
|
5
|
+
* minor fix in rlist list()
|
6
|
+
|
7
|
+
**2013-03-29**
|
8
|
+
## 0.0.13 rbcurse-core
|
9
|
+
* textpad - support cases where dimension changes, or a row is updated
|
10
|
+
|
1
11
|
**2013-03-25**
|
2
12
|
## 0.0.12 rbcurse-core
|
3
13
|
* Minor tweaks and fixes to statusline (tested in ribhu gem)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.14
|
data/lib/rbcurse.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# I am moving the common title and border printing stuff into
|
2
2
|
# a separate module.
|
3
|
-
module
|
3
|
+
module RubyCurses
|
4
|
+
module BorderTitle
|
4
5
|
dsl_accessor :suppress_borders #to_print_borders
|
5
6
|
dsl_accessor :border_attrib, :border_color
|
6
7
|
dsl_accessor :title #set this on top
|
@@ -42,5 +43,6 @@ module BorderTitle
|
|
42
43
|
@graphic.printstring( @row, @col+(@width-_title.length)/2, _title, @color_pair, @title_attrib) unless @title.nil?
|
43
44
|
end
|
44
45
|
|
46
|
+
end
|
45
47
|
end
|
46
48
|
include BorderTitle
|
@@ -4,198 +4,200 @@
|
|
4
4
|
# Author: rkumar http://github.com/rkumar/rbcurse/
|
5
5
|
# Date: 07.11.11 - 12:31
|
6
6
|
# Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
7
|
-
# Last update: 2013-
|
7
|
+
# Last update: 2013-04-01 13:38
|
8
8
|
# ------------------------------------------------------------ #
|
9
9
|
#
|
10
10
|
|
11
|
-
module
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
11
|
+
module RubyCurses
|
12
|
+
module Chunks
|
13
|
+
extend self
|
14
|
+
class Chunk
|
15
|
+
|
16
|
+
# color_pair of associated text
|
17
|
+
# text to print
|
18
|
+
# attribute of associated text
|
19
|
+
#attr_accessor :color, :text, :attrib
|
20
|
+
attr_reader :chunk
|
21
|
+
|
22
|
+
def initialize color, text, attrib
|
23
|
+
@chunk = [ color, text, attrib ]
|
24
|
+
#@color = color
|
25
|
+
#@text = text
|
26
|
+
#@attrib = attrib
|
27
|
+
end
|
28
|
+
def color
|
29
|
+
@chunk[0]
|
30
|
+
end
|
31
|
+
def text
|
32
|
+
@chunk[1]
|
33
|
+
end
|
34
|
+
def attrib
|
35
|
+
@chunk[2]
|
36
|
+
end
|
35
37
|
end
|
36
|
-
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
# consists of an array of chunks and corresponds to a line
|
40
|
+
# to be printed.
|
41
|
+
class ChunkLine
|
41
42
|
|
42
|
-
|
43
|
-
|
43
|
+
# an array of chunks
|
44
|
+
attr_reader :chunks
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
def initialize arr=nil
|
47
|
+
@chunks = arr.nil? ? Array.new : arr
|
48
|
+
end
|
49
|
+
def <<(chunk)
|
50
|
+
raise ArgumentError, "Chunk object expected. Received #{chunk.class} " unless chunk.is_a? Chunk
|
51
|
+
@chunks << chunk
|
52
|
+
end
|
53
|
+
alias :add :<<
|
54
|
+
def each &block
|
55
|
+
@chunks.each &block
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
58
|
+
# returns length of text in chunks
|
59
|
+
def row_length
|
60
|
+
result = 0
|
61
|
+
@chunks.each { |e| result += e.text.length }
|
62
|
+
return result
|
63
|
+
end
|
64
|
+
# returns match for str in this chunk
|
65
|
+
# added 2013-03-07 - 23:59
|
66
|
+
def index str
|
67
|
+
result = 0
|
68
|
+
@chunks.each { |e| txt = e.text;
|
69
|
+
ix = txt.index(str)
|
70
|
+
return result + ix if ix
|
71
|
+
result += e.text.length
|
72
|
+
}
|
73
|
+
return nil
|
74
|
+
end
|
75
|
+
alias :length :row_length
|
76
|
+
alias :size :row_length
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
78
|
+
# return a Chunkline containing only the text for the range requested
|
79
|
+
def substring start, size
|
80
|
+
raise "substring not implemented yet"
|
81
|
+
end
|
82
|
+
def to_s
|
83
|
+
result = ""
|
84
|
+
@chunks.each { |e| result << e.text }
|
85
|
+
result
|
86
|
+
end
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
94
|
-
class ColorParser
|
95
|
-
def initialize cp
|
96
|
-
color_parser cp
|
97
|
-
@color_pair = $datacolor
|
98
|
-
@attrib = FFI::NCurses::A_NORMAL
|
99
|
-
@color_array = [:white]
|
100
|
-
@bgcolor_array = [:black]
|
101
|
-
@attrib_array = [@attrib]
|
102
|
-
@color_pair_array = [@color_pair]
|
103
|
-
@color = :white
|
104
|
-
@bgcolor = :black
|
88
|
+
# added to take care of many string methods that are called.
|
89
|
+
# Callers really don't know this is a chunkline, they assume its a string
|
90
|
+
# 2013-03-21 - 19:01
|
91
|
+
def method_missing(sym, *args, &block)
|
92
|
+
self.to_s.send sym, *args, &block
|
93
|
+
end
|
105
94
|
end
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
#
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
95
|
+
class ColorParser
|
96
|
+
def initialize cp
|
97
|
+
color_parser cp
|
98
|
+
@color_pair = $datacolor
|
99
|
+
@attrib = FFI::NCurses::A_NORMAL
|
100
|
+
@color_array = [:white]
|
101
|
+
@bgcolor_array = [:black]
|
102
|
+
@attrib_array = [@attrib]
|
103
|
+
@color_pair_array = [@color_pair]
|
104
|
+
@color = :white
|
105
|
+
@bgcolor = :black
|
106
|
+
end
|
107
|
+
#
|
108
|
+
# Takes a formatted string and converts the parsed parts to chunks.
|
109
|
+
#
|
110
|
+
# @param [String] takes the entire line or string and breaks into an array of chunks
|
111
|
+
# @yield chunk if block
|
112
|
+
# @return [ChunkLine] # [Array] array of chunks
|
113
|
+
# @since 1.4.1 2011-11-3 experimental, can change
|
114
|
+
public
|
115
|
+
def convert_to_chunk s, colorp=$datacolor, att=FFI::NCurses::A_NORMAL
|
116
|
+
#require 'rbcurse/core/include/chunk'
|
117
|
+
|
118
|
+
@color_parser ||= get_default_color_parser()
|
119
|
+
## defaults
|
120
|
+
color_pair = @color_pair
|
121
|
+
attrib = @attrib
|
122
|
+
#res = []
|
123
|
+
res = ChunkLine.new
|
124
|
+
color = @color
|
125
|
+
bgcolor = @bgcolor
|
126
|
+
# stack the values, so when user issues "/end" we can pop earlier ones
|
127
|
+
|
128
|
+
@color_parser.parse_format(s) do |p|
|
129
|
+
case p
|
130
|
+
when Array
|
131
|
+
## got color / attrib info, this starts a new span
|
132
|
+
|
133
|
+
#color, bgcolor, attrib = *p
|
134
|
+
lc, lb, la = *p
|
135
|
+
if la
|
136
|
+
@attrib = get_attrib la
|
137
|
+
end
|
138
|
+
if lc || lb
|
139
|
+
@color = lc ? lc : @color_array.last
|
140
|
+
@bgcolor = lb ? lb : @bgcolor_array.last
|
141
|
+
@color_array << @color
|
142
|
+
@bgcolor_array << @bgcolor
|
143
|
+
@color_pair = get_color($datacolor, @color, @bgcolor)
|
144
|
+
end
|
145
|
+
@color_pair_array << @color_pair
|
146
|
+
@attrib_array << @attrib
|
147
|
+
#$log.debug "XXX: CHUNK start #{color_pair} , #{attrib} :: c:#{lc} b:#{lb} "
|
148
|
+
#$log.debug "XXX: CHUNK start arr #{@color_pair_array} :: #{@attrib_array} "
|
149
|
+
|
150
|
+
when :endcolor
|
151
|
+
|
152
|
+
# end the current (last) span
|
153
|
+
@color_pair_array.pop
|
154
|
+
@color_pair = @color_pair_array.last
|
155
|
+
@attrib_array.pop
|
156
|
+
@attrib = @attrib_array.last
|
157
|
+
#$log.debug "XXX: CHUNK end #{color_pair} , #{attrib} "
|
158
|
+
#$log.debug "XXX: CHUNK end arr #{@color_pair_array} :: #{@attrib_array} "
|
159
|
+
when :reset # ansi has this
|
160
|
+
# end all previous colors
|
161
|
+
@color_pair = $datacolor # @color_pair_array.first
|
162
|
+
@color_pair_array = [@color_pair]
|
163
|
+
@attrib = FFI::NCurses::A_NORMAL #@attrib_array.first
|
164
|
+
@attrib_array = [@attrib]
|
165
|
+
@bgcolor_array = [@bgcolor_array.first]
|
166
|
+
@color_array = [@color_array.first]
|
167
|
+
|
168
|
+
when String
|
169
|
+
|
170
|
+
## create the chunk
|
171
|
+
#$log.debug "XXX: CHUNK using on #{p} : #{@color_pair} , #{@attrib} " # 2011-12-10 12:38:51
|
172
|
+
|
173
|
+
#chunk = [color_pair, p, attrib]
|
174
|
+
chunk = Chunk.new @color_pair, p, @attrib
|
175
|
+
if block_given?
|
176
|
+
yield chunk
|
177
|
+
else
|
178
|
+
res << chunk
|
179
|
+
end
|
178
180
|
end
|
181
|
+
end # parse
|
182
|
+
return res unless block_given?
|
183
|
+
end
|
184
|
+
def get_default_color_parser
|
185
|
+
require 'rbcurse/core/util/colorparser'
|
186
|
+
@color_parser || DefaultColorParser.new
|
187
|
+
end
|
188
|
+
# supply with a color parser, if you supplied formatted text
|
189
|
+
public
|
190
|
+
def color_parser f
|
191
|
+
$log.debug "XXX: color_parser setting in CP to #{f} "
|
192
|
+
if f == :tmux
|
193
|
+
@color_parser = get_default_color_parser()
|
194
|
+
elsif f == :ansi
|
195
|
+
require 'rbcurse/core/util/ansiparser'
|
196
|
+
@color_parser = AnsiParser.new
|
197
|
+
else
|
198
|
+
@color_parser = f
|
179
199
|
end
|
180
|
-
end # parse
|
181
|
-
return res unless block_given?
|
182
|
-
end
|
183
|
-
def get_default_color_parser
|
184
|
-
require 'rbcurse/core/util/colorparser'
|
185
|
-
@color_parser || DefaultColorParser.new
|
186
|
-
end
|
187
|
-
# supply with a color parser, if you supplied formatted text
|
188
|
-
public
|
189
|
-
def color_parser f
|
190
|
-
$log.debug "XXX: color_parser setting in CP to #{f} "
|
191
|
-
if f == :tmux
|
192
|
-
@color_parser = get_default_color_parser()
|
193
|
-
elsif f == :ansi
|
194
|
-
require 'rbcurse/core/util/ansiparser'
|
195
|
-
@color_parser = AnsiParser.new
|
196
|
-
else
|
197
|
-
@color_parser = f
|
198
200
|
end
|
199
|
-
end
|
200
|
-
end
|
201
|
+
end # class
|
202
|
+
end
|
201
203
|
end
|
@@ -10,47 +10,48 @@
|
|
10
10
|
# Changes:
|
11
11
|
# 2011-12-6 : removed many old, outdated methods.
|
12
12
|
#*******************************************************#
|
13
|
-
module
|
13
|
+
module RubyCurses
|
14
|
+
module Io
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
# create a 2 line window at bottom to accept user input
|
17
|
+
#
|
18
|
+
def __create_footer_window h = 2 , w = Ncurses.COLS, t = Ncurses.LINES-2, l = 0
|
19
|
+
ewin = VER::Window.new(h, w , t, l)
|
20
|
+
end
|
21
|
+
# 2011-11-27 I have replaced the getting of chars with a field
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
23
|
+
# routine to get a string at bottom of window.
|
24
|
+
# The first 3 params are no longer required since we create a window
|
25
|
+
# of our own.
|
26
|
+
# @param [String] prompt - label to show
|
27
|
+
# @param [Fixnum] maxlen - max length of input
|
28
|
+
# @param [Hash] config - :default, :display_length of Field, :help_text, :tab_completion
|
29
|
+
# help_text is displayed on F1
|
30
|
+
# tab_completion is a proc which helps to complete user input
|
31
|
+
# This method is now only for backward compatibility
|
32
|
+
# rbgetstr had various return codes based on whether user asked for help
|
33
|
+
# possibly mimicking alpine, or because i could do nothing about it.
|
34
|
+
# Now, rbgets handles that and only returns if the user cancels or enters
|
35
|
+
# a string, so rbgets does not need to return other codes.
|
36
|
+
def rbgetstr(nolongerused, r, c, prompt, maxlen, config={})
|
37
|
+
config[:maxlen] = maxlen
|
38
|
+
str = rb_gets(prompt, config)
|
39
|
+
if str
|
40
|
+
return 0, str
|
41
|
+
else
|
42
|
+
return -1, nil
|
43
|
+
end
|
42
44
|
end
|
43
|
-
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
# get a string at the bottom of the screen
|
47
|
+
#
|
48
|
+
# @param [String] prompt - label to show
|
49
|
+
# @param [Hash] config - :default, :display_length of Field, :help_text, :tab_completion
|
50
|
+
# help_text is displayed on F1
|
51
|
+
# tab_completion is a proc which helps to complete user input
|
52
|
+
# @yield [Field] for overriding or customization
|
53
|
+
# @return [String, nil] String if entered, nil if canceled
|
54
|
+
def rb_gets(prompt, config={}) # yield field
|
54
55
|
if config.is_a? Array
|
55
56
|
options = config
|
56
57
|
completion_proc = Proc.new{|str|
|
@@ -59,493 +60,494 @@ module Io
|
|
59
60
|
config = {}
|
60
61
|
config[:tab_completion] = completion_proc
|
61
62
|
end
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
63
|
+
begin
|
64
|
+
win = __create_footer_window
|
65
|
+
form = Form.new win
|
66
|
+
r = 0; c = 1;
|
67
|
+
default = config[:default] || ""
|
68
|
+
prompt = "#{prompt} [#{default}]:" if default.size > 0
|
69
|
+
_max = FFI::NCurses.COLS-1-prompt.size-4
|
70
|
+
displen = config[:display_length] || [config[:maxlen] || 999, _max].min
|
71
|
+
maxlen = config[:maxlen] || _max
|
72
|
+
field = Field.new form, :row => r, :col => c, :maxlen => maxlen, :default => default, :label => prompt,
|
73
|
+
:display_length => displen
|
74
|
+
bg = Ncurses.COLORS >= 236 ? 233 : :blue
|
75
|
+
field.bgcolor = bg
|
76
|
+
field.cursor_end if default.size > 0
|
77
|
+
def field.default=(x); default(x);end
|
77
78
|
|
78
|
-
|
79
|
-
|
80
|
-
|
79
|
+
# if user wishes to use the yield and say "field.history = [x,y,z] then
|
80
|
+
# we should alredy have extended this, so lets make it permanent
|
81
|
+
#if config[:history]
|
81
82
|
#raise ArgumentError, "Field history must be an array" unless config[:history].is_a? Array
|
82
83
|
require 'rbcurse/core/include/rhistory'
|
83
84
|
field.extend(FieldHistory)
|
84
85
|
#field.history_config :row =>
|
85
86
|
field.history = config[:history]
|
86
|
-
#end
|
87
|
-
|
88
|
-
yield field if block_given?
|
89
|
-
form.repaint
|
90
|
-
win.wrefresh
|
91
|
-
prevchar = 0
|
92
|
-
entries = nil
|
93
|
-
oldstr = nil # for tab completion, origal word entered by user
|
94
|
-
while ((ch = win.getchar()) != 999)
|
95
|
-
break if ch == 10 || ch == 13 || ch == KEY_ENTER
|
96
|
-
#return -1, nil if ch == ?\C-c.getbyte(0) || ch == ?\C-g.getbyte(0)
|
97
|
-
return nil if ch == ?\C-c.getbyte(0) || ch == ?\C-g.getbyte(0)
|
98
|
-
#if ch == ?\M-h.getbyte(0) # HELP KEY
|
99
|
-
#help_text = config[:help_text] || "No help provided"
|
100
|
-
#color = $datacolor
|
101
|
-
#print_help(win, r, c, color, help_text)
|
102
|
-
## this will come over our text
|
103
87
|
#end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
88
|
+
|
89
|
+
yield field if block_given?
|
90
|
+
form.repaint
|
91
|
+
win.wrefresh
|
92
|
+
prevchar = 0
|
93
|
+
entries = nil
|
94
|
+
oldstr = nil # for tab completion, origal word entered by user
|
95
|
+
while ((ch = win.getchar()) != 999)
|
96
|
+
break if ch == 10 || ch == 13 || ch == KEY_ENTER
|
97
|
+
#return -1, nil if ch == ?\C-c.getbyte(0) || ch == ?\C-g.getbyte(0)
|
98
|
+
return nil if ch == ?\C-c.getbyte(0) || ch == ?\C-g.getbyte(0)
|
99
|
+
#if ch == ?\M-h.getbyte(0) # HELP KEY
|
100
|
+
#help_text = config[:help_text] || "No help provided"
|
101
|
+
#color = $datacolor
|
102
|
+
#print_help(win, r, c, color, help_text)
|
103
|
+
## this will come over our text
|
104
|
+
#end
|
105
|
+
# TODO tab completion and help_text print on F1
|
106
|
+
# that field objects can extend, same for tab completion and gmail completion
|
107
|
+
if ch == KEY_TAB
|
108
|
+
if config
|
109
|
+
str = field.text
|
110
|
+
if prevchar == KEY_TAB
|
111
|
+
if !entries.nil? && !entries.empty?
|
112
|
+
str = entries.delete_at(0)
|
113
|
+
else
|
114
|
+
str = oldstr if oldstr
|
115
|
+
prevchar = ch = nil # so it can start again completing
|
116
|
+
end
|
112
117
|
else
|
113
|
-
|
114
|
-
|
118
|
+
tabc = config[:tab_completion] unless tabc
|
119
|
+
next unless tabc
|
120
|
+
oldstr = str.dup
|
121
|
+
entries = tabc.call(str).dup
|
122
|
+
$log.debug " tab got #{entries} for str=#{str}"
|
123
|
+
str = entries.delete_at(0) unless entries.nil? || entries.empty?
|
124
|
+
str = str.to_s.dup
|
115
125
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
str = str.to_s.dup
|
124
|
-
end
|
125
|
-
if str
|
126
|
-
field.text = str
|
127
|
-
field.cursor_end
|
128
|
-
field.set_form_col # shit why are we doign this, text sets curpos to 0
|
126
|
+
if str
|
127
|
+
field.text = str
|
128
|
+
field.cursor_end
|
129
|
+
field.set_form_col # shit why are we doign this, text sets curpos to 0
|
130
|
+
end
|
131
|
+
form.repaint
|
132
|
+
win.wrefresh
|
129
133
|
end
|
130
|
-
form.repaint
|
131
|
-
win.wrefresh
|
132
|
-
end
|
133
134
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
135
|
+
# tab_completion
|
136
|
+
# if previous char was not tab, execute tab_completion_proc and push first entry
|
137
|
+
# else push the next entry
|
138
|
+
elsif ch == KEY_F1
|
139
|
+
help_text = config[:help_text] || "No help provided. C-c/C-g aborts. <TAB> completion. Alt-h history. C-a/e"
|
140
|
+
print_status_message help_text, :wait => 7
|
141
|
+
else
|
142
|
+
form.handle_key ch
|
143
|
+
end
|
144
|
+
prevchar = ch
|
145
|
+
win.wrefresh
|
142
146
|
end
|
143
|
-
|
144
|
-
|
147
|
+
rescue => err
|
148
|
+
Ncurses.beep
|
149
|
+
textdialog [err.to_s, *err.backtrace], :title => "Exception"
|
150
|
+
$log.error "EXC in rbgetsr #{err} "
|
151
|
+
$log.error(err.backtrace.join("\n"))
|
152
|
+
ensure
|
153
|
+
win.destroy if win
|
145
154
|
end
|
146
|
-
|
147
|
-
|
148
|
-
textdialog [err.to_s, *err.backtrace], :title => "Exception"
|
149
|
-
$log.error "EXC in rbgetsr #{err} "
|
150
|
-
$log.error(err.backtrace.join("\n"))
|
151
|
-
ensure
|
152
|
-
win.destroy if win
|
155
|
+
config[:history] << field.text if config[:history] && field.text
|
156
|
+
return field.text
|
153
157
|
end
|
154
|
-
config[:history] << field.text if config[:history] && field.text
|
155
|
-
return field.text
|
156
|
-
end
|
157
158
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
159
|
+
# get a character.
|
160
|
+
# unlike rb_gets allows user to enter control or alt or function character too.
|
161
|
+
# @param [String] prompt or label to show.
|
162
|
+
# @param [Hash] configuration such as default or regexp for validation
|
163
|
+
# @return [Fixnum] nil if canceled, or ret value of getchar which is numeric
|
164
|
+
# If default provided, then ENTER returns the default
|
165
|
+
def rb_getchar(prompt, config={}) # yield field
|
166
|
+
begin
|
167
|
+
win = __create_footer_window
|
168
|
+
#form = Form.new win
|
169
|
+
r = 0; c = 1;
|
170
|
+
default = config[:default]
|
171
|
+
prompt = "#{prompt} [#{default}] " if default
|
172
|
+
win.mvprintw(r, c, "%s: " % prompt);
|
173
|
+
bg = Ncurses.COLORS >= 236 ? 236 : :blue
|
174
|
+
color_pair = get_color($reversecolor, :white, bg)
|
175
|
+
win.printstring r, c + prompt.size + 2, " ", color_pair
|
175
176
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
177
|
+
win.wrefresh
|
178
|
+
prevchar = 0
|
179
|
+
entries = nil
|
180
|
+
while ((ch = win.getchar()) != 999)
|
181
|
+
return default.ord if default && (ch == 13 || ch == KEY_ENTER)
|
182
|
+
return nil if ch == ?\C-c.getbyte(0) || ch == ?\C-g.getbyte(0)
|
183
|
+
if ch == KEY_F1
|
184
|
+
help_text = config[:help_text] || "No help provided. C-c/C-g aborts."
|
185
|
+
print_status_message help_text, :wait => 7
|
186
|
+
win.wrefresh # nevr had to do this with ncurses, but have to with ffi-ncurses ??
|
187
|
+
next
|
188
|
+
end
|
189
|
+
if config[:regexp]
|
190
|
+
reg = config[:regexp]
|
191
|
+
if ch > 0 && ch < 256
|
192
|
+
chs = ch.chr
|
193
|
+
return ch if chs =~ reg
|
194
|
+
alert "Wrong character. #{reg} "
|
195
|
+
else
|
196
|
+
alert "Wrong character. #{reg} "
|
197
|
+
end
|
194
198
|
else
|
195
|
-
|
199
|
+
return ch
|
196
200
|
end
|
197
|
-
|
198
|
-
|
201
|
+
#form.handle_key ch
|
202
|
+
win.wrefresh
|
199
203
|
end
|
200
|
-
|
201
|
-
|
204
|
+
rescue => err
|
205
|
+
Ncurses.beep
|
206
|
+
$log.error "EXC in rbgetsr #{err} "
|
207
|
+
$log.error(err.backtrace.join("\n"))
|
208
|
+
ensure
|
209
|
+
win.destroy if win
|
202
210
|
end
|
203
|
-
|
204
|
-
Ncurses.beep
|
205
|
-
$log.error "EXC in rbgetsr #{err} "
|
206
|
-
$log.error(err.backtrace.join("\n"))
|
207
|
-
ensure
|
208
|
-
win.destroy if win
|
211
|
+
return nil
|
209
212
|
end
|
210
|
-
return nil
|
211
|
-
end
|
212
213
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
214
|
+
# This is just experimental, trying out tab_completion
|
215
|
+
# Prompt user for a file name, allowing him to tab to complete filenames
|
216
|
+
# @param [String] label to print before field
|
217
|
+
# @param [Fixnum] max length of field
|
218
|
+
# @return [String] filename or blank if user cancelled
|
219
|
+
def get_file prompt, config={} #:nodoc:
|
220
|
+
maxlen = 70
|
221
|
+
tabc = Proc.new {|str| Dir.glob(str +"*") }
|
222
|
+
config[:tab_completion] ||= tabc
|
223
|
+
#config[:default] = "test"
|
224
|
+
ret, str = rbgetstr(nil,0,0, prompt, maxlen, config)
|
225
|
+
#$log.debug " get_file returned #{ret} , #{str} "
|
226
|
+
return "" if ret != 0
|
227
|
+
return str
|
228
|
+
end
|
229
|
+
def clear_this win, r, c, color, len
|
230
|
+
print_this(win, "%-*s" % [len," "], color, r, c)
|
231
|
+
end
|
231
232
|
|
232
233
|
|
233
234
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
235
|
+
##
|
236
|
+
# prints given text to window, in color at x and y coordinates
|
237
|
+
# @param [Window] window to write to
|
238
|
+
# @param [String] text to print
|
239
|
+
# @param [int] color pair such as $datacolor or $promptcolor
|
240
|
+
# @param [int] x row
|
241
|
+
# @param [int] y col
|
242
|
+
# @see Window#printstring
|
243
|
+
def print_this(win, text, color, x, y)
|
244
|
+
raise "win nil in print_this" unless win
|
245
|
+
color=Ncurses.COLOR_PAIR(color);
|
246
|
+
win.attron(color);
|
247
|
+
#win.mvprintw(x, y, "%-40s" % text);
|
248
|
+
win.mvprintw(x, y, "%s" % text);
|
249
|
+
win.attroff(color);
|
250
|
+
win.refresh
|
251
|
+
end
|
251
252
|
|
252
253
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
254
|
+
#
|
255
|
+
# warn user: currently flashes and places error in log file
|
256
|
+
# experimental, may change interface later
|
257
|
+
# it does not say anything on screen
|
258
|
+
# @param [String] text of error/warning to put in log
|
259
|
+
# @since 1.1.5
|
260
|
+
def warn string
|
261
|
+
$log.warn string
|
262
|
+
Ncurses.beep
|
263
|
+
end
|
263
264
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
265
|
+
#def add_item hotkey, label, desc,action
|
266
|
+
#
|
267
|
+
## A *simple* way of creating menus that will appear in a single row.
|
268
|
+
# This copies the menu at the bottom of "most" upon pressing ":".
|
269
|
+
# hotkey is the key to invoke an item (a single digit letter)
|
270
|
+
#
|
271
|
+
# label is an action name
|
272
|
+
#
|
273
|
+
# desc is a description displayed after an item is chosen. Usually, its like:
|
274
|
+
#+ "Folding has been enabled" or "Searches will now be case sensitive"
|
275
|
+
#
|
276
|
+
# action may be a Proc or a symbol which will be called if item selected
|
277
|
+
#+ action may be another menu, so recursive menus can be built, but each
|
278
|
+
#+ should fit in a line, its a simple system.
|
278
279
|
|
279
|
-
|
280
|
+
CMenuItem = Struct.new( :hotkey, :label, :desc, :action )
|
280
281
|
|
281
282
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
283
|
+
## An encapsulated form of yesterday's Most Menu
|
284
|
+
# It keeps the internals away from the user.
|
285
|
+
# Its not really OOP in the sense that the PromptMenu is not a MenuItem. That's how it is in
|
286
|
+
# our Menu system, and that led to a lot of painful coding (at least for me). This is quite
|
287
|
+
# simple. A submenu contains a PromptMenu in its action object and is evaluated in a switch.
|
288
|
+
# A recursive loop handles submenus.
|
289
|
+
#
|
290
|
+
# Prompting of menu options with suboptions etc.
|
291
|
+
# A block of code or symbol or proc is executed for any leaf node
|
292
|
+
# This allows us to define different menus for different objects on the screen, and not have to map
|
293
|
+
# all kinds of control keys for operations, and have the user remember them. Only one key invokes the menu
|
294
|
+
# and the rest are ordinary characters.
|
295
|
+
#
|
296
|
+
# == Example
|
297
|
+
# menu = PromptMenu.new self do
|
298
|
+
# item :s, :goto_start
|
299
|
+
# item :b, :goto_bottom
|
300
|
+
# item :r, :scroll_backward
|
301
|
+
# item :l, :scroll_forward
|
302
|
+
# submenu :m, "submenu" do
|
303
|
+
# item :p, :goto_last_position
|
304
|
+
# item :r, :scroll_backward
|
305
|
+
# item :l, :scroll_forward
|
306
|
+
# end
|
307
|
+
# end
|
308
|
+
# menu.display @form.window, $error_message_row, $error_message_col, $datacolor #, menu
|
308
309
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
310
|
+
class PromptMenu
|
311
|
+
include Io
|
312
|
+
attr_reader :text
|
313
|
+
attr_reader :options
|
314
|
+
def initialize caller, text="Choose:", &block
|
315
|
+
@caller = caller
|
316
|
+
@text = text
|
317
|
+
@options = []
|
318
|
+
yield_or_eval &block if block_given?
|
319
|
+
end
|
320
|
+
def add *menuitem
|
321
|
+
item = nil
|
322
|
+
case menuitem.first
|
323
|
+
when CMenuItem
|
324
|
+
item = menuitem.first
|
325
|
+
@options << item
|
326
|
+
else
|
327
|
+
case menuitem.size
|
328
|
+
when 4
|
329
|
+
item = CMenuItem.new(*menuitem.flatten)
|
330
|
+
when 2
|
331
|
+
# if user only sends key and symbol
|
332
|
+
menuitem[3] = menuitem[1]
|
333
|
+
item = CMenuItem.new(*menuitem.flatten)
|
334
|
+
when 1
|
335
|
+
if menuitem.first.is_a? Action
|
336
|
+
item = menuitem.first
|
337
|
+
else
|
338
|
+
raise ArgumentError, "Don't know how to handle #{menuitem.size} : #{menuitem} "
|
339
|
+
end
|
336
340
|
else
|
337
341
|
raise ArgumentError, "Don't know how to handle #{menuitem.size} : #{menuitem} "
|
338
342
|
end
|
339
|
-
|
340
|
-
raise ArgumentError, "Don't know how to handle #{menuitem.size} : #{menuitem} "
|
343
|
+
@options << item
|
341
344
|
end
|
345
|
+
return item
|
346
|
+
end
|
347
|
+
alias :item :add
|
348
|
+
def create_mitem *args
|
349
|
+
item = CMenuItem.new(*args.flatten)
|
350
|
+
end
|
351
|
+
# Added this, since actually it could have been like this 2011-12-22
|
352
|
+
def self.create_menuitem *args
|
353
|
+
item = CMenuItem.new(*args.flatten)
|
354
|
+
end
|
355
|
+
# create the whole thing using a MenuTree which has minimal information.
|
356
|
+
# It uses a hotkey and a code only. We are supposed to resolve the display text
|
357
|
+
# and actual proc from the caller using this code.
|
358
|
+
def menu_tree mt, pm = self
|
359
|
+
mt.each_pair { |ch, code|
|
360
|
+
if code.is_a? RubyCurses::MenuTree
|
361
|
+
item = pm.add(ch, code.value, "")
|
362
|
+
current = PromptMenu.new @caller, code.value
|
363
|
+
item.action = current
|
364
|
+
menu_tree code, current
|
365
|
+
else
|
366
|
+
item = pm.add(ch, code.to_s, "", code)
|
367
|
+
end
|
368
|
+
}
|
369
|
+
end
|
370
|
+
#
|
371
|
+
# To allow a more rubyesque way of defining menus and submenus
|
372
|
+
def submenu key, label, &block
|
373
|
+
item = CMenuItem.new(key, label)
|
342
374
|
@options << item
|
375
|
+
item.action = PromptMenu.new @caller, label, &block
|
343
376
|
end
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
377
|
+
#
|
378
|
+
# Display prompt_menu in columns using commandwindow
|
379
|
+
# This is an improved way of showing the "most" like menu. The earlier
|
380
|
+
# format would only print in one row.
|
381
|
+
#
|
382
|
+
def display_columns config={}
|
383
|
+
prompt = config[:prompt] || "Choose: "
|
384
|
+
require 'rbcurse/core/util/rcommandwindow'
|
385
|
+
layout = { :height => 5, :width => Ncurses.COLS-0, :top => Ncurses.LINES-6, :left => 0 }
|
386
|
+
rc = CommandWindow.new nil, :layout => layout, :box => true, :title => config[:title] || "Menu"
|
387
|
+
w = rc.window
|
388
|
+
r = 4
|
389
|
+
c = 1
|
390
|
+
color = $datacolor
|
391
|
+
begin
|
392
|
+
menu = @options
|
393
|
+
$log.debug " DISP MENU "
|
394
|
+
ret = 0
|
395
|
+
len = 80
|
396
|
+
while true
|
397
|
+
h = {}
|
398
|
+
valid = []
|
399
|
+
labels = []
|
400
|
+
menu.each{ |item|
|
401
|
+
if item.respond_to? :hotkey
|
402
|
+
hk = item.hotkey.to_s
|
403
|
+
else
|
404
|
+
raise ArgumentError, "Promptmenu needs hotkey or mnemonic"
|
405
|
+
end
|
406
|
+
# 187compat 2013-03-20 - 19:00 throws up
|
407
|
+
labels << "%c. %s " % [ hk.getbyte(0), item.label ]
|
408
|
+
h[hk] = item
|
409
|
+
valid << hk
|
410
|
+
}
|
411
|
+
#$log.debug " valid are #{valid} "
|
412
|
+
color = $datacolor
|
413
|
+
#print_this(win, str, color, r, c)
|
414
|
+
rc.display_menu labels, :indexing => :custom
|
415
|
+
ch=w.getchar()
|
416
|
+
rc.clear
|
417
|
+
#$log.debug " got ch #{ch} "
|
418
|
+
next if ch < 0 or ch > 255
|
419
|
+
if ch == 3 || ch == ?\C-g.getbyte(0)
|
420
|
+
clear_this w, r, c, color, len
|
421
|
+
print_this(w, "Aborted.", color, r,c)
|
422
|
+
break
|
423
|
+
end
|
424
|
+
ch = ch.chr
|
425
|
+
index = valid.index ch
|
426
|
+
if index.nil?
|
427
|
+
clear_this w, r, c, color, len
|
428
|
+
print_this(w, "Not valid. Valid are #{valid}. C-c/C-g to abort.", color, r,c)
|
429
|
+
sleep 1
|
430
|
+
next
|
431
|
+
end
|
432
|
+
#$log.debug " index is #{index} "
|
433
|
+
item = h[ch]
|
434
|
+
# I don;t think this even shows now, its useless
|
435
|
+
if item.respond_to? :desc
|
436
|
+
desc = item.desc
|
437
|
+
#desc ||= "Could not find desc for #{ch} "
|
438
|
+
desc ||= ""
|
439
|
+
clear_this w, r, c, color, len
|
440
|
+
print_this(w, desc, color, r,c)
|
441
|
+
end
|
442
|
+
action = item.action
|
443
|
+
case action
|
444
|
+
#when Array
|
445
|
+
when PromptMenu
|
446
|
+
# submenu
|
447
|
+
menu = action.options
|
448
|
+
title = rc.title
|
449
|
+
rc.title title +" => " + action.text # set title of window to submenu
|
450
|
+
when Proc
|
451
|
+
ret = action.call
|
452
|
+
break
|
453
|
+
when Symbol
|
454
|
+
if @caller.respond_to?(action, true)
|
455
|
+
$log.debug "XXX: IO caller responds to action #{action} "
|
456
|
+
ret = @caller.send(action)
|
457
|
+
elsif @caller.respond_to?(:execute_this, true)
|
458
|
+
ret = @caller.send(:execute_this, action)
|
459
|
+
else
|
460
|
+
alert "PromptMenu: unidentified action #{action} for #{@caller.class} "
|
461
|
+
raise "PromptMenu: unidentified action #{action} for #{@caller.class} "
|
462
|
+
end
|
463
|
+
|
464
|
+
break
|
465
|
+
else
|
466
|
+
$log.debug " Unidentified flying class #{action.class} "
|
467
|
+
break
|
468
|
+
end
|
469
|
+
end # while
|
470
|
+
ensure
|
471
|
+
rc.destroy
|
472
|
+
rc = nil
|
366
473
|
end
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
@
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
prompt = config[:prompt] || "Choose: "
|
383
|
-
require 'rbcurse/core/util/rcommandwindow'
|
384
|
-
layout = { :height => 5, :width => Ncurses.COLS-0, :top => Ncurses.LINES-6, :left => 0 }
|
385
|
-
rc = CommandWindow.new nil, :layout => layout, :box => true, :title => config[:title] || "Menu"
|
386
|
-
w = rc.window
|
387
|
-
r = 4
|
388
|
-
c = 1
|
389
|
-
color = $datacolor
|
390
|
-
begin
|
474
|
+
end
|
475
|
+
alias :display_new :display_columns
|
476
|
+
|
477
|
+
# Display the top level menu and accept user input
|
478
|
+
# Calls actions or symbols upon selection, or traverses submenus
|
479
|
+
# @return retvalue of last call or send, or 0
|
480
|
+
# @param win window
|
481
|
+
# @param r, c row and col to display on
|
482
|
+
# @param color text color (use $datacolor if in doubt)
|
483
|
+
# @see display_new - it presents in a much better manner
|
484
|
+
# and is not restricted to one row. Avoid this.
|
485
|
+
def display win, r, c, color
|
486
|
+
raise "Please use display_new, i've replace this with that"
|
487
|
+
# FIXME use a oneline window, user should not have to give all this crap.
|
488
|
+
# What about panning if we can;t fit, should we use horiz list to show ?
|
391
489
|
menu = @options
|
392
490
|
$log.debug " DISP MENU "
|
393
491
|
ret = 0
|
394
|
-
len = 80
|
395
492
|
while true
|
493
|
+
str = @text.dup
|
396
494
|
h = {}
|
397
495
|
valid = []
|
398
|
-
labels = []
|
399
496
|
menu.each{ |item|
|
400
|
-
|
401
|
-
|
402
|
-
else
|
403
|
-
raise ArgumentError, "Promptmenu needs hotkey or mnemonic"
|
404
|
-
end
|
405
|
-
# 187compat 2013-03-20 - 19:00 throws up
|
406
|
-
labels << "%c. %s " % [ hk.getbyte(0), item.label ]
|
497
|
+
hk = item.hotkey.to_s
|
498
|
+
str << "(%c) %s " % [ hk, item.label ]
|
407
499
|
h[hk] = item
|
408
500
|
valid << hk
|
409
501
|
}
|
410
502
|
#$log.debug " valid are #{valid} "
|
411
503
|
color = $datacolor
|
412
|
-
|
413
|
-
|
414
|
-
ch=w.getchar()
|
415
|
-
rc.clear
|
504
|
+
print_this(win, str, color, r, c)
|
505
|
+
ch=win.getchar()
|
416
506
|
#$log.debug " got ch #{ch} "
|
417
507
|
next if ch < 0 or ch > 255
|
418
508
|
if ch == 3 || ch == ?\C-g.getbyte(0)
|
419
|
-
clear_this
|
420
|
-
print_this(
|
509
|
+
clear_this win, r, c, color, str.length
|
510
|
+
print_this(win, "Aborted.", color, r,c)
|
421
511
|
break
|
422
512
|
end
|
423
513
|
ch = ch.chr
|
424
514
|
index = valid.index ch
|
425
515
|
if index.nil?
|
426
|
-
clear_this
|
427
|
-
print_this(
|
516
|
+
clear_this win, r, c, color, str.length
|
517
|
+
print_this(win, "Not valid. Valid are #{valid}", color, r,c)
|
428
518
|
sleep 1
|
429
519
|
next
|
430
520
|
end
|
431
521
|
#$log.debug " index is #{index} "
|
432
522
|
item = h[ch]
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
clear_this w, r, c, color, len
|
439
|
-
print_this(w, desc, color, r,c)
|
440
|
-
end
|
523
|
+
desc = item.desc
|
524
|
+
#desc ||= "Could not find desc for #{ch} "
|
525
|
+
desc ||= ""
|
526
|
+
clear_this win, r, c, color, str.length
|
527
|
+
print_this(win, desc, color, r,c)
|
441
528
|
action = item.action
|
442
529
|
case action
|
443
530
|
#when Array
|
444
531
|
when PromptMenu
|
445
532
|
# submenu
|
446
533
|
menu = action.options
|
447
|
-
|
448
|
-
rc.title title +" => " + action.text # set title of window to submenu
|
534
|
+
str = "%s: " % action.text
|
449
535
|
when Proc
|
450
536
|
ret = action.call
|
451
537
|
break
|
452
538
|
when Symbol
|
453
|
-
|
454
|
-
$log.debug "XXX: IO caller responds to action #{action} "
|
455
|
-
ret = @caller.send(action)
|
456
|
-
elsif @caller.respond_to?(:execute_this, true)
|
457
|
-
ret = @caller.send(:execute_this, action)
|
458
|
-
else
|
459
|
-
alert "PromptMenu: unidentified action #{action} for #{@caller.class} "
|
460
|
-
raise "PromptMenu: unidentified action #{action} for #{@caller.class} "
|
461
|
-
end
|
462
|
-
|
539
|
+
ret = @caller.send(action)
|
463
540
|
break
|
464
541
|
else
|
465
542
|
$log.debug " Unidentified flying class #{action.class} "
|
466
543
|
break
|
467
544
|
end
|
468
545
|
end # while
|
469
|
-
|
470
|
-
rc.destroy
|
471
|
-
rc = nil
|
546
|
+
return ret # ret val of last send or call
|
472
547
|
end
|
473
|
-
end
|
474
|
-
alias :display_new :display_columns
|
475
|
-
|
476
|
-
# Display the top level menu and accept user input
|
477
|
-
# Calls actions or symbols upon selection, or traverses submenus
|
478
|
-
# @return retvalue of last call or send, or 0
|
479
|
-
# @param win window
|
480
|
-
# @param r, c row and col to display on
|
481
|
-
# @param color text color (use $datacolor if in doubt)
|
482
|
-
# @see display_new - it presents in a much better manner
|
483
|
-
# and is not restricted to one row. Avoid this.
|
484
|
-
def display win, r, c, color
|
485
|
-
raise "Please use display_new, i've replace this with that"
|
486
|
-
# FIXME use a oneline window, user should not have to give all this crap.
|
487
|
-
# What about panning if we can;t fit, should we use horiz list to show ?
|
488
|
-
menu = @options
|
489
|
-
$log.debug " DISP MENU "
|
490
|
-
ret = 0
|
491
|
-
while true
|
492
|
-
str = @text.dup
|
493
|
-
h = {}
|
494
|
-
valid = []
|
495
|
-
menu.each{ |item|
|
496
|
-
hk = item.hotkey.to_s
|
497
|
-
str << "(%c) %s " % [ hk, item.label ]
|
498
|
-
h[hk] = item
|
499
|
-
valid << hk
|
500
|
-
}
|
501
|
-
#$log.debug " valid are #{valid} "
|
502
|
-
color = $datacolor
|
503
|
-
print_this(win, str, color, r, c)
|
504
|
-
ch=win.getchar()
|
505
|
-
#$log.debug " got ch #{ch} "
|
506
|
-
next if ch < 0 or ch > 255
|
507
|
-
if ch == 3 || ch == ?\C-g.getbyte(0)
|
508
|
-
clear_this win, r, c, color, str.length
|
509
|
-
print_this(win, "Aborted.", color, r,c)
|
510
|
-
break
|
511
|
-
end
|
512
|
-
ch = ch.chr
|
513
|
-
index = valid.index ch
|
514
|
-
if index.nil?
|
515
|
-
clear_this win, r, c, color, str.length
|
516
|
-
print_this(win, "Not valid. Valid are #{valid}", color, r,c)
|
517
|
-
sleep 1
|
518
|
-
next
|
519
|
-
end
|
520
|
-
#$log.debug " index is #{index} "
|
521
|
-
item = h[ch]
|
522
|
-
desc = item.desc
|
523
|
-
#desc ||= "Could not find desc for #{ch} "
|
524
|
-
desc ||= ""
|
525
|
-
clear_this win, r, c, color, str.length
|
526
|
-
print_this(win, desc, color, r,c)
|
527
|
-
action = item.action
|
528
|
-
case action
|
529
|
-
#when Array
|
530
|
-
when PromptMenu
|
531
|
-
# submenu
|
532
|
-
menu = action.options
|
533
|
-
str = "%s: " % action.text
|
534
|
-
when Proc
|
535
|
-
ret = action.call
|
536
|
-
break
|
537
|
-
when Symbol
|
538
|
-
ret = @caller.send(action)
|
539
|
-
break
|
540
|
-
else
|
541
|
-
$log.debug " Unidentified flying class #{action.class} "
|
542
|
-
break
|
543
|
-
end
|
544
|
-
end # while
|
545
|
-
return ret # ret val of last send or call
|
546
|
-
end
|
547
|
-
end # class PromptMenu
|
548
|
+
end # class PromptMenu
|
548
549
|
|
549
|
-
|
550
|
+
### ADD HERE ###
|
550
551
|
|
552
|
+
end # module
|
551
553
|
end # module
|