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,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