home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
c_news
/
14
/
paint.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-20
|
34KB
|
1,302 lines
/* PAINT.C
*
* Scott R. Houck
* Written in Turbo C 2.0
*
* Add the EGAVGA.BGI driver to graphics.lib using the BGIOBJ program.
*
* Compile with: tcc -ml paint graphics.lib
*
* This is a simple paint program
*/
#include <stdio.h>
#include <math.h>
#include <dos.h>
#include <mem.h>
#include <alloc.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>
#include <ctype.h>
#include <graphics.h>
/* Mouse buttons */
#define LEFTBUTTON 1
#define RIGHTBUTTON 2
/* Clipping */
#define CLIPPING_ON 1
#define CLIPPING_OFF 0
/* Boolean values */
#define TRUE 1
#define FALSE 0
/* Dialog box options */
#define YES 1
#define NO 0
/* Menu choices */
#define IGNORE -1
#define PAINT 0
#define FILL 1
#define ERASER 2
#define CLEAR 3
#define SAVE 4
#define LOAD 5
#define QUIT 6
#define RUBBER_LINE 7
#define RUBBER_RECTANGLE 8
#define LINE 0
#define RECTANGLE 1
/* Some useful typedefs */
typedef struct pointtype POINT; /* A point with x and y as ints */
typedef POINT EXTENT [2]; /* Rectangular extent */
/* Function prototypes */
void InitializeGraphics(void);
void DrawScreen(void);
int MouseReset(int *);
void MouseOn(void);
void MouseOff(void);
int MouseStatus(POINT *);
void MouseWaitForPress(int, POINT *);
void MouseWaitForRelease(int, POINT *);
void MouseSetCursor(int [16][2]);
void HighlightMenu(int, int, int);
int PointInExtent(POINT, EXTENT);
void HandleDraw(POINT);
int PickCorrInMenu(POINT);
int PickCorrInColor(POINT);
int PickCorrInPattern(POINT);
void HandlePick(POINT);
void SetForeground(int);
void SetBackground(int);
void SetPattern(int);
void DoPaint(POINT);
void DoFill(POINT);
void DoEraser(POINT);
void DoClear(void);
void DoSave(void);
void DoLoad(void);
void DoRubber(int, POINT);
int DialogBox(void);
void Beep(void);
void LowBeep(void);
int GetChar(char *, char *, int *);
char * GetString(char *, int, int, int, char *, char *, char *, int,
int (*)(int, int));
int PromptForFilename(char *);
/* Global variables */
int maxx, maxy; /* Maximum pixel values */
int dminx, dminy, dmaxx, dmaxy; /* Drawing area coordinates */
int bgminx, bgminy, bgmaxx, bgmaxy; /* Background box */
int fgminx, fgminy, fgmaxx, fgmaxy; /* Foreground box */
int rl1x, rl1y, rl2x, rl2y; /* Rubber line coordinates */
int rr1x, rr1y, rr2x, rr2y; /* Rubber rectangle coordinates */
int xminx, xminy, xmaxx, xmaxy; /* Dialog box coordinates */
EXTENT drawExtent; /* Extent of the drawing area */
EXTENT colorExtent[16]; /* Extents of the 16 color boxes */
EXTENT patternExtent[11]; /* Extents of the 11 patterns */
EXTENT yesExtent, noExtent; /* Extent of the YES/NO buttons */
int currentColor; /* Current foreground color */
int fillPattern; /* Current fill pattern */
int fillColor; /* Current fill color */
unsigned dialogSize; /* Dialog box image size */
unsigned drawSize; /* Drawing size */
unsigned promptSize; /* Size of prompt box */
void *dialogBuffer, *saveBuffer; /* Dialog box and screen buffers */
void *promptBuffer, *drawBuffer; /* Prompt box and drawing buffers */
int fminx, fminy, fmaxx, fmaxy; /* File prompt box coords */
int promptx, prompty; /* File prompt x and y coords */
struct {
EXTENT extent;
char *text;
} menuBox[10]; /* menu buttons */
int mode; /* current mode */
/* The following two arrays define the eraser-type cursor and the
* regular arrow cursor for use in the MouseSetCursor() routine.
*/
int eraser [16][2] = {
{ 0xFFFF, 0xFFFF }, /* screen mask */
{ 0xFFFF, 0xFFFF },
{ 0xFFFF, 0xFFFF },
{ 0xFFFF, 0xFFFF },
{ 0xFFFF, 0xFFFF },
{ 0xFFFF, 0xFFFF },
{ 0xFFFF, 0xFFFF },
{ 0xFFFF, 0xFFFF },
{ 0xFFFF, 0x8001 }, /* cursor mask */
{ 0x8001, 0x8001 },
{ 0x8001, 0x8001 },
{ 0x8001, 0xFFFF },
{ 0x0000, 0x0000 },
{ 0x0000, 0x0000 },
{ 0x0000, 0x0000 },
{ 0x0000, 0x0000 }
};
int cursor [16][2] = {
{ 0x3FFF, 0x1FFF }, /* screen mask */
{ 0x0FFF, 0x07FF },
{ 0x03FF, 0x01FF },
{ 0x00FF, 0x007F },
{ 0x003F, 0x001F },
{ 0x01FF, 0x10FF },
{ 0x30FF, 0xF87F },
{ 0xF87F, 0xFC7F },
{ 0x0000, 0x4000 }, /* cursor mask */
{ 0x6000, 0x7000 },
{ 0x7800, 0x7C00 },
{ 0x7E00, 0x7F00 },
{ 0x7F80, 0x7C00 },
{ 0x6C00, 0x4600 },
{ 0x0600, 0x0300 },
{ 0x0300, 0x0000 }
};
main()
{
POINT position;
int buttonPressed;
InitializeGraphics();
DrawScreen();
MouseOn();
HighlightMenu(mode = PAINT, LIGHTGRAY, BLACK);
while (mode != QUIT)
{
do
{
buttonPressed = MouseStatus(&position);
if (mode == ERASER && PointInExtent(position, drawExtent))
MouseSetCursor(eraser);
else
MouseSetCursor(cursor);
}
while (!(buttonPressed & (RIGHTBUTTON | LEFTBUTTON)));
if (PointInExtent(position, drawExtent))
HandleDraw(position);
else
HandlePick(position);
}
MouseOff();
closegraph();
}
/* InitializeGraphics() initializes the graphics package and mouse driver.
* If there is an error, the program aborts with an appropriate error
* message.
*/
void InitializeGraphics()
{
int graphDriver, graphMode, errorCode;
int numberOfButtons;
if (MouseReset(&numberOfButtons) == 0)
{
printf("Mouse driver is not installed\n");
exit(1);
}
if (numberOfButtons < 2)
{
printf("This program requires a mouse with at least two buttons\n");
exit(2);
}
if (registerbgidriver(EGAVGA_driver) < 0)
exit(1);
graphDriver = DETECT;
initgraph(&graphDriver, &graphMode, "");
errorCode = graphresult();
if (errorCode != grOk)
{
printf("Graphics System Error: %s\n", grapherrormsg(errorCode));
exit(1);
}
/* Get maximum x and y screen coordinates */
maxx = getmaxx();
maxy = getmaxy();
}
void DrawScreen()
{
int i;
int cminx, cminy, cmaxx, cmaxy; /* color box coordinates */
int pminx, pminy, pmaxx, pmaxy; /* pattern box coordinates */
int cwidth; /* width of color box */
int cheight; /* height of color box */
int pwidth; /* width of pattern box */
int gap; /* gap between various objects */
int bminx, bminy, bmaxx, bmaxy; /* Menu buttons */
int bwidth, bheight, bgap, bstart; /* Menu buttons */
int dwidth, dheight; /* Drawing area dimensions */
int xwidth, xheight; /* Dialog box dimensions */
int yminx, yminy, ymaxx, ymaxy; /* YES button */
int nminx, nminy, nmaxx, nmaxy; /* NO button */
int fwidth, fheight; /* Height of file prompt box */
static char *boxText[] = { "PAINT", "FILL", "ERASER", "CLEAR", "SAVE",
"LOAD", "QUIT", "", "" };
setvisualpage(0);
setactivepage(0);
/* Draw the main background */
setcolor(WHITE);
rectangle(0, 0, maxx, maxy);
setfillstyle(INTERLEAVE_FILL, CYAN);
floodfill(1, 1, WHITE);
/* Draw the drawing area */
drawExtent[0].x = dminx = (int)(0.30 * maxx);
drawExtent[0].y = dminy = (int)(0.05 * maxy);
drawExtent[1].x = dmaxx = (int)(0.95 * maxx);
drawExtent[1].y = dmaxy = (int)(0.80 * maxy);
drawSize = imagesize(dminx, dminy, dmaxx, dmaxy);
drawBuffer = malloc(drawSize);
dwidth = dmaxx - dminx;
dheight = dmaxy - dminy;
setfillstyle(SOLID_FILL, WHITE);
setcolor(WHITE);
rectangle(dminx-1, dminy-1, dmaxx+1, dmaxy+1);
floodfill(dminx, dminy, WHITE);
/* Draw the dialog box */
setactivepage(1);
xwidth = (int)(0.35 * dwidth);
xheight = (int)(0.25 * dheight);
xminx = dminx + (dwidth - xwidth) / 2;
xminy = dminy + (dheight - xheight) / 2;
xmaxx = xminx + xwidth;
xmaxy = xminy + xheight;
rectangle(xminx, xminy, xmaxx, xmaxy); /* The outline */
yesExtent[0].x = yminx = xminx + (int)(0.10 * xwidth);
yesExtent[0].y = yminy = xminy + (int)(0.60 * xheight);
yesExtent[1].x = ymaxx = xminx + (int)(0.40 * xwidth);
yesExtent[1].y = ymaxy = xminy + (int)(0.90 * xheight);
rectangle(yminx, yminy, ymaxx, ymaxy);
setfillstyle(SOLID_FILL, BLUE);
floodfill(yminx+1, yminy+1, WHITE); /* YES button */
noExtent[0].x = nminx = xminx + (int)(0.60 * xwidth);
noExtent[0].y = nminy = yminy;
noExtent[1].x = nmaxx = xminx + (int)(0.90 * xwidth);
noExtent[1].y = nmaxy = ymaxy;
rectangle(nminx, nminy, nmaxx, nmaxy);
floodfill(nminx+1, nminy+1, WHITE); /* NO button */
setfillstyle(SOLID_FILL, LIGHTGRAY);
floodfill(xminx+1, xminy+1, WHITE); /* The interior */
settextjustify(CENTER_TEXT, CENTER_TEXT);
moveto(xminx+xwidth/2, xminy+(yminy-xminy)/2);
setcolor(BLACK);
outtext("Are you sure?");
setcolor(WHITE);
moveto((yminx+ymaxx)/2, (yminy+ymaxy)/2);
outtext("YES");
moveto((nminx+nmaxx)/2, (nminy+nmaxy)/2);
outtext("NO");
setcolor(WHITE);
/* Save dialog box in memory */
dialogSize = imagesize(xminx, xminy, xmaxx, xmaxy);
dialogBuffer = malloc(dialogSize);
getimage(xminx, xminy, xmaxx, xmaxy, dialogBuffer);
/* Draw the prompt box */
cleardevice();
fwidth = (int)(0.35 * dwidth);
fheight = (int)(0.20 * dheight);
fminx = dminx + (int)(0.25 * dwidth);
fminy = dminy + (dheight - fheight) / 2;
fmaxx = fminx + fwidth;
fmaxy = fminy + fheight;
rectangle(fminx, fminy, fmaxx, fmaxy); /* The outline */
promptx = fminx + (int)(0.40 * fwidth);
prompty = (fminy + fmaxy) / 2;
rectangle(promptx-5, prompty-fheight/6, fminx + (int)(0.90 * fwidth),
prompty+fheight/6); /* Draw the filename input box */
setfillstyle(SOLID_FILL, CYAN);
floodfill(fminx+1, fminy+1, WHITE);
moveto(fminx+8, prompty);
setcolor(BLACK);
settextjustify(LEFT_TEXT, CENTER_TEXT);
outtext("File:");
setcolor(WHITE);
setfillstyle(SOLID_FILL, WHITE);
floodfill(promptx+1, prompty, WHITE);
/* Save the prompt box in memory */
promptSize = imagesize(fminx, fminy, fmaxx, fmaxy);
promptBuffer = malloc(promptSize);
getimage(fminx, fminy, fmaxx, fmaxy, promptBuffer);
setactivepage(0);
/* Draw the color boxes */
cwidth = (int)((dmaxx - dminx) / 16.0);
cheight = (int)(0.07 * maxy);
gap = (int)(0.025 * maxy);
cminy = dmaxy + gap;
cmaxy = cminy + cheight;
for (i = 0; i < 16; i++)
{
colorExtent[i][0].x = cminx = dminx + i * cwidth;
colorExtent[i][0].y = cminy;
colorExtent[i][1].x = cmaxx = cminx + cwidth;
colorExtent[i][1].y = cmaxy;
rectangle(cminx, cminy, cmaxx, cmaxy);
setfillstyle(SOLID_FILL, i);
floodfill(cminx+3, cminy+3, WHITE);
}
/* Draw the pattern boxes */
pwidth = (int)((dmaxx - dminx) / 11.0);
pminy = cmaxy + gap;
pmaxy = pminy + cheight;
for (i = 0; i < 11; i++)
{
patternExtent[i][0].x = pminx = dminx + i * pwidth;
patternExtent[i][0].y = pminy;
patternExtent[i][1].x = pmaxx = pminx + pwidth;
patternExtent[i][1].y = pmaxy;
rectangle(pminx, pminy, pmaxx, pmaxy);
setfillstyle(i+1, WHITE);
floodfill(pminx+3, pminy+3, WHITE);
}
/* Draw the menu buttons */
bheight = (int)(0.055 * maxy);
bwidth = (int)(0.150 * maxx);
bgap = (int)(0.025 * maxy);
bstart = (int)(0.050 * maxy);
setfillstyle(SOLID_FILL, BLUE);
bminx = (int)(0.05 * maxx);
for (i = 0; i < 9; i++)
{
bminy = (int)(i * (bheight + bgap)) + bstart;
bmaxx = bminx + bwidth;
bmaxy = bminy + bheight;
rectangle(bminx, bminy, bmaxx, bmaxy);
floodfill(bminx+1, bminy+1, WHITE);
moveto(bminx+bwidth/2, bminy+bheight/2);
settextjustify(CENTER_TEXT, CENTER_TEXT);
outtext(boxText[i]);
/* Initialize the menuBox info */
menuBox[i].extent[0].x = bminx;
menuBox[i].extent[0].y = bminy;
menuBox[i].extent[1].x = bmaxx;
menuBox[i].extent[1].y = bmaxy;
menuBox[i].text = boxText[i];
if (i == RUBBER_LINE)
{
rl1x = bminx + (int)(0.20 * (bmaxx-bminx));
rl1y = bmaxy - (int)(0.20 * (bmaxy-bminy));
rl2x = bmaxx - (int)(0.20 * (bmaxx-bminx));
rl2y = bminy + (int)(0.20 * (bmaxy-bminy));
line(rl1x, rl1y, rl2x, rl2y);
}
if (i == RUBBER_RECTANGLE)
{
rr1x = bminx + (int)(0.20 * (bmaxx-bminx));
rr1y = bminy + (int)(0.20 * (bmaxy-bminy));
rr2x = bmaxx - (int)(0.20 * (bmaxx-bminx));
rr2y = bmaxy - (int)(0.20 * (bmaxy-bminy));
rectangle(rr1x, rr1y, rr2x, rr2y);
}
}
/* Draw the foreground/background box */
bgminx = (int)(0.15 * maxx);
bgminy = (int)(0.83 * maxy);
bgmaxx = (int)(0.25 * maxx);
bgmaxy = (int)(0.97 * maxy);
rectangle(bgminx, bgminy, bgmaxx, bgmaxy);
fgminx = bgminx + (int)(0.20 * (bgmaxx-bgminx));
fgminy = bgminy + (int)(0.20 * (bgmaxy-bgminy));
fgmaxx = bgmaxx - (int)(0.20 * (bgmaxx-bgminx));
fgmaxy = bgmaxy - (int)(0.20 * (bgmaxy-bgminy));
rectangle(fgminx, fgminy, fgmaxx, fgmaxy);
setfillstyle(SOLID_FILL, WHITE);
floodfill(bgminx+3, bgminy+3, WHITE);
setfillstyle(SOLID_FILL, BLACK);
floodfill(fgminx+3, fgminy+3, WHITE);
/* Set defaults */
currentColor = BLACK;
fillPattern = SOLID_FILL;
fillColor = WHITE;
setcolor(currentColor);
setfillstyle(fillPattern, fillColor);
setviewport(dminx, dminy, dmaxx, dmaxy, CLIPPING_ON);
}
/* MouseReset() returns the current status of the mouse hardware and
* software. The mouse status is 0 if the mouse hardware and software
* are not installed or -1 if the hardware and software are installed.
*
* This function also resets the mouse driver to the default values.
* The number of buttons is returned in numberOfButtons.
*/
int MouseReset(int *numberOfButtons)
{
union REGS inregs, outregs;
inregs.x.ax = 0; /* Mouse Function 0 -- Mouse Reset and Status */
int86(0x33, &inregs, &outregs);
*numberOfButtons = outregs.x.bx;
return outregs.x.ax;
}
/* MouseOn() shows the mouse cursor. */
void MouseOn()
{
union REGS inregs, outregs;
inregs.x.ax = 1; /* Mouse Function 1 -- Show Cursor */
int86(0x33, &inregs, &outregs);
}
/* MouseOff() hides the mouse cursor. */
void MouseOff()
{
union REGS inregs, outregs;
inregs.x.ax = 2; /* Mouse function 2 -- Hide Cursor */
int86(0x33, &inregs, &outregs);
}
/* MouseStatus() returns the state of the left and right mouse buttons
* and the horizontal and vertical coordinates of the cursor.
*
* The button status is a single integer value. Bit 0 represents the
* left button; bit 1 represents the right button. These bits are 1
* if the corresponding button is down, and 0 if it is up.
*/
int MouseStatus(POINT *position)
{
union REGS inregs, outregs;
inregs.x.ax = 3; /* Mouse function 3 --
Get Button Status and Mouse Position */
int86(0x33, &inregs, &outregs);
position->x = outregs.x.cx;
position->y = outregs.x.dx;
return outregs.x.bx; /* Button status */
}
/* MouseWaitForPress() puts the program in a wait state until the
* user presses the specified mouse button.
*/
void MouseWaitForPress(int button, POINT *posptr)
{
int buttonPressed;
do
buttonPressed = MouseStatus(posptr);
while (!(buttonPressed & button));
}
/* MouseWaitForRelease() puts the program in a wait state until the
* user releases the specified mouse button.
*/
void MouseWaitForRelease(int button, POINT *posptr)
{
int buttonPressed;
do
buttonPressed = MouseStatus(posptr);
while (buttonPressed & button);
}
void MouseSetCursor(int picture[16][2])
{
struct SREGS segregs;
union REGS inregs, outregs;
segread(&segregs);
inregs.x.ax = 9; /* Mouse function 9 -- Set Graphics Cursor */
inregs.x.bx = 0;
inregs.x.cx = 0;
inregs.x.dx = (int) picture;
segregs.es = segregs.ds;
int86x(0x33, &inregs, &outregs, &segregs);
}
/* HighlightMenu() highlights the specified menu box. */
void HighlightMenu(int box, int background, int foreground)
{
struct viewporttype view;
struct fillsettingstype fill;
int color;
int bminx = menuBox[box].extent[0].x;
int bminy = menuBox[box].extent[0].y;
int bmaxx = menuBox[box].extent[1].x;
int bmaxy = menuBox[box].extent[1].y;
MouseOff();
/* Get attributes */
getviewsettings(&view);
getfillsettings(&fill);
color = getcolor();
setviewport(bminx, bminy, bmaxx, bmaxy, CLIPPING_OFF);
clearviewport();
setviewport(0, 0, maxx, maxy, CLIPPING_OFF);
setcolor(WHITE);
rectangle(bminx, bminy, bmaxx, bmaxy);
setfillstyle(SOLID_FILL, background);
floodfill(bminx+1, bminy+1, WHITE);
settextjustify(CENTER_TEXT, CENTER_TEXT);
setcolor(foreground);
moveto((bminx + bmaxx) / 2, (bminy + bmaxy) / 2);
outtext(menuBox[box].text);
if (box == RUBBER_LINE)
line(rl1x, rl1y, rl2x, rl2y);
if (box == RUBBER_RECTANGLE)
rectangle(rr1x, rr1y, rr2x, rr2y);
/* Reset attributes */
setviewport(view.left, view.top, view.right, view.bottom, view.clip);
setfillstyle(fill.pattern, fill.color);
setcolor(color);
MouseOn();
}
/* PointInExtent() returns a boolean value specifying whether a point
* is in a certain extent.
*/
int PointInExtent(POINT pt, EXTENT ext)
{
return ext[0].x <= pt.x && pt.x <= ext[1].x &&
ext[0].y <= pt.y && pt.y <= ext[1].y;
}
/* HandleDraw() dispatches to the correct routine depending on the
* current mode while the user has the mouse cursor in the drawing
* area.
*/
void HandleDraw(POINT position)
{
int numberOfButtons;
switch (mode)
{
case PAINT:
DoPaint(position);
break;
case FILL:
DoFill(position);
break;
case ERASER:
DoEraser(position);
break;
case RUBBER_LINE:
DoRubber(LINE, position);
break;
case RUBBER_RECTANGLE:
DoRubber(RECTANGLE, position);
break;
}
}
/* PickCorrInMenu() performs pick correlation within the menu box area. */
int PickCorrInMenu(POINT pt)
{
int i;
for (i = 0; i < 9; i++)
if (PointInExtent(pt, menuBox[i].extent))
return i;
return IGNORE;
}
/* PickCorrInColor() performs pick correlation within the foreground and
* background color boxes.
*/
int PickCorrInColor(POINT pt)
{
int i;
for (i = 0; i < 16; i++)
if (PointInExtent(pt, colorExtent[i]))
return i;
return IGNORE;
}
/* PickCorrInPattern() performs pick correlation within the pattern
* boxes.
*/
int PickCorrInPattern(POINT pt)
{
int i;
for (i = 0; i < 11; i++)
if (PointInExtent(pt, patternExtent[i]))
return i;
return IGNORE;
}
/* HandlePick() sets the current mode of the program and handles other
* cases when the mouse cursor is outside of the drawing area.
*/
void HandlePick(POINT position)
{
int choice;
if ((choice = PickCorrInMenu(position)) != IGNORE)
switch (choice)
{
case PAINT:
HighlightMenu(mode, BLUE, WHITE);
HighlightMenu(mode = PAINT, LIGHTGRAY, BLACK);
break;
case FILL:
HighlightMenu(mode, BLUE, WHITE);
HighlightMenu(mode = FILL, LIGHTGRAY, BLACK);
break;
case ERASER:
HighlightMenu(mode, BLUE, WHITE);
HighlightMenu(mode = ERASER, LIGHTGRAY, BLACK);
break;
case CLEAR:
HighlightMenu(mode, BLUE, WHITE);
HighlightMenu(CLEAR, LIGHTGRAY, BLACK);
DoClear();
HighlightMenu(CLEAR, BLUE, WHITE);
HighlightMenu(mode = PAINT, LIGHTGRAY, BLACK);
break;
case SAVE:
HighlightMenu(mode, BLUE, WHITE);
HighlightMenu(SAVE, LIGHTGRAY, BLACK);
DoSave();
HighlightMenu(SAVE, BLUE, WHITE);
HighlightMenu(mode, LIGHTGRAY, BLACK);
break;
case LOAD:
HighlightMenu(mode, BLUE, WHITE);
HighlightMenu(LOAD, LIGHTGRAY, BLACK);
DoLoad();
HighlightMenu(LOAD, BLUE, WHITE);
HighlightMenu(mode, LIGHTGRAY, BLACK);
break;
case QUIT:
if (DialogBox() == YES)
mode = QUIT;
break;
case RUBBER_LINE:
HighlightMenu(mode, BLUE, WHITE);
HighlightMenu(mode = RUBBER_LINE, LIGHTGRAY, BLACK);
break;
case RUBBER_RECTANGLE:
HighlightMenu(mode, BLUE, WHITE);
HighlightMenu(mode = RUBBER_RECTANGLE, LIGHTGRAY, BLACK);
break;
}
else if ((choice = PickCorrInColor(position)) != IGNORE)
{
if (MouseStatus(&position) & LEFTBUTTON)
SetForeground(choice);
else
SetBackground(choice);
}
else if ((choice = PickCorrInPattern(position)) != IGNORE)
SetPattern(choice);
}
/* SetForeground() sets the current color (foreground) which is used
* when drawing.
*/
void SetForeground(int color)
{
MouseOff();
currentColor = color;
setcolor(currentColor);
setviewport(fgminx+1, fgminy+1, fgmaxx-1, fgmaxy-1, CLIPPING_ON);
clearviewport();
setfillstyle(SOLID_FILL, color);
floodfill(3, 3, WHITE);
setfillstyle(fillPattern, fillColor);
setviewport(dminx, dminy, dmaxx, dmaxy, CLIPPING_ON);
MouseOn();
}
/* SetBackground() sets the current fill color, which is also the color
* used when the drawing area is cleared by selecting the CLEAR option
* from the menu buttons.
*/
void SetBackground(int color)
{
MouseOff();
fillColor = color;
setviewport(bgminx+1, bgminy+1, bgmaxx-1, bgmaxy-1, CLIPPING_ON);
clearviewport();
setfillstyle(fillPattern, fillColor);
floodfill(3, 3, WHITE);
MouseOn();
SetForeground(currentColor);
}
/* SetPattern() sets the current fill pattern, which is also the pattern
* used when the drawing area is cleared by selecting the CLEAR option
* from the menu buttons.
*/
void SetPattern(int pattern)
{
MouseOff();
fillPattern = pattern + 1;
setfillstyle(fillPattern, fillColor);
MouseOn();
SetBackground(fillColor);
}
/* DoPaint() handles the paint option. */
void DoPaint(POINT position)
{
int first = TRUE;
POINT oldpt = position;
moveto(position.x-dminx, position.y-dminy);
while (MouseStatus(&position) & LEFTBUTTON)
if (first || position.x != oldpt.x || position.y != oldpt.y)
{
first = FALSE;
MouseOff();
lineto(position.x-dminx, position.y-dminy);
oldpt = position;
MouseOn();
}
}
/* DoFill() handles the fill option. The floodfill() function requires
* that the border color be specified, so DoFill() compares pixels in
* increasing x coordinates until a different color is found, and then
* uses that color as the border color argument to floodfill().
*/
void DoFill(POINT position)
{
int interior, border;
int x = position.x-dminx;
MouseWaitForRelease(LEFTBUTTON, &position);
MouseOff();
interior = getpixel(position.x-dminx, position.y-dminy);
do
border = getpixel(++x, position.y-dminy);
while (border == interior);
floodfill(position.x-dminx, position.y-dminy, border);
MouseOn();
}
/* DoEraser handles the ERASER option. It uses a rectangular cursor as
* an eraser, drawing lines in the background color. If the cursor is
* moved outside the drawing area, the eraser reverts to the normal cursor
* shape.
*/
void DoEraser(POINT position)
{
int i, x, y, first = TRUE;
POINT oldpt = position;
setcolor(fillColor);
while (MouseStatus(&position) & LEFTBUTTON)
{
if (PointInExtent(position, drawExtent))
MouseSetCursor(eraser);
else
MouseSetCursor(cursor);
if (first || position.x != oldpt.x || position.y != oldpt.y)
{
first = FALSE;
MouseOff();
x = position.x - dminx;
y = position.y - dminy;
for (i = 0; i < 8; i++)
line(x, y+i, x+15, y+i);
oldpt = position;
MouseOn();
}
}
setcolor(currentColor);
}
/* DoClear() clears the drawing area in the current background color and
* pattern after receiving confirmation from the user by means of a dialog
* box.
*/
void DoClear()
{
if (DialogBox() == YES)
{
MouseOff();
clearviewport();
floodfill(5, 5, WHITE);
MouseOn();
}
}
/* DoSave() saves the drawing */
void DoSave()
{
FILE *outfile;
char filename[13];
PromptForFile(filename);
if ((outfile = fopen(filename, "wb")) == NULL)
return;
setviewport(0, 0, maxx, maxy, CLIPPING_ON);
MouseOff();
getimage(dminx, dminy, dmaxx, dmaxy, drawBuffer);
MouseOn();
setviewport(dminx, dminy, dmaxx, dmaxy, CLIPPING_ON);
fwrite(drawBuffer, drawSize, 1, outfile);
fclose(outfile);
}
/* DoLoad() loads a file into the drawing area. */
void DoLoad()
{
FILE *infile;
char filename[13];
int status;
status = PromptForFile(filename);
if (status != 0) /* File does not exist */
{
LowBeep();
return;
}
if ((infile = fopen(filename, "rb")) == NULL)
return;
fread(drawBuffer, drawSize, 1, infile);
fclose(infile);
setviewport(0, 0, maxx, maxy, CLIPPING_ON);
MouseOff();
putimage(dminx, dminy, drawBuffer, COPY_PUT);
MouseOn();
setviewport(dminx, dminy, dmaxx, dmaxy, CLIPPING_ON);
}
/* DoRubber() performs a rubber line/rectangle drawing routine. */
void DoRubber(int type, POINT position)
{
POINT anchor = position;
POINT oldpt = position;
setwritemode(XOR_PUT);
setcolor(currentColor ^ 15);
moveto(anchor.x-dminx, anchor.y-dminy);
while (MouseStatus(&position) & LEFTBUTTON)
{
if (position.x != oldpt.x || position.y != oldpt.y)
{
MouseOff();
/* erase old and draw new */
if (type == LINE)
{
line(anchor.x-dminx, anchor.y-dminy, oldpt.x-dminx,
oldpt.y-dminy);
line(anchor.x-dminx, anchor.y-dminy, position.x-dminx,
position.y-dminy);
}
else
{
rectangle(anchor.x-dminx, anchor.y-dminy, oldpt.x-dminx,
oldpt.y-dminy);
rectangle(anchor.x-dminx, anchor.y-dminy, position.x-dminx,
position.y-dminy);
}
oldpt = position;
MouseOn();
}
}
setcolor(currentColor);
setwritemode(COPY_PUT);
/* draw final */
MouseOff();
if (type == LINE)
line(anchor.x-dminx, anchor.y-dminy, position.x-dminx,
position.y-dminy);
else
rectangle(anchor.x-dminx, anchor.y-dminy, position.x-dminx,
position.y-dminy);
MouseOn();
}
/* DialogBox() pops up a dialog box containing the message "Are you sure?"
* It returns YES or NO depending on the user's choice.
*/
int DialogBox()
{
POINT position;
int choice, done = FALSE;
struct viewporttype view;
MouseOff();
getviewsettings(&view);
setviewport(0, 0, maxx, maxy, CLIPPING_OFF); /* Entire screen */
/* Save the screen area under where the dialog box will display */
saveBuffer = malloc(dialogSize);
getimage(xminx, xminy, xmaxx, xmaxy, saveBuffer);
/* Display the dialog box */
putimage(xminx, xminy, dialogBuffer, COPY_PUT);
MouseOn();
do
{
MouseWaitForPress(LEFTBUTTON, &position);
MouseWaitForRelease(LEFTBUTTON, &position);
if (PointInExtent(position, yesExtent))
{
choice = YES;
done = TRUE;
}
else if (PointInExtent(position, noExtent))
{
choice = NO;
done = TRUE;
}
}
while (!done);
/* Restore the screen area and free the buffer */
MouseOff();
putimage(xminx, xminy, saveBuffer, COPY_PUT);
free(saveBuffer);
MouseOn();
setviewport(view.left, view.top, view.right, view.bottom, view.clip);
return choice;
}
void Beep()
{
sound(1000);
delay(150);
nosound();
}
void LowBeep()
{
sound(100);
delay(150);
nosound();
}
/* GetChar() gets a character from the keyboard. legalchars and
* legalscans are strings that contain the characters and scan codes
* that the function will accept.
*/
int GetChar(char *legalchars, char *legalscans, int *scancode)
{
int ch, ok;
do
{
ch = getch();
if ((ch == '\0') && kbhit()) /* extended key */
ok = (strchr(legalscans, *scancode = getch()) != NULL);
else
ok = (strchr(legalchars, ch) != NULL);
if (!ok)
Beep();
}
while (!ok);
return ch;
}
/* GetString() gets a string of input */
char *GetString(char *inpstr, int x, int y, int width, char *deflt,
char *legalchars, char *legalscans, int upcaseFlag,
int (*keyHandler)(int, int))
{
char ch, temp[2], blanks[80];
int len, scancode, done = FALSE;
/* blanks is a string of character 219's -- block characters */
memset(blanks, 219, width);
blanks[width] = '\0';
settextjustify(LEFT_TEXT, CENTER_TEXT);
inpstr[0] = '\0'; /* Initialize the string to empty */
/* Write the default */
moveto(x, y);
outtext(deflt);
do
{
len = strlen(inpstr);
ch = GetChar(legalchars, legalscans, &scancode);
if (upcaseFlag)
ch = toupper(ch);
switch (ch)
{
case '\b': /* Backspace */
if (len == 0)
Beep();
else
{
inpstr[len-1] = '\0'; /* Truncate the string */
/* Blank out the input area and write the input string */
setcolor(WHITE);
moveto(x, y);
outtext(blanks);
setcolor(BLACK);
moveto(x, y);
if (strlen(inpstr) == 0)
outtext(deflt);
else
outtext(inpstr);
}
break;
case '\x1b': /* Escape key */
/* Blank out the input area and write the default */
setcolor(WHITE);
moveto(x, y);
outtext(blanks);
setcolor(BLACK);
inpstr[0] = '\0';
moveto(x, y);
outtext(deflt);
break;
case '\r':
done = TRUE;
break;
case '\0': /* Handle function keys if desired */
done = (*keyHandler)(ch, scancode);
break;
default:
if (len < width)
{
if (len == 0)
{
setcolor(WHITE);
moveto(x, y);
outtext(blanks);
setcolor(BLACK);
moveto(x, y);
}
temp[0] = ch;
temp[1] = '\0';
strcat(inpstr, temp); /* accept the character */
outtext(temp);
}
else
Beep(); /* len was equal to width */
}
}
while (!done);
if (len == 0)
strcpy(inpstr, deflt);
return inpstr;
}
/* PromptForFile prompts the user for a filename. It returns 0 if the
* file exists, 1 if it does not exist.
*/
int PromptForFile(char *filename)
{
struct viewporttype view;
int ch, scancode;
/* Don't allow backslashes, periods, colons, etc. */
char *legalchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \
"01234567890!@#$%^&()-_=`~[]{}'\"" \
"\b\x1b\r";
MouseOff();
getviewsettings(&view);
setviewport(0, 0, maxx, maxy, CLIPPING_OFF); /* Entire screen */
/* Save the screen area under where the prompt box will display */
saveBuffer = malloc(promptSize);
getimage(fminx, fminy, fmaxx, fmaxy, saveBuffer);
/* Display the prompt box */
putimage(fminx, fminy, promptBuffer, COPY_PUT);
MouseOn();
/* Get the filename from the user */
GetString(filename, promptx, prompty, 8, "PAINT", legalchars,
NULL, TRUE, NULL);
strcat(filename, ".pic");
/* Restore the screen area and free the buffer */
MouseOff();
putimage(fminx, fminy, saveBuffer, COPY_PUT);
MouseOn();
free(saveBuffer);
setviewport(view.left, view.top, view.right, view.bottom, view.clip);
return access(filename, 0);
}