INTERNAL/REVIEW: Defining a custom cursor in IDL
Anonym
[Needs to be reviewed for Compliance and IP issues (i.e. .pro file included)]
Topic:
This tech tip provides a handy program for setting the IDL cursor.Discussion:
The following keywords to DEVICE are used to create a custom cursor:
CURSOR_IMAGE
Specifies the cursor pattern. The value of this keyword must be a 16-line by 16-column bitmap, contained in a 16-element short integer vector. The offset from the upper left pixel to the point that is considered the hot spot can be provided via the CURSOR_XY keyword.
CURSOR_MASK
When the CURSOR_IMAGE keyword is used to specify a cursor bitmap, the CURSOR_MASK keyword can be used to simultaneously specify the mask that should be used. In the mask, bits that are set indicate bits in the CURSOR_IMAGE that should be seen and bits that are not set are masked out.
By default, the CURSOR_IMAGE bitmap is used for both the image and the mask. This can cause the cursor to be invisible on a black background (because only black pixels are allowed to be displayed).
CURSOR_XY
A two element integer vector giving the (X, Y) pixel offset of the cursor hot spot, the point which is considered to be the mouse position, from the lower left corner of the cursor image. This parameter is only applicable if CURSOR_IMAGE is provided. The cursor image is displayed top-down—the first row is displayed at the top.
The following program (
define_cursor.pro) can be used to set the IDL cursor using a 16x16 integer array. For instance, the following will define the cursor as a spiral:
bitMap = [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], $
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], $
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1], $
[1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1], $
[1,0,1,0,1,1,1,1,1,1,1,1,0,1,0,1], $
[1,0,1,0,1,0,0,0,0,0,0,1,0,1,0,1], $
[1,0,1,0,1,0,1,1,1,1,0,1,0,1,0,1], $
[1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1], $
[1,0,1,0,1,0,1,0,0,0,0,1,0,1,0,1], $
[1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1], $
[1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1], $
[1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1], $
[1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1], $
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1], $
[1,0,0,0,0,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]]
WINDOW, /FREE, XSIZE = 500, YSIZE = 500
TVSCL, DIST(500)
DEFINE_CURSOR, bitMap
Solution:
;--------------------------------------------------
; MAKE_CURSOR_ARRAY
;+
;
; This routine converts a 16X16 array into a 16-element
; array to be used by the CURSOR_IMAGE and CURSOR_MASK
; keywords to DEVICE. The Ith integer in the resulting
; array will be the unique integer with all whose bitmask
; is all of the non-zero elements of the Ith row of CDATA.
;
; SYNTAX:
; result = MAKE_CURSOR_ARRAY, cData, [/MASK]
;
; ARGUMENTS
; CDATA : A 16x16 integer array defining the cursor. The
; resulting cursor array will have all non-zero
; values white and zeros black.
;
; KEYWORDS
; MASK : Set this keyword to have a mask array returned.
; In this case, CDATA will be used as the mask
; array. All non-zero values will be visible and
; all zero values will be transparent.
;
;-
FUNCTION make_cursor_array, cData, $
MASK = mask
IF ~ARRAY_EQUAL(SIZE(cData, /DIM),[16,16]) THEN $
RETURN, -1
outArr = INTARR(16)
mArr = KEYWORD_SET(mask) ? cData NE 0 : cData EQ 0
FOR i = 0, 15 DO $
outArr[i] = TOTAL(2L^WHERE(mArr[*,i]))
RETURN, SWAP_ENDIAN(outArr)
END
;--------------------------------------------------
; DEFINE_CURSOR
;+
;
; This routine will define the cursor used by IDL
;
; SYNTAX:
; DEFINE_CURSOR [,bitMap] [,CENTER = vector]
; [,CURSOR_MASK = array]
;
; ARGUMENTS:
; BITMAP : A 16x16 integer array defining the cursor. The
; resulting cursor will have all non-zero values
; white and zeros black. The default bitmap will
; result in "X"
;
; KEYWORDS:
; CENTER : A two element integer vector giving the
; (X,Y) pixel offset of the cursor hot spot,
; the point which is considered to be the
; mouse position, from the lower left corner
; of the cursor image. The default value is
; [8,8]
; CURSOR_MASK : A 16x16 integer array defining the mask
; that should be used. All non-zero values
; will be visible and all zeros will be
; transparent. The default mask will
; show all non-zero values in BITMAP and
; make all zeros transparent.
;-
PRO define_cursor, bitMap, $
CENTER = center, $
CURSOR_MASK = maskBitMap
IF ARRAY_EQUAL(SIZE(bitMap, /DIM), [16,16]) THEN BEGIN
bitMap = BYTE(bitMap GT 0)
ENDIF ELSE $ ; Default bitmap
bitMap = BYTE([[1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1], $
[1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1], $
[0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0], $
[0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0], $
[0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0], $
[0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,0], $
[0,0,0,0,0,1,1,1,1,1,1,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,1,1,1,1,1,1,0,0,0,0,0], $
[0,0,0,0,1,1,1,0,1,1,1,1,0,0,0,0], $
[0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0], $
[0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0], $
[0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0], $
[1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1], $
[1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1]])
cArray = MAKE_CURSOR_ARRAY(bitMap)
maskBitMap = BYTE(ARRAY_EQUAL(SIZE(maskBitMap,/DIM),[16,16]) ? $
(maskBitMap GT 0) : bitMap)
cMask = MAKE_CURSOR_ARRAY(maskBitMap, /MASK)
center = N_ELEMENTS(center) EQ 2 ? center : [8,8]
DEVICE, CURSOR_IMAGE = cArray, $
CURSOR_MASK = cMask, $
CURSOR_XY = center
END