/* linedraw.e $Revision: 1.3 $ */ /* EPSHeader File: linedraw.e Author: J. Kercheval Created: Tue, 04/02/1991 20:26:00 */ /* EPSRevision History J. Kercheval Tue, 04/02/1991 23:10:28 creation J. Kercheval Wed, 04/03/1991 15:49:24 add context sensitive char insert J. Kercheval Wed, 04/03/1991 20:30:22 add line set selection J. Kercheval Wed, 04/03/1991 21:02:19 clean code and complete commenting J. Kercheval Thu, 04/04/1991 11:48:41 add help text J. Kercheval Thu, 04/04/1991 12:21:51 handle embedded tabs intelligently J. Kercheval Thu, 04/04/1991 17:36:07 completion for V1.0 J. Kercheval Thu, 03/19/1992 13:42:04 modify for V6.0 and fix tab munge J. Kercheval Fri, 09/16/1994 13:04:19 add support for virtual space J. Kercheval Tue, 05/02/1995 23:11:44 correct Epsilon V7.0 virtual problems Lugaru 7/10/2003 modify for Epsilon 12 */ /* This file implements a line drawing mode. It is context sensitive and will correctly place intersection characters where required. Several line drawing sets are available including most of the commonly used standards for character line drawing in the UNIX and MSDOS worlds. John Kercheval 15563 10th Ave NE Seattle, WA 98155-6209 INTERNET: johnk@wrq.com Compu$erve: 72450,3702 line_draw_mode Turn on line drawing mode using the arrow keys. This mode allows the direct entry of a line drawing set by using the arrow keys to specify the direction of line draw. The commands recognized in this mode are: X Exit line drawing mode D Toggle drawing. When "Line No Draw" is in the mode line you may use the arrow keys for movement without drawing. When "Line Draw" is in the mode line you may use the arrow keys to draw using the current line drawing character set. L Select the current line drawing character set. H,? Show this help screen. There is a choice of 8 different line drawing sets as listed below: Plus: This set uses the +, - and | to create line drawings and is a good choice for standard ascii drawings. Smooth Plus: This set uses the +, -, | ,\ and / characters to create a set with smooth external corners. Star: This set is the * character and is commonly used for comment boxing. Comment: This set is the # character and is also a common comment character, but is usually used as a comment leader rather than for boxing. Single: This is a single line character set. Double: This is a double line character set. Shade: This is a large character which uses about 50% of the character space. Solid: This is a large character which uses in excess of 50% of the character space. */ #include "eel.h" #ifndef BOOLEAN #define BOOLEAN int #define TRUE 1 #define FALSE 0 #endif #define UP 0x01 #define RIGHT 0x02 #define DOWN 0x04 #define LEFT 0x08 keytable line_draw_tab; /* key table for line drawing mode */ buffer short *old_key_tab; /* the key table present before line mode */ buffer char *old_major_mode; /* the major mode before line mode */ /* the prompt seen in the echo line during line draw mode */ char line_draw_mode_prompt[] = "(?) Help, (D) Toggle Drawing, (L) Linetype, (X) Exit line draw mode"; /* the mode name global for memory optimization */ char line_draw_mode_base[] = "Line"; char line_draw_mode_name[15]; /* the line draw character array */ char line_draw_set[12]; /*---------------------------------------------------------------------------- * * when_loading * * sets up the new key table for line drawing mode. This disables all * standard character input but does nothing with the standard bindings * for non standard keys. * ----------------------------------------------------------------------------*/ when_loading() { fix_key_table(reg_tab, (short) normal_character, line_draw_tab, -1); } /*---------------------------------------------------------------------------- * * line_draw_help * * calls the help facility for line drawing mode. * ----------------------------------------------------------------------------*/ line_draw_help() on line_draw_tab['h'], line_draw_tab['?'] { help_on_command("line_draw_mode"); note("%s",line_draw_mode_prompt); } /*---------------------------------------------------------------------------- * * line_draw_active * * reactivates the line drawing using the arrow keys * ----------------------------------------------------------------------------*/ line_draw_active() { /* arrow keys are drawing */ line_draw_tab[KEYLEFT] = find_index("line_draw_left"); line_draw_tab[KEYUP] = find_index("line_draw_up"); line_draw_tab[KEYRIGHT] = find_index("line_draw_right"); line_draw_tab[KEYDOWN] = find_index("line_draw_down"); /* next 'd' toggles drawing off */ line_draw_tab['d'] = find_index("line_draw_inactive"); /* alter mode line */ strcpy(line_draw_mode_name,line_draw_mode_base); strcat(line_draw_mode_name," Draw"); major_mode = line_draw_mode_name; make_mode(); } /*---------------------------------------------------------------------------- * * line_draw_inactive * * disables line drawing so that standard positioning can occur using * the arrow keys. This allows user to move current line drawing location. * ----------------------------------------------------------------------------*/ line_draw_inactive() { /* arrow keys are *normal* */ line_draw_tab[KEYLEFT] = find_index("backward_character"); line_draw_tab[KEYUP] = find_index("up_line"); line_draw_tab[KEYRIGHT] = find_index("forward_character"); line_draw_tab[KEYDOWN] = find_index("down_line"); /* next 'd' toggles drawing on */ line_draw_tab['d'] = find_index("line_draw_active"); /* alter mode line */ strcpy(line_draw_mode_name,line_draw_mode_base); strcat(line_draw_mode_name," No Draw"); major_mode = line_draw_mode_name; make_mode(); } /*---------------------------------------------------------------------------- * * line_draw_index() * * The parameter, direction, is a bit mask specified as UP, RIGHT, * DOWN or LEFT. Behavior is undetermined for general integer * values. This subroutine will compute and return an index value. * This is a mapping where the value of the array at the computed * index is an index into the character set array. For instance, * if the computed index is 12 on a Down computation, then the * value of the index in the character set array to place in the * buffer is line_draw_set[ down_map[ 12 ] ]. * * Map Set "³ À Á Ù Ã Å ´ Ú Â ¿ Ä"; * * {0,1,2,3,4,5,6,7,8,9,10} * * UP mask 0x1 * "³ ³ À À ³ ³ à à ٠٠Á Á ´ ´ Å Å" * * {0,0,1,1,0,0,4,4,3,3,2,2,6,6,5,5} * * RIGHT mask 0x2 * "Ä À Ä À Ú Ã Ú Ã Ä Á Ä Á  Š Å" * * {10,1,10,1,7,4,7,4,10,2,10,2,8,5,8,5} * * DOWN mask 0x4 * "³ ³ Ú Ã ³ ³ Ú Ã ¿ ´  Š¿ ´  Å" * * {0,0,7,4,0,0,7,4,9,6,8,5,9,6,8,5} * * LEFT mask 0x8 * "Ä Ù Ä Á ¿ ´ Â Å Ä Ù Ä Á ¿ ´  Å" * * {10,3,10,2,9,6,8,5,10,3,10,2,9,6,8,5} * * line_draw_is_map_member() * * This is a helper function to test membership in a set of * characters specified in one of the map arrays. * ----------------------------------------------------------------------------*/ char line_draw_up_map[] = { 0,0,1,1,0,0,4,4,3,3,2,2,6,6,5,5 }; char line_draw_right_map[] = { 10,1,10,1,7,4,7,4,10,2,10,2,8,5,8,5 }; char line_draw_down_map[] = { 0,0,7,4,0,0,7,4,9,6,8,5,9,6,8,5 }; char line_draw_left_map[] = { 10,3,10,2,9,6,8,5,10,3,10,2,9,6,8,5 }; BOOLEAN line_draw_is_map_member(map, ch) char *map; char ch; { int i; /* check the line drawing set with the passed direction mapping */ for (i=0; i<16; i++) { if (ch == line_draw_set[map[i]]) { return TRUE; } } return FALSE; } int line_draw_index(direction) int direction; { char cur_char; /* the potential line character */ int old_point; /* the starting point in the current buffer */ int old_column; /* the starting column in the current line */ int map_index; /* the final index into the mapping table */ /* init */ old_point = point; old_column = virtual_column(); map_index = 0; /* check char above current */ if (nl_reverse()) { to_virtual_column(old_column); if (old_column == virtual_column() && cursor_to_column < 0) { cur_char = curchar(); if (index(line_draw_set, cur_char)) { if (line_draw_is_map_member(line_draw_down_map, cur_char)) { map_index |= UP; } } } } point = old_point; /* check char below current */ if (nl_forward()) { to_virtual_column(old_column); if (old_column == virtual_column() && cursor_to_column < 0) { cur_char = curchar(); if (index(line_draw_set, cur_char)) { if (line_draw_is_map_member(line_draw_up_map, cur_char)) { map_index |= DOWN; } } } } point = old_point; /* check char to right of current */ to_virtual_column(old_column + 1); if (old_column + 1 == virtual_column() && cursor_to_column < 0) { cur_char = curchar(); if (index(line_draw_set, cur_char)) { if (line_draw_is_map_member(line_draw_left_map, cur_char)) { map_index |= RIGHT; } } } point = old_point; /* check char to left of current */ to_virtual_column(old_column - 1); if (old_column - 1 == virtual_column() && cursor_to_column < 0) { cur_char = curchar(); if (index(line_draw_set, cur_char)) { if (line_draw_is_map_member(line_draw_right_map, cur_char)) { map_index |= LEFT; } } } point = old_point; /* return the index into the line_draw_set to be used */ switch (direction) { case UP: return line_draw_up_map[map_index]; break; case RIGHT: return line_draw_right_map[map_index]; break; case DOWN: return line_draw_down_map[map_index]; break; case LEFT: return line_draw_left_map[map_index]; break; default: return 0; break; } } /*---------------------------------------------------------------------------- * * line_draw_check_point * * validate that the character at point is a space * ----------------------------------------------------------------------------*/ int line_draw_check_point() { int cur_col; cur_col = virtual_column(); force_to_column(cur_col+1); force_to_column(cur_col); return cur_col; } /*---------------------------------------------------------------------------- * * line_draw_up * * handles the up arrow line drawing * ----------------------------------------------------------------------------*/ line_draw_up() { int cur_col; /* current column in line */ /* save the current line drawing column */ cur_col = line_draw_check_point(); /* place the line character */ replace(point, line_draw_set[line_draw_index(UP)]); /* move to the previous line and go to the correct column */ nl_reverse(); force_to_column(cur_col); /* place prompt */ note("%s",line_draw_mode_prompt); } /*---------------------------------------------------------------------------- * * line_draw_right * * handles the right arrow line drawing * ----------------------------------------------------------------------------*/ line_draw_right() { int cur_col; /* current column in line */ /* save the current line drawing column */ cur_col = line_draw_check_point(); /* place the line character */ replace(point, line_draw_set[line_draw_index(RIGHT)]); /* move left to next character */ force_to_column(cur_col+1); /* place prompt */ note("%s",line_draw_mode_prompt); } /*---------------------------------------------------------------------------- * * line_draw_down * * handles the down arrow line drawing * ----------------------------------------------------------------------------*/ line_draw_down() { int cur_col; /* current column in line */ /* save the current line drawing column */ cur_col = line_draw_check_point(); /* place the line character */ replace(point, line_draw_set[line_draw_index(DOWN)]); /* move to the next line and go to the correct column */ if (!nl_forward()) { insert('\n'); } force_to_column(cur_col); /* place prompt */ note("%s",line_draw_mode_prompt); } /*---------------------------------------------------------------------------- * * line_draw_left * * handle the left arrow line drawing * ----------------------------------------------------------------------------*/ line_draw_left() { int cur_col; /* current column in line */ /* save the current line drawing column */ cur_col = line_draw_check_point(); /* place the line character */ replace(point, line_draw_set[line_draw_index(LEFT)]); /* stay within the current line */ if (cur_col) { /* move left to next character */ force_to_column(cur_col-1); } /* place prompt */ note("%s",line_draw_mode_prompt); } /*---------------------------------------------------------------------------- * * line_draw_select * * This routine enables the user to choose among all the available * character sets. * * There are 8 character line drawing sets. The sets are arranged in * a buffer and shown to the user in more mode. A response (1-8) is * requested with standard echo line input. * * These character sets are commonly used for 7 and 8 bit character * line drawings. The order counts in the character set arrays. The * characters used to draw corners and intersections rely on the following * relationship: * * Index Meaning * ----- ------- * 0 Vertical element, no intersections * 1 Lower left corner * 2 Bottom horizontal line intersection with vertical * 3 Lower right corner * 4 Left vertical line intersection with horizontal * 5 Center intersection, vertical with horizontal * 6 Right vertical line intersection with horizontal * 7 Upper left corner * 8 Top horizontal line intersection with vertical * 9 Upper right corner * 10 Horizontal element, no intersections * ----------------------------------------------------------------------------*/ char line_draw_plus_set[] = "|+++++++++-"; char line_draw_splus_set[] = "|\\+/+++/+\\-"; char line_draw_star_set[] = "***********"; char line_draw_comment_set[]= "###########"; #ifdef UNIX /* UNIX gets the brain damaged stuff as the default */ char line_draw_single_set[] = "..........."; char line_draw_double_set[] = ":::::::::::"; char line_draw_shade_set[] = "%%%%%%%%%%%"; char line_draw_solid_set[] = "@@@@@@@@@@@"; #else /* MSDOS and OS2 at least have decent line characters */ char line_draw_single_set[] = "³ÀÁÙÃÅ´Ú¿Ä"; char line_draw_double_set[] = "ºÈʼÌιÉË»Í"; char line_draw_shade_set[] = "±±±±±±±±±±±"; char line_draw_solid_set[] = "ÛÛÛÛÛÛÛÛÛÛÛ"; #endif line_draw_select() on line_draw_tab['l'] { char *select_buf; /* the buffer viewed with more mode */ char *current_buf; /* the current buffer */ char response[80]; /* the response to the set query */ int select_set; /* the integer translation of response */ /* init */ current_buf = bufname; select_buf = temp_buf(); /* set current buffer to more mode buffer */ bufname = select_buf; /* fill the more mode buffer */ bprintf("Select the desired line draw set below:\n\n"); bprintf(" 1) The plus set \"%s\"\n",line_draw_plus_set); bprintf(" 2) The smooth plus set \"%s\"\n",line_draw_splus_set); bprintf(" 3) The star set \"%s\"\n",line_draw_star_set); bprintf(" 4) The comment set \"%s\"\n",line_draw_comment_set); bprintf(" 5) The single set \"%s\"\n",line_draw_single_set); bprintf(" 6) The double set \"%s\"\n",line_draw_double_set); bprintf(" 7) The shade set \"%s\"\n",line_draw_shade_set); bprintf(" 8) The solid set \"%s\"\n\n",line_draw_solid_set); /* move back to current buffer, view the more mode buffer and parse the response */ bufname = current_buf; say("Select line draw character set [5]: "); view_buffer(select_buf, FALSE); do { get_strdef(response,"Select line draw character set","5"); select_set = strtoi(response,10); } while (select_set < 1 || select_set > 8); /* assign the line draw character set based on the response */ switch (select_set) { case 1: strcpy(line_draw_set, line_draw_plus_set); break; case 2: strcpy(line_draw_set, line_draw_splus_set); break; case 3: strcpy(line_draw_set, line_draw_star_set); break; case 4: strcpy(line_draw_set, line_draw_comment_set); break; case 5: strcpy(line_draw_set, line_draw_single_set); break; case 6: strcpy(line_draw_set, line_draw_double_set); break; case 7: strcpy(line_draw_set, line_draw_shade_set); break; case 8: strcpy(line_draw_set, line_draw_solid_set); break; } /* clean up */ delete_buffer(select_buf); screen_messed(); note("%s",line_draw_mode_prompt); } /*---------------------------------------------------------------------------- * * line_draw_exit * * restore the mode and key table and clean the echo line * ----------------------------------------------------------------------------*/ line_draw_exit() on line_draw_tab['x'] { /* restore the previous mode */ mode_keys = old_key_tab; major_mode = old_major_mode; make_mode(); /* clear the echo line */ note(""); } /*---------------------------------------------------------------------------- * * line_draw_mode * * start the line draw mode, initialize required variables and save old * buffer specific stuff needed later. The will be the completion * command interface to the user. * ----------------------------------------------------------------------------*/ command line_draw_mode() on cx_tab[CTRL('l')] { /* reset the key table */ old_key_tab = mode_keys; mode_keys = line_draw_tab; /* reset the major mode string */ old_major_mode = major_mode; strcpy(line_draw_mode_name,line_draw_mode_base); strcat(line_draw_mode_name," Draw"); major_mode = line_draw_mode_name; make_mode(); /* generate initial key bindings */ line_draw_tab[KEYLEFT] = find_index("line_draw_left"); line_draw_tab[KEYUP] = find_index("line_draw_up"); line_draw_tab[KEYRIGHT] = find_index("line_draw_right"); line_draw_tab[KEYDOWN] = find_index("line_draw_down"); /* next 'd' toggles drawing off */ line_draw_tab['d'] = find_index("line_draw_inactive"); /* get line type wanted */ strcpy(line_draw_set,line_draw_single_set); /* place prompt */ note(line_draw_mode_prompt); }