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/menu.rb ADDED
@@ -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.maxx
18
+ leftloc = 0
19
+ xpos = cdkscreen.window.begx
20
+ ypos = cdkscreen.window.begy
21
+ ymax = cdkscreen.window.maxy
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.maxy
173
+
174
+ if 1 + @pull_win[@current_title].begy + @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].refresh
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 Curses::KEY_LEFT
238
+ self.acrossSubmenus(-1)
239
+ when Curses::KEY_RIGHT, CDK::KEY_TAB
240
+ self.acrossSubmenus(1)
241
+ when Curses::KEY_UP
242
+ self.withinSubmenu(-1)
243
+ when Curses::KEY_DOWN, ' '
244
+ self.withinSubmenu(1)
245
+ when Curses::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 Curses::Error
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].maxy - 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(CDK::ACS_VLINE, CDK::ACS_HLINE)
298
+ if @menu_pos == CDK::BOTTOM
299
+ @pull_win[@current_title].mvwaddch(@subsize[@current_title] + 1,
300
+ 0, CDK::ACS_LTEE)
301
+ else
302
+ @pull_win[@current_title].mvwaddch(0, 0, CDK::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].refresh
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].refresh
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].refresh
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].refresh
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].erase
376
+ @title_win[x].refresh
377
+ @pull_win[x].erase
378
+ @pull_win[x].refresh
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].refresh
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