]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/panel.cxx
Internal interface changes by David Megginson.
[flightgear.git] / src / Cockpit / panel.cxx
1 //  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 <string.h>
30
31 #include <plib/ssg.h>
32 #include <plib/fnt.h>
33
34 #include <simgear/debug/logstream.hxx>
35 #include <simgear/misc/fgpath.hxx>
36
37 #include <Main/globals.hxx>
38 #include <Main/fg_props.hxx>
39 #include <Objects/texload.h>
40 #include <Time/light.hxx>
41
42 #include "hud.hxx"
43 #include "panel.hxx"
44
45
46 bool
47 fgPanelVisible ()
48 {
49   return ((globals->get_options()->get_panel_status()) &&
50           (globals->get_viewmgr()->get_current() == 0) &&
51           (globals->get_current_view()->get_view_offset() == 0.0));
52 }
53
54
55 \f
56 ////////////////////////////////////////////////////////////////////////
57 // Implementation of FGTextureManager.
58 ////////////////////////////////////////////////////////////////////////
59
60 map<string,ssgTexture *> FGTextureManager::_textureMap;
61
62 ssgTexture *
63 FGTextureManager::createTexture (const string &relativePath)
64 {
65   ssgTexture * texture = _textureMap[relativePath];
66   if (texture == 0) {
67     cerr << "Texture " << relativePath << " does not yet exist" << endl;
68     FGPath tpath(globals->get_options()->get_fg_root());
69     tpath.append(relativePath);
70     texture = new ssgTexture((char *)tpath.c_str(), false, false);
71     _textureMap[relativePath] = texture;
72     if (_textureMap[relativePath] == 0) 
73       cerr << "Texture *still* doesn't exist" << endl;
74     cerr << "Created texture " << relativePath
75          << " handle=" << texture->getHandle() << endl;
76   }
77
78   return texture;
79 }
80
81
82
83 \f
84 ////////////////////////////////////////////////////////////////////////
85 // Implementation of FGCropped Texture.
86 ////////////////////////////////////////////////////////////////////////
87
88
89 FGCroppedTexture::FGCroppedTexture ()
90   : _path(""), _texture(0),
91     _minX(0.0), _minY(0.0), _maxX(1.0), _maxY(1.0)
92 {
93 }
94
95
96 FGCroppedTexture::FGCroppedTexture (const string &path,
97                                     float minX, float minY,
98                                     float maxX, float maxY)
99   : _path(path), _texture(0),
100     _minX(minX), _minY(minY), _maxX(maxX), _maxY(maxY)
101 {
102 }
103
104
105 FGCroppedTexture::~FGCroppedTexture ()
106 {
107 }
108
109
110 ssgTexture *
111 FGCroppedTexture::getTexture ()
112 {
113   if (_texture == 0) {
114     _texture = FGTextureManager::createTexture(_path);
115   }
116   return _texture;
117 }
118
119
120 \f
121 ////////////////////////////////////////////////////////////////////////
122 // Implementation of FGPanel.
123 ////////////////////////////////////////////////////////////////////////
124
125 FGPanel * current_panel = NULL;
126 static fntRenderer text_renderer;
127
128
129 /**
130  * Constructor.
131  */
132 FGPanel::FGPanel (int window_x, int window_y, int window_w, int window_h)
133   : _mouseDown(false),
134     _mouseInstrument(0),
135     _winx(window_x), _winy(window_y), _winw(window_w), _winh(window_h),
136     _width(_winw), _height(int(_winh * 0.5768 + 1)),
137     _x_offset(0), _y_offset(0), _view_height(int(_winh * 0.4232))
138 {
139   setVisibility(fgPanelVisible());
140 }
141
142
143 /**
144  * Destructor.
145  */
146 FGPanel::~FGPanel ()
147 {
148   unbind();
149   for (instrument_list_type::iterator it = _instruments.begin();
150        it != _instruments.end();
151        it++) {
152     delete *it;
153     *it = 0;
154   }
155 }
156
157
158 /**
159  * Add an instrument to the panel.
160  */
161 void
162 FGPanel::addInstrument (FGPanelInstrument * instrument)
163 {
164   _instruments.push_back(instrument);
165 }
166
167
168 /**
169  * Initialize the panel.
170  */
171 void
172 FGPanel::init ()
173 {
174   // NO-OP
175 }
176
177
178 /**
179  * Bind panel properties.
180  */
181 void
182 FGPanel::bind ()
183 {
184   fgTie("/sim/panel/visibility", &_visibility);
185   fgTie("/sim/panel/x-offset", &_x_offset);
186   fgTie("/sim/panel/y-offset", &_y_offset);
187 }
188
189
190 /**
191  * Unbind panel properties.
192  */
193 void
194 FGPanel::unbind ()
195 {
196   fgUntie("/sim/panel/visibility");
197   fgUntie("/sim/panel/x-offset");
198   fgUntie("/sim/panel/y-offset");
199 }
200
201
202 /**
203  * Update the panel.
204  */
205 void
206 FGPanel::update ()
207 {
208                                 // Do nothing if the panel isn't visible.
209   if (!fgPanelVisible())
210     return;
211
212                                 // If the mouse is down, do something
213   if (_mouseDown) {
214     _mouseDelay--;
215     if (_mouseDelay < 0) {
216       _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
217       _mouseDelay = 2;
218     }
219   }
220
221                                 // Now, draw the panel
222   glMatrixMode(GL_PROJECTION);
223   glPushMatrix();
224   glLoadIdentity();
225   gluOrtho2D(_winx, _winx + _winw, _winy, _winy + _winh);
226
227   glMatrixMode(GL_MODELVIEW);
228   glPushMatrix();
229   glLoadIdentity();
230
231   glTranslated(_x_offset, _y_offset, 0);
232
233                                 // Draw the background
234   glEnable(GL_TEXTURE_2D);
235   glDisable(GL_LIGHTING);
236   glEnable(GL_BLEND);
237   glEnable(GL_ALPHA_TEST);
238   glEnable(GL_COLOR_MATERIAL);
239   // glColor4f(1.0, 1.0, 1.0, 1.0);
240   if ( cur_light_params.sun_angle * RAD_TO_DEG < 95.0 ) {
241       glColor4fv( cur_light_params.scene_diffuse );
242   } else {
243       glColor4f(0.7, 0.2, 0.2, 1.0);
244   }
245   glBindTexture(GL_TEXTURE_2D, _bg->getHandle());
246   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
247   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
248   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
249   glBegin(GL_POLYGON);
250   glTexCoord2f(0.0, 0.0); glVertex3f(_winx, _winy, 0);
251   glTexCoord2f(1.0, 0.0); glVertex3f(_winx + _width, _winy, 0);
252   glTexCoord2f(1.0, 1.0); glVertex3f(_winx + _width, _winy + _height, 0);
253   glTexCoord2f(0.0, 1.0); glVertex3f(_winx, _winy + _height, 0);
254   glEnd();
255
256                                 // Draw the instruments.
257   instrument_list_type::const_iterator current = _instruments.begin();
258   instrument_list_type::const_iterator end = _instruments.end();
259
260   for ( ; current != end; current++) {
261     FGPanelInstrument * instr = *current;
262     glLoadIdentity();
263     glTranslated(_x_offset, _y_offset, 0);
264     glTranslated(instr->getXPos(), instr->getYPos(), 0);
265     instr->draw();
266   }
267
268   glMatrixMode(GL_PROJECTION);
269   glPopMatrix();
270   glMatrixMode(GL_MODELVIEW);
271   glPopMatrix();
272   ssgForceBasicState();
273   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
274 }
275
276
277 /**
278  * Set the panel's visibility.
279  */
280 void
281 FGPanel::setVisibility (bool visibility)
282 {
283   _visibility = visibility;
284 }
285
286
287 /**
288  * Return true if the panel is visible.
289  */
290 bool
291 FGPanel::getVisibility () const
292 {
293   return _visibility;
294 }
295
296
297 /**
298  * Set the panel's background texture.
299  */
300 void
301 FGPanel::setBackground (ssgTexture * texture)
302 {
303   _bg = texture;
304 }
305
306
307 /**
308  * Set the panel's x-offset.
309  */
310 void
311 FGPanel::setXOffset (int offset)
312 {
313   if (offset <= 0 && offset >= -_width + _winw)
314     _x_offset = offset;
315 }
316
317
318 /**
319  * Set the panel's y-offset.
320  */
321 void
322 FGPanel::setYOffset (int offset)
323 {
324   if (offset <= 0 && offset >= -_height)
325     _y_offset = offset;
326 }
327
328
329 /**
330  * Perform a mouse action.
331  */
332 bool
333 FGPanel::doMouseAction (int button, int updown, int x, int y)
334 {
335
336                                 // Note a released button and return
337   // cerr << "Doing mouse action\n";
338   if (updown == 1) {
339     _mouseDown = false;
340     _mouseInstrument = 0;
341     return true;
342   }
343
344                                 // Scale for the real window size.
345   x = int(((float)x / globals->get_options()->get_xsize()) * _winw);
346   y = int(_winh - (((float)y / globals->get_options()->get_ysize())
347                    * _winh));
348
349                                 // Adjust for offsets.
350   x -= _x_offset;
351   y -= _y_offset;
352
353                                 // Search for a matching instrument.
354   for (int i = 0; i < (int)_instruments.size(); i++) {
355     FGPanelInstrument *inst = _instruments[i];
356     int ix = inst->getXPos();
357     int iy = inst->getYPos();
358     int iw = inst->getWidth() / 2;
359     int ih = inst->getHeight() / 2;
360     if (x >= ix - iw && x < ix + iw && y >= iy - ih && y < iy + ih) {
361       _mouseDown = true;
362       _mouseDelay = 20;
363       _mouseInstrument = inst;
364       _mouseButton = button;
365       _mouseX = x - ix;
366       _mouseY = y - iy;
367                                 // Always do the action once.
368       _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
369       return true;
370     }
371   }
372   return false;
373 }
374
375
376 \f
377 ////////////////////////////////////////////////////////////////////////.
378 // Implementation of FGPanelAction.
379 ////////////////////////////////////////////////////////////////////////
380
381 FGPanelAction::FGPanelAction ()
382 {
383 }
384
385 FGPanelAction::FGPanelAction (int button, int x, int y, int w, int h)
386   : _button(button), _x(x), _y(y), _w(w), _h(h)
387 {
388 }
389
390 FGPanelAction::~FGPanelAction ()
391 {
392 }
393
394
395 \f
396 ////////////////////////////////////////////////////////////////////////
397 // Implementation of FGAdjustAction.
398 ////////////////////////////////////////////////////////////////////////
399
400 FGAdjustAction::FGAdjustAction (int button, int x, int y, int w, int h,
401                                 SGValue * value, float increment, 
402                                 float min, float max, bool wrap)
403   : FGPanelAction(button, x, y, w, h),
404     _value(value), _increment(increment), _min(min), _max(max), _wrap(wrap)
405 {
406 }
407
408 FGAdjustAction::~FGAdjustAction ()
409 {
410 }
411
412 void
413 FGAdjustAction::doAction ()
414 {
415   float val = _value->getFloatValue();
416   val += _increment;
417   if (val < _min) {
418     val = (_wrap ? _max : _min);
419   } else if (val > _max) {
420     val = (_wrap ? _min : _max);
421   }
422   _value->setDoubleValue(val);
423 }
424
425
426 \f
427 ////////////////////////////////////////////////////////////////////////
428 // Implementation of FGSwapAction.
429 ////////////////////////////////////////////////////////////////////////
430
431 FGSwapAction::FGSwapAction (int button, int x, int y, int w, int h,
432                             SGValue * value1, SGValue * value2)
433   : FGPanelAction(button, x, y, w, h), _value1(value1), _value2(value2)
434 {
435 }
436
437 FGSwapAction::~FGSwapAction ()
438 {
439 }
440
441 void
442 FGSwapAction::doAction ()
443 {
444   float val = _value1->getFloatValue();
445   _value1->setDoubleValue(_value2->getFloatValue());
446   _value2->setDoubleValue(val);
447 }
448
449
450 \f
451 ////////////////////////////////////////////////////////////////////////
452 // Implementation of FGToggleAction.
453 ////////////////////////////////////////////////////////////////////////
454
455 FGToggleAction::FGToggleAction (int button, int x, int y, int w, int h,
456                                 SGValue * value)
457   : FGPanelAction(button, x, y, w, h), _value(value)
458 {
459 }
460
461 FGToggleAction::~FGToggleAction ()
462 {
463 }
464
465 void
466 FGToggleAction::doAction ()
467 {
468   _value->setBoolValue(!(_value->getBoolValue()));
469 }
470
471
472 \f
473 ////////////////////////////////////////////////////////////////////////
474 // Implementation of FGPanelTransformation.
475 ////////////////////////////////////////////////////////////////////////
476
477 FGPanelTransformation::FGPanelTransformation ()
478 {
479 }
480
481 FGPanelTransformation::~FGPanelTransformation ()
482 {
483 }
484
485
486 \f
487 ////////////////////////////////////////////////////////////////////////
488 // Implementation of FGPanelInstrument.
489 ////////////////////////////////////////////////////////////////////////
490
491
492 FGPanelInstrument::FGPanelInstrument ()
493 {
494   setPosition(0, 0);
495   setSize(0, 0);
496 }
497
498 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
499 {
500   setPosition(x, y);
501   setSize(w, h);
502 }
503
504 FGPanelInstrument::~FGPanelInstrument ()
505 {
506   for (action_list_type::iterator it = _actions.begin();
507        it != _actions.end();
508        it++) {
509     delete *it;
510     *it = 0;
511   }
512 }
513
514 void
515 FGPanelInstrument::setPosition (int x, int y)
516 {
517   _x = x;
518   _y = y;
519 }
520
521 void
522 FGPanelInstrument::setSize (int w, int h)
523 {
524   _w = w;
525   _h = h;
526 }
527
528 int
529 FGPanelInstrument::getXPos () const
530 {
531   return _x;
532 }
533
534 int
535 FGPanelInstrument::getYPos () const
536 {
537   return _y;
538 }
539
540 int
541 FGPanelInstrument::getWidth () const
542 {
543   return _w;
544 }
545
546 int
547 FGPanelInstrument::getHeight () const
548 {
549   return _h;
550 }
551
552 void
553 FGPanelInstrument::addAction (FGPanelAction * action)
554 {
555   _actions.push_back(action);
556 }
557
558                                 // Coordinates relative to centre.
559 bool
560 FGPanelInstrument::doMouseAction (int button, int x, int y)
561 {
562   action_list_type::iterator it = _actions.begin();
563   action_list_type::iterator last = _actions.end();
564   for ( ; it != last; it++) {
565     if ((*it)->inArea(button, x, y)) {
566       (*it)->doAction();
567       return true;
568     }
569   }
570   return false;
571 }
572
573
574 \f
575 ////////////////////////////////////////////////////////////////////////
576 // Implementation of FGLayeredInstrument.
577 ////////////////////////////////////////////////////////////////////////
578
579 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
580   : FGPanelInstrument(x, y, w, h)
581 {
582 }
583
584 FGLayeredInstrument::~FGLayeredInstrument ()
585 {
586   for (layer_list::iterator it = _layers.begin(); it != _layers.end(); it++) {
587     delete *it;
588     *it = 0;
589   }
590 }
591
592 void
593 FGLayeredInstrument::draw ()
594 {
595   for (int i = 0; i < (int)_layers.size(); i++) {
596     glPushMatrix();
597     glTranslatef(0.0, 0.0, (i / 100.0) + 0.1);
598     _layers[i]->draw();
599     glPopMatrix();
600   }
601 }
602
603 int
604 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
605 {
606   int n = _layers.size();
607   if (layer->getWidth() == -1) {
608     layer->setWidth(getWidth());
609   }
610   if (layer->getHeight() == -1) {
611     layer->setHeight(getHeight());
612   }
613   _layers.push_back(layer);
614   return n;
615 }
616
617 int
618 FGLayeredInstrument::addLayer (FGCroppedTexture &texture,
619                                int w, int h)
620 {
621   return addLayer(new FGTexturedLayer(texture, w, h));
622 }
623
624 void
625 FGLayeredInstrument::addTransformation (FGPanelTransformation * transformation)
626 {
627   int layer = _layers.size() - 1;
628   _layers[layer]->addTransformation(transformation);
629 }
630
631
632 \f
633 ////////////////////////////////////////////////////////////////////////
634 // Implementation of FGInstrumentLayer.
635 ////////////////////////////////////////////////////////////////////////
636
637 FGInstrumentLayer::FGInstrumentLayer (int w, int h)
638   : _w(w),
639     _h(h)
640 {
641 }
642
643 FGInstrumentLayer::~FGInstrumentLayer ()
644 {
645   for (transformation_list::iterator it = _transformations.begin();
646        it != _transformations.end();
647        it++) {
648     delete *it;
649     *it = 0;
650   }
651 }
652
653 void
654 FGInstrumentLayer::transform () const
655 {
656   transformation_list::const_iterator it = _transformations.begin();
657   transformation_list::const_iterator last = _transformations.end();
658   while (it != last) {
659     FGPanelTransformation *t = *it;
660     float val = (t->value == 0 ? 0.0 : t->value->getFloatValue());
661     if (val < t->min) {
662       val = t->min;
663     } else if (val > t->max) {
664       val = t->max;
665     }
666     val = val * t->factor + t->offset;
667
668     switch (t->type) {
669     case FGPanelTransformation::XSHIFT:
670       glTranslatef(val, 0.0, 0.0);
671       break;
672     case FGPanelTransformation::YSHIFT:
673       glTranslatef(0.0, val, 0.0);
674       break;
675     case FGPanelTransformation::ROTATION:
676       glRotatef(-val, 0.0, 0.0, 1.0);
677       break;
678     }
679     it++;
680   }
681 }
682
683 void
684 FGInstrumentLayer::addTransformation (FGPanelTransformation * transformation)
685 {
686   _transformations.push_back(transformation);
687 }
688
689
690 \f
691 ////////////////////////////////////////////////////////////////////////
692 // Implementation of FGTexturedLayer.
693 ////////////////////////////////////////////////////////////////////////
694
695
696 FGTexturedLayer::FGTexturedLayer (const FGCroppedTexture &texture, int w, int h)
697   : FGInstrumentLayer(w, h)
698 {
699   setTexture(texture);
700 }
701
702
703 FGTexturedLayer::~FGTexturedLayer ()
704 {
705 }
706
707
708 void
709 FGTexturedLayer::draw ()
710 {
711   int w2 = _w / 2;
712   int h2 = _h / 2;
713
714   transform();
715   glBindTexture(GL_TEXTURE_2D, _texture.getTexture()->getHandle());
716   glBegin(GL_POLYGON);
717
718                                 // From Curt: turn on the panel
719                                 // lights after sundown.
720   if ( cur_light_params.sun_angle * RAD_TO_DEG < 95.0 ) {
721       glColor4fv( cur_light_params.scene_diffuse );
722   } else {
723       glColor4f(0.7, 0.2, 0.2, 1.0);
724   }
725
726
727   glTexCoord2f(_texture.getMinX(), _texture.getMinY()); glVertex2f(-w2, -h2);
728   glTexCoord2f(_texture.getMaxX(), _texture.getMinY()); glVertex2f(w2, -h2);
729   glTexCoord2f(_texture.getMaxX(), _texture.getMaxY()); glVertex2f(w2, h2);
730   glTexCoord2f(_texture.getMinX(), _texture.getMaxY()); glVertex2f(-w2, h2);
731   glEnd();
732 }
733
734
735 \f
736 ////////////////////////////////////////////////////////////////////////
737 // Implementation of FGTextLayer.
738 ////////////////////////////////////////////////////////////////////////
739
740 FGTextLayer::FGTextLayer (int w, int h)
741   : FGInstrumentLayer(w, h), _pointSize(14.0)
742 {
743   _then.stamp();
744   _color[0] = _color[1] = _color[2] = 0.0;
745   _color[3] = 1.0;
746 }
747
748 FGTextLayer::~FGTextLayer ()
749 {
750   chunk_list::iterator it = _chunks.begin();
751   chunk_list::iterator last = _chunks.end();
752   for ( ; it != last; it++) {
753     delete *it;
754   }
755 }
756
757 void
758 FGTextLayer::draw ()
759 {
760   glPushMatrix();
761   glColor4fv(_color);
762   transform();
763   text_renderer.setFont(guiFntHandle);
764   text_renderer.setPointSize(_pointSize);
765   text_renderer.begin();
766   text_renderer.start3f(0, 0, 0);
767
768   _now.stamp();
769   if (_now - _then > 100000) {
770     recalc_value();
771     _then = _now;
772   }
773   text_renderer.puts((char *)(_value.c_str()));
774
775   text_renderer.end();
776   glColor4f(1.0, 1.0, 1.0, 1.0);        // FIXME
777   glPopMatrix();
778 }
779
780 void
781 FGTextLayer::addChunk (FGTextLayer::Chunk * chunk)
782 {
783   _chunks.push_back(chunk);
784 }
785
786 void
787 FGTextLayer::setColor (float r, float g, float b)
788 {
789   _color[0] = r;
790   _color[1] = g;
791   _color[2] = b;
792   _color[3] = 1.0;
793 }
794
795 void
796 FGTextLayer::setPointSize (float size)
797 {
798   _pointSize = size;
799 }
800
801 void
802 FGTextLayer::setFont(fntFont * font)
803 {
804   text_renderer.setFont(font);
805 }
806
807
808 void
809 FGTextLayer::recalc_value () const
810 {
811   _value = "";
812   chunk_list::const_iterator it = _chunks.begin();
813   chunk_list::const_iterator last = _chunks.end();
814   for ( ; it != last; it++) {
815     _value += (*it)->getValue();
816   }
817 }
818
819
820 \f
821 ////////////////////////////////////////////////////////////////////////
822 // Implementation of FGTextLayer::Chunk.
823 ////////////////////////////////////////////////////////////////////////
824
825 FGTextLayer::Chunk::Chunk (const string &text, const string &fmt)
826   : _type(FGTextLayer::TEXT), _fmt(fmt)
827 {
828   _text = text;
829   if (_fmt == "") 
830     _fmt = "%s";
831 }
832
833 FGTextLayer::Chunk::Chunk (ChunkType type, const SGValue * value,
834                            const string &fmt, float mult)
835   : _type(type), _fmt(fmt), _mult(mult)
836 {
837   if (_fmt == "") {
838     if (type == TEXT_VALUE)
839       _fmt = "%s";
840     else
841       _fmt = "%.2f";
842   }
843   _value = value;
844 }
845
846 const char *
847 FGTextLayer::Chunk::getValue () const
848 {
849   switch (_type) {
850   case TEXT:
851     sprintf(_buf, _fmt.c_str(), _text.c_str());
852     return _buf;
853   case TEXT_VALUE:
854     sprintf(_buf, _fmt.c_str(), _value->getStringValue().c_str());
855     break;
856   case DOUBLE_VALUE:
857     sprintf(_buf, _fmt.c_str(), _value->getFloatValue() * _mult);
858     break;
859   }
860   return _buf;
861 }
862
863
864 \f
865 ////////////////////////////////////////////////////////////////////////
866 // Implementation of FGSwitchLayer.
867 ////////////////////////////////////////////////////////////////////////
868
869 FGSwitchLayer::FGSwitchLayer (int w, int h, const SGValue * value,
870                               FGInstrumentLayer * layer1,
871                               FGInstrumentLayer * layer2)
872   : FGInstrumentLayer(w, h), _value(value), _layer1(layer1), _layer2(layer2)
873 {
874 }
875
876 FGSwitchLayer::~FGSwitchLayer ()
877 {
878   delete _layer1;
879   delete _layer2;
880 }
881
882 void
883 FGSwitchLayer::draw ()
884 {
885   transform();
886   if (_value->getBoolValue()) {
887     _layer1->draw();
888   } else {
889     _layer2->draw();
890   }
891 }
892
893 \f
894 // end of panel.cxx