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 #include"main.h"
24
25 #include"MemoryDebug.h"
26 #include"Ortho.h"
27 #include"P.h"
28 #include"PConv.h"
29 #include"PopUp.h"
30
31 #include"Wizard.h"
32 #include"Scene.h"
33
34 #include"Executive.h"
35 #include"Block.h"
36 #include"Text.h"
37 #include"CGO.h"
38
39 #define cWizBlank 0
40 #define cWizTypeText 1
41 #define cWizTypeButton 2
42 #define cWizTypePopUp 3
43
44 #define cWizEventPick 1
45 #define cWizEventSelect 2
46 #define cWizEventKey 4
47 #define cWizEventSpecial 8
48 #define cWizEventScene 16
49 #define cWizEventState 32
50 #define cWizEventFrame 64
51 #define cWizEventDirty 128
52 #define cWizEventView 256
53 #define cWizEventPosition 512
54
55 typedef struct {
56 int type;
57 WordType text;
58 OrthoLineType code;
59 } WizardLine;
60
61 struct CWizard : public Block {
62 PyObject **Wiz {};
63 WizardLine *Line {};
64 ov_size NLine { 0 };
65 ov_diff Stack { -1 };
66 int Pressed { -1 };
67 int EventMask { 0 };
68 int Dirty {};
69 int LastUpdatedState { -1 };
70 int LastUpdatedFrame { -1 };
71 float LastUpdatedPosition[3] {};
72 SceneViewType LastUpdatedView {};
73
CWizardCWizard74 CWizard(PyMOLGlobals * G) : Block(G) {};
75
76 int click(int button, int x, int y, int mod) override;
77 int drag(int x, int y, int mod) override;
78 void draw(CGO* orthoCGO) override;
79 int release(int button, int x, int y, int mod) override;
80 };
81
82 #define cWizardLeftMargin DIP2PIXEL(3)
83 #define cWizardTopMargin 0
84 #define cWizardClickOffset DIP2PIXEL(2)
85
WizardDirty(PyMOLGlobals * G)86 void WizardDirty(PyMOLGlobals * G)
87 {
88 CWizard *I = G->Wizard;
89 I->Dirty = true;
90 OrthoDirty(G);
91 }
92
WizardUpdate(PyMOLGlobals * G)93 int WizardUpdate(PyMOLGlobals * G)
94 {
95 CWizard *I = G->Wizard;
96 int result = false;
97
98 if(OrthoGetDirty(G)) {
99 WizardDoDirty(G);
100 }
101
102 {
103 int frame = SettingGetGlobal_i(G, cSetting_frame);
104 if(frame != I->LastUpdatedFrame) {
105 I->LastUpdatedFrame = frame;
106 WizardDoFrame(G);
107 }
108 }
109 {
110 int state = SettingGetGlobal_i(G, cSetting_state);
111 if(state != I->LastUpdatedState) {
112 I->LastUpdatedState = state;
113 WizardDoState(G);
114 }
115 }
116 WizardDoPosition(G, false);
117 WizardDoView(G, false);
118 if(I->Dirty) {
119 WizardRefresh(G);
120 I->Dirty = false;
121 result = true;
122 }
123 return result;
124 }
125
WizardPurgeStack(PyMOLGlobals * G)126 void WizardPurgeStack(PyMOLGlobals * G)
127 {
128 #ifndef _PYMOL_NOPY
129 int blocked;
130 ov_diff a;
131 CWizard *I = G->Wizard;
132 blocked = PAutoBlock(G);
133 for(a = I->Stack; a >= 0; a--)
134 Py_XDECREF(I->Wiz[a]);
135 I->Stack = -1;
136 PAutoUnblock(G, blocked);
137 #endif
138 }
139
WizardDoSelect(PyMOLGlobals * G,char * name,int state)140 int WizardDoSelect(PyMOLGlobals * G, char *name, int state)
141 {
142 /**
143 * Run when user selects something with the mouse, in a wizard
144 */
145 #ifdef _PYMOL_NOPY
146 return 0;
147 #else
148 /* grab 'this' */
149 OrthoLineType buf;
150 CWizard *I = G->Wizard;
151 int result = false;
152
153 /* if the event is a selection and we're listening for selections */
154 if(I->EventMask & cWizEventSelect)
155 if(I->Stack >= 0)
156 if(I->Wiz[I->Stack]) {
157 /* log if necessary */
158 sprintf(buf, "cmd.get_wizard().do_select('''%s''')", name);
159 PLog(G, buf, cPLog_pym);
160 /* block and call (in Python) the wizard's do_select */
161 PBlock(G);
162 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_pick_state")) {
163 result = PTruthCallStr1i(I->Wiz[I->Stack], "do_pick_state", state + 1);
164 if(PyErr_Occurred())
165 PyErr_Print();
166 }
167 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_select")) {
168 result = PTruthCallStr(I->Wiz[I->Stack], "do_select", name);
169 if(PyErr_Occurred())
170 PyErr_Print();
171 }
172 PUnblock(G);
173 }
174 return result;
175 #endif
176 }
177
178
179 /*========================================================================*/
WizardRefresh(PyMOLGlobals * G)180 void WizardRefresh(PyMOLGlobals * G)
181 {
182
183 #ifndef _PYMOL_NOPY
184 CWizard *I = G->Wizard;
185 char *vla = NULL;
186 PyObject *P_list;
187 ov_size ll;
188 PyObject *i;
189 ov_size a;
190 int blocked;
191 blocked = PAutoBlock(G);
192
193 /* get the current prompt */
194 if(I->Stack >= 0)
195 if(I->Wiz[I->Stack]) {
196 vla = NULL;
197 if(PyObject_HasAttrString(I->Wiz[I->Stack], "get_prompt")) {
198 P_list = PYOBJECT_CALLMETHOD(I->Wiz[I->Stack], "get_prompt", "");
199 if(PyErr_Occurred())
200 PyErr_Print();
201 if(P_list)
202 PConvPyListToStringVLA(P_list, &vla);
203 Py_XDECREF(P_list);
204 }
205 }
206
207 OrthoSetWizardPrompt(G, vla);
208
209 /* get the current panel list */
210
211 I->NLine = 0;
212 if(I->Stack >= 0)
213 if(I->Wiz[I->Stack]) {
214
215 I->EventMask = cWizEventPick + cWizEventSelect;
216
217 if(PyObject_HasAttrString(I->Wiz[I->Stack], "get_event_mask")) {
218 i = PYOBJECT_CALLMETHOD(I->Wiz[I->Stack], "get_event_mask", "");
219 if(PyErr_Occurred())
220 PyErr_Print();
221 if(!PConvPyIntToInt(i, &I->EventMask))
222 I->EventMask = cWizEventPick + cWizEventSelect;
223 Py_XDECREF(i);
224 }
225
226 if(PyObject_HasAttrString(I->Wiz[I->Stack], "get_panel")) {
227 P_list = PYOBJECT_CALLMETHOD(I->Wiz[I->Stack], "get_panel", "");
228 if(PyErr_Occurred())
229 PyErr_Print();
230 if(P_list) {
231 if(PyList_Check(P_list)) {
232 ll = PyList_Size(P_list);
233 VLACheck(I->Line, WizardLine, ll);
234 for(a = 0; a < ll; a++) {
235 /* fallback defaults */
236
237 I->Line[a].text[0] = 0;
238 I->Line[a].code[0] = 0;
239 I->Line[a].type = 0;
240
241 i = PyList_GetItem(P_list, a);
242 if(PyList_Check(i))
243 if(PyList_Size(i) > 2) {
244 PConvPyObjectToInt(PyList_GetItem(i, 0), &I->Line[a].type);
245 PConvPyObjectToStrMaxLen(PyList_GetItem(i, 1),
246 I->Line[a].text, sizeof(WordType) - 1);
247 PConvPyObjectToStrMaxLen(PyList_GetItem(i, 2),
248 I->Line[a].code, sizeof(OrthoLineType) - 1);
249 }
250 }
251 I->NLine = ll;
252 }
253 }
254 Py_XDECREF(P_list);
255 }
256 }
257 if(I->NLine) {
258 int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
259 OrthoReshapeWizard(G, LineHeight * I->NLine + 4);
260 } else {
261 OrthoReshapeWizard(G, 0);
262 }
263 PAutoUnblock(G, blocked);
264 #endif
265 }
266
267
268 /*========================================================================*/
WizardSet(PyMOLGlobals * G,PyObject * wiz,int replace)269 void WizardSet(PyMOLGlobals * G, PyObject * wiz, int replace)
270 {
271 #ifndef _PYMOL_NOPY
272 CWizard *I = G->Wizard;
273 int blocked;
274 blocked = PAutoBlock(G);
275 if(I->Wiz) {
276 if((!wiz) || (wiz == Py_None) || ((I->Stack >= 0) && replace)) {
277 if(I->Stack >= 0) { /* pop */
278 PyObject *old_wiz = I->Wiz[I->Stack];
279
280 /* remove wizard from stack first */
281
282 I->Wiz[I->Stack] = NULL;
283 I->Stack--;
284
285 if(old_wiz) {
286 /* then call cleanup, etc. */
287 if(PyObject_HasAttrString(old_wiz, "cleanup")) {
288 PXDecRef(PYOBJECT_CALLMETHOD(old_wiz, "cleanup", ""));
289 if(PyErr_Occurred())
290 PyErr_Print();
291 }
292 Py_DECREF(old_wiz);
293 }
294 }
295 }
296 if(wiz && (wiz != Py_None)) { /* push */
297 if(wiz) {
298 I->Stack++;
299 VLACheck(I->Wiz, PyObject *, I->Stack);
300 I->Wiz[I->Stack] = wiz;
301 if(I->Wiz[I->Stack])
302 Py_INCREF(I->Wiz[I->Stack]);
303 }
304 }
305 }
306 WizardRefresh(G);
307 PAutoUnblock(G, blocked);
308 #endif
309 }
310
311
312 /*========================================================================*/
WizardActive(PyMOLGlobals * G)313 int WizardActive(PyMOLGlobals * G)
314 {
315 CWizard *I = G->Wizard;
316 if(!I->Wiz)
317 return (false);
318 if(I->Stack < 0)
319 return false;
320 return (I->Wiz[I->Stack] && 1);
321 }
322
323
324 /*========================================================================*/
WizardGetBlock(PyMOLGlobals * G)325 Block *WizardGetBlock(PyMOLGlobals * G)
326 {
327 CWizard *I = G->Wizard;
328 {
329 return (I);
330 }
331 }
332
333
334 /*========================================================================*/
WizardDoPick(PyMOLGlobals * G,int bondFlag,int state)335 int WizardDoPick(PyMOLGlobals * G, int bondFlag, int state)
336 {
337 /**
338 * Run when user picks something
339 */
340 #ifdef _PYMOL_NOPY
341 return 0;
342 #else
343 CWizard *I = G->Wizard;
344 int result = false;
345
346 /* process the pick if it happened and we're listening for it */
347 if(I->EventMask & cWizEventPick)
348 if(I->Stack >= 0)
349 if(I->Wiz[I->Stack]) {
350 if(bondFlag)
351 PLog(G, "cmd.get_wizard().do_pick(1)", cPLog_pym);
352 else
353 PLog(G, "cmd.get_wizard().do_pick(0)", cPLog_pym);
354
355 PBlock(G);
356 if(I->Stack >= 0)
357 if(I->Wiz[I->Stack]) {
358 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_pick_state")) {
359 result = PTruthCallStr1i(I->Wiz[I->Stack], "do_pick_state", state + 1);
360 if(PyErr_Occurred())
361 PyErr_Print();
362 }
363 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_pick")) {
364 result = PTruthCallStr1i(I->Wiz[I->Stack], "do_pick", bondFlag);
365 if(PyErr_Occurred())
366 PyErr_Print();
367 }
368 }
369 PUnblock(G);
370 }
371 return result;
372 #endif
373 }
374
WizardDoKey(PyMOLGlobals * G,unsigned char k,int x,int y,int mod)375 int WizardDoKey(PyMOLGlobals * G, unsigned char k, int x, int y, int mod)
376 {
377 #ifdef _PYMOL_NOPY
378 return 0;
379 #else
380 CWizard *I = G->Wizard;
381 int result = false;
382 if(I->EventMask & cWizEventKey)
383 if(I->Stack >= 0)
384 if(I->Wiz[I->Stack]) {
385 OrthoLineType buffer;
386 sprintf(buffer, "cmd.get_wizard().do_key(%d,%d,%d,%d)", k, x, y, mod);
387 PLog(G, buffer, cPLog_pym);
388 PBlock(G);
389 if(I->Stack >= 0)
390 if(I->Wiz[I->Stack]) {
391 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_key")) {
392 result = PTruthCallStr4i(I->Wiz[I->Stack], "do_key", k, x, y, mod);
393 if(PyErr_Occurred())
394 PyErr_Print();
395 }
396 }
397 PUnblock(G);
398 }
399 return result;
400 #endif
401 }
402
WizardDoPosition(PyMOLGlobals * G,int force)403 int WizardDoPosition(PyMOLGlobals * G, int force)
404 {
405 #ifdef _PYMOL_NOPY
406 return 0;
407 #else
408 CWizard *I = G->Wizard;
409 int result = false;
410 if(I->EventMask & cWizEventPosition)
411 if(I->Stack >= 0)
412 if(I->Wiz[I->Stack]) {
413 int changed = force;
414 if(!changed) {
415 float pos[3];
416 SceneGetCenter(G, pos);
417 changed = ((fabs(pos[0] - I->LastUpdatedPosition[0]) > R_SMALL4) ||
418 (fabs(pos[1] - I->LastUpdatedPosition[1]) > R_SMALL4) ||
419 (fabs(pos[2] - I->LastUpdatedPosition[2]) > R_SMALL4));
420 }
421 if(changed) {
422 SceneGetCenter(G, I->LastUpdatedPosition);
423 PBlock(G);
424 if(I->Stack >= 0)
425 if(I->Wiz[I->Stack]) {
426 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_position")) {
427 result = PTruthCallStr0(I->Wiz[I->Stack], "do_position");
428 if(PyErr_Occurred())
429 PyErr_Print();
430 }
431 }
432 PUnblock(G);
433 }
434 }
435 return result;
436 #endif
437 }
438
WizardDoView(PyMOLGlobals * G,int force)439 int WizardDoView(PyMOLGlobals * G, int force)
440 {
441 #ifdef _PYMOL_NOPY
442 return 0;
443 #else
444 CWizard *I = G->Wizard;
445 int result = false;
446 if(I->EventMask & cWizEventView)
447 if(I->Stack >= 0)
448 if(I->Wiz[I->Stack]) {
449 int changed = force;
450 if(!changed) {
451 SceneViewType view;
452 SceneGetView(G, view);
453 changed = !SceneViewEqual(view, I->LastUpdatedView);
454 }
455 if(changed) {
456 SceneGetView(G, I->LastUpdatedView);
457 PBlock(G);
458 if(I->Stack >= 0)
459 if(I->Wiz[I->Stack]) {
460 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_view")) {
461 result = PTruthCallStr0(I->Wiz[I->Stack], "do_view");
462 if(PyErr_Occurred())
463 PyErr_Print();
464 }
465 }
466 PUnblock(G);
467 }
468 }
469 return result;
470 #endif
471 }
472
WizardDoScene(PyMOLGlobals * G)473 int WizardDoScene(PyMOLGlobals * G)
474 {
475 #ifdef _PYMOL_NOPY
476 return 0;
477 #else
478 CWizard *I = G->Wizard;
479 int result = false;
480 if(I->EventMask & cWizEventScene)
481 if(I->Stack >= 0)
482 if(I->Wiz[I->Stack]) {
483 OrthoLineType buffer;
484 sprintf(buffer, "cmd.get_wizard().do_scene()");
485 PLog(G, buffer, cPLog_pym);
486 PBlock(G);
487 if(I->Stack >= 0)
488 if(I->Wiz[I->Stack]) {
489 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_scene")) {
490 result = PTruthCallStr0(I->Wiz[I->Stack], "do_scene");
491 if(PyErr_Occurred())
492 PyErr_Print();
493 }
494 }
495 PUnblock(G);
496 }
497 return result;
498 #endif
499 }
500
WizardDoDirty(PyMOLGlobals * G)501 int WizardDoDirty(PyMOLGlobals * G)
502 {
503 #ifdef _PYMOL_NOPY
504 return 0;
505 #else
506 CWizard *I = G->Wizard;
507 int result = false;
508 if(I->EventMask & cWizEventDirty)
509 if(I->Stack >= 0)
510 if(I->Wiz[I->Stack]) {
511 OrthoLineType buffer;
512 sprintf(buffer, "cmd.get_wizard().do_dirty()");
513 PLog(G, buffer, cPLog_pym);
514 PBlock(G);
515 if(I->Stack >= 0)
516 if(I->Wiz[I->Stack]) {
517 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_dirty")) {
518 result = PTruthCallStr0(I->Wiz[I->Stack], "do_dirty");
519 if(PyErr_Occurred())
520 PyErr_Print();
521 }
522 }
523 PUnblock(G);
524 }
525 return result;
526 #endif
527 }
528
WizardDoState(PyMOLGlobals * G)529 int WizardDoState(PyMOLGlobals * G)
530 {
531 #ifdef _PYMOL_NOPY
532 return 0;
533 #else
534 CWizard *I = G->Wizard;
535 int result = false;
536 if(I->EventMask & cWizEventState)
537 if(I->Stack >= 0)
538 if(I->Wiz[I->Stack]) {
539 OrthoLineType buffer;
540 int state = SettingGetGlobal_i(G, cSetting_state);
541 sprintf(buffer, "cmd.get_wizard().do_state(%d)", state);
542 PLog(G, buffer, cPLog_pym);
543 PBlock(G);
544 if(I->Stack >= 0)
545 if(I->Wiz[I->Stack]) {
546 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_state")) {
547 result = PTruthCallStr1i(I->Wiz[I->Stack], "do_state", state);
548 if(PyErr_Occurred())
549 PyErr_Print();
550 }
551 }
552 PUnblock(G);
553 }
554 return result;
555 #endif
556 }
557
WizardDoFrame(PyMOLGlobals * G)558 int WizardDoFrame(PyMOLGlobals * G)
559 {
560 #ifdef _PYMOL_NOPY
561 return 0;
562 #else
563 CWizard *I = G->Wizard;
564 int result = false;
565 if(I->EventMask & cWizEventFrame)
566 if(I->Stack >= 0)
567 if(I->Wiz[I->Stack]) {
568 OrthoLineType buffer;
569 int frame = SettingGetGlobal_i(G, cSetting_frame) + 1;
570 sprintf(buffer, "cmd.get_wizard().do_frame(%d)", frame);
571 PLog(G, buffer, cPLog_pym);
572 PBlock(G);
573 if(I->Stack >= 0)
574 if(I->Wiz[I->Stack]) {
575 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_frame")) {
576 result = PTruthCallStr1i(I->Wiz[I->Stack], "do_frame", frame);
577 if(PyErr_Occurred())
578 PyErr_Print();
579 }
580 }
581 PUnblock(G);
582 }
583 return result;
584 #endif
585 }
586
WizardDoSpecial(PyMOLGlobals * G,int k,int x,int y,int mod)587 int WizardDoSpecial(PyMOLGlobals * G, int k, int x, int y, int mod)
588 {
589 #ifdef _PYMOL_NOPY
590 return 0;
591 #else
592 CWizard *I = G->Wizard;
593 int result = false;
594
595 if(I->EventMask & cWizEventSpecial)
596 if(I->Stack >= 0)
597 if(I->Wiz[I->Stack]) {
598 OrthoLineType buffer;
599 sprintf(buffer, "cmd.get_wizard().do_special(%d,%d,%d,%d)", k, x, y, mod);
600 PLog(G, buffer, cPLog_pym);
601 PBlock(G);
602 if(I->Stack >= 0)
603 if(I->Wiz[I->Stack]) {
604 if(PyObject_HasAttrString(I->Wiz[I->Stack], "do_special")) {
605 result = PTruthCallStr4i(I->Wiz[I->Stack], "do_special", k, x, y, mod);
606 if(PyErr_Occurred())
607 PyErr_Print();
608 }
609 }
610 PUnblock(G);
611 }
612 return result;
613 #endif
614 }
615
616
617 /*========================================================================*/
click(int button,int x,int y,int mod)618 int CWizard::click(int button, int x, int y, int mod)
619 {
620 #ifdef _PYMOL_NOPY
621 return 0;
622 #else
623 PyMOLGlobals *G = m_G;
624 CWizard *I = G->Wizard;
625 int a;
626 PyObject *menuList = NULL;
627 int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
628
629 a = ((rect.top - (y + cWizardClickOffset)) - cWizardTopMargin) / LineHeight;
630 if((a >= 0) && ((ov_size) a < I->NLine)) {
631 switch (I->Line[a].type) {
632 case cWizTypeButton:
633 OrthoGrab(G, this);
634 I->Pressed = (int) a;
635 OrthoDirty(G);
636 break;
637 case cWizTypePopUp:
638 PBlock(G);
639 if(I->Stack >= 0)
640 if(I->Wiz[I->Stack]) {
641 if(PyObject_HasAttrString(I->Wiz[I->Stack], "get_menu")) {
642 menuList =
643 PYOBJECT_CALLMETHOD(I->Wiz[I->Stack], "get_menu", "s", I->Line[a].code);
644 if(PyErr_Occurred())
645 PyErr_Print();
646 }
647 }
648
649 if(PyErr_Occurred())
650 PyErr_Print();
651 if(menuList && (menuList != Py_None)) {
652 int my = rect.top - (cWizardTopMargin + a * LineHeight) - 2;
653
654 PopUpNew(G, x, my, x, y, false, menuList, NULL);
655 }
656 Py_XDECREF(menuList);
657 PUnblock(G);
658 break;
659 }
660 }
661 return (1);
662 #endif
663 }
664
665
666 /*========================================================================*/
drag(int x,int y,int mod)667 int CWizard::drag(int x, int y, int mod)
668 {
669 #ifdef _PYMOL_NOPY
670 return 0;
671 #else
672
673 PyMOLGlobals *G = m_G;
674
675 CWizard *I = G->Wizard;
676 int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
677
678 int a;
679 a = ((rect.top - (y + cWizardClickOffset)) - cWizardTopMargin) / LineHeight;
680
681 if((x < rect.left) || (x > rect.right))
682 a = -1;
683
684 if(I->Pressed != a) {
685 I->Pressed = -1;
686 OrthoDirty(G);
687 }
688 if((a >= 0) && ((ov_size) a < I->NLine)) {
689
690 switch (I->Line[a].type) {
691 case cWizTypeButton:
692 if(I->Pressed != a) {
693 I->Pressed = a;
694 OrthoDirty(G);
695 }
696 break;
697 }
698 }
699 return (1);
700 #endif
701 }
702
703
704 /*========================================================================*/
release(int button,int x,int y,int mod)705 int CWizard::release(int button, int x, int y, int mod)
706 {
707 PyMOLGlobals *G = m_G;
708
709 CWizard *I = this; // TODO: Remove during Wizard Refactor
710 int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
711
712 int a;
713 a = ((rect.top - (y + cWizardClickOffset)) - cWizardTopMargin) / LineHeight;
714
715 if(I->Pressed)
716 I->Pressed = -1;
717 OrthoDirty(G);
718
719 OrthoUngrab(G);
720
721 if((a >= 0) && ((ov_size) a < I->NLine)) {
722 switch (I->Line[a].type) {
723 case cWizTypeButton:
724 if(I->Stack >= 0)
725 if(I->Wiz[I->Stack]) {
726 PLog(G, I->Line[a].code, cPLog_pym);
727 PParse(G, I->Line[a].code);
728 PFlush(G);
729 }
730 break;
731 }
732 }
733 I->Pressed = -1;
734 return (1);
735 }
736
draw_button(int x2,int y2,int w,int h,float * light,float * dark,float * inside ORTHOCGOARG)737 static void draw_button(int x2, int y2, int w, int h, float *light, float *dark,
738 float *inside ORTHOCGOARG)
739 {
740 if (orthoCGO){
741 CGOColorv(orthoCGO, light);
742 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
743 CGOVertex(orthoCGO, x2, y2, 0.f);
744 CGOVertex(orthoCGO, x2, y2 + h, 0.f);
745 CGOVertex(orthoCGO, x2 + w, y2, 0.f);
746 CGOVertex(orthoCGO, x2 + w, y2 + h, 0.f);
747 CGOEnd(orthoCGO);
748 } else {
749 glColor3fv(light);
750 glBegin(GL_POLYGON);
751 glVertex2i(x2, y2);
752 glVertex2i(x2, y2 + h);
753 glVertex2i(x2 + w, y2 + h);
754 glVertex2i(x2 + w, y2);
755 glEnd();
756 }
757
758 if (orthoCGO){
759 CGOColorv(orthoCGO, dark);
760 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
761 CGOVertex(orthoCGO, x2 + 1, y2, 0.f);
762 CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
763 CGOVertex(orthoCGO, x2 + w, y2, 0.f);
764 CGOVertex(orthoCGO, x2 + w, y2 + h - 1, 0.f);
765 CGOEnd(orthoCGO);
766 } else {
767 glColor3fv(dark);
768 glBegin(GL_POLYGON);
769 glVertex2i(x2 + 1, y2);
770 glVertex2i(x2 + 1, y2 + h - 1);
771 glVertex2i(x2 + w, y2 + h - 1);
772 glVertex2i(x2 + w, y2);
773 glEnd();
774 }
775
776 if(inside) {
777 if (orthoCGO){
778 CGOColorv(orthoCGO, inside);
779 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
780 CGOVertex(orthoCGO, x2 + 1, y2 + 1, 0.f);
781 CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
782 CGOVertex(orthoCGO, x2 + w - 1, y2 + 1, 0.f);
783 CGOVertex(orthoCGO, x2 + w - 1, y2 + h - 1, 0.f);
784 CGOEnd(orthoCGO);
785 } else {
786 glColor3fv(inside);
787 glBegin(GL_POLYGON);
788 glVertex2i(x2 + 1, y2 + 1);
789 glVertex2i(x2 + 1, y2 + h - 1);
790 glVertex2i(x2 + w - 1, y2 + h - 1);
791 glVertex2i(x2 + w - 1, y2 + 1);
792 glEnd();
793 }
794 } else { /* rainbow */
795 if (orthoCGO){
796 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
797 CGOColor(orthoCGO, 0.1F, 1.0F, 0.1F); // green
798 CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
799 CGOColor(orthoCGO, 1.0F, 1.0F, 0.1F); // yellow
800 CGOVertex(orthoCGO, x2 + w - 1, y2 + h - 1, 0.f);
801 CGOColor(orthoCGO, 1.f, 0.1f, 0.1f); // red
802 CGOVertex(orthoCGO, x2 + 1, y2 + 1, 0.f);
803 CGOColor(orthoCGO, 0.1F, 0.1F, 1.0F); // blue
804 CGOVertex(orthoCGO, x2 + w - 1, y2 + 1, 0.f);
805 CGOEnd(orthoCGO);
806 } else {
807 glBegin(GL_POLYGON);
808 glColor3f(1.0F, 0.1F, 0.1F);
809 glVertex2i(x2 + 1, y2 + 1);
810 glColor3f(0.1F, 1.0F, 0.1F);
811 glVertex2i(x2 + 1, y2 + h - 1);
812 glColor3f(1.0F, 1.0F, 0.1F);
813 glVertex2i(x2 + w - 1, y2 + h - 1);
814 glColor3f(0.1F, 0.1F, 1.0F);
815 glVertex2i(x2 + w - 1, y2 + 1);
816 glEnd();
817 }
818 }
819
820 }
821
draw_text(PyMOLGlobals * G,char * c,int xx,int yy,float * color ORTHOCGOARG)822 static void draw_text(PyMOLGlobals * G, char *c, int xx, int yy, float *color ORTHOCGOARG)
823 {
824 TextSetColor(G, color);
825 while(*c) {
826 if(TextSetColorFromCode(G, c, color)) {
827 c += 4;
828 }
829 TextSetPos2i(G, xx, yy);
830 TextDrawChar(G, *(c++) ORTHOCGOARGVAR);
831 xx = xx + DIP2PIXEL(8);
832 }
833 }
834
835
836 /*========================================================================*/
draw(CGO * orthoCGO)837 void CWizard::draw(CGO* orthoCGO)
838 {
839 PyMOLGlobals *G = m_G;
840
841 CWizard *I = G->Wizard;
842 int x, y;
843 int a;
844
845 float buttonTextColor[3] = { 1.0, 1.0, 1.0 };
846 float buttonActiveColor[3] = { 0.8F, 0.8F, 0.8F };
847
848 float dimColor[3] = { 0.45F, 0.45F, 0.45F };
849
850 float dimLightEdge[3] = { 0.6F, 0.6F, 0.6F };
851 float dimDarkEdge[3] = { 0.25F, 0.25F, 0.25F };
852
853 float menuBGColor[3] = { 0.5F, 0.5F, 1.0 };
854 float menuLightEdge[3] = { 0.7F, 0.7F, 0.9F };
855 float menuDarkEdge[3] = { 0.3F, 0.3F, 0.5F };
856
857 float black_color[3] = { 0.0F, 0.0F, 0.0F };
858 float menuColor[3] = { 0.0, 0.0, 0.0 };
859 int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
860 int text_lift = (LineHeight / 2) - DIP2PIXEL(5);
861 float *text_color, *text_color2 = TextColor;
862
863 text_color = menuColor;
864
865 if(G->HaveGUI && G->ValidContext && ((rect.right - rect.left) > 6)) {
866
867 if(SettingGetGlobal_b(G, cSetting_internal_gui_mode) == 0) {
868 if (orthoCGO)
869 CGOColorv(orthoCGO, BackColor);
870 #ifndef PURE_OPENGL_ES_2
871 else
872 glColor3fv(BackColor);
873 #endif
874 fill(orthoCGO);
875 drawLeftEdge(orthoCGO);
876 } else {
877 drawLeftEdge(orthoCGO);
878 if (orthoCGO)
879 CGOColor(orthoCGO, .5f, .5f, .5f);
880 else
881 glColor3f(0.5, 0.5, 0.5);
882 drawTopEdge();
883 text_color2 = OrthoGetOverlayColor(G);
884 }
885
886 if (orthoCGO)
887 CGOColorv(orthoCGO, TextColor);
888 #ifndef PURE_OPENGL_ES_2
889 else
890 glColor3fv(TextColor);
891 #endif
892 x = rect.left + cWizardLeftMargin;
893 y = (rect.top - LineHeight) - cWizardTopMargin;
894
895 for(a = 0; (ov_size) a < I->NLine; a++) {
896 if(I->Pressed == a) {
897 draw_button(rect.left + 1, y,
898 (rect.right - rect.left) - 1,
899 LineHeight - 1, dimLightEdge, dimDarkEdge, buttonActiveColor ORTHOCGOARGVAR);
900 /* glColor3f(0.0,0.0,0.0); */
901 text_color = black_color;
902 } else {
903 switch (I->Line[a].type) {
904 case cWizTypeText:
905 text_color = text_color2;
906 glColor3fv(text_color2);
907 break;
908 case cWizTypeButton:
909 draw_button(rect.left + 1, y,
910 (rect.right - rect.left) - 1,
911 LineHeight - 1, dimLightEdge, dimDarkEdge, dimColor ORTHOCGOARGVAR);
912
913 /* glColor3fv(buttonTextColor); */
914 text_color = buttonTextColor;
915 break;
916 case cWizTypePopUp:
917 draw_button(rect.left + 1, y,
918 (rect.right - rect.left) - 1,
919 LineHeight - 1, menuLightEdge, menuDarkEdge, menuBGColor ORTHOCGOARGVAR);
920 /* glColor3fv(menuColor); */
921 text_color = menuColor;
922 break;
923 default:
924 break;
925 }
926 }
927 draw_text(G, I->Line[a].text, x, y + text_lift, text_color ORTHOCGOARGVAR);
928 /*GrapDrawStr(I->Line[a].text,x+1,y+text_lift); */
929 y -= LineHeight;
930 }
931 }
932 }
933
934
935 /*========================================================================*/
WizardGet(PyMOLGlobals * G)936 PyObject *WizardGet(PyMOLGlobals * G)
937 {
938 CWizard *I = G->Wizard;
939 if(!I->Wiz)
940 return (NULL);
941 if(I->Stack < 0)
942 return (NULL);
943 return (I->Wiz[I->Stack]);
944 }
945
946
947 /*========================================================================*/
WizardGetStack(PyMOLGlobals * G)948 PyObject *WizardGetStack(PyMOLGlobals * G)
949 {
950 #ifdef _PYMOL_NOPY
951 return NULL;
952 #else
953 CWizard *I = G->Wizard;
954 PyObject *result;
955
956 result = PyList_New(I->Stack - (-1));
957 if(I->Wiz) {
958 ov_diff a;
959 for(a = I->Stack; a >= 0; a--) {
960 Py_INCREF(I->Wiz[a]);
961 PyList_SetItem(result, a, I->Wiz[a]); /* steals ref */
962 }
963 }
964 return (result);
965 #endif
966 }
967
968
969 /*========================================================================*/
WizardSetStack(PyMOLGlobals * G,PyObject * list)970 int WizardSetStack(PyMOLGlobals * G, PyObject * list)
971 {
972 #ifdef _PYMOL_NOPY
973 return 0;
974 #else
975
976 CWizard *I = G->Wizard;
977 int ok = true;
978
979 if(I->Wiz) {
980 WizardPurgeStack(G);
981 if(ok)
982 ok = (list != NULL);
983 if(ok)
984 ok = PyList_Check(list);
985 if(ok) {
986 I->Stack = PyList_Size(list) - 1;
987 if(I->Stack >= 0) {
988 ov_diff a;
989 VLACheck(I->Wiz, PyObject *, I->Stack);
990 for(a = I->Stack; a >= 0; a--) {
991 I->Wiz[a] = PyList_GetItem(list, a);
992 Py_INCREF(I->Wiz[a]);
993 }
994 }
995 }
996 if(ok)
997 WizardRefresh(G);
998 if(ok)
999 OrthoDirty(G);
1000 }
1001 return (ok);
1002 #endif
1003 }
1004
1005
1006 /*========================================================================*/
WizardInit(PyMOLGlobals * G)1007 int WizardInit(PyMOLGlobals * G)
1008 {
1009 CWizard *I = NULL;
1010 if((I = (G->Wizard = new CWizard(G)))) {
1011
1012 I->active = true;
1013 I->TextColor[0] = 0.2F;
1014 I->TextColor[1] = 1.0F;
1015 I->TextColor[2] = 0.2F;
1016
1017 OrthoAttach(G, I, cOrthoTool);
1018
1019 I->Line = VLAlloc(WizardLine, 1);
1020 I->Wiz = VLAlloc(PyObject *, 10);
1021 return 1;
1022 } else
1023 return 0;
1024 }
1025
1026
1027 /*========================================================================*/
WizardFree(PyMOLGlobals * G)1028 void WizardFree(PyMOLGlobals * G)
1029 {
1030 CWizard *I = G->Wizard;
1031 WizardPurgeStack(G);
1032 VLAFreeP(I->Line);
1033 VLAFreeP(I->Wiz);
1034 DeleteP(G->Wizard);
1035 }
1036