/************************************************************************/ /* File: doodle.c */ /************************************************************************/ /* */ /* GGGGG EEEEEEEE MM MM */ /* GG EE MMMM MMMM */ /* GG GGG EEEEE MM MM MM */ /* GG GG EE MM MM */ /* GGGGG EEEEEEEE MM MM */ /* */ /************************************************************************/ /* */ /* */ /* The source code contained in this listing is a non-copyrighted */ /* work which can be freely used. In applications of this source */ /* code you are requested to acknowledge Digital Research, Inc. as */ /* the originator of portions of this code. The code was */ /* originally developed by them for the IBM PC. */ /* */ /* ATARI ADAPTATION IN COLOR BY HARRY KOONS */ /* VERSION 1.1B 7/11/85 */ /* */ /* If you find this program of value, I would appreciate a */ /* contribution of $20 for the time and effort I have spent in */ /* making it work on the Atari 520 ST. */ /* */ /* Harry Koons */ /* 1123 Oakfair Lane */ /* Harbor City, CA 90710 */ /* */ /************************************************************************/ /* Page*/ /*------------------------------*/ /* includes */ /*------------------------------*/ #include "define.h" /* misc. definitions */ #include "osbind.h" /* gemdos bindings */ #include "portab.h" /* portable coding conv */ /* #include "machine.h" */ /* machine dependent */ #include "obdefs.h" /* object definitions */ #include "gemdefs.h" /* misc gem definitions */ #include "taddr.h" /* tree address macros */ #include "vdibind.h" /* vdi binding structs */ #include "b:doodle.h" /* doodle apl resource */ /*------------------------------*/ /* defines */ /*------------------------------*/ #define DESK 0 #define END_UPDATE 0 #define BEG_UPDATE 1 #define SHADE0 0 #define SHADE1 1 #define SHADE2 2 #define SHADE3 3 #define SHADE4 4 #define SHADE5 5 #define SHADE6 6 #define SHADE7 7 #define SHADE8 8 #define SHADE9 9 #define SHADE10 10 #define SHADE11 11 #define SHADE12 12 #define SHADE13 13 #define SHADE14 14 #define SHADE15 15 #define PEN_FINE 1 #define PEN_MEDIUM 5 #define PEN_BROAD 9 /*------------------------------*/ /* Macros */ /*------------------------------*/ #define LLGET(x) (*((LONG*)(x))) #define LLSET(x,y) (*((LONG*)(x))=y) #define LWGET(x) ((WORD)*((WORD*)(x))) #define LWSET(x,y) (*((WORD*)(x))=y) #define YSCALE(x) umul_div(x, scrn_xsize, scrn_ysize) #define TE_TXTLEN(x) (x + 24) #define ADDR /**/ #define GLOBAL /**/ /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Data Structures ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* Extrnl Data Structures */ /*------------------------------*/ UWORD dos_err; /* no longer external */ /*------------------------------*/ /* Global Data Structures */ /*------------------------------*/ GLOBAL WORD contrl[11]; /* control inputs */ GLOBAL WORD intin[80]; /* max string length */ GLOBAL WORD ptsin[256]; /* polygon fill points */ GLOBAL WORD intout[45]; /* open workstation output */ GLOBAL WORD ptsout[12]; /*------------------------------*/ /* Local Data Structures */ /*------------------------------*/ WORD gl_wchar; /* character width */ WORD gl_hchar; /* character height */ WORD gl_wbox; /* box (cell) width */ WORD gl_hbox; /* box (cell) height */ WORD gl_hspace; /* height of space between lines*/ WORD gem_handle; /* GEM vdi handle */ WORD vdi_handle; /* doodle vdi handle */ WORD work_out[57]; /* open virt workstation values */ GRECT scrn_area; /* whole scrn area */ GRECT work_area; /* drawing area of main window */ GRECT undo_area; /* area equal to work_area */ GRECT save_area; /* save area for full/unfulling */ WORD gl_rmsg[8]; /* message buffer */ LONG ad_rmsg; /* LONG pointer to message bfr */ LONG gl_menu; /* menu tree address */ WORD gl_apid; /* application ID */ WORD gl_xfull; /* full window 'x' */ WORD gl_yfull; /* full window 'y' */ WORD gl_wfull; /* full window 'w' */ WORD gl_hfull; /* full window 'h' */ WORD scrn_width; /* scrn width in pixels */ WORD scrn_height; /* scrn height in pixels */ WORD scrn_planes; /* number of color planes */ WORD scrn_xsize; /* width of one pixel */ WORD scrn_ysize; /* height of one pixel */ UWORD m_out = FALSE; /* mouse in/out of window flag */ WORD ev_which; /* event multi return state(s) */ UWORD mousex, mousey; /* mouse x,y position */ UWORD bstate, bclicks; /* button state, & # of clicks */ UWORD kstate, kreturn; /* key state and keyboard char */ MFDB undo_mfdb; /* undo buffer mmry frm def blk */ MFDB scrn_mfdb; /* scrn memory form defn blk */ LONG buff_size; /* buffer size req'd for scrn */ LONG buff_location; /* scrn buffer pointer */ WORD dodle_whndl; /* doodle window handle */ BOOLEAN dood_fill = FALSE; /* fill or draw flag */ BOOLEAN first_fill = FALSE; /* to set background color */ WORD dodle_shade = SHADE1; /* doodle current pen shade */ WORD pen_ink = SHADE1; /* current ink shade */ WORD bkgr_color = SHADE0; /* current background shade */ WORD bkgr_next = SHADE0; /* next background shade */ WORD dodle_pen = 1; /* doodle current pen width */ WORD dodle_height = 4; /* doodle current char height */ WORD char_fine; /* character height for fine */ WORD char_medium; /* character height for medium */ WORD char_broad; /* character height for broad */ WORD monumber = 5; /* mouse form number */ LONG mofaddr = 0x0L; /* mouse form address */ WORD file_handle; /* file handle -> pict ld/sv */ BYTE file_name[64] = ""; /* current pict file name */ BOOLEAN key_input; /* key inputting state */ WORD key_xbeg; /* x position for line beginning*/ WORD key_ybeg; /* y position for line beginning*/ WORD key_xcurr; /* current x position */ WORD key_ycurr; /* current y position */ /* doodle window title */ BYTE *wdw_title = " Dr Doodle Window "; /* Page*/ /*------------------------------*/ /* Mouse Data Structures */ /*------------------------------*/ WORD erase_broad[37] = /* mouse form for broad eraser */ { 7, 7, 1, 0, 1, 0x0000, 0x0000, 0x0000, 0x0000, /* mask */ 0x0000, 0x1ff0, 0x1ff0, 0x1ff0, 0x1ff0, 0x1ff0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* data */ 0x7ffc, 0x600c, 0x600c, 0x600c, 0x600c, 0x600c, 0x7ffc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; WORD erase_medium[37] = /* mouse form for medium eraser */ { 7, 7, 1, 0, 1, 0x0000, 0x0000, 0x0000, 0x0000, /* mask */ 0x0000, 0x0000, 0x07c0, 0x07c0, 0x07c0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* data */ 0x0000, 0x1ff0, 0x1830, 0x1830, 0x1830, 0x1ff0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; WORD erase_fine[37] = /* mouse form for fine eraser */ { 7, 7, 1, 0, 1, 0x0000, 0x0000, 0x0000, 0x0000, /* mask */ 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* data */ 0x0000, 0x0000, 0x07c0, 0x06c0, 0x07c0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Local Procedures ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* min */ /*------------------------------*/ WORD min(a, b) /* return min of two values */ WORD a, b; { return( (a < b) ? a : b ); } /*------------------------------*/ /* max */ /*------------------------------*/ WORD max(a, b) /* return max of two values */ WORD a, b; { return( (a > b) ? a : b ); } /*------------------------------*/ /* string_addr */ /*------------------------------*/ LONG string_addr(which) /* returns a tedinfo LONG string addr */ WORD which; { LONG where; rsrc_gaddr(R_STRING, which, &where); return (where); } /*------------------------------*/ /* rc_equal */ /*------------------------------*/ WORD rc_equal(p1, p2) /* tests for two rectangles equal */ GRECT *p1, *p2; { if ((p1->g_x != p2->g_x) || (p1->g_y != p2->g_y) || (p1->g_w != p2->g_w) || (p1->g_h != p2->g_h)) return(FALSE); return(TRUE); } /*------------------------------*/ /* rc_copy */ /*------------------------------*/ VOID rc_copy(psbox, pdbox) /* copy source to destination rectangle */ GRECT *psbox; GRECT *pdbox; { pdbox->g_x = psbox->g_x; pdbox->g_y = psbox->g_y; pdbox->g_w = psbox->g_w; pdbox->g_h = psbox->g_h; } /*------------------------------*/ /* rc_intersect */ /*------------------------------*/ WORD rc_intersect(p1, p2) /* compute intersect of two rectangles */ GRECT *p1, *p2; { WORD tx, ty, tw, th; tw = min(p2->g_x + p2->g_w, p1->g_x + p1->g_w); th = min(p2->g_y + p2->g_h, p1->g_y + p1->g_h); tx = max(p2->g_x, p1->g_x); ty = max(p2->g_y, p1->g_y); p2->g_x = tx; p2->g_y = ty; p2->g_w = tw - tx; p2->g_h = th - ty; return( (tw > tx) && (th > ty) ); } /*------------------------------*/ /* inside */ /*------------------------------*/ UWORD inside(x, y, pt) /* determine if x,y is in rectangle */ UWORD x, y; GRECT *pt; { if ( (x >= pt->g_x) && (y >= pt->g_y) && (x < pt->g_x + pt->g_w) && (y < pt->g_y + pt->g_h) ) return(TRUE); else return(FALSE); } /* inside */ /*------------------------------*/ /* grect_to_array */ /*------------------------------*/ VOID grect_to_array(area, array) /* convert x,y,w,h to upr lt x,y and */ GRECT *area; /* lwr rt x,y */ WORD *array; { *array++ = area->g_x; *array++ = area->g_y; *array++ = area->g_x + area->g_w - 1; *array = area->g_y + area->g_h - 1; } /*------------------------------*/ /* rast_op */ /*------------------------------*/ VOID rast_op(mode, s_area, s_mfdb, d_area, d_mfdb) /* bit block level trns */ WORD mode; GRECT *s_area, *d_area; MFDB *s_mfdb, *d_mfdb; { WORD pxy[8]; grect_to_array(s_area, pxy); grect_to_array(d_area, &pxy[4]); vro_cpyfm(vdi_handle, mode, pxy, s_mfdb, d_mfdb); } /*------------------------------*/ /* do_open */ /*------------------------------*/ VOID do_open(wh, org_x, org_y, x, y, w, h) /* grow and open specified wdw */ WORD wh; WORD org_x, org_y; WORD x, y, w, h; { graf_growbox(org_x, org_y, 21, 21, x, y, w, h); wind_open(wh, x, y, w, h); } /*------------------------------*/ /* do_close */ /*------------------------------*/ VOID do_close(wh, org_x, org_y) /* close and shrink specified window */ WORD wh; WORD org_x, org_y; { WORD x, y, w, h; wind_get(wh, WF_CURRXYWH, &x, &y, &w, &h); wind_close(wh); graf_shrinkbox(org_x, org_y, 21, 21, x, y, w, h); } /*------------------------------*/ /* hndl_dial */ /*------------------------------*/ WORD hndl_dial(tree, def, x, y, w, h) /* center, display and get input*/ LONG tree; /* from specified dialogue box*/ WORD def; WORD x, y, w, h; { WORD xdial, ydial, wdial, hdial; WORD exit_obj; form_center(tree, &xdial, &ydial, &wdial, &hdial); form_dial(0, x, y, w, h, xdial, ydial, wdial, hdial); form_dial(1, x, y, w, h, xdial, ydial, wdial, hdial); objc_draw(tree, ROOT, MAX_DEPTH, xdial, ydial, wdial, hdial); exit_obj = form_do(tree, def); form_dial(2, x, y, w, h, xdial, ydial, wdial, hdial); form_dial(3, x, y, w, h, xdial, ydial, wdial, hdial); return (exit_obj); } /*------------------------------*/ /* set_clip */ /*------------------------------*/ VOID set_clip(clip_flag, s_area) /* set clip to specified area */ WORD clip_flag; GRECT *s_area; { WORD pxy[4]; grect_to_array(s_area, pxy); vs_clip(vdi_handle, clip_flag, pxy); } /*------------------------------*/ /* align_x */ /*------------------------------*/ WORD align_x(x) /* forces word alignment for column position */ WORD x; /* rounding to nearest word */ { /* return((x & 0xfff0) + ((x & 0x000c) ? 0x0010 : 0)); IBM */ return(x); /* ATARI */ } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Work Area Management ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* set_work */ /*------------------------------*/ VOID set_work(slider_update) /* update undo area, clamping to page */ BOOLEAN slider_update; /* edges, and updt sliders if req'd */ { WORD i; wind_get(dodle_whndl, WF_WORKXYWH, &work_area.g_x, &work_area.g_y, &work_area.g_w, &work_area.g_h); undo_area.g_w = work_area.g_w; undo_area.g_h = work_area.g_h; /**/ /* clamp work area to page edges */ if ((i = undo_mfdb.fwp - (undo_area.g_x + undo_area.g_w)) < 0) undo_area.g_x += i; if ((i = undo_mfdb.fh - (undo_area.g_y + undo_area.g_h)) < 0) undo_area.g_y += i; if (slider_update) { wind_set(dodle_whndl, WF_HSLIDE, umul_div(undo_area.g_x, 1000, undo_mfdb.fwp - undo_area.g_w), 0, 0, 0); wind_set(dodle_whndl, WF_VSLIDE, umul_div(undo_area.g_y, 1000, undo_mfdb.fh - undo_area.g_h), 0, 0, 0); wind_set(dodle_whndl, WF_HSLSIZ, umul_div(work_area.g_w, 1000, undo_mfdb.fwp), 0, 0, 0); wind_set(dodle_whndl, WF_VSLSIZ, umul_div(work_area.g_h, 1000, undo_mfdb.fh), 0, 0, 0); } undo_area.g_x = align_x(undo_area.g_x); /* only use portion of work_area on scrn */ rc_intersect(&scrn_area, &work_area); undo_area.g_w = work_area.g_w; undo_area.g_h = work_area.g_h; } /*------------------------------*/ /* save_work */ /*------------------------------*/ VOID save_work() /* copy work_area to undo_area buffer */ { GRECT tmp_area; rc_copy(&work_area,&tmp_area); rc_intersect(&scrn_area,&tmp_area); graf_mouse(M_OFF, 0x0L); rast_op(3, &tmp_area, &scrn_mfdb, &undo_area, &undo_mfdb); graf_mouse(M_ON, 0x0L); } /*------------------------------*/ /* restore_work */ /*------------------------------*/ VOID restore_work() /* restore work_area from undo_area */ { GRECT tmp_area; rc_copy(&work_area,&tmp_area); rc_intersect(&scrn_area,&tmp_area); graf_mouse(M_OFF, 0x0L); rast_op(3, &undo_area, &undo_mfdb, &tmp_area, &scrn_mfdb); graf_mouse(M_ON, 0x0L); } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Object Tree Manipulation ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* do_obj */ /*------------------------------*/ VOID do_obj(tree, which, bit) /* set specified bit in object state */ LONG tree; WORD which, bit; { WORD state; state = LWGET(OB_STATE(which)); LWSET(OB_STATE(which), state | bit); } /*------------------------------*/ /* undo_obj */ /*------------------------------*/ VOID undo_obj(tree, which, bit) /* clear specified bit in object state */ LONG tree; WORD which, bit; { WORD state; state = LWGET(OB_STATE(which)); LWSET(OB_STATE(which), state & ~bit); } /*------------------------------*/ /* sel_obj */ /*------------------------------*/ VOID sel_obj(tree, which) /* turn on selected bit of spcfd object */ LONG tree; WORD which; { do_obj(tree, which, SELECTED); } /*------------------------------*/ /* desel_obj */ /*------------------------------*/ VOID desel_obj(tree, which) /* turn off selected bit of spcfd object*/ LONG tree; WORD which; { undo_obj(tree, which, SELECTED); } /*------------------------------*/ /* enab_menu */ /*------------------------------*/ VOID enab_menu(which) /* enable specified menu item */ WORD which; { undo_obj(gl_menu, which, DISABLED); } /*------------------------------*/ /* objc_xywh */ /*------------------------------*/ VOID objc_xywh(tree, obj, p) /* get x,y,w,h for specified object */ LONG tree; WORD obj; GRECT *p; { objc_offset(tree, obj, &p->g_x, &p->g_y); p->g_w = LWGET(OB_WIDTH(obj)); p->g_h = LWGET(OB_HEIGHT(obj)); } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** File Path Name Functions ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* dial_name */ /*------------------------------*/ WORD dial_name ( name ) /* dialogue box input filename */ BYTE *name; { LONG tree ; LONG ted_addr ; BYTE c ; WORD i, j; GRECT box; objc_xywh(gl_menu, DOODFILE, &box); rsrc_gaddr( R_TREE, DOODSVAD, &tree) ; ted_addr = LLGET(OB_SPEC(DOODNAME)); LLSET( ted_addr, ADDR(name) ) ; LWSET( TE_TXTLEN(ted_addr),8); name[0] = '\0'; if (hndl_dial(tree, DOODNAME, box.g_x, box.g_y, box.g_w, box.g_h) == DOODSOK) { i = j = 0; while (TRUE) { c = name[i++]; if (!c) break ; if ( (c != ' ') && (c != '_') ) name[j++] = c ; } if ( *name ) strcpy( &name[j], ".DOO" ) ; desel_obj(tree, DOODSOK); return ((WORD) *name); } else { desel_obj(tree, DOODSCNL); return (FALSE); } } /*------------------------------*/ /* get_path */ /*------------------------------*/ VOID get_path(tmp_path, spec) /* get directory path name */ BYTE *tmp_path, *spec; { WORD cur_drv; cur_drv = Dgetdrv(); tmp_path[0] = cur_drv + 'A'; tmp_path[1] = ':'; tmp_path[2] = '\\'; Dgetpath(ADDR(&tmp_path[3]), cur_drv+1); if (strlen(tmp_path) > 3) strcat(tmp_path, "\\"); else tmp_path[2] = '\0'; strcat(tmp_path, spec); } /*------------------------------*/ /* add_file_name */ /*------------------------------*/ VOID add_file_name(dname, fname) /* replace name at end of input file spec*/ BYTE *dname, *fname; { BYTE c; WORD ii; ii = strlen(dname); while (ii && (((c = dname[ii-1]) != '\\') && (c != ':'))) ii--; dname[ii] = '\0'; strcat(dname, fname); } /*------------------------------*/ /* get_file */ /*------------------------------*/ WORD get_file(loop) /* use file selector to get input file */ BOOLEAN loop; { WORD fs_iexbutton; BYTE fs_iinsel[13]; while (TRUE) { get_path(file_name, "*.DOO"); fs_iinsel[0] = '\0'; fsel_input(ADDR(file_name), ADDR(fs_iinsel), &fs_iexbutton); if (fs_iexbutton) { add_file_name(file_name, fs_iinsel); file_handle = Fopen(ADDR(file_name),2); dos_err = (file_handle < 0) ? -1 : 0; if (!loop || (loop && !dos_err)) return(1); } else return (0); } } /* get_file */ /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Soft Cursor Support ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* cursor */ /*------------------------------*/ VOID cursor(color) /* turn cursor on, color = pen_ink */ WORD color; /* or cursor off, color = bkgr_color */ { WORD pxy[4]; pxy[0] = key_xcurr + 1; pxy[1] = key_ycurr + gl_hspace; pxy[2] = key_xcurr + 1; pxy[3] = key_ycurr - gl_hbox; vsl_color(vdi_handle,color); vswr_mode(vdi_handle,MD_REPLACE); vsl_type (vdi_handle,IP_1PATT); vsl_width (vdi_handle,PEN_FINE); v_pline(vdi_handle, 2, pxy); } /*------------------------------*/ /* curs_on */ /*------------------------------*/ VOID curs_on() /* turn 'soft' cursor 'on' */ { cursor(pen_ink); } /*------------------------------*/ /* curs_off */ /*------------------------------*/ VOID curs_off() /* turn 'soft' cursor 'off' */ { cursor(bkgr_color); } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Menu Handling ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* hdl_menu */ /*------------------------------*/ WORD hdl_menu(title, item) WORD title, item; { WORD done; WORD me_creturn; graf_mouse(ARROW, 0x0L); done = FALSE; switch (title) { case DOODDESK: if (item == DOODINFO) do_about(); break; case DOODFILE: switch (item) { case DOODLOAD: do_load(TRUE); break; case DOODSAVE: do_sav(); break; case DOODSVAS: do_savas(); break; case DOODABAN: file_handle = Fopen(ADDR(file_name),2); do_load(FALSE); break; case DOODQUIT: done = TRUE; break; } case DOODOPTS: switch (item) { case DOODPENS: do_penselect(); break; case DOODERAP: do_erase(); first_fill = TRUE; break; } case DOODCOLR: switch (item) { case COLOR0: pen_ink = SHADE0; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR0, SELECTED); break; case COLOR1: pen_ink = SHADE1; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR1, SELECTED); break; case COLOR2: pen_ink = SHADE2; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR2, SELECTED); break; case COLOR3: pen_ink = SHADE3; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR3, SELECTED); break; case COLOR4: pen_ink = SHADE4; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR4, SELECTED); break; case COLOR5: pen_ink = SHADE5; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR5, SELECTED); break; case COLOR6: pen_ink = SHADE6; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR6, SELECTED); break; case COLOR7: pen_ink = SHADE7; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR7, SELECTED); break; case COLOR8: pen_ink = SHADE8; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR8, SELECTED); break; case COLOR9: pen_ink = SHADE9; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR9, SELECTED); break; case COLOR10: pen_ink = SHADE10; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR10, SELECTED); break; case COLOR11: pen_ink = SHADE11; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR11, SELECTED); break; case COLOR12: pen_ink = SHADE12; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR12, SELECTED); break; case COLOR13: pen_ink = SHADE13; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR13, SELECTED); break; case COLOR14: pen_ink = SHADE14; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR14, SELECTED); break; case COLOR15: pen_ink = SHADE15; do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR15, SELECTED); break; } dodle_shade = pen_ink; } menu_tnormal(gl_menu,title,TRUE); graf_mouse(monumber, mofaddr); return (done); } /*------------------------------*/ /* do_clnormal */ /*------------------------------*/ VOID do_clnormal() /* set all color checks to NORMAL in color menu */ { WORD me_creturn; me_creturn = menu_icheck(gl_menu, COLOR0, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR1, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR2, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR3, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR4, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR5, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR6, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR7, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR8, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR9, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR10, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR11, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR12, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR13, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR14, NORMAL); me_creturn = menu_icheck(gl_menu, COLOR15, NORMAL); } /*------------------------------*/ /* do_about */ /*------------------------------*/ VOID do_about() /* display Doodle Info... */ { LONG tree; GRECT box; objc_xywh(gl_menu, DOODDESK, &box); rsrc_gaddr(R_TREE, DOODINFD, &tree); hndl_dial(tree, 0, box.g_x, box.g_y, box.g_w, box.g_h); desel_obj(tree, DOODOK); } /*------------------------------*/ /* do_load */ /*------------------------------*/ VOID do_load(need_name) /* load doodle picture file */ BOOLEAN need_name; { if (!need_name || get_file(TRUE)) { if (!dos_err) { Fread(file_handle, buff_size,buff_location); Fclose(file_handle); enab_menu(DOODSAVE); enab_menu(DOODABAN); restore_work(); } } } /*------------------------------*/ /* do_sav */ /*------------------------------*/ VOID do_sav() /* save current named doodle picture */ { if (*file_name) { file_handle = Fopen(ADDR(file_name),2); dos_err = (file_handle < 0) ? 1 : 0; if (dos_err) file_handle = Fcreate(ADDR(file_name),0); else { if (form_alert(1, string_addr(DOODOVWR)) == 2) return; } Fwrite(file_handle, buff_size, buff_location); enab_menu(DOODSAVE); enab_menu(DOODABAN); Fclose(file_handle); } } /*------------------------------*/ /* do_sav_as */ /*------------------------------*/ VOID do_savas() /* save doodle picture as named */ { BYTE name[13]; if (dial_name(&name[0])) { add_file_name(file_name, name); do_sav(); } } /*------------------------------*/ /* do_penselect */ /*------------------------------*/ VOID do_penselect() /* use dialogue box to input selection */ { /* of specified pen/eraser */ WORD exit_obj; LONG tree; GRECT box; objc_xywh(gl_menu, DOODPENS, &box); rsrc_gaddr(R_TREE, DOODPEND, &tree); /**/ /* first setup current selection state */ if (dodle_pen == PEN_FINE) { sel_obj(tree, DOODFINE); desel_obj(tree, DOODMED); desel_obj(tree, DOODBRD); } else if (dodle_pen == PEN_MEDIUM) { sel_obj(tree, DOODMED); desel_obj(tree, DOODFINE); desel_obj(tree, DOODBRD); } else { sel_obj(tree, DOODBRD); desel_obj(tree, DOODFINE); desel_obj(tree, DOODMED); } if (dodle_shade == pen_ink && dood_fill == FALSE) { sel_obj(tree, DOODPEN); desel_obj(tree, DOODERSR); desel_obj(tree, DOODFILL); } else if (dodle_shade == pen_ink && dood_fill == TRUE) { desel_obj(tree, DOODPEN); desel_obj(tree, DOODERSR); sel_obj(tree, DOODFILL); } else { desel_obj(tree, DOODPEN); sel_obj(tree, DOODERSR); desel_obj(tree, DOODFILL); } /* get dialogue box input */ exit_obj = hndl_dial(tree, 0, box.g_x, box.g_y, box.g_w, box.g_h); if (exit_obj == DOODPSOK) { if (LWGET(OB_STATE(DOODFINE)) & SELECTED) { dodle_pen = PEN_FINE; dodle_height = char_fine; } else if (LWGET(OB_STATE(DOODMED)) & SELECTED) { dodle_pen = PEN_MEDIUM; dodle_height = char_medium; } else { dodle_pen = PEN_BROAD; dodle_height = char_broad; } if (LWGET(OB_STATE(DOODPEN)) & SELECTED) { dodle_shade = pen_ink; monumber = 5; mofaddr = 0x0L; dood_fill = FALSE; } else if (LWGET(OB_STATE(DOODERSR)) & SELECTED) { dodle_shade = bkgr_color; monumber = 255; mofaddr = (dodle_pen == PEN_FINE) ? ADDR((BYTE *)erase_fine) : (dodle_pen == PEN_MEDIUM) ? ADDR((BYTE *)erase_medium) : ADDR((BYTE *)erase_broad); dood_fill = FALSE; } else { dodle_shade = pen_ink; monumber = POINT_HAND; mofaddr = 0x0L; dood_fill = TRUE; } desel_obj(tree, DOODPSOK); } else desel_obj(tree, DOODCNCL); } /*------------------------------*/ /* do_erase */ /*------------------------------*/ VOID do_erase() /* clear the scrn and the undo buffer */ { WORD fo_aexbttn; fo_aexbttn = form_alert(0, string_addr(ERASEWRN)); if (fo_aexbttn == 1) { rast_op(0, &scrn_area, &scrn_mfdb, &scrn_area, &undo_mfdb); restore_work(); } } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Keyboard Handling ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* hndl_keyboard */ /*------------------------------*/ WORD hndl_keyboard() { WORD i; BYTE str[2]; if ((str[0] = kreturn) == 0x03) return(TRUE); graf_mouse(M_OFF, 0x0L); if (!key_input) { vsl_color(vdi_handle,dodle_shade); vswr_mode(vdi_handle,MD_TRANS); vsl_type (vdi_handle,IP_1PATT); vst_height(vdi_handle, dodle_height, &gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox); gl_hspace = gl_hbox - gl_hchar; set_clip(TRUE, &work_area); graf_mkstate(&key_xbeg, &key_ybeg, &i, &i); key_xcurr = ++key_xbeg; key_ycurr = --key_ybeg; } else /* curs_off(); remove from color version 6/30/85 */ str[1] = '\0'; if (str[0] == 0x1A) { save_work(); graf_mouse(M_ON, 0x0L); return(key_input = FALSE); } else if (str[0] == 0x0D) { key_ycurr += gl_hbox + gl_hspace; key_xcurr = key_xbeg; } else if (str[0] == 0x08) { if (key_input && (key_xcurr != key_xbeg)) { for (i = 0; i < gl_wbox; i++) { key_xcurr--; /* curs_off(); */ } } } else if ((str[0] >= ' ') && (str[0] <= 'z')) { str[1] = '\0'; vswr_mode(vdi_handle, MD_TRANS); vst_color(vdi_handle, pen_ink); v_gtext(vdi_handle, key_xcurr, key_ycurr, str); key_xcurr += gl_wbox; } if (!key_input) { key_input = TRUE; } /* curs_on(); remove from color version 6/30/85 */ graf_mouse(M_ON, 0x0L); return(FALSE); } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Message Handling ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* hdl_mesag */ /*------------------------------*/ /*MLOCAL*/ BOOLEAN hdl_mesag() { BOOLEAN done; WORD wdw_hndl; done = FALSE; wdw_hndl = gl_rmsg[3]; switch( gl_rmsg[0] ) { case MN_SELECTED: done = hdl_menu(wdw_hndl, gl_rmsg[4]); break; case WM_REDRAW: do_redraw(wdw_hndl, (GRECT *) &gl_rmsg[4]); break; case WM_TOPPED: wind_set(wdw_hndl, WF_TOP, 0, 0, 0, 0); break; case WM_CLOSED: done = TRUE; break; case WM_FULLED: do_full(wdw_hndl); break; case WM_ARROWED: switch(gl_rmsg[4]) { case WA_UPPAGE: undo_area.g_y = max(undo_area.g_y - undo_area.g_h, 0); break; case WA_DNPAGE: undo_area.g_y += undo_area.g_h; break; case WA_UPLINE: undo_area.g_y = max(undo_area.g_y - YSCALE(16), 0); break; case WA_DNLINE: undo_area.g_y += YSCALE(16); break; case WA_LFPAGE: undo_area.g_x = max(undo_area.g_x-undo_area.g_w, 0); break; case WA_RTPAGE: undo_area.g_x += undo_area.g_w; break; case WA_LFLINE: undo_area.g_x = max(undo_area.g_x - 16, 0); break; case WA_RTLINE: undo_area.g_x += 16; break; } set_work(TRUE); restore_work(); break; case WM_HSLID: undo_area.g_x = align_x(umul_div(undo_mfdb.fwp - undo_area.g_w, gl_rmsg[4], 1000)); wind_set(dodle_whndl, WF_HSLIDE, umul_div(undo_area.g_x, 1000, undo_mfdb.fwp - undo_area.g_w), 0, 0, 0); restore_work(); break; case WM_VSLID: undo_area.g_y = umul_div(undo_mfdb.fh - undo_area.g_h, gl_rmsg[4],1000); wind_set(dodle_whndl, WF_VSLIDE, umul_div(undo_area.g_y, 1000, undo_mfdb.fh - undo_area.g_h), 0, 0, 0); restore_work(); break; case WM_SIZED: wind_set(wdw_hndl, WF_CURRXYWH, align_x(gl_rmsg[4]) - 1, gl_rmsg[5], gl_rmsg[6], gl_rmsg[7]); set_work(TRUE); break; case WM_MOVED: gl_rmsg[4] = align_x(gl_rmsg[4]); wind_set(wdw_hndl, WF_CURRXYWH, align_x(gl_rmsg[4]) - 1, gl_rmsg[5], gl_rmsg[6], gl_rmsg[7]); set_work(FALSE); break; } /* switch */ return(done); } /* hdl_mesag */ /*------------------------------*/ /* do_redraw */ /*------------------------------*/ VOID do_redraw(wh, area) /* redraw specified area from undo bfr */ WORD wh; GRECT *area; { GRECT box; GRECT dirty_source, dirty_dest; graf_mouse(M_OFF, 0x0L); wind_get(wh, WF_FIRSTXYWH, &box.g_x, &box.g_y, &box.g_w, &box.g_h); while ( box.g_w && box.g_h ) { if (rc_intersect(area, &box)) { if (wh == dodle_whndl) { rc_copy(&box, &dirty_dest); if (rc_intersect(&work_area, &dirty_dest)) { dirty_source.g_x = (dirty_dest.g_x - work_area.g_x) + undo_area.g_x; dirty_source.g_y = (dirty_dest.g_y - work_area.g_y) + undo_area.g_y; dirty_source.g_w = dirty_dest.g_w; dirty_source.g_h = dirty_dest.g_h; rast_op(3, &dirty_source, &undo_mfdb, &dirty_dest, &scrn_mfdb); } } } wind_get(wh, WF_NEXTXYWH, &box.g_x, &box.g_y, &box.g_w, &box.g_h); } graf_mouse(M_ON, 0x0L); } /*------------------------------*/ /* do_full */ /*------------------------------*/ VOID do_full(wh) /* depending on current window state, either make window*/ WORD wh; /* full size -or- return to previous shrunken size */ { GRECT prev; GRECT curr; GRECT full; graf_mouse(M_OFF,0x0L); wind_get(wh, WF_CURRXYWH, &curr.g_x, &curr.g_y, &curr.g_w, &curr.g_h); wind_get(wh, WF_PREVXYWH, &prev.g_x, &prev.g_y, &prev.g_w, &prev.g_h); wind_get(wh, WF_FULLXYWH, &full.g_x, &full.g_y, &full.g_w, &full.g_h); if ( rc_equal(&curr, &full) ) { /* is full now so change*/ /**/ /* to previous */ graf_shrinkbox(prev.g_x, prev.g_y, prev.g_w, prev.g_h, full.g_x, full.g_y, full.g_w, full.g_h); wind_set(wh, WF_CURRXYWH, prev.g_x, prev.g_y, prev.g_w, prev.g_h); rc_copy(&save_area, &undo_area); set_work(TRUE); if ((prev.g_x == full.g_x) && (prev.g_y == full.g_y)) do_redraw(wh, &work_area); } else { /* is not full so make */ /**/ /* it full */ rc_copy(&undo_area, &save_area); graf_growbox(curr.g_x, curr.g_y, curr.g_w, curr.g_h, full.g_x, full.g_y, full.g_w, full.g_h); wind_set(wh, WF_CURRXYWH, full.g_x, full.g_y, full.g_w, full.g_h); set_work(TRUE); } graf_mouse(M_ON,0x0L); } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Mouse Handling ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* hdl_mouse */ /*------------------------------*/ WORD hdl_mouse() { BOOLEAN done; if (m_out) graf_mouse(ARROW, 0x0L); else graf_mouse(monumber, mofaddr); m_out = !m_out; done = FALSE; return(done); } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Button Handling ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* hndl_button */ /*------------------------------*/ WORD hndl_button() { WORD done; done = FALSE; if (inside(mousex, mousey, &work_area)) { if (dood_fill == TRUE) do_fill(mousex, mousey); else draw_pencil(mousex, mousey); } return(done); } /*------------------------------*/ /* draw_pencil */ /*------------------------------*/ WORD draw_pencil(x, y) UWORD x, y; { UWORD pxy[4]; WORD done; UWORD mflags; UWORD locount, hicount; UWORD ev_which, bbutton, kstate, kreturn, breturn; set_clip(TRUE, &work_area); pxy[0] = x; pxy[1] = y; vsl_color(vdi_handle,dodle_shade); vswr_mode(vdi_handle,MD_REPLACE); vsl_type (vdi_handle,IP_1PATT); if (dodle_shade == pen_ink) { vsl_width (vdi_handle,dodle_pen); vsl_ends(vdi_handle, 2, 2); hicount = 0; locount = 125; mflags = MU_BUTTON | MU_M1 | MU_TIMER; graf_mouse(M_OFF, 0x0L); } else { vsf_interior(vdi_handle, 1); vsf_color(vdi_handle, bkgr_color); mflags = MU_BUTTON | MU_M1; } done = FALSE; while (!done) { ev_which = evnt_multi(mflags, 0x01, 0x01, 0x00, 1, pxy[0], pxy[1], 1, 1, 0, 0, 0, 0, 0, ad_rmsg, locount, hicount, &pxy[2], &pxy[3], &bbutton, &kstate, &kreturn, &breturn); if (ev_which & MU_BUTTON) { if (!(mflags & MU_TIMER)) graf_mouse(M_OFF, 0x0L); if (dodle_shade == pen_ink) v_pline(vdi_handle, 2, (WORD *) pxy); else eraser((WORD) pxy[2], (WORD) pxy[3]); graf_mouse(M_ON, 0x0L); done = TRUE; } else if (ev_which & MU_TIMER) { graf_mouse(M_ON, 0x0L); mflags = MU_BUTTON | MU_M1; } else { if (!(mflags & MU_TIMER)) graf_mouse(M_OFF, 0x0L); if (dodle_shade == pen_ink) { v_pline(vdi_handle, 2, (WORD *) pxy); mflags = MU_BUTTON | MU_M1 | MU_TIMER; } else { eraser((WORD) pxy[2], (WORD) pxy[3]); graf_mouse(M_ON,0x0L); } pxy[0] = pxy[2]; pxy[1] = pxy[3]; } } /* while */ set_clip(FALSE, &work_area); save_work(); } /*------------------------------*/ /* eraser */ /*------------------------------*/ VOID eraser(x, y) /* erase rectangle of eraser size at x,y */ WORD x, y; { WORD erase_xy[4]; if (dodle_pen == PEN_FINE) { erase_xy[0] = x - 2; erase_xy[1] = y - 1; erase_xy[2] = x + 2; erase_xy[3] = y + 1; } else if (dodle_pen == PEN_MEDIUM) { erase_xy[0] = x - 4; erase_xy[1] = y - 2; erase_xy[2] = x + 4; erase_xy[3] = y + 2; } else { erase_xy[0] = x - 6; erase_xy[1] = y - 3; erase_xy[2] = x + 6; erase_xy[3] = y + 3; } vr_recfl(vdi_handle, erase_xy); } /*----------------------------------------------*/ /* do_fill HK 6/30/85 */ /*----------------------------------------------*/ WORD do_fill(x, y) WORD x, y; { WORD index; vsf_interior(vdi_handle, IP_1PATT); vsf_color(vdi_handle, pen_ink); index = -1; /* for complete fill */ graf_mouse(M_OFF, 0x0L); v_contourfill(vdi_handle, x, y, index); save_work(); graf_mouse(M_ON, 0x0L); if (first_fill == TRUE) { bkgr_color = pen_ink; first_fill = FALSE; } } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Doodle Event Handler ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* dodle */ /*------------------------------*/ dodle() { BOOLEAN done; key_input = FALSE; done = FALSE; while( !done ) /* loop handling user input until done */ { ev_which = evnt_multi(MU_BUTTON | MU_MESAG | MU_M1 | MU_KEYBD, 0x02, 0x01, 0x01, m_out, (UWORD) work_area.g_x, (UWORD) work_area.g_y, (UWORD) work_area.g_w, (UWORD) work_area.g_h, 0, 0, 0, 0, 0, ad_rmsg, 0, 0, &mousex, &mousey, &bstate, &kstate, &kreturn, &bclicks); wind_update(BEG_UPDATE); if (!(ev_which & MU_KEYBD)) { if (key_input) { /* curs_off(); */ key_input = FALSE; save_work(); } } if (ev_which & MU_BUTTON) done = hndl_button(); if (ev_which & MU_M1) done = hdl_mouse(); if (ev_which & MU_MESAG) done = hdl_message(); if (ev_which & MU_KEYBD) done = hndl_keyboard(); wind_update(END_UPDATE); } } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Termination ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* dodle_term */ /*------------------------------*/ dodle_term(term_type) WORD term_type; { switch (term_type) /* NOTE: all cases fall through */ { case (0 /* normal termination */): do_close(dodle_whndl, gl_wfull/2, gl_hfull/2); wind_delete(dodle_whndl); case (3): menu_bar(0x0L, FALSE); Mfree(undo_mfdb.mp); case (2): v_clsvwk( vdi_handle ); case (1): appl_exit(); case (4): break; } } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Initialization ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* dodle_init */ /*------------------------------*/ WORD dodle_init() { WORD work_in[11]; WORD i; WORD me_creturn; gl_apid = appl_init(); /* initialize libraries */ if (gl_apid == -1) return(4); wind_update(BEG_UPDATE); graf_mouse(HOURGLASS, 0x0L); if (!rsrc_load( ADDR("DOODLE.RSC") )) { graf_mouse(ARROW, 0x0L); form_alert(1, ADDR("[3][Fatal Error !|DOODLE.RSC|File Not Found][ Abort ]")); return(1); } /* open virtual workstation */ /* allocate undo buffer */ for (i=0; i<10; i++) { work_in[i]=1; } work_in[10]=2; gem_handle = graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox); vdi_handle = gem_handle; v_opnvwk(work_in,&vdi_handle,work_out); if (vdi_handle == 0) return(1); scrn_width = work_out[0] + 1; scrn_height = work_out[1] + 1; scrn_xsize = work_out[3]; scrn_ysize = work_out[4]; char_fine = work_out[46]; char_medium = work_out[48]; char_broad = char_medium * 2; vq_extnd(vdi_handle, 1, work_out); scrn_planes = work_out[4]; undo_mfdb.fwp = scrn_width; undo_mfdb.fww = undo_mfdb.fwp>>4; undo_mfdb.fh = scrn_height; undo_mfdb.np = scrn_planes; undo_mfdb.ff = 0; buff_size = (LONG)(undo_mfdb.fwp>>3) * (LONG)undo_mfdb.fh * (LONG)undo_mfdb.np; buff_location = undo_mfdb.mp = Malloc(buff_size); if (undo_mfdb.mp == 0) return(2); scrn_area.g_x = 0; scrn_area.g_y = 0; scrn_area.g_w = scrn_width; scrn_area.g_h = scrn_height; scrn_mfdb.mp = 0x0L; rc_copy(&scrn_area, &undo_area); rast_op(0, &undo_area, &scrn_mfdb, &undo_area, &undo_mfdb); ad_rmsg = ADDR((BYTE *) &gl_rmsg[0]); wind_get(DESK, WF_WORKXYWH, &gl_xfull, &gl_yfull, &gl_wfull, &gl_hfull); /* initialize menu */ rsrc_gaddr(R_TREE, DOODMENU, &gl_menu); do_clnormal(); me_creturn = menu_icheck (gl_menu, COLOR1, SELECTED); /* show menu */ menu_bar(gl_menu, TRUE); dodle_whndl = wind_create(0x0fef, gl_xfull - 1, gl_yfull, gl_wfull, gl_hfull); if (dodle_whndl == -1) { form_alert(1, string_addr(DOODNWDW)); return(3); } graf_mouse(HOURGLASS, 0x0L); wind_set(dodle_whndl, WF_NAME, " Dr. Doodle Window ", 0, 0); gl_xfull = align_x(gl_xfull); do_open(dodle_whndl, gl_wfull/2, gl_hfull/2, align_x(gl_xfull), gl_yfull, gl_wfull, gl_hfull); wind_get(dodle_whndl, WF_WORKXYWH, &work_area.g_x, &work_area.g_y, &work_area.g_w, &work_area.g_h); set_work(TRUE); rc_copy (&undo_area, &save_area); graf_mouse(ARROW,0x0L); wind_update(END_UPDATE); return(0); } /* Page*/ /************************************************************************/ /************************************************************************/ /**** ****/ /**** Main Program ****/ /**** ****/ /************************************************************************/ /************************************************************************/ /*------------------------------*/ /* main() */ /*------------------------------*/ main() { WORD term_type; if (!(term_type = dodle_init())) dodle(); dodle_term(term_type); } /* * UMUL_DIV() I don't know who needs this in capitals letters but it won't link without it */ int UMUL_DIV(m1, m2, d1) unsigned int m1; unsigned int m2; unsigned int d1; { unsigned int x; x = m2; x = x << 1; x *= m1; x /= d1; x += 1; x = x >> 1; return(x); } dodle_height, &gl_wchar,&gl_hch