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