mirror of
https://github.com/libretro/ppsspp.git
synced 2025-01-27 03:35:14 +00:00
More new UI work
This commit is contained in:
parent
02a3cc1b5b
commit
7bad683cae
@ -63,6 +63,7 @@ LOCAL_SRC_FILES :=\
|
||||
ui/ui_context.cpp \
|
||||
ui/screen.cpp \
|
||||
ui/virtual_input.cpp \
|
||||
ui/drawing.cpp \
|
||||
util/random/perlin.cpp \
|
||||
util/text/utf8.cpp
|
||||
|
||||
|
@ -9,10 +9,10 @@ GestureDetector::GestureDetector() : active_(0) {
|
||||
|
||||
}
|
||||
|
||||
void GestureDetector::Update(const TouchInput &touch) {
|
||||
TouchInput GestureDetector::Update(const TouchInput &touch, const Bounds &bounds) {
|
||||
// Mouse / 1-finger-touch control.
|
||||
Pointer &p = pointers[touch.id];
|
||||
if (touch.flags & TOUCH_DOWN) {
|
||||
if ((touch.flags & TOUCH_DOWN) && bounds.Contains(touch.x, touch.y)) {
|
||||
p.down = true;
|
||||
p.downTime = time_now_d();
|
||||
p.downX = touch.x;
|
||||
@ -33,13 +33,18 @@ void GestureDetector::Update(const TouchInput &touch) {
|
||||
if (touch.id == 0 && p.distanceY > p.distanceX) {
|
||||
if (p.down) {
|
||||
double timeDown = time_now_d() - p.downTime;
|
||||
if (p.distanceY * timeDown > 3) {
|
||||
if (!active_ && p.distanceY * timeDown > 3) {
|
||||
active_ |= GESTURE_DRAG_VERTICAL;
|
||||
// Kill the drag
|
||||
TouchInput inp2 = touch;
|
||||
inp2.flags = TOUCH_UP;
|
||||
return inp2;
|
||||
}
|
||||
} else {
|
||||
active_ = 0;
|
||||
}
|
||||
}
|
||||
return touch;
|
||||
}
|
||||
|
||||
bool GestureDetector::IsGestureActive(Gesture gesture) const {
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "input/input_state.h"
|
||||
#include "math/geom2d.h"
|
||||
|
||||
// WIP - doesn't do much yet
|
||||
// Mainly for detecting (multi-)touch gestures but also useable for left button mouse dragging etc.
|
||||
@ -13,15 +14,16 @@ enum Gesture {
|
||||
|
||||
// May track multiple gestures at the same time. You simply call GetGestureInfo
|
||||
// with the gesture you are interested in.
|
||||
class GestureDetector
|
||||
{
|
||||
class GestureDetector {
|
||||
public:
|
||||
GestureDetector();
|
||||
void Update(const TouchInput &touch);
|
||||
TouchInput Update(const TouchInput &touch, const Bounds &bounds);
|
||||
bool IsGestureActive(Gesture gesture) const;
|
||||
void GetGestureInfo(Gesture gesture, float info[4]);
|
||||
|
||||
private:
|
||||
Bounds bounds_;
|
||||
|
||||
// jazzhands!
|
||||
enum Locals {
|
||||
MAX_PTRS = 10
|
||||
@ -41,7 +43,6 @@ private:
|
||||
};
|
||||
|
||||
Pointer pointers[MAX_PTRS];
|
||||
// ...
|
||||
|
||||
uint32_t active_;
|
||||
};
|
||||
|
42
math/geom2d.h
Normal file
42
math/geom2d.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
struct Point {
|
||||
Point() {}
|
||||
Point(float x_, float y_) : x(x_), y(y_) {}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
|
||||
float distanceTo(const Point &other) const {
|
||||
float dx = other.x - x, dy = other.y - y;
|
||||
return sqrtf(dx*dx + dy*dy);
|
||||
}
|
||||
|
||||
/*
|
||||
FocusDirection directionTo(const Point &other) const {
|
||||
int angle = atan2f(other.y - y, other.x - x) / (2 * M_PI) - 0.125;
|
||||
|
||||
}*/
|
||||
};
|
||||
|
||||
|
||||
// Resolved bounds on screen after layout.
|
||||
struct Bounds {
|
||||
bool Contains(float px, float py) const {
|
||||
return (px >= x && py >= y && px < x + w && py < y + h);
|
||||
}
|
||||
float x2() const { return x + w; }
|
||||
float y2() const { return y + h; }
|
||||
float centerX() const { return x + w * 0.5f; }
|
||||
float centerY() const { return y + h * 0.5f; }
|
||||
Point Center() const {
|
||||
return Point(centerX(), centerY());
|
||||
}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float w;
|
||||
float h;
|
||||
};
|
||||
|
||||
|
@ -218,6 +218,7 @@
|
||||
<ClInclude Include="json\json_writer.h" />
|
||||
<ClInclude Include="math\compression.h" />
|
||||
<ClInclude Include="math\curves.h" />
|
||||
<ClInclude Include="math\geom2d.h" />
|
||||
<ClInclude Include="math\lin\aabb.h" />
|
||||
<ClInclude Include="math\lin\matrix4x4.h" />
|
||||
<ClInclude Include="math\lin\plane.h" />
|
||||
@ -232,6 +233,7 @@
|
||||
<ClInclude Include="thread\thread.h" />
|
||||
<ClInclude Include="thread\threadpool.h" />
|
||||
<ClInclude Include="thread\threadutil.h" />
|
||||
<ClInclude Include="ui\drawing.h" />
|
||||
<ClInclude Include="ui\screen.h" />
|
||||
<ClInclude Include="ui\ui.h" />
|
||||
<ClInclude Include="ui\ui_context.h" />
|
||||
@ -348,6 +350,7 @@
|
||||
<ClCompile Include="thread\prioritizedworkqueue.cpp" />
|
||||
<ClCompile Include="thread\threadpool.cpp" />
|
||||
<ClCompile Include="thread\threadutil.cpp" />
|
||||
<ClCompile Include="ui\drawing.cpp" />
|
||||
<ClCompile Include="ui\screen.cpp" />
|
||||
<ClCompile Include="ui\ui.cpp" />
|
||||
<ClCompile Include="ui\ui_context.cpp" />
|
||||
|
@ -260,6 +260,10 @@
|
||||
<ClInclude Include="ui\viewgroup.h">
|
||||
<Filter>ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="math\geom2d.h">
|
||||
<Filter>math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ui\drawing.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="gfx\gl_debug_log.cpp">
|
||||
@ -462,6 +466,7 @@
|
||||
<ClCompile Include="ui\viewgroup.cpp">
|
||||
<Filter>ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ui\drawing.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="gfx">
|
||||
|
3
ui/drawing.cpp
Normal file
3
ui/drawing.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
namespace UI {
|
||||
|
||||
}
|
0
ui/drawing.h
Normal file
0
ui/drawing.h
Normal file
39
ui/view.cpp
39
ui/view.cpp
@ -94,24 +94,37 @@ void Clickable::Click() {
|
||||
};
|
||||
|
||||
void Clickable::Touch(const TouchInput &input) {
|
||||
if (input.flags & (TOUCH_DOWN | TOUCH_MOVE)) {
|
||||
if (input.flags & TOUCH_DOWN) {
|
||||
if (bounds_.Contains(input.x, input.y)) {
|
||||
if (IsFocusMovementEnabled())
|
||||
SetFocusedView(this);
|
||||
down_ = true;
|
||||
downCountDown_ = 8;
|
||||
} else {
|
||||
down_ = false;
|
||||
dragging_ = false;
|
||||
}
|
||||
} else if (input.flags & TOUCH_MOVE) {
|
||||
if (dragging_)
|
||||
down_ = bounds_.Contains(input.x, input.y);
|
||||
}
|
||||
if (input.flags & TOUCH_UP) {
|
||||
if (bounds_.Contains(input.x, input.y)) {
|
||||
if (dragging_ && bounds_.Contains(input.x, input.y)) {
|
||||
Click();
|
||||
}
|
||||
downCountDown_ = 0;
|
||||
down_ = false;
|
||||
dragging_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Clickable::Update(const InputState &input_state) {
|
||||
if (downCountDown_ == 1) {
|
||||
downCountDown_ = 0;
|
||||
dragging_ = true;
|
||||
down_ = true;
|
||||
} else if (downCountDown_ > 0) {
|
||||
downCountDown_--;
|
||||
}
|
||||
if (!HasFocus())
|
||||
return;
|
||||
if (input_state.pad_buttons_down & PAD_BUTTON_A) {
|
||||
@ -125,10 +138,19 @@ void Clickable::Update(const InputState &input_state) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClickableItem::Draw(DrawContext &dc) {
|
||||
if (down_) {
|
||||
dc.draw->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), dc.theme->itemDownStyle.bgColor);
|
||||
} else if (HasFocus()) {
|
||||
dc.draw->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), dc.theme->itemFocusedStyle.bgColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Choice::Draw(DrawContext &dc) {
|
||||
ClickableItem::Draw(dc);
|
||||
int paddingX = 4;
|
||||
int paddingY = 4;
|
||||
dc.draw->DrawText(dc.theme->uiFont, text_.c_str(), paddingX, paddingY, 0xFFFFFFFF, ALIGN_TOPLEFT);
|
||||
dc.draw->DrawText(dc.theme->uiFont, text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
// dc.draw->DrawText(dc.theme->uiFontSmaller, text_.c_str(), paddingX, paddingY, 0xFFFFFFFF, ALIGN_TOPLEFT);
|
||||
}
|
||||
|
||||
@ -137,16 +159,21 @@ void InfoItem::Draw(DrawContext &dc) {
|
||||
int paddingY = 4;
|
||||
dc.draw->DrawText(dc.theme->uiFont, text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
dc.draw->DrawText(dc.theme->uiFont, text_.c_str(), bounds_.x2() - paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER | ALIGN_RIGHT);
|
||||
dc.draw->hLine(bounds_.x, bounds_.y, bounds_.x2(), 0xFFFFFFFF);
|
||||
dc.draw->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y + 2, dc.theme->itemDownStyle.bgColor);
|
||||
}
|
||||
|
||||
void ItemHeader::Draw(DrawContext &dc) {
|
||||
dc.draw->DrawText(dc.theme->uiFontSmaller, text_.c_str(), bounds_.x + 4, bounds_.y, 0xFF707070, ALIGN_LEFT);
|
||||
dc.draw->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.theme->itemDownStyle.bgColor);
|
||||
}
|
||||
|
||||
void CheckBox::Draw(DrawContext &dc) {
|
||||
ClickableItem::Draw(dc);
|
||||
int paddingX = 80;
|
||||
int paddingY = 4;
|
||||
dc.draw->DrawImage(dc.theme->checkOn, bounds_.x + 30, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
dc.draw->DrawText(dc.theme->uiFont, text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
// dc.draw->DrawText(dc.theme->uiFontSmaller, text_.c_str(), paddingX, paddingY, 0xFFFFFFFF, ALIGN_TOPLEFT);
|
||||
dc.draw->hLine(bounds_.x, bounds_.y, bounds_.x2(), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void Button::GetContentDimensions(const DrawContext &dc, float &w, float &h) const {
|
||||
|
49
ui/view.h
49
ui/view.h
@ -9,11 +9,14 @@
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cmath>
|
||||
|
||||
#include "base/mutex.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "math/lin/matrix4x4.h"
|
||||
#include "math/math_util.h"
|
||||
#include "math/geom2d.h"
|
||||
|
||||
struct TouchInput;
|
||||
struct InputState;
|
||||
@ -62,10 +65,14 @@ struct Theme {
|
||||
int buttonSelected;
|
||||
int checkOn;
|
||||
int checkOff;
|
||||
int whiteImage;
|
||||
|
||||
Style buttonStyle;
|
||||
Style buttonFocusedStyle;
|
||||
Style buttonDownStyle;
|
||||
|
||||
Style itemDownStyle;
|
||||
Style itemFocusedStyle;
|
||||
};
|
||||
|
||||
// The four cardinal directions should be enough, plus Prev/Next in "element order".
|
||||
@ -124,23 +131,6 @@ enum EventReturn {
|
||||
|
||||
class ViewGroup;
|
||||
|
||||
// Resolved bounds on screen after layout.
|
||||
struct Bounds {
|
||||
bool Contains(float px, float py) const {
|
||||
return (px >= x && py >= y && px < x + w && py < y + h);
|
||||
}
|
||||
|
||||
float x2() const { return x + w; }
|
||||
float y2() const { return y + h; }
|
||||
float centerX() const { return x + w * 0.5f; }
|
||||
float centerY() const { return y + h * 0.5f; }
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float w;
|
||||
float h;
|
||||
};
|
||||
|
||||
void Fill(DrawContext &dc, const Bounds &bounds, const Drawable &drawable);
|
||||
|
||||
struct MeasureSpec {
|
||||
@ -200,6 +190,7 @@ private:
|
||||
struct Margins {
|
||||
Margins() : top(0), bottom(0), left(0), right(0) {}
|
||||
explicit Margins(uint8_t all) : top(all), bottom(all), left(all), right(all) {}
|
||||
explicit Margins(uint8_t horiz, uint8_t vert) : top(vert), bottom(vert), left(horiz), right(horiz) {}
|
||||
uint8_t top;
|
||||
uint8_t bottom;
|
||||
uint8_t left;
|
||||
@ -217,7 +208,6 @@ public:
|
||||
|
||||
Size width;
|
||||
Size height;
|
||||
private:
|
||||
};
|
||||
|
||||
class LinearLayoutParams : public LayoutParams {
|
||||
@ -327,7 +317,7 @@ public:
|
||||
class Clickable : public View {
|
||||
public:
|
||||
Clickable(LayoutParams *layoutParams)
|
||||
: View(layoutParams), down_(false) {}
|
||||
: View(layoutParams), downCountDown_(0), down_(false), dragging_(false) {}
|
||||
|
||||
virtual void Touch(const TouchInput &input);
|
||||
virtual void Update(const InputState &input_state);
|
||||
@ -340,6 +330,8 @@ protected:
|
||||
// Use it for checking/unchecking checkboxes, etc.
|
||||
virtual void Click();
|
||||
|
||||
int downCountDown_;
|
||||
bool dragging_;
|
||||
bool down_;
|
||||
};
|
||||
|
||||
@ -354,7 +346,6 @@ public:
|
||||
private:
|
||||
Style style_;
|
||||
std::string text_;
|
||||
DISALLOW_COPY_AND_ASSIGN(Button);
|
||||
};
|
||||
|
||||
class Item : public InertView {
|
||||
@ -381,10 +372,12 @@ public:
|
||||
w = 0.0f;
|
||||
h = 0.0f;
|
||||
}
|
||||
|
||||
// Draws the item background.
|
||||
virtual void Draw(DrawContext &dc);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// The following classes are mostly suitable as items in ListView which
|
||||
// really is just a LinearLayout in a ScrollView, possibly with some special optimizations.
|
||||
|
||||
@ -413,6 +406,18 @@ private:
|
||||
std::string rightText_;
|
||||
};
|
||||
|
||||
class ItemHeader : public Item {
|
||||
public:
|
||||
ItemHeader(const std::string &text, LayoutParams *layoutParams = 0)
|
||||
: Item(layoutParams), text_(text) {
|
||||
layoutParams_->width = FILL_PARENT;
|
||||
layoutParams_->height = 26;
|
||||
}
|
||||
virtual void Draw(DrawContext &dc);
|
||||
private:
|
||||
std::string text_;
|
||||
};
|
||||
|
||||
class CheckBox : public ClickableItem {
|
||||
public:
|
||||
CheckBox(bool *toggle, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = 0)
|
||||
|
@ -259,29 +259,44 @@ void FrameLayout::Layout() {
|
||||
}
|
||||
|
||||
void ScrollView::Measure(const DrawContext &dc, MeasureSpec horiz, MeasureSpec vert) {
|
||||
// Respect margins
|
||||
Margins margins;
|
||||
const LinearLayoutParams *params = dynamic_cast<const LinearLayoutParams*>(views_[0]->GetLayoutParams());
|
||||
if (params) {
|
||||
margins = params->margins;
|
||||
}
|
||||
|
||||
// The scroll view itself simply obeys its parent.
|
||||
MeasureBySpec(layoutParams_->width, 0.0f, horiz, &measuredWidth_);
|
||||
MeasureBySpec(layoutParams_->height, 0.0f, vert, &measuredHeight_);
|
||||
|
||||
if (orientation_ == ORIENT_HORIZONTAL) {
|
||||
views_[0]->Measure(dc, MeasureSpec(UNSPECIFIED), vert);
|
||||
views_[0]->Measure(dc, MeasureSpec(UNSPECIFIED), vert - (margins.top + margins.bottom));
|
||||
} else {
|
||||
views_[0]->Measure(dc, horiz, MeasureSpec(UNSPECIFIED));
|
||||
views_[0]->Measure(dc, horiz - (margins.left + margins.right), MeasureSpec(UNSPECIFIED));
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollView::Layout() {
|
||||
Bounds scrolled;
|
||||
scrolled.w = views_[0]->GetMeasuredWidth();
|
||||
scrolled.h = views_[0]->GetMeasuredHeight();
|
||||
|
||||
// Respect margins
|
||||
Margins margins;
|
||||
const LinearLayoutParams *params = dynamic_cast<const LinearLayoutParams*>(views_[0]->GetLayoutParams());
|
||||
if (params) {
|
||||
margins = params->margins;
|
||||
}
|
||||
|
||||
scrolled.w = views_[0]->GetMeasuredWidth() - (margins.left + margins.right);
|
||||
scrolled.h = views_[0]->GetMeasuredHeight() - (margins.top + margins.bottom);
|
||||
|
||||
switch (orientation_) {
|
||||
case ORIENT_HORIZONTAL:
|
||||
scrolled.x = bounds_.x - scrollPos_;
|
||||
scrolled.y = bounds_.y;
|
||||
scrolled.y = bounds_.y + margins.top;
|
||||
break;
|
||||
case ORIENT_VERTICAL:
|
||||
scrolled.x = bounds_.x;
|
||||
scrolled.x = bounds_.x + margins.left;
|
||||
scrolled.y = bounds_.y - scrollPos_;
|
||||
break;
|
||||
}
|
||||
@ -293,17 +308,18 @@ void ScrollView::Touch(const TouchInput &input) {
|
||||
if ((input.flags & TOUCH_DOWN) && input.id == 0) {
|
||||
scrollStart_ = scrollPos_;
|
||||
}
|
||||
|
||||
gesture_.Update(input);
|
||||
|
||||
TouchInput input2 = gesture_.Update(input, bounds_);
|
||||
|
||||
if (gesture_.IsGestureActive(GESTURE_DRAG_VERTICAL)) {
|
||||
float info[4];
|
||||
gesture_.GetGestureInfo(GESTURE_DRAG_VERTICAL, info);
|
||||
scrollPos_ = scrollStart_ - info[0];
|
||||
} else {
|
||||
ViewGroup::Touch(input);
|
||||
}
|
||||
|
||||
|
||||
if (!(input.flags & TOUCH_DOWN) || bounds_.Contains(input.x, input.y))
|
||||
ViewGroup::Touch(input2);
|
||||
|
||||
// Clamp scrollPos_. TODO: flinging, bouncing, etc.
|
||||
if (scrollPos_ < 0.0f) {
|
||||
scrollPos_ = 0.0f;
|
||||
|
Loading…
x
Reference in New Issue
Block a user