rbcurse-core 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +69 -0
- data/VERSION +1 -0
- data/examples/abasiclist.rb +151 -0
- data/examples/alpmenu.rb +46 -0
- data/examples/app.sample +17 -0
- data/examples/atree.rb +100 -0
- data/examples/common/file.rb +45 -0
- data/examples/data/README.markdown +9 -0
- data/examples/data/brew.txt +38 -0
- data/examples/data/color.2 +37 -0
- data/examples/data/gemlist.txt +60 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/ports.txt +136 -0
- data/examples/data/table.txt +37 -0
- data/examples/data/tasks.csv +88 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/data/todo.txt +10 -0
- data/examples/data/todocsv.csv +28 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/data/unix2.txt +11 -0
- data/examples/dbdemo.rb +487 -0
- data/examples/dirtree.rb +90 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +132 -0
- data/examples/tasks.rb +167 -0
- data/examples/term2.rb +83 -0
- data/examples/testkeypress.rb +72 -0
- data/examples/testlistbox.rb +158 -0
- data/examples/testmessagebox.rb +140 -0
- data/examples/testree.rb +106 -0
- data/examples/testwsshortcuts.rb +66 -0
- data/examples/testwsshortcuts2.rb +127 -0
- data/lib/rbcurse.rb +8 -0
- data/lib/rbcurse/core/docs/index.txt +73 -0
- data/lib/rbcurse/core/include/action.rb +40 -0
- data/lib/rbcurse/core/include/appmethods.rb +112 -0
- data/lib/rbcurse/core/include/bordertitle.rb +41 -0
- data/lib/rbcurse/core/include/chunk.rb +182 -0
- data/lib/rbcurse/core/include/io.rb +953 -0
- data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
- data/lib/rbcurse/core/include/listeditable.rb +317 -0
- data/lib/rbcurse/core/include/listscrollable.rb +590 -0
- data/lib/rbcurse/core/include/listselectable.rb +264 -0
- data/lib/rbcurse/core/include/multibuffer.rb +83 -0
- data/lib/rbcurse/core/include/orderedhash.rb +77 -0
- data/lib/rbcurse/core/include/ractionevent.rb +67 -0
- data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
- data/lib/rbcurse/core/include/rhistory.rb +62 -0
- data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
- data/lib/rbcurse/core/include/vieditable.rb +170 -0
- data/lib/rbcurse/core/system/colormap.rb +163 -0
- data/lib/rbcurse/core/system/keyboard.rb +150 -0
- data/lib/rbcurse/core/system/keydefs.rb +30 -0
- data/lib/rbcurse/core/system/ncurses.rb +218 -0
- data/lib/rbcurse/core/system/panel.rb +162 -0
- data/lib/rbcurse/core/system/window.rb +901 -0
- data/lib/rbcurse/core/util/ansiparser.rb +117 -0
- data/lib/rbcurse/core/util/app.rb +1235 -0
- data/lib/rbcurse/core/util/basestack.rb +407 -0
- data/lib/rbcurse/core/util/bottomline.rb +1850 -0
- data/lib/rbcurse/core/util/colorparser.rb +71 -0
- data/lib/rbcurse/core/util/focusmanager.rb +31 -0
- data/lib/rbcurse/core/util/padreader.rb +189 -0
- data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
- data/lib/rbcurse/core/util/rdialogs.rb +619 -0
- data/lib/rbcurse/core/util/viewer.rb +149 -0
- data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
- data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
- data/lib/rbcurse/core/widgets/box.rb +58 -0
- data/lib/rbcurse/core/widgets/divider.rb +310 -0
- data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
- data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
- data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
- data/lib/rbcurse/core/widgets/rlink.rb +30 -0
- data/lib/rbcurse/core/widgets/rlist.rb +723 -0
- data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
- data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
- data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
- data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
- data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
- data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
- data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
- data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
- data/lib/rbcurse/core/widgets/rtree.rb +787 -0
- data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
- data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
- data/lib/rbcurse/core/widgets/statusline.rb +94 -0
- data/lib/rbcurse/core/widgets/tabular.rb +264 -0
- data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
- data/lib/rbcurse/core/widgets/textpad.rb +516 -0
- data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
- 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
|