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   starplot.cc
21   This is the file which includes the StarPlot main() function.
22   However, this does little besides set up the main program window -
23   most of the program functionality is defined in the other .cc files
24   in this directory.
25 */
26 
27 #include <gtk/gtk.h>
28 #include "starplot.h"
29 #include "starplot.xpm"
30 
31 #define FLIP(boolean) ((boolean) = !(boolean))
32 
33 // initialize globals
34 
35 #define SET(type, var)		type var = defaults::var
36 namespace globals {
37   SET(Rules, chart_rules);
38   SET(double, hr_mag_bright);
39   SET(double, hr_mag_dim);
40 #ifdef BROWSER
41   const
42 #endif
43   SET(std::string, program_help_browser);
44   SET(std::string, display_fontname);
45 
46   StarArray	    *chart_stararray	= NULL;
47   GTKViewer	    *program_viewer	= NULL;
48   GtkWidget	    *program_canvas	= NULL;
49   GtkWidget	    *program_status	= NULL;
50   GTKViewer         *program_hr_viewer  = NULL;
51   GtkWidget         *program_hr_canvas  = NULL;
52   GdkPixbuf	    *program_icon	= NULL;
53   GdkPixmap	    *program_pixmap	= NULL;
54 } // end "globals" namespace
55 
56 
redraw_display(GtkWidget * widget)57 void redraw_display(GtkWidget *widget)
58 {
59   if (globals::program_viewer && globals::chart_stararray) {
60     globals::chart_stararray->Display(globals::program_viewer);
61     gdk_draw_pixmap(widget->window,
62 		    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
63 		    globals::program_pixmap,
64 		    0, 0, 0, 0,
65 		    widget->allocation.width, widget->allocation.height);
66   }
67 }
68 
69 
70 /* Create a new backing pixmap of the appropriate size */
configure_event(GtkWidget * widget,GdkEventConfigure * event)71 static gint configure_event( GtkWidget         *widget,
72 			     GdkEventConfigure *event )
73 {
74   if (globals::program_pixmap) {
75     delete globals::program_viewer;
76     gdk_pixmap_unref (globals::program_pixmap);
77   }
78   globals::program_pixmap = gdk_pixmap_new(widget->window,
79 					   widget->allocation.width,
80 					   widget->allocation.height,
81 					   -1);
82   globals::program_viewer =
83     new GTKViewer(globals::program_pixmap, widget);
84   redraw_display(widget);
85   return true;
86 }
87 
88 
89 /* Redraw the screen from the backing pixmap */
expose_event(GtkWidget * widget,GdkEventExpose * event)90 static gint expose_event( GtkWidget      *widget,
91 			  GdkEventExpose *event )
92 {
93   gdk_draw_pixmap(widget->window,
94 		  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
95 		  globals::program_pixmap,
96 		  event->area.x, event->area.y,
97 		  event->area.x, event->area.y,
98 		  event->area.width, event->area.height);
99   return false;
100 }
101 
102 
redraw_all(star_changetype_t changetype)103 void redraw_all(star_changetype_t changetype)
104 {
105   globals::chart_stararray->SetRules(globals::chart_rules, changetype);
106   redraw_display(globals::program_canvas);
107   if (globals::program_hr_viewer)
108     hr_redraw_display(globals::program_hr_canvas);
109   if (globals::program_treeview)
110     update_info(globals::program_treeview);
111 
112   std::string statustext;
113   if (globals::chart_rules.ChartFileNames.size() == 1)
114     statustext = starstrings::ssprintf(_("Viewing %d of %d stars of %s"),
115 	globals::chart_stararray->size(),
116 	globals::chart_stararray->totalstars(),
117 	globals::chart_rules.ChartFileNames[0].c_str());
118   else
119     statustext = starstrings::ssprintf(_("Viewing %d of %d stars in %d files"),
120 	globals::chart_stararray->size(),
121 	globals::chart_stararray->totalstars(),
122 	globals::chart_rules.ChartFileNames.size());
123   gtk_label_set_text (GTK_LABEL (globals::program_status), statustext.c_str());
124 }
125 
126 
127 /* Function to respond to mouse clicks on the star chart.  A left-click
128  * will recenter the chart to the clicked star.  A right-click will pop up
129  * a mini-dialog box with some information about the star.  A left-click
130  * on a chart legend item will toggle the visibility of that spectral
131  * class.  If no star or legend item is near the mouse click location,
132  * nothing will happen.
133  */
button_press_event(GtkWidget * widget,GdkEventButton * event)134 static gint button_press_event( GtkWidget      *widget,
135 				GdkEventButton *event )
136 {
137   bool found = false;
138   int i;
139   gdouble X = event->x, Y = event->y;
140 
141   if (! (globals::program_pixmap && globals::chart_stararray)) return false;
142 
143   /* check for star legend item */
144   if (event->button == 1 && globals::chart_rules.ChartLegend) {
145     int xbase = (globals::program_viewer->width() > 100) ?
146 		globals::program_viewer->width() - 95 : 5;
147 
148     if (pow(X - (xbase + LEGEND_OFFSETS[10][0]), 2)
149     	+ pow(Y - LEGEND_OFFSETS[10][1], 2) < 25) {
150       FLIP(globals::chart_rules.StarClasses[0]);
151       redraw_all(FILTER_CHANGE);
152       return true;
153     }
154 
155     for (unsigned int i = 0; i < 10; i++) {
156       if (pow(X - (xbase + LEGEND_OFFSETS[i][0]), 2)
157           + pow(Y - LEGEND_OFFSETS[i][1], 2) < 25) {
158 	FLIP(globals::chart_rules.StarClasses[i]);
159 	redraw_all(FILTER_CHANGE);
160 	return true;
161       }
162     }
163   }
164 
165   /* if not a legend item, find the star that was clicked on */
166   for (i = globals::chart_stararray->size() - 1; i >= 0; i--) {
167     int x = (*globals::chart_stararray)[i].GetXPixel();
168     int y = (*globals::chart_stararray)[i].GetYPixel();
169     int r = (*globals::chart_stararray)[i].GetRPixel();
170 
171     // give the hotspot two pixels extra in radius to make it easier to
172     // click on stars --------------------------v
173     if (pow(X - x, 2) + pow(Y - y, 2) < pow(r + 2, 2)) {
174       found = true;
175       break;
176     }
177   }
178 
179   if (found) {
180     if (event->button == 1) {
181       /* recenter the chart on the clicked star */
182       globals::chart_rules.ChartLocation =
183 	(*globals::chart_stararray)[i].GetStarXYZ();
184       redraw_all(LOCATION_CHANGE);
185     }
186     else if (event->button == 3 || event->button == 2) {
187       /* display information about the star */
188       my_gtk_star_popup((*globals::chart_stararray)[i]);
189     }
190   }
191 
192   return true;
193 }
194 
195 
delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)196 gint delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
197 {
198   starplot_quit();
199   return false;
200 }
201 
202 
main(int argc,char * argv[])203 int main( int argc, char *argv[] )
204 {
205   GtkWidget *window;
206   GtkWidget *mainmenu;
207   GtkWidget *mainbox, *hbox, *statusbar;
208   GtkWidget *buttonbar;
209 
210   /* extract GTK command-line flags and set LC_ALL */
211   gtk_init(&argc, &argv);
212 
213   // Get starplot-specific command-line flags
214   // XXX: to do
215 
216   // set up i18n
217 
218   // This prevents the problem of having atof not deal well with en_US
219   // style decimal numbers in the data files.  Of course then all numbers
220   // are displayed in en_US style as well, so this isn't perfect...
221   setlocale(LC_NUMERIC, "C");
222   bindtextdomain (PACKAGE, LOCALEDIR);
223   // GTK+ 2 gets very angry if UTF-8 isn't used:
224   bind_textdomain_codeset (PACKAGE, "UTF-8");
225   textdomain (PACKAGE);
226 
227   // Set up the window icon
228   globals::program_icon = gdk_pixbuf_new_from_xpm_data (starplot_xpm);
229 
230   /* This sets the window title and border width: */
231   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
232   gtk_window_set_title (GTK_WINDOW (window), "StarPlot " STARPLOT_VERSION);
233   gtk_window_set_icon (GTK_WINDOW (window), globals::program_icon);
234   gtk_container_set_border_width (GTK_CONTAINER (window), 0);
235   my_gtk_main_menu (window, &mainmenu);
236   my_gtk_push_buttons (window, &buttonbar);
237 
238   /* Set a delete_event handler for ending the program */
239   g_signal_connect (G_OBJECT (window), "delete_event",
240 		      G_CALLBACK (delete_event), NULL);
241 
242   /* Set up the drawing area */
243   globals::program_canvas = gtk_drawing_area_new();
244   gtk_drawing_area_size (GTK_DRAWING_AREA (globals::program_canvas),
245 		          defaults::program_width,
246 			  defaults::program_height);
247   gtk_widget_show (globals::program_canvas);
248 
249   /* Signals used to handle backing pixmap */
250   g_signal_connect (G_OBJECT (globals::program_canvas), "expose_event",
251 		      G_CALLBACK (expose_event), NULL);
252   g_signal_connect (G_OBJECT (globals::program_canvas),"configure_event",
253 		      G_CALLBACK (configure_event), NULL);
254 
255   /* Event signals */
256   g_signal_connect (G_OBJECT (globals::program_canvas), "button_press_event",
257 		      G_CALLBACK (button_press_event), NULL);
258   gtk_widget_set_events (globals::program_canvas, GDK_EXPOSURE_MASK
259 			 | GDK_LEAVE_NOTIFY_MASK
260 			 | GDK_BUTTON_PRESS_MASK
261 			 | GDK_POINTER_MOTION_MASK
262 			 | GDK_POINTER_MOTION_HINT_MASK);
263 
264   hbox = gtk_hbox_new (false, 0);
265   gtk_widget_show (hbox);
266   gtk_box_pack_start (GTK_BOX (hbox), buttonbar, false, true, 0);
267   gtk_box_pack_start (GTK_BOX (hbox), globals::program_canvas, true, true, 0);
268 
269   globals::program_status = gtk_label_new ("");
270   gtk_misc_set_alignment (GTK_MISC (globals::program_status), 0.0F, 0.0F);
271   gtk_widget_show (globals::program_status);
272   statusbar = gtk_frame_new (0);
273   gtk_frame_set_shadow_type (GTK_FRAME (statusbar), GTK_SHADOW_OUT);
274   gtk_widget_show (statusbar);
275   gtk_container_add (GTK_CONTAINER (statusbar), globals::program_status);
276 
277   mainbox = gtk_vbox_new (false, 0);
278   gtk_container_border_width (GTK_CONTAINER (mainbox), 1);
279   gtk_container_add (GTK_CONTAINER (window), mainbox);
280   gtk_box_pack_start (GTK_BOX (mainbox), mainmenu, false, true, 0);
281   gtk_box_pack_start (GTK_BOX (mainbox), hbox, true, true, 0);
282   gtk_box_pack_start (GTK_BOX (mainbox), statusbar, false, true, 0);
283 
284   globals::chart_stararray = new StarArray();
285   gtk_widget_realize (globals::program_canvas);
286 
287   /* load settings from starplot RC file, if it exists */
288   read_rc_file();
289 
290   /* assume any command-line arguments are data files to use */
291   if (argc > 1) {
292     globals::chart_rules.ChartFileNames = StringList(1, argv[1]);
293     for (int i = 2; i < argc; i++)
294       globals::chart_rules.ChartFileNames.push_back(argv[i]);
295   }
296 
297   gtk_widget_modify_font (GTK_WIDGET (globals::program_canvas),
298     pango_font_description_from_string (globals::display_fontname.c_str()));
299   redraw_all(FILE_CHANGE);
300 
301   gtk_widget_show (globals::program_canvas);
302   gtk_widget_show (mainmenu);
303   gtk_widget_show (buttonbar);
304   gtk_widget_show (mainbox);
305   gtk_widget_show (window);
306 
307   gtk_main ();
308   return 0;
309 }
310 
311