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