blob: cd9bbfe82c67c6de42b256039600a2948b603cd8 [file] [log] [blame]
adamdunkelsb9614dc2004-08-09 20:33:51 +00001#include "ctk.h"
2#include "ctk-draw.h"
3
4#include "contiki.h"
5#include "loader.h"
6#include "ctk-term.h"
7#include "ctk-term-int.h"
8#include "ctk-term-out.h"
9#include "ctk-term-conf.h"
10#include "libconio.h"
11
12#define PRINTF(x)
13
14#define reverse(x)
15
16/*-----------------------------------------------------------------------------------*/
17/*
18 * #defines and enums
19 */
20/*-----------------------------------------------------------------------------------*/
21#define CH_ULCORNER '+' //0x00
22#define CH_TITLEBAR '-' //0x01
23#define CH_URCORNER '+' //0x02
24#define CH_WINDOWRBORDER '|' //0x03
25#define CH_LRCORNER '+' //0x04
26#define CH_WINDOWLOWERBORDER '-' //0x05
27#define CH_LLCORNER '+' //0x06
28#define CH_WINDOWLBORDER '|' //0x07
29
30#define CH_DIALOG_ULCORNER '+' //0x12
31#define CH_DIALOGUPPERBORDER '-' //0x09
32#define CH_DIALOG_URCORNER '+' //0x0a
33#define CH_DIALOGRBORDER '|' //0x0b
34#define CH_DIALOG_LRCORNER '+' //0x0c
35#define CH_DIALOGLOWERBORDER '-' //0x0d
36#define CH_DIALOG_LLCORNER '+' //0x0e
37#define CH_DIALOGLBORDER '|' //0x0f
38
39#define CH_BUTTONLEFT '[' //0x10
40#define CH_BUTTONRIGHT ']' //0x11
41
42#define CH_SEPARATOR '=' //0x13
43
44#ifdef CTK_TERM_CONF_MAX_CLIENTS
45#define CTK_TERM_NUMCONNS CTK_TERM_CONF_MAX_CLIENTS
46#else
47#define CTK_TERM_NUMCONNS 1
48#endif
49
50unsigned char ctk_draw_windowborder_height = 1;
51unsigned char ctk_draw_windowborder_width = 1;
52unsigned char ctk_draw_windowtitle_height = 1;
53
54
55/* Term context states */
56enum {
57 TERM_DEALLOCATED,
58 TERM_ALLOCATED
59};
60
61/*-----------------------------------------------------------------------------------*/
62/*
63 * Local variables
64 */
65/*-----------------------------------------------------------------------------------*/
66
67static unsigned char sizex, sizey;
68static struct ctk_term_state conns[CTK_TERM_NUMCONNS];
69
70/*-----------------------------------------------------------------------------------*/
71/*
72 * Unconditionally add an update
73 */
74/*-----------------------------------------------------------------------------------*/
75void ctk_term_update_add(struct ctk_term_state *ts, struct ctk_term_update *a)
76{
77 /* XXX: test both head and tail placement!*/
78 a->next = ts->updates_pending;
79 ts->updates_pending = a;
80}
81
82/*-----------------------------------------------------------------------------------*/
83/*
84 * Allocate an update from the update pool
85 */
86/*-----------------------------------------------------------------------------------*/
87struct ctk_term_update *
88ctk_term_update_alloc(struct ctk_term_state *vs)
89{
90 struct ctk_term_update *a;
91
92 a = vs->updates_free;
93 if(a == NULL) {
94 return NULL;
95 }
96 vs->updates_free = a->next;
97 a->next = NULL;
98 return a;
99}
100
101/*-----------------------------------------------------------------------------------*/
102/*
103 * Return an update to the pool
104 */
105/*-----------------------------------------------------------------------------------*/
106void
107ctk_term_update_free(struct ctk_term_state *ts, struct ctk_term_update *a)
108{
109 a->next = ts->updates_free;
110 ts->updates_free = a;
111}
112
113/*-----------------------------------------------------------------------------------*/
114/*
115 * Fetch update from the update list
116 */
117/*-----------------------------------------------------------------------------------*/
118struct ctk_term_update *
119ctk_term_update_dequeue(struct ctk_term_state *ts)
120{
121 struct ctk_term_update *a;
122
123 a = ts->updates_pending;
124 if(a == NULL) {
125 return a;
126 }
127 ts->updates_pending = a->next;
128 a->next = NULL;
129 return a;
130}
131
132/*-----------------------------------------------------------------------------------*/
133/*
134 * Remove an update from the update list
135 */
136/*-----------------------------------------------------------------------------------*/
137void
138ctk_term_update_remove(struct ctk_term_state *ts, struct ctk_term_update *a)
139{
140 struct ctk_term_update *b, *c;
141
142 if(a == ts->updates_pending) {
143 ts->updates_pending = a->next;
144 } else {
145 b = ts->updates_pending;
146 for(c = ts->updates_pending; c != a; b = c, c = c->next);
147
148 b->next = a->next;
149 }
150}
151/*-----------------------------------------------------------------------------------*/
152/*
153 * Add an area update for a specific connection. Overlapping updates are merged
154 */
155/*-----------------------------------------------------------------------------------*/
156static void
157update_area_connection(struct ctk_term_state *ts,
158 unsigned char x, unsigned char y, unsigned char w, unsigned char h)
159{
160 unsigned char x2, y2, ax2, ay2;
161 struct ctk_term_update *a;
162
163 PRINTF(("update_area_connection: should update (%d:%d) (%d:%d)\n",
164 x, y, w, h));
165
166 /* First check if we already have a full update queued. If so, there
167 is no need to put this update on the list. If there is a full
168 update, it is always the first one on the list, so there is no
169 need to go step the list in search for it. */
170
171 if(ts->updates_pending != NULL &&
172 ts->updates_pending->type == UPDATE_FULL) {
173 PRINTF(("Update_area_connecion: full update already queued...\n"));
174 return;
175 }
176
177again:
178
179 /* Check that we don't update the same area twice by going through
180 the list and search for an update with the same coordinates. */
181 for(a = ts->updates_pending; a != NULL; a = a->next) {
182 if(a->x == x && a->y == y &&
183 a->w == w && a->h == h) {
184 PRINTF(("Update_area_connecion: found equal area\n"));
185 return;
186 }
187 }
188
189 /* Next we check if this update covers an existing update. If so, we
190 remove the old update, expand this update so that it covers both
191 areas to be updated and run through the process again. */
192 for(a = ts->updates_pending; a != NULL; a = a->next) {
193 x2 = x + w;
194 y2 = y + h;
195
196 ax2 = a->x + a->w;
197 ay2 = a->y + a->h;
198
199 /* Test if updates overlaps */
200 if(((x < ax2) && (a->x < x2)) &&
201 ((y < ay2) && (a->y < y2))) {
202
203 /* Remove the old update from the list. */
204 ctk_term_update_remove(ts, a);
205
206 /* Put it on the free list. */
207 ctk_term_update_free(ts, a);
208
209 PRINTF(("update_area_connection: inside (%d:%d, %d:%d)\n",
210 a->x, a->y, ax2, ay2));
211
212 /* Find the area that covers both updates. */
213#define MIN(a,b) ((a) < (b)? (a): (b))
214#define MAX(a,b) ((a) > (b)? (a): (b))
215 x = MIN(a->x, x);
216 y = MIN(a->y, y);
217 ax2 = MAX(ax2, x2);
218 ay2 = MAX(ay2, y2);
219 w = ax2 - x;
220 h = ay2 - y;
221
222 /* This should really be done by a recursive call to this
223 function: update_area_connection(vs, x, y, w, h); but because
224 some compilers might not be able to optimize away the
225 recursive call, we do it using a goto instead. */
226 PRINTF(("Update_area_connecion: trying larger area (%d:%d) (%d:%d)\n", x, y, w, h));
227 goto again;
228 }
229 }
230
231 /* Allocate an update object by pulling it off the free list. If
232 there are no free objects, we go for a full update instead. */
233
234 a = ctk_term_update_alloc(ts);
235 if(a == NULL) {
236 PRINTF(("Update_area_connecion: no free updates, doing full\n"));
237 /* Put all pending updates, except for one, on the free list. Use
238 the remaining update as a full update. */
239 while(ts->updates_pending != NULL) {
240 a = ts->updates_pending;
241 ctk_term_update_remove(ts, a);
242 ctk_term_update_free(ts, a);
243 }
244
245 a = ctk_term_update_alloc(ts);
246 a->type = UPDATE_FULL;
247 ctk_term_update_add(ts, a);
248
249
250 } else {
251
252 PRINTF(("Update_area_connecion: allocated update for (%d:%d) (%d:%d)\n", x, y, w, h));
253 /* Else, we put the update object at the end of the pending
254 list. */
255 a->type = UPDATE_PARTS;
256 a->x = x;
257 a->y = y;
258 a->w = w;
259 a->h = h;
260 ctk_term_update_add(ts, a);
261 }
262}
263
264/*-----------------------------------------------------------------------------------*/
265/*
266 * Update an area for all connections.
267 */
268/*-----------------------------------------------------------------------------------*/
269static void
270update_area(unsigned char x, unsigned char y, unsigned char w, unsigned char h)
271{
272 unsigned char i;
273
274 if(h == 0 || w == 0) {
275 return;
276 }
277
278 if ((x+w) > sizex) {
279 w = sizex - x;
280 }
281
282 if ((y+h) > sizey) {
283 h = sizey - y;
284 }
285
286 /* Update for all active terminal connections. */
287 for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {
288 if(conns[i].state != TERM_DEALLOCATED) {
289 update_area_connection(&conns[i],x, y, w, h);
290 }
291 }
292
293}
294/*-----------------------------------------------------------------------------------*/
295/**
296 * Request a full update for a specific connections. Usefull when a new client is
297 * connected through telnet for example.
298 *
299 * \param ts Terminal connection state
300 */
301/*-----------------------------------------------------------------------------------*/
302void ctk_term_redraw(struct ctk_term_state *ts)
303{
304 update_area_connection(ts,0,0,ts->width, ts->height);
305}
306
307/*-----------------------------------------------------------------------------------*/
308/*
309 * Initialize a terminal state structure
310 */
311/*-----------------------------------------------------------------------------------*/
312static void
313init_state(struct ctk_term_state *ts)
314{
315 unsigned char i;
316
317 ts->width = sizex;
318 ts->height = sizey;
319 ts->x = ts->y = ts->x1 = ts->y1 = ts->x2 = ts->y2 = 0;
320 ts->c1 = ts->c2 = 0;
321 ts->w = sizex;
322 ts->h = sizey;
323 ts->state = TERM_ALLOCATED;
324 ts->inputstate = ANS_IDLE;
325
326 /* Initialize the linked list of updates. */
327 for(i = 0; i < CTK_TERM_MAX_UPDATES - 1; ++i) {
328 ts->updates_pool[i].next = &(ts->updates_pool[i + 1]);
329 }
330 ts->updates_pool[CTK_TERM_MAX_UPDATES-1].next = NULL;
331
332 ts->updates_free = &ts->updates_pool[0];
333 ts->updates_pending = ts->updates_current = NULL;
334}
335
336/*-----------------------------------------------------------------------------------*/
337/**
338 * Allocate a new state structure. Returns NULL if none available
339 */
340/*-----------------------------------------------------------------------------------*/
341struct ctk_term_state *
342ctk_term_alloc_state(void)
343{
344 unsigned char i;
345 for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {
346 if(conns[i].state == TERM_DEALLOCATED) {
347 init_state(&conns[i]);
348 return &conns[i];
349 }
350 }
351 return NULL;
352}
353
354/*-----------------------------------------------------------------------------------*/
355/**
356 * Free a state structure.
357 *
358 * \param ts Terminal connection state
359 */
360/*-----------------------------------------------------------------------------------*/
361void
362ctk_term_dealloc_state(struct ctk_term_state *s)
363{
364 s->state = TERM_DEALLOCATED;
365}
366/*-----------------------------------------------------------------------------------*/
367static char tmp[40];
368static void
369cputsn(char *str, unsigned char len)
370{
371 strncpy(tmp, str, len);
372 tmp[len] = 0;
373 cputs(tmp);
374}
375
376/*-----------------------------------------------------------------------------------*/
377/**
378 * Initialize the terminal ctk-draw module. Called by the CTK module.
379 *
380 */
381/*-----------------------------------------------------------------------------------*/
382void
383ctk_draw_init(void)
384{
385 int i;
386 bgcolor(TERM_BACKGROUNDCOLOR);
387 screensize(&sizex, &sizey);
388 ctk_draw_clear(0, sizey);
389 ctk_term_input_init();
390 for(i = 0; i < CTK_TERM_NUMCONNS; ++i) {
391 conns[i].state = TERM_DEALLOCATED;
392 }
393}
394
395/*-----------------------------------------------------------------------------------*/
396static void
397draw_widget(struct ctk_widget *w,
398 unsigned char x, unsigned char y,
399 unsigned char clipx,
400 unsigned char clipy,
401 unsigned char clipy1, unsigned char clipy2,
402 unsigned char focus)
403{
404 unsigned char xpos, ypos, xscroll;
405 unsigned char i, j;
406 char c, *text;
407 unsigned char len;
408
409 xpos = x + w->x;
410 ypos = y + w->y;
411
412 switch(w->type) {
413 case CTK_WIDGET_SEPARATOR:
414 textcolor((unsigned char)(TERM_SEPARATORCOLOR + focus));
415 if(ypos >= clipy1 && ypos < clipy2) {
416 gotoxy(xpos, ypos);
417 for(i = 0; i < w->w; ++i) {
418 cputc(CH_SEPARATOR);
419 }
420 }
421 break;
422 case CTK_WIDGET_LABEL:
423 textcolor((unsigned char)(TERM_LABELCOLOR + focus));
424 text = w->widget.label.text;
425 for(i = 0; i < w->h; ++i) {
426 if(ypos >= clipy1 && ypos < clipy2) {
427 gotoxy(xpos, ypos);
428 cputsn(text, w->w);
429 if(w->w - (wherex() - xpos) > 0) {
430 cclear((unsigned char)(w->w - (wherex() - xpos)));
431 }
432 }
433 ++ypos;
434 text += w->w;
435 }
436 break;
437 case CTK_WIDGET_BUTTON:
438 textcolor((unsigned char)(TERM_BUTTONCOLOR + focus));
439 if(ypos >= clipy1 && ypos < clipy2) {
440 if(focus & CTK_FOCUS_WIDGET) {
441 revers(1);
442 } else {
443 revers(0);
444 }
445 cputcxy(xpos, ypos, CH_BUTTONLEFT);
446 cputsn(w->widget.button.text, w->w);
447 cputc(CH_BUTTONRIGHT);
448 revers(0);
449 }
450 break;
451 case CTK_WIDGET_HYPERLINK:
452 textcolor((unsigned char)(TERM_HYPERLINKCOLOR + focus));
453 if(ypos >= clipy1 && ypos < clipy2) {
454 if(focus & CTK_FOCUS_WIDGET) {
455 revers(0);
456 } else {
457 revers(1);
458 }
459 gotoxy(xpos, ypos);
460 cputsn(w->widget.button.text, w->w);
461 revers(0);
462 }
463 break;
464 case CTK_WIDGET_TEXTENTRY:
465 textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + focus));
466 text = w->widget.textentry.text;
adamdunkelsb9614dc2004-08-09 20:33:51 +0000467 xscroll = 0;
468 if(w->widget.textentry.xpos >= w->w - 1) {
469 xscroll = w->widget.textentry.xpos - w->w + 1;
470 }
471 for(j = 0; j < w->h; ++j) {
472 if(ypos >= clipy1 && ypos < clipy2) {
473 if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
474 w->widget.textentry.ypos == j) {
475 revers(0);
476 cputcxy(xpos, ypos, '>');
oliverschmidte43cb182006-05-28 20:38:19 +0000477 c = 1;
adamdunkelsb9614dc2004-08-09 20:33:51 +0000478 for(i = 0; i < w->w; ++i) {
oliverschmidte43cb182006-05-28 20:38:19 +0000479 if(c != 0) {
480 c = text[i + xscroll];
481 }
adamdunkelsb9614dc2004-08-09 20:33:51 +0000482 if(i == w->widget.textentry.xpos - xscroll) {
483 textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + (focus ^ 0x01)));
484 revers(1);
485 } else {
486 revers(0);
487 }
488 if(c == 0) {
489 cputc(' ');
490 } else {
491 cputc(c);
492 }
493 revers(0);
494 textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + focus));
495 }
496 cputc('<');
497 } else {
oliverschmidtacdf6e92005-05-04 22:04:35 +0000498 if(focus & CTK_FOCUS_WIDGET && j == w->widget.textentry.ypos) {
499 revers(1);
500 } else {
501 revers(0);
502 }
adamdunkelsb9614dc2004-08-09 20:33:51 +0000503 cvlinexy(xpos, ypos, 1);
504 gotoxy((unsigned char)(xpos + 1), ypos);
505 cputsn(text, w->w);
506 i = wherex();
507 if(i - xpos - 1 < w->w) {
508 cclear((unsigned char)(w->w - (i - xpos) + 1));
509 }
510 cvline(1);
511 }
512 }
513 ++ypos;
oliverschmidtcd6c30b2005-05-05 20:54:16 +0000514 text += w->widget.textentry.len + 1;
adamdunkelsb9614dc2004-08-09 20:33:51 +0000515 }
516 revers(0);
517 break;
518 case CTK_WIDGET_ICON:
519 if(ypos >= clipy1 && ypos < clipy2) {
520 textcolor((unsigned char)(TERM_ICONCOLOR + focus));
521 if(focus & 1) {
522 revers(1);
523 } else {
524 revers(0);
525 }
526
527 x = xpos;
528 len = strlen(w->widget.icon.title);
529 if(x + len >= sizex) {
530 x = sizex - len;
531 }
532
533 gotoxy(x, (unsigned char)(ypos + 3));
534 if(ypos >= clipy1 && ypos < clipy2) {
535 cputs(w->widget.icon.title);
536 }
537
538 gotoxy(xpos, ypos);
539
540 if (w->widget.icon.textmap != NULL) {
541 for(i = 0; i < 3; ++i) {
542
543 if(ypos >= clipy1 && ypos < clipy2) {
544 gotoxy(xpos,ypos);
545 cputc(w->widget.icon.textmap[0 + 3 * i]);
546 cputc(w->widget.icon.textmap[1 + 3 * i]);
547 cputc(w->widget.icon.textmap[2 + 3 * i]);
548 }
549 ++ypos;
550 }
551 }
552 x = xpos;
553 revers(0);
554 }
555 break;
556
557 default:
558 break;
559 }
560}
561
562/*-----------------------------------------------------------------------------------*/
563/**
564 * Draw a widget on the VNC screen. Called by the CTK module.
565 *
566 * \param w The widget to be drawn.
567 * \param focus The focus of the widget.
568 * \param clipy1 The lower y coordinate bound.
569 * \param clipy2 The upper y coordinate bound.
570 */
571/*-----------------------------------------------------------------------------------*/
572void
573ctk_draw_widget(struct ctk_widget *w,
574 unsigned char focus,
575 unsigned char clipy1,
576 unsigned char clipy2)
577{
578 struct ctk_window *win = w->window;
579 struct ctk_icon *icon;
580 unsigned char posx, posy, x, len;
581
582 posx = win->x + 1;
583 posy = win->y + 2;
584
585 if(w == win->focused) {
586 focus |= CTK_FOCUS_WIDGET;
587 }
588
589 draw_widget(w, posx, posy,
590 (unsigned char)(posx + win->w),
591 (unsigned char)(posy + win->h),
592 clipy1, clipy2,
593 focus);
594
595 if(w->type != CTK_WIDGET_ICON) {
596 update_area((unsigned char)(posx + w->x),
597 (unsigned char)(posy + w->y),
598 (unsigned char)(w->w + 2),
599 w->h);
600 } else {
601 icon = (struct ctk_icon *)w;
602
603 len = strlen(icon->title);
604 x = posx + w->x;
605 if(x + len >= sizex) {
606 x = sizex - len;
607 }
608
609 update_area(x,
610 (unsigned char)(posy + w->y),
611 (unsigned char)(len > 4? len: 4),
612 w->h);
613 }
614
615#ifdef CTK_CONIO_CONF_UPDATE
616 CTK_CONIO_CONF_UPDATE();
617#endif /* CTK_CONIO_CONF_UPDATE */
618}
619
620/*-----------------------------------------------------------------------------------*/
621/**
622 * Clear a window on the terminal screen. Called by the CTK module.
623 *
624 * \param window The window to be cleared.
625 * \param focus The focus of the window.
626 * \param clipy1 The lower y coordinate bound.
627 * \param clipy2 The upper y coordinate bound.
628 */
629/*-----------------------------------------------------------------------------------*/
630void
631ctk_draw_clear_window(struct ctk_window *window,
632 unsigned char focus,
633 unsigned char clipy1,
634 unsigned char clipy2)
635{
636 unsigned char i;
637 unsigned char h;
638
639 textcolor((unsigned char)(TERM_WINDOWCOLOR + focus));
640
641 h = window->y + 2 + window->h;
642 /* Clear window contents. */
643 for(i = window->y + 2; i < h; ++i) {
644 if(i >= clipy1 && i < clipy2) {
645 cclearxy((unsigned char)(window->x + 1), i, window->w);
646 }
647 }
648
649 update_area((unsigned char)(window->x + 1),
650 (unsigned char)(window->y + 2),
651 window->w, window->h);
652}
653/*-----------------------------------------------------------------------------------*/
654static void
655draw_window_contents(struct ctk_window *window, unsigned char focus,
656 unsigned char clipy1, unsigned char clipy2,
657 unsigned char x1, unsigned char x2,
658 unsigned char y1, unsigned char y2)
659{
660 struct ctk_widget *w;
661 unsigned char wfocus;
662
663 /* Draw inactive widgets. */
664 for(w = window->inactive; w != NULL; w = w->next) {
665 draw_widget(w, x1, y1, x2, y2,
666 clipy1, clipy2,
667 focus);
668 }
669
670 /* Draw active widgets. */
671 for(w = window->active; w != NULL; w = w->next) {
672 wfocus = focus;
673 if(w == window->focused) {
674 wfocus |= CTK_FOCUS_WIDGET;
675 }
676
677 draw_widget(w, x1, y1, x2, y2,
678 clipy1, clipy2,
679 wfocus);
680 }
681
682#ifdef CTK_CONIO_CONF_UPDATE
683 CTK_CONIO_CONF_UPDATE();
684#endif /* CTK_CONIO_CONF_UPDATE */
685
686}
687
688/*-----------------------------------------------------------------------------------*/
689/**
690 * Draw a window on the terminal screen. Called by the CTK module.
691 *
692 * \param window The window to be drawn.
693 * \param focus The focus of the window.
694 * \param clipy1 The lower y coordinate bound.
695 * \param clipy2 The upper y coordinate bound.
oliverschmidtd1040582005-03-15 16:07:35 +0000696 * \param draw_borders The flag for border drawing.
adamdunkelsb9614dc2004-08-09 20:33:51 +0000697 */
698/*-----------------------------------------------------------------------------------*/
699void
700ctk_draw_window(struct ctk_window *window, unsigned char focus,
oliverschmidtadf27db2005-03-15 15:51:17 +0000701 unsigned char clipy1, unsigned char clipy2,
702 unsigned char draw_borders)
adamdunkelsb9614dc2004-08-09 20:33:51 +0000703{
704 unsigned char x, y;
705 unsigned char h;
706 unsigned char x1, y1, x2, y2;
707 unsigned char i;
708
709
710 if(window->y + 1 >= clipy2) {
711 return;
712 }
713
714 x = window->x;
715 y = window->y + 1;
adamdunkelsb9614dc2004-08-09 20:33:51 +0000716 x1 = x + 1;
717 y1 = y + 1;
718 x2 = x1 + window->w;
719 y2 = y1 + window->h;
720
oliverschmidtadf27db2005-03-15 15:51:17 +0000721 if(draw_borders) {
adamdunkelsb9614dc2004-08-09 20:33:51 +0000722
oliverschmidtadf27db2005-03-15 15:51:17 +0000723 /* Draw window frame. */
724 textcolor((unsigned char)(TERM_WINDOWCOLOR + focus));
adamdunkelsb9614dc2004-08-09 20:33:51 +0000725
oliverschmidtadf27db2005-03-15 15:51:17 +0000726 if(y >= clipy1) {
727 cputcxy(x, y, CH_ULCORNER);
oliverschmidt7b9025d2005-03-18 01:08:35 +0000728 for(i = wherex() + window->titlelen + CTK_CONF_WINDOWMOVE * 2; i < x2; ++i) {
oliverschmidtadf27db2005-03-15 15:51:17 +0000729 cputcxy(i, y, CH_TITLEBAR);
730 }
731 cputcxy(x2, y, CH_URCORNER);
adamdunkelsb9614dc2004-08-09 20:33:51 +0000732 }
oliverschmidtadf27db2005-03-15 15:51:17 +0000733
734 h = window->h;
735
736 if(clipy1 > y1) {
737 if(clipy1 - y1 < h) {
738 h = clipy1 - y1;
739 y1 = clipy1;
740 } else {
741 h = 0;
742 }
743 }
744
745 if(clipy2 < y1 + h) {
746 if(y1 >= clipy2) {
747 h = 0;
748 } else {
749 h = clipy2 - y1;
750 }
751 }
752
753 for(i = y1; i < y1 + h; ++i) {
754 cputcxy(x, i, CH_WINDOWLBORDER);
755 cputcxy(x2, i, CH_WINDOWRBORDER);
756 }
757
758 if(y2 >= clipy1 &&
759 y2 < clipy2) {
760 cputcxy(x, y2, CH_LLCORNER);
761 for(i = x1; i < x2; ++i) {
762 cputcxy(i, y2, CH_WINDOWLOWERBORDER);
763 }
764 cputcxy(x2, y2, CH_LRCORNER);
765 }
adamdunkelsb9614dc2004-08-09 20:33:51 +0000766 }
767
oliverschmidte99386b2004-12-27 22:03:04 +0000768 draw_window_contents(window, focus, clipy1, clipy2,
adamdunkelsb9614dc2004-08-09 20:33:51 +0000769 x1, x2, (unsigned char)(y + 1), y2);
770
771 update_area(window->x, window->y,
772 (unsigned char)(window->w + 2),
773 (unsigned char)(window->h + 2));
774}
775/*-----------------------------------------------------------------------------------*/
776/**
777 * Draw a dialog on the terminal screen. Called by the CTK module.
778 *
779 * \param dialog The dialog to be drawn.
780 */
781/*-----------------------------------------------------------------------------------*/
782void
783ctk_draw_dialog(struct ctk_window *dialog)
784{
785 unsigned char x, y;
786 unsigned char i;
787 unsigned char x1, y1, x2, y2;
788
789 textcolor(TERM_WINDOWCOLOR + CTK_FOCUS_DIALOG);
790
791 x = dialog->x;
792 y = dialog->y + 1;
793
794
795 x1 = x + 1;
796 y1 = y + 1;
797 x2 = x1 + dialog->w;
798 y2 = y1 + dialog->h;
799
800
801 /* Draw dialog frame. */
802
803 for(i = y1; i < y1 + dialog->h; ++i) {
804 cputcxy(x, i, CH_DIALOGLBORDER);
805 cputcxy(x2, i, CH_DIALOGRBORDER);
806 }
807
808 for(i = x1; i < x2; ++i) {
809 cputcxy(i, y, CH_DIALOGUPPERBORDER);
810 cputcxy(i, y2, CH_DIALOGLOWERBORDER);
811 }
812
813 cputcxy(x, y, CH_DIALOG_ULCORNER);
814 cputcxy(x, y2, CH_DIALOG_LLCORNER);
815 cputcxy(x2, y, CH_DIALOG_URCORNER);
816 cputcxy(x2, y2, CH_DIALOG_LRCORNER);
817
818
819 /* Clear dialog contents. */
820 for(i = y1; i < y2; ++i) {
821 cclearxy(x1, i, dialog->w);
822 }
823
824 draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
825 x1, x2, y1, y2);
826
827 update_area(dialog->x, dialog->y,
828 (unsigned char)(dialog->w + 4),
829 (unsigned char)(dialog->h + 4));
830}
831/*-----------------------------------------------------------------------------------*/
832/**
833 * Clear parts of the terminal desktop. Called by the CTK module.
834 *
835 * \param y1 The lower y coordinate bound.
836 * \param y2 The upped y coordinate bound.
837 */
838/*-----------------------------------------------------------------------------------*/
839void
840ctk_draw_clear(unsigned char y1, unsigned char y2)
841{
842 unsigned char i;
843
844 textcolor(TERM_BACKGROUNDCOLOR);
845 for(i = y1; i < y2; ++i) {
846 cclearxy(0, i, sizex);
847 }
848
849 update_area(0, y1, sizex, (unsigned char)(y2 - y1));
850}
851/*-----------------------------------------------------------------------------------*/
852/** \internal
853 * Draw one menu on the termainl desktop.
854 *
855 * \param m The CTK menu to be drawn.
856 */
857/*-----------------------------------------------------------------------------------*/
858static void
859draw_menu(struct ctk_menu *m)
860{
861 unsigned char x, x2, y;
862
863 textcolor(TERM_MENUCOLOR);
864 x = wherex();
865 cputs(m->title);
866 cputc(' ');
867 x2 = wherex();
868 if(x + CTK_CONF_MENUWIDTH > sizex) {
869 x = sizex - CTK_CONF_MENUWIDTH;
870 }
871
872
873 for(y = 0; y < m->nitems; ++y) {
874 if(y == m->active) {
875 textcolor(TERM_ACTIVEMENUCOLOR);
876 revers(0);
877 } else {
878 textcolor(TERM_MENUCOLOR);
879 }
880 gotoxy(x, (unsigned char)(y + 1));
881 if(m->items[y].title[0] == '-') {
882 chline(CTK_CONF_MENUWIDTH);
883 } else {
884 cputs(m->items[y].title);
885 }
886 if(x + CTK_CONF_MENUWIDTH > wherex()) {
887 cclear((unsigned char)(x + CTK_CONF_MENUWIDTH - wherex()));
888 }
889 revers(1);
890 }
891
892 gotoxy(x2, 0);
893 textcolor(TERM_MENUCOLOR);
894
895 update_area(x, 0, CTK_CONF_MENUWIDTH, (unsigned char)(m->nitems + 1));
896}
897/*-----------------------------------------------------------------------------------*/
898/**
899 * Draw the menus on the terminal desktop. Called by the CTK module.
900 *
901 * \param menus The CTK menubar.
902 */
903/*-----------------------------------------------------------------------------------*/
904void
905ctk_draw_menus(struct ctk_menus *menus)
906{
907 struct ctk_menu *m;
908
909
910 /* Draw menus */
911 textcolor(TERM_MENUCOLOR);
912 gotoxy(0, 0);
913 revers(1);
914 cputc(' ');
915 for(m = menus->menus->next; m != NULL; m = m->next) {
916 if(m != menus->open) {
917 update_area(wherex(), 0, (unsigned char)(strlen(m->title) + 1), 1);
918 cputs(m->title);
919 cputc(' ');
920 } else {
921 draw_menu(m);
922 }
923 }
924
925
926 if(wherex() + strlen(menus->desktopmenu->title) + 1>= sizex) {
927 gotoxy((unsigned char)(sizex - strlen(menus->desktopmenu->title) - 1), 0);
928 } else {
929 cclear((unsigned char)(sizex - wherex() - strlen(menus->desktopmenu->title) - 1));
930 update_area(wherex(), 0,
931 (unsigned char)(sizex - wherex() -strlen(menus->desktopmenu->title) - 1),
932 1);
933 }
934
935 /* Draw desktopmenu */
936 if(menus->desktopmenu != menus->open) {
937 update_area(wherex(), 0, (unsigned char)(strlen(menus->desktopmenu->title) + 1), 1);
938 cputs(menus->desktopmenu->title);
939 cputc(' ');
940 } else {
941 draw_menu(menus->desktopmenu);
942 }
943
944 revers(0);
945}
946
947/*-----------------------------------------------------------------------------------*/
948/**
949 * Obtain the height of the terminal desktop. Called by the CTK module.
950 *
951 * \return The height of the terminal desktop, in characters.
952 */
953/*-----------------------------------------------------------------------------------*/
954unsigned char
955ctk_draw_height(void)
956{
957 return sizey;
958}
959
960/*-----------------------------------------------------------------------------------*/
961/**
962 * Obtain the height of the terminal desktop. Called by the CTK module.
963 *
964 * \return The height of the terminal desktop, in characters.
965 */
966/*-----------------------------------------------------------------------------------*/
967unsigned char
968ctk_draw_width(void)
969{
970 return sizex;
971}
972
973/*-----------------------------------------------------------------------------------*/
974/**
975 * Draws a character on the virtual screen. Called by the libconio module.
976 *
977 * \param c The character to be drawn.
978 * \param xpos The x position of the character.
979 * \param ypos The y position of the character.
980 * \param reversedflag Determines if the character should be reversed or not.
981 * \param color The color of the character.
982 */
983/*-----------------------------------------------------------------------------------*/
984void
985ctk_arch_draw_char(char c,
986 unsigned char xpos,
987 unsigned char ypos,
988 unsigned char reversedflag,
989 unsigned char color)
990{
991 /* Check if out of bounds */
992 if (xpos >= sizex || ypos >= sizey) {
993 return;
994 }
995 ctk_term_out_update_screen(xpos,ypos, (unsigned char)(c & 0x7f), color);
996}