celestia/src/celestia/kde/selectionpopup.cpp

527 lines
18 KiB
C++

/***************************************************************************
selectionpopup.cpp - description
-------------------
begin : 2003-05-06
copyright : (C) 2002 by Christophe Teyssier
email : chris@teyssier.org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <libintl.h>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <libintl.h>
#include "selectionpopup.h"
#include <qlabel.h>
#include <klocale.h>
#include <kurl.h>
#include <krun.h>
#include "celutil/utf8.h"
#include "celestia/celestiacore.h"
#include "celengine/axisarrow.h"
#include "celengine/planetgrid.h"
SelectionPopup::SelectionPopup(QWidget* parent, CelestiaCore* _appCore, Selection _sel):
KPopupMenu(parent),
appCore(_appCore),
sel(_sel),
baseId(0)
{
}
SelectionPopup::~SelectionPopup() {
}
void SelectionPopup::init()
{
QPalette pal( palette() );
pal.setColor( QPalette::Normal, QColorGroup::Background, QColor( "White" ) );
pal.setColor( QPalette::Normal, QColorGroup::Foreground, QColor( "Black" ) );
pal.setColor( QPalette::Inactive, QColorGroup::Foreground, QColor( "Black" ) );
QFont rsFont = font();
rsFont.setPointSize( rsFont.pointSize() - 2 );
Simulation *sim = appCore->getSimulation();
Vec3d v = sel.getPosition(sim->getTime()) - sim->getObserver().getPosition();
if (sel.body() != NULL)
{
insertTitle(QString::fromUtf8(sel.body()->getName(true).c_str()), 0, 0);
insert(this, sel);
}
else if (sel.star() != NULL)
{
std::string name = sim->getUniverse()->getStarCatalog()->getStarName(*sel.star());
double distance = v.length() * 1e-6;
char buff[50];
ostringstream o;
setlocale(LC_NUMERIC, "");
if (abs(distance) >= astro::AUtoLightYears(1000.0f))
sprintf(buff, "%'.3f %s", distance, _("ly"));
else if (abs(distance) >= astro::kilometersToLightYears(10000000.0))
sprintf(buff, "%'.3f %s", astro::lightYearsToAU(distance), _("au"));
else if (abs(distance) > astro::kilometersToLightYears(1.0f))
sprintf(buff, "%'.3f km", astro::lightYearsToKilometers(distance));
else
sprintf(buff, "%'.3f m", astro::lightYearsToKilometers(distance) * 1000.0f);
o << i18n("Distance: ") << QString::fromUtf8(buff) << "\n";
o << i18n("Abs (app) mag: ");
sprintf(buff, "%'.2f (%.2f)",
sel.star()->getAbsoluteMagnitude(),
astro::absToAppMag(sel.star()->getAbsoluteMagnitude(),
(float) distance));
o << QString::fromUtf8(buff) << "\n";
o << i18n("Class: ");
sprintf(buff, "%s", sel.star()->getSpectralType());
o << QString::fromUtf8(buff) << "\n";
o << i18n("Surface Temp: ");
sprintf(buff, "%'.0f K", sel.star()->getTemperature());
o << QString::fromUtf8(buff) << "\n";
o << i18n("Radius: ");
sprintf(buff, "%'.2f %s", sel.star()->getRadius() / 696000.0f, _("Rsun"));
o << QString::fromUtf8(buff);
setlocale(LC_NUMERIC, "C");
QLabel *starDetails = new QLabel(QString(o.str().c_str()), this);
starDetails->setPalette(pal);
starDetails->setFont(rsFont);
insertTitle(QString::fromUtf8(ReplaceGreekLetterAbbr(name).c_str()), 0, 0);
insertItem(starDetails);
insertSeparator();
insert(this, sel);
}
else if (sel.deepsky() != NULL)
{
insertTitle(QString::fromUtf8(sim->getUniverse()->getDSOCatalog()->getDSOName(sel.deepsky()).c_str()), 0);
insert(this, sel);
}
if (sim->getUniverse() != NULL)
{
MarkerList* markers = sim->getUniverse()->getMarkers();
if (markers->size() > 0)
{
KPopupMenu *markMenu = new KPopupMenu(this);
int j=1;
for (std::vector<Marker>::iterator i = markers->begin(); i < markers->end(); i++)
{
KPopupMenu *objMenu = new KPopupMenu(this);
insert(objMenu, (*i).object(), false);
markMenu->insertItem(QString::fromUtf8(getSelectionName((*i).object())), objMenu);
j++;
}
insertItem(i18n("Marked objects"), markMenu);
}
}
}
void SelectionPopup::process(int id)
{
if (id < 0) return;
Simulation *sim = appCore->getSimulation();
sel = getSelectionFromId(id);
int actionId = id - baseId;
if (actionId == 1) {
sim->setSelection(sel);
return;
}
if (actionId == 2) {
sim->setSelection(sel);
appCore->charEntered('c');
return;
}
if (actionId == 3) {
sim->setSelection(sel);
appCore->charEntered('g');
return;
}
if (actionId == 4) {
sim->setSelection(sel);
appCore->charEntered('f');
return;
}
if (actionId == 5) {
sim->setSelection(sel);
appCore->charEntered('y');
return;
}
if (actionId == 6) {
QString url;
if (sel.body() != NULL)
{
url = QString(sel.body()->getInfoURL().c_str());
if (url == "")
{
QString name = QString(sel.body()->getName().c_str()).lower();
url = QString("http://www.nineplanets.org/") + name + ".html";
}
}
else if (sel.star() != NULL)
{
if (sel.star()->getCatalogNumber() != 0)
url = QString("http://simbad.u-strasbg.fr/sim-id.pl?protocol=html&Ident=HIP %1")
.arg(sel.star()->getCatalogNumber() & ~0xf0000000);
else
url = QString("http://www.nineplanets.org/sun.html");
}
else if (sel.deepsky() != NULL)
{
url = QString(sel.deepsky()->getInfoURL().c_str());
if (url == "")
url = QString("http://simbad.u-strasbg.fr/sim-id.pl?protocol=html&Ident=%1")
.arg(sim->getUniverse()->getDSOCatalog()->getDSOName(sel.deepsky()).c_str());
}
KRun::runURL(url, "text/html");
return;
}
if (actionId == 7)
{
if (sim->getUniverse() != NULL)
sim->getUniverse()->unmarkObject(sel, 1);
return;
}
if (actionId == 8)
{
sim->getUniverse()->unmarkAll();
return;
}
if (actionId >= 10 && actionId < 25)
{
if (sim->getUniverse() != NULL)
{
MarkerRepresentation markerRep((MarkerRepresentation::Symbol) (actionId - 1), 10.0f, Color(0.0f, 1.0f, 0.0f, 0.9f));
sim->getUniverse()->markObject(sel, markerRep, 1);
}
return;
}
if (actionId >=25 && actionId < 31 && sel.body() != NULL)
{
switch(actionId)
{
case 25:
appCore->toggleReferenceMark("body axes");
break;
case 26:
appCore->toggleReferenceMark("frame axes");
break;
case 27:
appCore->toggleReferenceMark("sun direction");
break;
case 28:
appCore->toggleReferenceMark("velocity vector");
break;
case 29:
appCore->toggleReferenceMark("planetographic grid");
break;
case 30:
appCore->toggleReferenceMark("terminator");
break;
}
}
if (actionId == 31) {
sim->getActiveObserver()->setDisplayedSurface("");
return;
}
if (actionId > 31) {
std::vector<std::string>* altSurfaces = sel.body()->getAlternateSurfaceNames();
if (altSurfaces != NULL && (int) altSurfaces->size() > actionId - 32)
{
sim->getActiveObserver()->setDisplayedSurface((*altSurfaces)[actionId - 32]);
}
}
}
const char* SelectionPopup::getSelectionName(const Selection& sel) const
{
if (sel.body() != NULL)
return sel.body()->getName(true).c_str();
else if (sel.star() != NULL)
return ReplaceGreekLetterAbbr(appCore->getSimulation()->getUniverse()->getStarCatalog()->getStarName(*(sel.star()))).c_str();
else if (sel.deepsky() != NULL)
return appCore->getSimulation()->getUniverse()->getDSOCatalog()->getDSOName(sel.deepsky()).c_str();
return "";
}
Selection SelectionPopup::getSelectionFromId(int id)
{
for(std::vector< std::pair<int, Selection> >::const_iterator i = baseIds.begin() + 1;
i != baseIds.end();
++i) {
if ((*i).first > id) {
baseId = (*(i-1)).first;
return (*(i-1)).second;
}
}
baseId = baseIds.back().first;
return baseIds.back().second;
}
void SelectionPopup::insert(KPopupMenu *popup, Selection sel, bool showSubObjects)
{
baseIds.push_back(make_pair(baseId, sel));
int locBaseId = baseId;
popup->insertItem(i18n("&Select"), baseId + 1);
popup->insertItem(i18n("&Center"), baseId + 2);
popup->insertItem(i18n("&Goto"), baseId + 3);
popup->insertItem(i18n("&Follow"), baseId + 4);
if (sel.star() == NULL && sel.deepsky() == NULL)
popup->insertItem(i18n("S&ynch Orbit"), baseId + 5);
popup->insertItem(i18n("&Info"), baseId + 6);
if (baseId == 0)
popup->insertItem(i18n("Unmark &All"), baseId + 8);
if (appCore->getSimulation()->getUniverse()->isMarked(sel, 1))
{
popup->insertItem(i18n("&Unmark"), baseId + 7);
}
else
{
KPopupMenu *markMenu = new KPopupMenu(this);
markMenu->insertItem(i18n("Diamond"), baseId + 10);
markMenu->insertItem(i18n("Triangle"), baseId + 11);
markMenu->insertItem(i18n("Square"), baseId + 12);
markMenu->insertItem(i18n("Filled Square"), baseId + 13);
markMenu->insertItem(i18n("Plus"), baseId + 14);
markMenu->insertItem(i18n("X"), baseId + 15);
markMenu->insertItem(i18n("Left Arrow"), baseId + 16);
markMenu->insertItem(i18n("Right Arrow"), baseId + 17);
markMenu->insertItem(i18n("Up Arrow"), baseId + 18);
markMenu->insertItem(i18n("Down Arrow"), baseId + 19);
markMenu->insertItem(i18n("Circle"), baseId + 20);
markMenu->insertItem(i18n("Disk"), baseId + 21);
popup->insertItem(i18n("&Mark"), markMenu);
}
if (sel.body() != NULL) {
KPopupMenu *refVectorMenu = new KPopupMenu(this);
refVectorMenu->setCheckable(true);
popup->insertItem(i18n("&Reference Marks"), refVectorMenu);
refVectorMenu->insertItem(i18n("Show Body Axes"), baseId + 25);
refVectorMenu->setItemChecked(baseId + 25, sel.body()->findReferenceMark("body axes"));
refVectorMenu->insertItem(i18n("Show Frame Axes"), baseId + 26);
refVectorMenu->setItemChecked(baseId + 26, sel.body()->findReferenceMark("frame axes"));
refVectorMenu->insertItem(i18n("Show Sun Direction"), baseId + 27);
refVectorMenu->setItemChecked(baseId + 27, sel.body()->findReferenceMark("sun direction"));
refVectorMenu->insertItem(i18n("Show Velocity Vector"), baseId + 28);
refVectorMenu->setItemChecked(baseId + 28, sel.body()->findReferenceMark("velocity vector"));
refVectorMenu->insertItem(i18n("Show Planetographic Grid"), baseId + 29);
refVectorMenu->setItemChecked(baseId + 29, sel.body()->findReferenceMark("planetographic grid"));
refVectorMenu->insertItem(i18n("Show Terminator"), baseId + 30);
refVectorMenu->setItemChecked(baseId + 30, sel.body()->findReferenceMark("terminator"));
}
baseId += 31;
if (showSubObjects && sel.body() != NULL)
{
std::vector<std::string>* altSurfaces = sel.body()->getAlternateSurfaceNames();
if (altSurfaces != NULL)
{
if (!altSurfaces->empty())
{
KPopupMenu *surfaces = new KPopupMenu(this);
surfaces->insertItem(i18n("Normal"), locBaseId + 31);
int j=0;
for (std::vector<std::string>::const_iterator i = altSurfaces->begin();
i < altSurfaces->end(); i++, j++)
{
surfaces->insertItem(QString((*i).c_str()), locBaseId + 32 + j);
}
baseId += 7 + j;
popup->insertItem(i18n("&Alternate Surfaces"), surfaces);
}
delete altSurfaces;
}
const PlanetarySystem* satellites = sel.body()->getSatellites();
if (satellites != NULL && satellites->getSystemSize() != 0)
{
insertPlanetaryMenu(popup, getSelectionName(sel), satellites);
}
}
else if (showSubObjects && sel.star() != NULL)
{
Simulation *sim = appCore->getSimulation();
SolarSystemCatalog* solarSystemCatalog = sim->getUniverse()->getSolarSystemCatalog();
SolarSystemCatalog::iterator iter = solarSystemCatalog->find(sel.star()->getCatalogNumber());
if (iter != solarSystemCatalog->end())
{
SolarSystem* solarSys = iter->second;
insertPlanetaryMenu(popup, getSelectionName(sel), solarSys->getPlanets());
}
}
}
struct BodyComparePredicate
{
bool operator()(Body* a, Body* b)
{
return (a->getName(true).compare(b->getName(true)) < 0);
}
};
void SelectionPopup::insertPlanetaryMenu(KPopupMenu* popup, const string& parentName, const PlanetarySystem* psys) {
std::vector<Body*> asteroids;
std::vector<Body*> comets;
std::vector<Body*> invisibles;
std::vector<Body*> moons;
std::vector<Body*> planets;
std::vector<Body*> spacecraft;
std::vector<Body*> smallBodies;
std::vector<Body*> dwarfPlanets;
std::vector<std::vector<Body*>* > objects;
std::vector<std::string> menuNames;
// Add each vector of PlanetarySystem bodies to a vector to iterate over
objects.push_back(&asteroids);
menuNames.push_back(QString::fromUtf8(_("Asteroids")));
objects.push_back(&comets);
menuNames.push_back(QString::fromUtf8(_("Comets")));
objects.push_back(&moons);
menuNames.push_back(QString::fromUtf8(_("Moons")));
objects.push_back(&planets);
menuNames.push_back(QString::fromUtf8(_("Planets")));
objects.push_back(&spacecraft);
menuNames.push_back(QString::fromUtf8(_("Spacecraft")));
objects.push_back(&smallBodies);
menuNames.push_back(QString::fromUtf8(_("Small Bodies")));
objects.push_back(&dwarfPlanets);
menuNames.push_back(QString::fromUtf8(_("Dwarf Planets")));
for (int i = 0; i < psys->getSystemSize(); i++) {
Body* body = psys->getBody(i);
switch(body->getClassification()) {
case Body::Asteroid:
asteroids.push_back(body);
break;
case Body::Comet:
comets.push_back(body);
break;
case Body::Moon:
moons.push_back(body);
break;
case Body::Planet:
planets.push_back(body);
break;
case Body::Spacecraft:
spacecraft.push_back(body);
break;
case Body::SmallBody:
smallBodies.push_back(body);
break;
case Body::DwarfPlanet:
dwarfPlanets.push_back(body);
break;
case Body::Invisible:
case Body::Barycenter:
break;
}
}
// Count how many submenus we need to create
int numSubMenus = 0;
int nonEmpty = 0;
for (std::vector<std::vector<Body*>* >::const_iterator obj = objects.begin();
obj != objects.end();
++obj) {
if ((*obj)->size() > 0) {
numSubMenus++;
nonEmpty = obj - objects.begin();
}
}
if (numSubMenus == 0) return;
KPopupMenu *submenu = new KPopupMenu(this);
popup->insertSeparator();
if (numSubMenus > 1)
popup->insertItem(i18n("Orbiting Bodies"), submenu);
else
popup->insertItem(menuNames[nonEmpty], submenu);
std::vector<std::string>::const_iterator menuName = menuNames.begin();
BodyComparePredicate pred;
for (std::vector<std::vector<Body*>* >::const_iterator obj = objects.begin();
obj != objects.end();
++obj) {
// Only generate a submenu if the vector is not empty
if ((*obj)->size() > 0) {
// Don't create a submenu for a single item
if ((*obj)->size() == 1) {
std::vector<Body*>::const_iterator it = (*obj)->begin();
Selection s(*it);
KPopupMenu *objMenu = new KPopupMenu(this);
insert(objMenu, s);
submenu->insertItem(QString::fromUtf8((*it)->getName(true).c_str()), objMenu);
} else {
// Skip sorting if we are dealing with the planets in our own Solar System.
if (parentName != "Sol" || *menuName != QString::fromUtf8(_("Planets")))
std::sort((*obj)->begin(), (*obj)->end(), pred);
if (numSubMenus > 1) {
// Add items to submenu
KPopupMenu* objMenu = new KPopupMenu(this);
for(std::vector<Body*>::const_iterator it = (*obj)->begin(); it != (*obj)->end(); ++it) {
Selection s(*it);
KPopupMenu *menu = new KPopupMenu(this);
insert(menu, s);
objMenu->insertItem(QString::fromUtf8((*it)->getName(true).c_str()), menu);
}
submenu->insertItem(*menuName, objMenu);
} else {
// Just add items to the popup
for(std::vector<Body*>::const_iterator it = (*obj)->begin(); it != (*obj)->end(); ++it) {
Selection s(*it);
KPopupMenu *menu = new KPopupMenu(this);
insert(menu, s);
submenu->insertItem(QString::fromUtf8((*it)->getName(true).c_str()), menu);
}
}
}
}
menuName++;
}
}