rbcurse-extras 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.md +75 -0
- data/VERSION +1 -0
- data/examples/data/list.txt +300 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/table.txt +36 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/inc/qdfilechooser.rb +70 -0
- data/examples/inc/rfe_renderer.rb +121 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/rfe.rb +1236 -0
- data/examples/test2.rb +670 -0
- data/examples/testeditlist.rb +78 -0
- data/examples/testtable.rb +270 -0
- data/examples/testvimsplit.rb +141 -0
- data/lib/rbcurse/extras/include/celleditor.rb +112 -0
- data/lib/rbcurse/extras/include/checkboxcellrenderer.rb +57 -0
- data/lib/rbcurse/extras/include/comboboxcellrenderer.rb +30 -0
- data/lib/rbcurse/extras/include/defaultlistselectionmodel.rb +79 -0
- data/lib/rbcurse/extras/include/listkeys.rb +37 -0
- data/lib/rbcurse/extras/include/listselectable.rb +144 -0
- data/lib/rbcurse/extras/include/tableextended.rb +40 -0
- data/lib/rbcurse/extras/widgets/horizlist.rb +203 -0
- data/lib/rbcurse/extras/widgets/menutree.rb +63 -0
- data/lib/rbcurse/extras/widgets/multilinelabel.rb +142 -0
- data/lib/rbcurse/extras/widgets/rcomboedit.rb +256 -0
- data/lib/rbcurse/extras/widgets/rlink.rb.moved +27 -0
- data/lib/rbcurse/extras/widgets/rlistbox.rb +1247 -0
- data/lib/rbcurse/extras/widgets/rmenulink.rb.moved +21 -0
- data/lib/rbcurse/extras/widgets/rmulticontainer.rb +304 -0
- data/lib/rbcurse/extras/widgets/rmultisplit.rb +722 -0
- data/lib/rbcurse/extras/widgets/rmultitextview.rb +306 -0
- data/lib/rbcurse/extras/widgets/rpopupmenu.rb +755 -0
- data/lib/rbcurse/extras/widgets/rtable.rb +1758 -0
- data/lib/rbcurse/extras/widgets/rvimsplit.rb +800 -0
- data/lib/rbcurse/extras/widgets/table/tablecellrenderer.rb +86 -0
- data/lib/rbcurse/extras/widgets/table/tabledatecellrenderer.rb +98 -0
- metadata +94 -0
@@ -0,0 +1,306 @@
|
|
1
|
+
=begin
|
2
|
+
* Name: MultiTextView
|
3
|
+
* Description View text in this widget for multiple files
|
4
|
+
* This differs from multicontainer in that since all components are textviews, so they
|
5
|
+
* are all gauranteed to be non-editable and thus we can map many more keys.
|
6
|
+
* MultiContainer can only map Ctrl and Alt (Meta) keys.
|
7
|
+
* Author: rkumar (arunachalesha)
|
8
|
+
* file created 2010-03-11 08:05
|
9
|
+
--------
|
10
|
+
* License:
|
11
|
+
Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
12
|
+
|
13
|
+
=end
|
14
|
+
require 'logger'
|
15
|
+
require 'rbcurse'
|
16
|
+
require 'rbcurse/core/widgets/rtextview'
|
17
|
+
require 'rbcurse/core/include/listscrollable'
|
18
|
+
|
19
|
+
#include Ncurses # FFI 2011-09-8
|
20
|
+
include RubyCurses
|
21
|
+
module RubyCurses
|
22
|
+
extend self
|
23
|
+
|
24
|
+
##
|
25
|
+
# A viewable read only box. Can scroll.
|
26
|
+
# Extends TextView with ability to load more than one file or content
|
27
|
+
# and switch between files (buffers).
|
28
|
+
# NOTE: ideally, i should be able to dynamically add this functionality to either Textview
|
29
|
+
# or TextArea or even ListBox or Table someday. Should then be a Module rather than a class.
|
30
|
+
class MultiTextView < TextView
|
31
|
+
include ListScrollable
|
32
|
+
|
33
|
+
def initialize form = nil, config={}, &block
|
34
|
+
|
35
|
+
super
|
36
|
+
@bmanager = BufferManager.new self
|
37
|
+
|
38
|
+
end
|
39
|
+
def init_vars
|
40
|
+
super
|
41
|
+
bind_key(?:, :buffer_menu)
|
42
|
+
bind_key(?e, :file_edit)
|
43
|
+
bind_key([?\C-x, ?f], :file_edit)
|
44
|
+
bind_key([?\C-x, ?k], :buffer_delete)
|
45
|
+
bind_key([?\C-x, ?\C-b], :buffers_list)
|
46
|
+
# easily cycle using p. n is used for next search.
|
47
|
+
bind_key(?p, :buffer_previous)
|
48
|
+
end
|
49
|
+
## returns current buffer
|
50
|
+
# @return [RBuffer] current buffer
|
51
|
+
def current_buffer
|
52
|
+
@bmanager.current
|
53
|
+
end
|
54
|
+
##
|
55
|
+
# send in a list
|
56
|
+
# e.g. set_content File.open("README.txt","r").readlines
|
57
|
+
# set wrap at time of passing :WRAP_NONE :WRAP_WORD
|
58
|
+
# @see add (add takes a title too which is required here)
|
59
|
+
def set_content list, wrap = :WRAP_NONE
|
60
|
+
ret = super
|
61
|
+
# buff = @bmanager.add_content @list
|
62
|
+
return ret
|
63
|
+
end
|
64
|
+
# multi-textview
|
65
|
+
def handle_key ch
|
66
|
+
# put list as current list and buffer too then super
|
67
|
+
#@current_buffer = @bmanager.current
|
68
|
+
#@list = @current_buffer.list
|
69
|
+
@buffer = @list[@current_index]
|
70
|
+
#@buffer = @bmanager.current
|
71
|
+
ret = super
|
72
|
+
# check for any keys not handled and check our own ones
|
73
|
+
return ret #
|
74
|
+
end
|
75
|
+
## prompt user for a filename to read in
|
76
|
+
def getfilename prompt="Enter filename: ", maxlen=90
|
77
|
+
tabc = Proc.new {|str| Dir.glob(str +"*") }
|
78
|
+
config={}; config[:tab_completion] = tabc
|
79
|
+
#config[:default] = "defaulT"
|
80
|
+
$log.debug " inside getstr before call #{$error_message_row} + #{$error_message_col} "
|
81
|
+
#ret, str = rbgetstr(@form.window, @row+@height-1, @col+1, prompt, maxlen, config)
|
82
|
+
ret, str = rbgetstr(@form.window, $error_message_row, $error_message_col, prompt, maxlen, config)
|
83
|
+
$log.debug " rbgetstr returned #{ret} , #{str} "
|
84
|
+
return "" if ret != 0
|
85
|
+
return str
|
86
|
+
end
|
87
|
+
# this is just a test of the simple "most" menu
|
88
|
+
# can use this for next, prev, first, last, new, delete, overwrite etc
|
89
|
+
def buffer_menu
|
90
|
+
menu = PromptMenu.new self
|
91
|
+
menu.add(menu.create_mitem( 'e', "edit a file", "opened file ", :file_edit ))
|
92
|
+
menu.add(menu.create_mitem( 'o', "overwrite file", "opened a file ", :file_overwrite ))
|
93
|
+
menu.add(menu.create_mitem( 'l', "list buffers", "list buffers ", :buffers_list ))
|
94
|
+
item = menu.create_mitem( 'b', "Buffer Options", "Buffer Options" )
|
95
|
+
menu1 = PromptMenu.new( self, "Buffer Options")
|
96
|
+
menu1.add(menu1.create_mitem( 'n', "Next", "Switched to next buffer", :buffer_next ))
|
97
|
+
menu1.add(menu1.create_mitem( 'p', "Prev", "Switched to previous buffer", :buffer_previous ))
|
98
|
+
menu1.add(menu1.create_mitem( 'f', "First", "Switched to first buffer", :buffer_first ))
|
99
|
+
menu1.add(menu1.create_mitem( 'l', "Last", "Switched to last buffer", :buffer_last ))
|
100
|
+
menu1.add(menu1.create_mitem( 'd', "Delete", "Deleted buffer", :buffer_delete ))
|
101
|
+
item.action = menu1
|
102
|
+
menu.add(item)
|
103
|
+
# how do i know what's available. the application or window should know where to place
|
104
|
+
menu.display @form.window, $error_message_row, $error_message_col, $datacolor #, menu
|
105
|
+
end
|
106
|
+
|
107
|
+
%w[next previous first last].each do |pos|
|
108
|
+
eval(
|
109
|
+
"def _buffer_#{pos}
|
110
|
+
@current_buffer = @bmanager.#{pos}
|
111
|
+
set_current_buffer
|
112
|
+
end"
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
def buffer_next
|
117
|
+
perror "No other buffer" and return if @bmanager.size < 2
|
118
|
+
|
119
|
+
@current_buffer = @bmanager.next
|
120
|
+
set_current_buffer
|
121
|
+
end
|
122
|
+
def buffer_previous
|
123
|
+
perror "No other buffer" and return if @bmanager.size < 2
|
124
|
+
|
125
|
+
@current_buffer = @bmanager.previous
|
126
|
+
$log.debug " buffer_prev got #{@current_buffer} "
|
127
|
+
set_current_buffer
|
128
|
+
end
|
129
|
+
def buffer_first
|
130
|
+
@current_buffer = @bmanager.first
|
131
|
+
$log.debug " buffer_first got #{@current_buffer} "
|
132
|
+
set_current_buffer
|
133
|
+
end
|
134
|
+
def buffer_last
|
135
|
+
@current_buffer = @bmanager.last
|
136
|
+
$log.debug " buffer_last got #{@current_buffer} "
|
137
|
+
set_current_buffer
|
138
|
+
end
|
139
|
+
def buffer_delete
|
140
|
+
if @bmanager.size > 1
|
141
|
+
@bmanager.delete_at
|
142
|
+
@current_buffer = @bmanager.previous
|
143
|
+
set_current_buffer
|
144
|
+
else
|
145
|
+
perror "Only one buffer. Cannot delete."
|
146
|
+
end
|
147
|
+
end
|
148
|
+
def buffers_list
|
149
|
+
menu = PromptMenu.new self
|
150
|
+
@bmanager.each_with_index{ |b, ix|
|
151
|
+
aproc = Proc.new { buffer_at(ix) }
|
152
|
+
name = b.title
|
153
|
+
num = ix + 1
|
154
|
+
menu.add(menu.create_mitem( num.to_s, name, "Switched to buffer #{ix}", aproc ))
|
155
|
+
}
|
156
|
+
menu.display @form.window, $error_message_row, $error_message_col, $datacolor
|
157
|
+
end
|
158
|
+
# prompts user for filename and opens in buffer
|
159
|
+
# Like vim's :e
|
160
|
+
def file_edit
|
161
|
+
file = getfilename()
|
162
|
+
$log.debug " got file_edit: #{file} "
|
163
|
+
return if file == ""
|
164
|
+
add file, file
|
165
|
+
end
|
166
|
+
# load a file into the textview.
|
167
|
+
# This is the preferred method since it lets us add a title too
|
168
|
+
# Shucks, this misses wrap_style which the other one has
|
169
|
+
# @param [String] filename
|
170
|
+
def add file, title
|
171
|
+
begin
|
172
|
+
@current_buffer = @bmanager.add file, title
|
173
|
+
$log.debug " file edit got cb : #{@current_buffer} "
|
174
|
+
set_current_buffer
|
175
|
+
rescue => err
|
176
|
+
alert err.to_s
|
177
|
+
Ncurses.beep
|
178
|
+
return -1
|
179
|
+
end
|
180
|
+
end
|
181
|
+
def buffer_at index
|
182
|
+
@current_buffer = @bmanager.element_at index
|
183
|
+
$log.debug " buffer_last got #{@current_buffer} "
|
184
|
+
set_current_buffer
|
185
|
+
end
|
186
|
+
def set_current_buffer
|
187
|
+
@current_index = @current_buffer.current_index
|
188
|
+
@curpos = @current_buffer.curpos
|
189
|
+
@title = @current_buffer.title
|
190
|
+
@list = @current_buffer.list
|
191
|
+
end
|
192
|
+
def perror errmess
|
193
|
+
#@form.window.print_error_message errmess
|
194
|
+
alert errmess
|
195
|
+
end
|
196
|
+
end # class multitextview
|
197
|
+
##
|
198
|
+
# Handles multiple buffers, navigation, maintenance etc
|
199
|
+
# Instantiated at startup of MultiTextView
|
200
|
+
#
|
201
|
+
class BufferManager
|
202
|
+
include Enumerable
|
203
|
+
def initialize source
|
204
|
+
@source = source
|
205
|
+
@buffers = [] # contains RBuffer
|
206
|
+
@counter = 0
|
207
|
+
# for each buffer i need to store data, current_index (row), curpos (col offset) and title (filename).
|
208
|
+
end
|
209
|
+
def element_at index
|
210
|
+
@buffers[index]
|
211
|
+
end
|
212
|
+
def each
|
213
|
+
@buffers.each {|k| yield(k)}
|
214
|
+
end
|
215
|
+
##
|
216
|
+
# @return [RBuffer] current buffer/file
|
217
|
+
##
|
218
|
+
def current
|
219
|
+
@buffers[@counter]
|
220
|
+
end
|
221
|
+
##
|
222
|
+
# Would have liked to just return next buffer and not get lost in details of caller
|
223
|
+
#
|
224
|
+
# @return [RBuffer] next buffer/file
|
225
|
+
##
|
226
|
+
def next
|
227
|
+
@counter += 1
|
228
|
+
@counter = 0 if @counter >= @buffers.size
|
229
|
+
@buffers[@counter]
|
230
|
+
end
|
231
|
+
##
|
232
|
+
# @return [RBuffer] previous buffer/file
|
233
|
+
##
|
234
|
+
def previous
|
235
|
+
$log.debug " previous bs: #{@buffers.size}, #{@counter} "
|
236
|
+
@counter -= 1
|
237
|
+
return last() if @counter < 0
|
238
|
+
$log.debug " previous ctr #{@counter} "
|
239
|
+
@buffers[@counter]
|
240
|
+
end
|
241
|
+
def first
|
242
|
+
@counter = 0
|
243
|
+
@buffers[@counter]
|
244
|
+
end
|
245
|
+
def last
|
246
|
+
@counter = @buffers.size - 1
|
247
|
+
@buffers[@counter]
|
248
|
+
end
|
249
|
+
##
|
250
|
+
def delete_at index=@counter
|
251
|
+
@buffers.delete_at index
|
252
|
+
end
|
253
|
+
def delete_by_name name
|
254
|
+
@buffers.delete_if {|b| b.filename == name }
|
255
|
+
end
|
256
|
+
def insert filename, position, title=nil
|
257
|
+
# read up file
|
258
|
+
lines = File.open(filename,"r").readlines
|
259
|
+
$log.debug "multitextview loaded #{filename}, #{lines.size} lines " if $log.debug?
|
260
|
+
list = @source.set_content lines
|
261
|
+
# set new RBuffer
|
262
|
+
title = filename unless title
|
263
|
+
raise "invalid value for list, Should be an array #{list.class} " unless list.is_a? Array
|
264
|
+
anew = RBuffer.new(list, 0, 0, filename, title)
|
265
|
+
#@buffers << anew
|
266
|
+
@buffers.insert position, anew
|
267
|
+
@counter = position
|
268
|
+
return anew
|
269
|
+
end
|
270
|
+
def add filename, title=nil
|
271
|
+
insert filename, @buffers.size, title
|
272
|
+
end
|
273
|
+
def insert_content str, position, title="UNTitled"
|
274
|
+
case str
|
275
|
+
when String
|
276
|
+
# put str into list
|
277
|
+
@source.set_content str
|
278
|
+
list = @list
|
279
|
+
when Array
|
280
|
+
list = str
|
281
|
+
end
|
282
|
+
anew = RBuffer.new(list, 0, 0, "", title)
|
283
|
+
#@buffers << anew
|
284
|
+
@buffers.insert position, anew
|
285
|
+
@counter = position
|
286
|
+
return anew
|
287
|
+
end
|
288
|
+
# add content (array or str) to buffer list as a new buffer
|
289
|
+
def add_content str, title="UNtitled"
|
290
|
+
$log.debug " inside BUFFER MANAGER "
|
291
|
+
insert_content str, @buffers.size, title
|
292
|
+
end
|
293
|
+
def size
|
294
|
+
@buffers.size
|
295
|
+
end
|
296
|
+
alias :count :size
|
297
|
+
def index buff
|
298
|
+
return @buffers.index
|
299
|
+
end
|
300
|
+
end
|
301
|
+
RBuffer = Struct.new(:list, :current_index, :curpos, :filename, :title) do
|
302
|
+
def xxx
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
end # modul
|
@@ -0,0 +1,755 @@
|
|
1
|
+
=begin
|
2
|
+
* Name: rpopupmenu - this is based on the crappy menubar code and needs a rewrite.
|
3
|
+
* Description
|
4
|
+
* Author: rkumar
|
5
|
+
TODO
|
6
|
+
- Action: may have to listen to Action property changes so enabled, name etc change can be reflected
|
7
|
+
- menu bar : what to do if adding a menu, or option later.
|
8
|
+
we dnt show disabld options in a way that user can know its disabled
|
9
|
+
- separate file created on 2008-12-24 17:58
|
10
|
+
|
11
|
+
Mnemonic should highlight the row if its a menu.
|
12
|
+
NOTE : this program works but is one of the first programs and is untouched. It needs to be rewritten
|
13
|
+
since its quite crappy.
|
14
|
+
Also, we should move to Action classes as against just blokcs of code. And action class would have
|
15
|
+
a user friendly string to identifiy the action, as well as a disabled option.
|
16
|
+
|
17
|
+
I am prefixing class names since they are same as those in rmenu and there's
|
18
|
+
some crashing happening when i first execcute rmenu in one app then rpopupmenu
|
19
|
+
in another.
|
20
|
+
|
21
|
+
--------
|
22
|
+
* Date: 2008-11-14 23:43
|
23
|
+
* License:
|
24
|
+
Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
25
|
+
|
26
|
+
=end
|
27
|
+
require 'logger'
|
28
|
+
require 'rbcurse'
|
29
|
+
require 'rbcurse/core/include/action'
|
30
|
+
|
31
|
+
#include Ncurses # FFI 2011-09-8
|
32
|
+
include RubyCurses
|
33
|
+
module RubyCurses
|
34
|
+
extend self
|
35
|
+
|
36
|
+
|
37
|
+
class PMenuSeparator
|
38
|
+
attr_accessor :enabled
|
39
|
+
attr_accessor :parent
|
40
|
+
attr_accessor :row
|
41
|
+
attr_accessor :col
|
42
|
+
attr_accessor :width
|
43
|
+
def initialize
|
44
|
+
@enable = false
|
45
|
+
end
|
46
|
+
def repaint
|
47
|
+
@parent.window.printstring( @row, 0, "|%s|" % ("-"*@width), $reversecolor)
|
48
|
+
end
|
49
|
+
def destroy
|
50
|
+
end
|
51
|
+
def on_enter
|
52
|
+
end
|
53
|
+
def on_leave
|
54
|
+
end
|
55
|
+
def to_s
|
56
|
+
""
|
57
|
+
end
|
58
|
+
end
|
59
|
+
##
|
60
|
+
class PMenuItem
|
61
|
+
attr_accessor :parent
|
62
|
+
# attr_accessor :window
|
63
|
+
attr_accessor :row
|
64
|
+
attr_accessor :col
|
65
|
+
attr_accessor :width
|
66
|
+
attr_accessor :accelerator
|
67
|
+
attr_accessor :enabled
|
68
|
+
attr_accessor :mnemonic # changed reader to accessor
|
69
|
+
def initialize txt, mnemonic=nil, &block
|
70
|
+
@mnemonic = mnemonic
|
71
|
+
text txt
|
72
|
+
@enabled = true
|
73
|
+
instance_eval &block if block_given?
|
74
|
+
end
|
75
|
+
##
|
76
|
+
# changed so ampersand can be mnemonic esp when action comes in
|
77
|
+
def text s
|
78
|
+
s = s.dup # since actions are being shared
|
79
|
+
if (( ix = s.index('&')) != nil)
|
80
|
+
s.slice!(ix,1)
|
81
|
+
#@underline = ix unless @form.nil? # this setting a fake underline in messageboxes
|
82
|
+
@mnemonic = s[ix,1]
|
83
|
+
end
|
84
|
+
@text = s
|
85
|
+
end
|
86
|
+
def to_s
|
87
|
+
"#{@text} #{@accelerator}"
|
88
|
+
end
|
89
|
+
def command *args, &block
|
90
|
+
$log.debug ">>>command : #{@text} "
|
91
|
+
@command = block if block_given?
|
92
|
+
@args = args
|
93
|
+
end
|
94
|
+
def on_enter
|
95
|
+
$log.debug ">>>on enter Pmenuitem : #{@text} #{@row} #{@width} "
|
96
|
+
highlight
|
97
|
+
end
|
98
|
+
def on_leave
|
99
|
+
$log.debug ">>>on leave Pmenuitem : #{@text} "
|
100
|
+
highlight false
|
101
|
+
end
|
102
|
+
## XXX it could be a menu again
|
103
|
+
def fire
|
104
|
+
$log.debug ">>>fire Pmenuitem : #{@text} #{@command} "
|
105
|
+
@command.call self, *@args if !@command.nil?
|
106
|
+
@parent.clear_menus
|
107
|
+
return :CLOSE # added 2009-01-02 00:09 to close only actions, not submenus
|
108
|
+
end
|
109
|
+
def highlight tf=true
|
110
|
+
if tf
|
111
|
+
color = $datacolor
|
112
|
+
#@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_NORMAL, color, nil)
|
113
|
+
# above line did not work in vt100, 200 terminals, next works.
|
114
|
+
@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_REVERSE, $reversecolor, nil)
|
115
|
+
else
|
116
|
+
repaint
|
117
|
+
end
|
118
|
+
@parent.window.wrefresh
|
119
|
+
end
|
120
|
+
def repaint # menuitem.repaint
|
121
|
+
if @parent.nil? or @parent.window.nil?
|
122
|
+
$log.debug " #{self} parent nil"
|
123
|
+
return
|
124
|
+
end
|
125
|
+
r = @row
|
126
|
+
acolor = $reversecolor
|
127
|
+
acolor = get_color($reversecolor, 'green', 'white') if !@enabled
|
128
|
+
@parent.window.printstring( @row, 0, "|%-*s|" % [@width, @text], acolor)
|
129
|
+
if !@accelerator.nil?
|
130
|
+
@parent.window.printstring( r, (@width+1)-@accelerator.length, @accelerator, acolor)
|
131
|
+
else
|
132
|
+
#@parent.window.printstring( r, (@width+1)-1, ".", acolor)
|
133
|
+
end
|
134
|
+
if !@mnemonic.nil?
|
135
|
+
m = @mnemonic
|
136
|
+
ix = @text.index(m) || @text.index(m.swapcase)
|
137
|
+
charm = @text[ix,1]
|
138
|
+
#@parent.window.printstring( r, ix+1, charm, $datacolor) if !ix.nil?
|
139
|
+
# prev line changed since not working in vt100 and vt200
|
140
|
+
#@parent.window.printstring( r, ix+1, charm, $reversecolor, 'reverse') if !ix.nil?
|
141
|
+
@parent.window.mvchgat(y=r, x=ix+1, max=1, Ncurses::A_BOLD|Ncurses::A_UNDERLINE, acolor, nil)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
def destroy
|
145
|
+
$log.debug "DESTRY menuitem #{@text}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
class PMenu < PMenuItem
|
149
|
+
attr_accessor :parent
|
150
|
+
attr_accessor :row
|
151
|
+
attr_accessor :col
|
152
|
+
attr_accessor :width
|
153
|
+
attr_accessor :enabled
|
154
|
+
#attr_reader :text
|
155
|
+
attr_reader :items
|
156
|
+
attr_reader :window
|
157
|
+
attr_reader :panel
|
158
|
+
attr_reader :current_menu
|
159
|
+
attr_reader :row_margin
|
160
|
+
@@menus = []
|
161
|
+
@@row = 0
|
162
|
+
@@col = 0
|
163
|
+
|
164
|
+
def initialize text, &block
|
165
|
+
super text, nil, &block
|
166
|
+
@items = []
|
167
|
+
@enabled = true
|
168
|
+
@current_menu = []
|
169
|
+
instance_eval &block if block_given?
|
170
|
+
@row ||=10
|
171
|
+
@col ||=10
|
172
|
+
@@menus ||= []
|
173
|
+
end
|
174
|
+
def to_s
|
175
|
+
@text
|
176
|
+
end
|
177
|
+
def clear_menus
|
178
|
+
@@menus = []
|
179
|
+
end
|
180
|
+
# create a Menuitem given an Action
|
181
|
+
# if menuitem.kind_of? RubyCurses::Action
|
182
|
+
def create_action_component action
|
183
|
+
m = PMenuItem.new(action.name, action.mnemonic)
|
184
|
+
m.command { action.call }
|
185
|
+
m.accelerator = action.accelerator
|
186
|
+
return m
|
187
|
+
end
|
188
|
+
# item could be menuitem or another menu or a string or a Action
|
189
|
+
# support for action added 2009-01-21 18:08
|
190
|
+
def add menuitem
|
191
|
+
insert menuitem, @items.size
|
192
|
+
return self
|
193
|
+
end
|
194
|
+
##
|
195
|
+
# added 2009-01-20 13:28 NEW
|
196
|
+
def insert menuitem, ix
|
197
|
+
if menuitem.kind_of? RubyCurses::Action
|
198
|
+
menuitem = create_action_component menuitem
|
199
|
+
end
|
200
|
+
@items.insert ix, menuitem
|
201
|
+
return self
|
202
|
+
end
|
203
|
+
def insert_separator ix
|
204
|
+
@items.insert ix, PMenuSeparator.new
|
205
|
+
end
|
206
|
+
def add_separator
|
207
|
+
@items << PMenuSeparator.new
|
208
|
+
end
|
209
|
+
def get_item i
|
210
|
+
@items[i]
|
211
|
+
end
|
212
|
+
def remove n
|
213
|
+
if n.is_a? Fixnum
|
214
|
+
@items.delete_at n
|
215
|
+
else
|
216
|
+
@items.delete n
|
217
|
+
end
|
218
|
+
end
|
219
|
+
# menu -
|
220
|
+
def fire
|
221
|
+
$log.debug "menu fire called: #{@text} "
|
222
|
+
if @window.nil?
|
223
|
+
#repaint
|
224
|
+
create_window
|
225
|
+
if !@parent.is_a? RubyCurses::PMenuBar
|
226
|
+
$log.debug " ADDING self to current menu: #{self}"
|
227
|
+
# xxx highlight true
|
228
|
+
@parent.current_menu << self
|
229
|
+
@@menus << self
|
230
|
+
|
231
|
+
$log.debug "DDD #{@@menus} << #{self}"
|
232
|
+
end
|
233
|
+
else
|
234
|
+
### shouod this not just show ?
|
235
|
+
$log.debug "menu fire called: #{@text} ELSE XXX WHEN IS THIS CALLED ? 658 "
|
236
|
+
return @items[@active_index].fire # this should happen if selected. else selected()
|
237
|
+
end
|
238
|
+
#@action.call if !@action.nil?
|
239
|
+
end
|
240
|
+
# user has clicked down, we shoud display items
|
241
|
+
# DRAW menuitems
|
242
|
+
def repaint # menu.repaint
|
243
|
+
return if @items.nil? or @items.empty?
|
244
|
+
$log.debug "menu repaint: #{@text} row #{@row} col #{@col} "
|
245
|
+
if !@parent.is_a? RubyCurses::PMenuBar
|
246
|
+
@parent.window.printstring( @row, 0, "|%-*s>|" % [@width-1, @text], $reversecolor)
|
247
|
+
# added 2009-01-23 00:49
|
248
|
+
if !@mnemonic.nil?
|
249
|
+
m = @mnemonic
|
250
|
+
ix = @text.index(m) || @text.index(m.swapcase)
|
251
|
+
charm = @text[ix,1]
|
252
|
+
#@parent.window.printstring( r, ix+1, charm, $datacolor) if !ix.nil?
|
253
|
+
# prev line changed since not working in vt100 and vt200
|
254
|
+
#@parent.window.printstring( @row, ix+1, charm, $reversecolor, 'reverse') if !ix.nil?
|
255
|
+
# 2009-01-23 13:03 replaced reverse with ul
|
256
|
+
@parent.window.mvchgat(y=@row, x=ix+1, max=1, Ncurses::A_BOLD|Ncurses::A_UNDERLINE, $reversecolor, nil)
|
257
|
+
end
|
258
|
+
@parent.window.refresh
|
259
|
+
end
|
260
|
+
if @window.nil?
|
261
|
+
#create_window
|
262
|
+
else
|
263
|
+
@window.show
|
264
|
+
select_item 0
|
265
|
+
@window.refresh
|
266
|
+
end
|
267
|
+
end
|
268
|
+
##
|
269
|
+
# recursive if given one not enabled goes to next enabled
|
270
|
+
def select_item ix0
|
271
|
+
return if @items.nil? or @items.empty?
|
272
|
+
$log.debug "insdie select item : #{ix0}"
|
273
|
+
if !@active_index.nil?
|
274
|
+
@items[@active_index].on_leave
|
275
|
+
end
|
276
|
+
previtem = @active_index
|
277
|
+
@active_index = ix0
|
278
|
+
if @items[ix0].enabled
|
279
|
+
@items[ix0].on_enter
|
280
|
+
else
|
281
|
+
$log.debug "insdie sele nxt item ENABLED FALSE : #{ix0}"
|
282
|
+
if @active_index > previtem
|
283
|
+
select_next_item
|
284
|
+
else
|
285
|
+
select_prev_item
|
286
|
+
end
|
287
|
+
end
|
288
|
+
@window.refresh
|
289
|
+
end
|
290
|
+
def select_next_item
|
291
|
+
return if @items.nil? or @items.empty?
|
292
|
+
$log.debug "insdie sele nxt item : #{@active_index}"
|
293
|
+
@active_index = -1 if @active_index.nil?
|
294
|
+
if @active_index < @items.length-1
|
295
|
+
select_item @active_index + 1
|
296
|
+
else
|
297
|
+
# select_item 0
|
298
|
+
end
|
299
|
+
end
|
300
|
+
def select_prev_item
|
301
|
+
return if @items.nil? or @items.empty?
|
302
|
+
$log.debug "insdie sele prv item : #{@active_index}"
|
303
|
+
if @active_index > 0
|
304
|
+
select_item @active_index - 1
|
305
|
+
else
|
306
|
+
#select_item @items.length-1
|
307
|
+
end
|
308
|
+
end
|
309
|
+
def on_enter # menu.on_enter
|
310
|
+
$log.debug "menu onenter: #{@text} #{@row} #{@col} "
|
311
|
+
# call parent method. XXX
|
312
|
+
if @parent.is_a? RubyCurses::PMenuBar
|
313
|
+
@parent.window.printstring( @row, @col, " %s " % @text, $datacolor)
|
314
|
+
else
|
315
|
+
highlight
|
316
|
+
end
|
317
|
+
if !@window.nil? #and @parent.selected
|
318
|
+
$log.debug "menu onenter: #{@text} calling window,show"
|
319
|
+
@window.show
|
320
|
+
select_item 0
|
321
|
+
elsif @parent.is_a? RubyCurses::PMenuBar and @parent.selected
|
322
|
+
# only on the top level do we open a window if a previous one was opened
|
323
|
+
$log.debug "menu onenter: #{@text} calling repaint CLASS: #{@parent.class}"
|
324
|
+
# repaint
|
325
|
+
create_window
|
326
|
+
end
|
327
|
+
end
|
328
|
+
def on_leave # menu.on_leave
|
329
|
+
$log.debug "menu onleave: #{@text} #{@row} #{@col} "
|
330
|
+
# call parent method. XXX
|
331
|
+
if @parent.is_a? RubyCurses::PMenuBar
|
332
|
+
@parent.window.printstring( @row, @col, " %s " % @text, $reversecolor)
|
333
|
+
@window.hide if !@window.nil?
|
334
|
+
else
|
335
|
+
$log.debug "MENU SUBMEN. menu onleave: #{@text} #{@row} #{@col} will pop !! "
|
336
|
+
# parent is a menu
|
337
|
+
highlight false
|
338
|
+
#@parent.current_menu.pop
|
339
|
+
#@@menus.pop
|
340
|
+
#destroy
|
341
|
+
end
|
342
|
+
end
|
343
|
+
def highlight tf=true # menu
|
344
|
+
$log.debug "MENU SUBMENU menu highlight: #{@text} #{@row} #{@col}, PW #{@parent.width} "
|
345
|
+
color = tf ? $datacolor : $reversecolor
|
346
|
+
att = tf ? Ncurses::A_REVERSE : Ncurses::A_NORMAL
|
347
|
+
#@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_NORMAL, color, nil)
|
348
|
+
#@parent.window.mvchgat(y=@row, x=1, @parent.width, Ncurses::A_NORMAL, color, nil)
|
349
|
+
# above line did not work with vt100/vt200 next does
|
350
|
+
@parent.window.mvchgat(y=@row, x=1, @parent.width, att, $reversecolor, nil)
|
351
|
+
@parent.window.wrefresh
|
352
|
+
end
|
353
|
+
def create_window # menu XXX
|
354
|
+
margin = 3
|
355
|
+
@width = array_width @items
|
356
|
+
$log.debug "create window menu #{@text}: #{@row} ,#{@col},parent: #{@parent}, wd #{@width} "
|
357
|
+
#$log.debug "create window menu parent: #{@parent.row}, " unless @parent.nil?
|
358
|
+
@row_margin = 1 #+ @@row
|
359
|
+
@row_margin = @parent.row+@parent.row_margin unless @parent.nil?
|
360
|
+
#@row = @parent.row unless @parent.nil?
|
361
|
+
@layout = { :height => @items.length+3, :width => @width+margin, :top => @row+@row_margin, :left => @col }
|
362
|
+
@win = VER::Window.new(@layout)
|
363
|
+
@window = @win
|
364
|
+
@win.bkgd(Ncurses.COLOR_PAIR($datacolor));
|
365
|
+
@panel = @win.panel
|
366
|
+
@window.printstring( 0, 0, "+%s+" % ("-"*@width), $reversecolor)
|
367
|
+
r = 1
|
368
|
+
@items.each do |item|
|
369
|
+
item.row = r
|
370
|
+
item.col = 0
|
371
|
+
item.col = @col+@width+margin # margins???
|
372
|
+
item.width = @width
|
373
|
+
#item.window = @window
|
374
|
+
item.parent = self
|
375
|
+
item.repaint
|
376
|
+
#end
|
377
|
+
r+=1
|
378
|
+
end
|
379
|
+
@window.printstring( r, 0, "+%s+" % ("-"*@width), $reversecolor)
|
380
|
+
select_item 0
|
381
|
+
@window.refresh
|
382
|
+
return @window
|
383
|
+
end
|
384
|
+
# private
|
385
|
+
def array_width a
|
386
|
+
longest = a.max {|a,b| a.to_s.length <=> b.to_s.length }
|
387
|
+
$log.debug "array width #{longest}"
|
388
|
+
longest.to_s.length
|
389
|
+
end
|
390
|
+
def destroy
|
391
|
+
$log.debug "DESTRY menu #{@text}"
|
392
|
+
return if @window.nil?
|
393
|
+
@visible = false
|
394
|
+
panel = @window.panel
|
395
|
+
Ncurses::Panel.del_panel(panel.pointer) if !panel.nil?
|
396
|
+
@window.delwin if !@window.nil? # FFI
|
397
|
+
@items.each do |item|
|
398
|
+
#next if item == :SEPARATOR
|
399
|
+
item.destroy
|
400
|
+
end
|
401
|
+
@window = nil
|
402
|
+
end
|
403
|
+
# menu LEFT, RIGHT, DOWN, UP, ENTER
|
404
|
+
# item could be Pmenuitem or another menu
|
405
|
+
#
|
406
|
+
def handle_key ch
|
407
|
+
#if !@current_menu.empty?
|
408
|
+
# cmenu = @current_menu.last
|
409
|
+
#else
|
410
|
+
# cmenu = self
|
411
|
+
#end
|
412
|
+
if !@@menus.empty?
|
413
|
+
cmenu = @@menus.last
|
414
|
+
else
|
415
|
+
cmenu = self
|
416
|
+
end
|
417
|
+
$log.debug " CMENU is #{cmenu}: #{@@menus} "
|
418
|
+
case ch
|
419
|
+
when KEY_DOWN
|
420
|
+
cmenu.select_next_item
|
421
|
+
when KEY_UP
|
422
|
+
cmenu.select_prev_item
|
423
|
+
when KEY_ENTER, 10, 13, 32 # added 32 2008-11-28 23:50
|
424
|
+
return cmenu.fire
|
425
|
+
when KEY_LEFT
|
426
|
+
if cmenu.parent.is_a? RubyCurses::PMenu
|
427
|
+
$log.debug "LEFT IN MENU : #{cmenu.parent.class} len: #{cmenu.parent.current_menu.length}"
|
428
|
+
$log.debug "left IN MENU : #{cmenu.parent.class} len: #{cmenu.current_menu.length}"
|
429
|
+
end
|
430
|
+
if cmenu.parent.is_a? RubyCurses::PMenu and !cmenu.parent.current_menu.empty?
|
431
|
+
$log.debug " ABOU TO DESTROY DUE TO LEFT"
|
432
|
+
cmenu.parent.current_menu.pop
|
433
|
+
@@menus.pop
|
434
|
+
cmenu.destroy
|
435
|
+
else
|
436
|
+
$log.debug " returning UNHANDLED 370"
|
437
|
+
return :UNHANDLED
|
438
|
+
end
|
439
|
+
when KEY_RIGHT
|
440
|
+
$log.debug "RIGHTIN MENU : "
|
441
|
+
if cmenu.parent.is_a? RubyCurses::PMenu
|
442
|
+
$log.debug "right IN MENU : #{cmenu.parent.class} len: #{cmenu.parent.current_menu.length}"
|
443
|
+
$log.debug "right IN MENU : #{cmenu.parent.class} len: #{cmenu.current_menu.length}"
|
444
|
+
end
|
445
|
+
if cmenu.parent.is_a? RubyCurses::PMenu and !cmenu.parent.current_menu.empty?
|
446
|
+
$log.debug " ABOU TO DESTROY DUE TO RIGHT"
|
447
|
+
cmenu.parent.current_menu.pop
|
448
|
+
@@menus.pop
|
449
|
+
cmenu.destroy
|
450
|
+
end
|
451
|
+
return :UNHANDLED
|
452
|
+
else
|
453
|
+
ret = check_mnemonics cmenu, ch
|
454
|
+
return ret
|
455
|
+
end
|
456
|
+
end
|
457
|
+
##
|
458
|
+
# checks given key against current menu's items and fires key if
|
459
|
+
# added on 2008-11-27 12:07
|
460
|
+
def check_mnemonics cmenu, ch
|
461
|
+
# $log.debug "inside check_mnemonics #{ch}"
|
462
|
+
key = ch.chr.downcase rescue ""
|
463
|
+
cmenu.items.each_with_index do |item, ix|
|
464
|
+
next if !item.respond_to? :mnemonic or item.mnemonic.nil?
|
465
|
+
# $log.debug "inside check_mnemonics #{item.mnemonic}"
|
466
|
+
if key == item.mnemonic.downcase
|
467
|
+
cmenu.select_item ix # 2009-01-23 13:32 so focus moves to menu
|
468
|
+
ret = item.fire
|
469
|
+
return ret # 0 # 2009-01-23 00:43 Pmenuitem returns CLOSE, menu 0
|
470
|
+
end
|
471
|
+
end
|
472
|
+
return :UNHANDLED
|
473
|
+
end
|
474
|
+
## menu
|
475
|
+
def show # menu.show
|
476
|
+
$log.debug "show (menu) : #{@text} "
|
477
|
+
if @window.nil?
|
478
|
+
create_window
|
479
|
+
end
|
480
|
+
@window.show
|
481
|
+
select_item 0
|
482
|
+
end
|
483
|
+
end
|
484
|
+
class PopupMenu < PMenu
|
485
|
+
def initialize text, &block
|
486
|
+
@row_margin = 0
|
487
|
+
@@row = 0
|
488
|
+
@@col = 0
|
489
|
+
super
|
490
|
+
instance_eval &block if block_given?
|
491
|
+
end
|
492
|
+
def show component, x, y
|
493
|
+
@component = component
|
494
|
+
@@row = component.row
|
495
|
+
@@col = component.col
|
496
|
+
create_window
|
497
|
+
handle_keys
|
498
|
+
end
|
499
|
+
def handle_keys # popup
|
500
|
+
@toggle_key ||= 27 # default switch off with ESC, if nothing else defined
|
501
|
+
begin
|
502
|
+
catch(:menubarclose) do
|
503
|
+
while((ch = @window.getchar()) != @toggle_key )
|
504
|
+
case ch
|
505
|
+
when -1
|
506
|
+
next
|
507
|
+
else
|
508
|
+
ret = handle_key ch
|
509
|
+
$log.debug " POPUP got #{ret} added 2009-01-21 18:18 "
|
510
|
+
break if ret == :CLOSE
|
511
|
+
end
|
512
|
+
Ncurses::Panel.update_panels();
|
513
|
+
Ncurses.doupdate();
|
514
|
+
|
515
|
+
@window.wrefresh
|
516
|
+
end
|
517
|
+
end # catch
|
518
|
+
ensure
|
519
|
+
#ensure is required becos one can throw a :close
|
520
|
+
@@menus = [] # added 2009-01-23 13:21
|
521
|
+
destroy # Note that we destroy the menu bar upon exit
|
522
|
+
end
|
523
|
+
end
|
524
|
+
def destroy
|
525
|
+
$log.debug "DESTRY popup "
|
526
|
+
@visible = false
|
527
|
+
panel = @window.panel
|
528
|
+
Ncurses::Panel.del_panel(panel.pointer) if !panel.nil?
|
529
|
+
@window.delwin if !@window.nil? # FFI
|
530
|
+
@items.each do |item|
|
531
|
+
item.destroy
|
532
|
+
end
|
533
|
+
@window = nil
|
534
|
+
end
|
535
|
+
end # class
|
536
|
+
##
|
537
|
+
# An application related menubar.
|
538
|
+
# Currently, I am adding this to a form. But should this not be application specific ?
|
539
|
+
# It should popup no matter which window you are on ?? XXX
|
540
|
+
class PMenuBar
|
541
|
+
attr_reader :items
|
542
|
+
attr_reader :window
|
543
|
+
attr_reader :panel
|
544
|
+
attr_reader :selected
|
545
|
+
attr_accessor :visible
|
546
|
+
attr_accessor :active_index
|
547
|
+
attr_accessor :state # normal, selected, highlighted
|
548
|
+
attr_accessor :toggle_key # key used to popup, should be set prior to attaching to form
|
549
|
+
def initialize &block
|
550
|
+
@window = nil
|
551
|
+
@active_index = 0
|
552
|
+
@items = []
|
553
|
+
@visible = false
|
554
|
+
@cols = Ncurses.COLS-1
|
555
|
+
instance_eval &block if block_given?
|
556
|
+
end
|
557
|
+
def focusable
|
558
|
+
false
|
559
|
+
end
|
560
|
+
def add menu
|
561
|
+
@items << menu
|
562
|
+
return self
|
563
|
+
end
|
564
|
+
def next_menu
|
565
|
+
$log.debug "next meu: #{@active_index} "
|
566
|
+
if @active_index < @items.length-1
|
567
|
+
set_menu @active_index + 1
|
568
|
+
else
|
569
|
+
set_menu 0
|
570
|
+
end
|
571
|
+
end
|
572
|
+
def prev_menu
|
573
|
+
$log.debug "prev meu: #{@active_index} "
|
574
|
+
if @active_index > 0
|
575
|
+
set_menu @active_index-1
|
576
|
+
else
|
577
|
+
set_menu @items.length-1
|
578
|
+
end
|
579
|
+
end
|
580
|
+
def set_menu index
|
581
|
+
$log.debug "set meu: #{@active_index} #{index}"
|
582
|
+
menu = @items[@active_index]
|
583
|
+
menu.on_leave # hide its window, if open
|
584
|
+
@active_index = index
|
585
|
+
menu = @items[@active_index]
|
586
|
+
menu.on_enter #display window, if previous was displayed
|
587
|
+
@window.wmove menu.row, menu.col
|
588
|
+
# menu.show
|
589
|
+
# menu.window.wrefresh # XXX we need this
|
590
|
+
end
|
591
|
+
# menubar LEFT, RIGHT, DOWN
|
592
|
+
def handle_keys
|
593
|
+
@selected = false
|
594
|
+
@toggle_key ||= 27 # default switch off with ESC, if nothing else defined
|
595
|
+
set_menu 0
|
596
|
+
begin
|
597
|
+
catch(:popupclose) do
|
598
|
+
while((ch = @window.getchar()) != @toggle_key )
|
599
|
+
$log.debug "menuubar inside handle_keys : #{ch}" if ch != -1
|
600
|
+
case ch
|
601
|
+
when -1
|
602
|
+
next
|
603
|
+
when KEY_DOWN
|
604
|
+
$log.debug "insdie keyDOWN : #{ch}"
|
605
|
+
if !@selected
|
606
|
+
current_menu.fire
|
607
|
+
else
|
608
|
+
current_menu.handle_key ch
|
609
|
+
end
|
610
|
+
|
611
|
+
@selected = true
|
612
|
+
when KEY_ENTER, 10, 13, 32
|
613
|
+
@selected = true
|
614
|
+
$log.debug " mb insdie ENTER : #{current_menu}"
|
615
|
+
ret = current_menu.handle_key ch
|
616
|
+
$log.debug "ret = #{ret} mb insdie ENTER : #{current_menu}"
|
617
|
+
#break; ## 2008-12-29 18:00 This will close after firing
|
618
|
+
#anything
|
619
|
+
break if ret == :CLOSE
|
620
|
+
when KEY_UP
|
621
|
+
$log.debug " mb insdie keyUPP : #{ch}"
|
622
|
+
current_menu.handle_key ch
|
623
|
+
when KEY_LEFT
|
624
|
+
$log.debug " mb insdie KEYLEFT : #{ch}"
|
625
|
+
ret = current_menu.handle_key ch
|
626
|
+
prev_menu if ret == :UNHANDLED
|
627
|
+
#display_items if @selected
|
628
|
+
when KEY_RIGHT
|
629
|
+
$log.debug " mb insdie KEYRIGHT : #{ch}"
|
630
|
+
ret = current_menu.handle_key ch
|
631
|
+
next_menu if ret == :UNHANDLED
|
632
|
+
else
|
633
|
+
$log.debug " mb insdie ELSE : #{ch}"
|
634
|
+
ret = current_menu.handle_key ch
|
635
|
+
if ret == :UNHANDLED
|
636
|
+
Ncurses.beep
|
637
|
+
else
|
638
|
+
break # we handled a menu action, close menubar (THIS WORKS FOR MNEMONICS ONLY and always)
|
639
|
+
end
|
640
|
+
end
|
641
|
+
Ncurses::Panel.update_panels();
|
642
|
+
Ncurses.doupdate();
|
643
|
+
|
644
|
+
@window.wrefresh
|
645
|
+
end
|
646
|
+
end # catch
|
647
|
+
ensure
|
648
|
+
#ensure is required becos one can throw a :close
|
649
|
+
destroy # Note that we destroy the menu bar upon exit
|
650
|
+
end
|
651
|
+
end
|
652
|
+
def current_menu
|
653
|
+
@items[@active_index]
|
654
|
+
end
|
655
|
+
def toggle
|
656
|
+
@visible = !@visible
|
657
|
+
if !@visible
|
658
|
+
hide
|
659
|
+
else
|
660
|
+
show
|
661
|
+
end
|
662
|
+
end
|
663
|
+
def hide
|
664
|
+
@visible = false
|
665
|
+
@window.hide if !@window.nil?
|
666
|
+
end
|
667
|
+
def show
|
668
|
+
@visible = true
|
669
|
+
if @window.nil?
|
670
|
+
repaint # XXX FIXME
|
671
|
+
else
|
672
|
+
@window.show
|
673
|
+
end
|
674
|
+
end
|
675
|
+
## menubar
|
676
|
+
def repaint
|
677
|
+
return if !@visible
|
678
|
+
@window ||= create_window
|
679
|
+
@window.printstring( 0, 0, "%-*s" % [@cols," "], $reversecolor)
|
680
|
+
c = 1; r = 0;
|
681
|
+
@items.each do |item|
|
682
|
+
item.row = r; item.col = c; item.parent = self
|
683
|
+
@window.printstring( r, c, " %s " % item.text, $reversecolor)
|
684
|
+
c += (item.text.length + 2)
|
685
|
+
end
|
686
|
+
@window.wrefresh
|
687
|
+
end
|
688
|
+
def create_window
|
689
|
+
@layout = { :height => 1, :width => 0, :top => 0, :left => 0 }
|
690
|
+
@win = VER::Window.new(@layout)
|
691
|
+
@window = @win
|
692
|
+
@win.bkgd(Ncurses.COLOR_PAIR(5));
|
693
|
+
@panel = @win.panel
|
694
|
+
return @window
|
695
|
+
end
|
696
|
+
def destroy
|
697
|
+
$log.debug "DESTRY menubar "
|
698
|
+
@visible = false
|
699
|
+
panel = @window.panel
|
700
|
+
Ncurses::Panel.del_panel(panel.pointer) if !panel.nil?
|
701
|
+
@window.delwin if !@window.nil?
|
702
|
+
@items.each do |item|
|
703
|
+
item.destroy
|
704
|
+
end
|
705
|
+
@window = nil
|
706
|
+
end
|
707
|
+
end # menubar
|
708
|
+
|
709
|
+
class PCheckBoxMenuItem < PMenuItem
|
710
|
+
attr_reader :checkbox
|
711
|
+
def initialize text, mnemonic=nil, &block
|
712
|
+
@checkbox = CheckBox.new nil
|
713
|
+
@checkbox.text text
|
714
|
+
super
|
715
|
+
end
|
716
|
+
def onvalue
|
717
|
+
@checkbox.onvalue onvalue
|
718
|
+
end
|
719
|
+
def offvalue
|
720
|
+
@checkbox.onvalue offvalue
|
721
|
+
end
|
722
|
+
def text=(t) # stack level too deep if no = .????
|
723
|
+
@checkbox.text t
|
724
|
+
end
|
725
|
+
## added @ with text, else crashing on testmenu.rb
|
726
|
+
def to_s
|
727
|
+
" #{@text} "
|
728
|
+
end
|
729
|
+
def getvalue
|
730
|
+
checkbox.getvalue
|
731
|
+
end
|
732
|
+
def getvalue_for_paint
|
733
|
+
"|%-*s|" % [@width, checkbox.getvalue_for_paint]
|
734
|
+
end
|
735
|
+
def fire
|
736
|
+
checkbox.toggle
|
737
|
+
super
|
738
|
+
repaint
|
739
|
+
highlight true
|
740
|
+
end
|
741
|
+
def repaint
|
742
|
+
@parent.window.printstring( row, 0, getvalue_for_paint, $reversecolor)
|
743
|
+
parent.window.wrefresh
|
744
|
+
end
|
745
|
+
def method_missing(sym, *args)
|
746
|
+
if checkbox.respond_to? sym
|
747
|
+
$log.debug("calling CHECKBOXMENU #{sym} called #{args[0]}")
|
748
|
+
checkbox.send(sym, args)
|
749
|
+
else
|
750
|
+
$log.error("ERROR CHECKBOXMENU #{sym} called")
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
754
|
+
end
|
755
|
+
end # modul
|