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.
- data/README.markdown +75 -0
- data/VERSION +1 -0
- data/examples/teststackflow.rb +113 -0
- data/lib/rbcurse/experimental/widgets/directorylist.rb +467 -0
- data/lib/rbcurse/experimental/widgets/directorytree.rb +69 -0
- data/lib/rbcurse/experimental/widgets/masterdetail.rb +166 -0
- data/lib/rbcurse/experimental/widgets/multiform.rb +330 -0
- data/lib/rbcurse/experimental/widgets/resultsetbrowser.rb +281 -0
- data/lib/rbcurse/experimental/widgets/resultsettextview.rb +586 -0
- data/lib/rbcurse/experimental/widgets/rscrollform.rb +418 -0
- data/lib/rbcurse/experimental/widgets/stackflow.rb +478 -0
- data/lib/rbcurse/experimental/widgets/undomanager.rb +188 -0
- metadata +89 -0
data/README.markdown
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# rbcurse-experimental
|
2
|
+
|
3
|
+
This is related to the rbcurse ncurses toolkit, for building ncurses applications.
|
4
|
+
|
5
|
+
This provides stuff I've experimented with, and tested to some extent. It can be useful stuff to build upon
|
6
|
+
or to even use if it suits your purposes. Most of this stuff has been tested with positive cases and not
|
7
|
+
with negative data. It is minimally tested.
|
8
|
+
|
9
|
+
Use for home or unimportant programs, preferable don't release these widgets for public use.
|
10
|
+
|
11
|
+
Please submit patches if you find bugs or improve upon it.
|
12
|
+
|
13
|
+
> We better hurry up and start coding, there are going to be a lot of bugs to fix.
|
14
|
+
|
15
|
+
Contents as of time of creation of repo:
|
16
|
+
|
17
|
+
* directorylist.rb - shows directory in a list, allowing various kinds of selection and filtering and ENTER
|
18
|
+
|
19
|
+
* directorytree.rb - shows directory in a tree, allowing expansion
|
20
|
+
|
21
|
+
* masterdetail.rb - master detail pattern, two widgets
|
22
|
+
|
23
|
+
* multiform.rb - do not touch this at all. Should be nuked. It works but in order to keep
|
24
|
+
rbcurse simple and maintainable, I advise against using forms within forms. I've spent
|
25
|
+
weeks and months tracking cursor placement for forms within forms as in the old
|
26
|
+
tabbedpane and some old deprecated widgets.
|
27
|
+
|
28
|
+
* resultsetbrowser.rb - I am working on database aware widgets, check dbdemo.rb in examples
|
29
|
+
|
30
|
+
* resultsettextview.rb - same as above
|
31
|
+
|
32
|
+
* rscrollform.rb - a form that can display more objects than the window, scrolls horiz and vertically.
|
33
|
+
Used and tested only with single line widgets like Field, not with textviews and lists.
|
34
|
+
|
35
|
+
* stackflow.rb - widget that allows complex weightages to be assigned to stacks and flows
|
36
|
+
and resizing if window dimension changes. Tested only with weightages and not
|
37
|
+
absolute sizes. Expects weightages to be correct. More work can go into this
|
38
|
+
to make it robust.
|
39
|
+
|
40
|
+
* undomanager.rb - used in lists and textareas to support undo and redo. I've used it but
|
41
|
+
its a very simple piece of code and I am not too confident how well it will stand
|
42
|
+
in heavy use. Certainly use it for lists and textareas in personal applications.
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
## Short story
|
47
|
+
|
48
|
+
Minimally tested but interesting stuff
|
49
|
+
|
50
|
+
## Long story
|
51
|
+
|
52
|
+
Use stuff here at your own risk. Most of this works, and will work in most situations but may not take care validations, extreme cases, wrong data passed.
|
53
|
+
|
54
|
+
Its tested for basic use cases. Samples should help you. Don't use in production, or release for others to use. Use for personal use if you have too.
|
55
|
+
|
56
|
+
|
57
|
+
Feel free to fork and further develop stuff in here, or submit patches to me.
|
58
|
+
|
59
|
+
Some of this stuff may move to extras or core if its really useful and stable.
|
60
|
+
|
61
|
+
## See also
|
62
|
+
|
63
|
+
* rbcurse - <http://github.com/rkumar/rbcurse/>
|
64
|
+
|
65
|
+
* rbcurse-core - <http://github.com/rkumar/rbcurse-core/>
|
66
|
+
|
67
|
+
* rbcurse-extras - <http://github.com/rkumar/rbcurse-extras/>
|
68
|
+
|
69
|
+
## Install
|
70
|
+
|
71
|
+
gem install rbcurse-experimental
|
72
|
+
|
73
|
+
## License
|
74
|
+
|
75
|
+
Same as ruby license.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# #!/usr/bin/env ruby -w
|
2
|
+
=begin
|
3
|
+
* Name : teststackflow.rb
|
4
|
+
* Description : to test Container2.rb (to be renamed)
|
5
|
+
* :
|
6
|
+
* Author : rkumar http://github.com/rkumar/rbcurse/
|
7
|
+
* Date : 25.10.11 - 12:57
|
8
|
+
* License :
|
9
|
+
* Last update : Use ,,L to update
|
10
|
+
Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
11
|
+
|
12
|
+
=end
|
13
|
+
|
14
|
+
|
15
|
+
if __FILE__ == $PROGRAM_NAME
|
16
|
+
require 'rbcurse/core/util/app'
|
17
|
+
require 'rbcurse/extras/widgets/rlistbox'
|
18
|
+
require 'rbcurse/experimental/widgets/stackflow'
|
19
|
+
App.new do
|
20
|
+
|
21
|
+
lb = Listbox.new nil, :list => ["borodin","berlioz","bernstein","balakirev", "elgar"] , :name => "mylist"
|
22
|
+
lb1 = Listbox.new nil, :list => ["bach","beethoven","mozart","gorecki", "chopin","wagner","grieg","holst"] , :name => "mylist1"
|
23
|
+
|
24
|
+
lb2 = Listbox.new nil, :list => `gem list --local`.split("\n") , :name => "mylist2"
|
25
|
+
|
26
|
+
alist = %w[ ruby perl python java jruby macruby rubinius rails rack sinatra pylons django cakephp grails]
|
27
|
+
str = "Hello, people of Earth.\nI am HAL, a textbox.\nUse arrow keys, j/k/h/l/gg/G/C-a/C-e/C-n/C-p\n"
|
28
|
+
str << alist.join("\n")
|
29
|
+
require 'rbcurse/core/widgets/rtextview'
|
30
|
+
tv = TextView.new nil, :name => "text"
|
31
|
+
tv.set_content str
|
32
|
+
=begin
|
33
|
+
f1 = field "name", :maxlen => 20, :display_length => 20, :bgcolor => :white,
|
34
|
+
:color => :black, :text => "abc", :label => " Name: ", :label_color_pair => @datacolor
|
35
|
+
f2 = field "email", :display_length => 20, :bgcolor => :white,
|
36
|
+
:color => :blue, :text => "me@google.com", :label => "Email: ", :label_color_pair => @datacolor
|
37
|
+
f3 = radio :group => :grp, :text => "red", :value => "RED", :color => :red
|
38
|
+
f4 = radio :group => :grp, :text => "blue", :value => "BLUE", :color => :blue
|
39
|
+
f5 = radio :group => :grp, :text => "green", :value => "GREEN", :color => :green
|
40
|
+
=end
|
41
|
+
|
42
|
+
f1 = Field.new nil, :maxlen => 20, :display_length => 20, :bgcolor => :white,
|
43
|
+
:color => :black, :text => "abc", :label => " Name: ", :label_color_pair => @datacolor,
|
44
|
+
:valid_regex => /[A-Z][a-z]*/
|
45
|
+
f2 = Field.new nil, :display_length => 20, :bgcolor => :white,
|
46
|
+
:color => :blue, :text => "me@google.com", :label => "Email: ", :label_color_pair => @datacolor
|
47
|
+
f3 = Field.new nil, :display_length => 20, :bgcolor => :white,
|
48
|
+
:color => :blue, :text => "24", :label => "Age: ", :label_color_pair => @datacolor,
|
49
|
+
:valid_range => (20..100)
|
50
|
+
w = Ncurses.COLS-1
|
51
|
+
h = Ncurses.LINES-3
|
52
|
+
r = StackFlow.new @form, :row => 1, :col => 1, :width => w, :height => h, :title => "Stack n Flow with margins" do
|
53
|
+
#stack :margin_top => 2, :margin_left => 1 do
|
54
|
+
flow :margin_top => 0, :margin_left => 2, :margin_right => 0, :orientation => :right do #:weight => 49 do
|
55
|
+
add tv, :weight => 40
|
56
|
+
add lb2 , :weight => 50
|
57
|
+
end
|
58
|
+
stack :margin_top => 0, :orientation => :bottom do #stack :height => 12, :width => 78 do
|
59
|
+
add lb, :weight => 40, :margin_left => 1
|
60
|
+
add lb1 , :weight => 40
|
61
|
+
#add f1
|
62
|
+
#stack :weight => 30 do
|
63
|
+
#add f1
|
64
|
+
#add f2
|
65
|
+
#add f3
|
66
|
+
end
|
67
|
+
#end # stack
|
68
|
+
end # r
|
69
|
+
def increase_height
|
70
|
+
@r.height += 1
|
71
|
+
@r.repaint_all(true)
|
72
|
+
end
|
73
|
+
def increase_width
|
74
|
+
@r.width += 1
|
75
|
+
@r.repaint_all(true)
|
76
|
+
end
|
77
|
+
@r = r
|
78
|
+
@r.bind_key(?\M-w) {increase_width}
|
79
|
+
@r.bind_key(?\M-h) {increase_height}
|
80
|
+
@r.bind_key(0) {
|
81
|
+
f = @r.item_for tv
|
82
|
+
f1 = @r.item_for lb2
|
83
|
+
p = @r.parent_of tv
|
84
|
+
p1 = @r.parent_of lb2
|
85
|
+
$log.debug "XXX: ITEM_FOR tv is #{f}, #{f1} #{p} , #{p1} "
|
86
|
+
@ctr ||= 0
|
87
|
+
case @ctr
|
88
|
+
when 0
|
89
|
+
@r.components[0].orientation = :left
|
90
|
+
when 1
|
91
|
+
@r.components[0].orientation = :right
|
92
|
+
when 2
|
93
|
+
@r.components[1].orientation = :top
|
94
|
+
when 3
|
95
|
+
@r.components[1].orientation = :bottom
|
96
|
+
else
|
97
|
+
@ctr = -1
|
98
|
+
end
|
99
|
+
$status_message.value =" Flow: #{@r.components[0].orientation} | Stack #{@r.components[1].orientation}. Use C-Space to change "
|
100
|
+
@r.repaint_all(true)
|
101
|
+
@ctr += 1
|
102
|
+
|
103
|
+
}
|
104
|
+
$status_message.value =" Flow: #{@r.components[0].orientation} | Stack #{@r.components[1].orientation}. Use Ctrl-Space to change "
|
105
|
+
|
106
|
+
#r.add(f1)
|
107
|
+
#r.add(f2)
|
108
|
+
#r.add(f3,f4,f5)
|
109
|
+
#sl = status_line
|
110
|
+
|
111
|
+
st = status_line :row => -1
|
112
|
+
end # app
|
113
|
+
end # if
|
@@ -0,0 +1,467 @@
|
|
1
|
+
require 'rbcurse'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'rbcurse/extras/widgets/rlistbox'
|
4
|
+
require 'rbcurse/core/include/vieditable'
|
5
|
+
require 'rbcurse/experimental/widgets/undomanager'
|
6
|
+
##
|
7
|
+
# Created on : Wed Sep 22 22:30:13 IST 2010
|
8
|
+
# (c) rkumar (arunachalesha)
|
9
|
+
#
|
10
|
+
module RubyCurses
|
11
|
+
# Display a directory listing, allowing user to drill down on pressing Enter
|
12
|
+
# on a directory, or sort when pressing enter on header row.
|
13
|
+
class DirectoryList < Listbox
|
14
|
+
|
15
|
+
include ViEditable
|
16
|
+
|
17
|
+
def initialize form, config={}, &block
|
18
|
+
@hide_dot_files = false
|
19
|
+
@hide_others = false
|
20
|
+
@curpos = 0
|
21
|
+
super
|
22
|
+
|
23
|
+
#@current_path ||= Dir.getwd # setting it causes selection not to fire if same one
|
24
|
+
# is selected first
|
25
|
+
@_header_array = [ "Attr", "Size", "Modified" , "Name" , "<Order_by_Extension>" ]
|
26
|
+
@_header = " %s %8s %19s %s %s " % @_header_array
|
27
|
+
end
|
28
|
+
def init_vars
|
29
|
+
# which rows are not data, thus don't fire, or give error
|
30
|
+
@_non_data_indices = []
|
31
|
+
@_header_row_index = 0
|
32
|
+
@_first_data_index = 1
|
33
|
+
@one_key_selection = false # this allows us to map keys to methods
|
34
|
+
vieditable_init_listbox
|
35
|
+
undom = SimpleUndo.new self
|
36
|
+
bind_key(?\M-h, :scroll_left)
|
37
|
+
bind_key(?\M-l, :scroll_right)
|
38
|
+
bind_key(KEY_RIGHT, :cursor_forward)
|
39
|
+
bind_key(KEY_LEFT, :cursor_backward)
|
40
|
+
bind_key(?$, :end_of_line)
|
41
|
+
bind_key(?\C-e, :end_of_line)
|
42
|
+
bind_key(?\C-a, :start_of_line)
|
43
|
+
bind_key(?a, :select_all)
|
44
|
+
bind_key(?*, :invert_selection)
|
45
|
+
bind_key(?u, :clear_selection)
|
46
|
+
bind_key(?+, :ask_select)
|
47
|
+
bind_key(?-, :ask_unselect)
|
48
|
+
bind_key(?I) { @hide_dot_files = !@hide_dot_files; prune_entries; }
|
49
|
+
#bind_key(?v, :view_current) # does not respond to ??? XXX
|
50
|
+
bind_key(?v) {view_current}
|
51
|
+
super
|
52
|
+
end
|
53
|
+
# changing the current path, refreshes files
|
54
|
+
def current_path(*val)
|
55
|
+
if val.empty?
|
56
|
+
return @current_path
|
57
|
+
else
|
58
|
+
raise ArgumentError, "current_path should be a directory:#{val[0]}." unless File.directory? val[0]
|
59
|
+
oldvalue = @current_path
|
60
|
+
if oldvalue != val[0]
|
61
|
+
@current_path = val[0]
|
62
|
+
populate @current_path
|
63
|
+
fire_property_change(:current_path, oldvalue, @current_path)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
self
|
67
|
+
end
|
68
|
+
# populate the list with file names
|
69
|
+
# @param [String, Array] string is the path name to populate with
|
70
|
+
# Array is a list of files
|
71
|
+
def populate path
|
72
|
+
case path
|
73
|
+
when String
|
74
|
+
@current_path = path
|
75
|
+
@entries = Dir.new(path).entries
|
76
|
+
@entries.delete(".")
|
77
|
+
# isn;t it a bit late here. it needs to happen to what's already there
|
78
|
+
@entries.delete_if {|x| x =~ /^\./} if @hide_dot_files
|
79
|
+
@entries.delete_if {|x| x =~ /\.bak$/ || x=~/\.swp$/} if @hide_others
|
80
|
+
when Array
|
81
|
+
path = @current_path
|
82
|
+
# we've been passed @entries so we don't need to put it again ??? XXX
|
83
|
+
end
|
84
|
+
# TODO K M etc
|
85
|
+
list @entries
|
86
|
+
@list.insert 0, @_header
|
87
|
+
@title = @current_path
|
88
|
+
@current_index = @_first_data_index
|
89
|
+
set_form_row if @form
|
90
|
+
end
|
91
|
+
# called by parent's repaint
|
92
|
+
def convert_value_to_text file, crow
|
93
|
+
if @short
|
94
|
+
file
|
95
|
+
else
|
96
|
+
if crow == @_header_row_index
|
97
|
+
return file
|
98
|
+
else
|
99
|
+
# OUCH i don't know if its a header !!
|
100
|
+
fullname = File.join(@current_path, file)
|
101
|
+
fname = file
|
102
|
+
stat = File::Stat.new fullname
|
103
|
+
time = stat.mtime.to_s[0..18]
|
104
|
+
attr = stat.directory? ? "d" : "-"
|
105
|
+
attr << (stat.writable? ? "w" : "-")
|
106
|
+
attr << (stat.readable? ? "r" : "-")
|
107
|
+
attr << (stat.executable? ? "x" : "-")
|
108
|
+
fname << "/" if stat.directory? && fname[-1] != "/"
|
109
|
+
value = " %s %8d %s %s" % [attr, stat.size, time, fname]
|
110
|
+
return value
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def ___create_default_cell_renderer
|
116
|
+
cell_renderer( RubyCurses::DirectoryListCellRenderer.new "", {:color=>@color, :bgcolor=>@bgcolor, :parent => self, :display_length=> @width-2-@left_margin})
|
117
|
+
end
|
118
|
+
def _get_word_under_cursor line=@_header, pos=@curpos
|
119
|
+
finish = line.index(" ", pos)
|
120
|
+
start = line.rindex(" ",pos)
|
121
|
+
finish = -1 if finish.nil?
|
122
|
+
start = 0 if start.nil?
|
123
|
+
return line[start..finish]
|
124
|
+
end
|
125
|
+
# sorts entries by various parameters.
|
126
|
+
# Not optimal since it creates file stat objects each time rather than cacheing, but this is a demo of widgets
|
127
|
+
# not a real directory lister!
|
128
|
+
def sort_by key, reverse=false
|
129
|
+
# remove parent before sorting, keep at top
|
130
|
+
first = @entries.delete_at(0) if @entries[0]==".."
|
131
|
+
#key ||= @sort_key
|
132
|
+
sort_keys = { 'Name' => :name, 'Modified' => :mtime, "Size" => :size, "<Order_by_Extension>" => :ext, 'Attr' => :attr, "Accessed" => :atime }
|
133
|
+
key = sort_keys[key] if sort_keys.has_key? key
|
134
|
+
#if key == @sort_key
|
135
|
+
#reverse = true
|
136
|
+
#end
|
137
|
+
cdir=@current_path+"/"
|
138
|
+
case key
|
139
|
+
when :size
|
140
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
141
|
+
if reverse
|
142
|
+
xs.size <=> ys.size
|
143
|
+
else
|
144
|
+
ys.size <=> xs.size
|
145
|
+
end
|
146
|
+
}
|
147
|
+
when :mtime
|
148
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
149
|
+
if reverse
|
150
|
+
xs.mtime <=> ys.mtime
|
151
|
+
else
|
152
|
+
ys.mtime <=> xs.mtime
|
153
|
+
end
|
154
|
+
}
|
155
|
+
when :atime
|
156
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
157
|
+
if reverse
|
158
|
+
xs.atime <=> ys.atime
|
159
|
+
else
|
160
|
+
ys.atime <=> xs.atime
|
161
|
+
end
|
162
|
+
}
|
163
|
+
when :name
|
164
|
+
@entries.sort! {|x,y| x <=> y
|
165
|
+
if reverse
|
166
|
+
x <=> y
|
167
|
+
else
|
168
|
+
y <=> x
|
169
|
+
end
|
170
|
+
}
|
171
|
+
when :ext
|
172
|
+
@entries.sort! {|x,y|
|
173
|
+
if reverse
|
174
|
+
File.extname(cdir+x) <=> File.extname(cdir+y)
|
175
|
+
else
|
176
|
+
File.extname(cdir+y) <=> File.extname(cdir+x)
|
177
|
+
end
|
178
|
+
}
|
179
|
+
when :attr
|
180
|
+
@entries.sort! {|x,y| xs = File.stat(cdir+x); ys = File.stat(cdir+y);
|
181
|
+
x = xs.directory? ? "d" : "D"
|
182
|
+
y = ys.directory? ? "d" : "D"
|
183
|
+
if reverse
|
184
|
+
x <=> y
|
185
|
+
else
|
186
|
+
y <=> x
|
187
|
+
end
|
188
|
+
}
|
189
|
+
end
|
190
|
+
@sort_key = key
|
191
|
+
@entries.insert 0, first unless first.nil? # keep parent on top
|
192
|
+
populate @entries
|
193
|
+
end
|
194
|
+
GIGA_SIZE = 1073741824.0
|
195
|
+
MEGA_SIZE = 1048576.0
|
196
|
+
KILO_SIZE = 1024.0
|
197
|
+
|
198
|
+
# Return the file size with a readable style.
|
199
|
+
def readable_file_size(size, precision)
|
200
|
+
case
|
201
|
+
#when size == 1 : "1 B"
|
202
|
+
when size < KILO_SIZE then "%d B" % size
|
203
|
+
when size < MEGA_SIZE then "%.#{precision}f K" % (size / KILO_SIZE)
|
204
|
+
when size < GIGA_SIZE then "%.#{precision}f M" % (size / MEGA_SIZE)
|
205
|
+
else "%.#{precision}f G" % (size / GIGA_SIZE)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
def date_format t
|
209
|
+
t.strftime "%Y/%m/%d"
|
210
|
+
end
|
211
|
+
|
212
|
+
# on pressing Enter, execute this action.
|
213
|
+
# Here we take the current file and if its a directory, we step into it.
|
214
|
+
def fire_action_event
|
215
|
+
if @_non_data_indices.include? @current_index
|
216
|
+
Ncurses.error
|
217
|
+
return
|
218
|
+
end
|
219
|
+
$log.debug "inside fire_action_event of directorylist #{@current_index} #{toprow} "
|
220
|
+
if @_header_row_index == @current_index
|
221
|
+
# user hit enter on the header row. we determine column and sort.
|
222
|
+
header = _get_word_under_cursor
|
223
|
+
#@reverse = false
|
224
|
+
if header == @_last_header_sorted
|
225
|
+
@reverse = !@reverse # clicking 2 times won't reverse again
|
226
|
+
else
|
227
|
+
@reverse = false
|
228
|
+
end
|
229
|
+
sort_by header.strip, @reverse
|
230
|
+
# this next line will keep the cursor on header after sorting
|
231
|
+
# earlier cursor would appear in header but selection would be data row
|
232
|
+
@current_index = @_header_row_index # FFI 2011-09-16 keeping cursor synched with selection
|
233
|
+
@_last_header_sorted = header
|
234
|
+
set_form_row
|
235
|
+
return
|
236
|
+
end
|
237
|
+
value = current_value
|
238
|
+
value = value.split.last
|
239
|
+
if value == ".."
|
240
|
+
_path = File.dirname(@current_path)
|
241
|
+
else
|
242
|
+
_path = File.join(@current_path, value)
|
243
|
+
end
|
244
|
+
if File.directory? _path
|
245
|
+
populate _path
|
246
|
+
end
|
247
|
+
$log.debug "after fire_action_event of directorylist #{@current_index} #{toprow} "
|
248
|
+
|
249
|
+
super
|
250
|
+
end
|
251
|
+
def addcol num
|
252
|
+
#@repaint_required = true
|
253
|
+
@repaint_footer_required = true # 2010-01-23 22:41
|
254
|
+
if @form
|
255
|
+
@form.addcol num
|
256
|
+
else
|
257
|
+
@parent_component.form.addcol num
|
258
|
+
end
|
259
|
+
end
|
260
|
+
# set cursor column position
|
261
|
+
# if i set col1 to @curpos, i can move around left right if key mapped
|
262
|
+
def set_form_col col1=@curpos
|
263
|
+
col1 ||= 0
|
264
|
+
@cols_panned ||= 0 # RFED16 2010-02-17 23:40
|
265
|
+
win_col = 0 # 2010-02-17 23:19 RFED16
|
266
|
+
col2 = win_col + @col + @col_offset + col1 + @cols_panned + @left_margin
|
267
|
+
setrowcol nil, col2 # 2010-02-17 23:19 RFED16
|
268
|
+
end
|
269
|
+
def start_of_line
|
270
|
+
@repaint_required = true if @pcol > 0 # tried other things but did not work
|
271
|
+
set_form_col 0
|
272
|
+
@pcol = 0
|
273
|
+
end
|
274
|
+
# this does not work, since the value in list is not the printed value
|
275
|
+
def end_of_line
|
276
|
+
blen = current_value.rstrip.length
|
277
|
+
set_form_col blen
|
278
|
+
end
|
279
|
+
|
280
|
+
def cursor_backward
|
281
|
+
repeatm {
|
282
|
+
if @curpos > 0
|
283
|
+
@curpos -= 1
|
284
|
+
set_form_col
|
285
|
+
#addcol -1
|
286
|
+
elsif @pcol > 0
|
287
|
+
@pcol -= 1
|
288
|
+
end
|
289
|
+
}
|
290
|
+
#@repaint_required = true
|
291
|
+
@repaint_footer_required = true # 2010-01-23 22:41
|
292
|
+
end
|
293
|
+
|
294
|
+
|
295
|
+
def cursor_forward
|
296
|
+
@curpos ||= 0
|
297
|
+
maxlen = @maxlen || @width-2
|
298
|
+
repeatm {
|
299
|
+
if @curpos < @width and @curpos < maxlen-1 # else it will do out of box
|
300
|
+
@curpos += 1
|
301
|
+
addcol 1
|
302
|
+
else
|
303
|
+
#@pcol += 1 if @pcol <= @buffer.length
|
304
|
+
# buffer not eixstent FIXME
|
305
|
+
end
|
306
|
+
}
|
307
|
+
set_form_col
|
308
|
+
#@repaint_required = true
|
309
|
+
@repaint_footer_required = true # 2010-01-23 22:41
|
310
|
+
end
|
311
|
+
def [](index)
|
312
|
+
@entries[index]
|
313
|
+
end
|
314
|
+
|
315
|
+
@private
|
316
|
+
def longest_line=(l)
|
317
|
+
@longest_line = l
|
318
|
+
end
|
319
|
+
def longest_line
|
320
|
+
@longest_line
|
321
|
+
end
|
322
|
+
# modify a file name.
|
323
|
+
# call using 'C'
|
324
|
+
def edit_line lineno=@current_index
|
325
|
+
line = @list[lineno]
|
326
|
+
fullname = File.join(@current_path, line)
|
327
|
+
prompt = "Rename file [#{line}] to: "
|
328
|
+
maxlen = 80
|
329
|
+
config={};
|
330
|
+
oldline = line.dup
|
331
|
+
config[:default] = line
|
332
|
+
ret, str = rbgetstr(@form.window, $error_message_row, $error_message_col, prompt, maxlen, config)
|
333
|
+
$log.debug " rbgetstr returned #{ret} , #{str} "
|
334
|
+
return if ret != 0
|
335
|
+
@list[lineno].replace(str)
|
336
|
+
FileUtils.mv fullname, File.join(@current_path, str)
|
337
|
+
fire_handler :CHANGE, InputDataEvent.new(0,oldline.length, self, :DELETE_LINE, lineno, oldline)
|
338
|
+
fire_handler :CHANGE, InputDataEvent.new(0,str.length, self, :INSERT_LINE, lineno, str)
|
339
|
+
@repaint_required = true
|
340
|
+
end
|
341
|
+
def ask_select
|
342
|
+
prompt = "Select Files: "
|
343
|
+
maxlen = 80
|
344
|
+
config={}
|
345
|
+
config[:default] = @file_pattern if @file_pattern
|
346
|
+
ret, str = rbgetstr(@form.window, $error_message_row, $error_message_col, prompt, maxlen, config)
|
347
|
+
return if ret != 0
|
348
|
+
@file_pattern = str
|
349
|
+
# 2011-09-19 doesn't work if pwd changed
|
350
|
+
if Dir.pwd != @current_path
|
351
|
+
Dir.chdir @current_path
|
352
|
+
end
|
353
|
+
values = Dir.glob(str)
|
354
|
+
$log.debug "ask select dir.glob got #{values} "
|
355
|
+
select_values values unless values.empty?
|
356
|
+
@repaint_required = true
|
357
|
+
end
|
358
|
+
def ask_unselect
|
359
|
+
prompt = "Unselect Files: "
|
360
|
+
maxlen = 80
|
361
|
+
config={}
|
362
|
+
config[:default] = @file_pattern if @file_pattern
|
363
|
+
ret, str = rbgetstr(@form.window, $error_message_row, $error_message_col, prompt, maxlen, config)
|
364
|
+
return if ret != 0
|
365
|
+
@file_pattern = str
|
366
|
+
if Dir.pwd != @current_path
|
367
|
+
Dir.chdir @current_path
|
368
|
+
end
|
369
|
+
values = Dir.glob(str)
|
370
|
+
unselect_values values unless values.empty?
|
371
|
+
@repaint_required = true
|
372
|
+
end
|
373
|
+
def select_all
|
374
|
+
# don't select header row
|
375
|
+
add_row_selection_interval 1, row_count()
|
376
|
+
end
|
377
|
+
def invert_selection
|
378
|
+
1.upto(row_count()){|i| toggle_row_selection i }
|
379
|
+
end
|
380
|
+
# selects all rows with the values given, leaving existing selections
|
381
|
+
# intact
|
382
|
+
def select_values values
|
383
|
+
return unless values
|
384
|
+
values.each do |val|
|
385
|
+
row = @list.index val
|
386
|
+
add_row_selection_interval row, row unless row.nil?
|
387
|
+
end
|
388
|
+
end
|
389
|
+
# unselects all rows with the values given, leaving all other rows intact
|
390
|
+
def unselect_values values
|
391
|
+
return unless values
|
392
|
+
values.each do |val|
|
393
|
+
row = @list.index val
|
394
|
+
remove_row_selection_interval row, row unless row.nil?
|
395
|
+
end
|
396
|
+
end
|
397
|
+
private
|
398
|
+
# was meant to filter rows, but no point. since we can't undo the delete
|
399
|
+
# so we just call populate again. this method could get axed
|
400
|
+
def prune_entries
|
401
|
+
#@entries.delete_if {|x| x =~ /^\./} if @hide_dot_files
|
402
|
+
#@entries.delete_if {|x| x =~ /\.bak$/ || x=~/\.swp$/} if @hide_others
|
403
|
+
populate @current_path
|
404
|
+
set_form_row
|
405
|
+
end
|
406
|
+
def view_current
|
407
|
+
file = self.current_value
|
408
|
+
require 'rbcurse/core/util/viewer.rb'
|
409
|
+
RubyCurses::Viewer.view("#{current_path}/#{file}", :close_key => KEY_RETURN, :title => "<Enter> to close, M-l M-h to scroll")
|
410
|
+
end
|
411
|
+
# ADD HERE
|
412
|
+
##
|
413
|
+
end # class
|
414
|
+
|
415
|
+
##
|
416
|
+
# A cell renderer should not changed the length of a line otherwise scrolling etc goes for a toss.
|
417
|
+
# The calling repaint method does trimming.
|
418
|
+
#
|
419
|
+
# A cell renderer can do small modifications, or color changing to data.
|
420
|
+
# Here we should color directories or bak files or hidden files, swap files etc differently
|
421
|
+
# Should this class do the trimming of data, else its hard to figure out what the extension
|
422
|
+
# is if its trimeed out. But then it would have to handle the panning too.
|
423
|
+
require 'rbcurse/core/include/listcellrenderer'
|
424
|
+
class DirectoryListCellRenderer < ListCellRenderer
|
425
|
+
#def initialize text="", config={}, &block
|
426
|
+
#super
|
427
|
+
#end
|
428
|
+
# sets @color_pair and @attr
|
429
|
+
|
430
|
+
##
|
431
|
+
# paint a list box cell
|
432
|
+
# 2010-09-02 15:38 changed focussed to take true, false and :SOFT_FOCUS
|
433
|
+
# SOFT_FOCUS means the form focus is no longer on this field, but this row
|
434
|
+
# was focussed when use was last on this field. This row will take focus
|
435
|
+
# when field is focussed again
|
436
|
+
#
|
437
|
+
# @param [Buffer] window or buffer object used for printing
|
438
|
+
# @param [Fixnum] row
|
439
|
+
# @param [Fixnum] column
|
440
|
+
# @param [Fixnum] actual index into data, some lists may have actual data elsewhere and
|
441
|
+
# display data separate. e.g. rfe_renderer (directory listing)
|
442
|
+
# @param [String] text to print in cell
|
443
|
+
# @param [Boolean, :SOFT_FOCUS] cell focussed, not focussed, cell focussed but field is not focussed
|
444
|
+
# @param [Boolean] cell selected or not
|
445
|
+
def repaint graphic, r=@row,c=@col, row_index=-1,value=@text, focussed=false, selected=false
|
446
|
+
|
447
|
+
prepare_default_colors focussed, selected
|
448
|
+
if row_index == 0
|
449
|
+
#nvalue = " %s %8s %19s %s %s " % value.split(",")
|
450
|
+
graphic.printstring r, c, "%-s" % value, @color_pair,@attr
|
451
|
+
else
|
452
|
+
$log.debug " CELL XXX GTETING #{row_index} ,#{value}"
|
453
|
+
|
454
|
+
|
455
|
+
# ensure we do not exceed
|
456
|
+
if !@display_length.nil?
|
457
|
+
if value.length > @display_length
|
458
|
+
value = value[0..@display_length-1]
|
459
|
+
end
|
460
|
+
end
|
461
|
+
len = @display_length || value.length
|
462
|
+
graphic.printstring r, c, "%-*s" % [len, value], @color_pair,@attr
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end # module
|
467
|
+
# set filetype=ruby
|