rbcurse-core 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/README.md +69 -0
  2. data/VERSION +1 -0
  3. data/examples/abasiclist.rb +151 -0
  4. data/examples/alpmenu.rb +46 -0
  5. data/examples/app.sample +17 -0
  6. data/examples/atree.rb +100 -0
  7. data/examples/common/file.rb +45 -0
  8. data/examples/data/README.markdown +9 -0
  9. data/examples/data/brew.txt +38 -0
  10. data/examples/data/color.2 +37 -0
  11. data/examples/data/gemlist.txt +60 -0
  12. data/examples/data/lotr.txt +12 -0
  13. data/examples/data/ports.txt +136 -0
  14. data/examples/data/table.txt +37 -0
  15. data/examples/data/tasks.csv +88 -0
  16. data/examples/data/tasks.txt +27 -0
  17. data/examples/data/todo.txt +10 -0
  18. data/examples/data/todocsv.csv +28 -0
  19. data/examples/data/unix1.txt +21 -0
  20. data/examples/data/unix2.txt +11 -0
  21. data/examples/dbdemo.rb +487 -0
  22. data/examples/dirtree.rb +90 -0
  23. data/examples/newtabbedwindow.rb +100 -0
  24. data/examples/newtesttabp.rb +92 -0
  25. data/examples/tabular.rb +132 -0
  26. data/examples/tasks.rb +167 -0
  27. data/examples/term2.rb +83 -0
  28. data/examples/testkeypress.rb +72 -0
  29. data/examples/testlistbox.rb +158 -0
  30. data/examples/testmessagebox.rb +140 -0
  31. data/examples/testree.rb +106 -0
  32. data/examples/testwsshortcuts.rb +66 -0
  33. data/examples/testwsshortcuts2.rb +127 -0
  34. data/lib/rbcurse.rb +8 -0
  35. data/lib/rbcurse/core/docs/index.txt +73 -0
  36. data/lib/rbcurse/core/include/action.rb +40 -0
  37. data/lib/rbcurse/core/include/appmethods.rb +112 -0
  38. data/lib/rbcurse/core/include/bordertitle.rb +41 -0
  39. data/lib/rbcurse/core/include/chunk.rb +182 -0
  40. data/lib/rbcurse/core/include/io.rb +953 -0
  41. data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
  42. data/lib/rbcurse/core/include/listeditable.rb +317 -0
  43. data/lib/rbcurse/core/include/listscrollable.rb +590 -0
  44. data/lib/rbcurse/core/include/listselectable.rb +264 -0
  45. data/lib/rbcurse/core/include/multibuffer.rb +83 -0
  46. data/lib/rbcurse/core/include/orderedhash.rb +77 -0
  47. data/lib/rbcurse/core/include/ractionevent.rb +67 -0
  48. data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
  49. data/lib/rbcurse/core/include/rhistory.rb +62 -0
  50. data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
  51. data/lib/rbcurse/core/include/vieditable.rb +170 -0
  52. data/lib/rbcurse/core/system/colormap.rb +163 -0
  53. data/lib/rbcurse/core/system/keyboard.rb +150 -0
  54. data/lib/rbcurse/core/system/keydefs.rb +30 -0
  55. data/lib/rbcurse/core/system/ncurses.rb +218 -0
  56. data/lib/rbcurse/core/system/panel.rb +162 -0
  57. data/lib/rbcurse/core/system/window.rb +901 -0
  58. data/lib/rbcurse/core/util/ansiparser.rb +117 -0
  59. data/lib/rbcurse/core/util/app.rb +1235 -0
  60. data/lib/rbcurse/core/util/basestack.rb +407 -0
  61. data/lib/rbcurse/core/util/bottomline.rb +1850 -0
  62. data/lib/rbcurse/core/util/colorparser.rb +71 -0
  63. data/lib/rbcurse/core/util/focusmanager.rb +31 -0
  64. data/lib/rbcurse/core/util/padreader.rb +189 -0
  65. data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
  66. data/lib/rbcurse/core/util/rdialogs.rb +619 -0
  67. data/lib/rbcurse/core/util/viewer.rb +149 -0
  68. data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
  69. data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
  70. data/lib/rbcurse/core/widgets/box.rb +58 -0
  71. data/lib/rbcurse/core/widgets/divider.rb +310 -0
  72. data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
  73. data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
  74. data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
  75. data/lib/rbcurse/core/widgets/rlink.rb +30 -0
  76. data/lib/rbcurse/core/widgets/rlist.rb +723 -0
  77. data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
  78. data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
  79. data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
  80. data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
  81. data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
  82. data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
  83. data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
  84. data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
  85. data/lib/rbcurse/core/widgets/rtree.rb +787 -0
  86. data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
  87. data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
  88. data/lib/rbcurse/core/widgets/statusline.rb +94 -0
  89. data/lib/rbcurse/core/widgets/tabular.rb +264 -0
  90. data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
  91. data/lib/rbcurse/core/widgets/textpad.rb +516 -0
  92. data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
  93. data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
  94. metadata +156 -0
