mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-03 21:03:44 +01:00
Add ListView, make FrameLayout do something
This commit is contained in:
1 parent
2143b5b608
commit
bc2a18eeee
8 files changed
+120
-24
No files matched your search
+9
-3
@@ -95,8 +95,7 @@ void ScreenManager::sendMessage(const char *msg, const char *value) {
|
||||
stack_.back().screen->sendMessage(msg, value);
|
||||
}
|
||||
|
||||
void ScreenManager::deviceLost()
|
||||
{
|
||||
void ScreenManager::deviceLost() {
|
||||
if (!stack_.empty())
|
||||
stack_.back().screen->deviceLost();
|
||||
// Dialogs too? Nah, they should only use the standard UI texture anyway.
|
||||
@@ -124,6 +123,9 @@ void ScreenManager::push(Screen *screen, int layerFlags) {
|
||||
switchToNext();
|
||||
}
|
||||
screen->setScreenManager(this);
|
||||
if (screen->isTransparent()) {
|
||||
layerFlags |= LAYER_TRANSPARENT;
|
||||
}
|
||||
Layer layer = {screen, layerFlags};
|
||||
stack_.push_back(layer);
|
||||
}
|
||||
@@ -157,7 +159,11 @@ void ScreenManager::processFinishDialog() {
|
||||
}
|
||||
|
||||
Screen *caller = topScreen();
|
||||
caller->dialogFinished(dialogFinished_, dialogResult_);
|
||||
if (caller) {
|
||||
caller->dialogFinished(dialogFinished_, dialogResult_);
|
||||
} else {
|
||||
ELOG("ERROR: no top screen when finishing dialog");
|
||||
}
|
||||
delete dialogFinished_;
|
||||
dialogFinished_ = 0;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
|
||||
virtual void *dialogData() { return 0; }
|
||||
|
||||
virtual bool isTransparent() { return false; }
|
||||
|
||||
private:
|
||||
ScreenManager *screenManager_;
|
||||
DISALLOW_COPY_AND_ASSIGN(Screen);
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ void UIScreen::render() {
|
||||
UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_);
|
||||
|
||||
screenManager()->getUIContext()->Begin();
|
||||
DrawBackground();
|
||||
DrawBackground(*screenManager()->getUIContext());
|
||||
root_->Draw(*screenManager()->getUIContext());
|
||||
screenManager()->getUIContext()->End();
|
||||
screenManager()->getUIContext()->Flush();
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void CreateViews() = 0;
|
||||
virtual void DrawBackground() {}
|
||||
virtual void DrawBackground(UIContext &dc) {}
|
||||
|
||||
void RecreateViews() { recreateViews_ = true; }
|
||||
|
||||
|
||||
+12
-1
@@ -154,8 +154,19 @@ Item::Item(LayoutParams *layoutParams) : InertView(layoutParams) {
|
||||
layoutParams_->height = ITEM_HEIGHT;
|
||||
}
|
||||
|
||||
void Item::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 0.0f;
|
||||
h = 0.0f;
|
||||
}
|
||||
|
||||
void ClickableItem::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 0.0f;
|
||||
h = 0.0f;
|
||||
}
|
||||
|
||||
ClickableItem::ClickableItem(LayoutParams *layoutParams) : Clickable(layoutParams) {
|
||||
layoutParams_->width = FILL_PARENT;
|
||||
if (layoutParams_->width == WRAP_CONTENT)
|
||||
layoutParams_->width = FILL_PARENT;
|
||||
layoutParams_->height = ITEM_HEIGHT;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,14 +183,16 @@ public:
|
||||
// Call this from UI thread
|
||||
void Update();
|
||||
|
||||
// This is suggested for use in most cases. Autobinds, allowing for neat syntax.
|
||||
template<class T>
|
||||
void Handle(T *thiz, EventReturn (T::* theCallback)(EventParams &e)) {
|
||||
Add(std::bind(theCallback, thiz, placeholder::_1));
|
||||
}
|
||||
|
||||
private:
|
||||
// Sometimes you have an already-bound function<>, just use this then.
|
||||
void Add(std::function<EventReturn(EventParams&)> func);
|
||||
|
||||
private:
|
||||
recursive_mutex mutex_;
|
||||
std::vector<HandlerRegistration> handlers_;
|
||||
bool triggered_;
|
||||
@@ -381,19 +383,13 @@ private:
|
||||
class Item : public InertView {
|
||||
public:
|
||||
Item(LayoutParams *layoutParams);
|
||||
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 0.0f;
|
||||
h = 0.0f;
|
||||
}
|
||||
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
|
||||
};
|
||||
|
||||
class ClickableItem : public Clickable {
|
||||
public:
|
||||
ClickableItem(LayoutParams *layoutParams);
|
||||
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 0.0f;
|
||||
h = 0.0f;
|
||||
}
|
||||
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
|
||||
|
||||
// Draws the item background.
|
||||
virtual void Draw(UIContext &dc);
|
||||
|
||||
+52
-8
@@ -1,4 +1,5 @@
|
||||
#include "base/display.h"
|
||||
#include "base/functional.h"
|
||||
#include "base/logging.h"
|
||||
#include "ui/ui_context.h"
|
||||
#include "ui/view.h"
|
||||
@@ -368,7 +369,18 @@ void FrameLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ve
|
||||
}
|
||||
|
||||
void FrameLayout::Layout() {
|
||||
for (size_t i = 0; i < views_.size(); i++) {
|
||||
float w = views_[i]->GetMeasuredWidth();
|
||||
float h = views_[i]->GetMeasuredHeight();
|
||||
|
||||
Bounds bounds;
|
||||
bounds.w = w;
|
||||
bounds.h = h;
|
||||
|
||||
bounds.x = bounds_.x + (measuredWidth_ - w) / 2;
|
||||
bounds.y = bounds_.y + (measuredWidth_ - h) / 2;
|
||||
views_[i]->SetBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) {
|
||||
@@ -537,8 +549,8 @@ void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
if (params->top >= 0 && params->bottom >= 0) {
|
||||
height = measuredHeight_ - params->top - params->bottom;
|
||||
}
|
||||
specW = MeasureSpec(EXACTLY, width);
|
||||
specH = MeasureSpec(EXACTLY, height);
|
||||
specW = width < 0 ? MeasureSpec(UNSPECIFIED) : MeasureSpec(EXACTLY, width);
|
||||
specH = height < 0 ? MeasureSpec(UNSPECIFIED) : MeasureSpec(EXACTLY, height);
|
||||
}
|
||||
|
||||
views_[i]->Measure(dc, specW, specH);
|
||||
@@ -562,12 +574,18 @@ void AnchorLayout::Layout() {
|
||||
bottom = params->bottom;
|
||||
}
|
||||
|
||||
if (left >= 0) vBounds.x = bounds_.x + left;
|
||||
if (top >= 0) vBounds.y = bounds_.y + top;
|
||||
if (right >= 0) vBounds.x = bounds_.x2() - right - vBounds.w;
|
||||
if (bottom >= 0) vBounds.y = bounds_.y2() - bottom - vBounds.y;
|
||||
if (left >= 0)
|
||||
vBounds.x = bounds_.x + left;
|
||||
else if (right >= 0)
|
||||
vBounds.x = bounds_.x2() - right - vBounds.w;
|
||||
|
||||
if (top >= 0)
|
||||
vBounds.y = bounds_.y + top;
|
||||
else if (bottom >= 0)
|
||||
vBounds.y = bounds_.y2() - bottom - vBounds.h;
|
||||
|
||||
views_[i]->SetBounds(vBounds);
|
||||
views_[i]->Layout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,8 +646,7 @@ void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root) {
|
||||
}
|
||||
|
||||
void UpdateViewHierarchy(const InputState &input_state, ViewGroup *root) {
|
||||
if (input_state.pad_buttons_down & (PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT | PAD_BUTTON_UP | PAD_BUTTON_DOWN))
|
||||
{
|
||||
if (input_state.pad_buttons_down & (PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT | PAD_BUTTON_UP | PAD_BUTTON_DOWN)) {
|
||||
EnableFocusMovement(true);
|
||||
if (!GetFocusedView()) {
|
||||
root->SetFocus();
|
||||
@@ -651,4 +668,31 @@ void UpdateViewHierarchy(const InputState &input_state, ViewGroup *root) {
|
||||
root->Update(input_state);
|
||||
}
|
||||
|
||||
ListView::ListView(ListAdaptor *a, LayoutParams *layoutParams)
|
||||
: ScrollView(ORIENT_VERTICAL, layoutParams), adaptor_(a) {
|
||||
// Let's not be clever yet, we'll just create them all up front and add them all in.
|
||||
for (int i = 0; i < adaptor_->GetNumItems(); i++) {
|
||||
View * v = Add(adaptor_->CreateItemView(i));
|
||||
adaptor_->AddEventCallback(v, std::bind(&ListView::OnItemCallback, this, i, placeholder::_1));
|
||||
}
|
||||
}
|
||||
|
||||
EventReturn ListView::OnItemCallback(int num, EventParams &e) {
|
||||
EventParams ev;
|
||||
ev.v = e.v;
|
||||
ev.a = num;
|
||||
OnChoice.Trigger(ev);
|
||||
return EVENT_DONE;
|
||||
}
|
||||
|
||||
View *ChoiceListAdaptor::CreateItemView(int index) {
|
||||
return new Choice(items_[index]);
|
||||
}
|
||||
|
||||
bool ChoiceListAdaptor::AddEventCallback(View *view, std::function<EventReturn(EventParams&)> callback) {
|
||||
Choice *choice = (Choice *)view;
|
||||
choice->OnClick.Add(callback);
|
||||
return EVENT_DONE;
|
||||
}
|
||||
|
||||
} // namespace UI
|
||||
+38
-1
@@ -51,6 +51,7 @@ protected:
|
||||
};
|
||||
|
||||
// A frame layout contains a single child view (normally).
|
||||
// It simply centers the child view.
|
||||
class FrameLayout : public ViewGroup {
|
||||
public:
|
||||
void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert);
|
||||
@@ -65,7 +66,9 @@ enum {
|
||||
class AnchorLayoutParams : public LayoutParams {
|
||||
public:
|
||||
AnchorLayoutParams(Size w, Size h, float l, float t, float r, float b)
|
||||
: LayoutParams(w, h), left(l), top(t), right(r), bottom(b) {}
|
||||
: LayoutParams(w, h), left(l), top(t), right(r), bottom(b) {
|
||||
|
||||
}
|
||||
|
||||
AnchorLayoutParams(float l, float t, float r, float b)
|
||||
: LayoutParams(WRAP_CONTENT, WRAP_CONTENT), left(l), top(t), right(r), bottom(b) {}
|
||||
@@ -232,6 +235,40 @@ private:
|
||||
std::vector<View *> tabs_;
|
||||
};
|
||||
|
||||
// Yes, this feels a bit Java-ish...
|
||||
class ListAdaptor {
|
||||
public:
|
||||
virtual ~ListAdaptor() {}
|
||||
virtual View *CreateItemView(int index) = 0;
|
||||
virtual int GetNumItems() = 0;
|
||||
virtual bool AddEventCallback(View *view, std::function<EventReturn(EventParams&)> callback) { return false; }
|
||||
};
|
||||
|
||||
class ChoiceListAdaptor {
|
||||
public:
|
||||
ChoiceListAdaptor(const char *items[], int numItems) : items_(items), numItems_(numItems) {}
|
||||
virtual View *CreateItemView(int index);
|
||||
virtual int GetNumItems() { return numItems_; }
|
||||
virtual bool AddEventCallback(View *view, std::function<EventReturn(EventParams&)> callback);
|
||||
|
||||
private:
|
||||
const char **items_;
|
||||
int numItems_;
|
||||
};
|
||||
|
||||
// A list view is a scroll view with autogenerated items.
|
||||
// In the future, it might be smart and load/unload items as they go, but currently not.
|
||||
class ListView : public ScrollView {
|
||||
public:
|
||||
ListView(ListAdaptor *a, LayoutParams *layoutParams);
|
||||
|
||||
Event OnChoice;
|
||||
|
||||
private:
|
||||
EventReturn OnItemCallback(int num, EventParams &e);
|
||||
ListAdaptor *adaptor_;
|
||||
};
|
||||
|
||||
void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root);
|
||||
void UpdateViewHierarchy(const InputState &input_state, ViewGroup *root);
|
||||
|
||||
|
||||
Reference in new issue
Block a user