1#A* -------------------------------------------------------------------
2#B* This file contains source code for the PyMOL computer program
3#C* Copyright (c) Schrodinger, LLC.
4#D* -------------------------------------------------------------------
5#E* It is unlawful to modify or remove this copyright notice.
6#F* -------------------------------------------------------------------
7#G* Please see the accompanying LICENSE file for further information.
8#H* -------------------------------------------------------------------
9#I* Additional authors of this source file include:
10#-*
11#-*
12#-*
13#Z* -------------------------------------------------------------------
14
15if True:
16
17    import sys
18    if sys.version_info[0] == 2:
19        import thread
20    else:
21        import _thread as thread
22
23    from . import selector
24    import pymol
25    import re
26    cmd = sys.modules["pymol.cmd"]
27    from .cmd import _cmd,Shortcut, \
28          toggle_dict,toggle_sc, \
29          DEFAULT_ERROR, DEFAULT_SUCCESS, _raising, is_ok, is_error
30
31    def accept(_self=cmd):
32        '''
33
34DESCRIPTION
35
36    "accept" is an internal method for handling of session file
37    security.
38
39        '''
40        r = DEFAULT_ERROR
41        try:
42            _self.lock(_self)
43            r = _cmd.accept(_self._COb)
44            _self.set_wizard()
45        finally:
46            _self.unlock(r,_self)
47        if _self._raising(r,_self): raise pymol.CmdException
48        return r
49
50    def decline(_self=cmd):
51        '''
52DESCRIPTION
53
54    "decline" is an internal method for handling of session file
55    security.
56
57        '''
58        r = DEFAULT_ERROR
59        try:
60            _self.lock(_self)
61            r = _cmd.decline(_self._COb)
62            _self.set_wizard()
63        finally:
64            _self.unlock(r,_self)
65
66    def get_movie_playing(_self=cmd):
67        '''
68DECRIPTION
69
70    "get_movie_playing" returns a boolean value informing the caller
71    as to whether or not the movie is currently playing.
72
73        '''
74        r = DEFAULT_ERROR
75        try:
76            _self.lock(_self)
77            r = _cmd.get_movie_playing(_self._COb)
78        finally:
79            _self.unlock(r,_self)
80        if _self._raising(r,_self): raise pymol.CmdException
81        return r
82
83    def mdump(_self=cmd):
84        '''
85DESCRIPTION
86
87    "mdump" dumps the current set of movie commands as text output.
88
89USAGE
90
91    mdump
92
93SEE ALSO
94
95    mplay, mset, mdo, mclear, mmatrix
96        '''
97        r = DEFAULT_ERROR
98        try:
99            _self.lock(_self)
100            r = _cmd.mdump(_self._COb)
101        finally:
102            _self.unlock(r,_self)
103        if _self._raising(r,_self): raise pymol.CmdException
104        return r
105
106    def mtoggle(_self=cmd):
107        '''
108DESCRIPTION
109
110    "mtoggle" toggles playing of the movie.
111
112    '''
113        r = DEFAULT_ERROR
114        try:
115            _self.lock(_self)
116            r = _cmd.mplay(_self._COb,-1)
117        finally:
118            _self.unlock(r,_self)
119        if _self._raising(r,_self): raise pymol.CmdException
120        return r
121
122
123    def mstop(_self=cmd):
124        '''
125DESCRIPTION
126
127    "mstop" stops playing of the movie.
128
129USAGE
130
131    mstop
132
133SEE ALSO
134
135    mplay, mset, mdo, mclear, mmatrix
136        '''
137        r = DEFAULT_ERROR
138        try:
139            _self.lock(_self)
140            r = _cmd.mplay(_self._COb,0)
141        finally:
142            _self.unlock(r,_self)
143        if _self._raising(r,_self): raise pymol.CmdException
144        return r
145
146
147    mview_action_dict = {
148        'store'       : 0,
149        'clear'       : 1,
150        'interpolate' : 2,
151        'reinterpolate' : 3,
152        'smooth'   : 4,
153        'reset'    : 5,
154        'uninterpolate' : 6,
155        'toggle'    : 7,
156        'toggle_interp' : 8,
157        'purge'      : 9
158        }
159
160    mview_action_sc = Shortcut(mview_action_dict.keys())
161
162    def mview(action='store', first=0, last=0, power=0.0,
163              bias=-1.0, simple=-1, linear=0.0, object='',
164              wrap=-1, hand=0, window=5, cycles=1, scene='',
165              cut=0.5, quiet=1, auto=-1, state=0, freeze=0,
166              _self=cmd):
167
168        '''
169DESCRIPTION
170
171    "mview" stores camera and object matrices for use in movie
172    interpolation.
173
174USAGE
175
176    mview [action [, first [, last [, power [, bias [, simple
177       [, linear [, object [, wrap [, hand [, window [, cycles [,scene
178       [, cut [, quiet ]]]]]]]]]]]]]]]
179
180ARGUMENTS
181
182    action = str: one of store, clear, reset, purge, interpolate,
183    uninterpolate, reinterpolate, toggle, toggle_interp, smooth
184    {default: store}
185
186    first = int: frame number or 0 for current frame {default: 0}
187
188    power = float: slow down animation at keyframe (0.0) or not (1.0)
189    {default: 0.0}
190
191    object = str: name of object for object keyframes, or empty for
192    global (camera) keyframes {default: }
193
194    scene = str: name of scene to store scene with key frame {default: }
195
196    cut = float 0.0-1.0: scene switch moment (0.0: beginning of transition,
197    1.0: end of transition) {default: 0.5}
198
199    auto = -1/0/1: if freeze=0, then auto reinterpolate after store, clear,
200    or toggle {default: -1 = use movie_auto_interpolate}
201
202    state = int: if > 0, then store object state {default: 0}
203
204    freeze = 0/1: never auto reinterpolate {default: 0}
205
206SEE ALSO
207
208    mplay, mset, mdo, mclear, mmatrix
209        '''
210
211        r = DEFAULT_ERROR
212        first = int(first)
213        last = int(last)
214        auto = int(auto)
215        freeze = int(freeze)
216        if first<0:
217            first = _self.count_frames() + first + 1
218            if last == 0:
219                last = _self.count_frames()
220        if last<0:
221            last = _self.count_frames() + last + 1
222        action = mview_action_dict[mview_action_sc.auto_err(action,'action')]
223        if (scene is None) or (scene=='auto'):
224            scene = _self.get("scene_current_name")
225        scene = str(scene)
226        if (scene!=''):
227            _self.scene(scene,"recall","",animate=0,frame=0)
228        try:
229            _self.lock(_self)
230            r = _cmd.mview(_self._COb,int(action),int(first)-1,int(last)-1,
231                           float(power),float(bias),
232                           int(simple), float(linear),str(object),
233                           int(wrap),int(hand),int(window),int(cycles),
234                           str(scene),float(cut),int(quiet),int(state)-1,0)
235            if (not freeze and
236                ((auto>0) or ((auto<0) and
237                              (_self.get_setting_int("movie_auto_interpolate")>0)))):
238                if action in [0,1,7]: # reinterpolate after store, clear, or toggle
239                    _cmd.mview(_self._COb,3,-1,-1,
240                               float(power),float(bias),
241                               int(simple), float(linear),str(object),
242                               int(wrap),int(hand),int(window),int(cycles),
243                               str(scene),float(cut),int(quiet),-1,1)
244        finally:
245            _self.unlock(r,_self)
246        if _self._raising(r,_self): raise pymol.CmdException
247        return r
248
249    def mplay(_self=cmd):
250        '''
251DESCRIPTION
252
253    "mplay" starts the movie.
254
255USAGE
256
257    mplay
258
259PYMOL API
260
261    cmd.mplay()
262
263SEE ALSO
264
265    mstop, mset, mdo, mclear, mmatrix
266        '''
267        r = DEFAULT_ERROR
268        try:
269            _self.lock(_self)
270            r = _cmd.mplay(_self._COb,1)
271        finally:
272            _self.unlock(r,_self)
273        if _self._raising(r,_self): raise pymol.CmdException
274        return r
275
276    def mdo(frame,command,_self=cmd):
277        '''
278DESCRIPTION
279
280    "mdo" defines (or redefines) the command-line operations
281    associated with a particular movie frame.  These "generalized
282    movie commands" will be executed every time the numbered frame is
283    played.
284
285USAGE
286
287    mdo frame: command
288
289PYMOL API
290
291    cmd.mdo( int frame, string command )
292
293EXAMPLE
294
295    // Creates a single frame movie involving a rotation about X and Y
296
297    load test.pdb
298    mset 1
299    mdo 1, turn x,5; turn y,5;
300    mplay
301
302NOTES
303
304 These commands are usually created
305    by a PyMOL utility program (such as movie.rock).  Command can
306    actually contain several commands separated by semicolons ';'
307
308    The "mset" command must first be used to define the movie before
309    "mdo" statements will have any effect.  Redefinition of the movie
310    clears any existing mdo statements.
311
312SEE ALSO
313
314    mset, mplay, mstop
315        '''
316        r = DEFAULT_ERROR
317        try:
318            _self.lock(_self)
319            r = _cmd.mdo(_self._COb,int(frame)-1,str(command),0)
320        finally:
321            _self.unlock(r,_self)
322        if _self._raising(r,_self): raise pymol.CmdException
323        return r
324
325    def mappend(frame,command,_self=cmd):
326        '''
327DESCRIPTION
328
329    "mappend" associates additional command line operations with a
330    particular movie frame.  These "generalized movie commands" will
331    be executed every time the numbered frame is played.
332
333USAGE
334
335    mappend frame: command
336
337ARGUMENTS
338
339    frame = integer: the frame to modify
340
341    command = literal command-line text
342
343EXAMPLE
344
345    mappend 1: hide everything; show sticks
346    mappend 60: hide sticks; show spheres
347    mappend 120: hide spheres; show surface
348
349NOTES
350
351    The "mset" command must first be used to define the movie before
352    "mdo" statements will have any effect.  Redefinition of the movie
353    clears any existing movie commands specified with mdo or mappend.
354
355SEE ALSO
356
357    mset, madd, mdo, mplay, mstop
358        '''
359        r = DEFAULT_ERROR
360        try:
361            _self.lock(_self)
362            r = _cmd.mdo(_self._COb,int(frame)-1,str(";"+command),1)
363        finally:
364            _self.unlock(r,_self)
365        if _self._raising(r,_self): raise pymol.CmdException
366        return r
367
368    def mpng(prefix,first=0,last=0,preserve=0,modal=0,
369             mode=-1, quiet=1,
370             width=0, height=0,
371             _self=cmd):
372        '''
373DESCRIPTION
374
375    "mpng" writes movie frames as a series of numbered png files.
376
377USAGE
378
379    mpng prefix [, first [, last [, preserve [, modal [, mode [, quiet
380        [, width [, height ]]]]]]]]
381
382ARGUMENTS
383
384    prefix = string: filename prefix for saved images -- output files
385    will be numbered and end in ".png"
386
387    first = integer: starting frame {default: 0 (first frame)}
388
389    last = integer: last frame {default: 0 (last frame)}
390
391    preserve = 0/1: Only write non-existing files {default: 0}
392
393    modal = integer: will frames be rendered with a modal draw loop
394
395    mode = int: 2=ray, 1=draw, 0=normal {default: -1, check
396    ray_trace_frames or draw_frames}
397
398    width = int: width in pixels {default: current viewport}
399
400    height = int: height in pixels {default: current viewport}
401
402NOTES
403
404    If the "ray_trace_frames" variable is non-zero, then the frames
405    will be ray-traced.  Note that this can take many hours for a long
406    movie with complex content displayed.
407
408    Also, be sure to avoid setting "cache_frames" when rendering a
409    long movie to avoid running out of memory.
410
411    Arguments "first" and "last" can be used to specify an inclusive
412    interval over which to render frames.  Thus, you can write a smart
413    Python program that will automatically distribute rendering over a
414    cluster of workstations.  If these options are left at zero, then
415    the entire movie will be rendered.
416
417PYMOL API
418
419    cmd.mpng(string prefix, int first, int last)
420
421SEE ALSO
422
423    png, save
424
425        '''
426        r = DEFAULT_ERROR
427        args = (prefix, int(first) - 1, int(last) - 1,
428                int(preserve), int(modal), -1, int(mode), int(quiet),
429                int(width), int(height))
430
431        if _self.is_gui_thread():
432            r = _self._mpng(*args)
433        else:
434            r = _self.do('cmd._mpng(*%s)' % repr(args), 0)
435        if _self._raising(r,_self): raise pymol.CmdException
436        return r
437
438    def mclear(_self=cmd):
439        '''
440DESCRIPTION
441
442    "mclear" clears the movie frame image cache.
443
444USAGE
445
446    mclear
447
448PYMOL API
449
450    cmd.mclear()
451        '''
452        r = DEFAULT_ERROR
453        try:
454            _self.lock(_self)
455            r = _cmd.mclear(_self._COb)
456        finally:
457            _self.unlock(r,_self)
458        if _self._raising(r,_self): raise pymol.CmdException
459        return r
460
461
462    def frame(frame,trigger=-1,scene=0,_self=cmd):
463        '''
464DESCRIPTION
465
466    "frame" sets the viewer to the indicated movie frame.
467
468USAGE
469
470    frame frame
471
472ARGUMENTS
473
474    frame = integer: frame number to display
475
476EXAMPLE
477
478    frame 10
479
480PYMOL API
481
482    cmd.frame( int frame_number )
483
484NOTES
485
486    Frame numbers are 1-based.
487
488SEE ALSO
489
490    count_states
491        '''
492        with _self.lockcm:
493            return _cmd.frame(_self._COb, int(frame) - 1, int(trigger))
494
495    def mmove(target,source=0,count=-1,freeze=0,object='',quiet=1,_self=cmd):
496        '''
497DESCRIPTION
498
499    "mmove" moves key frames and movie commands
500
501ARGUMENTS
502
503    target = int: frame to move to
504
505    source = int: frame to move from, 0 for current frame {default: 0}
506
507    count = int: number of frames to move
508
509SEE ALSO
510
511    mcopy, mdelete, minsert
512
513    '''
514        r = DEFAULT_ERROR
515        count = int(count)
516        source = int(source)
517        target = int(target)
518        freeze = int(freeze)
519        object = str(object)
520        quiet = int(quiet)
521        cur_len = _self.count_frames()
522        if not source: # 0 means use current frame
523            source = _self.get_frame() - 1
524        elif source<0:
525            source = _self.count_sources() + 1 + source
526            if (count>0) and (source + count) > cur_len:
527                source = cur_len - count
528        else:
529            source -= 1
530        if not target: # 0 means use current frame
531            target = _self.get_frame() - 1
532        elif target<0:
533            target = _self.count_targets() + 1 + target
534            if (count>0) and (target + count) > cur_len:
535                target = cur_len - count
536        else:
537            target -= 1
538        try:
539            _self.lock(_self)
540            r = _cmd.mmodify(_self._COb,2,source,count,
541                             target,object,freeze,quiet)
542        finally:
543            _self.unlock(r,_self)
544        if _self._raising(r,_self): raise pymol.CmdException
545        return r
546
547    def mcopy(target,source=0,count=-1,freeze=0,object='',quiet=1,_self=cmd):
548        '''
549DESCRIPTION
550
551    "mcopy" copies key frames and movie commands
552
553    Usage like "mmove".
554
555SEE ALSO
556
557    mmove, mdelete, minsert
558
559    '''
560        r = DEFAULT_ERROR
561        count = int(count)
562        source = int(source)
563        target = int(target)
564        freeze = int(freeze)
565        object = str(object)
566        quiet = int(quiet)
567        cur_len = _self.count_frames()
568        if not source: # 0 means use current frame
569            source = _self.get_frame() - 1
570        elif source<0:
571            source = _self.count_sources() + 1 + source
572            if (count>0) and (source + count) > cur_len:
573                source = cur_len - count
574        else:
575            source -= 1
576        if not target: # 0 means use current frame
577            target = _self.get_frame() - 1
578        elif target<0:
579            target = _self.count_targets() + 1 + target
580            if (count>0) and (target + count) > cur_len:
581                target = cur_len - count
582        else:
583            target -= 1
584        try:
585            _self.lock(_self)
586            r = _cmd.mmodify(_self._COb,3,source,count,
587                             target,object,freeze,quiet)
588        finally:
589            _self.unlock(r,_self)
590        if _self._raising(r,_self): raise pymol.CmdException
591        return r
592
593    def mdelete(count=-1,frame=0,freeze=0,object='',quiet=1,_self=cmd):
594        '''
595DESCRIPTION
596
597    "mdelete" removes frames from camera view and object motions.
598
599ARGUMENTS
600
601    count = int: number of frames to delete, or -1 to delete all the way
602    to the end {default: -1}
603
604    frame = int: first frame to delete, or 0 for current frame {default: 0}
605
606EXAMPLE
607
608    # delete frames 81 to 90
609    mdelete 10, 81
610
611SEE ALSO
612
613    minsert, mmove
614
615    '''
616        r = DEFAULT_ERROR
617        count = int(count)
618        frame = int(frame)
619        freeze = int(freeze)
620        object = str(object)
621        quiet = int(quiet)
622        cur_len = _self.count_frames()
623        if not frame: # 0 means use current frame
624            frame = _self.get_frame() - 1
625        elif frame<0:
626            frame = _self.count_frames() + 1 + frame
627            if (count>0) and (frame + count) > cur_len:
628                frame = cur_len - count
629        else:
630            frame -= 1
631        if count < 0: # negative count means delete to end
632            count = 1 + cur_len - frame
633        try:
634            _self.lock(_self)
635            r = _cmd.mmodify(_self._COb,-1,frame,count,
636                             0,object,freeze,quiet)
637        finally:
638            _self.unlock(r,_self)
639        if _self._raising(r,_self): raise pymol.CmdException
640        return r
641
642    def minsert(count,frame=0,freeze=0,object='',quiet=1,_self=cmd):
643        '''
644DESCRIPTION
645
646    "minsert" adds frames into camera view and object motions.
647
648ARGUMENTS
649
650    count = int: number of frames to insert
651
652    frame = int: insert before "frame" if frame > 0, otherwise insert before
653    the current frame {default: 0}
654
655SEE ALSO
656
657    mdelete, mmove, madd
658
659    '''
660        r = DEFAULT_ERROR
661        frame = int(frame)
662        count = int(count)
663        freeze = int(freeze)
664        object = str(object)
665        quiet = int(quiet)
666        if not frame: # 0 means use current frame
667            frame = _self.get_frame() - 1
668        else:
669            frame -= 1
670        try:
671            _self.lock(_self)
672            r = _cmd.mmodify(_self._COb,1,frame,count,
673                             0,object,freeze,quiet)
674        finally:
675            _self.unlock(r,_self)
676        if _self._raising(r,_self): raise pymol.CmdException
677        return r
678
679    def madd(specification="",frame=0,freeze=0,_self=cmd):
680        '''
681DESCRIPTION
682
683    "madd" extends the existing movie specification using the same
684    syntax as mset.
685
686SEE ALSO
687
688    mset, mdo, mplay, mclear
689
690    '''
691        mset(specification,frame,freeze,_self=_self)
692
693    def mset(specification="",frame=1,freeze=0,_self=cmd):
694        '''
695DESCRIPTION
696
697    "mset" sets up a relationship between molecular states and movie
698    frames.  This makes it possible to control which states are shown
699    in which frame.
700
701USAGE
702
703    mset specification [ ,frame ]
704
705PYMOL API
706
707    cmd.mset( string specification [, int frame] )
708
709EXAMPLES
710
711    # simplest case, one state -> one frame
712
713    mset 1
714
715    # ten frames, all corresponding to state 1
716
717    mset 1 x10
718
719    # the first thirty frames are state 1
720    # the next 15 frames pass through states 1-15
721    # the next 30 frames are of state 15
722    # the next 15 frames iterate back to state 1
723
724    mset 1 x30 1 -15 15 x30 15 -1
725
726SEE ALSO
727
728    madd, mdo, mplay, mclear
729        '''
730        r = DEFAULT_ERROR
731        cur_state = _self.get_state()-1 # use the current state
732        specification = str(specification)
733        try:
734            _self.lock(_self)
735            output=[]
736            input = re.sub("\s"," ",specification)
737            input = input.replace("x"," x");
738            input = input.replace("-"," -");
739            input = input.replace("x ","x");
740            input = input.replace("- ","-");
741            input = input.strip().split()
742            last = -1
743            for x in input:
744                if x[0]>"9" or x[0]<"0":
745                    if x[0]=="x":
746                        if last<0:
747                            last = cur_state
748                            cnt = int(x[1:])
749                        else:
750                            cnt = int(x[1:])-1
751                        while cnt>0:
752                            output.append(str(last))
753                            cnt=cnt-1
754                    elif x[0]=="-":
755                        dir=1
756                        cnt=last
757                        last = int(x[1:])-1
758                        if last<cnt:
759                            dir=-1
760                        while cnt!=last:
761                            cnt=cnt+dir
762                            output.append(str(cnt))
763                else:
764                    val = int(x) - 1
765                    output.append(str(val))
766                    last=val
767            r = _cmd.mset(_self._COb, ' '.join(output),int(frame)-1,int(freeze))
768        finally:
769            _self.unlock(r,_self)
770        if _self._raising(r,_self): raise pymol.CmdException
771        return r
772
773
774    def mmatrix(action,_self=cmd):
775        '''
776DESCRIPTION
777
778    "mmatrix" sets up a matrix to be used for the first frame of the movie.
779
780USAGE
781
782    mmatrix action
783
784ARGUMENTS
785
786    action = clear, store, or recall
787
788NOTES
789
790    This command ensures that the movie always starts from the same
791    camera view.
792
793    "mmatrix" should not be used when controlling the camera using
794    "mview".
795
796PYMOL API
797
798    cmd.mmatrix( string action )
799
800EXAMPLES
801
802    mmatrix store
803        '''
804        r = DEFAULT_ERROR
805        try:
806            _self.lock(_self)
807            if action=="clear":
808                r = _cmd.mmatrix(_self._COb,0)
809            elif action=="store":
810                r = _cmd.mmatrix(_self._COb,1)
811            elif action=="recall":
812                r = _cmd.mmatrix(_self._COb,2)
813            elif action=="check":
814                r = _cmd.mmatrix(_self._COb,3)
815        finally:
816            _self.unlock(r,_self)
817        if _self._raising(r,_self): raise pymol.CmdException
818        return r
819
820
821    def forward(_self=cmd):
822        '''
823DESCRIPTION
824
825    "forward" moves the movie one frame forward.
826
827USAGE
828
829    forward
830
831PYMOL API
832
833    cmd.forward()
834
835SEE ALSO
836
837    mset, backward, rewind
838        '''
839        r = DEFAULT_ERROR
840        try:
841            _self.lock(_self)
842            r = _cmd.set_frame(_self._COb,5,1)
843        finally:
844            _self.unlock(r,_self)
845        if _self._raising(r,_self): raise pymol.CmdException
846        return r
847
848    def backward(_self=cmd):
849        '''
850DESCRIPTION
851
852    "backward" moves the movie back one frame.
853
854USAGE
855
856    backward
857
858PYMOL API
859
860    cmd.backward()
861
862SEE ALSO
863
864    mset, forward, rewind
865        '''
866        r = DEFAULT_ERROR
867        try:
868            _self.lock(_self)
869            r = _cmd.set_frame(_self._COb,5,-1)
870        finally:
871            _self.unlock(r,_self)
872        if _self._raising(r,_self): raise pymol.CmdException
873        return r
874
875
876    def rewind(_self=cmd):
877        '''
878DESCRIPTION
879
880    "rewind" goes to the beginning of the movie.
881
882USAGE
883
884    rewind
885
886PYMOL API
887
888    cmd.rewind()
889        '''
890        r = DEFAULT_ERROR
891        try:
892            _self.lock(_self)
893            r = _cmd.set_frame(_self._COb,4,0)
894        finally:
895            _self.unlock(r,_self)
896        if _self._raising(r,_self): raise pymol.CmdException
897        return r
898
899
900    def set_frame(frame=1, mode=0, _self=cmd):
901        '''
902internal
903        '''
904        r = DEFAULT_ERROR
905        try:
906            _self.lock(_self)
907            r=_cmd.set_frame(_self._COb, int(mode), int(frame)-1)
908        finally:
909            _self.unlock(r,_self)
910        if _self._raising(r,_self): raise pymol.CmdException
911        return r
912
913    def ending(_self=cmd):
914        '''
915DESCRIPTION
916
917    "ending" goes to the end of the movie.
918
919USAGE
920
921    ending
922
923PYMOL API
924
925    cmd.ending()
926        '''
927        r = DEFAULT_ERROR
928        try:
929            _self.lock(_self)
930            r=_cmd.set_frame(_self._COb,6,0)
931        finally:
932            _self.unlock(r,_self)
933        if _self._raising(r,_self): raise pymol.CmdException
934        return r
935
936    def middle(_self=cmd):
937        '''
938DESCRIPTION
939
940    "middle" goes to the middle of the movie.
941
942USAGE
943
944    middle
945
946PYMOL API
947
948    cmd.middle()
949        '''
950        r = DEFAULT_ERROR
951        try:
952            _self.lock(_self)
953            r = _cmd.set_frame(_self._COb,3,0)
954        finally:
955            _self.unlock(r,_self)
956        if _self._raising(r,_self): raise pymol.CmdException
957        return r
958
959
960    def get_state(_self=cmd):
961        '''
962DESCRIPTION
963
964    "get_state" returns the current state index (1-based)
965
966PYMOL API
967
968    cmd.get_state()
969
970NOTES
971
972    States refer to different geometric configurations which an object
973    can above.  By default, states and movie frames have a one-to-one
974    relationship.  States can be visited in an arbitrary order to
975    create frames.  The "mset" command allows you to build a
976    relationship between states and frames.
977
978SEE ALSO
979
980    get_frame
981        '''
982        # NOTE: NO LOCKS...this is/can be called from cmd.refresh()
983        r = _cmd.get_state(_self._COb)+1
984        return r
985
986    def get_frame(_self=cmd):
987        '''
988DESCRIPTION
989
990    "get_frame" returns the current frame index (1-based)
991
992PYMOL API
993
994    Frames refers to sequences of images in a movie.  Sequential frames
995    may contain identical molecular states, they may have one-to-one
996    correspondance to molecular states (default), or they may have an
997    arbitrary relationship, specific using the "mset" command.
998
999SEE ALSO
1000
1001    get_state
1002
1003        '''
1004        # NOTE: NO LOCKS...this is/can be be called from cmd.refresh()
1005        r = _cmd.get_frame(_self._COb)
1006        return r
1007