rbcurse 1.4.0 → 1.4.1.pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/NOTES +68 -0
- data/README.markdown +73 -330
- data/TODO2.txt +2 -2
- data/VERSION +1 -1
- data/examples/abasiclist.rb +8 -2
- data/examples/alpmenu.rb +1 -1
- data/examples/app.rb +1 -24
- data/examples/appdirtree.rb +1 -1
- data/examples/appemail.rb +8 -14
- data/examples/appemaillb.rb +2 -2
- data/examples/appgcompose.rb +7 -5
- data/examples/common/file.rb +40 -0
- data/examples/{rmail.rb → common/rmail.rb} +0 -0
- data/examples/data/README.markdown +9 -0
- data/examples/data/brew.txt +38 -0
- data/examples/data/color.2 +37 -0
- data/examples/data/gemlist.txt +60 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/ports.txt +136 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/{todocsv.csv → data/todocsv.csv} +0 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/data/unix2.txt +11 -0
- data/examples/dbdemo.rb +49 -14
- data/examples/{appgmail.rb → deprecated/appgmail.rb} +1 -1
- data/examples/{splitp.rb → deprecated/splitp.rb} +0 -0
- data/examples/{testscrolllb.rb → deprecated/testscrolllb.rb} +0 -0
- data/examples/{testscrollp.rb → deprecated/testscrollp.rb} +0 -0
- data/examples/{testscrollta.rb → deprecated/testscrollta.rb} +0 -0
- data/examples/{testscrolltable.rb → deprecated/testscrolltable.rb} +0 -0
- data/examples/{testsplit.rb → deprecated/testsplit.rb} +0 -0
- data/examples/{testsplit2.rb → deprecated/testsplit2.rb} +0 -0
- data/examples/{testsplit3.rb → deprecated/testsplit3.rb} +0 -0
- data/examples/{testsplit3_1.rb → deprecated/testsplit3_1.rb} +0 -0
- data/examples/{testsplit3a.rb → deprecated/testsplit3a.rb} +0 -0
- data/examples/{testsplit3b.rb → deprecated/testsplit3b.rb} +0 -0
- data/examples/{testsplitta.rb → deprecated/testsplitta.rb} +0 -0
- data/examples/{testsplittv.rb → deprecated/testsplittv.rb} +0 -0
- data/examples/{testsplittvv.rb → deprecated/testsplittvv.rb} +0 -0
- data/examples/{testtpane.rb → deprecated/testtpane.rb} +0 -0
- data/examples/{testtpane2.rb → deprecated/testtpane2.rb} +0 -0
- data/examples/{testtpanetable.rb → deprecated/testtpanetable.rb} +0 -0
- data/examples/dirtree.rb +17 -7
- data/examples/experimental/resultsetdemo.rb +280 -0
- data/examples/experimental/testmform.rb +35 -0
- data/examples/{testscroller.rb → experimental/testscroller.rb} +1 -19
- data/examples/experimental/teststackflow.rb +111 -0
- data/examples/menu1.rb +1 -0
- data/examples/multispl.rb +4 -4
- data/examples/newmessagebox.rb +130 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +0 -3
- data/examples/qdfilechooser.rb +0 -3
- data/examples/rfe.rb +134 -18
- data/examples/rfe_renderer.rb +48 -2
- data/examples/sqlc.rb +2 -1
- data/examples/sqlm.rb +0 -2
- data/examples/table1.rb +1 -7
- data/examples/term2.rb +4 -1
- data/examples/test1.rb +0 -5
- data/examples/test2.rb +42 -31
- data/examples/testapp2.rb +8 -1
- data/examples/testchars.rb +0 -4
- data/examples/testcombo.rb +5 -9
- data/examples/testkeypress.rb +0 -3
- data/examples/testmenu.rb +0 -4
- data/examples/testmulticomp.rb +3 -5
- data/examples/testmulticontainer.rb +94 -0
- data/examples/testtable.rb +0 -5
- data/examples/testtabp.rb +16 -18
- data/examples/testtodo.rb +1 -5
- data/examples/testwsshortcuts.rb +64 -0
- data/examples/testwsshortcuts2.rb +126 -0
- data/examples/viewtodo.rb +1 -4
- data/lib/rbcurse.rb +1 -1
- data/lib/rbcurse/app.rb +92 -69
- data/lib/rbcurse/applicationheader.rb +46 -6
- data/lib/rbcurse/celleditor.rb +1 -9
- data/lib/rbcurse/comboboxcellrenderer.rb +0 -4
- data/lib/rbcurse/common/ansiparser.rb +117 -0
- data/{examples → lib/rbcurse/common}/appmethods.rb +25 -0
- data/lib/rbcurse/common/basestack.rb +407 -0
- data/lib/rbcurse/common/bordertitle.rb +41 -0
- data/lib/rbcurse/common/chunk.rb +177 -0
- data/lib/rbcurse/common/colorparser.rb +71 -0
- data/lib/rbcurse/common/keydefs.rb +30 -0
- data/lib/rbcurse/common/widgetshortcuts.rb +302 -0
- data/lib/rbcurse/deprecated/README.markdown +12 -0
- data/lib/rbcurse/{rscrollpane.rb → deprecated/rscrollpane.rb} +0 -0
- data/lib/rbcurse/{rsplitpane.rb → deprecated/rsplitpane.rb} +0 -0
- data/lib/rbcurse/{rsplitpane2.rb → deprecated/rsplitpane2.rb} +0 -0
- data/lib/rbcurse/{rviewport.rb → deprecated/rviewport.rb} +0 -0
- data/lib/rbcurse/experimental/README.markdown +14 -0
- data/lib/rbcurse/experimental/resultsettextview.rb +585 -0
- data/lib/rbcurse/experimental/stackflow.rb +478 -0
- data/lib/rbcurse/extras/bottomline.rb +85 -16
- data/lib/rbcurse/extras/box.rb +58 -0
- data/lib/rbcurse/extras/directorylist.rb +1 -1
- data/lib/rbcurse/extras/horizlist.rb +203 -0
- data/lib/rbcurse/extras/listselectable.rb +8 -0
- data/lib/rbcurse/extras/multiform.rb +330 -0
- data/lib/rbcurse/extras/multilinelabel.rb +142 -0
- data/lib/rbcurse/extras/newmessagebox.rb +328 -0
- data/lib/rbcurse/extras/newtabbedpane.rb +612 -0
- data/lib/rbcurse/extras/newtabbedwindow.rb +68 -0
- data/lib/rbcurse/extras/padreader.rb +189 -0
- data/lib/rbcurse/extras/rcomboedit.rb +256 -0
- data/lib/rbcurse/extras/resultsetbrowser.rb +281 -0
- data/lib/rbcurse/extras/statusline.rb +44 -6
- data/lib/rbcurse/extras/tabularwidget.rb +141 -104
- data/lib/rbcurse/extras/textpad.rb +516 -0
- data/lib/rbcurse/extras/viewer.rb +2 -0
- data/lib/rbcurse/io.rb +120 -3
- data/lib/rbcurse/listcellrenderer.rb +2 -1
- data/lib/rbcurse/listkeys.rb +1 -1
- data/lib/rbcurse/listscrollable.rb +72 -7
- data/lib/rbcurse/rbasiclistbox.rb +64 -12
- data/lib/rbcurse/rchangeevent.rb +0 -1
- data/lib/rbcurse/rcombo.rb +54 -59
- data/lib/rbcurse/rcommandwindow.rb +46 -10
- data/lib/rbcurse/rcontainer.rb +415 -0
- data/lib/rbcurse/rdialogs.rb +242 -165
- data/lib/rbcurse/rinputdataevent.rb +0 -1
- data/lib/rbcurse/rlistbox.rb +19 -9
- data/lib/rbcurse/rmessagebox.rb +1 -5
- data/lib/rbcurse/rmulticontainer.rb +64 -61
- data/lib/rbcurse/rmultitextview.rb +0 -2
- data/lib/rbcurse/rpopupmenu.rb +0 -2
- data/lib/rbcurse/rscrollform.rb +61 -12
- data/lib/rbcurse/rtabbedpane.rb +89 -73
- data/lib/rbcurse/rtabbedwindow.rb +53 -211
- data/lib/rbcurse/rtable.rb +0 -2
- data/lib/rbcurse/rtextarea.rb +14 -14
- data/lib/rbcurse/rtextview.rb +165 -50
- data/lib/rbcurse/rvimsplit.rb +15 -12
- data/lib/rbcurse/rwidget.rb +404 -150
- data/lib/rbcurse/table/tablecellrenderer.rb +1 -4
- data/lib/rbcurse/table/tabledatecellrenderer.rb +0 -3
- data/lib/ver/ncurses.rb +1 -9
- data/lib/ver/rpad.rb +375 -0
- data/lib/ver/window.rb +262 -440
- metadata +73 -31
data/lib/rbcurse/rchangeevent.rb
CHANGED
data/lib/rbcurse/rcombo.rb
CHANGED
@@ -1,41 +1,43 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
# ----------------------------------------------------------------------------- #
|
2
|
+
# File: rcombo.rb
|
3
|
+
# Description: Non-editable combo box.
|
4
|
+
# Make it dead-simple to use.
|
5
|
+
# This is a simpler version of the original ComboBox which allowed
|
6
|
+
# editing and used rlistbox. This simpler class is meant for the rbcurse
|
7
|
+
# core package and will only depend on a core class if at all.
|
8
|
+
# Author: rkumar http://github.com/rkumar/rbcurse/
|
9
|
+
# Date: 2011-11-11 - 21:42
|
10
|
+
# License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
11
|
+
# Last update: use ,,L
|
12
|
+
# ----------------------------------------------------------------------------- #
|
13
|
+
#
|
12
14
|
require 'rbcurse'
|
13
|
-
require 'rbcurse/rlistbox'
|
14
15
|
|
15
|
-
#include Ncurses # FFI 2011-09-8
|
16
16
|
include RubyCurses
|
17
17
|
module RubyCurses
|
18
|
-
META_KEY = 128
|
19
18
|
extend self
|
20
19
|
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
20
|
+
# the quick approach would be to use field, and just add a popup.
|
21
|
+
# Or since we are not editing, we could use a Label and a popup
|
22
|
+
# Or just display a label and a popup without using anything else.
|
23
|
+
#
|
24
|
+
|
25
25
|
class ComboBox < Field
|
26
26
|
include RubyCurses::EventHandler
|
27
27
|
dsl_accessor :list_config
|
28
|
-
dsl_accessor :insert_policy # NO_INSERT, INSERT_AT_TOP, INSERT_AT_BOTTOM, INSERT_AT_CURRENT
|
29
|
-
# INSERT_AFTER_CURRENT, INSERT_BEFORE_CURRENT,INSERT_ALPHABETICALLY
|
30
28
|
|
31
29
|
attr_accessor :current_index
|
32
30
|
# the symbol you want to use for combos
|
33
31
|
attr_accessor :COMBO_SYMBOL
|
34
32
|
attr_accessor :show_symbol # show that funny symbol after a combo to signify its a combo
|
33
|
+
dsl_accessor :arrow_key_policy # :IGNORE :NEXT_ROW :POPUP
|
35
34
|
|
36
35
|
def initialize form, config={}, &block
|
36
|
+
@arrow_key_policy = :ignore
|
37
|
+
@editable = false
|
38
|
+
@COMBO_SYMBOL = "v".ord # trying this out
|
39
|
+
@current_index = 0
|
37
40
|
super
|
38
|
-
@current_index ||= 0
|
39
41
|
# added if check since it was overriding set_buffer in creation. 2009-01-18 00:03
|
40
42
|
set_buffer @list[@current_index].dup if @buffer.nil? or @buffer.empty?
|
41
43
|
init_vars
|
@@ -43,7 +45,8 @@ module RubyCurses
|
|
43
45
|
end
|
44
46
|
def init_vars
|
45
47
|
super
|
46
|
-
@show_symbol
|
48
|
+
@show_symbol = true if @show_symbol.nil? # if set to false don't touch
|
49
|
+
#@show_symbol = false if @label # 2011-11-13
|
47
50
|
@COMBO_SYMBOL ||= FFI::NCurses::ACS_DARROW #GEQUAL
|
48
51
|
bind_key(KEY_UP) { previous_row }
|
49
52
|
bind_key(KEY_DOWN) { next_row }
|
@@ -59,13 +62,8 @@ module RubyCurses
|
|
59
62
|
# convert given list to datamodel
|
60
63
|
def list alist=nil
|
61
64
|
return @list if alist.nil?
|
62
|
-
|
63
|
-
|
64
|
-
##
|
65
|
-
# set given datamodel
|
66
|
-
def list_data_model ldm
|
67
|
-
raise "Expecting list_data_model" unless ldm.is_a? RubyCurses::ListDataModel
|
68
|
-
@list = ldm
|
65
|
+
#@list = RubyCurses::ListDataModel.new(alist)
|
66
|
+
@list = alist
|
69
67
|
end
|
70
68
|
##
|
71
69
|
# combo edit box key handling
|
@@ -78,26 +76,36 @@ module RubyCurses
|
|
78
76
|
return :UNHANDLED
|
79
77
|
end
|
80
78
|
end
|
79
|
+
case @arrow_key_policy
|
80
|
+
when :ignore
|
81
|
+
if ch == KEY_DOWN or ch == KEY_UP
|
82
|
+
return :UNHANDLED
|
83
|
+
end
|
84
|
+
when :popup
|
85
|
+
if ch == KEY_DOWN or ch == KEY_UP
|
86
|
+
popup
|
87
|
+
end
|
88
|
+
end
|
81
89
|
case ch
|
82
90
|
#when KEY_UP # show previous value
|
83
91
|
# previous_row
|
84
92
|
#when KEY_DOWN # show previous value
|
85
93
|
# next_row
|
86
94
|
# adding spacebar to popup combo, as in microemacs 2010-10-01 13:21
|
87
|
-
when 32, KEY_DOWN+
|
95
|
+
when 32, KEY_DOWN+ META_KEY # alt down
|
88
96
|
popup # pop up the popup
|
89
97
|
else
|
90
98
|
super
|
91
99
|
end
|
92
100
|
end
|
93
|
-
def
|
101
|
+
def DEPprevious_row
|
94
102
|
@current_index -= 1 if @current_index > 0
|
95
103
|
set_buffer @list[@current_index].dup
|
96
104
|
set_modified(true) ## ??? not required
|
97
105
|
fire_handler :ENTER_ROW, self
|
98
106
|
@list.on_enter_row self
|
99
107
|
end
|
100
|
-
def
|
108
|
+
def DEPnext_row
|
101
109
|
@current_index += 1 if @current_index < @list.length()-1
|
102
110
|
set_buffer @list[@current_index].dup
|
103
111
|
set_modified(true) ## ??? not required
|
@@ -117,6 +125,19 @@ module RubyCurses
|
|
117
125
|
# added dup in PRESS since editing edit field mods this
|
118
126
|
# on pressing ENTER, value set back and current_index updated
|
119
127
|
def popup
|
128
|
+
@list_config ||= {}
|
129
|
+
@list_config[:row] ||= @row
|
130
|
+
@list_config[:col] ||= @col
|
131
|
+
@list_config[:relative_to] ||= self
|
132
|
+
# this does not allow us to bind to events in the list
|
133
|
+
index = popuplist @list, @list_config
|
134
|
+
if index
|
135
|
+
set_buffer @list[index].dup
|
136
|
+
set_modified(true) if @current_index != index
|
137
|
+
@current_index = index
|
138
|
+
end
|
139
|
+
end
|
140
|
+
def OLDpopup
|
120
141
|
listconfig = (@list_config && @list_config.dup) || {}
|
121
142
|
dm = @list
|
122
143
|
# current item in edit box will be focussed when list pops up
|
@@ -199,43 +220,17 @@ module RubyCurses
|
|
199
220
|
# no effect on the list, and wont trigger events.
|
200
221
|
# Do not override.
|
201
222
|
def on_leave
|
202
|
-
if !@list.include? @buffer and !@buffer.strip.empty?
|
203
|
-
_insert_policy = @insert_policy || :INSERT_AT_BOTTOM
|
204
|
-
case _insert_policy
|
205
|
-
when :INSERT_AT_BOTTOM, :INSERT_AT_END
|
206
|
-
@list.append @buffer
|
207
|
-
when :INSERT_AT_TOP
|
208
|
-
@list.insert(0, @buffer)
|
209
|
-
when :INSERT_AFTER_CURRENT
|
210
|
-
@current_index += 1
|
211
|
-
@list.insert(@current_index, @buffer)
|
212
|
-
|
213
|
-
when :INSERT_BEFORE_CURRENT
|
214
|
-
#_index = @current_index-1 if @current_index>0
|
215
|
-
_index = @current_index
|
216
|
-
@list.insert(_index, @buffer)
|
217
|
-
when :INSERT_AT_CURRENT
|
218
|
-
@list[@current_index]=@buffer
|
219
|
-
when :NO_INSERT
|
220
|
-
; # take a break
|
221
|
-
end
|
222
|
-
end
|
223
223
|
fire_handler :LEAVE, self
|
224
224
|
end
|
225
225
|
|
226
226
|
def repaint
|
227
227
|
super
|
228
228
|
c = @col + @display_length
|
229
|
-
# @form.window.mvwvline( @row, c, ACS_VLINE, 1)
|
230
229
|
if @show_symbol # 2009-01-11 18:47
|
231
230
|
# i have changed c +1 to c, since we have no right to print beyond display_length
|
232
231
|
@form.window.mvwaddch @row, c, @COMBO_SYMBOL # Ncurses::ACS_GEQUAL
|
232
|
+
@form.window.mvchgat(y=@row, x=c, max=1, Ncurses::A_REVERSE|Ncurses::A_UNDERLINE, $datacolor, nil)
|
233
233
|
end
|
234
|
-
# @form.window.mvwvline( @row, c+2, ACS_VLINE, 1)
|
235
|
-
# @form.window.mvwaddch @row, c+2, Ncurses::ACS_S1
|
236
|
-
# @form.window.mvwaddch @row, c+3, Ncurses::ACS_S9
|
237
|
-
# @form.window.mvwaddch @row, c+4, Ncurses::ACS_LRCORNER
|
238
|
-
# @form.window.mvwhline( @row, c+5, ACS_HLINE, 2)
|
239
234
|
end
|
240
235
|
|
241
236
|
end # class ComboBox
|
@@ -30,7 +30,7 @@ module RubyCurses
|
|
30
30
|
@config.each_pair { |k,v| instance_variable_set("@#{k}",v) }
|
31
31
|
instance_eval &block if block_given?
|
32
32
|
if @layout.nil?
|
33
|
-
set_layout(1,80,
|
33
|
+
set_layout(1,80, -1, 0)
|
34
34
|
end
|
35
35
|
@height = @layout[:height]
|
36
36
|
@width = @layout[:width]
|
@@ -51,7 +51,8 @@ module RubyCurses
|
|
51
51
|
@window.printstring 0,0,@title, $normalcolor #, 'normal' if @title
|
52
52
|
@window.attroff(Ncurses.COLOR_PAIR($normalcolor) | Ncurses::A_REVERSE)
|
53
53
|
else
|
54
|
-
|
54
|
+
#@window.printstring 0,0,@title, $normalcolor, 'reverse' if @title
|
55
|
+
title @title
|
55
56
|
end
|
56
57
|
@window.wrefresh
|
57
58
|
@panel = @window.panel
|
@@ -62,6 +63,12 @@ module RubyCurses
|
|
62
63
|
@row_offset = 1
|
63
64
|
end
|
64
65
|
end
|
66
|
+
# modify the window title, or get it if no params passed.
|
67
|
+
def title t=nil
|
68
|
+
return @title unless t
|
69
|
+
@title = t
|
70
|
+
@window.printstring 0,0,@title, $normalcolor, 'reverse' if @title
|
71
|
+
end
|
65
72
|
##
|
66
73
|
## message box
|
67
74
|
def stopping?
|
@@ -135,6 +142,10 @@ module RubyCurses
|
|
135
142
|
end
|
136
143
|
|
137
144
|
def set_layout(height=0, width=0, top=0, left=0)
|
145
|
+
# negative means top should be n rows from last line. -1 is last line
|
146
|
+
if top < 0
|
147
|
+
top = Ncurses.LINES-top
|
148
|
+
end
|
138
149
|
@layout = { :height => height, :width => width, :top => top, :left => left }
|
139
150
|
@height = height
|
140
151
|
@width = width
|
@@ -150,9 +161,21 @@ module RubyCurses
|
|
150
161
|
end
|
151
162
|
end
|
152
163
|
end
|
153
|
-
#
|
164
|
+
#
|
165
|
+
# Displays list in a window at bottom of screen, if large then 2 or 3 columns.
|
166
|
+
# @param [Array] list of string to be displayed
|
167
|
+
# @param [Hash] configuration options: indexing and indexcolor
|
168
|
+
# indexing - can be letter or number. Anything else will be ignored, however
|
169
|
+
# it will result in first letter being highlighted in indexcolor
|
170
|
+
# indexcolor - color of mnemonic, default green
|
154
171
|
def display_menu list, options={}
|
155
172
|
indexing = options[:indexing]
|
173
|
+
indexcolor = options[:indexcolor] || get_color($normalcolor, :yellow, :black)
|
174
|
+
indexatt = Ncurses::A_BOLD
|
175
|
+
#
|
176
|
+
# the index to start from (used when scrolling a long menu such as file list)
|
177
|
+
startindex = options[:startindex] || 0
|
178
|
+
|
156
179
|
max_cols = 3 # maximum no of columns, we will reduce based on data size
|
157
180
|
l_succ = "`"
|
158
181
|
act_height = @height
|
@@ -169,11 +192,16 @@ module RubyCurses
|
|
169
192
|
text = e.first + " ..."
|
170
193
|
end
|
171
194
|
if indexing == :number
|
195
|
+
mnem = i+1
|
172
196
|
text = "%d. %s" % [i+1, text]
|
173
197
|
elsif indexing == :letter
|
174
|
-
|
198
|
+
mnem = l_succ.succ!
|
199
|
+
text = "%s. %s" % [mnem, text]
|
175
200
|
end
|
176
201
|
@window.printstring i+@row_offset, 1, text, $normalcolor
|
202
|
+
if indexing
|
203
|
+
window.mvchgat(y=i+@row_offset, x=1, max=1, indexatt, indexcolor, nil)
|
204
|
+
end
|
177
205
|
}
|
178
206
|
else
|
179
207
|
$log.debug "DDD inside two window" if $log.debug?
|
@@ -193,7 +221,6 @@ module RubyCurses
|
|
193
221
|
col = 1
|
194
222
|
$log.debug "DDDcols #{cols}, adv #{adv} size: #{lh} h: #{act_height} w #{@width} " if $log.debug?
|
195
223
|
list.each_with_index { |e, i|
|
196
|
-
# check that row + @row_offset < @top + @height or whatever TODO
|
197
224
|
text = e
|
198
225
|
# signify that there's a deeper level
|
199
226
|
case e
|
@@ -201,11 +228,19 @@ module RubyCurses
|
|
201
228
|
text = e.first + "..."
|
202
229
|
end
|
203
230
|
if indexing == :number
|
204
|
-
|
231
|
+
mnem = i+1
|
232
|
+
text = "%d. %s" % [mnem, text]
|
205
233
|
elsif indexing == :letter
|
206
|
-
|
234
|
+
mnem = l_succ.succ!
|
235
|
+
text = "%s. %s" % [mnem, text]
|
207
236
|
end
|
208
|
-
|
237
|
+
# print only within range and window height
|
238
|
+
if i >= startindex && row < @window.actual_height
|
239
|
+
$log.debug "XXX: MENU #{i} > #{startindex} row #{row} col #{col} "
|
240
|
+
@window.printstring row+@row_offset, col, text, $normalcolor
|
241
|
+
if indexing
|
242
|
+
@window.mvchgat(y=row+@row_offset, x=col, max=1, indexatt, indexcolor, nil)
|
243
|
+
end
|
209
244
|
colct += 1
|
210
245
|
if colct == cols
|
211
246
|
col = 1
|
@@ -214,6 +249,7 @@ module RubyCurses
|
|
214
249
|
else
|
215
250
|
col += adv
|
216
251
|
end
|
252
|
+
end # startindex
|
217
253
|
}
|
218
254
|
end
|
219
255
|
Ncurses::Panel.update_panels();
|
@@ -521,7 +557,7 @@ module RubyCurses
|
|
521
557
|
@window.wmove row, c
|
522
558
|
@window.wrefresh # FFI added to keep cursor display in synch with selection
|
523
559
|
end
|
524
|
-
def OLDbounds_check
|
560
|
+
def OLDbounds_check #:nodoc:
|
525
561
|
@start = 0 if @start < 0
|
526
562
|
row_offset = 1
|
527
563
|
last = (@list.length)-(@height-row_offset-1)
|
@@ -529,7 +565,7 @@ module RubyCurses
|
|
529
565
|
@start = last
|
530
566
|
end
|
531
567
|
end # bounds_check
|
532
|
-
def handle_keys
|
568
|
+
def handle_keys #:nodoc:
|
533
569
|
begin
|
534
570
|
while((ch = @window.getchar()) != 999 )
|
535
571
|
case ch
|
@@ -0,0 +1,415 @@
|
|
1
|
+
=begin
|
2
|
+
* Name: A container that manages components placed in it but
|
3
|
+
is not a form. Thus it can be safely placed as a widget
|
4
|
+
without all the complicatinos of a form embedded inside another.
|
5
|
+
NOTE: Still experimental
|
6
|
+
* Description
|
7
|
+
* Author: rkumar (http://github.com/rkumar/rbcurse/)
|
8
|
+
* Date: 21.10.11 - 00:29
|
9
|
+
* License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
10
|
+
|
11
|
+
* Last update: 23.10.11 - 00:29
|
12
|
+
== CHANGES
|
13
|
+
Focusables so we don't focus on label
|
14
|
+
== TODO
|
15
|
+
How to put blank lines in stack - use a blank label
|
16
|
+
|
17
|
+
- The contaomers and multis need to do their own on_enter and on_leave
|
18
|
+
management, they cannot rely on some other container doing it.
|
19
|
+
We can only rely on handle_key being called. HK should determine
|
20
|
+
whether any set_form row etc needs to be done.
|
21
|
+
- Should have its own stack and flow
|
22
|
+
=end
|
23
|
+
|
24
|
+
require 'rbcurse'
|
25
|
+
|
26
|
+
include RubyCurses
|
27
|
+
module RubyCurses
|
28
|
+
extend self
|
29
|
+
|
30
|
+
# This is an attempt at having a container which can contain multiple
|
31
|
+
# widgets without being a form itself. Having forms within forms
|
32
|
+
# complicates code too much, esp cursor positioning. e.g. tabbedpane
|
33
|
+
|
34
|
+
class Container < Widget
|
35
|
+
|
36
|
+
dsl_accessor :suppress_borders #to_print_borders
|
37
|
+
dsl_accessor :border_attrib, :border_color
|
38
|
+
dsl_accessor :title #set this on top
|
39
|
+
dsl_accessor :title_attrib #bold, reverse, normal
|
40
|
+
# should container stack objects ignoring users row col
|
41
|
+
# this is esp needed since App sets row and col which is too early
|
42
|
+
# This is now the default value, till i can redo things
|
43
|
+
#dsl_accessor :stack
|
44
|
+
dsl_accessor :positioning # absolute, relative, stack
|
45
|
+
attr_reader :current_component
|
46
|
+
|
47
|
+
def initialize form=nil, config={}, &block
|
48
|
+
@suppress_borders = false
|
49
|
+
@row_offset = @col_offset = 1
|
50
|
+
@_events ||= []
|
51
|
+
@stack = true
|
52
|
+
@positioning = :stack
|
53
|
+
super
|
54
|
+
@focusable = true
|
55
|
+
@editable = false
|
56
|
+
@components = [] # all components
|
57
|
+
@focusables = [] # focusable components, makes checks easier
|
58
|
+
|
59
|
+
init_vars
|
60
|
+
end
|
61
|
+
def init_vars
|
62
|
+
@repaint_required = true
|
63
|
+
@row_offset = @col_offset = 0 if @suppress_borders # FIXME supposed to use this !!
|
64
|
+
|
65
|
+
@internal_width = 2
|
66
|
+
@internal_width = 1 if @suppress_borders
|
67
|
+
@name ||= "AContainer"
|
68
|
+
@first_time = true
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
# NOTE: since we are handling the traversal, we delink the object from any
|
73
|
+
# form's widgets array that might have been added. Whenever a form is available,
|
74
|
+
# we set it (without adding widget to it) so it can print using the form's window.
|
75
|
+
#
|
76
|
+
# @param [Widget] to add
|
77
|
+
def add *items
|
78
|
+
items.each do |c|
|
79
|
+
raise ArgumentError, "Nil component passed to add" unless c
|
80
|
+
if c.is_a? Widget
|
81
|
+
if c.form && c.form != @form
|
82
|
+
$log.debug " removing widget VIMSPLIT #{c.class} wr: #{c.row} row:#{@row} ht:#{@height} "
|
83
|
+
c.form.remove_widget c
|
84
|
+
c.form = nil
|
85
|
+
# or should i just stack them myself and screw what you've asked for
|
86
|
+
end
|
87
|
+
# take it out of form's control. We will control it.
|
88
|
+
if c.form
|
89
|
+
c.form.remove_widget c
|
90
|
+
end
|
91
|
+
# shoot, what if at this point the container does not have a form
|
92
|
+
attach_form c if @form
|
93
|
+
end
|
94
|
+
# most likely if you have created both container and widgets
|
95
|
+
# inside app, it would have given row after container
|
96
|
+
|
97
|
+
@components << c
|
98
|
+
if c.focusable
|
99
|
+
@focusables << c
|
100
|
+
@current_component ||= c # only the first else cursor falls on last on enter
|
101
|
+
end
|
102
|
+
|
103
|
+
end # items each
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
# When we get a form, we silently attach it to this object, without the form
|
108
|
+
# knowing. We don't want form managing this object.
|
109
|
+
def attach_form c
|
110
|
+
c.form = @form
|
111
|
+
c.override_graphic @graphic
|
112
|
+
c.parent_component = self
|
113
|
+
end
|
114
|
+
alias :add_widget :add
|
115
|
+
def widgets; @components; end
|
116
|
+
# what of by_name
|
117
|
+
|
118
|
+
|
119
|
+
# correct coordinates of comp esp if App has stacked them after this
|
120
|
+
# container
|
121
|
+
# It is best to use the simple stack feature. The rest could change at any time
|
122
|
+
# and is quite arbitrary. Some folks may set absolute locations if container
|
123
|
+
# is directly on a form, others may set relative locations if it is inside a
|
124
|
+
# tabbed pane or other container. Thus, stacks are best
|
125
|
+
def correct_component c
|
126
|
+
raise "Form is still not set in Container" unless @form
|
127
|
+
attach_form(c) unless c.form
|
128
|
+
@last_row ||= @row + 1
|
129
|
+
inset = 2
|
130
|
+
# 2011-10-20 current default behaviour is to stack
|
131
|
+
if @positioning == :stack
|
132
|
+
c.row = @last_row
|
133
|
+
c.col = @col + inset
|
134
|
+
|
135
|
+
# do not advance row, save col for next row
|
136
|
+
@last_row += 1
|
137
|
+
elsif @positioning == :relative # UNTESTED NOTE
|
138
|
+
if (c.row || 0) <= 0
|
139
|
+
$log.warn "c.row in CONTAINER is #{c.row} "
|
140
|
+
c.row = @last_row
|
141
|
+
@last_row += 1
|
142
|
+
elsif c.row > @row + @height -1
|
143
|
+
$log.warn "c.row in CONTAINER exceeds container. #{c.row} "
|
144
|
+
c.row -= @height - @row_offset
|
145
|
+
else
|
146
|
+
# this is where it should come
|
147
|
+
c.row += @row + @row_offset
|
148
|
+
@last_row = c.row + 1
|
149
|
+
end
|
150
|
+
if (c.col || 0) <= 0
|
151
|
+
c.col = @col + inset + @col_offset
|
152
|
+
elsif c.col > @col + @width -1
|
153
|
+
c.col -= @width
|
154
|
+
elsif c.col == @col
|
155
|
+
c.col += @col_offset + inset
|
156
|
+
else #f c.col < @col
|
157
|
+
c.col += @col+@col_offset
|
158
|
+
end
|
159
|
+
$log.debug "XXX: CORRECT #{c.name} r:#{c.row} c:#{c.col} "
|
160
|
+
end
|
161
|
+
@first_time = false
|
162
|
+
end
|
163
|
+
def check_component c
|
164
|
+
raise "row is less than container #{c.row} #{@row} " if c.row <= @row
|
165
|
+
raise "col is less than container #{c.col} #{@col} " if c.col <= @col
|
166
|
+
end
|
167
|
+
|
168
|
+
public
|
169
|
+
# repaint object
|
170
|
+
# called by Form, and sometimes parent component (if not form).
|
171
|
+
def repaint
|
172
|
+
my_win = @form ? @form.window : @target_window
|
173
|
+
@graphic = my_win unless @graphic
|
174
|
+
raise " #{@name} NO GRAPHIC set as yet CONTAINER paint " unless @graphic
|
175
|
+
@components.each { |e| correct_component e } if @first_time
|
176
|
+
#@components.each { |e| check_component e } # seeme one if printing out
|
177
|
+
|
178
|
+
#return unless @repaint_required
|
179
|
+
|
180
|
+
# if some major change has happened then repaint everything
|
181
|
+
if @repaint_required
|
182
|
+
$log.debug " VIM repaint graphic #{@graphic} "
|
183
|
+
print_borders unless @suppress_borders # do this once only, unless everything changes
|
184
|
+
@components.each { |e| e.repaint_all(true); e.repaint }
|
185
|
+
else
|
186
|
+
@components.each { |e| e.repaint }
|
187
|
+
end # if repaint_required
|
188
|
+
|
189
|
+
@repaint_required = false
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
def print_borders
|
194
|
+
width = @width
|
195
|
+
height = @height-1 # 2010-01-04 15:30 BUFFERED HEIGHT
|
196
|
+
window = @graphic # 2010-01-04 12:37 BUFFERED
|
197
|
+
startcol = @col
|
198
|
+
startrow = @row
|
199
|
+
@color_pair = get_color($datacolor)
|
200
|
+
#$log.debug "rlistb #{name}: window.print_border #{startrow}, #{startcol} , h:#{height}, w:#{width} , @color_pair, @attr "
|
201
|
+
window.print_border startrow, startcol, height, width, @color_pair, @attr
|
202
|
+
print_title
|
203
|
+
end
|
204
|
+
def print_title
|
205
|
+
$log.debug "CONTAINER PRINTING TITLE at #{row} #{col} "
|
206
|
+
@graphic.printstring( @row, @col+(@width-@title.length)/2, @title, @color_pair, @title_attrib) unless @title.nil?
|
207
|
+
end
|
208
|
+
|
209
|
+
public
|
210
|
+
# called by parent or form, otherwise its private
|
211
|
+
def handle_key ch
|
212
|
+
$log.debug " CONTAINER handle_key #{ch} "
|
213
|
+
return if @components.empty?
|
214
|
+
_multiplier = ($multiplier == 0 ? 1 : $multiplier )
|
215
|
+
|
216
|
+
# should this go here 2011-10-19
|
217
|
+
unless @_entered
|
218
|
+
$log.warn "XXX WARN: calling ON_ENTER since in this situation it was not called"
|
219
|
+
on_enter
|
220
|
+
end
|
221
|
+
if ch == KEY_TAB
|
222
|
+
$log.debug "CONTAINER GOTO NEXT TAB"
|
223
|
+
return goto_next_component
|
224
|
+
elsif ch == KEY_BTAB
|
225
|
+
return goto_prev_component
|
226
|
+
end
|
227
|
+
comp = @current_component
|
228
|
+
$log.debug " CONTAINER handle_key #{ch}: #{comp}"
|
229
|
+
if comp
|
230
|
+
ret = comp.handle_key(ch)
|
231
|
+
$log.debug " CONTAINER handle_key#{ch}: #{comp} returned #{ret} "
|
232
|
+
if ret != :UNHANDLED
|
233
|
+
comp.repaint # NOTE: if we don;t do this, then it won't get repainted. I will have to repaint ALL
|
234
|
+
# in repaint of this.
|
235
|
+
return ret
|
236
|
+
end
|
237
|
+
$log.debug "XXX CONTAINER key unhandled by comp #{comp.name} "
|
238
|
+
else
|
239
|
+
$log.warn "XXX CONTAINER key unhandled NULL comp"
|
240
|
+
end
|
241
|
+
case ch
|
242
|
+
when ?\C-c.getbyte(0)
|
243
|
+
$multiplier = 0
|
244
|
+
return 0
|
245
|
+
when ?0.getbyte(0)..?9.getbyte(0)
|
246
|
+
$log.debug " VIM coming here to set multiplier #{$multiplier} "
|
247
|
+
$multiplier *= 10 ; $multiplier += (ch-48)
|
248
|
+
return 0
|
249
|
+
end
|
250
|
+
ret = process_key ch, self
|
251
|
+
# allow user to map left and right if he wants
|
252
|
+
if ret == :UNHANDLED
|
253
|
+
case ch
|
254
|
+
when KEY_UP
|
255
|
+
# form will pick this up and do needful
|
256
|
+
return goto_prev_component #unless on_first_component?
|
257
|
+
when KEY_LEFT
|
258
|
+
# if i don't check for first component, key will go back to form,
|
259
|
+
# but not be processes. so focussed remain here, but be false.
|
260
|
+
# In case of returnign an unhandled TAB, on_leave will happen and cursor will move to
|
261
|
+
# previous component outside of this.
|
262
|
+
return goto_prev_component unless on_first_component?
|
263
|
+
when KEY_RIGHT
|
264
|
+
return goto_next_component #unless on_last_component?
|
265
|
+
when KEY_DOWN
|
266
|
+
return goto_next_component #unless on_last_component?
|
267
|
+
else
|
268
|
+
@_entered = false
|
269
|
+
return :UNHANDLED
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
$multiplier = 0
|
274
|
+
return 0
|
275
|
+
end
|
276
|
+
# Actually we should only go to current component if it accepted
|
277
|
+
# a key stroke. if user tabbed thru it, then no point going back to
|
278
|
+
# it. Go to first or last depending on TAB or BACKTAB otherwise.
|
279
|
+
# NOTE: if user comes in using DOWN or UP, last traversed component will get the focus
|
280
|
+
#
|
281
|
+
def on_enter
|
282
|
+
# if BTAB, the last comp XXX they must be focusable FIXME
|
283
|
+
if $current_key == KEY_BTAB || $current_key == KEY_UP
|
284
|
+
@current_component = @focusables.last
|
285
|
+
else
|
286
|
+
@current_component = @focusables.first
|
287
|
+
end
|
288
|
+
return unless @current_component
|
289
|
+
$log.debug " CONTAINER came to ON_ENTER #{@current_component} "
|
290
|
+
set_form_row
|
291
|
+
@_entered = true
|
292
|
+
end
|
293
|
+
# we cannot be sure that this will be called especially if this is embedded
|
294
|
+
# inside some other component
|
295
|
+
def on_leave
|
296
|
+
@_entered = false
|
297
|
+
super
|
298
|
+
end
|
299
|
+
def goto_next_component
|
300
|
+
if @current_component != nil
|
301
|
+
leave_current_component
|
302
|
+
if on_last_component?
|
303
|
+
#@_entered = false
|
304
|
+
return :UNHANDLED
|
305
|
+
end
|
306
|
+
@current_index = @focusables.index(@current_component)
|
307
|
+
index = @current_index + 1
|
308
|
+
f = @focusables[index]
|
309
|
+
if f
|
310
|
+
@current_index = index
|
311
|
+
@current_component = f
|
312
|
+
return set_form_row
|
313
|
+
end
|
314
|
+
end
|
315
|
+
@_entered = false
|
316
|
+
return :UNHANDLED
|
317
|
+
end
|
318
|
+
def goto_prev_component
|
319
|
+
if @current_component != nil
|
320
|
+
leave_current_component
|
321
|
+
if on_first_component?
|
322
|
+
@_entered = false
|
323
|
+
return :UNHANDLED
|
324
|
+
end
|
325
|
+
@current_index = @focusables.index(@current_component)
|
326
|
+
index = @current_index -= 1
|
327
|
+
f = @focusables[i]
|
328
|
+
if f
|
329
|
+
@current_index = index
|
330
|
+
@current_component = f
|
331
|
+
return set_form_row
|
332
|
+
end
|
333
|
+
end
|
334
|
+
return :UNHANDLED
|
335
|
+
end
|
336
|
+
# private
|
337
|
+
# XXX why are we calling 3 methods in a row, why not OE manages these 3
|
338
|
+
# There's double calling going on.
|
339
|
+
def set_form_row
|
340
|
+
return :UNHANDLED if @current_component.nil?
|
341
|
+
cc = @current_component
|
342
|
+
$log.debug "CONT #{@name} set_form_row calling sfr for #{cc.name}, r #{cc.row} c: #{cc.col} "
|
343
|
+
$log.debug " CONTAINER on enter sfr #{@current_component.name} #{@current_component} "
|
344
|
+
|
345
|
+
# bug caught here. we were printing a field before it had been set, so it printed out
|
346
|
+
@components.each { |e| correct_component e } if @first_time
|
347
|
+
@current_component.on_enter
|
348
|
+
@current_component.set_form_row # why was this missing in vimsplit. is it
|
349
|
+
$log.debug "CONT2 #{@name} set_form_row calling sfr for #{cc.name}, r #{cc.row} c: #{cc.col} "
|
350
|
+
# that on_enter does a set_form_row
|
351
|
+
@current_component.set_form_col # XXX
|
352
|
+
@current_component.repaint # OMG this could happen before we've set row and col
|
353
|
+
# XXX compo should do set_form_row and col if it has that
|
354
|
+
end
|
355
|
+
#
|
356
|
+
def set_form_col
|
357
|
+
return if @current_component.nil?
|
358
|
+
$log.debug " #{@name} CONTAINER EMPTY set_form_col calling sfc for #{@current_component.name} "
|
359
|
+
# already called from above.
|
360
|
+
#@current_component.set_form_col
|
361
|
+
end
|
362
|
+
# leave the component we are on.
|
363
|
+
# This should be followed by all containers, so that the on_leave action
|
364
|
+
# of earlier comp can be displayed, such as dimming components selections
|
365
|
+
def leave_current_component
|
366
|
+
@current_component.on_leave
|
367
|
+
# NOTE this is required, since repaint will just not happen otherwise
|
368
|
+
# Some components are erroneously repainting all, after setting this to true so it is
|
369
|
+
# working there.
|
370
|
+
@current_component.repaint_required true
|
371
|
+
$log.debug " after on_leave RCONT XXX #{@current_component.focussed} #{@current_component.name}"
|
372
|
+
@current_component.repaint
|
373
|
+
end
|
374
|
+
|
375
|
+
# is focus on first component FIXME check for focusable
|
376
|
+
def on_first_component?
|
377
|
+
@current_component == @focusables.first
|
378
|
+
end
|
379
|
+
# is focus on last component FIXME check for focusable
|
380
|
+
def on_last_component?
|
381
|
+
@current_component == @focusables.last
|
382
|
+
end
|
383
|
+
# set focus on given component
|
384
|
+
# Sometimes you have the handle to component, and you want to move focus to it
|
385
|
+
def goto_component comp
|
386
|
+
return if comp == @current_component
|
387
|
+
leave_current_component
|
388
|
+
@current_component = comp
|
389
|
+
set_form_row
|
390
|
+
end
|
391
|
+
|
392
|
+
# ADD HERE ABOVe
|
393
|
+
end # class
|
394
|
+
end # module
|
395
|
+
|
396
|
+
if __FILE__ == $PROGRAM_NAME
|
397
|
+
require 'rbcurse/app'
|
398
|
+
App.new do
|
399
|
+
f1 = field "name", :maxlen => 20, :display_length => 20, :bgcolor => :white,
|
400
|
+
:color => :black, :text => "abc", :label => " Name: ", :label_color_pair => @datacolor
|
401
|
+
f2 = field "email", :display_length => 20, :bgcolor => :white,
|
402
|
+
:color => :blue, :text => "me@google.com", :label => "Email: ", :label_color_pair => @datacolor
|
403
|
+
f3 = radio :group => :grp, :text => "red", :value => "RED", :color => :red
|
404
|
+
f4 = radio :group => :grp, :text => "blue", :value => "BLUE", :color => :blue
|
405
|
+
f5 = radio :group => :grp, :text => "green", :value => "GREEN", :color => :green
|
406
|
+
stack :margin_top => 2, :margin => 2 do
|
407
|
+
r = container :row => 1, :col => 2, :width => 80, :height => 20, :title => "A container"
|
408
|
+
r.add(f1)
|
409
|
+
r.add(f2)
|
410
|
+
r.add(f3,f4,f5)
|
411
|
+
sl = status_line
|
412
|
+
end # stack
|
413
|
+
|
414
|
+
end # app
|
415
|
+
end # if
|