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