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