rbcurse-experimental 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|