1 #include <u.h> 2 #include <libc.h> 3 #include <libg.h> 4 #include <bio.h> 5 6 /* 7 * This program keeps the system's and the application's bitmap and 8 * subfont structures consistent, but that is really not necessary; 9 * in fact it isn't even necessary to hold the subfonts in the system 10 * at all. Doing it this way makes it easy to do I/O on subfonts. 11 * Even so, edits to individual character's Fontchars are not passed 12 * to the system. 13 */ 14 15 typedef struct Thing Thing; 16 17 struct Thing 18 { 19 Bitmap *b; 20 Subfont *s; 21 char *name; /* file name */ 22 int face; /* is 48x48 face file or cursor file*/ 23 Rectangle r; /* drawing region */ 24 Rectangle tr; /* text region */ 25 Rectangle er; /* entire region */ 26 long c; /* character number in subfont */ 27 int mod; /* modified */ 28 int mag; /* magnification */ 29 Rune off; /* offset for subfont indices */ 30 Thing *parent; /* thing of which i'm an edit */ 31 Thing *next; 32 }; 33 34 enum 35 { 36 Border = 1, 37 Up = 1, 38 Down = 0, 39 Mag = 4, 40 Maxmag = 10, 41 }; 42 43 enum 44 { 45 Mopen, 46 Mread, 47 Mwrite, 48 Mcopy, 49 Mchar, 50 Mclose, 51 Mexit, 52 }; 53 54 55 char *menu3str[] = { 56 [Mopen] "open", 57 [Mread] "read", 58 [Mwrite] "write", 59 [Mcopy] "copy", 60 [Mchar] "char", 61 [Mclose] "close", 62 [Mexit] "exit", 63 0, 64 }; 65 66 Menu menu3 = { 67 menu3str 68 }; 69 70 Cursor sweep0 = { 71 {-7, -7}, 72 {0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 73 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 74 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0, 75 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0}, 76 {0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 77 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x7F, 0xFE, 78 0x7F, 0xFE, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 79 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00} 80 }; 81 82 Cursor box = { 83 {-7, -7}, 84 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 85 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 86 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, 87 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 88 {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 89 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 90 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 91 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00} 92 }; 93 94 Cursor sight = { 95 {-7, -7}, 96 {0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF, 97 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 98 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF, 99 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,}, 100 {0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84, 101 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE, 102 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 103 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,} 104 }; 105 106 Cursor busy = { 107 {-7, -7}, 108 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 109 0x00, 0x00, 0x00, 0x0c, 0x00, 0x8e, 0x1d, 0xc7, 110 0xff, 0xe3, 0xff, 0xf3, 0xff, 0xff, 0x7f, 0xfe, 111 0x3f, 0xf8, 0x17, 0xf0, 0x03, 0xe0, 0x00, 0x00,}, 112 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 113 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x82, 114 0x04, 0x41, 0xff, 0xe1, 0x5f, 0xf1, 0x3f, 0xfe, 115 0x17, 0xf0, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00,} 116 }; 117 118 Cursor skull = { 119 {-7,-7}, 120 {0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xe7, 0xe7, 121 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfc, 0x1f, 0xf8, 122 0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff, 123 0xef, 0xf7, 0xc7, 0xe3, 0x00, 0x00, 0x00, 0x00,}, 124 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 125 0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0, 126 0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27, 127 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} 128 }; 129 130 char *fns[] = { 131 "0", "Zero", 0, 132 "~(S|D)", "~(D|S)", "DnorS", 0, 133 "~S&D", "D&~S", "DandnotS", 0, 134 "~S", "notS", 0, 135 "S&~D", "~D&S", "notDandS", 0, 136 "~D", "notD", 0, 137 "S^D", "D^S", "DxorS", 0, 138 "~(S&D)", "~(D&S)", "DnandS", 0, 139 "S&D", "D&S", "DandS", 0, 140 "~(S^D)", "~(D^S)", "DxnorS", 0, 141 "D", 0, 142 "~S|D", "D|~S", "DornotS", 0, 143 "S", 0, 144 "S|~D", "~D|S", "notDorS", 0, 145 "S|D", "D|S", "DorS", 0, 146 "F", 0, 147 0 148 }; 149 150 Rectangle cntlr; /* control region */ 151 Rectangle editr; /* editing region */ 152 Rectangle textr; /* text region */ 153 Thing *thing; 154 Mouse mouse; 155 char hex[] = "0123456789abcdefABCDEF"; 156 jmp_buf err; 157 char *file; 158 int mag; 159 uint copyfn = S; 160 uint but1fn = S; 161 uint but2fn = 0; 162 Bitmap *values; 163 ulong val = ~0; 164 uchar data[8192]; 165 166 Thing* tget(char*); 167 void mesg(char*, ...); 168 void draw(Thing*, int); 169 void select(void); 170 void menu(void); 171 void error(char*); 172 void buttons(int); 173 char *fntostr(uint); 174 int strtofn(char*); 175 void drawall(void); 176 void tclose1(Thing*); 177 178 void 179 main(int argc, char *argv[]) 180 { 181 int i, j; 182 Event e; 183 Thing *t; 184 185 mag = Mag; 186 binit(error, 0, "tweak"); 187 values = balloc(Rect(0, 0, 256*Maxmag, Maxmag), screen.ldepth); 188 if(values == 0) 189 berror("can't balloc"); 190 for(i=0; i<256; i++) 191 for(j=0; j<Maxmag; j++) 192 segment(values, Pt(i*Maxmag, j), Pt((i+1)*Maxmag, j), i, S); 193 einit(Emouse|Ekeyboard); 194 ereshaped(screen.r); 195 i = 1; 196 setjmp(err); 197 for(; i<argc; i++){ 198 file = argv[i]; 199 t = tget(argv[i]); 200 if(t) 201 draw(t, 1); 202 bflush(); 203 } 204 file = 0; 205 setjmp(err); 206 for(;;) 207 switch(event(&e)){ 208 case Ekeyboard: 209 break; 210 case Emouse: 211 mouse = e.mouse; 212 if(mouse.buttons & 3){ 213 select(); 214 break; 215 } 216 if(mouse.buttons & 4) 217 menu(); 218 } 219 } 220 221 void 222 error(char *s) 223 { 224 if(file) 225 mesg("can't read %s: %s: %r", file, s); 226 else 227 mesg("/dev/bitblt error: %s", s); 228 if(err[0]) 229 longjmp(err, 1); 230 exits(s); 231 } 232 233 void 234 redraw(Thing *t) 235 { 236 Thing *nt; 237 Point p; 238 239 if(thing==0 || thing==t) 240 bitblt(&screen, editr.min, &screen, editr, 0); 241 if(thing == 0) 242 return; 243 if(thing != t){ 244 for(nt=thing; nt->next!=t; nt=nt->next) 245 ; 246 bitblt(&screen, Pt(screen.r.min.x, nt->er.max.y), &screen, 247 Rect(screen.r.min.x, nt->er.max.y, editr.max.x, editr.max.y), 0); 248 } 249 for(nt=t; nt; nt=nt->next){ 250 draw(nt, 0); 251 if(nt->next == 0){ 252 p = Pt(editr.min.x, nt->er.max.y); 253 bitblt(&screen, p, &screen, Rpt(p, editr.max), 0); 254 } 255 } 256 mesg(""); 257 } 258 259 void 260 ereshaped(Rectangle r) 261 { 262 USED(r); 263 264 screen.r = bscreenrect(&screen.clipr); 265 cntlr = inset(screen.clipr, 1); 266 editr = cntlr; 267 textr = editr; 268 textr.min.y = textr.max.y - font->height; 269 cntlr.max.y = cntlr.min.y + font->height; 270 editr.min.y = cntlr.max.y+1; 271 editr.max.y = textr.min.y-1; 272 bitblt(&screen, screen.clipr.min, &screen, screen.clipr, 0); 273 segment(&screen, Pt(editr.min.x, editr.max.y), 274 Pt(editr.max.x+1, editr.max.y), ~0, F); 275 clipr(&screen, editr); 276 drawall(); 277 } 278 279 void 280 mesgstr(Point p, int line, char *s) 281 { 282 Rectangle c, r; 283 284 r.min = p; 285 r.min.y += line*font->height; 286 r.max.y = r.min.y+font->height; 287 r.max.x = editr.max.x; 288 c = screen.clipr; 289 clipr(&screen, r); 290 bitblt(&screen, r.min, &screen, r, 0); 291 r.min.x++; 292 p = string(&screen, r.min, font, s, S); 293 r.max.x = p.x + 1; 294 r.min.x--; 295 bitblt(&screen, r.min, &screen, r, ~D); 296 clipr(&screen, c); 297 bflush(); 298 } 299 300 void 301 mesg(char *fmt, ...) 302 { 303 char buf[1024]; 304 305 doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)); 306 mesgstr(textr.min, 0, buf); 307 } 308 309 void 310 tmesg(Thing *t, int line, char *fmt, ...) 311 { 312 char buf[1024]; 313 314 doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)); 315 mesgstr(t->tr.min, line, buf); 316 } 317 318 319 void 320 scntl(char *l) 321 { 322 char vals[16]; 323 324 if(val & 0x80000000) 325 sprint(vals, "~%lux", ~val); 326 else 327 sprint(vals, "%lux", val); 328 sprint(l, "mag: %d val(hex): %s but1: %s but2: %s copy: %s", 329 mag, vals, fntostr(but1fn), fntostr(but2fn), fntostr(copyfn)); 330 } 331 332 void 333 cntl(void) 334 { 335 char buf[256]; 336 337 scntl(buf); 338 mesgstr(cntlr.min, 0, buf); 339 } 340 341 void 342 stext(Thing *t, char *l0, char *l1) 343 { 344 Fontchar *fc; 345 char buf[256]; 346 347 l1[0] = 0; 348 sprint(buf, "ldepth:%d r:%d %d %d %d ", 349 t->b->ldepth, t->b->r.min.x, t->b->r.min.y, 350 t->b->r.max.x, t->b->r.max.y); 351 if(t->parent) 352 sprint(buf+strlen(buf), "mag: %d ", t->mag); 353 sprint(l0, "%s file: %s", buf, t->name); 354 if(t->c >= 0){ 355 fc = &t->parent->s->info[t->c]; 356 sprint(l1, "c(hex): %x c(char): %C x: %d " 357 "top: %d bottom: %d left: %d width: %d iwidth: %d", 358 t->c+t->parent->off, t->c+t->parent->off, 359 fc->x, fc->top, fc->bottom, fc->left, 360 fc->width, Dx(t->b->r)); 361 }else if(t->s) 362 sprint(l1, "offset(hex): %ux n:%d height:%d ascent:%d", 363 t->off, t->s->n, t->s->height, t->s->ascent); 364 } 365 366 void 367 text(Thing *t) 368 { 369 char l0[256], l1[256]; 370 371 stext(t, l0, l1); 372 tmesg(t, 0, l0); 373 if(l1[0]) 374 tmesg(t, 1, l1); 375 } 376 377 void 378 drawall(void) 379 { 380 Thing *t; 381 382 cntl(); 383 for(t=thing; t; t=t->next) 384 draw(t, 0); 385 } 386 387 int 388 value(Bitmap *b, int x) 389 { 390 int v, l, w; 391 uchar mask; 392 393 l = b->ldepth; 394 if(l > 3){ 395 mesg("ldepth too large"); 396 return 0; 397 } 398 w = 1<<l; 399 mask = (2<<w)-1; /* ones at right end of word */ 400 x -= b->r.min.x&~(7>>l); /* adjust x relative to first pixel */ 401 v = data[x>>(3-l)]; 402 v >>= ((7>>l)<<l) - ((x&(7>>l))<<l); /* pixel at right end of word */ 403 v &= mask; /* pixel at right end of word */ 404 return v; 405 } 406 407 int 408 bvalue(int v, int l) 409 { 410 v &= (1<<(1<<l))-1; 411 if(l > screen.ldepth) 412 v >>= (1<<l) - (1<<screen.ldepth); 413 else 414 while(l < screen.ldepth){ 415 v |= v << (1<<l); 416 l++; 417 } 418 return v*Maxmag; 419 } 420 421 void 422 draw(Thing *nt, int link) 423 { 424 int nl, nf, i, x, y, sx, sy, fdx, dx, dy, v; 425 Thing *t; 426 Subfont *s; 427 Bitmap *b; 428 Point p, p1, p2; 429 430 if(link){ 431 nt->next = 0; 432 if(thing == 0){ 433 thing = nt; 434 y = editr.min.y; 435 }else{ 436 for(t=thing; t->next; t=t->next) 437 ; 438 t->next = nt; 439 y = t->er.max.y; 440 } 441 }else{ 442 if(thing == nt) 443 y = editr.min.y; 444 else{ 445 for(t=thing; t->next!=nt; t=t->next) 446 ; 447 y = t->er.max.y; 448 } 449 } 450 s = nt->s; 451 b = nt->b; 452 nl = font->height; 453 if(s || nt->c>=0) 454 nl += font->height; 455 fdx = Dx(editr) - 2*Border; 456 dx = Dx(b->r); 457 dy = Dy(b->r); 458 if(nt->mag > 1){ 459 dx *= nt->mag; 460 dy *= nt->mag; 461 fdx -= fdx%nt->mag; 462 } 463 nf = 1 + dx/fdx; 464 nt->er.min.y = y; 465 nt->er.min.x = editr.min.x; 466 nt->er.max.x = nt->er.min.x + Border + dx + Border; 467 if(nt->er.max.x > editr.max.x) 468 nt->er.max.x = editr.max.x; 469 nt->er.max.y = nt->er.min.y + Border + nf*(dy+Border); 470 nt->r = inset(nt->er, Border); 471 nt->er.max.x = editr.max.x; 472 bitblt(&screen, nt->er.min, &screen, nt->er, 0); 473 for(i=0; i<nf; i++){ 474 p1 = Pt(nt->r.min.x-1, nt->r.min.y+i*(Border+dy)); 475 /* draw portion of bitmap */ 476 p = Pt(p1.x+1, p1.y); 477 if(nt->mag == 1) 478 bitblt(&screen, p, b, 479 Rect(b->r.min.x+i*fdx, b->r.min.y, 480 b->r.max.x+(i+1)*fdx, b->r.max.y), S); 481 else{ 482 for(y=b->r.min.y; y<b->r.max.y; y++){ 483 sy = p.y+(y-b->r.min.y)*nt->mag; 484 rdbitmap(b, y, y+1, data); 485 for(x=b->r.min.x+i*(fdx/nt->mag); x<b->r.max.x; x++){ 486 sx = p.x+(x-i*(fdx/nt->mag)-b->r.min.x)*nt->mag; 487 if(sx >= nt->r.max.x) 488 break; 489 v = bvalue(value(b, x), b->ldepth); 490 if(v) 491 bitblt(&screen, Pt(sx, sy), 492 values, 493 Rect(v, 0, v+nt->mag, nt->mag), S); 494 } 495 496 } 497 } 498 /* line down left */ 499 segment(&screen, p1, Pt(p1.x, p1.y+dy+Border+1), i==0? ~0 : 0, S); 500 /* line across top */ 501 segment(&screen, Pt(p1.x, p1.y-1), Pt(nt->r.max.x+Border, p1.y-1), ~0, F); 502 p2 = p1; 503 if(i == nf-1) 504 p2.x += 1 + dx%fdx; 505 else 506 p2.x = nt->r.max.x; 507 /* line down right */ 508 segment(&screen, p2, Pt(p2.x, p2.y+dy+1), i==nf-1? ~0 : 0, S); 509 /* line across bottom */ 510 if(i == nf-1){ 511 p1.y += Border+dy; 512 segment(&screen, Pt(p1.x, p1.y-1), Pt(p2.x, p1.y-1), ~0, F); 513 } 514 } 515 nt->tr.min.x = editr.min.x; 516 nt->tr.max.x = editr.max.x; 517 nt->tr.min.y = nt->er.max.y + Border; 518 nt->tr.max.y = nt->tr.min.y + nl; 519 nt->er.max.y = nt->tr.max.y + Border; 520 text(nt); 521 } 522 523 int 524 tohex(int c) 525 { 526 if('0'<=c && c<='9') 527 return c - '0'; 528 if('a'<=c && c<='f') 529 return 10 + (c - 'a'); 530 if('A'<=c && c<='F') 531 return 10 + (c - 'A'); 532 } 533 534 Thing* 535 tget(char *file) 536 { 537 int i, j, fd, face, x, y, c, ld; 538 Bitmap *b, *tb; 539 Subfont *s; 540 Thing *t; 541 Dir d; 542 jmp_buf oerr; 543 uchar buf[256]; 544 char *data; 545 546 errstr((char*)buf); /* flush pending error message */ 547 memmove(oerr, err, sizeof err); 548 if(setjmp(err)){ 549 Err: 550 memmove(err, oerr, sizeof err); 551 return 0; 552 } 553 fd = open(file, OREAD); 554 if(fd < 0){ 555 mesg("can't open %s: %r", file); 556 goto Err; 557 } 558 if(dirfstat(fd, &d) < 0){ 559 mesg("can't stat bitmap file %s: %r", file); 560 close(fd); 561 goto Err; 562 } 563 if(read(fd, buf, 2) != 2){ 564 mesg("can't read %s: %r", file); 565 close(fd); 566 goto Err; 567 } 568 seek(fd, 0, 0); 569 if(buf[0]=='0' && buf[1]=='x'){ 570 /* 571 * face file 572 */ 573 face = 1; 574 s = 0; 575 data = malloc(d.length+1); 576 if(data == 0){ 577 mesg("can't malloc buffer: %r"); 578 close(fd); 579 goto Err; 580 } 581 data[d.length] = 0; 582 if(read(fd, data, d.length) != d.length){ 583 mesg("can't read bitmap file %s: %r", file); 584 close(fd); 585 goto Err; 586 } 587 for(y=0,i=0; i<d.length; i++) 588 if(data[i] == '\n') 589 y++; 590 if(y == 0){ 591 ill: 592 mesg("ill-formed face file %s", file); 593 close(fd); 594 free(data); 595 goto Err; 596 } 597 for(x=0,i=0; (c=data[i])!='\n'; ){ 598 if(c==',' || c==' ' || c=='\t'){ 599 i++; 600 continue; 601 } 602 if(c=='0' && data[i+1] == 'x'){ 603 i += 2; 604 continue; 605 } 606 if(strchr(hex, c)){ 607 x += 4; 608 i++; 609 continue; 610 } 611 goto ill; 612 } 613 if(x % y) 614 goto ill; 615 switch(x / y){ 616 default: 617 goto ill; 618 case 1: 619 ld = 0; 620 break; 621 case 2: 622 ld = 1; 623 break; 624 case 4: 625 ld = 2; 626 break; 627 case 8: 628 ld = 3; 629 break; 630 } 631 b = balloc(Rect(0, 0, y, y), ld); 632 if(b == 0){ 633 mesg("balloc failed file %s: %r", file); 634 free(data); 635 close(fd); 636 goto Err; 637 } 638 i = 0; 639 for(j=0; j<y; j++){ 640 for(x=0; (c=data[i])!='\n'; ){ 641 if(strchr(" \t,{}", c)){ 642 i++; 643 continue; 644 } 645 if(c=='0' && data[i+1] == 'x'){ 646 i += 2; 647 continue; 648 } 649 if(strchr(hex, c)){ 650 buf[x++] = (tohex(c)<<4) | tohex(data[i+1]); 651 i += 2; 652 continue; 653 } 654 } 655 i++; 656 wrbitmap(b, j, j+1, buf); 657 } 658 free(data); 659 }else{ 660 /* 661 * plain bitmap file 662 */ 663 face = 0; 664 s = 0; 665 b = rdbitmapfile(fd); 666 if(b == 0){ 667 mesg("can't read bitmap file %s: %r", file); 668 close(fd); 669 goto Err; 670 } 671 if(seek(fd, 0, 1) < d.length){ 672 /* rdsubfontfile drops bitmap; must make a copy */ 673 tb = balloc(b->r, b->ldepth); 674 if(tb == 0){ 675 mesg("can't balloc bitmap for file %s: %r", file); 676 close(fd); 677 goto Err; 678 } 679 bitblt(tb, tb->r.min, b, b->r, S); 680 s = rdsubfontfile(fd, tb); 681 } 682 } 683 close(fd); 684 t = malloc(sizeof(Thing)); 685 if(t == 0){ 686 nomem: 687 mesg("malloc failed: %r"); 688 if(s) 689 subffree(s); 690 bfree(b); 691 goto Err; 692 } 693 t->name = strdup(file); 694 if(t->name == 0){ 695 free(t); 696 goto nomem; 697 } 698 t->b = b; 699 t->s = s; 700 t->face = face; 701 t->mod = 0; 702 t->parent = 0; 703 t->c = -1; 704 t->mag = 1; 705 t->off = 0; 706 memmove(err, oerr, sizeof err); 707 return t; 708 } 709 710 int 711 atline(int x, Point p, char *line, char *buf) 712 { 713 char *s, *c, *word, *hit; 714 int w, wasblank; 715 Rune r; 716 717 wasblank = 1; 718 hit = 0; 719 word = 0; 720 for(s=line; *s; s+=w){ 721 w = chartorune(&r, s); 722 x += charwidth(font, r); 723 if(wasblank && r!=' ') 724 word = s; 725 wasblank = 0; 726 if(r == ' '){ 727 if(x >= p.x) 728 break; 729 wasblank = 1; 730 } 731 if(r == ':') 732 hit = word; 733 } 734 if(x < p.x) 735 return 0; 736 c = utfrune(hit, ':'); 737 strncpy(buf, hit, c-hit); 738 buf[c-hit] = 0; 739 return 1; 740 } 741 742 int 743 attext(Thing *t, Point p, char *buf) 744 { 745 char l0[256], l1[256]; 746 747 if(!ptinrect(p, t->tr)) 748 return 0; 749 stext(t, l0, l1); 750 if(p.y < t->tr.min.y+font->height) 751 return atline(t->r.min.x, p, l0, buf); 752 else 753 return atline(t->r.min.x, p, l1, buf); 754 } 755 756 int 757 type(char *buf, char *tag) 758 { 759 Rune r; 760 char *p; 761 762 cursorswitch(&busy); 763 p = buf; 764 for(;;){ 765 *p = 0; 766 mesg("%s: %s", tag, buf); 767 r = ekbd(); 768 switch(r){ 769 case '\n': 770 mesg(""); 771 cursorswitch(0); 772 return p-buf; 773 case 0x15: /* control-U */ 774 p = buf; 775 break; 776 case '\b': 777 if(p > buf) 778 --p; 779 break; 780 default: 781 p += runetochar(p, &r); 782 } 783 } 784 return 0; /* shut up compiler */ 785 } 786 787 void 788 textedit(Thing *t, char *tag) 789 { 790 char buf[256]; 791 char *s; 792 Bitmap *b; 793 Subfont *f; 794 Fontchar *fc, *nfc; 795 Rectangle r; 796 int i, ld, w, c, doredraw, fdx, x; 797 Thing *nt; 798 799 buttons(Up); 800 if(type(buf, tag) == 0) 801 return; 802 if(strcmp(tag, "file") == 0){ 803 for(s=buf; *s; s++) 804 if(*s <= ' '){ 805 mesg("illegal file name"); 806 return; 807 } 808 if(strcmp(t->name, buf) != 0){ 809 if(t->parent) 810 t->parent->mod = 1; 811 else 812 t->mod = 1; 813 } 814 for(nt=thing; nt; nt=nt->next) 815 if(t==nt || t->parent==nt || nt->parent==t){ 816 free(nt->name); 817 nt->name = strdup(buf); 818 if(nt->name == 0){ 819 nomem: 820 mesg("malloc failed: %r"); 821 return; 822 } 823 text(nt); 824 } 825 return; 826 } 827 if(strcmp(tag, "ldepth") == 0){ 828 if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0 || ld>3){ 829 mesg("illegal ldepth"); 830 return; 831 } 832 if(ld == t->b->ldepth) 833 return; 834 if(t->parent) 835 t->parent->mod = 1; 836 else 837 t->mod = 1; 838 for(nt=thing; nt; nt=nt->next){ 839 if(nt!=t && nt!=t->parent && nt->parent!=t) 840 continue; 841 b = balloc(nt->b->r, ld); 842 if(b == 0){ 843 nobmem: 844 mesg("balloc failed: %r"); 845 return; 846 } 847 bitblt(b, b->r.min, nt->b, nt->b->r, S); 848 bfree(nt->b); 849 nt->b = b; 850 if(nt->s){ 851 b = balloc(nt->b->r, ld); 852 if(b == 0) 853 goto nobmem; 854 bitblt(b, b->r.min, nt->b, nt->b->r, S); 855 f = subfalloc(nt->s->n, nt->s->height, nt->s->ascent, 856 nt->s->info, b, ~0, ~0); 857 if(f == 0){ 858 nofmem: 859 mesg("can't make subfont: %r"); 860 return; 861 } 862 subffree(nt->s); 863 nt->s = f; 864 } 865 draw(nt, 0); 866 } 867 return; 868 } 869 if(strcmp(tag, "mag") == 0){ 870 if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<=0 || ld>Maxmag){ 871 mesg("illegal magnification"); 872 return; 873 } 874 if(t->mag == ld) 875 return; 876 t->mag = ld; 877 redraw(t); 878 return; 879 } 880 if(strcmp(tag, "ascent") == 0){ 881 if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0 || ld>t->s->height){ 882 mesg("illegal ascent"); 883 return; 884 } 885 if(t->s->ascent == ld) 886 return; 887 t->s->ascent = ld; 888 text(t); 889 t->mod = 1; 890 return; 891 } 892 if(strcmp(tag, "height") == 0){ 893 if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0){ 894 mesg("illegal height"); 895 return; 896 } 897 if(t->s->height == ld) 898 return; 899 t->s->height = ld; 900 text(t); 901 t->mod = 1; 902 return; 903 } 904 if(strcmp(tag, "left")==0 || strcmp(tag, "width") == 0){ 905 if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0){ 906 mesg("illegal value"); 907 return; 908 } 909 fc = &t->parent->s->info[t->c]; 910 if(strcmp(tag, "left")==0){ 911 if(fc->left == ld) 912 return; 913 fc->left = ld; 914 }else{ 915 if(fc->width == ld) 916 return; 917 fc->width = ld; 918 } 919 text(t); 920 t->parent->mod = 1; 921 return; 922 } 923 if(strcmp(tag, "offset(hex)") == 0){ 924 if(!strchr(hex, buf[0])){ 925 illoff: 926 mesg("illegal offset"); 927 return; 928 } 929 s = 0; 930 ld = strtoul(buf, &s, 16); 931 if(*s) 932 goto illoff; 933 t->off = ld; 934 text(t); 935 for(nt=thing; nt; nt=nt->next) 936 if(nt->parent == t) 937 text(nt); 938 return; 939 } 940 if(strcmp(tag, "n") == 0){ 941 if(buf[0]<'0' || '9'<buf[0] || (w=atoi(buf))<=0){ 942 mesg("illegal n"); 943 return; 944 } 945 f = t->s; 946 if(w == f->n) 947 return; 948 doredraw = 0; 949 again: 950 for(nt=thing; nt; nt=nt->next) 951 if(nt->parent == t){ 952 doredraw = 1; 953 tclose1(nt); 954 goto again; 955 } 956 r = t->b->r; 957 if(w < f->n) 958 r.max.x = f->info[w].x; 959 b = balloc(r, t->b->ldepth); 960 if(b == 0) 961 goto nobmem; 962 bitblt(b, b->r.min, t->b, r, S); 963 fdx = Dx(editr) - 2*Border; 964 if(Dx(t->b->r)/fdx != Dx(b->r)/fdx) 965 doredraw = 1; 966 bfree(t->b); 967 t->b = b; 968 b = balloc(r, t->b->ldepth); 969 if(b == 0) 970 goto nobmem; 971 bitblt(b, b->r.min, t->b, r, S); 972 nfc = malloc((w+1)*sizeof(Fontchar)); 973 if(nfc == 0){ 974 mesg("malloc failed"); 975 bfree(b); 976 return; 977 } 978 fc = f->info; 979 for(i=0; i<=w && i<=f->n; i++) 980 nfc[i] = fc[i]; 981 if(w+1 < i) 982 memset(nfc+i, 0, ((w+1)-i)*sizeof(Fontchar)); 983 x = fc[f->n].x; 984 for(; i<=w; i++) 985 nfc[i].x = x; 986 f = subfalloc(w, f->height, f->ascent, nfc, b, ~0, ~0); 987 if(f == 0) 988 goto nofmem; 989 subffree(t->s); 990 f->info = nfc; 991 t->s = f; 992 if(doredraw) 993 redraw(thing); 994 else 995 draw(t, 0); 996 t->mod = 1; 997 return; 998 } 999 if(strcmp(tag, "iwidth") == 0){ 1000 if(buf[0]<'0' || '9'<buf[0] || (w=atoi(buf))<0){ 1001 mesg("illegal iwidth"); 1002 return; 1003 } 1004 w -= Dx(t->b->r); 1005 if(w == 0) 1006 return; 1007 r = t->parent->b->r; 1008 r.max.x += w; 1009 c = t->c; 1010 t = t->parent; 1011 f = t->s; 1012 b = balloc(r, t->b->ldepth); 1013 if(b == 0) 1014 goto nobmem; 1015 fc = &f->info[c]; 1016 bitblt(b, b->r.min, t->b, 1017 Rect(t->b->r.min.x, t->b->r.min.y, 1018 fc[1].x, t->b->r.max.y), S); 1019 bitblt(b, Pt(fc[1].x+w, b->r.min.y), t->b, 1020 Rect(fc[1].x, t->b->r.min.y, 1021 t->b->r.max.x, t->b->r.max.y), S); 1022 fdx = Dx(editr) - 2*Border; 1023 doredraw = 0; 1024 if(Dx(t->b->r)/fdx != Dx(b->r)/fdx) 1025 doredraw = 1; 1026 bfree(t->b); 1027 t->b = b; 1028 b = balloc(r, t->b->ldepth); 1029 if(b == 0) 1030 goto nobmem; 1031 bitblt(b, b->r.min, t->b, t->b->r, S); 1032 fc = &f->info[c+1]; 1033 for(i=c+1; i<=f->n; i++, fc++) 1034 fc->x += w; 1035 f = subfalloc(f->n, f->height, f->ascent, 1036 f->info, b, ~0, ~0); 1037 if(f == 0) 1038 goto nofmem; 1039 /* t->s and f share info; free carefully */ 1040 fc = f->info; 1041 t->s->info = 0; 1042 subffree(t->s); 1043 f->info = fc; 1044 t->s = f; 1045 if(doredraw) 1046 redraw(t); 1047 else 1048 draw(t, 0); 1049 /* redraw all affected chars */ 1050 for(nt=thing; nt; nt=nt->next){ 1051 if(nt->parent!=t || nt->c<c) 1052 continue; 1053 fc = &f->info[nt->c]; 1054 r.min.x = fc[0].x; 1055 r.min.y = nt->b->r.min.y; 1056 r.max.x = fc[1].x; 1057 r.max.y = nt->b->r.max.y; 1058 b = balloc(r, nt->b->ldepth); 1059 if(b == 0) 1060 goto nobmem; 1061 bitblt(b, r.min, t->b, r, S); 1062 doredraw = 0; 1063 if(Dx(nt->b->r)/fdx != Dx(b->r)/fdx) 1064 doredraw = 1; 1065 bfree(nt->b); 1066 nt->b = b; 1067 if(c != nt->c) 1068 text(nt); 1069 else{ 1070 if(doredraw) 1071 redraw(nt); 1072 else 1073 draw(nt, 0); 1074 } 1075 } 1076 t->mod = 1; 1077 return; 1078 } 1079 mesg("cannot edit %s in file %s", tag, t->name); 1080 } 1081 1082 void 1083 cntledit(char *tag) 1084 { 1085 char buf[256]; 1086 char *p, *q; 1087 ulong l; 1088 int i, inv; 1089 1090 buttons(Up); 1091 if(type(buf, tag) == 0) 1092 return; 1093 if(strcmp(tag, "mag") == 0){ 1094 if(buf[0]<'0' || '9'<buf[0] || (l=atoi(buf))<=0 || l>Maxmag){ 1095 mesg("illegal magnification"); 1096 return; 1097 } 1098 mag = l; 1099 cntl(); 1100 return; 1101 } 1102 if(strcmp(tag, "val(hex)") == 0){ 1103 inv = 0; 1104 p = buf; 1105 if(*p == '~'){ 1106 p++; 1107 inv = 1; 1108 } 1109 l = strtoul(p, &q, 16); 1110 if(l==0 && q==p){ 1111 mesg("illegal magnification"); 1112 return; 1113 } 1114 if(inv) 1115 l = ~l; 1116 val = l; 1117 cntl(); 1118 return; 1119 } 1120 if(strcmp(tag, "but1")==0 1121 || strcmp(tag, "but2")==0 1122 || strcmp(tag, "copy")==0){ 1123 i = strtofn(buf); 1124 if(i < 0){ 1125 mesg("unknown function"); 1126 return; 1127 } 1128 if(strcmp(tag, "but1") == 0) 1129 but1fn = i; 1130 else if(strcmp(tag, "but2") == 0) 1131 but2fn = i; 1132 else 1133 copyfn = i; 1134 cntl(); 1135 return; 1136 } 1137 mesg("cannot edit %s", tag); 1138 } 1139 1140 void 1141 buttons(int ud) 1142 { 1143 while((mouse.buttons==0) != ud) 1144 mouse = emouse(); 1145 } 1146 1147 int 1148 sweep(int butmask, Rectangle *r) 1149 { 1150 Point p; 1151 1152 cursorswitch(&sweep0); 1153 buttons(Down); 1154 if(mouse.buttons != butmask){ 1155 buttons(Up); 1156 cursorswitch(0); 1157 return 0; 1158 } 1159 p = mouse.xy; 1160 cursorswitch(&box); 1161 r->min = p; 1162 r->max = p; 1163 while(mouse.buttons == butmask){ 1164 border(&screen, *r, -2, ~D); 1165 bflush(); 1166 mouse = emouse(); 1167 border(&screen, *r, -2, ~D); 1168 *r = rcanon(Rpt(p, mouse.xy)); 1169 } 1170 cursorswitch(0); 1171 if(mouse.buttons){ 1172 buttons(Up); 1173 return 0; 1174 } 1175 return 1; 1176 } 1177 1178 void 1179 openedit(Thing *t, Point pt, int c) 1180 { 1181 int x, y; 1182 Point p; 1183 Rectangle r; 1184 Rectangle br; 1185 Fontchar *fc; 1186 Thing *nt; 1187 1188 br = t->b->r; 1189 if(t->s == 0){ 1190 c = -1; 1191 /* if big enough to bother, sweep box */ 1192 if(Dx(br)<=16 && Dy(br)<=16) 1193 r = br; 1194 else{ 1195 if(!sweep(1, &r)) 1196 return; 1197 r = raddp(r, sub(br.min, t->r.min)); 1198 if(!rectclip(&r, br)) 1199 return; 1200 if(Dx(br) <= 8){ 1201 r.min.x = br.min.x; 1202 r.max.x = br.max.x; 1203 }else if(Dx(r) < 4){ 1204 toosmall: 1205 mesg("rectangle too small"); 1206 return; 1207 } 1208 if(Dy(br) <= 8){ 1209 r.min.y = br.min.y; 1210 r.max.y = br.max.y; 1211 }else if(Dy(r) < 4) 1212 goto toosmall; 1213 } 1214 }else if(c >= 0){ 1215 fc = &t->s->info[c]; 1216 r.min.x = fc[0].x; 1217 r.min.y = br.min.y; 1218 r.max.x = fc[1].x; 1219 r.max.y = br.min.y + Dy(br); 1220 }else{ 1221 /* just point at character */ 1222 fc = t->s->info; 1223 p = add(pt, sub(br.min, t->r.min)); 1224 x = br.min.x; 1225 y = br.min.y; 1226 for(c=0; c<t->s->n; c++,fc++){ 1227 again: 1228 r.min.x = x; 1229 r.min.y = y; 1230 r.max.x = x + fc[1].x - fc[0].x; 1231 r.max.y = y + Dy(br); 1232 if(ptinrect(p, r)) 1233 goto found; 1234 if(r.max.x >= br.min.x+Dx(t->r)){ 1235 x -= Dx(t->r); 1236 y += t->s->height; 1237 if(fc[1].x > fc[0].x) 1238 goto again; 1239 } 1240 x += fc[1].x - fc[0].x; 1241 } 1242 return; 1243 found: 1244 r = br; 1245 r.min.x = fc[0].x; 1246 r.max.x = fc[1].x; 1247 } 1248 nt = malloc(sizeof(Thing)); 1249 if(nt == 0){ 1250 nomem: 1251 mesg("can't allocate: %r"); 1252 return; 1253 } 1254 memset(nt, 0, sizeof(Thing)); 1255 nt->c = c; 1256 nt->b = balloc(r, t->b->ldepth); 1257 if(nt->b == 0){ 1258 free(nt); 1259 goto nomem; 1260 } 1261 bitblt(nt->b, r.min, t->b, r, S); 1262 nt->name = strdup(t->name); 1263 if(nt->name == 0){ 1264 bfree(nt->b); 1265 free(nt); 1266 goto nomem; 1267 } 1268 nt->parent = t; 1269 nt->mag = mag; 1270 draw(nt, 1); 1271 } 1272 1273 void 1274 ckinfo(Thing *t, Rectangle mod) 1275 { 1276 int i, j, k, top, bot, n, zero; 1277 Fontchar *fc; 1278 Rectangle r; 1279 Bitmap *b; 1280 Thing *nt; 1281 1282 if(t->parent) 1283 t = t->parent; 1284 if(t->s==0 || Dy(t->b->r)==0) 1285 return; 1286 b = 0; 1287 /* check bounding boxes */ 1288 fc = &t->s->info[0]; 1289 r.min.y = t->b->r.min.y; 1290 r.max.y = t->b->r.max.y; 1291 for(i=0; i<t->s->n; i++, fc++){ 1292 r.min.x = fc[0].x; 1293 r.max.x = fc[1].x; 1294 if(!rectXrect(mod, r)) 1295 continue; 1296 if(b==0 || Dx(b->r)<Dx(r)){ 1297 if(b) 1298 bfree(b); 1299 b = balloc(rsubp(r, r.min), t->b->ldepth); 1300 if(b == 0){ 1301 mesg("can't balloc"); 1302 break; 1303 } 1304 } 1305 bitblt(b, b->r.min, b, b->r, 0); 1306 bitblt(b, b->r.min, t->b, r, S); 1307 top = 100000; 1308 bot = 0; 1309 n = 2+(Dx(r)/8<<t->b->ldepth); 1310 for(j=0; j<b->r.max.y; j++){ 1311 memset(data, 0, n); 1312 rdbitmap(b, j, j+1, data); 1313 zero = 1; 1314 for(k=0; k<n; k++) 1315 if(data[k]){ 1316 zero = 0; 1317 break; 1318 } 1319 if(!zero){ 1320 if(top > j) 1321 top = j; 1322 bot = j+1; 1323 } 1324 } 1325 if(top > j) 1326 top = 0; 1327 if(top!=fc->top || bot!=fc->bottom){ 1328 fc->top = top; 1329 fc->bottom = bot; 1330 for(nt=thing; nt; nt=nt->next) 1331 if(nt->parent==t && nt->c==i) 1332 text(nt); 1333 } 1334 } 1335 if(b) 1336 bfree(b); 1337 } 1338 1339 Point 1340 screenpt(Thing *t, Point realp) 1341 { 1342 int fdx, n; 1343 Point p; 1344 1345 fdx = Dx(editr)-2*Border; 1346 if(t->mag > 1) 1347 fdx -= fdx%t->mag; 1348 p = mul(sub(realp, t->b->r.min), t->mag); 1349 if(fdx < Dx(t->b->r)*t->mag){ 1350 n = p.x/fdx; 1351 p.y += n * (Dy(t->b->r)*t->mag+Border); 1352 p.x -= n * fdx; 1353 } 1354 p = add(p, t->r.min); 1355 return p; 1356 } 1357 1358 Point 1359 realpt(Thing *t, Point screenp) 1360 { 1361 int fdx, n, dy; 1362 Point p; 1363 1364 fdx = (Dx(editr)-2*Border); 1365 if(t->mag > 1) 1366 fdx -= fdx%t->mag; 1367 p.y = screenp.y-t->r.min.y; 1368 p.x = 0; 1369 if(fdx < Dx(t->b->r)*t->mag){ 1370 dy = Dy(t->b->r)*t->mag+Border; 1371 n = (p.y/dy); 1372 p.x = n * fdx; 1373 p.y -= n * dy; 1374 } 1375 p.x += screenp.x-t->r.min.x; 1376 p = add(div(p, t->mag), t->b->r.min); 1377 return p; 1378 } 1379 1380 void 1381 twidpix(Thing *t, Point p, int set) 1382 { 1383 Bitmap *b; 1384 int v, c; 1385 1386 c = but1fn; 1387 if(!set) 1388 c = but2fn; 1389 b = t->b; 1390 if(!ptinrect(p, b->r)) 1391 return; 1392 point(b, p, val, c); 1393 v = bvalue(val, b->ldepth); 1394 p = screenpt(t, p); 1395 bitblt(&screen, p, values, Rect(v, 0, v+t->mag, t->mag), c); 1396 } 1397 1398 void 1399 twiddle(Thing *t) 1400 { 1401 int set; 1402 Point p, lastp; 1403 Bitmap *b; 1404 Thing *nt; 1405 Rectangle mod; 1406 1407 if(mouse.buttons!=1 && mouse.buttons!=2){ 1408 buttons(Up); 1409 return; 1410 } 1411 set = mouse.buttons==1; 1412 b = t->b; 1413 lastp = add(b->r.min, Pt(-1, -1)); 1414 mod = Rpt(add(b->r.max, Pt(1, 1)), lastp); 1415 while(mouse.buttons){ 1416 p = realpt(t, mouse.xy); 1417 if(!eqpt(p, lastp)){ 1418 lastp = p; 1419 if(ptinrect(p, b->r)){ 1420 for(nt=thing; nt; nt=nt->next) 1421 if(nt->parent==t->parent || nt==t->parent) 1422 twidpix(nt, p, set); 1423 if(t->parent) 1424 t->parent->mod = 1; 1425 else 1426 t->mod = 1; 1427 if(p.x < mod.min.x) 1428 mod.min.x = p.x; 1429 if(p.y < mod.min.y) 1430 mod.min.y = p.y; 1431 if(p.x >= mod.max.x) 1432 mod.max.x = p.x+1; 1433 if(p.y >= mod.max.y) 1434 mod.max.y = p.y+1; 1435 } 1436 } 1437 mouse = emouse(); 1438 } 1439 ckinfo(t, mod); 1440 } 1441 1442 void 1443 select(void) 1444 { 1445 Thing *t; 1446 char line[128], buf[128]; 1447 Point p; 1448 1449 if(ptinrect(mouse.xy, cntlr)){ 1450 scntl(line); 1451 if(atline(cntlr.min.x, mouse.xy, line, buf)){ 1452 if(mouse.buttons == 1) 1453 cntledit(buf); 1454 else 1455 buttons(Up); 1456 return; 1457 } 1458 return; 1459 } 1460 for(t=thing; t; t=t->next){ 1461 if(attext(t, mouse.xy, buf)){ 1462 if(mouse.buttons == 1) 1463 textedit(t, buf); 1464 else 1465 buttons(Up); 1466 return; 1467 } 1468 if(ptinrect(mouse.xy, t->r)){ 1469 if(t->parent == 0){ 1470 if(mouse.buttons == 1){ 1471 p = mouse.xy; 1472 buttons(Up); 1473 openedit(t, p, -1); 1474 }else 1475 buttons(Up); 1476 return; 1477 } 1478 twiddle(t); 1479 return; 1480 } 1481 } 1482 } 1483 1484 void 1485 twrite(Thing *t) 1486 { 1487 int i, j, x, y, fd, ws, ld; 1488 Biobuf buf; 1489 Rectangle r; 1490 1491 if(t->parent) 1492 t = t->parent; 1493 cursorswitch(&busy); 1494 fd = create(t->name, OWRITE, 0666); 1495 if(fd < 0){ 1496 mesg("can't write %s: %r", t->name); 1497 return; 1498 } 1499 if(t->face){ 1500 r = t->b->r; 1501 ld = t->b->ldepth; 1502 /* This heuristic reflects peculiarly different formats */ 1503 ws = 4; 1504 if(Dx(r) == 16) /* probably cursor file */ 1505 ws = 1; 1506 else if(Dx(r)<32 || ld==0) 1507 ws = 2; 1508 Binit(&buf, fd, OWRITE); 1509 for(y=r.min.y; y<r.max.y; y++){ 1510 rdbitmap(t->b, y, y+1, data); 1511 j = 0; 1512 for(x=r.min.x; x<r.max.x; j+=ws,x+=ws*8>>ld){ 1513 Bprint(&buf, "0x"); 1514 for(i=0; i<ws; i++) 1515 Bprint(&buf, "%.2x", data[i+j]); 1516 Bprint(&buf, ", "); 1517 } 1518 Bprint(&buf, "\n"); 1519 } 1520 Bterm(&buf); 1521 }else{ 1522 wrbitmapfile(fd, t->b); 1523 if(t->s) 1524 wrsubfontfile(fd, t->s); 1525 } 1526 t->mod = 0; 1527 close(fd); 1528 mesg("wrote %s", t->name); 1529 } 1530 1531 void 1532 tclose1(Thing *t) 1533 { 1534 Thing *nt; 1535 1536 if(t == thing) 1537 thing = t->next; 1538 else{ 1539 for(nt=thing; nt->next!=t; nt=nt->next) 1540 ; 1541 nt->next = t->next; 1542 } 1543 do 1544 for(nt=thing; nt; nt=nt->next) 1545 if(nt->parent == t){ 1546 tclose1(nt); 1547 break; 1548 } 1549 while(nt); 1550 if(t->s) 1551 subffree(t->s); 1552 bfree(t->b); 1553 free(t->name); 1554 free(t); 1555 } 1556 1557 void 1558 tclose(Thing *t) 1559 { 1560 Thing *ct; 1561 1562 if(t->mod){ 1563 mesg("%s modified", t->name); 1564 t->mod = 0; 1565 return; 1566 } 1567 /* fiddle to save redrawing unmoved things */ 1568 if(t == thing) 1569 ct = 0; 1570 else 1571 for(ct=thing; ct; ct=ct->next) 1572 if(ct->next==t || ct->next->parent==t) 1573 break; 1574 tclose1(t); 1575 if(ct) 1576 ct = ct->next; 1577 else 1578 ct = thing; 1579 redraw(ct); 1580 } 1581 1582 void 1583 tread(Thing *t) 1584 { 1585 Thing *nt, *new; 1586 Fontchar *i; 1587 Rectangle r; 1588 int nclosed; 1589 1590 if(t->parent) 1591 t = t->parent; 1592 new = tget(t->name); 1593 if(new == 0) 1594 return; 1595 nclosed = 0; 1596 again: 1597 for(nt=thing; nt; nt=nt->next) 1598 if(nt->parent == t){ 1599 if(!rectinrect(nt->b->r, new->b->r) 1600 || new->b->ldepth!=nt->b->ldepth){ 1601 closeit: 1602 nclosed++; 1603 nt->parent = 0; 1604 tclose1(nt); 1605 goto again; 1606 } 1607 if((t->s==0) != (new->s==0)) 1608 goto closeit; 1609 if((t->face==0) != (new->face==0)) 1610 goto closeit; 1611 if(t->s){ /* check same char */ 1612 if(nt->c >= new->s->n) 1613 goto closeit; 1614 i = &new->s->info[nt->c]; 1615 r.min.x = i[0].x; 1616 r.max.x = i[1].x; 1617 r.min.y = new->b->r.min.y; 1618 r.max.y = new->b->r.max.y; 1619 if(!eqrect(r, nt->b->r)) 1620 goto closeit; 1621 } 1622 nt->parent = new; 1623 bitblt(nt->b, nt->b->r.min, new->b, 1624 nt->b->r, S); 1625 } 1626 new->next = t->next; 1627 if(t == thing) 1628 thing = new; 1629 else{ 1630 for(nt=thing; nt->next!=t; nt=nt->next) 1631 ; 1632 nt->next = new; 1633 } 1634 if(t->s) 1635 subffree(t->s); 1636 bfree(t->b); 1637 free(t->name); 1638 free(t); 1639 for(nt=thing; nt; nt=nt->next) 1640 if(nt==new || nt->parent==new) 1641 if(nclosed == 0) 1642 draw(nt, 0); /* can draw in place */ 1643 else{ 1644 redraw(nt); /* must redraw all below */ 1645 break; 1646 } 1647 } 1648 1649 void 1650 tchar(Thing *t) 1651 { 1652 char buf[256], *p; 1653 Rune r; 1654 ulong c, d; 1655 1656 if(t->s == 0){ 1657 mesg("not a subfont"); 1658 return; 1659 } 1660 if(type(buf, "char (hex or character or hex-hex)") == 0) 1661 return; 1662 if(utflen(buf) == 1){ 1663 chartorune(&r, buf); 1664 c = r; 1665 d = r; 1666 }else{ 1667 if(!strchr(hex, buf[0])){ 1668 mesg("illegal hex character"); 1669 return; 1670 } 1671 c = strtoul(buf, 0, 16); 1672 d = c; 1673 p = utfrune(buf, '-'); 1674 if(p){ 1675 d = strtoul(p+1, 0, 16); 1676 if(d < c){ 1677 mesg("invalid range"); 1678 return; 1679 } 1680 } 1681 } 1682 c -= t->off; 1683 d -= t->off; 1684 while(c <= d){ 1685 if(c<0 || c>=t->s->n){ 1686 mesg("0x%lux not in font %s", c+t->off, t->name); 1687 return; 1688 } 1689 openedit(t, Pt(0, 0), c); 1690 c++; 1691 } 1692 } 1693 1694 void 1695 apply(void (*f)(Thing*)) 1696 { 1697 Thing *t; 1698 1699 cursorswitch(&sight); 1700 buttons(Down); 1701 if(mouse.buttons == 4) 1702 for(t=thing; t; t=t->next) 1703 if(ptinrect(mouse.xy, t->er)){ 1704 buttons(Up); 1705 f(t); 1706 break; 1707 } 1708 buttons(Up); 1709 cursorswitch(0); 1710 } 1711 1712 void 1713 copy(void) 1714 { 1715 Thing *st, *dt, *nt; 1716 Rectangle sr, dr, fr; 1717 Point p1, p2; 1718 int but, up; 1719 1720 if(!sweep(4, &sr)) 1721 return; 1722 for(st=thing; st; st=st->next) 1723 if(rectXrect(sr, st->r)) 1724 break; 1725 if(st == 0) 1726 return; 1727 /* click gives full rectangle */ 1728 if(Dx(sr)<4 && Dy(sr)<4) 1729 sr = st->r; 1730 rectclip(&sr, st->r); 1731 p1 = realpt(st, sr.min); 1732 p2 = realpt(st, Pt(sr.min.x, sr.max.y)); 1733 if(p1.x != p2.x){ /* swept across a fold */ 1734 onafold: 1735 mesg("sweep spans a fold"); 1736 return; 1737 } 1738 p2 = realpt(st, sr.max); 1739 sr.min = p1; 1740 sr.max = p2; 1741 fr.min = screenpt(st, sr.min); 1742 fr.max = screenpt(st, sr.max); 1743 border(&screen, fr, -3, ~D); 1744 p1 = sub(p2, p1); /* diagonal */ 1745 if(p1.x==0 || p1.y==0){ 1746 Return: 1747 border(&screen, fr, -3, ~D); 1748 return; 1749 } 1750 cursorswitch(&box); 1751 up = 0; 1752 for(; mouse.buttons==0; mouse=emouse()){ 1753 for(dt=thing; dt; dt=dt->next) 1754 if(ptinrect(mouse.xy, dt->er)) 1755 break; 1756 if(up) 1757 border(&screen, dr, -2, ~D); 1758 up = 0; 1759 if(dt == 0) 1760 continue; 1761 dr.max = screenpt(dt, realpt(dt, mouse.xy)); 1762 dr.min = sub(dr.max, mul(p1, dt->mag)); 1763 if(!rectXrect(dr, dt->r)) 1764 continue; 1765 border(&screen, dr, -2, ~D); 1766 up = 1; 1767 } 1768 /* if up==1, we had a hit */ 1769 cursorswitch(0); 1770 if(up) 1771 border(&screen, dr, -2, ~D); 1772 but = mouse.buttons; 1773 border(&screen, fr, -3, ~D); 1774 buttons(Up); 1775 if(!up || but!=4) 1776 return; 1777 dt = 0; 1778 for(nt=thing; nt; nt=nt->next) 1779 if(rectXrect(dr, nt->r)){ 1780 if(dt){ 1781 mesg("ambiguous sweep"); 1782 return; 1783 } 1784 dt = nt; 1785 } 1786 if(dt == 0) 1787 return; 1788 p1 = realpt(dt, dr.min); 1789 p2 = realpt(dt, Pt(dr.min.x, dr.max.y)); 1790 if(p1.x != p2.x) 1791 goto onafold; 1792 p2 = realpt(dt, dr.max); 1793 dr.min = p1; 1794 dr.max = p2; 1795 bitblt(dt->b, dr.min, st->b, sr, copyfn); 1796 if(dt->parent){ 1797 bitblt(dt->parent->b, dr.min, dt->b, dr, S); 1798 dt = dt->parent; 1799 } 1800 draw(dt, 0); 1801 for(nt=thing; nt; nt=nt->next) 1802 if(nt->parent==dt && rectXrect(dr, nt->b->r)){ 1803 bitblt(nt->b, dr.min, dt->b, dr, S); 1804 draw(nt, 0); 1805 } 1806 ckinfo(dt, dr); 1807 dt->mod = 1; 1808 } 1809 1810 void 1811 menu(void) 1812 { 1813 Thing *t; 1814 char *mod; 1815 int sel; 1816 char buf[256]; 1817 1818 sel = menuhit(3, &mouse, &menu3); 1819 switch(sel){ 1820 case Mopen: 1821 if(type(buf, "file")){ 1822 t = tget(buf); 1823 if(t) 1824 draw(t, 1); 1825 } 1826 break; 1827 case Mwrite: 1828 apply(twrite); 1829 break; 1830 case Mread: 1831 apply(tread); 1832 break; 1833 case Mchar: 1834 apply(tchar); 1835 break; 1836 case Mcopy: 1837 copy(); 1838 break; 1839 case Mclose: 1840 apply(tclose); 1841 break; 1842 case Mexit: 1843 mod = 0; 1844 for(t=thing; t; t=t->next) 1845 if(t->mod){ 1846 mod = t->name; 1847 t->mod = 0; 1848 } 1849 if(mod){ 1850 mesg("%s modified", mod); 1851 break; 1852 } 1853 cursorswitch(&skull); 1854 buttons(Down); 1855 if(mouse.buttons == 4){ 1856 buttons(Up); 1857 exits(0); 1858 } 1859 buttons(Up); 1860 cursorswitch(0); 1861 break; 1862 } 1863 } 1864 1865 char* 1866 fntostr(uint f) 1867 { 1868 char **s; 1869 int i; 1870 1871 f &= F; 1872 s = fns; 1873 for(i=0; i<f; i++) 1874 do; while(*s++); 1875 return *s; 1876 } 1877 1878 int 1879 strtofn(char *str) 1880 { 1881 char **s; 1882 int i; 1883 1884 s = fns; 1885 i = 0; 1886 while(i <= F){ 1887 if(*s == 0) 1888 i++; 1889 else 1890 if(strcmp(str, *s) == 0) 1891 return i; 1892 s++; 1893 } 1894 return -1; 1895 } 1896