rndk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/COPYING +137 -0
  4. data/Gemfile +4 -0
  5. data/README.md +100 -0
  6. data/Rakefile +3 -0
  7. data/TODO +68 -0
  8. data/demos/appointment.rb +346 -0
  9. data/demos/clock.rb +56 -0
  10. data/examples/01-hello-world.rb +56 -0
  11. data/examples/05-position-widget.rb +108 -0
  12. data/lib/rndk.rb +912 -0
  13. data/lib/rndk/alphalist.rb +572 -0
  14. data/lib/rndk/button.rb +370 -0
  15. data/lib/rndk/buttonbox.rb +359 -0
  16. data/lib/rndk/calendar.rb +766 -0
  17. data/lib/rndk/core/display.rb +63 -0
  18. data/lib/rndk/core/draw.rb +238 -0
  19. data/lib/rndk/core/quick_widgets.rb +106 -0
  20. data/lib/rndk/core/screen.rb +269 -0
  21. data/lib/rndk/core/traverse.rb +289 -0
  22. data/lib/rndk/core/widget.rb +506 -0
  23. data/lib/rndk/dialog.rb +367 -0
  24. data/lib/rndk/dscale.rb +13 -0
  25. data/lib/rndk/entry.rb +575 -0
  26. data/lib/rndk/fscale.rb +61 -0
  27. data/lib/rndk/fselect.rb +940 -0
  28. data/lib/rndk/fslider.rb +80 -0
  29. data/lib/rndk/graph.rb +401 -0
  30. data/lib/rndk/histogram.rb +412 -0
  31. data/lib/rndk/itemlist.rb +474 -0
  32. data/lib/rndk/label.rb +218 -0
  33. data/lib/rndk/marquee.rb +244 -0
  34. data/lib/rndk/matrix.rb +1189 -0
  35. data/lib/rndk/mentry.rb +619 -0
  36. data/lib/rndk/menu.rb +478 -0
  37. data/lib/rndk/radio.rb +538 -0
  38. data/lib/rndk/scale.rb +538 -0
  39. data/lib/rndk/scroll.rb +633 -0
  40. data/lib/rndk/scroller.rb +183 -0
  41. data/lib/rndk/selection.rb +630 -0
  42. data/lib/rndk/slider.rb +545 -0
  43. data/lib/rndk/swindow.rb +766 -0
  44. data/lib/rndk/template.rb +560 -0
  45. data/lib/rndk/uscale.rb +14 -0
  46. data/lib/rndk/uslider.rb +14 -0
  47. data/lib/rndk/version.rb +6 -0
  48. data/lib/rndk/viewer.rb +825 -0
  49. data/rndk.gemspec +35 -0
  50. metadata +141 -0
