From 8de0ef47df8a01cde2a2b49ce8b1be510b9a0bf6 Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Thu, 19 Oct 2023 13:12:42 +0100 Subject: [PATCH] Better background handling in themes - Modify view structures so that we're able to control background drawing better - Remove transparent concept from box view - Add background styles for dialog, menu/status bars - Relates #824 --- .../component/view/control/AbstractView.java | 15 ++++++ .../shell/component/view/control/BoxView.java | 30 +++-------- .../component/view/control/ButtonView.java | 6 +++ .../component/view/control/DialogView.java | 17 ++++++- .../component/view/control/MenuBarView.java | 7 ++- .../component/view/control/StatusBarView.java | 6 +++ .../component/view/control/WindowView.java | 6 ++- .../view/control/cell/AbstractCell.java | 14 ++++++ .../view/control/cell/AbstractListCell.java | 17 ++++++- .../shell/style/StyleSettings.java | 50 ++++++++++++++++++- .../shell/samples/catalog/Catalog.java | 12 ++++- .../samples/catalog/CatalogConfiguration.java | 20 ++++++++ 12 files changed, 168 insertions(+), 32 deletions(-) diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/AbstractView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/AbstractView.java index c7d2142f..d3b81dee 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/AbstractView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/AbstractView.java @@ -108,8 +108,15 @@ public abstract class AbstractView extends AbstractControl implements View { return layer; } + /** + * Calls drawing logic in two stages. First a background is drawn and then an + * actual content. This logic allows to separate how child implementation + * can use drawing logic from its parent as usually background should get + * overridden in child but actual content should get overridden in a parent. + */ @Override public final void draw(Screen screen) { + drawBackground(screen); drawInternal(screen); } @@ -121,6 +128,14 @@ public abstract class AbstractView extends AbstractControl implements View { */ protected abstract void drawInternal(Screen screen); + /** + * Internal drawing method for background. + * + * @param screen the screen + */ + protected void drawBackground(Screen screen) { + } + @Override public void focus(View view, boolean focus) { log.debug("Focus view={} focus={}", view, focus); diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/BoxView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/BoxView.java index fe78dd08..79d84aae 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/BoxView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/BoxView.java @@ -45,7 +45,6 @@ public class BoxView extends AbstractView { private int paddingBottom; private int paddingLeft; private int paddingRight; - private boolean transparent = true; private int backgroundColor = -1; private int titleColor = -1; private int titleStyle = -1; @@ -162,22 +161,15 @@ public class BoxView extends AbstractView { this.titleAlign = titleAlign; } - /** - * Sets if box should be transparent, {@code true} by default. - * - * @param transparent a transparency flag - */ - public void setTransparent(boolean transparent) { - this.transparent = transparent; + protected String getBackgroundStyle() { + return StyleSettings.TAG_BACKGROUND; } - /** - * Is box transparent. - * - * @return box transparency - */ - protected boolean isTransparent() { - return transparent; + @Override + protected void drawBackground(Screen screen) { + int bgColor = resolveThemeBackground(getBackgroundStyle(), backgroundColor, -1); + Rectangle rect = getRect(); + screen.writerBuilder().layer(getLayer()).build().background(rect, bgColor); } /** @@ -192,14 +184,6 @@ public class BoxView extends AbstractView { if (rect.width() <= 0 || rect.height() <= 0) { return; } - int bgColor; - if (isTransparent()) { - bgColor = backgroundColor > -1 ? backgroundColor : -1; - } - else { - bgColor = resolveThemeBackground(StyleSettings.TAG_BACKGROUND, backgroundColor, -1); - } - screen.writerBuilder().layer(getLayer()).build().background(rect, bgColor); if (showBorder && rect.width() >= 2 && rect.height() >= 2) { screen.writerBuilder().layer(getLayer()).build().border(rect.x(), rect.y(), rect.width(), rect.height()); if (StringUtils.hasText(title)) { diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ButtonView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ButtonView.java index 7efb5e50..f0885eb3 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ButtonView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ButtonView.java @@ -26,6 +26,7 @@ import org.springframework.shell.component.view.geom.VerticalAlign; import org.springframework.shell.component.view.message.ShellMessageBuilder; import org.springframework.shell.component.view.screen.Screen; import org.springframework.shell.component.view.screen.Screen.Writer; +import org.springframework.shell.style.StyleSettings; /** * {@code ButtonView} is a {@link View} with border and text acting as a button. @@ -66,6 +67,11 @@ public class ButtonView extends BoxView { return super.getMouseHandler(); } + @Override + protected String getBackgroundStyle() { + return StyleSettings.TAG_BUTTON_BACKGROUND; + } + @Override protected void drawInternal(Screen screen) { Rectangle rect = getInnerRect(); diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/DialogView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/DialogView.java index 3dc6a069..e80e8854 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/DialogView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/DialogView.java @@ -27,6 +27,7 @@ import org.springframework.shell.component.view.geom.Rectangle; import org.springframework.shell.component.view.message.ShellMessageBuilder; import org.springframework.shell.component.view.screen.Screen; import org.springframework.shell.component.view.screen.Screen.Writer; +import org.springframework.shell.style.StyleSettings; /** * {@code DialogView} is a {@link View} with border, number of buttons and area @@ -59,6 +60,20 @@ public class DialogView extends WindowView { hookButtonEvents(); } + @Override + protected String getBackgroundStyle() { + return StyleSettings.TAG_DIALOG_BACKGROUND; + } + + @Override + public void setLayer(int index) { + if (content != null) { + content.setLayer(index); + } + buttons.forEach(b -> b.setLayer(index + 1)); + super.setLayer(index); + } + private void hookButtonEvents() { buttons.forEach(b -> { onDestroy(getEventLoop().viewEvents(ButtonViewSelectEvent.class, b) @@ -95,13 +110,11 @@ public class DialogView extends WindowView { rect = new Rectangle(rect.x() + 1, rect.y() + 1, rect.width() - 2, rect.height() - 2); if (content != null) { content.setRect(rect.x(), rect.y(), rect.width(), rect.height() - 3); - content.setLayer(getLayer()); } int xx = rect.x(); ListIterator iter = buttons.listIterator(); while (iter.hasNext()) { ButtonView button = iter.next(); - button.setLayer(getLayer()); button.setRect(xx, rect.y() + rect.height() - 3, 7, 3); xx += 7; } diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/MenuBarView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/MenuBarView.java index 2082dae3..9002e813 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/MenuBarView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/MenuBarView.java @@ -36,6 +36,7 @@ import org.springframework.shell.component.view.geom.Rectangle; import org.springframework.shell.component.view.screen.Screen; import org.springframework.shell.component.view.screen.Screen.Writer; import org.springframework.shell.component.view.screen.ScreenItem; +import org.springframework.shell.style.StyleSettings; import org.springframework.shell.style.ThemeResolver; /** @@ -74,6 +75,11 @@ public class MenuBarView extends BoxView { return new MenuBarView(items); } + @Override + protected String getBackgroundStyle() { + return StyleSettings.TAG_MENUBAR_BACKGROUND; + } + @Override protected void drawInternal(Screen screen) { Rectangle rect = getInnerRect(); @@ -245,7 +251,6 @@ public class MenuBarView extends BoxView { menuView.setThemeResolver(getThemeResolver()); menuView.setThemeName(getThemeName()); menuView.setShowBorder(true); - menuView.setTransparent(false); menuView.setLayer(1); Rectangle rect = getInnerRect(); int x = positionAtIndex(activeItemIndex); diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/StatusBarView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/StatusBarView.java index e8854f29..f484d284 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/StatusBarView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/StatusBarView.java @@ -29,6 +29,7 @@ import org.springframework.shell.component.view.geom.Rectangle; import org.springframework.shell.component.view.message.ShellMessageBuilder; import org.springframework.shell.component.view.screen.Screen; import org.springframework.shell.component.view.screen.Screen.Writer; +import org.springframework.shell.style.StyleSettings; /** * {@link StatusBarView} shows {@link StatusItem items} horizontally and is @@ -53,6 +54,11 @@ public class StatusBarView extends BoxView { setItems(items); } + @Override + protected String getBackgroundStyle() { + return StyleSettings.TAG_STATUSBAR_BACKGROUND; + } + @Override protected void drawInternal(Screen screen) { Rectangle rect = getInnerRect(); diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/WindowView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/WindowView.java index 26d5bc7d..1cc7a896 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/WindowView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/WindowView.java @@ -44,10 +44,14 @@ public class WindowView extends AbstractView { this.backgroundColor = backgroundColor; } + protected String getBackgroundStyle() { + return StyleSettings.TAG_BACKGROUND; + } + @Override protected void drawInternal(Screen screen) { Rectangle rect = getInnerRect(); - int bgColor = resolveThemeBackground(StyleSettings.TAG_BACKGROUND, backgroundColor, -1); + int bgColor = resolveThemeBackground(getBackgroundStyle(), backgroundColor, -1); screen.writerBuilder().layer(getLayer()).build().background(rect, bgColor); } diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/cell/AbstractCell.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/cell/AbstractCell.java index e831c8a8..d19c0115 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/cell/AbstractCell.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/cell/AbstractCell.java @@ -16,6 +16,7 @@ package org.springframework.shell.component.view.control.cell; import org.springframework.shell.component.view.control.AbstractControl; +import org.springframework.shell.component.view.screen.Screen; /** * Base implementation of a {@link Cell}. @@ -69,4 +70,17 @@ public abstract class AbstractCell extends AbstractControl implements Cell public int getBackgroundColor() { return backgroundColor; } + + @Override + public void draw(Screen screen) { + drawBackground(screen); + drawContent(screen); + } + + protected void drawBackground(Screen screen) { + } + + protected void drawContent(Screen screen) { + } + } diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/cell/AbstractListCell.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/cell/AbstractListCell.java index 834ee9db..cbc3d7ae 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/cell/AbstractListCell.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/cell/AbstractListCell.java @@ -19,6 +19,7 @@ import org.springframework.shell.component.view.control.ListView.ItemStyle; import org.springframework.shell.component.view.geom.Rectangle; import org.springframework.shell.component.view.screen.Screen; import org.springframework.shell.component.view.screen.Screen.Writer; +import org.springframework.shell.style.StyleSettings; import org.springframework.util.StringUtils; /** @@ -51,8 +52,21 @@ public abstract class AbstractListCell extends AbstractCell implements Lis return null; } + protected String getBackgroundStyle() { + return StyleSettings.TAG_BACKGROUND; + } + @Override - public void draw(Screen screen) { + protected void drawBackground(Screen screen) { + Rectangle rect = getRect(); + int bgColor = resolveThemeBackground(getBackgroundStyle(), getBackgroundColor(), -1); + if (bgColor > -1) { + screen.writerBuilder().build().background(rect, bgColor); + } + } + + @Override + protected void drawContent(Screen screen) { String indicator = getIndicator(); String text = null; if (StringUtils.hasText(indicator)) { @@ -64,7 +78,6 @@ public abstract class AbstractListCell extends AbstractCell implements Lis Rectangle rect = getRect(); Writer writer = screen.writerBuilder().style(getStyle()).color(getForegroundColor()).build(); writer.text(text, rect.x(), rect.y()); - writer.background(rect, getBackgroundColor()); } @Override diff --git a/spring-shell-core/src/main/java/org/springframework/shell/style/StyleSettings.java b/spring-shell-core/src/main/java/org/springframework/shell/style/StyleSettings.java index 610ee3f5..6536fbdf 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/style/StyleSettings.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/style/StyleSettings.java @@ -96,6 +96,26 @@ public abstract class StyleSettings { */ public final static String TAG_BACKGROUND = "style-background"; + /** + * Styling for dialog background. + */ + public final static String TAG_DIALOG_BACKGROUND = "style-dialog-background"; + + /** + * Styling for button background. + */ + public final static String TAG_BUTTON_BACKGROUND = "style-button-background"; + + /** + * Styling for menubar background. + */ + public final static String TAG_MENUBAR_BACKGROUND = "style-menubar-background"; + + /** + * Styling for statusbar background. + */ + public final static String TAG_STATUSBAR_BACKGROUND = "style-statusbar-background"; + public String title() { return "bold"; } @@ -152,6 +172,22 @@ public abstract class StyleSettings { return "default"; } + public String dialogBackground() { + return "default"; + } + + public String buttonBackground() { + return "default"; + } + + public String menubarBackground() { + return "default"; + } + + public String statusbarBackground() { + return "default"; + } + /** * Resolve a theme setting from a given tag. * @@ -188,6 +224,14 @@ public abstract class StyleSettings { return highlight(); case TAG_BACKGROUND: return background(); + case TAG_DIALOG_BACKGROUND: + return dialogBackground(); + case TAG_BUTTON_BACKGROUND: + return buttonBackground(); + case TAG_MENUBAR_BACKGROUND: + return menubarBackground(); + case TAG_STATUSBAR_BACKGROUND: + return statusbarBackground(); } throw new IllegalArgumentException(String.format("Unknown tag '%s'", tag)); } @@ -225,7 +269,11 @@ public abstract class StyleSettings { TAG_ITEM_UNSELECTED, TAG_ITEM_SELECTOR, TAG_HIGHLIGHT, - TAG_BACKGROUND + TAG_BACKGROUND, + TAG_DIALOG_BACKGROUND, + TAG_BUTTON_BACKGROUND, + TAG_MENUBAR_BACKGROUND, + TAG_STATUSBAR_BACKGROUND }; } diff --git a/spring-shell-samples/spring-shell-sample-catalog/src/main/java/org/springframework/shell/samples/catalog/Catalog.java b/spring-shell-samples/spring-shell-sample-catalog/src/main/java/org/springframework/shell/samples/catalog/Catalog.java index 3145df81..9795bf09 100644 --- a/spring-shell-samples/spring-shell-sample-catalog/src/main/java/org/springframework/shell/samples/catalog/Catalog.java +++ b/spring-shell-samples/spring-shell-sample-catalog/src/main/java/org/springframework/shell/samples/catalog/Catalog.java @@ -245,11 +245,19 @@ public class Catalog { } @Override - public void draw(Screen screen) { + protected void drawBackground(Screen screen) { + int bgColor = resolveThemeBackground(getBackgroundStyle(), getBackgroundColor(), -1); + if (bgColor > -1) { + Rectangle rect = getRect(); + screen.writerBuilder().build().background(rect, bgColor); + } + } + + @Override + protected void drawContent(Screen screen) { Rectangle rect = getRect(); Writer writer = screen.writerBuilder().style(getStyle()).build(); writer.text(String.format("%-20s %s", getItem().name(), getItem().description()), rect.x(), rect.y()); - writer.background(rect, getBackgroundColor()); } } diff --git a/spring-shell-samples/spring-shell-sample-catalog/src/main/java/org/springframework/shell/samples/catalog/CatalogConfiguration.java b/spring-shell-samples/spring-shell-sample-catalog/src/main/java/org/springframework/shell/samples/catalog/CatalogConfiguration.java index 28abb490..25d8b896 100644 --- a/spring-shell-samples/spring-shell-sample-catalog/src/main/java/org/springframework/shell/samples/catalog/CatalogConfiguration.java +++ b/spring-shell-samples/spring-shell-sample-catalog/src/main/java/org/springframework/shell/samples/catalog/CatalogConfiguration.java @@ -59,6 +59,26 @@ class CatalogConfiguration { return "bg:blue"; } + @Override + public String dialogBackground() { + return "bg:green"; + } + + @Override + public String buttonBackground() { + return "bg:red"; + } + + @Override + public String menubarBackground() { + return "bg:magenta"; + } + + @Override + public String statusbarBackground() { + return "bg:cyan"; + } + } }