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    = cast(ubyte) 1,
20     resize = cast(ubyte) 2,
21     mouse  = cast(ubyte) 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 /* Sets the position of the cursor. Upper-left character is (0, 0). If you pass
79  * TB_HIDE_CURSOR as both coordinates, then the cursor will be hidden. Cursor
80  * is hidden by default.
81  */
82 private extern (C) void tb_set_cursor(int cx, int cy);
83 
84 /* Changes cell's parameters in the internal back buffer at the specified
85  * position.
86  */
87 private extern (C) void tb_put_cell(int x, int y, Cell* cell);
88 private extern (C) void tb_change_cell(int x, int y, uint ch, uint fg, uint bg);
89 
90 /* Returns a pointer to internal cell back buffer. You can get its dimensions
91  * using tb_width() and tb_height() functions. The pointer stays valid as long
92  * as no tb_clear() and tb_present() calls are made. The buffer is
93  * one-dimensional buffer containing lines of cells starting from the top.
94  */
95 private extern (C) Cell* tb_cell_buffer();
96 
97 /* Sets the termbox input mode. Termbox has two input modes:
98  * 1. Esc input mode.
99  *    When ESC sequence is in the buffer and it doesn't match any known
100  *    ESC sequence => ESC means TB_KEY_ESC.
101  * 2. Alt input mode.
102  *    When ESC sequence is in the buffer and it doesn't match any known
103  *    sequence => ESC enables TB_MOD_ALT modifier for the next keyboard event.
104  *
105  * You can also apply TB_INPUT_MOUSE via bitwise OR operation to either of the
106  * modes (e.g. TB_INPUT_ESC | TB_INPUT_MOUSE). If none of the main two modes
107  * were set, but the mouse mode was, TB_INPUT_ESC mode is used. If for some
108  * reason you've decided to use (TB_INPUT_ESC | TB_INPUT_ALT) combination, it
109  * will behave as if only TB_INPUT_ESC was selected.
110  *
111  * If 'mode' is TB_INPUT_CURRENT, it returns the current input mode.
112  *
113  * Default termbox input mode is TB_INPUT_ESC.
114  */
115 private extern (C) int tb_select_input_mode(int mode);
116 
117 enum InputMode {
118     current = 0,
119     esc     = 1,
120     alt     = 2,
121     mouse   = 4
122 }
123 
124 enum OutputMode {
125     current   = 0,
126     normal    = 1,
127     out256    = 2,
128     out216    = 3,
129     grayscale = 4
130 }
131 
132 /* Sets the termbox output mode. Termbox has three output options:
133  * 1. TB_OUTPUT_NORMAL     => [1..8]
134  *    This mode provides 8 different colors:
135  *      black, red, green, yellow, blue, magenta, cyan, white
136  *    Shortcut: TB_BLACK, TB_RED, ...
137  *    Attributes: TB_BOLD, TB_UNDERLINE, TB_REVERSE
138  *
139  *    Example usage:
140  *        tb_change_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED);
141  *
142  * 2. TB_OUTPUT_256        => [0..256]
143  *    In this mode you can leverage the 256 terminal mode:
144  *    0x00 - 0x07: the 8 colors as in TB_OUTPUT_NORMAL
145  *    0x08 - 0x0f: TB_* | TB_BOLD
146  *    0x10 - 0xe7: 216 different colors
147  *    0xe8 - 0xff: 24 different shades of grey
148  *
149  *    Example usage:
150  *        tb_change_cell(x, y, '@', 184, 240);
151  *        tb_change_cell(x, y, '@', 0xb8, 0xf0);
152  *
153  * 2. TB_OUTPUT_216        => [0..216]
154  *    This mode supports the 3rd range of the 256 mode only.
155  *    But you don't need to provide an offset.
156  *
157  * 3. TB_OUTPUT_GRAYSCALE  => [0..23]
158  *    This mode supports the 4th range of the 256 mode only.
159  *    But you dont need to provide an offset.
160  *
161  * Execute build/src/demo/output to see its impact on your terminal.
162  *
163  * If 'mode' is TB_OUTPUT_CURRENT, it returns the current output mode.
164  *
165  * Default termbox output mode is TB_OUTPUT_NORMAL.
166  */
167 private extern (C) int tb_select_output_mode(int mode);
168 
169 /* Wait for an event up to 'timeout' milliseconds and fill the 'event'
170  * structure with it, when the event is available. Returns the type of the
171  * event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case
172  * there were no event during 'timeout' period.
173  */
174 private extern (C) int tb_peek_event(Event* event, int timeout);
175 
176 /* Wait for an event forever and fill the 'event' structure with it, when the
177  * event is available. Returns the type of the event (one of TB_EVENT_*
178  * constants) or -1 if there was an error.
179  */
180 private extern (C) int tb_poll_event(Event* event);
181 
182 /* Utility utf8 functions. */
183 enum TB_EOF = -1;
184 private extern (C) int tb_utf8_char_length(char c);
185 private extern (C) int tb_utf8_char_to_unicode(uint* out_, const char* c);
186 private extern (C) int tb_utf8_unicode_to_char(char* out_, uint c);
187 
188 
189 int init() { return tb_init(); }
190 void shutdown() { tb_shutdown(); }
191 
192 int height() { return tb_height(); }
193 int width() { return tb_width(); }
194 
195 void clear() { tb_clear(); }
196 void setClearAttributes(ushort fg, ushort bg) { tb_set_clear_attributes(fg, bg); }
197 
198 void flush() { tb_present(); }
199 
200 void setCursor(int cx, int cy) { tb_set_cursor(cx, cy); }
201 
202 void putCell(int x, int y, Cell* cell) { tb_put_cell(x, y, cell); }
203 void setCell(int x, int y, uint ch, ushort fg, ushort bg) { tb_change_cell(x, y, ch, fg, bg); }
204 
205 Cell* cellBuffer() { return tb_cell_buffer(); }
206 
207 int setInputMode(InputMode mode) { return tb_select_input_mode(mode); }
208 int setOutputMode(OutputMode mode) { return tb_select_output_mode(mode); }
209 
210 int peekEvent(Event* event, int timeout) { return tb_peek_event(event, timeout); }
211 int pollEvent(Event* event) { return tb_poll_event(event); }
212 
213 int charLength(char c) { return tb_utf8_char_length(c); }
214 int charToUnicode(uint* out_, const char* c) { return tb_utf8_char_to_unicode(out_, c); }
215 int unicodeToChar(char* out_, uint c) { return tb_utf8_unicode_to_char(out_, c); }
216 
217 void hideCursor() { setCursor(-1, -1); }