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