rbhex-core 1.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.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/CHANGELOG +2000 -0
- data/LICENSE +56 -0
- data/README.md +44 -0
- data/examples/abasiclist.rb +179 -0
- data/examples/alpmenu.rb +50 -0
- data/examples/app.sample +19 -0
- data/examples/atree.rb +100 -0
- data/examples/bline.rb +136 -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/todo.txt.bak +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 +502 -0
- data/examples/dirtree.rb +94 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +146 -0
- data/examples/tasks.rb +178 -0
- data/examples/term2.rb +84 -0
- data/examples/testbuttons.rb +296 -0
- data/examples/testcombo.rb +102 -0
- data/examples/testfields.rb +195 -0
- data/examples/testkeypress.rb +72 -0
- data/examples/testlistbox.rb +170 -0
- data/examples/testmessagebox.rb +140 -0
- data/examples/testprogress.rb +116 -0
- data/examples/testree.rb +106 -0
- data/examples/testwsshortcuts.rb +66 -0
- data/examples/testwsshortcuts2.rb +128 -0
- data/lib/rbhex.rb +6 -0
- data/lib/rbhex/core/docs/index.txt +73 -0
- data/lib/rbhex/core/include/action.rb +80 -0
- data/lib/rbhex/core/include/actionmanager.rb +49 -0
- data/lib/rbhex/core/include/appmethods.rb +214 -0
- data/lib/rbhex/core/include/bordertitle.rb +48 -0
- data/lib/rbhex/core/include/chunk.rb +203 -0
- data/lib/rbhex/core/include/io.rb +553 -0
- data/lib/rbhex/core/include/listbindings.rb +74 -0
- data/lib/rbhex/core/include/listcellrenderer.rb +140 -0
- data/lib/rbhex/core/include/listeditable.rb +317 -0
- data/lib/rbhex/core/include/listscrollable.rb +663 -0
- data/lib/rbhex/core/include/listselectable.rb +271 -0
- data/lib/rbhex/core/include/multibuffer.rb +83 -0
- data/lib/rbhex/core/include/orderedhash.rb +77 -0
- data/lib/rbhex/core/include/ractionevent.rb +73 -0
- data/lib/rbhex/core/include/rchangeevent.rb +27 -0
- data/lib/rbhex/core/include/rhistory.rb +95 -0
- data/lib/rbhex/core/include/rinputdataevent.rb +47 -0
- data/lib/rbhex/core/include/vieditable.rb +172 -0
- data/lib/rbhex/core/include/widgetmenu.rb +66 -0
- data/lib/rbhex/core/system/colormap.rb +165 -0
- data/lib/rbhex/core/system/keyboard.rb +150 -0
- data/lib/rbhex/core/system/keydefs.rb +30 -0
- data/lib/rbhex/core/system/ncurses.rb +236 -0
- data/lib/rbhex/core/system/panel.rb +162 -0
- data/lib/rbhex/core/system/window.rb +913 -0
- data/lib/rbhex/core/util/ansiparser.rb +119 -0
- data/lib/rbhex/core/util/app.rb +1228 -0
- data/lib/rbhex/core/util/basestack.rb +410 -0
- data/lib/rbhex/core/util/bottomline.rb +1859 -0
- data/lib/rbhex/core/util/colorparser.rb +77 -0
- data/lib/rbhex/core/util/focusmanager.rb +31 -0
- data/lib/rbhex/core/util/padreader.rb +192 -0
- data/lib/rbhex/core/util/rcommandwindow.rb +604 -0
- data/lib/rbhex/core/util/rdialogs.rb +574 -0
- data/lib/rbhex/core/util/viewer.rb +149 -0
- data/lib/rbhex/core/util/widgetshortcuts.rb +506 -0
- data/lib/rbhex/core/version.rb +5 -0
- data/lib/rbhex/core/widgets/applicationheader.rb +103 -0
- data/lib/rbhex/core/widgets/box.rb +58 -0
- data/lib/rbhex/core/widgets/divider.rb +310 -0
- data/lib/rbhex/core/widgets/keylabelprinter.rb +194 -0
- data/lib/rbhex/core/widgets/rcombo.rb +253 -0
- data/lib/rbhex/core/widgets/rcontainer.rb +415 -0
- data/lib/rbhex/core/widgets/rlink.rb +30 -0
- data/lib/rbhex/core/widgets/rlist.rb +696 -0
- data/lib/rbhex/core/widgets/rmenu.rb +958 -0
- data/lib/rbhex/core/widgets/rmenulink.rb +22 -0
- data/lib/rbhex/core/widgets/rmessagebox.rb +387 -0
- data/lib/rbhex/core/widgets/rprogress.rb +118 -0
- data/lib/rbhex/core/widgets/rtabbedpane.rb +634 -0
- data/lib/rbhex/core/widgets/rtabbedwindow.rb +70 -0
- data/lib/rbhex/core/widgets/rtextarea.rb +960 -0
- data/lib/rbhex/core/widgets/rtextview.rb +739 -0
- data/lib/rbhex/core/widgets/rtree.rb +768 -0
- data/lib/rbhex/core/widgets/rwidget.rb +3277 -0
- data/lib/rbhex/core/widgets/scrollbar.rb +143 -0
- data/lib/rbhex/core/widgets/statusline.rb +113 -0
- data/lib/rbhex/core/widgets/tabular.rb +264 -0
- data/lib/rbhex/core/widgets/tabularwidget.rb +1142 -0
- data/lib/rbhex/core/widgets/textpad.rb +995 -0
- data/lib/rbhex/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/rbhex/core/widgets/tree/treemodel.rb +428 -0
- data/rbhex-core.gemspec +32 -0
- metadata +172 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# ----------------------------------------------------------------------------- #
|
|
2
|
+
# File: colorparser.rb
|
|
3
|
+
# Description: Default parse for our tmux format
|
|
4
|
+
# The aim is to be able to specify parsers so different kinds
|
|
5
|
+
# of formatting or documents can be used, such as ANSI formatted
|
|
6
|
+
# manpages.
|
|
7
|
+
# Author: rkumar http://github.com/rkumar/rbcurse/
|
|
8
|
+
# Date: 07.11.11 - 13:17
|
|
9
|
+
# License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
|
10
|
+
# Last update: 2013-04-01 13:43
|
|
11
|
+
# ----------------------------------------------------------------------------- #
|
|
12
|
+
# == TODO
|
|
13
|
+
# - perhaps we can compile the regexp once and reuse
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
module RubyCurses
|
|
17
|
+
class AnsiParser
|
|
18
|
+
|
|
19
|
+
# NOTE: Experimental and minimal
|
|
20
|
+
# parses the formatted string and yields either an array of color, bgcolor and attrib
|
|
21
|
+
# or the text. This will be called by convert_to_chunk.
|
|
22
|
+
#
|
|
23
|
+
# Currently, assumes colors and attributes are correct. No error checking or fancy stuff.
|
|
24
|
+
# s="#[fg=green]hello there#[fg=yellow, bg=black, dim]"
|
|
25
|
+
# @since 1.4.1 2011-11-3 experimental, can change
|
|
26
|
+
# @return [nil] knows nothign about output format.
|
|
27
|
+
|
|
28
|
+
def parse_format s # yields attribs or text
|
|
29
|
+
## set default colors
|
|
30
|
+
color = :white
|
|
31
|
+
bgcolor = :black
|
|
32
|
+
attrib = FFI::NCurses::A_NORMAL
|
|
33
|
+
text = ""
|
|
34
|
+
|
|
35
|
+
## split #[...]
|
|
36
|
+
#a = s.split /(#\[[^\]]*\])/
|
|
37
|
+
a = s.split /(\x1b\[\d*(?:;\d+)*?[a-zA-Z])/
|
|
38
|
+
a.each { |e|
|
|
39
|
+
## process color or attrib portion
|
|
40
|
+
#[ "", "\e[1m", "", "\e[34m", "", "\e[47m", "Showing all items...", "\e[0m", "", "\e[0m", "\n"]
|
|
41
|
+
if e[0,1] == "\x1b" && e[-1,1] == "m"
|
|
42
|
+
|
|
43
|
+
#e.each { |f| x=/^.\[(.*).$/.match(f)
|
|
44
|
+
$log.debug "XXX: ANSI e #{e} "
|
|
45
|
+
x=/^.\[(.*).$/.match(e)
|
|
46
|
+
color, bgcolor, attrib = nil, nil, nil
|
|
47
|
+
$log.debug "XXX: ANSI #{x} ..... #{x[1]} "
|
|
48
|
+
args = x[1].split ';'
|
|
49
|
+
## first split on commas to separate fg, bg and attr
|
|
50
|
+
# http://ascii-table.com/ansi-escape-sequences.php
|
|
51
|
+
args.each { |att|
|
|
52
|
+
$log.debug "XXX: ANSI att: #{att} "
|
|
53
|
+
case att.to_i
|
|
54
|
+
when 0
|
|
55
|
+
color, bgcolor, attrib = nil, nil, nil
|
|
56
|
+
yield :reset # actually this resets all so we need an endall or clearall reset
|
|
57
|
+
|
|
58
|
+
when 1
|
|
59
|
+
attrib = 'bold'
|
|
60
|
+
when 2
|
|
61
|
+
attrib = 'dim'
|
|
62
|
+
when 4
|
|
63
|
+
attrib = 'underline'
|
|
64
|
+
when 5
|
|
65
|
+
attrib = 'blink'
|
|
66
|
+
when 7
|
|
67
|
+
attrib = 'reverse'
|
|
68
|
+
when 8
|
|
69
|
+
attrib = 'hidden' # XXX
|
|
70
|
+
when 30
|
|
71
|
+
color = 'black'
|
|
72
|
+
when 31
|
|
73
|
+
color = 'red'
|
|
74
|
+
when 32
|
|
75
|
+
color = 'green'
|
|
76
|
+
when 33
|
|
77
|
+
color = 'yellow'
|
|
78
|
+
when 34
|
|
79
|
+
color = 'blue'
|
|
80
|
+
when 35
|
|
81
|
+
color = 'magenta'
|
|
82
|
+
when 36
|
|
83
|
+
color = 'cyan'
|
|
84
|
+
when 37
|
|
85
|
+
color = 'white'
|
|
86
|
+
|
|
87
|
+
#Background colors
|
|
88
|
+
when 40
|
|
89
|
+
bgcolor = 'black'
|
|
90
|
+
when 41
|
|
91
|
+
bgcolor = 'red'
|
|
92
|
+
when 42
|
|
93
|
+
bgcolor = 'green'
|
|
94
|
+
when 43
|
|
95
|
+
bgcolor = 'yellow'
|
|
96
|
+
when 44
|
|
97
|
+
bgcolor = 'blue'
|
|
98
|
+
when 45
|
|
99
|
+
bgcolor = 'magenta'
|
|
100
|
+
when 46
|
|
101
|
+
bgcolor = 'cyan'
|
|
102
|
+
when 47
|
|
103
|
+
bgcolor = 'white'
|
|
104
|
+
else
|
|
105
|
+
$log.warn "XXX: WARN ANSI not used #{att} "
|
|
106
|
+
end
|
|
107
|
+
} # args.ea
|
|
108
|
+
#} # e.each
|
|
109
|
+
$log.debug "XXX: ANSI YIELDING #{color} , #{bgcolor} , #{attrib} "
|
|
110
|
+
yield [color,bgcolor,attrib] if block_given?
|
|
111
|
+
else
|
|
112
|
+
text = e
|
|
113
|
+
yield text if block_given?
|
|
114
|
+
end
|
|
115
|
+
} # a.each
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,1228 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
* Name: App
|
|
3
|
+
* Description: Experimental Application class
|
|
4
|
+
* Author: rkumar (arunachalesha)
|
|
5
|
+
* file created 2010-09-04 22:10
|
|
6
|
+
Todo:
|
|
7
|
+
|
|
8
|
+
* 1.5.0 : redo the constructors of these widgets
|
|
9
|
+
as per stack flow improved, and make the constructor
|
|
10
|
+
simpler, no need for jugglery of row col etc. let user
|
|
11
|
+
specify in config.
|
|
12
|
+
--------
|
|
13
|
+
* License:
|
|
14
|
+
Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
|
15
|
+
|
|
16
|
+
=end
|
|
17
|
+
require 'logger'
|
|
18
|
+
require 'rbhex'
|
|
19
|
+
require 'rbhex/core/util/widgetshortcuts'
|
|
20
|
+
|
|
21
|
+
include RubyCurses
|
|
22
|
+
include RubyCurses::Utils
|
|
23
|
+
include Io
|
|
24
|
+
module RubyCurses
|
|
25
|
+
extend self
|
|
26
|
+
##
|
|
27
|
+
#
|
|
28
|
+
# @since 1.2.0
|
|
29
|
+
# TODO -
|
|
30
|
+
# / combo
|
|
31
|
+
# - popup
|
|
32
|
+
# - promptmenu
|
|
33
|
+
# - stack and flow should be objects in Form/App?, put in widget when creating
|
|
34
|
+
# - box / rect
|
|
35
|
+
# - para looks like a label that is more than one line, and calculates rows itself based on text
|
|
36
|
+
# - multicontainer
|
|
37
|
+
# - multitextview, multisplit
|
|
38
|
+
# - tabbedpane
|
|
39
|
+
# / table - more work regarding vim keys, also editable
|
|
40
|
+
# - margin - is left offset
|
|
41
|
+
# http://lethain.com/entry/2007/oct/15/getting-started-shoes-os-x/
|
|
42
|
+
#
|
|
43
|
+
|
|
44
|
+
class Widget
|
|
45
|
+
def changed *args, &block
|
|
46
|
+
bind :CHANGED, *args, &block
|
|
47
|
+
end
|
|
48
|
+
def leave *args, &block
|
|
49
|
+
bind :LEAVE, *args, &block
|
|
50
|
+
end
|
|
51
|
+
def enter *args, &block
|
|
52
|
+
bind :ENTER, *args, &block
|
|
53
|
+
end
|
|
54
|
+
# actually we already have command() for buttons
|
|
55
|
+
def click *args, &block
|
|
56
|
+
bind :PRESS, *args, &block
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
class CheckBox
|
|
60
|
+
# a little dicey XXX
|
|
61
|
+
def text(*val)
|
|
62
|
+
if val.empty?
|
|
63
|
+
@value ? @onvalue : @offvalue
|
|
64
|
+
else
|
|
65
|
+
super
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
# This is the Application class which does the job of setting up the
|
|
70
|
+
# environment, and closing it at the end.
|
|
71
|
+
class App
|
|
72
|
+
include RubyCurses::WidgetShortcuts
|
|
73
|
+
attr_reader :config
|
|
74
|
+
attr_reader :form
|
|
75
|
+
attr_reader :window
|
|
76
|
+
attr_writer :quit_key
|
|
77
|
+
# the row on which to prompt user for any inputs
|
|
78
|
+
#attr_accessor :prompt_row # 2011-10-17 14:06:22
|
|
79
|
+
|
|
80
|
+
# TODO: i should be able to pass window coords here in config
|
|
81
|
+
# :title
|
|
82
|
+
def initialize config={}, &block
|
|
83
|
+
#$log.debug " inside constructor of APP #{config} "
|
|
84
|
+
@config = config
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
widget_shortcuts_init
|
|
88
|
+
#@app_row = @app_col = 0
|
|
89
|
+
#@stack = [] # stack's coordinates
|
|
90
|
+
#@flowstack = []
|
|
91
|
+
@variables = {}
|
|
92
|
+
# if we are creating child objects then we will not use outer form. this object will manage
|
|
93
|
+
@current_object = []
|
|
94
|
+
@_system_commands = %w{ bind_global bind_component field_help_text }
|
|
95
|
+
|
|
96
|
+
init_vars
|
|
97
|
+
$log.debug "XXX APP CONFIG: #{@config} " if $log.debug?
|
|
98
|
+
run &block
|
|
99
|
+
end
|
|
100
|
+
def init_vars
|
|
101
|
+
@quit_key ||= FFI::NCurses::KEY_F10
|
|
102
|
+
# actually this should be maintained inside ncurses pack, so not loaded 2 times.
|
|
103
|
+
# this way if we call an app from existing program, App won't start ncurses.
|
|
104
|
+
unless $ncurses_started
|
|
105
|
+
init_ncurses
|
|
106
|
+
end
|
|
107
|
+
$lastline = Ncurses.LINES - 1
|
|
108
|
+
#@message_row = Ncurses.LINES-1
|
|
109
|
+
#@prompt_row = @message_row # hope to use for ask etc # 2011-10-17 14:06:27
|
|
110
|
+
unless $log
|
|
111
|
+
path = File.join(ENV["LOGDIR"] || "./" ,"rbc13.log")
|
|
112
|
+
file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT)
|
|
113
|
+
$log = Logger.new(path)
|
|
114
|
+
$log.level = Logger::DEBUG # change to warn when you've tested your app.
|
|
115
|
+
colors = Ncurses.COLORS
|
|
116
|
+
$log.debug "START #{colors} colors --------- #{$0} win: #{@window} "
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
def logger; return $log; end
|
|
120
|
+
def close
|
|
121
|
+
raw_message_destroy
|
|
122
|
+
$log.debug " INSIDE CLOSE, #{@stop_ncurses_on_close} "
|
|
123
|
+
@window.destroy if !@window.nil?
|
|
124
|
+
$log.debug " INSIDE CLOSE, #{@stop_ncurses_on_close} "
|
|
125
|
+
if @stop_ncurses_on_close
|
|
126
|
+
$tt.destroy if $tt # added on 2011-10-9 since we created a window, but only hid it after use
|
|
127
|
+
VER::stop_ncurses
|
|
128
|
+
$log.debug " CLOSING NCURSES"
|
|
129
|
+
end
|
|
130
|
+
#p $error_message.value unless $error_message.value.nil?
|
|
131
|
+
$log.debug " CLOSING APP"
|
|
132
|
+
#end
|
|
133
|
+
end
|
|
134
|
+
# not sure, but user shuld be able to trap keystrokes if he wants
|
|
135
|
+
# but do i still call handle_key if he does, or give him total control.
|
|
136
|
+
# But loop is already called by framework
|
|
137
|
+
def loop &block
|
|
138
|
+
@form.repaint
|
|
139
|
+
@window.wrefresh
|
|
140
|
+
Ncurses::Panel.update_panels
|
|
141
|
+
@break_key = ?\C-q.getbyte(0)
|
|
142
|
+
# added this extra loop since from some places we exit using throw :close
|
|
143
|
+
# amd that was in a much higher place, and was getting us right out, with
|
|
144
|
+
# no chance of user canceling quit. This extra loop allows us to remain
|
|
145
|
+
# added on 2011-11-24
|
|
146
|
+
while true
|
|
147
|
+
catch :close do
|
|
148
|
+
while((ch = @window.getchar()) != 999 )
|
|
149
|
+
#break if ch == @break_key
|
|
150
|
+
if ch == @break_key || ch == @quit_key
|
|
151
|
+
#stopping = @window.fire_close_handler
|
|
152
|
+
#break if stopping.nil? || stopping
|
|
153
|
+
break
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
if @keyblock
|
|
157
|
+
str = keycode_tos ch
|
|
158
|
+
@keyblock.call(str.gsub(/-/, "_").to_sym) # not used ever
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
yield ch if block # <<<----
|
|
162
|
+
# this is what the user should have control ove. earlier we would put this in
|
|
163
|
+
# a try catch block so user could do what he wanted with the error. Now we
|
|
164
|
+
# need to get it to him somehow, perhaps through a block or on_error event
|
|
165
|
+
begin
|
|
166
|
+
@form.handle_key ch
|
|
167
|
+
rescue => err
|
|
168
|
+
$log.debug( "handle_key rescue reached ")
|
|
169
|
+
$log.debug( err.to_s)
|
|
170
|
+
$log.debug(err.backtrace.join("\n"))
|
|
171
|
+
textdialog [err.to_s, *err.backtrace], :title => "Exception"
|
|
172
|
+
end
|
|
173
|
+
#@form.repaint # was this duplicate ?? handle calls repaint not needed
|
|
174
|
+
@window.wrefresh
|
|
175
|
+
end
|
|
176
|
+
end # catch
|
|
177
|
+
stopping = @window.fire_close_handler
|
|
178
|
+
@window.wrefresh
|
|
179
|
+
break if stopping.nil? || stopping
|
|
180
|
+
end # while
|
|
181
|
+
end
|
|
182
|
+
# if calling loop separately better to call this, since it will shut off ncurses
|
|
183
|
+
# and print error on screen.
|
|
184
|
+
def safe_loop &block
|
|
185
|
+
begin
|
|
186
|
+
loop &block
|
|
187
|
+
rescue => ex
|
|
188
|
+
$log.debug( "APP.rb rescue reached ")
|
|
189
|
+
$log.debug( ex) if ex
|
|
190
|
+
$log.debug(ex.backtrace.join("\n")) if ex
|
|
191
|
+
ensure
|
|
192
|
+
close
|
|
193
|
+
# putting it here allows it to be printed on screen, otherwise it was not showing at all.
|
|
194
|
+
if ex
|
|
195
|
+
puts "========== EXCEPTION =========="
|
|
196
|
+
p ex
|
|
197
|
+
puts "==============================="
|
|
198
|
+
puts(ex.backtrace.join("\n"))
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
# returns a symbol of the key pressed
|
|
203
|
+
# e.g. :C_c for Ctrl-C
|
|
204
|
+
# :Space, :bs, :M_d etc
|
|
205
|
+
def keypress &block
|
|
206
|
+
@keyblock = block
|
|
207
|
+
end
|
|
208
|
+
# updates a global var with text. Calling app has to set up a Variable with that name and attach to
|
|
209
|
+
# a label so it can be printed.
|
|
210
|
+
def message text
|
|
211
|
+
$status_message.value = text # trying out 2011-10-9
|
|
212
|
+
#@message.value = text # 2011-10-17 14:07:01
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# during a process, when you wish to update status, since ordinarily the thread is busy
|
|
216
|
+
# and form does not get control back, so the window won't refresh.
|
|
217
|
+
# This will only update on keystroke since it uses statusline
|
|
218
|
+
# @deprecated please use {#status_line} instead of a message label
|
|
219
|
+
def message_immediate text
|
|
220
|
+
$log.warn "DEPRECATED, use message(), or rb_puts or use status_window"
|
|
221
|
+
$status_message.value = text # trying out 2011-10-9 user needs to use in statusline command
|
|
222
|
+
# 2011-10-17 knocking off label, should be printed on status_line
|
|
223
|
+
end
|
|
224
|
+
# Usage: application is inside a long processing loop and wishes to print ongoing status
|
|
225
|
+
# NOTE: if you use this, you must use raw_message_destroy at some stage, after processing
|
|
226
|
+
# or on_leave of object.
|
|
227
|
+
# @deprecated Use say_with_pause or use rdialogs status_window, see test2.rb
|
|
228
|
+
def raw_message text, config={}, &blk
|
|
229
|
+
$raw_window ||= one_line_window last_line(), config, &blk
|
|
230
|
+
width = $raw_window.width == 0 ? FFI::NCurses.COLS : $raw_window.width
|
|
231
|
+
text = "%-*s" % [width, text]
|
|
232
|
+
|
|
233
|
+
$raw_window.attron(Ncurses.COLOR_PAIR($normalcolor) )
|
|
234
|
+
$raw_window.printstring 0,0,text, $normalcolor #, 'normal' if @title
|
|
235
|
+
$raw_window.wrefresh
|
|
236
|
+
|
|
237
|
+
end
|
|
238
|
+
def raw_message_destroy
|
|
239
|
+
if $raw_window
|
|
240
|
+
$raw_window.destroy
|
|
241
|
+
$raw_window = nil
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
# shows a simple progress bar on last row, using stdscr
|
|
245
|
+
# @param [Float, Array<Fixnum,Fixnum>] percentage, or part/total
|
|
246
|
+
# If Array of two numbers is given then also print part/total on left of bar
|
|
247
|
+
# @deprecated - don't use stdscr at all, use rdialogs status_window (see test2.rb)
|
|
248
|
+
def raw_progress arg
|
|
249
|
+
$log.warning "WARNING: don't use this method as it uses stdscr"
|
|
250
|
+
row = @message_label ? @message_label.row : Ncurses.LINES-1
|
|
251
|
+
s = nil
|
|
252
|
+
case arg
|
|
253
|
+
when Array
|
|
254
|
+
#calculate percentage
|
|
255
|
+
pc = (arg[0]*1.0)/arg[1]
|
|
256
|
+
# print items/total also
|
|
257
|
+
s = "%-10s" % "(#{arg[0]}/#{arg[1]})"
|
|
258
|
+
when
|
|
259
|
+
Float
|
|
260
|
+
pc = arg
|
|
261
|
+
end
|
|
262
|
+
scr = Ncurses.stdscr
|
|
263
|
+
endcol = Ncurses.COLS-1
|
|
264
|
+
startcol = endcol - 12
|
|
265
|
+
stext = ("=" * (pc*10).to_i)
|
|
266
|
+
text = "[" + "%-10s" % stext + "]"
|
|
267
|
+
Ncurses.mvprintw( row ,startcol-10, s) if s
|
|
268
|
+
Ncurses.mvprintw row ,startcol, text
|
|
269
|
+
#scr.refresh() # XXX FFI NW
|
|
270
|
+
|
|
271
|
+
end
|
|
272
|
+
# used only by LiveConsole, if enables in an app, usually only during testing.
|
|
273
|
+
def get_binding
|
|
274
|
+
return binding()
|
|
275
|
+
end
|
|
276
|
+
#
|
|
277
|
+
# suspends curses so you can play around on the shell
|
|
278
|
+
# or in cooked mode like Vim does. Expects a block to be passed.
|
|
279
|
+
# Purpose: you can print some stuff without creating a window, or
|
|
280
|
+
# just run shell commands without coming out.
|
|
281
|
+
# NOTE: if you pass clear as true, then the screen will be cleared
|
|
282
|
+
# and you can use puts or print to print. You may have to flush.
|
|
283
|
+
# However, with clear as false, the screen will not be cleared. You
|
|
284
|
+
# will have to print using printw, and if you expect user input
|
|
285
|
+
# you must do a "system /bin/stty sane"
|
|
286
|
+
# If you print stuff, you will have to put a getch() or system("read")
|
|
287
|
+
# to pause the screen.
|
|
288
|
+
def suspend clear=true
|
|
289
|
+
return unless block_given?
|
|
290
|
+
Ncurses.def_prog_mode
|
|
291
|
+
if clear
|
|
292
|
+
Ncurses.endwin
|
|
293
|
+
# NOTE: avoid false since screen remains half off
|
|
294
|
+
# too many issues
|
|
295
|
+
else
|
|
296
|
+
system "/bin/stty sane"
|
|
297
|
+
end
|
|
298
|
+
yield if block_given?
|
|
299
|
+
Ncurses.reset_prog_mode
|
|
300
|
+
if !clear
|
|
301
|
+
# Hope we don't screw your terminal up with this constantly.
|
|
302
|
+
VER::stop_ncurses
|
|
303
|
+
VER::start_ncurses
|
|
304
|
+
#@form.reset_all # not required
|
|
305
|
+
end
|
|
306
|
+
@form.repaint
|
|
307
|
+
@window.wrefresh
|
|
308
|
+
Ncurses::Panel.update_panels
|
|
309
|
+
end
|
|
310
|
+
def get_all_commands
|
|
311
|
+
opts = @_system_commands.dup
|
|
312
|
+
if respond_to? :get_commands
|
|
313
|
+
opts.push(*get_commands())
|
|
314
|
+
end
|
|
315
|
+
opts
|
|
316
|
+
end
|
|
317
|
+
# bind a key to a method at global (form) level
|
|
318
|
+
# Note that individual component may be overriding this.
|
|
319
|
+
# FIXME: why are we using rawmessage and then getchar when ask would suffice
|
|
320
|
+
def bind_global
|
|
321
|
+
opts = get_all_commands
|
|
322
|
+
cmd = rb_gets("Select a command (<tab> for choices) : ", opts)
|
|
323
|
+
if cmd.nil? || cmd == ""
|
|
324
|
+
rb_puts "Aborted."
|
|
325
|
+
return
|
|
326
|
+
end
|
|
327
|
+
key = []
|
|
328
|
+
str = ""
|
|
329
|
+
#raw_message "Enter one or 2 keys. Finish with ENTER. Enter first key:"
|
|
330
|
+
#ch = @window.getchar()
|
|
331
|
+
#raw_message_destroy
|
|
332
|
+
#if [KEY_ENTER, 10, 13, ?\C-g.getbyte(0)].include? ch
|
|
333
|
+
#say_with_pause "Aborted."
|
|
334
|
+
#return
|
|
335
|
+
#end
|
|
336
|
+
# the next is fine but does not allow user to enter a control or alt or function character
|
|
337
|
+
# since it uses Field. It is fine if you want to force alphanum input
|
|
338
|
+
ch = rb_getchar("Enter one or two keys. Finish with <ENTER>. Enter first key:")
|
|
339
|
+
unless ch
|
|
340
|
+
rb_puts "Aborted. <Press a key>"
|
|
341
|
+
return
|
|
342
|
+
end
|
|
343
|
+
key << ch
|
|
344
|
+
str << keycode_tos(ch)
|
|
345
|
+
ch = rb_getchar "Got #{str}. Enter second key or hit return:"
|
|
346
|
+
unless ch
|
|
347
|
+
rb_puts "Aborted. <Press a key>"
|
|
348
|
+
return
|
|
349
|
+
end
|
|
350
|
+
if ch == KEY_ENTER || ch == 13
|
|
351
|
+
else
|
|
352
|
+
key << ch
|
|
353
|
+
str << keycode_tos(ch)
|
|
354
|
+
end
|
|
355
|
+
if !key.empty?
|
|
356
|
+
rb_puts "Binding #{cmd} to #{str}. "
|
|
357
|
+
key = key[0] if key.size == 1
|
|
358
|
+
#@form.bind_key(key, cmd.to_sym) # not finding it, getting called by that comp
|
|
359
|
+
@form.bind_key(key){ send(cmd.to_sym) }
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
def bind_component
|
|
363
|
+
#rb_puts "Todo. ", :color_pair => get_color($promptcolor, :red, :black)
|
|
364
|
+
print_error_message "Todo this. "
|
|
365
|
+
# the idea here is to get the current component
|
|
366
|
+
# and bind some keys to some methods.
|
|
367
|
+
# however, how do we divine the methods we can map to
|
|
368
|
+
# and also in some cases the components itself has multiple components
|
|
369
|
+
end
|
|
370
|
+
# displays help_text associated with field. 2011-10-15
|
|
371
|
+
def field_help_text
|
|
372
|
+
f = @form.get_current_field
|
|
373
|
+
if f.respond_to?('help_text')
|
|
374
|
+
h = f.help_text
|
|
375
|
+
h = "No help text defined for this field.\nTry F1, or press '?' for key-bindings." unless h
|
|
376
|
+
textdialog "#{h}", :title => "Widget Help Text"
|
|
377
|
+
else
|
|
378
|
+
alert "Could not get field #{f} or does not respond to helptext. Try F1 or '?'"
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
# prompts user for a command. we need to get this back to the calling app
|
|
382
|
+
# or have some block stuff TODO
|
|
383
|
+
# Actually, this is naive, you would want to pass some values in like current data value
|
|
384
|
+
# or lines ??
|
|
385
|
+
# Also may want command completion, or help so all commands can be displayed
|
|
386
|
+
# NOTE: This is gonna change very soon - 2012-01-8
|
|
387
|
+
def get_command_from_user choices=["quit","help", "suspend", "shell_output"]
|
|
388
|
+
@_command_history ||= Array.new
|
|
389
|
+
str = rb_gets("Cmd: ", choices) { |q| q.default = @_previous_command; q.history = @_command_history }
|
|
390
|
+
@_command_history << str unless @_command_history.include? str
|
|
391
|
+
# shell the command
|
|
392
|
+
if str =~ /^!/
|
|
393
|
+
str = str[1..-1]
|
|
394
|
+
suspend(false) {
|
|
395
|
+
#system(str);
|
|
396
|
+
$log.debug "XXX STR #{str} " if $log.debug?
|
|
397
|
+
|
|
398
|
+
output=`#{str}`
|
|
399
|
+
system("echo ' ' ");
|
|
400
|
+
$log.debug "XXX output #{output} " if $log.debug?
|
|
401
|
+
system("echo '#{output}' ");
|
|
402
|
+
system("echo Press Enter to continue.");
|
|
403
|
+
system("read");
|
|
404
|
+
}
|
|
405
|
+
return nil # i think
|
|
406
|
+
else
|
|
407
|
+
# TODO
|
|
408
|
+
# here's where we can take internal commands
|
|
409
|
+
#alert "[#{str}] string did not match :!"
|
|
410
|
+
str = str.to_s #= str[1..-1]
|
|
411
|
+
cmdline = str.split
|
|
412
|
+
cmd = cmdline.shift #.to_sym
|
|
413
|
+
return unless cmd # added 2011-09-11 FFI
|
|
414
|
+
f = @form.get_current_field
|
|
415
|
+
if respond_to?(cmd, true)
|
|
416
|
+
if cmd == "close"
|
|
417
|
+
throw :close # other seg faults in del_panel window.destroy executes 2x
|
|
418
|
+
else
|
|
419
|
+
res = send cmd, *cmdline
|
|
420
|
+
end
|
|
421
|
+
elsif f.respond_to?(cmd, true)
|
|
422
|
+
res = f.send(cmd, *cmdline)
|
|
423
|
+
else
|
|
424
|
+
alert "App: #{self.class} does not respond to #{cmd} "
|
|
425
|
+
ret = false
|
|
426
|
+
# what is this execute_this: some kind of general routine for all apps ?
|
|
427
|
+
ret = execute_this(cmd, *cmdline) if respond_to?(:execute_this, true)
|
|
428
|
+
rb_puts("#{self.class} does not respond to #{cmd} ", :color_pair => $promptcolor) unless ret
|
|
429
|
+
# should be able to say in red as error
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
#
|
|
434
|
+
# @group methods to create widgets easily
|
|
435
|
+
#
|
|
436
|
+
# process arguments based on datatype, perhaps making configuration
|
|
437
|
+
# of some components easier for caller avoiding too much boiler plate code
|
|
438
|
+
#
|
|
439
|
+
# create a field
|
|
440
|
+
def OLDfield *args, &block
|
|
441
|
+
config = {}
|
|
442
|
+
events = [ :CHANGED, :LEAVE, :ENTER, :CHANGE ]
|
|
443
|
+
block_event = :CHANGED # LEAVE, ENTER, CHANGE
|
|
444
|
+
|
|
445
|
+
_process_args args, config, block_event, events
|
|
446
|
+
config.delete(:title)
|
|
447
|
+
_position config
|
|
448
|
+
# hope next line doesn't bonk anything
|
|
449
|
+
config[:display_length] ||= @stack.last.width if @stack.last # added here not sure 2010-11-17 18:43
|
|
450
|
+
field = Field.new @form, config
|
|
451
|
+
# shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
|
|
452
|
+
if block
|
|
453
|
+
field.bind(block_event, &block)
|
|
454
|
+
end
|
|
455
|
+
return field
|
|
456
|
+
end
|
|
457
|
+
#instance_eval &block if block_given?
|
|
458
|
+
# or
|
|
459
|
+
#@blk = block # for later execution using @blk.call()
|
|
460
|
+
#colorlabel = Label.new @form, {'text' => "Select a color:", "row" => row, "col" => col, "color"=>"cyan", "mnemonic" => 'S'}
|
|
461
|
+
#var = RubyCurses::Label.new @form, {'text_variable' => $results, "row" => r, "col" => fc}
|
|
462
|
+
|
|
463
|
+
def OLDlabel *args
|
|
464
|
+
events = block_event = nil
|
|
465
|
+
config = {}
|
|
466
|
+
_process_args args, config, block_event, events
|
|
467
|
+
config[:text] ||= config[:name]
|
|
468
|
+
config[:height] ||= 1
|
|
469
|
+
config.delete(:title)
|
|
470
|
+
_position(config)
|
|
471
|
+
label = Label.new @form, config
|
|
472
|
+
# shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
|
|
473
|
+
return label
|
|
474
|
+
end
|
|
475
|
+
alias :text :label
|
|
476
|
+
def OLDbutton *args, &block
|
|
477
|
+
config = {}
|
|
478
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
|
479
|
+
block_event = :PRESS
|
|
480
|
+
|
|
481
|
+
_process_args args, config, block_event, events
|
|
482
|
+
config[:text] ||= config[:name]
|
|
483
|
+
config.delete(:title)
|
|
484
|
+
# flow gets precedence over stack
|
|
485
|
+
_position(config)
|
|
486
|
+
button = Button.new @form, config
|
|
487
|
+
# shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
|
|
488
|
+
if block
|
|
489
|
+
button.bind(block_event, &block)
|
|
490
|
+
end
|
|
491
|
+
return button
|
|
492
|
+
end
|
|
493
|
+
#
|
|
494
|
+
# create a list
|
|
495
|
+
# Since we are mouseless, one can traverse without selection. So we have a different
|
|
496
|
+
# way of selecting row/s and traversal. XXX this aspect of LB's has always troubled me hugely.
|
|
497
|
+
def OLDedit_list *args, &block # earlier list_box
|
|
498
|
+
config = {}
|
|
499
|
+
# TODO confirm events
|
|
500
|
+
# listdataevent has interval added and interval removed, due to multiple
|
|
501
|
+
# selection, we have to make that simple for user here.
|
|
502
|
+
events = [ :LEAVE, :ENTER, :ENTER_ROW, :LEAVE_ROW, :LIST_DATA_EVENT ]
|
|
503
|
+
# TODO how to do this so he gets selected row easily
|
|
504
|
+
block_event = :ENTER_ROW
|
|
505
|
+
|
|
506
|
+
_process_args args, config, block_event, events
|
|
507
|
+
# naive defaults, since list could be large or have very long items
|
|
508
|
+
# usually user will provide
|
|
509
|
+
if !config.has_key? :height
|
|
510
|
+
ll = 0
|
|
511
|
+
ll = config[:list].length + 2 if config.has_key? :list
|
|
512
|
+
config[:height] ||= ll
|
|
513
|
+
config[:height] = 15 if config[:height] > 20
|
|
514
|
+
end
|
|
515
|
+
if @current_object.empty?
|
|
516
|
+
$log.debug "1 APP LB w: #{config[:width]} ,#{config[:name]} "
|
|
517
|
+
config[:width] ||= @stack.last.width if @stack.last
|
|
518
|
+
$log.debug "2 APP LB w: #{config[:width]} "
|
|
519
|
+
config[:width] ||= longest_in_list(config[:list])+2
|
|
520
|
+
$log.debug "3 APP LB w: #{config[:width]} "
|
|
521
|
+
end
|
|
522
|
+
# if no width given, expand to flows width XXX SHOULD BE NOT EXPAND ?
|
|
523
|
+
#config[:width] ||= @stack.last.width if @stack.last
|
|
524
|
+
#if config.has_key? :choose
|
|
525
|
+
config[:default_values] = config.delete :choose
|
|
526
|
+
# we make the default single unless specified
|
|
527
|
+
config[:selection_mode] = :single unless config.has_key? :selection_mode
|
|
528
|
+
if @current_object.empty?
|
|
529
|
+
if @instack
|
|
530
|
+
# most likely you won't have row and col. should we check or just go ahead
|
|
531
|
+
col = @stack.last.margin
|
|
532
|
+
config[:row] = @app_row
|
|
533
|
+
config[:col] = col
|
|
534
|
+
@app_row += config[:height] # this needs to take into account height of prev object
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
useform = nil
|
|
538
|
+
useform = @form if @current_object.empty?
|
|
539
|
+
field = EditList.new useform, config # earlier ListBox
|
|
540
|
+
# shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
|
|
541
|
+
if block
|
|
542
|
+
# this way you can't pass params to the block
|
|
543
|
+
field.bind(block_event, &block)
|
|
544
|
+
end
|
|
545
|
+
return field
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
# toggle button
|
|
549
|
+
def OLDtoggle *args, &block
|
|
550
|
+
config = {}
|
|
551
|
+
# TODO confirm events
|
|
552
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
|
553
|
+
block_event = :PRESS
|
|
554
|
+
_process_args args, config, block_event, events
|
|
555
|
+
config[:text] ||= longest_in_list2( [config[:onvalue], config[:offvalue]])
|
|
556
|
+
#config[:onvalue] # needed for flow, we need a better way FIXME
|
|
557
|
+
_position(config)
|
|
558
|
+
toggle = ToggleButton.new @form, config
|
|
559
|
+
if block
|
|
560
|
+
toggle.bind(block_event, &block)
|
|
561
|
+
end
|
|
562
|
+
return toggle
|
|
563
|
+
end
|
|
564
|
+
# check button
|
|
565
|
+
def OLDcheck *args, &block
|
|
566
|
+
config = {}
|
|
567
|
+
# TODO confirm events
|
|
568
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
|
569
|
+
block_event = :PRESS
|
|
570
|
+
_process_args args, config, block_event, events
|
|
571
|
+
_position(config)
|
|
572
|
+
toggle = CheckBox.new @form, config
|
|
573
|
+
if block
|
|
574
|
+
toggle.bind(block_event, &block)
|
|
575
|
+
end
|
|
576
|
+
return toggle
|
|
577
|
+
end
|
|
578
|
+
# radio button
|
|
579
|
+
def OLDradio *args, &block
|
|
580
|
+
config = {}
|
|
581
|
+
# TODO confirm events
|
|
582
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
|
583
|
+
block_event = :PRESS
|
|
584
|
+
_process_args args, config, block_event, events
|
|
585
|
+
a = config[:group]
|
|
586
|
+
# FIXME we should check if user has set a varialbe in :variable.
|
|
587
|
+
# we should create a variable, so he can use it if he wants.
|
|
588
|
+
if @variables.has_key? a
|
|
589
|
+
v = @variables[a]
|
|
590
|
+
else
|
|
591
|
+
v = Variable.new
|
|
592
|
+
@variables[a] = v
|
|
593
|
+
end
|
|
594
|
+
config[:variable] = v
|
|
595
|
+
config.delete(:group)
|
|
596
|
+
_position(config)
|
|
597
|
+
radio = RadioButton.new @form, config
|
|
598
|
+
if block
|
|
599
|
+
radio.bind(block_event, &block)
|
|
600
|
+
end
|
|
601
|
+
return radio
|
|
602
|
+
end
|
|
603
|
+
# editable text area
|
|
604
|
+
def OLDtextarea *args, &block
|
|
605
|
+
require 'rbhex/core/widgets/rtextarea'
|
|
606
|
+
config = {}
|
|
607
|
+
# TODO confirm events many more
|
|
608
|
+
events = [ :CHANGE, :LEAVE, :ENTER ]
|
|
609
|
+
block_event = events[0]
|
|
610
|
+
_process_args args, config, block_event, events
|
|
611
|
+
config[:width] = config[:display_length] unless config.has_key? :width
|
|
612
|
+
_position(config)
|
|
613
|
+
# if no width given, expand to flows width
|
|
614
|
+
config[:width] ||= @stack.last.width if @stack.last
|
|
615
|
+
useform = nil
|
|
616
|
+
useform = @form if @current_object.empty?
|
|
617
|
+
w = TextArea.new useform, config
|
|
618
|
+
if block
|
|
619
|
+
w.bind(block_event, &block)
|
|
620
|
+
end
|
|
621
|
+
return w
|
|
622
|
+
end
|
|
623
|
+
# similar definitions for textview and resultsettextview
|
|
624
|
+
# NOTE This is not allowing me to send blocks,
|
|
625
|
+
# so do not use for containers
|
|
626
|
+
{
|
|
627
|
+
'rbhex/core/widgets/rtextview' => 'TextView',
|
|
628
|
+
'rbhex/experimental/resultsettextview' => 'ResultsetTextView',
|
|
629
|
+
'rbhex/core/widgets/rcontainer' => 'Container',
|
|
630
|
+
'rbhex/extras/rcontainer2' => 'Container2',
|
|
631
|
+
}.each_pair {|k,p|
|
|
632
|
+
eval(
|
|
633
|
+
"def OLD#{p.downcase} *args, &block
|
|
634
|
+
require \"#{k}\"
|
|
635
|
+
config = {}
|
|
636
|
+
# TODO confirm events many more
|
|
637
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
|
638
|
+
block_event = events[0]
|
|
639
|
+
_process_args args, config, block_event, events
|
|
640
|
+
config[:width] = config[:display_length] unless config.has_key? :width
|
|
641
|
+
_position(config)
|
|
642
|
+
# if no width given, expand to flows width
|
|
643
|
+
config[:width] ||= @stack.last.width if @stack.last
|
|
644
|
+
raise \"height needed for #{p.downcase}\" if !config.has_key? :height
|
|
645
|
+
useform = nil
|
|
646
|
+
useform = @form if @current_object.empty?
|
|
647
|
+
w = #{p}.new useform, config
|
|
648
|
+
if block
|
|
649
|
+
w.bind(block_event, &block)
|
|
650
|
+
end
|
|
651
|
+
return w
|
|
652
|
+
end"
|
|
653
|
+
)
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
# table widget
|
|
657
|
+
# @example
|
|
658
|
+
# data = [["Roger",16,"SWI"], ["Phillip",1, "DEU"]]
|
|
659
|
+
# colnames = ["Name", "Wins", "Place"]
|
|
660
|
+
# t = table :width => 40, :height => 10, :columns => colnames, :data => data, :estimate_widths => true
|
|
661
|
+
# other options are :column_widths => [12,4,12]
|
|
662
|
+
# :size_to_fit => true
|
|
663
|
+
def edit_table *args, &block # earlier table
|
|
664
|
+
require 'rbhex/extras/widgets/rtable'
|
|
665
|
+
config = {}
|
|
666
|
+
# TODO confirm events many more
|
|
667
|
+
events = [ :ENTER_ROW, :LEAVE, :ENTER ]
|
|
668
|
+
block_event = events[0]
|
|
669
|
+
_process_args args, config, block_event, events
|
|
670
|
+
# if user is leaving out width, then we don't want it in config
|
|
671
|
+
# else Widget will put a value of 10 as default, overriding what we've calculated
|
|
672
|
+
if config.has_key? :display_length
|
|
673
|
+
config[:width] = config[:display_length] unless config.has_key? :width
|
|
674
|
+
end
|
|
675
|
+
ext = config.delete :extended_keys
|
|
676
|
+
|
|
677
|
+
model = nil
|
|
678
|
+
_position(config)
|
|
679
|
+
# if no width given, expand to flows width
|
|
680
|
+
config[:width] ||= @stack.last.width if @stack.last
|
|
681
|
+
w = Table.new @form, config
|
|
682
|
+
if ext
|
|
683
|
+
require 'rbhex/extras/include/tableextended'
|
|
684
|
+
# so we can increase and decrease column width using keys
|
|
685
|
+
w.extend TableExtended
|
|
686
|
+
w.bind_key(?w){ w.next_column }
|
|
687
|
+
w.bind_key(?b){ w.previous_column }
|
|
688
|
+
w.bind_key(?+) { w.increase_column }
|
|
689
|
+
w.bind_key(?-) { w.decrease_column }
|
|
690
|
+
w.bind_key([?d, ?d]) { w.table_model.delete_at w.current_index }
|
|
691
|
+
w.bind_key(?u) { w.table_model.undo w.current_index}
|
|
692
|
+
end
|
|
693
|
+
if block
|
|
694
|
+
w.bind(block_event, &block)
|
|
695
|
+
end
|
|
696
|
+
return w
|
|
697
|
+
end
|
|
698
|
+
# print a title on first row
|
|
699
|
+
def title string, config={}
|
|
700
|
+
## TODO center it
|
|
701
|
+
@window.printstring 1, 30, string, $normalcolor, 'reverse'
|
|
702
|
+
end
|
|
703
|
+
# print a sutitle on second row
|
|
704
|
+
def subtitle string, config={}
|
|
705
|
+
@window.printstring 2, 30, string, $datacolor, 'normal'
|
|
706
|
+
end
|
|
707
|
+
# menu bar
|
|
708
|
+
|
|
709
|
+
# creates a blank row
|
|
710
|
+
def OLDblank rows=1, config={}
|
|
711
|
+
@app_row += rows
|
|
712
|
+
end
|
|
713
|
+
# displays a horizontal line
|
|
714
|
+
# takes col (column to start from) from current stack
|
|
715
|
+
# take row from app_row
|
|
716
|
+
#
|
|
717
|
+
# requires width to be passed in config, else defaults to 20
|
|
718
|
+
# @example
|
|
719
|
+
# hline :width => 55
|
|
720
|
+
def hline config={}
|
|
721
|
+
row = config[:row] || @app_row
|
|
722
|
+
width = config[:width] || 20
|
|
723
|
+
_position config
|
|
724
|
+
col = config[:col] || 1
|
|
725
|
+
@color_pair = config[:color_pair] || $datacolor
|
|
726
|
+
@attrib = config[:attrib] || Ncurses::A_NORMAL
|
|
727
|
+
@window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
|
|
728
|
+
@window.mvwhline( row, col, FFI::NCurses::ACS_HLINE, width)
|
|
729
|
+
@window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
|
|
730
|
+
@app_row += 1
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
def TODOmultisplit *args, &block
|
|
734
|
+
require 'rbhex/extras/widgets/rmultisplit'
|
|
735
|
+
config = {}
|
|
736
|
+
events = [ :PROPERTY_CHANGE, :LEAVE, :ENTER ]
|
|
737
|
+
block_event = events[0]
|
|
738
|
+
_process_args args, config, block_event, events
|
|
739
|
+
_position(config)
|
|
740
|
+
# if no width given, expand to flows width
|
|
741
|
+
config[:width] ||= @stack.last.width if @stack.last
|
|
742
|
+
config.delete :title
|
|
743
|
+
useform = nil
|
|
744
|
+
useform = @form if @current_object.empty?
|
|
745
|
+
|
|
746
|
+
w = MultiSplit.new useform, config
|
|
747
|
+
#if block
|
|
748
|
+
#w.bind(block_event, w, &block)
|
|
749
|
+
#end
|
|
750
|
+
if block_given?
|
|
751
|
+
@current_object << w
|
|
752
|
+
#instance_eval &block if block_given?
|
|
753
|
+
yield w
|
|
754
|
+
@current_object.pop
|
|
755
|
+
end
|
|
756
|
+
return w
|
|
757
|
+
end
|
|
758
|
+
# create a readonly list
|
|
759
|
+
# I don't want to rename this to list, as that could lead to
|
|
760
|
+
# confusion, maybe rlist
|
|
761
|
+
def OLDlistbox *args, &block # earlier basic_list
|
|
762
|
+
require 'rbhex/core/widgets/rlist'
|
|
763
|
+
config = {}
|
|
764
|
+
#TODO check these
|
|
765
|
+
events = [ :LEAVE, :ENTER, :ENTER_ROW, :LEAVE_ROW, :LIST_DATA_EVENT ]
|
|
766
|
+
# TODO how to do this so he gets selected row easily
|
|
767
|
+
block_event = :ENTER_ROW
|
|
768
|
+
_process_args args, config, block_event, events
|
|
769
|
+
# some guesses at a sensible height for listbox
|
|
770
|
+
if !config.has_key? :height
|
|
771
|
+
ll = 0
|
|
772
|
+
ll = config[:list].length + 2 if config.has_key? :list
|
|
773
|
+
config[:height] ||= ll
|
|
774
|
+
config[:height] = 15 if config[:height] > 20
|
|
775
|
+
end
|
|
776
|
+
_position(config)
|
|
777
|
+
# if no width given, expand to flows width
|
|
778
|
+
config[:width] ||= @stack.last.width if @stack.last
|
|
779
|
+
config[:width] ||= longest_in_list(config[:list])+2
|
|
780
|
+
#config.delete :title
|
|
781
|
+
#config[:default_values] = config.delete :choose
|
|
782
|
+
config[:selection_mode] = :single unless config.has_key? :selection_mode
|
|
783
|
+
useform = nil
|
|
784
|
+
useform = @form if @current_object.empty?
|
|
785
|
+
|
|
786
|
+
w = List.new useform, config # NO BLOCK GIVEN
|
|
787
|
+
if block_given?
|
|
788
|
+
field.bind(block_event, &block)
|
|
789
|
+
end
|
|
790
|
+
return w
|
|
791
|
+
end
|
|
792
|
+
alias :basiclist :listbox # this alias will be removed
|
|
793
|
+
def TODOmaster_detail *args, &block
|
|
794
|
+
require 'rbhex/experimental/widgets/masterdetail'
|
|
795
|
+
config = {}
|
|
796
|
+
events = [:PROPERTY_CHANGE, :LEAVE, :ENTER ]
|
|
797
|
+
block_event = nil
|
|
798
|
+
_process_args args, config, block_event, events
|
|
799
|
+
#config[:height] ||= 10
|
|
800
|
+
_position(config)
|
|
801
|
+
# if no width given, expand to flows width
|
|
802
|
+
config[:width] ||= @stack.last.width if @stack.last
|
|
803
|
+
#config.delete :title
|
|
804
|
+
useform = nil
|
|
805
|
+
useform = @form if @current_object.empty?
|
|
806
|
+
|
|
807
|
+
w = MasterDetail.new useform, config # NO BLOCK GIVEN
|
|
808
|
+
if block_given?
|
|
809
|
+
@current_object << w
|
|
810
|
+
yield_or_eval &block
|
|
811
|
+
@current_object.pop
|
|
812
|
+
end
|
|
813
|
+
return w
|
|
814
|
+
end
|
|
815
|
+
# scrollbar attached to the right of a parent object
|
|
816
|
+
def OLDscrollbar *args, &block
|
|
817
|
+
require 'rbhex/core/widgets/scrollbar'
|
|
818
|
+
config = {}
|
|
819
|
+
events = [:PROPERTY_CHANGE, :LEAVE, :ENTER ] # # none really at present
|
|
820
|
+
block_event = nil
|
|
821
|
+
_process_args args, config, block_event, events
|
|
822
|
+
raise "parent needed for scrollbar" if !config.has_key? :parent
|
|
823
|
+
useform = nil
|
|
824
|
+
useform = @form if @current_object.empty?
|
|
825
|
+
sb = Scrollbar.new useform, config
|
|
826
|
+
end
|
|
827
|
+
# divider used to resize neighbouring components TOTEST XXX
|
|
828
|
+
def OLDdivider *args, &block
|
|
829
|
+
require 'rbhex/core/widgets/divider'
|
|
830
|
+
config = {}
|
|
831
|
+
events = [:PROPERTY_CHANGE, :LEAVE, :ENTER, :DRAG_EVENT ] # # none really at present
|
|
832
|
+
block_event = nil
|
|
833
|
+
_process_args args, config, block_event, events
|
|
834
|
+
useform = nil
|
|
835
|
+
useform = @form if @current_object.empty?
|
|
836
|
+
sb = Divider.new useform, config
|
|
837
|
+
end
|
|
838
|
+
# creates a simple readonly table, that allows users to click on rows
|
|
839
|
+
# and also on the header. Header clicking is for column-sorting.
|
|
840
|
+
def OLDcombo *args, &block
|
|
841
|
+
require 'rbhex/core/widgets/rcombo'
|
|
842
|
+
config = {}
|
|
843
|
+
events = [:PROPERTY_CHANGE, :LEAVE, :ENTER, :CHANGE, :ENTER_ROW, :PRESS ] # XXX
|
|
844
|
+
block_event = nil
|
|
845
|
+
_process_args args, config, block_event, events
|
|
846
|
+
_position(config)
|
|
847
|
+
# if no width given, expand to flows width
|
|
848
|
+
config[:width] ||= @stack.last.width if @stack.last
|
|
849
|
+
#config.delete :title
|
|
850
|
+
useform = nil
|
|
851
|
+
useform = @form if @current_object.empty?
|
|
852
|
+
|
|
853
|
+
w = ComboBox.new useform, config # NO BLOCK GIVEN
|
|
854
|
+
if block_given?
|
|
855
|
+
@current_object << w
|
|
856
|
+
yield_or_eval &block
|
|
857
|
+
@current_object.pop
|
|
858
|
+
end
|
|
859
|
+
return w
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
# ADD new widget above this
|
|
863
|
+
|
|
864
|
+
# @endgroup
|
|
865
|
+
|
|
866
|
+
# @group positioning of components
|
|
867
|
+
|
|
868
|
+
# line up vertically whatever comes in, ignoring r and c
|
|
869
|
+
# margin_top to add to margin of existing stack (if embedded) such as extra spacing
|
|
870
|
+
# margin to add to margin of existing stack, or window (0)
|
|
871
|
+
# NOTE: since these coordins are calculated at start
|
|
872
|
+
# therefore if window resized i can't recalculate.
|
|
873
|
+
#Stack = Struct.new(:margin_top, :margin, :width)
|
|
874
|
+
def OLDstack config={}, &block
|
|
875
|
+
@instack = true
|
|
876
|
+
mt = config[:margin_top] || 1
|
|
877
|
+
mr = config[:margin] || 0
|
|
878
|
+
# must take into account margin
|
|
879
|
+
defw = Ncurses.COLS - mr
|
|
880
|
+
config[:width] = defw if config[:width] == :EXPAND
|
|
881
|
+
w = config[:width] || [50, defw].min
|
|
882
|
+
s = Stack.new(mt, mr, w)
|
|
883
|
+
@app_row += mt
|
|
884
|
+
mr += @stack.last.margin if @stack.last
|
|
885
|
+
@stack << s
|
|
886
|
+
yield_or_eval &block if block_given?
|
|
887
|
+
@stack.pop
|
|
888
|
+
@instack = false if @stack.empty?
|
|
889
|
+
@app_row = 0 if @stack.empty?
|
|
890
|
+
end
|
|
891
|
+
# keep adding to right of previous and when no more space
|
|
892
|
+
# move down and continue fitting in.
|
|
893
|
+
# Useful for button positioning. Currently, we can use a second flow
|
|
894
|
+
# to get another row.
|
|
895
|
+
# TODO: move down when row filled
|
|
896
|
+
# TODO: align right, center
|
|
897
|
+
def OLDflow config={}, &block
|
|
898
|
+
@inflow = true
|
|
899
|
+
mt = config[:margin_top] || 0
|
|
900
|
+
@app_row += mt
|
|
901
|
+
col = @flowstack.last || @stack.last.margin || @app_col
|
|
902
|
+
col += config[:margin] || 0
|
|
903
|
+
@flowstack << col
|
|
904
|
+
@flowcol = col
|
|
905
|
+
yield_or_eval &block if block_given?
|
|
906
|
+
@flowstack.pop
|
|
907
|
+
@inflow = false if @flowstack.empty?
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
private
|
|
911
|
+
def quit
|
|
912
|
+
throw(:close)
|
|
913
|
+
end
|
|
914
|
+
def help; display_app_help; end
|
|
915
|
+
# Initialize curses
|
|
916
|
+
def init_ncurses
|
|
917
|
+
VER::start_ncurses # this is initializing colors via ColorMap.setup
|
|
918
|
+
#$ncurses_started = true
|
|
919
|
+
@stop_ncurses_on_close = true
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
# returns length of longest
|
|
923
|
+
def longest_in_list list #:nodoc:
|
|
924
|
+
longest = list.inject(0) do |memo,word|
|
|
925
|
+
memo >= word.length ? memo : word.length
|
|
926
|
+
end
|
|
927
|
+
longest
|
|
928
|
+
end
|
|
929
|
+
# returns longest item
|
|
930
|
+
# rows = list.max_by(&:length)
|
|
931
|
+
#
|
|
932
|
+
def longest_in_list2 list #:nodoc:
|
|
933
|
+
longest = list.inject(list[0]) do |memo,word|
|
|
934
|
+
memo.length >= word.length ? memo : word
|
|
935
|
+
end
|
|
936
|
+
longest
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
# if partial command entered then returns matches
|
|
940
|
+
def _resolve_command opts, cmd
|
|
941
|
+
return cmd if opts.include? cmd
|
|
942
|
+
matches = opts.grep Regexp.new("^#{cmd}")
|
|
943
|
+
end
|
|
944
|
+
# Now i am not creating this unless user wants it. Pls avoid it.
|
|
945
|
+
# Use either say_with_pause, or put $status_message in command of statusline
|
|
946
|
+
# @deprecated please use {#status_line} instead of a message label
|
|
947
|
+
def create_message_label row=Ncurses.LINES-1
|
|
948
|
+
@message_label = RubyCurses::Label.new @form, {:text_variable => @message, :name=>"message_label",:row => row, :col => 0, :display_length => Ncurses.COLS, :height => 1, :color => :white}
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
def run &block
|
|
952
|
+
begin
|
|
953
|
+
|
|
954
|
+
# check if user has passed window coord in config, else root window
|
|
955
|
+
@window = VER::Window.root_window
|
|
956
|
+
awin = @window
|
|
957
|
+
catch(:close) do
|
|
958
|
+
@form = Form.new @window
|
|
959
|
+
@form.bind_key([?\C-x, ?c], 'suspend') { suspend(false) do
|
|
960
|
+
system("tput cup 26 0")
|
|
961
|
+
system("tput ed")
|
|
962
|
+
system("echo Enter C-d to return to application")
|
|
963
|
+
system (ENV['PS1']='\s-\v\$ ')
|
|
964
|
+
system(ENV['SHELL']);
|
|
965
|
+
end
|
|
966
|
+
}
|
|
967
|
+
# this is a very rudimentary default command executer, it does not
|
|
968
|
+
# allow tab completion. App should use M-x with names of commands
|
|
969
|
+
# as in appgmail
|
|
970
|
+
# NOTE: This is gonna change very soon - 2012-01-8
|
|
971
|
+
@form.bind_key(?:, 'prompt') {
|
|
972
|
+
str = get_command_from_user
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
# this M-x stuff has to be moved out so it can be used by all. One should be able
|
|
976
|
+
# to add_commands properly to this, and to C-x. I am thinking how to go about this,
|
|
977
|
+
# and what function M-x actually serves.
|
|
978
|
+
|
|
979
|
+
@form.bind_key(?\M-x, 'M-x commands'){
|
|
980
|
+
# TODO previous command to be default
|
|
981
|
+
opts = get_all_commands()
|
|
982
|
+
@_command_history ||= Array.new
|
|
983
|
+
# previous command should be in opts, otherwise it is not in this context
|
|
984
|
+
cmd = rb_gets("Command: ", opts){ |q| q.default = @_previous_command; q.history = @_command_history }
|
|
985
|
+
if cmd.nil? || cmd == ""
|
|
986
|
+
else
|
|
987
|
+
@_command_history << cmd unless @_command_history.include? cmd
|
|
988
|
+
cmdline = cmd.split
|
|
989
|
+
cmd = cmdline.shift
|
|
990
|
+
# check if command is a substring of a larger command
|
|
991
|
+
if !opts.include?(cmd)
|
|
992
|
+
rcmd = _resolve_command(opts, cmd) if !opts.include?(cmd)
|
|
993
|
+
if rcmd.size == 1
|
|
994
|
+
cmd = rcmd.first
|
|
995
|
+
elsif !rcmd.empty?
|
|
996
|
+
rb_puts "Cannot resolve #{cmd}. Matches are: #{rcmd} "
|
|
997
|
+
end
|
|
998
|
+
end
|
|
999
|
+
if respond_to?(cmd, true)
|
|
1000
|
+
@_previous_command = cmd
|
|
1001
|
+
#raw_message "calling #{cmd} "
|
|
1002
|
+
begin
|
|
1003
|
+
send cmd, *cmdline
|
|
1004
|
+
rescue => exc
|
|
1005
|
+
$log.error "ERR EXC: send throwing an exception now. Duh. IMAP keeps crashing haha !! #{exc} " if $log.debug?
|
|
1006
|
+
if exc
|
|
1007
|
+
$log.debug( exc)
|
|
1008
|
+
$log.debug(exc.backtrace.join("\n"))
|
|
1009
|
+
rb_puts exc.to_s
|
|
1010
|
+
end
|
|
1011
|
+
end
|
|
1012
|
+
else
|
|
1013
|
+
rb_puts("Command [#{cmd}] not supported by #{self.class} ", :color_pair => $promptcolor)
|
|
1014
|
+
end
|
|
1015
|
+
end
|
|
1016
|
+
}
|
|
1017
|
+
#@form.bind_key(KEY_F1, 'help'){ display_app_help } # NOT REQUIRED NOW 2012-01-7 since form does it
|
|
1018
|
+
@form.bind_key([?q,?q], 'quit' ){ throw :close } if $log.debug?
|
|
1019
|
+
|
|
1020
|
+
#@message = Variable.new
|
|
1021
|
+
#@message.value = ""
|
|
1022
|
+
$status_message ||= Variable.new # remember there are multiple levels of apps
|
|
1023
|
+
$status_message.value = ""
|
|
1024
|
+
#$error_message.update_command { @message.set_value($error_message.value) }
|
|
1025
|
+
if block
|
|
1026
|
+
begin
|
|
1027
|
+
yield_or_eval &block if block_given? # modified 2010-11-17 20:36
|
|
1028
|
+
# how the hell does a user trap exception if the loop is hidden from him ? FIXME
|
|
1029
|
+
loop
|
|
1030
|
+
rescue => ex
|
|
1031
|
+
$log.debug( "APP.rb rescue reached ")
|
|
1032
|
+
$log.debug( ex) if ex
|
|
1033
|
+
$log.debug(ex.backtrace.join("\n")) if ex
|
|
1034
|
+
ensure
|
|
1035
|
+
close
|
|
1036
|
+
# putting it here allows it to be printed on screen, otherwise it was not showing at all.
|
|
1037
|
+
if ex
|
|
1038
|
+
puts "========== EXCEPTION =========="
|
|
1039
|
+
p ex
|
|
1040
|
+
puts "==============================="
|
|
1041
|
+
puts(ex.backtrace.join("\n"))
|
|
1042
|
+
end
|
|
1043
|
+
end
|
|
1044
|
+
nil
|
|
1045
|
+
else
|
|
1046
|
+
#@close_on_terminate = true
|
|
1047
|
+
self
|
|
1048
|
+
end #if block
|
|
1049
|
+
end # :close
|
|
1050
|
+
end
|
|
1051
|
+
end
|
|
1052
|
+
# TODO
|
|
1053
|
+
# process args, all widgets should call this
|
|
1054
|
+
def _process_args args, config, block_event, events #:nodoc:
|
|
1055
|
+
args.each do |arg|
|
|
1056
|
+
case arg
|
|
1057
|
+
when Array
|
|
1058
|
+
# please don't use this, keep it simple and use hash NOTE
|
|
1059
|
+
# we can use r,c, w, h
|
|
1060
|
+
row, col, display_length, height = arg
|
|
1061
|
+
config[:row] = row
|
|
1062
|
+
config[:col] = col
|
|
1063
|
+
config[:display_length] = display_length if display_length
|
|
1064
|
+
config[:width] = display_length if display_length
|
|
1065
|
+
# width for most XXX ?
|
|
1066
|
+
config[:height] = height if height
|
|
1067
|
+
when Hash
|
|
1068
|
+
config.merge!(arg)
|
|
1069
|
+
if block_event
|
|
1070
|
+
block_event = config.delete(:block_event){ block_event }
|
|
1071
|
+
raise "Invalid event. Use #{events}" unless events.include? block_event
|
|
1072
|
+
end
|
|
1073
|
+
when String
|
|
1074
|
+
config[:name] = arg
|
|
1075
|
+
config[:title] = arg # some may not have title
|
|
1076
|
+
#config[:text] = arg # some may not have title
|
|
1077
|
+
end
|
|
1078
|
+
end
|
|
1079
|
+
end # _process
|
|
1080
|
+
# position object based on whether in a flow or stack.
|
|
1081
|
+
# @app_row is prepared for next object based on this objects ht
|
|
1082
|
+
def OLD_position config #:nodoc:
|
|
1083
|
+
unless @current_object.empty?
|
|
1084
|
+
$log.debug " WWWW returning from position #{@current_object.last} "
|
|
1085
|
+
return
|
|
1086
|
+
end
|
|
1087
|
+
if @inflow
|
|
1088
|
+
#col = @flowstack.last
|
|
1089
|
+
config[:row] = @app_row
|
|
1090
|
+
config[:col] = @flowcol
|
|
1091
|
+
$log.debug " YYYY config #{config} "
|
|
1092
|
+
if config[:text]
|
|
1093
|
+
@flowcol += config[:text].length + 5 # 5 came from buttons
|
|
1094
|
+
else
|
|
1095
|
+
@flowcol += (config[:length] || 10) + 5 # trying out for combo
|
|
1096
|
+
end
|
|
1097
|
+
elsif @instack
|
|
1098
|
+
# most likely you won't have row and col. should we check or just go ahead
|
|
1099
|
+
# what if he has put it 2011-10-19 as in a container
|
|
1100
|
+
col = @stack.last.margin
|
|
1101
|
+
config[:row] ||= @app_row
|
|
1102
|
+
config[:col] ||= col
|
|
1103
|
+
@app_row += config[:height] || 1 #unless config[:no_advance]
|
|
1104
|
+
# TODO need to allow stack to have its spacing, but we don't have an object as yet.
|
|
1105
|
+
end
|
|
1106
|
+
end
|
|
1107
|
+
end # class
|
|
1108
|
+
end # module
|
|
1109
|
+
if $0 == __FILE__
|
|
1110
|
+
include RubyCurses
|
|
1111
|
+
#app = App.new
|
|
1112
|
+
#window = app.window
|
|
1113
|
+
#window.printstring 2, 30, "Demo of Listbox - rbhex", $normalcolor, 'reverse'
|
|
1114
|
+
#app.logger.info "beforegetch"
|
|
1115
|
+
#window.getch
|
|
1116
|
+
#app.close
|
|
1117
|
+
# this was the yield example, but now we've moved to instance eval
|
|
1118
|
+
App.new do
|
|
1119
|
+
@window.printstring 0, 30, "Demo of Listbox - rbhex", $normalcolor, 'reverse'
|
|
1120
|
+
@window.printstring 1, 30, "Hit F1 to quit", $datacolor, 'normal'
|
|
1121
|
+
form = @form
|
|
1122
|
+
fname = "Search"
|
|
1123
|
+
r, c = 7, 30
|
|
1124
|
+
c += fname.length + 1
|
|
1125
|
+
#field1 = field( [r,c, 30], fname, :bgcolor => "cyan", :block_event => :CHANGE) do |fld|
|
|
1126
|
+
stack :margin_top => 2, :margin => 10 do
|
|
1127
|
+
lbl = label({:text => fname, :color=>'white',:bgcolor=>'red', :mnemonic=> 's'})
|
|
1128
|
+
field1 = field( [r,c, 30], fname, :bgcolor => "cyan",:block_event => :CHANGE) do |fld|
|
|
1129
|
+
message("You entered #{fld.getvalue}. To quit enter quit and tab out")
|
|
1130
|
+
if fld.getvalue == "quit"
|
|
1131
|
+
logger.info "you typed quit!"
|
|
1132
|
+
throw :close
|
|
1133
|
+
end
|
|
1134
|
+
end
|
|
1135
|
+
#field1.set_label Label.new @form, {:text => fname, :color=>'white',:bgcolor=>'red', :mnemonic=> 's'}
|
|
1136
|
+
field1.set_label( lbl )
|
|
1137
|
+
field1.enter do
|
|
1138
|
+
message "you entered this field"
|
|
1139
|
+
end
|
|
1140
|
+
|
|
1141
|
+
stack :margin_top => 2, :margin => 0 do
|
|
1142
|
+
#label( [8, 30, 60],{:text => "A label", :color=>'white',:bgcolor=>'blue'} )
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
@bluelabel = label( [8, 30, 60],{:text => "B label", :color=>'white',:bgcolor=>'blue'} )
|
|
1146
|
+
|
|
1147
|
+
stack :margin_top => 2, :margin => 0 do
|
|
1148
|
+
toggle :onvalue => " Toggle Down ", :offvalue => " Untoggle ", :mnemonic => 'T', :value => true
|
|
1149
|
+
|
|
1150
|
+
toggle :onvalue => " On ", :offvalue => " Off ", :value => true do |e|
|
|
1151
|
+
alert "You pressed me #{e.state}"
|
|
1152
|
+
end
|
|
1153
|
+
check :text => "Check me!", :onvalue => "Checked", :offvalue => "Unchecked", :value => true do |e|
|
|
1154
|
+
# this works but long and complicated
|
|
1155
|
+
#@bluelabel.text = e.item.getvalue ? e.item.onvalue : e.item.offvalue
|
|
1156
|
+
@bluelabel.text = e.item.text
|
|
1157
|
+
end
|
|
1158
|
+
radio :text => "red", :value => "RED", :color => "red", :group => :colors
|
|
1159
|
+
radio :text => "green", :value => "GREEN", :color => "green", :group => :colors
|
|
1160
|
+
flow do
|
|
1161
|
+
button_row = 17
|
|
1162
|
+
ok_button = button( [button_row,30], "OK", {:mnemonic => 'O'}) do
|
|
1163
|
+
alert("About to dump data into log file!")
|
|
1164
|
+
message "Dumped data to log file"
|
|
1165
|
+
end
|
|
1166
|
+
|
|
1167
|
+
# using ampersand to set mnemonic
|
|
1168
|
+
cancel_button = button( [button_row, 40], "&Cancel" ) do
|
|
1169
|
+
if confirm("Do your really want to quit?")== :YES
|
|
1170
|
+
#throw(:close);
|
|
1171
|
+
quit
|
|
1172
|
+
else
|
|
1173
|
+
message "Quit aborted"
|
|
1174
|
+
end
|
|
1175
|
+
end # cancel
|
|
1176
|
+
button "Don't know"
|
|
1177
|
+
end
|
|
1178
|
+
flow :margin_top => 2 do
|
|
1179
|
+
button "Another"
|
|
1180
|
+
button "Line"
|
|
1181
|
+
end
|
|
1182
|
+
stack :margin_top => 2, :margin => 0 do
|
|
1183
|
+
@pbar = progress :width => 20, :bgcolor => 'white', :color => 'red'
|
|
1184
|
+
@pbar1 = progress :width => 20, :style => :old
|
|
1185
|
+
end
|
|
1186
|
+
end
|
|
1187
|
+
end # stack
|
|
1188
|
+
# lets make another column
|
|
1189
|
+
stack :margin_top => 2, :margin => 70 do
|
|
1190
|
+
l = label "Column 2"
|
|
1191
|
+
f1 = field "afield", :bgcolor => 'white', :color => 'black'
|
|
1192
|
+
listbox "A list", :list => ["Square", "Oval", "Rectangle", "Somethinglarge"], :choose => ["Square"]
|
|
1193
|
+
lb = listbox "Another", :list => ["Square", "Oval", "Rectangle", "Somethinglarge"] do |list|
|
|
1194
|
+
#f1.set_buffer list.text
|
|
1195
|
+
#f1.text list.text
|
|
1196
|
+
f1.text = list.text
|
|
1197
|
+
l.text = list.text.upcase
|
|
1198
|
+
end
|
|
1199
|
+
t = textarea :height => 10 do |e|
|
|
1200
|
+
#@bluelabel.text = e.to_s.tr("\n",' ')
|
|
1201
|
+
@bluelabel.text = e.text.gsub("\n"," ")
|
|
1202
|
+
len = e.source.get_text.length
|
|
1203
|
+
len = len % 20 if len > 20
|
|
1204
|
+
$log.debug " PBAR len of text is #{len}: #{len/20.0} "
|
|
1205
|
+
@pbar.fraction(len/20.0)
|
|
1206
|
+
@pbar1.fraction(len/20.0)
|
|
1207
|
+
i = ((len/20.0)*100).to_i
|
|
1208
|
+
@pbar.text = "completed:#{i}"
|
|
1209
|
+
end
|
|
1210
|
+
t.leave do |c|
|
|
1211
|
+
@bluelabel.text = c.get_text.gsub("\n"," ")
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
# Allow user to get the keys
|
|
1217
|
+
keypress do |key|
|
|
1218
|
+
if key == :C_c
|
|
1219
|
+
message "You tried to cancel"
|
|
1220
|
+
#throw :close
|
|
1221
|
+
quit
|
|
1222
|
+
else
|
|
1223
|
+
#app.message "You pressed #{key}, #{char} "
|
|
1224
|
+
message "You pressed #{key}"
|
|
1225
|
+
end
|
|
1226
|
+
end
|
|
1227
|
+
end
|
|
1228
|
+
end
|