added sprite editor spred
This commit is contained in:
parent
555a05018b
commit
712fd30652
11 changed files with 1895 additions and 0 deletions
58
sys/man/1/spred
Normal file
58
sys/man/1/spred
Normal file
|
@ -0,0 +1,58 @@
|
|||
b.TH SPRED 1
|
||||
.SH NAME
|
||||
spred \- sprite editor
|
||||
.SH SYNOPSIS
|
||||
.B spred
|
||||
.SH DESCRIPTION
|
||||
.I Spred
|
||||
is an editor for small images using a limited palette.
|
||||
It uses a window system mimicking
|
||||
.IR samterm (1).
|
||||
There is a command window which uses a command language described below.
|
||||
There is also an arbitrary number of palette and sprite windows.
|
||||
Each open sprite file has an associated palette file.
|
||||
.PP
|
||||
A left click on a color in a palette window selects that color.
|
||||
Colors in different palettes can be selected indepedently.
|
||||
A left click on a pixel in a sprite window sets that pixel to the selected color.
|
||||
.PP
|
||||
A right click brings up the global menu to create windows etc.
|
||||
It also lists all currently open files, including those that are not open in any window.
|
||||
A middle click brings up the menu for the local window, if applicable. Available commands there are:
|
||||
.TP
|
||||
.I pal
|
||||
The \fIpal\fR command sets the palette for the current sprite window. The palette is selected with a middle click.
|
||||
.PP
|
||||
The command language is a very stripped down version of
|
||||
.IR rc (1),
|
||||
currently only supporting "simple" commands consisting of a name and an arbitrary number of arguments separated by spaces. Quoting works just like with
|
||||
.IR rc (1).
|
||||
Available commands are:
|
||||
.TP
|
||||
.B q
|
||||
Quits the program. If any files have unsaved changes, it will fail on the first attempt to quit.
|
||||
.TP
|
||||
.BI pal file
|
||||
.TP
|
||||
.BI spr file
|
||||
Open a palette (\fIpal\fR) or sprite (\fIspr\fR) file named \fIfile\fR.
|
||||
If the file does not exist it is created.
|
||||
.TP
|
||||
.BI w [file]
|
||||
Write the currently selected file to \fIfile\fR. If \fIfile\fR is not specified, the name specified to the command opening the file is used.
|
||||
.TP
|
||||
.BI size sz
|
||||
Sets the size of the current file to \fIsz\fR.
|
||||
\fISz\fR should be of the form \fIn\fR for palettes or \fIn\fB*\fIm\fR for sprites where \fIn\fR and \fIm\fR are integers.
|
||||
.TP
|
||||
.B set 0x\fIrrggbb\fR
|
||||
Sets the currently selected color to the rgb color \fI(rr,gg,bb)\fR where
|
||||
.IR rr , gg and bb
|
||||
are in hexadecimal notation.
|
||||
.TP
|
||||
.B zoom n
|
||||
Sets the current zoom factor to \fIn\fR.
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/spred
|
||||
.SH SEE ALSO
|
||||
.IR sam (1)
|
188
sys/src/cmd/spred/cmd.c
Normal file
188
sys/src/cmd/spred/cmd.c
Normal file
|
@ -0,0 +1,188 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <mouse.h>
|
||||
#include <frame.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
extern Mousectl *mc;
|
||||
|
||||
static void
|
||||
dopal(int, char **argv)
|
||||
{
|
||||
Pal *p;
|
||||
|
||||
p = findpal("", argv[1], 2);
|
||||
if(p == nil){
|
||||
cmdprint("?%r\n");
|
||||
p = newpal(argv[1]);
|
||||
}
|
||||
if(newwinsel(PAL, mc, p) == nil){
|
||||
if(p->ref == 0)
|
||||
putfil(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dosize(int, char **argv)
|
||||
{
|
||||
char *p;
|
||||
int n, m;
|
||||
|
||||
if(actf == nil)
|
||||
goto err;
|
||||
switch(actf->type){
|
||||
case PAL:
|
||||
n = strtol(argv[1], &p, 0);
|
||||
if(*p != 0 || n < 0)
|
||||
goto err;
|
||||
palsize((Pal *) actf->f, n);
|
||||
return;
|
||||
case SPR:
|
||||
n = strtol(argv[1], &p, 0);
|
||||
if(*p != '*' || n < 0)
|
||||
goto err;
|
||||
m = strtol(++p, &p, 0);
|
||||
if(*p != 0 || m < 0)
|
||||
goto err;
|
||||
sprsize((Spr *) actf->f, n, m);
|
||||
return;
|
||||
}
|
||||
err:
|
||||
cmdprint("?\n");
|
||||
}
|
||||
|
||||
static void
|
||||
doset(int, char **argv)
|
||||
{
|
||||
int n;
|
||||
char *p;
|
||||
Pal *q;
|
||||
|
||||
if(actf == nil)
|
||||
goto err;
|
||||
switch(actf->type){
|
||||
case PAL:
|
||||
n = strtol(argv[1], &p, 0);
|
||||
if(*p != 0 || n < 0 || n > 0xffffff)
|
||||
goto err;
|
||||
q = (Pal *) actf->f;
|
||||
palset(q, q->sel, n);
|
||||
return;
|
||||
}
|
||||
err:
|
||||
cmdprint("?\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dozoom(int, char **argv)
|
||||
{
|
||||
int n;
|
||||
char *p;
|
||||
|
||||
if(actf == nil)
|
||||
goto err;
|
||||
n = strtol(argv[1], &p, 0);
|
||||
if(*p != 0 || n <= 0)
|
||||
goto err;
|
||||
actf->zoom = n;
|
||||
actf->tab->draw(actf);
|
||||
return;
|
||||
err:
|
||||
cmdprint("?\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dospr(int, char **argv)
|
||||
{
|
||||
Win *w;
|
||||
Spr *s;
|
||||
Biobuf *bp;
|
||||
|
||||
s = newspr(argv[1]);
|
||||
bp = Bopen(argv[1], OREAD);
|
||||
if(bp == nil)
|
||||
cmdprint("?%r\n");
|
||||
else{
|
||||
if(readspr(s, bp) < 0)
|
||||
cmdprint("?%r\n");
|
||||
Bterm(bp);
|
||||
}
|
||||
w = newwinsel(SPR, mc, s);
|
||||
if(w == nil){
|
||||
putfil(s);
|
||||
return;
|
||||
}
|
||||
if(s->palfile != nil){
|
||||
s->pal = findpal(argv[1], s->palfile, 1);
|
||||
if(s->pal == nil)
|
||||
cmdprint("?palette: %r\n");
|
||||
else{
|
||||
incref(s->pal);
|
||||
w->tab->draw(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dowrite(int argc, char **argv)
|
||||
{
|
||||
char *f;
|
||||
|
||||
if(argc > 2)
|
||||
cmdprint("?\n");
|
||||
if(argc == 2)
|
||||
f = argv[1];
|
||||
else
|
||||
f = nil;
|
||||
if(actf == nil)
|
||||
cmdprint("?\n");
|
||||
winwrite(actf, f);
|
||||
}
|
||||
|
||||
static void
|
||||
doquit(int, char **)
|
||||
{
|
||||
if(quit() < 0)
|
||||
threadexitsall(nil);
|
||||
}
|
||||
|
||||
static struct cmd {
|
||||
char *name;
|
||||
int argc;
|
||||
void (*f)(int, char **);
|
||||
} cmds[] = {
|
||||
{"pal", 2, dopal},
|
||||
{"size", 2, dosize},
|
||||
{"set", 2, doset},
|
||||
{"spr", 2, dospr},
|
||||
{"w", 0, dowrite},
|
||||
{"q", 1, doquit},
|
||||
{"zoom", 2, dozoom},
|
||||
{nil, nil}
|
||||
};
|
||||
|
||||
void
|
||||
docmd(char *s)
|
||||
{
|
||||
char *t[32];
|
||||
int nt;
|
||||
struct cmd *c;
|
||||
|
||||
nt = tokenize(s, t, nelem(t));
|
||||
if(nt == 0)
|
||||
return;
|
||||
for(c = cmds; c->name != 0; c++)
|
||||
if(strcmp(t[0], c->name) == 0){
|
||||
if(c->argc != 0 && c->argc != nt)
|
||||
cmdprint("?\n");
|
||||
else
|
||||
c->f(nt, t);
|
||||
return;
|
||||
}
|
||||
cmdprint("?\n");
|
||||
}
|
199
sys/src/cmd/spred/cmdw.c
Normal file
199
sys/src/cmd/spred/cmdw.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <mouse.h>
|
||||
#include <frame.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static int
|
||||
cmdinit(Win *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
scrollbar(Win *w)
|
||||
{
|
||||
int h, t0, t1;
|
||||
|
||||
h = Dy(w->inner);
|
||||
draw(w->im, rectaddpt(Rect(0, 0, SCRBSIZ+1, h), w->inner.min), w->tab->cols[BORD], nil, ZP);
|
||||
t0 = w->toprune * h;
|
||||
t1 = (w->toprune + w->fr.nchars) * h;
|
||||
if(w->nrunes == 0){
|
||||
t0 = 0;
|
||||
t1 = h;
|
||||
}else{
|
||||
t0 /= w->nrunes;
|
||||
t1 /= w->nrunes;
|
||||
}
|
||||
draw(w->im, rectaddpt(Rect(0, t0, SCRBSIZ, t1), w->inner.min), w->tab->cols[BACK], nil, ZP);
|
||||
}
|
||||
|
||||
static void
|
||||
cmddraw(Win *w)
|
||||
{
|
||||
Rectangle r;
|
||||
|
||||
frclear(&w->fr, 0);
|
||||
r = insetrect(w->inner, 1);
|
||||
r.min.x += SCRTSIZ;
|
||||
scrollbar(w);
|
||||
frinit(&w->fr, r, display->defaultfont, w->im, w->tab->cols);
|
||||
frinsert(&w->fr, w->runes + w->toprune, w->runes + w->nrunes, 0);
|
||||
}
|
||||
|
||||
void
|
||||
cmdscroll(Win *w, int l)
|
||||
{
|
||||
int r;
|
||||
|
||||
if(l == 0)
|
||||
return;
|
||||
if(l > 0){
|
||||
for(r = w->toprune; r < w->nrunes && l != 0; r++)
|
||||
if(w->runes[r] == '\n')
|
||||
l--;
|
||||
frdelete(&w->fr, 0, r - w->toprune);
|
||||
w->toprune = r;
|
||||
}else{
|
||||
for(r = w->toprune; r > 0; r--)
|
||||
if(w->runes[r] == '\n' && --l == 0)
|
||||
break;
|
||||
frinsert(&w->fr, w->runes + r, w->runes + w->toprune, 0);
|
||||
w->toprune = r;
|
||||
}
|
||||
scrollbar(w);
|
||||
}
|
||||
|
||||
static void
|
||||
cmdclick(Win *w, Mousectl *mc)
|
||||
{
|
||||
if(mc->xy.x <= w->inner.min.x + SCRBSIZ){
|
||||
cmdscroll(w, -5);
|
||||
return;
|
||||
}
|
||||
frselect(&w->fr, mc);
|
||||
}
|
||||
|
||||
static int
|
||||
cmdrmb(Win *w, Mousectl *mc)
|
||||
{
|
||||
if(mc->xy.x > w->inner.min.x + SCRBSIZ)
|
||||
return -1;
|
||||
cmdscroll(w, 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cmdinsert(Win *w, Rune *r, int nr, int rp)
|
||||
{
|
||||
Rune *s;
|
||||
|
||||
if(nr < 0)
|
||||
for(nr = 0, s = r; *s++ != 0; nr++)
|
||||
;
|
||||
if(rp < 0 || rp > w->nrunes)
|
||||
rp = w->nrunes;
|
||||
if(w->nrunes + nr > w->arunes){
|
||||
w->runes = realloc(w->runes, w->arunes = w->arunes + (nr + RUNEBLK - 1) & ~(RUNEBLK - 1));
|
||||
if(w->runes == nil)
|
||||
sysfatal("realloc: %r");
|
||||
}
|
||||
if(rp != w->nrunes)
|
||||
memmove(w->runes + rp, w->runes + rp + nr, (w->nrunes - rp) * sizeof(Rune));
|
||||
memmove(w->runes + rp, r, nr * sizeof(Rune));
|
||||
w->nrunes += nr;
|
||||
if(w->toprune > rp)
|
||||
w->toprune += nr;
|
||||
else{
|
||||
frinsert(&w->fr, w->runes + rp, w->runes + rp + nr, rp - w->toprune);
|
||||
if(rp == w->nrunes - nr){
|
||||
if(w->fr.lastlinefull)
|
||||
cmdscroll(w, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmddel(Win *w, int a, int b)
|
||||
{
|
||||
if(a >= b)
|
||||
return;
|
||||
memmove(w->runes + a, w->runes + b, w->nrunes - b);
|
||||
w->nrunes -= b - a;
|
||||
if(w->toprune >= b)
|
||||
w->toprune -= b - a;
|
||||
else{
|
||||
frdelete(&w->fr, a - w->toprune, b - w->toprune);
|
||||
if(w->toprune >= a)
|
||||
w->toprune = a;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmdkey(Win *w, Rune r)
|
||||
{
|
||||
static char buf[4096];
|
||||
char *p;
|
||||
Rune *q;
|
||||
|
||||
if(w->fr.p0 < w->fr.p1)
|
||||
cmddel(w, w->toprune + w->fr.p0, w->toprune + w->fr.p1);
|
||||
switch(r){
|
||||
case 0x00:
|
||||
case 0x1b:
|
||||
break;
|
||||
case '\b':
|
||||
if(w->fr.p0 > 0)
|
||||
cmddel(w, w->toprune + w->fr.p0 - 1, w->toprune + w->fr.p0);
|
||||
break;
|
||||
case '\n':
|
||||
cmdinsert(w, &r, 1, w->fr.p0 + w->toprune);
|
||||
if(w->toprune + w->fr.p0 == w->nrunes){
|
||||
q = w->runes + w->toprune + w->fr.p0 - 1;
|
||||
p = buf;
|
||||
while(*--q != 0xa && q > w->runes)
|
||||
;
|
||||
if(*q == 0xa)
|
||||
q++;
|
||||
while(q < w->runes + w->nrunes && p < buf + nelem(buf) + 1 && *q != 0xa)
|
||||
p += runetochar(p, q++);
|
||||
*p = 0;
|
||||
docmd(buf);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cmdinsert(w, &r, 1, w->fr.p0 + w->toprune);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cmdprint(char *fmt, ...)
|
||||
{
|
||||
Rune *r;
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
r = runevsmprint(fmt, va);
|
||||
va_end(va);
|
||||
if(r != nil)
|
||||
cmdinsert(cmdw, r, -1, -1);
|
||||
}
|
||||
|
||||
Wintab cmdtab = {
|
||||
.init = cmdinit,
|
||||
.draw = cmddraw,
|
||||
.click = cmdclick,
|
||||
.rmb = cmdrmb,
|
||||
.key = cmdkey,
|
||||
.hexcols = {
|
||||
[BORD] DPurpleblue,
|
||||
[DISB] 0xCCCCEEFF,
|
||||
[BACK] 0xCCFFFFFF,
|
||||
[HIGH] DPalegreygreen
|
||||
}
|
||||
};
|
98
sys/src/cmd/spred/dat.h
Normal file
98
sys/src/cmd/spred/dat.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
typedef struct Ident Ident;
|
||||
typedef struct Win Win;
|
||||
typedef struct Wintab Wintab;
|
||||
typedef struct Pal Pal;
|
||||
typedef struct Spr Spr;
|
||||
typedef struct File File;
|
||||
|
||||
enum {
|
||||
BORDSIZ = 5,
|
||||
MINSIZ = 3 * BORDSIZ,
|
||||
SELSIZ = 2,
|
||||
SCRBSIZ = 11,
|
||||
SCRTSIZ = 14,
|
||||
RUNEBLK = 4096,
|
||||
};
|
||||
|
||||
enum {
|
||||
DISB = NCOL,
|
||||
NCOLS
|
||||
};
|
||||
|
||||
enum {
|
||||
CMD,
|
||||
PAL,
|
||||
SPR,
|
||||
NTYPES
|
||||
};
|
||||
|
||||
struct Wintab {
|
||||
int (*init)(Win *);
|
||||
void (*die)(Win *);
|
||||
void (*click)(Win *, Mousectl *);
|
||||
void (*menu)(Win *, Mousectl *);
|
||||
int (*rmb)(Win *, Mousectl *);
|
||||
void (*key)(Win *, Rune);
|
||||
void (*draw)(Win *);
|
||||
void (*zerox)(Win *, Win *);
|
||||
u32int hexcols[NCOLS];
|
||||
Image *cols[NCOLS];
|
||||
};
|
||||
|
||||
struct Win {
|
||||
Rectangle entire;
|
||||
Rectangle inner;
|
||||
Image *im;
|
||||
Win *next, *prev;
|
||||
Win *wnext, *wprev;
|
||||
int type;
|
||||
Wintab *tab;
|
||||
|
||||
Frame fr;
|
||||
Rune *runes;
|
||||
int nrunes, arunes;
|
||||
int toprune;
|
||||
|
||||
int zoom;
|
||||
Point scr;
|
||||
File *f;
|
||||
Rectangle sprr;
|
||||
};
|
||||
|
||||
struct Ident {
|
||||
uint type, dev;
|
||||
Qid;
|
||||
};
|
||||
|
||||
struct File {
|
||||
int type;
|
||||
Ref;
|
||||
File *next, *prev;
|
||||
char *name;
|
||||
int change;
|
||||
Ident id;
|
||||
Win wins;
|
||||
};
|
||||
|
||||
struct Pal {
|
||||
File;
|
||||
int ncol;
|
||||
u32int *cols;
|
||||
Image **ims;
|
||||
int sel;
|
||||
};
|
||||
|
||||
struct Spr {
|
||||
File;
|
||||
Pal *pal;
|
||||
int w, h;
|
||||
u32int *data;
|
||||
char *palfile;
|
||||
};
|
||||
|
||||
extern Win wlist;
|
||||
extern File flist;
|
||||
extern Win *actw, *actf, *cmdw;
|
||||
extern Screen *scr;
|
||||
extern Image *invcol;
|
||||
extern int quitok;
|
157
sys/src/cmd/spred/fil.c
Normal file
157
sys/src/cmd/spred/fil.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <mouse.h>
|
||||
#include <frame.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
int
|
||||
tline(Biobuf *bp, char **str, char **args, int max)
|
||||
{
|
||||
char *s, *p;
|
||||
int q, dq, rc;
|
||||
|
||||
do{
|
||||
s = Brdstr(bp, '\n', 10);
|
||||
if(s == nil)
|
||||
return -1;
|
||||
q = dq = 0;
|
||||
for(p = s; *p != 0; p++)
|
||||
if(*p == '\'')
|
||||
dq = !dq;
|
||||
else{
|
||||
if(dq){
|
||||
q = !q;
|
||||
dq = 0;
|
||||
}
|
||||
if(*p == '#' && !q){
|
||||
*p = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rc = tokenize(s, args, max);
|
||||
}while(rc == 0 && (free(s), 1));
|
||||
*str = s;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Ident
|
||||
getident(int fd)
|
||||
{
|
||||
Dir *d;
|
||||
Ident i;
|
||||
|
||||
d = dirfstat(fd);
|
||||
if(d == nil)
|
||||
return (Ident){-1, -1, (Qid){0, 0, 0}};
|
||||
i = (Ident){d->type, d->dev, d->qid};
|
||||
free(d);
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
putident(Ident)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
identcmp(Ident *a, Ident *b)
|
||||
{
|
||||
return a->type != b->type || a->dev != b->dev || a->path != b->path;
|
||||
}
|
||||
|
||||
int
|
||||
filcmp(File *f, File *g)
|
||||
{
|
||||
if(f->type != g->type)
|
||||
return f->type - g->type;
|
||||
if(f->name == nil || g->name == nil)
|
||||
return -1;
|
||||
return strcmp(f->name, g->name);
|
||||
}
|
||||
|
||||
void
|
||||
filinit(File *f, char *t)
|
||||
{
|
||||
File *g;
|
||||
|
||||
f->wins.wnext = f->wins.wprev = &f->wins;
|
||||
f->name = strdup(t);
|
||||
for(g = flist.next; g != &flist && filcmp(g, f) < 0; g = g->next)
|
||||
;
|
||||
f->prev = g->prev;
|
||||
f->next = g;
|
||||
g->prev->next = f;
|
||||
g->prev = f;
|
||||
}
|
||||
|
||||
void
|
||||
putfil(File *f)
|
||||
{
|
||||
switch(f->type){
|
||||
case PAL: putpal((Pal *) f); break;
|
||||
case SPR: putspr((Spr *) f); break;
|
||||
}
|
||||
f->prev->next = f->next;
|
||||
f->next->prev = f->prev;
|
||||
free(f->name);
|
||||
free(f);
|
||||
}
|
||||
|
||||
static char phasetitle[] = "??? phase error ???";
|
||||
|
||||
int
|
||||
filtitlelen(File *f)
|
||||
{
|
||||
if(f->name != nil)
|
||||
return utflen(f->name) + 4;
|
||||
return strlen(phasetitle);
|
||||
}
|
||||
|
||||
char *
|
||||
filtitle(File *f, char *s, char *e)
|
||||
{
|
||||
if(f->name == nil)
|
||||
return strecpy(s, e, phasetitle);
|
||||
*s++ = f->change ? '\'' : ' ';
|
||||
if(f->wins.wnext != &f->wins)
|
||||
if(f->wins.wnext->wnext != &f->wins)
|
||||
*s++ = '*';
|
||||
else
|
||||
*s++ = '+';
|
||||
else
|
||||
*s++ = '-';
|
||||
*s++ = actf != nil && f == actf->f ? '.' : ' ';
|
||||
*s++ = ' ';
|
||||
return strecpy(s, e, f->name);
|
||||
}
|
||||
|
||||
void
|
||||
winwrite(Win *w, char *f)
|
||||
{
|
||||
if(w->f == nil){
|
||||
cmdprint("?\n");
|
||||
return;
|
||||
}
|
||||
switch(w->type){
|
||||
case PAL:
|
||||
writepal((Pal *) w->f, f);
|
||||
return;
|
||||
case SPR:
|
||||
writespr((Spr *) w->f, f);
|
||||
return;
|
||||
}
|
||||
cmdprint("?\n");
|
||||
}
|
||||
|
||||
void
|
||||
filredraw(File *f)
|
||||
{
|
||||
Win *w;
|
||||
|
||||
for(w = f->wins.wnext; w != &f->wins; w = w->wnext)
|
||||
w->tab->draw(w);
|
||||
}
|
37
sys/src/cmd/spred/fns.h
Normal file
37
sys/src/cmd/spred/fns.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
void cmdprint(char *, ...);
|
||||
void docmd(char *);
|
||||
void* emalloc(ulong);
|
||||
void filinit(File *, char *);
|
||||
void filredraw(File *);
|
||||
char* filtitle(File *, char *, char *);
|
||||
int filtitlelen(File *);
|
||||
Pal* findpal(char *, char *, int);
|
||||
Ident getident(int);
|
||||
int identcmp(Ident*, Ident *);
|
||||
void initwin(void);
|
||||
Pal* newpal(char *);
|
||||
Spr* newspr(char *);
|
||||
Win* newwin(int, Rectangle, File *);
|
||||
Win* newwinsel(int, Mousectl *, File *);
|
||||
void paldraw(Win *);
|
||||
void palset(Pal *, int, u32int);
|
||||
void palsize(Pal *, int);
|
||||
void putfil(File *);
|
||||
void putident(Ident);
|
||||
void putpal(Pal *);
|
||||
void putspr(Spr *);
|
||||
int quit(void);
|
||||
int readpal(Pal *, Biobuf *);
|
||||
int readspr(Spr *, Biobuf *);
|
||||
void resize(void);
|
||||
void setfocus(Win *);
|
||||
void sprsize(Spr *, int, int);
|
||||
int tline(Biobuf *, char **, char **, int);
|
||||
void winclick(Mousectl *);
|
||||
void winclose(Win *);
|
||||
void winresize(Win *, Mousectl *);
|
||||
Win* winsel(Mousectl*, int);
|
||||
void winwrite(Win *, char *);
|
||||
void winzerox(Win *, Mousectl *);
|
||||
int writepal(Pal *, char *);
|
||||
int writespr(Spr *, char *);
|
16
sys/src/cmd/spred/mkfile
Normal file
16
sys/src/cmd/spred/mkfile
Normal file
|
@ -0,0 +1,16 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
TARG=spred
|
||||
BIN=/$objtype/bin
|
||||
OFILES=\
|
||||
spred.$O\
|
||||
win.$O\
|
||||
cmd.$O\
|
||||
pal.$O\
|
||||
cmdw.$O\
|
||||
spr.$O\
|
||||
fil.$O\
|
||||
|
||||
HFILES=dat.h fns.h
|
||||
|
||||
</sys/src/cmd/mkone
|
280
sys/src/cmd/spred/pal.c
Normal file
280
sys/src/cmd/spred/pal.c
Normal file
|
@ -0,0 +1,280 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <mouse.h>
|
||||
#include <keyboard.h>
|
||||
#include <frame.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
Pal *
|
||||
newpal(char *f)
|
||||
{
|
||||
Pal *p;
|
||||
|
||||
p = emalloc(sizeof(*p));
|
||||
p->type = PAL;
|
||||
p->sel = -1;
|
||||
filinit(p, f);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
putpal(Pal *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < p->ncol; i++)
|
||||
freeimage(p->ims[i]);
|
||||
free(p->cols);
|
||||
free(p->ims);
|
||||
}
|
||||
|
||||
int
|
||||
readpal(Pal *p, Biobuf *bp)
|
||||
{
|
||||
char *s, *sp;
|
||||
char *args[8];
|
||||
int nc, i, c;
|
||||
|
||||
s = nil;
|
||||
if(tline(bp, &s, args, nelem(args)) != 2)
|
||||
goto err;
|
||||
if(strcmp(args[0], "pal") != 0)
|
||||
goto err;
|
||||
nc = strtol(args[1], &sp, 0);
|
||||
if(*sp != 0 || nc < 0)
|
||||
goto err;
|
||||
free(s);
|
||||
s = nil;
|
||||
p->ncol = nc;
|
||||
p->cols = emalloc(nc * sizeof(*p->cols));
|
||||
p->ims = emalloc(nc * sizeof(*p->ims));
|
||||
for(i = 0; i < nc; i++){
|
||||
if(tline(bp, &s, args, nelem(args)) != 1)
|
||||
goto err;
|
||||
c = strtol(args[0], &sp, 0);
|
||||
if(*sp != 0 || c < 0 || c > 0xffffff)
|
||||
goto err;
|
||||
p->cols[i] = c;
|
||||
free(s);
|
||||
s = nil;
|
||||
}
|
||||
for(i = 0; i < nc; i++)
|
||||
p->ims[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, p->cols[i] << 8 | 0xff);
|
||||
p->id = getident(bp->fid);
|
||||
return 0;
|
||||
err:
|
||||
if(s != nil)
|
||||
free(s);
|
||||
werrstr("invalid format");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
writepal(Pal *p, char *f)
|
||||
{
|
||||
Biobuf *bp;
|
||||
int i, rc, n;
|
||||
|
||||
if(f == nil)
|
||||
f = p->name;
|
||||
bp = Bopen(f, OWRITE);
|
||||
if(bp == nil){
|
||||
cmdprint("?%r\n");
|
||||
return -1;
|
||||
}
|
||||
n = 0;
|
||||
rc = Bprint(bp, "pal %d\n", p->ncol);
|
||||
if(rc < 0) goto err;
|
||||
n += rc;
|
||||
for(i = 0; i < p->ncol; i++){
|
||||
rc = Bprint(bp, "%#.6x\n", p->cols[i]);
|
||||
if(rc < 0) goto err;
|
||||
n += rc;
|
||||
}
|
||||
if(Bterm(bp) < 0){
|
||||
cmdprint("?%r\n");
|
||||
return -1;
|
||||
}
|
||||
p->change = 0;
|
||||
cmdprint("%s: #%d\n", f, n);
|
||||
return 0;
|
||||
err:
|
||||
cmdprint("?%r\n");
|
||||
Bterm(bp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Pal *
|
||||
findpal(char *sf, char *fn, int op)
|
||||
{
|
||||
File *f;
|
||||
char *s, *q;
|
||||
Ident i;
|
||||
int fd;
|
||||
Biobuf *bp;
|
||||
Pal *p;
|
||||
|
||||
if(sf == nil)
|
||||
sf = "";
|
||||
s = emalloc(strlen(sf) + strlen(fn) + 2);
|
||||
strcpy(s, sf);
|
||||
q = strrchr(s, '/');
|
||||
if(q != nil)
|
||||
*++q = 0;
|
||||
else
|
||||
*s = 0;
|
||||
strcpy(s, fn);
|
||||
fd = open(s, OREAD);
|
||||
if(fd < 0){
|
||||
free(s);
|
||||
return nil;
|
||||
}
|
||||
i = getident(fd);
|
||||
if(i.type == (uint)-1){
|
||||
close(fd);
|
||||
return nil;
|
||||
}
|
||||
for(f = flist.next; f != &flist; f = f->next)
|
||||
if(f->type == PAL && identcmp(&f->id, &i) == 0){
|
||||
close(fd);
|
||||
putident(i);
|
||||
return (Pal *) f;
|
||||
}
|
||||
putident(i);
|
||||
if(op == 0){
|
||||
close(fd);
|
||||
return nil;
|
||||
}
|
||||
bp = emalloc(sizeof(*bp));
|
||||
Binit(bp, fd, OREAD);
|
||||
p = newpal(s);
|
||||
if(readpal(p, bp) < 0){
|
||||
putfil(p);
|
||||
p = nil;
|
||||
goto end;
|
||||
}
|
||||
end:
|
||||
Bterm(bp);
|
||||
close(fd);
|
||||
free(bp);
|
||||
free(s);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
palredraw(Pal *p)
|
||||
{
|
||||
File *f;
|
||||
|
||||
filredraw(p);
|
||||
for(f = flist.next; f != &flist; f = f->next)
|
||||
if(f->type == SPR && ((Spr *) f)->pal == p)
|
||||
filredraw(f);
|
||||
}
|
||||
|
||||
void
|
||||
palsize(Pal *p, int sz)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(sz == p->ncol)
|
||||
return;
|
||||
p->cols = realloc(p->cols, sz * sizeof(*p->cols));
|
||||
p->ims = realloc(p->ims, sz * sizeof(*p->ims));
|
||||
if(sz > p->ncol){
|
||||
memset(p->cols + p->ncol, 0, sz);
|
||||
for(i = p->ncol; i < sz; i++)
|
||||
p->ims[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0);
|
||||
}
|
||||
p->ncol = sz;
|
||||
p->change = 1;
|
||||
quitok = 0;
|
||||
palredraw(p);
|
||||
}
|
||||
|
||||
void
|
||||
paldraw(Win *w)
|
||||
{
|
||||
Pal *p;
|
||||
int n, i;
|
||||
Rectangle r;
|
||||
|
||||
if(w->type != PAL || w->f == nil)
|
||||
sysfatal("paldraw: phase error");
|
||||
p = (Pal *) w->f;
|
||||
n = Dx(w->inner) / w->zoom;
|
||||
draw(w->im, w->inner, w->tab->cols[BACK], nil, ZP);
|
||||
for(i = 0; i < p->ncol; i++){
|
||||
r.min = addpt(w->inner.min, mulpt(Pt(i%n, i/n), w->zoom));
|
||||
r.max.x = r.min.x + w->zoom;
|
||||
r.max.y = r.min.y + w->zoom;
|
||||
draw(w->im, r, p->ims[i], nil, ZP);
|
||||
if(p->sel == i)
|
||||
border(w->im, r, SELSIZ, display->white, ZP);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
palset(Pal *p, int s, u32int c)
|
||||
{
|
||||
if(s < 0 || s >= p->ncol || p->cols[s] == c)
|
||||
return;
|
||||
p->cols[s] = c;
|
||||
freeimage(p->ims[s]);
|
||||
p->ims[s] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c << 8 | 0xff);
|
||||
p->change = 1;
|
||||
quitok = 0;
|
||||
palredraw(p);
|
||||
}
|
||||
|
||||
static int
|
||||
palinit(Win *w)
|
||||
{
|
||||
w->zoom = 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
palzerox(Win *w, Win *v)
|
||||
{
|
||||
v->zoom = w->zoom;
|
||||
}
|
||||
|
||||
static void
|
||||
palclick(Win *w, Mousectl *mc)
|
||||
{
|
||||
int n, i;
|
||||
Point pt;
|
||||
Pal *p;
|
||||
|
||||
if(!ptinrect(mc->xy, w->inner))
|
||||
return;
|
||||
if(w->f == nil)
|
||||
sysfatal("palclick: phase error");
|
||||
p = (Pal *) w->f;
|
||||
n = Dx(w->inner) / w->zoom;
|
||||
pt = subpt(mc->xy, w->inner.min);
|
||||
if(pt.x >= n * w->zoom)
|
||||
return;
|
||||
i = pt.x / w->zoom + pt.y / w->zoom * n;
|
||||
if(i >= p->ncol)
|
||||
return;
|
||||
p->sel = i;
|
||||
palredraw(p);
|
||||
}
|
||||
|
||||
Wintab paltab = {
|
||||
.init = palinit,
|
||||
.click = palclick,
|
||||
.draw = paldraw,
|
||||
.zerox = palzerox,
|
||||
.hexcols = {
|
||||
[BORD] 0xAA0000FF,
|
||||
[DISB] 0xCC8888FF,
|
||||
[BACK] 0xFFCCFFFF,
|
||||
},
|
||||
};
|
371
sys/src/cmd/spred/spr.c
Normal file
371
sys/src/cmd/spred/spr.c
Normal file
|
@ -0,0 +1,371 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <mouse.h>
|
||||
#include <keyboard.h>
|
||||
#include <frame.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
Spr *
|
||||
newspr(char *f)
|
||||
{
|
||||
Spr *s;
|
||||
|
||||
s = emalloc(sizeof(*s));
|
||||
s->type = SPR;
|
||||
filinit(s, f);
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
putspr(Spr *s)
|
||||
{
|
||||
if(s->pal != nil && !decref(s->pal) && s->pal->change <= 0)
|
||||
putfil(s->pal);
|
||||
free(s->palfile);
|
||||
free(s->data);
|
||||
}
|
||||
|
||||
int
|
||||
readspr(Spr *s, Biobuf *bp)
|
||||
{
|
||||
char *args0[8], *p, *ss, **args;
|
||||
int n, i, j;
|
||||
|
||||
args = nil;
|
||||
ss = nil;
|
||||
if(tline(bp, &ss, args0, nelem(args0)) != 4)
|
||||
goto err;
|
||||
if(strcmp(args0[0], "sprite") != 0)
|
||||
goto err;
|
||||
n = strtol(args0[1], &p, 0);
|
||||
if(*p != 0 || n < 0)
|
||||
goto err;
|
||||
s->w = n;
|
||||
n = strtol(args0[2], &p, 0);
|
||||
if(*p != 0 || n < 0)
|
||||
goto err;
|
||||
s->h = n;
|
||||
if(*args0[3] != 0)
|
||||
s->palfile = strdup(args0[3]);
|
||||
else
|
||||
s->palfile = nil;
|
||||
free(ss);
|
||||
ss = nil;
|
||||
s->data = emalloc(s->w * s->h * sizeof(u32int));
|
||||
args = emalloc((s->w + 1) * sizeof(char *));
|
||||
for(i = 0; i < s->h; i++){
|
||||
if(tline(bp, &ss, args, s->w + 1) != s->w)
|
||||
goto err;
|
||||
for(j = 0; j < s->w; j++){
|
||||
n = strtol(args[j], &p, 0);
|
||||
if(*p != 0 || n < 0)
|
||||
goto err;
|
||||
s->data[i * s->w + j] = n;
|
||||
}
|
||||
free(ss);
|
||||
ss = nil;
|
||||
}
|
||||
free(args);
|
||||
return 0;
|
||||
err:
|
||||
werrstr("invalid format");
|
||||
free(s->data);
|
||||
free(args);
|
||||
s->w = 0;
|
||||
s->h = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
writespr(Spr *s, char *file)
|
||||
{
|
||||
Biobuf *bp;
|
||||
int n, rc;
|
||||
int i, j;
|
||||
|
||||
if(file == nil)
|
||||
file = s->name;
|
||||
bp = Bopen(file, OWRITE);
|
||||
if(bp == nil){
|
||||
cmdprint("?%r\n");
|
||||
return -1;
|
||||
}
|
||||
rc = Bprint(bp, "sprite %d %d %q\n", s->w, s->h, s->palfile != nil ? s->palfile : "");
|
||||
if(rc < 0) goto err;
|
||||
n = rc;
|
||||
for(i = 0; i < s->h; i++)
|
||||
for(j = 0; j < s->w; j++){
|
||||
rc = Bprint(bp, "%d%c", s->data[s->w * i + j], j == s->w - 1 ? '\n' : ' ');
|
||||
if(rc < 0) goto err;
|
||||
n += rc;
|
||||
}
|
||||
if(Bterm(bp) < 0){
|
||||
cmdprint("?%r\n");
|
||||
return -1;
|
||||
}
|
||||
s->change = 0;
|
||||
quitok = 0;
|
||||
cmdprint("%s: #%d\n", file, n);
|
||||
return 0;
|
||||
err:
|
||||
cmdprint("?%r\n");
|
||||
Bterm(bp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
sprinit(Win *w)
|
||||
{
|
||||
w->zoom = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Rectangle
|
||||
sprrect(Win *w, Rectangle s)
|
||||
{
|
||||
Rectangle r;
|
||||
Point p, q;
|
||||
Spr *t;
|
||||
|
||||
t = (Spr *) w->f;
|
||||
p = Pt(t->w * w->zoom, t->h * w->zoom);
|
||||
q = addpt(divpt(addpt(s.min, s.max), 2), w->scr);
|
||||
r.min = subpt(q, divpt(p, 2));
|
||||
r.max = addpt(r.min, p);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
scrollbars(Win *w)
|
||||
{
|
||||
Rectangle r, s;
|
||||
int dx, dy;
|
||||
int t0, t1;
|
||||
|
||||
if(rectinrect(w->sprr, w->inner))
|
||||
return;
|
||||
r = w->inner;
|
||||
dx = Dx(r) - SCRTSIZ;
|
||||
dy = Dy(r) - SCRTSIZ;
|
||||
if(dx <= 0 || dy <= 0)
|
||||
return;
|
||||
s = r;
|
||||
if(!rectclip(&s, w->sprr))
|
||||
return;
|
||||
draw(w->im, Rect(r.min.x, r.max.y - SCRBSIZ, r.max.x - SCRTSIZ, r.max.y), w->tab->cols[BORD], nil, ZP);
|
||||
draw(w->im, Rect(r.max.x - SCRBSIZ, r.min.y, r.max.x, r.max.y - SCRTSIZ), w->tab->cols[BORD], nil, ZP);
|
||||
t0 = (s.min.x - w->sprr.min.x) * dx / Dx(w->sprr) + r.min.x;
|
||||
t1 = (s.max.x - w->sprr.min.x) * dx / Dx(w->sprr) + r.min.x;
|
||||
draw(w->im, Rect(t0, r.max.y - SCRBSIZ + 1, t1, r.max.y), w->tab->cols[BACK], nil, ZP);
|
||||
t0 = (s.min.y - w->sprr.min.y) * dy / Dy(w->sprr) + r.min.y;
|
||||
t1 = (s.max.y - w->sprr.min.y) * dy / Dy(w->sprr) + r.min.y;
|
||||
draw(w->im, Rect(r.max.x - SCRBSIZ, t0, r.max.x, t1), w->tab->cols[BACK], nil, ZP);
|
||||
}
|
||||
|
||||
void
|
||||
sprdraw(Win *w)
|
||||
{
|
||||
Rectangle r, t;
|
||||
Spr *s;
|
||||
Pal *p;
|
||||
int i, j;
|
||||
Image *im;
|
||||
u32int *d;
|
||||
|
||||
if(w->type != SPR || w->f == nil)
|
||||
sysfatal("sprdraw: phase error");
|
||||
s = (Spr *) w->f;
|
||||
p = s->pal;
|
||||
draw(w->im, w->inner, w->tab->cols[BACK], nil, ZP);
|
||||
r = sprrect(w, w->inner);
|
||||
w->sprr = r;
|
||||
if(!rectinrect(r, w->inner)){
|
||||
t = w->inner;
|
||||
t.max.x -= SCRTSIZ;
|
||||
t.max.y -= SCRTSIZ;
|
||||
r = sprrect(w, t);
|
||||
w->sprr = r;
|
||||
rectclip(&r, t);
|
||||
scrollbars(w);
|
||||
}
|
||||
d = s->data;
|
||||
for(j = 0; j < s->h; j++)
|
||||
for(i = 0; i < s->w; i++, d++){
|
||||
t.min = addpt(w->sprr.min, Pt(i * w->zoom, j * w->zoom));
|
||||
t.max = addpt(t.min, Pt(w->zoom, w->zoom));
|
||||
if(!rectclip(&t, r))
|
||||
continue;
|
||||
if(p != nil && *d < p->ncol)
|
||||
im = p->ims[*d];
|
||||
else
|
||||
im = invcol;
|
||||
draw(w->im, t, im, nil, ZP);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sprbars(Win *w, Mousectl *mc)
|
||||
{
|
||||
int d;
|
||||
|
||||
if(rectinrect(w->sprr, w->inner))
|
||||
return -1;
|
||||
if(mc->xy.x >= w->inner.max.x - SCRBSIZ){
|
||||
d = Dy(w->inner) / 5;
|
||||
switch(mc->buttons){
|
||||
case 1: w->scr.y += d; break;
|
||||
case 4: w->scr.y -= d; break;
|
||||
default: return 0;
|
||||
}
|
||||
sprdraw(w);
|
||||
return 0;
|
||||
}
|
||||
if(mc->xy.y >= w->inner.max.y - SCRBSIZ){
|
||||
d = Dx(w->inner) / 5;
|
||||
switch(mc->buttons){
|
||||
case 1: w->scr.x += d; break;
|
||||
case 4: w->scr.x -= d; break;
|
||||
default: return 0;
|
||||
}
|
||||
sprdraw(w);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
sprclick(Win *w, Mousectl *mc)
|
||||
{
|
||||
Spr *s;
|
||||
Pal *p;
|
||||
Point q;
|
||||
|
||||
if(w->f == nil)
|
||||
sysfatal("sprclick: phase error");
|
||||
if(sprbars(w, mc) >= 0)
|
||||
return;
|
||||
s = (Spr *) w->f;
|
||||
p = s->pal;
|
||||
if(p == nil || p->sel < 0 || p->sel >= p->ncol)
|
||||
return;
|
||||
do{
|
||||
q = divpt(subpt(mc->xy, w->sprr.min), w->zoom);
|
||||
if(q.x < 0 || q.y < 0 || q.x >= s->w || q.y >= s->h)
|
||||
continue;
|
||||
if(s->data[q.y * s->w + q.x] != p->sel){
|
||||
s->data[q.y * s->w + q.x] = p->sel;
|
||||
s->change = 1;
|
||||
quitok = 0;
|
||||
sprdraw(w);
|
||||
}
|
||||
}while(readmouse(mc) >= 0 && (mc->buttons & 1) != 0);
|
||||
}
|
||||
|
||||
void
|
||||
sprsize(Spr *s, int n, int m)
|
||||
{
|
||||
u32int *v;
|
||||
int i, j, w, h;
|
||||
|
||||
v = s->data;
|
||||
if(s->w == n && s->h == m)
|
||||
return;
|
||||
s->data = emalloc(n * m * sizeof(u32int));
|
||||
w = n < s->w ? n : s->w;
|
||||
h = m < s->h ? m : s->h;
|
||||
for(j = 0; j < h; j++)
|
||||
for(i = 0; i < w; i++)
|
||||
s->data[j * n + i] = v[j * w + i];
|
||||
s->w = n;
|
||||
s->h = m;
|
||||
s->change = 1;
|
||||
quitok = 0;
|
||||
filredraw(s);
|
||||
}
|
||||
|
||||
static char *
|
||||
palfile(char *, char *n)
|
||||
{
|
||||
return strdup(n);
|
||||
}
|
||||
|
||||
static void
|
||||
sprmenu(Win *w, Mousectl *mc)
|
||||
{
|
||||
enum { MPAL };
|
||||
static char *menus[] = {
|
||||
"pal",
|
||||
nil,
|
||||
};
|
||||
static Menu menu = {menus};
|
||||
Win *wp;
|
||||
Spr *s;
|
||||
|
||||
if(w->f == nil)
|
||||
sysfatal("sprmenu: phase error");
|
||||
s = (Spr *) w->f;
|
||||
switch(menuhit(2, mc, &menu, scr)){
|
||||
case MPAL:
|
||||
wp = winsel(mc, 2);
|
||||
if(wp == nil || wp->type != PAL)
|
||||
break;
|
||||
if(wp->f == nil)
|
||||
sysfatal("sprmenu: pal phase error");
|
||||
if(s->pal != (Pal *) wp->f){
|
||||
if(s->pal != nil && decref(s->pal) == 0 && s->pal->change <= 0)
|
||||
putfil(s->pal);
|
||||
incref(wp->f);
|
||||
s->pal = (Pal *) wp->f;
|
||||
free(s->palfile);
|
||||
s->palfile = palfile(s->name, s->pal->name);
|
||||
s->change = 1;
|
||||
quitok = 0;
|
||||
filredraw(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sprzerox(Win *w, Win *v)
|
||||
{
|
||||
v->zoom = w->zoom;
|
||||
v->scr = w->scr;
|
||||
}
|
||||
|
||||
static void
|
||||
sprkey(Win *w, Rune r)
|
||||
{
|
||||
static char keys[] = "1234567890qwertyuiop";
|
||||
char *p;
|
||||
Spr *s;
|
||||
|
||||
s = (Spr *) w->f;
|
||||
if(s == nil)
|
||||
sysfatal("sprkey: phase error");
|
||||
if(r < 0x100 && (p = strchr(keys, r)) != nil){
|
||||
if(s->pal == nil || p - keys >= s->pal->ncol)
|
||||
return;
|
||||
s->pal->sel = p - keys;
|
||||
filredraw(s->pal);
|
||||
}
|
||||
}
|
||||
|
||||
Wintab sprtab = {
|
||||
.init = sprinit,
|
||||
.click = sprclick,
|
||||
.draw = sprdraw,
|
||||
.menu = sprmenu,
|
||||
.rmb = sprbars,
|
||||
.zerox = sprzerox,
|
||||
.key = sprkey,
|
||||
.hexcols = {
|
||||
[BORD] 0x00AA00FF,
|
||||
[DISB] 0x88CC88FF,
|
||||
[BACK] 0xCCFFCCFF,
|
||||
},
|
||||
};
|
210
sys/src/cmd/spred/spred.c
Normal file
210
sys/src/cmd/spred/spred.c
Normal file
|
@ -0,0 +1,210 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <mouse.h>
|
||||
#include <keyboard.h>
|
||||
#include <frame.h>
|
||||
#include <cursor.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
Mousectl *mc;
|
||||
Keyboardctl *kc;
|
||||
int quitok;
|
||||
|
||||
enum {
|
||||
ZEROX,
|
||||
RESIZE,
|
||||
CLOSE,
|
||||
WRITE,
|
||||
QUIT,
|
||||
WIN
|
||||
};
|
||||
|
||||
int
|
||||
quit(void)
|
||||
{
|
||||
File *f;
|
||||
|
||||
if(!quitok)
|
||||
for(f = flist.next; f != &flist; f = f->next)
|
||||
if(f->change > 0){
|
||||
cmdprint("?\n");
|
||||
quitok = 1;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *
|
||||
menugen(int n)
|
||||
{
|
||||
File *f;
|
||||
static int mw;
|
||||
static char buf[512];
|
||||
int rc;
|
||||
char *p;
|
||||
|
||||
switch(n){
|
||||
case ZEROX: return "zerox";
|
||||
case CLOSE: return "close";
|
||||
case RESIZE: return "resize";
|
||||
case WRITE: return "write";
|
||||
case QUIT: return "quit";
|
||||
}
|
||||
if(n < WIN)
|
||||
sysfatal("menugen: no string for n=%d", n);
|
||||
n -= WIN;
|
||||
if(n == 0){
|
||||
mw = 0;
|
||||
for(f = flist.next; f != &flist; f = f->next){
|
||||
rc = filtitlelen(f);
|
||||
if(rc > mw)
|
||||
mw = rc;
|
||||
}
|
||||
return "~~spred~~";
|
||||
}
|
||||
for(f = flist.next; f != &flist; f = f->next)
|
||||
if(--n == 0){
|
||||
p = filtitle(f, buf, buf + sizeof(buf));
|
||||
rc = mw - utflen(buf);
|
||||
if(p + rc >= buf + sizeof(buf))
|
||||
rc = buf + sizeof(buf) - p - 1;
|
||||
memset(p, ' ', rc);
|
||||
p[rc] = 0;
|
||||
return buf;
|
||||
}
|
||||
return nil;
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
rmb(void)
|
||||
{
|
||||
static Menu menu = {nil, menugen};
|
||||
int n;
|
||||
Win *w;
|
||||
File *f;
|
||||
|
||||
if(actw != nil && actw->tab->rmb != nil && actw->tab->rmb(actw, mc) >= 0)
|
||||
return 0;
|
||||
n = menuhit(3, mc, &menu, nil);
|
||||
if(n < 0)
|
||||
return 0;
|
||||
switch(n){
|
||||
case ZEROX:
|
||||
w = winsel(mc, 3);
|
||||
if(w != nil)
|
||||
winzerox(w, mc);
|
||||
return 0;
|
||||
case CLOSE:
|
||||
w = winsel(mc, 3);
|
||||
if(w != nil)
|
||||
winclose(w);
|
||||
return 0;
|
||||
case RESIZE:
|
||||
winresize(winsel(mc, 3), mc);
|
||||
return 0;
|
||||
case WRITE:
|
||||
w = winsel(mc, 3);
|
||||
if(w != nil)
|
||||
winwrite(w, nil);
|
||||
return 0;
|
||||
case QUIT:
|
||||
return quit();
|
||||
}
|
||||
if(n < WIN)
|
||||
sysfatal("rmb: no action for n=%d", n);
|
||||
if(n == 0){
|
||||
setfocus(cmdw);
|
||||
return 0;
|
||||
}
|
||||
n -= WIN;
|
||||
for(f = flist.next; f != &flist; f = f->next)
|
||||
if(--n == 0){
|
||||
if(f->wins.wnext == &f->wins){
|
||||
newwinsel(f->type, mc, f);
|
||||
return 0;
|
||||
}
|
||||
for(w = f->wins.wnext; w != &f->wins && w != actw; w = w->wnext)
|
||||
;
|
||||
if(w->wnext == &f->wins)
|
||||
w = w->wnext;
|
||||
setfocus(w->wnext);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
loop(void)
|
||||
{
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
Alt a[] = {
|
||||
{mc->c, &mc->Mouse, CHANRCV},
|
||||
{kc->c, &r, CHANRCV},
|
||||
{mc->resizec, &n, CHANRCV},
|
||||
{nil, nil, CHANEND}
|
||||
};
|
||||
|
||||
for(;;){
|
||||
flushimage(display, 1);
|
||||
switch(alt(a)){
|
||||
case 0:
|
||||
if((mc->buttons & 1) != 0)
|
||||
winclick(mc);
|
||||
if((mc->buttons & 2) != 0)
|
||||
if(actw != nil && actw->tab->menu != nil)
|
||||
actw->tab->menu(actw, mc);
|
||||
if((mc->buttons & 4) != 0)
|
||||
if(rmb() < 0)
|
||||
return;
|
||||
break;
|
||||
case 1:
|
||||
if(actw != nil && actw->tab->key != nil)
|
||||
actw->tab->key(actw, r);
|
||||
break;
|
||||
case 2:
|
||||
resize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
threadmain(int argc, char **argv)
|
||||
{
|
||||
ARGBEGIN {
|
||||
default:
|
||||
;
|
||||
} ARGEND;
|
||||
|
||||
quotefmtinstall();
|
||||
if(initdraw(nil, nil, nil) < 0)
|
||||
sysfatal("initdraw: %r");
|
||||
initwin();
|
||||
mc = initmouse(nil, screen);
|
||||
if(mc == nil)
|
||||
sysfatal("initmouse: %r");
|
||||
kc = initkeyboard(nil);
|
||||
if(kc == nil)
|
||||
sysfatal("initkeyboard: %r");
|
||||
loop();
|
||||
threadexitsall(nil);
|
||||
}
|
||||
|
||||
Cursor crosscursor = {
|
||||
{-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, }
|
||||
};
|
281
sys/src/cmd/spred/win.c
Normal file
281
sys/src/cmd/spred/win.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include <mouse.h>
|
||||
#include <cursor.h>
|
||||
#include <frame.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
Screen *scr;
|
||||
extern Wintab *tabs[];
|
||||
Win wlist;
|
||||
File flist;
|
||||
Win *actw, *actf, *cmdw;
|
||||
Image *invcol;
|
||||
|
||||
void*
|
||||
emalloc(ulong sz)
|
||||
{
|
||||
void *v;
|
||||
|
||||
v = malloc(sz);
|
||||
if(v == nil)
|
||||
sysfatal("malloc: %r");
|
||||
memset(v, 0, sz);
|
||||
setmalloctag(v, getcallerpc(&sz));
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
initwin(void)
|
||||
{
|
||||
Rectangle r;
|
||||
int i, j;
|
||||
|
||||
scr = allocscreen(screen, display->white, 0);
|
||||
if(scr == nil)
|
||||
sysfatal("allocscreen: %r");
|
||||
for(i = 0; i < NTYPES; i++)
|
||||
for(j = 0; j < NCOLS; j++)
|
||||
tabs[i]->cols[j] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, tabs[i]->hexcols[j]);
|
||||
invcol = allocimage(display, Rect(0, 0, 2, 2), screen->chan, 1, 0);
|
||||
draw(invcol, Rect(1, 0, 2, 1), display->white, nil, ZP);
|
||||
draw(invcol, Rect(0, 1, 1, 2), display->white, nil, ZP);
|
||||
wlist.next = wlist.prev = &wlist;
|
||||
flist.next = flist.prev = &flist;
|
||||
r = screen->r;
|
||||
r.max.y = r.min.y + Dy(r) / 5;
|
||||
cmdw = newwin(CMD, r, nil);
|
||||
if(cmdw == nil)
|
||||
sysfatal("newwin: %r");
|
||||
}
|
||||
|
||||
Win *
|
||||
newwin(int t, Rectangle r, File *f)
|
||||
{
|
||||
Win *w;
|
||||
|
||||
w = emalloc(sizeof(*w));
|
||||
w->next = &wlist;
|
||||
w->prev = wlist.prev;
|
||||
w->next->prev = w;
|
||||
w->prev->next = w;
|
||||
w->type = t;
|
||||
w->tab = tabs[t];
|
||||
w->entire = r;
|
||||
w->inner = insetrect(r, BORDSIZ);
|
||||
w->im = allocwindow(scr, r, Refbackup, 0);
|
||||
draw(w->im, w->inner, w->tab->cols[BACK], nil, ZP);
|
||||
if(f != nil){
|
||||
incref(f);
|
||||
w->wprev = f->wins.wprev;
|
||||
w->wnext = &f->wins;
|
||||
f->wins.wprev->wnext = w;
|
||||
f->wins.wprev = w;
|
||||
w->f = f;
|
||||
}
|
||||
w->tab->init(w);
|
||||
setfocus(w);
|
||||
w->tab->draw(w);
|
||||
return w;
|
||||
}
|
||||
|
||||
Win *
|
||||
newwinsel(int t, Mousectl *mc, File *f)
|
||||
{
|
||||
Rectangle u;
|
||||
|
||||
u = getrect(3, mc);
|
||||
if(Dx(u) < MINSIZ || Dy(u) < MINSIZ)
|
||||
return nil;
|
||||
rectclip(&u, screen->r);
|
||||
return newwin(t, u, f);
|
||||
}
|
||||
|
||||
void
|
||||
winzerox(Win *w, Mousectl *mc)
|
||||
{
|
||||
Win *v;
|
||||
|
||||
if(w->tab->zerox == nil){
|
||||
cmdprint("?\n");
|
||||
return;
|
||||
}
|
||||
v = newwinsel(w->type, mc, w->f);
|
||||
if(v == nil)
|
||||
return;
|
||||
w->tab->zerox(w, v);
|
||||
v->tab->draw(v);
|
||||
}
|
||||
|
||||
void
|
||||
winclose(Win *w)
|
||||
{
|
||||
if(w->f == nil){
|
||||
cmdprint("?\n");
|
||||
return;
|
||||
}
|
||||
if(!decref(w->f)){
|
||||
if(w->f->change > 0){
|
||||
cmdprint("?\n");
|
||||
incref(w->f);
|
||||
w->f->change = -1;
|
||||
return;
|
||||
}
|
||||
putfil(w->f);
|
||||
w->f = nil;
|
||||
}
|
||||
freeimage(w->im);
|
||||
if(w->f != nil){
|
||||
w->wnext->wprev = w->wprev;
|
||||
w->wprev->wnext = w->wnext;
|
||||
}
|
||||
w->next->prev = w->prev;
|
||||
w->prev->next = w->next;
|
||||
if(w == actw)
|
||||
actw = nil;
|
||||
if(w == actf)
|
||||
actf = nil;
|
||||
free(w);
|
||||
}
|
||||
|
||||
void
|
||||
setfocus(Win *w)
|
||||
{
|
||||
if(actw != nil)
|
||||
border(actw->im, actw->entire, BORDSIZ, actw->tab->cols[DISB], ZP);
|
||||
actw = w;
|
||||
if(w != cmdw)
|
||||
actf = w;
|
||||
if(w == nil)
|
||||
return;
|
||||
if(w->im == nil)
|
||||
sysfatal("setfocus: phase error");
|
||||
topwindow(w->im);
|
||||
w->prev->next = w->next;
|
||||
w->next->prev = w->prev;
|
||||
w->prev = wlist.prev;
|
||||
w->next = &wlist;
|
||||
w->prev->next = w;
|
||||
w->next->prev = w;
|
||||
border(w->im, w->entire, BORDSIZ, w->tab->cols[BORD], ZP);
|
||||
}
|
||||
|
||||
static Win *
|
||||
winpoint(Point p)
|
||||
{
|
||||
Win *w;
|
||||
|
||||
for(w = wlist.prev; w != &wlist; w = w->prev)
|
||||
if(ptinrect(p, w->entire))
|
||||
return w;
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
winclick(Mousectl *mc)
|
||||
{
|
||||
Win *w;
|
||||
|
||||
w = winpoint(mc->xy);
|
||||
if(w != nil){
|
||||
if(w != actw)
|
||||
setfocus(w);
|
||||
w->tab->click(w, mc);
|
||||
}
|
||||
while((mc->buttons & 1) != 0)
|
||||
readmouse(mc);
|
||||
}
|
||||
|
||||
Win *
|
||||
winsel(Mousectl *mc, int but)
|
||||
{
|
||||
extern Cursor crosscursor;
|
||||
int m;
|
||||
Win *w;
|
||||
|
||||
m = 1 << but - 1;
|
||||
setcursor(mc, &crosscursor);
|
||||
for(;;){
|
||||
readmouse(mc);
|
||||
if((mc->buttons & ~m) != 0){
|
||||
w = nil;
|
||||
goto end;
|
||||
}
|
||||
if((mc->buttons & m) != 0)
|
||||
break;
|
||||
}
|
||||
w = winpoint(mc->xy);
|
||||
end:
|
||||
while(readmouse(mc), mc->buttons != 0)
|
||||
;
|
||||
setcursor(mc, nil);
|
||||
return w;
|
||||
}
|
||||
|
||||
void
|
||||
winresize(Win *w, Mousectl *mc)
|
||||
{
|
||||
Rectangle r;
|
||||
|
||||
if(w == nil)
|
||||
return;
|
||||
r = getrect(3, mc);
|
||||
if(Dx(r) < MINSIZ || Dy(r) < MINSIZ)
|
||||
return;
|
||||
rectclip(&r, screen->r);
|
||||
freeimage(w->im);
|
||||
w->entire = r;
|
||||
w->inner = insetrect(r, BORDSIZ);
|
||||
w->im = allocwindow(scr, r, Refbackup, 0);
|
||||
draw(w->im, w->inner, w->tab->cols[BACK], nil, ZP);
|
||||
setfocus(w);
|
||||
w->tab->draw(w);
|
||||
}
|
||||
|
||||
void
|
||||
resize(void)
|
||||
{
|
||||
Rectangle old, r;
|
||||
int dxo, dyo, dxn, dyn;
|
||||
Win *w;
|
||||
|
||||
old = screen->r;
|
||||
dxo = Dx(old);
|
||||
dyo = Dy(old);
|
||||
if(getwindow(display, Refnone) < 0)
|
||||
sysfatal("resize failed: %r");
|
||||
dxn = Dx(screen->r);
|
||||
dyn = Dy(screen->r);
|
||||
freescreen(scr);
|
||||
scr = allocscreen(screen, display->white, 0);
|
||||
if(scr == nil)
|
||||
sysfatal("allocscreen: %r");
|
||||
for(w = wlist.next; w != &wlist; w = w->next){
|
||||
r = rectsubpt(w->entire, old.min);
|
||||
r.min.x = muldiv(r.min.x, dxn, dxo);
|
||||
r.max.x = muldiv(r.max.x, dxn, dxo);
|
||||
r.min.y = muldiv(r.min.y, dyn, dyo);
|
||||
r.max.y = muldiv(r.max.y, dyn, dyo);
|
||||
w->entire = rectaddpt(r, screen->r.min);
|
||||
w->inner = insetrect(w->entire, BORDSIZ);
|
||||
freeimage(w->im);
|
||||
w->im = allocwindow(scr, w->entire, Refbackup, 0);
|
||||
if(w->im == nil)
|
||||
sysfatal("allocwindow: %r");
|
||||
draw(w->im, w->inner, w->tab->cols[BACK], nil, ZP);
|
||||
border(w->im, w->entire, BORDSIZ, w->tab->cols[w == actw ? BORD : DISB], ZP);
|
||||
w->tab->draw(w);
|
||||
}
|
||||
}
|
||||
|
||||
extern Wintab cmdtab, paltab, sprtab;
|
||||
|
||||
Wintab *tabs[] = {
|
||||
[CMD] &cmdtab,
|
||||
[PAL] &paltab,
|
||||
[SPR] &sprtab,
|
||||
};
|
Loading…
Reference in a new issue