/* Copyright (C) 2003 by Sean David Fleming sean@ivec.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The GNU GPL can also be found at http://www.gnu.org */ #include #include #include #include #include #include #include "gdis.h" #include "coords.h" #include "edit.h" #include "file.h" #include "parse.h" #include "matrix.h" #include "numeric.h" #include "surface.h" #include "select.h" #include "interface.h" #include "shortcuts.h" #include "opengl.h" /* main structures */ extern struct sysenv_pak sysenv; extern struct elem_pak elements[]; /* TODO - XML & add diffraction data to elements file */ /**************************************/ /* parse a file for gdis element data */ /**************************************/ /* type - should the element data be treated as default or patched */ /* ie the standard library, or modified values from a gdisrc file */ gint read_elem_data(FILE *fp, gint type) { gint i, n, key, flag, num_tokens; gint *set; gchar **buff, *str, *symbol, line[LINELEN]; gdouble *sfc; struct elem_pak elem, elem_default; GSList *list; /* checks */ g_return_val_if_fail(fp != NULL, 1); /* FIXME - num_keys() is returning a value that is too small */ /* n = num_keys(); */ n = 1000; set = g_malloc0(n * sizeof(gint)); while(!fgetline(fp,line)) { list = get_keywords(line); if (list) { switch(GPOINTER_TO_INT(list->data)) { case GDIS_ELEM_START: /* init for element */ elem.shell_charge = 0.0; /* init the set flags */ for (i=n ; i-- ; ) set[i] = 0; /* keep looping until end of element data, or EOF */ flag=0; while(!flag) { /* get next line & process for keywords */ if (fgetline(fp, line)) break; list = get_keywords(line); buff = tokenize(line, &num_tokens); /* process 1st keyword, and subsequent data (if any) */ if (list) { key = GPOINTER_TO_INT(list->data); g_assert(key < n); switch (key) { /* these shouldn't be modified if not default */ case SYMBOL: g_assert(num_tokens > 1); elem.symbol = g_strdup(*(buff+1)); break; case NAME: g_assert(num_tokens > 1); elem.name = g_strdup(*(buff+1)); break; case NUMBER: g_assert(num_tokens > 1); elem.number = (gint) str_to_float(*(buff+1)); set[key]++; break; case WEIGHT: g_assert(num_tokens > 1); elem.weight = str_to_float(*(buff+1)); set[key]++; break; case COVALENT: g_assert(num_tokens > 1); elem.cova = str_to_float(*(buff+1)); set[key]++; break; case VDW: g_assert(num_tokens > 1); elem.vdw = str_to_float(*(buff+1)); set[key]++; break; case CHARGE: g_assert(num_tokens > 1); elem.charge = str_to_float(*(buff+1)); set[key]++; break; case COLOUR: g_assert(num_tokens > 3); elem.colour[0] = str_to_float(*(buff+1)); elem.colour[1] = str_to_float(*(buff+2)); elem.colour[2] = str_to_float(*(buff+3)); if (VEC3MAGSQ(elem.colour) > 3.0) { VEC3MUL(elem.colour, 1.0/65535.0); } set[key]++; break; case GDIS_END: flag++; break; } } g_strfreev(buff); } /* store the element data according to type (ie global/model only etc.) */ switch(type) { case DEFAULT: if (elem.number < 0 || elem.number > MAX_ELEMENTS-1) printf("Error: Element number %d outside allocated bounds.\n", elem.number); else memcpy(&elements[elem.number], &elem, sizeof(struct elem_pak)); break; case MODIFIED: /* TODO - scan for symbol as well (elem_seek with data = NULL) */ if (!set[NUMBER]) { printf("Warning: missing element number.\n"); elem.number = 0; } /* get default values */ get_elem_data(elem.number, &elem_default, NULL); /* fill out specified values */ if (set[WEIGHT]) elem_default.weight = elem.weight; if (set[COVALENT]) elem_default.cova = elem.cova; if (set[VDW]) elem_default.vdw = elem.vdw; if (set[CHARGE]) elem_default.charge = elem.charge; if (set[COLOUR]) { elem_default.colour[0] = elem.colour[0]; elem_default.colour[1] = elem.colour[1]; elem_default.colour[2] = elem.colour[2]; } put_elem_data(&elem_default, NULL); break; /* ignore other types */ default: break; } /* ignore all other keywords */ default: break; } } /* scattering factor coeffs */ if (g_ascii_strncasecmp("\%gdis_sfc", line, 9) == 0) { while ((str = file_read_line(fp))) { buff = tokenize(str, &num_tokens); if (num_tokens != 12) { /* printf("suspicious line: %s\n", str); */ g_strfreev(buff); g_free(str); break; } symbol = g_strdup(*(buff+0)); if (elem_symbol_test(symbol)) { list = NULL; for (i=1 ; idata; if (elem) { fprintf(fp, "%%gdis_elem\n"); fprintf(fp, "number: %d\n", elem->number); fprintf(fp, "weight: %f\n", elem->weight); fprintf(fp, " cova: %f\n", elem->cova); fprintf(fp, " vdw: %f\n", elem->vdw); fprintf(fp, "charge: %f\n", elem->charge); fprintf(fp, "colour: %f %f %f\n", elem->colour[0], elem->colour[1], elem->colour[2]); fprintf(fp, "%%gdis_end\n"); } list = g_slist_next(list); } return(0); } void write_sfc(gpointer key, gpointer val, gpointer data) { GSList *list; FILE *fp = data; fprintf(fp, "%s", (gchar *) key); for (list=val ; list ; list=g_slist_next(list)) fprintf(fp, " %f", *((gdouble *) list->data)); fprintf(fp, " \n"); } void write_sfc_data(FILE *fp) { fprintf(fp, "%%gdis_sfc\n"); g_hash_table_foreach(sysenv.sfc_table, &write_sfc, fp); fprintf(fp, "%%gdis_end\n"); } /***************************************/ /* find all unique elements in a model */ /***************************************/ #define DEBUG_FIND_UNIQUE 0 GSList *find_unique(gint mode, struct model_pak *model) { gint found; GSList *list, *types, *unique; struct core_pak *core; unique = NULL; /* go through all atoms */ for (list=model->cores ; list ; list=g_slist_next(list)) { core = list->data; /* determine if current atom type is in the list */ found=0; for (types=unique ; types ; types = g_slist_next(types)) { switch(mode) { case ELEMENT: if (GPOINTER_TO_INT(types->data) == core->atom_code) found++; break; case LABEL: case LABEL_NORMAL: case LABEL_GHOST: if (g_ascii_strcasecmp(types->data, core->atom_label) == 0) found++; break; } if (found) break; } /* not in list, so add it */ if (!found) { switch(mode) { case ELEMENT: unique = g_slist_prepend(unique, GINT_TO_POINTER(core->atom_code)); break; case LABEL: unique = g_slist_prepend(unique, g_strdup(core->atom_label)); break; case LABEL_NORMAL: if (!core->ghost) unique = g_slist_prepend(unique, g_strdup(core->atom_label)); break; case LABEL_GHOST: if (core->ghost) unique = g_slist_prepend(unique, g_strdup(core->atom_label)); break; } } } #if DEBUG_FIND_UNIQUE printf("Found: "); for (types=unique ; types ; types = g_slist_next(types)) { switch(mode) { case ELEMENT: printf("[%3d] ", GPOINTER_TO_INT(types->data)); break; case LABEL: case LABEL_NORMAL: case LABEL_GHOST: printf("[%s] ", (gchar *) types->data); break; } } printf("\n"); #endif /* return reversed list (preserves order) */ return(g_slist_reverse(unique)); } /***********************/ /* set the atom colour */ /***********************/ void init_atom_colour(struct core_pak *core, struct model_pak *model) { struct elem_pak elem_data; get_elem_data(core->atom_code, &elem_data, model); ARR3SET(core->colour, elem_data.colour); VEC3MUL(core->colour, 65535.0); if (core->ghost) core->colour[3] = 0.5; else core->colour[3] = 1.0; } /***********************/ /* set the atom charge */ /***********************/ void init_atom_charge(struct core_pak *core, struct model_pak *model) { struct elem_pak elem_data; if (core->lookup_charge) { get_elem_data(core->atom_code, &elem_data, model); core->charge = elem_data.charge; } } /************************/ /* set the atom charges */ /************************/ void init_model_charges(struct model_pak *model) { GSList *list; for (list=model->cores ; list ; list=g_slist_next(list)) init_atom_charge(list->data, model); } /*******************************************/ /* net charge on atom (ie including shell) */ /*******************************************/ gdouble atom_charge(struct core_pak *core) { gdouble q; struct shel_pak *shell; q = core->charge; if (core->shell) { shell = core->shell; q += shell->charge; } return(q); } /********************************************/ /* initialize element properties for a core */ /********************************************/ void elem_init(struct core_pak *core, struct model_pak *model) { struct elem_pak elem; g_assert(model != NULL); g_assert(core != NULL); /* NB: assumes core->atom_code is the atomic number */ get_elem_data(core->atom_code, &elem, model); core->atom_code = elem.number; core->bond_cutoff = elem.cova; core->charge = elem.charge; ARR3SET(core->colour, elem.colour); VEC3MUL(core->colour, 65535.0); } /*********************************************************/ /* compute net charge and dipole (if model is a surface) */ /*********************************************************/ #define DEBUG_CALC_EMP 0 void calc_emp(struct model_pak *data) { gdouble qsum, x[3], p[3]; GSList *list; struct core_pak *core; struct shel_pak *shell; /* checks */ g_assert(data != NULL); /* TODO - speed up by getting to a local var the elem data for unique atoms */ /* cores & shell dipole calc */ qsum=0.0; VEC3SET(p, 0.0, 0.0, 0.0); for (list=data->cores ; list ; list=g_slist_next(list)) { core = list->data; /* if (core->region != REGION1A) continue; */ if (core->status & DELETED) continue; ARR3SET(x, core->x); vecmat(data->latmat, x); /* dipole */ VEC3MUL(x, core->charge); ARR3ADD(p, x); /* monopole */ qsum += core->charge; /* NB: add shell constribution at the core's z location */ if (core->shell) { shell = core->shell; ARR3SET(x, shell->x); vecmat(data->latmat, x); /* dipole */ VEC3MUL(x, shell->charge); ARR3ADD(p, x); /* monopole */ qsum += shell->charge; } } #if DEBUG_CALC_EMP printf("surface: %f %f %f (%f)\n", data->surface.miller[0], data->surface.miller[1], data->surface.miller[2], data->surface.shift); P3VEC("dipole: ", p); printf("sum charge: %e\n", qsum); if (qsum*qsum > FRACTION_TOLERANCE) printf("Warning: your model has a net charge = %f\n", qsum); #endif /* only surfaces get the z dipole */ if (data->periodic == 2) data->gulp.sdipole = p[2]; data->gulp.qsum = qsum; } /***************************************************/ /* does a given string represent an atomic number? */ /***************************************************/ gint elem_number_test(const gchar *input) { gint n=0; if (str_is_float(input)) { n = str_to_float(input); if (n<0 || n>MAX_ELEMENTS-1) n=0; } return(n); } /***************************************************/ /* does a given string represent an element symbol */ /***************************************************/ #define DEBUG_ELEM_TYPE 0 gint elem_symbol_test(const gchar *input) { gint i, j, m, n; gchar *elem1, **buff; /* checks */ if (input == NULL) return(0); /* zero length string matches something, so force it to return 0 */ if (!strlen(input)) return(0); /* duplicate for manipulation */ elem1 = g_strdup(input); /* remove anything but alphabetic chars */ for (i=0 ; ielements ; list ; list=g_slist_next(list)) { elem_data = list->data; if (code == elem_data->number) { #if DEBUG_GET_ELEM printf("Retrieving local exception.\n"); #endif memcpy(elem, elem_data, sizeof(struct elem_pak)); return(0); } } } /* search global exceptions */ for (list=sysenv.elements ; list ; list=g_slist_next(list)) { elem_data = list->data; if (code == elem_data->number) { #if DEBUG_GET_ELEM printf("Retrieving global exception.\n"); #endif memcpy(elem, elem_data, sizeof(struct elem_pak)); return(0); } } /* return from the standard database */ if (code >= 0 && code < sysenv.num_elements) { #if DEBUG_GET_ELEM printf("Retrieving default.\n"); #endif memcpy(elem, &elements[code], sizeof(struct elem_pak)); return(0); } #if DEBUG_GET_ELEM printf("ERROR: bad element code.\n"); #endif return(1); } /**********************************/ /* store non-default element data */ /**********************************/ #define DEBUG_PUT_ELEM_DATA 0 void put_elem_data(struct elem_pak *elem, struct model_pak *model) { gint flag, create; GSList *list, *elements; struct elem_pak *elem_data; struct core_pak *core; /* checks */ g_return_if_fail(elem != NULL); #if DEBUG_PUT_ELEM_DATA printf(" *** Saving element ***\n"); printf("symbol: %s\n", elem->symbol); printf(" name: %s\n", elem->name); printf("number: %d\n", elem->number); printf("weight: %f\n", elem->weight); printf(" cova: %f\n", elem->cova); printf(" vdw: %f\n", elem->vdw); printf("charge: %f\n", elem->charge); printf("colour: %f %f %f\n", elem->colour[0], elem->colour[1], elem->colour[2]); #endif /* global or local database */ if (model) { elements = model->elements; flag = TRUE; } else { elements = sysenv.elements; flag = FALSE; } /* replace element if exists */ create = TRUE; for (list=elements ; list ; list=g_slist_next(list)) { elem_data = list->data; if (elem_data->number == elem->number) { #if DEBUG_PUT_ELEM_DATA printf("replacing existing...\n"); #endif memcpy(elem_data, elem, sizeof(struct elem_pak)); create = FALSE; break; } } /* create new item if it didn't exist */ if (create) { #if DEBUG_PUT_ELEM_DATA printf("creating new exception...\n"); #endif elem_data = g_malloc(sizeof(struct elem_pak)); memcpy(elem_data, elem, sizeof(struct elem_pak)); if (flag) model->elements = g_slist_prepend(model->elements, elem_data); else sysenv.elements = g_slist_prepend(sysenv.elements, elem_data); } /* update atom bond_cutoff */ if (flag) { for (list=model->cores ; list ; list=g_slist_next(list)) { core = list->data; if (core->atom_code == elem->number) core->bond_cutoff = elem->cova; } } } /* globals for the atom properties dialog */ GtkWidget *apd_label, *apd_type, *apd_charge, *apd_x, *apd_y, *apd_z; GtkWidget *apd_growth, *apd_region, *apd_translate; struct model_pak *apd_data=NULL; struct core_pak *apd_core=NULL; /*************************************************************/ /* get the nth colour in a sequence (eg sample RGB spectrum) */ /*************************************************************/ void get_colour(gdouble *colour, gint n) { gint byte; gdouble r, g, b, f; byte = 1 + n % 7; if (byte & 4) r = 1.0; else r = 0.0; if (byte & 2) g = 1.0; else g = 0.0; if (byte & 1) b = 1.0; else b = 0.0; f = n / 7; f *= 0.5; f += 1.0; f = 1.0/f; r *= f; g *= f; b *= f; VEC3SET(colour, r, g, b); } /****************************************/ /* change the colour scheme for an atom */ /****************************************/ void atom_colour_scheme(gint type, struct core_pak *core, struct model_pak *model) { gdouble t; struct elem_pak elem; switch (type) { case ELEM: get_elem_data(core->atom_code, &elem, model); break; case MOL: /* get the sequence number for the colour type */ /* NB: core->molecule is deprec. */ get_colour(elem.colour, core->molecule); break; case OCCUPANCY: VEC3MUL(core->colour, core->sof); return; case REGION: /* get the sequence number for the colour type */ get_colour(elem.colour, core->region); break; case GROWTH_SLICE: if (core->growth) { VEC3SET(elem.colour, 0.5, 0.5, 0.5); } else { get_elem_data(core->atom_code, &elem, model); } break; case TRANSLATE: if (core->translate) { VEC3SET(elem.colour, 0.5, 0.5, 0.5); } else { get_elem_data(core->atom_code, &elem, model); } break; case VELOCITY: #define BC 1.3806503 #define AN 6.0221420 #define TMIN 0.0 #define TRANGE 2000.0 get_elem_data(core->atom_code, &elem, model); t = elem.weight * VEC3MAGSQ(core->v) * 10.0 / (3.0*AN*BC); /* printf("T = %f\n", t); */ /* clamp */ t -= TMIN; if (t > TRANGE) { /* printf("tmax = %f\n", t + TMIN); */ t = TRANGE; } if (t < 0.0) t = 0.0; /* bright red when hot (TMAX) */ elem.colour[0] = t/TRANGE; elem.colour[1] = 0.0; /* dark blue when cold */ elem.colour[2] = 0.5 * (1.0 - t/TRANGE); break; } ARR3SET(core->colour, elem.colour); VEC3MUL(core->colour, 65535.0); } /*************************************/ /* set the colour scheme for a model */ /*************************************/ void model_colour_scheme(gint type, struct model_pak *model) { GSList *list; struct core_pak *core; model->colour_scheme = type; for (list=model->cores ; list ; list=g_slist_next(list)) { core = (struct core_pak *) list->data; atom_colour_scheme(type, core, model); } } /***********************************************/ /* change the properties of all selected atoms */ /***********************************************/ /* NB: this is a bit dangerous as you change everything in the */ /* selection to the specified value - even (eg) incompatible elements */ void selection_properties_change(gint type) { gint n, growth, region, translate; gdouble charge; const gchar *text; GSList *list; struct elem_pak edata; struct model_pak *model; struct core_pak *core; model = sysenv.active_model; if (!model) return; if (!model->selection) return; switch (type) { case NAME: text = gtk_entry_get_text(GTK_ENTRY(apd_label)); n = elem_symbol_test(text); if (n) { get_elem_data(n, &edata, model); /* make sure we alow enough space for the string and the \0 */ n = (LABEL_SIZE-1 > strlen(text)) ? strlen(text) : LABEL_SIZE-1; for (list=model->selection ; list ; list=g_slist_next(list)) { core = list->data; g_free(core->atom_label); core->atom_label = g_strdup(text); /* update atttached shell */ if (core->shell) { struct shel_pak *shell = core->shell; g_free(shell->shell_label); shell->shell_label = g_strdup(text); } /* NEW - don't update element specific data if the element type was not */ /* changed - ie the user has just made a labelling change (eg C -> C1) */ if (edata.number != core->atom_code) { core->atom_code = edata.number; core->bond_cutoff = edata.cova; } init_atom_colour(core, model); init_atom_charge(core, model); } /* model updates */ g_slist_free(model->unique_atom_list); model->unique_atom_list = find_unique(ELEMENT, model); calc_emp(model); } break; case CHARGE: charge = str_to_float(gtk_entry_get_text(GTK_ENTRY(apd_charge))); for (list=model->selection ; list ; list=g_slist_next(list)) { core = list->data; /* core updates */ core->charge = charge; core->lookup_charge = FALSE; } calc_emp(model); break; case CORE_GROWTH_SLICE: growth = str_to_float(gtk_entry_get_text(GTK_ENTRY(apd_growth))); growth = CLAMP(growth, 0, 1); for (list=model->selection ; list ; list=g_slist_next(list)) { core = list->data; core->growth = growth; if (model->colour_scheme == GROWTH_SLICE) atom_colour_scheme(GROWTH_SLICE, core, model); } break; case CORE_REGION: region = str_to_float(gtk_entry_get_text(GTK_ENTRY(apd_region))); if (region > model->region_max) model->region_max = region; for (list=model->selection ; list ; list=g_slist_next(list)) { core = list->data; core->region = region; if (core->shell) (core->shell)->region = region; if (model->colour_scheme == REGION) atom_colour_scheme(REGION, core, model); } break; case CORE_TRANSLATE: translate = str_to_float(gtk_entry_get_text(GTK_ENTRY(apd_translate))); translate = CLAMP(translate, 0, 1); for (list=model->selection ; list ; list=g_slist_next(list)) { core = list->data; core->translate = translate; if (core->shell) (core->shell)->translate = translate; if (model->colour_scheme == TRANSLATE) atom_colour_scheme(TRANSLATE, core, model); } break; case CORE_FF: text = gtk_entry_get_text(GTK_ENTRY(apd_type)); for (list=model->selection ; list ; list=g_slist_next(list)) { core = list->data; if (core->atom_type) g_free(core->atom_type); core->atom_type = g_strdup(text); } break; } gui_refresh(GUI_MODEL_PROPERTIES); gui_refresh(GUI_CANVAS); } /*****************************/ /* commit changes to an atom */ /*****************************/ void atom_properties_change(GtkWidget *w, gint type) { gint n, growth, region, translate; const gchar *text; struct elem_pak edata; struct model_pak *model; model = sysenv.active_model; if (!model) return; /* act on multiple atoms? */ if (g_slist_length(model->selection) > 1) { selection_properties_change(type); return; } if (!apd_core) return; switch(type) { case NAME: text = gtk_entry_get_text(GTK_ENTRY(apd_label)); g_free(apd_core->atom_label); apd_core->atom_label = g_strdup(text); n = elem_symbol_test(text); /* update atttached shell */ if (apd_core->shell) { struct shel_pak *shell = apd_core->shell; g_free(shell->shell_label); shell->shell_label = g_strdup(text); } /* if recognized -> update */ if (n) { get_elem_data(n, &edata, model); /* NEW - don't update element specific data if the element type was not */ /* changed - ie the user has just made a labelling change (eg C -> C1) */ if (n != apd_core->atom_code) { apd_core->atom_code = n; apd_core->bond_cutoff = edata.cova; } init_atom_colour(apd_core, model); init_atom_charge(apd_core, model); g_slist_free(model->unique_atom_list); model->unique_atom_list = find_unique(ELEMENT, model); calc_emp(model); /* REFRESH */ gui_refresh(GUI_MODEL_PROPERTIES); } break; case CORE_FF: text = gtk_entry_get_text(GTK_ENTRY(apd_type)); if (apd_core->atom_type) g_free(apd_core->atom_type); apd_core->atom_type = g_strdup(text); break; case CHARGE: text = gtk_entry_get_text(GTK_ENTRY(apd_charge)); apd_core->charge = str_to_float(text); apd_core->lookup_charge = FALSE; calc_emp(model); break; case COORD_X: text = gtk_entry_get_text(GTK_ENTRY(apd_x)); apd_core->x[0] = str_to_float(text); coords_compute(model); break; case COORD_Y: text = gtk_entry_get_text(GTK_ENTRY(apd_y)); apd_core->x[1] = str_to_float(text); coords_compute(model); break; case COORD_Z: text = gtk_entry_get_text(GTK_ENTRY(apd_z)); apd_core->x[2] = str_to_float(text); coords_compute(model); break; case CORE_GROWTH_SLICE: text = gtk_entry_get_text(GTK_ENTRY(apd_growth)); growth = CLAMP(str_to_float(text), 0, 1); apd_core->growth = growth; if (model->colour_scheme == GROWTH_SLICE) atom_colour_scheme(GROWTH_SLICE, apd_core, model); break; case CORE_REGION: text = gtk_entry_get_text(GTK_ENTRY(apd_region)); region = str_to_float(text); if (region > model->region_max) model->region_max = region; apd_core->region = region; if (apd_core->shell) (apd_core->shell)->region = region; if (model->colour_scheme == REGION) atom_colour_scheme(REGION, apd_core, model); break; case CORE_TRANSLATE: text = gtk_entry_get_text(GTK_ENTRY(apd_translate)); translate = CLAMP(str_to_float(text), 0, 1); apd_core->translate = translate; if (apd_core->shell) (apd_core->shell)->translate = translate; if (model->colour_scheme == TRANSLATE) atom_colour_scheme(TRANSLATE, apd_core, model); break; default: printf("Not yet modifiable...\n"); } gui_refresh(GUI_CANVAS); } /*************************************/ /* updates the dialog for a new atom */ /*************************************/ void gui_refresh_selection(void) { gdouble q; gchar *element, *label, *type, *charge, *x, *y, *z, *growth, *region, *translate; struct core_pak *core; struct model_pak *model; model = sysenv.active_model; core = NULL; if (model) { GSList *list = model->selection; if (g_slist_length(list) == 1) core = list->data; } if (core && model) { /* data available */ element = g_strdup(elements[core->atom_code].symbol); label = g_strdup(core->atom_label); if (core->atom_type) type = g_strdup(core->atom_type); else type = g_strdup(""); q = atom_charge(core); /* Replaced by C. Fisher 2004 */ charge = g_strdup_printf("%9.4f", q); x = g_strdup_printf("%9.4f", core->x[0]); y = g_strdup_printf("%9.4f", core->x[1]); z = g_strdup_printf("%9.4f", core->x[2]); growth = g_strdup_printf("%d", core->growth); region = g_strdup_printf("%d", core->region); translate = g_strdup_printf("%d", core->translate); apd_core = core; } else { /* otherwise defaults */ element = g_strdup(""); label = g_strdup(""); type = g_strdup(""); charge = g_strdup(""); x = g_strdup(""); y = g_strdup(""); z = g_strdup(""); growth = g_strdup(""); region = g_strdup(""); translate = g_strdup(""); } /* prevent changes from messing up the atom_properties_change() callback */ apd_data = NULL; /* entry updates */ gtk_entry_set_text(GTK_ENTRY(apd_label), label); gtk_entry_set_text(GTK_ENTRY(apd_type), type); gtk_entry_set_text(GTK_ENTRY(apd_charge), charge); gtk_entry_set_text(GTK_ENTRY(apd_x), x); gtk_entry_set_text(GTK_ENTRY(apd_y), y); gtk_entry_set_text(GTK_ENTRY(apd_z), z); gtk_entry_set_text(GTK_ENTRY(apd_growth), growth); gtk_entry_set_text(GTK_ENTRY(apd_region), region); gtk_entry_set_text(GTK_ENTRY(apd_translate), translate); apd_data = model; /* cleanup */ g_free(element); g_free(label); g_free(type); g_free(charge); g_free(x); g_free(y); g_free(z); g_free(growth); g_free(region); g_free(translate); } /*******************************************/ /* display the properties of a single atom */ /*******************************************/ void gui_edit_widget(GtkWidget *box) { GtkWidget *frame, *hbox, *vbox, *entry; /* checks */ g_return_if_fail(box != NULL); /* two column element data display */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 0); /* left vbox - titles */ vbox = gtk_vbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); /* TODO - put in a for loop? */ entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "Label"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "FF Type"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "X"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "Y"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "Z"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "Charge"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "Growth"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "Region"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), "Translate"); gtk_entry_set_editable(GTK_ENTRY(entry), FALSE); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); /* right vbox - data */ vbox = gtk_vbox_new(TRUE, 0); gtk_box_pack_end(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); apd_label = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_label, FALSE, FALSE, 0); apd_type = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_type, FALSE, FALSE, 0); apd_x = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_x, FALSE, FALSE, 0); apd_y = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_y, FALSE, FALSE, 0); apd_z = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_z, FALSE, FALSE, 0); apd_charge = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_charge, FALSE, FALSE, 0); apd_growth = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_growth, FALSE, FALSE, 0); apd_region = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_region, FALSE, FALSE, 0); apd_translate = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), apd_translate, FALSE, FALSE, 0); /* attach callbacks (NB: set initial data first) */ g_signal_connect(GTK_OBJECT(apd_label), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(NAME)); g_signal_connect(GTK_OBJECT(apd_type), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(CORE_FF)); g_signal_connect(GTK_OBJECT(apd_x), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(COORD_X)); g_signal_connect(GTK_OBJECT(apd_y), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(COORD_Y)); g_signal_connect(GTK_OBJECT(apd_z), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(COORD_Z)); g_signal_connect(GTK_OBJECT(apd_charge), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(CHARGE)); g_signal_connect(GTK_OBJECT(apd_growth), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(CORE_GROWTH_SLICE)); g_signal_connect(GTK_OBJECT(apd_region), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(CORE_REGION)); g_signal_connect(GTK_OBJECT(apd_translate), "activate", GTK_SIGNAL_FUNC(atom_properties_change), GINT_TO_POINTER(CORE_TRANSLATE)); /* CURRENT */ frame = gtk_frame_new(NULL); gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(frame), PANEL_SPACING); vbox = gtk_vbox_new(TRUE, 1); gtk_container_add(GTK_CONTAINER(frame), vbox); gui_button_x("Add atoms", gtk_mode_switch, (gpointer) ATOM_ADD, vbox); gui_button_x("Add bonds", gtk_mode_switch, (gpointer) BOND_SINGLE, vbox); gui_button_x("Delete bonds", gtk_mode_switch, (gpointer) BOND_DELETE, vbox); gui_button_x("Normal mode", gtk_mode_switch, (gpointer) FREE, vbox); frame = gtk_frame_new(NULL); gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(frame), PANEL_SPACING); vbox = gtk_vbox_new(TRUE, 1); gtk_container_add(GTK_CONTAINER(frame), vbox); gui_button_x("Mark as ghost", select_flag_ghost, NULL, vbox); gui_button_x("Mark as normal", select_flag_normal, NULL, vbox); }