cdk 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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