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