swk

static widget kit
git clone git://git.suckless.org/swk
Log | Files | Refs | README | LICENSE

commit 496e2221c65c0c2d568d6a470abc1cef654e595a
parent 04d94badb03c95e9baca7076233804944b7d04d9
Author: pancake <pancake@nopcode.org>
Date:   Wed, 21 Apr 2010 03:21:46 +0200

added sdl_ttf as dependency to draw text
basic example is now working with layout and clicks
implemented basic drawing primitives in sdl backend
sdl backend can be configured with few defines
on mouse over and click change box selection
added 'Alt' modifier to SwkKeyMod
Diffstat:
Inconsolata.otf | 0
Makefile | 6++----
gi_sdl.c | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
swk.c | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
swk.h | 20+++++++++++++-------
test.c | 22+++++++++++++++++-----
6 files changed, 235 insertions(+), 52 deletions(-)

diff --git a/Inconsolata.otf b/Inconsolata.otf Binary files differ. diff --git a/Makefile b/Makefile @@ -4,18 +4,16 @@ VERSION=0.1 DESTDIR?= PREFIX?=${DESTDIR}/usr/local LIBDIR?=${PREFIX}/lib +CFLAGS+=-I. # graphic backend GI?=sdl -GI_LIBS=-lSDL +GI_LIBS=-lSDL -lSDL_ttf GI_OBJS=gi_${GI}.o all: static test -test.o: - ${CC} -I. test.c -c -o test.o - test: test.o libswk.a ${CC} test.o -o test libswk.a ${GI_LIBS} diff --git a/gi_sdl.c b/gi_sdl.c @@ -1,7 +1,46 @@ #include <SDL/SDL.h> +#include <SDL/SDL_ttf.h> #include "swk.h" +#define HICOLOR 0xa0,0x00,0x00 +#define FGCOLOR 0xa0,0xa0,0xa0 +#define BGCOLOR 0x00,0x00,0x00 +#define TFCOLOR 0xff,0xff,0xff +#define FONTNAME "Inconsolata.otf" +//#define FONTSIZE 16 +#define FONTSIZE 32 +#define FS FONTSIZE +#define BPP 32 +/* --- */ + + +static Uint32 pal[ColorLast]; +static SDL_Color fontcolor = { TFCOLOR }; static SDL_Surface *screen = NULL; +static TTF_Font *font = NULL; + +static void putpixel(int x, int y, Uint32 pixel) { + int bpp = screen->format->BytesPerPixel; + Uint8 *p; + p = (Uint8 *)screen->pixels + y * screen->pitch + x * bpp; +#if BPP == 8 + *p = pixel; +#elif BPP == 16 + *(Uint16 *)p = pixel; +#elif BPP == 24 + #if SDL_BYTEORDER == SDL_BIG_ENDIAN + p[0] = (pixel >> 16) & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = pixel & 0xff; + #else + p[0] = pixel & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = (pixel >> 16) & 0xff; + #endif +#elif BPP == 32 + *(Uint32 *)p = pixel; +#endif +} int swk_gi_init(SwkWindow *w) { @@ -9,17 +48,32 @@ swk_gi_init(SwkWindow *w) { fprintf(stderr, "Cannot initialize SDL\n"); return 0; } - SDL_SetVideoMode(w->r.w, w->r.h, 32, SDL_DOUBLEBUF|SDL_RESIZABLE); + if (TTF_Init()==-1) { + fprintf(stderr, "Cannot initialize TTF: %s\n", TTF_GetError()); + return 0; + } + SDL_SetVideoMode(w->r.w, w->r.h, BPP, SDL_DOUBLEBUF|SDL_RESIZABLE); + SDL_WM_SetCaption(w->title, NULL); screen = SDL_GetVideoSurface(); SDL_EnableUNICODE(1); SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + pal[ColorFG] = SDL_MapRGB(screen->format, FGCOLOR); + pal[ColorBG] = SDL_MapRGB(screen->format, BGCOLOR); + pal[ColorHI] = SDL_MapRGB(screen->format, HICOLOR); + font = TTF_OpenFont(FONTNAME, FONTSIZE); + if (font == NULL) { + fprintf(stderr, "Cannot open font '%s'\n", FONTNAME); + return 0; + } return 1; } int swk_gi_update(SwkWindow *w) { - SDL_SetVideoMode(screen->w, screen->h, 32, SDL_DOUBLEBUF|SDL_RESIZABLE); + SDL_SetVideoMode(screen->w, screen->h, BPP, SDL_DOUBLEBUF|SDL_RESIZABLE); screen = SDL_GetVideoSurface(); + w->r.w = screen->w / FS; + w->r.h = screen->h / FS; return 1; } @@ -28,18 +82,29 @@ swk_gi_exit() { SDL_Quit(); } + +static int has_event = 0; +static SDL_Event lastev = {.type=-1}; + +int +swk_gi_has_event() { + if (!has_event) + has_event = SDL_PollEvent(&lastev); + return has_event; +} + SwkEvent * swk_gi_event(int dowait) { - int evret; SDL_Event event; static SwkEvent ev; SwkEvent *ret = NULL; - if (dowait) evret = SDL_WaitEvent(&event); - else evret = SDL_PollEvent(&event); + if(has_event) { + event = lastev; + } else has_event = SDL_WaitEvent(&event); - if (evret) - switch (event.type) { + if (has_event); + switch(event.type) { case SDL_VIDEORESIZE: fprintf(stderr, "resize %d %d\n", event.resize.w, event.resize.h); SDL_SetVideoMode(event.resize.w, event.resize.h, @@ -53,17 +118,17 @@ swk_gi_event(int dowait) { case SDL_MOUSEMOTION: ret = &ev; ev.type = EMotion; - ev.data.motion.x = event.motion.x; - ev.data.motion.y = event.motion.y; - fprintf(stderr, "event: motion %d %d\n", - event.motion.x, event.motion.y); + ev.data.motion.x = event.motion.x / FS; + ev.data.motion.y = event.motion.y / FS; + // fprintf(stderr, "event: motion %d %d\n", + // event.motion.x, event.motion.y); break; case SDL_MOUSEBUTTONDOWN: ret = &ev; ev.type = EClick; ev.data.click.button = event.button.button; - ev.data.click.point.x = event.button.x; - ev.data.click.point.y = event.button.y; + ev.data.click.point.x = event.button.x / FS; + ev.data.click.point.y = event.button.y / FS; fprintf(stderr, "event: click %d\n", event.button.button); break; case SDL_KEYDOWN: @@ -72,14 +137,13 @@ swk_gi_event(int dowait) { ev.type = EKey; ev.data.key.keycode = event.key.keysym.unicode; ev.data.key.modmask = 0; - if(event.key.keysym.mod & KMOD_LCTRL || - event.key.keysym.mod & KMOD_RCTRL) + if(event.key.keysym.mod & KMOD_CTRL) ev.data.key.modmask |= Ctrl; - if(event.key.keysym.mod & KMOD_LSHIFT|| - event.key.keysym.mod & KMOD_RSHIFT) + if(event.key.keysym.mod & KMOD_SHIFT) ev.data.key.modmask |= Shift; - if(event.key.keysym.mod & KMOD_LMETA || - event.key.keysym.mod & KMOD_RMETA) + if(event.key.keysym.mod & KMOD_ALT) + ev.data.key.modmask |= Alt; + if(event.key.keysym.mod & KMOD_META) ev.data.key.modmask |= Meta; fprintf(stderr, "event: key %d %d\n", ev.data.key.modmask, ev.data.key.keycode); @@ -91,28 +155,53 @@ swk_gi_event(int dowait) { ret = &ev; break; } + has_event = 0; return ret; } void +swk_gi_clear() { + SDL_Rect rect = { 0, 0, screen->w, screen->h }; + SDL_FillRect(screen, &rect, pal[ColorBG]); +} + +void swk_gi_flip() { - fprintf(stderr, "flip\n"); - SDL_Flip(screen); + SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); } /* -- drawing primitives -- */ void -swk_gi_line(int x, int y, int w, int h) { +swk_gi_line(int x, int y, int w, int h, int color) { + int i; + x *= FS; y *= FS; + w *= FS; h *= FS; + + if (w==0) for(i=0;i<h;i++) putpixel(x, y+i, pal[color]); + else + if (h==0) for(i=0;i<w;i++) putpixel(x+i, y, pal[color]); } void -swk_gi_box(int x, int y, int w, int h) { +swk_gi_fill(int x, int y, int w, int h, int color) { + SDL_Rect area = { x*FS, y*FS, w*FS, h*FS }; + SDL_FillRect(screen, &area, pal[color]); } void -swk_gi_rect(int x, int y, int w, int h) { +swk_gi_rect(int x, int y, int w, int h, int color) { + swk_gi_line(x, y, w, 0, color); + swk_gi_line(x, y+h, w, 0, color); + swk_gi_line(x, y, 0, h, color); + swk_gi_line(x+w, y, 0, h, color); } void swk_gi_text(int x, int y, const char *text) { + SDL_Surface *ts = TTF_RenderText_Solid(font, text, fontcolor); + if (ts) { + SDL_Rect to = { x*FS, y*FS, ts->w, ts->h }; + SDL_BlitSurface(ts, NULL, screen, &to); + SDL_FreeSurface(ts); + } else fprintf(stderr, "Cannot render string (%s)\n", text); } diff --git a/swk.c b/swk.c @@ -13,16 +13,25 @@ swk_init(SwkWindow* window) { w->r.w = 640; w->r.h = 480; } - if (swk_gi_init(w)) + if (swk_gi_init(w)) { running = 1; + swk_update(); + } return running; } void swk_update() { - if (!swk_gi_update(w)) - running = 0; - else swk_gi_flip(); + SwkEvent ev = { .type = EExpose }; + if (swk_gi_update(w)) { + SwkBox *b = w->boxes; + swk_fit(); + for(;b->cb; b++) { + ev.box = b; + b->cb(&ev); + } + swk_gi_flip(); + } else running = 0; } void @@ -38,12 +47,37 @@ swk_loop() { swk_event_handle(e); } while (!e || e->type != EQuit); } +void +swk_fit_row(SwkBox *a, SwkBox *b, int y) { + int count, x = 0; + SwkBox *btmp; + count = 0; + for(btmp=a; btmp<b; btmp++) + count++; + if (count) { + int winc = w->r.w / count; + for(btmp=a; btmp<b; btmp++) { + btmp->r.x = x; + btmp->r.y = y; + btmp->r.w = winc; + btmp->r.h = 1; + x+=winc; + } + } +} void swk_fit() { - SwkBox *b; - for(b=w->boxes; b->cb; b++) - printf("Handler: %p text: \"%s\"\n", b->cb, b->text); + int y = 0; + SwkBox *b, *b2; + for(b=b2=w->boxes; b->cb; b++) { + if(b->r.w==-1 && b->r.h==-1) { + swk_fit_row(b2, b, y); + y += (int)(size_t)b->data; + b2 = b+1; + } + } + swk_fit_row(b2, b, y); } SwkEvent * @@ -57,14 +91,45 @@ swk_event(int dowait) { void swk_event_handle(SwkEvent *e) { + SwkBox *b; switch(e->type) { case EKey: - case EClick: - if (w->box && w->box->cb) + if (e->data.key.keycode == 9) { + /* not working */ + if (e->data.key.modmask&Ctrl) + swk_focus_prev(); + else swk_focus_next(); + swk_update(); + } + // send key to focused box + e->box = w->box; + if (w->box) w->box->cb(e); break; + case EMotion: + for(b=w->boxes;b->cb;b++) { + Point p = e->data.motion; + if (p.x>=b->r.x && p.x<=(b->r.x+b->r.w) + && p.y>=b->r.y && p.y<=(b->r.y+b->r.h)) { + w->box = e->box = b; + b->cb(e); + swk_update(); + break; + } + } + break; + case EClick: + for(b=w->boxes;b->cb;b++) { + Point p = e->data.click.point; + if (p.x>=b->r.x && p.x<=(b->r.x+b->r.w) + && p.y>=b->r.y && p.y<=(b->r.y+b->r.h)) { + e->box = w->box = b; + e->box->cb(e); + swk_update(); + } + } + break; case EExpose: - swk_fit(); swk_update(); break; case EQuit: @@ -94,6 +159,15 @@ swk_focus_prev() { /* widgets */ void swk_label(SwkEvent *e) { + Rect r; + switch(e->type) { + case EExpose: + r = e->box->r; + swk_gi_text(r.x, r.y, e->box->text); + break; + default: + break; + } } void @@ -102,10 +176,14 @@ swk_entry(SwkEvent *e) { void swk_button(SwkEvent *e) { + Rect r; switch(e->type) { case EExpose: - // TODO: use box position - swk_gi_rect(0, 0, 10, 10); + r = e->box->r; + if (w->box == e->box) + swk_gi_rect(r.x, r.y, r.w, r.h, ColorHI); + else swk_gi_rect(r.x, r.y, r.w, r.h, ColorFG); + swk_gi_text(r.x+1, r.y, e->box->text); break; default: break; diff --git a/swk.h b/swk.h @@ -1,8 +1,10 @@ /* See LICENSE file for copyright and license details. */ -#define SWK_NEWLINE .h=-1, .w=-1 + +#define SWK_NEWLINE(x) .data=(void*)(size_t)x, .r.w=-1, .r.h=-1, .cb = swk_filler typedef enum { EVoid, EClick, EMotion, EKey, EExpose, EQuit, ELast } SwkEventType; -typedef enum { Shift=1, Ctrl=2, Meta=4 } SwkKeyMod; +typedef enum { Shift=1, Ctrl=2, Alt=4, Meta=8 } SwkKeyMod; +typedef enum { ColorFG, ColorBG, ColorHI, ColorLast } Palete; typedef struct SwkBox SwkBox; @@ -37,14 +39,14 @@ typedef struct { Point motion; Key key; Rect expose; + int rows; } data; } SwkEvent; typedef void (*SwkEventCallback)(SwkEvent *e); struct SwkBox { - int w; - int h; + Rect r; SwkEventCallback cb; char *text; void *data; @@ -59,10 +61,14 @@ typedef struct { int swk_init(SwkWindow *w); int swk_gi_update(SwkWindow *w); +void swk_update(); void swk_exit(); void swk_fit(); +void swk_loop(); +void swk_fit_row(SwkBox *a, SwkBox *b, int y); SwkEvent * swk_event(); void swk_event_handle(SwkEvent *e); +int swk_gi_has_event(); void swk_focus_next(); void swk_focus_prev(); @@ -80,7 +86,7 @@ SwkEvent * swk_gi_event(); void swk_gi_flip(); -void swk_gi_line(int x, int y, int w, int h); -void swk_gi_box(int x, int y, int w, int h); -void swk_gi_rect(int x, int y, int w, int h); +void swk_gi_line(int x, int y, int w, int h, int color); +void swk_gi_fill(int x, int y, int w, int h, int color); +void swk_gi_rect(int x, int y, int w, int h, int color); void swk_gi_text(int x, int y, const char *text); diff --git a/test.c b/test.c @@ -2,21 +2,34 @@ #include "swk.h" static int count = 3; +static char text[64]; +static SwkBox helloworld[]; static void mybutton(SwkEvent *e) { if (e->type == EClick) { - fprintf(stderr, "Button clicked %d\n", count); + sprintf(text, "Do it again %d times\n", count); + helloworld[0].text = text; if (count-- == 0) swk_exit(); } swk_button(e); } + static SwkBox helloworld[] = { - { .cb=swk_label, .text="Press this button", }, - { SWK_NEWLINE }, + { SWK_NEWLINE(1) }, + { .cb=swk_label, .text="Press a button", }, + { SWK_NEWLINE(2) }, + { .cb=mybutton, .text="yes" }, { .cb=swk_filler, }, - { .cb=mybutton, .text="clickme" }, + { .cb=mybutton, .text="no" }, +#if 0 + { SWK_NEWLINE(1) }, + { .cb=mybutton, .text="yes" }, + { .cb=mybutton, .text="no" }, +#endif + { SWK_NEWLINE(5) }, + { .cb=swk_label, .text="--swktest", }, { .cb=NULL } }; @@ -26,7 +39,6 @@ main() { .title="Hello World", .boxes=helloworld }; - if (!swk_init(&w)) return 1; swk_loop();