diff --git a/Readme.md b/Readme.md index caf3cb9..3b362de 100644 --- a/Readme.md +++ b/Readme.md @@ -167,7 +167,7 @@ The following widget types and features have been implemented with basic functio * Action Button to open display or web link * Action Button to write value to PV * Combo - * Group with group border + * Group with 'Group', 'Title, 'Line' or 'None' styles * Embedded Displays * Tabs * Navigation Tabs diff --git a/examples/Groups.bob b/examples/Groups.bob new file mode 100644 index 0000000..8eedcce --- /dev/null +++ b/examples/Groups.bob @@ -0,0 +1,297 @@ + + + + Display + 710 + 598 + + Label + TITLE + Groups + 0 + 0 + 550 + 31 + + + + + + + + + true + + + Rectangle + 60 + 31 + 300 + 80 + 1 + + + + + true + + + Rectangle_1 + 398 + 31 + 264 + 100 + 1 + + + + + true + + + Rectangle_3 + 111 + 60 + 200 + 1 + + + + + true + + + Group + 60 + 111 + + Label_1 + 'Group Box' Style + 2 + 2 + 260 + 160 + + + + + false + 1 + 1 + + + + Rectangle_7 + 360 + 111 + 20 + 200 + 1 + + + + + true + + + Group_1 + 398 + 129 + 264 + 164 + + + Label_2 + 'None' Style + 2 + 2 + 260 + 160 + + + + + false + 1 + 1 + + + + Rectangle_4 + 380 + 131 + 20 + 162 + 1 + + + + + true + + + Rectangle_2 + 662 + 131 + 48 + 162 + 1 + + + + + true + + + Rectangle_6 + 398 + 293 + 264 + 98 + 1 + + + + + true + + + Rectangle_5 + 60 + 311 + 300 + 80 + 1 + + + + + true + + + Group + 60 + 391 + 167 + + + + + + + + + + + Label_4 + 'Title' Style: +'Foreground' green, +'Line Color' gray + -1 + 297 + 146 + + + + + false + 1 + 1 + + + + Rectangle_8 + 360 + 392 + 38 + 166 + 1 + + + + + true + + + Group_2 + 398 + 391 + 266 + 166 + + + Label_3 + 'Line' Style + -1 + -1 + 260 + 160 + + + + + false + 1 + 1 + + + + Colors + 61 + 620 + 249 + 150 + + + + + + + Label_5 + 'Title' Style: +'Foreground' blue, +'Line Color' default=black + 28 + 11 + 190 + 100 + + + + + false + 1 + 1 + + + + Colors + 398 + 620 + 266 + 150 + + + + + + + + + + Label_6 + 'Group Box' Style + 24 + 12 + 182 + 90 + + + + + false + 1 + 1 + + + diff --git a/src/main/java/dbwr/widgets/GroupWidget.java b/src/main/java/dbwr/widgets/GroupWidget.java index ca81894..fefaba0 100644 --- a/src/main/java/dbwr/widgets/GroupWidget.java +++ b/src/main/java/dbwr/widgets/GroupWidget.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019-2020 Oak Ridge National Laboratory. + * Copyright (c) 2019-2024 Oak Ridge National Laboratory. * All rights reserved. This program and the accompanying materials * are made available under the terms of the LICENSE * which accompanies this distribution @@ -9,9 +9,12 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; import org.w3c.dom.Element; +import static dbwr.WebDisplayRepresentation.logger; + import dbwr.parser.FontInfo; import dbwr.parser.HTMLUtil; import dbwr.parser.WidgetFactory; @@ -29,9 +32,10 @@ public class GroupWidget extends BaseMacroWidget } private final String name; - private final int style; + private enum Style { GROUP, TITLE, LINE, NONE }; + private final Style style; private final FontInfo font; - private String foreground_color, line_color, background_color,background_color_label; + private String foreground_color, line_color, background_color, background_color_label; private final boolean transparent; private final List children = new ArrayList<>(); @@ -46,16 +50,23 @@ public GroupWidget(final ParentWidget parent, final Element xml) throws Exceptio switch (XMLUtil.getChildInteger(xml, "border_style").orElse(0)) { case 13: - // GROUP - style = 0; + style = Style.GROUP; break; default: - // NONE - style = 3; + style = Style.NONE; } } else - style = XMLUtil.getChildInteger(xml, "style").orElse(0); + { + int index = XMLUtil.getChildInteger(xml, "style").orElse(0); + if (index >= 0 && index < Style.values().length) + style = Style.values()[index]; + else + { + logger.log(Level.WARNING, "Group " + getWID() + ": Invalid group style " + index); + style = Style.GROUP; + } + } font = XMLUtil.getFont(xml, "font").orElse(LabelWidget.DEFAULT_FONT); @@ -71,10 +82,12 @@ public GroupWidget(final ParentWidget parent, final Element xml) throws Exceptio foreground_color = XMLUtil.getColor(xml, "foreground_color").orElse("#000"); background_color = XMLUtil.getColor(xml, "background_color").orElse("#FFF"); background_color_label = background_color; - line_color = XMLUtil.getColor(xml, "line_color").orElse(null); - if(line_color == null) { + // Line color was introduced in version 3.0.0 and defaults to black since then + line_color = XMLUtil.getColor(xml, "line_color").orElse("#000"); + if (version.major < 3) + { line_color = foreground_color; - if (style == 1) + if (style == Style.TITLE) foreground_color = background_color; } @@ -90,13 +103,14 @@ protected void fillHTML(final PrintWriter html, final int indent) int hinset = (font.getSize()+1)/2; int vinset = hinset; - if (style == 2) + if (style == Style.LINE || style == Style.NONE) hinset = vinset = 0; - else if (style == 1) + else if (style == Style.TITLE) hinset = 0; - - // Style 0: Group, 1:Title, 2:Line, 3:None - if (style == 1) + + // For the following lines, 'stroke-width=1' should match the desktop display builder look, + // but colors are a bit dimmed, black shows as gray, unless we use a slightly larger stroke-width + if (style == Style.TITLE) { // Group name as box on top with outline below HTMLUtil.indent(html, indent+1); html.print("
"); @@ -105,7 +119,7 @@ else if (style == 1) HTMLUtil.indent(html, indent+1); html.println(""); HTMLUtil.indent(html, indent+2); - html.println(""); + html.println(""); HTMLUtil.indent(html, indent+1); html.println(""); } @@ -113,34 +127,32 @@ else if (style == 1) { // SVG for border HTMLUtil.indent(html, indent+1); html.println(""); - if(style != 3){ + if (style != Style.NONE) + { HTMLUtil.indent(html, indent+2); - html.println(""); + html.println(""); HTMLUtil.indent(html, indent+1); } html.println(""); } - if (style == 0) + if (style == Style.GROUP) { // Group name as label on top of border HTMLUtil.indent(html, indent+1); html.print("
"); html.print(name); html.println("
"); } -// if (style != 3) -// { // Wrap content in
- HTMLUtil.indent(html, indent+1); - html.println("
"); -// } + + // Wrap content in
+ HTMLUtil.indent(html, indent+1); + html.println("
"); for (final Widget child : children) child.getHTML(html, indent+2); -// if (style != 3) -// { // Close the content-div - HTMLUtil.indent(html, indent+1); - html.println("
"); -// } + // Close the content-div + HTMLUtil.indent(html, indent+1); + html.println("
"); HTMLUtil.indent(html, indent); } diff --git a/src/main/java/dbwr/widgets/Version.java b/src/main/java/dbwr/widgets/Version.java new file mode 100644 index 0000000..14c202c --- /dev/null +++ b/src/main/java/dbwr/widgets/Version.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2024 Oak Ridge National Laboratory. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the LICENSE + * which accompanies this distribution + ******************************************************************************/ +package dbwr.widgets; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** Widget version info + * @author Kay Kasemir + */ +public class Version +{ + private static final Pattern VERSION_PATTERN = Pattern.compile("([0-9]+)\\.([0-9]+)\\.([0-9]+)"); + // Some older displays used a shorter "1.0" format without patch level + private static final Pattern SHORT_VERSION_PATTERN = Pattern.compile("([0-9]+)\\.([0-9]+)"); + + public final int major, minor, patch; + + public Version(final int major, final int minor, final int patch) + { + this.major = major; + this.minor = minor; + this.patch = patch; + } + + /** Parse version from text + * @param version "Major.Minor.Patch" type of text or null for "0.0.0" + * @return {@link Version} + * @throws IllegalArgumentException on error + */ + public static Version parse(final String version) + { + if (version == null) + return new Version(0, 0, 0); + + // First try the long format + Matcher matcher = VERSION_PATTERN.matcher(version); + if (matcher.matches()) + return new Version(Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3))); + + matcher = SHORT_VERSION_PATTERN.matcher(version); + if (matcher.matches()) + return new Version(Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)), + 0); + throw new IllegalArgumentException("Invalid version string '" + version + "'"); + } + + public int compareTo(final Version other) + { + if (major != other.major) + return major - other.major; + if (minor != other.minor) + return minor - other.minor; + return patch - other.patch; + } + + @Override + public String toString() + { + return major + "." + minor + "." + patch; + } +} + + diff --git a/src/main/java/dbwr/widgets/Widget.java b/src/main/java/dbwr/widgets/Widget.java index 2d55840..66a1173 100644 --- a/src/main/java/dbwr/widgets/Widget.java +++ b/src/main/java/dbwr/widgets/Widget.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Oak Ridge National Laboratory. + * Copyright (c) 2019-2024 Oak Ridge National Laboratory. * All rights reserved. This program and the accompanying materials * are made available under the terms of the LICENSE * which accompanies this distribution @@ -59,6 +59,9 @@ public class Widget implements ParentWidget /** Styles (inline) to add to the HTML for this widget */ protected final Map styles = new LinkedHashMap<>(); + /** Widget version */ + protected final Version version; + /** Widget position and size */ protected final int x, y, width, height; @@ -88,6 +91,8 @@ public Widget(final ParentWidget parent, final Element xml, final String type) t public Widget(final ParentWidget parent, final Element xml, final String type, final int default_width, final int default_height) throws Exception { this.parent = parent; + + version = Version.parse(xml.getAttribute("version")); x = XMLUtil.getChildInteger(xml, "x").orElse(0); y = XMLUtil.getChildInteger(xml, "y").orElse(0); width = XMLUtil.getChildInteger(xml, "width").orElse(default_width); diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp index 725c823..c70815f 100644 --- a/src/main/webapp/index.jsp +++ b/src/main/webapp/index.jsp @@ -120,6 +120,7 @@ view.jsp?cache=false&display=file:/Path/to/Display+Builder/01_main.bob
+ 2024-01-31 Group widget: Correct inset for style 'None' and fix colors for newly added example.
2023-09-11 LED only displayed values above zero instead of non-zero, incl. negative. Byte monitor layout float calc
2023-08-15 Preserve spaces in labels, text updates
2023-07-28 Cache invalidates entry based on modification time