222 lines
5.2 KiB
C++
222 lines
5.2 KiB
C++
#pragma once
|
|
|
|
#include <glm/glm.hpp>
|
|
#include <string>
|
|
|
|
#include "fonts.h"
|
|
#include "input.h"
|
|
#include "types.h"
|
|
|
|
#define uiPx(val) kek::UIValue(val, kek::UIUnit::PIXELS)
|
|
#define uiPw(val) kek::UIValue(val, kek::UIUnit::PARENT_WIDTH)
|
|
#define uiPh(val) kek::UIValue(val, kek::UIUnit::PARENT_HEIGHT)
|
|
#define uiSw(val) kek::UIValue(val, kek::UIUnit::SCREEN_WIDTH)
|
|
#define uiSh(val) kek::UIValue(val, kek::UIUnit::SCREEN_HEIGHT)
|
|
|
|
namespace kek {
|
|
|
|
struct UIBounds {
|
|
int x, y, w, h;
|
|
|
|
UIBounds(int x, int y, int w, int h)
|
|
: x(x),
|
|
y(y),
|
|
w(w),
|
|
h(h) {}
|
|
|
|
// Checks if a point is contained in the bounds
|
|
inline bool contains(IntPoint2 pos) {
|
|
return pos.x > x && pos.y > y && pos.x < x + w && pos.y < y + h;
|
|
}
|
|
|
|
// Checks if an already offset point is contained in the bounds
|
|
inline bool containsOffset(IntPoint2 pos) {
|
|
return pos.x > 0 && pos.y > 0 && pos.x < w && pos.y < h;
|
|
}
|
|
};
|
|
|
|
enum class UIElementType {
|
|
WINDOW,
|
|
RECTANGLE,
|
|
TEXT,
|
|
BUTTON,
|
|
TEXTURE,
|
|
TEXT_FIELD,
|
|
SLIDER,
|
|
CHECKBOX,
|
|
GROUP
|
|
};
|
|
|
|
enum class Origin {
|
|
TOP_LEFT,
|
|
TOP_CENTER,
|
|
TOP_RIGHT,
|
|
BOTTOM_LEFT,
|
|
BOTTOM_CENTER,
|
|
BOTTOM_RIGHT,
|
|
LEFT_CENTER,
|
|
RIGHT_CENTER,
|
|
CENTER
|
|
};
|
|
|
|
enum class UIUnit {
|
|
PIXELS,
|
|
PARENT_WIDTH,
|
|
PARENT_HEIGHT,
|
|
SCREEN_WIDTH,
|
|
SCREEN_HEIGHT
|
|
};
|
|
|
|
struct UIValue {
|
|
float pixels = 0;
|
|
float parentWidth = 0;
|
|
float parentHeight = 0;
|
|
float screenWidth = 0;
|
|
float screenHeight = 0;
|
|
|
|
constexpr UIValue(float value, UIUnit unit) {
|
|
switch(unit) {
|
|
case UIUnit::PIXELS:
|
|
this->pixels = value;
|
|
break;
|
|
case UIUnit::PARENT_WIDTH:
|
|
this->parentWidth = value;
|
|
break;
|
|
case UIUnit::PARENT_HEIGHT:
|
|
this->parentHeight = value;
|
|
break;
|
|
case UIUnit::SCREEN_WIDTH:
|
|
this->screenWidth = value;
|
|
break;
|
|
case UIUnit::SCREEN_HEIGHT:
|
|
this->screenHeight = value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
constexpr UIValue() = default;
|
|
|
|
constexpr UIValue &operator+=(const UIValue &rhs) {
|
|
this->pixels += rhs.pixels;
|
|
this->parentWidth += rhs.parentWidth;
|
|
this->parentHeight += rhs.parentHeight;
|
|
this->screenWidth += rhs.screenWidth;
|
|
this->screenHeight += rhs.screenHeight;
|
|
return *this;
|
|
}
|
|
|
|
constexpr UIValue &operator-=(const UIValue &rhs) {
|
|
this->pixels -= rhs.pixels;
|
|
this->parentWidth -= rhs.parentWidth;
|
|
this->parentHeight -= rhs.parentHeight;
|
|
this->screenWidth -= rhs.screenWidth;
|
|
this->screenHeight -= rhs.screenHeight;
|
|
return *this;
|
|
}
|
|
|
|
constexpr friend UIValue operator+(const UIValue &lhs, const UIValue &rhs) {
|
|
return UIValue(lhs) += rhs;
|
|
}
|
|
|
|
constexpr friend UIValue operator-(const UIValue &lhs, const UIValue &rhs) {
|
|
return UIValue(lhs) -= rhs;
|
|
}
|
|
};
|
|
|
|
class UIElement {
|
|
|
|
protected:
|
|
UIElement *parent = nullptr;
|
|
std::vector<UIElement *> children;
|
|
|
|
public:
|
|
UIValue x, y;
|
|
Origin origin = Origin::TOP_LEFT;
|
|
bool enableClipping = false;
|
|
|
|
bool clickable = false;
|
|
bool visible = true;
|
|
bool focusable = false;
|
|
bool draggable = false;
|
|
|
|
bool hovering = false;
|
|
bool focused = false;
|
|
|
|
UIElement(UIValue x, UIValue y);
|
|
|
|
virtual ~UIElement();
|
|
|
|
virtual UIElementType getType() = 0;
|
|
|
|
// Returns the element's origin position relative to its parent in pixels (not offset by getBounds())
|
|
IntPoint2 getOriginPosition();
|
|
|
|
// Returns the element's position relative to its parent in pixels (offset by getBounds())
|
|
IntPoint2 getPosition();
|
|
|
|
// Returns the element's origin position on the screen in pixels (not offset by getBounds())
|
|
IntPoint2 getScreenOriginPosition();
|
|
|
|
// Returns the element's position on the screen in pixels (offset by getBounds())
|
|
IntPoint2 getScreenPosition();
|
|
|
|
// Returns the bounds of the element relative to its origin
|
|
virtual UIBounds getBounds() = 0;
|
|
|
|
// Returns the bounds of the element on the screen
|
|
UIBounds getScreenBounds();
|
|
|
|
std::vector<UIElement *> getChildren();
|
|
void addChild(UIElement *child);
|
|
void removeChild(UIElement *child);
|
|
|
|
protected:
|
|
int uiToScreen(UIValue val);
|
|
static int offsetX(int w, Origin origin);
|
|
static int offsetY(int h, Origin origin);
|
|
static UIBounds offsetUIBounds(int w, int h, Origin origin);
|
|
|
|
public:
|
|
void drawAll(IntPoint2 screenPos, glm::mat4 projection);
|
|
virtual void draw(IntPoint2 screenPos, glm::mat4 projection) = 0;
|
|
|
|
void hoverAll(IntPoint2 pos, IntPoint2 screenPos);
|
|
void hoverExitAll();
|
|
virtual void hoverEnter(IntPoint2 pos, IntPoint2 screenPos){};
|
|
virtual void hover(IntPoint2 pos, IntPoint2 screenPos){};
|
|
virtual void hoverExit(){};
|
|
|
|
bool clickAll(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button);
|
|
virtual void click(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button){};
|
|
|
|
bool focusEnterAll(IntPoint2 pos, IntPoint2 screenPos);
|
|
virtual void focusEnter(){};
|
|
virtual void focusExit(){};
|
|
|
|
bool dragEnterAll(IntPoint2 pos, IntPoint2 screenPos);
|
|
virtual void dragEnter(IntPoint2 pos, IntPoint2 screenPos){};
|
|
virtual void drag(IntPoint2 pos, IntPoint2 screenPos){};
|
|
virtual void dragExit(IntPoint2 pos, IntPoint2 screenPos){};
|
|
};
|
|
|
|
namespace UI {
|
|
|
|
void init();
|
|
void destroy();
|
|
|
|
std::vector<UIElement *> getElements();
|
|
void addElement(UIElement *element);
|
|
void removeElement(UIElement *element);
|
|
|
|
void focusElement(UIElement *element);
|
|
void unfocusElement(UIElement *element);
|
|
|
|
// Finds the first (topmost) element at the given screen position
|
|
UIElement *findElementAt(IntPoint2 screenPos);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#include "uielements.h"
|