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