]> git.mxchange.org Git - flightgear.git/blobdiff - src/GUI/WaypointList.cxx
Launcher: Maintain aircraft selection better
[flightgear.git] / src / GUI / WaypointList.cxx
index 235ef960f572416f7aa9e4de057c2bbb819be191..5b010f0d2690a7e6a9b14fce8dc0df9149b6510a 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <plib/puAux.h>
 
-#include <simgear/route/waypoint.hxx>
 #include <simgear/structure/callback.hxx>
 #include <simgear/sg_inlines.h>
 
@@ -19,6 +18,7 @@
 #include <Main/fg_props.hxx>
 
 #include <Navaids/positioned.hxx>
+#include <Navaids/routePath.hxx>
 #include <Autopilot/route_mgr.hxx>
 
 // select if the widget grabs keys necessary to fly aircraft from the keyboard,
@@ -37,34 +37,37 @@ enum {
 static const double BLINK_TIME = 0.3;
 static const int DRAG_START_DISTANCE_PX = 5;
   
-class RouteManagerWaypointModel : 
+class FlightPlanWaypointModel : 
   public WaypointList::Model, 
   public SGPropertyChangeListener
 {
 public:
-  RouteManagerWaypointModel()
-  {
-    _rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
-    
+  FlightPlanWaypointModel(flightgear::FlightPlan* fp) :
+    _fp(fp)
+  {    
     SGPropertyNode* routeEdited = fgGetNode("/autopilot/route-manager/signals/edited", true);
+    SGPropertyNode* flightplanChanged = fgGetNode("/autopilot/route-manager/signals/flightplan-changed", true);
     routeEdited->addChangeListener(this);
+    flightplanChanged->addChangeListener(this);
   }
   
-  virtual ~RouteManagerWaypointModel()
+  ~FlightPlanWaypointModel()
   {
     SGPropertyNode* routeEdited = fgGetNode("/autopilot/route-manager/signals/edited", true);
+    SGPropertyNode* flightplanChanged = fgGetNode("/autopilot/route-manager/signals/flightplan-changed", true);
     routeEdited->removeChangeListener(this);
+    flightplanChanged->removeChangeListener(this);
   }
   
 // implement WaypointList::Model
   virtual unsigned int numWaypoints() const
   {
-    return _rm->numWaypts();
+    return _fp->numLegs();
   }
   
   virtual int currentWaypoint() const
   {
-    return _rm->currentIndex();
+    return _fp->currentIndex();
   }
   
   virtual flightgear::Waypt* waypointAt(unsigned int index) const
@@ -73,12 +76,17 @@ public:
       return NULL;
     }
     
-    return _rm->wayptAtIndex(index);
+    return _fp->legAtIndex(index)->waypoint();
   }
 
+  virtual flightgear::FlightPlan* flightplan() const
+  {
+    return _fp;
+  }
+  
   virtual void deleteAt(unsigned int index)
   {
-    _rm->removeWayptAtIndex(index);
+    _fp->deleteIndex(index);
   }
   
   virtual void moveWaypointToIndex(unsigned int srcIndex, unsigned int destIndex)
@@ -88,14 +96,15 @@ public:
       --destIndex;
     }
     
-    unsigned int currentWpIndex = currentWaypoint();
-    WayptRef w(_rm->removeWayptAtIndex(srcIndex));
-    SG_LOG(SG_GENERAL, SG_INFO, "wpt:" << w->ident());
-    _rm->insertWayptAtIndex(w, destIndex);
+     int currentWpIndex = currentWaypoint();
+    
+    WayptRef w = _fp->legAtIndex(srcIndex)->waypoint();
+    _fp->deleteIndex(srcIndex);
+    _fp->insertWayptAtIndex(w, destIndex);
 
-    if (srcIndex == currentWpIndex) {
+    if ((signed int) srcIndex == currentWpIndex) {
         // current waypoint was moved
-        _rm->jumpToIndex(destIndex);
+        _fp->setCurrentIndex(destIndex);
     }
   }
   
@@ -107,12 +116,19 @@ public:
 // implement SGPropertyChangeListener
   void valueChanged(SGPropertyNode *prop)
   {
-    if (_cb) {
-      (*_cb)();
+    if (prop->getNameString() == "edited") {
+      if (_cb) {
+        (*_cb)();
+      }
+    }
+    
+    if (prop->getNameString() == "flightplan-changed") {
+      _fp = 
+        static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"))->flightPlan();
     }
   }
 private:
-  FGRouteMgr* _rm;
+  flightgear::FlightPlan* _fp;
   SGCallback* _cb;
 };
 
