cfad47cfa3/src/osscurses.cc

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* This file implements the functions described in tads2/osgen.h.
2
 */
3
#include "common.h"
4
5
#include <sys/time.h>
6
#include <unistd.h>
7
#include <string.h> // FD_SET is a macro for memset()
8
9
#include "frobtadsapp.h"
10
11
#include "os.h"
12
extern "C" {
13
#include "osgen.h"
14
}
15
16
#include "colors.h"
17
#include "frobcurses.h"
18
19
20
/* Translate a portable color specification to an oss-style color code.
21
 *
22
 * We treat colors as another form of attribute, just like curses does.
23
 * Therefore, the return value is an OR'ed together combination of
24
 * curses attributes that include information for both color as well as
25
 * hilite.
26
 *
27
 * Note that we cannot support all the 16 ANSI colors, since curses has
28
 * only 8 colors.  The other 8 are normally obtained by using the A_BOLD
29
 * attribute.  Since A_BOLD is reserved for the TADS OS_ATTR_BOLD
30
 * attribute, we can only use the 8 low intensity ANSI colors.  Using
31
 * A_BOLD to support the other 8 would leave us no way to display the
32
 * TADS OS_ATTR_BOLD attribute.  A solution to this would be to use
33
 * A_UNDERLINE instead of A_BOLD for bold text.  But a) not all
34
 * terminals support this and b) it looks ugly.  Using A_HILITE is no
35
 * solution either, as most terminals treat it the same as A_REVERSE.
36
 * If you ask me, 8 colors should be more than enough for everyone [sic].
37
 * Back in my days we had only 2 of them, you know.
38
 */
39
int
40
ossgetcolor( int fg, int bg, int attrs, int screen_color )
41
{
42
	int f, b, ret;
43
44
	// If we don't have color-support enabled, just check if the
45
	// caller wants to know the statusline colors, in which case we
46
	// should use the A_REVERSE attribute, wants invisible text, in
47
	// which case we use the A_INVIS attribute, and if bold is to be
48
	// used.
49
	if (not globalApp->colorsEnabled()) {
50
		f = fg;
51
		b = (bg == OSGEN_COLOR_TRANSPARENT) ? screen_color : bg;
52
53
		if (b == OSGEN_COLOR_STATUSBG)
54
			// It's the statusline; reverse it.
55
			ret = A_REVERSE;
56
		else if (f == b)
57
			// The caller wants invisible text.
58
			ret = A_INVIS;
59
		else
60
			// Don't know, don't care.
61
			ret = A_NORMAL;
62
		// Check for bold.
63
		if (attrs & OS_ATTR_HILITE) ret |= A_BOLD;
64
		return ret;
65
	}
66
67
	switch (fg) {
68
	  case OSGEN_COLOR_BLACK:
69
	  case OSGEN_COLOR_GRAY:       f = FROB_BLACK; break;
70
71
	  case OSGEN_COLOR_MAROON:
72
	  case OSGEN_COLOR_RED:        f = FROB_RED; break;
73
74
	  case OSGEN_COLOR_GREEN:
75
	  case OSGEN_COLOR_LIME:       f = FROB_GREEN; break;
76
77
	  case OSGEN_COLOR_NAVY:
78
	  case OSGEN_COLOR_BLUE:       f = FROB_BLUE; break;
79
80
	  case OSGEN_COLOR_TEAL:
81
	  case OSGEN_COLOR_CYAN:       f = FROB_CYAN; break;
82
83
	  case OSGEN_COLOR_PURPLE:
84
	  case OSGEN_COLOR_MAGENTA:    f = FROB_MAGENTA; break;
85
86
	  case OSGEN_COLOR_OLIVE:
87
	  case OSGEN_COLOR_YELLOW:     f = FROB_YELLOW; break;
88
89
	  case OSGEN_COLOR_SILVER:
90
	  case OSGEN_COLOR_WHITE:      f = FROB_WHITE; break;
91
92
	  case OSGEN_COLOR_TEXTBG:     f = globalApp->options.bgColor; break;
93
94
	  case OSGEN_COLOR_INPUT:      f = globalApp->options.textColor; break;
95
96
	  case OSGEN_COLOR_STATUSLINE: f = globalApp->options.statTextColor; break;
97
98
	  case OSGEN_COLOR_STATUSBG:   f = globalApp->options.statBgColor; break;
99
100
	  default:                     f = globalApp->options.textColor;
101
	}
102
103
	switch ((bg != OSGEN_COLOR_TRANSPARENT) ? bg : screen_color) {
104
	  case OSGEN_COLOR_BLACK:
105
	  case OSGEN_COLOR_GRAY:       b = FROB_BLACK; break;
106
107
	  case OSGEN_COLOR_MAROON:
108
	  case OSGEN_COLOR_RED:        b = FROB_RED; break;
109
110
	  case OSGEN_COLOR_GREEN:
111
	  case OSGEN_COLOR_LIME:       b = FROB_GREEN; break;
112
113
	  case OSGEN_COLOR_NAVY:
114
	  case OSGEN_COLOR_BLUE:       b = FROB_BLUE; break;
115
116
	  case OSGEN_COLOR_TEAL:
117
	  case OSGEN_COLOR_CYAN:       b = FROB_CYAN; break;
118
119
	  case OSGEN_COLOR_PURPLE:
120
	  case OSGEN_COLOR_MAGENTA:    b = FROB_MAGENTA; break;
121
122
	  case OSGEN_COLOR_OLIVE:
123
	  case OSGEN_COLOR_YELLOW:     b = FROB_YELLOW; break;
124
125
	  case OSGEN_COLOR_SILVER:
126
	  case OSGEN_COLOR_WHITE:      b = FROB_WHITE; break;
127
128
	  case OSGEN_COLOR_TEXT:
129
	  case OSGEN_COLOR_INPUT:      b = globalApp->options.textColor; break;
130
131
	  case OSGEN_COLOR_STATUSBG:   b = globalApp->options.statBgColor; break;
132
133
	  case OSGEN_COLOR_STATUSLINE: b = globalApp->options.statTextColor; break;
134
135
	  default:                     b = globalApp->options.bgColor;
136
	}
137
138
	// Construct the color pair.
139
	ret = COLOR_PAIR(makeColorPair(f,b));
140
141
	// Make Tads happy if it wants bold.
142
	if (attrs & OS_ATTR_HILITE) ret |= A_BOLD;
143
	return ret;
144
}
145
146
147
/* Translate a key event from "raw" mode to processed mode.
148
 */
