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,545 @@
1
+ require 'rndk'
2
+
3
+ module RNDK
4
+ class SLIDER < RNDK::Widget
5
+ def initialize(rndkscreen, xplace, yplace, title, label, filler,
6
+ field_width, start, low, high, inc, fast_inc, box, shadow)
7
+ super()
8
+ parent_width = Ncurses.getmaxx(rndkscreen.window)
9
+ parent_height = Ncurses.getmaxy(rndkscreen.window)
10
+ bindings = {
11
+ 'u' => Ncurses::KEY_UP,
12
+ 'U' => Ncurses::KEY_PPAGE,
13
+ RNDK::BACKCHAR => Ncurses::KEY_PPAGE,
14
+ RNDK::FORCHAR => Ncurses::KEY_NPAGE,
15
+ 'g' => Ncurses::KEY_HOME,
16
+ '^' => Ncurses::KEY_HOME,
17
+ 'G' => Ncurses::KEY_END,
18
+ '$' => Ncurses::KEY_END,
19
+ }
20
+ self.setBox(box)
21
+ box_height = @border_size * 2 + 1
22
+
23
+ # Set some basic values of the widget's data field.
24
+ @label = []
25
+ @label_len = 0
26
+ @label_win = nil
27
+ high_value_len = self.formattedSize(high)
28
+
29
+ # If the field_width is a negative will be COLS-field_width,
30
+ # otherwise field_width will be the given width.
31
+ field_width = RNDK.setWidgetDimension(parent_width, field_width, 0)
32
+
33
+ # Translate the label string to a chtype array.
34
+ if !(label.nil?) && label.size > 0
35
+ label_len = []
36
+ @label = RNDK.char2Chtype(label, label_len, [])
37
+ @label_len = label_len[0]
38
+ box_width = @label_len + field_width +
39
+ high_value_len + 2 * @border_size
40
+ else
41
+ box_width = field_width + high_value_len + 2 * @border_size
42
+ end
43
+
44
+ old_width = box_width
45
+ box_width = self.setTitle(title, box_width)
46
+ horizontal_adjust = (box_width - old_width) / 2
47
+
48
+ box_height += @title_lines
49
+
50
+ # Make sure we didn't extend beyond the dimensions of the window.
51
+ box_width = [box_width, parent_width].min
52
+ box_height = [box_height, parent_height].min
53
+ field_width = [field_width, box_width - @label_len - high_value_len - 1].min
54
+
55
+ # Rejustify the x and y positions if we need to.
56
+ xtmp = [xplace]
57
+ ytmp = [yplace]
58
+ RNDK.alignxy(rndkscreen.window, xtmp, ytmp, box_width, box_height)
59
+ xpos = xtmp[0]
60
+ ypos = ytmp[0]
61
+
62
+ # Make the widget's window.
63
+ @win = Ncurses.newwin(box_height, box_width, ypos, xpos)
64
+
65
+ # Is the main window nil?
66
+ if @win.nil?
67
+ self.destroy
68
+ return nil
69
+ end
70
+
71
+ # Create the widget's label window.
72
+ if @label.size > 0
73
+ @label_win = Ncurses.subwin(@win,
74
+ 1,
75
+ @label_len,
76
+ ypos + @title_lines + @border_size,
77
+ xpos + horizontal_adjust + @border_size)
78
+ if @label_win.nil?
79
+ self.destroy
80
+ return nil
81
+ end
82
+ end
83
+
84
+ # Create the widget's data field window.
85
+ @field_win = Ncurses.subwin(@win,
86
+ 1,
87
+ field_width + high_value_len - 1,
88
+ ypos + @title_lines + @border_size,
89
+ xpos + @label_len + horizontal_adjust + @border_size)
90
+
91
+ if @field_win.nil?
92
+ self.destroy
93
+ return nil
94
+ end
95
+ Ncurses.keypad(@field_win, true)
96
+ Ncurses.keypad(@win, true)
97
+
98
+ # Create the widget's data field.
99
+ @screen = rndkscreen
100
+ @window = rndkscreen.window
101
+ @shadow_win = nil
102
+ @box_width = box_width
103
+ @box_height = box_height
104
+ @field_width = field_width - 1
105
+ @filler = filler
106
+ @low = low
107
+ @high = high
108
+ @current = start
109
+ @inc = inc
110
+ @fastinc = fast_inc
111
+ @accepts_focus = true
112
+ @input_window = @win
113
+ @shadow = shadow
114
+ @field_edit = 0
115
+
116
+ # Set the start value.
117
+ if start < low
118
+ @current = low
119
+ end
120
+
121
+ # Do we want a shadow?
122
+ if shadow
123
+ @shadow_win = Ncurses.newwin(box_height,
124
+ box_width,
125
+ ypos + 1,
126
+ xpos + 1)
127
+ if @shadow_win.nil?
128
+ self.destroy
129
+ return nil
130
+ end
131
+ end
132
+
133
+ # Setup the key bindings.
134
+ bindings.each do |from, to|
135
+ self.bind(:SLIDER, from, :getc, to)
136
+ end
137
+
138
+ rndkscreen.register(:SLIDER, self)
139
+ end
140
+
141
+ # This allows the person to use the widget's data field.
142
+ def activate(actions)
143
+ # Draw the widget.
144
+ self.draw(@box)
145
+
146
+ if actions.nil? || actions.size == 0
147
+ while true
148
+ input = self.getch([])
149
+
150
+ # Inject the character into the widget.
151
+ ret = self.inject(input)
152
+ if @exit_type != :EARLY_EXIT
153
+ return ret
154
+ end
155
+ end
156
+ else
157
+ # Inject each character one at a time.
158
+ actions.each do |action|
159
+ ret = self.inject(action)
160
+ if @exit_type != :EARLY_EXIT
161
+ return ret
162
+ end
163
+ end
164
+ end
165
+
166
+ # Set the exit type and return.
167
+ self.setExitType(0)
168
+ return -1
169
+ end
170
+
171
+ # Check if the value lies outside the low/high range. If so, force it in.
172
+ def limitCurrentValue
173
+ if @current < @low
174
+ @current = @low
175
+ RNDK.beep
176
+ elsif @current > @high
177
+ @current = @high
178
+ RNDK.beep
179
+ end
180
+ end
181
+
182
+ # Move the cursor to the given edit-position.
183
+ def moveToEditPosition(new_position)
184
+ return Ncurses.wmove(@field_win,
185
+ 0,
186
+ @field_width + self.formattedSize(@current) - new_position)
187
+ end
188
+
189
+ # Check if the cursor is on a valid edit-position. This must be one of
190
+ # the non-blank cells in the field.
191
+ def validEditPosition(new_position)
192
+ if new_position <= 0 || new_position >= @field_width
193
+ return false
194
+ end
195
+ if self.moveToEditPosition(new_position) == Ncurses::ERR
196
+ return false
197
+ end
198
+ ch = Ncurses.winch(@field_win)
199
+ if RNDK.CharOf(ch) != ' '
200
+ return true
201
+ end
202
+ if new_position > 1
203
+ # Don't use recursion - only one level is wanted
204
+ if self.moveToEditPosition(new_position - 1) == Ncurses::ERR
205
+ return false
206
+ end
207
+ ch = Ncurses.winch(@field_win)
208
+ return RNDK.CharOf(ch) != ' '
209
+ end
210
+ return false
211
+ end
212
+
213
+ # Set the edit position. Normally the cursor is one cell to the right of
214
+ # the editable field. Moving it left, over the field, allows the user to
215
+ # modify cells by typing in replacement characters for the field's value.
216
+ def setEditPosition(new_position)
217
+ if new_position < 0
218
+ RNDK.beep
219
+ elsif new_position == 0
220
+ @field_edit = new_position
221
+ elsif self.validEditPosition(new_position)
222
+ @field_edit = new_position
223
+ else
224
+ RNDK.beep
225
+ end
226
+ end
227
+
228
+ # Remove the character from the string at the given column, if it is blank.
229
+ # Returns true if a change was made.
230
+ def self.removeChar(string, col)
231
+ result = false
232
+ if col >= 0 && string[col] != ' '
233
+ while col < string.size - 1
234
+ string[col] = string[col + 1]
235
+ col += 1
236
+ end
237
+ string.chop!
238
+ result = true
239
+ end
240
+ return result
241
+ end
242
+
243
+ # Perform an editing function for the field.
244
+ def performEdit(input)
245
+ result = false
246
+ modify = true
247
+ base = @field_width
248
+ need = self.formattedSize(@current)
249
+ temp = ''
250
+ col = need - @field_edit
251
+
252
+ adj = if col < 0 then -col else 0 end
253
+ if adj != 0
254
+ temp = ' ' * adj
255
+ end
256
+ Ncurses.wmove(@field_win, 0, base)
257
+ Ncurses.winnstr(@field_win, temp, need)
258
+ temp << ' '
259
+ if RNDK.isChar(input) # Replace the char at the cursor
260
+ temp[col] = input.chr
261
+ elsif input == Ncurses::KEY_BACKSPACE
262
+ # delete the char before the cursor
263
+ modify = RNDK::SLIDER.removeChar(temp, col - 1)
264
+ elsif input == Ncurses::KEY_DC
265
+ # delete the char at the cursor
266
+ modify = RNDK::SLIDER.removeChar(temp, col)
267
+ else
268
+ modify = false
269
+ end
270
+ if modify &&
271
+ ((value, test) = temp.scanf(self.SCAN_FMT)).size == 2 &&
272
+ test == ' ' && value >= @low && value <= @high
273
+ self.setValue(value)
274
+ result = true
275
+ end
276
+ return result
277
+ end
278
+
279
+ def self.Decrement(value, by)
280
+ if value - by < value
281
+ value - by
282
+ else
283
+ value
284
+ end
285
+ end
286
+
287
+ def self.Increment(value, by)
288
+ if value + by > value
289
+ value + by
290
+ else
291
+ value
292
+ end
293
+ end
294
+
295
+ # This function injects a single character into the widget.
296
+ def inject(input)
297
+ pp_return = 1
298
+ ret = -1
299
+ complete = false
300
+
301
+ # Set the exit type.
302
+ self.setExitType(0)
303
+
304
+ # Draw the field.
305
+ self.drawField
306
+
307
+ # Check if there is a pre-process function to be called.
308
+ unless @pre_process_func.nil?
309
+ # Call the pre-process function.
310
+ pp_return = @pre_process_func.call(:SLIDER, self,
311
+ @pre_process_data, input)
312
+ end
313
+
314
+ # Should we continue?
315
+ if pp_return != 0
316
+ # Check for a key binding.
317
+ if self.checkBind(:SLIDER, input)
318
+ complete = true
319
+ else
320
+ case input
321
+ when Ncurses::KEY_LEFT
322
+ self.setEditPosition(@field_edit + 1)
323
+ when Ncurses::KEY_RIGHT
324
+ self.setEditPosition(@field_edit - 1)
325
+ when Ncurses::KEY_DOWN
326
+ @current = RNDK::SLIDER.Decrement(@current, @inc)
327
+ when Ncurses::KEY_UP
328
+ @current = RNDK::SLIDER.Increment(@current, @inc)
329
+ when Ncurses::KEY_PPAGE
330
+ @current = RNDK::SLIDER.Increment(@current, @fastinc)
331
+ when Ncurses::KEY_NPAGE
332
+ @current = RNDK::SLIDER.Decrement(@current, @fastinc)
333
+ when Ncurses::KEY_HOME
334
+ @current = @low
335
+ when Ncurses::KEY_END
336
+ @current = @high
337
+ when RNDK::KEY_TAB, RNDK::KEY_RETURN, Ncurses::KEY_ENTER
338
+ self.setExitType(input)
339
+ ret = @current
340
+ complete = true
341
+ when RNDK::KEY_ESC
342
+ self.setExitType(input)
343
+ complete = true
344
+ when Ncurses::ERR
345
+ self.setExitType(input)
346
+ complete = true
347
+ when RNDK::REFRESH
348
+ @screen.erase
349
+ @screen.refresh
350
+ else
351
+ if @field_edit != 0
352
+ if !self.performEdit(input)
353
+ RNDK.beep
354
+ end
355
+ else
356
+ # The cursor is not within the editable text. Interpret
357
+ # input as commands.
358
+ case input
359
+ when 'd'.ord, '-'.ord
360
+ return self.inject(Ncurses::KEY_DOWN)
361
+ when '+'.ord
362
+ return self.inject(Ncurses::KEY_UP)
363
+ when 'D'.ord
364
+ return self.inject(Ncurses::KEY_NPAGE)
365
+ when '0'.ord
366
+ return self.inject(Ncurses::KEY_HOME)
367
+ else
368
+ RNDK.beep
369
+ end
370
+ end
371
+ end
372
+ end
373
+ self.limitCurrentValue
374
+
375
+ # Should we call a post-process?
376
+ if !complete && !(@post_process_func.nil?)
377
+ @post_process_func.call(:SLIDER, self, @post_process_data, input)
378
+ end
379
+ end
380
+
381
+ if !complete
382
+ self.drawField
383
+ self.setExitType(0)
384
+ end
385
+
386
+ @return_data = 0
387
+ return ret
388
+ end
389
+
390
+ # This moves the widget's data field to the given location.
391
+ def move(xplace, yplace, relative, refresh_flag)
392
+ windows = [@win, @label_win, @field_win, @shadow_win]
393
+
394
+ self.move_specific(xplace, yplace, relative, refresh_flag, windows, [])
395
+ end
396
+
397
+ # This function draws the widget.
398
+ def draw(box)
399
+ # Draw the shadow.
400
+ unless @shadow_win.nil?
401
+ Draw.drawShadow(@shadow_win)
402
+ end
403
+
404
+ # Box the widget if asked.
405
+ if box
406
+ Draw.drawObjBox(@win, self)
407
+ end
408
+
409
+ self.drawTitle(@win)
410
+
411
+ # Draw the label.
412
+ unless @label_win.nil?
413
+ Draw.writeChtype(@label_win, 0, 0, @label, RNDK::HORIZONTAL,
414
+ 0, @label_len)
415
+ Ncurses.wrefresh(@label_win)
416
+ end
417
+ Ncurses.wrefresh @win
418
+
419
+ # Draw the field window.
420
+ self.drawField
421
+ end
422
+
423
+ # This draws the widget.
424
+ def drawField
425
+ step = 1.0 * @field_width / (@high - @low)
426
+
427
+ # Determine how many filler characters need to be drawn.
428
+ filler_characters = (@current - @low) * step
429
+
430
+ Ncurses.werase(@field_win)
431
+
432
+ # Add the character to the window.
433
+ (0...filler_characters).each do |x|
434
+ Ncurses.mvwaddch(@field_win, 0, x, @filler)
435
+ end
436
+
437
+ # Draw the value in the field.
438
+ Draw.writeCharAttrib(@field_win, @field_width, 0, @current.to_s,
439
+ Ncurses::A_NORMAL, RNDK::HORIZONTAL, 0, @current.to_s.size)
440
+
441
+ self.moveToEditPosition(@field_edit)
442
+ Ncurses.wrefresh(@field_win)
443
+ end
444
+
445
+ # This sets the background attribute of the widget.
446
+ def setBKattr(attrib)
447
+ # Set the widget's background attribute.
448
+ Ncurses.wbkgd(@win, attrib)
449
+ Ncurses.wbkgd(@field_win, attrib)
450
+ Ncurses.wbkgd(@label_win, attrib) unless @label_win.nil?
451
+ end
452
+
453
+ # This function destroys the widget.
454
+ def destroy
455
+ self.cleanTitle
456
+ @label = []
457
+
458
+ # Clean up the windows.
459
+ RNDK.deleteCursesWindow(@field_win)
460
+ RNDK.deleteCursesWindow(@label_win)
461
+ RNDK.deleteCursesWindow(@shadow_win)
462
+ RNDK.deleteCursesWindow(@win)
463
+
464
+ # Clean the key bindings.
465
+ self.cleanBindings(:SLIDER)
466
+
467
+ # Unregister this object.
468
+ RNDK::Screen.unregister(:SLIDER, self)
469
+ end
470
+
471
+ # This function erases the widget from the screen.
472
+ def erase
473
+ if self.validRNDKObject
474
+ RNDK.eraseCursesWindow(@label_win)
475
+ RNDK.eraseCursesWindow(@field_win)
476
+ RNDK.eraseCursesWindow(@lwin)
477
+ RNDK.eraseCursesWindow(@shadow_win)
478
+ end
479
+ end
480
+
481
+ def formattedSize(value)
482
+ return value.to_s.size
483
+ end
484
+
485
+ # This function sets the low/high/current values of the widget.
486
+ def set(low, high, value, box)
487
+ self.setLowHigh(low, high)
488
+ self.setValue(value)
489
+ self.setBox(box)
490
+ end
491
+
492
+ # This sets the widget's value.
493
+ def setValue(value)
494
+ @current = value
495
+ self.limitCurrentValue
496
+ end
497
+
498
+ def getValue
499
+ return @current
500
+ end
501
+
502
+ # This function sets the low/high values of the widget.
503
+ def setLowHigh(low, high)
504
+ # Make sure the values aren't out of bounds.
505
+ if low <= high
506
+ @low = low
507
+ @high = high
508
+ elsif low > high
509
+ @low = high
510
+ @high = low
511
+ end
512
+
513
+ # Make sure the user hasn't done something silly.
514
+ self.limitCurrentValue
515
+ end
516
+
517
+ def getLowValue
518
+ return @low
519
+ end
520
+
521
+ def getHighValue
522
+ return @high
523
+ end
524
+
525
+ def focus
526
+ self.draw(@box)
527
+ end
528
+
529
+ def unfocus
530
+ self.draw(@box)
531
+ end
532
+
533
+ def SCAN_FMT
534
+ '%d%c'
535
+ end
536
+
537
+ def position
538
+ super(@win)
539
+ end
540
+
541
+ def object_type
542
+ :SLIDER
543
+ end
544
+ end
545
+ end