feat(displays): expose DDC/CI contrast, input source, color preset, picture mode

Backend (routes/display.py, services/display_service.py):
- Probe DDC/CI capabilities per monitor at enumeration time
- New endpoints POST /api/display/{contrast,input_source,color_preset,picture_mode}/{id}
- Picture mode goes through raw VCP 0xDC since monitorcontrol has no
  high-level wrapper; labels follow MCCS spec with vendor-friendly fallbacks
- Each capability reports a *_supported flag so the UI can hide rows that
  the hardware does not advertise

Frontend (links.js, app.js, styles.css, locales):
- Monitor cards grow a contrast slider (same editorial copper treatment
  as brightness) and a "PICTURE TUNING" section beneath
- Picture tuning uses the IconSelect widget (matching the audio device
  selector): per-port icons (HDMI, DisplayPort, DVI, VGA, USB-C),
  thermometer for color temps, per-mode icons (movie reel, gamepad,
  ball, etc.) for picture modes
- Humanizers turn SHOUT_CASE enum names into readable labels
  (COLOR_TEMP_6500K -> "6500 K", HDMI1 -> "HDMI 1")
- 14 new i18n keys per locale (en/ru)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 14:28:04 +03:00
parent 0d07f7f1f4
commit 57fdeb70fb
7 changed files with 853 additions and 43 deletions
+13
View File
@@ -161,6 +161,19 @@
"display.power_on": "Включить",
"display.power_off": "Выключить",
"display.primary": "Основной",
"display.brightness": "Яркость",
"display.contrast": "Контраст",
"display.tuning": "Настройка изображения",
"display.input_source": "Вход",
"display.color_preset": "Цветовая температура",
"display.picture_mode": "Режим изображения",
"display.msg.contrast_failed": "Не удалось установить контраст",
"display.msg.input_changed": "Источник входа переключён",
"display.msg.input_failed": "Не удалось переключить источник",
"display.msg.color_changed": "Цветовая температура применена",
"display.msg.color_failed": "Не удалось применить цветовую температуру",
"display.msg.mode_changed": "Режим изображения применён",
"display.msg.mode_failed": "Не удалось применить режим изображения",
"browser.title": "Медиа Браузер",
"browser.home": "Главная",
"browser.manage_folders": "Управление папками",