]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/sp_panel.cxx
Sep 8, 2000 panel updates from David Megginson.
[flightgear.git] / src / Cockpit / sp_panel.cxx
1 //  sp_panel.cxx - default, 2D single-engine prop instrument panel
2 //
3 //  Written by David Megginson, started January 2000.
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License as
7 //  published by the Free Software Foundation; either version 2 of the
8 //  License, or (at your option) any later version.
9 // 
10 //  This program is distributed in the hope that it will be useful, but
11 //  WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //  General Public License for more details.
14 // 
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //
19 //  $Id$
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #ifdef HAVE_WINDOWS_H          
26 #  include <windows.h>
27 #endif
28
29 #include <map>
30
31 #include <simgear/debug/logstream.hxx>
32
33 #include <Main/bfi.hxx>
34 #include <Main/globals.hxx>
35
36 #include "panel.hxx"
37 #include "steam.hxx"
38 #include "radiostack.hxx"
39
40 FG_USING_STD(map);
41
42                                 // Macros for instrument sizes
43                                 // (these aren't used consistently
44                                 // anyway, and should probably be
45                                 // removed).
46 #define SIX_X 200
47 #define SIX_Y 345
48 #define SIX_W 128
49 #define SIX_SPACING (SIX_W + 5)
50 #define SMALL_W 112
51
52 #define createTexture(a) FGTextureManager::createTexture(a)
53 #define V(n) (current_properties.getValue(n, true))
54
55
56 \f
57 ////////////////////////////////////////////////////////////////////////
58 // Static functions for obtaining settings.
59 //
60 // These are all temporary, and should be moved somewhere else
61 // as soon as convenient.
62 ////////////////////////////////////////////////////////////////////////
63
64 static const string &panelGetTime ()
65 {
66   static string out;            // FIXME: not thread-safe
67   char buf[16];
68   struct tm * t = globals->get_time_params()->getGmt();
69   sprintf(buf, " %.2d:%.2d:%.2d",
70           t->tm_hour, t->tm_min, t->tm_sec);
71   out = buf;
72   return out;
73 }
74
75 static bool panelGetNAV1TO ()
76 {
77   if (current_radiostack->get_nav1_inrange()) {
78     double heading = current_radiostack->get_nav1_heading();
79     double radial = current_radiostack->get_nav1_radial();
80     double var = FGBFI::getMagVar();
81     if (current_radiostack->get_nav1_loc()) {
82       double offset = fabs(heading - radial);
83       return (offset<= 8.0 || offset >= 352.0);
84     } else {
85       double offset =
86         fabs(heading - var - radial);
87       return (offset <= 20.0 || offset >= 340.0);
88     }
89   } else {
90     return false;
91   }
92 }
93
94 static bool panelGetNAV1FROM ()
95 {
96   if (current_radiostack->get_nav1_inrange()) {
97     double heading = current_radiostack->get_nav1_heading();
98     double radial = current_radiostack->get_nav1_radial();
99     double var = FGBFI::getMagVar();
100     if (current_radiostack->get_nav1_loc()) {
101       double offset = fabs(heading - radial);
102       return (offset >= 172.0 && offset<= 188.0);
103     } else {
104       double offset =
105         fabs(heading - var - radial);
106       return (offset >= 160.0 && offset <= 200.0);
107     }
108   } else {
109     return false;
110   }
111 }
112
113 static bool panelGetNAV2TO ()
114 {
115   if (current_radiostack->get_nav2_inrange()) {
116     double heading = current_radiostack->get_nav2_heading();
117     double radial = current_radiostack->get_nav2_radial();
118     double var = FGBFI::getMagVar();
119     if (current_radiostack->get_nav2_loc()) {
120       double offset = fabs(heading - radial);
121       return (offset<= 8.0 || offset >= 352.0);
122     } else {
123       double offset =
124         fabs(heading - var - radial);
125       return (offset <= 20.0 || offset >= 340.0);
126     }
127   } else {
128     return false;
129   }
130 }
131
132 static bool panelGetNAV2FROM ()
133 {
134   if (current_radiostack->get_nav2_inrange()) {
135     double heading = current_radiostack->get_nav2_heading();
136     double radial = current_radiostack->get_nav2_radial();
137     double var = FGBFI::getMagVar();
138     if (current_radiostack->get_nav2_loc()) {
139       double offset = fabs(heading - radial);
140       return (offset >= 172.0 && offset<= 188.0);
141     } else {
142       double offset =
143         fabs(heading - var - radial);
144       return (offset >= 160.0 && offset <= 200.0);
145     }
146   } else {
147     return false;
148   }
149 }
150
151
152 \f
153 ////////////////////////////////////////////////////////////////////////
154 // Cropped textures, with string keys.
155 ////////////////////////////////////////////////////////////////////////
156
157                                 // External representation of data.
158 struct TextureData
159 {
160   const char * name;            // the cropped texture's name
161   const char * path;            // the source texture file
162
163                                 // the rectangular area containing
164                                 // the texture (0.0-1.0)
165   float xMin, yMin, xMax, yMax;
166 };
167
168
169                                 // This table is temporarily hard-coded,
170                                 // but soon it will be initialized from
171                                 // an XML file at runtime.
172 TextureData textureData[] = {
173 {"compassFront", "Textures/Panel/misc-1.rgb",
174   48.0/128.0, 0.0, 1.0, 24.0/128.0},
175 {"airspeedBG", "Textures/Panel/faces-2.rgb",
176    0, 0.5, 0.5, 1.0},
177 {"longNeedle", "Textures/Panel/misc-1.rgb",
178    102.0/128.0, 100.0/128.0, 107.0/128.0, 1.0},
179 {"horizonBG", "Textures/Panel/faces-2.rgb",
180    0.5, 0.5, 1.0, 1.0},
181 {"horizonFloat", "Textures/Panel/misc-1.rgb",
182    15.0/32.0, 54.0/128.0, 28.0/32.0, 87.0/128.0},
183 {"horizonRim", "Textures/Panel/faces-2.rgb",
184    0, 0, 0.5, 0.5},
185 {"horizonFront", "Textures/Panel/faces-2.rgb",
186    0.5, 0.0, 1.0, 0.5},
187 {"altimeterBG", "Textures/Panel/faces-1.rgb",
188    0.5, 0.5, 1.0, 1.0},
189 {"shortNeedle", "Textures/Panel/misc-1.rgb",
190    107.0/128.0, 110.0/128.0, 113.0/128.0, 1.0},
191 {"bug", "Textures/Panel/misc-1.rgb",
192    108.0/128.0, 104.0/128.0, 112.0/128.0, 108.0/128.0},
193 {"turnBG", "Textures/Panel/faces-1.rgb",
194    0.5, 0.0, 1.0, 0.5},
195 {"turnPlane", "Textures/Panel/misc-1.rgb",
196    0.0, 3.0/8.0, 3.0/8.0, 0.5},
197 {"turnBall", "Textures/Panel/misc-1.rgb",
198    108.0/128.0, 100.0/128.0, 112.0/128.0, 104.0/128.0},
199 {"compassBG", "Textures/Panel/faces-1.rgb",
200    0.0, 0.5, 0.5, 1.0},
201 {"compassCenter", "Textures/Panel/misc-1.rgb",
202    15.0/32.0, 11.0/16.0, 25.0/32.0, 1.0},
203 {"headingKnob", "Textures/Panel/misc-1.rgb",
204    0, 64.0/128.0, 21.0/128.0, 85.0/128.0},
205 {"knob", "Textures/Panel/misc-1.rgb",
206    79.0/128.0, 31.0/128.0, 101.0/128.0, 53.0/128.0},
207 {"verticalBG", "Textures/Panel/faces-1.rgb",
208    0.0, 0.0, 0.5, 0.5},
209 {"rpmBG", "Textures/Panel/faces-3.rgb",
210    0.0, 0.5, 0.5, 1.0},
211 {"flapsBG", "Textures/Panel/faces-3.rgb",
212    0.5, 0.5, 1.0, 1.0},
213 {"clockBG", "Textures/Panel/faces-3.rgb",
214    0.5, 0.0, 1.0, 0.5},
215 {"controlsBG", "Textures/Panel/faces-3.rgb",
216    0.0, 0.0, 0.5, 0.5},
217 {"navFG", "Textures/Panel/misc-1.rgb",
218    0, 0, 0.25, 5.0/16.0},
219 {"obsKnob", "Textures/Panel/misc-1.rgb",
220    0.0, 86.0/128.0, 21.0/128.0, 107.0/128.0},
221 {"toFlag", "Textures/Panel/misc-1.rgb",
222    120.0/128.0, 74.0/128.0, 1.0, 80.0/128.0},
223 {"fromFlag", "Textures/Panel/misc-1.rgb",
224    120.0/128.0, 80.0/128.0, 1.0, 86.0/128.0},
225 {"offFlag", "Textures/Panel/misc-1.rgb",
226    120.0/128.0, 0.5, 1.0, 70.0/128.0},
227 {"navNeedle", "Textures/Panel/misc-1.rgb",
228    56.0/128.0, 0.5, 58.0/128.0, 1.0},
229 {"adfNeedle", "Textures/Panel/misc-1.rgb",
230    120.0/128.0, 88.0/128.0, 1.0, 1.0},
231 {"adfKnob", "Textures/Panel/misc-1.rgb",
232    0.0, 107.0/128.0, 21.0/128.0, 1.0},
233 {"adfPlane", "Textures/Panel/misc-1.rgb",
234    102.0/128.0, 32.0/128.0, 1.0, 48.0/128.0},
235 {"adfFace", "Textures/Panel/faces-4.rgb",
236    0.0, 0.5, 0.5, 1.0},
237 {"navRadioBG", "Textures/Panel/radios-1.rgb",
238    0.0, 0.75, 1.0, 1.0},
239 {"adfRadioBG", "Textures/Panel/radios-1.rgb",
240    0.0, 0.5, 1.0, 0.75},
241 {"autopilotBG", "Textures/Panel/radios-1.rgb",
242    0.0, 0.375, 1.0, 0.5},
243 {"hdgButtonOn", "Textures/Panel/misc-1.rgb",
244    39.0/128.0, 118.0/128.0, 54.0/128.0, 128.0/128.0},
245 {"hdgButtonOff", "Textures/Panel/misc-1.rgb",
246    22.0/128.0, 118.0/128.0, 37.0/128.0, 128.0/128.0},
247 {"navButtonOn", "Textures/Panel/misc-1.rgb",
248    39.0/128.0, 106.0/128.0, 54.0/128.0, 116.0/128.0},
249 {"navButtonOff", "Textures/Panel/misc-1.rgb",
250    22.0/128.0, 106.0/128.0, 37.0/128.0, 116.0/128.0},
251 {"altButtonOn", "Textures/Panel/misc-1.rgb",
252    39.0/128.0, 82.0/128.0, 54.0/128.0, 92.0/128.0},
253 {"altButtonOff", "Textures/Panel/misc-1.rgb",
254    22.0/128.0, 82.0/128.0, 37.0/128.0, 92.0/128.0},
255 {"dmeBG", "Textures/Panel/radios-1.rgb",
256    0.0, 0.25, 0.375, 0.375},
257 {"compassRibbon", "Textures/Panel/compass-ribbon.rgb",
258    0.0, 0.0, 1.0, 1.0},
259 {0, 0}
260 };
261
262                                 // Internal representation of
263                                 // data.
264 map<const char *,CroppedTexture> tex;
265
266
267
268 /**
269  * Ugly kludge to delay texture loading.
270  */
271 class MyTexturedLayer : public FGTexturedLayer
272 {
273 public:
274   MyTexturedLayer (const char * name, int w = -1, int h = -1)
275     : FGTexturedLayer(w, h), _name(name), _textureLoaded(false) {}
276
277   virtual void draw ();
278   virtual CroppedTexture &getTexture ();
279
280 private:
281   const char * _name;
282   mutable bool _textureLoaded;
283 };
284
285 CroppedTexture &
286 MyTexturedLayer::getTexture ()
287 {
288   MyTexturedLayer * me = (MyTexturedLayer *)this;
289   if (!_textureLoaded) {
290     _textureLoaded = true;
291     me->setTexture(tex[_name]);
292   }
293   return FGTexturedLayer::getTexture();
294 }
295
296 void
297 MyTexturedLayer::draw ()
298 {
299   getTexture();
300   FGTexturedLayer::draw();
301 }
302
303
304
305 /**
306  * Populate the textureMap from the data table.
307  */
308 static void
309 setupTextures ()
310 {
311   for (int i = 0; textureData[i].name; i++) {
312     tex[textureData[i].name] =
313       CroppedTexture(textureData[i].path, textureData[i].xMin,
314                      textureData[i].yMin, textureData[i].xMax,
315                      textureData[i].yMax);
316   }
317 }
318
319
320 \f
321 ////////////////////////////////////////////////////////////////////////
322 // Special class for magnetic compass ribbon layer.
323 ////////////////////////////////////////////////////////////////////////
324
325 class MagRibbon : public MyTexturedLayer
326 {
327 public:
328   MagRibbon (int w, int h);
329   virtual ~MagRibbon () {}
330
331   virtual void draw ();
332 };
333
334 MagRibbon::MagRibbon (int w, int h)
335   : MyTexturedLayer("compassRibbon", w, h)
336 {
337 }
338
339 void
340 MagRibbon::draw ()
341 {
342   double heading = FGSteam::get_MH_deg();
343   double xoffset, yoffset;
344
345   while (heading >= 360.0) {
346     heading -= 360.0;
347   }
348   while (heading < 0.0) {
349     heading += 360.0;
350   }
351
352   if (heading >= 60.0 && heading <= 180.0) {
353     xoffset = heading / 240.0;
354     yoffset = 0.75;
355   } else if (heading >= 150.0 && heading <= 270.0) {
356     xoffset = (heading - 90.0) / 240.0;
357     yoffset = 0.50;
358   } else if (heading >= 240.0 && heading <= 360.0) {
359     xoffset = (heading - 180.0) / 240.0;
360     yoffset = 0.25;
361   } else {
362     if (heading < 270.0)
363       heading += 360.0;
364     xoffset = (heading - 270.0) / 240.0;
365     yoffset = 0.0;
366   }
367
368   xoffset = 1.0 - xoffset;
369                                 // Adjust to put the number in the centre
370   xoffset -= 0.25;
371
372   CroppedTexture &t = getTexture();
373   t.minX = xoffset;
374   t.minY = yoffset;
375   t.maxX = xoffset + 0.5;
376   t.maxY = yoffset + 0.25;
377   MyTexturedLayer::draw();
378 }
379
380
381 \f
382 ////////////////////////////////////////////////////////////////////////
383 // Instruments.
384 ////////////////////////////////////////////////////////////////////////
385
386 struct TransData
387 {
388   enum Type {
389     End = 0,
390     Rotation,
391     XShift,
392     YShift
393   };
394   Type type;
395   const char * propName;
396   float min, max, factor, offset;
397 };
398
399 struct LayerData
400 {
401   FGInstrumentLayer * layer;
402   TransData transformations[16];
403 };
404
405 struct InstrumentData
406 {
407   const char * name;
408   int x, y, w, h;
409   FGPanelAction * actions[16];
410   LayerData layers[16];
411 };
412
413 InstrumentData instruments[] =
414 {
415
416   {"magcompass", 768, 459, SIX_W, SIX_W/2, {}, {
417     {new MagRibbon(int(SIX_W*0.8), int(SIX_W*0.2))},
418     {new MyTexturedLayer("compassFront", SIX_W, SIX_W*(24.0/80.0))}
419   }},
420
421   {"airspeed", SIX_X, SIX_Y, SIX_W, SIX_W, {}, {
422     {new MyTexturedLayer("airspeedBG", -1, -1)},
423     {new MyTexturedLayer("longNeedle", int(SIX_W*(5.0/64.0)),
424        int(SIX_W*(7.0/16.0))), {
425       {TransData::Rotation, "/steam/airspeed",
426          30.0, 220.0, 36.0/20.0, -54.0},
427       {TransData::YShift, 0,
428          0.0, 0.0, 0.0, SIX_W*(12.0/64.0)}
429     }}
430   }},
431
432   {"horizon", SIX_X + SIX_SPACING, SIX_Y, SIX_W, SIX_W, {}, {
433     {new MyTexturedLayer("horizonBG", -1, -1), {
434       {TransData::Rotation, "/orientation/roll", -360.0, 360.0, -1.0, 0.0}
435     }},
436     {new MyTexturedLayer("horizonFloat",
437        int(SIX_W * (13.0/16.0)), int(SIX_W * (33.0/64.0))), {
438       {TransData::Rotation, "/orientation/roll", -360.0, 360.0, -1.0, 0.0},
439       {TransData::YShift, "/orientation/pitch",
440          -20.0, 20.0, -(1.5/160.0)*SIX_W, 0.0}
441     }},
442     {new MyTexturedLayer("horizonRim", -1, -1), {
443       {TransData::Rotation, "/orientation/roll", -360.0, 360.0, -1.0, 0.0}
444     }},
445     {new MyTexturedLayer("horizonFront", -1, -1)}
446   }},
447
448   {"altimeter", SIX_X + SIX_SPACING + SIX_SPACING, SIX_Y, SIX_W, SIX_W, {}, {
449     {new MyTexturedLayer("altimeterBG", -1, -1)},
450     {new MyTexturedLayer("longNeedle",
451        int(SIX_W*(5.0/64.0)), int(SIX_W*(7.0/16.0))), {
452       {TransData::Rotation, "/steam/altitude",
453          0.0, 100000.0, 360.0/1000.0, 0.0},
454       {TransData::YShift, 0, 0.0, 0.0, 0.0, SIX_W*(12.0/64.0)}
455     }},
456     {new MyTexturedLayer("shortNeedle",
457        int(SIX_W*(6.0/64.0)), int(SIX_W*(18.0/64.0))), {
458       {TransData::Rotation, "/steam/altitude",
459          0.0, 100000.0, 360.0/10000.0, 0.0},
460       {TransData::YShift, 0, 0.0, 0.0, 0.0, SIX_W/8.0}
461     }},
462     {new MyTexturedLayer("bug", int(SIX_W*(4.0/64.0)), int(SIX_W*(4.0/64.0))), {
463       {TransData::Rotation, "/steam/altitude",
464          0.0, 100000.0, 360.0/100000.0, 0.0},
465       {TransData::YShift, 0, 0.0, 0.0, 0.0, SIX_W/2.0-4}
466     }},
467   }},
468
469   {"turn", SIX_X, SIX_Y-SIX_SPACING, SIX_W, SIX_W, {}, {
470     {new MyTexturedLayer("turnBG", -1, -1)},
471     {new MyTexturedLayer("turnPlane", int(SIX_W * 0.75), int(SIX_W * 0.25)), {
472       {TransData::Rotation, "/steam/turn-rate", -2.5, 2.5, 20.0, 0.0},
473       {TransData::YShift, 0, 0.0, 0.0, 0.0, int(SIX_W * 0.0625)}
474     }},
475     {new MyTexturedLayer("turnBall",
476        int(SIX_W * (4.0/64.0)), int(SIX_W * (4.0/64.0))), {
477       {TransData::Rotation, "/steam/slip-skid",
478          -0.1, 0.1, 400.0, 0.0},
479       {TransData::YShift, 0, 0.0, 0.0, 0.0, -(SIX_W/4)+4}
480     }}
481   }},
482
483   {"verticalVelocity", SIX_X+SIX_SPACING+SIX_SPACING, SIX_Y-SIX_SPACING,
484     SIX_W, SIX_W, {}, {
485     {new MyTexturedLayer("verticalBG", -1, -1)},
486     {new MyTexturedLayer("longNeedle",
487        int(SIX_W*(5.0/64.0)), int(SIX_W*(7.0/16.0))), {
488       {TransData::Rotation, "/steam/vertical-speed",
489          -2000.0, 2000.0, 42.0/500.0, 270.0},
490       {TransData::YShift, 0, 0.0, 0.0, 0.0, SIX_W*12.0/64.0}
491     }}
492   }},
493
494   {"controls", SIX_X, SIX_Y-(SIX_SPACING*2), SMALL_W, SMALL_W, {}, {
495     {new MyTexturedLayer("controlsBG", -1, -1)},
496     {new MyTexturedLayer("bug", int(SIX_W*4.0/64.0), int(SIX_W*4.0/64.0)), {
497       {TransData::XShift, "/controls/aileron",
498          -1.0, 1.0, SMALL_W*0.75/2.0, 0.0},
499       {TransData::YShift, 0, 0.0, 0.0, 0.0, (SIX_W/2.0)-12.0}
500     }},
501     {new MyTexturedLayer("bug", int(SIX_W*4.0/64.0), int(SIX_W*4.0/64.0)), {
502       {TransData::Rotation, 0, 0.0, 0.0, 0.0, 180.0},
503       {TransData::XShift, "/controls/rudder",
504          -1.0, 1.0, -SMALL_W*0.75/2.0, 0.0},
505       {TransData::YShift, 0, 0.0, 0.0, 0.0, SIX_W/2.0-12.0}
506     }},
507     {new MyTexturedLayer("bug", int(SIX_W*4.0/64.0), int(SIX_W*4.0/64.0)), {
508       {TransData::Rotation, 0, 0.0, 0.0, 0.0, 270.0},
509       {TransData::YShift, 0, 0.0, 0.0, 0.0, -SMALL_W*3.0/8.0},
510       {TransData::XShift, "/controls/elevator-trim",
511          -1.0, 1.0, SMALL_W*0.75/2.0, 0.0},
512       {TransData::YShift, 0, 0.0, 0.0, 0.0, (SIX_W/2.0)-12.0}
513     }},
514     {new MyTexturedLayer("bug", int(SIX_W*4.0/64.0), int(SIX_W*4.0/64.0)), {
515       {TransData::Rotation, 0, 0.0, 0.0, 0.0, 90.0},
516       {TransData::YShift, 0, 0.0, 0.0, 0.0, -SMALL_W*(3.0/8.0)},
517       {TransData::XShift, "/controls/elevator",
518          -1.0, 1.0, -SMALL_W*0.75/2.0, 0.0},
519       {TransData::YShift, 0, 0.0, 0.0, 0.0, (SIX_W/2.0)-12.0}
520     }}
521   }},
522
523   {"flaps", SIX_X+SIX_SPACING, SIX_Y-(SIX_SPACING*2), SMALL_W, SMALL_W, {}, {
524     {new MyTexturedLayer("flapsBG", -1, -1)},
525     {new MyTexturedLayer("longNeedle",
526        int(SIX_W*(5.0/64.0)), int(SIX_W*(7.0/16.0))), {
527       {TransData::XShift, 0, 0.0, 0.0, 0.0, -(SMALL_W/4) + (SMALL_W/16)},
528       {TransData::Rotation, "/controls/flaps", 0.0, 1.0, 120.0, 30.0},
529       {TransData::YShift, 0, 0.0, 0.0, 0.0, SIX_W*12.0/64.0}
530     }}
531   }},
532
533   {"rpm", SIX_X+(SIX_SPACING*2), SIX_Y-(SIX_SPACING*2), SMALL_W, SMALL_W, {}, {
534     {new MyTexturedLayer("rpmBG", -1, -1)},
535     {new MyTexturedLayer("longNeedle",
536        int(SIX_W*(5.0/64.0)), int(SIX_W*(7.0/16.0))), {
537       {TransData::Rotation, "/controls/throttle", 0.0, 100.0, 300.0, -150.0},
538       {TransData::YShift, 0, 0.0, 0.0, 0.0, SIX_W*12.0/64.0}
539     }}
540   }},
541
542   {"gyro", SIX_X+SIX_SPACING, SIX_Y-SIX_SPACING, SIX_W, SIX_W, {
543     new FGAdjustAction(0, SIX_W/2-SIX_W/5, -SIX_W/2, SIX_W/10, SIX_W/5,
544                        V("/autopilot/settings/heading-magnetic"),
545                        -1.0, -360.0, 360.0, true),
546     new FGAdjustAction(0, SIX_W/2 - SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
547                        V("/autopilot/settings/heading-magnetic"),
548                        1.0, -360.0, 360.0, true),
549     new FGAdjustAction(1, SIX_W/2 - SIX_W/5, -SIX_W/2, SIX_W/10, SIX_W/5,
550                        V("/autopilot/settings/heading-magnetic"),
551                        -5.0, -360.0, 360.0, true),
552     new FGAdjustAction(1, SIX_W/2 - SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
553                        V("/autopilot/settings/heading-magnetic"),
554                        5.0, -360.0, 360.0, true),
555     new FGAdjustAction(0, -SIX_W/2, -SIX_W/2, SIX_W/10, SIX_W/5,
556                        V("/steam/gyro-compass-error"),
557                        -1.0, -360.0, 360.0, true),
558     new FGAdjustAction(0, -SIX_W/2+SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
559                        V("/steam/gyro-compass-error"),
560                        1.0, -360.0, 360.0, true),
561     new FGAdjustAction(1, -SIX_W/2, -SIX_W/2, SIX_W/10, SIX_W/5,
562                        V("/steam/gyro-compass-error"),
563                        -5.0, -360.0, 360.0, true),
564     new FGAdjustAction(1, -SIX_W/2+SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
565                        V("/steam/gyro-compass-error"),
566                        5.0, -360.0, 360.0, true)
567    }, {
568     {new MyTexturedLayer("compassBG", -1, -1), {
569       {TransData::Rotation, "/steam/gyro-compass", -720.0, 720.0, -1.0, 0.0}
570     }},
571     {new MyTexturedLayer("bug",
572                          int(SIX_W*(4.0/64.0)), int(SIX_W*(4.0/64.0))), {
573       {TransData::Rotation, "/autopilot/settings/heading",
574          -720.0, 720.0, 1.0, 180.0},
575       {TransData::Rotation, "/steam/gyro-compass", -720.0, 720.0, -1.0, 0.0},
576       {TransData::YShift, 0, 0.0, 0.0, 0.0, -(SIX_W/2.0)+4}
577     }},
578     {new MyTexturedLayer("compassCenter", int(SIX_W*0.625), int(SIX_W*0.625))},
579     {new MyTexturedLayer("headingKnob",
580        int(SIX_W*(21.0/112.0)), int(SIX_W*(21.0/112.0))), {
581       {TransData::XShift, 0, 0.0, 0.0, 0.0, SIX_W/2-10},
582       {TransData::YShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10},
583       {TransData::Rotation, "/autopilot/settings/heading",
584          -360.0, 360.0, 1.0, 0.0}
585     }},
586     {new MyTexturedLayer("knob",
587                          int(SIX_W*(22.0/112.0)), int(SIX_W*(22.0/112.0))), {
588       {TransData::XShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10},
589       {TransData::YShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10}
590     }}
591
592   }},
593
594   {"chronometer", SIX_X-SIX_SPACING-8, SIX_Y, SMALL_W, SMALL_W, {}, {
595     {new MyTexturedLayer("clockBG")},
596     {new FGTextLayer(SMALL_W, SMALL_W,
597                      new FGTextLayer::Chunk(FGTextLayer::TEXT_VALUE,
598                                             V("/panel/time"))), {
599       {TransData::XShift, 0, 0.0, 0.0, 0.0, SMALL_W*-0.38},
600       {TransData::YShift, 0, 0.0, 0.0, 0.0, SMALL_W*-0.06}
601     }}
602   }},
603
604   {"nav1", SIX_X+(SIX_SPACING*3)+20, SIX_Y, SIX_W, SIX_W, {
605     new FGAdjustAction(0, -SIX_W/2, -SIX_W/2, SIX_W/10, SIX_W/5,
606                        V("/radios/nav1/radials/selected"),
607                        1.0, 0.0, 360.0, true),
608     new FGAdjustAction(0, -SIX_W/2 + SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
609                        V("/radios/nav1/radials/selected"),
610                        -1.0, 0.0, 360.0, true),
611     new FGAdjustAction(1, -SIX_W/2, -SIX_W/2, SIX_W/10, SIX_W/5,
612                        V("/radios/nav1/radials/selected"),
613                        5.0, 0.0, 360.0, true),
614     new FGAdjustAction(1, -SIX_W/2 + SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
615                        V("/radios/nav1/radials/selected"),
616                        -5.0, 0.0, 360.0, true)
617   }, {
618     {new MyTexturedLayer("compassBG"), {
619       {TransData::Rotation, "/radios/nav1/radials/selected",
620          -360.0, 360.0, -1.0, 0.0}
621     }},
622     {new MyTexturedLayer("navFG", SIX_W/2, int(SIX_W*(5.0/8.0)))},
623     {new MyTexturedLayer("obsKnob", int(SIX_W*(21.0/112.0)),
624                          int(SIX_W*(21.0/112.0))), {
625       {TransData::XShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10},
626       {TransData::YShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10},
627       {TransData::Rotation, "/radios/nav1/radials/selected",
628          -360.0, 360.0, 1.0, 0.0}
629     }},
630     {new FGSwitchLayer(SIX_W/8, SIX_W/8, V("/panel/vor1/to-flag"),
631                        new MyTexturedLayer("toFlag", SIX_W/8, SIX_W/8),
632                        new FGSwitchLayer(SIX_W/8, SIX_W/8,
633                                          V("/panel/vor1/from-flag"),
634                                          new MyTexturedLayer("fromFlag",
635                                                              SIX_W/8,
636                                                              SIX_W/8),
637                                          new MyTexturedLayer("offFlag",
638                                                              SIX_W/8,
639                                                              SIX_W/8))), {
640       {TransData::YShift, 0, 0.0, 0.0, 0.0, -int(SIX_W*0.1875)}
641     }},
642     {new MyTexturedLayer("navNeedle", SIX_W/32, SIX_W/2), {
643       {TransData::XShift, "/steam/vor1",
644          -10.0, 10.0, SIX_W/40.0, 0.0}
645     }},
646     {new MyTexturedLayer("navNeedle", SIX_W/32, SIX_W/2), {
647       {TransData::YShift, "/steam/glidescope1", -1.0, 1.0, SIX_W/5.0, 0.0},
648       {TransData::Rotation, 0, 0.0, 0.0, 0.0, 90}
649     }}
650   }},
651
652   {"nav2", SIX_X+(SIX_SPACING*3)+20, SIX_Y-SIX_SPACING, SIX_W, SIX_W, {
653     new FGAdjustAction(0, -SIX_W/2, -SIX_W/2, SIX_W/10, SIX_W/5,
654                        V("/radios/nav2/radials/selected"),
655                        1.0, 0.0, 360.0, true),
656     new FGAdjustAction(0, -SIX_W/2 + SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
657                        V("/radios/nav2/radials/selected"),
658                        -1.0, 0.0, 360.0, true),
659     new FGAdjustAction(1, -SIX_W/2, -SIX_W/2, SIX_W/10, SIX_W/5,
660                        V("/radios/nav2/radials/selected"),
661                        5.0, 0.0, 360.0, true),
662     new FGAdjustAction(1, -SIX_W/2 + SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
663                        V("/radios/nav2/radials/selected"),
664                        -5.0, 0.0, 360.0, true)
665   }, {
666     {new MyTexturedLayer("compassBG"), {
667       {TransData::Rotation, "/radios/nav2/radials/selected",
668          -360.0, 360.0, -1.0, 0.0}
669     }},
670     {new MyTexturedLayer("navFG", SIX_W/2, int(SIX_W*(5.0/8.0)))},
671     {new MyTexturedLayer("obsKnob", int(SIX_W*(21.0/112.0)),
672                          int(SIX_W*(21.0/112.0))), {
673       {TransData::XShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10},
674       {TransData::YShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10},
675       {TransData::Rotation, "/radios/nav2/radials/selected",
676          -360.0, 360.0, 1.0, 0.0}
677     }},
678     {new FGSwitchLayer(SIX_W/8, SIX_W/8, V("/panel/vor2/to-flag"),
679                        new MyTexturedLayer("toFlag", SIX_W/8, SIX_W/8),
680                        new FGSwitchLayer(SIX_W/8, SIX_W/8,
681                                          V("/panel/vor2/from-flag"),
682                                          new MyTexturedLayer("fromFlag",
683                                                              SIX_W/8,
684                                                              SIX_W/8),
685                                          new MyTexturedLayer("offFlag",
686                                                              SIX_W/8,
687                                                              SIX_W/8))), {
688       {TransData::YShift, 0, 0.0, 0.0, 0.0, -int(SIX_W*0.1875)}
689     }},
690     {new MyTexturedLayer("navNeedle", SIX_W/32, SIX_W/2), {
691       {TransData::XShift, "/steam/vor2",
692          -10.0, 10.0, SIX_W/40.0, 0.0}
693     }}
694   }},
695
696   {"adf", SIX_X+(SIX_SPACING*3)+20, SIX_Y-(SIX_SPACING*2), SIX_W, SIX_W, {
697     new FGAdjustAction(0, -SIX_W/2, -SIX_W/2, SIX_W/10, SIX_W/5,
698                        V("/radios/adf/rotation"),
699                        -1.0, 0.0, 360.0, true),
700     new FGAdjustAction(0, -SIX_W/2 + SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
701                        V("/radios/adf/rotation"),
702                        1.0, 0.0, 360.0, true),
703     new FGAdjustAction(1, -SIX_W/2, -SIX_W/2, SIX_W/10, SIX_W/5,
704                        V("/radios/adf/rotation"),
705                        -5.0, 0.0, 360.0, true),
706        
707     new FGAdjustAction(1, -SIX_W/2 + SIX_W/10, -SIX_W/2, SIX_W/10, SIX_W/5,
708                        V("/radios/adf/rotation"),
709                        5.0, 0.0, 360.0, true)
710   },{
711     {new MyTexturedLayer("compassBG"), {
712       {TransData::Rotation, "/radios/adf/rotation", 0.0, 360.0, 1.0, 0.0}
713     }},
714     {new MyTexturedLayer("adfFace", -1, -1), {}},
715     {new MyTexturedLayer("adfNeedle", SIX_W/8, int(SIX_W*0.625)), {
716       {TransData::Rotation, "/steam/adf", -720.0, 720.0, 1.0, 0.0}
717     }},
718     {new MyTexturedLayer("adfKnob", int(SIX_W*(21.0/112.0)),
719                          int(SIX_W*(21.0/112.0))), {
720       {TransData::XShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10},
721       {TransData::YShift, 0, 0.0, 0.0, 0.0, -SIX_W/2+10},
722       {TransData::Rotation, "/radios/adf/rotation", 0.0, 360.0, 1.0, 0.0}
723     }}
724   }},
725
726   {0}
727
728 };
729
730
731 \f
732 ////////////////////////////////////////////////////////////////////////
733 // Static factory functions to create textured gauges.
734 //
735 // These will be replaced first with a giant table, and then with
736 // configuration files read from an external source, but for now
737 // they're hard-coded.
738 ////////////////////////////////////////////////////////////////////////
739
740
741 /**
742  * Create Nav-Com radio 1.
743  */
744 static FGPanelInstrument *
745 createNavCom1 (int x, int y)
746 {
747   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W*2, SIX_W/2);
748
749                                 // Use the button to swap standby and active
750                                 // NAV frequencies
751   inst->addAction(new FGSwapAction(0, int(SIX_W * .375),
752                                    -SIX_W/4, SIX_W/4, SIX_W/4,
753                                    V("/radios/nav1/frequencies/selected"),
754                                    V("/radios/nav1/frequencies/standby")));
755
756                                 // Use the knob to tune the standby NAV
757   inst->addAction(new FGAdjustAction(0, SIX_W-SIX_W/4, -SIX_W/4,
758                                      SIX_W/8, SIX_W/4,
759                                      V("/radios/nav1/frequencies/standby"),
760                                      -0.05, 108.0, 117.95, true));
761   inst->addAction(new FGAdjustAction(0, SIX_W-SIX_W/8, -SIX_W/4,
762                                      SIX_W/8, SIX_W/4,
763                                      V("/radios/nav1/frequencies/standby"),
764                                      0.05, 108.0, 117.95, true));
765   inst->addAction(new FGAdjustAction(1, SIX_W-SIX_W/4, -SIX_W/4,
766                                      SIX_W/8, SIX_W/4,
767                                      V("/radios/nav1/frequencies/standby"),
768                                      -0.5, 108.0, 117.95, true));
769   inst->addAction(new FGAdjustAction(1, SIX_W-SIX_W/8, -SIX_W/4,
770                                      SIX_W/8, SIX_W/4,
771                                      V("/radios/nav1/frequencies/standby"),
772                                      0.5, 108.0, 117.95, true));
773
774                                 // Layer 0: background
775   inst->addLayer(tex["navRadioBG"], SIX_W*2, SIX_W/2);
776
777                                 // Layer 1: NAV frequencies
778   FGTextLayer * text = new FGTextLayer(SIX_W*2, SMALL_W/2);
779   text->addChunk(new
780                  FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE,
781                                     V("/radios/nav1/frequencies/selected"),
782                                     "%.2f"));
783   text->addChunk(new
784                  FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE,
785                                     V("/radios/nav1/frequencies/standby"),
786                                     "%7.2f"));
787   text->setPointSize(14);
788   text->setColor(1.0, 0.5, 0.0);
789   inst->addLayer(text);
790   inst->addTransformation
791     (new FGPanelTransformation(FGPanelTransformation::XSHIFT, 0,
792                                0.0, 0.0, 0.0, 3));
793   inst->addTransformation
794     (new FGPanelTransformation(FGPanelTransformation::YSHIFT, 0,
795                                0.0, 0.0, 0.0, 5));
796
797   return inst;
798 }
799
800
801 /**
802  * Create Nav-Com radio 2.
803  */
804 static FGPanelInstrument *
805 createNavCom2 (int x, int y)
806 {
807   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W*2, SIX_W/2);
808
809                                 // Use the button to swap standby and active
810                                 // NAV frequencies
811   inst->addAction(new FGSwapAction(0, int(SIX_W * .375), -SIX_W/4, SIX_W/4, SIX_W/4,
812                   V("/radios/nav2/frequencies/selected"),
813                                    V("/radios/nav2/frequencies/standby")));
814
815                                 // Use the knob to tune the standby NAV
816   inst->addAction(new FGAdjustAction(0, SIX_W-SIX_W/4, -SIX_W/4, SIX_W/8, SIX_W/4,
817                   V("/radios/nav2/frequencies/standby"),
818                                      -0.05, 108.0, 117.95, true));
819   inst->addAction(new FGAdjustAction(0, SIX_W-SIX_W/8, -SIX_W/4, SIX_W/8, SIX_W/4,
820                   V("/radios/nav2/frequencies/standby"),
821                                      0.05, 108.0, 117.95, true));
822   inst->addAction(new FGAdjustAction(1, SIX_W-SIX_W/4, -SIX_W/4, SIX_W/8, SIX_W/4,
823                   V("/radios/nav2/frequencies/standby"),
824                                      -0.5, 108.0, 117.95, true));
825   inst->addAction(new FGAdjustAction(1, SIX_W-SIX_W/8, -SIX_W/4, SIX_W/8, SIX_W/4,
826                   V("/radios/nav2/frequencies/standby"),
827                                      0.5, 108.0, 117.95, true));
828
829                                 // Layer 0: background
830   inst->addLayer(tex["navRadioBG"], SIX_W*2, SIX_W/2);
831
832                                 // Layer 1: NAV frequencies
833   FGTextLayer * text = new FGTextLayer(SIX_W*2, SIX_W/2);
834   text->addChunk(new
835                  FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE,
836                                     V("/radios/nav2/frequencies/selected"),
837                                     "%.2f"));
838   text->addChunk(new
839                  FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE,
840                                     V("/radios/nav2/frequencies/standby"),
841                                     "%7.2f"));
842   text->setPointSize(14);
843   text->setColor(1.0, 0.5, 0.0);
844   inst->addLayer(text);
845   inst->addTransformation
846     (new FGPanelTransformation(FGPanelTransformation::XSHIFT, 0,
847                                0.0, 0.0, 1.0, 3));
848   inst->addTransformation
849     (new FGPanelTransformation(FGPanelTransformation::YSHIFT, 0,
850                                0.0, 0.0, 1.0, 5));
851
852   return inst;
853 }
854
855
856 /**
857  * Create ADF radio.
858  */
859 static FGPanelInstrument *
860 createADFRadio (int x, int y)
861 {
862   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W*2, SIX_W/2);
863
864                                 // Use the knob to tune the standby NAV
865   inst->addAction(new FGAdjustAction(0, int(SIX_W * 0.7), int(-SIX_W * 0.07),
866                   int(SIX_W * 0.09), int(SIX_W * 0.14),
867                   V("/radios/adf/frequencies/selected"),
868                                      -1.0, 100.0, 1299, true));
869   inst->addAction(new FGAdjustAction(0, int(SIX_W * 0.79), int(-SIX_W * 0.07),
870                   int(SIX_W * 0.09), int(SIX_W * 0.14),
871                   V("/radios/adf/frequencies/selected"),
872                                      1.0, 100.0, 1299, true));
873   inst->addAction(new FGAdjustAction(1, int(SIX_W * 0.7), int(-SIX_W * 0.07),
874                   int(SIX_W * 0.09), int(SIX_W * 0.14),
875                   V("/radios/adf/frequencies/selected"),
876                                      -25.0, 100.0, 1299, true));
877   inst->addAction(new FGAdjustAction(1, int(SIX_W * 0.79), int(-SIX_W * 0.07),
878                   int(SIX_W * 0.09), int(SIX_W * 0.14),
879                   V("/radios/adf/frequencies/selected"),
880                                      25.0, 100.0, 1299, true));
881
882                                 // Layer 0: background
883   inst->addLayer(tex["adfRadioBG"], SIX_W*2, SIX_W/2);
884
885                                 // Layer: ADF frequency
886   FGTextLayer * text = new FGTextLayer(SIX_W*2, SIX_W/2);
887   text->addChunk(new
888                  FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE,
889                                     V("/radios/adf/frequencies/selected"),
890                                     "%4.0f"));
891   text->setPointSize(14);
892   text->setColor(1.0, 0.5, 0.0);
893   inst->addLayer(text);
894   inst->addTransformation
895     (new FGPanelTransformation(FGPanelTransformation::XSHIFT, 0,
896                                0.0, 0.0, 1.0, -SIX_W + 18));
897
898   return inst;
899 }
900
901
902 /**
903  * Construct the autopilot.
904  */
905
906 FGPanelInstrument *
907 createAP (int x, int y)
908 {
909   FGLayeredInstrument * inst = new FGLayeredInstrument(x, y, SIX_W*2, SIX_W/4);
910
911                                 // Action: select HDG button
912   inst->addAction(new FGToggleAction(0, int(-SIX_W*0.6125), -SIX_W/16, SIX_W/4, SIX_W/8,
913                   V("/autopilot/locks/heading")));
914
915                                 // Action: select NAV button
916   inst->addAction(new FGToggleAction(0, int(-SIX_W*0.3625), -SIX_W/16, SIX_W/4, SIX_W/8,
917                   V("/autopilot/locks/nav1")));
918
919                                 // Action: select ALT button
920   inst->addAction(new FGToggleAction(0, int(-SIX_W*0.1125), -SIX_W/16, SIX_W/4, SIX_W/8,
921                   V("/autopilot/locks/altitude")));
922
923                                 // Layer: AP background
924   inst->addLayer(tex["autopilotBG"], SIX_W*2, SIX_W/4);
925
926                                 // Display HDG button
927   FGSwitchLayer * sw =
928     new FGSwitchLayer(SIX_W/4, SIX_W/8, V("/autopilot/locks/heading"),
929                       new FGTexturedLayer(tex["hdgButtonOn"], SIX_W/4, SIX_W/8),
930                       new FGTexturedLayer(tex["hdgButtonOff"], SIX_W/4, SIX_W/8));
931   inst->addLayer(sw);
932   inst->addTransformation
933     (new FGPanelTransformation(FGPanelTransformation::XSHIFT, 0,
934                                0.0, 0.0, 1.0, -SIX_W * 0.5));
935
936                                 // Display NAV button
937   sw = new FGSwitchLayer(SIX_W/4, SIX_W/8, V("/autopilot/locks/nav1"),
938                          new FGTexturedLayer(tex["navButtonOn"], SIX_W/4, SIX_W/8),
939                          new FGTexturedLayer(tex["navButtonOff"], SIX_W/4, SIX_W/8));
940   inst->addLayer(sw);
941   inst->addTransformation
942     (new FGPanelTransformation(FGPanelTransformation::XSHIFT, 0,
943                                0.0, 0.0, 1.0, -SIX_W * 0.25));
944
945                                 // Display ALT button
946   sw = new FGSwitchLayer(SIX_W/4, SIX_W/8, V("/autopilot/locks/altitude"),
947                          new FGTexturedLayer(tex["altButtonOn"], SIX_W/4, SIX_W/8),
948                          new FGTexturedLayer(tex["altButtonOff"], SIX_W/4, SIX_W/8));
949   inst->addLayer(sw);
950
951   return inst;
952 }
953
954 FGPanelInstrument * 
955 createDME (int x, int y)
956 {
957   FGLayeredInstrument * inst =
958     new FGLayeredInstrument(x, y, int(SIX_W * 0.75), int(SIX_W * 0.25));
959
960                                 // Layer: background
961   inst->addLayer(tex["dmeBG"]);
962
963                                 // Layer: current distance
964
965   FGTextLayer * text1 = new FGTextLayer(SIX_W/2, SIX_W/4);
966   text1->addChunk(new FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE,
967                                          V("/radios/nav1/dme/distance"),
968                                          "%05.1f",
969                                          METER_TO_NM));
970   text1->setPointSize(12);
971   text1->setColor(1.0, 0.5, 0.0);
972
973   FGTextLayer * text2 = new FGTextLayer(SIX_W/2, SIX_W/4);
974   text2->addChunk(new FGTextLayer::Chunk("---.-"));
975   text2->setPointSize(12);
976   text2->setColor(1.0, 0.5, 0.0);
977
978   FGSwitchLayer * sw =
979     new FGSwitchLayer(SIX_W/2, SIX_W/4, V("/radios/nav1/dme/in-range"),
980                       text1, text2);
981
982   inst->addLayer(sw);
983   inst->addTransformation
984     (new FGPanelTransformation(FGPanelTransformation::XSHIFT, 0,
985                                0.0, 0.0, 1.0, -20));
986   inst->addTransformation
987     (new FGPanelTransformation(FGPanelTransformation::YSHIFT, 0,
988                                0.0, 0.0, 1.0, -6));
989
990   return inst;
991 }
992
993
994 \f
995 ////////////////////////////////////////////////////////////////////////
996 // Construct a panel for a small, single-prop plane.
997 ////////////////////////////////////////////////////////////////////////
998
999 FGPanel *
1000 fgCreateSmallSinglePropPanel (int xpos, int ypos, int finx, int finy)
1001 {
1002   int w = finx - xpos;
1003   int h = finy - ypos;
1004   FGPanel * panel = new FGPanel(xpos, ypos, w, h);
1005   int x, y;
1006
1007                                 // Tie local functions
1008                                 // FIXME: define these elsewhere...
1009   current_properties.tieString("/panel/time", panelGetTime);
1010   current_properties.tieBool("/panel/vor1/to-flag", panelGetNAV1TO);
1011   current_properties.tieBool("/panel/vor1/from-flag", panelGetNAV1FROM);
1012   current_properties.tieBool("/panel/vor2/to-flag", panelGetNAV2TO);
1013   current_properties.tieBool("/panel/vor2/from-flag", panelGetNAV2FROM);
1014
1015   setupTextures();
1016
1017                                 // Read gauges from data table.
1018   for (int i = 0; instruments[i].name; i++) {
1019     InstrumentData &gauge = instruments[i];
1020     FGLayeredInstrument * inst =
1021       new FGLayeredInstrument(gauge.x, gauge.y, gauge.w, gauge.h);
1022
1023     for (int j = 0; gauge.actions[j]; j++) {
1024       inst->addAction(gauge.actions[j]);
1025     }
1026
1027     for (int j = 0; gauge.layers[j].layer; j++) {
1028       LayerData &layer = gauge.layers[j];
1029 //       inst->addLayer(tex[layer.textureName], layer.w, layer.h);
1030       inst->addLayer(layer.layer);
1031
1032       for (int k = 0; layer.transformations[k].type; k++) {
1033         TransData &trans = layer.transformations[k];
1034         FGPanelTransformation::Type type;
1035         switch (trans.type) {
1036         case TransData::Rotation:
1037           type = FGPanelTransformation::ROTATION;
1038           break;
1039         case TransData::XShift:
1040           type = FGPanelTransformation::XSHIFT;
1041           break;
1042         case TransData::YShift:
1043           type = FGPanelTransformation::YSHIFT;
1044           break;
1045         default:
1046           break;
1047         }
1048         if (trans.propName != 0) {
1049           inst->addTransformation
1050             (new FGPanelTransformation(type, V(trans.propName),
1051                                        trans.min, trans.max,
1052                                        trans.factor, trans.offset));
1053         } else {
1054           inst->addTransformation
1055             (new FGPanelTransformation(type, 0,
1056                                        0.0, 0.0, 1.0, trans.offset));
1057         }
1058       }
1059
1060     }
1061     panel->addInstrument(inst);
1062   }
1063
1064   x = SIX_X;
1065   y = SIX_Y;
1066
1067                                 // Set the background texture
1068   panel->setBackground(createTexture("Textures/Panel/panel-bg.rgb"));
1069
1070                                 // Radio stack
1071   x = SIX_X + (SIX_SPACING * 5);
1072   y = SIX_Y;
1073   panel->addInstrument(createDME(x, y));
1074   y -= (int)(SIX_W * 0.375);
1075   panel->addInstrument(createNavCom1(x, y));
1076   y -= SIX_W / 2;
1077   panel->addInstrument(createNavCom2(x, y));
1078   y -= SIX_W / 2;
1079   panel->addInstrument(createADFRadio(x, y));
1080   y -= (int)(SIX_W * 0.375);
1081   panel->addInstrument(createAP(x, y));
1082
1083   return panel;
1084 }
1085
1086 // end of sp_panel.cxx