cdk 0.9.0

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