ncumbra 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +48 -0
- data/README.md.bak +15 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/ex1.rb +85 -0
- data/examples/ex2.rb +128 -0
- data/examples/ex21.rb +136 -0
- data/examples/ex3.rb +163 -0
- data/examples/ex4.rb +142 -0
- data/examples/ex5.rb +103 -0
- data/examples/exbox.rb +141 -0
- data/examples/exm1.rb +137 -0
- data/examples/keys.rb +67 -0
- data/examples/tt.rb +462 -0
- data/lib/umbra/box.rb +137 -0
- data/lib/umbra/button.rb +130 -0
- data/lib/umbra/buttongroup.rb +96 -0
- data/lib/umbra/checkbox.rb +42 -0
- data/lib/umbra/dialog.rb +214 -0
- data/lib/umbra/eventhandler.rb +134 -0
- data/lib/umbra/field.rb +503 -0
- data/lib/umbra/form.rb +473 -0
- data/lib/umbra/keymappinghandler.rb +96 -0
- data/lib/umbra/label.rb +95 -0
- data/lib/umbra/labeledfield.rb +97 -0
- data/lib/umbra/listbox.rb +384 -0
- data/lib/umbra/menu.rb +93 -0
- data/lib/umbra/messagebox.rb +348 -0
- data/lib/umbra/pad.rb +340 -0
- data/lib/umbra/radiobutton.rb +71 -0
- data/lib/umbra/textbox.rb +417 -0
- data/lib/umbra/togglebutton.rb +140 -0
- data/lib/umbra/version.rb +3 -0
- data/lib/umbra/widget.rb +220 -0
- data/lib/umbra/window.rb +270 -0
- data/lib/umbra.rb +47 -0
- data/umbra.gemspec +27 -0
- metadata +127 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
# ----------------------------------------------------------------------------- #
|
2
|
+
# File: radiobutton.rb
|
3
|
+
# Description: a member of a group of buttons, only one can be selected at a time.
|
4
|
+
# Author: j kepler http://github.com/mare-imbrium/canis/
|
5
|
+
# Date: 2018-04-02 - 10:37
|
6
|
+
# License: MIT
|
7
|
+
# Last update: 2018-04-03 14:22
|
8
|
+
# ----------------------------------------------------------------------------- #
|
9
|
+
# radiobutton.rb Copyright (C) 2012-2018 j kepler
|
10
|
+
|
11
|
+
module Umbra
|
12
|
+
##
|
13
|
+
# A selectable button that has a text value. It is based on a Variable that
|
14
|
+
# is shared by other radio buttons. Only one is selected at a time, unlike checkbox
|
15
|
+
# +text+ is the value to display, which can include an ampersand for a hotkey
|
16
|
+
# +value+ is the value returned if selected, which usually is similar to text (or a short word)
|
17
|
+
# +width+ is helpful if placing the brackets to right of text, used to align round brackets
|
18
|
+
# By default, radio buttons place the button on the left of the text.
|
19
|
+
#
|
20
|
+
# Typically, the variable's update_command is passed a block to execute whenever any of the
|
21
|
+
# radiobuttons of this group is fired.
|
22
|
+
|
23
|
+
class RadioButton < ToggleButton
|
24
|
+
attr_accessor :align_right # the button will be on the right
|
25
|
+
attr_accessor :button_group # group that this button belongs to.
|
26
|
+
|
27
|
+
def initialize config={}, &block
|
28
|
+
@surround_chars = ['(', ')'] if @surround_chars.nil?
|
29
|
+
super
|
30
|
+
$log.warn "XXX: FIXME Please set 'value' for radiobutton. If not sure, try setting it to the same value as 'text'" unless @value
|
31
|
+
@value ||= @text
|
32
|
+
end
|
33
|
+
|
34
|
+
# all radio buttons will return the value of the selected value, not the offered value
|
35
|
+
def getvalue
|
36
|
+
@button_group.value
|
37
|
+
end
|
38
|
+
|
39
|
+
def getvalue_for_paint
|
40
|
+
buttontext = getvalue() == @value ? "o" : " "
|
41
|
+
$log.debug "called get_value_for paint for buttong #{@value} :#{buttontext} "
|
42
|
+
dtext = @width.nil? ? text : "%-*s" % [@width, text]
|
43
|
+
if @align_right
|
44
|
+
@text_offset = 0
|
45
|
+
@col_offset = dtext.length + @surround_chars[0].length + 1
|
46
|
+
return "#{dtext} " + @surround_chars[0] + buttontext + @surround_chars[1]
|
47
|
+
else
|
48
|
+
pretext = @surround_chars[0] + buttontext + @surround_chars[1]
|
49
|
+
@text_offset = pretext.length + 1
|
50
|
+
@col_offset = @surround_chars[0].length
|
51
|
+
return pretext + " #{dtext}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def toggle
|
56
|
+
fire
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# If user has pressed on this then set the group to this button.
|
61
|
+
def checked tf
|
62
|
+
|
63
|
+
if @button_group.value == value
|
64
|
+
@button_group.value = ""
|
65
|
+
else
|
66
|
+
@button_group.value = value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end # class radio
|
71
|
+
end # module
|
@@ -0,0 +1,417 @@
|
|
1
|
+
# ----------------------------------------------------------------------------- #
|
2
|
+
# File: textbox.rb
|
3
|
+
# Description: a multiline text view
|
4
|
+
# Author: j kepler http://github.com/mare-imbrium/canis/
|
5
|
+
# Date: 2018-03-24 - 12:39
|
6
|
+
# License: MIT
|
7
|
+
# Last update: 2018-04-20 12:58
|
8
|
+
# ----------------------------------------------------------------------------- #
|
9
|
+
# textbox.rb Copyright (C) 2012-2018 j kepler
|
10
|
+
## TODO -----------------------------------
|
11
|
+
# improve the object sent when row change or cursor movement
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# ----------------------------------------
|
15
|
+
## CHANGELOG
|
16
|
+
#
|
17
|
+
# ----------------------------------------
|
18
|
+
require 'umbra/widget'
|
19
|
+
module Umbra
|
20
|
+
class Textbox < Widget
|
21
|
+
attr_reader :list # list containing data
|
22
|
+
attr_accessor :file_name # filename passed in for reading
|
23
|
+
attr_accessor :selection_key # key used to select a row
|
24
|
+
attr_accessor :selected_index # row selected, may change to plural
|
25
|
+
attr_accessor :selected_color_pair # row selected color_pair
|
26
|
+
attr_accessor :selected_attr # row selected color_pair
|
27
|
+
#attr_accessor :cursor # position of cursor in line ??
|
28
|
+
=begin
|
29
|
+
attr_accessor :selected_mark # row selected character
|
30
|
+
attr_accessor :unselected_mark # row unselected character (usually blank)
|
31
|
+
attr_accessor :current_mark # row current character (default is >)
|
32
|
+
=end
|
33
|
+
|
34
|
+
def initialize config={}, &block
|
35
|
+
@focusable = false # will only be set true if data is set
|
36
|
+
@editable = false
|
37
|
+
@pstart = 0 # which row does printing start from
|
38
|
+
@current_index = 0 # index of row on which cursor is
|
39
|
+
@selected_index = nil # index of row selected
|
40
|
+
@selection_key = 0 # presently no selection. Actually 0 is Ctrl-Space.
|
41
|
+
@highlight_attr = FFI::NCurses::A_BOLD
|
42
|
+
@to_print_border = false
|
43
|
+
@row_offset = 0
|
44
|
+
@col_offset = 0
|
45
|
+
@pcol = 0
|
46
|
+
@curpos = 0 # current cursor position in buffer (NOT screen/window/field)
|
47
|
+
=begin
|
48
|
+
|
49
|
+
@selected_color_pair = CP_RED
|
50
|
+
@selected_attr = REVERSE
|
51
|
+
@selected_mark = 'x' # row selected character
|
52
|
+
@unselected_mark = ' ' # row unselected character (usually blank)
|
53
|
+
@current_mark = '>' # row current character (default is >)
|
54
|
+
=end
|
55
|
+
register_events([:ENTER_ROW, :LEAVE_ROW, :CURSOR_MOVE]) #
|
56
|
+
super
|
57
|
+
|
58
|
+
map_keys
|
59
|
+
# internal width and height
|
60
|
+
@repaint_required = true
|
61
|
+
end
|
62
|
+
def _calculate_dimensions
|
63
|
+
@int_width = @width
|
64
|
+
@int_height = @height # used here only
|
65
|
+
@scroll_lines ||= @int_height/2 # fix these to be perhaps half and one of ht
|
66
|
+
@page_lines = @int_height
|
67
|
+
@calculate_dimensions = true
|
68
|
+
end
|
69
|
+
# set list of data to be displayed.
|
70
|
+
# NOTE this can be called again and again, so we need to take care of change in size of data
|
71
|
+
# as well as things like current_index and selected_index or indices.
|
72
|
+
def list=(alist)
|
73
|
+
if !alist or alist.size == 0
|
74
|
+
self.focusable=(false)
|
75
|
+
else
|
76
|
+
self.focusable=(true)
|
77
|
+
end
|
78
|
+
@list = alist
|
79
|
+
@repaint_required = true
|
80
|
+
@pstart = @current_index = 0
|
81
|
+
@selected_index = nil
|
82
|
+
@focusable = true # too late since form is not rechecking its array
|
83
|
+
end
|
84
|
+
def file_name=(fp)
|
85
|
+
raise "File #{fp} not readable" unless File.readable? fp
|
86
|
+
return Dir.new(fp).entries if File.directory? fp
|
87
|
+
case File.extname(fp)
|
88
|
+
when '.tgz','.gz'
|
89
|
+
cmd = "tar -ztvf #{fp}"
|
90
|
+
content = %x[#{cmd}]
|
91
|
+
when '.zip'
|
92
|
+
cmd = "unzip -l #{fp}"
|
93
|
+
content = %x[#{cmd}]
|
94
|
+
when '.jar', '.gem'
|
95
|
+
cmd = "tar -tvf #{fp}"
|
96
|
+
content = %x[#{cmd}]
|
97
|
+
when '.png', '.out','.jpg', '.gif','.pdf'
|
98
|
+
content = "File #{fp} not displayable"
|
99
|
+
when '.sqlite'
|
100
|
+
cmd = "sqlite3 #{fp} 'select name from sqlite_master;'"
|
101
|
+
content = %x[#{cmd}]
|
102
|
+
else
|
103
|
+
#content = File.open(fp,"r").readlines # this keeps newlines which mess with output
|
104
|
+
content = File.open(fp,"r").read.split("\n")
|
105
|
+
end
|
106
|
+
self.list = content
|
107
|
+
raise "list not set" unless @list
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def repaint
|
112
|
+
_calculate_dimensions unless @calculate_dimensions
|
113
|
+
return unless @repaint_required
|
114
|
+
return unless @list
|
115
|
+
win = @graphic
|
116
|
+
r,c = @row, @col
|
117
|
+
_attr = @attr || NORMAL
|
118
|
+
_color = @color_pair || CP_WHITE
|
119
|
+
#_bordercolor = @border_color_pair || CP_BLUE
|
120
|
+
rowpos = 1
|
121
|
+
coffset = 0
|
122
|
+
#width = win.width-1
|
123
|
+
width = @width
|
124
|
+
files = @list
|
125
|
+
|
126
|
+
#ht = win.height-2
|
127
|
+
ht = @height
|
128
|
+
cur = @current_index
|
129
|
+
st = pstart = @pstart # previous start
|
130
|
+
pend = pstart + ht -1 #- previous end
|
131
|
+
if cur > pend
|
132
|
+
st = (cur -ht) + 1 #+
|
133
|
+
elsif cur < pstart
|
134
|
+
st = cur
|
135
|
+
end
|
136
|
+
$log.debug "LISTBOX: cur = #{cur} st = #{st} pstart = #{pstart} pend = #{pend} listsize = #{@list.size} "
|
137
|
+
hl = cur
|
138
|
+
y = 0
|
139
|
+
ctr = 0
|
140
|
+
filler = " "*(width)
|
141
|
+
files.each_with_index {|f, y|
|
142
|
+
next if y < st
|
143
|
+
colr = CP_WHITE # white on bg -1
|
144
|
+
mark = @unselected_mark
|
145
|
+
if y == hl
|
146
|
+
attr = @highlight_attr #FFI::NCurses::A_REVERSE
|
147
|
+
mark = @current_mark
|
148
|
+
rowpos = ctr
|
149
|
+
else
|
150
|
+
attr = FFI::NCurses::A_NORMAL
|
151
|
+
end
|
152
|
+
if y == @selected_index
|
153
|
+
colr = @selected_color_pair
|
154
|
+
attr = @selected_attr
|
155
|
+
mark = @selected_mark
|
156
|
+
end
|
157
|
+
#ff = "#{mark} #{f}"
|
158
|
+
ff = f
|
159
|
+
if ff
|
160
|
+
if ff.size > width
|
161
|
+
#ff = ff[0...width]
|
162
|
+
# pcol can be greater than width then we get null
|
163
|
+
if @pcol < ff.size
|
164
|
+
ff = ff[@pcol..@pcol+width-1]
|
165
|
+
else
|
166
|
+
ff = ""
|
167
|
+
end
|
168
|
+
else
|
169
|
+
if @pcol < ff.size
|
170
|
+
ff = ff[@pcol..-1]
|
171
|
+
else
|
172
|
+
ff = ""
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
ff = "" unless ff
|
177
|
+
|
178
|
+
win.printstring(ctr + r, coffset+c, filler, colr )
|
179
|
+
win.printstring(ctr + r, coffset+c, ff, colr, attr)
|
180
|
+
ctr += 1
|
181
|
+
@pstart = st
|
182
|
+
break if ctr >= ht #-
|
183
|
+
}
|
184
|
+
## if counter < ht then we need to clear the rest in case there was data earlier {{{
|
185
|
+
if ctr < ht
|
186
|
+
while ctr < ht
|
187
|
+
win.printstring(ctr + r, coffset+c, filler, _color )
|
188
|
+
ctr += 1
|
189
|
+
end
|
190
|
+
end # }}}
|
191
|
+
@row_offset = rowpos
|
192
|
+
#@col_offset = coffset # this way form can pick it up XXX can't override it like this
|
193
|
+
@repaint_required = false
|
194
|
+
end
|
195
|
+
|
196
|
+
def getvalue
|
197
|
+
@list
|
198
|
+
end
|
199
|
+
|
200
|
+
# ensure text has been passed or action
|
201
|
+
def getvalue_for_paint
|
202
|
+
raise
|
203
|
+
ret = getvalue
|
204
|
+
#@text_offset = @surround_chars[0].length
|
205
|
+
#@surround_chars[0] + ret + @surround_chars[1]
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
def map_keys
|
210
|
+
return if @keys_mapped
|
211
|
+
bind_keys([?k,FFI::NCurses::KEY_UP], "Up") { cursor_up }
|
212
|
+
bind_keys([?j,FFI::NCurses::KEY_DOWN], "Down") { cursor_down }
|
213
|
+
bind_keys([?l,FFI::NCurses::KEY_RIGHT], "Right") { cursor_forward }
|
214
|
+
bind_keys([?h,FFI::NCurses::KEY_LEFT], "Left") { cursor_backward }
|
215
|
+
bind_key(?g, 'goto_start') { goto_start }
|
216
|
+
bind_key(?G, 'goto_end') { goto_end }
|
217
|
+
bind_key(FFI::NCurses::KEY_CTRL_A, 'cursor_home') { cursor_home }
|
218
|
+
bind_key(FFI::NCurses::KEY_CTRL_E, 'cursor_end') { cursor_end }
|
219
|
+
bind_key(FFI::NCurses::KEY_CTRL_F, 'page_forward') { page_forward }
|
220
|
+
bind_key(32, 'page_forward') { page_forward }
|
221
|
+
bind_key(FFI::NCurses::KEY_CTRL_B, 'page_backward'){ page_backward }
|
222
|
+
bind_key(FFI::NCurses::KEY_CTRL_U, 'scroll_up') { scroll_up }
|
223
|
+
bind_key(FFI::NCurses::KEY_CTRL_D, 'scroll_down') { scroll_down }
|
224
|
+
@keys_mapped = true
|
225
|
+
end
|
226
|
+
|
227
|
+
# listbox key handling
|
228
|
+
def handle_key ch
|
229
|
+
return :UNHANDLED unless @list
|
230
|
+
# save old positions so we know movement has happened
|
231
|
+
old_current_index = @current_index
|
232
|
+
old_pcol = @pcol
|
233
|
+
old_col_offset = @col_offset
|
234
|
+
|
235
|
+
begin
|
236
|
+
case ch
|
237
|
+
when @selection_key
|
238
|
+
@repaint_required = true
|
239
|
+
if @selected_index == @current_index
|
240
|
+
@selected_index = nil
|
241
|
+
else
|
242
|
+
@selected_index = @current_index
|
243
|
+
end
|
244
|
+
else
|
245
|
+
ret = super
|
246
|
+
return ret
|
247
|
+
end
|
248
|
+
ensure
|
249
|
+
@current_index = 0 if @current_index < 0
|
250
|
+
@current_index = @list.size-1 if @current_index >= @list.size
|
251
|
+
@repaint_required = true if @current_index != old_current_index
|
252
|
+
if @current_index != old_current_index or @pcol != old_pcol or @col_offset != old_col_offset
|
253
|
+
if @current_index != old_current_index
|
254
|
+
on_leave_row old_current_index
|
255
|
+
on_enter_row @current_index
|
256
|
+
#fire_handler(:CHANGE_ROW, [old_current_index, @current_index, ch ]) # 2018-03-26 - improve this
|
257
|
+
end
|
258
|
+
@repaint_required = true
|
259
|
+
fire_handler(:CURSOR_MOVE, [@col_offset, @current_index, @curpos, @pcol, ch ]) # 2018-03-25 - improve this
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
# advance col_offset (where cursor will be displayed on screen)
|
264
|
+
# @param [Integer] advance by n (can be negative or positive)
|
265
|
+
# @return -1 if cannot advance
|
266
|
+
private def add_col_offset num
|
267
|
+
x = @col_offset + num
|
268
|
+
return -1 if x < 0
|
269
|
+
return -1 if x > @int_width
|
270
|
+
# is it a problem that i am directly changing col_offset ??? XXX
|
271
|
+
@col_offset += num
|
272
|
+
end
|
273
|
+
# returns current row
|
274
|
+
def current_row
|
275
|
+
@list[@current_index]
|
276
|
+
end
|
277
|
+
|
278
|
+
# move cursor forward one character, called with KEY_RIGHT action.
|
279
|
+
def cursor_forward
|
280
|
+
blen = current_row().size-1
|
281
|
+
if @curpos < blen
|
282
|
+
if add_col_offset(1)==-1 # go forward if you can, else scroll
|
283
|
+
#@pcol += 1 if @pcol < @width
|
284
|
+
@pcol += 1 if @pcol < blen
|
285
|
+
end
|
286
|
+
@curpos += 1
|
287
|
+
end
|
288
|
+
end
|
289
|
+
def cursor_backward
|
290
|
+
|
291
|
+
if @col_offset > 0
|
292
|
+
@curpos -= 1
|
293
|
+
add_col_offset -1
|
294
|
+
else
|
295
|
+
# cur is on the first col, then scroll left
|
296
|
+
if @pcol > 0
|
297
|
+
@pcol -= 1
|
298
|
+
@curpos -= 1
|
299
|
+
else
|
300
|
+
# do nothing
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
# position cursor at start of field
|
305
|
+
def cursor_home
|
306
|
+
@curpos = 0
|
307
|
+
@pcol = 0
|
308
|
+
set_col_offset 0
|
309
|
+
end
|
310
|
+
# goto end of line.
|
311
|
+
# This should be consistent with moving the cursor to the end of the row with right arrow
|
312
|
+
def cursor_end
|
313
|
+
blen = current_row().length
|
314
|
+
if blen < @int_width
|
315
|
+
set_col_offset blen # just after the last character
|
316
|
+
@pcol = 0
|
317
|
+
else
|
318
|
+
@pcol = blen-@int_width
|
319
|
+
set_col_offset blen
|
320
|
+
end
|
321
|
+
@curpos = blen # this is position in array where editing or motion is to happen regardless of what you see
|
322
|
+
# regardless of pcol (panning)
|
323
|
+
end
|
324
|
+
# go to start of file (first line)
|
325
|
+
def goto_start
|
326
|
+
@current_index = 0
|
327
|
+
@pcol = @curpos = 0
|
328
|
+
set_col_offset 0
|
329
|
+
end
|
330
|
+
# go to end of file (last line)
|
331
|
+
def goto_end
|
332
|
+
@current_index = @list.size-1
|
333
|
+
end
|
334
|
+
def scroll_down
|
335
|
+
@current_index += @scroll_lines
|
336
|
+
end
|
337
|
+
def scroll_up
|
338
|
+
@current_index -= @scroll_lines
|
339
|
+
end
|
340
|
+
def page_backward
|
341
|
+
@current_index -= @page_lines
|
342
|
+
end
|
343
|
+
def page_forward
|
344
|
+
@current_index += @page_lines
|
345
|
+
end
|
346
|
+
# sets the visual cursor on the window at correct place
|
347
|
+
# NOTE be careful of curpos - pcol being less than 0
|
348
|
+
# @param [Integer] position in data on the line
|
349
|
+
private def set_col_offset x=@curpos
|
350
|
+
@curpos = x || 0 # NOTE we set the index of cursor here - WHY TWO THINGS ??? XXX
|
351
|
+
#return -1 if x < 0
|
352
|
+
#return -1 if x > @width
|
353
|
+
if x >= @int_width
|
354
|
+
x = @int_width
|
355
|
+
@col_offset = @int_width
|
356
|
+
return
|
357
|
+
end
|
358
|
+
@col_offset = x
|
359
|
+
@col_offset = @int_width if @col_offset > @int_width
|
360
|
+
return
|
361
|
+
end
|
362
|
+
def cursor_up
|
363
|
+
@current_index -= 1
|
364
|
+
end
|
365
|
+
# go to next row
|
366
|
+
def cursor_down
|
367
|
+
@current_index += 1
|
368
|
+
end
|
369
|
+
def on_enter
|
370
|
+
super
|
371
|
+
return unless @list
|
372
|
+
on_enter_row @current_index
|
373
|
+
end
|
374
|
+
def on_leave
|
375
|
+
super
|
376
|
+
on_leave_row @current_index
|
377
|
+
end
|
378
|
+
# called when object leaves a row and when object is exited.
|
379
|
+
def on_leave_row index
|
380
|
+
fire_handler(:LEAVE_ROW, [index]) # 2018-03-26 - improve this
|
381
|
+
end
|
382
|
+
# called whenever a row entered.
|
383
|
+
# Call when object entered, also.
|
384
|
+
def on_enter_row index
|
385
|
+
#fire_handler(:ENTER_ROW, [old_current_index, @current_index, ch ]) # 2018-03-26 - improve this
|
386
|
+
fire_handler(:ENTER_ROW, [@current_index]) # 2018-03-26 - improve this
|
387
|
+
# if cursor ahead of blen then fix it
|
388
|
+
blen = current_row().size-1
|
389
|
+
if @curpos > blen
|
390
|
+
@col_offset = blen - @pcol
|
391
|
+
@curpos = blen
|
392
|
+
if @pcol > blen
|
393
|
+
@pcol = blen - @int_width
|
394
|
+
@pcol = 0 if @pcol < 0
|
395
|
+
@col_offset = blen - @pcol
|
396
|
+
end
|
397
|
+
end
|
398
|
+
@col_offset = 0 if @col_offset < 0
|
399
|
+
end
|
400
|
+
## border {{{
|
401
|
+
private def print_border row, col, height, width, color, att=FFI::NCurses::A_NORMAL
|
402
|
+
raise
|
403
|
+
pointer = @graphic.pointer
|
404
|
+
FFI::NCurses.wattron(pointer, FFI::NCurses.COLOR_PAIR(color) | att)
|
405
|
+
FFI::NCurses.mvwaddch pointer, row, col, FFI::NCurses::ACS_ULCORNER
|
406
|
+
FFI::NCurses.mvwhline( pointer, row, col+1, FFI::NCurses::ACS_HLINE, width-2)
|
407
|
+
FFI::NCurses.mvwaddch pointer, row, col+width-1, FFI::NCurses::ACS_URCORNER
|
408
|
+
FFI::NCurses.mvwvline( pointer, row+1, col, FFI::NCurses::ACS_VLINE, height-2)
|
409
|
+
|
410
|
+
FFI::NCurses.mvwaddch pointer, row+height-1, col, FFI::NCurses::ACS_LLCORNER
|
411
|
+
FFI::NCurses.mvwhline(pointer, row+height-1, col+1, FFI::NCurses::ACS_HLINE, width-2)
|
412
|
+
FFI::NCurses.mvwaddch pointer, row+height-1, col+width-1, FFI::NCurses::ACS_LRCORNER
|
413
|
+
FFI::NCurses.mvwvline( pointer, row+1, col+width-1, FFI::NCurses::ACS_VLINE, height-2)
|
414
|
+
FFI::NCurses.wattroff(pointer, FFI::NCurses.COLOR_PAIR(color) | att)
|
415
|
+
end # }}}
|
416
|
+
end
|
417
|
+
end # module
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'umbra/button'
|
2
|
+
##
|
3
|
+
# ----------------------------------------------------------------------------- #
|
4
|
+
# File: togglebutton.rb
|
5
|
+
# Description: a button that has two states, on and off
|
6
|
+
# Author: j kepler http://github.com/mare-imbrium/umbra/
|
7
|
+
# Date: 2018-03-17 - 22:50
|
8
|
+
# License: MIT
|
9
|
+
# Last update: 2018-04-07 23:08
|
10
|
+
# ----------------------------------------------------------------------------- #
|
11
|
+
# togglebutton.rb Copyright (C) 2012-2018 j kepler
|
12
|
+
#
|
13
|
+
#
|
14
|
+
module Umbra
|
15
|
+
##
|
16
|
+
# an event fired when an item that can be selected is toggled/selected
|
17
|
+
class ItemEvent # {{{
|
18
|
+
# http://java.sun.com/javase/6/docs/api/java/awt/event/ItemEvent.html
|
19
|
+
attr_reader :state # :SELECTED :DESELECTED
|
20
|
+
attr_reader :item # the item pressed such as toggle button
|
21
|
+
attr_reader :item_selectable # item originating event such as list or collection
|
22
|
+
attr_reader :item_first # if from a list
|
23
|
+
attr_reader :item_last #
|
24
|
+
attr_reader :param_string # for debugging etc
|
25
|
+
=begin
|
26
|
+
def initialize item, item_selectable, state, item_first=-1, item_last=-1, paramstring=nil
|
27
|
+
@item, @item_selectable, @state, @item_first, @item_last =
|
28
|
+
item, item_selectable, state, item_first, item_last
|
29
|
+
@param_string = "Item event fired: #{item}, #{state}"
|
30
|
+
end
|
31
|
+
=end
|
32
|
+
# i think only one is needed per object, so create once only
|
33
|
+
def initialize item, item_selectable
|
34
|
+
@item, @item_selectable =
|
35
|
+
item, item_selectable
|
36
|
+
end
|
37
|
+
def set state, item_first=-1, item_last=-1, param_string=nil
|
38
|
+
@state, @item_first, @item_last, @param_string =
|
39
|
+
state, item_first, item_last, param_string
|
40
|
+
@param_string = "Item event fired: #{item}, #{state}" if param_string.nil?
|
41
|
+
end
|
42
|
+
end # }}}
|
43
|
+
# A button that may be switched off an on.
|
44
|
+
# Extended by RadioButton and checkbox.
|
45
|
+
# WARNING, pls do not override +text+ otherwise checkboxes etc will stop functioning.
|
46
|
+
# TODO: add editable here nd prevent toggling if not so.
|
47
|
+
class ToggleButton < Button
|
48
|
+
# text for on value and off value
|
49
|
+
attr_accessor :onvalue, :offvalue
|
50
|
+
# boolean, which value to use currently, onvalue or offvalue
|
51
|
+
attr_accessor :value
|
52
|
+
# characters to use for surround, array, default square brackets
|
53
|
+
attr_accessor :surround_chars
|
54
|
+
# 2018-04-02 - removing variable
|
55
|
+
#attr_accessor :variable # value linked to this variable which is a boolean
|
56
|
+
# background to use when selected, if not set then default
|
57
|
+
# 2018-04-02 - unused so commenting off. color_pair is not used here or in checkbox
|
58
|
+
#attr_accessor :selected_bgcolor
|
59
|
+
#attr_accessor :selected_color
|
60
|
+
attr_accessor :selected_color_pair
|
61
|
+
|
62
|
+
def initialize config={}, &block
|
63
|
+
super
|
64
|
+
|
65
|
+
#@value ||= (@variable.nil? ? false : @variable.get_value(@name)==true)
|
66
|
+
# TODO may need to do this when this is added to button_group
|
67
|
+
end
|
68
|
+
def getvalue
|
69
|
+
@value ? @onvalue : @offvalue
|
70
|
+
end
|
71
|
+
|
72
|
+
# WARNING, pls do not override +text+ otherwise checkboxes etc will stop functioning.
|
73
|
+
|
74
|
+
# added for some standardization 2010-09-07 20:28
|
75
|
+
# alias :text :getvalue # NEXT VERSION
|
76
|
+
# change existing text to label
|
77
|
+
##
|
78
|
+
# is the button on or off
|
79
|
+
# added 2008-12-09 19:05
|
80
|
+
def checked?
|
81
|
+
@value
|
82
|
+
end
|
83
|
+
alias :selected? :checked?
|
84
|
+
|
85
|
+
def getvalue_for_paint
|
86
|
+
# when the width is set externally then the surround chars sit outside the width
|
87
|
+
#unless @width
|
88
|
+
if @onvalue && @offvalue
|
89
|
+
@width = [ @onvalue.length, @offvalue.length ].max
|
90
|
+
end
|
91
|
+
#end
|
92
|
+
buttontext = getvalue().center(@width)
|
93
|
+
@text_offset = @surround_chars[0].length
|
94
|
+
@surround_chars[0] + buttontext + @surround_chars[1]
|
95
|
+
end
|
96
|
+
|
97
|
+
# toggle button handle key
|
98
|
+
# @param [int] key received
|
99
|
+
#
|
100
|
+
def handle_key ch
|
101
|
+
if ch == 32
|
102
|
+
toggle
|
103
|
+
@repaint_required = true # need to change the label
|
104
|
+
else
|
105
|
+
super
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# toggle the button value
|
111
|
+
def toggle
|
112
|
+
fire
|
113
|
+
end
|
114
|
+
|
115
|
+
# called on :PRESS event
|
116
|
+
# caller should check state of itemevent passed to block
|
117
|
+
# NOTE i have not brought ItemEvent in here.
|
118
|
+
def fire
|
119
|
+
checked(!@value)
|
120
|
+
@item_event = ItemEvent.new self, self if @item_event.nil?
|
121
|
+
@item_event.set(@value ? :SELECTED : :DESELECTED)
|
122
|
+
fire_handler :PRESS, @item_event # should the event itself be ITEM_EVENT
|
123
|
+
end
|
124
|
+
##
|
125
|
+
# set the value to true or false
|
126
|
+
# user may programmatically want to check or uncheck
|
127
|
+
def checked tf
|
128
|
+
@value = tf
|
129
|
+
=begin
|
130
|
+
if @variable
|
131
|
+
if @value
|
132
|
+
@variable.set_value((@onvalue || 1), @name)
|
133
|
+
else
|
134
|
+
@variable.set_value((@offvalue || 0), @name)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
=end
|
138
|
+
end
|
139
|
+
end # class
|
140
|
+
end # module
|