1 /*
2  *   Copyright (C) 1989-1992 Yale University
3  *
4  *   This work is distributed in the hope that it will be useful; you can
5  *   redistribute it and/or modify it under the terms of the
6  *   GNU General Public License as published by the Free Software Foundation;
7  *   either version 2 of the License,
8  *   or any later version, on the following conditions:
9  *
10  *   (a) YALE MAKES NO, AND EXPRESSLY DISCLAIMS
11  *   ALL, REPRESENTATIONS OR WARRANTIES THAT THE MANUFACTURE, USE, PRACTICE,
12  *   SALE OR
13  *   OTHER DISPOSAL OF THE SOFTWARE DOES NOT OR WILL NOT INFRINGE UPON ANY
14  *   PATENT OR
15  *   OTHER RIGHTS NOT VESTED IN YALE.
16  *
17  *   (b) YALE MAKES NO, AND EXPRESSLY DISCLAIMS ALL, REPRESENTATIONS AND
18  *   WARRANTIES
19  *   WHATSOEVER WITH RESPECT TO THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
20  *   INCLUDING,
21  *   BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
22  *   PARTICULAR
23  *   PURPOSE.
24  *
25  *   (c) LICENSEE SHALL MAKE NO STATEMENTS, REPRESENTATION OR WARRANTIES
26  *   WHATSOEVER TO
27  *   ANY THIRD PARTIES THAT ARE INCONSISTENT WITH THE DISCLAIMERS BY YALE IN
28  *   ARTICLE
29  *   (a) AND (b) above.
30  *
31  *   (d) IN NO EVENT SHALL YALE, OR ITS TRUSTEES, DIRECTORS, OFFICERS,
32  *   EMPLOYEES AND
33  *   AFFILIATES BE LIABLE FOR DAMAGES OF ANY KIND, INCLUDING ECONOMIC DAMAGE OR
34  *   INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER YALE SHALL BE
35  *   ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE
36  *   POSSIBILITY OF THE FOREGOING.
37  *
38  */
39 
40 /* -----------------------------------------------------------------
41 FILE:	    draw.c
42 DESCRIPTION:This file draw the data structures to the screen
43 CONTENTS:   initgraphics()
44 DATE:	    Aug  9, 1989
45 REVISIONS:  Feb  7, 1990 - took total row length out of procedure calls.
46 	    Feb 28, 1990 - added tile dialog box.
47 	    Sep 25, 1990 - added modify core area.
48 	    Oct 14, 1990 - updated for new graphics.
49 	    Oct 21, 1990 - fixed dialog boxes.
50 	    Dec  7, 1990 - rewrote and reorganized graphics functions.
51 		Added merge functions, align function, set parameter
52 		menus.  Also modified edit tile dialog box.
53 	    Dec 15, 1990 - added divide tile and reset tiles.
54 	    Dec 28, 1990 - added edit and align functions for macros.
55 		Also added divide tiles L/R.
56 	    Mon Jan  7 18:21:05 CST 1991 - now announce
57 		presence of restart file.  Also check
58 		for errors during read_vertices.
59 	    Fri Jan 25 17:50:54 PST 1991 - added mirror row feature.
60 	    Sat Jan 26 16:24:18 PST 1991 - made feeds a double
61 		and moved force rows to a call in main.c
62 	    Sat Feb 23 00:32:10 EST 1991 - disallow macro moves during
63 		partitioning.
64 	    Tue Mar 12 16:52:19 CST 1991 - added numrows function.
65 	    Thu Apr 18 00:57:25 EDT 1991 - now genrows can rotate
66 		macros.
67 	    Sun Apr 21 21:48:10 EDT 1991 - fixed problem with macro
68 		orientation and now follow control menu convention.
69 	    Sat Sep 21 15:37:36 EDT 1991 - added memory capability.
70 ----------------------------------------------------------------- */
71 
72 #include <string.h>
73 #include <yalecad/base.h>
74 #include <yalecad/debug.h>
75 #include <globals.h>
76 
77 #ifndef NOGRAPHICS
78 
79 #define MENUP   "genrows_menu"
80 
81 #include <yalecad/file.h>
82 #include <yalecad/draw.h>
83 #include <yalecad/colors.h>
84 #include <yalecad/message.h>
85 #include <yalecad/dialog.h>
86 #include <yalecad/relpos.h>
87 #include "genrows.h"
88 
89 #define FCOLOR   TWYELLOW
90 
91 static BOOL auto_drawS=TRUE ;/* whether to draw immediately after exp.*/
92 static BOOL drawLabelS=FALSE ; /* whether to draw labels */
93 static BOOL drawTileS=TRUE ; /* whether to draw tiles */
94 static BOOL drawMacroS=TRUE ; /* whether to draw macros */
95 static BOOL drawRowS=TRUE ;  /* whether to draw stdcell rows */
96 static BOOL drawOrientS=FALSE ;  /* whether to draw macro orientation label */
97 static BOOL selectMacroS = 0 ; /* current chosen macro */
98 static TILE_BOX *selected_tileS = NULL ;/* current chosen tile */
99 static ROW_BOX *selected_rowS = NULL ;/* current chosen row */
100 
101 
102 /* #define DEVELOPMENU */
103 /* During development use TWread_menus in place of menuS */
104 /* to create menu record, ie.  TWread_menus(MENUP) */
105 #ifdef DEVELOPMENU
106 #define MENU   TWread_menus(MENUP)
107 #else
108 #define MENU   menuS
109 #endif
110 
111 /* #define DEVELOPDIALOG */
112 
113 #ifndef DEVELOPDIALOG
114 #include <dialog.h>
115 #include <dialog2.h>
116 #include <dialog3.h>
117 #else
118 static TWDIALOGPTR dialogS ;
119 static TWDIALOGPTR row_dialogS ;
120 static TWDIALOGPTR macro_dialogS ;
121 #endif
122 
123 #include <menus.h>
124 
125 static void draw_tile();
126 static void draw_macro();
127 static void draw_fs();
128 static void last_chance();
129 static void no_move_message();
130 static void save_for_do();
131 static void update_macro();
132 static void graphics_dump();
133 static INT pick_macro();
134 static TILE_BOX *pick_tile();
135 static ROW_BOX *pick_row();
136 static BOOL edit_tiles();
137 static void edit_macro();
138 static void update_vertices();
139 static void rotate_vertices();
140 static void find_nearest_corner();
141 static void highlight_corner();
142 static void outm();
143 
144 /* forward declarations */
145 void edit_row(ROW_BOX* rowptr );
146 void get_global_pos(INT macro, INT *l, INT *b, INT *r, INT *t );
147 
initgraphics(argc,argv,windowId)148 void initgraphics( argc, argv, windowId )
149 INT argc, windowId ;
150 char *argv[] ;
151 {
152 
153     char *host ;
154     char *Ygetenv() ;
155     void draw_the_data() ;
156 
157 
158     if( !(graphicsG) ){
159 	return ;
160     }
161     /* we need to find host for display */
162     if(!(TWcheckServer() )){
163 	M(MSG,NULL, "Aborting graphics...\n\n" ) ;
164 	graphicsG = FALSE ;
165 	return ;
166     }
167     if( windowId ){
168 	/* init windows as a parasite */
169 	if( !( TWinitParasite(argc,argv,TWnumcolors(),
170 	    TWstdcolors(),FALSE,MENU, (INT (*)()) draw_the_data, windowId ))){
171 	    M(ERRMSG,"initgraphics","Aborting graphics.");
172 	    graphicsG = FALSE ;
173 	    return ;
174 	}
175     } else {
176 	/* init window as a master */
177 	if(!(TWinitGraphics(argc,argv,TWnumcolors(),TWstdcolors(),
178 	    FALSE,MENU, (INT (*)()) draw_the_data ))){
179 	    M(ERRMSG,"initgraphics","Aborting graphics.");
180 	    graphicsG = FALSE ;
181 	    return ;
182 	}
183     }
184     TWsetMode(0) ;
185     TWsetwindow( 0, 0, 10, 10 ) ;
186     TWdrawMenus() ;
187     TWflushFrame() ;
188 
189 } /* end initgraphics */
190 
191 
192 /* how to draw the data */
193 void
draw_the_data()194 draw_the_data()
195 {
196     INT      i ;            /* counter */
197     INT      l, b, r, t ;   /* core dimensions */
198     INT      color ;        /* current color */
199     INT      macro ;        /* current macro */
200     char     label[LRECL] ; /* make a label buffer */
201     char     *labelptr ;    /* pointer to current label */
202     TILE_BOX *tileptr ;     /* current tile */
203     ROW_BOX  *rowptr  ;     /* current row being output */
204     ROW_BOX  *segment ;     /* current segment being output */
205     ROW_BOX  *get_rowptr(); /* get data structure */
206 
207     if( !(graphicsG) ){
208 	return ;
209     }
210     /* initialize screen */
211     TWstartFrame() ;
212     /**** draw the MC calculated core *******/
213     get_core( &l, &b, &r, &t, FALSE ) ;
214     TWdrawCell( 0, l, b, r, t, TWWHITE, NULL ) ;
215     /**** draw the tiles *******/
216     if( drawTileS ){
217 	/* draw all but last tile */
218 	for( tileptr=tile_listG;tileptr->next;tileptr=tileptr->next ){
219 	    draw_tile( tileptr ) ;
220 	}
221     }
222     /**** draw the rows *******/
223     if( drawRowS ){
224 	for( rowptr=get_rowptr();rowptr;rowptr=rowptr->next_row ){
225 
226 	    if( rowptr->class ){
227 		sprintf( label, "SEGMENT:%d CLASS:%d", rowptr->seg, rowptr->class);
228 	    } else {
229 		sprintf( label, "SEGMENT:%d CLASS:1", rowptr->seg ) ;
230 	    }
231 	    if( rowptr->mirror ){
232 		strcat( label, " MIRROR" ) ;
233 	    }
234 	    if( drawLabelS ){
235 		labelptr = label ;
236 	    } else {
237 		labelptr = NULL ;
238 	    }
239 
240 	    if( feeds_per_segG > 0 ){
241 		if( rowptr->next_segment ){
242 		    /* means we have more that one segment to row */
243 		    for( segment=rowptr;segment;segment=segment->next_segment){
244 			if( segment->class ){
245 			    sprintf( label, "SEGMENT:%d CLASS:%d",
246 			    segment->seg, segment->class);
247 			} else {
248 			    sprintf( label, "SEGMENT:%d CLASS:1", segment->seg ) ;
249 			}
250 			if( rowptr->mirror ){
251 			    strcat( label, " MIRROR" ) ;
252 			}
253 			if( drawLabelS ){
254 			    labelptr = label ;
255 			} else {
256 			    labelptr = NULL ;
257 			}
258 			r = segment->urx - feeds_per_segG ;
259 			if( r > segment->llx ){
260 			    /* make sure we have two valid segments */
261 			    TWdrawCell( segment->seg, segment->llx, segment->lly,
262 					r, segment->ury,
263 					TWBLUE, labelptr ) ;
264 			    TWdrawCell( segment->seg, r, segment->lly,
265 					segment->urx, segment->ury,
266 					TWYELLOW, NULL ) ;
267 			} else {
268 			    TWdrawCell( segment->seg, segment->llx, segment->lly,
269 					segment->urx, segment->ury,
270 					TWBLUE, labelptr ) ;
271 			}
272 			if( segment == selected_rowS ){
273 			    TWdrawCell( segment->seg, segment->llx, segment->lly,
274 					segment->urx, segment->ury,
275 					TWVIOLET, labelptr ) ;
276 			}
277 
278 		    } /* end for loop */
279 
280 		} else {
281 		    r = rowptr->urx - feeds_per_segG ;
282 		    if( r > rowptr->llx ){
283 			/* make sure we have two valid segments */
284 			TWdrawCell( rowptr->seg, rowptr->llx, rowptr->lly,
285 				    r, rowptr->ury,
286 				    TWBLUE, labelptr ) ;
287 			TWdrawCell( rowptr->seg, r, rowptr->lly,
288 				    rowptr->urx, rowptr->ury,
289 				    TWYELLOW, NULL ) ;
290 		    } else {
291 			TWdrawCell( rowptr->seg, rowptr->llx, rowptr->lly,
292 				    rowptr->urx, rowptr->ury,
293 				    TWBLUE, labelptr ) ;
294 		    }
295 		    if( rowptr == selected_rowS ){
296 			TWdrawCell( rowptr->seg, rowptr->llx, rowptr->lly,
297 				    rowptr->urx, rowptr->ury,
298 				    TWVIOLET, labelptr ) ;
299 		    }
300 		}
301 	    } else {
302 		if( rowptr->next_segment ){
303 		    /* means we have more that one segment to row */
304 		    for( segment=rowptr;segment;segment=segment->next_segment){
305 			if( segment->class ){
306 			    sprintf( label, "SEGMENT:%d CLASS:%d",
307 			    segment->seg, segment->class);
308 			} else {
309 			    sprintf( label, "SEGMENT:%d CLASS:1", segment->seg ) ;
310 			}
311 			if( rowptr->mirror ){
312 			    strcat( label, " MIRROR" ) ;
313 			}
314 			TWdrawCell( segment->seg, segment->llx, segment->lly,
315 				    segment->urx, segment->ury,
316 				    TWBLUE, labelptr ) ;
317 			if( segment == selected_rowS ){
318 			    TWdrawCell( segment->seg, segment->llx, segment->lly,
319 					segment->urx, segment->ury,
320 					TWVIOLET, labelptr ) ;
321 			}
322 
323 		    } /* end for loop */
324 
325 		} else {
326 		    TWdrawCell( rowptr->seg, rowptr->llx, rowptr->lly,
327 				rowptr->urx, rowptr->ury,
328 				TWBLUE, labelptr ) ;
329 		    if( rowptr == selected_rowS ){
330 			TWdrawCell( rowptr->seg, rowptr->llx, rowptr->lly,
331 				    rowptr->urx, rowptr->ury,
332 				    TWVIOLET, labelptr ) ;
333 		    }
334 		}
335 	    }
336 	} /* end for loop */
337     } /* end drawRowS */
338 
339     if( drawMacroS ){
340 	for( macro = 1; macro <= num_macrosG; macro++ ){
341 	    draw_macro( macro, TWORANGE ) ;
342 	}
343     }
344     if( selectMacroS ){
345 	draw_macro( selectMacroS, TWVIOLET ) ;
346     }
347 
348     /* FLUSH OUTPUT BUFFER */
349     TWflushFrame() ;
350 
351 } /* end draw_the_data */
352 /* ***************************************************************** */
353 
draw_tile(tileptr)354 static void draw_tile( tileptr )
355 TILE_BOX *tileptr ;     /* current tile */
356 {
357     INT      color ;        /* current color */
358     char     label[LRECL] ; /* make a label buffer */
359     char     *labelptr ;    /* pointer to current label */
360 
361     if( drawLabelS ){
362 	sprintf( label, "TILE:%d", tileptr->name ) ;
363 	labelptr = label ;
364     } else {
365 	labelptr = NULL ;
366     }
367     /* determine color base on legality */
368     if( tileptr == selected_tileS ){
369 	color = TWVIOLET ;
370     } else if( tileptr->illegal ){
371 	color = TWRED ;
372     } else {
373 	color = TWGREEN ;
374     }
375     TWdrawCell( tileptr->name, tileptr->llx , tileptr->lly ,
376 		   tileptr->urx , tileptr->ury,
377 		   color, labelptr ) ;
378 } /* end draw_tile */
379 
draw_macro(macro,color)380 static void draw_macro( macro, color )
381 INT macro ;
382 INT color ;
383 {
384     INT i ;
385     char *labelptr ;        /* name of cell */
386     char label[LRECL] ;     /* buffer for name */
387     VERTEXPTR *vptr ;       /* current vertex array */
388     VERTEXPTR pt_ptr ;      /* current point */
389     MACROPTR  mptr ;        /* current macro */
390 
391     mptr = macroArrayG[macro] ;
392     vptr = mptr->vertices ;
393     TWarb_init() ;
394     for( i = 0 ; i < mptr->num_vertices ; i++ ) {
395 	pt_ptr = vptr[i] ;
396 	TWarb_addpt( pt_ptr->x, pt_ptr->y ) ;
397 	D( "genrows/macropts",
398 	    sprintf( label, "%d", i ) ;
399 	    TWdrawString( pt_ptr->x, pt_ptr->y, TWRED, label ) ;
400 	) ;
401     }
402     if( drawLabelS ){
403 	sprintf( label, "C:%d", macro ) ;
404 	labelptr = label ;
405     } else {
406 	labelptr = NULL ;
407     }
408     TWdrawArb( macro, color, labelptr ) ;
409     if( drawOrientS ){
410 	draw_fs( mptr ) ;
411     }
412 } /* end draw_macro */
413 
draw_fs(mptr)414 static void draw_fs( mptr )
415 MACROPTR  mptr ;        /* current macro */
416 {
417     INT i ;              /* counter */
418     INT x[10], y[10] ;   /* only 10 points to an F */
419     INT l, b, r, t ;     /* bounding box points */
420     VERTEXPTR pt_ptr ;   /* current point */
421     VERTEXPTR *vptr ;    /* current vertex array */
422     INT xout, yout ;     /* rotated points */
423     INT wid ;            /* with of the F */
424     INT pt ;             /* point counter */
425     INT xc, yc ;         /* center of cell */
426 
427     l = INT_MAX ;
428     b = INT_MAX ;
429     r = INT_MIN ;
430     t = INT_MIN ;
431     vptr = mptr->vertices ;
432     xc = mptr->xcenter ;
433     yc = mptr->ycenter ;
434     for( i = 0 ; i < mptr->num_vertices ; i++ ) {
435 	pt_ptr = vptr[i] ;
436 	if( mptr->orient <= 3 ){
437 	    l = MIN( l, pt_ptr->x - xc ) ;
438 	    b = MIN( b, pt_ptr->y - yc ) ;
439 	    r = MAX( r, pt_ptr->x - xc ) ;
440 	    t = MAX( t, pt_ptr->y - yc ) ;
441 	} else {
442 	    /* opposite aspect ratio */
443 	    l = MIN( l, pt_ptr->y - yc ) ;
444 	    b = MIN( b, pt_ptr->x - xc ) ;
445 	    r = MAX( r, pt_ptr->y - yc ) ;
446 	    t = MAX( t, pt_ptr->x - xc ) ;
447 	}
448     }
449     wid = (INT) (0.25 * (DOUBLE)( t - b ) ) ;
450     /* now set the points */
451     x[0] = l ;         y[0] = b ;
452     x[1] = l ;         y[1] = t ;
453     x[2] = r ;         y[2] = t ;
454     x[3] = r ;         y[3] = t - wid ;
455     x[4] = l + wid ;   y[4] = y[3] ;
456     x[5] = x[4] ;      y[5] = y[4] - wid ;
457     x[6] = l + 2*wid ; y[6] = y[5] ;
458     x[7] = x[6] ;      y[7] = y[6] - wid ;
459     x[8] = x[5] ;      y[8] = y[7] ;
460     x[9] = x[4] ;      y[9] = b ;
461     TWarb_init() ;
462     for( pt = 0; pt <= 9; pt++ ){
463 	/* rel position is a macro which calculates */
464 	/* absolute pin loc - defined in relpos.h */
465 	REL_POS( mptr->orient,
466 	    xout, yout,                              /* result */
467 	    x[pt], y[pt],                      /* cell relative */
468 	    xc, yc ) ;   /* cell center */
469 
470 	TWarb_addpt( xout, yout ) ;
471     }
472     TWdrawArb( 0, FCOLOR, NULL ) ;
473 } /* end draw_fs */
474 
475 /* set the size of the graphics window */
setGraphicWindow()476 void setGraphicWindow()
477 {
478     INT l, b, r, t ;
479     INT expand ;
480 
481     get_core( &l, &b, &r, &t, TRUE ) ;
482     expand = (int) (0.10 * (DOUBLE) (r - l) ) ;
483     expand = MAX( expand,
484     		  (int) (0.10 * (DOUBLE) (t - b) ) ) ;
485     l -= expand ;
486     r += expand ;
487     b -= expand ;
488     t += expand ;
489     TWsetwindow( l, b, r, t ) ;
490 
491 } /* end draw_changraph */
492 
493 /* *****************************************************************
494    USER INTERFACE
495 */
496 
497 /* heart of the graphic system processes user input */
498 void
process_graphics()499 process_graphics()
500 {
501 
502     INT x1, y1, x2, y2 ; /* coordinates for fixing cells and neighhds */
503     INT x, y ;           /* coordinates from pointer */
504     INT i ;             /* temp variable */
505     INT rows ;          /* number of stdcell rows */
506     INT net ;           /* net for minimum spanning tree */
507     INT selection ;     /* the users pick */
508     INT temp ;          /* temporary variable for atoi calc */
509     INT minlength ;     /* minimum length of a tile */
510     DOUBLE tempf ;      /* user reply transformed to float */
511     /* static INT pick_macro(); */ /* get macro from user */
512     INT pick_macro(); /* get macro from user */
513     char *reply ;       /* user reply to a querry */
514     char filename[LRECL];/* file name */
515     BOOL ok ;           /* loop until this value is true */
516     BOOL save_memory ;  /* save the memory state */
517     FILE *fp ;          /* restore file */
518     TILE_BOX *tile ;    /* traverse list of tiles */
519     /* static TILE_BOX *pick_tile() ; */ /* used to pick a tile */
520     TILE_BOX *pick_tile() ; /* used to pick a tile */
521     TILE_BOX *cur_tile ; /* currently lit up tile */
522     /* static ROW_BOX *pick_row() ; */ /* used to pick a row */
523     ROW_BOX *pick_row() ; /* used to pick a row */
524 
525     sprintf( filename, "%s.gsav", cktNameG ) ;
526     if( YfileExists( filename) ){
527 	sprintf( YmsgG, "Note: restore state file exists:%s\n\n",
528 	cktNameG ) ;
529 	M( MSG, NULL, YmsgG ) ;
530     }
531 
532     /* data might have changed so show user current config */
533     /* any function other that the draw controls need to worry about */
534     /* this concurrency problem -  show user current config */
535     setGraphicWindow() ;
536     draw_the_data() ;
537     /* use TWcheckExposure to flush exposure events since we just */
538     /* drew the data */
539     TWcheckExposure() ;
540     if(!(wait_for_userG)){
541 	if (last_chanceG) {
542 	   wait_for_userG = TRUE ;
543 	   last_chance() ;
544 	}
545 	return;
546     }
547     TWmessage( "Genrows is waiting for your response..." ) ;
548 
549     selection  = CANCEL ;
550     while( selection != CONTINUE_PGM ){ /* loop until exit */
551 	selection = TWcheckMouse() ;
552 	switch( selection ){
553 	case CANCEL:
554 	    /* do nothing */
555 	    break ;
556 	case AUTO_REDRAW_ON:
557 	    auto_drawS = TRUE ;
558 	    break ;
559 	case AUTO_REDRAW_OFF:
560 	    auto_drawS = FALSE ;
561 	    break ;
562 	case CLOSE_GRAPHICS:
563 	    if( invalidG ){
564 		TWmessage( "ERROR:you may not quit graphics since errors exist");
565 		selection = CANCEL ;
566 		break ;
567 	    } else {
568 		TWcloseGraphics() ;
569 		/* update all costs and reload cells */
570 		return ;
571 	    }
572 	case COLORS:
573 	    TWtoggleColors() ;
574 	    break ;
575 	case CONTINUE_PGM:
576 	    if( invalidG ){
577 		TWmessage( "ERROR:you may not continue since errors exist" ) ;
578 		selection = CANCEL ;
579 	    }
580 	    break ;
581 	case DUMP_GRAPHICS:
582 	    graphics_dump() ;
583 	    break ;
584 	case FULLVIEW:
585 	    TWfullView() ;
586 	    break ;
587 	case REDRAW:
588 	    draw_the_data() ;
589 	    /* use TWcheckExposure to flush exposure events since */
590 	    /* we just drew the data */
591 	    TWcheckExposure() ;
592 	    break ;
593 	case TELL_POINT:
594 	    TWmessage( "Pick a point" ) ;
595 	    TWgetPt( &x, &y ) ;
596 	    sprintf( YmsgG,"The point is (%d,%d)",x,y ) ;
597 	    TWmessage( YmsgG ) ;
598 	    break ;
599 	case TRANSLATE:
600 	    TWtranslate() ;
601 	    break ;
602 	case ZOOM:
603 	    TWzoom() ;
604 	    break ;
605 	case ALIGN_MACRO_IN_X:
606 	    if( noMacroMoveG ){
607 		no_move_message() ;
608 		break ;
609 	    }
610 	    if(!(selectMacroS = pick_macro(
611 	    "Select the reference macro by clicking any mouse button in cell center"))){
612 		break ;
613 	    }
614 	    draw_macro( selectMacroS, TWVIOLET ) ;
615 	    TWmessage( "Now pick the reference corner|center for alignment" ) ;
616 	    TWgetPt2( &x, &y ) ;
617 	    find_nearest_corner( selectMacroS, x, y, &x1, &y1 ) ;
618 	    highlight_corner( selectMacroS, x1, y1 ) ;
619 	    if(!(selectMacroS = pick_macro(
620 	    "Select the macro to be aligned by clicking any mouse button in cell center"))){
621 		break ;
622 	    }
623 	    draw_macro( selectMacroS, TWVIOLET ) ;
624 	    TWmessage( "Now pick the corner|center you wish to align" ) ;
625 	    TWgetPt2( &x, &y ) ;
626 	    find_nearest_corner( selectMacroS, x, y, &x2, &y2 ) ;
627 	    highlight_corner( selectMacroS, x2, y2 ) ;
628 	    if( x1 == x2 ){
629 		/* no work to be done */
630 		draw_the_data() ;
631 		TWcheckExposure() ;
632 		break ;
633 	    }
634 	    save_for_do( UNDO ) ;
635 	    /* calculate the new center of the macro */
636 	    x = macroArrayG[selectMacroS]->xcenter + x1 - x2 ;
637 	    y = macroArrayG[selectMacroS]->ycenter ;
638 	    update_vertices( selectMacroS, x, y ) ;
639 	    update_macro() ;
640 	    break ;
641 	case ALIGN_MACRO_IN_Y:
642 	    if( noMacroMoveG ){
643 		no_move_message() ;
644 		break ;
645 	    }
646 	    if(!(selectMacroS = pick_macro(
647 	    "Select the reference macro by clicking any mouse button in cell center"))){
648 		break ;
649 	    }
650 	    draw_macro( selectMacroS, TWVIOLET ) ;
651 	    TWmessage( "Now pick the reference corner|center for alignment" ) ;
652 	    TWgetPt2( &x, &y ) ;
653 	    find_nearest_corner( selectMacroS, x, y, &x1, &y1 ) ;
654 	    highlight_corner( selectMacroS, x1, y1 ) ;
655 	    if(!(selectMacroS = pick_macro(
656 	    "Select the macro to be aligned by clicking any mouse button in cell center"))){
657 		break ;
658 	    }
659 	    draw_macro( selectMacroS, TWVIOLET ) ;
660 	    TWmessage( "Now pick the corner|center you wish to align" ) ;
661 	    TWgetPt2( &x, &y ) ;
662 	    find_nearest_corner( selectMacroS, x, y, &x2, &y2 ) ;
663 	    highlight_corner( selectMacroS, x2, y2 ) ;
664 	    if( y1 == y2 ){
665 		/* no work to be done */
666 		draw_the_data() ;
667 		TWcheckExposure() ;
668 		break ;
669 	    }
670 	    save_for_do( UNDO ) ;
671 	    /* calculate the new center of the macro */
672 	    x = macroArrayG[selectMacroS]->xcenter ;
673 	    y = macroArrayG[selectMacroS]->ycenter + y1 - y2 ;
674 	    update_vertices( selectMacroS, x, y ) ;
675 	    update_macro() ;
676 	    break ;
677 	case ALIGN_ROWS:
678 	    save_for_do( UNDO ) ;
679 	    selected_tileS = pick_tile(
680 	    "Pick reference tile whose row separation is desired") ;
681 	    if( selected_tileS == 0 ){
682 		break ;
683 	    }
684 	    temp = selected_tileS->channel_separation ;
685 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
686 	    selected_tileS = pick_tile(
687 	    "Pick destination tile whose rows need to be aligned") ;
688 	    if( selected_tileS == 0 ){
689 		draw_the_data() ;
690 		TWcheckExposure() ;
691 		break ;
692 	    }
693 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
694 	    selected_tileS->channel_separation = temp ;
695 	    selected_tileS = NULL ;
696 	    remakerows() ;
697 	    draw_the_data() ;
698 	    TWcheckExposure() ;
699 	    save_for_do( REDO ) ;
700 	    break ;
701 	case EDIT_ROW:
702 	    if( shortRowG ){
703 		TWmessage( "You cannot edit row in KEEP SHORT ROW mode") ;
704 		break ;
705 	    }
706 	    selected_rowS = pick_row() ;
707 	    if(!(selected_rowS)){
708 		break ;
709 	    }
710 	    save_for_do( UNDO ) ;
711 	    draw_the_data() ; /* show user which row is selected */
712 	    edit_row( selected_rowS ) ;
713 	    selected_rowS = NULL ;
714 	    draw_the_data() ;
715 	    TWcheckExposure() ;
716 	    save_for_do( REDO ) ;
717 	    break ;
718 	case EDIT_MACRO:
719 	    if( noMacroMoveG ){
720 		no_move_message() ;
721 		break ;
722 	    }
723 	    if(!(selectMacroS = pick_macro(NULL) )){
724 		break ;
725 	    }
726 	    draw_macro( selectMacroS, TWVIOLET ) ;
727 	    TWmessage( "Now pick the reference corner|center" ) ;
728 	    TWgetPt2( &x, &y ) ;
729 	    find_nearest_corner( selectMacroS, x, y, &x1, &y1 ) ;
730 	    highlight_corner( selectMacroS, x1, y1 ) ;
731 	    save_for_do( UNDO ) ;
732 	    edit_macro( selectMacroS, x1, y1 ) ;
733 	    update_macro() ;
734 	    break ;
735 
736 	case EDIT_TILE:
737 	    selected_tileS = pick_tile(NULL) ;
738 	    if( selected_tileS == 0 ){
739 		break ;
740 	    }
741 	    save_for_do( UNDO ) ;
742 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
743 	    if(!(edit_tiles( selected_tileS))){
744 		/* nothing changed so don't do any work */
745 		cur_tile = selected_tileS ;
746 		selected_tileS = NULL ;/* turn off tile */
747 		draw_tile( cur_tile ) ;
748 		break ;
749 	    }
750 	    selected_tileS = NULL ;
751 	    remakerows() ;
752 	    draw_the_data() ;
753 	    TWcheckExposure() ;
754 	    save_for_do( REDO ) ;
755 	    break ;
756 	case KEEP_SHORT_ROW:
757 	    shortRowG = TRUE ;
758 	    TWmessage( "Genrows will keep short row" ) ;
759 	    remakerows() ;
760 	    draw_the_data() ;
761 	    TWcheckExposure() ;
762 	    break ;
763 	case DISCARD_SHORT_ROW:
764 	    TWmessage( "Genrows will discard short row and round up if possible" ) ;
765 	    shortRowG = FALSE ;
766 	    remakerows() ;
767 	    draw_the_data() ;
768 	    TWcheckExposure() ;
769 	    break ;
770 	case MODIFY_CORE_AREA:
771 	    if( noMacroMoveG ){
772 		no_move_message() ;
773 		break ;
774 	    }
775 	    TWmessage( "Pick or enter bottom left corner of core area:" ) ;
776 	    TWgetPt2( &x, &y ) ;
777 	    TWmessage( "Pick or enter upper right corner of core area:" ) ;
778 	    TWgetPt2( &x1, &y1 ) ;
779 	    if( x1 <= x ){
780 		TWmessage("ERROR:x coordinates invalid - ignored" ) ;
781 		break ;
782 	    }
783 	    if( y1 <= y ){
784 		TWmessage("ERROR:y coordinates invalid - ignored" ) ;
785 		break ;
786 	    }
787 	    save_for_do( UNDO ) ;
788 	    set_core( x, x1, y, y1 ) ;
789 	    /* now we need to redo all the work we have done before */
790 	    start_tileG = NULL;
791 	    recalculate(TRUE) ; /* free data */
792 	    remakerows() ;
793 	    draw_the_data() ;
794 	    get_core( &x, &y, &x1, &y1, FALSE ) ;
795 	    sprintf( YmsgG, "Core is now llx:(%d,%d) urx:(%d,%d)",
796 		x, y, x1, y1 ) ;
797 	    TWmessage( YmsgG ) ;
798 	    TWcheckExposure() ;
799 	    save_for_do( REDO ) ;
800 	    break ;
801 	case MOVE_MACRO:
802 	    if( noMacroMoveG ){
803 		no_move_message() ;
804 		break ;
805 	    }
806 	    if(!(selectMacroS = pick_macro(NULL) )){
807 		break ;
808 	    }
809 	    save_for_do( UNDO ) ;
810 	    TWmessage( "Pick or enter a reference point relative to cell center:" ) ;
811 	    if( TWgetPt2( &x, &y ) ){
812 		/* we know from keyboard */
813 		TWmessage( "Enter new position x, y<cr>:" ) ;
814 		TWgetPt( &x1, &y1 ) ;
815 		update_vertices( selectMacroS, x1 - x, y1 - y ) ;
816 	    } else {
817 		/* from mouse */
818 		TWmessage( "Pick new position with mouse" ) ;
819 		/* get old position of cell */
820 		get_global_pos( selectMacroS, &x1, &y1, &x2, &y2 ) ;
821 		TWmoveRect( &x1, &y1, &x2, &y2, x, y ) ;
822 		/* calculate new position for cell */
823 		update_vertices( selectMacroS, (x1+x2)/2,(y1+y2)/2 );
824 	    }
825 	    update_macro() ;
826 	    break ;
827 	case NUMROWS:
828 	    if( noMacroMoveG ){
829 		no_move_message() ;
830 		break ;
831 	    }
832 	    if( num_macrosG != 0 ){
833 		TWmessage( "Number of rows may not be set since macros exist") ;
834 		break ;
835 	    }
836 	    save_for_do( UNDO ) ;
837 	    do {
838 		if( reply = TWgetString("Enter the number of rows: ")){
839 		    num_rowsG = atoi(reply) ;
840 		    if( num_rowsG <= 0 ){
841 			TWmessage( "Number of row may not be <= 0" ) ;
842 			(void) sleep( (unsigned) 2) ;
843 		    }
844 		}
845 	    } while( num_rowsG <= 0 ) ;
846 	    save_memory = memoryG ;
847 	    memoryG = FALSE ;
848 	    calculate_numrows() ;
849 	    setGraphicWindow() ;
850 	    draw_the_data() ;
851 	    TWcheckExposure() ;
852 	    save_for_do( REDO ) ;
853 	    memoryG = save_memory ;
854 	    break ;
855 	case REDO:
856 	    sprintf( filename, "%s.redo", cktNameG ) ;
857 	    fp = TWOPEN( filename, "r", NOABORT ) ;
858 	    if(!fp){
859 		outm(ERRMSG,"save_state", "could not redo command" ) ;
860 		break ;
861 	    }
862 	    if(!(read_vertices(fp,FALSE))){
863 		break ;
864 	    }
865 	    start_tileG = NULL;
866 	    recalculate(FALSE) ; /* don't free data */
867 	    if( restore_state(fp) ){
868 		remakerows() ;
869 		draw_the_data() ;
870 		TWcheckExposure() ;
871 	    }
872 	    TWCLOSE( fp ) ;
873 	    break ;
874 	case RESTORE_STATE:
875 	    do {
876 		reply = TWgetString("Enter restore file name: ") ;
877 	    } while(!(reply)) ;
878 	    sprintf( filename, "%s.gsav", reply ) ;
879 	    fp = TWOPEN( filename, "r", NOABORT ) ;
880 	    if(!fp){
881 		sprintf( YmsgG, "ERROR:could not open file:%s",
882 		    filename ) ;
883 		outm(ERRMSG,"save_state", YmsgG ) ;
884 		break ;
885 	    }
886 	    if(!(read_vertices(fp,FALSE))){
887 		break ;
888 	    }
889 	    start_tileG = NULL;
890 	    recalculate(FALSE) ; /* don't free data */
891 	    if( restore_state(fp) ){
892 		remakerows() ;
893 		setGraphicWindow() ;
894 		draw_the_data() ;
895 		TWcheckExposure() ;
896 	    }
897 	    TWCLOSE( fp ) ;
898 	    break ;
899 	case SAVE_STATE:
900 	    do {
901 		reply = TWgetString("Enter file name for save file: ") ;
902 	    } while(!(reply)) ;
903 	    sprintf( filename, "%s.gsav", reply ) ;
904 	    fp = TWOPEN( filename, "w", NOABORT ) ;
905 	    if(!fp){
906 		sprintf( YmsgG, "ERROR:could not open file:%s",
907 		    filename ) ;
908 		outm(ERRMSG,"save_state", YmsgG ) ;
909 		break ;
910 	    }
911 	    save_state(fp) ;
912 	    TWCLOSE( fp ) ;
913 	    sprintf( YmsgG, "Genrows saved state:%s", reply ) ;
914 	    TWmessage( YmsgG ) ;
915 	    break ;
916 	case UNDO:
917 	    sprintf( filename, "%s.undo", cktNameG ) ;
918 	    fp = TWOPEN( filename, "r", NOABORT ) ;
919 	    if(!fp){
920 		outm(ERRMSG,"save_state", "could not undo command" ) ;
921 		break ;
922 	    }
923 	    if(!(read_vertices(fp,FALSE))){
924 		break ;
925 	    }
926 	    start_tileG = NULL;
927 	    recalculate(FALSE) ; /* don't free data */
928 	    if( restore_state(fp) ){
929 		remakerows() ;
930 		draw_the_data() ;
931 		TWcheckExposure() ;
932 	    }
933 	    TWCLOSE( fp ) ;
934 	    break ;
935 	case DIVIDE_TILE_LEFT_RIGHT:
936 	    selected_tileS = pick_tile(NULL) ;
937 	    if( selected_tileS == 0 ){
938 		break ;
939 	    }
940 	    save_for_do( UNDO ) ;
941 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
942 	    TWmessage( "Now pick the division point for the tile");
943 	    do {
944 		ok = FALSE ;
945 		TWgetPt2( &x, &y ) ;
946 		if( x<=selected_tileS->llx || x>=selected_tileS->urx ){
947 		    TWmessage("Division line outside tile - pick again" ) ;
948 		} else {
949 		    ok = TRUE ;
950 		}
951 
952 	    } while(!(ok)) ;
953 	    divide_tilelr( selected_tileS , x ) ;
954 	    renumber_tiles() ;
955 	    remakerows() ;
956 	    selected_tileS = NULL;
957 	    draw_the_data() ;
958 	    TWcheckExposure() ;
959 	    save_for_do( REDO ) ;
960 	    break ;
961 	case DIVIDE_TILE_UP_DOWN:
962 	    selected_tileS = pick_tile(NULL) ;
963 	    if( selected_tileS == 0 ){
964 		break ;
965 	    }
966 	    save_for_do( UNDO ) ;
967 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
968 	    TWmessage( "Now pick the division point for the tile");
969 	    do {
970 		ok = FALSE ;
971 		TWgetPt2( &x, &y ) ;
972 		if( y<=selected_tileS->lly || y>=selected_tileS->ury ){
973 		    TWmessage("Division line outside tile pick again" ) ;
974 		} else {
975 		    ok = TRUE ;
976 		}
977 
978 	    } while(!(ok)) ;
979 	    divide_tile( selected_tileS , y ) ;
980 	    renumber_tiles() ;
981 	    remakerows() ;
982 	    selected_tileS = NULL;
983 	    draw_the_data() ;
984 	    TWcheckExposure() ;
985 	    save_for_do( REDO ) ;
986 	    break ;
987 	case LIMIT_MERGES:
988 	    limitMergeG = TRUE ;
989 	    TWmessage( "Merges will be limited to immediate neighbors");
990 	    break ;
991 	case UNLIMIT_MERGES:
992 	    limitMergeG = FALSE ;
993 	    TWmessage( "Maximum possible merges from a tile will be performed" );
994 	    break ;
995 	case MERGE_DOWNWARD:
996 	    selected_tileS = pick_tile(NULL) ;
997 	    if( selected_tileS == 0 ){
998 		break ;
999 	    }
1000 	    save_for_do( UNDO ) ;
1001 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
1002 	    TWflushFrame() ;
1003 	    (void) sleep( (unsigned) 2) ;
1004 	    merge_downward( selected_tileS ) ;
1005 	    renumber_tiles() ;
1006 	    selected_tileS = NULL ;
1007 	    remakerows() ;
1008 	    draw_the_data() ;
1009 	    TWcheckExposure() ;
1010 	    save_for_do( REDO ) ;
1011 	    break ;
1012 	case MERGE_LEFT:
1013 	    selected_tileS = pick_tile(NULL) ;
1014 	    if( selected_tileS == 0 ){
1015 		break ;
1016 	    }
1017 	    save_for_do( UNDO ) ;
1018 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
1019 	    TWflushFrame() ;
1020 	    (void) sleep( (unsigned) 2) ;
1021 	    merge_left( selected_tileS ) ;
1022 	    renumber_tiles() ;
1023 	    selected_tileS = NULL ;
1024 	    remakerows() ;
1025 	    draw_the_data() ;
1026 	    TWcheckExposure() ;
1027 	    save_for_do( REDO ) ;
1028 	    break ;
1029 	case MERGE_RIGHT:
1030 	    selected_tileS = pick_tile(NULL) ;
1031 	    if( selected_tileS == 0 ){
1032 		break ;
1033 	    }
1034 	    save_for_do( UNDO ) ;
1035 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
1036 	    TWflushFrame() ;
1037 	    (void) sleep( (unsigned) 2) ;
1038 	    merge_right( selected_tileS ) ;
1039 	    renumber_tiles() ;
1040 	    selected_tileS = NULL ;
1041 	    remakerows() ;
1042 	    draw_the_data() ;
1043 	    TWcheckExposure() ;
1044 	    save_for_do( REDO ) ;
1045 	    break ;
1046 	case MERGE_UPWARD:
1047 	    selected_tileS = pick_tile(NULL) ;
1048 	    if( selected_tileS == 0 ){
1049 		break ;
1050 	    }
1051 	    save_for_do( UNDO ) ;
1052 	    draw_tile( selected_tileS ) ; /* show user which tile selected */
1053 	    TWflushFrame() ;
1054 	    (void) sleep( (unsigned) 2) ;
1055 	    merge_upward( selected_tileS ) ;
1056 	    renumber_tiles() ;
1057 	    selected_tileS = NULL ;
1058 	    remakerows() ;
1059 	    draw_the_data() ;
1060 	    TWcheckExposure() ;
1061 	    save_for_do( REDO ) ;
1062 	    break ;
1063 	case RESET_TILES:
1064 	    save_for_do( UNDO ) ;
1065 	    save_memory = memoryG ;
1066 	    memoryG = FALSE ;
1067 	    /* redo all the work we have done before */
1068 	    recalculate(TRUE) ; /* free data */
1069 	    remakerows() ;
1070 	    draw_the_data() ;
1071 	    TWcheckExposure() ;
1072 	    save_for_do( REDO ) ;
1073 	    memoryG = save_memory ;
1074 	    break ;
1075 	case DRAW_LABELS:
1076 	    drawLabelS = TRUE ;
1077 	    TWforceRedraw() ;
1078 	    break ;
1079 	case IGNORE_LABELS:
1080 	    drawLabelS = FALSE ;
1081 	    TWforceRedraw() ;
1082 	    break ;
1083 	case DRAW_ORIENT:
1084 	    drawOrientS = TRUE ;
1085 	    TWforceRedraw() ;
1086 	    break ;
1087 	case IGNORE_ORIENT:
1088 	    drawOrientS = FALSE ;
1089 	    TWforceRedraw() ;
1090 	    break ;
1091 	case DRAW_MACROS:
1092 	    drawMacroS = TRUE ;
1093 	    TWforceRedraw() ;
1094 	    break ;
1095 	case IGNORE_MACROS:
1096 	    drawMacroS = FALSE ;
1097 	    TWforceRedraw() ;
1098 	    break ;
1099 	case DRAW_ROWS:
1100 	    drawRowS = TRUE ;
1101 	    TWforceRedraw() ;
1102 	    break ;
1103 	case IGNORE_ROWS:
1104 	    drawRowS = FALSE ;
1105 	    TWforceRedraw() ;
1106 	    break ;
1107 	case DRAW_TILES:
1108 	    drawTileS = TRUE ;
1109 	    TWforceRedraw() ;
1110 	    break ;
1111 	case IGNORE_TILES:
1112 	    drawTileS = FALSE ;
1113 	    TWforceRedraw() ;
1114 	    break ;
1115 	case FEED_PERCENTAGE:
1116 	    save_for_do( UNDO ) ;
1117 	    ok = FALSE ;
1118 	    while(!(ok)){
1119 		if( reply = TWgetString( "Enter feed ratio in percentage [0-100]: " )){
1120 		    tempf = atof( reply ) ;
1121 		    if( tempf >= 0.0 ){
1122 			ok = TRUE ;
1123 		    }
1124 		}
1125 	    }
1126 	    set_feed_length( tempf ) ;
1127 	    remakerows() ;
1128 	    draw_the_data() ;
1129 	    TWcheckExposure() ;
1130 	    save_for_do( REDO ) ;
1131 	    break ;
1132 	case MIN_ROW_LENGTH:
1133 	    save_for_do( UNDO ) ;
1134 	    ok = FALSE ;
1135 	    while(!(ok)){
1136 		if( reply = TWgetString( "Enter minimum valid row length: " )){
1137 		    temp = atoi( reply ) ;
1138 		    if( temp >= 0 ){
1139 			ok = TRUE ;
1140 			set_minimum_length( temp ) ;
1141 		    } else {
1142 			outm( ERRMSG, "reset_min_row_length",
1143 			    "Invalid minimum row length. Must be >= 0" ) ;
1144 		    }
1145 		}
1146 	    }
1147 	    remakerows() ;
1148 	    draw_the_data() ;
1149 	    TWcheckExposure() ;
1150 	    save_for_do( REDO ) ;
1151 	    break ;
1152 	case ROW_SEPARATION:
1153 	    save_for_do( UNDO ) ;
1154 	    ok = FALSE ;
1155 	    while(!(ok)){
1156 		if( reply = TWgetString( "Enter row separation [1.0 nominal]:" )){
1157 		    tempf = atof( reply ) ;
1158 		    if( tempf > 0.0 ){
1159 			ok = TRUE ;
1160 			set_row_separation( tempf, 0.0 ) ;
1161 		    } else {
1162 			outm( ERRMSG, "reset_row_separation",
1163 			    "Invalid row separation. Must be > 0.0" ) ;
1164 		    }
1165 		}
1166 	    }
1167 	    remakerows() ;
1168 	    draw_the_data() ;
1169 	    TWcheckExposure() ;
1170 	    save_for_do( REDO ) ;
1171 	    break ;
1172 	case SET_SPACING:
1173 	    save_for_do( UNDO ) ;
1174 	    ok = FALSE ;
1175 	    while(!(ok)){
1176 		if( reply = TWgetString( "Enter spacing between row and tile edge: " )){
1177 		    temp = atoi( reply ) ;
1178 		    if( temp >= 0 ){
1179 			ok = TRUE ;
1180 			spacingG = temp ;
1181 			set_spacing() ;
1182 		    } else {
1183 			outm( ERRMSG, "set_spacing", "Invalid space. Must be >= 0" ) ;
1184 		    }
1185 		}
1186 	    }
1187 	    remakerows() ;
1188 	    draw_the_data() ;
1189 	    TWcheckExposure() ;
1190 	    save_for_do( REDO ) ;
1191 	    break ;
1192 	case MEMORY_ON:
1193 	    memoryG = TRUE ;
1194 	    TWmessage("Genrows will try to remember the last state" ) ;
1195 	    break ;
1196 	case MEMORY_OFF:
1197 	    memoryG = FALSE ;
1198 	    TWmessage("Genrow's memory has been turned off" ) ;
1199 	    break ;
1200 	} /*********************** end graphics SWITCH *****************/
1201 	if( auto_drawS && TWcheckExposure() ){
1202 	    draw_the_data() ;
1203 	}
1204 
1205     }
1206 
1207     if( shortRowG ){
1208 	TWmessage( "Now forcing removal of short row") ;
1209 	shortRowG = FALSE ;
1210 	remakerows() ;
1211 	draw_the_data() ;
1212 	if (last_chanceG) last_chance() ;
1213 
1214     }
1215 
1216 } /* end process_graphics */
1217 
last_chance()1218 static void last_chance()
1219 {
1220     INT i ; /* counter */
1221 
1222     (void) sleep( (unsigned) 1 ) ;
1223     TWmessage( "If you wish to modify the rows, you have 10 secs. to click on top menu") ;
1224     for( i = 1; i <= 10; i++ ){
1225 	(void) sleep( (unsigned) 1 ) ;
1226 	if( TWinterupt() ){
1227 	    TWmessage( "Please reconfigure the rows" ) ;
1228 	    (void) sleep( (unsigned) 1 ) ;
1229 	    process_graphics() ;
1230 	    break ;
1231 	}
1232     }
1233 } /* end last_chance */
1234 
no_move_message()1235 static void no_move_message()
1236 {
1237     TWmessage("Macro moves/core changes not allowed in partitioning");
1238 }
1239 
save_for_do(save)1240 static void save_for_do( save )
1241 INT save ;
1242 {
1243     char filename[LRECL] ;
1244     FILE *fp ;
1245 
1246     if( save == UNDO ){
1247 	sprintf( filename, "%s.undo", cktNameG ) ;
1248     } else if( save == REDO ){
1249 	sprintf( filename, "%s.redo", cktNameG ) ;
1250     }
1251     fp = TWOPEN( filename, "w", ABORT ) ;
1252     save_state(fp) ;
1253     TWCLOSE( fp ) ;
1254 } /* end undo */
1255 
update_macro()1256 static void update_macro()
1257 {
1258     char filename[LRECL] ;
1259     FILE *fp ;
1260 
1261     /* this is the easiest way to redo entire algorithm from scratch */
1262     sprintf( filename, "%s.tmp", cktNameG ) ;
1263     fp = TWOPEN( filename, "w", ABORT ) ;
1264     save_state(fp) ;
1265     TWCLOSE( fp ) ;
1266 
1267     fp = TWOPEN( filename, "r", ABORT ) ;
1268     if(!(read_vertices(fp,FALSE))){
1269 	return ;
1270     }
1271     start_tileG = NULL;
1272     selectMacroS = 0 ;
1273     recalculate(FALSE) ; /* don't free data */
1274     remakerows() ;
1275     draw_the_data() ;
1276     TWcheckExposure() ;
1277     save_for_do( REDO ) ;
1278 } /* update_macro */
1279 
1280 /* dumps the data to a file for future study */
graphics_dump()1281 static void graphics_dump()
1282 {
1283     /* now change mode to dump to file */
1284     TWsetMode(1) ;
1285     TWsetFrame(0) ;
1286     /* dump the data to a file now instead of screen */
1287     draw_the_data() ;
1288     /* restore the state to previous condition and set draw to screen */
1289     TWsetMode(0) ;
1290 }
1291 
1292 
1293 /* find the macro in question */
pick_macro(twmsg)1294 static INT pick_macro( twmsg )
1295 char *twmsg ;
1296 {
1297 
1298     INT i ;
1299     INT match_count ;        /* keep track of all cells that match */
1300     INT x, y ;               /* coordinates picked by user */
1301     INT cell ;               /* selected cell */
1302     INT l, r, b, t ;         /* cell sides */
1303 
1304     if( twmsg ){
1305 	TWmessage( twmsg ) ;
1306     } else {
1307 	TWmessage("Pick cell by clicking any mouse button at center of cell");
1308     }
1309     TWgetPt( &x, &y ) ;
1310     /* look thru all cells O(numcells) algorithm */
1311     match_count = 0 ;
1312     for( i = 1 ; i <= num_macrosG; i++ ){
1313 	get_global_pos( i, &l, &b, &r, &t ) ;
1314 	/* see if cell boundary contains this point */
1315 	if( x >= l && x <= r ){
1316 	    if( y >= b && y <= t ){
1317 		selectMacroS = i ;
1318 		match_count++ ;
1319 	    }
1320 	}
1321     } /* end loop */
1322 
1323     if( match_count == 0 ){
1324 	TWmessage( "No cell selected" ) ;
1325 	if( selectMacroS ){  /* user didn't like any options */
1326 	    selectMacroS = 0 ;
1327 	    /* draw the data with highlight off
1328 		draw_the_data() ;
1329 		TWcheckExposure() ;
1330 	    */
1331 	}
1332 	return( 0 ) ;
1333     } else if( match_count == 1 ){
1334 	/* draw the data with highlight on */
1335 	draw_macro( selectMacroS, TWVIOLET ) ;
1336 	TWcheckExposure() ;
1337 	sprintf( YmsgG, "Selected macro:%d", selectMacroS ) ;
1338 	TWmessage( YmsgG ) ;
1339 	return( selectMacroS ) ;
1340     } else {
1341 	/* more than one match */
1342 	TWmessage( "More than one match.  Choose correct cell" ) ;
1343 	(void) sleep( (unsigned) 2 ) ;
1344 	while( TRUE ){
1345 	    for( i = 1 ; i <= num_macrosG; i++ ){
1346 		get_global_pos( i, &l, &b, &r, &t ) ;
1347 		/* see if cell boundary contains this point */
1348 		if( x >= l && x <= r ){
1349 		    if( y >= b && y <= t ){
1350 			selectMacroS = i ;
1351 			draw_the_data() ;
1352 			TWcheckExposure() ;
1353 
1354 			/* give directions */
1355 			sprintf( YmsgG, "Selected cell:%d",
1356 			    selectMacroS ) ;
1357 			TWmessage( YmsgG ) ;
1358 			(void) sleep( (unsigned) 2 ) ;
1359 			sprintf( YmsgG,"%s","If correct, enter <cr>. Otherwise ") ;
1360 			strcat( YmsgG,
1361 			    "enter n<cr> for next cell: ") ;
1362 			/* look for empty string - means we are satisfied */
1363 			if(!(TWgetString(YmsgG))){
1364 			    return( selectMacroS ) ;
1365 			}
1366 		    }
1367 		}
1368 	    } /* end loop */
1369 	}
1370     }
1371 
1372 } /* end pick_macro */
1373 
pick_tile(pmsg)1374 static TILE_BOX *pick_tile( pmsg )
1375 char *pmsg ;
1376 {
1377     INT x, y ;            /* the user's pick points */
1378     TILE_BOX *tile ;      /* the current tile */
1379 
1380     if( pmsg ){
1381 	TWmessage( pmsg ) ;
1382     } else {
1383 	TWmessage( "Select tile to edit by using mouse") ;
1384     }
1385     TWgetPt( &x, &y ) ;
1386     for( tile=tile_listG;tile;tile=tile->next ){
1387 	if( tile->llx <= x && x <= tile->urx &&
1388 	    tile->lly <= y && y <= tile->ury ){
1389 	    /* we found a tile return */
1390 	    return(tile) ;
1391 	}
1392     }
1393     /* if we get here we didn't find a tile */
1394     TWmessage( "No tile selected") ;
1395     return( NULL ) ;
1396 
1397 } /* end pick_tile */
1398 
pick_row()1399 static ROW_BOX *pick_row()
1400 {
1401     INT x, y ;            /* the user's pick points */
1402     ROW_BOX  *rowptr  ;     /* current row being output */
1403     ROW_BOX  *segment ;     /* current segment being output */
1404     ROW_BOX  *get_rowptr(); /* get data structure */
1405 
1406     TWmessage( "Select row to edit by using mouse") ;
1407     TWgetPt( &x, &y ) ;
1408     for( rowptr=get_rowptr();rowptr;rowptr=rowptr->next_row ){
1409 
1410 	if( rowptr->next_segment ){
1411 	    /* means we have more that one segment to row */
1412 	    for( segment=rowptr;segment;segment=segment->next_segment){
1413 		if( segment->llx <= x && x <= segment->urx &&
1414 		    segment->lly <= y && y <= segment->ury ){
1415 		    /* we found a tile return */
1416 		    return(segment) ;
1417 		}
1418 
1419 	    } /* end for loop */
1420 
1421 	} else {
1422 	    if( rowptr->llx <= x && x <= rowptr->urx &&
1423 		rowptr->lly <= y && y <= rowptr->ury ){
1424 		/* we found a tile return */
1425 		return(rowptr) ;
1426 	    }
1427 	}
1428     } /* end for loop */
1429     /* if we get here we didn't find a row */
1430     TWmessage( "No row selected") ;
1431     return( NULL ) ;
1432 } /* end pick row */
1433 
1434 
1435 #define TILEF        3
1436 #define LEFTF        4
1437 #define BOTF         LEFTF+1
1438 #define RITEF        LEFTF+2
1439 #define TOPF         LEFTF+3
1440 #define LEGALF       8
1441 #define LEGALCASE    LEGALF+1
1442 #define ILLEGALCASE  LEGALF+2
1443 #define ROWF         12
1444 #define MAXROWF      14
1445 #define NUMROWF      16
1446 #define MINF         21
1447 #define STARTF       23
1448 #define MAXF         25
1449 #define SEPF         27
1450 #define CLASSF       29
1451 #define FORCEF       17
1452 #define FORCECASE    FORCEF+1
1453 #define NOFORCECASE  FORCEF+2
1454 #define MIRRORF      30
1455 #define MIRRORCASE   MIRRORF+1
1456 #define NOMIRRORCASE MIRRORF+2
1457 #define FWIDTH       15   /* field width */
1458 
get_row_height(answer)1459 static INT get_row_height( answer )
1460 TWDRETURNPTR answer ;  /* return from user */
1461 {
1462     INT height ;
1463 
1464     height = atoi( answer[ROWF].string ) ;
1465     if( height <= 0 ){
1466 	outm( ERRMSG, "edit_tile",
1467 	"Invalid row height.  Must be greater than zero" ) ;
1468 	return( 1 ) ; ;
1469     }
1470     return( height ) ;
1471 } /* end get_row_height */
1472 
get_row_sep(answer)1473 static INT get_row_sep( answer )
1474 TWDRETURNPTR answer ;  /* return from user */
1475 {
1476     INT sep ;
1477 
1478     sep = atoi( answer[SEPF].string ) ;
1479     if( sep <= 0 ){
1480 	outm( ERRMSG, "edit_tile",
1481 	"Invalid row separation.  Must be greater than zero" ) ;
1482 	return(1) ;
1483     }
1484     if( sep > selected_tileS->ury - selected_tileS->lly ){
1485 	outm( ERRMSG, "edit_tile",
1486 	"Invalid row separation.  Must be less than tile y dimension" ) ;
1487 	return(1) ;
1488     }
1489     return( sep ) ;
1490 } /* end get_row_sep */
1491 
get_maxrows(answer)1492 static INT get_maxrows( answer )
1493 TWDRETURNPTR answer ;  /* return from user */
1494 {
1495     INT maxrows ;
1496 
1497     /* means the user change the field */
1498     maxrows = atoi( answer[MAXROWF].string ) ;
1499     if( maxrows < 0 ){
1500 	outm( ERRMSG, "edit_tile",
1501 	"Invalid number of rows.  Must be non-negative" ) ;
1502 	return( 0 ) ;
1503     }
1504     return( maxrows ) ;
1505 } /* end get_maxrows */
1506 
update_tile_data_wrap(answer,field)1507 static void update_tile_data_wrap( answer, field )
1508 TWDRETURNPTR answer ;  /* return from user */
1509 INT field ;
1510 {
1511     INT sep ;
1512     INT rows ;
1513     INT maxrows ;
1514     INT height ;
1515     INT row_height ;
1516 
1517     switch( field ){
1518     case FORCECASE:
1519 	break ;
1520     case NOFORCECASE:
1521 	sprintf( answer[STARTF].string, "%d", selected_tileS->llx + spacingG ) ;
1522 	sprintf( answer[MAXF].string, "%d", selected_tileS->urx - spacingG ) ;
1523 	answer[STARTF].bool = TRUE ;
1524 	answer[MAXF].bool = TRUE ;
1525 	break ;
1526     case ROWF:
1527 	row_height = get_row_height( answer ) ;
1528 	sep = get_row_sep( answer ) ;
1529 	height = selected_tileS->ury - selected_tileS->lly ;
1530 	maxrows = ( height ) / (row_height + sep ) ;
1531 	sprintf( answer[MAXROWF].string, "%d", maxrows ) ;
1532 	rows = atoi( answer[NUMROWF].string ) ;
1533 	if( rows < 0 ){
1534 	    outm( ERRMSG, "edit_tile",
1535 	    "Invalid number of rows.  Must be non-negative" ) ;
1536 	    return ;
1537 	}
1538 	if( rows > maxrows ){
1539 	    sprintf( answer[NUMROWF].string, "%d", maxrows ) ;
1540 	}
1541 	break ;
1542     case MAXROWF:
1543 	/* means the user change the field */
1544 	maxrows = get_maxrows( answer ) ;
1545 	row_height = get_row_height( answer ) ;
1546 	/* now calculate the channel separation for this tile */
1547 	height = selected_tileS->ury - selected_tileS->lly ;
1548 	sep =  (height - maxrows * row_height) / (maxrows) ;
1549 	if( sep <= 0 ){
1550 	    /* calculate the maximum amount of rows if sep = 1 */
1551 	    sep = 1 ;
1552 	    maxrows = ( height ) / (row_height + sep ) ;
1553 	    outm( WARNMSG, "edit_tile",
1554 	    "Exceeded maximum number of rows.  Set to maximum." ) ;
1555 	}
1556 	sprintf( answer[NUMROWF].string, "%d", maxrows ) ;
1557 	sprintf( answer[SEPF].string, "%d", sep ) ;
1558 	break ;
1559     case NUMROWF:
1560 	maxrows = get_maxrows( answer ) ;
1561 	/* means the user changed the field */
1562 	rows = atoi( answer[NUMROWF].string ) ;
1563 	if( rows < 0 ){
1564 	    outm( ERRMSG, "edit_tile",
1565 	    "Invalid number of rows.  Must be non-negative" ) ;
1566 	    return ;
1567 	}
1568 	if( rows > maxrows ){
1569 	    outm( WARNMSG, "edit_tile",
1570 	    "Exceeded maximum number of rows.  Set to maximum." ) ;
1571 	    sprintf( answer[NUMROWF].string, "%d", maxrows ) ;
1572 	}
1573 	break ;
1574     case MINF:
1575 	break ;
1576     case SEPF:
1577 	sep = get_row_sep( answer ) ;
1578 	row_height = get_row_height( answer ) ;
1579 	height = selected_tileS->ury - selected_tileS->lly ;
1580 	rows = ( height ) / (row_height + sep ) ;
1581 	sprintf( answer[MAXROWF].string, "%d", rows ) ;
1582 	if( rows > selected_tileS->numrows ){
1583 	    sprintf( answer[NUMROWF].string, "%d", rows ) ;
1584 	}
1585 	break ;
1586     } /* end switch */
1587 }
1588 
update_tile_data(TWDRETURNPTR answer,INT field)1589 static INT update_tile_data(TWDRETURNPTR answer, INT field )
1590 {
1591     update_tile_data_wrap( answer, field );
1592     return 0; // return value is ignored
1593 }
1594 
edit_tiles(tile)1595 static BOOL edit_tiles( tile )
1596 TILE_BOX *tile ;
1597  {
1598     INT  temp ;            /* temporary answer from user */
1599     INT  sep ;             /* channel separation */
1600     INT  rows ;            /* number of rows */
1601     INT  height ;          /* tile height */
1602     INT  max_rows ;        /* maximum number of rows */
1603     char tileName[FWIDTH]; /* a scratch buffer for tile name */
1604     char left[FWIDTH];     /* a scratch buffer for left tile side */
1605     char right[FWIDTH];    /* a scratch buffer for right tile side */
1606     char class[FWIDTH];    /* a scratch buffer for the class */
1607     char top[FWIDTH];      /* a scratch buffer for top tile side */
1608     char bottom[FWIDTH];   /* a scratch buffer for bottom tile side */
1609     char numrows[FWIDTH];  /* a scratch buffer for number of rows */
1610     char maxrows[FWIDTH];  /* a scratch buffer for number of rows */
1611     char rowHeight[FWIDTH];/* a scratch buffer for row height */
1612     char minlength[FWIDTH];/* a scratch buffer for minimum length of row */
1613     char maxlength[FWIDTH];/* a scratch buffer for maximum length of row */
1614     char separation[FWIDTH];/* a scratch buffer for row separation */
1615     char startrow[FWIDTH]; /* a scratch buffer for row separation */
1616     BOOL old_force ;       /* keep track of change */
1617     TWDRETURNPTR answer ;  /* return from user */
1618 
1619     TWmessage( "Edit Tile" ) ;
1620 
1621 #ifdef DEVELOPDIALOG
1622     dialogS = TWread_dialog( "genrows.dialog" ) ;
1623     if( !(dialogS) ){
1624 	return ; /* avoid crashes */
1625     }
1626 #endif
1627 
1628 
1629     /* now initialize the fields to user data */
1630     sprintf( tileName,  "Tile  : %d", tile->name ) ;
1631     dialogS[TILEF].string = tileName ;
1632     dialogS[TILEF].len = strlen( tileName ) ;
1633     sprintf( left,  "Left  : %d", tile->llx ) ;
1634     dialogS[LEFTF].string = left ;
1635     dialogS[LEFTF].len = strlen( left ) ;
1636     sprintf( bottom,"Bottom: %d", tile->lly ) ;
1637     dialogS[BOTF].string = bottom ;
1638     dialogS[BOTF].len = strlen( bottom ) ;
1639     sprintf( right, "Right : %d", tile->urx ) ;
1640     dialogS[RITEF].string = right ;
1641     dialogS[RITEF].len = strlen( right ) ;
1642     sprintf( top,   "Top   : %d", tile->ury ) ;
1643     dialogS[TOPF].string = top ;
1644     dialogS[TOPF].len = strlen( top ) ;
1645     /* set legality of tile */
1646     if( tile->illegal ){
1647 	dialogS[LEGALF].group = ILLEGALCASE ;
1648     } else {
1649 	dialogS[LEGALF].group = LEGALCASE ;
1650     }
1651     /* Now set the row height fields */
1652     sprintf( rowHeight,   "%d", tile->actual_row_height ) ;
1653     dialogS[ROWF].string = rowHeight ;
1654     /* Now set the number of rows */
1655     height = tile->ury - tile->lly ;
1656     sep = tile->channel_separation ;
1657     max_rows = ( height ) / (tile->actual_row_height + sep ) ;
1658     if( tile->numrows > max_rows ){
1659 	max_rows = tile->numrows ;
1660     }
1661     sprintf( maxrows, "%d", max_rows ) ;
1662     dialogS[MAXROWF].string = maxrows ;
1663     sprintf( numrows,   "%d", tile->numrows ) ;
1664     dialogS[NUMROWF].string = numrows ;
1665     /* Now set the min length of row */
1666     sprintf( minlength,   "%d", tile->min_length ) ;
1667     dialogS[MINF].string = minlength ;
1668     /* Now set the start of the row */
1669     sprintf( startrow,   "%d", tile->llx + tile->row_start ) ;
1670     dialogS[STARTF].string = startrow ;
1671     /* Now set the max length of row */
1672     sprintf( maxlength,   "%d",
1673 	tile->llx + tile->row_start + tile->max_length ) ;
1674     dialogS[MAXF].string = maxlength ;
1675     /* Now set the chan separation of row */
1676     sprintf( separation,   "%d", tile->channel_separation ) ;
1677     dialogS[SEPF].string = separation ;
1678     sprintf( class,  "%d", tile->class ) ;
1679     dialogS[CLASSF].string = class ;
1680     if( tile->force ){
1681 	dialogS[FORCEF].group = FORCECASE ;
1682     } else {
1683 	dialogS[FORCEF].group = NOFORCECASE ;
1684     }
1685     old_force = tile->force ;
1686     /* set mirror option of tile */
1687     if( tile->mirror ){
1688 	dialogS[MIRRORF].group = MIRRORCASE ;
1689     } else {
1690 	dialogS[MIRRORF].group = NOMIRRORCASE ;
1691     }
1692 
1693     /* initialization complete */
1694 
1695     if( answer = TWdialog( dialogS, "genrows", update_tile_data ) ){
1696 	/* must be the number of the case field */
1697 	if( answer[LEGALCASE].bool ){
1698 	    /* the tile is legal */
1699 	    tile->illegal = FALSE ;
1700 	} else if( answer[ILLEGALCASE].bool ){
1701 	    tile->illegal = TRUE ;
1702 	}
1703 	if( answer[MIRRORCASE].bool ){
1704 	    tile->mirror = TRUE ;
1705 	} else if( answer[NOMIRRORCASE].bool ){
1706 	    tile->mirror = FALSE ;
1707 	}
1708 	if( answer[FORCECASE].bool ){
1709 	    tile->force = TRUE ;
1710 	} else if( answer[NOFORCECASE].bool ){
1711 	    tile->force = FALSE ;
1712 	    if( old_force != tile->force ){
1713 		/* only do this on a change */
1714 		tile->row_start = spacingG ;
1715 		tile->max_length = tile->urx - tile->llx - 2 * spacingG ;
1716 	    }
1717 	}
1718 	if( answer[ROWF].bool ){
1719 	    /* means the user change the field */
1720 	    temp = get_row_height( answer ) ;
1721 	    if( temp <= 0 ){
1722 		return FALSE;
1723 	    }
1724 	    tile->actual_row_height = temp ;
1725 	}
1726 	if( answer[MAXROWF].bool ){
1727 	    /* means the user change the field */
1728 	    rows = atoi( answer[MAXROWF].string ) ;
1729 	    if( rows < 0 ){
1730 		outm( ERRMSG, "edit_tile",
1731 		"Invalid number of rows.  Must be non-negative" ) ;
1732 		return FALSE;
1733 	    }
1734 	    /* now calculate the channel separation for this tile */
1735 	    height = tile->ury - tile->lly ;
1736 	    sep =  (height - rows * tile->actual_row_height) / (rows) ;
1737 	    if( sep <= 0 ){
1738 		/* calculate the maximum amount of rows if sep = 1 */
1739 		sep = 1 ;
1740 		rows = ( height ) / (tile->actual_row_height + sep ) ;
1741 		outm( WARNMSG, "edit_tile",
1742 		"Exceeded maximum number of rows.  Set to maximum." ) ;
1743 	    }
1744 	    tile->numrows = rows ;
1745 	    tile->channel_separation = sep ;
1746 	}
1747 	if( answer[NUMROWF].bool ){
1748 	    /* means the user change the field */
1749 	    rows = atoi( answer[NUMROWF].string ) ;
1750 	    if( rows < 0 ){
1751 		outm( ERRMSG, "edit_tile",
1752 		"Invalid number of rows.  Must be non-negative" ) ;
1753 		return FALSE;
1754 	    }
1755 	    /* now calculate the channel separation for this tile */
1756 	    height = tile->ury - tile->lly ;
1757 	    sep = tile->channel_separation ;
1758 	    max_rows = ( height ) / (tile->actual_row_height + sep ) ;
1759 
1760 	    if( rows <= max_rows ){
1761 		tile->numrows = rows ;
1762 	    } else {
1763 		outm( WARNMSG, "edit_tile",
1764 		"Exceeded maximum number of rows.  Set to maximum." ) ;
1765 		tile->numrows = max_rows ;
1766 	    }
1767 	}
1768 	if( answer[MINF].bool ){
1769 	    /* means the user change the field */
1770 	    temp = atoi( answer[MINF].string ) ;
1771 	    if( temp <= 0 ){
1772 		outm( ERRMSG, "edit_tile",
1773 		"Invalid minimum length.  Must be greater than zero" ) ;
1774 		return FALSE;
1775 	    }
1776 	    tile->min_length = temp ;
1777 	}
1778 	if( answer[MAXF].bool ){
1779 	    /* means the user change the field */
1780 	    temp = atoi( answer[MAXF].string ) ;
1781 	    if( temp < tile->llx  ){
1782 		outm( ERRMSG, "edit_tile",
1783 		"Invalid end of row.  Must be greater than tile left" );
1784 		return FALSE;
1785 	    }
1786 	    if( temp > tile->urx ){
1787 		outm( ERRMSG, "edit_tile",
1788 		"Invalid end of row.  Must be less than tile right" ) ;
1789 		return FALSE;
1790 	    }
1791 	    tile->max_length = temp - tile->llx - tile->row_start ;
1792 	}
1793 	if( answer[STARTF].bool ){
1794 	    /* means the user change the field */
1795 	    temp = atoi( answer[STARTF].string ) ;
1796 	    if( temp < tile->llx ){
1797 		outm( ERRMSG, "edit_tile",
1798 		"Invalid start of row.  Must be greater than tile left") ;
1799 		return FALSE;
1800 	    }
1801 	    if( temp > tile->urx ){
1802 		outm( ERRMSG, "edit_tile",
1803 		"Invalid start of row.  Row must start before end of tile" ) ;
1804 		return FALSE;
1805 	    }
1806 	    tile->row_start = temp - tile->llx ;
1807 	    /* now modify the width of the tile accordingly */
1808 	    if(  tile->llx + tile->row_start + tile->max_length >
1809 						    tile->urx - 2*spacingG ){
1810 		tile->max_length =
1811 		    tile->urx - tile->llx - tile->row_start - 2*spacingG ;
1812 		outm( MSG, "edit_tile",
1813 		"Note:resetting maximum length of row." ) ;
1814 	    }
1815 	}
1816 	if( answer[SEPF].bool ){
1817 	    /* means the user change the field */
1818 	    tile->channel_separation = get_row_sep( answer ) ;
1819 	}
1820 	if( answer[CLASSF].bool ){
1821 	    /* means the user change the field */
1822 	    temp = atoi( answer[CLASSF].string ) ;
1823 	    if( temp <= 0 ){
1824 		outm( ERRMSG, "edit_tile",
1825 		    "ERROR:Invalid class.  Must be greater than zero" ) ;
1826 		return FALSE;
1827 	    }
1828 	    tile->class = temp ;
1829 	}
1830 	return( TRUE ) ;
1831     } else {
1832 	return( FALSE ) ;
1833     }
1834 } /* end edit_tiles */
1835 
1836 
edit_row(rowptr)1837 void edit_row( rowptr )
1838 ROW_BOX *rowptr ;
1839 {
1840 
1841 #define LEFT_F         3
1842 #define BOT_F          LEFT_F+1
1843 #define RITE_F         LEFT_F+2
1844 #define TOP_F          LEFT_F+3
1845 #define CLASS_F        8
1846 #define MIRROR_F       9
1847 #define MIRRORCASE_F   MIRROR_F+1
1848 #define NOMIRRORCASE_F MIRROR_F+2
1849 
1850 
1851     char left[FWIDTH];     /* a scratch buffer for left tile side */
1852     char right[FWIDTH];    /* a scratch buffer for right tile side */
1853     char top[FWIDTH];      /* a scratch buffer for top tile side */
1854     char bottom[FWIDTH];   /* a scratch buffer for bottom tile side */
1855     char class[FWIDTH];    /* a scratch buffer for the class */
1856     INT  temp ;            /* calculate the class */
1857     TWDRETURNPTR answer ;  /* return from user */
1858 
1859     TWmessage( "Edit Row" ) ;
1860 
1861 #ifdef DEVELOPDIALOG
1862     row_dialogS = TWread_dialog( "row.dialog" ) ;
1863     if( !(row_dialogS) ){
1864 	return ; /* avoid crashes */
1865     }
1866 #endif
1867     /* now initialize the fields to user data */
1868     sprintf( left,  "Left  : %d", rowptr->llx ) ;
1869     row_dialogS[LEFT_F].string = left ;
1870     row_dialogS[LEFT_F].len = strlen(left) ;
1871     sprintf( bottom,"Bottom: %d", rowptr->lly ) ;
1872     row_dialogS[BOT_F].string = bottom ;
1873     row_dialogS[BOT_F].len = strlen(bottom) ;
1874     sprintf( right, "Right : %d", rowptr->urx ) ;
1875     row_dialogS[RITE_F].string = right ;
1876     row_dialogS[RITE_F].len = strlen(right) ;
1877     sprintf( top,   "Top   : %d", rowptr->ury ) ;
1878     row_dialogS[TOP_F].string = top ;
1879     row_dialogS[TOP_F].len = strlen(top) ;
1880     /* Now set the class field */
1881     if( rowptr->class ){
1882 	sprintf( class, "%d", rowptr->class ) ;
1883     } else {
1884 	sprintf( class, "1" ) ;
1885     }
1886     row_dialogS[CLASS_F].string = class ;
1887     /* set mirror option of tile */
1888     if( rowptr->mirror ){
1889 	row_dialogS[MIRROR_F].group = MIRRORCASE_F ;
1890     } else {
1891 	row_dialogS[MIRROR_F].group = NOMIRRORCASE_F ;
1892     }
1893 
1894     /* Now call the dialog box */
1895     if( answer = TWdialog( row_dialogS, "row", NULL ) ){
1896 	if( answer[CLASS_F].bool ){
1897 	    /* means the user change the field */
1898 	    temp = atoi( answer[CLASS_F].string ) ;
1899 	    if( temp <= 0 ){
1900 		TWmessage( "ERROR:Invalid class.  Must be greater than zero" ) ;
1901 		return ;
1902 	    }
1903 	    rowptr->class = temp ;
1904 	}
1905 	if( answer[MIRRORCASE_F].bool ){
1906 	    rowptr->mirror = TRUE ;
1907 	} else if( answer[NOMIRRORCASE_F].bool ){
1908 	    rowptr->mirror = FALSE ;
1909 	}
1910     }
1911 } /* end edit_row */
1912 
1913 /* the MACRO DIALOG definitions */
1914 #define XPOSF        6
1915 #define YPOSF        8
1916 #define DELTAXF      10
1917 #define DELTAYF      12
1918 #define ORIENTF      13
1919 #define ORIENTBASE   14
1920 
update_macro_data(answer,field)1921 static INT update_macro_data( answer, field )
1922 TWDRETURNPTR answer ;  /* return from user */
1923 INT field ;
1924 {
1925     INT pos ;
1926     INT deltax, deltay ;
1927     INT orient ;
1928 
1929     deltax = 0 ;
1930     deltay = 0 ;
1931     switch( field ){
1932     case DELTAXF:
1933 	deltax = atoi( answer[DELTAXF].string ) ;
1934 	break ;
1935     case DELTAYF:
1936 	deltay = atoi( answer[DELTAYF].string ) ;
1937 	break ;
1938     case ORIENTBASE:
1939     case ORIENTBASE+1:
1940     case ORIENTBASE+2:
1941     case ORIENTBASE+3:
1942     case ORIENTBASE+4:
1943     case ORIENTBASE+5:
1944     case ORIENTBASE+6:
1945     case ORIENTBASE+7:
1946 #ifdef TI
1947 	orient = ice2tw(field-ORIENTBASE+1) ;
1948 #else
1949 	orient = field - ORIENTBASE ;
1950 #endif
1951 	/* order is important here */
1952 	rotate_vertices( macroArrayG[selectMacroS], orient ) ;
1953 	macroArrayG[selectMacroS]->orient = orient ;
1954 	TWforceRedraw() ;
1955 	break ;
1956     } /* end switch */
1957 
1958     if( deltax == 0 && deltay == 0 ){
1959 	return 0; /* no work to do */
1960     }
1961     /* else update the cooridates positions */
1962     if( deltax != 0 ){
1963 	pos = atoi( answer[XPOSF].string ) ;
1964 	pos += deltax ;
1965 	sprintf( answer[XPOSF].string, "%d", pos ) ;
1966 	answer[XPOSF].bool = TRUE ;
1967 	sprintf( answer[DELTAXF].string, "0" ) ;
1968     }
1969     if( deltay != 0 ){
1970 	pos = atoi( answer[YPOSF].string ) ;
1971 	pos += deltay ;
1972 	sprintf( answer[YPOSF].string, "%d", pos ) ;
1973 	answer[YPOSF].bool = TRUE ;
1974 	sprintf( answer[DELTAYF].string, "0" ) ;
1975     }
1976 } /* end update_macro_data */
1977 
edit_macro(int macro,int xoff,int yoff)1978 static void edit_macro(int macro,int xoff, int yoff )
1979 {
1980     TWDRETURNPTR answer ;  /* return from user */
1981     MACROPTR mptr ;        /* current macro information */
1982     char xpos[FWIDTH];     /* a scratch buffer for xpos */
1983     char ypos[FWIDTH];     /* a scratch buffer for ypos */
1984     char deltax[FWIDTH];   /* a scratch buffer for deltax */
1985     char deltay[FWIDTH];   /* a scratch buffer for deltay */
1986     INT x, y ;             /* new coordinates */
1987     INT pos ;              /* user's input */
1988     INT old_orient ;       /* put orientation back if necessary */
1989 
1990 #ifdef DEVELOPDIALOG
1991     macro_dialogS = TWread_dialog( "macro.dialog" ) ;
1992     if( !(macro_dialogS) ){
1993 	return ; /* avoid crashes */
1994     }
1995 #endif
1996     mptr = macroArrayG[macro] ;
1997     /* now initialize the fields to user data */
1998     sprintf( xpos,  "%d", xoff ) ;
1999     macro_dialogS[XPOSF].string = xpos ;
2000     sprintf( ypos, "%d", yoff ) ;
2001     macro_dialogS[YPOSF].string = ypos ;
2002     sprintf( deltax,"0" ) ;
2003     macro_dialogS[DELTAXF].string = deltax ;
2004     sprintf( deltay,"0" ) ;
2005     macro_dialogS[DELTAYF].string = deltay ;
2006 
2007     /* set orientation */
2008 #ifdef TI
2009     macro_dialogS[ORIENTF].group = tw2ice(mptr->orient) + ORIENTBASE - 1 ;
2010 #else
2011     macro_dialogS[ORIENTF].group = mptr->orient + ORIENTBASE ;
2012 #endif /* TI */
2013 
2014     old_orient = macroArrayG[selectMacroS]->orient ;
2015 
2016     if( answer = TWdialog( macro_dialogS, "macro", update_macro_data )){
2017 	if( answer[XPOSF].bool ){
2018 	    /* means the user change the field */
2019 	    pos = atoi( answer[XPOSF].string ) ;
2020 	    /* calculate the new center of the macro */
2021 	    x = mptr->xcenter + pos - xoff ;
2022 	} else {
2023 	    x = mptr->xcenter ;
2024 	}
2025 	if( answer[YPOSF].bool ){
2026 	    /* means the user change the field */
2027 	    pos = atoi( answer[YPOSF].string ) ;
2028 	    /* calculate the new center of the macro */
2029 	    y = mptr->ycenter + pos - yoff ;
2030 	} else {
2031 	    y = mptr->ycenter ;
2032 	}
2033 	update_vertices( selectMacroS, x, y ) ;
2034     } else if( macroArrayG[selectMacroS]->orient != old_orient ){
2035 	/* order is important here */
2036 	rotate_vertices( macroArrayG[selectMacroS], old_orient ) ;
2037 	macroArrayG[selectMacroS]->orient = old_orient ;
2038 	TWforceRedraw() ;
2039     }
2040 
2041 } /* end edit_macro */
2042 
2043 
get_global_pos(INT macro,INT * l,INT * b,INT * r,INT * t)2044 void get_global_pos(INT macro, INT *l, INT *b, INT *r, INT *t )
2045 {
2046 
2047     MACROPTR mptr ;
2048 
2049     mptr = macroArrayG[macro] ;
2050     *l = mptr->left + mptr->xcenter ;
2051     *r = mptr->right + mptr->xcenter ;
2052     *b = mptr->bottom + mptr->ycenter ;
2053     *t = mptr->top + mptr->ycenter ;
2054 } /* end get_global_pos */
2055 
update_vertices(macro,newxcenter,newycenter)2056 static void update_vertices( macro, newxcenter, newycenter )
2057 INT macro, newxcenter, newycenter ;
2058 {
2059     INT j ;
2060     INT deltaX ;
2061     INT deltaY ;
2062     MACROPTR mptr ;
2063     VERTEXPTR vptr ;
2064 
2065     mptr = macroArrayG[macro] ;
2066     deltaX = newxcenter - mptr->xcenter ;
2067     deltaY = newycenter - mptr->ycenter ;
2068     for( j = 0; j < mptr->num_vertices; j++ ){
2069 	vptr = mptr->vertices[j] ;
2070 	vptr->x += deltaX ;
2071 	vptr->y += deltaY ;
2072     }
2073     mptr->xcenter = newxcenter ;
2074     mptr->ycenter = newycenter ;
2075 } /* end update_vertices */
2076 
rotate_vertices(mptr,orient)2077 static void rotate_vertices( mptr, orient )
2078 MACROPTR mptr ;
2079 INT orient ;
2080 {
2081     INT j, p ;
2082     INT x, y ;
2083     INT l, b ;
2084     INT this_pt ;
2085     INT inverse ;
2086     INT old_orient ;
2087     INT lowestp ;
2088     INT limit ;
2089     INT nextpos, nextneg ;
2090     INT *temp_x ;
2091     INT *temp_y ;
2092     INT numpts ;
2093     VERTEXPTR vptr ;
2094 
2095     old_orient = mptr->orient ;
2096     numpts = mptr->num_vertices ;
2097     /* allocate the space for reoordering the points of the macro */
2098     temp_x = (INT *) Ysafe_malloc( numpts * sizeof(INT) ) ;
2099     temp_y = (INT *) Ysafe_malloc( numpts * sizeof(INT) ) ;
2100     /* first subtract off the center */
2101     for( j = 0; j < mptr->num_vertices; j++ ){
2102 	vptr = mptr->vertices[j] ;
2103 	vptr->x -= mptr->xcenter ;
2104 	vptr->y -= mptr->ycenter ;
2105     }
2106     if( old_orient ){
2107 	/* we need to perform the inverse first */
2108 	/* if we have any orientation other than zero */
2109 	inverse = Ytrans_inv_orient( old_orient ) ;
2110 	for( j = 0; j < numpts; j++ ){
2111 	    vptr = mptr->vertices[j] ;
2112 	    REL_POST( inverse,
2113 		x, y,                               /* result */
2114 		vptr->x, vptr->y,                   /* cell relative */
2115 		0, 0 ) ;  /* cell center */
2116 	    vptr->x = x ;
2117 	    vptr->y = y ;
2118 	}
2119     }
2120     for( j = 0; j < numpts; j++ ){
2121 	vptr = mptr->vertices[j] ;
2122 	REL_POST( orient,
2123 	    temp_x[j], temp_y[j],                 /* result */
2124 	    vptr->x, vptr->y,                   /* cell relative */
2125 	    mptr->xcenter, mptr->ycenter ) ;  /* cell center */
2126     }
2127     /* now we need to reorder the vertices */
2128     /* all the points have been rotated into their proper view and */
2129     /* stored in the vertices array.  Now find lowest of the left pts. */
2130     l = INT_MAX ;
2131     b = INT_MAX ;
2132     for( j = 0; j < numpts; j++ ){
2133 	if( temp_x[j] <= l ){
2134 	    if( temp_y[j] <= b ){
2135 		l = temp_x[j] ;
2136 		b = temp_y[j] ;
2137 		lowestp = j ;
2138 	    }
2139 	}
2140     }
2141     /* now determine CW direction */
2142     nextpos = (lowestp + 1 ) % numpts; ;
2143     if( lowestp == 0 ){
2144 	nextneg = numpts - 1 ;
2145     } else {
2146 	nextneg = lowestp - 1 ;
2147     }
2148     j = 0 ;
2149     if( temp_x[nextpos] == l && temp_y[nextpos] > b ){
2150 	/* clockwise is positive */
2151 	limit = lowestp + numpts;
2152 	for( p = lowestp; p < limit; p++ ) {
2153 	    this_pt = p % numpts ;
2154 	    vptr = mptr->vertices[j++] ;
2155 	    vptr->x = temp_x[this_pt] ;
2156 	    vptr->y = temp_y[this_pt] ;
2157 	}
2158 
2159     } else if( temp_x[nextneg] == l && temp_y[nextneg] > b ){
2160 	/* clockwise is negative */
2161 	limit = lowestp - numpts ;
2162 	for( p = lowestp; p > limit; p-- ) {
2163 	    if( p < 0 ){
2164 		this_pt = numpts + p ;
2165 	    } else {
2166 		this_pt = p ;
2167 	    }
2168 	    vptr = mptr->vertices[j++] ;
2169 	    vptr->x = temp_x[this_pt] ;
2170 	    vptr->y = temp_y[this_pt] ;
2171 	}
2172     } else {
2173 	M( ERRMSG, "rotate_vertices",
2174 	"couldn't find clockwise direction for boundary\n" ) ;
2175     }
2176     Ysafe_free( temp_x ) ;
2177     Ysafe_free( temp_y ) ;
2178 
2179 } /* end rotate_vertices */
2180 
find_nearest_corner(macro,x,y,x_ret,y_ret)2181 static void find_nearest_corner( macro, x, y, x_ret, y_ret )
2182 INT macro, x, y, *x_ret, *y_ret ;
2183 {
2184     INT j ;
2185     INT dist ;
2186     INT cdist ;
2187     INT closest_pt ;
2188     MACROPTR mptr ;
2189     VERTEXPTR vptr ;
2190 
2191     mptr = macroArrayG[macro] ;
2192     dist = INT_MAX ;
2193     for( j = 0; j < mptr->num_vertices; j++ ){
2194 	vptr = mptr->vertices[j] ;
2195 	cdist = ABS(vptr->x - x) + ABS(vptr->y - y) ;
2196 	if( cdist < dist ){
2197 	    closest_pt = j ;
2198 	    dist = cdist ;
2199 	}
2200     }
2201     /* now check the center point */
2202     cdist = ABS(mptr->xcenter-x) + ABS(mptr->ycenter-y) ;
2203     if( cdist < dist ){
2204 	/* the center is the closest point */
2205 	*x_ret = mptr->xcenter ;
2206 	*y_ret = mptr->ycenter ;
2207     } else {
2208 	/* one of the corner points */
2209 	vptr = mptr->vertices[closest_pt] ;
2210 	*x_ret = vptr->x ;
2211 	*y_ret = vptr->y ;
2212     }
2213 } /* end find_nearest_corner */
2214 
2215 
highlight_corner(macro,x,y)2216 static void highlight_corner( macro, x, y )
2217 INT macro, x, y ;
2218 {
2219     INT l, b, r, t ;   /* the core */
2220     INT xpand ;        /* blow up corner by this amount */
2221 
2222     get_core( &l, &b, &r, &t, TRUE ) ;
2223     xpand = MIN( r - l, t - b ) ;
2224     xpand = (INT) (0.025 * (DOUBLE) xpand ) ;
2225     xpand = MAX( xpand, 1 ) ; /* don't let it go to zero */
2226     TWdrawCell( 0, x-xpand,y-xpand,x+xpand,y+xpand,TWBLACK, NULL ) ;
2227     TWflushFrame() ;
2228     /*
2229     (void) sleep( (unsigned) 2 ) ;
2230     */
2231 
2232 } /* end highlight_corner */
2233 
outm(errtype,routine,string)2234 static void outm( errtype, routine, string )
2235 INT errtype ;
2236 char *routine ;
2237 char *string ;
2238 {
2239     char buffer[LRECL] ;
2240 
2241     switch( errtype ){
2242     case ERRMSG:
2243 	if( routine ){
2244 	    sprintf( buffer, "ERROR[%s]:", routine ) ;
2245 	} else {
2246 	    sprintf( buffer, "ERROR:" ) ;
2247 	}
2248 	break ;
2249     case WARNMSG:
2250 	if( routine ){
2251 	    sprintf( buffer, "WARNING[%s]:", routine ) ;
2252 	} else {
2253 	    sprintf( buffer, "WARNING:" ) ;
2254 	}
2255 	break ;
2256     default :
2257 	buffer[0] = EOS ;
2258     }
2259     strcat( buffer, string ) ;
2260     TWmessage( buffer ) ;
2261     sprintf( buffer, "%s\n", string ) ;
2262     M( errtype, routine, buffer ) ;
2263 } /* end outm */
2264 
2265 #else /* NOGRAPHICS */
2266 /* dummy routines to resolve globals */
2267 #endif
2268