/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Matthew P. Hodges This file is part of XMakemol. XMakemol 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, or (at your option) any later version. XMakemol 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 XMakemol; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "defs.h" #include "globals.h" void echo_to_message_area(char *); void place_dialog_cb (Widget, XtPointer, XtPointer); enum perspective_types {PERSPECTIVE_ALL, PERSPECTIVE_CURRENT}; static enum perspective_types perspective_type = PERSPECTIVE_ALL; static Widget d_scale, v_scale; char string[BUFSIZ]; double deg_to_rad=(double)(180.0/PI); void cont_cb(Widget widget, XtPointer client_data, XtPointer call_data) { void animate(Widget); void make_frame_dlg(Widget); void make_pers_dlg(Widget); void measure(Widget); int item_no = (int) client_data; switch(item_no){ case 0: make_frame_dlg(main_w); break; case 1: animate(main_w); break; case 2: measure(main_w); break; case 3: make_pers_dlg(main_w); break; } } void measure(Widget parent) { void meas_dlg_cancel_cb(Widget, XtPointer, XtPointer); void sel_reset_cb(Widget, XtPointer, XtPointer); void select_atom_cb(Widget, XtPointer, XtPointer); void update_lengths_dialog(Boolean); int i,j,k,w,n=0; static Widget meas_rc[6],meas_frame[4]; Widget sep,select_atom_label_w,select_atom_w,sel_reset_w; XmString label=XmStringCreateLocalized("Measure"); if(!meas_dialog){ XtSetArg (args[n],XmNdialogTitle, label); n++; XtSetArg (args[n],XmNautoUnmanage, False); n++; XtSetArg (args[n],XmNdefaultPosition, False); n++; meas_dialog=(Widget)XmCreateMessageDialog(parent, "lengths", args, n); label=XmStringCreateLocalized(" "); meas_rc[0] = XtVaCreateManagedWidget ("lengths", xmRowColumnWidgetClass,meas_dialog, XmNorientation, XmVERTICAL, NULL); meas_frame[0] = XtVaCreateManagedWidget ("frame1", xmFrameWidgetClass, meas_rc[0], XmNshadowType, XmSHADOW_IN, NULL); meas_rc[1] = XtVaCreateManagedWidget ("lengths", xmRowColumnWidgetClass,meas_frame[0], XmNorientation, XmVERTICAL, NULL); XtVaCreateManagedWidget ("Label X Y Z Type No.", xmLabelWidgetClass,meas_rc[1], XmNalignment, XmALIGNMENT_BEGINNING, NULL); if(!meas_label_w){ meas_label_w=(Widget *)malloc(15*sizeof(Widget)); } w=0; for(i=0;i<4;i++){ meas_label_w[w] = XtVaCreateManagedWidget ("dim", xmLabelWidgetClass,meas_rc[1], XmNlabelString, label, NULL); w++; } meas_rc[2] = XtVaCreateManagedWidget ("lengths", xmRowColumnWidgetClass,meas_rc[0], XmNorientation, XmHORIZONTAL, NULL); meas_frame[1] = XtVaCreateManagedWidget ("frame1", xmFrameWidgetClass, meas_rc[2], XmNshadowType, XmSHADOW_IN, NULL); meas_rc[3] = XtVaCreateManagedWidget ("lengths", xmRowColumnWidgetClass,meas_frame[1], XmNorientation, XmVERTICAL, NULL); XtVaCreateManagedWidget (" Lengths", xmLabelWidgetClass,meas_rc[3], XmNalignment, XmALIGNMENT_BEGINNING, NULL); for(i=0;i<3;i++){ for(j=i+1;j<4;j++){ meas_label_w[w] = XtVaCreateManagedWidget ("dim", xmLabelWidgetClass,meas_rc[3], XmNlabelString, label, NULL); w++; } } meas_rc[4] = XtVaCreateManagedWidget ("lengths", xmRowColumnWidgetClass,meas_rc[2] , XmNorientation, XmVERTICAL, NULL); meas_frame[2] = XtVaCreateManagedWidget ("frame1", xmFrameWidgetClass, meas_rc[4], XmNshadowType, XmSHADOW_IN, NULL); meas_rc[5] = XtVaCreateManagedWidget ("lengths", xmRowColumnWidgetClass,meas_frame[2] , XmNorientation, XmVERTICAL, NULL); XtVaCreateManagedWidget (" Angles", xmLabelWidgetClass,meas_rc[5], XmNalignment, XmALIGNMENT_BEGINNING, NULL); for(i=0;i<2;i++){ for(j=i+1;j<3;j++){ for(k=j+1;k<4;k++){ meas_label_w[w] = XtVaCreateManagedWidget ("dim", xmLabelWidgetClass,meas_rc[5], XmNlabelString, label, NULL); w++; } } } meas_frame[3] = XtVaCreateManagedWidget ("frame1", xmFrameWidgetClass, meas_rc[4], XmNshadowType, XmSHADOW_IN, NULL); meas_rc[5] = XtVaCreateManagedWidget ("lengths", xmRowColumnWidgetClass,meas_frame[3] , XmNorientation, XmVERTICAL, NULL); XtVaCreateManagedWidget (" Torsion", xmLabelWidgetClass,meas_rc[5], XmNalignment, XmALIGNMENT_BEGINNING, NULL); meas_label_w[w] = XtVaCreateManagedWidget ("dim", xmLabelWidgetClass,meas_rc[5], XmNlabelString, label, NULL); XmStringFree(label); sep=XmCreateSeparator(meas_rc[0],"sep",NULL,0); XtManageChild(sep); select_atom_label_w=XtVaCreateManagedWidget ("Select atom:", xmLabelWidgetClass,meas_rc[0], XmNalignment, XmALIGNMENT_BEGINNING, NULL); select_atom_w=XtVaCreateManagedWidget ("select",xmTextFieldWidgetClass,meas_rc[0], NULL); XtAddCallback(select_atom_w,XmNactivateCallback,select_atom_cb,NULL); sep=XmCreateSeparator(meas_rc[0],"sep",NULL,0); XtManageChild(sep); sel_reset_w=XtVaCreateManagedWidget ("Unselect all atoms",xmPushButtonWidgetClass,meas_rc[0],NULL); XtAddCallback(sel_reset_w,XmNactivateCallback,sel_reset_cb,NULL); /* If the user selects cancel, just destroy the meas_dialog */ XtAddCallback((Widget)meas_dialog, XmNcancelCallback, meas_dlg_cancel_cb, NULL); /* XtUnmanageChild (XmMessageBoxGetChild(meas_dialog,XmDIALOG_OK_BUTTON)); */ /* No help available ... */ XtUnmanageChild (XmMessageBoxGetChild(meas_dialog,XmDIALOG_HELP_BUTTON)); update_lengths_dialog(True); } XtAddCallback (meas_dialog, XmNmapCallback, place_dialog_cb, NULL); XtManageChild(meas_dialog); XtPopup(XtParent(meas_dialog), XtGrabNone); } void meas_dlg_cancel_cb(Widget widget, XtPointer client_data, XtPointer call_data) { XtDestroyWidget(meas_dialog); meas_dialog=NULL; } double get_length(int l, int m) { double x, y, z, distance; x = atoms[l].x - atoms[m].x; y = atoms[l].y - atoms[m].y; z = atoms[l].z - atoms[m].z; distance = sqrt ((x * x) + (y * y) + (z * z)); return (distance); } double get_angle(int l, int m, int n) { double dot_product(double *, double *); void normalize_vec(double *); double a[3],b[3],angle; /* work out angle */ a[0]=atoms[l].x-atoms[m].x; a[1]=atoms[l].y-atoms[m].y; a[2]=atoms[l].z-atoms[m].z; normalize_vec(a); b[0]=atoms[n].x-atoms[m].x; b[1]=atoms[n].y-atoms[m].y; b[2]=atoms[n].z-atoms[m].z; normalize_vec(b); angle=dot_product(a,b); angle=acos(angle)*deg_to_rad; return(angle); } double get_torsion(int l, int m, int n, int o) { double dot_product(double *, double *); void normalize_vec(double *); void vector_product(double *, double *, double *); double lm[3], mn[3], no[3], p[3], q[3], temp[3], torsion; /* work out torsion angle: there are four atoms (l,m,n,o). Two planes are defined - the first contains atoms l, m and n and the second contains atoms m, n and o. The angle between these two planes (actually plane normals) is the torsion angle. Additionally, we need to assign a sign - the cross product of the two plane normals is either parallel or antiparallel to the vector between atoms m and n. Parallel -> +ve torsion angle and antiparallel -> -ve torsion angle. */ /* The l->m vector */ lm[0] = atoms[m].x - atoms[l].x; lm[1] = atoms[m].y - atoms[l].y; lm[2] = atoms[m].z - atoms[l].z; normalize_vec(lm); /* The m->n vector */ mn[0] = atoms[n].x - atoms[m].x; mn[1] = atoms[n].y - atoms[m].y; mn[2] = atoms[n].z - atoms[m].z; normalize_vec(mn); /* The n->o vector */ no[0] = atoms[o].x - atoms[n].x; no[1] = atoms[o].y - atoms[n].y; no[2] = atoms[o].z - atoms[n].z; normalize_vec(no); /* The plane normal of (l,m,n) */ vector_product(p, lm, mn); /* p = lm x mn */ normalize_vec(p); /* The plane normal of (m,n,o) */ vector_product(q, mn, no); /* q = mn x no */ normalize_vec(q); /* The torsion angle is the angle between the two plane normals - the next step gives cos(torsion) */ torsion = dot_product(p, q); /* some systems don't like acos(1.0) and return nan0x7fffffff */ if(fabs((torsion - 1.0)) < 1e-10) { torsion = 0.0; } else { torsion = acos(torsion) * deg_to_rad; } /* Now determine the sign - determined from mn . (p x q) */ vector_product(temp, p, q); /* temp = p x q */ if(dot_product(mn, temp) < 0.0) { torsion *= -1.0; /* Negate */ } return(torsion); } void make_pers_dlg(Widget parent) { void d_scale_cb(Widget, XtPointer, XtPointer); void depth_on_cb(Widget, XtPointer, XtPointer); void pers_dlg_cancel_cb(Widget, XtPointer, XtPointer); void perspective_type_cb (Widget, XtPointer, XtPointer); void reset_pers_scales(void); void v_scale_cb(Widget, XtPointer, XtPointer); int n=0; Widget depth_on, rc1, radio, button; XmString title; if(!pers_dialog){ title=XmStringCreateLocalized("Perspective"); n=0; XtSetArg (args[n],XmNdialogTitle,title); n++; XtSetArg (args[n],XmNwidth,300); n++; pers_dialog=XmCreateMessageDialog(parent,"v_scale",args,n); rc1=XtVaCreateManagedWidget ("rc1",xmRowColumnWidgetClass,pers_dialog,NULL); title=XmStringCreateLocalized("Alter scale"); v_scale = XtVaCreateManagedWidget ("v_scale", xmScaleWidgetClass, rc1, XmNmaximum, 1000, XmNminimum, 0, XmNvalue, 0, XmNshowValue, True, XmNorientation, XmHORIZONTAL, XmNtitleString, title, NULL); XtAddCallback(v_scale, XmNdragCallback, v_scale_cb, NULL); XtAddCallback(v_scale, XmNvalueChangedCallback, v_scale_cb, NULL); title=XmStringCreateLocalized("Choose depth"); d_scale = XtVaCreateManagedWidget ("d_scale", xmScaleWidgetClass, rc1, XmNmaximum, 100, XmNminimum, 0, XmNvalue, 1, XmNshowValue, True, XmNorientation, XmHORIZONTAL, XmNtitleString, title, NULL); /* This sets the value correctly from the current canvas_scale */ reset_pers_scales(); XmStringFree(title); XtAddCallback(d_scale, XmNdragCallback, d_scale_cb, NULL); XtAddCallback(d_scale, XmNvalueChangedCallback, d_scale_cb, NULL); depth_on=XtVaCreateManagedWidget ("Toggle depth",xmToggleButtonGadgetClass, rc1, NULL); if(depth_is_on){ XtVaSetValues(depth_on,XmNset,True,NULL); } XtAddCallback(depth_on,XmNvalueChangedCallback, depth_on_cb,(XtPointer)1); XtManageChild (XmCreateSeparator (rc1, "sep", NULL, 0)); radio = XmCreateRadioBox (rc1, "pers_radio", NULL, 0); button = XtVaCreateManagedWidget ("Act on all frames", xmToggleButtonGadgetClass, radio, NULL); if (perspective_type == PERSPECTIVE_ALL) { XtVaSetValues (button, XmNset, True, NULL); } XtAddCallback (button, XmNvalueChangedCallback, perspective_type_cb, (XtPointer) PERSPECTIVE_ALL); button = XtVaCreateManagedWidget ("Act on current frame", xmToggleButtonGadgetClass, radio, NULL); if (perspective_type == PERSPECTIVE_CURRENT) { XtVaSetValues (button, XmNset, True, NULL); } XtAddCallback (button, XmNvalueChangedCallback, perspective_type_cb, (XtPointer) PERSPECTIVE_CURRENT); XtManageChild (radio); XtAddCallback(pers_dialog, XmNcancelCallback, pers_dlg_cancel_cb,NULL); XtUnmanageChild (XmMessageBoxGetChild(pers_dialog,XmDIALOG_OK_BUTTON)); /* No help available ... */ XtUnmanageChild (XmMessageBoxGetChild(pers_dialog,XmDIALOG_HELP_BUTTON)); } XtAddCallback (pers_dialog, XmNmapCallback, place_dialog_cb, NULL); XtManageChild(pers_dialog); } void pers_dlg_cancel_cb(Widget widget, XtPointer client_data, XtPointer call_data) { XtDestroyWidget(pers_dialog); pers_dialog=NULL; d_scale = NULL; v_scale = NULL; } void v_scale_cb(Widget widget, XtPointer client_data, XtPointer call_data) { void canvas_cb(Widget, XtPointer, XtPointer); struct frame * get_selected_frame (void); void set_canvas_scale (double); void set_scale_all_frames (int); double scale; struct frame *this_frame; XmScaleCallbackStruct *cbs= (XmScaleCallbackStruct *)call_data; int cb_value; cb_value = cbs->value; if (no_frames != 0) { if (perspective_type == PERSPECTIVE_CURRENT) { /* Update current frame */ this_frame = get_selected_frame (); this_frame->perspective_scale = cb_value; } else { /* Update all frames */ set_scale_all_frames (cb_value); } } /* cb_value can vary between 0 and 1000 so we can vary the scale between 0 and 1023 */ scale = pow (2.0, cb_value / 100.0) - 1; set_canvas_scale (scale); redraw = 1; canvas_cb (canvas, NULL, NULL); } void set_scale_all_frames (int value) { struct frame * get_first_frame (); struct frame *this_frame; this_frame = get_first_frame (); while (this_frame != NULL) { this_frame->perspective_scale = value; this_frame = this_frame->next; } } void d_scale_cb (Widget widget, XtPointer client_data, XtPointer call_data) { void canvas_cb(Widget, XtPointer, XtPointer); struct frame * get_selected_frame (void); void set_depth_all_frames (int); void set_z_depth (double); struct frame *this_frame; XmScaleCallbackStruct *cbs= (XmScaleCallbackStruct *)call_data; int cb_value; cb_value = cbs->value; depth = cb_value; if (no_frames != 0) { if (perspective_type == PERSPECTIVE_CURRENT) { /* Update current frame */ this_frame = get_selected_frame (); this_frame->perspective_depth = cb_value; } else { /* Update all frames */ set_depth_all_frames (cb_value); } } set_z_depth (depth); redraw = 1; canvas_cb (canvas, NULL, NULL); } void set_depth_all_frames (int value) { struct frame * get_first_frame (); struct frame *this_frame; this_frame = get_first_frame (); while (this_frame != NULL) { this_frame->perspective_depth = value; this_frame = this_frame->next; } } void depth_on_cb(Widget widget, XtPointer client_data, XtPointer call_data) { void canvas_cb(Widget, XtPointer, XtPointer); if(depth_is_on==0){ depth_is_on=1; }else{ depth_is_on=0; } redraw=1; canvas_cb(canvas,NULL,NULL); /* update display */ } void perspective_type_cb (Widget widget, XtPointer client_data, XtPointer call_data) { perspective_type = (enum perspective_types) client_data; } void select_atom_cb(Widget widget, XtPointer client_data, XtPointer call_data) { void update_selected(int); int selected_atom; char* selected_atom_str,string[100]; XtVaGetValues(widget,XmNvalue,&selected_atom_str,NULL); if ((strlen (selected_atom_str) == 0) || (sscanf (selected_atom_str, "%d", &selected_atom) <= 0)) { echo_to_message_area("Cannot parse string!"); return; } selected_atom--; /* 0..no_atoms-1 */ if((selected_atom>no_atoms-1)||(selected_atom<0)){ echo_to_message_area("Choice of atom out of bounds!"); return; }else{ update_selected(selected_atom); sprintf(string,"Atom %d selected",selected_atom+1); echo_to_message_area(string); } } void sel_reset_cb(Widget widget, XtPointer client_data, XtPointer call_data) { void canvas_cb(Widget, XtPointer, XtPointer); void update_lengths_dialog(Boolean); int i; for(i = 0; i < 4; i++) { if(selected[i] != -1) { atoms[selected[i]].sel = 0; selected[i] = -1; } } redraw = 1; canvas_cb(canvas, NULL, NULL); update_lengths_dialog(True); } void reset_pers_scales(void) { double get_z_depth(void); double get_canvas_scale(void); int xm_nint (double); int v_scale_int, local_z_depth; v_scale_int = xm_nint (100.0 * log (get_canvas_scale() + 1) / log(2.0)); if(d_scale != NULL) { local_z_depth = (int) get_z_depth(); XtVaSetValues(d_scale, XmNvalue, local_z_depth, NULL); } if(v_scale != NULL) { XtVaSetValues(v_scale, XmNvalue, v_scale_int, NULL); } }