rbcurse 1.1.5 → 1.2.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +45 -0
- data/Makefile +1 -1
- data/Manifest.txt +91 -0
- data/NOTES +349 -2
- data/README.markdown +12 -0
- data/VERSION +1 -1
- data/examples/abasiclist.rb +25 -0
- data/examples/alpmenu.rb +42 -0
- data/examples/app.rb +883 -0
- data/examples/appcombo.rb +17 -0
- data/examples/appdirtree.rb +73 -0
- data/examples/appemail.rb +164 -0
- data/examples/appemaillb.rb +308 -0
- data/examples/appgcompose.rb +303 -0
- data/examples/appgmail.rb +951 -0
- data/examples/atree.rb +56 -0
- data/examples/dirtree.rb +78 -0
- data/examples/focusmanager.rb +31 -0
- data/examples/imap.rb +48 -0
- data/examples/menu1.rb +79 -0
- data/examples/multispl.rb +86 -0
- data/examples/rfe.rb +3 -4
- data/examples/rmail.rb +188 -0
- data/examples/s.rb +10 -0
- data/examples/scrollbar.rb +104 -0
- data/examples/splitp.rb +56 -0
- data/examples/table1.rb +30 -0
- data/examples/term.rb +48 -0
- data/examples/term2.rb +54 -0
- data/examples/test1.rb +4 -2
- data/examples/test2.rb +9 -9
- data/examples/testapp.rb +44 -0
- data/examples/testapp2.rb +51 -0
- data/examples/testcombo.rb +2 -2
- data/examples/testgmail.rb +46 -0
- data/examples/testlistbox.rb +0 -1
- data/examples/testmultispl.rb +199 -0
- data/examples/testree.rb +127 -0
- data/examples/testscroller.rb +0 -1
- data/examples/testscrolllb.rb +1 -1
- data/examples/testscrollp.rb +2 -1
- data/examples/testscrollta.rb +1 -1
- data/examples/testscrolltable.rb +1 -2
- data/examples/testsplit.rb +1 -1
- data/examples/testsplit2.rb +1 -1
- data/examples/testsplit3.rb +1 -1
- data/examples/testsplit3_1.rb +1 -1
- data/examples/testsplit3a.rb +1 -1
- data/examples/testsplit3b.rb +1 -1
- data/examples/testsplitta.rb +1 -1
- data/examples/testsplittv.rb +1 -1
- data/examples/testsplittvv.rb +1 -1
- data/examples/testtodo.rb +491 -488
- data/examples/testvimsplit.rb +111 -0
- data/examples/todo.db +0 -0
- data/examples/todocsv.csv +28 -0
- data/examples/viewtodo.rb +408 -403
- data/lib/rbcurse/action.rb +1 -0
- data/lib/rbcurse/app.rb +1294 -0
- data/lib/rbcurse/applicationheader.rb +7 -2
- data/lib/rbcurse/checkboxcellrenderer.rb +0 -12
- data/lib/rbcurse/colormap.rb +34 -8
- data/lib/rbcurse/comboboxcellrenderer.rb +0 -11
- data/lib/rbcurse/defaultlistselectionmodel.rb +23 -7
- data/lib/rbcurse/extras/bottomline.rb +1681 -0
- data/lib/rbcurse/extras/directorylist.rb +445 -0
- data/lib/rbcurse/extras/directorytree.rb +69 -0
- data/lib/rbcurse/extras/divider.rb +310 -0
- data/lib/rbcurse/extras/focusmanager.rb +31 -0
- data/lib/rbcurse/extras/listselectable.rb +222 -0
- data/lib/rbcurse/extras/masterdetail.rb +164 -0
- data/lib/rbcurse/extras/menutree.rb +63 -0
- data/lib/rbcurse/extras/rlink.rb +27 -0
- data/lib/rbcurse/extras/rmenulink.rb +21 -0
- data/lib/rbcurse/extras/scrollbar.rb +134 -0
- data/lib/rbcurse/extras/stdscrwindow.rb +247 -0
- data/lib/rbcurse/extras/tabular.rb +258 -0
- data/lib/rbcurse/extras/tabularwidget.rb +1070 -0
- data/lib/rbcurse/extras/viewer.rb +106 -0
- data/lib/rbcurse/io.rb +137 -80
- data/lib/rbcurse/keylabelprinter.rb +4 -0
- data/lib/rbcurse/listcellrenderer.rb +91 -59
- data/lib/rbcurse/listscrollable.rb +93 -95
- data/lib/rbcurse/listselectable.rb +60 -7
- data/lib/rbcurse/ractionevent.rb +67 -0
- data/lib/rbcurse/rbasiclistbox.rb +688 -0
- data/lib/rbcurse/rcombo.rb +5 -5
- data/lib/rbcurse/rcommandwindow.rb +555 -0
- data/lib/rbcurse/rinputdataevent.rb +12 -0
- data/lib/rbcurse/rlistbox.rb +305 -124
- data/lib/rbcurse/rmenu.rb +99 -46
- data/lib/rbcurse/rmessagebox.rb +13 -6
- data/lib/rbcurse/rmulticontainer.rb +54 -93
- data/lib/rbcurse/rmultisplit.rb +731 -0
- data/lib/rbcurse/rmultitextview.rb +3 -2
- data/lib/rbcurse/rpopupmenu.rb +0 -1
- data/lib/rbcurse/rprogress.rb +117 -0
- data/lib/rbcurse/rscrollpane.rb +2 -1
- data/lib/rbcurse/rsplitpane.rb +94 -20
- data/lib/rbcurse/rsplitpane2.rb +1009 -0
- data/lib/rbcurse/rtabbedpane.rb +3 -2
- data/lib/rbcurse/rtabbedwindow.rb +0 -1
- data/lib/rbcurse/rtable.rb +92 -64
- data/lib/rbcurse/rtextarea.rb +91 -57
- data/lib/rbcurse/rtextview.rb +223 -70
- data/lib/rbcurse/rtree.rb +723 -0
- data/lib/rbcurse/rviewport.rb +2 -1
- data/lib/rbcurse/rvimsplit.rb +768 -0
- data/lib/rbcurse/rwidget.rb +524 -325
- data/lib/rbcurse/table/tablecellrenderer.rb +1 -1
- data/lib/rbcurse/table/tabledatecellrenderer.rb +0 -1
- data/lib/rbcurse/tree/treecellrenderer.rb +137 -0
- data/lib/rbcurse/tree/treemodel.rb +428 -0
- data/lib/rbcurse/vieditable.rb +14 -13
- data/lib/ver/ncurses.rb +6 -0
- data/lib/ver/window.rb +67 -32
- metadata +99 -23
- data/bin/rbcurse +0 -0
- data/examples/rvimsplit.rb +0 -376
- data/examples/todo.rb +0 -1
- data/lib/rbcurse/rform.rb +0 -845
- data/lib/rbcurse/selectable.rb +0 -94
- data/rbcurse.gemspec +0 -188
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'rbcurse/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)
|
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(@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 "got a resize event #{e.type} "
|
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
|
+
|
104
|
+
end
|
105
|
+
when :DECREASE
|
106
|
+
case e.source
|
107
|
+
when @right2
|
108
|
+
increase_headers
|
109
|
+
when @right1
|
110
|
+
increase_body
|
111
|
+
when @left
|
112
|
+
@left.width -= 1
|
113
|
+
@right2.col -=1
|
114
|
+
@right1.col -=1
|
115
|
+
@right1.width +=1
|
116
|
+
@right2.width +=1
|
117
|
+
@right2.repaint_required true
|
118
|
+
@right1.repaint_required true
|
119
|
+
@left.repaint_required true
|
120
|
+
end
|
121
|
+
when :EXPAND
|
122
|
+
case e.source
|
123
|
+
when @right2
|
124
|
+
h = 3
|
125
|
+
@right2.row(@right1.row + h)
|
126
|
+
oldh = @right1.height
|
127
|
+
@right1.height = h
|
128
|
+
@right1.current_index = 0
|
129
|
+
@right2.height += (oldh - h)
|
130
|
+
@right2.repaint_required true
|
131
|
+
@right1.repaint_required true
|
132
|
+
when @right1
|
133
|
+
h = 3
|
134
|
+
@right2.row(@right2.row + (@right2.height - 3))
|
135
|
+
oldh = @right2.height
|
136
|
+
@right2.height = h
|
137
|
+
#@right1.current_index = 0
|
138
|
+
@right1.height += (oldh - h)
|
139
|
+
@right2.repaint_required true
|
140
|
+
@right1.repaint_required true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end # bind
|
144
|
+
end
|
145
|
+
end # def
|
146
|
+
# increase the top right pane and reduces lower one
|
147
|
+
# TODO: to take into account multiplier
|
148
|
+
def increase_headers #:nodoc:
|
149
|
+
@right2.row @right2.row()+1
|
150
|
+
@right1.height +=1
|
151
|
+
@right2.height -=1
|
152
|
+
@right2.repaint_required true
|
153
|
+
@right1.repaint_required true
|
154
|
+
end
|
155
|
+
# decrease the top right pane and increase lower one
|
156
|
+
# TODO: to take into account multiplier
|
157
|
+
def increase_body #:nodoc:
|
158
|
+
@right2.row @right2.row()-1
|
159
|
+
@right1.height -=1
|
160
|
+
@right2.height +=1
|
161
|
+
@right2.repaint_required true
|
162
|
+
@right1.repaint_required true
|
163
|
+
end
|
164
|
+
end # class
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module RubyCurses
|
2
|
+
# Create a simple tree-ish structure.
|
3
|
+
# Each node is not a tree, only submenus are trees
|
4
|
+
# Others contain a hash with menu character and code
|
5
|
+
# Typically the code is not a method symbol, it is to be
|
6
|
+
# used to decode a description or method symbol from anoterh hash
|
7
|
+
# @usage
|
8
|
+
# menu = MenuTree.new "Main", { c: :goprev, d: :gonext, e: :gonext, s: :submenu }
|
9
|
+
# menu.submenu :s, "submenu", {a: :next1, b: :next2, f: :next3 }
|
10
|
+
# puts menu.hash
|
11
|
+
# puts "each ..."
|
12
|
+
# menu.each { |e| puts e }
|
13
|
+
# menu.each_pair { |e, v| puts "#{e} #{v}" }
|
14
|
+
# puts " -- :c -- "
|
15
|
+
# puts menu[:c]
|
16
|
+
# puts " -- :s -- "
|
17
|
+
# puts menu[:s].children
|
18
|
+
class MenuTree
|
19
|
+
attr_reader :value
|
20
|
+
def initialize value, hash = {}
|
21
|
+
@value = [value, hash]
|
22
|
+
end
|
23
|
+
def << kv
|
24
|
+
@value[1][kv[0]] = kv[1]
|
25
|
+
end
|
26
|
+
def hash
|
27
|
+
@value[1]
|
28
|
+
end
|
29
|
+
alias :children :hash
|
30
|
+
def push hsh
|
31
|
+
hash().merge hsh
|
32
|
+
end
|
33
|
+
def [](x)
|
34
|
+
hash()[x]
|
35
|
+
end
|
36
|
+
def []=(x,y)
|
37
|
+
hash()[x] = y
|
38
|
+
end
|
39
|
+
def submenu key, value, hash = {}
|
40
|
+
m = MenuTree.new value, hash
|
41
|
+
#hash()[key] = [value, hash]
|
42
|
+
hash()[key] = m
|
43
|
+
end
|
44
|
+
def each
|
45
|
+
hash().keys.each { |e| yield e }
|
46
|
+
end
|
47
|
+
def each_pair
|
48
|
+
hash().each_pair { |name, val| yield name, val }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
if __FILE__ == $PROGRAM_NAME
|
53
|
+
menu = RubyCurses::MenuTree.new "Main", { c: :goprev, d: :gonext, e: :gonext, s: :submenu }
|
54
|
+
menu.submenu :s, "submenu", {a: :next1, b: :next2, f: :next3 }
|
55
|
+
puts menu.hash
|
56
|
+
puts "each ..."
|
57
|
+
menu.each { |e| puts e }
|
58
|
+
menu.each_pair { |e, v| puts "#{e} #{v}" }
|
59
|
+
puts " -- :c -- "
|
60
|
+
puts menu[:c]
|
61
|
+
puts " -- :s -- "
|
62
|
+
puts menu[:s].children
|
63
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rbcurse'
|
2
|
+
##
|
3
|
+
module RubyCurses
|
4
|
+
class Link < Button
|
5
|
+
dsl_property :description
|
6
|
+
|
7
|
+
|
8
|
+
def initialize form, config={}, &block
|
9
|
+
super
|
10
|
+
@text_offset = 0
|
11
|
+
# haha we've never done this, pin the cursor up on 0,0
|
12
|
+
@col_offset = -1
|
13
|
+
if @mnemonic
|
14
|
+
form.bind_key(@mnemonic.downcase, self){ self.fire }
|
15
|
+
end
|
16
|
+
@display_length = config[:width]
|
17
|
+
end
|
18
|
+
def fire
|
19
|
+
super
|
20
|
+
self.focus
|
21
|
+
end
|
22
|
+
def getvalue_for_paint
|
23
|
+
getvalue()
|
24
|
+
end
|
25
|
+
##
|
26
|
+
end # class
|
27
|
+
end # module
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rbcurse/extras/rlink'
|
2
|
+
##
|
3
|
+
module RubyCurses
|
4
|
+
class MenuLink < Link
|
5
|
+
dsl_property :description
|
6
|
+
|
7
|
+
def initialize form, config={}, &block
|
8
|
+
super
|
9
|
+
@col_offset = -1 * @col
|
10
|
+
@row_offset = -1 * @row
|
11
|
+
end
|
12
|
+
# added for some standardization 2010-09-07 20:28
|
13
|
+
# alias :text :getvalue # NEXT VERSION
|
14
|
+
# change existing text to label
|
15
|
+
|
16
|
+
def getvalue_for_paint
|
17
|
+
"%s %-12s - %-s" % [ @mnemonic , getvalue(), @description ]
|
18
|
+
end
|
19
|
+
##
|
20
|
+
end # class
|
21
|
+
end # module
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'rbcurse/app'
|
2
|
+
include Ncurses
|
3
|
+
include RubyCurses
|
4
|
+
|
5
|
+
# This paints a vertical white bar given row and col, and length. It also calculates and prints
|
6
|
+
# a small bar over this based on relaetd objects list.length and current_index.
|
7
|
+
# Typically, after setup one would keep updating only current_index from the repaint method
|
8
|
+
# of caller or in the traversal event. This would look best if the listbox also has a reverse video border, or none.
|
9
|
+
# @example
|
10
|
+
# lb = list_box ....
|
11
|
+
# sb = Scrollbar.new @form, :row => lb.row, :col => lb.col, :length => lb.height, :list_length => lb.row_count, :current_index => 0
|
12
|
+
# .... later as user traverses
|
13
|
+
# sb.current_index = lb.current_index
|
14
|
+
# sb = Scrollbar.new @form, :parent => list
|
15
|
+
#
|
16
|
+
# At a later stage, we will integrate this with lists and tables, so it will happen automatically.
|
17
|
+
#
|
18
|
+
# @since 1.2.0 UNTESTED
|
19
|
+
module RubyCurses
|
20
|
+
class Scrollbar < Widget
|
21
|
+
# row to start, same as listbox, required.
|
22
|
+
dsl_property :row
|
23
|
+
# column to start, same as listbox, required.
|
24
|
+
dsl_property :col
|
25
|
+
# how many rows is this (should be same as listboxes height, required.
|
26
|
+
dsl_property :length
|
27
|
+
# vertical or horizontal currently only VERTICAL
|
28
|
+
dsl_property :orientation
|
29
|
+
# initialize based on parent's values
|
30
|
+
dsl_property :parent
|
31
|
+
# which row is focussed, current_index of listbox, required.
|
32
|
+
dsl_property :current_index
|
33
|
+
# how many total rows of data does the list have, same as @list.length, required.
|
34
|
+
dsl_property :list_length
|
35
|
+
|
36
|
+
# TODO: if parent passed, we shold bind to ON_ENTER and get current_index, so no extra work is required.
|
37
|
+
|
38
|
+
def initialize form, config={}, &block
|
39
|
+
|
40
|
+
# setting default first or else Widget will place its BW default
|
41
|
+
#@color, @bgcolor = ColorMap.get_colors_for_pair $bottomcolor
|
42
|
+
super
|
43
|
+
@color_pair = get_color $datacolor, @color, @bgcolor
|
44
|
+
@scroll_pair = get_color $bottomcolor, :green, :white
|
45
|
+
@window = form.window
|
46
|
+
@editable = false
|
47
|
+
@focusable = false
|
48
|
+
@repaint_required = true
|
49
|
+
@orientation = :V
|
50
|
+
if @parent
|
51
|
+
@parent.bind :ENTER_ROW do |p|
|
52
|
+
# parent must implement row_count, and have a @current_index
|
53
|
+
raise StandardError, "Parent must implement row_count" unless p.respond_to? :row_count
|
54
|
+
self.current_index = p.current_index
|
55
|
+
@repaint_required = true #requred otherwise at end when same value sent, prop handler
|
56
|
+
# will not be fired (due to optimization).
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# repaint the scrollbar
|
63
|
+
# Taking the data from parent as late as possible in case parent resized, or
|
64
|
+
# moved around by a container.
|
65
|
+
def repaint
|
66
|
+
if @parent
|
67
|
+
@row = @parent.row+1
|
68
|
+
@col = @parent.col + @parent.width - 1
|
69
|
+
@length = @parent.height - 2
|
70
|
+
@list_length = @parent.row_count
|
71
|
+
@current_index ||= @parent.current_index
|
72
|
+
@border_attrib ||= @parent.border_attrib
|
73
|
+
end
|
74
|
+
raise ArgumentError, "current_index must be provided" unless @current_index
|
75
|
+
raise ArgumentError, "list_length must be provided" unless @list_length
|
76
|
+
my_win = @form ? @form.window : @target_window
|
77
|
+
@graphic = my_win unless @graphic
|
78
|
+
return unless @repaint_required
|
79
|
+
|
80
|
+
# first print a right side vertical line
|
81
|
+
#bc = $bottomcolor # dark blue
|
82
|
+
bc = $datacolor
|
83
|
+
bordercolor = @border_color || bc
|
84
|
+
borderatt = @border_attrib || Ncurses::A_REVERSE
|
85
|
+
|
86
|
+
|
87
|
+
@graphic.attron(Ncurses.COLOR_PAIR(bordercolor) | borderatt)
|
88
|
+
$log.debug " XXX SCROLL #{@row} #{@col} #{@length} "
|
89
|
+
@graphic.mvvline(@row+0, @col, 1, @length-0)
|
90
|
+
@graphic.attroff(Ncurses.COLOR_PAIR(bordercolor) | borderatt)
|
91
|
+
|
92
|
+
# now calculate and paint the scrollbar
|
93
|
+
pht = @length
|
94
|
+
listlen = @list_length * 1.0
|
95
|
+
@current_index = 0 if @current_index < 0
|
96
|
+
@current_index = listlen-1 if @current_index >= listlen
|
97
|
+
sclen = (pht/listlen)* @length
|
98
|
+
scloc = (@current_index/listlen)* @length
|
99
|
+
scloc = (@length - sclen) if scloc > @length - sclen # don't exceed end
|
100
|
+
if @current_index == @list_length - 1
|
101
|
+
scloc = @length - sclen + 1
|
102
|
+
end
|
103
|
+
@graphic.attron(Ncurses.COLOR_PAIR(@scroll_pair) | borderatt)
|
104
|
+
r = @row + scloc
|
105
|
+
c = @col + 0
|
106
|
+
@graphic.mvvline(r, c, 1, sclen)
|
107
|
+
@graphic.attroff(Ncurses.COLOR_PAIR(@scroll_pair) | borderatt)
|
108
|
+
@repaint_required = false
|
109
|
+
end
|
110
|
+
##
|
111
|
+
##
|
112
|
+
# ADD HERE
|
113
|
+
end
|
114
|
+
end
|
115
|
+
if __FILE__ == $PROGRAM_NAME
|
116
|
+
App.new do
|
117
|
+
r = 5
|
118
|
+
len = 20
|
119
|
+
list = []
|
120
|
+
0.upto(100) { |v| list << "#{v} scrollable data" }
|
121
|
+
lb = list_box "A list", :list => list
|
122
|
+
#sb = Scrollbar.new @form, :row => r, :col => 20, :length => len, :list_length => 50, :current_index => 0
|
123
|
+
rb = Scrollbar.new @form, :parent => lb
|
124
|
+
#hline :width => 20, :row => len+r
|
125
|
+
#keypress do |ch|
|
126
|
+
#case ch
|
127
|
+
#when :down
|
128
|
+
#sb.current_index += 1
|
129
|
+
#when :up
|
130
|
+
#sb.current_index -= 1
|
131
|
+
#end
|
132
|
+
#end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'ver/ncurses'
|
2
|
+
module RubyCurses
|
3
|
+
#
|
4
|
+
# an attempt to make a window based on stdscr for bottom line printing so the entire
|
5
|
+
# application can have one pointer, regardless of whether through App
|
6
|
+
# or otherwise. This still provides the full getchar operation, copied from
|
7
|
+
# Window class which is the main purpose of this. So as to provide ask, agree and say.
|
8
|
+
#
|
9
|
+
# We should be able to pass this window to bottomline and have one global bottomline
|
10
|
+
# created once (by window class ?)
|
11
|
+
#
|
12
|
+
class StdscrWindow
|
13
|
+
attr_reader :width, :height, :top, :left
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
|
17
|
+
@window = Ncurses.stdscr
|
18
|
+
$error_message_row ||= Ncurses.LINES-1
|
19
|
+
$error_message_col ||= 1
|
20
|
+
init_vars
|
21
|
+
|
22
|
+
|
23
|
+
end
|
24
|
+
def init_vars
|
25
|
+
Ncurses::keypad(@window, true)
|
26
|
+
@stack = []
|
27
|
+
end
|
28
|
+
##
|
29
|
+
|
30
|
+
# Ncurses
|
31
|
+
|
32
|
+
def method_missing(meth, *args)
|
33
|
+
@window.send(meth, *args)
|
34
|
+
end
|
35
|
+
|
36
|
+
def print(string, width = width)
|
37
|
+
return unless visible?
|
38
|
+
@window.waddnstr(string.to_s, width)
|
39
|
+
end
|
40
|
+
|
41
|
+
def print_yx(string, y = 0, x = 0)
|
42
|
+
@window.mvwaddnstr(y, x, string, width)
|
43
|
+
end
|
44
|
+
|
45
|
+
def print_empty_line
|
46
|
+
return unless visible?
|
47
|
+
@window.printw(' ' * width)
|
48
|
+
end
|
49
|
+
|
50
|
+
def print_line(string)
|
51
|
+
print(string.ljust(width))
|
52
|
+
end
|
53
|
+
|
54
|
+
def puts(*strings)
|
55
|
+
print(strings.join("\n") << "\n")
|
56
|
+
end
|
57
|
+
|
58
|
+
def refresh
|
59
|
+
@window.refresh
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def color=(color)
|
64
|
+
@color = color
|
65
|
+
@window.color_set(color, nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
def highlight_line(color, y, x, max)
|
69
|
+
@window.mvchgat(y, x, max, Ncurses::A_NORMAL, color, nil)
|
70
|
+
end
|
71
|
+
|
72
|
+
def ungetch(ch)
|
73
|
+
Ncurses.ungetch(ch)
|
74
|
+
end
|
75
|
+
|
76
|
+
def getch
|
77
|
+
c = @window.getch
|
78
|
+
#if c == Ncurses::KEY_RESIZE
|
79
|
+
rescue Interrupt => ex
|
80
|
+
3 # is C-c
|
81
|
+
end
|
82
|
+
|
83
|
+
# returns control, alt, alt+ctrl, alt+control+shift, F1 .. etc
|
84
|
+
# ALT combinations also send a 27 before the actual key
|
85
|
+
# Please test with above combinations before using on your terminal
|
86
|
+
# added by rkumar 2008-12-12 23:07
|
87
|
+
def getchar
|
88
|
+
while 1
|
89
|
+
ch = getch
|
90
|
+
#$log.debug "window getchar() GOT: #{ch}" if ch != -1
|
91
|
+
if ch == -1
|
92
|
+
# the returns escape 27 if no key followed it, so its SLOW if you want only esc
|
93
|
+
if @stack.first == 27
|
94
|
+
#$log.debug " -1 stack sizze #{@stack.size}: #{@stack.inspect}, ch #{ch}"
|
95
|
+
case @stack.size
|
96
|
+
when 1
|
97
|
+
@stack.clear
|
98
|
+
return 27
|
99
|
+
when 2 # basically a ALT-O, this will be really slow since it waits for -1
|
100
|
+
ch = 128 + @stack.last
|
101
|
+
@stack.clear
|
102
|
+
return ch
|
103
|
+
when 3
|
104
|
+
$log.debug " SHOULD NOT COME HERE getchar()"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
@stack.clear
|
108
|
+
next
|
109
|
+
end
|
110
|
+
# this is the ALT combination
|
111
|
+
if @stack.first == 27
|
112
|
+
# experimental. 2 escapes in quick succession to make exit faster
|
113
|
+
if ch == 27
|
114
|
+
@stack.clear
|
115
|
+
return ch
|
116
|
+
end
|
117
|
+
# possible F1..F3 on xterm-color
|
118
|
+
if ch == 79 or ch == 91
|
119
|
+
#$log.debug " got 27, #{ch}, waiting for one more"
|
120
|
+
@stack << ch
|
121
|
+
next
|
122
|
+
end
|
123
|
+
#$log.debug "stack SIZE #{@stack.size}, #{@stack.inspect}, ch: #{ch}"
|
124
|
+
if @stack == [27,79]
|
125
|
+
# xterm-color
|
126
|
+
case ch
|
127
|
+
when 80
|
128
|
+
ch = KEY_F1
|
129
|
+
when 81
|
130
|
+
ch = KEY_F2
|
131
|
+
when 82
|
132
|
+
ch = KEY_F3
|
133
|
+
when 83
|
134
|
+
ch = KEY_F4
|
135
|
+
end
|
136
|
+
@stack.clear
|
137
|
+
return ch
|
138
|
+
elsif @stack == [27, 91]
|
139
|
+
if ch == 90
|
140
|
+
@stack.clear
|
141
|
+
return KEY_BTAB # backtab
|
142
|
+
end
|
143
|
+
end
|
144
|
+
# the usual Meta combos. (alt)
|
145
|
+
ch = 128 + ch
|
146
|
+
@stack.clear
|
147
|
+
return ch
|
148
|
+
end
|
149
|
+
# append a 27 to stack, actually one can use a flag too
|
150
|
+
if ch == 27
|
151
|
+
@stack << 27
|
152
|
+
next
|
153
|
+
end
|
154
|
+
return ch
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def clear
|
159
|
+
# return unless visible?
|
160
|
+
move 0, 0
|
161
|
+
puts *Array.new(height){ ' ' * (width - 1) }
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
def visible?
|
166
|
+
@visible
|
167
|
+
end
|
168
|
+
##
|
169
|
+
# added by rk 2008-11-29 19:01
|
170
|
+
# I usually use this, not the others ones here
|
171
|
+
# @param r - row
|
172
|
+
# @param c - col
|
173
|
+
# @param string - text to print
|
174
|
+
# @param color - color pair
|
175
|
+
# @ param att - ncurses attribute: normal, bold, reverse, blink,
|
176
|
+
# underline
|
177
|
+
def printstring(r,c,string, color, att = Ncurses::A_NORMAL)
|
178
|
+
prv_printstring(r,c,string, color, att )
|
179
|
+
end
|
180
|
+
|
181
|
+
## name changed from printstring to prv_prinstring
|
182
|
+
def prv_printstring(r,c,string, color, att = Ncurses::A_NORMAL)
|
183
|
+
|
184
|
+
#$log.debug " #{@name} inside window printstring r #{r} c #{c} #{string} "
|
185
|
+
att = Ncurses::A_NORMAL if att.nil?
|
186
|
+
case att.to_s.downcase
|
187
|
+
when 'normal'
|
188
|
+
att = Ncurses::A_NORMAL
|
189
|
+
when 'underline'
|
190
|
+
att = Ncurses::A_UNDERLINE
|
191
|
+
when 'bold'
|
192
|
+
att = Ncurses::A_BOLD
|
193
|
+
when 'blink'
|
194
|
+
att = Ncurses::A_BLINK # unlikely to work
|
195
|
+
when 'reverse'
|
196
|
+
att = Ncurses::A_REVERSE
|
197
|
+
end
|
198
|
+
|
199
|
+
attron(Ncurses.COLOR_PAIR(color) | att)
|
200
|
+
# we should not print beyond window coordinates
|
201
|
+
# trying out on 2009-01-03 19:29
|
202
|
+
width = Ncurses.COLS
|
203
|
+
# the next line won't ensure we don't write outside some bounds like table
|
204
|
+
#string = string[0..(width-c)] if c + string.length > width
|
205
|
+
#$log.debug "PRINT len:#{string.length}, #{Ncurses.COLS}, #{r}, #{c} w: #{@window} "
|
206
|
+
mvprintw(r, c, "%s", string);
|
207
|
+
attroff(Ncurses.COLOR_PAIR(color) | att)
|
208
|
+
end
|
209
|
+
# added by rk 2008-11-29 19:01
|
210
|
+
# Since these methods write directly to window they are not advised
|
211
|
+
# since clearing previous message we don't know how much to clear.
|
212
|
+
# Best to map error_message to a label.
|
213
|
+
# 2010-09-13 00:22 WE should not use these any longer.
|
214
|
+
# Application should create a label and map a Variable named
|
215
|
+
# $errormessage to it. We should only update the Variable
|
216
|
+
def print_error_message text=$error_message
|
217
|
+
r = $error_message_row || Ncurses.LINES-1
|
218
|
+
c = $error_message_col || (Ncurses.COLS-text.length)/2
|
219
|
+
|
220
|
+
$log.debug "got ERROR MESSAGE #{text} row #{r} "
|
221
|
+
clear_error r, $datacolor
|
222
|
+
printstring r, c, text, color = $promptcolor
|
223
|
+
$error_message_clear_pending = true
|
224
|
+
end
|
225
|
+
# added by rk 2008-11-29 19:01
|
226
|
+
def print_status_message text=$status_message
|
227
|
+
r = $status_message_row || Ncurses.LINES-1
|
228
|
+
clear_error r, $datacolor
|
229
|
+
# print it in centre
|
230
|
+
printstring r, (Ncurses.COLS-text.length)/2, text, color = $promptcolor
|
231
|
+
end
|
232
|
+
# Clear error message printed
|
233
|
+
# I am not only clearing if something was printed. This is since
|
234
|
+
# certain small forms like TabbedForm top form throw an error on printstring.
|
235
|
+
#
|
236
|
+
def clear_error r = $error_message_row, color = $datacolor
|
237
|
+
return unless $error_message_clear_pending
|
238
|
+
c = $error_message_col || (Ncurses.COLS-text.length)/2
|
239
|
+
sz = $error_message_size || Ncurses.COLS
|
240
|
+
printstring(r, c, "%-*s" % [sz, " "], color)
|
241
|
+
$error_message_clear_pending = false
|
242
|
+
end
|
243
|
+
##
|
244
|
+
def get_window; @window; end
|
245
|
+
def to_s; @name || self; end
|
246
|
+
end
|
247
|
+
end
|