blob: c83f64dea8645e798452169311f14412a6057e82 [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;
467 if(focus & CTK_FOCUS_WIDGET) {
468 revers(1);
469 } else {
470 revers(0);
471 }
472 xscroll = 0;
473 if(w->widget.textentry.xpos >= w->w - 1) {
474 xscroll = w->widget.textentry.xpos - w->w + 1;
475 }
476 for(j = 0; j < w->h; ++j) {
477 if(ypos >= clipy1 && ypos < clipy2) {
478 if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
479 w->widget.textentry.ypos == j) {
480 revers(0);
481 cputcxy(xpos, ypos, '>');
482 for(i = 0; i < w->w; ++i) {
483 c = text[i + xscroll];
484 if(i == w->widget.textentry.xpos - xscroll) {
485 textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + (focus ^ 0x01)));
486 revers(1);
487 } else {
488 revers(0);
489 }
490 if(c == 0) {
491 cputc(' ');
492 } else {
493 cputc(c);
494 }
495 revers(0);
496 textcolor((unsigned char)(TERM_TEXTENTRYCOLOR + focus));
497 }
498 cputc('<');
499 } else {
500 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;
511 text += w->w;
512 }
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.
693 */
694/*-----------------------------------------------------------------------------------*/
695void
696ctk_draw_window(struct ctk_window *window, unsigned char focus,
697 unsigned char clipy1, unsigned char clipy2)
698{
699 unsigned char x, y;
700 unsigned char h;
701 unsigned char x1, y1, x2, y2;
702 unsigned char i;
703
704
705 if(window->y + 1 >= clipy2) {
706 return;
707 }
708
709 x = window->x;
710 y = window->y + 1;
711
712 textcolor((unsigned char)(TERM_WINDOWCOLOR + focus));
713
714 x1 = x + 1;
715 y1 = y + 1;
716 x2 = x1 + window->w;
717 y2 = y1 + window->h;
718
719 /* Draw window frame. */
720 if(y >= clipy1) {
721 cputcxy(x, y, CH_ULCORNER);
722 for(i = wherex() + window->titlelen + 2; i < x2; ++i) {
723 cputcxy(i, y, CH_TITLEBAR);
724 }
725 cputcxy(x2, y, CH_URCORNER);
726 }
727
728 h = window->h;
729
730 if(clipy1 > y1) {
731 if(clipy1 - y1 < h) {
732 h = clipy1 - y1;
733 y1 = clipy1;
734 } else {
735 h = 0;
736 }
737 }
738
739 if(clipy2 < y1 + h) {
740 if(y1 >= clipy2) {
741 h = 0;
742 } else {
743 h = clipy2 - y1;
744 }
745 }
746
747 for(i = y1; i < y1 + h; ++i) {
748 cputcxy(x, i, CH_WINDOWLBORDER);
749 cputcxy(x2, i, CH_WINDOWRBORDER);
750 }
751
752 if(y2 >= clipy1 &&
753 y2 < clipy2) {
754 cputcxy(x, y2, CH_LLCORNER);
755 for(i = x1; i < x2; ++i) {
756 cputcxy(i, y2, CH_WINDOWLOWERBORDER);
757 }
758 cputcxy(x2, y2, CH_LRCORNER);
759 }
760
oliverschmidte99386b2004-12-27 22:03:04 +0000761 draw_window_contents(window, focus, clipy1, clipy2,
adamdunkelsb9614dc2004-08-09 20:33:51 +0000762 x1, x2, (unsigned char)(y + 1), y2);
763
764 update_area(window->x, window->y,
765 (unsigned char)(window->w + 2),
766 (unsigned char)(window->h + 2));
767}
768/*-----------------------------------------------------------------------------------*/
769/**
770 * Draw a dialog on the terminal screen. Called by the CTK module.
771 *
772 * \param dialog The dialog to be drawn.
773 */
774/*-----------------------------------------------------------------------------------*/
775void
776ctk_draw_dialog(struct ctk_window *dialog)
777{
778 unsigned char x, y;
779 unsigned char i;
780 unsigned char x1, y1, x2, y2;
781
782 textcolor(TERM_WINDOWCOLOR + CTK_FOCUS_DIALOG);
783
784 x = dialog->x;
785 y = dialog->y + 1;
786
787
788 x1 = x + 1;
789 y1 = y + 1;
790 x2 = x1 + dialog->w;
791 y2 = y1 + dialog->h;
792
793
794 /* Draw dialog frame. */
795
796 for(i = y1; i < y1 + dialog->h; ++i) {
797 cputcxy(x, i, CH_DIALOGLBORDER);
798 cputcxy(x2, i, CH_DIALOGRBORDER);
799 }
800
801 for(i = x1; i < x2; ++i) {
802 cputcxy(i, y, CH_DIALOGUPPERBORDER);
803 cputcxy(i, y2, CH_DIALOGLOWERBORDER);
804 }
805
806 cputcxy(x, y, CH_DIALOG_ULCORNER);
807 cputcxy(x, y2, CH_DIALOG_LLCORNER);
808 cputcxy(x2, y, CH_DIALOG_URCORNER);
809 cputcxy(x2, y2, CH_DIALOG_LRCORNER);
810
811
812 /* Clear dialog contents. */
813 for(i = y1; i < y2; ++i) {
814 cclearxy(x1, i, dialog->w);
815 }
816
817 draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
818 x1, x2, y1, y2);
819
820 update_area(dialog->x, dialog->y,
821 (unsigned char)(dialog->w + 4),
822 (unsigned char)(dialog->h + 4));
823}
824/*-----------------------------------------------------------------------------------*/
825/**
826 * Clear parts of the terminal desktop. Called by the CTK module.
827 *
828 * \param y1 The lower y coordinate bound.
829 * \param y2 The upped y coordinate bound.
830 */
831/*-----------------------------------------------------------------------------------*/
832void
833ctk_draw_clear(unsigned char y1, unsigned char y2)
834{
835 unsigned char i;
836
837 textcolor(TERM_BACKGROUNDCOLOR);
838 for(i = y1; i < y2; ++i) {
839 cclearxy(0, i, sizex);
840 }
841
842 update_area(0, y1, sizex, (unsigned char)(y2 - y1));
843}
844/*-----------------------------------------------------------------------------------*/
845/** \internal
846 * Draw one menu on the termainl desktop.
847 *
848 * \param m The CTK menu to be drawn.
849 */
850/*-----------------------------------------------------------------------------------*/
851static void
852draw_menu(struct ctk_menu *m)
853{
854 unsigned char x, x2, y;
855
856 textcolor(TERM_MENUCOLOR);
857 x = wherex();
858 cputs(m->title);
859 cputc(' ');
860 x2 = wherex();
861 if(x + CTK_CONF_MENUWIDTH > sizex) {
862 x = sizex - CTK_CONF_MENUWIDTH;
863 }
864
865
866 for(y = 0; y < m->nitems; ++y) {
867 if(y == m->active) {
868 textcolor(TERM_ACTIVEMENUCOLOR);
869 revers(0);
870 } else {
871 textcolor(TERM_MENUCOLOR);
872 }
873 gotoxy(x, (unsigned char)(y + 1));
874 if(m->items[y].title[0] == '-') {
875 chline(CTK_CONF_MENUWIDTH);
876 } else {
877 cputs(m->items[y].title);
878 }
879 if(x + CTK_CONF_MENUWIDTH > wherex()) {
880 cclear((unsigned char)(x + CTK_CONF_MENUWIDTH - wherex()));
881 }
882 revers(1);
883 }
884
885 gotoxy(x2, 0);
886 textcolor(TERM_MENUCOLOR);
887
888 update_area(x, 0, CTK_CONF_MENUWIDTH, (unsigned char)(m->nitems + 1));
889}
890/*-----------------------------------------------------------------------------------*/
891/**
892 * Draw the menus on the terminal desktop. Called by the CTK module.
893 *
894 * \param menus The CTK menubar.
895 */
896/*-----------------------------------------------------------------------------------*/
897void
898ctk_draw_menus(struct ctk_menus *menus)
899{
900 struct ctk_menu *m;
901
902
903 /* Draw menus */
904 textcolor(TERM_MENUCOLOR);
905 gotoxy(0, 0);
906 revers(1);
907 cputc(' ');
908 for(m = menus->menus->next; m != NULL; m = m->next) {
909 if(m != menus->open) {
910 update_area(wherex(), 0, (unsigned char)(strlen(m->title) + 1), 1);
911 cputs(m->title);
912 cputc(' ');
913 } else {
914 draw_menu(m);
915 }
916 }
917
918
919 if(wherex() + strlen(menus->desktopmenu->title) + 1>= sizex) {
920 gotoxy((unsigned char)(sizex - strlen(menus->desktopmenu->title) - 1), 0);
921 } else {
922 cclear((unsigned char)(sizex - wherex() - strlen(menus->desktopmenu->title) - 1));
923 update_area(wherex(), 0,
924 (unsigned char)(sizex - wherex() -strlen(menus->desktopmenu->title) - 1),
925 1);
926 }
927
928 /* Draw desktopmenu */
929 if(menus->desktopmenu != menus->open) {
930 update_area(wherex(), 0, (unsigned char)(strlen(menus->desktopmenu->title) + 1), 1);
931 cputs(menus->desktopmenu->title);
932 cputc(' ');
933 } else {
934 draw_menu(menus->desktopmenu);
935 }
936
937 revers(0);
938}
939
940/*-----------------------------------------------------------------------------------*/
941/**
942 * Obtain the height of the terminal desktop. Called by the CTK module.
943 *
944 * \return The height of the terminal desktop, in characters.
945 */
946/*-----------------------------------------------------------------------------------*/
947unsigned char
948ctk_draw_height(void)
949{
950 return sizey;
951}
952
953/*-----------------------------------------------------------------------------------*/
954/**
955 * Obtain the height of the terminal desktop. Called by the CTK module.
956 *
957 * \return The height of the terminal desktop, in characters.
958 */
959/*-----------------------------------------------------------------------------------*/
960unsigned char
961ctk_draw_width(void)
962{
963 return sizex;
964}
965
966/*-----------------------------------------------------------------------------------*/
967/**
968 * Draws a character on the virtual screen. Called by the libconio module.
969 *
970 * \param c The character to be drawn.
971 * \param xpos The x position of the character.
972 * \param ypos The y position of the character.
973 * \param reversedflag Determines if the character should be reversed or not.
974 * \param color The color of the character.
975 */
976/*-----------------------------------------------------------------------------------*/
977void
978ctk_arch_draw_char(char c,
979 unsigned char xpos,
980 unsigned char ypos,
981 unsigned char reversedflag,
982 unsigned char color)
983{
984 /* Check if out of bounds */
985 if (xpos >= sizex || ypos >= sizey) {
986 return;
987 }
988 ctk_term_out_update_screen(xpos,ypos, (unsigned char)(c & 0x7f), color);
989}