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