diff --git a/js/Makefile.am b/js/Makefile.am index 7920dff1e..4216df8de 100644 --- a/js/Makefile.am +++ b/js/Makefile.am @@ -37,6 +37,7 @@ nobase_dist_js_DATA = \ misc/util.js \ perf/core.js \ ui/altTab.js \ + ui/animation.js \ ui/appDisplay.js \ ui/appFavorites.js \ ui/backgroundMenu.js \ diff --git a/js/ui/animation.js b/js/ui/animation.js new file mode 100644 index 000000000..fb72e74e0 --- /dev/null +++ b/js/ui/animation.js @@ -0,0 +1,84 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Lang = imports.lang; +const Mainloop = imports.mainloop; +const St = imports.gi.St; +const Signals = imports.signals; +const Atk = imports.gi.Atk; + +const ANIMATED_ICON_UPDATE_TIMEOUT = 100; + +const Animation = new Lang.Class({ + Name: 'Animation', + + _init: function(filename, width, height, speed) { + this.actor = new St.Bin(); + this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); + this._speed = speed; + + this._isLoaded = false; + this._isPlaying = false; + this._timeoutId = 0; + this._frame = 0; + this._animations = St.TextureCache.get_default().load_sliced_image (filename, width, height, + Lang.bind(this, this._animationsLoaded)); + this.actor.set_child(this._animations); + }, + + play: function() { + if (this._isLoaded && this._timeoutId == 0) { + if (this._frame == 0) + this._showFrame(0); + + this._timeoutId = Mainloop.timeout_add(this._speed, Lang.bind(this, this._update)); + } + + this._isPlaying = true; + }, + + stop: function() { + if (this._timeoutId > 0) { + Mainloop.source_remove(this._timeoutId); + this._timeoutId = 0; + } + + this._isPlaying = false; + }, + + _showFrame: function(frame) { + let oldFrameActor = this._animations.get_child_at_index(this._frame); + if (oldFrameActor) + oldFrameActor.hide(); + + this._frame = (frame % this._animations.get_n_children()); + + let newFrameActor = this._animations.get_child_at_index(this._frame); + if (newFrameActor) + newFrameActor.show(); + }, + + _update: function() { + this._showFrame(this._frame + 1); + return true; + }, + + _animationsLoaded: function() { + this._isLoaded = true; + + if (this._isPlaying) + this.play(); + }, + + _onDestroy: function() { + this.stop(); + } +}); + +const AnimatedIcon = new Lang.Class({ + Name: 'AnimatedIcon', + Extends: Animation, + + _init: function(filename, size) { + this.parent(filename, size, size, ANIMATED_ICON_UPDATE_TIMEOUT); + } +}); diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js index f770faf6a..8af40131c 100644 --- a/js/ui/modalDialog.js +++ b/js/ui/modalDialog.js @@ -14,6 +14,7 @@ const Atk = imports.gi.Atk; const Params = imports.misc.params; +const Animation = imports.ui.animation; const Layout = imports.ui.layout; const Lightbox = imports.ui.lightbox; const Main = imports.ui.main; @@ -187,10 +188,8 @@ const ModalDialog = new Lang.Class({ }, placeSpinner: function(layoutInfo) { - /* This is here because of recursive imports */ - const Panel = imports.ui.panel; let spinnerIcon = global.datadir + '/theme/process-working.svg'; - this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE); + this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE); this._workSpinner.actor.opacity = 0; this._workSpinner.actor.show(); diff --git a/js/ui/panel.js b/js/ui/panel.js index ded8ceea2..729a57409 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -15,6 +15,7 @@ const Signals = imports.signals; const Atk = imports.gi.Atk; +const Animation = imports.ui.animation; const Config = imports.misc.config; const CtrlAltTab = imports.ui.ctrlAltTab; const DND = imports.ui.dnd; @@ -29,7 +30,6 @@ const PANEL_ICON_SIZE = 24; const BUTTON_DND_ACTIVATION_TIMEOUT = 250; -const ANIMATED_ICON_UPDATE_TIMEOUT = 100; const SPINNER_ANIMATION_TIME = 0.2; // To make sure the panel corners blend nicely with the panel, @@ -75,81 +75,6 @@ function _unpremultiply(color) { blue: blue, alpha: color.alpha }); }; -const Animation = new Lang.Class({ - Name: 'Animation', - - _init: function(filename, width, height, speed) { - this.actor = new St.Bin(); - this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); - this._speed = speed; - - this._isLoaded = false; - this._isPlaying = false; - this._timeoutId = 0; - this._frame = 0; - this._animations = St.TextureCache.get_default().load_sliced_image (filename, width, height, - Lang.bind(this, this._animationsLoaded)); - this.actor.set_child(this._animations); - }, - - play: function() { - if (this._isLoaded && this._timeoutId == 0) { - if (this._frame == 0) - this._showFrame(0); - - this._timeoutId = Mainloop.timeout_add(this._speed, Lang.bind(this, this._update)); - } - - this._isPlaying = true; - }, - - stop: function() { - if (this._timeoutId > 0) { - Mainloop.source_remove(this._timeoutId); - this._timeoutId = 0; - } - - this._isPlaying = false; - }, - - _showFrame: function(frame) { - let oldFrameActor = this._animations.get_child_at_index(this._frame); - if (oldFrameActor) - oldFrameActor.hide(); - - this._frame = (frame % this._animations.get_n_children()); - - let newFrameActor = this._animations.get_child_at_index(this._frame); - if (newFrameActor) - newFrameActor.show(); - }, - - _update: function() { - this._showFrame(this._frame + 1); - return true; - }, - - _animationsLoaded: function() { - this._isLoaded = true; - - if (this._isPlaying) - this.play(); - }, - - _onDestroy: function() { - this.stop(); - } -}); - -const AnimatedIcon = new Lang.Class({ - Name: 'AnimatedIcon', - Extends: Animation, - - _init: function(filename, size) { - this.parent(filename, size, size, ANIMATED_ICON_UPDATE_TIMEOUT); - } -}); - const TextShadower = new Lang.Class({ Name: 'TextShadower', @@ -360,7 +285,7 @@ const AppMenuButton = new Lang.Class({ if (!success || this._spinnerIcon == icon) return; this._spinnerIcon = icon; - this._spinner = new AnimatedIcon(this._spinnerIcon, PANEL_ICON_SIZE); + this._spinner = new Animation.AnimatedIcon(this._spinnerIcon, PANEL_ICON_SIZE); this._container.add_actor(this._spinner.actor); this._spinner.actor.hide(); this._spinner.actor.lower_bottom();