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 Tue Feb 3 10:24:32 2009
19 ****************************************************************************/
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <signal.h>
25 #include "tkgate.h"
26
27 extern int sync_Xserver;
28 extern int did_interface_resize;
29
30 /*
31 * This is a kludge to prevent a problem that can occur when a hyperlink leads
32 * to a file that has a hyperlink in the same location such as the <PREVIOUS
33 * and NEXT> links in the tutorial. If the user starts click NEXT> too quickly,
34 * it can count as a double click after loading the file. To prevent this, we
35 * clear the flag when reading a new circuit, then increment it each time we click
36 * on the canvas. The flag must be at least 2 to recognize a double click
37 */
38 int click_count = 0;
39
40 void doScroll(int dx,int dy);
41
42 int gat_scope(ClientData d,Tcl_Interp *tcl,int argc,const char *argv[]);
43
44 /*****************************************************************************
45 *
46 * Top global variable with tkgate state.
47 *
48 *****************************************************************************/
49 TkGateParams TkGate;
50
51 static int did_doubleclick = 0; /* Did we just do a double click */
52
53 static Tk_ConfigSpec configSpecs[] = {
54 {TK_CONFIG_COLOR, "-background", "background", "Background", "white", Tk_Offset(TkgGateWin,bgColor), 0, 0},
55 {TK_CONFIG_SYNONYM,"-bg", "background", 0, 0, 0, 0, 0},
56 {TK_CONFIG_SYNONYM,"-fg", "foreground", 0, 0, 0, 0, 0},
57 {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", "black", Tk_Offset(TkgGateWin,fgColor), 0, 0},
58 {TK_CONFIG_INT, "-height", "height", "Height", STR(TKG_GATEWIN_HEIGHT), Tk_Offset(TkgGateWin,height), 0, 0},
59 {TK_CONFIG_INT, "-width", "width", "Width", STR(TKG_GATEWIN_WIDTH), Tk_Offset(TkgGateWin,width), 0, 0},
60 {TK_CONFIG_STRING, "-xscrollcommand", "xscrollcommand", "Xscrollcommand", "", Tk_Offset(TkgGateWin,xscroll), 0, 0},
61 {TK_CONFIG_STRING, "-yscrollcommand", "yscrollcommand", "Yscrollcommand", "", Tk_Offset(TkgGateWin,yscroll), 0, 0},
62 {TK_CONFIG_STRING, "-takefocus", "takefocus", "Takefocus", "", Tk_Offset(TkgGateWin,takefocus), 0, 0},
63 {TK_CONFIG_END, 0, 0, 0, 0, 0, 0, 0}
64 };
65 int numConfigSpecs = sizeof(configSpecs)/sizeof(configSpecs[0]);
66
67 /*****************************************************************************
68 *
69 * Return the code for the current major mode
70 *
71 *****************************************************************************/
tkgate_currentMode()72 MajorMode tkgate_currentMode()
73 {
74 return TkGate.ed->major_mode;
75 }
76
77 /*****************************************************************************
78 *
79 * Changes the major mode opening/closing any windows or connections necessary
80 * to do so.
81 *
82 *****************************************************************************/
tkgate_setMajorMode(MajorMode requestedMode)83 void tkgate_setMajorMode(MajorMode requestedMode)
84 {
85 MajorMode currentMode;
86
87 if (!TkGate.circuit || !TkGate.circuit->es) return;
88
89 currentMode = tkgate_currentMode();
90
91 /*
92 * No change in mode, but we might want to issue a message.
93 */
94 if (requestedMode == currentMode)
95
96 /* Gen. error message if simulator is already running */
97 if (currentMode == MM_SIMULATE) {
98 message(0,msgLookup("err.sim.isrun"));
99 return;
100 }
101
102 if (requestedMode == MM_SIMULATE || requestedMode == MM_ANALYZE) {
103 GModuleDef *R;
104
105 ob_begin_framef("-RCheck",FF_TRANSPARENT);
106 R = GModuleDef_isRecursive(TkGate.circuit->es->env);
107 ob_end_frame();
108
109 if (R) {
110 message(1,msgLookup("sim.recursive"),R->m_name);
111 FlagRedraw(MF_ALL);
112 return;
113 }
114 }
115
116 /*
117 * Transition to MM_EDIT before changing to new mode.
118 */
119 switch (currentMode) {
120 case MM_EDIT :
121 break;
122 case MM_SIMULATE :
123 if (TkGate.circuit->simulator.active) {
124 SimInterface_end(&TkGate.circuit->simulator);
125 FlagRedraw();
126 }
127 break;
128 case MM_ANALYZE :
129 cpath_close();
130 break;
131 }
132
133 /* Always reset edit mode when changing major modes */
134 setEditMode(TkGate.circuit->es,MODE_MOVE);
135 #if TOUCH_XGATE_ED
136 ob_touch(TkGate.ed);
137 #endif
138 TkGate.ed->major_mode = requestedMode;
139
140 switch (requestedMode) {
141 case MM_EDIT :
142 DoTcl("tkg_editLogo");
143 ob_set_mode(OM_ENABLED);
144 break;
145 case MM_SIMULATE :
146 ob_set_mode(OM_DISABLED);
147 ob_clear();
148 TkGate.circuit->simulator.no_scope = 0;
149 SimInterface_begin(&TkGate.circuit->simulator);
150 DoTcl("tkg_resetLogo");
151 break;
152 case MM_ANALYZE :
153 ob_set_mode(OM_DISABLED);
154 ob_clear();
155 cpath_open();
156 DoTcl("tkg_analysisLogo");
157 break;
158 }
159 SetModified(MF_MODULE|MF_SYNCONLY);
160 }
161
162 /*****************************************************************************
163 *
164 * Show the name of the selected object on the status line.
165 *
166 *****************************************************************************/
showSelectedName()167 void showSelectedName()
168 {
169 if (TkGate.circuit->es && TkGate.circuit->es->isInterface) {
170 if (TkGate.circuit->nsel) {
171 GWire *w = TkGate.circuit->wsel;
172 GCElement *g;
173
174 if (w->name)
175 g = w->gate;
176 else {
177 w = wire_other(w);
178 g = w->gate;
179 }
180
181 if (w && g && w->name && GCElement_isModule(g))
182 message(0,msgLookup("msg.iselwire"),w->name,g->u.block.moduleName);
183 } else if (TkGate.circuit->select) {
184 if (!GCElement_isModule(TkGate.circuit->select)) {
185 /* should be impossible */
186 message(0,msgLookup("msg.iselgate"),
187 TkGate.circuit->select->typeinfo->name,
188 TkGate.circuit->select->ename);
189 } else {
190 message(0,msgLookup("msg.iselblock"),
191 TkGate.circuit->select->u.block.moduleName);
192 }
193 }
194 } else {
195 if (TkGate.circuit->nsel) {
196 message(0,msgLookup("msg.selwire"),GNet_getVType(TkGate.circuit->nsel),
197 TkGate.circuit->nsel->n_signame); /* Selected wire named '%s'. */
198 } else if (TkGate.circuit->select) {
199 if (!GCElement_isModule(TkGate.circuit->select)) {
200 message(0,msgLookup("msg.selgate"), /* Selected %s named '%s'. */
201 TkGate.circuit->select->typeinfo->name,
202 TkGate.circuit->select->ename);
203 } else {
204 message(0,msgLookup("msg.selblock"), /* "Selected %s block named '%s'." */
205 TkGate.circuit->select->u.block.moduleName,
206 TkGate.circuit->select->ename);
207 }
208 }
209 }
210 }
211
212 /*****************************************************************************
213 *
214 * Return the pixel value for a named color.
215 *
216 *****************************************************************************/
Tkg_GetColor(const char * name)217 int Tkg_GetColor(const char *name)
218 {
219 XColor XC,eXC;
220
221 XAllocNamedColor(TkGate.D,TkGate.CM,name,&XC,&eXC);
222 return XC.pixel;
223 }
224
225 /*****************************************************************************
226 *
227 * Create a graphic context (GC) with the given transfer function, color
228 * and font.
229 *
230 *****************************************************************************/
Tkg_createGC(int func,char * colorName,XFontStruct * font)231 GC Tkg_createGC(int func,char *colorName,XFontStruct *font)
232 {
233 unsigned mask;
234 XGCValues values;
235 int color, white;
236
237 white = XWhitePixelOfScreen(TkGate.S);
238 color = Tkg_GetColor(colorName);
239
240 mask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures;
241
242 if (func == GXxor) {
243 mask |= GCPlaneMask;
244 values.function = GXxor;
245 values.foreground = color ^ white;
246 values.background = 0;
247 values.plane_mask = color ^ white;
248 } else {
249 values.function = func;
250 values.foreground = color;
251 values.background = white;
252 }
253
254 values.graphics_exposures = False;
255
256 if (font) {
257 values.font = font->fid;
258 mask |= GCFont;
259 }
260
261 return XCreateGC(TkGate.D,TkGate.root,mask,&values);
262 }
263
264 /*****************************************************************************
265 *
266 * Set initial color for a GC
267 *
268 *****************************************************************************/
Tkg_setColor(GC gc,int func,const char * colorName)269 static void Tkg_setColor(GC gc,int func, const char *colorName)
270 {
271 unsigned mask;
272 XGCValues values;
273 int color, white;
274
275 if (!colorName) return;
276
277 white = XWhitePixelOfScreen(TkGate.S);
278 color = Tkg_GetColor(colorName);
279
280 mask = GCForeground | GCBackground;
281
282 if (func == GXxor) {
283 mask |= GCPlaneMask;
284 values.foreground = color ^ white;
285 values.background = 0;
286 values.plane_mask = color ^ white;
287 } else {
288 values.foreground = color;
289 values.background = white;
290 }
291
292 XChangeGC(TkGate.D,gc,mask,&values);
293 }
294
295 /*****************************************************************************
296 *
297 * Change the color of a GC
298 *
299 *****************************************************************************/
Tkg_changeColor(GC gc,int func,int pixel)300 void Tkg_changeColor(GC gc,int func,int pixel)
301 {
302 XGCValues values;
303 unsigned mask;
304 int white;
305
306 white = XWhitePixelOfScreen(TkGate.S);
307 mask = GCForeground | GCBackground;
308
309 if (func == GXxor) {
310 mask |= GCPlaneMask;
311 values.foreground = pixel ^ white;
312 values.background = 0;
313 values.plane_mask = pixel ^ white;
314 } else {
315 values.foreground = pixel;
316 values.background = white;
317 }
318
319 XChangeGC(TkGate.D,gc,mask,&values);
320 }
321
322 /*****************************************************************************
323 *
324 * Load Japanese fonts if we have not already done so.
325 *
326 *****************************************************************************/
initJapanese()327 void initJapanese()
328 {
329 if (TkGate.D && !TkGate.ktextXF)
330 TkGate.ktextXF = GetXFonts(FF_KANJI,FP_ROMAN,FS_SMALL);
331 }
332
333 /*****************************************************************************
334 *
335 * Set up all of the initial colors in the GCs used by tkgate.
336 *
337 *****************************************************************************/
setGCcolors()338 void setGCcolors()
339 {
340 const char *bgcolor = Tcl_GetVar(TkGate.tcl,"tkg_backgroundColor",TCL_GLOBAL_ONLY);
341 int bgcolor_pixel = Tkg_GetColor(bgcolor);
342
343 Tk_SetWindowBackground(TkGate.gw->win, bgcolor_pixel);
344
345 Tkg_setColor(TkGate.instGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_instColor",TCL_GLOBAL_ONLY));
346 Tkg_setColor(TkGate.moduleGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_moduleColor",TCL_GLOBAL_ONLY));
347 Tkg_setColor(TkGate.modportGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_modulePortColor",TCL_GLOBAL_ONLY));
348 Tkg_setColor(TkGate.frameGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_frameColor",TCL_GLOBAL_ONLY));
349 Tkg_setColor(GatePainterContext_gc(TkGate.commentContext),
350 GXxor, Tcl_GetVar(TkGate.tcl,"tkg_commentColor",TCL_GLOBAL_ONLY));
351 Tkg_setColor(TkGate.imageGC, GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_commentColor",TCL_GLOBAL_ONLY));
352 Tkg_setColor(TkGate.hyperlinkGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_hyperlinkColor",TCL_GLOBAL_ONLY));
353 Tkg_setColor(TkGate.wireGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_wireColor",TCL_GLOBAL_ONLY));
354 Tkg_setColor(TkGate.busGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_busColor",TCL_GLOBAL_ONLY));
355 Tkg_setColor(TkGate.selWireGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_wireColor",TCL_GLOBAL_ONLY));
356 Tkg_setColor(TkGate.selBusGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_busColor",TCL_GLOBAL_ONLY));
357 Tkg_setColor(TkGate.toolGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_toolColor",TCL_GLOBAL_ONLY));
358 Tkg_setColor(TkGate.cpathGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_cpathColor",TCL_GLOBAL_ONLY));
359 Tkg_setColor(TkGate.kanjiGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_commentColor",TCL_GLOBAL_ONLY));
360
361 /* Tkg_setColor(TkGate.scopeSelectGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_gridColor",TCL_GLOBAL_ONLY));*/
362 Tkg_setColor(TkGate.scopeXHairGC, GXxor, Tcl_GetVar(TkGate.tcl,"tkg_gridColor",TCL_GLOBAL_ONLY));
363 Tkg_setColor(TkGate.scopeGridGC, GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_gridColor",TCL_GLOBAL_ONLY));
364 Tkg_setColor(TkGate.scopeOneGC, GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_oneColor",TCL_GLOBAL_ONLY));
365 Tkg_setColor(TkGate.scopeZeroGC, GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_zeroColor",TCL_GLOBAL_ONLY));
366 Tkg_setColor(TkGate.scopeFloatGC, GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_floatColor",TCL_GLOBAL_ONLY));
367 Tkg_setColor(TkGate.scopeUnknownGC, GXcopy, Tcl_GetVar(TkGate.tcl,"tkg_unknownColor",TCL_GLOBAL_ONLY));
368
369 TkGate.inst_pixel = Tkg_GetColor(Tcl_GetVar(TkGate.tcl,"tkg_instColor",TCL_GLOBAL_ONLY));
370 TkGate.ledoff_pixel = Tkg_GetColor(Tcl_GetVar(TkGate.tcl,"tkg_offLedColor",TCL_GLOBAL_ONLY));
371 TkGate.ledon_pixel = Tkg_GetColor(Tcl_GetVar(TkGate.tcl,"tkg_onLedColor",TCL_GLOBAL_ONLY));
372 TkGate.ledunknown_pixel = Tkg_GetColor(Tcl_GetVar(TkGate.tcl,"tkg_zLedColor",TCL_GLOBAL_ONLY));
373 }
374
375 /*****************************************************************************
376 *
377 * Allocate GCs for main window
378 *
379 *****************************************************************************/
initGCs()380 void initGCs()
381 {
382 unsigned mask;
383 XGCValues values;
384 Pixmap bitPM;
385
386 /*
387 Do font set up
388 */
389 TkGate.textXF = GetXFonts(FF_COURIER,FP_ROMAN,FS_NORMAL);
390 TkGate.textbXF = GetXFonts(FF_COURIER,FP_BOLD,FS_NORMAL);
391 TkGate.stextXF = GetXFonts(FF_COURIER,FP_ROMAN,FS_SMALL);
392 TkGate.stextbXF = GetXFonts(FF_COURIER,FP_BOLD,FS_SMALL);
393 if (TkGate.japaneseMode)
394 TkGate.ktextXF = GetXFonts(FF_KANJI,FP_ROMAN,FS_SMALL);
395 else
396 TkGate.ktextXF = 0;
397
398 TkGate.inst_pixel = Tkg_GetColor("blue");
399 TkGate.ledoff_pixel = Tkg_GetColor("firebrick4");
400 TkGate.ledon_pixel = Tkg_GetColor("red");
401 TkGate.ledunknown_pixel = Tkg_GetColor("yellow");
402
403 TkGate.instGC = Tkg_createGC(GXxor,"blue",TkGate.textXF[1]);
404 TkGate.moduleGC = Tkg_createGC(GXxor,"magenta4",TkGate.textXF[1]);
405 TkGate.modportGC = Tkg_createGC(GXxor,"cyan4",TkGate.textXF[1]);
406 TkGate.frameGC = Tkg_createGC(GXxor,"tan4",TkGate.textXF[1]);
407 TkGate.imageGC = Tkg_createGC(GXcopy,"tan4",TkGate.textXF[1]);
408 TkGate.hyperlinkGC = Tkg_createGC(GXxor,"tan4",TkGate.textXF[1]);
409 TkGate.wireGC = Tkg_createGC(GXxor,"green4",TkGate.stextXF[1]);
410 TkGate.busGC = Tkg_createGC(GXxor,"red",TkGate.stextXF[1]);
411 TkGate.selWireGC = Tkg_createGC(GXxor,"green4",TkGate.stextbXF[1]);
412 TkGate.selBusGC = Tkg_createGC(GXxor,"red",TkGate.stextbXF[1]);
413 TkGate.toolGC = Tkg_createGC(GXxor,"black",TkGate.textXF[1]);
414 TkGate.cpathGC = Tkg_createGC(GXxor,"red",TkGate.textXF[1]);
415 TkGate.kanjiGC = Tkg_createGC(GXxor,"tan4",TkGate.ktextXF ? TkGate.ktextXF[1] : 0);
416
417 TkGate.copyGC = Tkg_createGC(GXcopy,"black",TkGate.textXF[1]);
418 XSetGraphicsExposures(TkGate.D,TkGate.copyGC,True);
419
420 TkGate.scopeXHairGC = Tkg_createGC(GXxor,"black",TkGate.textXF[1]);
421 TkGate.scopeSelectGC = Tkg_createGC(GXxor,"grey90",TkGate.textXF[1]);
422 TkGate.scopeGridGC = Tkg_createGC(GXcopy,"black",TkGate.textXF[1]);
423 TkGate.scopeOneGC = Tkg_createGC(GXcopy,"green4",TkGate.stextXF[1]);
424 TkGate.scopeZeroGC = Tkg_createGC(GXcopy,"magenta",TkGate.stextXF[1]);
425 TkGate.scopeFloatGC = Tkg_createGC(GXcopy,"blue",TkGate.stextXF[1]);
426 TkGate.scopeUnknownGC = Tkg_createGC(GXcopy,"red",TkGate.stextXF[1]);
427 TkGate.scopeClearGC = Tkg_createGC(GXcopy,"white",TkGate.stextXF[1]);
428
429 XSetLineAttributes(TkGate.D,TkGate.busGC,2,LineSolid,CapButt,JoinMiter);
430 XSetLineAttributes(TkGate.D,TkGate.selBusGC,3,LineSolid,CapButt,JoinMiter);
431 XSetLineAttributes(TkGate.D,TkGate.selWireGC,2,LineSolid,CapButt,JoinMiter);
432
433 mask = GCLineStyle | GCDashList;
434 values.line_style = LineOnOffDash;
435 values.dashes = DASH_LENGTH/2;
436 XChangeGC(TkGate.D,TkGate.frameGC, mask, &values);
437
438 mask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures;
439 values.foreground = 1;
440 values.background = 1;
441 values.function = GXcopy;
442 values.graphics_exposures = False;
443
444 bitPM = XCreatePixmap(TkGate.D,TkGate.root,8,8,1);
445 TkGate.bitGC = XCreateGC(TkGate.D,bitPM,mask,&values);
446 XFreePixmap(TkGate.D,bitPM);
447 }
448
449 /*****************************************************************************
450 *
451 * The TkGateParms object is the top-level data structure used in the
452 * original xgate program. Since there is too much depending on it,
453 * just initialize it appropriately for now.
454 *
455 *****************************************************************************/
initGateParms(TkgGateWin * gw,TkGateParams * P)456 static void initGateParms(TkgGateWin *gw,TkGateParams *P)
457 {
458 Tk_MakeWindowExist(gw->win);
459
460 P->W = Tk_WindowId(gw->win);
461
462 P->painterW = (GatePainter*)new_GatePainterXlib();
463 GatePainter_init(P->painterW, P->D, P->W); /* Initializing editing window painter */
464 P->commentContext = GatePainter_createContext(P->painterW);
465 *GatePainterContext_gcRef(TkGate.commentContext) =
466 Tkg_createGC(GXxor,"tan4",TkGate.textXF[1]);
467
468 P->comment_color = GatePainter_getColor(P->painterW,
469 Tcl_GetVar(TkGate.tcl,"tkg_commentColor",TCL_GLOBAL_ONLY));
470 P->hyperlink_color = GatePainter_getColor(P->painterW,
471 Tcl_GetVar(TkGate.tcl,"tkg_hyperlinkColor",TCL_GLOBAL_ONLY));
472
473 P->painterScopeW = (GatePainter*)new_GatePainterXlib();
474 GatePainter_init(P->painterScopeW, P->D, None); /* Initializing scope window painter */
475
476 P->circuit->es = new_EditState();
477 TkGate.circuit->no_set_modify = 1;
478 P->circuit->es->env = env_defineModule("main",1);
479 editstate_setCurrent(P->circuit->es);
480 TkGate.circuit->root_mod = P->circuit->es->env;
481 TkGate.circuit->no_set_modify = 0;
482 TkGate_setOrigin(0,0);
483 ClearModified();
484 }
485
486 /*****************************************************************************
487 *
488 * gateCleanUp - This function is called when exiting tkgate to cleanup any
489 * data structures that need to be explicitly released before we exit.
490 *
491 *****************************************************************************/
gateCleanUp()492 void gateCleanUp()
493 {
494 UnloadAllFonts(); /* Free all font structures */
495 }
496
497 /*****************************************************************************
498 *
499 * Rescan all HDL modules
500 *
501 * This function is called as an idle task while in edit mode. It looks for
502 * any HDL modules that have been modified since the last scan and does a scan
503 * on them by running the simulator in scan mode.
504 *
505 *****************************************************************************/
RescanHDLModules()506 void RescanHDLModules()
507 {
508 HashElem *e;
509 SHash *modules = TkGate.circuit->moduleTable;
510 int anyscanned = 0;
511
512 for (e = Hash_first(modules);e;e = Hash_next(modules,e)) {
513 GModuleDef *M = (GModuleDef*) HashElem_obj(e);
514 if (GModuleDef_getType(M) == MT_TEXTHDL && M->m_needScan) {
515 if (!anyscanned)
516 ob_begin_framef("ScanMod",FF_TRANSPARENT|FF_BACKGROUND);
517 GModuleDef_scanHDLModule(M);
518 anyscanned = 1;
519 }
520 }
521
522 if (anyscanned) {
523 SetModified(MF_MODULE|MF_SYNCONLY);
524 ob_end_frame();
525 }
526 }
527
528
529 /*****************************************************************************
530 *
531 * This function is called when the tk event queue becomes idle.
532 *
533 *****************************************************************************/
idleGateWin(ClientData data)534 void idleGateWin(ClientData data)
535 {
536 extern int want_exit;
537 MajorMode cm = tkgate_currentMode();
538
539 if (want_exit) {
540 switch (cm) {
541 case MM_SIMULATE :
542 if (TkGate.circuit->simulator.active)
543 SimInterface_end(&TkGate.circuit->simulator);
544 break;
545 case MM_ANALYZE :
546 cpath_close();
547 break;
548 case MM_EDIT :
549 break;
550 }
551 DoTcl("File::closeApplication");
552 want_exit = 0;
553 }
554
555 #if TOUCH_XGATE_ED
556 ob_begin_framef("-Idle",FF_TRANSPARENT);
557 #endif
558
559 if (TkGate.idle_ev.scroll_area) {
560 ob_begin_framef("Scroll",FF_STICKY);
561 doScroll(wtoc_x(TkGate.idle_ev.scroll_new_x),
562 wtoc_y(TkGate.idle_ev.scroll_new_y));
563 ob_end_frame();
564
565 TkGate.idle_ev.scroll_new_x = TkGate.circuit->org_x;
566 TkGate.idle_ev.scroll_new_y = TkGate.circuit->org_y;
567 TkGate.idle_ev.scroll_area = 0;
568 TkGate.idle_ev.redraw = 0;
569 } else {
570 if (TkGate.idle_ev.redraw) {
571 editstate_fullUpdate(TkGate.circuit->es);
572 TkGate.idle_ev.redraw = 0;
573 }
574 }
575
576 if (TkGate.idle_ev.scope_redraw || TkGate.idle_ev.trace_redraw) {
577 extern GScope *Scope;
578 if (Scope)
579 GScope_fullUpdate(Scope);
580 TkGate.idle_ev.scope_redraw = 0;
581 TkGate.idle_ev.trace_redraw = 0;
582 }
583
584 #if TOUCH_XGATE_ED
585 ob_end_frame();
586 #endif
587
588 /*
589 * Synchronize main tabs with actual edit state.
590 */
591 switch (cm) {
592 case MM_SIMULATE :
593 DoTcl("syncMainTabs Simulate");
594 break;
595 case MM_ANALYZE :
596 DoTcl("syncMainTabs CriticalPath");
597 break;
598 case MM_EDIT :
599 {
600 EditState *es = TkGate.circuit->es;
601 if (es && es->isInterface)
602 DoTcl("syncMainTabs EditInterfaces");
603 else
604 DoTcl("syncMainTabs Edit");
605 }
606 RescanHDLModules();
607 break;
608 }
609
610 SynchronizeInterface();
611
612 TkGate.idle_ev.pending = 0;
613 }
614
615 /*****************************************************************************
616 *
617 * This function is called to request that a redraw be performed the
618 * next time the tk event queue becomes empty.
619 *
620 *****************************************************************************/
FlagRedraw()621 void FlagRedraw()
622 {
623 TkGate.idle_ev.redraw = 1;
624 TkGate.idle_ev.scroll_area = 0;
625
626 if (!TkGate.idle_ev.pending) {
627 TkGate.idle_ev.pending = 1;
628 Tk_DoWhenIdle(idleGateWin,0);
629 }
630 }
631
632 /*****************************************************************************
633 *
634 * This function is called to request that scrolling be done the next time
635 * the tk event queue becomes empty. Calls to this function accumulate
636 * x and y change, and when the action is performed the combined scrolling
637 * action is performed.
638 *
639 *****************************************************************************/
FlagScrolling(void)640 void FlagScrolling(void)
641 {
642 if (!TkGate.idle_ev.redraw) {
643 TkGate.idle_ev.redraw = 1;
644 TkGate.idle_ev.scroll_area = 1;
645 }
646
647 if (!TkGate.idle_ev.pending) {
648 TkGate.idle_ev.pending = 1;
649 Tk_DoWhenIdle(idleGateWin,0);
650 }
651 }
652
653 /*****************************************************************************
654 *
655 * Handle an X event for the main tkgate window (primarily Exposure events)
656 * that hasn't already been handled elsewhere.
657 *
658 *****************************************************************************/
gateWinEvent(ClientData data,XEvent * E)659 static void gateWinEvent(ClientData data, XEvent *E)
660 {
661 #if TOUCH_XGATE_ED
662 ob_begin_framef("-WEvent",FF_TRANSPARENT);
663 #endif
664
665 switch (E->type) {
666 case DestroyNotify :
667 gateCleanUp();
668 break;
669 case GraphicsExpose :
670 if (TkGate.regionUpdate) {
671 XGraphicsExposeEvent *xE = &E->xgraphicsexpose;
672 editstate_regionUpdate(TkGate.circuit->es,xE->x,xE->y,xE->x+xE->width,xE->y+xE->height);
673 } else {
674 FlagRedraw();
675 }
676 break;
677 case Expose :
678 if (TkGate.regionUpdate) {
679 XExposeEvent *xE = &E->xexpose;
680 editstate_regionUpdate(TkGate.circuit->es,xE->x,xE->y,xE->x+xE->width,xE->y+xE->height);
681 } else {
682 FlagRedraw();
683 }
684 break;
685 case NoExpose :
686 break;
687 default :
688 FlagRedraw();
689 }
690 #if TOUCH_XGATE_ED
691 ob_end_frame();
692 #endif
693 }
694
695 /*****************************************************************************
696 *
697 * Update the positions of the scroll bars to reflect the new window visiblity.
698 *
699 *****************************************************************************/
scrollbar_update()700 void scrollbar_update()
701 {
702 int width = TkGate.width/TkGate.circuit->zoom_factor;
703 int height = TkGate.height/TkGate.circuit->zoom_factor;
704 int x0 = -TkGate.circuit->org_x;
705 int y0 = -TkGate.circuit->org_y;
706 int min_x = TkGate.ed->min_x;
707 int min_y = TkGate.ed->min_y;
708 int max_x = TkGate.ed->max_x;
709 int max_y = TkGate.ed->max_y;
710 double range_x = 1.0/(double)imax(10,max_x-min_x);
711 double range_y = 1.0/(double)imax(10,max_y-min_y);
712 double xb = 0.0;
713 double xe = 1.0;
714 double yb = 0.0;
715 double ye = 1.0;
716
717 xb = (x0 - min_x)*range_x;
718 xe = (x0 + width - min_x)*range_x;
719 yb = (y0 - min_y)*range_y;
720 ye = (y0 + height - min_y)*range_y;
721
722 if (xb < 0) xb = 0;
723 if (xe > 1) xe = 1;
724 if (yb < 0) yb = 0;
725 if (ye > 1) ye = 1;
726
727 if (min_x >= max_x) {
728 xb = yb = 0;
729 xe = ye = 1;
730 }
731
732 DoTcl("%s %lf %lf",TkGate.gw->xscroll,xb,xe);
733 DoTcl("%s %lf %lf",TkGate.gw->yscroll,yb,ye);
734 #if 0
735 printf("Y-Scroll: [%d..%d] (%d..%d) --> %s %lf %lf\n",min_y,max_y,y0,y0+TkGate.height,TkGate.gw->yscroll,yb,ye);
736 printf("X-Scroll: [%d..%d] (%d..%d) --> %s %lf %lf\n",min_x,max_x,x0,x0+TkGate.width ,TkGate.gw->xscroll,xb,xe);
737 #endif
738 }
739
740 /*****************************************************************************
741 *
742 * Get the bounding box and update the scroll bars to reflect it.
743 *
744 *****************************************************************************/
scrollbar_bbx_update()745 void scrollbar_bbx_update()
746 {
747 #if TOUCH_XGATE_ED
748 ob_touch(TkGate.ed);
749 #endif
750 GModuleDef_getBBX(TkGate.circuit->es->env, TD_X11,
751 &TkGate.ed->min_x,&TkGate.ed->max_x,
752 &TkGate.ed->min_y,&TkGate.ed->max_y);
753 scrollbar_update();
754 }
755
756
757 /*****************************************************************************
758 *
759 * Parse a scroll distance specification.
760 *
761 *****************************************************************************/
parseScrollDistance(int argc,const char * argv[],int org,int min_c,int max_c,int range_c,int * new_org_c)762 static int parseScrollDistance(int argc,const char *argv[],int org,int min_c,int max_c,int range_c,int *new_org_c)
763 {
764 int len = max_c - min_c;
765 int old_new_org_c = *new_org_c; /* Old value of coordinate update value */
766 int x;
767
768 if (argc == 1) { /* n */
769 sscanf(argv[0],"%d",&x);
770 } else if (argc == 2 && strcmp(argv[0],"press") == 0) { /* press n */
771 int b;
772 sscanf(argv[1],"%d",&b);
773
774 scrollbar_update();
775
776 TkGate.ed->scr_x = TkGate.circuit->org_x;
777 TkGate.ed->scr_y = TkGate.circuit->org_y;
778 } else if (argc == 2 && strcmp(argv[0],"moveto") == 0) { /* moveto n */
779 double dx;
780 sscanf(argv[1],"%lf",&dx);
781
782 *new_org_c = -(min_c + (int) (dx*len)) - imin(0,-org-min_c);
783
784
785 } else if (argc == 3 && strcmp(argv[0],"scroll") == 0 /* scroll n pages */
786 && strcmp(argv[2],"pages") == 0) {
787 double dx;
788 sscanf(argv[1],"%lf",&dx);
789
790 *new_org_c -= (int) (dx*len);
791 } else if (argc == 3 && strcmp(argv[0],"scroll") == 0 /* scroll n units */
792 && strcmp(argv[2],"units") == 0) {
793 double dx;
794 sscanf(argv[1],"%lf",&dx);
795
796 *new_org_c -= (int) (dx*50);
797 } else if (argc == 3 && strcmp(argv[0],"scroll") == 0 /* scroll n pixels */
798 && strcmp(argv[2],"pixels") == 0) {
799 double dx;
800 sscanf(argv[1],"%lf",&dx);
801
802 *new_org_c -= (int) (dx);
803 }
804
805 if (-*new_org_c > max_c + SCROLL_LIMIT)
806 *new_org_c = -(max_c + SCROLL_LIMIT);
807 if (-*new_org_c < min_c - range_c - SCROLL_LIMIT)
808 *new_org_c = -(min_c - range_c - SCROLL_LIMIT);
809
810
811 return old_new_org_c != *new_org_c;
812 }
813
814 /*****************************************************************************
815 *
816 * Parse an X distance scroll specification
817 *
818 *****************************************************************************/
parseXScrollDistance(int argc,const char * argv[])819 static int parseXScrollDistance(int argc,const char *argv[])
820 {
821 int x0 = TkGate.ed->scr_x;
822 int min_x = TkGate.ed->min_x;
823 int max_x = imax(TkGate.ed->max_x,TkGate.ed->min_x+TkGate.width/TkGate.circuit->zoom_factor);
824
825 return parseScrollDistance(argc,argv,x0,min_x,max_x,TkGate.width/TkGate.circuit->zoom_factor,
826 &TkGate.idle_ev.scroll_new_x);
827 }
828
829 /*****************************************************************************
830 *
831 * Parse an Y distance scroll specification
832 *
833 *****************************************************************************/
parseYScrollDistance(int argc,const char * argv[])834 static int parseYScrollDistance(int argc,const char *argv[])
835 {
836 int y0 = TkGate.ed->scr_y;
837 int min_y = TkGate.ed->min_y;
838 int max_y = imax(TkGate.ed->max_y,TkGate.ed->min_y+TkGate.height/TkGate.circuit->zoom_factor);
839
840 return parseScrollDistance(argc,argv,y0,min_y,max_y,TkGate.height/TkGate.circuit->zoom_factor,&TkGate.idle_ev.scroll_new_y);
841 }
842
843 /*
844 * Do a scrolling update in the circuit window.
845 */
doScroll(int dx,int dy)846 void doScroll(int dx,int dy)
847 {
848 /*
849 * If circuit is empty, return to default position.
850 */
851 if (TkGate.ed->min_x >= TkGate.ed->max_x) {
852 TkGate_setOrigin(0,0);
853 return;
854 }
855
856 if (dx != 0) {
857 int x1,y1,w,h,x2,y2;
858 int delta = -dx*TkGate.circuit->zoom_factor;
859
860 h = TkGate.height;
861 w = TkGate.width;
862 y1 = y2 = 0;
863 if (delta > 0) {
864 x1 = delta;
865 x2 = 0;
866 } else {
867 x1 = 0;
868 x2 = -delta;
869 }
870
871 XCopyArea(TkGate.D,TkGate.W,TkGate.W,TkGate.copyGC,x1,y1,w,h,x2,y2);
872
873 TkGate_setOrigin(TkGate.circuit->org_x + dx,TkGate.circuit->org_y);
874 if (delta > 0) {
875 editstate_regionUpdate(TkGate.circuit->es,w-delta-1,0,w+1,h+1);
876 } else {
877 editstate_regionUpdate(TkGate.circuit->es,0,0,-delta+1,h+1);
878 }
879 }
880 if (dy != 0) {
881 int x1,y1,w,h,x2,y2;
882 int delta = -dy*TkGate.circuit->zoom_factor;
883
884 h = TkGate.height;
885 w = TkGate.width;
886 x1 = x2 = 0;
887 if (delta > 0) {
888 y1 = delta;
889 y2 = 0;
890 } else {
891 y1 = 0;
892 y2 = -delta;
893 }
894
895 XCopyArea(TkGate.D,TkGate.W,TkGate.W,TkGate.copyGC,x1,y1,w,h,x2,y2);
896
897 TkGate_setOrigin(TkGate.circuit->org_x,TkGate.circuit->org_y + dy);
898 if (delta > 0) {
899 editstate_regionUpdate(TkGate.circuit->es,0,h-delta-1,w+1,h+1);
900 } else {
901 editstate_regionUpdate(TkGate.circuit->es,0,0,w+1,-delta+1);
902 }
903 }
904 }
905
906 /*****************************************************************************
907 *
908 * Respond to a tcl "window" command on the main edit window. Normally this
909 * is a scroll bar change notice.
910 *
911 *****************************************************************************/
gateWinCommand(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])912 static int gateWinCommand(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
913 {
914 TkgGateWin *gw = (TkgGateWin*) data;
915
916
917 if (strcmp(argv[1],"xview") == 0) {
918 TkGate.idle_ev.scroll_new_x = TkGate.circuit->org_x;
919 TkGate.idle_ev.scroll_new_y = TkGate.circuit->org_y;
920 if (parseXScrollDistance(argc-2,argv+2)) {
921 if (TkGate.smoothScroll) {
922 FlagScrolling();
923 } else {
924 ob_begin_framef("Scroll",FF_TRANSPARENT);
925 TkGate_setOrigin(TkGate.idle_ev.scroll_new_x,TkGate.circuit->org_y);
926 ob_end_frame();
927 FlagRedraw();
928 }
929 }
930 } else if (strcmp(argv[1],"yview") == 0) {
931 TkGate.idle_ev.scroll_new_x = TkGate.circuit->org_x;
932 TkGate.idle_ev.scroll_new_y = TkGate.circuit->org_y;
933 if (parseYScrollDistance(argc-2,argv+2)) {
934 if (TkGate.smoothScroll) {
935 FlagScrolling();
936 } else {
937 ob_begin_framef("Scroll",FF_TRANSPARENT);
938 TkGate_setOrigin(TkGate.circuit->org_x, TkGate.idle_ev.scroll_new_y);
939 ob_end_frame();
940 FlagRedraw();
941 }
942 }
943 } else if (argc == 3 && strcmp(argv[1],"cget") == 0) {
944 int i;
945
946 for (i = 0;i < numConfigSpecs;i++) {
947 Tk_ConfigSpec *C = &configSpecs[i];
948 if (C->type == TK_CONFIG_STRING && strcmp(C->argvName,argv[2]) == 0) {
949 char *value = *(char**)(((char*)gw) + C->offset);
950 Tcl_SetResult(tcl, value, TCL_VOLATILE);
951 break;
952 }
953 }
954 }
955
956 return TCL_OK;
957 }
958
959 /*****************************************************************************
960 *
961 * Called if our call to Tk_ConfigureWidget failed. It seems to be broken
962 * in some tcl/tk versions.
963 *
964 *****************************************************************************/
configWarning(int p)965 void configWarning(int p)
966 {
967 printf("\n- FATAL ERROR -\n\n");
968 printf("If you get this message, it probably means that Tk_ConfigureWidget is\n");
969 printf("broken on your machine. Try recompiling with TKGATE_BROKENCONFIGWIDGET\n");
970 printf("set to 1 in the top-level file config.h.\n");
971
972 exit(1);
973 }
974
975 /*****************************************************************************
976 *
977 * Callback function that is called when the size of the main window is changed
978 * by the user, normally be resizing with the mouse.
979 *
980 *****************************************************************************/
tkg_configMain(ClientData data,Tcl_Interp * tcl,int argc,const char ** argv)981 static int tkg_configMain(ClientData data, Tcl_Interp *tcl, int argc, const char **argv)
982 {
983 TkgGateWin *gw = (TkgGateWin *) data;
984
985 #if TKGATE_BROKENCONFIGWIDGET
986 char *wstr = Tcl_GetVar(TkGate.tcl,"tkg_initialWidth",TCL_GLOBAL_ONLY);
987 char *hstr = Tcl_GetVar(TkGate.tcl,"tkg_initialHeight",TCL_GLOBAL_ONLY);
988 if (wstr) sscanf(wstr,"%d",&gw->width);
989 if (hstr) sscanf(hstr,"%d",&gw->height);
990 gw->xscroll = ".horz set";
991 gw->yscroll = ".vert set";
992 gw->takefocus = 0;
993
994 Tk_SetWindowBackground(gw->win, XWhitePixelOfScreen(TkGate.S));
995 #else
996 signal(SIGBUS,configWarning);
997 signal(SIGSEGV,configWarning);
998
999 if (Tk_ConfigureWidget(tcl, gw->win, configSpecs, argc, argv, (char*) gw, 0) != TCL_OK)
1000 return TCL_ERROR;
1001
1002 Tk_SetWindowBackground(gw->win, gw->bgColor->pixel);
1003
1004 signal(SIGBUS,SIG_DFL);
1005 signal(SIGSEGV,SIG_DFL);
1006 #endif
1007
1008 Tk_GeometryRequest(gw->win,gw->width,gw->height);
1009
1010 if (gw->gc == None) {
1011 XGCValues gcv;
1012
1013 gcv.function = GXxor;
1014 gcv.graphics_exposures = False;
1015 gw->gc = Tk_GetGC(gw->win,GCFunction|GCGraphicsExposures, &gcv);
1016
1017 }
1018
1019 did_interface_resize = 1;
1020
1021 return TCL_OK;
1022 }
1023
1024 /*****************************************************************************
1025 *
1026 * Called when tkgate window is externally destroyed.
1027 *
1028 *****************************************************************************/
gateWinDestroy(ClientData data)1029 static void gateWinDestroy(ClientData data)
1030 {
1031 }
1032
1033 /*****************************************************************************
1034 * Process the command for creating the main tkgate circuit editing window.
1035 *
1036 * Usage: gatewin .w
1037 *
1038 *****************************************************************************/
tkg_gateWin(ClientData data,Tcl_Interp * tcl,int argc,const char ** argv)1039 static int tkg_gateWin(ClientData data, Tcl_Interp *tcl, int argc, const char **argv)
1040 {
1041 Tk_Window root = (Tk_Window) data;
1042 TkgGateWin *gw;
1043 Tk_Window w;
1044
1045 if (argc < 2) {
1046 Tcl_AppendResult(tcl, "wrong # args: should be \"",argv[0], " pathName ?options?\"", 0);
1047 return TCL_ERROR;
1048 }
1049
1050 w = Tk_CreateWindowFromPath(tcl, root, argv[1], 0);
1051 if (!w) return TCL_ERROR;
1052 Tk_SetClass(w, "GateWin");
1053
1054 gw = (TkgGateWin*) ob_malloc(sizeof(TkgGateWin),"TkgGateWin");
1055 gw->win = w;
1056 gw->d = Tk_Display(w);
1057 gw->tcl = tcl;
1058 gw->width = TKG_GATEWIN_WIDTH;
1059 gw->height = TKG_GATEWIN_HEIGHT;
1060 gw->gc = None;
1061 gw->bgColor = gw->fgColor = 0;
1062 gw->parms = &TkGate;
1063 gw->xscroll = 0;
1064 gw->yscroll = 0;
1065 gw->takefocus = 0;
1066 TkGate.gw = gw;
1067
1068 initGateParms(gw,&TkGate);
1069
1070 Tk_CreateEventHandler(w, ExposureMask|StructureNotifyMask,
1071 gateWinEvent, gw);
1072 Tcl_CreateCommand(tcl, Tk_PathName(w), gateWinCommand, gw, gateWinDestroy);
1073 if (tkg_configMain(gw, tcl, argc-2, argv+2) != TCL_OK) {
1074 Tk_DestroyWindow(w);
1075 return TCL_ERROR;
1076 }
1077
1078 setGCcolors();
1079
1080 Tcl_SetResult(tcl, Tk_PathName(w), TCL_STATIC);
1081
1082 return TCL_OK;
1083 }
1084
1085 /*****************************************************************************
1086 *
1087 * Do a tcl/tk script command. Arguments act like printf and are used to
1088 * construct the command before execution.
1089 *
1090 *****************************************************************************/
DoTcl(const char * str,...)1091 int DoTcl(const char *str,...)
1092 {
1093 char buf[1024];
1094 int r;
1095 va_list ap;
1096
1097 /*
1098 * Ignore tcl commands invoked before starting up the editor.
1099 */
1100 if (!TkGate.tcl) return TCL_OK;
1101
1102 va_start(ap,str);
1103
1104 vsprintf(buf,str,ap);
1105 r = Tcl_Eval(TkGate.tcl,buf);
1106 va_end(ap);
1107
1108 if (r != TCL_OK) {
1109 printf("DoTCL Error: %s\n",Tcl_GetStringResult(TkGate.tcl));
1110 // printf("DoTCL Error: %s\n",TkGate.tcl->result);
1111 printf(" while executing: %s\n",buf);
1112 }
1113
1114 return r;
1115 }
1116
1117 /*****************************************************************************
1118 *
1119 * Do a tcl/tk script command constructed from string objects.
1120 *
1121 *****************************************************************************/
DoTclL(const char * cmd,...)1122 int DoTclL(const char *cmd,...)
1123 {
1124 Tcl_Obj *objv[50];
1125 int n;
1126 int r;
1127 va_list ap;
1128
1129 objv[0] = Tcl_NewStringObj(cmd,strlen(cmd));
1130
1131 va_start(ap,cmd);
1132 for (n = 1;n < 50;n++) {
1133 char *s = va_arg(ap,char*);
1134 if (!s) break;
1135 objv[n] = Tcl_NewStringObj(s,strlen(s));
1136 }
1137 va_end(ap);
1138
1139 r = Tcl_EvalObjv(TkGate.tcl, n, objv, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL);
1140 /* Are the objects freed here? */
1141
1142 if (r != TCL_OK) {
1143 printf("tkgate: DoTclL Error - %s\n",Tcl_GetStringResult(TkGate.tcl));
1144 printf(" while executing: %s\n",cmd);
1145 }
1146
1147
1148 return r;
1149 }
1150
1151 /*****************************************************************************
1152 *
1153 * Do a tcl/tk script command constructed from string objects.
1154 *
1155 *****************************************************************************/
DoTclV(const char * cmd,int nargs,const char ** args)1156 int DoTclV(const char *cmd,int nargs,const char **args)
1157 {
1158 Tcl_Obj *objv[50];
1159 int n;
1160 int r;
1161
1162 objv[0] = Tcl_NewStringObj(cmd,strlen(cmd));
1163
1164 for (n = 1;n < 50;n++) {
1165 if (nargs-- <= 0) break;
1166 objv[n] = Tcl_NewStringObj(args[n-1],strlen(args[n-1]));
1167 }
1168
1169 r = Tcl_EvalObjv(TkGate.tcl, n, objv, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL);
1170 /* Are the objects freed here? */
1171
1172 if (r != TCL_OK) {
1173 printf("DoTclV Error: %s\n",Tcl_GetStringResult(TkGate.tcl));
1174 printf(" while executing: %s\n",cmd);
1175 }
1176
1177
1178 return r;
1179 }
1180
1181
1182
1183 /*****************************************************************************
1184 *
1185 * Handler function for button down events in the tkgate edit window.
1186 *
1187 *****************************************************************************/
tkg_buttonPress(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])1188 static int tkg_buttonPress(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
1189 {
1190 EditState *es = TkGate.circuit->es;
1191 int x,y,state,button;
1192
1193 click_count++;
1194
1195 DoTcl("tkg_cancel");
1196 DoTcl("tkg_undoSelections gate");
1197
1198 sscanf(argv[2],"%d",&x);
1199 sscanf(argv[3],"%d",&y);
1200 sscanf(argv[4],"%d",&state);
1201 sscanf(argv[5],"%d",&button);
1202
1203 if (button == 2) {
1204 TkGate.ed->saved_mode = EditState_getMode();
1205 DoTcl("ToolBar::selectTool 3");
1206 button = 1;
1207 }
1208
1209 TkGate.ed->rx = x;
1210 TkGate.ed->ry = y;
1211
1212 x /= TkGate.circuit->zoom_factor;
1213 y /= TkGate.circuit->zoom_factor;
1214
1215 TkGate.state = state;
1216 TkGate.button = button;
1217
1218 #if TOUCH_XGATE_ED
1219 ob_touch(TkGate.ed);
1220 #endif
1221 TkGate.ed->lx = TkGate.ed->tx;
1222 TkGate.ed->ly = TkGate.ed->ty;
1223 TkGate.ed->tx = wtoc_x(x);
1224 TkGate.ed->ty = wtoc_y(y);
1225
1226 /*
1227 * Check to see if we are selecting a hyperlink.
1228 */
1229 if (!(state & (ShiftMask|ControlMask))
1230 && (EditState_getMode() == MODE_MOVE)
1231 && Hyperlink_selectAt(TkGate.ed->tx,TkGate.ed->ty)) {
1232 return TCL_OK;
1233 }
1234
1235 /*
1236 * Special handling for scrolling mode
1237 */
1238 if (EditState_getMode() == MODE_SCROLL) {
1239 HandScroll_set(es);
1240 return TCL_OK;
1241 }
1242
1243 switch (tkgate_currentMode()) {
1244 case MM_SIMULATE :
1245 SimInterface_hit(&TkGate.circuit->simulator,TkGate.ed->tx,TkGate.ed->ty,0);
1246 break;
1247 case MM_ANALYZE :
1248 cpath_mouseDown(es);
1249 break;
1250 case MM_EDIT :
1251 ClearErrorMark();
1252 mark_unpost();
1253 EditState_selectobject(es);
1254 mark_post();
1255 break;
1256 }
1257
1258
1259 showSelectedName();
1260
1261 return TCL_OK;
1262 }
1263
1264 /*****************************************************************************
1265 *
1266 * Handler function for double clicks in the tkgate edit window.
1267 *
1268 *****************************************************************************/
tkg_buttonDoublePress(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])1269 static int tkg_buttonDoublePress(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
1270 {
1271 if (click_count < 1) return TCL_OK;
1272
1273 switch (tkgate_currentMode()) {
1274 case MM_SIMULATE :
1275 SimInterface_hit(&TkGate.circuit->simulator,TkGate.ed->tx,TkGate.ed->ty,1);
1276 break;
1277 case MM_ANALYZE :
1278 break;
1279 case MM_EDIT :
1280 if (EditState_getMode() == MODE_MOVE) {
1281 did_doubleclick = 1;
1282 }
1283 break;
1284 }
1285
1286 return TCL_OK;
1287 }
1288
1289 /*****************************************************************************
1290 *
1291 * Generate a checkpoint file name from the specified base filename.
1292 *
1293 *****************************************************************************/
getCheckpointFilename(char * checkPointFile,const char * fileName,size_t size)1294 int getCheckpointFilename(char *checkPointFile,const char *fileName,size_t size)
1295 {
1296 const char *p;
1297 char *q;
1298 /** @TODO to remove */
1299 /*
1300 int n;
1301 */
1302
1303 if (!fileName) {
1304 strcpy(checkPointFile,"#checkpoint#");
1305 return 0;
1306 }
1307
1308 if (strlen(fileName)+2 >= size)
1309 return -1;
1310
1311 /*
1312 * Start with a copy of the file name.
1313 */
1314 strcpy(checkPointFile,fileName);
1315
1316 /*
1317 * Find the base name of the file.
1318 */
1319 p = strrchr(fileName,'/');
1320 if (p) {
1321 p++;
1322 q = checkPointFile+(p-fileName);
1323 } else {
1324 p = fileName;
1325 q = checkPointFile;
1326 }
1327
1328 /*
1329 * The filename part of the path was empty (this condition
1330 * is probably not possible).
1331 */
1332 if (!*p) return -1;
1333
1334 /*
1335 * We are editing a checkpoint file, do not create further checkpoints.
1336 */
1337 if (*p == '#' && p[strlen(p)-1] == '#')
1338 return -1;
1339
1340
1341 /*
1342 * Create the checkpoint file name.
1343 */
1344 sprintf(q,"#%s#",p);
1345
1346 return 0;
1347 }
1348
1349 /*****************************************************************************
1350 *
1351 * Test if we want to write the checkpoint file and if so, write it.
1352 *
1353 *****************************************************************************/
doCheckpointTest()1354 static void doCheckpointTest()
1355 {
1356 extern int wantCheckpoint,checkpointenabled;
1357 const char *currentFile = CurrentFile_path(TkGate.circuit->currentFile);
1358
1359 if (wantCheckpoint && checkpointenabled && TkGate.changedp
1360 && !TkGate.circuit->discardChanges && currentFile) {
1361 char buf[STRMAX];
1362
1363 /* Generate checkpoint file name */
1364 if (getCheckpointFilename(buf,currentFile,STRMAX) == 0) {
1365 message(0,msgLookup("msg.wroteckpt"),buf); /* Checkpointed to %s... */
1366 VerilogWriteModules(buf,VSO_NOHDLCHECK); /* Write the checkpoint file */
1367 }
1368 }
1369
1370 wantCheckpoint = 0;
1371 }
1372
checkMouseoverAction(int x,int y)1373 static void checkMouseoverAction(int x,int y)
1374 {
1375 EditState *es = TkGate.circuit->es;
1376 int tx = wtoc_x(x);
1377 int ty = wtoc_y(y);
1378 const char *link = 0;
1379 static const char *visible_link = 0;
1380
1381 if (EditState_getMode() == MODE_MOVE)
1382 link = Hyperlink_getAt(tx,ty);
1383
1384 if (link) {
1385 MouseoverCursor(HYPERLINKCURSOR);
1386 } else if (tkgate_currentMode() == MM_EDIT && EditState_getMode() == MODE_MOVE) {
1387 GCElement *g = gate_hit(es->env,tx,ty);
1388 GWireNode *n = wire_hit(tx,ty,es->env->m_wires);
1389
1390 int pside = PSIDE_UNKNOWN;
1391
1392 if (!n && g && GCElement_getType(g) == GC_BLOCK) {
1393 pside = Block_HitEdge(g,tx,ty);
1394 }
1395
1396 switch (pside) {
1397 case PSIDE_LEFT :
1398 MouseoverCursor(ADDPORTLEFT);
1399 break;
1400 case PSIDE_RIGHT :
1401 MouseoverCursor(ADDPORTRIGHT);
1402 break;
1403 case PSIDE_BOTTOM :
1404 MouseoverCursor(ADDPORTBOTTOM);
1405 break;
1406 case PSIDE_TOP :
1407 MouseoverCursor(ADDPORTTOP);
1408 break;
1409 default :
1410 MouseoverCursor(CANCELMOUSEOVER);
1411 break;
1412 }
1413 } else
1414 MouseoverCursor(CANCELMOUSEOVER);
1415
1416
1417 /*
1418 * Update the status line if mouse is over a link
1419 */
1420 if (link != visible_link) {
1421 if (link)
1422 message(0,link);
1423 else
1424 message(0,"");
1425
1426 visible_link = link;
1427 }
1428 }
1429
1430
1431 /*****************************************************************************
1432 *
1433 * Handler function for button release events in the tkgate edit window.
1434 *
1435 *****************************************************************************/
tkg_buttonRelease(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])1436 static int tkg_buttonRelease(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
1437 {
1438 EditState *es = TkGate.circuit->es;
1439 int x,y,state;
1440 int ret = TCL_OK;
1441
1442 DoTcl("tkg_hideTempMessage");
1443
1444 sscanf(argv[2],"%d",&x);
1445 sscanf(argv[3],"%d",&y);
1446 sscanf(argv[4],"%d",&state);
1447
1448 TkGate.ed->rx = x;
1449 TkGate.ed->ry = y;
1450
1451 x /= TkGate.circuit->zoom_factor;
1452 y /= TkGate.circuit->zoom_factor;
1453
1454 TkGate.state = state;
1455 TkGate.button = -1;
1456 #if TOUCH_XGATE_ED
1457 ob_touch(TkGate.ed);
1458 #endif
1459 TkGate.ed->lx = TkGate.ed->tx;
1460 TkGate.ed->ly = TkGate.ed->ty;
1461 TkGate.ed->tx = wtoc_x(x);
1462 TkGate.ed->ty = wtoc_y(y);
1463
1464 if (TkGate.circuit->select || TkGate.circuit->nsel)
1465 message(0,"");
1466
1467 if (EditState_getMode() == MODE_SCROLL) {
1468 HandScroll_drop(es);
1469 wm_SetCursor(SCROLLCURSOR);
1470
1471 if (TkGate.ed->saved_mode >= 0) {
1472 DoTcl("ToolBar::selectTool %d",TkGate.ed->saved_mode);
1473 TkGate.ed->saved_mode = -1;
1474 }
1475 return TCL_OK;
1476 }
1477
1478 switch (tkgate_currentMode()) {
1479 case MM_SIMULATE :
1480 SimInterface_hitRelease(&TkGate.circuit->simulator);
1481 ret = TCL_OK;
1482 break;
1483 case MM_ANALYZE :
1484 cpath_mouseUp(es);
1485 ret = TCL_OK;
1486 break;
1487 case MM_EDIT :
1488 mark_unpost();
1489
1490 EditState_dropobject(es);
1491 ob_touch(TkGate.circuit);
1492 TkGate.circuit->wnsel = NULL;
1493 TkGate.circuit->wsel = NULL;
1494
1495 if (es->isInterface && did_interface_resize) {
1496 modint_arrange(es);
1497 FlagRedraw();
1498 did_interface_resize = 0;
1499 }
1500
1501 if (did_doubleclick && EditState_getMode() == MODE_MOVE) {
1502 GCElement *g;
1503 GWire *w;
1504 EditState_selectobject(es);
1505 g = TkGate.circuit->select;
1506 w = TkGate.circuit->wsel;
1507 EditState_dropobject(es);
1508 mark_unpost();
1509
1510 if (g) {
1511 ob_suggest_name("EditProps");
1512 DoTcl("gat_editProps");
1513 } else if (w) {
1514 if (!es->isInterface) {
1515 ob_suggest_name("EditProps");
1516 net_editProps(w->net,TkGate.ed->tx,TkGate.ed->ty);
1517 }
1518 }
1519 }
1520
1521 did_doubleclick = 0;
1522
1523 doCheckpointTest();
1524
1525 scrollbar_bbx_update();
1526
1527 ret = TCL_OK;
1528 break;
1529 }
1530
1531 if (debugContinuousVerify)
1532 verify_circuit();
1533
1534 SynchronizeInterface();
1535
1536 checkMouseoverAction(x,y);
1537
1538 Hyperlink_confirmAt(TkGate.ed->tx,TkGate.ed->ty);
1539
1540 return ret;
1541 }
1542
1543
1544 /*****************************************************************************
1545 *
1546 * Handler function for button motion events in the tkgate edit window.
1547 *
1548 *****************************************************************************/
tkg_buttonMotion(ClientData data,Tcl_Interp * tcl,int argc,const char * argv[])1549 static int tkg_buttonMotion(ClientData data, Tcl_Interp *tcl, int argc, const char *argv[])
1550 {
1551 EditState *es = TkGate.circuit->es;
1552 int x,y,state;
1553
1554 if (Hyperlink_isPending()) return TCL_OK;
1555
1556 sscanf(argv[2],"%d",&x);
1557 sscanf(argv[3],"%d",&y);
1558 sscanf(argv[4],"%d",&state);
1559
1560 TkGate.ed->rx = x;
1561 TkGate.ed->ry = y;
1562
1563 x /= TkGate.circuit->zoom_factor;
1564 y /= TkGate.circuit->zoom_factor;
1565
1566 /*
1567 * Mouseover cursor handling if no buttons are pressed
1568 */
1569 if (!(state & (Button1Mask|Button2Mask|Button3Mask))) {
1570 checkMouseoverAction(x,y);
1571 return TCL_OK;
1572 }
1573
1574 /*
1575 * Only track button 1 or 2 motin
1576 */
1577 if (!(state & (Button1Mask|Button2Mask)))
1578 return TCL_OK;
1579
1580
1581 /*
1582 * Special handling for scrolling
1583 */
1584 if (EditState_getMode() == MODE_SCROLL) {
1585 HandScroll_move(es);
1586 return TCL_OK;
1587 }
1588
1589 switch (tkgate_currentMode()) {
1590 case MM_SIMULATE :
1591 break;
1592 case MM_ANALYZE :
1593 break;
1594 case MM_EDIT :
1595 TkGate.state = state;
1596 #if TOUCH_XGATE_ED
1597 ob_touch(TkGate.ed);
1598 #endif
1599 TkGate.ed->lx = TkGate.ed->tx;
1600 TkGate.ed->ly = TkGate.ed->ty;
1601 TkGate.ed->tx = wtoc_x(x);
1602 TkGate.ed->ty = wtoc_y(y);
1603
1604 EditState_moveobject(es);
1605
1606 break;
1607 }
1608
1609 return TCL_OK;
1610 }
1611
1612 /*****************************************************************************
1613 *
1614 * Clear the selection.
1615 *
1616 *****************************************************************************/
TkGate_clearSelection()1617 void TkGate_clearSelection()
1618 {
1619 #if TOUCH_XGATE_ED
1620 ob_touch(TkGate.ed);
1621 #endif
1622 TkGate.ed->tx = TkGate.ed->ty = TkGate.ed->lx = TkGate.ed->ly = TkGate.ed->sx = TkGate.ed->sy = 0;
1623 TkGate.circuit->select = 0;
1624 TkGate.circuit->last = 0;
1625 TkGate.circuit->wsel = 0;
1626 TkGate.circuit->wnsel = 0;
1627 TkGate.circuit->nsel = 0;
1628 }
1629
1630 /*****************************************************************************
1631 *
1632 * Set up widget for the main tkgate window.
1633 *
1634 *****************************************************************************/
init_mainWindow(Tcl_Interp * tcl)1635 void init_mainWindow(Tcl_Interp *tcl)
1636 {
1637 Tk_Window root = Tk_MainWindow(tcl);
1638 Tk_MakeWindowExist(root);
1639
1640 TkGate.circuit = new_Circuit();
1641 TkGate.ed = (EditData*) ob_malloc(sizeof(EditData),"EditData");
1642 TkGate.ed->mark_vis = 0;
1643 TkGate.ed->mark_posted = 0;
1644 TkGate.ed->major_mode = MM_EDIT;
1645 TkGate.ed->saved_mode = -1;
1646 TkGate.errl = new_ErrorList();
1647 TkGate.tcl = tcl;
1648 TkGate.D = Tk_Display(root);
1649 TkGate.root = Tk_WindowId(root);
1650 TkGate.S = XDefaultScreenOfDisplay(TkGate.D);
1651 TkGate.CM = DefaultColormapOfScreen(TkGate.S);
1652 TkGate.ScopeW = None;
1653 TkGate.bitorder = XBitmapBitOrder(TkGate.D);
1654 TkGate.byteorder = XImageByteOrder(TkGate.D);
1655 TkGate.rdb = XrmGetDatabase(TkGate.D);
1656 TkGate.ErrorMarkTimeout = 0;
1657
1658 TkGate_clearSelection();
1659
1660 SimInterface_init(&TkGate.circuit->simulator);
1661
1662 if (sync_Xserver) {
1663 printf("[synchronized X11 connection]\n");
1664 XSynchronize(TkGate.D,True);
1665 }
1666
1667 initGCs();
1668
1669 Tcl_CreateCommand(tcl,"gat_scope"
1670 ,gat_scope
1671 ,(ClientData)root
1672 ,0);
1673
1674 Tcl_CreateCommand(tcl,"tkg_gatewin"
1675 ,tkg_gateWin
1676 ,(ClientData)root
1677 ,0);
1678
1679 Tcl_CreateCommand(tcl,"tkg_configMain"
1680 ,tkg_configMain
1681 ,(ClientData)root
1682 ,0);
1683
1684 Tcl_CreateCommand(tcl,"tkg_buttonPress"
1685 ,tkg_buttonPress
1686 ,(ClientData)root
1687 ,0);
1688
1689 Tcl_CreateCommand(tcl,"tkg_buttonDoublePress"
1690 ,tkg_buttonDoublePress
1691 ,(ClientData)root
1692 ,0);
1693
1694 Tcl_CreateCommand(tcl,"tkg_buttonRelease"
1695 ,tkg_buttonRelease
1696 ,(ClientData)root
1697 ,0);
1698
1699 Tcl_CreateCommand(tcl,"tkg_buttonMotion"
1700 ,tkg_buttonMotion
1701 ,(ClientData)root
1702 ,0);
1703 }
1704
1705