/*
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 <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
#include "gdis.h"
#include "coords.h"
#include "edit.h"
#include "file.h"
#include "parse.h"
#include "library.h"
#include "matrix.h"
#include "zmatrix.h"
#include "measure.h"
#include "model.h"
#include "morph.h"
#include "numeric.h"
#include "select.h"
#include "space.h"
#include "spatial.h"
#include "surface.h"
#include "shortcuts.h"
#include "type.h"
#include "interface.h"
#include "dialog.h"
#include "opengl.h"
#include "zone.h"
#define DEBUG 0
extern struct sysenv_pak sysenv;
extern struct elem_pak elements[];
extern GtkWidget *apd_label;
extern GtkWidget *window;
/* globals */
gdouble tmat[9];
gdouble tvec[3];
gdouble edit_anim_n=0;
gdouble edit_chirality[2] = {6, 6};
gdouble edit_length = 1.44;
gpointer edit_construct;
gchar *edit_basis[2] = {NULL, NULL};
GtkWidget *elem_entry, *grid_dim, *grid_sep;
GtkWidget *axis_entry, *obj_entry, *periodicity_spin;
GtkWidget *transmat[12];
/* NEW */
gdouble edit_spatial_colour[3] = {1.0, 0.0, 0.0};
gdouble edit_label_colour[3] = {1.0, 1.0, 1.0};
enum{AT_ANY, AT_SELECTED, AT_LATTICE};
/*********************************************/
/* update widget values with internal values */
/*********************************************/
void update_transmat(void)
{
gint i, j;
gchar *text;
/* set transformation matrix widget entries */
for (j=0 ; j<3 ; j++)
{
for (i=0 ; i<3 ; i++)
{
text = g_strdup_printf("%f", tmat[3*j+i]);
/* NB: display transpose */
gtk_entry_set_text(GTK_ENTRY(transmat[3*j+i]), text);
g_free(text);
}
}
/* set translation widget entries */
for (i=0 ; i<3 ; i++)
{
text = g_strdup_printf("%f", tvec[i]);
gtk_entry_set_text(GTK_ENTRY(transmat[9+i]), text);
g_free(text);
}
}
/********************************************/
/* restore original transformation settings */
/********************************************/
void reset_transmat(void)
{
VEC3SET(tvec, 0.0, 0.0, 0.0);
matrix_identity(tmat);
update_transmat();
}
/*************************************/
/* construct a transformation matrix */
/*************************************/
void construct_transmat(void)
{
gint n, flag=0, type=-1;
const gchar *text;
gdouble angle;
gdouble v1[3];
struct vec_pak *p[3];
struct spatial_pak *spatial=NULL;
struct model_pak *data;
/* checks */
data = sysenv.active_model;
if (!data)
return;
if (!GTK_IS_ENTRY(edit_construct))
return;
/* requested transformation */
text = gtk_entry_get_text(GTK_ENTRY(edit_construct));
if (g_ascii_strncasecmp(text, "z alignment", 11) == 0)
type = ALIGNMENT;
if (g_ascii_strncasecmp(text, "reflection", 10) == 0)
type = REFLECTION;
if (g_ascii_strncasecmp(text, "rotation", 8) == 0)
type = PAXIS;
if (g_ascii_strncasecmp(text, "lattice", 7) == 0)
type = LATMAT;
if (g_ascii_strncasecmp(text, "identity", 8) == 0)
type = IDENTITY;
/* special cases */
switch(type)
{
case IDENTITY:
reset_transmat();
return;
case LATMAT:
memcpy(tmat, data->latmat, 9*sizeof(gdouble));
VEC3SET(tvec, 0.0, 0.0, 0.0);
update_transmat();
return;
}
/* rotation angle */
text = gtk_entry_get_text(GTK_ENTRY(axis_entry));
angle = str_to_float(text);
/* check for special reference objects */
text = gtk_entry_get_text(GTK_ENTRY(obj_entry));
if (g_ascii_strncasecmp("x", text, 1) == 0)
flag = 1;
if (g_ascii_strncasecmp("y", text, 1) == 0)
flag = 2;
if (g_ascii_strncasecmp("z", text, 1) == 0)
flag = 3;
if (g_ascii_strncasecmp("a", text, 1) == 0)
flag = 4;
if (g_ascii_strncasecmp("b", text, 1) == 0)
flag = 5;
if (g_ascii_strncasecmp("c", text, 1) == 0)
flag = 6;
/* construct appropriate reference vector */
switch (flag)
{
case 1:
VEC3SET(v1, 1.0, 0.0, 0.0);
break;
case 2:
VEC3SET(v1, 0.0, 1.0, 0.0);
break;
case 3:
VEC3SET(v1, 0.0, 0.0, 1.0);
break;
case 4:
VEC3SET(v1, 1.0, 0.0, 0.0);
vecmat(data->latmat, v1);
break;
case 5:
VEC3SET(v1, 0.0, 1.0, 0.0);
vecmat(data->latmat, v1);
break;
case 6:
VEC3SET(v1, 0.0, 0.0, 1.0);
vecmat(data->latmat, v1);
break;
default:
/* no special reference object - assume a numerical spatial reference */
n = str_to_float(text);
spatial = g_slist_nth_data(data->spatial, n);
if (!spatial)
{
gui_text_show(ERROR, "Undefined reference spatial object.\n");
return;
}
/* compute orientation vector (plane normal/vector direction) */
switch (spatial->type)
{
case SPATIAL_VECTOR:
p[0] = g_slist_nth_data(spatial->list, 0);
p[1] = g_slist_nth_data(spatial->list, 1);
g_assert(p[0] != NULL);
g_assert(p[1] != NULL);
/* vector points from 1st to 2nd */
ARR3SET(v1, p[1]->rx);
ARR3SUB(v1, p[0]->rx);
break;
default:
p[0] = g_slist_nth_data(spatial->list, 0);
p[1] = g_slist_nth_data(spatial->list, 1);
p[2] = g_slist_nth_data(spatial->list, 2);
g_assert(p[0] != NULL);
g_assert(p[1] != NULL);
g_assert(p[2] != NULL);
calc_norm(v1, p[0]->rx, p[1]->rx, p[2]->rx);
break;
}
break;
}
/* construct */
switch (type)
{
case ALIGNMENT:
matrix_z_alignment(tmat, v1);
break;
case PAXIS:
matrix_v_rotation(tmat, v1, D2R*angle);
break;
case REFLECTION:
matrix_v_reflection(tmat, v1);
break;
}
VEC3SET(tvec, 0.0, 0.0, 0.0);
update_transmat();
}
/********************************************/
/* put text entry values into actual matrix */
/********************************************/
void change_transmat(GtkWidget *w, gint i)
{
const gchar *text;
text = gtk_entry_get_text(GTK_ENTRY(transmat[i]));
if (i < 9)
tmat[i] = str_to_float(text);
else
tvec[i-9] = str_to_float(text);
}
/************************************************/
/* apply the current transformation/translation */
/************************************************/
void apply_transmat(GtkWidget *w, gint mode)
{
GSList *item, *list=NULL;
struct model_pak *data;
struct core_pak *core;
struct shel_pak *shel;
data = sysenv.active_model;
if (!data)
return;
/* application mode */
switch(mode)
{
case AT_ANY:
list = data->cores;
break;
case AT_SELECTED:
list = data->selection;
break;
case AT_LATTICE:
matrix_lattice_new(tmat, data);
return;
default:
g_assert_not_reached();
}
for (item=list ; item ; item=g_slist_next(item))
{
core = item->data;
/* transform */
vecmat(data->latmat, core->x);
vecmat(tmat, core->x);
ARR3ADD(core->x, tvec);
vecmat(data->ilatmat, core->x);
/* assoc. shell? */
if (core->shell)
{
shel = core->shell;
/* transform */
vecmat(data->latmat, shel->x);
vecmat(tmat, shel->x);
ARR3ADD(shel->x, tvec);
vecmat(data->ilatmat, shel->x);
}
}
/* update */
coords_compute(data);
zone_init(data);
connect_bonds(data);
connect_molecules(data);
redraw_canvas(SINGLE);
}
/***************************************************/
/* construct animation using multiple applications */
/***************************************************/
/* FIXME - this is all broken (due to new quat based camera) */
void apply_n_transmat(GtkWidget *w, gint mode)
{
/*
gint i;
gdouble mat[9];
struct model_pak *model;
struct transform_pak *transform;
model = sysenv.active_model;
if (!model)
return;
dialog_destroy_single(ANIM, model);
memcpy(mat, model->rotmat, 9*sizeof(gdouble));
for (i=0 ; i<edit_anim_n ; i++)
{
transform = g_malloc(sizeof(struct transform_pak));
model->transform_list = g_slist_append(model->transform_list, transform);
transform->id = ROTATION;
transpose(mat);
matmat(tmat, mat);
transpose(mat);
memcpy(transform->matrix, mat, 9*sizeof(gdouble));
memcpy(transform->matrix, tmat, 9*sizeof(gdouble));
VEC3SET(transform->vector, model->offset[0], model->offset[1], 0.0);
transform->scalar = model->scale;
model->num_frames++;
}
if (model->num_frames)
model->animation = TRUE;
redraw_canvas(SINGLE);
*/
}
/*********************************************/
/* find and record the maximum region number */
/*********************************************/
gint region_max(struct model_pak *mdata)
{
gint max;
GSList *list;
struct core_pak *core;
max = 0;
for (list=mdata->cores ; list ; list=g_slist_next(list))
{
core = list->data;
if (core->region > max)
max = core->region;
}
return(max);
}
/*************************************************************/
/* region changing routine - for dealing with polar surfaces */
/*************************************************************/
/* can now go both ways via the direction flag (UP or DOWN) */
#define DEBUG_REGION_SWITCH_ATOM 0
gint region_move_atom(struct core_pak *core, gint direction,
struct model_pak *data)
{
gint flag, primary, secondary, mov[2];
gdouble vec[3], tmp[3], d[3];
GSList *list;
struct core_pak *comp;
#if DEBUG_REGION_SWITCH_ATOM
printf(" model: %s\n", data->basename);
printf(" periodicity: %d\n", data->periodic);
printf(" hkl: %f %f %f\n", data->surface.miller[0],
data->surface.miller[1], data->surface.miller[2]);
printf(" dhkl: %f\n", data->surface.dspacing);
printf("region sizes: %f %f\n", data->surface.region[0], data->surface.region[1]);
printf(" moving: ");
if (direction == UP)
printf("UP\n");
else
printf("DOWN\n");
#endif
/* checks */
g_return_val_if_fail(data != NULL, 1);
g_return_val_if_fail(data->periodic == 2, 1);
if (data->surface.region[0] < 1)
{
gui_text_show(ERROR, "region 1 is empty.\n");
return(1);
}
/* setup region switching labels */
if (direction == UP)
{
primary = REGION1A;
secondary = REGION2A;
}
else
{
primary = REGION2A;
secondary = REGION1A;
}
/* get fractional depth translation vector */
ARR3SET(vec, data->surface.depth_vec);
vecmat(data->ilatmat, vec);
/* calculate offset to region boundary */
ARR3SET(tmp, vec);
if (direction == DOWN)
{
VEC3MUL(tmp, data->surface.region[0]);
VEC3MUL(tmp, -1.0);
}
else
{
if (data->surface.region[1] == 0)
{
VEC3MUL(tmp, data->surface.region[0]);
}
else
{
VEC3MUL(tmp, data->surface.region[1]);
}
}
/* if region 2 is empty, just move core to the bottom */
if (data->surface.region[1] == 0.0)
{
ARR3ADD(core->x, tmp);
if (core->shell)
{
ARR3ADD((core->shell)->x, tmp);
}
atom_colour_scheme(data->colour_scheme, core, data);
return(0);
}
/* get coordinates of target atom */
ARR3ADD(tmp, core->x);
#if DEBUG_REGION_SWITCH_ATOM
P3VEC(" translation: ", vec);
P3VEC(" target coords: ", tmp);
#endif
/* find the target */
flag=0;
for (list=data->cores ; list ; list=g_slist_next(list))
{
comp = list->data;
/* only atoms of the same type need apply */
if (core->atom_code != comp->atom_code)
continue;
/* get difference vector */
ARR3SET(d, comp->x);
ARR3SUB(d, tmp);
/* pbc constraint */
while(d[0] < -FRACTION_TOLERANCE)
d[0] += 1.0;
while(d[0] > 0.5)
d[0] -= 1.0;
while(d[1] < -FRACTION_TOLERANCE)
d[1] += 1.0;
while(d[1] > 0.5)
d[1] -= 1.0;
/* test difference vector's magnitude */
if (VEC3MAGSQ(d) < FRACTION_TOLERANCE)
{
/* change its labelling */
#if DEBUG_REGION_SWITCH_ATOM
printf("Matched core: %p\n", comp);
#endif
comp->region = secondary;
if (comp->shell)
{
(comp->shell)->region = secondary;
}
atom_colour_scheme(data->colour_scheme, comp, data);
flag++;
break;
}
}
if (!flag)
{
gui_text_show(ERROR, "Failed to find a boundary image.\n");
return(1);
}
/* now move selected atom to bottom of region 2 */
ARR3SET(tmp, vec);
VEC3MUL(tmp, (data->surface.region[0] + data->surface.region[1]));
if (direction == UP)
VEC3MUL(tmp, -1.0);
ARR3SUB(core->x, tmp);
core->region = primary;
/* pbc constrain */
fractional_clamp(core->x, mov, 2);
if (core->shell)
{
ARR3SUB((core->shell)->x, tmp);
ARR2ADD((core->shell)->x, mov);
(core->shell)->region = primary;
}
atom_colour_scheme(data->colour_scheme, core, data);
return(0);
}
/********************************************/
/* move a selection using the above routine */
/********************************************/
#define DEBUG_REGION_MOVE 0
void region_move(GtkWidget *w, gint direction)
{
gchar txt[60];
GSList *list;
struct model_pak *data;
struct core_pak *core;
data = sysenv.active_model;
/* checks */
if (!data)
return;
if (data->periodic != 2)
return;
if (!data->selection)
{
gui_text_show(WARNING, "Empty selection.\n");
return;
}
#if DEBUG_REGION_MOVE
P3MAT("depth vec:", data->surface.depth_vec);
#endif
/* quit if no depth info ie a loaded 2D file */
if (VEC3MAG(data->surface.depth_vec) < FRACTION_TOLERANCE)
{
gui_text_show(ERROR,
"This is only possible for surfaces generated in the current session.\n");
return;
}
/* move all atoms in selection */
for (list=data->selection ; list ; list=g_slist_next(list))
{
core = list->data;
region_move_atom(core, direction, data);
}
/* update */
coords_compute(data);
connect_bonds(data);
connect_molecules(data);
#if DEBUG_REGION_MOVE
printf("old dipole: %f\n", data->gulp.sdipole);
#endif
/* recompute */
calc_emp(data);
#if DEBUG_REGION_MOVE
printf("new dipole: %f\n", data->gulp.sdipole);
#endif
/* inform the user */
sprintf(txt, "New surface dipole: %f\n", data->gulp.sdipole);
gui_text_show(STANDARD, txt);
redraw_canvas(SINGLE);
}
/****************************/
/* connectivity only update */
/****************************/
void update_bonds(void)
{
struct model_pak *data;
data = sysenv.active_model;
if (!data)
return;
coords_compute(data);
connect_bonds(data);
connect_molecules(data);
redraw_canvas(SINGLE);
}
/*******************************/
/* creates a new (blank) model */
/*******************************/
void edit_model_create(void)
{
struct model_pak *data;
/* make a slot for the new model */
data = model_new();
sysenv.active_model = data;
/* setup model parameters */
data->id = CREATOR;
strcpy(data->filename, "new_model");
g_free(data->basename);
data->basename = g_strdup("new_model");
/* initialize */
model_prep(data);
data->mode = FREE;
/* rmax has to be after coords_init() as INIT_COORDS will set it to 1.0 */
data->rmax = 5.0*RMAX_FUDGE;
/* update/redraw */
tree_model_add(data);
tree_select_model(data);
redraw_canvas(SINGLE);
}
/***********************/
/* add atom event hook */
/***********************/
void add_atom(gint x, gint y, struct model_pak *data)
{
gchar *elem;
const gchar *orig;
gdouble r[3];
struct core_pak *core;
g_assert(data != NULL);
/* get the atom type from the label */
orig = gtk_entry_get_text(GTK_ENTRY(apd_label));
elem = g_strdup(orig);
/* add the atom to the model */
core = new_core(elem, data);
/* set atom position in the plane running through the origin */
gl_project(r, x, y, canvas_find(data));
/*
ARR3ADD(r, data->centroid);
VEC3MUL(r, 1.0/data->scale);
*/
ARR3SET(core->rx, r);
ARR3SET(core->x, r);
vecmat(data->ilatmat, core->x);
ARR3ADD(core->x, data->centroid);
data->cores = g_slist_append(data->cores, core);
/* make sure this atom is in the apd box, so we can keep adding this type */
select_clear(data);
select_add_core(core, data);
/* TODO - need a more fine grained update (atoms/selection) */
/*
coords_compute(data);
*/
zone_init(data);
connect_bonds(data);
connect_molecules(data);
/* REFRESH */
gui_refresh(GUI_MODEL_PROPERTIES);
g_slist_free(data->unique_atom_list);
data->unique_atom_list = find_unique(ELEMENT, data);
init_atom_colour(core, data);
init_atom_charge(core, data);
calc_emp(data);
/* done */
g_free(elem);
}
/*******************************************************/
/* permanently remove all deleted cores from all lists */
/*******************************************************/
#define DEBUG_DELETE_COMMIT 0
void delete_commit(struct model_pak *data)
{
gint flag1=FALSE, flag2=FALSE;
gpointer m;
GSList *list1, *list2;
struct core_pak *core;
struct shel_pak *shell;
struct bond_pak *bond;
g_assert(data != NULL);
/* delete flaged cores in list */
list1 = data->cores;
while (list1)
{
core = list1->data;
list1 = g_slist_next(list1);
if (core->status & DELETED)
{
#if DEBUG_DELETE_COMMIT
printf("Deleting %s core [%p] ...\n", core->label, core);
#endif
flag1 = TRUE;
/* flag assoc. shell */
if (core->shell)
{
shell = core->shell;
shell->status |= DELETED;
}
/* update connectivity */
connect_atom_clear(core, data);
list2 = data->ubonds;
while (list2)
{
bond = list2->data;
list2 = g_slist_next(list2);
if (bond->atom1 == core || bond->atom2 == core)
{
data->ubonds = g_slist_remove(data->ubonds, bond);
g_free(bond);
}
}
/* update selection */
data->selection = g_slist_remove(data->selection, core);
/* delete any labels that reference the deleted core */
list2 = data->measure_list;
while (list2)
{
m = list2->data;
list2 = g_slist_next(list2);
if (measure_has_core(core, m))
measure_free(m, data);
}
/* update main list */
data->cores = g_slist_remove(data->cores, core);
g_free(core);
}
}
/* delete flaged shells in list */
list1 = data->shels;
while (list1)
{
shell = list1->data;
list1 = g_slist_next(list1);
if (shell->status & DELETED)
{
flag2 = TRUE;
/* update main list */
data->shels = g_slist_remove(data->shels, shell);
g_free(shell);
}
}
/* refresh totals */
data->num_atoms = g_slist_length(data->cores);
data->num_shells = g_slist_length(data->shels);
/* refresh spatial partitioning */
/* it's probably best to refresh the partitioning here, rather than */
/* incrementally as it's speedups for large models we're targeting */
zone_init(data);
/* cope with deleted bonds - expensive, so only do if required */
if (flag1)
{
connect_bonds(data);
connect_molecules(data);
}
/* refresh net charge calc */
calc_emp(data);
/* refresh unique atom list */
g_slist_free(data->unique_atom_list);
data->unique_atom_list = find_unique(ELEMENT, data);
/* refresh widgets */
meas_graft_model(data);
gui_refresh(GUI_MODEL_PROPERTIES);
/* reset functions with static pointers to cores */
data->state = 0;
}
/**********************************/
/* flag core and associated shell */
/**********************************/
void delete_core(struct core_pak *core)
{
core->status |= DELETED;
if (core->shell)
(core->shell)->status |= DELETED;
}
/*********************************/
/* delete atom by pixel position */
/*********************************/
void delete_atom_at(gdouble *r, struct model_pak *data)
{
struct core_pak *core;
/* attempt to match point with an atom */
core = seek_coord3d(r, data);
if (core)
{
delete_core(core);
delete_commit(data);
}
}
/*****************************/
/* change the lattice matrix */
/*****************************/
void edit_transform_latmat(void)
{
GSList *list;
struct model_pak *model;
struct core_pak *core;
struct shel_pak *shell;
/* checks */
model = sysenv.active_model;
if (!model)
return;
/* remove all symmetry and convert to cartesian */
space_make_p1(model);
/* make coordinates cartesian for the prep stqage */
for (list=model->cores ; list ; list=g_slist_next(list))
{
core = list->data;
vecmat(model->latmat, core->x);
}
for (list=model->shels ; list ; list=g_slist_next(list))
{
shell = list->data;
vecmat(model->latmat, shell->x);
}
/* create new lattice */
matmat(tmat, model->latmat);
model->fractional = FALSE;
model->construct_pbc = TRUE;
model_prep(model);
/* GUI updates */
dialog_destroy_single(GENSURF, model);
tree_model_refresh(model);
gui_active_refresh();
gui_relation_update(model);
redraw_canvas(SINGLE);
}
/***********************************/
/* change periodicity of the model */
/***********************************/
void cb_modify_periodicity(void)
{
gint i, n, button;
gdouble d, x[3];
GSList *list;
GtkWidget *dialog;
struct model_pak *model;
struct core_pak *core;
struct shel_pak *shell;
/* checks */
model = sysenv.active_model;
if (!model)
return;
n = SPIN_IVAL(GTK_SPIN_BUTTON(periodicity_spin));
/* if we're increasing the periodicity, we need repeat vector info */
if (n > model->periodic)
{
/* check if its the unit vector (ie likely unchanged from default) */
for (i=model->periodic ; i<n ; i++)
{
VEC3SET(x, tmat[i], tmat[i+3], tmat[i+6]);
d = fabs(VEC3MAGSQ(x) - 1.0);
if (d < FRACTION_TOLERANCE)
{
dialog = gtk_message_dialog_new(GTK_WINDOW(window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_YES_NO,
"Are you sure the transformation matrix contains the appropriate repeat vectors for this change in periodicity?");
button = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if (button != -8)
return;
else
break;
}
}
}
/* remove all symmetry and convert to cartesian */
space_make_p1(model);
/* make coordinates cartesian for the prep stqage */
for (list=model->cores ; list ; list=g_slist_next(list))
{
core = list->data;
vecmat(model->latmat, core->x);
}
for (list=model->shels ; list ; list=g_slist_next(list))
{
shell = list->data;
vecmat(model->latmat, shell->x);
}
/* set the (extra) new lattice matrix periodicty */
for (i=model->periodic ; i<n ; i++)
{
model->latmat[i+0] = tmat[i+0];
model->latmat[i+3] = tmat[i+3];
model->latmat[i+6] = tmat[i+6];
}
/* init new lattice */
model->periodic = n;
model->fractional = FALSE;
model->construct_pbc = TRUE;
model_prep(model);
/* GUI updates */
/* REFRESH */
dialog_destroy_single(GENSURF, model);
tree_model_refresh(model);
gui_relation_update(model);
gui_refresh(GUI_MODEL_PROPERTIES);
gui_refresh(GUI_CANVAS);
}
/********************/
/* build a nanotube */
/********************/
#define EDIT_NANOTUBE_NEW 0
void edit_nanotube_new(void)
{
gint i, j, k, n, m, d, dr, np, mp;
gint imin, imax, jmin, jmax, dummy[3];
gdouble a1[3], a2[3], a3[3];
gdouble a, r, x[3], y[3], ch[3], t[3], v[3], p[2];
gchar *text;
struct core_pak *core;
struct model_pak *model;
/* checks */
model = sysenv.active_model;
if (!model)
{
edit_model_create();
model = sysenv.active_model;
g_assert(model != NULL);
}
/* default to brenner if potential set is absent */
if (!model->gulp.potentials && !model->gulp.libfile)
model->gulp.potentials = g_strdup("brenner\n");
#define ROOT3 sqrt(3)
/* TODO - test basis atom strings for validity */
#if EDIT_NANOTUBE_NEW
printf("Basis: %s, %s (%f)\n", edit_basis[0], edit_basis[1], edit_length);
#endif
/* compute lattice basis vectors */
VEC3SET(a1, 1.5*edit_length, 0.5*ROOT3*edit_length, 0.0);
VEC3SET(a2, 1.5*edit_length, -0.5*ROOT3*edit_length, 0.0);
VEC3SET(a3, edit_length, 0.0, 0.0);
/* compute indices */
n = edit_chirality[0];
m = edit_chirality[1];
d = gcd(n, m);
if ((n - m) % (3*d))
dr = d;
else
dr = 3.0*d;
np = 2*m + n;
np /= dr;
mp = 2*n + m;
mp /= dr;
/* chirality vector */
ARR3SET(x, a1);
ARR3SET(y, a2);
VEC3MUL(x, n);
VEC3MUL(y, m);
ARR3SET(ch, x);
ARR3ADD(ch, y);
/* tube radius */
r = 0.5 * VEC3MAG(ch) / G_PI;
/* translation vector */
ARR3SET(x, a1);
ARR3SET(y, a2);
VEC3MUL(x, np);
VEC3MUL(y, mp);
ARR3SET(t, x);
ARR3SUB(t, y);
/* loop limits */
imin = MIN(MIN(np, 0), n);
imax = MAX(MAX(n+np, n), np);
jmin = MIN(MIN(-mp, 0), m);
jmax = MAX(MAX(m-np, m), -mp);
#if EDIT_NANOTUBE_NEW
printf("chirality vector index: (%d, %d)\n", n, m);
printf("chirality xlat index: (%d, %d)\n", np, -mp);
P3VEC("chiral vector: ", ch);
P3VEC("xlat vector: ", t);
#endif
/* loop over graphite lattice */
for (i=imin ; i<=imax ; i++)
{
for (j=jmin ; j<=jmax ; j++)
{
/* compute lattice vector */
ARR3SET(x, a1);
ARR3SET(y, a2);
VEC3MUL(x, i);
VEC3MUL(y, j);
ARR3SET(v, x);
ARR3ADD(v, y);
/* compute basis atom coord */
for (k=0 ; k<2 ; k++)
{
if (k)
{
ARR3ADD(v, a3);
}
ARR3SET(x, v);
ARR3MUL(x, ch);
p[0] = x[0] + x[1] + x[2];
p[0] /= VEC3MAGSQ(ch);
ARR3SET(y, v);
ARR3MUL(y, t);
p[1] = y[0] + y[1] + y[2];
p[1] /= VEC3MAGSQ(t);
/* clamp to one unit's worth of atoms */
fractional_clamp(p, dummy, 2);
/* choose basis atom type */
if (k)
core = core_new(edit_basis[0], NULL, model);
else
core = core_new(edit_basis[1], NULL, model);
model->cores = g_slist_prepend(model->cores, core);
/* compute 1D fractional coords */
a = 2.0 * G_PI * p[0];
/* xlat in x */
/*
core->x[0] = -p[1];
*/
core->x[0] = p[1];
core->x[1] = r*sin(a);
core->x[2] = r*cos(a);
}
}
}
/* setup */
/* TODO - what if periodicity in z is desired??? */
model->periodic = 1;
model->fractional = TRUE;
model->pbc[0] = VEC3MAG(t);
model_prep(model);
/* model info */
text = g_strdup_printf("(%d, %d)", n, m);
property_add_ranked(2, "Chirality", text, model);
g_free(text);
text = g_strdup_printf("%.4f Angs", r);
property_add_ranked(3, "Radius", text, model);
g_free(text);
tree_model_refresh(model);
gui_refresh(GUI_MODEL_PROPERTIES);
gui_refresh(GUI_CANVAS);
gui_relation_update(model);
}
/***********************************************/
/* periodicity dialog hook to make a supercell */
/***********************************************/
void edit_make_supercell(void)
{
struct model_pak *model;
model = sysenv.active_model;
if (model)
{
space_make_supercell(model);
model_prep(model);
}
/* REFRESH */
gui_refresh(GUI_MODEL_PROPERTIES);
gui_refresh(GUI_CANVAS);
}
/************************/
/* make active model P1 */
/************************/
void edit_make_p1(void)
{
struct model_pak *model;
model = sysenv.active_model;
if (!model)
return;
if (model->periodic != 3)
return;
space_make_p1(model);
/* REFRESH */
gui_refresh(GUI_MODEL_PROPERTIES);
gui_refresh(GUI_CANVAS);
}
/***********************/
/* start add atom mode */
/***********************/
void edit_atom_add(void)
{
if (!sysenv.active_model)
edit_model_create();
gui_mode_switch(ATOM_ADD);
}
/********************************/
/* add shells to selected cores */
/********************************/
void edit_shells_add(void)
{
GSList *list;
struct core_pak *core;
struct shel_pak *shell;
struct model_pak *model;
model = sysenv.active_model;
if (model)
{
for (list=model->selection ; list ; list=g_slist_next(list))
{
core = list->data;
/* create new shell if none present */
if (!core->shell)
{
shell = shell_new(core->atom_label, NULL, model);
model->shels = g_slist_prepend(model->shels, shell);
/* start shell at core coords */
ARR3SET(shell->x, core->x);
ARR3SET(shell->rx, core->rx);
/* transfer appropriate core characteristics */
shell->primary = core->primary;
shell->orig = core->orig;
shell->region = core->region;
/* do core-shell link */
shell->core = core;
core->shell = shell;
}
}
}
}
/*****************************/
/* atom/mol cell confinement */
/*****************************/
void edit_confine(GtkWidget *w, gint mode)
{
struct model_pak *model;
model = sysenv.active_model;
if (!model)
return;
switch (mode)
{
case CORE:
coords_confine_cores(model->cores, model);
coords_compute(model);
connect_bonds(model);
break;
case MOL:
connect_molecules(model);
break;
}
redraw_canvas(SINGLE);
}
/******************/
/* bonding toggle */
/******************/
void gui_connect_toggle(void)
{
struct model_pak *model = sysenv.active_model;
if (model)
{
model->build_molecules ^= 1;
connect_refresh(model);
redraw_canvas(SINGLE);
}
}
/**********************/
/* model builder page */
/**********************/
/* TODO - molecule fragments (library?) */
void build_page(GtkWidget *box)
{
GtkWidget *frame, *vbox, *hbox;
GtkWidget *label, *entry, *spin;
g_return_if_fail(box != NULL);
/* Frame */
frame = gtk_frame_new ("Atoms");
gtk_box_pack_start(GTK_BOX(box),frame,FALSE,TRUE,0);
gtk_container_set_border_width (GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(TRUE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width (GTK_CONTAINER(vbox), PANEL_SPACING);
gui_button_x("Add atoms", edit_atom_add, NULL, vbox);
gui_button_x("Confine atoms to cell", edit_confine, (gpointer) CORE, vbox);
gui_button_x("Confine molecules to cell", edit_confine, (gpointer) MOL, vbox);
/* NEW */
gui_button_x("Add shells to selected cores", edit_shells_add, NULL, vbox);
/* Frame */
/* FIXME - fix up user bonds then re-introduce */
frame = gtk_frame_new ("Connectivity");
gtk_box_pack_start(GTK_BOX(box),frame,FALSE,TRUE,0);
gtk_container_set_border_width (GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(TRUE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width (GTK_CONTAINER(vbox), PANEL_SPACING);
gui_button_x("Add single bonds ", gtk_mode_switch, (gpointer) BOND_SINGLE, vbox);
/*
gui_button_x("Add double bonds ", gtk_mode_switch, (gpointer) BOND_DOUBLE, vbox);
gui_button_x("Add triple bonds ", gtk_mode_switch, (gpointer) BOND_TRIPLE, vbox);
*/
gui_button_x("Delete bonds ", gtk_mode_switch, (gpointer) BOND_DELETE, vbox);
gui_button_x("Toggle bonding ", gui_connect_toggle, NULL, vbox);
/* Frame */
frame = gtk_frame_new ("Structural");
gtk_box_pack_start(GTK_BOX(box),frame,FALSE,TRUE,0);
gtk_container_set_border_width (GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(TRUE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width (GTK_CONTAINER(vbox), PANEL_SPACING);
gui_button_x("Make new model", edit_model_create, NULL, vbox);
gui_button_x("Make supercell", edit_make_supercell, NULL, vbox);
gui_button_x("Force structure to P1", edit_make_p1, NULL, vbox);
/* NEW - nanotube setup */
frame = gtk_frame_new ("Nanotube");
gtk_box_pack_start(GTK_BOX(box),frame,FALSE,TRUE,0);
gtk_container_set_border_width(GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(FALSE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), PANEL_SPACING);
/* chirality */
hbox = gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new("Chirality ");
gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
spin = gui_direct_spin(NULL, &edit_chirality[0], 0, 99, 1, NULL, NULL, NULL);
gtk_box_pack_start(GTK_BOX(hbox),spin,FALSE,FALSE,0);
spin = gui_direct_spin(NULL, &edit_chirality[1], 0, 99, 1, NULL, NULL, NULL);
gtk_box_pack_start(GTK_BOX(hbox),spin,FALSE,FALSE,0);
/* basis atoms */
/*
hbox = gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
*/
if (!edit_basis[0])
edit_basis[0] = g_strdup("C");
if (!edit_basis[1])
edit_basis[1] = g_strdup("C");
entry = gui_text_entry(" Basis ", &edit_basis[0], TRUE, TRUE, hbox);
gtk_entry_set_width_chars(GTK_ENTRY(entry), 4);
entry = gui_text_entry(" - ", &edit_basis[1], TRUE, TRUE, hbox);
gtk_entry_set_width_chars(GTK_ENTRY(entry), 4);
/* characteristic length */
gui_direct_spin(" : ", &edit_length, 0.1, 5.0, 0.05, NULL, NULL, hbox);
gui_button_x("Create nanotube ", edit_nanotube_new, NULL, vbox);
gtk_widget_show_all(box);
}
/*******************/
/* spatial globals */
/*******************/
GtkListStore *spatial_list=NULL;
GtkWidget *spatial_tree=NULL;
gpointer spatial_selected=NULL;
/**************************************/
/* delete all spatials of given label */
/**************************************/
void gui_spatial_delete(GtkWidget *w, gpointer data)
{
const gchar *label = data;
if (sysenv.active_model)
spatial_destroy_by_label(label, sysenv.active_model);
sysenv.refresh_dialog=TRUE;
redraw_canvas(SINGLE);
}
/***********************/
/* delete all spatials */
/***********************/
void gui_spatial_delete_all(GtkWidget *w, gpointer data)
{
struct model_pak *model = sysenv.active_model;
if (model)
{
spatial_destroy_all(model);
sysenv.refresh_dialog=TRUE;
redraw_canvas(SINGLE);
}
}
/*****************************************/
/* delete the currently selected spatial */
/*****************************************/
void gui_spatial_delete_selected(GtkWidget *w, gpointer data)
{
spatial_destroy(spatial_selected, sysenv.active_model);
sysenv.refresh_dialog=TRUE;
redraw_canvas(SINGLE);
}
/*****************************/
/* fill out the spatial list */
/*****************************/
void gui_spatial_populate(void)
{
gint n;
gchar *size, *type;
GSList *list;
GtkTreeIter iter;
struct spatial_pak *spatial;
struct model_pak *model;
gtk_list_store_clear(spatial_list);
model = sysenv.active_model;
if (!model)
return;
for (list=model->spatial ; list ; list=g_slist_next(list))
{
spatial = list->data;
/* compute number of primitives */
n = g_slist_length(spatial->list);
if (spatial->size)
n /= spatial->size;
size = g_strdup_printf("%d", n);
/* primitive type */
switch (spatial->size)
{
case 1:
type = g_strdup("points");
break;
case 2:
type = g_strdup("vectors");
break;
case 3:
type = g_strdup("triangles");
break;
case 4:
type = g_strdup("quads");
break;
default:
type = g_strdup("vertices");
break;
}
/* add the spatial and descriptors */
gtk_list_store_append(spatial_list, &iter);
gtk_list_store_set(spatial_list, &iter, 0, spatial->label,
1, size,
2, type,
3, spatial,
-1);
/* NB: the list will make its own copy */
g_free(size);
g_free(type);
}
}
/*******************************/
/* select a particular spatial */
/*******************************/
void gui_spatial_select(GtkTreeSelection *selection, gpointer data)
{
GtkTreeIter iter;
GtkTreeModel *treemodel;
gpointer spatial;
struct model_pak *model;
/* checks */
model = sysenv.active_model;
if (!model)
return;
/* record selection as active */
if (gtk_tree_selection_get_selected(selection, &treemodel, &iter))
{
gtk_tree_model_get(treemodel, &iter, 3, &spatial, -1);
spatial_selected = spatial;
}
}
/**************************************/
/* callback for spatial colour change */
/**************************************/
void gui_spatial_colour_all(GtkWidget *w, gdouble *colour)
{
GSList *list1, *list2;
struct model_pak *model;
struct spatial_pak *spatial;
struct vec_pak *vertex;
model = sysenv.active_model;
if (model)
{
for (list1=model->spatial ; list1 ; list1=g_slist_next(list1))
{
spatial = list1->data;
for (list2=spatial->list ; list2 ; list2=g_slist_next(list2))
{
vertex = list2->data;
ARR3SET(vertex->colour, colour);
}
}
}
gui_refresh(GUI_CANVAS);
}
/***********************************************/
/* callback for selected spatial colour change */
/***********************************************/
void gui_spatial_colour_select(GtkWidget *w, gdouble *colour)
{
GSList *list;
struct vec_pak *vertex;
struct spatial_pak *spatial = spatial_selected;
if (spatial)
{
for (list=spatial->list ; list ; list=g_slist_next(list))
{
vertex = list->data;
ARR3SET(vertex->colour, colour);
}
gui_refresh(GUI_CANVAS);
}
}
/********************************************/
/* callback for spatial label colour change */
/********************************************/
void gui_spatial_colour_label_all(GtkWidget *w, gdouble *colour)
{
GSList *list;
struct model_pak *model;
struct spatial_pak *spatial;
model = sysenv.active_model;
if (model)
{
for (list=model->spatial ; list ; list=g_slist_next(list))
{
spatial = list->data;
ARR3SET(spatial->c, colour);
}
}
gui_refresh(GUI_CANVAS);
}
/*****************************************************/
/* callback for selected spatial label colour change */
/*****************************************************/
void gui_spatial_colour_label_select(GtkWidget *w, gdouble *colour)
{
struct spatial_pak *spatial = spatial_selected;
if (spatial)
{
ARR3SET(spatial->c, colour);
gui_refresh(GUI_CANVAS);
}
}
/************************/
/* spatial objects page */
/************************/
void spatial_page(GtkWidget *box)
{
gint i;
gchar *titles[] = {" Label ", " Size ", " Primitive "};
GtkCellRenderer *r;
GtkTreeViewColumn *c;
GtkTreeSelection *select;
GtkWidget *swin, *frame, *hbox, *vbox1, *vbox2, *vbox;
/* initialize - nothing selected */
spatial_selected = NULL;
/* left & right pane split */
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(box), hbox);
vbox1 = gtk_vbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(hbox), vbox1, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0);
/* Frame */
frame = gtk_frame_new ("Adding");
gtk_box_pack_start(GTK_BOX(vbox1),frame,FALSE,FALSE,0);
gtk_container_set_border_width(GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(TRUE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), PANEL_SPACING);
/* mode buttons */
gui_button_x("Add vectors ",
gtk_mode_switch, GINT_TO_POINTER(DEFINE_VECTOR),
vbox);
gui_button_x("Add planes ",
gtk_mode_switch, GINT_TO_POINTER(DEFINE_PLANE),
vbox);
/* FIXME - currently, ribbons are not spatial objects */
gui_button_x("Add ribbons ",
gtk_mode_switch, GINT_TO_POINTER(DEFINE_RIBBON),
vbox);
/* Frame */
frame = gtk_frame_new ("Deleting");
gtk_box_pack_start(GTK_BOX(vbox1),frame,FALSE,TRUE,0);
gtk_container_set_border_width(GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(TRUE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), PANEL_SPACING);
gui_button_x("Delete all vectors ", gui_spatial_delete, "vector", vbox);
gui_button_x("Delete all planes ", gui_spatial_delete, "plane", vbox);
gui_button_x("Delete all ", gui_spatial_delete_all, NULL, vbox);
gui_button_x("Delete selected ", gui_spatial_delete_selected, NULL, vbox);
/* Frame */
frame = gtk_frame_new (NULL);
gtk_box_pack_start(GTK_BOX(vbox1),frame,FALSE,TRUE,0);
gtk_container_set_border_width(GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(TRUE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), PANEL_SPACING);
/* TODO - apply to selection */
gui_colour_box("Spatial fill colour ", edit_spatial_colour, vbox);
gui_button_x("Apply to all ",
gui_spatial_colour_all, edit_spatial_colour, vbox);
gui_button_x("Apply to selected ",
gui_spatial_colour_select, edit_spatial_colour, vbox);
/* Frame */
frame = gtk_frame_new (NULL);
gtk_box_pack_start(GTK_BOX(vbox1),frame,FALSE,TRUE,0);
gtk_container_set_border_width(GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(TRUE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), PANEL_SPACING);
/* TODO - apply to selection */
gui_colour_box("Spatial label colour ", edit_label_colour, vbox);
gui_button_x("Apply to all ",
gui_spatial_colour_label_all, edit_label_colour, vbox);
gui_button_x("Apply to selected ",
gui_spatial_colour_label_select, edit_label_colour, vbox);
/* spatial list */
frame = gtk_frame_new(NULL);
gtk_box_pack_start(GTK_BOX(vbox2),frame,TRUE,TRUE,0);
gtk_container_set_border_width (GTK_CONTAINER(frame), PANEL_SPACING);
vbox = gtk_vbox_new(TRUE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(vbox), PANEL_SPACING);
/* scrolled window */
swin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
/* list */
spatial_list = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
spatial_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(spatial_list));
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swin), spatial_tree);
for (i=0 ; i<3 ; i++)
{
r = gtk_cell_renderer_text_new();
c = gtk_tree_view_column_new_with_attributes(titles[i], r, "text", i, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(spatial_tree), c);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(spatial_tree), FALSE);
}
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(spatial_tree), TRUE);
/* selection handler */
select = gtk_tree_view_get_selection(GTK_TREE_VIEW(spatial_tree));
gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
g_signal_connect(G_OBJECT(select), "changed",
G_CALLBACK(gui_spatial_select),
NULL);
gui_spatial_populate();
gtk_widget_show_all(box);
}
/************************/
/* transformations page */
/************************/
void trans_page(GtkWidget *box)
{
gint i, j;
GList *list;
GtkWidget *frame, *table, *hbox, *vbox, *label;
g_assert(box != NULL);
/* transformation construction */
frame = gtk_frame_new("Construction");
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(FALSE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(GTK_BOX(vbox)), PANEL_SPACING);
/* TODO - use spinners instead of gtk entries for these numbers */
/* axes order */
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, FALSE, 0);
label = gtk_label_new("Rotation angle (degrees):");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
axis_entry = gtk_entry_new();
gtk_box_pack_end(GTK_BOX(hbox), axis_entry, FALSE, FALSE, 0);
/*
gtk_entry_set_text(GTK_ENTRY(axis_entry), "90");
*/
/* spatial object */
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, FALSE, 0);
label = gtk_label_new("Reference spatial object: ");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
obj_entry = gtk_entry_new();
gtk_box_pack_end(GTK_BOX(hbox), obj_entry, FALSE, FALSE, 0);
/*
gtk_entry_set_text(GTK_ENTRY(obj_entry), "0");
*/
/* construction buttons */
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
list = NULL;
list = g_list_prepend(list, "identity matrix");
list = g_list_prepend(list, "lattice matrix");
list = g_list_prepend(list, "reflection matrix");
list = g_list_prepend(list, "rotation matrix");
list = g_list_prepend(list, "z alignment matrix");
list = g_list_reverse(list);
edit_construct = gui_pulldown_new("Construct", list, FALSE, hbox);
gui_button_x(NULL, construct_transmat, NULL, hbox);
/* table */
table = gtk_table_new(5, 4, FALSE);
gtk_container_add(GTK_CONTAINER(GTK_BOX(vbox)),table);
label = gtk_label_new("a*");
gtk_table_attach_defaults(GTK_TABLE(table),label,0,1,1,2);
label = gtk_label_new("b*");
gtk_table_attach_defaults(GTK_TABLE(table),label,0,1,2,3);
label = gtk_label_new("c*");
gtk_table_attach_defaults(GTK_TABLE(table),label,0,1,3,4);
label = gtk_label_new("a");
gtk_table_attach_defaults(GTK_TABLE(table),label,1,2,0,1);
label = gtk_label_new("b");
gtk_table_attach_defaults(GTK_TABLE(table),label,2,3,0,1);
label = gtk_label_new("c");
gtk_table_attach_defaults(GTK_TABLE(table),label,3,4,0,1);
label = gtk_label_new("t");
gtk_table_attach_defaults(GTK_TABLE(table),label,4,5,0,1);
/* column loop */
for (j=0 ; j<3 ; j++)
{
/* row loop */
for (i=0 ; i<3 ; i++)
{
transmat[3*j+i] = gtk_entry_new();
gtk_table_attach_defaults(GTK_TABLE(table),transmat[3*j+i],i+1,i+2,j+1,j+2);
gtk_widget_set_size_request(transmat[3*j+i], 7*sysenv.gtk_fontsize, -1);
}
}
/* translation */
for (j=0 ; j<3 ; j++)
{
transmat[9+j] = gtk_entry_new();
gtk_table_attach_defaults(GTK_TABLE(table),transmat[9+j],4,5,j+1,j+2);
gtk_widget_set_size_request(transmat[9+j], 7*sysenv.gtk_fontsize, -1);
}
/* control buttons */
frame = gtk_frame_new("Coordinate transformations");
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(FALSE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(GTK_BOX(vbox)), PANEL_SPACING);
gui_button_x("Apply to all atoms",
apply_transmat, GINT_TO_POINTER(AT_ANY),
vbox);
gui_button_x("Apply to selected atoms",
apply_transmat, GINT_TO_POINTER(AT_SELECTED),
vbox);
/* animation construction */
/* FIXME - broken by new quaternion camera */
/*
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new("Generate animation frames ");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
gui_direct_spin(NULL, &edit_anim_n, 0.0, 1000.0, 1.0, NULL, NULL, hbox);
gui_button_x(NULL, apply_n_transmat, GINT_TO_POINTER(AT_ANY), hbox);
*/
/* control buttons */
frame = gtk_frame_new("Lattice transformations");
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(FALSE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(GTK_BOX(vbox)), PANEL_SPACING);
gui_button_x("Apply to lattice matrix", edit_transform_latmat, NULL, vbox);
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new("Alter lattice periodicity ");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
periodicity_spin = gtk_spin_button_new_with_range(0, 3, 1);
gtk_box_pack_start(GTK_BOX(hbox), periodicity_spin, FALSE, FALSE, 0);
gui_button_x(NULL, cb_modify_periodicity, NULL, hbox);
gui_button_x("Create new lattice model from linear combination",
apply_transmat, GINT_TO_POINTER(AT_LATTICE),
vbox);
}
/*************************************/
/* save a diffraction (DIFFAX) setup */
/*************************************/
struct model_pak *diffract_model=NULL;
void diffract_save(gchar *name)
{
write_diffax(name, diffract_model);
dialog_destroy_type(FILE_SELECT);
}
/******************************************/
/* create a file dialog for a DIFFAX save */
/******************************************/
void diffract_save_dialog(GtkWidget *w, struct model_pak *model)
{
diffract_model = model;
file_dialog("Save DIFFAX file", model->basename, FILE_SAVE,
(gpointer) diffract_save, DIFFAX_INP);
}
/*******************/
/* add a new layer */
/*******************/
GtkWidget *diffract_layer_total;
#define DEBUG_DIFFRACT_LAYER_SETUP 0
void diffract_layer_setup(struct model_pak *data)
{
gint n, region;
gint num_layer, tot_layer;
gdouble start, stop;
GSList *clist, *list1=NULL;
struct layer_pak *layer;
struct core_pak *core;
if (!data)
return;
if (GTK_IS_SPIN_BUTTON(diffract_layer_total))
tot_layer = SPIN_IVAL(GTK_SPIN_BUTTON(diffract_layer_total));
else
return;
/* get rid of old list */
free_slist(data->layer_list);
data->layer_list = NULL;
for (num_layer=0 ; num_layer<tot_layer ; num_layer++)
{
/* create the new layer */
layer = g_malloc(sizeof(struct layer_pak));
layer->width = 1.0/(gdouble) tot_layer;
VEC3SET(layer->centroid, 0.0, 0.0, 0.0);
start = (gdouble) num_layer / (gdouble) tot_layer;
stop = (gdouble) (num_layer+1) / (gdouble) tot_layer;
#if DEBUG_DIFFRACT_LAYER_SETUP
printf("new layer: %f-%f (%f)\n", start, stop, layer->width);
#endif
region = num_layer;
/* add cores that satisfy the start/stop condition */
list1 = NULL;
for (clist=data->cores ; clist ; clist=g_slist_next(clist))
{
core = (struct core_pak *) clist->data;
/* FIXME - floating point boundary problems? */
if (core->x[2] >= start && core->x[2] < stop)
{
list1 = g_slist_prepend(list1, core);
ARR3ADD(layer->centroid, core->x);
core->region = region;
/* update region colouring (if necessary) */
if (data->colour_scheme == REGION)
atom_colour_scheme(REGION, core, data);
}
}
/* centroid calc. */
n = g_slist_length(list1);
if (n)
{
#if DEBUG_DIFFRACT_LAYER_SETUP
printf("[%d] added layer with %d cores.\n", num_layer, n);
#endif
layer->cores = list1;
VEC3MUL(layer->centroid, 1.0/(gdouble) n);
}
/* always save the layer - may *want* to have an empty layer */
/* eg to simulate a vacuum gap */
data->layer_list = g_slist_prepend(data->layer_list, layer);
}
#if DEBUG_DIFFRACT_LAYER_SETUP
printf("Total layers: %d\n", g_slist_length(data->layer_list));
#endif
redraw_canvas(SINGLE);
}
/***********************************************/
/* create a defect structure from input layers */
/***********************************************/
GtkWidget *diffract_layer_order;
#define DEBUG_DIFFRACT_MODEL_CREATE 0
void diffract_model_create(GtkWidget *w, struct model_pak *model)
{
gint i, n, num_layer, tot_layer;
gdouble new_width, old_width, offset;
const gchar *text;
GSList *list;
struct model_pak *dest_model;
struct layer_pak *layer;
struct core_pak *core;
if (!model)
return;
diffract_layer_setup(model);
text = gtk_entry_get_text(GTK_ENTRY(diffract_layer_order));
/* create a new model */
dest_model = model_new();
g_return_if_fail(dest_model != NULL);
/* NB: not DIFFAX_INP, since this is demonstrating a particular layer packing */
dest_model->id = CREATOR;
strcpy(dest_model->filename, "new_model");
g_free(dest_model->basename);
dest_model->basename = g_strdup("new model");
/* find how many valid layers we will create */
tot_layer = 0;
for (i=0 ; i<strlen(text) ; i++)
{
if (g_ascii_isdigit(text[i]))
{
n = text[i] - '0';
layer = g_slist_nth_data(model->layer_list, n-1);
if (layer)
tot_layer++;
}
}
#if DEBUG_DIFFRACT_MODEL_CREATE
printf("Requested layers: %d\n", tot_layer);
#endif
/* build the new model from the input layer string */
num_layer=0;
new_width=1.0/tot_layer;
old_width=1.0;
for (i=strlen(text) ; i-- ; )
{
if (g_ascii_isdigit(text[i]))
{
n = text[i] - '0';
/* NB: numbering starts from 0 */
layer = g_slist_nth_data(model->layer_list, n-1);
if (layer)
{
old_width = layer->width;
/* add j based z offset */
offset = num_layer+0.5;
offset *= new_width;
#if DEBUG_DIFFRACT_MODEL_CREATE
printf("[%d] inserting layer: %d (scale: %f) (offset: %f)\n",
num_layer, n, new_width/old_width, offset);
#endif
/* add the layer's cores */
for (list=layer->cores ; list ; list=g_slist_next(list))
{
core = dup_core(list->data);
core->region = tot_layer - i - 1;
/* remove z centroid */
core->x[2] -= layer->centroid[2];
/* z values need to be SCALED (to meet the new layer width) */
core->x[2] *= new_width/old_width;
core->x[2] += offset;
dest_model->cores = g_slist_prepend(dest_model->cores, core);
}
num_layer++;
}
else
printf("Layer number %d not defined.\n", n);
}
}
/* test if anything was created */
if (!num_layer)
{
model_delete(dest_model);
return;
}
dest_model->cores = g_slist_reverse(dest_model->cores);
/* setup */
dest_model->periodic = 3;
dest_model->fractional = TRUE;
ARR3SET(&dest_model->pbc[0], &model->pbc[0]);
ARR3SET(&dest_model->pbc[3], &model->pbc[3]);
dest_model->pbc[2] *= num_layer*old_width;
#if DEBUG_DIFFRACT_MODEL_CREATE
printf("Setting c to: %f\n", dest_model->pbc[2]);
#endif
model_prep(dest_model);
model_colour_scheme(model->colour_scheme, dest_model);
tree_model_add(dest_model);
}
/**********************************/
/* callback for forcefield typing */
/**********************************/
void cb_type_model(GtkWidget *w, gpointer data)
{
struct model_pak *model;
model = sysenv.active_model;
if (!model)
return;
type_model(gtk_entry_get_text(GTK_ENTRY(data)), model);
/* possible label update */
redraw_canvas(ALL);
}
/**************************/
/* cell sculpting globals */
/**************************/
gdouble sculpt_length = 20.0;
/***********************************************************/
/* tests if a given image t[] is inside the list of planes */
/***********************************************************/
gint sculpt_image_test(gint *t, gdouble scale, struct model_pak *model)
{
gdouble r[3], n[3];
GSList *list;
struct plane_pak *plane;
/* convert periodic image to cartesian point */
/* NB: ensure we get the closest lattice point to the origin */
if (t[0] < 0)
r[0] = t[0]+1;
else
r[0] = t[0];
if (t[1] < 0)
r[1] = t[1]+1;
else
r[1] = t[1];
if (t[2] < 0)
r[2] = t[2]+1;
else
r[2] = t[2];
vecmat(model->latmat, r);
/* compare against planes to see if this image is excluded */
for (list=model->planes ; list ; list=g_slist_next(list))
{
plane = list->data;
/* get cartesian normal */
ARR3SET(n, plane->index);
vecmat(model->rlatmat, n);
normalize(n, 3);
/* test dot product against required distance to plane */
ARR3MUL(n, r);
if ((n[0]+n[1]+n[2]) > scale*plane->f[0])
{
return(FALSE);
}
}
return(TRUE);
}
/***************************/
/* cell sculpting callback */
/***************************/
#define DEBUG_SCULPT_CREATE 0
void sculpt_model_create(struct model_pak *model)
{
gint i, t[3], limit[3];
gdouble scale, r=1.0, s, rmin, x[3], n[3];
GSList *list, *clist, *slist, *plist;
struct model_pak *dest;
struct core_pak *core;
struct shel_pak *shell;
struct mol_pak *mol;
struct plane_pak *plane;
struct spatial_pak *spatial;
/* checks */
g_assert(model != NULL);
if (model->periodic != 3)
{
gui_text_show(ERROR, "Source model is not 3D periodic.\n");
return;
}
if (!model->planes)
{
gui_text_show(ERROR, "No cleavage planes supplied.\n");
return;
}
#if DEBUG_SCULPT_CREATE
else
printf("Planes: %d\n", g_slist_length(model->planes));
#endif
/* compute required periodic images (assumed symmetric) */
/* FIXME - most of the nuclei shape problems come from an insufficient number of repeats */
VEC3SET(limit, 0, 0, 0);
for (i=0 ; i<model->periodic ; i++)
limit[i] = 1 + sculpt_length/model->pbc[i];
/* init destination model for sculpture */
dest = model_new();
if (!dest)
{
gui_text_show(ERROR, "Failed to allocate for new model.\n");
return;
}
model_init(dest);
gulp_data_copy(model, dest);
#if DEBUG_SCULPT_CREATE
printf("maximum length: %f\n", sculpt_length);
printf("periodic images: %d %d %d\n", limit[0], limit[1], limit[2]);
#endif
/* TODO - going to have to put this ABOVE the sculpt_image_test() call, so we get rmin */
/* morphology computation */
morph_build(model);
/* compute the facet closest to the center */
rmin = G_MAXDOUBLE;
for (plist = model->planes ; plist ; plist=g_slist_next(plist))
{
plane = plist->data;
/* ensure we've got the best shift value data sitting in the plane structure */
update_plane_energy(plane, model);
/* compute distance to plane facet */
/* NEW - a little naughty, but using the f[] (structure factor) to store the length/shift */
/* value of the plane in the nuclei sculpting so we dont keep recalculating */
switch (model->morph_type)
{
case EQUIL_UN:
plane->f[0] = plane->esurf[0];
plane->f[1] = plane->esurf_shift;
break;
case GROWTH_UN:
plane->f[0] = fabs(plane->eatt[0]);
plane->f[1] = plane->eatt_shift;
break;
case EQUIL_RE:
plane->f[0] = plane->esurf[1];
plane->f[1] = plane->esurf_shift;
break;
case GROWTH_RE:
plane->f[0] = fabs(plane->eatt[1]);
plane->f[1] = plane->eatt_shift;
break;
case DHKL:
default:
plane->f[0] = 1.0/plane->dhkl;
plane->f[1] = 0.0;
break;
}
/* NEW - stop zero result (failed/bad calc) from messing things up */
if (plane->f[0] != 0.0 && plane->f[0] < rmin)
rmin = plane->f[0];
}
#if DEBUG_SCULPT_CREATE
printf("rmin = %f\n", rmin);
#endif
scale = 0.5*sculpt_length/rmin;
/* periodic image creation */
for (t[0] = -limit[0] ; t[0] <= limit[0] ; t[0]++)
{
for (t[1] = -limit[1] ; t[1] <= limit[1] ; t[1]++)
{
for (t[2] = -limit[2] ; t[2] <= limit[2] ; t[2]++)
{
/* test vertices of the t[] image against planes */
if (!sculpt_image_test(t, scale, model))
continue;
/* duplicate cores, add periodic image offset & convert to cartesian */
clist = dup_core_list(model->cores);
slist = dup_shell_list(model->shels);
dest->cores = g_slist_concat(dest->cores, clist);
dest->shels = g_slist_concat(dest->shels, slist);
for (list=clist ; list ; list=g_slist_next(list))
{
core = list->data;
core->primary = TRUE;
ARR3ADD(core->x, t);
vecmat(model->latmat, core->x);
}
for (list=slist ; list ; list=g_slist_next(list))
{
shell = list->data;
shell->primary = TRUE;
ARR3ADD(shell->x, t);
vecmat(model->latmat, shell->x);
}
}
}
}
/* initialize connectivity and core-shell links for the new model */
zone_init(dest);
connect_bonds(dest);
connect_molecules(dest);
shell_make_links(dest);
/* plane cutoff tests */
for (plist=model->planes ; plist ; plist=g_slist_next(plist))
{
plane = plist->data;
/* get cartesian distance to plane facet */
r = plane->f[0] * scale;
s = plane->f[1];
/* attempt to create the correct (ie surface shift) termination */
if (model->sculpt_shift_use)
{
/*
g = GCD(GCD(plane->index[0], plane->index[1]), GCD(plane->index[1], plane->index[2]));
*/
r /= plane->dhkl;
/* TODO - if nearest_int(r) == 0 -> set to 1 */
s += nearest_int(r);
r = s * plane->dhkl;
}
/* get cartesian normal */
ARR3SET(n, plane->index);
vecmat(model->rlatmat, n);
normalize(n, 3);
/* project coords onto plane normal & remove if greater than distance to facet */
/* TODO - do cutoff by molecule centroid when combining with periodic image loop */
for (list=dest->moles ; list ; list=g_slist_next(list))
{
mol = list->data;
ARR3SET(x, mol->centroid);
ARR3MUL(x, n);
if ((x[0]+x[1]+x[2]) > r)
{
for (clist=mol->cores ; clist ; clist=g_slist_next(clist))
{
core = clist->data;
core->status |= DELETED;
if (core->shell)
{
shell = core->shell;
shell->status |= DELETED;
}
}
}
}
}
/* transfer the spatials from the source model morphology to the nuclei */
list = model->spatial;
while (list)
{
spatial = list->data;
list = g_slist_next(list);
/* search for all morphology related spatials */
/* a bit crude... */
if (g_strrstr(spatial->label, "(") && g_strrstr(spatial->label, ")"))
{
dest->spatial = g_slist_prepend(dest->spatial, spatial);
model->spatial = g_slist_remove(model->spatial, spatial);
spatial->method = GL_LINE_LOOP;
/* mult vertices by len */
for (plist=spatial->list ; plist ; plist=g_slist_next(plist))
{
struct vec_pak *vec = plist->data;
ARR3SET(vec->colour, sysenv.render.fg_colour);
/* convert fractional vertices to cartesian */
vecmat(model->latmat, vec->x);
/* scale the morphology to match the constructed nuclei */
VEC3MUL(vec->x, scale);
}
}
}
/* init for display */
delete_commit(dest);
model_prep(dest);
tree_model_add(dest);
redraw_canvas(ALL);
}
/********************************/
/* callback for nuclei creation */
/********************************/
void morph_sculpt(GtkWidget *w, gpointer data)
{
gpointer model;
sculpt_length = SPIN_FVAL(GTK_SPIN_BUTTON(data));
model = g_object_get_data(data, "model");
sculpt_model_create(model);
}
/*******************************************/
/* unit cell sculpting (eg via morphology) */
/*******************************************/
void sculpting_page(GtkWidget *box)
{
GtkWidget *hbox, *hbox2;
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
gui_direct_spin("Maximum length", &sculpt_length, 10.0, 100.0, 10.0, NULL, NULL, hbox);
/* action buttons */
hbox2 = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(box), hbox2, FALSE, FALSE, PANEL_SPACING);
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_end(GTK_BOX(hbox2), hbox, TRUE, FALSE, 0);
gui_icon_button(GTK_STOCK_APPLY, "Create ",
sculpt_model_create, NULL,
hbox);
}
/************************************/
/* build a new rule from the dialog */
/************************************/
void gui_make_rule(GtkWidget *w, gpointer dialog)
{
gint count, level;
const gchar *ff_type, *ff_elem;
gpointer type;
GtkWidget *obj;
struct model_pak *model;
model = sysenv.active_model;
g_assert(model != NULL);
obj = dialog_child_get(dialog, "FF_label");
ff_type = gtk_entry_get_text(GTK_ENTRY(obj));
obj = dialog_child_get(dialog, "FF_level");
level = str_to_float(gtk_entry_get_text(GTK_ENTRY(obj)));
obj = dialog_child_get(dialog, "FF_element");
ff_elem = gtk_entry_get_text(GTK_ENTRY(obj));
obj = dialog_child_get(dialog, "FF_count");
count = str_to_float(gtk_entry_get_text(GTK_ENTRY(obj)));
type = type_new();
type_ff_set(TRUE, ff_type, type);
type_rule_add(level, count, ff_elem, type);
type_apply(type, model->cores);
type_free(type);
}
/*******************************/
/* core labelling manipulation */
/*******************************/
/* TODO - not enough options now - link to surface dialog somehow? */
void labelling_page(GtkWidget *box, gpointer dialog)
{
GtkWidget *w, *frame, *vbox;
/* Surface options */
frame = gtk_frame_new("Regions");
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, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(GTK_BOX(vbox)), PANEL_SPACING);
gui_button_x("Move selection up", region_move, (gpointer) UP, vbox);
gui_button_x("Move selection down", region_move, (gpointer) DOWN, vbox);
#define FF_TYPING 1
#if FF_TYPING
{
GList *list;
GtkWidget *combo, *hbox, *label;
/* EXP - forcefield assignment */
frame = gtk_frame_new("Typing");
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, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
gtk_container_set_border_width(GTK_CONTAINER(GTK_BOX(vbox)), PANEL_SPACING);
/* typing setup */
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new("Assign atom: ");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
list = NULL;
list = g_list_prepend(list, "QEq charges");
list = g_list_prepend(list, "CVFF labels");
list = g_list_prepend(list, "Dreiding labels");
list = g_list_prepend(list, "Gasteiger charges");
combo = gtk_combo_new();
gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo)->entry), FALSE);
gtk_combo_set_popdown_strings(GTK_COMBO(combo), list);
gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, PANEL_SPACING);
gui_button_x(NULL, cb_type_model, GTK_COMBO(combo)->entry, hbox);
}
#endif
#if DIFFAX
/* DIFFAX stuff - shunted here */
/* frame */
frame = gtk_frame_new("DIFFAX");
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(FALSE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
/* source */
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new(g_strdup_printf("Source model: %s", data->basename));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
/* layer subdivision */
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new("Number of layers ");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
diffract_layer_total = gtk_spin_button_new_with_range(0, 10, 1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(diffract_layer_total), 0);
gtk_box_pack_end(GTK_BOX(hbox), diffract_layer_total, FALSE, FALSE, 0);
/* layer stacking */
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, PANEL_SPACING);
label = gtk_label_new("Stacking sequence ");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
diffract_layer_order = gtk_entry_new();
gtk_box_pack_end(GTK_BOX(hbox), diffract_layer_order, FALSE, FALSE, 0);
/* action buttons */
hbox2 = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, PANEL_SPACING);
hbox = gtk_hbox_new(FALSE, PANEL_SPACING);
gtk_box_pack_end(GTK_BOX(hbox2), hbox, TRUE, FALSE, 0);
gui_icon_button(GTK_STOCK_APPLY, "Create ",
diffract_model_create, data,
hbox);
gui_icon_button(GTK_STOCK_SAVE, "Save ",
diffract_save_dialog, data,
hbox);
#endif
/* frame */
frame = gtk_frame_new("Experimental typing");
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(FALSE, PANEL_SPACING);
gtk_container_add(GTK_CONTAINER(frame), vbox);
w = gui_text_entry("FF label ", NULL, TRUE, FALSE, vbox);
dialog_child_set(dialog, "FF_label", w);
w = gui_text_entry("Neighbour Element ", NULL, TRUE, FALSE, vbox);
dialog_child_set(dialog, "FF_element", w);
w = gui_text_entry("Neighbour Distance ", NULL, TRUE, FALSE, vbox);
dialog_child_set(dialog, "FF_level", w);
w = gui_text_entry("Neighbour Count ", NULL, TRUE, FALSE, vbox);
dialog_child_set(dialog, "FF_count", w);
/* apply single rule */
gui_button_x("Apply rule ", gui_make_rule, dialog, vbox);
}
/**************************/
/* dialog update function */
/**************************/
void gui_edit_refresh(void)
{
/* may be other updates */
gui_spatial_populate();
}
/****************************/
/* the model editing dialog */
/****************************/
void gui_edit_dialog(void)
{
gint i;
gpointer dialog;
GtkWidget *window, *frame, *label;
GtkWidget *notebook, *page;
/* request a new dialog */
dialog = dialog_request(CREATOR, "Model editing", gui_edit_refresh, NULL, NULL);
if (!dialog)
return;
window = dialog_window(dialog);
/* notebook frame */
frame = gtk_frame_new(NULL);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), frame, FALSE, FALSE, 0);
gtk_container_set_border_width(GTK_CONTAINER(frame), PANEL_SPACING);
/* create notebook */
notebook = gtk_notebook_new();
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
gtk_container_add(GTK_CONTAINER(frame), notebook);
gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
/* add page */
page = gtk_vbox_new(FALSE,0);
label = gtk_label_new("Builder");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
build_page(page);
/* add page */
page = gtk_vbox_new(FALSE,0);
label = gtk_label_new("Spatials");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
spatial_page(page);
/* add page */
page = gtk_vbox_new(FALSE,0);
label = gtk_label_new("Transformations");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
trans_page(page);
/* add page */
page = gtk_vbox_new(FALSE,0);
label = gtk_label_new("Labelling");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
labelling_page(page, dialog);
/* add page */
page = gtk_vbox_new(FALSE,0);
label = gtk_label_new("Library");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
gui_library_window(page);
/* terminating buttons */
gui_stock_button(GTK_STOCK_CLOSE, dialog_destroy, dialog,
GTK_DIALOG(window)->action_area);
gtk_widget_show_all(window);
/* init the transformation values */
reset_transmat();
for (i=0 ; i<12; i++)
g_signal_connect(GTK_OBJECT(transmat[i]), "changed",
GTK_SIGNAL_FUNC(change_transmat), (gpointer) i);
}
syntax highlighted by Code2HTML, v. 0.9.1