Coverage for /builds/kinetik161/ase/ase/gui/movie.py: 60.32%
63 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
1import numpy as np
3import ase.gui.ui as ui
4from ase.gui.i18n import _
7class Movie:
8 def __init__(self, gui):
9 self.win = win = ui.Window(
10 _('Movie'), close=self.close, wmtype='utility')
11 win.add(_('Image number:'))
12 self.frame_number = ui.Scale(gui.frame, 0,
13 len(gui.images) - 1,
14 callback=self.new_frame)
15 win.add(self.frame_number)
17 win.add([ui.Button(_('First'), self.click, -1, True),
18 ui.Button(_('Back'), self.click, -1),
19 ui.Button(_('Forward'), self.click, 1),
20 ui.Button(_('Last'), self.click, 1, True)])
22 play = ui.Button(_('Play'), self.play)
23 stop = ui.Button(_('Stop'), self.stop)
25 # TRANSLATORS: This function plays an animation forwards and backwards
26 # alternatingly, e.g. for displaying vibrational movement
27 self.rock = ui.CheckButton(_('Rock'))
29 win.add([play, stop, self.rock])
31 if len(gui.images) > 150:
32 skipdefault = len(gui.images) // 150
33 tdefault = min(max(len(gui.images) / (skipdefault * 5.0),
34 1.0), 30)
35 else:
36 skipdefault = 0
37 tdefault = min(max(len(gui.images) / 5.0, 1.0), 30)
38 self.time = ui.SpinBox(tdefault, 1.0, 99, 0.1)
39 self.skip = ui.SpinBox(skipdefault, 0, 99, 1)
40 win.add([_(' Frame rate: '), self.time, _(' Skip frames: '),
41 self.skip])
43 self.gui = gui
44 self.direction = 1
45 self.timer = None
46 gui.register_vulnerable(self)
48 def notify_atoms_changed(self):
49 """Called by gui object when the atoms have changed."""
50 self.close()
52 def close(self):
53 self.stop()
54 self.win.close()
56 def click(self, step, firstlast=False):
57 if firstlast and step < 0:
58 i = 0
59 elif firstlast:
60 i = len(self.gui.images)
61 else:
62 i = max(0, min(len(self.gui.images) - 1, self.gui.frame + step))
64 self.frame_number.value = i
65 if firstlast:
66 self.direction = np.sign(-step)
67 else:
68 self.direction = np.sign(step)
70 def new_frame(self, value):
71 self.gui.set_frame(value)
73 def play(self):
74 self.stop()
75 t = 1 / self.time.value
76 self.timer = self.gui.window.after(t, self.step)
78 def stop(self):
79 if self.timer is not None:
80 self.timer.cancel()
82 def step(self):
83 i = self.gui.frame
84 nimages = len(self.gui.images)
85 delta = int(self.skip.value) + 1
87 if self.rock.value:
88 if i <= self.skip.value:
89 self.direction = 1
90 elif i >= nimages - delta:
91 self.direction = -1
92 i += self.direction * delta
93 else:
94 i = (i + self.direction * delta + nimages) % nimages
96 self.frame_number.value = i
97 self.play()