/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 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 */ char * gnu_basename (char *); #include #include #include #include #include #include #include #include #include #include #ifdef XPM #include #endif #include "draw.h" #include "globals.h" void echo_to_message_area(char *); void clear_message_area (void); void place_dialog_cb (Widget, XtPointer, XtPointer); #ifdef HAVE_USLEEP static int frame_speed = 1; #endif static int stop_anim; #ifdef XPM static Widget save_anim_dialog = NULL; #endif static Widget label_w,stop_b; #ifdef HAVE_USLEEP static Widget speed_scale_w, scale_scroll_bar; #endif void make_frame_dlg(Widget parent) { void bounce_cb(Widget, XtPointer, XtPointer); void centre_b_cb(Widget, XtPointer, XtPointer); void frame_dlg_cancel_cb(Widget, XtPointer, XtPointer); void frame_no_cb(Widget, XtPointer, XtPointer); #ifdef HAVE_USLEEP void frame_speed_cb(Widget, XtPointer, XtPointer); #endif void next_frame_cb(Widget, XtPointer, XtPointer); void prev_frame_cb(Widget, XtPointer, XtPointer); void rewind_cb(Widget, XtPointer, XtPointer); void start_anim_cb(Widget, XtPointer, XtPointer); void stop_anim_cb(Widget, XtPointer, XtPointer); void update_frame_label(void); #ifdef XPM void make_anim_cb(Widget, XtPointer, XtPointer); #endif int n=0; #ifdef XPM Widget make_anim_b; #endif Widget rc_ver,rc_hor,start_b,next_b,prev_b,bounce_b,rewind_b; Widget centre_b, child; #ifdef HAVE_USLEEP int s, t, nkids; Arg tmpargs[2]; Widget *kids; #endif XmString label = ""; if (! frames_dialog) { label = XmStringCreateLocalized ("Frames"); XtSetArg (args[n], XmNautoUnmanage, False); n++; XtSetArg (args[n], XmNdialogTitle, label); n++; frames_dialog = (Widget) XmCreateMessageDialog (parent, "frames", args, n); rc_ver = XtVaCreateManagedWidget ("rc_ver",xmRowColumnWidgetClass,frames_dialog, NULL); label_w=XtVaCreateManagedWidget ("Comment", xmLabelWidgetClass, rc_ver, XmNlabelString, label, XmNwidth, 400, NULL); update_frame_label(); rc_hor = XtVaCreateManagedWidget ("rc_hor",xmRowColumnWidgetClass,rc_ver, XmNorientation, XmHORIZONTAL, NULL); start_b = XtVaCreateManagedWidget ("Start",xmPushButtonWidgetClass,rc_hor, NULL); XtAddCallback(start_b, XmNactivateCallback, start_anim_cb, NULL); stop_b = XtVaCreateManagedWidget ("Stop",xmPushButtonWidgetClass,rc_hor, NULL); XtAddCallback(stop_b, XmNactivateCallback, stop_anim_cb, NULL); next_b = XtVaCreateManagedWidget ("Next (>)",xmPushButtonWidgetClass,rc_hor, NULL); XtAddCallback(next_b, XmNactivateCallback, next_frame_cb, NULL); prev_b = XtVaCreateManagedWidget ("Previous (<)",xmPushButtonWidgetClass,rc_hor, NULL); XtAddCallback(prev_b, XmNactivateCallback, prev_frame_cb, NULL); rewind_b = XtVaCreateManagedWidget ("Rewind (^)",xmPushButtonWidgetClass,rc_hor, NULL); XtAddCallback(rewind_b, XmNactivateCallback, rewind_cb, NULL); bounce_b = XtVaCreateManagedWidget ("Bounce",xmPushButtonWidgetClass,rc_hor, NULL); XtAddCallback(bounce_b, XmNactivateCallback, bounce_cb, NULL); #ifdef XPM make_anim_b = XtVaCreateManagedWidget ("Make anim",xmPushButtonWidgetClass,rc_hor, NULL); XtAddCallback(make_anim_b, XmNactivateCallback, make_anim_cb, NULL); #endif #ifdef HAVE_USLEEP label=XmStringCreateLocalized("Select speed"); speed_scale_w = XtVaCreateManagedWidget ("Speed",xmScaleWidgetClass, rc_ver, XmNmaximum, 20, XmNminimum, 1, XmNvalue, (int) (20-frame_speed+1), XmNshowValue, True, XmNorientation, XmHORIZONTAL, XmNtitleString, label, NULL); /* need to access scale bar widget for callbacks */ s=0; XtSetArg(tmpargs[s], XmNnumChildren, &nkids); s++; XtSetArg(tmpargs[s], XmNchildren, &kids); s++; XtGetValues(speed_scale_w, tmpargs, s); for(t=0;t (no_frames - 1))) { echo_to_message_area("Choice of frame out of bounds!"); return; } /* if OK, change frame_no */ frame_no = temp_frame; sprintf(string,"Frame %d selected",frame_no+1); echo_to_message_area(string); if(centre_each_frame){ /* Change frame, reset title _and_ centre the frame */ change_frame(frame_no, True, True); }else{ /* Change frame, reset title, _don't_ centre the frame */ change_frame(frame_no, True, False); } } void start_anim_cb(Widget widget, XtPointer client_data, XtPointer call_data) { void change_frame(int, Boolean, Boolean); XEvent event; stop_anim=0; if(no_frames < 2){ return; } while(1){ /* infinite loop, stop with button press */ if(frame_novalue, XmFONTLIST_DEFAULT_TAG, &anim_file)) return; /* internal error */ /* Save directory shown in the dialog so that all the other file selection dialogs could be made to operate the very same directory */ set_current_directory (cbs->dir); } #ifdef GL set_gl_copy_canvas (1); #endif for(i = 0; i < no_frames; i++) { frame_no = i; XmUpdateDisplay(toplevel); /* handle all expose events during loop */ if(centre_each_frame) { /* Change frame, reset title _and_ centre the frame */ change_frame(frame_no, True, True); } else { /* Change frame, reset title, _don't_ centre the frame */ change_frame(frame_no, True, False); } sprintf(pixmap_file, "%s.%d.xpm", anim_file, (i + 1)); /* Write the `canvas_pm' to the file. */ if (write_xpm (pixmap_file, 1) == /*failure*/0) { /* Could not write the file. Flag the error so that we know not to overwrite the error message currently in the message area with our status message. */ success = /*failure*/ 0; } } #ifdef GL set_gl_copy_canvas (0); #endif if (success) { if(no_frames == 1) { sprintf(buf, "File %s.1.xpm written", gnu_basename(anim_file)); } else { sprintf(buf, "Files %s.1..%d.xpm written", gnu_basename(anim_file), no_frames); } echo_to_message_area(buf); } } #endif #ifdef HAVE_USLEEP void frame_speed_cb(Widget w, XtPointer client_data, XtPointer call_data) { XmScaleCallbackStruct *cbs= (XmScaleCallbackStruct *)call_data; frame_speed = 20-cbs->value+1; } #endif void centre_b_cb(Widget widget, XtPointer client_data, XtPointer call_data) { if(centre_each_frame==1){ centre_each_frame=0; echo_to_message_area("Not centering each frame"); }else{ centre_each_frame=1; echo_to_message_area("Centering each frame"); } } /* update_label is redundant - remove at some point from calls to change_frame */ void change_frame(int frame_no, Boolean update_label, Boolean centre_this_frame) { double get_angle_axis(double *); void canvas_cb(Widget, XtPointer, XtPointer); void centre_atoms(void); void make_label_uppercase (char *); void rotate_atoms(double *,double,Boolean,Boolean); void update_bbox(void); void update_bond_matrix(Boolean); void update_frame_label(void); void frame_content_to_atoms (int); int i,j; double angle,axis[3]; /* if no frames, return ... */ if(no_frames == 0) return; changing_frame = True; frame_content_to_atoms (frame_no); /* Centre frame if required, by modifying global_vector[] */ if(centre_this_frame){ centre_atoms(); } /* get angle-axis rotation from global_matrix positions... */ for(i=0;i<3;i++){ for(j=0;j<3;j++){ angle_axis_matrix[i][j]=global_matrix[i][j]; } } angle=get_angle_axis(axis); update_bbox(); update_bond_matrix (True); redraw=0; rotate_atoms(axis,angle,0,False); redraw=1; canvas_cb(canvas,NULL,NULL); update_frame_label(); changing_frame = False; } double get_angle_axis(double *axis) { int i,j; double angle,s,z,mod,r[3][3]; for(i=0;i<3;i++){ for(j=0;j<3;j++){ r[i][j]=angle_axis_matrix[i][j]; } } /* adapted from quater.f (ajs) */ z=r[0][0]+r[1][1]+r[2][2]+1; if(z>0){ angle=0.5*sqrt(z); }else{ angle=0; } if(angle > 0.0001){ axis[0]=0.25*(r[2][1]-r[1][2])/angle; axis[1]=0.25*(r[0][2]-r[2][0])/angle; axis[2]=0.25*(r[1][0]-r[0][1])/angle; }else{ s=1-r[0][0]-r[1][1]-r[2][2]; for(i=0;i<3;i++){ z=2*r[i][i]+s; if(z > 0){ axis[i]=0.5*sqrt(z); }else{ axis[i]=0; } } if(angle > 0){ if(r[1][0] < r[0][1]){axis[2]=-axis[2];} if(r[2][1] < r[1][2]){axis[0]=-axis[0];} if(r[0][2] < r[2][0]){axis[1]=-axis[1];} }else{ if(axis[0] > 0.5){ if(r[0][1]+r[1][0] < 0){axis[1]=-axis[1];} if(r[0][2]+r[2][0] < 0){axis[2]=-axis[2];} }else if(axis[1] > 0.5){ if(r[0][1]+r[1][0] < 0){axis[0]=-axis[0];} if(r[1][2]+r[2][1] < 0){axis[2]=-axis[2];} }else if(axis[2] > 0.5){ if(r[0][2]+r[2][0] < 0){axis[0]=-axis[0];} if(r[1][2]+r[2][1] < 0){axis[1]=-axis[1];} } } } angle=2*acos(angle); mod = (axis[0] * axis[0]) + (axis[1] * axis[1]) + (axis[2] * axis[2]); if(mod==0){ axis[2]=1; } return(angle); } void update_frame_label(void) { struct frame * get_selected_frame (int); char string[1024]; struct frame *this_frame; XmString xm_str; this_frame = get_selected_frame (frame_no); if(no_frames == 0) { sprintf(string, "No frames loaded"); } else if(strlen(this_frame->comment) == 0) { sprintf(string, "Frame %d (%d atoms); comment \"(empty)\".", frame_no + 1, this_frame->no_atoms); } else { sprintf(string, "Frame %d (%d atoms); comment \"%s\".", frame_no + 1, this_frame->no_atoms, this_frame->comment); } if(frames_dialog != NULL) { /* Set label in frames_dialog ... */ xm_str = XmStringCreateLocalized(string); XtVaSetValues (label_w, XmNlabelString, xm_str, NULL); XmStringFree(xm_str); clear_message_area (); } else { echo_to_message_area (string); } } void frame_key (Widget widget, XEvent *event, String *args, int *num_args) { void change_frame(int, Boolean, Boolean); if (*num_args != 1) { XtError ("Wrong number of args!"); } if (strcmp (args[0], "next") == 0) { if (frame_no == (no_frames - 1)) { frame_no = 0; } else { frame_no++; } } else if (strcmp (args[0], "prev") == 0) { if (frame_no == 0) { frame_no = no_frames - 1; } else { frame_no--; } } else if (strcmp (args[0], "start") == 0) { frame_no = 0; } /* Select the frame */ if (centre_each_frame) { change_frame(frame_no, True, True); } else { change_frame(frame_no, True, False); } }