cdk 0.9.0
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.
- checksums.yaml +7 -0
- data/lib/cdk.rb +916 -0
- data/lib/cdk/alphalist.rb +562 -0
- data/lib/cdk/buttonbox.rb +354 -0
- data/lib/cdk/calendar.rb +770 -0
- data/lib/cdk/cdk_objs.rb +463 -0
- data/lib/cdk/dialog.rb +727 -0
- data/lib/cdk/display.rb +63 -0
- data/lib/cdk/draw.rb +233 -0
- data/lib/cdk/dscale.rb +13 -0
- data/lib/cdk/entry.rb +556 -0
- data/lib/cdk/fscale.rb +44 -0
- data/lib/cdk/fselect.rb +940 -0
- data/lib/cdk/fslider.rb +61 -0
- data/lib/cdk/histogram.rb +410 -0
- data/lib/cdk/itemlist.rb +475 -0
- data/lib/cdk/label.rb +207 -0
- data/lib/cdk/marquee.rb +241 -0
- data/lib/cdk/matrix.rb +1176 -0
- data/lib/cdk/mentry.rb +614 -0
- data/lib/cdk/menu.rb +448 -0
- data/lib/cdk/radio.rb +533 -0
- data/lib/cdk/scale.rb +525 -0
- data/lib/cdk/screen.rb +280 -0
- data/lib/cdk/scroll.rb +994 -0
- data/lib/cdk/scroller.rb +183 -0
- data/lib/cdk/selection.rb +619 -0
- data/lib/cdk/slider.rb +541 -0
- data/lib/cdk/swindow.rb +762 -0
- data/lib/cdk/template.rb +562 -0
- data/lib/cdk/traverse.rb +289 -0
- data/lib/cdk/uscale.rb +14 -0
- data/lib/cdk/uslider.rb +14 -0
- data/lib/cdk/viewer.rb +812 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -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
|
data/lib/cdk.rb
ADDED
@@ -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
|