From affd68aad981f29b8afb7ba67b3abb758aa5579e Mon Sep 17 00:00:00 2001 From: Vasil Yordanov Date: Sat, 18 Nov 2023 12:46:49 +0200 Subject: [PATCH] EDIT: wrapper maketoolbar method refactored into a separate script, with changes to the toolbar. Reorder layers functionality added as well --- tcltk/Makefile | 2 + tcltk/reorderLayers.tcl | 316 ++++++++++++++++++++++++++++++++++++++++ tcltk/toolbar.tcl | 221 ++++++++++++++++++++++++++++ tcltk/wrapper.tcl | 147 ++----------------- 4 files changed, 548 insertions(+), 138 deletions(-) create mode 100644 tcltk/reorderLayers.tcl create mode 100644 tcltk/toolbar.tcl diff --git a/tcltk/Makefile b/tcltk/Makefile index 10dd8087..3e74017d 100644 --- a/tcltk/Makefile +++ b/tcltk/Makefile @@ -16,6 +16,8 @@ TCL_FILES = \ tkcon.tcl \ tkshell.tcl \ wrapper.tcl \ + toolbar.tcl \ + reorderLayers.tcl \ console.tcl \ techbuilder.tcl \ cellmgr.tcl \ diff --git a/tcltk/reorderLayers.tcl b/tcltk/reorderLayers.tcl new file mode 100644 index 00000000..997a9079 --- /dev/null +++ b/tcltk/reorderLayers.tcl @@ -0,0 +1,316 @@ + +global Opts + +global search_var +global current_toolbar +global search_var "" + +# Dialog window to reorder layers in the toolbar, as well as remove some of them +proc magic::reorderToolbar {framename} { + global Opts + global current_toolbar + + # Create the main window + if {[catch {toplevel .reorder}]} { + foreach child [winfo children .reorder] { + destroy $child + } + } + + # Establish the geomtery of the window + reorderToolbar_addWidgets + + # Add all the functionalities to the placed widgets + reorderToolbar_widgetBindings $framename + + # Clear the current listbox contents + # .reorder.frame.listbox delete 0 end + + # Populate the listbox initially + set all_layers_array [split $current_toolbar] + updateTreeview $all_layers_array +} + +proc reorderToolbar_addWidgets {} { + # Set the window title + wm title .reorder "Reorder layers" + + # Add the container frame for the window + frame .reorder.frame -borderwidth 1 + grid .reorder.frame -pady 10 -padx 10 + + # Add the searchbar for layers + # TODO fix without using a global variable. + global search_var "" + label .reorder.frame.search_label -text "Search layer: " + entry .reorder.frame.entry -textvariable search_var -width 30 + + # Add the dropdown menu which allows to load a chosen toolbar + label .reorder.frame.toolbar_search_label -text "Preset toolbar: " + ttk::combobox .reorder.frame.toolbar_preset_menu -textvariable selected_toolbar + + # Add the listbox, containing all the layers + # listbox .reorder.frame.listbox -width 40 -height 10 + ttk::treeview .reorder.frame.tree -columns {layer order} -show headings + # TODO fix this to show... -show headings broke it somehow + .reorder.frame.tree insert {} end -id 0 -tag treeAll \ + -text "All layers" -values {"All layers" -} -open true + .reorder.frame.tree heading layer -text "Layer" + .reorder.frame.tree heading order -text "Toolbar row" + + # Add buttons for editing layer ordering + button .reorder.frame.move_layer_button -width 10 -text "Move layer" + button .reorder.frame.group_layer_button -width 10 -text "Group selected" + button .reorder.frame.delete_layer_button -width 10 -text "Delete layer" + + # Add the buttons at the bottom (Confirm, Load, and Save) the toolbar settings + button .reorder.frame.button_confirm -width 10 -text "Confirm" + button .reorder.frame.button_save -width 10 -text "Save" + button .reorder.frame.button_load -width 10 -text "Load" + + # Organize widgets placement in the window + grid .reorder.frame.search_label -row 0 -column 0 -sticky e -columnspan 1 + grid .reorder.frame.entry -row 0 -column 1 -sticky we -columnspan 2 + grid .reorder.frame.tree -pady 5 -row 1 -column 0 -columnspan 3 -rowspan 3 -sticky we + grid .reorder.frame.move_layer_button -padx 5 -pady 5 -row 1 -column 3 -sticky sn + grid .reorder.frame.delete_layer_button -padx 5 -pady 5 -row 2 -column 3 -sticky sn + grid .reorder.frame.group_layer_button -padx 5 -pady 5 -row 3 -column 3 -sticky sn + grid .reorder.frame.toolbar_search_label -row 4 -column 0 \ + -columnspan 1 -sticky e + grid .reorder.frame.toolbar_preset_menu -row 4 -column 1 \ + -columnspan 2 -sticky nw + grid .reorder.frame.button_confirm -pady 5 -padx 10 -row 5 -column 0 \ + -columnspan 1 -sticky w + grid .reorder.frame.button_save -pady 5 -padx 10 -row 5 -column 1 \ + -columnspan 1 -sticky w + grid .reorder.frame.button_load -pady 5 -padx 10 -row 5 -column 2 \ + -columnspan 1 -sticky w +} + +proc reorderToolbar_widgetBindings {framename} { + + global current_toolbar + + set all_layers_array [split $current_toolbar] + + # When window is closed reset the search entry + bind .reorder.frame {set search_var ""} + + # Bind the updateTreeview function to the entry widget + bind .reorder.frame.entry [list updateTreeview $all_layers_array] + + # configure the combobox widget to include all the presets in toolbox.tcl + .reorder.frame.toolbar_preset_menu configure -values [reorderToolbar_getToolbarPresets] + + # Bind the Move layer, Delete layer, and Group selection buttons + + bind .reorder.frame.move_layer_button { + set selectedItems [.reorder.frame.tree selection] + puts "$selectedItems" + } + + bind .reorder.frame.delete_layer_button { + # Get selected layers from the tree and delete them (from the tree) + set selectedItems [.reorder.frame.tree selection] + if {[llength $selectedItems] > 0} { + + global current_toolbar + + # Delete layers from the tree, and from the $current_toolbar, sourced from toolbar.tcl + # in order to reuse updateTreeview to simply regenerate the tree. Note, this is doesn't + # remember the changes the user made. The user needs to give a name to the preset and click + # the Save button + foreach item $selectedItems { + # remove item from current_toolbar, inplace + #set current_toolbar [lreplace $current_toolbar [set current_toolbar {}] \ + #$item $item ] + + set current_toolbar [lreplace $current_toolbar [expr {$item-1}] [expr {$item-1}] ] + } + .reorder.frame.tree delete $selectedItems + # Regenerate the tree + updateTreeview $current_toolbar + } + } + + bind .reorder.frame.group_layer_button { + set selectedItems [.reorder.frame.tree selection] + puts "$selectedItems" + } + + # Bind the Confirm, Save and Load buttons + bind .reorder.frame.button_confirm [list apply {{framename} { + magic::maketoolbar $framename + }} $framename] + + + bind .reorder.frame.button_load [list apply {{framename} { + global search_var + + # clear the search var + set search_var "" + set selected_toolbar_name [.reorder.frame.toolbar_preset_menu get] + + # If an improper string is written in the dropbox, throw an error + if {[lsearch -exact [reorderToolbar_getToolbarPresets] $selected_toolbar_name] == -1} { + after 5 [ list tk_messageBox -icon error -title "Error" \ + -message "Selected preset $selected_toolbar_name is \ + not in the list of toolbar configurations, inside [tech name]_toolbar.tcl. \ + Maybe you would like to save this new configuration?" -parent .reorder.frame] + + # Otherwise, set the listbox content to the toolbar preset + } else { + # Source the presets first. This is done due to scoping of variables + source "${CAD_ROOT}/magic/tcl/toolbar.tcl" + set selected_toolbar_layers [set $selected_toolbar_name] + set layers_list [split $selected_toolbar_layers] + updateTreeview $layers_list + reorderToolbar_set-current_toolbar $layers_list + } + }} $framename] + + bind .reorder.frame.button_save { + set toolbar_ordering [reorderToolbar_getListboxContents] + } + +} + +proc reorderToolbar_set-current_toolbar { toolbar_preset } { + global fileName + global current_toolbar + + # if [tech name]_toolbars.tcl exists in the directory + if {$fileName ne ""} { + # Read the content of toolbar.tcl + set scriptContent [exec cat $fileName] + + # Change the value in the script content + set substitution [subst {set current_toolbar \{$toolbar_preset\} }] + + regsub -line -all {set current_toolbar \{.*\}} $scriptContent \ + $substitution newScriptContent + + # Write the updated content back to toolbar.tcl + set scriptFile [open $fileName w] + puts $scriptFile $newScriptContent + close $scriptFile + } else { + set current_toolbar $toolbar_preset + } +} + +# Get the layers ordering from the listbox in reorderToolbar +proc reorderToolbar_getListboxContents {} { + set listboxLayers {} + set listbox .reorder.frame.listbox + + # Regular expression to match "word" followed by one or more spaces and one or more digits + set regex {^(\w+)\s+\d+} ; + for {set i 0} {$i < [$listbox size]} {incr i} { + set item [$listbox get $i] + if {[regexp $regex $item match layer]} { + lappend listboxLayers $layer + } + } + return $listboxLayers +} + +# return the names of the toolbar presets defined in toolbar.tcl +# TODO: find a better way to implement this +proc reorderToolbar_getToolbarPresets {} { + + global fileName + global current_toolbar + if {$fileName ne ""} { + set toolbarPresets [list] + # Get the variable names defined so far + set oldVariables [info vars] + # [info vars] does not take into account the new variable + lappend oldVariables "oldVariables" + + source $fileName + + # Find the new variables + foreach item [info vars] { + if {[lsearch -exact $oldVariables $item] == -1} { + lappend toolbarPresets $item + } + } + } else { + lappend toolbarPresets "default_toolbar" + } + + # Return the toolbar preset names + return $toolbarPresets +} + + +# update the listbox in the Reorder layers window +proc updateTreeview {data} { + global search_var + set treeAll_id [.reorder.frame.tree tag has "treeAll"] + + set search [string tolower $search_var] + set layers_containing_string [lsearch -inline -all $data *$search*] + set layers_not_containing_string [lsearch -inline -all -not $data *$search*] + + # destroy the treeview, so when we update with a new preset, we can clean everything + foreach child [.reorder.frame.tree children $treeAll_id ] { + .reorder.frame.tree delete $child + } + # 1) populate the tree: if items already exist, dont insert, if not insert (check using tag) + # 2) if layer is in layers_containing string: move it to proper position + # 3) if item is in layers_not_containing, delete it + set i $treeAll_id + foreach item $data { + incr i + # if the layer is not in the treeview, insert it + if { [string equal [.reorder.frame.tree tag has $item] ""] } { + .reorder.frame.tree insert $treeAll_id end -id $i -tags $item -values "$item $i" + } + + if { [lsearch -inline -all $layers_containing_string $item] != ""} { + .reorder.frame.tree move [.reorder.frame.tree tag has $item] $treeAll_id end + } + + if { [lsearch -inline -all $layers_not_containing_string $item] != ""} { + .reorder.frame.tree delete [.reorder.frame.tree tag has $item] + } + } +} + + +# Function to handle input submission +proc handleInput {entry listbox selectedLayer selectedIndex} { + set inputNumber [$entry get] + if {$inputNumber ne ""} { + set formattedText [format "%-20s %5s" $selectedLayer $inputNumber] + $listbox delete $selectedIndex + $listbox insert $inputNumber $formattedText + + # Renumber the layers, between where the selected layer was removed and inserted + renumberListbox $listbox $selectedIndex $inputNumber + destroy .inputWindow + } +} + +proc renumberListbox {listbox initialIndex finalIndex} { + # if layer was inserted above where it was originally + if {$initialIndex > $finalIndex } { + for { set ind [expr {$finalIndex + 1 }] } { $ind <= $initialIndex } { incr ind 1 } { + set selectedLayer [lindex [$listbox get $ind] 0] + set formattedText [format "%-20s %5s" $selectedLayer $ind] + $listbox delete $ind + $listbox insert $ind $formattedText + } + } + # if layer was inserted below where it was originally + if {$initialIndex < $finalIndex } { + for { set ind $initialIndex } { $ind < $finalIndex } { incr ind 1 } { + set selectedLayer [lindex [$listbox get $ind] 0] + set formattedText [format "%-20s %5s" $selectedLayer $ind] + $listbox delete $ind + $listbox insert $ind $formattedText + } + } +} diff --git a/tcltk/toolbar.tcl b/tcltk/toolbar.tcl new file mode 100644 index 00000000..a587dac3 --- /dev/null +++ b/tcltk/toolbar.tcl @@ -0,0 +1,221 @@ +global Opts +global Winopts + +global current_toolbar +global fileName + +# Generate the toolbar for the wrapper +proc magic::maketoolbar {framename} { + + global Opts + global Winopts + # Don't do anything if in suspend mode + set topname [winfo toplevel $framename] + if {[info exists Winopts(${topname},suspend)]} { + if { $Winopts(${topname},suspend) > 0} { return } + } + + if {$Opts(toolbar) == 0} { + magic::maketoolimages + set Opts(toolbar) 1 + } + + # Destroy any existing toolbar before starting + set alltools [winfo children ${framename}.toolbar] + foreach i $alltools { destroy $i } + + # All toolbar commands will be passed to the appropriate window + set win ${framename}.magic + + # Generate layer images and buttons for toolbar + if {$Opts(hidespecial) == 0} { + set special_layers {errors labels subcell} + } else { + set special_layers {} + } + + if {$Opts(hidelocked) == 0} { + set all_layers [concat $special_layers [magic::tech layer "*"]] + } else { + set all_layers [concat $special_layers [magic::tech unlocked]] + } + + # Create a canvas for the toolbar + if {![winfo exists ${framename}.toolbar.canvas]} { + canvas ${framename}.toolbar.canvas + } + grid ${framename}.toolbar.canvas -row 0 -column 0 -sticky "news" + + # Add a frame to the canvas, on which the layer buttons and + # labels are placed + frame ${framename}.toolbar.canvas.frame + ${framename}.toolbar.canvas create window 0 0 -anchor nw \ + -window ${framename}.toolbar.canvas.frame + + # Read layers from a tcl file [tech name]_toolbar.tcl + + global current_toolbar + global fileName + + # Check if the file exists, and if not, create it and populate with a default_toolbar + # and a current_toolbar. current_toolbar is a placeholder + if {![file exists "./[tech name]_toolbars.tcl"]} { + # If the file doesn't exist, just set the global variable current_toolba + # which is a default toolbar ordering + set current_toolbar $all_layers + set fileName "" + } else { + # otherwise, use the current_toolbar from the file + set fileName "./[tech name]_toolbars.tcl" + source $fileName + # this will set current_toolbar to the one from the file + } + + + # Place layers on the toolbar + set i 0 + foreach layername $current_toolbar { + createLayerFrame $framename $layername $i + incr i + } + + # Add mouswheel functionlity + # Bind Button-4 (scroll up) and Button-5 (scroll down) to the custom procedure + bind ${framename}.toolbar.canvas [subst { ${framename}.toolbar.canvas \ + yview scroll -1 units}] + bind ${framename}.toolbar.canvas [subst { ${framename}.toolbar.canvas \ + yview scroll 1 units}] + + # Create a vertical scrollbar for the canvas + scrollbar ${framename}.toolbar.vscroll -orient "vertical" \ + -command [list ${framename}.toolbar.canvas yview] + + grid ${framename}.toolbar.vscroll -row 0 -column 1 -sticky "nws" + + # Configure the canvas to use the scrollbar + ${framename}.toolbar.canvas configure -yscrollcommand \ + [list ${framename}.toolbar.vscroll set] + + # Define the canvas scroll region (as an event callback) + bind ${framename} "updateCanvasScrollRegion ${framename}" +} + +# Function to place layer frame with a button and label +# on the toolbar, at a specific row $i +proc createLayerFrame {framename layername i} { + + # All toolbar commands will be passed to the appropriate window + set win ${framename}.magic + + # Frame to group together the layer button and label + frame ${framename}.toolbar.canvas.frame.f$layername + set layer_frame ${framename}.toolbar.canvas.frame.f$layername + grid $layer_frame -row $i -column 0 -sticky "news" + + # Set short naming for buttons and labels + set toolbar_label ${layer_frame}.l + # Place label of layer next to the layer button + label $toolbar_label -text $layername + grid $toolbar_label -row $i -column 1 -sticky "w" + + # Place the layer button, checking if it is locked or not + set locklist [tech locked] + + # Locked button bindings + if {[lsearch $locklist $layername] != -1} { + set toolbar_button ${layer_frame}.p + + button $toolbar_button -image pale_$layername -command \ + "$win see $layername" + bind $layer_frame \ + [subst {focus %W ; ${framename}.titlebar.message configure \ + -text "$layername (locked)"}] + + bind $layer_frame \ + "$win see no $layername" + + bind $layer_frame \ + "$win tech unlock $layername ; \ + grid forget $toolbar_button ; \ + grid ${layer_frame}.b -row $i -column 0 -sticky w" + + # Unlocked button bindings + } else { + + set toolbar_button ${layer_frame}.b + button $toolbar_button -image img_$layername + + # Bind keypresses when mouse if over layer frame + bind $layer_frame "$win paint $layername" + bind $layer_frame "$win select more area $layername" + bind $layer_frame "$win select less area $layername" + bind $layer_frame "$win erase $layername" + + bind $layer_frame \ + "puts $i; \ + $win tech lock $layername ; \ + grid forget $toolbar_button ; \ + grid ${layer_frame}.p -row $i -column 0 -sticky w" + + # Bindings for painiting, erasing and seeing layers, + # which are bound both to the layer button, as well + # as the layer label + set childrenList [winfo children $layer_frame] + + foreach child $childrenList { + # 3rd mouse button makes layer invisible; 1st mouse button restores it. + # 2nd mouse button paints the layer color. Key "p" also does paint, esp. + # for users with 2-button mice. Key "e" erases, as does Shift-Button-2. + bind $child "$win see $layername" + bind $child "$win paint $layername" + bind $child "$win erase $layername" + bind $child "$win see no $layername" + + # Intercept mousewheel on the layer/button as well + bind $child \ + [subst { event generate ${framename}.toolbar.canvas }] + bind $child \ + [subst { event generate ${framename}.toolbar.canvas }] + } + + # Bind the mouse enter event to highlight the label + bind $toolbar_label "$toolbar_label configure -background yellow" + + bind $layer_frame \ + [subst {focus %W ; ${framename}.titlebar.message configure -text "$layername"}] + + } + + # Common bindings + + grid $toolbar_button -row $i -column 0 -sticky "w" + + # Bindings: Leaving the layer row clears titlbar message + bind $layer_frame \ + [subst {${framename}.titlebar.message configure -text ""}] + + # Intercept mousewheel and redirect command to the canvas + bind $layer_frame \ + [subst { event generate ${framename}.toolbar.canvas }] + bind $layer_frame \ + [subst { event generate ${framename}.toolbar.canvas }] + + # Bind the mouse leave event to reset the label + set bgColor [${framename}.toolbar cget -background] + bind $toolbar_label "$toolbar_label configure -background $bgColor" + +} + +# Function to update the canvas scrolling region after a resize +proc updateCanvasScrollRegion {framename} { + set bbox [${framename}.toolbar.canvas bbox all] + set minwidth [expr [lindex $bbox 2] - [lindex $bbox 0]] + if {[llength $bbox] == 4} { + ${framename}.toolbar.canvas configure -scrollregion $bbox + } + ${framename}.toolbar.canvas configure -width $minwidth + set winheight [expr [winfo height ${framename}] \ + - [winfo height ${framename}.titlebar]] + + ${framename}.toolbar.canvas configure -height $winheight +} diff --git a/tcltk/wrapper.tcl b/tcltk/wrapper.tcl index f028cf12..bd99d48e 100644 --- a/tcltk/wrapper.tcl +++ b/tcltk/wrapper.tcl @@ -388,6 +388,14 @@ proc magic::maketechmanager { mgrpath } { catch {source ${CAD_ROOT}/magic/tcl/cellmgr.tcl} +# Generate the toolbar for the wrapper + +catch {source ${CAD_ROOT}/magic/tcl/toolbar.tcl} + +# Include the reorder toolbar script + +catch {source ${CAD_ROOT}/magic/tcl/reorderLayers.tcl} + # Generate the library manager catch {source ${CAD_ROOT}/magic/tcl/libmgr.tcl} @@ -785,144 +793,6 @@ proc magic::maketoolimages {} { } } -# Generate the toolbar for the wrapper - -proc magic::maketoolbar { framename } { - global Opts - global Winopts - - # Don't do anything if in suspend mode - set topname [winfo toplevel $framename] - if {[info exists Winopts(${topname},suspend)]} { - if { $Winopts(${topname},suspend) > 0} { return } - } - - if {$Opts(toolbar) == 0} { - magic::maketoolimages - set Opts(toolbar) 1 - } - - # Destroy any existing toolbar before starting - set alltools [winfo children ${framename}.toolbar] - foreach i $alltools { - destroy $i - } - - # All toolbar commands will be passed to the appropriate window - set win ${framename}.magic - - # Generate layer images and buttons for toolbar - if {$Opts(hidespecial) == 0} { - set special_layers {errors labels subcell} - } else { - set special_layers {} - } - - if {$Opts(hidelocked) == 0} { - set all_layers [concat $special_layers [magic::tech layer "*"]] - } else { - set all_layers [concat $special_layers [magic::tech unlocked]] - } - foreach layername $all_layers { - button ${framename}.toolbar.b$layername -image img_$layername -command \ - "$win see $layername" - - # Bindings: Entering the button puts the canonical layer name in the - # message window. - bind ${framename}.toolbar.b$layername \ - [subst {focus %W ; ${framename}.titlebar.message configure \ - -text "$layername"}] - bind ${framename}.toolbar.b$layername \ - [subst {${framename}.titlebar.message configure -text ""}] - - # 3rd mouse button makes layer invisible; 1st mouse button restores it. - # 2nd mouse button paints the layer color. Key "p" also does paint, esp. - # for users with 2-button mice. Key "e" erases, as does Shift-Button-2. - - bind ${framename}.toolbar.b$layername \ - "$win paint $layername" - bind ${framename}.toolbar.b$layername \ - "$win paint $layername" - bind ${framename}.toolbar.b$layername \ - "$win erase $layername" - bind ${framename}.toolbar.b$layername \ - "$win erase $layername" - bind ${framename}.toolbar.b$layername \ - "$win see no $layername" - bind ${framename}.toolbar.b$layername \ - "$win select more area $layername" - bind ${framename}.toolbar.b$layername \ - "$win select less area $layername" - } - - # Create an additional set of layers and buttons in the "disabled" style - # These buttons can be swapped in place of the regular buttons when the - # layer is locked. They define no bindings except "u" for "unlock", - # and the button bindings (see, see no) - - foreach layername $all_layers { - button ${framename}.toolbar.p$layername -image pale_$layername -command \ - "$win see $layername" - bind ${framename}.toolbar.p$layername \ - "$win see no $layername" - bind ${framename}.toolbar.p$layername \ - [subst {focus %W ; ${framename}.titlebar.message configure \ - -text "$layername (locked)"}] - bind ${framename}.toolbar.p$layername \ - [subst {${framename}.titlebar.message configure -text ""}] - } - - # Figure out how many columns we need to fit all the layer buttons inside - # the toolbar without going outside the window area. - - set locklist [tech locked] - set ncols 0 - - # Sometimes the window manager can have bogus values, so allow an - # environment variable LAYOUT_ICON_COLS to override the number of icon - # columns. - if {[info exists ::env(LAYOUT_ICON_COLS)]} { - set ncols [expr $::env(LAYOUT_ICON_COLS) - 1] - } - - while {1} { - incr ncols - set i 0 - set j 0 - foreach layername $all_layers { - if {[lsearch $locklist $layername] >= 0} { - grid ${framename}.toolbar.p$layername -row $i -column $j -sticky news - } else { - grid ${framename}.toolbar.b$layername -row $i -column $j -sticky news - } - bind ${framename}.toolbar.p$layername \ - "$win tech unlock $layername ; \ - grid forget ${framename}.toolbar.p$layername ; \ - grid ${framename}.toolbar.b$layername \ - -row $i -column $j -sticky news" - bind ${framename}.toolbar.b$layername \ - "$win tech lock $layername ; \ - grid forget ${framename}.toolbar.b$layername ; \ - grid ${framename}.toolbar.p$layername \ - -row $i -column $j -sticky news" - incr j - if {$j == $ncols} { - set j 0 - incr i - } - } - - # Make sure that window has been created so we will get the correct - # height value. - - update idletasks - set winheight [expr {[winfo height ${framename}] - \ - [winfo height ${framename}.titlebar]}] - set toolheight [lindex [grid bbox ${framename}.toolbar] 3] - if {$toolheight <= $winheight} {break} - } -} - # Delete and rebuild the toolbar buttons in response to a "tech load" # command. @@ -1439,6 +1309,7 @@ proc magic::openwrapper {{cell ""} {framename ""}} { $m add separator $m add command -label "Clear Feedback" -command {magic::feedback clear} $m add separator + $m add command -label "Reorder layers" -command "magic::reorderToolbar ${layoutframe}" # ################################# # DRC