changing mouse cursor

Mac OSX specific forum
spacebuddy
Enthusiast
Enthusiast
Posts: 349
Joined: Thu Jul 02, 2009 5:42 am

changing mouse cursor

Post by spacebuddy »

Hi All,

How do you change the cursor to busy then back?

I checked the documentation and did a search with no results. :shock:
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: changing mouse cursor

Post by Shardik »

Try this little code example to cycle through all 19 cursor shapes
MacOS X is offering. Click onto "Change cursor" to see the next
cursor. But beware: if you move the cursor, the default cursor is
immediately restored.

Code: Select all

ImportC ""
  SetThemeCursor(CursorType.L)
EndImport

OpenWindow(0, 200, 100, 200, 180, "Change cursor")
ButtonGadget(0, 40, 70, 120, 20, "Change cursor")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 0
        If CursorID = 18
          CursorID = 0
        Else
          CursorID + 1
        EndIf

        SetThemeCursor(CursorID)
      EndIf
  EndSelect
ForEver
To switch the default arrow cursor to a busy cursor, try this
code example which also contains the constants of all possible
cursors:

Code: Select all

ImportC ""
  SetThemeCursor(CursorType.L)
EndImport

; ----- Theme Cursors

#kThemeArrowCursor = 0
#kThemeCopyArrowCursor = 1
#kThemeAliasArrowCursor = 2
#kThemeContextualMenuArrowCursor = 3
#kThemeIBeamCursor = 4
#kThemeCrossCursor = 5
#kThemePlusCursor = 6
#kThemeWatchCursor = 7
#kThemeClosedHandCursor = 8
#kThemeOpenHandCursor = 9
#kThemePointingHandCursor = 10
#kThemeCountingUpHandCursor = 11
#kThemeCountingDownHandCursor = 12
#kThemeCountingUpAndDownHandCursor = 13
#kThemeSpinningCursor = 14
#kThemeResizeLeftCursor = 15
#kThemeResizeRightCursor = 16
#kThemeResizeLeftRightCursor = 17
#kThemeNotAllowedCursor = 18

