#include "SaveButton.h" #include "ContextMenu.h" #include "Format.h" #include "client/Client.h" #include "client/ThumbnailRendererTask.h" #include "client/SaveFile.h" #include "client/SaveInfo.h" #include "gui/dialogues/ErrorMessage.h" #include "graphics/Graphics.h" #include "SimulationConfig.h" #include namespace ui { SaveButton::SaveButton(Point position, Point size) : Component(position, size), file(nullptr), save(nullptr), wantsDraw(false), triedThumbnail(false), isMouseInsideAuthor(false), isMouseInsideHistory(false), showVotes(false), thumbnailRenderer(nullptr), isButtonDown(false), isMouseInside(false), selected(false), selectable(false) { } SaveButton::SaveButton(Point position, Point size, SaveInfo * save_) : SaveButton(position, size) { save = save_; if(save) { name = save->name; if (Graphics::TextSize(name).X > Size.X) { auto it = Graphics::TextFit(name, Size.X - (Appearance.icon ? 38 : 22)); name.erase(it, name.end()); name += "..."; } String votes, icon; votes = String::Build(save->GetVotesUp()-save->GetVotesDown()); icon += 0xE03B; for (size_t j = 1; j < votes.length(); j++) icon += 0xE03C; icon += 0xE039; icon += 0xE03A; votesBackground = icon; for (String::iterator iter = icon.begin(), end = icon.end(); iter != end; ++iter) *iter -= 14; // 0xE039 -> 0xE02B votesBackground2 = icon; for (String::iterator iter = votes.begin(), end = votes.end(); iter != end; ++iter) if(*iter != '-') *iter += 0xDFFF; // 0x30 -> 0xE02F votesString = votes; int voteMax = std::max(save->GetVotesUp(),save->GetVotesDown()); if (voteMax) { if (voteMax < 34) { float ry = 33.0f/voteMax; if (voteMax<8) ry = ry/(8-voteMax); voteBarHeightUp = (int)(save->GetVotesUp()*ry)-1; voteBarHeightDown = (int)(save->GetVotesDown()*ry)-1; } else { float ry = voteMax/33.0f; voteBarHeightUp = (int)(save->GetVotesUp()/ry)-1; voteBarHeightDown = (int)(save->GetVotesDown()/ry)-1; } } else { voteBarHeightUp = 0; voteBarHeightDown = 0; } } } SaveButton::SaveButton(Point position, Point size, SaveFile * file_) : SaveButton(position, size) { file = file_; if(file) { name = file->GetDisplayName(); if (Graphics::TextSize(name).X > Size.X) { auto it = Graphics::TextFit(name, Size.X - (Appearance.icon ? 38 : 22)); name.erase(it, name.end()); name += "..."; } } } SaveButton::~SaveButton() { if (thumbnailRenderer) { thumbnailRenderer->Abandon(); } delete save; delete file; } void SaveButton::Tick(float dt) { if (!thumbnail) { if (!triedThumbnail && wantsDraw && ThumbnailRendererTask::QueueSize() < 10) { float scaleFactor = (Size.Y-25)/((float)YRES); ui::Point thumbBoxSize = ui::Point(int(XRES*scaleFactor), int(YRES*scaleFactor)); if (save) { if(save->GetGameSave()) { thumbnailRenderer = new ThumbnailRendererTask(*save->GetGameSave(), thumbBoxSize, true, true); thumbnailRenderer->Start(); triedThumbnail = true; } else if (save->GetID()) { thumbnailRequest = std::make_unique(save->GetID(), save->GetVersion(), thumbBoxSize); thumbnailRequest->Start(); triedThumbnail = true; } } else if (file && file->GetGameSave()) { thumbnailRenderer = new ThumbnailRendererTask(*file->GetGameSave(), thumbBoxSize, true, false); thumbnailRenderer->Start(); triedThumbnail = true; } } if (thumbnailRequest && thumbnailRequest->CheckDone()) { thumbnail = thumbnailRequest->Finish(); thumbnailRequest.reset(); } if (thumbnailRenderer) { thumbnailRenderer->Poll(); if (thumbnailRenderer->GetDone()) { thumbnail = thumbnailRenderer->Finish(); thumbnailRenderer = nullptr; } } if (thumbnail && file) { thumbSize = thumbnail->Size(); } } if (file && !wantsDraw && !thumbnailRenderer) { file->LazyUnload(); } wantsDraw = false; } void SaveButton::Draw(const Point& screenPos) { Graphics * g = GetGraphics(); float scaleFactor = (Size.Y-25)/((float)YRES); ui::Point thumbBoxSize = ui::Point(int(XRES*scaleFactor), int(YRES*scaleFactor)); wantsDraw = true; if(selected && selectable) { g->fillrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 100, 170, 255, 100); } if (thumbnail) { //thumbBoxSize = ui::Point(thumbnail->Width, thumbnail->Height); if (save && save->id) g->draw_image(thumbnail.get(), screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 255); else g->draw_image(thumbnail.get(), screenPos.X+(Size.X-thumbSize.X)/2, screenPos.Y+(Size.Y-21-thumbSize.Y)/2, 255); } else if (file && !file->GetGameSave()) g->drawtext(screenPos.X+(Size.X-Graphics::textwidth("Error loading save"))/2, screenPos.Y+(Size.Y-28)/2, "Error loading save", 180, 180, 180, 255); if(save) { if(save->id) { if(isMouseInside) { g->drawrect(screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 210, 230, 255, 255); g->drawrect(screenPos.X-4+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 7, thumbBoxSize.Y, 210, 230, 255, 255); } else { g->drawrect(screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 180, 180, 180, 255); g->drawrect(screenPos.X-4+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 7, thumbBoxSize.Y, 180, 180, 180, 255); } g->fillrect(screenPos.X-3+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+1+(Size.Y-20-thumbBoxSize.Y)/2, 5, (thumbBoxSize.Y+1)/2-1, 0, 107, 10, 255); g->fillrect(screenPos.X-3+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-20)/2, 5, thumbBoxSize.Y/2-1, 107, 10, 0, 255); g->fillrect(screenPos.X-2+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-20)/2-voteBarHeightUp, 3, voteBarHeightUp, 57, 187, 57, 255); //green g->fillrect(screenPos.X-2+thumbBoxSize.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-20)/2, 3, voteBarHeightDown, 187, 57, 57, 255); //red } else { if(isMouseInside) g->drawrect(screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 210, 230, 255, 255); else g->drawrect(screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 180, 180, 180, 255); } if(isMouseInside && !isMouseInsideAuthor) g->drawtext(screenPos.X+(Size.X-Graphics::textwidth(name))/2, screenPos.Y+Size.Y - 21, name, 255, 255, 255, 255); else g->drawtext(screenPos.X+(Size.X-Graphics::textwidth(name))/2, screenPos.Y+Size.Y - 21, name, 180, 180, 180, 255); if(isMouseInsideAuthor) g->drawtext(screenPos.X+(Size.X-Graphics::textwidth(save->userName.FromUtf8()))/2, screenPos.Y+Size.Y - 10, save->userName.FromUtf8(), 200, 230, 255, 255); else g->drawtext(screenPos.X+(Size.X-Graphics::textwidth(save->userName.FromUtf8()))/2, screenPos.Y+Size.Y - 10, save->userName.FromUtf8(), 100, 130, 160, 255); if (showVotes)// && !isMouseInside) { int x = screenPos.X-7+(Size.X-thumbBoxSize.X)/2+thumbBoxSize.X-Graphics::textwidth(votesBackground); int y = screenPos.Y-23+(Size.Y-thumbBoxSize.Y)/2+thumbBoxSize.Y; g->drawtext(x, y, votesBackground, 16, 72, 16, 255); g->drawtext(x, y, votesBackground2, 192, 192, 192, 255); g->drawtext(x+3, y, votesString, 255, 255, 255, 255); } if (isMouseInsideHistory && showVotes) { int x = screenPos.X; int y = screenPos.Y-15+(Size.Y-thumbBoxSize.Y)/2+thumbBoxSize.Y; g->fillrect(x+1, y+1, 7, 8, 255, 255, 255, 255); if (isMouseInsideHistory) { g->drawtext(x, y, 0xE026, 200, 100, 80, 255); } else { g->drawtext(x, y, 0xE026, 160, 70, 50, 255); } } if (!save->GetPublished()) { g->drawtext(screenPos.X, screenPos.Y-2, 0xE04D, 255, 255, 255, 255); g->drawtext(screenPos.X, screenPos.Y-2, 0xE04E, 212, 151, 81, 255); } } else if (file) { if (isMouseInside) g->drawrect(screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 210, 230, 255, 255); else g->drawrect(screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbBoxSize.X, thumbBoxSize.Y, 180, 180, 180, 255); if (thumbSize.X) g->xor_rect(screenPos.X+(Size.X-thumbSize.X)/2, screenPos.Y+(Size.Y-21-thumbSize.Y)/2, thumbSize.X, thumbSize.Y); if (isMouseInside) { g->drawtext(screenPos.X+(Size.X-Graphics::textwidth(name))/2, screenPos.Y+Size.Y - 21, name, 255, 255, 255, 255); } else { g->drawtext(screenPos.X+(Size.X-Graphics::textwidth(name))/2, screenPos.Y+Size.Y - 21, name, 180, 180, 180, 255); } } if(isMouseInside && selectable) { g->clearrect(screenPos.X+(Size.X-20), screenPos.Y+6, 14, 14); g->drawrect(screenPos.X+(Size.X-20), screenPos.Y+6, 14, 14, 255, 255, 255, 255); if(selected) g->fillrect(screenPos.X+(Size.X-18), screenPos.Y+8, 10, 10, 255, 255, 255, 255); } } void SaveButton::OnMouseUnclick(int x, int y, unsigned int button) { if(button != 1) { return; //left click only! } if (file && !file->GetGameSave()) { new ErrorMessage("Error loading save", file->GetError()); return; } if(x>=Size.X-20 && y>=6 && y<=20 && x<=Size.X-6 && selectable) { selected = !selected; DoSelection(); return; } if(isButtonDown) { isButtonDown = false; if(isMouseInsideHistory) DoAltAction(); else if(isMouseInsideAuthor) DoAltAction2(); else DoAction(); } } void SaveButton::AddContextMenu(int menuType) { if (menuType == 0) //Save browser { menu = new ContextMenu(this); menu->AddItem(ContextMenuItem("Open", 0, true)); if (Client::Ref().GetAuthUser().UserID) menu->AddItem(ContextMenuItem("Select", 1, true)); menu->AddItem(ContextMenuItem("View History", 2, true)); menu->AddItem(ContextMenuItem("More by this user", 3, true)); } else if (menuType == 1) //Local save browser { menu = new ContextMenu(this); menu->AddItem(ContextMenuItem("Open", 0, true)); menu->AddItem(ContextMenuItem("Rename", 2, true)); menu->AddItem(ContextMenuItem("Delete", 3, true)); } } void SaveButton::OnContextMenuAction(int item) { switch(item) { case 0: DoAction(); break; case 1: selected = !selected; DoSelection(); break; case 2: DoAltAction(); break; case 3: DoAltAction2(); break; } } void SaveButton::OnMouseClick(int x, int y, unsigned int button) { if(button == SDL_BUTTON_RIGHT) { if(menu) menu->Show(GetScreenPos() + ui::Point(x, y)); } else { isButtonDown = true; if(button !=1 && selectable) { selected = !selected; DoSelection(); } } } void SaveButton::OnMouseMovedInside(int x, int y, int dx, int dy) { if(y > Size.Y-11) isMouseInsideAuthor = true; else isMouseInsideAuthor = false; if(showVotes && y > Size.Y-29 && y < Size.Y - 18 && x > 0 && x < 9) isMouseInsideHistory = true; else isMouseInsideHistory = false; } void SaveButton::OnMouseEnter(int x, int y) { isMouseInside = true; } void SaveButton::OnMouseLeave(int x, int y) { isMouseInside = false; isMouseInsideAuthor = false; isMouseInsideHistory = false; } void SaveButton::DoAltAction() { if (actionCallback.altAction) actionCallback.altAction(); } void SaveButton::DoAltAction2() { if (actionCallback.altAltAction) actionCallback.altAltAction(); } void SaveButton::DoAction() { if (actionCallback.action) actionCallback.action(); } void SaveButton::DoSelection() { if(menu) { if(selected) menu->SetItem(1, "Deselect"); else menu->SetItem(1, "Select"); } if (selectable && actionCallback.selected) actionCallback.selected(); } } /* namespace ui */