More new UI work

This commit is contained in:
Henrik Rydgard 2013-05-25 16:52:27 +02:00
parent 02a3cc1b5b
commit 7bad683cae
11 changed files with 154 additions and 46 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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
View 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;
};

View File

@ -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" />

View File

@ -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
View File

@ -0,0 +1,3 @@
namespace UI {
}

0
ui/drawing.h Normal file
View File

View File

@ -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 {

View File

@ -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)

View File

@ -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;