1 module termbox;
2 
3 public import color;
4 public import keyboard;
5 
6 /* A cell, single conceptual entity on the terminal screen. The terminal screen
7  * is basically a 2d array of cells. It has the following fields:
8  *  - 'ch' is a unicode character
9  *  - 'fg' foreground color and attributes
10  *  - 'bg' background color and attributes
11  */
12 struct Cell {
13     uint ch;
14     ushort fg;
15     ushort bg;
16 };
17 
18 enum EventType {
19     key    = 1,
20     resize = 2,
21     mouse  = 3
22 }
23 
24 /* An event, single interaction from the user. The 'mod' and 'ch' fields are
25  * valid if 'type' is TB_EVENT_KEY. The 'w' and 'h' fields are valid if 'type'
26  * is TB_EVENT_RESIZE. The 'x' and 'y' fields are valid if 'type' is
27  * TB_EVENT_MOUSE. The 'key' field is valid if 'type' is either TB_EVENT_KEY
28  * or TB_EVENT_MOUSE. The fields 'key' and 'ch' are mutually exclusive; only
29  * one of them can be non-zero at a time.
30  */
31 struct Event {
32     ubyte type;
33     ubyte mod; /* modifiers to either 'key' or 'ch' below */
34     ushort key; /* one of the TB_KEY_* constants */
35     uint ch; /* unicode character */
36     int w;
37     int h;
38     int x;
39     int y;
40 };
41 
42 /* Error codes returned by tb_init(). All of them are self-explanatory, except
43  * the pipe trap error. Termbox uses unix pipes in order to deliver a message
44  * from a signal handler (SIGWINCH) to the main event reading loop. Honestly in
45  * most cases you should just check the returned code as < 0.
46  */
47 enum Error {
48     unsupportedTerminal = -1,
49     failedToOpenTTY     = -2,
50     pipeTrapError       = -3
51 }
52 
53 /* Initializes the termbox library. This function should be called before any
54  * other functions. After successful initialization, the library must be
55  * finalized using the tb_shutdown() function.
56  */
57 private extern (C) int tb_init();
58 private extern (C) void tb_shutdown();
59 
60 /* Returns the size of the internal back buffer (which is the same as
61  * terminal's window size in characters). The internal buffer can be resized
62  * after tb_clear() or tb_present() function calls. Both dimensions have an
63  * unspecified negative value when called before tb_init() or after
64  * tb_shutdown().
65  */
66 private extern (C) int tb_width();
67 private extern (C) int tb_height();
68 
69 /* Clears the internal back buffer using TB_DEFAULT color or the
70  * color/attributes set by tb_set_clear_attributes() function.
71  */
72 private extern (C) void tb_clear();
73 private extern (C) void tb_set_clear_attributes(ushort fg, ushort bg);
74 
75 /* Synchronizes the internal back buffer with the terminal. */
76 private extern (C) void tb_present();
77 
78 enum hideCursor = -1;
79 
80 /* Sets the position of the cursor. Upper-left character is (0, 0). If you pass
81  * TB_HIDE_CURSOR as both coordinates, then the cursor will be hidden. Cursor
82  * is hidden by default.
83  */
84 private extern (C) void tb_set_cursor(int cx, int cy);
85 
86 /* Changes cell's parameters in the internal back buffer at the specified
87  * position.
88  */
89 private extern (C) void tb_put_cell(int x, int y, Cell* cell);
90 private extern (C) void tb_change_cell(int x, int y, uint ch, uint fg, uint bg);
91 
92 /* Copies the buffer from 'cells' at the specified position, assuming the
93  * buffer is a two-dimensional array of size ('w' x 'h'), represented as a
94  * one-dimensional buffer containing lines of cells starting from the top.
95  *
96  * (DEPRECATED: use tb_cell_buffer() instead and copy memory on your own)
97  */
98 private extern (C) void tb_blit(int x, int y, int w, int h, Cell* cells);
99 
100 /* Returns a pointer to internal cell back buffer. You can get its dimensions
101  * using tb_width() and tb_height() functions. The pointer stays valid as long
102  * as no tb_clear() and tb_present() calls are made. The buffer is
103  * one-dimensional buffer containing lines of cells starting from the top.
104  */
105 private extern (C) Cell* tb_cell_buffer();
106 
107 /* Sets the termbox input mode. Termbox has two input modes:
108  * 1. Esc input mode.
109  *    When ESC sequence is in the buffer and it doesn't match any known
110  *    ESC sequence => ESC means TB_KEY_ESC.
111  * 2. Alt input mode.
112  *    When ESC sequence is in the buffer and it doesn't match any known
113  *    sequence => ESC enables TB_MOD_ALT modifier for the next keyboard event.
114  *
115  * You can also apply TB_INPUT_MOUSE via bitwise OR operation to either of the
116  * modes (e.g. TB_INPUT_ESC | TB_INPUT_MOUSE). If none of the main two modes
117  * were set, but the mouse mode was, TB_INPUT_ESC mode is used. If for some
118  * reason you've decided to use (TB_INPUT_ESC | TB_INPUT_ALT) combination, it
119  * will behave as if only TB_INPUT_ESC was selected.
120  *
121  * If 'mode' is TB_INPUT_CURRENT, it returns the current input mode.
122  *
123  * Default termbox input mode is TB_INPUT_ESC.
124  */
125 private extern (C) int tb_select_input_mode(int mode);
126 
127 enum InputMode {
128     current = 0,
129     esc     = 1,
130     alt     = 2,
131     mouse   = 4
132 }
133 
134 enum OutputMode {
135     current   = 0,
136     normal    = 1,
137     out256    = 2,
138     out216    = 3,
139     grayscale = 4
140 }
141 
142 /* Sets the termbox output mode. Termbox has three output options:
143  * 1. TB_OUTPUT_NORMAL     => [1..8]
144  *    This mode provides 8 different colors:
145  *      black, red, green, yellow, blue, magenta, cyan, white
146  *    Shortcut: TB_BLACK, TB_RED, ...
147  *    Attributes: TB_BOLD, TB_UNDERLINE, TB_REVERSE
148  *
149  *    Example usage:
150  *        tb_change_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED);
151  *
152  * 2. TB_OUTPUT_256        => [0..256]
153  *    In this mode you can leverage the 256 terminal mode:
154  *    0x00 - 0x07: the 8 colors as in TB_OUTPUT_NORMAL
155  *    0x08 - 0x0f: TB_* | TB_BOLD
156  *    0x10 - 0xe7: 216 different colors
157  *    0xe8 - 0xff: 24 different shades of grey
158  *
159  *    Example usage:
160  *        tb_change_cell(x, y, '@', 184, 240);
161  *        tb_change_cell(x, y, '@', 0xb8, 0xf0);
162  *
163  * 2. TB_OUTPUT_216        => [0..216]
164  *    This mode supports the 3rd range of the 256 mode only.
165  *    But you don't need to provide an offset.
166  *
167  * 3. TB_OUTPUT_GRAYSCALE  => [0..23]
168  *    This mode supports the 4th range of the 256 mode only.
169  *    But you dont need to provide an offset.
170  *
171  * Execute build/src/demo/output to see its impact on your terminal.
172  *
173  * If 'mode' is TB_OUTPUT_CURRENT, it returns the current output mode.
174  *
175  * Default termbox output mode is TB_OUTPUT_NORMAL.
176  */
177 private extern (C) int tb_select_output_mode(int mode);
178 
179 /* Wait for an event up to 'timeout' milliseconds and fill the 'event'
180  * structure with it, when the event is available. Returns the type of the
181  * event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case
182  * there were no event during 'timeout' period.
183  */
184 private extern (C) int tb_peek_event(Event* event, int timeout);
185 
186 /* Wait for an event forever and fill the 'event' structure with it, when the
187  * event is available. Returns the type of the event (one of TB_EVENT_*
188  * constants) or -1 if there was an error.
189  */
190 private extern (C) int tb_poll_event(Event* event);
191 
192 /* Utility utf8 functions. */
193 enum TB_EOF = -1;
194 private extern (C) int tb_utf8_char_length(char c);
195 private extern (C) int tb_utf8_char_to_unicode(uint* out_, char* c);
196 private extern (C) int tb_utf8_unicode_to_char(char* out_, uint c);
197 
198 
199 
200 int init() { return tb_init(); }
201 void shutdown() { tb_shutdown(); }
202 
203 int height() { return tb_height(); }
204 int width() { return tb_width(); }
205 
206 void clear() { tb_clear(); }
207 void setClearAttributes(ushort fg, ushort bg) { tb_set_clear_attributes(fg, bg); }
208 
209 void present() { tb_present(); }
210 
211 void setCursor(int cx, int cy) { tb_set_cursor(cx, cy); }
212 
213 void putCell(int x, int y, Cell* cell) { tb_put_cell(x, y, cell); }
214 void changeCell(int x, int y, uint ch, ushort fg, ushort bg) { tb_change_cell(x, y, ch, fg, bg); }
215 
216 void blit(int x, int y, int w, int h, Cell* cells) { tb_blit(x, y, w, h, cells); }
217 
218 Cell* cellBuffer() { return tb_cell_buffer(); }
219 
220 int selectInputMode(InputMode mode) { return tb_select_input_mode(mode); }
221 int selectOutputMode(OutputMode mode) { return tb_select_output_mode(mode); }
222 
223 int peekEvent(Event* event, int timeout) { return tb_peek_event(event, timeout); }
224 int pollEvent(Event* event) { return tb_poll_event(event); }
225 
226 int charLength(char c) { return tb_utf8_char_length(c); }
227 int charToUnicode(uint* out_, char* c) { return tb_utf8_char_to_unicode(out_, c); }
228 int unicodeToChar(char* out_, uint c) { return tb_utf8_unicode_to_char(out_, c); }