home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d3xx
/
d326
/
snap.lha
/
Snap
/
source
/
snapchars.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-05
|
22KB
|
771 lines
/* Auto: make
*/
IMPORT struct SnapRsrc *SnapRsrc;
#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;
WORD Pattern[5] = {
0,
0x0c3f, /* Frame ....oo....oooooo */
0x3333, /* Char ..oo..oo..oo..oo */
0x1f1f, /* Word ...ooooo...ooooo */
0xffff /* Line oooooooooooooooo */
};
IMPORT LONG xl; /* leftmost x position */
IMPORT LONG xr; /* rightmost x position */
IMPORT LONG yt; /* topmost y position */
IMPORT LONG yb; /* bottommost y position */
LONG minx; /* left limit */
LONG maxx; /* right limit */
LONG maxy; /* bottom limit */
LONG tl, tr; /* used by findword - left and right edge of word */
WORD fw, fh; /* Font width and height used when drawing the frame */
WORD GZZ;
WORD SBM;
IMPORT 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;
UWORD FontWidth;
UWORD Underscore;
UBYTE FontType;
UBYTE LoChar;
UBYTE HiChar;
UWORD Modulo;
UWORD *CharLoc;
UWORD NoOfChars;
UBYTE *SrcData;
IMPORT UBYTE *CharData;
UBYTE IFlags;
IMPORT struct RastPort TempRp, MyRP;
IMPORT struct BitMap TempBM, MyBM;
IMPORT UWORD *TempRaster; /* Used for character recognition */
IMPORT struct Screen *theScreen;
IMPORT struct RastPort rp;
struct Layer *LockedLayer;
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;
Underscore = font->tf_Baseline + 1;
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, 256L * 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((char *)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 + fw; NewFrame[1].y = yt - 1;
NewFrame[2].x = xr + fw; NewFrame[2].y = yb + fh;
NewFrame[3].x = xl - 1; NewFrame[3].y = yb + fh;
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 + fw; NewFrame[1].y = yt - 1;
NewFrame[2].x = xr + fw; NewFrame[2].y = yb + fh;
NewFrame[3].x = xl - 1; NewFrame[3].y = yb + fh;
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 + fw; NewFrame[1].y = yt - 1;
NewFrame[2].x = maxx + fw; NewFrame[2].y = yb;
NewFrame[3].x = xr + fw; NewFrame[3].y = yb;
NewFrame[4].x = xr + fw; NewFrame[4].y = yb + fh;
NewFrame[5].x = minx - 1; NewFrame[5].y = yb + fh;
NewFrame[6].x = minx - 1; NewFrame[6].y = yt + fh;
NewFrame[7].x = xl - 1; NewFrame[7].y = yt + fh;
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 + fw; NewFrame[1].y = yt - 1;
NewFrame[2].x = maxx + fw; NewFrame[2].y = yb + fh;
NewFrame[3].x = minx - 1; NewFrame[3].y = yb + fh;
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 -= fw;
if (tl < minx) {
break;
}
}
tl += fw;
tr = mx;
/* ...and to the right */
while (!IsSpace(tr, my)) {
tr += fw;
if (tr + fw > maxx) {
break;
}
}
tr -= fw;
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;
}
}
if (SnapRsrc->CrawlPtrn == 0) {
Ptrn = Pattern[Unit];
}
}
/* 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(); /* 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 - fh == yb) {
yb += fh;
}
if (yt == yb && xl - fw == xr) {
xr += fw;
}
if (xr > maxx) { /* Check for window bounds */
xr = maxx;
}
if (xl < minx) { /* Check for window bounds */
xl = minx;
}
if (yb > maxy) { /* Check for window bounds */
yb = maxy;
}
}
/* The actual character snapper. It actually works. :-) */
WORD SnapChars()
{
LONG width;
LONG height;
UBYTE *SnapSpace;
ULONG SnapSize;
ULONG counter;
REGISTER LONG x, y;
/* Check coordinates */
if (yt - fh == yb) { /* No rows, shouldn't happen */
return 0;
}
if (yt == yb && xl - fw == xr) { /* Nothing at all */
return 0;
}
/* Calculate stuff */
width = maxx - (minx + 1) + fw + fw; /* Add one for a LF */
height = yb - yt + fh;
SnapSize = ((width / fw) + 1) * (height / fh);
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;
}
IFlags = 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 */
UnlockLayer(LockedLayer);
/* Clear our work area */
BltClear((char *)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 += fw, counter++) {
CopyChar(x, yt, COPY);
if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
}
}
if (Unit == UNIT_LINE) {
while (counter && SnapSpace[counter-1] == ' ') {
counter--;
}
}
} else { /* Multiple lines */
if (Unit == UNIT_FRAME) {
minx = xl;
maxx = xr;
}
/* Read first line */
for (x = xl; x <= maxx; x += fw, counter++) {
CopyChar(x, yt, COPY);
if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
}
}
if (Unit == UNIT_FRAME) {
SnapSpace[counter++] = 10;
} else {
SHORT endspace = (SnapSpace[counter-1] == ' ');
/* Remove trailing blanks */
while (counter && SnapSpace[counter-1] == ' ') {
counter--;
}
if (endspace || !(SnapRsrc->flags & JOINLONG)) {
SnapSpace[counter++] = 10;
}
}
/* If more than two rows - read full middle rows */
if (yt + fh != yb) {
for (y = yt + fh; y < yb; y += fh) {
for (x = minx; x <= maxx; x += fw, counter++) {
CopyChar(x, y, COPY);
if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
}
}
if (Unit == UNIT_FRAME) {
SnapSpace[counter++] = 10;
} else {
SHORT endspace = (SnapSpace[counter-1] == ' ');
/* Remove trailing blanks */
while (counter && SnapSpace[counter-1] == ' ') {
counter--;
}
if (endspace || !(SnapRsrc->flags & JOINLONG)) {
SnapSpace[counter++] = 10;
}
}
}
}
/* Read last line */
for (x = minx; x <= xr; x += fw, counter++) {
CopyChar(x, yb, COPY);
if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
}
}
/* 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 */
LockedLayer = window->WLayer;
LockLayer(0L, LockedLayer);
/* Don't want to wreck somebody's rastport */
CopyMem((char *)window->RPort, (char *)&rp, (LONG)sizeof(struct RastPort));
/* Or his picture */
SetDrMd(&rp, COMPLEMENT);
rp.Mask = SnapRsrc->FrameMask;
/* Find out what we're trying to read */
SetSnapFont(rp.Font);
if (FontWidth == -1) {
UnlockLayer(LockedLayer);
action = noaction;
return 0;
}
if (window->Flags & GIMMEZEROZERO) {
GZZ = 1;
} else {
GZZ = 0;
}
if (window->Flags & SUPER_BITMAP) {
SBM = 1;
} else {
SBM = 0;
}
/* Find a position */
xl = (GZZ ? window->GZZMouseX : window->MouseX)
+ window->RPort->Layer->Scroll_X;
yt = (GZZ ? window->GZZMouseY : window->MouseY)
+ window->RPort->Layer->Scroll_Y;
if (xl < 0) {
xl = 0;
}
if (yt < 0) {
yt = 0;
}
/* Check your position */
if (xl > (GZZ ? window->GZZWidth : window->Width) ||
yt > (GZZ ? window->GZZHeight : window->Height)) {
UnlockLayer(LockedLayer);
action = noaction;
return 0;
}
IFlags = 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 struct CacheWindow *cw = GetCachedWindow(theScreen, window);
if (cw) {
xoff = - ((xl - cw->xoff) % cw->fw);
yoff = - ((yt - cw->yoff) % cw->fh);
BltClear((char *)TempRaster, 32L, 0L);
ClipBlit(&rp, xl + xoff, yt + yoff,
&TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
WaitBlit();
if (interpret(TempRaster) != 255) {
goto found;
}
}
/* No cache or cache didn't match */
xl -= 7;
yt -= 7;
BltClear((char *)TempRaster, 32L, 0L);
xoff = 0;
while (xoff < (16 - FontWidth)) {
ClipBlit(&rp, xl + xoff, yt,
&TempRp, 0L, 0L, (LONG)FontWidth, 16L, COPY);
WaitBlit();
yoff = 0;
while (yoff < (16 - FontHeight)) {
if (interpret(&TempRaster[yoff]) != 255) {
goto found;
}
++yoff;
}
++xoff;
}
/* No character found. Back off */
UnlockLayer(LockedLayer);
action = noaction;
return 0;
found:
/* Ok, now we know where to look for chars.
** xoff and yoff is character position within our 16x16 bitmap.
*/
xl = xl + xoff; /* Adjust x */
yt = yt + yoff; /* Adjust y */
fw = FontWidth;
fh = FontHeight;
{
SHORT temp = fh;
while (temp <= fh + 1) { /* Check for extra pixel row */
BltClear((char *)TempRaster, 32L, 0L);
ClipBlit(&rp, xl, yt + temp,
&TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
WaitBlit();
if (interpret(TempRaster) != 255) {
fh = temp;
break;
}
++temp;
}
}
/* Find out offsets within the window */
xoff = xl % fw;
yoff = yt % fh;
if (cw) {
cw->xoff = xoff;
cw->yoff = yoff;
cw->fw = fw;
cw->fh = fh;
} else {
CacheWindow(window, xoff, yoff, fw, fh);
}
}
/* Set bounds */
minx = xoff;
maxx = minx +
(((GZZ ?
window->GZZWidth :
window->Width - window->BorderRight
/* Hack for borderless conman windows */
+ (window->Flags & BORDERLESS && window->Flags & WINDOWSIZING ? 14 : 0))
- minx - fw) / fw) * fw;
maxy = ((GZZ ? window->GZZHeight : window->Height) / fh) * fh;
/* Check bounds */
if (xl > maxx) {
UnlockLayer(LockedLayer);
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 = SnapRsrc->StartUnit;
Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[Unit]);
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) && (SnapRsrc->CrawlPtrn != 0xffff)) {
crawl_frame(0L);
}
mx = (LONG)(GZZ ? window->GZZMouseX : window->MouseX)
+ window->RPort->Layer->Scroll_X;
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) % fw);
my = (LONG)(GZZ ? window->GZZMouseY : window->MouseY)
+ window->RPort->Layer->Scroll_Y;
if (my < 0) {
my = 0;
}
/* Calculate which row is closest */
if ((my - yt) < (yb - my)) {
closey = closetop;
} else {
closey = closebottom;
}
my = my - ((my - yoff) % fh);
/* 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();
UnlockLayer(LockedLayer);
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();
}
}
}