-
-
Notifications
You must be signed in to change notification settings - Fork 477
/
player.py
172 lines (125 loc) · 5.48 KB
/
player.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
"""
Defines Player widgets which offer media-player like controls.
"""
from __future__ import annotations
from typing import (
TYPE_CHECKING, ClassVar, Mapping, Type,
)
import param
from ..config import config
from ..models.widgets import Player as _BkPlayer
from ..util import indexOf, isIn
from .base import Widget
from .select import SelectBase
if TYPE_CHECKING:
from bokeh.model import Model
class PlayerBase(Widget):
direction = param.Integer(default=0, doc="""
Current play direction of the Player (-1: playing in reverse,
0: paused, 1: playing)""")
interval = param.Integer(default=500, doc="""
Interval between updates, in milliseconds. Default is 500, i.e.
two updates per second.""")
loop_policy = param.ObjectSelector(
default='once', objects=['once', 'loop', 'reflect'], doc="""
Policy used when player hits last frame""")
show_loop_controls = param.Boolean(default=True, doc="""
Whether the loop controls radio buttons are shown""")
step = param.Integer(default=1, doc="""
Number of frames to step forward and back by on each event.""")
height = param.Integer(default=80)
width = param.Integer(default=510, allow_None=True, doc="""
Width of this component. If sizing_mode is set to stretch
or scale mode this will merely be used as a suggestion.""")
_rename: ClassVar[Mapping[str, str | None]] = {'name': None}
_widget_type: ClassVar[Type[Model]] = _BkPlayer
__abstract = True
def __init__(self, **params):
if 'value' in params and 'value_throttled' in self.param:
params['value_throttled'] = params['value']
super().__init__(**params)
def play(self):
self.direction = 1
def pause(self):
self.direction = 0
def reverse(self):
self.direction = -1
class Player(PlayerBase):
"""
The `Player` provides controls to play and skip through a number of
frames defined by explicit start and end values. The speed at
which the widget plays is defined by the `interval` (in milliseconds), but it is also
possible to skip frames using the `step` parameter.
Reference: https://panel.holoviz.org/reference/widgets/Player.html
:Example:
>>> Player(name='Player', start=0, end=100, value=32, loop_policy='loop')
"""
start = param.Integer(default=0, doc="Lower bound on the slider value")
end = param.Integer(default=10, doc="Upper bound on the slider value")
value = param.Integer(default=0, doc="Current player value")
value_throttled = param.Integer(default=0, constant=True, doc="""
Current throttled player value.""")
_supports_embed: ClassVar[bool] = True
def __init__(self, **params):
if 'length' in params:
if 'start' in params or 'end' in params:
raise ValueError('Supply either length or start and end to Player not both')
params['start'] = 0
params['end'] = params.pop('length')-1
elif params.get('start', 0) > 0 and 'value' not in params:
params['value'] = params['start']
super().__init__(**params)
def _process_property_change(self, msg):
if config.throttled:
if "value" in msg:
del msg["value"]
if "value_throttled" in msg:
msg["value"] = msg["value_throttled"]
return super()._process_property_change(msg)
def _get_embed_state(self, root, values=None, max_opts=3):
if values is None:
values = list(range(self.start, self.end, self.step))
return (self, self._models[root.ref['id']][0], values,
lambda x: x.value, 'value', 'cb_obj.value')
class DiscretePlayer(PlayerBase, SelectBase):
"""
The `DiscretePlayer` provides controls to iterate through a list of
discrete options. The speed at which the widget plays is defined
by the `interval` (in milliseconds), but it is also possible to skip items using the
`step` parameter.
Reference: https://panel.holoviz.org/reference/widgets/DiscretePlayer.html
:Example:
>>> DiscretePlayer(
... name='Discrete Player',
... options=[2, 4, 8, 16, 32, 64, 128], value=32,
... loop_policy='loop'
... )
"""
interval = param.Integer(default=500, doc="Interval between updates")
value = param.Parameter(doc="Current player value")
value_throttled = param.Parameter(constant=True, doc="Current player value")
_rename: ClassVar[Mapping[str, str | None]] = {'name': None, 'options': None}
_source_transforms: ClassVar[Mapping[str, str | None]] = {'value': None, 'value_throttled': None}
def _process_param_change(self, msg):
values = self.values
if 'options' in msg:
msg['start'] = 0
msg['end'] = len(values) - 1
if values and not isIn(self.value, values):
self.value = values[0]
if 'value' in msg:
value = msg['value']
if isIn(value, values):
msg['value'] = indexOf(value, values)
elif values:
self.value = values[0]
if 'value_throttled' in msg:
del msg['value_throttled']
return super()._process_param_change(msg)
def _process_property_change(self, msg):
for prop in ('value', 'value_throttled'):
if prop in msg:
value = msg.pop(prop)
if value < len(self.options):
msg[prop] = self.values[value]
return msg