diff --git a/bundles/org.openhab.ui.basic/snippets-src/buttons.html b/bundles/org.openhab.ui.basic/snippets-src/buttons.html
index 23eac2e086..5502192bc2 100644
--- a/bundles/org.openhab.ui.basic/snippets-src/buttons.html
+++ b/bundles/org.openhab.ui.basic/snippets-src/buttons.html
@@ -2,7 +2,7 @@
%icon_snippet%
-
+
%label%
diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/SwitchRenderer.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/SwitchRenderer.java
index 6b131e85f4..9b527e6b95 100644
--- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/SwitchRenderer.java
+++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/SwitchRenderer.java
@@ -133,9 +133,17 @@ public EList renderWidget(Widget w, StringBuilder sb, String sitemap) th
snippet = preprocessSnippet(snippet, w);
- snippet = snippet.replaceAll("%height_auto%", multiline ? "mdl-form__row--height-auto" : "");
- snippet = snippet.replaceAll("%buttons_class%",
- multiline ? "mdl-form__buttons-multiline" : "mdl-form__buttons");
+ if (multiline) {
+ snippet = snippet //
+ .replaceAll("%height_auto%", "mdl-form__row--height-auto")
+ .replaceAll("%buttons_class%", "mdl-form__buttons-multiline")
+ .replaceAll("%label_class%", "mdl-form__label-multiline");
+ } else {
+ snippet = snippet //
+ .replaceAll("%height_auto%", "") //
+ .replaceAll("%buttons_class%", "mdl-form__buttons") //
+ .replaceAll("%label_class%", "");
+ }
StringBuilder buttons = new StringBuilder();
if (s.getMappings().isEmpty() && item != null) {
diff --git a/bundles/org.openhab.ui.basic/web-src/_layout.scss b/bundles/org.openhab.ui.basic/web-src/_layout.scss
index 7c4f1f42ef..ea4ec39ae4 100644
--- a/bundles/org.openhab.ui.basic/web-src/_layout.scss
+++ b/bundles/org.openhab.ui.basic/web-src/_layout.scss
@@ -168,7 +168,7 @@
@media screen and (max-width: $layout-tablet-size-threshold) {
padding-left: $form-row-mobile-padding;
html.ui-layout-condensed & {
- padding-left: $form-row-mobile-padding-condensed;
+ padding-left: 0; // there's already padding in .mdl-form__row
}
}
html:not(.ui-icons-enabled) & {
@@ -212,16 +212,16 @@
}
}
&__label {
+ padding-left: $form-row-desktop-padding;
+ html.ui-layout-condensed & {
+ padding-left: $form-row-desktop-padding-condensed;
+ }
@media screen and (max-width: $layout-tablet-size-threshold) {
padding-left: $form-row-mobile-padding;
html.ui-layout-condensed & {
padding-left: $form-row-mobile-padding-condensed;
}
}
- padding-left: $form-row-desktop-padding;
- html.ui-layout-condensed & {
- padding-left: $form-row-desktop-padding-condensed;
- }
@include flex-shrink(0);
@include flex-grow(2);
@include flex-2011(2 2 auto);
@@ -232,18 +232,22 @@
font-size: 18px;
}
}
+ &__label-multiline {
+ min-width: 3em;
+ }
&__control {
+ padding-right: $form-row-desktop-padding;
+ padding-left: 4px;
+ html.ui-layout-condensed & {
+ padding-left: 0;
+ padding-right: $form-row-desktop-padding-condensed;
+ }
@media screen and (max-width: $layout-tablet-size-threshold) {
padding-right: $form-row-mobile-padding;
html.ui-layout-condensed & {
- padding-left: $form-row-mobile-padding-condensed;
+ padding-right: $form-row-mobile-padding-condensed;
}
}
- padding-right: $form-row-desktop-padding;
- padding-left: 4px;
- html.ui-layout-condensed & {
- padding-left: $form-row-desktop-padding-condensed;
- }
font-weight: 700;
html.ui-capitalize-values & {
text-transform: uppercase;
@@ -270,7 +274,7 @@
.buttongrid-cell {
height: 36px;
.buttongrid-button {
- min-width: 100%;
+ min-width: 100% !important;
text-transform: none;
}
}
@@ -279,6 +283,12 @@
box-shadow: none;
-webkit-box-shadow: none;
text-transform: unset;
+ min-width: 54px;
+ html.ui-layout-condensed & {
+ min-width: 40px;
+ padding-left: 4px;
+ padding-right: 4px;
+ }
}
.mdl-button-text {
html.ui-bigger-font & {
@@ -502,16 +512,20 @@
}
&__buttons {
padding-top: 2px;
+ padding-bottom: 2px;
}
&__buttons-multiline {
margin: 6px 0;
+ gap: 4px;
html.ui-layout-condensed & {
margin: 0;
+ gap: 3px;
}
- max-width: 60%;
+ padding-top: 2px;
+ padding-bottom: 2px;
display: flex;
flex-wrap: wrap;
- gap: 4px;
+ justify-content: end;
}
&__buttongrid {
padding: 0;
diff --git a/bundles/org.openhab.ui.basic/web-src/smarthome.js b/bundles/org.openhab.ui.basic/web-src/smarthome.js
index 2fb704bbe8..804ddcfda8 100644
--- a/bundles/org.openhab.ui.basic/web-src/smarthome.js
+++ b/bundles/org.openhab.ui.basic/web-src/smarthome.js
@@ -168,6 +168,12 @@
});
}
+ function getElementWidth(element) {
+ var style = getComputedStyle(element);
+ return element.offsetWidth + parseFloat(style.marginLeft) + parseFloat(style.marginRight) +
+ parseFloat(style.paddingLeft) + parseFloat(style.paddingRight);
+ }
+
function EventMapper() {
var
_t = this;
@@ -1177,6 +1183,7 @@
Control.call(this, parentNode);
var
+ maxButtonWidth = 0,
_t = this;
_t.ignoreState = _t.parentNode.getAttribute("data-ignore-state") === "true";
@@ -1239,6 +1246,7 @@
) {
_t.valueMap[itemState].classList.add(o.buttonActiveClass);
}
+ _t.minimizeWidth();
};
_t.setValueColor = function(color) {
@@ -1337,8 +1345,72 @@
icon.addEventListener("load", _t.convertToInlineSVG);
icon.addEventListener("error", _t.replaceImageWithNone);
}
+
+ if (maxButtonWidth < button.offsetWidth) {
+ maxButtonWidth = button.offsetWidth;
+ }
});
+ if (_t.buttons.length > 1 && _t.parentNode.classList.contains(o.buttonsMultilineClass)) {
+ var labelMinWidth = 0;
+ if (_t.label.textContent.trim().length === 0) {
+ _t.label.style.paddingLeft = 0;
+ _t.label.style.minWidth = 0;
+ } else {
+ // Try to see if setting min-width: min-content would result in a narrower min-width
+ // than the one set in _layout.scss, e.g. when the label is short.
+ // If it does make it narrower, it frees up more space for the buttons.
+ // If it is not narrower, un-set it, so that the min-width from _layout.scss can take effect.
+
+ // To measure the min-width using offsetWidth,
+ // we need to make the neighbouring element (buttons) as wide as possible
+ // to force the label to shrink to its min-width
+ // Note that _t.parentNode.style.width will get readjusted inside minimizeWidth()
+ // so setting it to 100% here wouldn't affect the final layout.
+ _t.parentNode.style.width = "100%";
+
+ var defaultMinWidth = parseFloat(getComputedStyle(_t.label).minWidth);
+ _t.label.style.minWidth = "min-content";
+ var minContentWidth = _t.label.offsetWidth;
+ if (minContentWidth > defaultMinWidth) {
+ _t.label.style.removeProperty("min-width");
+ labelMinWidth = defaultMinWidth;
+ } else {
+ labelMinWidth = minContentWidth;
+ }
+ }
+
+ _t.minimizeWidth = function() {
+ // Minimize the width taken by the buttons without adding extra rows.
+ // Start from the maximum width the buttons can take,
+ // then shrink it down to the minimum without causing additional wrapping.
+ var buttons = _t.parentNode;
+ var buttonsStyle = getComputedStyle(buttons);
+ var labelStyle = getComputedStyle(_t.label);
+ // Calculate the maximum width the buttons can take
+ var width = buttons.parentElement.offsetWidth -
+ parseFloat(buttonsStyle.paddingLeft) - parseFloat(buttonsStyle.paddingRight) -
+ getElementWidth(_t.iconContainer) - getElementWidth(_t.value);
+ if (labelMinWidth) {
+ width -= labelMinWidth + parseFloat(labelStyle.paddingLeft) + parseFloat(labelStyle.paddingRight);
+ }
+ buttons.style.width = width + "px";
+ width = buttons.offsetWidth;
+ var height = buttons.offsetHeight;
+ while (buttons.offsetHeight === height && width >= maxButtonWidth) {
+ buttons.style.width = --width + "px";
+ }
+ buttons.style.width = (width+1) + "px";
+ };
+
+ _t.minimizeWidth();
+ // Wait until after all the icons are loaded before running minimizeWidth()
+ window.addEventListener("load", _t.minimizeWidth);
+ window.addEventListener("resize", _t.minimizeWidth);
+ } else {
+ _t.minimizeWidth = function() {};
+ }
+
_t.destroy = function() {
_t.buttons.forEach(function(button) {
var
@@ -1361,6 +1433,8 @@
}
});
componentHandler.downgradeElements(_t.buttons);
+ window.removeEventListener("load", _t.minimizeWidth);
+ window.removeEventListener("resize", _t.minimizeWidth);
};
_t.setValueColor(_t.valueColor);
@@ -3936,6 +4010,7 @@
buttonTextClass: "mdl-button-text",
buttonIconText: ".mdl-button-icon-text",
buttonIconTextClass: "mdl-button-icon-text",
+ buttonsMultilineClass: "mdl-form__buttons-multiline",
modal: ".mdl-modal",
modalContainer: ".mdl-modal__content",
selectionRows: ".mdl-form__selection-rows",