Skip to content

Registries

This document details the core registries used in Macro Studio for handling type conversions and data captures. These systems are designed to be extensible, allowing developers to add support for new data types and capture methods.

Type Handler Overview

The GlobalTypeHandler is a static class that provides a centralized system for converting objects to and from human-readable strings. It also manages user-friendly display names for different types. This is crucial for the UI, where variables and action parameters need to be displayed and edited as text.

Key Concepts

  • Formatter: A function that takes an object and returns its string representation.
  • Parser: A function that takes a string and converts it back into an object of a specific type.
  • Display Name: A user-friendly name for a type (e.g., "Region" for QRect).

Core Methods

register(target_type, formatter, parser, display_name)

Registers a new type or updates an existing one with custom handlers.

  • target_type: The class you are supporting (e.g., QRect).
  • formatter: A function that converts an instance of target_type into a string.
  • parser: A function that converts a string back into an instance of target_type.
  • display_name: A pretty name to display the type as (e.g., "Region").

toString(obj)

Converts any object to a string using the best registered formatter. It prioritizes exact type matches, then checks for base types, and finally falls back to str(obj).

fromString(target_type, val_str)

Converts a string to an instance of the target_type using a registered parser. If no custom parser is found, it attempts to call the type's constructor with the string (e.g., int("123")).

getDisplayName(target_type)

Returns the friendly name for a type if registered; otherwise, it defaults to the class name.

Example: Registering a Custom Type

You can easily add support for new types using the @register_handler decorator. This decorator automatically finds toString, fromString, and display_name in your handler class.

Python
from PySide6.QtCore import QSize
from macro_studio import register_handler

@register_handler(QSize)
class QSizeHandler:
    """Handler for converting QSize objects."""
    display_name = "Size"

    @staticmethod
    def toString(obj: QSize) -> str:
        return f"{obj.width()}, {obj.height()}"

    @staticmethod
    def fromString(text: str) -> QSize:
        parts = [p.strip() for p in text.split(',') if p.strip()]
        if len(parts) != 2:
            raise ValueError("QSize requires 2 integers (width, height).")
        vals = [int(p) for p in parts]
        return QSize(vals[0], vals[1])

Type Handler API Reference

macro_studio.GlobalTypeHandler

A static class for managing type formatters, parsers, and display names.

This registry allows for the registration of custom functions to convert objects to and from strings, and to provide user-friendly names for types.

Functions

register classmethod

Python
register(target_type: Type, formatter: Callable[[Any], str] = None, parser: Callable[[str], Any] = None, display_name: str = None)

Registers a new type or updates an existing one with custom handlers.

Parameters:

Name Type Description Default
target_type Type

The class to register (e.g., QRect).

required
formatter Callable[[Any], str]

A function that converts an instance of target_type into a string.

None
parser Callable[[str], Any]

A function that converts a string back into an instance of target_type.

None
display_name str

A user-friendly name for the type (e.g., "Region").

None

toString classmethod

Python
toString(obj: Any) -> str

Converts an object to a string using the best available registered formatter.

The method first attempts an exact type match, then checks for base types, and finally falls back to checking for subclass relationships. If no registered formatter is found, it defaults to str(obj).

Parameters:

Name Type Description Default
obj Any

The object to convert to a string.

required

Returns:

Type Description
str

A string representation of the object.

fromString classmethod

Python
fromString(target_type: Type, val_str: str) -> Any

Converts a string to an instance of the target type using a registered parser.

If a custom parser is registered for the target_type, it will be used. Otherwise, it falls back to calling the target_type's constructor with the string.

Parameters:

Name Type Description Default
target_type Type

The desired type of the output object.

required
val_str str

The string to parse.

required

Returns:

Type Description
Any

An instance of target_type.

Raises:

Type Description
ValueError / TypeError

If parsing fails, either in the custom parser or the default constructor.

getDisplayName classmethod

Python
getDisplayName(target_type: Type) -> str

Gets the user-friendly display name for a given type.

Parameters:

Name Type Description Default
target_type Type

The type to look up.

required

Returns:

Type Description
str

The registered display name, or a capitalized version of the

str

class name as a fallback.

getTypeClass classmethod

Python
getTypeClass(type_name: str) -> Type

Retrieves the class object for a given type name string.

Parameters:

Name Type Description Default
type_name str

The name of the type (e.g., "QRect", "int").

required

Returns:

Type Description
Type

The class object if found, otherwise defaults to str.

setIfEvals classmethod

Python
setIfEvals(key: Any, value: Any, to_dict: dict, strict_eval: bool = False)

Conditionally sets a key-value pair in a dictionary.

The value is added to the dictionary only if it evaluates to True. In strict_eval mode, it is only added if it is not None.

Parameters:

Name Type Description Default
key Any

The key to use in the dictionary.

required
value Any

The value to potentially set.

required
to_dict dict

The dictionary to modify.

required
strict_eval bool

If True, only adds the value if it is not None. If False, adds the value if bool(value) is True.

False

getRegisteredTypes classmethod

Python
getRegisteredTypes() -> list[Type]

Returns a list of all registered types.

Returns:

Type Description
list[Type]

A list containing all type classes that have been registered.


Capture Registry Overview

The GlobalCaptureRegistry is a static class that manages different "capture modes." A capture mode defines how the user interacts with the screen overlay to capture a specific piece of data, such as a point, a rectangular region, or a color.

