12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <cursor.h>
- #include <event.h>
- #include <bio.h>
- typedef struct Thing Thing;
- struct Thing
- {
- Image *b;
- Subfont *s;
- char *name; /* file name */
- int face; /* is 48x48 face file or cursor file*/
- Rectangle r; /* drawing region */
- Rectangle tr; /* text region */
- Rectangle er; /* entire region */
- int32_t c; /* character number in subfont */
- int mod; /* modified */
- int mag; /* magnification */
- Rune off; /* offset for subfont indices */
- Thing *parent; /* thing of which i'm an edit */
- Thing *next;
- };
- enum
- {
- Border = 1,
- Up = 1,
- Down = 0,
- Mag = 4,
- Maxmag = 10,
- };
- enum
- {
- NORMAL =0,
- FACE =1,
- CURSOR =2
- };
- enum
- {
- Mopen,
- Mread,
- Mwrite,
- Mcopy,
- Mchar,
- Mpixels,
- Mclose,
- Mexit,
- };
- enum
- {
- Blue = 54,
- };
- char *menu3str[] = {
- [Mopen] "open",
- [Mread] "read",
- [Mwrite] "write",
- [Mcopy] "copy",
- [Mchar] "char",
- [Mpixels] "pixels",
- [Mclose] "close",
- [Mexit] "exit",
- 0,
- };
- Menu menu3 = {
- menu3str
- };
- Cursor sweep0 = {
- {-7, -7},
- {0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
- 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0,
- 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0},
- {0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
- 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x7F, 0xFE,
- 0x7F, 0xFE, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
- 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00}
- };
- Cursor box = {
- {-7, -7},
- {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
- 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
- {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
- 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
- 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
- 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00}
- };
- Cursor sight = {
- {-7, -7},
- {0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
- 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
- 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,},
- {0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
- 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
- 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
- 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,}
- };
- Cursor pixel = {
- {-7, -7},
- {0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0xf8, 0x1f,
- 0xf0, 0x0f, 0xe0, 0x07, 0xe0, 0x07, 0xfe, 0x7f,
- 0xfe, 0x7f, 0xe0, 0x07, 0xe0, 0x07, 0xf0, 0x0f,
- 0x78, 0x1f, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0xf8, },
- {0x00, 0x00, 0x0f, 0xf0, 0x31, 0x8c, 0x21, 0x84,
- 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x40, 0x02,
- 0x40, 0x02, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
- 0x21, 0x84, 0x31, 0x8c, 0x0f, 0xf0, 0x00, 0x00, }
- };
- Cursor busy = {
- {-7, -7},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0c, 0x00, 0x8e, 0x1d, 0xc7,
- 0xff, 0xe3, 0xff, 0xf3, 0xff, 0xff, 0x7f, 0xfe,
- 0x3f, 0xf8, 0x17, 0xf0, 0x03, 0xe0, 0x00, 0x00,},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x82,
- 0x04, 0x41, 0xff, 0xe1, 0x5f, 0xf1, 0x3f, 0xfe,
- 0x17, 0xf0, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00,}
- };
- Cursor skull = {
- {-7,-7},
- {0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xe7, 0xe7,
- 0xff, 0xff, 0xff, 0xff, 0x3f, 0xfc, 0x1f, 0xf8,
- 0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff,
- 0xef, 0xf7, 0xc7, 0xe3, 0x00, 0x00, 0x00, 0x00,},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
- 0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
- 0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
- 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
- };
- Rectangle cntlr; /* control region */
- Rectangle editr; /* editing region */
- Rectangle textr; /* text region */
- Thing *thing;
- Mouse mouse;
- char hex[] = "0123456789abcdefABCDEF";
- jmp_buf err;
- char *file;
- int mag;
- int but1val = 0;
- int but2val = 255;
- int invert = 0;
- Image *values[256];
- Image *greyvalues[256];
- uint8_t data[8192];
- Thing* tget(char*);
- void mesg(char*, ...);
- void drawthing(Thing*, int);
- void select(void);
- void menu(void);
- void error(Display*, char*);
- void buttons(int);
- void drawall(void);
- void tclose1(Thing*);
- void
- main(int argc, char *argv[])
- {
- int i;
- Event e;
- Thing *t;
- mag = Mag;
- if(initdraw(error, 0, "tweak") < 0){
- fprint(2, "tweak: initdraw failed: %r\n");
- exits("initdraw");
- }
- for(i=0; i<256; i++){
- values[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, cmap2rgba(i));
- greyvalues[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, (i<<24)|(i<<16)|(i<<8)|0xFF);
- if(values[i] == 0 || greyvalues[i] == 0)
- drawerror(display, "can't allocate image");
- }
- einit(Emouse|Ekeyboard);
- eresized(0);
- i = 1;
- setjmp(err);
- for(; i<argc; i++){
- file = argv[i];
- t = tget(argv[i]);
- if(t)
- drawthing(t, 1);
- flushimage(display, 1);
- }
- file = 0;
- setjmp(err);
- for(;;)
- switch(event(&e)){
- case Ekeyboard:
- break;
- case Emouse:
- mouse = e.mouse;
- if(mouse.buttons & 3){
- select();
- break;
- }
- if(mouse.buttons & 4)
- menu();
- }
- }
- void
- error(Display *d, char *s)
- {
- if(file)
- mesg("can't read %s: %s: %r", file, s);
- else
- mesg("/dev/bitblt error: %s", s);
- if(err[0])
- longjmp(err, 1);
- exits(s);
- }
- void
- redraw(Thing *t)
- {
- Thing *nt;
- Point p;
- if(thing==0 || thing==t)
- draw(screen, editr, display->white, nil, ZP);
- if(thing == 0)
- return;
- if(thing != t){
- for(nt=thing; nt->next!=t; nt=nt->next)
- ;
- draw(screen, Rect(screen->r.min.x, nt->er.max.y, editr.max.x, editr.max.y),
- display->white, nil, ZP);
- }
- for(nt=t; nt; nt=nt->next){
- drawthing(nt, 0);
- if(nt->next == 0){
- p = Pt(editr.min.x, nt->er.max.y);
- draw(screen, Rpt(p, editr.max), display->white, nil, ZP);
- }
- }
- mesg("");
- }
- void
- eresized(int new)
- {
- if(new && getwindow(display, Refnone) < 0)
- error(display, "can't reattach to window");
- cntlr = insetrect(screen->clipr, 1);
- editr = cntlr;
- textr = editr;
- textr.min.y = textr.max.y - font->height;
- cntlr.max.y = cntlr.min.y + font->height;
- editr.min.y = cntlr.max.y+1;
- editr.max.y = textr.min.y-1;
- draw(screen, screen->clipr, display->white, nil, ZP);
- draw(screen, Rect(editr.min.x, editr.max.y, editr.max.x+1, editr.max.y+1), display->black, nil, ZP);
- replclipr(screen, 0, editr);
- drawall();
- }
- void
- mesgstr(Point p, int line, char *s)
- {
- Rectangle c, r;
- r.min = p;
- r.min.y += line*font->height;
- r.max.y = r.min.y+font->height;
- r.max.x = editr.max.x;
- c = screen->clipr;
- replclipr(screen, 0, r);
- draw(screen, r, values[0xDD], nil, ZP);
- r.min.x++;
- string(screen, r.min, display->black, ZP, font, s);
- replclipr(screen, 0, c);
- flushimage(display, 1);
- }
- void
- mesg(char *fmt, ...)
- {
- char buf[1024];
- va_list arg;
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- mesgstr(textr.min, 0, buf);
- }
- void
- tmesg(Thing *t, int line, char *fmt, ...)
- {
- char buf[1024];
- va_list arg;
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof(buf), fmt, arg);
- va_end(arg);
- mesgstr(t->tr.min, line, buf);
- }
- void
- scntl(char *l)
- {
- sprint(l, "mag: %d but1: %d but2: %d invert-on-copy: %c", mag, but1val, but2val, "ny"[invert]);
- }
- void
- cntl(void)
- {
- char buf[256];
- scntl(buf);
- mesgstr(cntlr.min, 0, buf);
- }
- void
- stext(Thing *t, char *l0, char *l1)
- {
- Fontchar *fc;
- char buf[256];
- l1[0] = 0;
- sprint(buf, "depth:%d r:%d %d %d %d ",
- t->b->depth, t->b->r.min.x, t->b->r.min.y,
- t->b->r.max.x, t->b->r.max.y);
- if(t->parent)
- sprint(buf+strlen(buf), "mag: %d ", t->mag);
- sprint(l0, "%s file: %s", buf, t->name);
- if(t->c >= 0){
- fc = &t->parent->s->info[t->c];
- sprint(l1, "c(hex): %x c(char): %C x: %d "
- "top: %d bottom: %d left: %d width: %d iwidth: %d",
- (int)(t->c+t->parent->off), (int)(t->c+t->parent->off),
- fc->x, fc->top, fc->bottom, fc->left,
- fc->width, Dx(t->b->r));
- }else if(t->s)
- sprint(l1, "offset(hex): %ux n:%d height:%d ascent:%d",
- t->off, t->s->n, t->s->height, t->s->ascent);
- }
- void
- text(Thing *t)
- {
- char l0[256], l1[256];
- stext(t, l0, l1);
- tmesg(t, 0, l0);
- if(l1[0])
- tmesg(t, 1, l1);
- }
- void
- drawall(void)
- {
- Thing *t;
- cntl();
- for(t=thing; t; t=t->next)
- drawthing(t, 0);
- }
- /* imported from libdraw/arith.c to permit an extern log2 function */
- static int log2[] = {
- -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
- -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
- };
- int
- value(Image *b, int x)
- {
- int v, l, w;
- uint8_t mask;
- w = b->depth;
- if(w > 8){
- mesg("ldepth too large");
- return 0;
- }
- l = log2[w];
- mask = (1<<w)-1; /* ones at right end of word */
- x -= b->r.min.x&~(7>>l); /* adjust x relative to first pixel */
- v = data[x>>(3-l)];
- v >>= ((7>>l)<<l) - ((x&(7>>l))<<l); /* pixel at right end of word */
- v &= mask; /* pixel at right end of word */
- return v;
- }
- int
- bvalue(int v, int d)
- {
- v &= (1<<d)-1;
- if(d > screen->depth)
- v >>= d - screen->depth;
- else
- while(d < screen->depth && d < 8){
- v |= v << d;
- d <<= 1;
- }
- if(v<0 || v>255){
- mesg("internal error: bad color");
- return Blue;
- }
- return v;
- }
- void
- drawthing(Thing *nt, int link)
- {
- int nl, nf, i, x, y, sx, sy, fdx, dx, dy, v;
- Thing *t;
- Subfont *s;
- Image *b, *col;
- Point p, p1, p2;
- if(link){
- nt->next = 0;
- if(thing == 0){
- thing = nt;
- y = editr.min.y;
- }else{
- for(t=thing; t->next; t=t->next)
- ;
- t->next = nt;
- y = t->er.max.y;
- }
- }else{
- if(thing == nt)
- y = editr.min.y;
- else{
- for(t=thing; t->next!=nt; t=t->next)
- ;
- y = t->er.max.y;
- }
- }
- s = nt->s;
- b = nt->b;
- nl = font->height;
- if(s || nt->c>=0)
- nl += font->height;
- fdx = Dx(editr) - 2*Border;
- dx = Dx(b->r);
- dy = Dy(b->r);
- if(nt->mag > 1){
- dx *= nt->mag;
- dy *= nt->mag;
- fdx -= fdx%nt->mag;
- }
- nf = 1 + dx/fdx;
- nt->er.min.y = y;
- nt->er.min.x = editr.min.x;
- nt->er.max.x = nt->er.min.x + Border + dx + Border;
- if(nt->er.max.x > editr.max.x)
- nt->er.max.x = editr.max.x;
- nt->er.max.y = nt->er.min.y + Border + nf*(dy+Border);
- nt->r = insetrect(nt->er, Border);
- nt->er.max.x = editr.max.x;
- draw(screen, nt->er, display->white, nil, ZP);
- for(i=0; i<nf; i++){
- p1 = Pt(nt->r.min.x-1, nt->r.min.y+i*(Border+dy));
- /* draw portion of bitmap */
- p = Pt(p1.x+1, p1.y);
- if(nt->mag == 1)
- draw(screen, Rect(p.x, p.y, p.x+fdx+Dx(b->r), p.y+Dy(b->r)),
- b, nil, Pt(b->r.min.x+i*fdx, b->r.min.y));
- else{
- for(y=b->r.min.y; y<b->r.max.y; y++){
- sy = p.y+(y-b->r.min.y)*nt->mag;
- unloadimage(b, Rect(b->r.min.x, y, b->r.max.x, y+1), data, sizeof data);
- for(x=b->r.min.x+i*(fdx/nt->mag); x<b->r.max.x; x++){
- sx = p.x+(x-i*(fdx/nt->mag)-b->r.min.x)*nt->mag;
- if(sx >= nt->r.max.x)
- break;
- v = bvalue(value(b, x), b->depth);
- if(v == 255)
- continue;
- if(b->chan == GREY8)
- draw(screen, Rect(sx, sy, sx+nt->mag, sy+nt->mag),
- greyvalues[v], nil, ZP);
- else
- draw(screen, Rect(sx, sy, sx+nt->mag, sy+nt->mag),
- values[v], nil, ZP);
- }
- }
- }
- /* line down left */
- if(i == 0)
- col = display->black;
- else
- col = display->white;
- draw(screen, Rect(p1.x, p1.y, p1.x+1, p1.y+dy+Border), col, nil, ZP);
- /* line across top */
- draw(screen, Rect(p1.x, p1.y-1, nt->r.max.x+Border, p1.y), display->black, nil, ZP);
- p2 = p1;
- if(i == nf-1){
- p2.x += 1 + dx%fdx;
- col = display->black;
- }else{
- p2.x = nt->r.max.x;
- col = display->white;
- }
- /* line down right */
- draw(screen, Rect(p2.x, p2.y, p2.x+1, p2.y+dy+Border), col, nil, ZP);
- /* line across bottom */
- if(i == nf-1){
- p1.y += Border+dy;
- draw(screen, Rect(p1.x, p1.y-1, p2.x,p1.y), display->black, nil, ZP);
- }
- }
- nt->tr.min.x = editr.min.x;
- nt->tr.max.x = editr.max.x;
- nt->tr.min.y = nt->er.max.y + Border;
- nt->tr.max.y = nt->tr.min.y + nl;
- nt->er.max.y = nt->tr.max.y + Border;
- text(nt);
- }
- int
- tohex(int c)
- {
- if('0'<=c && c<='9')
- return c - '0';
- if('a'<=c && c<='f')
- return 10 + (c - 'a');
- if('A'<=c && c<='F')
- return 10 + (c - 'A');
- return 0;
- }
- Thing*
- tget(char *file)
- {
- int i, j, fd, face, x, y, c, chan;
- Image *b;
- Subfont *s;
- Thing *t;
- Dir *d;
- jmp_buf oerr;
- uint8_t buf[256];
- char *data;
- buf[0] = '\0';
- errstr((char*)buf, sizeof buf); /* flush pending error message */
- memmove(oerr, err, sizeof err);
- d = nil;
- if(setjmp(err)){
- Err:
- free(d);
- memmove(err, oerr, sizeof err);
- return 0;
- }
- fd = open(file, OREAD);
- if(fd < 0){
- mesg("can't open %s: %r", file);
- goto Err;
- }
- d = dirfstat(fd);
- if(d == nil){
- mesg("can't stat bitmap file %s: %r", file);
- close(fd);
- goto Err;
- }
- if(read(fd, buf, 11) != 11){
- mesg("can't read %s: %r", file);
- close(fd);
- goto Err;
- }
- seek(fd, 0, 0);
- data = (char*)buf;
- if(*data == '{')
- data++;
- if(memcmp(data, "0x", 2)==0 && data[4]==','){
- /*
- * cursor file
- */
- face = CURSOR;
- s = 0;
- data = malloc(d->length+1);
- if(data == 0){
- mesg("can't malloc buffer: %r");
- close(fd);
- goto Err;
- }
- data[d->length] = 0;
- if(read(fd, data, d->length) != d->length){
- mesg("can't read cursor file %s: %r", file);
- close(fd);
- goto Err;
- }
- b = allocimage(display, Rect(0, 0, 16, 32), GREY1, 0, DNofill);
- if(b == 0){
- mesg("image alloc failed file %s: %r", file);
- free(data);
- close(fd);
- goto Err;
- }
- i = 0;
- for(x=0;x<64; ){
- if((c=data[i]) == '\0')
- goto ill;
- if(c=='0' && data[i+1] == 'x'){
- i += 2;
- continue;
- }
- if(strchr(hex, c)){
- buf[x++] = (tohex(c)<<4) | tohex(data[i+1]);
- i += 2;
- continue;
- }
- i++;
- }
- loadimage(b, Rect(0, 0, 16, 32), buf, sizeof buf);
- free(data);
- }else if(memcmp(buf, "0x", 2)==0){
- /*
- * face file
- */
- face = FACE;
- s = 0;
- data = malloc(d->length+1);
- if(data == 0){
- mesg("can't malloc buffer: %r");
- close(fd);
- goto Err;
- }
- data[d->length] = 0;
- if(read(fd, data, d->length) != d->length){
- mesg("can't read bitmap file %s: %r", file);
- close(fd);
- goto Err;
- }
- for(y=0,i=0; i<d->length; i++)
- if(data[i] == '\n')
- y++;
- if(y == 0){
- ill:
- mesg("ill-formed face file %s", file);
- close(fd);
- free(data);
- goto Err;
- }
- for(x=0,i=0; (c=data[i])!='\n'; ){
- if(c==',' || c==' ' || c=='\t'){
- i++;
- continue;
- }
- if(c=='0' && data[i+1] == 'x'){
- i += 2;
- continue;
- }
- if(strchr(hex, c)){
- x += 4;
- i++;
- continue;
- }
- goto ill;
- }
- if(x % y)
- goto ill;
- switch(x / y){
- default:
- goto ill;
- case 1:
- chan = GREY1;
- break;
- case 2:
- chan = GREY2;
- break;
- case 4:
- chan = GREY4;
- break;
- case 8:
- chan = CMAP8;
- break;
- }
- b = allocimage(display, Rect(0, 0, y, y), chan, 0, -1);
- if(b == 0){
- mesg("image alloc failed file %s: %r", file);
- free(data);
- close(fd);
- goto Err;
- }
- i = 0;
- for(j=0; j<y; j++){
- for(x=0; (c=data[i])!='\n'; ){
- if(c=='0' && data[i+1] == 'x'){
- i += 2;
- continue;
- }
- if(strchr(hex, c)){
- buf[x++] = ~((tohex(c)<<4) | tohex(data[i+1]));
- i += 2;
- continue;
- }
- i++;
- }
- i++;
- loadimage(b, Rect(0, j, y, j+1), buf, sizeof buf);
- }
- free(data);
- }else{
- face = NORMAL;
- s = 0;
- b = readimage(display, fd, 0);
- if(b == 0){
- mesg("can't read bitmap file %s: %r", file);
- close(fd);
- goto Err;
- }
- if(seek(fd, 0, 1) < d->length)
- s = readsubfonti(display, file, fd, b, 0);
- }
- close(fd);
- t = malloc(sizeof(Thing));
- if(t == 0){
- nomem:
- mesg("malloc failed: %r");
- if(s)
- freesubfont(s);
- else
- freeimage(b);
- goto Err;
- }
- t->name = strdup(file);
- if(t->name == 0){
- free(t);
- goto nomem;
- }
- t->b = b;
- t->s = s;
- t->face = face;
- t->mod = 0;
- t->parent = 0;
- t->c = -1;
- t->mag = 1;
- t->off = 0;
- memmove(err, oerr, sizeof err);
- return t;
- }
- int
- atline(int x, Point p, char *line, char *buf)
- {
- char *s, *c, *word, *hit;
- int w, wasblank;
- Rune r;
- wasblank = 1;
- hit = 0;
- word = 0;
- for(s=line; *s; s+=w){
- w = chartorune(&r, s);
- x += runestringnwidth(font, &r, 1);
- if(wasblank && r!=' ')
- word = s;
- wasblank = 0;
- if(r == ' '){
- if(x >= p.x)
- break;
- wasblank = 1;
- }
- if(r == ':')
- hit = word;
- }
- if(x < p.x)
- return 0;
- c = utfrune(hit, ':');
- strncpy(buf, hit, c-hit);
- buf[c-hit] = 0;
- return 1;
- }
- int
- attext(Thing *t, Point p, char *buf)
- {
- char l0[256], l1[256];
- if(!ptinrect(p, t->tr))
- return 0;
- stext(t, l0, l1);
- if(p.y < t->tr.min.y+font->height)
- return atline(t->r.min.x, p, l0, buf);
- else
- return atline(t->r.min.x, p, l1, buf);
- }
- int
- type(char *buf, char *tag)
- {
- Rune r;
- char *p;
- esetcursor(&busy);
- p = buf;
- for(;;){
- *p = 0;
- mesg("%s: %s", tag, buf);
- r = ekbd();
- switch(r){
- case '\n':
- mesg("");
- esetcursor(0);
- return p-buf;
- case 0x15: /* control-U */
- p = buf;
- break;
- case '\b':
- if(p > buf)
- --p;
- break;
- default:
- p += runetochar(p, &r);
- }
- }
- }
- void
- textedit(Thing *t, char *tag)
- {
- char buf[256];
- char *s;
- Image *b;
- Subfont *f;
- Fontchar *fc, *nfc;
- Rectangle r;
- uint32_t chan;
- int i, ld, d, w, c, doredraw, fdx, x;
- Thing *nt;
- buttons(Up);
- if(type(buf, tag) == 0)
- return;
- if(strcmp(tag, "file") == 0){
- for(s=buf; *s; s++)
- if(*s <= ' '){
- mesg("illegal file name");
- return;
- }
- if(strcmp(t->name, buf) != 0){
- if(t->parent)
- t->parent->mod = 1;
- else
- t->mod = 1;
- }
- for(nt=thing; nt; nt=nt->next)
- if(t==nt || t->parent==nt || nt->parent==t){
- free(nt->name);
- nt->name = strdup(buf);
- if(nt->name == 0){
- mesg("malloc failed: %r");
- return;
- }
- text(nt);
- }
- return;
- }
- if(strcmp(tag, "depth") == 0){
- if(buf[0]<'0' || '9'<buf[0] || (d=atoi(buf))<0 || d>8 || log2[d]<0){
- mesg("illegal ldepth");
- return;
- }
- if(d == t->b->depth)
- return;
- if(t->parent)
- t->parent->mod = 1;
- else
- t->mod = 1;
- if(d == 8)
- chan = CMAP8;
- else
- chan = CHAN1(CGrey, d);
- for(nt=thing; nt; nt=nt->next){
- if(nt!=t && nt!=t->parent && nt->parent!=t)
- continue;
- b = allocimage(display, nt->b->r, chan, 0, 0);
- if(b == 0){
- nobmem:
- mesg("image alloc failed: %r");
- return;
- }
- draw(b, b->r, nt->b, nil, nt->b->r.min);
- freeimage(nt->b);
- nt->b = b;
- if(nt->s){
- b = allocimage(display, nt->b->r, chan, 0, -1);
- if(b == 0)
- goto nobmem;
- draw(b, b->r, nt->b, nil, nt->b->r.min);
- f = allocsubfont(t->name, nt->s->n, nt->s->height, nt->s->ascent, nt->s->info, b);
- if(f == 0){
- nofmem:
- freeimage(b);
- mesg("can't make subfont: %r");
- return;
- }
- nt->s->info = 0; /* prevent it being freed */
- nt->s->bits = 0;
- freesubfont(nt->s);
- nt->s = f;
- }
- drawthing(nt, 0);
- }
- return;
- }
- if(strcmp(tag, "mag") == 0){
- if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<=0 || ld>Maxmag){
- mesg("illegal magnification");
- return;
- }
- if(t->mag == ld)
- return;
- t->mag = ld;
- redraw(t);
- return;
- }
- if(strcmp(tag, "r") == 0){
- if(t->s){
- mesg("can't change rectangle of subfont\n");
- return;
- }
- s = buf;
- r.min.x = strtoul(s, &s, 0);
- r.min.y = strtoul(s, &s, 0);
- r.max.x = strtoul(s, &s, 0);
- r.max.y = strtoul(s, &s, 0);
- if(Dx(r)<=0 || Dy(r)<=0){
- mesg("illegal rectangle");
- return;
- }
- if(t->parent)
- t = t->parent;
- for(nt=thing; nt; nt=nt->next){
- if(nt->parent==t && !rectinrect(nt->b->r, r))
- tclose1(nt);
- }
- b = allocimage(display, r, t->b->chan, 0, 0);
- if(b == 0)
- goto nobmem;
- draw(b, r, t->b, nil, r.min);
- freeimage(t->b);
- t->b = b;
- b = allocimage(display, r, t->b->chan, 0, 0);
- if(b == 0)
- goto nobmem;
- redraw(t);
- t->mod = 1;
- return;
- }
- if(strcmp(tag, "ascent") == 0){
- if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0 || ld>t->s->height){
- mesg("illegal ascent");
- return;
- }
- if(t->s->ascent == ld)
- return;
- t->s->ascent = ld;
- text(t);
- t->mod = 1;
- return;
- }
- if(strcmp(tag, "height") == 0){
- if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0){
- mesg("illegal height");
- return;
- }
- if(t->s->height == ld)
- return;
- t->s->height = ld;
- text(t);
- t->mod = 1;
- return;
- }
- if(strcmp(tag, "left")==0 || strcmp(tag, "width") == 0){
- if(buf[0]<'0' || '9'<buf[0] || (ld=atoi(buf))<0){
- mesg("illegal value");
- return;
- }
- fc = &t->parent->s->info[t->c];
- if(strcmp(tag, "left")==0){
- if(fc->left == ld)
- return;
- fc->left = ld;
- }else{
- if(fc->width == ld)
- return;
- fc->width = ld;
- }
- text(t);
- t->parent->mod = 1;
- return;
- }
- if(strcmp(tag, "offset(hex)") == 0){
- if(!strchr(hex, buf[0])){
- illoff:
- mesg("illegal offset");
- return;
- }
- s = 0;
- ld = strtoul(buf, &s, 16);
- if(*s)
- goto illoff;
- t->off = ld;
- text(t);
- for(nt=thing; nt; nt=nt->next)
- if(nt->parent == t)
- text(nt);
- return;
- }
- if(strcmp(tag, "n") == 0){
- if(buf[0]<'0' || '9'<buf[0] || (w=atoi(buf))<=0){
- mesg("illegal n");
- return;
- }
- f = t->s;
- if(w == f->n)
- return;
- doredraw = 0;
- again:
- for(nt=thing; nt; nt=nt->next)
- if(nt->parent == t){
- doredraw = 1;
- tclose1(nt);
- goto again;
- }
- r = t->b->r;
- if(w < f->n)
- r.max.x = f->info[w].x;
- b = allocimage(display, r, t->b->chan, 0, 0);
- if(b == 0)
- goto nobmem;
- draw(b, b->r, t->b, nil, r.min);
- fdx = Dx(editr) - 2*Border;
- if(Dx(t->b->r)/fdx != Dx(b->r)/fdx)
- doredraw = 1;
- freeimage(t->b);
- t->b = b;
- b = allocimage(display, r, t->b->chan, 0, 0);
- if(b == 0)
- goto nobmem;
- draw(b, b->r, t->b, nil, r.min);
- nfc = malloc((w+1)*sizeof(Fontchar));
- if(nfc == 0){
- mesg("malloc failed");
- freeimage(b);
- return;
- }
- fc = f->info;
- for(i=0; i<=w && i<=f->n; i++)
- nfc[i] = fc[i];
- if(w+1 < i)
- memset(nfc+i, 0, ((w+1)-i)*sizeof(Fontchar));
- x = fc[f->n].x;
- for(; i<=w; i++)
- nfc[i].x = x;
- f = allocsubfont(t->name, w, f->height, f->ascent, nfc, b);
- if(f == 0)
- goto nofmem;
- t->s->bits = nil; /* don't free it */
- freesubfont(t->s);
- f->info = nfc;
- t->s = f;
- if(doredraw)
- redraw(thing);
- else
- drawthing(t, 0);
- t->mod = 1;
- return;
- }
- if(strcmp(tag, "iwidth") == 0){
- if(buf[0]<'0' || '9'<buf[0] || (w=atoi(buf))<0){
- mesg("illegal iwidth");
- return;
- }
- w -= Dx(t->b->r);
- if(w == 0)
- return;
- r = t->parent->b->r;
- r.max.x += w;
- c = t->c;
- t = t->parent;
- f = t->s;
- b = allocimage(display, r, t->b->chan, 0, 0);
- if(b == 0)
- goto nobmem;
- fc = &f->info[c];
- draw(b, Rect(b->r.min.x, b->r.min.y,
- b->r.min.x+(fc[1].x-t->b->r.min.x), b->r.min.y+Dy(t->b->r)),
- t->b, nil, t->b->r.min);
- draw(b, Rect(fc[1].x+w, b->r.min.y, w+t->b->r.max.x, b->r.min.y+Dy(t->b->r)),
- t->b, nil, Pt(fc[1].x, t->b->r.min.y));
- fdx = Dx(editr) - 2*Border;
- doredraw = 0;
- if(Dx(t->b->r)/fdx != Dx(b->r)/fdx)
- doredraw = 1;
- freeimage(t->b);
- t->b = b;
- b = allocimage(display, r, t->b->chan, 0, 0);
- if(b == 0)
- goto nobmem;
- draw(b, b->r, t->b, nil, t->b->r.min);
- fc = &f->info[c+1];
- for(i=c+1; i<=f->n; i++, fc++)
- fc->x += w;
- f = allocsubfont(t->name, f->n, f->height, f->ascent,
- f->info, b);
- if(f == 0)
- goto nofmem;
- /* t->s and f share info; free carefully */
- fc = f->info;
- t->s->bits = nil;
- t->s->info = 0;
- freesubfont(t->s);
- f->info = fc;
- t->s = f;
- if(doredraw)
- redraw(t);
- else
- drawthing(t, 0);
- /* redraw all affected chars */
- for(nt=thing; nt; nt=nt->next){
- if(nt->parent!=t || nt->c<c)
- continue;
- fc = &f->info[nt->c];
- r.min.x = fc[0].x;
- r.min.y = nt->b->r.min.y;
- r.max.x = fc[1].x;
- r.max.y = nt->b->r.max.y;
- b = allocimage(display, r, nt->b->chan, 0, 0);
- if(b == 0)
- goto nobmem;
- draw(b, r, t->b, nil, r.min);
- doredraw = 0;
- if(Dx(nt->b->r)/fdx != Dx(b->r)/fdx)
- doredraw = 1;
- freeimage(nt->b);
- nt->b = b;
- if(c != nt->c)
- text(nt);
- else{
- if(doredraw)
- redraw(nt);
- else
- drawthing(nt, 0);
- }
- }
- t->mod = 1;
- return;
- }
- mesg("cannot edit %s in file %s", tag, t->name);
- }
- void
- cntledit(char *tag)
- {
- char buf[256];
- int32_t l;
- buttons(Up);
- if(type(buf, tag) == 0)
- return;
- if(strcmp(tag, "mag") == 0){
- if(buf[0]<'0' || '9'<buf[0] || (l=atoi(buf))<=0 || l>Maxmag){
- mesg("illegal magnification");
- return;
- }
- mag = l;
- cntl();
- return;
- }
- if(strcmp(tag, "but1")==0
- || strcmp(tag, "but2")==0){
- if(buf[0]<'0' || '9'<buf[0] || (l=atoi(buf))<0 || l>255){
- mesg("illegal value");
- return;
- }
- if(strcmp(tag, "but1") == 0)
- but1val = l;
- else if(strcmp(tag, "but2") == 0)
- but2val = l;
- cntl();
- return;
- }
- if(strcmp(tag, "invert-on-copy")==0){
- if(buf[0]=='y' || buf[0]=='1')
- invert = 1;
- else if(buf[0]=='n' || buf[0]=='0')
- invert = 0;
- else{
- mesg("illegal value");
- return;
- }
- cntl();
- return;
- }
- mesg("cannot edit %s", tag);
- }
- void
- buttons(int ud)
- {
- while((mouse.buttons==0) != ud)
- mouse = emouse();
- }
- Point
- screenpt(Thing *t, Point realp)
- {
- int fdx, n;
- Point p;
- fdx = Dx(editr)-2*Border;
- if(t->mag > 1)
- fdx -= fdx%t->mag;
- p = mulpt(subpt(realp, t->b->r.min), t->mag);
- if(fdx < Dx(t->b->r)*t->mag){
- n = p.x/fdx;
- p.y += n * (Dy(t->b->r)*t->mag+Border);
- p.x -= n * fdx;
- }
- p = addpt(p, t->r.min);
- return p;
- }
- Point
- realpt(Thing *t, Point screenp)
- {
- int fdx, n, dy;
- Point p;
- fdx = (Dx(editr)-2*Border);
- if(t->mag > 1)
- fdx -= fdx%t->mag;
- p.y = screenp.y-t->r.min.y;
- p.x = 0;
- if(fdx < Dx(t->b->r)*t->mag){
- dy = Dy(t->b->r)*t->mag+Border;
- n = (p.y/dy);
- p.x = n * fdx;
- p.y -= n * dy;
- }
- p.x += screenp.x-t->r.min.x;
- p = addpt(divpt(p, t->mag), t->b->r.min);
- return p;
- }
- int
- sweep(int but, Rectangle *r)
- {
- Thing *t;
- Point p, q, lastq;
- esetcursor(&sweep0);
- buttons(Down);
- if(mouse.buttons != (1<<(but-1))){
- buttons(Up);
- esetcursor(0);
- return 0;
- }
- p = mouse.xy;
- for(t=thing; t; t=t->next)
- if(ptinrect(p, t->r))
- break;
- if(t)
- p = screenpt(t, realpt(t, p));
- r->min = p;
- r->max = p;
- esetcursor(&box);
- lastq = ZP;
- while(mouse.buttons == (1<<(but-1))){
- edrawgetrect(insetrect(*r, -Borderwidth), 1);
- mouse = emouse();
- edrawgetrect(insetrect(*r, -Borderwidth), 0);
- q = mouse.xy;
- if(t)
- q = screenpt(t, realpt(t, q));
- if(eqpt(q, lastq))
- continue;
- *r = canonrect(Rpt(p, q));
- lastq = q;
- }
- esetcursor(0);
- if(mouse.buttons){
- buttons(Up);
- return 0;
- }
- return 1;
- }
- void
- openedit(Thing *t, Point pt, int c)
- {
- int x, y;
- Point p;
- Rectangle r;
- Rectangle br;
- Fontchar *fc;
- Thing *nt;
- if(t->b->depth > 8){
- mesg("image has depth %d; can't handle >8", t->b->depth);
- return;
- }
- br = t->b->r;
- if(t->s == 0){
- c = -1;
- /* if big enough to bother, sweep box */
- if(Dx(br)<=16 && Dy(br)<=16)
- r = br;
- else{
- if(!sweep(1, &r))
- return;
- r = rectaddpt(r, subpt(br.min, t->r.min));
- if(!rectclip(&r, br))
- return;
- if(Dx(br) <= 8){
- r.min.x = br.min.x;
- r.max.x = br.max.x;
- }else if(Dx(r) < 4){
- toosmall:
- mesg("rectangle too small");
- return;
- }
- if(Dy(br) <= 8){
- r.min.y = br.min.y;
- r.max.y = br.max.y;
- }else if(Dy(r) < 4)
- goto toosmall;
- }
- }else if(c >= 0){
- fc = &t->s->info[c];
- r.min.x = fc[0].x;
- r.min.y = br.min.y;
- r.max.x = fc[1].x;
- r.max.y = br.min.y + Dy(br);
- }else{
- /* just point at character */
- fc = t->s->info;
- p = addpt(pt, subpt(br.min, t->r.min));
- x = br.min.x;
- y = br.min.y;
- for(c=0; c<t->s->n; c++,fc++){
- again:
- r.min.x = x;
- r.min.y = y;
- r.max.x = x + fc[1].x - fc[0].x;
- r.max.y = y + Dy(br);
- if(ptinrect(p, r))
- goto found;
- if(r.max.x >= br.min.x+Dx(t->r)){
- x -= Dx(t->r);
- y += t->s->height;
- if(fc[1].x > fc[0].x)
- goto again;
- }
- x += fc[1].x - fc[0].x;
- }
- return;
- found:
- r = br;
- r.min.x = fc[0].x;
- r.max.x = fc[1].x;
- }
- nt = malloc(sizeof(Thing));
- if(nt == 0){
- nomem:
- mesg("can't allocate: %r");
- return;
- }
- memset(nt, 0, sizeof(Thing));
- nt->c = c;
- nt->b = allocimage(display, r, t->b->chan, 0, DNofill);
- if(nt->b == 0){
- free(nt);
- goto nomem;
- }
- draw(nt->b, r, t->b, nil, r.min);
- nt->name = strdup(t->name);
- if(nt->name == 0){
- freeimage(nt->b);
- free(nt);
- goto nomem;
- }
- nt->parent = t;
- nt->mag = mag;
- drawthing(nt, 1);
- }
- void
- ckinfo(Thing *t, Rectangle mod)
- {
- int i, j, k, top, bot, n, zero;
- Fontchar *fc;
- Rectangle r;
- Image *b;
- Thing *nt;
- if(t->parent)
- t = t->parent;
- if(t->s==0 || Dy(t->b->r)==0)
- return;
- b = 0;
- /* check bounding boxes */
- fc = &t->s->info[0];
- r.min.y = t->b->r.min.y;
- r.max.y = t->b->r.max.y;
- for(i=0; i<t->s->n; i++, fc++){
- r.min.x = fc[0].x;
- r.max.x = fc[1].x;
- if(!rectXrect(mod, r))
- continue;
- if(b==0 || Dx(b->r)<Dx(r)){
- if(b)
- freeimage(b);
- b = allocimage(display, rectsubpt(r, r.min), t->b->chan, 0, 0);
- if(b == 0){
- mesg("can't alloc image");
- break;
- }
- }
- draw(b, b->r, display->white, nil, ZP);
- draw(b, b->r, t->b, nil, r.min);
- top = 100000;
- bot = 0;
- n = 2+((Dx(r)/8)*t->b->depth);
- for(j=0; j<b->r.max.y; j++){
- memset(data, 0, n);
- unloadimage(b, Rect(b->r.min.x, j, b->r.max.x, j+1), data, sizeof data);
- zero = 1;
- for(k=0; k<n; k++)
- if(data[k]){
- zero = 0;
- break;
- }
- if(!zero){
- if(top > j)
- top = j;
- bot = j+1;
- }
- }
- if(top > j)
- top = 0;
- if(top!=fc->top || bot!=fc->bottom){
- fc->top = top;
- fc->bottom = bot;
- for(nt=thing; nt; nt=nt->next)
- if(nt->parent==t && nt->c==i)
- text(nt);
- }
- }
- if(b)
- freeimage(b);
- }
- void
- twidpix(Thing *t, Point p, int set)
- {
- Image *b, *v;
- int c;
- b = t->b;
- if(!ptinrect(p, b->r))
- return;
- if(set)
- c = but1val;
- else
- c = but2val;
- if(b->chan == GREY8)
- v = greyvalues[c];
- else
- v = values[c];
- draw(b, Rect(p.x, p.y, p.x+1, p.y+1), v, nil, ZP);
- p = screenpt(t, p);
- draw(screen, Rect(p.x, p.y, p.x+t->mag, p.y+t->mag), v, nil, ZP);
- }
- void
- twiddle(Thing *t)
- {
- int set;
- Point p, lastp;
- Image *b;
- Thing *nt;
- Rectangle mod;
- if(mouse.buttons!=1 && mouse.buttons!=2){
- buttons(Up);
- return;
- }
- set = mouse.buttons==1;
- b = t->b;
- lastp = addpt(b->r.min, Pt(-1, -1));
- mod = Rpt(addpt(b->r.max, Pt(1, 1)), lastp);
- while(mouse.buttons){
- p = realpt(t, mouse.xy);
- if(!eqpt(p, lastp)){
- lastp = p;
- if(ptinrect(p, b->r)){
- for(nt=thing; nt; nt=nt->next)
- if(nt->parent==t->parent || nt==t->parent)
- twidpix(nt, p, set);
- if(t->parent)
- t->parent->mod = 1;
- else
- t->mod = 1;
- if(p.x < mod.min.x)
- mod.min.x = p.x;
- if(p.y < mod.min.y)
- mod.min.y = p.y;
- if(p.x >= mod.max.x)
- mod.max.x = p.x+1;
- if(p.y >= mod.max.y)
- mod.max.y = p.y+1;
- }
- }
- mouse = emouse();
- }
- ckinfo(t, mod);
- }
- void
- select(void)
- {
- Thing *t;
- char line[128], buf[128];
- Point p;
- if(ptinrect(mouse.xy, cntlr)){
- scntl(line);
- if(atline(cntlr.min.x, mouse.xy, line, buf)){
- if(mouse.buttons == 1)
- cntledit(buf);
- else
- buttons(Up);
- return;
- }
- return;
- }
- for(t=thing; t; t=t->next){
- if(attext(t, mouse.xy, buf)){
- if(mouse.buttons == 1)
- textedit(t, buf);
- else
- buttons(Up);
- return;
- }
- if(ptinrect(mouse.xy, t->r)){
- if(t->parent == 0){
- if(mouse.buttons == 1){
- p = mouse.xy;
- buttons(Up);
- openedit(t, p, -1);
- }else
- buttons(Up);
- return;
- }
- twiddle(t);
- return;
- }
- }
- }
- void
- twrite(Thing *t)
- {
- int i, j, x, y, fd, ws, ld;
- Biobuf buf;
- Rectangle r;
- if(t->parent)
- t = t->parent;
- esetcursor(&busy);
- fd = create(t->name, OWRITE, 0666);
- if(fd < 0){
- mesg("can't write %s: %r", t->name);
- return;
- }
- if(t->face && t->b->depth <= 4){
- r = t->b->r;
- ld = log2[t->b->depth];
- /* This heuristic reflects peculiarly different formats */
- ws = 4;
- if(t->face == 2) /* cursor file */
- ws = 1;
- else if(Dx(r)<32 || ld==0)
- ws = 2;
- Binit(&buf, fd, OWRITE);
- if(t->face == CURSOR)
- Bprint(&buf, "{");
- for(y=r.min.y; y<r.max.y; y++){
- unloadimage(t->b, Rect(r.min.x, y, r.max.x, y+1), data, sizeof data);
- j = 0;
- for(x=r.min.x; x<r.max.x; j+=ws,x+=ws*8>>ld){
- Bprint(&buf, "0x");
- for(i=0; i<ws; i++)
- Bprint(&buf, "%.2x", data[i+j]);
- Bprint(&buf, ", ");
- }
- if(t->face == CURSOR){
- switch(y){
- case 3: case 7: case 11: case 19: case 23: case 27:
- Bprint(&buf, "\n ");
- break;
- case 15:
- Bprint(&buf, "},\n{");
- break;
- case 31:
- Bprint(&buf, "}\n");
- break;
- }
- }else
- Bprint(&buf, "\n");
- }
- Bterm(&buf);
- }else
- if(writeimage(fd, t->b, 0)<0 || (t->s && writesubfont(fd, t->s)<0)){
- close(fd);
- mesg("can't write %s: %r", t->name);
- }
- t->mod = 0;
- close(fd);
- mesg("wrote %s", t->name);
- }
- void
- tpixels(void)
- {
- Thing *t;
- Point p, lastp;
- esetcursor(&pixel);
- for(;;){
- buttons(Down);
- if(mouse.buttons != 4)
- break;
- for(t=thing; t; t=t->next){
- lastp = Pt(-1, -1);
- if(ptinrect(mouse.xy, t->r)){
- while(ptinrect(mouse.xy, t->r) && mouse.buttons==4){
- p = realpt(t, mouse.xy);
- if(!eqpt(p, lastp)){
- if(p.y != lastp.y)
- unloadimage(t->b, Rect(t->b->r.min.x, p.y, t->b->r.max.x, p.y+1), data, sizeof data);
- mesg("[%d,%d] = %d=0x%ux", p.x, p.y, value(t->b, p.x), value(t->b, p.x));
- lastp = p;
- }
- mouse = emouse();
- }
- goto Continue;
- }
- }
- mouse = emouse();
- Continue:;
- }
- buttons(Up);
- esetcursor(0);
- }
- void
- tclose1(Thing *t)
- {
- Thing *nt;
- if(t == thing)
- thing = t->next;
- else{
- for(nt=thing; nt->next!=t; nt=nt->next)
- ;
- nt->next = t->next;
- }
- do
- for(nt=thing; nt; nt=nt->next)
- if(nt->parent == t){
- tclose1(nt);
- break;
- }
- while(nt);
- if(t->s)
- freesubfont(t->s);
- else
- freeimage(t->b);
- free(t->name);
- free(t);
- }
- void
- tclose(Thing *t)
- {
- Thing *ct;
- if(t->mod){
- mesg("%s modified", t->name);
- t->mod = 0;
- return;
- }
- /* fiddle to save redrawing unmoved things */
- if(t == thing)
- ct = 0;
- else
- for(ct=thing; ct; ct=ct->next)
- if(ct->next==t || ct->next->parent==t)
- break;
- tclose1(t);
- if(ct)
- ct = ct->next;
- else
- ct = thing;
- redraw(ct);
- }
- void
- tread(Thing *t)
- {
- Thing *nt, *new;
- Fontchar *i;
- Rectangle r;
- int nclosed;
- if(t->parent)
- t = t->parent;
- new = tget(t->name);
- if(new == 0)
- return;
- nclosed = 0;
- again:
- for(nt=thing; nt; nt=nt->next)
- if(nt->parent == t){
- if(!rectinrect(nt->b->r, new->b->r)
- || new->b->depth!=nt->b->depth){
- closeit:
- nclosed++;
- nt->parent = 0;
- tclose1(nt);
- goto again;
- }
- if((t->s==0) != (new->s==0))
- goto closeit;
- if((t->face==0) != (new->face==0))
- goto closeit;
- if(t->s){ /* check same char */
- if(nt->c >= new->s->n)
- goto closeit;
- i = &new->s->info[nt->c];
- r.min.x = i[0].x;
- r.max.x = i[1].x;
- r.min.y = new->b->r.min.y;
- r.max.y = new->b->r.max.y;
- if(!eqrect(r, nt->b->r))
- goto closeit;
- }
- nt->parent = new;
- draw(nt->b, nt->b->r, new->b, nil, nt->b->r.min);
- }
- new->next = t->next;
- if(t == thing)
- thing = new;
- else{
- for(nt=thing; nt->next!=t; nt=nt->next)
- ;
- nt->next = new;
- }
- if(t->s)
- freesubfont(t->s);
- else
- freeimage(t->b);
- free(t->name);
- free(t);
- for(nt=thing; nt; nt=nt->next)
- if(nt==new || nt->parent==new)
- if(nclosed == 0)
- drawthing(nt, 0); /* can draw in place */
- else{
- redraw(nt); /* must redraw all below */
- break;
- }
- }
- void
- tchar(Thing *t)
- {
- char buf[256], *p;
- Rune r;
- uint32_t c, d;
- if(t->s == 0){
- t = t->parent;
- if(t==0 || t->s==0){
- mesg("not a subfont");
- return;
- }
- }
- if(type(buf, "char (hex or character or hex-hex)") == 0)
- return;
- if(utflen(buf) == 1){
- chartorune(&r, buf);
- c = r;
- d = r;
- }else{
- if(!strchr(hex, buf[0])){
- mesg("illegal hex character");
- return;
- }
- c = strtoul(buf, 0, 16);
- d = c;
- p = utfrune(buf, '-');
- if(p){
- d = strtoul(p+1, 0, 16);
- if(d < c){
- mesg("invalid range");
- return;
- }
- }
- }
- c -= t->off;
- d -= t->off;
- while(c <= d){
- if(c>=t->s->n){
- mesg("0x%lux not in font %s", c+t->off, t->name);
- return;
- }
- openedit(t, Pt(0, 0), c);
- c++;
- }
- }
- void
- apply(void (*f)(Thing*))
- {
- Thing *t;
- esetcursor(&sight);
- buttons(Down);
- if(mouse.buttons == 4)
- for(t=thing; t; t=t->next)
- if(ptinrect(mouse.xy, t->er)){
- buttons(Up);
- f(t);
- break;
- }
- buttons(Up);
- esetcursor(0);
- }
- int
- complement(Image *t)
- {
- int i, n;
- uint8_t *buf;
- n = Dy(t->r)*bytesperline(t->r, t->depth);
- buf = malloc(n);
- if(buf == 0)
- return 0;
- unloadimage(t, t->r, buf, n);
- for(i=0; i<n; i++)
- buf[i] = ~buf[i];
- loadimage(t, t->r, buf, n);
- free(buf);
- return 1;
- }
- void
- copy(void)
- {
- Thing *st, *dt, *nt;
- Rectangle sr, dr, fr;
- Image *tmp;
- Point p1, p2;
- int but, up;
- if(!sweep(3, &sr))
- return;
- for(st=thing; st; st=st->next)
- if(rectXrect(sr, st->r))
- break;
- if(st == 0)
- return;
- /* click gives full rectangle */
- if(Dx(sr)<4 && Dy(sr)<4)
- sr = st->r;
- rectclip(&sr, st->r);
- p1 = realpt(st, sr.min);
- p2 = realpt(st, Pt(sr.min.x, sr.max.y));
- up = 0;
- if(p1.x != p2.x){ /* swept across a fold */
- onafold:
- mesg("sweep spans a fold");
- goto Return;
- }
- p2 = realpt(st, sr.max);
- sr.min = p1;
- sr.max = p2;
- fr.min = screenpt(st, sr.min);
- fr.max = screenpt(st, sr.max);
- p1 = subpt(p2, p1); /* diagonal */
- if(p1.x==0 || p1.y==0)
- return;
- border(screen, fr, -1, values[Blue], ZP);
- esetcursor(&box);
- for(; mouse.buttons==0; mouse=emouse()){
- for(dt=thing; dt; dt=dt->next)
- if(ptinrect(mouse.xy, dt->er))
- break;
- if(up)
- edrawgetrect(insetrect(dr, -Borderwidth), 0);
- up = 0;
- if(dt == 0)
- continue;
- dr.max = screenpt(dt, realpt(dt, mouse.xy));
- dr.min = subpt(dr.max, mulpt(p1, dt->mag));
- if(!rectXrect(dr, dt->r))
- continue;
- edrawgetrect(insetrect(dr, -Borderwidth), 1);
- up = 1;
- }
- /* if up==1, we had a hit */
- esetcursor(0);
- if(up)
- edrawgetrect(insetrect(dr, -Borderwidth), 0);
- but = mouse.buttons;
- buttons(Up);
- if(!up || but!=4)
- goto Return;
- dt = 0;
- for(nt=thing; nt; nt=nt->next)
- if(rectXrect(dr, nt->r)){
- if(dt){
- mesg("ambiguous sweep");
- return;
- }
- dt = nt;
- }
- if(dt == 0)
- goto Return;
- p1 = realpt(dt, dr.min);
- p2 = realpt(dt, Pt(dr.min.x, dr.max.y));
- if(p1.x != p2.x)
- goto onafold;
- p2 = realpt(dt, dr.max);
- dr.min = p1;
- dr.max = p2;
- if(invert){
- tmp = allocimage(display, dr, dt->b->chan, 0, 255);
- if(tmp == 0){
- nomem:
- mesg("can't allocate temporary");
- goto Return;
- }
- draw(tmp, dr, st->b, nil, sr.min);
- if(!complement(tmp))
- goto nomem;
- draw(dt->b, dr, tmp, nil, dr.min);
- freeimage(tmp);
- }else
- draw(dt->b, dr, st->b, nil, sr.min);
- if(dt->parent){
- draw(dt->parent->b, dr, dt->b, nil, dr.min);
- dt = dt->parent;
- }
- drawthing(dt, 0);
- for(nt=thing; nt; nt=nt->next)
- if(nt->parent==dt && rectXrect(dr, nt->b->r)){
- draw(nt->b, dr, dt->b, nil, dr.min);
- drawthing(nt, 0);
- }
- ckinfo(dt, dr);
- dt->mod = 1;
- Return:
- /* clear blue box */
- drawthing(st, 0);
- }
- void
- menu(void)
- {
- Thing *t;
- char *mod;
- int sel;
- char buf[256];
- sel = emenuhit(3, &mouse, &menu3);
- switch(sel){
- case Mopen:
- if(type(buf, "file")){
- t = tget(buf);
- if(t)
- drawthing(t, 1);
- }
- break;
- case Mwrite:
- apply(twrite);
- break;
- case Mread:
- apply(tread);
- break;
- case Mchar:
- apply(tchar);
- break;
- case Mcopy:
- copy();
- break;
- case Mpixels:
- tpixels();
- break;
- case Mclose:
- apply(tclose);
- break;
- case Mexit:
- mod = 0;
- for(t=thing; t; t=t->next)
- if(t->mod){
- mod = t->name;
- t->mod = 0;
- }
- if(mod){
- mesg("%s modified", mod);
- break;
- }
- esetcursor(&skull);
- buttons(Down);
- if(mouse.buttons == 4){
- buttons(Up);
- exits(0);
- }
- buttons(Up);
- esetcursor(0);
- break;
- }
- }
|