6f568194268ba1653ea1f223d939bb8f5b94b322
[debian/openrocket] / src / net / sf / openrocket / gui / configdialog / InnerTubeConfig.java
1 package net.sf.openrocket.gui.configdialog;
2
3
4
5 import java.awt.Color;
6 import java.awt.Dimension;
7 import java.awt.Graphics;
8 import java.awt.Graphics2D;
9 import java.awt.Rectangle;
10 import java.awt.RenderingHints;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.ActionListener;
13 import java.awt.event.MouseEvent;
14 import java.awt.event.MouseListener;
15 import java.awt.geom.Ellipse2D;
16 import java.util.List;
17
18 import javax.swing.BorderFactory;
19 import javax.swing.JButton;
20 import javax.swing.JComponent;
21 import javax.swing.JLabel;
22 import javax.swing.JPanel;
23 import javax.swing.JSpinner;
24 import javax.swing.border.BevelBorder;
25 import javax.swing.event.ChangeEvent;
26 import javax.swing.event.ChangeListener;
27
28 import net.miginfocom.swing.MigLayout;
29 import net.sf.openrocket.gui.Resettable;
30 import net.sf.openrocket.gui.SpinnerEditor;
31 import net.sf.openrocket.gui.adaptors.DoubleModel;
32 import net.sf.openrocket.gui.components.BasicSlider;
33 import net.sf.openrocket.gui.components.UnitSelector;
34 import net.sf.openrocket.rocketcomponent.ClusterConfiguration;
35 import net.sf.openrocket.rocketcomponent.Clusterable;
36 import net.sf.openrocket.rocketcomponent.InnerTube;
37 import net.sf.openrocket.rocketcomponent.MotorMount;
38 import net.sf.openrocket.rocketcomponent.RocketComponent;
39 import net.sf.openrocket.unit.UnitGroup;
40
41
42 public class InnerTubeConfig extends ThicknessRingComponentConfig {
43
44
45         public InnerTubeConfig(RocketComponent c) {
46                 super(c);
47                 
48                 JPanel tab;
49                 
50                 tab = positionTab();
51                 tabbedPane.insertTab("Radial position", null, tab, "Radial position", 1);
52                 
53                 tab = new MotorConfig((MotorMount)c);
54                 tabbedPane.insertTab("Motor", null, tab, "Motor mount configuration", 2);
55
56                 tab = clusterTab();
57                 tabbedPane.insertTab("Cluster", null, tab, "Cluster configuration", 3);
58                 
59                 tabbedPane.setSelectedIndex(0);
60         }
61         
62         
63         private JPanel clusterTab() {
64                 JPanel panel = new JPanel(new MigLayout());
65                 
66                 JPanel subPanel = new JPanel(new MigLayout());
67                 
68                 // Cluster type selection
69                 subPanel.add(new JLabel("Select cluster configuration:"),"spanx, wrap");
70                 subPanel.add(new ClusterSelectionPanel((InnerTube)component),"spanx, wrap");
71 //              JPanel clusterSelection = new ClusterSelectionPanel((InnerTube)component);
72 //              clusterSelection.setBackground(Color.blue);
73 //              subPanel.add(clusterSelection);
74                 
75                 panel.add(subPanel);
76                 
77                 
78                 subPanel = new JPanel(new MigLayout("gap rel unrel","[][65lp::][30lp::]"));
79
80                 // Tube separation scale
81                 JLabel l = new JLabel("Tube separation:");
82                 l.setToolTipText("The separation of the tubes, 1.0 = touching each other");
83                 subPanel.add(l);
84                 DoubleModel dm  = new DoubleModel(component,"ClusterScale",1,UnitGroup.UNITS_NONE,0);
85
86                 JSpinner spin = new JSpinner(dm.getSpinnerModel());
87                 spin.setEditor(new SpinnerEditor(spin));
88                 spin.setToolTipText("The separation of the tubes, 1.0 = touching each other");
89                 subPanel.add(spin,"growx");
90                 
91                 BasicSlider bs = new BasicSlider(dm.getSliderModel(0, 1, 4));
92                 bs.setToolTipText("The separation of the tubes, 1.0 = touching each other");
93                 subPanel.add(bs,"skip,w 100lp, wrap");
94
95                 // Rotation
96                 l = new JLabel("Rotation:");
97                 l.setToolTipText("Rotation angle of the cluster configuration");
98                 subPanel.add(l);
99                 dm  = new DoubleModel(component,"ClusterRotation",1,UnitGroup.UNITS_ANGLE,0);
100
101                 spin = new JSpinner(dm.getSpinnerModel());
102                 spin.setEditor(new SpinnerEditor(spin));
103                 spin.setToolTipText("Rotation angle of the cluster configuration");
104                 subPanel.add(spin,"growx");
105                 
106                 subPanel.add(new UnitSelector(dm),"growx");
107                 bs = new BasicSlider(dm.getSliderModel(-Math.PI, 0, Math.PI));
108                 bs.setToolTipText("Rotation angle of the cluster configuration");
109                 subPanel.add(bs,"w 100lp, wrap");
110
111                 // Reset button
112                 JButton reset = new JButton("Reset");
113                 reset.setToolTipText("Reset the separation and rotation to the default values");
114                 reset.addActionListener(new ActionListener() {
115                         @Override
116                         public void actionPerformed(ActionEvent arg0) {
117                                 ((InnerTube)component).setClusterScale(1.0);
118                                 ((InnerTube)component).setClusterRotation(0.0);
119                         }
120                 });
121                 subPanel.add(reset,"spanx,right");
122                 
123                 panel.add(subPanel,"grow");
124                 
125                 
126                 return panel;
127         }
128 }
129
130
131 class ClusterSelectionPanel extends JPanel {
132         private static final int BUTTON_SIZE = 50;
133         private static final int MOTOR_DIAMETER = 10;
134         
135         private static final Color SELECTED_COLOR = Color.RED;
136         private static final Color UNSELECTED_COLOR = Color.WHITE;
137         private static final Color MOTOR_FILL_COLOR = Color.GREEN;
138         private static final Color MOTOR_BORDER_COLOR = Color.BLACK;
139         
140         public ClusterSelectionPanel(Clusterable component) {
141                 super(new MigLayout("gap 0 0",
142                                 "["+BUTTON_SIZE+"!]["+BUTTON_SIZE+"!]["+BUTTON_SIZE+"!]["+BUTTON_SIZE+"!]",
143                                 "["+BUTTON_SIZE+"!]["+BUTTON_SIZE+"!]["+BUTTON_SIZE+"!]"));
144                 
145                 for (int i=0; i<ClusterConfiguration.CONFIGURATIONS.length; i++) {
146                         ClusterConfiguration config = ClusterConfiguration.CONFIGURATIONS[i];
147                         
148                         JComponent button = new ClusterButton(component,config);
149                         if (i%4 == 3) 
150                                 add(button,"wrap");
151                         else
152                                 add(button);
153                 }
154
155         }
156         
157         
158         private class ClusterButton extends JPanel implements ChangeListener, MouseListener,
159                                                                                                                   Resettable {
160                 private Clusterable component;
161                 private ClusterConfiguration config;
162                 
163                 public ClusterButton(Clusterable c, ClusterConfiguration config) {
164                         component = c;
165                         this.config = config;
166                         setMinimumSize(new Dimension(BUTTON_SIZE,BUTTON_SIZE));
167                         setPreferredSize(new Dimension(BUTTON_SIZE,BUTTON_SIZE));
168                         setMaximumSize(new Dimension(BUTTON_SIZE,BUTTON_SIZE));
169                         setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
170 //                      setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
171                         component.addChangeListener(this);
172                         addMouseListener(this);
173                 }
174                 
175
176                 @Override
177                 public void paintComponent(Graphics g) {
178                         super.paintComponent(g);
179                         Graphics2D g2 = (Graphics2D)g;
180                         Rectangle area = g2.getClipBounds();
181                         
182                         if (component.getClusterConfiguration() == config)
183                                 g2.setColor(SELECTED_COLOR);
184                         else
185                                 g2.setColor(UNSELECTED_COLOR);
186                         
187                         g2.fillRect(area.x, area.y, area.width, area.height);
188                         
189                         g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 
190                                         RenderingHints.VALUE_STROKE_NORMALIZE);
191                         g2.setRenderingHint(RenderingHints.KEY_RENDERING, 
192                                         RenderingHints.VALUE_RENDER_QUALITY);
193                         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
194                                         RenderingHints.VALUE_ANTIALIAS_ON);
195                         
196                         List<Double> points = config.getPoints();
197                         Ellipse2D.Float circle = new Ellipse2D.Float();
198                         for (int i=0; i < points.size()/2; i++) {
199                                 double x = points.get(i*2);
200                                 double y = points.get(i*2+1);
201                                 
202                                 double px = BUTTON_SIZE/2 + x*MOTOR_DIAMETER;
203                                 double py = BUTTON_SIZE/2 - y*MOTOR_DIAMETER;
204                                 circle.setFrameFromCenter(px,py,px+MOTOR_DIAMETER/2,py+MOTOR_DIAMETER/2);
205                                 
206                                 g2.setColor(MOTOR_FILL_COLOR);
207                                 g2.fill(circle);
208                                 g2.setColor(MOTOR_BORDER_COLOR);
209                                 g2.draw(circle);
210                         }
211                 }
212
213
214                 public void stateChanged(ChangeEvent e) {
215                         repaint();
216                 }
217
218
219                 public void mouseClicked(MouseEvent e) {
220                         if (e.getButton() == MouseEvent.BUTTON1) {
221                                 component.setClusterConfiguration(config);
222                         }
223                 }
224                 
225                 public void mouseEntered(MouseEvent e) { }
226                 public void mouseExited(MouseEvent e) { }
227                 public void mousePressed(MouseEvent e) { }
228                 public void mouseReleased(MouseEvent e) { }
229
230
231                 public void resetModel() {
232                         component.removeChangeListener(this);
233                         removeMouseListener(this);
234                 }
235         }
236         
237 }