cdk 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,614 @@
1
+ require_relative 'cdk_objs'
2
+
3
+ module CDK
4
+ class MENTRY < CDK::CDKOBJS
5
+ attr_accessor :info, :current_col, :current_row, :top_row
6
+ attr_reader :disp_type, :field_width, :rows, :field_win
7
+
8
+ def initialize(cdkscreen, xplace, yplace, title, label, field_attr,
9
+ filler, disp_type, f_width, f_rows, logical_rows, min, box, shadow)
10
+ super()
11
+ parent_width = cdkscreen.window.getmaxx
12
+ parent_height = cdkscreen.window.getmaxy
13
+ field_width = f_width
14
+ field_rows = f_rows
15
+
16
+ self.setBox(box)
17
+
18
+ # If the field_width is a negative value, the field_width will be
19
+ # COLS-field_width, otherwise the field_width will be the given width.
20
+ field_width = CDK.setWidgetDimension(parent_width, field_width, 0)
21
+
22
+ # If the field_rows is a negative value, the field_rows will be
23
+ # ROWS-field_rows, otherwise the field_rows will be the given rows.
24
+ field_rows = CDK.setWidgetDimension(parent_width, field_rows, 0)
25
+ box_height = field_rows + 2
26
+
27
+ # Set some basic values of the mentry field
28
+ @label = ''
29
+ @label_len = 0
30
+ @label_win = nil
31
+
32
+ # We need to translate the string label to a chtype array
33
+ if label.size > 0
34
+ label_len = []
35
+ @label = CDK.char2Chtype(label, label_len, [])
36
+ @label_len = label_len[0]
37
+ end
38
+ box_width = @label_len + field_width + 2
39
+
40
+ old_width = box_width
41
+ box_width = self.setTitle(title, box_width)
42
+ horizontal_adjust = (box_width - old_width) / 2
43
+
44
+ box_height += @title_lines
45
+
46
+ # Make sure we didn't extend beyond the parent window.
47
+ box_width = [box_width, parent_width].min
48
+ box_height = [box_height, parent_height].min
49
+ field_width = [box_width - @label_len - 2, field_width].min
50
+ field_rows = [box_height - @title_lines - 2, field_rows].min
51
+
52
+ # Rejustify the x and y positions if we need to.
53
+ xtmp = [xplace]
54
+ ytmp = [yplace]
55
+ CDK.alignxy(cdkscreen.window, xtmp, ytmp, box_width, box_height)
56
+ xpos = xtmp[0]
57
+ ypos = ytmp[0]
58
+
59
+ # Make the label window.
60
+ @win = Ncurses::WINDOW.new(box_height, box_width, ypos, xpos)
61
+
62
+ # Is the window nil?
63
+ if @win.nil?
64
+ self.destroy
65
+ return nil
66
+ end
67
+
68
+ # Create the label window.
69
+ if @label.size > 0
70
+ @label_win = @win.subwin(field_rows, @label_len + 2,
71
+ ypos + @title_lines + 1, xpos + horizontal_adjust + 1)
72
+ end
73
+
74
+ # make the field window.
75
+ @field_win = @win.subwin(field_rows, field_width,
76
+ ypos + @title_lines + 1, xpos + @label_len + horizontal_adjust + 1)
77
+
78
+ # Turn on the keypad.
79
+ @field_win.keypad(true)
80
+ @win.keypad(true)
81
+
82
+ # Set up the rest of the structure.
83
+ @parent = cdkscreen.window
84
+ @total_width = (field_width * logical_rows) + 1
85
+
86
+ # Create the info string
87
+ @info = ''
88
+
89
+ # Set up the rest of the widget information.
90
+ @screen = cdkscreen
91
+ @shadow_win = nil
92
+ @field_attr = field_attr
93
+ @field_width = field_width
94
+ @rows = field_rows
95
+ @box_height = box_height
96
+ @box_width = box_width
97
+ @filler = filler.ord
98
+ @hidden = filler.ord
99
+ @input_window = @win
100
+ @accepts_focus = true
101
+ @current_row = 0
102
+ @current_col = 0
103
+ @top_row = 0
104
+ @shadow = shadow
105
+ @disp_type = disp_type
106
+ @min = min
107
+ @logical_rows = logical_rows
108
+
109
+ # This is a generic character parser for the mentry field. It is used as
110
+ # a callback function, so any personal modifications can be made by
111
+ # creating a new function and calling that one the mentry activation.
112
+ mentry_callback = lambda do |mentry, character|
113
+ cursor_pos = mentry.getCursorPos
114
+ newchar = Display.filterByDisplayType(mentry.disp_type, character)
115
+
116
+ if newchar == Ncurses::ERR
117
+ CDK.Beep
118
+ else
119
+ mentry.info = mentry.info[0...cursor_pos] + newchar.chr +
120
+ mentry.info[cursor_pos..-1]
121
+ mentry.current_col += 1
122
+
123
+ mentry.drawField
124
+
125
+ # Have we gone out of bounds
126
+ if mentry.current_col >= mentry.field_width
127
+ # Update the row and col values.
128
+ mentry.current_col = 0
129
+ mentry.current_row += 1
130
+
131
+ # If we have gone outside of the visual boundaries, we
132
+ # need to scroll the window.
133
+ if mentry.current_row == mentry.rows
134
+ # We have to redraw the screen
135
+ mentry.current_row -= 1
136
+ mentry.top_row += 1
137
+ mentry.drawField
138
+ end
139
+ mentry.field_win.wmove(mentry.current_row, mentry.current_col)
140
+ mentry.field_win.wrefresh
141
+ end
142
+ end
143
+ end
144
+ @callbackfn = mentry_callback
145
+
146
+ # Do we need to create a shadow.
147
+ if shadow
148
+ @shadow_win = Ncurses::WINDOW.new(box_height, box_width,
149
+ ypos + 1, xpos + 1)
150
+ end
151
+
152
+ # Register
153
+ cdkscreen.register(:MENTRY, self)
154
+ end
155
+
156
+ # This actually activates the mentry widget...
157
+ def activate(actions)
158
+ input = 0
159
+
160
+ # Draw the mentry widget.
161
+ self.draw(@box)
162
+
163
+ if actions.size == 0
164
+ while true
165
+ input = self.getch([])
166
+
167
+ # Inject this character into the widget.
168
+ ret = self.inject(input)
169
+ if @exit_type != :EARLY_EXIT
170
+ return ret
171
+ end
172
+ end
173
+ else
174
+ actions.each do |action|
175
+ ret = self.inject(action)
176
+ if @exit_type != :EARLY_EXIT
177
+ return ret
178
+ end
179
+ end
180
+ end
181
+
182
+ # Set the exit type and exit.
183
+ self.setExitType(0)
184
+ return 0
185
+ end
186
+
187
+ def setTopRow(row)
188
+ if @top_row != row
189
+ @top_row = row
190
+ return true
191
+ end
192
+ return false
193
+ end
194
+
195
+ def setCurPos(row, col)
196
+ if @current_row != row || @current_col != col
197
+ @current_row = row
198
+ @current_col = col
199
+ return true
200
+ end
201
+ return false
202
+ end
203
+
204
+ def KEY_LEFT(moved, redraw)
205
+ result = true
206
+ if @current_col != 0
207
+ moved[0] = self.setCurPos(@current_row, @current_col - 1)
208
+ elsif @current_row == 0
209
+ if @top_row != 0
210
+ moved[0] = self.setCurPos(@current_row, @field_width - 1)
211
+ redraw[0] = self.setTopRow(@top_row - 1)
212
+ end
213
+ else
214
+ moved[0] = self.setCurPos(@current_row - 1, @field_width - 1)
215
+ end
216
+
217
+ if !moved[0] && !redraw[0]
218
+ CDK.Beep
219
+ result = false
220
+ end
221
+ return result
222
+ end
223
+
224
+ def getCursorPos
225
+ return (@current_row + @top_row) * @field_width + @current_col
226
+ end
227
+
228
+ # This injects a character into the widget.
229
+ def inject(input)
230
+ cursor_pos = self.getCursorPos
231
+ pp_return = 1
232
+ ret = -1
233
+ complete = false
234
+
235
+ # Set the exit type.
236
+ self.setExitType(0)
237
+
238
+ # Refresh the field.
239
+ self.drawField
240
+
241
+ # Check if there is a pre-process function to be called.
242
+ unless @pre_process_func.nil?
243
+ # Call the pre-process function
244
+ pp_return = @pre_process_func.call(:MENTRY, self,
245
+ @pre_process_data, input)
246
+ end
247
+
248
+ # Should we continue?
249
+ if pp_return != 0
250
+ # Check for a key binding...
251
+ if self.checkBind(:MENTRY, input)
252
+ complete = true
253
+ else
254
+ moved = false
255
+ redraw = false
256
+
257
+ case input
258
+ when Ncurses::KEY_HOME
259
+ moved = self.setCurPos(0, 0)
260
+ redraw = self.setTopRow(0)
261
+ when Ncurses::KEY_END
262
+ field_characters = @rows * @field_width
263
+ if @info.size < field_characters
264
+ redraw = self.setTopRow(0)
265
+ moved = self.setCurPos(
266
+ @info.size / @field_width, @info.size % @field_width)
267
+ else
268
+ redraw = self.setTopRow(@info.size / @field_width, @rows + 1)
269
+ moved = self.setCurPos(@rows - 1, @info.size % @field_width)
270
+ end
271
+ when Ncurses::KEY_LEFT
272
+ mtmp = [moved]
273
+ rtmp = [redraw]
274
+ self.KEY_LEFT(mtmp, rtmp)
275
+ moved = mtmp[0]
276
+ redraw = rtmp[0]
277
+ when Ncurses::KEY_RIGHT
278
+ if @current_col < @field_width - 1
279
+ if self.getCursorPos + 1 <= @info.size
280
+ moved = self.setCurPos(@current_row, @current_col + 1)
281
+ end
282
+ elsif @current_row == @rows - 1
283
+ if @top_row + @current_row + 1 < @logical_rows
284
+ moved = self.setCurPos(@current_row, 0)
285
+ redraw = self.setTopRow(@top_row + 1)
286
+ end
287
+ else
288
+ moved = self.setCurPos(@current_row + 1, 0)
289
+ end
290
+ if !moved && !redraw
291
+ CDK.Beep
292
+ end
293
+ when Ncurses::KEY_DOWN
294
+ if @current_row != @rows - 1
295
+ if self.getCursorPos + @field_width + 1 <= @info.size
296
+ moved = self.setCurPos(@current_row + 1, @current_col)
297
+ end
298
+ elsif @top_row < @logical_rows - @rows
299
+ if (@top_row + @current_row + 1) * @field_width <= @info.size
300
+ redraw = self.setTopRow(@top_row + 1)
301
+ end
302
+ end
303
+ if !moved && !redraw
304
+ CDK.Beep
305
+ end
306
+ when Ncurses::KEY_UP
307
+ if @current_row != 0
308
+ moved = self.setCurPos(@current_row - 1, @current_col)
309
+ elsif @top_row != 0
310
+ redraw = self.setTopRow(@top_row - 1)
311
+ end
312
+ if !moved && !redraw
313
+ CDK.Beep
314
+ end
315
+ when Ncurses::KEY_BACKSPACE, Ncurses::KEY_DC
316
+ if @disp_type == :VIEWONLY
317
+ CDK.Beep
318
+ elsif @info.length == 0
319
+ CDK.Beep
320
+ elsif input == Ncurses::KEY_DC
321
+ cursor_pos = self.getCursorPos
322
+ if cursor_pos < @info.size
323
+ @info = @info[0...cursor_pos] + @info[cursor_pos + 1..-1]
324
+ self.drawField
325
+ else
326
+ CDK.Beep
327
+ end
328
+ else
329
+ mtmp = [moved]
330
+ rtmp = [redraw]
331
+ hKL = self.KEY_LEFT(mtmp, rtmp)
332
+ moved = mtmp[0]
333
+ rtmp = [redraw]
334
+ if hKL
335
+ cursor_pos = self.getCursorPos
336
+ if cursor_pos < @info.size
337
+ @info = @info[0...cursor_pos] + @info[cursor_pos + 1..-1]
338
+ self.drawField
339
+ else
340
+ CDK.Beep
341
+ end
342
+ end
343
+ end
344
+ when CDK::TRANSPOSE
345
+ if cursor_pos >= @info.size - 1
346
+ CDK.Beep
347
+ else
348
+ holder = @info[cursor_pos]
349
+ @info[cursor_pos] = @info[cursor_pos + 1]
350
+ @info[cursor_pos + 1] = holder
351
+ self.drawField
352
+ end
353
+ when CDK::ERASE
354
+ if @info.size != 0
355
+ self.clean
356
+ self.drawField
357
+ end
358
+ when CDK::CUT
359
+ if @info.size == 0
360
+ CDK.Beep
361
+ else
362
+ @@g_paste_buffer = @info.clone
363
+ self.clean
364
+ self.drawField
365
+ end
366
+ when CDK::COPY
367
+ if @info.size == 0
368
+ CDK.Beep
369
+ else
370
+ @@g_paste_buffer = @info.clone
371
+ end
372
+ when CDK::PASTE
373
+ if @@g_paste_buffer.size == 0
374
+ CDK.Beep
375
+ else
376
+ self.setValue(@@g_paste_buffer)
377
+ self.draw(@box)
378
+ end
379
+ when CDK::KEY_TAB, CDK::KEY_RETURN, Ncurses::KEY_ENTER
380
+ if @info.size < @min + 1
381
+ CDK.Beep
382
+ else
383
+ self.setExitType(input)
384
+ ret = @info
385
+ complete = true
386
+ end
387
+ when Ncurses::ERR
388
+ self.setExitType(input)
389
+ complete = true
390
+ when CDK::KEY_ESC
391
+ self.setExitType(input)
392
+ complete = true
393
+ when CDK::REFRESH
394
+ @screen.erase
395
+ @screen.refresh
396
+ else
397
+ if @disp_type == :VIEWONLY || @info.size >= @total_width
398
+ CDK.Beep
399
+ else
400
+ @callbackfn.call(self, input)
401
+ end
402
+ end
403
+
404
+ if redraw
405
+ self.drawField
406
+ elsif moved
407
+ @field_win.wmove(@current_row, @current_col)
408
+ @field_win.wrefresh
409
+ end
410
+ end
411
+
412
+ # Should we do a post-process?
413
+ if !complete && !(@post_process_func.nil?)
414
+ @post_process_func.call(:MENTRY, self, @post_process_data, input)
415
+ end
416
+ end
417
+
418
+ if !complete
419
+ self.setExitType(0)
420
+ end
421
+
422
+ @result_data = ret
423
+ return ret
424
+ end
425
+
426
+ # This moves the mentry field to the given location.
427
+ def move(xplace, yplace, relative, refresh_flag)
428
+ windows = [@win, @field_win, @label_win, @shadow_win]
429
+ self.move_specific(xplace, yplace, relative, refresh_flag,
430
+ windows, [])
431
+ end
432
+
433
+ # This function redraws the multiple line entry field.
434
+ def drawField
435
+ currchar = @field_width * @top_row
436
+
437
+ self.drawTitle(@win)
438
+ @win.wrefresh
439
+
440
+ lastpos = @info.size
441
+
442
+ # Start redrawing the fields.
443
+ (0...@rows).each do |x|
444
+ (0...@field_width).each do |y|
445
+ if currchar < lastpos
446
+ if Display.isHiddenDisplayType(@disp_type)
447
+ @field_win.mvwaddch(x, y, @filler)
448
+ else
449
+ @field_win.mvwaddch(x, y, @info[currchar].ord | @field_attr)
450
+ currchar += 1
451
+ end
452
+ else
453
+ @field_win.mvwaddch(x, y, @filler)
454
+ end
455
+ end
456
+ end
457
+
458
+ # Refresh the screen.
459
+ @field_win.wmove(@current_row, @current_col)
460
+ @field_win.wrefresh
461
+ end
462
+
463
+ # This function draws the multiple line entry field.
464
+ def draw(box)
465
+ # Box the widget if asked.
466
+ if box
467
+ Draw.drawObjBox(@win, self)
468
+ @win.wrefresh
469
+ end
470
+
471
+ # Do we need to draw in the shadow?
472
+ unless @shadow_win.nil?
473
+ Draw.drawShadow(@shadow_win)
474
+ end
475
+
476
+ # Draw in the label to the widget.
477
+ unless @label_win.nil?
478
+ Draw.writeChtype(@label_win, 0, 0, @label, CDK::HORIZONTAL,
479
+ 0, @label_len)
480
+ @label_win.wrefresh
481
+ end
482
+
483
+ # Draw the mentry field
484
+ self.drawField
485
+ end
486
+
487
+ # This sets the background attribute of the widget.
488
+ def setBKattr(attrib)
489
+ @win.wbkgd(attrib)
490
+ @field_win.wbkgd(attrib)
491
+ unless @label_win.nil?
492
+ @label_win.wbkgd(attrib)
493
+ end
494
+ end
495
+
496
+ # This function erases the multiple line entry field from the screen.
497
+ def erase
498
+ if self.validCDKObject
499
+ CDK.eraseCursesWindow(@field_win)
500
+ CDK.eraseCursesWindow(@label_win)
501
+ CDK.eraseCursesWindow(@win)
502
+ CDK.eraseCursesWindow(@shadow_win)
503
+ end
504
+ end
505
+
506
+ # This function destroys a multiple line entry field widget.
507
+ def destroy
508
+ self.cleanTitle
509
+
510
+ # Clean up the windows.
511
+ CDK.deleteCursesWindow(@field_win)
512
+ CDK.deleteCursesWindow(@label_win)
513
+ CDK.deleteCursesWindow(@shadow_win)
514
+ CDK.deleteCursesWindow(@win)
515
+
516
+ # Clean the key bindings.
517
+ self.cleanBindings(:MENTRY)
518
+
519
+ # Unregister this object.
520
+ CDK::SCREEN.unregister(:MENTRY, self)
521
+ end
522
+
523
+ # This sets multiple attributes of the widget.
524
+ def set(value, min, box)
525
+ self.setValue(value)
526
+ self.setMin(min)
527
+ self.setBox(box)
528
+ end
529
+
530
+ # This removes the old information in the entry field and keeps the
531
+ # new information given.
532
+ def setValue(new_value)
533
+ field_characters = @rows * @field_width
534
+
535
+ @info = new_value
536
+
537
+ # Set the cursor/row info
538
+ if new_value.size < field_characters
539
+ @top_row = 0
540
+ @current_row = new_value.size / @field_width
541
+ @current_col = new_value.size % @field_width
542
+ else
543
+ row_used = new_value.size / @field_width
544
+ @top_row = row_used - @rows + 1
545
+ @current_row = @rows - 1
546
+ @current_col = new_value.size % @field_width
547
+ end
548
+
549
+ # Redraw the widget.
550
+ self.drawField
551
+ end
552
+
553
+ def getValue
554
+ return @info
555
+ end
556
+
557
+ # This sets the filler character to use when drawing the widget.
558
+ def setFillerChar(filler)
559
+ @filler = filler.ord
560
+ end
561
+
562
+ def getFillerChar
563
+ return @filler
564
+ end
565
+
566
+ # This sets the character to use when a hidden character type is used
567
+ def setHiddenChar(character)
568
+ @hidden = character
569
+ end
570
+
571
+ def getHiddenChar
572
+ return @hidden
573
+ end
574
+
575
+ # This sets a minimum length of the widget.
576
+ def setMin(min)
577
+ @min = min
578
+ end
579
+
580
+ def getMin
581
+ return @min
582
+ end
583
+
584
+ # This erases the information in the multiple line entry widget
585
+ def clean
586
+ @info = ''
587
+ @current_row = 0
588
+ @current_col = 0
589
+ @top_row = 0
590
+ end
591
+
592
+ # This sets the callback function.
593
+ def setCB(callback)
594
+ @callbackfn = callback
595
+ end
596
+
597
+ def focus
598
+ @field_win.wmove(0, @current_col)
599
+ @field_win.wrefresh
600
+ end
601
+
602
+ def unfocus
603
+ @field_win.wrefresh
604
+ end
605
+
606
+ def position
607
+ super(@win)
608
+ end
609
+
610
+ def object_type
611
+ :MENTRY
612
+ end
613
+ end
614
+ end