blob: fe10cfcbf621d4494a8f305a5779319ec77fbb7c [file] [log] [blame]
PulkoMandyc53d0f62014-07-01 22:35:10 +02001/*
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. The name of the author may not be used to endorse or promote
15 * 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 *
32 * $Id: ctk-conio-service.c,v 1.12 2006/05/28 20:38:19 oliverschmidt Exp $
33 *
34 */
35
36#include <conio.h>
37
38#include "ctk.h"
39#include "ctk-draw.h"
40
41#include "ctk-draw-service.h"
42
43#include "ctk-conio-conf.h"
44#include <string.h>
45
46#ifndef NULL
47#define NULL (void *)0
48#endif /* NULL */
49
50static unsigned char sizex, sizey;
51
52/*unsigned char ctk_draw_windowborder_height = 1;
53unsigned char ctk_draw_windowborder_width = 1;
54unsigned char ctk_draw_windowtitle_height = 1;*/
55
56// The revers function does nothing in our conio driver anyway.
57#define revers(x)
58
59/*-----------------------------------------------------------------------------------*/
60static void
61cputsn(char *str, unsigned char len)
62{
63 char c;
64
65 while(len > 0) {
66 --len;
67 c = *str;
68 if(c == 0) {
69 break;
70 }
71 cputc(c);
72 ++str;
73 }
74}
75/*-----------------------------------------------------------------------------------*/
76static void
77s_ctk_draw_init(void)
78{
79 (void)bgcolor(SCREENCOLOR);
80 (void)bordercolor(BORDERCOLOR);
PulkoMandy25ff0502014-07-03 09:55:24 +020081 clrscr();
PulkoMandyc53d0f62014-07-01 22:35:10 +020082 screensize(&sizex, &sizey);
PulkoMandyc53d0f62014-07-01 22:35:10 +020083}
84/*-----------------------------------------------------------------------------------*/
PulkoMandydf52c592014-07-03 15:36:50 +020085
86
87static void customchr(unsigned char* data) __naked
88{
89 __asm
90 pop de
91 pop hl
92 push hl
93 push de
94 ld a,#0xff
95 jp 0xbba8 ; SCR SET MATRIX
96 __endasm;
97}
98
99
PulkoMandyc53d0f62014-07-01 22:35:10 +0200100static void
101draw_widget(struct ctk_widget *w,
102 unsigned char x, unsigned char y,
103 unsigned char clipx,
104 unsigned char clipy,
105 unsigned char clipy1, unsigned char clipy2,
106 unsigned char focus)
107{
108 unsigned char xpos, ypos, xscroll;
109 unsigned char i, j;
110 char c, *text;
111 unsigned char len, wfocus;
112
113 wfocus = 0;
114 if(focus & CTK_FOCUS_WINDOW) {
115 (void)textcolor(WIDGETCOLOR_FWIN);
116 if(focus & CTK_FOCUS_WIDGET) {
117 (void)textcolor(WIDGETCOLOR_FOCUS);
118 wfocus = 1;
119 }
120 } else if(focus & CTK_FOCUS_DIALOG) {
121 (void)textcolor(WIDGETCOLOR_DIALOG);
122 if(focus & CTK_FOCUS_WIDGET) {
123 (void)textcolor(WIDGETCOLOR_FOCUS);
124 wfocus = 1;
125 }
126 } else {
127 (void)textcolor(WIDGETCOLOR);
128 }
129
130 xpos = x + w->x;
131 ypos = y + w->y;
132
133 switch(w->type) {
134 case CTK_WIDGET_SEPARATOR:
135 if(ypos >= clipy1 && ypos < clipy2) {
136 chlinexy(xpos, ypos, w->w);
137 }
138 break;
139 case CTK_WIDGET_LABEL:
140 text = w->widget.label.text;
141 for(i = 0; i < w->h; ++i) {
142 if(ypos >= clipy1 && ypos < clipy2) {
143 gotoxy(xpos, ypos);
144 cputsn(text, w->w);
145 if(w->w - (wherex() - xpos) > 0) {
146 cclear(w->w - (wherex() - xpos));
147 }
148 }
149 ++ypos;
150 text += w->w;
151 }
152 break;
153 case CTK_WIDGET_BUTTON:
154 if(ypos >= clipy1 && ypos < clipy2) {
155 revers(wfocus != 0);
156 cputcxy(xpos, ypos, '[');
157 cputsn(w->widget.button.text, w->w);
158 cputc(']');
159 revers(0);
160 }
161 break;
162 case CTK_WIDGET_HYPERLINK:
163 if(ypos >= clipy1 && ypos < clipy2) {
164 (void)textcolor(WIDGETCOLOR_HLINK);
165 revers(wfocus == 0);
166 gotoxy(xpos, ypos);
167 cputsn(w->widget.button.text, w->w);
168 revers(0);
169 }
170 break;
171 case CTK_WIDGET_TEXTENTRY:
172 text = w->widget.textentry.text;
173 xscroll = 0;
174 if(w->widget.textentry.xpos >= w->w - 1) {
175 xscroll = w->widget.textentry.xpos - w->w + 1;
176 }
177 for(j = 0; j < w->h; ++j) {
178 if(ypos >= clipy1 && ypos < clipy2) {
179 if(w->widget.textentry.state == CTK_TEXTENTRY_EDIT &&
180 w->widget.textentry.ypos == j) {
181 revers(0);
182 cputcxy(xpos, ypos, '>');
183 c = 1;
184 for(i = 0; i < w->w; ++i) {
185 if(c != 0) {
186 c = text[i + xscroll];
187 }
188 revers(i == w->widget.textentry.xpos - xscroll);
189 if(c == 0) {
190 cputc(' ');
191 } else {
192 cputc(c);
193 }
194 }
195 revers(0);
196 cputc('<');
197 } else {
198 revers(wfocus != 0 && j == w->widget.textentry.ypos);
199 cvlinexy(xpos, ypos, 1);
200 gotoxy(xpos + 1, ypos);
201 cputsn(text, w->w);
202 i = wherex();
203 if(i - xpos - 1 < w->w) {
204 cclear(w->w - (i - xpos) + 1);
205 }
206 cvline(1);
207 }
208 }
209 ++ypos;
210 text += w->widget.textentry.len + 1;
211 }
212 revers(0);
213 break;
214 case CTK_WIDGET_ICON:
PulkoMandydf52c592014-07-03 15:36:50 +0200215
PulkoMandyc53d0f62014-07-01 22:35:10 +0200216 if(ypos >= clipy1 && ypos < clipy2) {
217 revers(wfocus != 0);
PulkoMandydf52c592014-07-03 15:36:50 +0200218#if CTK_CONF_ICON_BITMAPS
219 gotoxy(xpos, ypos);
220 if(w->widget.icon.bitmap != NULL) {
221 unsigned char* ptr = w->widget.icon.bitmap;
222 printf("ICON BMP %p\r\n", ptr);
223 for(i = 0; i < 3; ++i) {
224 gotoxy(xpos, ypos);
225 if(ypos >= clipy1 && ypos < clipy2) {
226 customchr(ptr);
227 cputc(0xff);
228 ptr += 8;
229 customchr(ptr);
230 cputc(0xff);
231 ptr += 8;
232 customchr(ptr);
233 cputc(0xff);
234 ptr += 8;
235 }
236 ++ypos;
237 }
238 }
239#elif CTK_CONF_ICON_TEXTMAPS
PulkoMandyc53d0f62014-07-01 22:35:10 +0200240 gotoxy(xpos, ypos);
241 if(w->widget.icon.textmap != NULL) {
242 for(i = 0; i < 3; ++i) {
243 gotoxy(xpos, ypos);
244 if(ypos >= clipy1 && ypos < clipy2) {
245 cputc(w->widget.icon.textmap[0 + 3 * i]);
246 cputc(w->widget.icon.textmap[1 + 3 * i]);
247 cputc(w->widget.icon.textmap[2 + 3 * i]);
248 }
249 ++ypos;
250 }
251 }
PulkoMandydf52c592014-07-03 15:36:50 +0200252#endif
PulkoMandyc53d0f62014-07-01 22:35:10 +0200253 x = xpos;
254
255 len = strlen(w->widget.icon.title);
256 if(x + len >= sizex) {
257 x = sizex - len;
258 }
259
260 gotoxy(x, ypos);
261 if(ypos >= clipy1 && ypos < clipy2) {
262 cputs(w->widget.icon.title);
263 }
264 revers(0);
265 }
266 break;
267
268 default:
269 break;
270 }
271}
272/*-----------------------------------------------------------------------------------*/
273static void
274s_ctk_draw_widget(struct ctk_widget *w,
275 unsigned char focus,
276 unsigned char clipy1,
277 unsigned char clipy2)
278{
279 struct ctk_window *win = w->window;
280 unsigned char posx, posy;
281
282 posx = win->x + 1;
283 posy = win->y + 2;
284
285 if(w == win->focused) {
286 focus |= CTK_FOCUS_WIDGET;
287 }
288
289 draw_widget(w, posx, posy,
290 posx + win->w,
291 posy + win->h,
292 clipy1, clipy2,
293 focus);
294
295#ifdef CTK_CONIO_CONF_UPDATE
296 CTK_CONIO_CONF_UPDATE();
297#endif /* CTK_CONIO_CONF_UPDATE */
298}
299/*-----------------------------------------------------------------------------------*/
300
PulkoMandy25ff0502014-07-03 09:55:24 +0200301static void clearrect(unsigned char x2, unsigned char y2,
302 unsigned char x1, unsigned char y1)
PulkoMandyc53d0f62014-07-01 22:35:10 +0200303{
304 __asm
305 ld hl,#2
306 add hl,sp
307 ld d,(hl) ; X1
308 inc hl
309 ld e,(hl) ; Y1
310 inc hl
311 ld a,(hl) ; X2
312 inc hl
313 ld l,(hl) ; Y2
314
315 ld h,a
316
317 call 0xBB99 ; TXT GET PAPER
318 call 0xBC2C ; SCR INK ENCODE
319
320 jp 0xBC44 ; SCR FILL BOX
321 __endasm;
322}
323
324static void
325s_ctk_draw_clear_window(struct ctk_window *window,
326 unsigned char focus,
327 unsigned char clipy1,
328 unsigned char clipy2)
329{
330 unsigned char i;
331 unsigned char h;
332
333 /*
334 if(focus & CTK_FOCUS_WINDOW) {
335 (void)textcolor(WINDOWCOLOR_FOCUS);
336 } else {
337 (void)textcolor(WINDOWCOLOR);
338 }
339 */
340
PulkoMandy25ff0502014-07-03 09:55:24 +0200341 i = window->y + 2; // +1 for the border, +1 for ctk > cpc conversion
342 h = i + window->h;
PulkoMandyc53d0f62014-07-01 22:35:10 +0200343
PulkoMandy25ff0502014-07-03 09:55:24 +0200344 if (i < clipy1) i = clipy1;
345 --clipy2;
346 if (h > clipy2) h = clipy2;
347
348 clearrect(window->x + window->w, h, window->x + 1, i);
PulkoMandyc53d0f62014-07-01 22:35:10 +0200349}
350/*-----------------------------------------------------------------------------------*/
351static void
352draw_window_contents(struct ctk_window *window, unsigned char focus,
353 unsigned char clipy1, unsigned char clipy2,
354 unsigned char x1, unsigned char x2,
355 unsigned char y1, unsigned char y2)
356{
357 struct ctk_widget *w;
358 unsigned char wfocus;
359
360 /* Draw inactive widgets. */
361 for(w = window->inactive; w != NULL; w = w->next) {
362 draw_widget(w, x1, y1, x2, y2,
363 clipy1, clipy2,
364 focus);
365 }
366
367 /* Draw active widgets. */
368 for(w = window->active; w != NULL; w = w->next) {
369 wfocus = focus;
370 if(w == window->focused) {
371 wfocus |= CTK_FOCUS_WIDGET;
372 }
373
374 draw_widget(w, x1, y1, x2, y2,
375 clipy1, clipy2,
376 wfocus);
377 }
378
379#ifdef CTK_CONIO_CONF_UPDATE
380 CTK_CONIO_CONF_UPDATE();
381#endif /* CTK_CONIO_CONF_UPDATE */
382}
383/*-----------------------------------------------------------------------------------*/
384static void
385s_ctk_draw_window(struct ctk_window *window, unsigned char focus,
386 unsigned char clipy1, unsigned char clipy2,
387 unsigned char draw_borders)
388{
389 unsigned char x, y;
390 unsigned char h;
391 unsigned char x1, y1, x2, y2;
392
393 if(window->y + 1 >= clipy2) {
394 return;
395 }
396
397 x = window->x;
398 y = window->y + 1;
399 x1 = x + 1;
400 y1 = y + 1;
401 x2 = x1 + window->w;
402 y2 = y1 + window->h;
403
404 if(draw_borders) {
405
406 /* Draw window frame. */
407 if(focus & CTK_FOCUS_WINDOW) {
408 (void)textcolor(WINDOWCOLOR_FOCUS);
409 } else {
410 (void)textcolor(WINDOWCOLOR);
411 }
412
413 if(y >= clipy1) {
414 cputcxy(x, y, CH_ULCORNER);
415 gotoxy(wherex() + window->titlelen + CTK_CONF_WINDOWMOVE * 2, wherey());
416 chline(window->w - (wherex() - x) - 2);
417 cputcxy(x2, y, CH_URCORNER);
418 }
419
420 h = window->h;
421
422 if(clipy1 > y1) {
423 if(clipy1 - y1 < h) {
424 h = clipy1 - y1;
425 y1 = clipy1;
426 } else {
427 h = 0;
428 }
429 }
430
431 if(clipy2 < y1 + h) {
432 if(y1 >= clipy2) {
433 h = 0;
434 } else {
435 h = clipy2 - y1;
436 }
437 }
438
439 cvlinexy(x, y1, h);
440 cvlinexy(x2, y1, h);
441
442 if(y + window->h >= clipy1 &&
443 y + window->h < clipy2) {
444 cputcxy(x, y2, CH_LLCORNER);
445 chlinexy(x1, y2, window->w);
446 cputcxy(x2, y2, CH_LRCORNER);
447 }
448 }
449
450 draw_window_contents(window, focus, clipy1, clipy2,
451 x1, x2, y + 1, y2);
452}
453/*-----------------------------------------------------------------------------------*/
454static void
455s_ctk_draw_dialog(struct ctk_window *dialog)
456{
457 unsigned char x, y;
458 unsigned char i;
459 unsigned char x1, y1, x2, y2;
460
461 (void)textcolor(DIALOGCOLOR);
462
463 x = dialog->x;
464 y = dialog->y + 1;
465
466 x1 = x + 1;
467 y1 = y + 1;
468 x2 = x1 + dialog->w;
469 y2 = y1 + dialog->h;
470
471 /* Draw dialog frame. */
472 cvlinexy(x, y1,
473 dialog->h);
474 cvlinexy(x2, y1,
475 dialog->h);
476
477 chlinexy(x1, y,
478 dialog->w);
479 chlinexy(x1, y2,
480 dialog->w);
481
482 cputcxy(x, y, CH_ULCORNER);
483 cputcxy(x, y2, CH_LLCORNER);
484 cputcxy(x2, y, CH_URCORNER);
485 cputcxy(x2, y2, CH_LRCORNER);
486
487 /* Clear dialog contents. */
488 for(i = y1; i < y2; ++i) {
489 cclearxy(x1, i, dialog->w);
490 }
491
492 draw_window_contents(dialog, CTK_FOCUS_DIALOG, 0, sizey,
493 x1, x2, y1, y2);
494}
495/*-----------------------------------------------------------------------------------*/
496static void
497s_ctk_draw_clear(unsigned char y1, unsigned char y2) __naked
498{
499 __asm
500 ld hl,#2
501 add hl,sp
502 ld d,(hl) ; Y1
503 inc hl
504 ld e,(hl) ; Y2
505
506 push af
507
508 ld h,#1
509 ld l,d
510 ld d,#40
511
512 inc e
513
514 call 0xBB99 ; TXT GET PAPER
515 call 0xBC2C ; SCR INK ENCODE
516
517 call 0xBC44 ; SCR FILL BOX
518
519 pop af
520 ret
521 __endasm;
522}
523/*-----------------------------------------------------------------------------------*/
524static void
525draw_menu(struct ctk_menu *m, unsigned char open)
526{
527 unsigned char x, x2, y;
528
529 if(open) {
530 x = x2 = wherex();
531 if(x2 + CTK_CONF_MENUWIDTH > sizex) {
532 x2 = sizex - CTK_CONF_MENUWIDTH;
533 }
534
535 for(y = 0; y < m->nitems; ++y) {
536 if(y == m->active) {
537 (void)textcolor(ACTIVEMENUITEMCOLOR);
538 } else {
539 (void)textcolor(SCREENCOLOR);
540 }
541 gotoxy(x2, y + 1);
542 if(m->items[y].title[0] == '-') {
543 chline(CTK_CONF_MENUWIDTH);
544 } else {
545 cputs(m->items[y].title);
546 }
547 if(x2 + CTK_CONF_MENUWIDTH > wherex()) {
548 cclear(x2 + CTK_CONF_MENUWIDTH - wherex());
549 }
550 }
551
552 gotoxy(x, 0);
553 (void)textcolor(OPENMENUCOLOR);
554 }
555
556 cputs(m->title);
557 cputc(' ');
558}
559/*-----------------------------------------------------------------------------------*/
560static void
561s_ctk_draw_menus(struct ctk_menus *menus)
562{
563 struct ctk_menu *m;
564
565 /* Draw menus */
566 (void)bgcolor(MENUCOLOR);
567 (void)textcolor(SCREENCOLOR);
568 gotoxy(0, 0);
569 cputc(' ');
570 for(m = menus->menus->next; m != NULL; m = m->next) {
571 draw_menu(m, m == menus->open);
572 }
573
574 /* Draw desktopmenu */
575 if(wherex() + strlen(menus->desktopmenu->title) + 1 >= sizex) {
576 gotoxy(sizex - strlen(menus->desktopmenu->title) - 1, 0);
577 } else {
578 cclear(sizex - wherex() -
579 strlen(menus->desktopmenu->title) - 1);
580 }
581 draw_menu(menus->desktopmenu, menus->desktopmenu == menus->open);
582
583 (void)bgcolor(SCREENCOLOR);
584}
585/*-----------------------------------------------------------------------------------*/
586static unsigned char
587s_ctk_draw_height(void)
588{
589 return sizey;
590}
591/*-----------------------------------------------------------------------------------*/
592static unsigned char
593s_ctk_draw_width(void)
594{
595 return sizex;
596}
597/*-----------------------------------------------------------------------------------*/
598static unsigned short
599s_ctk_mouse_xtoc(unsigned short x)
600{
601 return x / 8;
602}
603/*-----------------------------------------------------------------------------------*/
604static unsigned short
605s_ctk_mouse_ytoc(unsigned short y)
606{
607 return y / 8;
608}
609/*-----------------------------------------------------------------------------------*/
610static const struct ctk_draw_service_interface interface =
611 {CTK_DRAW_SERVICE_VERSION,
612 1,
613 1,
614 1,
615 s_ctk_draw_init,
616 s_ctk_draw_clear,
617 s_ctk_draw_clear_window,
618 s_ctk_draw_window,
619 s_ctk_draw_dialog,
620 s_ctk_draw_widget,
621 s_ctk_draw_menus,
622 s_ctk_draw_width,
623 s_ctk_draw_height,
624 s_ctk_mouse_xtoc,
625 s_ctk_mouse_ytoc,
626 };
627
628EK_EVENTHANDLER(eventhandler, ev, data);
629EK_PROCESS(proc, CTK_DRAW_SERVICE_NAME ": text", EK_PRIO_NORMAL,
630 eventhandler, NULL, (void *)&interface);
631
632/*--------------------------------------------------------------------------*/
633LOADER_INIT_FUNC(ctk_conio_service_init, arg)
634{
635 s_ctk_draw_init();
636 ek_service_start(CTK_DRAW_SERVICE_NAME, &proc);
637}
638/*--------------------------------------------------------------------------*/
639EK_EVENTHANDLER(eventhandler, ev, data)
640{
641 EK_EVENTHANDLER_ARGS(ev, data);
642
643 switch(ev) {
644 case EK_EVENT_INIT:
645 case EK_EVENT_REPLACE:
646 s_ctk_draw_init();
647 ctk_restore();
648 break;
649 case EK_EVENT_REQUEST_REPLACE:
650 ek_replace((struct ek_proc *)data, NULL);
651 LOADER_UNLOAD();
652 break;
653 }
654}
655/*--------------------------------------------------------------------------*/