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