2022-11-21 19:15:22 +00:00
|
|
|
#include "Common/UI/View.h"
|
|
|
|
#include "Common/UI/AsyncImageFileView.h"
|
|
|
|
#include "Common/UI/Context.h"
|
|
|
|
#include "Common/Render/DrawBuffer.h"
|
2023-12-13 09:45:42 +00:00
|
|
|
#include "Common/Render/ManagedTexture.h"
|
2022-11-21 19:15:22 +00:00
|
|
|
|
|
|
|
AsyncImageFileView::AsyncImageFileView(const Path &filename, UI::ImageSizeMode sizeMode, UI::LayoutParams *layoutParams)
|
|
|
|
: UI::Clickable(layoutParams), canFocus_(true), filename_(filename), color_(0xFFFFFFFF), sizeMode_(sizeMode), textureFailed_(false), fixedSizeW_(0.0f), fixedSizeH_(0.0f) {}
|
|
|
|
|
|
|
|
AsyncImageFileView::~AsyncImageFileView() {}
|
|
|
|
|
|
|
|
static float DesiredSize(float sz, float contentSize, UI::MeasureSpec spec) {
|
|
|
|
float measured;
|
|
|
|
UI::MeasureBySpec(sz, contentSize, spec, &measured);
|
|
|
|
return measured;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AsyncImageFileView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const {
|
|
|
|
if (texture_ && texture_->GetTexture()) {
|
|
|
|
float texw = (float)texture_->Width();
|
|
|
|
float texh = (float)texture_->Height();
|
|
|
|
float desiredW = DesiredSize(layoutParams_->width, w, horiz);
|
|
|
|
float desiredH = DesiredSize(layoutParams_->height, h, vert);
|
|
|
|
switch (sizeMode_) {
|
|
|
|
case UI::IS_FIXED:
|
|
|
|
w = fixedSizeW_;
|
|
|
|
h = fixedSizeH_;
|
|
|
|
break;
|
|
|
|
case UI::IS_KEEP_ASPECT:
|
|
|
|
w = texw;
|
|
|
|
h = texh;
|
|
|
|
if (desiredW != w || desiredH != h) {
|
|
|
|
float aspect = w / h;
|
|
|
|
// We need the other dimension based on the desired scale to find the best aspect.
|
|
|
|
float desiredWOther = DesiredSize(layoutParams_->height, h * (desiredW / w), vert);
|
|
|
|
float desiredHOther = DesiredSize(layoutParams_->width, w * (desiredH / h), horiz);
|
|
|
|
|
|
|
|
float diffW = fabsf(aspect - desiredW / desiredWOther);
|
|
|
|
float diffH = fabsf(aspect - desiredH / desiredHOther);
|
|
|
|
if (diffW < diffH) {
|
|
|
|
w = desiredW;
|
|
|
|
h = desiredWOther;
|
|
|
|
} else {
|
|
|
|
w = desiredHOther;
|
|
|
|
h = desiredH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UI::IS_DEFAULT:
|
|
|
|
default:
|
|
|
|
w = texw;
|
|
|
|
h = texh;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
w = 16;
|
|
|
|
h = 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AsyncImageFileView::SetFilename(const Path &filename) {
|
|
|
|
if (filename_ != filename) {
|
|
|
|
textureFailed_ = false;
|
|
|
|
filename_ = filename;
|
|
|
|
texture_.reset(nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AsyncImageFileView::DeviceLost() {
|
|
|
|
if (texture_.get())
|
|
|
|
texture_->DeviceLost();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AsyncImageFileView::DeviceRestored(Draw::DrawContext *draw) {
|
|
|
|
if (texture_.get())
|
|
|
|
texture_->DeviceRestored(draw);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AsyncImageFileView::Draw(UIContext &dc) {
|
|
|
|
using namespace Draw;
|
|
|
|
if (!texture_ && !textureFailed_ && !filename_.empty()) {
|
2023-12-13 10:45:48 +00:00
|
|
|
texture_ = std::unique_ptr<ManagedTexture>(new ManagedTexture(dc.GetDrawContext(), filename_.c_str(), ImageFileType::DETECT, true));
|
2022-11-21 19:15:22 +00:00
|
|
|
if (!texture_.get())
|
|
|
|
textureFailed_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HasFocus()) {
|
|
|
|
dc.FillRect(dc.theme->itemFocusedStyle.background, bounds_.Expand(3));
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: involve sizemode
|
|
|
|
if (texture_ && texture_->GetTexture()) {
|
|
|
|
dc.Flush();
|
|
|
|
dc.GetDrawContext()->BindTexture(0, texture_->GetTexture());
|
|
|
|
dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_);
|
|
|
|
dc.Flush();
|
|
|
|
dc.RebindTexture();
|
|
|
|
if (!text_.empty()) {
|
|
|
|
dc.DrawText(text_.c_str(), bounds_.centerX() + 1, bounds_.centerY() + 1, 0x80000000, ALIGN_CENTER | FLAG_DYNAMIC_ASCII);
|
|
|
|
dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!filename_.empty()) {
|
|
|
|
// draw a black rectangle to represent the missing screenshot.
|
|
|
|
dc.FillRect(UI::Drawable(0xFF000000), GetBounds());
|
|
|
|
} else {
|
|
|
|
// draw a dark gray rectangle to represent no save state.
|
|
|
|
dc.FillRect(UI::Drawable(0x50202020), GetBounds());
|
|
|
|
}
|
|
|
|
if (!text_.empty()) {
|
|
|
|
dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER | FLAG_DYNAMIC_ASCII);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|