Spaces:
Runtime error
Runtime error
import math | |
from typing import List, Literal, Tuple, Union | |
import navi | |
from nodes.base_input import BaseInput, InputConversion, InputKind | |
from ...utils.utils import round_half_up | |
def clampNumber( | |
value: Union[float, int], | |
precision: int, | |
min_value: Union[float, int, None], | |
max_value: Union[float, int, None], | |
) -> Union[float, int]: | |
# Convert proper number type | |
value = round_half_up(value) if precision == 0 else round(value, precision) | |
# Clamp to max and min, correcting for max/min not aligning with offset + n * step | |
if max_value is not None: | |
value = min(value, max_value) | |
if min_value is not None: | |
value = max(value, min_value) | |
# guarantee integers | |
if precision <= 0: | |
return int(value) | |
else: | |
return float(value) | |
def get_number_type( | |
min_value: Union[float, int, None], | |
max_value: Union[float, int, None], | |
precision: int, | |
) -> navi.ExpressionJson: | |
if precision > 0: | |
# step is not an integer | |
return navi.interval(min_value, max_value) | |
return navi.int_interval(min_value, max_value) | |
class NumberInput(BaseInput): | |
"""Input a number""" | |
def __init__( | |
self, | |
label: str, | |
precision: int = 0, | |
controls_step: Union[float, int, None] = None, | |
default: Union[float, int] = 0, | |
minimum: Union[float, int, None] = 0, | |
maximum: Union[float, int, None] = None, | |
unit: Union[str, None] = None, | |
note_expression: Union[str, None] = None, | |
kind: InputKind = "number", | |
hide_trailing_zeros: bool = True, | |
hide_label: bool = False, | |
): | |
super().__init__("number", label, kind=kind, has_handle=True) | |
self.precision = precision | |
# controls_step is for increment/decrement arrows. | |
self.controls_step: Union[float, int] = ( | |
controls_step if controls_step is not None else 10**-precision | |
) | |
self.default = default | |
self.minimum = minimum | |
self.maximum = maximum | |
self.unit = unit | |
self.note_expression = note_expression | |
self.hide_trailing_zeros = hide_trailing_zeros | |
self.hide_label = hide_label | |
self.associated_type = float if precision > 0 else int | |
self.input_type = get_number_type( | |
self.minimum, | |
self.maximum, | |
self.precision, | |
) | |
if self.precision == 0: | |
self.input_conversions = [InputConversion("number", "round(Input)")] | |
def toDict(self): | |
return { | |
**super().toDict(), | |
"min": self.minimum, | |
"max": self.maximum, | |
"noteExpression": self.note_expression, | |
"def": self.default, | |
"precision": self.precision, | |
"controlsStep": self.controls_step, | |
"unit": self.unit, | |
"hideTrailingZeros": self.hide_trailing_zeros, | |
"hideLabel": self.hide_label, | |
} | |
def make_optional(self): | |
raise ValueError("NumberInput and SliderInput cannot be made optional") | |
def enforce(self, value): | |
assert isinstance(value, (int, float)) | |
if math.isnan(value): | |
raise ValueError("NaN is not a valid number") | |
return clampNumber(value, self.precision, self.minimum, self.maximum) | |
class SliderInput(NumberInput): | |
"""Input for integer number via slider""" | |
def __init__( | |
self, | |
label: str, | |
precision: int = 0, | |
controls_step: Union[float, int, None] = None, | |
slider_step: Union[float, int, None] = None, | |
minimum: Union[float, int] = 0, | |
maximum: Union[float, int] = 100, | |
default: Union[float, int] = 50, | |
unit: Union[str, None] = None, | |
note_expression: Union[str, None] = None, | |
ends: Tuple[Union[str, None], Union[str, None]] = (None, None), | |
hide_trailing_zeros: bool = False, | |
gradient: Union[List[str], None] = None, | |
scale: Literal["linear", "log", "log-offset", "sqrt"] = "linear", | |
): | |
super().__init__( | |
label, | |
precision=precision, | |
controls_step=controls_step, | |
default=default, | |
minimum=minimum, | |
maximum=maximum, | |
unit=unit, | |
note_expression=note_expression, | |
kind="slider", | |
hide_trailing_zeros=hide_trailing_zeros, | |
) | |
self.ends = ends | |
self.slider_step = ( | |
slider_step | |
if slider_step is not None | |
else (controls_step if controls_step is not None else 10**-precision) | |
) | |
self.gradient = gradient | |
self.scale = scale | |
def toDict(self): | |
return { | |
**super().toDict(), | |
"ends": self.ends, | |
"sliderStep": self.slider_step, | |
"gradient": self.gradient, | |
"scale": self.scale, | |
} | |