actually sensible classes

This commit is contained in:
Jorijn van der Graaf 2025-11-25 20:30:54 +01:00
commit c3b8761102
13 changed files with 128 additions and 152 deletions

View file

@ -6,9 +6,7 @@ using namespace Crafter;
int main() { int main() {
WindowWayland window(1280, 720, "Hello Input!"); WindowWayland window(1280, 720, "Hello Input!");
RenderingMouseElement element( Transform element(
2, //bufferWidth: the width of this elements pixel buffer
1, //bufferHeight: the height of this elements pixel buffer
FractionalToMapped(0.5), //anchorX: relative position where this elements x anchor (top-left) is placed to its parent x anchor FractionalToMapped(0.5), //anchorX: relative position where this elements x anchor (top-left) is placed to its parent x anchor
FractionalToMapped(0.5), //anchorY: relative position where this elements y anchor (top-left) is placed to its parent y anchor FractionalToMapped(0.5), //anchorY: relative position where this elements y anchor (top-left) is placed to its parent y anchor
FractionalToMapped(0.5), //relativeSizeX: the relative x size this element should be scaled to compared to its parent FractionalToMapped(0.5), //relativeSizeX: the relative x size this element should be scaled to compared to its parent
@ -19,13 +17,17 @@ int main() {
false //ignoreScaling: wether this element ignores the scaling of the window, if true its size will be scaled according to the window scale false //ignoreScaling: wether this element ignores the scaling of the window, if true its size will be scaled according to the window scale
); );
window.elements.push_back(&element.rendering); RenderingElement rendering(2, 1);
window.mouseElements.push_back(&element.mouse); MouseElement mouse(window);
element.rendering.buffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}}; element.children.push_back(&rendering);
element.children.push_back(&mouse);
window.elements.push_back(&element);
rendering.buffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}};
element.UpdatePosition(window); element.UpdatePosition(window);
EventListener<MousePoint> clickListener(&element.mouse.onMouseLeftClick, [&element, &window](MousePoint point){ EventListener<MousePoint> clickListener(&mouse.onMouseLeftClick, [&mouse, &window](MousePoint point){
// Print the coordinates where the user clicked relative to the element's top left corner. // Print the coordinates where the user clicked relative to the element's top left corner.
//Mapped space //Mapped space
@ -35,7 +37,7 @@ int main() {
std::cout << std::format("Clicked on Fraction X:{} Y:{}!", MappedToFractionalBoundless(point.x), MappedToFractionalBoundless(point.y)) << std::endl; std::cout << std::format("Clicked on Fraction X:{} Y:{}!", MappedToFractionalBoundless(point.x), MappedToFractionalBoundless(point.y)) << std::endl;
// Screen space // Screen space
std::cout << std::format("Clicked on Screen X:{} Y:{}!\n", MappedToPixelBoundless(point.x, MappedToPixelBoundless(element.mouse.transform.scaled.width, window.width)), MappedToPixelBoundless(point.y, MappedToPixelBoundless(element.mouse.transform.scaled.width, window.height))) << std::endl; std::cout << std::format("Clicked on Screen X:{} Y:{}!\n", MappedToPixelBoundless(point.x, MappedToPixelBoundless(mouse.scaled.width, window.width)), MappedToPixelBoundless(point.y, MappedToPixelBoundless(mouse.scaled.width, window.height))) << std::endl;
}); });
window.Render(); window.Render();

View file

@ -27,24 +27,24 @@ import std;
using namespace Crafter; using namespace Crafter;
MouseElement::MouseElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : transform(this, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) { MouseElement::MouseElement(WindowMouse& window, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
window.mouseElements.push_back(this);
} }
MouseElement::MouseElement(Transform transform) : transform(transform) { MouseElement::MouseElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
} }
void MouseElement::UpdatePosition(Window& window) { void MouseElement::UpdatePosition(Window& window) {
window.ScaleMouse(transform); window.ScaleMouse(*this);
for(Transform* child : transform.children) { for(Transform* child : children) {
reinterpret_cast<MouseElement*>(child->element)->UpdatePosition(window, transform); child->UpdatePosition(window, *this);
} }
} }
void MouseElement::UpdatePosition(Window& window, Transform& parent) { void MouseElement::UpdatePosition(Window& window, Transform& parent) {
window.ScaleMouse(transform, parent); window.ScaleMouse(*this, parent);
for(Transform* child : transform.children) { for(Transform* child : children) {
reinterpret_cast<MouseElement*>(child->element)->UpdatePosition(window, transform); child->UpdatePosition(window, *this);
} }
} }

