diff options
Diffstat (limited to 'src/displaywindow.c')
-rw-r--r-- | src/displaywindow.c | 1609 |
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; + } + +} |