Skip to content

Commit 0cd00a5

Browse files
Merge pull request #2283 from jtpio/play-widget
Play widget: expose playing and repeat
2 parents bd0f635 + 3661476 commit 0cd00a5

File tree

4 files changed

+66
-41
lines changed

4 files changed

+66
-41
lines changed

ipywidgets/widgets/widget_int.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,17 +224,18 @@ def _validate_value(self, proposal):
224224
class Play(_BoundedInt):
225225
"""Play/repeat buttons to step through values automatically, and optionally loop.
226226
"""
227-
interval = CInt(100, help="The time between two animation steps (ms).").tag(sync=True)
228-
step = CInt(1, help="Increment step").tag(sync=True)
229-
disabled = Bool(False, help="Enable or disable user changes").tag(sync=True)
230-
231227
_view_name = Unicode('PlayView').tag(sync=True)
232228
_model_name = Unicode('PlayModel').tag(sync=True)
233229

234-
_playing = Bool(help="Whether the control is currently playing.").tag(sync=True)
235-
_repeat = Bool(help="Whether the control will repeat in a continous loop.").tag(sync=True)
230+
playing = Bool(help="Whether the control is currently playing.").tag(sync=True)
231+
repeat = Bool(help="Whether the control will repeat in a continous loop.").tag(sync=True)
232+
233+
interval = CInt(100, help="The time between two animation steps (ms).").tag(sync=True)
234+
step = CInt(1, help="Increment step").tag(sync=True)
235+
disabled = Bool(False, help="Enable or disable user changes").tag(sync=True)
236236
show_repeat = Bool(True, help="Show the repeat toggle button in the widget.").tag(sync=True)
237237

238+
238239
class _BoundedIntRange(_IntRange):
239240
max = CInt(100, help="Max value").tag(sync=True)
240241
min = CInt(0, help="Min value").tag(sync=True)

