From baf3454bd6fc9c9ba0884ae400c3d5841c06233f Mon Sep 17 00:00:00 2001 From: bernie Date: Mon, 23 Jan 2006 23:14:29 +0000 Subject: [PATCH] Implement simple, but impressive windowing system. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@485 38d2e660-2303-0410-9eaa-f027e97ec537 --- gfx/win.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++ gfx/win.h | 89 +++++++++++++++++++++++ gfx/win_test.c | 124 ++++++++++++++++++++++++++++++++ 3 files changed, 405 insertions(+) create mode 100755 gfx/win.c create mode 100755 gfx/win.h create mode 100755 gfx/win_test.c diff --git a/gfx/win.c b/gfx/win.c new file mode 100755 index 00000000..3d6db455 --- /dev/null +++ b/gfx/win.c @@ -0,0 +1,192 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \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 index 00000000..d60041aa --- /dev/null +++ b/gfx/win.h @@ -0,0 +1,89 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \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 /* Node, List */ +#include /* 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 index 00000000..c78b4796 --- /dev/null +++ b/gfx/win_test.c @@ -0,0 +1,124 @@ +/** + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \brief Windowing system test. + */ + +/*#* + *#* $Log$ + *#* Revision 1.1 2006/01/23 23:14:29 bernie + *#* Implement simple, but impressive windowing system. + *#* + *#*/ + +#include +#include +#include +#include + +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; +} -- 2.25.1