]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/HUD/HUD_label.cxx
finally fix the text-in-box alignment (= Rocket Science[TM]!)
[flightgear.git] / src / Instrumentation / HUD / HUD_label.cxx
1 // HUD_label.cxx -- HUD Label
2 //
3 // Written by Michele America, started September 1997.
4 //
5 // Copyright (C) 1997  Michele F. America  [micheleamerica#geocities:com]
6 // Copyright (C) 2006  Melchior FRANZ  [mfranz#aon:at]
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25
26 #include <simgear/props/condition.hxx>
27 #include "HUD.hxx"
28
29
30 HUD::Label::Label(HUD *hud, const SGPropertyNode *n, float x, float y) :
31     Item(hud, n, x, y),
32     _input(n->getNode("input", false)),
33     _fontsize(fgGetInt("/sim/startup/xsize") > 1000 ? FONT_LARGE : FONT_SMALL),         // FIXME
34     _box(n->getBoolValue("box", false)),
35     _pointer_width(n->getFloatValue("pointer-width", 7.0)),
36     _pointer_length(n->getFloatValue("pointer-length", 5.0)),
37     _blink_condition(0),
38     _blink_interval(n->getFloatValue("blinking/interval", -1.0f)),
39     _blink_target(0.0),
40     _blink_state(true)
41 {
42     const SGPropertyNode *node = n->getNode("blinking/condition");
43     if (node)
44        _blink_condition = sgReadCondition(globals->get_props(), node);
45
46     const char *halign = n->getStringValue("halign", "center");
47     if (!strcmp(halign, "left"))
48         _halign = LEFT_ALIGN;
49     else if (!strcmp(halign, "right"))
50         _halign = RIGHT_ALIGN;
51     else
52         _halign = CENTER_ALIGN;
53
54     const char *pre = n->getStringValue("prefix", 0);
55     const char *post = n->getStringValue("postfix", 0);
56     const char *fmt = n->getStringValue("format", 0);
57
58     if (pre)
59         _format = pre;
60
61     if (fmt)
62         _format += fmt;
63     else
64         _format += "%s";
65
66     if (post)
67         _format += post;
68
69     _mode = check_format(_format.c_str());
70     if (_mode == INVALID) {
71         SG_LOG(SG_INPUT, SG_ALERT, "HUD: invalid format '" << _format.c_str() << '\'');
72         _format = "INVALID";
73         _mode = NONE;
74     }
75
76     float top, bot;
77     _hud->_font->getBBox("0", _hud->_font_size, 0.0, 0, 0, &bot, &top);
78     _text_y = _y + (_h - top + bot) / 2.0 - bot;
79     blink();
80 }
81
82
83 void HUD::Label::draw(void)
84 {
85     if (!(_mode == NONE || _input.isValid() && blink()))
86         return;
87
88     if (_box) {
89         float l, r, p;
90         float pw = _pointer_width / 2.0;
91
92         l = _center_x - pw;
93         r = _center_x + pw;
94         bool draw_parallel = fabsf(_pointer_width - _w) > 2.0; // draw lines left and right of arrow?
95
96         if (option_bottom()) {
97             if (draw_parallel) {
98                 draw_line(_x, _y, l, _y);
99                 draw_line(r, _y, _x + _w, _y);
100             }
101             p = _y - _pointer_length;
102             draw_line(l, _y, _center_x, p);
103             draw_line(_center_x, p, r, _y);
104         } else
105             draw_line(_x, _y, _x + _w, _y);
106
107         if (option_top()) {
108             if (draw_parallel) {
109                 draw_line(_x, _y + _h, l, _y + _h);
110                 draw_line(r, _y + _h, _x + _w, _y + _h);
111             }
112             p = _y + _h + _pointer_length;
113             draw_line(l, _y + _h, _center_x, p);
114             draw_line(_center_x, p, r, _y + _h);
115         } else
116             draw_line(_x + _w, _y + _h, _x, _y + _h);
117
118         l = _center_y - pw;
119         r = _center_y + pw;
120         draw_parallel = fabsf(_pointer_width - _h) > 2.0;
121
122         if (option_left()) {
123             if (draw_parallel) {
124                 draw_line(_x, _y, _x, l);
125                 draw_line(_x, r, _x, _y + _h);
126             }
127             p = _x - _pointer_length;
128             draw_line(_x, l, p, _center_y);
129             draw_line(p, _center_y, _x, r);
130         } else
131             draw_line(_x, _y + _h, _x, _y);
132
133         if (option_right()) {
134             if (draw_parallel) {
135                 draw_line(_x + _w, _y, _x + _w, l);
136                 draw_line(_x + _w, r, _x + _w, _y + _h);
137             }
138             p = _x + _w + _pointer_length;
139             draw_line(_x + _w, l, p, _center_y);
140             draw_line(p, _center_y, _x + _w, r);
141         } else
142             draw_line(_x + _w, _y, _x + _w, _y + _h);
143     }
144
145     const int BUFSIZE = 256;
146     char buf[BUFSIZE];
147     if (_mode == NONE)
148         snprintf(buf, BUFSIZE, _format.c_str());
149     else if (_mode == STRING)
150         snprintf(buf, BUFSIZE, _format.c_str(), _input.getStringValue());
151     else if (_mode == INT)
152         snprintf(buf, BUFSIZE, _format.c_str(), int(_input.getFloatValue()));
153     else if (_mode == LONG)
154         snprintf(buf, BUFSIZE, _format.c_str(), long(_input.getFloatValue()));
155     else if (_mode == FLOAT)
156         snprintf(buf, BUFSIZE, _format.c_str(), float(_input.getFloatValue()));
157     else if (_mode == DOUBLE) // not really supported yet
158         snprintf(buf, BUFSIZE, _format.c_str(), double(_input.getFloatValue()));
159
160     float posincr;
161     float L, R, B, T;
162     _hud->_font->getBBox(buf, _hud->_font_size, 0.0, &L, &R, &B, &T);
163     float lenstr = R - L;
164
165     if (_halign == RIGHT_ALIGN)
166         posincr = _w - lenstr;
167     else if (_halign == CENTER_ALIGN)
168         posincr = (_w - lenstr) / 2.0;
169     else // LEFT_ALIGN
170         posincr = 0;
171
172     posincr += _hud->_font->getGap() / 2.0 - L;
173
174     if (_fontsize == FONT_SMALL)
175         draw_text(_x + posincr, _text_y, buf, get_digits());
176     else if (_fontsize == FONT_LARGE)
177         draw_text(_x + posincr, _text_y, buf, get_digits());
178 }
179
180
181 // make sure the format matches '[ -+#]?\d*(\.\d*)?(l?[df]|s)'
182 //
183 HUD::Label::Format HUD::Label::check_format(const char *f) const
184 {
185     bool l = false;
186     Format fmt = STRING;
187
188     for (; *f; f++) {
189         if (*f == '%') {
190             if (f[1] == '%')
191                 f++;
192             else
193                 break;
194         }
195     }
196     if (*f++ != '%')
197         return NONE;
198     if (*f == ' ' || *f == '+' || *f == '-' || *f == '#')
199         f++;
200     while (*f && isdigit(*f))
201         f++;
202     if (*f == '.') {
203         f++;
204         while (*f && isdigit(*f))
205             f++;
206     }
207     if (*f == 'l')
208         l = true, f++;
209
210     if (*f == 'd')
211         fmt = l ? LONG : INT;
212     else if (*f == 'f')
213         fmt = l ? DOUBLE : FLOAT;
214     else if (*f == 's') {
215         if (l)
216             return INVALID;
217         fmt = STRING;
218     } else
219         return INVALID;
220
221     for (++f; *f; f++) {
222         if (*f == '%') {
223             if (f[1] == '%')
224                 f++;
225             else
226                 return INVALID;
227         }
228     }
229     return fmt;
230 }
231
232
233 bool HUD::Label::blink()
234 {
235     if (_blink_interval < 0.0f)
236         return true;
237
238     if (_blink_condition && !_blink_condition->test())
239         return true;
240
241     if (_hud->timer() < _blink_target)
242         return _blink_state;
243
244     _blink_target = _hud->timer() + _blink_interval;
245     return _blink_state = !_blink_state;
246 }
247
248