CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pygame-ce

Python Game Development library providing comprehensive multimedia functionality for creating games and interactive applications.

Pending
Overview
Eval results
Files

cursor-management.mddocs/

Cursor Management

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.

Capabilities

Cursor Object

The Cursor class provides unified interface for all cursor types.

class Cursor:
    def __init__(self, *args):
        """
        Create cursor from various sources.
        
        Parameters:
            *args: Variable arguments depending on cursor type:
                - (constant,) for system cursors  
                - (size, hotspot, xormasks, andmasks) for bitmap cursors
                - (hotspot, surface) for color cursors
        """
    
    type: str  # "system", "bitmap", or "color"
    data: tuple  # Cursor-specific data
    
    def copy(self) -> Cursor:
        """
        Create copy of cursor.
        
        Returns:
            Cursor: New cursor object with same data
        """

System Cursor Management

Functions for setting and querying the current system cursor.

def set_cursor(*args) -> None:
    """
    Set the current mouse cursor.
    
    Parameters:
        *args: Cursor data in various formats:
            - (cursor_object,) - Set from Cursor object
            - (constant,) - Set system cursor by constant
            - (size, hotspot, xormasks, andmasks) - Set bitmap cursor
            - (hotspot, surface) - Set color cursor from surface
    """

def get_cursor() -> Cursor:
    """
    Get the current cursor.
    
    Returns:
        Cursor: Current cursor object
    """

Bitmap Cursor Compilation

Utilities for creating bitmap cursors from string representations.

def compile(
    strings: tuple[str, ...], 
    black: str = "X", 
    white: str = ".", 
    xor: str = "o"
) -> tuple[tuple[int, ...], tuple[int, ...]]:
    """
    Compile cursor from string representation.
    
    Parameters:
        strings: Tuple of strings representing cursor bitmap
        black: Character representing black pixels
        white: Character representing white pixels  
        xor: Character representing XOR pixels
    
    Returns:
        tuple[tuple[int, ...], tuple[int, ...]]: (xormasks, andmasks) bitmap data
    """

def load_xbm(cursor_file, mask_file) -> tuple:
    """
    Load cursor from XBM format files.
    
    Parameters:
        cursor_file: Path to cursor XBM file
        mask_file: Path to mask XBM file
    
    Returns:
        tuple: Cursor data suitable for Cursor creation
    """

Pre-defined System Cursors

Built-in cursor constants for common system cursors.

# System cursor constants
SYSTEM_CURSOR_ARROW: int           # Standard arrow cursor
SYSTEM_CURSOR_IBEAM: int           # Text input cursor  
SYSTEM_CURSOR_WAIT: int            # Wait/busy cursor
SYSTEM_CURSOR_CROSSHAIR: int       # Crosshair cursor
SYSTEM_CURSOR_WAITARROW: int       # Arrow with wait symbol
SYSTEM_CURSOR_SIZENWSE: int        # Resize NW-SE cursor
SYSTEM_CURSOR_SIZENESW: int        # Resize NE-SW cursor
SYSTEM_CURSOR_SIZEWE: int          # Resize W-E cursor
SYSTEM_CURSOR_SIZENS: int          # Resize N-S cursor
SYSTEM_CURSOR_SIZEALL: int         # Move/resize all directions
SYSTEM_CURSOR_NO: int              # Not allowed cursor
SYSTEM_CURSOR_HAND: int            # Hand/pointer cursor

Pre-compiled Cursors

Ready-to-use cursor objects for common cursor types.

# Pre-compiled cursor objects
arrow: Cursor        # Standard arrow cursor
diamond: Cursor      # Diamond-shaped cursor
ball: Cursor         # Ball/circle cursor
broken_x: Cursor     # Broken X cursor
tri_left: Cursor     # Left-pointing triangle
tri_right: Cursor    # Right-pointing triangle

Cursor String Templates

String templates for creating custom cursors with compile().

# String templates for cursor compilation
thickarrow_strings: tuple[str, ...]    # Thick arrow cursor
sizer_x_strings: tuple[str, ...]       # Horizontal resize cursor
sizer_y_strings: tuple[str, ...]       # Vertical resize cursor  
sizer_xy_strings: tuple[str, ...]      # Diagonal resize cursor
textmarker_strings: tuple[str, ...]    # Text marker cursor

Usage Examples

Basic Cursor Management

import pygame
import pygame.cursors

pygame.init()
screen = pygame.display.set_mode((800, 600))

# Set different system cursors
print("Changing to different system cursors...")

# Standard arrow (default)
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_ARROW)
pygame.time.wait(1000)

