Library Manager Customization Using lmgr SKILL Functions
Each of these examples demonstrates some aspect of the Library Manager customization. Some examples solve a particular requirement. Others just demonstrate a principle.
Each example includes both the code you add to the cdsLibMgr.il file and the functions you need to define in the Virtuoso Studio design environment.
Example 1: Checking for Startup of Virtuoso in a Design Management System
In this example, the initialization procedure is used to check whether Virtuoso Studio design environment has been started from a design management workarea. If not, the Design Manager pull-down menu and all of the menu items contained within it are set to be unmanaged. This simplifies the appearance of the Library Manager menus for those not using design management.
; specify names of functions to call at startup and exit
lmgrDefineInits('("abLibMgrInitProc") '("abLibMgrCloseProc"))
/******************************************************************
* *
* abLibMgrInitProc() *
* *
* When Library Manager is initialized, this gets invoked. *
* It checks to see if we're in a DM workarea, and if not, removes *
* all the DM menus from the libManager. *
* *
******************************************************************/
procedure ( abLibMgrInitProc ( ) let ( ( path dm filePD )
path = simplifyFilename ( getWorkingDir ( ) )
dm = ddGetPathDMSys ( path )
; if you're not in a DM workarea, then remove the Design
Manager
; menu
when ( null ( dm ) || equal ( dm "none" )
lmgrManageMenuItems ( list ( "designCascade" ) nil )
lmgrDisplayMessage ( "Not in DM workarea, so DM menus
removed\n" )
)
t
)
)
/*************************************************************** * *
* abLibMgrCloseProc () *
* *
* Sample close procedure. *
* *
***************************************************************/
procedure ( abLibMgrCloseProc ( ) ; no reason to display lib manager, since it has been closed.
printf ( "My closing procedure was called\n" )
)
Example 2: Displaying Checked-Out Library Manager Cellviews and Files
This example uses a script, tdmfindallcheckouts, to display all files and cellviews in a library selected within the Library Manager that are checked out and opened by any user.
The menu command starts the callback in Virtuoso, which then uses asynchronous techniques to start the script that uses SKILL IPC. Because the program does not block the user interface, you do not need to wait for it to finish. When the results are available, they are postprocessed and displayed in a Show File window.
This example demonstrates the principles of using an external program via IPC and of displaying the results to the user using a Virtuoso applet.
lmgrCreateMenuItem ( "ShowAllCheckOuts" "simple"
'( ( "label" "Show All CheckOuts" )
( "callback" ("abShowAllCheckOuts" ) )
)
)
; show the pop-up in library (L) list box only, and on the ; design manager pull-down menu lmgrAddMenuItems ( "designCascade" "L" '( "ShowAllCheckOuts" ) )
; define the command to execute to find out the checkout information
unless ( boundp( 'abShowAllCheckOutsCommand )
abShowAllCheckOutsCommand="tdmfindallcheckouts -lisp"
)
* abListCompare ( a b ) *
* *
* Compares two lists of strings, for use in a sort function. *
* *
* *
***************************************************************/
procedure ( abListCompare ( a b ) let( ( ( status 0 ) )
while ( status==0 && a && b
status=strcmp ( car ( a ) car( b ) )
a=cdr ( a )
b=cdr ( b )
)
status<0
))
/******************************************************************* * *
* abShowAllCheckOutsPostHandler(child exitStatus) * *
* Read the results of tdmfindallcheckouts - which is in LISP format
* for parsing. Then sort it and display it neatly in a window to
* the user. This function gets called when the tdmfindallcheckouts *
* command completes.
* *
********************************************************************/
procedure( abShowAllCheckOutsPostHandler(child exitStatus) let( (fileName filePort readData window owner libName cellName viewName)
fileName=abShowAllCheckOutsFileTable[child]
if( fileName then
/* read the data from the tdmfindallcheckouts output file -
- it's in LISP syntax, so simple to read */
filePort=infile(fileName)
when(filePort
readData=car(lineread(filePort))
close(filePort)
)
/* remove the file - don't want to leave junk around */
deleteFile(fileName)
/* remove entry from the file table */
remove(child abShowAllCheckOutsFileTable)
if( readData then
/* create a text window */
window=hiCreateWindow(list(100:100 500:400) "text"
"Show File")
/* put the show file menus in */
hiInsertBannerMenu(window fileMenu 0)
/* sort the data, user, then lib, cell, view */
readData=sort(readData 'abListCompare)
/* put the titles in the window */
hiTextDisplayString(window sprintf(nil "%-10s %-10s
%-10s %-10s\n"
"Library" "Cell" "View" "CheckOut") nil)
hiTextDisplayString(window sprintf(nil "%-10s %-10s
%-10s %-10s\n"
"=======" "====" "====" "========") nil)
/* output the entries into the window */
foreach( entry readData
/* set the variables to the values in the list -
do it this way to make sure that each
variable has a default value of "" if the list isn't long enough */
owner=libName=cellName=viewName=""
foreach( (val varName) entry '(owner libName
cellName viewName)
set(varName val)
)
/* display the formatted output in the window */
hiTextDisplayString(window
sprintf(nil "%-10s %-10s %-10s %-10s\n"
libName cellName viewName owner) nil)
) ; foreach
/* set the title */
hiSetWindowName(window "Show All Checkouts")
/* finally, display the window to the user */
hiDisplayWindow(window)
else
lmgrDisplayMessage("No cellViews checked out\n")
) ; if
else
lmgrDisplayMessage("Couldn't find fileName for show all
checkouts\n")
) ; if
t
))
/******************************************************************* * *
* abShowAllCheckOuts(MenuName lib cell view file cat) *
* *
* Callback function for show all checkouts. Checks to see *
* if a library has been selected, is under DM, and then *
* starts the script to find all the checkouts. The post *
* handler will take care of reading the results and displaying *
* them in a window. This means that it will behave asynchronously. *
* *
*******************************************************************/
procedure( abShowAllCheckOuts(MenuName lib cell view file cat) let( (fileName dirName handle)
cond(
(lib==""
lmgrDisplayMessage("Must have library name
selected\n")
)
(ddAmUsingDM(ddGetObj(lib))
dirName=ddGetObj(lib)~>readPath
unless( boundp( 'abShowAllCheckOutsFileTable )
abShowAllCheckOutsFileTable=makeTable(
'abShowAllCheckOutsTable nil)
)
fileName=makeTempFileName("/tmp/abShowAllCheckOuts")
; fire off background process
handle=ipcBeginProcess(
sprintf(nil "%s %s > %s"
abShowAllCheckOutsCommand
dirName fileName)
"" nil nil 'abShowAllCheckOutsPostHandler)
; remember where the output was stored
abShowAllCheckOutsFileTable[handle]=fileName
lmgrDisplayMessage(
sprintf(nil
"Finding all checkouts for %s - this may
take some time\n" lib))
)
(t
lmgrDisplayMessage(sprintf(nil "%s is an unmanaged
library\n" lib))
)
) ; cond
t
))
#!/bin/csh -f
#
# Author John Doe
# Group Custom IC, Cadence UK
# Machine SUN
# Date Mar 13, 1998
# Modified Mar 26, 1998
# By
#
# script to locate all checkouts from a specified library directories
#
# Usage: tdmfindallcheckouts [-lisp] pathToLibrary [pathToLibrary…]
#
# SCCS Info: @(#) tdmfindallcheckouts 03/26/98.14:50:20 1.2
#
set progName=$0 set progName=$progName:t #check for -lisp argument if ("arg$1" == "arg-lisp") then set lispMode
shift
endif
# check sufficient arguments if ($#argv < 1) then echo "Usage: $progName [-lisp] pathToLibrary"
exit 1
endif
# choose awk in a platform independent way if (-x /bin/nawk) then set awk=/bin/nawk
else
set awk=/bin/awk
endif
# if the -lisp argument was specified, write out the query in a form # that's asily readable from SKILL if ($?lispMode) then tdmls -c $* | $awk '\
BEGIN {printf("(\n")}\
{\
owner=$4;\
paths[1]=paths[2]=paths[3]="";\
numf=split($1,paths,"/");\
paths[numf+1]=$2;\
if(paths[1]!=lib || paths[2]!=cell || paths[3]!=view) \
printf("(\"%s\" \"%s\" \"%s\" \"%s\")\n", \
owner,paths[1],paths[2],paths[3]);\
lib=paths[1];cell=paths[2];view=paths[3]}\
END {printf(")\n")}'
else
# otherwise write it out in a human readable form
echo "The following cellViews and files are checked out by:"
tdmls -c $* | $awk '{owner=$4;\
paths[1]=paths[2]=paths[3]="";\
numf=split($1,paths,"/");\
paths[numf+1]=$2;\
if(numf<3 || paths[1]!=lib || paths[2]!=cell || paths[3]!=view) \
print owner ":",paths[1],paths[2],paths[3];\
lib=paths[1];cell=paths[2];view=paths[3]}' | sort
echo "$progName completed"
endif
Example 3: Displaying Cellviews and Files to Be Updated with the Next Update Operation
Use this example to add a new command to display any cellviews and files to be updated when the next update operation is performed.
This example also uses the SKILL IPC to start tdmupdate -n on the directory that has been selected in the Library Manager. That is, if a cell is selected, just the updates within that cell will be reported. Rather than displaying the results in a Show File window, the results from tdmupdate -n are echoed back into the Library Manager output pane.
-
Add the following code to the
cdsLibMgr.ilfile:lmgrCreateMenuItem("ShowUpdates" "simple" '(("label" "Show Updates") ("callback" ("abShowWhatWillBeUpdated")) ) ) ; show the pop-up in library (L), cell (C) and View (V) list boxes lmgrAddMenuItems("designCascade" "LCV" '("ShowUpdates"))
- Define the following code in the Virtuoso session:
/****************************************************************
* *
* abTdmUpdateDataHandler(child data) *
* *
* Data handler for tdmupdate to echo output into the libManager *
* output pane. *
* *
****************************************************************/
procedure(abTdmUpdateDataHandler(child data)
lmgrDisplayMessage(data)
)
/***************************************************************
* *
* abTdmUpdateExitHandler(child status) *
* *
* When tdmupdate -n exits, put a message into the libManager *
* output pane. *
* *
***************************************************************/
procedure(abTdmUpdateExitHandler(child status)
lmgrDisplayMessage("tdmupdate -n completed\n")
)
/*************************************************************** * *
* abRunTdmUpdateCheck(@optional fileName) *
* *
* Start tdmupdate -check, with a couple of handler functions *
* *
***************************************************************/
procedure( abRunTdmUpdateCheck(@optional fileName)
let( (tdmUpdateCmd)
tdmUpdateCmd=if(fileName (strcat "tdmupdate -n " fileName)
"tdmupdate -n")
ipcBeginProcess(tdmUpdateCmd "" 'abTdmUpdateDataHandler nil
'abTdmUpdateExitHandler)
)
)
/******************************************************************* * *
* abShowWhatWillBeUpdated(MenuName lib cell view file cat) *
* *
* This will cause tdmupdate -n to be started on either the lib/cell/
* view selected, or on the whole workarea if nothing is selected. It
* uses IPC to start the command, and the results will be displayed *
* back into the libManager output pane.
* *
*******************************************************************/
procedure(abShowWhatWillBeUpdated(MenuName lib cell view file cat)
let((ddObj ddGetObjArgs)
ddGetObjArgs=setof(lcv list(lib cell view) lcv!="")
if(ddGetObjArgs
then
ddObj=apply('ddGetObj setof(lcv list(lib cell view) lcv!=""))
lmgrDisplayMessage(
sprintf(nil
"The following files will be updated by an update operation
for %s:\n"
buildString(ddGetObjArgs)))
abRunTdmUpdateCheck(ddObj~>readPath)
else
lmgrDisplayMessage("The following files will be updated by an
update for the whole workarea:\n")
abRunTdmUpdateCheck()
)
t
))
Example 4: Replacement of File – New – Library in the Library Manager
One potential problem with File – New – Library in the Library Manager is that it creates the library itself and then triggers Virtuoso to compile a technology file if needed. Therefore, if you define a CreateObj trigger in Virtuoso, the trigger will not be started if the library is created from the Library Manager.
You can resolve this problem by removing the existing facility in the Library Manager and creating a new menu item for which the callback is the function that is started from File – New – Library in the CIW.
-
Add the following code to the
cdsLibMgr.ilfile:; create a new menu item to start the new library in Virtuoso ; directly, without the lib manager version of the form appearing lmgrCreateMenuItem("abNewLib" "simple" '(("label" "Library ...") ("callback" ("abCreateNewLib")) )) ; Stop the existing new library "button" from being displayed. ; Do this by unmanaging it lmgrManageMenuItems(list("FileNewLibButton") nil) ; insert the new menu item before the old, now unmanaged, button. lmgrInsertMenuItems("FileNewLibButton" "" '("abNewLib"))
- Use the following function in the Virtuoso session:
/*********************************************************************
* *
* abCreateNewLib(menuName _l _c _v _f _cat) *
* *
* Callback so that the File -> New -> Library from the libManager *
* calls Virtuoso's File -> New -> Library. This means that the library *
* will be created from within Virtuoso so the postCreateLib trigger *
* will get invoked, for example. Most of the arguments here are *
* ignored. *
* *
*********************************************************************/
procedure( abCreateNewLib(menuName _l _c _v _f _cat)
when(equal(menuName "abNewLib") ddsHiCreateLibrary())
)
Example 5: Dynamically Sensitizing Menu Items in a Design Management Workarea
In this particular example, the capabilities of the function shown in Example 1 are extended so that certain menus can be sensitized within a design management workarea, based on whether the library currently selected is managed or not.
When either the pop-up menu is selected or the design manager pull-down menu is selected, the specified map callback is started in Virtuoso. This then sensitizes the menu items from examples 2 and 3 depending on whether the selected library is under DM control or not. It is vital for this kind of pre-map callback to be fast so that it can make the modification prior to the menu being displayed without blocking the window system.
-
Add the following code to the
cdsLibMgr.ilfile:lmgrCreateMenu("popup" '(("mapCallback" ("abPopupCallback")))) lmgrCreateMenu("designCascade" '(("mapCallback" ("abPopupCallback"))))
- Define the following function in Virtuoso:
/********************************************************************
* *
* abPopupCallback(_menuName lib _c _v _f _cat) *
* *
* pre-map callback to be started from either pop-up or design manager *
* pull-down. This sensitizes two of the menu items based on whether *
* this library is DM managed or not. *
* *
********************************************************************/
procedure( abPopupCallback(_menuName lib _c _v _f _cat)
lmgrSensitizeMenuItems('("ShowAllCheckOuts" "ShowUpdates")
lib!="" && ddAmUsingDM(ddGetObj(lib)))
t
)
Example 6: Changing Labels and Fonts
You can use this sample function either in Virtuoso or in the cdsLibMgr.il file. In the following simple example, the label for Copy Wizard is changed to Advanced Copy and the font for File – Open is changed.
; change label for Copy Wizard
lmgrSetObject("editCopyButton" '(("label" "Advanced Copy...")))
;; choose silly font for File->Open
lmgrSetObject("FileOpenButton"
'(("font"
"-adobe-helvetica-medium-o-normal--12-120-75-75-p-67-iso8859-1"))
)
Example 7: Adding Toggles and Radio Button Fields
This example does not perform any useful task, but it demonstrates how you use the other menu types that are available. It creates a new pull-down menu in the menu bar, GUI Objects, which contains a toggle menu underneath, and then a submenu containing three radio options. The callback to Virtuoso causes a message to be displayed on the Library Manager output pane reflecting the current settings.
; create the toggle button
lmgrCreateMenuItem("ToggleExample" "toggle"
'(("label" "Toggle Example")
("callback" ("abToggleExample"))
)
)
; create a new pull-down menu, to contain the toggle example
lmgrCreateMenu("GUIcascade" '(("label" "GUI Objects")))
; Add the toggle example into the new pull-down menu
lmgrAddMenuItems("GUIcascade" "" '("ToggleExample"))
; Add the new pull-down menu into the menu banner
lmgrAddMenuItems("menuBar" "" '("GUIcascade"))
; Create Three radio options
lmgrCreateMenuItem("RadioOption1" "radio"
'(("label" "Option 1")
("callback" ("abRadioExample"))
)
)
lmgrCreateMenuItem("RadioOption2" "radio"
'(("label" "Option 2")
("callback" ("abRadioExample"))
)
)
lmgrCreateMenuItem("RadioOption3" "radio"
'(("label" "Option 3")
("callback" ("abRadioExample"))
)
)
; Create a pull-down to contain the three radio options
lmgrCreateMenu("RadioPulldown" '(("label" "Radio Pulldown")))
; Add the radio options to the pull-down. Note: The radio options must
; be in their own submenu
lmgrAddMenuItems("RadioPulldown" "" '("RadioOption1" "RadioOption2"
"RadioOption3"))
lmgrAddMenuItems("GUIcascade" "" '("RadioPulldown"))
/********************************************************************
* *
* abToggleExample(_menuName _l _c _v _f _cat) *
* *
* Just prints a message saying what the current state of the toggle *
* setting is *
* *
********************************************************************/
procedure( abToggleExample(_menuName _l _c _v _f _cat)
lmgrDisplayMessage(
sprintf(nil "Toggle set to %L\n"
; note - uses assoc to lookup state information
cadr(assoc("state" lmgrGetObject("ToggleExample"))))
)
)
/***************************************************************
* *
* abRadioExample(menuName _l _c _v _f _cat) *
* *
* Displays which radio option was selected or unselected *
* *
***************************************************************/
procedure( abRadioExample(menuName _l _c _v _f _cat)
lmgrDisplayMessage(
sprintf(nil "Radio %s %sselected\n" menuName
if( cadr(assoc("state" lmgrGetObject(menuName))) "" "un")
))
)
Related Topics
Return to top