Tags, fixes #55

This commit is contained in:
Simon Robertshaw 2012-08-04 20:55:59 +01:00
parent 82d2bcc7c2
commit 5a2da01a5b
11 changed files with 252 additions and 28 deletions

View File

@ -1262,6 +1262,55 @@ std::vector<SaveComment*> * Client::GetComments(int saveID, int start, int count
return commentArray; return commentArray;
} }
std::vector<std::pair<std::string, int> > * Client::GetTags(int start, int count, string query, int & resultCount)
{
lastError = "";
resultCount = 0;
std::vector<std::pair<std::string, int> > * tagArray = new std::vector<std::pair<std::string, int> >();
std::stringstream urlStream;
char * data;
int dataStatus, dataLength;
urlStream << "http://" << SERVER << "/Browse/Tags.json?Start=" << start << "&Count=" << count;
if(query.length())
{
urlStream << "&Search_Query=";
if(query.length())
urlStream << URLEscape(query);
}
data = http_simple_get((char *)urlStream.str().c_str(), &dataStatus, &dataLength);
if(dataStatus == 200 && data)
{
try
{
std::istringstream dataStream(data);
json::Object objDocument;
json::Reader::Read(objDocument, dataStream);
json::Number tempCount = objDocument["TagTotal"];
resultCount = tempCount.Value();
json::Array tagsArray = objDocument["Tags"];
for(int j = 0; j < tagsArray.Size(); j++)
{
json::Number tagCount = tagsArray[j]["Count"];
json::String tag = tagsArray[j]["Tag"];
tagArray->push_back(std::pair<std::string, int>(tag.Value(), tagCount.Value()));
}
}
catch (json::Exception &e)
{
lastError = "Could not read response";
}
}
else
{
lastError = http_ret_text(dataStatus);
}
if(data)
free(data);
return tagArray;
}
std::vector<SaveInfo*> * Client::SearchSaves(int start, int count, string query, string sort, std::string category, int & resultCount) std::vector<SaveInfo*> * Client::SearchSaves(int start, int count, string query, string sort, std::string category, int & resultCount)
{ {
lastError = ""; lastError = "";

View File

@ -111,6 +111,7 @@ public:
LoginStatus Login(string username, string password, User & user); LoginStatus Login(string username, string password, User & user);
void ClearThumbnailRequests(); void ClearThumbnailRequests();
std::vector<SaveInfo*> * SearchSaves(int start, int count, string query, string sort, string category, int & resultCount); std::vector<SaveInfo*> * SearchSaves(int start, int count, string query, string sort, string category, int & resultCount);
std::vector<std::pair<std::string, int> > * GetTags(int start, int count, string query, int & resultCount);
std::vector<SaveComment*> * GetComments(int saveID, int start, int count); std::vector<SaveComment*> * GetComments(int saveID, int start, int count);
Thumbnail * GetPreview(int saveID, int saveDate); Thumbnail * GetPreview(int saveID, int saveDate);
Thumbnail * GetThumbnail(int saveID, int saveDate); Thumbnail * GetThumbnail(int saveID, int saveDate);

View File

@ -14,18 +14,21 @@ namespace ui
HorizontalAlign(AlignCentre), HorizontalAlign(AlignCentre),
VerticalAlign(AlignMiddle), VerticalAlign(AlignMiddle),
BackgroundHover(30, 30, 30), BackgroundHover(20, 20, 20),
BackgroundInactive(0, 0, 0), BackgroundInactive(0, 0, 0),
BackgroundActive(255, 255, 255), BackgroundActive(255, 255, 255),
BackgroundDisabled(100, 100, 100), BackgroundDisabled(10, 10, 10),
TextHover(255, 255, 255), TextHover(255, 255, 255),
TextInactive(255, 255, 255), TextInactive(255, 255, 255),
TextActive(0, 0, 0), TextActive(0, 0, 0),
TextDisabled(100, 100, 100),
BorderHover(255, 255, 255), BorderHover(255, 255, 255),
BorderInactive(200, 200, 200), BorderInactive(200, 200, 200),
BorderActive(255, 255, 255), BorderActive(235, 235, 235),
BorderDisabled(100, 100, 100),
Margin(1, 4), Margin(1, 4),
icon(NoIcon), icon(NoIcon),

View File

@ -40,10 +40,12 @@ namespace ui
ui::Colour TextHover; ui::Colour TextHover;
ui::Colour TextInactive; ui::Colour TextInactive;
ui::Colour TextActive; ui::Colour TextActive;
ui::Colour TextDisabled;
ui::Colour BorderHover; ui::Colour BorderHover;
ui::Colour BorderInactive; ui::Colour BorderInactive;
ui::Colour BorderActive; ui::Colour BorderActive;
ui::Colour BorderDisabled;
ui::Border Margin; ui::Border Margin;

View File

@ -86,32 +86,45 @@ void Button::Draw(const Point& screenPos)
Graphics * g = ui::Engine::Ref().g; Graphics * g = ui::Engine::Ref().g;
Point Position = screenPos; Point Position = screenPos;
ui::Colour bgColour(0, 0, 0); ui::Colour bgColour(0, 0, 0);
ui::Colour textColour = Appearance.TextInactive;
ui::Colour borderColour = Appearance.BorderInactive;
ui::Colour backgroundColour = Appearance.BackgroundInactive;
if(Enabled) if(Enabled)
{ {
if(isButtonDown || (isTogglable && toggle)) if(isButtonDown || (isTogglable && toggle))
{ {
bgColour = Appearance.BackgroundActive; textColour = Appearance.TextActive;
g->fillrect(Position.X+1, Position.Y+1, Size.X-2, Size.Y-2, Appearance.BackgroundActive.Red, Appearance.BackgroundActive.Green, Appearance.BackgroundActive.Blue, 255); borderColour = Appearance.BorderActive;
g->drawrect(Position.X, Position.Y, Size.X, Size.Y, Appearance.BorderActive.Red, Appearance.BorderActive.Green, Appearance.BorderActive.Blue, 255); backgroundColour = Appearance.BackgroundActive;
g->drawtext(Position.X+textPosition.X, Position.Y+textPosition.Y, buttonDisplayText, Appearance.TextActive.Red, Appearance.TextActive.Green, Appearance.TextActive.Blue, 255); }
else if (isMouseInside)
{
textColour = Appearance.TextHover;
borderColour = Appearance.BorderHover;
backgroundColour = Appearance.BackgroundHover;
} }
else else
{ {
bgColour = Appearance.BackgroundInactive; textColour = Appearance.TextInactive;
g->fillrect(Position.X+1, Position.Y+1, Size.X-2, Size.Y-2, Appearance.BackgroundInactive.Red, Appearance.BackgroundInactive.Green, Appearance.BackgroundInactive.Blue, 255); borderColour = Appearance.BorderInactive;
g->drawrect(Position.X, Position.Y, Size.X, Size.Y, Appearance.BorderInactive.Red, Appearance.BorderInactive.Green, Appearance.BorderInactive.Blue, 255); backgroundColour = Appearance.BackgroundInactive;
g->drawtext(Position.X+textPosition.X, Position.Y+textPosition.Y, buttonDisplayText, Appearance.TextInactive.Red, Appearance.TextInactive.Green, Appearance.TextInactive.Blue, 255);
} }
} }
else else
{ {
bgColour = Appearance.BackgroundInactive; textColour = Appearance.TextDisabled;
g->fillrect(Position.X+1, Position.Y+1, Size.X-2, Size.Y-2, Appearance.BackgroundInactive.Red, Appearance.BackgroundInactive.Green, Appearance.BackgroundInactive.Blue, 180); borderColour = Appearance.BorderDisabled;
g->drawrect(Position.X, Position.Y, Size.X, Size.Y, Appearance.BackgroundDisabled.Red, Appearance.BackgroundDisabled.Green, Appearance.BackgroundDisabled.Blue, Appearance.BackgroundDisabled.Alpha); backgroundColour = Appearance.BackgroundDisabled;
g->drawtext(Position.X+textPosition.X, Position.Y+textPosition.Y, buttonDisplayText, 180, 180, 180, 255);
} }
bool iconInvert = (bgColour.Blue + (3*bgColour.Green) + (2*bgColour.Red))>544?true:false; bgColour = Appearance.BackgroundInactive;
g->fillrect(Position.X+1, Position.Y+1, Size.X-2, Size.Y-2, backgroundColour.Red, backgroundColour.Green, backgroundColour.Blue, backgroundColour.Alpha);
g->drawrect(Position.X, Position.Y, Size.X, Size.Y, borderColour.Red, borderColour.Green, borderColour.Blue, borderColour.Alpha);
g->drawtext(Position.X+textPosition.X, Position.Y+textPosition.Y, buttonDisplayText, textColour.Red, textColour.Green, textColour.Blue, textColour.Alpha);
bool iconInvert = (backgroundColour.Blue + (3*backgroundColour.Green) + (2*backgroundColour.Red))>544?true:false;
if(Appearance.icon) if(Appearance.icon)
{ {

View File

@ -96,11 +96,19 @@ SearchController::~SearchController()
delete searchView; delete searchView;
} }
void SearchController::DoSearch(std::string query) void SearchController::DoSearch(std::string query, bool now)
{ {
nextQuery = query; nextQuery = query;
nextQueryTime = clock()+(0.6 * CLOCKS_PER_SEC); if(!now)
nextQueryDone = false; {
nextQueryTime = clock()+(0.6 * CLOCKS_PER_SEC);
nextQueryDone = false;
}
else
{
nextQueryDone = true;
searchModel->UpdateSaveList(1, nextQuery);
}
//searchModel->UpdateSaveList(1, query); //searchModel->UpdateSaveList(1, query);
} }

View File

@ -30,7 +30,7 @@ public:
~SearchController(); ~SearchController();
SearchView * GetView() { return searchView; } SearchView * GetView() { return searchView; }
void Exit(); void Exit();
void DoSearch(std::string query); void DoSearch(std::string query, bool now = false);
void NextPage(); void NextPage();
void PrevPage(); void PrevPage();
void ChangeSort(); void ChangeSort();

View File

@ -12,10 +12,16 @@ SearchModel::SearchModel():
updateSaveListFinished(false), updateSaveListFinished(false),
saveListLoaded(false), saveListLoaded(false),
currentPage(1), currentPage(1),
resultCount(0) resultCount(0),
showTags(true)
{ {
} }
void SearchModel::SetShowTags(bool show)
{
showTags = show;
}
void * SearchModel::updateSaveListTHelper(void * obj) void * SearchModel::updateSaveListTHelper(void * obj)
{ {
return ((SearchModel *)obj)->updateSaveListT(); return ((SearchModel *)obj)->updateSaveListT();
@ -23,14 +29,27 @@ void * SearchModel::updateSaveListTHelper(void * obj)
void * SearchModel::updateSaveListT() void * SearchModel::updateSaveListT()
{ {
void ** information = new void*[2];
std::string category = ""; std::string category = "";
if(showFavourite) if(showFavourite)
category = "Favourites"; category = "Favourites";
if(showOwn && Client::Ref().GetAuthUser().ID) if(showOwn && Client::Ref().GetAuthUser().ID)
category = "by:"+Client::Ref().GetAuthUser().Username; category = "by:"+Client::Ref().GetAuthUser().Username;
vector<SaveInfo*> * tempSaveList = Client::Ref().SearchSaves((currentPage-1)*20, 20, lastQuery, currentSort=="new"?"date":"votes", category, resultCount); information[0] = Client::Ref().SearchSaves((currentPage-1)*20, 20, lastQuery, currentSort=="new"?"date":"votes", category, resultCount);
if(showTags)
{
int tagResultCount;
information[1] = Client::Ref().GetTags(0, 24, "", tagResultCount);
}
else
{
information[1] = NULL;
}
updateSaveListFinished = true; updateSaveListFinished = true;
return tempSaveList; return information;
} }
void SearchModel::UpdateSaveList(int pageNumber, std::string query) void SearchModel::UpdateSaveList(int pageNumber, std::string query)
@ -46,6 +65,11 @@ void SearchModel::UpdateSaveList(int pageNumber, std::string query)
selected.clear(); selected.clear();
notifySelectedChanged(); notifySelectedChanged();
if(pageNumber == 1 && !showOwn && !showFavourite && currentSort == "best" && query == "")
SetShowTags(true);
else
SetShowTags(false);
//Threading //Threading
if(!updateSaveListWorking) if(!updateSaveListWorking)
{ {
@ -78,6 +102,11 @@ vector<SaveInfo*> SearchModel::GetSaveList()
return saveList; return saveList;
} }
vector<pair<string, int> > SearchModel::GetTagList()
{
return tagList;
}
void SearchModel::Update() void SearchModel::Update()
{ {
if(updateSaveListWorking) if(updateSaveListWorking)
@ -87,10 +116,25 @@ void SearchModel::Update()
updateSaveListWorking = false; updateSaveListWorking = false;
lastError = ""; lastError = "";
saveListLoaded = true; saveListLoaded = true;
vector<SaveInfo*> * tempSaveList; void ** tempInformation;
pthread_join(updateSaveListThread, (void**)(&tempSaveList)); //vector<SaveInfo*> * tempSaveList;
saveList = *tempSaveList; pthread_join(updateSaveListThread, (void**)(&tempInformation));
delete tempSaveList; saveList = *(vector<SaveInfo*>*)tempInformation[0];
delete (vector<SaveInfo*>*)tempInformation[0];
if(tempInformation[1])
{
tagList = *(vector<pair<string, int> >*)tempInformation[1];
delete (vector<pair<string, int> >*)tempInformation[1];
}
else
{
tagList = vector<pair<string, int> >();
}
delete[] tempInformation;
if(!saveList.size()) if(!saveList.size())
{ {
lastError = Client::Ref().GetLastError(); lastError = Client::Ref().GetLastError();

View File

@ -21,10 +21,12 @@ private:
vector<int> selected; vector<int> selected;
vector<SearchView*> observers; vector<SearchView*> observers;
vector<SaveInfo*> saveList; vector<SaveInfo*> saveList;
vector<pair<string, int> > tagList;
int currentPage; int currentPage;
int resultCount; int resultCount;
bool showOwn; bool showOwn;
bool showFavourite; bool showFavourite;
bool showTags;
void notifySaveListChanged(); void notifySaveListChanged();
void notifySelectedChanged(); void notifySelectedChanged();
void notifyPageChanged(); void notifyPageChanged();
@ -43,9 +45,11 @@ public:
SearchModel(); SearchModel();
virtual ~SearchModel(); virtual ~SearchModel();
void SetShowTags(bool show);
void AddObserver(SearchView * observer); void AddObserver(SearchView * observer);
void UpdateSaveList(int pageNumber, std::string query); void UpdateSaveList(int pageNumber, std::string query);
vector<SaveInfo*> GetSaveList(); vector<SaveInfo*> GetSaveList();
vector<pair<string, int> > GetTagList();
string GetLastError() { return lastError; } string GetLastError() { return lastError; }
int GetPageCount() { return max(1, (int)(ceil(resultCount/16))); } int GetPageCount() { return max(1, (int)(ceil(resultCount/16))); }
int GetPageNum() { return currentPage; } int GetPageNum() { return currentPage; }

View File

@ -16,6 +16,7 @@ SearchView::SearchView():
nextButton = new ui::Button(ui::Point(XRES+BARSIZE-52, YRES+MENUSIZE-18), ui::Point(50, 16), "Next \x95"); 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"); previousButton = new ui::Button(ui::Point(1, YRES+MENUSIZE-18), ui::Point(50, 16), "\x96 Prev");
infoLabel = new ui::Label(ui::Point(51, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-102, 16), "Loading..."); infoLabel = new ui::Label(ui::Point(51, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-102, 16), "Loading...");
tagsLabel = new ui::Label(ui::Point(51, YRES+MENUSIZE-18), ui::Point(XRES+BARSIZE-102, 16), "Popular Tags:");
class SearchAction : public ui::TextboxAction class SearchAction : public ui::TextboxAction
{ {
@ -219,6 +220,12 @@ SearchView::~SearchView()
delete infoLabel; delete infoLabel;
} }
void SearchView::Search(std::string query)
{
searchField->SetText(query);
c->DoSearch(query, true);
}
void SearchView::NotifySortChanged(SearchModel * sender) void SearchView::NotifySortChanged(SearchModel * sender)
{ {
sortButton->SetText("Show "+sender->GetSort()); sortButton->SetText("Show "+sender->GetSort());
@ -293,14 +300,29 @@ void SearchView::NotifySaveListChanged(SearchModel * sender)
int buttonWidth, buttonHeight, saveX = 0, saveY = 0, savesX = 5, savesY = 4, buttonPadding = 1; int buttonWidth, buttonHeight, saveX = 0, saveY = 0, savesX = 5, savesY = 4, buttonPadding = 1;
int buttonAreaWidth, buttonAreaHeight, buttonXOffset, buttonYOffset; 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(); vector<SaveInfo*> saves = sender->GetSaveList();
vector<pair<string, int> > tags = sender->GetTagList();
//string messageOfTheDay = sender->GetMessageOfTheDay();
RemoveComponent(tagsLabel);
tagsLabel->SetParentWindow(NULL);
Client::Ref().ClearThumbnailRequests(); Client::Ref().ClearThumbnailRequests();
for(i = 0; i < saveButtons.size(); i++) for(i = 0; i < saveButtons.size(); i++)
{ {
RemoveComponent(saveButtons[i]); RemoveComponent(saveButtons[i]);
delete saveButtons[i]; delete saveButtons[i];
} }
for(i = 0; i < tagButtons.size(); i++)
{
RemoveComponent(tagButtons[i]);
delete tagButtons[i];
}
saveButtons.clear(); saveButtons.clear();
tagButtons.clear();
if(!sender->GetSavesLoaded()) if(!sender->GetSavesLoaded())
{ {
nextButton->Enabled = false; nextButton->Enabled = false;
@ -341,12 +363,34 @@ void SearchView::NotifySaveListChanged(SearchModel * sender)
delete errorLabel; delete errorLabel;
errorLabel = NULL; errorLabel = NULL;
} }
buttonXOffset = buttonPadding;
buttonYOffset = 28; buttonYOffset = 28;
buttonXOffset = buttonPadding;
buttonAreaWidth = Size.X; buttonAreaWidth = Size.X;
buttonAreaHeight = Size.Y - buttonYOffset - 18; buttonAreaHeight = Size.Y - buttonYOffset - 18;
if(tags.size())
{
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;
}
buttonWidth = (buttonAreaWidth/savesX) - buttonPadding*2; buttonWidth = (buttonAreaWidth/savesX) - buttonPadding*2;
buttonHeight = (buttonAreaHeight/savesY) - buttonPadding*2; buttonHeight = (buttonAreaHeight/savesY) - buttonPadding*2;
class SaveOpenAction: public ui::SaveButtonAction class SaveOpenAction: public ui::SaveButtonAction
{ {
SearchView * v; SearchView * v;
@ -361,6 +405,59 @@ void SearchView::NotifySaveListChanged(SearchModel * sender)
v->c->Selected(sender->GetSave()->GetID(), sender->GetSelected()); v->c->Selected(sender->GetSave()->GetID(), sender->GetSelected());
} }
}; };
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);
}
};
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++;
}
for(i = 0; i < saves.size(); i++) for(i = 0; i < saves.size(); i++)
{ {
if(saveX == savesX) if(saveX == savesX)

View File

@ -19,12 +19,14 @@ class SearchView: public ui::Window
private: private:
SearchController * c; SearchController * c;
vector<ui::SaveButton*> saveButtons; vector<ui::SaveButton*> saveButtons;
vector<ui::Button*> tagButtons;
ui::Button * favButton; ui::Button * favButton;
ui::Button * nextButton; ui::Button * nextButton;
ui::Button * previousButton; ui::Button * previousButton;
ui::Label * errorLabel; ui::Label * errorLabel;
ui::Textbox * searchField; ui::Textbox * searchField;
ui::Label * infoLabel; ui::Label * infoLabel;
ui::Label * tagsLabel;
ui::Button * sortButton; ui::Button * sortButton;
ui::Button * ownButton; ui::Button * ownButton;
ui::Spinner * loadingSpinner; ui::Spinner * loadingSpinner;
@ -44,6 +46,7 @@ public:
SearchView(); SearchView();
virtual ~SearchView(); virtual ~SearchView();
void AttachController(SearchController * _c) { c = _c; } void AttachController(SearchController * _c) { c = _c; }
virtual void Search(std::string);
virtual void OnTick(float dt); virtual void OnTick(float dt);
virtual void OnMouseWheel(int x, int y, int d); virtual void OnMouseWheel(int x, int y, int d);
virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt); virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt);