dialog-eclipse.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:16k
源码类别:

OpenGL

开发平台:

Visual C++

  1. /*
  2.  *  Celestia GTK+ Front-End
  3.  *  Copyright (C) 2005 Pat Suwalski <pat@suwalski.net>
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  $Id: dialog-eclipse.cpp,v 1.2 2005-12-10 06:34:21 suwalski Exp $
  11.  */
  12. #include <gtk/gtk.h>
  13. #include <celengine/astro.h>
  14. #include <celengine/simulation.h>
  15. #include <celestia/eclipsefinder.h>
  16. #include "dialog-eclipse.h"
  17. #include "common.h"
  18. /* Definitions: Callbacks */
  19. static void calDateSelect(GtkCalendar *calendar, GtkToggleButton *button);
  20. static void showCalPopup(GtkToggleButton *button, EclipseData *ed);
  21. static gint eclipseGoto(GtkButton*, EclipseData* ed);
  22. static gint eclipse2Click(GtkWidget*, GdkEventButton* event, EclipseData* ed);
  23. static void eclipseCompute(GtkButton* button, EclipseData* ed);
  24. static void eclipseBodySelect(GtkMenuShell* menu, EclipseData* ed);
  25. static void eclipseTypeSelect(GtkMenuShell* menu, EclipseData* ed);
  26. static void listEclipseSelect(GtkTreeSelection* sel, EclipseData* ed);
  27. static void eclipseDestroy(GtkWidget* w, gint, EclipseData* ed);
  28. /* Definitions: Helpers */
  29. static void setButtonDateString(GtkToggleButton *button, int year, int month, int day);
  30. /* ENTRY: Navigation -> Eclipse Finder */
  31. void dialogEclipseFinder(AppData* app)
  32. {
  33. EclipseData* ed = g_new0(EclipseData, 1);
  34. selDate* d1 = g_new0(selDate, 1);
  35. selDate* d2 = g_new0(selDate, 1);
  36. ed->d1 = d1;
  37. ed->d2 = d2;
  38. ed->app = app;
  39. ed->eclipseList = NULL;
  40. ed->eclipseListStore = NULL;
  41. ed->bSolar = TRUE;
  42. sprintf(ed->body, "%s", eclipsePlanetTitles[0]);
  43. ed->sel = NULL;
  44. ed->window = GTK_DIALOG(gtk_dialog_new_with_buttons("Eclipse Finder",
  45.                                                     GTK_WINDOW(app->mainWindow),
  46.                                                     GTK_DIALOG_DESTROY_WITH_PARENT,
  47.                                                     GTK_STOCK_OK,
  48.                                                     GTK_RESPONSE_OK,
  49.                                                     NULL));
  50. gtk_window_set_modal(GTK_WINDOW(ed->window), FALSE);
  51.  
  52. GtkWidget *mainbox = gtk_vbox_new(FALSE, CELSPACING);
  53. gtk_container_set_border_width(GTK_CONTAINER(mainbox), CELSPACING);
  54. gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ed->window)->vbox), mainbox, TRUE, TRUE, 0);
  55. GtkWidget *scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  56. gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled_win),
  57.                                GTK_POLICY_AUTOMATIC,
  58.                                GTK_POLICY_ALWAYS);
  59. gtk_box_pack_start(GTK_BOX(mainbox), scrolled_win, TRUE, TRUE, 0);
  60. /* Create listbox list.
  61.  * Six invisible ints at the end to hold actual time.
  62.  * This will save string parsing like in KDE version.
  63.  * Last field holds pointer to selected Body. */
  64. ed->eclipseListStore = gtk_list_store_new(12,
  65.                                    G_TYPE_STRING,
  66.                                    G_TYPE_STRING,
  67.                                    G_TYPE_STRING,
  68.                                    G_TYPE_STRING,
  69.                                    G_TYPE_STRING,
  70.                                    G_TYPE_INT,
  71.                                    G_TYPE_INT,
  72.                                    G_TYPE_INT,
  73.                                    G_TYPE_INT,
  74.                                    G_TYPE_INT,
  75.                                    G_TYPE_INT,
  76.                                    G_TYPE_POINTER);
  77. ed->eclipseList = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ed->eclipseListStore));
  78. gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(ed->eclipseList), TRUE);
  79. gtk_container_add(GTK_CONTAINER(scrolled_win), ed->eclipseList);
  80. GtkCellRenderer *renderer;
  81. GtkTreeViewColumn *column;
  82. /* Add the columns */
  83. for (int i=0; i<5; i++) {
  84. renderer = gtk_cell_renderer_text_new();
  85. column = gtk_tree_view_column_new_with_attributes (eclipseTitles[i], renderer, "text", i, NULL);
  86. gtk_tree_view_append_column(GTK_TREE_VIEW(ed->eclipseList), column);
  87. }
  88. /* Set up callback for when an eclipse is selected */
  89. GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ed->eclipseList));
  90. g_signal_connect(selection, "changed", G_CALLBACK(listEclipseSelect), ed);
  91. /* From now on, it's the bottom-of-the-window controls */
  92. GtkWidget *label;
  93. GtkWidget *hbox;
  94. /* -------------------------------- */
  95. hbox = gtk_hbox_new(FALSE, CELSPACING);
  96. label = gtk_label_new("Find");
  97. gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  98. GtkWidget* menuTypeBox = gtk_option_menu_new();
  99. gtk_box_pack_start(GTK_BOX(hbox), menuTypeBox, FALSE, FALSE, 0);
  100. label = gtk_label_new("eclipse on");
  101. gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  102. GtkWidget* menuBodyBox = gtk_option_menu_new();
  103. gtk_box_pack_start(GTK_BOX(hbox), menuBodyBox, FALSE, FALSE, 0);
  104. gtk_box_pack_start(GTK_BOX(mainbox), hbox, FALSE, FALSE, 0);
  105. /* -------------------------------- */
  106. hbox = gtk_hbox_new(FALSE, CELSPACING);
  107. label = gtk_label_new("From");
  108. gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  109. /* Get current date */
  110. astro::Date datenow(app->simulation->getTime());
  111. /* Set current time */
  112. ed->d1->year = datenow.year - 1;
  113. ed->d1->month = datenow.month;
  114. ed->d1->day = datenow.day;
  115. /* Set time a year from now */
  116. ed->d2->year = ed->d1->year + 2;
  117. ed->d2->month = ed->d1->month;
  118. ed->d2->day = ed->d1->day;
  119. GtkWidget* date1Button = gtk_toggle_button_new();
  120. setButtonDateString(GTK_TOGGLE_BUTTON(date1Button), ed->d1->year, ed->d1->month, ed->d1->day);
  121. g_object_set_data(G_OBJECT(date1Button), "eclipsedata", ed->d1);
  122. gtk_box_pack_start(GTK_BOX(hbox), date1Button, FALSE, FALSE, 0);
  123. label = gtk_label_new("to");
  124. gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  125. GtkWidget* date2Button = gtk_toggle_button_new();
  126. setButtonDateString(GTK_TOGGLE_BUTTON(date2Button), ed->d2->year, ed->d2->month, ed->d2->day);
  127. g_object_set_data(G_OBJECT(date2Button), "eclipsedata", ed->d2);
  128. gtk_box_pack_start(GTK_BOX(hbox), date2Button, FALSE, FALSE, 0);
  129. gtk_box_pack_start(GTK_BOX(mainbox), hbox, FALSE, FALSE, 0);
  130. /* -------------------------------- */
  131. /* Common Buttons */
  132. hbox = gtk_hbox_new(TRUE, CELSPACING);
  133. if (buttonMake(hbox, "Compute", (GtkSignalFunc)eclipseCompute, ed))
  134. return;
  135. if (buttonMake(hbox, "Set Date and Go to Planet", (GtkSignalFunc)eclipseGoto, ed))
  136. return;
  137. gtk_box_pack_start(GTK_BOX(mainbox), hbox, FALSE, FALSE, 0);
  138. /* Set up the drop-down boxes */
  139. GtkWidget *item;
  140. GtkWidget* menuType = gtk_menu_new();
  141. for (int i = 0; eclipseTypeTitles[i] != NULL; i++)
  142. {
  143. item = gtk_menu_item_new_with_label(eclipseTypeTitles[i]);
  144. gtk_menu_append(GTK_MENU(menuType), item);
  145. gtk_widget_show(item);
  146. }
  147. gtk_option_menu_set_menu(GTK_OPTION_MENU(menuTypeBox), menuType);
  148. GtkWidget* menuBody = gtk_menu_new();
  149. for (int i = 0; eclipsePlanetTitles[i] != NULL; i++)
  150. {
  151. item = gtk_menu_item_new_with_label(eclipsePlanetTitles[i]);
  152. gtk_menu_append(GTK_MENU(menuBody), item);
  153. gtk_widget_show(item);
  154. }
  155. gtk_option_menu_set_menu(GTK_OPTION_MENU(menuBodyBox), menuBody);
  156. /* Hook up all the signals */
  157. g_signal_connect(GTK_OBJECT(menuType), "selection-done", G_CALLBACK(eclipseTypeSelect), ed);
  158.     g_signal_connect(GTK_OBJECT(menuBody), "selection-done", G_CALLBACK(eclipseBodySelect), ed);
  159. /* Double-click handler */
  160. g_signal_connect(GTK_OBJECT(ed->eclipseList), "button-press-event", G_CALLBACK(eclipse2Click), ed);
  161. g_signal_connect(GTK_OBJECT(date1Button), "toggled", G_CALLBACK(showCalPopup), ed);
  162. g_signal_connect(GTK_OBJECT(date2Button), "toggled", G_CALLBACK(showCalPopup), ed);
  163. g_signal_connect(ed->window, "response", G_CALLBACK(eclipseDestroy), ed);
  164. gtk_widget_set_usize(GTK_WIDGET(ed->window), 400, 400); /* Absolute Size, urghhh */
  165. gtk_widget_show_all(GTK_WIDGET(ed->window));
  166. }
  167. /* CALLBACK: When the GtkCalendar date is selected */
  168. static void calDateSelect(GtkCalendar *calendar, GtkToggleButton *button)
  169. {
  170. /* Set the selected date */
  171. guint year, month, day; 
  172. gtk_calendar_get_date(calendar, &year, &month, &day);
  173. /* A button stores its own date */
  174. selDate* date = (selDate *)g_object_get_data(G_OBJECT(button), "eclipsedata");
  175. date->year = year;
  176. date->month = month + 1;
  177. date->day = day;
  178. /* Update the button text */
  179. setButtonDateString(button, year, month + 1, day);
  180. /* Close the calendar window */
  181. gtk_toggle_button_set_active(button, !gtk_toggle_button_get_active(button));
  182. }
  183. /* CALLBACK: When a button is clicked to show a GtkCalendar */
  184. static void showCalPopup(GtkToggleButton *button, EclipseData *ed)
  185. {
  186. GtkWidget* calwindow = GTK_WIDGET(g_object_get_data(G_OBJECT(button), "calendar"));
  187. if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
  188. {
  189. /* Pushed in */
  190. if (!calwindow)
  191. {
  192. calwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  193. /* FIXME: should be a transient, but then there are focus issues */
  194. gtk_window_set_modal(GTK_WINDOW(calwindow), TRUE);
  195. gtk_window_set_type_hint(GTK_WINDOW(calwindow), GDK_WINDOW_TYPE_HINT_DOCK);
  196. gtk_window_set_decorated(GTK_WINDOW(calwindow), FALSE);
  197. gtk_window_set_resizable(GTK_WINDOW(calwindow), FALSE);
  198. gtk_window_stick(GTK_WINDOW(calwindow));
  199. GtkWidget* calendar = gtk_calendar_new();
  200. /* Load date structure stored in the button's data */
  201. selDate* date = (selDate *)g_object_get_data(G_OBJECT(button), "eclipsedata");
  202. gtk_calendar_select_month(GTK_CALENDAR(calendar), date->month - 1, date->year);
  203. gtk_calendar_select_day(GTK_CALENDAR(calendar), date->day);
  204. gtk_container_add(GTK_CONTAINER(calwindow), calendar);
  205. gtk_widget_show(calendar);
  206. int x, y, i, j;
  207. gdk_window_get_origin(GDK_WINDOW(GTK_WIDGET(button)->window), &x, &y);
  208. gtk_widget_translate_coordinates(GTK_WIDGET(button), GTK_WIDGET(ed->window), 10, 10, &i, &j);
  209. gtk_window_move(GTK_WINDOW(calwindow), x + i, y + j);
  210. g_signal_connect(calendar, "day-selected-double-click", G_CALLBACK(calDateSelect), button);
  211. gtk_window_present(GTK_WINDOW(calwindow));
  212. g_object_set_data_full(G_OBJECT (button), "calendar",
  213.                        calwindow, (GDestroyNotify)gtk_widget_destroy);
  214. }
  215. }
  216. else
  217. {
  218. /* Pushed out */
  219. if (calwindow)
  220. {
  221. /* Destroys the calendar */
  222. g_object_set_data(G_OBJECT (button), "calendar", NULL);
  223. calwindow = NULL;
  224. }
  225. }
  226. }
  227. /* CALLBACK: "SetTime/Goto" in Eclipse Finder */
  228. static gint eclipseGoto(GtkButton*, EclipseData* ed)
  229. {
  230. GValue value = { 0, 0 }; /* Initialize GValue to 0 */
  231. GtkTreeIter iter;
  232. GtkTreeModel* model;
  233. int time[6];
  234. Simulation* sim = ed->app->simulation;
  235. /* Nothing selected */
  236. if (ed->sel == NULL)
  237. return FALSE;
  238. /* IF prevents selection while list is being updated */
  239. if (!gtk_tree_selection_get_selected(ed->sel, &model, &iter))
  240. return FALSE;
  241. /* Tedious method of extracting the desired time.
  242.  * However, still better than parsing a single string. */
  243. for (int i = 0; i < 6; i++)
  244. {
  245. gtk_tree_model_get_value(model, &iter, i+5, &value);
  246. time[i] = g_value_get_int(&value);
  247. g_value_unset(&value);
  248. }
  249. /* Retrieve the selected body */
  250. gtk_tree_model_get_value(model, &iter, 11, &value);
  251. Body* body  = (Body *)g_value_get_pointer(&value);
  252. g_value_unset(&value);
  253. /* Set time based on retrieved values */
  254. astro::Date d(time[0], time[1], time[2]);
  255. d.hour = time[3];
  256. d.minute = time[4];
  257. d.seconds = (double)time[5];
  258. sim->setTime((double)d);
  259. /* The rest is directly from the Windows eclipse code */
  260. Selection target(body);
  261. Selection ref(body->getSystem()->getStar());
  262. /* Use the phase lock coordinate system to set a position
  263.  * on the line between the sun and the body where the eclipse
  264.  * is occurring. */
  265. sim->setFrame(ObserverFrame::PhaseLock, target, ref);
  266. sim->update(0.0);
  267. double distance = astro::kilometersToMicroLightYears(target.radius() * 4.0);
  268. sim->gotoLocation(Point3d(distance, 0, 0), Quatd::yrotation(-PI / 2) * Quatd::xrotation(-PI / 2), 5.0);
  269. return TRUE;
  270. }
  271. /* CALLBACK: Double-click on the Eclipse Finder Listbox */
  272. static gint eclipse2Click(GtkWidget*, GdkEventButton* event, EclipseData* ed)
  273. {
  274. if (event->type == GDK_2BUTTON_PRESS) {
  275. /* Double-click, same as hitting the select and go button */
  276. return eclipseGoto(NULL, ed);
  277. }
  278. return FALSE;
  279. }
  280. /* CALLBACK: Compute button in Eclipse Finder */
  281. static void eclipseCompute(GtkButton* button, EclipseData* ed)
  282. {
  283. GtkTreeIter iter;
  284. /* Set the cursor to a watch and force redraw */
  285. gdk_window_set_cursor(GTK_WIDGET(button)->window, gdk_cursor_new(GDK_WATCH));
  286. gtk_main_iteration();
  287. /* Clear the listbox */
  288. gtk_list_store_clear(ed->eclipseListStore);
  289. /* Create the dates in a more suitable format */
  290. astro::Date from(ed->d1->year, ed->d1->month, ed->d1->day);
  291. astro::Date to(ed->d2->year, ed->d2->month, ed->d2->day);
  292. /* Initialize the eclipse finder */
  293. EclipseFinder ef(ed->app->core, ed->body, ed->bSolar ? Eclipse::Solar : Eclipse::Moon, (double)from, (double)to);
  294. vector<Eclipse> eclipseListRaw = ef.getEclipses();
  295. for (std::vector<Eclipse>::iterator i = eclipseListRaw.begin();
  296. i != eclipseListRaw.end();
  297. i++)
  298. {
  299. /* Handle 0 case */
  300. if ((*i).planete == "None") {
  301. gtk_list_store_append(ed->eclipseListStore, &iter);
  302. gtk_list_store_set(ed->eclipseListStore, &iter, 0, (*i).planete.c_str(), -1);
  303. continue;
  304. }
  305. char d[12], strStart[10], strEnd[10];
  306. astro::Date start((*i).startTime);
  307. astro::Date end((*i).endTime);
  308. sprintf(d, "%d-%02d-%02d", (*i).date->year, (*i).date->month, (*i).date->day);
  309. sprintf(strStart, "%02d:%02d:%02d", start.hour, start.minute, (int)start.seconds);
  310. sprintf(strEnd, "%02d:%02d:%02d", end.hour, end.minute, (int)end.seconds);
  311. /* Set time to middle time so that eclipse it right on earth */
  312. astro::Date timeToSet = (start + end) / 2.0f;
  313. /* Add item to the list.
  314.  * Entries 5-11 are not displayed and store data. */
  315. gtk_list_store_append(ed->eclipseListStore, &iter);
  316. gtk_list_store_set(ed->eclipseListStore, &iter,
  317.                    0, (*i).planete.c_str(),
  318.                    1, (*i).sattelite.c_str(),
  319.                    2, d,
  320.                    3, strStart,
  321.                    4, strEnd,
  322.                    5, timeToSet.year,
  323.                    6, timeToSet.month,
  324.                    7, timeToSet.day,
  325.                    8, timeToSet.hour,
  326.                    9, timeToSet.minute,
  327.                    10, (int)timeToSet.seconds,
  328.                    11, (*i).body,
  329.                    -1);
  330. }
  331. /* Set the cursor back */
  332. gdk_window_set_cursor(GTK_WIDGET(button)->window, gdk_cursor_new(GDK_LEFT_PTR));
  333. }
  334. /* CALLBACK: When Eclipse Body is selected */
  335. static void eclipseBodySelect(GtkMenuShell* menu, EclipseData* ed)
  336. {
  337. GtkWidget* item = gtk_menu_get_active(GTK_MENU(menu));
  338. GList* list = gtk_container_children(GTK_CONTAINER(menu));
  339. int itemIndex = g_list_index(list, item);
  340. /* Set string according to body array */
  341. sprintf(ed->body, "%s", eclipsePlanetTitles[itemIndex]);
  342. }
  343. /* CALLBACK: When Eclipse Type (Solar:Moon) is selected */
  344. static void eclipseTypeSelect(GtkMenuShell* menu, EclipseData* ed)
  345. {
  346. GtkWidget* item = gtk_menu_get_active(GTK_MENU(menu));
  347. GList* list = gtk_container_children(GTK_CONTAINER(menu));
  348. int itemIndex = g_list_index(list, item);
  349. /* Solar eclipse */
  350. if (itemIndex == 0)
  351. ed->bSolar = 1;
  352. /* Moon eclipse */
  353. else
  354. ed->bSolar = 0;
  355. }
  356. /* CALLBACK: When Eclipse is selected in Eclipse Finder */
  357. static void listEclipseSelect(GtkTreeSelection* sel, EclipseData* ed)
  358. {
  359. /* Simply set the selection pointer to this data item */
  360. ed->sel = sel;
  361. }
  362. /* CALLBACK: Destroy Window */
  363. static void eclipseDestroy(GtkWidget* w, gint, EclipseData* ed)
  364. {
  365. gtk_widget_destroy(GTK_WIDGET(w));
  366. g_free(ed->d1);
  367. g_free(ed->d2);
  368. g_free(ed);
  369. }
  370. /* HELPER: set a date string in a button */
  371. static void setButtonDateString(GtkToggleButton *button, int year, int month, int day)
  372. {
  373. char date[50];
  374. sprintf(date, "%d %s %d", day, monthOptions[month - 1], year);
  375. gtk_button_set_label(GTK_BUTTON(button), date);
  376. }