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 }