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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/COPYING +137 -0
- data/Gemfile +4 -0
- data/README.md +100 -0
- data/Rakefile +3 -0
- data/TODO +68 -0
- data/demos/appointment.rb +346 -0
- data/demos/clock.rb +56 -0
- data/examples/01-hello-world.rb +56 -0
- data/examples/05-position-widget.rb +108 -0
- data/lib/rndk.rb +912 -0
- data/lib/rndk/alphalist.rb +572 -0
- data/lib/rndk/button.rb +370 -0
- data/lib/rndk/buttonbox.rb +359 -0
- data/lib/rndk/calendar.rb +766 -0
- data/lib/rndk/core/display.rb +63 -0
- data/lib/rndk/core/draw.rb +238 -0
- data/lib/rndk/core/quick_widgets.rb +106 -0
- data/lib/rndk/core/screen.rb +269 -0
- data/lib/rndk/core/traverse.rb +289 -0
- data/lib/rndk/core/widget.rb +506 -0
- data/lib/rndk/dialog.rb +367 -0
- data/lib/rndk/dscale.rb +13 -0
- data/lib/rndk/entry.rb +575 -0
- data/lib/rndk/fscale.rb +61 -0
- data/lib/rndk/fselect.rb +940 -0
- data/lib/rndk/fslider.rb +80 -0
- data/lib/rndk/graph.rb +401 -0
- data/lib/rndk/histogram.rb +412 -0
- data/lib/rndk/itemlist.rb +474 -0
- data/lib/rndk/label.rb +218 -0
- data/lib/rndk/marquee.rb +244 -0
- data/lib/rndk/matrix.rb +1189 -0
- data/lib/rndk/mentry.rb +619 -0
- data/lib/rndk/menu.rb +478 -0
- data/lib/rndk/radio.rb +538 -0
- data/lib/rndk/scale.rb +538 -0
- data/lib/rndk/scroll.rb +633 -0
- data/lib/rndk/scroller.rb +183 -0
- data/lib/rndk/selection.rb +630 -0
- data/lib/rndk/slider.rb +545 -0
- data/lib/rndk/swindow.rb +766 -0
- data/lib/rndk/template.rb +560 -0
- data/lib/rndk/uscale.rb +14 -0
- data/lib/rndk/uslider.rb +14 -0
- data/lib/rndk/version.rb +6 -0
- data/lib/rndk/viewer.rb +825 -0
- data/rndk.gemspec +35 -0
- metadata +141 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
module RNDK
|
2
|
+
module Display
|
3
|
+
# Given a string, returns the equivalent display type
|
4
|
+
def Display.char2DisplayType(string)
|
5
|
+
table = {
|
6
|
+
"CHAR" => :CHAR,
|
7
|
+
"HCHAR" => :HCHAR,
|
8
|
+
"INT" => :INT,
|
9
|
+
"HINT" => :HINT,
|
10
|
+
"UCHAR" => :UCHAR,
|
11
|
+
"LCHAR" => :LCHAR,
|
12
|
+
"UHCHAR" => :UHCHAR,
|
13
|
+
"LHCHAR" => :LHCHAR,
|
14
|
+
"MIXED" => :MIXED,
|
15
|
+
"HMIXED" => :HMIXED,
|
16
|
+
"UMIXED" => :UMIXED,
|
17
|
+
"LMIXED" => :LMIXED,
|
18
|
+
"UHMIXED" => :UHMIXED,
|
19
|
+
"LHMIXED" => :LHMIXED,
|
20
|
+
"VIEWONLY" => :VIEWONLY,
|
21
|
+
0 => :INVALID
|
22
|
+
}
|
23
|
+
|
24
|
+
if table.include?(string)
|
25
|
+
table[string]
|
26
|
+
else
|
27
|
+
:INVALID
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Tell if a display type is "hidden"
|
32
|
+
def Display.isHiddenDisplayType(type)
|
33
|
+
case type
|
34
|
+
when :HCHAR, :HINT, :HMIXED, :LHCHAR, :LHMIXED, :UHCHAR, :UHMIXED
|
35
|
+
true
|
36
|
+
when :CHAR, :INT, :INVALID, :LCHAR, :LMIXED, :MIXED, :UCHAR,
|
37
|
+
:UMIXED, :VIEWONLY
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Given a character input, check if it is allowed by the display type
|
43
|
+
# and return the character to apply to the display, or ERR if not
|
44
|
+
def Display.filterByDisplayType(type, input)
|
45
|
+
result = input
|
46
|
+
if !RNDK.isChar(input)
|
47
|
+
result = Ncurses::ERR
|
48
|
+
elsif [:INT, :HINT].include?(type) && !RNDK.digit?(result.chr)
|
49
|
+
result = Ncurses::ERR
|
50
|
+
elsif [:CHAR, :UCHAR, :LCHAR, :UHCHAR, :LHCHAR].include?(type) && RNDK.digit?(result.chr)
|
51
|
+
result = Ncurses::ERR
|
52
|
+
elsif type == :VIEWONLY
|
53
|
+
result = ERR
|
54
|
+
elsif [:UCHAR, :UHCHAR, :UMIXED, :UHMIXED].include?(type) && RNDK.alpha?(result.chr)
|
55
|
+
result = result.chr.upcase.ord
|
56
|
+
elsif [:LCHAR, :LHCHAR, :LMIXED, :LHMIXED].include?(type) && RNDK.alpha?(result.chr)
|
57
|
+
result = result.chr.downcase.ord
|
58
|
+
end
|
59
|
+
|
60
|
+
return result
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
module RNDK
|
2
|
+
module Draw
|
3
|
+
# This sets up a basic set of color pairs. These can be redefined if wanted
|
4
|
+
def Draw.initRNDKColor
|
5
|
+
color = [Ncurses::COLOR_WHITE,
|
6
|
+
Ncurses::COLOR_RED,
|
7
|
+
Ncurses::COLOR_GREEN,
|
8
|
+
Ncurses::COLOR_YELLOW,
|
9
|
+
Ncurses::COLOR_BLUE,
|
10
|
+
Ncurses::COLOR_MAGENTA,
|
11
|
+
Ncurses::COLOR_CYAN,
|
12
|
+
Ncurses::COLOR_BLACK]
|
13
|
+
pair = 1
|
14
|
+
|
15
|
+
if Ncurses.has_colors
|
16
|
+
# XXX: Only checks if terminal has colours not if colours are started
|
17
|
+
Ncurses.start_color
|
18
|
+
limit = if Ncurses.COLORS < 8 then Ncurses.COLORS else 8 end
|
19
|
+
|
20
|
+
# Create the color pairs
|
21
|
+
(0...limit).each do |fg|
|
22
|
+
(0...limit).each do |bg|
|
23
|
+
Ncurses.init_pair(pair, color[fg], color[bg])
|
24
|
+
pair += 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# This prints out a box around a window with attributes
|
31
|
+
def Draw.boxWindow(window, attr)
|
32
|
+
tlx = 0
|
33
|
+
tly = 0
|
34
|
+
brx = Ncurses.getmaxx(window) - 1
|
35
|
+
bry = Ncurses.getmaxy(window) - 1
|
36
|
+
|
37
|
+
# Draw horizontal lines.
|
38
|
+
Ncurses.mvwhline(window, tly, 0, Ncurses::ACS_HLINE | attr, Ncurses.getmaxx(window))
|
39
|
+
Ncurses.mvwhline(window, bry, 0, Ncurses::ACS_HLINE | attr, Ncurses.getmaxx(window))
|
40
|
+
|
41
|
+
# Draw horizontal lines.
|
42
|
+
Ncurses.mvwvline(window, 0, tlx, Ncurses::ACS_VLINE | attr, Ncurses.getmaxy(window))
|
43
|
+
Ncurses.mvwvline(window, 0, brx, Ncurses::ACS_VLINE | attr, Ncurses.getmaxy(window))
|
44
|
+
|
45
|
+
# Draw in the corners.
|
46
|
+
Ncurses.mvwaddch(window, tly, tlx, Ncurses::ACS_ULCORNER | attr)
|
47
|
+
Ncurses.mvwaddch(window, tly, brx, Ncurses::ACS_URCORNER | attr)
|
48
|
+
Ncurses.mvwaddch(window, bry, tlx, Ncurses::ACS_LLCORNER | attr)
|
49
|
+
Ncurses.mvwaddch(window, bry, brx, Ncurses::ACS_LRCORNER | attr)
|
50
|
+
Ncurses.wrefresh(window)
|
51
|
+
end
|
52
|
+
|
53
|
+
# This draws a box with attributes and lets the user define each
|
54
|
+
# element of the box
|
55
|
+
def Draw.attrbox(win, tlc, trc, blc, brc, horz, vert, attr)
|
56
|
+
x1 = 0
|
57
|
+
y1 = 0
|
58
|
+
y2 = Ncurses.getmaxy(win) - 1
|
59
|
+
x2 = Ncurses.getmaxx(win) - 1
|
60
|
+
count = 0
|
61
|
+
|
62
|
+
# Draw horizontal lines
|
63
|
+
if horz != 0
|
64
|
+
Ncurses.mvwhline(win, y1, 0, horz | attr, Ncurses.getmaxx(win))
|
65
|
+
Ncurses.mvwhline(win, y2, 0, horz | attr, Ncurses.getmaxx(win))
|
66
|
+
count += 1
|
67
|
+
end
|
68
|
+
|
69
|
+
# Draw vertical lines
|
70
|
+
if vert != 0
|
71
|
+
Ncurses.mvwvline(win, 0, x1, vert | attr, Ncurses.getmaxy(win))
|
72
|
+
Ncurses.mvwvline(win, 0, x2, vert | attr, Ncurses.getmaxy(win))
|
73
|
+
count += 1
|
74
|
+
end
|
75
|
+
|
76
|
+
# Draw in the corners.
|
77
|
+
if tlc != 0
|
78
|
+
Ncurses.mvwaddch(win, y1, x1, tlc | attr)
|
79
|
+
count += 1
|
80
|
+
end
|
81
|
+
if trc != 0
|
82
|
+
Ncurses.mvwaddch(win, y1, x2, trc | attr)
|
83
|
+
count += 1
|
84
|
+
end
|
85
|
+
if blc != 0
|
86
|
+
Ncurses.mvwaddch(win, y2, x1, blc | attr)
|
87
|
+
count += 1
|
88
|
+
end
|
89
|
+
if brc != 0
|
90
|
+
Ncurses.mvwaddch(win, y2, x2, brc | attr)
|
91
|
+
count += 1
|
92
|
+
end
|
93
|
+
if count != 0
|
94
|
+
Ncurses.wrefresh win
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Draw a box around the given window using the object's defined
|
99
|
+
# line-drawing characters
|
100
|
+
def Draw.drawObjBox(win, object)
|
101
|
+
Draw.attrbox(win,
|
102
|
+
object.ULChar, object.URChar, object.LLChar, object.LRChar,
|
103
|
+
object.HZChar, object.VTChar, object.BXAttr)
|
104
|
+
end
|
105
|
+
|
106
|
+
# This draws a line on the given window. (odd angle lines not working yet)
|
107
|
+
def Draw.drawLine(window, startx, starty, endx, endy, line)
|
108
|
+
xdiff = endx - startx
|
109
|
+
ydiff = endy - starty
|
110
|
+
x = 0
|
111
|
+
y = 0
|
112
|
+
|
113
|
+
# Determine if we're drawing a horizontal or vertical line.
|
114
|
+
if ydiff == 0
|
115
|
+
if xdiff > 0
|
116
|
+
Ncurses.mvwhline(window, starty, startx, line, xdiff)
|
117
|
+
end
|
118
|
+
elsif xdiff == 0
|
119
|
+
if ydiff > 0
|
120
|
+
Ncurses.mvwvline(window, starty, startx, line, ydiff)
|
121
|
+
end
|
122
|
+
else
|
123
|
+
# We need to determine the angle of the line.
|
124
|
+
height = xdiff
|
125
|
+
width = ydiff
|
126
|
+
xratio = if height > width then 1 else width / height end
|
127
|
+
yration = if width > height then width / height else 1 end
|
128
|
+
xadj = 0
|
129
|
+
yadj = 0
|
130
|
+
|
131
|
+
# Set the vars
|
132
|
+
x = startx
|
133
|
+
y = starty
|
134
|
+
while x!= endx && y != endy
|
135
|
+
# Add the char to the window
|
136
|
+
Ncurses.mvwaddch(window, y, x, line)
|
137
|
+
|
138
|
+
# Make the x and y adjustments.
|
139
|
+
if xadj != xratio
|
140
|
+
x = if xdiff < 0 then x - 1 else x + 1 end
|
141
|
+
xadj += 1
|
142
|
+
else
|
143
|
+
xadj = 0
|
144
|
+
end
|
145
|
+
if yadj != yratio
|
146
|
+
y = if ydiff < 0 then y - 1 else y + 1 end
|
147
|
+
yadj += 1
|
148
|
+
else
|
149
|
+
yadj = 0
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# This draws a shadow around a window.
|
156
|
+
def Draw.drawShadow(shadow_win)
|
157
|
+
unless shadow_win.nil?
|
158
|
+
x_hi = Ncurses.getmaxx(shadow_win) - 1
|
159
|
+
y_hi = Ncurses.getmaxy(shadow_win) - 1
|
160
|
+
|
161
|
+
# Draw the line on the bottom.
|
162
|
+
Ncurses.mvwhline(shadow_win, y_hi, 1, Ncurses::ACS_HLINE | Ncurses::A_DIM, x_hi)
|
163
|
+
|
164
|
+
# Draw the line on teh right.
|
165
|
+
Ncurses.mvwvline(shadow_win, 0, x_hi, Ncurses::ACS_VLINE | Ncurses::A_DIM, y_hi)
|
166
|
+
|
167
|
+
Ncurses.mvwaddch(shadow_win, 0, x_hi, Ncurses::ACS_URCORNER | Ncurses::A_DIM)
|
168
|
+
Ncurses.mvwaddch(shadow_win, y_hi, 0, Ncurses::ACS_LLCORNER | Ncurses::A_DIM)
|
169
|
+
Ncurses.mvwaddch(shadow_win, y_hi, x_hi, Ncurses::ACS_LRCORNER | Ncurses::A_DIM)
|
170
|
+
Ncurses.wrefresh shadow_win
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Write a string of blanks using writeChar()
|
175
|
+
def Draw.writeBlanks(window, xpos, ypos, align, start, endn)
|
176
|
+
if start < endn
|
177
|
+
want = (endn - start) + 1000
|
178
|
+
blanks = ''
|
179
|
+
|
180
|
+
RNDK.cleanChar(blanks, want - 1, ' ')
|
181
|
+
Draw.writeChar(window, xpos, ypos, blanks, align, start, endn)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# This writes out a char string with no attributes
|
186
|
+
def Draw.writeChar(window, xpos, ypos, string, align, start, endn)
|
187
|
+
Draw.writeCharAttrib(window, xpos, ypos, string, Ncurses::A_NORMAL,
|
188
|
+
align, start, endn)
|
189
|
+
end
|
190
|
+
|
191
|
+
# This writes out a char string with attributes
|
192
|
+
def Draw.writeCharAttrib(window, xpos, ypos, string, attr, align,
|
193
|
+
start, endn)
|
194
|
+
display = endn - start
|
195
|
+
|
196
|
+
if align == RNDK::HORIZONTAL
|
197
|
+
# Draw the message on a horizontal axis
|
198
|
+
display = [display, Ncurses.getmaxx(window) - 1].min
|
199
|
+
(0...display).each do |x|
|
200
|
+
Ncurses.mvwaddch(window, ypos, xpos + x, string[x + start].ord | attr)
|
201
|
+
end
|
202
|
+
else
|
203
|
+
# Draw the message on a vertical axis
|
204
|
+
display = [display, Ncurses.getmaxy(window) - 1].min
|
205
|
+
(0...display).each do |x|
|
206
|
+
Ncurses.mvwaddch(window, ypos + x, xpos, string[x + start].ord | attr)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# This writes out a chtype string
|
212
|
+
def Draw.writeChtype (window, xpos, ypos, string, align, start, endn)
|
213
|
+
Draw.writeChtypeAttrib(window, xpos, ypos, string, Ncurses::A_NORMAL,
|
214
|
+
align, start, endn)
|
215
|
+
end
|
216
|
+
|
217
|
+
# This writes out a chtype string with the given attributes added.
|
218
|
+
def Draw.writeChtypeAttrib(window, xpos, ypos, string, attr,
|
219
|
+
align, start, endn)
|
220
|
+
diff = endn - start
|
221
|
+
display = 0
|
222
|
+
x = 0
|
223
|
+
if align == RNDK::HORIZONTAL
|
224
|
+
# Draw the message on a horizontal axis.
|
225
|
+
display = [diff, Ncurses.getmaxx(window) - xpos].min
|
226
|
+
(0...display).each do |x|
|
227
|
+
Ncurses.mvwaddch(window, ypos, xpos + x, string[x + start].ord | attr)
|
228
|
+
end
|
229
|
+
else
|
230
|
+
# Draw the message on a vertical axis.
|
231
|
+
display = [diff, Ncurses.getmaxy(window) - ypos].min
|
232
|
+
(0...display).each do |x|
|
233
|
+
Ncurses.mvwaddch(window, ypos + x, xpos, string[x + start].ord | attr)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Provides easy ways to do things with Widgets, without
|
2
|
+
# all that hassle of initializing values and whatnot.
|
3
|
+
#
|
4
|
+
# ## Usage
|
5
|
+
#
|
6
|
+
# They're all methods to the RNDK::Screen class.
|
7
|
+
# For example:
|
8
|
+
#
|
9
|
+
# curses_win = Ncurses.initscr
|
10
|
+
# rndkscreen = RNDK::Screen.new(curses_win)
|
11
|
+
# message = ["awesome quick label!"]
|
12
|
+
# rndkscreen.popupLabel message
|
13
|
+
#
|
14
|
+
require 'rndk/label'
|
15
|
+
require 'rndk/dialog'
|
16
|
+
|
17
|
+
module RNDK
|
18
|
+
class Screen
|
19
|
+
|
20
|
+
# Executes a block of code without modifying the
|
21
|
+
# screen state.
|
22
|
+
#
|
23
|
+
# See usage right below.
|
24
|
+
def cleanly &block
|
25
|
+
prev_state = Ncurses.curs_set 0
|
26
|
+
|
27
|
+
yield
|
28
|
+
|
29
|
+
Ncurses.curs_set prev_state
|
30
|
+
self.erase
|
31
|
+
self.refresh
|
32
|
+
end
|
33
|
+
|
34
|
+
# Quickly pops up a `message`.
|
35
|
+
#
|
36
|
+
# Creates a centered pop-up Label Widget that
|
37
|
+
# waits until the user hits a character.
|
38
|
+
#
|
39
|
+
# @note: `message` must be an array of strings.
|
40
|
+
def popupLabel message
|
41
|
+
return if message.class != Array or message.empty?
|
42
|
+
|
43
|
+
self.cleanly do
|
44
|
+
count = message.size
|
45
|
+
|
46
|
+
popup = RNDK::LABEL.new(self, CENTER, CENTER, message, count, true, false)
|
47
|
+
popup.draw(true)
|
48
|
+
|
49
|
+
# Wait for some input.
|
50
|
+
Ncurses.keypad(popup.win, true)
|
51
|
+
popup.getch([])
|
52
|
+
popup.destroy
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Quickly pops up a `message`, using `attrib` for
|
57
|
+
# the background of the dialog.
|
58
|
+
#
|
59
|
+
# @note: `message` must be an array of strings.
|
60
|
+
def popupLabelAttrib(message, attrib)
|
61
|
+
return if message.class != Array or message.empty?
|
62
|
+
|
63
|
+
self.cleanly do
|
64
|
+
popup = RNDK::LABEL.new(self, CENTER, CENTER, message, message.size, true, false)
|
65
|
+
popup.setBackgroundAttrib attrib
|
66
|
+
popup.draw(true)
|
67
|
+
|
68
|
+
# Wait for some input
|
69
|
+
Ncurses.keypad(popup.win, true)
|
70
|
+
popup.getch([])
|
71
|
+
|
72
|
+
popup.destroy
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Shows a centered pop-up Dialog box with `message` label and
|
77
|
+
# each button label on `buttons`.
|
78
|
+
#
|
79
|
+
# @returns The user choice or `nil` if wrong parameters
|
80
|
+
# were given.
|
81
|
+
#
|
82
|
+
# @note: `message` and `buttons` must be Arrays of Strings.
|
83
|
+
def popupDialog(message, buttons)
|
84
|
+
return nil if message.class != Array or message.empty?
|
85
|
+
return nil if buttons.class != Array or buttons.empty?
|
86
|
+
|
87
|
+
self.cleanly do
|
88
|
+
popup = RNDK::DIALOG.new(self,
|
89
|
+
RNDK::CENTER,
|
90
|
+
RNDK::CENTER,
|
91
|
+
message,
|
92
|
+
message.size,
|
93
|
+
buttons,
|
94
|
+
buttons.size,
|
95
|
+
Ncurses::A_REVERSE,
|
96
|
+
true, true, false)
|
97
|
+
popup.draw(true)
|
98
|
+
choice = popup.activate('')
|
99
|
+
popup.destroy
|
100
|
+
end
|
101
|
+
choice
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
@@ -0,0 +1,269 @@
|
|
1
|
+
|
2
|
+
module RNDK
|
3
|
+
|
4
|
+
# Placeholder for RNDK Widgets.
|
5
|
+
#
|
6
|
+
# Since all Widgets are bonded to a Screen, you pretty much
|
7
|
+
# won't need to call any of the methods here.
|
8
|
+
#
|
9
|
+
# The only methods you should worry about are:
|
10
|
+
#
|
11
|
+
# * #initialize
|
12
|
+
# * #end_rndk
|
13
|
+
# * #draw or #refresh
|
14
|
+
# * #erase
|
15
|
+
#
|
16
|
+
# ## Developer Notes
|
17
|
+
#
|
18
|
+
# If you want to create your own Widget, you'll need to
|
19
|
+
# call some methods in here to register/unregister it
|
20
|
+
# to a Screen.
|
21
|
+
#
|
22
|
+
class Screen
|
23
|
+
attr_accessor :object_focus, :object_count, :object_limit, :object, :window
|
24
|
+
attr_accessor :exit_status
|
25
|
+
|
26
|
+
NOEXIT = 0
|
27
|
+
EXITOK = 1
|
28
|
+
EXITCANCEL = 2
|
29
|
+
|
30
|
+
# Takes a Ncurses `WINDOW*` pointer and creates a CDKScreen.
|
31
|
+
#
|
32
|
+
# This also starts Ncurses, if it wasn't started before or
|
33
|
+
# no `WINDOW*` were provided
|
34
|
+
#
|
35
|
+
def initialize(ncurses_window=nil)
|
36
|
+
|
37
|
+
# If the user didn't start Ncurses for us,
|
38
|
+
# we'll do it anyway.
|
39
|
+
if RNDK::ALL_SCREENS.size == 0 or ncurses_window.nil?
|
40
|
+
|
41
|
+
## Why is this here?
|
42
|
+
# Set up basic curses settings.
|
43
|
+
# #ifdef HAVE_SETLOCALE
|
44
|
+
# setlocale (LC_ALL, "");
|
45
|
+
# #endif
|
46
|
+
|
47
|
+
ncurses_window = Ncurses.initscr
|
48
|
+
Ncurses.noecho
|
49
|
+
Ncurses.cbreak
|
50
|
+
end
|
51
|
+
|
52
|
+
RNDK::ALL_SCREENS << self
|
53
|
+
@object_count = 0
|
54
|
+
@object_limit = 2
|
55
|
+
@object = Array.new(@object_limit, nil)
|
56
|
+
@window = ncurses_window
|
57
|
+
@object_focus = 0
|
58
|
+
end
|
59
|
+
|
60
|
+
# Shuts down RNDK and Ncurses.
|
61
|
+
def self.end_rndk
|
62
|
+
Ncurses.echo
|
63
|
+
Ncurses.nocbreak
|
64
|
+
Ncurses.endwin
|
65
|
+
end
|
66
|
+
|
67
|
+
# Adds a Widget to this Screen.
|
68
|
+
#
|
69
|
+
# @note This is called automatically when a widget is created.
|
70
|
+
#
|
71
|
+
# `rndktype` states what RNDK Widget type this object is.
|
72
|
+
# `object` is a pointer to the Widget itself.
|
73
|
+
#
|
74
|
+
def register(rndktype, object)
|
75
|
+
if @object_count + 1 >= @object_limit
|
76
|
+
@object_limit += 2
|
77
|
+
@object_limit *= 2
|
78
|
+
@object.concat Array.new(@object_limit - @object.size, nil)
|
79
|
+
end
|
80
|
+
|
81
|
+
if object.validObjType(rndktype)
|
82
|
+
self.setScreenIndex(@object_count, object)
|
83
|
+
@object_count += 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Removes a Widget from the Screen.
|
88
|
+
#
|
89
|
+
# @note This is called automatically when a widget is destroyed.
|
90
|
+
#
|
91
|
+
# This does NOT destroy the object, it removes the Widget
|
92
|
+
# from any further refreshes by Screen#refresh.
|
93
|
+
#
|
94
|
+
# `rndktype` states what RNDK Widget type this object is.
|
95
|
+
# `object` is a pointer to the Widget itself.
|
96
|
+
#
|
97
|
+
def self.unregister(rndktype, object)
|
98
|
+
return if not (object.validObjType(rndktype) && object.screen_index >= 0)
|
99
|
+
|
100
|
+
screen = object.screen
|
101
|
+
return if screen.nil?
|
102
|
+
|
103
|
+
index = object.screen_index
|
104
|
+
object.screen_index = -1
|
105
|
+
|
106
|
+
# Resequence the objects
|
107
|
+
(index...screen.object_count - 1).each do |x|
|
108
|
+
screen.setScreenIndex(x, screen.object[x+1])
|
109
|
+
end
|
110
|
+
|
111
|
+
if screen.object_count <= 1
|
112
|
+
# if no more objects, remove the array
|
113
|
+
screen.object = []
|
114
|
+
screen.object_count = 0
|
115
|
+
screen.object_limit = 0
|
116
|
+
else
|
117
|
+
screen.object[screen.object_count] = nil
|
118
|
+
screen.object_count -= 1
|
119
|
+
|
120
|
+
# Update the object-focus
|
121
|
+
if screen.object_focus == index
|
122
|
+
screen.object_focus -= 1
|
123
|
+
Traverse.setRNDKFocusNext(screen)
|
124
|
+
|
125
|
+
elsif screen.object_focus > index
|
126
|
+
screen.object_focus -= 1
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def setScreenIndex(number, obj)
|
132
|
+
obj.screen_index = number
|
133
|
+
obj.screen = self
|
134
|
+
@object[number] = obj
|
135
|
+
end
|
136
|
+
|
137
|
+
def validIndex(n)
|
138
|
+
n >= 0 && n < @object_count
|
139
|
+
end
|
140
|
+
|
141
|
+
def swapRNDKIndices(n1, n2)
|
142
|
+
if n1 != n2 && self.validIndex(n1) && self.validIndex(n2)
|
143
|
+
o1 = @object[n1]
|
144
|
+
o2 = @object[n2]
|
145
|
+
self.setScreenIndex(n1, o2)
|
146
|
+
self.setScreenIndex(n2, o1)
|
147
|
+
|
148
|
+
if @object_focus == n1
|
149
|
+
@object_focus = n2
|
150
|
+
elsif @object_focus == n2
|
151
|
+
@object_focus = n1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Raises the Widget to the top of the screen.
|
157
|
+
# It will now overlap any other obstructing Widgets.
|
158
|
+
#
|
159
|
+
# `rndktype` states what RNDK Widget type this object is.
|
160
|
+
# `object` is a pointer to the Widget itself.
|
161
|
+
#
|
162
|
+
def self.raise_widget(rndktype, object)
|
163
|
+
if object.validObjType(rndktype)
|
164
|
+
screen = object.screen
|
165
|
+
screen.swapRNDKIndices(object.screen_index, screen.object_count - 1)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Has the opposite effect of #raise_widget.
|
170
|
+
def self.lower_widget(rndktype, object)
|
171
|
+
if object.validObjType(rndktype)
|
172
|
+
object.screen.swapRNDKIndices(object.screen_index, 0)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Refresh a raw Ncurses window.
|
177
|
+
#
|
178
|
+
# FIXME(original): this should be rewritten to use the panel library, so
|
179
|
+
# it would not be necessary to touch the window to ensure that it covers
|
180
|
+
# other windows.
|
181
|
+
def self.refresh_window win
|
182
|
+
Ncurses.touchwin win
|
183
|
+
Ncurses.wrefresh win
|
184
|
+
end
|
185
|
+
|
186
|
+
# Redraws all Widgets inside this Screen.
|
187
|
+
def draw
|
188
|
+
self.refresh
|
189
|
+
end
|
190
|
+
|
191
|
+
# Redraws all Widgets inside this Screen.
|
192
|
+
def refresh
|
193
|
+
focused = -1
|
194
|
+
visible = -1
|
195
|
+
|
196
|
+
RNDK::Screen.refresh_window(@window)
|
197
|
+
|
198
|
+
# We erase all the invisible objects, then only draw it all back, so
|
199
|
+
# that the objects can overlap, and the visible ones will always be
|
200
|
+
# drawn after all the invisible ones are erased
|
201
|
+
(0...@object_count).each do |x|
|
202
|
+
obj = @object[x]
|
203
|
+
if obj.validObjType(obj.object_type)
|
204
|
+
if obj.is_visible
|
205
|
+
if visible < 0
|
206
|
+
visible = x
|
207
|
+
end
|
208
|
+
if obj.has_focus && focused < 0
|
209
|
+
focused = x
|
210
|
+
end
|
211
|
+
else
|
212
|
+
obj.erase
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
(0...@object_count).each do |x|
|
218
|
+
obj = @object[x]
|
219
|
+
|
220
|
+
if obj.validObjType(obj.object_type)
|
221
|
+
obj.has_focus = (x == focused)
|
222
|
+
|
223
|
+
if obj.is_visible
|
224
|
+
obj.draw(obj.box)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Erases all Widgets inside this Screen.
|
231
|
+
#
|
232
|
+
# @note Erase in the sense of clearing the actual
|
233
|
+
# characters on the terminal screen.
|
234
|
+
# This does NOT destroy any widgets.
|
235
|
+
def erase
|
236
|
+
(0...@object_count).each do |x|
|
237
|
+
obj = @object[x]
|
238
|
+
obj.erase if obj.validObjType obj.object_type
|
239
|
+
end
|
240
|
+
Ncurses.wrefresh(@window)
|
241
|
+
end
|
242
|
+
|
243
|
+
# Destroys all the Widgets inside this Screen.
|
244
|
+
def destroy_widgets
|
245
|
+
(0...@object_count).each do |x|
|
246
|
+
obj = @object[x]
|
247
|
+
before = @object_count
|
248
|
+
|
249
|
+
if obj.validObjType(obj.object_type)
|
250
|
+
obj.erase
|
251
|
+
obj.destroy
|
252
|
+
x -= (@object_count - before)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Destroys this Screen.
|
258
|
+
# @note It does nothing to the widgets inside it.
|
259
|
+
# You must either destroy them separatedly
|
260
|
+
# or call #destroy_widgets before.
|
261
|
+
def destroy
|
262
|
+
RNDK::ALL_SCREENS.delete self
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
require 'rndk/core/quick_widgets'
|
269
|
+
|