aboutsummaryrefslogtreecommitdiff
path: root/src/model-editor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/model-editor.c')
-rw-r--r--src/model-editor.c831
1 files changed, 831 insertions, 0 deletions
diff --git a/src/model-editor.c b/src/model-editor.c
new file mode 100644
index 0000000..3146b5d
--- /dev/null
+++ b/src/model-editor.c
@@ -0,0 +1,831 @@
+/*
+ * model-editor.c
+ *
+ * GUI for editing atomic models
+ *
+ * (c) 2006-2007 Thomas White <taw27@cam.ac.uk>
+ *
+ * synth2d - Two-Dimensional Crystallographic Fourier Synthesis
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <gtk/gtk.h>
+#include <math.h>
+#include <string.h>
+
+#include "displaywindow.h"
+#include "data.h"
+#include "elements.h"
+#include "main.h"
+#include "statistics.h"
+#include "refine.h"
+#include "model.h"
+#include "gtk-symmetry.h"
+
+enum {
+ MODEL_ATOMS_COLUMN_ACTIVE,
+ MODEL_ATOMS_COLUMN_REFINE,
+ MODEL_ATOMS_COLUMN_ELEMENT,
+ MODEL_ATOMS_COLUMN_X,
+ MODEL_ATOMS_COLUMN_Y,
+ MODEL_ATOMS_COLUMN_Z, /* Atomic coordinates */
+ MODEL_ATOMS_COLUMN_B, /* Debye-Waller */
+ MODEL_ATOMS_COLUMN_OCC, /* Occupancy */
+ MODEL_ATOMS_COLUMNS
+};
+
+static gint model_save_response(GtkWidget *dialog, gint response, gpointer data) {
+
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ model_save(filename, model_get_current());
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(dialog);
+
+ return 0;
+
+}
+
+gint model_save_open(GtkWidget *widget, gpointer data) {
+
+ GtkWidget *dialog;
+
+ dialog = gtk_file_chooser_dialog_new("Save Atomic Model", GTK_WINDOW(displaywindow_gtkwindow()), GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
+ #if 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.xyz");
+
+ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(model_save_response), NULL);
+
+ gtk_widget_show_all(dialog);
+
+ return 0;
+
+}
+
+static gint model_load_response(GtkWidget *dialog, gint response, gpointer data) {
+
+ if ( response == GTK_RESPONSE_ACCEPT ) {
+
+ char *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ model_load_as_current(filename);
+ displaywindow_forceview(DWV_MODEL);
+ g_free(filename);
+
+ }
+
+ gtk_widget_destroy(dialog);
+
+ return 0;
+
+}
+
+gint model_load_open(GtkWidget *widget, gpointer data) {
+
+ GtkWidget *dialog;
+
+ dialog = gtk_file_chooser_dialog_new("Load Atomic Model", GTK_WINDOW(displaywindow_gtkwindow()), GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+
+ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(model_load_response), NULL);
+
+ gtk_widget_show_all(dialog);
+
+ return 0;
+
+}
+
+/* Not all model updates should trigger an update of the display and R-factor
+ * (e.g. changing a refinement flag) */
+static void model_editor_put_model_noupdate(ModelEditor *editor) {
+
+ GtkTreeIter iter;
+ gboolean ival;
+
+ editor->model->n_atoms = 0;
+ ival = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(editor->list_store), &iter);
+ while ( ival ) {
+
+ double x, y, z, B, occ;
+ gboolean refine, active;
+ gchar *tmp;
+
+ gtk_tree_model_get(GTK_TREE_MODEL(editor->list_store), &iter, MODEL_ATOMS_COLUMN_X, &x, MODEL_ATOMS_COLUMN_Y, &y, MODEL_ATOMS_COLUMN_Z, &z,
+ MODEL_ATOMS_COLUMN_ELEMENT, &tmp,
+ MODEL_ATOMS_COLUMN_B, &B, MODEL_ATOMS_COLUMN_OCC, &occ,
+ MODEL_ATOMS_COLUMN_ACTIVE, &active, MODEL_ATOMS_COLUMN_REFINE, &refine, -1);
+
+ editor->model->atoms[editor->model->n_atoms].x = x;
+ editor->model->atoms[editor->model->n_atoms].y = y;
+ editor->model->atoms[editor->model->n_atoms].z = z;
+ editor->model->atoms[editor->model->n_atoms].B = B;
+ editor->model->atoms[editor->model->n_atoms].occ = occ;
+ editor->model->atoms[editor->model->n_atoms].active = active;
+ editor->model->atoms[editor->model->n_atoms].refine = refine;
+ editor->model->atoms[editor->model->n_atoms].ref = elements_lookup(tmp);
+ editor->model->n_atoms++;
+
+ ival = gtk_tree_model_iter_next(GTK_TREE_MODEL(editor->list_store), &iter);
+
+ }
+
+}
+
+/* Transfer model from an editor to its corresponding model */
+static void model_editor_put_model(ModelEditor *editor) {
+ model_editor_put_model_noupdate(editor);
+ model_notify_update_editor(editor->model);
+}
+
+/* Transfer model->editor */
+void model_editor_get_model(ModelEditor *editor) {
+
+ size_t i;
+ char tmp[32];
+
+ gtk_list_store_clear(GTK_LIST_STORE(editor->list_store));
+ for ( i=0; i<editor->model->n_atoms; i++ ) {
+
+ double x, y, z, B, occ;
+ gboolean refine, active;
+ GtkTreeIter iter;
+
+ x = editor->model->atoms[i].x;
+ y = editor->model->atoms[i].y;
+ z = editor->model->atoms[i].z;
+ B = editor->model->atoms[i].B;
+ occ = editor->model->atoms[i].occ;
+ active = editor->model->atoms[i].active;
+ refine = editor->model->atoms[i].refine;
+
+ gtk_list_store_append(GTK_LIST_STORE(editor->list_store), &iter);
+ gtk_list_store_set(editor->list_store, &iter, MODEL_ATOMS_COLUMN_X, x, MODEL_ATOMS_COLUMN_Y, y, MODEL_ATOMS_COLUMN_Z, z,
+ MODEL_ATOMS_COLUMN_ELEMENT, elements[editor->model->atoms[i].ref].element_name,
+ MODEL_ATOMS_COLUMN_B, B, MODEL_ATOMS_COLUMN_OCC, occ,
+ MODEL_ATOMS_COLUMN_ACTIVE, active, MODEL_ATOMS_COLUMN_REFINE, refine, -1);
+
+ };
+
+ snprintf(tmp, 31, "%.2f", editor->model->thickness);
+ gtk_entry_set_text(GTK_ENTRY(editor->thickness), tmp);
+ gtk_symmetry_set_symmetry(GTK_SYMMETRY(editor->symmetry), editor->model->sym);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(editor->point_atoms), editor->model->point_atoms);
+
+
+}
+
+static gint model_editor_symmetry_changed(GtkWidget *thickness, ModelEditor *editor) {
+
+ editor->model->sym = gtk_symmetry_get_symmetry(GTK_SYMMETRY(editor->symmetry));
+ model_notify_update_editor(editor->model);
+
+ return 0;
+
+}
+
+static gint model_editor_thickness_edited(GtkWidget *thickness, ModelEditor *editor) {
+
+ const char *str;
+ float tf;
+ double t;
+ char tmp[32];
+
+ str = gtk_entry_get_text(GTK_ENTRY(thickness));
+ sscanf(str, "%f", &tf); t = tf;
+ editor->model->thickness = t;
+
+ snprintf(tmp, 31, "%.2f", editor->model->thickness);
+ gtk_entry_set_text(GTK_ENTRY(thickness), tmp);
+
+ model_notify_update_editor(editor->model);
+
+ return 0;
+
+}
+
+void model_editor_unlock(ModelEditor *editor) {
+
+ gtk_widget_set_sensitive(editor->add_button, TRUE);
+ gtk_widget_set_sensitive(editor->model_atoms_tree, TRUE);
+
+}
+
+void model_editor_lock(ModelEditor *editor) {
+
+ gtk_widget_set_sensitive(editor->add_button, FALSE);
+ gtk_widget_set_sensitive(editor->model_atoms_tree, FALSE);
+ gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(editor->model_atoms_tree)));
+
+}
+
+static gint model_atoms_delete_atom(GtkWidget *widget, ModelEditor *editor) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_remove(GTK_LIST_STORE(editor->list_store), &iter);
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_atoms_add_atom(GtkWidget *widget, ModelEditor *editor) {
+
+ GtkTreeIter iter;
+ unsigned int number;
+
+ number = gtk_combo_box_get_active(GTK_COMBO_BOX(editor->atom_define));
+ gtk_list_store_append(GTK_LIST_STORE(editor->list_store), &iter);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter,
+ MODEL_ATOMS_COLUMN_ELEMENT, elements[number].element_name,
+ MODEL_ATOMS_COLUMN_ACTIVE, TRUE, MODEL_ATOMS_COLUMN_REFINE, TRUE,
+ MODEL_ATOMS_COLUMN_B, 0.0005,
+ MODEL_ATOMS_COLUMN_OCC, 1.0, -1);
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_atoms_selection_changed(GtkTreeSelection *selection, ModelEditor *editor) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ double x, y, z, B, occ;
+ char tmp[32];
+
+ gtk_widget_set_sensitive(editor->delete_button, gtk_tree_selection_get_selected(selection, NULL, NULL));
+ gtk_widget_set_sensitive(editor->position_table, gtk_tree_selection_get_selected(selection, NULL, NULL));
+
+ if ( !gtk_tree_selection_get_selected(selection, NULL, NULL) ) return 0;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_tree_model_get(GTK_TREE_MODEL(editor->list_store), &iter, MODEL_ATOMS_COLUMN_X, &x,
+ MODEL_ATOMS_COLUMN_Y, &y, MODEL_ATOMS_COLUMN_Z, &z,
+ MODEL_ATOMS_COLUMN_B, &B, MODEL_ATOMS_COLUMN_OCC, &occ, -1);
+
+ /* Set the scales, but don't trigger a callback */
+ editor->scale_lock++;
+ gtk_range_set_value(GTK_RANGE(editor->x_scale), x);
+ gtk_range_set_value(GTK_RANGE(editor->y_scale), y);
+ gtk_range_set_value(GTK_RANGE(editor->z_scale), z);
+ gtk_range_set_value(GTK_RANGE(editor->b_scale), B);
+ gtk_range_set_value(GTK_RANGE(editor->occ_scale), occ);
+ editor->scale_lock--;
+
+ snprintf(tmp, 31, "%f", x); gtk_entry_set_text(GTK_ENTRY(editor->x_edit), tmp);
+ snprintf(tmp, 31, "%f", y); gtk_entry_set_text(GTK_ENTRY(editor->y_edit), tmp);
+ snprintf(tmp, 31, "%f", z); gtk_entry_set_text(GTK_ENTRY(editor->z_edit), tmp);
+ snprintf(tmp, 31, "%f", B); gtk_entry_set_text(GTK_ENTRY(editor->b_edit), tmp);
+ snprintf(tmp, 31, "%f", occ); gtk_entry_set_text(GTK_ENTRY(editor->occ_edit), tmp);
+
+ return 0;
+
+}
+
+static gint model_atoms_active_toggled(GtkCellRendererToggle *cell, gchar *path_string, ModelEditor *editor) {
+
+ GtkTreeIter iter;
+ gboolean active;
+
+ gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(editor->list_store), &iter, path_string);
+
+ gtk_tree_model_get(GTK_TREE_MODEL(editor->list_store), &iter, MODEL_ATOMS_COLUMN_ACTIVE, &active, -1);
+ active = !active;
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_ACTIVE, active, -1);
+
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_atoms_refine_toggled(GtkCellRendererToggle *cell, gchar *path_string, ModelEditor *editor) {
+
+ GtkTreeIter iter;
+ gboolean refine;
+
+ gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(editor->list_store), &iter, path_string);
+
+ gtk_tree_model_get(GTK_TREE_MODEL(editor->list_store), &iter, MODEL_ATOMS_COLUMN_REFINE, &refine, -1);
+ refine = !refine;
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_REFINE, refine, -1);
+
+ model_editor_put_model_noupdate(editor);
+
+ return 0;
+
+}
+
+static gint model_editor_x_edit(GtkWidget *x_edit, ModelEditor *editor) {
+
+ const char *str;
+ float xf;
+ double x;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+
+ str = gtk_entry_get_text(GTK_ENTRY(x_edit));
+ sscanf(str, "%f", &xf); x = xf;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_X, x, -1);
+
+ /* This triggers an x_scale callback which updates the model */
+ gtk_range_set_value(GTK_RANGE(editor->x_scale), x);
+
+ return 0;
+
+}
+
+static gint model_editor_y_edit(GtkWidget *y_edit, ModelEditor *editor) {
+
+ const char *str;
+ float yf;
+ double y;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+
+ str = gtk_entry_get_text(GTK_ENTRY(y_edit));
+ sscanf(str, "%f", &yf); y = yf;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_Y, y, -1);
+
+ /* This triggers a y_scale callback which updates the model */
+ gtk_range_set_value(GTK_RANGE(editor->y_scale), y);
+
+ return 0;
+
+}
+
+static gint model_editor_z_edit(GtkWidget *z_edit, ModelEditor *editor) {
+
+ const char *str;
+ float zf;
+ double z;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+
+ str = gtk_entry_get_text(GTK_ENTRY(z_edit));
+ sscanf(str, "%f", &zf); z = zf;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_Z, z, -1);
+
+ /* This triggers a z_scale callback which updates the model */
+ gtk_range_set_value(GTK_RANGE(editor->z_scale), z);
+
+ return 0;
+
+}
+
+static gint model_editor_b_edit(GtkWidget *b_edit, ModelEditor *editor) {
+
+ const char *str;
+ float bf;
+ double b;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+
+ str = gtk_entry_get_text(GTK_ENTRY(b_edit));
+ sscanf(str, "%f", &bf); b = bf;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_B, b, -1);
+
+ /* This triggers a b_scale callback which updates the model */
+ gtk_range_set_value(GTK_RANGE(editor->b_scale), b);
+
+ return 0;
+
+}
+
+static gint model_editor_occ_edit(GtkWidget *occ_edit, ModelEditor *editor) {
+
+ const char *str;
+ float occf;
+ double occ;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+
+ str = gtk_entry_get_text(GTK_ENTRY(occ_edit));
+ sscanf(str, "%f", &occf); occ = occf;
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_OCC, occ, -1);
+
+ /* This triggers an occ_scale callback which updates the model */
+ gtk_range_set_value(GTK_RANGE(editor->occ_scale), occ);
+
+ return 0;
+
+}
+
+static gint model_editor_x_scale(GtkWidget *x_scale, ModelEditor *editor) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ double x;
+ char tmp[32];
+
+ if ( editor->scale_lock > 0 ) return 0;
+
+ x = gtk_range_get_value(GTK_RANGE(x_scale));
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_X, x, -1);
+
+ snprintf(tmp, 31, "%f", x); gtk_entry_set_text(GTK_ENTRY(editor->x_edit), tmp);
+
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_editor_y_scale(GtkWidget *y_scale, ModelEditor *editor) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ double y;
+ char tmp[32];
+
+ if ( editor->scale_lock > 0 ) return 0;
+
+ y = gtk_range_get_value(GTK_RANGE(y_scale));
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_Y, y, -1);
+
+ snprintf(tmp, 31, "%f", y); gtk_entry_set_text(GTK_ENTRY(editor->y_edit), tmp);
+
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_editor_z_scale(GtkWidget *z_scale, ModelEditor *editor) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ double z;
+ char tmp[32];
+
+ if ( editor->scale_lock > 0 ) return 0;
+
+ z = gtk_range_get_value(GTK_RANGE(z_scale));
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_Z, z, -1);
+
+ snprintf(tmp, 31, "%f", z); gtk_entry_set_text(GTK_ENTRY(editor->z_edit), tmp);
+
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_editor_b_scale(GtkWidget *b_scale, ModelEditor *editor) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ double b;
+ char tmp[32];
+
+ if ( editor->scale_lock > 0 ) return 0;
+
+ b = gtk_range_get_value(GTK_RANGE(b_scale));
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_B, b, -1);
+
+ snprintf(tmp, 31, "%f", b); gtk_entry_set_text(GTK_ENTRY(editor->b_edit), tmp);
+
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_editor_occ_scale(GtkWidget *occ_scale, ModelEditor *editor) {
+
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ double occ;
+ char tmp[32];
+
+ if ( editor->scale_lock > 0 ) return 0;
+
+ occ = gtk_range_get_value(GTK_RANGE(occ_scale));
+
+ gtk_tree_view_get_cursor(GTK_TREE_VIEW(editor->model_atoms_tree), &path, &column);
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(editor->list_store), &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(editor->list_store), &iter, MODEL_ATOMS_COLUMN_OCC, occ, -1);
+
+ snprintf(tmp, 31, "%f", occ); gtk_entry_set_text(GTK_ENTRY(editor->occ_edit), tmp);
+
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_editor_pointatoms_toggled(GtkWidget *point_atoms, ModelEditor *editor) {
+
+ editor->model->point_atoms = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(point_atoms));
+ model_editor_put_model(editor);
+
+ return 0;
+
+}
+
+static gint model_editor_close(GtkWidget *widget, gint response, ModelEditor *editor) {
+
+ /* Bye bye */
+ editor->model->editor = NULL;
+ gtk_widget_destroy(editor->window);
+ free(editor);
+
+ return 0;
+
+}
+
+static void model_editor_do_list(GtkWidget *vbox, ModelEditor *editor) {
+
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkCellRenderer *togglerenderer_active;
+ GtkCellRenderer *togglerenderer_refine;
+
+ GtkWidget *scrolledwindow;
+ GtkWidget *add_button;
+ GtkWidget *button_box;
+
+ unsigned int i = 0;
+
+ editor->list_store = gtk_list_store_new(MODEL_ATOMS_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_DOUBLE,
+ G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+ model_editor_get_model(editor);
+ editor->model_atoms_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(editor->list_store));
+
+ renderer = gtk_cell_renderer_text_new();
+ togglerenderer_active = gtk_cell_renderer_toggle_new();
+ togglerenderer_refine = gtk_cell_renderer_toggle_new();
+
+ column = gtk_tree_view_column_new_with_attributes("On", togglerenderer_active, "active", MODEL_ATOMS_COLUMN_ACTIVE, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(editor->model_atoms_tree), column);
+ g_signal_connect(G_OBJECT(togglerenderer_active), "toggled", G_CALLBACK(model_atoms_active_toggled), editor);
+
+ column = gtk_tree_view_column_new_with_attributes("R?", togglerenderer_refine, "active", MODEL_ATOMS_COLUMN_REFINE, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(editor->model_atoms_tree), column);
+ g_signal_connect(G_OBJECT(togglerenderer_refine), "toggled", G_CALLBACK(model_atoms_refine_toggled), editor);
+
+ column = gtk_tree_view_column_new_with_attributes("Element", renderer, "text", MODEL_ATOMS_COLUMN_ELEMENT, NULL);
+ gtk_tree_view_column_set_min_width(GTK_TREE_VIEW_COLUMN(column), 100);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(editor->model_atoms_tree), column);
+
+ column = gtk_tree_view_column_new_with_attributes("x", renderer, "text", MODEL_ATOMS_COLUMN_X, NULL);
+ gtk_tree_view_column_set_min_width(GTK_TREE_VIEW_COLUMN(column), 70);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(editor->model_atoms_tree), column);
+
+ column = gtk_tree_view_column_new_with_attributes("y", renderer, "text", MODEL_ATOMS_COLUMN_Y, NULL);
+ gtk_tree_view_column_set_min_width(GTK_TREE_VIEW_COLUMN(column), 70);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(editor->model_atoms_tree), column);
+
+ column = gtk_tree_view_column_new_with_attributes("z", renderer, "text", MODEL_ATOMS_COLUMN_Z, NULL);
+ gtk_tree_view_column_set_min_width(GTK_TREE_VIEW_COLUMN(column), 70);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(editor->model_atoms_tree), column);
+
+ column = gtk_tree_view_column_new_with_attributes("B", renderer, "text", MODEL_ATOMS_COLUMN_B, NULL);
+ gtk_tree_view_column_set_min_width(GTK_TREE_VIEW_COLUMN(column), 70);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(editor->model_atoms_tree), column);
+
+ column = gtk_tree_view_column_new_with_attributes("Occupancy", renderer, "text", MODEL_ATOMS_COLUMN_OCC, NULL);
+ gtk_tree_view_column_set_min_width(GTK_TREE_VIEW_COLUMN(column), 70);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(editor->model_atoms_tree), column);
+
+ scrolledwindow = gtk_scrolled_window_new(gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(editor->model_atoms_tree)),
+ gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(editor->model_atoms_tree)));
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(scrolledwindow), GTK_WIDGET(editor->model_atoms_tree));
+
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(scrolledwindow), TRUE, TRUE, 5);
+
+ button_box = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), button_box, FALSE, FALSE, 5);
+
+ add_button = gtk_button_new_from_stock(GTK_STOCK_ADD);
+ gtk_box_pack_end(GTK_BOX(button_box), add_button, FALSE, FALSE, 5);
+
+ editor->atom_define = gtk_combo_box_new_text();
+ while ( elements[i].z > 0 ) {
+ gtk_combo_box_append_text(GTK_COMBO_BOX(editor->atom_define), elements[i].element_name);
+ i++;
+ }
+ gtk_combo_box_set_active(GTK_COMBO_BOX(editor->atom_define), 0);
+ gtk_box_pack_end(GTK_BOX(button_box), GTK_WIDGET(editor->atom_define), FALSE, FALSE, 5);
+ g_signal_connect(G_OBJECT(add_button), "clicked", G_CALLBACK(model_atoms_add_atom), editor);
+
+ editor->delete_button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
+ gtk_box_pack_end(GTK_BOX(button_box), editor->delete_button, FALSE, FALSE, 5);
+ g_signal_connect(G_OBJECT(editor->delete_button), "clicked", G_CALLBACK(model_atoms_delete_atom), editor);
+
+ g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(editor->model_atoms_tree))), "changed",
+ G_CALLBACK(model_atoms_selection_changed), editor);
+ gtk_widget_set_sensitive(editor->delete_button,
+ gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(editor->model_atoms_tree)), NULL, NULL));
+
+ editor->add_button = add_button;
+
+}
+
+/* Open the model editor for a given model */
+ModelEditor *model_editor_open(AtomicModel *model) {
+
+ ModelEditor *editor;
+
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *x_scale_label;
+ GtkWidget *y_scale_label;
+ GtkWidget *z_scale_label;
+ GtkWidget *b_scale_label;
+ GtkWidget *occ_scale_label;
+ GtkWidget *top_hbox;
+ GtkWidget *label;
+
+ /* Don't proceed if an editor is already open for this model */
+ if ( model->editor ) return model->editor;
+ editor = malloc(sizeof(ModelEditor));
+ editor->model = model;
+ editor->scale_lock = 0;
+
+ editor->window = gtk_dialog_new_with_buttons("Edit Atomic Model", GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+ gtk_window_set_default_size(GTK_WINDOW(editor->window), 550, 600);
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(editor->window)->vbox), GTK_WIDGET(hbox), TRUE, TRUE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox), TRUE, TRUE, 5);
+
+ top_hbox = gtk_hbox_new(FALSE, 0);
+ label = gtk_label_new("Thickness: ");
+ gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+ gtk_box_pack_start(GTK_BOX(top_hbox), GTK_WIDGET(label), TRUE, TRUE, 5);
+ editor->thickness = gtk_entry_new();
+ gtk_entry_set_alignment(GTK_ENTRY(editor->thickness), 1);
+ gtk_entry_set_max_length(GTK_ENTRY(editor->thickness), 10);
+ gtk_entry_set_width_chars(GTK_ENTRY(editor->thickness), 8);
+ gtk_box_pack_start(GTK_BOX(top_hbox), GTK_WIDGET(editor->thickness), TRUE, TRUE, 5);
+ label = gtk_label_new(" nm");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+ gtk_box_pack_start(GTK_BOX(top_hbox), GTK_WIDGET(label), TRUE, TRUE, 5);
+ g_signal_connect(G_OBJECT(editor->thickness), "activate", G_CALLBACK(model_editor_thickness_edited), editor);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(top_hbox), FALSE, FALSE, 2);
+
+ editor->point_atoms = gtk_check_button_new_with_label("Point atoms");
+ g_signal_connect(G_OBJECT(editor->point_atoms), "toggled", G_CALLBACK(model_editor_pointatoms_toggled), editor);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(editor->point_atoms), FALSE, TRUE, 2);
+
+ editor->symmetry = gtk_symmetry_new(2, 2, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(editor->symmetry), FALSE, FALSE, 2);
+ g_signal_connect(G_OBJECT(editor->symmetry), "changed", G_CALLBACK(model_editor_symmetry_changed), editor);
+
+ /* Add the list of atoms and Add/Remove widgets */
+ model_editor_do_list(vbox, editor);
+
+ /* Add the atomic coordinate editor */
+ editor->position_table = gtk_table_new(5, 3, FALSE);
+ gtk_table_set_homogeneous(GTK_TABLE(editor->position_table), FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(editor->position_table), 2);
+ gtk_table_set_col_spacings(GTK_TABLE(editor->position_table), 5);
+ gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(editor->position_table), FALSE, FALSE, 5);
+
+ editor->x_scale = gtk_hscale_new_with_range(0, 1, 0.05);
+ gtk_scale_set_draw_value(GTK_SCALE(editor->x_scale), FALSE);
+ //gtk_range_set_update_policy(GTK_RANGE(editor->x_scale), GTK_UPDATE_DELAYED);
+ g_signal_connect(G_OBJECT(editor->x_scale), "value-changed", G_CALLBACK(model_editor_x_scale), editor);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->x_scale), 2, 3, 1, 2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 2, 2);
+ x_scale_label = gtk_label_new("x");
+ gtk_misc_set_alignment(GTK_MISC(x_scale_label), 1.0, 0.5);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(x_scale_label), 1, 2, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
+ editor->x_edit = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(editor->x_edit), 10);
+ gtk_entry_set_width_chars(GTK_ENTRY(editor->x_edit), 8);
+ g_signal_connect(G_OBJECT(editor->x_edit), "activate", G_CALLBACK(model_editor_x_edit), editor);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->x_edit), 3, 4, 1, 2, GTK_SHRINK, GTK_SHRINK, 2, 2);
+
+ editor->y_scale = gtk_hscale_new_with_range(0, 1, 0.05);
+ gtk_scale_set_draw_value(GTK_SCALE(editor->y_scale), FALSE);
+ g_signal_connect(G_OBJECT(editor->y_scale), "value-changed", G_CALLBACK(model_editor_y_scale), editor);
+ //gtk_range_set_update_policy(GTK_RANGE(editor->y_scale), GTK_UPDATE_DELAYED);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->y_scale), 2, 3, 2, 3, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 2, 2);
+ y_scale_label = gtk_label_new("y");
+ gtk_misc_set_alignment(GTK_MISC(y_scale_label), 1.0, 0.5);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(y_scale_label), 1, 2, 2, 3, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
+ editor->y_edit = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(editor->y_edit), 10);
+ gtk_entry_set_width_chars(GTK_ENTRY(editor->y_edit), 8);
+ g_signal_connect(G_OBJECT(editor->y_edit), "activate", G_CALLBACK(model_editor_y_edit), editor);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->y_edit), 3, 4, 2, 3, GTK_SHRINK, GTK_SHRINK, 2, 2);
+
+ editor->z_scale = gtk_hscale_new_with_range(0, 1, 0.05);
+ gtk_scale_set_draw_value(GTK_SCALE(editor->z_scale), FALSE);
+ g_signal_connect(G_OBJECT(editor->z_scale), "value-changed", G_CALLBACK(model_editor_z_scale), editor);
+ //gtk_range_set_update_policy(GTK_RANGE(editor->z_scale), GTK_UPDATE_DELAYED);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->z_scale), 2, 3, 3, 4, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 2, 2);
+ z_scale_label = gtk_label_new("z");
+ gtk_misc_set_alignment(GTK_MISC(z_scale_label), 1.0, 0.5);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(z_scale_label), 1, 2, 3, 4, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
+ editor->z_edit = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(editor->z_edit), 10);
+ gtk_entry_set_width_chars(GTK_ENTRY(editor->z_edit), 8);
+ g_signal_connect(G_OBJECT(editor->z_edit), "activate", G_CALLBACK(model_editor_z_edit), editor);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->z_edit), 3, 4, 3, 4, GTK_SHRINK, GTK_SHRINK, 2, 2);
+
+ editor->b_scale = gtk_hscale_new_with_range(0, 0.001, 0.00001);
+ gtk_scale_set_draw_value(GTK_SCALE(editor->b_scale), FALSE);
+ g_signal_connect(G_OBJECT(editor->b_scale), "value-changed", G_CALLBACK(model_editor_b_scale), editor);
+ //gtk_range_set_update_policy(GTK_RANGE(editor->b_scale), GTK_UPDATE_DELAYED);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->b_scale), 2, 3, 4, 5, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 2, 2);
+ b_scale_label = gtk_label_new("B");
+ gtk_misc_set_alignment(GTK_MISC(b_scale_label), 1.0, 0.5);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(b_scale_label), 1, 2, 4, 5, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
+ editor->b_edit = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(editor->b_edit), 10);
+ gtk_entry_set_width_chars(GTK_ENTRY(editor->b_edit), 8);
+ g_signal_connect(G_OBJECT(editor->b_edit), "activate", G_CALLBACK(model_editor_b_edit), editor);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->b_edit), 3, 4, 4, 5, GTK_SHRINK, GTK_SHRINK, 2, 2);
+
+ editor->occ_scale = gtk_hscale_new_with_range(0, 1, 0.05);
+ gtk_scale_set_draw_value(GTK_SCALE(editor->occ_scale), FALSE);
+ g_signal_connect(G_OBJECT(editor->occ_scale), "value-changed", G_CALLBACK(model_editor_occ_scale), editor);
+ //gtk_range_set_update_policy(GTK_RANGE(editor->occ_scale), GTK_UPDATE_DELAYED);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->occ_scale), 2, 3, 5, 6, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 2, 2);
+ occ_scale_label = gtk_label_new("Occ");
+ gtk_misc_set_alignment(GTK_MISC(occ_scale_label), 1.0, 0.5);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(occ_scale_label), 1, 2, 5, 6, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
+ editor->occ_edit = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(editor->occ_edit), 10);
+ gtk_entry_set_width_chars(GTK_ENTRY(editor->occ_edit), 8);
+ g_signal_connect(G_OBJECT(editor->occ_edit), "activate", G_CALLBACK(model_editor_occ_edit), editor);
+ gtk_table_attach(GTK_TABLE(editor->position_table), GTK_WIDGET(editor->occ_edit), 3, 4, 5, 6, GTK_SHRINK, GTK_SHRINK, 2, 2);
+
+ g_signal_connect(G_OBJECT(editor->window), "response", G_CALLBACK(model_editor_close), editor);
+
+ gtk_widget_set_sensitive(editor->delete_button, FALSE);
+ gtk_widget_set_sensitive(editor->position_table, FALSE);
+ /* If the model is locked, disable things appropriately from the start */
+ if ( editor->model->lock_count > 0 ) model_editor_lock(editor);
+
+ gtk_widget_show_all(editor->window);
+
+ return editor;
+
+}
+