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
@@ -0,0 +1,204 @@
1
+ =begin
2
+ * Name: Viewport
3
+ * $Id$
4
+ * Description: a viewport thru which you see an underlying form or widget. Scrolling
5
+ the viewport reveals new sections of the underlying object.
6
+ * Author: rkumar arunachala
7
+ TODO
8
+ * file created 2009-10-27 18:05
9
+ Major change 2010-02-11 23:32
10
+ * removed buffering, was totally unnecessary
11
+ * FIXME avoid repaint and handle_keys totally, let scrollpane talk to child.
12
+ Do we really need this ?
13
+ If we do strip it down to its major function - nothign extraneous. Currently its a huge layer in between.
14
+ --------
15
+ * License:
16
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
17
+
18
+ =end
19
+ #require 'rubygems'
20
+ #require 'ncurses'
21
+ require 'logger'
22
+ require 'rbcurse'
23
+ require 'rbcurse/core/include/rchangeevent'
24
+
25
+ #include Ncurses # FFI 2011-09-8
26
+ include RubyCurses
27
+ module RubyCurses
28
+ extend self
29
+
30
+ ##
31
+ # A viewport or porthole throgh which one can see portions of underlying object
32
+ # such as textarea, table or a form, usually the underlying data is larger
33
+ # than what can be displayed and thus must be seen through a viewport.
34
+ # TODO -
35
+
36
+ class Viewport < Widget
37
+ # row and col also present int widget
38
+ dsl_accessor :child # component that is being viewed
39
+ attr_accessor :cascade_changes
40
+ #attr_reader :top_margin, :left_margin
41
+
42
+ def initialize form, config={}, &block
43
+ @focusable = false
44
+ @editable = false
45
+ #@top_margin = @left_margin = 1 # 2010-02-06 23:27 reduce in scrollpane
46
+ @row = 1 # 1 # 0 2010-02-06 22:46 so we don't write on scrollpanes border
47
+ @col = 1 # 1 # 0 2010-02-06 22:47
48
+ super
49
+ #@row_offset = @col_offset = 1
50
+ #@orig_col = @col
51
+ init_vars
52
+ @_events.push :STATE_CHANGE
53
+ end
54
+ def init_vars
55
+ #@curpos = @pcol = @toprow = @current_index = 0
56
+ should_create_buffer = true
57
+ @border_width = 2
58
+ end
59
+ # set the component to be viewed
60
+ def set_view ch
61
+ @child = ch
62
+ end
63
+ def set_view_size h,w
64
+ # calling the property shoudl uniformally trigger fire_property_change
65
+ $log.debug " setting viewport to h #{h} , w #{w} "
66
+ height(h)
67
+ width(w)
68
+ fire_state_changed
69
+ #fire_handler :PROPERTY_CHANGE, self # XXX should it be an event STATE_CHANGE with details
70
+ end
71
+ ##
72
+ # Set the row and col of the child, that the viewport starts displaying.
73
+ # Used to initialize the view, and later if scrolling.
74
+ # Initially would be set to 0,0.
75
+ #
76
+ def set_view_position r,c
77
+ return false if r < 0 or c < 0
78
+ # 2010-02-04 19:29 TRYING -2 for borders
79
+ $log.debug " set_view if #{r} +1+ #{@height} - #{@border_width} )} >=#{@child.height} "
80
+ # 2010-02-12 15:33 XXX made > into >= and added +1 since -1 in set_buffering
81
+ # testscrollp was crashing out when child height exceeded
82
+ if r+ (@height+1-@border_width) >= @child.height
83
+ # basically r + (:bottom - :screen_top) < @child.height
84
+ #if r+ (@height) >= @child.height
85
+ $log.debug " set_view_position : trying to exceed ht #{r} + #{@height} > #{@child.height} returned false"
86
+ return false
87
+ end
88
+ # testscrollp was printing junk on right end. Why the 1?
89
+ if c+ (@width+1-@border_width) >=@child.width
90
+ #if c+ (@width) >=@child.width
91
+ $log.debug " set_view_position : trying to exceed width #{c} + #{@width} . returned false"
92
+ return false
93
+ end
94
+ $log.debug " VP row #{@row} col #{@col}, now will be #{r} , #{c} "
95
+ row(r) # commnting off 2010-02-06 22:47
96
+ col(c) # commnting off 2010-02-06 22:47
97
+ # next call sets pminrow and pmincol
98
+ $log.debug " VP setting child buffer pmin to #{r} #{c} "
99
+ @child.get_buffer().set_pad_top_left(r, c)
100
+ # replaced this on 2010-02-26 11:49 HOPE IT WORKS XXX
101
+ #@child.fire_property_change("row", r, r) # XXX quick dirty, this should happen
102
+ @child.repaint_required(true)
103
+ @repaint_required = true
104
+ #fire_handler :PROPERTY_CHANGE, self
105
+ fire_state_changed
106
+ return true
107
+ end
108
+ # instead of using row and col to increment, try using this, since this is what's actually incremented.
109
+ def get_pad_top_left
110
+ p = @child.get_buffer()
111
+ return p.pminrow, p.pmincol
112
+ end
113
+ def repaint # viewport
114
+ return unless @repaint_required
115
+ # should call child's repaint onto pad
116
+ # then this should return clipped pad
117
+ $log.debug "VP calling child #{@child.name} repaint"
118
+ #x @graphic.wclear # required otherwise bottom of scrollpane had old rows still repeated. 2010-01-17 22:51
119
+ @child.repaint_all
120
+ @child.repaint
121
+ paint
122
+ end
123
+ def getvalue
124
+ # TODO ???
125
+ end
126
+ ## most likely should just return an unhandled and not try being intelligent
127
+ # should viewport handle keys or should parent do so directly to child
128
+ def handle_key ch
129
+ # if this gets key it should just hand it to child
130
+ if @child != nil
131
+ ret = @child.handle_key ch
132
+ # 2010-01-19 19:26 commenting off repaint to see.
133
+ return :UNHANDLED if ret == :UNHANDLED
134
+ # moved below return so only if table handles
135
+ @repaint_required=true # added 2009-12-27 22:25 BUFFERED WHY ??
136
+ else
137
+ return :UNHANDLED
138
+ end
139
+ return 0
140
+ #$log.debug "TV after loop : curpos #{@curpos} blen: #{@buffer.length}"
141
+ end
142
+ def paint
143
+ @repaint_required = false
144
+ @repaint_all = false
145
+ end
146
+ # set height
147
+ # a container must pass down changes in size to it's children
148
+ #+ 2010-02-04 18:06 - i am not sure about this. When viewport is set then it passes down
149
+ #+ changes to child which user did not intend. Maybe in splitpane it is okay but other cases?
150
+ #+ Perhaps its okay if scrollpane gets larger than child, not otherwise.
151
+ # added 2010-01-16 23:55
152
+ def height(*val)
153
+ return @height if val.empty?
154
+ oldvalue = @height || 0
155
+ super
156
+ @height = val[0]
157
+ return if @child == nil
158
+ delta = @height - oldvalue
159
+ return if delta == 0
160
+ @repaint_required = true
161
+ if @child.height.nil?
162
+ @child.height = @height
163
+ $log.warn " viewport setting child #{@child.name} to default h of #{@height} -- child is usually larger. "
164
+ else
165
+ if @cascade_changes
166
+ $log.debug "warn!! viewport adding #{delta} to child ht #{child.height} "
167
+ @child.height += delta
168
+ end
169
+ end
170
+ end
171
+ # set width
172
+ # a container must pass down changes in size to it's children
173
+ # added 2010-01-16 23:55
174
+ def width(*val)
175
+ return @width if val.empty?
176
+ oldvalue = @width || 0
177
+ super
178
+ @width = val[0]
179
+ return if @child == nil
180
+ delta = @width - oldvalue
181
+ return if delta == 0
182
+ @repaint_required = true
183
+ # another safeguard if user did not enter. usesomething sensible 2010-01-17 15:23
184
+ if @child.width.nil?
185
+ @child.width = @width
186
+ $log.warn " viewport setting child #{@child.name} to default w of #{@width}. Usually child is larger. "
187
+ else
188
+ ## sometime we are needless increasing. this happens when we set viewport and
189
+ ##+ child has been set. Or may do only if scrollpane is getting larger than child
190
+ ##+ largely a situation with splitpanes.
191
+ if @cascade_changes
192
+ $log.debug "warn!! viewport adding #{delta} to child wt #{child.width} "
193
+ @child.width += delta
194
+ end
195
+ end
196
+ end
197
+ # should this be in widget ?
198
+ # inform listeners that state has changed
199
+ def fire_state_changed
200
+ @sce = ChangeEvent.new(self) if @sce.nil?
201
+ fire_handler :STATE_CHANGE, @sce
202
+ end
203
+ end # class viewport
204
+ end # module
@@ -0,0 +1,130 @@
1
+ ## this class allows us to do multiple key mappings such as emacs
2
+ # See the example keytest.rb
3
+ # However, integrating this into our library seems a little difficult now
4
+ # since each widget handles keys and often there are heirachies of widgets.
5
+ # However, this being a terminal app, mouseless, we really need to make it key-friendly.
6
+ require 'rbcurse/core/include/orderedhash'
7
+ class Mapper
8
+ attr_reader :keymap
9
+ attr_reader :view
10
+ attr_accessor :mode
11
+ attr_reader :keys
12
+ def initialize handler
13
+ #@handler = handler
14
+ @view = handler # caller program
15
+ @keys = {}
16
+ @mode = nil # used when defining
17
+ @pendingkeys = nil
18
+ @prevkey = nil # in case of a key sequence such as C-x C-c, will have C-x
19
+ @arg = nil # regex matched this key.
20
+ end
21
+ def let mode, &block
22
+ h = OrderedHash.new
23
+ @keys[mode] = h
24
+ @mode = mode
25
+ instance_eval(&block)
26
+ $log.debug("KEYS: #{@keys[mode].inspect}")
27
+ end
28
+
29
+ ## mapping keys to blocks or symbols
30
+ # 2010-02-23 19:17 added check for string, so no required to use getbyte everywhere, esp for existing app
31
+ # However, this means that we can't map an actual string, which we may want to for commands
32
+ # which cuold be passed outside keys, or as aliases.
33
+ def map(*args, &block)
34
+ if block_given?
35
+
36
+ # We check for cases like C-x C-c etc. Only 2 levels.
37
+ #args = arg.split(/ +/)
38
+ arg0 = args[0]
39
+ arg0 = args[0].getbyte(0) if args[0].class.to_s == 'String'
40
+ if args.length == 2
41
+ arg1 = args[1]
42
+ arg1 = args[1].getbyte(0) if args[1].class.to_s == 'String'
43
+ $log.debug " KEY2 #{args[0]} , #{args[0].class}, #{args[1]} , #{args[1].class} "
44
+ @keys[@mode][arg0] ||= OrderedHash.new
45
+ @keys[@mode][arg0][arg1]=block
46
+ else
47
+ # single key or control key
48
+ $log.debug " KEY #{args[0]} , #{args[0].class} "
49
+ @keys[@mode][arg0]=block
50
+ end
51
+ else
52
+ #no block, last arg shold be a symbol
53
+ symb = args.pop
54
+ raise "If block not passed, last arg should be a method symbol" if !symb.is_a? Symbol
55
+ arg0 = args[0]
56
+ arg0 = args[0].getbyte(0) if args[0].class.to_s == 'String'
57
+ if args.length == 2
58
+ arg1 = args[1]
59
+ arg1 = args[1].getbyte(0) if args[1].class.to_s == 'String'
60
+ @keys[@mode][arg0] ||= OrderedHash.new
61
+ @keys[@mode][arg0][arg1]=symb
62
+ else
63
+ # single key or control key
64
+ @keys[@mode][arg0]=symb
65
+ end
66
+ end
67
+ end
68
+
69
+ ## manages key pressing
70
+ # takes care of multiple key combos too
71
+ def press key
72
+ #$log.debug("press Got: #{key}")
73
+ # for a double key combination such as C-x C-c this has the set of pending keys to check against
74
+ if @pendingkeys != nil
75
+ blk = @pendingkeys[key]
76
+ else
77
+ # this is the regular single key mode
78
+ #blk = @keys[@view.mode][key]
79
+ blk = match(key)
80
+ end
81
+ # this means this key expects more keys to follow such as C-x could
82
+ if blk.is_a? OrderedHash
83
+ @pendingkeys = blk
84
+ @prevkey = key
85
+ return
86
+ end
87
+ if blk.nil? # this should go up XXX
88
+ if !@pendingkeys.nil?
89
+ # this error message to be modified if using numeric keys -- need to convert to char
90
+ view.info("%p not valid in %p. Try: #{@pendingkeys.keys.join(', ')}" % [key, @prevkey]) # XXX
91
+ else
92
+ view.info("%p not valid in %p. " % [key, @view.mode])
93
+ end
94
+ return
95
+ end
96
+ # call the block or symbol - our user defined key mappings use symbols
97
+ if blk.is_a? Symbol
98
+ @view.send(blk)
99
+ else
100
+ blk.call
101
+ end
102
+ @prevkey = nil
103
+ @pendingkeys = nil
104
+ end
105
+ def match key
106
+ #$log.debug "MATCH #{key} "
107
+ #blk = @keys[@view.mode][key]
108
+ @keys[@view.mode].each_pair do |k,v|
109
+ #$log.debug "LOOP #{k.class}, #{k}, #{v} "
110
+ case k.class.to_s
111
+ when "String"
112
+ return v if k == key
113
+ when "Fixnum" # for keyboard2
114
+ #$log.debug "FIXNUM LOOP #{k.class}, #{k}, #{v} "
115
+ return v if k == key
116
+ when "Regexp"
117
+ # $log.debug "REGEX #key , #k, #{k.match(key)}"
118
+ key1 = key.chr if key.is_a? Fixnum
119
+ if !k.match(key1).nil?
120
+ @arg = key1
121
+ return v
122
+ end
123
+ else
124
+ $log.error "MATCH: Unhandled class #{k.class} "
125
+ end
126
+ end
127
+ $log.debug "MATCH #{key} ret nil "
128
+ return nil
129
+ end
130
+ end
@@ -0,0 +1,348 @@
1
+ =begin
2
+ * Name: rmessagebox: creates messageboxes
3
+ * Description
4
+ * Author: rkumar (arunachalesha)
5
+ * Date: 2008-11-19 12:49
6
+ * License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
7
+ * file separated on 2009-01-13 22:39
8
+
9
+ =end
10
+ require 'rbcurse/core/widgets/rwidget'
11
+ require 'rbcurse/extras/widgets/rlistbox'
12
+
13
+ module RubyCurses
14
+ ##
15
+ # dimensions of window should be derived on content
16
+ #
17
+ class MessageBox
18
+ include RubyCurses::Utils
19
+ dsl_accessor :title
20
+ dsl_accessor :message
21
+ dsl_accessor :type # :ok, :ok_cancel :yes_no :yes_no_cancel :custom
22
+ dsl_accessor :default_button # TODO - currently first
23
+ dsl_accessor :layout
24
+ dsl_accessor :buttons # used if type :custom
25
+ dsl_accessor :underlines # offsets of each button to underline
26
+ attr_reader :config
27
+ attr_reader :selected_index # button index selected by user
28
+ attr_reader :window # required for keyboard
29
+ dsl_accessor :list_selection_mode # true or false allow multiple selection
30
+ dsl_accessor :list # 2009-01-05 23:59
31
+ dsl_accessor :button_type # ok, ok_cancel, yes_no
32
+ dsl_accessor :default_value #
33
+ dsl_accessor :default_values # # 2009-01-06 00:05 after removing meth missing
34
+ dsl_accessor :height, :width, :top, :left # 2009-01-06 00:05 after removing meth missing
35
+
36
+ dsl_accessor :message_height
37
+
38
+
39
+ def initialize form=nil, aconfig={}, &block
40
+ @form = form
41
+ @config = aconfig
42
+ @buttons = []
43
+ #@keys = {}
44
+ @bcol = 5
45
+ @selected_index = -1
46
+ @config.each_pair { |k,v| instance_variable_set("@#{k}",v) }
47
+ instance_eval &block if block_given?
48
+ if @layout.nil?
49
+ case @type.to_s
50
+ when "input"
51
+ layout(10,60, 10, 20)
52
+ when "list"
53
+ height = [5, @list.length].min
54
+ layout(10+height, 60, 5, 20)
55
+ when "field_list"
56
+ height = @field_list.length
57
+ layout(10+height, 60, 5, 20)
58
+ when "override"
59
+ $log.debug " override: #{@height},#{@width}, #{@top}, #{@left} "
60
+ layout(@height,@width, @top, @left)
61
+ $log.debug " override: #{@layout.inspect}"
62
+ else
63
+ height = @form && @form.widgets.length ## quick fix. FIXME
64
+ height ||= 0
65
+ layout(10+height,60, 10, 20)
66
+ end
67
+ end
68
+ @window = VER::Window.new(@layout)
69
+ if @form.nil?
70
+ @form = RubyCurses::Form.new @window
71
+ else
72
+ @form.window = @window
73
+ end
74
+ acolor = get_color $reversecolor # this implicitly uses color and bgcolor fooling me often
75
+ $log.debug " MESSAGE BOX #{@bgcolor} , #{@color} , #{acolor}"
76
+ @window.bkgd(Ncurses.COLOR_PAIR(acolor));
77
+ @window.wrefresh
78
+ @panel = @window.panel
79
+ Ncurses::Panel.update_panels
80
+ process_field_list
81
+ print_borders
82
+ print_title
83
+ print_message unless @message.nil?
84
+ print_input
85
+ create_buttons
86
+ @form.repaint
87
+ @window.wrefresh
88
+ handle_keys
89
+ end
90
+ ##
91
+ # takes care of a field list sent in
92
+ def process_field_list
93
+ return if @field_list.nil? or @field_list.length == 0
94
+ @field_list.each do |f|
95
+ f.set_form @form
96
+ end
97
+ end
98
+ def default_button offset0
99
+ @selected_index = offset0
100
+ end
101
+ ##
102
+ # value entered by user if type = input
103
+ def input_value
104
+ return @input.buffer if !@input.nil?
105
+ return @listbox.getvalue if !@listbox.nil?
106
+ end
107
+ def create_buttons
108
+ case @button_type.to_s.downcase
109
+ when "ok"
110
+ make_buttons ["&OK"]
111
+ when "ok_cancel" #, "input", "list", "field_list"
112
+ make_buttons %w[&OK &Cancel]
113
+ # experience 2009-02-22 12:52 trapping y and n - hopefully wont cause an edit problem
114
+ @form.bind_key(?o){ press(?\M-o) } # called method takes care of getbyte 1.9
115
+ @form.bind_key(?c){ press(?\M-c) } # called method takes care of getbyte 1.9
116
+ when "yes_no"
117
+ make_buttons %w[&Yes &No]
118
+ # experience 2009-02-22 12:52 trapping y and n - hopefully wont cause an edit problem
119
+ @form.bind_key(?y){ press(?\M-y) } # called method takes care of getbyte 1.9
120
+ @form.bind_key(?n){ press(?\M-n) } # called method takes care of getbyte 1.9
121
+ when "yes_no_cancel"
122
+ make_buttons ["&Yes", "&No", "&Cancel"]
123
+ when "custom"
124
+ raise "Blank list of buttons passed to custom" if @buttons.nil? or @buttons.size == 0
125
+ make_buttons @buttons
126
+ else
127
+ $log.debug "No type passed for creating messagebox. Using default (OK)"
128
+ make_buttons ["&OK"]
129
+ end
130
+ end
131
+ def make_buttons names
132
+ total = names.inject(0) {|total, item| total + item.length + 4}
133
+ bcol = center_column total
134
+
135
+ brow = @layout[:height]-3
136
+ button_ct=0
137
+ names.each_with_index do |bname, ix|
138
+ text = bname
139
+ #underline = @underlines[ix] if !@underlines.nil?
140
+
141
+ button = Button.new @form do
142
+ text text
143
+ name bname
144
+ row brow
145
+ col bcol
146
+ #underline underline
147
+ highlight_background $datacolor
148
+ color $reversecolor
149
+ bgcolor $reversecolor
150
+ end
151
+ index = button_ct
152
+ button.command { |form| @selected_index = index; @stop = true; $log.debug "Pressed Button #{bname}";}
153
+ button_ct += 1
154
+ bcol += text.length+6
155
+ end
156
+ end
157
+ ## message box
158
+ def stopping?
159
+ @stop
160
+ end
161
+ def handle_keys
162
+ begin
163
+ while((ch = @window.getchar()) != 999 )
164
+ case ch
165
+ when -1
166
+ next
167
+ else
168
+ press ch
169
+ break if @stop
170
+ end
171
+ end
172
+ ensure
173
+ destroy
174
+ end
175
+ return @selected_index
176
+ end
177
+ def press ch
178
+ ch = ch.getbyte(0) if ch.class==String ## 1.9
179
+ case ch
180
+ when -1
181
+ return
182
+ when KEY_F1, 27, ?\C-q.getbyte(0)
183
+ @selected_index = -1
184
+ @stop = true
185
+ return
186
+ when KEY_ENTER, 10, 13
187
+ field = @form.get_current_field
188
+ if field.respond_to? :fire
189
+ field.fire
190
+ end
191
+ #$log.debug "popup ENTER : #{@selected_index} "
192
+ #$log.debug "popup ENTER : #{field.name}" if !field.nil?
193
+ @stop = true
194
+ return
195
+ when KEY_TAB
196
+ @form.select_next_field
197
+ when KEY_BTAB
198
+ @form.select_prev_field
199
+ else
200
+ # fields must return unhandled else we will miss hotkeys.
201
+ # On messageboxes, often if no edit field, then O and C are hot.
202
+ field = @form.get_current_field
203
+ handled = field.handle_key ch
204
+
205
+ if handled == :UNHANDLED
206
+ ret = @form.process_key ch, self ## trying out trigger button
207
+ end
208
+ end
209
+ @form.repaint
210
+ Ncurses::Panel.update_panels();
211
+ Ncurses.doupdate();
212
+ @window.wrefresh
213
+ end
214
+ def print_borders
215
+ width = @layout[:width]
216
+ height = @layout[:height]
217
+ @window.print_border_mb 1,2, height, width, $normalcolor, FFI::NCurses::A_REVERSE
218
+ =begin
219
+ start = 2
220
+ hline = "+%s+" % [ "-"*(width-((start+1)*2)) ]
221
+ hline2 = "|%s|" % [ " "*(width-((start+1)*2)) ]
222
+ @window.printstring(row=1, col=start, hline, color=$reversecolor)
223
+ (start).upto(height-2) do |row|
224
+ @window.printstring row, col=start, hline2, color=$normalcolor, A_REVERSE
225
+ end
226
+ @window.printstring(height-2, col=start, hline, color=$reversecolor)
227
+ =end
228
+ end
229
+ def print_title title=@title
230
+ width = @layout[:width]
231
+ title = " "+title+" "
232
+ @window.printstring(row=1,col=(width-title.length)/2,title, color=$normalcolor)
233
+ end
234
+ def center_column textlen
235
+ width = @layout[:width]
236
+ return (width-textlen)/2
237
+ end
238
+ def print_message message=@message, row=nil
239
+ @message_row = @message_col = 2
240
+ display_length = @layout[:width]-8
241
+ $log.debug " print_message: dl:#{display_length} "
242
+ # XXX this needs to go up and decide height of window
243
+ if @message_height.nil?
244
+ @message_height = (message.length/display_length)+2
245
+ #$log.debug " print_message: mh:#{@message_height}, ml: #{message.length}"
246
+ end
247
+ @message_height ||= 1
248
+ width = @layout[:width]
249
+ return if message.nil?
250
+ case @type.to_s
251
+ when "input"
252
+ row=(@layout[:height]/3) if row.nil?
253
+ @message_col = 4
254
+ when "list"
255
+ row=3
256
+ @message_col = 4
257
+ else
258
+ row=(@layout[:height]/3) if row.nil?
259
+ @message_col = (width-message.length)/2
260
+ @message_col = 4 if @message.is_a? Array
261
+ @message_col = 4 if @message_col < 4 # this was often disappearing 2010-10-17 13:00
262
+ #$log.debug "XX ALERT col #{@message_col} w: #{width} len: #{message.length} "
263
+ end
264
+ @message_row = row
265
+ # added 2009-11-05 14:53 to fix erasure of border
266
+ display_length -= @message_col
267
+ # 2008-12-30 19:45 experimenting with label so we can get justify and wrapping.
268
+ # 2011-09-20 trying to take care of when user changes color and bgcolor while calling.
269
+ clr = @color || :black
270
+ bgclr = @bgcolor || :white
271
+ message_label = RubyCurses::Label.new @form, {'text' => message, "name"=>"message_label","row" => row, "col" => @message_col, "display_length" => display_length, "height" => @message_height, 'bgcolor' => bgclr , 'color' => clr}
272
+
273
+ end
274
+ def print_input
275
+ #return if @type.to_s != "input"
276
+ @message_height ||= 0
277
+ @message_row ||= 2
278
+ @message_col ||= 2
279
+ r = @message_row + @message_height + 1
280
+ c = @message_col
281
+ disp_len = @layout[:width]-8
282
+ defaultvalue = @default_value || ""
283
+ input_config = @config["input_config"] || {} # see test1.rb for usage example
284
+ case @type.to_s
285
+ when "input"
286
+ @input = RubyCurses::Field.new @form, input_config do
287
+ name "input"
288
+ row r
289
+ col c
290
+ display_length disp_len
291
+ set_buffer defaultvalue
292
+ end
293
+ when "list"
294
+ list = @list
295
+ selection_mode = @list_selection_mode
296
+ default_values = @default_values
297
+ $log.debug " value of select_mode #{selection_mode}"
298
+ @listbox = RubyCurses::Listbox.new @form do
299
+ name "input"
300
+ row r
301
+ col c
302
+
303
+ color 'black'
304
+ bgcolor 'white'
305
+ # now listcellrenderer only uses BOLD for selected, with a white bgcolor
306
+ # so here it won't show up on white bg
307
+ selected_color 'red'
308
+ selected_bgcolor 'black'
309
+ # just added 2010-10-14 21:24
310
+ border_attrib :reverse
311
+ width 30
312
+ height 6
313
+ list list
314
+ # ?? display_length 30
315
+ #set_buffer defaultvalue
316
+ selection_mode selection_mode
317
+ default_values default_values
318
+ is_popup false
319
+ end
320
+ end
321
+ end
322
+ def configure(*val , &block)
323
+ case val.size
324
+ when 1
325
+ return @config[val[0]]
326
+ when 2
327
+ @config[val[0]] = val[1]
328
+ instance_variable_set("@#{val[0]}", val[1])
329
+ end
330
+ instance_eval &block if block_given?
331
+ end
332
+ def cget param
333
+ @config[param]
334
+ end
335
+
336
+ def layout(height=0, width=0, top=0, left=0)
337
+ @layout = { :height => height, :width => width, :top => top, :left => left }
338
+ end
339
+ def destroy
340
+ $log.debug "DESTROY : messagebox"
341
+ panel = @window.panel
342
+ #Ncurses::Panel.del_panel(panel) if !panel.nil?
343
+ panel.del_panel if !panel.nil?
344
+ @window.delwin if !@window.nil?
345
+ Ncurses::Panel.update_panels # 2011-10-1 so window below doesn't have a black rectangle
346
+ end
347
+ end
348
+ end