From e6bca489c9aae88f1c7bbb44c4e2df71f481cbd3 Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Sun, 10 Mar 2013 18:08:34 +0000 Subject: AvatarButton/holder, rename ThumbnailBroker for more general purposes diff --git a/src/Format.cpp b/src/Format.cpp index f7c3c09..e4056c2 100644 --- a/src/Format.cpp +++ b/src/Format.cpp @@ -138,6 +138,21 @@ std::vector format::VideoBufferToPTI(const VideoBuffer & vidBuf) return data; } +VideoBuffer * format::PTIToVideoBuffer(std::vector & data) +{ + + int newWidth, newHeight; + pixel * buffer = Graphics::ptif_unpack(&data[0], data.size(), &newWidth, &newHeight); + + if(buffer) + { + VideoBuffer * vb = new VideoBuffer(buffer, newWidth, newHeight); + free(buffer); + return vb; + } + return NULL; +} + std::vector format::VideoBufferToPPM(const VideoBuffer & vidBuf) { std::vector data; diff --git a/src/Format.h b/src/Format.h index 0fd63a1..a791511 100644 --- a/src/Format.h +++ b/src/Format.h @@ -33,5 +33,6 @@ namespace format std::vector VideoBufferToPNG(const VideoBuffer & vidBuf); std::vector VideoBufferToPPM(const VideoBuffer & vidBuf); std::vector VideoBufferToPTI(const VideoBuffer & vidBuf); + VideoBuffer * PTIToVideoBuffer(std::vector & data); unsigned long CalculateCRC(unsigned char * data, int length); } \ No newline at end of file diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 4c13850..97251e0 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -42,7 +42,7 @@ #include "search/Thumbnail.h" #include "preview/Comment.h" #include "ClientListener.h" -#include "ThumbnailBroker.h" +#include "RequestBroker.h" #include "cajun/reader.h" #include "cajun/writer.h" @@ -617,7 +617,7 @@ std::vector > Client::GetServerNotifications void Client::Tick() { //Check thumbnail queue - ThumbnailBroker::Ref().FlushThumbQueue(); + RequestBroker::Ref().FlushThumbQueue(); //Check status on version check request if(versionCheckRequest && http_async_req_status(versionCheckRequest)) @@ -809,7 +809,7 @@ void Client::WritePrefs() void Client::Shutdown() { - ThumbnailBroker::Ref().Shutdown(); + RequestBroker::Ref().Shutdown(); ClearThumbnailRequests(); http_done(); @@ -1150,6 +1150,28 @@ std::vector Client::GetSaveData(int saveID, int saveDate) return saveData; } +VideoBuffer * Client::GetAvatar(std::string username) +{ + lastError = ""; + int dataStatus; + int dataLength = 0; + unsigned char * data; + std::stringstream urlStream; + urlStream << "http://" << STATICSERVER << "/avatars/" << username << ".pti"; + + data = (unsigned char *)http_simple_get((char *)urlStream.str().c_str(), &dataStatus, &dataLength); + if(data && dataStatus == 200) + { + std::vector responseData(data, data+dataLength); + return format::PTIToVideoBuffer(responseData); + } + else if(data) + { + free(data); + } + return NULL; +} + LoginStatus Client::Login(std::string username, std::string password, User & user) { lastError = ""; diff --git a/src/client/Client.h b/src/client/Client.h index 0b40012..41eeef7 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -17,6 +17,7 @@ class SaveInfo; class SaveFile; class SaveComment; class GameSave; +class VideoBuffer; enum LoginStatus { LoginOkay, LoginError @@ -125,6 +126,8 @@ public: RequestStatus AddComment(int saveID, std::string comment); + VideoBuffer * GetAvatar(std::string username); + unsigned char * GetSaveData(int saveID, int saveDate, int & dataLength); std::vector GetSaveData(int saveID, int saveDate); LoginStatus Login(std::string username, std::string password, User & user); diff --git a/src/client/RequestBroker.cpp b/src/client/RequestBroker.cpp new file mode 100644 index 0000000..e09cb5c --- /dev/null +++ b/src/client/RequestBroker.cpp @@ -0,0 +1,392 @@ +#include +#include +#include +#include +#include "RequestBroker.h" +#include "ThumbnailListener.h" +#include "Client.h" +#include "HTTP.h" +#include "GameSave.h" +#include "search/Thumbnail.h" +#include "simulation/SaveRenderer.h" + +//Asynchronous Thumbnail render & request processing + +RequestBroker::RequestBroker() +{ + thumbnailQueueRunning = false; + //thumbnailQueueMutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_init (&thumbnailQueueMutex, NULL); + + //listenersMutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_init (&listenersMutex, NULL); + + + pthread_mutex_init (&runningMutex, NULL); +} + +RequestBroker::~RequestBroker() +{ + +} + +void RequestBroker::assureRunning() +{ + pthread_mutex_lock(&runningMutex); + bool running = thumbnailQueueRunning; + thumbnailQueueRunning = true; + pthread_mutex_unlock(&runningMutex); + + if(!running) + { +#ifdef DEBUG + std::cout << typeid(*this).name() << " Starting background thread for new " << __FUNCTION__ << " request" << std::endl; +#endif + pthread_create(&thumbnailQueueThread, 0, &RequestBroker::thumbnailQueueProcessHelper, this); + } +} + +void RequestBroker::Shutdown() +{ + pthread_mutex_lock(&runningMutex); + if(thumbnailQueueRunning) + { + thumbnailQueueRunning = false; + pthread_mutex_unlock(&runningMutex); + pthread_join(thumbnailQueueThread, NULL); + } + else + pthread_mutex_unlock(&runningMutex); + + + for (std::list::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter) + { + ThumbnailRequest req = *iter; + if(req.HTTPContext) + { + http_async_req_close(req.HTTPContext); + } + } +} + +void RequestBroker::RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener) +{ + RenderThumbnail(gameSave, true, true, width, height, tListener); +} + +void RequestBroker::RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener) +{ + AttachThumbnailListener(tListener); + pthread_mutex_lock(&thumbnailQueueMutex); + renderRequests.push_back(ThumbRenderRequest(new GameSave(*gameSave), decorations, fire, width, height, ListenerHandle(tListener->ListenerRand, tListener))); + pthread_mutex_unlock(&thumbnailQueueMutex); + + assureRunning(); +} + +void RequestBroker::RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener) +{ + AttachThumbnailListener(tListener); + pthread_mutex_lock(&thumbnailQueueMutex); + thumbnailRequests.push_back(ThumbnailRequest(saveID, saveDate, width, height, ListenerHandle(tListener->ListenerRand, tListener))); + pthread_mutex_unlock(&thumbnailQueueMutex); + + assureRunning(); +} + +void * RequestBroker::thumbnailQueueProcessHelper(void * ref) +{ + ((RequestBroker*)ref)->thumbnailQueueProcessTH(); + return NULL; +} + +void RequestBroker::FlushThumbQueue() +{ + pthread_mutex_lock(&thumbnailQueueMutex); + while(thumbnailComplete.size()) + { + if(CheckThumbnailListener(thumbnailComplete.front().first)) + { + thumbnailComplete.front().first.second->OnThumbnailReady(thumbnailComplete.front().second); + } + else + { +#ifdef DEBUG + std::cout << typeid(*this).name() << " Listener lost, discarding request" << std::endl; +#endif + delete thumbnailComplete.front().second; + } + thumbnailComplete.pop_front(); + } + pthread_mutex_unlock(&thumbnailQueueMutex); +} + +void RequestBroker::thumbnailQueueProcessTH() +{ + time_t lastAction = time(NULL); + pthread_mutex_lock(&runningMutex); + thumbnailQueueRunning = true; + pthread_mutex_unlock(&runningMutex); + while(true) + { + //Shutdown after 2 seconds of idle + if(time(NULL) - lastAction > 2) + { +#ifdef DEBUG + std::cout << typeid(*this).name() << " Idle shutdown" << std::endl; +#endif + break; + } + + + pthread_mutex_lock(&runningMutex); + bool running = thumbnailQueueRunning; + pthread_mutex_unlock(&runningMutex); + if(!running) + { +#ifdef DEBUG + std::cout << typeid(*this).name() << " Requested shutdown" << std::endl; +#endif + break; + } + + + //Renderer + pthread_mutex_lock(&thumbnailQueueMutex); + if(renderRequests.size()) + { + lastAction = time(NULL); + ThumbRenderRequest req; + req = renderRequests.front(); + renderRequests.pop_front(); + pthread_mutex_unlock(&thumbnailQueueMutex); + +#ifdef DEBUG + std::cout << typeid(*this).name() << " Processing render request" << std::endl; +#endif + + Thumbnail * thumbnail = SaveRenderer::Ref().Render(req.Save, req.Decorations, req.Fire); + delete req.Save; + + if(thumbnail) + { + thumbnail->Resize(req.Width, req.Height); + + pthread_mutex_lock(&thumbnailQueueMutex); + thumbnailComplete.push_back(std::pair(req.CompletedListener, thumbnail)); + pthread_mutex_unlock(&thumbnailQueueMutex); + } + } + else + { + pthread_mutex_unlock(&thumbnailQueueMutex); + } + + //Renderer + pthread_mutex_lock(&thumbnailQueueMutex); + if(thumbnailRequests.size()) + { + lastAction = time(NULL); + Thumbnail * thumbnail = NULL; + + ThumbnailRequest req; + req = thumbnailRequests.front(); + + //Check the cache + for(std::deque >::iterator iter = thumbnailCache.begin(), end = thumbnailCache.end(); iter != end; ++iter) + { + if((*iter).first == req.ID) + { + thumbnail = (*iter).second; +#ifdef DEBUG + std::cout << typeid(*this).name() << " " << req.ID.SaveID << ":" << req.ID.SaveDate << " found in cache" << std::endl; +#endif + } + } + + if(thumbnail) + { + //Got thumbnail from cache + thumbnailRequests.pop_front(); + pthread_mutex_unlock(&thumbnailQueueMutex); + + for(std::vector::iterator specIter = req.SubRequests.begin(), specEnd = req.SubRequests.end(); specIter != specEnd; ++specIter) + { + Thumbnail * tempThumbnail = new Thumbnail(*thumbnail); + tempThumbnail->Resize((*specIter).Width, (*specIter).Height); + + pthread_mutex_lock(&thumbnailQueueMutex); + thumbnailComplete.push_back(std::pair((*specIter).CompletedListener, tempThumbnail)); + pthread_mutex_unlock(&thumbnailQueueMutex); + } + } + else + { + //Check for ongoing requests + bool requested = false; + for(std::list::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter) + { + if((*iter).ID == req.ID) + { + requested = true; + +#ifdef DEBUG + std::cout << typeid(*this).name() << " Request for " << req.ID.SaveID << ":" << req.ID.SaveDate << " found, appending." << std::endl; +#endif + + //Add the current listener to the item already being requested + (*iter).SubRequests.push_back(req.SubRequests.front()); + } + } + + if(requested) + { + //Already requested + thumbnailRequests.pop_front(); + pthread_mutex_unlock(&thumbnailQueueMutex); + } + else if(currentRequests.size() < IMGCONNS) //If it's not already being requested and we still have more space for a new connection, request it + { + thumbnailRequests.pop_front(); + pthread_mutex_unlock(&thumbnailQueueMutex); + + //If it's not already being requested, request it + std::stringstream urlStream; + urlStream << "http://" << STATICSERVER << "/" << req.ID.SaveID; + if(req.ID.SaveDate) + { + urlStream << "_" << req.ID.SaveDate; + } + urlStream << "_small.pti"; + +#ifdef DEBUG + std::cout << typeid(*this).name() << " Creating new request for " << req.ID.SaveID << ":" << req.ID.SaveDate << std::endl; +#endif + + req.HTTPContext = http_async_req_start(NULL, (char *)urlStream.str().c_str(), NULL, 0, 0); + req.RequestTime = time(NULL); + currentRequests.push_back(req); + } + else + { + //Already full of requests + pthread_mutex_unlock(&thumbnailQueueMutex); + + } + } + } + else + { + pthread_mutex_unlock(&thumbnailQueueMutex); + } + + std::list::iterator iter = currentRequests.begin(); + while (iter != currentRequests.end()) + { + lastAction = time(NULL); + + ThumbnailRequest req = *iter; + Thumbnail * thumbnail = NULL; + + if(http_async_req_status(req.HTTPContext)) + { + + pixel * thumbData; + char * data; + int status, data_size, imgw, imgh; + data = http_async_req_stop(req.HTTPContext, &status, &data_size); + + if (status == 200 && data) + { + thumbData = Graphics::ptif_unpack(data, data_size, &imgw, &imgh); + free(data); + + if(thumbData) + { + thumbnail = new Thumbnail(req.ID.SaveID, req.ID.SaveID, thumbData, ui::Point(imgw, imgh)); + free(thumbData); + } + else + { + //Error thumbnail + VideoBuffer errorThumb(128, 128); + errorThumb.SetCharacter(64, 64, 'x', 255, 255, 255, 255); + + thumbnail = new Thumbnail(req.ID.SaveID, req.ID.SaveID, errorThumb.Buffer, ui::Point(errorThumb.Width, errorThumb.Height)); + } + + if(thumbnailCache.size() >= THUMB_CACHE_SIZE) + { + delete thumbnailCache.front().second; + thumbnailCache.pop_front(); + } + thumbnailCache.push_back(std::pair(req.ID, thumbnail)); + + for(std::vector::iterator specIter = req.SubRequests.begin(), specEnd = req.SubRequests.end(); specIter != specEnd; ++specIter) + { + Thumbnail * tempThumbnail = new Thumbnail(*thumbnail); + tempThumbnail->Resize((*specIter).Width, (*specIter).Height); + + pthread_mutex_lock(&thumbnailQueueMutex); + thumbnailComplete.push_back(std::pair((*specIter).CompletedListener, tempThumbnail)); + pthread_mutex_unlock(&thumbnailQueueMutex); + } + } + else + { +#ifdef DEBUG + std::cout << typeid(*this).name() << " Request for " << req.ID.SaveID << ":" << req.ID.SaveDate << " failed with status " << status << std::endl; +#endif + if(data) + free(data); + } + iter = currentRequests.erase(iter); + } + else + { + ++iter; + } + } + + } + pthread_mutex_lock(&runningMutex); + thumbnailQueueRunning = false; + pthread_mutex_unlock(&runningMutex); +} + +void RequestBroker::RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener) +{ + RetrieveThumbnail(saveID, 0, width, height, tListener); +} + +bool RequestBroker::CheckThumbnailListener(ListenerHandle handle) +{ + pthread_mutex_lock(&listenersMutex); + int count = std::count(validListeners.begin(), validListeners.end(), handle); + pthread_mutex_unlock(&listenersMutex); + + return count; +} + +void RequestBroker::AttachThumbnailListener(ThumbnailListener * tListener) +{ + pthread_mutex_lock(&listenersMutex); + validListeners.push_back(ListenerHandle(tListener->ListenerRand, tListener)); + pthread_mutex_unlock(&listenersMutex); +} + +void RequestBroker::DetachThumbnailListener(ThumbnailListener * tListener) +{ + pthread_mutex_lock(&listenersMutex); + + std::vector::iterator iter = validListeners.begin(); + while (iter != validListeners.end()) + { + if(*iter == ListenerHandle(tListener->ListenerRand, tListener)) + iter = validListeners.erase(iter); + else + ++iter; + } + + pthread_mutex_unlock(&listenersMutex); +} \ No newline at end of file diff --git a/src/client/RequestBroker.h b/src/client/RequestBroker.h new file mode 100644 index 0000000..b3d1fc3 --- /dev/null +++ b/src/client/RequestBroker.h @@ -0,0 +1,121 @@ +#pragma once +#include +#include +#include +#include +#include +#undef GetUserName //God dammit microsoft! + +#include "Singleton.h" + +class GameSave; +class Thumbnail; +class ThumbnailListener; +typedef std::pair ListenerHandle; +class RequestBroker: public Singleton +{ +private: + class ThumbnailSpec + { + public: + int Width, Height; + ListenerHandle CompletedListener; + ThumbnailSpec(int width, int height, ListenerHandle completedListener) : + Width(width), Height(height), CompletedListener(completedListener) {} + }; + + class ThumbnailID + { + public: + int SaveID, SaveDate; + bool operator ==(const ThumbnailID & second) + { + return SaveID == second.SaveID && SaveDate == second.SaveDate; + } + ThumbnailID(int saveID, int saveDate) : SaveID(saveID), SaveDate(saveDate) {} + ThumbnailID() : SaveID(0), SaveDate(0) {} + }; + + class ThumbnailRequest + { + public: + bool Complete; + void * HTTPContext; + int RequestTime; + + ThumbnailID ID; + std::vector SubRequests; + + ThumbnailRequest(int saveID, int saveDate, int width, int height, ListenerHandle completedListener) : + ID(saveID, saveDate), Complete(false), HTTPContext(NULL), RequestTime(0) + { + SubRequests.push_back(ThumbnailSpec(width, height, completedListener)); + } + ThumbnailRequest() : Complete(false), HTTPContext(NULL), RequestTime(0) {} + }; + + class ThumbRenderRequest + { + public: + int Width, Height; + bool Decorations; + bool Fire; + GameSave * Save; + ListenerHandle CompletedListener; + ThumbRenderRequest(GameSave * save, bool decorations, bool fire, int width, int height, ListenerHandle completedListener) : + Save(save), Width(width), Height(height), CompletedListener(completedListener), Decorations(decorations), Fire(fire) {} + ThumbRenderRequest() : Save(0), Decorations(true), Fire(true), Width(0), Height(0), CompletedListener(ListenerHandle(0, (ThumbnailListener*)NULL)) {} + }; + + class Request + { + enum RequestType { Thumbnail, ThumbnailRender, HTTP }; + public: + RequestType Type; + void * RequestObject; + ListenerHandle Listener; + }; + + //Thumbnail retreival + /*int thumbnailCacheNextID; + Thumbnail * thumbnailCache[THUMB_CACHE_SIZE]; + void * activeThumbRequests[IMGCONNS]; + int activeThumbRequestTimes[IMGCONNS]; + int activeThumbRequestCompleteTimes[IMGCONNS]; + std::string activeThumbRequestIDs[IMGCONNS];*/ + + pthread_mutex_t thumbnailQueueMutex; + pthread_mutex_t listenersMutex; + pthread_mutex_t runningMutex; + pthread_t thumbnailQueueThread; + bool thumbnailQueueRunning; + std::deque thumbnailRequests; + std::deque renderRequests; + + std::deque > thumbnailComplete; + std::list currentRequests; + std::deque > thumbnailCache; + + std::vector validListeners; + + std::deque requestQueue; + + static void * thumbnailQueueProcessHelper(void * ref); + void thumbnailQueueProcessTH(); + void assureRunning(); + +public: + RequestBroker(); + virtual ~RequestBroker(); + void Shutdown(); + + void FlushThumbQueue(); + void RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener); + void RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener); + void RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener); + void RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener); + + bool CheckThumbnailListener(ListenerHandle handle); + void AttachThumbnailListener(ThumbnailListener * tListener); + void DetachThumbnailListener(ThumbnailListener * tListener); +}; \ No newline at end of file diff --git a/src/client/ThumbnailBroker.cpp b/src/client/ThumbnailBroker.cpp deleted file mode 100644 index 85fee3a..0000000 --- a/src/client/ThumbnailBroker.cpp +++ /dev/null @@ -1,392 +0,0 @@ -#include -#include -#include -#include -#include "ThumbnailBroker.h" -#include "ThumbnailListener.h" -#include "Client.h" -#include "HTTP.h" -#include "GameSave.h" -#include "search/Thumbnail.h" -#include "simulation/SaveRenderer.h" - -//Asynchronous Thumbnail render & request processing - -ThumbnailBroker::ThumbnailBroker() -{ - thumbnailQueueRunning = false; - //thumbnailQueueMutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_init (&thumbnailQueueMutex, NULL); - - //listenersMutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_init (&listenersMutex, NULL); - - - pthread_mutex_init (&runningMutex, NULL); -} - -ThumbnailBroker::~ThumbnailBroker() -{ - -} - -void ThumbnailBroker::assureRunning() -{ - pthread_mutex_lock(&runningMutex); - bool running = thumbnailQueueRunning; - thumbnailQueueRunning = true; - pthread_mutex_unlock(&runningMutex); - - if(!running) - { -#ifdef DEBUG - std::cout << typeid(*this).name() << " Starting background thread for new " << __FUNCTION__ << " request" << std::endl; -#endif - pthread_create(&thumbnailQueueThread, 0, &ThumbnailBroker::thumbnailQueueProcessHelper, this); - } -} - -void ThumbnailBroker::Shutdown() -{ - pthread_mutex_lock(&runningMutex); - if(thumbnailQueueRunning) - { - thumbnailQueueRunning = false; - pthread_mutex_unlock(&runningMutex); - pthread_join(thumbnailQueueThread, NULL); - } - else - pthread_mutex_unlock(&runningMutex); - - - for (std::list::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter) - { - ThumbnailRequest req = *iter; - if(req.HTTPContext) - { - http_async_req_close(req.HTTPContext); - } - } -} - -void ThumbnailBroker::RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener) -{ - RenderThumbnail(gameSave, true, true, width, height, tListener); -} - -void ThumbnailBroker::RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener) -{ - AttachThumbnailListener(tListener); - pthread_mutex_lock(&thumbnailQueueMutex); - renderRequests.push_back(ThumbRenderRequest(new GameSave(*gameSave), decorations, fire, width, height, ListenerHandle(tListener->ListenerRand, tListener))); - pthread_mutex_unlock(&thumbnailQueueMutex); - - assureRunning(); -} - -void ThumbnailBroker::RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener) -{ - AttachThumbnailListener(tListener); - pthread_mutex_lock(&thumbnailQueueMutex); - thumbnailRequests.push_back(ThumbnailRequest(saveID, saveDate, width, height, ListenerHandle(tListener->ListenerRand, tListener))); - pthread_mutex_unlock(&thumbnailQueueMutex); - - assureRunning(); -} - -void * ThumbnailBroker::thumbnailQueueProcessHelper(void * ref) -{ - ((ThumbnailBroker*)ref)->thumbnailQueueProcessTH(); - return NULL; -} - -void ThumbnailBroker::FlushThumbQueue() -{ - pthread_mutex_lock(&thumbnailQueueMutex); - while(thumbnailComplete.size()) - { - if(CheckThumbnailListener(thumbnailComplete.front().first)) - { - thumbnailComplete.front().first.second->OnThumbnailReady(thumbnailComplete.front().second); - } - else - { -#ifdef DEBUG - std::cout << typeid(*this).name() << " Listener lost, discarding request" << std::endl; -#endif - delete thumbnailComplete.front().second; - } - thumbnailComplete.pop_front(); - } - pthread_mutex_unlock(&thumbnailQueueMutex); -} - -void ThumbnailBroker::thumbnailQueueProcessTH() -{ - time_t lastAction = time(NULL); - pthread_mutex_lock(&runningMutex); - thumbnailQueueRunning = true; - pthread_mutex_unlock(&runningMutex); - while(true) - { - //Shutdown after 2 seconds of idle - if(time(NULL) - lastAction > 2) - { -#ifdef DEBUG - std::cout << typeid(*this).name() << " Idle shutdown" << std::endl; -#endif - break; - } - - - pthread_mutex_lock(&runningMutex); - bool running = thumbnailQueueRunning; - pthread_mutex_unlock(&runningMutex); - if(!running) - { -#ifdef DEBUG - std::cout << typeid(*this).name() << " Requested shutdown" << std::endl; -#endif - break; - } - - - //Renderer - pthread_mutex_lock(&thumbnailQueueMutex); - if(renderRequests.size()) - { - lastAction = time(NULL); - ThumbRenderRequest req; - req = renderRequests.front(); - renderRequests.pop_front(); - pthread_mutex_unlock(&thumbnailQueueMutex); - -#ifdef DEBUG - std::cout << typeid(*this).name() << " Processing render request" << std::endl; -#endif - - Thumbnail * thumbnail = SaveRenderer::Ref().Render(req.Save, req.Decorations, req.Fire); - delete req.Save; - - if(thumbnail) - { - thumbnail->Resize(req.Width, req.Height); - - pthread_mutex_lock(&thumbnailQueueMutex); - thumbnailComplete.push_back(std::pair(req.CompletedListener, thumbnail)); - pthread_mutex_unlock(&thumbnailQueueMutex); - } - } - else - { - pthread_mutex_unlock(&thumbnailQueueMutex); - } - - //Renderer - pthread_mutex_lock(&thumbnailQueueMutex); - if(thumbnailRequests.size()) - { - lastAction = time(NULL); - Thumbnail * thumbnail = NULL; - - ThumbnailRequest req; - req = thumbnailRequests.front(); - - //Check the cache - for(std::deque >::iterator iter = thumbnailCache.begin(), end = thumbnailCache.end(); iter != end; ++iter) - { - if((*iter).first == req.ID) - { - thumbnail = (*iter).second; -#ifdef DEBUG - std::cout << typeid(*this).name() << " " << req.ID.SaveID << ":" << req.ID.SaveDate << " found in cache" << std::endl; -#endif - } - } - - if(thumbnail) - { - //Got thumbnail from cache - thumbnailRequests.pop_front(); - pthread_mutex_unlock(&thumbnailQueueMutex); - - for(std::vector::iterator specIter = req.SubRequests.begin(), specEnd = req.SubRequests.end(); specIter != specEnd; ++specIter) - { - Thumbnail * tempThumbnail = new Thumbnail(*thumbnail); - tempThumbnail->Resize((*specIter).Width, (*specIter).Height); - - pthread_mutex_lock(&thumbnailQueueMutex); - thumbnailComplete.push_back(std::pair((*specIter).CompletedListener, tempThumbnail)); - pthread_mutex_unlock(&thumbnailQueueMutex); - } - } - else - { - //Check for ongoing requests - bool requested = false; - for(std::list::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter) - { - if((*iter).ID == req.ID) - { - requested = true; - -#ifdef DEBUG - std::cout << typeid(*this).name() << " Request for " << req.ID.SaveID << ":" << req.ID.SaveDate << " found, appending." << std::endl; -#endif - - //Add the current listener to the item already being requested - (*iter).SubRequests.push_back(req.SubRequests.front()); - } - } - - if(requested) - { - //Already requested - thumbnailRequests.pop_front(); - pthread_mutex_unlock(&thumbnailQueueMutex); - } - else if(currentRequests.size() < IMGCONNS) //If it's not already being requested and we still have more space for a new connection, request it - { - thumbnailRequests.pop_front(); - pthread_mutex_unlock(&thumbnailQueueMutex); - - //If it's not already being requested, request it - std::stringstream urlStream; - urlStream << "http://" << STATICSERVER << "/" << req.ID.SaveID; - if(req.ID.SaveDate) - { - urlStream << "_" << req.ID.SaveDate; - } - urlStream << "_small.pti"; - -#ifdef DEBUG - std::cout << typeid(*this).name() << " Creating new request for " << req.ID.SaveID << ":" << req.ID.SaveDate << std::endl; -#endif - - req.HTTPContext = http_async_req_start(NULL, (char *)urlStream.str().c_str(), NULL, 0, 0); - req.RequestTime = time(NULL); - currentRequests.push_back(req); - } - else - { - //Already full of requests - pthread_mutex_unlock(&thumbnailQueueMutex); - - } - } - } - else - { - pthread_mutex_unlock(&thumbnailQueueMutex); - } - - std::list::iterator iter = currentRequests.begin(); - while (iter != currentRequests.end()) - { - lastAction = time(NULL); - - ThumbnailRequest req = *iter; - Thumbnail * thumbnail = NULL; - - if(http_async_req_status(req.HTTPContext)) - { - - pixel * thumbData; - char * data; - int status, data_size, imgw, imgh; - data = http_async_req_stop(req.HTTPContext, &status, &data_size); - - if (status == 200 && data) - { - thumbData = Graphics::ptif_unpack(data, data_size, &imgw, &imgh); - free(data); - - if(thumbData) - { - thumbnail = new Thumbnail(req.ID.SaveID, req.ID.SaveID, thumbData, ui::Point(imgw, imgh)); - free(thumbData); - } - else - { - //Error thumbnail - VideoBuffer errorThumb(128, 128); - errorThumb.SetCharacter(64, 64, 'x', 255, 255, 255, 255); - - thumbnail = new Thumbnail(req.ID.SaveID, req.ID.SaveID, errorThumb.Buffer, ui::Point(errorThumb.Width, errorThumb.Height)); - } - - if(thumbnailCache.size() >= THUMB_CACHE_SIZE) - { - delete thumbnailCache.front().second; - thumbnailCache.pop_front(); - } - thumbnailCache.push_back(std::pair(req.ID, thumbnail)); - - for(std::vector::iterator specIter = req.SubRequests.begin(), specEnd = req.SubRequests.end(); specIter != specEnd; ++specIter) - { - Thumbnail * tempThumbnail = new Thumbnail(*thumbnail); - tempThumbnail->Resize((*specIter).Width, (*specIter).Height); - - pthread_mutex_lock(&thumbnailQueueMutex); - thumbnailComplete.push_back(std::pair((*specIter).CompletedListener, tempThumbnail)); - pthread_mutex_unlock(&thumbnailQueueMutex); - } - } - else - { -#ifdef DEBUG - std::cout << typeid(*this).name() << " Request for " << req.ID.SaveID << ":" << req.ID.SaveDate << " failed with status " << status << std::endl; -#endif - if(data) - free(data); - } - iter = currentRequests.erase(iter); - } - else - { - ++iter; - } - } - - } - pthread_mutex_lock(&runningMutex); - thumbnailQueueRunning = false; - pthread_mutex_unlock(&runningMutex); -} - -void ThumbnailBroker::RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener) -{ - RetrieveThumbnail(saveID, 0, width, height, tListener); -} - -bool ThumbnailBroker::CheckThumbnailListener(ListenerHandle handle) -{ - pthread_mutex_lock(&listenersMutex); - int count = std::count(validListeners.begin(), validListeners.end(), handle); - pthread_mutex_unlock(&listenersMutex); - - return count; -} - -void ThumbnailBroker::AttachThumbnailListener(ThumbnailListener * tListener) -{ - pthread_mutex_lock(&listenersMutex); - validListeners.push_back(ListenerHandle(tListener->ListenerRand, tListener)); - pthread_mutex_unlock(&listenersMutex); -} - -void ThumbnailBroker::DetachThumbnailListener(ThumbnailListener * tListener) -{ - pthread_mutex_lock(&listenersMutex); - - std::vector::iterator iter = validListeners.begin(); - while (iter != validListeners.end()) - { - if(*iter == ListenerHandle(tListener->ListenerRand, tListener)) - iter = validListeners.erase(iter); - else - ++iter; - } - - pthread_mutex_unlock(&listenersMutex); -} \ No newline at end of file diff --git a/src/client/ThumbnailBroker.h b/src/client/ThumbnailBroker.h deleted file mode 100644 index 5160479..0000000 --- a/src/client/ThumbnailBroker.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#undef GetUserName //God dammit microsoft! - -#include "Singleton.h" - -class GameSave; -class Thumbnail; -class ThumbnailListener; -typedef std::pair ListenerHandle; -class ThumbnailBroker: public Singleton -{ -private: - class ThumbnailSpec - { - public: - int Width, Height; - ListenerHandle CompletedListener; - ThumbnailSpec(int width, int height, ListenerHandle completedListener) : - Width(width), Height(height), CompletedListener(completedListener) {} - }; - - class ThumbnailID - { - public: - int SaveID, SaveDate; - bool operator ==(const ThumbnailID & second) - { - return SaveID == second.SaveID && SaveDate == second.SaveDate; - } - ThumbnailID(int saveID, int saveDate) : SaveID(saveID), SaveDate(saveDate) {} - ThumbnailID() : SaveID(0), SaveDate(0) {} - }; - - class ThumbnailRequest - { - public: - bool Complete; - void * HTTPContext; - int RequestTime; - - ThumbnailID ID; - std::vector SubRequests; - - ThumbnailRequest(int saveID, int saveDate, int width, int height, ListenerHandle completedListener) : - ID(saveID, saveDate), Complete(false), HTTPContext(NULL), RequestTime(0) - { - SubRequests.push_back(ThumbnailSpec(width, height, completedListener)); - } - ThumbnailRequest() : Complete(false), HTTPContext(NULL), RequestTime(0) {} - }; - - class ThumbRenderRequest - { - public: - int Width, Height; - bool Decorations; - bool Fire; - GameSave * Save; - ListenerHandle CompletedListener; - ThumbRenderRequest(GameSave * save, bool decorations, bool fire, int width, int height, ListenerHandle completedListener) : - Save(save), Width(width), Height(height), CompletedListener(completedListener), Decorations(decorations), Fire(fire) {} - ThumbRenderRequest() : Save(0), Decorations(true), Fire(true), Width(0), Height(0), CompletedListener(ListenerHandle(0, (ThumbnailListener*)NULL)) {} - }; - - //Thumbnail retreival - /*int thumbnailCacheNextID; - Thumbnail * thumbnailCache[THUMB_CACHE_SIZE]; - void * activeThumbRequests[IMGCONNS]; - int activeThumbRequestTimes[IMGCONNS]; - int activeThumbRequestCompleteTimes[IMGCONNS]; - std::string activeThumbRequestIDs[IMGCONNS];*/ - - pthread_mutex_t thumbnailQueueMutex; - pthread_mutex_t listenersMutex; - pthread_mutex_t runningMutex; - pthread_t thumbnailQueueThread; - bool thumbnailQueueRunning; - std::deque thumbnailRequests; - std::deque renderRequests; - - std::deque > thumbnailComplete; - std::list currentRequests; - std::deque > thumbnailCache; - - - std::vector validListeners; - - static void * thumbnailQueueProcessHelper(void * ref); - void thumbnailQueueProcessTH(); - void assureRunning(); - -public: - ThumbnailBroker(); - virtual ~ThumbnailBroker(); - void Shutdown(); - - void FlushThumbQueue(); - void RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener); - void RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener); - void RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener); - void RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener); - - bool CheckThumbnailListener(ListenerHandle handle); - void AttachThumbnailListener(ThumbnailListener * tListener); - void DetachThumbnailListener(ThumbnailListener * tListener); -}; \ No newline at end of file diff --git a/src/graphics/Graphics.cpp b/src/graphics/Graphics.cpp index 068cc5d..3394ab2 100644 --- a/src/graphics/Graphics.cpp +++ b/src/graphics/Graphics.cpp @@ -35,10 +35,25 @@ VideoBuffer::VideoBuffer(VideoBuffer * old): std::copy(old->Buffer, old->Buffer+(old->Width*old->Height), Buffer); }; +VideoBuffer::VideoBuffer(pixel * buffer, int width, int height): + Width(width), + Height(height) +{ + Buffer = new pixel[width*height]; + std::copy(buffer, buffer+(width*height), Buffer); +} + void VideoBuffer::Resize(float factor, bool resample) { int newWidth = ((float)Width)*factor; int newHeight = ((float)Height)*factor; + Resize(newWidth, newHeight); +} + +void VideoBuffer::Resize(int width, int height, bool resample) +{ + int newWidth = width; + int newHeight = height; pixel * newBuffer; if(resample) newBuffer = Graphics::resample_img(Buffer, Width, Height, newWidth, newHeight); diff --git a/src/graphics/Graphics.h b/src/graphics/Graphics.h index 2c90074..596d93d 100644 --- a/src/graphics/Graphics.h +++ b/src/graphics/Graphics.h @@ -110,8 +110,10 @@ public: VideoBuffer(const VideoBuffer & old); VideoBuffer(VideoBuffer * old); + VideoBuffer(pixel * buffer, int width, int height); VideoBuffer(int width, int height); void Resize(float factor, bool resample = false); + void Resize(int width, int height, bool resample = false); TPT_INLINE void BlendPixel(int x, int y, int r, int g, int b, int a) { #ifdef PIX32OGL diff --git a/src/interface/AvatarButton.cpp b/src/interface/AvatarButton.cpp new file mode 100644 index 0000000..0343aed --- /dev/null +++ b/src/interface/AvatarButton.cpp @@ -0,0 +1,110 @@ +#include +#include + +#include "AvatarButton.h" +#include "Format.h" +#include "Engine.h" +#include "client/Client.h" +#include "graphics/Graphics.h" +#include "ContextMenu.h" +#include "Keys.h" + +namespace ui { + +AvatarButton::AvatarButton(Point position, Point size, std::string username): + Component(position, size), + name(username), + actionCallback(NULL), + avatar(NULL), + tried(false) +{ + +} + +AvatarButton::~AvatarButton() +{ + if(avatar) + delete avatar; + if(actionCallback) + delete actionCallback; +} + +void AvatarButton::Tick(float dt) +{ + if(!avatar && !tried && name.size() > 0) + { + tried = true; + avatar = Client::Ref().GetAvatar(name); + if(avatar) { + if(avatar->Width != Size.X && avatar->Height != Size.Y) + { + avatar->Resize(Size.X, Size.Y, true); + } + } + } +} + +void AvatarButton::Draw(const Point& screenPos) +{ + Graphics * g = ui::Engine::Ref().g; + + if(avatar) + { + g->draw_image(avatar, screenPos.X, screenPos.Y, 255); + } +} + +void AvatarButton::OnMouseUnclick(int x, int y, unsigned int button) +{ + if(button != 1) + { + return; //left click only! + } + + if(isButtonDown) + { + isButtonDown = false; + DoAction(); + } +} + +void AvatarButton::OnContextMenuAction(int item) +{ + //Do nothing +} + +void AvatarButton::OnMouseClick(int x, int y, unsigned int button) +{ + if(button == BUTTON_RIGHT) + { + if(menu) + menu->Show(GetScreenPos() + ui::Point(x, y)); + } + else + { + isButtonDown = true; + } +} + +void AvatarButton::OnMouseEnter(int x, int y) +{ + isMouseInside = true; +} + +void AvatarButton::OnMouseLeave(int x, int y) +{ + isMouseInside = false; +} + +void AvatarButton::DoAction() +{ + if(actionCallback) + actionCallback->ActionCallback(this); +} + +void AvatarButton::SetActionCallback(AvatarButtonAction * action) +{ + actionCallback = action; +} + +} /* namespace ui */ diff --git a/src/interface/AvatarButton.h b/src/interface/AvatarButton.h new file mode 100644 index 0000000..b336256 --- /dev/null +++ b/src/interface/AvatarButton.h @@ -0,0 +1,51 @@ +#ifndef AVATARBUTTON_H_ +#define AVATARBUTTON_H_ + +#include + +#include "Component.h" +#include "graphics/Graphics.h" +#include "interface/Colour.h" + +namespace ui +{ +class AvatarButton; +class AvatarButtonAction +{ +public: + virtual void ActionCallback(ui::AvatarButton * sender) {} + virtual ~AvatarButtonAction() {} +}; + +class AvatarButton : public Component +{ + VideoBuffer * avatar; + std::string name; + bool tried; +public: + AvatarButton(Point position, Point size, std::string username); + virtual ~AvatarButton(); + + virtual void OnMouseClick(int x, int y, unsigned int button); + virtual void OnMouseUnclick(int x, int y, unsigned int button); + + virtual void OnMouseEnter(int x, int y); + virtual void OnMouseLeave(int x, int y); + + virtual void OnContextMenuAction(int item); + + virtual void Draw(const Point& screenPos); + virtual void Tick(float dt); + + virtual void DoAction(); + + void SetUsername(std::string username) { name = username; } + std::string GetUsername() { return name; } + void SetActionCallback(AvatarButtonAction * action); +protected: + bool isMouseInside, isButtonDown; + AvatarButtonAction * actionCallback; +}; +} +#endif /* AVATARBUTTON_H_ */ + diff --git a/src/interface/SaveButton.cpp b/src/interface/SaveButton.cpp index c5840c8..6e42169 100644 --- a/src/interface/SaveButton.cpp +++ b/src/interface/SaveButton.cpp @@ -5,7 +5,7 @@ #include "client/SaveInfo.h" #include "graphics/Graphics.h" #include "Engine.h" -#include "client/ThumbnailBroker.h" +#include "client/RequestBroker.h" #include "simulation/SaveRenderer.h" #include "Format.h" #include "ContextMenu.h" @@ -117,7 +117,7 @@ SaveButton::SaveButton(Point position, Point size, SaveFile * file): SaveButton::~SaveButton() { - ThumbnailBroker::Ref().DetachThumbnailListener(this); + RequestBroker::Ref().DetachThumbnailListener(this); if(thumbnail) delete thumbnail; @@ -149,18 +149,18 @@ void SaveButton::Tick(float dt) if(save->GetGameSave()) { waitingForThumb = true; - ThumbnailBroker::Ref().RenderThumbnail(save->GetGameSave(), Size.X-3, Size.Y-25, this); + RequestBroker::Ref().RenderThumbnail(save->GetGameSave(), Size.X-3, Size.Y-25, this); } else if(save->GetID()) { waitingForThumb = true; - ThumbnailBroker::Ref().RetrieveThumbnail(save->GetID(), save->GetVersion(), Size.X-3, Size.Y-25, this); + RequestBroker::Ref().RetrieveThumbnail(save->GetID(), save->GetVersion(), Size.X-3, Size.Y-25, this); } } else if(file && file->GetGameSave()) { waitingForThumb = true; - ThumbnailBroker::Ref().RenderThumbnail(file->GetGameSave(), Size.X-3, Size.Y-25, this); + RequestBroker::Ref().RenderThumbnail(file->GetGameSave(), Size.X-3, Size.Y-25, this); } } } diff --git a/src/preview/PreviewView.cpp b/src/preview/PreviewView.cpp index 005cef9..b9bae9a 100644 --- a/src/preview/PreviewView.cpp +++ b/src/preview/PreviewView.cpp @@ -12,6 +12,7 @@ #include "search/Thumbnail.h" #include "client/Client.h" #include "interface/ScrollPanel.h" +#include "interface/AvatarButton.h" #include "interface/Keys.h" class PreviewView::LoginAction: public ui::ButtonAction @@ -52,7 +53,8 @@ PreviewView::PreviewView(): doOpen(false), addCommentBox(NULL), submitCommentButton(NULL), - commentBoxHeight(20) + commentBoxHeight(20), + showAvatars(true) { class FavAction: public ui::ButtonAction { @@ -133,23 +135,38 @@ PreviewView::PreviewView(): browserOpenButton->SetActionCallback(new BrowserOpenAction(this)); AddComponent(browserOpenButton); - saveNameLabel = new ui::Label(ui::Point(5, (YRES/2)+4), ui::Point(100, 16), ""); + if(showAvatars) + saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(100, 16), ""); + else + saveNameLabel = new ui::Label(ui::Point(5, (YRES/2)+4), ui::Point(100, 16), ""); saveNameLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; saveNameLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; AddComponent(saveNameLabel); - saveDescriptionLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15+17), ui::Point((XRES/2)-10, Size.Y-((YRES/2)+4+15+17)-21), ""); + if(showAvatars) + saveDescriptionLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15+21), ui::Point((XRES/2)-10, Size.Y-((YRES/2)+4+15+17)-25), ""); + else + saveDescriptionLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15+19), ui::Point((XRES/2)-10, Size.Y-((YRES/2)+4+15+17)-23), ""); saveDescriptionLabel->SetMultiline(true); saveDescriptionLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; saveDescriptionLabel->Appearance.VerticalAlign = ui::Appearance::AlignTop; saveDescriptionLabel->SetTextColour(ui::Colour(180, 180, 180)); AddComponent(saveDescriptionLabel); - authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15), ui::Point(200, 16), ""); + if(showAvatars) + authorDateLabel = new ui::Label(ui::Point(39, (YRES/2)+4+15), ui::Point(180, 16), ""); + else + authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15), ui::Point(200, 16), ""); authorDateLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; authorDateLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; AddComponent(authorDateLabel); + if(showAvatars) + { + avatarButton = new ui::AvatarButton(ui::Point(4, (YRES/2)+4), ui::Point(34, 34), ""); + AddComponent(avatarButton); + } + viewsLabel = new ui::Label(ui::Point((XRES/2)-80, (YRES/2)+4+15), ui::Point(80, 16), ""); viewsLabel->Appearance.HorizontalAlign = ui::Appearance::AlignRight; viewsLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle; @@ -373,7 +390,14 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender) votesUp = save->votesUp; votesDown = save->votesDown; saveNameLabel->SetText(save->name); - authorDateLabel->SetText("\bgAuthor:\bw " + save->userName + " \bgDate:\bw " + format::UnixtimeToDateMini(save->date)); + if(showAvatars) { + avatarButton->SetUsername(save->userName); + authorDateLabel->SetText("\bw" + save->userName + " \bgDate:\bw " + format::UnixtimeToDateMini(save->date)); + } + else + { + authorDateLabel->SetText("\bgAuthor:\bw " + save->userName + " \bgDate:\bw " + format::UnixtimeToDateMini(save->date)); + } viewsLabel->SetText("\bgViews:\bw " + format::NumberToString(save->Views)); saveDescriptionLabel->SetText(save->Description); if(save->Favourite) @@ -513,10 +537,21 @@ void PreviewView::NotifyCommentsChanged(PreviewModel * sender) int currentY = 0;//-yOffset; ui::Label * tempUsername; ui::Label * tempComment; + ui::AvatarButton * tempAvatar; for(int i = 0; i < comments->size(); i++) { int usernameY = currentY+5, commentY; - tempUsername = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName); + if(showAvatars) + { + tempAvatar = new ui::AvatarButton(ui::Point(4, currentY+4), ui::Point(26, 26), comments->at(i)->authorName); + commentComponents.push_back(tempAvatar); + commentsPanel->AddChild(tempAvatar); + } + + if(showAvatars) + tempUsername = new ui::Label(ui::Point(31, currentY+5), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName); + else + tempUsername = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName); tempUsername->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; tempUsername->Appearance.VerticalAlign = ui::Appearance::AlignBottom; currentY += 16; @@ -524,7 +559,6 @@ void PreviewView::NotifyCommentsChanged(PreviewModel * sender) commentComponents.push_back(tempUsername); commentsPanel->AddChild(tempUsername); - commentY = currentY+5; tempComment = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), -1), comments->at(i)->comment); tempComment->SetMultiline(true); diff --git a/src/preview/PreviewView.h b/src/preview/PreviewView.h index 03a3a47..1a01f9b 100644 --- a/src/preview/PreviewView.h +++ b/src/preview/PreviewView.h @@ -14,6 +14,7 @@ namespace ui { class ScrollPanel; + class AvatarButton; } class PreviewModel; @@ -32,6 +33,7 @@ class PreviewView: public ui::Window { ui::Textbox * addCommentBox; ui::Label * saveNameLabel; ui::Label * authorDateLabel; + ui::AvatarButton * avatarButton; ui::Label * pageInfo; ui::Label * saveDescriptionLabel; ui::Label * viewsLabel; @@ -42,6 +44,7 @@ class PreviewView: public ui::Window { int votesUp; int votesDown; bool doOpen; + bool showAvatars; int commentBoxHeight; float commentBoxPositionX; diff --git a/src/save/LocalSaveActivity.cpp b/src/save/LocalSaveActivity.cpp index 96296f0..193f0aa 100644 --- a/src/save/LocalSaveActivity.cpp +++ b/src/save/LocalSaveActivity.cpp @@ -3,7 +3,7 @@ #include "interface/Textbox.h" #include "interface/Button.h" #include "search/Thumbnail.h" -#include "client/ThumbnailBroker.h" +#include "client/RequestBroker.h" #include "dialogues/ErrorMessage.h" #include "dialogues/ConfirmPrompt.h" #include "client/Client.h" @@ -67,7 +67,7 @@ LocalSaveActivity::LocalSaveActivity(SaveFile save, FileSavedCallback * callback SetOkayButton(okayButton); if(save.GetGameSave()) - ThumbnailBroker::Ref().RenderThumbnail(save.GetGameSave(), true, false, Size.X-16, -1, this); + RequestBroker::Ref().RenderThumbnail(save.GetGameSave(), true, false, Size.X-16, -1, this); } void LocalSaveActivity::Save() diff --git a/src/save/ServerSaveActivity.cpp b/src/save/ServerSaveActivity.cpp index a666a73..fc10814 100644 --- a/src/save/ServerSaveActivity.cpp +++ b/src/save/ServerSaveActivity.cpp @@ -4,7 +4,7 @@ #include "interface/Button.h" #include "interface/Checkbox.h" #include "search/Thumbnail.h" -#include "client/ThumbnailBroker.h" +#include "client/RequestBroker.h" #include "dialogues/ErrorMessage.h" #include "dialogues/ConfirmPrompt.h" #include "client/Client.h" @@ -132,7 +132,7 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, ServerSaveActivity::SaveUp SetOkayButton(okayButton); if(save.GetGameSave()) - ThumbnailBroker::Ref().RenderThumbnail(save.GetGameSave(), false, true, (Size.X/2)-16, -1, this); + RequestBroker::Ref().RenderThumbnail(save.GetGameSave(), false, true, (Size.X/2)-16, -1, this); } ServerSaveActivity::ServerSaveActivity(SaveInfo save, bool saveNow, ServerSaveActivity::SaveUploadedCallback * callback) : -- cgit v0.9.2-21-gd62e