ncumbra 0.1.0 → 0.1.1
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 +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG +14 -0
- data/README.md +21 -6
- data/examples/data/atp_matches_2017.csv +2887 -0
- data/examples/data/atp_matches_2018.csv +460 -0
- data/examples/data/import.sh +13 -0
- data/examples/data/schema.txt +51 -0
- data/examples/ex1.rb +2 -0
- data/examples/ex2.rb +1 -0
- data/examples/ex5.rb +1 -1
- data/examples/exbox.rb +3 -2
- data/examples/exm1.rb +1 -2
- data/examples/extab2.rb +170 -0
- data/examples/extab3.rb +306 -0
- data/examples/extabular.rb +123 -0
- data/examples/tasks.csv +88 -0
- data/lib/umbra/box.rb +38 -21
- data/lib/umbra/checkbox.rb +2 -2
- data/lib/umbra/dialog.rb +1 -2
- data/lib/umbra/eventhandler.rb +52 -4
- data/lib/umbra/field.rb +7 -3
- data/lib/umbra/form.rb +119 -55
- data/lib/umbra/keymappinghandler.rb +4 -4
- data/lib/umbra/label.rb +31 -17
- data/lib/umbra/labeledfield.rb +7 -8
- data/lib/umbra/listbox.rb +114 -341
- data/lib/umbra/messagebox.rb +93 -42
- data/lib/umbra/multiline.rb +476 -0
- data/lib/umbra/pad.rb +20 -14
- data/lib/umbra/radiobutton.rb +2 -2
- data/lib/umbra/table.rb +260 -0
- data/lib/umbra/tabular.rb +431 -0
- data/lib/umbra/textbox.rb +36 -223
- data/lib/umbra/togglebutton.rb +3 -5
- data/lib/umbra/version.rb +1 -1
- data/lib/umbra/widget.rb +72 -13
- data/lib/umbra/window.rb +59 -15
- data/lib/umbra.rb +82 -11
- data/umbra.gemspec +2 -2
- metadata +18 -4
data/lib/umbra/textbox.rb
CHANGED
@@ -4,26 +4,21 @@
|
|
4
4
|
# Author: j kepler http://github.com/mare-imbrium/canis/
|
5
5
|
# Date: 2018-03-24 - 12:39
|
6
6
|
# License: MIT
|
7
|
-
# Last update: 2018-
|
7
|
+
# Last update: 2018-05-10 11:06
|
8
8
|
# ----------------------------------------------------------------------------- #
|
9
9
|
# textbox.rb Copyright (C) 2012-2018 j kepler
|
10
10
|
## TODO -----------------------------------
|
11
11
|
# improve the object sent when row change or cursor movement
|
12
|
-
|
12
|
+
## 2018-05-08 - extend Multiline
|
13
13
|
#
|
14
14
|
# ----------------------------------------
|
15
15
|
## CHANGELOG
|
16
16
|
#
|
17
17
|
# ----------------------------------------
|
18
|
-
require 'umbra/
|
18
|
+
require 'umbra/multiline'
|
19
19
|
module Umbra
|
20
|
-
class Textbox <
|
21
|
-
attr_reader :list # list containing data
|
20
|
+
class Textbox < Multiline
|
22
21
|
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
22
|
#attr_accessor :cursor # position of cursor in line ??
|
28
23
|
=begin
|
29
24
|
attr_accessor :selected_mark # row selected character
|
@@ -32,55 +27,18 @@ class Textbox < Widget
|
|
32
27
|
=end
|
33
28
|
|
34
29
|
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
30
|
@highlight_attr = FFI::NCurses::A_BOLD
|
42
|
-
@to_print_border = false
|
43
31
|
@row_offset = 0
|
44
32
|
@col_offset = 0
|
45
|
-
@pcol = 0
|
46
33
|
@curpos = 0 # current cursor position in buffer (NOT screen/window/field)
|
47
|
-
|
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]) #
|
34
|
+
#register_events([:ENTER_ROW, :LEAVE_ROW, :CURSOR_MOVE]) #
|
35
|
+
register_events([:CURSOR_MOVE]) #
|
56
36
|
super
|
57
37
|
|
58
|
-
map_keys
|
59
|
-
# internal width and height
|
60
|
-
@repaint_required = true
|
61
38
|
end
|
62
|
-
|
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.
|
39
|
+
# set list of data to be displayed from filename. {{{
|
70
40
|
# NOTE this can be called again and again, so we need to take care of change in size of data
|
71
41
|
# 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
42
|
def file_name=(fp)
|
85
43
|
raise "File #{fp} not readable" unless File.readable? fp
|
86
44
|
return Dir.new(fp).entries if File.directory? fp
|
@@ -106,126 +64,28 @@ class Textbox < Widget
|
|
106
64
|
self.list = content
|
107
65
|
raise "list not set" unless @list
|
108
66
|
|
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
|
67
|
+
end # }}}
|
199
68
|
|
200
|
-
#
|
201
|
-
def
|
202
|
-
|
203
|
-
ret = getvalue
|
204
|
-
#@text_offset = @surround_chars[0].length
|
205
|
-
#@surround_chars[0] + ret + @surround_chars[1]
|
69
|
+
# returns current row
|
70
|
+
def current_row
|
71
|
+
@list[@current_index]
|
206
72
|
end
|
207
73
|
|
208
74
|
|
209
|
-
|
210
|
-
|
211
|
-
|
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
|
75
|
+
## textbox key handling
|
76
|
+
## Textbox varies from multiline in that it fires a cursor_move event whrease the parent
|
77
|
+
## fires a cursor_move event which is mostly used for testing out
|
228
78
|
def handle_key ch
|
79
|
+
begin
|
80
|
+
ret = super
|
81
|
+
return ret
|
82
|
+
ensure
|
83
|
+
if @repaint_required
|
84
|
+
fire_handler(:CURSOR_MOVE, [@col_offset, @current_index, @curpos, @pcol, ch ]) # 2018-03-25 - improve this
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
def OLDhandle_key ch # {{{
|
229
89
|
return :UNHANDLED unless @list
|
230
90
|
# save old positions so we know movement has happened
|
231
91
|
old_current_index = @current_index
|
@@ -233,18 +93,8 @@ class Textbox < Widget
|
|
233
93
|
old_col_offset = @col_offset
|
234
94
|
|
235
95
|
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
96
|
ret = super
|
246
97
|
return ret
|
247
|
-
end
|
248
98
|
ensure
|
249
99
|
@current_index = 0 if @current_index < 0
|
250
100
|
@current_index = @list.size-1 if @current_index >= @list.size
|
@@ -253,30 +103,25 @@ class Textbox < Widget
|
|
253
103
|
if @current_index != old_current_index
|
254
104
|
on_leave_row old_current_index
|
255
105
|
on_enter_row @current_index
|
256
|
-
#fire_handler(:CHANGE_ROW, [old_current_index, @current_index, ch ]) # 2018-03-26 - improve this
|
257
106
|
end
|
258
107
|
@repaint_required = true
|
259
108
|
fire_handler(:CURSOR_MOVE, [@col_offset, @current_index, @curpos, @pcol, ch ]) # 2018-03-25 - improve this
|
260
109
|
end
|
261
110
|
end
|
262
|
-
end
|
263
|
-
# advance col_offset (where cursor will be displayed on screen)
|
111
|
+
end # }}}
|
112
|
+
# advance col_offset (where cursor will be displayed on screen) {{{
|
264
113
|
# @param [Integer] advance by n (can be negative or positive)
|
265
114
|
# @return -1 if cannot advance
|
266
|
-
private def
|
115
|
+
private def OLDadd_col_offset num
|
267
116
|
x = @col_offset + num
|
268
117
|
return -1 if x < 0
|
269
118
|
return -1 if x > @int_width
|
270
119
|
# is it a problem that i am directly changing col_offset ??? XXX
|
271
120
|
@col_offset += num
|
272
121
|
end
|
273
|
-
# returns current row
|
274
|
-
def current_row
|
275
|
-
@list[@current_index]
|
276
|
-
end
|
277
122
|
|
278
123
|
# move cursor forward one character, called with KEY_RIGHT action.
|
279
|
-
def
|
124
|
+
def OLDcursor_forward
|
280
125
|
blen = current_row().size-1
|
281
126
|
if @curpos < blen
|
282
127
|
if add_col_offset(1)==-1 # go forward if you can, else scroll
|
@@ -286,7 +131,7 @@ class Textbox < Widget
|
|
286
131
|
@curpos += 1
|
287
132
|
end
|
288
133
|
end
|
289
|
-
def
|
134
|
+
def OLDcursor_backward
|
290
135
|
|
291
136
|
if @col_offset > 0
|
292
137
|
@curpos -= 1
|
@@ -302,14 +147,14 @@ class Textbox < Widget
|
|
302
147
|
end
|
303
148
|
end
|
304
149
|
# position cursor at start of field
|
305
|
-
def
|
150
|
+
def OLDcursor_home
|
306
151
|
@curpos = 0
|
307
152
|
@pcol = 0
|
308
153
|
set_col_offset 0
|
309
154
|
end
|
310
155
|
# goto end of line.
|
311
156
|
# This should be consistent with moving the cursor to the end of the row with right arrow
|
312
|
-
def
|
157
|
+
def OLDcursor_end
|
313
158
|
blen = current_row().length
|
314
159
|
if blen < @int_width
|
315
160
|
set_col_offset blen # just after the last character
|
@@ -322,31 +167,19 @@ class Textbox < Widget
|
|
322
167
|
# regardless of pcol (panning)
|
323
168
|
end
|
324
169
|
# go to start of file (first line)
|
325
|
-
def
|
170
|
+
def OLDgoto_start
|
326
171
|
@current_index = 0
|
327
172
|
@pcol = @curpos = 0
|
328
173
|
set_col_offset 0
|
329
174
|
end
|
330
175
|
# go to end of file (last line)
|
331
|
-
def
|
176
|
+
def OLDgoto_end
|
332
177
|
@current_index = @list.size-1
|
333
178
|
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
179
|
# sets the visual cursor on the window at correct place
|
347
180
|
# NOTE be careful of curpos - pcol being less than 0
|
348
181
|
# @param [Integer] position in data on the line
|
349
|
-
private def
|
182
|
+
private def OLD_set_col_offset x=@curpos
|
350
183
|
@curpos = x || 0 # NOTE we set the index of cursor here - WHY TWO THINGS ??? XXX
|
351
184
|
#return -1 if x < 0
|
352
185
|
#return -1 if x > @width
|
@@ -359,29 +192,9 @@ class Textbox < Widget
|
|
359
192
|
@col_offset = @int_width if @col_offset > @int_width
|
360
193
|
return
|
361
194
|
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
195
|
# called whenever a row entered.
|
383
196
|
# Call when object entered, also.
|
384
|
-
def
|
197
|
+
def OLD_on_enter_row index
|
385
198
|
#fire_handler(:ENTER_ROW, [old_current_index, @current_index, ch ]) # 2018-03-26 - improve this
|
386
199
|
fire_handler(:ENTER_ROW, [@current_index]) # 2018-03-26 - improve this
|
387
200
|
# if cursor ahead of blen then fix it
|
@@ -396,7 +209,7 @@ class Textbox < Widget
|
|
396
209
|
end
|
397
210
|
end
|
398
211
|
@col_offset = 0 if @col_offset < 0
|
399
|
-
end
|
212
|
+
end # }}}
|
400
213
|
## border {{{
|
401
214
|
private def print_border row, col, height, width, color, att=FFI::NCurses::A_NORMAL
|
402
215
|
raise
|
data/lib/umbra/togglebutton.rb
CHANGED
@@ -6,7 +6,7 @@ require 'umbra/button'
|
|
6
6
|
# Author: j kepler http://github.com/mare-imbrium/umbra/
|
7
7
|
# Date: 2018-03-17 - 22:50
|
8
8
|
# License: MIT
|
9
|
-
# Last update: 2018-
|
9
|
+
# Last update: 2018-05-14 14:35
|
10
10
|
# ----------------------------------------------------------------------------- #
|
11
11
|
# togglebutton.rb Copyright (C) 2012-2018 j kepler
|
12
12
|
#
|
@@ -50,14 +50,12 @@ class ToggleButton < Button
|
|
50
50
|
# boolean, which value to use currently, onvalue or offvalue
|
51
51
|
attr_accessor :value
|
52
52
|
# characters to use for surround, array, default square brackets
|
53
|
-
|
53
|
+
attr_property :surround_chars
|
54
54
|
# 2018-04-02 - removing variable
|
55
55
|
#attr_accessor :variable # value linked to this variable which is a boolean
|
56
56
|
# background to use when selected, if not set then default
|
57
57
|
# 2018-04-02 - unused so commenting off. color_pair is not used here or in checkbox
|
58
|
-
|
59
|
-
#attr_accessor :selected_color
|
60
|
-
attr_accessor :selected_color_pair
|
58
|
+
attr_property :selected_color_pair
|
61
59
|
|
62
60
|
def initialize config={}, &block
|
63
61
|
super
|
data/lib/umbra/version.rb
CHANGED
data/lib/umbra/widget.rb
CHANGED
@@ -3,10 +3,39 @@
|
|
3
3
|
# extend this, if it wants to be repainted or wants focus. Otherwise.
|
4
4
|
# form will be unaware of it.
|
5
5
|
# 2018-03-08 -
|
6
|
-
|
6
|
+
|
7
7
|
require 'umbra/eventhandler' # for register_events and fire_handler etc
|
8
8
|
require 'umbra/keymappinghandler' # for bind_key and process_key
|
9
9
|
|
10
|
+
class Module # {{{
|
11
|
+
|
12
|
+
def attr_property(*symbols)
|
13
|
+
symbols.each { |sym|
|
14
|
+
class_eval %{
|
15
|
+
def #{sym}=(val)
|
16
|
+
oldvalue = @#{sym}
|
17
|
+
newvalue = val
|
18
|
+
if @_object_created.nil?
|
19
|
+
@#{sym} = newvalue
|
20
|
+
end
|
21
|
+
# return(self) if oldvalue.nil? || @_object_created.nil?
|
22
|
+
return(self) if @_object_created.nil?
|
23
|
+
|
24
|
+
if oldvalue != newvalue
|
25
|
+
begin
|
26
|
+
fire_property_change("#{sym}", oldvalue, newvalue)
|
27
|
+
@#{sym} = newvalue
|
28
|
+
rescue PropertyVetoException
|
29
|
+
$log.warn "PropertyVetoException for #{sym}:" + oldvalue.to_s + "-> "+ newvalue.to_s
|
30
|
+
end
|
31
|
+
end # oldvalue !=
|
32
|
+
self
|
33
|
+
end # def
|
34
|
+
attr_reader sym
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end # def
|
38
|
+
end # module }}}
|
10
39
|
module Umbra
|
11
40
|
class FieldValidationException < RuntimeError
|
12
41
|
end
|
@@ -14,27 +43,29 @@ class Widget
|
|
14
43
|
include EventHandler
|
15
44
|
include KeyMappingHandler
|
16
45
|
# common interface for text related to a field, label, textview, button etc
|
17
|
-
|
46
|
+
attr_property :text
|
47
|
+
attr_property :width, :height ## FIXME this won't trigger repaint or property !!!
|
18
48
|
|
19
49
|
# foreground and background colors when focussed. Currently used with buttons and field
|
20
50
|
# Form checks and repaints on entry if these are set.
|
21
|
-
|
22
|
-
|
51
|
+
attr_property :highlight_color_pair
|
52
|
+
attr_property :highlight_attr
|
23
53
|
|
24
54
|
# NOTE: 2018-03-04 - user will have to call repaint_required if he changes color or coordinates.
|
25
|
-
attr_accessor :
|
55
|
+
attr_accessor :col # location of object
|
56
|
+
attr_writer :row # location of object
|
26
57
|
#attr_writer :color, :bgcolor # normal foreground and background 2018-03-08 - now color_pair
|
27
58
|
# moved to a method which calculates color 2011-11-12
|
28
|
-
|
29
|
-
|
59
|
+
attr_property :color_pair # instead of colors give just color_pair
|
60
|
+
attr_property :attr # attribute bold, normal, reverse
|
30
61
|
attr_accessor :name # name to refr to or recall object by_name
|
31
62
|
attr_accessor :curpos # cursor position inside object - column, not row.
|
32
|
-
attr_reader :config # can be used for popping user objects too
|
63
|
+
attr_reader :config # can be used for popping user objects too. NOTE unused
|
33
64
|
#attr_accessor :form # made accessor 2008-11-27 22:32 so menu can set
|
34
65
|
attr_accessor :graphic # window which should be set by form when adding 2018-03-19
|
35
66
|
attr_accessor :state # normal, selected, highlighted
|
36
67
|
attr_reader :row_offset, :col_offset # where should the cursor be placed to start with
|
37
|
-
|
68
|
+
attr_property :visible # boolean # 2008-12-09 11:29
|
38
69
|
# if changing focusable property of a field after form creation, you may need to call
|
39
70
|
# pack again, or atl east update_focusables
|
40
71
|
attr_reader :focusable # boolean can this get focus # 2018-03-21 - 23:13
|
@@ -104,7 +135,7 @@ class Widget
|
|
104
135
|
#alias :modified :set_modified
|
105
136
|
|
106
137
|
# triggered whenever a widget is entered.
|
107
|
-
#
|
138
|
+
# NOTE should we not fix cursor at this point (on_enter) ?
|
108
139
|
def on_enter
|
109
140
|
@state = :HIGHLIGHTED # duplicating since often these are inside containers
|
110
141
|
@focussed = true
|
@@ -126,7 +157,7 @@ class Widget
|
|
126
157
|
# row and col is where a widget starts. offsets usually take into account borders.
|
127
158
|
# the offsets typically are where the cursor should be positioned inside, upon on_enter.
|
128
159
|
def rowcol
|
129
|
-
return
|
160
|
+
return self.row+@row_offset, self.col+@col_offset
|
130
161
|
end
|
131
162
|
## return the value of the widget.
|
132
163
|
def getvalue
|
@@ -144,12 +175,13 @@ class Widget
|
|
144
175
|
r,c = rowcol
|
145
176
|
$log.debug("widget repaint : r:#{r} c:#{c} col:#{@color_pair}" )
|
146
177
|
value = getvalue_for_paint
|
147
|
-
len =
|
178
|
+
len = self.width || value.length
|
148
179
|
acolor = @color_pair
|
149
180
|
@graphic.printstring r, c, "%-*s" % [len, value], acolor, attr()
|
150
181
|
end
|
151
182
|
|
152
183
|
def destroy
|
184
|
+
raise "what is this dong here still SHOULD Not be CALLED"
|
153
185
|
$log.debug "DESTROY : widget #{@name} "
|
154
186
|
panel = @window.panel
|
155
187
|
Ncurses::Panel.del_panel(panel.pointer) if !panel.nil?
|
@@ -186,10 +218,13 @@ class Widget
|
|
186
218
|
# is the entire widget to be repainted including things like borders and titles
|
187
219
|
# earlier took a default of true, now must be explicit. Perhaps, not used currently.
|
188
220
|
def repaint_all(tf)
|
221
|
+
# NOTE NOT USED
|
222
|
+
raise " not used repaint all"
|
189
223
|
@repaint_all = tf
|
190
224
|
@repaint_required = tf
|
191
225
|
end
|
192
226
|
# shortcut for users to indicate that a widget should be redrawn since some property has been changed.
|
227
|
+
# Now that I have created attr_property this may not be needed
|
193
228
|
def touch
|
194
229
|
@repaint_required = true
|
195
230
|
end
|
@@ -210,10 +245,34 @@ class Widget
|
|
210
245
|
@_form = aform
|
211
246
|
end
|
212
247
|
def focusable=(bool)
|
213
|
-
|
248
|
+
#$log.debug " inside focusable= with #{bool} "
|
214
249
|
@focusable = bool
|
215
250
|
@_form.update_focusables if @_form
|
216
251
|
end
|
252
|
+
|
253
|
+
## TODO maybe check for decimal between 0 and 1 which will be percentage of width
|
254
|
+
def width
|
255
|
+
return nil unless @width ## this is required otherwise checking for nil will fail
|
256
|
+
if @width < 0
|
257
|
+
return ( FFI::NCurses.COLS + @width ) - self.col + 1
|
258
|
+
#return ( FFI::NCurses.COLS + @width ) #- self.col + 1
|
259
|
+
end
|
260
|
+
@width
|
261
|
+
end
|
262
|
+
def height
|
263
|
+
return nil unless @height
|
264
|
+
if @height < 0
|
265
|
+
return ((FFI::NCurses.LINES + @height) - self.row) + 1
|
266
|
+
#return (FFI::NCurses.LINES + @height)
|
267
|
+
end
|
268
|
+
@height
|
269
|
+
end
|
270
|
+
def row
|
271
|
+
if @row < 0
|
272
|
+
return FFI::NCurses.LINES + @row
|
273
|
+
end
|
274
|
+
@row
|
275
|
+
end
|
217
276
|
#
|
218
277
|
## ADD HERE WIDGET
|
219
278
|
end #
|
data/lib/umbra/window.rb
CHANGED
@@ -1,22 +1,35 @@
|
|
1
1
|
require 'ffi-ncurses'
|
2
2
|
require 'ffi-ncurses/widechars'
|
3
3
|
|
4
|
+
## NOTE: conflict between KEY_RESIZE and wtimeout or halfdelay.
|
5
|
+
## Setting a timeout or delay allows an application to respond to updates without a keypress,
|
6
|
+
## such as continuous updates.
|
7
|
+
## However, this means that KEY_RESIZE will not work unless a key is pressed.
|
8
|
+
## If resizing is important, then caller may set $ncurses_timeout to -1.
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
|
4
13
|
module Umbra
|
5
14
|
|
6
|
-
|
7
|
-
BOLD
|
8
|
-
REVERSE
|
9
|
-
UNDERLINE
|
10
|
-
NORMAL
|
11
|
-
|
12
|
-
|
13
|
-
COLOR_BLACK
|
14
|
-
COLOR_WHITE
|
15
|
-
COLOR_BLUE
|
16
|
-
COLOR_RED
|
17
|
-
COLOR_GREEN
|
18
|
-
COLOR_CYAN
|
19
|
-
COLOR_MAGENTA
|
15
|
+
## attribute constants, use them to specify an attrib for a widget or window.
|
16
|
+
BOLD = FFI::NCurses::A_BOLD
|
17
|
+
REVERSE = FFI::NCurses::A_REVERSE
|
18
|
+
UNDERLINE = FFI::NCurses::A_UNDERLINE
|
19
|
+
NORMAL = FFI::NCurses::A_NORMAL
|
20
|
+
|
21
|
+
## color constants, use these when creating a color
|
22
|
+
COLOR_BLACK = FFI::NCurses::BLACK
|
23
|
+
COLOR_WHITE = FFI::NCurses::WHITE
|
24
|
+
COLOR_BLUE = FFI::NCurses::BLUE
|
25
|
+
COLOR_RED = FFI::NCurses::RED
|
26
|
+
COLOR_GREEN = FFI::NCurses::GREEN
|
27
|
+
COLOR_CYAN = FFI::NCurses::CYAN
|
28
|
+
COLOR_MAGENTA = FFI::NCurses::MAGENTA
|
29
|
+
|
30
|
+
## key constants
|
31
|
+
KEY_ENTER = 13 ## FFI::NCurses::KEY_ENTER is 343 ???
|
32
|
+
KEY_RETURN = 10 ## already defined by ffi
|
20
33
|
|
21
34
|
# Initialize ncurses before any program.
|
22
35
|
# Reduce the value of $ncurses_timeout if you want a quicker response to Escape keys or continuous updates.
|
@@ -125,6 +138,19 @@ module Umbra
|
|
125
138
|
return @pointer
|
126
139
|
end
|
127
140
|
|
141
|
+
## create a window and return window, or yield window to block
|
142
|
+
def self.create h=0, w=0, top=0, left=0
|
143
|
+
win = Window.new h, w, top, left
|
144
|
+
return win unless block_given?
|
145
|
+
|
146
|
+
begin
|
147
|
+
yield win
|
148
|
+
ensure
|
149
|
+
win.destroy
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
128
154
|
# print string at x, y coordinates. replace this with the original one below
|
129
155
|
# @deprecated
|
130
156
|
def printstr(str, x=0,y=0)
|
@@ -253,18 +279,36 @@ module Umbra
|
|
253
279
|
end # }}}
|
254
280
|
# make a box around the window. Just a wrapper
|
255
281
|
def box
|
282
|
+
@box = true
|
256
283
|
FFI::NCurses.box(@pointer, 0, 0)
|
257
284
|
end
|
258
|
-
#
|
285
|
+
# Print a centered title on top of window.
|
286
|
+
# NOTE : the string is not stored, so it can be overwritten.
|
259
287
|
# This should be called after box, or else box will erase the title
|
260
288
|
# @param str [String] title to print
|
261
289
|
# @param color [Integer] color_pair
|
262
290
|
# @param att [Integer] attribute constant
|
263
291
|
def title str, color=0, att=BOLD
|
292
|
+
## save so we can repaint if required
|
293
|
+
@title_data = [str, color, att]
|
264
294
|
strl = str.length
|
265
295
|
col = (@width - strl)/2
|
266
296
|
printstring(0,col, str, color, att)
|
267
297
|
end
|
268
298
|
|
299
|
+
## repaints windows objects like title and box.
|
300
|
+
## To be called from form on pressing redraw, and SIGWINCH
|
301
|
+
def repaint
|
302
|
+
curses.wclear(@pointer)
|
303
|
+
if @box
|
304
|
+
self.box
|
305
|
+
end
|
306
|
+
if @title_data
|
307
|
+
str, color, att = @title_data
|
308
|
+
self.title str, color, att
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
|
269
313
|
end # window
|
270
314
|
end # module
|