00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <algorithm>
00014 #include <gtk/gtk.h>
00015
00016 #include <celengine/simulation.h>
00017 #include <celestia/celestiacore.h>
00018 #include <celutil/utf8.h>
00019
00020 #include "menu-context.h"
00021 #include "actions.h"
00022 #include "common.h"
00023
00024
00025
00026 static void wrapAction(GtkAction* action);
00027 static void menuMark();
00028 static void menuUnMark();
00029 static void handleContextPlanet(gpointer data);
00030 static void handleContextSurface(gpointer data);
00031
00032
00033 static GtkMenuItem* AppendMenu(GtkWidget* parent, GtkSignalFunc callback, const gchar* name, gpointer extra);
00034 static GtkMenu* CreatePlanetarySystemMenu(string parentName, const PlanetarySystem* psys);
00035 static GtkMenu* CreateAlternateSurfaceMenu(const vector<string>& surfaces);
00036
00037
00038
00039
00040 static AppData* app;
00041
00042
00043
00044 void initContext(AppData* a)
00045 {
00046 app = a;
00047 }
00048
00049
00050
00051
00052 void menuContext(float, float, Selection sel)
00053 {
00054 GtkWidget* popup = gtk_menu_new();
00055 string name;
00056
00057 switch (sel.getType())
00058 {
00059 case Selection::Type_Body:
00060 {
00061 name = sel.body()->getName();
00062 AppendMenu(popup, NULL, name.c_str(), gtk_action_group_get_action(app->agMain, "CenterSelection"));
00063 AppendMenu(popup, NULL, NULL, 0);
00064 AppendMenu(popup, NULL, "_Goto", gtk_action_group_get_action(app->agMain, "GotoSelection"));
00065 AppendMenu(popup, NULL, "_Follow", gtk_action_group_get_action(app->agMain, "FollowSelection"));
00066 AppendMenu(popup, NULL, "S_ync Orbit", gtk_action_group_get_action(app->agMain, "SyncSelection"));
00067
00068
00069
00070 const PlanetarySystem* satellites = sel.body()->getSatellites();
00071 if (satellites != NULL && satellites->getSystemSize() != 0)
00072 {
00073 GtkMenu* satMenu = CreatePlanetarySystemMenu(name, satellites);
00074 gtk_menu_item_set_submenu(AppendMenu(popup, NULL, "_Satellites", 0), GTK_WIDGET(satMenu));
00075 }
00076
00077 vector<string>* altSurfaces = sel.body()->getAlternateSurfaceNames();
00078 if (altSurfaces != NULL)
00079 {
00080 if (altSurfaces->size() > 0)
00081 {
00082 GtkMenu* surfMenu = CreateAlternateSurfaceMenu(*altSurfaces);
00083 gtk_menu_item_set_submenu(AppendMenu(popup, NULL, "_Alternate Surfaces", 0), GTK_WIDGET(surfMenu));
00084 delete altSurfaces;
00085 }
00086 }
00087 }
00088 break;
00089
00090 case Selection::Type_Star:
00091 {
00092 Simulation* sim = app->simulation;
00093 name = ReplaceGreekLetterAbbr(sim->getUniverse()->getStarCatalog()->getStarName(*(sel.star())));
00094 AppendMenu(popup, NULL, name.c_str(), gtk_action_group_get_action(app->agMain, "CenterSelection"));
00095 AppendMenu(popup, NULL, NULL, 0);
00096 AppendMenu(popup, NULL, "_Goto", gtk_action_group_get_action(app->agMain, "GotoSelection"));
00097
00098
00099
00100 SolarSystemCatalog* solarSystemCatalog = sim->getUniverse()->getSolarSystemCatalog();
00101 SolarSystemCatalog::iterator iter = solarSystemCatalog->find(sel.star()->getCatalogNumber());
00102 if (iter != solarSystemCatalog->end())
00103 {
00104 SolarSystem* solarSys = iter->second;
00105 GtkMenu* planetsMenu = CreatePlanetarySystemMenu(name, solarSys->getPlanets());
00106 if (name == "Sol")
00107 gtk_menu_item_set_submenu(AppendMenu(popup, NULL, "Orbiting Bodies", 0), GTK_WIDGET(planetsMenu));
00108 else
00109 gtk_menu_item_set_submenu(AppendMenu(popup, NULL, "Planets", 0), GTK_WIDGET(planetsMenu));
00110 }
00111 }
00112 break;
00113
00114 case Selection::Type_DeepSky:
00115 {
00116 AppendMenu(popup, NULL, app->simulation->getUniverse()->getDSOCatalog()->getDSOName(sel.deepsky()).c_str(), gtk_action_group_get_action(app->agMain, "CenterSelection"));
00117 AppendMenu(popup, NULL, NULL, 0);
00118 AppendMenu(popup, NULL, "_Goto", gtk_action_group_get_action(app->agMain, "GotoSelection"));
00119 AppendMenu(popup, NULL, "_Follow", gtk_action_group_get_action(app->agMain, "FollowSelection"));
00120
00121
00122 }
00123 break;
00124
00125 case Selection::Type_Location:
00126 break;
00127
00128 default:
00129 break;
00130 }
00131
00132 if (app->simulation->getUniverse()->isMarked(sel, 1))
00133 AppendMenu(popup, menuUnMark, "_Unmark", 0);
00134 else
00135 AppendMenu(popup, menuMark, "_Mark", 0);
00136
00137 app->simulation->setSelection(sel);
00138
00139 gtk_widget_show_all(popup);
00140 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
00141 }
00142
00143
00144
00145
00146 static void wrapAction(GtkAction* action)
00147 {
00148 gtk_action_activate(action);
00149 }
00150
00151
00152
00153 static void menuMark()
00154 {
00155 Simulation* sim = app->simulation;
00156 if (sim->getUniverse() != NULL)
00157 {
00158 sim->getUniverse()->markObject(sim->getSelection(),
00159 10.0f,
00160 Color(0.0f, 1.0f, 0.0f, 0.9f),
00161 Marker::Diamond,
00162 1);
00163 }
00164 }
00165
00166
00167
00168 static void menuUnMark()
00169 {
00170 Simulation* sim = app->simulation;
00171 if (sim->getUniverse() != NULL)
00172 sim->getUniverse()->unmarkObject(sim->getSelection(), 1);
00173 }
00174
00175
00176
00177 static void handleContextPlanet(gpointer data)
00178 {
00179 int value = GPOINTER_TO_INT(data);
00180
00181
00182 Selection sel = app->simulation->getSelection();
00183 switch (sel.getType())
00184 {
00185 case Selection::Type_Star:
00186 app->simulation->selectPlanet(value);
00187 break;
00188
00189 case Selection::Type_Body:
00190 {
00191 PlanetarySystem* satellites = (PlanetarySystem*) sel.body()->getSatellites();
00192 app->simulation->setSelection(Selection(satellites->getBody(value)));
00193 break;
00194 }
00195
00196 case Selection::Type_DeepSky:
00197
00198
00199 break;
00200
00201 case Selection::Type_Location:
00202 break;
00203
00204 default:
00205 break;
00206 }
00207 }
00208
00209
00210
00211 static void handleContextSurface(gpointer data)
00212 {
00213 int value = GPOINTER_TO_INT(data);
00214
00215
00216 Selection sel = app->simulation->getSelection();
00217 if (sel.body() != NULL)
00218 {
00219 guint index = value - 1;
00220 vector<string>* surfNames = sel.body()->getAlternateSurfaceNames();
00221 if (surfNames != NULL)
00222 {
00223 string surfName;
00224 if (index < surfNames->size())
00225 surfName = surfNames->at(index);
00226 app->simulation->getActiveObserver()->setDisplayedSurface(surfName);
00227 delete surfNames;
00228 }
00229 }
00230 }
00231
00232
00233
00234 static GtkMenuItem* AppendMenu(GtkWidget* parent, GtkSignalFunc callback, const gchar* name, gpointer extra)
00235 {
00236 GtkWidget* menuitem;
00237 gpointer data;
00238
00239
00240 if (name == NULL)
00241 menuitem = gtk_separator_menu_item_new();
00242 else
00243 menuitem = gtk_menu_item_new_with_mnemonic(name);
00244
00245
00246 if (callback == NULL && extra != 0)
00247 {
00248 callback = G_CALLBACK(wrapAction);
00249 data = extra;
00250 }
00251 else
00252 data = GINT_TO_POINTER(extra);
00253
00254
00255 if (callback != NULL)
00256 g_signal_connect_swapped (G_OBJECT(menuitem), "activate",
00257 G_CALLBACK(callback),
00258 data);
00259
00260 gtk_menu_shell_append(GTK_MENU_SHELL(parent), menuitem);
00261 return GTK_MENU_ITEM(menuitem);
00262 }
00263
00264
00265
00266 typedef pair<int,string> IntStrPair;
00267 typedef vector<IntStrPair> IntStrPairVec;
00268
00269 struct IntStrPairComparePredicate
00270 {
00271 IntStrPairComparePredicate() : dummy(0) {}
00272
00273 bool operator()(const IntStrPair pair1, const IntStrPair pair2) const
00274 {
00275 return (pair1.second.compare(pair2.second) < 0);
00276 }
00277
00278 int dummy;
00279 };
00280
00281
00282 static GtkMenu* CreatePlanetarySystemMenu(string parentName, const PlanetarySystem* psys)
00283 {
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 vector<IntStrPair> asteroids;
00296 vector<IntStrPair> comets;
00297 vector<IntStrPair> invisibles;
00298 vector<IntStrPair> moons;
00299 vector<IntStrPair> planets;
00300 vector<IntStrPair> spacecraft;
00301
00302
00303 vector<IntStrPairVec> objects;
00304 vector<string> menuNames;
00305
00306
00307 GtkWidget* menu = gtk_menu_new();
00308 for (int i = 0; i < psys->getSystemSize(); i++)
00309 {
00310 Body* body = psys->getBody(i);
00311 switch(body->getClassification())
00312 {
00313 case Body::Asteroid:
00314 asteroids.push_back(make_pair(i, body->getName()));
00315 break;
00316 case Body::Comet:
00317 comets.push_back(make_pair(i, body->getName()));
00318 break;
00319 case Body::Invisible:
00320 invisibles.push_back(make_pair(i, body->getName()));
00321 break;
00322 case Body::Moon:
00323 moons.push_back(make_pair(i, body->getName()));
00324 break;
00325 case Body::Planet:
00326 planets.push_back(make_pair(i, body->getName()));
00327 break;
00328 case Body::Spacecraft:
00329 spacecraft.push_back(make_pair(i, body->getName()));
00330 break;
00331 }
00332 }
00333
00334
00335 objects.push_back(asteroids);
00336 menuNames.push_back("Asteroids");
00337 objects.push_back(comets);
00338 menuNames.push_back("Comets");
00339 objects.push_back(invisibles);
00340 menuNames.push_back("Invisibles");
00341 objects.push_back(moons);
00342 menuNames.push_back("Moons");
00343 objects.push_back(planets);
00344 menuNames.push_back("Planets");
00345 objects.push_back(spacecraft);
00346 menuNames.push_back("Spacecraft");
00347
00348
00349 IntStrPairComparePredicate pred;
00350 vector<IntStrPairVec>::iterator obj;
00351 vector<IntStrPair>::iterator it;
00352 vector<string>::iterator menuName;
00353 GtkWidget* subMenu;
00354 int numSubMenus;
00355
00356
00357 numSubMenus = 0;
00358 for (obj=objects.begin(); obj != objects.end(); obj++)
00359 {
00360 if (obj->size() > 0)
00361 numSubMenus++;
00362 }
00363
00364 menuName = menuNames.begin();
00365 for (obj=objects.begin(); obj != objects.end(); obj++)
00366 {
00367
00368 if (obj->size() > 0)
00369 {
00370
00371 if (obj->size() == 1)
00372 {
00373 it=obj->begin();
00374 AppendMenu(menu, GTK_SIGNAL_FUNC(handleContextPlanet), it->second.c_str(), GINT_TO_POINTER(it->first));
00375 }
00376 else
00377 {
00378
00379
00380 if (parentName != "Sol" || *menuName != "Planets")
00381 sort(obj->begin(), obj->end(), pred);
00382
00383 if (numSubMenus > 1)
00384 {
00385
00386 subMenu = gtk_menu_new();
00387
00388 for(it=obj->begin(); it != obj->end(); it++)
00389 AppendMenu(subMenu, GTK_SIGNAL_FUNC(handleContextPlanet), it->second.c_str(), GINT_TO_POINTER(it->first));
00390
00391 gtk_menu_item_set_submenu(AppendMenu(menu, NULL, menuName->c_str(), 0), GTK_WIDGET(subMenu));
00392 }
00393 else
00394 {
00395
00396 for(it=obj->begin(); it != obj->end(); it++)
00397 AppendMenu(menu, GTK_SIGNAL_FUNC(handleContextPlanet), it->second.c_str(), GINT_TO_POINTER(it->first));
00398 }
00399 }
00400 }
00401 menuName++;
00402 }
00403
00404 return GTK_MENU(menu);
00405 }
00406
00407
00408
00409 static GtkMenu* CreateAlternateSurfaceMenu(const vector<string>& surfaces)
00410 {
00411 GtkWidget* menu = gtk_menu_new();
00412
00413 AppendMenu(menu, GTK_SIGNAL_FUNC(handleContextSurface), "Normal", 0);
00414 for (guint i = 0; i < surfaces.size(); i++)
00415 {
00416 AppendMenu(menu, GTK_SIGNAL_FUNC(handleContextSurface), surfaces[i].c_str(), GINT_TO_POINTER(i+1));
00417 }
00418
00419 return GTK_MENU(menu);
00420 }