rbcurse-experimental 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.
@@ -0,0 +1,69 @@
1
+ require 'rbcurse/core/widgets/rtree'
2
+ #require 'forwardable'
3
+ # we can extend from Tree but lets just try forwarding
4
+ module RubyCurses
5
+ # this class shows a tree of directories. Pressing ENTER expands or collapses
6
+ # the node. Pressing ENTER selects a node.
7
+ # Should we give options for displaying filenames also ? TODO
8
+ class DirectoryTree < Tree
9
+ attr_reader :selected_path
10
+ #@t = tree :data => model, :height => ht, :border_attrib => borderattrib, :suppress_borders => true
11
+ def _directories wd
12
+ d = Dir.new(wd)
13
+ ent = d.entries.reject{|e| !File.directory? File.join(wd,e)}
14
+ ent.delete(".");ent.delete("..")
15
+ return ent
16
+ end
17
+
18
+ def init_vars
19
+ super
20
+
21
+ one_key_selection = false
22
+ bind :TREE_WILL_EXPAND_EVENT do |node|
23
+ will_expand_action node
24
+ end
25
+
26
+ bind :TREE_SELECTION_EVENT do |ev|
27
+ selection_event ev
28
+ end
29
+ end # init_v
30
+
31
+ # populate this node with child directories
32
+ # this gives user application a chance to override or extend this action
33
+ def will_expand_action node
34
+ path = File.join(*node.user_object_path)
35
+ dirs = _directories path
36
+ ch = node.children
37
+ # add only children that may not be there
38
+ ch.each do |e|
39
+ o = e.user_object
40
+ if dirs.include? o
41
+ dirs.delete o
42
+ else
43
+ # delete this child since its no longer present TODO
44
+ end
45
+ end
46
+ node.add dirs
47
+ path_expanded path
48
+ end
49
+ # notify applications of path expanded so they may do any
50
+ # related action
51
+ # # NOTE: this is not the cleanest way, since you will need objects from your app
52
+ # scope here. User will have to add objects into the config hash after object creation
53
+ # and access them here. (See appdirtree.rb in examples)
54
+ def path_expanded path
55
+ end
56
+ def selection_event ev
57
+ if ev.state == :SELECTED
58
+ node = ev.node
59
+ path = File.join(*node.user_object_path)
60
+ @selected_path = path
61
+ selected_path_changed path
62
+ end
63
+ end
64
+ # inform applications that path has changed
65
+ # gives the user application a place to effect changes elsewhere in app
66
+ def selected_path_changed path
67
+ end
68
+ end # class
69
+ end
@@ -0,0 +1,166 @@
1
+ require 'rbcurse/extras/widgets/rvimsplit'
2
+ require 'forwardable'
3
+ # A convenience class that implements a 3 way Master Detail like form
4
+ # as in some email clients. See appemail.rb for usage.
5
+ # You may use this class or extend it. It takes care of expanding,
6
+ # increasing etc the 3 splits.
7
+ # This class is not fully tested beyond appemail.rb, and can change
8
+ # quite a bit. Users may want to copy this to prevent from major changes
9
+ # that could take place.
10
+ class MasterDetail < Widget
11
+ dsl_property :weight
12
+ attr_reader :vim # the vimsplit for any further configuration such as min_weight etc
13
+ extend Forwardable
14
+ def_delegators :@vim, :on_enter, :on_leave, :handle_key, :current_component
15
+ def initialize form, config={}, &block
16
+ @focusable = true
17
+ @height = Ncurses.LINES-2
18
+ @weight = 0.25
19
+ super
20
+ _create_vimsplit
21
+ init_vars
22
+ end
23
+ def init_vars #:nodoc:
24
+ @first_time = true
25
+ @repaint_required = true
26
+ end
27
+ def repaint
28
+ if @first_time
29
+ @first_time = nil
30
+ [@vim, @left, @right1, @right2].each { |e|
31
+ e.set_buffering(:target_window => @target_window || @form.window, :form => @form) # removed on 2011-09-29
32
+ }
33
+ end
34
+ @vim.repaint
35
+ end
36
+ # set the single component on the left side/pane, typically a +Listbox+.
37
+ # If an array is passed, the Listbox created is returned for further
38
+ # manipulation.
39
+ # @param [Widget] component to set on left
40
+ # @return [Widget] component added
41
+ def set_left_component comp, weight=nil
42
+ @left = @vim.add comp, :FIRST, weight
43
+ _add_component comp
44
+ @left
45
+ end
46
+ # set the first component on the right side/pane, typically a +Listbox+.
47
+ # @param [Widget] component to set on right
48
+ # @return [Widget] component added
49
+ def set_right_top_component comp, weight=0.5
50
+ @added_top = true
51
+ @right1 = @vim.add comp, :SECOND, weight
52
+ _add_component comp
53
+ @right1
54
+ end
55
+ # set the second component on the right side/pane, typically a
56
+ # +TextView+
57
+ # @param [Widget] component to set on right
58
+ # @return [Widget] component added
59
+ def set_right_bottom_component comp, weight=nil
60
+ raise "Please add top component first!" unless @added_top
61
+ # what if user gives in wrong order !!
62
+ @gb = @vim.add :divider, :SECOND, 0
63
+ @right2 = @vim.add comp, :SECOND, weight
64
+ @gb.next_component(@right2)
65
+ _add_component comp
66
+ @right2
67
+ end
68
+ def focus comp
69
+ case comp
70
+ when :left
71
+ @vim.goto_component @left
72
+ when :top_right
73
+ @vim.goto_component @right1
74
+ when :bottom_right
75
+ @vim.goto_component @right2
76
+ else
77
+ @vim.goto_component comp
78
+ end
79
+ end
80
+ private
81
+ # does nothing at present
82
+ def _add_component comp #:nodoc:
83
+ end
84
+ # creates a Vimplit containing 3 panes. Sets events in order to
85
+ # increase and decrease panes/windows.
86
+ def _create_vimsplit #:nodoc:
87
+ @vim = VimSplit.new nil, :row => @row, :col => @col, :width => @width, :height => @height, :weight => @weight, :orientation => :VERTICAL, :suppress_borders => true do |s|
88
+ s.parent_component = self
89
+ #s.target_window = @form.window
90
+ #s.add @left, :FIRST
91
+ #s.add @right1, :SECOND
92
+ #s.add @right2, :SECOND
93
+ s.bind :COMPONENT_RESIZE_EVENT do |e|
94
+ alert "masterdetail got a resize event #{e.type}, #{e.source} "
95
+ case e.type
96
+ when :INCREASE
97
+ case e.source
98
+ when @right2
99
+ increase_body
100
+ when @right1
101
+ increase_headers
102
+ when @left
103
+ alert "masterdetail left increase - not handled"
104
+
105
+ end
106
+ when :DECREASE
107
+ case e.source
108
+ when @right2
109
+ increase_headers
110
+ when @right1
111
+ increase_body
112
+ when @left
113
+ @left.width -= 1
114
+ @right2.col -=1
115
+ @right1.col -=1
116
+ @right1.width +=1
117
+ @right2.width +=1
118
+ @right2.repaint_required true
119
+ @right1.repaint_required true
120
+ @left.repaint_required true
121
+ alert "masterdetail left decrease"
122
+ end
123
+ when :EXPAND
124
+ case e.source
125
+ when @right2
126
+ h = 3
127
+ @right2.row(@right1.row + h)
128
+ oldh = @right1.height
129
+ @right1.height = h
130
+ @right1.current_index = 0
131
+ @right2.height += (oldh - h)
132
+ @right2.repaint_required true
133
+ @right1.repaint_required true
134
+ when @right1
135
+ h = 3
136
+ @right2.row(@right2.row + (@right2.height - 3))
137
+ oldh = @right2.height
138
+ @right2.height = h
139
+ #@right1.current_index = 0
140
+ @right1.height += (oldh - h)
141
+ @right2.repaint_required true
142
+ @right1.repaint_required true
143
+ end
144
+ end
145
+ end # bind
146
+ end
147
+ end # def
148
+ # increase the top right pane and reduces lower one
149
+ # TODO: to take into account multiplier
150
+ def increase_headers #:nodoc:
151
+ @right2.row @right2.row()+1
152
+ @right1.height +=1
153
+ @right2.height -=1
154
+ @right2.repaint_required true
155
+ @right1.repaint_required true
156
+ end
157
+ # decrease the top right pane and increase lower one
158
+ # TODO: to take into account multiplier
159
+ def increase_body #:nodoc:
160
+ @right2.row @right2.row()-1
161
+ @right1.height -=1
162
+ @right2.height +=1
163
+ @right2.repaint_required true
164
+ @right1.repaint_required true
165
+ end
166
+ end # class
@@ -0,0 +1,330 @@
1
+ =begin
2
+ * Name: Multiform.rb
3
+ * Description View (cycle) multiple forms
4
+ * Author: rkumar (arunachalesha)
5
+ * file created 2011-10-17 8:18 PM
6
+ --------
7
+ * License:
8
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
9
+
10
+ =end
11
+ require 'rbcurse'
12
+
13
+ include RubyCurses
14
+ module RubyCurses
15
+ extend self
16
+
17
+ # Trying to implement TabbedPanes using a multiform approach, but no more windows
18
+ # or pads. Try to keep it as simple as possible
19
+ class MultiForm < Widget
20
+ dsl_accessor :title
21
+
22
+
23
+ def initialize form = nil, config={}, &block
24
+ @focusable = true
25
+ @window = form.window
26
+ @row_offset = @col_offset = 1
27
+ @bmanager = BufferManager.new self
28
+ @forms = []
29
+ super
30
+ init_vars
31
+
32
+ end
33
+ def init_vars
34
+ super
35
+ # the following allows us to navigate buffers with :bn :bp etc (with Alt pressed)
36
+ bind_key(?\M-:, :buffer_menu)
37
+ bind_key(?\M-;, :buffer_menu)
38
+ # bind_key([?\C-x, ?f], :file_edit)
39
+ bind_key([?\C-x, ?k], :delete_component)
40
+ bind_key([?\C-x, ?\C-b], :list_components)
41
+ bind_key(?\M-n, :goto_next_component)
42
+ bind_key(?\M-p, :goto_prev_component)
43
+ bind_key(?\M-1, :goto_first_component)
44
+ # easily cycle using p. n is used for next search.
45
+ #bind_key(?p, :buffer_previous)
46
+ @suppress_borders = false
47
+ @repaint_all = true
48
+ @name ||= "multiform"
49
+ end
50
+ ## returns current buffer
51
+ # @return [RBuffer] current buffer
52
+ def current_component
53
+ @bmanager.current
54
+ end
55
+ ##
56
+ # multi-container
57
+ def handle_key ch #:nodoc:
58
+ @current_component.repaint
59
+ @current_component.window.wrefresh
60
+ $log.debug " MULTI handle_key #{ch}, #{@current_component}"
61
+ ret = :UNHANDLED
62
+ return :UNHANDLED unless @current_component
63
+ ret = @current_component.handle_key(ch)
64
+ $log.debug " MULTI comp #{@current_component} returned #{ret} "
65
+ if ret == :UNHANDLED
66
+ # check for bindings, these cannot override above keys since placed at end
67
+ begin
68
+ ret = process_key ch, self
69
+ $log.debug " MULTI = process_key returned #{ret} "
70
+ if ch > 177 && ch < 187
71
+ n = ch - 177
72
+ component_at(n)
73
+ # go to component n
74
+ end
75
+ rescue => err
76
+ # $error_message = err # changed 2010 dts
77
+ $error_message.value = err.to_s
78
+ #@form.window.print_error_message PLEASE CREATE LABEL
79
+ $log.error " Multicomponent process_key #{err} "
80
+ $log.debug(err.backtrace.join("\n"))
81
+ alert err.to_s
82
+ end
83
+ return :UNHANDLED if ret == :UNHANDLED
84
+ end
85
+ @current_component.repaint
86
+ @current_component.window.wrefresh
87
+ FFI::NCurses.update_panels
88
+
89
+ # check for any keys not handled and check our own ones
90
+ return ret #
91
+ end
92
+ def repaint
93
+ print_border if (@suppress_borders == false && @repaint_all) # do this once only, unless everything changes
94
+ return unless @current_component
95
+ $log.debug " MULTIFORM REPAINT "
96
+ ret = @current_component.repaint
97
+ end
98
+ def print_border #:nodoc:
99
+ $log.debug " #{@name} print_borders, #{@graphic.name} "
100
+ color = $datacolor
101
+ @graphic.print_border_only @row, @col, @height-1, @width, color #, Ncurses::A_REVERSE
102
+ print_title
103
+ end
104
+ def print_title #:nodoc:
105
+ $log.debug " print_title #{@row}, #{@col}, #{@width} #{@title} "
106
+ @graphic.printstring( @row, @col+(@width-@title.length)/2, @title, $datacolor, @title_attrib) unless @title.nil?
107
+ end
108
+ # this is just a test of the simple "most" menu
109
+ # can use this for next, prev, first, last, new, delete, overwrite etc
110
+ def buffer_menu
111
+ menu = PromptMenu.new self
112
+ menu.add(menu.create_mitem( 'l', "list buffers", "list buffers ", :list_components ))
113
+ item = menu.create_mitem( 'b', "Buffer Options", "Buffer Options" )
114
+ menu1 = PromptMenu.new( self, "Buffer Options")
115
+ menu1.add(menu1.create_mitem( 'n', "Next", "Switched to next buffer", :goto_next_component ))
116
+ menu1.add(menu1.create_mitem( 'p', "Prev", "Switched to previous buffer", :goto_prev_component ))
117
+ menu1.add(menu1.create_mitem( 'f', "First", "Switched to first buffer", :goto_first_component ))
118
+ menu1.add(menu1.create_mitem( 'l', "Last", "Switched to last buffer", :goto_last_component ))
119
+ menu1.add(menu1.create_mitem( 'd', "Delete", "Deleted buffer", :delete_component ))
120
+ item.action = menu1
121
+ menu.add(item)
122
+ # how do i know what's available. the application or window should know where to place
123
+ menu.display @form.window, $error_message_row, $error_message_col, $datacolor #, menu
124
+ end
125
+
126
+
127
+ def goto_next_component
128
+ perror "No other buffer" and return if @bmanager.size < 2
129
+
130
+ @current_component = @bmanager.next
131
+ set_current_component
132
+ # set_form_row and shit
133
+ end
134
+
135
+ def goto_prev_component
136
+ perror "No other buffer" and return if @bmanager.size < 2
137
+
138
+ @current_component = @bmanager.previous
139
+ $log.debug " buffer_prev got #{@current_component} "
140
+ set_current_component
141
+ end
142
+ def goto_first_component
143
+ @current_component = @bmanager.first
144
+ $log.debug " buffer_first got #{@current_component} "
145
+ set_current_component
146
+ end
147
+ def goto_last_component
148
+ @current_component = @bmanager.last
149
+ $log.debug " buffer_last got #{@current_component} "
150
+ set_current_component
151
+ end
152
+ def delete_component
153
+ if @bmanager.size > 1
154
+ @bmanager.delete_at
155
+ @current_component = @bmanager.previous
156
+ set_current_component
157
+ else
158
+ perror "Only one buffer. Cannot delete."
159
+ end
160
+ end
161
+
162
+ def component_at index
163
+ cc = @bmanager.element_at index
164
+ return unless cc
165
+ @current_component = cc
166
+ #$log.debug " buffer_last got #{@current_component} "
167
+ set_current_component
168
+ end
169
+ def add_form title, config={}, &blk
170
+ $log.debug "XXX: add_form window coords were hwtl #{@height} , #{@width} , #{@top} , #{@left} "
171
+ #w = VER::Window.new 16, 30, 2, 2 #@height-1, @width-1, @top, @left
172
+ w = VER::Window.new @height-2, @width-2, @row+1, @col+1
173
+ #w.box(0,0)
174
+ frm = Form.new w
175
+ @forms << frm
176
+ frm.parent_form = @form
177
+ frm.add_cols=@col+@col_offset
178
+ frm.add_rows=@row+@row_offset
179
+ @current_component = @bmanager.add frm, title
180
+ set_current_component
181
+ yield frm if block_given?
182
+ return @current_component # not a form but a Rcomponent containing component and title
183
+ end
184
+ def _add_to(index, component)
185
+ raise ArgumentError, "index out of bounds" unless @forms[index]
186
+ component.set_form(@forms[index])
187
+ $log.debug "XXX: comp r c #{component.row} #{component.col} "
188
+ component.row += @row
189
+ component.col += @col
190
+ $log.debug "XXX: after comp r c #{component.row} #{component.col} "
191
+ end
192
+ ##
193
+ # Add a component with a title
194
+ # @param [Widget] component
195
+ # @param [String] title
196
+ def add component, title
197
+ component.row = @row+@row_offset+0 # FFI changed 1 to 0 2011-09-12
198
+ component.col = @col+@col_offset+0 # FFI changed 1 to 0 2011-09-12
199
+ component.width = @width-2
200
+ component.height = @height-2
201
+ component.form = @form
202
+ component.override_graphic(@graphic)
203
+ @current_component = @bmanager.add component, title
204
+ set_current_component
205
+ set_form_row ## FFI added 2011-09-12 to get cursor at start when adding
206
+ $log.debug " ADD got cb : #{@current_component} "
207
+ end
208
+ def set_current_component
209
+ @title = @current_component.title
210
+ @current_component = @current_component.component
211
+ @current_component.repaint #2011-10-17 need to set all comps to repaint XXX
212
+ @current_component.window.wrefresh
213
+ @current_component.window.show
214
+ FFI::NCurses.update_panels
215
+ set_form_row
216
+ #@current_title = @current_component.title
217
+ #@current_component.repaint_all true 2011-10-17 need to set all comps to repaint XXX
218
+ end
219
+ def perror errmess
220
+ alert errmess
221
+ #@form.window.print_error_message errmess
222
+ end
223
+ def list_components
224
+ $log.debug " TODO buffers_list: #{@bmanager.size} "
225
+ menu = PromptMenu.new self
226
+ @bmanager.each_with_index{ |b, ix|
227
+ aproc = Proc.new { component_at(ix) }
228
+ name = b.title
229
+ num = ix + 1
230
+ menu.add(menu.create_mitem( num.to_s, name, "Switched to buffer #{ix}", aproc ))
231
+ }
232
+ menu.display @form.window, $error_message_row, $error_message_col, $datacolor
233
+ end
234
+ # required otherwise some components may not get correct cursor position on entry
235
+ # e.g. table
236
+ def on_enter
237
+ set_form_row # 2011-10-17
238
+ end
239
+ # nothing happening, the cursor goes to 1,1 and does not move
240
+ # alhough the fields can be edited XXX
241
+ def set_form_row #:nodoc:
242
+ if !@current_component.nil?
243
+ #$log.debug " #{@name} set_form_row calling sfr for #{@current_component.name} "
244
+ #fc = @current_component.widgets[0]
245
+ fc = @current_component.get_current_field
246
+ fc ||= @current_component.widgets[0]
247
+ fc.set_form_row if fc
248
+ #fc.set_form_col
249
+ end
250
+ end
251
+ # ADD HERE
252
+ end # class multicontainer
253
+ ##
254
+ # Handles multiple buffers, navigation, maintenance etc
255
+ # Instantiated at startup of
256
+ #
257
+ class BufferManager
258
+ include Enumerable
259
+ def initialize source
260
+ @source = source
261
+ @buffers = [] # contains RBuffer
262
+ @counter = 0
263
+ # for each buffer i need to store data, current_index (row), curpos (col offset) and title (filename).
264
+ end
265
+ def element_at index
266
+ @buffers[index]
267
+ end
268
+ def each
269
+ @buffers.each {|k| yield(k)}
270
+ end
271
+
272
+ ##
273
+ # @return [RBuffer] current buffer/file
274
+ ##
275
+ def current
276
+ @buffers[@counter]
277
+ end
278
+ ##
279
+ # Would have liked to just return next buffer and not get lost in details of caller
280
+ #
281
+ # @return [RBuffer] next buffer/file
282
+ ##
283
+ def next
284
+ @counter += 1
285
+ @counter = 0 if @counter >= @buffers.size
286
+ @buffers[@counter]
287
+ end
288
+ ##
289
+ # @return [RBuffer] previous buffer/file
290
+ ##
291
+ def previous
292
+ $log.debug " previous bs: #{@buffers.size}, #{@counter} "
293
+ @counter -= 1
294
+ return last() if @counter < 0
295
+ $log.debug " previous ctr #{@counter} "
296
+ @buffers[@counter]
297
+ end
298
+ def first
299
+ @counter = 0
300
+ @buffers[@counter]
301
+ end
302
+ def last
303
+ @counter = @buffers.size - 1
304
+ @buffers[@counter]
305
+ end
306
+ ##
307
+ def delete_at index=@counter
308
+ @buffers.delete_at index
309
+ end
310
+ def delete_by_name name
311
+ @buffers.delete_if {|b| b.filename == name }
312
+ end
313
+ def insert component, position, title=nil
314
+ anew = RComponents.new(component, title)
315
+ @buffers.insert position, anew
316
+ @counter = position
317
+ return anew
318
+ end
319
+ def add component, title=nil
320
+ #$log.debug " ADD H: #{component.height} C: #{component.width} "
321
+ insert component, @buffers.size, title
322
+ end
323
+ def size
324
+ @buffers.size
325
+ end
326
+ alias :count :size
327
+ end
328
+ RComponents = Struct.new(:component, :title)
329
+
330
+ end # modul