summaryrefslogtreecommitdiff
path: root/src/gui/search
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2013-03-24 12:24:17 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2013-03-24 12:24:17 (GMT)
commit9b5b85f9b01cbda7ef9a7ec2a15b2a35630a5b9d (patch)
treeac7d040253b459ce102e476cb19ab59e3cfa90d7 /src/gui/search
parent6bf98ccdca39936a3c51367862eed7c49f8786ec (diff)
parentbdc69f31c0be94191015838886bdcc2bc67f1acb (diff)
downloadpowder-9b5b85f9b01cbda7ef9a7ec2a15b2a35630a5b9d.zip
powder-9b5b85f9b01cbda7ef9a7ec2a15b2a35630a5b9d.tar.gz
Merge branch 'reorganisation' of github.com:FacialTurd/The-Powder-Toy
Diffstat (limited to 'src/gui/search')
-rw-r--r--src/gui/search/SearchController.cpp364
-rw-r--r--src/gui/search/SearchController.h51
-rw-r--r--src/gui/search/SearchModel.cpp283
-rw-r--r--src/gui/search/SearchModel.h83
-rw-r--r--src/gui/search/SearchView.cpp718
-rw-r--r--src/gui/search/SearchView.h74
-rw-r--r--src/gui/search/Thumbnail.cpp73
-rw-r--r--src/gui/search/Thumbnail.h25
8 files changed, 1671 insertions, 0 deletions
diff --git a/src/gui/search/SearchController.cpp b/src/gui/search/SearchController.cpp
new file mode 100644
index 0000000..b881962
--- /dev/null
+++ b/src/gui/search/SearchController.cpp
@@ -0,0 +1,364 @@
+#include <string>
+#include <sstream>
+#include <time.h>
+#include "SearchController.h"
+#include "SearchModel.h"
+#include "SearchView.h"
+#include "gui/interface/Panel.h"
+#include "gui/dialogues/ConfirmPrompt.h"
+#include "gui/dialogues/ErrorMessage.h"
+#include "gui/preview/PreviewController.h"
+#include "client/Client.h"
+#include "tasks/Task.h"
+#include "tasks/TaskWindow.h"
+
+class SearchController::OpenCallback: public ControllerCallback
+{
+ SearchController * cc;
+public:
+ OpenCallback(SearchController * cc_) { cc = cc_; }
+ virtual void ControllerExit()
+ {
+ if(cc->activePreview->GetDoOpen() && cc->activePreview->GetSave())
+ {
+ cc->searchModel->SetLoadedSave(cc->activePreview->GetSave());
+ }
+ else
+ {
+ cc->searchModel->SetLoadedSave(NULL);
+ }
+
+ }
+};
+
+SearchController::SearchController(ControllerCallback * callback):
+ activePreview(NULL),
+ HasExited(false),
+ nextQueryTime(0.0f),
+ nextQueryDone(true),
+ searchModel(NULL)
+{
+ searchModel = new SearchModel();
+ searchView = new SearchView();
+ searchModel->AddObserver(searchView);
+ searchView->AttachController(this);
+
+ searchModel->UpdateSaveList(1, "");
+
+ this->callback = callback;
+
+ //Set up interface
+ //windowPanel.AddChild();
+}
+
+SaveInfo * SearchController::GetLoadedSave()
+{
+ return searchModel->GetLoadedSave();
+}
+
+void SearchController::ReleaseLoadedSave()
+{
+ searchModel->SetLoadedSave(NULL);
+}
+
+void SearchController::Update()
+{
+ if(!nextQueryDone && nextQueryTime < clock())
+ {
+ nextQueryDone = true;
+ searchModel->UpdateSaveList(1, nextQuery);
+ }
+ searchModel->Update();
+ if(activePreview && activePreview->HasExited)
+ {
+ delete activePreview;
+ activePreview = NULL;
+ if(searchModel->GetLoadedSave())
+ {
+ Exit();
+ }
+ }
+}
+
+void SearchController::Exit()
+{
+ if(ui::Engine::Ref().GetWindow() == searchView)
+ {
+ ui::Engine::Ref().CloseWindow();
+ }
+ if(callback)
+ callback->ControllerExit();
+ //HasExited = true;
+}
+
+SearchController::~SearchController()
+{
+ if(activePreview)
+ delete activePreview;
+ if(ui::Engine::Ref().GetWindow() == searchView)
+ {
+ ui::Engine::Ref().CloseWindow();
+ }
+ delete searchModel;
+ delete searchView;
+ delete callback;
+}
+
+void SearchController::DoSearch(std::string query, bool now)
+{
+ nextQuery = query;
+ if(!now)
+ {
+ nextQueryTime = clock()+(0.6 * CLOCKS_PER_SEC);
+ nextQueryDone = false;
+ }
+ else
+ {
+ nextQueryDone = true;
+ searchModel->UpdateSaveList(1, nextQuery);
+ }
+ //searchModel->UpdateSaveList(1, query);
+}
+
+void SearchController::PrevPage()
+{
+ if(searchModel->GetPageNum()>1)
+ searchModel->UpdateSaveList(searchModel->GetPageNum()-1, searchModel->GetLastQuery());
+}
+
+void SearchController::NextPage()
+{
+ if(searchModel->GetPageNum() <= searchModel->GetPageCount())
+ searchModel->UpdateSaveList(searchModel->GetPageNum()+1, searchModel->GetLastQuery());
+}
+
+void SearchController::ChangeSort()
+{
+ if(searchModel->GetSort() == "new")
+ {
+ searchModel->SetSort("best");
+ }
+ else
+ {
+ searchModel->SetSort("new");
+ }
+ searchModel->UpdateSaveList(1, searchModel->GetLastQuery());
+}
+
+void SearchController::ShowOwn(bool show)
+{
+ if(Client::Ref().GetAuthUser().ID)
+ {
+ searchModel->SetShowFavourite(false);
+ searchModel->SetShowOwn(show);
+ }
+ else
+ searchModel->SetShowOwn(false);
+ searchModel->UpdateSaveList(1, searchModel->GetLastQuery());
+}
+
+void SearchController::ShowFavourite(bool show)
+{
+ if(Client::Ref().GetAuthUser().ID)
+ {
+ searchModel->SetShowOwn(false);
+ searchModel->SetShowFavourite(show);
+ }
+ else
+ searchModel->SetShowFavourite(false);
+ searchModel->UpdateSaveList(1, searchModel->GetLastQuery());
+}
+
+void SearchController::Selected(int saveID, bool selected)
+{
+ if(!Client::Ref().GetAuthUser().ID)
+ return;
+
+ if(selected)
+ searchModel->SelectSave(saveID);
+ else
+ searchModel->DeselectSave(saveID);
+}
+
+void SearchController::OpenSave(int saveID)
+{
+ if(activePreview)
+ delete activePreview;
+ activePreview = new PreviewController(saveID, new OpenCallback(this));
+ ui::Engine::Ref().ShowWindow(activePreview->GetView());
+}
+
+void SearchController::OpenSave(int saveID, int saveDate)
+{
+ if(activePreview)
+ delete activePreview;
+ activePreview = new PreviewController(saveID, saveDate, new OpenCallback(this));
+ ui::Engine::Ref().ShowWindow(activePreview->GetView());
+}
+
+void SearchController::ClearSelection()
+{
+ searchModel->ClearSelected();
+}
+
+void SearchController::RemoveSelected()
+{
+ class RemoveSelectedConfirmation: public ConfirmDialogueCallback {
+ public:
+ SearchController * c;
+ RemoveSelectedConfirmation(SearchController * c_) { c = c_; }
+ virtual void ConfirmCallback(ConfirmPrompt::DialogueResult result) {
+ if (result == ConfirmPrompt::ResultOkay)
+ c->removeSelectedC();
+ }
+ virtual ~RemoveSelectedConfirmation() { }
+ };
+
+ std::stringstream desc;
+ desc << "Are you sure you want to delete " << searchModel->GetSelected().size() << " save";
+ if(searchModel->GetSelected().size()>1)
+ desc << "s";
+ new ConfirmPrompt("Delete saves", desc.str(), new RemoveSelectedConfirmation(this));
+}
+
+void SearchController::removeSelectedC()
+{
+ class RemoveSavesTask : public Task
+ {
+ std::vector<int> saves;
+ public:
+ RemoveSavesTask(std::vector<int> saves_) { saves = saves_; }
+ virtual bool doWork()
+ {
+ for(int i = 0; i < saves.size(); i++)
+ {
+ std::stringstream saveID;
+ saveID << "Deleting save [" << saves[i] << "] ...";
+ notifyStatus(saveID.str());
+ if(Client::Ref().DeleteSave(saves[i])!=RequestOkay)
+ {
+ std::stringstream saveIDF;
+ saveIDF << "\boFailed to delete [" << saves[i] << "] ...";
+ notifyStatus(saveIDF.str());
+ }
+ notifyProgress((float(i+1)/float(saves.size())*100));
+ }
+ return true;
+ }
+ };
+
+ std::vector<int> selected = searchModel->GetSelected();
+ new TaskWindow("Removing saves", new RemoveSavesTask(selected));
+ ClearSelection();
+ searchModel->UpdateSaveList(searchModel->GetPageNum(), searchModel->GetLastQuery());
+}
+
+void SearchController::UnpublishSelected()
+{
+ class UnpublishSelectedConfirmation: public ConfirmDialogueCallback {
+ public:
+ SearchController * c;
+ UnpublishSelectedConfirmation(SearchController * c_) { c = c_; }
+ virtual void ConfirmCallback(ConfirmPrompt::DialogueResult result) {
+ if (result == ConfirmPrompt::ResultOkay)
+ c->unpublishSelectedC();
+ }
+ virtual ~UnpublishSelectedConfirmation() { }
+ };
+
+ std::stringstream desc;
+ desc << "Are you sure you want to hide " << searchModel->GetSelected().size() << " save";
+ if(searchModel->GetSelected().size()>1)
+ desc << "s";
+ new ConfirmPrompt("Unpublish saves", desc.str(), new UnpublishSelectedConfirmation(this));
+}
+
+void SearchController::unpublishSelectedC()
+{
+ class UnpublishSavesTask : public Task
+ {
+ std::vector<int> saves;
+ public:
+ UnpublishSavesTask(std::vector<int> saves_) { saves = saves_; }
+ virtual bool doWork()
+ {
+ for(int i = 0; i < saves.size(); i++)
+ {
+ std::stringstream saveID;
+ saveID << "Hiding save [" << saves[i] << "] ...";
+ notifyStatus(saveID.str());
+ if(Client::Ref().UnpublishSave(saves[i])!=RequestOkay)
+ {
+ std::stringstream saveIDF;
+ saveIDF << "\boFailed to hide [" << saves[i] << "] ...";
+ notifyStatus(saveIDF.str());
+ }
+ notifyProgress((float(i+1)/float(saves.size())*100));
+ }
+ return true;
+ }
+ };
+
+ std::vector<int> selected = searchModel->GetSelected();
+ new TaskWindow("Unpublishing saves", new UnpublishSavesTask(selected));
+ ClearSelection();
+ searchModel->UpdateSaveList(searchModel->GetPageNum(), searchModel->GetLastQuery());
+}
+
+void SearchController::FavouriteSelected()
+{
+ class FavouriteSavesTask : public Task
+ {
+ std::vector<int> saves;
+ public:
+ FavouriteSavesTask(std::vector<int> saves_) { saves = saves_; }
+ virtual bool doWork()
+ {
+ for(int i = 0; i < saves.size(); i++)
+ {
+ std::stringstream saveID;
+ saveID << "Favouring save [" << saves[i] << "] ...";
+ notifyStatus(saveID.str());
+ if(Client::Ref().FavouriteSave(saves[i], true)!=RequestOkay)
+ {
+ std::stringstream saveIDF;
+ saveIDF << "\boFailed to favourite [" << saves[i] << "] ...";
+ notifyStatus(saveIDF.str());
+ }
+ notifyProgress((float(i+1)/float(saves.size())*100));
+ }
+ return true;
+ }
+ };
+
+ class UnfavouriteSavesTask : public Task
+ {
+ std::vector<int> saves;
+ public:
+ UnfavouriteSavesTask(std::vector<int> saves_) { saves = saves_; }
+ virtual bool doWork()
+ {
+ for(int i = 0; i < saves.size(); i++)
+ {
+ std::stringstream saveID;
+ saveID << "Unfavouring save [" << saves[i] << "] ...";
+ notifyStatus(saveID.str());
+ if(Client::Ref().FavouriteSave(saves[i], false)!=RequestOkay)
+ {
+ std::stringstream saveIDF;
+ saveIDF << "\boFailed to remove [" << saves[i] << "] ...";
+ notifyStatus(saveIDF.str());
+ }
+ notifyProgress((float(i+1)/float(saves.size())*100));
+ }
+ return true;
+ }
+ };
+
+ std::vector<int> selected = searchModel->GetSelected();
+ if(!searchModel->GetShowFavourite())
+ new TaskWindow("Favouring saves", new FavouriteSavesTask(selected));
+ else
+ new TaskWindow("Unfavouring saves", new UnfavouriteSavesTask(selected));
+ ClearSelection();
+}
diff --git a/src/gui/search/SearchController.h b/src/gui/search/SearchController.h
new file mode 100644
index 0000000..8d811ab
--- /dev/null
+++ b/src/gui/search/SearchController.h
@@ -0,0 +1,51 @@
+#ifndef SEARCHCONTROLLER_H
+#define SEARCHCONTROLLER_H
+
+#include "gui/interface/Panel.h"
+#include "SearchModel.h"
+#include "SearchView.h"
+#include "gui/preview/PreviewController.h"
+#include "Controller.h"
+#include "client/SaveInfo.h"
+
+class SearchView;
+class SearchModel;
+class SearchController
+{
+private:
+ SearchModel * searchModel;
+ SearchView * searchView;
+ PreviewController * activePreview;
+ ControllerCallback * callback;
+
+ double nextQueryTime;
+ std::string nextQuery;
+ bool nextQueryDone;
+ void removeSelectedC();
+ void unpublishSelectedC();
+public:
+ class OpenCallback;
+ bool HasExited;
+ SearchController(ControllerCallback * callback = NULL);
+ ~SearchController();
+ SearchView * GetView() { return searchView; }
+ void Exit();
+ void DoSearch(std::string query, bool now = false);
+ void NextPage();
+ void PrevPage();
+ void ChangeSort();
+ void ShowOwn(bool show);
+ void ShowFavourite(bool show);
+ void Selected(int saveID, bool selected);
+ void OpenSave(int saveID);
+ void OpenSave(int saveID, int saveDate);
+ void Update();
+ void ClearSelection();
+ void RemoveSelected();
+ void UnpublishSelected();
+ void FavouriteSelected();
+ void ReleaseLoadedSave();
+ SaveInfo * GetLoadedSave();
+};
+
+#endif // SEARCHCONTROLLER_H
diff --git a/src/gui/search/SearchModel.cpp b/src/gui/search/SearchModel.cpp
new file mode 100644
index 0000000..f4de2d6
--- /dev/null
+++ b/src/gui/search/SearchModel.cpp
@@ -0,0 +1,283 @@
+#include "SearchModel.h"
+#include "client/SaveInfo.h"
+
+#include "client/Client.h"
+
+SearchModel::SearchModel():
+ currentSort("best"),
+ showOwn(false),
+ showFavourite(false),
+ loadedSave(NULL),
+ updateSaveListWorking(false),
+ updateSaveListFinished(false),
+ updateTagListWorking(false),
+ updateTagListFinished(false),
+ saveListLoaded(false),
+ currentPage(1),
+ resultCount(0),
+ showTags(true)
+{
+}
+
+void SearchModel::SetShowTags(bool show)
+{
+ showTags = show;
+}
+
+bool SearchModel::GetShowTags()
+{
+ return showTags;
+}
+
+void * SearchModel::updateSaveListTHelper(void * obj)
+{
+ return ((SearchModel *)obj)->updateSaveListT();
+}
+
+void * SearchModel::updateSaveListT()
+{
+ std::string category = "";
+ if(showFavourite)
+ category = "Favourites";
+ if(showOwn && Client::Ref().GetAuthUser().ID)
+ category = "by:"+Client::Ref().GetAuthUser().Username;
+ vector<SaveInfo*> * saveList = Client::Ref().SearchSaves((currentPage-1)*20, 20, lastQuery, currentSort=="new"?"date":"votes", category, thResultCount);
+
+ updateSaveListFinished = true;
+ return saveList;
+}
+
+void * SearchModel::updateTagListTHelper(void * obj)
+{
+ return ((SearchModel *)obj)->updateTagListT();
+}
+
+void * SearchModel::updateTagListT()
+{
+ int tagResultCount;
+ std::vector<std::pair<std::string, int> > * tagList = Client::Ref().GetTags(0, 24, "", tagResultCount);
+
+ updateTagListFinished = true;
+ return tagList;
+}
+
+void SearchModel::UpdateSaveList(int pageNumber, std::string query)
+{
+ //Threading
+ if(!updateSaveListWorking)
+ {
+ lastQuery = query;
+ lastError = "";
+ saveListLoaded = false;
+ saveList.clear();
+ //resultCount = 0;
+ currentPage = pageNumber;
+
+ if(pageNumber == 1 && !showOwn && !showFavourite && currentSort == "best" && query == "")
+ SetShowTags(true);
+ else
+ SetShowTags(false);
+
+ notifySaveListChanged();
+ notifyTagListChanged();
+ notifyPageChanged();
+ selected.clear();
+ notifySelectedChanged();
+
+ if(GetShowTags() && !tagList.size() && !updateTagListWorking)
+ {
+ updateTagListFinished = false;
+ updateTagListWorking = true;
+ pthread_create(&updateTagListThread, 0, &SearchModel::updateTagListTHelper, this);
+ }
+
+ updateSaveListFinished = false;
+ updateSaveListWorking = true;
+ pthread_create(&updateSaveListThread, 0, &SearchModel::updateSaveListTHelper, this);
+ }
+}
+
+void SearchModel::SetLoadedSave(SaveInfo * save)
+{
+ if(loadedSave != save && loadedSave)
+ delete loadedSave;
+ if(save)
+ {
+ loadedSave = new SaveInfo(*save);
+ }
+ else
+ {
+ loadedSave = NULL;
+ }
+}
+
+SaveInfo * SearchModel::GetLoadedSave(){
+ return loadedSave;
+}
+
+vector<SaveInfo*> SearchModel::GetSaveList()
+{
+ return saveList;
+}
+
+vector<pair<string, int> > SearchModel::GetTagList()
+{
+ return tagList;
+}
+
+void SearchModel::Update()
+{
+ if(updateSaveListWorking)
+ {
+ if(updateSaveListFinished)
+ {
+ updateSaveListWorking = false;
+ lastError = "";
+ saveListLoaded = true;
+
+ vector<SaveInfo*> * tempSaveList;
+ pthread_join(updateSaveListThread, (void**)&tempSaveList);
+
+ if(tempSaveList)
+ {
+ saveList = *tempSaveList;
+ delete tempSaveList;
+ }
+
+ if(!saveList.size())
+ {
+ lastError = Client::Ref().GetLastError();
+ }
+
+ resultCount = thResultCount;
+ notifyPageChanged();
+ notifySaveListChanged();
+ }
+ }
+ if(updateTagListWorking)
+ {
+ if(updateTagListFinished)
+ {
+ updateTagListWorking = false;
+
+ vector<pair<string, int> > * tempTagList;
+ pthread_join(updateTagListThread, (void**)&tempTagList);
+
+ if(tempTagList)
+ {
+ tagList = *tempTagList;
+ delete tempTagList;
+ }
+ notifyTagListChanged();
+ }
+ }
+}
+
+void SearchModel::AddObserver(SearchView * observer)
+{
+ observers.push_back(observer);
+ observer->NotifySaveListChanged(this);
+ observer->NotifyPageChanged(this);
+ observer->NotifySortChanged(this);
+ observer->NotifyShowOwnChanged(this);
+ observer->NotifyTagListChanged(this);
+}
+
+void SearchModel::SelectSave(int saveID)
+{
+ for(int i = 0; i < selected.size(); i++)
+ {
+ if(selected[i]==saveID)
+ {
+ return;
+ }
+ }
+ selected.push_back(saveID);
+ notifySelectedChanged();
+}
+
+void SearchModel::DeselectSave(int saveID)
+{
+ bool changed = false;
+restart:
+ for(int i = 0; i < selected.size(); i++)
+ {
+ if(selected[i]==saveID)
+ {
+ selected.erase(selected.begin()+i);
+ changed = true;
+ goto restart; //Just ensure all cases are removed.
+ }
+ }
+ if(changed)
+ notifySelectedChanged();
+}
+
+void SearchModel::notifySaveListChanged()
+{
+ for(int i = 0; i < observers.size(); i++)
+ {
+ SearchView* cObserver = observers[i];
+ cObserver->NotifySaveListChanged(this);
+ }
+}
+
+void SearchModel::notifyTagListChanged()
+{
+ for(int i = 0; i < observers.size(); i++)
+ {
+ SearchView* cObserver = observers[i];
+ cObserver->NotifyTagListChanged(this);
+ }
+}
+
+void SearchModel::notifyPageChanged()
+{
+ for(int i = 0; i < observers.size(); i++)
+ {
+ SearchView* cObserver = observers[i];
+ cObserver->NotifyPageChanged(this);
+ }
+}
+
+void SearchModel::notifySortChanged()
+{
+ for(int i = 0; i < observers.size(); i++)
+ {
+ SearchView* cObserver = observers[i];
+ cObserver->NotifySortChanged(this);
+ }
+}
+
+void SearchModel::notifyShowOwnChanged()
+{
+ for(int i = 0; i < observers.size(); i++)
+ {
+ SearchView* cObserver = observers[i];
+ cObserver->NotifyShowOwnChanged(this);
+ }
+}
+
+void SearchModel::notifyShowFavouriteChanged()
+{
+ for(int i = 0; i < observers.size(); i++)
+ {
+ SearchView* cObserver = observers[i];
+ cObserver->NotifyShowOwnChanged(this);
+ }
+}
+
+void SearchModel::notifySelectedChanged()
+{
+ for(int i = 0; i < observers.size(); i++)
+ {
+ SearchView* cObserver = observers[i];
+ cObserver->NotifySelectedChanged(this);
+ }
+}
+
+SearchModel::~SearchModel()
+{
+ if(loadedSave)
+ delete loadedSave;
+}
diff --git a/src/gui/search/SearchModel.h b/src/gui/search/SearchModel.h
new file mode 100644
index 0000000..0fe9480
--- /dev/null
+++ b/src/gui/search/SearchModel.h
@@ -0,0 +1,83 @@
+#ifndef SEARCHMODEL_H
+#define SEARCHMODEL_H
+
+#include <vector>
+#include <string>
+#include <pthread.h>
+#undef GetUserName //God dammit microsoft!
+#include <cmath>
+#include "client/SaveInfo.h"
+#include "SearchView.h"
+
+using namespace std;
+
+class SearchView;
+class SearchModel
+{
+private:
+ SaveInfo * loadedSave;
+ string currentSort;
+ string lastQuery;
+ string lastError;
+ vector<int> selected;
+ vector<SearchView*> observers;
+ vector<SaveInfo*> saveList;
+ vector<pair<string, int> > tagList;
+ int currentPage;
+ int resultCount;
+ int thResultCount;
+ bool showOwn;
+ bool showFavourite;
+ bool showTags;
+ void notifySaveListChanged();
+ void notifyTagListChanged();
+ void notifySelectedChanged();
+ void notifyPageChanged();
+ void notifySortChanged();
+ void notifyShowOwnChanged();
+ void notifyShowFavouriteChanged();
+
+ //Variables and methods for background save request
+ bool saveListLoaded;
+ bool updateSaveListWorking;
+ volatile bool updateSaveListFinished;
+ pthread_t updateSaveListThread;
+ static void * updateSaveListTHelper(void * obj);
+ void * updateSaveListT();
+
+ bool updateTagListWorking;
+ volatile bool updateTagListFinished;
+ pthread_t updateTagListThread;
+ static void * updateTagListTHelper(void * obj);
+ void * updateTagListT();
+public:
+ SearchModel();
+ virtual ~SearchModel();
+
+ void SetShowTags(bool show);
+ bool GetShowTags();
+ void AddObserver(SearchView * observer);
+ void UpdateSaveList(int pageNumber, std::string query);
+ vector<SaveInfo*> GetSaveList();
+ vector<pair<string, int> > GetTagList();
+ string GetLastError() { return lastError; }
+ int GetPageCount() { return max(1, (int)(ceil(resultCount/16.0f))); }
+ int GetPageNum() { return currentPage; }
+ std::string GetLastQuery() { return lastQuery; }
+ void SetSort(string sort) { if(!updateSaveListWorking) { currentSort = sort; } notifySortChanged(); }
+ string GetSort() { return currentSort; }
+ void SetShowOwn(bool show) { if(!updateSaveListWorking) { if(show!=showOwn) { showOwn = show; } } notifyShowOwnChanged(); }
+ bool GetShowOwn() { return showOwn; }
+ void SetShowFavourite(bool show) { if(show!=showFavourite && !updateSaveListWorking) { showFavourite = show; } notifyShowFavouriteChanged(); }
+ bool GetShowFavourite() { return showFavourite; }
+ void SetLoadedSave(SaveInfo * save);
+ SaveInfo * GetLoadedSave();
+ bool GetSavesLoaded() { return saveListLoaded; }
+ vector<int> GetSelected() { return selected; }
+ void ClearSelected() { selected.clear(); notifySelectedChanged(); }
+ void SelectSave(int saveID);
+ void DeselectSave(int saveID);
+ void Update();
+};
+
+#endif // SEARCHMODEL_H
diff --git a/src/gui/search/SearchView.cpp b/src/gui/search/SearchView.cpp
new file mode 100644
index 0000000..902be77
--- /dev/null
+++ b/src/gui/search/SearchView.cpp
@@ -0,0 +1,718 @@
+#include <sstream>
+
+#include "SearchView.h"
+#include "client/Client.h"
+#include "gui/interface/Keys.h"
+#include "gui/interface/SaveButton.h"
+#include "gui/interface/Label.h"
+#include "gui/interface/RichLabel.h"
+#include "gui/interface/Textbox.h"
+#include "Misc.h"
+
+SearchView::SearchView():
+ ui::Window(ui::Point(0, 0), ui::Point(XRES+BARSIZE, YRES+MENUSIZE)),
+ saveButtons(vector<ui::SaveButton*>()),
+ errorLabel(NULL),
+ c(NULL)
+{
+
+ Client::Ref().AddListener(this);
+
+ nextButton = new ui::Button(ui::Point(XRES+BARSIZE-52, YRES+MENUSIZE-18), ui::Point(50, 16), "Next \x95");
+ previousButton = new ui::Button(ui::Point(1, YRES+MENUSIZE-18), ui::Point(50, 16), "\x96 Prev");
+ infoLabel = new ui::Label(ui::Point(260, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-520, 16), "Page 1 of 1");
+ tagsLabel = new ui::Label(ui::Point(270, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-540, 16), "\boPopular Tags:");
+ motdLabel = new ui::RichLabel(ui::Point(51, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-102, 16), Client::Ref().GetMessageOfTheDay());
+
+ class SearchAction : public ui::TextboxAction
+ {
+ SearchView * v;
+ public:
+ SearchAction(SearchView * _v) { v = _v; }
+ void TextChangedCallback(ui::Textbox * sender)
+ {
+ v->doSearch();
+ }
+ };
+ searchField = new ui::Textbox(ui::Point(60, 10), ui::Point((XRES+BARSIZE)-238, 17), "", "[search]");
+ searchField->Appearance.icon = IconSearch;
+ searchField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
+ searchField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
+ searchField->SetActionCallback(new SearchAction(this));
+
+
+ class SortAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ SortAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->ChangeSort();
+ }
+ };
+ sortButton = new ui::Button(ui::Point(XRES+BARSIZE-140, 10), ui::Point(61, 17), "Sort");
+ sortButton->SetIcon(IconVoteSort);
+ sortButton->SetTogglable(true);
+ sortButton->SetActionCallback(new SortAction(this));
+ sortButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
+ sortButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
+ AddComponent(sortButton);
+
+ class MyOwnAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ MyOwnAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->ShowOwn(sender->GetToggleState());
+ }
+ };
+ ownButton = new ui::Button(ui::Point(XRES+BARSIZE-70, 10), ui::Point(61, 17), "My Own");
+ ownButton->SetIcon(IconMyOwn);
+ ownButton->SetTogglable(true);
+ ownButton->SetActionCallback(new MyOwnAction(this));
+ ownButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
+ ownButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
+ AddComponent(ownButton);
+
+ class FavAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ FavAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->ShowFavourite(sender->GetToggleState());
+ }
+ };
+ favButton = new ui::Button(searchField->Position+ui::Point(searchField->Size.X+15, 0), ui::Point(17, 17), "");
+ favButton->SetIcon(IconFavourite);
+ favButton->SetTogglable(true);
+ favButton->Appearance.Margin.Left+=2;
+ favButton->SetActionCallback(new FavAction(this));
+ favButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
+ favButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
+ favButton->Appearance.BorderInactive = ui::Colour(170,170,170);
+ AddComponent(favButton);
+
+ class ClearSearchAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ ClearSearchAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->clearSearch();
+ }
+ };
+ ui::Button * clearSearchButton = new ui::Button(searchField->Position+ui::Point(searchField->Size.X-1, 0), ui::Point(17, 17), "");
+ clearSearchButton->SetIcon(IconClose);
+ clearSearchButton->SetActionCallback(new ClearSearchAction(this));
+ clearSearchButton->Appearance.Margin.Left+=2;
+ clearSearchButton->Appearance.Margin.Top+=2;
+ clearSearchButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
+ clearSearchButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
+ clearSearchButton->Appearance.BorderInactive = ui::Colour(170,170,170);
+ AddComponent(clearSearchButton);
+
+ class NextPageAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ NextPageAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->NextPage();
+ }
+ };
+ nextButton->SetActionCallback(new NextPageAction(this));
+ nextButton->Appearance.HorizontalAlign = ui::Appearance::AlignRight;
+ nextButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
+ class PrevPageAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ PrevPageAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->PrevPage();
+ }
+ };
+ previousButton->SetActionCallback(new PrevPageAction(this));
+ previousButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
+ previousButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
+ AddComponent(nextButton);
+ AddComponent(previousButton);
+ AddComponent(searchField);
+ AddComponent(infoLabel);
+
+ loadingSpinner = new ui::Spinner(ui::Point(((XRES+BARSIZE)/2)-12, ((YRES+MENUSIZE)/2)+12), ui::Point(24, 24));
+ AddComponent(loadingSpinner);
+
+ ui::Label * searchPrompt = new ui::Label(ui::Point(10, 10), ui::Point(50, 16), "Search:");
+ searchPrompt->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
+ searchPrompt->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
+ AddComponent(searchPrompt);
+
+ class RemoveSelectedAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ RemoveSelectedAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->RemoveSelected();
+ }
+ };
+
+ class UnpublishSelectedAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ UnpublishSelectedAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->UnpublishSelected();
+ }
+ };
+
+ class FavouriteSelectedAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ FavouriteSelectedAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->FavouriteSelected();
+ }
+ };
+
+ class ClearSelectionAction : public ui::ButtonAction
+ {
+ SearchView * v;
+ public:
+ ClearSelectionAction(SearchView * _v) { v = _v; }
+ void ActionCallback(ui::Button * sender)
+ {
+ v->c->ClearSelection();
+ }
+ };
+
+ removeSelected = new ui::Button(ui::Point((((XRES+BARSIZE)-415)/2), YRES+MENUSIZE-18), ui::Point(100, 16), "Delete");
+ removeSelected->Visible = false;
+ removeSelected->SetActionCallback(new RemoveSelectedAction(this));
+ AddComponent(removeSelected);
+
+ unpublishSelected = new ui::Button(ui::Point((((XRES+BARSIZE)-415)/2)+105, YRES+MENUSIZE-18), ui::Point(100, 16), "Unpublish");
+ unpublishSelected->Visible = false;
+ unpublishSelected->SetActionCallback(new UnpublishSelectedAction(this));
+ AddComponent(unpublishSelected);
+
+ favouriteSelected = new ui::Button(ui::Point((((XRES+BARSIZE)-415)/2)+210, YRES+MENUSIZE-18), ui::Point(100, 16), "Favourite");
+ favouriteSelected->Visible = false;
+ favouriteSelected->SetActionCallback(new FavouriteSelectedAction(this));
+ AddComponent(favouriteSelected);
+
+ clearSelection = new ui::Button(ui::Point((((XRES+BARSIZE)-415)/2)+315, YRES+MENUSIZE-18), ui::Point(100, 16), "Clear selection");
+ clearSelection->Visible = false;
+ clearSelection->SetActionCallback(new ClearSelectionAction(this));
+ AddComponent(clearSelection);
+
+ CheckAccess();
+}
+
+void SearchView::NotifyMessageOfTheDay(Client * sender)
+{
+ motdLabel->SetText(sender->GetMessageOfTheDay());
+}
+
+void SearchView::doSearch()
+{
+ if (searchField->GetText().length() > 3 || !searchField->GetText().length())
+ c->DoSearch(searchField->GetText());
+}
+
+
+void SearchView::clearSearch()
+{
+ searchField->SetText("");
+ c->DoSearch(searchField->GetText(), true);
+}
+
+void SearchView::OnTryOkay(OkayMethod method)
+{
+ c->DoSearch(searchField->GetText(), true);
+}
+
+SearchView::~SearchView()
+{
+ Client::Ref().RemoveListener(this);
+ RemoveComponent(nextButton);
+ RemoveComponent(previousButton);
+ RemoveComponent(infoLabel);
+
+ for(int i = 0; i < saveButtons.size(); i++)
+ {
+ RemoveComponent(saveButtons[i]);
+ delete saveButtons[i];
+ }
+ saveButtons.clear();
+
+ delete nextButton;
+ delete previousButton;
+ delete infoLabel;
+}
+
+void SearchView::Search(std::string query)
+{
+ searchField->SetText(query);
+ c->DoSearch(query, true);
+}
+
+void SearchView::NotifySortChanged(SearchModel * sender)
+{
+ if(sender->GetSort() == "best")
+ {
+ sortButton->SetToggleState(false);
+ sortButton->SetText("By votes");
+ sortButton->SetIcon(IconVoteSort);
+ }
+ else
+ {
+ sortButton->SetToggleState(true);
+ sortButton->SetText("By date");
+ sortButton->SetIcon(IconDateSort);
+ }
+}
+
+void SearchView::NotifyShowOwnChanged(SearchModel * sender)
+{
+ ownButton->SetToggleState(sender->GetShowOwn());
+ if(sender->GetShowOwn() || Client::Ref().GetAuthUser().UserElevation == User::ElevationAdmin || Client::Ref().GetAuthUser().UserElevation == User::ElevationModerator)
+ {
+ unpublishSelected->Enabled = true;
+ removeSelected->Enabled = true;
+ }
+ else if(sender->GetShowFavourite())
+ {
+ unpublishSelected->Enabled = false;
+ removeSelected->Enabled = false;
+ }
+ else
+ {
+ unpublishSelected->Enabled = false;
+ removeSelected->Enabled = false;
+ }
+}
+
+void SearchView::NotifyShowFavouriteChanged(SearchModel * sender)
+{
+ favButton->SetToggleState(sender->GetShowFavourite());
+ if(sender->GetShowFavourite())
+ {
+ unpublishSelected->Enabled = false;
+ removeSelected->Enabled = false;
+ }
+ else if(sender->GetShowOwn() || Client::Ref().GetAuthUser().UserElevation == User::ElevationAdmin || Client::Ref().GetAuthUser().UserElevation == User::ElevationModerator)
+ {
+ unpublishSelected->Enabled = true;
+ removeSelected->Enabled = true;
+ }
+ else
+ {
+ unpublishSelected->Enabled = false;
+ removeSelected->Enabled = false;
+ }
+}
+
+void SearchView::NotifyPageChanged(SearchModel * sender)
+{
+ std::stringstream pageInfo;
+ pageInfo << "Page " << sender->GetPageNum() << " of " << sender->GetPageCount();
+ infoLabel->SetText(pageInfo.str());
+ if(sender->GetPageNum() == 1)
+ {
+ previousButton->Visible = false;
+ }
+ else
+ {
+ previousButton->Visible = true;
+ }
+ if(sender->GetPageNum() == sender->GetPageCount())
+ {
+ nextButton->Visible = false;
+ }
+ else
+ {
+ nextButton->Visible = true;
+ }
+}
+
+void SearchView::NotifyAuthUserChanged(Client * sender)
+{
+ CheckAccess();
+}
+
+void SearchView::CheckAccess()
+{
+ if(c)
+ {
+ c->ClearSelection();
+
+ if(ownButton->GetToggleState())
+ ownButton->DoAction();
+ if(favButton->GetToggleState())
+ favButton->DoAction();
+ }
+
+ if(Client::Ref().GetAuthUser().ID)
+ {
+ ownButton->Enabled = true;
+ favButton->Enabled = true;
+ favouriteSelected->Enabled = true;
+
+ if(Client::Ref().GetAuthUser().UserElevation == User::ElevationAdmin || Client::Ref().GetAuthUser().UserElevation == User::ElevationModerator)
+ {
+ unpublishSelected->Enabled = true;
+ removeSelected->Enabled = true;
+ for(int i = 0; i < saveButtons.size(); i++)
+ {
+ saveButtons[i]->SetSelectable(true);
+ }
+ }
+
+ }
+ else
+ {
+ ownButton->Enabled = false;
+ favButton->Enabled = false;
+
+
+ favouriteSelected->Enabled = false;
+ unpublishSelected->Enabled = false;
+ removeSelected->Enabled = false;
+
+ for(int i = 0; i < saveButtons.size(); i++)
+ {
+ saveButtons[i]->SetSelectable(false);
+ saveButtons[i]->SetSelected(false);
+ }
+ }
+}
+
+void SearchView::NotifyTagListChanged(SearchModel * sender)
+{
+ int i = 0;
+ int buttonWidth, buttonHeight, saveX = 0, saveY = 0, savesX = 5, savesY = 4, buttonPadding = 1;
+ int buttonAreaWidth, buttonAreaHeight, buttonXOffset, buttonYOffset;
+
+ int tagWidth, tagHeight, tagX = 0, tagY = 0, tagsX = 6, tagsY = 4, tagPadding = 1;
+ int tagAreaWidth, tagAreaHeight, tagXOffset, tagYOffset;
+
+ vector<pair<string, int> > tags = sender->GetTagList();
+
+ RemoveComponent(motdLabel);
+ motdLabel->SetParentWindow(NULL);
+
+ RemoveComponent(tagsLabel);
+ tagsLabel->SetParentWindow(NULL);
+
+ for(i = 0; i < tagButtons.size(); i++)
+ {
+ RemoveComponent(tagButtons[i]);
+ delete tagButtons[i];
+ }
+ tagButtons.clear();
+
+ buttonYOffset = 28;
+ buttonXOffset = buttonPadding;
+ buttonAreaWidth = Size.X;
+ buttonAreaHeight = Size.Y - buttonYOffset - 18;
+
+ if(sender->GetShowTags())
+ {
+ buttonYOffset += (buttonAreaHeight/savesY) - buttonPadding*2;
+ buttonAreaHeight = Size.Y - buttonYOffset - 18;
+ savesY--;
+
+ tagXOffset = tagPadding;
+ tagYOffset = 60;
+ tagAreaWidth = Size.X;
+ tagAreaHeight = ((buttonAreaHeight/savesY) - buttonPadding*2)-(tagYOffset-28)-5;
+ tagWidth = (tagAreaWidth/tagsX) - tagPadding*2;
+ tagHeight = (tagAreaHeight/tagsY) - tagPadding*2;
+
+ AddComponent(tagsLabel);
+ tagsLabel->Position.Y = tagYOffset-16;
+
+ AddComponent(motdLabel);
+ motdLabel->Position.Y = tagYOffset-30;
+ }
+
+ class TagAction: public ui::ButtonAction
+ {
+ SearchView * v;
+ std::string tag;
+ public:
+ TagAction(SearchView * v, std::string tag) : v(v), tag(tag) {}
+ virtual void ActionCallback(ui::Button * sender)
+ {
+ v->Search(tag);
+ }
+ };
+ if(sender->GetShowTags())
+ {
+ for(i = 0; i < tags.size(); i++)
+ {
+ int maxTagVotes = tags[0].second;
+
+ pair<string, int> tag = tags[i];
+
+ if(tagX == tagsX)
+ {
+ if(tagY == tagsY-1)
+ break;
+ tagX = 0;
+ tagY++;
+ }
+
+ int tagAlpha = 192;
+ if (maxTagVotes)
+ tagAlpha = 127+(128*tag.second)/maxTagVotes;
+
+ ui::Button * tagButton;
+ tagButton = new ui::Button(
+ ui::Point(
+ tagXOffset + tagPadding + tagX*(tagWidth+tagPadding*2),
+ tagYOffset + tagPadding + tagY*(tagHeight+tagPadding*2)
+ ),
+ ui::Point(tagWidth, tagHeight),
+ tag.first
+ );
+ tagButton->SetActionCallback(new TagAction(this, tag.first));
+ tagButton->Appearance.BorderInactive = ui::Colour(0, 0, 0);
+ tagButton->Appearance.BorderHover = ui::Colour(0, 0, 0);
+ tagButton->Appearance.BorderActive = ui::Colour(0, 0, 0);
+ tagButton->Appearance.BackgroundHover = ui::Colour(0, 0, 0);
+
+ tagButton->Appearance.TextInactive = ui::Colour(tagAlpha, tagAlpha, tagAlpha);
+ tagButton->Appearance.TextHover = ui::Colour((tagAlpha*5)/6, (tagAlpha*5)/6, tagAlpha);
+ AddComponent(tagButton);
+ tagButtons.push_back(tagButton);
+ tagX++;
+
+ }
+ }
+}
+
+void SearchView::NotifySaveListChanged(SearchModel * sender)
+{
+ int i = 0;
+ int buttonWidth, buttonHeight, saveX = 0, saveY = 0, savesX = 5, savesY = 4, buttonPadding = 1;
+ int buttonAreaWidth, buttonAreaHeight, buttonXOffset, buttonYOffset;
+
+ int tagWidth, tagHeight, tagX = 0, tagY = 0, tagsX = 6, tagsY = 4, tagPadding = 1;
+ int tagAreaWidth, tagAreaHeight, tagXOffset, tagYOffset;
+
+ vector<SaveInfo*> saves = sender->GetSaveList();
+ //string messageOfTheDay = sender->GetMessageOfTheDay();
+
+ if(sender->GetShowFavourite())
+ favouriteSelected->SetText("Unfavourite");
+ else
+ favouriteSelected->SetText("Favourite");
+
+ Client::Ref().ClearThumbnailRequests();
+ for(i = 0; i < saveButtons.size(); i++)
+ {
+ RemoveComponent(saveButtons[i]);
+ }
+ if(!sender->GetSavesLoaded())
+ {
+ nextButton->Enabled = false;
+ previousButton->Enabled = false;
+ favButton->Enabled = false;
+ }
+ else
+ {
+ nextButton->Enabled = true;
+ previousButton->Enabled = true;
+ if (Client::Ref().GetAuthUser().ID)
+ favButton->Enabled = true;
+ }
+ if (!sender->GetSavesLoaded() || favButton->GetToggleState())
+ {
+ ownButton->Enabled = false;
+ sortButton->Enabled = false;
+ }
+ else
+ {
+ if (Client::Ref().GetAuthUser().ID)
+ ownButton->Enabled = true;
+ sortButton->Enabled = true;
+ }
+ if(!saves.size())
+ {
+ loadingSpinner->Visible = false;
+ if(!errorLabel)
+ {
+ errorLabel = new ui::Label(ui::Point(((XRES+BARSIZE)/2)-100, ((YRES+MENUSIZE)/2)-6), ui::Point(200, 12), "Error");
+ AddComponent(errorLabel);
+ }
+ if(!sender->GetSavesLoaded())
+ {
+ errorLabel->SetText("Loading...");
+ loadingSpinner->Visible = true;
+ }
+ else
+ {
+ if(sender->GetLastError().length())
+ errorLabel->SetText("\bo" + sender->GetLastError());
+ else
+ errorLabel->SetText("\boNo saves found");
+ }
+ }
+ else
+ {
+ loadingSpinner->Visible = false;
+ if(errorLabel)
+ {
+ RemoveComponent(errorLabel);
+ delete errorLabel;
+ errorLabel = NULL;
+ }
+ for(i = 0; i < saveButtons.size(); i++)
+ {
+ delete saveButtons[i];
+ }
+ saveButtons.clear();
+
+ buttonYOffset = 28;
+ buttonXOffset = buttonPadding;
+ buttonAreaWidth = Size.X;
+ buttonAreaHeight = Size.Y - buttonYOffset - 18;
+
+ if(sender->GetShowTags())
+ {
+ buttonYOffset += (buttonAreaHeight/savesY) - buttonPadding*2;
+ buttonAreaHeight = Size.Y - buttonYOffset - 18;
+ savesY--;
+
+ tagXOffset = tagPadding;
+ tagYOffset = 60;
+ tagAreaWidth = Size.X;
+ tagAreaHeight = ((buttonAreaHeight/savesY) - buttonPadding*2)-(tagYOffset-28)-5;
+ tagWidth = (tagAreaWidth/tagsX) - tagPadding*2;
+ tagHeight = (tagAreaHeight/tagsY) - tagPadding*2;
+ }
+
+ buttonWidth = (buttonAreaWidth/savesX) - buttonPadding*2;
+ buttonHeight = (buttonAreaHeight/savesY) - buttonPadding*2;
+
+
+
+ class SaveOpenAction: public ui::SaveButtonAction
+ {
+ SearchView * v;
+ public:
+ SaveOpenAction(SearchView * _v) { v = _v; }
+ virtual void ActionCallback(ui::SaveButton * sender)
+ {
+ v->c->OpenSave(sender->GetSave()->GetID(), sender->GetSave()->GetVersion());
+ }
+ virtual void SelectedCallback(ui::SaveButton * sender)
+ {
+ v->c->Selected(sender->GetSave()->GetID(), sender->GetSelected());
+ }
+ virtual void AltActionCallback(ui::SaveButton * sender)
+ {
+ stringstream search;
+ search << "history:" << sender->GetSave()->GetID();
+ v->Search(search.str());
+ }
+ virtual void AltActionCallback2(ui::SaveButton * sender)
+ {
+ v->Search("user:"+sender->GetSave()->GetUserName());
+ }
+ };
+ for(i = 0; i < saves.size(); i++)
+ {
+ if(saveX == savesX)
+ {
+ if(saveY == savesY-1)
+ break;
+ saveX = 0;
+ saveY++;
+ }
+ ui::SaveButton * saveButton;
+ saveButton = new ui::SaveButton(
+ ui::Point(
+ buttonXOffset + buttonPadding + saveX*(buttonWidth+buttonPadding*2),
+ buttonYOffset + buttonPadding + saveY*(buttonHeight+buttonPadding*2)
+ ),
+ ui::Point(buttonWidth, buttonHeight),
+ saves[i]);
+ saveButton->AddContextMenu(0);
+ saveButton->SetActionCallback(new SaveOpenAction(this));
+ if(Client::Ref().GetAuthUser().ID)
+ saveButton->SetSelectable(true);
+ if (saves[i]->GetUserName() == Client::Ref().GetAuthUser().Username || Client::Ref().GetAuthUser().UserElevation == User::ElevationAdmin || Client::Ref().GetAuthUser().UserElevation == User::ElevationModerator)
+ saveButton->SetShowVotes(true);
+ saveButtons.push_back(saveButton);
+ AddComponent(saveButton);
+ saveX++;
+ }
+ }
+}
+
+void SearchView::NotifySelectedChanged(SearchModel * sender)
+{
+ vector<int> selected = sender->GetSelected();
+ for(int j = 0; j < saveButtons.size(); j++)
+ {
+ saveButtons[j]->SetSelected(false);
+ for(int i = 0; i < selected.size(); i++)
+ {
+ if(saveButtons[j]->GetSave()->GetID()==selected[i])
+ saveButtons[j]->SetSelected(true);
+ }
+ }
+
+ if(selected.size())
+ {
+ removeSelected->Visible = true;
+ unpublishSelected->Visible = true;
+ favouriteSelected->Visible = true;
+ clearSelection->Visible = true;
+ }
+ else
+ {
+ removeSelected->Visible = false;
+ unpublishSelected->Visible = false;
+ favouriteSelected->Visible = false;
+ clearSelection->Visible = false;
+ }
+}
+
+void SearchView::OnTick(float dt)
+{
+ c->Update();
+}
+
+void SearchView::OnMouseWheel(int x, int y, int d)
+{
+ if(!d)
+ return;
+ if(d<0)
+ c->NextPage();
+ else
+ c->PrevPage();
+}
+void SearchView::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ if(key==KEY_ESCAPE)
+ c->Exit();
+}
+
diff --git a/src/gui/search/SearchView.h b/src/gui/search/SearchView.h
new file mode 100644
index 0000000..5752a2c
--- /dev/null
+++ b/src/gui/search/SearchView.h
@@ -0,0 +1,74 @@
+#ifndef SEARCHVIEW_H
+#define SEARCHVIEW_H
+
+#include <vector>
+#include "SearchController.h"
+#include "gui/interface/SaveButton.h"
+#include "gui/interface/Button.h"
+#include "gui/interface/Label.h"
+#include "gui/interface/Spinner.h"
+#include "gui/interface/Textbox.h"
+#include "client/ClientListener.h"
+
+using namespace std;
+
+namespace ui
+{
+ class RichLabel;
+ class SaveButton;
+ class Button;
+ class Label;
+ class Spinner;
+ class Textbox;
+}
+
+class SearchModel;
+class SearchController;
+
+class SearchView: public ui::Window, public ClientListener
+{
+private:
+ SearchController * c;
+ vector<ui::SaveButton*> saveButtons;
+ vector<ui::Button*> tagButtons;
+ ui::Button * favButton;
+ ui::Button * nextButton;
+ ui::Button * previousButton;
+ ui::Label * errorLabel;
+ ui::Textbox * searchField;
+ ui::Label * infoLabel;
+ ui::Label * tagsLabel;
+ ui::RichLabel * motdLabel;
+ ui::Button * sortButton;
+ ui::Button * ownButton;
+ ui::Spinner * loadingSpinner;
+
+ ui::Button * removeSelected;
+ ui::Button * unpublishSelected;
+ ui::Button * favouriteSelected;
+ ui::Button * clearSelection;
+ void clearSearch();
+ void doSearch();
+public:
+ void NotifyTagListChanged(SearchModel * sender);
+ void NotifySaveListChanged(SearchModel * sender);
+ void NotifySelectedChanged(SearchModel * sender);
+ void NotifyPageChanged(SearchModel * sender);
+ void NotifySortChanged(SearchModel * sender);
+ void NotifyShowOwnChanged(SearchModel * sender);
+ void NotifyShowFavouriteChanged(SearchModel * sender);
+ void NotifyAuthUserChanged(Client * sender);
+ void NotifyMessageOfTheDay(Client * sender);
+ void CheckAccess();
+ virtual void OnTryOkay(OkayMethod method);
+ SearchView();
+ virtual ~SearchView();
+ void AttachController(SearchController * _c) { c = _c; }
+ virtual void Search(std::string);
+ virtual void OnTick(float dt);
+ virtual void OnMouseWheel(int x, int y, int d);
+ virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);
+
+};
+
+#endif // SEARCHVIEW_H
diff --git a/src/gui/search/Thumbnail.cpp b/src/gui/search/Thumbnail.cpp
new file mode 100644
index 0000000..1f06c45
--- /dev/null
+++ b/src/gui/search/Thumbnail.cpp
@@ -0,0 +1,73 @@
+#include "Thumbnail.h"
+
+Thumbnail::Thumbnail(const Thumbnail & thumb):
+ ID(thumb.ID),
+ Datestamp(thumb.Datestamp),
+ Data(thumb.Data),
+ Size(thumb.Size)
+{
+ //Ensure the actual thumbnail data is copied
+ if(thumb.Data)
+ {
+ Data = new pixel[thumb.Size.X*thumb.Size.Y];
+ memcpy(Data, thumb.Data, (thumb.Size.X*thumb.Size.Y) * PIXELSIZE);
+ }
+ else
+ {
+ Data = NULL;
+ }
+}
+
+Thumbnail::Thumbnail(int _id, int _datestamp, pixel * _data, ui::Point _size):
+ ID(_id),
+ Datestamp(_datestamp),
+ Data(_data),
+ Size(_size)
+{
+ if(_data)
+ {
+ Data = new pixel[_size.X*_size.Y];
+ memcpy(Data, _data, (_size.X*_size.Y) * PIXELSIZE);
+ }
+ else
+ {
+ Data = NULL;
+ }
+}
+
+void Thumbnail::Resize(int width, int height)
+{
+ Resize(ui::Point(width, height));
+}
+
+void Thumbnail::Resize(ui::Point newSize)
+{
+ float scaleFactorX = 1.0f, scaleFactorY = 1.0f;
+ if(Size.Y > newSize.Y)
+ {
+ scaleFactorY = float(newSize.Y)/((float)Size.Y);
+ }
+ if(Size.X > newSize.X)
+ {
+ scaleFactorX = float(newSize.X)/((float)Size.X);
+ }
+ if(newSize.X == -1)
+ scaleFactorX = scaleFactorY;
+ if(newSize.Y == -1)
+ scaleFactorY = scaleFactorX;
+ if(scaleFactorY < 1.0f || scaleFactorX < 1.0f)
+ {
+ float scaleFactor = scaleFactorY < scaleFactorX ? scaleFactorY : scaleFactorX;
+ pixel * thumbData = Data;
+ Data = Graphics::resample_img(thumbData, Size.X, Size.Y, Size.X * scaleFactor, Size.Y * scaleFactor);
+ Size.X *= scaleFactor;
+ Size.Y *= scaleFactor;
+ delete[] thumbData;
+ }
+}
+
+Thumbnail::~Thumbnail()
+{
+ if(Data)
+ delete[] Data;
+}
diff --git a/src/gui/search/Thumbnail.h b/src/gui/search/Thumbnail.h
new file mode 100644
index 0000000..27ffa87
--- /dev/null
+++ b/src/gui/search/Thumbnail.h
@@ -0,0 +1,25 @@
+#ifndef THUMBNAIL_H
+#define THUMBNAIL_H
+
+#include <iostream>
+#include "graphics/Graphics.h"
+#include "gui/interface/Point.h"
+
+class Thumbnail
+{
+public:
+ Thumbnail(const Thumbnail & thumb);
+
+ Thumbnail(int _id, int _datestamp, pixel * _data, ui::Point _size);
+
+ ~Thumbnail();
+
+ void Resize(int Width, int Height);
+ void Resize(ui::Point newSize);
+
+ int ID, Datestamp;
+ ui::Point Size;
+ pixel * Data;
+};
+
+#endif // THUMBNAIL_H