Cursor.st
author claus
Fri, 12 Aug 1994 01:40:40 +0200
changeset 56 cc69f5a6a51d
parent 54 29a6b2f8e042
child 71 6a42b2b115f8
permissions -rw-r--r--
thumbsUp/Down for compatibility

"
 COPYRIGHT (c) 1992 by Claus Gittinger
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

Object subclass:#Cursor
       instanceVariableNames:'shape sourceForm maskForm hotX hotY
                              device cursorId'
       classVariableNames:   'Lobby
                              DefaultFgColor DefaultBgColor

                              NormalCursor HandCursor ArrowCursor
                              ReadCursor WriteCursor WaitCursor
                              XeqCursor CrossHairCursor OriginCursor
                              CornerCursor SquareCursor FourWayCursor
                              UpDownArrowCursor LeftRightArrowCursor
                              Wait2Cursor Wait3Cursor Wait4Cursor
                              StopCursor'
       poolDictionaries:''
       category:'Graphics-Support'
!

Cursor comment:'
COPYRIGHT (c) 1992 by Claus Gittinger
             All Rights Reserved

$Header: /cvs/stx/stx/libview/Cursor.st,v 1.11 1994-08-11 23:40:40 claus Exp $
'!

!Cursor class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1992 by Claus Gittinger
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

version
"
$Header: /cvs/stx/stx/libview/Cursor.st,v 1.11 1994-08-11 23:40:40 claus Exp $
"
!

