• 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. Custom Function when Manually Closing Form

Stats

  • Locked Locked
  • Replies 6
  • Subscribers 143
  • Views 4841
  • 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

Custom Function when Manually Closing Form

Palenzuela18
Palenzuela18 over 1 year ago

Hi everyone. I'm relatively new to SKILL. I have implemented a custom form via "hiCreateLayoutForm(...)". I would like to add a custom "callback" to be executed when the user "closes" the form by pressing the cross at the upper right of the form. Is this even possible? Kind of an "?unmapCB". Thanks in advance.

  • Cancel
  • Andrew Beckett
    Andrew Beckett over 1 year ago

    When you define the form with hiCreateLayoutForm(), the ?callback argument can be a list of two callbacks - the "OK" and "Cancel" callbacks. If you are using a window manager that shows transient forms with a "X" to close the transient form (not all window managers do this), then the Cancel callback will be fired when you do this - there's no need for an additional ?unmapCB as the cancel callback can use used instead. That way you get the same behaviour if you use cancel on the form or close the form via the window manager.

    Regards,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Palenzuela18
    Palenzuela18 over 1 year ago in reply to Andrew Beckett

    Thanks for quick the response Andrew. Sorry for the delayed answer, I haven't got any notification.

    I am NOT using the "?callback" argument because I'm defining the "OK" and "Cancel" callbacks in the "?buttonLayout" argument. I'm using the "?buttonLayout" because I want "OK" and "Apply" to behave differently (apart from "OK" closing the form after the execution of the callback, they have different callbacks).

    Defining the "Cancel" callback in the "?buttonLayout" seems to be the reason why closing the form via "x" doesn't execute this callback too.

    I'll try to find a way to marry the best of both worlds: having different callbacks for "OK" and "Apply" and having the cancel callback executed when pressing "Cancel" or the "X" at the upper right corner.

    My initial intuition was passing the "OK/Apply" and "Cancel" callbacks as a function symbols in the "?callback" argument to check, inside the callback, which was the pressed button (usually, in field button callbacks, the button pressed is passed as an argument to the symbol function). It doesn't seem to be the case.

    To summarize everything, I think your solution doesn't fit my case cause I need "Apply" and "OK" to have different callbacks while "X" and "Cancel" execute the same callback.

    Sorry if this is confusing or I don't properly explain myself. As I said, I'm relatively new to this context.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 1 year ago in reply to Palenzuela18

    Here's an example that (I think) does what you want. The key ideas are:

    1. I have ?buttonLayout specified with callbacks for OK, Apply and Cancel buttons. The OK calls hiFormDone, and Cancel calls hiFormCancel - but print some messages just so you can see what it does
    2. I have specified ?callback too - with both an OK and Cancel callback. The OK callback is just a "No-Op" (this will get called when hiFormDone() is called from the OK callback; we just need it there so there's a Cancel callback). The Cancel callback is the same as with the Cancel button
    3. I then have a "semaphore" so that the cancel callback doesn't get into an infinitely recursive loop. It then knows that it's already in the cancel callback and so doesn't do the core again - that's because I am using hiFormCancel to cancel the form, which triggers the cancel callback - and hence that would keep calling itself over and over again (resulting in a stack overflow).

    Anyway, this example behaves OK and consistently I think. Simply load it and call ExGrid() to see it.

    procedure(ExGrid()
      let((grid)
        grid=hiCreateGridLayout(
          'grid
          ?items
            list(
              list(
                hiCreateLabel(
                  ?name 'enableLabel
                  ?labelText "Enable"
                )
                'row 0 'col 0
              )
              list(
                hiCreateBooleanButton(
                  ?name 'enable
                  ?buttonText " "
                )
                'row 0 'col 1
              )
              list(
                hiCreateLabel(
                  ?name 'libLabel
                  ?labelText "Lib"
                )
                'row 1 'col 0
              )
              list(
                hiCreateStringField(
                  ?name 'lib
                )
                'row 1 'col 1
              )
              list(
                hiCreateLabel(
                  ?name 'cellLabel
                  ?labelText "Cell"
                )
                'row 2 'col 0
              )
              list(
                hiCreateStringField(
                  ?name 'cell
                )
                'row 2 'col 1
              )
              list(
                hiCreateLabel(
                  ?name 'viewLabel
                  ?labelText "View"
                )
                'row 3 'col 0
              )
              list(
                hiCreateStringField(
                  ?name 'view
                )
                'row 3 'col 1
              )
              list(
                hiCreateLabel(
                  ?name 'explanation
                  ?labelText "Fields can also span across multiple columns or rows"
                )
                'row 4 'col 0 'col_span 2
              )
              ; only the entry fields are stretchable
              ; the labels do not stretch
              list('col_stretch 0 0)
              list('col_stretch 1 1)
            )
          ?frame "Grid Layout"
        )
        hiCreateLayoutForm(
          'ExGridLayout
          "Grid"
          ; surround the grid with a vertical box layout
          ; to provide a stretch_item below to prevent fields
          ; spreading vertically when the form is stretched
          hiCreateVerticalBoxLayout(
            'vbox
            ?items
              list(
                grid
                list('stretch_item 1)
              )
          )
          ; specify custom buttons
          ?buttonLayout 
    	'(Empty (OK ExOKCB) (Apply ExApplyCB) (Cancel ExCancelCB))
          ; standard callbacks are so that we have a cancel callback
          ; for when the window manager is used to close the form
          ?callback '(ExNoopCB ExCancelCB)
    ;      ?dialogStyle 'modal
        )
        hiDisplayForm(ExGridLayout)
    ;    printf("Stuff %L\n" ExGridLayout->view->value)
      )
    )
    
    procedure(ExOKCB(form)
      printf("OK pressed\n")
      hiFormDone(form)
    )
    
    ; use a global semaphore (flag) to know if already in the
    ; cancel callback.
    ExInCancelSemaphore=nil
    procedure(ExCancelCB(form)
      ; prevent doing the cancel if already in cancel callback
      ; this works by using a 
      unless(ExInCancelSemaphore
        let(((ExInCancelSemaphore t))
          printf("Cancel pressed\n")
          hiFormCancel(form)
        )
      )
    )
    procedure(ExApplyCB(form)
      printf("Apply pressed\n")
    )
    
    ; this is just so that we have a callback for the ?callback OK callback. Doesn't need to
    ; acutally do anything
    procedure(ExNoopCB(form)
      printf("Do nothing\n")
      t
    )

    Regards,

    Andrew

    • Cancel
    • Vote Up +1 Vote Down
    • Cancel
  • Palenzuela18
    Palenzuela18 over 1 year ago in reply to Andrew Beckett

    Thanks for taking the time, Andrew, it works just as I wanted. I didn't knew that when "hiFormDone()"-ing (and all its equivalents) and "hiFormCancel()"-ing, the functions passed to the "?callback" argument are called.


    I've slightly modified your example though, to avoid the use of a global variable (semaphore). I substituted your cancel callback for the following one. It seems to work as good as yours but the "No-Op" callback is also called when canceling, something not too cumbersome for me.


    procedure(ExCancelCB(form)
    printf("Cancel pressed\n")
    hiFormDone(form)
    )

    Saludos, Palen.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 1 year ago in reply to Palenzuela18

    Hi Palen,

    The difference with your approach to mine is that any changed values on the form are kept when you press cancel (in your case) whereas they are discarded (in my case). So you are not really truly cancelling the form (the behaviour would be different from other Virtuoso forms) if you use your approach. This means that the next time you bring up the form, it will show the values from when you cancelled the form. Of course, this may not matter for your application!

    Regards,

    Andrew

    • Cancel
    • Vote Up +1 Vote Down
    • Cancel
  • Palenzuela18
    Palenzuela18 over 1 year ago in reply to Andrew Beckett

    Hi again Andrew,

    Currently my form is rebuild from the ground up every time is redisplayed, except for some information stored externally, so there's no practical difference between exiting by "hiFormDone"-ing or "hiFormCancel"-ing. I will definitively consider your approach to better fit Virtuoso's forms standard behavior and to be more efficient, but it will require revisiting how the form is designed.

    Thanks a lot. Saludos, Palen.

    • 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