View file

@ -31,30 +31,27 @@ import std;
using namespace Crafter; using namespace Crafter;
RenderingElement::RenderingElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : transform(this, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) { RenderingElement::RenderingElement() : Transform() {
} }
RenderingElement::RenderingElement(std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : bufferWidth(bufferWidth), bufferHeight(bufferHeight), buffer(bufferWidth*bufferHeight), transform(this, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
RenderingElement::RenderingElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
} }
RenderingElement::RenderingElement(const std::string_view imagePath, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : transform(this, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) { RenderingElement::RenderingElement(std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : bufferWidth(bufferWidth), bufferHeight(bufferHeight), buffer(bufferWidth*bufferHeight), Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
}
RenderingElement::RenderingElement(const std::string_view imagePath, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
RenderImage(imagePath); RenderImage(imagePath);
} }
RenderingElement::RenderingElement(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : transform(this, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) { RenderingElement::RenderingElement(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
RenderText(text, size, pixel, font); RenderText(text, size, pixel, font);
} }
RenderingElement::RenderingElement(Transform transform) : transform(transform) {
}
RenderingElement::RenderingElement(Transform transform, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight) : transform(transform), bufferWidth(bufferWidth), bufferHeight(bufferHeight), buffer(bufferWidth*bufferHeight) {
}
void RenderingElement::ResizeBuffer(std::uint_fast32_t width, std::uint_fast32_t height) { void RenderingElement::ResizeBuffer(std::uint_fast32_t width, std::uint_fast32_t height) {
this->bufferWidth = width; this->bufferWidth = width;
this->bufferHeight = height; this->bufferHeight = height;
@ -138,19 +135,19 @@ void RenderingElement::CopyNearestNeighbour(Pixel_BU8_GU8_RU8_AU8* dst, std::uin
} }
void RenderingElement::UpdatePosition(Window& window) { void RenderingElement::UpdatePosition(Window& window) {
window.ScaleElement(transform); window.ScaleElement(*this);
scaled.resize(transform.scaled.width * transform.scaled.height); bufferScaled.resize(scaled.width * scaled.height);
CopyNearestNeighbour(scaled.data(), transform.scaled.width, transform.scaled.height); CopyNearestNeighbour(bufferScaled.data(), scaled.width, scaled.height);
for(Transform* child : transform.children) { for(Transform* child : children) {
reinterpret_cast<RenderingElement*>(child->element)->UpdatePosition(window, transform); child->UpdatePosition(window, *this);
} }
} }
void RenderingElement::UpdatePosition(Window& window, Transform& parent) { void RenderingElement::UpdatePosition(Window& window, Transform& parent) {
window.ScaleElement(transform, parent); window.ScaleElement(*this, parent);
scaled.resize(transform.scaled.width * transform.scaled.height); bufferScaled.resize(scaled.width * scaled.height);
CopyNearestNeighbour(scaled.data(), transform.scaled.width, transform.scaled.height); CopyNearestNeighbour(bufferScaled.data(), scaled.width, scaled.height);
for(Transform* child : transform.children) { for(Transform* child : children) {
reinterpret_cast<RenderingElement*>(child->element)->UpdatePosition(window, transform); child->UpdatePosition(window, *this);
} }
} }

View file

@ -18,8 +18,8 @@ License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
module Crafter.Graphics:UiElement_impl; module Crafter.Graphics:Transform_impl;
import :UiElement; import :Transform;
import :Window; import :Window;
import :Types; import :Types;
import :Font; import :Font;
@ -27,6 +27,20 @@ import std;
using namespace Crafter; using namespace Crafter;
Transform::Transform(void* element, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : element(element), anchorX(anchorX), anchorY(anchorY), relativeWidth(relativeWidth), relativeHeight(relativeHeight), anchorOffsetX(anchorOffsetX), anchorOffsetY(anchorOffsetY), z(z), ignoreScaling(ignoreScaling) { Transform::Transform(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : anchorX(anchorX), anchorY(anchorY), relativeWidth(relativeWidth), relativeHeight(relativeHeight), anchorOffsetX(anchorOffsetX), anchorOffsetY(anchorOffsetY), z(z), ignoreScaling(ignoreScaling) {
} }
void Transform::UpdatePosition(Window& window) {
window.ScaleElement(*this);
for(Transform* child : children) {
child->UpdatePosition(window, *this);
}
}
void Transform::UpdatePosition(Window& window, Transform& parent) {
window.ScaleElement(*this, parent);
for(Transform* child : children) {
child->UpdatePosition(window, *this);
}
}

View file

@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
module Crafter.Graphics:Window_impl; module Crafter.Graphics:Window_impl;
import :Window; import :Window;
import :UiElement; import :Transform;
import std; import std;
using namespace Crafter; using namespace Crafter;

View file

@ -39,7 +39,8 @@ module;
module Crafter.Graphics:Window_wayland_impl; module Crafter.Graphics:Window_wayland_impl;
import :Window; import :Window;
import :UiElement; import :RenderingElement;
import :MouseElement;
import std; import std;
import :Types; import :Types;
import :Shm; import :Shm;
@ -135,12 +136,14 @@ void WindowWayland::StartSync() {
void RenderElement(RenderingElement* element, WindowWayland* window) { void RenderElement(Transform* transform, WindowWayland* window) {
for (std::int_fast32_t x = element->transform.scaled.x; x - element->transform.scaled.x < element->transform.scaled.width; x++) { RenderingElement* element = dynamic_cast<RenderingElement*>(transform);
for (std::int_fast32_t y = element->transform.scaled.y; y - element->transform.scaled.y < element->transform.scaled.height; y++) { if(element) {
for (std::int_fast32_t x = element->scaled.x; x - element->scaled.x < element->scaled.width; x++) {
for (std::int_fast32_t y = element->scaled.y; y - element->scaled.y < element->scaled.height; y++) {
if (x >= 0 && x < window->width && y >= 0 && y < window->height) { if (x >= 0 && x < window->width && y >= 0 && y < window->height) {
Pixel_BU8_GU8_RU8_AU8& dst = window->framebuffer[y * window->width + x]; Pixel_BU8_GU8_RU8_AU8& dst = window->framebuffer[y * window->width + x];
const Pixel_BU8_GU8_RU8_AU8& src = element->scaled[(y - element->transform.scaled.y) * element->transform.scaled.width + (x - element->transform.scaled.x)]; const Pixel_BU8_GU8_RU8_AU8& src = element->bufferScaled[(y - element->scaled.y) * element->scaled.width + (x - element->scaled.x)];
float srcA = src.a / 255.0f; float srcA = src.a / 255.0f;
float dstA = dst.a / 255.0f; float dstA = dst.a / 255.0f;
@ -157,14 +160,16 @@ void RenderElement(RenderingElement* element, WindowWayland* window) {
} }
} }
} }
std::sort(element->transform.children.begin(), element->transform.children.end(), [](Transform* a, Transform* b){ return a->z < b->z; }); }
for(Transform* child : element->transform.children) {
RenderElement(reinterpret_cast<RenderingElement*>(child->element), window); std::sort(transform->children.begin(), transform->children.end(), [](Transform* a, Transform* b){ return a->z < b->z; });
for(Transform* child : transform->children) {
RenderElement(child, window);
} }
} }
void WindowWayland::Render() { void WindowWayland::Render() {
std::sort(elements.begin(), elements.end(), [](RenderingElement* a, RenderingElement* b){ return a->transform.z < b->transform.z; }); std::sort(elements.begin(), elements.end(), [](Transform* a, Transform* b){ return a->z < b->z; });
for (std::uint_fast32_t x = 0; x < width; x++) { for (std::uint_fast32_t x = 0; x < width; x++) {
for (std::uint_fast32_t y = 0; y - height; y++) { for (std::uint_fast32_t y = 0; y - height; y++) {
@ -172,8 +177,8 @@ void WindowWayland::Render() {
} }
} }
for(RenderingElement* element : elements) { for(Transform* child : elements) {
RenderElement(element, this); RenderElement(child, this);
} }
wl_surface_attach(surface, buffer, 0, 0); wl_surface_attach(surface, buffer, 0, 0);
@ -261,16 +266,16 @@ void WindowWayland::pointer_handle_button(void* data, wl_pointer* pointer, std::
window->mouseLeftHeld = true; window->mouseLeftHeld = true;
window->onMouseLeftClick.Invoke(window->currentMousePos); window->onMouseLeftClick.Invoke(window->currentMousePos);
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(window->currentMousePos.x >= element->transform.scaled.x && window->currentMousePos.x <= element->transform.scaled.x+element->transform.scaled.width && window->currentMousePos.y > element->transform.scaled.y && window->currentMousePos.y < element->transform.scaled.y+element->transform.scaled.height) { if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) {
element->onMouseLeftClick.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->transform.scaled.x) / element->transform.scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->transform.scaled.y) / element->transform.scaled.height)}); element->onMouseLeftClick.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.height)});
} }
} }
} else { } else {
window->mouseLeftHeld = false; window->mouseLeftHeld = false;
window->onMouseLeftRelease.Invoke(window->currentMousePos); window->onMouseLeftRelease.Invoke(window->currentMousePos);
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(window->currentMousePos.x >= element->transform.scaled.x && window->currentMousePos.x <= element->transform.scaled.x+element->transform.scaled.width && window->currentMousePos.y > element->transform.scaled.y && window->currentMousePos.y < element->transform.scaled.y+element->transform.scaled.height) { if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) {
element->onMouseLeftRelease.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->transform.scaled.x) / element->transform.scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->transform.scaled.y) / element->transform.scaled.height)}); element->onMouseLeftRelease.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.height)});
} }
} }
} }
@ -279,16 +284,16 @@ void WindowWayland::pointer_handle_button(void* data, wl_pointer* pointer, std::
window->mouseRightHeld = true; window->mouseRightHeld = true;
window->onMouseRightClick.Invoke(window->currentMousePos); window->onMouseRightClick.Invoke(window->currentMousePos);
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(window->currentMousePos.x >= element->transform.scaled.x && window->currentMousePos.x <= element->transform.scaled.x+element->transform.scaled.width && window->currentMousePos.y > element->transform.scaled.y && window->currentMousePos.y < element->transform.scaled.y+element->transform.scaled.height) { if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) {
element->onMouseRightClick.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->transform.scaled.x) / element->transform.scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->transform.scaled.y) / element->transform.scaled.height)}); element->onMouseRightClick.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.height)});
} }
} }
} else { } else {
window->mouseRightHeld = true; window->mouseRightHeld = true;
window->onMouseRightRelease.Invoke(window->currentMousePos); window->onMouseRightRelease.Invoke(window->currentMousePos);
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(window->currentMousePos.x >= element->transform.scaled.x && window->currentMousePos.x <= element->transform.scaled.x+element->transform.scaled.width && window->currentMousePos.y > element->transform.scaled.y && window->currentMousePos.y < element->transform.scaled.y+element->transform.scaled.height) { if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) {
element->onMouseRightRelease.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->transform.scaled.x) / element->transform.scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->transform.scaled.y) / element->transform.scaled.height)}); element->onMouseRightRelease.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.height)});
} }
} }
} }
@ -303,13 +308,13 @@ void WindowWayland::PointerListenerHandleMotion(void* data, wl_pointer* wl_point
window->mouseDelta = {window->currentMousePos.x-window->lastMousePos.x, window->currentMousePos.y-window->lastMousePos.y}; window->mouseDelta = {window->currentMousePos.x-window->lastMousePos.x, window->currentMousePos.y-window->lastMousePos.y};
window->onMouseMove.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); window->onMouseMove.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta});
for(MouseElement* element : window->mouseElements) { for(MouseElement* element : window->mouseElements) {
if(window->currentMousePos.x >= element->transform.scaled.x && window->currentMousePos.x <= element->transform.scaled.x+element->transform.scaled.width && window->currentMousePos.y > element->transform.scaled.y && window->currentMousePos.y < element->transform.scaled.y+element->transform.scaled.height) { if(window->currentMousePos.x >= element->scaled.x && window->currentMousePos.x <= element->scaled.x+element->scaled.width && window->currentMousePos.y > element->scaled.y && window->currentMousePos.y < element->scaled.y+element->scaled.height) {
element->onMouseMove.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->transform.scaled.x) / element->transform.scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->transform.scaled.y) / element->transform.scaled.height)}); element->onMouseMove.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.height)});
if(!(window->lastMousePos.x >= element->transform.scaled.x && window->lastMousePos.x <= element->transform.scaled.x+element->transform.scaled.width && window->lastMousePos.y > element->transform.scaled.y && window->lastMousePos.y < element->transform.scaled.y+element->transform.scaled.height)) { if(!(window->lastMousePos.x >= element->scaled.x && window->lastMousePos.x <= element->scaled.x+element->scaled.width && window->lastMousePos.y > element->scaled.y && window->lastMousePos.y < element->scaled.y+element->scaled.height)) {
element->onMouseEnter.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->transform.scaled.x) / element->transform.scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->transform.scaled.y) / element->transform.scaled.height)}); element->onMouseEnter.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.height)});
} }
} else if(window->lastMousePos.x >= element->transform.scaled.x && window->lastMousePos.x <= element->transform.scaled.x+element->transform.scaled.width && window->lastMousePos.y > element->transform.scaled.y && window->lastMousePos.y < element->transform.scaled.y+element->transform.scaled.height) { } else if(window->lastMousePos.x >= element->scaled.x && window->lastMousePos.x <= element->scaled.x+element->scaled.width && window->lastMousePos.y > element->scaled.y && window->lastMousePos.y < element->scaled.y+element->scaled.height) {
element->onMouseLeave.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->transform.scaled.x) / element->transform.scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->transform.scaled.y) / element->transform.scaled.height)}); element->onMouseLeave.Invoke({FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.x - element->scaled.x) / element->scaled.width), FractionalToMappedBoundless(static_cast<double>(window->currentMousePos.y - element->scaled.y) / element->scaled.height)});
} }
} }
} }

