OSDN Git Service

Ruby: Molecule#make_front, set_name, get_view_rotation, get_view_scale, get_view_tran...
authortoshinagata1964 <toshinagata1964@a2be9bc6-48de-4e38-9406-05402d4bc13c>
Tue, 31 Jan 2012 10:04:29 +0000 (10:04 +0000)
committertoshinagata1964 <toshinagata1964@a2be9bc6-48de-4e38-9406-05402d4bc13c>
Tue, 31 Jan 2012 10:04:29 +0000 (10:04 +0000)
git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/molby/trunk@179 a2be9bc6-48de-4e38-9406-05402d4bc13c

MolLib/MainView.c
MolLib/MainView.h
MolLib/Molecule.h
MolLib/Ruby_bind/ruby_bind.c
MolLib/Types.h
wxSources/MoleculeView.cpp
wxSources/MyDocument.cpp

index 598b102..10e31e2 100755 (executable)
@@ -906,9 +906,8 @@ drawCone(const GLfloat *a, const GLfloat *b, GLfloat r, int sect, int closed)
 {
     GLfloat *c, *s;
     int n, i;
-       float nx, ny, nz;
     GLfloat d[3], v[3], w[3];
-       Vector p1, p2;
+       Vector p1, nv;
     n = setSinCache(sect);
     if (n <= 0)
         return;
@@ -920,31 +919,32 @@ drawCone(const GLfloat *a, const GLfloat *b, GLfloat r, int sect, int closed)
     if (getOrthogonalVectors(d, v, w) == 0)
         return;
     glBegin(GL_TRIANGLE_FAN);
-       glVertex3f(a[0], a[1], a[2]);
-       p1.x = b[0] + r * (v[0] * c[0] + w[0] * s[0]);
-       p1.y = b[1] + r * (v[1] * c[0] + w[1] * s[0]);
-       p1.z = b[2] + r * (v[2] * c[0] + w[2] * s[0]);
-       glVertex3f(p1.x, p1.y, p1.z);
-    for (i = 1; i <= n; i++) {
-        p2.x = b[0] + r * (v[0] * c[i] + w[0] * s[i]);
-        p2.y = b[1] + r * (v[1] * c[i] + w[1] * s[i]);
-        p2.z = b[2] + r * (v[2] * c[i] + w[2] * s[i]);
-               nx = p1.x + p2.x - b[0] * 2;
-               ny = p1.y + p2.y - b[1] * 2;
-               nz = p1.z + p2.z - b[2] * 2;
-        glNormal3f(nx, ny, nz);
-               glVertex3f(p2.x, p2.y, p2.z);
-               p1 = p2;
+       nv.x = d[0];
+       nv.y = d[1];
+       nv.z = d[2];
+       NormalizeVec(&nv, &nv);
+       glNormal3f(nv.x, nv.y, nv.z);
+       glVertex3f(b[0], b[1], b[2]);
+    for (i = 0; i <= n; i++) {
+        nv.x = v[0] * c[i] + w[0] * s[i];
+        nv.y = v[1] * c[i] + w[1] * s[i];
+        nv.z = v[2] * c[i] + w[2] * s[i];
+               glNormal3f(nv.x, nv.y, nv.z);
+               p1.x = a[0] + r * nv.x;
+               p1.y = a[1] + r * nv.y;
+               p1.z = a[2] + r * nv.z;
+        glNormal3f(nv.x, nv.y, nv.z);
+               glVertex3f(p1.x, p1.y, p1.z);
     }
     glEnd();
        if (closed) {
                glBegin(GL_TRIANGLE_FAN);
                glNormal3f(d[0], d[1], d[2]);
                for (i = 0; i <= n; i++) {
-                       p2.x = b[0] + r * (v[0] * c[i] + w[0] * s[i]);
-                       p2.y = b[1] + r * (v[1] * c[i] + w[1] * s[i]);
-                       p2.z = b[2] + r * (v[2] * c[i] + w[2] * s[i]);
-                       glVertex3f(p2.x, p2.y, p2.z);
+                       p1.x = a[0] + r * (v[0] * c[i] + w[0] * s[i]);
+                       p1.y = a[1] + r * (v[1] * c[i] + w[1] * s[i]);
+                       p1.z = a[2] + r * (v[2] * c[i] + w[2] * s[i]);
+                       glVertex3f(p1.x, p1.y, p1.z);
                }
                glEnd();
        }
@@ -1610,40 +1610,60 @@ skip:
 static void
 drawGraphics(MainView *mview)
 {
-       int i, j, n;
+       int i, j;
        MainViewGraphic *g;
        for (i = 0; i < mview->ngraphics; i++) {
                g = &mview->graphics[i];
+               if (g->visible == 0)
+                       continue;
                glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, g->rgba);
                switch (g->kind) {
                        case kMainViewGraphicLine:
                                glDisable(GL_LIGHTING);
                                glColor4fv(g->rgba);
-                               glBegin(GL_LINES);
-                               n = g->npoints;
-                               if (n % 2 == 1)
-                                       n--;
-                               for (j = 0; j < n; j++)
+                               glBegin(GL_LINE_STRIP);
+                               for (j = 0; j < g->npoints; j++) {
+                                       if (g->points[j * 3] >= kInvalidFloat)
+                                               break;
                                        glVertex3fv(&g->points[j * 3]);
+                               }
                                glEnd();
                                glEnable(GL_LIGHTING);
                                break;
-                       case kMainViewGraphicPoly:
+                       case kMainViewGraphicPoly: {
+                               Vector v0, v1, v2, v3;
                                glBegin(GL_TRIANGLE_FAN);
-                               for (j = 0; j < g->npoints; j++)
+                               v1.x = g->points[0] - g->points[g->npoints - 3];
+                               v1.y = g->points[1] - g->points[g->npoints - 2];
+                               v1.z = g->points[2] - g->points[g->npoints - 1];
+                               v0 = v1;
+                               for (j = 0; j < g->npoints; j++) {
+                                       v2.x = g->points[j * 3 + 3] - g->points[j * 3];
+                                       v2.y = g->points[j * 3 + 4] - g->points[j * 3 + 1];
+                                       v2.z = g->points[j * 3 + 5] - g->points[j * 3 + 2];
+                                       VecCross(v3, v1, v2);
+                                       if (NormalizeVec(&v3, &v3) == 0)
+                                               glNormal3f(v3.x, v3.y, v3.z);
                                        glVertex3fv(&g->points[j * 3]);
-                               if (g->closed)
+                                       v1 = v2;
+                               }
+                               if (g->closed) {
+                                       VecCross(v3, v1, v0);
+                                       if (NormalizeVec(&v3, &v3) == 0)
+                                               glNormal3f(v3.x, v3.y, v3.z);
                                        glVertex3fv(g->points);
+                               }
                                glEnd();
                                break;
+                       }
                        case kMainViewGraphicCylinder:
-                               drawCylinder(g->points, g->points + 3, g->points[6], 6, g->closed);
+                               drawCylinder(g->points, g->points + 3, g->points[6], 15, g->closed);
                                break;
                        case kMainViewGraphicCone:
-                               drawCone(g->points, g->points + 3, g->points[6], 6, g->closed);
+                               drawCone(g->points, g->points + 3, g->points[6], 15, g->closed);
                                break;
                        case kMainViewGraphicEllipsoid:
-                               drawEllipsoid(g->points, g->points + 3, g->points + 6, g->points + 9, 6);
+                               drawEllipsoid(g->points, g->points + 3, g->points + 6, g->points + 9, 8);
                                break;
                }
        }
@@ -1806,7 +1826,7 @@ compareLabelByDepth(const void *ap, const void *bp)
 static void
 drawLabels(MainView *mview)
 {
-       Transform *trp;
+/*     Transform *trp; */
        Atom *ap;
        LabelRecord *lp;
        int i, nlabels;
index eca59ec..a12dadc 100755 (executable)
@@ -85,7 +85,8 @@ enum {
 
 typedef struct MainViewGraphic {
        Int kind;
-       Int closed;
+       Byte closed;
+       Byte visible;
        GLfloat rgba[4];
        Int npoints;
        GLfloat *points;
@@ -235,6 +236,7 @@ STUB void MainViewCallback_lockFocus(MainView *mview);
 STUB void MainViewCallback_unlockFocus(MainView *mview);
 STUB void MainViewCallback_frame(MainView *mview, float *rect);
 STUB void MainViewCallback_display(MainView *mview);
+STUB void MainViewCallback_makeFront(MainView *mview);
 STUB void MainViewCallback_setNeedsDisplay(MainView *mview, int flag);
 STUB void MainViewCallback_setKeyboardFocus(MainView *mview);
 STUB int MainViewCallback_mouseCheck(MainView *mview);
index 86c721e..00b0998 100755 (executable)
@@ -509,6 +509,7 @@ STUB Molecule *MoleculeCallback_moleculeAtIndex(int idx);
 STUB Molecule *MoleculeCallback_moleculeAtOrderedIndex(int idx);
 STUB void MoleculeCallback_displayName(Molecule *mol, char *buf, int bufsize);
 STUB void MoleculeCallback_pathName(Molecule *mol, char *buf, int bufsize);
+STUB int MoleculeCallback_setDisplayName(Molecule *mol, const char *name);
 
 STUB void MoleculeCallback_lockMutex(void *mutex);
 STUB void MoleculeCallback_unlockMutex(void *mutex);
index 54b863c..91d5f9c 100644 (file)
@@ -4664,6 +4664,24 @@ s_Molecule_Name(VALUE self)
 
 /*
  *  call-seq:
+ *     set_name(string) -> self
+ *
+ *  Set the name of an untitled molecule. If the molecule is not associated with window
+ *  or it already has an associated file, then exception is thrown.
+ */
+static VALUE
+s_Molecule_SetName(VALUE self, VALUE nval)
+{
+    Molecule *mol;
+    Data_Get_Struct(self, Molecule, mol);
+       if (MoleculeCallback_setDisplayName(mol, StringValuePtr(nval)))
+               rb_raise(rb_eMolbyError, "Cannot change the window title");
+       return self;
+}
+
+
+/*
+ *  call-seq:
  *     path       -> String
  *
  *  Returns the full path name of the molecule, if it is associated with a file.
@@ -7470,6 +7488,22 @@ s_Molecule_Display(VALUE self)
 
 /*
  *  call-seq:
+ *     make_front
+ *
+ *  Make the window frontmost if this molecule is bound to a view. Otherwise do nothing.
+ */
+static VALUE
+s_Molecule_MakeFront(VALUE self)
+{
+    Molecule *mol;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview != NULL)
+               MainViewCallback_makeFront(mol->mview);
+       return Qnil;
+}
+
+/*
+ *  call-seq:
  *     update_enabled? -> bool
  *
  *  Returns true if screen update is enabled; otherwise no.
@@ -7771,6 +7805,135 @@ s_Molecule_ResizeToFit(VALUE self)
 
 /*
  *  call-seq:
+ *     get_view_rotation -> [[ax, ay, az], angle]
+ *
+ *  Get the current rotation for the view. Angle is in degree, not radian.
+ */
+static VALUE
+s_Molecule_GetViewRotation(VALUE self)
+{
+    Molecule *mol;
+       float f[4];
+       Vector v;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               return Qnil;
+       TrackballGetRotate(mol->mview->track, f);
+       v.x = f[1];
+       v.y = f[2];
+       v.z = f[3];
+       return rb_ary_new3(2, ValueFromVector(&v), rb_float_new(f[0]));
+}
+
+/*
+ *  call-seq:
+ *     get_view_scale -> float
+ *
+ *  Get the current scale for the view.
+ */
+static VALUE
+s_Molecule_GetViewScale(VALUE self)
+{
+    Molecule *mol;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               return Qnil;
+       return rb_float_new(TrackballGetScale(mol->mview->track));
+}
+
+/*
+ *  call-seq:
+ *     get_view_translation -> Vector
+ *
+ *  Get the current translation factor for the view.
+ */
+static VALUE
+s_Molecule_GetViewTranslation(VALUE self)
+{
+    Molecule *mol;
+       float f[4];
+       Vector v;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               return Qnil;
+       TrackballGetTranslate(mol->mview->track, f);
+       v.x = f[0];
+       v.y = f[1];
+       v.z = f[2];
+       return ValueFromVector(&v);
+}
+
+/*
+ *  call-seq:
+ *     set_view_rotation([ax, ay, az], angle) -> self
+ *
+ *  Set the current rotation for the view. Angle is in degree, not radian.
+ */
+static VALUE
+s_Molecule_SetViewRotation(VALUE self, VALUE aval, VALUE angval)
+{
+    Molecule *mol;
+       float f[4];
+       Vector v;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               return Qnil;
+       VectorFromValue(aval, &v);
+       if (NormalizeVec(&v, &v))
+               rb_raise(rb_eMolbyError, "Cannot normalize nearly zero vector");
+       f[1] = v.x;
+       f[2] = v.y;
+       f[3] = v.z;
+       f[0] = NUM2DBL(rb_Float(angval));
+       TrackballSetRotate(mol->mview->track, f);
+       MainViewCallback_setNeedsDisplay(mol->mview, 0);
+       return self;
+}
+
+/*
+ *  call-seq:
+ *     set_view_scale(scale) -> self
+ *
+ *  Set the current scale for the view.
+ */
+static VALUE
+s_Molecule_SetViewScale(VALUE self, VALUE aval)
+{
+    Molecule *mol;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               return Qnil;
+       TrackballSetScale(mol->mview->track, NUM2DBL(rb_Float(aval)));
+       MainViewCallback_setNeedsDisplay(mol->mview, 0);
+       return self;
+}
+
+/*
+ *  call-seq:
+ *     set_view_translation(vec) -> self
+ *
+ *  Set the current translation for the view.
+ */
+static VALUE
+s_Molecule_SetViewTranslation(VALUE self, VALUE aval)
+{
+    Molecule *mol;
+       Vector v;
+       float f[4];
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               return Qnil;
+       VectorFromValue(aval, &v);
+       f[0] = v.x;
+       f[1] = v.y;
+       f[2] = v.z;
+       TrackballSetTranslate(mol->mview->track, f);
+       MainViewCallback_setNeedsDisplay(mol->mview, 0);
+       return self;
+}
+
+/*
+ *  call-seq:
  *     set_background_color(red, green, blue)
  *
  *  Set the background color of the model window.
@@ -7812,6 +7975,7 @@ s_Molecule_CreateGraphic(int argc, VALUE *argv, VALUE self)
        rb_scan_args(argc, argv, "31", &kval, &cval, &pval, &fval);
        kval = rb_obj_as_string(kval);
        memset(&g, 0, sizeof(g));
+       g.visible = 1;
        p = RSTRING_PTR(kval);
        if (strcmp(p, "line") == 0)
                g.kind = kMainViewGraphicLine;
@@ -7840,8 +8004,8 @@ s_Molecule_CreateGraphic(int argc, VALUE *argv, VALUE self)
                rb_raise(rb_eArgError, "no control points are given");
        switch (g.kind) {
                case kMainViewGraphicLine:
-                       if (n % 2 != 0)
-                               rb_raise(rb_eArgError, "the line object must have even number of control points");
+                       if (n < 2)
+                               rb_raise(rb_eArgError, "the line object must have at least two control points");
                        break;
                case kMainViewGraphicPoly:
                        if (n < 3)
@@ -7954,7 +8118,10 @@ s_Molecule_SetGraphicPoint(VALUE self, VALUE gval, VALUE pval, VALUE nval)
                        return nval;
                } else rb_raise(rb_eArgError, "the argument must be an array-like object");
        } else {
-               VectorFromValue(nval, &v);
+               if (nval == Qnil) {
+                       v.x = kInvalidFloat;
+                       v.y = v.z = 0.0;
+               } else VectorFromValue(nval, &v);
        }
        gp->points[index * 3] = v.x;
        gp->points[index * 3 + 1] = v.y;
@@ -7965,6 +8132,89 @@ s_Molecule_SetGraphicPoint(VALUE self, VALUE gval, VALUE pval, VALUE nval)
 
 /*
  *  call-seq:
+ *     set_graphic_color(graphic_index, new_value) -> new_value
+ *
+ *  Change the color of graphic_index-th graphic object
+ *   
+ */
+static VALUE
+s_Molecule_SetGraphicColor(VALUE self, VALUE gval, VALUE cval)
+{
+       MainViewGraphic *gp;
+    Molecule *mol;
+       int index, n;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
+       index = NUM2INT(rb_Integer(gval));
+       if (index < 0 || index >= mol->mview->ngraphics)
+               rb_raise(rb_eArgError, "the graphic index is out of range");
+       gp = mol->mview->graphics + index;
+       cval = rb_ary_to_ary(cval);
+       n = RARRAY_LEN(cval);
+       if (n != 3 && n != 4)
+               rb_raise(rb_eArgError, "the color argument must have 3 or 4 numbers");
+       for (index = 0; index < n; index++) {
+               gp->rgba[index] = NUM2DBL(rb_Float(RARRAY_PTR(cval)[index]));
+       }
+       if (n == 3)
+               gp->rgba[3] = 1.0;
+       MoleculeCallback_notifyModification(mol, 0);
+       return cval;
+}
+
+/*
+ *  call-seq:
+ *     show_graphic(graphic_index) -> self
+ *
+ *  Enable the visible flag of the graphic_index-th graphic object
+ *   
+ */
+static VALUE
+s_Molecule_ShowGraphic(VALUE self, VALUE gval)
+{
+       MainViewGraphic *gp;
+    Molecule *mol;
+       int index;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
+       index = NUM2INT(rb_Integer(gval));
+       if (index < 0 || index >= mol->mview->ngraphics)
+               rb_raise(rb_eArgError, "the graphic index is out of range");
+       gp = mol->mview->graphics + index;
+       gp->visible = 1;
+       MoleculeCallback_notifyModification(mol, 0);
+       return self;
+}
+
+/*
+ *  call-seq:
+ *     hide_graphic(graphic_index) -> self
+ *
+ *  Disable the visible flag of the graphic_index-th graphic object
+ *   
+ */
+static VALUE
+s_Molecule_HideGraphic(VALUE self, VALUE gval)
+{
+       MainViewGraphic *gp;
+    Molecule *mol;
+       int index;
+    Data_Get_Struct(self, Molecule, mol);
+       if (mol->mview == NULL)
+               rb_raise(rb_eMolbyError, "this molecule has no associated graphic view");
+       index = NUM2INT(rb_Integer(gval));
+       if (index < 0 || index >= mol->mview->ngraphics)
+               rb_raise(rb_eArgError, "the graphic index is out of range");
+       gp = mol->mview->graphics + index;
+       gp->visible = 0;
+       MoleculeCallback_notifyModification(mol, 0);
+       return self;
+}
+
+/*
+ *  call-seq:
  *     show_text(string)
  *
  *  Show the string in the info text box.
@@ -8562,6 +8812,7 @@ Init_Molby(void)
     rb_define_method(rb_cMolecule, "savedcd", s_Molecule_Savedcd, 1);
     rb_define_method(rb_cMolecule, "savetep", s_Molecule_Savetep, 1);
     rb_define_method(rb_cMolecule, "name", s_Molecule_Name, 0);
+       rb_define_method(rb_cMolecule, "set_name", s_Molecule_SetName, 1);
     rb_define_method(rb_cMolecule, "path", s_Molecule_Path, 0);
     rb_define_method(rb_cMolecule, "dir", s_Molecule_Dir, 0);
     rb_define_method(rb_cMolecule, "inspect", s_Molecule_Inspect, 0);
@@ -8670,6 +8921,7 @@ Init_Molby(void)
        rb_define_method(rb_cMolecule, "wrap_unit_cell", s_Molecule_WrapUnitCell, 1);
        rb_define_method(rb_cMolecule, "find_conflicts", s_Molecule_FindConflicts, -1);
        rb_define_method(rb_cMolecule, "display", s_Molecule_Display, 0);
+       rb_define_method(rb_cMolecule, "make_front", s_Molecule_MakeFront, 0);
        rb_define_method(rb_cMolecule, "update_enabled?", s_Molecule_UpdateEnabled, 0);
        rb_define_method(rb_cMolecule, "update_enabled=", s_Molecule_SetUpdateEnabled, 1);      
        rb_define_method(rb_cMolecule, "show_unitcell", s_Molecule_ShowUnitCell, -1);
@@ -8697,11 +8949,20 @@ Init_Molby(void)
        rb_define_method(rb_cMolecule, "line_mode", s_Molecule_LineMode, -1);
        rb_define_alias(rb_cMolecule, "line_mode=", "line_mode");
        rb_define_method(rb_cMolecule, "resize_to_fit", s_Molecule_ResizeToFit, 0);
+       rb_define_method(rb_cMolecule, "get_view_rotation", s_Molecule_GetViewRotation, 0);
+       rb_define_method(rb_cMolecule, "get_view_scale", s_Molecule_GetViewScale, 0);
+       rb_define_method(rb_cMolecule, "get_view_translation", s_Molecule_GetViewTranslation, 0);
+       rb_define_method(rb_cMolecule, "set_view_rotation", s_Molecule_SetViewRotation, 2);
+       rb_define_method(rb_cMolecule, "set_view_scale", s_Molecule_SetViewScale, 1);
+       rb_define_method(rb_cMolecule, "set_view_translation", s_Molecule_SetViewTranslation, 1);
        rb_define_method(rb_cMolecule, "set_background_color", s_Molecule_SetBackgroundColor, -1);
        rb_define_method(rb_cMolecule, "create_graphic", s_Molecule_CreateGraphic, -1);
        rb_define_method(rb_cMolecule, "delete_graphic", s_Molecule_DeleteGraphic, 1);
        rb_define_method(rb_cMolecule, "ngraphics", s_Molecule_NGraphics, 0);
        rb_define_method(rb_cMolecule, "set_graphic_point", s_Molecule_SetGraphicPoint, 3);
+       rb_define_method(rb_cMolecule, "set_graphic_color", s_Molecule_SetGraphicColor, 2);
+       rb_define_method(rb_cMolecule, "show_graphic", s_Molecule_ShowGraphic, 1);
+       rb_define_method(rb_cMolecule, "hide_graphic", s_Molecule_HideGraphic, 1);
        rb_define_method(rb_cMolecule, "show_text", s_Molecule_ShowText, 1);
        rb_define_method(rb_cMolecule, "md_arena", s_Molecule_MDArena, 0);
        rb_define_method(rb_cMolecule, "set_parameter_attr", s_Molecule_SetParameterAttr, 5);
index 3d4c88b..dd78283 100755 (executable)
@@ -71,6 +71,8 @@ typedef unsigned int UInt;
 
 #define kInvalidIndex -99999999  /*  Used for terminating integer array  */
 
+#define kInvalidFloat 1e30
+
 typedef struct Vector { Double x, y, z; } Vector;
 typedef struct Quat { Double x, y, z, w; } Quat;   /*  A quaternion  */
 typedef Double Mat33[9];  /*  Columns first!  */
index 40ca4b7..f632fdf 100755 (executable)
@@ -831,6 +831,14 @@ MainViewCallback_display(MainView *mview)
 }
 
 void
+MainViewCallback_makeFront(MainView *mview)
+{
+       if (mview != NULL && mview->ref != NULL) {
+               ((MoleculeView *)(mview->ref))->GetFrame()->Raise();
+       }
+}
+
+void
 MainViewCallback_setNeedsDisplay(MainView *mview, int flag)
 {
   if (mview != NULL && mview->ref != NULL) {
index dc650d6..8a812de 100755 (executable)
@@ -1662,6 +1662,18 @@ MoleculeCallback_pathName(Molecule *mol, char *buf, int bufsize)
        else buf[0] = 0;
 }
 
+int
+MoleculeCallback_setDisplayName(Molecule *mol, const char *name)
+{
+       MyDocument *doc = MyDocumentFromMolecule(mol);
+       if (doc == NULL || doc->hasFile)
+               return 1; /*  Cannot change file-associated window title  */
+       wxString fname(name, wxConvFile);
+       doc->SetTitle(fname);
+       doc->GetFirstView()->OnChangeFilename();
+       return 0;
+}
+
 void
 MoleculeCallback_lockMutex(void *mutex)
 {