swk

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

gi_sdl.c (8657B)


      1 /* See LICENSE file for copyright and license details. */
      2 #define _BSD_SOURCE // strdup
      3 #include <SDL/SDL.h>
      4 #include <SDL/SDL_image.h>
      5 #include <SDL/SDL_ttf.h>
      6 #include "swk.h"
      7 #define SWK
      8 #include "config.h"
      9 
     10 #define FONTNAME "Inconsolata.otf"
     11 #define FONTFACTOR 2.1 /* XXX */
     12 #define BPP 32
     13 #define SDLFLAGS SDL_DOUBLEBUF|SDL_RESIZABLE
     14 
     15 static int first = 1;
     16 static int fs = FONTSIZE;
     17 static Uint32 pal[ColorLast];
     18 static SDL_Color fontcolor = { TFCOLOR };
     19 static SDL_Color bgcolor = { BGCOLOR };
     20 static SDL_Color tfcolor = { TFCOLOR };
     21 static SDL_Color cccolor = { CCCOLOR };
     22 static SDL_Surface *screen = NULL;
     23 static TTF_Font *font = NULL;
     24 /* FIXME: put ugly statics into void *aux of SwkWindow ? */
     25 static int has_event = 0;
     26 static SDL_Event lastev = { .type=-1 };
     27 
     28 static inline Uint8 *
     29 getscrpoint(SDL_Surface *scr, int x, int y) {
     30 	Uint8 *p = (Uint8 *)scr->pixels + (y*scr->pitch+x*(BPP/8));
     31 	Uint8 *pend = (Uint8 *)scr->pixels + (scr->h*scr->w*(BPP/8));
     32 	if((p<((Uint8 *)scr->pixels)) || (p>=pend))
     33 		return NULL;
     34 	return p;
     35 }
     36 
     37 static void
     38 putpixel(SDL_Surface *scr, int x, int y, Uint32 pixel) { 
     39 	Uint8 *p = getscrpoint(scr, x, y);
     40 	if(!p) return;
     41 #if BPP == 8
     42 	*p = pixel;
     43 #elif BPP == 16
     44 	*(Uint16 *)p = pixel; 
     45 #elif BPP == 24
     46 # if SDL_BYTEORDER == SDL_BIG_ENDIAN
     47 	p[0] = (pixel >> 16) & 0xff;
     48 	p[1] = (pixel >> 8) & 0xff;
     49 	p[2] = pixel & 0xff;
     50 # else
     51 	p[0] = pixel & 0xff;
     52 	p[1] = (pixel >> 8) & 0xff;
     53 	p[2] = (pixel >> 16) & 0xff;
     54 # endif
     55 #elif BPP == 32
     56 	*(Uint32 *)p = pixel;
     57 #endif
     58 }
     59 
     60 int
     61 swk_gi_fontsize(int sz) {
     62 	fs += sz*2;
     63 	font = TTF_OpenFont(FONTNAME, fs); 
     64 	if(font == NULL) {
     65 		fprintf(stderr, "Cannot open font '%s'\n", FONTNAME);
     66 		return 0;
     67 	} else
     68 	if(FONTBOLD)
     69 		TTF_SetFontStyle(font, TTF_STYLE_BOLD);
     70 	return 1;
     71 }
     72 
     73 int
     74 swk_gi_init(SwkWindow *w) {
     75 	if(first) {
     76 		if(SDL_Init(SDL_INIT_VIDEO)) {
     77 			fprintf(stderr, "Cannot initialize SDL\n");
     78 			return 0;
     79 		}
     80 		if(TTF_Init()==-1) {
     81 			fprintf(stderr, "Cannot initialize TTF: %s\n", TTF_GetError());
     82 			return 0;
     83 		}
     84 		first = 0;
     85 	}
     86 	SDL_SetVideoMode(w->r.w, w->r.h, BPP, SDLFLAGS);
     87 	// double init is necesary to get window size
     88 	SDL_SetVideoMode(w->r.w, w->r.h, BPP, SDLFLAGS);
     89 	SDL_WM_SetCaption(w->title, NULL);
     90 	screen = SDL_GetVideoSurface();
     91 	SDL_EnableUNICODE(1);
     92 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
     93 	pal[ColorFG] = SDL_MapRGB(screen->format, FGCOLOR);
     94 	pal[ColorBG] = SDL_MapRGB(screen->format, BGCOLOR);
     95 	pal[ColorHI] = SDL_MapRGB(screen->format, HICOLOR);
     96 	pal[ColorTF] = SDL_MapRGB(screen->format, TFCOLOR);
     97 	pal[ColorCC] = SDL_MapRGB(screen->format, CCCOLOR);
     98 	return swk_gi_fontsize(0);
     99 }
    100 
    101 int
    102 swk_gi_update(SwkWindow *w) {
    103 	screen = SDL_GetVideoSurface();
    104 	if(screen == NULL)
    105 		return 0;
    106 	w->r.w = (screen->w / fs)-1;
    107 	w->r.h = (screen->h / fs)-1;
    108 	return 1;
    109 }
    110 
    111 void
    112 swk_gi_exit() {
    113 	SDL_Quit();
    114 }
    115 
    116 SwkEvent *
    117 swk_gi_event(SwkWindow *w, int dowait) {
    118 	static int mousedowny, mousedownx, mousedown = 0;
    119 	static int mousemoved = 0;
    120 	SDL_Event event;
    121 	SwkEvent *ret = &w->_e;
    122 
    123 	if(has_event) event = lastev;
    124 	else has_event = SDL_WaitEvent(&event);
    125 
    126 	if(has_event);
    127 	switch(event.type) {
    128 	default: ret = NULL; break;
    129 	case SDL_VIDEORESIZE:
    130 		//fprintf(stderr, "resize %d %d\n", event.resize.w, event.resize.h);
    131 		SDL_SetVideoMode(event.resize.w, event.resize.h, BPP, SDLFLAGS);
    132 	case SDL_ACTIVEEVENT:
    133 	case SDL_VIDEOEXPOSE:
    134 		ret->type = EExpose;
    135 		ret->data.expose.x = ret->data.expose.y = \
    136 		ret->data.expose.w = ret->data.expose.h = 0;
    137 		break;
    138 	case SDL_MOUSEMOTION:
    139 		// TODO: move this stuff into swk.c.. shoudlnt be backend dependent
    140 		//fprintf(stderr, "event: motion (%d,%d)\n", event.motion.x,event.motion.y);
    141 		if(mousedown) {
    142 			// touchscreen spaguetti trick
    143 			if(mousedowny==-1) mousedowny = event.motion.y; else mousemoved = 1;
    144 			if(mousedownx==-1) mousedownx = event.motion.x; else mousemoved = 1;
    145 			if(event.motion.y>mousedowny+fs) {
    146 				mousedowny = event.motion.y;
    147 				swk_scroll_up(w);
    148 			} else
    149 			if(event.motion.y<mousedowny-fs) {
    150 				mousedowny = event.motion.y;
    151 				swk_scroll_down(w);
    152 			}
    153 			if(event.motion.x>mousedownx+fs) {
    154 				mousedownx = event.motion.x;
    155 				swk_column_move_right();
    156 				swk_column_move_right();
    157 			} else
    158 			if(event.motion.x<mousedownx-fs) {
    159 				mousedownx = event.motion.x;
    160 				swk_column_move_left();
    161 				swk_column_move_left();
    162 			}
    163 			ret->type = EExpose;
    164 			ret->data.expose.x = ret->data.expose.y = \
    165 			ret->data.expose.w = ret->data.expose.h = 0;
    166 		} else {
    167 			ret->type = EMotion;
    168 			ret->data.motion.x = event.motion.x / fs;
    169 			ret->data.motion.y = event.motion.y / fs;
    170 		}
    171 		break;
    172 	case SDL_MOUSEBUTTONUP:
    173 		//fprintf(stderr, "event: up %d (%d,%d)\n", event.button.button,event.button.x,event.button.y);
    174 		mousedown = 0;
    175 		if(!mousemoved) {
    176 			ret->type = EClick;
    177 			ret->data.click.button = event.button.button;
    178 			ret->data.click.point.x = event.button.x / fs;
    179 			ret->data.click.point.y = event.button.y / fs;
    180 		}
    181 		break;
    182 	case SDL_MOUSEBUTTONDOWN:
    183 		//fprintf(stderr, "event: down %d (%d,%d)\n", event.button.button,event.button.x,event.button.y);
    184 		mousemoved = 0;
    185 		mousedown = 1;
    186 		mousedowny = TOUCHSCREEN?-1:event.button.y;
    187 		break;
    188 	case SDL_KEYDOWN:
    189 		ret->type = EKey;
    190 		ret->data.key.modmask = 0;
    191 		if(event.key.keysym.mod & KMOD_CTRL)
    192 			ret->data.key.modmask |= Ctrl;
    193 		if(event.key.keysym.mod & KMOD_SHIFT)
    194 			ret->data.key.modmask |= Shift;
    195 		if(event.key.keysym.mod & KMOD_ALT)
    196 			ret->data.key.modmask |= Alt;
    197 		if(event.key.keysym.mod & KMOD_META)
    198 			ret->data.key.modmask |= Meta;
    199 		if(ret->data.key.keycode != 0 && event.key.keysym.unicode != 0) {
    200 			ret->data.key.keycode = event.key.keysym.unicode;
    201 		}
    202 		switch((int)event.key.keysym.sym) {
    203 		case 13:
    204 			ret->data.key.keycode = '\n';
    205 			break;
    206 		case 275:
    207 			ret->data.key.keycode = KRight;
    208 			break;
    209 		case 276:
    210 			ret->data.key.keycode = KLeft;
    211 			break;
    212 		case 1073741906: // n900 up key
    213 		case 273:
    214 			ret->data.key.keycode = KUp;
    215 			break;
    216 		case 1073741912: // n900 down key
    217 		case 274:
    218 			ret->data.key.keycode = KDown;
    219 			break;
    220 		default:
    221 			ret->data.key.keycode = event.key.keysym.sym;
    222 			break;
    223 		}
    224 		fprintf(stderr, "event: key %d %d\n", 
    225 			ret->data.key.modmask, ret->data.key.keycode);
    226 		break;
    227 	case SDL_QUIT:
    228 		ret->type = EQuit;
    229 		break;
    230 	}
    231 	has_event = 0;
    232 	return ret;
    233 }
    234 
    235 void
    236 swk_gi_clear() {
    237 	SDL_Rect rect = { 0, 0, screen->w, screen->h };
    238 	SDL_FillRect(screen, &rect, pal[ColorBG]);
    239 }
    240 
    241 void
    242 swk_gi_flip() {
    243 	SDL_LockSurface(screen);
    244 	SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); 
    245 	SDL_UnlockSurface(screen);
    246 }
    247 
    248 /* -- drawing primitives -- */
    249 void
    250 swk_gi_line(int x1, int y1, int x2, int y2, int color) {
    251 	Rect r = { x1, y1, x2, y2 };
    252 	if(!x2 || !y2)
    253 		swk_gi_fill(r, color, 0);
    254 	// TODO: add support for diagonal lines?
    255 }
    256 
    257 void
    258 swk_gi_fill(Rect r, int color, int lil) {
    259 	SDL_Rect area = { r.x*fs, r.y*fs, r.w*fs, r.h*fs };
    260 	if(lil==1) {
    261 		const int s = fs/4;
    262 		area.x += s;
    263 		area.y += s;
    264 		area.w -= (s*2);
    265 		area.h -= (s*2);
    266 	} else if (lil==2) {
    267 		area.x/=4;
    268 		area.y+=4;
    269 		area.w/=4;
    270 		area.h-=4;
    271 	} else if (lil==3) {
    272 		const int s = fs/4;
    273 		area.w -= (s*2);
    274 		area.h -= (s*4);
    275 	}
    276 	if(!area.w) area.w = 1;
    277 	if(!area.h) area.h = 1;
    278 	SDL_FillRect(screen, &area, pal[color]);
    279 }
    280 
    281 void
    282 swk_gi_rect(Rect r, int color) {
    283 	swk_gi_line(r.x, r.y, r.w, 0, color);
    284 	swk_gi_line(r.x, r.y+r.h, r.w, 0, color);
    285 	swk_gi_line(r.x, r.y, 0, r.h, color);
    286 	swk_gi_line(r.x+r.w, r.y, 0, r.h, color);
    287 }
    288 
    289 void
    290 swk_gi_text(Rect r, const char *text) {
    291 	const char *tptr = text;
    292 	char *ptr = NULL;
    293 	int w = (int)((double)r.w * FONTFACTOR);
    294 	if(text && *text) {
    295 		int len = text?strlen(text):0;
    296 		if(len>w) {
    297 			tptr = ptr = strdup(text);
    298 			ptr[w]='\0';
    299 		}
    300 		SDL_Surface *ts = TTF_RenderText_Shaded(font, tptr, fontcolor, bgcolor);
    301 		if(ts) {
    302 			SDL_Rect from = { 0, 4, ts->w, ts->h-2 };
    303 			SDL_Rect to = { (r.x)*fs, 2+r.y*fs, ts->w, ts->h-4 };
    304 			SDL_BlitSurface(ts, &from, screen, &to);
    305 			SDL_FreeSurface(ts);
    306 		} else fprintf(stderr, "Cannot render string (%s)\n", text);
    307 	}
    308 	free(ptr);
    309 }
    310 
    311 void
    312 swk_gi_img(Rect r, void *img) {
    313 	if(img) {
    314 		SDL_Rect area = { r.x*fs, r.y*fs, r.w*fs, r.h*fs };
    315 		area.x++; area.y++;
    316 		SDL_BlitSurface((SDL_Surface*)img, NULL, screen, &area);
    317 	}
    318 }
    319 
    320 /* image api */
    321 void*
    322 swk_gi_img_new(int w, int h, int color) {
    323 	return (void *)SDL_CreateRGBSurface(0, (w*fs)-2, (h*fs)-2, BPP, 0, 0, 0, 0);
    324 }
    325 
    326 void*
    327 swk_gi_img_load(const char *str) {
    328 	return IMG_Load(str);
    329 }
    330 
    331 void
    332 swk_gi_img_free(void *s) {
    333 	SDL_FreeSurface(s);
    334 }
    335 
    336 void
    337 swk_gi_img_set(void *img, int x, int y, int color) {
    338 	if(img) putpixel((SDL_Surface*)img, x, y, pal[color]);
    339 }
    340 
    341 int
    342 swk_gi_img_get(void *img, int x, int y) {
    343 	Uint8 *p = getscrpoint(img, x, y);
    344 	return p?*p:0;
    345 }