@@ -152,7 +168,9 @@ WaypointList::WaypointList(int x, int y, int width, int height) :
 {
   // pretend to be a list, so fgPopup doesn't mess with our mouse events
   type |= PUCLASS_LIST;  
-  setModel(new RouteManagerWaypointModel());
+  flightgear::FlightPlan* fp = 
+    static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"))->flightPlan();
+  setModel(new FlightPlanWaypointModel(fp));
   setSize(width, height);
   setValue(-1);
   
@@ -252,7 +270,7 @@ void WaypointList::handleDrag(int x, int y)
     
     _dragSourceRow = rowForY(y - abox.min[1]);
     Waypt* wp = _model->waypointAt(_dragSourceRow);
-    if (!wp || wp->flag(WPT_GENERATED)) {
+    if (!wp || wp->flag(WPT_GENERATED) || (wp->type() == "discontinuity")) {
       return; // don't allow generated points to be dragged
     }
     
@@ -360,8 +378,11 @@ void WaypointList::draw( int dx, int dy )
   y -= (_scrollPx % rowHeight); // partially draw the first row
   
   _arrowWidth = legendFont.getStringWidth(">");
+  
+  RoutePath path(_model->flightplan());
+  
   for ( ; row <= final; ++row, y += rowHeight) {
-    drawRow(dx, dy, row, y);
+    drawRow(dx, dy, row, y, path);
   } // of row drawing iteration
   
   glDisable(GL_SCISSOR_TEST);
@@ -380,14 +401,15 @@ void WaypointList::draw( int dx, int dy )
   }
 }
 
