#include "paint.h" typedef void Op(Widget *, Mousectl *, int); static Op tlcorner, tedge, trcorner; static Op ledge, move, redge; static Op blcorner, bedge, brcorner; static Op sweep; typedef struct State { Cursor *c; Op *f; } State; static State statetab[] = { {&topleft, tlcorner}, {&top, tedge}, {&topright, trcorner}, {&cross, sweep}, {&left, ledge}, {&box, move}, {&right, redge}, {&cross, sweep}, {&bottomleft, blcorner}, {&bottom, bedge}, {&bottomright, brcorner}, {&cross, sweep}, {&cross, sweep}, {&cross, sweep}, {&cross, sweep}, {&cross, sweep}, }; static int region1(int m, int emin, int emax, int om, int im) { if(m < emin - om) return 3; if(m <= emin + im) return 0; if(m < emax - im) return 1; if(m <= emax + om) return 2; return 3; } static State * regionstate(Point m, Rectangle r) { enum { om = 8 }; int imx, imy, reg; /* calculate the interior margins so that there is at least an 8*8 space for the center region */ imx = clampint(0, (r.max.x - r.min.x - om) / 2, om); imy = clampint(0, (r.max.y - r.min.y - om) / 2, om); reg = region1(m.x, r.min.x, r.max.x, om, imx); reg |= region1(m.y, r.min.y, r.max.y, om, imy) << 2; return &statetab[reg]; } static void sweep(Widget *w, Mousectl *mctl, int but) { Canvas *c; Rectangle r; Point p, q; c = w->aux; c->sel.active = 0; p = mctl->xy; do { q = mctl->xy; r = clamprect(stomrect(canonrect(Rpt(p, q)), w), c->s->mem->r); w->redraw(w, RDall); antsrect(w->screen, w->r, mtosrect(r, w)); readmouse(mctl); } while((mctl->buttons & 7) == but); if(mctl->buttons == 0) { if(c->sel.active = !eqpt(p, q)) c->sel.r = r; } } static void move(Widget *w, Mousectl *mctl, int but) { Canvas *c; Point m; /* the position of the mouse within the selection */ Rectangle s; /* the area of the selection relative to 0,0 */ Point p; /* the location of the new selection on the image */ c = w->aux; s = rectsubpt(c->sel.r, c->sel.r.min); c->sel.active = 0; m = subpt(stompt(mctl->xy, w), c->sel.r.min); do { p = subpt(stompt(mctl->xy, w), m); w->redraw(w, RDall); antsrect(w->screen, w->r, mtosrect(rectaddpt(s, p), w)); readmouse(mctl); } while((mctl->buttons & 7) == but); if(mctl->buttons == 0) { c->sel.r = rectaddpt(s, p); c->sel.active = 1; } } #define EDGE(NAME, DIM, PT) \ static void \ NAME(Widget *w, Mousectl *mctl, int but) \ { \ Canvas *c; \ Point itmp; \ Rectangle s, r; \ int m; /* the position of the mouse relative to the edge */ \ \ c = w->aux; \ s = c->sel.r; \ itmp = stompt(mctl->xy, w); \ m = itmp.DIM - s.PT.DIM; \ c->sel.active = 0; \ do { \ itmp = stompt(mctl->xy, w); \ s.PT.DIM = itmp.DIM - m; \ r = clamprect(canonrect(s), c->s->mem->r); \ w->redraw(w, RDall); \ antsrect(w->screen, w->r, mtosrect(r, w)); \ readmouse(mctl); \ } while((mctl->buttons & 7) == but); \ \ if(mctl->buttons == 0) { \ c->sel.r = r; \ c->sel.active = 1; \ } \ } \ EDGE(tedge, y, min) EDGE(bedge, y, max) EDGE(ledge, x, min) EDGE(redge, x, max) #define CORNER(NAME, X, Y) \ static void \ NAME(Widget *w, Mousectl *mctl, int but) \ { \ Canvas *c; \ Rectangle s, r; \ Point m; /* the position of the mouse relative to the corner */ \ Point p; \ \ c = w->aux; \ s = c->sel.r; \ m = subpt(stompt(mctl->xy, w), Pt(X, Y)); \ c->sel.active = 0; \ do { \ p = subpt(stompt(mctl->xy, w), m); \ X = p.x; \ Y = p.y; \ r = clamprect(canonrect(s), c->s->mem->r); \ w->redraw(w, RDall); \ antsrect(w->screen, w->r, mtosrect(r, w)); \ readmouse(mctl); \ } while((mctl->buttons & 7) == but); \ \ if(mctl->buttons == 0) { \ c->sel.r = r; \ c->sel.active = 1; \ } \ } \ CORNER(tlcorner, s.min.x, s.min.y) CORNER(trcorner, s.max.x, s.min.y) CORNER(blcorner, s.min.x, s.max.y) CORNER(brcorner, s.max.x, s.max.y) static int mouse(Widget *w, Mousectl *mctl) { Canvas *c; State *state; Point oldxy; Selection oldsel; c = w->aux; while(ptinrect(mctl->xy, w->r)) { state = c->sel.active ? regionstate(mctl->xy, mtosrect(c->sel.r, w)) : &statetab[3]; fastsetcursor(mctl, state->c); if(mctl->buttons & 7) { oldxy = mctl->xy; oldsel = c->sel; state->f(w, mctl, mctl->buttons); if(mctl->buttons != 0) { // moveto(mctl, oldxy); c->sel = oldsel; w->redraw(w, RDall); while(mctl->buttons) readmouse(mctl); } } else { readmouse(mctl); } } fastsetcursor(mctl, nil); return 0; } CanvasTool rselect = { mouse, };