Skip to content

Commit

Permalink
Add ui::Interactable, ui::Button
Browse files Browse the repository at this point in the history
  • Loading branch information
karnkaul committed Oct 19, 2023
1 parent 518eab7 commit 14a93d7
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 35 deletions.
2 changes: 2 additions & 0 deletions scene/header_list.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ set(header_list
${prefix}/scene/imcpp/scene_inspector.hpp
${prefix}/scene/imcpp/scene_graph.hpp

${prefix}/scene/ui/button.hpp
${prefix}/scene/ui/element.hpp
${prefix}/scene/ui/input_text.hpp
${prefix}/scene/ui/interactable.hpp
${prefix}/scene/ui/primitive_renderer.hpp
${prefix}/scene/ui/quad.hpp
${prefix}/scene/ui/rect_transform.hpp
Expand Down
41 changes: 41 additions & 0 deletions scene/include/le/scene/ui/button.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once
#include <le/core/signal.hpp>
#include <le/scene/ui/interactable.hpp>
#include <le/scene/ui/quad.hpp>
#include <le/scene/ui/text.hpp>
#include <le/scene/ui/view.hpp>

namespace le::ui {
class Button : public View, public Interactable {
public:
using OnTrigger = Signal<>;

explicit Button(Ptr<View> parent_view = {});

auto on_trigger(OnTrigger::Callback callback) { return m_on_trigger.connect(std::move(callback)); }

template <typename PointerT, typename MemberFuncT>
requires(std::is_invocable_v<MemberFuncT, PointerT>)
auto on_trigger(PointerT object, MemberFuncT member_func) {
return m_on_trigger.connect(object, member_func);
}

[[nodiscard]] auto get_quad() const -> Quad& { return *m_quad; }
[[nodiscard]] auto get_text() const -> Text& { return *m_text; }

graphics::Rgba no_focus{graphics::white_v};
graphics::Rgba in_focus{graphics::yellow_v};

protected:
void tick(Duration dt) override;

void on_focus_gained() override { m_quad->set_tint(in_focus); }
void on_focus_lost() override { m_quad->set_tint(no_focus); }
void on_release() override { m_on_trigger(); }

private:
Ptr<Quad> m_quad{};
Ptr<Text> m_text{};
OnTrigger m_on_trigger{};
};
} // namespace le::ui
11 changes: 3 additions & 8 deletions scene/include/le/scene/ui/element.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <le/core/polymorphic.hpp>
#include <le/core/radians.hpp>
#include <le/core/time.hpp>
#include <le/graphics/render_object.hpp>
Expand All @@ -9,15 +10,8 @@ using graphics::RenderObject;

class View;

class Element {
class Element : public Polymorphic {
public:
Element(Element const&) = default;
Element(Element&&) = default;
auto operator=(Element const&) -> Element& = default;
auto operator=(Element&&) -> Element& = default;

virtual ~Element() = default;

Element(NotNull<View*> parent_view) : m_parent_view(parent_view) {}

virtual auto tick(Duration dt) -> void = 0;
Expand All @@ -33,6 +27,7 @@ class Element {
[[nodiscard]] auto get_parent_matrix() const -> glm::mat4 const& { return m_parent_mat; }

[[nodiscard]] auto local_matrix() const -> glm::mat4;
[[nodiscard]] auto global_position() const -> glm::vec3;

RectTransform transform{};
float z_index{};
Expand Down
22 changes: 22 additions & 0 deletions scene/include/le/scene/ui/interactable.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once
#include <le/core/polymorphic.hpp>
#include <le/core/time.hpp>
#include <le/graphics/rect.hpp>

namespace le::ui {
class Interactable : public Polymorphic {
public:
[[nodiscard]] auto in_focus() const -> bool { return m_in_focus; }

void update(graphics::Rect2D<> const& hitbox);

protected:
virtual void on_focus_gained() {}
virtual void on_focus_lost() {}
virtual void on_press() {}
virtual void on_release() {}

private:
bool m_in_focus{};
};
} // namespace le::ui
7 changes: 4 additions & 3 deletions scene/include/le/scene/ui/primitive_renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ class PrimitiveRenderer : public Renderable {
public:
using Renderable::Renderable;

auto set_quad(graphics::Quad quad) -> void;
void set_quad(graphics::Quad quad);
void set_texture(Ptr<graphics::Texture const> texture);

auto tick(Duration /*dt*/) -> void override {}
auto render(std::vector<graphics::RenderObject>& out) const -> void override;
void tick(Duration /*dt*/) override {}
void render(std::vector<graphics::RenderObject>& out) const override;

graphics::DynamicPrimitive primitive{};
graphics::UnlitMaterial material{};
Expand Down
13 changes: 9 additions & 4 deletions scene/include/le/scene/ui/text.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@
#include <le/vfs/uri.hpp>

namespace le::ui {
enum class HorzAlign { eLeft, eMid, eRight };
enum class VertAlign { eTop, eMid, eBottom };

class Text : public Renderable {
public:
enum class Align : std::uint8_t { eLeft, eMid, eRight };
struct Align {
HorzAlign horz{HorzAlign::eMid};
VertAlign vert{VertAlign::eTop};
};

// NOLINTNEXTLINE
inline static Uri default_font_uri{"fonts/default.ttf"};
inline static Uri default_font_uri{"fonts/default.ttf"}; // NOLINT

Text(NotNull<View*> parent_view);

Expand Down Expand Up @@ -39,7 +44,7 @@ class Text : public Renderable {
std::string m_text{};
Ptr<graphics::Font> m_font{};
graphics::TextHeight m_height{graphics::TextHeight::eDefault};
Align m_align{Align::eMid};
Align m_align{};

graphics::DynamicPrimitive m_text_primitive{};
graphics::UnlitMaterial m_text_material{};
Expand Down
10 changes: 2 additions & 8 deletions scene/include/le/scene/ui/view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,8 @@
namespace le::ui {
class Quad;

class View {
class View : public Polymorphic {
public:
View(View const&) = delete;
View(View&&) = delete;
auto operator=(View const&) -> View& = delete;
auto operator=(View&&) -> View& = delete;

virtual ~View() = default;

explicit View(Ptr<View> parent_view = {});

virtual auto tick(Duration dt) -> void;
Expand Down Expand Up @@ -46,6 +39,7 @@ class View {

[[nodiscard]] auto get_parent() const -> Ptr<View> { return m_parent; }
[[nodiscard]] auto get_parent_matrix() const -> glm::mat4 { return m_parent_mat; }
[[nodiscard]] auto global_position() const -> glm::vec3;

RectTransform transform{};

Expand Down
2 changes: 2 additions & 0 deletions scene/src/ui/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
target_sources(${PROJECT_NAME} PRIVATE
button.cpp
element.cpp
input_text.cpp
interactable.cpp
primitive_renderer.cpp
quad.cpp
rect_transform.cpp
Expand Down
17 changes: 17 additions & 0 deletions scene/src/ui/button.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <le/scene/ui/button.hpp>

namespace le::ui {
Button::Button(Ptr<View> parent_view) : View(parent_view), m_quad(&push_element<Quad>()), m_text(&push_element<Text>()) {
transform.extent = {200, 100};
m_text->set_text("button");
m_text->set_tint(graphics::black_v);
m_text->set_align({.vert = VertAlign::eMid});
}

void Button::tick(Duration dt) {
m_quad->transform.extent = transform.extent;
View::tick(dt);
auto const hitbox = graphics::Rect2D<>::from_extent(transform.extent, global_position());
Interactable::update(hitbox);
}
} // namespace le::ui
6 changes: 6 additions & 0 deletions scene/src/ui/element.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <le/core/transform.hpp>
#include <le/scene/ui/element.hpp>

namespace le::ui {
Expand All @@ -15,4 +16,9 @@ auto Element::local_matrix() const -> glm::mat4 {
auto const s = glm::scale(identity_v, glm::vec3{transform.scale, 1.0f});
return t * r * s;
}

auto Element::global_position() const -> glm::vec3 {
auto const mat = get_parent_matrix() * local_matrix();
return Transform::from(mat).position();
}
} // namespace le::ui
32 changes: 32 additions & 0 deletions scene/src/ui/interactable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <le/engine.hpp>
#include <le/scene/ui/interactable.hpp>

namespace le::ui {
void Interactable::update(graphics::Rect2D<> const& hitbox) {
auto const extent = hitbox.extent();
auto const hit_test = [hitbox, extent](glm::vec2 const point) {
if (extent.x <= 0.0f || extent.y <= 0.0f) { return false; };
return hitbox.contains(point);
};

auto const& input_state = Engine::self().input_state();
auto const in_focus = hit_test(input_state.cursor_position);

if (!m_in_focus && in_focus) {
on_focus_gained();
} else if (!in_focus && m_in_focus) {
on_focus_lost();
}
m_in_focus = in_focus;

if (!m_in_focus) { return; }

auto const mb1_state = input_state.mouse_buttons.at(GLFW_MOUSE_BUTTON_1);
using enum input::Action;
switch (mb1_state) {
case ePress: on_press(); break;
case eRelease: on_release(); break;
default: break;
}
}
} // namespace le::ui
6 changes: 4 additions & 2 deletions scene/src/ui/primitive_renderer.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include <le/scene/ui/primitive_renderer.hpp>

namespace le::ui {
auto PrimitiveRenderer::set_quad(graphics::Quad quad) -> void { primitive.set_geometry(graphics::Geometry::from(quad)); }
void PrimitiveRenderer::set_quad(graphics::Quad quad) { primitive.set_geometry(graphics::Geometry::from(quad)); }

auto PrimitiveRenderer::render(std::vector<graphics::RenderObject>& out) const -> void {
void PrimitiveRenderer::set_texture(Ptr<graphics::Texture const> texture) { material.texture = texture; }

void PrimitiveRenderer::render(std::vector<graphics::RenderObject>& out) const {
if (!is_active()) { return; }

render_to(out, &material, &primitive);
Expand Down
22 changes: 14 additions & 8 deletions scene/src/ui/text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,24 @@ auto Text::refresh() -> void {
if (m_font == nullptr) { return; }

auto const n_offset = [&] {
switch (m_align) {
// NOLINTNEXTLINE
case Align::eLeft: return -0.5f;
// NOLINTNEXTLINE
case Align::eRight: return +0.5f;
default: return 0.0f;
auto ret = glm::vec2{};
switch (m_align.horz) {
case HorzAlign::eLeft: ret.x = -0.5f; break; // NOLINT
case HorzAlign::eRight: ret.x = +0.5f; break; // NOLINT
default: break;
}
switch (m_align.vert) {
case VertAlign::eTop: ret.y = 0.5f; break; // NOLINT
case VertAlign::eBottom: ret.y = -0.5f; break; // NOLINT
default: break;
}
return ret;
}();

auto pen = graphics::Font::Pen{*m_font, m_height};
auto const offset_x = (n_offset - 0.5f) * pen.calc_line_extent(m_text).x;
pen.cursor.x = offset_x;
auto const offset = (n_offset - 0.5f) * pen.calc_line_extent(m_text);
pen.cursor.x = offset.x;
pen.cursor.y = offset.y;
m_text_start = pen.cursor;
m_text_primitive.set_geometry(pen.generate_quads(m_text));
m_text_material.texture = &pen.get_texture();
Expand Down
11 changes: 9 additions & 2 deletions scene/src/ui/view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ View::View(Ptr<View> parent_view) : m_parent(parent_view), m_background(&push_el
m_background->set_active(false);
}

auto View::tick(Duration dt) -> void { // NOLINT
auto View::tick(Duration dt) -> void { // NOLINT(misc-no-recursion)
if (m_background != nullptr) { m_background->transform.extent = transform.extent; }

auto do_tick = [this, dt](auto& cache, auto& source) {
Expand All @@ -30,7 +30,7 @@ auto View::tick(Duration dt) -> void { // NOLINT
do_tick(m_view_cache, m_sub_views);
}

auto View::render_tree(std::vector<RenderObject>& out) const -> void { // NOLINT
auto View::render_tree(std::vector<RenderObject>& out) const -> void { // NOLINT(misc-no-recursion)
for (auto const& element : m_elements) { element->render(out); }
for (auto const& view : m_sub_views) { view->render_tree(out); }
}
Expand All @@ -46,4 +46,11 @@ auto View::set_background(graphics::Rgba tint) -> void {
}

auto View::reset_background() -> void { m_background->set_active(false); }

auto View::global_position() const -> glm::vec3 {
auto offset_transform = transform;
offset_transform.position += transform.anchor * transform.extent;
auto const mat = get_parent_matrix() * offset_transform.matrix();
return Transform::from(mat).position();
}
} // namespace le::ui

0 comments on commit 14a93d7

Please sign in to comment.