@@ -0,0 +1,149 @@
1
+ require 'rbcurse/core/widgets/rtextview'
2
+ require 'fileutils'
3
+
4
+ # NOTE: experimental, not yet firmed up
5
+ # If you use in application, please copy to some application folder in case i change this.
6
+ # Can be used for print_help_page
7
+ # TODO: add vi_keys here
8
+ # SUGGESTIONS WELCOME.
9
+ # @since 1.2.0
10
+ module RubyCurses
11
+ # a data viewer for viewing some text or filecontents
12
+ # view filename, :close_key => KEY_ENTER
13
+ # send data in an array
14
+ # view Array, :close_key => KEY_ENTER, :layout => [0,0,23,80]
15
+ # when passing layout reserve 4 rows for window and border. So for 2 lines of text
16
+ # give 6 rows.
17
+ class Viewer
18
+ # @param filename as string or content as array
19
+ # @yield textview object for further configuration before display
20
+ # NOTE: i am experimentally yielding textview object so i could supress borders
21
+ # just for kicks, but on can also bind_keys or events if one wanted.
22
+ def self.view what, config={} #:yield: textview
23
+ case what
24
+ when String # we have a path
25
+ content = _get_contents(what)
26
+ when Array
27
+ content = what
28
+ else
29
+ raise ArgumentError, "Viewer: Expecting Filename or Contents (array), but got #{what.class} "
30
+ end
31
+ wt = 0 # top margin
32
+ wl = 0 # left margin
33
+ wh = Ncurses.LINES-wt # height, goes to bottom of screen
34
+ ww = Ncurses.COLS-wl # width, goes to right end
35
+ wt, wl, wh, ww = config[:layout] if config.has_key? :layout
36
+
37
+ fp = config[:title] || ""
38
+ pf = config.fetch(:print_footer, true)
39
+ ta = config.fetch(:title_attrib, 'bold')
40
+ fa = config.fetch(:footer_attrib, 'bold')
41
+ type = config[:content_type]
42
+
43
+ layout = { :height => wh, :width => ww, :top => wt, :left => wl }
44
+ v_window = VER::Window.new(layout)
45
+ v_form = RubyCurses::Form.new v_window
46
+ colors = Ncurses.COLORS
47
+ back = :blue
48
+ back = 235 if colors >= 256
49
+ blue_white = get_color($datacolor, :white, back)
50
+ #blue_white = RubyCurses::Utils.get_color($datacolor, :white, 235)
51
+ textview = TextView.new v_form do
52
+ name "Viewer"
53
+ row 0
54
+ col 0
55
+ width ww
56
+ height wh-0 # earlier 2 but seems to be leaving space.
57
+ title fp
58
+ title_attrib ta
59
+ print_footer pf
60
+ footer_attrib fa
61
+ #border_attrib :reverse
62
+ border_color blue_white
63
+ end
64
+ require 'rbcurse/core/include/multibuffer'
65
+ textview.extend(RubyCurses::MultiBuffers)
66
+
67
+ t = textview
68
+ t.bind_key('<', 'move window left'){ f = t.form.window; c = f.left - 1; f.hide; f.mvwin(f.top, c); f.show;
69
+ f.reset_layout([f.height, f.width, f.top, c]);
70
+ }
71
+ t.bind_key('>', 'move window right'){ f = t.form.window; c = f.left + 1; f.hide; f.mvwin(f.top, c);
72
+ f.reset_layout([f.height, f.width, f.top, c]); f.show;
73
+ }
74
+ t.bind_key('^', 'move window up'){ f = t.form.window; c = f.top - 1 ; f.hide; f.mvwin(c, f.left);
75
+ f.reset_layout([f.height, f.width, c, f.left]) ; f.show;
76
+ }
77
+ t.bind_key('V', 'move window down'){ f = t.form.window; c = f.top + 1 ; f.hide; f.mvwin(c, f.left);
78
+ f.reset_layout([f.height, f.width, c, f.left]); f.show;
79
+ }
80
+ # yielding textview so you may further configure or bind keys or events
81
+ begin
82
+ textview.set_content content, :content_type => type
83
+ textview.add_content content, :content_type => type
84
+ # the next can also be used to use formatted_text(text, :ansi)
85
+ yield textview if block_given?
86
+ v_form.repaint
87
+ v_window.wrefresh
88
+ Ncurses::Panel.update_panels
89
+ # allow closing using q and Ctrl-q in addition to any key specified
90
+ # user should not need to specify key, since that becomes inconsistent across usages
91
+ while((ch = v_window.getchar()) != ?\C-q.getbyte(0) )
92
+ break if ch == config[:close_key] || ch == ?q.ord
93
+ # if you've asked for ENTER then i also check for 10 and 13
94
+ break if (ch == 10 || ch == 13) && config[:close_key] == KEY_ENTER
95
+ v_form.handle_key ch
96
+ v_form.repaint
97
+ end
98
+ rescue => err
99
+ $log.error " VIEWER ERROR #{err} "
100
+ $log.debug(err.backtrace.join("\n"))
101
+ alert "Viewer:" + err.to_s
102
+ ensure
103
+ v_window.destroy if !v_window.nil?
104
+ end
105
+ end
106
+ private
107
+ def self._get_contents fp
108
+ return "File #{fp} not readable" unless File.readable? fp
109
+ return Dir.new(fp).entries if File.directory? fp
110
+ case File.extname(fp)
111
+ when '.tgz','.gz'
112
+ cmd = "tar -ztvf #{fp}"
113
+ content = %x[#{cmd}]
114
+ when '.zip'
115
+ cmd = "unzip -l #{fp}"
116
+ content = %x[#{cmd}]
117
+ when '.jar', '.gem'
118
+ cmd = "tar -tvf #{fp}"
119
+ content = %x[#{cmd}]
120
+ when '.png', '.out','.jpg', '.gif','.pdf'
121
+ content = "File #{fp} not displayable"
122
+ when '.sqlite'
123
+ cmd = "sqlite3 #{fp} 'select name from sqlite_master;'"
124
+ content = %x[#{cmd}]
125
+ else
126
+ content = File.open(fp,"r").readlines
127
+ end
128
+ end
129
+ end # class
130
+
131
+ end # module
132
+ if __FILE__ == $PROGRAM_NAME
133
+ require 'rbcurse/core/util/app'
134
+
135
+ App.new do
136
+ header = app_header "rbcurse 1.2.0", :text_center => "Viewer Demo", :text_right =>"New Improved!", :color => :black, :bgcolor => :white, :attr => :bold
137
+ message "Press F1 to exit from here"
138
+
139
+ RubyCurses::Viewer.view(ARGV[0] || $0, :close_key => KEY_ENTER, :title => "Enter to close") do |t|
140
+ # you may configure textview further here.
141
+ #t.suppress_borders true
142
+ #t.color = :black
143
+ #t.bgcolor = :white
144
+ # or
145
+ #t.attr = :reverse
146
+ end
147
+
148
+ end # app
149
+ end
@@ -0,0 +1,505 @@
1
+ # ------------------------------------------------------------ #
2
+ # File: widgetshortcuts.rb
3
+ # Description: A common module for shortcuts to create widgets
4
+ # Also, stacks and flows objects
5
+ # Author: rkumar http://github.com/rkumar/rbcurse/
6
+ # Date: 05.11.11 - 15:13
7
+ # Last update: 2011-11-21 - 19:28
8
+ #
9
+ # I hope this slowly does not become an unmaintainable maze like vimsplit
10
+ #
11
+ # "Simplicity hinges as much on cutting nonessential features as on adding helpful ones."
12
+ # - Walter Bender
13
+ #
14
+ # == TODO
15
+ # add multirow comps like textview and textarea, list
16
+ # add blocks that make sense like in app
17
+ # - what if user does not want form attached - app uses useform ot
18
+ # to check for this, if current_object don't add form
19
+ #
20
+ # - usage of _position inside means these shortcuts cannot be reused
21
+ # with other positioning systems, we'll be cut-pasting forever
22
+ #
23
+ # == CHANGES
24
+ # ------------------------------------------------------------ #
25
+ #
26
+
27
+ # what is the real purpose of the shortcuts, is it to avoid putting nil
28
+ # for form there if not required.
29
+ # Or is it positioning, such as in a stack. or just a method ?
30
+ require 'rbcurse/core/widgets/rlist'
31
+ require 'rbcurse/core/widgets/rtextview'
32
+ module RubyCurses
33
+ module WidgetShortcuts
34
+ class Ws
35
+ attr_reader :config
36
+ def initialize config={}
37
+ @config = config
38
+ end
39
+ def [](sym)
40
+ @config[sym]
41
+ end
42
+ def []=(sym, val)
43
+ @config[sym] = val
44
+ end
45
+ end
46
+ class WsStack < Ws; end
47
+ class WsFlow < Ws; end
48
+ def widget_shortcuts_init
49
+ @_ws_app_row = @_ws_app_col = 0
50
+ #@_ws_active = []
51
+ @_ws_active = nil # so we can use shortcuts if no stack used
52
+ @_ws_components = []
53
+ @variables = {}
54
+ end
55
+ def blank
56
+ label :text => ""
57
+ end
58
+ def line config={}
59
+ #horizontal line TODO
60
+ #row = config[:row] || @app_row
61
+ #width = config[:width] || 20
62
+ #_position config
63
+ #col = config[:col] || 1
64
+ #@color_pair = config[:color_pair] || $datacolor
65
+ #@attrib = config[:attrib] || Ncurses::A_NORMAL
66
+ #@window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
67
+ #@window.mvwhline( row, col, FFI::NCurses::ACS_HLINE, width)
68
+ #@window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
69
+ end
70
+ def radio config={}, &block
71
+ a = config[:group]
72
+ # should we not check for a nil
73
+ if @variables.has_key? a
74
+ v = @variables[a]
75
+ else
76
+ v = Variable.new
77
+ @variables[a] = v
78
+ end
79
+ config[:variable] = v
80
+ config.delete(:group)
81
+ w = RadioButton.new nil, config #, &block
82
+ _position w
83
+ if block
84
+ w.bind(:PRESS, &block)
85
+ end
86
+ return w
87
+ end
88
+ # create a shortcut for a class
89
+ # path is path of file to use in require starting with rbcurse
90
+ # klass is name of class to instantiate
91
+ def self.def_widget(path, klass, short=nil)
92
+ p=""
93
+ if path
94
+ p="require \"#{path}\""
95
+ end
96
+ short ||= klass.downcase
97
+ eval %{
98
+ def #{short}(config={}, &block)
99
+ if config.is_a? String
100
+ _s = config
101
+ config = {}
102
+ config[:text] = _s
103
+ end
104
+ #{p}
105
+ w = #{klass}.new nil, config
106
+ _position w
107
+ w.command &block if block_given?
108
+ return w
109
+ end
110
+ }
111
+ end
112
+ def_widget "rbcurse/core/widgets/rprogress", "Progress"
113
+ def_widget "rbcurse/core/widgets/scrollbar", "Scrollbar"
114
+ def_widget nil, "Label"
115
+ def_widget nil, "Field"
116
+ def_widget nil, :CheckBox, 'check'
117
+ def_widget nil, :Button
118
+ def_widget nil, :ToggleButton, 'toggle'
119
+ def menubar &block
120
+ require 'rbcurse/core/widgets/rmenu'
121
+ RubyCurses::MenuBar.new &block
122
+ end
123
+ def app_header title, config={}, &block
124
+ require 'rbcurse/core/widgets/applicationheader'
125
+ header = ApplicationHeader.new @form, title, config, &block
126
+ end
127
+ # editable text area
128
+ def textarea config={}, &block
129
+ require 'rbcurse/core/widgets/rtextarea'
130
+ # TODO confirm events many more
131
+ events = [ :CHANGE, :LEAVE, :ENTER ]
132
+ block_event = events[0]
133
+ #_process_args args, config, block_event, events
134
+ #config[:width] = config[:display_length] unless config.has_key? :width
135
+ # if no width given, expand to flows width
136
+ #config[:width] ||= @stack.last.width if @stack.last
137
+ useform = nil
138
+ #useform = @form if @current_object.empty?
139
+ w = TextArea.new useform, config
140
+ w.width = :expand unless w.width
141
+ w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
142
+ _position(w)
143
+ w.height ||= 8 # TODO
144
+ # need to expand to stack's width or flows itemwidth if given
145
+ if block
146
+ w.bind(block_event, &block)
147
+ end
148
+ return w
149
+ end
150
+ def textview config={}, &block
151
+ events = [ :LEAVE, :ENTER ]
152
+ block_event = events[0]
153
+ #_process_args args, config, block_event, events
154
+ #config[:width] = config[:display_length] unless config.has_key? :width
155
+ # if no width given, expand to flows width
156
+ #config[:width] ||= @stack.last.width if @stack.last
157
+ useform = nil
158
+ #useform = @form if @current_object.empty?
159
+ w = TextView.new useform, config
160
+ w.width = :expand unless w.width
161
+ w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
162
+ _position(w)
163
+ # need to expand to stack's width or flows itemwidth if given
164
+ if block
165
+ w.bind(block_event, &block)
166
+ end
167
+ return w
168
+ end
169
+ def listbox config={}, &block
170
+ events = [ :PRESS, :ENTER_ROW, :LEAVE, :ENTER ]
171
+ block_event = events[0]
172
+ #_process_args args, config, block_event, events
173
+ #config[:width] = config[:display_length] unless config.has_key? :width
174
+ # if no width given, expand to flows width
175
+ #config[:width] ||= @stack.last.width if @stack.last
176
+ useform = nil
177
+ #useform = @form if @current_object.empty?
178
+ w = List.new useform, config
179
+ w.width = :expand unless w.width
180
+ w.height ||= :expand # TODO We may need to push this before _position so it can be accounted for in stack
181
+ _position(w)
182
+ # need to expand to stack's width or flows itemwidth if given
183
+ if block
184
+ w.bind(block_event, &block)
185
+ end
186
+ return w
187
+ end
188
+ # prints pine-like key labels
189
+ def dock labels, config={}, &block
190
+ require 'rbcurse/core/widgets/keylabelprinter'
191
+ klp = RubyCurses::KeyLabelPrinter.new @form, labels, config, &block
192
+ end
193
+
194
+ def link config={}, &block
195
+ if config.is_a? String
196
+ _s = config
197
+ config = {}
198
+ config[:text] = _s
199
+ end
200
+ require 'rbcurse/core/widgets/rlink'
201
+ events = [ :PRESS, :LEAVE, :ENTER ]
202
+ block_event = :PRESS
203
+ config[:highlight_foreground] = "yellow"
204
+ config[:highlight_background] = "red"
205
+ toggle = Link.new nil, config
206
+ _position(toggle)
207
+ if block
208
+ toggle.bind(block_event, toggle, &block)
209
+ end
210
+ return toggle
211
+ end
212
+ def menulink config={}, &block
213
+ if config.is_a? String
214
+ _s = config
215
+ config = {}
216
+ config[:text] = _s
217
+ end
218
+ require 'rbcurse/core/widgets/rmenulink'
219
+ events = [ :PRESS, :LEAVE, :ENTER ]
220
+ block_event = :PRESS
221
+ config[:highlight_foreground] = "yellow"
222
+ config[:highlight_background] = "red"
223
+ #config[:hotkey] = true
224
+ w = MenuLink.new nil, config
225
+ _position(w)
226
+ if block
227
+ w.bind(block_event, w, &block)
228
+ end
229
+ return w
230
+ end
231
+ def tree config={}, &block
232
+ require 'rbcurse/core/widgets/rtree'
233
+ events = [:TREE_WILL_EXPAND_EVENT, :TREE_EXPANDED_EVENT, :TREE_SELECTION_EVENT, :PROPERTY_CHANGE, :LEAVE, :ENTER ]
234
+ block_event = nil
235
+ #config[:height] ||= 10
236
+ # if no width given, expand to flows width
237
+ useform = nil
238
+ #useform = @form if @current_object.empty?
239
+ w = Tree.new useform, config, &block
240
+ w.width ||= :expand
241
+ w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
242
+ _position w
243
+ return w
244
+ end
245
+ # creates a simple readonly table, that allows users to click on rows
246
+ # and also on the header. Header clicking is for column-sorting.
247
+ def tabular_widget config={}, &block
248
+ require 'rbcurse/core/widgets/tabularwidget'
249
+ events = [:PROPERTY_CHANGE, :LEAVE, :ENTER, :CHANGE, :ENTER_ROW, :PRESS ]
250
+ block_event = nil
251
+ # if no width given, expand to stack width
252
+ #config.delete :title
253
+ useform = nil
254
+
255
+ w = TabularWidget.new useform, config # NO BLOCK GIVEN
256
+ w.width ||= :expand
257
+ w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
258
+ _position(w)
259
+ if block_given?
260
+ #@current_object << w
261
+ yield_or_eval &block
262
+ #@current_object.pop
263
+ end
264
+ return w
265
+ end
266
+ alias :table :tabular_widget
267
+ def vimsplit config={}, &block
268
+ require 'rbcurse/extras/widgets/rvimsplit'
269
+ #TODO check these
270
+ events = [:PROPERTY_CHANGE, :LEAVE, :ENTER ]
271
+ block_event = nil
272
+ config[:height] ||= 10
273
+ _position(w)
274
+ # if no width given, expand to flows width
275
+ #config.delete :title
276
+ useform = nil
277
+
278
+ w = VimSplit.new useform, config # NO BLOCK GIVEN
279
+ if block_given?
280
+ #@current_object << w
281
+ #instance_eval &block if block_given?
282
+ yield w
283
+ #@current_object.pop
284
+ end
285
+ return w
286
+ end
287
+ def _position w
288
+ if @_ws_active.nil? || @_ws_active.empty?
289
+ # no stack or flow, this is independent usage, or else we are outside stacks and flows
290
+ #
291
+ # this is outside any stack or flow, so we do the minimal
292
+ # user should specify row and col
293
+ w.row ||= 0
294
+ w.col ||= 0
295
+ #$log.debug "XXX: LABEL #{w.row} , #{w.col} "
296
+ w.set_form @form if @form # temporary,, only set if not inside an object FIXME
297
+ if w.width == :expand # calculate from current col, not 0 FIXME
298
+ w.width = FFI::NCurses.COLS-w.col # or take windows width since this could be in a message box
299
+ end
300
+ if w.height == :expand
301
+ # take from current row, and not zero FIXME
302
+ w.height = FFI::NCurses.LINES-w.row # or take windows width since this could be in a message box
303
+ end
304
+ return
305
+
306
+ end
307
+ # -------------------------- there is a stack or flow -------------------- #
308
+ #
309
+ cur = @_ws_active.last
310
+ unless cur
311
+ raise "This should have been handled previously.Somethings wrong, check/untested"
312
+ end
313
+ r = cur[:row] || 0
314
+ c = cur[:col] || 0
315
+ w.row = r
316
+ w.col = c
317
+ # if flow then take flows height, else use dummy value
318
+ if w.height_pc
319
+ w.height = ( (cur[:height] * w.height_pc.to_i)/100).floor
320
+ end
321
+ if w.height == :expand
322
+ if cur.is_a? WsFlow
323
+ w.height = cur[:height] || 8 #or raise "height not known for flow"
324
+ else
325
+ w.height = cur[:item_height] || 8 #or raise "height not known for flow"
326
+ end
327
+ #alert "setting ht to #{w.height}, #{cur[:height]} , for #{cur} "
328
+ end
329
+ if w.width == :expand
330
+ if cur.is_a? WsFlow
331
+ if cur[:item_width]
332
+ w.width = cur[:item_width] #or raise "item_Width not known for flow #{cur.class}, #{cur[:item_width]}, #{cur[:width]} , #{w.width_pc} "
333
+ elsif w.width_pc
334
+ #w.width = w.width_pc * cur[:width]
335
+ w.width = (cur[:width] * (w.width_pc.to_i * 0.01)).floor
336
+ else
337
+ w.width = cur[:width]
338
+ end
339
+ raise "width could not be calculated. i need flow width and item width_pc" if w.width == :expand
340
+ else
341
+ w.width = cur[:width] or raise "Width not known for stack #{cur.class}, #{cur[:width]} "
342
+ end
343
+ end
344
+ if cur.is_a? WsStack
345
+ r += w.height || 1 # NOTE, we need to have height for this purpose defined BEFORE calling for list/text
346
+ cur[:row] = r
347
+ else
348
+ wid = cur[:item_width] || w.width || 10
349
+ c += wid + 1
350
+ cur[:col] = c
351
+ end
352
+ #alert "set width to #{w.width} ,cur: #{cur[:width]} ,iw: #{cur[:item_width]} "
353
+ if cur.is_a? WsFlow
354
+ unless w.height
355
+ w.height = cur[:height] #or raise "Height not known for flow"
356
+ end
357
+ end
358
+ w.color ||= cur[:color]
359
+ w.bgcolor ||= cur[:bgcolor]
360
+ w.set_form @form if @form # temporary
361
+ @_ws_components << w
362
+ cur[:components] << w
363
+ end
364
+ # make it as simple as possible, don't try to be intelligent or
365
+ # clever, put as much on the user
366
+ def stack config={}, &block
367
+ s = WsStack.new config
368
+ @_ws_active ||= []
369
+ _configure s
370
+ @_ws_active << s
371
+ yield_or_eval &block if block_given?
372
+ @_ws_active.pop
373
+
374
+ # ---- stack is finished now
375
+ last = @_ws_active.last
376
+ if last
377
+ case last
378
+ when WsStack
379
+ when WsFlow
380
+ last[:col] += last[:item_width] || 0
381
+ # this tries to set height of outer flow based on highest row
382
+ # printed, however that does not account for height of object,
383
+ # so user should give a height to the flow.
384
+ last[:height] = s[:row] if s[:row] > (last[:height]||0)
385
+ $log.debug "XXX: STACK setting col to #{s[:col]} "
386
+ end
387
+ end
388
+
389
+ end
390
+ #
391
+ # item_width - width to use per item
392
+ # but the item width may apply to stacks inside not to items
393
+ def flow config={}, &block
394
+ s = WsFlow.new config
395
+ @_ws_active ||= []
396
+ _configure s
397
+ @_ws_active << s
398
+ yield_or_eval &block if block_given?
399
+ @_ws_active.pop
400
+ last = @_ws_active.last
401
+ if last
402
+ case last
403
+ when WsStack
404
+ if s[:height]
405
+ last[:row] += s[:height]
406
+ else
407
+ #last[:row] += last[:highest_row]
408
+ last[:row] += 1
409
+ end
410
+ when WsFlow
411
+ last[:col] += last[:item_width] || 0
412
+ end
413
+ end
414
+ end
415
+ # flow and stack could have a border option
416
+ # NOTE: box takes one row below too, so :expand overwrites that line
417
+ def box config={}, &block
418
+ require 'rbcurse/core/widgets/box'
419
+ # take current stacks row and col
420
+ # advance row by one and col by one
421
+ # at end note row and advance by one
422
+ # draw a box around using these coordinates. width should be
423
+ # provided unless we have item width or something.
424
+ @_ws_active ||= []
425
+ last = @_ws_active.last
426
+ if last
427
+ r = last[:row]
428
+ c = last[:col]
429
+ config[:row] = r
430
+ config[:col] = c
431
+ last[:row] += config[:margin_top] || 1
432
+ last[:col] += config[:margin_left] || 1
433
+ _box = Box.new @form, config # needs to be created first or will overwrite area after others painted
434
+ yield_or_eval &block if block_given?
435
+ # FIXME last[height] needs to account for row
436
+ h = config[:height] || last[:height] || (last[:row] - r)
437
+ h = 2 if h < 2
438
+ w = config[:width] || last[:width] || 15 # tmp
439
+ case last
440
+ when WsFlow
441
+ w = last[:col]
442
+ when WsStack
443
+ #h += 1
444
+ end
445
+ config[:row] = r
446
+ config[:col] = c
447
+ config[:height] = h
448
+ config[:width] = w
449
+ _box.row r
450
+ _box.col c
451
+ _box.height h
452
+ _box.width w
453
+ last[:row] += 1
454
+ last[:col] += 1 # ??? XXX if flow we need to increment properly or not ?
455
+ end
456
+ end
457
+
458
+ # This configures a stack or flow not the objects inside
459
+ def _configure s
460
+ s[:row] ||= 0
461
+ s[:col] ||= 0
462
+ s[:row] += (s[:margin_top] || 0)
463
+ s[:col] += (s[:margin_left] || 0)
464
+ s[:width] = FFI::NCurses.COLS-s[:col] if s[:width] == :expand
465
+ s[:height] = FFI::NCurses.LINES-s[:row] if s[:height] == :expand # 2011-11-30
466
+ last = @_ws_active.last
467
+ if last
468
+ if s[:width_pc]
469
+ if last.is_a? WsStack
470
+ s[:width] = (last[:width] * (s[:width_pc].to_i * 0.01)).floor
471
+ else
472
+ # i think this width is picked up by next stack in this flow
473
+ last[:item_width] = (last[:width] * (s[:width_pc].to_i* 0.01)).floor
474
+ end
475
+ end
476
+ if s[:height_pc]
477
+ if last.is_a? WsFlow
478
+ s[:height] = ( (last[:height] * s[:height_pc].to_i)/100).floor
479
+ else
480
+ # this works only for flows within stacks not for an object unless
481
+ # you put a single object in a flow
482
+ s[:item_height] = ( (last[:height] * s[:height_pc].to_i)/100).floor
483
+ end
484
+ #alert "item height set as #{s[:height]} for #{s} "
485
+ end
486
+ if last.is_a? WsStack
487
+ s[:row] += (last[:row] || 0)
488
+ s[:col] += (last[:col] || 0)
489
+ else
490
+ s[:row] += (last[:row] || 0)
491
+ s[:col] += (last[:col] || 0) # we are updating with item_width as each st finishes
492
+ s[:width] ||= last[:item_width] #
493
+ end
494
+ else
495
+ # this should be outer most flow or stack, if nothing mentioned
496
+ # trying this out
497
+ s[:width] ||= :expand
498
+ s[:height] ||= :expand
499
+ s[:width] = FFI::NCurses.COLS-s[:col] if s[:width] == :expand
500
+ s[:height] = FFI::NCurses.LINES-s[:row] if s[:height] == :expand # 2011-11-30
501
+ end
502
+ s[:components] = []
503
+ end
504
+ end
505
+ end