mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 07:20:49 +00:00
A lot of NewUI work: layout and focus fixes, "TabHolder"
This commit is contained in:
parent
8e5890a7e2
commit
166acebeff
@ -37,7 +37,7 @@ TouchInput GestureDetector::Update(const TouchInput &touch, const Bounds &bounds
|
||||
active_ |= GESTURE_DRAG_VERTICAL;
|
||||
// Kill the drag
|
||||
TouchInput inp2 = touch;
|
||||
inp2.flags = TOUCH_UP;
|
||||
inp2.flags = TOUCH_UP | TOUCH_CANCEL;
|
||||
return inp2;
|
||||
}
|
||||
} else {
|
||||
|
@ -98,6 +98,7 @@ enum {
|
||||
TOUCH_MOVE = 1,
|
||||
TOUCH_DOWN = 2,
|
||||
TOUCH_UP = 4,
|
||||
TOUCH_CANCEL = 8, // Sent by scrollviews to their children when they detect a scroll
|
||||
};
|
||||
|
||||
// Used for asynchronous touch input.
|
||||
|
@ -24,6 +24,9 @@ struct Point {
|
||||
|
||||
// Resolved bounds on screen after layout.
|
||||
struct Bounds {
|
||||
Bounds() {}
|
||||
Bounds(float x_, float y_, float w_, float h_) : x(x_), y(y_), w(w_), h(h_) {}
|
||||
|
||||
bool Contains(float px, float py) const {
|
||||
return (px >= x && py >= y && px < x + w && py < y + h);
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
#include "ui.h"
|
||||
#include "ui_context.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/view.h"
|
||||
#include "ui/ui_context.h"
|
||||
#include "gfx/texture.h"
|
||||
#include "gfx_es2/draw_buffer.h"
|
||||
#include "gfx_es2/glsl_program.h"
|
||||
#include "gfx_es2/gl_state.h"
|
||||
|
||||
void UIContext::Begin()
|
||||
{
|
||||
void UIContext::Begin() {
|
||||
glstate.blend.enable();
|
||||
glstate.blendFunc.set(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glstate.cullFace.disable();
|
||||
@ -24,8 +24,7 @@ void UIContext::Begin()
|
||||
uidrawbufferTop_->Begin();*/
|
||||
}
|
||||
|
||||
void UIContext::BeginNoTex()
|
||||
{
|
||||
void UIContext::BeginNoTex() {
|
||||
glstate.blend.enable();
|
||||
glstate.blendFunc.set(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glstate.cullFace.disable();
|
||||
@ -44,28 +43,23 @@ void UIContext::BeginNoTex()
|
||||
}
|
||||
|
||||
|
||||
void UIContext::RebindTexture() const
|
||||
{
|
||||
void UIContext::RebindTexture() const {
|
||||
if (uitexture_)
|
||||
uitexture_->Bind(0);
|
||||
}
|
||||
|
||||
void UIContext::Flush()
|
||||
{
|
||||
if (uidrawbuffer_)
|
||||
{
|
||||
void UIContext::Flush() {
|
||||
if (uidrawbuffer_) {
|
||||
uidrawbuffer_->End();
|
||||
uidrawbuffer_->Flush();
|
||||
}
|
||||
if (uidrawbufferTop_)
|
||||
{
|
||||
if (uidrawbufferTop_) {
|
||||
uidrawbufferTop_->End();
|
||||
uidrawbufferTop_->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
void UIContext::End()
|
||||
{
|
||||
void UIContext::End() {
|
||||
UIEnd();
|
||||
Flush();
|
||||
}
|
||||
@ -97,4 +91,18 @@ void UIContext::ActivateTopScissor() {
|
||||
} else {
|
||||
glstate.scissorTest.disable();
|
||||
}
|
||||
}
|
||||
|
||||
void UIContext::FillRect(const UI::Drawable &drawable, const Bounds &bounds) {
|
||||
switch (drawable.type) {
|
||||
case UI::DRAW_SOLID_COLOR:
|
||||
uidrawbuffer_->DrawImageStretch(theme->whiteImage, bounds.x, bounds.y, bounds.x2(), bounds.y2(), drawable.color);
|
||||
break;
|
||||
case UI::DRAW_4GRID:
|
||||
uidrawbuffer_->DrawImage4Grid(drawable.image, bounds.x, bounds.y, bounds.x2(), bounds.y2(), drawable.color);
|
||||
break;
|
||||
case UI::DRAW_STRETCH_IMAGE:
|
||||
uidrawbuffer_->DrawImageStretch(drawable.image, bounds.x, bounds.y, bounds.x2(), bounds.y2(), drawable.color);
|
||||
break;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ class DrawBuffer;
|
||||
|
||||
// Kind of ugly connection to UI.
|
||||
namespace UI {
|
||||
struct Drawable;
|
||||
struct Theme;
|
||||
}
|
||||
|
||||
@ -49,6 +50,12 @@ public:
|
||||
|
||||
const UI::Theme *theme;
|
||||
|
||||
|
||||
// Utility methods
|
||||
void FillRect(const UI::Drawable &drawable, const Bounds &bounds);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
// TODO: Collect these into a UIContext
|
||||
const GLSLProgram *uishader_;
|
||||
|
@ -3,12 +3,17 @@
|
||||
#include "ui/ui_context.h"
|
||||
#include "ui/screen.h"
|
||||
|
||||
UIScreen::UIScreen()
|
||||
: Screen(), root_(0), recreateViews_(false) {
|
||||
|
||||
}
|
||||
|
||||
void UIScreen::update(InputState &input) {
|
||||
if (!root_) {
|
||||
CreateViews();
|
||||
}
|
||||
|
||||
if (orientationChanged_) {
|
||||
if (recreateViews_) {
|
||||
delete root_;
|
||||
root_ = 0;
|
||||
CreateViews();
|
||||
@ -18,17 +23,25 @@ void UIScreen::update(InputState &input) {
|
||||
}
|
||||
|
||||
void UIScreen::render() {
|
||||
UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_);
|
||||
if (root_) {
|
||||
UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_);
|
||||
|
||||
screenManager()->getUIContext()->Begin();
|
||||
DrawBackground();
|
||||
root_->Draw(*screenManager()->getUIContext());
|
||||
screenManager()->getUIContext()->End();
|
||||
screenManager()->getUIContext()->Flush();
|
||||
screenManager()->getUIContext()->Begin();
|
||||
DrawBackground();
|
||||
root_->Draw(*screenManager()->getUIContext());
|
||||
screenManager()->getUIContext()->End();
|
||||
screenManager()->getUIContext()->Flush();
|
||||
} else {
|
||||
ELOG("Tried to render without a view root");
|
||||
}
|
||||
}
|
||||
|
||||
void UIScreen::touch(const TouchInput &touch) {
|
||||
root_->Touch(touch);
|
||||
if (root_) {
|
||||
root_->Touch(touch);
|
||||
} else {
|
||||
ELOG("Tried to touch without a view root");
|
||||
}
|
||||
}
|
||||
|
||||
UI::EventReturn UIScreen::OnBack(UI::EventParams &e) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
class UIScreen : public Screen {
|
||||
public:
|
||||
UIScreen() : Screen(), root_(0), orientationChanged_(false) {}
|
||||
UIScreen();
|
||||
~UIScreen() { delete root_; }
|
||||
|
||||
virtual void update(InputState &input);
|
||||
@ -19,6 +19,10 @@ protected:
|
||||
virtual void CreateViews() = 0;
|
||||
virtual void DrawBackground() {}
|
||||
|
||||
void RecreateViews() { recreateViews_ = true; }
|
||||
|
||||
UI::ViewGroup *root_;
|
||||
bool orientationChanged_;
|
||||
|
||||
private:
|
||||
bool recreateViews_;
|
||||
};
|
||||
|
42
ui/view.cpp
42
ui/view.cpp
@ -2,6 +2,7 @@
|
||||
#include "base/mutex.h"
|
||||
#include "input/input_state.h"
|
||||
#include "gfx_es2/draw_buffer.h"
|
||||
#include "gfx/texture.h"
|
||||
#include "gfx/texture_atlas.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/view.h"
|
||||
@ -117,7 +118,7 @@ void Clickable::Touch(const TouchInput &input) {
|
||||
down_ = bounds_.Contains(input.x, input.y);
|
||||
}
|
||||
if (input.flags & TOUCH_UP) {
|
||||
if (dragging_ && bounds_.Contains(input.x, input.y)) {
|
||||
if ((input.flags & TOUCH_CANCEL) == 0 && dragging_ && bounds_.Contains(input.x, input.y)) {
|
||||
Click();
|
||||
}
|
||||
downCountDown_ = 0;
|
||||
@ -159,15 +160,18 @@ ClickableItem::ClickableItem(LayoutParams *layoutParams) : Clickable(layoutParam
|
||||
}
|
||||
|
||||
void ClickableItem::Draw(UIContext &dc) {
|
||||
Style style = dc.theme->itemStyle;
|
||||
if (down_) {
|
||||
dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), dc.theme->itemDownStyle.bgColor);
|
||||
style = dc.theme->itemDownStyle;
|
||||
} else if (HasFocus()) {
|
||||
dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), dc.theme->itemFocusedStyle.bgColor);
|
||||
style = dc.theme->itemFocusedStyle;
|
||||
}
|
||||
dc.FillRect(style.background, bounds_);
|
||||
}
|
||||
|
||||
void Choice::Draw(UIContext &dc) {
|
||||
ClickableItem::Draw(dc);
|
||||
|
||||
int paddingX = 4;
|
||||
int paddingY = 4;
|
||||
dc.Draw()->DrawText(dc.theme->uiFont, text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
@ -175,16 +179,17 @@ void Choice::Draw(UIContext &dc) {
|
||||
}
|
||||
|
||||
void InfoItem::Draw(UIContext &dc) {
|
||||
Item::Draw(dc);
|
||||
int paddingX = 4;
|
||||
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()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y + 2, dc.theme->itemDownStyle.bgColor);
|
||||
// dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y + 2, dc.theme->itemDownStyle.bgColor);
|
||||
}
|
||||
|
||||
void ItemHeader::Draw(UIContext &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);
|
||||
dc.Draw()->DrawImageStretch(dc.theme->whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void CheckBox::Draw(UIContext &dc) {
|
||||
@ -195,7 +200,7 @@ void CheckBox::Draw(UIContext &dc) {
|
||||
int image = *toggle_ ? dc.theme->checkOn : dc.theme->checkOff;
|
||||
|
||||
dc.Draw()->DrawText(dc.theme->uiFont, text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), 0xFFFFFFFF, ALIGN_VCENTER);
|
||||
dc.Draw()->DrawImage(image, bounds_.x2() - 4, bounds_.centerY(), 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
dc.Draw()->DrawImage(image, bounds_.x2() - 4, bounds_.centerY(), 1.0f, 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
}
|
||||
|
||||
void Button::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
@ -208,7 +213,8 @@ void Button::Draw(UIContext &dc) {
|
||||
if (down_) style = dc.theme->buttonDownStyle;
|
||||
if (!enabled_) style = dc.theme->buttonDisabledStyle;
|
||||
|
||||
dc.Draw()->DrawImage4Grid(style.image, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), style.bgColor);
|
||||
// dc.Draw()->DrawImage4Grid(style.image, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), style.bgColor);
|
||||
dc.FillRect(style.background, bounds_);
|
||||
dc.Draw()->DrawText(dc.theme->uiFont, text_.c_str(), bounds_.centerX(), bounds_.centerY(), style.fgColor, ALIGN_CENTER);
|
||||
}
|
||||
|
||||
@ -224,6 +230,28 @@ void ImageView::Draw(UIContext &dc) {
|
||||
dc.Draw()->DrawImage(atlasImage_, bounds_.x, bounds_.y, bounds_.w, bounds_.h, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void TextureView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
// TODO: involve sizemode
|
||||
if (texture_) {
|
||||
w = (float)texture_->Width();
|
||||
h = (float)texture_->Height();
|
||||
} else {
|
||||
w = 16;
|
||||
h = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureView::Draw(UIContext &dc) {
|
||||
// TODO: involve sizemode
|
||||
if (texture_) {
|
||||
dc.Flush();
|
||||
texture_->Bind(0);
|
||||
dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_);
|
||||
dc.Flush();
|
||||
dc.RebindTexture();
|
||||
}
|
||||
}
|
||||
|
||||
void TextView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
dc.Draw()->SetFontScale(textScale_, textScale_);
|
||||
dc.Draw()->MeasureText(dc.theme->uiFont, text_.c_str(), &w, &h);
|
||||
|
45
ui/view.h
45
ui/view.h
@ -24,6 +24,7 @@ struct TouchInput;
|
||||
struct InputState;
|
||||
|
||||
class DrawBuffer;
|
||||
class Texture;
|
||||
class UIContext;
|
||||
|
||||
// I don't generally like namespaces but I think we do need one for UI, so many potentially-clashing names.
|
||||
@ -42,6 +43,7 @@ enum DrawableType {
|
||||
DRAW_NOTHING,
|
||||
DRAW_SOLID_COLOR,
|
||||
DRAW_4GRID,
|
||||
DRAW_STRETCH_IMAGE,
|
||||
};
|
||||
|
||||
enum Visibility {
|
||||
@ -51,17 +53,20 @@ enum Visibility {
|
||||
};
|
||||
|
||||
struct Drawable {
|
||||
Drawable() : type(DRAW_NOTHING) {}
|
||||
Drawable() : type(DRAW_NOTHING), image(-1), color(0xFFFFFFFF) {}
|
||||
explicit Drawable(uint32_t col) : type(DRAW_SOLID_COLOR), image(-1), color(col) {}
|
||||
Drawable(DrawableType t, int img, uint32_t col = 0xFFFFFFFF) : type(t), image(img), color(col) {}
|
||||
|
||||
DrawableType type;
|
||||
uint32_t data;
|
||||
uint32_t image;
|
||||
uint32_t color;
|
||||
};
|
||||
|
||||
struct Style {
|
||||
Style() : fgColor(0xFFFFFFFF), bgColor(0xFF303030), image(-1) {}
|
||||
Style() : fgColor(0xFFFFFFFF), background(0xFF303030), image(-1) {}
|
||||
|
||||
uint32_t fgColor;
|
||||
uint32_t bgColor;
|
||||
Drawable background;
|
||||
int image; // where applicable.
|
||||
};
|
||||
|
||||
@ -79,6 +84,7 @@ struct Theme {
|
||||
Style buttonDownStyle;
|
||||
Style buttonDisabledStyle;
|
||||
|
||||
Style itemStyle;
|
||||
Style itemDownStyle;
|
||||
Style itemFocusedStyle;
|
||||
};
|
||||
@ -195,7 +201,9 @@ 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) {}
|
||||
Margins(uint8_t horiz, uint8_t vert) : top(vert), bottom(vert), left(horiz), right(horiz) {}
|
||||
Margins(uint8_t l, uint8_t t, uint8_t r, uint8_t b) : top(t), bottom(b), left(l), right(r) {}
|
||||
|
||||
uint8_t top;
|
||||
uint8_t bottom;
|
||||
uint8_t left;
|
||||
@ -250,6 +258,7 @@ public:
|
||||
// Called when the layout is done.
|
||||
void SetBounds(Bounds bounds) { bounds_ = bounds; }
|
||||
virtual const LayoutParams *GetLayoutParams() const { return layoutParams_.get(); }
|
||||
virtual void ReplaceLayoutParams(LayoutParams *newLayoutParams) { layoutParams_.reset(newLayoutParams); }
|
||||
const Bounds &GetBounds() const { return bounds_; }
|
||||
|
||||
virtual bool SetFocus() {
|
||||
@ -272,10 +281,14 @@ public:
|
||||
void SetVisibility(Visibility visibility) { visibility_ = visibility; }
|
||||
Visibility GetVisibility() const { return visibility_; }
|
||||
|
||||
const std::string &Tag() const { return tag_; }
|
||||
void SetTag(const std::string &str) { tag_ = str; }
|
||||
|
||||
protected:
|
||||
// Inputs to layout
|
||||
scoped_ptr<LayoutParams> layoutParams_;
|
||||
|
||||
|
||||
std::string tag_;
|
||||
bool enabled_;
|
||||
Visibility visibility_;
|
||||
|
||||
@ -425,7 +438,7 @@ private:
|
||||
class CheckBox : public ClickableItem {
|
||||
public:
|
||||
CheckBox(bool *toggle, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = 0)
|
||||
: ClickableItem(layoutParams), text_(text), smallText_(smallText) {
|
||||
: ClickableItem(layoutParams), toggle_(toggle), text_(text), smallText_(smallText) {
|
||||
OnClick.Handle(this, &CheckBox::OnClicked);
|
||||
}
|
||||
|
||||
@ -488,6 +501,24 @@ private:
|
||||
ImageSizeMode sizeMode_;
|
||||
};
|
||||
|
||||
class TextureView : public InertView {
|
||||
public:
|
||||
TextureView(Texture *texture, ImageSizeMode sizeMode, LayoutParams *layoutParams = 0)
|
||||
: InertView(layoutParams), texture_(texture), sizeMode_(sizeMode) {}
|
||||
|
||||
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
|
||||
virtual void Draw(UIContext &dc);
|
||||
|
||||
void SetTexture(Texture *texture) { texture_ = texture; }
|
||||
void SetColor(uint32_t color) { color_ = color; }
|
||||
|
||||
private:
|
||||
Texture *texture_;
|
||||
uint32_t color_;
|
||||
ImageSizeMode sizeMode_;
|
||||
};
|
||||
|
||||
|
||||
class ProgressBar : public InertView {
|
||||
public:
|
||||
ProgressBar(LayoutParams *layoutParams = 0)
|
||||
|
@ -3,9 +3,12 @@
|
||||
#include "ui/ui_context.h"
|
||||
#include "ui/view.h"
|
||||
#include "ui/viewgroup.h"
|
||||
#include "gfx_es2/draw_buffer.h"
|
||||
|
||||
namespace UI {
|
||||
|
||||
const float ITEM_HEIGHT = 64.f;
|
||||
|
||||
void ApplyGravity(const Bounds outer, const Margins &margins, float w, float h, int gravity, Bounds &inner) {
|
||||
inner.w = w - (margins.left + margins.right);
|
||||
inner.h = h - (margins.right + margins.left);
|
||||
@ -79,6 +82,8 @@ float GetDirectionScore(View *origin, View *destination, FocusDirection directio
|
||||
return 0.0f;
|
||||
if (destination->GetEnabled() == false)
|
||||
return 0.0f;
|
||||
if (destination->GetVisibility() != V_VISIBLE)
|
||||
return 0.0f;
|
||||
|
||||
float dx = destination->GetBounds().centerX() - origin->GetBounds().centerX();
|
||||
float dy = destination->GetBounds().centerY() - origin->GetBounds().centerY();
|
||||
@ -111,6 +116,11 @@ float GetDirectionScore(View *origin, View *destination, FocusDirection directio
|
||||
|
||||
|
||||
NeighborResult ViewGroup::FindNeighbor(View *view, FocusDirection direction, NeighborResult result) {
|
||||
if (!GetEnabled())
|
||||
return result;
|
||||
if (GetVisibility() != V_VISIBLE)
|
||||
return result;
|
||||
|
||||
// First, find the position of the view in the list.
|
||||
size_t num = -1;
|
||||
for (size_t i = 0; i < views_.size(); i++) {
|
||||
@ -162,7 +172,7 @@ NeighborResult ViewGroup::FindNeighbor(View *view, FocusDirection direction, Nei
|
||||
|
||||
// Boost neighbors with the same parent
|
||||
if (num != -1) {
|
||||
result.score += 100.0f;
|
||||
//result.score += 100.0f;
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -196,11 +206,11 @@ void MoveFocus(ViewGroup *root, FocusDirection direction) {
|
||||
}
|
||||
|
||||
void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) {
|
||||
if (views_.empty()) {
|
||||
MeasureBySpec(layoutParams_->width, 0.0f, horiz, &measuredWidth_);
|
||||
MeasureBySpec(layoutParams_->height, 0.0f, vert, &measuredHeight_);
|
||||
MeasureBySpec(layoutParams_->width, 0.0f, horiz, &measuredWidth_);
|
||||
MeasureBySpec(layoutParams_->height, 0.0f, vert, &measuredHeight_);
|
||||
|
||||
if (views_.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
float sum = 0.0f;
|
||||
float maxOther = 0.0f;
|
||||
@ -226,9 +236,13 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
}
|
||||
|
||||
if (orientation_ == ORIENT_HORIZONTAL) {
|
||||
views_[i]->Measure(dc, MeasureSpec(UNSPECIFIED), vert - (float)(margins.top + margins.bottom));
|
||||
MeasureSpec v = vert;
|
||||
if (v.type == UNSPECIFIED) v = MeasureSpec(AT_MOST, measuredHeight_);
|
||||
views_[i]->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), vert - (float)(margins.top + margins.bottom));
|
||||
} else if (orientation_ == ORIENT_VERTICAL) {
|
||||
views_[i]->Measure(dc, horiz - (float)(margins.left + margins.right), MeasureSpec(UNSPECIFIED));
|
||||
MeasureSpec h = horiz;
|
||||
if (h.type == UNSPECIFIED) h = MeasureSpec(AT_MOST, measuredWidth_);
|
||||
views_[i]->Measure(dc, h - (float)(margins.left + margins.right), MeasureSpec(UNSPECIFIED, measuredHeight_));
|
||||
}
|
||||
|
||||
float amount;
|
||||
@ -265,8 +279,8 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
const LayoutParams *layoutParams = views_[i]->GetLayoutParams();
|
||||
const LinearLayoutParams *linLayoutParams = dynamic_cast<const LinearLayoutParams *>(layoutParams);
|
||||
|
||||
if (linLayoutParams && linLayoutParams->weight > 0.0)
|
||||
views_[i]->Measure(dc, MeasureSpec(EXACTLY, unit * linLayoutParams->weight), vert);
|
||||
if (linLayoutParams && linLayoutParams->weight > 0.0f)
|
||||
views_[i]->Measure(dc, MeasureSpec(EXACTLY, unit * linLayoutParams->weight), MeasureSpec(EXACTLY, measuredHeight_));
|
||||
}
|
||||
} else {
|
||||
MeasureBySpec(layoutParams_->height, weightZeroSum, vert, &measuredHeight_);
|
||||
@ -279,8 +293,8 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
const LayoutParams *layoutParams = views_[i]->GetLayoutParams();
|
||||
const LinearLayoutParams *linLayoutParams = dynamic_cast<const LinearLayoutParams *>(layoutParams);
|
||||
|
||||
if (linLayoutParams && linLayoutParams->weight)
|
||||
views_[i]->Measure(dc, horiz, MeasureSpec(EXACTLY, unit * linLayoutParams->weight));
|
||||
if (linLayoutParams && linLayoutParams->weight > 0.0f)
|
||||
views_[i]->Measure(dc, MeasureSpec(EXACTLY, measuredWidth_), MeasureSpec(EXACTLY, unit * linLayoutParams->weight));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -367,9 +381,9 @@ void ScrollView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver
|
||||
MeasureBySpec(layoutParams_->height, 0.0f, vert, &measuredHeight_);
|
||||
|
||||
if (orientation_ == ORIENT_HORIZONTAL) {
|
||||
views_[0]->Measure(dc, MeasureSpec(UNSPECIFIED), vert - (margins.top + margins.bottom));
|
||||
views_[0]->Measure(dc, MeasureSpec(UNSPECIFIED), MeasureSpec(AT_MOST, measuredHeight_ - (margins.top + margins.bottom)));
|
||||
} else {
|
||||
views_[0]->Measure(dc, horiz - (margins.left + margins.right), MeasureSpec(UNSPECIFIED));
|
||||
views_[0]->Measure(dc, MeasureSpec(AT_MOST, measuredWidth_ - (margins.left + margins.right)), MeasureSpec(UNSPECIFIED));
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,7 +505,7 @@ void GridLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver
|
||||
|
||||
// Okay, got the width we are supposed to adjust to. Now we can calculate the number of columns.
|
||||
int numColumns = (measuredWidth_ - settings_.spacing) / (settings_.columnWidth + settings_.spacing);
|
||||
int numRows = (views_.size() + (numColumns - 1)) / numColumns;
|
||||
int numRows = (int)(views_.size() + (numColumns - 1)) / numColumns;
|
||||
|
||||
float estimatedHeight = settings_.rowHeight * numRows;
|
||||
|
||||
@ -500,7 +514,7 @@ void GridLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver
|
||||
|
||||
void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) {
|
||||
MeasureBySpec(layoutParams_->width, 0.0f, horiz, &measuredWidth_);
|
||||
MeasureBySpec(layoutParams_->height, 0.0f, horiz, &measuredHeight_);
|
||||
MeasureBySpec(layoutParams_->height, 0.0f, vert, &measuredHeight_);
|
||||
|
||||
for (size_t i = 0; i < views_.size(); i++) {
|
||||
Size width = WRAP_CONTENT;
|
||||
@ -582,6 +596,17 @@ void GridLayout::Layout() {
|
||||
}
|
||||
}
|
||||
|
||||
EventReturn TabHolder::OnTabClick(EventParams &e) {
|
||||
tabs_[currentTab_]->SetVisibility(V_GONE);
|
||||
for (int i = 0; i < tabChoices_.size(); i++) {
|
||||
if (e.v == tabChoices_[i]) {
|
||||
currentTab_ = i;
|
||||
}
|
||||
}
|
||||
tabs_[currentTab_]->SetVisibility(V_VISIBLE);
|
||||
return EVENT_DONE;
|
||||
}
|
||||
|
||||
void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root) {
|
||||
Bounds rootBounds;
|
||||
rootBounds.x = 0;
|
||||
@ -599,7 +624,6 @@ void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root) {
|
||||
root->Layout();
|
||||
}
|
||||
|
||||
|
||||
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))
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "ui/view.h"
|
||||
#include "math/geom2d.h"
|
||||
#include "input/gesture_detector.h"
|
||||
|
||||
namespace UI {
|
||||
@ -93,6 +94,8 @@ public:
|
||||
: LayoutParams(w, h), weight(wgt), gravity(grav), hasMargins_(false) {}
|
||||
LinearLayoutParams(Size w, Size h, float wgt, Gravity grav, const Margins &mgn)
|
||||
: LayoutParams(w, h), weight(wgt), gravity(grav), margins(mgn), hasMargins_(true) {}
|
||||
LinearLayoutParams(Size w, Size h, const Margins &mgn)
|
||||
: LayoutParams(w, h), weight(0.0f), gravity(G_TOPLEFT), margins(mgn), hasMargins_(true) {}
|
||||
LinearLayoutParams(const Margins &mgn)
|
||||
: LayoutParams(WRAP_CONTENT, WRAP_CONTENT), weight(0.0f), gravity(G_TOPLEFT), margins(mgn), hasMargins_(true) {}
|
||||
|
||||
@ -187,6 +190,48 @@ class ViewPager : public ScrollView {
|
||||
public:
|
||||
};
|
||||
|
||||
class TabHolder : public LinearLayout {
|
||||
public:
|
||||
TabHolder(Orientation orientation, float stripSize, LayoutParams *layoutParams = 0)
|
||||
: LinearLayout(ORIENT_HORIZONTAL, layoutParams),
|
||||
orientation_(orientation), stripSize_(stripSize), currentTab_(0) {
|
||||
tabStrip_ = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(stripSize, WRAP_CONTENT));
|
||||
Add(tabStrip_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *AddTab(const std::string &title, T *tabContents) {
|
||||
tabContents->ReplaceLayoutParams(new LinearLayoutParams(1.0f));
|
||||
tabTitles_.push_back(title);
|
||||
tabs_.push_back(tabContents);
|
||||
Choice *choice = new Choice(title);
|
||||
tabStrip_->Add(choice)->OnClick.Handle(this, &TabHolder::OnTabClick);
|
||||
tabChoices_.push_back(choice);
|
||||
Add(tabContents);
|
||||
if (tabs_.size() > 1)
|
||||
tabContents->SetVisibility(V_GONE);
|
||||
return tabContents;
|
||||
}
|
||||
|
||||
void SetCurrentTab(int tab) {
|
||||
tabs_[currentTab_]->SetVisibility(V_GONE);
|
||||
currentTab_ = tab;
|
||||
tabs_[currentTab_]->SetVisibility(V_VISIBLE);
|
||||
}
|
||||
|
||||
private:
|
||||
EventReturn OnTabClick(EventParams &e);
|
||||
|
||||
ViewGroup *tabStrip_;
|
||||
|
||||
Orientation orientation_;
|
||||
int currentTab_;
|
||||
float stripSize_;
|
||||
std::vector<std::string> tabTitles_;
|
||||
std::vector<Choice *> tabChoices_;
|
||||
std::vector<View *> tabs_;
|
||||
};
|
||||
|
||||
void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root);
|
||||
void UpdateViewHierarchy(const InputState &input_state, ViewGroup *root);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user