2004-04-19 05:54:21 +00:00
|
|
|
#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 */
|
|
|
|
long 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[] = {
|
2004-04-20 01:13:04 +00:00
|
|
|
"open",
|
|
|
|
"read",
|
|
|
|
"write",
|
|
|
|
"copy",
|
|
|
|
"char",
|
|
|
|
"pixels",
|
|
|
|
"close",
|
|
|
|
"exit",
|
2004-04-19 05:54:21 +00:00
|
|
|
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];
|
|
|
|
uchar data[8192];
|
|
|
|
|
|
|
|
Thing* tget(char*);
|
|
|
|
void mesg(char*, ...);
|
|
|
|
void drawthing(Thing*, int);
|
|
|
|
void xselect(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){
|
|
|
|
xselect();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(mouse.buttons & 4)
|
|
|
|
menu();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
xlog2(int n)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; (1<<i) <= n; i++)
|
|
|
|
if((1<<i) == n)
|
|
|
|
return i;
|
|
|
|
fprint(2, "log2 %d = 0\n", n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
error(Display *d, char *s)
|
|
|
|
{
|
|
|
|
USED(d);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
value(Image *b, int x)
|
|
|
|
{
|
|
|
|
int v, l, w;
|
|
|
|
uchar mask;
|
|
|
|
|
|
|
|
w = b->depth;
|
|
|
|
if(w > 8){
|
|
|
|
mesg("ldepth too large");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
l = xlog2(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 n, 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;
|
|
|
|
if((n=unloadimage(b, Rect(b->r.min.x, y, b->r.max.x, y+1), data, sizeof data)) < 0)
|
|
|
|
fprint(2, "unloadimage: %r\n");
|
|
|
|
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;
|
|
|
|
uchar 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0; /* shut up compiler */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
textedit(Thing *t, char *tag)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
char *s;
|
|
|
|
Image *b;
|
|
|
|
Subfont *f;
|
|
|
|
Fontchar *fc, *nfc;
|
|
|
|
Rectangle r;
|
|
|
|
ulong 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 || xlog2(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];
|
|
|
|
ulong 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
|
|
|
|
xselect(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 = xlog2(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;
|
|
|
|
ulong 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<0 || 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;
|
|
|
|
uchar *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;
|
|
|
|
}
|
|
|
|
}
|