OpenWindow(0, 200, 100, 200, 180, "Display Wait cursor")
ButtonGadget(0, 40, 70, 120, 20, "Change cursor")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 0
        SetThemeCursor(#kThemeWatchCursor)
      EndIf
  EndSelect
ForEver
spacebuddy
Enthusiast
Enthusiast
Posts: 349
Joined: Thu Jul 02, 2009 5:42 am

Re: changing mouse cursor

Post by spacebuddy »

Wow, works perfectly, thank you :D
WilliamL
Addict
Addict
Posts: 1224
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: changing mouse cursor

Post by WilliamL »

Thanks again, Shardik,

I wanted to ask if using the other cursors were possible on the Mac.

I think I need it to stay changed until I change it back...
MacBook Pro-M1 (2021), Sonoma 14.4.1, PB 6.10LTS M1
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: changing mouse cursor

Post by Shardik »

WilliamL wrote:I think I need it to stay changed until I change it back...
William,

that's a very delicate topic which already resulted in numerous postings
and heated discussions in different Mac forums. Most Mac addicts don't
like the concept that the programmer changes the cursor shape to a wait
cursor. They argue that MacOS takes care of changing the cursor
automatically if your application is busy and that therefore it should be
forbidden to change its shape programmatically. As an example for that
concept try the following simple code example which switches the cursor
shape to a spinning wheel (I had to learn that this cursor is called "Spinning
pizza Of Death" or SPOD :lol:). A "Delay(2000)" simulates activity (and doesn't
process window events in this time span) and therefore keeps this cursor
active for 2000 ms and automatically switches back to the default cursor.
Most Mac addicts argue that you should never use the SPOD cursor because
the normal Mac user is thinking that the application hangs and he would have
to terminate your app or even has to reboot his Mac...: :P

Code: Select all

ImportC ""
  QDDisplayWaitCursor(ForceWaitCursor.L)
EndImport

OpenWindow(0, 200, 100, 250, 130, "Display Wait cursor")
ButtonGadget(0, 10, 50, 230, 20, "Change cursor to spinning wheel")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 0
        QDDisplayWaitCursor(#True)
        Delay(2000)
        QDDisplayWaitCursor(#False)
      EndIf
  EndSelect
ForEver
But nevertheless it's possible to display a wait cursor as long as you want it.
But it's a lot of effort to realize it because you have to install an EventHandler
that intercepts mouse movements and restores the wait cursor on every mouse
movement. As an additional goodie I have implemented a WindowTimer, so that
animated wait cursors are possible. But don't reveal this example to the hardcore
Mac addicts because they would probably lynch me... :lol:

Code: Select all

EnableExplicit

ImportC ""
  GetEventClass(Event)
  RemoveEventHandler(EventHandlerRef.L)
  SetAnimatedThemeCursor(CursorType.L, AnimationStep.L)
  SetThemeCursor(CursorType.L)
EndImport

#kEventClassMouse = 'mous'
#kEventMouseMoved = 5
#kThemeArrowCursor = 0
#kThemeWatchCursor = 7
#kThemeSpinningCursor = 14

Structure EventTypeSpec
  EventClass.L
  EventKind.L
EndStructure

Define AnimationStep.L
Define CursorID.L
Define EventHandlerRef.L
Define EventHandlerUPP.L
Define NumAnimationSteps.L

Procedure EventHandler(*NextEventHandler, Event, UserData)
  Shared AnimationStep.L
  Shared CursorID.L

  If GetEventClass(Event) = #kEventClassMouse
    If GetEventKind_(Event) = #kEventMouseMoved
      SetAnimatedThemeCursor(CursorID, AnimationStep)
    EndIf
  EndIf
EndProcedure

Dim EventTypes.EventTypeSpec(0)

OpenWindow(0, 200, 100, 250, 120, "Display animated wait cursor")
ButtonGadget(0, 10, 20, 230, 20, "Change cursor to spinning wheel")
ButtonGadget(1, 10, 50, 230, 20, "Change cursor to running watch")
ButtonGadget(2, 10, 80, 230, 20, "Restore default cursor")

EventHandlerUPP = NewEventHandlerUPP_(@EventHandler())
EventTypes(0)\EventClass = #kEventClassMouse
EventTypes(0)\EventKind = #kEventMouseMoved

CursorID = #kThemeSpinningCursor
NumAnimationSteps = 4

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      If EventHandlerRef
        RemoveEventHandler(EventHandlerRef)
      EndIf
      Break
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0
          CursorID = #kThemeSpinningCursor
          NumAnimationSteps = 4
          InstallEventHandler_(GetWindowEventTarget_(WindowID(0)), EventHandlerUPP, 1, @EventTypes(), 0, @EventHandlerRef)
          AddWindowTimer(0, 0, 150)
          DisableGadget(0, #True)
          DisableGadget(1, #True)
        Case 1
          CursorID = #kThemeWatchCursor
          NumAnimationSteps = 8
          InstallEventHandler_(GetWindowEventTarget_(WindowID(0)), EventHandlerUPP, 1, @EventTypes(), 0, @EventHandlerRef)
          AddWindowTimer(0, 0, 150)
          DisableGadget(0, #True)
          DisableGadget(1, #True)
        Case 2
          RemoveEventHandler(EventHandlerRef)
          EventHandlerRef = 0
          RemoveWindowTimer(0, 0)
          DisableGadget(0, #False)
          DisableGadget(1, #False)
          SetThemeCursor(#kThemeArrowCursor)
      EndSelect
    Case #PB_Event_Timer
      If EventTimer() = 0
        SetAnimatedThemeCursor(CursorID, AnimationStep)
        AnimationStep = (AnimationStep + 1) % NumAnimationSteps
      EndIf
  EndSelect
ForEver
WilliamL
Addict
Addict
Posts: 1224
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: changing mouse cursor

Post by WilliamL »

Thanks Shardik,

Your work-around seems to work! I didn't know about the arguments but I can see the point for the 'busy' cursor but there are other cursors that have other uses like the hand if you are moving something. I've noticed that the cursor changes to the 'I' bar in the StringGadget but stays as an arrow in the CanvasGadget I haven't checked what happens with the cursor with other gadgets. With 16 cursors there must be times that the programmer would want control over what cursor is showing...

It's too bad that it is so hard to change the cursor (I think). The Basic I came from had a cursor command for changing the cursor and I used it.
MacBook Pro-M1 (2021), Sonoma 14.4.1, PB 6.10LTS M1
User avatar
Shardik
Addict
Addict
Posts: 1991
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: changing mouse cursor

Post by Shardik »

By analysing which WindowEvents PB is reporting during an event loop
with WaitWindowEvent(), I found out that while moving the mouse a
-1 event is reported. Consequently I was able to simplify my above
code example by removing the EventHandler and repaint the cursor on
every event with -1:

Code: Select all

EnableExplicit

ImportC ""
  SetAnimatedThemeCursor(CursorType.L, AnimationStep.L)
  SetThemeCursor(CursorType.L)
EndImport

#kEventClassMouse = 'mous'
#kEventMouseMoved = 5
#kThemeArrowCursor = 0
#kThemeWatchCursor = 7
#kThemeSpinningCursor = 14

Define AnimationStep.L
Define CursorID.L
Define CursorIsAnimated.L
Define NumAnimationSteps.L
Define WindowEvent.L

OpenWindow(0, 200, 100, 250, 120, "Display animated wait cursor")
ButtonGadget(0, 10, 20, 230, 20, "Change cursor to spinning wheel")
ButtonGadget(1, 10, 50, 230, 20, "Change cursor to running watch")
ButtonGadget(2, 10, 80, 230, 20, "Restore default cursor")
DisableGadget(2, #True)

Repeat
  WindowEvent = WaitWindowEvent()

  Select WindowEvent
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0
          CursorID = #kThemeSpinningCursor
          NumAnimationSteps = 4
          CursorIsAnimated = #True
          AddWindowTimer(0, 0, 150)
          DisableGadget(0, #True)
          DisableGadget(1, #True)
          DisableGadget(2, #False)
        Case 1
          CursorID = #kThemeWatchCursor
          NumAnimationSteps = 8
          CursorIsAnimated = #True
          AddWindowTimer(0, 0, 150)
          DisableGadget(0, #True)
          DisableGadget(1, #True)
          DisableGadget(2, #False)
        Case 2
          CursorIsAnimated = #False
          RemoveWindowTimer(0, 0)
          SetThemeCursor(#kThemeArrowCursor)
          DisableGadget(0, #False)
          DisableGadget(1, #False)
          DisableGadget(2, #True)
      EndSelect
    Case #PB_Event_Timer
      If EventTimer() = 0
        SetAnimatedThemeCursor(CursorID, AnimationStep)
        AnimationStep = (AnimationStep + 1) % NumAnimationSteps
      EndIf
    Case -1
      If CursorIsAnimated
        SetAnimatedThemeCursor(CursorID, AnimationStep)
      Else
        SetThemeCursor(#kThemeArrowCursor)
      EndIf
  EndSelect
ForEver
And the shortest example of a non-changing wait cursor can even be
reduced to this:

Code: Select all

ImportC ""
  SetThemeCursor(CursorType.L)
EndImport

#kThemeArrowCursor = 0
#kThemeWatchCursor = 7

OpenWindow(0, 200, 100, 200, 180, "Display Wait cursor")
ButtonGadget(0, 40, 70, 120, 20, "Change cursor")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 0
        If IsWaitCursor
          SetThemeCursor(#kThemeArrowCursor)
          IsWaitCursor = #False
        Else
          SetThemeCursor(#kThemeWatchCursor)
          IsWaitCursor = #True
        EndIf
      EndIf
    Case -1
      If IsWaitCursor
        SetThemeCursor(#kThemeWatchCursor)
      EndIf
  EndSelect
ForEver
WilliamL
Addict
Addict
Posts: 1224
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: changing mouse cursor

Post by WilliamL »

Shardik,

It crossed my mind to check for the -1 event and just change the cursor back to my choice. Somehow it seemed inefficient but it does seem to work fine. I think your last example could be worked into a program with a global for CursorID & AnimationStep (and GetActiveWindow for timer) and just set as needed. I'd have to try it to see if it was that simple.

Showing how to handle the steps in an animated cursor is also helpful.
MacBook Pro-M1 (2021), Sonoma 14.4.1, PB 6.10LTS M1
Post Reply