mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #10388 from unknownbrackets/ui-tween2
Transition between tab content
This commit is contained in:
commit
caf9eca2db
7 changed files with 109 additions and 31 deletions
|
@ -132,7 +132,7 @@ void TextDrawerWin32::MeasureString(const char *str, size_t len, float *w, float
|
|||
}
|
||||
|
||||
SIZE size;
|
||||
std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(std::string(str, len), "\n", "\r\n"));
|
||||
std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(ReplaceAll(std::string(str, len), "\n", "\r\n"), "&&", "&"));
|
||||
GetTextExtentPoint32(ctx_->hDC, wstr.c_str(), (int)wstr.size(), &size);
|
||||
|
||||
entry = new TextMeasureEntry();
|
||||
|
@ -171,7 +171,7 @@ void TextDrawerWin32::MeasureStringRect(const char *str, size_t len, const Bound
|
|||
entry = iter->second.get();
|
||||
} else {
|
||||
SIZE size;
|
||||
std::wstring wstr = ConvertUTF8ToWString(lines[i].length() == 0 ? " " : lines[i]);
|
||||
std::wstring wstr = ConvertUTF8ToWString(lines[i].length() == 0 ? " " : ReplaceAll(lines[i], "&&", "&"));
|
||||
GetTextExtentPoint32(ctx_->hDC, wstr.c_str(), (int)wstr.size(), &size);
|
||||
|
||||
entry = new TextMeasureEntry();
|
||||
|
|
|
@ -14,6 +14,10 @@ struct Point {
|
|||
return sqrtf(dx*dx + dy*dy);
|
||||
}
|
||||
|
||||
bool operator ==(const Point &other) const {
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
|
||||
/*
|
||||
FocusDirection directionTo(const Point &other) const {
|
||||
int angle = atan2f(other.y - y, other.x - x) / (2 * M_PI) - 0.125;
|
||||
|
|
|
@ -70,6 +70,8 @@ void UIContext::PushScissor(const Bounds &bounds) {
|
|||
Bounds clipped = TransformBounds(bounds);
|
||||
if (scissorStack_.size())
|
||||
clipped.Clip(scissorStack_.back());
|
||||
else
|
||||
clipped.Clip(bounds_);
|
||||
scissorStack_.push_back(clipped);
|
||||
ActivateTopScissor();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "base/colorutil.h"
|
||||
#include "ui/ui_tween.h"
|
||||
#include "ui/view.h"
|
||||
#include "ui/viewgroup.h"
|
||||
|
||||
namespace UI {
|
||||
|
||||
|
@ -66,6 +67,7 @@ void TweenBase<Value>::PersistData(PersistStatus status, std::string anonId, Per
|
|||
|
||||
template void TweenBase<uint32_t>::PersistData(PersistStatus status, std::string anonId, PersistMap &storage);
|
||||
template void TweenBase<Visibility>::PersistData(PersistStatus status, std::string anonId, PersistMap &storage);
|
||||
template void TweenBase<Point>::PersistData(PersistStatus status, std::string anonId, PersistMap &storage);
|
||||
|
||||
uint32_t ColorTween::Current(float pos) {
|
||||
return colorBlend(to_, from_, pos);
|
||||
|
@ -96,4 +98,19 @@ Visibility VisibilityTween::Current(float p) {
|
|||
return p >= 1.0f ? to_ : from_;
|
||||
}
|
||||
|
||||
void AnchorTranslateTween::DoApply(View *view, float pos) {
|
||||
Point cur = Current(pos);
|
||||
|
||||
auto prev = view->GetLayoutParams()->As<AnchorLayoutParams>();
|
||||
auto lp = new AnchorLayoutParams(prev ? *prev : AnchorLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
lp->left = cur.x;
|
||||
lp->top = cur.y;
|
||||
view->ReplaceLayoutParams(lp);
|
||||
}
|
||||
|
||||
Point AnchorTranslateTween::Current(float p) {
|
||||
float inv = 1.0f - p;
|
||||
return Point(from_.x * inv + to_.x * p, from_.y * inv + to_.y * p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -182,4 +182,14 @@ protected:
|
|||
Visibility Current(float pos) override;
|
||||
};
|
||||
|
||||
class AnchorTranslateTween : public TweenBase<Point> {
|
||||
public:
|
||||
using TweenBase::TweenBase;
|
||||
|
||||
protected:
|
||||
void DoApply(View *view, float pos) override;
|
||||
|
||||
Point Current(float pos) override;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
#include "base/stringutil.h"
|
||||
#include "base/timeutil.h"
|
||||
#include "input/keycodes.h"
|
||||
#include "math/curves.h"
|
||||
#include "ui/ui_context.h"
|
||||
#include "ui/ui_tween.h"
|
||||
#include "ui/view.h"
|
||||
#include "ui/viewgroup.h"
|
||||
#include "gfx_es2/draw_buffer.h"
|
||||
|
@ -143,6 +145,7 @@ void ViewGroup::Draw(UIContext &dc) {
|
|||
}
|
||||
|
||||
void ViewGroup::Update() {
|
||||
View::Update();
|
||||
for (View *view : views_) {
|
||||
if (view->GetVisibility() != V_GONE)
|
||||
view->Update();
|
||||
|
@ -994,10 +997,10 @@ void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
|||
height = params->height;
|
||||
|
||||
if (!params->center) {
|
||||
if (params->left >= 0 && params->right >= 0) {
|
||||
if (params->left > NONE && params->right > NONE) {
|
||||
width = measuredWidth_ - params->left - params->right;
|
||||
}
|
||||
if (params->top >= 0 && params->bottom >= 0) {
|
||||
if (params->top > NONE && params->bottom > NONE) {
|
||||
height = measuredHeight_ - params->top - params->bottom;
|
||||
}
|
||||
}
|
||||
|
@ -1034,22 +1037,22 @@ void AnchorLayout::Layout() {
|
|||
center = params->center;
|
||||
}
|
||||
|
||||
if (left >= 0) {
|
||||
if (left > NONE) {
|
||||
vBounds.x = bounds_.x + left;
|
||||
if (center)
|
||||
vBounds.x -= vBounds.w * 0.5f;
|
||||
} else if (right >= 0) {
|
||||
} else if (right > NONE) {
|
||||
vBounds.x = bounds_.x2() - right - vBounds.w;
|
||||
if (center) {
|
||||
vBounds.x += vBounds.w * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
if (top >= 0) {
|
||||
if (top > NONE) {
|
||||
vBounds.y = bounds_.y + top;
|
||||
if (center)
|
||||
vBounds.y -= vBounds.h * 0.5f;
|
||||
} else if (bottom >= 0) {
|
||||
} else if (bottom > NONE) {
|
||||
vBounds.y = bounds_.y2() - bottom - vBounds.h;
|
||||
if (center)
|
||||
vBounds.y += vBounds.h * 0.5f;
|
||||
|
@ -1110,10 +1113,7 @@ void GridLayout::Layout() {
|
|||
}
|
||||
|
||||
TabHolder::TabHolder(Orientation orientation, float stripSize, LayoutParams *layoutParams)
|
||||
: LinearLayout(Opposite(orientation), layoutParams),
|
||||
tabStrip_(nullptr), tabScroll_(nullptr),
|
||||
stripSize_(stripSize),
|
||||
currentTab_(0) {
|
||||
: LinearLayout(Opposite(orientation), layoutParams), stripSize_(stripSize) {
|
||||
SetSpacing(0.0f);
|
||||
if (orientation == ORIENT_HORIZONTAL) {
|
||||
tabStrip_ = new ChoiceStrip(orientation, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
|
@ -1125,9 +1125,23 @@ TabHolder::TabHolder(Orientation orientation, float stripSize, LayoutParams *lay
|
|||
tabStrip_ = new ChoiceStrip(orientation, new LayoutParams(stripSize, WRAP_CONTENT));
|
||||
tabStrip_->SetTopTabs(true);
|
||||
Add(tabStrip_);
|
||||
tabScroll_ = nullptr;
|
||||
}
|
||||
tabStrip_->OnChoice.Handle(this, &TabHolder::OnTabClick);
|
||||
|
||||
contents_ = new AnchorLayout(new LinearLayoutParams(1.0f));
|
||||
Add(contents_)->SetClip(true);
|
||||
}
|
||||
|
||||
void TabHolder::AddTabContents(const std::string &title, View *tabContents) {
|
||||
tabContents->ReplaceLayoutParams(new AnchorLayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
tabs_.push_back(tabContents);
|
||||
tabStrip_->AddChoice(title);
|
||||
contents_->Add(tabContents);
|
||||
if (tabs_.size() > 1)
|
||||
tabContents->SetVisibility(V_GONE);
|
||||
|
||||
// Will be filled in later.
|
||||
tabTweens_.push_back(nullptr);
|
||||
}
|
||||
|
||||
void TabHolder::SetCurrentTab(int tab) {
|
||||
|
@ -1135,10 +1149,44 @@ void TabHolder::SetCurrentTab(int tab) {
|
|||
// Ignore
|
||||
return;
|
||||
}
|
||||
|
||||
auto setupTween = [&](View *view, AnchorTranslateTween *&tween) {
|
||||
if (tween)
|
||||
return;
|
||||
|
||||
tween = new AnchorTranslateTween(0.15f, bezierEaseInOut);
|
||||
tween->Finish.Add([&](EventParams &e) {
|
||||
e.v->SetVisibility(tabs_[currentTab_] == e.v ? V_VISIBLE : V_GONE);
|
||||
return EVENT_DONE;
|
||||
});
|
||||
view->AddTween(tween)->Persist();
|
||||
};
|
||||
|
||||
if (tab != currentTab_) {
|
||||
tabs_[currentTab_]->SetVisibility(V_GONE);
|
||||
Orientation orient = Opposite(orientation_);
|
||||
// Direction from which the new tab will come.
|
||||
float dir = tab < currentTab_ ? -1.0f : 1.0f;
|
||||
|
||||
// First, setup any missing tweens.
|
||||
setupTween(tabs_[currentTab_], tabTweens_[currentTab_]);
|
||||
setupTween(tabs_[tab], tabTweens_[tab]);
|
||||
|
||||
// Currently displayed, so let's reset it.
|
||||
tabTweens_[currentTab_]->Reset(Point(0.0f, 0.0f));
|
||||
|
||||
if (orient == ORIENT_HORIZONTAL) {
|
||||
tabTweens_[tab]->Reset(Point(bounds_.w * dir, 0.0f));
|
||||
tabTweens_[currentTab_]->Divert(Point(bounds_.w * -dir, 0.0f));
|
||||
} else {
|
||||
tabTweens_[tab]->Reset(Point(0.0f, bounds_.h * dir));
|
||||
tabTweens_[currentTab_]->Divert(Point(0.0f, bounds_.h * -dir));
|
||||
}
|
||||
// Actually move it to the initial position now, just to avoid any flicker.
|
||||
tabTweens_[tab]->Apply(tabs_[tab]);
|
||||
tabTweens_[tab]->Divert(Point(0.0f, 0.0f));
|
||||
tabs_[tab]->SetVisibility(V_VISIBLE);
|
||||
|
||||
currentTab_ = tab;
|
||||
tabs_[currentTab_]->SetVisibility(V_VISIBLE);
|
||||
}
|
||||
tabStrip_->SetSelection(tab);
|
||||
}
|
||||
|
@ -1146,10 +1194,8 @@ void TabHolder::SetCurrentTab(int tab) {
|
|||
EventReturn TabHolder::OnTabClick(EventParams &e) {
|
||||
// We have e.b set when it was an explicit click action.
|
||||
// In that case, we make the view gone and then visible - this scrolls scrollviews to the top.
|
||||
if (currentTab_ != (int)e.a || e.b != 0) {
|
||||
tabs_[currentTab_]->SetVisibility(V_GONE);
|
||||
currentTab_ = e.a;
|
||||
tabs_[currentTab_]->SetVisibility(V_VISIBLE);
|
||||
if (e.b != 0) {
|
||||
SetCurrentTab((int)e.a);
|
||||
}
|
||||
return EVENT_DONE;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <cfloat>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <mutex>
|
||||
|
@ -11,6 +12,8 @@
|
|||
|
||||
namespace UI {
|
||||
|
||||
class AnchorTranslateTween;
|
||||
|
||||
struct NeighborResult {
|
||||
NeighborResult() : view(0), score(0) {}
|
||||
NeighborResult(View *v, float s) : view(v), score(s) {}
|
||||
|
@ -95,9 +98,7 @@ public:
|
|||
void Layout() override;
|
||||
};
|
||||
|
||||
enum {
|
||||
NONE = -1,
|
||||
};
|
||||
const float NONE = -FLT_MAX;
|
||||
|
||||
class AnchorLayoutParams : public LayoutParams {
|
||||
public:
|
||||
|
@ -304,12 +305,7 @@ public:
|
|||
|
||||
template <class T>
|
||||
T *AddTab(const std::string &title, T *tabContents) {
|
||||
tabContents->ReplaceLayoutParams(new LinearLayoutParams(1.0f));
|
||||
tabs_.push_back(tabContents);
|
||||
tabStrip_->AddChoice(title);
|
||||
Add(tabContents);
|
||||
if (tabs_.size() > 1)
|
||||
tabContents->SetVisibility(V_GONE);
|
||||
AddTabContents(title, (View *)tabContents);
|
||||
return tabContents;
|
||||
}
|
||||
|
||||
|
@ -321,14 +317,17 @@ public:
|
|||
void PersistData(PersistStatus status, std::string anonId, PersistMap &storage) override;
|
||||
|
||||
private:
|
||||
void AddTabContents(const std::string &title, View *tabContents);
|
||||
EventReturn OnTabClick(EventParams &e);
|
||||
|
||||
ChoiceStrip *tabStrip_;
|
||||
ScrollView *tabScroll_;
|
||||
ChoiceStrip *tabStrip_ = nullptr;
|
||||
ScrollView *tabScroll_ = nullptr;
|
||||
AnchorLayout *contents_ = nullptr;
|
||||
|
||||
float stripSize_;
|
||||
int currentTab_;
|
||||
int currentTab_ = 0;
|
||||
std::vector<View *> tabs_;
|
||||
std::vector<AnchorTranslateTween *> tabTweens_;
|
||||
};
|
||||
|
||||
// Yes, this feels a bit Java-ish...
|
||||
|
|
Loading…
Add table
Reference in a new issue