documentation
"
    I represents cursors in a device independent manner.

    Instance variables:

        shape           <Symbol>        a shape (i.e. #arrow, #hand, ...) or nil
        sourceForm      <Form>          if shape is nil, the source bits
        maskForm        <Form>          if shape is nil, the mask bits
        hotX            <SmallInteger>  if shape is nil, the hotSpot x of the cursor
        hotY            <SmallInteger>  if shape is nil, the hotSpot y of the cursor
        device          <aDevice>       the device, if associated to one
        cursorId        <anObject>      the device-specific id if device is nonNil

    class variables:

        Lobby           <Registry>      keeps track of known device cursors

        DefaultFgColor  <Color>         default foreground color for cursors (usually black)
        DefaultBgColor  <Color>         default background color for cursors (usually white)

        NormalCursor    <Cursor>        cached instance of normal (arrow) cursor
         ...

"
! !

!Cursor class methodsFor:'initialization'!

initialize
    Lobby isNil ifTrue:[
        Lobby := Registry new.

        "want to be informed when returning from snapshot"
        ObjectMemory addDependent:self
    ]
!

flushDeviceCursors
    "unassign all cursors from their device"

    Lobby contentsDo:[:aCursor |
        aCursor restored.
        Lobby changed:aCursor
    ]
!

update:something
    "sent when restarted after a snapIn"

    (something == #restarted) ifTrue:[
        self flushDeviceCursors
    ]
! !

!Cursor class methodsFor:'default access'!

defaultFgColor:fgColor defaultBgColor:bgColor
    "set the default colors used for cursors"

    DefaultFgColor := fgColor.
    DefaultBgColor := bgColor
! !

!Cursor class methodsFor:'instance creation'!

extent:extent fromArray:array offset:offset
    "create a new bitmap cursor from bits in the array argument
     - ST-80 compatibility"

    |sourceForm|

    sourceForm := Form extent:extent fromArray:array offset:offset.
    ^ self sourceForm:sourceForm maskForm:sourceForm hotSpot:(offset negated)
!

extent:extent sourceArray:sourceArray maskArray:maskArray offset:offset
    "create a new bitmap cursor with mask from bits in sourceArray and
     maskArray"

    |sourceForm maskForm|

    sourceForm := Form extent:extent fromArray:sourceArray offset:offset.
    maskForm := Form extent:extent fromArray:maskArray offset:offset.
    ^ self sourceForm:sourceForm maskForm:maskForm hotSpot:(offset negated)
!

sourceForm:aForm
    "return a new cursor.
     Source- and mask-Bits are taken from aForm; hotSpot is center"

    ^ self sourceForm:aForm
             maskForm:aForm
                 hotX:(aForm width // 2)
                 hotY:(aForm height // 2)
!

sourceForm:sourceForm maskForm:maskForm
    "return a new cursor. hotSpot is center"

    ^ self sourceForm:sourceForm
             maskForm:maskForm
                 hotX:(sourceForm width // 2)
                 hotY:(sourceForm height // 2)
!

sourceForm:sourceForm maskForm:maskForm hotSpot:aPoint
    "return a new cursor"

    ^ self sourceForm:sourceForm
             maskForm:maskForm
                 hotX:(aPoint x)
                 hotY:(aPoint y)
!

sourceForm:sourceForm maskForm:maskForm hotX:hotX hotY:hotY
    "return a new cursor"

    |newCursor|

    "first look if not already known"
    Lobby contentsDo:[:aCursor |
        (aCursor sourceForm == sourceForm) ifTrue:[
            (aCursor maskForm == maskForm) ifTrue:[
                (aCursor hotX == hotX) ifTrue:[
                    (aCursor hotY == hotY) ifTrue:[
                        ^ aCursor
                    ]
                ]
            ]
        ]
    ].
    (sourceForm isNil or:[maskForm isNil]) ifTrue:[^ nil].

    newCursor := self basicNew setSourceForm:sourceForm 
                                    maskForm:maskForm
                                        hotX:hotX
                                        hotY:hotY.
    Lobby register:newCursor.
    ^ newCursor
!

shape:aShape 
    "return one of the standard cursors.
     Each display may offer different shapes - see for example XWorkstation
     for details (however a basic minimum set should be supported by all)"

    |newCursor|

    "first look if not already known"
    Lobby contentsDo:[:aCursor |
        (aCursor shape == aShape) ifTrue:[
            ^ aCursor
        ]
    ].
    newCursor := self basicNew setShape:aShape.
    Lobby register:newCursor.
    ^ newCursor
!

fileCursorNamed:cursorName
    "return a cursor read from the files 'cursorName_bits.bit' and
     'cursorName_mask.bit' - return nil if file does not exist"

    |cursorBits maskBits|

    cursorBits := Form fromFile:(cursorName , '_bits.bit').
    cursorBits notNil ifTrue:[
        maskBits := Form fromFile:(cursorName , '_mask.bit').
        maskBits notNil ifTrue:[
            ^ self sourceForm:cursorBits maskForm:maskBits
        ]
    ].
    ^ nil
! !

!Cursor class methodsFor:'standard cursors'!

normal
    "return the normal cursor; an arrow.
     for ST-80 compatibility"

    NormalCursor isNil ifTrue:[
        NormalCursor := self arrow
    ].
    ^ NormalCursor
!

hand
    "return a hand cursor"

    HandCursor isNil ifTrue:[
        HandCursor := self shape:#upRightHand
    ].
    ^ HandCursor
!

upRightHand
    "return an up-right-hand cursor"

    ^ self shape:#upRightHand
!

leftHand
    "return a left-hand cursor"

    ^ self shape:#leftHand
!

upDownArrow
    "return an up-down-arrow cursor"

    UpDownArrowCursor isNil ifTrue:[
        UpDownArrowCursor := self shape:#upDownArrow
    ].
    ^ UpDownArrowCursor
!

leftRightArrow
    "return a left-right-arrow cursor"

    LeftRightArrowCursor isNil ifTrue:[
        LeftRightArrowCursor := self shape:#leftRightArrow
    ].
    ^ LeftRightArrowCursor
!

upLimitArrow
    "return an up-arrow-to-limit cursor"

    ^ self shape:#upLimitArrow
!

downLimitArrow
    "return a down-arrow-to-limit cursor"

    ^ self shape:#downLimitArrow
!

leftLimitArrow
    "return a left-arrow-to-limit cursor"

    ^ self shape:#leftLimitArrow
!

rightLimitArrowOn
    "return a right-arrow-to-limit cursor"

    ^ self shape:#rightLimitArrow
!

text
    "return a text-cursor"

    ^ self shape:#text
!

arrow
    "return an arrow (up-left-arrow) cursor"

    ^ self shape:#upLeftArrow
!

upLeftArrow
    "return an up-right-arrow cursor"

    ^ self shape:#upLeftArrow
!

upRightArrow
    "return an up-right-arrow cursor"

    ^ self shape:#upRightArrow
!

questionMark
    "return a question-mark cursor"

    ^ self shape:#questionMark
!

cross
    "return a cross cursor"

    ^ self shape:#cross
!

origin
    "return an origin cursor"

    OriginCursor isNil ifTrue:[
        OriginCursor := self shape:#origin
    ].
    ^ OriginCursor
!

corner 
    "return a corner cursor"

    CornerCursor isNil ifTrue:[
        CornerCursor := self shape:#corner 
    ].
    ^ CornerCursor
!

crossHair
    "return a crossHair cursor"

    CrossHairCursor isNil ifTrue:[
        CrossHairCursor := self shape:#crossHair
    ].
    ^ CrossHairCursor
!

fourWay 
    "return a four-way arrow cursor"

    FourWayCursor isNil ifTrue:[
        FourWayCursor := self shape:#fourWay 
    ].
    ^ FourWayCursor
!

stop
    "return a stop cursor"

    StopCursor isNil ifTrue:[
        StopCursor := (self
                        extent: 16@16
                        sourceArray: #(
                            2r0000011111000000
                            2r0001111111110000
                            2r0011111111111000
                            2r0111111111111100
                            2r0111111111111100
                            2r1111111111111110
                            2r1111111111111110
                            2r1100000000000110
                            2r1100000000000110
                            2r1111111111111110
                            2r1111111111111110
                            2r0111111111111100
                            2r0111111111111100
                            2r0011111111111000
                            2r0001111111110000
                            2r0000011111000000
                            )    
                        maskArray: #(
                            2r0000011111000000
                            2r0001111111110000
                            2r0011111111111000
                            2r0111111111111100
                            2r0111111111111100
                            2r1111111111111110
                            2r1111111111111110
                            2r1111111111111110
                            2r1111111111111110
                            2r1111111111111110
                            2r1111111111111110
                            2r0111111111111100
                            2r0111111111111100
                            2r0011111111111000
                            2r0001111111110000
                            2r0000011111000000
                           ) 
                        offset: -9 @ -9).
        StopCursor := StopCursor on:Display.
    ].
    ^ StopCursor
!

wait
    "return a wait cursor"

    WaitCursor isNil ifTrue:[
        WaitCursor := self shape:#wait
    ].
    ^ WaitCursor
!

wait2
    "return a wait cursor showing 3 o'clock"

    Wait2Cursor isNil ifTrue:[
        Wait2Cursor := (self
                        extent: 16@16
                        sourceArray: #(
                            2r0001111111100000
                            2r0001111111100000
                            2r0001111111100000
                            2r0011111111110000
                            2r0110000000011000
                            2r1100000000001100
                            2r1000000000000111
                            2r1000001110000111
                            2r1000001111111111
                            2r1000010000000111
                            2r1100100000001100
                            2r0110000000011000
                            2r0011111111110000
                            2r0001111111100000
                            2r0001111111100000
                            2r0001111111100000
                            )
                        maskArray: #(
                            2r0011111111110000
                            2r0011111111110000
                            2r0011111111110000
                            2r0111111111111000
                            2r1111111111111100
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111100
                            2r0111111111111000
                            2r0011111111110000
                            2r0011111111110000
                            2r0011111111110000
                           )
                        offset: -15 @ -9).
        Wait2Cursor := Wait2Cursor on:Display.
    ].
    ^ Wait2Cursor
!

wait3
    "return a wait cursor showing 6 o'clock"

    Wait3Cursor isNil ifTrue:[
        Wait3Cursor := (Cursor
                        extent: 16@16
                        sourceArray: #(
                            2r0001111111100000
                            2r0001111111100000
                            2r0001111111100000
                            2r0011111111110000
                            2r0110000000011000
                            2r1100000000001100
                            2r1000000000000111
                            2r1000001110000111
                            2r1000001110000111
                            2r1000010100000111
                            2r1100100100001100
                            2r0110000100011000
                            2r0011111111110000
                            2r0001111111100000
                            2r0001111111100000
                            2r0001111111100000
                            )
                        maskArray: #(
                            2r0011111111110000
                            2r0011111111110000
                            2r0011111111110000
                            2r0111111111111000
                            2r1111111111111100
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111100
                            2r0111111111111000
                            2r0011111111110000
                            2r0011111111110000
                            2r0011111111110000
                           )
                        offset: -15 @ -9).
        Wait3Cursor := Wait3Cursor on:Display.
    ].
    ^ Wait3Cursor
