blob: 1944ade191542b49b700763482ef357561d04f22 [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 *
adamdunkels76a4c4a2004-06-06 05:52:21 +000032 * $Id: ctk-conio.c,v 1.9 2004/06/06 05:52:21 adamdunkels 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/*-----------------------------------------------------------------------------------*/
51static char tmp[40];
52static void
53cputsn(char *str, unsigned char len)
54{
55 strncpy(tmp, str, len);
56 tmp[len] = 0;
57 cputs(tmp);
58}
59/*-----------------------------------------------------------------------------------*/
60void
61ctk_draw_init(void)
62{
63 bgcolor(SCREENCOLOR);
64 bordercolor(BORDERCOLOR);
65 screensize(&sizex, &sizey);
66 ctk_draw_clear(0, sizey);
67}
68/*-----------------------------------------------------------------------------------*/
69static void
70draw_widget(struct ctk_widget *w,
71 unsigned char x, unsigned char y,
72 unsigned char clipx,
73 unsigned char clipy,
74 unsigned char clipy1, unsigned char clipy2,
75 unsigned char focus)
76{
77 unsigned char xpos, ypos, xscroll;
78 unsigned char i, j;
79 char c, *text;
adamdunkels09e27572004-03-25 09:50:13 +000080 unsigned char len, wfocus;
81
82 wfocus = 0;
adamdunkels09c28b62003-04-02 10:17:52 +000083 if(focus & CTK_FOCUS_WINDOW) {
84 textcolor(WIDGETCOLOR_FWIN);
85 if(focus & CTK_FOCUS_WIDGET) {
86 textcolor(WIDGETCOLOR_FOCUS);
adamdunkels09e27572004-03-25 09:50:13 +000087 wfocus = 1;
adamdunkels09c28b62003-04-02 10:17:52 +000088 }
89 } else if(focus & CTK_FOCUS_DIALOG) {
90 textcolor(WIDGETCOLOR_DIALOG);
91 if(focus & CTK_FOCUS_WIDGET) {
92 textcolor(WIDGETCOLOR_FOCUS);
adamdunkels09e27572004-03-25 09:50:13 +000093 wfocus = 1;
adamdunkels09c28b62003-04-02 10:17:52 +000094 }
95 } else {
96 textcolor(WIDGETCOLOR);
97 }
98
99 xpos = x + w->x;
100 ypos = y + w->y;
101
102 switch(w->type) {
103 case CTK_WIDGET_SEPARATOR:
104 if(ypos >= clipy1 && ypos < clipy2) {
105 chlinexy(xpos, ypos, w->w);
106 }
107 break;
108 case CTK_WIDGET_LABEL:
109 text = w->widget.label.text;
adamdunkels62393fb2003-07-30 23:31:56 +0000110 for(i = 0; i < w->h; ++i) {
adamdunkels09c28b62003-04-02 10:17:52 +0000111 if(ypos >= clipy1 && ypos < clipy2) {
112 gotoxy(xpos, ypos);
113 cputsn(text, w->w);
114 if(w->w - (wherex() - xpos) > 0) {
115 cclear(w->w - (wherex() - xpos));
116 }
117 }
118 ++ypos;
119 text += w->w;
120 }
121 break;
122 case CTK_WIDGET_BUTTON:
123 if(ypos >= clipy1 && ypos < clipy2) {
adamdunkels09e27572004-03-25 09:50:13 +0000124 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000125 revers(1);
126 } else {
127 revers(0);
128 }
129 cputcxy(xpos, ypos, '[');
130 cputsn(w->widget.button.text, w->w);
131 cputc(']');
132 revers(0);
133 }
134 break;
135 case CTK_WIDGET_HYPERLINK:
136 if(ypos >= clipy1 && ypos < clipy2) {
adamdunkels09e27572004-03-25 09:50:13 +0000137 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000138 revers(0);
139 } else {
140 revers(1);
141 }
142 gotoxy(xpos, ypos);
143 textcolor(WIDGETCOLOR_HLINK);
144 cputsn(w->widget.button.text, w->w);
145 revers(0);
146 }
147 break;
148 case CTK_WIDGET_TEXTENTRY:
149 text = w->widget.textentry.text;
adamdunkels09e27572004-03-25 09:50:13 +0000150 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000151 revers(1);
152 } else {
153 revers(0);
154 }
155 xscroll = 0;
156 if(w->widget.textentry.xpos >= w->w - 1) {
157 xscroll = w->widget.textentry.xpos - w->w + 1;
158 }
adamdunkels62393fb2003-07-30 23:31:56 +0000159 for(j = 0; j < w->h; ++j) {
adamdunkels09c28b62003-04-02 10:17:52 +0000160 if(ypos >= clipy1 && ypos < clipy2) {
161 if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
162 w->widget.textentry.ypos == j) {
163 revers(0);
164 cputcxy(xpos, ypos, '>');
165 for(i = 0; i < w->w; ++i) {
166 c = text[i + xscroll];
167 if(i == w->widget.textentry.xpos - xscroll) {
168 revers(1);
169 } else {
170 revers(0);
171 }
172 if(c == 0) {
173 cputc(' ');
174 } else {
175 cputc(c);
176 }
177 revers(0);
178 }
179 cputc('<');
180 } else {
181 cvlinexy(xpos, ypos, 1);
182 gotoxy(xpos + 1, ypos);
183 cputsn(text, w->w);
184 i = wherex();
185 if(i - xpos - 1 < w->w) {
186 cclear(w->w - (i - xpos) + 1);
187 }
188 cvline(1);
189 }
190 }
191 ++ypos;
192 text += w->w;
193 }
194 revers(0);
195 break;
196 case CTK_WIDGET_ICON:
197 if(ypos >= clipy1 && ypos < clipy2) {
adamdunkelsc5ed2f02003-04-24 17:20:18 +0000198 if(focus & 1) {
adamdunkels09c28b62003-04-02 10:17:52 +0000199 revers(1);
200 } else {
201 revers(0);
202 }
203 gotoxy(xpos, ypos);
204 if(w->widget.icon.textmap != NULL) {
205 for(i = 0; i < 3; ++i) {
206 gotoxy(xpos, ypos);
207 if(ypos >= clipy1 && ypos < clipy2) {
208 cputc(w->widget.icon.textmap[0 + 3 * i]);
209 cputc(w->widget.icon.textmap[1 + 3 * i]);
210 cputc(w->widget.icon.textmap[2 + 3 * i]);
211 }
212 ++ypos;
213 }
214 }
215 x = xpos;
216
217 len = strlen(w->widget.icon.title);
218 if(x + len >= sizex) {
219 x = sizex - len;
220 }
221
222 gotoxy(x, ypos);
223 if(ypos >= clipy1 && ypos < clipy2) {
224 cputs(w->widget.icon.title);
225 }
226 revers(0);
227 }
228 break;
229
230 default:
231 break;
232 }
233}
234/*-----------------------------------------------------------------------------------*/
235void
236ctk_draw_widget(struct ctk_widget *w,
237 unsigned char focus,
238 unsigned char clipy1,
239 unsigned char clipy2)
240{
241 struct ctk_window *win = w->window;
242 unsigned char posx, posy;
243
244 posx = win->x + 1;
245 posy = win->y + 2;
246
247 if(w == win->focused) {
248 focus |= CTK_FOCUS_WIDGET;
249 }
250
251 draw_widget(w, posx, posy,
252 posx + win->w,
253 posy + win->h,
254 clipy1, clipy2,
255 focus);
adamdunkelsfe32f8d2003-04-28 20:31:48 +0000256
257#ifdef CTK_CONIO_CONF_UPDATE
258 CTK_CONIO_CONF_UPDATE();
259#endif /* CTK_CONIO_CONF_UPDATE */
adamdunkels09c28b62003-04-02 10:17:52 +0000260}
261/*-----------------------------------------------------------------------------------*/
262void
263ctk_draw_clear_window(struct ctk_window *window,
264 unsigned char focus,
265 unsigned char clipy1,
266 unsigned char clipy2)
267{
268 unsigned char i;
269 unsigned char h;
270
271
272 h = window->y + 2 + window->h;
273 /* Clear window contents. */
274 for(i = window->y + 2; i < h; ++i) {
275 if(i >= clipy1 && i < clipy2) {
276 cclearxy(window->x + 1, i, window->w);
277 }
278 }
279}
280/*-----------------------------------------------------------------------------------*/
adamdunkelsa45d8a12003-04-08 07:22:13 +0000281static void
282draw_window_contents(struct ctk_window *window, unsigned char focus,
283 unsigned char clipy1, unsigned char clipy2,
284 unsigned char x1, unsigned char x2,
285 unsigned char y1, unsigned char y2)
286{
287 struct ctk_widget *w;
288 unsigned char wfocus;
289
290 /* Draw inactive widgets. */
291 for(w = window->inactive; w != NULL; w = w->next) {
292 draw_widget(w, x1, y1, x2, y2,
293 clipy1, clipy2,
294 focus);
295 }
296
297 /* Draw active widgets. */
298 for(w = window->active; w != NULL; w = w->next) {
299 wfocus = focus;
300 if(w == window->focused) {
301 wfocus |= CTK_FOCUS_WIDGET;
302 }
303
304 draw_widget(w, x1, y1, x2, y2,
305 clipy1, clipy2,
306 wfocus);
307 }
308
adamdunkelsfe32f8d2003-04-28 20:31:48 +0000309#ifdef CTK_CONIO_CONF_UPDATE
310 CTK_CONIO_CONF_UPDATE();
311#endif /* CTK_CONIO_CONF_UPDATE */
312
adamdunkelsa45d8a12003-04-08 07:22:13 +0000313}
314/*-----------------------------------------------------------------------------------*/
adamdunkels09c28b62003-04-02 10:17:52 +0000315void
316ctk_draw_window(struct ctk_window *window, unsigned char focus,
317 unsigned char clipy1, unsigned char clipy2)
318{
319 unsigned char x, y;
320 unsigned char h;
adamdunkels09c28b62003-04-02 10:17:52 +0000321 unsigned char x1, y1, x2, y2;
322
323 if(window->y + 1 >= clipy2) {
324 return;
325 }
326
327 x = window->x;
328 y = window->y + 1;
329
330 if(focus & CTK_FOCUS_WINDOW) {
331 textcolor(WINDOWCOLOR_FOCUS);
332 } else {
333 textcolor(WINDOWCOLOR);
334 }
335
336 x1 = x + 1;
337 y1 = y + 1;
338 x2 = x1 + window->w;
339 y2 = y1 + window->h;
340
341 /* Draw window frame. */
342 if(y >= clipy1) {
343 cputcxy(x, y, CH_ULCORNER);
adamdunkels09c28b62003-04-02 10:17:52 +0000344 gotoxy(wherex() + window->titlelen + 2, wherey());
345 chline(window->w - (wherex() - x) - 2);
346 cputcxy(x2, y, CH_URCORNER);
347 }
348
349 h = window->h;
350
351 if(clipy1 > y1) {
352 if(clipy1 - y1 < h) {
353 h = clipy1 - y1;
adamdunkels62393fb2003-07-30 23:31:56 +0000354 y1 = clipy1;
adamdunkels09c28b62003-04-02 10:17:52 +0000355 } else {
356 h = 0;
357 }
358 }
359
adamdunkels62393fb2003-07-30 23:31:56 +0000360 if(clipy2 < y1 + h) {
adamdunkels09c28b62003-04-02 10:17:52 +0000361 if(y1 >= clipy2) {
362 h = 0;
363 } else {
364 h = clipy2 - y1;
365 }
366 }
adamdunkels62393fb2003-07-30 23:31:56 +0000367
adamdunkels09c28b62003-04-02 10:17:52 +0000368 cvlinexy(x, y1, h);
adamdunkels62393fb2003-07-30 23:31:56 +0000369 cvlinexy(x2, y1, h);
adamdunkels09c28b62003-04-02 10:17:52 +0000370
371 if(y + window->h >= clipy1 &&
372 y + window->h < clipy2) {
373 cputcxy(x, y2, CH_LLCORNER);
374 chlinexy(x1, y2, window->w);
375 cputcxy(x2, y2, CH_LRCORNER);
376 }
377
adamdunkelsa45d8a12003-04-08 07:22:13 +0000378 draw_window_contents(window, focus & CTK_FOCUS_WINDOW, clipy1, clipy2,
adamdunkels62393fb2003-07-30 23:31:56 +0000379 x1, x2, y + 1, y2);
adamdunkels09c28b62003-04-02 10:17:52 +0000380}
381/*-----------------------------------------------------------------------------------*/
382void
383ctk_draw_dialog(struct ctk_window *dialog)
384{
385 unsigned char x, y;
386 unsigned char i;
adamdunkels09c28b62003-04-02 10:17:52 +0000387 unsigned char x1, y1, x2, y2;
388
389 textcolor(DIALOGCOLOR);
390
391 x = dialog->x;
392 y = dialog->y + 1;
393
394
395 x1 = x + 1;
396 y1 = y + 1;
397 x2 = x1 + dialog->w;
398 y2 = y1 + dialog->h;
399
400
401 /* Draw dialog frame. */
402
403 cvlinexy(x, y1,
404 dialog->h);
405 cvlinexy(x2, y1,
406 dialog->h);
407
408 chlinexy(x1, y,
409 dialog->w);
410 chlinexy(x1, y2,
411 dialog->w);
412
413 cputcxy(x, y, CH_ULCORNER);
414 cputcxy(x, y2, CH_LLCORNER);
415 cputcxy(x2, y, CH_URCORNER);
416 cputcxy(x2, y2, CH_LRCORNER);
417
418
adamdunkels09c28b62003-04-02 10:17:52 +0000419 /* Clear dialog contents. */
420 for(i = y1; i < y2; ++i) {
421 cclearxy(x1, i, dialog->w);
422 }
adamdunkels09c28b62003-04-02 10:17:52 +0000423
adamdunkelsa45d8a12003-04-08 07:22:13 +0000424 draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
425 x1, x2, y1, y2);
adamdunkels09c28b62003-04-02 10:17:52 +0000426}
427/*-----------------------------------------------------------------------------------*/
428void
429ctk_draw_clear(unsigned char y1, unsigned char y2)
430{
431 unsigned char i;
432
433 for(i = y1; i < y2; ++i) {
434 cclearxy(0, i, sizex);
435 }
436}
437/*-----------------------------------------------------------------------------------*/
438static void
439draw_menu(struct ctk_menu *m)
440{
441 unsigned char x, x2, y;
442 textcolor(OPENMENUCOLOR);
443 x = wherex();
444 cputs(m->title);
445 cputc(' ');
446 x2 = wherex();
447 if(x + CTK_CONF_MENUWIDTH > sizex) {
448 x = sizex - CTK_CONF_MENUWIDTH;
449 }
450
451
452 for(y = 0; y < m->nitems; ++y) {
453 if(y == m->active) {
454 textcolor(ACTIVEMENUITEMCOLOR);
455 revers(0);
456 } else {
457 textcolor(MENUCOLOR);
458 }
459 gotoxy(x, y + 1);
460 if(m->items[y].title[0] == '-') {
461 chline(CTK_CONF_MENUWIDTH);
462 } else {
463 cputs(m->items[y].title);
464 }
465 if(x + CTK_CONF_MENUWIDTH > wherex()) {
466 cclear(x + CTK_CONF_MENUWIDTH - wherex());
467 }
468 revers(1);
469 }
470 gotoxy(x2, 0);
471 textcolor(MENUCOLOR);
472}
473/*-----------------------------------------------------------------------------------*/
474void
475ctk_draw_menus(struct ctk_menus *menus)
476{
477 struct ctk_menu *m;
adamdunkels62393fb2003-07-30 23:31:56 +0000478
adamdunkels09c28b62003-04-02 10:17:52 +0000479 /* Draw menus */
480 textcolor(MENUCOLOR);
481 gotoxy(0, 0);
482 revers(1);
adamdunkelse68091d2003-04-16 18:29:10 +0000483 cputc(' ');
adamdunkels09c28b62003-04-02 10:17:52 +0000484 for(m = menus->menus->next; m != NULL; m = m->next) {
485 if(m != menus->open) {
486 cputs(m->title);
487 cputc(' ');
488 } else {
489 draw_menu(m);
490 }
491 }
492
493
494 if(wherex() + strlen(menus->desktopmenu->title) + 1>= sizex) {
495 gotoxy(sizex - strlen(menus->desktopmenu->title) - 1, 0);
496 } else {
497 cclear(sizex - wherex() -
498 strlen(menus->desktopmenu->title) - 1);
499 }
500
501 /* Draw desktopmenu */
502 if(menus->desktopmenu != menus->open) {
503 cputs(menus->desktopmenu->title);
504 cputc(' ');
505 } else {
506 draw_menu(menus->desktopmenu);
507 }
508
509 revers(0);
510}
511/*-----------------------------------------------------------------------------------*/
512unsigned char
513ctk_draw_height(void)
514{
515 return sizey;
516}
517/*-----------------------------------------------------------------------------------*/
518unsigned char
519ctk_draw_width(void)
520{
521 return sizex;
522}
523/*-----------------------------------------------------------------------------------*/