Android release v6.7_preview1
[xcsoar.git] / src / Gauge / GaugeVario.cpp
blob4aeaa354987fc8ea0614cdcf7b7aa5592d717873
1 /*
2 Copyright_License {
4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "Gauge/GaugeVario.hpp"
25 #include "Look/VarioLook.hpp"
26 #include "Look/UnitsLook.hpp"
27 #include "Screen/Canvas.hpp"
28 #include "Screen/UnitSymbol.hpp"
29 #include "Screen/Layout.hpp"
30 #include "Screen/FastPixelRotation.hpp"
31 #include "LogFile.hpp"
32 #include "Units/Units.hpp"
33 #include "Util/Clamp.hpp"
35 #include <assert.h>
36 #include <stdio.h>
38 #include <algorithm>
40 using std::min;
41 using std::max;
43 #define DELTA_V_STEP fixed(4)
44 #define DELTA_V_LIMIT fixed(16)
45 #define TEXT_BUG _T("Bug")
46 #define TEXT_BALLAST _T("Bal")
48 GaugeVario::GaugeVario(const FullBlackboard &_blackboard,
49 ContainerWindow &parent, const VarioLook &_look,
50 const UnitsLook &_units_look,
51 PixelRect rc, const WindowStyle style)
52 :blackboard(_blackboard), look(_look), units_look(_units_look),
53 nlength0(Layout::Scale(15)),
54 nlength1(Layout::Scale(6)),
55 nwidth(Layout::Scale(4)),
56 nline(Layout::Scale(8)),
57 dirty(true), layout_initialised(false), needle_initialised(false),
58 ballast_initialised(false), bugs_initialised(false)
60 value_top.initialised = false;
61 value_middle.initialised = false;
62 value_bottom.initialised = false;
63 label_top.initialised = false;
64 label_middle.initialised = false;
65 label_bottom.initialised = false;
67 Create(parent, rc, style);
70 void
71 GaugeVario::OnPaintBuffer(Canvas &canvas)
73 const PixelRect rc = GetClientRect();
74 const UPixelScalar width = rc.right - rc.left;
75 const UPixelScalar height = rc.bottom - rc.top;
77 if (!IsPersistent() || !layout_initialised) {
78 UPixelScalar value_height = 4 + look.value_font->GetCapitalHeight()
79 + look.text_font->GetCapitalHeight();
81 middle_position.y = yoffset - value_height / 2;
82 middle_position.x = rc.right;
83 top_position.y = middle_position.y - value_height;
84 top_position.x = rc.right;
85 bottom_position.y = middle_position.y + value_height;
86 bottom_position.x = rc.right;
88 canvas.Stretch(rc.left, rc.top, width, height,
89 look.background_bitmap,
90 look.background_x, 0, 58, 120);
92 layout_initialised = true;
95 if (Settings().show_average) {
96 // JMW averager now displays netto average if not circling
97 if (!Calculated().circling) {
98 RenderValue(canvas, top_position.x, top_position.y, &value_top, &label_top,
99 Units::ToUserVSpeed(Calculated().netto_average),
100 _T("NetAvg"));
101 } else {
102 RenderValue(canvas, top_position.x, top_position.y,
103 &value_top, &label_top,
104 Units::ToUserVSpeed(Calculated().average), _T("Avg"));
108 if (Settings().show_mc) {
109 fixed mc = Units::ToUserVSpeed(GetGlidePolar().GetMC());
110 RenderValue(canvas, bottom_position.x, bottom_position.y,
111 &value_bottom, &label_bottom,
113 GetComputerSettings().task.auto_mc ? _T("Auto MC") : _T("MC"));
116 if (Settings().show_speed_to_fly)
117 RenderSpeedToFly(canvas, rc.right - 11, (rc.top + rc.bottom) / 2);
118 else
119 RenderClimb(canvas);
121 if (Settings().show_ballast)
122 RenderBallast(canvas);
124 if (Settings().show_bugs)
125 RenderBugs(canvas);
127 dirty = false;
128 int ival, sval, ival_av = 0;
129 static int vval_last = 0;
130 static int sval_last = 0;
131 static int ival_last = 0;
133 fixed vval = Basic().brutto_vario;
134 ival = ValueToNeedlePos(fixed(vval));
135 sval = ValueToNeedlePos(Calculated().sink_rate);
136 if (Settings().show_average_needle) {
137 if (!Calculated().circling)
138 ival_av = ValueToNeedlePos(Calculated().netto_average);
139 else
140 ival_av = ValueToNeedlePos(Calculated().average);
143 // clear items first
145 if (Settings().show_average_needle) {
146 if (!IsPersistent() || ival_av != ival_last)
147 RenderNeedle(canvas, ival_last, true, true);
149 ival_last = ival_av;
152 if (!IsPersistent() || (sval != sval_last) || (ival != vval_last))
153 RenderVarioLine(canvas, vval_last, sval_last, true);
155 sval_last = sval;
157 if (!IsPersistent() || ival != vval_last)
158 RenderNeedle(canvas, vval_last, false, true);
160 vval_last = ival;
162 // now draw items
163 RenderVarioLine(canvas, ival, sval, false);
164 if (Settings().show_average_needle)
165 RenderNeedle(canvas, ival_av, true, false);
167 RenderNeedle(canvas, ival, false, false);
169 if (Settings().show_gross) {
170 fixed vvaldisplay = Clamp(Units::ToUserVSpeed(vval),
171 fixed(-99.9), fixed(99.9));
173 RenderValue(canvas, middle_position.x, middle_position.y,
174 &value_middle, &label_middle,
175 vvaldisplay,
176 _T("Gross"));
179 RenderZero(canvas);
182 gcc_const
183 static RasterPoint
184 TransformRotatedPoint(RasterPoint pt, PixelScalar xoffset, PixelScalar yoffset)
186 return { pt.x + xoffset, (pt.y * 112 / 100) + yoffset + 1 };
189 void
190 GaugeVario::MakePolygon(const int i)
192 RasterPoint *bit = getPolygon(i);
193 RasterPoint *bline = &lines[i + gmax];
195 const FastPixelRotation r(Angle::Degrees(i));
197 bit[0] = TransformRotatedPoint(r.Rotate(-xoffset + nlength0, nwidth),
198 xoffset, yoffset);
199 bit[1] = TransformRotatedPoint(r.Rotate(-xoffset + nlength1, 0),
200 xoffset, yoffset);
201 bit[2] = TransformRotatedPoint(r.Rotate(-xoffset + nlength0, -nwidth),
202 xoffset, yoffset);
204 *bline = TransformRotatedPoint(r.Rotate(-xoffset + nline, 0),
205 xoffset, yoffset);
208 RasterPoint *
209 GaugeVario::getPolygon(int i)
211 return polys + (i + gmax) * 3;
214 void
215 GaugeVario::MakeAllPolygons()
217 if (polys && lines)
218 for (int i = -gmax; i <= gmax; i++)
219 MakePolygon(i);
222 void
223 GaugeVario::RenderClimb(Canvas &canvas)
225 const PixelRect rc = GetClientRect();
226 PixelScalar x = rc.right - Layout::Scale(14);
227 PixelScalar y = rc.bottom - Layout::Scale(24);
229 if (!dirty)
230 return;
232 if (Basic().switch_state.flight_mode == SwitchState::FlightMode::CIRCLING)
233 canvas.ScaleCopy(x, y, look.climb_bitmap, 12, 0, 12, 12);
234 else if (IsPersistent())
235 canvas.DrawFilledRectangle(x, y, x + Layout::Scale(12), y + Layout::Scale(12),
236 look.background_color);
239 void
240 GaugeVario::RenderZero(Canvas &canvas)
242 if (look.inverse)
243 canvas.SelectWhitePen();
244 else
245 canvas.SelectBlackPen();
247 canvas.DrawLine(0, yoffset, Layout::Scale(17), yoffset);
248 canvas.DrawLine(0, yoffset + 1, Layout::Scale(17), yoffset + 1);
252 GaugeVario::ValueToNeedlePos(fixed Value)
254 static fixed degrees_per_unit = fixed(GAUGEVARIOSWEEP) / GAUGEVARIORANGE;
255 int i;
257 if (!needle_initialised){
258 MakeAllPolygons();
259 needle_initialised = true;
261 i = iround(Value * degrees_per_unit);
262 i = Clamp(i, -int(gmax), int(gmax));
263 return i;
266 void
267 GaugeVario::RenderVarioLine(Canvas &canvas, int i, int sink, bool clear)
269 dirty = true;
270 if (i == sink)
271 return;
273 canvas.Select(clear
274 ? look.thick_background_pen
275 : (i > sink ? look.thick_lift_pen : look.thick_sink_pen));
277 if (i > sink)
278 canvas.DrawPolyline(lines + gmax + sink, i - sink);
279 else
280 canvas.DrawPolyline(lines + gmax + i, sink - i);
282 if (!clear) {
283 canvas.SelectNullPen();
285 // clear up naked (sink) edge of polygon, this gives it a nice
286 // taper look
287 if (look.inverse) {
288 canvas.SelectBlackBrush();
289 } else {
290 canvas.SelectWhiteBrush();
292 canvas.DrawTriangleFan(getPolygon(sink), 3);
296 void
297 GaugeVario::RenderNeedle(Canvas &canvas, int i, bool average, bool clear)
299 dirty = true;
301 canvas.SelectNullPen();
303 // legacy behaviour
304 if (clear ^ look.inverse) {
305 canvas.SelectWhiteBrush();
306 } else {
307 canvas.SelectBlackBrush();
310 if (average)
311 canvas.DrawPolyline(getPolygon(i), 3);
312 else
313 canvas.DrawTriangleFan(getPolygon(i), 3);
316 // TODO code: Optimise vario rendering, this is slow
317 void
318 GaugeVario::RenderValue(Canvas &canvas, PixelScalar x, PixelScalar y,
319 DrawInfo *value_info, DrawInfo *label_info,
320 fixed value, const TCHAR *label)
322 PixelSize tsize;
324 #ifndef FIXED_MATH
325 value = (double)iround(value * 10) / 10; // prevent the -0.0 case
326 #endif
328 if (!value_info->initialised) {
330 value_info->rc.right = x - Layout::Scale(5);
331 value_info->rc.top = y + Layout::Scale(3)
332 + look.text_font->GetCapitalHeight();
334 value_info->rc.left = value_info->rc.right;
335 // update back rect with max label size
336 value_info->rc.bottom = value_info->rc.top + look.value_font->GetCapitalHeight();
338 value_info->text_position.x = value_info->rc.left;
339 value_info->text_position.y = value_info->rc.top
340 + look.value_font->GetCapitalHeight()
341 - look.value_font->GetAscentHeight();
343 value_info->last_value = fixed(-9999);
344 value_info->last_text[0] = '\0';
345 value_info->last_unit = Unit::UNDEFINED;
346 value_info->initialised = true;
349 if (!label_info->initialised) {
351 label_info->rc.right = x;
352 label_info->rc.top = y + Layout::Scale(1);
354 label_info->rc.left = label_info->rc.right;
355 // update back rect with max label size
356 label_info->rc.bottom = label_info->rc.top
357 + look.text_font->GetCapitalHeight();
359 label_info->text_position.x = label_info->rc.left;
360 label_info->text_position.y = label_info->rc.top
361 + look.text_font->GetCapitalHeight()
362 - look.text_font->GetAscentHeight();
364 label_info->last_value = fixed(-9999);
365 label_info->last_text[0] = '\0';
366 label_info->initialised = true;
369 canvas.SetBackgroundTransparent();
371 if (!IsPersistent() || (dirty && _tcscmp(label_info->last_text, label) != 0)) {
372 canvas.SetTextColor(look.dimmed_text_color);
373 canvas.Select(*look.text_font);
374 tsize = canvas.CalcTextSize(label);
375 label_info->text_position.x = label_info->rc.right - tsize.cx;
377 if (IsPersistent()) {
378 canvas.SetBackgroundColor(look.background_color);
379 canvas.DrawOpaqueText(label_info->text_position.x, label_info->text_position.y,
380 label_info->rc, label);
381 label_info->rc.left = label_info->text_position.x;
382 _tcscpy(label_info->last_text, label);
383 } else {
384 canvas.DrawText(label_info->text_position.x, label_info->text_position.y,
385 label);
389 if (!IsPersistent() || (dirty && value_info->last_value != value)) {
390 TCHAR buffer[18];
391 canvas.SetBackgroundColor(look.background_color);
392 canvas.SetTextColor(look.text_color);
393 _stprintf(buffer, _T("%.1f"), (double)value);
394 canvas.Select(*look.value_font);
395 tsize = canvas.CalcTextSize(buffer);
396 value_info->text_position.x = value_info->rc.right - tsize.cx;
398 if (IsPersistent()) {
399 canvas.DrawOpaqueText(value_info->text_position.x,
400 value_info->text_position.y,
401 value_info->rc, buffer);
403 value_info->rc.left = value_info->text_position.x;
404 value_info->last_value = value;
405 } else {
406 canvas.DrawText(value_info->text_position.x, value_info->text_position.y,
407 buffer);
411 if (!IsPersistent() ||
412 value_info->last_unit != Units::current.vertical_speed_unit) {
413 value_info->last_unit = Units::current.vertical_speed_unit;
414 const UnitSymbol *unit_symbol = units_look.GetSymbol(value_info->last_unit);
415 unit_symbol->Draw(canvas, x - Layout::Scale(5), value_info->rc.top,
416 look.inverse
417 ? UnitSymbol::INVERSE_GRAY
418 : UnitSymbol::GRAY);
422 void
423 GaugeVario::RenderSpeedToFly(Canvas &canvas, PixelScalar x, PixelScalar y)
425 if (!Basic().airspeed_available ||
426 !Basic().total_energy_vario_available)
427 return;
429 static fixed last_v_diff;
430 fixed v_diff;
432 const UPixelScalar arrow_y_size = Layout::Scale(3);
433 const UPixelScalar arrow_x_size = Layout::Scale(7);
435 const PixelRect rc = GetClientRect();
437 PixelScalar nary = NARROWS * arrow_y_size;
438 PixelScalar ytop = rc.top + YOFFSET + nary; // JMW
439 PixelScalar ybottom = rc.bottom - YOFFSET - nary - Layout::FastScale(1);
441 ytop += Layout::Scale(14);
442 ybottom -= Layout::Scale(14);
444 x = rc.right - 2 * arrow_x_size;
446 // only draw speed command if flying and vario is not circling
447 if ((Calculated().flight.flying)
448 && (!Basic().gps.simulator || !Calculated().circling)) {
449 v_diff = Calculated().V_stf - Basic().indicated_airspeed;
450 v_diff = Clamp(v_diff, -DELTA_V_LIMIT, DELTA_V_LIMIT); // limit it
451 v_diff = iround(v_diff/DELTA_V_STEP) * DELTA_V_STEP;
452 } else
453 v_diff = fixed(0);
455 if (!IsPersistent() || last_v_diff != v_diff || dirty) {
456 last_v_diff = v_diff;
458 if (IsPersistent()) {
459 // bottom (too slow)
460 canvas.DrawFilledRectangle(x, ybottom + YOFFSET,
461 x + arrow_x_size * 2 + 1,
462 ybottom + YOFFSET + nary + arrow_y_size +
463 Layout::FastScale(2),
464 look.background_color);
466 // top (too fast)
467 canvas.DrawFilledRectangle(x, ytop - YOFFSET + 1,
468 x + arrow_x_size * 2 +1,
469 ytop - YOFFSET - nary + 1 - arrow_y_size -
470 Layout::FastScale(2),
471 look.background_color);
474 RenderClimb(canvas);
476 canvas.SelectNullPen();
478 if (look.colors) {
479 if (positive(v_diff)) {
480 // too slow
481 canvas.Select(look.sink_brush);
482 } else {
483 canvas.Select(look.lift_brush);
485 } else {
486 if (look.inverse)
487 canvas.SelectWhiteBrush();
488 else
489 canvas.SelectBlackBrush();
492 if (positive(v_diff)) {
493 // too slow
494 y = ybottom;
495 y += YOFFSET;
497 while (positive(v_diff)) {
498 if (v_diff > DELTA_V_STEP) {
499 canvas.Rectangle(x, y,
500 x + arrow_x_size * 2 + 1, y + arrow_y_size - 1);
501 } else {
502 RasterPoint arrow[3];
503 arrow[0].x = x;
504 arrow[0].y = y;
505 arrow[1].x = x + arrow_x_size;
506 arrow[1].y = y + arrow_y_size - 1;
507 arrow[2].x = x + 2 * arrow_x_size;
508 arrow[2].y = y;
509 canvas.DrawTriangleFan(arrow, 3);
511 v_diff -= DELTA_V_STEP;
512 y += arrow_y_size;
514 } else if (negative(v_diff)) {
515 // too fast
516 y = ytop;
517 y -= YOFFSET;
519 while (negative(v_diff)) {
520 if (v_diff < -DELTA_V_STEP) {
521 canvas.Rectangle(x, y + 1,
522 x + arrow_x_size * 2 + 1, y - arrow_y_size + 2);
523 } else {
524 RasterPoint arrow[3];
525 arrow[0].x = x;
526 arrow[0].y = y;
527 arrow[1].x = x + arrow_x_size;
528 arrow[1].y = y - arrow_y_size + 1;
529 arrow[2].x = x + 2 * arrow_x_size;
530 arrow[2].y = y;
531 canvas.DrawTriangleFan(arrow, 3);
533 v_diff += DELTA_V_STEP;
534 y -= arrow_y_size;
540 void
541 GaugeVario::RenderBallast(Canvas &canvas)
543 static unsigned last_ballast = -1;
544 static PixelRect label_rect = {-1,-1,-1,-1};
545 static PixelRect value_rect = {-1,-1,-1,-1};
546 static RasterPoint label_pos = {-1,-1};
547 static RasterPoint value_pos = {-1,-1};
549 if (!ballast_initialised) { // ontime init, origin and background rect
550 const PixelRect rc = GetClientRect();
552 PixelSize tSize;
554 // position of ballast label
555 label_pos.x = 1;
556 label_pos.y = rc.top + 2
557 + look.text_font->GetCapitalHeight() * 2
558 - look.text_font->GetAscentHeight();
560 // position of ballast value
561 value_pos.x = 1;
562 value_pos.y = rc.top + 1
563 + look.text_font->GetCapitalHeight()
564 - look.text_font->GetAscentHeight();
566 // set upper left corner
567 label_rect.left = label_pos.x;
568 label_rect.top = label_pos.y
569 + look.text_font->GetAscentHeight()
570 - look.text_font->GetCapitalHeight();
572 // set upper left corner
573 value_rect.left = value_pos.x;
574 value_rect.top = value_pos.y
575 + look.text_font->GetAscentHeight()
576 - look.text_font->GetCapitalHeight();
578 // get max label size
579 canvas.Select(*look.text_font);
580 tSize = canvas.CalcTextSize(TEXT_BALLAST);
582 // update back rect with max label size
583 label_rect.right = label_rect.left + tSize.cx;
584 label_rect.bottom = label_rect.top +
585 look.text_font->GetCapitalHeight();
587 // get max value size
588 tSize = canvas.CalcTextSize(_T("100%"));
590 value_rect.right = value_rect.left + tSize.cx;
591 // update back rect with max label size
592 value_rect.bottom = value_rect.top +
593 look.text_font->GetCapitalHeight();
595 ballast_initialised = true;
598 unsigned ballast = uround(GetGlidePolar().GetBugs() * 100);
600 if (!IsPersistent() || ballast != last_ballast) {
601 // ballast hase been changed
603 canvas.Select(*look.text_font);
605 if (IsPersistent())
606 canvas.SetBackgroundColor(look.background_color);
607 else
608 canvas.SetBackgroundTransparent();
610 if (IsPersistent() || last_ballast == 0 || ballast == 0) {
611 // new ballast is 0, hide label
612 if (ballast > 0) {
613 canvas.SetTextColor(look.dimmed_text_color);
614 // ols ballast was 0, show label
615 if (IsPersistent())
616 canvas.DrawOpaqueText(label_pos.x, label_pos.y, label_rect, TEXT_BALLAST);
617 else
618 canvas.DrawText(label_pos.x, label_pos.y, TEXT_BALLAST);
619 } else if (IsPersistent())
620 canvas.DrawFilledRectangle(label_rect, look.background_color);
623 // new ballast 0, hide value
624 if (ballast > 0) {
625 TCHAR buffer[18];
626 _stprintf(buffer, _T("%u%%"), ballast);
627 canvas.SetTextColor(look.text_color);
629 if (IsPersistent())
630 canvas.DrawOpaqueText(value_pos.x, value_pos.y, value_rect, buffer);
631 else
632 canvas.DrawText(value_pos.x, value_pos.y, buffer);
633 } else if (IsPersistent())
634 canvas.DrawFilledRectangle(value_rect, look.background_color);
636 if (IsPersistent())
637 last_ballast = ballast;
641 void
642 GaugeVario::RenderBugs(Canvas &canvas)
644 static int last_bugs = -1;
645 static PixelRect label_rect = {-1,-1,-1,-1};
646 static PixelRect value_rect = {-1,-1,-1,-1};
647 static RasterPoint label_pos = {-1,-1};
648 static RasterPoint value_pos = {-1,-1};
650 if (!bugs_initialised) {
651 const PixelRect rc = GetClientRect();
652 PixelSize tSize;
654 label_pos.x = 1;
655 label_pos.y = rc.bottom - 2
656 - look.text_font->GetCapitalHeight()
657 - look.text_font->GetAscentHeight();
659 value_pos.x = 1;
660 value_pos.y = rc.bottom - 1
661 - look.text_font->GetAscentHeight();
663 label_rect.left = label_pos.x;
664 label_rect.top = label_pos.y
665 + look.text_font->GetAscentHeight()
666 - look.text_font->GetCapitalHeight();
667 value_rect.left = value_pos.x;
668 value_rect.top = value_pos.y
669 + look.text_font->GetAscentHeight()
670 - look.text_font->GetCapitalHeight();
672 canvas.Select(*look.text_font);
673 tSize = canvas.CalcTextSize(TEXT_BUG);
675 label_rect.right = label_rect.left + tSize.cx;
676 label_rect.bottom = label_rect.top
677 + look.text_font->GetCapitalHeight()
678 + look.text_font->GetHeight()
679 - look.text_font->GetAscentHeight();
681 tSize = canvas.CalcTextSize(_T("100%"));
683 value_rect.right = value_rect.left + tSize.cx;
684 value_rect.bottom = value_rect.top +
685 look.text_font->GetCapitalHeight();
687 bugs_initialised = true;
690 int bugs = iround((fixed(1) - GetComputerSettings().polar.bugs) * 100);
691 if (!IsPersistent() || bugs != last_bugs) {
693 canvas.Select(*look.text_font);
695 if (IsPersistent())
696 canvas.SetBackgroundColor(look.background_color);
697 else
698 canvas.SetBackgroundTransparent();
700 if (IsPersistent() || last_bugs < 1 || bugs < 1) {
701 if (bugs > 0) {
702 canvas.SetTextColor(look.dimmed_text_color);
703 if (IsPersistent())
704 canvas.DrawOpaqueText(label_pos.x, label_pos.y, label_rect, TEXT_BUG);
705 else
706 canvas.DrawText(label_pos.x, label_pos.y, TEXT_BUG);
707 } else if (IsPersistent())
708 canvas.DrawFilledRectangle(label_rect, look.background_color);
711 if (bugs > 0) {
712 TCHAR buffer[18];
713 _stprintf(buffer, _T("%d%%"), bugs);
714 canvas.SetTextColor(look.text_color);
715 if (IsPersistent())
716 canvas.DrawOpaqueText(value_pos.x, value_pos.y, value_rect, buffer);
717 else
718 canvas.DrawText(value_pos.x, value_pos.y, buffer);
719 } else if (IsPersistent())
720 canvas.DrawFilledRectangle(value_rect, look.background_color);
722 if (IsPersistent())
723 last_bugs = bugs;
727 void
728 GaugeVario::OnResize(PixelSize new_size)
730 AntiFlickerWindow::OnResize(new_size);
732 /* trigger reinitialisation */
733 xoffset = new_size.cx;
734 yoffset = new_size.cy / 2;
735 layout_initialised = false;
736 needle_initialised = false;
737 ballast_initialised = false;
738 bugs_initialised = false;
740 value_top.initialised = false;
741 value_middle.initialised = false;
742 value_bottom.initialised = false;
743 label_top.initialised = false;
744 label_middle.initialised = false;
745 label_bottom.initialised = false;