1 //  panel.hxx - generic support classes for a 2D 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //
19 //  $Id$
20 
21 #ifndef __PANEL_HXX
22 #define __PANEL_HXX
23 
24 #include <osg/ref_ptr>
25 #include <osg/StateSet>
26 #include <osg/Texture2D>
27 
28 #include <simgear/compiler.h>
29 #include <simgear/props/props.hxx>
30 #include <simgear/props/propertyObject.hxx>
31 
32 #include <simgear/structure/SGBinding.hxx>
33 #include <simgear/math/interpolater.hxx>
34 #include <simgear/timing/timestamp.hxx>
35 
36 #include <cmath>
37 #include <vector>
38 #include <map>
39 
40 #include <Main/fg_props.hxx>
41 
42 class FGPanelInstrument;
43 class fntFont;
44 class DCLGPS;
45 class IntRect;
46 
47 ////////////////////////////////////////////////////////////////////////
48 // Texture management.
49 ////////////////////////////////////////////////////////////////////////
50 
51 
52 /**
53  * Texture manager (should migrate out into FGFS).
54  *
55  * This class ensures that no texture is loaded more than once.
56  */
57 class FGTextureManager
58 {
59 public:
60   static osg::Texture2D* createTexture(const std::string &relativePath,
61                                        bool staticTexture = true);
62   static void addTexture(const std::string &relativePath, osg::Texture2D* texture);
63 private:
64   static std::map<std::string,osg::ref_ptr<osg::Texture2D> > _textureMap;
65 };
66 
67 
68 /**
69  * Cropped texture (should migrate out into FGFS).
70  *
71  * This structure wraps an SSG texture with cropping information.
72  */
73 class FGCroppedTexture
74 {
75 public:
76 
77   FGCroppedTexture ();
78   FGCroppedTexture (const std::string &path,
79 		  float _minX = 0.0, float _minY = 0.0,
80 		  float _maxX = 1.0, float _maxY = 1.0);
81   virtual ~FGCroppedTexture ();
82 
setPath(const std::string & path)83   virtual void setPath (const std::string &path) { _path = path; }
84 
getPath() const85   virtual const std::string &getPath () const { return _path; }
86 
87   virtual osg::StateSet* getTexture ();
88 
setCrop(float minX,float minY,float maxX,float maxY)89   virtual void setCrop (float minX, float minY, float maxX, float maxY) {
90     _minX = minX; _minY = minY; _maxX = maxX; _maxY = maxY;
91   }
92 
getMinX() const93   virtual float getMinX () const { return _minX; }
getMinY() const94   virtual float getMinY () const { return _minY; }
getMaxX() const95   virtual float getMaxX () const { return _maxX; }
getMaxY() const96   virtual float getMaxY () const { return _maxY; }
97 
98 
99 private:
100   std::string _path;
101   osg::ref_ptr<osg::StateSet> _texture;
102   float _minX, _minY, _maxX, _maxY;
103 };
104 
105 
106 
107 ////////////////////////////////////////////////////////////////////////
108 // Top-level panel.
109 ////////////////////////////////////////////////////////////////////////
110 
111 
112 /**
113  * Instrument panel class.
114  *
115  * The panel is a container that has a background texture and holds
116  * zero or more instruments.  The panel will order the instruments to
117  * redraw themselves when necessary, and will pass mouse clicks on to
118  * the appropriate instruments for processing.
119  */
120 class FGPanel : public SGReferenced
121 {
122 public:
123 
124   FGPanel ();
125   virtual ~FGPanel ();
126 
127   virtual void draw (osg::State& state);
128 
129   virtual void updateMouseDelay(double dt);
130 
131 				// transfer pointer ownership!!!
132   virtual void addInstrument (FGPanelInstrument * instrument);
133 
134 				// Background texture.
135   virtual void setBackground (osg::Texture2D* texture);
136 
137 				// Background multiple textures.
138   virtual void setMultiBackground (osg::Texture2D* texture, int idx);
139 
setWidth(int width)140   virtual void setWidth (int width) { _width = width; }
getWidth() const141   virtual int getWidth () const { return _width; }
142 
143 				// Full height of panel.
setHeight(int height)144   virtual void setHeight (int height) { _height = height; }
getHeight() const145   virtual int getHeight () const { return _height; }
146 
147 				// X-offset
148   virtual void setXOffset (int offset);
getXOffset() const149   virtual int getXOffset () const { return _x_offset->getIntValue(); }
150 
151 				// Y-offset.
152   virtual void setYOffset (int offset);
getYOffset() const153   virtual int getYOffset () const { return _y_offset->getIntValue(); }
154 
155 				// View height.
156  // virtual void setViewHeight (int height) { _view_height = height; }
157  // virtual int getViewHeight () const { return _view_height; }
158 
159   /**
160    * find the actual logical extend of the panel, including all instruments
161    * and actions.
162    */
163   void getLogicalExtent(int &x0, int& y0, int& x1, int &y1);
164 
165 				// Handle a mouse click.
166   virtual bool doMouseAction (int button, int updown, int x, int y);
167   virtual bool doLocalMouseAction(int button, int updown, int x, int y);
168 
169   virtual void setDepthTest (bool enable);
170 
getAutohide(void) const171   bool getAutohide(void) const { return _autohide; };
setAutohide(bool enable)172   void setAutohide(bool enable) { _autohide = enable; };
173 
174   double getAspectScale() const;
175 
176 private:
177   void setupVirtualCockpit();
178   void cleanupVirtualCockpit();
179 
180   mutable bool _mouseDown;
181   mutable int _mouseButton, _mouseX, _mouseY;
182   double _mouseActionRepeat;
183 
184   mutable FGPanelInstrument * _mouseInstrument;
185   typedef std::vector<FGPanelInstrument *> instrument_list_type;
186   int _width;
187   int _height;
188  // int _view_height;
189 
190   SGPropertyNode_ptr _x_offset;
191   SGPropertyNode_ptr _y_offset;
192   SGPropertyNode_ptr _jitter;
193   SGPropertyNode_ptr _flipx;
194 
195   SGConstPropertyNode_ptr _xsize_node;
196   SGConstPropertyNode_ptr _ysize_node;
197 
198   osg::ref_ptr<osg::StateSet> _bg;
199   osg::ref_ptr<osg::StateSet> _mbg[8];
200 				// List of instruments in panel.
201   instrument_list_type _instruments;
202   bool _enable_depth_test;
203   bool _autohide;
204 
205   SGPropObjBool _drawPanelHotspots;
206 };
207 
208 
209 
210 ////////////////////////////////////////////////////////////////////////
211 // Actions
212 ////////////////////////////////////////////////////////////////////////
213 
214 
215 /**
216  * Class for user actions.
217  *
218  * The actions are command bindings, like bindings for the keyboard
219  * or joystick, but they are tied to specific mouse actions in
220  * rectangular areas of the panel.
221  */
222 class FGPanelAction : public SGConditional
223 {
224 public:
225   FGPanelAction ();
226   FGPanelAction (int button, int x, int y, int w, int h, bool repeatable);
227   virtual ~FGPanelAction ();
228 
229 				// Getters.
getButton() const230   virtual int getButton () const { return _button; }
getX() const231   virtual int getX () const { return _x; }
getY() const232   virtual int getY () const { return _y; }
getWidth() const233   virtual int getWidth () const { return _w; }
getHeight() const234   virtual int getHeight () const { return _h; }
235 
236 				// Setters.
237 
238 				// transfer pointer ownership
239   virtual void addBinding (SGBinding * binding, int updown);
setButton(int button)240   virtual void setButton (int button) { _button = button; }
setX(int x)241   virtual void setX (int x) { _x = x; }
setY(int y)242   virtual void setY (int y) { _y = y; }
setWidth(int w)243   virtual void setWidth (int w) { _w = w; }
setHeight(int h)244   virtual void setHeight (int h) { _h = h; }
245 
246 				// Check whether we're in the area.
inArea(int button,int x,int y)247   virtual bool inArea (int button, int x, int y)
248   {
249     return (button == _button &&
250 	    x >= _x &&
251 	    x < _x + _w &&
252 	    y >= _y &&
253 	    y < _y + _h);
254   }
255 
256 				// Perform the action.
257   virtual bool doAction (int updown);
258 
259 private:
260   typedef std::vector<SGBinding *> binding_list_t;
261 
262   int _button;
263   int _x;
264   int _y;
265   int _w;
266   int _h;
267   bool _repeatable;
268   int _last_state;
269   binding_list_t _bindings[2];
270 };
271 
272 
273 
274 ////////////////////////////////////////////////////////////////////////
275 // Transformations.
276 ////////////////////////////////////////////////////////////////////////
277 
278 
279 /**
280  * A transformation for a layer.
281  */
282 class FGPanelTransformation : public SGConditional
283 {
284 public:
285 
286   enum Type {
287     XSHIFT,
288     YSHIFT,
289     ROTATION
290   };
291 
292   FGPanelTransformation ();
293   virtual ~FGPanelTransformation ();
294 
295   Type type;
296   SGConstPropertyNode_ptr node;
297   float min;
298   float max;
299   bool has_mod;
300   float mod;
301   float factor;
302   float offset;
303   SGInterpTable * table;
304 };
305 
306 
307 
308 
309 ////////////////////////////////////////////////////////////////////////
310 // Layers
311 ////////////////////////////////////////////////////////////////////////
312 
313 
314 /**
315  * A single layer of a multi-layered instrument.
316  *
317  * Each layer can be subject to a series of transformations based
318  * on current FGFS instrument readings: for example, a texture
319  * representing a needle can rotate to show the airspeed.
320  */
321 class FGInstrumentLayer : public SGConditional
322 {
323 public:
324 
325   FGInstrumentLayer (int w = -1, int h = -1);
326   virtual ~FGInstrumentLayer ();
327 
328   virtual void draw (osg::State& state) = 0;
329   virtual void transform () const;
330 
getWidth() const331   virtual int getWidth () const { return _w; }
getHeight() const332   virtual int getHeight () const { return _h; }
setWidth(int w)333   virtual void setWidth (int w) { _w = w; }
setHeight(int h)334   virtual void setHeight (int h) { _h = h; }
335 
336 				// Transfer pointer ownership!!
337 				// DEPRECATED
338   virtual void addTransformation (FGPanelTransformation * transformation);
339 
340 protected:
341   int _w, _h;
342 
343   typedef std::vector<FGPanelTransformation *> transformation_list;
344   transformation_list _transformations;
345 };
346 
347 
348 
349 ////////////////////////////////////////////////////////////////////////
350 // Instruments.
351 ////////////////////////////////////////////////////////////////////////
352 
353 
354 /**
355  * Abstract base class for a panel instrument.
356  *
357  * A panel instrument consists of zero or more actions, associated
358  * with mouse clicks in rectangular areas.  Currently, the only
359  * concrete class derived from this is FGLayeredInstrument, but others
360  * may show up in the future (some complex instruments could be
361  * entirely hand-coded, for example).
362  */
363 class FGPanelInstrument : public SGConditional
364 {
365 public:
366   FGPanelInstrument ();
367   FGPanelInstrument (int x, int y, int w, int h);
368   virtual ~FGPanelInstrument ();
369 
370   virtual void draw (osg::State& state) = 0;
371   virtual void drawHotspots(osg::State& state);
372 
373   virtual void setPosition(int x, int y);
374   virtual void setSize(int w, int h);
375 
376   virtual int getXPos () const;
377   virtual int getYPos () const;
378   virtual int getWidth () const;
379   virtual int getHeight () const;
380 
381 				// Coordinates relative to centre.
382 				// Transfer pointer ownership!!
383   virtual void addAction (FGPanelAction * action);
384 
385 				// Coordinates relative to centre.
386   virtual bool doMouseAction (int button, int updown, int x, int y);
387 
388   void extendRect(IntRect& r) const;
389 protected:
390   int _x, _y, _w, _h;
391   typedef std::vector<FGPanelAction *> action_list_type;
392   action_list_type _actions;
393 };
394 
395 
396 /**
397  * An instrument constructed of multiple layers.
398  *
399  * Each individual layer can be rotated or shifted to correspond
400  * to internal FGFS instrument readings.
401  */
402 class FGLayeredInstrument : public FGPanelInstrument
403 {
404 public:
405   FGLayeredInstrument (int x, int y, int w, int h);
406   virtual ~FGLayeredInstrument ();
407 
408   virtual void draw (osg::State& state);
409 
410 				// Transfer pointer ownership!!
411   virtual int addLayer (FGInstrumentLayer *layer);
412   virtual int addLayer (const FGCroppedTexture &texture, int w = -1, int h = -1);
413 
414 				// Transfer pointer ownership!!
415   virtual void addTransformation (FGPanelTransformation * transformation);
416 
417 protected:
418   typedef std::vector<FGInstrumentLayer *> layer_list;
419   layer_list _layers;
420 };
421 
422 
423 /**
424  * An empty-shell instrument that exists soley in
425  * order to redirect commands from the panel to a
426  * complex instrument inherited from SGSubsystem.
427  *
428  * Currently the only complex instrument is the KLN89,
429  * which we've hardwired this to for now.
430  */
431 class FGSpecialInstrument : public FGPanelInstrument
432 {
433 public:
434   FGSpecialInstrument(DCLGPS* sb);
435   //FGSpecialInstrument (int x, int y, int w, int h);
436   virtual ~FGSpecialInstrument ();
437 
438   virtual void draw (osg::State& state);
439 
440 protected:
441   DCLGPS* complex;
442 };
443 
444 
445 /**
446  * An instrument layer containing a group of sublayers.
447  *
448  * This class is useful for gathering together a group of related
449  * layers, either to hold in an external file or to work under
450  * the same condition.
451  */
452 class FGGroupLayer : public FGInstrumentLayer
453 {
454 public:
455   FGGroupLayer ();
456   virtual ~FGGroupLayer ();
457   virtual void draw (osg::State& state);
458 				// transfer pointer ownership
459   virtual void addLayer (FGInstrumentLayer * layer);
460 protected:
461   std::vector<FGInstrumentLayer *> _layers;
462 };
463 
464 
465 /**
466  * A textured layer of an instrument.
467  *
468  * This is a layer holding a single texture.  Normally, the texture's
469  * backgound should be transparent so that lower layers and the panel
470  * background can show through.
471  */
472 class FGTexturedLayer : public FGInstrumentLayer
473 {
474 public:
FGTexturedLayer(int w=-1,int h=-1)475   FGTexturedLayer (int w = -1, int h = -1) : FGInstrumentLayer(w, h) {}
476   FGTexturedLayer (const FGCroppedTexture &texture, int w = -1, int h = -1);
477   virtual ~FGTexturedLayer ();
478 
479   virtual void draw (osg::State& state);
480 
setTexture(const FGCroppedTexture & texture)481   virtual void setTexture (const FGCroppedTexture &texture) {
482     _texture = texture;
483   }
getTexture() const484   virtual const FGCroppedTexture &getTexture () const { return _texture; }
getTexture()485   virtual FGCroppedTexture *getTexture() { return &_texture; }
486 
setEmissive(bool e)487   void setEmissive(bool e) { _emissive = e; }
488 
489 private:
490   FGCroppedTexture _texture;
491   bool _emissive;
492 };
493 
494 
495 /**
496  * A text layer of an instrument.
497  *
498  * This is a layer holding a string of static and/or generated text.
499  * It is useful for instruments that have text displays, such as
500  * a chronometer, GPS, or NavCom radio.
501  */
502 class FGTextLayer : public FGInstrumentLayer
503 {
504 public:
505   enum ChunkType {
506     TEXT,
507     TEXT_VALUE,
508     DOUBLE_VALUE
509   };
510 
511   class Chunk : public SGConditional
512   {
513   public:
514     Chunk (const std::string &text, const std::string &fmt = "%s");
515     Chunk (ChunkType type, const SGPropertyNode * node,
516 	   const std::string &fmt = "", float mult = 1.0, float offs = 0.0,
517            bool truncation = false);
518 
519     const char * getValue () const;
520   private:
521     ChunkType _type;
522     std::string _text;
523     SGConstPropertyNode_ptr _node;
524     std::string _fmt;
525     float _mult;
526     float _offs;
527     bool _trunc;
528     mutable char _buf[1024];
529   };
530 
531   FGTextLayer (int w = -1, int h = -1);
532   virtual ~FGTextLayer ();
533 
534   virtual void draw (osg::State& state);
535 
536 				// Transfer pointer!!
537   virtual void addChunk (Chunk * chunk);
538   virtual void setColor (float r, float g, float b);
539   virtual void setPointSize (float size);
540   virtual void setFontName ( const std::string &name );
541   virtual void setFont (fntFont * font);
542 
543 private:
544 
545   void recalc_value () const;
546 
547   typedef std::vector<Chunk *> chunk_list;
548   chunk_list _chunks;
549   float _color[4];
550 
551   float _pointSize;
552   mutable std::string _font_name;
553   mutable std::string _value;
554   mutable SGTimeStamp _then;
555   mutable SGTimeStamp _now;
556 };
557 
558 
559 /**
560  * A group layer that switches among its children.
561  *
562  * The first layer that passes its condition will be drawn, and
563  * any following layers will be ignored.
564  */
565 class FGSwitchLayer : public FGGroupLayer
566 {
567 public:
568 				// Transfer pointers!!
569   FGSwitchLayer ();
570   virtual void draw (osg::State& state);
571 
572 };
573 #endif // __PANEL_HXX
574 
575 // end of panel.hxx
576 
577 
578 
579