1 // StarPlot - A program for interactively viewing 3D maps of stellar positions.
2 // Copyright (C) 2000 Kevin B. McCarty
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 /*
20 chartdialogs.cc
21 This file contains code for the dialog boxes in the StarPlot Chart menu.
22 */
23
24 #include "starplot.h"
25 #include <gtk/gtk.h>
26 using std::string;
27
28 /* automagnitude(): Tries to estimate a good dim magnitude cutoff for a given
29 * chart radius. */
automagnitude(double radius)30 double automagnitude(double radius)
31 {
32 if (radius <= 10) return 25;
33 else if (radius < 12.5) return 25 - (radius - 10) * 4.4;
34 else if (radius < 15) return 14 - (radius - 12.5) * 1.0;
35 else if (radius < 20) return 11.5 - (radius - 15) * 0.8;
36 else if (radius < 30) return 7.5 - (radius - 20) * 0.26;
37 else if (radius < 40) return 4.9 - (radius - 30) * 0.14;
38 else if (radius < 50) return 3.5 - (radius - 40) * 0.10;
39 else if (radius < 75) return 2.5 - (radius - 50) * 0.068;
40 else if (radius < 150) return 0.8 - (radius - 75) * 0.0173;
41 else if (radius < 200) return -0.5 - (radius - 150) * 0.002;
42 else if (radius < 600) return -0.6 - (radius - 200) * 0.005;
43 else if (radius < 1000) return -2.6 - (radius - 600) * 0.0025;
44 else if (radius < 2000) return -3.6 - (radius - 1000) * 0.001;
45 else if (radius < 4000) return -4.6 - (radius - 2000) * 0.00045;
46 else if (radius <10000) return -5.5 - (radius - 4000) * 0.000133;
47 else if (radius <12500) return -6.3;
48 else return -6.4;
49 }
50
51 /* my_gtk_position_dialog(): Sets up a box containing entry boxes for
52 * RA and Declination */
my_gtk_position_dialog(GtkWidget ** entrybox,GtkWidget * insertionbox,SolidAngle posn,bool celestial_coords)53 void my_gtk_position_dialog( GtkWidget **entrybox, GtkWidget *insertionbox,
54 SolidAngle posn, bool celestial_coords )
55 {
56 GtkWidget *table, *labels[8];
57 string labeltext[8], boxentries[6];
58
59 labeltext[5] = DEGREE_UTF8;
60 labeltext[6] = "'";
61 labeltext[7] = "\"";
62
63 if (celestial_coords) {
64 labeltext[1] =
65 /* TRANSLATORS: This is the abbreviation for
66 "hours of right ascension". */
67 _("h");
68 labeltext[2] =
69 /* TRANSLATORS: This is the abbreviation for
70 "minutes of right ascension". */
71 _("m");
72 labeltext[3] =
73 /* TRANSLATORS: This is the abbreviation for
74 "seconds of right ascension". */
75 _("s");
76 labeltext[0] = _("Right Ascension:"); labeltext[4] = _("Declination:");
77 }
78 else {
79 labeltext[1] = DEGREE_UTF8; labeltext[2] = "'"; labeltext[3] = "\"";
80 labeltext[0] = _("Galactic Longitude:");
81 labeltext[4] = _("Galactic Latitude:");
82 }
83
84 StringList rastrings=starstrings::ra_to_strs(posn.getPhi(),celestial_coords);
85 StringList decstrings = starstrings::dec_to_strs(posn.getTheta());
86 for (unsigned int i = 0; i < 3; i++) boxentries[i] = rastrings[i];
87 for (unsigned int i = 0; i < 3; i++) boxentries[i + 3] = decstrings[i];
88
89 for (int i = 0; i < 6; i++) {
90 starstrings::stripspace(boxentries[i]);
91 entrybox[i] = gtk_entry_new_with_max_length (10);
92 gtk_entry_set_text (GTK_ENTRY (entrybox[i]), boxentries[i].c_str());
93 gtk_widget_set_usize (entrybox[i], 40, 20);
94 gtk_widget_show (entrybox[i]);
95 }
96 for (int i = 0; i < 8; i++) {
97 labels[i] = gtk_label_new (labeltext[i].c_str());
98 gtk_misc_set_alignment (GTK_MISC (labels[i]), 0.0F, 0.0F);
99 gtk_widget_show (labels[i]);
100 }
101
102 table = gtk_table_new (2, 7, false);
103 gtk_widget_show (table);
104 for (int i = 0; i < 2; i++) {
105 gtk_table_attach (GTK_TABLE (table), labels[i*4], 0, 1, i, i + 1,
106 (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)GTK_FILL,
107 5, 5);
108 for (int j = 0; j < 3; j++) {
109 gtk_table_attach (GTK_TABLE (table), entrybox[i*3 + j],
110 j*2 + 1, j*2 + 2, i, i + 1,
111 (GtkAttachOptions)0, (GtkAttachOptions)0, 5, 5);
112 gtk_table_attach (GTK_TABLE (table), labels[i*4 + 1 + j],
113 j*2 + 2, j*2 + 3, i, i + 1,
114 (GtkAttachOptions)0, (GtkAttachOptions)0, 5, 5);
115 }
116 }
117 gtk_box_pack_start (GTK_BOX (insertionbox), table, false, false, 0);
118
119 return;
120 }
121
122
123 /* Handler for the Chart->Define Chart menu item */
124
125 /* The top-level Chart Define window pointer */
126 GtkWidget * definedialog;
127
128 /* Callback functions */
129
130 /* chart_define_callback(): Set the chart parameters to what was specified
131 * in the dialog box and update the chart. */
chart_define_callback(GtkWidget * widget,gpointer chart_define_data)132 void chart_define_callback(GtkWidget *widget, gpointer chart_define_data)
133 {
134 GtkWidget **data = (GtkWidget **)chart_define_data;
135 double oldchartradius = globals::chart_rules.ChartRadius;
136 double newchartradius = starmath::atof(
137 gtk_entry_get_text (GTK_ENTRY (data[8])))
138 / distance_conversion[globals::chart_rules.ChartUnits[1]];
139
140 if (newchartradius <= 0) {
141 my_gtk_error (GTK_WINDOW (definedialog),
142 starstrings::ssprintf(
143 _("You have entered a negative or\n\
144 zero value (%s %s) for the chart radius!\n\
145 Ignoring the change in this parameter."),
146 gtk_entry_get_text (GTK_ENTRY (data[8])),
147 distance_name[globals::chart_rules.ChartUnits[1]]).c_str());
148 newchartradius = oldchartradius;
149 }
150
151 globals::chart_rules.ChartLocation =
152 SolidAngle( starstrings::strs_to_ra(
153 gtk_entry_get_text (GTK_ENTRY (data[0])),
154 gtk_entry_get_text (GTK_ENTRY (data[1])),
155 gtk_entry_get_text (GTK_ENTRY (data[2])),
156 globals::chart_rules.CelestialCoords),
157 starstrings::strs_to_dec(
158 gtk_entry_get_text (GTK_ENTRY (data[3])),
159 gtk_entry_get_text (GTK_ENTRY (data[4])),
160 gtk_entry_get_text (GTK_ENTRY (data[5]))
161 )
162 ).toCartesian(starmath::atof(
163 gtk_entry_get_text(GTK_ENTRY(data[6])))
164 / distance_conversion[globals::chart_rules.ChartUnits[1]]);
165
166 globals::chart_rules.ChartRadius = newchartradius;
167
168 /* Even if the magnitude autoset feature is on, the user may have set
169 * the dim magnitude limit manually. We should discard the user's
170 * changes only if the new chart radius differs from the old radius.
171 * In this test, we compare the ratio of new and old radii to 1.0 in order
172 * to get around floating point imprecision. */
173
174 if (globals::chart_rules.ChartAutosetDimmestMagnitude
175 && (oldchartradius == 0.0
176 || fabs(newchartradius / oldchartradius - 1.0) > 0.01))
177 globals::chart_rules.ChartDimmestMagnitude =
178 automagnitude(globals::chart_rules.ChartRadius);
179
180 redraw_all(LOCATION_CHANGE);
181 return;
182 }
183
184 /* chart_define_defaults(): Restore the values handled by this dialog box
185 * to their default settings and update the chart. */
chart_define_defaults(GtkWidget * widget,gpointer dummy)186 void chart_define_defaults(GtkWidget *widget, gpointer dummy /* not used */)
187 {
188 double oldchartradius = globals::chart_rules.ChartRadius;
189 double newchartradius = defaults::chart_rules.ChartRadius;
190 RESET_GLOBAL(chart_rules.ChartLocation);
191 RESET_GLOBAL(chart_rules.ChartRadius);
192
193 /* Even if the magnitude autoset feature is on, the user may have set
194 * the dim magnitude limit manually. We should discard the user's
195 * changes only if the new chart radius differs from the old radius.
196 * In this test, we compare the ratio of new and old radii to 1.0 in order
197 * to get around floating point imprecision. */
198
199 if (globals::chart_rules.ChartAutosetDimmestMagnitude
200 && (oldchartradius == 0.0
201 || fabs(newchartradius / oldchartradius - 1.0) > 0.01))
202 globals::chart_rules.ChartDimmestMagnitude =
203 automagnitude(globals::chart_rules.ChartRadius);
204
205 redraw_all(LOCATION_CHANGE);
206 return;
207 }
208
209 /* chart_define_search(): Look up the star in the star name entry box, and if
210 * found, insert its coordinates into all the other entry boxes. Note: this
211 * function does not do anything else, it is still up to the user to hit
212 * OK to set these coordinates! */
chart_define_search(GtkWidget * widget,gpointer chart_define_data)213 void chart_define_search(GtkWidget *widget, gpointer chart_define_data)
214 {
215 GtkWidget **data = (GtkWidget **)chart_define_data;
216 string starname = gtk_entry_get_text (GTK_ENTRY (data[7]));
217 StarArray searchresults;
218
219 if (starstrings::isempty(starname)) return;
220
221 StringList ra, dec;
222
223 if (starname == string("[") + _("Chart Center") + string("]")) {
224 SolidAngle s = globals::chart_rules.ChartLocation.toSpherical();
225 //if (globals::chart_rules.CelestialCoords == GALACTIC)
226 //s = s.toGalactic();
227
228 ra = starstrings::ra_to_strs(s.getPhi(),
229 globals::chart_rules.CelestialCoords);
230 dec = starstrings::dec_to_strs(s.getTheta());
231
232 gtk_entry_set_text (GTK_ENTRY (data[6]), starstrings::ftoa(
233 globals::chart_rules.ChartLocation.magnitude()
234 * distance_conversion[globals::chart_rules.ChartUnits[1]], 8).c_str());
235 }
236 else {
237
238 // Try several different kinds of searches, order of most to least specific
239 searchresults.Search(starname, globals::chart_rules.ChartFileNames,
240 globals::chart_rules,
241 /* not case-sensitive */ false,
242 /* exact match */ true,
243 /* exit on match */ true);
244
245 // If the search string was quoted, an exact match was forced, so skip
246 // the remaining redundant search attempts
247 unsigned size = starname.size();
248 if (size > 2 && starname[0] == '"' && starname[size - 1] == '"')
249 /* nothing */;
250 else {
251
252 if (! searchresults.size())
253 searchresults.Search(starname, globals::chart_rules.ChartFileNames,
254 globals::chart_rules,
255 /* case-sensitive */ true,
256 /* substring match */ false,
257 /* exit on match */ true);
258 if (! searchresults.size())
259 searchresults.Search(starname, globals::chart_rules.ChartFileNames,
260 globals::chart_rules,
261 /* not case-sensitive */ false,
262 /* substring match */ false,
263 /* exit on match */ true);
264 } // end "else"
265
266 // if we don't find anything, leave a message in the star name entry
267 // box and return
268 if (! searchresults.size()) {
269 my_gtk_error (GTK_WINDOW (definedialog),
270 starstrings::ssprintf(_("Sorry, star \"%s\" not found."),
271 starname.c_str()).c_str());
272 return;
273 }
274
275 // otherwise, put the name which matched into the star name entry box,
276 // and put the star coordinates into the coordinate entry boxes.
277
278 StringList infolist = searchresults[0].GetInfo(globals::chart_rules,
279 false /*no dms punctuation*/,
280 SUBFIELD_DELIMITER);
281 // where is the star name which matches the search string in the
282 // list of star characteristics?
283 unsigned int nameplace = starmath::atoi(infolist[0]);
284 unsigned int infolistplace = nameplace ? nameplace + 9 : 1;
285 gtk_entry_set_text (GTK_ENTRY (data[7]), infolist[infolistplace].c_str());
286
287 ra = StringList(infolist[2], SUBFIELD_DELIMITER);
288 dec = StringList(infolist[3], SUBFIELD_DELIMITER);
289
290 if (ra[0] == string(_("N/A")))
291 ra = dec = StringList("00,00,00", ',');
292
293 gtk_entry_set_text (GTK_ENTRY (data[6]), starstrings::ftoa(
294 searchresults[0].GetStarDistance()
295 * distance_conversion[globals::chart_rules.ChartUnits[1]], 8).c_str());
296 } // end "else"
297
298 for (unsigned int i = 0; i < 3; i++) {
299 gtk_entry_set_text (GTK_ENTRY (data[i]), ra[i].c_str());
300 gtk_entry_set_text (GTK_ENTRY (data[i + 3]), dec[i].c_str());
301 }
302
303 return;
304 }
305
306 /* my_gtk_star_coordinates(): Create a dialog that permits entering a
307 * star name and clicking "Search" to enter coordinates, or entering
308 * coordinates by hand. Dialog is packed into an existing vbox passed
309 * in as an argument.
310 *
311 * entryboxes must be an array of or pointer to at least 8 GtkWidget *'s
312 * and is assumed to have the following layout:
313 *
314 * entryboxes[0] through [5] - controlled by my_gtk_position_dialog()
315 * gives the two angular coordinates
316 * entryboxes[6] - distance of coordinate from Sun
317 * entryboxes[7] - entry box for star name
318 *
319 * */
my_gtk_star_coordinates(GtkWidget ** entryboxes,GtkWidget * main_vbox)320 void my_gtk_star_coordinates(GtkWidget ** entryboxes, GtkWidget * main_vbox)
321 {
322 GtkWidget * lookup_frame, * lookup_hbox, * search;
323 GtkWidget * coord_frame, * coord_vbox;
324 GtkWidget * distance_hbox, * distance_label;
325 string distance_text;
326
327 // First element: a frame containing an hbox containing the star search
328 // entry box
329 lookup_frame = gtk_frame_new (
330 _("Enter a star name and press \"Search\""));
331 gtk_box_pack_start (GTK_BOX (main_vbox), lookup_frame, false, false, 0);
332 gtk_widget_show (lookup_frame);
333
334 lookup_hbox = gtk_hbox_new (false, 5);
335 gtk_container_add (GTK_CONTAINER (lookup_frame), lookup_hbox);
336 gtk_container_set_border_width (GTK_CONTAINER (lookup_hbox), 5);
337 gtk_widget_show (lookup_hbox);
338
339 entryboxes[7] = gtk_entry_new();
340 gtk_box_pack_start (GTK_BOX (lookup_hbox), entryboxes[7], true, true, 5);
341 gtk_widget_show (entryboxes[7]);
342
343 search = gtk_button_new_with_mnemonic (_("_Search"));
344 gtk_box_pack_start (GTK_BOX (lookup_hbox), search, false, false, 5);
345 gtk_widget_set_usize (search, defaults::program_button_width,
346 defaults::program_button_height);
347 gtk_widget_show (search);
348
349 // Second element: a frame containing a vbox containing the coordinate
350 // entry boxes
351 coord_frame = gtk_frame_new (
352 _("Or, enter coordinates manually"));
353 gtk_box_pack_start (GTK_BOX (main_vbox), coord_frame, false, false, 0);
354 gtk_widget_show (coord_frame);
355
356 coord_vbox = gtk_vbox_new (false, 5);
357 gtk_container_add (GTK_CONTAINER (coord_frame), coord_vbox);
358 gtk_container_set_border_width (GTK_CONTAINER (coord_vbox), 5);
359 gtk_widget_show (coord_vbox);
360
361 // fills in entryboxes[0] through [5]
362 my_gtk_position_dialog (entryboxes, coord_vbox,
363 globals::chart_rules.ChartLocation.toSpherical(),
364 globals::chart_rules.CelestialCoords);
365
366 distance_hbox = gtk_hbox_new (false, 5);
367 gtk_box_pack_start (GTK_BOX (coord_vbox), distance_hbox, false, false, 5);
368 gtk_widget_show (distance_hbox);
369
370 distance_label = gtk_label_new ((string(
371 _("Distance of position from Sun")) + " ("
372 + distance_name[globals::chart_rules.ChartUnits[1]] + "):").c_str());
373 gtk_box_pack_start (GTK_BOX (distance_hbox), distance_label, false, false, 5);
374 gtk_widget_show (distance_label);
375
376 distance_text =
377 starstrings::ftoa(globals::chart_rules.ChartLocation.magnitude()
378 * distance_conversion[globals::chart_rules.ChartUnits[1]], 8);
379 entryboxes[6] = gtk_entry_new_with_max_length (14);
380 gtk_box_pack_start (GTK_BOX(distance_hbox), entryboxes[6], false, false, 5);
381 gtk_entry_set_text (GTK_ENTRY (entryboxes[6]), distance_text.c_str());
382 gtk_widget_set_usize (entryboxes[6], 80, 20);
383 gtk_widget_show (entryboxes[6]);
384
385 // Connect the buttons to signals
386 g_signal_connect (G_OBJECT (search), "clicked",
387 G_CALLBACK (chart_define_search),
388 entryboxes);
389 g_signal_connect (G_OBJECT (entryboxes[7]), "activate",
390 G_CALLBACK (chart_define_search),
391 entryboxes);
392 }
393
394 /* This function has lots of GTK gui boilerplate because it is the most
395 * complicated of the dialog boxes. Sorry about that. */
chart_define()396 void chart_define()
397 {
398 GtkWidget *main_vbox, *query;
399 GtkWidget *chartrad_hbox, *chartrad_label, *chartrad_entry;
400 GtkWidget *OK, *defaults, *cancel;
401 static GtkWidget *chart_define_data[9];
402 string chartrad_text;
403
404 // The window
405 definedialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
406 gtk_window_set_resizable (GTK_WINDOW (definedialog), false);
407 gtk_window_set_title (GTK_WINDOW (definedialog), _("StarPlot: Define Chart"));
408 gtk_window_set_modal (GTK_WINDOW (definedialog), true);
409 g_signal_connect (G_OBJECT (definedialog), "destroy",
410 G_CALLBACK (gtk_widget_destroy), NULL);
411
412 // Pack it vertically
413 main_vbox = gtk_vbox_new (false, 5);
414 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
415 gtk_container_add (GTK_CONTAINER (definedialog), main_vbox);
416 gtk_widget_show (main_vbox);
417
418 // Query text
419 query = gtk_label_new (
420 _("Where should the chart origin be located?"));
421 gtk_box_pack_start (GTK_BOX (main_vbox), query, false, false, 0);
422 gtk_misc_set_alignment (GTK_MISC (query), 0.0F, 0.0F);
423 gtk_widget_show (query);
424
425 // Drop in the two elements of the star search frame
426 // (fills in chart_define_data[0] through [7])
427 my_gtk_star_coordinates(chart_define_data, main_vbox);
428
429 // Third element: an hbox containing the Chart Radius entry box
430 chartrad_hbox = gtk_hbox_new (false, 5);
431 gtk_box_pack_start (GTK_BOX (main_vbox), chartrad_hbox, false, false, 10);
432 gtk_widget_show (chartrad_hbox);
433
434 chartrad_label = gtk_label_new ((string(
435 _("Radius of chart")) + " ("
436 + distance_name[globals::chart_rules.ChartUnits[1]] + "):").c_str());
437 gtk_box_pack_start (GTK_BOX(chartrad_hbox), chartrad_label, false, false, 5);
438 gtk_misc_set_alignment (GTK_MISC (chartrad_label), 0.0F, 0.0F);
439 gtk_widget_show (chartrad_label);
440
441 chartrad_text = starstrings::ftoa(globals::chart_rules.ChartRadius
442 * distance_conversion[globals::chart_rules.ChartUnits[1]], 8);
443 chartrad_entry = gtk_entry_new_with_max_length (14);
444 gtk_box_pack_start(GTK_BOX(chartrad_hbox), chartrad_entry, false, false, 10);
445 gtk_entry_set_text (GTK_ENTRY (chartrad_entry), chartrad_text.c_str());
446 gtk_widget_set_usize (chartrad_entry, 80, 20);
447 gtk_widget_show (chartrad_entry);
448 chart_define_data[8] = chartrad_entry;
449
450 // Last element: the OK/Defaults/Cancel buttons
451 my_gtk_button_bar(&OK, &defaults, &cancel, main_vbox);
452
453 // Connect the buttons to signals
454 g_signal_connect (G_OBJECT (OK), "clicked",
455 G_CALLBACK (chart_define_callback),
456 chart_define_data);
457 g_signal_connect (G_OBJECT (defaults), "clicked",
458 G_CALLBACK (chart_define_defaults), NULL);
459 my_gtk_buttons_connect_destroy(OK, defaults, cancel, definedialog);
460
461 // Finally, set the window policy and show it
462 gtk_window_set_focus (GTK_WINDOW (definedialog), OK);
463 gtk_widget_show (definedialog);
464
465 return;
466 }
467
468
469 /* Handler for the Chart->Orientation menu item */
470
471 /* Callback functions */
472
473 /* chart_orient_callback(): Set the chart parameters to what was specified
474 * in the dialog box and update the chart. */
chart_orient_callback(GtkWidget * widget,gpointer chart_orient_data)475 void chart_orient_callback(GtkWidget *widget, gpointer chart_orient_data)
476 {
477 GtkWidget **data = (GtkWidget **)chart_orient_data;
478
479 globals::chart_rules.ChartOrientation =
480 SolidAngle( starstrings::strs_to_ra(
481 gtk_entry_get_text (GTK_ENTRY (data[0])),
482 gtk_entry_get_text (GTK_ENTRY (data[1])),
483 gtk_entry_get_text (GTK_ENTRY (data[2])),
484 globals::chart_rules.CelestialCoords),
485 starstrings::strs_to_dec(
486 gtk_entry_get_text (GTK_ENTRY (data[3])),
487 gtk_entry_get_text (GTK_ENTRY (data[4])),
488 gtk_entry_get_text (GTK_ENTRY (data[5]))
489 )
490 ); // <sarcasm>what is this, LISP?</sarcasm>
491
492 redraw_all(ORIENTATION_CHANGE);
493 return;
494 }
495
496 /* chart_orient_defaults(): Restore the values handled by this dialog box
497 * to their default settings and update the chart. */
chart_orient_defaults(GtkWidget * widget,gpointer data)498 void chart_orient_defaults(GtkWidget *widget, gpointer data)
499 {
500 RESET_GLOBAL(chart_rules.ChartOrientation);
501 redraw_all(ORIENTATION_CHANGE);
502 return;
503 }
504
chart_orient()505 void chart_orient()
506 {
507 GtkWidget *orientdialog, *vbox, *entrybox[6], *explanation;
508 GtkWidget *OK, *defaults, *cancel;
509 static GtkWidget *chart_orient_data[6];
510
511 // The window
512 orientdialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
513 gtk_window_set_resizable (GTK_WINDOW (orientdialog), false);
514 gtk_window_set_title (GTK_WINDOW (orientdialog), _("StarPlot: Orientation"));
515 gtk_window_set_modal (GTK_WINDOW (orientdialog), true);
516 g_signal_connect (G_OBJECT (orientdialog), "destroy",
517 G_CALLBACK (gtk_widget_destroy), NULL);
518
519 // Pack it vertically
520 vbox = gtk_vbox_new (false, 10);
521 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
522 gtk_container_add (GTK_CONTAINER (orientdialog), vbox);
523 gtk_widget_show (vbox);
524
525 explanation =
526 gtk_label_new (_("Set the orientation of the front of the chart:"));
527 gtk_misc_set_alignment (GTK_MISC (explanation), 0.0F, 0.0F);
528 gtk_box_pack_start (GTK_BOX (vbox), explanation, false, false, 0);
529 gtk_widget_show (explanation);
530
531 // The entry boxes
532 my_gtk_position_dialog (entrybox, vbox, globals::chart_rules.ChartOrientation,
533 globals::chart_rules.CelestialCoords);
534 for (int i = 0; i < 6; i++)
535 chart_orient_data[i] = entrybox[i];
536
537 // set up the buttons
538 my_gtk_button_bar (&OK, &defaults, &cancel, vbox);
539 g_signal_connect (G_OBJECT (OK), "clicked",
540 G_CALLBACK (chart_orient_callback),
541 chart_orient_data);
542 g_signal_connect (G_OBJECT (defaults), "clicked",
543 G_CALLBACK (chart_orient_defaults), NULL);
544 my_gtk_buttons_connect_destroy (OK, defaults, cancel, orientdialog);
545
546 gtk_window_set_focus (GTK_WINDOW (orientdialog), OK);
547 gtk_widget_show (orientdialog);
548
549 return;
550 }
551
552
553 /* Handler for the Chart->Star Filter menu item */
554
555 /* Callback functions */
556
557 /* chart_filter_callback(): Set the chart parameters to what was specified
558 * in the dialog box and update the chart. */
chart_filter_callback(GtkWidget * widget,gpointer chart_filter_data)559 void chart_filter_callback(GtkWidget *widget, gpointer chart_filter_data)
560 {
561 double origdimmag = globals::chart_rules.ChartDimmestMagnitude;
562 bool origautoset = globals::chart_rules.ChartAutosetDimmestMagnitude;
563 GtkWidget **data = (GtkWidget **)chart_filter_data;
564
565 for (int i = 0; i < 10; i++)
566 globals::chart_rules.StarClasses[i] = GTK_TOGGLE_BUTTON (data[i])->active;
567
568 globals::chart_rules.ChartDimmestMagnitude =
569 starmath::atof(gtk_entry_get_text (GTK_ENTRY (data[11])));
570 globals::chart_rules.ChartBrightestMagnitude =
571 starmath::atof(gtk_entry_get_text (GTK_ENTRY (data[10])));
572 globals::chart_rules.ChartAutosetDimmestMagnitude =
573 GTK_TOGGLE_BUTTON (data[12])->active;
574 globals::chart_rules.ChartHideCompanions =
575 GTK_TOGGLE_BUTTON (data[13])->active;
576
577 /* If the user has just turned on the magnitude autoset feature, we should
578 * autoset the dim magnitude limit, UNLESS the user has also just manually
579 * edited the dim magnitude limit. */
580 if (!origautoset && globals::chart_rules.ChartAutosetDimmestMagnitude
581 && fabs(origdimmag - globals::chart_rules.ChartDimmestMagnitude) < 0.1)
582 globals::chart_rules.ChartDimmestMagnitude =
583 automagnitude(globals::chart_rules.ChartRadius);
584
585 redraw_all(FILTER_CHANGE);
586 return;
587 }
588
589 /* chart_filter_defaults(): Restore the values handled by this dialog box
590 * to their default settings and update the chart. */
chart_filter_defaults(GtkWidget * widget,gpointer data)591 void chart_filter_defaults(GtkWidget *widget, gpointer data)
592 {
593 for (int i = 0; i < 10; i++)
594 RESET_GLOBAL(chart_rules.StarClasses[i]);
595 RESET_GLOBAL(chart_rules.ChartBrightestMagnitude);
596 RESET_GLOBAL(chart_rules.ChartDimmestMagnitude);
597 RESET_GLOBAL(chart_rules.ChartHideCompanions);
598 RESET_GLOBAL(chart_rules.ChartAutosetDimmestMagnitude);
599
600 if (globals::chart_rules.ChartAutosetDimmestMagnitude)
601 globals::chart_rules.ChartDimmestMagnitude =
602 automagnitude(globals::chart_rules.ChartRadius);
603
604 redraw_all(FILTER_CHANGE);
605 return;
606 }
607
608 /* chart_filter(): This function creates the dialog box for turning stars on
609 * or off by spectral class and magnitude. */
610
chart_filter()611 void chart_filter()
612 {
613 GtkWidget *filterdialog, *mainbox, *classframe, *magframe;
614 GtkWidget *classtable, *classboxes[10], *clabel;
615 GtkWidget *magtable, *magentrybox[2], *maglabel[2], *magautoset;
616 GtkWidget *hidecomps;
617 GtkWidget *OK, *defaults, *cancel;
618 static GtkWidget *chart_filter_data[14];
619 string maglimits[2];
620
621 // The window
622 filterdialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
623 gtk_window_set_resizable (GTK_WINDOW (filterdialog), false);
624 gtk_window_set_title (GTK_WINDOW (filterdialog), _("StarPlot: Star Filter"));
625 gtk_window_set_modal (GTK_WINDOW (filterdialog), true);
626 g_signal_connect (G_OBJECT (filterdialog), "destroy",
627 G_CALLBACK (gtk_widget_destroy), NULL);
628
629 // Pack it vertically
630 mainbox = gtk_vbox_new (false, 10);
631 gtk_container_set_border_width (GTK_CONTAINER (mainbox), 10);
632 gtk_container_add (GTK_CONTAINER (filterdialog), mainbox);
633 gtk_widget_show (mainbox);
634
635 // Frames in the window
636 classframe = gtk_frame_new (
637 _("By Spectral Class"));
638 magframe = gtk_frame_new (_("By Magnitude"));
639 gtk_box_pack_start (GTK_BOX (mainbox), classframe, true, false, 0);
640 gtk_box_pack_start (GTK_BOX (mainbox), magframe, true, false, 0);
641 gtk_widget_show (classframe);
642 gtk_widget_show (magframe);
643
644 // Create the spectral class checkboxes
645 classtable = gtk_table_new (5, 4, false);
646 gtk_container_add (GTK_CONTAINER (classframe), classtable);
647 gtk_widget_show (classtable);
648
649 clabel = gtk_label_new (_("Indicate which stellar classes to include:"));
650 gtk_widget_show (clabel);
651 gtk_misc_set_alignment (GTK_MISC (clabel), 0.0F, 0.0F);
652 gtk_table_attach (GTK_TABLE (classtable), clabel, 0, 4, 0, 1,
653 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND),
654 (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), 5, 5);
655
656 classboxes[0] =
657 gtk_check_button_new_with_mnemonic (
658 /* TRANSLATORS: "Wolf-Rayet" is a proper name for a type of star. */
659 _("Class _O / Wolf-Rayet"));
660 classboxes[1] = gtk_check_button_new_with_mnemonic (_("Class _B"));
661 classboxes[2] = gtk_check_button_new_with_mnemonic (_("Class _A"));
662 classboxes[3] = gtk_check_button_new_with_mnemonic (_("Class _F"));
663 classboxes[4] = gtk_check_button_new_with_mnemonic (_("Class _G"));
664 classboxes[5] = gtk_check_button_new_with_mnemonic (_("Class _K"));
665 classboxes[6] = gtk_check_button_new_with_mnemonic (_("Class _M"));
666 classboxes[7] = gtk_check_button_new_with_mnemonic (_("_Dwarf stars"));
667 classboxes[9] =
668 gtk_check_button_new_with_mnemonic (_("Show _Non-Stellar Objects"));
669 classboxes[8] =
670 gtk_check_button_new_with_mnemonic (_("Show _Unclassified Objects"));
671
672 for (int i = 0; i < 10; i++) {
673 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (classboxes[i]),
674 globals::chart_rules.StarClasses[i]);
675 gtk_widget_show (classboxes[i]);
676 chart_filter_data[i] = classboxes[i];
677 }
678
679 for (int i = 0; i < 4; i++) {
680 gtk_table_attach_defaults (GTK_TABLE (classtable), classboxes[2*i],
681 i, i + 1, 1, 2);
682 gtk_table_attach_defaults (GTK_TABLE (classtable), classboxes[2*i + 1],
683 i, i + 1, 2, 3);
684 }
685 gtk_table_attach_defaults (GTK_TABLE (classtable), classboxes[9], 0,2,3,4);
686 gtk_table_attach_defaults (GTK_TABLE (classtable), classboxes[8], 0,2,4,5);
687
688 // Create the magnitude text boxes
689 maglimits[0]=starstrings::ftoa(globals::chart_rules.ChartBrightestMagnitude);
690 maglimits[1]=starstrings::ftoa(globals::chart_rules.ChartDimmestMagnitude);
691 maglabel[0] = gtk_label_new (_("Smallest (brightest) allowed magnitude: "));
692 maglabel[1] = gtk_label_new (_("Largest (dimmest) allowed magnitude: "));
693
694 magtable = gtk_table_new (3, 2, false);
695 gtk_container_add (GTK_CONTAINER (magframe), magtable);
696 gtk_widget_show (magtable);
697
698 for (int i = 0; i < 2; i++) {
699 gtk_widget_show (maglabel[i]);
700 gtk_misc_set_alignment (GTK_MISC (maglabel[i]), 0.0F, 0.0F);
701
702 magentrybox[i] = gtk_entry_new_with_max_length (6);
703 gtk_entry_set_text (GTK_ENTRY (magentrybox[i]), maglimits[i].c_str());
704 gtk_widget_set_usize (magentrybox[i], 50, 20);
705 gtk_widget_show (magentrybox[i]);
706
707 gtk_table_attach (GTK_TABLE (magtable), maglabel[i], 0, 1, i, i + 1,
708 (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)GTK_FILL,
709 5, 5);
710 gtk_table_attach (GTK_TABLE (magtable), magentrybox[i], 1, 2, i, i + 1,
711 (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 5);
712
713 chart_filter_data[10 + i] = magentrybox[i];
714 }
715
716 magautoset = gtk_check_button_new_with_mnemonic
717 (_("Automatically set dim magnitude limit\nbased on _chart radius"));
718 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (magautoset),
719 globals::chart_rules.ChartAutosetDimmestMagnitude);
720 gtk_table_attach (GTK_TABLE (magtable), magautoset, 0, 2, 2, 3,
721 (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 5);
722 gtk_widget_show (magautoset);
723 chart_filter_data[12] = magautoset;
724
725 hidecomps = gtk_check_button_new_with_mnemonic
726 (_("_Hide nearby companion stars"));
727 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (hidecomps),
728 globals::chart_rules.ChartHideCompanions);
729 gtk_box_pack_start (GTK_BOX (mainbox), hidecomps, true, false, 0);
730 gtk_widget_show (hidecomps);
731 chart_filter_data[13] = hidecomps;
732
733 // set up the buttons
734 my_gtk_button_bar (&OK, &defaults, &cancel, mainbox);
735 g_signal_connect (G_OBJECT (OK), "clicked",
736 G_CALLBACK (chart_filter_callback),
737 chart_filter_data);
738 g_signal_connect (G_OBJECT (defaults), "clicked",
739 G_CALLBACK (chart_filter_defaults), NULL);
740 my_gtk_buttons_connect_destroy (OK, defaults, cancel, filterdialog);
741
742 gtk_window_set_focus (GTK_WINDOW (filterdialog), OK);
743 gtk_widget_show (filterdialog);
744
745 return;
746 }
747