diff --git a/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizer.java b/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizer.java index b905d858a63e7c4b0f3c35d0e9e877616285704f..74c163c64413c0be8dd4f397a13abcb24a6292f4 100644 --- a/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizer.java +++ b/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizer.java @@ -18,8 +18,6 @@ import static org.eclipse.escet.common.java.Lists.listc; import static org.eclipse.escet.common.java.Strings.fmt; import static org.eclipse.escet.common.java.Strings.str; -import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; @@ -37,6 +35,8 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Platform; import org.eclipse.escet.cif.simulator.runtime.meta.RuntimeStateObjectMeta; import org.eclipse.escet.common.app.framework.Paths; +import org.eclipse.escet.common.app.framework.eclipse.themes.EclipseThemePreferenceChangeListener; +import org.eclipse.escet.common.app.framework.eclipse.themes.EclipseThemeUtils; import org.eclipse.escet.common.eclipse.ui.ControlEditor; import org.eclipse.escet.common.eclipse.ui.MsgBox; import org.eclipse.escet.common.eclipse.ui.SelectionListenerBase; @@ -61,15 +61,10 @@ import org.eclipse.swt.widgets.MenuItem; import org.eclipse.ui.PlatformUI; import org.knowm.xchart.XYChart; import org.knowm.xchart.XYChartBuilder; -import org.knowm.xchart.style.MatlabTheme; import org.knowm.xchart.style.Styler.LegendLayout; -import org.knowm.xchart.style.Styler.LegendPosition; import org.knowm.xchart.style.Styler.TextAlignment; +import org.knowm.xchart.style.Theme; import org.knowm.xchart.style.XYStyler; -import org.knowm.xchart.style.colors.ChartColor; -import org.knowm.xchart.style.lines.SeriesLines; -import org.knowm.xchart.style.markers.Marker; -import org.knowm.xchart.style.markers.SeriesMarkers; /** Visualizer to use to graphically plot the values of variables as time progresses, during simulation. */ public class PlotVisualizer extends ControlEditor { @@ -92,36 +87,28 @@ public class PlotVisualizer extends ControlEditor { /** The plot visualizer update thread. {@code null} until initialized by the {@link #createContents} method. */ private PlotVisualizerUpdateThread thread; + /** The Eclipse theme preference change listener. */ + private EclipseThemePreferenceChangeListener themeListener; + @SuppressWarnings("restriction") @Override protected Control createContents(Composite parent) { // Create chart. chart = new XYChartBuilder().build(); - - // Configure chart. + applyChartStyle(); chart.setXAxisTitle("time"); + chart.getStyler().setXAxisMin(0.0); - // Apply Matlab theme. - XYStyler styler = chart.getStyler(); - styler.setTheme(new MatlabTheme()); - - // Custom styling. - styler.setAntiAlias(true); - styler.setChartPadding(15); - styler.setLegendBorderColor(ChartColor.getAWTColor(ChartColor.DARK_GREY)); - styler.setLegendFont(chart.getStyler().getAxisTitleFont()); - styler.setLegendLayout(LegendLayout.Horizontal); - styler.setLegendPadding(7); - styler.setLegendPosition(LegendPosition.OutsideS); - styler.setPlotContentSize(1.0); - styler.setPlotGridLinesColor(new Color(245, 245, 245)); - styler.setPlotGridLinesStroke(new BasicStroke()); - styler.setPlotBackgroundColor(new Color(252, 252, 252)); - styler.setSeriesMarkers(new Marker[] {SeriesMarkers.NONE}); - styler.setSeriesLines(new BasicStroke[] {SeriesLines.SOLID}); - styler.setSeriesColors(MaterialUiColors600.COLORS); - styler.setXAxisMin(0.0); - styler.setYAxisLabelAlignment(TextAlignment.Centre); + // Add Eclipse theme listener. + themeListener = new EclipseThemePreferenceChangeListener(e -> { + if (canvas.isDisposed()) { + return; + } + applyChartStyle(); + canvas.updatePixels(); + canvas.redraw(); + }); + parent.addDisposeListener(e -> themeListener.unregister()); // Create canvas on which to display the chart. canvas = new PlotVisualizerCanvas(parent, chart); @@ -170,6 +157,21 @@ public class PlotVisualizer extends ControlEditor { return canvas; } + /** Apply chart style. */ + @SuppressWarnings("restriction") + private void applyChartStyle() { + // Apply theme. + XYStyler styler = chart.getStyler(); + Theme theme = EclipseThemeUtils.isDarkThemeInUse() ? new PlotVisualizerDarkTheme() + : new PlotVisualizerLightTheme(); + styler.setTheme(theme); + + // Set styling not set by themes. + styler.setAntiAlias(true); + styler.setLegendLayout(LegendLayout.Horizontal); + styler.setYAxisLabelAlignment(TextAlignment.Centre); + } + /** * Notifies the chart that updates have finished on {@link #varDatas} and {@link #rangeX}, and a redraw is needed. */ diff --git a/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizerDarkTheme.java b/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizerDarkTheme.java new file mode 100644 index 0000000000000000000000000000000000000000..31998256137fe109abfb8719cf7f80fc19f80a15 --- /dev/null +++ b/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizerDarkTheme.java @@ -0,0 +1,71 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2022 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available +// under the terms of the MIT License which is available at +// https://opensource.org/licenses/MIT +// +// SPDX-License-Identifier: MIT +////////////////////////////////////////////////////////////////////////////// + +package org.eclipse.escet.cif.simulator.output.plotviz; + +import java.awt.Color; + +/** + * Plot visualizer dark theme. + * + *

+ * This dark theme extends the {@link PlotVisualizerLightTheme light theme} and should only override its colors. Other + * changes should be applied to the light theme, to keep the light and dark themes consistent. + *

+ */ +public class PlotVisualizerDarkTheme extends PlotVisualizerLightTheme { + @Override + public Color getAxisTickLabelsColor() { + return getChartFontColor(); + } + + @Override + public Color getAxisTickMarksColor() { + return getChartFontColor(); + } + + @Override + public Color getChartBackgroundColor() { + return new Color(32, 32, 32); + } + + @Override + public Color getChartFontColor() { + return new Color(240, 240, 240); + } + + @Override + public Color getLegendBackgroundColor() { + return getChartBackgroundColor(); + } + + @Override + public Color getLegendBorderColor() { + return getChartFontColor(); + } + + @Override + public Color getPlotBackgroundColor() { + return new Color(16, 16, 16); + } + + @Override + public Color getPlotBorderColor() { + return getChartFontColor(); + } + + @Override + public Color getPlotGridLinesColor() { + return new Color(42, 42, 42); + } +} diff --git a/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizerLightTheme.java b/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizerLightTheme.java new file mode 100644 index 0000000000000000000000000000000000000000..6db885b1397234e9ba96631c6c23267f2cbbe58e --- /dev/null +++ b/cif/org.eclipse.escet.cif.simulator/src/org/eclipse/escet/cif/simulator/output/plotviz/PlotVisualizerLightTheme.java @@ -0,0 +1,89 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2022 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available +// under the terms of the MIT License which is available at +// https://opensource.org/licenses/MIT +// +// SPDX-License-Identifier: MIT +////////////////////////////////////////////////////////////////////////////// + +package org.eclipse.escet.cif.simulator.output.plotviz; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Stroke; + +import org.knowm.xchart.style.MatlabTheme; +import org.knowm.xchart.style.Styler.LegendPosition; +import org.knowm.xchart.style.colors.ChartColor; +import org.knowm.xchart.style.lines.SeriesLines; +import org.knowm.xchart.style.markers.Marker; +import org.knowm.xchart.style.markers.SeriesMarkers; + +/** Plot visualizer light theme. */ +public class PlotVisualizerLightTheme extends MatlabTheme { + @Override + public int getChartPadding() { + return 15; + } + + @Override + public Color getLegendBorderColor() { + return ChartColor.getAWTColor(ChartColor.DARK_GREY); + } + + @Override + public Font getLegendFont() { + return getAxisTitleFont(); + } + + @Override + public int getLegendPadding() { + return 7; + } + + @Override + public LegendPosition getLegendPosition() { + return LegendPosition.OutsideS; + } + + @Override + public double getPlotContentSize() { + return 1.0; + } + + @Override + public Color getPlotGridLinesColor() { + return new Color(235, 235, 235); + } + + @Override + public Stroke getPlotGridLinesStroke() { + return new BasicStroke(); + } + + @Override + public Color getPlotBackgroundColor() { + return new Color(252, 252, 252); + } + + @Override + public Marker[] getSeriesMarkers() { + return new Marker[] {SeriesMarkers.NONE}; + } + + @Override + public BasicStroke[] getSeriesLines() { + return new BasicStroke[] {SeriesLines.SOLID}; + } + + @Override + public Color[] getSeriesColors() { + return MaterialUiColors600.COLORS; + } +} diff --git a/common/org.eclipse.escet.common.app.framework.appsview.ui/src/org/eclipse/escet/common/app/framework/appsview/ui/commands/AppStatusLegendDialog.java b/common/org.eclipse.escet.common.app.framework.appsview.ui/src/org/eclipse/escet/common/app/framework/appsview/ui/commands/AppStatusLegendDialog.java index d6cd6e3971f1d5f1a45cda59dedc8be2e30e7944..568d58d3551574ded5330796bde61b7ce0a9b52e 100644 --- a/common/org.eclipse.escet.common.app.framework.appsview.ui/src/org/eclipse/escet/common/app/framework/appsview/ui/commands/AppStatusLegendDialog.java +++ b/common/org.eclipse.escet.common.app.framework.appsview.ui/src/org/eclipse/escet/common/app/framework/appsview/ui/commands/AppStatusLegendDialog.java @@ -27,14 +27,13 @@ import org.eclipse.swt.events.TraverseEvent; import org.eclipse.swt.events.TraverseListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeItem; /** Application status legend dialog. */ public class AppStatusLegendDialog extends Dialog { @@ -56,20 +55,19 @@ public class AppStatusLegendDialog extends Dialog { protected Control createDialogArea(Composite parent) { // Get dialog area. Composite area = (Composite)super.createDialogArea(parent); - area.setLayout(new FillLayout()); - - // Add background. - Composite background = new Composite(area, SWT.BORDER); - background.setLayout(new GridLayout()); - - // Put a tree in the center. - Tree tree = new Tree(background, SWT.NO_SCROLL); - tree.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true)); - - // Set background color, same as background of tree. - background.setBackground(tree.getBackground()); - - // Add items for each status, with the proper icon. + area.setLayout(new GridLayout()); + + // Add centered composite. + Composite center = new Composite(area, SWT.NONE); + center.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true)); + GridLayout centerLayout = new GridLayout(2, false); + centerLayout.marginWidth = 8; + centerLayout.marginHeight = 8; + centerLayout.horizontalSpacing = 8; + centerLayout.verticalSpacing = 8; + center.setLayout(centerLayout); + + // Add each status. for (AppStatus status: AppStatus.values()) { // Get icon for status. Image icon = icons.getIcon(status); @@ -77,18 +75,20 @@ public class AppStatusLegendDialog extends Dialog { continue; } - // Add item to tree. - TreeItem item = new TreeItem(tree, SWT.NONE); - item.setImage(icon); + // Add canvas for icon. + Canvas canvas = new Canvas(center, SWT.NO_REDRAW_RESIZE); + canvas.addPaintListener(e -> e.gc.drawImage(icon, 0, 0)); + canvas.setLayoutData(new GridData(icon.getBounds().width, icon.getBounds().height)); - // Set item text. + // Add label for description. + Label label = new Label(center, SWT.NONE); String text = status.toString().toLowerCase(Locale.US); text = StringUtils.capitalize(text); - item.setText(text); + label.setText(text); } // Resize shell a bit wider, to make sure the title is fully shown. - Point size = tree.computeSize(SWT.DEFAULT, SWT.DEFAULT); + Point size = center.computeSize(SWT.DEFAULT, SWT.DEFAULT); parent.getShell().setMinimumSize((int)(size.x * 2.5), 50); // Return the dialog area. diff --git a/common/org.eclipse.escet.common.app.framework/src/org/eclipse/escet/common/app/framework/console/Console.java b/common/org.eclipse.escet.common.app.framework/src/org/eclipse/escet/common/app/framework/console/Console.java index be64d4bc257952d8ed5bc4942832a632d3f310d5..518ebfdbc4026c496c4ba1930dfb34a78fdf25f7 100644 --- a/common/org.eclipse.escet.common.app.framework/src/org/eclipse/escet/common/app/framework/console/Console.java +++ b/common/org.eclipse.escet.common.app.framework/src/org/eclipse/escet/common/app/framework/console/Console.java @@ -14,6 +14,8 @@ package org.eclipse.escet.common.app.framework.console; import org.eclipse.escet.common.app.framework.Application; +import org.eclipse.escet.common.app.framework.eclipse.themes.EclipseThemePreferenceChangeListener; +import org.eclipse.escet.common.app.framework.eclipse.themes.EclipseThemeUtils; import org.eclipse.escet.common.app.framework.io.AppStream; import org.eclipse.escet.common.app.framework.io.AppStreams; import org.eclipse.escet.common.app.framework.io.EclipseConsoleAppStream; @@ -38,14 +40,14 @@ import org.eclipse.ui.console.IOConsoleOutputStream; * console from a plug-in? */ public class Console extends IOConsole { - /** The color to use for the input stream. */ - private static final Color COLOR_IN = new Color(0, 200, 125); + /** Console input stream. */ + private final IOConsoleInputStream inputStream; - /** The color to use for the output stream. */ - private static final Color COLOR_OUT = new Color(0, 0, 0); + /** Console output stream. */ + private final IOConsoleOutputStream outputStream; - /** The color to use for the error stream. */ - private static final Color COLOR_ERR = new Color(255, 0, 0); + /** Console error stream. */ + private final IOConsoleOutputStream errorStream; /** * The console streams. The input stream reader uses a default buffer size, and a default character encoding. The @@ -67,6 +69,9 @@ public class Console extends IOConsole { */ private ConsolePageParticipant consolePageParticipant; + /** The Eclipse theme preference change listener. */ + private EclipseThemePreferenceChangeListener themeListener; + /** * Constructor for the {@link Console} class. * @@ -76,19 +81,18 @@ public class Console extends IOConsole { super(title, null); // Get input stream, and construct the output and error streams. - IOConsoleInputStream in = getInputStream(); - IOConsoleOutputStream out = newOutputStream(); - IOConsoleOutputStream err = newOutputStream(); + inputStream = getInputStream(); + outputStream = newOutputStream(); + errorStream = newOutputStream(); // Set stream colors. - in.setColor(COLOR_IN); - out.setColor(COLOR_OUT); - err.setColor(COLOR_ERR); + themeListener = new EclipseThemePreferenceChangeListener(e -> setStreamColors()); + setStreamColors(); // Save streams. - AppStream appOut = new EclipseConsoleAppStream(out); - AppStream appErr = new EclipseConsoleAppStream(err); - streams = new AppStreams(in, appOut, appErr); + AppStream appOut = new EclipseConsoleAppStream(outputStream); + AppStream appErr = new EclipseConsoleAppStream(errorStream); + streams = new AppStreams(inputStream, appOut, appErr); // Register the console with the console manager, and show it. IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager(); @@ -96,6 +100,19 @@ public class Console extends IOConsole { manager.showConsoleView(this); } + /** Set the console stream colors. */ + private void setStreamColors() { + if (EclipseThemeUtils.isDarkThemeInUse()) { + inputStream.setColor(new Color(0, 200, 125)); + outputStream.setColor(new Color(240, 240, 240)); + errorStream.setColor(new Color(255, 97, 97)); + } else { + inputStream.setColor(new Color(0, 200, 125)); + outputStream.setColor(new Color(0, 0, 0)); + errorStream.setColor(new Color(255, 0, 0)); + } + } + /** * Sets the console page participant. Should only be called by the {@link ConsolePageParticipant#init} method. * @@ -192,4 +209,13 @@ public class Console extends IOConsole { this.application = null; this.consolePageParticipant = null; } + + @Override + protected void dispose() { + // Unregister theme listener. + themeListener.unregister(); + + // Perform normal dispose. + super.dispose(); + } } diff --git a/org.eclipse.escet.setup b/org.eclipse.escet.setup index 9fbebb9370b1fe9cbd8e9f37d9a50cc47619ddac..0e3dfb1ff9aa3290a36ecf083f3cc9cb7c8dde73 100644 --- a/org.eclipse.escet.setup +++ b/org.eclipse.escet.setup @@ -184,6 +184,18 @@ xsi:type="setup:PreferenceTask" key="/instance/org.eclipse.ui.editors/net.sf.eclipsecs.warning.color" value="255,196,0"/> + + +