swk

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

text.c (5513B)


      1 /* See LICENSE file for copyright and license details. */
      2 #define _BSD_SOURCE
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <stdlib.h>
      6 #include <swk.h>
      7 
      8 int
      9 text_rowcount(Text *t) {
     10 	int rows = 1;
     11 	char *p;
     12 	for(p=t->text;*p;p++)
     13 		if(*p=='\n')
     14 			rows++;
     15 	return rows;
     16 }
     17 
     18 int
     19 text_rowoff(Text *t, int row) {
     20 	char *p;
     21 	int off = 0;
     22 	if(row<1)
     23 		return 0;
     24 	for(p=t->text;row&&*p;p++) {
     25 		if(*p=='\n')
     26 			row--;
     27 		off++;
     28 	}
     29 	return off;
     30 }
     31 
     32 int
     33 text_rowcol(Text *t, int off, int *col) {
     34 	char *p,*nl = NULL;
     35 	char *e = t->text+off;
     36 	int r = 0;
     37 	int c = 0;
     38 	for(p=t->text;*p&&p<=e;p++) {
     39 		if(*p=='\n') {
     40 			r++;
     41 			c = 0;
     42 			nl = p+1;
     43 		} else c++;
     44 	}
     45 	if(col) *col = c;
     46 	return r;
     47 }
     48 int
     49 text_off(Text *t, int col, int row) {
     50 	int off = text_rowoff(t, row);
     51 	int len = strlen (t->text);
     52 	if (col>len)
     53 		col = len;
     54 	return off+(t->text[off])?col:0;
     55 }
     56 
     57 char *
     58 text_sub(Text *t, int col, int row, int rows) {
     59 	// find row number N in text
     60 	// +=col if < \n
     61 	// count N rows and \0
     62 	return NULL;
     63 }
     64 
     65 void
     66 text_init(Text *t, const char *str) {
     67 	if(!t->text) {
     68 		t->len = strlen (t->otext);
     69 		t->size = (t->len+1)*2;
     70 		t->text = malloc (t->size);
     71 		if (str) strcpy(t->text, t->otext);
     72 		else strcpy(t->text, t->otext);
     73 	}
     74 }
     75 
     76 void
     77 text_set(Text *t, const char *text) {
     78 	int len = strlen (text);
     79 	if(t->text) {
     80 		if(len>t->size) {
     81 			t->size = (len+10)*2;
     82 			t->text = realloc(t->text, t->size);
     83 		}
     84 		strcpy(t->text, text);
     85 	} else text_init(t, text);
     86 	text_sync(t);
     87 }
     88 
     89 char *
     90 text_get(Text *t, int from, int to) {
     91 	/* get buffer between from and to offsets */
     92 	char *p;
     93 	if(to!=-1&&(to<from || from>t->len))
     94 		return strdup ("");
     95 	if(to>t->len||to==-1)
     96 		to = t->len;
     97 	if (!t->text)
     98 		t->text = strdup((t->otext)?t->otext:"");
     99 	p = strdup (t->text+from);
    100 	//if(to!=-1) p[to-from] = '\0';
    101 	return p;
    102 }
    103 
    104 void
    105 text_sync(Text *t) {
    106 	// count cols, rows, fix xcur, ycur from cur, etc..
    107 	t->len = strlen(t->text);
    108 	t->ycur = text_rowcol(t, t->cur, &t->xcur);
    109 }
    110 
    111 void
    112 text_cur(Text *t, int num, int dir) {
    113 	if(dir) t->cur += (num*dir);
    114 	else t->cur = num;
    115 	if(t->cur<0)
    116 		t->cur = 0;
    117 	if(t->cur>t->len)
    118 		t->cur = t->len;
    119 	if(dir<0 && t->text[t->cur]=='\n')
    120 		t->cur+=dir;
    121 }
    122 
    123 void
    124 text_resize(Text *t, int newsize) {
    125 	if (newsize>t->size) {
    126 		t->text = realloc(t->text, newsize);
    127 		t->size = newsize;
    128 	}
    129 }
    130 
    131 void
    132 text_insc(Text *t, char ch, int app) {
    133 	char str[2] = {ch};
    134 	text_ins(t, str, app);
    135 }
    136 
    137 void
    138 text_ins(Text *t, const char *str, int app) {
    139 	int len = strlen(str);
    140 	text_resize(t, (2*len)+t->size);
    141 	if(app) {
    142 		char *tmp = strdup(t->text+t->cur);
    143 		strcpy(t->text+t->cur, str);
    144 		strcat(t->text+t->cur+len, tmp);
    145 		free(tmp);
    146 	} else memcpy(t->text+t->cur, str, len);
    147 	t->cur += len;
    148 }
    149 
    150 void
    151 text_del(Text *t, int num, int dir) {
    152 	switch(dir) {
    153 	case -1:
    154 		if(t->cur-num<0)
    155 			num = 0;
    156 		strcpy(t->text+t->cur-num, t->text+t->cur);
    157 		t->cur -= num;
    158 		break;
    159 	case 0:
    160 		t->text[num] = 0;
    161 		t->len = strlen (t->text);
    162 		if (t->cur>t->len)
    163 			t->cur = t->len;
    164 		break;
    165 	case 1:
    166 		if (t->cur+num>=t->len)
    167 			num = t->len-t->cur;
    168 		strcpy(t->text+t->cur, t->text+t->cur+num);
    169 		break;
    170 	}
    171 	text_sync(t);
    172 }
    173 
    174 void
    175 text_sel(Text *t, int begin, int end) { // if off != off2 text is selected
    176 	t->sel[0] = begin;
    177 	t->sel[1] = end;
    178 }
    179 
    180 void
    181 text_sel_mode(Text *t, int enable) {
    182 	t->selmode = enable;
    183 }
    184 
    185 /* swk widget */
    186 void
    187 swk_text(SwkEvent *e) {
    188 	Text *t = (Text*)e->box->data;
    189 	int row, key;
    190 
    191 	text_init(e->box->data, e->box->text);
    192 	text_sync(e->box->data);
    193 	switch(e->type) {
    194 	case EClick:
    195 		// TODO: text_sel//
    196 		switch(e->data.click.button) {
    197 		case 1:
    198 			//text_sel_mode(1)
    199 			break;
    200 		case 2:
    201 			// activate link (TODO: implement hyperlinks)
    202 			break;
    203 		case 3:
    204 			//text_sel_mode(0)
    205 			break;
    206 		}
    207 		break;
    208 	case EKey:
    209 		key = e->data.key.keycode;
    210 		if(e->data.key.modmask&Ctrl)
    211 			return;
    212 		if(key == KDel)
    213 			text_del(e->box->data, 1, -1);
    214 		else if(key == KSupr)
    215 			text_del(e->box->data, 1, 1);
    216 		else if(key=='\n'||(key>=' '&&key<='~'))
    217 			text_insc(e->box->data, key, 1);
    218 		else if(key==KUp)
    219 			text_cur(e->box->data, 10, -1); //XXX
    220 		else if(key==KDown)
    221 			text_cur(e->box->data, 10, 1); //XXX
    222 		else if(key==KLeft)
    223 			text_cur(e->box->data, 1, -1);
    224 		else if(key==KRight)
    225 			text_cur(e->box->data, 1, 1);
    226 		break;
    227 	case EExpose:
    228 		swk_gi_fill(e->box->r, ColorBG, 0);
    229 		row = t->ycur-2;
    230 		/* text */{
    231 		int len, rows = 0;
    232 		int y = e->box->r.y--;
    233 		char *p, *p0, *str;
    234 		str = text_get (e->box->data, text_rowoff(e->box->data,row), -1);
    235 		if(row<0) row = 0;
    236 		//printf("str(%s)\n", str);
    237 		for(p=p0=str;*p;p++) {
    238 			if(*p=='\n') {
    239 				if(++rows>e->box->r.h)
    240 					break;
    241 				*p = 0;
    242 				e->box->text = p0;
    243 				e->box->r.y++;
    244 				len = strlen(p0);
    245 				if(len>=e->box->r.w*3)
    246 					p0[(e->box->r.w*3)-1]=0;
    247 				swk_gi_text(e->box->r, p0);
    248 				p0 = p+1;
    249 			}
    250 		}
    251 		if((rows<=e->box->r.h-1)&&p0&&*p0) {
    252 			e->box->r.y++;
    253 			swk_gi_text(e->box->r, p0);
    254 		}
    255 		e->box->r.y = y;
    256 		free(str);
    257 		}
    258 		/* cursor */ {
    259 			int len, cut = e->box->r.w*2;
    260 			int row = ((Text*)e->box->data)->ycur;
    261 			int col = ((Text*)e->box->data)->xcur;
    262 		if(row>=e->box->r.h-1) row = e->box->r.h-2;
    263 #if 1
    264 			#ifdef USE_SDL
    265 			len = 4*e->box->r.x;
    266 			#else
    267 			len = 3*e->box->r.x;
    268 			#endif
    269 			if(col>cut)
    270 				len += cut;
    271 			#ifdef USE_SDL
    272 			else len += 2*col+1;
    273 			#else
    274 			else len += col+1;
    275 			#endif
    276 #endif
    277 			//Text* t = e->box->data;
    278 			text_sync(e->box->data);
    279 
    280 			Rect r = { (e->box->r.x*3)+col, e->box->r.y+row, 1, 1};
    281 			swk_gi_fill(r, ColorHI, 2);
    282 		}
    283 		swk_gi_rect(e->box->r, ColorFG);
    284 		break;
    285 	default:
    286 		swk_label(e);
    287 		break;
    288 	}
    289 }