• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Community Forums
  2. Custom IC SKILL
  3. Abstract Form Class

Stats

  • Locked Locked
  • Replies 6
  • Subscribers 143
  • Views 15459
  • Members are here 0
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Abstract Form Class

Curtisma
Curtisma over 6 years ago

Hello:

I am trying to write an abstract class for a form which allows the user to override the main callback called when the ok or apply buttons are pressed.  However, it is not clear how to define the callback as a method rather than as a function object.  I thought maybe I could have a function object that wraps around the method to change the arguments.  However, I don't see how I can get the class object without defining it globally.

Here is what I have so far.  It still is not clear if there is a good workaround for making the main callback a method.

Right now "formObj" would need to be a global in this environment, which is not great.  I suppose I could have the instance constructor function create the global in this environment, but I would prefer to avoid globals.

/*****************************************************************
* *
* AbstractForm *
* *
* An abstract Form Gui Class *
* *
*****************************************************************/

; The main form class
;
; Slots:
; FormName: The name of the form
; Fields: A Tconc list containing each of the form's fields
; Height: The total height of the form's fields
; Width: The max width of the form's field area

defclass( AbstractForm
()
((Name)
(Title)
(FormNameSymbol)
(Fields)
(Height)
(Width))
)
defgeneric(setupFields (obj) nil)
defgeneric(start (obj) nil)
defgeneric(setupHelpButton (obj) nil)
defgeneric(MainCallback (obj form) nil)