Key Concepts

  • Mode: A unique identifier for the capture type, usually a CaptureMode enum member.
  • Capture Method: The function that is executed to perform the capture. This function typically interacts with the screen overlay.
  • Type Class: The Python type of the data that will be captured (e.g., QPoint, QRect).

Core Methods

register(mode, tooltip, capture_method, type_class)

Registers a new capture mode definition.

  • mode: The CaptureMode enum member or other hashable key for this capture type.
  • tooltip: A helpful tip displayed to the user during the capture process.
  • capture_method: The function that will be called to perform the capture. It receives the overlay instance and the variable configuration.
  • type_class: The Python type that the captured data will be an instance of (e.g., QPoint).

get(mode)

Retrieves the full CaptureTypeDef for a given mode.

getModeFromType(type_class)

Performs a reverse lookup to find the capture mode associated with a specific Python type.

Default Capture Modes

Macro Studio pre-registers handlers for common types:

  • CaptureMode.POINT: Captures a QPoint.
  • CaptureMode.REGION: Captures a QRect.
  • CaptureMode.COLOR: Captures a QColor.

All default modes use a generic capture method (captureOverlayGeneric) that works with the screen overlay system.

Examples: Adding Custom Capture Modes

1. Registering via Enum (Implicit Type)

This approach is ideal when managing multiple custom types. By mapping the Enum value to a class, the registry automatically identifies the data type. This makes it easy to reference specific capture modes when programmatically creating variables or UI components.

Python
from enum import Enum
from macro_studio import GlobalCaptureRegistry

class MyCircle:
    """Custom data class for storing circle coordinates."""
    def __init__(self, x=0, y=0, radius=0):
        self.x = x
        self.y = y
        self.radius = radius

class CustomCaptureMode(Enum):
    # The registry will automatically infer MyCircle as the type_class
    CIRCLE = MyCircle 

def captureCircleFromOverlay(overlay, config):
    """Custom capture method triggered by the UI."""
    circle_data = MyCircle(10, 10, 50) # Example hardcoded data
    # ... logic to have the user draw a circle ...
    return circle_data

# Register the new mode using the Enum
GlobalCaptureRegistry.register(
    mode=CustomCaptureMode.CIRCLE,
    tooltip="Click and drag to define a circle",
    capture_method=captureCircleFromOverlay
)

2. Registering via Hashable String (Explicit Type)

Since mode accepts a Hashable object, developers do not actually need to create an Enum. They can simply pass a string as the mode identifier, but they must explicitly provide the type_class argument to avoid triggering a ValueError.

Python
from macro_studio import GlobalCaptureRegistry

class MyPolygon:
    """Custom data class for storing polygon vertices."""
    pass

def capturePolygonFromOverlay(overlay, config):
    polygon_data = MyPolygon()
    # ... logic to click points on the screen ...
    return polygon_data

# Register the new mode using a string identifier and explicit type_class
GlobalCaptureRegistry.register(
    mode="custom_polygon_capture",
    tooltip="Click screen points to draw a polygon",
    capture_method=capturePolygonFromOverlay,
    type_class=MyPolygon
)

Capture Registry API Reference

macro_studio.GlobalCaptureRegistry

A static class that serves as a global registry for capture modes.

This registry maps capture modes (which can be CaptureMode enums or other hashable types) to a CaptureTypeDef definition. It also provides reverse lookups from Python types to their associated capture modes.

Functions

register classmethod

Python
register(mode: PotentialMode, tooltip: str, capture_method: Callable[[TransparentOverlay, VariableConfig], None], type_class: type | None = None)

Registers a new capture mode definition.

If the type_class is not provided, this method will attempt to infer it from the mode enum's value, if applicable.

Parameters:

Name Type Description Default
mode PotentialMode

The capture mode to register.

required
tooltip str

A string providing guidance to the user during capture.

required
capture_method Callable[[TransparentOverlay, VariableConfig], None]

The function called to perform the capture.

required
type_class type | None

The Python type associated with this capture mode.

None

Raises:

Type Description
ValueError

If type_class cannot be inferred from the provided mode.

get classmethod

Python
get(mode: PotentialMode) -> CaptureTypeDef | None

Retrieves the definition for a given capture mode.

Parameters:

Name Type Description Default
mode PotentialMode

The capture mode to look up.

required

Returns:

Type Description
CaptureTypeDef | None

The CaptureTypeDef for the specified mode, or None if not found.

getDefinitions classmethod

Python
getDefinitions() -> dict[PotentialMode, CaptureTypeDef]

Returns all registered capture mode definitions.

Returns:

Type Description
dict[PotentialMode, CaptureTypeDef]

A dictionary mapping all registered modes to their definitions.

getModeFromType classmethod

Python
getModeFromType(type_class: type) -> PotentialMode | None

Finds the capture mode associated with a specific Python type.

Parameters:

Name Type Description Default
type_class type

The Python type to look up (e.g., QPoint, QRect).

required

Returns:

Type Description
PotentialMode | None

The associated capture mode, or None if no mode is registered for the type.

containsMode classmethod

Python
containsMode(mode: PotentialMode) -> bool

Checks if a specific capture mode is registered.

Parameters:

Name Type Description Default
mode PotentialMode

The capture mode to check.

required

Returns:

Type Description
bool

True if the mode is registered, False otherwise.

containsType classmethod

Python
containsType(type_class: type) -> bool

Checks if a capture mode is registered for a specific Python type.

Parameters:

Name Type Description Default
type_class type

The Python type to check.

required

Returns:

Type Description
bool

True if a mode is associated with the type, False otherwise.