@@ -0,0 +1,572 @@
1
+ require 'rndk'
2
+
3
+ module RNDK
4
+ class ALPHALIST < RNDK::Widget
5
+ attr_reader :scroll_field, :entry_field, :list
6
+
7
+ def initialize(rndkscreen, xplace, yplace, height, width, title, label,
8
+ list, list_size, filler_char, highlight, box, shadow)
9
+ super()
10
+ parent_width = Ncurses.getmaxx(rndkscreen.window)
11
+ parent_height = Ncurses.getmaxy(rndkscreen.window)
12
+ box_width = width
13
+ box_height = height
14
+ label_len = 0
15
+ bindings = {
16
+ RNDK::BACKCHAR => Ncurses::KEY_PPAGE,
17
+ RNDK::FORCHAR => Ncurses::KEY_NPAGE,
18
+ }
19
+
20
+ if !self.createList(list, list_size)
21
+ self.destroy
22
+ return nil
23
+ end
24
+
25
+ self.setBox(box)
26
+
27
+ # If the height is a negative value, the height will be ROWS-height,
28
+ # otherwise the height will be the given height.
29
+ box_height = RNDK.setWidgetDimension(parent_height, height, 0)
30
+
31
+ # If the width is a negative value, the width will be COLS-width,
32
+ # otherwise the width will be the given width.
33
+ box_width = RNDK.setWidgetDimension(parent_width, width, 0)
34
+
35
+ # Translate the label string to a chtype array
36
+ if label.size > 0
37
+ lentmp = []
38
+ chtype_label = RNDK.char2Chtype(label, lentmp, [])
39
+ label_len = lentmp[0]
40
+ end
41
+
42
+ # Rejustify the x and y positions if we need to.
43
+ xtmp = [xplace]
44
+ ytmp = [yplace]
45
+ RNDK.alignxy(rndkscreen.window, xtmp, ytmp, box_width, box_height)
46
+ xpos = xtmp[0]
47
+ ypos = ytmp[0]
48
+
49
+ # Make the file selector window.
50
+ @win = Ncurses.newwin(box_height, box_width, ypos, xpos)
51
+
52
+ if @win.nil?
53
+ self.destroy
54
+ return nil
55
+ end
56
+ Ncurses.keypad(@win, true)
57
+
58
+ # Set some variables.
59
+ @screen = rndkscreen
60
+ @parent = rndkscreen.window
61
+ @highlight = highlight
62
+ @filler_char = filler_char
63
+ @box_height = box_height
64
+ @box_width = box_width
65
+ @shadow = shadow
66
+ @shadow_win = nil
67
+
68
+ # Do we want a shadow?
69
+ if shadow
70
+ @shadow_win = Ncurses.newwin(box_height, box_width,
71
+ ypos + 1, xpos + 1)
72
+ end
73
+
74
+ # Create the entry field.
75
+ temp_width = if RNDK::ALPHALIST.isFullWidth(width)
76
+ then RNDK::FULL
77
+ else box_width - 2 - label_len
78
+ end
79
+ @entry_field = RNDK::ENTRY.new(rndkscreen, Ncurses.getbegx(@win), Ncurses.getbegy(@win),
80
+ title, label, Ncurses::A_NORMAL, filler_char, :MIXED, temp_width,
81
+ 0, 512, box, false)
82
+ if @entry_field.nil?
83
+ self.destroy
84
+ return nil
85
+ end
86
+ @entry_field.setLLchar(Ncurses::ACS_LTEE)
87
+ @entry_field.setLRchar(Ncurses::ACS_RTEE)
88
+
89
+ # Callback functions
90
+ adjust_alphalist_cb = lambda do |object_type, object, alphalist, key|
91
+ scrollp = alphalist.scroll_field
92
+ entry = alphalist.entry_field
93
+
94
+ if scrollp.list_size > 0
95
+ # Adjust the scrolling list.
96
+ alphalist.injectMyScroller(key)
97
+
98
+ # Set the value in the entry field.
99
+ current = RNDK.chtype2Char(scrollp.item[scrollp.current_item])
100
+ entry.setValue(current)
101
+ entry.draw(entry.box)
102
+ return true
103
+ end
104
+ RNDK.beep
105
+ return false
106
+ end
107
+
108
+ complete_word_cb = lambda do |object_type, object, alphalist, key|
109
+ entry = alphalist.entry_field
110
+ scrollp = nil
111
+ selected = -1
112
+ ret = 0
113
+ alt_words = []
114
+
115
+ if entry.info.size == 0
116
+ RNDK.beep
117
+ return true
118
+ end
119
+
120
+ # Look for a unique word match.
121
+ index = RNDK.searchList(alphalist.list, alphalist.list.size, entry.info)
122
+
123
+ # if the index is less than zero, return we didn't find a match
124
+ if index < 0
125
+ RNDK.beep
126
+ return true
127
+ end
128
+
129
+ # Did we find the last word in the list?
130
+ if index == alphalist.list.size - 1
131
+ entry.setValue(alphalist.list[index])
132
+ entry.draw(entry.box)
133
+ return true
134
+ end
135
+
136
+
137
+ # Ok, we found a match, is the next item similar?
138
+ len = [entry.info.size, alphalist.list[index + 1].size].min
139
+ ret = alphalist.list[index + 1][0...len] <=> entry.info
140
+ if ret == 0
141
+ current_index = index
142
+ match = 0
143
+ selected = -1
144
+
145
+ # Start looking for alternate words
146
+ # FIXME(original): bsearch would be more suitable.
147
+ while current_index < alphalist.list.size &&
148
+ (alphalist.list[current_index][0...len] <=> entry.info) == 0
149
+ alt_words << alphalist.list[current_index]
150
+ current_index += 1
151
+ end
152
+
153
+ # Determine the height of the scrolling list.
154
+ height = if alt_words.size < 8 then alt_words.size + 3 else 11 end
155
+
156
+ # Create a scrolling list of close matches.
157
+ scrollp = RNDK::SCROLL.new(entry.screen,
158
+ RNDK::CENTER, RNDK::CENTER, RNDK::RIGHT, height, -30,
159
+ "<C></B/5>Possible Matches.", alt_words, alt_words.size,
160
+ true, Ncurses::A_REVERSE, true, false)
161
+
162
+ # Allow them to select a close match.
163
+ match = scrollp.activate([])
164
+ selected = scrollp.current_item
165
+
166
+ # Check how they exited the list.
167
+ if scrollp.exit_type == :ESCAPE_HIT
168
+ # Destroy the scrolling list.
169
+ scrollp.destroy
170
+
171
+ # beep at the user.
172
+ RNDK.beep
173
+
174
+ # Redraw the alphalist and return.
175
+ alphalist.draw(alphalist.box)
176
+ return true
177
+ end
178
+
179
+ # Destroy the scrolling list.
180
+ scrollp.destroy
181
+
182
+ # Set the entry field to the selected value.
183
+ entry.set(alt_words[match], entry.min, entry.max, entry.box)
184
+
185
+ # Move the highlight bar down to the selected value.
186
+ (0...selected).each do |x|
187
+ alphalist.injectMyScroller(Ncurses::KEY_DOWN)
188
+ end
189
+
190
+ # Redraw the alphalist.
191
+ alphalist.draw(alphalist.box)
192
+ else
193
+ # Set the entry field with the found item.
194
+ entry.set(alphalist.list[index], entry.min, entry.max, entry.box)
195
+ entry.draw(entry.box)
196
+ end
197
+ return true
198
+ end
199
+
200
+ pre_process_entry_field = lambda do |rndktype, object, alphalist, input|
201
+ scrollp = alphalist.scroll_field
202
+ entry = alphalist.entry_field
203
+ info_len = entry.info.size
204
+ result = 1
205
+ empty = false
206
+
207
+ if alphalist.isBind(:ALPHALIST, input)
208
+ result = 1 # Don't try to use this key in editing
209
+ elsif (RNDK.isChar(input) &&
210
+ input.chr.match(/^[[:alnum:][:punct:]]$/)) ||
211
+ [Ncurses::KEY_BACKSPACE, Ncurses::KEY_DC].include?(input)
212
+ index = 0
213
+ curr_pos = entry.screen_col + entry.left_char
214
+ pattern = entry.info.clone
215
+ if [Ncurses::KEY_BACKSPACE, Ncurses::KEY_DC].include?(input)
216
+ if input == Ncurses::KEY_BACKSPACE
217
+ curr_pos -= 1
218
+ end
219
+ if curr_pos >= 0
220
+ pattern.slice!(curr_pos)
221
+ end
222
+ else
223
+ front = (pattern[0...curr_pos] or '')
224
+ back = (pattern[curr_pos..-1] or '')
225
+ pattern = front + input.chr + back
226
+ end
227
+
228
+ if pattern.size == 0
229
+ empty = true
230
+ elsif (index = RNDK.searchList(alphalist.list,
231
+ alphalist.list.size, pattern)) >= 0
232
+ # XXX: original uses n scroll downs/ups for <10 positions change
233
+ scrollp.setPosition(index)
234
+ alphalist.drawMyScroller
235
+ else
236
+ RNDK.beep
237
+ result = 0
238
+ end
239
+ end
240
+
241
+ if empty
242
+ scrollp.setPosition(0)
243
+ alphalist.drawMyScroller
244
+ end
245
+
246
+ return result
247
+ end
248
+
249
+ # Set the key bindings for the entry field.
250
+ @entry_field.bind(:ENTRY, Ncurses::KEY_UP, adjust_alphalist_cb, self)
251
+ @entry_field.bind(:ENTRY, Ncurses::KEY_DOWN, adjust_alphalist_cb, self)
252
+ @entry_field.bind(:ENTRY, Ncurses::KEY_NPAGE, adjust_alphalist_cb, self)
253
+ @entry_field.bind(:ENTRY, Ncurses::KEY_PPAGE, adjust_alphalist_cb, self)
254
+ @entry_field.bind(:ENTRY, RNDK::KEY_TAB, complete_word_cb, self)
255
+
256
+ # Set up the post-process function for the entry field.
257
+ @entry_field.setPreProcess(pre_process_entry_field, self)
258
+
259
+ # Create the scrolling list. It overlaps the entry field by one line if
260
+ # we are using box-borders.
261
+ temp_height = Ncurses.getmaxy(@entry_field.win) - @border_size
262
+ temp_width = if RNDK::ALPHALIST.isFullWidth(width)
263
+ then RNDK::FULL
264
+ else box_width - 1
265
+ end
266
+
267
+ @scroll_field = RNDK::SCROLL.new(rndkscreen,
268
+ Ncurses.getbegx(@win),
269
+ Ncurses.getbegy(@entry_field.win) + temp_height,
270
+ RNDK::RIGHT,
271
+ box_height - temp_height,
272
+ temp_width,
273
+ '',
274
+ list,
275
+ list_size,
276
+ false,
277
+ Ncurses::A_REVERSE,
278
+ box,
279
+ false)
280
+ @scroll_field.setULchar(Ncurses::ACS_LTEE)
281
+ @scroll_field.setURchar(Ncurses::ACS_RTEE)
282
+
283
+ # Setup the key bindings.
284
+ bindings.each do |from, to|
285
+ self.bind(:ALPHALIST, from, :getc, to)
286
+ end
287
+
288
+ rndkscreen.register(:ALPHALIST, self)
289
+ end
290
+
291
+ # This erases the alphalist from the screen.
292
+ def erase
293
+ if self.validRNDKObject
294
+ @scroll_field.erase
295
+ @entry_field.erase
296
+
297
+ RNDK.eraseCursesWindow(@shadow_win)
298
+ RNDK.eraseCursesWindow(@win)
299
+ end
300
+ end
301
+
302
+ # This moves the alphalist field to the given location.
303
+ def move(xplace, yplace, relative, refresh_flag)
304
+ windows = [@win, @shadow_win]
305
+ subwidgets = [@entry_field, @scroll_field]
306
+ self.move_specific(xplace, yplace, relative, refresh_flag,
307
+ windows, subwidgets)
308
+ end
309
+
310
+ # The alphalist's focus resides in the entry widget. But the scroll widget
311
+ # will not draw items highlighted unless it has focus. Temporarily adjust
312
+ # the focus of the scroll widget when drawing on it to get the right
313
+ # highlighting.
314
+ def saveFocus
315
+ @save = @scroll_field.has_focus
316
+ @scroll_field.has_focus = @entry_field.has_focus
317
+ end
318
+
319
+ def restoreFocus
320
+ @scroll_field.has_focus = @save
321
+ end
322
+
323
+ def drawMyScroller
324
+ self.saveFocus
325
+ @scroll_field.draw(@scroll_field.box)
326
+ self.restoreFocus
327
+ end
328
+
329
+ def injectMyScroller(key)
330
+ self.saveFocus
331
+ @scroll_field.inject(key)
332
+ self.restoreFocus
333
+ end
334
+
335
+ # This draws the alphalist widget.
336
+ def draw(box)
337
+ # Does this widget have a shadow?
338
+ unless @shadow_win.nil?
339
+ Draw.drawShadow(@shadow_win)
340
+ end
341
+
342
+ # Draw in the entry field.
343
+ @entry_field.draw(@entry_field.box)
344
+
345
+ # Draw in the scroll field.
346
+ self.drawMyScroller
347
+ end
348
+
349
+ # This activates the alphalist
350
+ def activate(actions)
351
+ ret = 0
352
+
353
+ # Draw the widget.
354
+ self.draw(@box)
355
+
356
+ # Activate the widget.
357
+ ret = @entry_field.activate(actions)
358
+
359
+ # Copy the exit type from the entry field.
360
+ @exit_type = @entry_field.exit_type
361
+
362
+ # Determine the exit status.
363
+ if @exit_type != :EARLY_EXIT
364
+ return ret
365
+ end
366
+ return 0
367
+ end
368
+
369
+ # This injects a single character into the alphalist.
370
+ def inject(input)
371
+ ret = -1
372
+
373
+ # Draw the widget.
374
+ self.draw(@box)
375
+
376
+ # Inject a character into the widget.
377
+ ret = @entry_field.inject(input)
378
+
379
+ # Copy the eixt type from the entry field.
380
+ @exit_type = @entry_field.exit_type
381
+
382
+ # Determine the exit status.
383
+ if @exit_type == :EARLY_EXIT
384
+ ret = -1
385
+ end
386
+
387
+ @result_data = ret
388
+ return ret
389
+ end
390
+
391
+ # This sets multiple attributes of the widget.
392
+ def set(list, list_size, filler_char, highlight, box)
393
+ self.setContents(list, list_size)
394
+ self.setFillerChar(filler_char)
395
+ self.setHighlight(highlight)
396
+ self.setBox(box)
397
+ end
398
+
399
+ # This function sets the information inside the alphalist.
400
+ def setContents(list, list_size)
401
+ if !self.createList(list, list_size)
402
+ return
403
+ end
404
+
405
+ # Set the information in the scrolling list.
406
+ @scroll_field.set(@list, @list_size, false,
407
+ @scroll_field.highlight, @scroll_field.box)
408
+
409
+ # Clean out the entry field.
410
+ self.setCurrentItem(0)
411
+ @entry_field.clean
412
+
413
+ # Redraw the widget.
414
+ self.erase
415
+ self.draw(@box)
416
+ end
417
+
418
+ # This returns the contents of the widget.
419
+ def getContents(size)
420
+ size << @list_size
421
+ return @list
422
+ end
423
+
424
+ # Get/set the current position in the scroll widget.
425
+ def getCurrentItem
426
+ return @scroll_field.getCurrentItem
427
+ end
428
+
429
+ def setCurrentItem(item)
430
+ if @list_size != 0
431
+ @scroll_field.setCurrentItem(item)
432
+ @entry_field.setValue(@list[@scroll_field.getCurrentItem])
433
+ end
434
+ end
435
+
436
+ # This sets the filler character of the entry field of the alphalist.
437
+ def setFillerChar(filler_character)
438
+ @filler_char = filler_character
439
+ @entry_field.setFillerChar(filler_character)
440
+ end
441
+
442
+ def getFillerChar
443
+ return @filler_char
444
+ end
445
+
446
+ # This sets the highlgith bar attributes
447
+ def setHighlight(highlight)
448
+ @highlight = highlight
449
+ end
450
+
451
+ def getHighlight
452
+ @highlight
453
+ end
454
+
455
+ # These functions set the drawing characters of the widget.
456
+ def setMyULchar(character)
457
+ @entry_field.setULchar(character)
458
+ end
459
+
460
+ def setMyURchar(character)
461
+ @entry_field.setURchar(character)
462
+ end
463
+
464
+ def setMyLLchar(character)
465
+ @scroll_field.setLLchar(character)
466
+ end
467
+
468
+ def setMyLRchar(character)
469
+ @scroll_field.setLRchar(character)
470
+ end
471
+
472
+ def setMyVTchar(character)
473
+ @entry_field.setVTchar(character)
474
+ @scroll_field.setVTchar(character)
475
+ end
476
+
477
+ def setMyHZchar(character)
478
+ @entry_field.setHZchar(character)
479
+ @scroll_field.setHZchar(character)
480
+ end
481
+
482
+ def setMyBXattr(character)
483
+ @entry_field.setBXattr(character)
484
+ @scroll_field.setBXattr(character)
485
+ end
486
+
487
+ # This sets the background attribute of the widget.
488
+ def setBKattr(attrib)
489
+ @entry_field.setBKattr(attrib)
490
+ @scroll_field.setBKattr(attrib)
491
+ end
492
+
493
+ def destroyInfo
494
+ @list = ''
495
+ @list_size = 0
496
+ end
497
+
498
+ # This destroys the alpha list
499
+ def destroy
500
+ self.destroyInfo
501
+
502
+ # Clean the key bindings.
503
+ self.cleanBindings(:ALPHALIST)
504
+
505
+ @entry_field.destroy
506
+ @scroll_field.destroy
507
+
508
+ # Free up the window pointers.
509
+ RNDK.deleteCursesWindow(@shadow_win)
510
+ RNDK.deleteCursesWindow(@win)
511
+
512
+ # Unregister the object.
513
+ RNDK::Screen.unregister(:ALPHALIST, self)
514
+ end
515
+
516
+ # This function sets the pre-process function.
517
+ def setPreProcess(callback, data)
518
+ @entry_field.setPreProcess(callback, data)
519
+ end
520
+
521
+ # This function sets the post-process function.
522
+ def setPostProcess(callback, data)
523
+ @entry_field.setPostProcess(callback, data)
524
+ end
525
+
526
+ def createList(list, list_size)
527
+ if list_size >= 0
528
+ newlist = []
529
+
530
+ # Copy in the new information.
531
+ status = true
532
+ (0...list_size).each do |x|
533
+ newlist << list[x]
534
+ if newlist[x] == 0
535
+ status = false
536
+ break
537
+ end
538
+ end
539
+ if status
540
+ self.destroyInfo
541
+ @list_size = list_size
542
+ @list = newlist
543
+ @list.sort!
544
+ end
545
+ else
546
+ self.destroyInfo
547
+ status = true
548
+ end
549
+ return status
550
+ end
551
+
552
+ def focus
553
+ self.entry_field.focus
554
+ end
555
+
556
+ def unfocus
557
+ self.entry_field.unfocus
558
+ end
559
+
560
+ def self.isFullWidth(width)
561
+ width == RNDK::FULL || (Ncurses.COLS != 0 && width >= Ncurses.COLS)
562
+ end
563
+
564
+ def position
565
+ super(@win)
566
+ end
567
+
568
+ def object_type
569
+ :ALPHALIST
570
+ end
571
+ end
572
+ end