Fixed file picker and scroll area clipping region
This commit is contained in:
parent
b95adcf0f0
commit
10217e97f4
12 changed files with 69 additions and 23 deletions
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
std::filesystem::path force_extension_on_path(std::filesystem::path p, const std::string& extensions) {
|
||||
std::vector<std::string> extensionList = split_string_by_token(extensions, ";");
|
||||
std::erase(extensionList, "*");
|
||||
if(extensionList.empty())
|
||||
return p;
|
||||
for(std::string& s : extensionList) {
|
||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||
s.insert(0, ".");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -477,6 +477,7 @@ void TextBox::clear_text() {
|
|||
paragraphs.clear();
|
||||
tStyleMods.clear();
|
||||
paragraphs.emplace_back();
|
||||
needsRebuild = true;
|
||||
}
|
||||
|
||||
void TextBox::set_string(const std::string& str) {
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ void Toolbar::open_file_selector(const std::string& filePickerName, const std::v
|
|||
filePicker.filePickerWindowName = filePickerName;
|
||||
filePicker.postSelectionFunc = postSelectionFunc;
|
||||
filePicker.fileName = "";
|
||||
filePicker.isSaving = isSaving;
|
||||
file_picker_gui_refresh_entries();
|
||||
}
|
||||
}
|
||||
|
|
@ -299,7 +300,7 @@ void Toolbar::close_popup_gui() {
|
|||
});
|
||||
center_obstructing_window_gui("Close program popup GUI", CLAY_SIZING_FIT(0), CLAY_SIZING_FIT(0, 600), [&] {
|
||||
text_label(gui, "Files may contain unsaved changes");
|
||||
gui.element<ScrollArea>("close file popup gui scroll area", ScrollArea::Options{
|
||||
gui.clipping_element<ScrollArea>("close file popup gui scroll area", ScrollArea::Options{
|
||||
.scrollVertical = true,
|
||||
.clipVertical = true,
|
||||
.showScrollbarY = true,
|
||||
|
|
@ -1680,7 +1681,7 @@ void Toolbar::general_settings_inner_gui() {
|
|||
}
|
||||
}) {
|
||||
auto general_scroll_area = [&](const char* id, const std::function<void()>& innerContent) {
|
||||
gui.element<ScrollArea>("general settings scroll area", ScrollArea::Options{
|
||||
gui.clipping_element<ScrollArea>("general settings scroll area", ScrollArea::Options{
|
||||
.scrollVertical = true,
|
||||
.clipHorizontal = false,
|
||||
.clipVertical = true,
|
||||
|
|
@ -1925,7 +1926,7 @@ void Toolbar::about_menu_inner_gui() {
|
|||
.layoutDirection = CLAY_TOP_TO_BOTTOM
|
||||
}
|
||||
}) {
|
||||
gui.element<ScrollArea>("About Menu Selector Scroll Area", ScrollArea::Options{
|
||||
gui.clipping_element<ScrollArea>("About Menu Selector Scroll Area", ScrollArea::Options{
|
||||
.scrollVertical = true,
|
||||
.clipHorizontal = false,
|
||||
.clipVertical = true,
|
||||
|
|
@ -1968,7 +1969,7 @@ void Toolbar::about_menu_inner_gui() {
|
|||
}
|
||||
});
|
||||
|
||||
gui.element<ScrollArea>("About Menu Text Scroll Area", ScrollArea::Options{
|
||||
gui.clipping_element<ScrollArea>("About Menu Text Scroll Area", ScrollArea::Options{
|
||||
.scrollVertical = true,
|
||||
.clipHorizontal = false,
|
||||
.clipVertical = true,
|
||||
|
|
@ -2060,7 +2061,9 @@ void Toolbar::file_picker_gui_refresh_entries() {
|
|||
void Toolbar::file_picker_gui_done() {
|
||||
if(!filePicker.fileName.empty()) {
|
||||
std::filesystem::path pathToRet = filePicker.currentSearchPath / filePicker.fileName;
|
||||
filePicker.postSelectionFunc(force_extension_on_path(pathToRet, filePicker.extensionFiltersComplete[filePicker.extensionSelected].extensions), filePicker.extensionFiltersComplete[filePicker.extensionSelected]);
|
||||
if(filePicker.isSaving)
|
||||
pathToRet = force_extension_on_path(pathToRet, filePicker.extensionFiltersComplete[filePicker.extensionSelected].extensions);
|
||||
filePicker.postSelectionFunc(pathToRet, filePicker.extensionFiltersComplete[filePicker.extensionSelected]);
|
||||
}
|
||||
filePicker.isOpen = false;
|
||||
}
|
||||
|
|
@ -2127,8 +2130,10 @@ void Toolbar::file_picker_gui() {
|
|||
if(mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down) {
|
||||
gui.set_post_callback_func([&, button, selectedEntry, entry] {
|
||||
if(selectedEntry && button.clicks >= 2) {
|
||||
if(std::filesystem::is_directory(entry))
|
||||
if(std::filesystem::is_directory(entry)) {
|
||||
filePicker.currentSearchPath = entry;
|
||||
file_picker_gui_refresh_entries();
|
||||
}
|
||||
else if(std::filesystem::is_regular_file(entry))
|
||||
file_picker_gui_done();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,7 +193,8 @@ class Toolbar {
|
|||
std::vector<std::filesystem::path> entries;
|
||||
std::filesystem::path currentSearchPath;
|
||||
std::filesystem::path currentSelectedPath;
|
||||
std::string fileName;
|
||||
std::string fileName = "";
|
||||
bool isSaving = false;
|
||||
size_t extensionSelected;
|
||||
OpenFileSelectorCallback postSelectionFunc;
|
||||
} filePicker;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue