aboutsummaryrefslogtreecommitdiff
path: root/src/displaywindow.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/displaywindow.c')
-rw-r--r--src/displaywindow.c1609
1 files changed, 1609 insertions, 0 deletions
diff --git a/src/displaywindow.c b/src/displaywindow.c
new file mode 100644
index 0000000..a4ceec0
--- /dev/null
+++ b/src/displaywindow.c
@@ -0,0 +1,1609 @@
+/*
+ * displaywindow.c
+ *
+ * The main display window
+ *
+ * (c) 2006-2008 Thomas White <taw27@cam.ac.uk>
+ *
+ * synth2d - Two-Dimensional Crystallographic Fourier Synthesis
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <math.h>
+#include <fftw3.h>
+
+#include "displaywindow.h"
+#include "data.h"
+#include "png-file.h"
+#include "reflist.h"
+#include "main.h"
+#include "normalise.h"
+#include "contourise.h"
+#include "gtk-symmetry.h"
+#include "gsf.h"
+#include "cflip.h"
+#include "cdm.h"
+#include "clean.h"
+#include "geometry.h"
+#include "luzzatti.h"
+#include "correspondence.h"
+#include "amplitude-r.h"
+#include "superlattice.h"
+#include "refine.h"
+#include "elser.h"
+#include "colwheel.h"
+#include "model.h"
+#include "model-display.h"
+#include "dpsynth.h"
+#include "renderer.h"
+
+typedef struct {
+
+ GtkWidget *window;
+ GtkWidget *xcells;
+ GtkWidget *ycells;
+
+} UnitCellsWindow;
+
+GtkUIManager *displaywindow_ui;
+GtkActionGroup *displaywindow_action_group;
+GtkWidget *displaywindow_window;
+GtkWidget *displaywindow_bigvbox;
+GtkWidget *displaywindow_image_widget = NULL;
+GdkPixbuf *displaywindow_pixbuf = NULL;
+double displaywindow_brightness = 700;
+gint displaywindow_autobrightness = FALSE;
+GtkWidget *displaywindow_status_bar;
+
+int displaywindow_model_names = TRUE;
+int displaywindow_model_heights = FALSE;
+
+fftw_complex *displaywindow_in = NULL;
+fftw_complex *displaywindow_out = NULL;
+fftw_plan displaywindow_plan_i2o;
+fftw_plan displaywindow_plan_o2i;
+unsigned int displaywindow_width = 0;
+unsigned int displaywindow_height = 0;
+
+fftw_complex *displaywindow_realspace = NULL;
+DisplayWindowRealSpace displaywindow_rs = DWR_NONE;
+int displaywindow_view = DWV_PATTERSON;
+
+int displaywindow_xc = 1;
+int displaywindow_yc = 1; /* Size of synthesis in unit cells */
+UnitCellsWindow *displaywindow_unitcellswindow = NULL;
+
+static void displaywindow_switchview_real(unsigned int was_rescale);
+
+GtkWidget *displaywindow_gtkwindow() { return displaywindow_window; }
+
+int displaywindow_mode() { return displaywindow_view; }
+
+double displaywindow_max() { return displaywindow_brightness; }
+
+void error_report(const char *message) {
+
+ GtkWidget *window;
+
+ window = gtk_message_dialog_new(GTK_WINDOW(displaywindow_window), GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, message);
+
+ g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window);
+ gtk_widget_show(window);
+
+}
+
+static void displaywindow_about() {
+
+ GtkWidget *window;
+
+ const gchar *authors[] = {
+ "Thomas White <taw27@cam.ac.uk>",
+ NULL
+ };
+
+ window = gtk_about_dialog_new();
+
+ gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(window), PACKAGE_NAME);
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window), PACKAGE_VERSION);
+ gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window), "(c) 2006-2007 Thomas White <taw27@cam.ac.uk>");
+ gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window), "Crystallographic Fourier Synthesis Utility");
+ gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(window), "(c) 2006-2007 Thomas White <taw27@cam.ac.uk>\n"
+ "\n"
+ "Research funded by:\n"
+ "The Engineering and Physical Sciences Research Council\n"
+ "FEI Electron Optics B.V.");
+ gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window), "http://www-hrem.msm.cam.ac.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);
+
+}
+
+static void displaywindow_close() {
+ gtk_exit(0);
+}
+
+void displaywindow_disablephasegrabbing() {
+ GtkWidget *disable;
+ disable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/tools/grabphases");
+ gtk_widget_set_sensitive(GTK_WIDGET(disable), FALSE);
+}
+
+void displaywindow_enablephasegrabbing() {
+ GtkWidget *enable;
+ enable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/tools/grabphases");
+ gtk_widget_set_sensitive(GTK_WIDGET(enable), TRUE);
+}
+
+static gint displaywindow_changeview(GtkWidget *widget, GtkRadioAction *action) {
+
+ displaywindow_view = gtk_radio_action_get_current_value(action);
+ displaywindow_switchview();
+
+ switch ( displaywindow_view ) {
+ case DWV_PATTERSON: displaywindow_statusbar("Patterson transform"); break;
+ case DWV_PATTERSONE: displaywindow_statusbar("E²-1 Patterson transform"); break;
+ case DWV_KNOWNPHASE: displaywindow_statusbar("Known phases"); break;
+ case DWV_CALCPHASE: displaywindow_statusbar("Calculated phases"); break;
+ case DWV_REALSPACE: displaywindow_statusbar("Real space estimate"); break;
+ case DWV_MODEL: displaywindow_statusbar("Atomic model"); break;
+ case DWV_DIFFERENCE: displaywindow_statusbar("Fourier difference synthesis"); break;
+ case DWV_REFSYN: displaywindow_statusbar("Fourier refinement synthesis"); break;
+ case DWV_SIMPATT: displaywindow_statusbar("Simulated Patterson transform"); break;
+ case DWV_SIMFOLZPATT: displaywindow_statusbar("Simulated FOLZ Patterson transform"); break;
+ case DWV_EXITWAVE: displaywindow_statusbar("Simulated exit wave"); break;
+ }
+
+ if ( displaywindow_view == DWV_REALSPACE ) {
+ displaywindow_enablephasegrabbing();
+ } else {
+ displaywindow_disablephasegrabbing();
+ }
+
+ /* Saving images from the model display is not allowed. Use Save PDF in this case... */
+ if ( displaywindow_view == DWV_MODEL ) {
+ GtkWidget *disable;
+ #if HAVE_CAIRO
+ GtkWidget *enable;
+ #endif
+ disable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/file/save");
+ gtk_widget_set_sensitive(GTK_WIDGET(disable), FALSE);
+ #if HAVE_CAIRO
+ enable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/file/savepdf");
+ gtk_widget_set_sensitive(GTK_WIDGET(enable), TRUE);
+ #else
+ disable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/file/savepdf");
+ gtk_widget_set_sensitive(GTK_WIDGET(disable), FALSE);
+ #endif
+ disable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/view/contour");
+ gtk_widget_set_sensitive(GTK_WIDGET(disable), FALSE);
+ } else {
+ GtkWidget *enable;
+ GtkWidget *disable;
+ enable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/file/save");
+ gtk_widget_set_sensitive(GTK_WIDGET(enable), TRUE);
+ disable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/file/savepdf");
+ gtk_widget_set_sensitive(GTK_WIDGET(disable), FALSE);
+ enable = gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/view/contour");
+ gtk_widget_set_sensitive(GTK_WIDGET(enable), TRUE);
+ }
+
+ return 0;
+
+}
+
+void displaywindow_forceview(int new_view) {
+
+ GtkAction *action;
+
+ if ( new_view == displaywindow_view ) return; /* Nothing to do */
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "ExitWaveAction");
+ #ifdef HAVE_GTK_TEN
+ gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), new_view);
+ #endif /* HAVE_GTK_TEN */
+
+}
+
+static gint displaywindow_wilsonplot() {
+ main_wilsonplot();
+ return 0;
+}
+
+static gint displaywindow_falloffplot() {
+ main_falloffplot();
+ return 0;
+}
+
+static gint displaywindow_dpsynth() {
+ main_dpsynth();
+ return 0;
+}
+
+static gint displaywindow_simdp() {
+ dpsynth_simdp_open(model_calculate_f(main_reflist(), NULL, 0));
+ return 0;
+}
+
+static gint displaywindow_argand() {
+ main_argand();
+ return 0;
+}
+
+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);
+ }
+
+}
+
+unsigned int symmetrise_window_open = 0;
+static gint displaywindow_symmetrise_response(GtkWidget *widget, gint response, GtkWidget *symmetry) {
+
+ if ( response == GTK_RESPONSE_OK ) {
+ main_symmetrise(gtk_symmetry_get_symmetry(GTK_SYMMETRY(symmetry)));
+ }
+
+ symmetrise_window_open = 0;
+ gtk_widget_destroy(widget);
+
+ return 0;
+
+}
+
+static void displaywindow_symmetrise() {
+
+ GtkWidget *symmetrise_window;
+ GtkWidget *symmetry;
+
+ if ( symmetrise_window_open ) {
+ return;
+ }
+ symmetrise_window_open = 1;
+
+ symmetry = gtk_symmetry_new(2, 2, TRUE);
+
+ symmetrise_window = gtk_dialog_new_with_buttons("Symmetrise", GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(symmetrise_window)->vbox), symmetry, FALSE, FALSE, 7);
+
+ g_signal_connect(G_OBJECT(symmetrise_window), "response", G_CALLBACK(displaywindow_symmetrise_response), symmetry);
+
+ gtk_widget_show_all(symmetrise_window);
+
+}
+
+static gint displaywindow_closedown(GtkWidget *widget, gpointer data) {
+
+ fftw_destroy_plan(displaywindow_plan_i2o);
+ fftw_destroy_plan(displaywindow_plan_o2i);
+ fftw_free(displaywindow_in);
+ fftw_free(displaywindow_out);
+
+ displaywindow_in = NULL;
+ displaywindow_out = NULL;
+
+ return 0;
+
+}
+
+void displaywindow_statusbar(const char *message) {
+ gtk_statusbar_pop(GTK_STATUSBAR(displaywindow_status_bar), 0);
+ gtk_statusbar_push(GTK_STATUSBAR(displaywindow_status_bar), 0, message);
+}
+
+static void displaywindow_free_data(guchar *image_data, gpointer data) {
+ free(image_data);
+}
+
+GdkPixbuf *displaywindow_render_pixbuf(fftw_complex *out, double brightness, size_t width, size_t height, double gamma, int nx, int ny) {
+
+ GdkPixbuf *pixbuf;
+ guchar *data;
+ int width_n, height_n; /* Size of the image without border */
+ int width_i, height_i; /* Size of the image, including border */
+ int xn, yn; /* Iterators */
+ int bx, by; /* Border width in x and y */
+ ComplexArray cxar;
+ size_t data_len;
+
+ bx = 20; by = 20;
+
+ width_n = (int)renderer_width(width, height, gamma, nx, ny);
+ height_n = (int)renderer_height(width, height, gamma, nx, ny);
+ width_i = width_n + 2*bx;
+ height_i = height_n + 2*by;
+
+ data_len = height_i*width_i*3*sizeof(guchar);
+ data = malloc(data_len);
+ memset(data, 0xE5, data_len);
+
+ cxar = renderer_draw(out, width, height, gamma, nx, ny);
+ for ( yn=0; yn<height_n; yn++ ) {
+ for ( xn=0; xn<width_n; xn++ ) {
+
+ double re, im, am, ph;
+
+ re = cxar.re[xn+width_n*yn];
+ im = cxar.im[xn+width_n*yn];
+
+ am = sqrt(re*re + im*im) / brightness;
+ ph = atan2(im, re);
+ if ( am > 1.0 ) am = 1.0;
+
+ data[3*((xn+bx)+width_i*(height_i-1-(yn+by))) + 0] =
+ (guchar)(255.0*colwheel_red(am, ph));
+ data[3*((xn+bx)+width_i*(height_i-1-(yn+by))) + 1] =
+ (guchar)(255.0*colwheel_green(am, ph));
+ data[3*((xn+bx)+width_i*(height_i-1-(yn+by))) + 2] =
+ (guchar)(255.0*colwheel_blue(am, ph));
+
+ }
+ }
+
+ free(cxar.re);
+ free(cxar.im);
+
+ pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, FALSE, 8, width_i, height_i, 3*width_i,
+ (GdkPixbufDestroyNotify)displaywindow_free_data, NULL);
+
+ return pixbuf;
+
+}
+
+static void displaywindow_update() {
+
+ if ( displaywindow_pixbuf ) {
+ gdk_pixbuf_unref(displaywindow_pixbuf);
+ }
+
+ displaywindow_pixbuf = displaywindow_render_pixbuf(displaywindow_outarray(),
+ displaywindow_brightness, data_width(), data_height(), data_gamma(), displaywindow_xc, displaywindow_yc);
+
+ if ( displaywindow_image_widget ) {
+ g_object_set(G_OBJECT(displaywindow_image_widget), "pixbuf", displaywindow_pixbuf, NULL);
+ } else {
+ displaywindow_image_widget = gtk_image_new_from_pixbuf(displaywindow_pixbuf);
+ gtk_box_pack_end(GTK_BOX(displaywindow_bigvbox), GTK_WIDGET(displaywindow_image_widget), 0, FALSE, FALSE);
+ gtk_widget_show(displaywindow_image_widget);
+ }
+
+}
+
+void displaywindow_blank() {
+
+ fftw_complex *blank;
+
+ if ( displaywindow_pixbuf ) {
+ gdk_pixbuf_unref(displaywindow_pixbuf);
+ }
+ if ( displaywindow_image_widget ) {
+ gtk_widget_destroy(displaywindow_image_widget);
+ }
+
+ blank = malloc(data_width()*data_height()*sizeof(fftw_complex));
+ bzero(blank, data_width()*data_height()*sizeof(fftw_complex));
+ displaywindow_pixbuf = displaywindow_render_pixbuf(blank, 1000000, data_width(), data_height(), data_gamma(),
+ displaywindow_xc, displaywindow_yc);
+ displaywindow_image_widget = gtk_image_new_from_pixbuf(displaywindow_pixbuf);
+ gtk_box_pack_end(GTK_BOX(displaywindow_bigvbox), GTK_WIDGET(displaywindow_image_widget), 0, FALSE, FALSE);
+ gtk_widget_show(displaywindow_image_widget);
+
+ displaywindow_realspace = blank;
+
+}
+
+static unsigned int displaywindow_brightnesswindow_open = 0;
+
+static gint displaywindow_brightnesswindow_activate(GtkWidget *brightness_entry, GtkWidget *brightness_window) {
+
+ float brightness_new;
+ const char *brightness_string = gtk_entry_get_text(GTK_ENTRY(brightness_entry));
+ if ( sscanf(brightness_string, "%f", &brightness_new) == 1 ) {
+
+ displaywindow_brightnesswindow_open = 0;
+ gtk_widget_destroy(brightness_window);
+ if ( displaywindow_brightness != brightness_new ) {
+ displaywindow_brightness = brightness_new;
+ displaywindow_update();
+ //displaywindow_statusbar("Display brightness changed");
+ if ( displaywindow_brightness < 0.000000001 ) {
+ error_report("Watch out for rounding errors!");
+ }
+ }
+
+ }
+
+ return FALSE;
+
+}
+
+static gint displaywindow_brightnesswindow_response(GtkWidget *brightness_window, gint response, GtkWidget *brightness_entry) {
+
+ if ( response == GTK_RESPONSE_OK ) {
+ displaywindow_brightnesswindow_activate(brightness_entry, brightness_window);
+ }
+
+ displaywindow_brightnesswindow_open = 0;
+ gtk_widget_destroy(brightness_window);
+
+ return FALSE;
+
+}
+
+static void displaywindow_brightness_open() {
+
+ GtkWidget *brightness_window;
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *brightness_label;
+ GtkWidget *brightness_entry;
+ char *brightness_string;
+
+ if ( displaywindow_brightnesswindow_open ) {
+ return;
+ }
+ displaywindow_brightnesswindow_open = 1;
+
+ brightness_entry = gtk_entry_new();
+ brightness_window = gtk_dialog_new_with_buttons("Brightness", GTK_WINDOW(displaywindow_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(brightness_window)->vbox), GTK_WIDGET(vbox), FALSE, FALSE, 7);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, FALSE, 5);
+
+ brightness_label = gtk_label_new("Full brightness = ");
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(brightness_label), FALSE, FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(brightness_entry), FALSE, FALSE, 5);
+
+ brightness_string = malloc(32);
+ snprintf(brightness_string, 31, "%f", displaywindow_brightness);
+ gtk_entry_set_text(GTK_ENTRY(brightness_entry), brightness_string);
+ free(brightness_string);
+
+ g_signal_connect(G_OBJECT(brightness_window), "response", G_CALLBACK(displaywindow_brightnesswindow_response), brightness_entry);
+ g_signal_connect(G_OBJECT(brightness_entry), "activate", G_CALLBACK(displaywindow_brightnesswindow_activate), brightness_window);
+
+ gtk_widget_show_all(brightness_window);
+
+}
+
+gint displaywindow_brightness_auto(GtkWidget *widget, gpointer data) {
+ displaywindow_brightness = displaywindow_maxpeak();
+ displaywindow_switchview_real(TRUE);
+ return 0;
+}
+
+static gint displaywindow_brightness_autotoggle(GtkWidget *widget, gpointer data) {
+ displaywindow_autobrightness = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget));
+ if ( displaywindow_autobrightness) displaywindow_brightness_auto(NULL, NULL);
+ return 0;
+}
+
+static gint displaywindow_model_names_toggle(GtkWidget *widget, gpointer data) {
+ displaywindow_model_names = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget));
+ displaywindow_switchview();
+ return 0;
+}
+
+static gint displaywindow_model_heights_toggle(GtkWidget *widget, gpointer data) {
+ displaywindow_model_heights = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(widget));
+ displaywindow_switchview();
+ return 0;
+}
+
+/* Display the Patterson transform based on the given reflections */
+void displaywindow_show_patterson(ReflectionList *reflections) {
+
+ signed int h, k;
+ unsigned int i;
+ GtkAction *action;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ /* Amplitudes squared since this is a Patterson transform */
+ displaywindow_in[k + displaywindow_height*h][0] = reflections->refs[i].amplitude * reflections->refs[i].amplitude;
+ /* Imaginary component is zero */
+
+ }
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "PattersonAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+/* for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ double re = displaywindow_out[k+displaywindow_height*h][0];
+ double im = displaywindow_out[k+displaywindow_height*h][1];
+ re_t += re*re;
+ im_t += im*im;
+ }
+ }
+ printf("Real total = %f\nImaginary total = %f\n", re_t, im_t); */
+
+}
+
+/* Display the Patterson transform with E^2-1 based on the given reflections */
+void displaywindow_show_pattersone(ReflectionList *reflections) {
+
+ signed int h, k;
+ unsigned int i;
+ GtkAction *action;
+ double sigma = 0; /* Actually this is "Epsilon times sigma" */
+ unsigned int n = 0;
+ double dev = 0;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ for ( i=1; i<reflections->n_reflections; i++ ) {
+ if ( reflections->refs[i].amplitude > 0 ) {
+ sigma += reflections->refs[i].amplitude * reflections->refs[i].amplitude;
+ n++;
+ }
+ }
+ sigma = sigma / n;
+
+ for ( i=1; i<reflections->n_reflections; i++ ) {
+
+ double Esq;
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+
+ if ( (abs(h) > displaywindow_width/2) || (abs(k) > displaywindow_height/2) ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ if ( reflections->refs[i].amplitude != 0 ) {
+ Esq = (reflections->refs[i].amplitude * reflections->refs[i].amplitude) / sigma;
+ displaywindow_in[k + displaywindow_height*h][0] = Esq - 1;
+ /* Imaginary component is zero */
+ dev += Esq - 1;
+ }
+
+ }
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "PattersonEAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+/* Display the known phase synthesis based on the given reflections */
+void displaywindow_show_knownphases(ReflectionList *reflections) {
+
+ signed int h, k;
+ unsigned int i;
+ unsigned int n = 0;
+ GtkAction *action;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ if ( reflections->refs[i].phase_known_set ) {
+ displaywindow_in[k + displaywindow_height*h][0] = reflections->refs[i].amplitude * cos(reflections->refs[i].phase_known);
+ displaywindow_in[k + displaywindow_height*h][1] = reflections->refs[i].amplitude * sin(reflections->refs[i].phase_known);
+ n++;
+ //printf("%3i %3i = %f %f\n", reflections->refs[i].h, reflections->refs[i].k, reflections->refs[i].amplitude, reflections->refs[i].phase_known);
+ } else {
+ /* else don't include it */
+ //printf("%3i %3i not included\n", reflections->refs[i].h, reflections->refs[i].k);
+ }
+
+ }
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "KnownPhaseAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+/* Display the calculated phase synthesis based on the given reflections */
+void displaywindow_show_calcphases(ReflectionList *reflections) {
+
+ signed int h, k;
+ unsigned int i;
+ GtkAction *action;
+ unsigned int n = 0;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, reflections->refs[i].l);
+ continue;
+ }
+
+ if ( reflections->refs[i].phase_calc_set ) {
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ displaywindow_in[k + displaywindow_height*h][0] = reflections->refs[i].amplitude * cos(reflections->refs[i].phase_calc);
+ displaywindow_in[k + displaywindow_height*h][1] = reflections->refs[i].amplitude * sin(reflections->refs[i].phase_calc);
+ n++;
+
+ } /* else don't include it */
+
+ }
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "CalcPhaseAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+/* Display the current "real space estimate" */
+static void displaywindow_show_realspace() {
+
+ if ( displaywindow_realspace ) {
+ /* displaywindow_update() knows to look in displaywindow_realspace instead of displaywindow_out */
+ displaywindow_update();
+ } else {
+ displaywindow_blank();
+ }
+
+}
+
+void displaywindow_set_realspace(fftw_complex *out, DisplayWindowRealSpace rs) {
+ //if ( rs != DWR_NONE ) fftw_free(displaywindow_realspace);
+ displaywindow_realspace = out;
+ displaywindow_rs = rs;
+}
+
+/* Show the current real-space atomic structure model */
+static void displaywindow_show_model() {
+
+ GtkAction *action;
+
+ #ifdef HAVE_CAIRO
+ if ( displaywindow_pixbuf ) gdk_pixbuf_unref(displaywindow_pixbuf);
+
+ displaywindow_pixbuf = model_display_render_pixbuf(model_get_current(), data_width(), data_height(), data_gamma(),
+ displaywindow_model_names, displaywindow_model_heights, displaywindow_xc, displaywindow_yc);
+ if ( !displaywindow_pixbuf ) return;
+
+ if ( displaywindow_image_widget ) {
+ g_object_set(G_OBJECT(displaywindow_image_widget), "pixbuf", displaywindow_pixbuf, NULL);
+ } else {
+ displaywindow_image_widget = gtk_image_new_from_pixbuf(displaywindow_pixbuf);
+ gtk_box_pack_end(GTK_BOX(displaywindow_bigvbox), GTK_WIDGET(displaywindow_image_widget), 0, FALSE, FALSE);
+ gtk_widget_show(displaywindow_image_widget);
+ }
+ #else
+ displaywindow_blank();
+ #endif
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "ModelAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+/* Show the simulated Patterson based on the structure model */
+static void displaywindow_show_simpatt() {
+
+ signed int h, k, l;
+ unsigned int i;
+ GtkAction *action;
+ ReflectionList *model_reflections;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ model_reflections = model_calculate_f(NULL, NULL, 0);
+
+ for ( i=0; i<model_reflections->n_reflections; i++ ) {
+
+ h = model_reflections->refs[i].h;
+ k = model_reflections->refs[i].k;
+ l = model_reflections->refs[i].l;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, model_reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ displaywindow_in[k + displaywindow_height*h][0] = model_reflections->refs[i].amplitude * model_reflections->refs[i].amplitude;
+
+ }
+
+ free(model_reflections);
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "SimPattAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+static void displaywindow_show_simfolzpatt() {
+
+ signed int h, k, l;
+ unsigned int i;
+ GtkAction *action;
+ ReflectionList *model_reflections;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ model_reflections = model_calculate_f(NULL, NULL, 1);
+
+ for ( i=0; i<model_reflections->n_reflections; i++ ) {
+
+ h = model_reflections->refs[i].h;
+ k = model_reflections->refs[i].k;
+ l = model_reflections->refs[i].l;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, model_reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ displaywindow_in[k + displaywindow_height*h][0] = model_reflections->refs[i].amplitude * model_reflections->refs[i].amplitude;
+
+ }
+
+ free(model_reflections);
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "SimFOLZPattAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+/* This works because of dodginess in main.c */
+void displaywindow_show_difference(ReflectionList *reflections) {
+
+ signed int h, k;
+ unsigned int i;
+ GtkAction *action;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+
+ if ( reflections->refs[i].phase_known_set == 0 ) continue;
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ displaywindow_in[k + displaywindow_height*h][0] = reflections->refs[i].amplitude * cos(reflections->refs[i].phase_known);
+ displaywindow_in[k + displaywindow_height*h][1] = reflections->refs[i].amplitude * sin(reflections->refs[i].phase_known);
+
+ }
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "DifferenceAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+/* This works because of dodginess in main.c */
+void displaywindow_show_diffpatt(ReflectionList *reflections) {
+
+ signed int h, k;
+ unsigned int i;
+ GtkAction *action;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ displaywindow_in[k + displaywindow_height*h][0] = reflections->refs[i].amplitude*reflections->refs[i].amplitude;
+ displaywindow_in[k + displaywindow_height*h][1] = 0;
+
+ }
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "DifferencePattAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+/* This works because of dodginess in main.c */
+void displaywindow_show_refsyn(ReflectionList *reflections) {
+
+ signed int h, k;
+ unsigned int i;
+ GtkAction *action;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ for ( i=0; i<reflections->n_reflections; i++ ) {
+
+ h = reflections->refs[i].h;
+ k = reflections->refs[i].k;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ displaywindow_in[k + displaywindow_height*h][0] = reflections->refs[i].amplitude * cos(reflections->refs[i].phase_known);
+ displaywindow_in[k + displaywindow_height*h][1] = reflections->refs[i].amplitude * sin(reflections->refs[i].phase_known);
+
+ }
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "RefSynAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+/* Show the simulated specimen exit wave based on the structure model */
+static void displaywindow_show_exitwave() {
+
+ signed int h, k, l;
+ unsigned int i;
+ GtkAction *action;
+ ReflectionList *model_reflections;
+
+ for ( h=0; h<displaywindow_width; h++ ) {
+ for ( k=0; k<displaywindow_height; k++ ) {
+ displaywindow_in[k+displaywindow_height*h][0] = 0;
+ displaywindow_in[k+displaywindow_height*h][1] = 0;
+ }
+ }
+
+ model_reflections = model_calculate_f(NULL, NULL, 0);
+
+ for ( i=0; i<model_reflections->n_reflections; i++ ) {
+
+ h = model_reflections->refs[i].h;
+ k = model_reflections->refs[i].k;
+ l = model_reflections->refs[i].l;
+
+ if ( abs(h) > displaywindow_width/2 ) {
+ printf("Index %i %i (%i) is above the Nyquist frequency!\n", h, k, model_reflections->refs[i].l);
+ continue;
+ }
+
+ if ( h < 0 ) { h = displaywindow_width+h; }
+ if ( k < 0 ) { k = displaywindow_height+k; }
+
+ displaywindow_in[k + displaywindow_height*h][0] = model_reflections->refs[i].amplitude * cos(model_reflections->refs[i].phase_known);
+ displaywindow_in[k + displaywindow_height*h][1] = model_reflections->refs[i].amplitude * sin(model_reflections->refs[i].phase_known);
+
+ }
+
+ free(model_reflections);
+
+ /* Transform, preserving input array */
+ fftw_execute(displaywindow_plan_i2o);
+
+ displaywindow_update();
+
+ action = gtk_action_group_get_action(displaywindow_action_group, "ExitWaveAction");
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), TRUE);
+
+}
+
+static void displaywindow_switchview_real(unsigned int was_rescale) {
+
+ switch ( displaywindow_view ) {
+ case DWV_PATTERSON: main_show_patterson(); break;
+ case DWV_PATTERSONE: main_show_pattersone(); break;
+ case DWV_KNOWNPHASE: main_show_knownphases(); break;
+ case DWV_CALCPHASE: main_show_calcphases(); break;
+ case DWV_REALSPACE: displaywindow_show_realspace(); break;
+ case DWV_MODEL: displaywindow_show_model(); break;
+ case DWV_DIFFERENCE: main_show_difference(); break;
+ case DWV_REFSYN: main_show_refsyn(); break;
+ case DWV_DIFFPATT: main_show_diffpatt(); break;
+ case DWV_SIMPATT: displaywindow_show_simpatt(); break;
+ case DWV_SIMFOLZPATT: displaywindow_show_simfolzpatt(); break;
+ case DWV_EXITWAVE: displaywindow_show_exitwave(); break;
+ }
+
+ if ( !was_rescale && displaywindow_autobrightness) displaywindow_brightness_auto(NULL, NULL);
+
+ if ( !was_rescale ) {
+ /* Things which need updating... */
+ main_displayr();
+ main_argand_update();
+ main_dpsynth_update();
+ }
+
+}
+
+void displaywindow_switchview() {
+ displaywindow_switchview_real(FALSE);
+}
+
+static gint displaywindow_geometry_open(GtkWidget *widget, gpointer data) {
+ geometry_dialog_open();
+ return 0;
+}
+
+static gint displaywindow_aperture(GtkWidget *widget, gpointer data) {
+ main_aperture_open();
+ return 0;
+}
+
+static gint displaywindow_luzzatti(GtkWidget *widget, gpointer data) {
+ luzzatti_show();
+ return 0;
+}
+
+static gint displaywindow_correspondence(GtkWidget *widget, gpointer data) {
+ correspondence_show();
+ return 0;
+}
+
+static gint displaywindow_hpfilter(GtkWidget *widget, gpointer data) {
+ main_hpfilter();
+ return 0;
+}
+
+static gint displaywindow_saveimage_response(GtkWidget *dialog, gint response, gpointer data) {
+
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ printf("DW: Saving to '%s'\n", filename);
+ if ( displaywindow_view != DWV_REALSPACE ) {
+ png_write(filename, displaywindow_out, displaywindow_brightness, displaywindow_xc, displaywindow_yc);
+ } else {
+ png_write(filename, displaywindow_realspace, displaywindow_brightness, displaywindow_xc, displaywindow_yc);
+ }
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(dialog);
+
+ return 0;
+
+}
+
+static gint displaywindow_saveimage_open(GtkWidget *widget, gpointer data) {
+
+ GtkWidget *dialog;
+
+ dialog = gtk_file_chooser_dialog_new("Save Image", GTK_WINDOW(displaywindow_gtkwindow()), GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
+
+ #ifdef HAVE_GTK_TEN
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
+ #endif /* HAVE_GTK_TEN */
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "synth2d-output.png");
+
+ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(displaywindow_saveimage_response), NULL);
+
+ gtk_widget_show_all(dialog);
+
+ return 0;
+
+}
+
+static gint displaywindow_savepdf_response(GtkWidget *dialog, gint response, gpointer data) {
+
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ //printf("DW: Saving to '%s'\n", filename);
+
+ if ( displaywindow_view == DWV_MODEL ) {
+ if ( model_display_render_pdf(model_get_current(), data_width(), data_height(), data_gamma(), filename,
+ displaywindow_model_names, displaywindow_model_heights, displaywindow_xc, displaywindow_yc) ) {
+ error_report("Failed to save PDF");
+ }
+ } else {
+ error_report("Can only (currently) save a PDF from the atomic model display");
+ }
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(dialog);
+
+ return 0;
+
+}
+
+static gint displaywindow_savehkl_response(GtkWidget *dialog, gint response, gpointer data) {
+
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ printf("DW: Saving to '%s'\n", filename);
+
+ if ( displaywindow_view == DWV_REALSPACE ) {
+
+ signed int h, k;
+ signed int h1, h2, k1, k2;
+ FILE *fh;
+
+ memcpy(displaywindow_out, displaywindow_realspace, displaywindow_width*displaywindow_height*sizeof(fftw_complex));
+ fftw_execute(displaywindow_plan_o2i);
+ fh = fopen(filename, "w");
+ fprintf(fh, "a %f\n", data_a());
+ fprintf(fh, "b %f\n", data_b());
+ fprintf(fh, "c %f\n", data_c());
+ fprintf(fh, "scale %i\n", data_get_image_scale());
+ h1 = (signed)-main_max_h();
+ h2 = main_max_h();
+ k1 = (signed)-main_max_k();
+ k2 = main_max_k();
+
+ printf("\nWARNING: calculated structure factor amplitudes are being square-rooted.\n");
+ printf("This is the right thing to do to get structure factors from (eg) a CLEANed Patterson map\n");
+ printf("If the real-space estimate is a structure model, you'll need to square them.\n");
+
+ printf("\nWARNING: l index is fixed at zero. Check this is what you wanted.\n");
+
+ for ( h=h1; h<=h2; h++ ) {
+ for ( k=k1; k<=k2; k++ ) {
+
+ double re, im;
+ signed int hd, kd;
+
+ hd = h; kd = k;
+ if ( h < 0 ) hd = displaywindow_width+h;
+ if ( k < 0 ) kd = displaywindow_height+k;
+ re = displaywindow_in[kd + displaywindow_height*hd][0];
+ im = displaywindow_in[kd + displaywindow_height*hd][1];
+
+ fprintf(fh, "%3i %3i %3i %f %f\n", h, k, 0, sqrt(sqrt(re*re + im*im)), atan2(im, re));
+
+ }
+ }
+ fclose(fh);
+
+ } else {
+ main_savereflections(filename);
+ }
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(dialog);
+
+ return 0;
+
+}
+
+static gint displaywindow_savehkl_open(GtkWidget *widget, gpointer data) {
+
+ GtkWidget *dialog;
+
+ dialog = gtk_file_chooser_dialog_new("Save Reflections", GTK_WINDOW(displaywindow_gtkwindow()), GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
+ #ifdef HAVE_GTK_TEN
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
+ #endif /* HAVE_GTK_TEN */
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "synth2d-output.hkl");
+
+ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(displaywindow_savehkl_response), NULL);
+
+ gtk_widget_show_all(dialog);
+
+ return 0;
+
+}
+
+static gint displaywindow_savepdf_open(GtkWidget *widget, gpointer data) {
+
+ GtkWidget *dialog;
+
+ dialog = gtk_file_chooser_dialog_new("Save PDF", GTK_WINDOW(displaywindow_gtkwindow()), GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
+ #ifdef HAVE_GTK_TEN
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
+ #endif /* HAVE_GTK_TEN */
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "synth2d-model.pdf");
+
+ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(displaywindow_savepdf_response), NULL);
+
+ gtk_widget_show_all(dialog);
+
+ return 0;
+
+}
+
+static gint displaywindow_amplituder(GtkWidget *widget, gpointer data) {
+ amplituder_show();
+ return 0;
+}
+
+static gint displaywindow_refine_open(GtkWidget *widget, gpointer data) {
+ refine_open(model_get_current());
+ return 0;
+}
+
+static gint displaywindow_grabphases(GtkWidget *widget, gpointer data) {
+
+ if ( displaywindow_view != DWV_REALSPACE ) {
+ /* Should never happen because option is disabled */
+ error_report("Can only grab phases from Real Space Estimate");
+ return 0;
+ }
+
+ if ( displaywindow_rs != DWR_ELSER ) {
+ error_report("Can only grab phases from Elser Difference Map");
+ return 0;
+ }
+ elser_grab_phases(main_reflist());
+
+ displaywindow_forceview(DWV_KNOWNPHASE);
+
+ return 0;
+
+}
+
+static gint displaywindow_contourise(GtkWidget *widget, gpointer data) {
+ contourise_dialog_open(displaywindow_xc, displaywindow_yc);
+ return 0;
+}
+
+void displaywindow_kicksize() {
+ gtk_window_resize(GTK_WINDOW(displaywindow_window), 1, 1);
+}
+
+static gint displaywindow_unitcells_response(GtkWidget *widget, gint response, UnitCellsWindow *cw) {
+
+ int done = 1;
+
+ if ( response == GTK_RESPONSE_OK ) {
+ const char *xcells;
+ const char *ycells;
+ unsigned int xc, yc;
+ int scanval;
+ xcells = gtk_entry_get_text(GTK_ENTRY(cw->xcells));
+ ycells = gtk_entry_get_text(GTK_ENTRY(cw->ycells));
+ scanval = sscanf(xcells, "%u", &xc);
+ scanval += sscanf(ycells, "%u", &yc);
+ if ( scanval != 2 ) {
+ error_report("Please enter valid values for both dimensions.");
+ done = 0;
+ } else {
+ displaywindow_xc = xc;
+ displaywindow_yc = yc;
+ displaywindow_switchview();
+ displaywindow_kicksize();
+ }
+ }
+
+ if ( done ) {
+ gtk_widget_destroy(cw->window);
+ free(cw);
+ displaywindow_unitcellswindow = NULL;
+ }
+
+ return 0;
+}
+
+static gint displaywindow_unitcells_response_ac(GtkWidget *widget, UnitCellsWindow *cw) {
+ return displaywindow_unitcells_response(widget, GTK_RESPONSE_OK, cw);
+}
+
+static gint displaywindow_stripzero(GtkWidget *widget, gpointer data) {
+ main_stripzero();
+ displaywindow_switchview();
+ return 0;
+}
+
+static gint displaywindow_antialias(GtkWidget *widget, gpointer data) {
+ main_antialias();
+ displaywindow_switchview();
+ return 0;
+}
+
+static gint displaywindow_unitcells_open(GtkWidget *widget, gpointer data) {
+
+ UnitCellsWindow *cw;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *table;
+ GtkWidget *xcells_label;
+ GtkWidget *ycells_label;
+ char tmp[32];
+
+ if ( displaywindow_unitcellswindow ) {
+ return 0;
+ }
+ cw = malloc(sizeof(UnitCellsWindow));
+ if ( !cw ) return 1;
+ displaywindow_unitcellswindow = cw;
+
+ cw->window = gtk_dialog_new_with_buttons("Number of Unit Cells", GTK_WINDOW(displaywindow_gtkwindow()),
+ 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(cw->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(2, 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);
+
+ xcells_label = gtk_label_new("Number of cells along x:");
+ gtk_misc_set_alignment(GTK_MISC(xcells_label), 1, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(xcells_label), 1, 2, 1, 2);
+
+ cw->xcells = gtk_entry_new();
+ snprintf(tmp, 31, "%i", displaywindow_xc);
+ gtk_entry_set_text(GTK_ENTRY(cw->xcells), tmp);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(cw->xcells), 2, 3, 1, 2);
+
+ ycells_label = gtk_label_new("Number of cells along y:");
+ gtk_misc_set_alignment(GTK_MISC(ycells_label), 1, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(ycells_label), 1, 2, 2, 3);
+
+ cw->ycells = gtk_entry_new();
+ snprintf(tmp, 31, "%i", displaywindow_yc);
+ gtk_entry_set_text(GTK_ENTRY(cw->ycells), tmp);
+ gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(cw->ycells), 2, 3, 2, 3);
+
+ g_signal_connect(G_OBJECT(cw->ycells), "activate", G_CALLBACK(displaywindow_unitcells_response_ac), cw);
+ g_signal_connect(G_OBJECT(cw->window), "response", G_CALLBACK(displaywindow_unitcells_response), cw);
+ gtk_widget_show_all(cw->window);
+ gtk_widget_grab_focus(GTK_WIDGET(cw->xcells));
+
+ return 0;
+
+}
+
+static void displaywindow_addmenubar(GtkWidget *vbox) {
+
+ GtkActionEntry entries[] = {
+
+ { "FileAction", NULL, "_File", NULL, NULL, NULL },
+ { "SaveAction", GTK_STOCK_SAVE, "_Save Image...", "", NULL, G_CALLBACK(displaywindow_saveimage_open) },
+ { "SaveHKLAction", GTK_STOCK_SAVE, "_Save HKL...", "", NULL, G_CALLBACK(displaywindow_savehkl_open) },
+ { "SavePDFAction", GTK_STOCK_SAVE, "_Save PDF...", "", NULL, G_CALLBACK(displaywindow_savepdf_open) },
+ { "CloseAction", GTK_STOCK_QUIT, "_Quit", NULL, NULL, G_CALLBACK(displaywindow_close) },
+
+ { "ViewAction", NULL, "_View", NULL, NULL, NULL },
+ { "CellsAction", NULL, "Number of Unit Cells...", "F3", NULL, G_CALLBACK(displaywindow_unitcells_open) },
+ { "ScaleMenuAction", NULL, "Display Brightness", NULL, NULL, G_CALLBACK(NULL) },
+ { "ModelMenuAction", NULL, "Model Display Features", NULL, NULL, G_CALLBACK(NULL) },
+ { "ScaleAction", NULL, "Set Display _Brightness Manually...", "<Ctrl>F5", NULL, G_CALLBACK(displaywindow_brightness_open) },
+ { "AutoScaleOnceAction", NULL, "Automatic Brightness Once Only", "F5", NULL, G_CALLBACK(displaywindow_brightness_auto) },
+ { "ContourAction", NULL, "C_ontour Map...", NULL, NULL, G_CALLBACK(displaywindow_contourise) },
+ { "ArgandAction", NULL, "Ar_gand Plane...", NULL, NULL, G_CALLBACK(displaywindow_argand) },
+ { "DPAction", NULL, "_Diffraction Pattern...", NULL, NULL, G_CALLBACK(displaywindow_dpsynth) },
+ { "SimDPAction", NULL, "Simulated Diffraction Pattern...", NULL, NULL, G_CALLBACK(displaywindow_simdp) },
+ { "ApertureAction", NULL, "Aper_ture Function...", NULL, NULL, G_CALLBACK(displaywindow_aperture) },
+ { "ColWheelAction", NULL, "Co_lour Wheel...", NULL, NULL, G_CALLBACK(colwheel_show) },
+
+ { "PlotsAction", NULL, "_Plots", NULL, NULL, NULL },
+ { "WilsonAction", "gnome-calc3", "_Wilson...", NULL, NULL, G_CALLBACK(displaywindow_wilsonplot) },
+ { "FalloffAction", "gnome-calc3", "_Resolution Falloff...", NULL, NULL, G_CALLBACK(displaywindow_falloffplot) },
+ { "LuzzattiAction", "gnome-calc3", "Lu_zzatti...", NULL, NULL, G_CALLBACK(displaywindow_luzzatti) },
+ { "CorrespondenceAction", "gnome-calc3", "Correspondence...", NULL, NULL, G_CALLBACK(displaywindow_correspondence) },
+ { "AmplitudeRAction", "gnome-calc3", "Amplitude-R...", NULL, NULL, G_CALLBACK(displaywindow_amplituder) },
+
+ { "SolveAction", NULL, "_Solve", NULL, NULL, NULL },
+ { "GSFAction", GTK_STOCK_EXECUTE, "_GSF Iteration...", NULL, NULL, G_CALLBACK(gsf_dialog_open) },
+ { "CFAction", GTK_STOCK_EXECUTE, "_Charge Flipping...", NULL, NULL, G_CALLBACK(cflip_dialog_open) },
+ { "CDMAction", GTK_STOCK_EXECUTE, "_Tangent Formula...", NULL, NULL, G_CALLBACK(cdm_dialog_open) },
+ { "ElserAction", GTK_STOCK_EXECUTE, "_Elser Difference Map...", NULL, NULL, G_CALLBACK(elser_dialog_open) },
+ { "CLEANAction", NULL, "_CLEAN...", NULL, NULL, G_CALLBACK(clean_dialog_open) },
+ { "ModelRefineAction", NULL, "_Refine Atomic Model...", NULL, NULL, G_CALLBACK(displaywindow_refine_open) },
+
+ { "ToolsAction", NULL, "_Tools", NULL, NULL, NULL },
+ { "SymmAction", GTK_STOCK_CONVERT, "_Symmetrise...", NULL, NULL, G_CALLBACK(displaywindow_symmetrise) },
+ { "SharpenAction", NULL, "_Deconvolve...", NULL, NULL, G_CALLBACK(normalise_dialog_open) },
+ { "DethermaliseAction", NULL, "_Normalise...", NULL, NULL, G_CALLBACK(normalise_dethermalise_open) },
+ { "ExpNormaliseAction", NULL, "_Exponential Normalisation...", NULL, NULL, G_CALLBACK(normalise_exponential_open) },
+ { "GeometryCorrAction", NULL, "_Geometrical Correction...", NULL, NULL, G_CALLBACK(displaywindow_geometry_open) },
+ { "SuperlatticeSplitAction", NULL, "Superlattice S_plit...", NULL, NULL, G_CALLBACK(superlattice_split_open) },
+ { "HighPassFilterAction", NULL, "_High Pass Filter", NULL, NULL, G_CALLBACK(displaywindow_hpfilter) },
+ { "GrabPhaseAction", GTK_STOCK_COPY, "_Grab Phases as Known", NULL, NULL, G_CALLBACK(displaywindow_grabphases) },
+ { "StripZeroAction", NULL, "Strip Zero-Order Beam", NULL, NULL, G_CALLBACK(displaywindow_stripzero) },
+ { "AntiAliasAction", NULL, "Anti-alias Filter", NULL, NULL, G_CALLBACK(displaywindow_antialias) },
+ { "ModelAtomAction", NULL, "_Edit Atomic Model...", NULL, NULL, G_CALLBACK(model_open_editor) },
+ { "ModelLoadAction", GTK_STOCK_OPEN, "_Load Atomic Model...", NULL, NULL, G_CALLBACK(model_load_open) },
+ { "ModelSaveAction", GTK_STOCK_SAVE, "_Save Atomic Model...", NULL, NULL, G_CALLBACK(model_save_open) },
+
+ { "HelpAction", NULL, "_Help", NULL, NULL, NULL },
+ { "AboutAction", GTK_STOCK_ABOUT, "_About Synth2D...", NULL, NULL, G_CALLBACK(displaywindow_about) },
+
+ };
+ guint n_entries = G_N_ELEMENTS(entries);
+ GError *error = NULL;
+ GtkRadioActionEntry radios[] = {
+ { "PattersonAction", NULL, "_Patterson Transform", NULL, NULL, DWV_PATTERSON },
+ { "PattersonEAction", NULL, "Patterson Transform with _E²-1", NULL, NULL, DWV_PATTERSONE },
+ { "KnownPhaseAction", NULL, "_Known Phases", NULL, NULL, DWV_KNOWNPHASE },
+ { "CalcPhaseAction", NULL, "_Calculated Phases", NULL, NULL, DWV_CALCPHASE },
+ { "RealSpaceAction", NULL, "_Real Space Estimate", NULL, NULL, DWV_REALSPACE },
+ { "ModelAction", NULL, "Atomic _Model", NULL, NULL, DWV_MODEL },
+ { "DifferenceAction", NULL, "Fourier _Difference Synthesis", NULL, NULL, DWV_DIFFERENCE },
+ { "RefSynAction", NULL, "_Fourier Refinement Synthesis", NULL, NULL, DWV_REFSYN },
+ { "DifferencePattAction", NULL, "Difference Patterson Map", NULL, NULL, DWV_DIFFPATT },
+ { "SimPattAction", NULL, "_Simulated Patterson Transform", NULL, NULL, DWV_SIMPATT },
+ { "SimFOLZPattAction", NULL, "_Simulated FOLZ Patterson Transform", NULL, NULL, DWV_SIMFOLZPATT },
+ { "ExitWaveAction", NULL, "Simulated _Exit Wave", NULL, NULL, DWV_EXITWAVE },
+ };
+ guint n_radios = G_N_ELEMENTS(radios);
+ GtkToggleActionEntry toggles[] = {
+ { "AutoScaleAction", NULL, "Automatic Brightness", NULL, NULL, G_CALLBACK(displaywindow_brightness_autotoggle), FALSE },
+ { "ModelNamesAction", NULL, "Element Names", NULL, NULL, G_CALLBACK(displaywindow_model_names_toggle), TRUE },
+ { "ModelHeightsAction", NULL, "Atom Heights", NULL, NULL, G_CALLBACK(displaywindow_model_heights_toggle), FALSE },
+ };
+ guint n_toggles = G_N_ELEMENTS(toggles);
+
+ displaywindow_action_group = gtk_action_group_new("synth2Ddisplaywindow");
+ gtk_action_group_add_actions(displaywindow_action_group, entries, n_entries, displaywindow_window);
+ /* Weird choice of initial selected action ensures signal gets sent on opening window to sort out menu enabling/disabling */
+ gtk_action_group_add_radio_actions(displaywindow_action_group, radios, n_radios, DWV_SIMFOLZPATT, G_CALLBACK(displaywindow_changeview), NULL);
+ gtk_action_group_add_toggle_actions(displaywindow_action_group, toggles, n_toggles, NULL);
+
+ displaywindow_ui = gtk_ui_manager_new();
+ gtk_ui_manager_insert_action_group(displaywindow_ui, displaywindow_action_group, 0);
+ g_signal_connect(displaywindow_ui, "add_widget", G_CALLBACK(displaywindow_addui_callback), vbox);
+ if ( gtk_ui_manager_add_ui_from_file(displaywindow_ui, DATADIR"/synth2d/displaywindow.ui", &error) == 0 ) {
+ fprintf(stderr, "Error loading message window menu bar: %s\n", error->message);
+ return;
+ }
+
+ gtk_window_add_accel_group(GTK_WINDOW(displaywindow_window), gtk_ui_manager_get_accel_group(displaywindow_ui));
+ gtk_ui_manager_ensure_update(displaywindow_ui);
+
+ #ifndef HAVE_CAIRO
+ gtk_widget_set_sensitive(gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/view/model"), FALSE);
+ gtk_widget_set_sensitive(gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/view/dp"), FALSE);
+ gtk_widget_set_sensitive(gtk_ui_manager_get_widget(displaywindow_ui, "/ui/displaywindow/view/simdp"), FALSE);
+ #endif
+
+}
+
+void displaywindow_createfourier() {
+
+ /* (Re-)Create Fourier data structures */
+
+ if ( displaywindow_in ) {
+ fftw_free(displaywindow_in);
+ fftw_free(displaywindow_out);
+ fftw_destroy_plan(displaywindow_plan_i2o);
+ fftw_destroy_plan(displaywindow_plan_o2i);
+ }
+
+ displaywindow_in = fftw_malloc(data_width()*data_height()*sizeof(fftw_complex));
+ displaywindow_out = fftw_malloc(data_width()*data_height()*sizeof(fftw_complex));
+
+ displaywindow_plan_i2o = fftw_plan_dft_2d(data_width(), data_height(), displaywindow_in, displaywindow_out,
+ FFTW_BACKWARD, FFTW_MEASURE | FFTW_PRESERVE_INPUT);
+ displaywindow_plan_o2i = fftw_plan_dft_2d(data_width(), data_height(), displaywindow_out, displaywindow_in,
+ FFTW_FORWARD, FFTW_MEASURE | FFTW_PRESERVE_INPUT);
+ displaywindow_width = data_width();
+ displaywindow_height = data_height();
+
+}
+
+void displaywindow_open(const char *filenamefull) {
+
+ const char *filename;
+ char *title;
+ GtkWidget *vbox;
+
+ filename = basename(filenamefull);
+ title = malloc(11+strlen(filename));
+ strcpy(title, filename);
+ strcat(title, " - synth2d");
+
+ displaywindow_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(displaywindow_window), title);
+ free(title);
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(displaywindow_window), vbox);
+ displaywindow_addmenubar(vbox);
+
+ displaywindow_status_bar = gtk_statusbar_new();
+ gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(displaywindow_status_bar), FALSE);
+ gtk_box_pack_end(GTK_BOX(vbox), displaywindow_status_bar, FALSE, FALSE, 0);
+
+ displaywindow_bigvbox = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(vbox), displaywindow_bigvbox, FALSE, TRUE, 0);
+
+ g_signal_connect(GTK_OBJECT(displaywindow_window), "destroy", G_CALLBACK(displaywindow_closedown), NULL);
+ g_signal_connect_after(GTK_OBJECT(displaywindow_window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
+
+ displaywindow_disablephasegrabbing();
+
+ gtk_widget_show_all(displaywindow_window);
+
+ displaywindow_createfourier();
+
+}
+
+double displaywindow_maxpeak() {
+
+ fftw_complex *out;
+ double max;
+ unsigned int x, y;
+
+ out = displaywindow_outarray();
+
+ max = 0;
+ for ( x=0; x<displaywindow_width; x++ ) {
+ for ( y=0; y<displaywindow_height; y++ ) {
+ double re, im, am;
+ re = out[y + displaywindow_height*x][0];
+ im = out[y + displaywindow_height*x][1];
+ am = sqrt(re*re + im*im);
+ if ( fabs(am) > fabs(max) ) max = am;
+ }
+ }
+
+ return max;
+
+}
+
+/* To be used with caution */
+fftw_complex *displaywindow_outarray() {
+
+ if ( displaywindow_view != DWV_REALSPACE ) {
+ return displaywindow_out;
+ } else {
+ return displaywindow_realspace;
+ }
+
+}