cdk 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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