mgr's weblog

Conditional Commands (And Sheets) Extension for McCLIM

November 24, 2005, Lisp
Last edited on November 24, 2005

Finally my first entry about Lisp! I have been intending to write about my CLIM demonstration Town Example, the File Selector (also embedded into the Lisp Listener and used as the Find File command for Climacs), and the Tab Layout Pane, which is already used by Beirc, but I was too lazy. Now is the time! Be wowed by the shear beauty this impressive screenshot:

screenshot of the conditional commands example

Okay, this entry will not be too much work as I've already written the documentation and can therefore just quote the README file:

-----------------------------------------------------------
    Title: Conditional Commands (And Sheets) Extension
  Created: 2005/11/22
   Author: Max-Gerd Retzlaff , http://bl0rg.net/~mgr
------------------------------------------------------------
  (c) copyright 2005 by Max-Gerd Retzlaff


This extensions tries to add simple and elegant methods to specify dependencies among commands and between commands and sheets of a (Mc)CLIM application.

Imagine an audio player: The play commands should only be enabled if a audio file is loaded; the same is true for the push-buttons that trigger these commands and probably for a slider that might represent the current position in the audio file.

It may also be nice if only the possible commands and gadgets (in general: sheets) will be enabled if you restart the GUI of such a programme (restart only the GUI not the whole programme).


The extensions uses the term conditional command for commands that enable or disable commands and/or sheets, and the term conditional application frame for an application frame in whose context conditional commands are invoked.

It is stored which commands and sheets got disabled during a run of a conditional application frame; when you exit the application frame and run the top level of a newly created instance of the application frame the previous state will be re-established. This implies that only one instance of a conditional application frame can be running at given time!

You can define conditional command by using the macro DEFINE-CONDITIONAL-COMMAND, that is very similar to the CLIM macro DEFINE-COMMAND: The only change is that ENTITIY-ENABLEDNESS-CHANGE is inserted as the new second parameter.


ENTITY-ENABLEDNESS-CHANGE has to be a list that matches the parameter list:

   (application-frame &key enable-commands
                           disable-commands
                           enable-sheets
                           disable-sheets
                           evaluate-this)

For example:

(define-conditional-command (com-bar :name t :menu t
                                     :command-table cruft-command-table)
    (conditional-commands-example :enable-commands  (com-baz)
                                  :disable-commands (com-bar)
                                  :enable-sheets    (thud)
                                  :disable-sheets   (grunt))
    ()
    (format t "~%bar called"))

Note that the elements of the arguments to :ENABLE-COMMANDS and :DISABLE-COMMANDS can not only be names of commands but also names of command-tables; in the latter case all comamnds of the command table will be enabled (or disabled).

With EVALUATE-THIS you can specify a form that will be evaluated when the "entity enabledness change" happens, for conditional commands this is immediately after the body of the command has been executed.

Initially all conditional commands and all sheets that might be disabled by them are enabled. To specify which commands and sheets should initially be disabled when the top level of the application frame is run (CLIM:RUN-FRAME-TOP-LEVEL) there is another macro: DEFINE-CONDITIONAL-APPLICATION-FRAME. It is very similar to CLIM:DEFINE-APPLICATION-FRAME, only ENTITY-ENABLEDNESS-CHANGE is inserted as the new third parameter.


In this case ENTITY-ENABLEDNESS-CHANGE has to be a list that matches the parameter list:

   (&key enable-commands
         disable-commands
         enable-sheets
         disable-sheets
         evaluate-this)

For example:

(define-conditional-application-frame conditional-commands-example ()
  (:disable-commands (com-bar com-baz)
   :disable-sheets (thud grunt)
   :evaluate-this (incf incarnation-number))
  ()
  (:command-table ...)
  (:panes ...)
  ...)

This "entity enabledness change" happens in a :BEFORE method of CLIM:RUN-FRAME-TOP-LEVEL that dispatches on the just defined conditional application frame.


It might be less confusing to define all "entity enabledness changes" in one place, therefore it is also possible to define an "entity enabledness change" separately, for example:

(add-entity-enabledness-change 'com-baz 'conditional-commands-example
                               :enable-commands  '(com-bar)
                               :disable-commands '(com-baz)
                               :enable-sheets   '(grunt)
                               :disable-sheets   '(thud))

The argument to ADD-ENTITY-ENABLEDNESS-CHANGE has to be a list that matches the parameter list:

   (command application-frame &key enable-commands
                                   disable-commands
                                   enable-sheets
                                   disable-sheets
                                   evaluate-this)
To define the "entity enabledness change" of a conditional application frame seperately the first argument to ADD-ENTITY-ENABLEDNESS-CHANGE has to be the string concatenation of the name of the conditional application frame and the string "-start".
In these cases the second argument for DEFINE-CONDITIONAL-COMMAND and DEFINE-CONDITIONAL-APPLICATION-FRAME might be the empty list. (Note: You still have to use DEFINE-CONDITIONAL-COMMAND and DEFINE-CONDITIONAL-APPLICATION-FRAME and not CLIM:DEFINE-COMMAND and DEFINE-APPLICATION-FRAME.)

(Be sure to have a look at the contents of the file conditional-commands-example.lisp for the full code of the example.)


I've just added the extension to the McCLIM CVS repository. (You can browse the code online via the CVSWeb interface.)

Trackback pings for this entry are listed below. The URL to ping for this entry is: http://blog.matroid.org/trackback/18

Select a Theme:

Basilique du Sacré-Cœur de Montmartre (Paris) Parc Floral de Paris Castillo de Santa Barbara (Alicante) About the photos

Entries: