Merge branch 'unstable' into 3D-export

# Conflicts:
#	swing/src/net/sf/openrocket/gui/dialogs/AboutDialog.java
#	swing/src/net/sf/openrocket/gui/util/SwingPreferences.java
This commit is contained in:
SiboVG 2023-08-21 02:44:58 +02:00
commit 8956aa1e52
19 changed files with 594 additions and 132 deletions

View File

@ -406,7 +406,8 @@ PreferencesOptionPanel.checkbox.windowInfo = Export window information (position
PreferencesOptionPanel.checkbox.windowInfo.ttip = If unchecked, window information (position, size\u2026) will not be exported.
! UI Themes
UITheme.Light = Light (Default)
UITheme.Auto = Auto (detect)
UITheme.Light = Light (default)
UITheme.Dark = Dark
! Welcome dialog

View File

@ -11,6 +11,13 @@
<classpathentry kind="lib" path="lib/iText-5.0.2.jar"/>
<classpathentry kind="lib" path="lib/jcommon-1.0.18.jar"/>
<classpathentry kind="lib" path="lib/jfreechart-1.0.15.jar"/>
<classpathentry kind="lib" path="lib/jSystemThemeDetector-3.8.jar"/>
<classpathentry kind="lib" path="lib/oshi-core-6.4.4.jar"/>
<classpathentry kind="lib" path="lib/jna-5.13.0.jar"/>
<classpathentry kind="lib" path="lib/jna-platform-5.13.0.jar"/>
<classpathentry kind="lib" path="lib/annotations-24.0.1.jar"/>
<classpathentry kind="lib" path="lib/jfa-1.2.0.jar"/>
<classpathentry kind="lib" path="lib/versioncompare-1.4.1.jar"/>
<classpathentry kind="lib" path="lib/darklaf/*.jar"/>
<classpathentry kind="lib" path="lib/jogl/gluegen-rt.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/OpenRocket Core"/>

View File

@ -5,6 +5,13 @@
<libelement value="jar://$MODULE_DIR$/lib/iText-5.0.2.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/jcommon-1.0.18.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/jfreechart-1.0.15.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/jSystemThemeDetector-3.8.jar!/" />$
<libelement value="jar://$MODULE_DIR$/lib/oshi-core-6.4.4.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/jna-5.13.0.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/jna-platform-5.13.0.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/annotations-24.0.1.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/jfa-1.2.0.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/versioncompare-1.4.1.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/darklaf/*.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/OrangeExtensions-1.2.jar!/" />
<libelement value="jar://$MODULE_DIR$/lib/jogl/gluegen-rt.jar!/" />
@ -109,9 +116,63 @@
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="flatlaf-3.1.1.jar">
<library name="jSystemThemeDetector-3.8.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/flatlaf-3.1.1.jar!/" />
<root url="jar://$MODULE_DIR$/lib/jSystemThemeDetector-3.8.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="oshi-core-6.4.4.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/oshi-core-6.4.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="jna-5.13.0.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/jna-5.13.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="jna-platform-5.13.0.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/jna-platform-5.13.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="versioncompare-1.4.1.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/versioncompare-1.4.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="annotations-24.0.1.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/annotations-24.0.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="jfa-1.2.0.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/jfa-1.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

View File

@ -116,6 +116,13 @@
<zipfileset src="${core.dir}/lib/jaxb-runtime.2.3.1.jar"/>
<zipfileset src="${lib.dir}/jcommon-1.0.18.jar"/>
<zipfileset src="${lib.dir}/jfreechart-1.0.15.jar"/>
<zipfileset src="${lib.dir}/jSystemThemeDetector-3.8.jar"/>
<zipfileset src="${lib.dir}/oshi-core-6.4.4.jar"/>
<zipfileset src="${lib.dir}/jna-5.13.0.jar"/>
<zipfileset src="${lib.dir}/jna-platform-5.13.0.jar"/>
<zipfileset src="${lib.dir}/annotations-24.0.1.jar"/>
<zipfileset src="${lib.dir}/jfa-1.2.0.jar"/>
<zipfileset src="${lib.dir}/versioncompare-1.4.1.jar"/>
<zipfileset src="${lib.dir}/darklaf/darklaf-compatibility-3.0.3-SNAPSHOT.jar"/>
<zipfileset src="${lib.dir}/darklaf/darklaf-core-3.0.3-SNAPSHOT.jar"/>
<zipfileset src="${lib.dir}/darklaf/darklaf-iconset-3.0.3-SNAPSHOT.jar"/>

Binary file not shown.

Binary file not shown.

BIN
swing/lib/jfa-1.2.0.jar Normal file

Binary file not shown.

BIN
swing/lib/jna-5.13.0.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -75,9 +75,10 @@ public class AboutDialog extends JDialog {
"Simple Logging Facade for Java" + href("http://www.slf4j.org", true, true) + "<br>" +
"Java library for parsing and rendering CommonMark" + href("https://github.com/commonmark/commonmark-java", true, true) + "<br>" +
"RSyntaxTextArea" + href("http://bobbylight.github.io/RSyntaxTextArea", true, true) + "<br>" +
"Darklaf (dark theme)" + href("https://github.com/weisJ/darklaf", true, true) + "<br>" +
"Darklaf (dark theme)" + href("https://github.com/weisJ/darklaf", true, true) + "<br>" +
"jSystemThemeDetector" + href("https://github.com/Dansoftowner/jSystemThemeDetector", true, true) + "<br>" +
"Obj" + href("https://github.com/javagl/Obj", true, true) + "<br>" +
"<br>" +
"<br>" +
"<b>OpenRocket gratefully acknowledges our use of the following databases:</b><br>" +
"<br>" +
"Rocket Motor Data" + href("https://www.thrustcurve.org", true, true) + "<br>" +

View File

@ -1,5 +1,6 @@
package net.sf.openrocket.gui.dialogs.motor.thrustcurve;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
@ -16,6 +17,7 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@ -144,26 +146,25 @@ public abstract class MotorFilterPanel extends JPanel {
// Manufacturer selection
JPanel sub = new JPanel(new MigLayout("fill"));
TitledBorder border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.MANUFACTURER"));
Border templateBorder = GUIUtil.getUITheme().getBorder();
TitledBorder border = BorderFactory.createTitledBorder(templateBorder);
border.setTitle(trans.get("TCurveMotorCol.MANUFACTURER"));
GUIUtil.changeFontStyle(border, Font.BOLD);
sub.setBorder(border);
this.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
List<Manufacturer> manufacturers = new ArrayList<Manufacturer>();
for (Manufacturer m : allManufacturers) {
manufacturers.add(m);
}
List<Manufacturer> manufacturers = new ArrayList<>(allManufacturers);
Collections.sort(manufacturers, new Comparator<Manufacturer>() {
@Override
public int compare(Manufacturer o1, Manufacturer o2) {
return o1.getSimpleName().compareTo( o2.getSimpleName());
}
manufacturers.sort(new Comparator<Manufacturer>() {
@Override
public int compare(Manufacturer o1, Manufacturer o2) {
return o1.getSimpleName().compareTo(o2.getSimpleName());
}
});
});
manufacturerCheckList = new CheckList.Builder().<Manufacturer>build();
manufacturerCheckList = new CheckList.Builder().build();
manufacturerCheckList.setData(manufacturers);
manufacturerCheckList.setUncheckedItems(unselectedManusFromPreferences);
@ -184,7 +185,12 @@ public abstract class MotorFilterPanel extends JPanel {
}
});
sub.add(new JScrollPane(manufacturerCheckList.getList()), "grow, pushy, wrap");
JScrollPane scrollPane = new JScrollPane(manufacturerCheckList.getList());
Border border1 = GUIUtil.getUITheme().getBorder();
if (border1 != null) {
scrollPane.setBorder(border1);
}
sub.add(scrollPane, "grow, pushy, wrap");
JButton clearMotors = new SelectColorButton(trans.get("TCMotorSelPan.btn.checkNone"));
clearMotors.addActionListener( new ActionListener() {
@ -213,7 +219,8 @@ public abstract class MotorFilterPanel extends JPanel {
// Total Impulse selection
{
sub = new JPanel(new MigLayout("fill"));
border = BorderFactory.createTitledBorder(trans.get("TCurveMotorCol.TOTAL_IMPULSE"));
border = BorderFactory.createTitledBorder(templateBorder);
border.setTitle(trans.get("TCurveMotorCol.TOTAL_IMPULSE"));
GUIUtil.changeFontStyle(border, Font.BOLD);
sub.setBorder(border);
@ -240,7 +247,8 @@ public abstract class MotorFilterPanel extends JPanel {
// Motor Dimensions
sub = new JPanel(new MigLayout("fill"));
TitledBorder diameterTitleBorder = BorderFactory.createTitledBorder(trans.get("TCMotorSelPan.MotorSize"));
TitledBorder diameterTitleBorder = BorderFactory.createTitledBorder(templateBorder);
diameterTitleBorder.setTitle(trans.get("TCMotorSelPan.MotorSize"));
GUIUtil.changeFontStyle(diameterTitleBorder, Font.BOLD);
sub.setBorder(diameterTitleBorder);

View File

@ -159,6 +159,7 @@ class MotorInformationPanel extends JPanel {
comment = new JTextArea(5, 5);
comment.setBorder(GUIUtil.getUITheme().getBorder());
GUIUtil.changeFontSize(comment, -2);
withCommentFont = comment.getFont();
noCommentFont = withCommentFont.deriveFont(Font.ITALIC);

View File

@ -45,6 +45,7 @@ import javax.swing.event.RowSorterListener;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import net.sf.openrocket.gui.util.UITheme;
import net.sf.openrocket.util.StateChangeListener;
import org.jfree.chart.ChartColor;
import org.slf4j.Logger;
@ -332,11 +333,10 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec
// Number of motors
{
nrOfMotorsLabel = new JLabel();
nrOfMotorsLabel = new StyledLabel(-2f, StyledLabel.Style.ITALIC);
nrOfMotorsLabel.setToolTipText(trans.get("TCMotorSelPan.lbl.ttip.nrOfMotors"));
updateNrOfMotors();
nrOfMotorsLabel.setForeground(Color.darkGray);
nrOfMotorsLabel.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, 11));
nrOfMotorsLabel.setForeground(GUIUtil.getUITheme().getDimTextColor());
panel.add(nrOfMotorsLabel, "gapleft para, spanx, wrap");
sorter.addRowSorterListener(new RowSorterListener() {
@Override

View File

@ -21,7 +21,6 @@ import net.sf.openrocket.util.Color;
import com.jogamp.opengl.util.texture.Texture;
public class RealisticRenderer extends RocketRenderer {
private final float[] colorClear = { 0, 0, 0, 0 };
private final float[] colorWhite = { 1, 1, 1, 1 };
private final float[] color = new float[4];
@ -165,7 +164,7 @@ public class RealisticRenderer extends RocketRenderer {
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, toEdgeMode(t.getEdgeMode()));
gl.glTexParameterfv(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_BORDER_COLOR, colorClear, 0);
gl.glTexParameterfv(GL.GL_TEXTURE_2D, GL2.GL_TEXTURE_BORDER_COLOR, convertedColor, 0);
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, colorWhite, 0);
gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, colorWhite, 0);

View File

@ -6,6 +6,8 @@ import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.awt.image.BufferedImage;
@ -28,6 +30,7 @@ import net.sf.openrocket.rocketcomponent.RailButton;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.MathUtil;
/**
* This is the core Swing representation of a fin marking guide. It can handle multiple fin and/or tube fin sets
@ -239,13 +242,16 @@ public class FinMarkingGuide extends JPanel {
private void paintFinMarkingGuide(Graphics2D g2) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.BLACK);
final Color lineColor = Color.BLACK;
g2.setColor(lineColor);
g2.setStroke(thinStroke);
int x = MARGIN;
int y = MARGIN;
int width = (int) PrintUnit.INCHES.toPoints(DEFAULT_GUIDE_WIDTH);
int length;
int column = 0;
@ -255,8 +261,8 @@ public class FinMarkingGuide extends JPanel {
List<ExternalComponent> componentList = markingGuideItems.get(next);
//Don't draw the lug if there are no fins.
if (hasFins(componentList)) {
drawMarkingGuide(g2, x, y, (int) Math.ceil(circumferenceInPoints), width);
length = (int) Math.ceil(circumferenceInPoints);
drawMarkingGuide(g2, x, y, length, width);
double radialOrigin = findRadialOrigin(componentList);
@ -284,13 +290,121 @@ public class FinMarkingGuide extends JPanel {
while (angle > TWO_PI) {
angle -= TWO_PI;
}
int offset = (int) Math.round(y + angle / TWO_PI * circumferenceInPoints);
drawDoubleArrowLine(g2, x, offset, x + width, offset);
// if (hasMultipleComponents) {
g2.drawString(externalComponent.getName(), x + (width / 3), offset - 2);
// }
final int yFinCenter = (int) Math.round(y + angle / TWO_PI * circumferenceInPoints);
final int yStart;
final int yEnd;
// Account for canted fins
/*
The arrow will be rotated around the aft base end of the fin.
This is because the aft end will most likely be at the aft end of the body tube.
If we were to rotate around the fore end, there's a good chance that the marking guide
extends beyond the body tube aft end and thus you cannot draw the arrow.
*/
final double cantAngle = fins.getCantAngle();
final boolean isCanted = !MathUtil.equals(cantAngle, 0);
if (isCanted) {
// We want to end the arrow at the aft end of the fin, so we need add an offset to
// the end to account for the y-shift of the aft end of the fin due to the cant.
final double finBaseHalfWidth = PrintUnit.METERS.toPoints(fins.getLength()) / 2;
final int yFinForeEndOffset = - (int) Math.round(finBaseHalfWidth * Math.sin(cantAngle));
yStart = yFinCenter + yFinForeEndOffset;
// Calculate y offset of end point
int yOffset = (int) Math.round(width * Math.tan(cantAngle));
yEnd = yStart + yOffset;
} else {
yStart = yFinCenter;
yEnd = yFinCenter;
}
// Draw double arrow
drawDoubleArrowLine(g2, x, yStart, x + width, yEnd, cantAngle);
// Draw horizontal dotted line where fin aft end is, vertical dotted line where the fore end is
// and cross at the fin center
if (isCanted) {
//// -- Aft end dashed line
// Dashed stroke settings
float originalLineWidth = thinStroke.getLineWidth();
float[] dashPattern = {10, 10}; // 10 pixel dash, 10 pixel space
Stroke dashedStroke = new BasicStroke(
originalLineWidth,
thinStroke.getEndCap(),
thinStroke.getLineJoin(),
thinStroke.getMiterLimit(),
dashPattern,
0
);
// Set color and stroke
g2.setColor(new Color(200, 200, 200));
g2.setStroke(dashedStroke);
// Draw aft end horizontal dashed line
// We draw from right to left to ensure that the side where the side does not touch
// with an arrow point (fore end) has the dashed line touching the marking guide edge
// (is useful for marking the fin position)
g2.drawLine(x + width, yStart, x, yStart);
//// -- Fore end dashed line
// Dashed stroke settings
dashPattern = new float[] {4, 6}; // 4 pixel dash, 6 pixel space
dashedStroke = new BasicStroke(
originalLineWidth * 0.7f,
thinStroke.getEndCap(),
thinStroke.getLineJoin(),
thinStroke.getMiterLimit(),
dashPattern,
0
);
// Set color and stroke
g2.setColor(new Color(220, 220, 220));
g2.setStroke(dashedStroke);
// Draw fore end vertical dashed line
final int finBaseWidth = (int) PrintUnit.METERS.toPoints(fins.getLength());
if (finBaseWidth < width) {
g2.drawLine(x + finBaseWidth, y, x + finBaseWidth, y + length);
}
// Reset stroke
g2.setStroke(thinStroke);
//// -- Cross
final double finBaseHalfWidth = PrintUnit.METERS.toPoints(fins.getLength()) / 2;
// The cant also has an x-shift. We want the aft end to be perfectly flush with the
// left of the marking guide, so apply an x-shift to fin center position
int xFinCenter = x + (int) Math.round(finBaseHalfWidth);
int xFinCenterOffset = - (int) Math.round(finBaseHalfWidth * (1 - Math.cos(cantAngle)));
xFinCenter += xFinCenterOffset;
// Draw a cross where the center of the fin should be
int crossSize = 3;
g2.drawLine(xFinCenter-crossSize, yFinCenter-crossSize, xFinCenter+crossSize, yFinCenter+crossSize);
g2.drawLine(xFinCenter-crossSize, yFinCenter+crossSize, xFinCenter+crossSize, yFinCenter-crossSize);
// Reset color
g2.setColor(lineColor);
}
// Draw fin name
final int xText = x + (width / 3);
int yText = yStart - 2;
if (isCanted) {
int yTextOffset = (int) Math.round((xText - x) * Math.tan(cantAngle));
yText += yTextOffset;
AffineTransform orig = g2.getTransform();
g2.rotate(cantAngle, xText, yText); // Rotate text for canted fins
g2.drawString(externalComponent.getName(), xText, yText);
g2.setTransform(orig); // Stop rotation
} else {
g2.drawString(externalComponent.getName(), xText, yText);
}
}
}
// END If FinSet instance
@ -318,9 +432,7 @@ public class FinMarkingGuide extends JPanel {
int offset = (int) Math.round(y + angle / TWO_PI * circumferenceInPoints);
drawDoubleArrowLine(g2, x, offset, x + width, offset);
// if (hasMultipleComponents) {
g2.drawString(externalComponent.getName(), x + (width / 3), offset - 2);
// }
}
}
// END If TubeFinSet instance
@ -354,9 +466,9 @@ public class FinMarkingGuide extends JPanel {
// END If RailButton instance
}
// Only if the tube has a lug or button or multiple fin and/or tube fin sets does the orientation of
// the marking guide matter. So print 'Front'.
// the marking guide matter. So print 'Fore end'.
if (hasMultipleComponents) {
drawFrontIndication(g2, x, y, 0, (int) circumferenceInPoints, width);
drawFrontIndication(g2, x, y + length, width);
}
// At most, two marking guides horizontally. After that, move down and back to the left margin.
@ -505,36 +617,131 @@ public class FinMarkingGuide extends JPanel {
g2.drawLine(x + fromEdge, y + length - tickLength, x + fromEdge, y + length);
//Lower right
g2.drawLine(x + width - fromEdge, y + length - tickLength, x + width - fromEdge, y + length);
drawFrontIndication(g2, x, y + length, width);
}
/**
* Draw a vertical string indicating the front of the rocket. This is necessary when a launch lug and/or
* Draw a tab indicating the fore end of the rocket. This is necessary when a launch lug and/or
* rail button exists to give proper orientation of the guide (assuming that the lug and/or button is
* asymmetrically positioned with respect to a fin).
* asymmetrically positioned with respect to a fin). Also necessary for canted fins.
*
* @param g2 the graphics context
* @param x the starting x coordinate
* @param y the starting y coordinate
* @param spacing the space between fin lines
* @param length the length, or height, in print units of the marking guide; should be equivalent to the outer tube
* circumference
* @param width the width of the marking guide in print units; somewhat arbitrary
*/
private void drawFrontIndication(Graphics2D g2, int x, int y, int spacing, int length, int width) {
//The magic numbers here are fairly arbitrary. They're chosen in a manner that best positions 'Front' to be
//readable, without going to complex string layout prediction logic.
int rotateX = x + width - 16;
int rotateY = y + (int) (spacing * 1.5) + 20;
if (rotateY > y + length + 14) {
rotateY = y + length / 2 - 10;
}
g2.translate(rotateX, rotateY);
g2.rotate(Math.PI / 2);
g2.drawString(trans.get("FinMarkingGuide.lbl.Front"), 0, 0);
g2.rotate(-Math.PI / 2);
g2.translate(-rotateX, -rotateY);
private void drawFrontIndication(Graphics2D g2, int x, int y, int width) {
// Draw a tab at the bottom of the marking guide to indicate the fore end of the rocket
int tabWidth = (int) Math.round(width * 0.8);
int tabSpacing = (width - tabWidth) / 2;
int tabHeight = 20;
float strokeWidth = 1.0f;
float strokeOffset = thinStroke.getLineWidth() / 2; // Offset to not draw over the marking guide stroke
Stroke origStroke = g2.getStroke();
Stroke stroke = new BasicStroke(strokeWidth, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL);
g2.setStroke(stroke);
// Draw the tab outline
Path2D tab = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
tab.moveTo(x, y + strokeOffset);
tab.lineTo(x + width, y + strokeOffset);
tab.lineTo(x + width - tabSpacing, y + tabHeight);
tab.lineTo(x + tabSpacing, y + tabHeight);
tab.closePath();
g2.draw(tab);
// Reset the stroke
g2.setStroke(origStroke);
// Fill in the tab
Color color = g2.getColor();
g2.setColor(new Color(220, 220, 220));
g2.fill(tab);
g2.setColor(color);
// Draw an arrow to the left and the text "Fore"
final int arrowXStart = x + width - tabSpacing - 5;
final int arrowWidth = 50;
final int arrowY = y + (tabHeight / 2);
final int textY = arrowY + g2.getFontMetrics().getHeight() / 2 - 3;
drawRightArrowLine(g2, arrowXStart - arrowWidth, arrowY, arrowXStart, arrowY);
String frontText = trans.get("FinMarkingGuide.lbl.Front");
final int textWidth = g2.getFontMetrics().stringWidth(frontText);
g2.drawString(frontText, arrowXStart - arrowWidth - textWidth - 3, textY);
}
/**
* Draw a horizontal line with arrows on only the right endpoint.
*
* @param g2 the graphics context
* @param x1 the starting x coordinate
* @param y1 the starting y coordinate
* @param x2 the ending x coordinate
* @param y2 the ending y coordinate
*/
void drawRightArrowLine(Graphics2D g2, int x1, int y1, int x2, int y2) {
drawArrowLine(g2, x1, y1, x2, y2, 0, false, true);
}
/**
* Draw a horizontal line with arrows on both endpoints. Depicts a fin alignment.
*
* @param g2 the graphics context
* @param x1 the starting x coordinate
* @param y1 the starting y coordinate
* @param x2 the ending x coordinate
* @param y2 the ending y coordinate
* @param angle angle to rotate the arrow header to
* @param leftArrow true if the left arrow should be drawn
* @param rightArrow true if the right arrow should be drawn
*/
void drawArrowLine(Graphics2D g2, int x1, int y1, int x2, int y2, double angle, boolean leftArrow, boolean rightArrow) {
int len = x2 - x1;
// Draw line
int xOffset = (int) Math.round(ARROW_SIZE * Math.abs(Math.cos(angle)));
int yOffset = (int) Math.round(ARROW_SIZE * Math.sin(angle));
g2.drawLine(x1 + xOffset, y1 + yOffset, x1 + len - xOffset, y2 - yOffset);
// Rotate for the right arrow
AffineTransform orig = g2.getTransform();
g2.rotate(angle, x1 + len, y2);
// Draw right arrow
if (rightArrow) {
g2.fillPolygon(new int[]{x1 + len, x1 + len - ARROW_SIZE, x1 + len - ARROW_SIZE, x1 + len},
new int[]{y2, y2 - ARROW_SIZE / 2, y2 + ARROW_SIZE / 2, y2}, 4);
}
// Rotate for the left arrow
g2.setTransform(orig);
g2.rotate(angle, x1, y1);
// Draw left arrow
if (leftArrow) {
g2.fillPolygon(new int[]{x1, x1 + ARROW_SIZE, x1 + ARROW_SIZE, x1},
new int[]{y1, y1 - ARROW_SIZE / 2, y1 + ARROW_SIZE / 2, y1}, 4);
}
g2.setTransform(orig);
}
/**
* Draw a horizontal line with arrows on both endpoints. Depicts a fin alignment.
*
* @param g2 the graphics context
* @param x1 the starting x coordinate
* @param y1 the starting y coordinate
* @param x2 the ending x coordinate
* @param y2 the ending y coordinate
* @param angle angle to rotate the arrow header to
*/
void drawDoubleArrowLine(Graphics2D g2, int x1, int y1, int x2, int y2, double angle) {
drawArrowLine(g2, x1, y1, x2, y2, angle, true, true);
}
/**
* Draw a horizontal line with arrows on both endpoints. Depicts a fin alignment.
*
@ -545,13 +752,6 @@ public class FinMarkingGuide extends JPanel {
* @param y2 the ending y coordinate
*/
void drawDoubleArrowLine(Graphics2D g2, int x1, int y1, int x2, int y2) {
int len = x2 - x1;
g2.drawLine(x1, y1, x1 + len, y2);
g2.fillPolygon(new int[] { x1 + len, x1 + len - ARROW_SIZE, x1 + len - ARROW_SIZE, x1 + len },
new int[] { y2, y2 - ARROW_SIZE / 2, y2 + ARROW_SIZE / 2, y2 }, 4);
g2.fillPolygon(new int[] { x1, x1 + ARROW_SIZE, x1 + ARROW_SIZE, x1 },
new int[] { y1, y1 - ARROW_SIZE / 2, y1 + ARROW_SIZE / 2, y1 }, 4);
drawDoubleArrowLine(g2, x1, y1, x2, y2, 0);
}
}

View File

@ -33,10 +33,8 @@ package net.sf.openrocket.gui.util;
import java.awt.Color;
import java.awt.Component;
import java.awt.Rectangle;
import java.io.Serializable;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.JList;
@ -49,7 +47,7 @@ import javax.swing.border.EmptyBorder;
public class CheckListRenderer extends JCheckBox implements ListCellRenderer, Serializable {
private static final Border NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
private static final Border SAFE_NO_FOCUS_BORDER = NO_FOCUS_BORDER; // may change in the feature
private static final Border SAFE_NO_FOCUS_BORDER = NO_FOCUS_BORDER; // may change in the future
/**
* Constructs a default renderer object for an item in a list.
@ -162,66 +160,4 @@ public class CheckListRenderer extends JCheckBox implements ListCellRenderer, Se
}
}
// Methods below are overridden for performance reasons.
@Override
public void validate() {
}
@Override
public void invalidate() {
}
@Override
public void repaint() {
}
@Override
public void revalidate() {
}
@Override
public void repaint(long tm, int x, int y, int width, int height) {
}
@Override
public void repaint(Rectangle r) {
}
@Override
public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {
}
@Override
public void firePropertyChange(String propertyName, char oldValue, char newValue) {
}
@Override
public void firePropertyChange(String propertyName, short oldValue, short newValue) {
}
@Override
public void firePropertyChange(String propertyName, int oldValue, int newValue) {
}
@Override
public void firePropertyChange(String propertyName, long oldValue, long newValue) {
}
@Override
public void firePropertyChange(String propertyName, float oldValue, float newValue) {
}
@Override
public void firePropertyChange(String propertyName, double oldValue, double newValue) {
}
@Override
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
}
@SuppressWarnings("serial")
public static class UIResource extends DefaultListCellRenderer implements javax.swing.plaf.UIResource {
}
}

View File

@ -2,6 +2,7 @@ package net.sf.openrocket.gui.util;
import com.github.weisj.darklaf.LafManager;
import com.github.weisj.darklaf.theme.DarculaTheme;
import com.jthemedetecor.OsThemeDetector;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
@ -10,14 +11,17 @@ import org.slf4j.LoggerFactory;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
public class UITheme {
private static final Translator trans = Application.getTranslator();
@ -527,6 +531,243 @@ public class UITheme {
log.warn("Unable to load RSyntaxTextArea theme", ioe);
}
}
},
AUTO {
private final String displayName = trans.get("UITheme.Auto");
private Theme getCurrentTheme() {
try {
final OsThemeDetector detector = OsThemeDetector.getDetector();
final boolean isDarkThemeUsed = detector.isDark();
if (isDarkThemeUsed) {
return Themes.DARK;
} else {
return Themes.LIGHT;
}
} catch (Exception ignore) {}
return Themes.LIGHT;
}
@Override
public void applyTheme() {
getCurrentTheme().applyTheme();
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public Color getBackgroundColor() {
return getCurrentTheme().getBackgroundColor();
}
@Override
public Color getBorderColor() {
return getCurrentTheme().getBorderColor();
}
@Override
public Color getTextColor() {
return getCurrentTheme().getTextColor();
}
@Override
public Color getDimTextColor() {
return getCurrentTheme().getDimTextColor();
}
@Override
public Color getTextSelectionForegroundColor() {
return getCurrentTheme().getTextSelectionForegroundColor();
}
@Override
public Color getTextSelectionBackgroundColor() {
return getCurrentTheme().getTextSelectionBackgroundColor();
}
@Override
public Color getWarningColor() {
return getCurrentTheme().getWarningColor();
}
@Override
public Color getDarkWarningColor() {
return getCurrentTheme().getDarkWarningColor();
}
@Override
public Color getRowBackgroundLighterColor() {
return getCurrentTheme().getRowBackgroundLighterColor();
}
@Override
public Color getRowBackgroundDarkerColor() {
return getCurrentTheme().getRowBackgroundDarkerColor();
}
@Override
public Color getFlightDataTextActiveColor() {
return getCurrentTheme().getFlightDataTextActiveColor();
}
@Override
public Color getFlightDataTextInactiveColor() {
return getCurrentTheme().getFlightDataTextInactiveColor();
}
@Override
public String getDefaultBodyComponentColor() {
return getCurrentTheme().getDefaultBodyComponentColor();
}
@Override
public String getDefaultTubeFinSetColor() {
return getCurrentTheme().getDefaultTubeFinSetColor();
}
@Override
public String getDefaultFinSetColor() {
return getCurrentTheme().getDefaultFinSetColor();
}
@Override
public String getDefaultLaunchLugColor() {
return getCurrentTheme().getDefaultLaunchLugColor();
}
@Override
public String getDefaultRailButtonColor() {
return getCurrentTheme().getDefaultRailButtonColor();
}
@Override
public String getDefaultInternalComponentColor() {
return getCurrentTheme().getDefaultInternalComponentColor();
}
@Override
public String getDefaultMassObjectColor() {
return getCurrentTheme().getDefaultMassObjectColor();
}
@Override
public String getDefaultRecoveryDeviceColor() {
return getCurrentTheme().getDefaultRecoveryDeviceColor();
}
@Override
public String getDefaultPodSetColor() {
return getCurrentTheme().getDefaultPodSetColor();
}
@Override
public String getDefaultParallelStageColor() {
return getCurrentTheme().getDefaultParallelStageColor();
}
@Override
public Color getMotorBorderColor() {
return getCurrentTheme().getMotorBorderColor();
}
@Override
public Color getMotorFillColor() {
return getCurrentTheme().getMotorFillColor();
}
@Override
public Color getCGColor() {
return getCurrentTheme().getCGColor();
}
@Override
public Color getCPColor() {
return getCurrentTheme().getCPColor();
}
@Override
public Color getURLColor() {
return getCurrentTheme().getURLColor();
}
@Override
public Color getComponentTreeBackgroundColor() {
return getCurrentTheme().getComponentTreeBackgroundColor();
}
@Override
public Color getComponentTreeForegroundColor() {
return getCurrentTheme().getComponentTreeForegroundColor();
}
@Override
public Color getFinPointGridMajorLineColor() {
return getCurrentTheme().getFinPointGridMajorLineColor();
}
@Override
public Color getFinPointGridMinorLineColor() {
return getCurrentTheme().getFinPointGridMinorLineColor();
}
@Override
public Color getFinPointPointColor() {
return getCurrentTheme().getFinPointPointColor();
}
@Override
public Color getFinPointSelectedPointColor() {
return getCurrentTheme().getFinPointSelectedPointColor();
}
@Override
public Color getFinPointBodyLineColor() {
return getCurrentTheme().getFinPointBodyLineColor();
}
@Override
public Icon getMassOverrideIcon() {
return getCurrentTheme().getMassOverrideIcon();
}
@Override
public Icon getMassOverrideSubcomponentIcon() {
return getCurrentTheme().getMassOverrideSubcomponentIcon();
}
@Override
public Icon getCGOverrideIcon() {
return getCurrentTheme().getCGOverrideIcon();
}
@Override
public Icon getCGOverrideSubcomponentIcon() {
return getCurrentTheme().getCGOverrideSubcomponentIcon();
}
@Override
public Icon getCDOverrideIcon() {
return getCurrentTheme().getCDOverrideIcon();
}
@Override
public Icon getCDOverrideSubcomponentIcon() {
return getCurrentTheme().getCDOverrideSubcomponentIcon();
}
@Override
public Border getBorder() {
return getCurrentTheme().getBorder();
}
@Override
public void formatScriptTextArea(RSyntaxTextArea textArea) {
getCurrentTheme().formatScriptTextArea(textArea);
}
}
}