ProgressView spinner theming
- New SpinnerSettings which integrates with ThemeSettings - Support infra around spinner theming - Relates #995
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 the original author or authors.
|
* Copyright 2022-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -26,6 +26,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.shell.style.FigureSettings;
|
import org.springframework.shell.style.FigureSettings;
|
||||||
|
import org.springframework.shell.style.SpinnerSettings;
|
||||||
import org.springframework.shell.style.StyleSettings;
|
import org.springframework.shell.style.StyleSettings;
|
||||||
import org.springframework.shell.style.TemplateExecutor;
|
import org.springframework.shell.style.TemplateExecutor;
|
||||||
import org.springframework.shell.style.Theme;
|
import org.springframework.shell.style.Theme;
|
||||||
@@ -90,7 +91,7 @@ public class ThemingAutoConfigurationTests {
|
|||||||
|
|
||||||
static class MyThemeSettings extends ThemeSettings {
|
static class MyThemeSettings extends ThemeSettings {
|
||||||
MyThemeSettings() {
|
MyThemeSettings() {
|
||||||
super(StyleSettings.defaults(), FigureSettings.defaults());
|
super(StyleSettings.defaults(), FigureSettings.defaults(), SpinnerSettings.defaults());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,4 +145,29 @@ public abstract class AbstractControl implements Control {
|
|||||||
return getThemeResolvedValues(tag).map(ResolvedValues::background).orElse(fallbackColor);
|
return getThemeResolvedValues(tag).map(ResolvedValues::background).orElse(fallbackColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve {@link Spinner} using existing {@link ThemeResolver} and {@code theme name}.
|
||||||
|
* {@code defaultSpinner} is used if it's not {@code null}. {@code fallbackSpinner} is
|
||||||
|
* used if theme resolver cannot be used.
|
||||||
|
*
|
||||||
|
* @param tag the spinner tag to use
|
||||||
|
* @param defaultSpinner the default spinner to use
|
||||||
|
* @param fallbackSpinner the fallback spinner to use
|
||||||
|
* @return resolved spinner
|
||||||
|
*/
|
||||||
|
protected Spinner resolveThemeSpinner(String tag, Spinner defaultSpinner, Spinner fallbackSpinner) {
|
||||||
|
if (defaultSpinner != null) {
|
||||||
|
return defaultSpinner;
|
||||||
|
}
|
||||||
|
Spinner spinner = null;
|
||||||
|
ThemeResolver themeResolver = getThemeResolver();
|
||||||
|
if (themeResolver != null) {
|
||||||
|
spinner = getThemeResolver().resolveSpinnerTag(tag);
|
||||||
|
}
|
||||||
|
if (spinner == null) {
|
||||||
|
spinner = fallbackSpinner;
|
||||||
|
}
|
||||||
|
return spinner;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.springframework.shell.component.view.control.cell.TextCell;
|
|||||||
import org.springframework.shell.component.view.screen.Screen;
|
import org.springframework.shell.component.view.screen.Screen;
|
||||||
import org.springframework.shell.geom.HorizontalAlign;
|
import org.springframework.shell.geom.HorizontalAlign;
|
||||||
import org.springframework.shell.geom.Rectangle;
|
import org.springframework.shell.geom.Rectangle;
|
||||||
|
import org.springframework.shell.style.SpinnerSettings;
|
||||||
import org.springframework.shell.style.ThemeResolver;
|
import org.springframework.shell.style.ThemeResolver;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -75,10 +76,10 @@ public class ProgressView extends BoxView {
|
|||||||
TextCell<Context> cell = TextCell.of(item, ctx -> {
|
TextCell<Context> cell = TextCell.of(item, ctx -> {
|
||||||
int frame = 0;
|
int frame = 0;
|
||||||
|
|
||||||
Spinner spin = ctx.getSpinner();
|
// via view setting, then via theming, then fallback default
|
||||||
if (spin == null) {
|
Spinner spin = ctx.resolveThemeSpinner(SpinnerSettings.TAG_DOT, ctx.getSpinner(),
|
||||||
spin = Spinner.of(Spinner.LINE1, 130);
|
Spinner.of(Spinner.LINE1, 130));
|
||||||
}
|
|
||||||
if (ctx.getState().running()) {
|
if (ctx.getState().running()) {
|
||||||
// we know start time and current update time,
|
// we know start time and current update time,
|
||||||
// calculate elapsed time "frame" to pick rolling
|
// calculate elapsed time "frame" to pick rolling
|
||||||
@@ -343,6 +344,11 @@ public class ProgressView extends BoxView {
|
|||||||
return ProgressView.this.resolveThemeStyle(tag, defaultStyle);
|
return ProgressView.this.resolveThemeStyle(tag, defaultStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Spinner resolveThemeSpinner(String tag, Spinner defaultSpinner, Spinner fallbackSpinner) {
|
||||||
|
return ProgressView.this.resolveThemeSpinner(tag, defaultSpinner, fallbackSpinner);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Spinner getSpinner() {
|
public Spinner getSpinner() {
|
||||||
return ProgressView.this.spinner;
|
return ProgressView.this.spinner;
|
||||||
@@ -393,6 +399,8 @@ public class ProgressView extends BoxView {
|
|||||||
*/
|
*/
|
||||||
int resolveThemeStyle(String tag, int defaultStyle);
|
int resolveThemeStyle(String tag, int defaultStyle);
|
||||||
|
|
||||||
|
Spinner resolveThemeSpinner(String tag, Spinner defaultSpinner, Spinner fallbackSpinner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.shell.style;
|
||||||
|
|
||||||
|
import org.springframework.shell.component.view.control.Spinner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class defining a settings for spinners.
|
||||||
|
*
|
||||||
|
* @author Janne Valkealahti
|
||||||
|
*/
|
||||||
|
public abstract class SpinnerSettings {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spinner with line characters.
|
||||||
|
*/
|
||||||
|
public final static String TAG_LINE = "line";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spinner with dot characters.
|
||||||
|
*/
|
||||||
|
public final static String TAG_DOT = "dot";
|
||||||
|
|
||||||
|
public Spinner line() {
|
||||||
|
return Spinner.of(Spinner.LINE1, 130);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Spinner dot() {
|
||||||
|
return Spinner.of(Spinner.DOTS1, 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Spinner resolveTag(String tag) {
|
||||||
|
switch (tag) {
|
||||||
|
case TAG_LINE:
|
||||||
|
return line();
|
||||||
|
case TAG_DOT:
|
||||||
|
return dot();
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(String.format("Unknown tag '%s'", tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] tags() {
|
||||||
|
return new String[] {
|
||||||
|
TAG_LINE,
|
||||||
|
TAG_DOT,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpinnerSettings defaults() {
|
||||||
|
return new DefaultSpinnerSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpinnerSettings dump() {
|
||||||
|
return new DumpSpinnerSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DefaultSpinnerSettings extends SpinnerSettings {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DumpSpinnerSettings extends SpinnerSettings {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Spinner dot() {
|
||||||
|
return Spinner.of(Spinner.DOTS14, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022-2023 the original author or authors.
|
* Copyright 2022-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,6 +25,7 @@ import org.jline.utils.AttributedString;
|
|||||||
import org.jline.utils.AttributedStyle;
|
import org.jline.utils.AttributedStyle;
|
||||||
import org.jline.utils.Colors;
|
import org.jline.utils.Colors;
|
||||||
|
|
||||||
|
import org.springframework.shell.component.view.control.Spinner;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,6 +142,16 @@ public class ThemeResolver {
|
|||||||
return theme.getSettings().figures().resolveTag(tag);
|
return theme.getSettings().figures().resolveTag(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve spinner from a tag with activated theme.
|
||||||
|
*
|
||||||
|
* @param tag the tag
|
||||||
|
* @return a spinner
|
||||||
|
*/
|
||||||
|
public Spinner resolveSpinnerTag(String tag) {
|
||||||
|
return theme.getSettings().spinners().resolveTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve {@link AttributedStyle} from a {@code spec}.
|
* Resolve {@link AttributedStyle} from a {@code spec}.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 the original author or authors.
|
* Copyright 2022-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -24,6 +24,7 @@ public abstract class ThemeSettings {
|
|||||||
|
|
||||||
private StyleSettings styleSettings;
|
private StyleSettings styleSettings;
|
||||||
private FigureSettings figureSettings;
|
private FigureSettings figureSettings;
|
||||||
|
private SpinnerSettings spinnerSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates theme settings with dump styles and figures.
|
* Creates theme settings with dump styles and figures.
|
||||||
@@ -32,6 +33,15 @@ public abstract class ThemeSettings {
|
|||||||
this(StyleSettings.dump(), FigureSettings.dump());
|
this(StyleSettings.dump(), FigureSettings.dump());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates theme settings with styles.
|
||||||
|
*
|
||||||
|
* @param styleSettings style settings
|
||||||
|
*/
|
||||||
|
public ThemeSettings(StyleSettings styleSettings) {
|
||||||
|
this(styleSettings, FigureSettings.dump(), SpinnerSettings.dump());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates theme settings with styles and figures.
|
* Creates theme settings with styles and figures.
|
||||||
*
|
*
|
||||||
@@ -39,8 +49,20 @@ public abstract class ThemeSettings {
|
|||||||
* @param figureSettings figure settings
|
* @param figureSettings figure settings
|
||||||
*/
|
*/
|
||||||
public ThemeSettings(StyleSettings styleSettings, FigureSettings figureSettings) {
|
public ThemeSettings(StyleSettings styleSettings, FigureSettings figureSettings) {
|
||||||
|
this(styleSettings, figureSettings, SpinnerSettings.dump());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates theme settings with styles, figures and spinners.
|
||||||
|
*
|
||||||
|
* @param styleSettings style settings
|
||||||
|
* @param figureSettings figure settings
|
||||||
|
* @param spinnerSettings spinner settings
|
||||||
|
*/
|
||||||
|
public ThemeSettings(StyleSettings styleSettings, FigureSettings figureSettings, SpinnerSettings spinnerSettings) {
|
||||||
this.styleSettings = styleSettings;
|
this.styleSettings = styleSettings;
|
||||||
this.figureSettings = figureSettings;
|
this.figureSettings = figureSettings;
|
||||||
|
this.spinnerSettings = spinnerSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,13 +83,22 @@ public abstract class ThemeSettings {
|
|||||||
return this.figureSettings;
|
return this.figureSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a {@link SpinnerSettings}.
|
||||||
|
*
|
||||||
|
* @return spinner settings
|
||||||
|
*/
|
||||||
|
public SpinnerSettings spinners() {
|
||||||
|
return this.spinnerSettings;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a default theme settings.
|
* Gets a default theme settings.
|
||||||
*
|
*
|
||||||
* @return default theme settings
|
* @return default theme settings
|
||||||
*/
|
*/
|
||||||
public static ThemeSettings defaults() {
|
public static ThemeSettings defaults() {
|
||||||
return new DefaultThemeSettings(StyleSettings.defaults(), FigureSettings.defaults());
|
return new DefaultThemeSettings(StyleSettings.defaults(), FigureSettings.defaults(), SpinnerSettings.defaults());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,8 +116,8 @@ public abstract class ThemeSettings {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultThemeSettings(StyleSettings styleSettings, FigureSettings figureSettings) {
|
DefaultThemeSettings(StyleSettings styleSettings, FigureSettings figureSettings, SpinnerSettings spinnerSettings) {
|
||||||
super(styleSettings, figureSettings);
|
super(styleSettings, figureSettings, spinnerSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,8 @@ public class ComponentUiCommands extends AbstractShellComponent {
|
|||||||
|
|
||||||
@Command(command = "componentui progress2")
|
@Command(command = "componentui progress2")
|
||||||
public void progress2() {
|
public void progress2() {
|
||||||
ProgressView view = new ProgressView(0, 100, ProgressViewItem.ofText(10, HorizontalAlign.LEFT),
|
ProgressView view = new ProgressView(0, 100,
|
||||||
|
ProgressViewItem.ofText(10, HorizontalAlign.LEFT),
|
||||||
ProgressViewItem.ofSpinner(3, HorizontalAlign.LEFT),
|
ProgressViewItem.ofSpinner(3, HorizontalAlign.LEFT),
|
||||||
ProgressViewItem.ofPercent(0, HorizontalAlign.RIGHT));
|
ProgressViewItem.ofPercent(0, HorizontalAlign.RIGHT));
|
||||||
view.setDescription("name");
|
view.setDescription("name");
|
||||||
@@ -154,4 +155,15 @@ public class ComponentUiCommands extends AbstractShellComponent {
|
|||||||
runProgress(view);
|
runProgress(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Command(command = "componentui progress4")
|
||||||
|
public void progress4() {
|
||||||
|
ProgressView view = new ProgressView();
|
||||||
|
view.setDescription("name");
|
||||||
|
view.setRect(0, 0, 20, 1);
|
||||||
|
view.setThemeResolver(getThemeResolver());
|
||||||
|
view.start();
|
||||||
|
|
||||||
|
runProgress(view);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user