Fixes
This commit is contained in:
parent
1a7f29b363
commit
a430110f94
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -321,6 +321,7 @@ bool KnxWorker::getGroupObjectInfo(size_t index, KnxGroupObjectInfo& info) {
|
||||
info.commFlag = go.commFlag();
|
||||
info.readFlag = go.readEnable();
|
||||
info.writeFlag = go.writeEnable();
|
||||
info.transmitFlag = go.transmitEnable();
|
||||
|
||||
// Resolve the primary group address via association/address tables
|
||||
info.groupAddress = resolveGroupAddress(static_cast<uint16_t>(index));
|
||||
@ -333,6 +334,47 @@ bool KnxWorker::getGroupObjectInfo(size_t index, KnxGroupObjectInfo& info) {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool KnxWorker::sendSwitch(uint16_t groupAddr, bool value) {
|
||||
#if !UART_DEBUG_MODE
|
||||
if (!knxBau.configured()) {
|
||||
ESP_LOGW(TAG, "sendSwitch: KNX not configured");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the GroupObject index for this group address
|
||||
size_t goCount = getGroupObjectCount();
|
||||
for (size_t i = 1; i <= goCount; i++) {
|
||||
uint16_t addr = resolveGroupAddress(static_cast<uint16_t>(i));
|
||||
if (addr == groupAddr) {
|
||||
GroupObject& go = knx.getGroupObject(i);
|
||||
|
||||
// Check if this GO can transmit
|
||||
if (!go.transmitEnable()) {
|
||||
ESP_LOGW(TAG, "sendSwitch: GO %d cannot transmit", (int)i);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set value and trigger send
|
||||
KNXValue knxVal = value;
|
||||
if (go.value(knxVal, DPT_Switch)) {
|
||||
ESP_LOGI(TAG, "sendSwitch: GA=%d GO=%d value=%d", groupAddr, (int)i, value);
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "sendSwitch: Failed to set value for GO %d", (int)i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "sendSwitch: No GO found for GA=%d", groupAddr);
|
||||
return false;
|
||||
#else
|
||||
(void)groupAddr;
|
||||
(void)value;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void KnxWorker::formatGroupAddress(uint16_t addr, char* buf, size_t bufSize) {
|
||||
// Format: main/middle/sub (5/3/8 bit)
|
||||
uint8_t main = (addr >> 11) & 0x1F;
|
||||
|
||||
@ -11,7 +11,8 @@ struct KnxGroupObjectInfo {
|
||||
uint8_t dptSub; // DPT Subtyp
|
||||
bool commFlag; // Kommunikations-Flag
|
||||
bool readFlag; // Lese-Flag
|
||||
bool writeFlag; // Schreib-Flag
|
||||
bool writeFlag; // Schreib-Flag (empfangen vom Bus)
|
||||
bool transmitFlag; // Sende-Flag (senden auf den Bus)
|
||||
};
|
||||
|
||||
class KnxWorker {
|
||||
@ -28,6 +29,9 @@ public:
|
||||
size_t getGroupObjectCount();
|
||||
bool getGroupObjectInfo(size_t index, KnxGroupObjectInfo& info);
|
||||
|
||||
// KNX Telegramm senden
|
||||
bool sendSwitch(uint16_t groupAddr, bool value);
|
||||
|
||||
// Gruppenadresse als String formatieren (z.B. "1/2/3")
|
||||
static void formatGroupAddress(uint16_t addr, char* buf, size_t bufSize);
|
||||
|
||||
|
||||
@ -119,10 +119,14 @@ void WidgetConfig::serialize(uint8_t* buf) const {
|
||||
buf[pos++] = cardStyle;
|
||||
for (size_t i = 0; i < MAX_SUBBUTTONS; ++i) {
|
||||
const SubButtonConfig& sb = subButtons[i];
|
||||
buf[pos++] = sb.iconCodepoint & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepoint >> 8) & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepoint >> 16) & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepoint >> 24) & 0xFF;
|
||||
buf[pos++] = sb.iconCodepointOff & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepointOff >> 8) & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepointOff >> 16) & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepointOff >> 24) & 0xFF;
|
||||
buf[pos++] = sb.iconCodepointOn & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepointOn >> 8) & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepointOn >> 16) & 0xFF;
|
||||
buf[pos++] = (sb.iconCodepointOn >> 24) & 0xFF;
|
||||
buf[pos++] = sb.knxAddrRead & 0xFF;
|
||||
buf[pos++] = (sb.knxAddrRead >> 8) & 0xFF;
|
||||
buf[pos++] = sb.knxAddrWrite & 0xFF;
|
||||
@ -303,8 +307,11 @@ void WidgetConfig::deserialize(const uint8_t* buf) {
|
||||
|
||||
for (size_t i = 0; i < MAX_SUBBUTTONS; ++i) {
|
||||
SubButtonConfig& sb = subButtons[i];
|
||||
if (pos + 20 <= SERIALIZED_SIZE) {
|
||||
sb.iconCodepoint = buf[pos] | (buf[pos + 1] << 8) |
|
||||
if (pos + 24 <= SERIALIZED_SIZE) {
|
||||
sb.iconCodepointOff = buf[pos] | (buf[pos + 1] << 8) |
|
||||
(buf[pos + 2] << 16) | (buf[pos + 3] << 24);
|
||||
pos += 4;
|
||||
sb.iconCodepointOn = buf[pos] | (buf[pos + 1] << 8) |
|
||||
(buf[pos + 2] << 16) | (buf[pos + 3] << 24);
|
||||
pos += 4;
|
||||
sb.knxAddrRead = buf[pos] | (buf[pos + 1] << 8); pos += 2;
|
||||
|
||||
@ -169,9 +169,10 @@ enum class SubButtonAction : uint8_t {
|
||||
NAVIGATE = 1, // Navigate to screen
|
||||
};
|
||||
|
||||
// Sub-button configuration for RoomCard (20 bytes)
|
||||
// Sub-button configuration for RoomCard (24 bytes)
|
||||
struct SubButtonConfig {
|
||||
uint32_t iconCodepoint; // 4 bytes - Icon codepoint
|
||||
uint32_t iconCodepointOff; // 4 bytes - Icon codepoint when OFF
|
||||
uint32_t iconCodepointOn; // 4 bytes - Icon codepoint when ON (0 = use iconCodepointOff)
|
||||
uint16_t knxAddrRead; // 2 bytes - KNX address to read status
|
||||
uint16_t knxAddrWrite; // 2 bytes - KNX address to write on click
|
||||
Color colorOn; // 3 bytes - Color when ON
|
||||
@ -181,7 +182,7 @@ struct SubButtonConfig {
|
||||
uint8_t targetScreen; // 1 byte - Target screen for navigate
|
||||
bool enabled; // 1 byte - Is this sub-button active?
|
||||
uint8_t _padding[2]; // 2 bytes - Alignment padding
|
||||
// Total: 20 bytes per SubButton
|
||||
// Total: 24 bytes per SubButton
|
||||
};
|
||||
|
||||
// Text line configuration for RoomCard (24 bytes)
|
||||
@ -296,8 +297,8 @@ struct WidgetConfig {
|
||||
uint8_t arcValueFontSize; // Center value font size index
|
||||
|
||||
// Serialization size (fixed for NVS storage)
|
||||
// 331 + 14 (arcMin + arcMax + arcUnit + arcShowValue + arcScaleOffset + arcScaleColor + arcValueColor + arcValueFontSize) = 345
|
||||
static constexpr size_t SERIALIZED_SIZE = 345;
|
||||
// 345 + 24 (6 subbuttons * 4 bytes for iconCodepointOn) = 369
|
||||
static constexpr size_t SERIALIZED_SIZE = 369;
|
||||
|
||||
void serialize(uint8_t* buf) const;
|
||||
void deserialize(const uint8_t* buf);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "widgets/RoomCardTileWidget.hpp"
|
||||
#include "HistoryStore.hpp"
|
||||
#include "SdCard.hpp"
|
||||
#include "Gui.hpp"
|
||||
#include "esp_lv_adapter.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
@ -604,13 +605,31 @@ void WidgetManager::handleButtonAction(const WidgetConfig& cfg, lv_obj_t* target
|
||||
case ButtonAction::KNX:
|
||||
default: {
|
||||
if (cfg.knxAddressWrite > 0) {
|
||||
bool state = false;
|
||||
bool currentState = false;
|
||||
if (target) {
|
||||
state = (lv_obj_get_state(target) & LV_STATE_CHECKED) != 0;
|
||||
currentState = (lv_obj_get_state(target) & LV_STATE_CHECKED) != 0;
|
||||
}
|
||||
|
||||
// For toggle buttons: send the opposite of current state
|
||||
// For non-toggle buttons: send ON (true)
|
||||
bool sendValue = cfg.isToggle ? !currentState : true;
|
||||
|
||||
ESP_LOGI(TAG, "Button %d clicked, KNX write to %d, value=%d (toggle=%d, currentState=%d)",
|
||||
cfg.id, cfg.knxAddressWrite, sendValue, cfg.isToggle, currentState);
|
||||
|
||||
// Send KNX telegram
|
||||
if (Gui::knxWorker.sendSwitch(cfg.knxAddressWrite, sendValue)) {
|
||||
// Update local UI state immediately for responsive feedback
|
||||
if (cfg.isToggle && target) {
|
||||
if (sendValue) {
|
||||
lv_obj_add_state(target, LV_STATE_CHECKED);
|
||||
} else {
|
||||
lv_obj_clear_state(target, LV_STATE_CHECKED);
|
||||
}
|
||||
}
|
||||
// Also update the cache
|
||||
cacheKnxSwitch(cfg.knxAddressWrite, sendValue);
|
||||
}
|
||||
ESP_LOGI(TAG, "Button %d clicked, KNX write to %d, state=%d",
|
||||
cfg.id, cfg.knxAddressWrite, state);
|
||||
// TODO: Send KNX telegram
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -680,10 +699,13 @@ void WidgetManager::navigateBack() {
|
||||
|
||||
void WidgetManager::sendKnxSwitch(uint16_t groupAddr, bool value) {
|
||||
ESP_LOGI(TAG, "sendKnxSwitch: GA=%d, value=%d", groupAddr, value);
|
||||
// TODO: Send actual KNX telegram via KnxWorker
|
||||
// For now, just log and update cache so UI reflects the change
|
||||
|
||||
// Send actual KNX telegram via KnxWorker
|
||||
if (Gui::knxWorker.sendSwitch(groupAddr, value)) {
|
||||
// Update cache so UI reflects the change
|
||||
cacheKnxSwitch(groupAddr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void WidgetManager::enterStandby() {
|
||||
if (!config_->standbyEnabled || config_->standbyMinutes == 0) return;
|
||||
@ -1693,7 +1715,8 @@ void WidgetManager::getConfigJson(char* buf, size_t bufSize) const {
|
||||
|
||||
cJSON* sbJson = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(sbJson, "pos", static_cast<int>(sb.position));
|
||||
cJSON_AddNumberToObject(sbJson, "icon", sb.iconCodepoint);
|
||||
cJSON_AddNumberToObject(sbJson, "iconOff", sb.iconCodepointOff);
|
||||
cJSON_AddNumberToObject(sbJson, "iconOn", sb.iconCodepointOn);
|
||||
cJSON_AddNumberToObject(sbJson, "knxRead", sb.knxAddrRead);
|
||||
cJSON_AddNumberToObject(sbJson, "knxWrite", sb.knxAddrWrite);
|
||||
cJSON_AddNumberToObject(sbJson, "action", static_cast<int>(sb.action));
|
||||
@ -2035,9 +2058,10 @@ bool WidgetManager::updateConfigFromJson(const char* json) {
|
||||
cond.style.flags |= ConditionStyle::FLAG_USE_TEXT_COLOR;
|
||||
}
|
||||
|
||||
// Background color
|
||||
// Background color (only if not empty and starts with #)
|
||||
cJSON* bgColor = cJSON_GetObjectItem(condItem, "bgColor");
|
||||
if (cJSON_IsString(bgColor)) {
|
||||
if (cJSON_IsString(bgColor) && bgColor->valuestring &&
|
||||
bgColor->valuestring[0] == '#' && strlen(bgColor->valuestring) >= 4) {
|
||||
cond.style.bgColor = Color::fromHex(parseHexColor(bgColor->valuestring));
|
||||
cond.style.flags |= ConditionStyle::FLAG_USE_BG_COLOR;
|
||||
}
|
||||
@ -2139,9 +2163,20 @@ bool WidgetManager::updateConfigFromJson(const char* json) {
|
||||
sb.position = static_cast<SubButtonPosition>(pos->valueint);
|
||||
}
|
||||
|
||||
cJSON* iconOff = cJSON_GetObjectItem(sbItem, "iconOff");
|
||||
if (cJSON_IsNumber(iconOff)) {
|
||||
sb.iconCodepointOff = static_cast<uint32_t>(iconOff->valuedouble);
|
||||
} else {
|
||||
// Backward compatibility: try old "icon" field
|
||||
cJSON* icon = cJSON_GetObjectItem(sbItem, "icon");
|
||||
if (cJSON_IsNumber(icon)) {
|
||||
sb.iconCodepoint = static_cast<uint32_t>(icon->valuedouble);
|
||||
sb.iconCodepointOff = static_cast<uint32_t>(icon->valuedouble);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON* iconOn = cJSON_GetObjectItem(sbItem, "iconOn");
|
||||
if (cJSON_IsNumber(iconOn)) {
|
||||
sb.iconCodepointOn = static_cast<uint32_t>(iconOn->valuedouble);
|
||||
}
|
||||
|
||||
cJSON* knxRead = cJSON_GetObjectItem(sbItem, "knxRead");
|
||||
|
||||
@ -24,7 +24,7 @@ esp_err_t WebServer::getKnxAddressesHandler(httpd_req_t* req) {
|
||||
cJSON_AddStringToObject(obj, "addrStr", addrStr);
|
||||
cJSON_AddBoolToObject(obj, "comm", info.commFlag);
|
||||
cJSON_AddBoolToObject(obj, "read", info.readFlag);
|
||||
cJSON_AddBoolToObject(obj, "write", info.writeFlag);
|
||||
cJSON_AddBoolToObject(obj, "write", info.transmitFlag); // transmit = kann auf Bus schreiben
|
||||
cJSON_AddItemToArray(arr, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,7 +235,9 @@ void ButtonWidget::applyStyle() {
|
||||
lv_obj_set_style_text_color(iconLabel_, lv_color_make(
|
||||
config_.textColor.r, config_.textColor.g, config_.textColor.b), 0);
|
||||
|
||||
uint8_t sizeIdx = config_.iconSize < 6 ? config_.iconSize : config_.fontSize;
|
||||
// Icon fonts support sizes 0-13 (14px to 260px)
|
||||
uint8_t sizeIdx = config_.iconSize;
|
||||
if (sizeIdx > 13) sizeIdx = 13;
|
||||
lv_obj_set_style_text_font(iconLabel_, Fonts::iconFont(sizeIdx), 0);
|
||||
}
|
||||
}
|
||||
@ -336,10 +338,16 @@ bool ButtonWidget::evaluateConditions(float primaryValue, float secondaryValue,
|
||||
}
|
||||
|
||||
if (bestMatch->style.flags & ConditionStyle::FLAG_USE_BG_COLOR) {
|
||||
lv_obj_set_style_bg_color(obj_, lv_color_make(
|
||||
lv_color_t bgColor = lv_color_make(
|
||||
bestMatch->style.bgColor.r,
|
||||
bestMatch->style.bgColor.g,
|
||||
bestMatch->style.bgColor.b), 0);
|
||||
bestMatch->style.bgColor.b);
|
||||
// Set for default state
|
||||
lv_obj_set_style_bg_color(obj_, bgColor, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
// Also set for checked state (toggle buttons)
|
||||
lv_obj_set_style_bg_color(obj_, bgColor, LV_PART_MAIN | LV_STATE_CHECKED);
|
||||
// And for pressed state
|
||||
lv_obj_set_style_bg_color(obj_, bgColor, LV_PART_MAIN | LV_STATE_PRESSED);
|
||||
}
|
||||
|
||||
if (bestMatch->style.flags & ConditionStyle::FLAG_USE_BG_OPACITY) {
|
||||
@ -411,8 +419,45 @@ void ButtonWidget::applyFakeShadowStyle() {
|
||||
}
|
||||
|
||||
void ButtonWidget::updateIcon(uint32_t codepoint) {
|
||||
if (!iconLabel_ || codepoint == 0) return;
|
||||
if (codepoint == 0) return;
|
||||
|
||||
// If no icon label exists yet, we need to create it dynamically
|
||||
if (!iconLabel_ && obj_ && Fonts::hasIconFont()) {
|
||||
// For buttons without a content container, we need to create the icon label
|
||||
if (!contentContainer_) {
|
||||
// Create a simple icon label directly in the button
|
||||
iconLabel_ = lv_label_create(obj_);
|
||||
if (iconLabel_) {
|
||||
lv_obj_clear_flag(iconLabel_, LV_OBJ_FLAG_CLICKABLE);
|
||||
// Position it based on icon position setting
|
||||
if (config_.iconPosition == static_cast<uint8_t>(IconPosition::LEFT)) {
|
||||
lv_obj_align(iconLabel_, LV_ALIGN_LEFT_MID, config_.iconPositionX, 0);
|
||||
} else if (config_.iconPosition == static_cast<uint8_t>(IconPosition::RIGHT)) {
|
||||
lv_obj_align(iconLabel_, LV_ALIGN_RIGHT_MID, -config_.iconPositionX, 0);
|
||||
} else {
|
||||
lv_obj_align(iconLabel_, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!iconLabel_) return;
|
||||
|
||||
// Set the icon text
|
||||
char iconText[5];
|
||||
encodeUtf8(codepoint, iconText);
|
||||
lv_label_set_text(iconLabel_, iconText);
|
||||
|
||||
// Apply the correct font size
|
||||
// If iconSize is 0 (no icon was originally configured), use fontSize instead
|
||||
// Default to size 2 (22px) if both are 0
|
||||
// Icon fonts support sizes 0-13 (14px to 260px)
|
||||
uint8_t sizeIdx = config_.iconSize > 0 ? config_.iconSize : config_.fontSize;
|
||||
if (sizeIdx == 0) sizeIdx = 2; // Default to medium size (22px)
|
||||
if (sizeIdx > 13) sizeIdx = 13; // Cap at max icon font size
|
||||
lv_obj_set_style_text_font(iconLabel_, Fonts::iconFont(sizeIdx), 0);
|
||||
|
||||
// Apply text color from config
|
||||
lv_obj_set_style_text_color(iconLabel_, lv_color_make(
|
||||
config_.textColor.r, config_.textColor.g, config_.textColor.b), 0);
|
||||
}
|
||||
|
||||
@ -115,12 +115,13 @@ void RoomCardWidgetBase::createSubButtonsCommon() {
|
||||
int16_t absY = config_.y + relY;
|
||||
lv_obj_set_pos(btn, absX, absY);
|
||||
|
||||
// Create icon
|
||||
if (cfg.iconCodepoint > 0 && Fonts::hasIconFont()) {
|
||||
// Create icon (use iconCodepointOff initially, will be updated based on state)
|
||||
uint32_t initialIcon = cfg.iconCodepointOff;
|
||||
if (initialIcon > 0 && Fonts::hasIconFont()) {
|
||||
lv_obj_t* icon = lv_label_create(btn);
|
||||
lv_obj_clear_flag(icon, LV_OBJ_FLAG_CLICKABLE);
|
||||
char iconText[5];
|
||||
encodeUtf8(cfg.iconCodepoint, iconText);
|
||||
encodeUtf8(initialIcon, iconText);
|
||||
lv_label_set_text(icon, iconText);
|
||||
lv_obj_center(icon);
|
||||
subButtonIcons_[i] = icon;
|
||||
@ -158,9 +159,20 @@ void RoomCardWidgetBase::updateSubButtonColor(uint8_t index) {
|
||||
if (index >= MAX_SUBBUTTONS || !subButtonObjs_[index]) return;
|
||||
|
||||
const SubButtonConfig& cfg = config_.subButtons[index];
|
||||
const Color& color = subButtonStates_[index] ? cfg.colorOn : cfg.colorOff;
|
||||
bool isOn = subButtonStates_[index];
|
||||
const Color& color = isOn ? cfg.colorOn : cfg.colorOff;
|
||||
|
||||
lv_obj_set_style_bg_color(subButtonObjs_[index], lv_color_hex(color.toLvColor()), 0);
|
||||
|
||||
// Update icon based on state
|
||||
if (subButtonIcons_[index]) {
|
||||
uint32_t iconCodepoint = isOn && cfg.iconCodepointOn > 0 ? cfg.iconCodepointOn : cfg.iconCodepointOff;
|
||||
if (iconCodepoint > 0) {
|
||||
char iconText[5];
|
||||
encodeUtf8(iconCodepoint, iconText);
|
||||
lv_label_set_text(subButtonIcons_[index], iconText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RoomCardWidgetBase::updateTemperature(float value) {
|
||||
|
||||
@ -2845,8 +2845,8 @@ CONFIG_LV_COLOR_DEPTH=16
|
||||
#
|
||||
# Memory Settings
|
||||
#
|
||||
CONFIG_LV_USE_BUILTIN_MALLOC=y
|
||||
# CONFIG_LV_USE_CLIB_MALLOC is not set
|
||||
# CONFIG_LV_USE_BUILTIN_MALLOC is not set
|
||||
CONFIG_LV_USE_CLIB_MALLOC=y
|
||||
# CONFIG_LV_USE_MICROPYTHON_MALLOC is not set
|
||||
# CONFIG_LV_USE_RTTHREAD_MALLOC is not set
|
||||
# CONFIG_LV_USE_CUSTOM_MALLOC is not set
|
||||
@ -2856,9 +2856,6 @@ CONFIG_LV_USE_BUILTIN_STRING=y
|
||||
CONFIG_LV_USE_BUILTIN_SPRINTF=y
|
||||
# CONFIG_LV_USE_CLIB_SPRINTF is not set
|
||||
# CONFIG_LV_USE_CUSTOM_SPRINTF is not set
|
||||
CONFIG_LV_MEM_SIZE_KILOBYTES=128
|
||||
CONFIG_LV_MEM_POOL_EXPAND_SIZE_KILOBYTES=0
|
||||
CONFIG_LV_MEM_ADR=0x0
|
||||
# end of Memory Settings
|
||||
|
||||
#
|
||||
|
||||
@ -71,6 +71,7 @@ const key = computed(() => w.value ? typeKeyFor(w.value.type) : 'label');
|
||||
const showIconPicker = ref(false);
|
||||
const conditionIconPickerIdx = ref(-1);
|
||||
const subButtonIconPickerIdx = ref(-1);
|
||||
const subButtonIconType = ref('off'); // 'off' or 'on'
|
||||
const textLineIconPickerIdx = ref(-1);
|
||||
|
||||
// Map widget types to settings components
|
||||
@ -110,9 +111,10 @@ function openConditionIconPicker(idx) {
|
||||
showIconPicker.value = true;
|
||||
}
|
||||
|
||||
function openSubButtonIconPicker(idx) {
|
||||
function openSubButtonIconPicker(idx, type = 'off') {
|
||||
conditionIconPickerIdx.value = -1;
|
||||
subButtonIconPickerIdx.value = idx;
|
||||
subButtonIconType.value = type;
|
||||
textLineIconPickerIdx.value = -1;
|
||||
showIconPicker.value = true;
|
||||
}
|
||||
@ -131,7 +133,8 @@ const activeIconCodepoint = computed({
|
||||
return w.value.conditions[conditionIconPickerIdx.value].icon || 0;
|
||||
}
|
||||
if (subButtonIconPickerIdx.value >= 0 && w.value?.subButtons?.[subButtonIconPickerIdx.value]) {
|
||||
return w.value.subButtons[subButtonIconPickerIdx.value].icon || 0;
|
||||
const sb = w.value.subButtons[subButtonIconPickerIdx.value];
|
||||
return subButtonIconType.value === 'on' ? (sb.iconOn || 0) : (sb.iconOff || 0);
|
||||
}
|
||||
if (textLineIconPickerIdx.value >= 0 && w.value?.textLines?.[textLineIconPickerIdx.value]) {
|
||||
return w.value.textLines[textLineIconPickerIdx.value].icon || 0;
|
||||
@ -142,7 +145,12 @@ const activeIconCodepoint = computed({
|
||||
if (conditionIconPickerIdx.value >= 0 && w.value?.conditions?.[conditionIconPickerIdx.value]) {
|
||||
w.value.conditions[conditionIconPickerIdx.value].icon = value;
|
||||
} else if (subButtonIconPickerIdx.value >= 0 && w.value?.subButtons?.[subButtonIconPickerIdx.value]) {
|
||||
w.value.subButtons[subButtonIconPickerIdx.value].icon = value;
|
||||
const sb = w.value.subButtons[subButtonIconPickerIdx.value];
|
||||
if (subButtonIconType.value === 'on') {
|
||||
sb.iconOn = value;
|
||||
} else {
|
||||
sb.iconOff = value;
|
||||
}
|
||||
} else if (textLineIconPickerIdx.value >= 0 && w.value?.textLines?.[textLineIconPickerIdx.value]) {
|
||||
w.value.textLines[textLineIconPickerIdx.value].icon = value;
|
||||
} else if (w.value) {
|
||||
@ -155,6 +163,7 @@ function handleIconPickerClose() {
|
||||
showIconPicker.value = false;
|
||||
conditionIconPickerIdx.value = -1;
|
||||
subButtonIconPickerIdx.value = -1;
|
||||
subButtonIconType.value = 'off';
|
||||
textLineIconPickerIdx.value = -1;
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -147,10 +147,14 @@
|
||||
</button>
|
||||
<button v-if="cond.icon" class="w-6 h-6 rounded-md border border-red-200 bg-[#f7dede] text-[#b3261e] grid place-items-center text-[11px] cursor-pointer hover:bg-[#f2cfcf]" @click="cond.icon = 0">x</button>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-[11px] text-muted">
|
||||
<label class="w-[50px]">Farbe</label>
|
||||
<div class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<label class="w-[50px]">Textfarbe</label>
|
||||
<input class="h-[22px] w-[32px] cursor-pointer border-0 bg-transparent p-0" type="color" v-model="cond.textColor">
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-[11px] text-muted">
|
||||
<label class="w-[50px]">Hintergr.</label>
|
||||
<input class="h-[22px] w-[32px] cursor-pointer border-0 bg-transparent p-0" type="color" v-model="cond.bgColor">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -190,7 +194,8 @@ const conditionCount = computed({
|
||||
op: 'eq',
|
||||
priority: props.widget.conditions.length,
|
||||
icon: 0,
|
||||
textColor: '#FFFFFF'
|
||||
textColor: '#FFFFFF',
|
||||
bgColor: ''
|
||||
});
|
||||
}
|
||||
if (props.widget.conditions.length > target) {
|
||||
|
||||
@ -166,11 +166,20 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<label class="w-[50px]">Icon</label>
|
||||
<button class="flex-1 bg-white border border-border rounded-md px-2.5 py-1 text-[11px] flex items-center justify-center gap-1 cursor-pointer hover:bg-[#e4ebf2]" @click="$emit('open-subbutton-icon-picker', idx)">
|
||||
<span v-if="sb.icon" class="material-symbols-outlined text-[16px]">{{ String.fromCodePoint(sb.icon) }}</span>
|
||||
<label class="w-[50px]">Icon Aus</label>
|
||||
<button class="flex-1 bg-white border border-border rounded-md px-2.5 py-1 text-[11px] flex items-center justify-center gap-1 cursor-pointer hover:bg-[#e4ebf2]" @click="$emit('open-subbutton-icon-picker', idx, 'off')">
|
||||
<span v-if="sb.iconOff" class="material-symbols-outlined text-[16px]">{{ String.fromCodePoint(sb.iconOff) }}</span>
|
||||
<span v-else>Kein Icon</span>
|
||||
</button>
|
||||
<button v-if="sb.iconOff" class="w-6 h-6 rounded-md border border-red-200 bg-[#f7dede] text-[#b3261e] grid place-items-center text-[11px] cursor-pointer hover:bg-[#f2cfcf]" @click="sb.iconOff = 0">x</button>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<label class="w-[50px]">Icon An</label>
|
||||
<button class="flex-1 bg-white border border-border rounded-md px-2.5 py-1 text-[11px] flex items-center justify-center gap-1 cursor-pointer hover:bg-[#e4ebf2]" @click="$emit('open-subbutton-icon-picker', idx, 'on')">
|
||||
<span v-if="sb.iconOn" class="material-symbols-outlined text-[16px]">{{ String.fromCodePoint(sb.iconOn) }}</span>
|
||||
<span v-else>Wie Aus</span>
|
||||
</button>
|
||||
<button v-if="sb.iconOn" class="w-6 h-6 rounded-md border border-red-200 bg-[#f7dede] text-[#b3261e] grid place-items-center text-[11px] cursor-pointer hover:bg-[#f2cfcf]" @click="sb.iconOn = 0">x</button>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2 text-[11px] text-muted">
|
||||
<label class="w-[50px]">Aktion</label>
|
||||
@ -184,7 +193,7 @@
|
||||
<select class="flex-1 bg-white border border-border rounded-md px-2 py-1 text-[11px]" v-model.number="sb.knxRead">
|
||||
<option :value="0">-- Keine --</option>
|
||||
<option v-for="addr in store.knxAddresses" :key="`${addr.addr}-${addr.index}`" :value="addr.addr">
|
||||
GA {{ addr.addrStr }}
|
||||
GA {{ addr.addrStr }} (GO{{ addr.index }})
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
@ -193,7 +202,7 @@
|
||||
<select class="flex-1 bg-white border border-border rounded-md px-2 py-1 text-[11px]" v-model.number="sb.knxWrite">
|
||||
<option :value="0">-- Keine --</option>
|
||||
<option v-for="addr in writeableAddresses" :key="`${addr.addr}-${addr.index}`" :value="addr.addr">
|
||||
GA {{ addr.addrStr }}
|
||||
GA {{ addr.addrStr }} (GO{{ addr.index }})
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
@ -316,7 +325,8 @@ const subButtonCount = computed({
|
||||
while (props.widget.subButtons.length < target) {
|
||||
props.widget.subButtons.push({
|
||||
pos: props.widget.subButtons.length,
|
||||
icon: 0,
|
||||
iconOff: 0,
|
||||
iconOn: 0,
|
||||
knxRead: 0,
|
||||
knxWrite: 0,
|
||||
action: 0,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user