slithernix-cdk 0.0.1

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.
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