blob: ae7c18a7a4c6ad8e4af95b2b295f9c194c9172c9 [file] [log] [blame]
adamdunkels09c28b62003-04-02 10:17:52 +00001/*
2 * Copyright (c) 2002, Adam Dunkels.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution.
adamdunkels76a4c4a2004-06-06 05:52:21 +000014 * 3. The name of the author may not be used to endorse or promote
adamdunkels09c28b62003-04-02 10:17:52 +000015 * products derived from this software without specific prior
16 * written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * This file is part of the "ctk" console GUI toolkit for cc65
31 *
oliverschmidt4037b262004-06-27 20:59:05 +000032 * $Id: ctk-conio.c,v 1.12 2004/06/27 20:59:05 oliverschmidt Exp $
adamdunkels09c28b62003-04-02 10:17:52 +000033 *
34 */
35
adamdunkels09e27572004-03-25 09:50:13 +000036#include <conio.h>
37
adamdunkels09c28b62003-04-02 10:17:52 +000038#include "ctk.h"
39#include "ctk-draw.h"
40
41#include "ctk-conio-conf.h"
adamdunkels09c28b62003-04-02 10:17:52 +000042#include <string.h>
43
44#ifndef NULL
45#define NULL (void *)0
46#endif /* NULL */
47
48static unsigned char sizex, sizey;
49
50/*-----------------------------------------------------------------------------------*/
adamdunkels09c28b62003-04-02 10:17:52 +000051static void
52cputsn(char *str, unsigned char len)
53{
oliverschmidt4037b262004-06-27 20:59:05 +000054 char c;
55
56 while(len > 0) {
57 --len;
58 c = *str;
59 if(c == 0) {
60 break;
61 }
62 cputc(c);
63 ++str;
64 }
adamdunkels09c28b62003-04-02 10:17:52 +000065}
66/*-----------------------------------------------------------------------------------*/
67void
68ctk_draw_init(void)
69{
70 bgcolor(SCREENCOLOR);
71 bordercolor(BORDERCOLOR);
72 screensize(&sizex, &sizey);
73 ctk_draw_clear(0, sizey);
74}
75/*-----------------------------------------------------------------------------------*/
76static void
77draw_widget(struct ctk_widget *w,
78 unsigned char x, unsigned char y,
79 unsigned char clipx,
80 unsigned char clipy,
81 unsigned char clipy1, unsigned char clipy2,
82 unsigned char focus)
83{
84 unsigned char xpos, ypos, xscroll;
85 unsigned char i, j;
86 char c, *text;
adamdunkels09e27572004-03-25 09:50:13 +000087 unsigned char len, wfocus;
88
89 wfocus = 0;
adamdunkels09c28b62003-04-02 10:17:52 +000090 if(focus & CTK_FOCUS_WINDOW) {
91 textcolor(WIDGETCOLOR_FWIN);
92 if(focus & CTK_FOCUS_WIDGET) {
93 textcolor(WIDGETCOLOR_FOCUS);
adamdunkels09e27572004-03-25 09:50:13 +000094 wfocus = 1;
adamdunkels09c28b62003-04-02 10:17:52 +000095 }
96 } else if(focus & CTK_FOCUS_DIALOG) {
97 textcolor(WIDGETCOLOR_DIALOG);
98 if(focus & CTK_FOCUS_WIDGET) {
99 textcolor(WIDGETCOLOR_FOCUS);
adamdunkels09e27572004-03-25 09:50:13 +0000100 wfocus = 1;
adamdunkels09c28b62003-04-02 10:17:52 +0000101 }
102 } else {
103 textcolor(WIDGETCOLOR);
104 }
105
106 xpos = x + w->x;
107 ypos = y + w->y;
108
109 switch(w->type) {
110 case CTK_WIDGET_SEPARATOR:
111 if(ypos >= clipy1 && ypos < clipy2) {
112 chlinexy(xpos, ypos, w->w);
113 }
114 break;
115 case CTK_WIDGET_LABEL:
116 text = w->widget.label.text;
adamdunkels62393fb2003-07-30 23:31:56 +0000117 for(i = 0; i < w->h; ++i) {
adamdunkels09c28b62003-04-02 10:17:52 +0000118 if(ypos >= clipy1 && ypos < clipy2) {
119 gotoxy(xpos, ypos);
120 cputsn(text, w->w);
121 if(w->w - (wherex() - xpos) > 0) {
122 cclear(w->w - (wherex() - xpos));
123 }
124 }
125 ++ypos;
126 text += w->w;
127 }
128 break;
129 case CTK_WIDGET_BUTTON:
130 if(ypos >= clipy1 && ypos < clipy2) {
adamdunkels09e27572004-03-25 09:50:13 +0000131 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000132 revers(1);
133 } else {
134 revers(0);
135 }
136 cputcxy(xpos, ypos, '[');
137 cputsn(w->widget.button.text, w->w);
138 cputc(']');
139 revers(0);
140 }
141 break;
142 case CTK_WIDGET_HYPERLINK:
143 if(ypos >= clipy1 && ypos < clipy2) {
adamdunkels09e27572004-03-25 09:50:13 +0000144 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000145 revers(0);
146 } else {
147 revers(1);
148 }
149 gotoxy(xpos, ypos);
150 textcolor(WIDGETCOLOR_HLINK);
151 cputsn(w->widget.button.text, w->w);
152 revers(0);
153 }
154 break;
155 case CTK_WIDGET_TEXTENTRY:
156 text = w->widget.textentry.text;
adamdunkels09e27572004-03-25 09:50:13 +0000157 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000158 revers(1);
159 } else {
160 revers(0);
161 }
162 xscroll = 0;
163 if(w->widget.textentry.xpos >= w->w - 1) {
164 xscroll = w->widget.textentry.xpos - w->w + 1;
165 }
adamdunkels62393fb2003-07-30 23:31:56 +0000166 for(j = 0; j < w->h; ++j) {
adamdunkels09c28b62003-04-02 10:17:52 +0000167 if(ypos >= clipy1 && ypos < clipy2) {
168 if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
169 w->widget.textentry.ypos == j) {
170 revers(0);
171 cputcxy(xpos, ypos, '>');
172 for(i = 0; i < w->w; ++i) {
173 c = text[i + xscroll];
174 if(i == w->widget.textentry.xpos - xscroll) {
175 revers(1);
176 } else {
177 revers(0);
178 }
179 if(c == 0) {
180 cputc(' ');
181 } else {
182 cputc(c);
183 }
184 revers(0);
185 }
186 cputc('<');
187 } else {
188 cvlinexy(xpos, ypos, 1);
189 gotoxy(xpos + 1, ypos);
190 cputsn(text, w->w);
191 i = wherex();
192 if(i - xpos - 1 < w->w) {
193 cclear(w->w - (i - xpos) + 1);
194 }
195 cvline(1);
196 }
197 }
198 ++ypos;
199 text += w->w;
200 }
201 revers(0);
202 break;
oliverschmidta98def52004-06-27 18:32:10 +0000203#if CTK_CONF_ICONS
adamdunkels09c28b62003-04-02 10:17:52 +0000204 case CTK_WIDGET_ICON:
205 if(ypos >= clipy1 && ypos < clipy2) {
oliverschmidtf42b7bc2004-06-27 15:04:01 +0000206 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000207 revers(1);
208 } else {
209 revers(0);
210 }
oliverschmidta98def52004-06-27 18:32:10 +0000211#if CTK_CONF_ICON_TEXTMAPS
adamdunkels09c28b62003-04-02 10:17:52 +0000212 if(w->widget.icon.textmap != NULL) {
213 for(i = 0; i < 3; ++i) {
214 gotoxy(xpos, ypos);
215 if(ypos >= clipy1 && ypos < clipy2) {
216 cputc(w->widget.icon.textmap[0 + 3 * i]);
217 cputc(w->widget.icon.textmap[1 + 3 * i]);
218 cputc(w->widget.icon.textmap[2 + 3 * i]);
219 }
220 ++ypos;
221 }
222 }
oliverschmidta98def52004-06-27 18:32:10 +0000223#endif /* CTK_CONF_ICON_TEXTMAPS */
adamdunkels09c28b62003-04-02 10:17:52 +0000224
225 len = strlen(w->widget.icon.title);
oliverschmidta98def52004-06-27 18:32:10 +0000226 if(xpos + len >= sizex) {
227 xpos = sizex - len;
adamdunkels09c28b62003-04-02 10:17:52 +0000228 }
229
oliverschmidta98def52004-06-27 18:32:10 +0000230 gotoxy(xpos, ypos);
adamdunkels09c28b62003-04-02 10:17:52 +0000231 if(ypos >= clipy1 && ypos < clipy2) {
232 cputs(w->widget.icon.title);
233 }
234 revers(0);
235 }
236 break;
oliverschmidta98def52004-06-27 18:32:10 +0000237#endif /* CTK_CONF_ICONS */
adamdunkels09c28b62003-04-02 10:17:52 +0000238
239 default:
240 break;
241 }
242}
243/*-----------------------------------------------------------------------------------*/
244void
245ctk_draw_widget(struct ctk_widget *w,
246 unsigned char focus,
247 unsigned char clipy1,
248 unsigned char clipy2)
249{
250 struct ctk_window *win = w->window;
251 unsigned char posx, posy;
252
253 posx = win->x + 1;
254 posy = win->y + 2;
255
256 if(w == win->focused) {
257 focus |= CTK_FOCUS_WIDGET;
258 }
259
260 draw_widget(w, posx, posy,
261 posx + win->w,
262 posy + win->h,
263 clipy1, clipy2,
264 focus);
adamdunkelsfe32f8d2003-04-28 20:31:48 +0000265
266#ifdef CTK_CONIO_CONF_UPDATE
267 CTK_CONIO_CONF_UPDATE();
268#endif /* CTK_CONIO_CONF_UPDATE */
adamdunkels09c28b62003-04-02 10:17:52 +0000269}
270/*-----------------------------------------------------------------------------------*/
271void
272ctk_draw_clear_window(struct ctk_window *window,
273 unsigned char focus,
274 unsigned char clipy1,
275 unsigned char clipy2)
276{
277 unsigned char i;
278 unsigned char h;
279
280
281 h = window->y + 2 + window->h;
282 /* Clear window contents. */
283 for(i = window->y + 2; i < h; ++i) {
284 if(i >= clipy1 && i < clipy2) {
285 cclearxy(window->x + 1, i, window->w);
286 }
287 }
288}
289/*-----------------------------------------------------------------------------------*/
adamdunkelsa45d8a12003-04-08 07:22:13 +0000290static void
291draw_window_contents(struct ctk_window *window, unsigned char focus,
292 unsigned char clipy1, unsigned char clipy2,
293 unsigned char x1, unsigned char x2,
294 unsigned char y1, unsigned char y2)
295{
296 struct ctk_widget *w;
297 unsigned char wfocus;
298
299 /* Draw inactive widgets. */
300 for(w = window->inactive; w != NULL; w = w->next) {
301 draw_widget(w, x1, y1, x2, y2,
302 clipy1, clipy2,
303 focus);
304 }
305
306 /* Draw active widgets. */
307 for(w = window->active; w != NULL; w = w->next) {
308 wfocus = focus;
309 if(w == window->focused) {
310 wfocus |= CTK_FOCUS_WIDGET;
311 }
312
313 draw_widget(w, x1, y1, x2, y2,
314 clipy1, clipy2,
315 wfocus);
316 }
317
adamdunkelsfe32f8d2003-04-28 20:31:48 +0000318#ifdef CTK_CONIO_CONF_UPDATE
319 CTK_CONIO_CONF_UPDATE();
320#endif /* CTK_CONIO_CONF_UPDATE */
321
adamdunkelsa45d8a12003-04-08 07:22:13 +0000322}
323/*-----------------------------------------------------------------------------------*/
adamdunkels09c28b62003-04-02 10:17:52 +0000324void
325ctk_draw_window(struct ctk_window *window, unsigned char focus,
326 unsigned char clipy1, unsigned char clipy2)
327{
328 unsigned char x, y;
329 unsigned char h;
adamdunkels09c28b62003-04-02 10:17:52 +0000330 unsigned char x1, y1, x2, y2;
331
332 if(window->y + 1 >= clipy2) {
333 return;
334 }
335
336 x = window->x;
337 y = window->y + 1;
338
339 if(focus & CTK_FOCUS_WINDOW) {
340 textcolor(WINDOWCOLOR_FOCUS);
341 } else {
342 textcolor(WINDOWCOLOR);
343 }
344
345 x1 = x + 1;
346 y1 = y + 1;
347 x2 = x1 + window->w;
348 y2 = y1 + window->h;
349
350 /* Draw window frame. */
351 if(y >= clipy1) {
352 cputcxy(x, y, CH_ULCORNER);
adamdunkels09c28b62003-04-02 10:17:52 +0000353 gotoxy(wherex() + window->titlelen + 2, wherey());
354 chline(window->w - (wherex() - x) - 2);
355 cputcxy(x2, y, CH_URCORNER);
356 }
357
358 h = window->h;
359
360 if(clipy1 > y1) {
361 if(clipy1 - y1 < h) {
362 h = clipy1 - y1;
adamdunkels62393fb2003-07-30 23:31:56 +0000363 y1 = clipy1;
adamdunkels09c28b62003-04-02 10:17:52 +0000364 } else {
365 h = 0;
366 }
367 }
368
adamdunkels62393fb2003-07-30 23:31:56 +0000369 if(clipy2 < y1 + h) {
adamdunkels09c28b62003-04-02 10:17:52 +0000370 if(y1 >= clipy2) {
371 h = 0;
372 } else {
373 h = clipy2 - y1;
374 }
375 }
adamdunkels62393fb2003-07-30 23:31:56 +0000376
adamdunkels09c28b62003-04-02 10:17:52 +0000377 cvlinexy(x, y1, h);
adamdunkels62393fb2003-07-30 23:31:56 +0000378 cvlinexy(x2, y1, h);
adamdunkels09c28b62003-04-02 10:17:52 +0000379
380 if(y + window->h >= clipy1 &&
381 y + window->h < clipy2) {
382 cputcxy(x, y2, CH_LLCORNER);
383 chlinexy(x1, y2, window->w);
384 cputcxy(x2, y2, CH_LRCORNER);
385 }
386
adamdunkelsa45d8a12003-04-08 07:22:13 +0000387 draw_window_contents(window, focus & CTK_FOCUS_WINDOW, clipy1, clipy2,
adamdunkels62393fb2003-07-30 23:31:56 +0000388 x1, x2, y + 1, y2);
adamdunkels09c28b62003-04-02 10:17:52 +0000389}
390/*-----------------------------------------------------------------------------------*/
391void
392ctk_draw_dialog(struct ctk_window *dialog)
393{
394 unsigned char x, y;
395 unsigned char i;
adamdunkels09c28b62003-04-02 10:17:52 +0000396 unsigned char x1, y1, x2, y2;
397
398 textcolor(DIALOGCOLOR);
399
400 x = dialog->x;
401 y = dialog->y + 1;
402
403
404 x1 = x + 1;
405 y1 = y + 1;
406 x2 = x1 + dialog->w;
407 y2 = y1 + dialog->h;
408
409
410 /* Draw dialog frame. */
411
412 cvlinexy(x, y1,
413 dialog->h);
414 cvlinexy(x2, y1,
415 dialog->h);
416
417 chlinexy(x1, y,
418 dialog->w);
419 chlinexy(x1, y2,
420 dialog->w);
421
422 cputcxy(x, y, CH_ULCORNER);
423 cputcxy(x, y2, CH_LLCORNER);
424 cputcxy(x2, y, CH_URCORNER);
425 cputcxy(x2, y2, CH_LRCORNER);
426
427
adamdunkels09c28b62003-04-02 10:17:52 +0000428 /* Clear dialog contents. */
429 for(i = y1; i < y2; ++i) {
430 cclearxy(x1, i, dialog->w);
431 }
adamdunkels09c28b62003-04-02 10:17:52 +0000432
adamdunkelsa45d8a12003-04-08 07:22:13 +0000433 draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
434 x1, x2, y1, y2);
adamdunkels09c28b62003-04-02 10:17:52 +0000435}
436/*-----------------------------------------------------------------------------------*/
437void
438ctk_draw_clear(unsigned char y1, unsigned char y2)
439{
440 unsigned char i;
441
442 for(i = y1; i < y2; ++i) {
443 cclearxy(0, i, sizex);
444 }
445}
446/*-----------------------------------------------------------------------------------*/
447static void
448draw_menu(struct ctk_menu *m)
449{
450 unsigned char x, x2, y;
451 textcolor(OPENMENUCOLOR);
452 x = wherex();
453 cputs(m->title);
454 cputc(' ');
455 x2 = wherex();
456 if(x + CTK_CONF_MENUWIDTH > sizex) {
457 x = sizex - CTK_CONF_MENUWIDTH;
458 }
459
460
461 for(y = 0; y < m->nitems; ++y) {
462 if(y == m->active) {
463 textcolor(ACTIVEMENUITEMCOLOR);
464 revers(0);
465 } else {
466 textcolor(MENUCOLOR);
467 }
468 gotoxy(x, y + 1);
469 if(m->items[y].title[0] == '-') {
470 chline(CTK_CONF_MENUWIDTH);
471 } else {
472 cputs(m->items[y].title);
473 }
474 if(x + CTK_CONF_MENUWIDTH > wherex()) {
475 cclear(x + CTK_CONF_MENUWIDTH - wherex());
476 }
477 revers(1);
478 }
479 gotoxy(x2, 0);
480 textcolor(MENUCOLOR);
481}
482/*-----------------------------------------------------------------------------------*/
483void
484ctk_draw_menus(struct ctk_menus *menus)
485{
486 struct ctk_menu *m;
adamdunkels62393fb2003-07-30 23:31:56 +0000487
adamdunkels09c28b62003-04-02 10:17:52 +0000488 /* Draw menus */
489 textcolor(MENUCOLOR);
490 gotoxy(0, 0);
491 revers(1);
adamdunkelse68091d2003-04-16 18:29:10 +0000492 cputc(' ');
adamdunkels09c28b62003-04-02 10:17:52 +0000493 for(m = menus->menus->next; m != NULL; m = m->next) {
494 if(m != menus->open) {
495 cputs(m->title);
496 cputc(' ');
497 } else {
498 draw_menu(m);
499 }
500 }
501
502
503 if(wherex() + strlen(menus->desktopmenu->title) + 1>= sizex) {
504 gotoxy(sizex - strlen(menus->desktopmenu->title) - 1, 0);
505 } else {
506 cclear(sizex - wherex() -
507 strlen(menus->desktopmenu->title) - 1);
508 }
509
510 /* Draw desktopmenu */
511 if(menus->desktopmenu != menus->open) {
512 cputs(menus->desktopmenu->title);
513 cputc(' ');
514 } else {
515 draw_menu(menus->desktopmenu);
516 }
517
518 revers(0);
519}
520/*-----------------------------------------------------------------------------------*/
521unsigned char
522ctk_draw_height(void)
523{
524 return sizey;
525}
526/*-----------------------------------------------------------------------------------*/
527unsigned char
528ctk_draw_width(void)
529{
530 return sizex;
531}
532/*-----------------------------------------------------------------------------------*/