| Allegro CL version 10.0 Moderately revised from 9.0. 9.0 version |
This document contains the following sections:
1.0 Introduction to pixmapsA pixmap stores and displays a graphical image as a rectangular array of pixel color values. (The term "pixmap" is short for "pixel map".) A pixmap that uses only a single bit to denote the color of each pixel (resulting in a monochrome image) is often referred to as a bitmap. Bitmap is also sometimes used to refer to any pixmap.
While the term "pixmap" is often used in a general way to describe the actual array of pixels or the image that they create, Common Graphics now uses the term to describe a class of objects that are used to manage pixmap images.
Applications may use Common Graphics pixmap objects (referred
to as pixmaps) to manage their images. A pixmap can be created either
by loading it from a pixmap file with load-pixmap, or by defining it
programmatically with a make-instance form. Once defined, a pixmap can
then be used either directly by copying it to a window or printer
stream with copy-to-stream, or indirectly by
associating it with a static-picture
, picture-button
, or
multi-picture-button
control. (Note
that while a bitmap-pane
is sometimes said to
have a backing-store pixmap or bitmap, this is actually an internal
object and not a pixmap.)
This document describes much of the programmatic interface to pixmaps
rather briefly in terms of properties. When we mention, for example,
that a pixmap has a "name property", this generally implies
that the name can
be specified when creating a pixmap by passing a
:name
initarg to make-instance, that the name can be read later
by calling name
on the pixmap, and that the name can be modified later with setf and name.
The names of the initarg and accessor symbols will always be the same as the property name (rare exceptions occur and will be noted). Some properties are defined as read-only, and so the setf will not be defined. When editing properties in the inspector, the property definition also tells the inspector what sort of extended editing to use when the button on the right side of the property row is clicked, and what sort of replacement values will be allowed. Properties also know how to enact needed side effects when modified.
Pixmaps have the following properties. While pixmap properties can be modified at any time, they typically are specified at creation time since the various properties must be mutually compatible, and a pixmap is typically a static object. (To use a different image, it's best to create a separate pixmap.)
bits-per-pixel | Specifies the number of bits that are
used to denote each pixel value. Must be either 1, 4, 8, 16, or
24. Must be large enough for the largest pixel value used by the
pixmap.
|
colors | A vector of RGB color structures that determines the color that will be used for each pixel value. Pixels with the value 0 will use the first color in the color vector, and in general pixels with the value N will use the (N+1)th member of the color vector. The colors vector should contain at least (one more than) as many members as the largest pixel value in the contents list. |
contents | A list of lists containing the individual pixel values of the pixmap. Each inner list contains the pixels for one row of the pixmap from left to right, and the outer list contains the rows from top to bottom. When pretty-printed, the contents list is oriented as the image will appear, giving a rough idea of what the real thing will look like. |
mask-contents | An optional property to define part of
the pixmap as transparent. If supplied, it is a list of lists
that corresponds to the contents list. Each member of the inner
lists is either a 1 to indicate that the pixel at that location
should be transparent, or a 0 to indicate that the pixel should
be the color in the corresponding contents list (or in the texture,
if a texture is supplied rather than a contents list).
When a mask is used, the main contents list (or texture) should have a zero for each transparent pixel. Therefore, the first entry in the colors vector of a pixmap that uses a mask will normally be a dummy color that never appears in the image, since index zero is reserved for transparent pixels. Also note that if a pixmap uses a mask then it should not also use a pixmap-handle, because the "device-dependent bitmap" that the handle points to will not incorporate the mask. This restriction may be removed in the future. An alternative to specifying the individual pixels for a mask is to call generate-mask, which will automatically create a mask that is transparent wherever a particular pixel value occurs. |
height | The height in pixels of the pixmap's texture. Normally this need not be specified, as it is computed automatically from the contents property. |
invert-p |
A flag indicating whether the rows of
the contents list are specified from top to bottom or from bottom to
top.
Note, though, that the operating system specifies pixmaps from bottom
to top, so when invert-p is non- |
name | An arbitrary symbol used for finding the
pixmap programmatically. A pixmap may be associated with a control by
specifying its name as the pixmap-name property of the
control (assuming that the pixmap has been cached).
See Also Section 6.0 Cached pixmaps below. |
palette-size | This property is no longer supported. Please use the bits-per-pixel option instead (the first entry above). |
pixmap-handle |
The handle to an optional more efficient version of the pixmap which
is managed inside the operating system. This property should not be
set directly by an application, but instead is set indirectly by
calling open-pixmap-handle on the pixmap to
create the handle. The handle can be destroyed later by calling
close-pixmap-handle on the pixmap.
This property is optional because there is a trade-off to using a pixmap handle. While they draw faster, they essentially double the amount of memory required for the pixmap since the operating system is making its own copy of the pixels that are defined in Lisp for the pixmap. It is a good idea to close pixmap handles that are no longer being used by calling close-pixmap-handle on the pixmaps that had used them.
Sometimes Common Graphics automatically opens a pixmap handle for a
pixmap, in particular if it is used by a control (since controls tend
to be small enough that we can assume that the extra space is not very
significant). A |
source |
If this pixmap was created by calling load-pixmap on a
pixmap file, then the path namestring will be preserved
as the value of the source property. If the pixmap was defined
programmatically instead, then the source property will be nil .
|
texture | A texture object that describes each pixel in the pixmap. Typically the pixels are specified with the contents property, but alternatively a texture object may first be created and then specified here. This is most useful for backward compatibility with the older texture interface, where textures and texture-infos are used individually. |
mask | An optional second texture object that describes whether or not the pixmap is transparent at each pixel. Typically the mask pixels are specified with the mask-contents property, but alternately a texture object may first be created and then specified here. If supplied, the mask texture's bits-per-pixel must be 1, and the texture should have a 1 for each transparent pixel and a 0 for each non-transparent pixel. |
texture-info |
A structure that internally contains the colors, bits-per-pixel, width, and height properties of the
pixmap.
Provided as a property that is redundant with these other properties, primarily for backward compatibility with the older texture interface in applications that have created texture-info structures, so that these structures can be specified directly as the texture-info property of a pixmap as an alternative to specifying the other properties separately. |
width | The width in pixels of the texture-info's texture. Normally this need not be specified, as it is computed automatically from the contents property. |
An example of a programmatically created pixmap:
(make-instance 'pixmap :name :find-debug-prompt :bits-per-pixel 4 :colors (vector black dark-red dark-green dark-yellow dark-blue dark-magenta dark-cyan light-gray gray red green yellow blue magenta cyan white) :contents '((7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7) (7 0 0 7 7 7 7 7 7 7 7 7 7 7 7 7) (7 0 0 0 7 7 7 7 7 7 7 7 7 7 7 7) (7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 7) (7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7) (7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7) (7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7) (7 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7) (7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7) (7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7) (7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7) (7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 7) (7 0 0 0 7 7 7 7 7 0 0 0 0 0 7 7) (7 0 0 7 7 7 7 7 7 0 0 0 0 0 7 7) (7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7) (7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7)))
In the above example, each "7" pixel will be drawn in light-gray because light-gray is at position 7 in the color vector of the pixmap.
While the example color vector above uses the built-in constants for the system colors, the general format using arbitrary colors is:
:colors (vector (make-rgb :red 200 :green 200) (make-rbg :red 200 :green 100 :blue 200) ...)
As a side note, if a pixmap uses the exact color vector shown in this
example, then it could instead specify
(default-pixmap-color-vector)
(see default-pixmap-color-vector) as its
colors property,
since it returns a vector with these particular colors. This saves
space by reusing the same vector. The IDE uses the default-pixmap-color-vector for
many of its picture buttons.
There is also (default-gray-pixmap-color-vector)
(see default-gray-pixmap-color-vector)
which is just like the default-pixmap-color-vector except
that black (at position 0) has been replaced by the value of system-edge-shadow-color. Replacing
a pixmap's color with this color vector can make it appear to be
dimmed. If your application uses multiple pixmaps that can share the
same color vector, then consider storing such color vectors globally
and reusing them to save space.
You may also want to use the default-pixmap-color-vector for the following reason. When the IDE or a standalone application starts up, a few of the colors in the default-pixmap-color-vector and the default-gray-pixmap-color-vector are modified.
These special functions return the colors that the end user has set up in the Windows Control Panel. If you use the default-pixmap-color-vector for your application's buttons, then the buttons will adapt at runtime to match the end user's color preferences. You can demonstrate this by choosing a new color scheme in Control Panel and then switching back to the Allegro IDE. Using the default-pixmap-color-vector will cause your own application to adapt in the same way.
A texture specifies the rectangular array of pixel values that are used by a pixmap, without the additional information such as colors that are included in a pixmap (or texture-info) object. While a pixmap internally includes a texture, using a pixmap does not require dealing with the texture object directly at all, since the information contained in the texture is available directly from the pixmap by using its contents, bits-per-pixel, width, and height properties.
A texture shares some of the properties of a pixmap, and these properties are accessed in the same way. The shared properties are contents, bits-per-pixel, palette-size, width, and height. In addition, a texture has the following unique properties:
texture-array | An internal two-dimensional array that implements the texture. The texture-array can be passed to Windows functions, like StretchDIBits, if direct WinAPI calls are made. Usually, the texture-array is not specified when making an instance; instead, the contents property is specified and the texture-array is created from the contents. |
texture-array-height | The height of the internal texture array. |
texture-array-width | The width of the internal texture array. This may be larger than the logical width of the texture (accessed with the width property) due to an internal need to pad the array rows to 32-bit boundaries (which is done automatically). |
Here is how to create the texture used by the earlier pixmap example. This texture would be created automatically by that example, but an application can alternately create a texture in this way and then pass it to a pixmap.
(make-instance 'texture :bits-per-pixel 4 :contents '((7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7) (7 0 0 7 7 7 7 7 7 7 7 7 7 7 7 7) (7 0 0 0 7 7 7 7 7 7 7 7 7 7 7 7) (7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 7) (7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7) (7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7) (7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7) (7 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7) (7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7) (7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7) (7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7) (7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 7) (7 0 0 0 7 7 7 7 7 0 0 0 0 0 7 7) (7 0 0 7 7 7 7 7 7 0 0 0 0 0 7 7) (7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7) (7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7)))
A texture-info is a structure that is retained mostly for backward compatibility with the older but still supported texture interface. It internally holds the colors, width, height, and bits-per-pixel property values of a pixmap. When using a pixmap object, you do not need to know about the texture-info used by the pixmap because each of the values held in the texture-info are immediately accessible from the pixmap by using the accessor functions.
Note: In order to access these values from a texture-info itself, the older accessor functions texture-info-colors, texture-info-width, texture-info-height, and texture-info-bits-per-pixel must be used instead.
A texture-info may be created by calling make-texture-info and then passed as the :texture-info initarg when creating a pixmap, as an alternative to passing separate initargs for the four corresponding properties when creating the pixmap.
A cached pixmap is simply a pixmap on which the function cache-pixmap has been called, and which therefore is a member of an internal global list of pixmaps.
An application may choose to cache a pixmap so that it can later look up the pixmap from its name, rather than keeping the pixmap itself around in a variable somewhere.
An IDE user may want to cache a pixmap so that it will appear in the
list of available pixmaps that drops down when using the inspector to
modify the pixmap-name property of a static-picture
, picture-button
, or
multi-picture-button
control.
A list of all cached pixmaps (with tiny representations of their images) can be viewed by evaluating the following form (in an editor or in the Debug window):
(inspect cg.pixmap:*cached-pixmaps*)
The following functions are useful when using cached pixmaps:
nil
if no such pixmap is
found. The name argument may be the actual name property of the pixmap (an
arbitrary symbol) or the source property (a path namestring
of the pixmap file from which the pixmap was originally
loaded).
Pixmap names should be mutually unique to ensure finding the desired one.
A control that can display a pixmap has several properties that
provide alternate ways of specifying the pixmap that it will
display. These properties exist on a static-picture
, or picture-button
control, or on a button-info
object (which specifies
a single button of a multi-picture-button
control). If
you are editing one of these objects in the inspector and change one
of these properties, the other properties in this set will update
themselves to match.
The properties are:
nil
if the pixmap was
created programmatically rather than being loaded from a
pixmap file.
As long as the pixmap is not replaced again, the path namestring will remain as the pixmap-source property of the control even though the original pixmap file may no longer exist. This is not a problem, because the pixmap is loaded only a single time and (when building a form) the pixmap definition is thereafter stored in the .bml file associated with the dialog that the control is on.
If the original pixmap file has changed and you need to update all pixmaps that were loaded from that file, update-widgets-of-image-file can be called. Or use the "Sync to Pixmap File" item on the right-button shortcut menu of a pixmap control on a form.
error-icon
, it is up to the
application at runtime to load or create the icon and then assign it
the control.
Note that setting a control's pixmap-icon will remove its pixmap, and vice versa.
The outline
and outline-item
controls also use
pixmaps as the other controls mentioned above do, but instead of
having a single pixmap property, there are separate properties for the
leaf, opened, and closed pixmaps. An icon cannot be used instead of a
pixmap, and there is no pixmap-use-handle property since
pixmap handles are always used for outlines. Typically these
properties are specified for the outline as a whole rather than for
each outline-item, but the latter is provided if needed. The pixmap
properties of an outline or outline-item are:
These behave similarly to the corresponding control properties documented in Section 6.0 Cached pixmaps.
There are serveral functions for creating and deleting pixmap handles. ("Creating a pixmap handle" is a lazy way of saying "telling the operating system to create an optimized internal version of the pixmap and returning a handle to this internal pixmap to Common Graphics".) This section describes the differences between them.
When working with textures and texture-infos, the pixmap handle must be created and managed as a separate object. create-pixmap-handle creates and returns a pixmap handle, and destroy-pixmap-handle will destroy it later to free up operating system resources. (If destroy-pixmap-handle is not called explicitly, the handle will be destroyed automatically when Lisp or a standalone application exits.)
When working with pixmaps, open-pixmap-handle will create a handle and store it on the pixmap, while close-pixmap-handle will remove the handle from the pixmap and destroy it. These functions may also be called on a control that uses a pixmap in order to address its pixmap indirectly.
When working with controls that use pixmaps (such as static-picture
s, or
picture-button
s control, or button-info
s, which
specifies a single button of a multi-picture-button
control),
calling (setf pixmap-use-handle) on the
control will establish whether its pixmap uses a handle.
Since loading pixmaps from pixmap files is pretty fast, an application can simply include any needed pixmap files with it and load them at runtime. But if you would rather embed the pixmap data in your Lisp code to avoid distributing the pixmap files, then you can convert the pixmap data into Lisp source code.
The simplest way is to call the function import-pixmaps. It loads an entire set of pixmap files and creates a new source code file that you can incorporate directly into your application code to create the pixmaps.
An older alternative is to call save-lisp-pixmap on a pixmap that has been loaded from a pixmap file with load-pixmap, which will create a new Lisp source code file with the programmatic definition of the pixmap in it. load-lisp-pixmap will then load this file and return the saved pixmap. The saved file may optionally be compiled in the meantime, and then load-lisp-pixmap called on the compiled file.
load-lisp-pixmap cannot be used at runtime, though, if the individual source code or fasl files have been replaced by an image file for distribution. In order to use save-lisp-pixmap for a generated application without distributing the pixmap source or fasl files, you would need to either edit the source code file that save-lisp-pixmap creates to force it to store the returned pixmap in some accessible location, or else make your application code call find-pixmap on the name of the pixmap that was saved. (The generated code does call cache-pixmap on the created pixmap.)
An alternative to using save-lisp-pixmap at all is to
evaluate a form like (pprint (recreation-code
my-pixmap))
in the debug window, and then to simply cut and
paste the printed source code into your application. (See recreation-code.)
This allows placing multiple pixmaps into a single Lisp source file. Or inspect a pixmap object, go to the internals tab, and click on the button at the right side of the top line to invoke the "extended editor" for the pixmap. The modal editor window that pops up will contain the recreation code for the pixmap, which you could copy and paste into your application. (Though the editor is read-only, you can still copy the text from it.)
The generic function pixmap returns a pixmap to be
associated with certain classes of objects. Normally this is a
4-bits-per-pixel 16 by 16 pixmap. The inspector will display a pixmap
in its history list for any object for which a pixmap method returns a pixmap. For
example, adding the following method would cause all conses that
appear in the inspector's history list to be represented by the
:macroexpand
pixmap (which looks like
(<->)
).
(defmethod pixmap ((object cons)) (find-pixmap :macroexpand))
Evaluate that form in the Debug window and then evaluate
(inspect (cons 1 2))
and you will see the pixmap in
the drop-down list in the Inspect dialog.
Evaluating
(defmethod pixmap ((object cons)) nil)
will undo the associated between conses and the icon.
Mouse cursors are now standard-objects with some of the same properties as pixmaps. The object is called a cursor and has the properties name, texture, mask, cursor-handle, and click-position (which is a position indicating the point within the cursor's image, relative to its upper left corner, that is considered to be the exact location pointed to by the cursor).
The properties texture-info, width, and height from pixmaps are not needed for mouse cursors since all cursors are the same size and depth. (The depth is always 1-bit-per-pixel, and the standard mouse cursor size is returned by the functions cg::mouse-cursor-width and cg::mouse-cursor-height.)
The function cursor and its setf get and set the mouse cursor of a window; the new cursor can be either a cursor object or a cursor handle. There is a cursor property on every window for its current cursor. Like pixmaps, cursors can be cached, using the function cache-cursor, retrieved with find-cursor, and uncached with uncache-cursor.
A cursor object will create its handle as needed when the cursor is assigned to a window.
Below is the IDE's definition of the "hand" mouse cursor. After defining a cursor in this way, you can immediately tell a window to use it with a form like
(setf (cursor my-window) (find-cursor :hand-cursor))
Note that black pixels require a "zero" in both the main texture and the mask texture, white pixels require a "one" in the main texture and a "zero" in the mask texture, and transparent pixels require a "zero" in the main texture and a "one" in the mask texture.
(cache-cursor (make-instance 'cursor :name :hand-cursor :click-position (make-position 13 4) :texture (make-instance 'texture :bits-per-pixel 1 :contents '( #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000011000000000000000000 #*00000000000011000000000000000000 #*00000000000011000000000000000000 #*00000000000011000000000000000000 #*00000000000011000000000000000000 #*00000000000011011000000000000000 #*00000000000011011011000000000000 #*00000000000011011011010000000000 #*00000000000011011011011000000000 #*00000000110011111111011000000000 #*00000000111011111111111000000000 #*00000000011011111111111000000000 #*00000000001011111111111000000000 #*00000000001111111111111000000000 #*00000000000111111111111000000000 #*00000000000111111111110000000000 #*00000000000011111111110000000000 #*00000000000011111111110000000000 #*00000000000001111111100000000000 #*00000000000001111111100000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 #*00000000000000000000000000000000 )) :mask (make-instance 'texture :bits-per-pixel 1 :contents '( #*11111111111111111111111111111111 #*11111111111111111111111111111111 #*11111111111111111111111111111111 #*11111111111111111111111111111111 #*11111111111100111111111111111111 #*11111111111000011111111111111111 #*11111111111000011111111111111111 #*11111111111000011111111111111111 #*11111111111000011111111111111111 #*11111111111000000011111111111111 #*11111111111000000000111111111111 #*11111111111000000000001111111111 #*11111111111000000000000111111111 #*11111110001000000000000011111111 #*11111110000000000000000011111111 #*11111110000000000000000011111111 #*11111111000000000000000011111111 #*11111111100000000000000011111111 #*11111111100000000000000011111111 #*11111111110000000000000011111111 #*11111111110000000000000111111111 #*11111111111000000000000111111111 #*11111111111000000000000111111111 #*11111111111100000000001111111111 #*11111111111100000000001111111111 #*11111111111100000000001111111111 #*11111111111111111111111111111111 #*11111111111111111111111111111111 #*11111111111111111111111111111111 #*11111111111111111111111111111111 #*11111111111111111111111111111111 #*11111111111111111111111111111111 ))))
In addition to the ability to define custom mouse cursors as above, a number of built-in mouse cursors are supplied. There are two groups of these.
The first is a set supplied by the operating system, and are the values of the following variables:
arrow-cursor
cross-cursor
line-cursor
waiting-cursor
vertical-arrow-cursor
app-starting-cursor
help-cursor
no-drop-cursor
sizing-cursor
sizing-north-south-cursor
sizing-west-east-cursor
sizing-northeast-southwest-cursor
sizing-northwest-southeast-cursor
The value of each of these variables is actually a cursor-handle integer rather than a cursor object, but it may be used in the same way that a cursor object is used. These cursors are standard in the Windows operating system, and if the user is using a custom Windows desktop scheme, then these built-in cursor handles will invoke the corresponding mouse cursors of that scheme.
The second set of built-in cursors is supplied by Common Graphics. These cursor objects must be retrieved by calling find-cursor on one of the following keyword symbols, which are the names of the cursors:
:hand-cursor
--- a human hand with pointing index
finger (often used by web browsers). On GTK, there is an OS hand
cursor, so there is a vaiable hand-cursor
whose value on GTK is the handle of
that cursor. On Windows, the value of that variable is nil
. (find-cursor :hand-cursor)
will always return the right thing on any platform.
:default-drop-cursor
--- a large hollow arrow
pointing downward (used by the CG drag-and-drop facility)
:horizontal-splitbar-cursor
--- used by particular
IDE dialogs that implement child pane split bars (and could be used by
applications that implement similar features)
:vertical-splitbar-cursor
--- similar to
:horizontal-splitbar-cursor
, but in the other
orientation
Copyright (c) 1998-2019, Franz Inc. Oakland, CA., USA. All rights reserved.
This page has had moderate revisions compared to the 9.0 page.
Created 2019.8.20.
| Allegro CL version 10.0 Moderately revised from 9.0. 9.0 version |