slithernix-cdk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/cdk/scroll.rb ADDED
@@ -0,0 +1,996 @@
1
+ require_relative 'scroller'
2
+
3
+ module CDK
4
+ class SCROLL < CDK::SCROLLER
5
+ attr_reader :item, :list_size, :current_item, :highlight
6
+
7
+ def initialize (cdkscreen, xplace, yplace, splace, height, width, title,
8
+ list, list_size, numbers, highlight, box, shadow)
9
+ super()
10
+ parent_width = cdkscreen.window.maxx
11
+ parent_height = cdkscreen.window.maxy
12
+ box_width = width
13
+ box_height = height
14
+ xpos = xplace
15
+ ypos = yplace
16
+ scroll_adjust = 0
17
+ bindings = {
18
+ CDK::BACKCHAR => Curses::KEY_PPAGE,
19
+ CDK::FORCHAR => Curses::KEY_NPAGE,
20
+ 'g' => Curses::KEY_HOME,
21
+ '1' => Curses::KEY_HOME,
22
+ 'G' => Curses::KEY_END,
23
+ '<' => Curses::KEY_HOME,
24
+ '>' => Curses::KEY_END
25
+ }
26
+
27
+ self.setBox(box)
28
+
29
+ # If the height is a negative value, the height will be ROWS-height,
30
+ # otherwise the height will be the given height
31
+ box_height = CDK.setWidgetDimension(parent_height, height, 0)
32
+
33
+ # If the width is a negative value, the width will be COLS-width,
34
+ # otherwise the width will be the given width
35
+ box_width = CDK.setWidgetDimension(parent_width, width, 0)
36
+
37
+ box_width = self.setTitle(title, box_width)
38
+
39
+ # Set the box height.
40
+ if @title_lines > box_height
41
+ box_height = @title_lines + [list_size, 8].min + 2 * @border_size
42
+ end
43
+
44
+ # Adjust the box width if there is a scroll bar
45
+ if splace == CDK::LEFT || splace == CDK::RIGHT
46
+ @scrollbar = true
47
+ box_width += 1
48
+ else
49
+ @scrollbar = false
50
+ end
51
+
52
+ # Make sure we didn't extend beyond the dimensions of the window.
53
+ @box_width = if box_width > parent_width
54
+ then parent_width - scroll_adjust
55
+ else box_width
56
+ end
57
+ @box_height = if box_height > parent_height
58
+ then parent_height
59
+ else box_height
60
+ end
61
+
62
+ self.setViewSize(list_size)
63
+
64
+ # Rejustify the x and y positions if we need to.
65
+ xtmp = [xpos]
66
+ ytmp = [ypos]
67
+ CDK.alignxy(cdkscreen.window, xtmp, ytmp, @box_width, @box_height)
68
+ xpos = xtmp[0]
69
+ ypos = ytmp[0]
70
+
71
+ # Make the scrolling window
72
+ @win = Curses::Window.new(@box_height, @box_width, ypos, xpos)
73
+
74
+ # Is the scrolling window null?
75
+ if @win.nil?
76
+ return nil
77
+ end
78
+
79
+ # Turn the keypad on for the window
80
+ @win.keypad(true)
81
+
82
+ # Create the scrollbar window.
83
+ if splace == CDK::RIGHT
84
+ @scrollbar_win = @win.subwin(self.maxViewSize, 1,
85
+ self.SCREEN_YPOS(ypos), xpos + box_width - @border_size - 1)
86
+ elsif splace == CDK::LEFT
87
+ @scrollbar_win = @win.subwin(self.maxViewSize, 1,
88
+ self.SCREEN_YPOS(ypos), self.SCREEN_XPOS(xpos))
89
+ else
90
+ @scrollbar_win = nil
91
+ end
92
+
93
+ # create the list window
94
+ @list_win = @win.subwin(self.maxViewSize,
95
+ box_width - (2 * @border_size) - scroll_adjust,
96
+ self.SCREEN_YPOS(ypos),
97
+ self.SCREEN_XPOS(xpos) + (if splace == CDK::LEFT then 1 else 0 end))
98
+
99
+ # Set the rest of the variables
100
+ @screen = cdkscreen
101
+ @parent = cdkscreen.window
102
+ @shadow_win = nil
103
+ @scrollbar_placement = splace
104
+ @max_left_char = 0
105
+ @left_char = 0
106
+ @highlight = highlight
107
+ # initExitType (scrollp);
108
+ @accepts_focus = true
109
+ @input_window = @win
110
+ @shadow = shadow
111
+
112
+ self.setPosition(0);
113
+
114
+ # Create the scrolling list item list and needed variables.
115
+ if self.createItemList(numbers, list, list_size) <= 0
116
+ return nil
117
+ end
118
+
119
+ # Do we need to create a shadow?
120
+ if shadow
121
+ @shadow_win = Curses::Window.new(@box_height, box_width,
122
+ ypos + 1, xpos + 1)
123
+ end
124
+
125
+ # Set up the key bindings.
126
+ bindings.each do |from, to|
127
+ #self.bind(:SCROLL, from, getc_lambda, to)
128
+ self.bind(:SCROLL, from, :getc, to)
129
+ end
130
+
131
+ cdkscreen.register(:SCROLL, self);
132
+
133
+ return self
134
+ end
135
+
136
+ def object_type
137
+ :SCROLL
138
+ end
139
+
140
+ def position
141
+ super(@win)
142
+ end
143
+
144
+ # Put the cursor on the currently-selected item's row.
145
+ def fixCursorPosition
146
+ scrollbar_adj = if @scrollbar_placement == LEFT then 1 else 0 end
147
+ ypos = self.SCREEN_YPOS(@current_item - @current_top)
148
+ xpos = self.SCREEN_XPOS(0) + scrollbar_adj
149
+
150
+ # Another .move that breaks a bunch of stuff!, BIGLY!!!
151
+ #@input_window.move(ypos, xpos)
152
+ @input_window.refresh
153
+ end
154
+
155
+ # This actually does all the 'real' work of managing the scrolling list.
156
+ def activate(actions)
157
+ # Draw the scrolling list
158
+ self.draw(@box)
159
+
160
+ if actions.nil? || actions.size == 0
161
+ while true
162
+ self.fixCursorPosition
163
+ input = self.getch([])
164
+
165
+ # Inject the character into the widget.
166
+ ret = self.inject(input)
167
+ if @exit_type != :EARLY_EXIT
168
+ return ret
169
+ end
170
+ end
171
+ else
172
+ # Inject each character one at a time.
173
+ actions.each do |action|
174
+ ret = self.inject(action)
175
+ if @exit_type != :EARLY_EXIT
176
+ return ret
177
+ end
178
+ end
179
+ end
180
+
181
+ # Set the exit type for the widget and return
182
+ self.setExitType(0)
183
+ return -1
184
+ end
185
+
186
+ # This injects a single character into the widget.
187
+ def inject(input)
188
+ pp_return = 1
189
+ ret = -1
190
+ complete = false
191
+
192
+ # Set the exit type for the widget.
193
+ self.setExitType(0)
194
+
195
+ # Draw the scrolling list
196
+ self.drawList(@box)
197
+
198
+ #Check if there is a pre-process function to be called.
199
+ unless @pre_process_func.nil?
200
+ pp_return = @pre_process_func.call(:SCROLL, self,
201
+ @pre_process_data, input)
202
+ end
203
+
204
+ # Should we continue?
205
+ if pp_return != 0
206
+ # Check for a predefined key binding.
207
+ if self.checkBind(:SCROLL, input) != false
208
+ #self.checkEarlyExit
209
+ complete = true
210
+ else
211
+ case input
212
+ when Curses::KEY_UP
213
+ self.KEY_UP
214
+ when Curses::KEY_DOWN
215
+ self.KEY_DOWN
216
+ when Curses::KEY_RIGHT
217
+ self.KEY_RIGHT
218
+ when Curses::KEY_LEFT
219
+ self.KEY_LEFT
220
+ when Curses::KEY_PPAGE
221
+ self.KEY_PPAGE
222
+ when Curses::KEY_NPAGE
223
+ self.KEY_NPAGE
224
+ when Curses::KEY_HOME
225
+ self.KEY_HOME
226
+ when Curses::KEY_END
227
+ self.KEY_END
228
+ when '$'
229
+ @left_char = @max_left_char
230
+ when '|'
231
+ @left_char = 0
232
+ when CDK::KEY_ESC
233
+ self.setExitType(input)
234
+ complete = true
235
+ when Curses::Error
236
+ self.setExitType(input)
237
+ complete = true
238
+ when CDK::REFRESH
239
+ @screen.erase
240
+ @screen.refresh
241
+ when CDK::KEY_TAB, Curses::KEY_ENTER, CDK::KEY_RETURN
242
+ self.setExitType(input)
243
+ ret = @current_item
244
+ complete = true
245
+ end
246
+ end
247
+
248
+ if !complete && !(@post_process_func.nil?)
249
+ @post_process_func.call(:SCROLL, self, @post_process_data, input)
250
+ end
251
+ end
252
+
253
+ if !complete
254
+ self.drawList(@box)
255
+ self.setExitType(0)
256
+ end
257
+
258
+ self.fixCursorPosition
259
+ @result_data = ret
260
+
261
+ #return ret != -1
262
+ return ret
263
+ end
264
+
265
+ def getCurrentTop
266
+ return @current_top
267
+ end
268
+
269
+ def setCurrentTop(item)
270
+ if item < 0
271
+ item = 0
272
+ elsif item > @max_top_item
273
+ item = @max_top_item
274
+ end
275
+ @current_top = item
276
+
277
+ self.setPosition(item);
278
+ end
279
+
280
+ # This moves the scroll field to the given location.
281
+ def move(xplace, yplace, relative, refresh_flag)
282
+ windows = [@win, @list_win, @shadow_win, @scrollbar_win]
283
+ self.move_specific(xplace, yplace, relative, refresh_flag,
284
+ windows, [])
285
+ end
286
+
287
+ # This function draws the scrolling list widget.
288
+ def draw(box)
289
+ # Draw in the shadow if we need to.
290
+ unless @shadow_win.nil?
291
+ Draw.drawShadow(@shadow_win)
292
+ end
293
+
294
+ self.drawTitle(@win)
295
+
296
+ # Draw in the scrolling list items.
297
+ self.drawList(box)
298
+ end
299
+
300
+ def drawCurrent
301
+ # Rehighlight the current menu item.
302
+ screen_pos = @item_pos[@current_item] - @left_char
303
+ highlight = if self.has_focus
304
+ then @highlight
305
+ else Curses::A_NORMAL
306
+ end
307
+
308
+ Draw.writeChtypeAttrib(@list_win,
309
+ if screen_pos >= 0 then screen_pos else 0 end,
310
+ @current_high, @item[@current_item], highlight, CDK::HORIZONTAL,
311
+ if screen_pos >= 0 then 0 else 1 - screen_pos end,
312
+ @item_len[@current_item])
313
+ end
314
+
315
+ def drawList(box)
316
+ # If the list is empty, don't draw anything.
317
+ if @list_size > 0
318
+ # Redraw the list
319
+ (0...@view_size).each do |j|
320
+ k = j + @current_top
321
+
322
+ Draw.writeBlanks(@list_win, 0, j, CDK::HORIZONTAL, 0,
323
+ @box_width - (2 * @border_size))
324
+
325
+ # Draw the elements in the scrolling list.
326
+ if k < @list_size
327
+ screen_pos = @item_pos[k] - @left_char
328
+ ypos = j
329
+
330
+ # Write in the correct line.
331
+ Draw.writeChtype(@list_win,
332
+ if screen_pos >= 0 then screen_pos else 1 end,
333
+ ypos, @item[k], CDK::HORIZONTAL,
334
+ if screen_pos >= 0 then 0 else 1 - screen_pos end,
335
+ @item_len[k])
336
+ end
337
+ end
338
+
339
+ self.drawCurrent
340
+
341
+ # Determine where the toggle is supposed to be.
342
+ unless @scrollbar_win.nil?
343
+ @toggle_pos = (@current_item * @step).floor
344
+
345
+ # Make sure the toggle button doesn't go out of bounds.
346
+
347
+ if @toggle_pos >= @scrollbar_win.maxy
348
+ @toggle_pos = @scrollbar_win.maxy - 1
349
+ end
350
+
351
+ # Draw the scrollbar
352
+ @scrollbar_win.mvwvline(0, 0, CDK::ACS_CKBOARD,
353
+ @scrollbar_win.maxy)
354
+ @scrollbar_win.mvwvline(@toggle_pos, 0, ' '.ord | Curses::A_REVERSE,
355
+ @toggle_size)
356
+ end
357
+ end
358
+
359
+ # Box it if needed.
360
+ if box
361
+ Draw.drawObjBox(@win, self)
362
+ end
363
+
364
+ # Refresh the window
365
+ @win.refresh
366
+ end
367
+
368
+ # This sets the background attribute of the widget.
369
+ def setBKattr(attrib)
370
+ @win.wbkgd(attrib)
371
+ @list_win.wbkgd(attrib)
372
+ unless @scrollbar_win.nil?
373
+ @scrollbar_win.wbkgd(attrib)
374
+ end
375
+ end
376
+
377
+ # This function destroys
378
+ def destroy
379
+ self.cleanTitle
380
+
381
+ # Clean up the windows.
382
+ CDK.deleteCursesWindow(@scrollbar_win)
383
+ CDK.deleteCursesWindow(@shadow_win)
384
+ CDK.deleteCursesWindow(@list_win)
385
+ CDK.deleteCursesWindow(@win)
386
+
387
+ # Clean the key bindings.
388
+ self.cleanBindings(:SCROLL)
389
+
390
+ # Unregister this object
391
+ CDK::SCREEN.unregister(:SCROLL, self)
392
+ end
393
+
394
+ # This function erases the scrolling list from the screen.
395
+ def erase
396
+ CDK.eraseCursesWindow(@win)
397
+ CDK.eraseCursesWindow(@shadow_win)
398
+ end
399
+
400
+ def allocListArrays(old_size, new_size)
401
+ result = true
402
+ new_list = Array.new(new_size)
403
+ new_len = Array.new(new_size)
404
+ new_pos = Array.new(new_size)
405
+
406
+ (0...old_size).each do |n|
407
+ new_list[n] = @item[n]
408
+ new_len[n] = @item_len[n]
409
+ new_pos[n] = @item_pos[n]
410
+ end
411
+
412
+ @item = new_list
413
+ @item_len = new_len
414
+ @item_pos = new_pos
415
+
416
+ return result
417
+ end
418
+
419
+ def allocListItem(which, work, used, number, value)
420
+ if number > 0
421
+ value = "%4d. %s" % [number, value]
422
+ end
423
+
424
+ item_len = []
425
+ item_pos = []
426
+ @item[which] = CDK.char2Chtype(value, item_len, item_pos)
427
+ @item_len[which] = item_len[0]
428
+ @item_pos[which] = item_pos[0]
429
+
430
+ @item_pos[which] = CDK.justifyString(@box_width,
431
+ @item_len[which], @item_pos[which])
432
+ return true
433
+ end
434
+
435
+ # This function creates the scrolling list information and sets up the
436
+ # needed variables for the scrolling list to work correctly.
437
+ def createItemList(numbers, list, list_size)
438
+ status = 0
439
+ if list_size > 0
440
+ widest_item = 0
441
+ x = 0
442
+ have = 0
443
+ temp = ''
444
+ if allocListArrays(0, list_size)
445
+ # Create the items in the scrolling list.
446
+ status = 1
447
+ (0...list_size).each do |x|
448
+ number = if numbers then x + 1 else 0 end
449
+ if !self.allocListItem(x, temp, have, number, list[x])
450
+ status = 0
451
+ break
452
+ end
453
+
454
+ widest_item = [@item_len[x], widest_item].max
455
+ end
456
+
457
+ if status
458
+ self.updateViewWidth(widest_item);
459
+
460
+ # Keep the boolean flag 'numbers'
461
+ @numbers = numbers
462
+ end
463
+ end
464
+ else
465
+ status = 1 # null list is ok - for a while
466
+ end
467
+
468
+ return status
469
+ end
470
+
471
+ # This sets certain attributes of the scrolling list.
472
+ def set(list, list_size, numbers, highlight, box)
473
+ self.setItems(list, list_size, numbers)
474
+ self.setHighlight(highlight)
475
+ self.setBox(box)
476
+ end
477
+
478
+ # This sets the scrolling list items
479
+ def setItems(list, list_size, numbers)
480
+ if self.createItemList(numbers, list, list_size) <= 0
481
+ return
482
+ end
483
+
484
+ # Clean up the display.
485
+ (0...@view_size).each do |x|
486
+ Draw.writeBlanks(@win, 1, x, CDK::HORIZONTAL, 0, @box_width - 2);
487
+ end
488
+
489
+ self.setViewSize(list_size)
490
+ self.setPosition(0)
491
+ @left_char = 0
492
+ end
493
+
494
+ def getItems(list)
495
+ (0...@list_size).each do |x|
496
+ list << CDK.chtype2Char(@item[x])
497
+ end
498
+
499
+ return @list_size
500
+ end
501
+
502
+ # This sets the highlight of the scrolling list.
503
+ def setHighlight(highlight)
504
+ @highlight = highlight
505
+ end
506
+
507
+ def getHighlight(highlight)
508
+ return @highlight
509
+ end
510
+
511
+ # Resequence the numbers after an insertion/deletion.
512
+ def resequence
513
+ if @numbers
514
+ (0...@list_size).each do |j|
515
+ target = @item[j]
516
+
517
+ source = "%4d. %s" % [j + 1, ""]
518
+
519
+ k = 0
520
+ while k < source.size
521
+ # handle deletions that change the length of number
522
+ if source[k] == "." && target[k] != "."
523
+ source = source[0...k] + source[k+1..-1]
524
+ end
525
+
526
+ target[k] &= Curses::A_ATTRIBUTES
527
+ target[k] |= source[k].ord
528
+ k += 1
529
+ end
530
+ end
531
+ end
532
+ end
533
+
534
+ def insertListItem(item)
535
+ @item = @item[0..item] + @item[item..-1]
536
+ @item_len = @item_len[0..item] + @item_len[item..-1]
537
+ @item_pos = @item_pos[0..item] + @item_pos[item..-1]
538
+ return true
539
+ end
540
+
541
+ # This adds a single item to a scrolling list, at the end of the list.
542
+ def addItem(item)
543
+ item_number = @list_size
544
+ widest_item = self.WidestItem
545
+ temp = ''
546
+ have = 0
547
+
548
+ if self.allocListArrays(@list_size, @list_size + 1) &&
549
+ self.allocListItem(item_number, temp, have,
550
+ if @numbers then item_number + 1 else 0 end,
551
+ item)
552
+ # Determine the size of the widest item.
553
+ widest_item = [@item_len[item_number], widest_item].max
554
+
555
+ self.updateViewWidth(widest_item)
556
+ self.setViewSize(@list_size + 1)
557
+ end
558
+ end
559
+
560
+ # This adds a single item to a scrolling list before the current item
561
+ def insertItem(item)
562
+ widest_item = self.WidestItem
563
+ temp = ''
564
+ have = 0
565
+
566
+ if self.allocListArrays(@list_size, @list_size + 1) &&
567
+ self.insertListItem(@current_item) &&
568
+ self.allocListItem(@current_item, temp, have,
569
+ if @numbers then @current_item + 1 else 0 end,
570
+ item)
571
+ # Determine the size of the widest item.
572
+ widest_item = [@item_len[@current_item], widest_item].max
573
+
574
+ self.updateViewWidth(widest_item)
575
+ self.setViewSize(@list_size + 1)
576
+ self.resequence
577
+ end
578
+ end
579
+
580
+ # This removes a single item from a scrolling list.
581
+ def deleteItem(position)
582
+ if position >= 0 && position < @list_size
583
+ # Adjust the list
584
+ @item = @item[0...position] + @item[position+1..-1]
585
+ @item_len = @item_len[0...position] + @item_len[position+1..-1]
586
+ @item_pos = @item_pos[0...position] + @item_pos[position+1..-1]
587
+
588
+ self.setViewSize(@list_size - 1)
589
+
590
+ if @list_size > 0
591
+ self.resequence
592
+ end
593
+
594
+ if @list_size < self.maxViewSize
595
+ @win.erase # force the next redraw to be complete
596
+ end
597
+
598
+ # do this to update the view size, etc
599
+ self.setPosition(@current_item)
600
+ end
601
+ end
602
+
603
+ def focus
604
+ self.drawCurrent
605
+ @list_win.refresh
606
+ end
607
+
608
+ def unfocus
609
+ self.drawCurrent
610
+ @list_win.refresh
611
+ end
612
+
613
+ def AvailableWidth
614
+ @box_width - (2 * @border_size)
615
+ end
616
+
617
+ def updateViewWidth(widest)
618
+ @max_left_char = if @box_width > widest
619
+ then 0
620
+ else widest - self.AvailableWidth
621
+ end
622
+ end
623
+
624
+ def WidestItem
625
+ @max_left_char + self.AvailableWidth
626
+ end
627
+ end
628
+
629
+ class BUTTON < CDK::CDKOBJS
630
+ def initialize(cdkscreen, xplace, yplace, text, callback, box, shadow)
631
+ super()
632
+ parent_width = cdkscreen.window.maxx
633
+ parent_height = cdkscreen.window.maxy
634
+ box_width = 0
635
+ xpos = xplace
636
+ ypos = yplace
637
+
638
+ self.setBox(box)
639
+ box_height = 1 + 2 * @border_size
640
+
641
+ # Translate the string to a chtype array.
642
+ info_len = []
643
+ info_pos = []
644
+ @info = CDK.char2Chtype(text, info_len, info_pos)
645
+ @info_len = info_len[0]
646
+ @info_pos = info_pos[0]
647
+ box_width = [box_width, @info_len].max + 2 * @border_size
648
+
649
+ # Create the string alignments.
650
+ @info_pos = CDK.justifyString(box_width - 2 * @border_size,
651
+ @info_len, @info_pos)
652
+
653
+ # Make sure we didn't extend beyond the dimensions of the window.
654
+ box_width = if box_width > parent_width
655
+ then parent_width
656
+ else box_width
657
+ end
658
+ box_height = if box_height > parent_height
659
+ then parent_height
660
+ else box_height
661
+ end
662
+
663
+ # Rejustify the x and y positions if we need to.
664
+ xtmp = [xpos]
665
+ ytmp = [ypos]
666
+ CDK.alignxy(cdkscreen.window, xtmp, ytmp, box_width, box_height)
667
+ xpos = xtmp[0]
668
+ ypos = ytmp[0]
669
+
670
+ # Create the button.
671
+ @screen = cdkscreen
672
+ # ObjOf (button)->fn = &my_funcs;
673
+ @parent = cdkscreen.window
674
+ @win = Curses::Window.new(box_height, box_width, ypos, xpos)
675
+ @shadow_win = nil
676
+ @xpos = xpos
677
+ @ypos = ypos
678
+ @box_width = box_width
679
+ @box_height = box_height
680
+ @callback = callback
681
+ @input_window = @win
682
+ @accepts_focus = true
683
+ @shadow = shadow
684
+
685
+ if @win.nil?
686
+ self.destroy
687
+ return nil
688
+ end
689
+
690
+ @win.keypad(true)
691
+
692
+ # If a shadow was requested, then create the shadow window.
693
+ if shadow
694
+ @shadow_win = Curses::Window.new(box_height, box_width,
695
+ ypos + 1, xpos + 1)
696
+ end
697
+
698
+ # Register this baby.
699
+ cdkscreen.register(:BUTTON, self)
700
+ end
701
+
702
+ # This was added for the builder.
703
+ def activate(actions)
704
+ self.draw(@box)
705
+ ret = -1
706
+
707
+ if actions.nil? || actions.size == 0
708
+ while true
709
+ input = self.getch([])
710
+
711
+ # Inject the character into the widget.
712
+ ret = self.inject(input)
713
+ if @exit_type != :EARLY_EXIT
714
+ return ret
715
+ end
716
+ end
717
+ else
718
+ # Inject each character one at a time.
719
+ actions.each do |x|
720
+ ret = self.inject(action)
721
+ if @exit_type == :EARLY_EXIT
722
+ return ret
723
+ end
724
+ end
725
+ end
726
+
727
+ # Set the exit type and exit
728
+ self.setExitType(0)
729
+ return -1
730
+ end
731
+
732
+ # This sets multiple attributes of the widget.
733
+ def set(mesg, box)
734
+ self.setMessage(mesg)
735
+ self.setBox(box)
736
+ end
737
+
738
+ # This sets the information within the button.
739
+ def setMessage(info)
740
+ info_len = []
741
+ info_pos = []
742
+ @info = CDK.char2Chtype(info, info_len, info_pos)
743
+ @info_len = info_len[0]
744
+ @info_pos = CDK.justifyString(@box_width - 2 * @border_size,
745
+ info_pos[0])
746
+
747
+ # Redraw the button widget.
748
+ self.erase
749
+ self.draw(box)
750
+ end
751
+
752
+ def getMessage
753
+ return @info
754
+ end
755
+
756
+ # This sets the background attribute of the widget.
757
+ def setBKattr(attrib)
758
+ @win.wbkgd(attrib)
759
+ end
760
+
761
+ def drawText
762
+ box_width = @box_width
763
+
764
+ # Draw in the message.
765
+ (0...(box_width - 2 * @border_size)).each do |i|
766
+ pos = @info_pos
767
+ len = @info_len
768
+ if i >= pos && (i - pos) < len
769
+ c = @info[i - pos]
770
+ else
771
+ c = ' '
772
+ end
773
+
774
+ if @has_focus
775
+ c = Curses::A_REVERSE | c
776
+ end
777
+
778
+ @win.mvwaddch(@border_size, i + @border_size, c)
779
+ end
780
+ end
781
+
782
+ # This draws the button widget
783
+ def draw(box)
784
+ # Is there a shadow?
785
+ unless @shadow_win.nil?
786
+ Draw.drawShadow(@shadow_win)
787
+ end
788
+
789
+ # Box the widget if asked.
790
+ if @box
791
+ Draw.drawObjBox(@win, self)
792
+ end
793
+ self.drawText
794
+ @win.refresh
795
+ end
796
+
797
+ # This erases the button widget.
798
+ def erase
799
+ if self.validCDKObject
800
+ CDK.eraseCursesWindow(@win)
801
+ CDK.eraseCursesWindow(@shadow_win)
802
+ end
803
+ end
804
+
805
+ # This moves the button field to the given location.
806
+ def move(xplace, yplace, relative, refresh_flag)
807
+ current_x = @win.begx
808
+ current_y = @win.begy
809
+ xpos = xplace
810
+ ypos = yplace
811
+
812
+ # If this is a relative move, then we will adjust where we want
813
+ # to move to.
814
+ if relative
815
+ xpos = @win.begx + xplace
816
+ ypos = @win.begy + yplace
817
+ end
818
+
819
+ # Adjust the window if we need to.
820
+ xtmp = [xpos]
821
+ ytmp = [ypos]
822
+ CDK.alignxy(@screen.window, xtmp, ytmp, @box_width, @box_height)
823
+ xpos = xtmp[0]
824
+ ypos = ytmp[0]
825
+
826
+ # Get the difference
827
+ xdiff = current_x - xpos
828
+ ydiff = current_y - ypos
829
+
830
+ # Move the window to the new location.
831
+ CDK.moveCursesWindow(@win, -xdiff, -ydiff)
832
+ CDK.moveCursesWindow(@shadow_win, -xdiff, -ydiff)
833
+
834
+ # Thouch the windows so they 'move'.
835
+ CDK::SCREEN.refreshCDKWindow(@screen.window)
836
+
837
+ # Redraw the window, if they asked for it.
838
+ if refresh_flag
839
+ self.draw(@box)
840
+ end
841
+ end
842
+
843
+ # This allows the user to use the cursor keys to adjust the
844
+ # position of the widget.
845
+ def position
846
+ # Declare some variables
847
+ orig_x = @win.begx
848
+ orig_y = @win.begy
849
+ key = 0
850
+
851
+ # Let them move the widget around until they hit return
852
+ # SUSPECT FOR BUG
853
+ while key != Curses::KEY_ENTER && key != CDK::KEY_RETURN
854
+ key = self.getch([])
855
+ if key == Curses::KEY_UP || key == '8'
856
+ if @win.begy > 0
857
+ self.move(0, -1, true, true)
858
+ else
859
+ CDK.Beep
860
+ end
861
+ elsif key == Curses::KEY_DOWN || key == '2'
862
+ if @win.begy + @win.maxy < @screen.window.maxy - 1
863
+ self.move(0, 1, true, true)
864
+ else
865
+ CDK.Beep
866
+ end
867
+ elsif key == Curses::KEY_LEFT || key == '4'
868
+ if @win.begx > 0
869
+ self.move(-1, 0, true, true)
870
+ else
871
+ CDK.Beep
872
+ end
873
+ elsif key == Curses::KEY_RIGHT || key == '6'
874
+ if @win.begx + @win.maxx < @screen.window.maxx - 1
875
+ self.move(1, 0, true, true)
876
+ else
877
+ CDK.Beep
878
+ end
879
+ elsif key == '7'
880
+ if @win.begy > 0 && @win.begx > 0
881
+ self.move(-1, -1, true, true)
882
+ else
883
+ CDK.Beep
884
+ end
885
+ elsif key == '9'
886
+ if @win.begx + @win.maxx < @screen.window.maxx - 1 &&
887
+ @win.begy > 0
888
+ self.move(1, -1, true, true)
889
+ else
890
+ CDK.Beep
891
+ end
892
+ elsif key == '1'
893
+ if @win.begx > 0 &&
894
+ @win.begx + @win.maxx < @screen.window.maxx - 1
895
+ self.move(-1, 1, true, true)
896
+ else
897
+ CDK.Beep
898
+ end
899
+ elsif key == '3'
900
+ if @win.begx + @win.maxx < @screen.window.maxx - 1 &&
901
+ @win.begy + @win.maxy < @screen.window.maxy - 1
902
+ self.move(1, 1, true, true)
903
+ else
904
+ CDK.Beep
905
+ end
906
+ elsif key == '5'
907
+ self.move(CDK::CENTER, CDK::CENTER, false, true)
908
+ elsif key == 't'
909
+ self.move(@win.begx, CDK::TOP, false, true)
910
+ elsif key == 'b'
911
+ self.move(@win.begx, CDK::BOTTOM, false, true)
912
+ elsif key == 'l'
913
+ self.move(CDK::LEFT, @win.begy, false, true)
914
+ elsif key == 'r'
915
+ self.move(CDK::RIGHT, @win.begy, false, true)
916
+ elsif key == 'c'
917
+ self.move(CDK::CENTER, @win.begy, false, true)
918
+ elsif key == 'C'
919
+ self.move(@win.begx, CDK::CENTER, false, true)
920
+ elsif key == CDK::REFRESH
921
+ @screen.erase
922
+ @screen.refresh
923
+ elsif key == CDK::KEY_ESC
924
+ self.move(orig_x, orig_y, false, true)
925
+ elsif key != CDK::KEY_RETURN && key != Curses::KEY_ENTER
926
+ CDK.Beep
927
+ end
928
+ end
929
+ end
930
+
931
+ # This destroys the button object pointer.
932
+ def destroy
933
+ CDK.deleteCursesWindow(@shadow_win)
934
+ CDK.deleteCursesWindow(@win)
935
+
936
+ self.cleanBindings(:BUTTON)
937
+
938
+ CDK::SCREEN.unregister(:BUTTON, self)
939
+ end
940
+
941
+ # This injects a single character into the widget.
942
+ def inject(input)
943
+ ret = -1
944
+ complete = false
945
+
946
+ self.setExitType(0)
947
+
948
+ # Check a predefined binding.
949
+ if self.checkBind(:BUTTON, input)
950
+ complete = true
951
+ else
952
+ case input
953
+ when CDK::KEY_ESC
954
+ self.setExitType(input)
955
+ complete = true
956
+ when Curses::Error
957
+ self.setExitType(input)
958
+ complete = true
959
+ when ' ', CDK::KEY_RETURN, Curses::KEY_ENTER
960
+ unless @callback.nil?
961
+ @callback.call(self)
962
+ end
963
+ self.setExitType(Curses::KEY_ENTER)
964
+ ret = 0
965
+ complete = true
966
+ when CDK::REFRESH
967
+ @screen.erase
968
+ @screen.refresh
969
+ else
970
+ CDK.Beep
971
+ end
972
+ end
973
+
974
+ unless complete
975
+ self.setExitType(0)
976
+ end
977
+
978
+ @result_data = ret
979
+ return ret
980
+ end
981
+
982
+ def focus
983
+ self.drawText
984
+ @win.refresh
985
+ end
986
+
987
+ def unfocus
988
+ self.drawText
989
+ @win.refresh
990
+ end
991
+
992
+ def object_type
993
+ :BUTTON
994
+ end
995
+ end
996
+ end