blob: 423307a254289635342af339a0fd24760a227a2a [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.
14 * 3. All advertising materials mentioning features or use of this
15 * software must display the following acknowledgement:
16 * This product includes software developed by Adam Dunkels.
17 * 4. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * This file is part of the "ctk" console GUI toolkit for cc65
34 *
adamdunkels09e27572004-03-25 09:50:13 +000035 * $Id: ctk-conio.c,v 1.8 2004/03/25 09:50:13 adamdunkels Exp $
adamdunkels09c28b62003-04-02 10:17:52 +000036 *
37 */
38
adamdunkels09e27572004-03-25 09:50:13 +000039#include <conio.h>
40
adamdunkels09c28b62003-04-02 10:17:52 +000041#include "ctk.h"
42#include "ctk-draw.h"
43
44#include "ctk-conio-conf.h"
adamdunkels09c28b62003-04-02 10:17:52 +000045#include <string.h>
46
47#ifndef NULL
48#define NULL (void *)0
49#endif /* NULL */
50
51static unsigned char sizex, sizey;
52
53/*-----------------------------------------------------------------------------------*/
54static char tmp[40];
55static void
56cputsn(char *str, unsigned char len)
57{
58 strncpy(tmp, str, len);
59 tmp[len] = 0;
60 cputs(tmp);
61}
62/*-----------------------------------------------------------------------------------*/
63void
64ctk_draw_init(void)
65{
66 bgcolor(SCREENCOLOR);
67 bordercolor(BORDERCOLOR);
68 screensize(&sizex, &sizey);
69 ctk_draw_clear(0, sizey);
70}
71/*-----------------------------------------------------------------------------------*/
72static void
73draw_widget(struct ctk_widget *w,
74 unsigned char x, unsigned char y,
75 unsigned char clipx,
76 unsigned char clipy,
77 unsigned char clipy1, unsigned char clipy2,
78 unsigned char focus)
79{
80 unsigned char xpos, ypos, xscroll;
81 unsigned char i, j;
82 char c, *text;
adamdunkels09e27572004-03-25 09:50:13 +000083 unsigned char len, wfocus;
84
85 wfocus = 0;
adamdunkels09c28b62003-04-02 10:17:52 +000086 if(focus & CTK_FOCUS_WINDOW) {
87 textcolor(WIDGETCOLOR_FWIN);
88 if(focus & CTK_FOCUS_WIDGET) {
89 textcolor(WIDGETCOLOR_FOCUS);
adamdunkels09e27572004-03-25 09:50:13 +000090 wfocus = 1;
adamdunkels09c28b62003-04-02 10:17:52 +000091 }
92 } else if(focus & CTK_FOCUS_DIALOG) {
93 textcolor(WIDGETCOLOR_DIALOG);
94 if(focus & CTK_FOCUS_WIDGET) {
95 textcolor(WIDGETCOLOR_FOCUS);
adamdunkels09e27572004-03-25 09:50:13 +000096 wfocus = 1;
adamdunkels09c28b62003-04-02 10:17:52 +000097 }
98 } else {
99 textcolor(WIDGETCOLOR);
100 }
101
102 xpos = x + w->x;
103 ypos = y + w->y;
104
105 switch(w->type) {
106 case CTK_WIDGET_SEPARATOR:
107 if(ypos >= clipy1 && ypos < clipy2) {
108 chlinexy(xpos, ypos, w->w);
109 }
110 break;
111 case CTK_WIDGET_LABEL:
112 text = w->widget.label.text;
adamdunkels62393fb2003-07-30 23:31:56 +0000113 for(i = 0; i < w->h; ++i) {
adamdunkels09c28b62003-04-02 10:17:52 +0000114 if(ypos >= clipy1 && ypos < clipy2) {
115 gotoxy(xpos, ypos);
116 cputsn(text, w->w);
117 if(w->w - (wherex() - xpos) > 0) {
118 cclear(w->w - (wherex() - xpos));
119 }
120 }
121 ++ypos;
122 text += w->w;
123 }
124 break;
125 case CTK_WIDGET_BUTTON:
126 if(ypos >= clipy1 && ypos < clipy2) {
adamdunkels09e27572004-03-25 09:50:13 +0000127 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000128 revers(1);
129 } else {
130 revers(0);
131 }
132 cputcxy(xpos, ypos, '[');
133 cputsn(w->widget.button.text, w->w);
134 cputc(']');
135 revers(0);
136 }
137 break;
138 case CTK_WIDGET_HYPERLINK:
139 if(ypos >= clipy1 && ypos < clipy2) {
adamdunkels09e27572004-03-25 09:50:13 +0000140 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000141 revers(0);
142 } else {
143 revers(1);
144 }
145 gotoxy(xpos, ypos);
146 textcolor(WIDGETCOLOR_HLINK);
147 cputsn(w->widget.button.text, w->w);
148 revers(0);
149 }
150 break;
151 case CTK_WIDGET_TEXTENTRY:
152 text = w->widget.textentry.text;
adamdunkels09e27572004-03-25 09:50:13 +0000153 if(wfocus != 0) {
adamdunkels09c28b62003-04-02 10:17:52 +0000154 revers(1);
155 } else {
156 revers(0);
157 }
158 xscroll = 0;
159 if(w->widget.textentry.xpos >= w->w - 1) {
160 xscroll = w->widget.textentry.xpos - w->w + 1;
161 }
adamdunkels62393fb2003-07-30 23:31:56 +0000162 for(j = 0; j < w->h; ++j) {
adamdunkels09c28b62003-04-02 10:17:52 +0000163 if(ypos >= clipy1 && ypos < clipy2) {
164 if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
165 w->widget.textentry.ypos == j) {
166 revers(0);
167 cputcxy(xpos, ypos, '>');
168 for(i = 0; i < w->w; ++i) {
169 c = text[i + xscroll];
170 if(i == w->widget.textentry.xpos - xscroll) {
171 revers(1);
172 } else {
173 revers(0);
174 }
175 if(c == 0) {
176 cputc(' ');
177 } else {
178 cputc(c);
179 }
180 revers(0);
181 }
182 cputc('<');
183 } else {
184 cvlinexy(xpos, ypos, 1);
185 gotoxy(xpos + 1, ypos);
186 cputsn(text, w->w);
187 i = wherex();
188 if(i - xpos - 1 < w->w) {
189 cclear(w->w - (i - xpos) + 1);
190 }
191 cvline(1);
192 }
193 }
194 ++ypos;
195 text += w->w;
196 }
197 revers(0);
198 break;
199 case CTK_WIDGET_ICON:
200 if(ypos >= clipy1 && ypos < clipy2) {
adamdunkelsc5ed2f02003-04-24 17:20:18 +0000201 if(focus & 1) {
adamdunkels09c28b62003-04-02 10:17:52 +0000202 revers(1);
203 } else {
204 revers(0);
205 }
206 gotoxy(xpos, ypos);
207 if(w->widget.icon.textmap != NULL) {
208 for(i = 0; i < 3; ++i) {
209 gotoxy(xpos, ypos);
210 if(ypos >= clipy1 && ypos < clipy2) {
211 cputc(w->widget.icon.textmap[0 + 3 * i]);
212 cputc(w->widget.icon.textmap[1 + 3 * i]);
213 cputc(w->widget.icon.textmap[2 + 3 * i]);
214 }
215 ++ypos;
216 }
217 }
218 x = xpos;
219
220 len = strlen(w->widget.icon.title);
221 if(x + len >= sizex) {
222 x = sizex - len;
223 }
224
225 gotoxy(x, ypos);
226 if(ypos >= clipy1 && ypos < clipy2) {
227 cputs(w->widget.icon.title);
228 }
229 revers(0);
230 }
231 break;
232
233 default:
234 break;
235 }
236}
237/*-----------------------------------------------------------------------------------*/
238void
239ctk_draw_widget(struct ctk_widget *w,
240 unsigned char focus,
241 unsigned char clipy1,
242 unsigned char clipy2)
243{
244 struct ctk_window *win = w->window;
245 unsigned char posx, posy;
246
247 posx = win->x + 1;
248 posy = win->y + 2;
249
250 if(w == win->focused) {
251 focus |= CTK_FOCUS_WIDGET;
252 }
253
254 draw_widget(w, posx, posy,
255 posx + win->w,
256 posy + win->h,
257 clipy1, clipy2,
258 focus);
adamdunkelsfe32f8d2003-04-28 20:31:48 +0000259
260#ifdef CTK_CONIO_CONF_UPDATE
261 CTK_CONIO_CONF_UPDATE();
262#endif /* CTK_CONIO_CONF_UPDATE */
adamdunkels09c28b62003-04-02 10:17:52 +0000263}
264/*-----------------------------------------------------------------------------------*/
265void
266ctk_draw_clear_window(struct ctk_window *window,
267 unsigned char focus,
268 unsigned char clipy1,
269 unsigned char clipy2)
270{
271 unsigned char i;
272 unsigned char h;
273
274
275 h = window->y + 2 + window->h;
276 /* Clear window contents. */
277 for(i = window->y + 2; i < h; ++i) {
278 if(i >= clipy1 && i < clipy2) {
279 cclearxy(window->x + 1, i, window->w);
280 }
281 }
282}
283/*-----------------------------------------------------------------------------------*/
adamdunkelsa45d8a12003-04-08 07:22:13 +0000284static void
285draw_window_contents(struct ctk_window *window, unsigned char focus,
286 unsigned char clipy1, unsigned char clipy2,
287 unsigned char x1, unsigned char x2,
288 unsigned char y1, unsigned char y2)
289{
290 struct ctk_widget *w;
291 unsigned char wfocus;
292
293 /* Draw inactive widgets. */
294 for(w = window->inactive; w != NULL; w = w->next) {
295 draw_widget(w, x1, y1, x2, y2,
296 clipy1, clipy2,
297 focus);
298 }
299
300 /* Draw active widgets. */
301 for(w = window->active; w != NULL; w = w->next) {
302 wfocus = focus;
303 if(w == window->focused) {
304 wfocus |= CTK_FOCUS_WIDGET;
305 }
306
307 draw_widget(w, x1, y1, x2, y2,
308 clipy1, clipy2,
309 wfocus);
310 }
311
adamdunkelsfe32f8d2003-04-28 20:31:48 +0000312#ifdef CTK_CONIO_CONF_UPDATE
313 CTK_CONIO_CONF_UPDATE();
314#endif /* CTK_CONIO_CONF_UPDATE */
315
adamdunkelsa45d8a12003-04-08 07:22:13 +0000316}
317/*-----------------------------------------------------------------------------------*/
adamdunkels09c28b62003-04-02 10:17:52 +0000318void
319ctk_draw_window(struct ctk_window *window, unsigned char focus,
320 unsigned char clipy1, unsigned char clipy2)
321{
322 unsigned char x, y;
323 unsigned char h;
adamdunkels09c28b62003-04-02 10:17:52 +0000324 unsigned char x1, y1, x2, y2;
325
326 if(window->y + 1 >= clipy2) {
327 return;
328 }
329
330 x = window->x;
331 y = window->y + 1;
332
333 if(focus & CTK_FOCUS_WINDOW) {
334 textcolor(WINDOWCOLOR_FOCUS);
335 } else {
336 textcolor(WINDOWCOLOR);
337 }
338
339 x1 = x + 1;
340 y1 = y + 1;
341 x2 = x1 + window->w;
342 y2 = y1 + window->h;
343
344 /* Draw window frame. */
345 if(y >= clipy1) {
346 cputcxy(x, y, CH_ULCORNER);
adamdunkels09c28b62003-04-02 10:17:52 +0000347 gotoxy(wherex() + window->titlelen + 2, wherey());
348 chline(window->w - (wherex() - x) - 2);
349 cputcxy(x2, y, CH_URCORNER);
350 }
351
352 h = window->h;
353
354 if(clipy1 > y1) {
355 if(clipy1 - y1 < h) {
356 h = clipy1 - y1;
adamdunkels62393fb2003-07-30 23:31:56 +0000357 y1 = clipy1;
adamdunkels09c28b62003-04-02 10:17:52 +0000358 } else {
359 h = 0;
360 }
361 }
362
adamdunkels62393fb2003-07-30 23:31:56 +0000363 if(clipy2 < y1 + h) {
adamdunkels09c28b62003-04-02 10:17:52 +0000364 if(y1 >= clipy2) {
365 h = 0;
366 } else {
367 h = clipy2 - y1;
368 }
369 }
adamdunkels62393fb2003-07-30 23:31:56 +0000370
adamdunkels09c28b62003-04-02 10:17:52 +0000371 cvlinexy(x, y1, h);
adamdunkels62393fb2003-07-30 23:31:56 +0000372 cvlinexy(x2, y1, h);
adamdunkels09c28b62003-04-02 10:17:52 +0000373
374 if(y + window->h >= clipy1 &&
375 y + window->h < clipy2) {
376 cputcxy(x, y2, CH_LLCORNER);
377 chlinexy(x1, y2, window->w);
378 cputcxy(x2, y2, CH_LRCORNER);
379 }
380
adamdunkelsa45d8a12003-04-08 07:22:13 +0000381 draw_window_contents(window, focus & CTK_FOCUS_WINDOW, clipy1, clipy2,
adamdunkels62393fb2003-07-30 23:31:56 +0000382 x1, x2, y + 1, y2);
adamdunkels09c28b62003-04-02 10:17:52 +0000383}
384/*-----------------------------------------------------------------------------------*/
385void
386ctk_draw_dialog(struct ctk_window *dialog)
387{
388 unsigned char x, y;
389 unsigned char i;
adamdunkels09c28b62003-04-02 10:17:52 +0000390 unsigned char x1, y1, x2, y2;
391
392 textcolor(DIALOGCOLOR);
393
394 x = dialog->x;
395 y = dialog->y + 1;
396
397
398 x1 = x + 1;
399 y1 = y + 1;
400 x2 = x1 + dialog->w;
401 y2 = y1 + dialog->h;
402
403
404 /* Draw dialog frame. */
405
406 cvlinexy(x, y1,
407 dialog->h);
408 cvlinexy(x2, y1,
409 dialog->h);
410
411 chlinexy(x1, y,
412 dialog->w);
413 chlinexy(x1, y2,
414 dialog->w);
415
416 cputcxy(x, y, CH_ULCORNER);
417 cputcxy(x, y2, CH_LLCORNER);
418 cputcxy(x2, y, CH_URCORNER);
419 cputcxy(x2, y2, CH_LRCORNER);
420
421
adamdunkels09c28b62003-04-02 10:17:52 +0000422 /* Clear dialog contents. */
423 for(i = y1; i < y2; ++i) {
424 cclearxy(x1, i, dialog->w);
425 }
adamdunkels09c28b62003-04-02 10:17:52 +0000426
adamdunkelsa45d8a12003-04-08 07:22:13 +0000427 draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
428 x1, x2, y1, y2);
adamdunkels09c28b62003-04-02 10:17:52 +0000429}
430/*-----------------------------------------------------------------------------------*/
431void
432ctk_draw_clear(unsigned char y1, unsigned char y2)
433{
434 unsigned char i;
435
436 for(i = y1; i < y2; ++i) {
437 cclearxy(0, i, sizex);
438 }
439}
440/*-----------------------------------------------------------------------------------*/
441static void
442draw_menu(struct ctk_menu *m)
443{
444 unsigned char x, x2, y;
445 textcolor(OPENMENUCOLOR);
446 x = wherex();
447 cputs(m->title);
448 cputc(' ');
449 x2 = wherex();
450 if(x + CTK_CONF_MENUWIDTH > sizex) {
451 x = sizex - CTK_CONF_MENUWIDTH;
452 }
453
454
455 for(y = 0; y < m->nitems; ++y) {
456 if(y == m->active) {
457 textcolor(ACTIVEMENUITEMCOLOR);
458 revers(0);
459 } else {
460 textcolor(MENUCOLOR);
461 }
462 gotoxy(x, y + 1);
463 if(m->items[y].title[0] == '-') {
464 chline(CTK_CONF_MENUWIDTH);
465 } else {
466 cputs(m->items[y].title);
467 }
468 if(x + CTK_CONF_MENUWIDTH > wherex()) {
469 cclear(x + CTK_CONF_MENUWIDTH - wherex());
470 }
471 revers(1);
472 }
473 gotoxy(x2, 0);
474 textcolor(MENUCOLOR);
475}
476/*-----------------------------------------------------------------------------------*/
477void
478ctk_draw_menus(struct ctk_menus *menus)
479{
480 struct ctk_menu *m;
adamdunkels62393fb2003-07-30 23:31:56 +0000481
adamdunkels09c28b62003-04-02 10:17:52 +0000482 /* Draw menus */
483 textcolor(MENUCOLOR);
484 gotoxy(0, 0);
485 revers(1);
adamdunkelse68091d2003-04-16 18:29:10 +0000486 cputc(' ');
adamdunkels09c28b62003-04-02 10:17:52 +0000487 for(m = menus->menus->next; m != NULL; m = m->next) {
488 if(m != menus->open) {
489 cputs(m->title);
490 cputc(' ');
491 } else {
492 draw_menu(m);
493 }
494 }
495
496
497 if(wherex() + strlen(menus->desktopmenu->title) + 1>= sizex) {
498 gotoxy(sizex - strlen(menus->desktopmenu->title) - 1, 0);
499 } else {
500 cclear(sizex - wherex() -
501 strlen(menus->desktopmenu->title) - 1);
502 }
503
504 /* Draw desktopmenu */
505 if(menus->desktopmenu != menus->open) {
506 cputs(menus->desktopmenu->title);
507 cputc(' ');
508 } else {
509 draw_menu(menus->desktopmenu);
510 }
511
512 revers(0);
513}
514/*-----------------------------------------------------------------------------------*/
515unsigned char
516ctk_draw_height(void)
517{
518 return sizey;
519}
520/*-----------------------------------------------------------------------------------*/
521unsigned char
522ctk_draw_width(void)
523{
524 return sizex;
525}
526/*-----------------------------------------------------------------------------------*/