CSS: add led_count field; calibration dialog improvements; color corrections collapsible section

- Add explicit led_count to PictureColorStripSource (0 = auto from calibration)
- Stream pads with black or truncates to match led_count exactly
- Calibration dialog: show led_count input above visual editor in CSS mode
- Calibration dialog: pre-populate led_count with effective count (cal sum) when stored value is 0
- Calibration dialog: sync preview label live as led_count input changes
- CSS editor: group brightness/saturation/gamma into collapsible "Color Corrections" section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 16:42:32 +03:00
parent 7de3546b14
commit a3aeafef13
14 changed files with 173 additions and 47 deletions

View File

@@ -20,7 +20,6 @@ from wled_controller.core.capture.calibration import (
CalibrationConfig,
calibration_from_dict,
calibration_to_dict,
create_default_calibration,
)
@@ -53,6 +52,7 @@ class ColorStripSource:
"smoothing": None,
"interpolation_mode": None,
"calibration": None,
"led_count": None,
}
@staticmethod
@@ -82,7 +82,7 @@ class ColorStripSource:
calibration = (
calibration_from_dict(calibration_data)
if calibration_data
else create_default_calibration(0)
else CalibrationConfig(layout="clockwise", start_position="bottom_left")
)
# Only "picture" type for now; extend with elif branches for future types
@@ -97,6 +97,7 @@ class ColorStripSource:
smoothing=data["smoothing"] if data.get("smoothing") is not None else 0.3,
interpolation_mode=data.get("interpolation_mode") or "average",
calibration=calibration,
led_count=data.get("led_count") or 0,
)
@@ -115,7 +116,10 @@ class PictureColorStripSource(ColorStripSource):
gamma: float = 1.0 # 1.0 = no correction; <1 = brighter, >1 = darker mids
smoothing: float = 0.3 # temporal smoothing (0.0 = none, 1.0 = full)
interpolation_mode: str = "average" # "average" | "median" | "dominant"
calibration: CalibrationConfig = field(default_factory=lambda: create_default_calibration(0))
calibration: CalibrationConfig = field(
default_factory=lambda: CalibrationConfig(layout="clockwise", start_position="bottom_left")
)
led_count: int = 0 # explicit LED count; 0 = auto (derived from calibration)
def to_dict(self) -> dict:
d = super().to_dict()
@@ -127,4 +131,5 @@ class PictureColorStripSource(ColorStripSource):
d["smoothing"] = self.smoothing
d["interpolation_mode"] = self.interpolation_mode
d["calibration"] = calibration_to_dict(self.calibration)
d["led_count"] = self.led_count
return d

View File

@@ -6,7 +6,7 @@ from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional
from wled_controller.core.capture.calibration import calibration_to_dict
from wled_controller.core.capture.calibration import CalibrationConfig, calibration_to_dict
from wled_controller.storage.color_strip_source import (
ColorStripSource,
PictureColorStripSource,
@@ -98,6 +98,7 @@ class ColorStripStore:
smoothing: float = 0.3,
interpolation_mode: str = "average",
calibration=None,
led_count: int = 0,
description: Optional[str] = None,
) -> ColorStripSource:
"""Create a new color strip source.
@@ -105,8 +106,6 @@ class ColorStripStore:
Raises:
ValueError: If validation fails
"""
from wled_controller.core.capture.calibration import create_default_calibration
if not name or not name.strip():
raise ValueError("Name is required")
@@ -115,7 +114,7 @@ class ColorStripStore:
raise ValueError(f"Color strip source with name '{name}' already exists")
if calibration is None:
calibration = create_default_calibration(0)
calibration = CalibrationConfig(layout="clockwise", start_position="bottom_left")
source_id = f"css_{uuid.uuid4().hex[:8]}"
now = datetime.utcnow()
@@ -135,6 +134,7 @@ class ColorStripStore:
smoothing=smoothing,
interpolation_mode=interpolation_mode,
calibration=calibration,
led_count=led_count,
)
self._sources[source_id] = source
@@ -155,6 +155,7 @@ class ColorStripStore:
smoothing: Optional[float] = None,
interpolation_mode: Optional[str] = None,
calibration=None,
led_count: Optional[int] = None,
description: Optional[str] = None,
) -> ColorStripSource:
"""Update an existing color strip source.
@@ -193,6 +194,8 @@ class ColorStripStore:
source.interpolation_mode = interpolation_mode
if calibration is not None:
source.calibration = calibration
if led_count is not None:
source.led_count = led_count
source.updated_at = datetime.utcnow()
self._save()