1 
2 /*
3 A* -------------------------------------------------------------------
4 B* This file contains source code for the PyMOL computer program
5 C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
6 D* -------------------------------------------------------------------
7 E* It is unlawful to modify or remove this copyright notice.
8 F* -------------------------------------------------------------------
9 G* Please see the accompanying LICENSE file for further information.
10 H* -------------------------------------------------------------------
11 I* Additional authors of this source file include:
12 -*
13 -*
14 -*
15 Z* -------------------------------------------------------------------
16 */
17 #include"os_python.h"
18 
19 #include"os_predef.h"
20 #include"os_std.h"
21 #include"os_gl.h"
22 #include"Err.h"
23 
24 #include"PConv.h"
25 #include"MemoryDebug.h"
26 #include"Vector.h"
27 #include"Matrix.h"
28 #include"ButMode.h"
29 #include"Scene.h"
30 #include"Editor.h"
31 #include"Selector.h"
32 #include"Ortho.h"
33 #include"main.h"
34 #include"Color.h"
35 #include"Setting.h"
36 #include"Util.h"
37 #include"Executive.h"
38 #include"P.h"
39 #include"CGO.h"
40 #include "Lex.h"
41 
42 struct _CEditor {
43   ObjectMolecule *DihedObject;
44   WordType DragSeleName;
45   int Active;
46   int ActiveState;
47   int DragIndex;
48   int DragSelection;
49   int DragHaveAxis, DragHaveBase, DragBondFlag, DragSlowFlag;
50   int PickMode;                 /* 1 = atom, 2 = bond, 3 = multiatom */
51   int NextPickSele;
52   int BondMode;
53   CObject *DragObject;
54   int NFrag;
55   float V0[3], V1[3], Axis[3], Center[3], DragBase[3];
56   float *PosVLA;
57   int ShowFrags;
58   int DihedralInvalid;
59   int MouseInvalid;
60   int FavorOrigin;
61   float FavoredOrigin[3];
62   CGO *shaderCGO;
63 };
64 
EditorGetScheme(PyMOLGlobals * G)65 int EditorGetScheme(PyMOLGlobals * G)
66 {
67   CEditor *I = G->Editor;
68   int scheme = EDITOR_SCHEME_OBJ;
69 
70   if(EditorActive(G))
71     scheme = EDITOR_SCHEME_FRAG;
72   else if(I->DragObject) {
73     if(I->DragIndex >= 0) {
74       scheme = EDITOR_SCHEME_OBJ;
75     } else {
76       scheme = EDITOR_SCHEME_DRAG;
77     }
78   }
79   return scheme;
80 }
81 
EditorFavorOrigin(PyMOLGlobals * G,float * v1)82 void EditorFavorOrigin(PyMOLGlobals * G, float *v1)
83 {
84   CEditor *I = G->Editor;
85   if(v1) {
86     I->FavorOrigin = true;
87     copy3f(v1, I->FavoredOrigin);
88   } else {
89     I->FavorOrigin = false;
90   }
91 }
92 
EditorDrawDihedral(PyMOLGlobals * G)93 static void EditorDrawDihedral(PyMOLGlobals * G)
94 {
95   if(EditorActive(G) && EditorIsBondMode(G)
96      && SettingGetGlobal_b(G, cSetting_editor_auto_dihedral)) {
97     ObjectMolecule *obj1, *obj2;
98     int at1, at2, at0, at3;
99     int sele1 = SelectorIndexByName(G, cEditorSele1);
100     int sele2 = SelectorIndexByName(G, cEditorSele2);
101     if((sele1 >= 0) && (sele2 >= 0)) {
102       obj1 = SelectorGetFastSingleAtomObjectIndex(G, sele1, &at1);
103       obj2 = SelectorGetFastSingleAtomObjectIndex(G, sele2, &at2);
104       if(obj1 && (obj1 == obj2)) {
105         CEditor *I = G->Editor;
106 
107         I->DihedObject = obj1;
108         at0 = ObjectMoleculeGetTopNeighbor(G, obj1, at1, at2);
109         at3 = ObjectMoleculeGetTopNeighbor(G, obj1, at2, at1);
110 
111         if((at0 >= 0) && (at3 >= 0)) {
112           /* find the highest priority atom attached to index1 */
113           SelectorCreateOrderedFromObjectIndices(G, cEditorDihe1, obj1, &at0, 1);
114           SelectorCreateOrderedFromObjectIndices(G, cEditorDihe2, obj2, &at3, 1);
115 
116           ExecutiveDihedral(G, cEditorDihedral, cEditorDihe1, cEditorSele1,
117               cEditorSele2, cEditorDihe2, 0, true, true, false, true, -1);
118           ExecutiveColor(G, cEditorDihedral, "white", 1, true);
119           ExecutiveSetSettingFromString(G, cSetting_float_labels,
120                                         "1", cEditorDihedral, 0, true, true);
121 #ifndef _PYMOL_FREETYPE
122           ExecutiveSetSettingFromString(G, cSetting_label_font_id,
123                                         "4", cEditorDihedral, 0, true, true);
124 #else
125           ExecutiveSetSettingFromString(G, cSetting_label_font_id,
126                                         "8", cEditorDihedral, 0, true, true);
127           ExecutiveSetSettingFromString(G, cSetting_label_size,
128                                         "20", cEditorDihedral, 0, true, true);
129 #endif
130           ExecutiveSetSettingFromString(G, cSetting_label_color,
131                                         "brightorange", cEditorDihedral, 0, true, true);
132         }
133       }
134     }
135   }
136 }
137 
EditorDihedralInvalid(PyMOLGlobals * G,ObjectMolecule * obj)138 void EditorDihedralInvalid(PyMOLGlobals * G, ObjectMolecule * obj)
139 {
140   CEditor *I = G->Editor;
141   if(!obj)
142     I->DihedralInvalid = true;
143   else if(obj == I->DihedObject)
144     I->DihedralInvalid = true;
145 }
146 
EditorMouseInvalid(PyMOLGlobals * G)147 void EditorMouseInvalid(PyMOLGlobals * G)
148 {
149   CEditor *I = G->Editor;
150   I->MouseInvalid = true;
151 }
152 
EditorConfigMouse(PyMOLGlobals * G)153 static void EditorConfigMouse(PyMOLGlobals * G)
154 {
155 
156   int scheme = EditorGetScheme(G);
157   const char *mouse_mode = SettingGetGlobal_s(G, cSetting_button_mode_name);
158 
159   if(mouse_mode && (!strcmp(mouse_mode, "3-Button Editing") ||
160                     !strcmp(mouse_mode, "3-Button Motions"))) {
161     /* WEAK! */
162     int button;
163 
164     button = cButModeMiddleShft;
165 
166     {
167       int action = ButModeGet(G, button);
168       if((action == cButModeMovFrag) ||
169          (action == cButModeMovObj) || (action == cButModeMovDrag)) {
170         switch (scheme) {
171         case EDITOR_SCHEME_OBJ:
172           action = cButModeMovObj;
173           break;
174         case EDITOR_SCHEME_FRAG:
175           action = cButModeMovFrag;
176           break;
177         case EDITOR_SCHEME_DRAG:
178           action = cButModeMovDrag;
179           break;
180         }
181         ButModeSet(G, button, action);
182       }
183     }
184 
185     button = cButModeLeftShft;
186     {
187       int action = ButModeGet(G, button);
188       if((action == cButModeRotFrag) ||
189          (action == cButModeRotObj) || (action == cButModeRotDrag)) {
190         switch (scheme) {
191         case EDITOR_SCHEME_OBJ:
192           action = cButModeRotObj;
193           break;
194         case EDITOR_SCHEME_FRAG:
195           action = cButModeRotFrag;
196           break;
197         case EDITOR_SCHEME_DRAG:
198           action = cButModeRotDrag;
199           break;
200         }
201         ButModeSet(G, button, action);
202       }
203     }
204 
205     button = cButModeRightShft;
206     {
207       int action = ButModeGet(G, button);
208       if((action == cButModeMovFragZ) ||
209          (action == cButModeMovObjZ) || (action == cButModeMovDragZ)) {
210         switch (scheme) {
211         case EDITOR_SCHEME_OBJ:
212           action = cButModeMovObjZ;
213           break;
214         case EDITOR_SCHEME_FRAG:
215           action = cButModeMovFragZ;
216           break;
217         case EDITOR_SCHEME_DRAG:
218           action = cButModeMovDragZ;
219           break;
220         }
221         ButModeSet(G, button, action);
222       }
223     }
224 
225     button = cButModeLeftCtrl;
226     {
227       int action = ButModeGet(G, button);
228       if((action == cButModeMoveAtom) || (action == cButModeTorFrag)) {
229         switch (scheme) {
230         case EDITOR_SCHEME_OBJ:
231           action = cButModeMoveAtom;
232           break;
233         case EDITOR_SCHEME_FRAG:
234           action = cButModeTorFrag;
235           break;
236         case EDITOR_SCHEME_DRAG:
237           action = cButModeMoveAtom;
238           break;
239         }
240         ButModeSet(G, button, action);
241       }
242     }
243 
244     button = cButModeLeftDouble;
245     {
246       int action = ButModeGet(G, button);
247       if((action == cButModeMoveAtom) || (action == cButModeTorFrag)) {
248         switch (scheme) {
249         case EDITOR_SCHEME_OBJ:
250           action = cButModeMoveAtom;
251           break;
252         case EDITOR_SCHEME_FRAG:
253           action = cButModeTorFrag;
254           break;
255         case EDITOR_SCHEME_DRAG:
256           action = cButModeMoveAtom;
257           break;
258         }
259         ButModeSet(G, button, action);
260       }
261     }
262 
263     button = cButModeLeftCtSh;
264     {
265       int action = ButModeGet(G, button);
266       if((action == cButModeMoveAtom) || (action == cButModeMoveAtomZ)) {
267         switch (scheme) {
268         case EDITOR_SCHEME_OBJ:
269           action = cButModeMoveAtomZ;
270           break;
271         case EDITOR_SCHEME_FRAG:
272           action = cButModeMoveAtom;
273           break;
274         case EDITOR_SCHEME_DRAG:
275           action = cButModeMoveAtomZ;
276           break;
277         }
278         ButModeSet(G, button, action);
279       }
280     }
281   }
282 
283 }
284 
EditorUpdate(PyMOLGlobals * G)285 void EditorUpdate(PyMOLGlobals * G)
286 {
287   CEditor *I = G->Editor;
288   if(I->DihedralInvalid) {
289     EditorDrawDihedral(G);
290     I->DihedralInvalid = false;
291   }
292   if(I->MouseInvalid) {
293     EditorConfigMouse(G);
294     I->MouseInvalid = false;
295   }
296 }
297 
EditorGetEffectiveState(PyMOLGlobals * G,CObject * obj,int state)298 static int EditorGetEffectiveState(PyMOLGlobals * G, CObject * obj, int state)
299 {
300   if(obj && (obj->type == cObjectMolecule)) {
301     ObjectMolecule *objMol = (ObjectMolecule*)(void*)obj;
302     if(!objMol)
303       objMol = SelectorGetFastSingleObjectMolecule(G, SelectorIndexByName(G, cEditorSele1));
304     if(!objMol)
305       objMol = SelectorGetFastSingleObjectMolecule(G, SelectorIndexByName(G, cEditorSele2));
306     if(!objMol)
307       objMol = SelectorGetFastSingleObjectMolecule(G, SelectorIndexByName(G, cEditorSele3));
308     if(!objMol)
309       objMol = SelectorGetFastSingleObjectMolecule(G, SelectorIndexByName(G, cEditorSele4));
310 
311     if(objMol) {
312       if((objMol->NCSet == 1) && (state > 0))
313         if(SettingGet_i(G, NULL, objMol->Setting, cSetting_static_singletons))
314           return 0;
315     }
316   }
317   return state;
318 }
319 
EditorGetNFrag(PyMOLGlobals * G)320 int EditorGetNFrag(PyMOLGlobals * G)
321 {
322   CEditor *I = G->Editor;
323   if(EditorActive(G)) {
324     return I->NFrag;
325   }
326   return 0;
327 }
328 
EditorDefineExtraPks(PyMOLGlobals * G)329 void EditorDefineExtraPks(PyMOLGlobals * G)
330 {
331   WordType name;
332   WordType buffer;
333 
334   if(EditorGetSinglePicked(G, name)) {
335     sprintf(buffer, "(byres %s)", name);
336     SelectorCreate(G, cEditorRes, buffer, NULL, true, NULL);
337     sprintf(buffer, "(bychain %s)", name);
338     SelectorCreate(G, cEditorChain, buffer, NULL, true, NULL);
339     sprintf(buffer, "(byobject %s)", name);
340     SelectorCreate(G, cEditorObject, buffer, NULL, true, NULL);
341 
342     if(SettingGetGlobal_b(G, cSetting_auto_hide_selections))
343       ExecutiveHideSelections(G);
344     EditorInvalidateShaderCGO(G);
345   }
346 }
347 
EditorDeselectIfSelected(PyMOLGlobals * G,ObjectMolecule * obj,int index,int update)348 int EditorDeselectIfSelected(PyMOLGlobals * G, ObjectMolecule * obj, int index,
349                              int update)
350 {
351   CEditor *I = G->Editor;
352   int result = false;
353   int s, sele;
354   if(obj) {
355     if((index >= 0) && (index < obj->NAtom)) {
356       s = obj->AtomInfo[index].selEntry;
357       sele = SelectorIndexByName(G, cEditorSele1);
358       if(SelectorIsMember(G, s, sele)) {
359         ExecutiveDelete(G, cEditorSele1);
360         result = true;
361       }
362       sele = SelectorIndexByName(G, cEditorSele2);
363       if(SelectorIsMember(G, s, sele)) {
364         ExecutiveDelete(G, cEditorSele2);
365         result = true;
366       }
367       sele = SelectorIndexByName(G, cEditorSele3);
368       if(SelectorIsMember(G, s, sele)) {
369         ExecutiveDelete(G, cEditorSele3);
370         result = true;
371       }
372       sele = SelectorIndexByName(G, cEditorSele4);
373       if(SelectorIsMember(G, s, sele)) {
374         ExecutiveDelete(G, cEditorSele4);
375         result = true;
376       }
377       if(result && update)
378         EditorActivate(G, I->ActiveState, I->BondMode);
379     }
380   }
381 
382   return result;
383 }
384 
EditorIsBondMode(PyMOLGlobals * G)385 int EditorIsBondMode(PyMOLGlobals * G)
386 {
387   CEditor *I = G->Editor;
388   return (I->BondMode);
389 }
390 
EditorAsPyList(PyMOLGlobals * G)391 PyObject *EditorAsPyList(PyMOLGlobals * G)
392 {
393   PyObject *result = NULL;
394   CEditor *I = G->Editor;
395 
396   if(!EditorActive(G)) {
397     result = PyList_New(0);     /* not editing? return null list */
398   } else {
399     result = PyList_New(3);
400     PyList_SetItem(result, 0, PyString_FromString(""));
401     PyList_SetItem(result, 1, PyInt_FromLong(I->ActiveState));
402     PyList_SetItem(result, 2, PyInt_FromLong(I->BondMode));
403   }
404   return (PConvAutoNone(result));
405 }
406 
EditorFromPyList(PyMOLGlobals * G,PyObject * list)407 int EditorFromPyList(PyMOLGlobals * G, PyObject * list)
408 {
409   int ok = true;
410   int active_flag = false;
411   int active_state;
412   WordType obj_name;
413   int ll = 0;
414   int bond_mode = true;
415 
416   if(ok)
417     ok = (list != NULL);
418   if(ok)
419     ok = PyList_Check(list);
420   if(ok)
421     ll = PyList_Size(list);
422   /* TO SUPPORT BACKWARDS COMPATIBILITY...
423      Always check ll when adding new PyList_GetItem's */
424   if(ok)
425     active_flag = (PyList_Size(list) != 0);
426   if(!active_flag) {
427     EditorInactivate(G);
428   } else {
429     if(ok)
430       ok = PConvPyStrToStr(PyList_GetItem(list, 0), obj_name, sizeof(WordType));
431     if(ok)
432       ok = PConvPyIntToInt(PyList_GetItem(list, 1), &active_state);
433     if(ok && (ll > 2))
434       ok = PConvPyIntToInt(PyList_GetItem(list, 2), &bond_mode);        /* newer session files */
435     if(ok) {
436       EditorActivate(G, active_state, bond_mode);
437       EditorDefineExtraPks(G);
438     } else {
439       EditorInactivate(G);
440     }
441   }
442   if(!ok) {
443     EditorInactivate(G);
444   }
445   return (ok);
446 }
447 
EditorActive(PyMOLGlobals * G)448 int EditorActive(PyMOLGlobals * G)
449 {
450   CEditor *I = G->Editor;
451   return (I->Active);
452 }
453 
EditorDragObject(PyMOLGlobals * G)454 CObject *EditorDragObject(PyMOLGlobals * G)
455 {
456   CEditor *I = G->Editor;
457   return I->DragObject;
458 }
459 
EditorGetSinglePicked(PyMOLGlobals * G,char * name)460 int EditorGetSinglePicked(PyMOLGlobals * G, char *name)
461 {
462   int cnt = 0;
463   int sele;
464   if((sele = SelectorIndexByName(G, cEditorSele1)) >= 0) {
465     cnt++;
466     if(name)
467       strcpy(name, cEditorSele1);
468   }
469   if((sele = SelectorIndexByName(G, cEditorSele2)) >= 0) {
470     cnt++;
471     if(name)
472       strcpy(name, cEditorSele2);
473   }
474   if((sele = SelectorIndexByName(G, cEditorSele3)) >= 0) {
475     cnt++;
476     if(name)
477       strcpy(name, cEditorSele3);
478   }
479   if((sele = SelectorIndexByName(G, cEditorSele4)) >= 0) {
480     cnt++;
481     if(name)
482       strcpy(name, cEditorSele4);
483   }
484   return (cnt == 1);
485 }
486 
EditorGetNextMultiatom(PyMOLGlobals * G,char * name)487 void EditorGetNextMultiatom(PyMOLGlobals * G, char *name)
488 {
489   CEditor *I = G->Editor;
490   int sele;
491   sele = SelectorIndexByName(G, cEditorSele1);
492   if(sele < 0) {
493     strcpy(name, cEditorSele1);
494     I->NextPickSele = 0;
495     return;
496   }
497   sele = SelectorIndexByName(G, cEditorSele2);
498   if(sele < 0) {
499     strcpy(name, cEditorSele2);
500     I->NextPickSele = 1;
501     return;
502   }
503   sele = SelectorIndexByName(G, cEditorSele3);
504   if(sele < 0) {
505     strcpy(name, cEditorSele3);
506     I->NextPickSele = 2;
507     return;
508   }
509   sele = SelectorIndexByName(G, cEditorSele4);
510   if(sele < 0) {
511     strcpy(name, cEditorSele4);
512     I->NextPickSele = 3;
513     return;
514   }
515   strcpy(name, cEditorSele4);
516   I->NextPickSele = 3;
517   return;
518   /*
519      I->NextPickSele = (++I->NextPickSele)&0x3;
520      switch(I->NextPickSele) {
521      case 0: strcpy(name,cEditorSele1); break;
522      case 1: strcpy(name,cEditorSele2); break;
523      case 2: strcpy(name,cEditorSele3); break;
524      case 3: strcpy(name,cEditorSele4); break;
525      }
526      return;
527    */
528 }
529 
530 
531 /*========================================================================*/
EditorLogState(PyMOLGlobals * G,int pkresi)532 int EditorLogState(PyMOLGlobals * G, int pkresi)
533 {
534   CEditor *I = G->Editor;
535   if(SettingGetGlobal_i(G, cSetting_logging)) {
536 
537     OrthoLineType buffer, buf1 = "None", buf2 = "None", buf3 = "None", buf4 = "None";
538     int pkbond = 1;
539 
540     if(!EditorActive(G)) {
541       PLog(G, "edit", cPLog_pml);
542     } else {
543       int sele1, sele2, sele3, sele4;
544       ObjectMolecule *obj1 = NULL, *obj2 = NULL, *obj3 = NULL, *obj4 = NULL;
545       int index1, index2, index3, index4;
546 
547       sele1 = SelectorIndexByName(G, cEditorSele1);
548       sele2 = SelectorIndexByName(G, cEditorSele2);
549       sele3 = SelectorIndexByName(G, cEditorSele3);
550       sele4 = SelectorIndexByName(G, cEditorSele4);
551 
552       obj1 = SelectorGetFastSingleAtomObjectIndex(G, sele1, &index1);
553       obj2 = SelectorGetFastSingleAtomObjectIndex(G, sele2, &index2);
554       obj3 = SelectorGetFastSingleAtomObjectIndex(G, sele3, &index3);
555       obj4 = SelectorGetFastSingleAtomObjectIndex(G, sele4, &index4);
556 
557       if((sele1 >= 0) && (sele2 >= 0) && I->BondMode && obj1 && obj2) {
558 
559         /* bond mode */
560         ObjectMoleculeGetAtomSeleLog(obj1, index1, buf1, true);
561         ObjectMoleculeGetAtomSeleLog(obj2, index2, buf2, true);
562 
563       } else {
564 
565         /* atom mode */
566         pkbond = 0;
567 
568         if(obj1) {
569           ObjectMoleculeGetAtomSeleLog(obj1, index1, buf1, true);
570         }
571 
572         if(obj2) {
573           ObjectMoleculeGetAtomSeleLog(obj2, index2, buf2, true);
574         }
575 
576         if(obj3) {
577           ObjectMoleculeGetAtomSeleLog(obj3, index3, buf3, true);
578         }
579 
580         if(obj4) {
581           ObjectMoleculeGetAtomSeleLog(obj4, index4, buf4, true);
582         }
583       }
584 
585       sprintf(buffer, "cmd.edit(%s,%s,%s,%s,pkresi=%d,pkbond=%d)",
586               buf1, buf2, buf3, buf4, pkresi ? 1 : 0, pkbond ? 1 : 0);
587 
588       PLog(G, buffer, cPLog_pym);
589 
590     }
591   }
592   return 1;
593 }
594 
595 
596 /*========================================================================*/
597 
598 pymol::Result<>
EditorInvert(PyMOLGlobals * G,int quiet)599 EditorInvert(PyMOLGlobals * G, int quiet)
600 {
601   CEditor *I = G->Editor;
602   int sele0, sele1, sele2;
603   int i0, frg;
604   int ia0 = -1;
605   int ia1 = -1;
606   float v[3], v0[3], v1[3];
607   float n0[3], n1[3];
608   float m[16];
609   int state;
610   int vf, vf0, vf1;
611   int found = false;
612   WordType name;
613   ObjectMolecule *obj0, *obj1, *obj2;
614 
615   if(!EditorActive(G)) {
616     return pymol::Error("Must pick an atom to invert");
617   } else {
618     sele0 = SelectorIndexByName(G, cEditorSele1);
619     sele1 = SelectorIndexByName(G, cEditorSele2);
620     sele2 = SelectorIndexByName(G, cEditorSele3);
621     obj0 = SelectorGetFastSingleAtomObjectIndex(G, sele0, &i0);
622     obj1 = SelectorGetFastSingleAtomObjectIndex(G, sele1, &ia0);
623     obj2 = SelectorGetFastSingleAtomObjectIndex(G, sele2, &ia1);
624     if(sele0 < 0) {
625       return pymol::Error("Must pick atom to invert as pk1");
626     } else if(sele1 < 0) {
627       return pymol::Error("Must pick immobile atom in pk2");
628     } else if(sele2 < 0) {
629       return pymol::Error("Must pick immobile atom in pk3");
630     } else if(!(obj0 && (obj0 == obj1) && (obj0 = obj2))) {
631       return pymol::Error("Must pick three atoms in the same object");
632     } else {
633 
634       state = SceneGetState(G);
635       ObjectMoleculeSaveUndo(obj0, state, false);
636 
637       vf = ObjectMoleculeGetAtomVertex(obj0, state, i0, v);
638       vf0 = ObjectMoleculeGetAtomVertex(obj0, state, ia0, v0);
639       vf1 = ObjectMoleculeGetAtomVertex(obj0, state, ia1, v1);
640 
641       if(vf & vf0 & vf1) {
642         subtract3f(v, v0, n0);
643         subtract3f(v, v1, n1);
644         normalize3f(n0);
645         normalize3f(n1);
646 
647         add3f(n0, n1, n0);
648         normalize3f(n0);
649 
650         get_rotation_about3f3fTTTf((float) cPI, n0, v, m);
651         for(frg = 1; frg <= I->NFrag; frg++) {
652           sprintf(name, "%s%1d", cEditorFragPref, frg);
653           sele2 = SelectorIndexByName(G, name);
654 
655           if(ObjectMoleculeDoesAtomNeighborSele(obj0, i0, sele2) &&
656              (!ObjectMoleculeDoesAtomNeighborSele(obj0, ia0, sele2)) &&
657              (!ObjectMoleculeDoesAtomNeighborSele(obj0, ia1, sele2))) {
658             found = true;
659               ObjectMoleculeTransformSelection(obj0, state, sele2, m, false, NULL, false,
660                                                false);
661           }
662         }
663         if(found) {
664           if(!quiet) {
665             PRINTFB(G, FB_Editor, FB_Actions)
666               " Editor: Inverted atom.\n" ENDFB(G);
667           }
668         } else {
669           return pymol::Error("No free fragments found for inversion");
670         }
671 
672         SceneInvalidate(G);
673         I->DragIndex = -1;
674         I->DragSelection = -1;
675         I->DragObject = NULL;
676       }
677     }
678   }
679   return {};
680 }
681 
682 
683 /*========================================================================*/
EditorTorsion(PyMOLGlobals * G,float angle)684 pymol::Result<> EditorTorsion(PyMOLGlobals * G, float angle)
685 {
686   CEditor *I = G->Editor;
687   int sele0, sele1, sele2;
688   int i0, i1;
689   float v0[3], v1[3];
690   float d1[3], n0[3];
691   float theta;
692   float m[16];
693   int state;
694   int vf1, vf2;
695   int ok = false;
696   WordType sele;
697   ObjectMolecule *obj0 = NULL, *obj1 = NULL, *obj2 = NULL;
698 
699   if(!EditorActive(G)) {
700     ErrMessage(G, "Editor", "Must specify a bond first.");
701   } else {
702     sele0 = SelectorIndexByName(G, cEditorSele1);
703     if(sele0 >= 0) {
704       obj0 = SelectorGetFastSingleAtomObjectIndex(G, sele0, &i0);
705       sele1 = SelectorIndexByName(G, cEditorSele2);
706       obj1 = SelectorGetFastSingleAtomObjectIndex(G, sele1, &i1);
707       strcpy(sele, cEditorFragPref);
708       strcat(sele, "1");
709       sele2 = SelectorIndexByName(G, sele);
710       obj2 = SelectorGetFastSingleObjectMolecule(G, sele2);
711       if(!((sele0 >= 0) && (sele1 >= 0) && (sele2 >= 0) && (obj0 == obj1))) {
712         return pymol::Error("Must specify a bond first.");
713       } else {
714         if((i0 >= 0) && (i1 >= 0)) {
715           state = SceneGetState(G);
716 
717           vf1 = ObjectMoleculeGetAtomVertex(obj0, state, i0, I->V0);
718           vf2 = ObjectMoleculeGetAtomVertex(obj1, state, i1, I->V1);
719 
720           if(vf1 && vf2) {
721             ObjectMoleculeSaveUndo(obj0, SceneGetState(G), false);
722 
723             subtract3f(I->V1, I->V0, I->Axis);
724             average3f(I->V1, I->V0, I->Center);
725             normalize3f(I->Axis);
726 
727             copy3f(I->V0, v1);
728             copy3f(I->V1, v0);
729 
730             subtract3f(v1, v0, d1);
731             copy3f(d1, n0);
732             normalize3f(n0);
733 
734             theta = (float) (cPI * angle / 180.0);
735             get_rotation_about3f3fTTTf(theta, n0, v1, m);
736             ok =
737               ObjectMoleculeTransformSelection(obj2, state, sele2, m, false, NULL, false,
738                                                false);
739             SceneInvalidate(G);
740 
741             I->DragIndex = -1;
742             I->DragSelection = -1;
743             I->DragObject = NULL;
744 
745             if(I->BondMode && SettingGetGlobal_b(G, cSetting_editor_auto_dihedral))
746               EditorDihedralInvalid(G, NULL);
747           }
748         }
749       }
750     }
751   }
752   if(ok) {
753     return {};
754   } else {
755     return pymol::Error("Error occurred.");
756   }
757 }
758 
759 
760 /*========================================================================*/
EditorSelect(PyMOLGlobals * G,const char * str0,const char * str1,const char * str2,const char * str3,int pkresi,int pkbond,int quiet)761 pymol::Result<> EditorSelect(PyMOLGlobals* G, const char* str0,
762     const char* str1, const char* str2, const char* str3, int pkresi,
763     int pkbond, int quiet)
764 {
765   SelectorTmp tmp0(G, str0);
766   SelectorTmp tmp1(G, str1);
767   SelectorTmp tmp2(G, str2);
768   SelectorTmp tmp3(G, str3);
769   auto s0 = tmp0.getName();
770   auto s1 = tmp1.getName();
771   auto s2 = tmp2.getName();
772   auto s3 = tmp3.getName();
773   int i0 = -1;
774   int i1 = -1;
775   int i2 = -1;
776   int i3 = -1;
777   int result = false;
778   int ok = true;
779   ObjectMolecule *obj0 = NULL, *obj1 = NULL, *obj2 = NULL, *obj3 = NULL;
780 
781   if(s0)
782     if(!*s0)
783       s0 = NULL;
784   if(s1)
785     if(!*s1)
786       s1 = NULL;
787   if(s2)
788     if(!*s2)
789       s2 = NULL;
790   if(s3)
791     if(!*s3)
792       s3 = NULL;
793 
794   if(s0) {
795     obj0 = SelectorGetFastSingleAtomObjectIndex(G, tmp0.getIndex(), &i0);
796     ExecutiveDelete(G, cEditorSele1);
797   }
798 
799   if(s1) {
800     obj1 = SelectorGetFastSingleAtomObjectIndex(G, tmp1.getIndex(), &i1);
801     ExecutiveDelete(G, cEditorSele2);
802   }
803 
804   if(s2) {
805     obj2 = SelectorGetFastSingleAtomObjectIndex(G, tmp2.getIndex(), &i2);
806     ExecutiveDelete(G, cEditorSele3);
807   }
808 
809   if(s3) {
810     obj3 = SelectorGetFastSingleAtomObjectIndex(G, tmp3.getIndex(), &i3);
811     ExecutiveDelete(G, cEditorSele4);
812   }
813 
814   if(!(obj0 || obj1 || obj2 || obj3))
815     ok = false;
816 
817   if(ok) {
818     if(obj0)
819       ObjectMoleculeVerifyChemistry(obj0, -1);
820     if(obj1 && (obj1 != obj0))
821       ObjectMoleculeVerifyChemistry(obj1, -1);
822     if(obj2 && (obj2 != obj0) && (obj2 != obj1))
823       ObjectMoleculeVerifyChemistry(obj2, -1);
824     if(obj3 && (obj3 != obj0) && (obj3 != obj1) && (obj3 != obj2))
825       ObjectMoleculeVerifyChemistry(obj3, -1);
826 
827     if(i0 >= 0)
828       SelectorCreate(G, cEditorSele1, s0, NULL, quiet, NULL);
829     if(i1 >= 0)
830       SelectorCreate(G, cEditorSele2, s1, NULL, quiet, NULL);
831     if(i2 >= 0)
832       SelectorCreate(G, cEditorSele3, s2, NULL, quiet, NULL);
833     if(i3 >= 0)
834       SelectorCreate(G, cEditorSele4, s3, NULL, quiet, NULL);
835 
836     EditorActivate(G, SceneGetState(G), pkbond);
837 
838     if(pkresi)
839       EditorDefineExtraPks(G);
840 
841     SceneInvalidate(G);
842     result = true;
843 
844   } else {
845     EditorInactivate(G);
846     if(s0 && s0[0]) {
847       return pymol::Error("Invalid input selection(s)");
848     }
849   }
850   return {};
851 }
852 
853 
854 /*========================================================================*/
EditorIsAnActiveObject(PyMOLGlobals * G,ObjectMolecule * obj)855 int EditorIsAnActiveObject(PyMOLGlobals * G, ObjectMolecule * obj)
856 {
857   if(EditorActive(G)) {
858     if(obj) {
859       if(obj == SelectorGetFastSingleObjectMolecule(G,
860                                                     SelectorIndexByName(G, cEditorSele1)))
861         return true;
862       if(obj == SelectorGetFastSingleObjectMolecule(G,
863                                                     SelectorIndexByName(G, cEditorSele2)))
864         return true;
865       if(obj == SelectorGetFastSingleObjectMolecule(G,
866                                                     SelectorIndexByName(G, cEditorSele3)))
867         return true;
868       if(obj == SelectorGetFastSingleObjectMolecule(G,
869                                                     SelectorIndexByName(G, cEditorSele4)))
870         return true;
871     }
872   }
873   return false;
874 }
875 
876 
877 /*========================================================================*/
EditorCycleValence(PyMOLGlobals * G,int quiet)878 pymol::Result<> EditorCycleValence(PyMOLGlobals * G, int quiet)
879 {
880   CEditor *I = G->Editor;
881 
882   if(EditorActive(G)) {
883     for(const char* eSele : {cEditorSele3, cEditorSele4}) {
884       if(SelectorIndexByName(G, eSele) >= 0) {
885         return pymol::make_error("Only two picked selections allowed.");
886       }
887     }
888     ObjectMolecule *obj0, *obj1;
889     auto sele0 = SelectorIndexByName(G, cEditorSele1);
890     if(sele0 >= 0) {
891       auto sele1 = SelectorIndexByName(G, cEditorSele2);
892       if(sele1 >= 0) {
893         obj0 = SelectorGetFastSingleObjectMolecule(G, sele0);
894         obj1 = SelectorGetFastSingleObjectMolecule(G, sele1);
895         if(obj0 != obj1) {
896           return pymol::make_error(
897               "Both pk selections must belong to the same molecule.");
898         }
899         if(I->BondMode) {
900           ObjectMoleculeVerifyChemistry(obj0, -1);
901           ObjectMoleculeAdjustBonds(obj0, sele0, sele1, 0, 0);
902         } else {
903           return pymol::make_error("Invalid bond.");
904         }
905       } else {
906         return pymol::make_error("No valid pk2 selection.");
907       }
908     } else {
909       return pymol::make_error("No valid pk1 selection.");
910     }
911   }
912   return {};
913 }
914 
915 
916 /*========================================================================*/
EditorAttach(PyMOLGlobals * G,const char * elem,int geom,int valence,const char * name,int quiet)917 pymol::Result<> EditorAttach(PyMOLGlobals * G, const char *elem, int geom, int valence,
918                   const char *name, int quiet)
919 {
920 
921   if(EditorActive(G)) {
922 
923     for(const char* eSele : {cEditorSele3, cEditorSele4}) {
924       if(SelectorIndexByName(G, eSele) >= 0) {
925         return pymol::make_error("Only 1 or 2 picked selections allowed.");
926       }
927     }
928 
929     auto sele0 = SelectorIndexByName(G, cEditorSele1);
930     if(sele0 >= 0) {
931       auto sele1 = SelectorIndexByName(G, cEditorSele2);
932       auto obj0 = SelectorGetFastSingleObjectMolecule(G, sele0);
933       auto obj1 = SelectorGetFastSingleObjectMolecule(G, sele1);
934 #ifndef _PYMOL_NO_UNDO
935 #endif
936       if(obj0) {
937         if(obj0->DiscreteFlag) {
938           return pymol::make_error("Can't attach atoms onto discrete objects.");
939         } else {
940           ObjectMoleculeVerifyChemistry(obj0, -1);      /* remember chemistry for later */
941           if(obj1) {
942             if(obj0 == obj1) {
943               /* bond mode - behave like replace */
944               EditorReplace(G, elem, geom, valence, name, quiet);
945             } else {
946                return pymol::make_error("Picked atoms must belong to the same object.");
947             }
948           } else {
949             pymol::vla<AtomInfoType> atInfo(1);
950             auto ai = &atInfo[0];
951             /* atom mode */
952             auto i0 = ObjectMoleculeGetAtomIndex(obj0, sele0);       /* slow */
953             if(i0 >= 0) {
954               UtilNCopy(ai->elem, elem, sizeof(ElemName));
955               ai->geom = geom;
956               ai->valence = valence;
957               if(name[0])
958                 LexAssign(G, ai->name, name);
959               if(!ObjectMoleculeAttach(obj0, i0, std::move(atInfo))) {
960                 return pymol::make_error("Could not attach atom.");
961               }
962             }
963           }
964         }
965       } else {
966         return pymol::make_error("Invalid object.");
967       }
968 #ifndef _PYMOL_NO_UNDO
969 #endif
970     } else {
971       return pymol::make_error("Invalid pk1 selection.");
972     }
973   }
974   return {};
975 }
976 
977 
978 /*========================================================================*/
EditorRemove(PyMOLGlobals * G,int hydrogen,int quiet)979 pymol::Result<> EditorRemove(PyMOLGlobals * G, int hydrogen, int quiet)
980 {
981 #define cEditorRemoveSele "_EditorRemove"
982 
983   if(!EditorActive(G)) {
984     return pymol::make_error("Editor not active");
985   }
986 
987   CEditor *I = G->Editor;
988   int sele0 = SelectorIndexByName(G, cEditorSele1);
989   ObjectMolecule *obj0 = SelectorGetFastSingleObjectMolecule(G, sele0);
990   ObjectMoleculeVerifyChemistry(obj0, -1);    /* remember chemistry for later */
991   if(!((sele0 >= 0) && obj0)) {
992     return pymol::make_error("Invalid pk selection");
993   }
994   int sele1 = SelectorIndexByName(G, cEditorSele2);
995   ObjectMolecule *obj1 = SelectorGetFastSingleObjectMolecule(G, sele1);
996   if((sele1 >= 0) && (obj0 == obj1) && I->BondMode) {
997     /* bond mode */
998     ObjectMoleculeRemoveBonds(obj0, sele0, sele1);
999     EditorInactivate(G);
1000   } else {
1001     int h_flag = false;
1002 
1003     if(SelectorIndexByName(G, cEditorSet) < 0) {
1004       int i0 = 0;
1005       /* only one atom picked */
1006 
1007       if(hydrogen) {
1008         auto buf = pymol::string_format("((neighbor %s) and hydro)", cEditorSele1);
1009         h_flag = SelectorCreate(G, cEditorRemoveSele, buf.c_str(), NULL, false, NULL).result();
1010       }
1011 
1012       if(SelectorGetFastSingleAtomObjectIndex(G, sele0, &i0)) {
1013         /* atom mode */
1014         if(i0 >= 0) {
1015           ExecutiveRemoveAtoms(G, cEditorSele1, quiet);
1016         }
1017       }
1018     } else {                /* multiple atoms picked */
1019 
1020       if(hydrogen) {
1021         auto buf = pymol::string_format("((neighbor %s) and hydro)", cEditorSet);
1022         h_flag = SelectorCreate(G, cEditorRemoveSele, buf.c_str(), NULL, false, NULL).result();
1023       }
1024       ExecutiveRemoveAtoms(G, cEditorSet, quiet);
1025     }
1026 
1027     EditorInactivate(G);
1028     if(h_flag) {
1029       ExecutiveRemoveAtoms(G, cEditorRemoveSele, quiet);
1030       SelectorDelete(G, cEditorRemoveSele);
1031     }
1032   }
1033 #undef cEditorRemoveSele
1034   return {};
1035 }
1036 
1037 
1038 /*========================================================================*/
EditorHFill(PyMOLGlobals * G,int quiet)1039 pymol::Result<> EditorHFill(PyMOLGlobals * G, int quiet)
1040 {
1041   int sele0, sele1;
1042   int i0;
1043   ObjectMolecule *obj0 = NULL, *obj1 = NULL;
1044 
1045   if(EditorActive(G)) {
1046     sele0 = SelectorIndexByName(G, cEditorSele1);
1047     obj0 = SelectorGetFastSingleObjectMolecule(G, sele0);
1048     ObjectMoleculeVerifyChemistry(obj0, -1);    /* remember chemistry for later */
1049     if(sele0 >= 0) {
1050 
1051       sele1 = SelectorIndexByName(G, cEditorSele2);
1052       if(sele0 >= 0) {
1053         std::string s1, s2;
1054 	if(sele1 >= 0){
1055           s2 = pymol::string_format("%s|%s", cEditorSele1, cEditorSele2);
1056           s1 = pymol::string_format("(neighbor (%s)) & hydro & !(%s)", s2, s2);
1057 	} else {
1058           s2 = cEditorSele1;
1059           s1 = pymol::string_format("(neighbor (%s)) & hydro", s2);
1060 	}
1061 	ExecutiveRemoveAtoms(G, s1.c_str(), quiet);
1062 	i0 = ObjectMoleculeGetAtomIndex(obj0, sele0);
1063 	obj0->AtomInfo[i0].chemFlag = false;
1064         ExecutiveAddHydrogens(G, cEditorSele1, quiet);
1065 
1066 	if(sele1 >= 0) {
1067 	  obj1 = SelectorGetFastSingleObjectMolecule(G, sele1);
1068 	  i0 = ObjectMoleculeGetAtomIndex(obj1, sele1);
1069 	  obj1->AtomInfo[i0].chemFlag = false;
1070           ExecutiveAddHydrogens(G, cEditorSele2, quiet);
1071 	}
1072       }
1073     } else {
1074       return pymol::Error("Nothing picked.");
1075     }
1076   } else {
1077     return pymol::Error("Editor not active.");
1078   }
1079   return {};
1080 }
1081 
1082 
1083 /*========================================================================*/
EditorHFix(PyMOLGlobals * G,const char * sele,int quiet)1084 pymol::Result<> EditorHFix(PyMOLGlobals * G, const char *sele, int quiet)
1085 {
1086   int sele0, sele1;
1087   ObjectMolecule *obj0, *obj1;
1088 
1089   if((!sele) || (!sele[0])) {   /* if selection is empty, then apply to picked atoms */
1090     if(EditorActive(G)) {
1091       sele0 = SelectorIndexByName(G, cEditorSele1);
1092       if(sele0 >= 0) {
1093         obj0 = SelectorGetFastSingleObjectMolecule(G, sele0);
1094         ObjectMoleculeVerifyChemistry(obj0, -1);
1095         ExecutiveFixHydrogens(G, cEditorSele1, quiet);
1096       }
1097       sele1 = SelectorIndexByName(G, cEditorSele2);
1098       if(sele1 >= 0) {
1099         obj1 = SelectorGetFastSingleObjectMolecule(G, sele1);
1100         ObjectMoleculeVerifyChemistry(obj1, -1);
1101         ExecutiveFixHydrogens(G, cEditorSele2, quiet);
1102       }
1103     } else {
1104       return pymol::Error("No valid selection and active editor.");
1105     }
1106   } else {
1107     ExecutiveFixHydrogens(G, sele, quiet);
1108   }
1109   return {};
1110 }
1111 
1112 
1113 /*========================================================================*/
EditorReplace(PyMOLGlobals * G,const char * elem,int geom,int valence,const char * name,int quiet)1114 pymol::Result<> EditorReplace(PyMOLGlobals* G, const char* elem, int geom,
1115     int valence, const char* name, int quiet)
1116 {
1117   int i0;
1118   int sele0;
1119   AtomInfoType ai;
1120   ObjectMolecule *obj0 = NULL;
1121   int ok = true;
1122   UtilZeroMem(&ai, sizeof(AtomInfoType));
1123   if(EditorActive(G)) {
1124     for (const char* eSele : {cEditorSele2, cEditorSele3, cEditorSele4}) {
1125       if (SelectorIndexByName(G, eSele) >= 0) {
1126         return pymol::make_error("Only one picked selection allowed.");
1127       }
1128     }
1129 
1130     sele0 = SelectorIndexByName(G, cEditorSele1);
1131     obj0 = SelectorGetFastSingleObjectMolecule(G, sele0);
1132     if(obj0->DiscreteFlag) {
1133       return pymol::make_error("Can't attach atoms onto discrete objects.");
1134     } else {
1135       ObjectMoleculeVerifyChemistry(obj0, -1);  /* remember chemistry for later */
1136       if(sele0 >= 0) {
1137         i0 = ObjectMoleculeGetAtomIndex(obj0, sele0);   /* slow */
1138         if(i0 >= 0) {
1139           UtilNCopy(ai.elem, elem, sizeof(ElemName));
1140           if(name[0])
1141             LexAssign(G, ai.name, name);
1142           ai.geom = geom;
1143           ai.valence = valence;
1144           if (ok)
1145 	    ok &= ObjectMoleculePrepareAtom(obj0, i0, &ai);
1146           if (ok)
1147 	    ok &= ObjectMoleculePreposReplAtom(obj0, i0, &ai);
1148           ObjectMoleculeReplaceAtom(obj0, i0, std::move(ai));
1149           ObjectMoleculeVerifyChemistry(obj0, -1);
1150           ObjectMoleculeFillOpenValences(obj0, i0);
1151           if (ok)
1152 	    ok &= ObjectMoleculeSort(obj0);
1153           ObjectMoleculeUpdateIDNumbers(obj0);
1154           EditorInactivate(G);
1155         }
1156       }
1157     }
1158   }
1159   if(ok) {
1160   return {};
1161   } else {
1162     return pymol::make_error("Could not replace atom.");
1163   }
1164 }
1165 
draw_bond(PyMOLGlobals * G,float * v0,float * v1,CGO * shaderCGO)1166 static void draw_bond(PyMOLGlobals * G, float *v0, float *v1, CGO *shaderCGO)
1167 {
1168 
1169   float v[3], v2[3], v3[3];
1170   float d0[3], n0[3], n1[3], n2[3];
1171   float x[50], y[50];
1172   int nEdge;
1173   int c, a;
1174   float tube_size1 = 0.5F;
1175   float tube_size3 = 0.45F;
1176 
1177   nEdge = SettingGetGlobal_i(G, cSetting_stick_quality) * 2;
1178   if(nEdge > 50)
1179     nEdge = 50;
1180   if(nEdge < 3)
1181     nEdge = 3;
1182 
1183   subdivide(nEdge, x, y);
1184 
1185   subtract3f(v1, v0, d0);
1186   average3f(v1, v0, v2);
1187   average3f(v0, v2, v3);
1188   average3f(v2, v3, v2);
1189   copy3f(d0, n0);
1190   get_system1f3f(n0, n1, n2);
1191   if (shaderCGO){
1192     CGOColorv(shaderCGO, ColorGet(G, 0));
1193     CGOBegin(shaderCGO, GL_TRIANGLE_STRIP);
1194     for(a = 0; a <= nEdge; a++) {
1195       c = a % nEdge;
1196       v[0] = n1[0] * x[c] + n2[0] * y[c];
1197       v[1] = n1[1] * x[c] + n2[1] * y[c];
1198       v[2] = n1[2] * x[c] + n2[2] * y[c];
1199       normalize3f(v);
1200       CGONormalv(shaderCGO, v);
1201       v[0] = v2[0] + n1[0] * tube_size1 * x[c] + n2[0] * tube_size1 * y[c];
1202       v[1] = v2[1] + n1[1] * tube_size1 * x[c] + n2[1] * tube_size1 * y[c];
1203       v[2] = v2[2] + n1[2] * tube_size1 * x[c] + n2[2] * tube_size1 * y[c];
1204       CGOVertexv(shaderCGO, v);
1205 
1206       v[0] = v3[0] + n1[0] * tube_size1 * x[c] + n2[0] * tube_size1 * y[c];
1207       v[1] = v3[1] + n1[1] * tube_size1 * x[c] + n2[1] * tube_size1 * y[c];
1208       v[2] = v3[2] + n1[2] * tube_size1 * x[c] + n2[2] * tube_size1 * y[c];
1209       CGOVertexv(shaderCGO, v);
1210     }
1211     CGOEnd(shaderCGO);
1212 
1213     CGOBegin(shaderCGO, GL_TRIANGLE_STRIP);
1214     CGONormalv(shaderCGO, n0);
1215     for(a = 0; a <= nEdge; a++) {
1216       c = a % nEdge;
1217       v[0] = v2[0] + n1[0] * tube_size3 * x[c] + n2[0] * tube_size3 * y[c];
1218       v[1] = v2[1] + n1[1] * tube_size3 * x[c] + n2[1] * tube_size3 * y[c];
1219       v[2] = v2[2] + n1[2] * tube_size3 * x[c] + n2[2] * tube_size3 * y[c];
1220       CGOVertexv(shaderCGO, v);
1221       v[0] = v2[0] + n1[0] * tube_size1 * x[c] + n2[0] * tube_size1 * y[c];
1222       v[1] = v2[1] + n1[1] * tube_size1 * x[c] + n2[1] * tube_size1 * y[c];
1223       v[2] = v2[2] + n1[2] * tube_size1 * x[c] + n2[2] * tube_size1 * y[c];
1224       CGOVertexv(shaderCGO, v);
1225     }
1226     CGOEnd(shaderCGO);
1227 
1228     CGOBegin(shaderCGO, GL_TRIANGLE_STRIP);
1229     scale3f(n0, -1.0F, v);
1230     CGONormalv(shaderCGO, v);
1231     for(a = 0; a <= nEdge; a++) {
1232       c = a % nEdge;
1233       v[0] = v3[0] + n1[0] * tube_size1 * x[c] + n2[0] * tube_size1 * y[c];
1234       v[1] = v3[1] + n1[1] * tube_size1 * x[c] + n2[1] * tube_size1 * y[c];
1235       v[2] = v3[2] + n1[2] * tube_size1 * x[c] + n2[2] * tube_size1 * y[c];
1236       CGOVertexv(shaderCGO, v);
1237       v[0] = v3[0] + n1[0] * tube_size3 * x[c] + n2[0] * tube_size3 * y[c];
1238       v[1] = v3[1] + n1[1] * tube_size3 * x[c] + n2[1] * tube_size3 * y[c];
1239       v[2] = v3[2] + n1[2] * tube_size3 * x[c] + n2[2] * tube_size3 * y[c];
1240       CGOVertexv(shaderCGO, v);
1241     }
1242     CGOEnd(shaderCGO);
1243   } else {
1244 #ifdef PURE_OPENGL_ES_2
1245     /* TODO */
1246 #else
1247   glColor3fv(ColorGet(G, 0));
1248   glBegin(GL_TRIANGLE_STRIP);
1249   for(a = 0; a <= nEdge; a++) {
1250     c = a % nEdge;
1251     v[0] = n1[0] * x[c] + n2[0] * y[c];
1252     v[1] = n1[1] * x[c] + n2[1] * y[c];
1253     v[2] = n1[2] * x[c] + n2[2] * y[c];
1254     normalize3f(v);
1255     glNormal3fv(v);
1256     v[0] = v2[0] + n1[0] * tube_size1 * x[c] + n2[0] * tube_size1 * y[c];
1257     v[1] = v2[1] + n1[1] * tube_size1 * x[c] + n2[1] * tube_size1 * y[c];
1258     v[2] = v2[2] + n1[2] * tube_size1 * x[c] + n2[2] * tube_size1 * y[c];
1259     glVertex3fv(v);
1260 
1261     v[0] = v3[0] + n1[0] * tube_size1 * x[c] + n2[0] * tube_size1 * y[c];
1262     v[1] = v3[1] + n1[1] * tube_size1 * x[c] + n2[1] * tube_size1 * y[c];
1263     v[2] = v3[2] + n1[2] * tube_size1 * x[c] + n2[2] * tube_size1 * y[c];
1264     glVertex3fv(v);
1265   }
1266   glEnd();
1267 #endif
1268 
1269 #ifdef PURE_OPENGL_ES_2
1270     /* TODO */
1271 #else
1272   glBegin(GL_TRIANGLE_STRIP);
1273   glNormal3fv(n0);
1274   for(a = 0; a <= nEdge; a++) {
1275     c = a % nEdge;
1276     v[0] = v2[0] + n1[0] * tube_size3 * x[c] + n2[0] * tube_size3 * y[c];
1277     v[1] = v2[1] + n1[1] * tube_size3 * x[c] + n2[1] * tube_size3 * y[c];
1278     v[2] = v2[2] + n1[2] * tube_size3 * x[c] + n2[2] * tube_size3 * y[c];
1279     glVertex3fv(v);
1280     v[0] = v2[0] + n1[0] * tube_size1 * x[c] + n2[0] * tube_size1 * y[c];
1281     v[1] = v2[1] + n1[1] * tube_size1 * x[c] + n2[1] * tube_size1 * y[c];
1282     v[2] = v2[2] + n1[2] * tube_size1 * x[c] + n2[2] * tube_size1 * y[c];
1283     glVertex3fv(v);
1284   }
1285   glEnd();
1286 #endif
1287 
1288 #ifdef PURE_OPENGL_ES_2
1289     /* TODO */
1290 #else
1291   glBegin(GL_TRIANGLE_STRIP);
1292   scale3f(n0, -1.0F, v);
1293   glNormal3fv(v);
1294   for(a = 0; a <= nEdge; a++) {
1295     c = a % nEdge;
1296     v[0] = v3[0] + n1[0] * tube_size1 * x[c] + n2[0] * tube_size1 * y[c];
1297     v[1] = v3[1] + n1[1] * tube_size1 * x[c] + n2[1] * tube_size1 * y[c];
1298     v[2] = v3[2] + n1[2] * tube_size1 * x[c] + n2[2] * tube_size1 * y[c];
1299     glVertex3fv(v);
1300     v[0] = v3[0] + n1[0] * tube_size3 * x[c] + n2[0] * tube_size3 * y[c];
1301     v[1] = v3[1] + n1[1] * tube_size3 * x[c] + n2[1] * tube_size3 * y[c];
1302     v[2] = v3[2] + n1[2] * tube_size3 * x[c] + n2[2] * tube_size3 * y[c];
1303     glVertex3fv(v);
1304   }
1305   glEnd();
1306 #endif
1307   }
1308 }
1309 
draw_globe(PyMOLGlobals * G,float * v2,int number,CGO * shaderCGO)1310 static void draw_globe(PyMOLGlobals * G, float *v2, int number, CGO *shaderCGO)
1311 {
1312   float v[3];
1313   float n0[3], n1[3], n2[3];
1314   float x[50], y[50];
1315   int nEdge;
1316   int a, c;
1317   float radius = 0.5F;
1318   float width_base = 0.10F;
1319   float width = 0.0F;
1320   float offset = 0.0F;
1321   int cycle_counter;
1322 
1323   nEdge = SettingGetGlobal_i(G, cSetting_stick_quality) * 2;
1324   if(nEdge > 50)
1325     nEdge = 50;
1326   if(nEdge < 3)
1327     nEdge = 3;
1328 
1329   subdivide(nEdge, x, y);
1330 
1331   n0[0] = 1.0;
1332   n0[1] = 0.0;
1333   n0[2] = 0.0;
1334   get_system1f3f(n0, n1, n2);
1335 
1336 #ifndef PURE_OPENGL_ES_2
1337   glColor3fv(ColorGet(G, 0));
1338 #endif
1339   if (shaderCGO)
1340     CGOColorv(shaderCGO, ColorGet(G, 0));
1341   cycle_counter = number;
1342   while(cycle_counter) {
1343 
1344     switch (number) {
1345     case 1:
1346       width = width_base;
1347       offset = 0.0F;
1348       break;
1349 
1350     case 2:
1351       switch (cycle_counter) {
1352       case 2:
1353         width = width_base / 2;
1354         offset = width_base;
1355         break;
1356       case 1:
1357         offset = -width_base;
1358         break;
1359       }
1360       break;
1361 
1362     case 3:
1363       switch (cycle_counter) {
1364       case 3:
1365         width = width_base / 2.8F;
1366         offset = 1.33F * width_base;
1367         break;
1368       case 2:
1369         offset = 0.0F;
1370         break;
1371       case 1:
1372         offset = -1.33F * width_base;
1373         break;
1374       }
1375       break;
1376 
1377     case 4:
1378       switch (cycle_counter) {
1379       case 4:
1380         width = width_base / 3.2F;
1381         offset = 2 * width_base;
1382         break;
1383       case 3:
1384         offset = 0.66F * width_base;
1385         break;
1386       case 2:
1387         offset = -0.66F * width_base;
1388         break;
1389       case 1:
1390         offset = -2 * width_base;
1391         break;
1392       }
1393     }
1394     if (shaderCGO){
1395       CGOBegin(shaderCGO, GL_TRIANGLE_STRIP);
1396       for(a = 0; a <= nEdge; a++) {
1397 	c = a % nEdge;
1398 	v[0] = n1[0] * x[c] + n2[0] * y[c];
1399 	v[1] = n1[1] * x[c] + n2[1] * y[c];
1400 	v[2] = n1[2] * x[c] + n2[2] * y[c];
1401 	normalize3f(v);
1402 	CGONormalv(shaderCGO, v);
1403 	v[0] =
1404 	  v2[0] + n1[0] * radius * x[c] + n2[0] * radius * y[c] + n0[0] * (offset + width);
1405 	v[1] =
1406 	  v2[1] + n1[1] * radius * x[c] + n2[1] * radius * y[c] + n0[1] * (offset + width);
1407 	v[2] =
1408 	  v2[2] + n1[2] * radius * x[c] + n2[2] * radius * y[c] + n0[2] * (offset + width);
1409 	CGOVertexv(shaderCGO, v);
1410 	v[0] =
1411 	  v2[0] + n1[0] * radius * x[c] + n2[0] * radius * y[c] + n0[0] * (offset - width);
1412 	v[1] =
1413 	  v2[1] + n1[1] * radius * x[c] + n2[1] * radius * y[c] + n0[1] * (offset - width);
1414 	v[2] =
1415 	  v2[2] + n1[2] * radius * x[c] + n2[2] * radius * y[c] + n0[2] * (offset - width);
1416 	CGOVertexv(shaderCGO, v);
1417       }
1418       CGOEnd(shaderCGO);
1419 
1420       CGOBegin(shaderCGO, GL_TRIANGLE_STRIP);
1421       for(a = 0; a <= nEdge; a++) {
1422 	c = a % nEdge;
1423 	v[0] = n2[0] * x[c] + n0[0] * y[c];
1424 	v[1] = n2[1] * x[c] + n0[1] * y[c];
1425 	v[2] = n2[2] * x[c] + n0[2] * y[c];
1426 	normalize3f(v);
1427 	CGONormalv(shaderCGO, v);
1428 	v[0] =
1429 	  v2[0] + n2[0] * radius * x[c] + n0[0] * radius * y[c] + n1[0] * (offset + width);
1430 	v[1] =
1431 	  v2[1] + n2[1] * radius * x[c] + n0[1] * radius * y[c] + n1[1] * (offset + width);
1432 	v[2] =
1433 	  v2[2] + n2[2] * radius * x[c] + n0[2] * radius * y[c] + n1[2] * (offset + width);
1434 	CGOVertexv(shaderCGO, v);
1435 	v[0] =
1436 	  v2[0] + n2[0] * radius * x[c] + n0[0] * radius * y[c] + n1[0] * (offset - width);
1437 	v[1] =
1438         v2[1] + n2[1] * radius * x[c] + n0[1] * radius * y[c] + n1[1] * (offset - width);
1439 	v[2] =
1440 	  v2[2] + n2[2] * radius * x[c] + n0[2] * radius * y[c] + n1[2] * (offset - width);
1441 	CGOVertexv(shaderCGO, v);
1442       }
1443       CGOEnd(shaderCGO);
1444 
1445       CGOBegin(shaderCGO, GL_TRIANGLE_STRIP);
1446       for(a = 0; a <= nEdge; a++) {
1447 	c = a % nEdge;
1448 	v[0] = n0[0] * x[c] + n1[0] * y[c];
1449 	v[1] = n0[1] * x[c] + n1[1] * y[c];
1450 	v[2] = n0[2] * x[c] + n1[2] * y[c];
1451 	normalize3f(v);
1452 	CGONormalv(shaderCGO, v);
1453 	v[0] =
1454 	  v2[0] + n0[0] * radius * x[c] + n1[0] * radius * y[c] + n2[0] * (offset + width);
1455 	v[1] =
1456 	  v2[1] + n0[1] * radius * x[c] + n1[1] * radius * y[c] + n2[1] * (offset + width);
1457 	v[2] =
1458 	  v2[2] + n0[2] * radius * x[c] + n1[2] * radius * y[c] + n2[2] * (offset + width);
1459 	CGOVertexv(shaderCGO, v);
1460 	v[0] =
1461 	  v2[0] + n0[0] * radius * x[c] + n1[0] * radius * y[c] + n2[0] * (offset - width);
1462 	v[1] =
1463 	  v2[1] + n0[1] * radius * x[c] + n1[1] * radius * y[c] + n2[1] * (offset - width);
1464 	v[2] =
1465 	  v2[2] + n0[2] * radius * x[c] + n1[2] * radius * y[c] + n2[2] * (offset - width);
1466 	CGOVertexv(shaderCGO, v);
1467       }
1468       CGOEnd(shaderCGO);
1469     } else {
1470 #ifdef PURE_OPENGL_ES_2
1471     /* TODO */
1472 #else
1473     glBegin(GL_TRIANGLE_STRIP);
1474     for(a = 0; a <= nEdge; a++) {
1475       c = a % nEdge;
1476       v[0] = n1[0] * x[c] + n2[0] * y[c];
1477       v[1] = n1[1] * x[c] + n2[1] * y[c];
1478       v[2] = n1[2] * x[c] + n2[2] * y[c];
1479       normalize3f(v);
1480       glNormal3fv(v);
1481       v[0] =
1482         v2[0] + n1[0] * radius * x[c] + n2[0] * radius * y[c] + n0[0] * (offset + width);
1483       v[1] =
1484         v2[1] + n1[1] * radius * x[c] + n2[1] * radius * y[c] + n0[1] * (offset + width);
1485       v[2] =
1486         v2[2] + n1[2] * radius * x[c] + n2[2] * radius * y[c] + n0[2] * (offset + width);
1487       glVertex3fv(v);
1488       v[0] =
1489         v2[0] + n1[0] * radius * x[c] + n2[0] * radius * y[c] + n0[0] * (offset - width);
1490       v[1] =
1491         v2[1] + n1[1] * radius * x[c] + n2[1] * radius * y[c] + n0[1] * (offset - width);
1492       v[2] =
1493         v2[2] + n1[2] * radius * x[c] + n2[2] * radius * y[c] + n0[2] * (offset - width);
1494       glVertex3fv(v);
1495     }
1496     glEnd();
1497 #endif
1498 
1499 #ifdef PURE_OPENGL_ES_2
1500     /* TODO */
1501 #else
1502     glBegin(GL_TRIANGLE_STRIP);
1503     for(a = 0; a <= nEdge; a++) {
1504       c = a % nEdge;
1505       v[0] = n2[0] * x[c] + n0[0] * y[c];
1506       v[1] = n2[1] * x[c] + n0[1] * y[c];
1507       v[2] = n2[2] * x[c] + n0[2] * y[c];
1508       normalize3f(v);
1509       glNormal3fv(v);
1510       v[0] =
1511         v2[0] + n2[0] * radius * x[c] + n0[0] * radius * y[c] + n1[0] * (offset + width);
1512       v[1] =
1513         v2[1] + n2[1] * radius * x[c] + n0[1] * radius * y[c] + n1[1] * (offset + width);
1514       v[2] =
1515         v2[2] + n2[2] * radius * x[c] + n0[2] * radius * y[c] + n1[2] * (offset + width);
1516       glVertex3fv(v);
1517       v[0] =
1518         v2[0] + n2[0] * radius * x[c] + n0[0] * radius * y[c] + n1[0] * (offset - width);
1519       v[1] =
1520         v2[1] + n2[1] * radius * x[c] + n0[1] * radius * y[c] + n1[1] * (offset - width);
1521       v[2] =
1522         v2[2] + n2[2] * radius * x[c] + n0[2] * radius * y[c] + n1[2] * (offset - width);
1523       glVertex3fv(v);
1524     }
1525     glEnd();
1526 #endif
1527 
1528 #ifdef PURE_OPENGL_ES_2
1529     /* TODO */
1530 #else
1531     glBegin(GL_TRIANGLE_STRIP);
1532     for(a = 0; a <= nEdge; a++) {
1533       c = a % nEdge;
1534       v[0] = n0[0] * x[c] + n1[0] * y[c];
1535       v[1] = n0[1] * x[c] + n1[1] * y[c];
1536       v[2] = n0[2] * x[c] + n1[2] * y[c];
1537       normalize3f(v);
1538       glNormal3fv(v);
1539       v[0] =
1540         v2[0] + n0[0] * radius * x[c] + n1[0] * radius * y[c] + n2[0] * (offset + width);
1541       v[1] =
1542         v2[1] + n0[1] * radius * x[c] + n1[1] * radius * y[c] + n2[1] * (offset + width);
1543       v[2] =
1544         v2[2] + n0[2] * radius * x[c] + n1[2] * radius * y[c] + n2[2] * (offset + width);
1545       glVertex3fv(v);
1546       v[0] =
1547         v2[0] + n0[0] * radius * x[c] + n1[0] * radius * y[c] + n2[0] * (offset - width);
1548       v[1] =
1549         v2[1] + n0[1] * radius * x[c] + n1[1] * radius * y[c] + n2[1] * (offset - width);
1550       v[2] =
1551         v2[2] + n0[2] * radius * x[c] + n1[2] * radius * y[c] + n2[2] * (offset - width);
1552       glVertex3fv(v);
1553     }
1554     glEnd();
1555 #endif
1556     }
1557     cycle_counter--;
1558   }
1559 
1560 }
1561 
1562 
1563 /*
1564 static void draw_string(float *v,char *l)
1565 {
1566   glDisable(GL_DEPTH_TEST);
1567   glDisable(GL_LIGHTING);
1568   if(*l) {
1569     glColor3f(1.0,0.0,0.5);
1570     glRasterPos4f(v[0],v[1],v[2],1.0);
1571   }
1572 
1573   while(*l) {
1574     p_g lutBi tmapChar acter(P_G LUT_BITMAP_8_BY_13,*(l++));
1575   }
1576 
1577   glEnable(GL_LIGHTING);
1578   glEnable(GL_DEPTH_TEST);
1579 }
1580 */
1581 
1582 
1583 /*========================================================================*/
EditorRender(PyMOLGlobals * G,int state)1584 void EditorRender(PyMOLGlobals * G, int state)
1585 {
1586   CEditor *I = G->Editor;
1587   int sele1, sele2, sele3, sele4;
1588   float v0[3], v1[3];
1589   float vp[12], *vv;
1590   /*  int v_cnt; */
1591   ObjectMolecule *obj1 = NULL, *obj2 = NULL, *obj3 = NULL, *obj4 = NULL;
1592   int index1, index2, index3, index4;
1593   int st, frozen;
1594   CGO *shaderCGO = NULL;
1595 
1596   if(EditorActive(G)) {
1597     int use_shader = SettingGetGlobal_b(G, cSetting_use_shaders);
1598     if (use_shader){
1599       if (!I->shaderCGO){
1600 	shaderCGO = CGONew(G);
1601       } else {
1602 	CGORenderGL(I->shaderCGO, NULL, NULL, NULL, NULL, NULL);
1603 	return;
1604       }
1605     } else {
1606       CGOFree(I->shaderCGO);
1607     }
1608 
1609     PRINTFD(G, FB_Editor)
1610       " EditorRender-Debug: rendering...\n" ENDFD;
1611 
1612     if(G->HaveGUI && G->ValidContext) {
1613 
1614       sele1 = SelectorIndexByName(G, cEditorSele1);
1615       sele2 = SelectorIndexByName(G, cEditorSele2);
1616       sele3 = SelectorIndexByName(G, cEditorSele3);
1617       sele4 = SelectorIndexByName(G, cEditorSele4);
1618 
1619       obj1 = SelectorGetFastSingleAtomObjectIndex(G, sele1, &index1);
1620       obj2 = SelectorGetFastSingleAtomObjectIndex(G, sele2, &index2);
1621       obj3 = SelectorGetFastSingleAtomObjectIndex(G, sele3, &index3);
1622       obj4 = SelectorGetFastSingleAtomObjectIndex(G, sele4, &index4);
1623 
1624       /*      printf("%d %d %d %d\n",sele1,sele2,sele3,sele4);
1625          printf("%p %p %p %p\n",obj1,obj2,obj3,obj4);
1626          printf("%d %d %d %d\n",index1,index2,index3,index4); */
1627 
1628       if((sele1 >= 0) && (sele2 >= 0) && I->BondMode && obj1 && obj2) {
1629         /* bond mode */
1630 
1631         ObjectMoleculeGetAtomTxfVertex(obj1, state, index1, v0);
1632         ObjectMoleculeGetAtomTxfVertex(obj2, state, index2, v1);
1633         draw_bond(G, v0, v1, shaderCGO);
1634 
1635       } else {
1636         /* atom mode */
1637 
1638         vv = vp;
1639 
1640         if(obj1) {
1641 	  /* if the user froze a state, use it instead of the global */
1642 	  if((frozen = SettingGetIfDefined_i(obj1->G, obj1->Setting, cSetting_state, &st))) {
1643 	    state = st-1;
1644 	  }
1645           if(ObjectMoleculeGetAtomTxfVertex(obj1, state, index1, vv)) {
1646             draw_globe(G, vv, 1, shaderCGO);
1647             vv += 3;
1648           }
1649         }
1650 
1651         if(obj2) {
1652 	  if((frozen = SettingGetIfDefined_i(obj2->G, obj2->Setting, cSetting_state, &st))) {
1653 	    state = st-1;
1654 	  }
1655           if(ObjectMoleculeGetAtomTxfVertex(obj2, state, index2, vv)) {
1656             draw_globe(G, vv, 2, shaderCGO);
1657             vv += 3;
1658           }
1659         }
1660 
1661         if(obj3) {
1662 	  if((frozen = SettingGetIfDefined_i(obj3->G, obj3->Setting, cSetting_state, &st))) {
1663 	    state = st-1;
1664 	  }
1665           if(ObjectMoleculeGetAtomTxfVertex(obj3, state, index3, vv)) {
1666             draw_globe(G, vv, 3, shaderCGO);
1667             vv += 3;
1668           }
1669         }
1670 
1671         if(obj4) {
1672 	  if((frozen = SettingGetIfDefined_i(obj4->G, obj4->Setting, cSetting_state, &st))) {
1673 	    state = st-1;
1674 	  }
1675           if(ObjectMoleculeGetAtomTxfVertex(obj4, state, index4, vv)) {
1676             draw_globe(G, vv, 4, shaderCGO);
1677             vv += 3;
1678           }
1679         }
1680       }
1681     }
1682     if (shaderCGO){
1683       CGO *convertcgo = NULL;
1684       int ok = true;
1685       CGOStop(shaderCGO);
1686       CHECKOK(ok, shaderCGO);
1687       convertcgo = CGOCombineBeginEnd(shaderCGO, 0);
1688       CHECKOK(ok, convertcgo);
1689       CGOFree(shaderCGO);
1690       if (ok){
1691 	CGO *tmpCGO = CGONew(G), *convertcgo2 = NULL;
1692 	if (ok) ok &= CGOEnable(tmpCGO, GL_DEFAULT_SHADER);
1693 	if (ok) ok &= CGODisable(tmpCGO, GL_TWO_SIDED_LIGHTING);
1694 	convertcgo2 = CGOOptimizeToVBONotIndexedNoShader(convertcgo, 0);
1695 	if (ok) ok &= CGOAppendNoStop(tmpCGO, convertcgo2);
1696 	if (ok) ok &= CGODisable(tmpCGO, GL_DEFAULT_SHADER);
1697 	if (ok) ok &= CGOStop(tmpCGO);
1698 	CGOFreeWithoutVBOs(convertcgo2);
1699 	I->shaderCGO = tmpCGO;
1700 	I->shaderCGO->use_shader = true;
1701       }
1702       CGOFree(convertcgo);
1703       if (ok){
1704 	CGORenderGL(I->shaderCGO, NULL, NULL, NULL, NULL, NULL);
1705       }
1706     }
1707   }
1708 }
1709 
1710 
1711 /*========================================================================*/
EditorInactivate(PyMOLGlobals * G)1712 void EditorInactivate(PyMOLGlobals * G)
1713 {
1714   CEditor *I = G->Editor;
1715 
1716   PRINTFD(G, FB_Editor)
1717     " EditorInactivate-Debug: callend.\n" ENDFD;
1718 
1719   if (I->Active) {
1720     // force refresh of the object menu panel (PYMOL-3411)
1721     OrthoInvalidateDoDraw(G);
1722   }
1723 
1724   I->DihedObject = NULL;
1725   I->DragObject = NULL;
1726   I->BondMode = false;
1727   I->ShowFrags = false;
1728   I->NFrag = 0;
1729   I->Active = false;
1730   SelectorDeletePrefixSet(G, cEditorFragPref);
1731   SelectorDeletePrefixSet(G, cEditorBasePref);
1732   ExecutiveDelete(G, cEditorSele1);
1733   ExecutiveDelete(G, cEditorSele2);
1734   ExecutiveDelete(G, cEditorSele3);
1735   ExecutiveDelete(G, cEditorSele4);
1736   ExecutiveDelete(G, cEditorSet);
1737   ExecutiveDelete(G, cEditorBond);
1738   ExecutiveDelete(G, cEditorRes);
1739   ExecutiveDelete(G, cEditorChain);
1740   ExecutiveDelete(G, cEditorObject);
1741   ExecutiveDelete(G, cEditorComp);
1742   ExecutiveDelete(G, cEditorLink);
1743   ExecutiveDelete(G, cEditorDihedral);
1744   ExecutiveDelete(G, cEditorDihe1);
1745   ExecutiveDelete(G, cEditorDihe2);
1746   ExecutiveDelete(G, cEditorMeasure);
1747   EditorMouseInvalid(G);
1748   EditorInvalidateShaderCGO(G);
1749   SceneInvalidate(G);
1750 }
1751 
1752 
1753 /*========================================================================*/
1754 /*
1755  * Create a transient distance, angle, or dihedral measurement between
1756  * the pk1 - pk4 atoms.
1757  *
1758  * Assumes that the cEditorMeasure object does not exist yet.
1759  */
1760 static
EditorAutoMeasure(PyMOLGlobals * G,int sele1,int sele2,int sele3,int sele4,int state)1761 void EditorAutoMeasure(PyMOLGlobals * G,
1762     int sele1, int sele2, int sele3, int sele4, int state)
1763 {
1764   if (sele1 < 0 || sele2 < 0)
1765     return;
1766 
1767   if (sele3 < 0) {
1768     ExecutiveDistance(G, cEditorMeasure, cEditorSele1, cEditorSele2, 0, -1.f, true,
1769         true, false /* reset */, state, false);
1770   } else if (sele4 < 0) {
1771     ExecutiveAngle(G, cEditorMeasure, cEditorSele1, cEditorSele2, cEditorSele3,
1772         0, true, false /* reset */, false, true, state);
1773   } else {
1774     ExecutiveDihedral(G, cEditorMeasure, cEditorSele1, cEditorSele2,
1775         cEditorSele3, cEditorSele4, 0, true, false /* reset */, false, true,
1776         state);
1777   }
1778 
1779   ExecutiveColor(G, cEditorMeasure, "gray", 0x1, true);
1780 }
1781 
1782 
1783 /*========================================================================*/
EditorActivate(PyMOLGlobals * G,int state,int enable_bond)1784 void EditorActivate(PyMOLGlobals * G, int state, int enable_bond)
1785 {
1786   int sele1, sele2, sele3, sele4;
1787 
1788   CEditor *I = G->Editor;
1789 
1790   sele1 = SelectorIndexByName(G, cEditorSele1);
1791   sele2 = SelectorIndexByName(G, cEditorSele2);
1792   sele3 = SelectorIndexByName(G, cEditorSele3);
1793   sele4 = SelectorIndexByName(G, cEditorSele4);
1794 
1795   if((sele1 >= 0) || (sele2 >= 0) || (sele3 >= 0) || (sele4 >= 0)) {
1796 
1797     I->Active = true;
1798     ExecutiveDelete(G, cEditorComp);
1799     ExecutiveDelete(G, cEditorRes);
1800     ExecutiveDelete(G, cEditorChain);
1801     ExecutiveDelete(G, cEditorObject);
1802     ExecutiveDelete(G, cEditorBond);
1803     ExecutiveDelete(G, cEditorDihedral);
1804     ExecutiveDelete(G, cEditorDihe1);
1805     ExecutiveDelete(G, cEditorDihe2);
1806     ExecutiveDelete(G, cEditorMeasure);
1807 
1808     I->BondMode = enable_bond;
1809     I->NFrag = SelectorSubdivide(G, cEditorFragPref,
1810                                  sele1, sele2,
1811                                  sele3, sele4,
1812                                  cEditorBasePref, cEditorComp, &I->BondMode);
1813     /* just returns 'state' */
1814     state = EditorGetEffectiveState(G, NULL, state);
1815     I->ActiveState = state;
1816 
1817     I->ShowFrags = false;
1818     if(SettingGetGlobal_b(G, cSetting_auto_hide_selections))
1819       ExecutiveHideSelections(G);
1820 
1821     if(I->BondMode && SettingGetGlobal_b(G, cSetting_editor_auto_dihedral))
1822       EditorDihedralInvalid(G, NULL);
1823 
1824     if (!I->BondMode && SettingGetGlobal_b(G, cSetting_editor_auto_measure))
1825       EditorAutoMeasure(G, sele1, sele2, sele3, sele4, state);
1826   } else {
1827     EditorInactivate(G);
1828   }
1829   EditorMouseInvalid(G);
1830   EditorInvalidateShaderCGO(G);
1831 }
1832 
1833 
1834 /*========================================================================*/
EditorSetDrag(PyMOLGlobals * G,CObject * obj,int sele,int quiet,int state)1835 void EditorSetDrag(PyMOLGlobals * G, CObject * obj, int sele, int quiet, int state)
1836 {
1837   EditorInactivate(G);
1838   state = EditorGetEffectiveState(G, obj, state);
1839   if(obj->type == cObjectMolecule) {
1840     ObjectMolecule *objMol = (ObjectMolecule*)(void*)obj;
1841     if(ObjectMoleculeCheckFullStateSelection(objMol, sele, state)) {
1842       int matrix_mode = SettingGet_i(G, obj->Setting, NULL, cSetting_matrix_mode);
1843       if(matrix_mode>=1) {
1844         /* force / coerce object matrix drags? */
1845         sele = -1;
1846       }
1847     }
1848   }
1849   EditorPrepareDrag(G, obj, sele, -1, state, 0);
1850 }
1851 
EditorReadyDrag(PyMOLGlobals * G,int state)1852 void EditorReadyDrag(PyMOLGlobals * G, int state)
1853 {
1854   CEditor *I = G->Editor;
1855   if(I->DragObject && (I->DragIndex == -1)) {
1856     EditorPrepareDrag(G, I->DragObject, I->DragSelection, -1, state, 0);
1857   }
1858 }
1859 
1860 
1861 /*========================================================================*/
EditorPrepareDrag(PyMOLGlobals * G,CObject * obj,int sele,int index,int state,int mode)1862 void EditorPrepareDrag(PyMOLGlobals * G, CObject * obj,
1863                        int sele, int index, int state, int mode)
1864 {
1865   int frg;
1866   int sele0 = -1, sele1 = -1, sele2 = -1, sele3 = -1;
1867   int s;
1868   WordType name;
1869   int seleFlag = false;
1870   int i0, i1, i2, i3;
1871   CEditor *I = G->Editor;
1872   int log_trans = SettingGetGlobal_b(G, cSetting_log_conformations);
1873   int drag_sele = -1;
1874   ObjectMolecule *objMol = NULL;
1875 
1876   PRINTFD(G, FB_Editor)
1877     " EditorPrepareDrag-Debug: entered. obj %p index %d\n", (void *) obj, index ENDFD;
1878 
1879   if(obj->type == cObjectMolecule)
1880     objMol = (ObjectMolecule*)(void*)obj;
1881 
1882   state = EditorGetEffectiveState(G, obj, state);
1883 
1884   /* TODO: if user is drags label, then the editor must be deactivated */
1885 
1886   if((!EditorActive(G))||(!objMol)) {
1887     /* non-anchored dragging of objects and now selections */
1888 
1889     float mn[3], mx[3];
1890 
1891     I->DragObject = obj;
1892     I->DragIndex = index;       /* set to -1 when in "mouse drag" mode */
1893     I->DragSelection = sele;
1894     I->DragHaveBase = false;
1895     if(sele >= 0) {
1896       auto sele_name = SelectorGetNameFromIndex(G, sele);
1897       if(sele_name) {
1898         strcpy(I->DragSeleName, sele_name);
1899         if(SettingGetGlobal_b(G, cSetting_editor_auto_origin)) {
1900           if(I->FavorOrigin) {
1901             I->DragHaveBase = true;
1902             copy3f(I->FavoredOrigin, I->DragBase);
1903           } else {
1904             if(ExecutiveGetExtent(G, sele_name, mn, mx, true, state, true)) {
1905               average3f(mn, mx, I->DragBase);
1906               I->DragHaveBase = true;
1907             }
1908           }
1909         }
1910       } else {
1911         I->DragSeleName[0] = 0;
1912       }
1913     } else {
1914       if(SettingGetGlobal_b(G, cSetting_editor_auto_origin)) {
1915         if(I->FavorOrigin) {
1916           I->DragHaveBase = true;
1917           copy3f(I->FavoredOrigin, I->DragBase);
1918         } else {
1919           if(ExecutiveGetExtent(G, obj->Name, mn, mx, true, state, true)) {
1920             average3f(mn, mx, I->DragBase);
1921             I->DragHaveBase = true;
1922           }
1923         }
1924       }
1925     }
1926   } else {
1927 
1928     /* anchored / fragment dragging  */
1929     for(frg = 1; frg <= I->NFrag; frg++) {
1930       sprintf(name, "%s%1d", cEditorFragPref, frg);
1931       drag_sele = SelectorIndexByName(G, name);
1932       if(drag_sele >= 0) {
1933         s = objMol->AtomInfo[index].selEntry;
1934         seleFlag = SelectorIsMember(G, s, drag_sele);
1935       }
1936       if(seleFlag) {
1937         strcpy(I->DragSeleName, name);
1938         break;
1939       }
1940     }
1941     if(seleFlag) {              /* normal selection */
1942 
1943       PRINTFB(G, FB_Editor, FB_Blather)
1944         " Editor: grabbing (%s).", name ENDFB(G);
1945 
1946       I->DragIndex = index;
1947       I->DragSelection = drag_sele;
1948       I->DragObject = obj;
1949       I->DragHaveAxis = false;
1950       I->DragHaveBase = false;
1951       I->DragBondFlag = false;
1952       I->DragSlowFlag = false;
1953 
1954       sprintf(name, "%s%1d", cEditorBasePref, frg);     /* get relevant base vertex of bond */
1955       sele1 = SelectorIndexByName(G, name);
1956       if(sele1 >= 0) {
1957         i1 = ObjectMoleculeGetAtomIndex(objMol, sele1);
1958         if(i1 >= 0) {
1959           ObjectMoleculeGetAtomTxfVertex(objMol, state, i1, I->DragBase);
1960           I->DragHaveBase = true;
1961           /*printf("base %s\n",name); */
1962         }
1963       }
1964 
1965       /* get axis or base atom */
1966 
1967       {
1968         int cnt = 0;
1969 
1970         if((sele0 = SelectorIndexByName(G, cEditorSele1)) >= 0) {
1971           if(SelectorIsAtomBondedToSele(G, objMol, sele0, drag_sele))
1972             cnt++;
1973           else
1974             sele0 = -1;
1975         }
1976         if((sele1 = SelectorIndexByName(G, cEditorSele2)) >= 0) {
1977           if(SelectorIsAtomBondedToSele(G, objMol, sele1, drag_sele))
1978             cnt++;
1979           else
1980             sele1 = -1;
1981         }
1982         if((sele2 = SelectorIndexByName(G, cEditorSele3)) >= 0) {
1983           if(SelectorIsAtomBondedToSele(G, objMol, sele2, drag_sele))
1984             cnt++;
1985           else
1986             sele2 = -1;
1987         }
1988         if((sele3 = SelectorIndexByName(G, cEditorSele4)) >= 0) {
1989           if(SelectorIsAtomBondedToSele(G, objMol, sele3, drag_sele))
1990             cnt++;
1991           else
1992             sele3 = -1;
1993         }
1994 
1995         i0 = ObjectMoleculeGetAtomIndex(objMol, sele0);
1996         i1 = ObjectMoleculeGetAtomIndex(objMol, sele1);
1997         i2 = ObjectMoleculeGetAtomIndex(objMol, sele2);
1998         i3 = ObjectMoleculeGetAtomIndex(objMol, sele3);
1999 
2000         if(cnt > 1) {           /* bond/multiatom mode */
2001 
2002           I->DragBondFlag = I->BondMode;
2003 
2004           zero3f(I->Center);
2005           if(i0 >= 0) {
2006             ObjectMoleculeGetAtomTxfVertex(objMol, state, i0, I->V0);
2007           } else if(i1 >= 0) {
2008             ObjectMoleculeGetAtomTxfVertex(objMol, state, i1, I->V0);
2009           } else if(i2 >= 0) {
2010             ObjectMoleculeGetAtomTxfVertex(objMol, state, i2, I->V0);
2011           } else if(i3 >= 0) {
2012             ObjectMoleculeGetAtomTxfVertex(objMol, state, i3, I->V0);
2013           }
2014 
2015           if(i0 >= 0) {
2016             ObjectMoleculeGetAtomTxfVertex(objMol, state, i0, I->V1);
2017             add3f(I->V1, I->Center, I->Center);
2018           }
2019           if(i1 >= 0) {
2020             ObjectMoleculeGetAtomTxfVertex(objMol, state, i1, I->V1);
2021             add3f(I->V1, I->Center, I->Center);
2022           }
2023           if(i2 >= 0) {
2024             ObjectMoleculeGetAtomTxfVertex(objMol, state, i2, I->V1);
2025             add3f(I->V1, I->Center, I->Center);
2026           }
2027           if(i3 >= 0) {
2028             ObjectMoleculeGetAtomTxfVertex(objMol, state, i3, I->V1);
2029             add3f(I->V1, I->Center, I->Center);
2030           }
2031 
2032           {
2033             float div = 1.0F / cnt;
2034             scale3f(I->Center, div, I->Center);
2035           }
2036 
2037           subtract3f(I->Center, I->V0, I->Axis);
2038 
2039           normalize3f(I->Axis);
2040           I->DragHaveAxis = true;
2041 
2042           if(SettingGetGlobal_b(G, cSetting_editor_auto_origin)) {
2043             if(I->FavorOrigin) {
2044               I->DragHaveBase = true;
2045               copy3f(I->FavoredOrigin, I->DragBase);
2046             } else {
2047               copy3f(I->Center, I->DragBase);
2048               I->DragHaveBase = true;
2049             }
2050           }
2051 
2052         } else {                /* atom mode */
2053 
2054           if(i0 >= 0) {
2055             ObjectMoleculeGetAtomTxfVertex(objMol, state, i0, I->V0);
2056           } else if(i1 >= 0) {
2057             ObjectMoleculeGetAtomTxfVertex(objMol, state, i1, I->V0);
2058           } else if(i2 >= 0) {
2059             ObjectMoleculeGetAtomTxfVertex(objMol, state, i2, I->V0);
2060           } else if(i3 >= 0) {
2061             ObjectMoleculeGetAtomTxfVertex(objMol, state, i3, I->V0);
2062           }
2063           if(I->DragHaveBase) {
2064 
2065             copy3f(I->DragBase, I->V1);
2066             subtract3f(I->V1, I->V0, I->Axis);
2067             average3f(I->V1, I->V0, I->Center);
2068             normalize3f(I->Axis);
2069             I->DragHaveAxis = true;
2070             if(mode == cButModeRotFrag) {
2071               copy3f(I->V0, I->DragBase);
2072             }
2073 
2074           }
2075         }
2076       }
2077     } else {                    /* clicked directly on an anchor atom */
2078 
2079       sele0 = SelectorIndexByName(G, cEditorSele1);
2080       if(sele0 < 0)
2081         sele0 = SelectorIndexByName(G, cEditorSele2);
2082       if(sele0 < 0)
2083         sele0 = SelectorIndexByName(G, cEditorSele3);
2084       if(sele0 < 0)
2085         sele0 = SelectorIndexByName(G, cEditorSele4);
2086       if(sele0 >= 0) {
2087         s = objMol->AtomInfo[index].selEntry;
2088         seleFlag = SelectorIsMember(G, s, sele0);
2089       }
2090 
2091       PRINTFB(G, FB_Editor, FB_Actions)
2092         " Editor: grabbing all fragments." ENDFB(G);
2093       I->DragIndex = index;
2094       I->DragSelection = SelectorIndexByName(G, cEditorComp);
2095       strcpy(I->DragSeleName, cEditorComp);
2096       I->DragObject = obj;
2097       I->DragHaveAxis = false;
2098       I->DragHaveBase = false;
2099       I->DragBondFlag = false;
2100 
2101       I->DragSlowFlag = true;
2102 
2103       if(sele0 >= 0) {          /* just provide a base vector, no valid axis exists */
2104         i1 = ObjectMoleculeGetAtomIndex(objMol, sele0);
2105         if(i1 >= 0) {
2106           ObjectMoleculeGetAtomTxfVertex(objMol, state, i1, I->DragBase);
2107           I->DragHaveBase = true;
2108           I->DragBondFlag = true;
2109         }
2110       }
2111     }
2112     if(!seleFlag) {
2113       I->DragIndex = -1;
2114       I->DragSelection = -1;
2115       I->DragObject = NULL;
2116     }
2117   }
2118   if(I->DragObject) {
2119     I->ShowFrags = false;
2120     if(objMol) {
2121       ObjectMoleculeSaveUndo(objMol, state, log_trans);
2122       if(SettingGetGlobal_b(G, cSetting_auto_sculpt)) {
2123         SettingSetGlobal_b(G, cSetting_sculpting, 1);
2124         if(!objMol->Sculpt)
2125           ObjectMoleculeSculptImprint(objMol, state, -1, 0);
2126       }
2127     }
2128   }
2129   if(log_trans)
2130     PLogFlush(G);
2131 
2132   PRINTFD(G, FB_Editor)
2133     " EditorPrepDrag-Debug: leaving Index %d Sele %d Object %p\n Axis %d Base %d BondFlag %d SlowFlag %d seleFlag %d\n",
2134     I->DragIndex, I->DragSelection, (void *) I->DragObject,
2135     I->DragHaveAxis, I->DragHaveBase, I->DragBondFlag, I->DragSlowFlag, seleFlag ENDFD;
2136 }
2137 
EditorDraggingObjectMatrix(PyMOLGlobals * G)2138 int EditorDraggingObjectMatrix(PyMOLGlobals *G)
2139 {
2140   CEditor *I = G->Editor;
2141   if(I->DragObject && (I->DragSelection < 0) && (I->DragIndex == -1)) {
2142       return true;
2143   }
2144   return false;
2145 }
2146 
EditorDrag(PyMOLGlobals * G,CObject * obj,int index,int mode,int state,float * pt,float * mov,float * z_dir)2147 void EditorDrag(PyMOLGlobals * G, CObject * obj, int index, int mode, int state,
2148                 float *pt, float *mov, float *z_dir)
2149 {
2150   CEditor *I = G->Editor;
2151   float v0[3], v1[3], v2[3], v3[3], v4[4], cp[3];
2152   float d0[3], d1[3], d2[3], n0[3], n1[3], n2[3];
2153   float opp, adj, theta;
2154   float m[16];
2155   int log_trans = SettingGetGlobal_b(G, cSetting_log_conformations);
2156 
2157   PRINTFD(G, FB_Editor)
2158     " EditorDrag-Debug: entered. obj %p state %d index %d mode %d \nIndex %d Sele %d Object %p\n Axis %d Base %d BondFlag %d SlowFlag %d\n",
2159     (void *) obj, state, index, mode,
2160     I->DragIndex, I->DragSelection, (void *) I->DragObject,
2161     I->DragHaveAxis, I->DragHaveBase, I->DragBondFlag, I->DragSlowFlag ENDFD;
2162 
2163   if((index < 0) && (!obj))
2164     obj = I->DragObject;
2165 
2166   if(obj) {
2167     ObjectMolecule *objMol = NULL;
2168     if(obj->type == cObjectMolecule)
2169       objMol = (ObjectMolecule*)(void*)obj;
2170 
2171     state = EditorGetEffectiveState(G, obj, state);
2172 
2173     if((index == I->DragIndex) && (obj == I->DragObject)) {
2174       if(!EditorActive(G)) {
2175         int matrix_mode = SettingGet_i(G, I->DragObject->Setting,
2176                                        NULL, cSetting_matrix_mode);
2177         if(matrix_mode<0)
2178           matrix_mode = EditorDraggingObjectMatrix(G) ? 1 : 0;
2179 
2180         /* always force use of matrix mode for non-molecular objects */
2181         if((!objMol)&&(!matrix_mode))
2182           matrix_mode = 1;
2183 
2184         /* non-achored actions */
2185         switch (mode) {
2186         case cButModeRotDrag:
2187           if(I->DragHaveBase) {
2188             copy3f(I->DragBase, v3);
2189           } else {
2190             SceneOriginGet(G, v3);
2191           }
2192 
2193           get_rotation_about3f3fTTTf(pt[0], mov, v3, m);
2194           if(matrix_mode && (I->DragSelection < 0)) {
2195             switch (matrix_mode) {
2196             case 1:
2197               ObjectCombineTTT(obj, m, false, SettingGetGlobal_b(G,cSetting_movie_auto_store));
2198               break;
2199             case 2:
2200               if(objMol)
2201                 ObjectMoleculeTransformState44f(objMol, state, m, log_trans, false, true);
2202               break;
2203             }
2204           } else {
2205             if(objMol)
2206               ObjectMoleculeTransformSelection(objMol, state, I->DragSelection,
2207                                                m, log_trans, I->DragSeleName, false, true);
2208           }
2209           SceneInvalidate(G);
2210           break;
2211         case cButModeRotFrag:
2212         case cButModeRotObj:
2213         case cButModeRotView:
2214           if(I->DragHaveBase) {
2215             copy3f(I->DragBase, v3);
2216           } else {
2217             SceneOriginGet(G, v3);
2218           }
2219           subtract3f(pt, v3, n0);
2220           add3f(pt, mov, n1);
2221           subtract3f(n1, v3, n1);
2222           normalize3f(n0);
2223           normalize3f(n1);
2224           cross_product3f(n0, n1, cp);
2225           theta = (float) asin(length3f(cp));
2226           normalize23f(cp, n2);
2227           get_rotation_about3f3fTTTf(theta, n2, v3, m);
2228           /* matrix m now contains a valid TTT rotation in global
2229              coordinate space that could be applied directly to the
2230              coordinates to effect the desired rotation */
2231           if(mode == cButModeRotView) {
2232             /* modify the object's TTT */
2233             ObjectCombineTTT(obj, m, false,
2234                              SettingGetGlobal_b(G,cSetting_movie_auto_store));
2235           } else {
2236             if(matrix_mode) {
2237               switch (matrix_mode) {
2238               case 1:
2239                 ObjectCombineTTT(obj, m, false,
2240                                  SettingGetGlobal_b(G,cSetting_movie_auto_store));
2241                 break;
2242               case 2:
2243                 if(objMol)
2244                   ObjectMoleculeTransformState44f(objMol, state, m, log_trans, false, true);
2245                 break;
2246               }
2247             } else {
2248               if(objMol)
2249                 ObjectMoleculeTransformSelection(objMol, state, I->DragSelection,
2250                                                  m, log_trans, I->DragSeleName, false,
2251                                                  true);
2252             }
2253           }
2254           SceneInvalidate(G);
2255           break;
2256         case cButModeTorFrag:
2257           if(objMol) {
2258             ObjectMoleculeMoveAtom(objMol, state, index, mov, 1, log_trans);
2259             SceneInvalidate(G);
2260           }
2261           break;
2262         case cButModeMovView:
2263         case cButModeMovViewZ:
2264           ObjectTranslateTTT(obj, mov, SettingGetGlobal_b(G,cSetting_movie_auto_store));
2265           break;
2266         case cButModeMovObj:
2267         case cButModeMovObjZ:
2268         case cButModeMovFrag:
2269         case cButModeMovFragZ:
2270         case cButModeMovDrag:
2271         case cButModeMovDragZ:
2272           if(matrix_mode && (I->DragSelection < 0)) {
2273             identity44f(m);
2274             m[3] = mov[0];
2275             m[7] = mov[1];
2276             m[11] = mov[2];
2277             switch (matrix_mode) {
2278             case 1:
2279               ObjectCombineTTT(obj, m, false, SettingGetGlobal_b(G,cSetting_movie_auto_store));
2280               break;
2281             case 2:
2282               if(objMol)
2283                 ObjectMoleculeTransformState44f(objMol, state, m, log_trans, true, true);
2284               break;
2285             }
2286           } else {
2287             identity44f(m);
2288             copy3f(mov, m + 12);        /* questionable... */
2289             if(objMol)
2290               ObjectMoleculeTransformSelection(objMol, state, I->DragSelection, m,
2291                                                log_trans, I->DragSeleName, false, true);
2292           }
2293           SceneInvalidate(G);
2294           break;
2295         }
2296       } else {
2297         switch (mode) {
2298         case cButModeRotFrag:
2299         case cButModeRotObj:
2300           if(I->DragHaveBase) {
2301             copy3f(I->DragBase, v3);
2302           } else {
2303             copy3f(I->V0, v3);
2304           }
2305           if(I->DragSlowFlag) {
2306             SceneGetViewNormal(G, v4);
2307             scale3f(v4, -1.0F, v4);
2308             add3f(v3, v4, v4);
2309               subtract3f(pt, v4, n0);
2310             add3f(pt, mov, n1);
2311             subtract3f(n1, v4, n1);
2312           } else {
2313             subtract3f(pt, v3, n0);
2314             add3f(pt, mov, n1);
2315             subtract3f(n1, v3, n1);
2316           }
2317           normalize3f(n0);
2318           normalize3f(n1);
2319           cross_product3f(n0, n1, cp);
2320           theta = (float) asin(length3f(cp));
2321           normalize23f(cp, n2);
2322 
2323           get_rotation_about3f3fTTTf(theta, n2, v3, m);
2324           if(objMol) {
2325             ObjectMoleculeTransformSelection(objMol, state, I->DragSelection,
2326                                              m, log_trans, I->DragSeleName, false, true);
2327             SceneInvalidate(G);
2328           }
2329           break;
2330         case cButModeTorFrag:
2331         case cButModePkTorBnd:
2332           if(I->DragHaveAxis) {
2333             subtract3f(pt, I->Center, d0);
2334             if(dot_product3f(d0, I->Axis) < 0.0) {
2335               copy3f(I->V0, v1);
2336               copy3f(I->V1, v0);
2337             } else {
2338               copy3f(I->V0, v0);
2339               copy3f(I->V1, v1);
2340             }
2341             subtract3f(v1, v0, d1);
2342             copy3f(d1, n0);
2343             normalize3f(n0);
2344             cross_product3f(n0, d0, n1);
2345             normalize3f(n1);
2346 
2347             project3f(d0, n0, v2);
2348             add3f(I->Center, v2, v2);   /* v2 is the perpendicular point on the axis */
2349             subtract3f(pt, v2, d2);
2350             opp = (float) length3f(mov);
2351             adj = (float) length3f(d2);
2352             if(adj > R_SMALL4) {
2353               theta = (float) atan(opp / adj);
2354               if(dot_product3f(n1, mov) < 0.0)
2355                 theta = -theta;
2356               get_rotation_about3f3fTTTf(theta, n0, v1, m);
2357               if(objMol)
2358                 ObjectMoleculeTransformSelection(objMol, state, I->DragSelection, m,
2359                                                  log_trans, I->DragSeleName, false, true);
2360             } else {
2361 
2362               if(z_dir) {       /* NULL-safety */
2363                 cross_product3f(I->Axis, z_dir, d0);
2364                 theta = -dot_product3f(d0, mov);
2365                 get_rotation_about3f3fTTTf(theta, n0, v1, m);
2366                 if(objMol)
2367                   ObjectMoleculeTransformSelection(objMol, state, I->DragSelection, m,
2368                                                    log_trans, I->DragSeleName, false, true);
2369               }
2370 
2371             }
2372             if(I->BondMode && SettingGetGlobal_b(G, cSetting_editor_auto_dihedral))
2373               EditorDihedralInvalid(G, NULL);
2374           }
2375 
2376           SceneInvalidate(G);
2377           break;
2378         case cButModeMovFrag:
2379         case cButModeMovFragZ:
2380           identity44f(m);
2381           copy3f(mov, m + 12);  /* questionable */
2382           if(objMol)
2383             ObjectMoleculeTransformSelection(objMol, state, I->DragSelection,
2384                                            m, log_trans, I->DragSeleName, false, true);
2385           SceneInvalidate(G);
2386           break;
2387         }
2388       }
2389     }
2390     ExecutiveInvalidateSelectionIndicatorsCGO(G);
2391     EditorInvalidateShaderCGO(G);
2392   }
2393   PRINTFD(G, FB_Editor)
2394     " EditorDrag-Debug: leaving...\n" ENDFD;
2395 
2396 }
2397 
2398 
2399 /*========================================================================*/
EditorInit(PyMOLGlobals * G)2400 int EditorInit(PyMOLGlobals * G)
2401 {
2402   CEditor *I = NULL;
2403   if((I = (G->Editor = pymol::calloc<CEditor>(1)))) {
2404 
2405     I->DihedObject = NULL;
2406     I->NFrag = 0;
2407     I->Active = false;
2408     I->DragObject = NULL;
2409     I->DragIndex = -1;
2410     I->DragSelection = -1;
2411     I->NextPickSele = 0;
2412     I->BondMode = false;
2413     I->PosVLA = VLAlloc(float, 30);
2414     I->DihedralInvalid = false;
2415     I->MouseInvalid = false;
2416     I->FavorOrigin = false;
2417     I->shaderCGO = NULL;
2418     return 1;
2419   } else
2420     return 0;
2421 }
2422 
2423 
2424 /*========================================================================*/
EditorFree(PyMOLGlobals * G)2425 void EditorFree(PyMOLGlobals * G)
2426 {
2427   CEditor *I = G->Editor;
2428   VLAFreeP(I->PosVLA);
2429   FreeP(G->Editor);
2430 }
2431 
EditorInvalidateShaderCGO(PyMOLGlobals * G)2432 void EditorInvalidateShaderCGO(PyMOLGlobals * G){
2433   CEditor *I = G->Editor;
2434   CGOFree(I->shaderCGO);
2435 }
2436