Source code for camtasia.timeline.clips.screen_recording

"""Screen recording clips (ScreenVMFile, ScreenIMFile)."""
from __future__ import annotations

from typing import Any

from .base import BaseClip


[docs] class ScreenVMFile(BaseClip): """Screen recording video clip. Inherits translation, scale, and other transform helpers from :class:`BaseClip`. Adds cursor effect properties. Args: data: The raw clip dict. """ # -- Cursor -- def _set_cursor_param(self, key: str, value: float, interp: str = 'linr') -> None: """Write a cursor parameter as a dict with interp (Camtasia's cursor format).""" params = self._data.setdefault('parameters', {}) if isinstance(params.get(key), dict): params[key]['defaultValue'] = value else: params[key] = {'type': 'double', 'defaultValue': value, 'interp': interp} @property def cursor_scale(self) -> float: """Cursor enlargement factor.""" return self._get_param_value('cursorScale', 1.0) @cursor_scale.setter def cursor_scale(self, value: float) -> None: """Set the cursor enlargement factor.""" self._set_cursor_param('cursorScale', value) @property def cursor_opacity(self) -> float: """Cursor opacity (0.0–1.0).""" return self._get_param_value('cursorOpacity', 1.0) @cursor_opacity.setter def cursor_opacity(self, value: float) -> None: """Set the cursor opacity (0.0–1.0).""" self._set_cursor_param('cursorOpacity', value) @property def cursor_track_level(self) -> float: """Cursor track level.""" return self._get_param_value('cursorTrackLevel') @property def smooth_cursor_across_edit_duration(self) -> float: """Smooth cursor across edit duration setting.""" return self._get_param_value('smoothCursorAcrossEditDuration') # -- Cursor effects helpers -- def _find_effect(self, name: str) -> dict[str, Any] | None: """Find an effect dict by name.""" for e in self.effects: if e.get('effectName') == name: return e return None def _get_effect_param(self, effect_name: str, param: str, default: float = 0.0) -> float: effect = self._find_effect(effect_name) if effect is None: return default p = effect.get('parameters', {}).get(param, default) if isinstance(p, dict): return float(p.get('defaultValue', default)) return float(p) @property def cursor_motion_blur_intensity(self) -> float: """CursorMotionBlur intensity.""" return self._get_effect_param('CursorMotionBlur', 'intensity') @property def cursor_shadow(self) -> dict[str, float]: """CursorShadow parameters.""" e = self._find_effect('CursorShadow') if e is None: return {} params = e.get('parameters', {}) return { k: (v.get('defaultValue', v) if isinstance(v, dict) else v) for k, v in params.items() } @property def cursor_physics(self) -> dict[str, float]: """CursorPhysics parameters (intensity, tilt).""" e = self._find_effect('CursorPhysics') if e is None: return {} params = e.get('parameters', {}) return { k: (v.get('defaultValue', v) if isinstance(v, dict) else v) for k, v in params.items() } @property def left_click_scaling(self) -> dict[str, float]: """LeftClickScaling parameters (scale, speed).""" e = self._find_effect('LeftClickScaling') if e is None: return {} params = e.get('parameters', {}) return { k: (v.get('defaultValue', v) if isinstance(v, dict) else v) for k, v in params.items() }
[docs] class ScreenIMFile(BaseClip): """Screen recording cursor overlay clip. Contains per-frame cursor position keyframes. Args: data: The raw clip dict. """ @property def cursor_image_path(self) -> str | None: """Cursor image path identifier.""" return self.parameters.get('cursorImagePath') @property def cursor_location_keyframes(self) -> list[dict[str, Any]]: """Cursor location keyframes. Returns: List of dicts with ``time``, ``endTime``, ``value``, ``duration`` keys. ``value`` is ``[x, y, z]``. """ loc = self.parameters.get('cursorLocation', {}) return loc.get('keyframes', []) # type: ignore[no-any-return]