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/radio.rb ADDED
@@ -0,0 +1,533 @@
1
+ require_relative 'scroller'
2
+
3
+ module CDK
4
+ class RADIO < CDK::SCROLLER
5
+ def initialize(cdkscreen, xplace, yplace, splace, height, width, title,
6
+ list, list_size, choice_char, def_item, highlight, box, shadow)
7
+ super()
8
+ parent_width = cdkscreen.window.maxx
9
+ parent_height = cdkscreen.window.maxy
10
+ box_width = width
11
+ box_height = height
12
+ widest_item = 0
13
+
14
+ bindings = {
15
+ CDK::BACKCHAR => Curses::KEY_PPAGE,
16
+ CDK::FORCHAR => Curses::KEY_NPAGE,
17
+ 'g' => Curses::KEY_HOME,
18
+ '1' => Curses::KEY_HOME,
19
+ 'G' => Curses::KEY_END,
20
+ '<' => Curses::KEY_HOME,
21
+ '>' => Curses::KEY_END,
22
+ }
23
+
24
+ self.setBox(box)
25
+
26
+ # If the height is a negative value, height will be ROWS-height,
27
+ # otherwise the height will be the given height.
28
+ box_height = CDK.setWidgetDimension(parent_height, height, 0)
29
+
30
+ # If the width is a negative value, the width will be COLS-width,
31
+ # otherwise the width will be the given width.
32
+ box_width = CDK.setWidgetDimension(parent_width, width, 5)
33
+
34
+ box_width = self.setTitle(title, box_width)
35
+
36
+ # Set the box height.
37
+ if @title_lines > box_height
38
+ box_height = @title_lines + [list_size, 8].min + 2 * @border_size
39
+ end
40
+
41
+ # Adjust the box width if there is a scroll bar.
42
+ if splace == CDK::LEFT || splace == CDK::RIGHT
43
+ box_width += 1
44
+ @scrollbar = true
45
+ else
46
+ scrollbar = false
47
+ end
48
+
49
+ # Make sure we didn't extend beyond the dimensions of the window
50
+ @box_width = [box_width, parent_width].min
51
+ @box_height = [box_height, parent_height].min
52
+
53
+ self.setViewSize(list_size)
54
+
55
+ # Each item in the needs to be converted to chtype array
56
+ widest_item = self.createList(list, list_size, @box_width)
57
+ if widest_item > 0
58
+ self.updateViewWidth(widest_item)
59
+ elsif list_size > 0
60
+ self.destroy
61
+ return nil
62
+ end
63
+
64
+ # Rejustify the x and y positions if we need to.
65
+ xtmp = [xplace]
66
+ ytmp = [yplace]
67
+ CDK.alignxy(cdkscreen.window, xtmp, ytmp, @box_width, @box_height)
68
+ xpos = xtmp[0]
69
+ ypos = ytmp[0]
70
+
71
+ # Make the radio window
72
+ @win = Curses::Window.new(@box_height, @box_width, ypos, xpos)
73
+
74
+ # Is the window nil?
75
+ if @win.nil?
76
+ self.destroy
77
+ return nil
78
+ end
79
+
80
+ # Turn on the keypad.
81
+ @win.keypad(true)
82
+
83
+ # Create the scrollbar window.
84
+ if splace == CDK::RIGHT
85
+ @scrollbar_win = @win.subwin(self.maxViewSize, 1,
86
+ self.SCREEN_YPOS(ypos), xpos + @box_width - @border_size - 1)
87
+ elsif splace == CDK::LEFT
88
+ @scrollbar_win = @win.subwin(self.maxViewSize, 1,
89
+ self.SCREEN_YPOS(ypos), self.SCREEN_XPOS(xpos))
90
+ else
91
+ @scrollbar_win = nil
92
+ end
93
+
94
+ # Set the rest of the variables
95
+ @screen = cdkscreen
96
+ @parent = cdkscreen.window
97
+ @scrollbar_placement = splace
98
+ @widest_item = widest_item
99
+ @left_char = 0
100
+ @selected_item = 0
101
+ @highlight = highlight
102
+ @choice_char = choice_char.ord
103
+ @left_box_char = '['.ord
104
+ @right_box_char = ']'.ord
105
+ @def_item = def_item
106
+ @input_window = @win
107
+ @accepts_focus = true
108
+ @shadow = shadow
109
+
110
+ self.setCurrentItem(0)
111
+
112
+ # Do we need to create the shadow?
113
+ if shadow
114
+ @shadow_win = Curses::Window.new(box_height, box_width + 1,
115
+ ypos + 1, xpos + 1)
116
+ end
117
+
118
+ # Setup the key bindings
119
+ bindings.each do |from, to|
120
+ self.bind(:RADIO, from, :getc, to)
121
+ end
122
+
123
+ cdkscreen.register(:RADIO, self)
124
+ end
125
+
126
+ # Put the cursor on the currently-selected item.
127
+ def fixCursorPosition
128
+ scrollbar_adj = if @scrollbar_placement == CDK::LEFT then 1 else 0 end
129
+ ypos = self.SCREEN_YPOS(@current_item - @current_top)
130
+ xpos = self.SCREEN_XPOS(0) + scrollbar_adj
131
+
132
+ #@input_window.move(ypos, xpos)
133
+ @input_window.refresh
134
+ end
135
+
136
+ # This actually manages the radio widget.
137
+ def activate(actions)
138
+ # Draw the radio list.
139
+ self.draw(@box)
140
+
141
+ if actions.nil? || actions.size == 0
142
+ while true
143
+ self.fixCursorPosition
144
+ input = self.getch([])
145
+
146
+ # Inject the character into the widget.
147
+ ret = self.inject(input)
148
+ if @exit_type != :EARLY_EXIT
149
+ return ret
150
+ end
151
+ end
152
+ else
153
+ actions.each do |action|
154
+ ret = self.inject(action)
155
+ if @exit_type != :EARLY_EXIT
156
+ return ret
157
+ end
158
+ end
159
+ end
160
+
161
+ # Set the exit type and return
162
+ self.setExitType(0)
163
+ return -1
164
+ end
165
+
166
+ # This injects a single character into the widget.
167
+ def inject(input)
168
+ pp_return = 1
169
+ ret = -1
170
+ complete = false
171
+
172
+ # Set the exit type
173
+ self.setExitType(0)
174
+
175
+ # Draw the widget list
176
+ self.drawList(@box)
177
+
178
+ # Check if there is a pre-process function to be called
179
+ unless @pre_process_func.nil?
180
+ # Call the pre-process function.
181
+ pp_return = @pre_process_func.call(:RADIO, self,
182
+ @pre_process_data, input)
183
+ end
184
+
185
+ # Should we continue?
186
+ if pp_return != 0
187
+ # Check for a predefined key binding.
188
+ if self.checkBind(:RADIO, input)
189
+ complete = true
190
+ else
191
+ case input
192
+ when Curses::KEY_UP
193
+ self.KEY_UP
194
+ when Curses::KEY_DOWN
195
+ self.KEY_DOWN
196
+ when Curses::KEY_RIGHT
197
+ self.KEY_RIGHT
198
+ when Curses::KEY_LEFT
199
+ self.KEY_LEFT
200
+ when Curses::KEY_PPAGE
201
+ self.KEY_PPAGE
202
+ when Curses::KEY_NPAGE
203
+ self.KEY_NPAGE
204
+ when Curses::KEY_HOME
205
+ self.KEY_HOME
206
+ when Curses::KEY_END
207
+ self.KEY_END
208
+ when '$'
209
+ @left_char = @max_left_char
210
+ when '|'
211
+ @left_char = 0
212
+ when ' '
213
+ @selected_item = @current_item
214
+ when CDK::KEY_ESC
215
+ self.setExitType(input)
216
+ ret = -1
217
+ complete = true
218
+ when Curses::Error
219
+ self.setExitType(input)
220
+ complete = true
221
+ when CDK::KEY_TAB, CDK::KEY_RETURN, Curses::KEY_ENTER
222
+ self.setExitType(input)
223
+ ret = @selected_item
224
+ complete = true
225
+ when CDK::REFRESH
226
+ @screen.erase
227
+ @screen.refresh
228
+ end
229
+ end
230
+
231
+ # Should we call a post-process?
232
+ if !complete && !(@post_process_func.nil?)
233
+ @post_process_func.call(:RADIO, self, @post_process_data, input)
234
+ end
235
+ end
236
+
237
+ if !complete
238
+ self.drawList(@box)
239
+ self.setExitType(0)
240
+ end
241
+
242
+ self.fixCursorPosition
243
+ @return_data = ret
244
+ return ret
245
+ end
246
+
247
+ # This moves the radio field to the given location.
248
+ def move(xplace, yplace, relative, refresh_flag)
249
+ windows = [@win, @scrollbar_win, @shadow_win]
250
+ self.move_specific(xplace, yplace, relative, refresh_flag,
251
+ windows, subwidgets)
252
+ end
253
+
254
+ # This function draws the radio widget.
255
+ def draw(box)
256
+ # Do we need to draw in the shadow?
257
+ if !(@shadow_win.nil?)
258
+ Draw.drawShadow(@shadow_win)
259
+ end
260
+
261
+ self.drawTitle(@win)
262
+
263
+ # Draw in the radio list.
264
+ self.drawList(@box)
265
+ end
266
+
267
+ # This redraws the radio list.
268
+ def drawList(box)
269
+ scrollbar_adj = if @scrollbar_placement == CDK::LEFT then 1 else 0 end
270
+ screen_pos = 0
271
+
272
+ # Draw the list
273
+ (0...@view_size).each do |j|
274
+ k = j + @current_top
275
+ if k < @list_size
276
+ xpos = self.SCREEN_XPOS(0)
277
+ ypos = self.SCREEN_YPOS(j)
278
+
279
+ screen_pos = self.SCREENPOS(k, scrollbar_adj)
280
+
281
+ # Draw the empty string.
282
+ Draw.writeBlanks(@win, xpos, ypos, CDK::HORIZONTAL, 0,
283
+ @box_width - @border_size)
284
+
285
+ # Draw the line.
286
+ Draw.writeChtype(@win,
287
+ if screen_pos >= 0 then screen_pos else 1 end,
288
+ ypos, @item[k], CDK::HORIZONTAL,
289
+ if screen_pos >= 0 then 0 else 1 - screen_pos end,
290
+ @item_len[k])
291
+
292
+ # Draw the selected choice
293
+ xpos += scrollbar_adj
294
+ @win.mvwaddch(ypos, xpos, @left_box_char)
295
+ @win.mvwaddch(ypos, xpos + 1,
296
+ if k == @selected_item then @choice_char else ' '.ord end)
297
+ @win.mvwaddch(ypos, xpos + 2, @right_box_char)
298
+ end
299
+ end
300
+
301
+ # Highlight the current item
302
+ if @has_focus
303
+ k = @current_item
304
+ if k < @list_size
305
+ screen_pos = self.SCREENPOS(k, scrollbar_adj)
306
+ ypos = self.SCREEN_YPOS(@current_high)
307
+
308
+ Draw.writeChtypeAttrib(@win,
309
+ if screen_pos >= 0 then screen_pos else 1 + scrollbar_adj end,
310
+ ypos, @item[k], @highlight, CDK::HORIZONTAL,
311
+ if screen_pos >= 0 then 0 else 1 - screen_pos end,
312
+ @item_len[k])
313
+ end
314
+ end
315
+
316
+ if @scrollbar
317
+ @toggle_pos = (@current_item * @step).floor
318
+ @toggle_pos = [@toggle_pos, @scrollbar_win.maxy - 1].min
319
+
320
+ @scrollbar_win.mvwvline(0, 0, CDK::ACS_CKBOARD,
321
+ @scrollbar_win.maxy)
322
+ @scrollbar_win.mvwvline(@toggle_pos, 0, ' '.ord | Curses::A_REVERSE,
323
+ @toggle_size)
324
+ end
325
+
326
+ # Box it if needed.
327
+ if box
328
+ Draw.drawObjBox(@win, self)
329
+ end
330
+
331
+ self.fixCursorPosition
332
+ end
333
+
334
+ # This sets the background attribute of the widget.
335
+ def setBKattr(attrib)
336
+ @win.wbkgd(attrib)
337
+ unless @scrollbar_win.nil?
338
+ @scrollbar_win.wbkgd(attrib)
339
+ end
340
+ end
341
+
342
+ def destroyInfo
343
+ @item = ''
344
+ end
345
+
346
+ # This function destroys the radio widget.
347
+ def destroy
348
+ self.cleanTitle
349
+ self.destroyInfo
350
+
351
+ # Clean up the windows.
352
+ CDK.deleteCursesWindow(@scrollbar_win)
353
+ CDK.deleteCursesWindow(@shadow_win)
354
+ CDK.deleteCursesWindow(@win)
355
+
356
+ # Clean up the key bindings.
357
+ self.cleanBindings(:RADIO)
358
+
359
+ # Unregister this object.
360
+ CDK::SCREEN.unregister(:RADIO, self)
361
+ end
362
+
363
+ # This function erases the radio widget
364
+ def erase
365
+ if self.validCDKObject
366
+ CDK.eraseCursesWindow(@win)
367
+ CDK.eraseCursesWindow(@shadow_win)
368
+ end
369
+ end
370
+
371
+ # This sets various attributes of the radio list.
372
+ def set(highlight, choice_char, box)
373
+ self.setHighlight(highlight)
374
+ self.setChoiceCHaracter(choice_char)
375
+ self.setBox(box)
376
+ end
377
+
378
+ # This sets the radio list items.
379
+ def setItems(list, list_size)
380
+ widest_item = self.createList(list, list_size, @box_width)
381
+ if widest_item <= 0
382
+ return
383
+ end
384
+
385
+ # Clean up the display.
386
+ (0...@view_size).each do |j|
387
+ Draw.writeBlanks(@win, self.SCREEN_XPOS(0), self.SCREEN_YPOS(j),
388
+ CDK::HORIZONTAL, 0, @box_width - @border_size)
389
+ end
390
+
391
+ self.setViewSize(list_size)
392
+
393
+ self.setCurrentItem(0)
394
+ @left_char = 0
395
+ @selected_item = 0
396
+
397
+ self.updateViewWidth(widest_item)
398
+ end
399
+
400
+ def getItems(list)
401
+ (0...@list_size).each do |j|
402
+ list << CDK.chtype2Char(@item[j])
403
+ end
404
+ return @list_size
405
+ end
406
+
407
+ # This sets the highlight bar of the radio list.
408
+ def setHighlight(highlight)
409
+ @highlight = highlight
410
+ end
411
+
412
+ def getHighlight
413
+ return @highlight
414
+ end
415
+
416
+ # This sets the character to use when selecting na item in the list.
417
+ def setChoiceCharacter(character)
418
+ @choice_char = character
419
+ end
420
+
421
+ def getChoiceCharacter
422
+ return @choice_char
423
+ end
424
+
425
+ # This sets the character to use to drw the left side of the choice box
426
+ # on the list
427
+ def setLeftBrace(character)
428
+ @left_box_char = character
429
+ end
430
+
431
+ def getLeftBrace
432
+ return @left_box_char
433
+ end
434
+
435
+ # This sets the character to use to draw the right side of the choice box
436
+ # on the list
437
+ def setRightBrace(character)
438
+ @right_box_char = character
439
+ end
440
+
441
+ def getRightBrace
442
+ return @right_box_char
443
+ end
444
+
445
+ # This sets the current highlighted item of the widget
446
+ def setCurrentItem(item)
447
+ self.setPosition(item)
448
+ @selected_item = item
449
+ end
450
+
451
+ def getCurrentItem
452
+ return @current_item
453
+ end
454
+
455
+ # This sets the selected item of the widget
456
+ def setSelectedItem(item)
457
+ @selected_item = item
458
+ end
459
+
460
+ def getSelectedItem
461
+ return @selected_item
462
+ end
463
+
464
+ def focus
465
+ self.drawList(@box)
466
+ end
467
+
468
+ def unfocus
469
+ self.drawList(@box)
470
+ end
471
+
472
+ def createList(list, list_size, box_width)
473
+ status = false
474
+ widest_item = 0
475
+
476
+ if list_size >= 0
477
+ new_list = []
478
+ new_len = []
479
+ new_pos = []
480
+
481
+ # Each item in the needs to be converted to chtype array
482
+ status = true
483
+ box_width -= 2 + @border_size
484
+ (0...list_size).each do |j|
485
+ lentmp = []
486
+ postmp = []
487
+ new_list << CDK.char2Chtype(list[j], lentmp, postmp)
488
+ new_len << lentmp[0]
489
+ new_pos << postmp[0]
490
+ if new_list[j].nil? || new_list[j].size == 0
491
+ status = false
492
+ break
493
+ end
494
+ new_pos[j] = CDK.justifyString(box_width, new_len[j], new_pos[j]) + 3
495
+ widest_item = [widest_item, new_len[j]].max
496
+ end
497
+ if status
498
+ self.destroyInfo
499
+ @item = new_list
500
+ @item_len = new_len
501
+ @item_pos = new_pos
502
+ end
503
+ end
504
+
505
+ return (if status then widest_item else 0 end)
506
+ end
507
+
508
+ # Determine how many characters we can shift to the right
509
+ # before all the items have been scrolled off the screen.
510
+ def AvailableWidth
511
+ @box_width - 2 * @border_size - 3
512
+ end
513
+
514
+ def updateViewWidth(widest)
515
+ @max_left_char = if @box_width > widest
516
+ then 0
517
+ else widest - self.AvailableWidth
518
+ end
519
+ end
520
+
521
+ def WidestItem
522
+ @max_left_char + self.AvailableWidth
523
+ end
524
+
525
+ def SCREENPOS(n, scrollbar_adj)
526
+ @item_pos[n] - @left_char + scrollbar_adj + @border_size
527
+ end
528
+
529
+ def object_type
530
+ :RADIO
531
+ end
532
+ end
533
+ end