source: mainline/uspace/app/gfxdemo/gfxdemo.c@ 788c76e3

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 788c76e3 was 788c76e3, checked in by Jiri Svoboda <jiri@…>, 22 months ago

GFX demo should downsize the window with -d cons@ ui

Also do not return task value if the ui is fullscreen.

  • Property mode set to 100644
File size: 26.0 KB
Line 
1/*
2 * Copyright (c) 2023 Jiri Svoboda
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 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup gfxdemo
30 * @{
31 */
32/** @file Graphic demo
33 */
34
35#include <congfx/console.h>
36#include <display.h>
37#include <fibril.h>
38#include <gfx/bitmap.h>
39#include <gfx/color.h>
40#include <gfx/render.h>
41#include <gfx/font.h>
42#include <gfx/text.h>
43#include <gfx/typeface.h>
44#include <io/console.h>
45#include <io/pixelmap.h>
46#include <stdbool.h>
47#include <stdlib.h>
48#include <str.h>
49#include <task.h>
50#include <ui/ui.h>
51#include <ui/window.h>
52#include <ui/wdecor.h>
53
54static void wnd_close_event(void *);
55static void wnd_kbd_event(void *, kbd_event_t *);
56
57static display_wnd_cb_t wnd_cb = {
58 .close_event = wnd_close_event,
59 .kbd_event = wnd_kbd_event
60};
61
62static void uiwnd_close_event(ui_window_t *, void *);
63static void uiwnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
64
65static ui_window_cb_t ui_window_cb = {
66 .close = uiwnd_close_event,
67 .kbd = uiwnd_kbd_event
68};
69
70static void demo_kbd_event(kbd_event_t *);
71
72static bool quit = false;
73static FIBRIL_MUTEX_INITIALIZE(quit_lock);
74static FIBRIL_CONDVAR_INITIALIZE(quit_cv);
75static gfx_typeface_t *tface;
76static gfx_font_t *font;
77static gfx_coord_t vpad;
78static console_ctrl_t *con = NULL;
79
80/** Determine if we are running in text mode.
81 *
82 * @param w Screen width
83 * @param h Screen height
84 * @return @c true iff we are running in text mode
85 */
86static bool demo_is_text(gfx_coord_t w, gfx_coord_t h)
87{
88 // XXX Need a proper way to determine text mode
89 return w <= 80;
90}
91
92/** Sleep until timeout or quit request.
93 *
94 * @param msec Number of microseconds to sleep for
95 */
96static void demo_msleep(unsigned msec)
97{
98 errno_t rc;
99 usec_t usec;
100 cons_event_t cevent;
101
102 fibril_mutex_lock(&quit_lock);
103 if (!quit) {
104 if (con != NULL) {
105 usec = (usec_t)msec * 1000;
106 while (usec > 0 && !quit) {
107 rc = console_get_event_timeout(con, &cevent, &usec);
108 if (rc == EOK) {
109 if (cevent.type == CEV_KEY) {
110 fibril_mutex_unlock(&quit_lock);
111 demo_kbd_event(&cevent.ev.key);
112 fibril_mutex_lock(&quit_lock);
113 }
114 }
115 }
116 } else {
117 (void) fibril_condvar_wait_timeout(&quit_cv, &quit_lock,
118 (usec_t)msec * 1000);
119 }
120 }
121 fibril_mutex_unlock(&quit_lock);
122}
123
124/** Clear screen.
125 *
126 * @param gc Graphic context
127 * @param w Screen width
128 * @param h Screen height
129 */
130static errno_t clear_scr(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
131{
132 gfx_color_t *color = NULL;
133 gfx_rect_t rect;
134 errno_t rc;
135
136 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
137 if (rc != EOK)
138 goto error;
139
140 rc = gfx_set_color(gc, color);
141 if (rc != EOK)
142 goto error;
143
144 rect.p0.x = 0;
145 rect.p0.y = 0;
146 rect.p1.x = w;
147 rect.p1.y = h;
148
149 rc = gfx_fill_rect(gc, &rect);
150 if (rc != EOK)
151 goto error;
152
153 gfx_color_delete(color);
154 return EOK;
155error:
156 if (color != NULL)
157 gfx_color_delete(color);
158 return rc;
159}
160
161/** Initialize demo font.
162 *
163 * @param gc Graphic context
164 * @param w Width
165 * @param h Height
166 * @return EOK on success or an error code
167 */
168static errno_t demo_font_init(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
169{
170 gfx_font_info_t *finfo;
171 errno_t rc;
172
173 if (quit)
174 return EOK;
175
176 /* XXX Crude way of detecting text mode */
177 if (w < 256) {
178 /* Create dummy font for text mode */
179 rc = gfx_typeface_create(gc, &tface);
180 if (rc != EOK) {
181 printf("Error creating typeface\n");
182 goto error;
183 }
184
185 rc = gfx_font_create_textmode(tface, &font);
186 if (rc != EOK) {
187 printf("Error creating font\n");
188 goto error;
189 }
190
191 vpad = 0;
192 } else {
193 /* Load font */
194 rc = gfx_typeface_open(gc, "/data/font/helena.tpf", &tface);
195 if (rc != EOK) {
196 printf("Error opening typeface\n");
197 goto error;
198 }
199
200 finfo = gfx_typeface_first_font(tface);
201 if (finfo == NULL) {
202 printf("Typeface contains no font.\n");
203 rc = ENOENT;
204 goto error;
205 }
206
207 rc = gfx_font_open(finfo, &font);
208 if (rc != EOK) {
209 printf("Error opening font.\n");
210 goto error;
211 }
212
213 vpad = 5;
214 }
215
216 return EOK;
217error:
218 if (tface != NULL)
219 gfx_typeface_destroy(tface);
220 return rc;
221}
222
223/** Finalize demo font. */
224static void demo_font_fini(void)
225{
226 if (font == NULL)
227 return;
228
229 gfx_font_close(font);
230 font = NULL;
231
232 gfx_typeface_destroy(tface);
233 tface = NULL;
234}
235
236/** Start a new demo screen.
237 *
238 * Clear the screen, display a status line and set up clipping.
239 *
240 * @param gc Graphic context
241 * @param w Width
242 * @param h Height
243 * @param text Demo screen description
244 * @return EOK on success or an error code
245 */
246static errno_t demo_begin(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h,
247 const char *text)
248{
249 gfx_text_fmt_t fmt;
250 gfx_font_metrics_t metrics;
251 gfx_coord2_t pos;
252 gfx_color_t *color;
253 gfx_rect_t rect;
254 gfx_coord_t height;
255 errno_t rc;
256
257 rc = gfx_set_clip_rect(gc, NULL);
258 if (rc != EOK)
259 return rc;
260
261 rc = clear_scr(gc, w, h);
262 if (rc != EOK)
263 return rc;
264
265 if (font != NULL) {
266 if (demo_is_text(w, h)) {
267 rc = gfx_color_new_ega(0x1e, &color);
268 if (rc != EOK)
269 goto error;
270 } else {
271 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
272 if (rc != EOK)
273 goto error;
274 }
275
276 gfx_text_fmt_init(&fmt);
277 fmt.font = font;
278 fmt.color = color;
279 fmt.halign = gfx_halign_center;
280 fmt.valign = gfx_valign_bottom;
281
282 pos.x = w / 2;
283 pos.y = h;
284 rc = gfx_puttext(&pos, &fmt, text);
285 if (rc != EOK) {
286 printf("Error rendering text.\n");
287 gfx_color_delete(color);
288 goto error;
289 }
290
291 gfx_color_delete(color);
292
293 gfx_font_get_metrics(font, &metrics);
294 height = metrics.ascent + metrics.descent + 1;
295 } else {
296 height = 0;
297 }
298
299 rect.p0.x = 0;
300 rect.p0.y = 0;
301 rect.p1.x = w;
302 rect.p1.y = h - height - vpad;
303 rc = gfx_set_clip_rect(gc, &rect);
304 if (rc != EOK)
305 return rc;
306
307 return EOK;
308error:
309 return rc;
310}
311
312/** Run rectangle demo on a graphic context.
313 *
314 * @param gc Graphic context
315 * @param w Width
316 * @param h Height
317 */
318static errno_t demo_rects(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
319{
320 gfx_color_t *color = NULL;
321 gfx_rect_t rect;
322 int i, j;
323 errno_t rc;
324
325 if (quit)
326 return EOK;
327
328 rc = demo_begin(gc, w, h, "Rectangle rendering");
329 if (rc != EOK)
330 return rc;
331
332 for (j = 0; j < 10; j++) {
333 rc = gfx_color_new_rgb_i16(rand() % 0x10000, rand() % 0x10000,
334 rand() % 0x10000, &color);
335 if (rc != EOK)
336 return rc;
337
338 rc = gfx_set_color(gc, color);
339 if (rc != EOK)
340 return rc;
341
342 for (i = 0; i < 10; i++) {
343 rect.p0.x = rand() % (w - 1);
344 rect.p0.y = rand() % (h - 1);
345 rect.p1.x = rect.p0.x + rand() % (w - 1 - rect.p0.x);
346 rect.p1.y = rect.p0.y + rand() % (h - 1 - rect.p0.y);
347
348 rc = gfx_fill_rect(gc, &rect);
349 if (rc != EOK)
350 return rc;
351 }
352
353 gfx_color_delete(color);
354
355 demo_msleep(500);
356 if (quit)
357 break;
358 }
359
360 return EOK;
361}
362
363/** Fill bitmap with tartan pattern.
364 *
365 * @param bitmap Bitmap
366 * @param w Bitmap width
367 * @param h Bitmap height
368 * @return EOK on success or an error code
369 */
370static errno_t bitmap_tartan(gfx_bitmap_t *bitmap, gfx_coord_t w, gfx_coord_t h)
371{
372 int i, j;
373 pixelmap_t pixelmap;
374 gfx_bitmap_alloc_t alloc;
375 errno_t rc;
376
377 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
378 if (rc != EOK)
379 return rc;
380
381 /* In absence of anything else, use pixelmap */
382 pixelmap.width = w;
383 pixelmap.height = h;
384 pixelmap.data = alloc.pixels;
385
386 for (i = 0; i < w; i++) {
387 for (j = 0; j < h; j++) {
388 pixelmap_put_pixel(&pixelmap, i, j,
389 PIXEL(0, (i % 30) < 3 ? 255 : 0,
390 (j % 30) < 3 ? 255 : 0, i / 2));
391 }
392 }
393
394 return EOK;
395}
396
397/** Fill bitmap with moire pattern.
398 *
399 * @param bitmap Bitmap
400 * @param w Bitmap width
401 * @param h Bitmap height
402 * @return EOK on success or an error code
403 */
404static errno_t bitmap_moire(gfx_bitmap_t *bitmap, gfx_coord_t w, gfx_coord_t h)
405{
406 int i, j;
407 int k;
408 pixelmap_t pixelmap;
409 gfx_bitmap_alloc_t alloc;
410 errno_t rc;
411
412 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
413 if (rc != EOK)
414 return rc;
415
416 /* In absence of anything else, use pixelmap */
417 pixelmap.width = w;
418 pixelmap.height = h;
419 pixelmap.data = alloc.pixels;
420
421 for (i = 0; i < w; i++) {
422 for (j = 0; j < h; j++) {
423 k = i * i + j * j;
424 pixelmap_put_pixel(&pixelmap, i, j,
425 PIXEL(0, k, k, k));
426 }
427 }
428
429 return EOK;
430}
431
432/** Render circle to a bitmap.
433 *
434 * @param bitmap Bitmap
435 * @param w Bitmap width
436 * @param h Bitmap height
437 * @return EOK on success or an error code
438 */
439static errno_t bitmap_circle(gfx_bitmap_t *bitmap, gfx_coord_t w, gfx_coord_t h)
440{
441 int i, j;
442 int k;
443 pixelmap_t pixelmap;
444 gfx_bitmap_alloc_t alloc;
445 errno_t rc;
446
447 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
448 if (rc != EOK)
449 return rc;
450
451 /* In absence of anything else, use pixelmap */
452 pixelmap.width = w;
453 pixelmap.height = h;
454 pixelmap.data = alloc.pixels;
455
456 for (i = 0; i < w; i++) {
457 for (j = 0; j < h; j++) {
458 k = i * i + j * j;
459 pixelmap_put_pixel(&pixelmap, i, j,
460 k < w * w / 2 ? PIXEL(0, 0, 255, 0) :
461 PIXEL(0, 255, 0, 255));
462 }
463 }
464
465 return EOK;
466}
467
468/** Run bitmap demo on a graphic context.
469 *
470 * @param gc Graphic context
471 * @param w Width
472 * @param h Height
473 */
474static errno_t demo_bitmap(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
475{
476 gfx_bitmap_t *bitmap;
477 gfx_bitmap_params_t params;
478 int i, j;
479 gfx_coord2_t offs;
480 gfx_rect_t srect;
481 errno_t rc;
482
483 if (quit)
484 return EOK;
485
486 rc = demo_begin(gc, w, h, "Bitmap rendering without offset");
487 if (rc != EOK)
488 return rc;
489
490 gfx_bitmap_params_init(&params);
491 params.rect.p0.x = 0;
492 params.rect.p0.y = 0;
493 params.rect.p1.x = w;
494 params.rect.p1.y = h;
495
496 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
497 if (rc != EOK)
498 return rc;
499
500 rc = bitmap_tartan(bitmap, w, h);
501 if (rc != EOK)
502 goto error;
503
504 for (j = 0; j < 10; j++) {
505 for (i = 0; i < 5; i++) {
506 srect.p0.x = rand() % (w - 40);
507 srect.p0.y = rand() % (h - 20);
508 srect.p1.x = srect.p0.x + rand() % (w - srect.p0.x);
509 srect.p1.y = srect.p0.y + rand() % (h - srect.p0.y);
510 offs.x = 0;
511 offs.y = 0;
512
513 rc = gfx_bitmap_render(bitmap, &srect, &offs);
514 if (rc != EOK)
515 goto error;
516
517 demo_msleep(250);
518 if (quit)
519 goto out;
520 }
521 }
522
523out:
524 gfx_bitmap_destroy(bitmap);
525
526 return EOK;
527error:
528 gfx_bitmap_destroy(bitmap);
529 return rc;
530}
531
532/** Run second bitmap demo on a graphic context.
533 *
534 * @param gc Graphic context
535 * @param w Width
536 * @param h Height
537 */
538static errno_t demo_bitmap2(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
539{
540 gfx_bitmap_t *bitmap;
541 gfx_bitmap_params_t params;
542 int i, j;
543 gfx_coord2_t offs;
544 errno_t rc;
545
546 if (quit)
547 return EOK;
548
549 rc = demo_begin(gc, w, h, "Bitmap rendering with offset");
550 if (rc != EOK)
551 return rc;
552
553 gfx_bitmap_params_init(&params);
554 params.rect.p0.x = 0;
555 params.rect.p0.y = 0;
556 params.rect.p1.x = 40;
557 params.rect.p1.y = 20;
558
559 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
560 if (rc != EOK)
561 return rc;
562
563 rc = bitmap_moire(bitmap, 40, 20);
564 if (rc != EOK)
565 goto error;
566
567 for (j = 0; j < 10; j++) {
568 for (i = 0; i < 10; i++) {
569 offs.x = rand() % (w - 40);
570 offs.y = rand() % (h - 20);
571
572 rc = gfx_bitmap_render(bitmap, NULL, &offs);
573 if (rc != EOK)
574 goto error;
575 }
576
577 demo_msleep(500);
578 if (quit)
579 break;
580 }
581
582 gfx_bitmap_destroy(bitmap);
583
584 return EOK;
585error:
586 gfx_bitmap_destroy(bitmap);
587 return rc;
588}
589
590/** Run bitmap color key demo on a graphic context.
591 *
592 * @param gc Graphic context
593 * @param w Width
594 * @param h Height
595 */
596static errno_t demo_bitmap_kc(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
597{
598 gfx_bitmap_t *bitmap;
599 gfx_bitmap_params_t params;
600 int i, j;
601 gfx_coord2_t offs;
602 errno_t rc;
603
604 if (quit)
605 return EOK;
606
607 rc = demo_begin(gc, w, h, "Bitmap rendering with color key");
608 if (rc != EOK)
609 return rc;
610
611 gfx_bitmap_params_init(&params);
612 params.rect.p0.x = 0;
613 params.rect.p0.y = 0;
614 params.rect.p1.x = 40;
615 params.rect.p1.y = 40;
616 params.flags = bmpf_color_key;
617 params.key_color = PIXEL(0, 255, 0, 255);
618
619 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
620 if (rc != EOK)
621 return rc;
622
623 rc = bitmap_circle(bitmap, 40, 40);
624 if (rc != EOK)
625 goto error;
626
627 for (j = 0; j < 10; j++) {
628 for (i = 0; i < 10; i++) {
629 offs.x = j * 20 + i * 20;
630 offs.y = i * 20;
631
632 rc = gfx_bitmap_render(bitmap, NULL, &offs);
633 if (rc != EOK)
634 goto error;
635 }
636
637 demo_msleep(500);
638 if (quit)
639 break;
640 }
641
642 gfx_bitmap_destroy(bitmap);
643
644 return EOK;
645error:
646 gfx_bitmap_destroy(bitmap);
647 return rc;
648}
649
650/** Run text demo on a graphic context.
651 *
652 * @param gc Graphic context
653 * @param w Width
654 * @param h Height
655 */
656static errno_t demo_text(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
657{
658 gfx_color_t *color = NULL;
659 gfx_rect_t rect;
660 gfx_coord2_t pos;
661 gfx_text_fmt_t fmt;
662 int i;
663 errno_t rc;
664
665 if (quit)
666 return EOK;
667
668 rc = demo_begin(gc, w, h, "Text rendering");
669 if (rc != EOK)
670 goto error;
671
672 /* Vertical bars */
673
674 for (i = 0; i < 20; i++) {
675 rc = gfx_color_new_rgb_i16(0, 0x8000 * i / 20,
676 0x8000 * i / 20, &color);
677 if (rc != EOK)
678 goto error;
679
680 rc = gfx_set_color(gc, color);
681 if (rc != EOK)
682 goto error;
683
684 rect.p0.x = w * i / 20;
685 rect.p0.y = 0;
686 rect.p1.x = w * (i + 1) / 20;
687 rect.p1.y = h;
688
689 rc = gfx_fill_rect(gc, &rect);
690 if (rc != EOK)
691 goto error;
692
693 gfx_color_delete(color);
694 }
695
696 rc = gfx_color_new_rgb_i16(0, 0, 0x8000, &color);
697 if (rc != EOK)
698 goto error;
699
700 rc = gfx_set_color(gc, color);
701 if (rc != EOK)
702 goto error;
703
704 rect.p0.x = w / 20;
705 rect.p0.y = 1 * h / 15;
706 rect.p1.x = w - w / 20;
707 rect.p1.y = 4 * h / 15;
708
709 rc = gfx_fill_rect(gc, &rect);
710 if (rc != EOK)
711 goto error;
712
713 gfx_color_delete(color);
714
715 if (demo_is_text(w, h)) {
716 rc = gfx_color_new_ega(0x1f, &color);
717 if (rc != EOK)
718 goto error;
719 } else {
720 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
721 if (rc != EOK)
722 goto error;
723 }
724
725 gfx_text_fmt_init(&fmt);
726 fmt.font = font;
727 fmt.color = color;
728
729 pos.x = rect.p0.x;
730 pos.y = rect.p0.y;
731 rc = gfx_puttext(&pos, &fmt, "Top left");
732 if (rc != EOK) {
733 printf("Error rendering text.\n");
734 goto error;
735 }
736
737 pos.x = (rect.p0.x + rect.p1.x - 1) / 2;
738 pos.y = rect.p0.y;
739 fmt.halign = gfx_halign_center;
740 rc = gfx_puttext(&pos, &fmt, "Top center");
741 if (rc != EOK)
742 goto error;
743
744 pos.x = rect.p1.x;
745 pos.y = rect.p0.y;
746 fmt.halign = gfx_halign_right;
747 rc = gfx_puttext(&pos, &fmt, "Top right");
748 if (rc != EOK)
749 goto error;
750
751 fmt.valign = gfx_valign_center;
752
753 pos.x = rect.p0.x;
754 pos.y = (rect.p0.y + rect.p1.y - 1) / 2;
755 fmt.halign = gfx_halign_left;
756 rc = gfx_puttext(&pos, &fmt, "Center left");
757 if (rc != EOK)
758 goto error;
759
760 pos.x = (rect.p0.x + rect.p1.x - 1) / 2;
761 pos.y = (rect.p0.y + rect.p1.y - 1) / 2;
762 fmt.halign = gfx_halign_center;
763 rc = gfx_puttext(&pos, &fmt, "Center");
764 if (rc != EOK)
765 goto error;
766
767 pos.x = rect.p1.x;
768 pos.y = (rect.p0.y + rect.p1.y - 1) / 2;
769 fmt.halign = gfx_halign_right;
770 rc = gfx_puttext(&pos, &fmt, "Center right");
771 if (rc != EOK)
772 goto error;
773
774 fmt.valign = gfx_valign_bottom;
775
776 pos.x = rect.p0.x;
777 pos.y = rect.p1.y - 1;
778 fmt.halign = gfx_halign_left;
779 rc = gfx_puttext(&pos, &fmt, "Bottom left");
780 if (rc != EOK)
781 goto error;
782
783 pos.x = (rect.p0.x + rect.p1.x - 1) / 2;
784 pos.y = rect.p1.y;
785 fmt.halign = gfx_halign_center;
786 rc = gfx_puttext(&pos, &fmt, "Bottom center");
787 if (rc != EOK)
788 goto error;
789
790 pos.x = rect.p1.x;
791 pos.y = rect.p1.y;
792 fmt.halign = gfx_halign_right;
793 rc = gfx_puttext(&pos, &fmt, "Bottom right");
794 if (rc != EOK)
795 goto error;
796
797 gfx_color_delete(color);
798
799 gfx_text_fmt_init(&fmt);
800 fmt.font = font;
801
802 for (i = 0; i < 8; i++) {
803 if (demo_is_text(w, h)) {
804 rc = gfx_color_new_ega(i != 0 ? i : 0x10, &color);
805 if (rc != EOK)
806 goto error;
807 } else {
808 rc = gfx_color_new_rgb_i16((i & 4) ? 0xffff : 0,
809 (i & 2) ? 0xffff : 0, (i & 1) ? 0xffff : 0, &color);
810 if (rc != EOK)
811 goto error;
812 }
813
814 fmt.color = color;
815 fmt.underline = !fmt.underline;
816
817 pos.x = w / 20;
818 pos.y = (6 + i) * h / 15;
819 rc = gfx_puttext(&pos, &fmt, "The quick brown fox jumps over the lazy dog.");
820 if (rc != EOK)
821 goto error;
822
823 gfx_color_delete(color);
824 }
825
826 for (i = 0; i < 10; i++) {
827 demo_msleep(500);
828 if (quit)
829 break;
830 }
831
832 return EOK;
833error:
834 return rc;
835}
836
837/** Run text abbreviation demo on a graphic context.
838 *
839 * @param gc Graphic context
840 * @param w Width
841 * @param h Height
842 */
843static errno_t demo_text_abbr(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
844{
845 gfx_color_t *color = NULL;
846 gfx_rect_t rect;
847 gfx_coord2_t pos;
848 gfx_text_fmt_t fmt;
849 int i;
850 errno_t rc;
851
852 if (quit)
853 return EOK;
854
855 rc = demo_begin(gc, w, h, "Text abbreviation");
856 if (rc != EOK)
857 goto error;
858
859 for (i = 0; i < 11; i++) {
860
861 rc = gfx_color_new_rgb_i16(0, 0, 0x8000, &color);
862 if (rc != EOK)
863 goto error;
864
865 rc = gfx_set_color(gc, color);
866 if (rc != EOK)
867 goto error;
868
869 rect.p0.x = w / 20;
870 rect.p0.y = (2 + 2 * i) * h / 25;
871 rect.p1.x = w - w / 20 - w * i / 12;
872 rect.p1.y = (3 + 2 * i) * h / 25;
873
874 rc = gfx_fill_rect(gc, &rect);
875 if (rc != EOK)
876 goto error;
877
878 gfx_color_delete(color);
879
880 if (demo_is_text(w, h)) {
881 rc = gfx_color_new_ega(0x1f, &color);
882 if (rc != EOK)
883 goto error;
884 } else {
885 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff,
886 &color);
887 if (rc != EOK)
888 goto error;
889 }
890
891 gfx_text_fmt_init(&fmt);
892 fmt.font = font;
893 fmt.color = color;
894 fmt.abbreviate = true;
895 fmt.width = rect.p1.x - rect.p0.x;
896
897 pos.x = rect.p0.x;
898 pos.y = rect.p0.y;
899 rc = gfx_puttext(&pos, &fmt,
900 "The quick brow fox jumps over the lazy dog!");
901 if (rc != EOK) {
902 printf("Error rendering text.\n");
903 goto error;
904 }
905 }
906
907 for (i = 0; i < 10; i++) {
908 demo_msleep(500);
909 if (quit)
910 break;
911 }
912
913 return EOK;
914error:
915 return rc;
916}
917
918/** Run clipping demo on a graphic context.
919 *
920 * @param gc Graphic context
921 * @param w Width
922 * @param h Height
923 */
924static errno_t demo_clip(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
925{
926 gfx_bitmap_t *bitmap;
927 gfx_color_t *color;
928 gfx_bitmap_params_t params;
929 int i, j;
930 gfx_coord2_t offs;
931 gfx_rect_t rect;
932 errno_t rc;
933
934 if (quit)
935 return EOK;
936
937 rc = demo_begin(gc, w, h, "Clipping demonstration");
938 if (rc != EOK)
939 return rc;
940
941 gfx_bitmap_params_init(&params);
942 params.rect.p0.x = 0;
943 params.rect.p0.y = 0;
944 params.rect.p1.x = 40;
945 params.rect.p1.y = 20;
946
947 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
948 if (rc != EOK)
949 return rc;
950
951 rc = bitmap_moire(bitmap, 40, 20);
952 if (rc != EOK)
953 goto error;
954
955 for (j = 0; j < 10; j++) {
956 rect.p0.x = w / 8;
957 rect.p0.y = h / 8;
958 rect.p1.x = w * 7 / 8;
959 rect.p1.y = h * 3 / 8;
960
961 rc = gfx_set_clip_rect(gc, &rect);
962 if (rc != EOK)
963 return rc;
964
965 rc = gfx_color_new_rgb_i16(rand() % 0x10000, rand() % 0x10000,
966 rand() % 0x10000, &color);
967 if (rc != EOK)
968 return rc;
969
970 rc = gfx_set_color(gc, color);
971 if (rc != EOK)
972 return rc;
973
974 for (i = 0; i < 10; i++) {
975 rect.p0.x = rand() % (w - 1);
976 rect.p0.y = rand() % (h - 1);
977 rect.p1.x = rect.p0.x + rand() % (w - 1 - rect.p0.x);
978 rect.p1.y = rect.p0.y + rand() % (h - 1 - rect.p0.y);
979
980 rc = gfx_fill_rect(gc, &rect);
981 if (rc != EOK)
982 return rc;
983 }
984
985 gfx_color_delete(color);
986
987 rect.p0.x = w / 8;
988 rect.p0.y = h * 5 / 8;
989 rect.p1.x = w * 7 / 8;
990 rect.p1.y = h * 7 / 8;
991
992 rc = gfx_set_clip_rect(gc, &rect);
993 if (rc != EOK)
994 return rc;
995
996 for (i = 0; i < 10; i++) {
997 offs.x = rand() % (w - 40);
998 offs.y = rand() % (h - 20);
999
1000 rc = gfx_bitmap_render(bitmap, NULL, &offs);
1001 if (rc != EOK)
1002 goto error;
1003 }
1004
1005 demo_msleep(500);
1006 if (quit)
1007 break;
1008 }
1009
1010 (void) gfx_set_clip_rect(gc, NULL);
1011 gfx_bitmap_destroy(bitmap);
1012 return EOK;
1013error:
1014 (void) gfx_set_clip_rect(gc, NULL);
1015 gfx_bitmap_destroy(bitmap);
1016 return rc;
1017}
1018
1019/** Run demo loop on a graphic context.
1020 *
1021 * @param gc Graphic context
1022 * @param w Width
1023 * @param h Height
1024 */
1025static errno_t demo_loop(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
1026{
1027 errno_t rc;
1028
1029 (void) demo_font_init(gc, w, h);
1030
1031 while (!quit) {
1032 rc = demo_rects(gc, w, h);
1033 if (rc != EOK)
1034 goto error;
1035
1036 rc = demo_bitmap(gc, w, h);
1037 if (rc != EOK)
1038 goto error;
1039
1040 rc = demo_bitmap2(gc, w, h);
1041 if (rc != EOK)
1042 goto error;
1043
1044 rc = demo_bitmap_kc(gc, w, h);
1045 if (rc != EOK)
1046 goto error;
1047
1048 rc = demo_text(gc, w, h);
1049 if (rc != EOK)
1050 goto error;
1051
1052 rc = demo_text_abbr(gc, w, h);
1053 if (rc != EOK)
1054 goto error;
1055
1056 rc = demo_clip(gc, w, h);
1057 if (rc != EOK)
1058 goto error;
1059 }
1060
1061 demo_font_fini();
1062 return EOK;
1063error:
1064 demo_font_fini();
1065 return rc;
1066}
1067
1068/** Run demo on console. */
1069static errno_t demo_console(void)
1070{
1071 console_gc_t *cgc = NULL;
1072 gfx_context_t *gc;
1073 sysarg_t cols, rows;
1074 errno_t rc;
1075
1076 con = console_init(stdin, stdout);
1077 if (con == NULL)
1078 return EIO;
1079
1080 rc = console_get_size(con, &cols, &rows);
1081 if (rc != EOK)
1082 return rc;
1083
1084 rc = console_gc_create(con, stdout, &cgc);
1085 if (rc != EOK)
1086 return rc;
1087
1088 gc = console_gc_get_ctx(cgc);
1089
1090 rc = demo_loop(gc, cols, rows);
1091 if (rc != EOK)
1092 return rc;
1093
1094 rc = console_gc_delete(cgc);
1095 if (rc != EOK)
1096 return rc;
1097
1098 return EOK;
1099}
1100
1101/** Run demo on UI. */
1102static errno_t demo_ui(const char *display_spec)
1103{
1104 ui_t *ui = NULL;
1105 ui_wnd_params_t params;
1106 ui_window_t *window = NULL;
1107 gfx_context_t *gc;
1108 gfx_rect_t rect;
1109 gfx_rect_t wrect;
1110 gfx_coord2_t off;
1111 gfx_rect_t ui_rect;
1112 gfx_coord2_t dims;
1113 errno_t rc;
1114
1115 rc = ui_create(display_spec, &ui);
1116 if (rc != EOK) {
1117 printf("Error initializing UI (%s)\n", display_spec);
1118 goto error;
1119 }
1120
1121 rc = ui_get_rect(ui, &ui_rect);
1122 if (rc != EOK) {
1123 printf("Error getting display size.\n");
1124 goto error;
1125 }
1126
1127 rect.p0.x = 0;
1128 rect.p0.y = 0;
1129 rect.p1.x = 400;
1130 rect.p1.y = 300;
1131
1132 ui_wnd_params_init(&params);
1133 params.caption = "GFX Demo";
1134
1135 /*
1136 * Compute window rectangle such that application area corresponds
1137 * to rect
1138 */
1139 ui_wdecor_rect_from_app(params.style, &rect, &wrect);
1140 off = wrect.p0;
1141 gfx_rect_rtranslate(&off, &wrect, &params.rect);
1142
1143 gfx_rect_dims(&ui_rect, &dims);
1144
1145 /* Make sure window is not larger than the entire screen */
1146 if (params.rect.p1.x > dims.x)
1147 params.rect.p1.x = dims.x;
1148 if (params.rect.p1.y > dims.y)
1149 params.rect.p1.y = dims.y;
1150
1151 rc = ui_window_create(ui, &params, &window);
1152 if (rc != EOK) {
1153 printf("Error creating window.\n");
1154 goto error;
1155 }
1156
1157 ui_window_set_cb(window, &ui_window_cb, NULL);
1158
1159 rc = ui_window_get_app_gc(window, &gc);
1160 if (rc != EOK) {
1161 printf("Error creating graphic context.\n");
1162 goto error;
1163 }
1164
1165 ui_window_get_app_rect(window, &rect);
1166 gfx_rect_dims(&rect, &dims);
1167
1168 if (!ui_is_fullscreen(ui))
1169 task_retval(0);
1170
1171 rc = demo_loop(gc, dims.x, dims.y);
1172 if (rc != EOK)
1173 goto error;
1174
1175 ui_window_destroy(window);
1176 ui_destroy(ui);
1177
1178 return EOK;
1179error:
1180 if (window != NULL)
1181 ui_window_destroy(window);
1182 if (ui != NULL)
1183 ui_destroy(ui);
1184 return rc;
1185}
1186
1187/** Run demo on display server. */
1188static errno_t demo_display(const char *display_svc)
1189{
1190 display_t *display = NULL;
1191 gfx_context_t *gc;
1192 display_wnd_params_t params;
1193 display_window_t *window = NULL;
1194 errno_t rc;
1195
1196 rc = display_open(display_svc, &display);
1197 if (rc != EOK) {
1198 printf("Error opening display.\n");
1199 return rc;
1200 }
1201
1202 display_wnd_params_init(&params);
1203 params.rect.p0.x = 0;
1204 params.rect.p0.y = 0;
1205 params.rect.p1.x = 400;
1206 params.rect.p1.y = 300;
1207 params.caption = "GFX Demo";
1208
1209 rc = display_window_create(display, &params, &wnd_cb, NULL, &window);
1210 if (rc != EOK) {
1211 printf("Error creating window.\n");
1212 return rc;
1213 }
1214
1215 rc = display_window_get_gc(window, &gc);
1216 if (rc != EOK) {
1217 printf("Error getting graphics context.\n");
1218 return rc;
1219 }
1220
1221 task_retval(0);
1222
1223 rc = demo_loop(gc, 400, 300);
1224 if (rc != EOK)
1225 return rc;
1226
1227 rc = gfx_context_delete(gc);
1228 if (rc != EOK)
1229 return rc;
1230
1231 display_window_destroy(window);
1232 display_close(display);
1233
1234 return EOK;
1235}
1236
1237static void demo_quit(void)
1238{
1239 fibril_mutex_lock(&quit_lock);
1240 quit = true;
1241 fibril_mutex_unlock(&quit_lock);
1242 fibril_condvar_broadcast(&quit_cv);
1243}
1244
1245static void wnd_close_event(void *arg)
1246{
1247 demo_quit();
1248}
1249
1250static void demo_kbd_event(kbd_event_t *event)
1251{
1252 if (event->type == KEY_PRESS) {
1253 /* Ctrl-Q */
1254 if ((event->mods & KM_CTRL) != 0 &&
1255 (event->mods & KM_ALT) == 0 &&
1256 (event->mods & KM_SHIFT) == 0 &&
1257 event->key == KC_Q) {
1258 demo_quit();
1259 }
1260
1261 /* Escape */
1262 if ((event->mods & KM_CTRL) == 0 &&
1263 (event->mods & KM_ALT) == 0 &&
1264 (event->mods & KM_SHIFT) == 0 &&
1265 event->key == KC_ESCAPE) {
1266 demo_quit();
1267 }
1268 }
1269}
1270
1271static void wnd_kbd_event(void *arg, kbd_event_t *event)
1272{
1273 (void)arg;
1274 demo_kbd_event(event);
1275}
1276
1277static void uiwnd_close_event(ui_window_t *window, void *arg)
1278{
1279 demo_quit();
1280}
1281
1282static void uiwnd_kbd_event(ui_window_t *window, void *arg, kbd_event_t *event)
1283{
1284 (void)window;
1285 (void)arg;
1286 demo_kbd_event(event);
1287}
1288
1289static void print_syntax(void)
1290{
1291 printf("Syntax: gfxdemo [-d <display>] {console|display|ui}\n");
1292}
1293
1294int main(int argc, char *argv[])
1295{
1296 errno_t rc;
1297 const char *display_svc = DISPLAY_DEFAULT;
1298 const char *ui_display_spec = UI_DISPLAY_DEFAULT;
1299 int i;
1300
1301 i = 1;
1302 while (i < argc && argv[i][0] == '-') {
1303 if (str_cmp(argv[i], "-d") == 0) {
1304 ++i;
1305 if (i >= argc) {
1306 printf("Argument missing.\n");
1307 print_syntax();
1308 return 1;
1309 }
1310
1311 display_svc = ui_display_spec = argv[i++];
1312 } else {
1313 printf("Invalid option '%s'.\n", argv[i]);
1314 print_syntax();
1315 return 1;
1316 }
1317 }
1318
1319 if (i >= argc || str_cmp(argv[i], "display") == 0) {
1320 rc = demo_display(display_svc);
1321 if (rc != EOK)
1322 return 1;
1323 } else if (str_cmp(argv[i], "console") == 0) {
1324 rc = demo_console();
1325 if (rc != EOK)
1326 return 1;
1327 } else if (str_cmp(argv[i], "ui") == 0) {
1328 rc = demo_ui(ui_display_spec);
1329 if (rc != EOK)
1330 return 1;
1331 } else {
1332 print_syntax();
1333 return 1;
1334 }
1335}
1336
1337/** @}
1338 */
Note: See TracBrowser for help on using the repository browser.