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