aboutsummaryrefslogtreecommitdiff
path: root/src/dw-hdfsee.c
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2011-03-01 14:52:47 +0100
committerThomas White <taw@physics.org>2012-02-22 15:27:16 +0100
commitd57837bdbc8a149bddb944ba7d125fafa70eb6fc (patch)
tree21a02772628aa5174bc60d2b5b79e11290408e5d /src/dw-hdfsee.c
parent8e8cd379cb9cb82b70d8a0de70543ff09840edf5 (diff)
Rename displaywindow.{c,h} -> dw-hdfsee.{c,h}, remove dw-geomatic.{c,h}
Diffstat (limited to 'src/dw-hdfsee.c')
-rw-r--r--src/dw-hdfsee.c1573
1 files changed, 1573 insertions, 0 deletions
diff --git a/src/dw-hdfsee.c b/src/dw-hdfsee.c
new file mode 100644
index 00000000..9c42bf5b
--- /dev/null
+++ b/src/dw-hdfsee.c
@@ -0,0 +1,1573 @@
+/*
+ * dw-hdfsee.c
+ *
+ * Quick yet non-crappy HDF viewer
+ *
+ * (c) 2006-2010 Thomas White <taw@physics.org>
+ *
+ * Part of CrystFEL - crystallography with a FEL
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "dw-hdfsee.h"
+#include "render.h"
+#include "hdf5-file.h"
+#include "hdfsee.h"
+#include "utils.h"
+#include "detector.h"
+
+
+static void displaywindow_error(DisplayWindow *dw, const char *message)
+{
+ GtkWidget *window;
+
+ window = gtk_message_dialog_new(GTK_WINDOW(dw->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE, message);
+ gtk_window_set_title(GTK_WINDOW(window), "Error");
+
+ g_signal_connect_swapped(window, "response",
+ G_CALLBACK(gtk_widget_destroy), window);
+ gtk_widget_show(window);
+}
+
+
+static void displaywindow_update(DisplayWindow *dw)
+{
+ gint width;
+ GdkGeometry geom;
+
+ if ( dw->image == NULL ) {
+ dw->width = 320;
+ dw->height = 320;
+ } else {
+
+ double min_x, min_y, max_x, max_y;
+
+ get_pixel_extents(dw->image->det,
+ &min_x, &min_y, &max_x, &max_y);
+
+ if ( min_x > 0.0 ) min_x = 0.0;
+ if ( max_x < 0.0 ) max_x = 0.0;
+ if ( min_y > 0.0 ) min_y = 0.0;
+ if ( max_y < 0.0 ) max_y = 0.0;
+ dw->min_x = min_x;
+ dw->max_x = max_x;
+ dw->min_y = min_y;
+ dw->max_y = max_y;
+
+ dw->width = (max_x - min_x) / dw->binning;
+ dw->height = (max_y - min_y) / dw->binning;
+
+ /* Add a thin border */
+ dw->width += 2.0;
+ dw->height += 2.0;
+ }
+
+ width = dw->width;
+ if ( dw->show_col_scale ) width += 20;
+
+ gtk_widget_set_size_request(GTK_WIDGET(dw->drawingarea), width,
+ dw->height);
+ geom.min_width = -1;
+ geom.min_height = -1;
+ geom.max_width = -1;
+ geom.max_height = -1;
+ gtk_window_set_geometry_hints(GTK_WINDOW(dw->window),
+ GTK_WIDGET(dw->drawingarea), &geom,
+ GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
+
+ /* Free old pixbufs */
+ if ( dw->pixbufs != NULL ) {
+ int i;
+ for ( i=0; i<dw->n_pixbufs; i++ ) {
+ gdk_pixbuf_unref(dw->pixbufs[i]);
+ }
+ free(dw->pixbufs);
+ }
+ if ( dw->col_scale != NULL ) {
+ gdk_pixbuf_unref(dw->col_scale);
+ }
+
+ if ( dw->image != NULL ) {
+ dw->pixbufs = render_panels(dw->image, dw->binning,
+ dw->scale, dw->boostint,
+ &dw->n_pixbufs);
+ } else {
+ dw->pixbufs = NULL;
+ }
+
+ dw->col_scale = render_get_colour_scale(20, dw->height, dw->scale);
+
+ /* Schedule redraw */
+ gdk_window_invalidate_rect(dw->drawingarea->window, NULL, FALSE);
+}
+
+
+/* Window closed - clean up */
+static gint displaywindow_closed(GtkWidget *window, DisplayWindow *dw)
+{
+ if ( dw->hdfile != NULL ) {
+ hdfile_close(dw->hdfile);
+ }
+
+ /* Notify 'main', so it can update the master list */
+ hdfsee_window_closed(dw);
+
+ return 0;
+}
+
+
+static double ring_radius(struct image *image, double d)
+{
+ double theta, r, r_px;
+
+ theta = asin(image->lambda / (2.0*d));
+ r = image->det->panels[0].clen * tan(2.0*theta);
+ r_px = r * image->det->panels[0].res;
+
+ return r_px;
+}
+
+
+static void show_ring(cairo_t *cr, DisplayWindow *dw,
+ double d, const char *label)
+{
+ cairo_identity_matrix(cr);
+ cairo_translate(cr, -dw->min_x/dw->binning, dw->max_y/dw->binning);
+ cairo_arc(cr, 0.0, 0.0, ring_radius(dw->image, d)/dw->binning,
+ 0.0, 2.0*M_PI);
+ cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
+ cairo_set_line_width(cr, 1.0);
+ cairo_stroke(cr);
+ cairo_rotate(cr, -M_PI/4.0);
+ cairo_translate(cr, 0.0,
+ ring_radius(dw->image, d)/dw->binning-5.0);
+ cairo_set_font_size(cr, 20.0);
+ cairo_show_text(cr, label);
+ cairo_fill(cr);
+}
+
+
+static int draw_stuff(cairo_surface_t *surf, DisplayWindow *dw)
+{
+ cairo_t *cr;
+ int i;
+ cairo_matrix_t basic_m;
+ cairo_matrix_t m;
+
+ cr = cairo_create(surf);
+
+ /* Blank white background */
+ cairo_rectangle(cr, 0.0, 0.0, dw->width, dw->height);
+ cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+ cairo_fill(cr);
+
+ if ( dw->image == NULL ) return 0;
+
+ /* Set up basic coordinate system
+ * - origin in the centre, y upwards. */
+ cairo_identity_matrix(cr);
+ cairo_matrix_init(&m, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
+ cairo_translate(cr, -dw->min_x/dw->binning, dw->max_y/dw->binning);
+ cairo_transform(cr, &m);
+ cairo_get_matrix(cr, &basic_m);
+
+ if ( dw->pixbufs != NULL ) {
+
+ int i;
+
+ for ( i=0; i<dw->image->det->n_panels; i++ ) {
+
+ struct panel p = dw->image->det->panels[i];
+ int w = gdk_pixbuf_get_width(dw->pixbufs[i]);
+ int h = gdk_pixbuf_get_height(dw->pixbufs[i]);
+ cairo_matrix_t m;
+
+ /* Start with the basic coordinate system */
+ cairo_set_matrix(cr, &basic_m);
+
+ /* Move to the right location */
+ cairo_translate(cr, p.cnx/dw->binning,
+ p.cny/dw->binning);
+
+ /* Twiddle directions according to matrix */
+ cairo_matrix_init(&m, p.fsx, p.fsy, p.ssx, p.ssy,
+ 0.0, 0.0);
+ cairo_transform(cr, &m);
+
+ gdk_cairo_set_source_pixbuf(cr, dw->pixbufs[i],
+ 0.0, 0.0);
+ cairo_rectangle(cr, 0.0, 0.0, w, h);
+ cairo_fill(cr);
+
+ }
+
+ }
+
+ if ( (dw->show_col_scale) && (dw->col_scale != NULL) ) {
+ cairo_identity_matrix(cr);
+ cairo_translate(cr, dw->width, 0.0);
+ cairo_rectangle(cr, 0.0, 0.0, 20.0, dw->height);
+ gdk_cairo_set_source_pixbuf(cr, dw->col_scale, 0.0, 0.0);
+ cairo_fill(cr);
+ }
+
+ if ( dw->show_rings ) {
+
+ /* Mark the beam */
+ cairo_set_matrix(cr, &basic_m);
+ cairo_arc(cr, 0.0, 0.0, 5.0/dw->binning, 0.0, 2.0*M_PI);
+ cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
+ cairo_fill(cr);
+
+ /* Draw resolution circles */
+ show_ring(cr, dw, 10.0e-10, "10A");
+ show_ring(cr, dw, 8.0e-10, "8A");
+ show_ring(cr, dw, 5.0e-10, "5A");
+ show_ring(cr, dw, 4.0e-10, "4A");
+ show_ring(cr, dw, 3.0e-10, "3A");
+ show_ring(cr, dw, 2.0e-10, "2A");
+ show_ring(cr, dw, 1.0e-10, "1A");
+
+ }
+
+ if ( dw->image->features == NULL ) {
+ cairo_destroy(cr);
+ return 0;
+ }
+
+ /* Ensure a clean Cairo context, since the rings often cause
+ * matrix trouble */
+ cairo_destroy(cr);
+ cr = cairo_create(surf);
+
+ cairo_set_matrix(cr, &basic_m);
+ for ( i=0; i<image_feature_count(dw->image->features); i++ ) {
+
+ double fs, ss;
+ double x, y, xs, ys;
+ struct imagefeature *f;
+ struct panel *p;
+
+ f = image_get_feature(dw->image->features, i);
+ if ( f == NULL ) continue;
+
+ fs = f->x;
+ ss = f->y;
+
+ p = find_panel(dw->image->det, fs, ss);
+ if ( p == NULL ) continue;
+
+ xs = (fs-p->min_fs)*p->fsx + (ss-p->min_ss)*p->ssx;
+ ys = (fs-p->min_fs)*p->fsy + (ss-p->min_ss)*p->ssy;
+ x = xs + p->cnx;
+ y = ys + p->cny;
+
+ cairo_arc(cr, x/dw->binning, y/dw->binning,
+ 7.0/dw->binning, 0.0, 2.0*M_PI);
+ switch ( dw->scale ) {
+
+ case SCALE_COLOUR :
+ cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
+ break;
+
+ case SCALE_MONO :
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ break;
+
+ case SCALE_INVMONO:
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ break;
+
+ }
+
+ cairo_set_line_width(cr, 0.75);
+ cairo_stroke(cr);
+
+ }
+
+ cairo_destroy(cr);
+
+ return 0;
+}
+
+
+static gboolean displaywindow_expose(GtkWidget *da, GdkEventExpose *event,
+ DisplayWindow *dw)
+{
+ cairo_t *cr;
+ cairo_surface_t *surf;
+
+ cr = gdk_cairo_create(da->window);
+ surf = cairo_get_target(cr);
+ draw_stuff(surf, dw);
+ cairo_destroy(cr);
+
+ return FALSE;
+}
+
+
+static int write_png(const char *filename, DisplayWindow *dw)
+{
+ cairo_status_t r;
+ cairo_t *cr;
+ cairo_surface_t *surf;
+
+ surf = gdk_window_create_similar_surface(dw->drawingarea->window,
+ CAIRO_CONTENT_COLOR,
+ dw->width, dw->height);
+
+ draw_stuff(surf, dw);
+
+ r = cairo_surface_write_to_png(surf, filename);
+ if ( r != CAIRO_STATUS_SUCCESS ) return 1;
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surf);
+
+ return 0;
+}
+
+
+static gint displaywindow_close(GtkWidget *widget, DisplayWindow *dw)
+{
+ gtk_widget_destroy(dw->window);
+ return 0;
+}
+
+
+static gint displaywindow_set_binning_response(GtkWidget *widget, gint response,
+ DisplayWindow *dw)
+{
+ int done = 1;
+
+ if ( response == GTK_RESPONSE_OK ) {
+
+ const char *sbinning;
+ unsigned int binning;
+ int scanval;
+
+ sbinning = gtk_entry_get_text(
+ GTK_ENTRY(dw->binning_dialog->entry));
+ scanval = sscanf(sbinning, "%u", &binning);
+ if ( (scanval != 1) || (binning <= 0) ) {
+ displaywindow_error(dw,
+ "Please enter a positive integer for the "
+ "binning factor.");
+ done = 0;
+ } else {
+ if ((binning < dw->image->width/10)
+ && (binning < dw->image->height/10)) {
+ dw->binning = binning;
+ displaywindow_update(dw);
+ } else {
+ displaywindow_error(dw,
+ "Please enter a sensible value for "
+ "the binning factor.");
+ done = 0;
+ }
+ }
+ }
+
+ if ( done ) {
+ gtk_widget_destroy(dw->binning_dialog->window);
+ }
+
+ return 0;
+
+}
+
+
+static gint displaywindow_set_binning_destroy(GtkWidget *widget,
+ DisplayWindow *dw)
+{
+ free(dw->binning_dialog);
+ dw->binning_dialog = NULL;
+ return 0;
+}
+
+
+static gint displaywindow_set_binning_response_ac(GtkWidget *widget,
+ DisplayWindow *dw)
+{
+ return displaywindow_set_binning_response(widget, GTK_RESPONSE_OK, dw);
+}
+
+
+/* Create a window to ask the user for a new binning factor */
+static gint displaywindow_set_binning(GtkWidget *widget, DisplayWindow *dw)
+{
+ BinningDialog *bd;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *table;
+ GtkWidget *label;
+ char tmp[64];
+
+ if ( dw->binning_dialog != NULL ) {
+ return 0;
+ }
+
+ if ( dw->hdfile == NULL ) {
+ return 0;
+ }
+
+ bd = malloc(sizeof(BinningDialog));
+ if ( bd == NULL ) return 0;
+ dw->binning_dialog = bd;
+
+ bd->window = gtk_dialog_new_with_buttons("Set Binning",
+ GTK_WINDOW(dw->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(bd->window)->vbox),
+ GTK_WIDGET(hbox), FALSE, FALSE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 5);
+
+ table = gtk_table_new(3, 2, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, FALSE, 0);
+
+ label = gtk_label_new("Smaller numbers mean larger images on screen");
+ gtk_label_set_markup(GTK_LABEL(label),
+ "<span style=\"italic\" weight=\"light\">"
+ "Smaller numbers mean larger images on screen</span>");
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(label),
+ 1, 3, 1, 2);
+
+ snprintf(tmp, 63, "Raw image size: %i by %i pixels",
+ dw->image->width, dw->image->height);
+ label = gtk_label_new(tmp);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(label),
+ 1, 3, 2, 3);
+
+ label = gtk_label_new("Binning Factor:");
+ gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(label),
+ 1, 2, 3, 4);
+
+ bd->entry = gtk_entry_new();
+ snprintf(tmp, 63, "%i", dw->binning);
+ gtk_entry_set_text(GTK_ENTRY(bd->entry), tmp);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(bd->entry),
+ 2, 3, 3, 4);
+
+ g_signal_connect(G_OBJECT(bd->entry), "activate",
+ G_CALLBACK(displaywindow_set_binning_response_ac), dw);
+ g_signal_connect(G_OBJECT(bd->window), "response",
+ G_CALLBACK(displaywindow_set_binning_response), dw);
+ g_signal_connect(G_OBJECT(bd->window), "destroy",
+ G_CALLBACK(displaywindow_set_binning_destroy), dw);
+ gtk_window_set_resizable(GTK_WINDOW(bd->window), FALSE);
+ gtk_widget_show_all(bd->window);
+ gtk_widget_grab_focus(GTK_WIDGET(bd->entry));
+
+ return 0;
+}
+
+
+static gint displaywindow_set_boostint_response(GtkWidget *widget,
+ gint response,
+ DisplayWindow *dw)
+{
+ int done = 1;
+
+ if ( response == GTK_RESPONSE_OK ) {
+
+ const char *sboostint;
+ float boostint;
+ int scanval;
+
+ sboostint = gtk_entry_get_text(
+ GTK_ENTRY(dw->boostint_dialog->entry));
+ scanval = sscanf(sboostint, "%f", &boostint);
+ if ( (scanval != 1) || (boostint <= 0) ) {
+ displaywindow_error(dw, "Please enter a positive "
+ "number for the intensity boost "
+ "factor.");
+ done = 0;
+ } else {
+ dw->boostint = boostint;
+ displaywindow_update(dw);
+ }
+ }
+
+ if ( done ) {
+ gtk_widget_destroy(dw->boostint_dialog->window);
+ }
+
+ return 0;
+}
+
+
+static gint displaywindow_set_boostint_destroy(GtkWidget *widget,
+ DisplayWindow *dw)
+{
+ free(dw->boostint_dialog);
+ dw->boostint_dialog = NULL;
+ return 0;
+}
+
+
+static gint displaywindow_set_boostint_response_ac(GtkWidget *widget,
+ DisplayWindow *dw)
+{
+ return displaywindow_set_boostint_response(widget, GTK_RESPONSE_OK, dw);
+}
+
+
+/* Create a window to ask the user for a new intensity boost factor */
+static gint displaywindow_set_boostint(GtkWidget *widget, DisplayWindow *dw)
+{
+ BoostIntDialog *bd;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *table;
+ GtkWidget *label;
+ char tmp[64];
+
+ if ( dw->boostint_dialog != NULL ) {
+ return 0;
+ }
+
+ if ( dw->hdfile == NULL ) {
+ return 0;
+ }
+
+ bd = malloc(sizeof(BoostIntDialog));
+ if ( bd == NULL ) return 0;
+ dw->boostint_dialog = bd;
+
+ bd->window = gtk_dialog_new_with_buttons("Intensity Boost",
+ GTK_WINDOW(dw->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(bd->window)->vbox),
+ GTK_WIDGET(hbox), FALSE, FALSE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 5);
+
+ table = gtk_table_new(3, 2, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, FALSE, 0);
+
+ label = gtk_label_new("Boost Factor:");
+ gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(label),
+ 1, 2, 3, 4);
+
+ bd->entry = gtk_entry_new();
+ snprintf(tmp, 63, "%.2f", dw->boostint);
+ gtk_entry_set_text(GTK_ENTRY(bd->entry), tmp);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(bd->entry),
+ 2, 3, 3, 4);
+
+ g_signal_connect(G_OBJECT(bd->entry), "activate",
+ G_CALLBACK(displaywindow_set_boostint_response_ac),
+ dw);
+ g_signal_connect(G_OBJECT(bd->window), "response",
+ G_CALLBACK(displaywindow_set_boostint_response), dw);
+ g_signal_connect(G_OBJECT(bd->window), "destroy",
+ G_CALLBACK(displaywindow_set_boostint_destroy), dw);
+ gtk_window_set_resizable(GTK_WINDOW(bd->window), FALSE);
+ gtk_widget_show_all(bd->window);
+ gtk_widget_grab_focus(GTK_WIDGET(bd->entry));
+
+ return 0;
+}
+
+
+static void load_features_from_file(struct image *image, const char *filename)
+{
+ FILE *fh;
+ char *rval;
+
+ fh = fopen(filename, "r");
+ if ( fh == NULL ) return;
+
+ if ( image->features != NULL ) {
+ image_feature_list_free(image->features);
+ }
+ image->features = image_feature_list_new();
+
+ do {
+ char line[1024];
+ float x, y, df;
+ int r;
+ signed int h, k, l;
+
+ rval = fgets(line, 1023, fh);
+ if ( rval == NULL ) continue;
+ chomp(line);
+
+ /* Try long format (output of pattern_sim --near-bragg) */
+ r = sscanf(line, "%i %i %i %f (at %f,%f)",
+ &h, &k, &l, &df, &x, &y);
+ if ( r == 6 ) {
+ char name[32];
+ snprintf(name, 31, "%i %i %i", h, k, l);
+ image_add_feature(image->features, x, y, image, 1.0,
+ strdup(name));
+ continue;
+ }
+
+ r = sscanf(line, "%f %f", &x, &y);
+ if ( r != 2 ) continue;
+
+ image_add_feature(image->features, x, y, image, 1.0, NULL);
+
+ } while ( rval != NULL );
+}
+
+
+static gint displaywindow_peaklist_response(GtkWidget *d, gint response,
+ DisplayWindow *dw)
+{
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
+
+ load_features_from_file(dw->image, filename);
+ displaywindow_update(dw);
+
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(d);
+
+ return 0;
+}
+
+
+static gint displaywindow_about(GtkWidget *widget, DisplayWindow *dw)
+{
+ GtkWidget *window;
+
+ const gchar *authors[] = {
+ "Thomas White <taw@physics.org>",
+ NULL
+ };
+
+ window = gtk_about_dialog_new();
+ gtk_window_set_transient_for(GTK_WINDOW(window),
+ GTK_WINDOW(dw->window));
+
+ gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(window), "hdfsee");
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window), PACKAGE_VERSION);
+ gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window),
+ "(c) 2006-2011 Thomas White <taw@physics.org> and others");
+ gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window),
+ "Quick viewer for HDF files");
+ gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(window),
+ "(c) 2006-2011 Thomas White <taw@physics.org>\n");
+ gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window),
+ "http://www.bitwiz.org.uk/");
+ gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors);
+
+ g_signal_connect(window, "response", G_CALLBACK(gtk_widget_destroy),
+ NULL);
+
+ gtk_widget_show_all(window);
+
+ return 0;
+}
+
+
+static int load_geometry_file(DisplayWindow *dw, struct image *image,
+ const char *filename)
+{
+ struct detector *geom;
+ GtkWidget *w;
+
+ geom = get_detector_geometry(filename);
+ if ( geom == NULL ) {
+ displaywindow_error(dw, "Failed to load geometry file");
+ return -1;
+ }
+ fill_in_values(geom, dw->hdfile);
+
+ if ( (1+geom->max_fs != dw->image->width)
+ || (1+geom->max_ss != dw->image->height) ) {
+
+ displaywindow_error(dw, "Geometry doesn't match image.");
+ return -1;
+
+ }
+
+ if ( dw->loaded_geom != NULL ) free_detector_geometry(dw->loaded_geom);
+ dw->loaded_geom = geom;
+
+ w = gtk_ui_manager_get_widget(dw->ui,
+ "/ui/displaywindow/view/usegeom");
+ gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE);
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), TRUE);
+ dw->use_geom = 1;
+
+ return 0;
+}
+
+
+static gint displaywindow_loadgeom_response(GtkWidget *d, gint response,
+ DisplayWindow *dw)
+{
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
+
+ if ( load_geometry_file(dw, dw->image, filename) == 0 ) {
+ displaywindow_update(dw);
+ }
+
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(d);
+
+ return 0;
+}
+
+
+static gint displaywindow_load_geom(GtkWidget *widget, DisplayWindow *dw)
+{
+ GtkWidget *d;
+
+ d = gtk_file_chooser_dialog_new("Load Geometry File",
+ GTK_WINDOW(dw->window),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ g_signal_connect(G_OBJECT(d), "response",
+ G_CALLBACK(displaywindow_loadgeom_response), dw);
+
+ gtk_widget_show_all(d);
+
+ return 0;
+}
+
+
+static gint displaywindow_peak_overlay(GtkWidget *widget, DisplayWindow *dw)
+{
+ GtkWidget *d;
+
+ d = gtk_file_chooser_dialog_new("Choose Peak List",
+ GTK_WINDOW(dw->window),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ g_signal_connect(G_OBJECT(d), "response",
+ G_CALLBACK(displaywindow_peaklist_response), dw);
+
+ gtk_widget_show_all(d);
+
+ return 0;
+}
+
+
+static gint displaywindow_set_usegeom(GtkWidget *d, DisplayWindow *dw)
+{
+ GtkWidget *w;
+
+ /* Get new value */
+ w = gtk_ui_manager_get_widget(dw->ui,
+ "/ui/displaywindow/view/usegeom");
+ dw->use_geom = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
+
+ if ( dw->use_geom ) {
+ dw->image->det = dw->loaded_geom;
+ } else {
+ dw->image->det = dw->simple_geom;
+ }
+
+ displaywindow_update(dw);
+
+ return 0;
+}
+
+
+static gint displaywindow_set_rings(GtkWidget *d, DisplayWindow *dw)
+{
+ GtkWidget *w;
+
+ /* Get new value */
+ w = gtk_ui_manager_get_widget(dw->ui,
+ "/ui/displaywindow/view/rings");
+ dw->show_rings = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
+
+ gdk_window_invalidate_rect(dw->drawingarea->window, NULL, FALSE);
+
+ return 0;
+}
+
+
+struct savedialog {
+ DisplayWindow *dw;
+ GtkWidget *cb;
+};
+
+
+static gint displaywindow_save_response(GtkWidget *d, gint response,
+ struct savedialog *cd)
+{
+ DisplayWindow *dw = cd->dw;
+ int r;
+
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *file;
+ int type;
+
+ file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
+
+ type = gtk_combo_box_get_active(GTK_COMBO_BOX(cd->cb));
+
+ if ( type == 0 ) {
+ r = write_png(file, dw);
+ } else if ( type == 1 ) {
+ r = render_tiff_fp(dw->image, file);
+ } else if ( type == 2 ) {
+ r = render_tiff_int16(dw->image, file, dw->boostint);
+ } else {
+ r = -1;
+ }
+
+ if ( r != 0 ) {
+ displaywindow_error(dw, "Unable to save the image.");
+ }
+
+ g_free(file);
+
+ }
+
+ gtk_widget_destroy(d);
+ free(cd);
+
+ return 0;
+}
+
+
+static gint displaywindow_save(GtkWidget *widget, DisplayWindow *dw)
+{
+ GtkWidget *d, *hbox, *l, *cb;
+ struct savedialog *cd;
+
+ d = gtk_file_chooser_dialog_new("Save Image",
+ GTK_WINDOW(dw->window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d),
+ TRUE);
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(d), hbox);
+ cb = gtk_combo_box_new_text();
+ gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(cb), TRUE, TRUE, 5);
+ l = gtk_label_new("Save as type:");
+ gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(l), FALSE, FALSE, 5);
+
+ gtk_combo_box_append_text(GTK_COMBO_BOX(cb),
+ "PNG - 8 bit RGB (colour, binned, filtered, boosted)");
+ gtk_combo_box_append_text(GTK_COMBO_BOX(cb),
+ "TIFF - Floating point (mono, unbinned, filtered, not boosted)");
+ gtk_combo_box_append_text(GTK_COMBO_BOX(cb),
+ "TIFF - 16 bit signed integer "
+ "(mono, unbinned, filtered, boosted)");
+ gtk_combo_box_set_active(GTK_COMBO_BOX(cb), 0);
+
+ cd = malloc(sizeof(*cd));
+ cd->dw = dw;
+ cd->cb = cb;
+
+ g_signal_connect(G_OBJECT(d), "response",
+ G_CALLBACK(displaywindow_save_response), cd);
+
+ gtk_widget_show_all(d);
+
+ return 0;
+}
+
+
+static gint displaywindow_set_colscale(GtkWidget *widget, DisplayWindow *dw)
+{
+ dw->show_col_scale = 1 - dw->show_col_scale;
+ displaywindow_update(dw);
+ return 0;
+}
+
+
+static gint displaywindow_numbers_response(GtkWidget *widget,
+ gint response, DisplayWindow *dw)
+{
+ gtk_widget_destroy(dw->numbers_window->window);
+ return 0;
+}
+
+
+static gint displaywindow_numbers_destroy(GtkWidget *widget, DisplayWindow *dw)
+{
+ free(dw->numbers_window);
+ dw->numbers_window = NULL;
+ return 0;
+}
+
+
+static gint displaywindow_show_numbers(GtkWidget *widget, DisplayWindow *dw)
+{
+ struct numberswindow *nw;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *hbox2;
+ GtkWidget *table;
+ GtkWidget *label;
+ unsigned int x, y;
+
+ if ( dw->numbers_window != NULL ) {
+ return 0;
+ }
+
+ if ( dw->hdfile == NULL ) {
+ return 0;
+ }
+
+ nw = malloc(sizeof(struct numberswindow));
+ if ( nw == NULL ) return 0;
+ dw->numbers_window = nw;
+
+ nw->window = gtk_dialog_new_with_buttons("Numbers",
+ GTK_WINDOW(dw->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+ NULL);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(nw->window)->vbox),
+ GTK_WIDGET(hbox), FALSE, FALSE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), FALSE, FALSE, 5);
+
+ table = gtk_table_new(17, 17, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 5);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), FALSE, FALSE, 0);
+
+ for ( x=0; x<17; x++ ) {
+ for ( y=0; y<17; y++ ) {
+
+ GtkWidget *label;
+
+ label = gtk_label_new("--");
+ gtk_widget_set_size_request(GTK_WIDGET(label), 40, -1);
+
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(label),
+ x, x+1, y, y+1);
+
+ nw->labels[x+17*y] = label;
+
+ }
+ }
+
+ hbox2 = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox2), FALSE, FALSE, 5);
+ label = gtk_label_new("Feature:");
+ gtk_box_pack_start(GTK_BOX(hbox2), GTK_WIDGET(label), FALSE, FALSE, 5);
+ nw->feat = gtk_label_new("-");
+ gtk_box_pack_start(GTK_BOX(hbox2), GTK_WIDGET(nw->feat), FALSE, FALSE, 5);
+
+ g_signal_connect(G_OBJECT(nw->window), "response",
+ G_CALLBACK(displaywindow_numbers_response), dw);
+ g_signal_connect(G_OBJECT(nw->window), "destroy",
+ G_CALLBACK(displaywindow_numbers_destroy), dw);
+ gtk_window_set_resizable(GTK_WINDOW(nw->window), FALSE);
+
+ gtk_widget_show_all(nw->window);
+
+ return 0;
+}
+
+
+static void numbers_update(DisplayWindow *dw)
+{
+ int px, py;
+ int imin;
+ double dmin;
+ struct imagefeature *f;
+
+ for ( px=0; px<17; px++ ) {
+ for ( py=0; py<17; py++ ) {
+
+ char s[32];
+ float val;
+ GtkWidget *l;
+ int x, y;
+ int invalid;
+ double dfs, dss;
+ int fs, ss;
+
+ x = dw->binning * dw->numbers_window->cx + (px-8);
+ y = dw->binning * dw->numbers_window->cy + (17-py-8);
+ x += dw->min_x;
+ y += dw->min_y;
+
+ /* Map from unbinned mapped pixel coordinates to a panel */
+ invalid = reverse_2d_mapping(x, y, &dfs, &dss, dw->image->det);
+ fs = dfs; ss = dss;
+ if ( !invalid ) {
+ val = dw->image->data[fs+ss*dw->image->width];
+ }
+
+ if ( !invalid ) {
+ if ( val > 0.0 ) {
+ if ( log(val)/log(10.0) < 5 ) {
+ snprintf(s, 31, "%.0f", val);
+ } else {
+ snprintf(s, 31, "HUGE");
+ }
+ } else {
+ if ( log(-val)/log(10) < 4 ) {
+ snprintf(s, 31, "%.0f", val);
+ } else {
+ snprintf(s, 31, "-HUGE");
+ }
+ }
+ } else {
+ strcpy(s, "-");
+ }
+ l = dw->numbers_window->labels[px+17*py];
+ gtk_label_set_text(GTK_LABEL(l), s);
+
+ }
+ }
+
+ if ( dw->image->features == NULL ) return;
+
+ f = image_feature_closest(dw->image->features,
+ dw->binning * dw->numbers_window->cx,
+ dw->binning * dw->numbers_window->cy,
+ &dmin, &imin);
+ if ( dmin < 20.0 ) {
+ gtk_label_set_text(GTK_LABEL(dw->numbers_window->feat),
+ f->name);
+ } else {
+ gtk_label_set_text(GTK_LABEL(dw->numbers_window->feat),
+ "-");
+ }
+}
+
+
+static void displaywindow_addui_callback(GtkUIManager *ui, GtkWidget *widget,
+ GtkContainer *container)
+{
+ gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0);
+
+ /* Enable overflow menu if this is a toolbar */
+ if ( GTK_IS_TOOLBAR(widget) ) {
+ gtk_toolbar_set_show_arrow(GTK_TOOLBAR(widget), TRUE);
+ }
+}
+
+
+static gint displaywindow_setscale(GtkWidget *widget, GtkRadioAction *action,
+ DisplayWindow *dw)
+{
+ switch ( gtk_radio_action_get_current_value(action) )
+ {
+ case 0 : dw->scale = SCALE_COLOUR; break;
+ case 1 : dw->scale = SCALE_MONO; break;
+ case 2 : dw->scale = SCALE_INVMONO; break;
+ }
+ displaywindow_update(dw);
+
+ return 0;
+}
+
+
+static void displaywindow_addmenubar(DisplayWindow *dw, GtkWidget *vbox,
+ int colscale)
+{
+ GError *error = NULL;
+ GtkActionEntry entries[] = {
+
+ { "FileAction", NULL, "_File", NULL, NULL, NULL },
+ { "SaveAction", GTK_STOCK_SAVE, "Save Image...", NULL, NULL,
+ G_CALLBACK(displaywindow_save) },
+ { "CloseAction", GTK_STOCK_CLOSE, "_Close", NULL, NULL,
+ G_CALLBACK(displaywindow_close) },
+
+ { "ViewAction", NULL, "_View", NULL, NULL, NULL },
+ { "ImagesAction", NULL, "Images", NULL, NULL, NULL },
+ { "BinningAction", NULL, "Set Binning...", "F3", NULL,
+ G_CALLBACK(displaywindow_set_binning) },
+ { "BoostIntAction", NULL, "Boost Intensity...", "F5", NULL,
+ G_CALLBACK(displaywindow_set_boostint) },
+
+ { "ToolsAction", NULL, "_Tools", NULL, NULL, NULL },
+ { "NumbersAction", NULL, "View Numbers...", "F2", NULL,
+ G_CALLBACK(displaywindow_show_numbers) },
+ { "PeaksAction", NULL, "Peak Position Overlay...", NULL, NULL,
+ G_CALLBACK(displaywindow_peak_overlay) },
+ { "LoadGeomAction", NULL, "Load Geometry File...", NULL, NULL,
+ G_CALLBACK(displaywindow_load_geom) },
+
+ { "HelpAction", NULL, "_Help", NULL, NULL, NULL },
+ { "AboutAction", GTK_STOCK_ABOUT, "_About hdfsee...",
+ NULL, NULL,
+ G_CALLBACK(displaywindow_about) },
+
+ };
+ guint n_entries = G_N_ELEMENTS(entries);
+
+ GtkToggleActionEntry toggles[] = {
+ { "ColScaleAction", NULL, "Show Colour Scale", NULL, NULL,
+ G_CALLBACK(displaywindow_set_colscale), FALSE },
+ { "GeometryAction", NULL, "Use Detector Geometry", NULL, NULL,
+ G_CALLBACK(displaywindow_set_usegeom), FALSE },
+ { "RingsAction", NULL, "Show Resolution Rings", NULL, NULL,
+ G_CALLBACK(displaywindow_set_rings), dw->show_rings },
+ };
+ guint n_toggles = G_N_ELEMENTS(toggles);
+ GtkRadioActionEntry radios[] = {
+ { "ColAction", NULL, "Colour", NULL, NULL,
+ SCALE_COLOUR },
+ { "MonoAction", NULL, "Monochrome", NULL, NULL,
+ SCALE_MONO },
+ { "InvMonoAction", NULL, "Inverse Monochrome", NULL, NULL,
+ SCALE_INVMONO },
+ };
+ guint n_radios = G_N_ELEMENTS(radios);
+
+ dw->action_group = gtk_action_group_new("hdfseedisplaywindow");
+ gtk_action_group_add_actions(dw->action_group, entries, n_entries, dw);
+ gtk_action_group_add_toggle_actions(dw->action_group, toggles,
+ n_toggles, dw);
+ gtk_action_group_add_radio_actions(dw->action_group, radios, n_radios,
+ colscale,
+ G_CALLBACK(displaywindow_setscale),
+ dw);
+
+ dw->ui = gtk_ui_manager_new();
+ gtk_ui_manager_insert_action_group(dw->ui, dw->action_group, 0);
+ g_signal_connect(dw->ui, "add_widget",
+ G_CALLBACK(displaywindow_addui_callback), vbox);
+ if ( gtk_ui_manager_add_ui_from_file(dw->ui,
+ DATADIR"/crystfel/hdfsee.ui", &error) == 0 ) {
+ fprintf(stderr, "Error loading message window menu bar: %s\n",
+ error->message);
+ return;
+ }
+
+ gtk_window_add_accel_group(GTK_WINDOW(dw->window),
+ gtk_ui_manager_get_accel_group(dw->ui));
+ gtk_ui_manager_ensure_update(dw->ui);
+}
+
+
+
+static int geometry_fits(struct image *image, struct detector *geom)
+{
+ if ( (1+geom->max_fs != image->width)
+ || (1+geom->max_ss != image->height) ) return 0;
+
+ return 1;
+}
+
+
+struct newhdf {
+ DisplayWindow *dw;
+ char name[1024];
+};
+
+static gint displaywindow_newhdf(GtkMenuItem *item, struct newhdf *nh)
+{
+ if ( nh->dw->not_ready_yet ) return 0;
+
+ hdfile_set_image(nh->dw->hdfile, nh->name);
+ hdf5_read(nh->dw->hdfile, nh->dw->image, 0, 0.0);
+
+ /* Check that the geometry still fits */
+ if ( !geometry_fits(nh->dw->image, nh->dw->simple_geom) ) {
+ int using = 0;
+ if ( nh->dw->simple_geom == nh->dw->image->det ) {
+ using = 1;
+ }
+ free_detector_geometry(nh->dw->simple_geom);
+ nh->dw->simple_geom = simple_geometry(nh->dw->image);
+ if ( using ) {
+ nh->dw->image->det = nh->dw->simple_geom;
+ }
+ }
+
+ if ( (nh->dw->loaded_geom != NULL )
+ && (!geometry_fits(nh->dw->image, nh->dw->loaded_geom)) ) {
+
+ GtkWidget *w;
+
+ free_detector_geometry(nh->dw->loaded_geom);
+ nh->dw->loaded_geom = NULL;
+
+ /* Force out of "use geometry" mode */
+ w = gtk_ui_manager_get_widget(nh->dw->ui,
+ "/ui/displaywindow/view/usegeom");
+ gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE);
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), FALSE);
+ nh->dw->use_geom = 0;
+ nh->dw->image->det = nh->dw->simple_geom;
+
+ }
+
+ if ( nh->dw->use_geom ) {
+ nh->dw->image->det = nh->dw->loaded_geom;
+ } else {
+ nh->dw->image->det = nh->dw->simple_geom;
+ }
+
+ displaywindow_update(nh->dw);
+ return 0;
+}
+
+
+static GtkWidget *displaywindow_addhdfgroup(struct hdfile *hdfile,
+ const char *group,
+ DisplayWindow *dw, GSList **rgp,
+ const char *selectme)
+{
+ char **names;
+ int *is_group;
+ int *is_image;
+ GtkWidget *ms;
+ int n, i;
+
+ if ( hdfile == NULL ) return NULL;
+
+ names = hdfile_read_group(hdfile, &n, group, &is_group, &is_image);
+ if ( n == 0 ) return NULL;
+
+ ms = gtk_menu_new();
+
+ for ( i=0; i<n; i++ ) {
+
+ GtkWidget *item;
+ GtkWidget *sub;
+
+ if ( names[i] == NULL ) return NULL;
+
+ if ( is_group[i] ) {
+
+ item = gtk_menu_item_new_with_label(names[i]);
+
+ sub = displaywindow_addhdfgroup(hdfile, names[i],
+ dw, rgp, selectme);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), sub);
+
+ } else if ( is_image[i] ) {
+
+ struct newhdf *nh;
+
+ item = gtk_radio_menu_item_new_with_label(*rgp,
+ names[i]);
+
+ nh = malloc(sizeof(struct newhdf));
+ if ( nh != NULL ) {
+ strncpy(nh->name, names[i], 1023);
+ nh->dw = dw;
+ g_signal_connect(G_OBJECT(item), "activate",
+ G_CALLBACK(displaywindow_newhdf), nh);
+ }
+
+ if ( (selectme != NULL)
+ && (strcmp(names[i], selectme) == 0) ) {
+ gtk_check_menu_item_set_active(
+ GTK_CHECK_MENU_ITEM(item), TRUE);
+ } else {
+ gtk_check_menu_item_set_active(
+ GTK_CHECK_MENU_ITEM(item), FALSE);
+ }
+
+ *rgp = gtk_radio_menu_item_get_group(
+ GTK_RADIO_MENU_ITEM(item));
+
+ } else {
+
+ char *tmp;
+
+ item = gtk_menu_item_new_with_label(names[i]);
+
+ tmp = hdfile_get_string_value(hdfile, names[i]);
+ if ( tmp != NULL ) {
+
+ GtkWidget *ss;
+ GtkWidget *mss;
+
+ mss = gtk_menu_new();
+ ss = gtk_menu_item_new_with_label(tmp);
+ gtk_widget_set_sensitive(ss, FALSE);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mss), ss);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
+ mss);
+
+ }
+
+
+ }
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(ms), item);
+
+ free(names[i]);
+
+
+ }
+
+ free(is_group);
+ free(is_image);
+
+ return ms;
+}
+
+
+static GtkWidget *displaywindow_createhdfmenus(struct hdfile *hdfile,
+ DisplayWindow *dw,
+ const char *selectme)
+{
+ GSList *rg = NULL;
+
+ return displaywindow_addhdfgroup(hdfile, "/", dw, &rg, selectme);
+}
+
+
+static int displaywindow_update_menus(DisplayWindow *dw, const char *selectme)
+{
+ GtkWidget *ms;
+ GtkWidget *w;
+
+ ms = displaywindow_createhdfmenus(dw->hdfile, dw, selectme);
+
+ if ( ms == NULL ) return 1;
+
+ /* Make new menu be the submenu for File->Images */
+ w = gtk_ui_manager_get_widget(dw->ui, "/ui/displaywindow/view/images");
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(w), ms);
+
+ gtk_widget_show_all(ms);
+
+ return 0;
+}
+
+
+static gint displaywindow_release(GtkWidget *widget, GdkEventButton *event,
+ DisplayWindow *dw)
+{
+ if ( (event->type == GDK_BUTTON_RELEASE) && (event->button == 1) ) {
+
+ g_signal_handler_disconnect(GTK_OBJECT(dw->drawingarea),
+ dw->motion_callback);
+ dw->motion_callback = 0;
+
+ }
+
+ return 0;
+}
+
+
+static gint displaywindow_motion(GtkWidget *widget, GdkEventMotion *event,
+ DisplayWindow *dw)
+{
+ if ( dw->numbers_window == NULL ) return 0;
+
+ dw->numbers_window->cx = event->x;
+ dw->numbers_window->cy = dw->height - 1 - event->y;
+
+ /* Schedule redraw */
+ gtk_widget_queue_draw_area(dw->drawingarea, 0, 0,
+ dw->width, dw->height);
+
+ /* Update numbers window */
+ numbers_update(dw);
+
+ return 0;
+
+}
+
+
+static gint displaywindow_press(GtkWidget *widget, GdkEventButton *event,
+ DisplayWindow *dw)
+{
+ if ( dw->motion_callback != 0 ) {
+ return 0;
+ }
+
+ if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 1) ) {
+
+ dw->motion_callback = g_signal_connect(
+ GTK_OBJECT(dw->drawingarea),
+ "motion-notify-event",
+ G_CALLBACK(displaywindow_motion),
+ dw);
+
+ if ( dw->numbers_window != NULL ) {
+ dw->numbers_window->cx = event->x;
+ dw->numbers_window->cy = dw->height - 1 - event->y;
+ numbers_update(dw);
+ }
+
+ }
+
+ return 0;
+
+}
+
+
+DisplayWindow *displaywindow_open(const char *filename, const char *peaks,
+ int boost, int binning, int cmfilter,
+ int noisefilter, int colscale,
+ const char *element, const char *geometry,
+ int show_rings)
+{
+ DisplayWindow *dw;
+ char *title;
+ GtkWidget *vbox;
+ GtkWidget *w;
+
+ dw = calloc(1, sizeof(DisplayWindow));
+ if ( dw == NULL ) return NULL;
+ dw->pixbufs = NULL;
+ dw->binning_dialog = NULL;
+ dw->show_col_scale = 0;
+ dw->col_scale = NULL;
+ dw->boostint_dialog = NULL;
+ dw->boostint = 1;
+ dw->motion_callback = 0;
+ dw->numbers_window = NULL;
+ dw->image = NULL;
+ dw->use_geom = 0;
+ dw->show_rings = show_rings;
+ dw->scale = colscale;
+ dw->binning = binning;
+ dw->boostint = boost;
+ dw->cmfilter = cmfilter;
+ dw->noisefilter = noisefilter;
+ dw->not_ready_yet = 1;
+
+ /* Open the file, if any */
+ if ( filename != NULL ) {
+
+ dw->hdfile = hdfile_open(filename);
+ if ( dw->hdfile == NULL ) {
+ ERROR("Couldn't open file '%s'\n", filename);
+ free(dw);
+ return NULL;
+ } else {
+ int fail = -1;
+
+ if ( element == NULL ) {
+ fail = hdfile_set_first_image(dw->hdfile, "/");
+ } else {
+ fail = hdfile_set_image(dw->hdfile, element);
+ }
+
+ if ( !fail ) {
+ dw->image = calloc(1, sizeof(struct image));
+ hdf5_read(dw->hdfile, dw->image, 0, 0.0);
+ } else {
+ ERROR("Couldn't select path\n");
+ free(dw);
+ return NULL;
+ }
+ }
+
+ } else {
+ free(dw);
+ return NULL;
+ }
+
+ dw->loaded_geom = NULL;
+ dw->simple_geom = simple_geometry(dw->image);
+ dw->image->det = dw->simple_geom;
+
+ /* Peak list provided at startup? */
+ if ( peaks != NULL ) {
+ load_features_from_file(dw->image, peaks);
+ }
+
+ dw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ char *bn = safe_basename(filename);
+ title = malloc(strlen(bn)+14);
+ sprintf(title, "%s - hdfsee", bn);
+ free(bn);
+ gtk_window_set_title(GTK_WINDOW(dw->window), title);
+ free(title);
+
+ g_signal_connect(G_OBJECT(dw->window), "destroy",
+ G_CALLBACK(displaywindow_closed), dw);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(dw->window), vbox);
+ displaywindow_addmenubar(dw, vbox, colscale);
+
+ dw->drawingarea = gtk_drawing_area_new();
+ gtk_box_pack_start(GTK_BOX(vbox), dw->drawingarea, TRUE, TRUE, 0);
+
+ g_signal_connect(GTK_OBJECT(dw->drawingarea), "expose-event",
+ G_CALLBACK(displaywindow_expose), dw);
+
+ gtk_window_set_resizable(GTK_WINDOW(dw->window), FALSE);
+ gtk_widget_show_all(dw->window);
+
+ w = gtk_ui_manager_get_widget(dw->ui, "/ui/displaywindow/view/usegeom");
+ gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE);
+ if ( geometry != NULL ) {
+ load_geometry_file(dw, dw->image, geometry);
+ }
+
+ displaywindow_update(dw);
+
+ gtk_widget_add_events(GTK_WIDGET(dw->drawingarea),
+ GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_BUTTON1_MOTION_MASK);
+ g_object_set(G_OBJECT(dw->drawingarea), "can-focus", TRUE, NULL);
+
+ g_signal_connect(GTK_OBJECT(dw->drawingarea), "button-press-event",
+ G_CALLBACK(displaywindow_press), dw);
+ g_signal_connect(GTK_OBJECT(dw->drawingarea), "button-release-event",
+ G_CALLBACK(displaywindow_release), dw);
+
+ displaywindow_update_menus(dw, element);
+ dw->not_ready_yet = 0;
+
+ return dw;
+}