1# This is the "Magic wrapper".
2# Its main purpose is to redefine the "openwindow" command in magic so that
3# opening a new window creates a window wrapped by a GUI interface.
4#
5# Written by Tim Edwards, August 23, 2002.
6
7# revision A: proof-of-concept.  Add whatever you want to this basic wrapper.
8# revision B: Adds Tk scrollbars and caption
9# revision C: Adds a layer manager toolbar on the left side
10# revision D: Adds a menubar on top with cell and tech manager tools
11
12global lwindow
13global tk_version
14global Glyph
15global Opts
16global Winopts
17
18set tk_version $::tk_version
19# Simple console commands (like TkCon, but much simpler)
20
21if {[lsearch [namespace children] ::tkshell] < 0} {
22   catch {source ${CAD_ROOT}/magic/tcl/tkshell.tcl}
23}
24
25proc magic::makeglyphimages {} {
26    global Opts
27    global Glyph
28    global CAD_ROOT
29
30    # Check if glyphs exist---don't need to make them more than once
31    if {![catch {set Glyph(up)}]} {return}
32
33    # Glyph images
34
35    set gsize [expr {int($Opts(scale) * 13)}]
36    set gscale [expr {int($Opts(scale))}]
37
38    image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/up.gif
39    image create photo Glyph(up) -width $gsize -height $gsize
40    Glyph(up) copy stdglyph -zoom $gscale
41
42    image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/down.gif
43    image create photo Glyph(down) -width $gsize -height $gsize
44    Glyph(down) copy stdglyph -zoom $gscale
45
46    image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/left.gif
47    image create photo Glyph(left) -width $gsize -height $gsize
48    Glyph(left) copy stdglyph -zoom $gscale
49
50    image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/right.gif
51    image create photo Glyph(right) -width $gsize -height $gsize
52    Glyph(right) copy stdglyph -zoom $gscale
53
54    image create photo stdglyph -file ${CAD_ROOT}/magic/tcl/bitmaps/zoom.gif
55    image create photo Glyph(zoom) -width $gsize -height $gsize
56    Glyph(zoom) copy stdglyph -zoom $gscale
57
58    image create bitmap Glyph(lock) \
59	-file ${CAD_ROOT}/magic/tcl/bitmaps/lock.xbm \
60	-background gray80 -foreground steelblue4]
61}
62
63# Menu button callback functions
64
65proc magic::promptload {type} {
66   global CAD_ROOT
67
68   switch $type {
69      cif { set Layoutfilename [ tk_getOpenFile -filetypes \
70		{{CIF {.cif {.cif}}} {"All files" {*}}}]
71	    if {$Layoutfilename != ""} {
72		set cifname [file tail [file root $Layoutfilename]]
73		magic::cellname create cif_temp
74		magic::load cif_temp
75		magic::cif read [file root $Layoutfilename]
76		set childcells [magic::cellname list children cif_temp]
77		magic::load [lindex $childcells 0]
78		magic::cellname delete cif_temp -noprompt
79		if {[llength $childcells] > 1} {
80		   puts stdout "Cells read from GDS file: $childcells"
81		}
82	     }
83	  }
84      gds { set Layoutfilename [ tk_getOpenFile -filetypes \
85		{{GDS {.gds .strm .cal {.gds .strm .cal}}} {"All files" {*}}}]
86	    if {$Layoutfilename != ""} {
87		set origlist [magic::cellname list top]
88		magic::gds read [file root $Layoutfilename]
89		set newlist [magic::cellname list top]
90
91		# Find entries in newlist that are not in origlist.
92		# If there's only one, load it into the window.
93
94		set newtopcells {}
95		foreach n $newlist {
96		   if {[lsearch $origlist $n] < 0} {
97		      lappend newtopcells $n
98		   }
99		}
100		if {[llength $newtopcells] == 1} {
101		   magic::load [lindex $newtopcells 0]
102		} elseif {[llength $newtopcells] != 0} {
103		   puts stdout "Top-level cells read from GDS file: $newtopcells"
104		}
105	    }
106	  }
107      magic { set Layoutfilename [ tk_getOpenFile -filetypes \
108		{{Magic {.mag {.mag}}} {"All files" {*}}}]
109	    if {$Layoutfilename != ""} {
110		magic::load [file root $Layoutfilename]
111	    }
112	  }
113
114      getcell { set Layoutfilename [ tk_getOpenFile -filetypes \
115		{{Magic {.mag {.mag}}} {"All files" {*}}}]
116	    if {$Layoutfilename != ""} {
117		set fdir [file dirname $Layoutfilename]
118		set lidx [lsearch [path search] $fdir]
119		if {$lidx < 0} {path search +$fdir}
120		magic::getcell [file tail $Layoutfilename]
121
122		# Append path to cell search path if it's not there already
123
124		if {[string index $Layoutfilename 0] != "/"} {
125		   set $Layoutfilename "./$Layoutfilename"
126		}
127		set sidx [string last "/" $Layoutfilename]
128		if {$sidx > 0} {
129		   set cellpath [string range $Layoutfilename 0 $sidx]
130		   magic::path cell +$cellpath
131		}
132	    }
133	  }
134   }
135}
136
137proc magic::promptsave {type} {
138   global CAD_ROOT
139
140   switch $type {
141      cif { set Layoutfilename [ tk_getSaveFile -filetypes \
142		{{CIF {.cif {.cif}}} {"All files" {*}}}]
143	    if {$Layoutfilename != ""} {
144	       magic::cif write $Layoutfilename
145	    }
146	  }
147      gds { set Layoutfilename [ tk_getSaveFile -filetypes \
148		{{GDS {.gds .strm .cal {.gds .strm .cal}}} {"All files" {*}}}]
149	    if {$Layoutfilename != ""} {
150		magic::gds write $Layoutfilename
151	    }
152	  }
153      force -
154      magic {
155	    set CellList [ magic::cellname list window ]
156	    if {[lsearch $CellList "(UNNAMED)"] >= 0} {
157	       set Layoutfilename [ tk_getSaveFile -filetypes \
158		   {{Magic {.mag {.mag}}} {"All files" {*}}} \
159		   -title "Save cell (UNNAMED) as:" ]
160	       if {$Layoutfilename != ""} {
161		   set cellpath [file dirname $Layoutfilename]
162		   if {$cellpath == [pwd]} {
163		      set Layoutfilename [file tail $Layoutfilename]
164		   } else {
165		      magic::path cell +$cellpath
166		   }
167		   magic::save $Layoutfilename
168	       }
169	    }
170	    if {$type == "force"} {
171	       magic::writeall force
172	    } else {
173	       magic::writeall
174	    }
175	  }
176   }
177}
178
179# Window to prompt for a new cell
180
181proc magic::prompt_dialog { type } {
182   global Opts
183
184   if {[catch {toplevel .dialog}]} {
185      foreach child [winfo children .dialog] {
186         destroy $child
187      }
188   }
189
190   frame .dialog.titlebar
191   frame .dialog.text
192   frame .dialog.bbar
193
194   switch $type {
195      new {
196         label .dialog.titlebar.title -text "Create new cell" -foreground blue
197         button .dialog.bbar.okay -text "Okay" -command {load $Opts(cell_name); \
198		lower .dialog}
199         set Opts(cell_name) "(UNNAMED)"
200      }
201      save {
202         label .dialog.titlebar.title -text "Save cell as..." -foreground blue
203         button .dialog.bbar.okay -text "Okay" -command {save $Opts(cell_name); \
204		lower .dialog}
205         set Opts(cell_name) [cellname list window]
206      }
207   }
208   pack .dialog.titlebar.title
209
210   label .dialog.text.tlabel -text "Cell name:" -foreground brown
211   entry .dialog.text.tentry -background white -textvariable Opts(cell_name)
212
213   pack .dialog.text.tlabel -side left
214   pack .dialog.text.tentry -side left
215
216   button .dialog.bbar.cancel -text "Cancel" -command "lower .dialog"
217
218   pack .dialog.bbar.okay -side left
219   pack .dialog.bbar.cancel -side right
220
221   pack .dialog.titlebar -side top -ipadx 2 -ipady 2
222   pack .dialog.text -side top -fill both -expand true
223   pack .dialog.bbar -side top -fill x -ipadx 5
224
225   bind .dialog.text.tentry <Return> {.dialog.bbar.okay invoke}
226
227   raise .dialog
228}
229
230# Callback functions used by the DRC.
231
232proc magic::drcupdate { option } {
233   global Opts
234   if {[info level] <= 1} {
235      switch $option {
236         on {set Opts(drc) 1}
237         off {set Opts(drc) 0}
238      }
239   }
240}
241
242proc magic::drcstate { status } {
243   set winlist [*bypass windownames layout]
244   foreach lwin $winlist {
245      set framename [winfo parent $lwin]
246      if {$framename == "."} {return}
247      switch $status {
248         idle {
249		set dct [*bypass drc list count total]
250		if {$dct > 0} {
251	           ${framename}.titlebar.drcbutton configure -selectcolor red
252		} else {
253	           ${framename}.titlebar.drcbutton configure -selectcolor green
254		}
255	        ${framename}.titlebar.drcbutton configure -text "DRC=$dct"
256	      }
257         busy { ${framename}.titlebar.drcbutton configure -selectcolor yellow }
258      }
259   }
260}
261
262# Create the menu of windows.  This is kept separate from the cell manager,
263# and linked into it by the "clone" command.
264
265menu .winmenu -tearoff 0
266
267proc magic::setgrid {gridsize} {
268   set techlambda [magic::tech lambda]
269   set tech1 [lindex $techlambda 1]
270   set tech0 [lindex $techlambda 0]
271   set tscale [expr {$tech1 / $tech0}]
272   set lambdaout [expr {[magic::cif scale output] * $tscale}]
273   set gridlambda [expr {$gridsize/$lambdaout}]
274   magic::grid ${gridlambda}l
275   magic::snap on
276}
277
278# Technology manager callback functions
279
280proc magic::techparseunits {} {
281   set techlambda [magic::tech lambda]
282   set tech1 [lindex $techlambda 1]
283   set tech0 [lindex $techlambda 0]
284
285   set target0 [.techmgr.lambda1.lval0 get]
286   set target1 [.techmgr.lambda1.lval1 get]
287
288   set newval0 [expr {$target0 * $tech0}]
289   set newval1 [expr {$target1 * $tech1}]
290
291   magic::scalegrid $newval1 $newval0
292   magic::techmanager update
293}
294
295# The technology manager
296
297proc magic::maketechmanager { mgrpath } {
298   toplevel $mgrpath
299   wm withdraw $mgrpath
300
301   frame ${mgrpath}.title
302   label ${mgrpath}.title.tlab -text "Technology: "
303   menubutton ${mgrpath}.title.tname -text "(none)" -foreground red3 \
304	-menu ${mgrpath}.title.tname.menu
305   label ${mgrpath}.title.tvers -text "" -foreground blue
306   label ${mgrpath}.subtitle -text "" -foreground sienna4
307
308   frame ${mgrpath}.lambda0
309   label ${mgrpath}.lambda0.llab -text "Microns per lambda (CIF): "
310   label ${mgrpath}.lambda0.lval -text "1" -foreground blue
311
312   frame ${mgrpath}.lambda1
313   label ${mgrpath}.lambda1.llab -text "Internal units per lambda: "
314   entry ${mgrpath}.lambda1.lval0 -foreground red3 -background white -width 3
315   label ${mgrpath}.lambda1.ldiv -text " / "
316   entry ${mgrpath}.lambda1.lval1 -foreground red3 -background white -width 3
317
318   frame ${mgrpath}.cif0
319   label ${mgrpath}.cif0.llab -text "CIF input style: "
320   menubutton ${mgrpath}.cif0.lstyle -text "" -foreground blue \
321	-menu ${mgrpath}.cif0.lstyle.menu
322   label ${mgrpath}.cif0.llab2 -text " Microns/lambda="
323   label ${mgrpath}.cif0.llambda -text "" -foreground red3
324
325   frame ${mgrpath}.cif1
326   label ${mgrpath}.cif1.llab -text "CIF output style: "
327   menubutton ${mgrpath}.cif1.lstyle -text "" -foreground blue \
328	-menu ${mgrpath}.cif1.lstyle.menu
329   label ${mgrpath}.cif1.llab2 -text " Microns/lambda="
330   label ${mgrpath}.cif1.llambda -text "" -foreground red3
331
332   frame ${mgrpath}.extract
333   label ${mgrpath}.extract.llab -text "Extract style: "
334   menubutton ${mgrpath}.extract.lstyle -text "" -foreground blue \
335	-menu ${mgrpath}.extract.lstyle.menu
336
337   frame ${mgrpath}.drc
338   label ${mgrpath}.drc.llab -text "DRC style: "
339   menubutton ${mgrpath}.drc.lstyle -text "" -foreground blue \
340	-menu ${mgrpath}.drc.lstyle.menu
341
342   pack ${mgrpath}.title.tlab -side left
343   pack ${mgrpath}.title.tname -side left
344   pack ${mgrpath}.title.tvers -side left
345   pack ${mgrpath}.lambda0.llab -side left
346   pack ${mgrpath}.lambda0.lval -side left
347   pack ${mgrpath}.lambda1.llab -side left
348   pack ${mgrpath}.lambda1.lval0 -side left
349   pack ${mgrpath}.lambda1.ldiv -side left
350   pack ${mgrpath}.lambda1.lval1 -side left
351   pack ${mgrpath}.cif0.llab -side left
352   pack ${mgrpath}.cif0.lstyle -side left
353   pack ${mgrpath}.cif0.llab2 -side left
354   pack ${mgrpath}.cif0.llambda -side left
355   pack ${mgrpath}.cif1.llab -side left
356   pack ${mgrpath}.cif1.lstyle -side left
357   pack ${mgrpath}.cif1.llab2 -side left
358   pack ${mgrpath}.cif1.llambda -side left
359   pack ${mgrpath}.extract.llab -side left
360   pack ${mgrpath}.extract.lstyle -side left
361   pack ${mgrpath}.drc.llab -side left
362   pack ${mgrpath}.drc.lstyle -side left
363
364   pack ${mgrpath}.title -side top -fill x
365   pack ${mgrpath}.subtitle -side top -fill x
366   pack ${mgrpath}.lambda0 -side top -fill x
367   pack ${mgrpath}.lambda1 -side top -fill x
368   pack ${mgrpath}.cif0 -side top -fill x
369   pack ${mgrpath}.cif1 -side top -fill x
370   pack ${mgrpath}.extract -side top -fill x
371
372   bind ${mgrpath}.lambda1.lval0 <Return> magic::techparseunits
373   bind ${mgrpath}.lambda1.lval1 <Return> magic::techparseunits
374
375   #Withdraw the window when the close button is pressed
376   wm protocol ${mgrpath} WM_DELETE_WINDOW  "set Opts(techmgr) 0 ; wm withdraw ${mgrpath}"
377}
378
379# Generate the cell manager
380
381catch {source ${CAD_ROOT}/magic/tcl/cellmgr.tcl}
382
383# Generate the library manager
384
385catch {source ${CAD_ROOT}/magic/tcl/libmgr.tcl}
386
387# Generate the DRC manager
388
389catch {source ${CAD_ROOT}/magic/tcl/drcmgr.tcl}
390
391# Generate the text helper
392
393catch {source ${CAD_ROOT}/magic/tcl/texthelper.tcl}
394
395# Create or redisplay the technology manager
396
397proc magic::techmanager {{option "update"}} {
398   global CAD_ROOT
399
400   if {[catch {wm state .techmgr}]} {
401      if {$option == "create"} {
402	 magic::maketechmanager .techmgr
403      } else {
404	 return
405      }
406   } elseif { $option == "create"} {
407      return
408   }
409
410   if {$option == "create"} {
411      menu .techmgr.title.tname.menu -tearoff 0
412      menu .techmgr.cif0.lstyle.menu -tearoff 0
413      menu .techmgr.cif1.lstyle.menu -tearoff 0
414      menu .techmgr.extract.lstyle.menu -tearoff 0
415      menu .techmgr.drc.lstyle.menu -tearoff 0
416
417   }
418
419   if {$option == "init"} {
420	.techmgr.title.tname.menu delete 0 end
421	.techmgr.cif0.lstyle.menu delete 0 end
422	.techmgr.cif1.lstyle.menu delete 0 end
423	.techmgr.extract.lstyle.menu delete 0 end
424	.techmgr.drc.lstyle.menu delete 0 end
425   }
426
427   if {$option == "init" || $option == "create"} {
428      set tlist [magic::cif listall istyle]
429      foreach i $tlist {
430	 .techmgr.cif0.lstyle.menu add command -label $i -command \
431		"magic::cif istyle $i ; \
432		 magic::techmanager update"
433      }
434
435      set tlist [magic::cif listall ostyle]
436      foreach i $tlist {
437	 .techmgr.cif1.lstyle.menu add command -label $i -command \
438		"magic::cif ostyle $i ; \
439		 magic::techmanager update"
440      }
441
442      set tlist [magic::extract listall style]
443      foreach i $tlist {
444	 .techmgr.extract.lstyle.menu add command -label $i -command \
445		"magic::extract style $i ; \
446		 magic::techmanager update"
447      }
448
449      set tlist [magic::drc listall style]
450      foreach i $tlist {
451	 .techmgr.drc.lstyle.menu add command -label $i -command \
452		"magic::drc style $i ; \
453		 magic::techmanager update"
454      }
455
456      set dirlist [subst [magic::path sys]]
457      set tlist {}
458      foreach i $dirlist {
459	 lappend tlist [glob -nocomplain ${i}/*.tech]
460	 lappend tlist [glob -nocomplain ${i}/*.tech27]
461      }
462      foreach i [join $tlist] {
463	 set j [file tail [file rootname ${i}]]
464	 .techmgr.title.tname.menu add command -label $j -command \
465		"magic::tech load $j ; \
466		 magic::techmanager update"
467      }
468   }
469
470   set techlambda [magic::tech lambda]
471   set tech1 [lindex $techlambda 1]
472   set tech0 [lindex $techlambda 0]
473   set tscale [expr {$tech1 / $tech0}]
474
475   .techmgr.title.tname configure -text [magic::tech name]
476   set techstuff [magic::tech version]
477   .techmgr.title.tvers configure -text "(version [lindex $techstuff 0])"
478   .techmgr.subtitle configure -text [lindex $techstuff 1]
479   set lotext [format "%g" [expr {[magic::cif scale output] * $tscale}]]
480   .techmgr.lambda0.lval configure -text $lotext
481   .techmgr.cif0.lstyle configure -text [magic::cif list istyle]
482   set litext [format "%g" [expr {[magic::cif scale input] * $tscale}]]
483   .techmgr.cif0.llambda configure -text $litext
484   .techmgr.cif1.lstyle configure -text [magic::cif list ostyle]
485   .techmgr.cif1.llambda configure -text $lotext
486   .techmgr.extract.lstyle configure -text [magic::extract list style]
487   .techmgr.drc.lstyle configure -text [magic::drc list style]
488
489   .techmgr.lambda1.lval0 delete 0 end
490   .techmgr.lambda1.lval1 delete 0 end
491   .techmgr.lambda1.lval0 insert end $tech1
492   .techmgr.lambda1.lval1 insert end $tech0
493}
494
495proc magic::captions {{subcommand {}}} {
496   global Opts
497
498   if {$subcommand != {} && $subcommand != "writeable" && $subcommand != "load"} {
499      return
500   }
501   set winlist [magic::windownames layout]
502   foreach winpath $winlist {
503      set framename [winfo parent $winpath]
504      set caption [$winpath windowcaption]
505      set subcaption1 [lindex $caption 0]
506      set techname [tech name]
507      if {[catch {set Opts(tool)}]} {
508         set Opts(tool) unknown
509      }
510      if {[lindex $caption 1] == "EDITING"} {
511         set subcaption2 [lindex $caption 2]
512      } else {
513         # set subcaption2 [join [lrange $caption 1 end]]
514         set subcaption2 $caption
515      }
516      ${framename}.titlebar.caption configure -text \
517	   "Loaded: ${subcaption1} Editing: ${subcaption2} Tool: $Opts(tool) \
518	   Technology: ${techname}"
519   }
520}
521
522# Allow captioning in the title window by tagging the "load" and "edit" commands
523# Note that the "box" tag doesn't apply to mouse-button events, so this function
524# is duplicated by Tk binding of mouse events in the layout window.
525
526magic::tag load "[magic::tag load]; magic::captions"
527magic::tag edit "magic::captions"
528magic::tag save "magic::captions"
529magic::tag down "magic::captions"
530magic::tag box "magic::boxview %W %1"
531magic::tag move "magic::boxview %W"
532magic::tag scroll "magic::scrollupdate %W"
533magic::tag view "magic::scrollupdate %W"
534magic::tag zoom "magic::scrollupdate %W"
535magic::tag findbox "magic::scrollupdate %W"
536magic::tag see "magic::toolupdate %W %1 %2"
537magic::tag tech "magic::techrebuild %W %1; magic::captions %1"
538magic::tag drc "magic::drcupdate %1"
539magic::tag path "[magic::tag path]; magic::techmanager update"
540magic::tag cellname "magic::mgrupdate %W %1"
541magic::tag cif      "magic::mgrupdate %W %1"
542magic::tag gds      "magic::mgrupdate %W %1"
543
544# This should be a list. . . do be done later
545set lwindow 0
546set owindow 0
547
548set Opts(techmgr) 0
549set Opts(target)  default
550set Opts(netlist) 0
551set Opts(colormap) 0
552set Opts(wind3d) 0
553set Opts(crosshair) 0
554set Opts(hidelocked) 0
555set Opts(hidespecial) 0
556set Opts(toolbar) 0
557set Opts(toolscale) 1.0
558set Opts(drc) 1
559set Opts(autobuttontext) 1
560
561# Update cell and tech managers in response to a cif or gds read command
562
563proc magic::mgrupdate {win {cmdstr ""}} {
564   if {${cmdstr} == "read"} {
565      catch {magic::cellmanager}
566      magic::captions
567      magic::techmanager update
568   } elseif {${cmdstr} == "delete" || ${cmdstr} == "rename"} {
569      catch {magic::cellmanager}
570      magic::captions
571   } elseif {${cmdstr} == "writeable"} {
572      magic::captions
573   }
574}
575
576# Set default width and height to be 3/4 of the screen size.
577set Opts(geometry) \
578"[expr {3 * [winfo screenwidth .] / 4}]x[expr {3 * [winfo screenheight .] \
579/ 4}]+100+100"
580
581# Procedures for the layout scrollbars, which are made from canvas
582# objects to avoid the problems associated with Tk's stupid scrollbar
583# implementation.
584
585# Repainting function for scrollbars, title, etc., to match the magic
586# Change the colormap (most useful in 8-bit PseudoColor)
587
588proc magic::repaintwrapper { win } {
589   set bgcolor [magic::magiccolor -]
590   ${win}.xscroll configure -background $bgcolor
591   ${win}.xscroll configure -highlightbackground $bgcolor
592   ${win}.xscroll configure -highlightcolor [magic::magiccolor K]
593
594   ${win}.yscroll configure -background $bgcolor
595   ${win}.yscroll configure -highlightbackground $bgcolor
596   ${win}.yscroll configure -highlightcolor [magic::magiccolor K]
597
598   ${win}.titlebar.caption configure -background [magic::magiccolor w]
599   ${win}.titlebar.caption configure -foreground [magic::magiccolor c]
600
601   ${win}.titlebar.message configure -background [magic::magiccolor w]
602   ${win}.titlebar.message configure -foreground [magic::magiccolor c]
603
604   ${win}.titlebar.pos configure -background [magic::magiccolor w]
605   ${win}.titlebar.pos configure -foreground [magic::magiccolor c]
606
607}
608
609# Coordinate display callback function
610# Because "box" calls "box", use the "info level" command to avoid
611# infinite recursion.
612
613proc magic::boxview {win {cmdstr ""}} {
614   if {${cmdstr} == "exists" || ${cmdstr} == "help" || ${cmdstr} == ""} {
615      # do nothing. . . informational only, no change to the box
616   } elseif {${cmdstr} == "remove"} {
617      set framename [winfo parent $win]
618      if {$framename == "."} {return}
619      ${framename}.titlebar.pos configure -text "no box"
620   } elseif {[info level] <= 1} {
621      # For NULL window, find all layout windows and apply update to each.
622      if {$win == {}} {
623         set winlist [magic::windownames layout]
624         foreach lwin $winlist {
625	    magic::boxview $lwin
626         }
627         return
628      }
629
630      set framename [winfo parent $win]
631      if {$framename == "."} {return}
632      if {[catch {set cr [cif scale out]}]} {return}
633      set bval [${win} box values]
634      set bllx [expr {[lindex $bval 0] * $cr }]
635      set blly [expr {[lindex $bval 1] * $cr }]
636      set burx [expr {[lindex $bval 2] * $cr }]
637      set bury [expr {[lindex $bval 3] * $cr }]
638      if {[expr {$bllx == int($bllx)}]} {set bllx [expr {int($bllx)}]}
639      if {[expr {$blly == int($blly)}]} {set blly [expr {int($blly)}]}
640      if {[expr {$burx == int($burx)}]} {set burx [expr {int($burx)}]}
641      if {[expr {$bury == int($bury)}]} {set bury [expr {int($bury)}]}
642      set titletext [format "box (%+g %+g) to (%+g %+g) microns" \
643			$bllx $blly $burx $bury]
644      ${framename}.titlebar.pos configure -text $titletext
645   }
646}
647
648proc magic::cursorview {win} {
649   global Opts
650   if {$win == {}} {
651      return
652   }
653   set framename [winfo parent $win]
654   if {[catch {set cr [*bypass cif scale out]}]} {return}
655   if {$cr == 0} {return}
656   set olst [${win} cursor internal]
657
658   set olstx [lindex $olst 0]
659   set olsty [lindex $olst 1]
660
661   if {$Opts(crosshair)} {
662      *bypass crosshair ${olstx}i ${olsty}i
663   }
664
665   # Use catch, because occasionally this fails on startup
666   if {[catch {
667      set olstx [expr {$olstx * $cr}]
668      set olsty [expr {$olsty * $cr}]
669   }]} {return}
670
671   if {[${win} box exists]} {
672      set dlst [${win} box position]
673      set dx [expr {$olstx - ([lindex $dlst 0]) * $cr }]
674      set dy [expr {$olsty - ([lindex $dlst 1]) * $cr }]
675      if {[expr {$dx == int($dx)}]} {set dx [expr {int($dx)}]}
676      if {[expr {$dy == int($dy)}]} {set dy [expr {int($dy)}]}
677      set titletext [format "(%+g %+g) %+g %+g microns" $olstx $olsty $dx $dy]
678      ${framename}.titlebar.pos configure -text $titletext
679   } else {
680      set titletext [format "(%+g %+g) microns" $olstx $olsty]
681      ${framename}.titlebar.pos configure -text $titletext
682   }
683}
684
685proc magic::toolupdate {win {yesno "yes"} {layerlist "none"}} {
686   global Winopts
687
688   if {$win == {}} {
689      set win [magic::windownames]
690   }
691
692   # Wind3d has a "see" function, so make sure this is not a 3d window
693   if {$win == [magic::windownames wind3d]} {
694      return
695   }
696
697   set topname [winfo toplevel $win]
698   set framename [winfo parent $win]
699
700   # Don't do anything if toolbar is not present
701   if { $Winopts(${topname},toolbar) == 0 } { return }
702
703   if {$layerlist == "none"} {
704	set layerlist $yesno
705	set yesno "yes"
706   }
707   if {$layerlist == "*"} {
708      set layerlist [magic::tech layer "*"]
709   }
710
711   # Change from comma-separated list to Tcl list
712   set layerlist [string map {, " "} $layerlist]
713
714   foreach layer $layerlist {
715      switch $layer {
716	 none {set canon ""}
717	 allSame {set canon ""}
718	 "*" {set canon ""}
719	 "$" {set canon ""}
720	 connect {set canon ""}
721	 errors {set canon $layer}
722	 subcell {set canon $layer}
723	 labels {set canon $layer}
724	 default {set canon [magic::tech layer $layer]}
725      }
726
727      # Layers may not be in the toolbar if "hidelocked" or
728      # "hidespecial" is used, so catch each configure command.
729
730      if {$canon != ""} {
731         if {$yesno == "yes"} {
732	    catch {${framename}.toolbar.b$canon configure -image img_$canon}
733	    catch {${framename}.toolbar.p$canon configure -image pale_$canon}
734         } else {
735	    catch {${framename}.toolbar.b$canon configure -image img_space}
736	    catch {${framename}.toolbar.p$canon configure -image img_space}
737	 }
738      }
739   }
740}
741
742# Generate the toolbar images for a technology
743
744proc magic::maketoolimages {} {
745   global Opts
746
747   # Tool size expands with the GUI scale but can also be expanded independently.
748   set tsize [expr {int($Opts(scale) * $Opts(toolscale) * 16)}]
749
750   # Generate a layer image for "space" that will be used when layers are
751   # invisible.
752
753   image create layer img_space -name none -width $tsize -height $tsize
754
755   set all_layers [concat {errors labels subcell} [magic::tech layer "*"]]
756
757   foreach layername $all_layers {
758      image create layer img_$layername -name $layername -width $tsize -height $tsize
759      image create layer pale_$layername -name $layername \
760		-disabled true -icon 23 -width $tsize -height $tsize
761    }
762}
763
764# Generate the toolbar for the wrapper
765
766proc magic::maketoolbar { framename } {
767   global Opts
768   global Winopts
769
770   # Don't do anything if in suspend mode
771   set topname [winfo toplevel $framename]
772   if {[info exists Winopts(${topname},suspend)]} {
773      if { $Winopts(${topname},suspend) > 0} { return }
774   }
775
776   if {$Opts(toolbar) == 0} {
777      magic::maketoolimages
778      set Opts(toolbar) 1
779   }
780
781   # Destroy any existing toolbar before starting
782   set alltools [winfo children ${framename}.toolbar]
783   foreach i $alltools {
784      destroy $i
785   }
786
787   # All toolbar commands will be passed to the appropriate window
788   set win ${framename}.magic
789
790   # Generate layer images and buttons for toolbar
791   if {$Opts(hidespecial) == 0} {
792       set special_layers {errors labels subcell}
793   } else {
794       set special_layers {}
795   }
796
797   if {$Opts(hidelocked) == 0} {
798       set all_layers [concat $special_layers [magic::tech layer "*"]]
799   } else {
800       set all_layers [concat $special_layers [magic::tech unlocked]]
801   }
802   foreach layername $all_layers {
803      button ${framename}.toolbar.b$layername -image img_$layername -command \
804		"$win see $layername"
805
806      # Bindings:  Entering the button puts the canonical layer name in the
807      # message window.
808      bind ${framename}.toolbar.b$layername <Enter> \
809		[subst {focus %W ; ${framename}.titlebar.message configure \
810		 -text "$layername"}]
811      bind ${framename}.toolbar.b$layername <Leave> \
812		[subst {${framename}.titlebar.message configure -text ""}]
813
814      # 3rd mouse button makes layer invisible; 1st mouse button restores it.
815      # 2nd mouse button paints the layer color.  Key "p" also does paint, esp.
816      # for users with 2-button mice.  Key "e" erases, as does Shift-Button-2.
817
818      bind ${framename}.toolbar.b$layername <ButtonPress-2> \
819		"$win paint $layername"
820      bind ${framename}.toolbar.b$layername <KeyPress-p> \
821		"$win paint $layername"
822      bind ${framename}.toolbar.b$layername <Shift-ButtonPress-2> \
823		"$win erase $layername"
824      bind ${framename}.toolbar.b$layername <KeyPress-e> \
825		"$win erase $layername"
826      bind ${framename}.toolbar.b$layername <ButtonPress-3> \
827		"$win see no $layername"
828      bind ${framename}.toolbar.b$layername <KeyPress-s> \
829		"$win select more area $layername"
830      bind ${framename}.toolbar.b$layername <KeyPress-S> \
831		"$win select less area $layername"
832   }
833
834   # Create an additional set of layers and buttons in the "disabled" style
835   # These buttons can be swapped in place of the regular buttons when the
836   # layer is locked.  They define no bindings except "u" for "unlock",
837   # and the button bindings (see, see no)
838
839   foreach layername $all_layers {
840      button ${framename}.toolbar.p$layername -image pale_$layername -command \
841		"$win see $layername"
842      bind ${framename}.toolbar.p$layername <ButtonPress-3> \
843		"$win see no $layername"
844      bind ${framename}.toolbar.p$layername <Enter> \
845		[subst {focus %W ; ${framename}.titlebar.message configure \
846		 -text "$layername (locked)"}]
847      bind ${framename}.toolbar.p$layername <Leave> \
848		[subst {${framename}.titlebar.message configure -text ""}]
849   }
850
851   # Figure out how many columns we need to fit all the layer buttons inside
852   # the toolbar without going outside the window area.
853
854   set locklist [tech locked]
855   set ncols 0
856   while {1} {
857      incr ncols
858      set i 0
859      set j 0
860      foreach layername $all_layers {
861	 if {[lsearch $locklist $layername] >= 0} {
862            grid ${framename}.toolbar.p$layername -row $i -column $j -sticky news
863	 } else {
864            grid ${framename}.toolbar.b$layername -row $i -column $j -sticky news
865	 }
866	 bind ${framename}.toolbar.p$layername <KeyPress-u> \
867		"$win tech unlock $layername ; \
868		grid forget ${framename}.toolbar.p$layername ; \
869		grid ${framename}.toolbar.b$layername \
870		-row $i -column $j -sticky news"
871	 bind ${framename}.toolbar.b$layername <KeyPress-l> \
872		"$win tech lock $layername ; \
873		grid forget ${framename}.toolbar.b$layername ; \
874		grid ${framename}.toolbar.p$layername \
875		-row $i -column $j -sticky news"
876         incr j
877         if {$j == $ncols} {
878	    set j 0
879	    incr i
880         }
881      }
882
883      # Make sure that window has been created so we will get the correct
884      # height value.
885
886      update idletasks
887      set winheight [expr {[winfo height ${framename}] - \
888		[winfo height ${framename}.titlebar]}]
889      set toolheight [lindex [grid bbox ${framename}.toolbar] 3]
890      if {$toolheight <= $winheight} {break}
891   }
892}
893
894# Delete and rebuild the toolbar buttons in response to a "tech load"
895# command.
896
897proc magic::techrebuild {winpath {cmdstr ""}} {
898   global Opts
899
900   # For NULL window, find all layout windows and apply update to each.
901   if {$winpath == {}} {
902      set winlist [magic::windownames layout]
903      foreach lwin $winlist {
904	 magic::techrebuild $lwin $cmdstr
905      }
906      return
907   }
908
909   set framename [winfo parent $winpath]
910   if {${cmdstr} == "load"} {
911      set Opts(toolbar) 0
912      maketoolbar ${framename}
913      magic::techmanager init
914   } elseif {${cmdstr} == "lock" || ${cmdstr} == "unlock" || ${cmdstr} == "revert"} {
915      maketoolbar ${framename}
916   }
917}
918
919# Scrollbar callback procs
920
921# Procedure to return the effective X and Y scrollbar bounds for the
922# current view in magic (in pixels)
923
924proc magic::setscrollvalues {win} {
925   global Opts
926
927   set svalues [${win} view get]
928   set bvalues [${win} view bbox]
929
930   set framename [winfo parent ${win}]
931   if {$framename == "."} {return}
932
933   set bwidth [expr {[lindex $bvalues 2] - [lindex $bvalues 0]}]
934   set bheight [expr {[lindex $bvalues 3] - [lindex $bvalues 1]}]
935
936   set wwidth [winfo width ${framename}.xscroll.bar]  ;# horizontal scrollbar
937   set wheight [winfo height ${framename}.yscroll.bar]  ;# vertical scrollbar
938
939   # Note that adding 0.0 here forces floating-point
940
941   set xscale [expr {(0.0 + $wwidth) / $bwidth}]
942   set yscale [expr {(0.0 + $wheight) / $bheight}]
943
944   set xa [expr {$xscale * ([lindex $svalues 0] - [lindex $bvalues 0]) }]
945   set xb [expr {$xscale * ([lindex $svalues 2] - [lindex $bvalues 0]) }]
946   set ya [expr {$yscale * ([lindex $svalues 1] - [lindex $bvalues 1]) }]
947   set yb [expr {$yscale * ([lindex $svalues 3] - [lindex $bvalues 1]) }]
948
949   # Magic's Y axis is inverted with respect to X11 window coordinates
950   set ya [expr { $wheight - $ya }]
951   set yb [expr { $wheight - $yb }]
952
953   set swidth [expr {int($Opts(scale) * 13)}]
954   set slength [expr {$swidth + 2}]
955
956   ${framename}.xscroll.bar coords slider $xa 2 $xb $slength
957   ${framename}.yscroll.bar coords slider 2 $ya $slength $yb
958
959   set xb [expr { 1 + ($xa + $xb) / 2 }]
960   set xa [expr { $xb - 2 }]
961   ${framename}.xscroll.bar coords centre $xa 4 $xb $swidth
962
963   set yb [expr { 1 + ($ya + $yb) / 2 }]
964   set ya [expr { $yb - 2 }]
965   ${framename}.yscroll.bar coords centre 4 $ya $swidth $yb
966}
967
968# Procedure to update scrollbars in response to an internal command
969# "view" calls "view", so avoid infinite recursion.
970
971proc magic::scrollupdate {win} {
972
973   if {[info level] <= 1} {
974
975      # For NULL window, find current window
976      if {$win == {}} {
977	 set win [magic::windownames]
978      }
979
980      # Make sure we're not a 3D window, which doesn't take window commands
981      # This is only necessary because the 3D window declares a "view"
982      # command, too.
983
984      if {$win != [magic::windownames wind3d]} {
985 	 magic::setscrollvalues $win
986      }
987   }
988}
989
990# scrollview:  update the magic display to match the
991# scrollbar positions.
992
993proc magic::scrollview { w win orient } {
994   global scale
995   set v1 $scale($orient,origin)
996   set v2 $scale($orient,update)
997   set delta [expr {$v2 - $v1}]
998
999   set bvalues [${win} view bbox]
1000   set wvalues [${win} windowpositions]
1001
1002   # Note that adding 0.000 in expression forces floating-point
1003
1004   if {"$orient" == "x"} {
1005
1006      set bwidth [expr {[lindex $bvalues 2] - [lindex $bvalues 0]}]
1007      set wwidth [expr {0.000 + [lindex $wvalues 2] - [lindex $wvalues 0]}]
1008      set xscale [expr {$bwidth / $wwidth}]
1009      ${win} scroll e [expr {$delta * $xscale}]i
1010
1011   } else {
1012
1013      set bheight [expr {[lindex $bvalues 3] - [lindex $bvalues 1]}]
1014      set wheight [expr {0.000 + [lindex $wvalues 3] - [lindex $wvalues 1]}]
1015      set yscale [expr {$bheight / $wheight}]
1016      ${win} scroll s [expr {$delta * $yscale}]i
1017   }
1018}
1019
1020# setscroll: get the current cursor position and save it as a
1021# reference point.
1022
1023proc magic::setscroll { w v orient } {
1024   global scale
1025   set scale($orient,origin) $v
1026   set scale($orient,update) $v
1027}
1028
1029proc magic::dragscroll { w v orient } {
1030   global scale
1031   set v1 $scale($orient,update)
1032   set scale($orient,update) $v
1033   set delta [expr {$v - $v1}]
1034
1035   if { "$orient" == "x" } {
1036      $w move slider $delta 0
1037      $w move centre $delta 0
1038   } else {
1039      $w move slider 0 $delta
1040      $w move centre 0 $delta
1041   }
1042}
1043
1044# Scrollbar generator for the wrapper window
1045
1046proc magic::makescrollbar { fname orient win } {
1047   global scale
1048   global Glyph
1049   global Opts
1050
1051   set swidth [expr {int($Opts(scale) * 13)}]
1052
1053   set scale($orient,update) 0
1054   set scale($orient,origin) 0
1055
1056   # To be done:  add glyphs for the arrows
1057
1058   if { "$orient" == "x" } {
1059      canvas ${fname}.bar -height $swidth -relief sunken -borderwidth 1
1060      button ${fname}.lb -image Glyph(left) -borderwidth 1 \
1061		-command "${win} scroll left .1 w"
1062      button ${fname}.ub -image Glyph(right) -borderwidth 1 \
1063		-command "${win} scroll right .1 w"
1064      pack ${fname}.lb -side left
1065      pack ${fname}.bar -fill $orient -expand true -side left
1066      pack ${fname}.ub -side right
1067   } else {
1068      canvas ${fname}.bar -width $swidth -relief sunken -borderwidth 1
1069      button ${fname}.lb -image Glyph(down) -borderwidth 1 \
1070		-command "${win} scroll down .1 w"
1071      button ${fname}.ub -image Glyph(up) -borderwidth 1 \
1072		-command "${win} scroll up .1 w"
1073      pack ${fname}.ub
1074      pack ${fname}.bar -fill $orient -expand true
1075      pack ${fname}.lb
1076   }
1077
1078   # Create the bar which controls the scrolling and bind actions to it
1079   ${fname}.bar create rect 2 2 15 15 -fill steelblue -width 0 -tag slider
1080   ${fname}.bar bind slider <Button-1> "magic::setscroll %W %$orient $orient"
1081   ${fname}.bar bind slider <ButtonRelease-1> "magic::scrollview %W $win $orient"
1082   ${fname}.bar bind slider <B1-Motion> "magic::dragscroll %W %$orient $orient"
1083
1084   # Create a small mark in the center of the scrolling rectangle which aids
1085   # in determining how much the window is being scrolled when the full
1086   # scrollbar extends past the window edges.
1087   ${fname}.bar create rect 4 4 $swidth $swidth -fill black -width 0 -tag centre
1088   ${fname}.bar bind centre <Button-1> "magic::setscroll %W %$orient $orient"
1089   ${fname}.bar bind centre <ButtonRelease-1> "magic::scrollview %W $win $orient"
1090   ${fname}.bar bind centre <B1-Motion> "magic::dragscroll %W %$orient $orient"
1091}
1092
1093# Save all and quit.  If something bad happens like an attempt to
1094# write cells into an unwriteable directory, then "cellname list modified"
1095# will contain a list of cells, so prompt to quit with the option to cancel.
1096# If there are no remaining modified and unsaved cells, then just exit.
1097# Because cell "(UNNAMED)" is not written by "writeall force", if that is
1098# the only modified cell, then prompt to change its name and save; then quit.
1099
1100proc magic::saveallandquit {} {
1101   magic::promptsave force
1102   set modlist [magic::cellname list modified]
1103   if {$modlist == {}} {
1104      magic::quit -noprompt
1105   } else {
1106      magic::quit
1107   }
1108}
1109
1110# Create the wrapper and open up a layout window in it.
1111
1112proc magic::openwrapper {{cell ""} {framename ""}} {
1113   global lwindow
1114   global owindow
1115   global tk_version
1116   global Glyph
1117   global Opts
1118   global Winopts
1119
1120   # Disallow scrollbars and title caption on windows---we'll do these ourselves
1121
1122   if {$lwindow == 0} {
1123      windowcaption off
1124      windowscrollbars off
1125      windowborder off
1126   }
1127
1128   if {$framename == ""} {
1129      incr lwindow
1130      set framename .layout${lwindow}
1131   }
1132   set winname ${framename}.pane.top.magic
1133
1134   toplevel $framename
1135   tkwait visibility $framename
1136
1137   # Get scale from the TkDefaultFont size, unless Opts(scale) is already
1138   # set.  On standard displays, an "M" in the Sans font is usually 10
1139   # pixels wide, and 22 on high resolution displays, so this maps to
1140   # a scale of 1 on standard displays and a scale of 2 on high resolution
1141   # displays.  Make sure scale doesn't go to zero or bad things happen.
1142
1143   if [catch {set Opts(scale)}] {
1144	set Opts(scale) [expr {max(1, int([font measure TkDefaultFont M] / 10))}]
1145   }
1146
1147   # Resize the window
1148   if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} {
1149      catch {wm geometry ${framename} $Opts(geometry)}
1150   }
1151
1152   # Create a paned window top--bottom inside the top level window to accomodate
1153   # a resizable command entry window at the bottom.  Sashwidth is zero by default
1154   # but is resized by enabling the command entry window.
1155
1156   panedwindow ${framename}.pane -orient vertical -sashrelief groove -sashwidth 6
1157
1158   frame ${framename}.pane.top
1159   frame ${framename}.pane.bot
1160
1161   set layoutframe ${framename}.pane.top
1162
1163   ${framename}.pane add ${framename}.pane.top
1164   ${framename}.pane add ${framename}.pane.bot
1165   ${framename}.pane paneconfigure ${framename}.pane.top -stretch always
1166   ${framename}.pane paneconfigure ${framename}.pane.bot -hide true
1167
1168   pack ${framename}.pane -side top -fill both -expand true
1169
1170   set swidth [expr {int($Opts(scale) * 13)}]
1171   frame ${layoutframe}.xscroll -height $swidth
1172   frame ${layoutframe}.yscroll -width $swidth
1173
1174   magic::makeglyphimages
1175   magic::makescrollbar ${layoutframe}.xscroll x ${winname}
1176   magic::makescrollbar ${layoutframe}.yscroll y ${winname}
1177   button ${layoutframe}.zb -image Glyph(zoom) -borderwidth 1 -command "${winname} zoom 2"
1178
1179   # Add bindings for mouse buttons 2 and 3 to the zoom button
1180   bind ${layoutframe}.zb <Button-3> "${winname} zoom 0.5"
1181   bind ${layoutframe}.zb <Button-2> "${winname} view"
1182
1183   frame ${layoutframe}.titlebar
1184   label ${layoutframe}.titlebar.caption -text "Loaded: none Editing: none Tool: box" \
1185	-foreground white -background sienna4 -anchor w -padx 15
1186   label ${layoutframe}.titlebar.message -text "" -foreground white \
1187	-background sienna4 -anchor w -padx 5
1188   label ${layoutframe}.titlebar.pos -text "" -foreground white \
1189	-background sienna4 -anchor w -padx 5
1190
1191   # Menu buttons
1192   frame ${layoutframe}.titlebar.mbuttons
1193
1194# File
1195   menubutton ${layoutframe}.titlebar.mbuttons.file -text File -relief raised \
1196		-menu ${layoutframe}.titlebar.mbuttons.file.toolmenu -borderwidth 2
1197# Edit
1198   menubutton ${layoutframe}.titlebar.mbuttons.edit -text Edit -relief raised \
1199		-menu ${layoutframe}.titlebar.mbuttons.edit.toolmenu -borderwidth 2
1200# Cell
1201   menubutton ${layoutframe}.titlebar.mbuttons.cell -text Cell -relief raised \
1202		-menu ${layoutframe}.titlebar.mbuttons.cell.toolmenu -borderwidth 2
1203# Window
1204   menubutton ${layoutframe}.titlebar.mbuttons.win -text Window -relief raised \
1205		-menu ${layoutframe}.titlebar.mbuttons.win.toolmenu -borderwidth 2
1206# Layers
1207   menubutton ${layoutframe}.titlebar.mbuttons.layers -text Layers -relief raised \
1208		-menu ${layoutframe}.titlebar.mbuttons.layers.toolmenu -borderwidth 2
1209# DRC
1210   menubutton ${layoutframe}.titlebar.mbuttons.drc -text Drc -relief raised \
1211		-menu ${layoutframe}.titlebar.mbuttons.drc.toolmenu -borderwidth 2
1212# Netlist
1213#   menubutton ${layoutframe}.titlebar.mbuttons.netlist -text Neltist -relief raised \
1214#		-menu ${layoutframe}.titlebar.mbuttons.netlist.netlistmenu -borderwidth 2
1215# Help
1216#   menubutton ${layoutframe}.titlebar.mbuttons.help -text Help -relief raised \
1217#		-menu ${layoutframe}.titlebar.mbuttons.help.helpmenu -borderwidth 2
1218# Options
1219   menubutton ${layoutframe}.titlebar.mbuttons.opts -text Options -relief raised \
1220		-menu ${layoutframe}.titlebar.mbuttons.opts.toolmenu -borderwidth 2
1221   pack ${layoutframe}.titlebar.mbuttons.file   -side left
1222   pack ${layoutframe}.titlebar.mbuttons.edit   -side left
1223   pack ${layoutframe}.titlebar.mbuttons.cell   -side left
1224   pack ${layoutframe}.titlebar.mbuttons.win    -side left
1225   pack ${layoutframe}.titlebar.mbuttons.layers -side left
1226   pack ${layoutframe}.titlebar.mbuttons.drc    -side left
1227#   pack ${layoutframe}.titlebar.mbuttons.netlist -side left
1228#   pack ${layoutframe}.titlebar.mbuttons.help    -side left
1229   pack ${layoutframe}.titlebar.mbuttons.opts    -side left
1230
1231   # DRC status button
1232   checkbutton ${layoutframe}.titlebar.drcbutton -text "DRC" -anchor w \
1233	-borderwidth 2 -variable Opts(drc) \
1234	-foreground white -background sienna4 -selectcolor green \
1235	-command [subst { if { \$Opts(drc) } { drc on } else { drc off } }]
1236
1237   magic::openwindow $cell $winname
1238
1239   # Create toolbar frame.  Make sure it has the same visual and depth as
1240   # the layout window, so there will be no problem using the GCs from the
1241   # layout window to paint into the toolbar.
1242   frame ${layoutframe}.toolbar \
1243	-visual "[winfo visual ${winname}] [winfo depth ${winname}]"
1244
1245   # Repaint to magic colors
1246   magic::repaintwrapper ${layoutframe}
1247
1248   grid ${layoutframe}.titlebar -row 0 -column 0 -columnspan 3 -sticky news
1249   grid ${layoutframe}.yscroll -row 1 -column 0 -sticky ns
1250   grid $winname -row 1 -column 1 -sticky news
1251   grid ${layoutframe}.zb -row 2 -column 0
1252   grid ${layoutframe}.xscroll -row 2 -column 1 -sticky ew
1253   # The toolbar is not attached by default
1254
1255   grid rowconfigure ${layoutframe} 1 -weight 1
1256   grid columnconfigure ${layoutframe} 1 -weight 1
1257
1258   grid ${layoutframe}.titlebar.mbuttons -row 0 -column 0 -sticky news
1259   grid ${layoutframe}.titlebar.drcbutton -row 0 -column 1 -sticky news
1260   grid ${layoutframe}.titlebar.caption -row 0 -column 2 -sticky news
1261   grid ${layoutframe}.titlebar.message -row 0 -column 3 -sticky news
1262   grid ${layoutframe}.titlebar.pos -row 0 -column 4 -sticky news
1263   grid columnconfigure ${layoutframe}.titlebar 2 -weight 1
1264
1265   bind $winname <Enter> "focus %W ; set Opts(focus) $framename"
1266
1267   # Note: Tk binding bypasses the event proc, so it is important to
1268   # set the current point;  otherwise, the cursor will report the
1269   # wrong position and/or the wrong window.  HOWEVER we should wrap
1270   # this command with the "bypass" command such that it does not
1271   # reset any current input redirection to the terminal.
1272
1273   bind ${winname} <Motion> "*bypass setpoint %x %y ${winname}; \
1274	magic::cursorview ${winname}"
1275
1276   set Winopts(${framename},toolbar) 1
1277   set Winopts(${framename},cmdentry) 0
1278
1279# #################################
1280# File
1281# #################################
1282   set m [menu ${layoutframe}.titlebar.mbuttons.file.toolmenu -tearoff 0]
1283   $m add command -label "Open..."      -command {magic::promptload magic}
1284   # $m add command -label "Save"       -command {magic::save }
1285   $m add command -label "Save..."      -command {magic::promptsave magic}
1286   # $m add command -label "Save as..." -command {echo "not implemented"}
1287   # $m add command -label "Save selection..." -command {echo "not implemented"}
1288   $m add separator
1289   $m add command -label "Flush changes" -command {magic::flush}
1290   $m add separator
1291   # $m add command -label "Read CIF" -command {magic::promptload cif}
1292   $m add command -label "Read GDS"    -command {magic::promptload gds}
1293   # $m add separator
1294   # $m add command -label "Write CIF" -command {magic::promptsave cif}
1295   $m add command -label "Write GDS"   -command {magic::promptsave gds}
1296   # $m add separator
1297   # $m add command -label "Print..."  -command {echo "not implemented"}
1298   $m add separator
1299   $m add command -label "Save All and Quit" -command {magic::saveallandquit}
1300   $m add command -label "Quit"              -command {magic::quit}
1301
1302# #################################
1303# Edit
1304# #################################
1305
1306   set m [menu ${layoutframe}.titlebar.mbuttons.edit.toolmenu -tearoff 0]
1307   # $m add command -label "Cut" -command {echo "not implemented"}
1308   # $m add command -label "Copy" -command {echo "not implemented"}
1309   # $m add command -label "Paste" -command {echo "not implemented"}
1310   $m add command -label "Delete" -command {delete}
1311   $m add separator
1312   $m add command -label "Select Area" -command {select area}
1313   $m add command -label "Select Clear" -command {select clear}
1314   $m add separator
1315   $m add command -label "Undo" -command {magic::undo}
1316   $m add command -label "Redo" -command {magic::redo}
1317   # $m add command -label "Repeat Last" -command {echo "not implemented"}
1318   $m add separator
1319   $m add command -label "Rotate 90 degree" -command {magic::clock}
1320   $m add command -label "Mirror   Up/Down"  -command {magic::upsidedown}
1321   $m add command -label "Mirror Left/Right" -command {magic::sideways}
1322   $m add separator
1323   $m add command -label "Move Right" -command {move right 1}
1324   $m add command -label "Move Left" -command {move left 1}
1325   $m add command -label "Move Up" -command {move up 1}
1326   $m add command -label "Move Down" -command {move down 1}
1327   $m add separator
1328   $m add command -label "Stretch Right" -command {stretch right 1}
1329   $m add command -label "Stretch Left" -command {stretch left 1}
1330   $m add command -label "Stretch Up" -command {stretch up 1}
1331   $m add command -label "Stretch Down" -command {stretch down 1}
1332   $m add separator
1333   $m add command -label "Text ..." \
1334		-command [subst {magic::update_texthelper; \
1335		wm deiconify .texthelper ; raise .texthelper}]
1336
1337# #################################
1338# Cell
1339# #################################
1340   set m [menu ${layoutframe}.titlebar.mbuttons.cell.toolmenu -tearoff 0]
1341   $m add command -label "New..." -command {magic::prompt_dialog new}
1342   $m add command -label "Save as..." -command {magic::prompt_dialog save}
1343   $m add command -label "Select" -command {magic::select cell}
1344   $m add command -label "Place Instance" -command {magic::promptload getcell}
1345   # $m add command -label "Rename" -command {echo "not implemented"}
1346   $m add separator
1347   $m add command -label "Down hierarchy" -command {magic::pushstack}
1348   $m add command -label "Up   hierarchy" -command {magic::popstack}
1349   $m add separator
1350   $m add command -label "Edit" -command {magic::edit}
1351   $m add separator
1352   $m add command -label "Delete" -command \
1353		{magic::cellname delete [magic::cellname list window]}
1354   $m add separator
1355   $m add command -label "Expand Toggle" -command {magic::expand toggle}
1356   $m add command -label "Expand" -command {magic::expand}
1357   $m add command -label "Unexpand" -command {magic::unexpand}
1358   $m add separator
1359   $m add command -label "Lock   Cell" -command {magic::instance lock}
1360   $m add command -label "Unlock Cell" -command {magic::instance unlock}
1361
1362# #################################
1363# Window
1364# #################################
1365   set m [menu ${layoutframe}.titlebar.mbuttons.win.toolmenu -tearoff 0]
1366   $m add command -label "Clone" -command \
1367		{magic::openwrapper [magic::cellname list window]}
1368   $m add command -label "New" -command "magic::openwrapper"
1369   $m add command -label "Set Editable" -command \
1370		"pushbox ; select top cell ; edit ; popbox"
1371   $m add command -label "Close" -command "closewrapper ${framename}"
1372   $m add separator
1373   $m add command -label "Full View" -command {magic::view}
1374   $m add command -label "Redraw" -command {magic::redraw}
1375   $m add command -label "Zoom Out" -command {magic::zoom 2}
1376   $m add command -label "Zoom In" -command {magic::zoom 0.5}
1377   $m add command -label "Zoom Box" -command {magic::findbox zoom}
1378   $m add separator
1379   $m add command -label "Grid on" -command {magic::grid on}
1380   $m add command -label "Grid off" -command {magic::grid off}
1381   $m add command -label "Snap-to-grid on" -command {magic::snap on}
1382   $m add command -label "Snap-to-grid off" -command {magic::snap off}
1383   $m add command -label "Measure box" -command {magic::box }
1384   $m add separator
1385   $m add command -label "Set grid 0.05um" -command {magic::grid 0.05um}
1386   $m add command -label "Set grid 0.10um" -command {magic::grid 0.10um}
1387   $m add command -label "Set grid 0.50um" -command {magic::grid 0.50um}
1388   $m add command -label "Set grid 1.00um" -command {magic::grid 1.00um}
1389   $m add command -label "Set grid 5.00um" -command {magic::grid 5.00um}
1390   $m add command -label "Set grid 10.0um" -command {magic::grid 10.0um}
1391   # $m add command -label "Set grid ..." -command {echo "not implemented"}
1392
1393# #################################
1394# Layers
1395# #################################
1396   set m [menu ${layoutframe}.titlebar.mbuttons.layers.toolmenu -tearoff 0]
1397   $m add command -label "Protect Base Layers" -command {magic::tech revert}
1398   $m add command -label "Unlock  Base Layers" -command {magic::tech unlock *}
1399   $m add separator
1400   $m add command -label "Clear Feedback" -command {magic::feedback clear}
1401   $m add separator
1402
1403# #################################
1404# DRC
1405# #################################
1406   set m [menu ${layoutframe}.titlebar.mbuttons.drc.toolmenu -tearoff 0]
1407   # $m add command -label "DRC On" -command {drc on}
1408   # $m add command -label "DRC Off" -command {drc off}
1409   # $m add separator
1410   $m add command -label "DRC update" -command {drc check; drc why}
1411   $m add command -label "DRC report" -command {drc why}
1412   $m add command -label "DRC Find next error" -command {drc find; findbox zoom}
1413   $m add separator
1414   $m add command -label "DRC Fast"     -command {drc style drc(fast)}
1415   $m add command -label "DRC Complete" -command {drc style drc(full)}
1416
1417   set m [menu ${layoutframe}.titlebar.mbuttons.opts.toolmenu -tearoff 0]
1418   $m add check -label "Toolbar" -variable Winopts(${framename},toolbar) \
1419	-command [subst {if { \$Winopts(${framename},toolbar) } { \
1420		magic::maketoolbar ${layoutframe} ; \
1421		grid ${layoutframe}.toolbar -row 1 -column 2 -rowspan 2 -sticky new ; \
1422		} else { \
1423		grid forget ${layoutframe}.toolbar } }]
1424
1425   $m add check -label "Toolbar Hide Locked" \
1426	-variable Opts(hidelocked) \
1427	-command "magic::maketoolbar ${layoutframe}"
1428
1429   .winmenu add radio -label ${framename} -variable Opts(target) -value ${winname}
1430   if {$tk_version >= 8.5} {
1431     $m add check -label "Cell Manager" -variable Opts(cellmgr) \
1432	-command [subst { magic::cellmanager create; \
1433	if { \$Opts(cellmgr) } { \
1434	   wm deiconify .cellmgr ; raise .cellmgr \
1435	} else { \
1436	   wm withdraw .cellmgr } }]
1437      .winmenu entryconfigure last -command ".cellmgr.target.list configure \
1438         -text ${framename}"
1439   }
1440   if {$tk_version >= 8.5} {
1441     $m add check -label "Library Manager" -variable Opts(libmgr) \
1442	-command [subst { magic::libmanager create; \
1443	if { \$Opts(libmgr) } { \
1444	   wm deiconify .libmgr ; raise .libmgr \
1445	} else { \
1446	   wm withdraw .libmgr } }]
1447      .winmenu entryconfigure last -command ".libmgr.target.list configure \
1448         -text ${framename}"
1449   }
1450   $m add check -label "Tech Manager" -variable Opts(techmgr) \
1451	-command [subst { magic::techmanager create; \
1452		if { \$Opts(techmgr) } { \
1453		wm deiconify .techmgr ; raise .techmgr \
1454		} else { \
1455		wm withdraw .techmgr } }]
1456
1457   $m add check -label "DRC Manager" -variable Opts(drcmgr) \
1458	-command [subst { magic::drcmanager create; \
1459		if { \$Opts(drcmgr) } { \
1460		wm deiconify .drcmgr ; raise .drcmgr \
1461		} else { \
1462		wm withdraw .drcmgr } }]
1463
1464   $m add check -label "Netlist Window" -variable Opts(netlist) \
1465	-command [subst { if { \[windownames netlist\] != {}} { \
1466		   set Opts(netlist) 0 ; closewindow \[windownames netlist\] \
1467		} else { \
1468		   set Opts(netlist) 1 ; specialopen netlist \
1469		} }]
1470
1471   $m add check -label "Colormap Window" -variable Opts(colormap) \
1472	-command [subst { if { \[windownames color\] != {}} { \
1473		   set Opts(colormap) 0 ; closewindow \[windownames color\] \
1474		} else { \
1475		   set Opts(colormap) 1 ; specialopen color \
1476		} }]
1477
1478   $m add check -label "3D Display" -variable Opts(wind3d) \
1479	-command [subst { if { \[windownames wind3d\] != {}} { \
1480		   set Opts(wind3d) 0 ; .render.magic closewindow ; \
1481		   destroy .render \
1482		} else { \
1483		   set Opts(wind3d) 1 ; \
1484		   magic::render3d \[${winname} cellname list window\] \
1485		} }]
1486
1487   $m add check -label "Window Command Entry" \
1488	-variable Winopts(${framename},cmdentry) \
1489	-command [subst { if { \$Winopts(${framename},cmdentry) } { \
1490		addcommandentry $framename \
1491		} else { \
1492		deletecommandentry $framename } }]
1493
1494   $m add check -label "Crosshair" \
1495	-variable Opts(crosshair) \
1496	-command {if {$Opts(crosshair) == 0} {crosshair off}}
1497
1498   catch {addmazehelper $m}
1499
1500   # Set the default view
1501
1502   update idletasks
1503   ${winname} magic::view
1504
1505   magic::captions
1506
1507   # If the toolbar is turned on, invoke the toolbar button
1508   if { $Winopts(${framename},toolbar) == 1} {
1509      magic::maketoolbar ${layoutframe}
1510      grid ${layoutframe}.toolbar -row 1 -column 2 -rowspan 2 -sticky new
1511   }
1512
1513   # Remove "open" and "close" macros so they don't generate non-GUI
1514   # windows or (worse) blow away the window inside the GUI frame
1515
1516   if {[magic::macro list o] == "openwindow"} {
1517      magic::macro o \
1518	   "incr owindow ;\
1519	   set rpt \[cursor screen\] ;\
1520	   set rptx \[lindex \$rpt 0\] ;\
1521	   set rpty \[lindex \$rpt 1\] ;\
1522	   set Winopts(.owindow\$owindow,geometry) 500x500+\$rptx+\$rpty ;\
1523	   openwrapper \[\$Opts(focus)*.magic cellname list window\] \
1524	   .owindow\$owindow ;\
1525	   .owindow\$owindow*.magic view \[box values\]"
1526   }
1527   if {[magic::macro list O] == "closewindow"} {
1528      magic::macro O "closewrapper \$Opts(focus)"
1529   }
1530
1531   # Make sure that closing from the window manager is equivalent to
1532   # the command "closewrapper"
1533   wm protocol ${framename} WM_DELETE_WINDOW "closewrapper ${framename}"
1534
1535   # If the variable $Opts(callback) is defined, then attempt to execute it.
1536   catch {eval $Opts(callback)}
1537
1538   # If the variable $Winopts(callback) is defined, then attempt to execute it.
1539   catch {eval $Winopts(${framename}, callback)}
1540
1541   # Since one purpose of the window callback is to customize the menus,
1542   # run the automatic generation of accelerator key text at the end.
1543   # This can be subverted by setting Opts(autobuttontext) to 0, e.g.,
1544   # to put it at the top of the Winopts callback and then generate
1545   # override values for specific buttons.
1546   if {$Opts(autobuttontext)} {
1547      catch {magic::button_auto_bind_text $layoutframe}
1548   }
1549   return ${winname}
1550}
1551
1552# Delete the wrapper and the layout window in it.
1553
1554proc magic::closewrapper { framename } {
1555   global tk_version
1556   global Opts
1557
1558   # Remove this window from the target list in .winmenu
1559   # (used by, e.g., cellmanager)
1560
1561   set layoutframe ${framename}.pane.top
1562   if { $Opts(target) == "${layoutframe}.magic" } {
1563      set Opts(target) "default"
1564      if {$tk_version >= 8.5} {
1565	 if {![catch {wm state .cellmgr}]} {
1566	    .cellmgr.target.list configure -text "default"
1567         }
1568      }
1569   }
1570
1571   set idx [.winmenu index $framename]
1572   .winmenu delete $idx
1573
1574   ${layoutframe}.magic magic::closewindow
1575   destroy $framename
1576}
1577
1578# This procedure adds a command-line entry window to the bottom of
1579# a wrapper window (rudimentary functionality---incomplete)
1580
1581proc magic::addcommandentry { framename } {
1582   set commandframe ${framename}.pane.bot
1583   if {![winfo exists ${commandframe}.eval]} {
1584      tkshell::YScrolled_Text ${commandframe}.eval -height 5
1585      tkshell::MakeEvaluator ${commandframe}.eval.text \
1586		"${framename}>" ${framename}.pane.top.magic
1587      pack ${commandframe}.eval -side top -fill both -expand true
1588      ${framename}.pane paneconfigure ${framename}.pane.bot -stretch never
1589      ${framename}.pane paneconfigure ${framename}.pane.bot -minsize 50
1590   }
1591   set entercmd [bind ${framename}.pane.top.magic <Enter>]
1592   set bindstr "$entercmd ; macro XK_colon \"set Opts(redirect) 1;\
1593		focus ${commandframe}.eval.text\";\
1594		alias puts tkshell::PutsTkShell"
1595   bind ${commandframe}.eval <Enter> \
1596	"focus ${commandframe}.eval.text ; set Opts(focus) $framename ;\
1597	catch {unset Opts(redirect)}"
1598   bind ${framename}.pane.top.magic <Enter> $bindstr
1599   # Make command entry window visible
1600   ${framename}.pane paneconfigure ${framename}.pane.bot -hide false
1601}
1602
1603# Remove the command entry window from the bottom of a frame.
1604
1605proc magic::deletecommandentry { framename } {
1606   set commandframe ${framename}.pane.bot
1607   ::grid forget ${commandframe}.eval
1608   # Remove the last bindings for <Enter>
1609   set bindstr [bind ${framename}.pane.top.magic <Enter>]
1610   set i [string first "; macro" $bindstr]
1611   set bindstr [string range $bindstr 0 $i-1]
1612   bind ${framename}.pane.top.magic <Enter> $bindstr
1613   # Restore the keybinding for colon
1614   imacro XK_colon ":"
1615   # Restore the alias for "puts"
1616   alias puts ::tkcon_puts
1617   # Make command entry window invisible
1618   ${framename}.pane paneconfigure ${framename}.pane.bot -hide true
1619}
1620
1621namespace import magic::openwrapper
1622puts "Use openwrapper to create a new GUI-based layout window"
1623namespace import magic::closewrapper
1624puts "Use closewrapper to remove a new GUI-based layout window"
1625
1626# Create a simple wrapper for the 3D window. . . this can be
1627# greatly expanded upon.
1628
1629proc magic::render3d {{cell ""}} {
1630   global Opts
1631
1632   toplevel .render
1633   tkwait visibility .render
1634   magic::specialopen wind3d $cell .render.magic
1635   .render.magic cutbox box
1636   set Opts(cutbox) 1
1637   wm protocol .render WM_DELETE_WINDOW "set Opts(wind3d) 0 ; \
1638		.render.magic closewindow ; destroy .render"
1639
1640   frame .render.title
1641   pack .render.title -expand true -fill x -side top
1642   checkbutton .render.title.cutbox -text "Cutbox" -variable Opts(cutbox) \
1643	-foreground white -background sienna4 -anchor w -padx 15 \
1644	-command [subst { if { \$Opts(cutbox) } { .render.magic cutbox box \
1645	} else { \
1646	.render.magic cutbox none } }]
1647
1648   if {$cell == ""} {set cell default}
1649   label .render.title.msg -text "3D Rendering window  Cell: $cell" \
1650	-foreground white -background sienna4 -anchor w -padx 15
1651   pack .render.title.cutbox -side left
1652   pack .render.title.msg -side right -fill x -expand true
1653   pack .render.magic -expand true -fill both -side bottom
1654   bind .render.magic <Enter> {focus %W}
1655}
1656
1657