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