Skip to content

Commit

Permalink
CLOUD: Change the cloud icon to be updated by the main thread
Browse files Browse the repository at this point in the history
The cloud manager registers itself as an event source as a mean to be polled
periodically by the GUI or engine code. The periodical polling is used to
update the OSD icon indicating background sync activity.

Also move the cloud icon from ConnectionManager to CloudManager,
allowing to decouple icon handling from network connections updates.
  • Loading branch information
bgK committed Sep 18, 2016
1 parent 361d84c commit 1a1a5b5
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 104 deletions.
Expand Up @@ -20,23 +20,21 @@
*
*/

#include "backends/networking/curl/cloudicon.h"
#include "backends/cloud/cloudmanager.h"
#include "backends/cloud/cloudicon.h"
#include "common/memstream.h"
#include "gui/ThemeEngine.h"
#include "gui/gui-manager.h"
#include "common/system.h"
#include "image/png.h"

namespace Networking {
namespace Cloud {

const float CloudIcon::ALPHA_STEP = 0.025;
const float CloudIcon::ALPHA_SPEED = 0.0005;
const float CloudIcon::ALPHA_MAX = 1;
const float CloudIcon::ALPHA_MIN = 0.6;

CloudIcon::CloudIcon():
_wasVisible(false), _iconsInited(false), _showingDisabled(false),
_currentAlpha(0), _alphaRising(true), _disabledFrames(0) {
CloudIcon::CloudIcon() {
initIcons();
hide();
_lastUpdateTime = g_system->getMillis();
}

CloudIcon::~CloudIcon() {
Expand All @@ -45,72 +43,95 @@ CloudIcon::~CloudIcon() {
_alphaIcon.free();
}

bool CloudIcon::draw() {
bool stop = false;
initIcons();
void CloudIcon::show(CloudIcon::Type icon, int duration) {
if (_type == icon) {
return; // Nothing to do
}

if (CloudMan.isWorking() || _disabledFrames > 0) {
if (g_system) {
if (!_wasVisible) {
_wasVisible = true;
}
--_disabledFrames;
if (_alphaRising) {
if (_currentAlpha < ALPHA_MIN)
_currentAlpha += 5 * ALPHA_STEP;
else
_currentAlpha += ALPHA_STEP;
if (_currentAlpha > ALPHA_MAX) {
_currentAlpha = ALPHA_MAX;
_alphaRising = false;
}
} else {
_currentAlpha -= ALPHA_STEP;
if (_currentAlpha < ALPHA_MIN) {
_currentAlpha = ALPHA_MIN;
_alphaRising = true;
}
}
if (icon != kNone) {
_state = kShown;
_type = icon;

if (duration) {
_hideTime = g_system->getMillis() + duration;
} else {
_wasVisible = false;
_hideTime = 0;
}
} else {
_wasVisible = false;
_currentAlpha -= 5 * ALPHA_STEP;
if (_currentAlpha <= 0) {
_currentAlpha = 0;
stop = true;
}
_state = kGoingToHide;
}
}

void CloudIcon::hide() {
_state = kHidden;
_type = kNone;
_hideTime = 0;
_currentAlpha = 0;
_alphaRising = true;
}

if (g_system) {
if (!stop) {
makeAlphaIcon((_showingDisabled ? _disabledIcon : _icon), _currentAlpha);
g_system->displayActivityIconOnOSD(&_alphaIcon);
CloudIcon::Type CloudIcon::getShownType() const {
return _type;
}

bool CloudIcon::needsUpdate() const {
uint32 delaySinceLastUpdate = g_system->getMillis() - _lastUpdateTime;
return delaySinceLastUpdate >= UPDATE_DELAY_MIN_MILLIS;
}

void CloudIcon::update() {
uint32 currentTime = g_system->getMillis();
uint32 delaySinceLastUpdate = currentTime - _lastUpdateTime;
_lastUpdateTime = currentTime;

switch (_state) {
case kHidden:
return; // Nothing to do
case kShown:
if (_alphaRising) {
if (_currentAlpha < ALPHA_MIN)
_currentAlpha += 5 * ALPHA_SPEED * delaySinceLastUpdate;
else
_currentAlpha += ALPHA_SPEED * delaySinceLastUpdate;
if (_currentAlpha > ALPHA_MAX) {
_currentAlpha = ALPHA_MAX;
_alphaRising = false;
}
} else {
g_system->displayActivityIconOnOSD(nullptr);
_currentAlpha -= ALPHA_SPEED * delaySinceLastUpdate;
if (_currentAlpha < ALPHA_MIN) {
_currentAlpha = ALPHA_MIN;
_alphaRising = true;
}
}
}

if (stop)
_showingDisabled = false;
return stop;
}
if (_hideTime != 0 && _hideTime <= currentTime) {
_hideTime = 0;
_state = kGoingToHide;
}
break;
case kGoingToHide:
_currentAlpha -= 5 * ALPHA_SPEED * delaySinceLastUpdate;
if (_currentAlpha <= 0) {
hide();
}
break;
}

void CloudIcon::showDisabled() {
_showingDisabled = true;
_disabledFrames = 20 * 3; //3 seconds 20 fps
if (_state != kHidden) {
makeAlphaIcon((_type == kDisabled ? _disabledIcon : _icon), _currentAlpha);
g_system->displayActivityIconOnOSD(&_alphaIcon);
} else {
g_system->displayActivityIconOnOSD(nullptr);
}
}

#include "backends/networking/curl/cloudicon_data.h"
#include "backends/networking/curl/cloudicon_disabled_data.h"
#include "backends/cloud/cloudicon_data.h"
#include "backends/cloud/cloudicon_disabled_data.h"

void CloudIcon::initIcons() {
if (_iconsInited)
return;
loadIcon(_icon, cloudicon_data, ARRAYSIZE(cloudicon_data));
loadIcon(_disabledIcon, cloudicon_disabled_data, ARRAYSIZE(cloudicon_disabled_data));
_iconsInited = true;
}

void CloudIcon::loadIcon(Graphics::Surface &icon, byte *data, uint32 size) {
Expand All @@ -123,7 +144,7 @@ void CloudIcon::loadIcon(Graphics::Surface &icon, byte *data, uint32 size) {
return icon.copyFrom(*s);
}

void CloudIcon::makeAlphaIcon(Graphics::Surface &icon, float alpha) {
void CloudIcon::makeAlphaIcon(const Graphics::Surface &icon, float alpha) {
_alphaIcon.copyFrom(icon);

byte *pixels = (byte *)_alphaIcon.getPixels();
Expand Down Expand Up @@ -154,4 +175,4 @@ void CloudIcon::makeAlphaIcon(Graphics::Surface &icon, float alpha) {
}
}

} // End of namespace Networking
} // End of namespace Cloud
78 changes: 49 additions & 29 deletions backends/networking/curl/cloudicon.h → backends/cloud/cloudicon.h
Expand Up @@ -25,46 +25,66 @@

#include "graphics/surface.h"

namespace Networking {
namespace Cloud {

class CloudIcon {
static const float ALPHA_STEP, ALPHA_MAX, ALPHA_MIN;

bool _wasVisible, _iconsInited, _showingDisabled;
Graphics::Surface _icon, _disabledIcon, _alphaIcon;
float _currentAlpha;
bool _alphaRising;
int _disabledFrames;

void initIcons();
void loadIcon(Graphics::Surface &icon, byte *data, uint32 size);
void makeAlphaIcon(Graphics::Surface &icon, float alpha);

public:
CloudIcon();
~CloudIcon();

/**
* This method is called from ConnectionManager every time
* its own timer calls the handle() method. The primary
* responsibility of this draw() method is to draw cloud icon
* on ScummVM's OSD when current cloud Storage is working.
*
* As we don't want ConnectionManager to work when no
* Requests are running, we'd like to stop the timer. But then
* this icon wouldn't have time to disappear smoothly. So,
* in order to do that, ConnectionManager stop its timer
* only when this draw() method returns true, indicating that
* the CloudIcon has disappeared and the timer could be stopped.
* The type of cloud icon to show
*/
enum Type {
kNone, /** Hide the currently shown icon if any */
kSyncing, /** Cloud syncing icon */
kDisabled /** Cloud syncing not available icon */
};

/**
* Select the icon to show on the OSD
*
* @return true if ConnMan's timer could be stopped.
* @param icon Icon type to show. Use kNone to hide the current icon if any.
* @param duration Duration in milliseconds the icon stays visible on screen. 0 means the icon stays indefinitely.
*/
bool draw();
void show(Type icon, int duration = 0);

/** The currently visible icon. kNone means no icon is shown. */
Type getShownType() const;

/** Returns true if the icon state needs to be checked for changes */
bool needsUpdate() const;

/** Update the icon visible on the OSD */
void update();

private:
static const float ALPHA_SPEED, ALPHA_MAX, ALPHA_MIN;
static const int UPDATE_DELAY_MIN_MILLIS = 10;

enum State {
kHidden,
kShown,
kGoingToHide
};

State _state;
Type _type;

Graphics::Surface _icon, _disabledIcon, _alphaIcon;
float _currentAlpha;
bool _alphaRising;

uint32 _hideTime;
uint32 _lastUpdateTime;

void initIcons();
void loadIcon(Graphics::Surface &icon, byte *data, uint32 size);
void makeAlphaIcon(const Graphics::Surface &icon, float alpha);

/** Draw a "cloud disabled" icon instead of "cloud syncing" one. */
void showDisabled();
void hide();
};

} // End of namespace Networking
} // End of namespace Cloud

#endif
File renamed without changes.
File renamed without changes.
24 changes: 24 additions & 0 deletions backends/cloud/cloudmanager.cpp
Expand Up @@ -45,6 +45,8 @@ const char *const CloudManager::kStoragePrefix = "storage_";
CloudManager::CloudManager() : _currentStorageIndex(0), _activeStorage(nullptr) {}

CloudManager::~CloudManager() {
g_system->getEventManager()->getEventDispatcher()->unregisterSource(this);

delete _activeStorage;
freeStorages();
}
Expand Down Expand Up @@ -108,6 +110,8 @@ void CloudManager::init() {
_currentStorageIndex = ConfMan.getInt("current_storage", ConfMan.kCloudDomain);

loadStorage();

g_system->getEventManager()->getEventDispatcher()->registerSource(this, false);
}

void CloudManager::save() {
Expand Down Expand Up @@ -383,6 +387,10 @@ void CloudManager::setSyncTarget(GUI::CommandReceiver *target) const {
storage->setSyncTarget(target);
}

void CloudManager::showCloudDisabledIcon() {
_icon.show(CloudIcon::kDisabled, 3000);
}

///// DownloadFolderRequest-related /////

bool CloudManager::startDownload(Common::String remotePath, Common::String localPath) const {
Expand Down Expand Up @@ -453,4 +461,20 @@ Common::String CloudManager::getDownloadLocalDirectory() const {
return "";
}

bool CloudManager::pollEvent(Common::Event &event) {
if (_icon.needsUpdate()) {
if (_icon.getShownType() != CloudIcon::kDisabled) {
if (isWorking()) {
_icon.show(CloudIcon::kSyncing);
} else {
_icon.show(CloudIcon::kNone);
}
}

_icon.update();
}

return false;
}

} // End of namespace Cloud
22 changes: 21 additions & 1 deletion backends/cloud/cloudmanager.h
Expand Up @@ -24,9 +24,12 @@
#define CLOUD_CLOUDMANAGER_H

#include "backends/cloud/storage.h"
#include "backends/cloud/cloudicon.h"

#include "common/array.h"
#include "common/singleton.h"
#include "common/str-array.h"
#include "common/events.h"

namespace GUI {

Expand All @@ -47,7 +50,7 @@ enum StorageID {
kStorageTotal
};

class CloudManager : public Common::Singleton<CloudManager> {
class CloudManager : public Common::Singleton<CloudManager>, public Common::EventSource {
static const char *const kStoragePrefix;

struct StorageConfig {
Expand All @@ -61,6 +64,8 @@ class CloudManager : public Common::Singleton<CloudManager> {
Storage *_activeStorage;
Common::Array<Storage *> _storagesToRemove;

CloudIcon _icon;

void loadStorage();

Common::String getStorageConfigName(uint32 index) const;
Expand All @@ -71,6 +76,18 @@ class CloudManager : public Common::Singleton<CloudManager> {
/** Calls the error callback with a special "no storage connected" message. */
void passNoStorageConnected(Networking::ErrorCallback errorCallback) const;

/**
* Common::EventSource interface
*
* The cloud manager registers itself as an event source even if does not
* actually produce events as a mean to be polled periodically by the GUI
* or engine code.
*
* The periodical polling is used to update the OSD icon indicating
* background sync activity.
*/
virtual bool pollEvent(Common::Event &event) override;

public:
CloudManager();
virtual ~CloudManager();
Expand Down Expand Up @@ -233,6 +250,9 @@ class CloudManager : public Common::Singleton<CloudManager> {
/** Sets SavesSyncRequest's target to given CommandReceiver. */
void setSyncTarget(GUI::CommandReceiver *target) const;

/** Shows a "cloud disabled" icon for three seconds. */
void showCloudDisabledIcon();

///// DownloadFolderRequest-related /////

/** Starts a folder download. */
Expand Down

0 comments on commit 1a1a5b5

Please sign in to comment.