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
data/demos/clock.rb ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Shows a colored clock on the screen according to
4
+ # current system time.
5
+ # Press any key to exit.
6
+
7
+ require 'rndk/label'
8
+
9
+ begin
10
+ # Set up RNDK
11
+ curses_win = Ncurses.initscr
12
+ rndkscreen = RNDK::Screen.new curses_win
13
+ RNDK::Draw.initRNDKColor
14
+
15
+ # Initial time string
16
+ mesg = ['</1/B>HH:MM:SS']
17
+
18
+ # Declare the labels.
19
+ label = RNDK::LABEL.new(rndkscreen, RNDK::CENTER, RNDK::CENTER, mesg, 1, true, true)
20
+
21
+ # Woops, something bad happened
22
+ if label.nil?
23
+ rndkscreen.destroy
24
+ RNDK.end_rndk
25
+
26
+ puts "Cannot create the label. Is the window too small?"
27
+ exit 1
28
+ end
29
+
30
+ # hiding cursor
31
+ Ncurses.curs_set 0
32
+
33
+ # Will wait 50ms before getting input
34
+ Ncurses.wtimeout(label.screen.window, 50)
35
+
36
+ begin
37
+ current_time = Time.now.getlocal
38
+
39
+ # Formatting time string.
40
+ str = "<C></B/29>%02d:%02d:%02d" % [current_time.hour, current_time.min, current_time.sec]
41
+ mesg = [str]
42
+
43
+ # Set the label contents
44
+ label.set(mesg, 1, label.box)
45
+
46
+ # Draw the label and sleep
47
+ label.draw(label.box)
48
+ Ncurses.napms(500)
49
+ end while (Ncurses.wgetch(label.screen.window)) == Ncurses::ERR
50
+
51
+ # Clean up
52
+ label.destroy
53
+ rndkscreen.destroy
54
+ RNDK::Screen.end_rndk
55
+ end
56
+
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Displays a colored "Hello, World!" Label on the screen.
4
+
5
+ # Widget we'll use
6
+ require 'rndk/label'
7
+
8
+ begin
9
+ # Startup Ncurses and RNDK
10
+ rndkscreen = RNDK::Screen.new
11
+
12
+ # Set up RNDK colors
13
+ RNDK::Draw.initRNDKColor
14
+
15
+ # Set the labels' content.
16
+ # (RNDK supports a "markup" string, with colors
17
+ # and attributes. Check out the other examples
18
+ # for more)
19
+ mesg = [
20
+ "</5><#UL><#HL(30)><#UR>",
21
+ "</5><#VL(10)>Hello, World!<#VL(9)>",
22
+ "</5><#LL><#HL(30)><#LR)",
23
+ "(press space to exit)"
24
+ ]
25
+
26
+ # Declare the labels.
27
+ label = RNDK::LABEL.new(rndkscreen, # screen
28
+ RNDK::CENTER, # x
29
+ RNDK::CENTER, # y
30
+ mesg, # message
31
+ 4, # lines count
32
+ true, # box?
33
+ true) # shadow?
34
+
35
+ if label.nil?
36
+ # Clean up the memory.
37
+ rndkscreen.destroy
38
+
39
+ # End curses...
40
+ RNDK::Screen.end_rndk
41
+
42
+ puts "Cannot create the label. Is the window too small?"
43
+ exit 1
44
+ end
45
+
46
+ # Draw the RNDK screen and waits for space to be pressed.
47
+ rndkscreen.refresh
48
+ label.wait(' ')
49
+
50
+ # Ending Ncurses and RNDK
51
+ RNDK::Screen.end_rndk
52
+ end
53
+
54
+ # Note: Unlike C's CDK, there's no need to clean up
55
+ # widgets/screens when finishing execution.
56
+
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Shows an Entry Widget, allowing you to move it around
4
+ # the screen via the Widget#position method.
5
+ # After positioning, you can interact with it normally.
6
+ # At the end, it shows you what you've typed.
7
+ #
8
+ # The following key bindings can be used to move the
9
+ # Widget around the screen:
10
+ #
11
+ # Up Arrow:: Moves the widget up one row.
12
+ # Down Arrow:: Moves the widget down one row.
13
+ # Left Arrow:: Moves the widget left one column
14
+ # Right Arrow:: Moves the widget right one column
15
+ # 1:: Moves the widget down one row and left one column.
16
+ # 2:: Moves the widget down one row.
17
+ # 3:: Moves the widget down one row and right one column.
18
+ # 4:: Moves the widget left one column.
19
+ # 5:: Centers the widget both vertically and horizontally.
20
+ # 6:: Moves the widget right one column
21
+ # 7:: Moves the widget up one row and left one column.
22
+ # 8:: Moves the widget up one row.
23
+ # 9:: Moves the widget up one row and right one column.
24
+ # t:: Moves the widget to the top of the screen.
25
+ # b:: Moves the widget to the bottom of the screen.
26
+ # l:: Moves the widget to the left of the screen.
27
+ # r:: Moves the widget to the right of the screen.
28
+ # c:: Centers the widget between the left and right of the window.
29
+ # C:: Centers the widget between the top and bottom of the window.
30
+ # Escape:: Returns the widget to its original position.
31
+ # Return:: Exits the function and leaves the Widget where it was.
32
+ #
33
+ require 'rndk/entry'
34
+
35
+ begin
36
+ label = "</U/5>Position me:<!U!5> "
37
+
38
+ # Set up RNDK
39
+ curses_win = Ncurses.initscr
40
+ rndkscreen = RNDK::Screen.new(curses_win)
41
+
42
+ # Set up RNDK colors
43
+ RNDK::Draw.initRNDKColor
44
+
45
+ # Create the entry field widget.
46
+ entry = RNDK::ENTRY.new(rndkscreen,
47
+ RNDK::CENTER, # x
48
+ RNDK::CENTER, # y
49
+ '',
50
+ label,
51
+ Ncurses::A_NORMAL,
52
+ '.',
53
+ :MIXED,
54
+ 30, # w
55
+ 0,
56
+ 256,
57
+ true,
58
+ false)
59
+
60
+ if entry.nil?
61
+ rndkscreen.destroy
62
+ RNDK::Screen.end_rndk
63
+
64
+ puts "Cannot create the entry box. Is the window too small?"
65
+ exit 1
66
+ end
67
+
68
+ # Let the user move the widget around the window.
69
+ entry.draw(entry.box)
70
+ entry.position
71
+
72
+ # Activate the entry field.
73
+ info = entry.activate('')
74
+
75
+ # Tell them what they typed.
76
+ if entry.exit_type == :ESCAPE_HIT
77
+ mesg = [
78
+ "<C>You hit escape. No information passed back.",
79
+ "",
80
+ "<C>Press any key to continue."
81
+ ]
82
+ rndkscreen.popupLabel mesg
83
+
84
+ elsif entry.exit_type == :NORMAL
85
+ mesg = [
86
+ "<C>You typed in the following",
87
+ "<C>%.*s" % [236, info], # FIXME magic number
88
+ "",
89
+ "<C>Press any key to continue."
90
+ ]
91
+ rndkscreen.popupLabel mesg
92
+ end
93
+
94
+ # Clean up
95
+ entry.destroy
96
+ rndkscreen.destroy
97
+ RNDK::Screen.end_rndk
98
+
99
+ # Just in case something bad happens.
100
+ rescue Exception => e
101
+ RNDK::Screen.end_rndk
102
+
103
+ puts e
104
+ puts e.inspect
105
+ puts e.backtrace
106
+ exit 1
107
+ end
108
+
data/lib/rndk.rb ADDED
@@ -0,0 +1,912 @@
1
+ # Welcome to the Ruby Ncurses Development Kit!
2
+
3
+ require 'ffi-ncurses'
4
+ require 'scanf'
5
+
6
+ require 'rndk/core/draw'
7
+ require 'rndk/core/display'
8
+ require 'rndk/core/traverse'
9
+ require 'rndk/core/widget'
10
+ require 'rndk/core/screen'
11
+
12
+ # Shortcut to avoid typing FFI::NCurses all the time.
13
+ # You can use it too!
14
+ Ncurses = FFI::NCurses
15
+
16
+ # The main RNDK module - contains everything we need.
17
+ #
18
+ # ## Developer Notes
19
+ #
20
+ # * Any questions on what a `Ncurses.*` function do, check it's man
21
+ # page with `man lowercase_function_name`.
22
+ #
23
+ module RNDK
24
+
25
+ # Some nice global constants.
26
+
27
+ RNDK_PATHMAX = 256
28
+
29
+ L_MARKER = '<'
30
+ R_MARKER = '>'
31
+
32
+ LEFT = 9000
33
+ RIGHT = 9001
34
+ CENTER = 9002
35
+ TOP = 9003
36
+ BOTTOM = 9004
37
+ HORIZONTAL = 9005
38
+ VERTICAL = 9006
39
+ FULL = 9007
40
+
41
+ NONE = 0
42
+ ROW = 1
43
+ COL = 2
44
+
45
+ MAX_BINDINGS = 300
46
+ MAX_ITEMS = 2000
47
+ MAX_BUTTONS = 200
48
+
49
+ # Key value when pressing Ctrl+`char`.
50
+ def RNDK.CTRL(char)
51
+ char.ord & 0x1f
52
+ end
53
+
54
+ # Aliasing the default keybindings
55
+ # for Widget interaction.
56
+ #
57
+ # Example: `RNDK.CTRL('L')` is `Ctrl+L` or `C-l`
58
+ REFRESH = RNDK.CTRL('L')
59
+ PASTE = RNDK.CTRL('V')
60
+ COPY = RNDK.CTRL('Y')
61
+ ERASE = RNDK.CTRL('U')
62
+ CUT = RNDK.CTRL('X')
63
+ BEGOFLINE = RNDK.CTRL('A')
64
+ ENDOFLINE = RNDK.CTRL('E')
65
+ BACKCHAR = RNDK.CTRL('B')
66
+ FORCHAR = RNDK.CTRL('F')
67
+ TRANSPOSE = RNDK.CTRL('T')
68
+ NEXT = RNDK.CTRL('N')
69
+ PREV = RNDK.CTRL('P')
70
+ DELETE = "\177".ord
71
+ KEY_ESC = "\033".ord
72
+ KEY_RETURN = "\012".ord
73
+ KEY_TAB = "\t".ord
74
+
75
+ ALL_SCREENS = []
76
+ ALL_OBJECTS = []
77
+
78
+ # This beeps then flushes the stdout stream.
79
+ #
80
+ # Normally it emits an audible bell - if that's not
81
+ # possible it flashes the screen.
82
+ def RNDK.beep
83
+ Ncurses.beep
84
+ $stdout.flush
85
+ end
86
+
87
+ # This sets a blank string to be len of the given characer.
88
+ def RNDK.cleanChar(s, len, character)
89
+ s << character * len
90
+ end
91
+
92
+ def RNDK.cleanChtype(s, len, character)
93
+ s.concat(character * len)
94
+ end
95
+
96
+ # This takes an x and y position and realigns the values iff they sent in
97
+ # values like CENTER, LEFT, RIGHT
98
+ #
99
+ # window is an Ncurses::WINDOW object
100
+ # xpos, ypos is an array with exactly one value, an integer
101
+ # box_width, box_height is an integer
102
+ def RNDK.alignxy (window, xpos, ypos, box_width, box_height)
103
+ first = Ncurses.getbegx window
104
+ last = Ncurses.getmaxx window
105
+ if (gap = (last - box_width)) < 0
106
+ gap = 0
107
+ end
108
+ last = first + gap
109
+
110
+ case xpos[0]
111
+ when LEFT
112
+ xpos[0] = first
113
+ when RIGHT
114
+ xpos[0] = first + gap
115
+ when CENTER
116
+ xpos[0] = first + (gap / 2)
117
+ else
118
+ if xpos[0] > last
119
+ xpos[0] = last
120
+ elsif xpos[0] < first
121
+ xpos[0] = first
122
+ end
123
+ end
124
+
125
+ first = Ncurses.getbegy window
126
+ last = Ncurses.getmaxy window
127
+ if (gap = (last - box_height)) < 0
128
+ gap = 0
129
+ end
130
+ last = first + gap
131
+
132
+ case ypos[0]
133
+ when TOP
134
+ ypos[0] = first
135
+ when BOTTOM
136
+ ypos[0] = first + gap
137
+ when CENTER
138
+ ypos[0] = first + (gap / 2)
139
+ else
140
+ if ypos[0] > last
141
+ ypos[0] = last
142
+ elsif ypos[0] < first
143
+ ypos[0] = first
144
+ end
145
+ end
146
+ end
147
+
148
+ # This takes a string, a field width, and a justification type
149
+ # and returns the adjustment to make, to fill the justification
150
+ # requirement
151
+ def RNDK.justifyString (box_width, mesg_length, justify)
152
+
153
+ # make sure the message isn't longer than the width
154
+ # if it is, return 0
155
+ if mesg_length >= box_width
156
+ return 0
157
+ end
158
+
159
+ # try to justify the message
160
+ case justify
161
+ when LEFT
162
+ 0
163
+ when RIGHT
164
+ box_width - mesg_length
165
+ when CENTER
166
+ (box_width - mesg_length) / 2
167
+ else
168
+ justify
169
+ end
170
+ end
171
+
172
+ # This reads a file and sticks it into the list provided.
173
+ def RNDK.readFile(filename, array)
174
+ begin
175
+ fd = File.new(filename, "r")
176
+ rescue
177
+ return -1
178
+ end
179
+
180
+ lines = fd.readlines.map do |line|
181
+ if line.size > 0 && line[-1] == "\n"
182
+ line[0...-1]
183
+ else
184
+ line
185
+ end
186
+ end
187
+ array.concat(lines)
188
+ fd.close
189
+ array.size
190
+ end
191
+
192
+ def RNDK.encodeAttribute (string, from, mask)
193
+ mask << 0
194
+ case string[from + 1]
195
+ when 'B'
196
+ mask[0] = Ncurses::A_BOLD
197
+ when 'D'
198
+ mask[0] = Ncurses::A_DIM
199
+ when 'K'
200
+ mask[0] = Ncurses::A_BLINK
201
+ when 'R'
202
+ mask[0] = Ncurses::A_REVERSE
203
+ when 'S'
204
+ mask[0] = Ncurses::A_STANDOUT
205
+ when 'U'
206
+ mask[0] = Ncurses::A_UNDERLINE
207
+ end
208
+
209
+ if mask[0] != 0
210
+ from += 1
211
+ elsif RNDK.digit?(string[from+1]) and RNDK.digit?(string[from + 2])
212
+ if Ncurses.has_colors
213
+ # XXX: Only checks if terminal has colours not if colours are started
214
+ pair = string[from + 1..from + 2].to_i
215
+ mask[0] = Ncurses.COLOR_PAIR(pair)
216
+ else
217
+ mask[0] = Ncurses.A_BOLD
218
+ end
219
+
220
+ from += 2
221
+ elsif RNDK.digit?(string[from + 1])
222
+ if Ncurses.has_colors
223
+ # XXX: Only checks if terminal has colours not if colours are started
224
+ pair = string[from + 1].to_i
225
+ mask[0] = Ncurses.COLOR_PAIR(pair)
226
+ else
227
+ mask[0] = Ncurses.A_BOLD
228
+ end
229
+
230
+ from += 1
231
+ end
232
+
233
+ return from
234
+ end
235
+
236
+ # The reverse of encodeAttribute
237
+ # Well, almost. If attributes such as bold and underline are combined in the
238
+ # same string, we do not necessarily reconstruct them in the same order.
239
+ # Also, alignment markers and tabs are lost.
240
+
241
+ def RNDK.decodeAttribute (string, from, oldattr, newattr)
242
+ table = {
243
+ 'B' => Ncurses::A_BOLD,
244
+ 'D' => Ncurses::A_DIM,
245
+ 'K' => Ncurses::A_BLINK,
246
+ 'R' => Ncurses::A_REVERSE,
247
+ 'S' => Ncurses::A_STANDOUT,
248
+ 'U' => Ncurses::A_UNDERLINE
249
+ }
250
+
251
+ result = if string.nil? then '' else string end
252
+ base_len = result.size
253
+ tmpattr = oldattr & Ncurses::A_ATTRIBUTES
254
+
255
+ newattr &= Ncurses::A_ATTRIBUTES
256
+ if tmpattr != newattr
257
+ while tmpattr != newattr
258
+ found = false
259
+ table.keys.each do |key|
260
+ if (table[key] & tmpattr) != (table[key] & newattr)
261
+ found = true
262
+ result << RNDK::L_MARKER
263
+ if (table[key] & tmpattr).nonzero?
264
+ result << '!'
265
+ tmpattr &= ~(table[key])
266
+ else
267
+ result << '/'
268
+ tmpattr |= table[key]
269
+ end
270
+ result << key
271
+ break
272
+ end
273
+ end
274
+ # XXX: Only checks if terminal has colours not if colours are started
275
+ if Ncurses.has_colors
276
+ if (tmpattr & Ncurses::A_COLOR) != (newattr & Ncurses::A_COLOR)
277
+ oldpair = Ncurses.PAIR_NUMBER(tmpattr)
278
+ newpair = Ncurses.PAIR_NUMBER(newattr)
279
+ if !found
280
+ found = true
281
+ result << RNDK::L_MARKER
282
+ end
283
+ if newpair.zero?
284
+ result << '!'
285
+ result << oldpair.to_s
286
+ else
287
+ result << '/'
288
+ result << newpair.to_s
289
+ end
290
+ tmpattr &= ~(Ncurses::A_COLOR)
291
+ newattr &= ~(Ncurses::A_COLOR)
292
+ end
293
+ end
294
+
295
+ if found
296
+ result << RNDK::R_MARKER
297
+ else
298
+ break
299
+ end
300
+ end
301
+ end
302
+
303
+ return from + result.size - base_len
304
+ end
305
+
306
+ # This function takes a string, full of format markers and translates
307
+ # them into a chtype array. This is better suited to curses because
308
+ # curses uses chtype almost exclusively
309
+ def RNDK.char2Chtype (string, to, align)
310
+ to << 0
311
+ align << LEFT
312
+ result = []
313
+
314
+ if string.size > 0
315
+ used = 0
316
+
317
+ # The original code makes two passes since it has to pre-allocate space but
318
+ # we should be able to make do with one since we can dynamically size it
319
+ adjust = 0
320
+ attrib = Ncurses::A_NORMAL
321
+ last_char = 0
322
+ start = 0
323
+ used = 0
324
+ x = 3
325
+
326
+ # Look for an alignment marker.
327
+ if string[0] == L_MARKER
328
+ if string[1] == 'C' && string[2] == R_MARKER
329
+ align[0] = CENTER
330
+ start = 3
331
+ elsif string[1] == 'R' && string[2] == R_MARKER
332
+ align[0] = RIGHT
333
+ start = 3
334
+ elsif string[1] == 'L' && string[2] == R_MARKER
335
+ start = 3
336
+ elsif string[1] == 'B' && string[2] == '='
337
+ # Set the item index value in the string.
338
+ result = [' '.ord, ' '.ord, ' '.ord]
339
+
340
+ # Pull out the bullet marker.
341
+ while x < string.size and string[x] != R_MARKER
342
+ result << (string[x].ord | Ncurses::A_BOLD)
343
+ x += 1
344
+ end
345
+ adjust = 1
346
+
347
+ # Set the alignment variables
348
+ start = x
349
+ used = x
350
+ elsif string[1] == 'I' && string[2] == '='
351
+ from = 3
352
+ x = 0
353
+
354
+ while from < string.size && string[from] != Ncurses.R_MARKER
355
+ if RNDK.digit?(string[from])
356
+ adjust = adjust * 10 + string[from].to_i
357
+ x += 1
358
+ end
359
+ from += 1
360
+ end
361
+
362
+ start = x + 4
363
+ end
364
+ end
365
+
366
+ while adjust > 0
367
+ adjust -= 1
368
+ result << ' '
369
+ used += 1
370
+ end
371
+
372
+ # Set the format marker boolean to false
373
+ inside_marker = false
374
+
375
+ # Start parsing the character string.
376
+ from = start
377
+ while from < string.size
378
+ # Are we inside a format marker?
379
+ if !inside_marker
380
+ if string[from] == L_MARKER &&
381
+ ['/', '!', '#'].include?(string[from + 1])
382
+ inside_marker = true
383
+ elsif string[from] == "\\" && string[from + 1] == L_MARKER
384
+ from += 1
385
+ result << (string[from].ord | attrib)
386
+ used += 1
387
+ from += 1
388
+ elsif string[from] == "\t"
389
+ begin
390
+ result << ' '
391
+ used += 1
392
+ end while (used & 7).nonzero?
393
+ else
394
+ result << (string[from].ord | attrib)
395
+ used += 1
396
+ end
397
+ else
398
+ case string[from]
399
+ when R_MARKER
400
+ inside_marker = false
401
+ when '#'
402
+ last_char = 0
403
+ case string[from + 2]
404
+ when 'L'
405
+ case string[from + 1]
406
+ when 'L'
407
+ last_char = Ncurses::ACS_LLCORNER
408
+ when 'U'
409
+ last_char = Ncurses::ACS_ULCORNER
410
+ when 'H'
411
+ last_char = Ncurses::ACS_HLINE
412
+ when 'V'
413
+ last_char = Ncurses::ACS_VLINE
414
+ when 'P'
415
+ last_char = Ncurses::ACS_PLUS
416
+ end
417
+ when 'R'
418
+ case string[from + 1]
419
+ when 'L'
420
+ last_char = Ncurses::ACS_LRCORNER
421
+ when 'U'
422
+ last_char = Ncurses::ACS_URCORNER
423
+ end
424
+ when 'T'
425
+ case string[from + 1]
426
+ when 'T'
427
+ last_char = Ncurses::ACS_TTEE
428
+ when 'R'
429
+ last_char = Ncurses::ACS_RTEE
430
+ when 'L'
431
+ last_char = Ncurses::ACS_LTEE
432
+ when 'B'
433
+ last_char = Ncurses::ACS_BTEE
434
+ end
435
+ when 'A'
436
+ case string[from + 1]
437
+ when 'L'
438
+ last_char = Ncurses::ACS_LARROW
439
+ when 'R'
440
+ last_char = Ncurses::ACS_RARROW
441
+ when 'U'
442
+ last_char = Ncurses::ACS_UARROW
443
+ when 'D'
444
+ last_char = Ncurses::ACS_DARROW
445
+ end
446
+ else
447
+ case [string[from + 1], string[from + 2]]
448
+ when ['D', 'I']
449
+ last_char = Ncurses::ACS_DIAMOND
450
+ when ['C', 'B']
451
+ last_char = Ncurses::ACS_CKBOARD
452
+ when ['D', 'G']
453
+ last_char = Ncurses::ACS_DEGREE
454
+ when ['P', 'M']
455
+ last_char = Ncurses::ACS_PLMINUS
456
+ when ['B', 'U']
457
+ last_char = Ncurses::ACS_BULLET
458
+ when ['S', '1']
459
+ last_char = Ncurses::ACS_S1
460
+ when ['S', '9']
461
+ last_char = Ncurses::ACS_S9
462
+ end
463
+ end
464
+
465
+ if last_char.nonzero?
466
+ adjust = 1
467
+ from += 2
468
+
469
+ if string[from + 1] == '('
470
+ # check for a possible numeric modifier
471
+ from += 2
472
+ adjust = 0
473
+
474
+ while from < string.size && string[from] != ')'
475
+ if RNDK.digit?(string[from])
476
+ adjust = (adjust * 10) + string[from].to_i
477
+ end
478
+ from += 1
479
+ end
480
+ end
481
+ end
482
+ (0...adjust).each do |x|
483
+ result << (last_char | attrib)
484
+ used += 1
485
+ end
486
+ when '/'
487
+ mask = []
488
+ from = RNDK.encodeAttribute(string, from, mask)
489
+ attrib |= mask[0]
490
+ when '!'
491
+ mask = []
492
+ from = RNDK.encodeAttribute(string, from, mask)
493
+ attrib &= ~(mask[0])
494
+ end
495
+ end
496
+ from += 1
497
+ end
498
+
499
+ if result.size == 0
500
+ result << attrib
501
+ end
502
+ to[0] = used
503
+ else
504
+ result = []
505
+ end
506
+ return result
507
+ end
508
+
509
+ # Compare a regular string to a chtype string
510
+ def RNDK.cmpStrChstr (str, chstr)
511
+ i = 0
512
+ r = 0
513
+
514
+ if str.nil? && chstr.nil?
515
+ return 0
516
+ elsif str.nil?
517
+ return 1
518
+ elsif chstr.nil?
519
+ return -1
520
+ end
521
+
522
+ while i < str.size && i < chstr.size
523
+ if str[r].ord < chstr[r]
524
+ return -1
525
+ elsif str[r].ord > chstr[r]
526
+ return 1
527
+ end
528
+ i += 1
529
+ end
530
+
531
+ if str.size < chstr.size
532
+ return -1
533
+ elsif str.size > chstr.size
534
+ return 1
535
+ else
536
+ return 0
537
+ end
538
+ end
539
+
540
+ def RNDK.CharOf(chtype)
541
+ (chtype.ord & 255).chr
542
+ end
543
+
544
+ # This returns a string from a chtype array
545
+ # Formatting codes are omitted.
546
+ def RNDK.chtype2Char(string)
547
+ newstring = ''
548
+
549
+ unless string.nil?
550
+ string.each do |char|
551
+ newstring << RNDK.CharOf(char)
552
+ end
553
+ end
554
+
555
+ return newstring
556
+ end
557
+
558
+ # This returns a string from a chtype array
559
+ # Formatting codes are embedded
560
+ def RNDK.chtype2String(string)
561
+ newstring = ''
562
+ unless string.nil?
563
+ need = 0
564
+ (0...string.size).each do |x|
565
+ need = RNDK.decodeAttribute(newstring, need,
566
+ x > 0 ? string[x - 1] : 0, string[x])
567
+ newstring << string[x]
568
+ end
569
+ end
570
+
571
+ return newstring
572
+ end
573
+
574
+
575
+
576
+ # This returns the length of the integer.
577
+ #
578
+ # Currently a wrapper maintained for easy of porting.
579
+ def RNDK.intlen (value)
580
+ value.to_str.size
581
+ end
582
+
583
+ # This opens the current directory and reads the contents.
584
+ def RNDK.getDirectoryContents(directory, list)
585
+ counter = 0
586
+
587
+ # Open the directory.
588
+ Dir.foreach(directory) do |filename|
589
+ next if filename == '.'
590
+ list << filename
591
+ end
592
+
593
+ list.sort!
594
+ return list.size
595
+ end
596
+
597
+ # This looks for a subset of a word in the given list
598
+ def RNDK.searchList(list, list_size, pattern)
599
+ index = -1
600
+
601
+ if pattern.size > 0
602
+ (0...list_size).each do |x|
603
+ len = [list[x].size, pattern.size].min
604
+ ret = (list[x][0...len] <=> pattern)
605
+
606
+ # If 'ret' is less than 0 then the current word is alphabetically
607
+ # less than the provided word. At this point we will set the index
608
+ # to the current position. If 'ret' is greater than 0, then the
609
+ # current word is alphabetically greater than the given word. We
610
+ # should return with index, which might contain the last best match.
611
+ # If they are equal then we've found it.
612
+ if ret < 0
613
+ index = ret
614
+ else
615
+ if ret == 0
616
+ index = x
617
+ end
618
+ break
619
+ end
620
+ end
621
+ end
622
+ return index
623
+ end
624
+
625
+ # This function checks to see if a link has been requested
626
+ def RNDK.checkForLink (line, filename)
627
+ f_pos = 0
628
+ x = 3
629
+ if line.nil?
630
+ return -1
631
+ end
632
+
633
+ # Strip out the filename.
634
+ if line[0] == L_MARKER && line[1] == 'F' && line[2] == '='
635
+ while x < line.size
636
+ if line[x] == R_MARKER
637
+ break
638
+ end
639
+ if f_pos < RNDK_PATHMAX
640
+ filename << line[x]
641
+ f_pos += 1
642
+ end
643
+ x += 1
644
+ end
645
+ end
646
+ return f_pos != 0
647
+ end
648
+
649
+ # Returns the filename portion of the given pathname, i.e. after the last
650
+ # slash
651
+ # For now this function is just a wrapper for File.basename kept for ease of
652
+ # porting and will be completely replaced in the future
653
+ def RNDK.baseName (pathname)
654
+ File.basename(pathname)
655
+ end
656
+
657
+ # Returns the directory for the given pathname, i.e. the part before the
658
+ # last slash
659
+ # For now this function is just a wrapper for File.dirname kept for ease of
660
+ # porting and will be completely replaced in the future
661
+ def RNDK.dirName (pathname)
662
+ File.dirname(pathname)
663
+ end
664
+
665
+ # If the dimension is a negative value, the dimension will be the full
666
+ # height/width of the parent window - the value of the dimension. Otherwise,
667
+ # the dimension will be the given value.
668
+ def RNDK.setWidgetDimension (parent_dim, proposed_dim, adjustment)
669
+ # If the user passed in FULL, return the parents size
670
+ if proposed_dim == FULL or proposed_dim == 0
671
+ parent_dim
672
+ elsif proposed_dim >= 0
673
+ # if they gave a positive value, return it
674
+
675
+ if proposed_dim >= parent_dim
676
+ parent_dim
677
+ else
678
+ proposed_dim + adjustment
679
+ end
680
+ else
681
+ # if they gave a negative value then return the dimension
682
+ # of the parent plus the value given
683
+ #
684
+ if parent_dim + proposed_dim < 0
685
+ parent_dim
686
+ else
687
+ parent_dim + proposed_dim
688
+ end
689
+ end
690
+ end
691
+
692
+ # This safely erases a given window
693
+ def RNDK.eraseCursesWindow (window)
694
+ return if window.nil?
695
+
696
+ Ncurses.werase window
697
+ Ncurses.wrefresh window
698
+ end
699
+
700
+ # This safely deletes a given window.
701
+ def RNDK.deleteCursesWindow (window)
702
+ return if window.nil?
703
+
704
+ RNDK.eraseCursesWindow(window)
705
+ Ncurses.delwin window
706
+ end
707
+
708
+ # This moves a given window (if we're able to set the window's beginning).
709
+ # We do not use mvwin(), because it does not (usually) move subwindows.
710
+ def RNDK.moveCursesWindow (window, xdiff, ydiff)
711
+ return if window.nil?
712
+
713
+ xpos = []
714
+ ypos = []
715
+ Ncurses.getbegyx(window, ypos, xpos)
716
+ if Ncurses.mvwin(window, ypos[0], xpos[0]) != Ncurses::ERR
717
+ xpos[0] += xdiff
718
+ ypos[0] += ydiff
719
+ Ncurses.werase window
720
+ Ncurses.mvwin(window, ypos[0], xpos[0])
721
+ else
722
+ RNDK.beep
723
+ end
724
+ end
725
+
726
+ def RNDK.digit? character
727
+ false if character.nil?
728
+ !(character.match(/^[[:digit:]]$/).nil?)
729
+ end
730
+
731
+ def RNDK.alpha? character
732
+ false if character.nil?
733
+ !(character.match(/^[[:alpha:]]$/).nil?)
734
+ end
735
+
736
+ def RNDK.isChar c
737
+ false if c.nil?
738
+ c >= 0 && c < Ncurses::KEY_MIN
739
+ end
740
+
741
+ # Returns the function keys - F1, F2 ... F12 ...
742
+ def RNDK.KEY_F(n)
743
+ 264 + n
744
+ end
745
+
746
+ def RNDK.getString(screen, title, label, init_value)
747
+ # Create the widget.
748
+ widget = RNDK::ENTRY.new(screen, RNDK::CENTER, RNDK::CENTER, title, label,
749
+ Ncurses::A_NORMAL, '.', :MIXED, 40, 0, 5000, true, false)
750
+
751
+ # Set the default value.
752
+ widget.setValue(init_value)
753
+
754
+ # Get the string.
755
+ value = widget.activate([])
756
+
757
+ # Make sure they exited normally.
758
+ if widget.exit_type != :NORMAL
759
+ widget.destroy
760
+ return nil
761
+ end
762
+
763
+ # Return a copy of the string typed in.
764
+ value = entry.getValue.clone
765
+ widget.destroy
766
+ return value
767
+ end
768
+
769
+ # This allows a person to select a file.
770
+ def RNDK.selectFile(screen, title)
771
+ # Create the file selector.
772
+ fselect = RNDK::FSELECT.new(screen, RNDK::CENTER, RNDK::CENTER, -4, -20,
773
+ title, 'File: ', Ncurses::A_NORMAL, '_', Ncurses::A_REVERSE,
774
+ '</5>', '</48>', '</N>', '</N>', true, false)
775
+
776
+ # Let the user play.
777
+ filename = fselect.activate([])
778
+
779
+ # Check the way the user exited the selector.
780
+ if fselect.exit_type != :NORMAL
781
+ fselect.destroy
782
+ screen.refresh
783
+ return nil
784
+ end
785
+
786
+ # Otherwise...
787
+ fselect.destroy
788
+ screen.refresh
789
+ return filename
790
+ end
791
+
792
+ # This returns a selected value in a list
793
+ def RNDK.getListindex(screen, title, list, list_size, numbers)
794
+ selected = -1
795
+ height = 10
796
+ width = -1
797
+ len = 0
798
+
799
+ # Determine the height of the list.
800
+ if list_size < 10
801
+ height = list_size + if title.size == 0 then 2 else 3 end
802
+ end
803
+
804
+ # Determine the width of the list.
805
+ list.each do |item|
806
+ width = [width, item.size + 10].max
807
+ end
808
+
809
+ width = [width, title.size].max
810
+ width += 5
811
+
812
+ # Create the scrolling list.
813
+ scrollp = RNDK::SCROLL.new(screen, RNDK::CENTER, RNDK::CENTER, RNDK::RIGHT,
814
+ height, width, title, list, list_size, numbers, Ncurses::A_REVERSE,
815
+ true, false)
816
+
817
+ # Check if we made the lsit.
818
+ if scrollp.nil?
819
+ screen.refresh
820
+ return -1
821
+ end
822
+
823
+ # Let the user play.
824
+ selected = scrollp.activate([])
825
+
826
+ # Check how they exited.
827
+ if scrollp.exit_type != :NORMAL
828
+ selected = -1
829
+ end
830
+
831
+ # Clean up.
832
+ scrollp.destroy
833
+ screen.refresh
834
+ return selected
835
+ end
836
+
837
+ # This allows the user to view information.
838
+ def RNDK.viewInfo(screen, title, info, count, buttons, button_count,
839
+ interpret)
840
+ selected = -1
841
+
842
+ # Create the file viewer to view the file selected.
843
+ viewer = RNDK::VIEWER.new(screen, RNDK::CENTER, RNDK::CENTER, -6, -16,
844
+ buttons, button_count, Ncurses::A_REVERSE, true, true)
845
+
846
+ # Set up the viewer title, and the contents to the widget.
847
+ viewer.set(title, info, count, Ncurses::A_REVERSE, interpret, true, true)
848
+
849
+ # Activate the viewer widget.
850
+ selected = viewer.activate([])
851
+
852
+ # Make sure they exited normally.
853
+ if viewer.exit_type != :NORMAL
854
+ viewer.destroy
855
+ return -1
856
+ end
857
+
858
+ # Clean up and return the button index selected
859
+ viewer.destroy
860
+ return selected
861
+ end
862
+
863
+ # This allows the user to view a file.
864
+ def RNDK.viewFile(screen, title, filename, buttons, button_count)
865
+ info = []
866
+ result = 0
867
+
868
+ # Open the file and read the contents.
869
+ lines = RNDK.readFile(filename, info)
870
+
871
+ # If we couldn't read the file, return an error.
872
+ if lines == -1
873
+ result = lines
874
+ else
875
+ result = RNDK.viewInfo(screen, title, info, lines, buttons,
876
+ button_count, true)
877
+ end
878
+ return result
879
+ end
880
+ end
881
+
882
+ # Why is this here?
883
+ #
884
+ # require 'rndk/alphalist'
885
+ # require 'rndk/button'
886
+ # require 'rndk/buttonbox'
887
+ # require 'rndk/calendar'
888
+ # require 'rndk/dialog'
889
+ # require 'rndk/dscale'
890
+ # require 'rndk/entry'
891
+ # require 'rndk/fscale'
892
+ # require 'rndk/fslider'
893
+ # require 'rndk/fselect'
894
+ # require 'rndk/graph'
895
+ # require 'rndk/histogram'
896
+ # require 'rndk/itemlist'
897
+ # require 'rndk/label'
898
+ # require 'rndk/marquee'
899
+ # require 'rndk/matrix'
900
+ # require 'rndk/mentry'
901
+ # require 'rndk/menu'
902
+ # require 'rndk/radio'
903
+ # require 'rndk/scale'
904
+ # require 'rndk/scroll'
905
+ # require 'rndk/selection'
906
+ # require 'rndk/slider'
907
+ # require 'rndk/swindow'
908
+ # require 'rndk/template'
909
+ # require 'rndk/uscale'
910
+ # require 'rndk/uslider'
911
+ # require 'rndk/viewer'
912
+