swk

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

commit 3b4b476d19e68b3cec52ea735742481356256e77
parent 175d41a26f55a312f2c90418b97a29b6bf09a915
Author: pancake <pancake@nopcode.org>
Date:   Fri, 11 Jun 2010 00:47:22 +0200

add support for a second column
hook Control-{H,L} to move left/right the column
one/two column setup can be changed in runtime
fix string corruption issue swk_gi_text
make SCROLLSPEED configurable
Diffstat:
TODO | 2+-
config.def.h | 10+++++++---
gi_sdl.c | 8++++----
swk.c | 135+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
swk.h | 7++++++-
t/test.c | 17++++++++++++-----
t/tlock.c | 6+++++-
t/ui.c | 37+++++++++++++++++++------------------
8 files changed, 135 insertions(+), 87 deletions(-)

diff --git a/TODO b/TODO @@ -1,6 +1,6 @@ TODO ==== - * add support for column breakers { SWK_NEWCOLUMN() } + * add support for negative colpos (align to right) * allow to set absolute font size * buttons must be 3 line height * receive fine-grained x,y in Point? for sketch or imaging stuff is important diff --git a/config.def.h b/config.def.h @@ -1,6 +1,8 @@ /* See LICENSE file for copyright and license details. */ /* appearance */ +#define SCROLLSPEED 2 +#define COLSPLIT 20 #define FONTSIZE 18 #define FONTBOLD 0 #define WINWIDTH 640 @@ -20,12 +22,14 @@ static SwkKeyBind keys[] = { { Ctrl, 'j', swk_focus_next }, { Ctrl, 'k', swk_focus_prev }, - { Ctrl, 8 , swk_focus_first }, - { Ctrl, 9 , swk_focus_prev }, + //{ Ctrl, 8 , swk_focus_first }, + //{ Ctrl, 9 , swk_focus_prev }, + { Ctrl, 8 , swk_column_move_left }, + { Ctrl, 12 , swk_column_move_right }, { 0 , 9 , swk_focus_next }, { Ctrl, 10 , swk_focus_next }, { Ctrl, 11 , swk_focus_prev }, - { Ctrl, 12 , swk_focus_activate }, +// { Ctrl, 12 , swk_focus_activate }, { 0 , KUp, swk_focus_prev }, { 0 , KDown, swk_focus_next }, { 0 , 13 , swk_focus_activate }, diff --git a/gi_sdl.c b/gi_sdl.c @@ -8,7 +8,7 @@ #include "config.h" #define FONTNAME "Inconsolata.otf" -#define FONTFACTOR 2.1 +#define FONTFACTOR 2.1 /* XXX */ #define BPP 32 #define SDLFLAGS SDL_DOUBLEBUF|SDL_RESIZABLE @@ -263,16 +263,16 @@ swk_gi_rect(Rect r, int color) { void swk_gi_text(Rect r, const char *text) { + const char *tptr = text; char *ptr = NULL; int w = (int)((double)r.w * FONTFACTOR); if(text && *text) { int len = text?strlen(text):0; if(len>w) { - ptr = strdup(text); - text = (const char *)ptr; + tptr = ptr = strdup(text); ptr[w]='\0'; } - SDL_Surface *ts = TTF_RenderText_Shaded(font, text, fontcolor, bgcolor); + SDL_Surface *ts = TTF_RenderText_Shaded(font, tptr, fontcolor, bgcolor); if(ts) { SDL_Rect to = { (r.x)*fs, r.y*fs, ts->w, ts->h }; SDL_BlitSurface(ts, NULL, screen, &to); diff --git a/swk.c b/swk.c @@ -13,6 +13,7 @@ static __thread int rendering = 0; int swk_use(SwkWindow *win) { w = win = win->_e.win = win; + w->colpos = COLSPLIT; if(win->box == NULL) swk_focus_first(w); if(w->r.w == 0 || w->r.h == 0) { @@ -30,38 +31,46 @@ void swk_update() { char text[8]; int roy, oy, scroll = 0; + int col = (w->boxes[1])?((w->colpos>w->r.w)?w->r.w:w->colpos):w->r.w; if(rendering) return; - //printf("boxy %d/%d\n", w->box->r.y, w->r.h); // TODO: Handle scrollup by widget focus - if (w->box->r.y > w->r.h) + if(w->box->r.y > w->r.h) setscrollbox(-2); rendering = 1; w->_e.type = EExpose; if(swk_gi_update(w)) { - SwkBox *b = w->boxes; + int count = 2; + int orw = w->r.w; + SwkBox *b = w->boxes[0]; swk_fit(w); swk_gi_clear(); - roy = oy = 0; - for(;b->cb; b++) { - w->_e.box = b; - if(b->r.w==-1 && b->r.h==-1 && ((int)(size_t)b->data)<0) - roy = oy+1; - if(b->scroll) - scroll = b->scroll; - if(roy && b->r.y < roy) { - sprintf(text, "(%d)", scroll); - Rect r = w->r; - r.x = r.w-1; - r.y = roy; - r.w = 3; - swk_gi_text(r, text); - swk_gi_line(--r.x, roy, r.w, 0, ColorHI); + for(w->r.w=col; ; b = w->boxes[1]) { + swk_fit(w); + roy = oy = 0; + for(;b->cb; b++) { + w->_e.box = b; + if(IS_SCROLLBOX(b)) + roy = oy+1; + if(b->scroll) + scroll = b->scroll; + if(roy && b->r.y < roy) { + Rect r = w->r; + r.x = col-1; + r.y = roy; + r.w = 3; + sprintf(text, "(%d)", scroll); + swk_gi_text(r, text); + swk_gi_line(--r.x, roy, 2, 0, ColorHI); + } else b->cb(&w->_e); + oy = b->r.y; } - else b->cb(&w->_e); - oy = b->r.y; + if(!w->boxes[1] || !--count) + break; + col = orw-w->col; } swk_gi_flip(); + w->r.w = orw; } rendering = 0; } @@ -84,19 +93,33 @@ swk_loop() { void swk_fontsize_increase() { swk_gi_fontsize(1); + w->colpos--; swk_update(w); } void swk_fontsize_decrease() { swk_gi_fontsize(-1); + w->colpos++; + swk_update(w); +} + +void +swk_column_move_left() { + w->colpos--; + swk_update(w); +} + +void +swk_column_move_right() { + w->colpos++; swk_update(w); } static void setscrollbox(int delta) { SwkBox *r = NULL; - SwkBox *b = w->boxes; + SwkBox *b = w->boxes[w->col]; for(; b->cb; b++) { if(IS_SCROLLBOX(b)) r = b; @@ -108,23 +131,23 @@ setscrollbox(int delta) { void swk_scroll_up() { - setscrollbox(2); + w->box = w->boxes[w->col]; + setscrollbox(SCROLLSPEED); } void swk_scroll_down() { - setscrollbox(-2); + w->box = w->boxes[w->col]; + setscrollbox(-SCROLLSPEED); } static void -swk_fit_row(SwkBox *a, SwkBox *b, int y) { - SwkBox *btmp; - int count = 0, x = 0; - for(btmp=a; btmp<b; btmp++) - count++; +swk_fit_row(SwkBox *a, SwkBox *b, int col, int y) { + int x = (col)?w->colpos:0, count = b-a; if(count) { int winc = w->r.w / count; - for(btmp=a; btmp<b; btmp++) { + SwkBox *btmp = a; + for(; btmp<b; btmp++) { btmp->r.x = x; btmp->r.y = y; btmp->r.w = winc; @@ -146,24 +169,27 @@ countrows(SwkBox *b) { void swk_fit() { + int i, x, y, skip, tskip; SwkBox *b, *b2; - int x, y = 0, skip = 0; - int tskip = 0; - for(b=b2=w->boxes; b->cb; b++) { - if(b->r.w==-1 && b->r.h==-1) { - x = (int)(size_t)b->data; - swk_fit_row(b2, b, y); - y += x-skip+tskip; - // vertical align // - tskip = 0; - if(x<0) y += w->r.h-countrows(b2); - b2 = b+1; - } else - if(b->r.h>1) - tskip = b->r.h; - y += b->scroll; + for(i=0;i<2;i++) { + skip = tskip = y = 0; + for(b=b2=w->boxes[i]; b->cb; b++) { + if(b->r.w==-1 && b->r.h==-1) { + x = (int)(size_t)b->data; + swk_fit_row(b2, b, i, y); + y += x-skip+tskip; + // vertical align // + tskip = 0; + if(x<0) y += w->r.h-countrows(b2); + b2 = b+1; + } else if(b->r.h>1) + tskip = b->r.h; + y += b->scroll; + } + swk_fit_row(b2, b, i, y); + if(!w->boxes[1]) + break; } - swk_fit_row(b2, b, y); } int @@ -201,7 +227,7 @@ swk_handle_event(SwkEvent *e) { break; } } - /* XXX: this must be implemented in app? */ + /* XXX: this must be implemented in app? .. sure */ if(e->data.key.keycode==27) { e->box = e->win->box; e->type = EQuit; @@ -215,7 +241,8 @@ swk_handle_event(SwkEvent *e) { swk_update(); break; case EMotion: - for(b=e->win->boxes; b->cb; b++) { + w->col = (e->data.motion.x > w->colpos)?1:0; + for(b=e->win->boxes[w->col]; b->cb; b++) { if(SWK_HIT(b->r, e->data.motion)) { e->win->box = e->box = b; b->cb(e); @@ -234,7 +261,7 @@ swk_handle_event(SwkEvent *e) { swk_scroll_down(e->win); break; default: - for(b=e->win->boxes; b->cb; b++) { + for(b=e->win->boxes[w->col]; b->cb; b++) { if(SWK_HIT(b->r, e->data.click.point)) { e->box = e->win->box = b; e->box->cb(e); @@ -256,18 +283,18 @@ swk_handle_event(SwkEvent *e) { void swk_focus_first() { - w->box = w->boxes; + w->box = w->boxes[w->col]; while(w->box->cb == swk_filler) w->box++; if(w->box->cb == NULL) - w->box = w->boxes; + w->box = w->boxes[w->col]; } void swk_focus_next() { w->box++; if(w->box->cb == NULL) - w->box = w->boxes; + w->box = w->boxes[w->col]; while(w->box->cb == swk_filler) w->box++; if(w->box->cb == NULL) @@ -276,7 +303,7 @@ swk_focus_next() { void swk_focus_prev() { - if(w->box == w->boxes) { + if(w->box == w->boxes[w->col]) { while(w->box->cb) w->box++; w->box--; @@ -284,8 +311,8 @@ swk_focus_prev() { w->box--; while(w->box->cb == swk_filler) { w->box--; - if(w->box < w->boxes) { - w->box = w->boxes; + if(w->box < w->boxes[w->col]) { + w->box = w->boxes[w->col]; swk_focus_prev(w); return; } diff --git a/swk.h b/swk.h @@ -70,7 +70,9 @@ struct SwkWindow { char *title; SwkEventCallback cb; Rect r; - SwkBox *boxes; + SwkBox *boxes[2]; + int col; + int colpos; /* internal use */ SwkBox *box; SwkEvent _e; @@ -93,8 +95,11 @@ void swk_scroll_up(); void swk_scroll_down(); void swk_fontsize_increase(); void swk_fontsize_decrease(); +void swk_column_move_left(); +void swk_column_move_right(); void swk_button(SwkEvent *e); +void swk_bigbutton(SwkEvent *e); void swk_label(SwkEvent *e); void swk_entry(SwkEvent *e); void swk_password(SwkEvent *e); diff --git a/t/test.c b/t/test.c @@ -30,7 +30,7 @@ static void myprogressbutton(SwkEvent *e) { pccount+=6; if(pccount > 100) { pccount = 0; - e->win->boxes = helloworld; + e->win->boxes[e->win->col] = helloworld; swk_update(e->win); } sprintf(pctext, "%d%%", pccount); @@ -65,7 +65,7 @@ static SwkBox about[] = { static void mybutton_about_ok(SwkEvent *e) { if(e->type == EClick) { - e->win->boxes = helloworld; + e->win->boxes[e->win->col] = helloworld; swk_update(e->win); } swk_button(e); @@ -73,7 +73,7 @@ static void mybutton_about_ok(SwkEvent *e) { static void mybutton_about(SwkEvent *e) { if(e->type == EClick) { - e->win->boxes = about; + e->win->boxes[e->win->col] = about; swk_update(e->win); } swk_button(e); @@ -96,7 +96,7 @@ static SwkBox scrollwin[] = { static void mybutton_numscroll(SwkEvent *e) { if(e->type == EClick) { - e->win->boxes = scrollwin; + e->win->boxes[e->win->col] = scrollwin; swk_update(e->win); } swk_button(e); @@ -139,11 +139,18 @@ static SwkBox helloworld[] = { { .cb=NULL } }; +static SwkBox column[] = { + { .cb=swk_label, .text="this is a column", }, + SWK_BOX_NEWLINE(-1), + { .cb=swk_label, .text="text in column", }, + { .cb=NULL } +}; + int main() { SwkWindow w = { .title="Hello World", - .boxes=helloworld, + .boxes={ helloworld, column }, .box=helloworld+10, //.r = { 0, 0, 320, 240 }, /* diff --git a/t/tlock.c b/t/tlock.c @@ -60,13 +60,17 @@ static void init_alarm() { int main() { SwkWindow w = { .title="touch lock", - .boxes=contents, + .boxes={contents,NULL}, .box=contents, + .r={200, 100, 800, 500} // x,y, w,h }; if(!swk_use(&w)) return 1; init_alarm(); swk_fontsize_increase(); + swk_fontsize_increase(); + swk_fontsize_increase(); + swk_fontsize_increase(); swk_loop(); return 0; } diff --git a/t/ui.c b/t/ui.c @@ -24,7 +24,7 @@ SwkBox *b = swk_ui_get(w, "ok"); void swk_ui_free(SwkWindow *w) { // leaks in box->text ? - free(w->boxes); + free(w->boxes[1]); free(w->title); free(w); } @@ -56,7 +56,8 @@ swk_ui(const char *text) { } printf("WINDETS=%d\n", sz); - w->box = w->boxes = (SwkBox*)malloc(128*sizeof(SwkBox)); // Use sz after counting + w->box = w->boxes[0] = (SwkBox*)malloc(128*sizeof(SwkBox)); // Use sz after counting + w->boxes[1] = NULL; memset(w->box, 0, 128*sizeof(SwkBox)); while(text && *text) { @@ -65,8 +66,8 @@ swk_ui(const char *text) { if ((*text=='\''&&str[stri-1]!='\\') || *text=='\n') { printf("label(%s)\n", str); stri = mode = 0; - w->boxes[count].cb = swk_label; - w->boxes[count].text = strdup (str); + w->boxes[w->col][count].cb = swk_label; + w->boxes[w->col][count].text = strdup (str); count++; } else { str[stri++] = *text; @@ -77,8 +78,8 @@ swk_ui(const char *text) { if ((*text=='>'&&str[stri-1]!='\\') || *text=='\n') { printf("image(%s)\n", str); stri = mode = 0; - w->boxes[count].cb = swk_image; - w->boxes[count].text = strdup (str); + w->boxes[w->col][count].cb = swk_image; + w->boxes[w->col][count].text = strdup (str); count++; } else { str[stri++] = *text; @@ -87,7 +88,7 @@ swk_ui(const char *text) { break; case '*': if (*text=='\n') { - w->boxes[count].cb = swk_filler; + w->boxes[w->col][count].cb = swk_filler; count++; mode = 0; } @@ -95,14 +96,14 @@ swk_ui(const char *text) { case '=': if (*text=='\n') { SwkBox b = SWK_BOX_NEWLINE(-1); - w->boxes[count] = b; + w->boxes[w->col][count] = b; count++; mode = 0; } break; case '-': if (*text=='\n') { - w->boxes[count].cb = swk_separator; + w->boxes[w->col][count].cb = swk_separator; count++; mode = 0; } @@ -111,8 +112,8 @@ swk_ui(const char *text) { if ((*text==')'&&str[stri-1]!='\\') || *text=='\n') { printf("option(%s)\n", str); stri = mode = 0; - w->boxes[count].cb = swk_option; - w->boxes[count].text = strdup (str); + w->boxes[w->col][count].cb = swk_option; + w->boxes[w->col][count].text = strdup (str); count++; } else { str[stri++] = *text; @@ -124,12 +125,12 @@ swk_ui(const char *text) { stri = mode = 0; if (*str=='*') { printf("pass(%s)\n", str); - w->boxes[count].cb = swk_password; - w->boxes[count].text = ""; + w->boxes[w->col][count].cb = swk_password; + w->boxes[w->col][count].text = ""; } else { printf("entry(%s)\n", str); - w->boxes[count].cb = swk_entry; - w->boxes[count].text = strdup (str); + w->boxes[w->col][count].cb = swk_entry; + w->boxes[w->col][count].text = strdup (str); } count++; } else { @@ -141,8 +142,8 @@ swk_ui(const char *text) { if ((*text==']'&&str[stri-1]!='\\') || *text=='\n') { printf("button(%s)\n", str); stri = mode = 0; - w->boxes[count].cb = swk_button; - w->boxes[count].text = strdup (str); + w->boxes[w->col][count].cb = swk_button; + w->boxes[w->col][count].text = strdup (str); count++; } else { str[stri++] = *text; @@ -162,7 +163,7 @@ swk_ui(const char *text) { default: if (*text=='\n') { SwkBox b = SWK_BOX_NEWLINE(1); - w->boxes[count] = b; + w->boxes[w->col][count] = b; count++; } else { mode = *text;