/* :ts=4 * * Amiga SnipIt 1.2 * (c) (opyright 1987,1988 - Scott Evernden - All Rights Reserved * * hand.c - input event handler & snipper & lib function replacements * */ #include "hs.h" int state; /* mouse state */ int snip; /* container type which is highlighted */ int maxx, maxy; /* maximum cells in snipped layer */ int origx, origy; /* pixel origin in conunit */ int charx, chary; /* pixel size of char cell of conunit */ int lastx, lasty; /* last cell highlighted */ int con_offx, con_offy; /* correction offsets for console windows */ int win_offx, win_offy; /* correction offsets for non-console windows */ int snipx[2], snipy[2]; /* snip area; top/left to bottom/right */ int left, right; /* sides of snip area, irrespective of rows */ struct TextFont *capttf; /* non-NULL indicates recognition required */ struct Window *snipw; /* clipped text window */ struct RastPort *sniprp; /* rastport of clipped text window */ struct RastPort captrp; /* rastport holding clipped snip area */ struct BitMap captbm; /* bitmap into which snipped area is copied */ int captx, capty; /* dimensions of capture map */ int jobFlag; /* flag input handler to ignore mouse events */ int lock_layer; /* lock window/console layer while snipping */ int windows=1; /* include windows in layer search */ int cmd1 = IEQUALIFIER_LCOMMAND; int cmd2 = IEQUALIFIER_LALT; extern struct IntuitionBase *IntuitionBase; extern struct ConsoleBase *ConsoleBase; extern struct Task *myTask; extern int mySignal; /* this does one at a time */ struct InputEvent *doEvent(); /*********************************************/ #asm public _geta4 ; Trap these Gfx/Intui functions; purpose is to remove hilighting, if nec. ; Not all possible cases are handled (window resizing, for example), but ; the most common ones are. public _myRectFill public _myScrollRaster public _myCloseWindow public _oldRectFill public _oldScrollRaster public _oldCloseWindow _myRectFill: ; pardon me move.l a4,-(sp) jsr _geta4 ; establish addressing tst.w _snip beq.s 1$ ; no highlighted area; get out cmpa.l _sniprp,a1 bne.s 1$ ; not the same RastPort; get out movem.l a1/d0-d5,-(sp) jsr _clearHi ; de-highlight movem.l (sp)+,a1/d0-d5 1$: movea.l _oldRectFill,a0 movea.l (sp)+,a4 jmp (a0) ; continue into library _myScrollRaster: ; 'scuse move.l a4,-(sp) jsr _geta4 tst.w _snip beq.s 1$ cmpa.l _sniprp,a1 bne.s 1$ movem.l a1/d0-d5,-(sp) jsr _clearHi movem.l (sp)+,a1/d0-d5 1$: movea.l _oldScrollRaster,a0 movea.l (sp)+,a4 jmp (a0) _myCloseWindow: move.l a4,-(sp) jsr _geta4 tst.w _snip beq.s 1$ cmpa.l _snipw,a0 bne.s 1$ ; not the same Window; get out clr.w _snip clr.l _capttf ; Window closing; reset indicators 1$: movea.l _oldCloseWindow,a1 movea.l (sp)+,a4 jmp (a1) ;************************ ; input event stream glue public _handlerCode _handlerCode: movem.l d2/d3/a0/a1/a4/a6,-(sp) ; i think this is right jsr _geta4 jsr _myHandler movem.l (sp)+,d2/d3/a0/a1/a4/a6 rts #endasm /*********************************************/ /* SnipIt's input event handler */ struct InputEvent *myHandler(d2, d3, ev) long d2, d3; register struct InputEvent *ev; { register struct InputEvent *inev, **evp; struct InputEvent *outev; if (jobFlag) return ev; inev = ev; outev = NULL; /* back-pointer */ evp = &outev; /* * Loop thru the possibly linked list of events. * We remove the ones having meaning to SnipIt, and leave the others */ while (inev) { ev = inev; inev = ev->ie_NextEvent; /* ensure that main code isn't running and this is a mouse event */ if (ev->ie_Class == IECLASS_RAWMOUSE) ev = doEvent(ev); /* patch back-pointer */ if (*evp = ev) evp = &ev->ie_NextEvent; } /* pass 'em along */ return outev; } /*********************************************/ /* handle a single (mouse) input event */ struct InputEvent *doEvent(ev) register struct InputEvent *ev; { static int lflag, rflag, cmd; register UWORD code; register int x, y; x = ev->ie_X; y = ev->ie_Y; code = ev->ie_Code; /* in mid-snip? */ if (lflag && code == IECODE_NOBUTTON && (ev->ie_Qualifier & IEQUALIFIER_LEFTBUTTON)) { mouse(M_MOVE, x, y); return ev; } /* button transition event... */ code &= ~IECODE_UP_PREFIX; /* mouse button down event? */ if ((ev->ie_Code & IECODE_UP_PREFIX) == 0) { if (cmd = ev->ie_Qualifier & (cmd1 | cmd2)) { if (!rflag && code == IECODE_LBUTTON) { lflag++; mouse(M_DOWN, x, y); } else if (!lflag && code == IECODE_RBUTTON) rflag++; /* note transition */ return NULL; } } /* release of left mouse button? */ else if (lflag && code == IECODE_LBUTTON) { lflag = 0; mouse(M_UP, x, y); return NULL; } /* release of right mouse button? */ else if (rflag && code == IECODE_RBUTTON) { rflag = 0; /* kick main code */ jobFlag = cmd; Signal(myTask, 1L << mySignal); return NULL; } /* event back into stream */ return ev; } /*********************************************/ /* find a console containing the layer holding (x,y); return success flag */ int whichConsole(layer, x, y) struct Layer *layer; int x, y; { register struct ConUnit *cu, *rcu; register struct Node *node; /* result conunit */ rcu = NULL; _Forbid(); /* begin at the beginning */ node = ConsoleBase->conUnits.lh_Head; /* next is NULL when back at listhead */ while (node->ln_Succ) { cu = (struct ConUnit *) node; /* see if console window's layer is the same */ if (cu && cu->cu_Window && cu->cu_Window->RPort->Layer == layer) { rcu = cu; /* found it */ break; } node = node->ln_Succ; } Permit(); if (rcu) { snip = CON_SNIP; snipw = rcu->cu_Window; sniprp = snipw->RPort; charx = rcu->cu_XRSize; chary = rcu->cu_YRSize; origx = rcu->cu_XROrigin; origy = rcu->cu_YROrigin; maxx = rcu->cu_XMax; maxy = rcu->cu_YMax; } return rcu != NULL; } /*********************************************/ /* find a window containing the layer holding (x,y); return success flag */ int whichWindow(s, layer, x, y) struct Screen *s; struct Layer *layer; int x, y; { register struct Window *w, *rw; if (!windows) return NULL; /* result window */ rw = NULL; _Forbid(); w = s->FirstWindow; while (w) { if (w->WLayer == layer) { rw = w; break; } w = w->NextWindow; } Permit(); if (rw) { snip = WIN_SNIP; snipw = rw; sniprp = snipw->RPort; charx = sniprp->Font->tf_XSize; chary = sniprp->Font->tf_YSize; origx = rw->BorderLeft; origy = rw->BorderTop; maxx = (rw->Width - rw->BorderRight - origx) / charx - 1; maxy = (rw->Height - rw->BorderBottom - origy) / chary - 1; } return rw != NULL; } /*********************************************/ /* handle meaningful mouse activity */ mouse(event, mx, my) int event; register int mx, my; { static struct Screen *s; static struct Layer *layer; if (event == M_DOWN) s = IntuitionBase->FirstScreen; /* correct raw positions according to this screen */ if (!(s->ViewPort.Modes & LACE)) my /= 2; mx += s->MouseX - 2; /* accumulate deltas */ my += s->MouseY - 1; /* x,y adjusted for feel */ if (event == M_DOWN) { /* de-hilight, if nec. */ if (snip) hiSnip(0); /* turn flag off */ snip = 0; /* locate pointed-at layer */ if ((layer = WhichLayer(&s->LayerInfo, (long) mx, (long) my)) && (whichConsole(layer, mx, my) || whichWindow(s, layer, mx, my))) { /* if mouse down in title line area, remain clear */ if (my - snipw->TopEdge < origy) snip = 0; } } /* nothing interesting */ if (!snip) return; /* mouse to window-relative cell coordinates */ mx = (mx - snipw->LeftEdge - origx) / charx; if (mx < 0) mx = 0; else if (maxx < mx) mx = maxx; my = (my - snipw->TopEdge - origy) / chary; if (my < 0) my = 0; else if (maxy < my) my = maxy; /* highlighting games ahead */ if (event == M_DOWN) { state = M_DOWN; if (lock_layer) LockLayerRom(layer); snipx[0] = mx; snipy[0] = my; hiLite(mx, my, 1, 1); } else if (event == M_UP) { snipx[1] = mx; snipy[1] = my; if (state == M_MOVE) hiLite(lastx, lasty, 1, 1); hiLite(snipx[0], snipy[0], 1, 1); hiSnip(charx == 8); state = M_UP; if (charx != 8) /* only able to do 8 pixel wide fonts */ clearHi(); if (lock_layer) UnlockLayerRom(layer); } else if (mx != lastx || my != lasty) { if (state == M_MOVE) hiLite(lastx, lasty, 1, 1); hiLite(lastx = mx, lasty = my, 1, 1); state = M_MOVE; } } /*********************************************/ /* de-highlight; snip is known to be set */ clearHi() { if (state == M_UP) hiSnip(0); else if (lock_layer) return; else { hiLite(snipx[0], snipy[0], 1, 1); if (state == M_MOVE) hiLite(lastx, lasty, 1, 1); } snip = 0; } /*********************************************/ /* local cleanup for this module */ finiHand() { int i; PLANEPTR p; if (snip) clearHi(); if (p = captbm.Planes[0]) FreeRaster(p, (long) captx, (long) capty); } /*********************************************/ /* manufacture rastport with bitmap, ready to receive captured bitmap */ int allocMap(sx, sy) int sx, sy; { PLANEPTR p; /* release previous, if any */ if (p = captbm.Planes[0]) { FreeRaster(p, (long) captx, (long) capty); captbm.Planes[0] = NULL; } /* record new map size */ captx = sx; capty = sy; /* build new bitmap to contain snipped area */ InitBitMap(&captbm, 1L, (long) captx, (long) capty); InitRastPort(&captrp); captrp.BitMap = &captbm; /* allocate bitmap planes */ p = (PLANEPTR) AllocRaster((long) captx, (long) capty); if (!p) return 0; captbm.Planes[0] = p; return 1; } /*********************************************/ /* video reverse the capture area; perform capture if flagged */ hiSnip(capt) int capt; { register int px, py, qx, qy, tx, ty; long ox, oy; /* need these vars to be handy */ tx = maxx; /* take care of backward snip areas */ if (snipy[0] < snipy[1] || snipy[0] == snipy[1] && snipx[0] <= snipx[1]) { px = snipx[0]; py = snipy[0]; qx = snipx[1]; qy = snipy[1]; } else { px = snipx[1]; py = snipy[1]; qx = snipx[0]; qy = snipy[0]; } /* only if capturing more than 1 cell... */ if (capt && (px != qx || py != qy)) { /* left and right sides */ left = px; right = qx; /* get a new bitmap */ if (allocMap((tx + 1) * charx, (qy - py + 1) * chary)) { /* copy console contents into snip-map */ ox = origx; oy = origy + py * chary; if (snip == CON_SNIP) { /* user-specified corrections */ ox += con_offx; oy += con_offy; } else { ox += win_offx; oy += win_offy; } ClipBlit(sniprp, ox, oy, &captrp, 0L, 0L, (long) captx, (long) capty, 0xC0L); /* note new info in snip-map */ capttf = sniprp->Font; } else { /* no memory, act dumb */ snip = captx = capty = 0; return; } } /* perform hilighting */ while (py <= qy) { if (py == qy) tx = qx; hiLite(px, py, tx - px + 1, 1); px = 0; py++; } } /*********************************************/ /* low-lever video reverser */ hiLite(x, y, xs, ys) int x, y, xs, ys; { register long ox, oy; ox = origx + x * charx; oy = origy + y * chary; if (snip == CON_SNIP) { /* user-specified corrections */ ox += con_offx; oy += con_offy; } else { ox += win_offx; oy += win_offy; } ClipBlit(sniprp, ox, oy, sniprp, ox, oy, (long) (xs * charx), (long) (ys * chary), 0x50L); } /*********************************************/