ncumbra 0.1.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.
- 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
|