Coverage for /builds/ase/ase/ase/gui/movie.py: 62.30%
61 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
1# fmt: off
3import numpy as np
5import ase.gui.ui as ui
6from ase.gui.i18n import _
9class Movie:
10 def __init__(self, gui):
11 self.win = win = ui.Window(
12 _('Movie'), close=self.close, wmtype='utility')
13 win.add(_('Image number:'))
14 self.frame_number = ui.Scale(gui.frame, 0,
15 len(gui.images) - 1,
16 callback=self.new_frame)
17 win.add(self.frame_number)
19 win.add([ui.Button(_('First'), self.click, -1, True),
20 ui.Button(_('Back'), self.click, -1),
21 ui.Button(_('Forward'), self.click, 1),
22 ui.Button(_('Last'), self.click, 1, True)])
24 play = ui.Button(_('Play'), self.play)
25 stop = ui.Button(_('Stop'), self.stop)
27 # TRANSLATORS: This function plays an animation forwards and backwards
28 # alternatingly, e.g. for displaying vibrational movement
29 self.rock = ui.CheckButton(_('Rock'))
31 win.add([play, stop, self.rock])
33 if len(gui.images) > 150:
34 skipdefault = len(gui.images) // 150
35 tdefault = min(max(len(gui.images) / (skipdefault * 5.0),
36 1.0), 30)
37 else:
38 skipdefault = 0
39 tdefault = min(max(len(gui.images) / 5.0, 1.0), 30)
40 self.time = ui.SpinBox(tdefault, 1.0, 99, 0.1)
41 self.skip = ui.SpinBox(skipdefault, 0, 99, 1)
42 win.add([_(' Frame rate: '), self.time, _(' Skip frames: '),
43 self.skip])
45 self.gui = gui
46 self.direction = 1
47 self.timer = None
48 gui.obs.new_atoms.register(self.close)
50 def close(self):
51 self.stop()
52 self.win.close()
54 def click(self, step, firstlast=False):
55 if firstlast and step < 0:
56 i = 0
57 elif firstlast:
58 i = len(self.gui.images)
59 else:
60 i = max(0, min(len(self.gui.images) - 1, self.gui.frame + step))
62 self.frame_number.value = i
63 if firstlast:
64 self.direction = np.sign(-step)
65 else:
66 self.direction = np.sign(step)
68 def new_frame(self, value):
69 self.gui.set_frame(value)
71 def play(self):
72 self.stop()
73 t = 1 / self.time.value
74 self.timer = self.gui.window.after(t, self.step)
76 def stop(self):
77 if self.timer is not None:
78 self.timer.cancel()
80 def step(self):
81 i = self.gui.frame
82 nimages = len(self.gui.images)
83 delta = int(self.skip.value) + 1
85 if self.rock.value:
86 if i <= self.skip.value:
87 self.direction = 1
88 elif i >= nimages - delta:
89 self.direction = -1
90 i += self.direction * delta
91 else:
92 i = (i + self.direction * delta + nimages) % nimages
94 self.frame_number.value = i
95 self.play()