cdk 0.9.0

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.
@@ -0,0 +1,448 @@
1
+ require_relative 'cdk_objs'
2
+
3
+ module CDK
4
+ class MENU < CDK::CDKOBJS
5
+ TITLELINES = 1
6
+ MAX_MENU_ITEMS = 30
7
+ MAX_SUB_ITEMS = 98
8
+
9
+ attr_reader :current_title, :current_subtitle
10
+ attr_reader :sublist
11
+
12
+ def initialize(cdkscreen, menu_list, menu_items, subsize,
13
+ menu_location, menu_pos, title_attr, subtitle_attr)
14
+ super()
15
+
16
+ right_count = menu_items - 1
17
+ rightloc = cdkscreen.window.getmaxx
18
+ leftloc = 0
19
+ xpos = cdkscreen.window.getbegx
20
+ ypos = cdkscreen.window.getbegy
21
+ ymax = cdkscreen.window.getmaxy
22
+
23
+ # Start making a copy of the information.
24
+ @screen = cdkscreen
25
+ @box = false
26
+ @accepts_focus = false
27
+ rightcount = menu_items - 1
28
+ @parent = cdkscreen.window
29
+ @menu_items = menu_items
30
+ @title_attr = title_attr
31
+ @subtitle_attr = subtitle_attr
32
+ @current_title = 0
33
+ @current_subtitle = 0
34
+ @last_selection = -1
35
+ @menu_pos = menu_pos
36
+
37
+ @pull_win = [nil] * menu_items
38
+ @title_win = [nil] * menu_items
39
+ @title = [''] * menu_items
40
+ @title_len = [0] * menu_items
41
+ @sublist = (1..menu_items).map {[nil] * subsize.max}.compact
42
+ @sublist_len = (1..menu_items).map {
43
+ [0] * subsize.max}.compact
44
+ @subsize = [0] * menu_items
45
+
46
+
47
+ # Create the pull down menus.
48
+ (0...menu_items).each do |x|
49
+ x1 = if menu_location[x] == CDK::LEFT
50
+ then x
51
+ else
52
+ rightcount -= 1
53
+ rightcount + 1
54
+ end
55
+ x2 = 0
56
+ y1 = if menu_pos == CDK::BOTTOM then ymax - 1 else 0 end
57
+ y2 = if menu_pos == CDK::BOTTOM
58
+ then ymax - subsize[x] - 2
59
+ else CDK::MENU::TITLELINES
60
+ end
61
+ high = subsize[x] + CDK::MENU::TITLELINES
62
+
63
+ # Limit the menu height to fit on the screen.
64
+ if high + y2 > ymax
65
+ high = ymax - CDK::MENU::TITLELINES
66
+ end
67
+
68
+ max = -1
69
+ (CDK::MENU::TITLELINES...subsize[x]).to_a.each do |y|
70
+ y0 = y - CDK::MENU::TITLELINES
71
+ sublist_len = []
72
+ @sublist[x1][y0] = CDK.char2Chtype(menu_list[x][y],
73
+ sublist_len, [])
74
+ @sublist_len[x1][y0] = sublist_len[0]
75
+ max = [max, sublist_len[0]].max
76
+ end
77
+
78
+ if menu_location[x] == CDK::LEFT
79
+ x2 = leftloc
80
+ else
81
+ x2 = (rightloc -= max + 2)
82
+ end
83
+
84
+ title_len = []
85
+ @title[x1] = CDK.char2Chtype(menu_list[x][0], title_len, [])
86
+ @title_len[x1] = title_len[0]
87
+ @subsize[x1] = subsize[x] - CDK::MENU::TITLELINES
88
+ @title_win[x1] = cdkscreen.window.subwin(CDK::MENU::TITLELINES,
89
+ @title_len[x1] + 2, ypos + y1, xpos + x2)
90
+ @pull_win[x1] = cdkscreen.window.subwin(high, max + 2,
91
+ ypos + y2, xpos + x2)
92
+ if @title_win[x1].nil? || @pull_win[x1].nil?
93
+ self.destroy
94
+ return nil
95
+ end
96
+
97
+ leftloc += @title_len[x] + 1
98
+ @title_win[x1].keypad(true)
99
+ @pull_win[x1].keypad(true)
100
+ end
101
+ @input_window = @title_win[@current_title]
102
+
103
+ # Register this baby.
104
+ cdkscreen.register(:MENU, self)
105
+ end
106
+
107
+ # This activates the CDK Menu
108
+ def activate(actions)
109
+ ret = 0
110
+
111
+ # Draw in the screen.
112
+ @screen.refresh
113
+
114
+ # Display the menu titles.
115
+ self.draw(@box)
116
+
117
+ # Highlight the current title and window.
118
+ self.drawSubwin
119
+
120
+ # If the input string is empty this is an interactive activate.
121
+ if actions.nil? || actions.size == 0
122
+ @input_window = @title_win[@current_title]
123
+
124
+ # Start taking input from the keyboard.
125
+ while true
126
+ input = self.getch([])
127
+
128
+ # Inject the character into the widget.
129
+ ret = self.inject(input)
130
+ if @exit_type != :EARLY_EXIT
131
+ return ret
132
+ end
133
+ end
134
+ else
135
+ actions.each do |action|
136
+ if @exit_type != :EARLY_EXIT
137
+ return ret
138
+ end
139
+ end
140
+ end
141
+
142
+ # Set the exit type and return.
143
+ self.setExitType(0)
144
+ return -1
145
+ end
146
+
147
+ def drawTitle(item)
148
+ Draw.writeChtype(@title_win[item], 0, 0, @title[item],
149
+ CDK::HORIZONTAL, 0, @title_len[item])
150
+ end
151
+
152
+ def drawItem(item, offset)
153
+ Draw.writeChtype(@pull_win[@current_title], 1,
154
+ item + CDK::MENU::TITLELINES - offset,
155
+ @sublist[@current_title][item],
156
+ CDK::HORIZONTAL, 0, @sublist_len[@current_title][item])
157
+ end
158
+
159
+ # Highlight the current sub-menu item
160
+ def selectItem(item, offset)
161
+ Draw.writeChtypeAttrib(@pull_win[@current_title], 1,
162
+ item + CDK::MENU::TITLELINES - offset,
163
+ @sublist[@current_title][item], @subtitle_attr,
164
+ CDK::HORIZONTAL, 0, @sublist_len[@current_title][item])
165
+ end
166
+
167
+ def withinSubmenu(step)
168
+ next_item = CDK::MENU.wrapped(@current_subtitle + step,
169
+ @subsize[@current_title])
170
+
171
+ if next_item != @current_subtitle
172
+ ymax = @screen.window.getmaxy
173
+
174
+ if 1 + @pull_win[@current_title].getbegy + @subsize[@current_title] >=
175
+ ymax
176
+ @current_subtitle = next_item
177
+ self.drawSubwin
178
+ else
179
+ # Erase the old subtitle.
180
+ self.drawItem(@current_subtitle, 0)
181
+
182
+ # Set the values
183
+ @current_subtitle = next_item
184
+
185
+ # Draw the new sub-title.
186
+ self.selectItem(@current_subtitle, 0)
187
+
188
+ @pull_win[@current_title].wrefresh
189
+ end
190
+
191
+ @input_window = @title_win[@current_title]
192
+ end
193
+ end
194
+
195
+ def acrossSubmenus(step)
196
+ next_item = CDK::MENU.wrapped(@current_title + step, @menu_items)
197
+
198
+ if next_item != @current_title
199
+ # Erase the menu sub-window.
200
+ self.eraseSubwin
201
+ @screen.refresh
202
+
203
+ # Set the values.
204
+ @current_title = next_item
205
+ @current_subtitle = 0
206
+
207
+ # Draw the new menu sub-window.
208
+ self.drawSubwin
209
+ @input_window = @title_win[@current_title]
210
+ end
211
+ end
212
+
213
+ # Inject a character into the menu widget.
214
+ def inject(input)
215
+ pp_return = 1
216
+ ret = -1
217
+ complete = false
218
+
219
+ # Set the exit type.
220
+ self.setExitType(0)
221
+
222
+ # Check if there is a pre-process function to be called.
223
+ unless @pre_process_func.nil?
224
+ # Call the pre-process function.
225
+ pp_return = @pre_process_func.call(:MENU, self,
226
+ @pre_process_data, input)
227
+ end
228
+
229
+ # Should we continue?
230
+
231
+ if pp_return != 0
232
+ # Check for key bindings.
233
+ if self.checkBind(:MENU, input)
234
+ complete = true
235
+ else
236
+ case input
237
+ when Ncurses::KEY_LEFT
238
+ self.acrossSubmenus(-1)
239
+ when Ncurses::KEY_RIGHT, CDK::KEY_TAB
240
+ self.acrossSubmenus(1)
241
+ when Ncurses::KEY_UP
242
+ self.withinSubmenu(-1)
243
+ when Ncurses::KEY_DOWN, ' '.ord
244
+ self.withinSubmenu(1)
245
+ when Ncurses::KEY_ENTER, CDK::KEY_RETURN
246
+ self.cleanUpMenu
247
+ self.setExitType(input)
248
+ @last_selection = @current_title * 100 + @current_subtitle
249
+ ret = @last_selection
250
+ complete = true
251
+ when CDK::KEY_ESC
252
+ self.cleanUpMenu
253
+ self.setExitType(input)
254
+ @last_selection = -1
255
+ ret = @last_selection
256
+ complete = true
257
+ when Ncurses::ERR
258
+ self.setExitType(input)
259
+ complete = true
260
+ when CDK::REFRESH
261
+ self.erase
262
+ self.refresh
263
+ end
264
+ end
265
+
266
+ # Should we call a post-process?
267
+ if !complete && !(@post_process_func.nil?)
268
+ @post_process_func.call(:MENU, self, @post_process_data, input)
269
+ end
270
+ end
271
+
272
+ if !complete
273
+ self.setExitType(0)
274
+ end
275
+
276
+ @result_data = ret
277
+ return ret
278
+ end
279
+
280
+ # Draw a menu item subwindow
281
+ def drawSubwin
282
+ high = @pull_win[@current_title].getmaxy - 2
283
+ x0 = 0
284
+ x1 = @subsize[@current_title]
285
+
286
+ if x1 > high
287
+ x1 = high
288
+ end
289
+
290
+ if @current_subtitle >= x1
291
+ x0 = @current_subtitle - x1 + 1
292
+ x1 += x0
293
+ end
294
+
295
+ # Box the window
296
+ @pull_win[@current_title]
297
+ @pull_win[@current_title].box(Ncurses::ACS_VLINE, Ncurses::ACS_HLINE)
298
+ if @menu_pos == CDK::BOTTOM
299
+ @pull_win[@current_title].mvwaddch(@subsize[@current_title] + 1,
300
+ 0, Ncurses::ACS_LTEE)
301
+ else
302
+ @pull_win[@current_title].mvwaddch(0, 0, Ncurses::ACS_LTEE)
303
+ end
304
+
305
+ # Draw the items.
306
+ (x0...x1).each do |x|
307
+ self.drawItem(x, x0)
308
+ end
309
+
310
+ self.selectItem(@current_subtitle, x0)
311
+ @pull_win[@current_title].wrefresh
312
+
313
+ # Highlight the title.
314
+ Draw.writeChtypeAttrib(@title_win[@current_title], 0, 0,
315
+ @title[@current_title], @title_attr, CDK::HORIZONTAL,
316
+ 0, @title_len[@current_title])
317
+ @title_win[@current_title].wrefresh
318
+ end
319
+
320
+ # Erase a menu item subwindow
321
+ def eraseSubwin
322
+ CDK.eraseCursesWindow(@pull_win[@current_title])
323
+
324
+ # Redraw the sub-menu title.
325
+ self.drawTitle(@current_title)
326
+ @title_win[@current_title].wrefresh
327
+ end
328
+
329
+ # Draw the menu.
330
+ def draw(box)
331
+ # Draw in the menu titles.
332
+ (0...@menu_items).each do |x|
333
+ self.drawTitle(x)
334
+ @title_win[x].wrefresh
335
+ end
336
+ end
337
+
338
+ # Move the menu to the given location.
339
+ def move(xplace, yplace, relative, refresh_flag)
340
+ windows = [@screen.window]
341
+ (0...@menu_items).each do |x|
342
+ windows << @title_win[x]
343
+ end
344
+ self.move_specific(xplace, yplace, relative, refresh_flag,
345
+ windows, [])
346
+ end
347
+
348
+ # Set the background attribute of the widget.
349
+ def setBKattr(attrib)
350
+ (0...@menu_items).each do |x|
351
+ @title_win[x].wbkgd(attrib)
352
+ @pull_win[x].wbkgd(attrib)
353
+ end
354
+ end
355
+
356
+ # Destroy a menu widget.
357
+ def destroy
358
+ # Clean up the windows
359
+ (0...@menu_items).each do |x|
360
+ CDK.deleteCursesWindow(@title_win[x])
361
+ CDK.deleteCursesWindow(@pull_win[x])
362
+ end
363
+
364
+ # Clean the key bindings.
365
+ self.cleanBindings(:MENU)
366
+
367
+ # Unregister the object
368
+ CDK::SCREEN.unregister(:MENU, self)
369
+ end
370
+
371
+ # Erase the menu widget from the screen.
372
+ def erase
373
+ if self.validCDKObject
374
+ (0...@menu_items).each do |x|
375
+ @title_win[x].werase
376
+ @title_win[x].wrefresh
377
+ @pull_win[x].werase
378
+ @pull_win[x].wrefresh
379
+ end
380
+ end
381
+ end
382
+
383
+ def set(menu_item, submenu_item, title_highlight, subtitle_highlight)
384
+ self.setCurrentItem(menu_item, submenu_item)
385
+ self.setTitleHighlight(title_highlight)
386
+ self.setSubTitleHighlight(subtitle_highlight)
387
+ end
388
+
389
+ # Set the current menu item to highlight.
390
+ def setCurrentItem(menuitem, submenuitem)
391
+ @current_title = CDK::MENU.wrapped(menuitem, @menu_items)
392
+ @current_subtitle = CDK::MENU.wrapped(
393
+ submenuitem, @subsize[@current_title])
394
+ end
395
+
396
+ def getCurrentItem(menu_item, submenu_item)
397
+ menu_item << @current_title
398
+ submenu_item << @current_subtitle
399
+ end
400
+
401
+ # Set the attribute of the menu titles.
402
+ def setTitleHighlight(highlight)
403
+ @title_attr = highlight
404
+ end
405
+
406
+ def getTitleHighlight
407
+ return @title_attr
408
+ end
409
+
410
+ # Set the attribute of the sub-title.
411
+ def setSubTitleHighlight(highlight)
412
+ @subtitle_attr = highlight
413
+ end
414
+
415
+ def getSubTitleHighlight
416
+ return @subtitle_attr
417
+ end
418
+
419
+ # Exit the menu.
420
+ def cleanUpMenu
421
+ # Erase the sub-menu.
422
+ self.eraseSubwin
423
+ @pull_win[@current_title].wrefresh
424
+
425
+ # Refresh the screen.
426
+ @screen.refresh
427
+ end
428
+
429
+ def focus
430
+ self.drawSubwin
431
+ @input_window = @title_win[@current_title]
432
+ end
433
+
434
+ # The "%" operator is simpler but does not handle negative values
435
+ def self.wrapped(within, limit)
436
+ if within < 0
437
+ within = limit - 1
438
+ elsif within >= limit
439
+ within = 0
440
+ end
441
+ return within
442
+ end
443
+
444
+ def object_type
445
+ :MENU
446
+ end
447
+ end
448
+ end
@@ -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.getmaxx
9
+ parent_height = cdkscreen.window.getmaxy
10
+ box_width = width
11
+ box_height = height
12
+ widest_item = 0
13
+
14
+ bindings = {
15
+ CDK::BACKCHAR => Ncurses::KEY_PPAGE,
16
+ CDK::FORCHAR => Ncurses::KEY_NPAGE,
17
+ 'g' => Ncurses::KEY_HOME,
18
+ '1' => Ncurses::KEY_HOME,
19
+ 'G' => Ncurses::KEY_END,
20
+ '<' => Ncurses::KEY_HOME,
21
+ '>' => Ncurses::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 = Ncurses::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 = Ncurses::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.wmove(ypos, xpos)
133
+ @input_window.wrefresh
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 Ncurses::KEY_UP
193
+ self.KEY_UP
194
+ when Ncurses::KEY_DOWN
195
+ self.KEY_DOWN
196
+ when Ncurses::KEY_RIGHT
197
+ self.KEY_RIGHT
198
+ when Ncurses::KEY_LEFT
199
+ self.KEY_LEFT
200
+ when Ncurses::KEY_PPAGE
201
+ self.KEY_PPAGE
202
+ when Ncurses::KEY_NPAGE
203
+ self.KEY_NPAGE
204
+ when Ncurses::KEY_HOME
205
+ self.KEY_HOME
206
+ when Ncurses::KEY_END
207
+ self.KEY_END
208
+ when '$'.ord
209
+ @left_char = @max_left_char
210
+ when '|'.ord
211
+ @left_char = 0
212
+ when ' '.ord
213
+ @selected_item = @current_item
214
+ when CDK::KEY_ESC
215
+ self.setExitType(input)
216
+ ret = -1
217
+ complete = true
218
+ when Ncurses::ERR
219
+ self.setExitType(input)
220
+ complete = true
221
+ when CDK::KEY_TAB, CDK::KEY_RETURN, Ncurses::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.getmaxy - 1].min
319
+
320
+ @scrollbar_win.mvwvline(0, 0, Ncurses::ACS_CKBOARD,
321
+ @scrollbar_win.getmaxy)
322
+ @scrollbar_win.mvwvline(@toggle_pos, 0, ' '.ord | Ncurses::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