From 53882c4a33d4bf5b34e4e988028df31ed014271e Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 2 Jul 2015 12:37:13 +0200 Subject: [PATCH] Display game icons in the homebrew store, downloaded from the store --- UI/PauseScreen.cpp | 1 - UI/PauseScreen.h | 1 - UI/Store.cpp | 152 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 151 insertions(+), 3 deletions(-) diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 423d6c19b..52ad0d89c 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -43,7 +43,6 @@ #include "ui/ui_context.h" void AsyncImageFileView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - // TODO: involve sizemode if (texture_) { float texw = (float)texture_->Width(); float texh = (float)texture_->Height(); diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 49fbd0e63..4782c27e6 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -76,7 +76,6 @@ public: void Draw(UIContext &dc) override; void SetFilename(std::string filename); - void SetTexture(Thin3DTexture *texture) { texture_ = texture; } void SetColor(uint32_t color) { color_ = color; } void SetOverlayText(std::string text) { text_ = text; } void SetFixedSize(float fixW, float fixH) { fixedSizeW_ = fixW; fixedSizeH_ = fixH; } diff --git a/UI/Store.cpp b/UI/Store.cpp index 46fbc7ec2..e827fd1c1 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -1,4 +1,23 @@ -#include "native/ext/vjson/json.h" +// Copyright (c) 2014- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "base/functional.h" +#include "base/basictypes.h" +#include "ext/vjson/json.h" #include "i18n/i18n.h" #include "ui/ui_context.h" @@ -6,11 +25,138 @@ #include "gfx_es2/draw_buffer.h" #include "Common/Log.h" +#include "Common/StringUtils.h" #include "Core/Config.h" #include "UI/Store.h" const std::string storeBaseUrl = "http://store.ppsspp.org/"; +// baseUrl is assumed to have a trailing slash, and not contain any subdirectories. +std::string ResolveUrl(std::string baseUrl, std::string url) { + if (url.empty()) { + return baseUrl; + } else if (url[0] == '/') { + return baseUrl + url.substr(1); + } else if (url.substr(0, 7) == "http://") { + return url; + } else { + // Huh. + return baseUrl + url; + } +} + +class HttpImageFileView : public UI::View { +public: + HttpImageFileView(http::Downloader *downloader, const std::string &path, UI::ImageSizeMode sizeMode = UI::IS_DEFAULT, UI::LayoutParams *layoutParams = 0) + : UI::View(layoutParams), downloader_(downloader), path_(path), color_(0xFFFFFFFF), sizeMode_(sizeMode), texture_(nullptr), textureFailed_(false), fixedSizeW_(0.0f), fixedSizeH_(0.0f) {} + + ~HttpImageFileView() { + delete texture_; + } + + void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; + void Draw(UIContext &dc) override; + + void SetFilename(std::string filename); + void SetColor(uint32_t color) { color_ = color; } + void SetFixedSize(float fixW, float fixH) { fixedSizeW_ = fixW; fixedSizeH_ = fixH; } + void SetCanBeFocused(bool can) { canFocus_ = can; } + + bool CanBeFocused() const override { return false; } + + const std::string &GetFilename() const { return path_; } + +private: + void DownloadCompletedCallback(http::Download &download); + + bool canFocus_; + std::string path_; + uint32_t color_; + UI::ImageSizeMode sizeMode_; + http::Downloader *downloader_; + std::shared_ptr download_; + + std::string textureData_; + Thin3DTexture *texture_; + bool textureFailed_; + float fixedSizeW_; + float fixedSizeH_; +}; + +void HttpImageFileView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { + switch (sizeMode_) { + case UI::IS_FIXED: + w = fixedSizeW_; + h = fixedSizeH_; + break; + case UI::IS_DEFAULT: + default: + if (texture_) { + float texw = (float)texture_->Width(); + float texh = (float)texture_->Height(); + w = texw; + h = texh; + } else { + w = 16; + h = 16; + } + break; + } +} + +void HttpImageFileView::SetFilename(std::string filename) { + if (path_ != filename) { + textureFailed_ = false; + path_ = filename; + if (texture_) { + texture_->Release(); + texture_ = nullptr; + } + } +} + +void HttpImageFileView::DownloadCompletedCallback(http::Download &download) { + if (download.ResultCode() == 200) { + download.buffer().TakeAll(&textureData_); + } else { + textureFailed_ = true; + } + + download_.reset(); +} + +void HttpImageFileView::Draw(UIContext &dc) { + if (!texture_ && !textureFailed_ && !path_.empty() && !download_) { + download_ = downloader_->StartDownloadWithCallback(path_, "", std::bind(&HttpImageFileView::DownloadCompletedCallback, this, std::placeholders::_1)); + download_->SetHidden(true); + } + + if (!textureData_.empty()) { + texture_ = dc.GetThin3DContext()->CreateTextureFromFileData((const uint8_t *)(textureData_.data()), (int)textureData_.size(), DETECT); + if (!texture_) + textureFailed_ = true; + textureData_.clear(); + } + + if (HasFocus()) { + dc.FillRect(dc.theme->itemFocusedStyle.background, bounds_.Expand(3)); + } + + // TODO: involve sizemode + if (texture_) { + dc.Flush(); + dc.GetThin3DContext()->SetTexture(0, texture_); + dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_); + dc.Flush(); + dc.RebindTexture(); + } else { + // draw a black rectangle to represent the missing image. + dc.FillRect(UI::Drawable(0xFF000000), GetBounds()); + } +} + + + // This is the entry in a list. Does not have install buttons and so on. class ProductItemView : public UI::Choice { public: @@ -61,6 +207,9 @@ void ProductView::CreateViews() { using namespace UI; Clear(); + if (!entry_.iconURL.empty()) { + Add(new HttpImageFileView(&g_DownloadManager, ResolveUrl(storeBaseUrl, entry_.iconURL), IS_FIXED))->SetFixedSize(144, 88); + } Add(new TextView(entry_.name)); Add(new TextView(entry_.author)); @@ -173,6 +322,7 @@ void StoreScreen::ParseListing(std::string json) { e.author = game->getString("author", "?"); e.size = game->getInt("size"); e.downloadURL = game->getString("download-url", ""); + e.iconURL = game->getString("icon-url", ""); const char *file = game->getString("file", 0); if (!file) continue;