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   hrdiagram.cc
21   This file contains code for viewing a Hertzsprung-Russell diagram of the
22   stars being shown in the main program window.
23 */
24 
25 #include <gtk/gtk.h>
26 #include "starplot.h"
27 #include <cstdlib>
28 
29 /* Functions to make sure the HR Diagram window stays updated */
30 
31 namespace globals {
32   static GtkWidget  *program_hr_window = NULL;
33   static GdkPixmap  *program_hr_pixmap = NULL;
34 }
35 
36 
hr_redraw_display(GtkWidget * widget)37 void hr_redraw_display(GtkWidget *widget)
38 {
39   if (globals::program_hr_viewer && globals::chart_stararray) {
40     globals::chart_stararray->Diagram(globals::program_hr_viewer,
41 				      globals::hr_mag_bright,
42 				      globals::hr_mag_dim);
43     gdk_draw_pixmap(widget->window,
44 		    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
45 		    globals::program_hr_pixmap,
46 		    0, 0, 0, 0,
47 		    widget->allocation.width, widget->allocation.height);
48   }
49 }
50 
51 
52 /* Create a new backing pixmap of the appropriate size */
configure_event(GtkWidget * widget,GdkEventConfigure * event)53 static gint configure_event( GtkWidget         *widget,
54 			     GdkEventConfigure *event )
55 {
56   if (globals::program_hr_pixmap) {
57     delete globals::program_hr_viewer;
58     gdk_pixmap_unref (globals::program_hr_pixmap);
59   }
60   globals::program_hr_pixmap = gdk_pixmap_new(widget->window,
61 					      widget->allocation.width,
62 					      widget->allocation.height,
63 					      -1);
64   globals::program_hr_viewer =
65     new GTKViewer(globals::program_hr_pixmap, globals::program_hr_canvas);
66   hr_redraw_display(widget);
67   return true;
68 }
69 
70 
71 /* Redraw the screen from the backing pixmap */
expose_event(GtkWidget * widget,GdkEventExpose * event)72 static gint expose_event( GtkWidget      *widget,
73 			  GdkEventExpose *event )
74 {
75   gdk_draw_pixmap(widget->window,
76 		  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
77 		  globals::program_hr_pixmap,
78 		  event->area.x, event->area.y,
79 		  event->area.x, event->area.y,
80 		  event->area.width, event->area.height);
81   return false;
82 }
83 
84 
85 /* function to exit the HR Diagram window */
hr_quit()86 void hr_quit()
87 {
88   delete globals::program_hr_viewer;
89   globals::program_hr_viewer = NULL;
90   gtk_widget_destroy(globals::program_hr_window);
91   return;
92 }
93 
94 
95 /* functions allowing to set the magnitude bounds of the HR Diagram */
96 
97 /* callback functions: */
hr_mag_callback(GtkWidget * widget,gpointer magnitude_data)98 void hr_mag_callback(GtkWidget *widget, gpointer magnitude_data)
99 {
100   GtkWidget **data = (GtkWidget **)magnitude_data;
101   globals::hr_mag_bright =
102     starmath::atof(gtk_entry_get_text (GTK_ENTRY (data[0])));
103   globals::hr_mag_dim =
104     starmath::atof(gtk_entry_get_text (GTK_ENTRY (data[1])));
105   hr_redraw_display(globals::program_hr_canvas);
106 }
107 
hr_mag_defaults(GtkWidget * widget,gpointer data)108 void hr_mag_defaults(GtkWidget *widget,
109 		     gpointer data /*just here so the type checker is happy*/)
110 {
111   RESET_GLOBAL(hr_mag_bright);
112   RESET_GLOBAL(hr_mag_dim);
113   hr_redraw_display(globals::program_hr_canvas);
114 }
115 
116 /* the function displaying the dialog box */
hr_settings()117 void hr_settings()
118 {
119   GtkWidget *hr_set_dialog, *vbox, *table, *labels[2];
120   GtkWidget *OK, *defaults, *cancel;
121   static GtkWidget *entrybox[2];
122   std::string entryboxtext[2];
123 
124   // The window
125   hr_set_dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
126   gtk_window_set_resizable (GTK_WINDOW (hr_set_dialog), false);
127   gtk_window_set_title (GTK_WINDOW (hr_set_dialog),
128       /* TRANSLATORS: "HR" stands for "Hertzsprung-Russell", a proper name. */
129       _("StarPlot: HR Diagram Scale"));
130   gtk_window_set_modal (GTK_WINDOW (hr_set_dialog), true);
131   g_signal_connect (G_OBJECT (hr_set_dialog), "destroy",
132 		      G_CALLBACK (gtk_widget_destroy), NULL);
133 
134   // Pack it vertically
135   vbox = gtk_vbox_new (false, 10);
136   gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
137   gtk_container_add (GTK_CONTAINER (hr_set_dialog), vbox);
138   gtk_widget_show (vbox);
139 
140   // will put in a table:
141   table = gtk_table_new (2, 2, false);
142   gtk_box_pack_start (GTK_BOX (vbox), table, true, false, 0);
143   gtk_widget_show (table);
144 
145   labels[0] = gtk_label_new (_("Magnitude at top of y axis:"));
146   labels[1] = gtk_label_new (_("Magnitude at bottom of y axis:"));
147   entryboxtext[0] = starstrings::ftoa(globals::hr_mag_bright);
148   entryboxtext[1] = starstrings::ftoa(globals::hr_mag_dim);
149 
150   for (unsigned int i = 0; i < 2; i++) {
151     gtk_misc_set_alignment (GTK_MISC (labels[i]), 0.0F, 0.0F);
152     gtk_widget_show (labels[i]);
153 
154     entrybox[i] = gtk_entry_new_with_max_length (8);
155     gtk_widget_set_usize (entrybox[i], 50, 20);
156     gtk_entry_set_text (GTK_ENTRY (entrybox[i]), entryboxtext[i].c_str());
157     gtk_widget_show (entrybox[i]);
158 
159     gtk_table_attach (GTK_TABLE (table), labels[i], 0, 1, i, i + 1,
160 		      (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)GTK_FILL,
161 		      5, 5);
162     gtk_table_attach (GTK_TABLE (table), entrybox[i], 1, 2, i, i + 1,
163 		      (GtkAttachOptions)0, (GtkAttachOptions)0, 5, 5);
164   }
165 
166   // set up the buttons
167   my_gtk_button_bar (&OK, &defaults, &cancel, vbox);
168   g_signal_connect (G_OBJECT (OK), "clicked",
169 		      G_CALLBACK (hr_mag_callback),
170 		      entrybox);
171   g_signal_connect (G_OBJECT (defaults), "clicked",
172 		      G_CALLBACK (hr_mag_defaults), NULL);
173   my_gtk_buttons_connect_destroy(OK, defaults, cancel, hr_set_dialog);
174 
175   gtk_window_set_focus (GTK_WINDOW (hr_set_dialog), OK);
176   gtk_widget_show (hr_set_dialog);
177 }
178 
179 
180 /* Here are all the items in the StarPlot HR Diagram window's menu.
181  *  Unimplemented items have been commented out.
182  *  Note: C++ compilers don't like having non-void callback functions in the
183  *  GtkItemFactoryEntry struct.  It interferes with strict type checking.
184  */
185 
186 GtkItemFactoryEntry hr_menu_items[] = {     /*       fn.        */
187   /* menu path             acc. key    callback fn. param  type */
188   {
189     _("/_File"),                   0,     0,             0, "<Branch>" },
190 //{ _("/File/_Save Window as PNG..."), 0, hr_save,       0,   "" },
191   {
192     _("/File/_Close Window"),      0,     hr_quit,       0, "" },
193 
194   { _("/_Options"),                0,     0,             0, "<Branch>" },
195   { _("/Options/Scale _Y Axis..."),0,     hr_settings,   0, "" },
196 
197   // star label and star diameter submenus
198   OPTIONS_LABEL_MENU, OPTIONS_DIAMETER_MENU // #defined in menu.h
199 };
200 
201 GtkWidget *hr_options_label_widgets[OPTIONS_LABEL_MENU_SIZE];
202 GtkWidget *hr_options_diameter_widgets[OPTIONS_DIAMETER_MENU_SIZE];
203 
204 
205 /* hr_main_menu(): This function prepares the StarPlot HR Diagram window
206    menu bar. */
207 
hr_main_menu(GtkWidget * hr_window,GtkWidget ** menubar)208 void hr_main_menu (GtkWidget *hr_window, GtkWidget **menubar)
209 {
210   GtkItemFactory *item_factory;
211   GtkAccelGroup *accel_group;
212   int nmenu_items = sizeof (hr_menu_items) / sizeof (hr_menu_items[0]);
213   static bool inited = false;
214 
215   if (! inited) {
216     /* Gettextize the menu item names */
217     for (int i = 0; i < nmenu_items; i++) {
218       hr_menu_items[i].path = strdup(gettext(hr_menu_items[i].path));
219       if (hr_menu_items[i].item_type[0] != 0 &&
220 	  hr_menu_items[i].item_type[0] != '<')
221         hr_menu_items[i].item_type = strdup(gettext(hr_menu_items[i].item_type));
222     }
223     inited = true;
224   }
225 
226   accel_group = gtk_accel_group_new ();
227 
228   /* This function initializes the item factory.
229      Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
230      or GTK_TYPE_OPTION_MENU.
231      Param 2: The path of the menu.
232      Param 3: A pointer to a gtk_accel_group.  The item factory sets up
233      the accelerator table while generating menus.
234   */
235 
236   item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
237 				       accel_group);
238 
239   /* This function generates the menu items. Pass the item factory,
240      the number of items in the array, the array itself, and any
241      callback data for the the menu items. */
242   gtk_item_factory_create_items (item_factory, nmenu_items,
243 				 hr_menu_items, NULL);
244 
245   /* Attach the new accelerator group to the window. */
246   gtk_window_add_accel_group (GTK_WINDOW (hr_window), accel_group);
247 
248   /* Make the options menu radio button widgets globally available and set
249    *  them to have the same state as the main menu options menu */
250   for (unsigned int i = 0; i < OPTIONS_LABEL_MENU_SIZE; i++) {
251     GtkWidget *item;
252     item = gtk_item_factory_get_widget (item_factory,
253 					options_label_names[i]);
254     hr_options_label_widgets[i] = item;
255 
256     if ((GTK_CHECK_MENU_ITEM (options_label_widgets[i]))->active)
257       set_item(&globals::chart_rules.StarLabels,
258 	       globals::chart_rules.StarLabels, item, false);
259   }
260 
261   for (unsigned int i = 0; i < OPTIONS_DIAMETER_MENU_SIZE; i++) {
262     GtkWidget *item;
263     item = gtk_item_factory_get_widget (item_factory,
264 					options_diameter_names[i]);
265     hr_options_diameter_widgets[i] = item;
266 
267     if ((GTK_CHECK_MENU_ITEM (options_diameter_widgets[i]))->active)
268       set_item(&globals::chart_rules.StarDiameters,
269 	       globals::chart_rules.StarDiameters, item, false);
270   }
271 
272   if (menubar) {
273     /* Finally, return the actual menu bar created by the item factory. */
274     *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
275   }
276 }
277 
278 
279 /* The main function for the HR Diagram window */
280 
hrdiagram()281 void hrdiagram()
282 {
283   GtkWidget *mainbox = NULL;
284   GtkWidget *menubar;
285 
286   // If the HR window is already open, do nothing but put it in front
287   if (globals::program_hr_viewer) {
288     gdk_window_raise(globals::program_hr_window->window);
289     return;
290   }
291 
292   /* This sets the window title and border width: */
293   globals::program_hr_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
294   gtk_window_set_title (GTK_WINDOW (globals::program_hr_window),
295     /* TRANSLATORS: "HR" stands for "Hertzsprung-Russell", a proper name. */
296     _("StarPlot: HR Diagram"));
297   gtk_container_set_border_width (GTK_CONTAINER (globals::program_hr_window),0);
298 
299   /* Set a delete_event handler for closing the window */
300   g_signal_connect (G_OBJECT (globals::program_hr_window), "delete_event",
301 		      G_CALLBACK (hr_quit), NULL);
302 
303   /* Set the menus for this window. */
304   hr_main_menu (globals::program_hr_window, &menubar);
305 
306   /* Set up the drawing area */
307   globals::program_hr_canvas = gtk_drawing_area_new();
308   gtk_widget_modify_font (GTK_WIDGET (globals::program_hr_canvas),
309     pango_font_description_from_string (globals::display_fontname.c_str()));
310   gtk_drawing_area_size (GTK_DRAWING_AREA (globals::program_hr_canvas),
311 		         defaults::program_hr_width,
312 			 defaults::program_hr_height);
313 
314   /* Signals used to handle backing pixmap */
315   g_signal_connect (G_OBJECT (globals::program_hr_canvas), "expose_event",
316 		      G_CALLBACK (expose_event), NULL);
317   g_signal_connect (G_OBJECT (globals::program_hr_canvas), "configure_event",
318 		      G_CALLBACK (configure_event), NULL);
319 
320   /* Event signals */
321   //  g_signal_connect (G_OBJECT (hr_drawing_area), "button_press_event",
322   //		        G_CALLBACK (button_press_event), NULL);
323   gtk_widget_set_events (globals::program_hr_canvas, GDK_EXPOSURE_MASK
324 			 | GDK_LEAVE_NOTIFY_MASK
325 			 | GDK_BUTTON_PRESS_MASK
326 			 | GDK_POINTER_MOTION_MASK
327 			 | GDK_POINTER_MOTION_HINT_MASK);
328 
329   /* finish putting widgets together */
330   mainbox = gtk_vbox_new (false, 0);
331   gtk_container_border_width (GTK_CONTAINER (mainbox), 1);
332   gtk_container_add (GTK_CONTAINER (globals::program_hr_window), mainbox);
333   gtk_box_pack_start (GTK_BOX (mainbox), menubar, false, true, 0);
334   gtk_box_pack_start (GTK_BOX (mainbox), globals::program_hr_canvas,
335 		      true, true, 0);
336 
337   gtk_widget_realize (globals::program_hr_canvas);
338   hr_redraw_display (globals::program_hr_canvas);
339   gtk_widget_show (globals::program_hr_canvas);
340   gtk_widget_show (menubar);
341   gtk_widget_show (mainbox);
342   gtk_widget_show (globals::program_hr_window);
343 
344   return;
345 }
346