altosui: Don't show the tracker motion value when switching units
[fw/altos] / altosui / AltosConfigPyroUI.java
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package altosui;
19
20 import java.awt.*;
21 import java.awt.event.*;
22 import javax.swing.*;
23 import javax.swing.event.*;
24 import org.altusmetrum.altoslib_5.*;
25 import org.altusmetrum.altosuilib_3.*;
26
27 public class AltosConfigPyroUI
28         extends AltosUIDialog
29         implements ItemListener, DocumentListener, AltosUnitsListener, ActionListener
30 {
31         AltosConfigUI   owner;
32         Container       pane;
33
34         static Insets il = new Insets(4,4,4,4);
35         static Insets ir = new Insets(4,4,4,4);
36
37         static String[] state_names;
38
39         static void make_state_names() {
40                 if (state_names == null) {
41
42                         state_names = new String[AltosLib.ao_flight_landed - AltosLib.ao_flight_boost + 1];
43                         for (int state = AltosLib.ao_flight_boost; state <= AltosLib.ao_flight_landed; state++)
44                                 state_names[state - AltosLib.ao_flight_boost] = AltosLib.state_name_capital(state);
45                 }
46         }
47
48         class PyroItem implements ItemListener, DocumentListener, AltosUnitsListener
49         {
50                 public int              flag;
51                 public JCheckBox        enable;
52                 public JTextField       value;
53                 public JComboBox<String>        combo;
54                 AltosConfigPyroUI       ui;
55                 boolean                 setting;
56
57                 public void set_enable(boolean enable) {
58                         if (value != null)
59                                 value.setEnabled(enable);
60                         if (combo != null)
61                                 combo.setEnabled(enable);
62                 }
63
64                 public void itemStateChanged(ItemEvent e) {
65                         set_enable(enable.isSelected());
66                         if (!setting)
67                                 ui.set_dirty();
68                 }
69
70                 public void changedUpdate(DocumentEvent e) {
71                         if (!setting)
72                                 ui.set_dirty();
73                 }
74
75                 public void insertUpdate(DocumentEvent e) {
76                         if (!setting)
77                                 ui.set_dirty();
78                 }
79
80                 public void removeUpdate(DocumentEvent e) {
81                         if (!setting)
82                                 ui.set_dirty();
83                 }
84
85                 public void units_changed(boolean imperial_units) {
86                         AltosUnits units = AltosPyro.pyro_to_units(flag);
87
88                         if (units != null) {
89                                 try {
90                                         double v = units.parse(value.getText(), !imperial_units);
91                                         set(enabled(), v);
92                                 } catch (NumberFormatException ne) {
93                                         set(enabled(), 0.0);
94                                 }
95                         }
96                 }
97
98                 public void set(boolean new_enable, double new_value) {
99                         setting = true;
100                         enable.setSelected(new_enable);
101                         set_enable(new_enable);
102                         if (value != null) {
103                                 double  scale = AltosPyro.pyro_to_scale(flag);
104                                 double  unit_value = new_value;
105                                 AltosUnits units = AltosPyro.pyro_to_units(flag);
106                                 if (units != null)
107                                         unit_value = units.value(new_value);
108                                 String  format;
109                                 if (scale >= 100)
110                                         format = "%6.2f";
111                                 else if (scale >= 10)
112                                         format = "%6.1f";
113                                 else
114                                         format = "%6.0f";
115                                 value.setText(String.format(format, unit_value));
116                         }
117                         if (combo != null)
118                                 if (new_value >= AltosLib.ao_flight_boost && new_value <= AltosLib.ao_flight_landed)
119                                         combo.setSelectedIndex((int) new_value - AltosLib.ao_flight_boost);
120                         setting = false;
121                 }
122
123                 public boolean enabled() {
124                         return enable.isSelected();
125                 }
126
127                 public double value() throws AltosConfigDataException {
128                         if (value != null) {
129                                 AltosUnits units = AltosPyro.pyro_to_units(flag);
130                                 try {
131                                         if (units != null)
132                                                 return units.parse(value.getText());
133                                         return Double.parseDouble(value.getText());
134                                 } catch (NumberFormatException e) {
135                                         throw new AltosConfigDataException("\"%s\": %s\n", value.getText(), e.getMessage());
136                                 }
137                         }
138                         if (combo != null)
139                                 return combo.getSelectedIndex() + AltosLib.ao_flight_boost;
140                         return 0;
141                 }
142
143                 public PyroItem(AltosConfigPyroUI in_ui, int in_flag, int x, int y) {
144
145                         ui = in_ui;
146                         flag = in_flag;
147
148                         GridBagConstraints      c;
149                         c = new GridBagConstraints();
150                         c.gridx = x; c.gridy = y;
151                         c.gridwidth = 1;
152                         c.fill = GridBagConstraints.NONE;
153                         c.anchor = GridBagConstraints.LINE_START;
154                         c.insets = il;
155                         enable = new JCheckBox();
156                         enable.addItemListener(this);
157                         pane.add(enable, c);
158
159                         if ((flag & AltosPyro.pyro_no_value) == 0) {
160                                 c = new GridBagConstraints();
161                                 c.gridx = x+1; c.gridy = y;
162                                 c.gridwidth = 1;
163                                 c.fill = GridBagConstraints.NONE;
164                                 c.anchor = GridBagConstraints.LINE_START;
165                                 c.insets = il;
166                                 if ((flag & AltosPyro.pyro_state_value) != 0) {
167                                         make_state_names();
168                                         combo = new JComboBox<String>(state_names);
169                                         combo.addItemListener(this);
170                                         pane.add(combo, c);
171                                 } else {
172                                         value = new JTextField(10);
173                                         value.getDocument().addDocumentListener(this);
174                                         pane.add(value, c);
175                                 }
176                         }
177                 }
178         }
179
180         class PyroColumn implements AltosUnitsListener {
181                 public PyroItem[]       items;
182                 public JLabel           label;
183                 int                     channel;
184
185                 public void set(AltosPyro pyro) {
186                         int row = 0;
187                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
188                                 if ((AltosPyro.pyro_all & flag) != 0) {
189                                         items[row].set((pyro.flags & flag) != 0,
190                                                        pyro.get_value(flag));
191                                         row++;
192                                 }
193                         }
194                 }
195
196                 public AltosPyro get() throws AltosConfigDataException {
197                         AltosPyro       p = new AltosPyro(channel);
198
199                         int row = 0;
200                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
201                                 if ((AltosPyro.pyro_all & flag) != 0) {
202                                         if (items[row].enabled()) {
203                                                 try {
204                                                 p.flags |= flag;
205                                                 p.set_value(flag, items[row].value());
206                                                 } catch (AltosConfigDataException ae) {
207                                                         throw new AltosConfigDataException("%s, %s",
208                                                                                            AltosPyro.pyro_to_name(flag),
209                                                                                            ae.getMessage());
210                                                 }
211                                         }
212                                         row++;
213                                 }
214                         }
215                         return p;
216                 }
217
218                 public void units_changed(boolean imperial_units) {
219                         int row = 0;
220                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
221                                 if ((AltosPyro.pyro_all & flag) != 0) {
222                                         items[row].units_changed(imperial_units);
223                                         row++;
224                                 }
225                         }
226                 }
227
228                 public PyroColumn(AltosConfigPyroUI ui, int x, int y, int in_channel) {
229
230                         channel = in_channel;
231
232                         int     nrow = 0;
233                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
234                                 if ((flag & AltosPyro.pyro_all) != 0)
235                                         nrow++;
236
237                         items = new PyroItem[nrow];
238                         int row = 0;
239
240                         GridBagConstraints      c;
241                         c = new GridBagConstraints();
242                         c.gridx = x; c.gridy = y;
243                         c.gridwidth = 2;
244                         c.fill = GridBagConstraints.NONE;
245                         c.anchor = GridBagConstraints.CENTER;
246                         c.insets = il;
247                         label = new JLabel(String.format("Pyro Channel %c", 'A' + channel));
248                         pane.add(label, c);
249                         y++;
250
251                         for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
252                                 if ((flag & AltosPyro.pyro_all) != 0) {
253                                         items[row] = new PyroItem(ui, flag, x, y + row);
254                                         row++;
255                                 }
256                 }
257         }
258
259         PyroColumn[]    columns;
260         JLabel[]        labels;
261
262         public void set_pyros(AltosPyro[] pyros) {
263                 for (int i = 0; i < pyros.length; i++) {
264                         if (pyros[i].channel < columns.length)
265                                 columns[pyros[i].channel].set(pyros[i]);
266                 }
267         }
268
269         public AltosPyro[] get_pyros() throws AltosConfigDataException {
270                 AltosPyro[]     pyros = new AltosPyro[columns.length];
271                 for (int c = 0; c < columns.length; c++) {
272                         try {
273                                 pyros[c] = columns[c].get();
274                         } catch (AltosConfigDataException ae) {
275                                 throw new AltosConfigDataException ("Channel %c, %s", c + 'A', ae.getMessage());
276                         }
277                 }
278                 return pyros;
279         }
280
281         JLabel                  pyro_firing_time_label;
282         JComboBox<String>       pyro_firing_time_value;
283
284         static String[]         pyro_firing_time_values = {
285                 "0.050", "0.100", "0.250", "0.500", "1.0", "2.0"
286         };
287
288         public void set_pyro_firing_time(double new_pyro_firing_time) {
289                 pyro_firing_time_value.setSelectedItem(Double.toString(new_pyro_firing_time));
290                 pyro_firing_time_value.setEnabled(new_pyro_firing_time >= 0);
291         }
292
293         public double get_pyro_firing_time() throws AltosConfigDataException {
294                 String  v = pyro_firing_time_value.getSelectedItem().toString();
295
296                 try {
297                         return Double.parseDouble(v);
298                 } catch (NumberFormatException e) {
299                         throw new AltosConfigDataException("Invalid pyro firing time \"%s\"", v);
300                 }
301         }
302
303         public void set_dirty() {
304                 owner.set_dirty();
305         }
306
307         public void itemStateChanged(ItemEvent e) {
308                 owner.set_dirty();
309         }
310
311         public void changedUpdate(DocumentEvent e) {
312                 owner.set_dirty();
313         }
314
315         public void insertUpdate(DocumentEvent e) {
316                 owner.set_dirty();
317         }
318
319         public void removeUpdate(DocumentEvent e) {
320                 owner.set_dirty();
321         }
322
323         public void units_changed(boolean imperial_units) {
324                 for (int c = 0; c < columns.length; c++)
325                         columns[c].units_changed(imperial_units);
326                 int r = 0;
327                 for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
328                         String n = AltosPyro.pyro_to_name(flag);
329                         if (n != null) {
330                                 labels[r].setText(n);
331                                 r++;
332                         }
333                 }
334         }
335
336         /* A window listener to catch closing events and tell the config code */
337         class ConfigListener extends WindowAdapter {
338                 AltosConfigPyroUI       ui;
339                 AltosConfigUI           owner;
340
341                 public ConfigListener(AltosConfigPyroUI this_ui, AltosConfigUI this_owner) {
342                         ui = this_ui;
343                         owner = this_owner;
344                 }
345
346                 public void windowClosing(WindowEvent e) {
347                         ui.setVisible(false);
348                 }
349         }
350
351         /* Listen for events from our buttons */
352         public void actionPerformed(ActionEvent e) {
353                 String  cmd = e.getActionCommand();
354
355                 if (cmd.equals("Close"))
356                         setVisible(false);
357         }
358
359         public AltosConfigPyroUI(AltosConfigUI in_owner, AltosPyro[] pyros, double pyro_firing_time) {
360
361                 super(in_owner, "Configure Pyro Channels", false);
362
363                 owner = in_owner;
364
365                 GridBagConstraints      c;
366
367                 pane = getContentPane();
368                 pane.setLayout(new GridBagLayout());
369
370                 int     nrow = 0;
371                 for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
372                         if ((flag & AltosPyro.pyro_all) != 0)
373                                 nrow++;
374
375                 labels = new JLabel[nrow];
376
377                 int     row = 1;
378
379                 for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
380                         String  n;
381
382                         n = AltosPyro.pyro_to_name(flag);
383                         if (n != null) {
384                                 c = new GridBagConstraints();
385                                 c.gridx = 0; c.gridy = row;
386                                 c.gridwidth = 1;
387                                 c.fill = GridBagConstraints.NONE;
388                                 c.anchor = GridBagConstraints.LINE_START;
389                                 c.insets = il;
390                                 JLabel label = new JLabel(n);
391                                 pane.add(label, c);
392                                 labels[row-1] = label;
393                                 row++;
394                         }
395                 }
396
397                 columns = new PyroColumn[pyros.length];
398
399                 for (int i = 0; i < pyros.length; i++) {
400                         columns[i] = new PyroColumn(this, i*2 + 1, 0, i);
401                         columns[i].set(pyros[i]);
402                 }
403
404                 /* Pyro firing time */
405                 c = new GridBagConstraints();
406                 c.gridx = 0; c.gridy = row;
407                 c.gridwidth = 2;
408                 c.fill = GridBagConstraints.NONE;
409                 c.anchor = GridBagConstraints.LINE_START;
410                 c.insets = il;
411                 c.ipady = 5;
412                 pyro_firing_time_label = new JLabel("Pyro Firing Time(s):");
413                 pane.add(pyro_firing_time_label, c);
414
415                 c = new GridBagConstraints();
416                 c.gridx = 2; c.gridy = row;
417                 c.gridwidth = 7;
418                 c.fill = GridBagConstraints.HORIZONTAL;
419                 c.weightx = 1;
420                 c.anchor = GridBagConstraints.LINE_START;
421                 c.insets = ir;
422                 c.ipady = 5;
423                 pyro_firing_time_value = new JComboBox<String>(pyro_firing_time_values);
424                 pyro_firing_time_value.setEditable(true);
425                 pyro_firing_time_value.addItemListener(this);
426                 set_pyro_firing_time(pyro_firing_time);
427                 pane.add(pyro_firing_time_value, c);
428                 pyro_firing_time_value.setToolTipText("Length of extra pyro channel firing pulse");
429
430                 c = new GridBagConstraints();
431                 c.gridx = pyros.length*2-1;
432                 c.fill = GridBagConstraints.HORIZONTAL;
433                 c.gridwidth = 2;
434                 c.gridy = 1000;
435                 JButton close = new JButton("Close");
436                 pane.add(close, c);
437                 close.addActionListener(this);
438                 close.setActionCommand("Close");
439
440                 addWindowListener(new ConfigListener(this, owner));
441                 AltosPreferences.register_units_listener(this);
442         }
443
444         public void dispose() {
445                 AltosPreferences.unregister_units_listener(this);
446                 super.dispose();
447         }
448
449         public void make_visible() {
450                 pack();
451                 setVisible(true);
452         }
453 }