From dcc3a41036f374a48b2b1791575e11e5e3f09d02 Mon Sep 17 00:00:00 2001 From: Ingo Albrecht Date: Wed, 1 Sep 2010 21:24:34 +0200 Subject: [PATCH] ui: Some experimental code snippets i cobbled together several months ago. --- src/target/ui-experiment/README | 11 ++ src/target/ui-experiment/display.h | 46 +++++ src/target/ui-experiment/font.h | Bin 0 -> 61204 bytes src/target/ui-experiment/image.h | 166 ++++++++++++++++++ src/target/ui-experiment/menu.h | 18 ++ src/target/ui-experiment/pixel.h | 113 +++++++++++++ src/target/ui-experiment/png2tiny.c | 51 ++++++ src/target/ui-experiment/screen.h | 21 +++ src/target/ui-experiment/sdl.c | 250 ++++++++++++++++++++++++++++ src/target/ui-experiment/sdl.h | 9 + src/target/ui-experiment/ui.h | 81 +++++++++ 11 files changed, 766 insertions(+) create mode 100644 src/target/ui-experiment/README create mode 100644 src/target/ui-experiment/display.h create mode 100644 src/target/ui-experiment/font.h create mode 100644 src/target/ui-experiment/image.h create mode 100644 src/target/ui-experiment/menu.h create mode 100644 src/target/ui-experiment/pixel.h create mode 100644 src/target/ui-experiment/png2tiny.c create mode 100644 src/target/ui-experiment/screen.h create mode 100644 src/target/ui-experiment/sdl.c create mode 100644 src/target/ui-experiment/sdl.h create mode 100644 src/target/ui-experiment/ui.h diff --git a/src/target/ui-experiment/README b/src/target/ui-experiment/README new file mode 100644 index 000000000..81b34d725 --- /dev/null +++ b/src/target/ui-experiment/README @@ -0,0 +1,11 @@ + +This is some exploratory and experimental code related +to the development of a proper lcd-based ui. + +It has been written by Ingo Albrecht +and, lacking further arrangements, should be considered to +be licensed under the GNU GPL v2 or later. + +I have placed this here due to general interest. All of it +can safely be removed once we have a proper ui. + diff --git a/src/target/ui-experiment/display.h b/src/target/ui-experiment/display.h new file mode 100644 index 000000000..559137002 --- /dev/null +++ b/src/target/ui-experiment/display.h @@ -0,0 +1,46 @@ + +#ifndef _UI_DISPLAY_H +#define _UI_DISPLAY_H + +#include +#include + +/** + * Displays - physical display devices + * + * This layer is introduced tentatively, expecting use + * of OSMOCOM on multi-display phones, most likely + * with a main screen and a cover screen. + * + */ +struct display { + const char *name; + + pxtype_t pixeltype; + pxsize_t width; + pxsize_t height; + + /* We always operate on an in-memory frame buffer that + * can be put on display using damage functions provided + * by the image class. + */ + struct image *fbuf; + + /* + * We display a top-level widget. + */ + struct widget *widget; + + /* + * We hold a graphics context, configured for the target + * pixel format. + */ + struct graphics *graphics; + + + void (*draw) (struct display *display); + + void *priv; +}; + +#endif diff --git a/src/target/ui-experiment/font.h b/src/target/ui-experiment/font.h new file mode 100644 index 0000000000000000000000000000000000000000..5dc6eae777407af78a7789df04a01c0f814ddc3c GIT binary patch literal 61204 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 y^0PBPXqCz + +#include +#include + +struct image { + pxtype_t type; + pxdims_t size; + unsigned char *data; +}; + + +struct image font_img_v = { + .type = PXTYPE_MONO_V8, + .size = {8, 2048}, + .data = &fontdata_r8x8, +}; + +struct image font_img_h = { + .type = PXTYPE_MONO_H8, + .size = {8, 2048}, + .data = &fontdata_r8x8_horiz, +}; + +px_t +image_get_pixel(struct image *img, pxoff_t x, pxoff_t y) { + unsigned stride, base, offset; + const uint8_t *p8; + const uint16_t *p16; + + switch(img->type) { + case PXTYPE_MONO_V8: + stride = img->size.w; + base = y / 8; + offset = y % 8; + p8 = (uint8_t*)(img->data + x + base * stride); + return px_from_mono(((*p8) >> offset) & 1); + case PXTYPE_MONO_H8: + stride = img->size.w / 8; + base = x / 8; + offset = x % 8; + p8 = (uint8_t*)(img->data + base + y * stride); + return px_from_mono(((*p8) >> offset) & 1); + case PXTYPE_RGB444: + stride = img->size.w * 2; + p16 = (uint16_t*)(img->data + x * 2 + y * stride); + return px_from_rgb444(*p16); + } + + return 0; +} + +void +image_set_pixel(struct image *img, pxoff_t x, pxoff_t y, px_t v) { + unsigned stride, base, offset; + uint8_t *p8; + uint16_t *p16; + + switch(img->type) { + case PXTYPE_MONO_V8: + stride = img->size.w; + base = y / 8; + offset = y % 8; + p8 = (uint8_t*)(img->data + x + base * stride); + *p8 |= (px_to_mono(v) << offset); + break; + case PXTYPE_MONO_H8: + stride = img->size.w / 8; + base = x / 8; + offset = x % 8; + p8 = (uint8_t*)(img->data + base + y * stride); + *p8 |= (px_to_mono(v) << offset); + break; + case PXTYPE_RGB444: + stride = img->size.w * 2; + p16 = (uint16_t*)(img->data + x * 2 + y * stride); + *p16 = px_to_rgb444(v); + break; + } +} + +void +image_blit(struct image *dst, pxposn_t dstp, + struct image *src, pxposn_t srcp, + pxdims_t d) +{ + unsigned x, y, s; + + printf("blit %dx%d from %dx%d to %dx%d\n", d.w, d.h, srcp.x, srcp.y, dstp.x, dstp.y); + + // *cough* slow. + for(y = 0; y < d.h; y++) { + for(x = 0; x < d.w; x++) { + px_t p = image_get_pixel(src, srcp.x + x, srcp.y + y); + image_set_pixel(dst, dstp.x + x, dstp.y + y, p); + } + } +} + +void +image_draw_char(struct image *dst, pxposn_t p, char chr) { + unsigned char c = (unsigned char)chr; + pxposn_t pf = {0,c*8}; + pxdims_t d = {8,8}; + image_blit(dst, p, &font_img_h, pf, d); +} + +void +image_draw_string(struct image *dst, pxposn_t p, char *str) { + while(*str) { + image_draw_char(dst, p, *str); + p.x += 8; + str++; + } +} + +static void +image_fill_rect_rgb444(struct image *dst, pxrect_t rect, uint16_t color) { + unsigned x, y, s; + uint16_t *p; + + unsigned stride = dst->size.w * 2; + + for(y = rect.p.y; y < rect.p.y + rect.d.h; y++) { + for(x = rect.p.x; x < rect.p.x + rect.d.w; x++) { + p = (uint16_t*)&dst->data[x * 2 + y * stride]; + *p = color; + } + } +} + +void +image_fill_rect(struct image *dst, pxrect_t rect, px_t color) +{ + switch(dst->type) { + case PXTYPE_MONO_V8: + break; + case PXTYPE_MONO_H8: + break; + case PXTYPE_RGB444: + image_fill_rect_rgb444(dst, rect, px_to_rgb444(color)); + break; + } +} + +void +image_draw_hline(struct image *dst, pxposn_t posn, pxoff_t len, px_t color) +{ +} + +void +image_draw_vline(struct image *dst, pxposn_t posn, pxoff_t len, px_t color) +{ +} + +void +image_draw_rect(struct image *dst, pxrect_t rect, px_t color) +{ +} + +#endif diff --git a/src/target/ui-experiment/menu.h b/src/target/ui-experiment/menu.h new file mode 100644 index 000000000..d9cc97b33 --- /dev/null +++ b/src/target/ui-experiment/menu.h @@ -0,0 +1,18 @@ + +/** + * Menus - menus and menu items + * + * We represent both menus and menu items in a single structure. + * + * They share the properties of having a title as well as having + * interaction callbacks such as on_select. + * + * Menus have a child item array that is indexed by menu position. + * The position of items in this array is used for numeric menu navigation. + * + */ +struct menu { + const char *title; + void (*on_select)(void); + struct menu *children[10]; +}; diff --git a/src/target/ui-experiment/pixel.h b/src/target/ui-experiment/pixel.h new file mode 100644 index 000000000..dde28e2ae --- /dev/null +++ b/src/target/ui-experiment/pixel.h @@ -0,0 +1,113 @@ + +#ifndef _UI_PIXEL_H +#define _UI_PIXEL_H + +#include +#include + +/** Supported pixel types */ +typedef enum { + _PXTYPE_INVALID, + + /** "Generic" pixel type (24/32bit RGB) */ + PXTYPE_GENERIC, + + /** 8 horizontal mono pixels per byte */ + PXTYPE_MONO_H8, + + /** 8 vertical mono pixels per byte */ + PXTYPE_MONO_V8, + + /** 12bit RGB444 colors */ + PXTYPE_RGB444, + +} pxtype_t; + + +/** Generic pixel type */ +typedef uint32_t px_t; + +#define PX_R(p) ((uint8_t)((v) >> 16 & 0xFF)) +#define PX_G(p) ((uint8_t)((v) >> 8 & 0xFF)) +#define PX_B(p) ((uint8_t)((v) >> 0 / 0xFF)) + +#define PX_RGB(r,g,b) ((px_t)((r)<<16|(g)<<8|(b))) + +#define PX_BLACK ((px_t)0x000000) +#define PX_RED ((px_t)0xFF0000) +#define PX_GREEN ((px_t)0x00FF00) +#define PX_BLUE ((px_t)0x0000FF) +#define PX_WHITE ((px_t)0xFFFFFF) + + +/* Mono types */ +typedef uint8_t px_mono_t; + +#define PX_MONO_BLACK ((px_mono_t)0) +#define PX_MONO_WHITE ((px_mono_t)1) + +inline px_t +px_from_mono(uint8_t v) { + return v ? PX_WHITE : PX_BLACK; +} + +inline uint8_t +px_to_mono(px_t v) { + uint16_t a = (PX_R(v) + PX_G(v) + PX_B(v)) / 3; + return (a >= 0x7f) ? 1 : 0; +} + +/* RGB444 */ +typedef uint16_t px_rgb444_t; + +#define PX_RGB444_R(p) ((p) >> 8 & 0xf) +#define PX_RGB444_G(p) ((p) >> 4 & 0xf) +#define PX_RGB444_B(p) ((p) >> 0 & 0xf) + +#define PX_RGB444_RGB(r,g,b) ((px_rgb444_t)((r)<<8|(g)<<4|(b))) + +inline px_t +px_from_rgb444(px_rgb444_t v) { + return + PX_RGB444_R(v) << 16 | PX_RGB444_R(v) << 20 + | PX_RGB444_G(v) << 8 | PX_RGB444_G(v) << 12 + | PX_RGB444_B(v) << 0 | PX_RGB444_B(v) << 4; +} + +inline uint16_t +px_to_rgb444(px_t v) { + uint8_t r = (v >> 20) & 0xF; + uint8_t g = (v >> 12) & 0xF; + uint8_t b = (v >> 4) & 0xF; + + uint16_t res = (r<< 8) | (g << 4) | (b << 0); + + return res; +} + + +/** Size in pixels */ +typedef uint16_t pxsize_t; + +/** Offset in pixels */ +typedef int16_t pxoff_t; + +/** 2D position in pixels */ +typedef struct { + pxoff_t x; + pxoff_t y; +} pxposn_t; + +/** 2D dimensions in pixels */ +typedef struct { + pxsize_t w; + pxsize_t h; +} pxdims_t; + +/** 2D rectangle in pixels */ +typedef struct { + pxposn_t p; + pxdims_t d; +} pxrect_t; + +#endif diff --git a/src/target/ui-experiment/png2tiny.c b/src/target/ui-experiment/png2tiny.c new file mode 100644 index 000000000..d314b9a2a --- /dev/null +++ b/src/target/ui-experiment/png2tiny.c @@ -0,0 +1,51 @@ + +#include + +#include + +enum { + FORMAT_NONE, + FORMAT_C +}; + +void +version(const char *name) { + puts(name); + //printf("%s rev %s\n", name, REVISION); + exit(2); +} + +void +usage(const char *name) { + printf("Usage: %s [-hv] [-f outfmt] [-s outsym] \n"); + exit(2); +} + +int +main(int argc, char **argv) { + int opt, outfmt; + const char *outsym = NULL; + SDL_Surface *img; + + while((opt = getopt(argc, argv, "f:s:hv")) != -1) { + switch(opt) { + case 'f': + if(!strcmp(optarg, "c")) { + outfmt = FORMAT_C; + } + break; + case 's': + outsym = optarg; + break; + case 'v': + version(argv[0]); + break; + case 'h': + default: + usage(argv[0]); + break; + } + } + + return 0; +} diff --git a/src/target/ui-experiment/screen.h b/src/target/ui-experiment/screen.h new file mode 100644 index 000000000..1174d9e70 --- /dev/null +++ b/src/target/ui-experiment/screen.h @@ -0,0 +1,21 @@ + +/** + * Screens - full-screen dialogs + * + * These compose the first level of interaction in the UI. + * + * There is always exactly one active screen, which is in + * control of the entire display on which it is displayed. + * + * Screen activations are stacked, providing interaction depth. + * + */ +struct screen { + const char *name; + void (*on_enter)(void); + void (*on_leave)(void); + void (*on_render)(void); + void (*on_key_press)(void); + void (*on_key_release)(void); +}; + diff --git a/src/target/ui-experiment/sdl.c b/src/target/ui-experiment/sdl.c new file mode 100644 index 000000000..e6daac70b --- /dev/null +++ b/src/target/ui-experiment/sdl.c @@ -0,0 +1,250 @@ + +#include +#include +#include + +#include + +#include + +#define SDL_PRIV(d) ((struct sdl_display*)(d)->priv) + +#define REFRESH_INTERVAL_MSEC 50 + +struct sdl_display { + SDL_Surface *display; + SDL_TimerID refresh; + unsigned width; + unsigned height; + unsigned scale; +}; + +static Uint32 sdl_redraw_callback(Uint32 interval, void *param) { + struct display *display = (struct display*)param; + + display->draw(display); + + return interval; +} + +void +sdl_init(struct display *display, + unsigned width, unsigned height, unsigned scale) +{ + if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER)) { + printf("Failed to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + atexit(&SDL_Quit); + + struct sdl_display *priv = SDL_PRIV(display); + + priv->width = width; + priv->height = height; + priv->scale = scale; + + priv->display = SDL_SetVideoMode(width * scale, height * scale, 32, 0); + if(!priv->display) { + printf("Failed to set SDL video mode: %s\n", SDL_GetError()); + exit(1); + } + + priv->refresh = SDL_AddTimer(REFRESH_INTERVAL_MSEC, + &sdl_redraw_callback, display); + if(!priv->refresh) { + printf("Failed to add refresh timer: %s\n", SDL_GetError()); + exit(1); + } +} + +void +sdl_draw(struct display *display) +{ + struct sdl_display *priv = SDL_PRIV(display); + + struct image *img = display->fbuf; + + SDL_Rect r; + + r.w = priv->scale; + r.h = priv->scale; + + if(img->type == PXTYPE_RGB444) { + unsigned stride = img->size.w * 2; + + unsigned x, y; + for(y = 0; y < img->size.h; y++) { + for(x = 0; x < img->size.w; x++) { + px_t color = image_get_pixel(img, x, y); + + r.x = x * priv->scale; + r.y = y * priv->scale; + + SDL_FillRect(priv->display, &r, color); + } + } + } else { + puts("Unsupported framebuffer type for SDL emulator."); + exit(1); + } + + SDL_UpdateRect(priv->display, 0, 0, 0, 0); +} + + +static struct sdl_display display_sdl_priv; + +uint8_t sdl_fbuf[96*64*2]; + +struct image display_sdl_fbuf = { + .type = PXTYPE_RGB444, + .size = {96, 64}, + .data = &sdl_fbuf +}; + +struct display display_sdl = { + .name = "Main Display", + .fbuf = &display_sdl_fbuf, + .priv = &display_sdl_priv, + .draw = &sdl_draw +}; + +uint16_t fnord_buf[] = { + 0x0F00, + 0x00F0, + 0x000F, + 0x00FF, + 0x0F00, + 0x00F0, + 0x000F, + 0x00FF, + 0x0F00, + 0x00F0, + 0x000F, + 0x00FF, + 0x0F00, + 0x00F0, + 0x000F, + 0x00FF, + 0x0F00, + 0x00F0, + 0x000F, + 0x00FF, + 0x0F00, + 0x00F0, + 0x000F, + 0x00FF, + 0x0F00, + 0x00F0, + 0x000F, + 0x00FF, + 0x0F00, + 0x00F0, + 0x000F, + 0x00FF + +}; + +struct image fnord = { + .type = PXTYPE_RGB444, + .size = {8,4}, + .data = &fnord_buf +}; + +uint8_t fubar_img[] = { + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x0f + +}; + +struct image fubar = { + .type = PXTYPE_MONO_V8, + .size = {8,16}, + .data = &fubar_img +}; + +void +sdl_run(void) +{ + int r; + SDL_Event e; + + while((r = SDL_WaitEvent(&e))) { + + if(e.type == SDL_KEYDOWN) { + if(e.key.keysym.sym == SDLK_ESCAPE) { + puts("Bloody quitter!"); + break; + } + if(e.key.keysym.sym == SDLK_SPACE) { + pxposn_t dp = {0,0}; + pxposn_t sp = {0,0}; + pxdims_t d = {8,4}; + + image_blit(&display_sdl_fbuf, dp, + &fnord, sp, + d); + + sp.x = 0; + sp.y = 0; + dp.x = 5; + dp.y = 10; + d.w = 8; + d.h = 16; + + image_blit(&display_sdl_fbuf, dp, + &fubar, sp, + d); + + pxrect_t r = {{12,0},{40,20}}; + image_fill_rect(&display_sdl_fbuf, + r, + 0xFF00FF); + + +#if 0 + dp.x = 0; + dp.y = 0; + + image_draw_string(&display_sdl_fbuf, dp, + "ABCDEFGHI"); + + dp.y += 10; + + image_draw_string(&display_sdl_fbuf, dp, + "abcdefghi"); + +#endif + + sdl_draw(&display_sdl); + + } + } + + switch(e.type) { + case SDL_KEYDOWN: + case SDL_KEYUP: + printf("Key %d %d\n", e.key.keysym.sym, e.key.state); + break; + } + } + + if(!r) { + printf("Failed to wait for SDL event: %s\n", SDL_GetError()); + exit(1); + } + +} + +int +main(void) +{ + sdl_init(&display_sdl, 96, 64, 4); + + sdl_run(); + + return 0; +} diff --git a/src/target/ui-experiment/sdl.h b/src/target/ui-experiment/sdl.h new file mode 100644 index 000000000..5a3d47520 --- /dev/null +++ b/src/target/ui-experiment/sdl.h @@ -0,0 +1,9 @@ + +#ifndef _UI_SDL_H +#define _UI_SDL_H + +#include + +extern struct display display_sdl; + +#endif diff --git a/src/target/ui-experiment/ui.h b/src/target/ui-experiment/ui.h new file mode 100644 index 000000000..9bc7c3240 --- /dev/null +++ b/src/target/ui-experiment/ui.h @@ -0,0 +1,81 @@ + +/****** MESSAGING MENU ******/ + +struct menu menu_message_compose = { + .title = "Compose", + .help = "Write a new text message." +}; + +struct menu menu_message_inbox = { + .title = "Inbox", + .help = "Incoming text messages" +}; + +struct menu menu_message_outbox = { + .title = "Outbox", + .help = "Outgoing text messages" +}; + +struct menu menu_message_sent = { + .title = "Sent", + .help = "Previously sent text messages" +}; + +struct menu menu_messages = { + .title = "Messages", + .help = "Short message service options", + .children = { + [0] = &menu_message_compose, + [1] = &menu_message_inbox, + [2] = &menu_message_outbox, + [3] = &menu_message_sent + } +}; + +/****** NETWORK MENU ******/ + +struct menu menu_network_about = { + .title = "About this network", + .help = "Information about your current network", +}; + +struct menu menu_network = { + .title = "Network", + .help = "Network interaction options", + .children = { + } +}; + +/****** SETTINGS MENU ******/ + +struct menu menu_settings = { + .title = "Settings", + .help = "Configure your phone", + .children = { + } +}; + +/****** MAIN MENU ******/ + +struct menu menu_about = { + .title = "About", + .help = "Information about this phone", +}; + +struct menu menu_main = { + .title = "Main Menu", + .children = { + [0] = &menu_messages, + [7] = &menu_network, + [8] = &menu_settings, + [9] = &menu_about, + }, +}; + + + +int +main(void) { + &menu_main; + return 0; +};