-void WaypointList::drawRow(int dx, int dy, int rowIndex, int y)
+void WaypointList::drawRow(int dx, int dy, int rowIndex, int y,
+                           const RoutePath& path)
 {
   flightgear::Waypt* wp(_model->waypointAt(rowIndex));
     
   bool isSelected = (rowIndex == getSelected());
   bool isCurrent = (rowIndex == _model->currentWaypoint());
   bool isDragSource = (_dragging && (rowIndex == _dragSourceRow));
-  
+
   puBox bkgBox = abox;
   bkgBox.min[1] = abox.max[1] - y;
   bkgBox.max[1] = bkgBox.min[1] + rowHeightPx();
@@ -399,12 +421,12 @@ void WaypointList::drawRow(int dx, int dy, int rowIndex, int y)
   if (wp->flag(WPT_MISS)) {
     drawBox = true;
     puSetColor(col, 1.0, 0.0, 0.0, 0.3);  // red
-  } else if (wp->flag(WPT_ARRIVAL)) {
+  } else if (wp->flag(WPT_ARRIVAL) || wp->flag(WPT_DEPARTURE)) {
     drawBox = true;
     puSetColor(col, 0.0, 0.0, 0.0, 0.3);
-  } else if (wp->flag(WPT_DEPARTURE)) {
+  } else if (wp->flag(WPT_APPROACH)) {
     drawBox = true;
-    puSetColor(col, 0.0, 0.0, 0.0, 0.3);
+    puSetColor(col, 0.0, 0.0, 0.1, 0.3);
   }
   
   if (isDragSource) {
@@ -431,64 +453,94 @@ void WaypointList::drawRow(int dx, int dy, int rowIndex, int y)
   
   int x = xx;
   x += _arrowWidth + PUSTR_LGAP;
-  
-  // row textual data
+    drawRowText(x, yy, rowIndex, path);
 
-  char buffer[128];
-  int count = ::snprintf(buffer, 128, "%03d   %-5s", rowIndex, wp->ident().c_str());
-  FGPositioned* src = wp->source(); 
-  if (src && !src->name().empty() && (src->name() != wp->ident())) { 
-    // append name if present, and different to id
-    ::snprintf(buffer + count, 128 - count, " (%s)", src->name().c_str());
-  }
 
-  drawClippedString(legendFont, buffer, x, yy, 300);
-  x += 300 + PUSTR_LGAP;
-  
-  if (_showLatLon) {
-    SGGeod p(wp->position());
-    char ns = (p.getLatitudeDeg() > 0.0) ? 'N' : 'S';
-    char ew = (p.getLongitudeDeg() > 0.0) ? 'E' : 'W';
-    
-    ::snprintf(buffer, 128 - count, "%4.2f%c %4.2f%c",
-      fabs(p.getLongitudeDeg()), ew, fabs(p.getLatitudeDeg()), ns);
-  } else if (rowIndex > 0) {
-    double courseDeg;
-    double distanceM;
-    Waypt* prev = _model->waypointAt(rowIndex - 1);
-    boost::tie(courseDeg, distanceM) = wp->courseAndDistanceFrom(prev->position());
-  
-    ::snprintf(buffer, 128 - count, "%03.0f %5.1fnm",
-      courseDeg, distanceM * SG_METER_TO_NM);
+  if (isDragSource) {
+    puSetColor(col, 1.0, 0.5, 0.0, 0.5);
+    bkgBox.draw(dx, dy, PUSTYLE_PLAIN, &col, false, 0);
   }
+}
+
+void WaypointList::drawRowText(int x, int baseline, int rowIndex, const RoutePath& path)
+{
+    flightgear::Waypt* wp(_model->waypointAt(rowIndex));
+    const bool isDiscontinuity = (wp->type() == "discontinuity");
+    const bool isVia = (wp->type() == "via");
+
+    char buffer[128];
+    int count;
+
+    if (isVia) {
+        // VIA has long ident but no name
+        count = ::snprintf(buffer, 128, "%03d   %s", rowIndex, wp->ident().c_str());
+        drawClippedString(legendFont, buffer, x, baseline, 300);
+        x += 300 + PUSTR_LGAP;
+    } else {
+        count = ::snprintf(buffer, 128, "%03d   %-5s", rowIndex, wp->ident().c_str());
+
+        FGPositioned* src = wp->source();
+        if (src && !src->name().empty() && (src->name() != wp->ident())) {
+          // append name if present, and different to id
+          ::snprintf(buffer + count, 128 - count, " (%s)", src->name().c_str());
+        }
 
-  f->drawString(buffer, x, yy);
+        drawClippedString(legendFont, buffer, x, baseline, 300);
+        x += 300 + PUSTR_LGAP;
+
+        if (isDiscontinuity) {
+            return;
+        }
+
+        if (_showLatLon) {
+          // only show for non-dynamic waypoints
+          if (!wp->flag(WPT_DYNAMIC)) {
+            SGGeod p(wp->position());
+            char ns = (p.getLatitudeDeg() > 0.0) ? 'N' : 'S';
+            char ew = (p.getLongitudeDeg() > 0.0) ? 'E' : 'W';
+
+            ::snprintf(buffer, 128 - count, "%4.2f%c %4.2f%c",
+              fabs(p.getLongitudeDeg()), ew, fabs(p.getLatitudeDeg()), ns);
+          } else {
+            buffer[0] = 0;
+          }
+        } else if (rowIndex > 0) {
+          double courseDeg = path.trackForIndex(rowIndex);
+          double distanceM = path.distanceForIndex(rowIndex);
+          ::snprintf(buffer, 128 - count, "%03.0f %5.1fnm",
+            courseDeg, distanceM * SG_METER_TO_NM);
+        }
+    } // of is not a VIA waypoint
+
+    puFont* f = &legendFont;
+  f->drawString(buffer, x, baseline);
   x += 100 + PUSTR_LGAP;
-  
+
   if (wp->altitudeRestriction() != RESTRICT_NONE) {
+    char aboveAtBelow = ' ';
+    if (wp->altitudeRestriction() == RESTRICT_ABOVE) {
+      aboveAtBelow = 'A';
+    } else if (wp->altitudeRestriction() == RESTRICT_BELOW) {
+      aboveAtBelow = 'B';
+    }
+
     int altHundredFt = (wp->altitudeFt() + 50) / 100; // round to nearest 100ft
     if (altHundredFt < 100) {
-      count = ::snprintf(buffer, 128, "%d'", altHundredFt * 100);
+      count = ::snprintf(buffer, 128, "%d'%c", altHundredFt * 100, aboveAtBelow);
     } else { // display as a flight-level
-      count = ::snprintf(buffer, 128, "FL%d", altHundredFt);
+      count = ::snprintf(buffer, 128, "FL%d%c", altHundredFt, aboveAtBelow);
     }
-    
-    f->drawString(buffer, x, yy);
+
+    f->drawString(buffer, x, baseline);
   } // of valid wp altitude
   x += 60 + PUSTR_LGAP;
-  
+
   if (wp->speedRestriction() == SPEED_RESTRICT_MACH) {
     count = ::snprintf(buffer, 126, "%03.2fM", wp->speedMach());
-    f->drawString(buffer, x, yy);
+    f->drawString(buffer, x, baseline);
   } else if (wp->speedRestriction() != RESTRICT_NONE) {
     count = ::snprintf(buffer, 126, "%dKts", (int) wp->speedKts());
-    f->drawString(buffer, x, yy);
-  }
-  
-  if (isDragSource) {
-    puSetColor(col, 1.0, 0.5, 0.0, 0.5);
-    bkgBox.draw(dx, dy, PUSTYLE_PLAIN, &col, false, 0);
+    f->drawString(buffer, x, baseline);
   }
 }