blob: c7314405147e4ba323bf5652fce4f7081644c8cf [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, '>');
477 for(i = 0; i < w->w; ++i) {
478 c = text[i + xscroll];
479 if(i == w->widget.textentry.xpos - xscroll) {
480 textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + (focus ^ 0x01)));
481 revers(1);
482 } else {
483 revers(0);
484 }
485 if(c == 0) {
486 cputc(' ');
487 } else {
488 cputc(c);
489 }
490 revers(0);
491 textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + focus));
492 }
493 cputc('<');
494 } else {
oliverschmidtacdf6e92005-05-04 22:04:35 +0000495 if(focus & CTK_FOCUS_WIDGET && j == w->widget.textentry.ypos) {
496 revers(1);
497 } else {
498 revers(0);
499 }
adamdunkelsb9614dc2004-08-09 20:33:51 +0000500 cvlinexy(xpos, ypos, 1);
501 gotoxy((unsigned char)(xpos + 1), ypos);
502 cputsn(text, w->w);
503 i = wherex();
504 if(i - xpos - 1 < w->w) {
505 cclear((unsigned char)(w->w - (i - xpos) + 1));
506 }
507 cvline(1);
508 }
509 }
510 ++ypos;
oliverschmidtcd6c30b2005-05-05 20:54:16 +0000511 text += w->widget.textentry.len + 1;
adamdunkelsb9614dc2004-08-09 20:33:51 +0000512 }
513 revers(0);
514 break;
515 case CTK_WIDGET_ICON:
516 if(ypos >= clipy1 && ypos < clipy2) {
517 textcolor((unsigned char)(TERM_ICONCOLOR + focus));
518 if(focus & 1) {
519 revers(1);
520 } else {
521 revers(0);
522 }
523
524 x = xpos;
525 len = strlen(w->widget.icon.title);
526 if(x + len >= sizex) {
527 x = sizex - len;
528 }
529
530 gotoxy(x, (unsigned char)(ypos + 3));
531 if(ypos >= clipy1 && ypos < clipy2) {
532 cputs(w->widget.icon.title);
533 }
534
535 gotoxy(xpos, ypos);
536
537 if (w->widget.icon.textmap != NULL) {
538 for(i = 0; i < 3; ++i) {
539
540 if(ypos >= clipy1 && ypos < clipy2) {
541 gotoxy(xpos,ypos);
542 cputc(w->widget.icon.textmap[0 + 3 * i]);
543 cputc(w->widget.icon.textmap[1 + 3 * i]);
544 cputc(w->widget.icon.textmap[2 + 3 * i]);
545 }
546 ++ypos;
547 }
548 }
549 x = xpos;
550 revers(0);
551 }
552 break;
553
554 default:
555 break;
556 }
557}
558
559/*-----------------------------------------------------------------------------------*/
560/**
561 * Draw a widget on the VNC screen. Called by the CTK module.
562 *
563 * \param w The widget to be drawn.
564 * \param focus The focus of the widget.
565 * \param clipy1 The lower y coordinate bound.
566 * \param clipy2 The upper y coordinate bound.
567 */
568/*-----------------------------------------------------------------------------------*/
569void
570ctk_draw_widget(struct ctk_widget *w,
571 unsigned char focus,
572 unsigned char clipy1,
573 unsigned char clipy2)
574{
575 struct ctk_window *win = w->window;
576 struct ctk_icon *icon;
577 unsigned char posx, posy, x, len;
578
579 posx = win->x + 1;
580 posy = win->y + 2;
581
582 if(w == win->focused) {
583 focus |= CTK_FOCUS_WIDGET;
584 }
585
586 draw_widget(w, posx, posy,
587 (unsigned char)(posx + win->w),
588 (unsigned char)(posy + win->h),
589 clipy1, clipy2,
590 focus);
591
592 if(w->type != CTK_WIDGET_ICON) {
593 update_area((unsigned char)(posx + w->x),
594 (unsigned char)(posy + w->y),
595 (unsigned char)(w->w + 2),
596 w->h);
597 } else {
598 icon = (struct ctk_icon *)w;
599
600 len = strlen(icon->title);
601 x = posx + w->x;
602 if(x + len >= sizex) {
603 x = sizex - len;
604 }
605
606 update_area(x,
607 (unsigned char)(posy + w->y),
608 (unsigned char)(len > 4? len: 4),
609 w->h);
610 }
611
612#ifdef CTK_CONIO_CONF_UPDATE
613 CTK_CONIO_CONF_UPDATE();
614#endif /* CTK_CONIO_CONF_UPDATE */
615}
616
617/*-----------------------------------------------------------------------------------*/
618/**
619 * Clear a window on the terminal screen. Called by the CTK module.
620 *
621 * \param window The window to be cleared.
622 * \param focus The focus of the window.
623 * \param clipy1 The lower y coordinate bound.
624 * \param clipy2 The upper y coordinate bound.
625 */
626/*-----------------------------------------------------------------------------------*/
627void
628ctk_draw_clear_window(struct ctk_window *window,
629 unsigned char focus,
630 unsigned char clipy1,
631 unsigned char clipy2)
632{
633 unsigned char i;
634 unsigned char h;
635
636 textcolor((unsigned char)(TERM_WINDOWCOLOR + focus));
637
638 h = window->y + 2 + window->h;
639 /* Clear window contents. */
640 for(i = window->y + 2; i < h; ++i) {
641 if(i >= clipy1 && i < clipy2) {
642 cclearxy((unsigned char)(window->x + 1), i, window->w);
643 }
644 }
645
646 update_area((unsigned char)(window->x + 1),
647 (unsigned char)(window->y + 2),
648 window->w, window->h);
649}
650/*-----------------------------------------------------------------------------------*/
651static void
652draw_window_contents(struct ctk_window *window, unsigned char focus,
653 unsigned char clipy1, unsigned char clipy2,
654 unsigned char x1, unsigned char x2,
655 unsigned char y1, unsigned char y2)
656{
657 struct ctk_widget *w;
658 unsigned char wfocus;
659
660 /* Draw inactive widgets. */
661 for(w = window->inactive; w != NULL; w = w->next) {
662 draw_widget(w, x1, y1, x2, y2,
663 clipy1, clipy2,
664 focus);
665 }
666
667 /* Draw active widgets. */
668 for(w = window->active; w != NULL; w = w->next) {
669 wfocus = focus;
670 if(w == window->focused) {
671 wfocus |= CTK_FOCUS_WIDGET;
672 }
673
674 draw_widget(w, x1, y1, x2, y2,
675 clipy1, clipy2,
676 wfocus);
677 }
678
679#ifdef CTK_CONIO_CONF_UPDATE
680 CTK_CONIO_CONF_UPDATE();
681#endif /* CTK_CONIO_CONF_UPDATE */
682
683}
684
685/*-----------------------------------------------------------------------------------*/
686/**
687 * Draw a window on the terminal screen. Called by the CTK module.
688 *
689 * \param window The window to be drawn.
690 * \param focus The focus of the window.
691 * \param clipy1 The lower y coordinate bound.
692 * \param clipy2 The upper y coordinate bound.
oliverschmidtd1040582005-03-15 16:07:35 +0000693 * \param draw_borders The flag for border drawing.
adamdunkelsb9614dc2004-08-09 20:33:51 +0000694 */
695/*-----------------------------------------------------------------------------------*/
696void
697ctk_draw_window(struct ctk_window *window, unsigned char focus,
oliverschmidtadf27db2005-03-15 15:51:17 +0000698 unsigned char clipy1, unsigned char clipy2,
699 unsigned char draw_borders)
adamdunkelsb9614dc2004-08-09 20:33:51 +0000700{
701 unsigned char x, y;
702 unsigned char h;
703 unsigned char x1, y1, x2, y2;
704 unsigned char i;
705
706
707 if(window->y + 1 >= clipy2) {
708 return;
709 }
710
711 x = window->x;
712 y = window->y + 1;
adamdunkelsb9614dc2004-08-09 20:33:51 +0000713 x1 = x + 1;
714 y1 = y + 1;
715 x2 = x1 + window->w;
716 y2 = y1 + window->h;
717
oliverschmidtadf27db2005-03-15 15:51:17 +0000718 if(draw_borders) {
adamdunkelsb9614dc2004-08-09 20:33:51 +0000719
oliverschmidtadf27db2005-03-15 15:51:17 +0000720 /* Draw window frame. */
721 textcolor((unsigned char)(TERM_WINDOWCOLOR + focus));
adamdunkelsb9614dc2004-08-09 20:33:51 +0000722
oliverschmidtadf27db2005-03-15 15:51:17 +0000723 if(y >= clipy1) {
724 cputcxy(x, y, CH_ULCORNER);
oliverschmidt7b9025d2005-03-18 01:08:35 +0000725 for(i = wherex() + window->titlelen + CTK_CONF_WINDOWMOVE * 2; i < x2; ++i) {
oliverschmidtadf27db2005-03-15 15:51:17 +0000726 cputcxy(i, y, CH_TITLEBAR);
727 }
728 cputcxy(x2, y, CH_URCORNER);
adamdunkelsb9614dc2004-08-09 20:33:51 +0000729 }
oliverschmidtadf27db2005-03-15 15:51:17 +0000730
731 h = window->h;
732
733 if(clipy1 > y1) {
734 if(clipy1 - y1 < h) {
735 h = clipy1 - y1;
736 y1 = clipy1;
737 } else {
738 h = 0;
739 }
740 }
741
742 if(clipy2 < y1 + h) {
743 if(y1 >= clipy2) {
744 h = 0;
745 } else {
746 h = clipy2 - y1;
747 }
748 }
749
750 for(i = y1; i < y1 + h; ++i) {
751 cputcxy(x, i, CH_WINDOWLBORDER);
752 cputcxy(x2, i, CH_WINDOWRBORDER);
753 }
754
755 if(y2 >= clipy1 &&
756 y2 < clipy2) {
757 cputcxy(x, y2, CH_LLCORNER);
758 for(i = x1; i < x2; ++i) {
759 cputcxy(i, y2, CH_WINDOWLOWERBORDER);
760 }
761 cputcxy(x2, y2, CH_LRCORNER);
762 }
adamdunkelsb9614dc2004-08-09 20:33:51 +0000763 }
764
oliverschmidte99386b2004-12-27 22:03:04 +0000765 draw_window_contents(window, focus, clipy1, clipy2,
adamdunkelsb9614dc2004-08-09 20:33:51 +0000766 x1, x2, (unsigned char)(y + 1), y2);
767
768 update_area(window->x, window->y,
769 (unsigned char)(window->w + 2),
770 (unsigned char)(window->h + 2));
771}
772/*-----------------------------------------------------------------------------------*/
773/**
774 * Draw a dialog on the terminal screen. Called by the CTK module.
775 *
776 * \param dialog The dialog to be drawn.
777 */
778/*-----------------------------------------------------------------------------------*/
779void
780ctk_draw_dialog(struct ctk_window *dialog)
781{
782 unsigned char x, y;
783 unsigned char i;
784 unsigned char x1, y1, x2, y2;
785
786 textcolor(TERM_WINDOWCOLOR + CTK_FOCUS_DIALOG);
787
788 x = dialog->x;
789 y = dialog->y + 1;
790
791
792 x1 = x + 1;
793 y1 = y + 1;
794 x2 = x1 + dialog->w;
795 y2 = y1 + dialog->h;
796
797
798 /* Draw dialog frame. */
799
800 for(i = y1; i < y1 + dialog->h; ++i) {
801 cputcxy(x, i, CH_DIALOGLBORDER);
802 cputcxy(x2, i, CH_DIALOGRBORDER);
803 }
804
805 for(i = x1; i < x2; ++i) {
806 cputcxy(i, y, CH_DIALOGUPPERBORDER);
807 cputcxy(i, y2, CH_DIALOGLOWERBORDER);
808 }
809
810 cputcxy(x, y, CH_DIALOG_ULCORNER);
811 cputcxy(x, y2, CH_DIALOG_LLCORNER);
812 cputcxy(x2, y, CH_DIALOG_URCORNER);
813 cputcxy(x2, y2, CH_DIALOG_LRCORNER);
814
815
816 /* Clear dialog contents. */
817 for(i = y1; i < y2; ++i) {
818 cclearxy(x1, i, dialog->w);
819 }
820
821 draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
822 x1, x2, y1, y2);
823
824 update_area(dialog->x, dialog->y,
825 (unsigned char)(dialog->w + 4),
826 (unsigned char)(dialog->h + 4));
827}
828/*-----------------------------------------------------------------------------------*/
829/**
830 * Clear parts of the terminal desktop. Called by the CTK module.
831 *
832 * \param y1 The lower y coordinate bound.
833 * \param y2 The upped y coordinate bound.
834 */
835/*-----------------------------------------------------------------------------------*/
836void
837ctk_draw_clear(unsigned char y1, unsigned char y2)
838{
839 unsigned char i;
840
841 textcolor(TERM_BACKGROUNDCOLOR);
842 for(i = y1; i < y2; ++i) {
843 cclearxy(0, i, sizex);
844 }
845
846 update_area(0, y1, sizex, (unsigned char)(y2 - y1));
847}
848/*-----------------------------------------------------------------------------------*/
849/** \internal
850 * Draw one menu on the termainl desktop.
851 *
852 * \param m The CTK menu to be drawn.
853 */
854/*-----------------------------------------------------------------------------------*/
855static void
856draw_menu(struct ctk_menu *m)
857{
858 unsigned char x, x2, y;
859
860 textcolor(TERM_MENUCOLOR);
861 x = wherex();
862 cputs(m->title);
863 cputc(' ');
864 x2 = wherex();
865 if(x + CTK_CONF_MENUWIDTH > sizex) {
866 x = sizex - CTK_CONF_MENUWIDTH;
867 }
868
869
870 for(y = 0; y < m->nitems; ++y) {
871 if(y == m->active) {
872 textcolor(TERM_ACTIVEMENUCOLOR);
873 revers(0);
874 } else {
875 textcolor(TERM_MENUCOLOR);
876 }
877 gotoxy(x, (unsigned char)(y + 1));
878 if(m->items[y].title[0] == '-') {
879 chline(CTK_CONF_MENUWIDTH);
880 } else {
881 cputs(m->items[y].title);
882 }
883 if(x + CTK_CONF_MENUWIDTH > wherex()) {
884 cclear((unsigned char)(x + CTK_CONF_MENUWIDTH - wherex()));
885 }
886 revers(1);
887 }
888
889 gotoxy(x2, 0);
890 textcolor(TERM_MENUCOLOR);
891
892 update_area(x, 0, CTK_CONF_MENUWIDTH, (unsigned char)(m->nitems + 1));
893}
894/*-----------------------------------------------------------------------------------*/
895/**
896 * Draw the menus on the terminal desktop. Called by the CTK module.
897 *
898 * \param menus The CTK menubar.
899 */
900/*-----------------------------------------------------------------------------------*/
901void
902ctk_draw_menus(struct ctk_menus *menus)
903{
904 struct ctk_menu *m;
905
906
907 /* Draw menus */
908 textcolor(TERM_MENUCOLOR);
909 gotoxy(0, 0);
910 revers(1);
911 cputc(' ');
912 for(m = menus->menus->next; m != NULL; m = m->next) {
913 if(m != menus->open) {
914 update_area(wherex(), 0, (unsigned char)(strlen(m->title) + 1), 1);
915 cputs(m->title);
916 cputc(' ');
917 } else {
918 draw_menu(m);
919 }
920 }
921
922
923 if(wherex() + strlen(menus->desktopmenu->title) + 1>= sizex) {
924 gotoxy((unsigned char)(sizex - strlen(menus->desktopmenu->title) - 1), 0);
925 } else {
926 cclear((unsigned char)(sizex - wherex() - strlen(menus->desktopmenu->title) - 1));
927 update_area(wherex(), 0,
928 (unsigned char)(sizex - wherex() -strlen(menus->desktopmenu->title) - 1),
929 1);
930 }
931
932 /* Draw desktopmenu */
933 if(menus->desktopmenu != menus->open) {
934 update_area(wherex(), 0, (unsigned char)(strlen(menus->desktopmenu->title) + 1), 1);
935 cputs(menus->desktopmenu->title);
936 cputc(' ');
937 } else {
938 draw_menu(menus->desktopmenu);
939 }
940
941 revers(0);
942}
943
944/*-----------------------------------------------------------------------------------*/
945/**
946 * Obtain the height of the terminal desktop. Called by the CTK module.
947 *
948 * \return The height of the terminal desktop, in characters.
949 */
950/*-----------------------------------------------------------------------------------*/
951unsigned char
952ctk_draw_height(void)
953{
954 return sizey;
955}
956
957/*-----------------------------------------------------------------------------------*/
958/**
959 * Obtain the height of the terminal desktop. Called by the CTK module.
960 *
961 * \return The height of the terminal desktop, in characters.
962 */
963/*-----------------------------------------------------------------------------------*/
964unsigned char
965ctk_draw_width(void)
966{
967 return sizex;
968}
969
970/*-----------------------------------------------------------------------------------*/
971/**
972 * Draws a character on the virtual screen. Called by the libconio module.
973 *
974 * \param c The character to be drawn.
975 * \param xpos The x position of the character.
976 * \param ypos The y position of the character.
977 * \param reversedflag Determines if the character should be reversed or not.
978 * \param color The color of the character.
979 */
980/*-----------------------------------------------------------------------------------*/
981void
982ctk_arch_draw_char(char c,
983 unsigned char xpos,
984 unsigned char ypos,
985 unsigned char reversedflag,
986 unsigned char color)
987{
988 /* Check if out of bounds */
989 if (xpos >= sizex || ypos >= sizey) {
990 return;
991 }
992 ctk_term_out_update_screen(xpos,ypos, (unsigned char)(c & 0x7f), color);
993}