This tutorial explains how to perform common GUI customization tasks using the GUI API, such as extending the main menu, extending the popup menu, and adding your own custom widgets.
The tutorial comes with a number of example Tcl files in demo/api/guiCustomization
.
You can load these Tcl files as usual Userware scripts, e.g. at application startup using GateVision PRO’s command-line option -userware demo/api/guiCustomization/script-name.tcl
, from the menu, or with the source demo/api/guiCustomization/script-name.tcl
command from the GUI’s Console window.
Extending the Main Menu
A new main menu entry (along with an empty sub-menu) can be added by using the gui menu mainMenu $name -position $position
command.
$name
is the display text of the menu entry in the main menu - if you add an underscore character _
to the $name
, the following character will be the menu entry’s keyboard shortcut in combination with the Alt key.
The optional $position
argument is either a number denoting the absolute insert position of the new menu entry into the main menu, or end
(the default), which puts the new menu entry right of all existing menu entries.
Note
|
The Help menu will always stay at the rightmost position.
|
Example
gui menu mainMenu _Custom -position 5
This adds a new menu entry names Custom
to the fifth position in the main menu, and assigns the keyboard shortcut Alt+C.
The new main menu entry can now be populated by:
gui menu command $path $command
which adds a simple menu item with an associated command,
gui menu checkbutton $path $command $variableName
which adds a checkable menu item where the check state is stored in the given variable,
gui menu radiobutton $path $command $variableName $variableValue
which adds a radio-button style menu item,
gui menu separator $path
which adds a menu separator and
gui menu submenu $path
which adds a menu item with an empty sub-menu.
The $path
argument of these commands defines the menu hierarchy into which to insert the new menu item, where the last item of $path
is the name of the new menu item - again, you can use an underscore character (_
) to define the keyboard shortcut.
Example
The following examples use as $command procedures that are defined in the demo/api/guiCustomization/customizeMenu.tcl
script.
gui menu command \
{{Custom} {_Into Memory}} \
{CustomizeMenu:intoMemory}
This adds a new menu item with the name Into Memory
and with the keyboard shortcut Alt+I into the sub-menu of the Custom
main menu entry and associates it with the command CustomizeMenu:intoMemory
(this command is run whenever the menu item is clicked).
gui menu submenu \
{{Custom} {_Rotate}}
This adds a new menu item with the name Rotate
and the keyboard shortcut Alt+R and an empty sub-menu into the sub-menu of the Custom
main menu entry.
gui menu command \
{{Custom} {Rotate} {_0}} \
{CustomizeMenu:rotate R0}
This adds a new menu item with the name 0
and the keyboard shortcut Alt+0 into the Custom / Rotate
sub-menu, and associates the command CustomizeMenu:rotate R0
with it.
gui menu checkbutton \
{{Custom} {Show _Net Names}} \
{gui settings changed} \
[gui settings variable "nlv:shownetname"]
This adds a checkable menu item named Show Net Names
and with the keyboard shortcut Alt+N into the sub-menu of the Custom
main menu entry. The check state is reflected in the nlv:shownetname
settings variable (this is a global configuration option - normally set via the Preferences dialog - that specifies if the names of nets should be shown in the Schematic view). Every time the menu item is clicked, the value of nlv:shownetname
setting is flipped and the command gui settings changed
is executed.
You can also perform context sensitive modifications to menu items by using the gui menu customizeEntry $path $command
command. The $command
is executed right after opening the corresponding menu and creating the menu item indicated by $path
. $command
is called with an $menuId
parameter which is the current Tk menu widget; by definition, the menu entry indicated by $path
is the last item of the Tk menu, so it can be referenced by the index end
when calling $menuId
sub-commands within $command
.
Example
proc CustomizeMenu:enableIfAnInstanceIsSelected {menuId} {
set hasInstSelection 0
set db [gui get database]
if {$db != {}} {
foreach oid [gui selection get] {
if {[$db oid type $oid] eq "inst"} {
set hasInstSelection 1
break
}
}
}
$menuId entryconfigure end \
-state [expr {$hasInstSelection ? "normal" : "disabled"}]
}
# Only enable the "Custom / Rotate" sub-menu if at least one object of
# type "Inst" is selected:
gui menu customizeEntry \
{{Custom} {Rotate}} \
CustomizeMenu:enableIfAnInstanceIsSelected
The full example can be found in demo/api/guiCustomization/customizeMenu.tcl
.
Extending the Toolbar
New toolbar buttons can be added with the gui toolbar addButton
function.
Example
set window .
set name toggleNetNames
set imageSetName show-net
set imageSetPattern [file join [file dirname [info script]] show-net-SIZE.png]
set position 10
set command {CustomizeToolbar:toggleNetNames}
set tooltip "Toggle the display of net names in the schematic view"
##
# Load an imageset. Since the file pattern is ".../show-net-SIZE.png", this will
# load 16, 24, 32, 48, 64 pixel versions from ".../show-net-16.png",
# ".../show-net-24.png", etc.
#
gui imageset load $imageSetName $imageSetPattern
gui toolbar addButton \
$window \
$name \
$imageSetName \
-command $command \
-tooltip $tooltip \
-position $position
proc CustomizeToolbar:toggleNetNames {} {
gui settings set "nlv:shownetname" [expr {![gui settings get "nlv:shownetname"]}]
gui settings changed
}
The full example can be found in demo/api/guiCustomization/customizeToolbar.tcl
.
Extending the Popup Menu
New popup menu entries can be added with gui popup append $label $command ?-menuname $menuname?
, where $label
is the intended menu label, $command
is the command to be associated with the popup menu entry ($command
is appended with the list of currently selected OIDs before being invoked), and $menuname
is the name of the sub-menu to create the new item in (if -menuname $menuname
is not specified, the menu item is created in a sub-menu called Userware
).
Example
gui popup append \
-menuname "Custom" \
"Toggle Net Names" \
{CustomizePopup:toggleNetNames}
gui popup append \
-menuname "Custom" \
"Rotate +90" \
{CustomizePopup:rotate +R90}
proc CustomizePopup:toggleNetNames {oids} {
gui settings set "nlv:shownetname" [expr {![gui settings get "nlv:shownetname"]}]
gui settings changed
}
proc CustomizePopup:rotate {mode oids} {
set db [gui database get]
foreach oid $oids {
if {[$db oid type $oid] eq "inst"} {
$db orient $oid $mode
}
}
gui database modified
}
This example creates two popup menu items Custom / Toggle Net Names
and Custom / Rotate 90
.
In order to customize the new popup menu entries (e.g. enable them only under specific conditions), gui popup customize $command
can be used.
This executes $command
($command
is appended with the Tk menu command corresponding to the popup menu and the list of currently selected OIDs before being executed) every time the popup menu is invoked, right after it is filled with all entries.
Example
gui popup customize {CustomizePopup:customize}
proc CustomizePopup:containsInst {oids} {
set db [gui database get]
if {$db != {}} {
foreach oid $oids {
if {[$db oid type $oid] eq "inst"} {
return 1
}
}
}
return 0
}
proc CustomizePopup:customize {menu oids} {
# Always enable our own "Custom" popup menu item.
$menu entryconfigure "Custom" -state normal
# Get the "Custom" sub-menu.
set customMenu [$menu entrycget "Custom" -menu]
# Always enable "Custom / Toggle Net Names".
$customMenu entryconfigure "Toggle Net Names" \
-state normal
# Only enable "Custom / Rotate 90" if at least one instance is
# selected.
set hasInst [CustomizePopup:containsInst $oids]
$customMenu entryconfigure "Rotate 90" \
-state [expr {$hasInst ? "normal" : "disabled"}]
}
The full example can be found in demo/api/guiCustomization/customizePopup.tcl
.
Adding Custom Widgets
GateVision PRO has a dedicated area where custom widgets can be shown - the bottom tabs that also contain the Search window, the Infobox, etc.
Users can add their own widgets into this area using the gui window insertCustomWidget $name
command, where $name
is the label displayed on the newly added tab.
gui window insertCustomWidget
internally creates a new ttk::frame
and return’s its widget path.
This ttk::frame
is fully customizable by the user (e.g. by adding child widgets, etc.).
The custom widget (and the corresponding tab) can be removed with gui window removeCustomWidget $name
.
The optional parameter -pluginNamespace
can be used to call the Finit
procedure in the given namespace to unload and therewith disable the plugin when the custom widget is destroyed (e.g. when the user clicks the 'x' in the widget’s tab).
Example
set name "My Custom Widget (in the bottom tab area)"
set customWidget [gui window insertCustomWidget $name]
ttk::label $customWidget.label \
-text "This is a custom widget."
ttk::button $customWidget.btnRemove \
-text "Remove" \
-command [list gui window removeCustomWidget $name]
pack $customWidget.label
pack $customWidget.btnRemove
This creates a custom widget and inserts it into the bottom tabs as My Custom Widget
.
The custom widget contains a label and a button that removes the widget by calling gui window removeCustomWidget
.
Instead of the "bottom tab" area, a custom widget can also be inserted into an arbitrary Tab window by using the -tabwindow $tab
option:
Example
set name2 "My Custom Widget (in an arbitrary tab)"
# get the Tab window where the "Schem" window lives in
set tab [gui window getTab "Schem"]
set customWidget2 [gui window insertCustomWidget -tabwindow $tab $name2]
ttk::label $customWidget2.label \
-text "This is a custom widget in the default Tab window."
pack $customWidget2.label
The full example can be found in demo/api/guiCustomization/customWidget.tcl
.
Changing the GUI Layout
This example adds a new Cone window to the right of the default/main Schem window using the high-level API function gui window split …
:
# get the main Schem window
set schem [gui window defaultClassWindow Schem]
# create an empty Tab window right of the Schem window
set tab [gui window split $schem right]
# insert a new Cone window into the Tab window
gui window new -tabwindow $tab "Cone"
This example adds a row with new Schem, Cone and Source windows using lower level API functions:
##
# Get the main vertical pane window of the main window.
#
set mainVertical [gui window getMainVerticalPane .]
##
# Insert a new horizontal pane window into the main vertical pane.
# It is added bottom-most into the vertical pane, but above the Console and
# Messages windows.
#
set horizontal [gui window createHorizontalPane $mainVertical]
##
# Create and insert three vertical Pane windows into the horizontal Pane.
#
set vertical1 [gui window createVerticalPane $horizontal]
set vertical2 [gui window createVerticalPane $horizontal]
set vertical3 [gui window createVerticalPane $horizontal]
##
# Insert a Tab window into each of the vertical Pane windows.
#
set tab1 [gui window createTab $vertical1]
set tab2 [gui window createTab $vertical2]
set tab3 [gui window createTab $vertical3]
##
# Space the three vertical Pane windows evenly by setting the horizontal
# pane's sash positions to 1/3 and 2/3.
#
gui window setPaneSashes $horizontal {0.333 0.666}
##
# Insert new Schem, Cone, Source windows into the three Tab windows.
#
gui window new -tabwindow $tab1 "Schem"
gui window new -tabwindow $tab2 "Cone"
gui window new -tabwindow $tab3 "Source"
This example adds a new top-level window with side-by-side Schem and Cone windows at the top and a full-width Source window at the bottom.
##
# Create a new top-level window (this also creates and inserts the
# obligatory vertical pane).
#
set top [gui window createToplevel]
##
# Show it.
#
gui window modelessDialog \
$top \
"My Custom Top-Level Window" \
-place "CENTER" \
-size {800 600} \
-onTop \
-closeCallback "destroy $top"
##
# Get the vertical pane.
#
set vertical [gui window getMainVerticalPane $top]
##
# Create two horizontal panes.
#
set horizontal1 [gui window createHorizontalPane $vertical]
set horizontal2 [gui window createHorizontalPane $vertical]
##
# Space the horizontal panes evenly (set the vertical pane's sash
# position to 1/2).
#
gui window setPaneSashes $vertical {0.5}
##
# Create some vertical Pane windows.
#
set vertical1_1 [gui window createVerticalPane $horizontal1]
set vertical1_2 [gui window createVerticalPane $horizontal1]
set vertical2 [gui window createVerticalPane $horizontal2]
##
# Space the vertical pane windows in the first horizontal Pane evenly by
# setting its sash position to 1/2.
#
gui window setPaneSashes $horizontal1 {0.5}
##
# Create a Tab window in each vertical Pane.
#
set tab1_1 [gui window createTab $vertical1_1]
set tab1_2 [gui window createTab $vertical1_2]
set tab2 [gui window createTab $vertical2]
##
# Insert Schem, Cone, Source windows into the Tab windows.
#
gui window new -tabwindow $tab1_1 "Schem"
gui window new -tabwindow $tab1_2 "Cone"
gui window new -tabwindow $tab2 "Source"
The full example can be found in demo/api/guiCustomization/customizeLayout.tcl
.