View file

@ -25,9 +25,9 @@ import :Transform;
export namespace Crafter { export namespace Crafter {
class Window; class Window;
class MouseElement { class WindowMouse;
class MouseElement : public Transform {
public: public:
Transform transform;
Event<MouseMoveEvent> onMouseMove; Event<MouseMoveEvent> onMouseMove;
Event<MouseMoveEvent> onMouseEnter; Event<MouseMoveEvent> onMouseEnter;
Event<MouseMoveEvent> onMouseLeave; Event<MouseMoveEvent> onMouseLeave;
@ -38,11 +38,11 @@ export namespace Crafter {
Event<MousePoint> onMouseRightRelease; Event<MousePoint> onMouseRightRelease;
Event<MousePoint> onMouseLeftRelease; Event<MousePoint> onMouseLeftRelease;
MouseElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false); MouseElement(WindowMouse& window, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
MouseElement(Transform transform); MouseElement(std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
MouseElement(MouseElement&) = delete; MouseElement(MouseElement&) = delete;
MouseElement& operator=(MouseElement&) = delete; MouseElement& operator=(MouseElement&) = delete;
void UpdatePosition(Window& window); void UpdatePosition(Window& window) override;
void UpdatePosition(Window& window, Transform& parent); void UpdatePosition(Window& window, Transform& parent) override;
}; };
} }

View file

@ -25,20 +25,18 @@ import :Types;
export namespace Crafter { export namespace Crafter {
class Window; class Window;
class Font; class Font;
class RenderingElement { class RenderingElement : public Transform {
public: public:
Transform transform;
std::vector<Pixel_BU8_GU8_RU8_AU8> buffer; std::vector<Pixel_BU8_GU8_RU8_AU8> buffer;
std::vector<Pixel_BU8_GU8_RU8_AU8> scaled; std::vector<Pixel_BU8_GU8_RU8_AU8> bufferScaled;
std::uint_fast32_t bufferWidth; std::uint_fast32_t bufferWidth;
std::uint_fast32_t bufferHeight; std::uint_fast32_t bufferHeight;
RenderingElement(Transform transform); RenderingElement();
RenderingElement(Transform transform, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight); RenderingElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling);
RenderingElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false); RenderingElement(std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
RenderingElement(std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false); RenderingElement(const std::string_view imagePath, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
RenderingElement(const std::string_view imagePath, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false); RenderingElement(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
RenderingElement(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
RenderingElement(RenderingElement&) = delete; RenderingElement(RenderingElement&) = delete;
RenderingElement& operator=(RenderingElement&) = delete; RenderingElement& operator=(RenderingElement&) = delete;
@ -46,7 +44,7 @@ export namespace Crafter {
void CopyNearestNeighbour(Pixel_BU8_GU8_RU8_AU8* dst, std::uint_fast32_t dstWidth, std::uint_fast32_t dstHeight) const; void CopyNearestNeighbour(Pixel_BU8_GU8_RU8_AU8* dst, std::uint_fast32_t dstWidth, std::uint_fast32_t dstHeight) const;
void RenderText(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font); void RenderText(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font);
void RenderImage(const std::string_view path); void RenderImage(const std::string_view path);
void UpdatePosition(Window& window); void UpdatePosition(Window& window) override;
void UpdatePosition(Window& window, Transform& parent); void UpdatePosition(Window& window, Transform& parent) override;
}; };
} }

View file

@ -22,9 +22,9 @@ import std;
import :Types; import :Types;
export namespace Crafter { export namespace Crafter {
class Window;
class Transform { class Transform {
public: public:
void* element;
std::int_fast32_t z; std::int_fast32_t z;
std::int_fast32_t anchorX; std::int_fast32_t anchorX;
std::int_fast32_t anchorY; std::int_fast32_t anchorY;
@ -35,6 +35,11 @@ export namespace Crafter {
bool ignoreScaling; bool ignoreScaling;
ScaleData scaled; ScaleData scaled;
std::vector<Transform*> children; std::vector<Transform*> children;
Transform(void* element, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false); Transform(std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
Transform(Transform&) = delete;
Transform& operator=(Transform&) = delete;
virtual ~Transform() = default;
virtual void UpdatePosition(Window& window);
virtual void UpdatePosition(Window& window, Transform& parent);
}; };
} }

View file

@ -1,44 +0,0 @@
/*
Crafter®.Graphics
Copyright (C) 2025 Catcrafts®
catcrafts.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 3.0 as published by the Free Software Foundation;
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
export module Crafter.Graphics:UiElement;
import std;
import Crafter.Event;
import :Types;
import :Transform;
import :RenderingElement;
import :MouseElement;
export namespace Crafter {
// Combined UI element that can have both rendering and interaction
class RenderingMouseElement {
public:
RenderingElement rendering;
MouseElement mouse;
RenderingMouseElement(const std::string_view imagePath, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
RenderingMouseElement(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
RenderingMouseElement(std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
RenderingMouseElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
RenderingMouseElement(Transform transform, Transform mouseTransform);
RenderingMouseElement(RenderingMouseElement&) = delete;
RenderingMouseElement& operator=(RenderingMouseElement&) = delete;
void UpdatePosition(Window& window);
void UpdatePosition(Window& window, Transform& parent);
};
}

View file

@ -50,6 +50,7 @@ export namespace Crafter {
std::uint_fast32_t width; std::uint_fast32_t width;
std::uint_fast32_t height; std::uint_fast32_t height;
std::chrono::time_point<std::chrono::high_resolution_clock> lastFrameBegin; std::chrono::time_point<std::chrono::high_resolution_clock> lastFrameBegin;
std::vector<Transform*> elements;
Event<void> onClose; Event<void> onClose;
Event<FrameTime> onUpdate; Event<FrameTime> onUpdate;
bool open = true; bool open = true;
@ -126,7 +127,6 @@ export namespace Crafter {
class WindowWayland final : public WindowKeyboard, public WindowMouse, public WindowFramebuffer, public WindowTitle { class WindowWayland final : public WindowKeyboard, public WindowMouse, public WindowFramebuffer, public WindowTitle {
public: public:
Pixel_BU8_GU8_RU8_AU8* framebuffer = nullptr; Pixel_BU8_GU8_RU8_AU8* framebuffer = nullptr;
std::vector<RenderingElement*> elements;
WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height); WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height);
WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height, const std::string_view title); WindowWayland(std::uint_fast32_t width, std::uint_fast32_t height, const std::string_view title);
~WindowWayland(); ~WindowWayland();

View file

@ -24,7 +24,6 @@ export import :Window;
export import :Transform; export import :Transform;
export import :RenderingElement; export import :RenderingElement;
export import :MouseElement; export import :MouseElement;
export import :UiElement;
export import :Types; export import :Types;
export import :Font; export import :Font;
export import :Shm; export import :Shm;

View file

@ -3,8 +3,8 @@
"configurations": [ "configurations": [
{ {
"name": "base", "name": "base",
"implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-UiElement", "implementations/Crafter.Graphics-Window", "implementations/Crafter.Graphics-RenderingElement", "implementations/Crafter.Graphics-MouseElement", "implementations/Crafter.Graphics-Transform"], "implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-Window", "implementations/Crafter.Graphics-RenderingElement", "implementations/Crafter.Graphics-MouseElement", "implementations/Crafter.Graphics-Transform"],
"interfaces": ["interfaces/Crafter.Graphics-Window", "interfaces/Crafter.Graphics", "interfaces/Crafter.Graphics-Types", "interfaces/Crafter.Graphics-Font", "interfaces/Crafter.Graphics-Shm", "interfaces/Crafter.Graphics-UiElement", "interfaces/Crafter.Graphics-Animation", "interfaces/Crafter.Graphics-RenderingElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform"], "interfaces": ["interfaces/Crafter.Graphics-Window", "interfaces/Crafter.Graphics", "interfaces/Crafter.Graphics-Types", "interfaces/Crafter.Graphics-Font", "interfaces/Crafter.Graphics-Shm", "interfaces/Crafter.Graphics-Animation", "interfaces/Crafter.Graphics-RenderingElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform"],
"type": "library" "type": "library"
}, },
{ {