0
# Cursor Management
1
2
Comprehensive mouse cursor control including system cursors, custom bitmap cursors, and color cursors. Provides both high-level cursor management and low-level cursor compilation utilities.
3
4
## Capabilities
5
6
### Cursor Object
7
8
The Cursor class provides unified interface for all cursor types.
9
10
```python { .api }
11
class Cursor:
12
def __init__(self, *args):
13
"""
14
Create cursor from various sources.
15
16
Parameters:
17
*args: Variable arguments depending on cursor type:
18
- (constant,) for system cursors
19
- (size, hotspot, xormasks, andmasks) for bitmap cursors
20
- (hotspot, surface) for color cursors
21
"""
22
23
type: str # "system", "bitmap", or "color"
24
data: tuple # Cursor-specific data
25
26
def copy(self) -> Cursor:
27
"""
28
Create copy of cursor.
29
30
Returns:
31
Cursor: New cursor object with same data
32
"""
33
```
34
35
### System Cursor Management
36
37
Functions for setting and querying the current system cursor.
38
39
```python { .api }
40
def set_cursor(*args) -> None:
41
"""
42
Set the current mouse cursor.
43
44
Parameters:
45
*args: Cursor data in various formats:
46
- (cursor_object,) - Set from Cursor object
47
- (constant,) - Set system cursor by constant
48
- (size, hotspot, xormasks, andmasks) - Set bitmap cursor
49
- (hotspot, surface) - Set color cursor from surface
50
"""
51
52
def get_cursor() -> Cursor:
53
"""
54
Get the current cursor.
55
56
Returns:
57
Cursor: Current cursor object
58
"""
59
```
60
61
### Bitmap Cursor Compilation
62
63
Utilities for creating bitmap cursors from string representations.
64
65
```python { .api }
66
def compile(
67
strings: tuple[str, ...],
68
black: str = "X",
69
white: str = ".",
70
xor: str = "o"
71
) -> tuple[tuple[int, ...], tuple[int, ...]]:
72
"""
73
Compile cursor from string representation.
74
75
Parameters:
76
strings: Tuple of strings representing cursor bitmap
77
black: Character representing black pixels
78
white: Character representing white pixels
79
xor: Character representing XOR pixels
80
81
Returns:
82
tuple[tuple[int, ...], tuple[int, ...]]: (xormasks, andmasks) bitmap data
83
"""
84
85
def load_xbm(cursor_file, mask_file) -> tuple:
86
"""
87
Load cursor from XBM format files.
88
89
Parameters:
90
cursor_file: Path to cursor XBM file
91
mask_file: Path to mask XBM file
92
93
Returns:
94
tuple: Cursor data suitable for Cursor creation
95
"""
96
```
97
98
### Pre-defined System Cursors
99
100
Built-in cursor constants for common system cursors.
101
102
```python { .api }
103
# System cursor constants
104
SYSTEM_CURSOR_ARROW: int # Standard arrow cursor
105
SYSTEM_CURSOR_IBEAM: int # Text input cursor
106
SYSTEM_CURSOR_WAIT: int # Wait/busy cursor
107
SYSTEM_CURSOR_CROSSHAIR: int # Crosshair cursor
108
SYSTEM_CURSOR_WAITARROW: int # Arrow with wait symbol
109
SYSTEM_CURSOR_SIZENWSE: int # Resize NW-SE cursor
110
SYSTEM_CURSOR_SIZENESW: int # Resize NE-SW cursor
111
SYSTEM_CURSOR_SIZEWE: int # Resize W-E cursor
112
SYSTEM_CURSOR_SIZENS: int # Resize N-S cursor
113
SYSTEM_CURSOR_SIZEALL: int # Move/resize all directions
114
SYSTEM_CURSOR_NO: int # Not allowed cursor
115
SYSTEM_CURSOR_HAND: int # Hand/pointer cursor
116
```
117
118
### Pre-compiled Cursors
119
120
Ready-to-use cursor objects for common cursor types.
121
122
```python { .api }
123
# Pre-compiled cursor objects
124
arrow: Cursor # Standard arrow cursor
125
diamond: Cursor # Diamond-shaped cursor
126
ball: Cursor # Ball/circle cursor
127
broken_x: Cursor # Broken X cursor
128
tri_left: Cursor # Left-pointing triangle
129
tri_right: Cursor # Right-pointing triangle
130
```
131
132
### Cursor String Templates
133
134
String templates for creating custom cursors with compile().
135
136
```python { .api }
137
# String templates for cursor compilation
138
thickarrow_strings: tuple[str, ...] # Thick arrow cursor
139
sizer_x_strings: tuple[str, ...] # Horizontal resize cursor
140
sizer_y_strings: tuple[str, ...] # Vertical resize cursor
141
sizer_xy_strings: tuple[str, ...] # Diagonal resize cursor
142
textmarker_strings: tuple[str, ...] # Text marker cursor
143
```
144
145
## Usage Examples
146
147
### Basic Cursor Management
148
149
```python
150
import pygame
151
import pygame.cursors
152
153
pygame.init()
154
screen = pygame.display.set_mode((800, 600))
155
156
# Set different system cursors
157
print("Changing to different system cursors...")
158
159
# Standard arrow (default)
160
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_ARROW)
161
pygame.time.wait(1000)
162
163
# Hand cursor for clickable elements
164
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_HAND)
165
pygame.time.wait(1000)
166
167
# Text input cursor
168
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_IBEAM)
169
pygame.time.wait(1000)
170
171
# Wait cursor
172
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_WAIT)
173
pygame.time.wait(1000)
174
175
# Crosshair cursor
176
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_CROSSHAIR)
177
pygame.time.wait(1000)
178
179
# Get current cursor
180
current_cursor = pygame.cursors.get_cursor()
181
print(f"Current cursor type: {current_cursor.type}")
182
183
pygame.quit()
184
```
185
186
### Pre-compiled Cursors
187
188
```python
189
import pygame
190
import pygame.cursors
191
192
pygame.init()
193
screen = pygame.display.set_mode((800, 600))
194
195
# Use pre-compiled cursors
196
cursors_to_try = [
197
("Arrow", pygame.cursors.arrow),
198
("Diamond", pygame.cursors.diamond),
199
("Ball", pygame.cursors.ball),
200
("Broken X", pygame.cursors.broken_x),
201
("Triangle Left", pygame.cursors.tri_left),
202
("Triangle Right", pygame.cursors.tri_right),
203
]
204
205
for name, cursor in cursors_to_try:
206
print(f"Setting cursor: {name}")
207
pygame.cursors.set_cursor(cursor)
208
pygame.time.wait(1500)
209
210
pygame.quit()
211
```
212
213
### Custom Bitmap Cursor
214
215
```python
216
import pygame
217
import pygame.cursors
218
219
pygame.init()
220
screen = pygame.display.set_mode((800, 600))
221
222
# Create custom cursor from string
223
custom_cursor_strings = (
224
" XX ",
225
" X..X ",
226
" X....X ",
227
" X......X ",
228
" X........X ",
229
"X..........X",
230
" X........X ",
231
" X......X ",
232
" X....X ",
233
" X..X ",
234
" XX ",
235
)
236
237
# Compile the cursor
238
cursor_data = pygame.cursors.compile(
239
custom_cursor_strings,
240
black='X', # Character for black pixels
241
white='.', # Character for white pixels
242
xor='o' # Character for XOR pixels (unused here)
243
)
244
245
# Create cursor object
246
size = (12, 11) # Width x Height
247
hotspot = (6, 5) # Center point
248
custom_cursor = pygame.cursors.Cursor(size, hotspot, cursor_data[0], cursor_data[1])
249
250
# Set the custom cursor
251
pygame.cursors.set_cursor(custom_cursor)
252
253
print("Custom cursor set! Move mouse to see it.")
254
pygame.time.wait(3000)
255
256
pygame.quit()
257
```
258
259
### Color Cursor from Surface
260
261
```python
262
import pygame
263
import pygame.cursors
264
265
pygame.init()
266
screen = pygame.display.set_mode((800, 600))
267
268
# Create a colorful cursor surface
269
cursor_size = (32, 32)
270
cursor_surface = pygame.Surface(cursor_size, pygame.SRCALPHA)
271
272
# Draw a colorful cursor
273
center = (cursor_size[0] // 2, cursor_size[1] // 2)
274
275
# Draw concentric circles
276
pygame.draw.circle(cursor_surface, (255, 0, 0, 200), center, 15)
277
pygame.draw.circle(cursor_surface, (0, 255, 0, 200), center, 10)
278
pygame.draw.circle(cursor_surface, (0, 0, 255, 200), center, 5)
279
280
# Add crosshair
281
pygame.draw.line(cursor_surface, (255, 255, 255), (center[0], 0), (center[0], cursor_size[1]), 2)
282
pygame.draw.line(cursor_surface, (255, 255, 255), (0, center[1]), (cursor_size[0], center[1]), 2)
283
284
# Create color cursor
285
hotspot = center # Click point at center
286
color_cursor = pygame.cursors.Cursor(hotspot, cursor_surface)
287
288
# Set the color cursor
289
pygame.cursors.set_cursor(color_cursor)
290
291
print("Color cursor set! Move mouse to see the colorful cursor.")
292
pygame.time.wait(5000)
293
294
pygame.quit()
295
```
296
297
### Context-Sensitive Cursors
298
299
```python
300
import pygame
301
import pygame.cursors
302
303
pygame.init()
304
screen = pygame.display.set_mode((800, 600))
305
pygame.display.set_caption("Context-Sensitive Cursors")
306
307
# Define areas with different cursors
308
button_rect = pygame.Rect(100, 100, 200, 100)
309
text_rect = pygame.Rect(400, 200, 300, 50)
310
resize_rect = pygame.Rect(650, 450, 100, 100)
311
312
# Cursor for different contexts
313
default_cursor = pygame.cursors.Cursor(pygame.cursors.SYSTEM_CURSOR_ARROW)
314
button_cursor = pygame.cursors.Cursor(pygame.cursors.SYSTEM_CURSOR_HAND)
315
text_cursor = pygame.cursors.Cursor(pygame.cursors.SYSTEM_CURSOR_IBEAM)
316
resize_cursor = pygame.cursors.Cursor(pygame.cursors.SYSTEM_CURSOR_SIZENWSE)
317
318
current_cursor = None
319
clock = pygame.time.Clock()
320
running = True
321
322
while running:
323
for event in pygame.event.get():
324
if event.type == pygame.QUIT:
325
running = False
326
327
# Get mouse position
328
mouse_pos = pygame.mouse.get_pos()
329
330
# Determine appropriate cursor based on mouse position
331
new_cursor = default_cursor
332
333
if button_rect.collidepoint(mouse_pos):
334
new_cursor = button_cursor
335
elif text_rect.collidepoint(mouse_pos):
336
new_cursor = text_cursor
337
elif resize_rect.collidepoint(mouse_pos):
338
new_cursor = resize_cursor
339
340
# Only change cursor if different
341
if new_cursor != current_cursor:
342
pygame.cursors.set_cursor(new_cursor)
343
current_cursor = new_cursor
344
345
# Draw interface elements
346
screen.fill((240, 240, 240))
347
348
# Draw button
349
pygame.draw.rect(screen, (100, 150, 255), button_rect)
350
pygame.draw.rect(screen, (0, 0, 0), button_rect, 2)
351
font = pygame.font.Font(None, 36)
352
text = font.render("Button", True, (255, 255, 255))
353
text_pos = (button_rect.centerx - text.get_width()//2,
354
button_rect.centery - text.get_height()//2)
355
screen.blit(text, text_pos)
356
357
# Draw text area
358
pygame.draw.rect(screen, (255, 255, 255), text_rect)
359
pygame.draw.rect(screen, (0, 0, 0), text_rect, 2)
360
text_label = font.render("Text Input Area", True, (0, 0, 0))
361
screen.blit(text_label, (text_rect.x + 5, text_rect.y + 10))
362
363
# Draw resize area
364
pygame.draw.rect(screen, (255, 200, 100), resize_rect)
365
pygame.draw.rect(screen, (0, 0, 0), resize_rect, 2)
366
resize_text = font.render("Resize", True, (0, 0, 0))
367
resize_pos = (resize_rect.centerx - resize_text.get_width()//2,
368
resize_rect.centery - resize_text.get_height()//2)
369
screen.blit(resize_text, resize_pos)
370
371
# Draw instructions
372
instructions = [
373
"Move mouse over different areas:",
374
"• Button area - Hand cursor",
375
"• Text area - I-beam cursor",
376
"• Resize area - Resize cursor",
377
"• Other areas - Default arrow"
378
]
379
380
small_font = pygame.font.Font(None, 24)
381
y = 20
382
for instruction in instructions:
383
text_surface = small_font.render(instruction, True, (0, 0, 0))
384
screen.blit(text_surface, (20, y))
385
y += 25
386
387
pygame.display.flip()
388
clock.tick(60)
389
390
pygame.quit()
391
```
392
393
### Advanced Cursor Animation
394
395
```python
396
import pygame
397
import pygame.cursors
398
import math
399
400
pygame.init()
401
screen = pygame.display.set_mode((800, 600))
402
pygame.display.set_caption("Animated Cursor")
403
404
class AnimatedCursor:
405
def __init__(self, frames, frame_duration=100):
406
self.frames = frames
407
self.frame_duration = frame_duration
408
self.current_frame = 0
409
self.last_update = pygame.time.get_ticks()
410
411
def update(self):
412
now = pygame.time.get_ticks()
413
if now - self.last_update > self.frame_duration:
414
self.current_frame = (self.current_frame + 1) % len(self.frames)
415
pygame.cursors.set_cursor(self.frames[self.current_frame])
416
self.last_update = now
417
418
# Create spinning cursor frames
419
def create_spinning_cursor_frames(num_frames=8):
420
frames = []
421
cursor_size = (32, 32)
422
center = (cursor_size[0] // 2, cursor_size[1] // 2)
423
424
for i in range(num_frames):
425
surface = pygame.Surface(cursor_size, pygame.SRCALPHA)
426
angle = (360 / num_frames) * i
427
428
# Draw rotating arrow
429
length = 12
430
angle_rad = math.radians(angle)
431
end_x = center[0] + length * math.cos(angle_rad)
432
end_y = center[1] + length * math.sin(angle_rad)
433
434
# Arrow shaft
435
pygame.draw.line(surface, (255, 255, 255), center, (end_x, end_y), 3)
436
437
# Arrow head
438
head_angle1 = angle_rad + math.radians(150)
439
head_angle2 = angle_rad - math.radians(150)
440
head_length = 8
441
442
head1_x = end_x + head_length * math.cos(head_angle1)
443
head1_y = end_y + head_length * math.sin(head_angle1)
444
head2_x = end_x + head_length * math.cos(head_angle2)
445
head2_y = end_y + head_length * math.sin(head_angle2)
446
447
pygame.draw.line(surface, (255, 255, 255), (end_x, end_y), (head1_x, head1_y), 2)
448
pygame.draw.line(surface, (255, 255, 255), (end_x, end_y), (head2_x, head2_y), 2)
449
450
# Create cursor
451
cursor = pygame.cursors.Cursor(center, surface)
452
frames.append(cursor)
453
454
return frames
455
456
# Create animated cursor
457
spinner_frames = create_spinning_cursor_frames(12)
458
animated_cursor = AnimatedCursor(spinner_frames, frame_duration=100)
459
460
clock = pygame.time.Clock()
461
running = True
462
463
while running:
464
for event in pygame.event.get():
465
if event.type == pygame.QUIT:
466
running = False
467
elif event.type == pygame.KEYDOWN:
468
if event.key == pygame.K_SPACE:
469
# Toggle between animated and normal cursor
470
if hasattr(animated_cursor, 'active'):
471
animated_cursor.active = not animated_cursor.active
472
if not animated_cursor.active:
473
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_ARROW)
474
else:
475
animated_cursor.active = True
476
477
# Update animated cursor
478
if hasattr(animated_cursor, 'active') and animated_cursor.active:
479
animated_cursor.update()
480
481
# Draw instructions
482
screen.fill((50, 50, 50))
483
font = pygame.font.Font(None, 48)
484
text1 = font.render("Animated Cursor Demo", True, (255, 255, 255))
485
text2 = font.render("Press SPACE to toggle animation", True, (200, 200, 200))
486
487
screen.blit(text1, (screen.get_width()//2 - text1.get_width()//2, 200))
488
screen.blit(text2, (screen.get_width()//2 - text2.get_width()//2, 300))
489
490
pygame.display.flip()
491
clock.tick(60)
492
493
pygame.quit()
494
```
495
496
### XBM Cursor Loading
497
498
```python
499
import pygame
500
import pygame.cursors
501
import tempfile
502
import os
503
504
pygame.init()
505
screen = pygame.display.set_mode((800, 600))
506
507
# Create sample XBM files for demonstration
508
cursor_xbm_data = """#define cursor_width 16
509
#define cursor_height 16
510
static unsigned char cursor_bits[] = {
511
0x00, 0x00, 0x40, 0x02, 0x60, 0x06, 0x70, 0x0e, 0x78, 0x1e, 0x7c, 0x3e,
512
0x7e, 0x7e, 0x7f, 0xfe, 0x7f, 0xfe, 0x7e, 0x7e, 0x6c, 0x36, 0x46, 0x62,
513
0x06, 0x60, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00 };"""
514
515
mask_xbm_data = """#define mask_width 16
516
#define mask_height 16
517
static unsigned char mask_bits[] = {
518
0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f,
519
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xef, 0xf7,
520
0xcf, 0xf3, 0x07, 0xe0, 0x07, 0xe0, 0x03, 0xc0 };"""
521
522
# Write temporary XBM files
523
with tempfile.NamedTemporaryFile(mode='w', suffix='.xbm', delete=False) as cursor_file:
524
cursor_file.write(cursor_xbm_data)
525
cursor_filename = cursor_file.name
526
527
with tempfile.NamedTemporaryFile(mode='w', suffix='.xbm', delete=False) as mask_file:
528
mask_file.write(mask_xbm_data)
529
mask_filename = mask_file.name
530
531
try:
532
# Load cursor from XBM files
533
xbm_cursor_data = pygame.cursors.load_xbm(cursor_filename, mask_filename)
534
535
# Create cursor object
536
size = (16, 16)
537
hotspot = (0, 0)
538
xbm_cursor = pygame.cursors.Cursor(size, hotspot, xbm_cursor_data[0], xbm_cursor_data[1])
539
540
# Set the XBM cursor
541
pygame.cursors.set_cursor(xbm_cursor)
542
543
print("XBM cursor loaded and set!")
544
pygame.time.wait(3000)
545
546
except Exception as e:
547
print(f"Error loading XBM cursor: {e}")
548
549
finally:
550
# Clean up temporary files
551
try:
552
os.unlink(cursor_filename)
553
os.unlink(mask_filename)
554
except:
555
pass
556
557
# Restore default cursor
558
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_ARROW)
559
560
pygame.quit()
561
```
562
563
## Constants
564
565
System cursor constants and cursor compilation characters:
566
567
```python { .api }
568
# System cursor types
569
SYSTEM_CURSOR_ARROW: int = 0 # Standard arrow
570
SYSTEM_CURSOR_IBEAM: int = 1 # Text selection
571
SYSTEM_CURSOR_WAIT: int = 2 # Wait/loading
572
SYSTEM_CURSOR_CROSSHAIR: int = 3 # Crosshair/precision
573
SYSTEM_CURSOR_WAITARROW: int = 4 # Arrow with hourglass
574
SYSTEM_CURSOR_SIZENWSE: int = 5 # Resize northwest-southeast
575
SYSTEM_CURSOR_SIZENESW: int = 6 # Resize northeast-southwest
576
SYSTEM_CURSOR_SIZEWE: int = 7 # Resize west-east
577
SYSTEM_CURSOR_SIZENS: int = 8 # Resize north-south
578
SYSTEM_CURSOR_SIZEALL: int = 9 # Move/resize all directions
579
SYSTEM_CURSOR_NO: int = 10 # Not allowed/prohibited
580
SYSTEM_CURSOR_HAND: int = 11 # Hand/pointing
581
582
# Default compilation characters
583
DEFAULT_BLACK: str = "X" # Black pixel character
584
DEFAULT_WHITE: str = "." # White pixel character
585
DEFAULT_XOR: str = "o" # XOR pixel character
586
```