--- /dev/null
+/*!
+ * \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);
+}
+
--- /dev/null
+/*!
+ * \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 */
+
--- /dev/null
+/**
+ * \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;
+}