ffi-ncurses 0.3.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.
data/History.txt ADDED
@@ -0,0 +1,22 @@
1
+ == 0.3.0 / 2009-02-15
2
+
3
+ * Features
4
+ * Use FFI::NCurses rather than NCurses
5
+ * Removed dependency on rubygems
6
+ * Reorganised library layout
7
+
8
+ == 0.2.0 / 2009-02-03
9
+
10
+ * Features
11
+ * Initial gem release
12
+ * Most features of ncurses wrapped for Linux, Mac, ruby 1.8.6
13
+ and JRuby 1.1.6
14
+
15
+ * Bugs
16
+ * +newscr+ and +curscr+ cannot be implemented in JRuby until
17
+ find_sym implemented in ffi (expected in JRuby 1.1.7)
18
+
19
+ == 0.1.0 / 2009-01-19
20
+
21
+ * Features
22
+ * Initial release
data/README.rdoc ADDED
@@ -0,0 +1,220 @@
1
+ = ffi-ncurses
2
+
3
+ Author: Sean O'Halpin
4
+
5
+ A wrapper for ncurses 5.x. Tested on Mac OS X 10.4 (Tiger) and Ubuntu
6
+ 8.04 with ruby 1.8.6 using ruby-ffi (>= 0.2.0) and JRuby 1.1.6.
7
+
8
+ The API is very much a transliteration of the C API rather than an
9
+ attempt to provide an idiomatic Ruby object-oriented API. The intent
10
+ is to provide a 'close to the metal' wrapper around the ncurses
11
+ library upon which you can build your own abstractions.
12
+
13
+ This is still very much a work-in-progress, so expect some rough
14
+ edges. Having said that, you can do quite a lot with it as it is. The
15
+ main things left to be done are tests, access to global variables and
16
+ various macros.
17
+
18
+ Below are some very preliminary notes on usage. See the examples
19
+ directory for real working examples.
20
+
21
+ == Usage
22
+
23
+ Load the library with:
24
+
25
+ require 'ffi-ncurses'
26
+
27
+ FFI::NCurses methods can be called as module methods:
28
+
29
+ begin
30
+ stdscr = FFI::NCurses.initscr
31
+ FFI::NCurses.clear
32
+ FFI::NCurses.addstr("Hello world!")
33
+ FFI::NCurses.refresh
34
+ FFI::NCurses.getch
35
+ ensure
36
+ FFI::NCurses.endwin
37
+ end
38
+
39
+ or as included methods:
40
+
41
+ require 'ffi-ncurses'
42
+ include FFI::NCurses
43
+ begin
44
+ stdscr = initscr
45
+ start_color
46
+ curs_set 0
47
+ raw
48
+ cbreak
49
+ noecho
50
+ clear
51
+ move 10, 10
52
+ standout
53
+ addstr("Hi!")
54
+ standend
55
+ refresh
56
+ getch
57
+ ensure
58
+ endwin
59
+ end
60
+
61
+ == Set up screen
62
+
63
+ require 'ffi-ncurses'
64
+
65
+ FFI::NCurses.initscr
66
+ begin
67
+ ...
68
+ ensure
69
+ FFI::NCurses.endwin
70
+ end
71
+
72
+ == Typical initialization
73
+
74
+ stdscr = FFI::NCurses.initscr
75
+ FFI::NCurses.start_color
76
+ FFI::NCurses.curs_set 0
77
+ FFI::NCurses.raw
78
+ FFI::NCurses.cbreak
79
+ FFI::NCurses.noecho
80
+ FFI::NCurses.keypad(stdscr, true)
81
+
82
+ == Colours
83
+
84
+ start_color
85
+ init_pair(1, FFI::NCurses::COLOR_BLACK, FFI::NCurses::COLOR_RED)
86
+ attr_set FFI::NCurses::A_NORMAL, 1, nil
87
+ addch(?A)
88
+ addch(?Z | COLOR_PAIR(1))
89
+
90
+ == Cursor
91
+
92
+ === Turn cursor off
93
+
94
+ FFI::NCurses.curs_set 0
95
+
96
+ === Turn cursor on
97
+
98
+ FFI::NCurses.curs_set 1
99
+
100
+ == Windows
101
+
102
+ require 'ffi-ncurses'
103
+ begin
104
+ win = newwin(6, 12, 15, 15)
105
+ box(win, 0, 0)
106
+ inner_win = newwin(4, 10, 16, 16)
107
+ waddstr(inner_win, (["Hello window!"] * 5).join(' '))
108
+ wrefresh(win)
109
+ wrefresh(inner_win)
110
+ ch = wgetch(inner_win)
111
+
112
+ rescue Object => e
113
+ FFI::NCurses.endwin
114
+ puts e
115
+ ensure
116
+ FFI::NCurses.endwin
117
+ end
118
+
119
+ == Mouse handling
120
+
121
+ The ncurses mouse API is defined in a separate file. To include it use:
122
+
123
+ require 'ffi-ncurses/mouse'
124
+
125
+ You need to specify that you want keypad translation with:
126
+
127
+ keypad stdscr, FFI::NCurses::TRUE
128
+
129
+ otherwise your program will receive the raw mouse escape codes,
130
+ instead of KEY_MOUSE mouse event codes.
131
+
132
+ Specify which events you want to handle with:
133
+
134
+ mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, nil)
135
+
136
+ and set up a mouse event structure to receive the returned values:
137
+
138
+ mouse_event = FFI::NCurses::MEVENT.new
139
+
140
+ Receiving mouse events is a two-stage process: first, you are notified
141
+ that a mouse event has taken place through a special key code, then
142
+ you retrieve the event using +getmouse+. For example:
143
+
144
+ ch = getch
145
+ case ch
146
+ when FFI::NCurses::KEY_MOUSE
147
+ if getmouse(mouse_event) == FFI::NCurses::OK
148
+
149
+ The mouse event contains the button state (+bstate+) and x, y
150
+ coordinates. You can test for the button state using:
151
+
152
+ if mouse_event[:bstate] & FFI::NCurses::BUTTON1_PRESSED
153
+
154
+ or
155
+
156
+ if FFI::NCurses.BUTTON_PRESS(mouse_event[:bstate], 1)
157
+
158
+ The possible button states are: PRESS, RELEASE, CLICK, DOUBLE_CLICK
159
+ and TRIPLE_CLICK.
160
+
161
+ = Experimental stuff
162
+
163
+ == Specifying which curses library to use
164
+
165
+ You can specify which variant of curses you want to use by setting the
166
+ environment variable +RUBY_FFI_NCURSES_LIB+ to the one you want. For
167
+ example, to use PDCurses X11 curses lib, use:
168
+
169
+ RUBY_FFI_NCURSES_LIB=XCurses ruby examples/hello.rb
170
+
171
+ You can use this to specify +ncursesw+ for example. Please note that
172
+ only the bog standard ncurses lib has been in any way tested as of
173
+ yet.
174
+
175
+ = TO DO
176
+
177
+ == Complete translation of core functions to Darwin (Mac OS X)
178
+
179
+ There are some macros in darwin ncurses.h which I haven't
180
+ implemented yet. I'm working on it but if there are any you
181
+ desperately need let me know.
182
+
183
+ == +curscr+ and +newscr+ for JRuby
184
+
185
+ These global variables are not often used but are required for certain
186
+ situations (e.g. doing a wrefresh after shelling out and for the
187
+ get/setsyx macros).
188
+
189
+ This requires the implementation of +find_sym+ in JRuby (expected in
190
+ JRuby 1.1.7).
191
+
192
+ == Tests
193
+
194
+ This is tricky - I'm not sure exactly how to properly test a wrapper
195
+ for a library like ncurses. I certainly don't want to test ncurses!
196
+ Instead, I want to ensure my wrapper faithfully reproduces the
197
+ functionality of the platform's ncurses lib. To that end, I'm
198
+ experimenting with a simple DSL to generate both C and Ruby versions
199
+ of a test. With that I can generate equivalent programs and compare
200
+ the output. However, this is not really ready for prime time yet.
201
+
202
+ == Tidy up internals and examples
203
+
204
+ Things got a bit messy as I switched between the Linux and Mac
205
+ versions. The examples should be more focussed.
206
+
207
+ == Scope implementation of Menu and Form interface wrappers
208
+
209
+ I'm not particularly interested in the ncurses extension libraries for
210
+ forms and menus. I would rather spend time implementing similar
211
+ functionality on top of a portable text console library (or porting
212
+ rbcurses). However, in the interests of completeness, I suppose I
213
+ ought to at least scope it out.
214
+
215
+ = Trivia
216
+
217
+ While researching ncurses on Google, I innocently entered "curses
218
+ getsx" as a search term. NSFW and definitely not one for "I'm Feeling
219
+ Lucky".
220
+
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ begin
10
+ load 'tasks/setup.rb'
11
+ rescue LoadError
12
+ raise RuntimeError, '### please install the "bones" gem ###'
13
+ end
14
+ end
15
+
16
+ ensure_in_path 'lib'
17
+ require 'ffi-ncurses'
18
+
19
+ task :default => 'spec:run'
20
+
21
+ # see tasks/setup.rb for full list of options
22
+
23
+ PROJ.name = 'ffi-ncurses'
24
+ PROJ.authors = ["Sean O'Halpin"]
25
+ PROJ.email = 'sean.ohalpin@gmail.com'
26
+ PROJ.url = 'http://github.com/seanohalpin/ffi-ncurses'
27
+ PROJ.summary = "FFI wrapper for ncurses"
28
+ PROJ.version = "0.3.0"
29
+ PROJ.rubyforge.name = 'ffi-ncurses'
30
+
31
+ # gem
32
+ PROJ.gem.dependencies << ["ffi", ">= 0.2.0"]
33
+
34
+ # rdoc
35
+ PROJ.rdoc.exclude << "^notes"
36
+ PROJ.readme_file = 'README.rdoc'
37
+
38
+ # spec
39
+ PROJ.spec.opts << '--color'
40
+
41
+ # files
42
+ PROJ.exclude = %w(tmp$ bak$ ~$ CVS \.svn ^pkg ^doc \.git local notes)
43
+ PROJ.exclude << '^tags$' << "^bug" << "^tools"
44
+ PROJ.exclude << File.read('.gitignore').split(/\n/)
45
+
46
+ # notes
47
+ #PROJ.notes.exclude = %w(^README\.txt$ ^data/)
48
+ PROJ.notes.extensions << '.org'
49
+
50
+ # EOF
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Sean O'Halpin, 2009-02-15
4
+ #
5
+ require 'ffi-ncurses'
6
+ begin
7
+ stdscr = FFI::NCurses.initscr
8
+ FFI::NCurses.clear
9
+ FFI::NCurses.addstr("Hello world!")
10
+ FFI::NCurses.refresh
11
+ FFI::NCurses.getch
12
+ ensure
13
+ FFI::NCurses.endwin
14
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Sean O'Halpin, 2009-02-15
4
+ #
5
+ require 'ffi-ncurses'
6
+ include FFI::NCurses
7
+ begin
8
+ stdscr = initscr
9
+ start_color
10
+ curs_set 0
11
+ raw
12
+ cbreak
13
+ noecho
14
+ clear
15
+ move 10, 10
16
+ standout
17
+ addstr("Hi!")
18
+ standend
19
+ refresh
20
+ getch
21
+ ensure
22
+ endwin
23
+ end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Sean O'Halpin, 2009-02-15
4
+ #
5
+ require 'ffi-ncurses'
6
+ include FFI::NCurses
7
+ initscr
8
+ begin
9
+ attributes = %w[
10
+ A_BLINK
11
+ A_BOLD
12
+ A_DIM
13
+ A_NORMAL
14
+ A_REVERSE
15
+ A_STANDOUT
16
+ A_UNDERLINE
17
+ ]
18
+ alt_attributes = %w[
19
+ A_ALTCHARSET
20
+ A_HORIZONTAL
21
+ A_INVIS
22
+ A_LEFT
23
+ A_LOW
24
+ A_PROTECT
25
+ A_RIGHT
26
+ A_TOP
27
+ A_VERTICAL
28
+ ]
29
+
30
+ attributes.each do |attr|
31
+ attr_const = FFI::NCurses.const_get(attr)
32
+ attr_set attr_const, 0, nil
33
+ addstr "THIS IS #{attr}\n"
34
+ end
35
+
36
+ refresh
37
+ ch = getch
38
+ ensure
39
+ endwin
40
+ end
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Sean O'Halpin, 2009-02-15
4
+ #
5
+ require 'ffi-ncurses'
6
+ include FFI::NCurses
7
+
8
+ initscr
9
+ begin
10
+ # turn cursor off
11
+ curs_set 0
12
+
13
+ # initialize colour
14
+ start_color
15
+
16
+ # set up colour pairs
17
+ # Background Foreground
18
+ init_pair(0, Colour::BLACK, Colour::BLACK)
19
+ init_pair(1, Colour::RED, Colour::BLACK)
20
+ init_pair(2, Colour::GREEN, Colour::BLACK)
21
+ init_pair(3, Colour::YELLOW, Colour::BLACK)
22
+ init_pair(4, Colour::BLUE, Colour::BLACK)
23
+ init_pair(5, Colour::MAGENTA, Colour::BLACK)
24
+ init_pair(6, Colour::CYAN, Colour::BLACK)
25
+ init_pair(7, Colour::WHITE, Colour::BLACK)
26
+
27
+ init_pair(8, Colour::BLACK, Colour::BLACK)
28
+ init_pair(9, Colour::BLACK, Colour::RED)
29
+ init_pair(10, Colour::BLACK, Colour::GREEN)
30
+ init_pair(11, Colour::BLACK, Colour::YELLOW)
31
+ init_pair(12, Colour::BLACK, Colour::BLUE)
32
+ init_pair(13, Colour::BLACK, Colour::MAGENTA)
33
+ init_pair(14, Colour::BLACK, Colour::CYAN)
34
+ init_pair(15, Colour::BLACK, Colour::WHITE)
35
+
36
+ 0.upto(15) do |i|
37
+ attr_set A_NORMAL, i, nil
38
+ addch(?A + i)
39
+ end
40
+
41
+ # add character and attribute together
42
+ addch(?Z | COLOR_PAIR(1)) # red
43
+
44
+ # reset attribute and colour to default
45
+ attr_set A_NORMAL, 0, nil
46
+
47
+ # start new line
48
+ addstr "\n"
49
+
50
+ # how to add a single space
51
+ addch(' '[0])
52
+ # or
53
+ addstr(" ")
54
+
55
+ addstr "Press any key"
56
+
57
+ # display and pause for key press
58
+ refresh
59
+ ch = getch
60
+ ensure
61
+ endwin
62
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Sean O'Halpin, 2009-02-15
4
+ #
5
+ require 'ffi-ncurses'
6
+ include FFI::NCurses
7
+ begin
8
+ initscr
9
+ addstr "Default"
10
+ getch
11
+ addstr "curs_set 0"
12
+ curs_set 0
13
+ getch
14
+ addstr "curs_set 1"
15
+ curs_set 1
16
+ getch
17
+ addstr "curs_set 2"
18
+ curs_set 2
19
+ getch
20
+ ensure
21
+ FFI::NCurses.endwin
22
+ end