summaryrefslogtreecommitdiff
path: root/ui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ui.cpp')
-rw-r--r--ui.cpp270
1 files changed, 218 insertions, 52 deletions
diff --git a/ui.cpp b/ui.cpp
index aeb084e..8cb9b59 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -157,7 +157,7 @@ void UI::Rect::shrink(int a) {
}
bool UI::Rect::contains(int px, int py) {
- return px >= x && py >= y && px < x + w && py < y + w;
+ return px >= x && py >= y && px < x + w && py < y + h;
}
void UI::Vertex_Buffer::init(Device* dev) {
@@ -375,14 +375,19 @@ void UI::Vertex_Buffer::draw(
start = usage;
}
-UI* UI::create(Device* dev, Arena* a, Shader_Id sh) {
+UI* UI::create(
+ Device* dev,
+ const App* app,
+ Arena* a,
+ Shader_Id sh
+) {
int hs;
Texture_Id atlas = create_atlas(dev);
UI* u = (UI*)arena_alloc(a, sizeof *u);
Heap* h = (Heap*)arena_alloc(a, sizeof *h);
hs = a->size - a->ptr - allocation_default_alignment - 1;
init_heap(h, arena_alloc(a, hs), hs);
- u->init(dev, h, atlas, sh);
+ u->init(dev, app, h, atlas, sh);
return u;
}
@@ -399,6 +404,7 @@ int UI::text_height(const char* t) {
void UI::init(
Device* dev,
+ const App* a,
Heap* h,
Texture_Id at,
Shader_Id sh
@@ -406,8 +412,11 @@ void UI::init(
Shader* sp;
heap = h;
device = dev;
+ app = a;
atlas = at;
shader = sh;
+ hot = 0;
+ hovered = 0;
mesh.init(device);
cbuffer.init(
device,
@@ -425,26 +434,48 @@ void UI::init(
}
void UI::destroy() {
- root->~Element();
- heap_free(heap, root);
+ root->destroy();
device->destroy_texture(atlas);
device->destroy_sampler(sampler);
mesh.destroy(this);
cbuffer.destroy(device);
}
-void UI::update(Arena* s, const App& app) {
+void UI::layout(int w, int h) {
+ area_w = w;
+ area_h = h;
+ Rect avail(0, 0, w, h);
+ root->layout(avail);
+ layout_dirty = 0;
+}
+
+void UI::update(Arena* s) {
(void)s;
hovered = 0;
- root->update(app);
- if (app.mjp(mbtn_left))
+ root->update();
+ if (app->mjp(mbtn_left)) {
+ if (hovered) {
+ Message msg{};
+ msg.type = Message::Type::activate;
+ hovered->message(msg);
+ }
hot = hovered;
- if (app.mjr(mbtn_left) && hot && hot == hovered) {
- Message msg{};
- msg.type = Message::Type::click;
- hot->message(msg);
- hot = 0;
}
+ if (app->mjr(mbtn_left)) {
+ if (hot) {
+ Message msg{};
+ msg.type = Message::Type::deactivate;
+ hot->message(msg);
+ if (hot == hovered) {
+ Message msg2{};
+ msg2.type = Message::Type::click;
+ hot->message(msg2);
+ }
+ hot = 0;
+ }
+ }
+ if (layout_dirty)
+ layout(area_w, area_h);
}
void UI::render(Arena* s, Texture_Id target) {
@@ -460,9 +491,6 @@ void UI::render(Arena* s, Texture_Id target) {
cbuffer.unmap(device);
cbuffer.update(ctx);
- Rect avail(0, 0, t.w, t.h);
- root->layout(avail);
-
Pipeline_Builder pb(s, device);
pb.begin_rp();
pb.rp_target(device->get_backbuffer(), Clear_Mode::restore);
@@ -474,7 +502,7 @@ void UI::render(Arena* s, Texture_Id target) {
pb.blend(
Blend_Mode::add,
Blend_Factor::src_alpha,
- Blend_Factor::inv_src_colour
+ Blend_Factor::inv_src_alpha
);
pb.cbuffer(shader_info.config_binding, cbuffer.gpuonly);
pb.texture(shader_info.atlas_binding, atlas, sampler);
@@ -485,7 +513,7 @@ void UI::render(Arena* s, Texture_Id target) {
mesh.draw(this, ctx, *pipeline, *render_pass);
}
-void UI::draw_container(const Rect& bound) {
+void UI::draw_container(const Rect& bound, Colour c) {
/* todo line function lmao */
mesh.add_rect(
this,
@@ -493,7 +521,7 @@ void UI::draw_container(const Rect& bound) {
bound.y,
bound.w,
bound.h,
- 0xffffff
+ c
);
mesh.add_rect(
this,
@@ -545,14 +573,14 @@ void UI::draw_container(const Rect& bound) {
);
}
-void UI::draw_containeri(const Rect& bound) {
+void UI::draw_containeri(const Rect& bound, Colour c) {
mesh.add_rect(
this,
bound.x,
bound.y,
bound.w,
bound.h,
- 0xffffff
+ c
);
mesh.add_rect(
this,
@@ -614,43 +642,58 @@ UI::Element::Element(UI* ui, Element* parent):
ui(ui),
parent(parent),
children(0),
+ next(0),
handler(0),
- child_count(0) {
+ flags(0) {
if (parent)
parent->add_child(this);
}
UI::Element::~Element() {
- int i, c = child_count;
- for (i = 0; i < c; i++) {
- Element* child = children[i];
+ Element* child;
+ for (child = children; child;) {
+ Element* n = child->next;
child->~Element();
heap_free(ui->heap, child);
+ child = n;
}
- if (children)
- heap_free(ui->heap, children);
+ if (parent)
+ parent->remove_child(this);
+}
+
+void UI::Element::destroy() {
+ Message m{};
+ m.type = Message::Type::destroy;
+ message(m);
+ this->~Element();
+ heap_free(ui->heap, this);
}
UI::Rect UI::Element::layout(const Rect& avail) {
return avail;
}
-void UI::Element::update(const App& app) {
- int i, c = child_count;
- if (bound.contains(app.mx, app.my)) {
+void UI::Element::update() {
+ Element* child;
+ if (enabled() && bound.contains(ui->app->mx, ui->app->my)) {
ui->hovered = this;
}
- for (i = 0; i < c; i++) {
- children[i]->update(app);
+ on_update();
+ for (child = children; child; child = child->next) {
+ child->update();
}
}
+void UI::Element::on_update() {
+
+}
+
void UI::Element::render() {
- int i, c = child_count;
+ Element* child;
Rect old_clip = ui->mesh.clip;
on_render();
- for (i = 0; i < c; i++) {
- children[i]->render();
+ for (child = children; child; child = child->next) {
+ child->render();
}
ui->mesh.clip = old_clip;
}
@@ -663,16 +706,39 @@ void UI::Element::on_render() {
}
+bool UI::Element::enabled() {
+ return (flags & Flags::disabled) == 0;
+}
+
+void UI::Element::disable() {
+ flags |= Flags::disabled;
+}
+
+void UI::Element::enable() {
+ flags &= ~Flags::disabled;
+}
+
void UI::Element::add_child(Element* ch) {
- int ncc = child_count + 1;
- Element** nc = (Element**)heap_alloc(ui->heap, sizeof *nc * ncc);
- if (children) {
- memcpy(nc, children, child_count * sizeof *children);
- heap_free(ui->heap, children);
+ if (!children)
+ children = ch;
+ else {
+ Element* child = children;
+ for (; child && child->next; child = child->next);
+ child->next = ch;
}
- children = nc;
- children[child_count] = ch;
- child_count = ncc;
+ ui->layout_dirty = true;
+}
+
+void UI::Element::remove_child(Element* ch) {
+ Element* child = children;
+ Element* prev = 0;
+ for (; child && child != ch; child = child->next)
+ prev = child;
+ assert(child != 0);
+ if (prev)
+ prev->next = ch->next;
+ else
+ children = ch->next;
}
void UI::Element::message(const Message& msg) {
@@ -685,19 +751,20 @@ UI::Container::Container(UI* ui, Element* parent):
Element(ui, parent), padding(ui_padding) {}
UI::Rect UI::Container::layout(const Rect& avail) {
- int i, c = child_count;
+ Element* child;
Rect area = avail;
Rect used = avail;
used.w = used.h = 0;
bound = avail;
clip = avail;
- for (i = 0; i < c; i++) {
- Rect r = children[i]->layout(area);
+ for (child = children; child; child = child->next) {
+ Rect r = child->layout(area);
area.y += r.h + padding;
area.h -= r.h;
if (r.w > used.w) used.w = r.w;
used.h += r.h;
}
+ bound = used;
return used;
}
@@ -705,14 +772,14 @@ UI::Toolbar::Toolbar(UI* ui, Element* parent):
Element(ui, parent), padding(0) {}
UI::Rect UI::Toolbar::layout(const Rect& avail) {
- int i, c = child_count;
+ Element* child;
Rect area = avail;
Rect used = avail;
used.w = used.h = 0;
bound = avail;
clip = avail;
- for (i = 0; i < c; i++) {
- Rect r = children[i]->layout(area);
+ for (child = children; child; child = child->next) {
+ Rect r = child->layout(area);
area.x += r.w + padding;
area.w -= r.w;
if (r.h > used.h) used.h = r.h;
@@ -741,6 +808,10 @@ UI::Button::Button(UI* ui, Element* parent, const char* label):
text = dup_stringh(ui->heap, label);
}
+UI::Button::~Button() {
+ heap_free(ui->heap, text);
+}
+
UI::Rect UI::Button::layout(const Rect& avail) {
Rect r = {
avail.x,
@@ -756,10 +827,49 @@ UI::Rect UI::Button::layout(const Rect& avail) {
}
void UI::Button::on_render() {
- if (this == ui->hot)
- ui->draw_containeri(bound);
+ Colour tc = 0x000000;
+ if (flags & Flags::disabled)
+ tc = 0x4f4f4f;
+ if (this == ui->hovered)
+ ui->draw_container(bound, 0xf0f8ff);
+ else if (this == ui->hot)
+ ui->draw_containeri(bound, 0xffffff);
else
- ui->draw_container(bound);
+ ui->draw_container(bound, 0xffffff);
+ ui->mesh.set_clip(clip);
+ ui->mesh.add_text(
+ ui,
+ bound.x + ui_padding,
+ bound.y + ui_padding,
+ text,
+ tc
+ );
+}
+
+UI::Label::Label(UI* ui, Element* parent, const char* label):
+ Element(ui, parent) {
+ text = dup_stringh(ui->heap, label);
+}
+
+UI::Label::~Label() {
+ heap_free(ui->heap, text);
+}
+
+UI::Rect UI::Label::layout(const Rect& avail) {
+ Rect r = {
+ avail.x,
+ avail.y,
+ ui->text_width(text) + ui_padding * 2,
+ ui->text_height(text) + ui_padding * 2
+ };
+ r.clip(avail);
+ bound = r;
+ clip = r;
+ clip.shrink(ui_padding);
+ return r;
+}
+
+void UI::Label::on_render() {
ui->mesh.set_clip(clip);
ui->mesh.add_text(
ui,
@@ -770,3 +880,59 @@ void UI::Button::on_render() {
);
}
+static int drag_handler(UI::Modal* modal, const UI::Message& msg) {
+ if (msg.type == UI::Message::Type::activate) {
+ const App& app = *modal->ui->app;
+ const UI::Rect& tb = modal->title_bar->bound;
+ modal->dragging = true;
+ modal->drag_offset[0] = app.mx - tb.x;
+ modal->drag_offset[1] = app.my - tb.y;
+ }
+ if (msg.type == UI::Message::Type::deactivate)
+ modal->dragging = false;
+ return 0;
+};
+
+UI::Modal::Modal(UI* ui, Element* parent, const char* text):
+ Element(ui, parent), dragging(false) {
+ contents = ui->create_element<Container>(this);
+ title_bar = ui->create_element<Toolbar>(contents);
+ title_bar->handler = [](Element* e, const Message& m) {
+ return drag_handler((Modal*)e->parent->parent, m);
+ };
+ close = ui->create_element<Button>(title_bar, "x");
+ title = ui->create_element<Label>(title_bar, text);
+ title->handler = [](Element* e, const Message& m) {
+ return drag_handler((Modal*)e->parent->parent->parent, m);
+ };
+ close->handler = [](Element* e, const Message& m) {
+ if (m.type == Message::Type::click)
+ e->parent->parent->parent->destroy();
+ return 0;
+ };
+}
+
+UI::Rect UI::Modal::layout(const Rect& avail) {
+ UI::Rect content_size = contents->layout(avail);
+ title_bar->layout(content_size);
+ bound = content_size;
+ clip = content_size;
+ return content_size;
+}
+
+void UI::Modal::on_render() {
+ ui->draw_container(
+ contents->bound,
+ Colour(0xffffff, 0x80)
+ );
+}
+
+void UI::Modal::on_update() {
+ if (dragging) {
+ const App& app = *ui->app;
+ Rect avail = bound;
+ avail.x = app.mx - drag_offset[0];
+ avail.y = app.my - drag_offset[1];
+ layout(avail);
+ }
+}