Implement simple, but impressive windowing system.
authorbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Mon, 23 Jan 2006 23:14:29 +0000 (23:14 +0000)
committerbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Mon, 23 Jan 2006 23:14:29 +0000 (23:14 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@485 38d2e660-2303-0410-9eaa-f027e97ec537

gfx/win.c [new file with mode: 0755]
gfx/win.h [new file with mode: 0755]
gfx/win_test.c [new file with mode: 0755]

diff --git a/gfx/win.c b/gfx/win.c
new file mode 100755 (executable)
index 0000000..3d6db45
--- /dev/null
+++ b/gfx/win.c
@@ -0,0 +1,192 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2006 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \brief Very simple hierarchical windowing system.
+ *
+ * All functions in this module are to be intended as methods
+ * of the Window class.  Please see its documentation
+ * for a module-wise introduction.
+ *
+ * \see struct Window
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2006/01/23 23:14:29  bernie
+ *#* Implement simple, but impressive windowing system.
+ *#*
+ *#*/
+
+#include "win.h"
+
+/**
+ * Map the contents of all child-windows into the bitmap of \a w.
+ *
+ * Please note that recursively draw children into their parent
+ * effectively damages the parent buffer.
+ */
+void win_compose(Window *w)
+{
+       Window *child;
+
+       /*
+        * Walk over all children, in back to front order and tell them
+        * to compose into us.
+        */
+       REVERSE_FOREACH_NODE(child, &w->children)
+       {
+               /* Recursively compose child first. */
+               win_compose(child);
+
+               /* Draw child into our bitmap. */
+               if (w->bitmap)
+                       gfx_blit(w->bitmap, &child->geom, child->bitmap, 0, 0);
+       }
+}
+
+/**
+ * Map window \a w into \a parent.
+ *
+ * The new window becomes the topmost window.
+ *
+ * \note Opening a window twice is illegal.
+ *
+ * \see win_close()
+ */
+void win_open(Window *w, Window *parent)
+{
+       ASSERT(!w->parent);
+       w->parent = parent;
+       ADDHEAD(&parent->children, &w->link);
+}
+
+/**
+ * Detach window from its parent.
+ *
+ * Closing a window causes it to become orphan of its
+ * parent.  Its content will no longer appear in its
+ * parent after the next refresh cycle.
+ *
+ * \note Closing a window that has not been previously
+ *       opened is illegal.
+ *
+ * \see win_open()
+ */
+void win_close(Window *w)
+{
+       ASSERT(w->parent);
+       REMOVE(&w->link);
+       w->parent = NULL;
+}
+
+/**
+ * Move window to the topmost position relative to its sibling.
+ *
+ * \see win_move(), win_resize(), win_setGeometry()
+ */
+void win_raise(Window *w)
+{
+       ASSERT(w->parent);
+       REMOVE(&w->link);
+       ADDHEAD(&w->parent->children, &w->link);
+}
+
+/**
+ * Set window position and size at the same time.
+ *
+ * This function is equivalent to subsequent calls to win_move()
+ * and win_resize() using the coordinates provided by the
+ * \a new_geom rectangle.
+ *
+ * \note The xmax and ymax members of \a new_geom are non-inclusive,
+ *       as usual for the Rect interface.
+ *
+ * \see win_move()
+ * \see win_resize()
+ */
+void win_setGeometry(Window *w, Rect *new_geom)
+{
+       // requires C99?
+       // memcpy(&w->geom, new_geom, sizeof(w->geom));
+       w->geom = *new_geom;
+}
+
+/**
+ * Move window to specified position.
+ *
+ * Move the window top-left corner to the pixel coordinates
+ * \a left and \a top, which are relative to the parent window.
+ *
+ * \note A window can also be moved outside the borders
+ *       of its parent, or at negative coordinates.
+ *
+ * \note It is allowed to move an orphan window.
+ */
+void win_move(Window *w, coord_t left, coord_t top)
+{
+       Rect r;
+
+       r.xmin = left;
+       r.ymin = top;
+       r.xmax = r.xmin + RECT_WIDTH(&w->geom);
+       r.ymax = r.ymin + RECT_WIDTH(&w->geom);
+
+       win_setGeometry(w, &r);
+}
+
+/**
+ * Resize the rectangle of a window.
+ *
+ * The window shrinks or grows to the specified size.
+ *
+ * \note Growing a window beyond the size of its
+ *       backing bitmap results in unspecified behavior.
+ *
+ * \note It is allowed to resize an orphan window.
+ */
+void win_resize(Window *w, coord_t width, coord_t height)
+{
+       Rect r;
+
+       r.xmin = w->geom.xmin;
+       r.ymin = w->geom.ymin;
+       r.xmax = r.xmin + width;
+       r.ymax = r.ymin + height;
+
+       win_setGeometry(w, &r);
+}
+
+/**
+ * Initialize a new window structure.
+ *
+ *
+ * The new window initial position is set to (0,0).
+ * The size is set to the size of the installed bitmap,
+ * or (0,0) if there's no backing store.
+ *
+ * \arg bm  The bitmap to install as backing store
+ *          for drawing into the window, or NULL if
+ *          the window is not drawable.
+ */
+void win_create(Window *w, Bitmap *bm)
+{
+       w->parent = NULL;
+       w->bitmap = bm;
+       w->geom.xmin = 0;
+       w->geom.ymin = 0;
+       if (bm)
+       {
+               w->geom.xmax = bm->width;
+               w->geom.ymax = bm->height;
+       }
+       LIST_INIT(&w->children);
+}
+
diff --git a/gfx/win.h b/gfx/win.h
new file mode 100755 (executable)
index 0000000..d60041a
--- /dev/null
+++ b/gfx/win.h
@@ -0,0 +1,89 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2006 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \brief Very simple hierarchical windowing system.
+ *
+ * All functions in this module are to be intended as methods
+ * of the Window class.  Please see its documentation
+ * for a module-wise introduction.
+ *
+ * \see struct Window
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2006/01/23 23:14:29  bernie
+ *#* Implement simple, but impressive windowing system.
+ *#*
+ *#*/
+
+#ifndef GFX_WIN_H
+#define GFX_WIN_H
+
+#include <mware/list.h> /* Node, List */
+#include <gfx/gfx.h>    /* coord_t */
+
+
+EXTERN_C_BEGIN
+
+/**
+ * Window handle and context structure.
+ *
+ * A window is a small rectangular area on the
+ * screen backed by its own bitmap where you
+ * can draw.
+ *
+ * A window can contain any number of children
+ * sub-windows that can be depth arranged with
+ * respect to their siblings.
+ *
+ * At any time, a window and all its children
+ * can be drawn into another bitmap to display
+ * a complete screen, taking depth and
+ * overlapping into account.
+ *
+ * This rendering model is commonly referred to as
+ * screen composition, and is quite popular among
+ * modern windowing systems.
+ */
+typedef struct Window
+{
+       Node    link;      /**< Link us with other siblings into our parent.  */
+       struct Window *parent;  /**< Our parent window.  NULL for the root window. */
+
+       Bitmap *bitmap;    /**< Pixel storage for window contents. */
+       Rect    geom;      /**< [px] Window size and position relative to parent. */
+
+       /**
+        * List of child windows, arranged by depth (front to back).
+        *
+        * Child top/left coordinates are relative to us.
+        */
+       List    children;
+
+} Window;
+
+/*
+ * Public function prototypes
+ */
+void win_compose(Window *w);
+void win_open(Window *w, Window *parent);
+void win_close(Window *w);
+void win_raise(Window *w);
+void win_setGeometry(Window *w, Rect *new_geom);
+void win_move(Window *w, coord_t left, coord_t top);
+void win_resize(Window *w, coord_t width, coord_t height);
+void win_create(Window *w, Bitmap *bm);
+
+EXTERN_C_END
+
+#endif /* GFX_WIN_H */
+
diff --git a/gfx/win_test.c b/gfx/win_test.c
new file mode 100755 (executable)
index 0000000..c78b479
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+ * \file
+ * <!--
+ * Copyright 2006 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \brief Windowing system test.
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2006/01/23 23:14:29  bernie
+ *#* Implement simple, but impressive windowing system.
+ *#*
+ *#*/
+
+#include <emul/emul.h>
+#include <drv/lcd_gfx.h>
+#include <gfx/gfx.h>
+#include <gfx/win.h>
+
+static void magic(struct Bitmap *bitmap, coord_t x, coord_t y)
+{
+       static const coord_t coords[] = { 120, 34, 90, 90, 30, 90, 0, 34, 60, 0, 90, 90, 0, 34, 120, 34, 30, 90, 60, 0 };
+       unsigned int i;
+
+       gfx_moveTo(bitmap, coords[countof(coords)-2]/2 + x, coords[countof(coords)-1]/3 + y);
+       for (i = 0; i < countof(coords); i += 2)
+               gfx_lineTo(bitmap, coords[i]/2 + x, coords[i+1]/3 + y);
+}
+
+int main(int argc, char *argv[])
+{
+       emul_init(&argc, argv);
+       lcd_init();
+
+       const coord_t small_left = 45, small_top = 30, small_width = 50, small_height = 30;
+       const coord_t large_left = -10, large_top = 10, large_width = 85, large_height = 41;
+
+       Window root_win, small_win, large_win;
+       Bitmap small_bm, large_bm;
+       uint8_t small_raster[RASTER_SIZE(small_width, small_height)];
+       uint8_t large_raster[RASTER_SIZE(large_width, large_height)];
+
+       win_create(&root_win,  &lcd_bitmap);
+
+       gfx_bitmapInit(&large_bm, large_raster, large_width, large_height);
+       win_create(&large_win, &large_bm);
+       win_open(&large_win, &root_win);
+       win_move(&large_win, large_left, large_top);
+
+       gfx_bitmapInit(&small_bm, small_raster, small_width, small_height);
+       win_create(&small_win, &small_bm);
+       win_open(&small_win, &root_win);
+       win_move(&small_win, small_left, small_top);
+
+
+       coord_t x = 0, y = LCD_WIDTH / 2;
+       coord_t xdir = +1, ydir = -1;
+       coord_t xdir_large = +1;
+       coord_t ydir_small = +1;
+       int raise_counter = 0;
+       int i;
+       Bitmap *bm;
+
+       for(;;)
+       {
+               /* Background animation */
+               bm = &lcd_bitmap;
+               gfx_bitmapClear(bm);
+/*             gfx_setClipRect(bm, 0, 0, bm->width, bm->height);
+               gfx_rectDraw(bm, 10, 10, bm->width-10, bm->height-10);
+               gfx_setClipRect(bm, 11, 11, bm->width-11, bm->height-11);
+*/             magic(bm, x, y);
+               x += xdir;
+               y += ydir;
+               if (x >= bm->width)  xdir = -1;
+               if (x <= -50)        xdir = +1;
+               if (y >= bm->height) ydir = -1;
+               if (y <= -50)        ydir = +1;
+
+               /* Large window animation */
+               bm = large_win.bitmap;
+               gfx_bitmapClear(bm);
+               for (i = 0; i < bm->height / 2; i += 2)
+                       gfx_rectDraw(bm, 0 + i, 0 + i, bm->width - i, bm->height - i);
+
+
+               /* Small window animation */
+               bm = small_win.bitmap;
+               gfx_bitmapClear(bm);
+               gfx_rectDraw(bm, 0, 0, bm->width, bm->height);
+               gfx_line(bm, 0, 0, bm->width, bm->height);
+               gfx_line(bm, bm->width, 0, 0, bm->height);
+
+               /* Move windows around */
+               win_move(&large_win, large_win.geom.xmin + xdir_large, large_top);
+               if (large_win.geom.xmin < -20) xdir_large = +1;
+               if (large_win.geom.xmin > RECT_WIDTH(&root_win.geom) - 5) xdir_large = -1;
+
+               win_move(&small_win, small_left, small_win.geom.ymin + ydir_small);
+               if (small_win.geom.ymin < -20) ydir_small = +1;
+               if (small_win.geom.ymin > RECT_HEIGHT(&root_win.geom) - 5) ydir_small = -1;
+
+               ++raise_counter;
+               if (raise_counter % 997 == 0)
+                       win_raise(&small_win);
+               else if (raise_counter % 731 == 0)
+                       win_raise(&large_win);
+
+               win_compose(&root_win);
+               lcd_blit_bitmap(root_win.bitmap);
+               emul_idle();
+               usleep(10000);
+       }
+
+       emul_cleanup();
+       return 0;
+}