#include <u.h>
#include <libc.h>
#include <thread.h>
#include <fcall.h>
#include <draw.h>
#include <mouse.h>
#include <cursor.h>
#include <keyboard.h>
#include <frame.h>
#include <9p.h>
#include <plumb.h>
#include <b.h>
#include "gui.h"
#include "cook.h"
#include <pool.h>
static int creatingcol;
static int creatingrow;
static int deleting;
static int identifying;
static int copying;
static File* movingf;
static void
resetcmd(void)
{
creatingcol = creatingrow = deleting = identifying = copying = 0;
movingf = nil;
argcursor(0);
}
int
within(File* d, File* f)
{
int found;
File** w;
File** l;
File* fp;
Panel* np;
found = 0;
assert(f);
w = newfilewalk(d);
for (l = w; fp = *l; l++)
if (ispanel(fp)){
found |= (fp == f);
np = fp->aux;
if (!found && (np->type == Qcol || np->type == Qrow))
found |= within(fp, f);
}
endfilewalk(w);
return found;
}
static void
notifymove(File* f, char* old, int nlen)
{
File** l;
File** w;
File* fp;
Panel* p;
char* npath;
p = f->aux;
npath = filepath(f);
free(p->path);
p->path = estrdup9p(npath);
conprint(p->con, "%s%s path %s\001", old, npath + nlen, npath);
free(npath);
w = newfilewalk(f);
for (l = w; fp = *l; l++)
if (ispanel(fp))
notifymove(fp, old, nlen);
endfilewalk(w);
}
static File*
insertpoint(File* f, Point xy)
{
File** l;
File** w;
File* fp;
Panel* p;
Panel* np;
File* last;
int m;
int v;
p = f->aux;
last = nil;
w = newfilewalk(f);
for (l = w; fp = *l; l++){
if (!ispanel(fp))
continue;
np = fp->aux;
if (p->type == Qcol){
m = (np->rect.min.y + np->rect.max.y)/2;
v = xy.y;
} else {
m = (np->rect.min.x + np->rect.max.x)/2;
v = xy.x;
}
if (v < m)
break;
last = fp;
}
endfilewalk(w);
return last;
}
static void
movefile(File* from, File* f, Point xy)
{
Panel* p;
File* at;
char* opath;
char* npath;
if (within(from, f))
return;
opath = filepath(from->parent);
detachfile(from);
p = f->aux;
if (p->type != Qcol && p->type != Qrow)
f = f->parent;
at = insertpoint(f, xy);
insertfile(from, f, at);
npath = filepath(f);
notifymove(from, opath, strlen(npath));
free(opath);
free(npath);
resize();
}
static void
mkpanel(int id, File* f)
{
Panel* p;
char* s;
File* nf;
p = f->aux;
if (p->type != Qcol && p->type != Qrow){
f = f->parent;
p = f->aux;
}
assert(p->type == Qcol || p->type == Qrow);
s = smprint("%s:%d", (id == Qcol ? "col:" : "row:"), rand());
nf = newfspanel(f, s, f->uid);
p = nf->aux;
p->flags |= Ptag|Playout;
closefile(nf);
free(s);
}
void
rmpanel(File* f)
{
File** l;
File** w;
File* fp;
edprint("rmpanel %s\n", f->name);
/* Deleting is a dangerous operation.
* Make sure despite bugs we won't delete on
* following clicks. Safety first.
*/
deleting = 0;
incref(f);
w = newfilewalk(f);
for (l = w; fp = *l; l++){
if (fp->qid.type&QTDIR)
rmpanel(fp);
else {
incref(fp);
if (removefile(fp) < 0)
fprint(2, "rmpanel: %r\n");
}
}
endfilewalk(w);
removefile(f);
}
int
intag(Panel* p, Point xy)
{
int ht;
if (p->flags&Pmore)
ht = 2*Taght;
else
ht = Taght;
return ptinrect(xy, Rect(p->rect.min.x, p->rect.min.y,
p->rect.min.x+Tagwid,
p->rect.min.y+ht));
}
int
wcommand(char* c)
{
char* s;
edprint("command: %s\n", c);
if (!strcmp(c, "Col"))
creatingcol = 1;
else if (!strcmp(c, "Row"))
creatingrow = 1;
else if (!strcmp(c, "Sel"))
identifying = 1;
else if (!strcmp(c, "Del"))
deleting = 1;
else if (!strcmp(c, "Arg"))
copying = 1;
else if (!strcmp(c, "Ox")){
sendp(startc, estrdup9p(Ox));
return 1;
} else if (!strncmp(c, "Ox ", 3)){
c += 3;
while(*c == ' ')
c++;
s = smprint("%s %s", Ox, c);
sendp(startc, s);
return 1;
} else
return 0;
argcursor(1);
return 1;
}
static void
snarfpath(File* f, char* pref)
{
Panel* p;
char* s;
p = f->aux;
if (pref)
s=smprint("%s /devs%s", pref, p->path);
else
s=smprint("/devs%s", p->path);
writefstr("/dev/snarf", s);
free(s);
}
static int
plumbexec(char* dir, char* arg)
{
static int plumbsendfd = -1;
Plumbmsg*m;
if (plumbsendfd < 0)
plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
if (plumbsendfd < 0){
fprint(2, "plumbopen: send: %r\n");
return 0;
}
m = malloc(sizeof(Plumbmsg));
if (m == nil)
return 0;
m->src = estrdup9p(argv0);
m->dst = estrdup9p("exec");
m->wdir= estrdup9p(dir);
m->type = estrdup9p("text");
m->attr = nil;
m->data = smprint("exec %s", arg);
m->ndata= -1;
assert(m->wdir && m->src && m->data);
if (plumbsend(plumbsendfd, m) < 0){
fprint(2, "plumbexec: %r\n");
plumbfree(m);
return 0;
}
plumbfree(m);
return 1;
}
static void
copypath(File* f)
{
Panel* p;
char* s;
char* cmd;
p = f->aux;
s = readfstr("/dev/snarf");
cmd = smprint("%s /devs%s", s, p->path);
plumbexec("/", cmd);
free(cmd);
free(s);
}
void
tagmousecmd(File *f, Cmouse* m, Channel* mc)
{
Panel* p;
Panel* pfp;
File* nf;
int innerok;
p = f->aux;
if (!m->buttons)
return;
innerok = 0;
if (m->buttons == 1){
recv(mc, m);
if (!m->buttons){
if (intag(p, m->xy))
if (p->type == Qcol || p->type == Qrow){
if (p->type == Qcol)
p->type = Qrow;
else
p->type = Qcol;
p->flags |= Predraw;
resize();
}
} else {
if (m->buttons == 3 && intag(p, m->xy)){
do {
recv(mc, m);
} while(m->buttons != 0);
argcursor(1);
snarfpath(f, "Ocp" );
argcursor(0);
return;
}
if (m->buttons == 5){
do {
recv(mc, m);
} while(m->buttons != 0);
argcursor(1);
copypath(f);
argcursor(0);
return;
}
slide:
if (!intag(p, m->xy))
return;
argcursor(1);
if (cookslide(m, mc)){
argcursor(0);
nf = pointinpanel(m->xy, innerok);
if (!innerok)
nf = paneltop(nf);
edprint("move start at %s\n", f->name);
edprint("move end at %s\n", nf->name);
if (nf != f){
pfp = f->parent->aux;
p = nf->aux;
p->flags |= Predraw;
pfp->flags|= Predraw;
movefile(f, nf, m->xy);
}
} else
argcursor(0);
}
} else if (m->buttons == 2 && intag(p, m->xy)){
recv(mc, m);
if (!m->buttons){
maxwin(f);
resize();
} else {
innerok = 1;
goto slide;
}
} else if (m->buttons == 4 && intag(p, m->xy)){
if (cookclick(m, mc)){
if (!(p->flags&Ptop)){
p->flags |= Phide;
pfp = f->parent->aux;
pfp->flags |= (Pmore|Predraw);
resize();
}
}
}
}
int
mousecmdarg(File* f, Cmouse* m, Channel* mc)
{
Panel* p;
char* s;
char* ns;
int istop;
if (creatingcol || creatingrow || deleting || identifying || copying)
if (m->buttons == 1)
if (cookclick(m, mc)){
f = pointinpanel(m->xy, 1);
if (creatingcol){
resetcmd();
mkpanel(Qcol, f);
resize();
return 1;
}
if (creatingrow){
resetcmd();
mkpanel(Qrow, f);
resize();
return 1;
}
if (deleting){
resetcmd();
p = f->aux;
istop = (p->flags&Ptop);
if (istop)
sysfatal("killed by user");
if ((p->type != Qrow && p->type != Qcol) || hastag(f)){
p = f->parent->aux;
p->flags |= Predraw;
rmpanel(f);
}
resize();
return 1;
}
if (identifying){
resetcmd();
snarfpath(f, nil);
return 1;
}
if (copying){
resetcmd();
p = f->aux;
s = readfstr("/dev/snarf");
ns = smprint("%s /devs%s", s, p->path);
writefstr("/dev/snarf", ns);
free(s);
free(ns);
return 1;
}
}
return 0;
}
|