packages/controls/src/widget_int.ts

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -776,8 +776,8 @@ class PlayModel extends BoundedIntModel {
776776
return _.extend(super.defaults(), {
777777
_model_name: 'PlayModel',
778778
_view_name: 'PlayView',
779-
_playing: false,
780-
_repeat: false,
779+
repeat: false,
780+
playing: false,
781781
show_repeat: true,
782782
interval: 100,
783783
step: 1,
@@ -789,42 +789,47 @@ class PlayModel extends BoundedIntModel {
789789
}
790790

791791
loop(): void {
792-
if (this.get('_playing')) {
793-
const next_value = this.get('value') + this.get('step');
794-
if (next_value <= this.get('max')) {
795-
this.set('value', next_value);
792+
if (!this.get('playing')) {
793+
return;
794+
}
795+
const next_value = this.get('value') + this.get('step');
796+
if (next_value <= this.get('max')) {
797+
this.set('value', next_value);
798+
this.schedule_next();
799+
} else {
800+
if (this.get('repeat')) {
801+
this.set('value', this.get('min'));
796802
this.schedule_next();
797803
} else {
798-
if(this.get('_repeat')) {
799-
this.set('value', this.get('min'));
800-
this.schedule_next();
801-
} else {
802-
this.set('_playing', false);
803-
}
804+
this.pause();
804805
}
805-
this.save_changes();
806806
}
807+
this.save_changes();
807808
}
808809

809810
schedule_next(): void {
810-
window.setTimeout(this.loop.bind(this), this.get('interval'));
811+
this._timerId = window.setTimeout(this.loop.bind(this), this.get('interval'));
811812
}
812813

813814
stop(): void {
814-
this.set('_playing', false);
815+
this.pause();
815816
this.set('value', this.get('min'));
816817
this.save_changes();
817818
}
818819

819820
pause(): void {
820-
this.set('_playing', false);
821+
window.clearTimeout(this._timerId);
822+
this._timerId = null;
823+
this.set('playing', false);
821824
this.save_changes();
822825
}
823826

824-
play(): void {
825-
this.set('_playing', true);
826-
if (this.get('value') == this.get('max')) {
827-
// if the value is at the end, reset if first, and then schedule the next
827+
animate(): void {
828+
if (this._timerId !== null) {
829+
return;
830+
}
831+
if (this.get('value') === this.get('max')) {
832+
// if the value is at the end, reset it first, and then schedule the next
828833
this.set('value', this.get('min'));
829834
this.schedule_next();
830835
this.save_changes();
@@ -833,12 +838,20 @@ class PlayModel extends BoundedIntModel {
833838
// loop will call save_changes in this case
834839
this.loop();
835840
}
841+
this.save_changes();
842+
}
843+
844+
play(): void {
845+
this.set('playing', !this.get('playing'));
846+
this.save_changes();
836847
}
837848

838849
repeat(): void {
839-
this.set('_repeat', !this.get('_repeat'));
850+
this.set('repeat', !this.get('repeat'));
840851
this.save_changes();
841852
}
853+
854+
private _timerId: number | null = null;
842855
}
843856

844857
export
@@ -882,11 +895,11 @@ class PlayView extends DOMWidgetView {
882895
this.stopButton.onclick = this.model.stop.bind(this.model);
883896
this.repeatButton.onclick = this.model.repeat.bind(this.model);
884897

885-
this.listenTo(this.model, 'change:_playing', this.update_playing);
886-
this.listenTo(this.model, 'change:_repeat', this.update_repeat);
887-
this.listenTo(this.model, 'change:show_repeat', this.update_repeat);
888-
this.update_playing();
889-
this.update_repeat();
898+
this.listenTo(this.model, 'change:playing', this.onPlayingChanged);
899+
this.listenTo(this.model, 'change:repeat', this.updateRepeat);
900+
this.listenTo(this.model, 'change:show_repeat', this.updateRepeat);
901+
this.updatePlaying();
902+
this.updateRepeat();
890903
this.update();
891904
}
892905

@@ -896,11 +909,22 @@ class PlayView extends DOMWidgetView {
896909
this.pauseButton.disabled = disabled;
897910
this.stopButton.disabled = disabled;
898911
this.repeatButton.disabled = disabled;
899-
this.update_playing();
912+
this.updatePlaying();
913+
}
914+
915+
onPlayingChanged() {
916+
this.updatePlaying();
917+
const previous = this.model.previous('playing');
918+
const current = this.model.get('playing');
919+
if (!previous && current) {
920+
this.model.animate();
921+
} else {
922+
this.model.pause();
923+
}
900924
}
901925

902-
update_playing(): void {
903-
const playing = this.model.get('_playing');
926+
updatePlaying(): void {
927+
const playing = this.model.get('playing');
904928
const disabled = this.model.get('disabled');
905929
if (playing) {
906930
if (!disabled) {
@@ -915,8 +939,8 @@ class PlayView extends DOMWidgetView {
915939
}
916940
}
917941

918-
update_repeat(): void {
919-
const repeat = this.model.get('_repeat');
942+
updateRepeat(): void {
943+
const repeat = this.model.get('repeat');
920944
this.repeatButton.style.display = this.model.get('show_repeat') ? this.playButton.style.display : 'none';
921945
if (repeat) {
922946
this.repeatButton.classList.add('mod-active');

packages/schema/jupyterwidgetmodels.latest.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -784,8 +784,6 @@ Attribute | Type | Default | Help
784784
`_model_module` | string | `'@jupyter-widgets/controls'` |
785785
`_model_module_version` | string | `'1.5.0'` |
786786
`_model_name` | string | `'PlayModel'` |
787-
`_playing` | boolean | `false` | Whether the control is currently playing.
788-
`_repeat` | boolean | `false` | Whether the control will repeat in a continous loop.
789787
`_view_module` | string | `'@jupyter-widgets/controls'` |
790788
`_view_module_version` | string | `'1.5.0'` |
791789
`_view_name` | string | `'PlayView'` |
@@ -795,6 +793,8 @@ Attribute | Type | Default | Help
795793
`layout` | reference to Layout widget | reference to new instance |
796794
`max` | number (integer) | `100` | Max value
797795
`min` | number (integer) | `0` | Min value
796+
`playing` | boolean | `false` | Whether the control is currently playing.
797+
`repeat` | boolean | `false` | Whether the control will repeat in a continous loop.
798798
`show_repeat` | boolean | `true` | Show the repeat toggle button in the widget.
799799
`step` | number (integer) | `1` | Increment step
800800
`style` | reference to DescriptionStyle widget | reference to new instance | Styling customizations

packages/schema/jupyterwidgetmodels.v8.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,8 +717,8 @@ Attribute | Type | Default | Help
717717
`_model_module` | string | `'@jupyter-widgets/controls'` |
718718
`_model_module_version` | string | `'1.4.0'` |
719719
`_model_name` | string | `'PlayModel'` |
720-
`_playing` | boolean | `false` | Whether the control is currently playing.
721-
`_repeat` | boolean | `false` | Whether the control will repeat in a continous loop.
720+
`playing` | boolean | `false` | Whether the control is currently playing.
721+
`repeat` | boolean | `false` | Whether the control will repeat in a continous loop.
722722
`_view_module` | string | `'@jupyter-widgets/controls'` |
723723
`_view_module_version` | string | `'1.4.0'` |
724724
`_view_name` | string | `'PlayView'` |

0 commit comments

Comments
 (0)