/* TODD-DRAW */ /* */ /* The poor man's paint program */ /* (no graphics adapter or printer needed) */ /* */ /* Andrew D. Todd */ /* */ /* v. 1.085 */ /* Working Draft of June 4, 1994 */ /*$LIST*/ #include #include #include #include #include #include /*-------------- Definitions for my package --------------*/ #include "charcode.h" #include "chararry.c" ///fix up the include statements /// /*-------------------------------------------------------------------------*/ /*--- BEGINING OF THE PROGRAM PROPER --------------------------------------*/ /*---------------- Definitions -----------------------*/ #define C_DIM_ROW 66 #define C_DIM_COL 80 #define SCRN_COL_N 80 #define S_MROW 24 #define BORDER E_ASC_LN_DRW_2_HOR #define MIDDLE_C 440 #define NIL 0 #define ADD_SCROLL 1 #define NO_PIV 1 #define OFF_EDGE 2 #define HIDBK 0 #define DELBK 1 #define CLRC 2 #define FARC 3 /*-------------------------------------------------------------------*/ enum dirty_bit {db_cln, db_drt}; /*------------------- The Canvas Type --------------------------------*/ struct canvas { char charbuf [C_DIM_ROW][C_DIM_COL]; char attrbuf[C_DIM_ROW][C_DIM_COL]; /*-----------------------------------------------------------*/ char fname[40]; /* The name of the file associated */ /* with the canvas */ FILE *fhandle; /*and the handle */ /*-----------------------------------------------------------*/ char wname; /* The one character name which has been */ /* temporarily given to this canvas, */ /* in order to distinguish it from */ /* the other one. */ /*-----------------------------------------------------------*/ int c_row, c_col; int updt_row, updt_col; /*-----------------------------------------------------------*/ int voffst; /* The row of the canvas referenced by the 0th */ /* row of the window that canvas */ /* is displayed in */ /*-----------------------------------------------------------*/ int pivon; int pivrow, pivcol; int file_has_contents_q; enum {ce_yes, ce_no} cv_exist; /* Does canvas exist? */ enum dirty_bit cv_drt_bt; /* Has canvas been altered? */ } canv1, canv2, canv3, *forg, *bakg, *temp; /*--------------------- Global Variables -----------------------------*/ /*------------------- The Screen Type --------------------------------*/ struct scrn_tp { int rulerln; int partln; int titleln; int statln; int t_forg_win; int b_forg_win; int t_bakg_win; int b_bakg_win; int s_split_q; } scrn_map; int fill; enum dirty_bit s_drt_bt; int l_marg = NIL; int r_marg = C_DIM_COL-1; enum {ms_yes, ms_no} marg_set = ms_no; char *errmess = "____________"; enum {er_is, er_not} error_bt; /*---------- Delete and Penup Toggles --------------------------------*/ enum toggle_flg {tg_yes, tg_no}; enum toggle_flg wipeout_q = tg_no; char *wipeout_q_indic[2] = {"Wip", " "}; enum toggle_flg pen_up_q = tg_no; char *pen_up_q_indic[2] = {"p_up", " "}; /*------------------------------------------------------------*/ enum {line_c, fill_c, mark_b} mode = line_c; char *mode_indic[3] = {"DrwLin", "Fill ", "MkBlk"}; /*----------------- The Main Routine ----------------------------------*/ main(int argc, char *argv[]) { struct key_in *nkey; forg=&canv1; bakg=&canv2; temp=&canv3; initial(argc, argv, &forg, &bakg, scrn_map); for(;;) { supdate(forg, bakg, scrn_map); get_mov_ch( n_key, 8, 8 ); strcpy( errmess, "____________"); /* if there is both movement and character activity, do the movement first */ if(nkey.have_move_q == LG_YES) slide(nkey.down_move, nkey.right_move, forg); if(nkey.mou_chng_q == LG_YES) { if(nkey.mou_l_bt == LG_YES) {pen_up_q=tg_no; wipeout_q=tg_no;} else if(nkey.mou_r_bt == LG_YES) {pen_up_q=tg_no; wipeout_q=tg_yes;} else {pen_up_q=tg_yes; wipeout_q=tg_no;} } if(nkey.have_char_q == LG_YES) { if(nkey.is_ext_q == LG_YES) switch(nkey.charin){ case INS_KEY: if(mou_chng_q != LG_YES) toggle(&pen_up_q); break; case DEL_KEY: if(mou_chng_q != LG_YES) toggle(&wipeout_q); break; /*if available, mouse buttons supersede the toggle keys */ case PF1_KEY : help_scrn(); break; case PF2_KEY : pen_fill(); break; case PF3_KEY : mode = line_c; break; case PF4_KEY : mode = mark_b; break; case PF10_KEY: menu1(&forg, &bakg, &temp, scrn_map); break; default : break; } else type(nkey.charin, forg); } } } /* The main is initialization and an endless loop - complete */ /*----------------------------------------------------------------------*/ pen_fill() { struct menu_dat key_choose_men = { { "Enter any character to be the new fill" } 1, 1, 1, choose_any } int new_fill; s_drt_bt=db_drt; if( (new_fill =x_menu(key_choose_men)) != R_ERR ) { if(isprint(new_fill)) { mode = fill_c; fill = new_fill; } else strcpy( errmess, "unprintabl"); } else strcpy( errmess, "unprintabl"); } /*--------------------------------------------------------------*/ char_is_move(struct key_in *nkey) { if(nkey->char_is_ext_q == LG_YES) switch(nkey->char) { case LF_ARW_KEY: nkey->down_move= 0; nkey->right_move=-1; return(LG_YES); case HOME_KEY: nkey->down_move=-1; nkey->right_move=-1; return(LG_YES); case UP_ARW_KEY: nkey->down_move=-1; nkey->right_move= 0; return(LG_YES); case PG_UP_KEY: nkey->down_move=-1; nkey->right_move= 1; return(LG_YES); case RT_ARW_KEY: nkey->down_move= 0; nkey->right_move= 1; return(LG_YES); case PG_DN_KEY: nkey->down_move= 1; nkey->right_move= 1; return(LG_YES); case DN_ARW_KEY: nkey->down_move= 1; nkey->right_move= 0; return(LG_YES); case END_KEY: nkey->down_move= 1; nkey->right_move=-1; return(LG_YES); default: return(LG_NO); } else { /*here is where you would insert a switch group to trap a 1-byte code */ return(LG_NO) } } /*-----------------*/ /*--------------------------------------------------------------------*/ /* THE SCREEN UPDATE SECTION */ /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ supdate( struct canvas *forg, struct canvas *bakg, struct scrn_tp *scrn_map ) { int new_voffst; char s2[17]; char s4[120]; char s5[2]; char tempattr; /*-----------------------------------------------*/ /* 1. Work out New Vertical Offset */ { new_voffst = forg->voffst; if(forg->c_row < forg->voffst) new_voffst = imax(forg->c_row-ADD_SCROLL, 0); /*--- scroll up if it would go off top of window ---*/ else if( forg->c_row > forg->voffst + scrn_map->b_forg_win-scrn_map->t_forg_win ) new_voffst = imin( forg->c_row+ADD_SCROLL, C_DIM_ROW-1 ) -scrn_map->b_forg_win +scrn_map->t_forg_win; /*--- or down if it would go off the bottom ---*/ } /*-----------------------------------------------*/ /* 2. Choose an Updating Action */ if(s_drt_bt != db_cln) { forg->voffst = new_voffst; refresh(forg, bakg, scrn_map); } /* full screen update */ else if(new_voffst != forg->voffst) canv_roll(forg, scrn_map, new_voffst); /* window roll */ /* always */ /*-----------------------------------------------*/ /* 3. Set Up the Status Line */ if(mode == fill_c) chtostr(&s5, fill); else s5='\0'; strbuild( &s4, /* = */ pen_up_q_indic[pen_up_q], /* pen up indicator */ " R: ", /* row */ itoa(forg->c_row, &s2, 10), " C: ", /* col */ itoa(forg->c_col, &s2, 10), " ", wipeout_q_indic[wipeout_q], /* delete indicator */ mode_indic[mode], /* mode indicator */ &s5, /* fill character */ " ", errmess, /* error message */ " ", chtostr(&s2, forg->wname), /* window name */ " ", forg->fname /* file name */ ); scrnputs(scrn_map->statln, NIL, &s4, ' ', REVERSE_VIDEO, SCRN_COL_N, LG_YES ); /*-----------------------------------------------*/ /* 4. Set Up the Ruler Line */ poscurs(scrn_map->rulerln, NIL); writechs(' ', REVERSE_VIDEO, SCRN_COL_N); if(marg_set == ms_yes) { if(l_marg >= 1) { poscurs(scrn_map->rulerln, l_marg-1); writechs(E_ASC_LF_TRIANGLE, REVERSE_VIDEO, 1); } if(r_marg <= SCRN_COL_N-2) { poscurs(scrn_map->rulerln, r_marg+1); writechs(E_ASC_RT_TRIANGLE, REVERSE_VIDEO, 1); } poscurs(scrn_map->rulerln, forg->c_col); writechs('M', REVERSE_VIDEO, 1); } else { poscurs(scrn_map->rulerln, forg->c_col); writechs('!', REVERSE_VIDEO, 1); } /*-----------------------------------------------*/ /* 5. Alter a Screen Position to Conform to Canvas */ if(inrange( forg->updt_row, '=', forg->voffst, '=',(forg->voffst+scrn_map->b_forg_win-scrn_map->t_forg_win) )) { poscurs( (forg->updt_row)-(forg->voffst) +(scrn_map->t_forg_win), forg->updt_col ); if( (forg->pivon == LG_YES) && (forg->updt_row == forg->pivrow) && (forg->updt_col == forg->pivcol) ) tempattr = BLINKBIT; /* if this is the pivot, make it blink */ else tempattr = NULL_BYTE; writechs( forg->charbuf[forg->updt_row][forg->updt_col], (forg->attrbuf[forg->updt_row][forg->updt_col] | tempattr), 1 ); } /*-----------------------------------------------*/ /* 6. Revise the update location counters */ forg->updt_row=forg->c_row; forg->updt_col=forg->c_col; /*-----------------------------------------------*/ /* 7. Positions the Screen Cursor */ poscurs( (forg->c_row -forg->voffst +scrn_map->t_forg_win ), forg->c_col ); curson(); } /*----------------------------------------------------------------------*/ /* these three routines are shot through with bugs */ /* create a generic routine to handle n lines from a specified canvas */ canv_roll( struct canvas *forg, struct scrn_tp *scrn_map, int new_voffst /* new offset */ ) { int i, roll; roll=-(new_voffst-forg->voffst); w_roll(scrn_map->t_forg_win, scrn_map->b_forg_win, NIL, SCRN_COL_N-1, roll, NORMAL_VIDEO); forg->voffst=new_voffst; if(roll > 0) putrow( forg, scrn_map->t_forg_win, (scrn_map->t_forg_win)+roll, scrn_map->t_forg_win ); if(roll < 0) putrow( forg, (scrn_map->b_forg_win)+roll, scrn_map->b_forg_win, scrn_map->t_forg_win ); } /*--------------------------------------------------------------------*/ /*------------------------------ Refresh ---------------------------------*/ /* Screen Refresh */ /* replaces window on canvas from memory and clears the dirty bit */ /*------------------------------------------------------------------------*/ refresh( struct canvas *forg, /* canvas to copy from forground from */ struct canvas *bakg, /* " " " " background " */ struct scrn_tp *scrn_map ) { int row; scrnputs(scrn_map->titleln, NIL, "F1)Help 2)Fill 3)Lin 4)Mk_Blk |TODD-DRAW| F10)MENU", ' ', REVERSE_VIDEO, SCRN_COL_N, LG_NO); putrow( forg, scrn_map->t_forg_win, scrn_map->b_forg_win, scrn_map->t_forg_win ); if(scrn_map->s_split_q == tg_yes) { poscurs(scrn_map->partln, NIL); writechs(BORDER, REVERSE_VIDEO, SCRN_COL_N); putrow( bakg, scrn_map->t_bakg_win, scrn_map->b_bakg_win, scrn_map->t_bakg_win ); } s_drt_bt = db_cln; men_bottom(LG_YES, LG_NO, 0); } /*-------------------------------------------------------*/ putrow(struct canvas *forg, /* canvas to copy from */ first_row, /* of the screen to be copied from the canvas */ last_row, /* ditto */ w_voffst) /* the row of the screen which is the 0th row */ /* of the window */ { int row, col, t_c_row, scrn_to_canv_off; scrn_to_canv_off=(forg->voffst)-w_voffst; for(row=first_row; row <= last_row; row++) for( col=NIL ; col < C_DIM_COL ; col++) { t_c_row=row+scrn_to_canv_off; poscurs(row, col); writechs(forg->charbuf[t_c_row][col], forg->attrbuf[t_c_row][col],1); } /* if the pivot point exists and is in this range... */ if( (forg->pivon == LG_YES) && inrange( forg->pivrow, '=', first_row+scrn_to_canv_off, '=', last_row+scrn_to_canv_off ) ) { poscurs( ((forg->pivrow)-scrn_to_canv_off), forg->pivcol ); writechs(forg->charbuf[forg->pivrow][forg->pivcol], (forg->attrbuf[forg->pivrow][forg->pivcol] | BLINKBIT), 1); } /* mark the pivot */ } setsplit( struct canvas *forg, struct canvas *bakg, struct scrn_tp *scrn_map, int tosplit_q ) { if(tosplit_q == LG_YES) { if(bakg->cv_exist == ce_no) return(R_ERR); scrn_map->titleln = 0; scrn_map->t_forg_win = 1; scrn_map->b_forg_win = S_MROW/2; scrn_map->rulerln = S_MROW/2+1; scrn_map->statln = S_MROW/2+2; scrn_map->partln = S_MROW/2+3; scrn_map->t_bakg_win = S_MROW/2+4; scrn_map->b_bakg_win = S_MROW; scrn_map->s_split_q = tg_yes; } else { scrn_map->titleln = 0; scrn_map->t_forg_win = 1; scrn_map->b_forg_win = S_MROW-2; scrn_map->rulerln = S_MROW-1; scrn_map->statln = S_MROW; scrn_map->s_split_q = tg_no; } } help_scrn() { struct menu_dat help_msg = { { " MOVEMENT AND MODES: (Num Lock must be off ) OTHER: ", /*00*/ "-------------------------------------------- Help Screen ", /*01*/ "| < 7 Home > | < 8 UP > | < 9 PgUp > | Draw Fill Char", /*02*/ "| (up, left) | (up) | (up, right) | Mark Block ", /*03*/ "|------------------------------------------| Draw Line ", /*04*/ "| < 4 LEFT > | < 5 > | < 6 RIGHT > | Main Menu ", /*05*/ "| (left) | | (right) | Set l. margin ", /*06*/ "|------------------------------------------| Set r. margin", /*07*/ "| < 1 End > | <2 DOWN > | < 3 PgDn > | ", /*08*/ "| (down, left) | (down) | (down,right) | ", /*09*/ "|------------------------------------------| ", /*10*/ "| < 0 Ins > (mode|toggles) < . Del > | ", /*11*/ "| (pen up--down)|(draw--undraw ) | ", /*12*/ "|------------------------------------------| ", /*13*/ " ", /*14*/ " To do block operations, you must first paint out the extent ", /*15*/ " of the block in MARK mode (you can use the BLOCK-INCLUDE ", /*16*/ " command to save time), set the pivot point (BLOCK-PIVOT) ", /*17*/ " and move to the destination corresponding to it if ", /*18*/ " appropriate, and then perform the operation. ", /*19*/ " ", /*20*/ " ", /*21*/ " ", /*22*/ " ", /*23*/ " Hit any key to resume " /*24*/ }, 25,25,25, choose_any }; x_menu(help_msg); s_drt_bt =db_drt; } /*------------- THE BASIC MOVEMENT ROUTINES ----------------------------*/ /*--------------------------- Slide ------------------------------------*/ /* Handles Cursor Key Input */ /*----------------------------------------------------------------------*/ slide(int irow, int icol, struct canvas *forg) { int nrow, ncol,al; char line_fill[3][3] = { '\\', /* <^ */ '|', /* ^ */ '/', /* ^> */ '-', /* < */ ' ', /* */ '-', /* > */ '/', /* */ }; /* 0. what is the line mode fill character? */ al=line_fill[irow+1][icol+1]; /* 1. would the move take it off side, top, or bottom of canvas? */ nrow = forg->c_row + irow; ncol = forg->c_col + icol; if( inrange(nrow, '=',NIL, '<',C_DIM_ROW) && inrange(ncol, '=',NIL, '<',C_DIM_COL) ) { /* 2. disable the typing margins */ marg_off(); /*--- 3. write to the current position ---*/ if(pen_up_q == tg_no) { if(mode == mark_b) { if(wipeout_q == tg_yes) forg->attrbuf[forg->c_row][forg->c_col] = NORMAL_VIDEO; else forg->attrbuf[forg->c_row][forg->c_col] = REVERSE_VIDEO; } else { forg->cv_drt_bt=db_drt; if(wipeout_q == tg_yes) forg->charbuf[forg->c_row][forg->c_col] = ' '; else if(mode == line_c) forg->charbuf[forg->c_row][forg->c_col] = al; else forg->charbuf[forg->c_row][forg->c_col] = fill; } } /*--- 4. now move the cursor ---*/ forg->c_row = nrow; forg->c_col = ncol; } } /*--------------------------- Type ------------------------------------*/ /* Handles Printable Character Input */ /*---------------------------------------------------------------------*/ type(int al, struct canvas *forg) { int trow, tcol, icol, i; switch(al) { case '\b': if( forg->c_col > NIL ) { forg->c_col--; forg->charbuf[forg->c_row][forg->c_col]=' '; forg->updt_col=forg->c_col; ver_marg(forg->c_col); } break; /* logic for back space */ case '\t': marg_set = ms_yes; l_marg = forg->c_col; /* set margins for note */ break; case '\r': ver_marg(forg->c_col); car_ret(LG_NO, forg); /* logic for car ret */ break; default: if(isprint(al)) /* if printable */ { ver_marg(forg->c_col); forg->cv_drt_bt=db_drt; forg->charbuf[forg->c_row][forg->c_col] = al; /* change array*/ if(forg->c_col < r_marg) forg->c_col++; else car_ret(LG_YES, forg); } } } /* sends an ordinary character ( or backspace) to the screen */ /* both operate on the principle of write and then move COMPLETE*/ /*-------------------------------------------------------------------------*/ ver_marg(int n_l_marg) { if(marg_set == ms_no) { l_marg = n_l_marg; marg_set = ms_yes; } else if((l_marg > n_l_marg) && (n_l_marg >= NIL)) l_marg = n_l_marg; } marg_off() { l_marg = NIL; r_marg = C_DIM_COL-1; marg_set = ms_no; } car_ret(int wrapflg, struct canvas *forg) { int s_w_col; if(forg->c_row >= (C_DIM_ROW-1) ) { sound(MIDDLE_C,10); return(R_ERR);} r_marg = forg->c_col; /* now wrap if appropriate, and move the cursor */ if(wrapflg == LG_YES) { for(s_w_col = r_marg; s_w_col > l_marg; s_w_col--) if(forg->charbuf[forg->c_row][s_w_col] == ' ') break; /*loc 1st spac*/ if( s_w_col > l_marg) /*if it is to the right of the left margin */ { s_drt_bt = db_drt; forg->cv_drt_bt = db_drt; carrmve(forg->charbuf, C_DIM_ROW, C_DIM_COL, 1, (l_marg-s_w_col-1), forg->c_row, forg->c_row, (s_w_col+1), r_marg, ' '); forg->c_col=l_marg+r_marg-s_w_col; } else forg->c_col=l_marg; } else forg->c_col=l_marg; forg->c_row++; } /*----------------------------------------------------------------------*/ toggle(enum toggle_flg *var) { if(*var == tg_no) *var = tg_yes; else *var = tg_no; } /*--------------------------- Initial ----------------------------------*/ /* The initialization routine */ /*----------------------------------------------------------------------*/ initial( int argc, char *argv[], int **pforg, int **pbakg, struct scrn_tp *scrn_map ) { int lflag=LG_NO; struct canvas *forg, *bakg; forg = *pforg; bakg = *pbakg; clrscrn(); forg->cv_exist=ce_no; bakg->cv_exist=ce_no; if( argc >= 2) { strcpy( forg->fname, argv[1]); lflag = LG_YES; } if(loadfil(lflag, forg) == N_ERR) { forg->wname=' '; setsplit(forg, bakg, scrn_map, LG_NO); s_drt_bt = db_drt; } else { clrscrn(); exit(3); } } /*---------------------------- Menu1 -----------------------------------*/ /* The Main Menu, invoked by F10 */ /*----------------------------------------------------------------------*/ menu1( int **pforg, int **pbakg, int **ptemp, struct scrn_tp *scrn_map ) { struct canvas *forg, *bakg, *temp; int option; struct menu_dat menu_msg = { { "The options are: ", /*00*/ "FILE: quit done change save ", /*01*/ "BLOCK: move copy hide del pivot fill other_canvas include ", /*02*/ "OTHER: clear_canvas print_canvas split_screen unsplit_screen " /*03*/ }, 4, 1, 3, choose_upcase }; struct menu_dat blok_men_msg = { { "block operations: ",/*00*/ " COPY the block, moving pivot point to cursor",/*01*/ " MOVE \" \" ",/*02*/ " DELete the block ",/*03*/ " HIDE \" \" ",/*04*/ " mark the PIVOT point ",/*05*/ " FILL the block with a specified character ",/*06*/ " INCLUDE the interior of the block ",/*07*/ " REFLECT the block across the cursor ",/*08*/ " from the OTHER canvas: " /*09*/ }, 10, 1, 9, choose_upcase }; struct menu_dat blok_smen1_msg = { { "reflect the block", /*00*/ "HORIZONTALY", /*01*/ "VERTICALY" /*02*/ }, 3, 1, 2, choose_upcase }; struct menu_dat blok_smen2_msg = { { "far block operations:", /*00*/ "COPY", /*01*/ "MOVE", /*02*/ "from other canvas" /*03*/ }, 4, 1, 2, choose_upcase }; struct menu_dat file_men_msg = { { "file operations: ",/*00*/ " QUIT this canvas without saving ",/*01*/ "all DONE with this canvas, save and exit or go to the other one ",/*02*/ " CHANGE to the other canvas ",/*03*/ " SAVE this canvas and go on editing " /*04*/ }, 5, 1, 4, choose_upcase }; struct menu_dat other_men_msg = { { "Other functions: ",/*00*/ "CLEAR the canvas ",/*01*/ "PRINT the canvas ",/*02*/ "SPLIT the screen ",/*03*/ "UNSPLIT the screen " /*04*/ }, 5, 1, 4, choose_upcase }; forg = *pforg; bakg = *pbakg; temp = *ptemp; marg_off(); s_drt_bt = db_drt; option=x_menu(menu_msg); switch(option) { case 'F': option=x_menu(file_men_msg); switch(option) { case 'Q': savedone(LG_NO, LG_YES, pforg, pbakg, scrn_map); break; case 'D': savedone(LG_YES,LG_YES, pforg, pbakg, scrn_map); break; case 'C': change(pforg, pbakg, scrn_map); break; case 'S': savedone(LG_YES,LG_NO, pforg, pbakg, scrn_map); break; default : break; }; break; case 'B': option=x_menu(blok_men_msg); switch(option) { case 'C': copymove(HIDBK, forg, bakg, temp); break; case 'M': copymove(DELBK, forg, bakg, temp); break; case 'D': pixmanip(DELBK, forg); break; case 'H': pixmanip(HIDBK, forg); break; case 'P': setpiv(forg, LG_YES, forg->c_row, forg->c_col); break; case 'I': enclose(forg); break; case 'F': overfill(forg); break; case 'R': option=x_menu(blok_smen1_msg); switch(option) { case 'H': reflect(LG_YES, forg); break; case 'V': reflect(LG_NO, forg); break; default : break; }break; case 'O': option=x_menu(blok_smen2_msg); switch(option) { case 'C': copymove(HIDBK+FARC, forg, bakg, temp); break; case 'M': copymove(DELBK+FARC, forg, bakg, temp); break; default : break; }break; default : break; } break; case 'O': option=x_menu(other_men_msg); switch(option) { case 'C': pixmanip(CLRC, forg); break; case 'P': prntcanv(forg); break; case 'S': setsplit(forg, bakg, scrn_map, LG_YES); break; case 'U': setsplit(forg, bakg, scrn_map, LG_NO); break; default : break; }; break; default : break; }; } /*-------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/ /* routines to export to and from files */ /* to be rewritten to deal with the array */ /*------------------------------------------------------------------------*/ prntcanv(struct canvas *canv) { put_canv(canv, stdprn); /* print the canvas */ putc( '\f', stdprn); /* and then issue a */ } /* sends screen to the printer */ /*think about commonizing this with the savefile */ /*----------------------------- Pixmanip ----------------------------------*/ /* applies an action specified by blnkflag (hide or delete block, */ /* clear canvas) to all positions in the canvas targ_canv */ /*-------------------------------------------------------------------------*/ pixmanip( int blnkflag, struct canvas *targ_canv ) { switch(blnkflag) { case DELBK: carrmsk(targ_canv->attrbuf, '!', NORMAL_VIDEO, targ_canv->charbuf, C_DIM_ROW, C_DIM_COL, ' '); targ_canv->cv_drt_bt = db_drt; case HIDBK: carrset(targ_canv->attrbuf, C_DIM_ROW, C_DIM_COL, NORMAL_VIDEO); break; case CLRC: carrset(targ_canv->attrbuf, C_DIM_ROW, C_DIM_COL, NORMAL_VIDEO); carrset(targ_canv->charbuf, C_DIM_ROW, C_DIM_COL, ' '); targ_canv->voffst = NIL; targ_canv->c_row = NIL; targ_canv->c_col = NIL; targ_canv->cv_drt_bt = db_drt; } setpiv(targ_canv, LG_NO, NIL, NIL); } /*------------------------------ Collect ----------------------------------*/ /* copies the block of src_canv into dest_canv, which is blanked, with a */ /* displacement so that the pivot is at the location (newrow, newcol). */ /* All the other positions are filled with spaces of normal attribute. */ /* - returns 0 if correct, 1 if no pivot, 2 if the move would take */ /* the block over the edge */ /*-------------------------------------------------------------------------*/ collect( struct canvas *src_canv, struct canvas *dest_canv, int newrow, int newcol ) { int row, col, mrow, mcol, lrow, hrow, lcol, hcol; if( src_canv->pivon == LG_NO) return(NO_PIV); mrow = newrow-src_canv->pivrow; mcol = newcol-src_canv->pivcol; carrset(dest_canv->attrbuf, C_DIM_ROW, C_DIM_COL, NORMAL_VIDEO); carrset(dest_canv->charbuf, C_DIM_ROW, C_DIM_COL, NORMAL_VIDEO); carrmcpy(src_canv->attrbuf, '!', NORMAL_VIDEO, src_canv->attrbuf, dest_canv->attrbuf, C_DIM_ROW, C_DIM_COL); carrmcpy(src_canv->attrbuf, '!', NORMAL_VIDEO, src_canv->charbuf, dest_canv->charbuf, C_DIM_ROW, C_DIM_COL); carrcbnd(src_canv->attrbuf, C_DIM_ROW,C_DIM_COL, &lrow, &hrow, &lcol, &hcol, '!', NORMAL_VIDEO ); dest_canv->cv_drt_bt = db_drt; if( (mrow+lrow < NIL) || (mrow+hrow >= C_DIM_ROW) || (mcol+lcol < NIL) || (mcol+hcol >= C_DIM_COL) ) return(OFF_EDGE); else { /* move in the array */ carrmve(dest_canv->charbuf, C_DIM_ROW,C_DIM_COL,mrow,mcol,lrow,hrow,lcol,hcol, ' '); carrmve(dest_canv->attrbuf, C_DIM_ROW,C_DIM_COL,mrow,mcol,lrow,hrow,lcol,hcol, NORMAL_VIDEO); return(N_ERR); } } /*---------------------------------------------------------------*/ copymove( int copyflag, struct canvas *forg, struct canvas *bakg, struct canvas *temp ) { int x; if(copyflag >= FARC) { x=collect(bakg, temp, forg->c_row, forg->c_col); copyflag-=FARC; } else x=collect(forg, temp, forg->c_row, forg->c_col); /* collect it */ switch(x){ case N_ERR : pixmanip(copyflag, forg); /* hide or delete on curent canvas */ replace(temp, forg); /* copy block back to current canvas */ break; case NO_PIV : strcpy( errmess, "no pivot pnt"); break; case OFF_EDGE : strcpy( errmess, "off the edge"); break; default : strcpy( errmess, "gone wombly "); break; } } /* copy (HIDBK), move(DELBK), farcopy(HIDBK+FARC), or farmove(DELBK+FARC) */ /*--------------------------------------------------------------------------*/ replace( struct canvas *src_canv, struct canvas *dest_canv ) { int row, col, trow, tcol; carrmcpy(src_canv->attrbuf, '!', NORMAL_VIDEO, src_canv->charbuf, dest_canv->charbuf, C_DIM_ROW, C_DIM_COL); carrmcpy(src_canv->attrbuf, '!', NORMAL_VIDEO, src_canv->attrbuf, dest_canv->attrbuf, C_DIM_ROW, C_DIM_COL); setpiv(dest_canv, LG_YES, dest_canv->c_row, dest_canv->c_col); dest_canv->cv_drt_bt = db_drt; } /* copies back the block from the buffer into the picture */ /*---------------------------*/ setpiv(struct canvas *targ_canv, int state, int row, int col) { targ_canv->pivon = state; targ_canv->pivrow = row; targ_canv->pivcol = col; } /*------------------------*/ enclose(struct canvas *targ_canv) { carrfldf(targ_canv->attrbuf, targ_canv->c_row, targ_canv->c_col, C_DIM_ROW, C_DIM_COL, REVERSE_VIDEO); } /* the auto block mark function */ /*--------------------------------------------------------------------------*/ overfill(struct canvas *targ_canv) { int tfill; if( (tfill=askchar( "what character to overwrite the whole block with? Use ESC to escape.") ) == R_ERR ) return(R_ERR); else { carrmsk(targ_canv->attrbuf, '=', REVERSE_VIDEO, targ_canv->charbuf, C_DIM_ROW, C_DIM_COL, tfill); return(N_ERR); } } /*-------------------------------------------------------------------------*/ reflect(int is_horizontal_q, struct canvas canv) { } to reflect: 1. get the bounds 2. make sure it doesn't cross the pivot line and the reflection doesn't go over the edge. isolate this as a function, for both horiz and vert scrnmin, scrnmax, blockmin, blockmax, cursor 3. copy backwards, moving the block marking to the new copy. isolate at the level of each character srcrow, srccol, dstrow, dstcol 4. do we need to make the screen dirty? /*-----------------------------------------------------------------------*/ /* WINDOW AND FILE MANIPULATION */ /* */ /* The Open and Input Section */ /*------------------------- Change --------------------------------------*/ /* Brings in (and if necesary opens) the other canvas */ /*-----------------------------------------------------------------------*/ change( int **pforg_canv, int **pbakg_canv, struct scrn_tp *scrn_map ) { struct canvas *forg_canv, *bakg_canv; forg_canv = *pforg_canv; bakg_canv = *pbakg_canv; if(bakg_canv->cv_exist != ce_yes) /*if not open */ { if(loadfil(LG_NO, bakg_canv) == N_ERR)/* open the canvas in background*/ { forg_canv->wname='X'; bakg_canv->wname='Y'; pswap(pforg_canv, pbakg_canv); setsplit(forg, bakg, scrn_map, LG_YES); } } else /* if already open */ { pswap(pforg_canv, pbakg_canv); } } /* routine to swap foreground and background canvases */ /*------------------------------------------ ------------------------- */ int (*g_file_open)(); int (*g_file_valid)(); struct parm_blk { int make_believe; } f_sel_parm; /*---------------------------------------------------------------------*/ loadfil( int f_nm_pres_q, /* file name already present in canvas */ struct canvas *canv /* canvas to load into */ ) { int row; int dhandle; char *sptr; char str[84]; fpos_t locat; /* debugging code */ if( ( dhandle= getfile(f_nm_pres_q, LG_YES, "File to edit?", canv->fname, f_sel_parm, g_file_open, g_file_valid ) ) != R_ERR ) { /* read the file */ close(dhandle); canv->fhandle=fopen(canv->fname, "r"); pixmanip(2, canv); rewind(canv->fhandle); fgetpos(canv->fhandle, &locat); /* debugging code */ for( row=NIL ; row < C_DIM_ROW ; row++) { if( fgets(str,83,canv->fhandle) != NULL) /*read a line */ { sptr=strchr(str, '\n'); /* cut off the newline */ *sptr=NULL_BYTE; carrstl(str, canv->charbuf, row, C_DIM_COL, ' '); } /* and put the line in the array */ else break; /* until there are no more */ } if(row == NIL) canv->file_has_contents_q = LG_NO; else canv->file_has_contents_q = LG_YES; canv->cv_exist=ce_yes; canv->cv_drt_bt=db_cln; return(N_ERR); } else return(R_ERR); } /*--------------------------------------------------------------------*/ g_file_open( char *filename, struct parm_blk *f_sel_parm ) { int dhandle; dhandle=open(filename, O_RDWR|O_CREAT|O_TEXT, S_IREAD|S_IWRITE); return(dhandle); } /*-----------------------------------------------------------------------*/ /* The Close and Output Section */ /*------------------- Savedone ------------------------------------------*/ savedone( int save_f, /* LG_YES or LG_NO save */ int done_f, /* " done */ int **pcur_canv, int **palt_canv, struct scrn_tp *scrn_map ) { struct canvas *cur_canv, *alt_canv; struct menu_dat abandon_verify_men = { { "Changes have been made. Do you really want to abandon?", "No", "Yes" } 3, 1, 2, choose_upcase } cur_canv = *pcur_canv; alt_canv = *palt_canv; if(save_f == LG_YES) { if( savefile(cur_canv) != N_ERR) return(R_ERR); } else if(done_f == LG_YES) /* if instructed to exit without saving, */ { if(cur_canv->cv_drt_bt == db_drt) /*but the canvas has been changed */ { /* prompt for specific permission */ if(x_menu(abandon_verify_men) != 'Y') { strcpy( errmess, "abort"); return(R_ERR); } else strcpy( errmess, "abandon"); } else strcpy( errmess, "quit"); } if(done_f == LG_YES) { fclose(cur_canv->fhandle); cur_canv->cv_exist=ce_no; alt_canv->wname=' '; if(alt_canv->cv_exist == ce_yes) { pswap(palt_canv, pcur_canv); setsplit(alt_canv, cur_canv, scrn_map, LG_NO); } else { clrscrn(); exit(N_ERR); } } } /* save or don't save, then exit or don't exit that canvas */ /* if the other one is open, go into it, else exit the program */ /*--------------------------------------------------------------------------*/ savefile(struct canvas *canv) { int tflags; char tpath[MAXPATH], tdrive[MAXDRIVE], tdir[MAXDIR], tfile[MAXFILE], texten[MAXEXT]; /*get the backup name using fnmerge*/ tflags=fnsplit(canv->fname,tdrive,tdir,tfile,texten); strcpy(texten, ".gbk"); fnmerge(tpath,tdrive,tdir,tfile,texten); if((unlink(tpath) != N_ERR ) && ( errno != ENOENT)) { strcpy(errmess, "backup file locked"); return(R_ERR); } else { /*if the backup file doesnt exist, or can be deleted */ fclose(canv->fhandle); if(canv->file_has_contents_q == LG_YES) rename(canv->fname, tpath); /*close main file, rename to backup, */ canv->fhandle=fopen(canv->fname, "w"); /* reopen in write mode */ rewind(canv->fhandle); if(put_canv(canv, canv->fhandle) == R_ERR) { strcpy(errmess, "could not write to file"); return(R_ERR); } else { canv->file_has_contents_q = LG_YES; canv->cv_drt_bt=db_cln; strcpy( errmess, "Saved"); return(N_ERR); } } } /*saves and resets the canvas dirty bit, returns N_ERR if sucessful */ /* does its own sucess or error posting via errmess */ /*--------------------------------------------------------------------------*/ /* Put_canv writes the character array field of the CANVAS to an open */ /* high-level file, with handle THANDLE, but does not set any */ /* status flags */ put_canv(struct canvas *canv, FILE *thandle) { char str[84], str2[4]; int row, dummy, lastline; carrcbnd(canv->charbuf, C_DIM_ROW, C_DIM_COL, &dummy, &lastline, &dummy, &dummy, '!', ' '); for( row=NIL ; row <= lastline ; row++) { carrlts(canv->charbuf, str, row, C_DIM_COL, ' '); /* convert each line */ strcat(str,chtostr(str2,'\n')); /* into a string, add newline */ if(fputs(str, thandle) != N_ERR) return(R_ERR); /* and write it, reporting error */ } return(N_ERR); } /*-------------------------------------------------------------------------*/ pswap(int **pt1, int **pt2) { int **t_ptr; t_ptr=*pt1; *pt1=*pt2; *pt2=t_ptr; }