/* * model-editor.c * * GUI for editing atomic models * * (c) 2006-2007 Thomas White * * synth2d - Two-Dimensional Crystallographic Fourier Synthesis * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #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; imodel->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; }