ppsspp/ui/view.h

536 lines
12 KiB
C
Raw Normal View History

2013-05-02 22:21:39 +00:00
#pragma once
// More traditional UI framework than ui/ui.h.
// Still very simple to use.
// Works very similarly to Android, there's a Measure pass and a Layout pass which you don't
// really need to care about if you just use the standard containers and widgets.
2013-05-31 22:50:08 +00:00
#include <string>
2013-05-02 22:21:39 +00:00
#include <vector>
2013-05-25 14:52:27 +00:00
#include <cmath>
#include <cstdio>
2013-05-02 22:21:39 +00:00
2013-06-01 16:59:03 +00:00
#include "base/functional.h"
2013-05-02 22:21:39 +00:00
#include "base/mutex.h"
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "math/lin/matrix4x4.h"
2013-05-25 14:52:27 +00:00
#include "math/math_util.h"
#include "math/geom2d.h"
2013-05-02 22:21:39 +00:00
struct TouchInput;
struct InputState;
2013-05-02 22:21:39 +00:00
class DrawBuffer;
2013-05-27 22:32:00 +00:00
class UIContext;
2013-05-02 22:21:39 +00:00
// I don't generally like namespaces but I think we do need one for UI, so many potentially-clashing names.
namespace UI {
class View;
// The ONLY global is the currently focused item.
// Can be and often is null.
void EnableFocusMovement(bool enable);
bool IsFocusMovementEnabled();
View *GetFocusedView();
void SetFocusedView(View *view);
2013-05-02 22:21:39 +00:00
enum DrawableType {
DRAW_NOTHING,
DRAW_SOLID_COLOR,
DRAW_4GRID,
};
2013-06-02 21:44:28 +00:00
enum Visibility {
V_VISIBLE,
V_INVISIBLE, // Keeps position, not drawn or interacted with
V_GONE, // Does not participate in layout
};
2013-05-02 22:21:39 +00:00
struct Drawable {
Drawable() : type(DRAW_NOTHING) {}
DrawableType type;
uint32_t data;
};
struct Style {
Style() : fgColor(0xFFFFFFFF), bgColor(0xFF303030), image(-1) {}
2013-05-02 22:21:39 +00:00
uint32_t fgColor;
uint32_t bgColor;
int image; // where applicable.
2013-05-02 22:21:39 +00:00
};
// To use with an UI atlas.
struct Theme {
int uiFont;
int uiFontSmall;
int uiFontSmaller;
int checkOn;
int checkOff;
2013-05-25 14:52:27 +00:00
int whiteImage;
2013-05-02 22:21:39 +00:00
Style buttonStyle;
Style buttonFocusedStyle;
Style buttonDownStyle;
2013-06-02 21:44:28 +00:00
Style buttonDisabledStyle;
2013-05-25 14:52:27 +00:00
Style itemDownStyle;
Style itemFocusedStyle;
};
// The four cardinal directions should be enough, plus Prev/Next in "element order".
enum FocusDirection {
FOCUS_UP,
FOCUS_DOWN,
FOCUS_LEFT,
FOCUS_RIGHT,
FOCUS_NEXT,
FOCUS_PREV,
2013-05-02 22:21:39 +00:00
};
enum {
WRAP_CONTENT = -1,
FILL_PARENT = -2,
};
// Gravity
enum Gravity {
G_LEFT = 0,
G_RIGHT = 1,
G_HCENTER = 2,
G_HORIZMASK = 3,
G_TOP = 0,
G_BOTTOM = 4,
G_VCENTER = 8,
G_TOPLEFT = G_TOP | G_LEFT,
G_TOPRIGHT = G_TOP | G_RIGHT,
G_BOTTOMLEFT = G_BOTTOM | G_LEFT,
G_BOTTOMRIGHT = G_BOTTOM | G_RIGHT,
G_VERTMASK = 3 << 2,
};
typedef float Size; // can also be WRAP_CONTENT or FILL_PARENT.
enum Orientation {
ORIENT_HORIZONTAL,
ORIENT_VERTICAL,
};
enum MeasureSpecType {
UNSPECIFIED,
EXACTLY,
AT_MOST,
};
enum EventReturn {
EVENT_DONE,
EVENT_SKIPPED,
};
class ViewGroup;
2013-05-27 22:32:00 +00:00
void Fill(UIContext &dc, const Bounds &bounds, const Drawable &drawable);
2013-05-02 22:21:39 +00:00
struct MeasureSpec {
MeasureSpec(MeasureSpecType t, float s = 0.0f) : type(t), size(s) {}
MeasureSpec() : type(UNSPECIFIED), size(0) {}
MeasureSpec operator -(float amount) {
// TODO: Check type
return MeasureSpec(type, size - amount);
}
MeasureSpecType type;
float size;
};
class View;
// Should cover all bases.
struct EventParams {
View *v;
uint32_t a, b, x, y;
const char *c;
};
struct HandlerRegistration {
2013-06-02 12:25:57 +00:00
std::function<EventReturn(EventParams&)> func;
2013-05-02 22:21:39 +00:00
};
class Event {
public:
Event() : triggered_(false) {}
// Call this from input thread or whatever, it doesn't matter
2013-06-01 16:59:03 +00:00
void Trigger(EventParams &e);
2013-05-02 22:21:39 +00:00
// Call this from UI thread
void Update();
template<class T>
void Handle(T *thiz, EventReturn (T::* theCallback)(EventParams &e)) {
Add(std::bind(theCallback, thiz, placeholder::_1));
}
2013-05-02 22:21:39 +00:00
private:
void Add(std::function<EventReturn(EventParams&)> func);
2013-05-02 22:21:39 +00:00
recursive_mutex mutex_;
std::vector<HandlerRegistration> handlers_;
bool triggered_;
EventParams eventParams_;
DISALLOW_COPY_AND_ASSIGN(Event);
};
struct Margins {
Margins() : top(0), bottom(0), left(0), right(0) {}
explicit Margins(uint8_t all) : top(all), bottom(all), left(all), right(all) {}
2013-05-25 14:52:27 +00:00
explicit Margins(uint8_t horiz, uint8_t vert) : top(vert), bottom(vert), left(horiz), right(horiz) {}
2013-05-02 22:21:39 +00:00
uint8_t top;
uint8_t bottom;
uint8_t left;
uint8_t right;
};
// Need a virtual destructor so vtables are created, otherwise RTTI can't work
class LayoutParams {
public:
LayoutParams()
: width(WRAP_CONTENT), height(WRAP_CONTENT) {}
LayoutParams(Size w, Size h)
: width(w), height(h) {}
virtual ~LayoutParams() {}
Size width;
Size height;
};
View *GetFocusedView();
class View {
public:
2013-06-02 21:44:28 +00:00
View(LayoutParams *layoutParams = 0) : layoutParams_(layoutParams), enabled_(true), visibility_(V_VISIBLE) {
2013-05-02 22:21:39 +00:00
if (!layoutParams)
layoutParams_.reset(new LayoutParams());
}
virtual ~View() {}
// Please note that Touch is called ENTIRELY asynchronously from drawing!
// Can even be called on a different thread! This is to really minimize latency, and decouple
// touch response from the frame rate.
virtual void Touch(const TouchInput &input) = 0;
virtual void Update(const InputState &input_state) = 0;
2013-05-02 22:21:39 +00:00
void Move(Bounds bounds) {
bounds_ = bounds;
}
// Views don't do anything here in Layout, only containers implement this.
2013-05-27 22:32:00 +00:00
virtual void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert);
2013-05-02 22:21:39 +00:00
virtual void Layout() {}
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc) {}
2013-05-02 22:21:39 +00:00
virtual float GetMeasuredWidth() const { return measuredWidth_; }
virtual float GetMeasuredHeight() const { return measuredHeight_; }
// Override this for easy standard behaviour. No need to override Measure.
2013-05-27 22:32:00 +00:00
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
2013-05-02 22:21:39 +00:00
// Called when the layout is done.
void SetBounds(Bounds bounds) { bounds_ = bounds; }
virtual const LayoutParams *GetLayoutParams() const { return layoutParams_.get(); }
const Bounds &GetBounds() const { return bounds_; }
virtual bool SetFocus() {
if (CanBeFocused()) {
SetFocusedView(this);
return true;
}
return false;
}
2013-05-02 22:21:39 +00:00
virtual bool CanBeFocused() const { return true; }
virtual bool SubviewFocused(View *view) { return false; }
bool HasFocus() const {
2013-05-02 22:21:39 +00:00
return GetFocusedView() == this;
}
2013-06-01 16:59:03 +00:00
void SetEnabled(bool enabled) { enabled_ = enabled; }
2013-06-02 21:44:28 +00:00
bool GetEnabled() const { return enabled_; }
void SetVisibility(Visibility visibility) { visibility_ = visibility; }
Visibility GetVisibility() const { return visibility_; }
2013-06-01 16:59:03 +00:00
2013-05-02 22:21:39 +00:00
protected:
// Inputs to layout
scoped_ptr<LayoutParams> layoutParams_;
2013-06-01 16:59:03 +00:00
bool enabled_;
2013-06-02 21:44:28 +00:00
Visibility visibility_;
2013-06-01 16:59:03 +00:00
2013-05-02 22:21:39 +00:00
// Results of measure pass. Set these in Measure.
float measuredWidth_;
float measuredHeight_;
// Outputs of layout. X/Y are absolute screen coordinates, hierarchy is "gone" here.
Bounds bounds_;
scoped_ptr<Matrix4x4> transform_;
private:
DISALLOW_COPY_AND_ASSIGN(View);
};
// These don't do anything when touched.
class InertView : public View {
public:
InertView(LayoutParams *layoutParams)
: View(layoutParams) {}
virtual void Touch(const TouchInput &input) {}
virtual bool CanBeFocused() const { return false; }
virtual void Update(const InputState &input_state) {}
2013-05-02 22:21:39 +00:00
};
// All these light up their background when touched, or have focus.
class Clickable : public View {
public:
Clickable(LayoutParams *layoutParams)
2013-06-01 16:59:03 +00:00
: View(layoutParams), downCountDown_(0), dragging_(false), down_(false) {}
2013-05-02 22:21:39 +00:00
virtual void Touch(const TouchInput &input);
virtual void Update(const InputState &input_state);
2013-05-02 22:21:39 +00:00
Event OnClick;
protected:
// Internal method that fires on a click. Default behaviour is to trigger
// the event.
// Use it for checking/unchecking checkboxes, etc.
virtual void Click();
2013-05-25 14:52:27 +00:00
int downCountDown_;
bool dragging_;
2013-05-02 22:21:39 +00:00
bool down_;
};
class Button : public Clickable {
public:
Button(const std::string &text, LayoutParams *layoutParams = 0)
: Clickable(layoutParams), text_(text) {}
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc);
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
2013-05-02 22:21:39 +00:00
private:
Style style_;
std::string text_;
};
2013-05-27 20:22:35 +00:00
// Basic button that modifies a bitfield based on the pressed status. Supports multitouch.
// Suitable for controller simulation (ABXY etc).
class TriggerButton : public View {
public:
TriggerButton(uint32_t *bitField, uint32_t bit, int imageBackground, int imageForeground, LayoutParams *layoutParams)
: View(layoutParams), down_(0.0), bitField_(bitField), bit_(bit), imageBackground_(imageBackground), imageForeground_(imageForeground) {}
virtual void Touch(const TouchInput &input);
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc);
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
2013-05-27 20:22:35 +00:00
private:
int down_; // bitfield of pressed fingers, translates into bitField
uint32_t *bitField_;
uint32_t bit_;
int imageBackground_;
int imageForeground_;
};
// The following classes are mostly suitable as items in ListView which
// really is just a LinearLayout in a ScrollView, possibly with some special optimizations.
class Item : public InertView {
public:
2013-05-27 22:50:19 +00:00
Item(LayoutParams *layoutParams);
2013-05-27 22:32:00 +00:00
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const {
w = 0.0f;
h = 0.0f;
}
};
class ClickableItem : public Clickable {
public:
2013-05-27 22:50:19 +00:00
ClickableItem(LayoutParams *layoutParams);
2013-05-27 22:32:00 +00:00
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const {
w = 0.0f;
h = 0.0f;
}
2013-05-25 14:52:27 +00:00
// Draws the item background.
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc);
2013-05-25 14:52:27 +00:00
};
2013-05-02 22:21:39 +00:00
// Use to trigger something or open a submenu screen.
class Choice : public ClickableItem {
2013-05-02 22:21:39 +00:00
public:
Choice(const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = 0)
: ClickableItem(layoutParams), text_(text), smallText_(smallText) {}
2013-05-02 22:21:39 +00:00
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc);
2013-05-02 22:21:39 +00:00
private:
std::string text_;
std::string smallText_;
};
class InfoItem : public Item {
public:
InfoItem(const std::string &text, const std::string &rightText, LayoutParams *layoutParams = 0)
: Item(layoutParams), text_(text), rightText_(rightText) {}
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc);
private:
std::string text_;
std::string rightText_;
};
2013-05-25 14:52:27 +00:00
class ItemHeader : public Item {
public:
ItemHeader(const std::string &text, LayoutParams *layoutParams = 0)
: Item(layoutParams), text_(text) {
layoutParams_->width = FILL_PARENT;
layoutParams_->height = 26;
}
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc);
2013-05-25 14:52:27 +00:00
private:
std::string text_;
};
2013-05-25 13:12:46 +00:00
class CheckBox : public ClickableItem {
2013-05-02 22:21:39 +00:00
public:
CheckBox(bool *toggle, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = 0)
2013-05-25 13:12:46 +00:00
: ClickableItem(layoutParams), text_(text), smallText_(smallText) {
OnClick.Handle(this, &CheckBox::OnClicked);
}
2013-05-02 22:21:39 +00:00
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc);
2013-05-02 22:21:39 +00:00
2013-06-01 16:59:03 +00:00
EventReturn OnClicked(EventParams &e) {
if (toggle_)
*toggle_ = !(*toggle_);
return EVENT_DONE;
}
2013-05-25 13:12:46 +00:00
2013-05-02 22:21:39 +00:00
private:
bool *toggle_;
2013-05-02 22:21:39 +00:00
std::string text_;
std::string smallText_;
};
// These are for generic use.
class Spacer : public InertView {
public:
Spacer(LayoutParams *layoutParams = 0)
: InertView(layoutParams) {}
2013-05-27 22:32:00 +00:00
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) {
w = 0.0f; h = 0.0f;
}
2013-05-27 22:32:00 +00:00
virtual void Draw(UIContext &dc) {}
2013-05-02 22:21:39 +00:00
};
class TextView : public InertView {
public:
2013-06-01 16:59:03 +00:00
TextView(int font, const std::string &text, int textAlign, float textScale, LayoutParams *layoutParams = 0)
: InertView(layoutParams), font_(font), text_(text), textScale_(textScale), textAlign_(textAlign) {}
2013-05-02 22:21:39 +00:00
2013-05-27 22:32:00 +00:00
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
virtual void Draw(UIContext &dc);
2013-06-02 21:44:28 +00:00
virtual void SetText(const std::string &text) { text_ = text; }
2013-05-02 22:21:39 +00:00
private:
int font_;
2013-06-01 16:59:03 +00:00
std::string text_;
float textScale_;
int textAlign_;
2013-05-02 22:21:39 +00:00
};
enum ImageSizeMode {
IS_DEFAULT,
};
2013-05-02 22:21:39 +00:00
class ImageView : public InertView {
public:
ImageView(int atlasImage, ImageSizeMode sizeMode, LayoutParams *layoutParams = 0)
: InertView(layoutParams), atlasImage_(atlasImage), sizeMode_(sizeMode) {}
2013-05-27 22:32:00 +00:00
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
virtual void Draw(UIContext &dc);
2013-05-02 22:21:39 +00:00
private:
int atlasImage_;
ImageSizeMode sizeMode_;
};
2013-06-02 21:44:28 +00:00
class ProgressBar : public InertView {
public:
ProgressBar(LayoutParams *layoutParams = 0)
: InertView(layoutParams), progress_(0.0) {}
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
virtual void Draw(UIContext &dc);
void SetProgress(float progress) { progress_ = progress; }
float GetProgress() const { return progress_; }
private:
float progress_;
};
2013-05-27 20:22:35 +00:00
2013-05-02 22:21:39 +00:00
// This tab strip is a little special.
/*
class TabStrip : public View {
public:
TabStrip();
virtual void Touch(const TouchInput &input);
virtual void Draw(DrawContext &dc);
void AddTab(const std::string &title, uint32_t color) {
Tab tab;
tab.title = title;
tab.color = color;
tabs_.push_back(tab);
}
private:
int selected_;
struct Tab {
std::string title;
uint32_t color;
};
std::vector<Tab> tabs_;
};*/
void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measured);
} // namespace