111 lines
4.1 KiB
Python
Raw Normal View History

2025-03-07 08:03:18 +01:00
# SPDX-FileCopyrightText: © 2022-2023 Wojciech Trybus <wojtryb@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
from typing import List, TypeVar, Generic, Optional
from core_components import Controller, Instruction
from .raw_instructions import RawInstructions
T = TypeVar('T')
class TemporaryKey(RawInstructions, Generic[T]):
"""
Temporarily activate (long press) a value or toggle it (short press).
Action switches between two states: `low_value` and `high_value`.
- pressing a key ensures `high_state`
- releasing a key before `time_interval` toggles between states
- releasing a key after `time_interval` ensures `low_state`
### Arguments:
- `name` -- unique name of action. Must match the definition
in shortcut_composer.action file.
- `controller` -- defines which krita property will be modified.
- `high_value` -- value to switch to compatibile with controller.
- `low_value` -- (optional*) value to return to compatibile with
controller. If not given, taken from controller.
- `instructions` -- (optional) list of additional instructions to
perform on key press and release.
- `short_vs_long_press_time` -- (optional) time [s] that specifies
if key press is short or long.
*some controllers don't have a default value. Then providing it
becomes required.
### Action implementation example:
Example action is meant to toggle between opacity 100% and 50%.
Using `OpacityController` which is one of the available `controllers`
tells krita, that requested values relate to brush opacity.
Key press shorter than 0.3 seconds will toggle between 100% and 50%
brush opacity. Longer press will ensure 50%, which will go back to
100% on the key release.
```python
templates.TemporaryKey(
name="Change opacity between 100 and 50,
controller=controllers.OpacityController(),
high_value=50,
low_value=100,
instructions=[], # See "instructions" for more info
short_vs_long_press_time=0.3,
)
```
"""
def __init__(
self, *,
name: str,
controller: Controller[T],
high_value: T,
low_value: Optional[T] = None,
instructions: Optional[List[Instruction]] = None,
short_vs_long_press_time: Optional[float] = None
) -> None:
super().__init__(name, instructions, short_vs_long_press_time)
self._controller = controller
self._high_value = high_value
self._low_value = self._read_default_value(low_value)
self._was_high_before_press = False
def _set_low(self) -> None:
"""Defines how to switch to low state."""
self._controller.set_value(self._low_value)
def _set_high(self) -> None:
"""Defines how to switch to high state."""
self._controller.set_value(self._high_value)
def _is_high_state(self) -> bool:
"""Defines how to determine that current state is high."""
return self._controller.get_value() == self._high_value
def on_key_press(self) -> None:
"""Set high state only if state before press was low."""
self._controller.refresh()
super().on_key_press()
self._was_high_before_press = self._is_high_state()
if not self._was_high_before_press:
self._set_high()
def on_short_key_release(self) -> None:
"""Set low state only when going from high state."""
super().on_short_key_release()
if self._was_high_before_press:
self._set_low()
def on_long_key_release(self) -> None:
"""End of long press ensures low state."""
super().on_long_key_release()
self._set_low()
def _read_default_value(self, value: Optional[T]) -> T:
"""Read value from controller if it was not given."""
if (default := self._controller.DEFAULT_VALUE) is None:
raise ValueError(
f"{self._controller} can't be used with TemporaryKeys.")
return value if value is not None else default