home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_08_01
/
8n01070a
< prev
next >
Wrap
Text File
|
1990-02-19
|
13KB
|
633 lines
*****Listing 1*****
/*
* this is a very simple drawing program that
* illustrates how to build a DCUWCU application
*
* Copyright 1989 Mark A. Johnson
*/
#include <stdio.h>
#include <graphics.h>
#define M_POINTER 0 /* mouse shapes */
#define M_CROSS 1
#define ON 1
#define OFF 0
#define MAX_OBJECT 100
#define ESC 27
#define BOX 'b' /* object types we support */
#define ELLIPSE 'e'
#define LINE 'l'
#define TEXT 't'
#define M_MAIN 1 /* handles for the menus */
#define M_FILE 2
#define M_OBJ 3
#define M_ACT 4
#define A_COPY 1 /* action requests for button() */
#define A_MOVE 2
#define A_EDIT 3
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
typedef struct { int type, l, t, r, b; char select, *data; } Object;
Object objects[MAX_OBJECT]; /* the table of objects defined so far */
int last_object; /* the end of the object table */
int map[] = { /* maps a M_OBJ menu item to an object */
0, BOX, ELLIPSE, LINE, TEXT };
char *about = /* form used on the M_MAIN About item */
" Draw This!| by|Mark A. Johnson| %{continue}";
char *help = /* help message for wrong keyboard input */
"quit refresh : box line ellipse text : delete copy move edit";
char filename[20]; /* save the filename we're working with */
char text[100]; /* extra buffer for text i/o */
int actn_obj = 0; /* flag for button(), some action req */
int make_obj = 0; /* flag for button(), need to create */
int slct_cnt = 0; /* count of selected objects */
int first; /* helps make_object collect points */
int grid = 0; /* grid displayed, snap coords */
extern int Maxx, Maxy, MaxColor;
/* start routine, called by the application driver, gets things going */
start(argc, argv) char **argv; {
add_menu(M_MAIN, "Main:About|Quit|Refresh|Grid");
add_menu(M_FILE, "File:Read|Write|Save|Print");
add_menu(M_OBJ, "Objects:Box|Ellipse|Line|Text");
add_menu(M_ACT, "Actions:Delete|Copy|Move|Edit");
menu_state(M_ACT, 0);
if (argc > 1) {
strcpy(filename, argv[1]);
read_objects();
}
}
/* no timers in this application , but DCUWCU needs an entry anyway */
timer() {}
/* button routine called every time button 1 is depressed */
button(b, x, y) {
if (make_obj) { /* need points to make an object */
make_object(x, y);
}
else if (actn_obj) { /* got a point for a copy or move */
action_object(x, y);
}
else { /* do a selection */
select_object(in_object(x, y));
}
check_menu();
}
/* menu routine called every time a menu item is selected */
menu(m, i) {
char junk = 0, on;
switch (m) {
case M_MAIN: /* main menu */
switch (i) {
case 1: form(about, &junk); break;
case 2: quit(); break;
case 3: refresh(); break;
case 4: do_grid(); break;
}
break;
case M_FILE: /* file menu */
if (i < 3 && !get_name())
break;
switch (i) {
case 1: read_objects(); break;
case 2: case 3: write_objects(); break;
case 4: print(); break;
}
break;
case M_OBJ: /* objects */
start_make(map[i]);
break;
case M_ACT: /* actions */
switch (i) {
case 1: kill_object(); break;
case 2: start_actn(A_COPY); break;
case 3: start_actn(A_MOVE); break;
case 4: start_edit(); break;
}
break;
}
}
/* routine called everytime a key is struck */
keyboard(c) {
switch (c) {
case 'p': print(); break;
case 'g': do_grid(); break;
case 'r': refresh(); break;
case 'q': quit(); break;
case 'b': start_make(BOX); break;
case 't': start_make(TEXT); break;
case 'l': start_make(LINE); break;
case 'm': start_actn(A_MOVE); break;
case 'c': start_actn(A_COPY); break;
case 'd': kill_object(); break;
case 'e':
if (slct_cnt)
start_edit();
else start_make(ELLIPSE);
break;
default: msg(help);
}
}
/* time to go, see if they really want to */
quit() {
char yes = 0, no = 0;
char *f_exit = "Are you sure?| %{yes} %{no}";
if (form(f_exit, &yes, &no) && no == 0)
finish();
}
/*
* miscellaneous support routines
*/
/* reset the current grid size */
do_grid() {
char gridval, ok = 0, nok = 0, x;
switch (grid) {
case 8: gridval = 1; break;
case 16: gridval = 2; break;
default: gridval = 0; break;
}
x = form("Change Grid Size| %[none:8:16]| %{ok} %{cancel}",
&gridval, &ok, &nok);
if (x == 0 || nok) return;
grid = gridval * 8;
refresh();
}
/* print the current screen somewhere, Epson-compatible graphics mode */
print() {
static char grhd[] = { ESC, 'L', 0, 0 }; /* 960 bit graphics */
static char grlf[] = { ESC, 'J', 24, '\r' }; /* line feed */
static char prbuf[960];
int x, y, i, b, n, any, pixel, max;
max = min(Maxx, 960);
grhd[2] = max;
grhd[3] = max >> 8;
mouse_state(OFF);
b = 0x80;
any = 0;
for (y = 0; y < Maxy; y++) {
for (x = 0; x < max; x++) {
if (getpixel(x, y)) {
any = 1;
prbuf[x] |= b;
}
}
b >>= 1;
if (b == 0) { /* out it goes */
if (any) {
prn(grhd, 4);
prn(prbuf, max);
}
prn(grlf, 4);
b = 0x80;
any = 0;
for (x = 0; x < max; x++)
prbuf[x] = 0;
}
}
mouse_state(ON);
}
/* print the n bytes out the printer port */
prn(s, n) char *s; { while (n--) biosprint(0, *s++, 0); }
/* select or de-select an object */
select_object(obj) {
int i;
Object *o;
if (obj == -1) { /* de-select all */
for (i = 0; i < last_object; i++) {
o = &objects[i];
if (o->select) {
o->select = 0;
highlight(o, 0);
}
}
slct_cnt = 0;
}
else {
o = &objects[obj];
o->select = !o->select;
highlight(o, o->select);
slct_cnt += o->select ? 1 : -1;
}
}
/* get a filename from the user, return 0 if abort */
get_name() {
return form("Path: %20s", filename);
}
/* based on current select state, set the top-most menu */
check_menu() {
menu_state(M_ACT, slct_cnt > 0);
menu_state(M_OBJ, slct_cnt <= 0);
}
/* start to make an object by collecting points */
start_make(type) {
char *s;
switch (make_obj = type) {
case BOX: s = "box: top left corner..."; break;
case ELLIPSE: s = "ellipse: top left corner..."; break;
case LINE: s = "line: one end..."; break;
case TEXT: s = "text: starting..."; break;
}
msg(s);
mouse_shape(M_CROSS);
first = 1;
}
/* if enough points have been collected, make the object */
make_object(x, y) {
static int fx, fy;
if (grid) snap(&x, &y);
switch (make_obj) {
case TEXT:
*text = 0;
form("text: %20s", text);
add_object(TEXT, x, y, x + strlen(text)*8, y+8, text);
make_obj = 0;
mouse_shape(M_POINTER);
msg("");
break;
default:
if (first) {
fx = x;
fy = y;
first = 0;
line(x-3, y, x+3, y);
line(x, y-3, x, y+3);
if (make_obj == LINE)
msg("other end...");
else msg("bottom right corner...");
}
else {
add_object(make_obj, fx, fy, x, y, 0L);
msg("");
make_obj = 0;
mouse_shape(M_POINTER);
}
}
}
/* snap the coordinates to the nearest grid point */
snap(xp, yp) int *xp, *yp; {
int g2 = grid/2, g4 = grid/4, x = *xp, y = *yp;
x = ((x + g2) / grid) * grid;
y = ((y + g4) / g2) * g2;
msg("x %d->%d y %d->%d", *xp, x, *yp, y);
*xp = x;
*yp = y;
}
/* move, copy, or edit a figure */
action_object(x, y) {
int i, dx, dy;
Object *o;
if (grid) snap(&x, &y);
/* find reference point and compute distance moved */
dx = dy = (actn_obj == A_EDIT ? 0 : 10000);
for (i = 0; i < last_object; i++) {
o = &objects[i];
if (o->select) {
if (actn_obj == A_EDIT) {
dx = max(o->r, dx);
dy = max(o->b, dy);
}
else {
dx = min(o->l, dx);
dy = min(o->t, dy);
}
}
}
dx = x - dx;
dy = y - dy;
/* do it to all selected items, de-selecting as you go */
for (i = 0; i < last_object; i++) {
o = &objects[i];
if (o->select) {
o->select = 0;
highlight(o, 0);
switch (actn_obj) {
case A_COPY:
highlight(o, 0);
add_object(o->type,
o->l + dx, o->t + dy,
o->r + dx, o->b + dy,
o->data);
break;
case A_MOVE:
draw_object(o, 0);
o->l += dx;
o->t += dy;
o->r += dx;
o->b += dy;
draw_object(o, 1);
break;
case A_EDIT:
draw_object(o, 0);
set_coords(o,
o->l, o->t,
o->r + dx, o->b + dy);
draw_object(o, 1);
break;
}
}
}
/* deselect all and reset the mouse */
actn_obj = 0;
slct_cnt = 0;
mouse_shape(M_POINTER);
msg("");
check_menu();
}
/* read objects from a file */
read_objects() {
int type, t, l, r, b;
FILE *f = fopen(filename, "r");
if (f != NULL) {
last_object = 0;
while (fgets(text, 100, f)) {
sscanf(text, "%c %d %d %d %d '%[^']\n",
&type, &l, &t, &r, &b, text);
add_object(type, l, t, r, b, text);
}
fclose(f);
msg("%d objects loaded", last_object);
}
else msg("can't open '%s'", filename);
}
/* write objects to a file */
write_objects() {
int i;
Object *o;
FILE *f;
if (*filename == 0 && !get_name())
return;
if ((f = fopen(filename, "w")) != NULL) {
for (i = 0; i < last_object; i++) {
o = &objects[i];
fprintf(f, "%c %d %d %d %d '%s'\n",
o->type, o->l, o->t, o->r, o->b,
o->type == TEXT ? o->data : "");
}
fclose(f);
}
else msg("can't write '%s'", filename);
}
/* save the given string in malloc'ed memory */
char *
strsave(s) char *s; {
char *malloc();
char *r = malloc(strlen(s)+1);
if (r) strcpy(r, s);
else msg("out of memory!!!");
return r;
}
/* re-display all the objects on the screen */
refresh() {
int i, x, y, gy;
Object *o;
clearviewport();
setcolor(MaxColor);
if (grid) {
gy = grid/2;
for (x = grid; x < Maxx; x += grid)
for (y = gy; y < Maxy; y += gy)
putpixel(x, y, 1);
}
for (i = 0; i < last_object; i++) {
o = &objects[i];
draw_object(o, 1);
if (o->select) highlight(o, 1);
}
}
/* (de)highlight the current selected item */
highlight(o, color) Object *o; {
setcolor(color);
rectangle(o->l-2, o->t-2, o->l+2, o->t+2);
rectangle(o->r-2, o->b-2, o->r+2, o->b+2);
}
/* give the user some feedback */
msg(fmt, a, b, c, d) char *fmt; {
static int lastback = 0;
setfillstyle(EMPTY_FILL, 0);
bar(0, 0, lastback, 8);
sprintf(text, fmt, a, b, c, d);
setcolor(MaxColor);
outtextxy(0, 0, text);
lastback = strlen(text) * 8;
}
/*
* object handling
*/
/* see if x,y are in an object, begin looking at start + 1 */
in_object(x, y) {
static int last = 0;
int l, r, t, b;
Object *o;
int i = last+1, n = last_object;
while (n--) {
if (i >= last_object) i = 0;
o = &objects[i];
l = min(o->l, o->r);
r = max(o->l, o->r);
t = min(o->t, o->b);
b = max(o->t, o->b);
if (x >= l && x <= r && y >= t && y <= b)
return (last = i);
i++;
}
return (last = -1);
}
/* add an object to the object table */
add_object(type, l, t, r, b, data) char *data; {
Object *o = &objects[last_object++];
char *s;
o->type = type;
set_coords(o, l, t, r, b);
o->select = 0;
if (type == TEXT)
o->data = strsave(data);
draw_object(o, 1);
}
/* set the coordinates properly */
set_coords(o, l, t, r, b) Object *o; {
if (o->type == LINE) { /* no fixup on these */
o->l = l;
o->t = t;
o->r = r;
o->b = b;
}
else {
o->l = min(l, r);
o->t = min(t, b);
o->r = max(l, r);
o->b = max(t, b);
}
}
/* draw an object on the screen */
draw_object(o, color) Object *o; {
int x, y, xrad, yrad;
setcolor(color);
switch (o->type) {
case TEXT:
x = strlen(o->data) * 8;
setfillstyle(EMPTY_FILL, 0);
bar(o->l, o->t, o->l + x, o->t + 8);
outtextxy(o->l, o->t, o->data);
break;
case BOX:
rectangle(o->l, o->t, o->r, o->b);
break;
case LINE:
line(o->l, o->t, o->r, o->b);
break;
case ELLIPSE:
x = o->l + (o->r - o->l)/2;
y = o->t + (o->b - o->t)/2;
xrad = o->r - x;
yrad = o->b - y;
ellipse(x, y, 0, 360, xrad, yrad);
break;
}
}
/* delete an object */
kill_object() {
int i, j;
Object *o;
for (i = j = 0; i < last_object; i++) {
o = &objects[i];
if (o->select) {
highlight(o, 0);
draw_object(o, 0);
o->select = 0;
}
else {
if (i > j)
objects[j++] = objects[i];
else j++;
}
}
last_object = j;
slct_cnt = 0;
check_menu();
}
/* start an edit on the selected objects */
start_edit() {
int i;
Object *o;
/* edit the text objects now */
for (i = 0; i < last_object; i++) {
o = &objects[i];
if (o->type == TEXT && o->select) {
o->select = 0;
highlight(o, 0);
draw_object(o, 0);
strcpy(text, o->data);
if (form("edit: %20s", text)) {
free(o->data);
o->data = strsave(text);
o->r = o->l + strlen(text)*8;
}
draw_object(o, 1);
slct_cnt--;
}
}
if (slct_cnt > 0) { /* must be other stuff */
start_actn(A_EDIT);
}
check_menu();
}
/* initiate an action on selected objects */
start_actn(actn) {
switch (actn) {
case A_COPY:
msg("copy to...");
break;
case A_MOVE:
msg("move to...");
break;
case A_EDIT:
msg("editing...");
break;
}
actn_obj = actn;
mouse_shape(M_CROSS);
}