ToC DocOverview CGDoc RelNotes FAQ Index PermutedIndex
Allegro CL version 11.0

About icons in Common Graphics


1.0 When to use icons

Icons are like small pixmaps that have a mask, don't stretch, and come in two standard sizes. Common Graphics applications usually use pixmaps whenever they need to draw pixelated images, but there are a couple of special places where icons must be used instead. These places include the image that appears on the left end of a window's title-bar, and the image that is used to represent an application in the Windows taskbar, alt-tab window, and file explorer.

These special icon requirements stem directly from the Windows operating system, and so icons are one Common Graphics facility whose API is likely to differ in future ports of Common Graphics to non-Windows platforms.

Note that some Common Graphics function names contain the word "icon" but are not related to Common Graphics icons. These include the function standard-toolbar-icons, the list-view function icon-index and the outline function draw-icons. "Icon" is used in a more generic way in these cases to refer to a small image. The functions discussed here refer instead to Common Graphics icon objects.


2.0 Using a built-in icon

Common Graphics includes several constants whose values are standard icons supplied by the operating system. These icons may be used directly instead of creating custom icons. The constants are error-icon, warning-icon, question-icon, information-icon, and application-icon.

Notice that the values of these constants are simply integers. Common Graphics does not supply an icon class or special Lisp objects for icons; instead they are simply handles that the operating system uses to look up the desired icon.


3.0 Assigning an icon to a window title-bar

Once you have an icon to use, you can add it to a window title-bar by calling (setf icon) on the window. This icon will override the default icon for the whole application (see below).

Example: This expression changes the icon in the inspector's title-bar to a question mark.

(setf (icon (find-window :inspector)) question-icon)

