/* "WOL", an integrated circuit layout tool, Copyright (C) 1983, 1990 California Institute of Technology. Author: Massimo Sivilotti Thanks to: Glenn Gribble, Marty Sirkin, Sylvie Rychebusch Maryann Mayer, Carver Mead, Rick Koshi, Torre Lande Maintainer: John Lazzaro Maintainers's address: lazzaro@hobiecat.cs.caltech.edu; CB 425/ CU Boulder/Boulder CO 91125. Send questions, bug fixes, to this address. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation (Version 1, 1989). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Output from p2c, the Pascal-to-C translator */ /* p2c: wolopt.text, line 9: Note: Range checking is OFF [216] */ /* p2c: wolopt.text, line 10: Note: Stack checking is OFF [217] */ /* p2c: wolopt.text, line 16: Note: Range checking is ON [216] */ /* From input file "wol_gr_2.text" */ /* Change these for testing */ #include "global.h" #define WOL_GRAPHICS_2_G #include "wol_graphics_2.h" #define dbug false /* set to true to print debugging info */ #define display_test false Static short redisp_last_layer; extern void menu_show(void); void do_refresh(void) { if (!strcmp(m_machine, "320")) { big_graphics(); clear_screen(); } if (display_buffers[current_buffer].refresh.link != NULL) ((void(*)(void *_link))display_buffers[current_buffer].refresh.proc)( display_buffers[current_buffer].refresh.link); else ((void(*)(void))display_buffers[current_buffer].refresh.proc)(); if (!strcmp(m_machine, "320")) { menu_show(); small_graphics(); } } void set_buffer(Char *n) { short i; Char STR2[32]; buffer_rec *WITH; if (!strcmp(n, current_buffer_name)) return; i = 0; while (i <= max_buffer && strcmp(n, display_buffers[i].name)) i++; if (i > max_buffer) { sprintf(STR2, "\007set_buffer: \"%s\" not found.", n); show_message(STR2, false); return; } /* Save old zoom stuff */ if (current_buffer >= 0) { WITH = &display_buffers[current_buffer]; WITH->b_off_x = off_x; WITH->b_off_y = off_y; WITH->b_zoom = zoom; WITH->b_izoom = izoom; WITH->b_intzoom = intzoom; } /* Now setup the current parameters */ current_buffer = i; WITH = &display_buffers[current_buffer]; off_x = WITH->b_off_x; off_y = WITH->b_off_y; zoom = WITH->b_zoom; izoom = WITH->b_izoom; intzoom = WITH->b_intzoom; strcpy(current_buffer_name, WITH->name); } void make_buffer(Char *n, _PROCEDURE p) { short i; Char STR2[42]; buffer_rec *WITH; i = 0; while (i <= max_buffer && strcmp("None", display_buffers[i].name)) i++; if (i > max_buffer) { sprintf(STR2, "\007make_buffer: Out of buffers for \"%s\".", n); show_message(STR2, false); return; } WITH = &display_buffers[i]; WITH->b_off_x = 0; WITH->b_off_y = 0; WITH->b_zoom = 8.0; WITH->b_izoom = 8; WITH->b_intzoom = true; strcpy(WITH->name, n); WITH->refresh = p; WITH->windows = NULL; } #define arrowlength 5 /* pixels */ #define fuzz 0.006 /* comparison tolerance */ void draw_arrow(point start, point finish, boolean erase) { long startx, starty, endx, endy, tmp_coord; double vectorx, vectory, normalx, normaly, leng; Char outstr[81]; point tp_d1, tp_d2; long j, TEMP, TEMP1; gsave(); startx = start.x; starty = start.y; endx = finish.x; endy = finish.y; /* turn on xor */ xor_on(); m_color(WHITE); m_linestyle(0); /* sort the coords, so vector goes up */ if (starty > endy) { tmp_coord = starty; starty = endy; endy = tmp_coord; tmp_coord = startx; startx = endx; endx = tmp_coord; } m_nocursor(); /* now calculate direction vector, and its normal, both normalized */ if (endx == startx) vectorx = 0.0; else { TEMP = endx - startx; TEMP1 = endy - starty; vectorx = (endx - startx) / sqrt((double)(TEMP * TEMP + TEMP1 * TEMP1)); } if (endy == starty) vectory = 0.0; else { TEMP = endx - startx; TEMP1 = endy - starty; vectory = (endy - starty) / sqrt((double)(TEMP * TEMP + TEMP1 * TEMP1)); } normalx = vectory; normaly = -vectorx; /* now draw vector, with arrowheads */ m_move(startx, starty); m_draw(endx, endy); m_move(startx, starty); m_draw((long)(startx + arrowlength * (vectorx + normalx)), (long)(starty + arrowlength * (vectory + normaly))); m_move(startx, starty); m_draw((long)(startx + arrowlength * (vectorx - normalx)), (long)(starty + arrowlength * (vectory - normaly))); m_move(endx, endy); m_draw((long)(endx + arrowlength * (normalx - vectorx)), (long)(endy + arrowlength * (normaly - vectory))); m_move(endx, endy); m_draw((long)(endx + arrowlength * (-vectorx - normalx)), (long)(endy + arrowlength * (-vectory - normaly))); /* now calculate and print vector length */ m_move((long)((startx + endx) / 2.0 + 6 * normalx), (long)((starty + endy) / 2.0 + 10 * normaly - 4)); tp_d1 = scale_down(start); /* convert to lambda units */ tp_d2 = scale_down(finish); startx = tp_d1.x; starty = tp_d1.y; endx = tp_d2.x; endy = tp_d2.y; TEMP = endx - startx; TEMP1 = endy - starty; leng = sqrt((double)(TEMP * TEMP + TEMP1 * TEMP1)); outstr[0] = '\0'; if (endx - startx == 0 || endy - starty == 0 || fabs(leng - 1.0 * (long)leng) <= fuzz) { /* its an integer */ sprintf(outstr, "%0.0f", leng); j = strlen(outstr) + 1; } else { sprintf(outstr, "%0.1f", leng); j = strlen(outstr) + 1; } display_text(outstr); grestore(); } #undef arrowlength #undef fuzz /*******************************************************************************/ void do_ruler(point start) { /* waits for the pen to be depressed twice on geometry, then draws vector between the points, labelled with the length of the vector */ point old_pt, new_pt; tablet_info new_pen; boolean first_time; /* first press was on grid area */ debounce(); /* we now have pen position for first click */ old_pt = start; first_time = true; do { new_pen = check_pen(); new_pt.x = new_pen.x; new_pt.y = new_pen.y; new_pt = scale_up(scale_down(new_pt)); /* put it on lambda grid */ if (new_pt.x != old_pt.x || new_pt.y != old_pt.y) { if (!first_time) draw_arrow(start, old_pt, true); first_time = false; draw_arrow(start, new_pt, false); old_pt = new_pt; } } while (!new_pen.depressed); debounce(); } void highlight_g(node *nd) { point a, b; long old_layer; /*$if dbug$ writeln ('Highlighting box in layer: ',nd^.layer:0); $end$*/ gsave(); small_graphics(); a = transform_point(nd->ll); /* XFORM */ b = transform_point(nd->ur); m_colormode(m_normal); m_color(WHITE); m_linestyle(0); smartbox(a.x, a.y, b.x, b.y); old_layer = last_layer; set_layer(nd->layer); m_linestyle(1); m_color(curr_color); smartbox(a.x, a.y, b.x, b.y); set_layer(old_layer); grestore(); /* highlight object */ } void unhighlight_g(node *nd) { point a, b; long old_layer; /*$if dbug$ writeln ('unHighlighting box in layer: ',nd^.layer:0); $end$*/ gsave(); small_graphics(); a = transform_point(nd->ll); /* XFORM */ b = transform_point(nd->ur); m_linestyle(0); m_color(BLACK); smartbox(a.x, a.y, b.x, b.y); old_layer = last_layer; set_layer(nd->layer); smartbox(a.x, a.y, b.x, b.y); set_layer(old_layer); grestore(); /* Un-highlight object */ } void highlight_c(c_cell *nd) { point pt1, pt2; gsave(); xor_on(); small_graphics(); gstate.dotted = true; set_layer(comp_box); xform_node(nd, &pt1, &pt2); pt1 = scale_up(pt1); pt2 = scale_up(pt2); draw_rbb(pt1, pt2); /*$if dbug$ writeln ('Highlighting comp cell.'); $end$*/ grestore(); /* highlight object */ } void unhighlight_c(c_cell *nd) { point pt1, pt2; /*$if dbug$ writeln ('Un-Highlighting comp cell.'); $end$*/ gsave(); small_graphics(); xor_off(); gstate.dotted = false; set_layer(comp_box); xform_node(nd, &pt1, &pt2); pt1 = scale_up(pt1); pt2 = scale_up(pt2); draw_rbb(pt1, pt2); grestore(); /* un-highlight object */ } void select_object(point pt) { /* accept a point in lambda coordinates; traverse the data structure, building a tree along the way; returns after EVERY possible object has been selected; returns that object in last_selected_object_g */ if (!strcmp(current_buffer_name, "GEOM")) { if (last_selected_object_g != NULL) { unhighlight_g(last_selected_object_g); last_selected_object_g = last_selected_object_g->next; } if (last_selected_object_g == NULL) /* wrap around */ last_selected_object_g = select_list_head_g; if (last_selected_object_g != NULL) /* no objects found */ highlight_g(last_selected_object_g); else select_in_progress_g = false; return; } if (strcmp(current_buffer_name, "COMP")) /* current buffer = COMP */ return; if (last_selected_object_c != NULL) { unhighlight_c(last_selected_object_c); last_selected_object_c = last_selected_object_c->next; } if (last_selected_object_c == NULL) /* wrap around */ last_selected_object_c = select_list_head_c; if (last_selected_object_c != NULL) /* no objects found */ highlight_c(last_selected_object_c); else select_in_progress_c = false; } Local void get_next_g(node *nd, point pt) { /* traverses the geometry tree depth first */ node *newnode; if (asm_memavail() < min_mem_recurse) { show_message("\007Low on memory in GET_NEXT_G", false); return; } while (nd != NULL) { get_next_g(nd->child, pt); if ((edges_only && (nd->ll.x == pt.x && pt.y >= nd->ll.y && pt.y <= nd->ur.y || nd->ll.y == pt.y && pt.x >= nd->ll.x && pt.x <= nd->ur.x || nd->ur.x == pt.x && pt.y >= nd->ll.y && pt.y <= nd->ur.y || nd->ur.y == pt.y && pt.x >= nd->ll.x && pt.x <= nd->ur.x)) || (!edges_only && pt.x >= nd->ll.x && pt.x <= nd->ur.x && pt.y >= nd->ll.y && pt.y <= nd->ur.y)) { /* get_next_g (nd^.child, pt); -- necessary for edges_only */ newnode = get_a_node(); if (select_list_head_g == NULL) select_list_head_g = newnode; else select_list_tail_g->next = newnode; *newnode = *nd; newnode->next = NULL; newnode->child = NULL; newnode->parent = nd; /* put a pointer to the real box here */ select_list_tail_g = newnode; /*$if dbug$ writeln ('Found box in layer: ',newnode^.layer:0); $end$*/ } nd = nd->next; } } Local void get_next_c(c_cell *nd, point pt) { /* traverses the composition linked list */ c_cell *newnode; point xll, xur; /* transformed extent of BB */ while (nd != NULL) { xll = nd->ll; xur = nd->ur; if ((edges_only && (xll.x == pt.x && pt.y >= xll.y && pt.y <= xur.y || xll.y == pt.y && pt.x >= xll.x && pt.x <= xur.x || xur.x == pt.x && pt.y >= xll.y && pt.y <= xur.y || xur.y == pt.y && pt.x >= xll.x && pt.x <= xur.x)) || (!edges_only && pt.x >= xll.x && pt.x <= xur.x && pt.y >= xll.y && pt.y <= xur.y)) { newnode = get_c_c_cell(); if (select_list_head_c == NULL) select_list_head_c = newnode; else select_list_tail_c->next = newnode; *newnode = *nd; newnode->next = NULL; newnode->select_list = nd; /* put a pointer to the real box here */ select_list_tail_c = newnode; /*$if dbug$ writeln ('Found a composition cell.'); $end$*/ } nd = nd->next; } } void find_all_possible_objects(point pt) { /* searches the geometry buffer for suitable objects, builds a linked list, which can then be traversed by select_object */ if (!strcmp(current_buffer_name, "GEOM")) { recl_nodes(&select_list_head_g); select_list_head_g = NULL; get_next_g(main_, pt); last_selected_object_g = NULL; return; } if (strcmp(current_buffer_name, "COMP")) /* next line is WRONG -- only reclaims one node */ return; if (select_list_head_c != NULL) { printf("WARNING: memory being wasted here -- recl_c_c_cell\n"); recl_c_c_cell(&select_list_head_c); } select_list_head_c = NULL; get_next_c(comp_cells->data, pt); last_selected_object_c = NULL; } /**************************************************************************/ tablet_info scale(tablet_info in_val, short arg) { /* SCALE - Takes two arguments. The first is the point to scale. */ /* The second has values of 1,2,3. 1 = scale only x. 2 = */ /* scale only y. 3 = scale both. */ if (arg == 1 || arg == 3) in_val.x = (long)((long)(in_val.x / zoom) * zoom); if (arg == 2 || arg == 3) in_val.y = (long)((long)(in_val.y / zoom) * zoom); return in_val; } /*******************************************************************************/ /* Convert a point in LAMBDA coordinates and output SCREEN coordinates */ point scale_up(point tlp) { point Result; Result.x = (long)((tlp.x - off_x) * zoom); Result.y = (long)((tlp.y - off_y) * zoom); return Result; } /*******************************************************************************/ /* Convert a point in SCREEN coordinates to LAMBDA coordinates */ point scale_down(point tlp) { point Result; Result.x = (long)(tlp.x / zoom) + off_x; Result.y = (long)(tlp.y / zoom) + off_y; return Result; } /*******************************************************************************/ point change_to_point(long a, long b) { point Result; Result.x = a; Result.y = b; return Result; } #define error 16 /* 1/16 */ /*******************************************************************************/ /* Re-make the transformation matrix, using the current offset and zoom */ /* Always call this after changing OFFSET or ZOOM */ void make_matrix(void) { long scale, num; /* Find a nice rational zoom */ num = 1; scale = (long)floor(zoom + 0.5); while (num < 256 && (double)error / num * fabs(scale - num * zoom) >= zoom) { /*writeln(#139'num='#136,num:2,' scale=',scale:3,'=',zoom:0:5,*/ /*' error=',error/num*abs(scale-num*zoom):0:5);*/ num *= 2; scale = (long)floor(num * zoom + 0.5); } /*writeln('num=',num:2,' scale=',scale:3,'=',zoom:0:5,*/ /*' error=',error/num*abs(scale-num*zoom):0:5);*/ pl_ident(); /* Always change ZOOM to reflect the actual value */ zoom = (double)scale / num; pl_scale(scale, scale, num); pl_tran(-off_x, -off_y); tr_set_matrix(); } #undef error /*******************************************************************************/ void set_bb(cell *c) { node *scan; c->ll.x = INFIN; c->ll.y = INFIN; c->ur.x = INFIN; c->ur.y = INFIN; scan = c->data; while (scan != NULL) { /* Keep up the B.B */ if (c->ll.x == INFIN || scan->ll.x < c->ll.x) c->ll.x = scan->ll.x; if (c->ll.y == INFIN || scan->ll.y < c->ll.y) c->ll.y = scan->ll.y; if (c->ur.x == INFIN || scan->ur.x > c->ur.x) c->ur.x = scan->ur.x; if (c->ur.y == INFIN || scan->ur.y > c->ur.y) c->ur.y = scan->ur.y; scan = scan->next; } } /*******************************************************************************/ void set_c_bb(comp_list *c) { c_cell *scan; point ll, ur; c->ll.x = INFIN; c->ll.y = INFIN; c->ur.x = INFIN; c->ur.y = INFIN; scan = c->data; while (scan != NULL) { xform_node(scan, &ll, &ur); if (c->ll.x == INFIN || ll.x < c->ll.x) /* Keep up the B.B */ c->ll.x = ll.x; if (c->ll.y == INFIN || ll.y < c->ll.y) c->ll.y = ll.y; if (c->ur.x == INFIN || ur.x > c->ur.x) c->ur.x = ur.x; if (c->ur.y == INFIN || ur.y > c->ur.y) c->ur.y = ur.y; scan = scan->next; } } /*******************************************************************************/ void xform_node(c_cell *c, point *vll, point *vur) { point t1, t2; switch (c->xform) { case 0: t1 = c->ll; t2 = c->ur; break; case 1: /* 5*/ t1 = change_to_point(c->ll.x - c->ur.y + c->ll.y, c->ll.y); t2 = change_to_point(c->ll.x, c->ll.y + c->ur.x - c->ll.x); break; case 2: /* 6 */ t1 = change_to_point(c->ll.x * 2 - c->ur.x, c->ll.y * 2 - c->ur.y); t2 = c->ll; break; case 3: /* 7 */ t1 = change_to_point(c->ll.x, c->ll.y - c->ur.x + c->ll.x); t2 = change_to_point(c->ll.x + c->ur.y - c->ll.y, c->ll.y); break; case 4: t1 = change_to_point(c->ll.x * 2 - c->ur.x, c->ll.y); t2 = change_to_point(c->ll.x, c->ur.y); break; case 5: t1 = change_to_point(c->ll.x - c->ur.y + c->ll.y, c->ll.y - c->ur.x + c->ll.x); t2 = c->ll; break; case 6: t1 = change_to_point(c->ll.x, c->ll.y * 2 - c->ur.y); t2 = change_to_point(c->ur.x, c->ll.y); break; case 7: t1 = c->ll; t2 = change_to_point(c->ll.x + c->ur.y - c->ll.y, c->ll.y + c->ur.x - c->ll.x); break; } *vll = t1; *vur = t2; } /*******************************************************************************/ void scroll_window(boolean immediate, Char firstchar) { long step_size; boolean done; /* done with loop? */ Char ch; /* input character */ long page_width; /* how wide is a page? */ long page_height; /* how high is a page? */ long movex, movey; /* how far to move in lambda */ long savemode, savecolor, oldx, oldy; /* make the scrolling rate proportional to the zoom factor */ step_size = (long)(20 / zoom); if (step_size == 0) step_size = 1; /* only move 80% at a time via page commands */ page_width = (long)(0.8 * RIGHT_OF_SCREEN / zoom); page_height = (long)(0.8 * TOP_OF_SCREEN / zoom); done = false; do { savemode = m_curcolormode(); m_colormode(m_xor); savecolor = m_curcolor(); m_color(m_white); movex = 0; movey = 0; switch (firstchar) { case '\b': movex = -step_size; break; case '\034': movex = step_size; break; case '\n': movey = -step_size; break; case '\037': movey = step_size; break; case '4': movex = -page_width; break; case '6': movex = page_width; break; case '2': movey = -page_height; break; case '8': movey = page_height; break; } if (movex < 0) m_drawline((long)floor(m_across + movex * zoom + 0.5), 0, (long)floor(m_across + movex * zoom + 0.5), m_down); else if (movex > 0) m_drawline((long)floor(movex * zoom + 0.5), 0, (long)floor(movex * zoom + 0.5), m_down); if (movey < 0) m_drawline(0, (long)floor(m_down + movey * zoom + 0.5), m_across, (long)floor(m_down + movey * zoom + 0.5)); else if (movey > 0) m_drawline(0, (long)floor(movey * zoom + 0.5), m_across, (long)floor(movey * zoom + 0.5)); oldx = movex; oldy = movey; while (nk_keybufsize() > 0 && !done) { ch = nk_getkey(); switch (ch) { case '\b': movex -= step_size; break; case '\034': movex += step_size; break; case '\n': movey -= step_size; break; case '\037': movey += step_size; break; case '4': movex -= page_width; break; case '6': movex += page_width; break; case '2': movey -= page_height; break; case '8': movey += page_height; break; default: done = true; break; } if (oldx < 0) m_drawline((long)floor(m_across + oldx * zoom + 0.5), 0, (long)floor(m_across + oldx * zoom + 0.5), m_down); else if (oldx > 0) m_drawline((long)floor(oldx * zoom + 0.5), 0, (long)floor(oldx * zoom + 0.5), m_down); if (oldy < 0) m_drawline(0, (long)floor(m_down + oldy * zoom + 0.5), m_across, (long)floor(m_down + oldy * zoom + 0.5)); else if (oldy > 0) m_drawline(0, (long)floor(oldy * zoom + 0.5), m_across, (long)floor(oldy * zoom + 0.5)); if (movex < 0) m_drawline((long)floor(m_across + movex * zoom + 0.5), 0, (long)floor(m_across + movex * zoom + 0.5), m_down); else if (movex > 0) m_drawline((long)floor(movex * zoom + 0.5), 0, (long)floor(movex * zoom + 0.5), m_down); if (movey < 0) m_drawline(0, (long)floor(m_down + movey * zoom + 0.5), m_across, (long)floor(m_down + movey * zoom + 0.5)); else if (movey > 0) m_drawline(0, (long)floor(movey * zoom + 0.5), m_across, (long)floor(movey * zoom + 0.5)); oldx = movex; oldy = movey; /* Wait for more keys if we feel like it. */ if (!done && nk_keybufsize() == 0) waitfor(20); } /* while loop */ if (oldx < 0) m_drawline((long)floor(m_across + oldx * zoom + 0.5), 0, (long)floor(m_across + oldx * zoom + 0.5), m_down); else if (oldx > 0) m_drawline((long)floor(oldx * zoom + 0.5), 0, (long)floor(oldx * zoom + 0.5), m_down); if (oldy < 0) m_drawline(0, (long)floor(m_down + oldy * zoom + 0.5), m_across, (long)floor(m_down + oldy * zoom + 0.5)); else if (oldy > 0) m_drawline(0, (long)floor(oldy * zoom + 0.5), m_across, (long)floor(oldy * zoom + 0.5)); m_color(savecolor); m_colormode(savemode); if (movex != 0 || movey != 0) { off_x += movex; off_y += movey; do_refresh(); } } while (!(done || immediate)); m_alpha_off(); } #define max_zoom 32.0 #define min_zoom 0.01 /*******************************************************************************/ void zoom_it(double new_zoom) { point t_calc; t_calc.x = X_CENTER; t_calc.y = Y_CENTER; t_calc = scale_down(t_calc); if (new_zoom > max_zoom) zoom = max_zoom; else if (new_zoom < min_zoom) zoom = min_zoom; else zoom = new_zoom; if (zoom > 1.0) zoom = (long)zoom; izoom = (long)zoom; intzoom = (zoom == izoom); off_x = t_calc.x - (long)(X_CENTER / zoom); off_y = t_calc.y - (long)(Y_CENTER / zoom); m_alpha_off(); do_refresh(); } #undef max_zoom #undef min_zoom /* FUNCTION get_rbb (start : point; var finish : point) : boolean; forward; */ /* FUNCTION tr_pen : tablet_info; forward; */ void window_zoom(boolean switch_windows) { /* if switch_windows = TRUE then actually switch, else just push */ tablet_info pen; point start, finish; double zoom1, zoom2; short old_color; double old_zoom; /* temp holder for calculaated zoom */ long old_off_x, old_off_y; /* temp holders for new offsets */ TRY(try1); pen = tr_pen(); start = change_to_point(pen.x, pen.y); old_color = curr_color; set_layer(sel_box); if (get_rbb(&start, &finish)) { old_zoom = zoom; old_off_x = off_x; old_off_y = off_y; if (switch_windows) /* save current window */ push_window(); /*$if dbug$ writeln ('start = ', start.x:0, ' ', start.y:0); $end$*/ /*$if dbug$ writeln ('finish = ', finish.x:0, ' ', finish.y:0); $end$*/ zoom1 = (double)RIGHT_OF_SCREEN / (finish.x - start.x); zoom2 = (double)TOP_OF_SCREEN / (finish.y - start.y); if (zoom1 >= zoom2) zoom = zoom2; else zoom = zoom1; if (zoom > 32) /* clip somewhere */ zoom = 32.0; if (zoom > 1.0) zoom = (long)zoom; izoom = (long)zoom; intzoom = (zoom == izoom); off_x = (start.x + finish.x - (long)(RIGHT_OF_SCREEN / zoom)) / 2; off_y = (start.y + finish.y - (long)(TOP_OF_SCREEN / zoom)) / 2; /*$if dbug$ writeln ('zoom = ',zoom:0:2, ' off_x = ',off_x:0, ' off_y = ',off_y:0); $end$*/ if (switch_windows) do_refresh(); else { /* push the new window onto the stack, restore the old */ push_window(); zoom = old_zoom; izoom = (long)zoom; intzoom = (zoom == izoom); off_x = old_off_x; off_y = old_off_y; } } RECOVER(try1); if (P_escapecode == 10) _Escape(10); else { show_error("ERROR in Window_zoom:", false); _Escape(P_escapecode); } ENDTRY(try1); set_layer(old_color); } void push_window(void) { /* store current window on window_stack */ window_rec *tmp; buffer_rec *WITH; if (garbage_window_stack != NULL) { /* pop one off */ tmp = garbage_window_stack; garbage_window_stack = garbage_window_stack->next; } else tmp = Malloc(sizeof(window_rec)); tmp->zoom = zoom; tmp->izoom = izoom; tmp->intzoom = intzoom; tmp->off_x = off_x; tmp->off_y = off_y; WITH = &display_buffers[current_buffer]; tmp->next = WITH->windows; WITH->windows = tmp; } void pop_window(void) { /* pop a window off the stack, redraw the screen if necessary */ window_rec *tmp; boolean redraw_it; buffer_rec *WITH; WITH = &display_buffers[current_buffer]; if (WITH->windows == NULL) return; tmp = WITH->windows; redraw_it = (zoom != tmp->zoom || off_x != tmp->off_x || off_y != tmp->off_y); zoom = tmp->zoom; izoom = tmp->izoom; intzoom = tmp->intzoom; off_x = tmp->off_x; off_y = tmp->off_y; WITH->windows = tmp->next; tmp->next = garbage_window_stack; garbage_window_stack = tmp; if (redraw_it) do_refresh(); } void exchange_window(void) { /* exchange the top two elements on the stack, and go to the top element, WITHOUT popping the stack */ window_rec *tmp1, *tmp2, *tmp3; buffer_rec *WITH; WITH = &display_buffers[current_buffer]; if (WITH->windows == NULL) return; tmp1 = WITH->windows; WITH->windows = tmp1->next; if (WITH->windows == NULL) { WITH->windows = tmp1; return; } tmp2 = WITH->windows; /* now exchange tmp1 and tmp2, making a copy of tmp2 */ tmp1->next = WITH->windows->next; tmp2->next = tmp1; if (garbage_window_stack != NULL) { /* pop one off */ tmp3 = garbage_window_stack; garbage_window_stack = garbage_window_stack->next; } else tmp3 = Malloc(sizeof(window_rec)); *tmp3 = *tmp2; tmp3->next = tmp2; WITH->windows = tmp3; pop_window(); /* no tmp2, so put tmp1 back on stack */ /* no windows to exchange */ } tablet_info tr_pen(void) { tablet_info t_i; big_graphics(); /* Force this */ do { t_i = check_pen(); if (t_i.y > TOP_OF_SCREEN && t_i.x > END_OF_MENU) t_i.y = TOP_OF_SCREEN; if (t_i.y <= TOP_OF_SCREEN) t_i = scale(t_i, 3); if (cursor_on) m_cursor(t_i.x, t_i.y); } while (!t_i.depressed); t_i.menu = 0; return t_i; } /*******************************************************************************/ tablet_info track(void) { tablet_info n_ti; debounce(); /* Make sure pen is up */ n_ti = tr_pen(); /* Track the pen */ debounce(); /* Get the pen up again */ if (n_ti.y <= TOP_OF_SCREEN + 3) n_ti.menu = 0; else n_ti.menu = 11; m_nocursor(); /* GEG if the calling routine wants it, it will put it back */ return n_ti; /* Set the value of the */ } /*******************************************************************************/ point transform_point(point pt) { /* XFORM */ point Result; tr_2(pt.x, pt.y); Result.x = tr_ax; Result.y = tr_ay; /*transform_point.x := (pt.x*tr_ctm.a+pt.y*tr_ctm.c+tr_ctm.e) div tr_ctm.g;*/ /*transform_point.y := (pt.x*tr_ctm.b+pt.y*tr_ctm.d+tr_ctm.f) div tr_ctm.g;*/ return Result; } #define l 0 /* left of screen */ #define b_ 0 /* bottom of screen */ /*******************************************************************************/ /* This returns TRUE if any part of the current box would fit on the screen */ /* As a usefull side-effect, it sets the value of the global BB_STATE */ bb_states bb_check(point bll, point bur) { long t, u, r; r = RIGHT_OF_SCREEN; u = TOP_OF_SCREEN; if (!debug_clip) { bb_state = bb_clip; return bb_state; } bll = transform_point(bll); bur = transform_point(bur); if (bur.x < bll.x) { t = bur.x; bur.x = bll.x; bll.x = t; } if (bur.y < bll.y) { t = bur.y; bur.y = bll.y; bll.y = t; } if (bll.x > r || bll.y > u || bur.x < l || bur.y < b_) { bb_state = bb_off; return bb_state; } if (bur.x <= r && bur.y <= u && bll.x >= l && bll.y >= b_) bb_state = bb_on; else bb_state = bb_clip; return bb_state; } #undef l #undef b_ /****************************************************************************/ /* Draw a box without retracing a single pixel--works in XOR mode */ void smartbox(long x1, long y1, long x2, long y2) { long t; if (x1 == x2 || y1 == y2) { m_move(x1, y1); m_draw(x2, y2); return; } /* points must be sorted */ if (x1 > x2) { t = x2; x2 = x1; x1 = t; } if (y1 > y2) { t = y2; y2 = y1; y1 = t; } m_move(x1, y1 + 1); m_draw(x1, y2); m_move(x1 + 1, y2); m_draw(x2, y2); m_move(x2, y2 - 1); m_draw(x2, y1); m_move(x2 - 1, y1); m_draw(x1, y1); } /*******************************************************************************/ void draw_rbb(point pta, point ptb) { m_nocursor(); m_linestyle(curr_style); /* Restart linestyle generator */ small_graphics(); smartbox(pta.x, pta.y, ptb.x, ptb.y); big_graphics(); /* show cursor when in menu area */ if (making_wire && ptb.y > TOP_OF_SCREEN) m_cursor(ptb.x, ptb.y); } /*******************************************************************************/ boolean within(node *t, point d1, point d2, short fl) { if (t == NULL) return false; else { if (fl == 1) return (t->ll.x <= d1.x && t->ll.y <= d1.y && t->ur.x >= d1.x && t->ur.y >= d1.y); else /* fl = 2 */ return (t->ll.x <= d1.x && t->ll.y <= d1.y && t->ur.x >= d1.x && t->ur.y >= d1.y && t->ll.x <= d2.x && t->ll.y <= d2.y && t->ur.x >= d2.x && t->ur.y >= d2.y); } } /*******************************************************************************/ node *parent_of(node *st, point c1, point c2, short flg) { node *Result; /* Parent - Returns the smallest shape that contains C1 (and sometimes C2). */ /* - Returns the largest shape that contains C1 if C1 is on an edge. */ /* ST - Is the node to start searching with. */ /* C1,C2 - Are points (Either pen point, or the ll,ur corners of a wire).*/ /* FLG - = 1 Only look at C1. = 2 Look at both C1, C2 */ /* = 3 look at both C1 and C2, but return the LARGEST shape containing both */ node *t1; boolean check; node *parent1, *parent2; if (asm_memavail() < min_mem_recurse) { Result = NULL; show_message("\007Low on memory in PARENT_OF", false); goto _L1; } if (edges_only && !select_in_progress_g && flg == 1) { find_all_possible_objects(c1); if (select_list_head_g != NULL) Result = select_list_head_g->parent; else { edges_only = false; t1 = parent_of(st, c1, c2, flg); edges_only = true; Result = t1; } } else { if (select_in_progress_g && last_selected_object_g != NULL && flg == 1) { Result = last_selected_object_g->parent; unhighlight_g(last_selected_object_g); recl_nodes(&select_list_head_g); /* reclaim list of selected objects */ select_list_head_g = NULL; last_selected_object_g = NULL; select_in_progress_g = false; } else { /* not select_in_progress_g and not edges_only */ check = within(st, c1, c2, flg); while (st != NULL && check == false) { st = st->next; check = within(st, c1, c2, flg); } if (st == NULL) Result = NULL; else { if (flg == 3) { parent1 = st; parent2 = parent_of(st->child, c1, c2, 2); if (parent1 == NULL || parent2 == NULL) Result = parent1; else if (parent1->ll.x == c1.x && parent1->ll.y == c1.y && parent1->ur.x == c2.x && parent1->ur.y == c2.y && parent1->ll.x == parent2->ll.x && parent1->ur.x == parent2->ur.x && parent1->ll.y == parent2->ll.y && parent1->ur.y == parent2->ur.y) Result = parent1; else Result = parent2; } else { if (flg == 1 && (st->ll.x == c1.x && c1.y >= st->ll.y && c1.y <= st->ur.y || st->ll.y == c1.y && c1.x >= st->ll.x && c1.x <= st->ur.x || st->ur.x == c1.x && c1.y >= st->ll.y && c1.y <= st->ur.y || st->ur.y == c1.y && c1.x >= st->ll.x && c1.x <= st->ur.x)) Result = st; else { t1 = parent_of(st->child, c1, c2, flg); if (t1 == NULL) Result = st; else Result = t1; } } } } } _L1: return Result; } /*$if false$ FUNCTION parent_of(st : node_ptr; c1,c2 : point; flg : shortint) : node_ptr; { Parent - Returns the smallest shape that contains C1 (and sometimes C2). } { - Returns the largest shape that contains C1 if C1 is on an edge. } { ST - Is the node to start searching with. } { C1,C2 - Are points (Either pen point, or the ll,ur corners of a wire).} { FLG - = 1 Only look at C1. = 2 Look at both C1, C2 } VAR t1,t2 : node_ptr; check : boolean; BEGIN TRY check := within(st,c1,c2,flg); WHILE (st <> NIL) and (check = false) do begin st := st^.next; check := within(st,c1,c2,flg); end; IF st = NIL THEN parent_of := NIL ELSE BEGIN if (flg = 1) and (((st^.ll.x = c1.x) and (c1.y >= st^.ll.y) and (c1.y <= st^.ur.y)) or ((st^.ll.y = c1.y) and (c1.x >= st^.ll.x) and (c1.x <= st^.ur.x)) or ((st^.ur.x = c1.x) and (c1.y >= st^.ll.y) and (c1.y <= st^.ur.y)) or ((st^.ur.y = c1.y) and (c1.x >= st^.ll.x) and (c1.x <= st^.ur.x))) THEN parent_of := st ELSE BEGIN t1 := parent_of(st^.child,c1,c2,flg); IF t1 = NIL THEN parent_of := st ELSE parent_of := t1; END; END; RECOVER if escapecode=10 then escape(10) else begin show_error('Parent_of',false); escape (escapecode); end; END; $end$*/ /*******************************************************************************/ /*$if false$ PROCEDURE add_wire(p1,p2 : point;l : shortint; name : str_nodename; port : port_ptr); VAR temp_val : coord; t_np,l_to_scan,temp : node_ptr; data_node,c_list : node_ptr; port2, tmp_portlist : port_ptr; old_ok_to_select : boolean; coincident_boxes : boolean; tmp_layer : integer; tmp_name : namestr; old_l_to_scan : node_ptr; BEGIN coincident_boxes := false; IF p1.x > p2.x { Make p1 the lower left point of } THEN BEGIN { the box, and p2 the upper right. } temp_val := p2.x; p2.x := p1.x; p1.x := temp_val; END; IF p1.y > p2.y THEN BEGIN temp_val := p2.y; p2.y := p1.y; p1.y := temp_val; END; {p1 := scale_down(p1);} { Scale the two points } {p2 := scale_down(p2);} data_node := get_a_node; { Get a node } data_node^.ll := p1; { Stuff points, and layer in it } data_node^.ur := p2; data_node^.layer := l; data_node^.name := name; { duplicate port tree, if necessary } while port <> NIL do begin port2 := get_port_node; port2^ := port^; port2^.next := data_node^.portlist; data_node^.portlist := port2; port := port^.next; end; last_added := data_node; { Set a global pointer (for move) } old_ok_to_select := ok_to_select; { MAS } ok_to_select := false; t_np := parent_of(main,p1,p2,2); { Find the node's parent } ok_to_select := old_ok_to_select; data_node^.parent := t_np; IF t_np = NIL { Set list of nodes to scan to see } THEN BEGIN l_to_scan := main; { which are children of data_node } { data_node^.parent := NIL; } { Set the node's parent to NIL } END ELSE BEGIN l_to_scan := t_np^.child; { and which should be on same level} { data_node^.parent := t_np; } { Set the data node's parent } END; c_list := NIL; { List of children of data_node } WHILE l_to_scan <> NIL do { Check all nodes on same level as } IF within(data_node,l_to_scan^.ll,l_to_scan^.ur,2) { data_node } THEN BEGIN { If each is inside of data_node... } { attempt to make insertion of coincident objects nest outwards in order of insertion.... } if (data_node^.ll.x = l_to_scan^.ll.x) and (data_node^.ll.y = l_to_scan^.ll.y) and (data_node^.ur.x = l_to_scan^.ur.x) and (data_node^.ur.y = l_to_scan^.ur.y) then begin { add to OUTSIDE of object } old_l_to_scan := l_to_scan; coincident_boxes := true; end; $end$*/ /*$if false$ data_node^.child := l_to_scan; data_node^.next := l_to_scan^.next; data_node^.parent := l_to_scan^.parent; l_to_scan^.parent := data_node; c_list := l_to_scan; l_to_scan^.next := NIL; l_to_scan := NIL; { we are done } end else $end$*/ /*$if false$ begin { add to INSIDE of object } temp := c_list; {MAS} { Append on to children list. } c_list := l_to_scan; l_to_scan := l_to_scan^.next; c_list^.next := temp; c_list^.parent := data_node; if coincident_boxes then begin { swap layers, ports, and names } tmp_layer := data_node^.layer; data_node^.layer := old_l_to_scan^.layer; old_l_to_scan^.layer := tmp_layer; tmp_portlist := data_node^.portlist; data_node^.portlist := old_l_to_scan^.portlist; old_l_to_scan^.portlist := tmp_portlist; tmp_name := data_node^.name; data_node^.name := old_l_to_scan^.name; old_l_to_scan^.name := tmp_name; end; end; END ELSE BEGIN { Otherwise, put on next list of data_node} temp := data_node^.next; data_node^.next := l_to_scan; l_to_scan := l_to_scan^.next; data_node^.next^.next := temp; END; IF t_np = NIL { If there was no parent, set main } THEN main := data_node { data_node, otherwise, set the } ELSE t_np^.child := data_node; { parent^.child to data_node } data_node^.child := c_list; { Set data_node's children list. } END; $end$*/ /*$if false$ most recent PROCEDURE add_wire(p1,p2 : point;l : shortint; name : str_nodename; port : port_ptr); VAR temp_val : coord; t_np,l_to_scan,temp : node_ptr; data_node,c_list : node_ptr; port2, tmp_portlist : port_ptr; coincident_boxes : boolean; BEGIN writeln ('add_wire called'); coincident_boxes := false; IF p1.x > p2.x { Make p1 the lower left point of } THEN BEGIN { the box, and p2 the upper right. } temp_val := p2.x; p2.x := p1.x; p1.x := temp_val; END; IF p1.y > p2.y THEN BEGIN temp_val := p2.y; p2.y := p1.y; p1.y := temp_val; END; data_node := get_a_node; { Get a node } data_node^.ll := p1; { Stuff points, and layer in it } data_node^.ur := p2; data_node^.layer := l; data_node^.name := name; { duplicate port tree, if necessary } while port <> NIL do begin port2 := get_port_node; port2^ := port^; port2^.next := data_node^.portlist; data_node^.portlist := port2; port := port^.next; end; last_added := data_node; { Set a global pointer (for move) } t_np := parent_of(main,p1,p2,2); { Find the node's parent } c_list := NIL; { List of children of data_node } data_node^.parent := t_np; IF t_np = NIL { Set list of nodes to scan to see } THEN l_to_scan := main { which are children of data_node } ELSE begin { attempt to make insertion of coincident objects nest outwards in order of insertion.... } if (data_node^.ll.x = t_np^.ll.x) and (data_node^.ll.y = t_np^.ll.y) and (data_node^.ur.x = t_np^.ur.x) and (data_node^.ur.y = t_np^.ur.y) then begin { add to OUTSIDE of object } coincident_boxes := true; writeln ('found coincident box'); data_node^.parent := t_np^.parent; if data_node^.parent = nil then begin writeln ('data_node^.parent = nil'); main := data_node; end else if data_node^.parent^.child = t_np then begin writeln ('data_node^.parent^.child = t_np'); data_node^.parent^.child := data_node; end else begin writeln ('data_node^.parent^.child <> t_np'); temp := data_node^.parent^.child; while (temp <> NIL) and (temp^.next <> t_np) do temp := temp^.next; if temp <> NIL then begin temp^.next := data_node; end; end; data_node^.next := t_np^.next; t_np^.next := nil; data_node^.child := t_np; t_np^.parent := data_node; end else begin writeln ('boxes not coincident'); l_to_scan := t_np^.child; { and which should be on same level} end; end; if not coincident_boxes then begin WHILE l_to_scan <> NIL do { Check all nodes on same level as } IF within(data_node,l_to_scan^.ll,l_to_scan^.ur,2) { data_node } THEN BEGIN { If each is inside of data_node... } { add to INSIDE of object, capturing any smaller boxes } writeln (' adding to inside of box, capturing smaller boxes'); temp := c_list; {MAS} { Append on to children list. } c_list := l_to_scan; l_to_scan := l_to_scan^.next; c_list^.next := temp; c_list^.parent := data_node; END ELSE BEGIN { Otherwise, put on next list of data_node} writeln (' adding to .next list '); temp := data_node^.next; data_node^.next := l_to_scan; l_to_scan := l_to_scan^.next; data_node^.next^.next := temp; END; IF t_np = NIL { If there was no parent, set main } THEN main := data_node { data_node, otherwise, set the } ELSE t_np^.child := data_node; { parent^.child to data_node } data_node^.child := c_list; { Set data_node's children list. } end; END; $end$*/ void add_wire(point p1, point p2, short l, Char *name, port_node *port) { long temp_val; node *t_np, *l_to_scan, *temp, *data_node, *c_list; port_node *port2; boolean old_ok_to_select, coincident_boxes; coincident_boxes = false; if (p1.x > p2.x) /* Make p1 the lower left point of */ { /* the box, and p2 the upper right. */ temp_val = p2.x; p2.x = p1.x; p1.x = temp_val; } if (p1.y > p2.y) { temp_val = p2.y; p2.y = p1.y; p1.y = temp_val; } data_node = get_a_node(); /* Get a node */ data_node->ll = p1; /* Stuff points, and layer in it */ data_node->ur = p2; data_node->layer = l; strcpy(data_node->name, name); /* duplicate port tree, if necessary */ while (port != NULL) { port2 = get_port_node(); *port2 = *port; port2->next = data_node->portlist; data_node->portlist = port2; port = port->next; } last_added = data_node; /* Set a global pointer (for move) */ old_ok_to_select = ok_to_select; /* MAS */ ok_to_select = false; t_np = parent_of(main_, p1, p2, 3); /* Find the node's parent -- NOTE FLG = 3*/ ok_to_select = old_ok_to_select; /* check for coincident boxes */ if (t_np != NULL && data_node->ll.x == t_np->ll.x && data_node->ll.y == t_np->ll.y && data_node->ur.x == t_np->ur.x && data_node->ur.y == t_np->ur.y) { /* replace t_np with data_node */ if (t_np->parent == NULL) { if (t_np == main_) main_ = data_node; /* it is the root of the tree */ else { /* it is a top-level node */ temp = main_; while (temp->next != t_np) temp = temp->next; temp->next = data_node; } } else { temp = t_np->parent->child; if (temp == t_np) /* it is the first son of a node */ t_np->parent->child = data_node; else { /* find the node in the .next list */ while (temp->next != t_np) temp = temp->next; temp->next = data_node; } } data_node->next = t_np->next; /*update the nodes*/ t_np->next = NULL; /*so that data_node winds up outside*/ data_node->parent = t_np->parent; t_np->parent = data_node; data_node->child = t_np; return; } data_node->parent = t_np; if (t_np == NULL) /* Set list of nodes to scan to see */ l_to_scan = main_; /* which are children of data_node */ else l_to_scan = t_np->child; /* and which should be on same level*/ c_list = NULL; /* List of children of data_node */ while (l_to_scan != NULL) { /* Check all nodes on same level as */ if (!within(data_node, l_to_scan->ll, l_to_scan->ur, 2)) /* data_node */ { /* If each is inside of data_node... */ temp = data_node->next; data_node->next = l_to_scan; l_to_scan = l_to_scan->next; data_node->next->next = temp; continue; } temp = c_list; /*MAS*/ /* Append on to children list. */ c_list = l_to_scan; l_to_scan = l_to_scan->next; c_list->next = temp; c_list->parent = data_node; } if (t_np == NULL) /* If there was no parent, set main */ main_ = data_node; /* data_node, otherwise, set the */ else t_np->child = data_node; /* parent^.child to data_node */ data_node->child = c_list; /* Set data_node's children list. */ /* not coincident */ /* Otherwise, put on next list of data_node*/ } Local long MAX(long a, long b) { if (a > b) return a; else return b; } Local long MIN(long a, long b) { if (a < b) return a; else return b; } /*******************************************************************************/ boolean get_rbb(point *start, point *finish) { /* draws an rbb on the screen, and returns its start and end positions in LAMBDA COORDINATES; when called, start is in SCREEN COORDINATES get_rbb returns TRUE if box successfully got, FALSE otherwise */ boolean Result; point fin; tablet_info t_t; point lambda_start; gsave(); making_wire = true; debounce(); /* Get the pen up */ xor_on(); /* Rubber band boxes are in xor */ m_nocursor(); /* We know where the cursor is from */ lambda_start = scale_down(*start); /* MAS - save start in LAMBDA coords */ fin = *start; /* Start off with an empty box */ *start = scale_up(lambda_start); draw_rbb(*start, fin); /* Draw it to get in phase with loop */ do { /* Repeat RBB's */ t_t = check_pen(); /* Find out where we are. */ if (t_t.y > TOP_OF_SCREEN) /* If we are off the drawing pad, */ t_t = scale(t_t, 1); /* Only scale the x coords */ else t_t = scale(t_t, 3); /* Otherwise scale both axes */ if (fin.x != t_t.x || fin.y != t_t.y) { /* only redraw if you have actually moved */ *start = scale_up(lambda_start); draw_rbb(*start, fin); /* Erase the old RBB */ fin.x = t_t.x; /* Save this point for next go around*/ fin.y = t_t.y; draw_rbb(*start, fin); /* Draw the new RBB */ } } while (!t_t.depressed && t_t.near_); /* Until they want to stop */ draw_rbb(*start, fin); /* Erase the xor'ed RBB */ making_wire = false; m_nocursor(); /* GEG erase cursor */ xor_off(); /* No more xor */ if (t_t.near_ && t_t.y <= TOP_OF_SCREEN && start->x != fin.x && start->y != fin.y) /* if pen not lifted (abort) and... */ { /* area... */ /* draw_rbb(start,fin); { Don't draw the wire. */ finish->x = start->x; finish->y = start->y; /* placeholders */ start->x = MIN(start->x, fin.x); start->y = MIN(start->y, fin.y); finish->x = MAX(finish->x, fin.x); finish->y = MAX(finish->y, fin.y); *start = scale_down(*start); *finish = scale_down(*finish); Result = true; /* successfully got rbb */ } else Result = false; /* If they ended the box in the pad */ /* no zero width wires */ grestore(); debounce(); /* make sure pen is up */ return Result; } void make_wire(point start, short l) { point finish; if (!get_rbb(&start, &finish)) return; add_wire(start, finish, l, "", NULL); small_graphics(); draw_wire(last_added->ll, last_added->ur); big_graphics(); } /*$if false$ PROCEDURE make_wire(start : point; l : shortint); VAR fin : point; t_t : tablet_info; lambda_start : point; BEGIN making_wire := true; debounce; { Get the pen up } xor_on; { Rubber band boxes are in xor } m_nocursor; { We know where the cursor is from } lambda_start := scale_down (start); { MAS - save start in LAMBDA coords } fin := start; { Start off with an empty box } start := scale_up (lambda_start); draw_rbb(start,fin); { Draw it to get in phase with loop } REPEAT { Repeat RBB's } t_t := check_pen; { Find out where we are. } IF t_t.y > top_of_screen { If we are off the drawing pad, } THEN t_t := scale(t_t,1) { Only scale the x coords } ELSE t_t := scale(t_t,3); { Otherwise scale both axes } if (fin.x <> t_t.x) or (fin.y <> t_t.y) then begin { only redraw if you have actually moved } start := scale_up (lambda_start); draw_rbb(start,fin); { Erase the old RBB } fin.x := t_t.x; { Save this point for next go around} fin.y := t_t.y; draw_rbb(start,fin); { Draw the new RBB } end; UNTIL t_t.depressed or not t_t.near; { Until they want to stop } draw_rbb(start,fin); { Erase the xor'ed RBB } making_wire := false; m_nocursor; { GEG erase cursor } xor_off; { No more xor } IF t_t.near { if pen not lifted (abort) and... } and (t_t.y <= top_of_screen) { If they ended the box in the pad } and (start.x <> fin.x) and (start.y <> fin.y) { no zero width wires } THEN BEGIN { area... } draw_rbb(start,fin); { Draw the wire. } add_wire(scale_down(start), { and add it to the tree. } scale_down(fin),l,'', nil); END; debounce; { make sure pen is up } END; $end$*/ /*******************************************************************************/ /* accepts two points on the screen-grid, and draws a box between them */ void draw_wire_box(long ax, long ay, long bx, long by) { if (curr_style != 0) /* start line style out at same point each time */ m_linestyle(curr_style); switch (curr_fillp) { case -3: /* Cross, same linestyle as border, black filled */ filledbox(ax, ay, bx, by, 0); m_color(curr_fillc); m_drawline(ax, ay, bx, by); m_drawline(bx, ay, ax, by); m_color(curr_color); break; case -2: /* Cross, same linestyle as border, not black filled */ m_drawrect(ax, ay, bx, by); m_color(curr_fillc); m_drawline(ax, ay, bx, by); m_drawline(bx, ay, ax, by); m_color(curr_color); break; case -1: m_drawrect(ax, ay, bx, by); break; case 0: filledbox(ax, ay, bx, by, curr_fillc); break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: pat_fillbox(ax, ay, bx, by, curr_fillp); break; default: printf("\007\007\007\007\007Illegal pattern in draw_wire_box=\007\007\007%d\n", curr_fillp); break; } } /* Accepts two points on the lambda-grid, and draws a box between them */ void draw_wire(point a, point b) { tr_4(a.x, a.y, b.x, b.y); draw_wire_box(tr_ax, tr_ay, tr_bx, tr_by); } /*******************************************************************************/ Static void start_deferred(void) { last_deferred = deferred_stack; } Static void add_deferred(point ll, point ur, long layer) { deferred_rec *tmp_deferred; if (last_deferred == NULL) { tmp_deferred = Malloc(sizeof(deferred_rec)); check_mem(); tmp_deferred->next = deferred_stack; deferred_stack = tmp_deferred; } else { tmp_deferred = last_deferred; last_deferred = last_deferred->next; } tmp_deferred->ll = ll; tmp_deferred->ur = ur; tmp_deferred->layer = layer; /*write(#139'Ad',layer:1,#136);*/ } Static void end_deferred(void) { deferred_rec *tmp_deferred, *WITH; tmp_deferred = deferred_stack; while (tmp_deferred != last_deferred) { WITH = tmp_deferred; if (redisp_last_layer != WITH->layer) { redisp_last_layer = WITH->layer; set_layer(redisp_last_layer); } draw_wire(WITH->ll, WITH->ur); tmp_deferred = WITH->next; /*write(#139'Dd',layer:1,#136);*/ } } /*******************************************************************************/ Static void redisplay2(node *t_p) { short qlayer; /* quick (local) layer */ bb_states bb_save; port_node *ports; point a, b; node *WITH; if (asm_memavail() < min_mem_recurse) { show_message("\007Low on memory in REDISPLAY", false); goto _L1; } bb_save = bb_state; while (t_p != NULL) { WITH = t_p; bb_state = bb_save; if (bb_state == bb_on || bb_check(WITH->ll, WITH->ur) != bb_off) { /*t_p^.*/ qlayer = WITH->layer; /*t_p^.*/ if (layers_on[qlayer - min_layer]) { if (deferred[qlayer - min_layer]) /*t_p^.*/ add_deferred(WITH->ll, WITH->ur, qlayer); else { if (redisp_last_layer != qlayer) { /*t_p^.*/ redisp_last_layer = qlayer; set_layer(redisp_last_layer); } /*t_p^.*/ draw_wire(WITH->ll, WITH->ur); } /*t_p^.*/ } ports = WITH->portlist; /*t_p^.*/ if (ports != NULL && display_ports) { /*t_p^.*/ while (ports != NULL) { a = transform_point(ports->p1); /* XFORM */ b = transform_point(ports->p2); m_linestyle(0); m_move(a.x, a.y); m_color(BLACK); m_draw(b.x, b.y); m_move(a.x, a.y); if (redisp_last_layer != ports->layerno) { /* restore current color */ redisp_last_layer = ports->layerno; set_layer(redisp_last_layer); } else m_color(curr_color); m_linestyle(2); /* set coarse dotted style */ m_draw(b.x, b.y); m_linestyle(curr_style); /* restore current style */ ports = ports->next; } } if (WITH->child != NULL) /*t_p^.*/ redisplay2(WITH->child); } /*t_p^.*/ /* else write(#137'G'#136) clipping in geometry */ t_p = WITH->next; /*t_p^.*/ } _L1: ; } void redisplay(node *t_p) { redisp_last_layer = -1; start_deferred(); redisplay2(t_p); end_deferred(); } /*******************************************************************************/ void refresh_geom(void) { gsave(); xor_off(); /* NEW - never screw with the menu!! */ small_graphics(); clear_screen(); m_graphics_on(); make_matrix(); /* re-make initial matrix */ bb_state = bb_clip; redisplay(main_); big_graphics(); if (!intzoom) { /*show_message('Non-integer ZOOM',true); */ m_color(WHITE); m_move(20, 355); m_displaytext("Non-integer Zoom"); } grestore(); } /*******************************************************************************/ void small_clear(void) { small_graphics(); clear_screen(); m_graphics_on(); big_graphics(); } /*******************************************************************************/ Static void SM(void) { printf("|%6ld%6ld| 1\n", tr_ctm.a, tr_ctm.b); printf("|%6ld%6ld| ---\n", tr_ctm.c, tr_ctm.d); printf("|%6ld%6ld|%6ld\n", tr_ctm.e, tr_ctm.f, tr_ctm.g); } Static void show_routing(routing *rt) { /* draw the routing within a composition cell */ routing *rt_ptr, *rt_horiz; point tp1, tp2; rt_horiz = rt; while (rt_horiz != NULL) { rt_ptr = rt_horiz; set_layer(rt_ptr->layer); while (rt_ptr != NULL) { /* writeln (rt_ptr^.pt1.x, rt_ptr^.pt1.y, rt_ptr^.pt2.x, rt_ptr^.pt2.y); */ tp1 = transform_point(rt_ptr->pt1); tp2 = transform_point(rt_ptr->pt2); /* writeln (' ',tp1.x, tp1.y, tp2.x, tp2.y); */ m_move(tp1.x, tp1.y); m_draw(tp2.x, tp2.y); rt_ptr = rt_ptr->to_point; } rt_horiz = rt_horiz->next; } } void show_comp_2(c_cell *root) { /* stacks up a transformation matrix */ point tp1, tp2; long wid; Char pr_name[81]; short ylabelpos; /* y position (screen units) of label*/ tr_matrix old_matrix; long t; bb_states bb_save; port_node *ports; Char STR2[256]; old_matrix = tr_ctm; bb_save = bb_state; if (asm_memavail() < min_mem_recurse) { show_message("\007Low on memory in SHOW_COMP", false); return; } TRY(try2); while (root != NULL) { bb_state = bb_save; pl_tran(root->ll.x, root->ll.y); pl_xform(root->xform); /* TP2 is used in bounding box calculation and also if the cell is */ /* closed. */ tp2.x = root->ur.x - root->ll.x; tp2.y = root->ur.y - root->ll.y; if (bb_state == bb_on || bb_check(zero_point, tp2) != bb_off) { /* Ok to draw this cell */ if (root->status == OPENED) { if (root->tag == COMP) { if (fleshed_out_routing) draw_routing(root->UU.U1.c_d->routing_); else show_routing(root->UU.U1.c_d->routing_); show_comp_2(root->UU.U1.c_d->data); } else redisplay(root->UU.g_d->data); } else { /* cell must be closed, so draw it */ set_layer(comp_box); draw_wire(zero_point, tp2); if (root->tag == GEOM && display_ports) { /* show ports if any */ ports = root->UU.g_d->portlist; while (ports != NULL) { m_color(BLACK); draw_wire(ports->p1, ports->p2); m_color(ports->layerno); draw_wire(ports->p1, ports->p2); ports = ports->next; } } tp1 = transform_point(zero_point); tp2 = transform_point(tp2); if (tp1.x > tp2.x) { t = tp1.x; tp1.x = tp2.x; tp2.x = t; } if (tp1.y > tp2.y) { t = tp1.y; tp1.y = tp2.y; tp2.y = t; } if (tp2.y - tp1.y > 7) { wid = tp2.x - tp1.x; if (root->tag == GEOM) strcpy(pr_name, root->UU.g_d->name); else strcpy(pr_name, root->UU.U1.c_d->name); if (*root->prefix != '\0') sprintf(pr_name + strlen(pr_name), ".%s", root->prefix); if (root->xform > 0 && root->xform < 7) m_color(root->xform); else if (root->xform == 0) m_color(BR_WHITE); else m_color(BUR); if (gstate.ref_in_black) m_color(0); if (wid - 2 >= strlen(pr_name) * 7) { ylabelpos = (tp1.y + tp2.y) / 2 - 3; m_move(tp1.x + (wid - strlen(pr_name) * 7) / 2, ylabelpos); if (ylabelpos < TOP_OF_SCREEN - 3) display_text(pr_name); } else { wid = (wid - 4) / 7; ylabelpos = (tp1.y + tp2.y) / 2 - 3; m_move(tp1.x + 2, ylabelpos); if (ylabelpos < TOP_OF_SCREEN - 3) { sprintf(STR2, "%.*s", (int)wid, pr_name); display_text(STR2); } } } } } root = root->next; /* deal with its siblings */ tr_ctm = old_matrix; /* restore transformation matrix */ } RECOVER(try2); if (P_escapecode == 10) _Escape(P_escapecode); else { show_error("Error in procedure SHOW_COMP_2", false); _Escape(10); } ENDTRY(try2); } void show_comp(void) { tr_matrix old_mat; /*$if display_test$ TIME_start; $end$*/ gsave(); xor_off(); make_matrix(); /* re-make initial matrix */ old_mat = tr_ctm; /* Save it for later */ small_graphics(); clear_screen(); m_graphics_on(); bb_state = bb_clip; /*$if display_test$ TIME_end('Setup and clear screen'); $end$*/ /*$if display_test$ TIME_start; $end$*/ if (fleshed_out_routing) draw_routing(comp_cells->routing_); else show_routing(comp_cells->routing_); /*$if display_test$ TIME_end('Routing'); $end$*/ /*$if display_test$ TIME_start; $end$*/ show_comp_2(comp_cells->data); /*$if display_test$ TIME_end('Drawing graphics'); $end$*/ /*$if display_test$ TIME_start; $end$*/ big_graphics(); if (!intzoom) { /*show_message('Non-integer ZOOM',true); */ m_color(WHITE); m_move(20, 355); m_displaytext("Non-integer Zoom"); } grestore(); /*$if display_test$ TIME_end('Shutdown time'); $end$*/ } /* call show_comp_2 with root of tree */ /*******************************************************************************/ void fast_add(point p1, point p2, short l, Char *name, port_node *port) { /* This routine adds a wire node into the tree. It assumes that the nodes */ /* being added are in the order of top/down and then left to right (i.e. */ /* Write node, recur down, recur across. This is currently being used by */ /* the read routine and the NEW routine (for geometry cells). In both */ /* cases, we know the ordering of the nodes (and there is no tree before */ /* the operation. */ node *t_fa_p, *t_np, *t_op; boolean end_loop; port_node *port2; t_fa_p = get_a_node(); t_fa_p->ll = p1; t_fa_p->ur = p2; t_fa_p->layer = l; t_fa_p->child = NULL; strcpy(t_fa_p->name, name); while (port != NULL) { port2 = get_port_node(); *port2 = *port; port2->next = t_fa_p->portlist; t_fa_p->portlist = port2; port = port->next; } last_added = t_fa_p; t_np = main_; t_op = NULL; end_loop = false; do { if (t_np != NULL) { if (within(t_np, p1, p2, 2)) { t_op = t_np; t_np = t_np->child; } else end_loop = true; } } while (end_loop != true && t_np != NULL); t_fa_p->next = t_np; if (t_op == NULL) { main_ = t_fa_p; t_fa_p->parent = NULL; } else { t_op->child = t_fa_p; t_fa_p->parent = t_op; } t_fa_p->next = t_np; } /*******************************************************************************/ void reshuffle(node *shuf_obj) { node *next_obj; /* Put last moved object(or any) back into tree one node at a time */ if (asm_memavail() < min_mem_recurse) { show_message("\007Low on memory in RESHUFFLE", false); return; } while (shuf_obj != NULL) { /*reshuffle(shuf_obj^.child); */ /* MAS--want it here for coincident boxes*/ if (shuf_obj->layer != sel_box) add_wire(shuf_obj->ll, shuf_obj->ur, shuf_obj->layer, shuf_obj->name, shuf_obj->portlist); reshuffle(shuf_obj->child); /* so what if things get swizzled! */ /* reshuffle(shuf_obj^.child); { MAS */ /* horizontal iteration vs. recursion */ next_obj = shuf_obj->next; if (!retain_nodes) { shuf_obj->next = NULL; /* Don't let recl_nodes get these!! */ shuf_obj->child = NULL; recl_nodes(&shuf_obj); } shuf_obj = next_obj; } } /*******************************************************************************/ void fast_shuf(node *shuf_obj) { /* This routine puts nodes back into the main tree (just like reshuffle), */ /* However, since it is only called when it is copying a tree, it knows */ /* Already that it is in the right order, and does not need to check if */ /* this node meets any criteria. */ if (asm_memavail() < min_mem_recurse) { show_message("\007Low on memory in FAST_SHUF", false); return; } while (shuf_obj != NULL) { if (shuf_obj->layer != sel_box) fast_add(shuf_obj->ll, shuf_obj->ur, shuf_obj->layer, shuf_obj->name, shuf_obj->portlist); fast_shuf(shuf_obj->child); shuf_obj = shuf_obj->next; } } /*******************************************************************************/ void reinstate(void) { /* Puts the last moved nodes back into the tree */ if (last_moved->parent == NULL) main_ = last_moved->next; else last_moved->parent->child = last_moved->next; last_moved->next = NULL; reshuffle(last_moved); if (auto_refresh) refresh_geom(); last_moved = NULL; /* disp_all_one_sel; */ /* draw_menu_square(build_mode, PURPLE); { Show which mode we are in */ } /*******************************************************************************/ void inc_nodes(node *n, long dx, long dy) { port_node *port; node *WITH; if (asm_memavail() < min_mem_recurse) { show_message("\007Low on memory in INC_NODES", false); return; } while (n != NULL) { WITH = n; WITH->ll.x += dx; WITH->ll.y += dy; WITH->ur.x += dx; WITH->ur.y += dy; port = WITH->portlist; while (port != NULL) { port->p1.x += dx; port->p2.x += dx; port->p1.y += dy; port->p2.y += dy; port = port->next; } inc_nodes(WITH->child, dx, dy); n = WITH->next; } } /*******************************************************************************/ void node_out_of_tree(node *obj) { /* it out of the tree */ node *obj_parent, *scan; /* Takes the passed node, and gets */ obj_parent = obj->parent; if (obj_parent == NULL) { if (main_ == obj) main_ = obj->next; else { scan = main_; /*####How do we know the loop will */ while (scan->next != obj) /* terminate??? */ scan = scan->next; scan->next = obj->next; } } else if (obj->parent->child == obj) obj->parent->child = obj->next; else { scan = obj->parent->child; while (scan->next != obj) /*####How do we know the loop will */ scan = scan->next; /* terminate??? */ scan->next = obj->next; } obj->next = NULL; } /*******************************************************************************/ void restore_in_tree(node *n) { node *obj_parent; obj_parent = parent_of(main_, n->ll, n->ur, 2); n->parent = obj_parent; if (obj_parent == NULL) { n->next = main_; main_ = n; } else { n->next = obj_parent->child; obj_parent->child = n; } } /*******************************************************************************/ void move_a_tree(node *obj, point start) { point old_pt, new_pt; tablet_info new_pen; xor_on(); small_graphics(); if (!point_to_point_move) { if (first_dotted) gstate.dotted = true; redisplay(obj); gstate.dotted = true; redisplay(obj); } old_pt = start; do { new_pen = check_pen(); new_pt.x = new_pen.x; new_pt.y = new_pen.y; if (point_to_point_move) { new_pt = scale_down(new_pt); new_pt = scale_up(new_pt); /* put it on lambda grid */ m_cursor(new_pt.x, new_pt.y); /* draw cursor */ } new_pt = scale_down(new_pt); if (new_pt.x != old_pt.x || new_pt.y != old_pt.y || !new_pen.near_) { if (!point_to_point_move) /* erase old shape */ redisplay(obj); inc_nodes(obj, new_pt.x - old_pt.x, new_pt.y - old_pt.y); if (new_pen.near_ && !point_to_point_move) redisplay(obj); old_pt = new_pt; } } while (!new_pen.depressed && new_pen.near_); if (!new_pen.near_) { /* move object back to where it started */ inc_nodes(obj, start.x - new_pt.x, start.y - new_pt.y); if (!point_to_point_move) redisplay(obj); } xor_off(); gstate.dotted = false; big_graphics(); } Local double dist(long x1, long y1, long x2, long y2) { long TEMP, TEMP1; TEMP = x2 - x1; TEMP1 = y2 - y1; return sqrt((double)(TEMP * TEMP + TEMP1 * TEMP1)); } void draw_routing(routing *rt) { boolean filled; double r; long dx, dy, radius; routing *rt2; point pt1, pt2; long xa[4], ya[4]; /* actually, 4 is enough */ filled = (disp_style != 0); /* this is not really correct */ while (rt != NULL) { /* rt will run across the list */ rt2 = rt; /* this pointer will run down the list */ while (rt2 != NULL) { radius = (long)(zoom * rt2->width / 2); pt1 = transform_point(rt2->pt1); pt2 = transform_point(rt2->pt2); if (radius != 0) { r = dist(pt1.x, pt1.y, pt2.x, pt2.y) / radius; dx = pt2.x - pt1.x; dy = pt2.y - pt1.y; if (r == 0) { dx = 0; dy = 0; r = 1.0; } } else { dx = 0; dy = 0; r = 1.0; radius = 0; } set_layer(rt2->layer); if (manhattan_routing) { /* draw skeletally connected boxes */ xa[0] = pt1.x - (long)floor(dx / r - dy / r + 0.5); /* To extend wire ends */ ya[0] = pt1.y - (long)floor(dy / r + dx / r + 0.5); /* by 1 radius, remove */ xa[1] = pt1.x - (long)floor(dx / r + dy / r + 0.5); /* comment braces */ ya[1] = pt1.y - (long)floor(dy / r - dx / r + 0.5); /* around first 'round' */ xa[2] = pt2.x + (long)floor(dx / r - dy / r + 0.5); /* term */ ya[2] = pt2.y + (long)floor(dy / r + dx / r + 0.5); xa[3] = pt2.x + (long)floor(dx / r + dy / r + 0.5); ya[3] = pt2.y + (long)floor(dy / r - dx / r + 0.5); } else { /* draw circles */ xa[0] = pt1.x - (long)floor(0.5 - dy / r); /*dx/r*/ /* To extend wire ends */ ya[0] = pt1.y - (long)floor(dx / r + 0.5); /*dy/r*/ /* by 1 radius, remove */ xa[1] = pt1.x - (long)floor(dy / r + 0.5); /*dx/r*/ /* comment braces */ ya[1] = pt1.y - (long)floor(0.5 - dx / r); /*dy/r*/ /* around first 'round' */ xa[2] = pt2.x + (long)floor(0.5 - dy / r); /*dx/r*/ /* term */ ya[2] = pt2.y + (long)floor(dx / r + 0.5); /*dy/r*/ xa[3] = pt2.x + (long)floor(dy / r + 0.5); /*dx/r*/ ya[3] = pt2.y + (long)floor(0.5 - dx / r); /*dy/r*/ } if (filled) { /* draw insides */ if (curr_fillp == -1) m_color(curr_color); else m_color(curr_fillc); m_fillpoly(4, (int *) xa, (int *) ya); /* draw the insides here */ } m_color(curr_color); if (!filled) m_linestyle(curr_style); m_drawpoly(4, (int *) xa, (int *) ya); /* draw the outline here */ rt2 = rt2->to_point; } /* now draw circles */ rt2 = rt; /* traverse the tree again */ /* draw the first circle in the path, if not Manhattan_routing */ radius = (long)(zoom * rt2->width / 2); pt1 = transform_point(rt2->pt1); set_layer(rt2->layer); if (!manhattan_routing) { if (filled) { if (curr_fillp == -1) m_color(curr_color); else m_color(curr_fillc); m_ellipse(pt1.x, pt1.y, radius, radius, curr_color); } else { m_color(m_trans); /* make inside transparent */ if (!filled) m_linestyle(curr_style); m_ellipse(pt1.x, pt1.y, radius, radius, curr_color); } } /* now draw the remaining circles, if necessary */ while (rt2 != NULL) { radius = (long)(zoom * rt2->width / 2); pt1 = transform_point(rt2->pt1); pt2 = transform_point(rt2->pt2); set_layer(rt2->layer); if (!manhattan_routing) { if (filled) { if (curr_fillp == -1) m_color(curr_color); else m_color(curr_fillc); m_ellipse(pt2.x, pt2.y, radius, radius, curr_color); } else { m_color(m_trans); /* make inside transparent */ if (!filled) m_linestyle(curr_style); m_ellipse(pt2.x, pt2.y, radius, radius, curr_color); } } rt2 = rt2->to_point; } rt = rt->next; /* draw next routing wire */ } m_linestyle(0); } /* End. */