Fixed file picker and scroll area clipping region

This commit is contained in:
Yousef Khadadeh 2026-04-01 21:49:44 +03:00
parent b95adcf0f0
commit 10217e97f4
12 changed files with 69 additions and 23 deletions

View file

@ -4,7 +4,7 @@
namespace GUIStuff { namespace ElementHelpers {
void scroll_area_many_entries(GUIManager& gui, const char* id, const ScrollBarManyEntriesOptions& options) {
gui.element<ScrollArea>(id, ScrollArea::Options{
gui.clipping_element<ScrollArea>(id, ScrollArea::Options{
.scrollVertical = true,
.clipHorizontal = options.clipHorizontal,
.clipVertical = true,

View file

@ -20,6 +20,10 @@ namespace GUIStuff {
boundingBox = std::nullopt;
}
void Element::set_parent_clipping_region(const std::optional<SCollision::AABB<float>>& bb) {
parentClippingRegion = bb;
}
const std::optional<SCollision::AABB<float>>& Element::get_bb() const {
return boundingBox;
}
@ -27,7 +31,8 @@ namespace GUIStuff {
bool Element::collides_with_point(const Vector2f& p) const {
if(!boundingBox.has_value())
return false;
return SCollision::collide(p, boundingBox.value());
bool inClippingRegion = !parentClippingRegion.has_value() || SCollision::collide(p, parentClippingRegion.value());
return inClippingRegion && SCollision::collide(p, boundingBox.value());
}
SCollision::AABB<float> Element::get_bb_from_command(Clay_RenderCommand* command) {

View file

@ -12,6 +12,7 @@ namespace GUIStuff {
virtual bool collides_with_point(const Vector2f& p) const;
void set_bounding_box_from_elem_data(const Clay_ElementData& elemData);
void set_parent_clipping_region(const std::optional<SCollision::AABB<float>>& bb);
const std::optional<SCollision::AABB<float>>& get_bb() const;
virtual ~Element() = default;
@ -27,6 +28,7 @@ namespace GUIStuff {
protected:
static SCollision::AABB<float> get_bb_from_command(Clay_RenderCommand* command);
std::optional<SCollision::AABB<float>> boundingBox;
std::optional<SCollision::AABB<float>> parentClippingRegion;
GUIManager& gui;
};

View file

@ -69,7 +69,7 @@ bool SelectableButton::input_mouse_button_callback(const InputManager::MouseButt
isHovering = mouseHovering;
isHeld = isHovering && button.button == InputManager::MouseButton::LEFT && button.down;
if(isHeld) {
gui.set_post_callback_func([&]{onClick();});
gui.set_post_callback_func([&]{ if(onClick) onClick(); });
gui.set_to_layout();
}
else if(isHovering != oldIsHovering || isHeld != oldIsHeld)

View file

@ -31,7 +31,8 @@ template <typename T> class TextBox : public Element {
virtual void input_key_callback(const InputManager::KeyCallbackArgs& key) override;
~TextBox();
private:
void init_textbox(UpdateInputData& io, bool forceTextUpdate);
void init_textbox(UpdateInputData& io);
void reset_textbox_text();
bool update_data();
std::optional<T> oldData;

View file

@ -8,7 +8,10 @@ template <typename T> TextBox<T>::TextBox(GUIManager& gui): Element(gui) {}
template <typename T> void TextBox<T>::layout(const Clay_ElementId& id, const TextBoxData<T>& userInfo) {
auto& io = gui.io;
this->userInfo = userInfo;
init_textbox(io, false);
init_textbox(io);
if(!oldData.has_value() || oldData.value() != *userInfo.data)
reset_textbox_text();
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(static_cast<float>(io.fontSize * 2)), .height = CLAY_SIZING_FIXED(static_cast<float>(io.fontSize * 1.25f))}
@ -73,7 +76,7 @@ template <typename T> bool TextBox<T>::input_mouse_button_callback(const InputMa
gui.io.input->remove_rich_text_box_input(textbox);
if(update_data())
gui.set_post_callback_func_high_priority(userInfo.onEdit);
init_textbox(gui.io, true);
reset_textbox_text();
isSelected = false;
}
}
@ -96,12 +99,12 @@ template <typename T> void TextBox<T>::input_key_callback(const InputManager::Ke
gui.set_post_callback_func_high_priority([&, success] {
if(success && userInfo.onEdit) userInfo.onEdit();
if(userInfo.onEnter) userInfo.onEnter();
init_textbox(gui.io, true);
reset_textbox_text();
});
}
}
template <typename T> void TextBox<T>::init_textbox(UpdateInputData& io, bool forceTextUpdate) {
template <typename T> void TextBox<T>::init_textbox(UpdateInputData& io) {
if(!textbox) {
textbox = std::make_shared<RichText::TextBox>();
textbox->set_width(std::numeric_limits<float>::max());
@ -111,11 +114,6 @@ template <typename T> void TextBox<T>::init_textbox(UpdateInputData& io, bool fo
rect = std::make_shared<SCollision::AABB<float>>();
}
if(forceTextUpdate || !oldData.has_value() || oldData.value() != *userInfo.data) {
textbox->clear_text();
cur->pos = cur->selectionBeginPos = cur->selectionEndPos = textbox->insert({0, 0}, userInfo.toStr(*userInfo.data));
}
textbox->onUserTextEdit = [&] {
if(userInfo.immutable)
cur->pos = cur->selectionBeginPos = cur->selectionEndPos = textbox->insert({0, 0}, userInfo.toStr(*userInfo.data));
@ -126,6 +124,11 @@ template <typename T> void TextBox<T>::init_textbox(UpdateInputData& io, bool fo
};
}
template <typename T> void TextBox<T>::reset_textbox_text() {
textbox->set_string(userInfo.toStr(*userInfo.data));
cur->pos = cur->selectionBeginPos = cur->selectionEndPos = {0, 0};
}
template <typename T> bool TextBox<T>::update_data() {
std::optional<T> dataToAssign = userInfo.fromStr(textbox->get_string());
if(dataToAssign.has_value()) {

View file

@ -243,7 +243,7 @@ void GUIManager::layout_if_necessary() {
}
void GUIManager::layout() {
constexpr int LAYOUT_RUN_COUNT = 3;
constexpr int LAYOUT_RUN_COUNT = 4;
for(int i = 0; i < LAYOUT_RUN_COUNT; i++)
single_layout_run();
}
@ -297,10 +297,13 @@ void GUIManager::new_id(int64_t id, const std::function<void()>& f) {
}
void GUIManager::set_z_index(int16_t z, const std::function<void()>& f) {
auto oldClippingRegion = clippingRegion;
clippingRegion = std::nullopt;
int16_t oldZIndex = zIndex;
zIndex = z;
f();
zIndex = oldZIndex;
clippingRegion = oldClippingRegion;
}
int16_t GUIManager::get_z_index() {
@ -333,8 +336,8 @@ void GUIManager::run_post_callback_func() {
if(postCallbackFunc) {
postCallbackFunc();
postCallbackFunc = nullptr;
postCallbackFuncIsHighPriority = false;
}
postCallbackFuncIsHighPriority = false;
}
bool GUIManager::cursor_obstructed() const {
@ -366,7 +369,7 @@ void GUIManager::mouse_callback(const Vector2f& mousePos, const std::function<vo
cursorObstructed = false;
int16_t zIndexObstructed = 0;
for(ElementContainer* e : orderedElements) {
if((!cursorObstructed || zIndexObstructed == e->elem->zIndex) && e->elem->get_bb().has_value() && SCollision::collide(e->elem->get_bb().value(), mousePos)) {
if((!cursorObstructed || zIndexObstructed == e->elem->zIndex) && e->elem->collides_with_point(mousePos)) {
zIndexObstructed = e->elem->zIndex;
cursorObstructed = true;
f(e, true);

View file

@ -39,12 +39,32 @@ class GUIManager {
push_id(id);
ElementType* elem = insert_element<ElementType>();
Clay_ElementId clayId = strArena.elem_id_from_id_stack(idStack);
elem->set_parent_clipping_region(clippingRegion);
elem->set_bounding_box_from_elem_data(Clay_GetElementData(clayId));
elem->layout(clayId, a...);
pop_id();
return elem;
}
template <typename ElementType, typename... Args> ElementType* clipping_element(const char* id, const Args&... a) {
push_id(id);
ElementType* elem = insert_element<ElementType>();
Clay_ElementId clayId = strArena.elem_id_from_id_stack(idStack);
elem->set_bounding_box_from_elem_data(Clay_GetElementData(clayId));
elem->set_parent_clipping_region(clippingRegion);
auto oldClippingRegion = clippingRegion;
if(elem->get_bb().has_value()) {
if(clippingRegion.has_value())
clippingRegion = clippingRegion.value().get_intersection_between_aabbs(elem->get_bb().value());
else
clippingRegion = elem->get_bb();
}
elem->layout(clayId, a...);
clippingRegion = oldClippingRegion;
pop_id();
return elem;
}
DefaultStringArena strArena;
void input_key_callback(const InputManager::KeyCallbackArgs& key);
@ -84,6 +104,8 @@ class GUIManager {
void pop_id();
int16_t zIndex = 0;
std::optional<SCollision::AABB<float>> clippingRegion;
std::function<void()> postCallbackFunc;
bool postCallbackFuncIsHighPriority;
Clay_Context* clayInstance;