home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d3xx
/
d326
/
vsnap.lha
/
VSnap
/
snapchars.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-05
|
19KB
|
676 lines
#include "snap.h"
#define COPY 0xC0L
#define INVCOPY 0x30L
#define CopyChar(_x, _y, _m) \
BltBitMap(&MyBM, (LONG)_x, (LONG)_y, \
&TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, \
_m, -1L, NULL); \
WaitBlit()
WORD Unit;
IMPORT WORD StartUnit;
LONG xl; /* leftmost x position */
LONG xr; /* rightmost x position */
LONG yt; /* topmost y position */
LONG yb; /* bottommost y position */
LONG minx; /* left limit */
LONG maxx; /* right limit */
LONG tl, tr; /* used by findword - left and right edge of word */
LONG mx, my; /* Mouse position in character steps */
#define closetop 0
#define closebottom 1
WORD closey;
#define closeleft 0
#define closeright 1
WORD closex;
struct Window *window; /* The window we're snapping from */
/* Data for font being snapped */
UWORD FontHeight;
UBYTE FontType;
UWORD FontWidth;
UBYTE LoChar;
UBYTE HiChar;
UWORD Modulo;
UWORD *CharLoc;
UWORD NoOfChars;
UBYTE *SrcData;
IMPORT UBYTE *CharData;
IMPORT struct RastPort TempRp, MyRP;
IMPORT struct BitMap TempBM, MyBM;
IMPORT WORD FrameMask;
IMPORT UWORD *TempRaster; /* Used for character recognition */
IMPORT struct Screen *theScreen;
IMPORT struct Layer_Info *LockedLayerInfo;
IMPORT struct RastPort rp;
IMPORT UWORD CrawlPtrn;
IMPORT LONGBITS cancelsignal, donesignal, movesignal, clicksignal, timersignal;
IMPORT WORD action;
WORD starting;
/* Init vars with font data.
*/
VOID SetSnapFont(font)
struct TextFont *font;
{
if (!font) {
FontWidth = -1;
return;
}
FontHeight = font->tf_YSize;
FontType = font->tf_Flags;
FontWidth = (FontType & FPF_PROPORTIONAL ? -1 : font->tf_XSize);
if (FontWidth == -1) {
return;
}
LoChar = font->tf_LoChar;
HiChar = font->tf_HiChar;
Modulo = font->tf_Modulo;
CharLoc = (UWORD *)font->tf_CharLoc;
NoOfChars = HiChar-LoChar+1;
Modulo = font->tf_Modulo;
SrcData = (UBYTE *)font->tf_CharData;
BltClear(CharData, 224L*32, 0L);
WaitBlit();
CopyFont();
}
/* Check if the character at x, y is a space
*/
WORD IsSpace(x, y)
LONG x, y;
{
REGISTER WORD i = FontHeight-1;
REGISTER UWORD *data = &TempRaster[i];
/* Copy character at x, y */
BltClear(TempRaster, 32L, 0L);
ClipBlit(&rp, x, y,
&TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
WaitBlit();
if (*data) { /* Try inverted copy */
ClipBlit(&rp, x, y,
&TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, INVCOPY);
WaitBlit();
}
while (i--) {
if (*data--) {
return 0;
}
}
return 1;
}
#define ShortFrame 4L /* Square frame - columnar select */
#define LongFrame 8L /* Strange frame - char or word select */
IMPORT LONG OFType; /* Old frame type: ShortFrame/LongFrame */
IMPORT UWORD Ptrn;
IMPORT Point OldFrame[];
IMPORT Point NewFrame[];
/* update_frame calculates the new frame,
** erases the old frame and draws the new one.
** It's all pretty obvious if you take it slowly.
*/
VOID update_frame()
{
LONG ft;
switch (Unit) {
case UNIT_FRAME: {
/*********\
* *
* *
\*********/
NewFrame[0].x = xl-1; NewFrame[0].y = yt-1;
NewFrame[1].x = xr+FontWidth; NewFrame[1].y = yt-1;
NewFrame[2].x = xr+FontWidth; NewFrame[2].y = yb+FontHeight;
NewFrame[3].x = xl-1; NewFrame[3].y = yb+FontHeight;
NewFrame[4].x = xl-1; NewFrame[4].y = yt-1;
ft = ShortFrame;
break;
}
case UNIT_CHAR:
case UNIT_WORD: {
if (yt == yb) { /* On the same line - same as UNIT_FRAME */
NewFrame[0].x = xl-1; NewFrame[0].y = yt-1;
NewFrame[1].x = xr+FontWidth; NewFrame[1].y = yt-1;
NewFrame[2].x = xr+FontWidth; NewFrame[2].y = yb+FontHeight;
NewFrame[3].x = xl-1; NewFrame[3].y = yb+FontHeight;
NewFrame[4].x = xl-1; NewFrame[4].y = yt-1;
ft = ShortFrame;
} else {
/*****\
****** *
* *
* *****
*******/
NewFrame[0].x = xl-1; NewFrame[0].y = yt-1;
NewFrame[1].x = maxx+FontWidth; NewFrame[1].y = yt-1;
NewFrame[2].x = maxx+FontWidth; NewFrame[2].y = yb;
NewFrame[3].x = xr+FontWidth; NewFrame[3].y = yb;
NewFrame[4].x = xr+FontWidth; NewFrame[4].y = yb+FontHeight;
NewFrame[5].x = minx-1; NewFrame[5].y = yb+FontHeight;
NewFrame[6].x = minx-1; NewFrame[6].y = yt+FontHeight;
NewFrame[7].x = xl-1; NewFrame[7].y = yt+FontHeight;
NewFrame[8].x = xl-1; NewFrame[8].y = yt-1;
ft = LongFrame;
}
break;
}
case UNIT_LINE: {
NewFrame[0].x = minx-1; NewFrame[0].y = yt-1;
NewFrame[1].x = maxx+FontWidth; NewFrame[1].y = yt-1;
NewFrame[2].x = maxx+FontWidth; NewFrame[2].y = yb+FontHeight;
NewFrame[3].x = minx-1; NewFrame[3].y = yb+FontHeight;
NewFrame[4].x = minx-1; NewFrame[4].y = yt-1;
ft = ShortFrame;
break;
}
default: {
break;
}
}
draw_frame(ft);
}
VOID FindWord()
{
/* Must remove frame to be able to search for spaces */
WaitTOF();
erase_frame();
tl = mx;
/* Find a space to the left... */
while (!IsSpace(tl, my)) {
tl -= FontWidth;
if (tl < minx) {
break;
}
}
tl += FontWidth;
tr = mx;
/* ...and to the right */
while (!IsSpace(tr, my)) {
tr += FontWidth;
if (tr+FontWidth > maxx) {
break;
}
}
tr -= FontWidth;
if (tr < tl) {
tl = xl;
tr = xr;
}
}
/* ChangeUnit cycles the unit of selection. The differents units
are: character, word and line.
*/
VOID ChangeUnit()
{
switch (Unit) {
case UNIT_FRAME: {
Unit = UNIT_CHAR;
break;
}
case UNIT_CHAR: {
Unit = UNIT_WORD;
FindWord();
xl = tl;
xr = tr;
break;
}
case UNIT_WORD: {
Unit = UNIT_LINE;
xl = minx;
xr = maxx;
break;
}
case UNIT_LINE: {
Unit = UNIT_FRAME;
xl = xr = mx;
break;
}
}
}
/* ExtendSelection extends the current selection according to
the mouse position and the selected unit.
Note that ExtendSelection doesn't optimize moves that don't
make any difference. FIXME
*/
VOID ExtendSelection()
{
/* Fix which row we're talking about */
if (closey == closetop) { /* Find closest row */
yt = my; /* change top row */
} else {
yb = my; /* change bottom row */
}
/* Take care of left and right character pos */
switch (Unit) {
case UNIT_FRAME: {
if (closex == closeleft) {
xl = mx;
} else {
xr = mx;
}
break;
}
case UNIT_CHAR: {
if (yt == yb) { /* One line */
if (closex == closeleft) {
xl = mx;
} else {
xr = mx;
}
} else { /* Multiple lines */
if (yt == my) {
xl = mx; /* At top - set left */
} else {
xr = mx; /* At bottom - set right */
}
}
break;
}
case UNIT_WORD: {
FindWord(mx, my); /* Find the word */
if (yt == yb) { /* One line */
if (closex == closeleft) { /* Find closest char pos */
xl = tl;
} else {
xr = tr;
}
} else { /* Multiple lines */
if (yt == my) { /* Where am I */
xl = tl; /* At top - set left */
} else {
xr = tr; /* At bottom - set right */
}
}
break;
}
case UNIT_LINE: { /* Always full width */
break;
}
}
if (yt-FontHeight == yb) {
yb += FontHeight;
}
if (yt == yb && xl-FontWidth == xr) {
xr += FontWidth;
}
if (xr > maxx) { /* Check for window bounds */
xr = maxx;
}
if (xl < minx) { /* Check for window bounds */
xl = minx;
}
}
/* The actual character snapper. It actually works. */
WORD SnapChars()
{
REGISTER struct RastPort MyRastPort;
LONG width;
LONG height;
UBYTE *SnapSpace;
ULONG SnapSize;
ULONG counter;
REGISTER LONG x, y;
/* Check coordinates */
if (yt-FontHeight == yb) { /* No rows, shouldn't happen */
return 0;
}
if (yt == yb && xl-FontWidth == xr) { /* Nothing at all */
return 0;
}
/* Calculate stuff */
width = maxx - (minx+1) + FontWidth+FontWidth; /* Add one for a LF */
height = yb - yt + FontHeight;
SnapSize = ((width/FontWidth)+1) * (height/FontHeight);
counter = 0;
/* Initialize things */
InitRastPort(&MyRP);
InitBitMap(&MyBM, 1L, width, height);
MyRP.BitMap = &MyBM;
SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC|MEMF_CLEAR);
/* Please insert more memory */
if (!SnapSpace) {
return 0;
}
MyBM.Planes[0] = AllocRaster(width, height);
if (!MyBM.Planes[0]) {
FreeMem(SnapSpace, SnapSize);
return 0;
}
/* Make a local copy of the snapped chars */
ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY);
/* Ok, now we've got a copy of the character data */
/* Now it's ok to mess with the layers again */
UnlockLayers(LockedLayerInfo);
/* Clear our work area */
BltClear(TempRaster, 32L, 0L);
/* Calculate bounds */
xl -= minx;
xr -= minx;
maxx -= minx;
minx = 0;
yb -= yt;
yt = 0;
/* Single line - needs to be handled separately */
if (yt == yb) { /* Ok, we've got one */
/* Read from left to right */
for (x=xl; x<=xr; x+=FontWidth, counter++) {
CopyChar(x, yt, COPY);
if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
SnapSpace[counter] = 63; /* Unrecognized changed to ? */
}
}
} else { /* Multiple lines */
if (Unit == UNIT_FRAME) {
minx = xl;
maxx = xr;
}
/* Read first line */
for (x=xl; x<=maxx; x+=FontWidth, counter++) {
CopyChar(x, yt, COPY);
if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
SnapSpace[counter] = 63; /* Unrecognized changed to ? */
}
}
if (Unit == UNIT_FRAME) {
SnapSpace[counter++] = 10;
} else {
/* Remove trailing blanks */
while (counter && SnapSpace[counter-1] == ' ') {
counter--;
}
SnapSpace[counter++] = 10;
}
/* If more than two rows - read full middle rows */
if (yt+FontHeight != yb) {
for (y=yt+FontHeight; y<yb; y+=FontHeight) {
for (x=minx; x<=maxx; x+=FontWidth, counter++) {
CopyChar(x, y, COPY);
if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
SnapSpace[counter] = 63; /* Unrecognized - ? */
}
}
if (Unit == UNIT_FRAME) {
SnapSpace[counter++] = 10;
} else {
/* Remove trailing blanks */
while (counter && SnapSpace[counter-1] == ' ') {
counter--;
}
SnapSpace[counter++] = 10;
}
}
}
/* Read last line */
for (x=minx; x<=xr; x+=FontWidth, counter++) {
CopyChar(x, yb, COPY);
if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
SnapSpace[counter] = 63; /* Unrecognized changed to ? */
}
}
/* Remove trailing blanks */
while (counter && SnapSpace[counter-1] == ' ') {
counter--;
}
}
FreeRaster(MyBM.Planes[0], width, height);
SaveClip(SnapSpace, counter);
FreeMem(SnapSpace, SnapSize);
return 1;
}
/* HandleChars is the part of the Snap state machine that handles
snapping of characters. The selection is done in different
units: char, word, line.
*/
WORD HandleChars()
{
LONG xoff, yoff;
LONG ox, oy;
/* Find out which screen we're working on */
theScreen = WhichScreen();
/* Oops, no screen? */
if (!theScreen) {
action = noaction;
return 0;
}
/* Ok, what window? */
window = WhichWindow(theScreen);
/* Oh dear, no window. */
if (!window) {
action = noaction;
return 0;
}
/* No messing with the layers while I think */
LockedLayerInfo = &window->WScreen->LayerInfo;
LockLayers(LockedLayerInfo);
/* Don't want to wreck somebody's rastport */
CopyMem(window->RPort, &rp, (long)sizeof(struct RastPort));
/* Or his picture */
SetDrMd(&rp, COMPLEMENT);
rp.Mask = FrameMask;
Ptrn = CrawlPtrn;
SetDrPt(&rp, Ptrn);
/* Find out what we're trying to read */
SetSnapFont(rp.Font);
if (FontWidth == -1) {
UnlockLayers(LockedLayerInfo);
action = noaction;
return 0;
}
/* Find a position */
xl = window->MouseX - 7;
yt = window->MouseY - 7;
if (xl<0) {
xl = 0;
}
if (yt<0) {
yt = 0;
}
/* Check your position */
if (xl>window->Width || yt>window->Height) {
UnlockLayers(LockedLayerInfo);
action = noaction;
return 0;
}
/* Find out the offset for the clicked character, if any.
** This is the part that makes it special. Simple, isn't it. Hah!
*/
{
REGISTER SHORT found = 0;
BltClear(TempRaster, 32L, 0L);
xoff = 0;
while ((xoff<(16-FontWidth)) && !found) {
ClipBlit(&rp, xl+xoff, yt,
&TempRp, 0L, 0L, (LONG)FontWidth, 16L, COPY);
WaitBlit();
yoff = 0;
while ((yoff<(16-FontHeight)) && !found) {
if (interpret(&TempRaster[yoff]) != 255) {
found = 1;
}
++yoff;
}
++xoff;
}
/* Did we find a character? */
if (!found) {
/* No, back off */
UnlockLayers(LockedLayerInfo);
action = noaction;
return 0;
}
}
/* Ok, now we know where to look for chars.
** xoff and yoff is character position within our 16x16 bitmap.
*/
xl = xl + xoff-1; /* Adjust x */
yt = yt + yoff-1; /* Adjust y */
/* Find out offsets within the window */
xoff = xl % FontWidth;
yoff = yt % FontHeight;
/* Set bounds */
minx = xoff;
maxx = minx+((window->Width-minx-FontWidth
-(window->Flags & BORDERLESS ? 0 : 2)
-(window->Flags & WINDOWSIZING ? 12 : 0))/FontWidth)*FontWidth;
/* Check bounds */
if (xl>maxx) {
UnlockLayers(LockedLayerInfo);
action = noaction;
return 0;
}
/* Set box dimensions */
xr = xl;
yb = yt;
ox = xr;
oy = yt;
/* Select unit while starting */
starting = 1;
/* Starting unit is character or frame */
Unit = StartUnit;
OFType = 0L;
update_frame();
/* Get the state machine running */
FOREVER {
/* Wait for something to happen */
REGISTER LONGBITS sig =
Wait(movesignal|cancelsignal|donesignal|clicksignal|timersignal);
if ((sig & timersignal) && (CrawlPtrn != 0xffff)) {
crawl_frame(0L);
}
mx = (LONG)window->MouseX;
if (mx<0) {
mx = 0;
}
/* Calculate which edge is closest */
if ((mx-xl) < (xr-mx)) {
closex = closeleft;
} else {
closex = closeright;
}
/* Only interested in real char pos */
mx = mx - ((mx-xoff) % FontWidth);
my = (LONG)window->MouseY;
if (my<0) {
my = 0;
}
/* Calculate which row is closest */
if ((my-yt) < (yb-my)) {
closey = closetop;
} else {
closey = closebottom;
}
my = my - ((my-yoff) % FontHeight);
/* Hey, it moves! It's alive!! */
if ((sig & movesignal) && (action == snaptext)) {
if (mx != ox || my != oy) { /* Something's happened */
ExtendSelection();
update_frame();
starting = 0;
ox = mx;
oy = my;
sig &= ~clicksignal;
}
}
/* Ok, forget it... */
if (sig & cancelsignal) {
erase_frame();
UnlockLayers(LockedLayerInfo);
return 0;
}
/* Click */
if ((sig & clicksignal) && (action == snaptext)) {
/* Selecting unit */
if (starting) {
if (mx == ox && my == oy) {
ChangeUnit();
if (Unit == UNIT_CHAR) {
ChangeUnit();
}
update_frame();
} else if (Unit == UNIT_FRAME) {
ChangeUnit();
update_frame();
}
}
if (mx != ox || my != oy) { /* Click in a new place */
ExtendSelection();
update_frame();
starting = 0;
ox = mx;
oy = my;
}
}
/* Finished */
if (sig & donesignal) {
erase_frame();
return SnapChars();
}
}
}