!

wait4
    "return a wait cursor showing 9 o'clock"

    Wait4Cursor isNil ifTrue:[
        Wait4Cursor := (Cursor
                        extent: 16@16
                        sourceArray: #(
                            2r0001111111100000
                            2r0001111111100000
                            2r0001111111100000
                            2r0011111111110000
                            2r0110000000011000
                            2r1100000000001100
                            2r1000000000000111
                            2r1111111110000111
                            2r1000001110000111
                            2r1000010000000111
                            2r1100100000001100
                            2r0110000000011000
                            2r0011111111110000
                            2r0001111111100000
                            2r0001111111100000
                            2r0001111111100000
                            )
                        maskArray: #(
                            2r0011111111110000
                            2r0011111111110000
                            2r0011111111110000
                            2r0111111111111000
                            2r1111111111111100
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111111
                            2r1111111111111100
                            2r0111111111111000
                            2r0011111111110000
                            2r0011111111110000
                            2r0011111111110000
                           )
                        offset: -15 @ -9).
        Wait4Cursor := Wait4Cursor on:Display.
    ].
    ^ Wait4Cursor
!

read
    "return a reading-file cursor"

    ReadCursor isNil ifTrue:[
        ReadCursor := self shape:#wait
    ].
    ^ ReadCursor
