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"MemoryDebug.h"
23 #include "main.h"
24 #include "Base.h"
25 #include "ButMode.h"
26 #include "Scene.h"
27 #include "Util.h"
28 #include "Ortho.h"
29 #include "Setting.h"
30 #include "P.h"
31 #include "Text.h"
32 #include "Menu.h"
33 #include "CGO.h"
34 #include "Movie.h"
35 
36 #define cButModeLineHeight DIP2PIXEL(12)
37 #define cButModeLeftMargin DIP2PIXEL(2)
38 #define cButModeTopMargin DIP2PIXEL(1)
39 #define cButModeBottomMargin DIP2PIXEL(2)
40 
41 struct CButMode : public Block {
42   CodeType Code[cButModeCount + 1] {};
43   int NCode {};
44   int Mode[cButModeInputCount] {};
45   int NBut {};
46   float Rate { 0.0f };
47   float RateShown { 0.0f };
48   float Samples { 0.0f }, Delay { 0.0f };
49   float TextColor1[3] = { 0.5f, 0.5f, 1.0f };
50   float TextColor2[3] = { 0.8f, 0.8f, 0.8f };
51   float TextColor3[3] = { 1.0f, 0.5f, 0.5f };
52   int DeferCnt { 0 };
53   float DeferTime { 0.0f };
54 
CButModeCButMode55   CButMode(PyMOLGlobals * G) : Block(G) {}
56 
57   int click(int button, int x, int y, int mod) override;
58   void draw(CGO *orthoCGO) override;
59   bool fastDraw(CGO* orthoCGO) override;
60 };
61 
62 
63 /*========================================================================*/
ButModeGetBlock(PyMOLGlobals * G)64 Block *ButModeGetBlock(PyMOLGlobals * G)
65 {
66   CButMode *I = G->ButMode;
67   {
68     return (I);
69   }
70 }
71 
ButModeGetHeight(PyMOLGlobals * G)72 int ButModeGetHeight(PyMOLGlobals * G)
73 {
74   if(SettingGetGlobal_b(G, cSetting_mouse_grid))
75     return DIP2PIXEL(124);
76   else
77     return DIP2PIXEL(40);
78 }
79 
80 
81 /*========================================================================*/
ButModeGet(PyMOLGlobals * G,int button)82 int ButModeGet(PyMOLGlobals * G, int button)
83 {
84   CButMode *I = G->ButMode;
85   if((button >= 0) && (button < I->NBut)) {
86     return I->Mode[button];
87   }
88   return 0;
89 }
90 
ButModeSet(PyMOLGlobals * G,int button,int action)91 void ButModeSet(PyMOLGlobals * G, int button, int action)
92 {
93   CButMode *I = G->ButMode;
94   if((button >= 0) && (button < I->NBut) && (action >= 0) && (action < I->NCode)) {
95     I->Mode[button] = action;
96     OrthoDirty(G);
97   }
98 }
99 
100 
101 /*========================================================================*/
ButModeSetRate(PyMOLGlobals * G,float interval)102 void ButModeSetRate(PyMOLGlobals * G, float interval)
103 {
104   CButMode *I = G->ButMode;
105 
106   if(interval >= 0.001F) {      /* sub-millisecond, defer... */
107     if(I->DeferCnt) {
108       interval = (interval + I->DeferTime) / (I->DeferCnt + 1);
109       I->DeferCnt = 0;
110       I->DeferTime = 0.0F;
111     }
112     I->Delay -= interval;
113     if(interval < 1.0F) {
114       I->Samples *= 0.95 * (1.0F - interval);
115       I->Rate *= 0.95 * (1.0F - interval);
116     } else {
117       I->Samples = 0.0F;
118       I->Rate = 0.0F;
119     }
120 
121     I->Samples++;
122     I->Rate += 1.0F / interval;
123   } else {
124     I->DeferCnt++;
125     I->DeferTime += interval;
126   }
127 }
128 
129 
130 /*========================================================================*/
ButModeResetRate(PyMOLGlobals * G)131 void ButModeResetRate(PyMOLGlobals * G)
132 {
133   CButMode *I = G->ButMode;
134   I->Samples = 0.0;
135   I->Rate = 0.0;
136   I->RateShown = 0;
137   I->Delay = 0;
138 }
139 
140 
141 /*========================================================================*/
ButModeFree(PyMOLGlobals * G)142 void ButModeFree(PyMOLGlobals * G)
143 {
144   DeleteP(G->ButMode);
145 }
146 
147 
148 /*========================================================================*/
click(int button,int x,int y,int mod)149 int CButMode::click(int button, int x, int y, int mod)
150 {
151   int dy = (y - rect.bottom) / cButModeLineHeight;
152   //  int dx = (x - block->rect.left);
153   int forward = 1;
154   // TAKEN OUT : BB 12/11 : Mouse position should not have
155   // an effect on whether the mouse ring goes forwards or
156   // backwards.
157   // forward = (dx > ((block->rect.right - block->rect.left) / 2));
158   //
159   /*  register CButMode *I=block->G->ButMode; */
160   if(button == P_GLUT_BUTTON_SCROLL_BACKWARD || button == P_GLUT_RIGHT_BUTTON)
161     forward = !forward;
162   if(mod == cOrthoSHIFT)
163     forward = !forward;
164   if(dy < 2) {
165     if(ButModeTranslate(m_G, P_GLUT_SINGLE_LEFT, 0) != cButModePickAtom) {
166       if(!forward) {
167         PLog(m_G, "cmd.mouse('select_backward')", cPLog_pym);
168         OrthoCommandIn(m_G, "mouse select_backward,quiet=1");
169       } else {
170         PLog(m_G, "cmd.mouse('select_forward')", cPLog_pym);
171         OrthoCommandIn(m_G, "mouse select_forward,quiet=1");
172       }
173     }
174   } else {
175     if(button == P_GLUT_RIGHT_BUTTON) {
176       MenuActivate0Arg(m_G,x,y,x,y,false,"mouse_config");
177     } else {
178       if(!forward) {
179         PLog(m_G, "cmd.mouse('backward')", cPLog_pym);
180         OrthoCommandIn(m_G, "mouse backward,quiet=1");
181       } else {
182         PLog(m_G, "cmd.mouse('forward')", cPLog_pym);
183         OrthoCommandIn(m_G, "mouse forward,quiet=1");
184       }
185     }
186   }
187   return (1);
188 }
189 
190 static bool ButModeDrawFastImpl(Block * block, short definitely ORTHOCGOARG);
191 /*========================================================================*/
draw(CGO * orthoCGO)192 void CButMode::draw(CGO* orthoCGO)
193 {
194   int x, y, a;
195   int mode;
196   const float *textColor = TextColor;
197   const float *textColor2 = TextColor2;
198   CButMode *I = this; // TODO: Remove during ButMode refactor
199 #define BLANK_STR "     "
200 
201   if(m_G->HaveGUI && m_G->ValidContext && ((rect.right - rect.left) > 6)) {
202     if(SettingGetGlobal_b(m_G, cSetting_internal_gui_mode) == 0) {
203       if (orthoCGO)
204 	CGOColorv(orthoCGO, BackColor);
205 #ifndef PURE_OPENGL_ES_2
206       else
207 	glColor3fv(BackColor);
208 #endif
209       fill(orthoCGO);
210       drawLeftEdge(orthoCGO);
211     } else {
212       drawLeftEdge(orthoCGO);
213       if (orthoCGO)
214 	CGOColor(orthoCGO, .5f, .5f, .5f);
215 #ifndef PURE_OPENGL_ES_2
216       else
217 	glColor3f(0.5, 0.5, 0.5);
218 #endif
219       drawTopEdge();
220       textColor2 = OrthoGetOverlayColor(m_G);
221       textColor = textColor2;
222     }
223 
224     x = rect.left + cButModeLeftMargin;
225     y = (rect.top - cButModeLineHeight) - cButModeTopMargin;
226 
227     TextSetColor(m_G, textColor);
228     TextDrawStrAt(m_G, "Mouse Mode ", x + 1, y ORTHOCGOARGVAR);
229     TextSetColor(m_G, TextColor3);
230     TextDrawStrAt(m_G, SettingGetGlobal_s(m_G, cSetting_button_mode_name), x + DIP2PIXEL(88), y ORTHOCGOARGVAR);
231     /*    TextDrawStrAt(m_G,"2-Bttn Selecting",x+88,y); */
232     y -= cButModeLineHeight;
233 
234     if(SettingGetGlobal_b(m_G, cSetting_mouse_grid)) {
235 
236       TextSetColor(m_G, TextColor3);
237       TextDrawStrAt(m_G, "Buttons", x + DIP2PIXEL(6), y ORTHOCGOARGVAR);
238       TextSetColor(m_G, TextColor1);
239       /*    TextDrawStrAt(m_G,"  Left Mddl Rght Scrl",x+48,y); */
240       TextDrawStrAt(m_G, "    L    M    R  Wheel", x + DIP2PIXEL(43), y ORTHOCGOARGVAR);
241 
242       y -= cButModeLineHeight;
243       /*    glColor3fv(I->Block->TextColor);
244          TextDrawStrAt(m_G,"K",x,y-4); */
245       TextSetColor(m_G, TextColor3);
246       TextDrawStrAt(m_G, "&", x + DIP2PIXEL(12), y ORTHOCGOARGVAR);
247       TextDrawStrAt(m_G, "Keys", x + DIP2PIXEL(24), y ORTHOCGOARGVAR);
248       TextSetColor(m_G, textColor2);
249 
250       TextSetPos2i(m_G, x + DIP2PIXEL(64), y);
251       for(a = 0; a < 3; a++) {
252         mode = Mode[a];
253         if(mode < 0)
254           TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
255         else
256           TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
257       }
258       mode = Mode[12];
259       if(mode < 0)
260         TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
261       else
262         TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
263 
264       y -= cButModeLineHeight;
265       /*    TextSetColor(m_G,I->Block->TextColor);
266          TextDrawStrAt(m_G,"e",x+5,y-1); */
267       TextSetColor(m_G, TextColor1);
268 
269       TextSetColor(m_G, TextColor1);
270       TextDrawStrAt(m_G, "Shft ", x + DIP2PIXEL(24), y ORTHOCGOARGVAR);
271       TextSetColor(m_G, textColor2);
272       TextSetPos2i(m_G, x + DIP2PIXEL(64), y);
273       for(a = 3; a < 6; a++) {
274         mode = I->Mode[a];
275         if(mode < 0)
276           TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
277         else
278           TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
279       }
280       mode = Mode[13];
281       if(mode < 0)
282         TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
283       else
284         TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
285 
286       y -= cButModeLineHeight;
287       /*    glColor3fv(I->Block->TextColor);
288          TextDrawStrAt(m_G,"y",x+10,y+2); */
289       TextSetColor(m_G, TextColor1);
290       TextDrawStrAt(m_G, "Ctrl ", x + DIP2PIXEL(24), y ORTHOCGOARGVAR);
291       TextSetColor(m_G, textColor2);
292       TextSetPos2i(m_G, x + DIP2PIXEL(64), y);
293       for(a = 6; a < 9; a++) {
294         mode = I->Mode[a];
295         if(mode < 0)
296           TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
297         else
298           TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
299       }
300       mode = I->Mode[14];
301       if(mode < 0)
302         TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
303       else
304         TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
305       y -= cButModeLineHeight;
306 
307       /*    glColor3fv(I->Block->TextColor);
308          TextDrawStrAt(m_G,"s",x+15,y+3); */
309       TextSetColor(m_G, TextColor1);
310       TextSetColor(m_G, TextColor1);
311       TextDrawStrAt(m_G, "CtSh ", x + DIP2PIXEL(24), y ORTHOCGOARGVAR);
312       TextSetColor(m_G, textColor2);
313       TextSetPos2i(m_G, x + DIP2PIXEL(64), y);
314       for(a = 9; a < 12; a++) {
315         mode = Mode[a];
316         if(mode < 0)
317           TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
318         else
319           TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
320       }
321       mode = Mode[15];
322       if(mode < 0)
323         TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
324       else
325         TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
326 
327       y -= cButModeLineHeight;
328 
329       TextSetColor(m_G, TextColor);
330       TextSetColor(m_G, TextColor1);
331       TextDrawStrAt(m_G, " SnglClk", x - DIP2PIXEL(8), y ORTHOCGOARGVAR);
332       TextSetColor(m_G, textColor2);
333       TextSetPos2i(m_G, x + DIP2PIXEL(64), y);
334       for(a = 19; a < 22; a++) {
335         mode = Mode[a];
336         if(mode < 0)
337           TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
338         else
339           TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
340       }
341       TextSetColor(m_G, TextColor);
342       y -= cButModeLineHeight;
343 
344       TextSetColor(m_G, TextColor);
345       TextSetColor(m_G, TextColor1);
346       TextDrawStrAt(m_G, " DblClk", x, y ORTHOCGOARGVAR);
347       TextSetColor(m_G, textColor2);
348       TextSetPos2i(m_G, x + DIP2PIXEL(64), y);
349       for(a = 16; a < 19; a++) {
350         mode = I->Mode[a];
351         if(mode < 0)
352           TextDrawStr(m_G, BLANK_STR ORTHOCGOARGVAR);
353         else
354           TextDrawStr(m_G, Code[mode] ORTHOCGOARGVAR);
355       }
356       TextSetColor(m_G, TextColor);
357       y -= cButModeLineHeight;
358 
359     }
360 
361     {
362       TextSetColor(m_G, textColor);
363       if(ButModeTranslate(m_G, P_GLUT_SINGLE_LEFT, 0) == cButModePickAtom) {
364         TextDrawStrAt(m_G, "Picking ", x, y ORTHOCGOARGVAR);
365         TextSetColor(m_G, TextColor3);
366         TextDrawStrAt(m_G, "Atoms (and Joints)", x + DIP2PIXEL(64), y ORTHOCGOARGVAR);
367       } else {
368         TextDrawStrAt(m_G, "Selecting ", x, y ORTHOCGOARGVAR);
369         TextSetColor(m_G, TextColor3);
370         switch (SettingGetGlobal_i(m_G, cSetting_mouse_selection_mode)) {
371         case 0:
372           TextDrawStrAt(m_G, "Atoms", x + DIP2PIXEL(80), y ORTHOCGOARGVAR);
373           break;
374         case 1:
375           TextDrawStrAt(m_G, "Residues", x + DIP2PIXEL(80), y ORTHOCGOARGVAR);
376           break;
377         case 2:
378           TextDrawStrAt(m_G, "Chains", x + DIP2PIXEL(80), y ORTHOCGOARGVAR);
379           break;
380         case 3:
381           TextDrawStrAt(m_G, "Segments", x + DIP2PIXEL(80), y ORTHOCGOARGVAR);
382           break;
383         case 4:
384           TextDrawStrAt(m_G, "Objects", x + DIP2PIXEL(80), y ORTHOCGOARGVAR);
385           break;
386         case 5:
387           TextDrawStrAt(m_G, "Molecules", x + DIP2PIXEL(80), y ORTHOCGOARGVAR);
388           break;
389         case 6:
390           TextDrawStrAt(m_G, "C-alphas", x + DIP2PIXEL(80), y ORTHOCGOARGVAR);
391           break;
392         }
393       }
394     }
395   }
396   if (!ORTHOCGOARGB || !(SettingGetGlobal_b(m_G, cSetting_show_frame_rate) || MoviePlaying(m_G))) {
397     ButModeDrawFastImpl(this, true ORTHOCGOARGVAR);
398   }
399 }
400 
fastDraw(CGO * orthoCGO)401 bool CButMode::fastDraw(CGO* orthoCGO){
402   return ButModeDrawFastImpl(this, false, orthoCGO);
403 }
404 
ButModeDrawFastImpl(Block * block,short definitely ORTHOCGOARG)405 static bool ButModeDrawFastImpl(Block * block, short definitely ORTHOCGOARG)
406 {
407   PyMOLGlobals *G = block->m_G;
408   CButMode *I = block->m_G->ButMode;
409   int x, y;
410   float *textColor = I->TextColor;
411   float *textColor2 = I->TextColor2;
412 
413   if (!definitely && (!(SettingGetGlobal_b(G, cSetting_show_frame_rate) || MoviePlaying(G)))) {
414     return false;
415   }
416 
417   x = I->rect.left + cButModeLeftMargin;
418   y = I->rect.bottom + cButModeLineHeight + cButModeBottomMargin;
419 
420   TextSetColor(G, I->TextColor);
421   y -= cButModeLineHeight;
422 #ifndef PURE_OPENGL_ES_2
423     {
424         int buffer;
425         /* TODO : Why do we only do this for the back right buffer,
426          for performance? */
427         glGetIntegerv(GL_DRAW_BUFFER, (GLint *) & buffer);
428         if(buffer != GL_BACK_RIGHT) {
429 #else
430     {
431         {
432 #endif
433             if(I->Delay <= 0.0F) {
434                 if(I->Samples > 0.0F)
435                     I->RateShown = (I->Rate / I->Samples);
436                 else
437                     I->RateShown = 0.0F;
438                 I->Delay = 0.2F;
439             }
440         }
441     }
442 
443   {
444     int has_movie = false;
445     int frame_rate = SettingGetGlobal_b(G, cSetting_show_frame_rate);
446     int nf;
447     char rateStr[255];
448     nf = SceneGetNFrame(G, &has_movie);
449     if(nf == 0)
450       nf = 1;
451     TextSetColor(G, textColor);
452     if(has_movie) {
453       TextDrawStrAt(G, "Frame ", x, y ORTHOCGOARGVAR);
454     } else {
455       TextDrawStrAt(G, "State ", x, y ORTHOCGOARGVAR);
456     }
457     TextSetColor(G, textColor2);
458     sprintf(rateStr, "%4d/%4d ", SceneGetFrame(G) + 1, nf);
459     TextDrawStrAt(G, rateStr, x + DIP2PIXEL(48), y ORTHOCGOARGVAR);
460     if(frame_rate) {
461       sprintf(rateStr,"%5.1f",I->RateShown);
462       TextDrawStrAt(G, rateStr, x + DIP2PIXEL(144), y ORTHOCGOARGVAR);
463       TextSetColor(G, textColor);
464       TextDrawStrAt(G, "Hz ", x + DIP2PIXEL(192), y ORTHOCGOARGVAR);
465       TextSetColor(G, textColor2);
466     } else if(has_movie) {
467       TextSetColor(G, textColor);
468       TextDrawStrAt(G, "State ", x + DIP2PIXEL(128), y ORTHOCGOARGVAR);
469       TextSetColor(G, textColor2);
470       sprintf(rateStr," %4d",SceneGetState(G)+1);
471       TextDrawStrAt(G, rateStr, x + DIP2PIXEL(168), y ORTHOCGOARGVAR);
472     } else if(frame_rate) {
473     }
474   }
475   return true;
476 }
477 
478 
479 /*========================================================================*/
480 int ButModeInit(PyMOLGlobals * G)
481 {
482   CButMode *I = NULL;
483   if((I = (G->ButMode = new CButMode(G)))) {
484 
485     int a;
486 
487     I->Rate = 0.0;
488     I->Samples = 0.0;
489     I->RateShown = 0.0;
490     I->Delay = 0.0;
491     I->DeferCnt = 0;
492     I->DeferTime = 0.0F;
493     I->NCode = cButModeCount;
494     I->NBut = cButModeInputCount;
495 
496     for(a = 0; a < I->NBut; a++) {
497       I->Mode[a] = -1;
498     }
499 
500     strcpy(I->Code[cButModeRotXYZ], "Rota ");
501     strcpy(I->Code[cButModeRotZ], "RotZ ");
502     strcpy(I->Code[cButModeTransXY], "Move ");
503     strcpy(I->Code[cButModeTransZ], "MovZ ");
504     strcpy(I->Code[cButModeClipNF], "Clip ");
505     strcpy(I->Code[cButModeClipN], "ClpN ");
506     strcpy(I->Code[cButModeClipF], "ClpF ");
507     strcpy(I->Code[cButModePickAtom], "PkAt ");
508     strcpy(I->Code[cButModePickBond], "PkBd ");
509     strcpy(I->Code[cButModeTorFrag], "TorF ");
510     strcpy(I->Code[cButModeRotFrag], "RotF ");
511     strcpy(I->Code[cButModeMovFrag], "MovF ");
512     strcpy(I->Code[cButModeLB], " lb  ");
513     strcpy(I->Code[cButModeMB], " mb  ");
514     strcpy(I->Code[cButModeRB], " rb  ");
515     strcpy(I->Code[cButModeAddToLB], "+lb  ");
516     strcpy(I->Code[cButModeAddToMB], "+mb  ");
517     strcpy(I->Code[cButModeAddToRB], "+rb  ");
518     strcpy(I->Code[cButModeOrigAt], "Orig ");
519     strcpy(I->Code[cButModeRectAdd], "+lBx ");
520     strcpy(I->Code[cButModeRectSub], "-lBx ");
521     strcpy(I->Code[cButModeRect], "lbBx ");
522     strcpy(I->Code[cButModeNone], "  -  ");
523     strcpy(I->Code[cButModeCent], "Cent ");
524     strcpy(I->Code[cButModePkTorBnd], "PkTB ");
525     strcpy(I->Code[cButModeScaleSlab], "Slab ");
526     strcpy(I->Code[cButModeMoveSlab], "MovS ");
527     strcpy(I->Code[cButModePickAtom1], "Pk1  ");
528     strcpy(I->Code[cButModeMoveAtom], "MovA ");
529     strcpy(I->Code[cButModeMenu], "Menu ");
530     strcpy(I->Code[cButModeSeleSet], "Sele ");
531     strcpy(I->Code[cButModeSeleToggle], "+/-  ");
532     strcpy(I->Code[cButModeSeleAddBox], "+Box ");
533     strcpy(I->Code[cButModeSeleSubBox], "-Box ");
534     strcpy(I->Code[cButModeMoveSlabAndZoom], "MvSZ ");
535     strcpy(I->Code[cButModeSimpleClick], "Clik ");
536     strcpy(I->Code[cButModeRotDrag], "RotD ");
537     strcpy(I->Code[cButModeMovDrag], "MovD ");
538     strcpy(I->Code[cButModeMovDragZ], "MvDZ ");
539     strcpy(I->Code[cButModeRotObj], "RotO ");
540     strcpy(I->Code[cButModeMovObj], "MovO ");
541     strcpy(I->Code[cButModeMovObjZ], "MvOZ ");
542     strcpy(I->Code[cButModeMovFragZ], "MvFZ ");
543     strcpy(I->Code[cButModeMoveAtomZ], "MvAZ ");
544     strcpy(I->Code[cButModeDragMol], "DrgM ");
545     strcpy(I->Code[cButModeRotView], "RotV ");
546     strcpy(I->Code[cButModeMovView], "MovV ");
547     strcpy(I->Code[cButModeMovViewZ], "MvVZ ");
548     strcpy(I->Code[cButModeDragObj], "DrgO ");
549     strcpy(I->Code[cButModeInvMoveSlabAndZoom], "IMSZ ");
550     strcpy(I->Code[cButModeInvTransZ], "IMvZ ");
551     strcpy(I->Code[cButModeSeleSetBox], " Box ");
552     strcpy(I->Code[cButModeInvRotZ], "IRtZ ");
553     strcpy(I->Code[cButModeRotL], "RotL " );
554     strcpy(I->Code[cButModeMovL], "MovL " );
555     strcpy(I->Code[cButModeMvzL], "MvzL " );
556 
557     I->active = true;
558 
559     I->TextColor[0] = 0.2F;
560     I->TextColor[1] = 1.0F;
561     I->TextColor[2] = 0.2F;
562 
563     I->TextColor1[0] = 0.5F;
564     I->TextColor1[1] = 0.5F;
565     I->TextColor1[2] = 1.0F;
566 
567     I->TextColor2[0] = 0.8F;
568     I->TextColor2[1] = 0.8F;
569     I->TextColor2[2] = 0.8F;
570 
571     I->TextColor3[0] = 1.0F;
572     I->TextColor3[1] = 0.5F;
573     I->TextColor3[2] = 0.5F;
574 
575     OrthoAttach(G, I, cOrthoTool);
576     return 1;
577   } else
578     return 0;
579 }
580 
581 
582 /*========================================================================*/
583 int ButModeCheckPossibleSingleClick(PyMOLGlobals * G, int button, int mod)
584 {
585   int click_button = -1;
586   switch (button) {
587   case P_GLUT_LEFT_BUTTON:
588     click_button = P_GLUT_SINGLE_LEFT;
589     break;
590   case P_GLUT_MIDDLE_BUTTON:
591     click_button = P_GLUT_SINGLE_MIDDLE;
592     break;
593   case P_GLUT_RIGHT_BUTTON:
594     click_button = P_GLUT_SINGLE_RIGHT;
595     break;
596   }
597   if(click_button < 0)
598     return false;
599   else
600     return (ButModeTranslate(G, click_button, mod) >= 0);
601 }
602 
603 int ButModeTranslate(PyMOLGlobals * G, int button, int mod)
604 {
605   int mode = cButModeNothing;
606   CButMode *I = G->ButMode;
607   switch (button) {
608   case P_GLUT_LEFT_BUTTON:
609     mode = 0;
610     break;
611   case P_GLUT_MIDDLE_BUTTON:
612     mode = 1;
613     break;
614   case P_GLUT_RIGHT_BUTTON:
615     mode = 2;
616     break;
617   case P_GLUT_BUTTON_SCROLL_FORWARD:
618   case P_GLUT_BUTTON_SCROLL_BACKWARD:
619     switch (mod) {
620     case 0:
621       mode = 12;
622       break;
623     case cOrthoSHIFT:
624       mode = 13;
625       break;
626     case cOrthoCTRL:
627       mode = 14;
628       break;
629     case (cOrthoCTRL + cOrthoSHIFT):
630       mode = 15;
631     }
632     mod = 0;
633     switch (I->Mode[mode]) {
634     case cButModeScaleSlab:
635       if(button == P_GLUT_BUTTON_SCROLL_FORWARD) {
636         return cButModeScaleSlabExpand;
637       } else {
638         return cButModeScaleSlabShrink;
639       }
640       break;
641     case cButModeMoveSlab:
642       if(button == P_GLUT_BUTTON_SCROLL_FORWARD) {
643         return cButModeMoveSlabForward;
644       } else {
645         return cButModeMoveSlabBackward;
646       }
647       break;
648     case cButModeMoveSlabAndZoom:
649       if(button == P_GLUT_BUTTON_SCROLL_FORWARD) {
650         return cButModeMoveSlabAndZoomForward;
651       } else {
652         return cButModeMoveSlabAndZoomBackward;
653       }
654       break;
655     case cButModeInvMoveSlabAndZoom:
656       if(button != P_GLUT_BUTTON_SCROLL_FORWARD) {
657         return cButModeMoveSlabAndZoomForward;
658       } else {
659         return cButModeMoveSlabAndZoomBackward;
660       }
661       break;
662     case cButModeTransZ:
663       if(button == P_GLUT_BUTTON_SCROLL_FORWARD) {
664         return cButModeZoomForward;
665       } else {
666         return cButModeZoomBackward;
667       }
668       break;
669     case cButModeInvTransZ:
670       if(button != P_GLUT_BUTTON_SCROLL_FORWARD) {
671         return cButModeZoomForward;
672       } else {
673         return cButModeZoomBackward;
674       }
675       break;
676     }
677     return -1;
678     break;
679   case P_GLUT_DOUBLE_LEFT:
680   case P_GLUT_DOUBLE_MIDDLE:
681   case P_GLUT_DOUBLE_RIGHT:
682   case P_GLUT_SINGLE_LEFT:
683   case P_GLUT_SINGLE_MIDDLE:
684   case P_GLUT_SINGLE_RIGHT:
685     switch (button) {
686     case P_GLUT_DOUBLE_LEFT:
687       mode = 16;
688       break;
689     case P_GLUT_DOUBLE_MIDDLE:
690       mode = 17;
691       break;
692     case P_GLUT_DOUBLE_RIGHT:
693       mode = 18;
694       break;
695     case P_GLUT_SINGLE_LEFT:
696       mode = 19;
697       break;
698     case P_GLUT_SINGLE_MIDDLE:
699       mode = 20;
700       break;
701     case P_GLUT_SINGLE_RIGHT:
702       mode = 21;
703       break;
704     }
705     switch (mod) {
706     case cOrthoSHIFT:
707       mode += 6;
708       break;
709     case cOrthoCTRL:
710       mode += 12;
711       break;
712     case (cOrthoCTRL + cOrthoSHIFT):
713       mode += 18;
714       break;
715     case cOrthoALT:
716       mode += 24;
717       break;
718     case (cOrthoALT + cOrthoSHIFT):
719       mode += 30;
720       break;
721     case (cOrthoALT + cOrthoCTRL):
722       mode += 36;
723       break;
724     case (cOrthoALT + cOrthoCTRL + cOrthoSHIFT):
725       mode += 42;
726       break;
727     }
728     mod = 0;
729     break;
730   }
731   switch (mod) {
732   case 0:
733     break;
734   case cOrthoSHIFT:
735     mode += 3;
736     break;
737   case cOrthoCTRL:
738     mode += 6;
739     break;
740   case (cOrthoCTRL + cOrthoSHIFT):
741     mode += 9;
742     break;
743   case cOrthoALT:
744     mode += 68;
745     break;
746   case (cOrthoALT + cOrthoSHIFT):
747     mode += 71;
748     break;
749   case (cOrthoALT + cOrthoCTRL):
750     mode += 74;
751     break;
752   case (cOrthoALT + cOrthoCTRL + cOrthoSHIFT):
753     mode += 77;
754     break;
755   }
756   return (I->Mode[mode]);
757 }
758