1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18     Last edit by hansen on Fri Jan 30 20:27:13 2009
19 ****************************************************************************/
20 
21 #ifdef __cplusplus
22 #include <cstdlib>
23 #include <cstring>
24 #else
25 #include <stdlib.h>
26 #include <string.h>
27 #endif
28 
29 #include "tkgate.h"
30 #include "print.h"
31 
32 static char *psFrame[] = {
33   "%",
34   "% An frame gate",
35   "%",
36   "/psframe {",
37   "  gsave",
38   "  translate",
39   "  pbox",
40   "  [3 3] 0 setdash",
41   "  stroke",
42   "  [] 0 setdash",
43   "  1 setgray 2 setlinewidth",
44   "  10 0 moveto 10 add 0 rlineto stroke",
45   "  0 setgray",
46   "  grestore",
47   "} bind def",
48   0
49 };
50 
51 GCElement *Frame_Make(EditState **es,GModuleDef *env,int GType,
52 		      int x,int y,int r,const char *Name,int noWire,const char**,int);
53 void Frame_Delete(GCElement *g,GModuleDef *env,int drawp);
54 void Frame_GetExtents(GCElement *g,TargetDev_e target,int *minx,int *miny,int *maxx,int *maxy,int *bd);
55 int Frame_HitDistance(GCElement *g,int x,int y);
56 void Frame_Draw(GCElement *g,int md);
57 void Frame_PSWrite(GPrint *P,GModLayout *L,GCElement *g);
58 void Frame_VerSave(FILE *f,GCElement *g);
59 int Frame_EditProps(GCElement *g,int isLoadDialog);
60 void Frame_SetProp(GCElement*,const char*,const void*);
61 GCElement *Frame_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned);
62 void Frame_Move(GCElement *g,int x,int y);
63 void Frame_Rotate(GCElement *g,int centX, int centY,int rdir);
64 
65 GGateInfo gate_frame_info = {
66   0,
67   "FRAME",
68   "frame",0x0,
69   "psframe",psFrame,
70   -1,-1,
71 
72   {{"F",	{0,0},			{"gm.frame",0,0},		"gat_make FRAME"},
73    {0}},
74   0,
75 
76   0,{{0}},
77   {{0,-12,CT},{12,0,LJ},{0,-12,CT},{12,0,LJ}},	/* Are these even used? */
78   {0,0,0,0,1},
79 
80   {0},
81 
82   Frame_Make,
83   Nop_WriteCellDef,
84   Generic_Init,
85   Frame_Delete,
86   Frame_GetExtents,
87   Frame_HitDistance,
88   Frame_Draw,
89   Frame_Move,
90   Frame_Copy,
91   Err_AddInput,
92   Err_AddOutput,
93   Err_AddInOut,
94   Frame_Rotate,
95   Err_RemovePort,
96   Err_ChangePin,
97   Nop_SimInitFunc,
98   Nop_SimHitFunc,
99   Frame_PSWrite,
100   Frame_EditProps,
101   Frame_VerSave,
102   Frame_SetProp
103 };
104 
Frame_Make(EditState ** es,GModuleDef * env,int GType,int x,int y,int r,const char * Name,int noWire,const char ** options,int nOptions)105 GCElement *Frame_Make(EditState **es,GModuleDef *env,int GType,
106 		      int x,int y,int r,const char *Name,int noWire,const char **options,int nOptions)
107 {
108   GCElement *g;
109 
110   if (!(g = Generic_Make(es,env,GType,x,y,r,Name,noWire,options,nOptions)))
111     return NULL;
112 
113   ob_touch(g);
114 
115   g->u.frame.width = g->u.frame.height = 100;
116   g->u.frame.text = ob_strdup("");
117   g->u.frame.html = 0;
118 
119   return g;
120 }
121 
Frame_flushHtml(GCElement * g)122 static void Frame_flushHtml(GCElement *g)
123 {
124   if (g->u.frame.html) {
125     delete_Html(g->u.frame.html);
126     g->u.frame.html = 0;
127   }
128 }
129 
Frame_Delete(GCElement * g,GModuleDef * M,int drawp)130 void Frame_Delete(GCElement *g,GModuleDef *M,int drawp)
131 {
132   if (M)     gate_remove(M,g);
133   if (drawp) gate_draw(g,0);
134 
135   if (g->u.frame.text)
136     ob_free(g->u.frame.text);
137 
138   Frame_flushHtml(g);
139 }
140 
Frame_Move(GCElement * g,int x,int y)141 void Frame_Move(GCElement *g,int x,int y)
142 {
143   ob_touch(g);
144 
145   if (g->top && g->left) {
146     if (g->u.frame.height - y < MINSIZE)
147       y = g->u.frame.height - MINSIZE;
148     g->u.frame.height -= y;
149     g->ypos += y;
150 
151     if (g->u.frame.width - x < MINSIZE)
152       x = g->u.frame.width - MINSIZE;
153     g->u.frame.width -= x;
154     g->xpos += x;
155 
156   } else if (g->bottom && g->left) {
157     if (g->u.frame.height + y < MINSIZE)
158       y = MINSIZE - g->u.frame.height;
159     g->u.frame.height += y;
160 
161     if (g->u.frame.width - x < MINSIZE)
162       x = g->u.frame.width - MINSIZE;
163     g->u.frame.width -= x;
164     g->xpos += x;
165 
166   } else if (g->top && g->right) {
167     if (g->u.frame.height - y < MINSIZE)
168       y = g->u.frame.height - MINSIZE;
169     g->u.frame.height -= y;
170     g->ypos += y;
171 
172     if (g->u.frame.width + x < MINSIZE)
173       x = MINSIZE - g->u.frame.width;
174     g->u.frame.width += x;
175   } else if (g->bottom && g->right) {
176     if (g->u.frame.height + y < MINSIZE)
177       y = MINSIZE - g->u.frame.height;
178     g->u.frame.height += y;
179 
180     if (g->u.frame.width + x < MINSIZE)
181       x = MINSIZE - g->u.frame.width;
182     g->u.frame.width += x;
183   } else {
184     g->xpos += x;
185     g->ypos += y;
186   }
187 }
188 
189 
Frame_GetExtents(GCElement * g,TargetDev_e target,int * minx,int * miny,int * maxx,int * maxy,int * bd)190 void Frame_GetExtents(GCElement *g,TargetDev_e target,int *minx,int *miny,int *maxx,int *maxy,int *bd)
191 {
192   *minx = g->xpos - 2;
193   *miny = g->ypos - 2;
194   *maxx = g->xpos + g->u.frame.width + 2;
195   *maxy = g->ypos + g->u.frame.height + 2;
196 
197   if (bd) *bd = 20;
198 }
199 
200 /*
201   Frames can only be selected on edges or corners
202  */
Frame_HitDistance(GCElement * g,int x,int y)203 int Frame_HitDistance(GCElement *g,int x,int y)
204 {
205   ob_touch(g);
206 
207   g->left = 0;
208   g->right = 0;
209   g->top = 0;
210   g->bottom = 0;
211 
212   if ((x > g->xpos - 10) &&
213       (x < g->xpos + g->u.frame.width + 10) &&
214       (y > g->ypos - 10) &&
215       (y < g->ypos + g->u.frame.height + 10)) {
216     if (x < g->xpos + 10) {
217       g->left = 1;
218     }
219     if (x > g->xpos + g->u.frame.width - 10) {
220       g->right = 1;
221     }
222     if (y < g->ypos + 10) {
223       g->top = 1;
224     }
225     if (y > g->ypos + g->u.frame.height - 10) {
226       g->bottom = 1;
227     }
228 
229     if (g->left || g->right || g->top || g->bottom)
230       return GATERANGE-1;
231   }
232   return NOHIT; 			/* out of range */
233 }
234 
235 
Frame_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)236 GCElement *Frame_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
237 {
238   GCElement *ng;
239 
240   ng = Generic_Copy(M,g,x,y,flags);
241 
242   ob_touch(ng);
243 
244   ng->u.frame.width = g->u.frame.width;
245   ng->u.frame.height = g->u.frame.height;
246   ng->u.frame.text = g->u.frame.text ? ob_strdup(g->u.frame.text) : 0;
247   ng->u.frame.html = 0;
248 
249   return ng;
250 }
251 
Frame_buildHtml(GCElement * g)252 static void Frame_buildHtml(GCElement *g)
253 {
254   Html *h;
255 
256   if (g->u.frame.html
257       && g->u.frame.html->h_zoom == TkGate.circuit->zoom_factor
258       && g->u.frame.html->h_locale == TkGate.circuit->c_locale)
259     return;
260 
261   ob_begin_framef("-BuildHtml",FF_TRANSPARENT);
262   ob_touch(g);
263 
264   Frame_flushHtml(g);
265 
266   if (*g->u.frame.text) {
267     h = new_Html(TD_X11);
268     Html_addLine(h, g->u.frame.text);
269     Html_format(h);
270     g->u.frame.html = h;
271   } else
272     g->u.frame.html = 0;
273 
274   ob_end_frame();
275 }
276 
Frame_Draw(GCElement * g,int md)277 void Frame_Draw(GCElement *g,int md)
278 {
279   Frame_buildHtml(g);
280 
281   if (g->selected)
282     XSetLineAttributes(TkGate.D,TkGate.frameGC,2,LineOnOffDash,CapButt,JoinMiter);
283 
284   if (!g->u.frame.html) {
285     ZDrawRectangle(TkGate.D,TkGate.W,TkGate.frameGC,
286 		   ctow_x(g->xpos),ctow_y(g->ypos),
287 		   g->u.frame.width,g->u.frame.height);
288   } else {
289     XPoint points[6];
290     int x = ctow_x(g->xpos);
291     int y = ctow_y(g->ypos);
292     int w,h;
293 
294     w = g->u.frame.html->h_width;
295     h = g->u.frame.html->h_height;
296     Html_draw(g->u.frame.html,g->xpos+15,g->ypos-h/2);
297 
298     if (w+20 < g->u.frame.width) {
299       points[0].x = x+w+20;
300       points[0].y = y;
301       points[1].x = x+g->u.frame.width;
302       points[1].y = y;
303       points[2].x = x+g->u.frame.width;
304       points[2].y = y+g->u.frame.height;
305       points[3].x = x;
306       points[3].y = y+g->u.frame.height;
307       points[4].x = x;
308       points[4].y = y;
309       points[5].x = x+10;
310       points[5].y = y;
311       ZDrawLines(TkGate.D,TkGate.W,TkGate.frameGC,points,6,CoordModeOrigin);
312     } else {
313       points[0].x = x+g->u.frame.width;
314       points[0].y = y+8;
315       points[1].x = x+g->u.frame.width;
316       points[1].y = y+g->u.frame.height;
317       points[2].x = x;
318       points[2].y = y+g->u.frame.height;
319       points[3].x = x;
320       points[3].y = y;
321       points[4].x = x+10;
322       points[4].y = y;
323       ZDrawLines(TkGate.D,TkGate.W,TkGate.frameGC,points,5,CoordModeOrigin);
324     }
325   }
326 
327   if (g->selected)
328     XSetLineAttributes(TkGate.D,TkGate.frameGC,1,LineOnOffDash,CapButt,JoinMiter);
329 }
330 
Frame_PSWrite(GPrint * P,GModLayout * L,GCElement * g)331 void Frame_PSWrite(GPrint *P,GModLayout *L,GCElement *g)
332 {
333   int width = 0;
334   int height = 0;
335 
336   if (*g->u.frame.text) {
337     Html *h = new_Html(TD_PRINT);
338     Html_addLine(h,g->u.frame.text);
339     Html_format(h);
340     width = h->h_width;
341     height = h->h_height;
342     fprintf(P->p_f,"%d %d %d %d %d psframe\n",width,g->u.frame.width,g->u.frame.height,g->xpos,g->ypos);
343     Html_psPrint(h,P,g->xpos+15,g->ypos-height/2);
344     delete_Html(h);
345   } else
346     fprintf(P->p_f,"0 %d %d %d %d psframe\n",g->u.frame.width,g->u.frame.height,g->xpos,g->ypos);
347 }
348 
Frame_VerSave(FILE * f,GCElement * g)349 void Frame_VerSave(FILE *f,GCElement *g)
350 {
351   char buf[STRMAX],buf2[STRMAX];
352   Encoder *encoder = Circuit_getSaveFileEncoder(TkGate.circuit);
353 
354   fprintf(f,"  //: frame %s",g->ename);
355   VerilogBasicGateComment(f,g,0);
356 
357   recodeText(encoder,buf,STRMAX,g->u.frame.text);
358   fprintf(f," /wi:%d /ht:%d /tx:\"%s\"\n",g->u.frame.width,g->u.frame.height,
359 	  quoteChars(buf2,buf,"\"\\"));
360 }
361 
Frame_EditProps(GCElement * g,int isLoadDialog)362 int Frame_EditProps(GCElement *g,int isLoadDialog)
363 {
364   char buf[STRMAX];
365 
366   Generic_EditProps(g,isLoadDialog);
367   if (isLoadDialog) {
368     quoteChars(buf,g->u.frame.text,"\"[]\\");
369     DoTcl("set ::edgat_frameLabel \"%s\"",buf);
370   } else {
371     strcpy(buf,Tcl_GetVar(TkGate.tcl,"edgat_frameLabel",TCL_GLOBAL_ONLY));
372 
373     ob_touch(g);
374 
375     if (g->u.frame.text)
376       ob_free(g->u.frame.text);
377     g->u.frame.text = ob_strdup(buf);
378     Frame_flushHtml(g);
379   }
380 
381   return 0;
382 }
383 
Frame_SetProp(GCElement * g,const char * prop,const void * value)384 void Frame_SetProp(GCElement *g,const char *prop,const void *value)
385 {
386   ob_touch(g);
387 
388   if (strcmp(prop,"/wi") == 0) {
389     int n = *(int*)value;
390     g->u.frame.width = n;
391   } else if (strcmp(prop,"/ht") == 0) {
392     int n = *(int*)value;
393     g->u.frame.height = n;
394   } else if (strcmp(prop,"/tx") == 0) {
395     if (g->u.frame.text)
396       ob_free(g->u.frame.text);
397     g->u.frame.text = ob_strdup((char*)value);;
398     Frame_flushHtml(g);
399   }
400 }
401 
Frame_Rotate(GCElement * g,int centX,int centY,int rdir)402 void Frame_Rotate(GCElement *g,int centX, int centY,int rdir)
403 {
404   int x = g->xpos + g->u.frame.width/2;
405   int y = g->ypos + g->u.frame.height/2;
406   int nx,ny,t;
407 
408   ob_touch(g);
409   nx = rotateX(x - centX,y - centY, rdir) + centX;
410   ny = rotateY(x - centX,y - centY, rdir) + centY;
411 
412   t = g->u.frame.width;
413   g->u.frame.width = g->u.frame.height;
414   g->u.frame.height = t;
415 
416   g->xpos = nx - g->u.frame.width/2;
417   g->ypos = ny - g->u.frame.height/2;
418 
419 }
420 
init_frame()421 void init_frame()
422 {
423   RegisterGate(&gate_frame_info);
424 }
425