!

write
    "return a writing-file cursor"

    WriteCursor isNil ifTrue:[
        WriteCursor := self shape:#wait
    ].
    ^ WriteCursor
!

execute
    "return a execute cursor - ST-80 compatibility"

    XeqCursor isNil ifTrue:[
        XeqCursor := self shape:#wait
    ].
    ^ XeqCursor
!

thumbsUp
    "return a hand cursor - ST-80 compatibility"

    ^ self hand
!

thumbsDown
    "return a hand cursor - ST-80 compatibility"

    ^ self hand
! !

!Cursor methodsFor:'instance release'!

disposed
    "some Cursor has been collected - tell it to the x-server"

    cursorId notNil ifTrue:[
        device destroyCursor:cursorId.
    ]
! !

!Cursor methodsFor:'private accessing'!

setShape:aShapeSymbol
    "set the shape"

    shape := aShapeSymbol.
!

setSourceForm:sForm maskForm:mForm hotX:hx hotY:hy
    "set the forms and hotspot"

    sourceForm := sForm.
    maskForm := mForm.
    hotX := hx.
    hotY := hy.
!

setDevice:aDevice id:anId
    "set the device and deviceId of the receiver"

    device := aDevice.
    cursorId := anId
! !

!Cursor methodsFor:'accessing'!

id
    "return the cursors deviceId"

    ^ cursorId
!

device
    "return the device I am associated with"

    ^ device
!

shape
    "return the shape"

    ^ shape
!

sourceForm
    "return the source-form of the receiver"

    ^ sourceForm
!

sourceForm:aForm
    "set the source-form of the receiver"

    sourceForm := aForm
!

maskForm
    "return the mask-form of the receiver"

    ^ maskForm
!