Setting the [icon)(cg-ops.html#icon) property to nil will revert to the default icon of the application. In the IDE this is the Franz bust icon.

(setf (icon (find-window :inspector)) nil)

4.0 Assigning an icon to a control

You can similarly assign an icon to a control, if the control is one that displays a pixelated image, by calling (setf pixmap-icon). Icons may be used with the static-picture, picture-button, and multi-picture-button controls. For the multi-picture-button control, (setf pixmap-icon) should be called on the individual button-info instances in the control's range, rather than on the control itself. (list-views and outlines can display pixmaps but not icons.)

There is generally no need to use icons on controls, since pixmaps can be used instead, but the option is available, and icons may draw slightly faster than pixmaps with masks. (If the image lives in an icon file, load-pixmap may still be used to create a pixmap for it, so a pixmap may be used in Common Graphics even for an image that was designed as an icon.)

Example: The following form will display the question icon on the button control near the top left of the inspector.

(setf (pixmap-icon (find-component
                    :back (frame-child (find-window :inspector))))
  question-icon)

Notice that the image is larger than it was for the same icon in the window title-bar (and in fact does not fit within the button). The reason is that icons are usually defined at two standard sizes, 16 by 16 pixels and 32 by 32 pixels, which are both referenced by the single icon handle. When assigning a window title-bar icon, the operating system always draws the small version in the title-bar, and the large version in the alt-tab window (for non-owned top-level windows). Common Graphics always draws the large version on a control.


5.0 Creating an icon

By this point you may have begun to tire of the built-in question mark icon, delightful though it is. Luckily, the rest of this document covers custom icons. There are two ways to create a Common Graphics icon: to load it from a file that defines icons, or to create it from a Common Graphics pixmap.

The typical way to create an icon is to call the function extract-icon-from-file, which loads a pre-made icon from a file. The file may be either a .ico file, which is a type of Windows file intended specifically for holding an icon, or a .dll file, which can contain a whole library of icons, or a .exe file. A distributed application that uses extract-icon-from-file must include the files from which it loads icons and load them at run time, since there is no way to embed these icons in the application's image file or executable file (other than the single icon for the application itself, as described later). Allegro CL does not provide any tools for creating icon files, though there are third-party tools for doing just that.

Example: This expression loads the eighth icon from the file moricons.dll in the Windows system directory (assuming that this file exists), and displays it in the title-bar of the inspector.

(setf (icon (find-window :inspector))
  (extract-icon-from-file
    (merge-pathnames "moricons.dll" (windows-directory t))
    8))

The function count-icons-in-file returns the number of icons in a specified file, so that you can know what indices make sense to pass to extract-icon-from-file.

The other way to create an icon is to create it from a Common Graphics pixmap by calling create-icon-handle. This technique is useful if the icon does not live in a .ico, .dll, or .exe file, since extract-icon-from-file is not applicable. It is also useful if it is desirable to not distribute .ico files with an application; in that case, a pixmap could be created in Lisp (see cg-pixmaps.html), and then an icon made from the pixmap.

create-icon-handle creates an icon with a single image, rather than the separate large and small images that are usually defined in .ico, .dll, and .exe files. If you intend to use the icon in window title-bars, the size should be 16 by 16 pixels.

Example: The following code defines the function open-folder-icon to return an icon with an image of an open file folder. It caches the icon so that this function may be called whenever the icon is needed, without recreating it each time.

Note that it would be a bad idea to instead write a defparameter or defvar form whose initial value is the icon returned by a call to create-icon-handle. The reason is that an icon handle will no longer be valid if used in a different Lisp session than where create-icon-handle was called, and this would happen after generating a standalone application due to the defparameter initform being evaluated when generating the application image rather than when running it. (A pixmap, on the other hand, would work fine if created in a defparameter initform.)

(let ((open-folder-icon nil))
  (defun open-folder-icon ()
    (or open-folder-icon
        (setq open-folder-icon
              (create-icon-handle
               (make-instance 'pixmap
                 :name :default-opened-with-mask
                 :contents
                 '(( 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0)
                   ( 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0)
                   ( 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0)
                   ( 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0)
                   ( 0  0 11 11 11 11 11  0  0  0  0  0  0  0  0  0)
                   ( 0 11 11 11 11 11 11 11  0  0  0  0  0  0  0  0)
                   ( 0 11 11 11 11 11 11 11 11 11 11  0  0  0  0  0)
                   ( 0 11 11 11 11 11 11 11 11 11 11  0  0  0  0  0)
                   ( 0 11 11 11 11  0  0  0  0  0  0  0  0  0  0  0)
                   ( 0 11 11 11  0  3  3  3  3  3  3  3  3  3  0  0)
                   ( 0 11 11  0  3  3  3  3  3  3  3  3  3  0  0  0)
                   ( 0 11  0  3  3  3  3  3  3  3  3  3  0  0  0  0)
                   ( 0  0  3  3  3  3  3  3  3  3  3  0  0  0  0  0)
                   ( 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0)
                   ( 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0)
                   ( 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0))
                 :mask-contents
                 '((1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
                   (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
                   (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
                   (1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1)
                   (1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1)
                   (0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1)
                   (0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1)
                   (0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1)
                   (0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1)
                   (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1)
                   (0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1)
                   (0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1)
                   (0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1)
                   (0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1)
                   (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
                   (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1))))))))

It is, of course, tedious to define a pixmap as a Lisp expression as above. Such expressions can be obtained, however, by evaluating a form such as (pprint (recreation-code my-pixmap)) and then pasting the output into your source code (see recreation-code). The pixmap may originally have lived in a .bmp or .ico file and loaded with load-pixmap, but this technique allows you to thereafter define the image completely within Lisp and avoid distributing the original .bmp or .ico file with your application.

The following expression displays our made-in-Lisp icon in the inspector's title-bar:

(setf (icon (find-window :inspector))(open-folder-icon))

6.0 Drawing an icon

The function draw-icon will draw an icon at an arbitrary position in any window. As with assigning an icon to a control, this is generally not needed since a pixmap that has a mask could be drawn instead with copy-to-stream (except for the five built-in icons). Icons may draw a bit faster than pixmaps with masks. draw-icon always draws the larger size of an icon that defines both icon sizes.

Example: The following expression draws the question mark icon on a window.

(let* ((window (make-window :what? :class 'bitmap-window
                 :background-color cyan
                 :exterior (make-box 200 200 330 300))))
  (with-positions (pos1)
  (draw-icon (frame-child window)
    question-icon (nmake-position pos1 30 20))))

7.0 Assigning an icon to an application

If you are using the IDE's project system to create an application, you can use an icon to represent the entire application by calling (setf icon-file) on the project. You can do this interactively by entering the name of a .ico file on the Build tab of the Project Manager dialog. (Click on the Icon File check box to show the file dialog for selecting an icon file.) When you later use File | Build Project Distribution to generate a standalone application and then run it, the windows of that application will show the small version of the icon in their title-bars, except where the application may have called (setf icon) on particular windows to override this default icon. Moreover, the Windows taskbar and the alt-tab window will show the custom icon instead of the Franz bust icon, and the Windows file explorer will show the icon for certain generated files. This particular facility requires a .ico icon file rather than a Common Graphics icon. There is no way to save a Common Graphics icon (that may have been created in Lisp) as a .ico icon file. This particular icon is embedded in the generated executable file that is to be distributed, so there is no need to distribute the original icon file with the application.


Copyright (c) Franz Inc. Lafayette, CA., USA. All rights reserved.

ToC DocOverview CGDoc RelNotes FAQ Index PermutedIndex
Allegro CL version 11.0