1 /*
2 Console
3 */
4
5 #include "console.h"
6
7 #include "alloc.h"
8 #include "head.h"
9 #include "infocom.h"
10 #include "os.h"
11 #include "print.h"
12 #include "queue.h"
13 #include "wio.h"
14
15 console con;
16 bool newlines_are_significant;
17
18 static int quick_redraw;
19 #define reformatting 0
20
wipe_slack(int x1,int y1,int x2,int y2)21 static void wipe_slack(int x1, int y1, int x2, int y2)
22 {
23 if(y1 < y2 && x1 < x2)
24 {
25 int i, j;
26 console_cell blank;
27 start_update();
28 /* Build a blank character */
29 blank.text = ' ';
30 blank.attr = con.cursor.attr;
31 blank.attr.font = FONT_NORMAL;
32 /* Blank the first row */
33 for(j = x1; j < x2; ++j)
34 con.row[y1].slack[j] = blank;
35 /* Blat that into the subsequent rows */
36 for(i = y1 + 1; i < y2; ++i)
37 os_mcpy(&con.row[i].slack[x1], &con.row[y1].slack[x1], (x2-x1) * sizeof(blank));
38 /* Touch the lines and adjust cached lengths */
39 for(i = y1; i < y2; ++i)
40 {
41 int last = con.row[i].held; /* Index of last known character */
42 /* Line needs redrawing if characters up to the last were altered */
43 if(x1 <= last)
44 touch(i);
45 /* Line has been truncated if the last character has changed */
46 if(x1 <= last && last < x2)
47 con.row[i].held = x1;
48 }
49 finish_update();
50 }
51 }
52
wipe_fixed(int x1,int y1,int x2,int y2)53 static void wipe_fixed(int x1, int y1, int x2, int y2)
54 {
55 int i;
56 console_cell blank;
57 blank.text = 0;
58 blank.attr = con.cursor.attr;
59 blank.attr.font = FONT_NORMAL;
60 start_update();
61 for(i = y1; i < y2; ++i)
62 if(con.row[i].fix)
63 {
64 int j;
65 bool f;
66 for(j = x1; j < x2; ++j)
67 con.row[i].fixed[j] = blank;
68 f = 0;
69 for(j = 0; j < x1 && !f; ++j)
70 f = con.row[i].fixed[j].text != 0;
71 for(j = x2; j < MAX_FIXED && !f; ++j)
72 f = con.row[i].fixed[j].text != 0;
73 con.row[i].fix = f;
74 touch(i);
75 }
76 finish_update();
77 }
78
find_eol(int row)79 int find_eol(int row)
80 {
81 int i = con.row[row].held;
82 while(i && is_a_space(con.row[row].slack[i - 1])) --i;
83 con.row[row].held = i;
84 return i;
85 }
86
87
init_console(int rows,int fixed)88 void init_console(int rows, int fixed)
89 {
90 if(!con.cursor.attr.font)
91 {
92 con.cursor.attr.font = FONT_NORMAL;
93 con.cursor.attr.fore = 2;
94 con.cursor.attr.back = 9;
95 }
96 con.shape.fixed = min(MAX_FIXED, fixed);
97 con.shape.height = min(MAX_HEIGHT, rows);
98 /* con.top = 0; */
99 con.bottom = con.shape.height;
100 hd_set_size(con.shape.height, con.shape.fixed);
101 {
102 erase_window(0, MAX_HEIGHT);
103 con.cursor.y = con.shape.height - 1;
104 }
105 }
106
start_update(void)107 void start_update(void)
108 {
109 ++quick_redraw;
110 }
111
finish_update(void)112 void finish_update(void)
113 {
114 if(--quick_redraw <= 0)
115 force_update();
116 }
117
touch(int row)118 void touch(int row)
119 {
120 if(quick_redraw > 0)
121 con.row[row].flag = 1;
122 else
123 repaint(row);
124 }
125
force_update(void)126 void force_update(void)
127 {
128 int y = con.shape.height;
129 while(--y >= 0)
130 if(con.row[y].flag)
131 repaint(y);
132 redraw_cursor();
133 }
134
set_xy(int x,int y)135 void set_xy(int x, int y)
136 {
137 hide_cursor();
138 if(x < 0) x = 0;
139 if(y < 0) y = 0;
140 if(con.cursor.align)
141 {
142 con.cursor.x = min(x, MAX_FIXED - 1);
143 con.cursor.y = min(y, MAX_HEIGHT - 1);
144 }
145 else
146 {
147 con.cursor.x = min(x, MAX_SLACK - 1);
148 con.cursor.y = min(y, con.shape.height - 1);
149 }
150 show_cursor();
151 }
152
goto_xy(int x,int y)153 void goto_xy(int x, int y)
154 {
155 con.cursor.align = 1;
156 set_xy(x, y);
157 }
158
put_char(word c)159 void put_char(word c)
160 {
161 extern bool enable_screen;
162
163 if(!enable_screen)
164 return;
165 if(is_font_request(c))
166 {
167 con.cursor.attr.font = c;
168 }
169 else if(is_attr_request(c))
170 {
171 byte b = request_get_data(c);
172 word fore = attr_get_fore(b);
173 word back = attr_get_back(b);
174 if(fore == 1) fore = 2;
175 if(2 <= fore && fore <= 9)
176 con.cursor.attr.fore = fore;
177 if(back == 1) back = 9;
178 if(2 <= back && back <= 9)
179 con.cursor.attr.back = back;
180 }
181 else if(kind(c) == 0)
182 {
183 start_update();
184 switch(c)
185 {
186 case 0:
187 c = ' ';
188 /* Fall through ... */
189 default:
190 if(c >= 32)
191 {
192 console_row *r = &con.row[con.cursor.y];
193 console_cell *p = con.cursor.align
194 ? &r->fixed[con.cursor.x]
195 : &r->slack[con.cursor.x];
196 if(con.cursor.align)
197 r->fix = 1;
198 else if(con.cursor.x >= r->held)
199 r->held = con.cursor.x + 1;
200 r->flag = 1;
201 p->text = c;
202 p->attr = con.cursor.attr;
203 if(p->attr.font != FONT_FIXED
204 && p->attr.font != FONT_FIXED_REVS
205 && (con.cursor.align || hd_get_fixed()))
206 p->attr.font = p->attr.font == FONT_REVS ? FONT_FIXED_REVS : FONT_FIXED;
207 set_xy(con.cursor.x + 1, con.cursor.y);
208 }
209 break;
210 case '\r':
211 set_xy(0, con.cursor.y);
212 break;
213 case '\f':
214 /* Enable justification on current line */
215 con.row[con.cursor.y].just = 1;
216 con.row[con.cursor.y].flag = 1;
217 break;
218 case '\n':
219 if(con.cursor.align
220 || con.cursor.y + 1 < con.bottom)
221 {
222 set_xy(0, con.cursor.y + 1);
223 }
224 else if(con.top < con.bottom)
225 {
226 int i;
227 console_cell *s = con.row[con.top].slack;
228 /* Scroll the slack plane and clear its last line */
229 for(i = con.top; i < con.bottom - 1; ++i)
230 {
231 con.row[i].slack = con.row[i+1].slack;
232 con.row[i].flag = con.row[i+1].flag;
233 con.row[i].just = con.row[i+1].just;
234 con.row[i].held = con.row[i+1].held;
235 }
236 con.row[con.bottom - 1].slack = s;
237 con.row[con.bottom - 1].just = 0;
238 wipe_slack(0, con.bottom - 1, MAX_SLACK, con.bottom);
239 set_xy(0, con.bottom - 1);
240 /* Scroll the fixed plane (possibly more than before) unless we are reformatting */
241 if(!reformatting)
242 {
243 int fixed_bottom = con.bottom == con.shape.height ? MAX_HEIGHT : con.bottom;
244 if(con.top < fixed_bottom)
245 {
246 console_cell *f = con.row[con.top].fixed;
247 int b = con.row[con.top].fix;
248 for(i = con.top; i < fixed_bottom - 1; ++i)
249 {
250 con.row[i].fixed = con.row[i+1].fixed;
251 con.row[i].fix = con.row[i+1].fix;
252 }
253 con.row[fixed_bottom - 1].fixed = f;
254 con.row[fixed_bottom - 1].fix = b;
255 wipe_fixed(0, fixed_bottom - 1, MAX_FIXED, fixed_bottom);
256 }
257 scrollup();
258 }
259 }
260 else
261 {
262 set_xy(0, con.cursor.y);
263 erase_to_eoln();
264 }
265 break;
266 }
267 finish_update();
268 }
269 }
270
use_window(int window)271 void use_window(int window)
272 {
273 static int active_window = FULL_SCREEN;
274 extern word status_height;
275 if(window == STATUS_WINDOW && active_window != STATUS_WINDOW)
276 start_update();
277 if(window != STATUS_WINDOW && active_window == STATUS_WINDOW)
278 finish_update();
279 switch(window)
280 {
281 case TEXT_WINDOW:
282 con.top = status_height;
283 con.bottom = con.shape.height;
284 break;
285 case STATUS_WINDOW:
286 con.top = 0;
287 con.bottom = status_height;
288 break;
289 case FULL_SCREEN:
290 con.top = 0;
291 con.bottom = con.shape.height;
292 break;
293 }
294 active_window = window;
295 }
296
erase_to_eoln(void)297 void erase_to_eoln(void)
298 {
299 if(con.cursor.align)
300 wipe_fixed(con.cursor.x, con.cursor.y, MAX_FIXED, con.cursor.y + 1);
301 else
302 wipe_slack(con.cursor.x, con.cursor.y, MAX_SLACK, con.cursor.y + 1);
303 }
304
erase_window(word top_of_window,word bottom_of_window)305 void erase_window(word top_of_window, word bottom_of_window)
306 {
307 start_update();
308 wipe_fixed(0, top_of_window, MAX_FIXED, bottom_of_window);
309 wipe_slack(0, top_of_window, MAX_SLACK, bottom_of_window);
310 newlines_are_significant = 0;
311 finish_update();
312 }
313
swap_font_status(int * font)314 void swap_font_status(int *font)
315 {
316 int t = con.cursor.attr.font; con.cursor.attr.font = *font; *font = t;
317 }
318
319 static console_context saved_cursor[2];
320
save_attributes(int context)321 void save_attributes(int context)
322 {
323 saved_cursor[context] = con.cursor;
324 }
325
restore_attributes(int context)326 void restore_attributes(int context)
327 {
328 con.cursor = saved_cursor[context];
329 }
330
clip_attributes(void)331 void clip_attributes(void)
332 {
333 saved_cursor[0].x = con.cursor.x;
334 saved_cursor[0].y = con.cursor.y;
335 }
336
get_xy(int * x,int * y)337 void get_xy(int *x, int *y)
338 {
339 *x = con.cursor.x;
340 *y = con.cursor.y;
341 }
342
343 #ifdef OLD
is_a_space(const console_cell * c)344 int is_a_space(const console_cell *c)
345 {
346 return c->text == ' ' && c->attr.font != FONT_FIXED_REVS;
347 }
348 #endif
349
allocate_console(void)350 void allocate_console(void)
351 {
352 int i, lump = 8; /* Do this many lines at a time */
353 console_cell *s, *f;
354 for(i = 0; i < MAX_HEIGHT; ++i)
355 {
356 int r = i % lump;
357 if(r == 0)
358 {
359 s = alloc0(lump * MAX_SLACK, console_cell);
360 f = alloc0(lump * MAX_FIXED, console_cell);
361 }
362 con.row[i].held = MAX_SLACK;
363 con.row[i].slack = s + r * MAX_SLACK;
364 con.row[i].fixed = f + r * MAX_FIXED;
365 }
366 }
367
368