maskForm:aForm
    "set the mask-form of the receiver"

    maskForm := aForm
!

hotX
    "return the hotspots x-coordinate of the receiver"

    ^ hotX
!

hotY
    "return the hotspots y-coordinate of the receiver"

    ^ hotY
!

foreground:fgColor background:bgColor
    "set the cursor colors"

    device colorCursor:cursorId foreground:fgColor background:bgColor
! !

!Cursor methodsFor:'creating a device cursor'!

on:aDevice
    "create a new Cursor representing the same cursor as
     myself on aDevice; if one already exists, return the one"

    |newCursor id|

    aDevice isNil ifTrue:[
        "this may not happen"
        self error:'nil device'
    ].

    "if Iam already assigned to that device ..."
    (device == aDevice) ifTrue:[^ self].

    "first look if not already there"
    Lobby contentsDo:[:aCursor |
        (aCursor device == aDevice) ifTrue:[
            shape notNil ifTrue:[
                (aCursor shape == shape) ifTrue:[
                    ^ aCursor
                ]
            ] ifFalse:[
                (aCursor sourceForm == sourceForm) ifTrue:[
                    (aCursor maskForm == maskForm) ifTrue:[
                        (aCursor hotX == hotX) ifTrue:[
                            (aCursor hotY == hotY) ifTrue:[
                                ^ aCursor
                            ]
                        ]
                    ]
                ]
            ]
        ]
    ].

    "ask that device for the cursor"
    shape notNil ifTrue:[
        id := aDevice createCursorShape:shape.
        id isNil ifTrue:[
            'no cursor with shape:' errorPrint. shape errorPrintNewline.
            ^ nil
        ].
    ] ifFalse:[
        id := aDevice createCursorSourceForm:sourceForm
                                    maskForm:maskForm
                                        hotX:hotX
                                        hotY:hotY.
        id isNil ifTrue:[
            'cannot create cursor' errorPrintNewline.
            ^ nil
        ].
    ].

    "goody for IRIXs red cursor"
    DefaultFgColor notNil ifTrue:[
        aDevice colorCursor:id foreground:DefaultFgColor
                               background:DefaultBgColor
    ].

    device isNil ifTrue:[
        "receiver was not associated - do it now"
        device := aDevice.
        cursorId := id.

        "must unregister, the old registration had a nil cursorId in it"
        Lobby changed:self.
        ^ self
    ].

    "receiver was already associated to another device - need a new cursor"
    newCursor := self class basicNew.
    shape notNil ifTrue:[
        newCursor setShape:shape.
    ] ifFalse:[
        newCursor setSourceForm:sourceForm
                       maskForm:maskForm
                           hotX:hotX
                           hotY:hotY
    ].
    newCursor setDevice:aDevice id:id.
    Lobby register:newCursor.
    ^ newCursor
! !

!Cursor methodsFor:'private'!

device:aDevice
    device := aDevice
!

id:anId
    "set the cursors deviceId"

    cursorId := anId
!

restored
    "set both device and id"

    device := nil.
    cursorId := nil
! !

!Cursor methodsFor:'displaying'!

showIn:aView 
    aView cursor:self
!

showIn:aView while:aBlock
    |savedCursor|

    savedCursor := aView cursor.
    aView cursor:self.
    [
        aBlock value.
    ] valueNowOrOnUnwindDo:[
        aView cursor:savedCursor
    ]
!

showWhile:aBlock
    "change all views cursors to the receiver.
     In X this seems to be very slow"

    |v|

    Display setCursors:self.
    v := aBlock valueNowOrOnUnwindDo:[
        Display restoreCursors.
    ].
    ^ v
!

displayOn:aGC at:origin clippingBox:aRectangle rule:aRule mask:aMask
    "ST-80 compatibility;
     limited functionality: can only display bitmap cursors (yet)"

    sourceForm notNil ifTrue:[
        sourceForm displayOn:aGC at:origin clippingBox:aRectangle 
                        rule:aRule mask:aMask
    ]
! !