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