cdk 0.9.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/lib/cdk.rb +916 -0
- data/lib/cdk/alphalist.rb +562 -0
- data/lib/cdk/buttonbox.rb +354 -0
- data/lib/cdk/calendar.rb +770 -0
- data/lib/cdk/cdk_objs.rb +463 -0
- data/lib/cdk/dialog.rb +727 -0
- data/lib/cdk/display.rb +63 -0
- data/lib/cdk/draw.rb +233 -0
- data/lib/cdk/dscale.rb +13 -0
- data/lib/cdk/entry.rb +556 -0
- data/lib/cdk/fscale.rb +44 -0
- data/lib/cdk/fselect.rb +940 -0
- data/lib/cdk/fslider.rb +61 -0
- data/lib/cdk/histogram.rb +410 -0
- data/lib/cdk/itemlist.rb +475 -0
- data/lib/cdk/label.rb +207 -0
- data/lib/cdk/marquee.rb +241 -0
- data/lib/cdk/matrix.rb +1176 -0
- data/lib/cdk/mentry.rb +614 -0
- data/lib/cdk/menu.rb +448 -0
- data/lib/cdk/radio.rb +533 -0
- data/lib/cdk/scale.rb +525 -0
- data/lib/cdk/screen.rb +280 -0
- data/lib/cdk/scroll.rb +994 -0
- data/lib/cdk/scroller.rb +183 -0
- data/lib/cdk/selection.rb +619 -0
- data/lib/cdk/slider.rb +541 -0
- data/lib/cdk/swindow.rb +762 -0
- data/lib/cdk/template.rb +562 -0
- data/lib/cdk/traverse.rb +289 -0
- data/lib/cdk/uscale.rb +14 -0
- data/lib/cdk/uslider.rb +14 -0
- data/lib/cdk/viewer.rb +812 -0
- metadata +91 -0
data/lib/cdk/template.rb
ADDED
@@ -0,0 +1,562 @@
|
|
1
|
+
require_relative 'cdk_objs'
|
2
|
+
|
3
|
+
module CDK
|
4
|
+
class TEMPLATE < CDK::CDKOBJS
|
5
|
+
def initialize(cdkscreen, xplace, yplace, title, label, plate,
|
6
|
+
overlay, box, shadow)
|
7
|
+
super()
|
8
|
+
parent_width = cdkscreen.window.getmaxx
|
9
|
+
parent_height = cdkscreen.window.getmaxy
|
10
|
+
box_width = 0
|
11
|
+
box_height = if box then 3 else 1 end
|
12
|
+
plate_len = 0
|
13
|
+
|
14
|
+
if plate.nil? || plate.size == 0
|
15
|
+
return nil
|
16
|
+
end
|
17
|
+
|
18
|
+
self.setBox(box)
|
19
|
+
|
20
|
+
field_width = plate.size + 2 * @border_size
|
21
|
+
|
22
|
+
# Set some basic values of the template field.
|
23
|
+
@label = []
|
24
|
+
@label_len = 0
|
25
|
+
@label_win = nil
|
26
|
+
|
27
|
+
# Translate the label string to achtype array
|
28
|
+
if !(label.nil?) && label.size > 0
|
29
|
+
label_len = []
|
30
|
+
@label = CDK.char2Chtype(label, label_len, [])
|
31
|
+
@label_len = label_len[0]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Translate the char * overlay to a chtype array
|
35
|
+
if !(overlay.nil?) && overlay.size > 0
|
36
|
+
overlay_len = []
|
37
|
+
@overlay = CDK.char2Chtype(overlay, overlay_len, [])
|
38
|
+
@overlay_len = overlay_len[0]
|
39
|
+
@field_attr = @overlay[0] & Ncurses::A_ATTRIBUTES
|
40
|
+
else
|
41
|
+
@overlay = []
|
42
|
+
@overlay_len = 0
|
43
|
+
@field_attr = Ncurses::A_NORMAL
|
44
|
+
end
|
45
|
+
|
46
|
+
# Set the box width.
|
47
|
+
box_width = field_width + @label_len + 2 * @border_size
|
48
|
+
|
49
|
+
old_width = box_width
|
50
|
+
box_width = self.setTitle(title, box_width)
|
51
|
+
horizontal_adjust = (box_width - old_width) / 2
|
52
|
+
|
53
|
+
box_height += @title_lines
|
54
|
+
|
55
|
+
# Make sure we didn't extend beyond the dimensions of the window.
|
56
|
+
box_width = [box_width, parent_width].min
|
57
|
+
box_height = [box_height, parent_height].min
|
58
|
+
field_width = [field_width,
|
59
|
+
box_width - @label_len - 2 * @border_size].min
|
60
|
+
|
61
|
+
# Rejustify the x and y positions if we need to.
|
62
|
+
xtmp = [xplace]
|
63
|
+
ytmp = [yplace]
|
64
|
+
CDK.alignxy(cdkscreen.window, xtmp, ytmp, box_width, box_height)
|
65
|
+
xpos = xtmp[0]
|
66
|
+
ypos = ytmp[0]
|
67
|
+
|
68
|
+
# Make the template window
|
69
|
+
@win = Ncurses::WINDOW.new(box_height, box_width, ypos, xpos)
|
70
|
+
|
71
|
+
# Is the template window nil?
|
72
|
+
if @win.nil?
|
73
|
+
self.destroy
|
74
|
+
return nil
|
75
|
+
end
|
76
|
+
@win.keypad(true)
|
77
|
+
|
78
|
+
# Make the label window.
|
79
|
+
if label.size > 0
|
80
|
+
@label_win = @win.subwin(1, @label_len,
|
81
|
+
ypos + @title_lines + @border_size,
|
82
|
+
xpos + horizontal_adjust + @border_size)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Make the field window
|
86
|
+
@field_win = @win.subwin(1, field_width,
|
87
|
+
ypos + @title_lines + @border_size,
|
88
|
+
xpos + @label_len + horizontal_adjust + @border_size)
|
89
|
+
@field_win.keypad(true)
|
90
|
+
|
91
|
+
# Set up the info field.
|
92
|
+
@plate_len = plate.size
|
93
|
+
@info = ''
|
94
|
+
# Copy the plate to the template
|
95
|
+
@plate = plate.clone
|
96
|
+
|
97
|
+
# Set up the rest of the structure.
|
98
|
+
@screen = cdkscreen
|
99
|
+
@parent = cdkscreen.window
|
100
|
+
@shadow_win = nil
|
101
|
+
@field_width = field_width
|
102
|
+
@box_height = box_height
|
103
|
+
@box_width = box_width
|
104
|
+
@plate_pos = 0
|
105
|
+
@screen_pos = 0
|
106
|
+
@info_pos = 0
|
107
|
+
@min = 0
|
108
|
+
@input_window = @win
|
109
|
+
@accepts_focus = true
|
110
|
+
@shadow = shadow
|
111
|
+
@callbackfn = lambda do |template, input|
|
112
|
+
failed = false
|
113
|
+
change = false
|
114
|
+
moveby = false
|
115
|
+
amount = 0
|
116
|
+
mark = @info_pos
|
117
|
+
have = @info.size
|
118
|
+
|
119
|
+
if input == Ncurses::KEY_LEFT
|
120
|
+
if mark != 0
|
121
|
+
moveby = true
|
122
|
+
amount = -1
|
123
|
+
else
|
124
|
+
failed = true
|
125
|
+
end
|
126
|
+
elsif input == Ncurses::KEY_RIGHT
|
127
|
+
if mark < @info.size
|
128
|
+
moveby = true
|
129
|
+
amount = 1
|
130
|
+
else
|
131
|
+
failed = true
|
132
|
+
end
|
133
|
+
else
|
134
|
+
test = @info.clone
|
135
|
+
if input == Ncurses::KEY_BACKSPACE
|
136
|
+
if mark != 0
|
137
|
+
front = @info[0...mark-1] || ''
|
138
|
+
back = @info[mark..-1] || ''
|
139
|
+
test = front + back
|
140
|
+
change = true
|
141
|
+
amount = -1
|
142
|
+
else
|
143
|
+
failed = true
|
144
|
+
end
|
145
|
+
elsif input == Ncurses::KEY_DC
|
146
|
+
if mark < @info.size
|
147
|
+
front = @info[0...mark] || ''
|
148
|
+
back = @info[mark+1..-1] || ''
|
149
|
+
test = front + back
|
150
|
+
change = true
|
151
|
+
amount = 0
|
152
|
+
else
|
153
|
+
failed = true
|
154
|
+
end
|
155
|
+
elsif CDK.isChar(input) && @plate_pos < @plate.size
|
156
|
+
test[mark] = input.chr
|
157
|
+
change = true
|
158
|
+
amount = 1
|
159
|
+
else
|
160
|
+
failed = true
|
161
|
+
end
|
162
|
+
|
163
|
+
if change
|
164
|
+
if self.validTemplate(test)
|
165
|
+
@info = test
|
166
|
+
self.drawField
|
167
|
+
else
|
168
|
+
failed = true
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
if failed
|
174
|
+
CDK.Beep
|
175
|
+
elsif change || moveby
|
176
|
+
@info_pos += amount
|
177
|
+
@plate_pos += amount
|
178
|
+
@screen_pos += amount
|
179
|
+
|
180
|
+
self.adjustCursor(amount)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Do we need to create a shadow?
|
185
|
+
if shadow
|
186
|
+
@shadow_win = Ncurses::WINDOW.new(box_height, box_width,
|
187
|
+
ypos + 1, xpos + 1)
|
188
|
+
end
|
189
|
+
|
190
|
+
cdkscreen.register(:TEMPLATE, self)
|
191
|
+
end
|
192
|
+
|
193
|
+
# This actually manages the tempalte widget
|
194
|
+
def activate(actions)
|
195
|
+
self.draw(@box)
|
196
|
+
|
197
|
+
if actions.nil? || actions.size == 0
|
198
|
+
while true
|
199
|
+
input = self.getch([])
|
200
|
+
|
201
|
+
# Inject each character into the widget.
|
202
|
+
ret = self.inject(input)
|
203
|
+
if @exit_type != :EARLY_EXIT
|
204
|
+
return ret
|
205
|
+
end
|
206
|
+
end
|
207
|
+
else
|
208
|
+
# Inject each character one at a time.
|
209
|
+
actions.each do |action|
|
210
|
+
ret = self.inject(action)
|
211
|
+
if @exit_type != :EARLY_EXIT
|
212
|
+
return ret
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Set the exit type and return.
|
218
|
+
self.setExitType(0)
|
219
|
+
return ret
|
220
|
+
end
|
221
|
+
|
222
|
+
# This injects a character into the widget.
|
223
|
+
def inject(input)
|
224
|
+
pp_return = 1
|
225
|
+
complete = false
|
226
|
+
ret = -1
|
227
|
+
|
228
|
+
self.setExitType(0)
|
229
|
+
|
230
|
+
# Move the cursor.
|
231
|
+
self.drawField
|
232
|
+
|
233
|
+
# Check if there is a pre-process function to be called.
|
234
|
+
unless @pre_process_func.nil?
|
235
|
+
pp_return = @pre_process_func.call(:TEMPLATE, self,
|
236
|
+
@pre_process_data, input)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Should we continue?
|
240
|
+
if pp_return != 0
|
241
|
+
# Check a predefined binding
|
242
|
+
if self.checkBind(:TEMPLATE, input)
|
243
|
+
complete = true
|
244
|
+
else
|
245
|
+
case input
|
246
|
+
when CDK::ERASE
|
247
|
+
if @info.size > 0
|
248
|
+
self.clean
|
249
|
+
self.drawField
|
250
|
+
end
|
251
|
+
when CDK::CUT
|
252
|
+
if @info.size > 0
|
253
|
+
@@g_paste_buffer = @info.clone
|
254
|
+
self.clean
|
255
|
+
self.drawField
|
256
|
+
else
|
257
|
+
CDK.Beep
|
258
|
+
end
|
259
|
+
when CDK::COPY
|
260
|
+
if @info.size > 0
|
261
|
+
@@g_paste_buffer = @info.clone
|
262
|
+
else
|
263
|
+
CDK.Beep
|
264
|
+
end
|
265
|
+
when CDK::PASTE
|
266
|
+
if @@g_paste_buffer.size > 0
|
267
|
+
self.clean
|
268
|
+
|
269
|
+
# Start inserting each character one at a time.
|
270
|
+
(0...@@g_paste_buffer.size).each do |x|
|
271
|
+
@callbackfn.call(self, @@g_paste_buffer[x])
|
272
|
+
end
|
273
|
+
self.drawField
|
274
|
+
else
|
275
|
+
CDK.Beep
|
276
|
+
end
|
277
|
+
when CDK::KEY_TAB, CDK::KEY_RETURN, Ncurses::KEY_ENTER
|
278
|
+
if @info.size < @min
|
279
|
+
CDK.Beep
|
280
|
+
else
|
281
|
+
self.setExitType(input)
|
282
|
+
ret = @info
|
283
|
+
complete = true
|
284
|
+
end
|
285
|
+
when CDK::KEY_ESC
|
286
|
+
self.setExitType(input)
|
287
|
+
complete = true
|
288
|
+
when Ncurses::ERR
|
289
|
+
self.setExitType(input)
|
290
|
+
complete = true
|
291
|
+
when CDK::REFRESH
|
292
|
+
@screen.erase
|
293
|
+
@screen.refresh
|
294
|
+
else
|
295
|
+
@callbackfn.call(self, input)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
# Should we call a post-process?
|
300
|
+
if !complete && !(@post_process_func.nil?)
|
301
|
+
@post_process_func.call(:TEMPLATE, self, @post_process_data, input)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
if !complete
|
306
|
+
self.setExitType(0)
|
307
|
+
end
|
308
|
+
|
309
|
+
@return_data = ret
|
310
|
+
return ret
|
311
|
+
end
|
312
|
+
|
313
|
+
def validTemplate(input)
|
314
|
+
pp = 0
|
315
|
+
ip = 0
|
316
|
+
while ip < input.size && pp < @plate.size
|
317
|
+
newchar = input[ip]
|
318
|
+
while pp < @plate.size && !CDK::TEMPLATE.isPlateChar(@plate[pp])
|
319
|
+
pp += 1
|
320
|
+
end
|
321
|
+
if pp == @plate.size
|
322
|
+
return false
|
323
|
+
end
|
324
|
+
|
325
|
+
# Check if the input matches the plate
|
326
|
+
if CDK.digit?(newchar) && 'ACc'.include?(@plate[pp])
|
327
|
+
return false
|
328
|
+
end
|
329
|
+
if !CDK.digit?(newchar) && @plate[pp] == '#'
|
330
|
+
return false
|
331
|
+
end
|
332
|
+
|
333
|
+
# Do we need to convert the case?
|
334
|
+
if @plate[pp] == 'C' || @plate[pp] == 'X'
|
335
|
+
newchar = newchar.upcase
|
336
|
+
elsif @plate[pp] == 'c' || @plate[pp] == 'x'
|
337
|
+
newchar = newchar.downcase
|
338
|
+
end
|
339
|
+
input[ip] = newchar
|
340
|
+
ip += 1
|
341
|
+
pp += 1
|
342
|
+
end
|
343
|
+
return true
|
344
|
+
end
|
345
|
+
|
346
|
+
# Return a mixture of the plate-overlay and field-info
|
347
|
+
def mix
|
348
|
+
mixed_string = ''
|
349
|
+
plate_pos = 0
|
350
|
+
info_pos = 0
|
351
|
+
|
352
|
+
if @info.size > 0
|
353
|
+
mixed_string = ''
|
354
|
+
while plate_pos < @plate_len && info_pos < @info.size
|
355
|
+
mixed_string << if CDK::TEMPLATE.isPlateChar(@plate[plate_pos])
|
356
|
+
then info_pos += 1; @info[info_pos - 1]
|
357
|
+
else @plate[plate_pos]
|
358
|
+
end
|
359
|
+
plate_pos += 1
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
return mixed_string
|
364
|
+
end
|
365
|
+
|
366
|
+
# Return the field_info from the mixed string.
|
367
|
+
def unmix(info)
|
368
|
+
pos = 0
|
369
|
+
unmixed_string = ''
|
370
|
+
|
371
|
+
while pos < @info.size
|
372
|
+
if CDK::TEMPLATE.isPlateChar(@plate[pos])
|
373
|
+
unmixed_string << info[pos]
|
374
|
+
end
|
375
|
+
pos += 1
|
376
|
+
end
|
377
|
+
|
378
|
+
return unmixed_string
|
379
|
+
end
|
380
|
+
|
381
|
+
# Move the template field to the given location.
|
382
|
+
def move(xplace, yplace, relative, refresh_flag)
|
383
|
+
windows = [@win, @label_win, @field_win, @shadow_win]
|
384
|
+
self.move_specific(xplace, yplace, relative, refresh_flag,
|
385
|
+
windows, [])
|
386
|
+
end
|
387
|
+
|
388
|
+
# Draw the template widget.
|
389
|
+
def draw(box)
|
390
|
+
# Do we need to draw the shadow.
|
391
|
+
unless @shadow_win.nil?
|
392
|
+
Draw.drawShadow(@shadow_win)
|
393
|
+
end
|
394
|
+
|
395
|
+
# Box it if needed
|
396
|
+
if box
|
397
|
+
Draw.drawObjBox(@win, self)
|
398
|
+
end
|
399
|
+
|
400
|
+
self.drawTitle(@win)
|
401
|
+
|
402
|
+
@win.wrefresh
|
403
|
+
|
404
|
+
self.drawField
|
405
|
+
end
|
406
|
+
|
407
|
+
# Draw the template field
|
408
|
+
def drawField
|
409
|
+
field_color = 0
|
410
|
+
|
411
|
+
# Draw in the label and the template object.
|
412
|
+
unless @label_win.nil?
|
413
|
+
Draw.writeChtype(@label_win, 0, 0, @label, CDK::HORIZONTAL,
|
414
|
+
0, @label_len)
|
415
|
+
@label_win.wrefresh
|
416
|
+
end
|
417
|
+
|
418
|
+
# Draw in the template
|
419
|
+
if @overlay.size > 0
|
420
|
+
Draw.writeChtype(@field_win, 0, 0, @overlay, CDK::HORIZONTAL,
|
421
|
+
0, @overlay_len)
|
422
|
+
end
|
423
|
+
|
424
|
+
# Adjust the cursor.
|
425
|
+
if @info.size > 0
|
426
|
+
pos = 0
|
427
|
+
(0...[@field_width, @plate.size].min).each do |x|
|
428
|
+
if CDK::TEMPLATE.isPlateChar(@plate[x]) && pos < @info.size
|
429
|
+
field_color = @overlay[x] & Ncurses::A_ATTRIBUTES
|
430
|
+
@field_win.mvwaddch(0, x, @info[pos].ord | field_color)
|
431
|
+
pos += 1
|
432
|
+
end
|
433
|
+
end
|
434
|
+
@field_win.wmove(0, @screen_pos)
|
435
|
+
else
|
436
|
+
self.adjustCursor(1)
|
437
|
+
end
|
438
|
+
@field_win.wrefresh
|
439
|
+
end
|
440
|
+
|
441
|
+
# Adjust the cursor for the template
|
442
|
+
def adjustCursor(direction)
|
443
|
+
while @plate_pos < [@field_width, @plate.size].min &&
|
444
|
+
!CDK::TEMPLATE.isPlateChar(@plate[@plate_pos])
|
445
|
+
@plate_pos += direction
|
446
|
+
@screen_pos += direction
|
447
|
+
end
|
448
|
+
@field_win.wmove(0, @screen_pos)
|
449
|
+
@field_win.wrefresh
|
450
|
+
end
|
451
|
+
|
452
|
+
# Set the background attribute of the widget.
|
453
|
+
def setBKattr(attrib)
|
454
|
+
@win.wbkgd(attrib)
|
455
|
+
@field_win.wbkgd(attrib)
|
456
|
+
unless @label_win.nil?
|
457
|
+
@label_win.wbkgd(attrib)
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
# Destroy this widget.
|
462
|
+
def destroy
|
463
|
+
self.cleanTitle
|
464
|
+
|
465
|
+
# Delete the windows
|
466
|
+
CDK.deleteCursesWindow(@field_win)
|
467
|
+
CDK.deleteCursesWindow(@label_win)
|
468
|
+
CDK.deleteCursesWindow(@shadow_win)
|
469
|
+
CDK.deleteCursesWindow(@win)
|
470
|
+
|
471
|
+
# Clean the key bindings.
|
472
|
+
self.cleanBindings(:TEMPLATE)
|
473
|
+
|
474
|
+
CDK::SCREEN.unregister(:TEMPLATE, self)
|
475
|
+
end
|
476
|
+
|
477
|
+
# Erase the widget.
|
478
|
+
def erase
|
479
|
+
if self.validCDKObject
|
480
|
+
CDK.eraseCursesWindow(@field_win)
|
481
|
+
CDK.eraseCursesWindow(@label_win)
|
482
|
+
CDK.eraseCursesWindow(@shadow_win)
|
483
|
+
CDK.eraseCursesWindow(@win)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
# Set the value given to the template
|
488
|
+
def set(new_value, box)
|
489
|
+
self.setValue(new_value)
|
490
|
+
self.setBox(box)
|
491
|
+
end
|
492
|
+
|
493
|
+
# Set the value given to the template.
|
494
|
+
def setValue(new_value)
|
495
|
+
len = 0
|
496
|
+
|
497
|
+
# Just to be sure, let's make sure the new value isn't nil
|
498
|
+
if new_value.nil?
|
499
|
+
self.clean
|
500
|
+
return
|
501
|
+
end
|
502
|
+
|
503
|
+
# Determine how many characters we need to copy.
|
504
|
+
copychars = [@new_value.size, @field_width, @plate.size].min
|
505
|
+
|
506
|
+
@info = new_value[0...copychars]
|
507
|
+
|
508
|
+
# Use the function which handles the input of the characters.
|
509
|
+
(0...new_value.size).each do |x|
|
510
|
+
@callbackfn.call(self, new_value[x].ord)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
def getValue
|
515
|
+
return @info
|
516
|
+
end
|
517
|
+
|
518
|
+
# Set the minimum number of characters to enter into the widget.
|
519
|
+
def setMin(min)
|
520
|
+
if min >= 0
|
521
|
+
@min = min
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
def getMin
|
526
|
+
return @min
|
527
|
+
end
|
528
|
+
|
529
|
+
# Erase the information in the template widget.
|
530
|
+
def clean
|
531
|
+
@info = ''
|
532
|
+
@screen_pos = 0
|
533
|
+
@info_pos = 0
|
534
|
+
@plaste_pos = 0
|
535
|
+
end
|
536
|
+
|
537
|
+
# Set the callback function for the widget.
|
538
|
+
def setCB(callback)
|
539
|
+
@callbackfn = callback
|
540
|
+
end
|
541
|
+
|
542
|
+
def focus
|
543
|
+
self.draw(@box)
|
544
|
+
end
|
545
|
+
|
546
|
+
def unfocus
|
547
|
+
self.draw(@box)
|
548
|
+
end
|
549
|
+
|
550
|
+
def self.isPlateChar(c)
|
551
|
+
'#ACcMXz'.include?(c.chr)
|
552
|
+
end
|
553
|
+
|
554
|
+
def position
|
555
|
+
super(@win)
|
556
|
+
end
|
557
|
+
|
558
|
+
def object_type
|
559
|
+
:TEMPLATE
|
560
|
+
end
|
561
|
+
end
|
562
|
+
end
|