rndk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/COPYING +137 -0
  4. data/Gemfile +4 -0
  5. data/README.md +100 -0
  6. data/Rakefile +3 -0
  7. data/TODO +68 -0
  8. data/demos/appointment.rb +346 -0
  9. data/demos/clock.rb +56 -0
  10. data/examples/01-hello-world.rb +56 -0
  11. data/examples/05-position-widget.rb +108 -0
  12. data/lib/rndk.rb +912 -0
  13. data/lib/rndk/alphalist.rb +572 -0
  14. data/lib/rndk/button.rb +370 -0
  15. data/lib/rndk/buttonbox.rb +359 -0
  16. data/lib/rndk/calendar.rb +766 -0
  17. data/lib/rndk/core/display.rb +63 -0
  18. data/lib/rndk/core/draw.rb +238 -0
  19. data/lib/rndk/core/quick_widgets.rb +106 -0
  20. data/lib/rndk/core/screen.rb +269 -0
  21. data/lib/rndk/core/traverse.rb +289 -0
  22. data/lib/rndk/core/widget.rb +506 -0
  23. data/lib/rndk/dialog.rb +367 -0
  24. data/lib/rndk/dscale.rb +13 -0
  25. data/lib/rndk/entry.rb +575 -0
  26. data/lib/rndk/fscale.rb +61 -0
  27. data/lib/rndk/fselect.rb +940 -0
  28. data/lib/rndk/fslider.rb +80 -0
  29. data/lib/rndk/graph.rb +401 -0
  30. data/lib/rndk/histogram.rb +412 -0
  31. data/lib/rndk/itemlist.rb +474 -0
  32. data/lib/rndk/label.rb +218 -0
  33. data/lib/rndk/marquee.rb +244 -0
  34. data/lib/rndk/matrix.rb +1189 -0
  35. data/lib/rndk/mentry.rb +619 -0
  36. data/lib/rndk/menu.rb +478 -0
  37. data/lib/rndk/radio.rb +538 -0
  38. data/lib/rndk/scale.rb +538 -0
  39. data/lib/rndk/scroll.rb +633 -0
  40. data/lib/rndk/scroller.rb +183 -0
  41. data/lib/rndk/selection.rb +630 -0
  42. data/lib/rndk/slider.rb +545 -0
  43. data/lib/rndk/swindow.rb +766 -0
  44. data/lib/rndk/template.rb +560 -0
  45. data/lib/rndk/uscale.rb +14 -0
  46. data/lib/rndk/uslider.rb +14 -0
  47. data/lib/rndk/version.rb +6 -0
  48. data/lib/rndk/viewer.rb +825 -0
  49. data/rndk.gemspec +35 -0
  50. metadata +141 -0
@@ -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
+