149
void
150
oss_raw_key_to_cmd( os_event_info_t* evt )
151
{
152
	if (evt->key[0] == 0) switch (evt->key[1]) {
153
		// Toggle scrollback-mode with F1.
154
		case CMD_F1: evt->key[1] = CMD_SCR; break;
155
156
		// Delete entire input with F2.
157
		case CMD_F2: evt->key[1] = CMD_KILL; break;
158
159
		// Delete from current position to end of input with F3.
160
		case CMD_F3: evt->key[1] = CMD_DEOL; break;
161
	} else switch (evt->key[0]) {
162
		// Also toggle scrollback mode with the ESC key, since
163
		// some terminals lack function keys.
164
		case 27: evt->key[0] = 0; evt->key[1] = CMD_SCR; break;
165
	}
166
}
167
168
169
/* Clear an area of the screen.
170
 */
171
void
172
ossclr( int top, int left, int bottom, int right, int color )
173
{
174
	globalApp->clear(top, left, bottom, right, color);
175
}
176
177
178
/* Display text at a particular location in a particular color.
179
 */
180
void
181
ossdsp( int line, int column, int color, const char* msg )
182
{
183
	// Suppress output if the text should be invisible.  This is the
184
	// only way to have "invisible" text without color-support.
185
	// When colors are enabled, text and background will have the
186
	// same color, so the text is really invisible in color-mode;
187
	// A_INVIS is not needed then.
188
	if (not (color & A_INVIS)) globalApp->print(line, column, color, msg);
189
}
190
191
192
/* Move the cursor.
193
 */
194
void
195
ossloc( int line, int column )
196
{
197
	globalApp->moveCursor(line, column);
198
}
199
200
201
/* Scroll a region of the screen UP one line.
202
 */
203
void
204
ossscu( int top_line, int left_column, int bottom_line, int right_column, int blank_color )
205
{
206
	globalApp->scrollRegionUp(top_line, left_column, bottom_line, right_column, blank_color);
207
}
208
209
210
/* Scroll a region of the screen DOWN one line.
211
 */
212
void
213
ossscr( int top_line, int left_column, int bottom_line, int right_column, int blank_color )
214
{
215
	globalApp->scrollRegionDown(top_line, left_column, bottom_line, right_column, blank_color);
216
}
217
218
219
/* Determine if stdin is at end-of-file.  If possible, this should
220
 * return the stdin status even if we've never attempted to read stdin.
221
 *
222
 * On non-Microsoft platforms, we check with select() if stdin can be
223
 * read from.  Note that feof() won't work, since this function is
224
 * required to check the status of stdin before even an attempt is made
225
 * to read from it.
226
 *
227
 * On Microsoft Windows (Windows also defines MSDOS), we use an
228
 * appropriate win32 API call.
229
 */
230
int
231
oss_eof_on_stdin()
232
{
233
#ifndef MSDOS
234
	fd_set rfds;
235
	timeval tv;
236
237
	// Zero time: non-blocking operation.
238
	tv.tv_sec = 0;
239
	tv.tv_usec = 0;
240
241
	FD_ZERO(&rfds);
242
	// stdin always has a file descriptor of 0.
243
	FD_SET(0, &rfds);
244
245
	return select(1, &rfds, 0, 0, &tv) == -1;
246
#else
247
	return _eof(_fileno(stdin)) > 0;
248
#endif
249
}
250
251
/* Get system information.
252
 */
253
int
254
oss_get_sysinfo( int code, void*, long* result )
255
{
256
	switch(code)
257
	{
258
	  case SYSINFO_TEXT_COLORS:
259
		// We support ANSI colors for both foreground and
260
		// background.
261
		*result = SYSINFO_TXC_ANSI_FGBG;
262
		break;
263
264
	  case SYSINFO_TEXT_HILITE:
265
		// We do text highlighting.
266
		*result = 1;
267
		break;
268
269
	  default:
270
		// We didn't recognize the code.
271
		return false;
272
	}
273
	// We recognized the code.
274
	return true;
275
}