rbcurse 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. data/Makefile +21 -0
  2. data/Manifest.txt +6 -0
  3. data/README.markdown +6 -4
  4. data/TODO +372 -0
  5. data/TODO2.txt +121 -0
  6. data/VERSION +1 -1
  7. data/examples/README.txt +67 -0
  8. data/examples/abasiclist.rb +33 -0
  9. data/examples/alpmenu.rb +42 -0
  10. data/examples/app.rb +859 -0
  11. data/examples/app.sample +17 -0
  12. data/examples/appdirtree.rb +74 -0
  13. data/examples/appemail.rb +191 -0
  14. data/examples/appemaillb.rb +308 -0
  15. data/examples/appgcompose.rb +315 -0
  16. data/examples/atree.rb +64 -0
  17. data/examples/common/file.rb +40 -0
  18. data/examples/common/rmail.rb +257 -0
  19. data/examples/data.txt +683 -0
  20. data/examples/data/README.markdown +9 -0
  21. data/examples/data/brew.txt +38 -0
  22. data/examples/data/color.2 +37 -0
  23. data/examples/data/gemlist.txt +60 -0
  24. data/examples/data/lotr.txt +12 -0
  25. data/examples/data/ports.txt +136 -0
  26. data/examples/data/tasks.txt +27 -0
  27. data/examples/data/todocsv.csv +28 -0
  28. data/examples/data/unix1.txt +21 -0
  29. data/examples/data/unix2.txt +11 -0
  30. data/examples/dbdemo.rb +495 -0
  31. data/examples/deprecated/appgmail.rb +952 -0
  32. data/examples/deprecated/splitp.rb +56 -0
  33. data/examples/deprecated/testscrolllb.rb +86 -0
  34. data/examples/deprecated/testscrollp.rb +88 -0
  35. data/examples/deprecated/testscrollta.rb +80 -0
  36. data/examples/deprecated/testscrolltable.rb +165 -0
  37. data/examples/deprecated/testsplit.rb +87 -0
  38. data/examples/deprecated/testsplit2.rb +123 -0
  39. data/examples/deprecated/testsplit3.rb +215 -0
  40. data/examples/deprecated/testsplit3_1.rb +244 -0
  41. data/examples/deprecated/testsplit3a.rb +215 -0
  42. data/examples/deprecated/testsplit3b.rb +237 -0
  43. data/examples/deprecated/testsplitta.rb +148 -0
  44. data/examples/deprecated/testsplittv.rb +142 -0
  45. data/examples/deprecated/testsplittvv.rb +144 -0
  46. data/examples/deprecated/testtpane.rb +215 -0
  47. data/examples/deprecated/testtpane2.rb +145 -0
  48. data/examples/deprecated/testtpanetable.rb +203 -0
  49. data/examples/dirtree.rb +88 -0
  50. data/examples/experimental/resultsetdemo.rb +280 -0
  51. data/examples/experimental/testmform.rb +35 -0
  52. data/examples/experimental/testscroller.rb +117 -0
  53. data/examples/experimental/teststackflow.rb +111 -0
  54. data/examples/menu1.rb +112 -0
  55. data/examples/multispl.rb +86 -0
  56. data/examples/newmessagebox.rb +131 -0
  57. data/examples/newtabbedwindow.rb +100 -0
  58. data/examples/newtesttabp.rb +121 -0
  59. data/examples/qdfilechooser.rb +68 -0
  60. data/examples/rfe.rb +1239 -0
  61. data/examples/rfe_renderer.rb +121 -0
  62. data/examples/sqlc.rb +454 -0
  63. data/examples/sqlm.rb +437 -0
  64. data/examples/sqlt.rb +408 -0
  65. data/examples/status.txt +68 -0
  66. data/examples/table1.rb +24 -0
  67. data/examples/term2.rb +84 -0
  68. data/examples/test1.rb +239 -0
  69. data/examples/test2.rb +674 -0
  70. data/examples/testapp.rb +44 -0
  71. data/examples/testapp2.rb +58 -0
  72. data/examples/testchars.rb +137 -0
  73. data/examples/testcombo.rb +91 -0
  74. data/examples/testkeypress.rb +66 -0
  75. data/examples/testlistbox.rb +113 -0
  76. data/examples/testmenu.rb +101 -0
  77. data/examples/testmulticomp.rb +70 -0
  78. data/examples/testmulticontainer.rb +94 -0
  79. data/examples/testmultispl.rb +199 -0
  80. data/examples/testree.rb +106 -0
  81. data/examples/testtable.rb +264 -0
  82. data/examples/testtabp.rb +107 -0
  83. data/examples/testtodo.rb +584 -0
  84. data/examples/testvimsplit.rb +112 -0
  85. data/examples/testwsshortcuts.rb +64 -0
  86. data/examples/testwsshortcuts2.rb +126 -0
  87. data/examples/todo.db +0 -0
  88. data/examples/todo.yml +191 -0
  89. data/examples/viewtodo.rb +574 -0
  90. data/lib/rbcurse/deprecated/README.markdown +12 -0
  91. data/lib/rbcurse/deprecated/rpad.rb +375 -0
  92. data/lib/rbcurse/deprecated/rscrollpane.rb +512 -0
  93. data/lib/rbcurse/deprecated/rsplitpane.rb +894 -0
  94. data/lib/rbcurse/deprecated/rsplitpane2.rb +1009 -0
  95. data/lib/rbcurse/deprecated/rviewport.rb +204 -0
  96. data/lib/rbcurse/deprecated/widgets/mapper.rb +130 -0
  97. data/lib/rbcurse/deprecated/widgets/rmessagebox.rb +348 -0
  98. data/lib/rbcurse/deprecated/widgets/rtabbedpane.rb +1158 -0
  99. data/lib/rbcurse/deprecated/widgets/rtabbedwindow.rb +167 -0
  100. data/lib/rbcurse/deprecated/widgets/scrollable.rb +301 -0
  101. data/lib/rbcurse/deprecated/widgets/stdscrwindow.rb +309 -0
  102. data/lib/ver/keyboard2.rb +170 -0
  103. data/test/test_rbcurse.rb +0 -0
  104. metadata +131 -9
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.0.pre1
1
+ 1.5.2
@@ -0,0 +1,67 @@
1
+
2
+ README
3
+ ------
4
+
5
+ ### For ruby 1.9.2, 2010-08-23 11:48
6
+
7
+ Changes in 1.9.2 require the following changes:
8
+ - $: no longer includes ".".
9
+ Fixed 2 examples.
10
+ - hash_update: cannot update hash during iteration
11
+ Modified rwidget.rb and rtable.rb
12
+
13
+ ### IMPORTANT
14
+
15
+ 1. If you are trying out the examples from a folder that does not have
16
+ write access (e.g. /opt/local/lib...), then you may have to run the
17
+ examples, with "sudo", since a log file is created. Or else, you could
18
+ copy the examples elsewhere, or change to location of the log file
19
+ (view.log) before running.
20
+
21
+ sudo ruby test2.rb
22
+
23
+ Update: Added an environment variable named LOGDIR. So you may do:
24
+
25
+ LOGDIR=~/ ruby test2.rb
26
+
27
+ or just set LOGDIR
28
+
29
+ export LOGDIR=~/tmp
30
+
31
+ 2. Please change directory to the examples folder before executing, since
32
+ some data files, or local programs may be loaded.
33
+
34
+ ## sqlc.rb
35
+
36
+ A sql client using tabbedpanes.
37
+
38
+ This uses a file testd.db that can be downloaded (check file for
39
+ location) or created using:
40
+
41
+ sqlite3 testd.db < data.txt
42
+
43
+ Enter an sql query in the textbox. Click Run.
44
+
45
+ Or Press Enter on the name of a table in the tables listing. Its
46
+ contents will be shown in a new tab in the tabbedpane.
47
+
48
+ Or Press Space on a table. Its columns are shown below. Now select
49
+ columns and then click Construct. Selected columns will be used to
50
+ construct a query. Press Run to execute it.
51
+
52
+ If you are inside a table, use Alt-TAb to exit.
53
+
54
+ ## sqlm.rb
55
+
56
+ Identical to sqlc.rb. This demo uses a multi-container for multiple
57
+ resultsets instead of a tabbedpane.
58
+
59
+ * * * * *
60
+
61
+ Please check the examples with test*.rb - since they are updated.
62
+ At the time of writing, viewtodo.rb may not be functional since I
63
+ changed to structure of the yaml file.
64
+
65
+ ## vim:tw=72:ai:formatoptions=tcqln:nocindent:
66
+
67
+
@@ -0,0 +1,33 @@
1
+ require 'rbcurse/core/util/app'
2
+ require 'rbcurse/core/widgets/rlist'
3
+
4
+ # just a simple test to ensure that rbasiclistbox is running inside a container.
5
+ App.new do
6
+ header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Basic List Demo", :text_right =>"New Improved!", :color => :black, :bgcolor => :white, :attr => :bold
7
+ message "Press F10 to escape from here"
8
+
9
+ #list = %W{ bhikshu boddisattva avalokiteswara mu mun kwan paramita prajna samadhi sutra shakyamuni }
10
+ list = File.open("data/brew.txt",'r').readlines
11
+ list2 = File.open("data/gemlist.txt",'r').readlines
12
+ lb = nil
13
+ vimsplit :row => 1, :col => 0, :suppress_borders => false, :width => 60, :height => Ncurses.LINES-2, :weight => 0.4, :orientation => :VERTICAL do |s|
14
+ lb = RubyCurses::List.new nil, :list => list, :suppress_borders => false
15
+ #lb = RubyCurses::List.new nil, :list => list, :show_selector => true, :row_selected_symbol => "*", :suppress_borders => false
16
+ #lb = RubyCurses::List.new nil, :list => list
17
+ #lb = list_box "A list", :list => list
18
+ lb.show_selector = false
19
+ #lb.row_selected_symbol = "*"
20
+ #lb = list_box "A list", :list => list
21
+
22
+ s.add lb, :FIRST
23
+ #lb2= RubyCurses::List.new nil, :list => list.shuffle, :justify => :center
24
+ lb2 = listbox :list => list2, :justify => :left, :suppress_borders => false
25
+ s.add lb2, :SECOND
26
+ label({:text => "checking overwrite from list", :row => 10, :col => 60})
27
+ label({:text => "checking overwrite from list 1", :row => 11, :col => 60})
28
+ end
29
+ label({:text => "Press F4 and F5 to test popup, space or enter to select", :row => Ncurses.LINES-1, :col => 0})
30
+
31
+ @form.bind_key(FFI::NCurses::KEY_F4) { row = lb.current_index+lb.row; col=lb.col+lb.current_value.length+1; ret = popuplist(%w[ andy berlioz strauss tchaiko matz beethoven], :row => row, :col => col, :title => "Names", :bgcolor => :blue, :color => :white) ; alert "got #{ret} "}
32
+ @form.bind_key(FFI::NCurses::KEY_F5) { list = %x[ls].split("\n");ret = popuplist(list, :title => "Files"); alert "Got #{ret} #{list[ret]} " }
33
+ end # app
@@ -0,0 +1,42 @@
1
+ require 'rbcurse/core/util/app'
2
+
3
+ App.new do
4
+ #title "Demo of Menu - rbcurse"
5
+ #subtitle "Hit F1 to quit, F2 for menubar toggle"
6
+ header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Alpine Menu Demo", :text_right =>""
7
+ #message_row(27)
8
+
9
+ stack :margin_top => 10, :margin => 15 do
10
+ #w = "Messages".length + 1
11
+ w = 60
12
+ menulink "&View Todo", :width => w, :description => "View TODO in sqlite" do |s|
13
+ message "Pressed #{s.text} "
14
+ #require './viewtodo'; todo = ViewTodo::TodoApp.new; todo.run
15
+ end
16
+ blank
17
+ menulink "&Edit Todo", :width => w, :description => "Edit TODO in CSV" do |s|
18
+ message "Pressed #{s.text} "
19
+ #require './testtodo'; todo = TestTodo::TodoApp.new; todo.run
20
+ end
21
+ blank
22
+ menulink "&Messages", :width => w, :description => "View messages in current folder" do |s|
23
+ message "Pressed #{s.text} "
24
+ #load './menu1.rb'
25
+ end
26
+ blank
27
+ menulink "&Compose", :width => w, :description => "Compose a mail" do |s|
28
+ message "Pressed #{s.getvalue} "
29
+ end
30
+ blank
31
+ menulink "Setup", :mnemonic => "?", :width => w, :description => "Configure Alpine options" do |s|
32
+ message "Pressed #{s.text} "
33
+ end
34
+ blank
35
+ menulink "&Quit", :width => w, :description => "Quit this application" do |s|
36
+ quit
37
+ end
38
+ @form.bind(:ENTER) do |w|
39
+ header.text_right = w.text
40
+ end
41
+ end # stack
42
+ end # app
data/examples/app.rb ADDED
@@ -0,0 +1,859 @@
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
+ * License:
9
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
10
+
11
+ =end
12
+ #require 'rubygems'
13
+ #require 'ncurses' # FFI
14
+ require 'logger'
15
+ require 'rbcurse'
16
+
17
+ #include Ncurses
18
+ include RubyCurses
19
+ include RubyCurses::Utils
20
+ module RubyCurses
21
+ extend self
22
+
23
+ # NOTE most of this has move to lib/rbcurse/core/util/app.rb
24
+ #
25
+ class Widget
26
+ def changed *args, &block
27
+ bind :CHANGED, *args, &block
28
+ end
29
+ def leave *args, &block
30
+ bind :LEAVE, *args, &block
31
+ end
32
+ def enter *args, &block
33
+ bind :ENTER, *args, &block
34
+ end
35
+ # actually we already have command() for buttons
36
+ def click *args, &block
37
+ bind :PRESS, *args, &block
38
+ end
39
+ end
40
+ #class Listbox
41
+ #def text
42
+ #return get_content()[@current_index]
43
+ #end
44
+ #end
45
+ class CheckBox
46
+ # a little dicey XXX
47
+ def text(*val)
48
+ if val.empty?
49
+ @value ? @onvalue : @offvalue
50
+ else
51
+ super
52
+ end
53
+ end
54
+ end
55
+ class App
56
+ attr_reader :config
57
+ attr_reader :form
58
+ attr_reader :window
59
+ attr_writer :quit_key
60
+
61
+
62
+ # i should be able to pass window coords here in config
63
+ # :title
64
+ def initialize config={}, &block
65
+ #$log.debug " inside constructor of APP #{config} "
66
+ @config = config
67
+ @app_row = @app_col = 0
68
+ @stack = [] # stack's coordinates
69
+ @flowstack = []
70
+ @variables = {}
71
+ # if we are creating child objects then we will not use outer form. this object will manage
72
+ @current_object = []
73
+ init_vars
74
+ run &block
75
+ end
76
+ def init_vars
77
+ @quit_key ||= KEY_F1
78
+ # actually this should be maintained inside ncurses pack, so not loaded 2 times.
79
+ # this way if we call an app from existing program, App won't start ncurses.
80
+ unless $ncurses_started
81
+ init_ncurses
82
+ end
83
+ unless $log
84
+ $log = Logger.new((File.join(ENV["LOGDIR"] || "./" ,"rbc13.log")))
85
+ $log.level = Logger::DEBUG
86
+ colors = Ncurses.COLORS
87
+ $log.debug "START #{colors} colors --------- #{$0}"
88
+ end
89
+ end
90
+ def logger; return $log; end
91
+ def close
92
+ $log.debug " INSIDE CLOSE, #{@stop_ncurses_on_close} "
93
+ @window.destroy if !@window.nil?
94
+ $log.debug " INSIDE CLOSE, #{@stop_ncurses_on_close} "
95
+ if @stop_ncurses_on_close
96
+ VER::stop_ncurses
97
+ $log.debug " CLOSING NCURSES"
98
+ end
99
+ #p $error_message.value unless $error_message.value.nil?
100
+ $log.debug " CLOSING APP"
101
+ #end
102
+ end
103
+ # not sure, but user shuld be able to trap keystrokes if he wants
104
+ # but do i still call handle_key if he does, or give him total control.
105
+ # But loop is already called by framework
106
+ def loop &block
107
+ @form.repaint
108
+ @window.wrefresh
109
+ Ncurses::Panel.update_panels
110
+ while((ch = @window.getchar()) != @quit_key )
111
+ str = keycode_tos ch
112
+ @keyblock.call(str.gsub(/-/, "_").to_sym) if @keyblock
113
+ $log.debug "#{ch} got (#{str})"
114
+ yield ch if block # <<<----
115
+ @form.handle_key ch
116
+ @form.repaint
117
+ @window.wrefresh
118
+ end
119
+ end
120
+ # returns a symbol of the key pressed
121
+ # e.g. :C_c for Ctrl-C
122
+ # :Space, :bs, :M_d etc
123
+ def keypress &block
124
+ @keyblock = block
125
+ end
126
+ # updates a global var with text. Calling app has to set up a Variable with that name and attach to
127
+ # a label so it can be printed.
128
+ def message text
129
+ @message.value = text
130
+ end
131
+ def message_row row
132
+ @message_label.row = row
133
+ end
134
+ #
135
+ # @group methods to create widgets easily
136
+ #
137
+ # process arguments based on datatype, perhaps making configuration
138
+ # of some components easier for caller avoiding too much boiler plate code
139
+ #
140
+ # create a field
141
+ def field *args, &block
142
+ config = {}
143
+ events = [ :CHANGED, :LEAVE, :ENTER, :CHANGE ]
144
+ block_event = :CHANGED # LEAVE, ENTER, CHANGE
145
+
146
+ args.each do |arg|
147
+ case arg
148
+ when Array
149
+ #puts "row, col #{arg[0]} #{arg[1]} "
150
+ # we can use r,c, w, h
151
+ row, col, display_length = arg
152
+ config[:row] = row
153
+ config[:col] = col
154
+ config[:display_length] = display_length if display_length
155
+ when Hash
156
+ config.merge!(arg)
157
+ block_event = config.delete(:block_event){ block_event }
158
+ raise "Invalid event. Use #{events}" unless events.include? block_event
159
+ #puts "hash #{config}"
160
+ when String
161
+ title = arg
162
+ config[:name] = title
163
+ end
164
+ end
165
+ if @instack
166
+ # most likely you won't have row and col. should we check or just go ahead
167
+ col = @stack.last.margin
168
+ config[:row] = @app_row
169
+ config[:col] = col
170
+ @app_row += 1
171
+ end
172
+ field = Field.new @form, config
173
+ # shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
174
+ if block
175
+ field.bind(block_event, &block)
176
+ end
177
+ return field
178
+ end
179
+ #instance_eval &block if block_given?
180
+ # or
181
+ #@blk = block # for later execution using @blk.call()
182
+ #colorlabel = Label.new @form, {'text' => "Select a color:", "row" => row, "col" => col, "color"=>"cyan", "mnemonic" => 'S'}
183
+ #var = RubyCurses::Label.new @form, {'text_variable' => $results, "row" => r, "col" => fc}
184
+
185
+ def label *args
186
+ block_event = nil
187
+ config = {}
188
+
189
+ args.each do |arg|
190
+ case arg
191
+ when Array
192
+ row, col, display_length, height = arg
193
+ config[:row] = row
194
+ config[:col] = col
195
+ config[:display_length] = display_length if display_length
196
+ config[:height] = height || 1
197
+ when Hash
198
+ config.merge!(arg)
199
+ when String
200
+ config[:text] = arg
201
+ end
202
+ end
203
+ config[:height] ||= 1
204
+ if @instack
205
+ # most likely you won't have row and col. should we check or just go ahead
206
+ col = @stack.last.margin
207
+ config[:row] = @app_row
208
+ config[:col] = col
209
+ @app_row += config[:height]
210
+ end
211
+ label = Label.new @form, config
212
+ # shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
213
+ return label
214
+ end
215
+ alias :text :label
216
+ def button *args, &block
217
+ config = {}
218
+ events = [ :PRESS, :LEAVE, :ENTER ]
219
+ block_event = :PRESS
220
+
221
+ #process_args args, config, block_event, events
222
+ args.each do |arg|
223
+ case arg
224
+ when Array
225
+ #puts "row, col #{arg[0]} #{arg[1]} "
226
+ # we can use r,c, w, h
227
+ row, col, display_length, height = arg
228
+ config[:row] = row
229
+ config[:col] = col
230
+ config[:display_length] = display_length if display_length
231
+ config[:height] = height if height
232
+ when Hash
233
+ config.merge!(arg)
234
+ block_event = config.delete(:block_event){ block_event }
235
+ raise "Invalid event. Use #{events}" unless events.include? block_event
236
+ #puts "hash #{config}"
237
+ when String
238
+ config[:text] = arg
239
+ config[:name] = arg
240
+ end
241
+ end
242
+ # flow gets precedence over stack
243
+ _position(config)
244
+ button = Button.new @form, config
245
+ # shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
246
+ if block
247
+ button.bind(block_event, &block)
248
+ end
249
+ return button
250
+ end
251
+ #
252
+ # create a list
253
+ # Since we are mouseless, one can traverse without selection. So we have a different
254
+ # way of selecting row/s and traversal. XXX this aspect of LB's has always troubled me hugely.
255
+ def list_box *args, &block
256
+ config = {}
257
+ # TODO confirm events
258
+ # listdataevent has interval added and interval removed, due to multiple
259
+ # selection, we have to make that simple for user here.
260
+ events = [ :LEAVE, :ENTER, :ENTER_ROW, :LEAVE_ROW, :LIST_DATA_EVENT ]
261
+ # TODO how to do this so he gets selected row easily
262
+ block_event = :ENTER_ROW
263
+
264
+ # TODO abstract this into a new method so no copying
265
+ args.each do |arg|
266
+ case arg
267
+ when Array
268
+ #puts "row, col #{arg[0]} #{arg[1]} "
269
+ # we can use r,c, w, h
270
+ row, col, display_length, height = arg
271
+ config[:row] = row
272
+ config[:col] = col
273
+ config[:display_length] = display_length if display_length
274
+ config[:height] = height if height
275
+ when Hash
276
+ config.merge!(arg)
277
+ block_event = config.delete(:block_event){ block_event }
278
+ raise "Invalid event. Use #{events}" unless events.include? block_event
279
+ #puts "hash #{config}"
280
+ when String
281
+ config[:name] = arg
282
+ config[:title] = arg
283
+ end
284
+ end
285
+ # naive defaults, since list could be large or have very long items
286
+ # usually user will provide
287
+ config[:height] ||= config[:list].length + 2
288
+ if @current_object.empty?
289
+ $log.debug "1 APP LB w: #{config[:width]} ,#{config[:name]} "
290
+ config[:width] ||= @stack.last.width if @stack.last
291
+ $log.debug "2 APP LB w: #{config[:width]} "
292
+ config[:width] ||= longest_in_list(config[:list])+2
293
+ $log.debug "3 APP LB w: #{config[:width]} "
294
+ end
295
+ # if no width given, expand to flows width XXX SHOULD BE NOT EXPAND ?
296
+ #config[:width] ||= @stack.last.width if @stack.last
297
+ #if config.has_key? :choose
298
+ config[:default_values] = config.delete :choose
299
+ # we make the default single unless specified
300
+ config[:selection_mode] = :single unless config.has_key? :selection_mode
301
+ if @current_object.empty?
302
+ if @instack
303
+ # most likely you won't have row and col. should we check or just go ahead
304
+ col = @stack.last.margin
305
+ config[:row] = @app_row
306
+ config[:col] = col
307
+ @app_row += config[:height] # this needs to take into account height of prev object
308
+ end
309
+ end
310
+ useform = nil
311
+ useform = @form if @current_object.empty?
312
+ field = Listbox.new useform, config
313
+ # shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
314
+ if block
315
+ # this way you can't pass params to the block
316
+ field.bind(block_event, &block)
317
+ end
318
+ return field
319
+ end
320
+
321
+ # toggle button
322
+ def toggle *args, &block
323
+ config = {}
324
+ # TODO confirm events
325
+ events = [ :PRESS, :LEAVE, :ENTER ]
326
+ block_event = :PRESS
327
+ _process_args args, config, block_event, events
328
+ config[:text] ||= longest_in_list2( [config[:onvalue], config[:offvalue]])
329
+ #config[:onvalue] # needed for flow, we need a better way FIXME
330
+ _position(config)
331
+ toggle = ToggleButton.new @form, config
332
+ if block
333
+ toggle.bind(block_event, &block)
334
+ end
335
+ return toggle
336
+ end
337
+ # check button
338
+ def check *args, &block
339
+ config = {}
340
+ # TODO confirm events
341
+ events = [ :PRESS, :LEAVE, :ENTER ]
342
+ block_event = :PRESS
343
+ _process_args args, config, block_event, events
344
+ _position(config)
345
+ toggle = CheckBox.new @form, config
346
+ if block
347
+ toggle.bind(block_event, &block)
348
+ end
349
+ return toggle
350
+ end
351
+ # radio button
352
+ def radio *args, &block
353
+ config = {}
354
+ # TODO confirm events
355
+ events = [ :PRESS, :LEAVE, :ENTER ]
356
+ block_event = :PRESS
357
+ _process_args args, config, block_event, events
358
+ a = config[:group]
359
+ # FIXME we should check if user has set a varialbe in :variable.
360
+ # we should create a variable, so he can use it if he wants.
361
+ if @variables.has_key? a
362
+ v = @variables[a]
363
+ else
364
+ v = Variable.new
365
+ @variables[a] = v
366
+ end
367
+ config[:variable] = v
368
+ config.delete(:group)
369
+ _position(config)
370
+ radio = RadioButton.new @form, config
371
+ if block
372
+ radio.bind(block_event, &block)
373
+ end
374
+ return radio
375
+ end
376
+ # editable text area
377
+ def textarea *args, &block
378
+ require 'rbcurse/core/widgets/rtextarea'
379
+ config = {}
380
+ # TODO confirm events many more
381
+ events = [ :CHANGE, :LEAVE, :ENTER ]
382
+ block_event = events[0]
383
+ _process_args args, config, block_event, events
384
+ config[:width] = config[:display_length] unless config.has_key? :width
385
+ _position(config)
386
+ # if no width given, expand to flows width
387
+ config[:width] ||= @stack.last.width if @stack.last
388
+ useform = nil
389
+ useform = @form if @current_object.empty?
390
+ w = TextArea.new useform, config
391
+ if block
392
+ w.bind(block_event, &block)
393
+ end
394
+ return w
395
+ end
396
+ # progress bar
397
+ def progress *args, &block
398
+ require 'rbcurse/core/widgets/rprogress'
399
+ config = {}
400
+ # TODO confirm events many more
401
+ events = [ :CHANGE, :LEAVE, :ENTER ]
402
+ block_event = nil
403
+ _process_args args, config, block_event, events
404
+ config[:width] = config[:display_length] || 10 unless config.has_key? :width
405
+ _position(config)
406
+ w = Progress.new @form, config
407
+ #if block
408
+ #w.bind(block_event, &block)
409
+ #end
410
+ return w
411
+ end
412
+
413
+ # table widget
414
+ # @example
415
+ # data = [["Roger",16,"SWI"], ["Phillip",1, "DEU"]]
416
+ # colnames = ["Name", "Wins", "Place"]
417
+ # t = table :width => 40, :height => 10, :columns => colnames, :data => data, :estimate_widths => true
418
+ # other options are :column_widths => [12,4,12]
419
+ # :size_to_fit => true
420
+ def table *args, &block
421
+ require 'rbcurse/extras/widgets/rtable'
422
+ config = {}
423
+ # TODO confirm events many more
424
+ events = [ :ENTER_ROW, :LEAVE, :ENTER ]
425
+ block_event = events[0]
426
+ _process_args args, config, block_event, events
427
+ # if user is leaving out width, then we don't want it in config
428
+ # else Widget will put a value of 10 as default, overriding what we've calculated
429
+ if config.has_key? :display_length
430
+ config[:width] = config[:display_length] unless config.has_key? :width
431
+ end
432
+ ext = config.delete :extended_keys
433
+
434
+ model = nil
435
+ _position(config)
436
+ # if no width given, expand to flows width
437
+ config[:width] ||= @stack.last.width if @stack.last
438
+ w = Table.new @form, config
439
+ if ext
440
+ require 'rbcurse/extras/include/tableextended'
441
+ # so we can increase and decrease column width using keys
442
+ w.extend TableExtended
443
+ w.bind_key(?w){ w.next_column }
444
+ w.bind_key(?b){ w.previous_column }
445
+ w.bind_key(?+) { w.increase_column }
446
+ w.bind_key(?-) { w.decrease_column }
447
+ w.bind_key([?d, ?d]) { w.table_model.delete_at w.current_index }
448
+ w.bind_key(?u) { w.table_model.undo w.current_index}
449
+ end
450
+ if block
451
+ w.bind(block_event, &block)
452
+ end
453
+ return w
454
+ end
455
+ # print a title on first row
456
+ def title string, config={}
457
+ ## TODO center it
458
+ @window.printstring 1, 30, string, $normalcolor, 'reverse'
459
+ end
460
+ # print a sutitle on second row
461
+ def subtitle string, config={}
462
+ @window.printstring 2, 30, string, $datacolor, 'normal'
463
+ end
464
+ # menu bar
465
+ def menubar &block
466
+ require 'rbcurse/core/widgets/rmenu'
467
+ RubyCurses::MenuBar.new &block
468
+ end
469
+
470
+ # creates a blank row
471
+ def blank rows=1, config={}
472
+ @app_row += rows
473
+ end
474
+ # displays a horizontal line
475
+ # takes col (column to start from) from current stack
476
+ # take row from app_row
477
+ #
478
+ # requires width to be passed in config, else defaults to 20
479
+ # @example
480
+ # hline :width => 55
481
+ def hline config={}
482
+ row = @app_row
483
+ width = config[:width] || 20
484
+ _position config
485
+ col = config[:col] || 1
486
+ @window.mvwhline( row, col, ACS_HLINE, width)
487
+ @app_row += 1
488
+ end
489
+ def app_header title, config={}, &block
490
+ require 'rbcurse/core/widgets/applicationheader'
491
+ header = ApplicationHeader.new @form, title, config, &block
492
+ end
493
+ def dock labels, config={}, &block
494
+ require 'rbcurse/core/widgets/keylabelprinter'
495
+ klp = RubyCurses::KeyLabelPrinter.new @form, labels, config, &block
496
+ end
497
+ def link *args, &block
498
+ require 'rbcurse/extras/widgets/rlink'
499
+ config = {}
500
+ events = [ :PRESS, :LEAVE, :ENTER ]
501
+ block_event = :PRESS
502
+ _process_args args, config, block_event, events
503
+ _position(config)
504
+ config[:text] ||= config.delete :title
505
+ config[:highlight_foreground] = "yellow"
506
+ config[:highlight_background] = "red"
507
+ toggle = Link.new @form, config
508
+ if block
509
+ toggle.bind(block_event, toggle, &block)
510
+ end
511
+ return toggle
512
+ end
513
+ def menulink *args, &block
514
+ require 'rbcurse/extras/widgets/rmenulink'
515
+ config = {}
516
+ events = [ :PRESS, :LEAVE, :ENTER ]
517
+ block_event = :PRESS
518
+ _process_args args, config, block_event, events
519
+ _position(config)
520
+ config[:text] ||= config.delete :title
521
+ config[:highlight_foreground] = "yellow"
522
+ config[:highlight_background] = "red"
523
+ toggle = MenuLink.new @form, config
524
+ if block
525
+ toggle.bind(block_event, toggle, &block)
526
+ end
527
+ return toggle
528
+ end
529
+ def splitpane *args, &block
530
+ require 'rbcurse/rsplitpane2'
531
+ config = {}
532
+ events = [ :PROPERTY_CHANGE, :LEAVE, :ENTER ]
533
+ block_event = events[0]
534
+ _process_args args, config, block_event, events
535
+ _position(config)
536
+ # if no width given, expand to flows width
537
+ config[:width] ||= @stack.last.width if @stack.last
538
+ config.delete :title
539
+ useform = nil
540
+ useform = @form if @current_object.empty?
541
+
542
+ w = SplitPane.new useform, config
543
+ #if block
544
+ #w.bind(block_event, w, &block)
545
+ #end
546
+ if block_given?
547
+ @current_object << w
548
+ #instance_eval &block if block_given?
549
+ yield w
550
+ @current_object.pop
551
+ end
552
+ return w
553
+ end
554
+ def multisplit *args, &block
555
+ require 'rbcurse/extras/widgets/rmultisplit'
556
+ config = {}
557
+ events = [ :PROPERTY_CHANGE, :LEAVE, :ENTER ]
558
+ block_event = events[0]
559
+ _process_args args, config, block_event, events
560
+ _position(config)
561
+ # if no width given, expand to flows width
562
+ config[:width] ||= @stack.last.width if @stack.last
563
+ config.delete :title
564
+ useform = nil
565
+ useform = @form if @current_object.empty?
566
+
567
+ w = MultiSplit.new useform, config
568
+ #if block
569
+ #w.bind(block_event, w, &block)
570
+ #end
571
+ if block_given?
572
+ @current_object << w
573
+ #instance_eval &block if block_given?
574
+ yield w
575
+ @current_object.pop
576
+ end
577
+ return w
578
+ end
579
+
580
+ # ADD new widget above this
581
+
582
+ # @endgroup
583
+
584
+ # @group positioning of components
585
+
586
+ # line up vertically whatever comes in, ignoring r and c
587
+ # margin_top to add to margin of existing stack (if embedded) such as extra spacing
588
+ # margin to add to margin of existing stack, or window (0)
589
+ Stack = Struct.new(:margin_top, :margin, :width)
590
+ def stack config={}, &block
591
+ @instack = true
592
+ mt = config[:margin_top] || 1
593
+ mr = config[:margin] || 0
594
+ # must take into account margin
595
+ defw = Ncurses.COLS - mr
596
+ w = config[:width] || [50, defw].min
597
+ s = Stack.new(mt, mr, w)
598
+ @app_row += mt
599
+ mr += @stack.last.margin if @stack.last
600
+ #@stack << mr
601
+ @stack << s
602
+ instance_eval &block if block_given?
603
+ @stack.pop
604
+ @instack = false if @stack.empty?
605
+ @app_row = 0 if @stack.empty?
606
+ end
607
+ # keep adding to right of previous and when no more space
608
+ # move down and continue fitting in.
609
+ # Useful for button positioning. Currently, we can use a second flow
610
+ # to get another row.
611
+ # TODO: move down when row filled
612
+ # TODO: align right, center
613
+ def flow config={}, &block
614
+ @inflow = true
615
+ mt = config[:margin_top] || 0
616
+ @app_row += mt
617
+ col = @flowstack.last || @stack.last.margin || @app_col
618
+ col += config[:margin] || 0
619
+ @flowstack << col
620
+ @flowcol = col
621
+ instance_eval &block if block_given?
622
+ @flowstack.pop
623
+ @inflow = false if @flowstack.empty?
624
+ end
625
+
626
+ private
627
+ def quit
628
+ throw(:close)
629
+ end
630
+ # Initialize curses
631
+ def init_ncurses
632
+ VER::start_ncurses # this is initializing colors via ColorMap.setup
633
+ #$ncurses_started = true
634
+ @stop_ncurses_on_close = true
635
+ end
636
+
637
+ # returns length of longest
638
+ def longest_in_list list
639
+ longest = list.inject(0) do |memo,word|
640
+ memo >= word.length ? memo : word.length
641
+ end
642
+ longest
643
+ end
644
+ # returns longest item
645
+ def longest_in_list2 list
646
+ longest = list.inject(list[0]) do |memo,word|
647
+ memo.length >= word.length ? memo : word
648
+ end
649
+ longest
650
+ end
651
+ def run &block
652
+ begin
653
+
654
+ # check if user has passed window coord in config, else root window
655
+ @window = VER::Window.root_window
656
+ catch(:close) do
657
+ @form = Form.new @window
658
+ @message = Variable.new
659
+ @message.value = "Message Comes Here"
660
+ @message_label = RubyCurses::Label.new @form, {:text_variable => @message, :name=>"message_label",:row => 24, :col => 1, :display_length => 60, :height => 1, :color => 'cyan'}
661
+ $error_message.update_command { @message.set_value($error_message.value) }
662
+ if block
663
+ begin
664
+ #yield(self, @window, @form)
665
+ instance_eval &block if block_given?
666
+ loop
667
+ rescue => ex
668
+ $log.debug( "APP.rb rescue reached ")
669
+ $log.debug( ex) if ex
670
+ $log.debug(ex.backtrace.join("\n")) if ex
671
+ ensure
672
+ close
673
+ # putting it here allows it to be printed on screen, otherwise it was not showing at all.
674
+ if ex
675
+ puts "========== EXCEPTION =========="
676
+ p ex
677
+ puts "=========="
678
+ puts(ex.backtrace.join("\n"))
679
+ end
680
+ end
681
+ nil
682
+ else
683
+ #@close_on_terminate = true
684
+ self
685
+ end #if block
686
+ end
687
+ end
688
+ end
689
+ # TODO
690
+ # process args, all widgets should call this
691
+ def _process_args args, config, block_event, events
692
+ args.each do |arg|
693
+ case arg
694
+ when Array
695
+ # we can use r,c, w, h
696
+ row, col, display_length, height = arg
697
+ config[:row] = row
698
+ config[:col] = col
699
+ config[:display_length] = display_length if display_length
700
+ config[:width] = display_length if display_length
701
+ # width for most XXX ?
702
+ config[:height] = height if height
703
+ when Hash
704
+ config.merge!(arg)
705
+ if block_event
706
+ block_event = config.delete(:block_event){ block_event }
707
+ raise "Invalid event. Use #{events}" unless events.include? block_event
708
+ end
709
+ when String
710
+ config[:name] = arg
711
+ config[:title] = arg # some may not have title
712
+ #config[:text] = arg # some may not have title
713
+ end
714
+ end
715
+ end # _process
716
+ # position object based on whether in a flow or stack.
717
+ # @app_row is prepared for next object based on this objects ht
718
+ def _position config
719
+ unless @current_object.empty?
720
+ $log.debug " WWWW returning from position #{@current_object.last} "
721
+ return
722
+ end
723
+ if @inflow
724
+ #col = @flowstack.last
725
+ config[:row] = @app_row
726
+ config[:col] = @flowcol
727
+ $log.debug " YYYY config #{config} "
728
+ @flowcol += config[:text].length + 5 # 5 came from buttons
729
+ elsif @instack
730
+ # most likely you won't have row and col. should we check or just go ahead
731
+ col = @stack.last.margin
732
+ config[:row] = @app_row
733
+ config[:col] = col
734
+ @app_row += config[:height] || 1
735
+ # TODO need to allow stack to have its spacing, but we don't have an object as yet.
736
+ end
737
+ end
738
+ end # class
739
+ end # module
740
+ if $0 == __FILE__
741
+ include RubyCurses
742
+ #app = App.new
743
+ #window = app.window
744
+ #window.printstring 2, 30, "Demo of Listbox - rbcurse", $normalcolor, 'reverse'
745
+ #app.logger.info "beforegetch"
746
+ #window.getch
747
+ #app.close
748
+ # this was the yield example, but now we've moved to instance eval
749
+ App.new do
750
+ @window.printstring 0, 30, "Demo of Listbox - rbcurse", $normalcolor, 'reverse'
751
+ @window.printstring 1, 30, "Hit F1 to quit", $datacolor, 'normal'
752
+ form = @form
753
+ fname = "Search"
754
+ r, c = 7, 30
755
+ c += fname.length + 1
756
+ #field1 = field( [r,c, 30], fname, :bgcolor => "cyan", :block_event => :CHANGE) do |fld|
757
+ stack :margin_top => 2, :margin => 10 do
758
+ lbl = label({:text => fname, :color=>'white',:bgcolor=>'red', :mnemonic=> 's'})
759
+ field1 = field( [r,c, 30], fname, :bgcolor => "cyan",:block_event => :CHANGE) do |fld|
760
+ message("You entered #{fld.getvalue}. To quit enter quit and tab out")
761
+ if fld.getvalue == "quit"
762
+ logger.info "you typed quit!"
763
+ throw :close
764
+ end
765
+ end
766
+ #field1.set_label Label.new @form, {:text => fname, :color=>'white',:bgcolor=>'red', :mnemonic=> 's'}
767
+ field1.set_label( lbl )
768
+ field1.enter do
769
+ message "you entered this field"
770
+ end
771
+
772
+ stack :margin_top => 2, :margin => 0 do
773
+ #label( [8, 30, 60],{:text => "A label", :color=>'white',:bgcolor=>'blue'} )
774
+ end
775
+
776
+ @bluelabel = label( [8, 30, 60],{:text => "B label", :color=>'white',:bgcolor=>'blue'} )
777
+
778
+ stack :margin_top => 2, :margin => 0 do
779
+ toggle :onvalue => " Toggle Down ", :offvalue => " Untoggle ", :mnemonic => 'T', :value => true
780
+
781
+ toggle :onvalue => " On ", :offvalue => " Off ", :value => true do |e|
782
+ alert "You pressed me #{e.state}"
783
+ end
784
+ check :text => "Check me!", :onvalue => "Checked", :offvalue => "Unchecked", :value => true do |e|
785
+ # this works but long and complicated
786
+ #@bluelabel.text = e.item.getvalue ? e.item.onvalue : e.item.offvalue
787
+ @bluelabel.text = e.item.text
788
+ end
789
+ radio :text => "red", :value => "RED", :color => "red", :group => :colors
790
+ radio :text => "green", :value => "GREEN", :color => "green", :group => :colors
791
+ flow do
792
+ button_row = 17
793
+ ok_button = button( [button_row,30], "OK", {:mnemonic => 'O'}) do
794
+ alert("About to dump data into log file!")
795
+ message "Dumped data to log file"
796
+ end
797
+
798
+ # using ampersand to set mnemonic
799
+ cancel_button = button( [button_row, 40], "&Cancel" ) do
800
+ if confirm("Do your really want to quit?")== :YES
801
+ #throw(:close);
802
+ quit
803
+ else
804
+ message "Quit aborted"
805
+ end
806
+ end # cancel
807
+ button "Don't know"
808
+ end
809
+ flow :margin_top => 2 do
810
+ button "Another"
811
+ button "Line"
812
+ end
813
+ stack :margin_top => 2, :margin => 0 do
814
+ @pbar = progress :width => 20, :bgcolor => 'white', :color => 'red'
815
+ @pbar1 = progress :width => 20, :style => :old
816
+ end
817
+ end
818
+ end # stack
819
+ # lets make another column
820
+ stack :margin_top => 2, :margin => 70 do
821
+ l = label "Column 2"
822
+ f1 = field "afield", :bgcolor => 'white', :color => 'black'
823
+ list_box "A list", :list => ["Square", "Oval", "Rectangle", "Somethinglarge"], :choose => ["Square"]
824
+ lb = list_box "Another", :list => ["Square", "Oval", "Rectangle", "Somethinglarge"] do |list|
825
+ #f1.set_buffer list.text
826
+ #f1.text list.text
827
+ f1.text = list.text
828
+ l.text = list.text.upcase
829
+ end
830
+ t = textarea :height => 10 do |e|
831
+ #@bluelabel.text = e.to_s.tr("\n",' ')
832
+ @bluelabel.text = e.text.gsub("\n"," ")
833
+ len = e.source.get_text.length
834
+ len = len % 20 if len > 20
835
+ $log.debug " PBAR len of text is #{len}: #{len/20.0} "
836
+ @pbar.fraction(len/20.0)
837
+ @pbar1.fraction(len/20.0)
838
+ i = ((len/20.0)*100).to_i
839
+ @pbar.text = "completed:#{i}"
840
+ end
841
+ t.leave do |c|
842
+ @bluelabel.text = c.get_text.gsub("\n"," ")
843
+ end
844
+
845
+ end
846
+
847
+ # Allow user to get the keys
848
+ keypress do |key|
849
+ if key == :C_c
850
+ message "You tried to cancel"
851
+ #throw :close
852
+ quit
853
+ else
854
+ #app.message "You pressed #{key}, #{char} "
855
+ message "You pressed #{key}"
856
+ end
857
+ end
858
+ end
859
+ end