# Hand cursor for clickable elements
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_HAND)  
pygame.time.wait(1000)

# Text input cursor
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_IBEAM)
pygame.time.wait(1000)

# Wait cursor
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_WAIT)
pygame.time.wait(1000)

# Crosshair cursor
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_CROSSHAIR)
pygame.time.wait(1000)

# Get current cursor
current_cursor = pygame.cursors.get_cursor()
print(f"Current cursor type: {current_cursor.type}")

pygame.quit()

Pre-compiled Cursors

import pygame
import pygame.cursors

pygame.init()
screen = pygame.display.set_mode((800, 600))

# Use pre-compiled cursors
cursors_to_try = [
    ("Arrow", pygame.cursors.arrow),
    ("Diamond", pygame.cursors.diamond),
    ("Ball", pygame.cursors.ball),
    ("Broken X", pygame.cursors.broken_x),
    ("Triangle Left", pygame.cursors.tri_left),
    ("Triangle Right", pygame.cursors.tri_right),
]

for name, cursor in cursors_to_try:
    print(f"Setting cursor: {name}")
    pygame.cursors.set_cursor(cursor)
    pygame.time.wait(1500)

pygame.quit()

Custom Bitmap Cursor

import pygame
import pygame.cursors

pygame.init()
screen = pygame.display.set_mode((800, 600))

# Create custom cursor from string
custom_cursor_strings = (
    "     XX     ",
    "    X..X    ",
    "   X....X   ",
    "  X......X  ",
    " X........X ",
    "X..........X",
    " X........X ",
    "  X......X  ",
    "   X....X   ",
    "    X..X    ",
    "     XX     ",
)

# Compile the cursor
cursor_data = pygame.cursors.compile(
    custom_cursor_strings,
    black='X',    # Character for black pixels
    white='.',    # Character for white pixels
    xor='o'       # Character for XOR pixels (unused here)
)

# Create cursor object
size = (12, 11)  # Width x Height
hotspot = (6, 5)  # Center point
custom_cursor = pygame.cursors.Cursor(size, hotspot, cursor_data[0], cursor_data[1])

# Set the custom cursor
pygame.cursors.set_cursor(custom_cursor)

print("Custom cursor set! Move mouse to see it.")
pygame.time.wait(3000)

pygame.quit()

Color Cursor from Surface

import pygame
import pygame.cursors

pygame.init()
screen = pygame.display.set_mode((800, 600))

# Create a colorful cursor surface
cursor_size = (32, 32)
cursor_surface = pygame.Surface(cursor_size, pygame.SRCALPHA)

