1 
2 /* Terminality - a portable terminal handling library
3  * Copyright (C) 1998-2002, Emil Mikulic.
4  * This is LGPL - look at COPYING.LIB
5  */
6 
7 /* Project:     Terminality/GUI
8  * File:	textarea.cpp
9  * Author:      Michal Safranek
10  * Description: Implements the textarea class
11  */
12 
13 #include <gui.h>
14 
15 const char textarea_rcsid[] =
16 "$Id: textarea.cpp,v 1.7 2002/07/26 01:39:40 darkmoon Exp $";
17 
18 
19 
20 /* Textbox elements */
element(const textarea_element el)21 void textarea::element(const textarea_element el)
22 {
23 	if(has_color()) {
24 		/* Pretty colors */
25 		switch(el){
26 		case TA_begin:
27 			if (focus)
28 				setcolor(SELECTED_FRAME,SELECTED_FRAME_BG);
29 			else
30 				setcolor(FRAME,FRAME_BG);
31 			printw("%c", BEG_CHR);
32 			break;
33 
34 		case TA_middle:
35 			if (focus)
36 				setcolor(SELECTED_SPACE,SELECTED_SPACE_BG);
37 			else
38 				setcolor(SPACE,SPACE_BG);
39 			printw("%c", MID_CHR);
40 			break;
41 
42 		case TA_char:
43 			if (focus)
44 				setcolor(SELECTED_TEXT,SELECTED_TEXT_BG);
45 			else
46 				setcolor(TEXT,TEXT_BG);
47 			break;
48 
49 		case TA_end:
50 			if (focus)
51 				setcolor(SELECTED_FRAME,SELECTED_FRAME_BG);
52 			else
53 				setcolor(FRAME,FRAME_BG);
54 			printw("%c", END_CHR);
55 			break;
56 		}
57 	} else {
58 		/* Plain */
59 		switch (el) {
60 		case TA_begin:
61 			if (focus)
62 				highvideo();
63 			else
64 				normvideo();
65 			printw("%c", BEG_CHR);
66 			break;
67 
68 		case TA_middle:
69 			lowvideo();
70 			printw("%c", MID_CHR);
71 			break;
72 
73 		case TA_char:
74 			if (focus)
75 				normvideo();
76 			else
77 				lowvideo();
78 			break;
79 
80 		case TA_end:
81 			if (focus)
82 				highvideo();
83 			else
84 			normvideo();
85 			printw("%c", END_CHR);
86 			break;
87 		}
88 	}
89 }
90 
91 
92 
93 #define TA_SETUP() FRAME = COLOR_TEXTAREA_FRAME; \
94 	SPACE = COLOR_TEXTAREA_SPACE; SELECTED_SPACE = COLOR_TEXTAREA_SSPACE; \
95 	TEXT_BG = COLOR_TEXTAREA_TEXTBG; SPACE_BG = COLOR_TEXTAREA_SPACEBG; \
96 	FRAME_BG = COLOR_TEXTAREA_FRAMEBG; TEXT = COLOR_TEXTAREA_TEXT; \
97 	SELECTED_TEXT_BG = COLOR_TEXTAREA_STEXTBG; \
98 	BEG_CHR = '|'; END_CHR = '|'; \
99 	SELECTED_SPACE_BG = COLOR_TEXTAREA_SSPACEBG; MID_CHR = '.'; \
100 	SELECTED_FRAME_BG = COLOR_TEXTAREA_SFRAMEBG; \
101 	SELECTED_TEXT = COLOR_TEXTAREA_STEXT; \
102 	SELECTED_FRAME = COLOR_TEXTAREA_SFRAME;
103 
104 
105 
106 // Construct textarea at <x,y> width <w> height <h>
textarea(const int xx,const int yy,const int w,const int h)107 textarea::textarea(const int xx, const int yy, const int w, const int h)
108 {
109 	// Encapsulate data
110 	x = xx;
111 	y = yy;
112 	width = w;
113 	height = h;
114 
115 	// Allocate buffer
116 	buf = (char*) xmalloc(width * height + 1);
117 	memset(buf, 0, width * height + 1);
118 	buf[0] = 0;
119 	posx = posy = count = 0;
120 	focus = false;
121 	charmap = NULL;
122 	type_id = Textarea;
123 	visible = true;
124 	fixed_colors = false;
125 	TA_SETUP();
126 }
127 
128 
129 
130 // Construct textarea at <x,y> width <w> height <h> with content <s>
textarea(const int xx,const int yy,const int w,const int h,const char * s)131 textarea::textarea(const int xx, const int yy, const int w, const int h,
132 	const char *s)
133 {
134 	// Encapsulate data
135 	x = xx;
136 	y = yy;
137 	width = w;
138 	height = h;
139 
140 	// Allocate buffer
141 	buf = (char*) xmalloc(width * height + 1);
142 	memset(buf, 0, width * height + 1);
143 
144 	// Copy buffer
145 	strncpy(buf, s, width * height);
146 	buf[width*height] = 0;
147 	count = strlen(s)>(unsigned) width * height?width * height:strlen(s);
148 	posx = posy = 0;
149 	focus = false;
150 	charmap = NULL;
151 	type_id = Textarea;
152 	visible = true;
153 	fixed_colors = false;
154 	TA_SETUP();
155 }
156 
157 
158 
159 // Destroy textarea
~textarea()160 textarea::~textarea()
161 {
162 	// Deallocate buffer!
163 	xfree(buf);
164 }
165 
166 
167 
168 // Draw textarea in its current state
draw(void)169 void textarea::draw(void)
170 {
171 	char *temp;
172 	int h;
173 
174 	if (!visible) return;
175 	for(h = 0; h < height; h++) {
176 		// Draw empty box
177 		gotoxy(x, y + h);
178 		element(TA_begin);
179 		for (int i=0; i<width; i++)
180 			element(TA_middle);
181 		element(TA_end);
182 
183 		// Go to beginning of box
184 		gotoxy (x + 1, y + h);
185 
186 		// Write out current string
187 		temp = (char*) xmalloc(width + 1);
188 		memcpy(temp, buf + width * h, width);
189 		temp[width] = 0;
190 		element(TA_char);
191 		printw(temp);
192 		xfree(temp);
193 	}
194 }
195 
196 
197 
198 /* Non-blocking get function
199  * Returns: 0 - enter, 27 - ESC, -1 - up, 1 - down
200  */
201 
202 #define killch(which)	for (tmp=which; tmp<count; tmp++) \
203 				buf[tmp-1] = buf[tmp]; \
204 				buf[count-1]=0;
205 
getnb(void)206 int textarea::getnb(void)
207 {
208 	key c;
209 	int result = 101;
210 	int tmp;
211 	cursor cs = get_cursor();
212 	bool old_vis = visible;
213 
214 	visible = true;
215 	set_cursor(line);
216 	focus = true;
217 	draw();
218 
219 	/* Get the input */
220 	do {
221 		// places, people!!
222 		gotoxy (x + posx + 1, y + posy);
223 
224 		// Update screen
225 		update();
226 
227 		/* Get letter */
228 		c = readkey();
229 		c = keyhandler(c, Textarea);
230 		c = handle_key(c, Textarea, this);
231 
232 		/* Handle input */
233 		switch (c) {
234 		// filter
235 		case KEY_ENTER: result = 0; break;
236 		case KEY_ESC: result = 27; break;
237 		case KEY_TAB: result = 1; break;
238 		case KEY_NOTHING: break;
239 		case KEY_PGUP:
240 			posy = 0;
241 			break;
242 
243 		case KEY_PGDOWN:
244 			posy = (count-posx) / width;
245 			if (posy == height) posy--;
246 			break;
247 
248 		case KEY_DOWN:
249 			if (posy < height - 1) {
250 				if((posy+1)*width+posx < count){
251 					posy++;
252 				} else {
253 					if ((posy+1)*width < count) {
254 						posy++;
255 						posx = count % width;
256 					} else {
257 						result = 1;
258 					}
259 				}
260 			} else {
261 				result = 1;
262 				break;
263 			}
264 			break;
265 
266 		case KEY_UP:
267 			if (posy > 0) {
268 				posy--;
269 			} else {
270 				result = -1;
271 				break;
272 			}
273 			break;
274 		case KEY_BACKSPACE:
275 #if !(__DJGPP__) && !(_WIN32)
276 		case 0x08: /* alt. backspace, thanks kromJx! */
277 #endif
278 			/* Backspace - move back a letter if we can */
279 			if (posx+posy) {
280 				killch(posy * width + posx);
281 				count--;
282 				if (posx) {
283 					posx--;
284 				} else {
285 					posy--;
286 					posx = width - 1;
287 				}
288 				draw();
289 				if(onchange) onchange(Textarea, this);
290 			} else {
291 				beep();
292 			}
293 			break;
294 
295 		case KEY_DEL:
296 			/* Delete - delete letter in front (if we can) */
297 			if (posy * width + posx < count) {
298 				killch(posy * width + posx + 1);
299 				count--;
300 				draw();
301 				if(onchange) onchange(Textarea, this);
302 			} else {
303 				beep();
304 			}
305 			break;
306 
307 		case KEY_RIGHT:
308 			if (posy * width + posx == count) {
309 				beep();
310 			} else {
311 				if (posx == width - 1) {
312 					if (posy+1 < height) {
313 						posy++;
314 						posx = 0;
315 					} else {
316 						beep();
317 					}
318 				} else {
319 					posx++;
320 				}
321 			}
322 			break;
323 
324 		case KEY_LEFT:
325 			if (!posx) {
326 				if (!posy) {
327 					beep();
328 				} else {
329 					posy--;
330 					posx = width - 1;
331 				}
332 			} else {
333 				posx--;
334 			}
335 			break;
336 
337 		case KEY_HOME:
338 			posx = 0;
339 			break;
340 
341 		case KEY_END:
342 			if ((posy+1)*width > count) {
343 				posx = count % width;
344 			} else {
345 				posx = width - 1;
346 			}
347 			break;
348 
349 		default:
350 			/* Is it acceptable? */
351 			if (32 > c || c > 255) {
352 				beep();
353 				break;
354 			}
355 
356 			if (charmap) {
357 				if (!strrchr(charmap, c)) {
358 					beep();
359 					break;
360 				}
361 			}
362 			if (count == width * height) {
363 				beep();
364 			} else {
365 				for (tmp = count; tmp > posx+width*posy - 1;
366 					tmp--) {
367 					buf[tmp] = buf[tmp-1];
368 				}
369 				buf[posx + width * posy] = c;
370 				count++;
371 				if (posx == width - 1) {
372 					if (count != width * height) {
373 						posy++;
374 						posx = 0;
375 					}
376 				} else {
377 					posx++;
378 				}
379 				draw();
380 				if(onchange) onchange(Textarea, this);
381 			}
382 			break;
383 		}
384 	} while (result == 101);
385 	visible = old_vis;
386 
387 	/* Mark end of string */
388 	buf[count] = 0;
389 
390 	set_cursor(cs);
391 	focus = false;
392 
393 	return result;
394 }
395 
396 
397 
398 // Blocking get (cannot be aborted)
get(void)399 char *textarea::get(void)
400 {
401 	while (1) {
402 		switch (getnb()) {
403 		case 27:
404 			return NULL;
405 		case 0:
406 			return buf;
407 		}
408 	}
409 }
410 
411 
412 
413 // Sets ta's content
set_buf(char * buffer)414 int textarea::set_buf(char *buffer)
415 {
416 	int i;
417 	memset(buf, 0, width * height + 1);
418 	for (i = 0; i < width*height && (unsigned) i < strlen(buffer); i++) {
419 		buf[i] = buffer[i];
420 	}
421 	buf[++i] = 0;
422 	count = i-1;
423 	posx = posy = 0;
424 	if(onchange) onchange(Textarea, this);
425 
426 	return 1;
427 }
428 
429 
430 
431 // Change scheme
change_scheme(void)432 void textarea::change_scheme(void)
433 {
434 	if (fixed_colors) return;
435 	SELECTED_FRAME = COLOR_TEXTAREA_SFRAME; FRAME = COLOR_TEXTAREA_FRAME;
436 	SPACE = COLOR_TEXTAREA_SPACE; SELECTED_SPACE = COLOR_TEXTAREA_SSPACE;
437 	TEXT_BG = COLOR_TEXTAREA_TEXTBG; SPACE_BG = COLOR_TEXTAREA_SPACEBG;
438 	FRAME_BG = COLOR_TEXTAREA_FRAMEBG; TEXT = COLOR_TEXTAREA_TEXT;
439 	SELECTED_SPACE_BG = COLOR_TEXTAREA_SSPACEBG;
440 	SELECTED_FRAME_BG = COLOR_TEXTAREA_SFRAMEBG;
441 	SELECTED_TEXT_BG = COLOR_TEXTAREA_STEXTBG;
442 	SELECTED_TEXT = COLOR_TEXTAREA_STEXT;
443 }
444 
445