let(()
;Override to setup the Fields slot
defmethod(setupFields ((obj AbstractForm))
error("This is an abstract form and is meant to be subclassed. The setupFields method must be overridden")
)
defmethod(start ((obj AbstractForm)) let((form)
; CREATE FORM
Obj->FormName = gensym(obj->Name)
form = hiCreateAppForm(
?name Obj->FormName
?formTitle obj->Title
?fields car(obj->Fields)
?buttonLayout 'OKCancelApply
?callback _MainCallbackFcn
?formType 'nonOptions
?unmapAfterCB t
)
setupHelpButton(obj)
hiInstantiateForm(form)
hiDisplayForm(form)
))
;override to change the help button callback
defmethod(setupHelpButton ((obj AbstractForm))
putprop(Obj->FormName "skyOpenSkyVerHelp()" 'hiHelpAction)
)
; Override to change the main form callback
defmethod(MainCallback ((obj AbstractForm) form)
print("AbstractForm MainCallback")
)
; A private helper function for setting up the main callback function
procedure(_MainCallbackFcn(form)
MainCallback(obj form)
)
)

I am using IC6.1.7

  • Cancel
Parents
  • Andrew Beckett
    Andrew Beckett over 6 years ago

    No need for a global. Put the code in a  file with a .ils suffix (to ensure you are using lexical scoping), and then specify the callback to the hiCreateAppForm using:

    ?callback lambda((form) MainCallback(obj form))

    That will then create a local function within the start function which refers to the obj passed into the start function. Could have nested a procedure inside the defmethod, but this is so simple there's no real need to give it a name since you're passing the function object to the hiCreateAppForm function.

    The code above seems to have a number of typos, but I'm sure that's probably just you simplifying things and you'll spot those. By the way, you should give your methods a unique prefix (starting with an uppercase letter by convention) as it's not terribly safe to have methods called things like start, setupFields as there's a fairly high chance of clashing with somebody else's functions with similar names.

    Regards,

    Andrew.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Curtisma
    Curtisma over 6 years ago in reply to Andrew Beckett

    Thanks Andrew!

    Is there an easy way to create a package that uses the object system?  Will I be able to call a method that was defined within the package outside of the package when both the method and class are defined inside the package?  I am thinking of something like the following for a superclass named hifMultiCell. The filename is hifMultiCell.ils.  Note the usage example at the end.  I'm not sure if the scope of defclass and defmethod relative to the calling of the methods outside the package will be an issue.

    /*****************************************************************
    * *
    * Multiple Cell Selection Form *
    * *
    * A form for selecting multiple cells from a library using a *
    * listbox. The form then runs the MainCallBack when the *
    * the user selects "ok" or "apply" *
    * *
    *****************************************************************/


    hifMultiCell = let(()
    skyVerLoad("hifAbstractForm.ils")

    ; The main form class
    ;
    ; Slots:
    ; FormName: The name of the form
    ; Fields: A Tconc list containing each of the form's fields
    ; Height: The total height of the form's fields
    ; Width: The max width of the form's field area

    defclass( MultiCellForm
    (AbstractForm)
    ((DefaultLibName))
    )

    defmethod(setupFields (obj MultiCellForm)
    obj->Fields = tconc(obj->Fields list(ddHiCreateLibraryComboField(
    ?name 'LibNameField
    ?prompt "Library"
    ?defValue obj->DefaultLibName
    ?callback _LibUpdateCB
    ?toolTip "Library Name"
    ?validationType 'allowExisting
    ?editable t)
    5:10 550:30 110))
    obj->Fields = tconc(obj->Fields list(hiCreateListBoxField(
    ?name 'CellField
    ?prompt "Cells"
    ?choices sort(ddGetObj(obj->DefaultLibName)~>cells~>name nil)
    ?multipleSelect t
    ?enabled t)
    5:10+60 550:200 110))
    )
    ; Callback that updates the cell selection field when the library selection changes.
    procedure(_LibUpdateCB(_o_field g_scope)
    g_scope->CellField->choices = sort(ddGetObj(g_scope->LibNameField->value)~>cells~>name nil)
    g_scope->CellField->value = nil
    )
    (nil
    'New New
    'Start Start
    'MenuCB MenuCB)
    )

    ; Usage example
    formObj =hifMultiCell->New()
    hifMultiCell->Start(formObj)

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 6 years ago in reply to Curtisma

    You can't hide methods by putting them inside a lexical scope - it doesn't work that way, unfortunately. So you can indeed call it the way you want in the example above, but  you equally well could call:

    Start(formObj)

    The class, and methods are in the global scope. You've referenced the generic function Start in your DPL returned by your package, but it's still visible outside.

    Regards,

    Andrew.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Curtisma
    Curtisma over 6 years ago in reply to Andrew Beckett

    Andrew:

    Yeah, thanks, that's what I thought.  I was hoping there was a better way to package objects.  I suppose I'll just give them prefixes.  

    I have seen some code "package" them by creating an environment and calling them from the environment.  For Example:

    hifMultiCell::SomeFunction()

    However, this wouldn't allow me to have the object in the top-level environment right? For example, the code below doesn't work, right? Will the class and generic functions still be defined in the global environment?

    Here hifMultiCell is an environment where the classdef, methoddef and defgeneric have been called for each method in an attempt to keep them from being visible in the calling environment.

    formObj = hifMultiCell::new()
    hifMultiCell::Start(formObj)
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 6 years ago in reply to Curtisma

    Do do this you'd have to use the namespace functionality which is rather challenging to use. I never use it because I don't think it really achieves the purpose of being any more useful than just using prefixes - it's not really a "module" or "package" system.

    Admittedly after the initial implementation of namespaces which was rather broken some things were fixed, and I've not attempted to revisit it to see whether the usability has improved. When I have a moment, I'll do that... so I can't comment that much on how practical it is to use them nowadays.

    Regards,

    Andrew.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
Reply
  • Andrew Beckett
    Andrew Beckett over 6 years ago in reply to Curtisma

    Do do this you'd have to use the namespace functionality which is rather challenging to use. I never use it because I don't think it really achieves the purpose of being any more useful than just using prefixes - it's not really a "module" or "package" system.

    Admittedly after the initial implementation of namespaces which was rather broken some things were fixed, and I've not attempted to revisit it to see whether the usability has improved. When I have a moment, I'll do that... so I can't comment that much on how practical it is to use them nowadays.

    Regards,

    Andrew.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
Children
  • Curtisma
    Curtisma over 5 years ago in reply to Andrew Beckett

    Hey Andrew,

    Did you have a chance to try out the namespace functionality?

    I found this set of code that is using it extensively to package their code:

    https://github.com/MatthewLoveQUB/SKILL_Tools

    I haven't tried it myself yet since you suggested it might be broken.

    Let me know if you still think it's broken and what's broken about it.

    -Curtis

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel

Community Guidelines

The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information