rbcurse-core 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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