java: Refactor AltosFlightDisplay units and font update handling
[fw/altos] / altosui / AltosDescent.java
1 /*
2  * Copyright © 2010 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 javax.swing.*;
22 import org.altusmetrum.altoslib_4.*;
23 import org.altusmetrum.altosuilib_2.*;
24
25 public class AltosDescent extends JComponent implements AltosFlightDisplay {
26         GridBagLayout   layout;
27
28         public abstract class DescentStatus implements AltosFontListener, AltosUnitsListener {
29                 JLabel          label;
30                 JTextField      value;
31                 AltosLights     lights;
32
33                 abstract void show(AltosState state, AltosListenerState listener_state);
34
35                 void show() {
36                         label.setVisible(true);
37                         value.setVisible(true);
38                         lights.setVisible(true);
39                 }
40
41                 void show(String s) {
42                         show();
43                         value.setText(s);
44                 }
45
46                 void show(String format, double value) {
47                         show(String.format(format, value));
48                 }
49
50                 void hide() {
51                         label.setVisible(false);
52                         value.setVisible(false);
53                         lights.setVisible(false);
54                 }
55
56                 void reset() {
57                         value.setText("");
58                         lights.set(false);
59                 }
60
61                 public void font_size_changed(int font_size) {
62                         label.setFont(Altos.label_font);
63                         value.setFont(Altos.value_font);
64                 }
65
66                 public void units_changed(boolean imperial_units) {
67                 }
68
69                 public DescentStatus (GridBagLayout layout, int y, String text) {
70                         GridBagConstraints      c = new GridBagConstraints();
71                         c.weighty = 1;
72
73                         lights = new AltosLights();
74                         c.gridx = 0; c.gridy = y;
75                         c.anchor = GridBagConstraints.CENTER;
76                         c.fill = GridBagConstraints.VERTICAL;
77                         c.weightx = 0;
78                         layout.setConstraints(lights, c);
79                         add(lights);
80
81                         label = new JLabel(text);
82                         label.setFont(Altos.label_font);
83                         label.setHorizontalAlignment(SwingConstants.LEFT);
84                         c.gridx = 1; c.gridy = y;
85                         c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
86                         c.anchor = GridBagConstraints.WEST;
87                         c.fill = GridBagConstraints.VERTICAL;
88                         c.gridwidth = 3;
89                         c.weightx = 0;
90                         layout.setConstraints(label, c);
91                         add(label);
92
93                         value = new JTextField(Altos.text_width);
94                         value.setFont(Altos.value_font);
95                         value.setHorizontalAlignment(SwingConstants.RIGHT);
96                         c.gridx = 4; c.gridy = y;
97                         c.gridwidth = 1;
98                         c.anchor = GridBagConstraints.WEST;
99                         c.fill = GridBagConstraints.BOTH;
100                         c.weightx = 1;
101                         layout.setConstraints(value, c);
102                         add(value);
103
104                 }
105         }
106
107         public abstract class DescentValue implements AltosFontListener, AltosUnitsListener {
108                 JLabel          label;
109                 JTextField      value;
110                 AltosUnits      units;
111                 double          v;
112
113                 void reset() {
114                         value.setText("");
115                 }
116
117                 abstract void show(AltosState state, AltosListenerState listener_state);
118
119                 void show() {
120                         label.setVisible(true);
121                         value.setVisible(true);
122                 }
123
124                 void hide() {
125                         label.setVisible(false);
126                         value.setVisible(false);
127                 }
128
129                 void show(String v) {
130                         show();
131                         value.setText(v);
132                 }
133
134                 void show(double v) {
135                         this.v = v;
136                         show(units.show(8, v));
137                 }
138
139                 void show(String format, double v) {
140                         show(String.format(format, v));
141                 }
142
143                 public void font_size_changed(int font_size) {
144                         label.setFont(Altos.label_font);
145                         value.setFont(Altos.value_font);
146                 }
147
148                 public void units_changed(boolean imperial_units) {
149                         if (units != null)
150                                 show(v);
151                 }
152
153                 public DescentValue (GridBagLayout layout, int x, int y, AltosUnits units, String text) {
154                         this.units = units;
155                         GridBagConstraints      c = new GridBagConstraints();
156                         c.weighty = 1;
157
158                         label = new JLabel(text);
159                         label.setFont(Altos.label_font);
160                         label.setHorizontalAlignment(SwingConstants.LEFT);
161                         c.gridx = x + 1; c.gridy = y;
162                         c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
163                         c.anchor = GridBagConstraints.WEST;
164                         c.fill = GridBagConstraints.VERTICAL;
165                         c.weightx = 0;
166                         add(label, c);
167
168                         value = new JTextField(Altos.text_width);
169                         value.setFont(Altos.value_font);
170                         value.setHorizontalAlignment(SwingConstants.RIGHT);
171                         c.gridx = x + 2; c.gridy = y;
172                         c.gridwidth = 1;
173                         c.anchor = GridBagConstraints.WEST;
174                         c.fill = GridBagConstraints.BOTH;
175                         c.weightx = 1;
176                         add(value, c);
177                 }
178
179                 public DescentValue (GridBagLayout layout, int x, int y, String text) {
180                         this(layout, x, y, null, text);
181                 }
182         }
183
184         public abstract class DescentDualValue implements AltosFontListener, AltosUnitsListener {
185                 JLabel          label;
186                 JTextField      value1;
187                 JTextField      value2;
188
189                 void reset() {
190                         value1.setText("");
191                         value2.setText("");
192                 }
193
194                 void show() {
195                         label.setVisible(true);
196                         value1.setVisible(true);
197                         value2.setVisible(true);
198                 }
199
200                 void hide() {
201                         label.setVisible(false);
202                         value1.setVisible(false);
203                         value2.setVisible(false);
204                 }
205
206                 public void font_size_changed(int font_size) {
207                         label.setFont(Altos.label_font);
208                         value1.setFont(Altos.value_font);
209                         value2.setFont(Altos.value_font);
210                 }
211
212                 public void units_changed(boolean imperial_units) {
213                 }
214
215                 abstract void show(AltosState state, AltosListenerState listener_state);
216
217                 void show(String v1, String v2) {
218                         show();
219                         value1.setText(v1);
220                         value2.setText(v2);
221                 }
222                 void show(String f1, double v1, String f2, double v2) {
223                         show();
224                         value1.setText(String.format(f1, v1));
225                         value2.setText(String.format(f2, v2));
226                 }
227
228                 public DescentDualValue (GridBagLayout layout, int x, int y, String text) {
229                         GridBagConstraints      c = new GridBagConstraints();
230                         c.weighty = 1;
231
232                         label = new JLabel(text);
233                         label.setFont(Altos.label_font);
234                         label.setHorizontalAlignment(SwingConstants.LEFT);
235                         c.gridx = x + 1; c.gridy = y;
236                         c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
237                         c.anchor = GridBagConstraints.WEST;
238                         c.fill = GridBagConstraints.VERTICAL;
239                         c.weightx = 0;
240                         layout.setConstraints(label, c);
241                         add(label);
242
243                         value1 = new JTextField(Altos.text_width);
244                         value1.setFont(Altos.value_font);
245                         value1.setHorizontalAlignment(SwingConstants.RIGHT);
246                         c.gridx = x + 2; c.gridy = y;
247                         c.anchor = GridBagConstraints.WEST;
248                         c.fill = GridBagConstraints.BOTH;
249                         c.weightx = 1;
250                         layout.setConstraints(value1, c);
251                         add(value1);
252
253                         value2 = new JTextField(Altos.text_width);
254                         value2.setFont(Altos.value_font);
255                         value2.setHorizontalAlignment(SwingConstants.RIGHT);
256                         c.gridx = x + 4; c.gridy = y;
257                         c.anchor = GridBagConstraints.WEST;
258                         c.fill = GridBagConstraints.BOTH;
259                         c.weightx = 1;
260                         c.gridwidth = 1;
261                         layout.setConstraints(value2, c);
262                         add(value2);
263                 }
264         }
265
266         class Height extends DescentValue {
267                 void show (AltosState state, AltosListenerState listener_state) {
268                         show(state.height());
269                 }
270                 public Height (GridBagLayout layout, int x, int y) {
271                         super (layout, x, y, AltosConvert.height, "Height");
272                 }
273         }
274
275         Height  height;
276
277         class Speed extends DescentValue {
278                 void show (AltosState state, AltosListenerState listener_state) {
279                         show(state.speed());
280                 }
281                 public Speed (GridBagLayout layout, int x, int y) {
282                         super (layout, x, y, AltosConvert.speed, "Speed");
283                 }
284         }
285
286         Speed   speed;
287
288         String pos(double p, String pos, String neg) {
289                 String  h = pos;
290                 if (p < 0) {
291                         h = neg;
292                         p = -p;
293                 }
294                 int deg = (int) Math.floor(p);
295                 double min = (p - Math.floor(p)) * 60.0;
296                 return String.format("%s %d° %9.6f", h, deg, min);
297         }
298
299         class Lat extends DescentValue {
300                 void show (AltosState state, AltosListenerState listener_state) {
301                         if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
302                                 show(pos(state.gps.lat,"N", "S"));
303                         else
304                                 show("???");
305                 }
306                 public Lat (GridBagLayout layout, int x, int y) {
307                         super (layout, x, y, "Latitude");
308                 }
309         }
310
311         Lat lat;
312
313         class Lon extends DescentValue {
314                 void show (AltosState state, AltosListenerState listener_state) {
315                         if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
316                                 show(pos(state.gps.lon,"W", "E"));
317                         else
318                                 show("???");
319                 }
320                 public Lon (GridBagLayout layout, int x, int y) {
321                         super (layout, x, y, "Longitude");
322                 }
323         }
324
325         Lon lon;
326
327         class Distance extends DescentValue {
328                 void show(AltosState state, AltosListenerState listener_state) {
329                         if (state.from_pad != null)
330                                 show(state.from_pad.distance);
331                         else
332                                 show("???");
333                 }
334
335                 public Distance (GridBagLayout layout, int x, int y) {
336                         super(layout, x, y, AltosConvert.distance, "Ground Distance");
337                 }
338         }
339
340         Distance distance;
341
342
343         class Apogee extends DescentStatus {
344                 void show (AltosState state, AltosListenerState listener_state) {
345                         show("%4.2f V", state.apogee_voltage);
346                         lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good);
347                 }
348                 public Apogee (GridBagLayout layout, int y) {
349                         super(layout, y, "Apogee Igniter Voltage");
350                 }
351         }
352
353         Apogee apogee;
354
355         class Main extends DescentStatus {
356                 void show (AltosState state, AltosListenerState listener_state) {
357                         show("%4.2f V", state.main_voltage);
358                         lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
359                 }
360                 public Main (GridBagLayout layout, int y) {
361                         super(layout, y, "Main Igniter Voltage");
362                 }
363         }
364
365         Main main;
366
367         class Bearing extends DescentDualValue {
368                 void show (AltosState state, AltosListenerState listener_state) {
369                         if (state.from_pad != null) {
370                                 show( String.format("%3.0f°", state.from_pad.bearing),
371                                       state.from_pad.bearing_words(
372                                               AltosGreatCircle.BEARING_LONG));
373                         } else {
374                                 show("???", "???");
375                         }
376                 }
377                 public Bearing (GridBagLayout layout, int x, int y) {
378                         super (layout, x, y, "Bearing");
379                 }
380         }
381
382         Bearing bearing;
383
384         class Range extends DescentValue {
385                 void show (AltosState state, AltosListenerState listener_state) {
386                         show(state.range);
387                 }
388                 public Range (GridBagLayout layout, int x, int y) {
389                         super (layout, x, y, AltosConvert.distance, "Range");
390                 }
391         }
392
393         Range range;
394
395         class Elevation extends DescentValue {
396                 void show (AltosState state, AltosListenerState listener_state) {
397                         show("%3.0f°", state.elevation);
398                 }
399                 public Elevation (GridBagLayout layout, int x, int y) {
400                         super (layout, x, y, "Elevation");
401                 }
402         }
403
404         Elevation elevation;
405
406         public void reset() {
407                 lat.reset();
408                 lon.reset();
409                 height.reset();
410                 speed.reset();
411                 bearing.reset();
412                 range.reset();
413                 distance.reset();
414                 elevation.reset();
415                 main.reset();
416                 apogee.reset();
417         }
418
419         public void font_size_changed(int font_size) {
420                 lat.font_size_changed(font_size);
421                 lon.font_size_changed(font_size);
422                 height.font_size_changed(font_size);
423                 speed.font_size_changed(font_size);
424                 bearing.font_size_changed(font_size);
425                 range.font_size_changed(font_size);
426                 distance.font_size_changed(font_size);
427                 elevation.font_size_changed(font_size);
428                 main.font_size_changed(font_size);
429                 apogee.font_size_changed(font_size);
430         }
431
432         public void units_changed(boolean imperial_units) {
433                 lat.units_changed(imperial_units);
434                 lon.units_changed(imperial_units);
435                 height.units_changed(imperial_units);
436                 speed.units_changed(imperial_units);
437                 bearing.units_changed(imperial_units);
438                 range.units_changed(imperial_units);
439                 distance.units_changed(imperial_units);
440                 elevation.units_changed(imperial_units);
441                 main.units_changed(imperial_units);
442                 apogee.units_changed(imperial_units);
443         }
444
445         public void show(AltosState state, AltosListenerState listener_state) {
446                 height.show(state, listener_state);
447                 speed.show(state, listener_state);
448                 if (state.gps != null && state.gps.connected) {
449                         bearing.show(state, listener_state);
450                         range.show(state, listener_state);
451                         distance.show(state, listener_state);
452                         elevation.show(state, listener_state);
453                         lat.show(state, listener_state);
454                         lon.show(state, listener_state);
455                 } else {
456                         bearing.hide();
457                         range.hide();
458                         distance.hide();
459                         elevation.hide();
460                         lat.hide();
461                         lon.hide();
462                 }
463                 if (state.main_voltage != AltosLib.MISSING)
464                         main.show(state, listener_state);
465                 else
466                         main.hide();
467                 if (state.apogee_voltage != AltosLib.MISSING)
468                         apogee.show(state, listener_state);
469                 else
470                         apogee.hide();
471         }
472
473         public String getName() {
474                 return "Descent";
475         }
476
477         public AltosDescent() {
478                 layout = new GridBagLayout();
479
480                 setLayout(layout);
481
482                 /* Elements in descent display */
483                 speed = new Speed(layout, 0, 0);
484                 height = new Height(layout, 2, 0);
485                 elevation = new Elevation(layout, 0, 1);
486                 range = new Range(layout, 2, 1);
487                 bearing = new Bearing(layout, 0, 2);
488                 distance = new Distance(layout, 0, 3);
489                 lat = new Lat(layout, 0, 4);
490                 lon = new Lon(layout, 2, 4);
491
492                 apogee = new Apogee(layout, 5);
493                 main = new Main(layout, 6);
494         }
495 }