# Draw a colorful cursor
center = (cursor_size[0] // 2, cursor_size[1] // 2)

# Draw concentric circles
pygame.draw.circle(cursor_surface, (255, 0, 0, 200), center, 15)
pygame.draw.circle(cursor_surface, (0, 255, 0, 200), center, 10)
pygame.draw.circle(cursor_surface, (0, 0, 255, 200), center, 5)

# Add crosshair
pygame.draw.line(cursor_surface, (255, 255, 255), (center[0], 0), (center[0], cursor_size[1]), 2)
pygame.draw.line(cursor_surface, (255, 255, 255), (0, center[1]), (cursor_size[0], center[1]), 2)

# Create color cursor
hotspot = center  # Click point at center
color_cursor = pygame.cursors.Cursor(hotspot, cursor_surface)

# Set the color cursor
pygame.cursors.set_cursor(color_cursor)

print("Color cursor set! Move mouse to see the colorful cursor.")
pygame.time.wait(5000)

pygame.quit()

Context-Sensitive Cursors

import pygame
import pygame.cursors

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Context-Sensitive Cursors")

# Define areas with different cursors
button_rect = pygame.Rect(100, 100, 200, 100)
text_rect = pygame.Rect(400, 200, 300, 50)
resize_rect = pygame.Rect(650, 450, 100, 100)

# Cursor for different contexts
default_cursor = pygame.cursors.Cursor(pygame.cursors.SYSTEM_CURSOR_ARROW)
button_cursor = pygame.cursors.Cursor(pygame.cursors.SYSTEM_CURSOR_HAND)
text_cursor = pygame.cursors.Cursor(pygame.cursors.SYSTEM_CURSOR_IBEAM)
resize_cursor = pygame.cursors.Cursor(pygame.cursors.SYSTEM_CURSOR_SIZENWSE)

current_cursor = None
clock = pygame.time.Clock()
running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    
    # Get mouse position
    mouse_pos = pygame.mouse.get_pos()
    
    # Determine appropriate cursor based on mouse position
    new_cursor = default_cursor
    
    if button_rect.collidepoint(mouse_pos):
        new_cursor = button_cursor
    elif text_rect.collidepoint(mouse_pos):
        new_cursor = text_cursor
    elif resize_rect.collidepoint(mouse_pos):
        new_cursor = resize_cursor
    
    # Only change cursor if different
    if new_cursor != current_cursor:
        pygame.cursors.set_cursor(new_cursor)
        current_cursor = new_cursor
    
    # Draw interface elements
    screen.fill((240, 240, 240))
    
    # Draw button
    pygame.draw.rect(screen, (100, 150, 255), button_rect)
    pygame.draw.rect(screen, (0, 0, 0), button_rect, 2)
    font = pygame.font.Font(None, 36)
    text = font.render("Button", True, (255, 255, 255))
    text_pos = (button_rect.centerx - text.get_width()//2, 
                button_rect.centery - text.get_height()//2)
    screen.blit(text, text_pos)
    
    # Draw text area
    pygame.draw.rect(screen, (255, 255, 255), text_rect)
    pygame.draw.rect(screen, (0, 0, 0), text_rect, 2)
    text_label = font.render("Text Input Area", True, (0, 0, 0))
    screen.blit(text_label, (text_rect.x + 5, text_rect.y + 10))
    
    # Draw resize area
    pygame.draw.rect(screen, (255, 200, 100), resize_rect)
    pygame.draw.rect(screen, (0, 0, 0), resize_rect, 2)
    resize_text = font.render("Resize", True, (0, 0, 0))
    resize_pos = (resize_rect.centerx - resize_text.get_width()//2,
                  resize_rect.centery - resize_text.get_height()//2)
    screen.blit(resize_text, resize_pos)
    
    # Draw instructions
    instructions = [
        "Move mouse over different areas:",
        "• Button area - Hand cursor",
        "• Text area - I-beam cursor", 
        "• Resize area - Resize cursor",
        "• Other areas - Default arrow"
    ]
    
    small_font = pygame.font.Font(None, 24)
    y = 20
    for instruction in instructions:
        text_surface = small_font.render(instruction, True, (0, 0, 0))
        screen.blit(text_surface, (20, y))
        y += 25
    
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Advanced Cursor Animation

import pygame
import pygame.cursors
import math

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Animated Cursor")

class AnimatedCursor:
    def __init__(self, frames, frame_duration=100):
        self.frames = frames
        self.frame_duration = frame_duration
        self.current_frame = 0
        self.last_update = pygame.time.get_ticks()
    
    def update(self):
        now = pygame.time.get_ticks()
        if now - self.last_update > self.frame_duration:
            self.current_frame = (self.current_frame + 1) % len(self.frames)
            pygame.cursors.set_cursor(self.frames[self.current_frame])
            self.last_update = now

# Create spinning cursor frames
def create_spinning_cursor_frames(num_frames=8):
    frames = []
    cursor_size = (32, 32)
    center = (cursor_size[0] // 2, cursor_size[1] // 2)
    
    for i in range(num_frames):
        surface = pygame.Surface(cursor_size, pygame.SRCALPHA)
        angle = (360 / num_frames) * i
        
        # Draw rotating arrow
        length = 12
        angle_rad = math.radians(angle)
        end_x = center[0] + length * math.cos(angle_rad)  
        end_y = center[1] + length * math.sin(angle_rad)
        
        # Arrow shaft
        pygame.draw.line(surface, (255, 255, 255), center, (end_x, end_y), 3)
        
        # Arrow head
        head_angle1 = angle_rad + math.radians(150)
        head_angle2 = angle_rad - math.radians(150) 
        head_length = 8
        
        head1_x = end_x + head_length * math.cos(head_angle1)
        head1_y = end_y + head_length * math.sin(head_angle1)
        head2_x = end_x + head_length * math.cos(head_angle2)
        head2_y = end_y + head_length * math.sin(head_angle2)
        
        pygame.draw.line(surface, (255, 255, 255), (end_x, end_y), (head1_x, head1_y), 2)
        pygame.draw.line(surface, (255, 255, 255), (end_x, end_y), (head2_x, head2_y), 2)
        
        # Create cursor
        cursor = pygame.cursors.Cursor(center, surface)
        frames.append(cursor)
    
    return frames

# Create animated cursor
spinner_frames = create_spinning_cursor_frames(12)
animated_cursor = AnimatedCursor(spinner_frames, frame_duration=100)

clock = pygame.time.Clock()
running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                # Toggle between animated and normal cursor
                if hasattr(animated_cursor, 'active'):
                    animated_cursor.active = not animated_cursor.active
                    if not animated_cursor.active:
                        pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_ARROW)
                else:
                    animated_cursor.active = True
    
    # Update animated cursor
    if hasattr(animated_cursor, 'active') and animated_cursor.active:
        animated_cursor.update()
    
    # Draw instructions
    screen.fill((50, 50, 50))
    font = pygame.font.Font(None, 48)
    text1 = font.render("Animated Cursor Demo", True, (255, 255, 255))
    text2 = font.render("Press SPACE to toggle animation", True, (200, 200, 200))
    
    screen.blit(text1, (screen.get_width()//2 - text1.get_width()//2, 200))
    screen.blit(text2, (screen.get_width()//2 - text2.get_width()//2, 300))
    
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

XBM Cursor Loading

import pygame
import pygame.cursors
import tempfile
import os

pygame.init()
screen = pygame.display.set_mode((800, 600))

# Create sample XBM files for demonstration
cursor_xbm_data = """#define cursor_width 16
#define cursor_height 16
static unsigned char cursor_bits[] = {
   0x00, 0x00, 0x40, 0x02, 0x60, 0x06, 0x70, 0x0e, 0x78, 0x1e, 0x7c, 0x3e,
   0x7e, 0x7e, 0x7f, 0xfe, 0x7f, 0xfe, 0x7e, 0x7e, 0x6c, 0x36, 0x46, 0x62,
   0x06, 0x60, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00 };"""

mask_xbm_data = """#define mask_width 16
#define mask_height 16
static unsigned char mask_bits[] = {
   0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xef, 0xf7,
   0xcf, 0xf3, 0x07, 0xe0, 0x07, 0xe0, 0x03, 0xc0 };"""

# Write temporary XBM files
with tempfile.NamedTemporaryFile(mode='w', suffix='.xbm', delete=False) as cursor_file:
    cursor_file.write(cursor_xbm_data)
    cursor_filename = cursor_file.name

with tempfile.NamedTemporaryFile(mode='w', suffix='.xbm', delete=False) as mask_file:
    mask_file.write(mask_xbm_data)
    mask_filename = mask_file.name

try:
    # Load cursor from XBM files
    xbm_cursor_data = pygame.cursors.load_xbm(cursor_filename, mask_filename)
    
    # Create cursor object
    size = (16, 16)
    hotspot = (0, 0)
    xbm_cursor = pygame.cursors.Cursor(size, hotspot, xbm_cursor_data[0], xbm_cursor_data[1])
    
    # Set the XBM cursor
    pygame.cursors.set_cursor(xbm_cursor)
    
    print("XBM cursor loaded and set!")
    pygame.time.wait(3000)
    
except Exception as e:
    print(f"Error loading XBM cursor: {e}")

finally:
    # Clean up temporary files
    try:
        os.unlink(cursor_filename)
        os.unlink(mask_filename)
    except:
        pass

# Restore default cursor
pygame.cursors.set_cursor(pygame.cursors.SYSTEM_CURSOR_ARROW)

pygame.quit()

Constants

System cursor constants and cursor compilation characters:

# System cursor types
SYSTEM_CURSOR_ARROW: int = 0        # Standard arrow
SYSTEM_CURSOR_IBEAM: int = 1        # Text selection
SYSTEM_CURSOR_WAIT: int = 2         # Wait/loading
SYSTEM_CURSOR_CROSSHAIR: int = 3    # Crosshair/precision
SYSTEM_CURSOR_WAITARROW: int = 4    # Arrow with hourglass
SYSTEM_CURSOR_SIZENWSE: int = 5     # Resize northwest-southeast
SYSTEM_CURSOR_SIZENESW: int = 6     # Resize northeast-southwest  
SYSTEM_CURSOR_SIZEWE: int = 7       # Resize west-east
SYSTEM_CURSOR_SIZENS: int = 8       # Resize north-south
SYSTEM_CURSOR_SIZEALL: int = 9      # Move/resize all directions
SYSTEM_CURSOR_NO: int = 10          # Not allowed/prohibited
SYSTEM_CURSOR_HAND: int = 11        # Hand/pointing

# Default compilation characters
DEFAULT_BLACK: str = "X"            # Black pixel character
DEFAULT_WHITE: str = "."            # White pixel character  
DEFAULT_XOR: str = "o"              # XOR pixel character

Install with Tessl CLI

npx tessl i tessl/pypi-pygame-ce

docs

advanced-features.md

audio-system.md

core-system.md

cursor-management.md

display-graphics.md

event-handling.md

index.md

input-systems.md

math-operations.md

midi-support.md

sprites-game-objects.md

typing-support.md

tile.json