diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index 72f5c27ab..f1ac5016f 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -823,6 +823,14 @@ RocketCompCfg.lbl.Componentname = Component name:
RocketCompCfg.ttip.Thecomponentname = The component name.
RocketCompCfg.tab.Override = Override
RocketCompCfg.tab.MassandCGoverride = Mass and CG override options
+RocketCompCfg.tab.Pod = Pod
+RocketCompCfg.tab.PodComment = Options for locating ExteriorComponents outside the Rocket
+RocketCompCfg.tab.Parallel = Parallel
+RocketCompCfg.tab.ParallelComment = Options for locating Stages parallel to other stages
+RocketCompCfg.parallel.inline = Make this Stage Parallel
+RocketCompCfg.parallel.radius = Radial Distance (meters)
+RocketCompCfg.parallel.angle = Angle (Radians)
+RocketCompCfg.parallel.rotation = Rotation (Radians)
RocketCompCfg.tab.Figure = Figure
RocketCompCfg.tab.Figstyleopt = Figure style options
RocketCompCfg.tab.Comment = Comment
diff --git a/core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java b/core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java
index 48c3e2228..622302737 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java
@@ -131,15 +131,18 @@ public abstract class ExternalComponent extends RocketComponent implements Outsi
fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
}
-
- @Override
public boolean isInline() {
return this.axial;
}
@Override
- public void setInline(final boolean inline) {
- this.axial = inline;
+ public boolean getParallel() {
+ return !this.axial;
+ }
+
+ @Override
+ public void setParallel(final boolean parallel) {
+ this.axial = !parallel;
}
@Override
diff --git a/core/src/net/sf/openrocket/rocketcomponent/OutsideComponent.java b/core/src/net/sf/openrocket/rocketcomponent/OutsideComponent.java
index 23da91663..808c57145 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/OutsideComponent.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/OutsideComponent.java
@@ -9,14 +9,14 @@ public interface OutsideComponent {
* @return True
This component is aligned with its parent
* False
This component is offset from its parent -- like an external pod, or strap-on stage
*/
- public boolean isInline();
+ public boolean getParallel();
/**
* Change whether this component is located inside or outside of the rest of the rocket. (Specifically, inside or outside its parent.)
*
* @param inline True indicates that this component axially aligned with its parent. False indicates an off-center component.
*/
- public void setInline(final boolean inline);
+ public void setParallel(final boolean inline);
/**
* Get the position of this component in polar coordinates
diff --git a/core/src/net/sf/openrocket/rocketcomponent/Stage.java b/core/src/net/sf/openrocket/rocketcomponent/Stage.java
index 9eefdeb48..be87bcce2 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/Stage.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/Stage.java
@@ -14,6 +14,8 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
private double position_radial_m = 0;
private double rotation_rad = 0;
+ // ParallelStagingConfiguration parallelConfiguration = null;
+
public Stage() {
this.separationConfigurations = new FlightConfigurationImpl(this, ComponentChangeEvent.EVENT_CHANGE, new StageSeparationConfiguration());
}
@@ -29,7 +31,9 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
return separationConfigurations;
}
-
+ // public ParallelStagingConfiguration getParallelStageConfiguration() {
+ // return parallelConfiguration;
+ // }
@Override
@@ -66,13 +70,17 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
@Override
- public boolean isInline() {
+ public boolean getParallel() {
+ return !this.axial;
+ }
+
+ public boolean getInline() {
return this.axial;
}
@Override
- public void setInline(final boolean inline) {
- this.axial = inline;
+ public void setParallel(final boolean parallel) {
+ this.axial = !parallel;
}
@Override
@@ -84,8 +92,8 @@ public class Stage extends ComponentAssembly implements FlightConfigurableCompon
}
@Override
- public void setAngularPosition(final double phi) {
- this.position_angular_rad = phi;
+ public void setAngularPosition(final double angle_rad) {
+ this.position_angular_rad = angle_rad;
}
@Override
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
index 30142f4cc..45d222d0f 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
@@ -1,6 +1,8 @@
package net.sf.openrocket.gui.configdialog;
+import java.awt.Component;
+import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
@@ -17,10 +19,14 @@ import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.database.ComponentPresetDatabase;
@@ -41,6 +47,8 @@ import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.OutsideComponent;
+import net.sf.openrocket.rocketcomponent.Stage;
import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.rocketcomponent.RocketComponent;
@@ -65,6 +73,9 @@ public class RocketComponentConfig extends JPanel {
protected JTextArea commentTextArea;
private final TextFieldListener textFieldListener;
+ private BooleanModel podsEnabledModel = null;
+ private JPanel podsEnabledPanel = null;
+
private JPanel buttonPanel;
private JLabel infoLabel;
@@ -115,6 +126,8 @@ public class RocketComponentConfig extends JPanel {
tabbedPane.addTab(trans.get("RocketCompCfg.tab.Comment"), null, commentTab(),
trans.get("RocketCompCfg.tab.Specifyacomment"));
+
+
addButtons();
updateFields();
@@ -146,6 +159,10 @@ public class RocketComponentConfig extends JPanel {
});
buttonPanel.add(closeButton, "right, gap 30lp");
+ if( component instanceof ExternalComponent ){
+ tabbedPane.insertTab( trans.get("RocketCompCfg.tab.Pod"), null, podTab( (ExternalComponent) component ), trans.get("RocketCompCfg.tab.PodComment"), 2);
+ }
+
updateFields();
this.add(buttonPanel, "spanx, growx");
@@ -268,6 +285,53 @@ public class RocketComponentConfig extends JPanel {
return subPanel;
}
+ private JPanel podTab( final ExternalComponent pod ){
+ // enable parallel staging
+ JPanel motherPanel = new JPanel( new MigLayout("fill"));
+ podsEnabledModel = new BooleanModel( component, "Parallel");
+ podsEnabledModel.setValue(false);
+ JCheckBox parallelEnabled = new JCheckBox( podsEnabledModel);
+ parallelEnabled.setText(trans.get("RocketCompCfg.parallel.inline"));
+ motherPanel.add(parallelEnabled, "wrap");
+
+ JPanel enabledPanel = new JPanel( new MigLayout("fill"));
+ this.podsEnabledPanel = enabledPanel;
+
+ enabledPanel.add(new JSeparator(SwingConstants.HORIZONTAL), "growx,wrap");
+
+ // set radial distance
+ enabledPanel.add(new JLabel(trans.get("RocketCompCfg.parallel.radius")), "align left");
+ DoubleModel radiusModel = new DoubleModel( pod, "RadialPosition", 0.);
+ JSpinner radiusSpinner = new JSpinner( radiusModel.getSpinnerModel());
+ radiusSpinner.setEditor(new SpinnerEditor(radiusSpinner ));
+ enabledPanel.add(radiusSpinner , "growx, wrap, align right");
+
+ // set angle around the primary stage
+ enabledPanel.add(new JLabel(trans.get("RocketCompCfg.parallel.angle")), "align left");
+ DoubleModel angleModel = new DoubleModel( pod, "AngularPosition", 0., Math.PI*2);
+ JSpinner angleSpinner = new JSpinner(angleModel.getSpinnerModel());
+ angleSpinner.setEditor(new SpinnerEditor(angleSpinner));
+ enabledPanel.add(angleSpinner, "growx, wrap");
+
+ enabledPanel.add(new JLabel(trans.get("RocketCompCfg.parallel.rotation")), "align left");
+ DoubleModel rotationModel = new DoubleModel( pod, "Rotation", 0.0, Math.PI*2);
+ JSpinner rotationSpinner = new JSpinner(rotationModel.getSpinnerModel());
+ rotationSpinner.setEditor(new SpinnerEditor(rotationSpinner));
+ enabledPanel.add(rotationSpinner, "growx, wrap");
+
+ setDeepEnabled( enabledPanel, podsEnabledModel.getValue());
+ parallelEnabled.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ setDeepEnabled( podsEnabledPanel, podsEnabledModel.getValue());
+ }
+ });
+
+ motherPanel.add( enabledPanel , "growx, wrap");
+
+ return motherPanel;
+ }
+
private JPanel overrideTab() {
JPanel panel = new JPanel(new MigLayout("align 50% 20%, fillx, gap rel unrel",
@@ -569,4 +633,12 @@ public class RocketComponentConfig extends JPanel {
}
+ protected static void setDeepEnabled(Component component, boolean enabled) {
+ component.setEnabled(enabled);
+ if (component instanceof Container) {
+ for (Component c : ((Container) component).getComponents()) {
+ setDeepEnabled(c, enabled);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/StageConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/StageConfig.java
index 70ce149b2..db6f6bd94 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/StageConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/StageConfig.java
@@ -1,18 +1,28 @@
package net.sf.openrocket.gui.configdialog;
+import java.awt.Component;
+import java.awt.Container;
+
+import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
+import javax.swing.JSeparator;
import javax.swing.JSpinner;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.SpinnerEditor;
+import net.sf.openrocket.gui.adaptors.BooleanModel;
import net.sf.openrocket.gui.adaptors.DoubleModel;
import net.sf.openrocket.gui.adaptors.EnumModel;
import net.sf.openrocket.gui.components.StyledLabel;
import net.sf.openrocket.gui.components.StyledLabel.Style;
import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.rocketcomponent.OutsideComponent;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.Stage;
import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration;
@@ -21,6 +31,9 @@ import net.sf.openrocket.startup.Application;
public class StageConfig extends RocketComponentConfig {
private static final Translator trans = Application.getTranslator();
+ private BooleanModel parallelEnabledModel = null;
+ private JPanel parallelEnabledPanel = null;
+
public StageConfig(OpenRocketDocument document, RocketComponent component) {
super(document, component);
@@ -30,9 +43,59 @@ public class StageConfig extends RocketComponentConfig {
tabbedPane.insertTab(trans.get("tab.Separation"), null, tab,
trans.get("tab.Separation.ttip"), 1);
}
-
+
+ // all stage instances should qualify here...
+ if( component instanceof OutsideComponent ){
+ tabbedPane.insertTab( trans.get("RocketCompCfg.tab.Parallel"), null, parallelTab( (Stage) component ), trans.get("RocketCompCfg.tab.ParallelComment"), 2);
+ }
}
+ private JPanel parallelTab( final Stage stage ){
+ // enable parallel staging
+ JPanel motherPanel = new JPanel( new MigLayout("fill"));
+ parallelEnabledModel = new BooleanModel( component, "Parallel");
+ parallelEnabledModel.setValue(false);
+ JCheckBox parallelEnabled = new JCheckBox( parallelEnabledModel);
+ parallelEnabled.setText(trans.get("RocketCompCfg.parallel.inline"));
+ motherPanel.add(parallelEnabled, "wrap");
+
+ JPanel enabledPanel = new JPanel( new MigLayout("fill"));
+ this.parallelEnabledPanel = enabledPanel;
+
+ enabledPanel.add(new JSeparator(SwingConstants.HORIZONTAL), "growx,wrap");
+
+ // set radial distance
+ enabledPanel.add(new JLabel(trans.get("RocketCompCfg.parallel.radius")), "align left");
+ DoubleModel radiusModel = new DoubleModel( stage, "RadialPosition", 0.0);
+ JSpinner radiusSpinner = new JSpinner( radiusModel.getSpinnerModel());
+ radiusSpinner.setEditor(new SpinnerEditor(radiusSpinner ));
+ enabledPanel.add(radiusSpinner , "growx, wrap, align right");
+
+ // set angle around the primary stage
+ enabledPanel.add(new JLabel(trans.get("RocketCompCfg.parallel.angle")), "align left");
+ DoubleModel angleModel = new DoubleModel( stage, "AngularPosition", 0.0, Math.PI*2);
+ JSpinner angleSpinner = new JSpinner(angleModel.getSpinnerModel());
+ angleSpinner.setEditor(new SpinnerEditor(angleSpinner));
+ enabledPanel.add(angleSpinner, "growx, wrap");
+
+ enabledPanel.add(new JLabel(trans.get("RocketCompCfg.parallel.rotation")), "align left");
+ DoubleModel rotationModel = new DoubleModel( stage, "Rotation", 0.0, Math.PI*2);
+ JSpinner rotationSpinner = new JSpinner(rotationModel.getSpinnerModel());
+ rotationSpinner.setEditor(new SpinnerEditor(rotationSpinner));
+ enabledPanel.add(rotationSpinner, "growx, wrap");
+
+ setDeepEnabled( enabledPanel, parallelEnabledModel.getValue());
+ parallelEnabled.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ setDeepEnabled( parallelEnabledPanel, parallelEnabledModel.getValue());
+ }
+ });
+
+ motherPanel.add( enabledPanel , "growx, wrap");
+
+ return motherPanel;
+ }
private JPanel separationTab(Stage stage) {
JPanel panel = new JPanel(new MigLayout("fill"));
@@ -59,5 +122,6 @@ public class StageConfig extends RocketComponentConfig {
return panel;
}
+
}