diff --git a/assets/data/icons/RemixIcon/image-add-line.svg b/assets/data/icons/RemixIcon/image-add-line.svg new file mode 100644 index 0000000..b2b670c --- /dev/null +++ b/assets/data/icons/RemixIcon/image-add-line.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 44a1573..13e3913 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -719,6 +719,8 @@ void DrawingProgram::add_file_to_canvas_by_path(const std::filesystem::path& fil CanvasComponentContainer* newContainer = new CanvasComponentContainer(world.netObjMan, CanvasComponentType::IMAGE); ImageCanvasComponent& img = static_cast(newContainer->get_comp()); newContainer->coords = world.drawData.cam.c; + if(world.main.g.gui.io.isTouchDevice) + newContainer->coords.scale_about_double(world.drawData.cam.c.from_space(dropPos), 1.0 / world.main.get_scale_and_density_factor_gui()); float imWidth = imTrueDim.x() / (imTrueDim.x() + imTrueDim.y()); float imHeight = imTrueDim.y() / (imTrueDim.x() + imTrueDim.y()); Vector2f imDim = Vector2f{world.main.window.size.x() * imWidth, world.main.window.size.x() * imHeight} * display->get_dimension_scale(); diff --git a/src/DrawingProgram/Tools/EditTools/TextBoxEditTool.cpp b/src/DrawingProgram/Tools/EditTools/TextBoxEditTool.cpp index f936054..f12ea94 100644 --- a/src/DrawingProgram/Tools/EditTools/TextBoxEditTool.cpp +++ b/src/DrawingProgram/Tools/EditTools/TextBoxEditTool.cpp @@ -404,7 +404,7 @@ void TextBoxEditTool::phone_bottom_toolbar_gui(PhoneDrawingProgramScreen& t) { gui.set_z_index(gui.get_z_index() + 1, [&] { dropdown_many_element_popup_layout(gui, "Font Picker Popup", DropDownPopupLayout{ .button = fontPickerButton, - .isOpen = &fontPickerIsOpen, + .clickAwayCallback = [&] { fontPickerIsOpen = false; }, .entrySize = {200.0f, BIG_BUTTON_SIZE}, .entryCount = FontPicker::sorted_font_list(gui).size(), .entryLayout = [&](size_t i) { diff --git a/src/DrawingProgram/Tools/ScreenshotTool.cpp b/src/DrawingProgram/Tools/ScreenshotTool.cpp index 4900753..fa4ddf1 100644 --- a/src/DrawingProgram/Tools/ScreenshotTool.cpp +++ b/src/DrawingProgram/Tools/ScreenshotTool.cpp @@ -93,7 +93,7 @@ void ScreenshotTool::gui_toolbox(Toolbar& t) { take_screenshot("a" + controls.typeSelections[screenshotConfig.selectedType], screenshotConfig.selectedType); #else // We can't actually use the extension from the callback, so we have to set the extension of choice beforehand - Toolbar::ExtensionFilter setExtensionFilter; + Screen::ExtensionFilter setExtensionFilter; switch(screenshotConfig.selectedType) { case WorldScreenshotInfo::ScreenshotType::JPG: setExtensionFilter = {"JPEG", "jpg;jpeg"}; diff --git a/src/DrawingProgram/Tools/TextBoxTool.cpp b/src/DrawingProgram/Tools/TextBoxTool.cpp index f66918b..0155f77 100644 --- a/src/DrawingProgram/Tools/TextBoxTool.cpp +++ b/src/DrawingProgram/Tools/TextBoxTool.cpp @@ -65,7 +65,7 @@ void TextBoxTool::input_mouse_button_on_canvas_callback(const InputManager::Mous newTextBox.d.editing = true; newContainer->coords = drawP.world.drawData.cam.c; if(drawP.world.main.g.gui.io.isTouchDevice) - newContainer->coords.scale_about_double(drawP.world.drawData.cam.c.from_space(startAt), 1.0 / drawP.world.main.g.final_gui_scale()); + newContainer->coords.scale_about_double(drawP.world.drawData.cam.c.from_space(startAt), 1.0 / drawP.world.main.get_scale_and_density_factor_gui()); objInfoBeingEdited = drawP.layerMan.add_component_to_layer_being_edited(newContainer); } else if(!button.down && objInfoBeingEdited) { diff --git a/src/GUIStuff/ElementHelpers/ButtonHelpers.cpp b/src/GUIStuff/ElementHelpers/ButtonHelpers.cpp index 3478507..b20ca01 100644 --- a/src/GUIStuff/ElementHelpers/ButtonHelpers.cpp +++ b/src/GUIStuff/ElementHelpers/ButtonHelpers.cpp @@ -19,6 +19,7 @@ #include "ButtonHelpers.hpp" #include "../Elements/SVGIcon.hpp" #include "../Elements/LayoutElement.hpp" +#include "Helpers/ConvertVec.hpp" #include "TextLabelHelpers.hpp" namespace GUIStuff { namespace ElementHelpers { @@ -37,7 +38,7 @@ void text_button(GUIManager& gui, const char* id, std::string_view text, const T }; CLAY_AUTO_ID({ .layout = { - .sizing = {.width = options.wide ? CLAY_SIZING_GROW(0) : CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0) }, + .sizing = {.width = options.wide ? CLAY_SIZING_GROW(0) : CLAY_SIZING_FIT(0), .height = options.growHeight ? CLAY_SIZING_GROW(0) : CLAY_SIZING_FIT(0) }, .childAlignment = {.x = options.centered ? CLAY_ALIGN_X_CENTER : CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER} } }) { diff --git a/src/GUIStuff/ElementHelpers/ButtonHelpers.hpp b/src/GUIStuff/ElementHelpers/ButtonHelpers.hpp index 1d77883..cbff7be 100644 --- a/src/GUIStuff/ElementHelpers/ButtonHelpers.hpp +++ b/src/GUIStuff/ElementHelpers/ButtonHelpers.hpp @@ -41,6 +41,7 @@ struct TextButtonOptions { bool isSelected = false; bool instantResponse = false; bool wide = false; + bool growHeight = false; bool centered = true; std::function onClick; diff --git a/src/GUIStuff/ElementHelpers/ColorPickerItemsHelpers.hpp b/src/GUIStuff/ElementHelpers/ColorPickerItemsHelpers.hpp index 4044331..d764423 100644 --- a/src/GUIStuff/ElementHelpers/ColorPickerItemsHelpers.hpp +++ b/src/GUIStuff/ElementHelpers/ColorPickerItemsHelpers.hpp @@ -18,12 +18,14 @@ #pragma once #include "../GUIManager.hpp" +#include "Helpers/ConvertVec.hpp" #include "TextBoxHelpers.hpp" #include "../Elements/ColorPicker.hpp" namespace GUIStuff { namespace ElementHelpers { struct ColorPickerItemsOptions { + bool forceAspectRatioOnColorPicker = true; bool hasAlpha = true; std::function onEdit; std::function onSelect; @@ -40,26 +42,28 @@ template void color_picker_items(GUIManager& gui, const char* id, T .layout = { .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)} }, - .aspectRatio = {1.0f} + .aspectRatio = {options.forceAspectRatioOnColorPicker ? 1.0f : 0.0f} }) { gui.element>("c", val, options.hasAlpha, ColorPickerData{ .onChange = fullOnEdit, .onHold = options.onSelect, .onRelease = options.onDeselect }); } - left_to_right_line_layout(gui, [&]() { - text_label(gui, "R"); - input_color_component_255(gui, "r", &(*val)[0], { .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); - text_label(gui, "G"); - input_color_component_255(gui, "g", &(*val)[1], { .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); - text_label(gui, "B"); - input_color_component_255(gui, "b", &(*val)[2], { .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); - if(options.hasAlpha) { - text_label(gui, "A"); - input_color_component_255(gui, "a", &(*val)[3], { .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); - } - }); - left_to_right_line_layout(gui, [&]() { - text_label(gui, "Hex"); - input_color_hex(gui, "h", val, { .hasAlpha = options.hasAlpha, .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); - }); + if(!gui.io.isTouchDevice) { + left_to_right_line_layout(gui, [&]() { + text_label(gui, "R"); + input_color_component_255(gui, "r", &(*val)[0], { .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); + text_label(gui, "G"); + input_color_component_255(gui, "g", &(*val)[1], { .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); + text_label(gui, "B"); + input_color_component_255(gui, "b", &(*val)[2], { .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); + if(options.hasAlpha) { + text_label(gui, "A"); + input_color_component_255(gui, "a", &(*val)[3], { .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); + } + }); + left_to_right_line_layout(gui, [&]() { + text_label(gui, "Hex"); + input_color_hex(gui, "h", val, { .hasAlpha = options.hasAlpha, .onEdit = fullOnEdit, .onSelect = options.onSelect, .onDeselect = options.onDeselect }); + }); + } }); } diff --git a/src/GUIStuff/ElementHelpers/LayoutHelpers.cpp b/src/GUIStuff/ElementHelpers/LayoutHelpers.cpp index 9c9fac5..c72e1f3 100644 --- a/src/GUIStuff/ElementHelpers/LayoutHelpers.cpp +++ b/src/GUIStuff/ElementHelpers/LayoutHelpers.cpp @@ -245,7 +245,7 @@ void bottom_offset_setup(GUIManager& gui, float dropdownHeight, Clay_FloatingEle floatConfig = { .offset = { .x = xOffset, - .y = bb.max.y() + d.dropdownOffset + .y = bb.max.y() + d.popupOffset }, .zIndex = gui.get_z_index(), .attachPoints = { @@ -255,7 +255,7 @@ void bottom_offset_setup(GUIManager& gui, float dropdownHeight, Clay_FloatingEle .attachTo = CLAY_ATTACH_TO_ROOT }; - maxHeight = std::max(gui.io.safeWindowRect.max.y() - bb.max.y() - d.dropdownOffset, 0.0f); + maxHeight = std::max(gui.io.safeWindowRect.max.y() - bb.max.y() - d.popupOffset, 0.0f); } void top_offset_setup(GUIManager& gui, float dropdownHeight, Clay_FloatingElementConfig& floatConfig, float& maxHeight, const DropDownPopupLayout& d) { @@ -271,7 +271,7 @@ void top_offset_setup(GUIManager& gui, float dropdownHeight, Clay_FloatingElemen floatConfig = { .offset = { .x = xOffset, - .y = bb.min.y() - d.dropdownOffset + .y = bb.min.y() - d.popupOffset }, .zIndex = gui.get_z_index(), .attachPoints = { @@ -281,7 +281,7 @@ void top_offset_setup(GUIManager& gui, float dropdownHeight, Clay_FloatingElemen .attachTo = CLAY_ATTACH_TO_ROOT }; - maxHeight = std::max(bb.min.y() - gui.io.safeWindowRect.min.y() - d.dropdownOffset, 0.0f); + maxHeight = std::max(bb.min.y() - gui.io.safeWindowRect.min.y() - d.popupOffset, 0.0f); } void left_right_offset_setup(GUIManager& gui, float dropdownHeight, Clay_FloatingElementConfig& floatConfig, float& maxHeight, bool isRightSide, const DropDownPopupLayout& d) { @@ -293,9 +293,9 @@ void left_right_offset_setup(GUIManager& gui, float dropdownHeight, Clay_Floatin offsetY -= (offsetY + dropdownHeight) - gui.io.safeWindowRect.max.y(); float offsetX = 0.0f; if(isRightSide) - offsetX = bb.max.x() + d.dropdownOffset; + offsetX = bb.max.x() + d.popupOffset; else - offsetX = bb.min.x() - d.entrySize.x() - d.dropdownOffset; + offsetX = bb.min.x() - d.entrySize.x() - d.popupOffset; floatConfig = { .offset = { .x = offsetX, @@ -314,9 +314,9 @@ void left_right_offset_setup(GUIManager& gui, float dropdownHeight, Clay_Floatin void dropdown_many_element_popup_layout(GUIManager& gui, const char* id, DropDownPopupLayout d) { if(!d.button->get_bb().has_value()) return; - d.entrySize.x() = std::min(d.entrySize.x(), gui.io.windowSize.x()); + d.entrySize.x() = std::min(d.entrySize.x(), gui.io.safeWindowRect.width()); gui.element(id, [&](LayoutElement* l, const Clay_ElementId& lId) { - float dropdownHeight = d.entrySize.y() * d.entryCount + d.dropdownOffset; + float dropdownHeight = d.entrySize.y() * d.entryCount + d.popupOffset; Clay_FloatingElementConfig floatConfig; float maxHeight = gui.io.safeWindowRect.height(); auto& buttonBB = d.button->get_bb().value(); @@ -356,9 +356,88 @@ void dropdown_many_element_popup_layout(GUIManager& gui, const char* id, DropDow } }, LayoutElement::Callbacks { .onClick = [&, d](LayoutElement* l, const InputManager::MouseButtonCallbackArgs& m) { - if(!l->mouseHovering && !l->childMouseHovering && m.down && !d.button->mouseHovering && d.isOpen) { - *d.isOpen = false; - gui.set_to_layout(); + if(!l->mouseHovering && !l->childMouseHovering && !d.button->mouseHovering) { + if(m.down && d.clickAwayCallback) { + d.clickAwayCallback(); + gui.set_to_layout(); + } + if(!m.down && d.clickUpAwayCallback) { + d.clickUpAwayCallback(); + gui.set_to_layout(); + } + } + } + }); +} + +void attach_to_button_popup_layout(GUIManager& gui, const char* id, AttachToButtonPopupLayout d) { + if(!d.button->get_bb().has_value()) + return; + d.popupSize.x() = std::min(d.popupSize.x(), std::abs(gui.io.safeWindowRect.width() - 10.0f)); + d.popupSize.y() = std::min(d.popupSize.y(), std::abs(gui.io.safeWindowRect.height() - 10.0f)); + float maxHeight = d.popupSize.y(); + gui.element(id, [&](LayoutElement* l, const Clay_ElementId& lId) { + Clay_FloatingElementConfig floatConfig; + auto& buttonBB = d.button->get_bb().value(); + if(buttonBB.max.y() + d.popupSize.y() > gui.io.safeWindowRect.max.y()) { + float rightSideWidth = gui.io.safeWindowRect.max.x() - buttonBB.max.x(); + float leftSideWidth = buttonBB.min.x() - gui.io.safeWindowRect.min.x(); + if(rightSideWidth > d.popupSize.x() || leftSideWidth > d.popupSize.x()) + left_right_offset_setup(gui, d.popupSize.y(), floatConfig, maxHeight, rightSideWidth >= leftSideWidth, { + .popupOffset = d.popupOffset, + .button = d.button, + .entrySize = d.popupSize + }); + else { + if(gui.io.safeWindowRect.max.y() - buttonBB.max.y() >= buttonBB.min.y() - gui.io.safeWindowRect.min.y()) + bottom_offset_setup(gui, d.popupSize.y(), floatConfig, maxHeight, { + .popupOffset = d.popupOffset, + .button = d.button, + .entrySize = d.popupSize + }); + else + top_offset_setup(gui, d.popupSize.y(), floatConfig, maxHeight, { + .popupOffset = d.popupOffset, + .button = d.button, + .entrySize = d.popupSize + }); + } + } + else + bottom_offset_setup(gui, d.popupSize.y(), floatConfig, maxHeight, { + .popupOffset = d.popupOffset, + .button = d.button, + .entrySize = d.popupSize + }); + + if(maxHeight < d.popupSize.y()) + d.popupSize.y() = maxHeight; + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_FIXED(d.popupSize.x()), .height = CLAY_SIZING_FIXED(d.popupSize.y())}, + .childGap = 0 + }, + .backgroundColor = convert_vec4(gui.io.theme->backColor1), + .cornerRadius = CLAY_CORNER_RADIUS(4), + .floating = floatConfig, + .border = { + .color = convert_vec4(gui.io.theme->fillColor2), + .width = CLAY_BORDER_OUTSIDE(1) + } + }) { + d.innerLayout(); + } + }, LayoutElement::Callbacks { + .onClick = [&, d](LayoutElement* l, const InputManager::MouseButtonCallbackArgs& m) { + if(!l->mouseHovering && !l->childMouseHovering && !d.button->mouseHovering) { + if(m.down && d.clickAwayCallback) { + d.clickAwayCallback(); + gui.set_to_layout(); + } + if(!m.down && d.clickUpAwayCallback) { + d.clickUpAwayCallback(); + gui.set_to_layout(); + } } } }); diff --git a/src/GUIStuff/ElementHelpers/LayoutHelpers.hpp b/src/GUIStuff/ElementHelpers/LayoutHelpers.hpp index 0f9b4ee..19f099b 100644 --- a/src/GUIStuff/ElementHelpers/LayoutHelpers.hpp +++ b/src/GUIStuff/ElementHelpers/LayoutHelpers.hpp @@ -42,14 +42,25 @@ void window_fill_side_bar(GUIManager& gui, const WindowFillSideBarConfig& config void window_gap_side_bar(GUIManager& gui, const WindowFillSideBarConfig::Direction& dir); struct DropDownPopupLayout { - float dropdownOffset = 4.0f; + float popupOffset = 4.0f; Element* button = nullptr; - bool* isOpen; + std::function clickAwayCallback; + std::function clickUpAwayCallback; Vector2f entrySize; size_t entryCount; std::function entryLayout; }; +struct AttachToButtonPopupLayout { + float popupOffset = 4.0f; + Element* button = nullptr; + std::function clickAwayCallback; + std::function clickUpAwayCallback; + Vector2f popupSize; + std::function innerLayout; +}; + +void attach_to_button_popup_layout(GUIManager& gui, const char* id, AttachToButtonPopupLayout d); void dropdown_many_element_popup_layout(GUIManager& gui, const char* id, DropDownPopupLayout d); }} diff --git a/src/GUIStuff/Elements/ColorPickerButton.impl.hpp b/src/GUIStuff/Elements/ColorPickerButton.impl.hpp index 6518ea4..e721520 100644 --- a/src/GUIStuff/Elements/ColorPickerButton.impl.hpp +++ b/src/GUIStuff/Elements/ColorPickerButton.impl.hpp @@ -20,6 +20,7 @@ #include "../ElementHelpers/ColorPickerItemsHelpers.hpp" #include "../ElementHelpers/ButtonHelpers.hpp" #include "../ElementHelpers/LayoutHelpers.hpp" +#include "Helpers/ConvertVec.hpp" namespace GUIStuff { @@ -28,7 +29,7 @@ template ColorPickerButton::ColorPickerButton(GUIManager& gui): template void ColorPickerButton::layout(const Clay_ElementId& id, T* val, const ColorPickerButtonData& d) { this->data = d; - GUIStuff::ElementHelpers::color_button(gui, "Color Picker Button", val, { + Element* button = GUIStuff::ElementHelpers::color_button(gui, "Color Picker Button", val, { .isSelected = isOpen, .hasAlpha = data.hasAlpha, .onClick = [&]{ @@ -38,18 +39,26 @@ template void ColorPickerButton::layout(const Clay_ElementId& id }); if(isOpen) { gui.set_z_index(gui.get_z_index() + 1, [&] { - ElementHelpers::top_to_bottom_window_popup_layout(gui, "Color Picker", CLAY_SIZING_FIT(300), CLAY_SIZING_FIT(0), [&, val, data = data](LayoutElement*) { - ElementHelpers::color_picker_items(gui, "c", val, { - .hasAlpha = data.hasAlpha, - .onEdit = data.onEdit, - .onSelect = data.onSelect, - .onDeselect = data.onDeselect - }); - }, { - .mouseButton = [&](LayoutElement* l, const InputManager::MouseButtonCallbackArgs& button) { - if(!l->mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down) { - isOpen = false; - gui.set_to_layout(); + ElementHelpers::attach_to_button_popup_layout(gui, "Color Picker", { + .button = button, + .clickAwayCallback = [&] { isOpen = false; }, + .popupSize = {300.0f, 300.0f}, + .innerLayout = [&] { + CLAY_AUTO_ID({ + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, + .padding = CLAY_PADDING_ALL(gui.io.theme->padding1), + .childGap = gui.io.theme->childGap1, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + }) { + ElementHelpers::color_picker_items(gui, "c", val, { + .forceAspectRatioOnColorPicker = false, + .hasAlpha = data.hasAlpha, + .onEdit = data.onEdit, + .onSelect = data.onSelect, + .onDeselect = data.onDeselect + }); } } }); diff --git a/src/GUIStuff/Elements/DropDown.hpp b/src/GUIStuff/Elements/DropDown.hpp index 8c78ed9..d43f388 100644 --- a/src/GUIStuff/Elements/DropDown.hpp +++ b/src/GUIStuff/Elements/DropDown.hpp @@ -94,7 +94,7 @@ template class DropDown : public Element { gui.set_z_index(gui.get_z_index() + 1, [&] { dropdown_many_element_popup_layout(gui, "DROPDOWN", { .button = this, - .isOpen = &isOpen, + .clickAwayCallback = [&] { isOpen = false; }, .entrySize = boundingBox.value().dim(), .entryCount = selections.size(), .entryLayout = [&](size_t i) { diff --git a/src/Screens/DesktopDrawingProgramScreen.cpp b/src/Screens/DesktopDrawingProgramScreen.cpp index 71599cd..0547677 100644 --- a/src/Screens/DesktopDrawingProgramScreen.cpp +++ b/src/Screens/DesktopDrawingProgramScreen.cpp @@ -22,7 +22,7 @@ DesktopDrawingProgramScreen::DesktopDrawingProgramScreen(MainProgram& m): DrawingProgramScreen(m), - toolbar(m) + toolbar(m, *this) {} void DesktopDrawingProgramScreen::update() { @@ -76,3 +76,10 @@ void DesktopDrawingProgramScreen::input_text_key_callback(const InputManager::Ke } DrawingProgramScreen::input_text_key_callback(key); } + +void DesktopDrawingProgramScreen::open_file_selector(const std::string& filePickerName, const std::vector& extensionFilters, OpenFileSelectorCallback postSelectionFunc, const std::string& fileName, bool isSaving) { + if(main.conf.useNativeFilePicker) + Screen::open_file_selector(filePickerName, extensionFilters, postSelectionFunc, fileName, isSaving); + else + toolbar.open_file_selector_non_native(filePickerName, extensionFilters, postSelectionFunc, fileName, isSaving); +} diff --git a/src/Screens/DesktopDrawingProgramScreen.hpp b/src/Screens/DesktopDrawingProgramScreen.hpp index 081dc0a..d2ffc49 100644 --- a/src/Screens/DesktopDrawingProgramScreen.hpp +++ b/src/Screens/DesktopDrawingProgramScreen.hpp @@ -28,6 +28,8 @@ class DesktopDrawingProgramScreen : public DrawingProgramScreen { virtual bool app_close_requested() override; virtual void input_key_callback(const InputManager::KeyCallbackArgs& key) override; virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key) override; + virtual void open_file_selector(const std::string& filePickerName, const std::vector& extensionFilters, OpenFileSelectorCallback postSelectionFunc, const std::string& fileName = "", bool isSaving = false) override; + private: Toolbar toolbar; }; diff --git a/src/Screens/FileSelectScreen.cpp b/src/Screens/FileSelectScreen.cpp index 83a6829..efe48f4 100644 --- a/src/Screens/FileSelectScreen.cpp +++ b/src/Screens/FileSelectScreen.cpp @@ -29,6 +29,8 @@ #include "../GUIStuff/Elements/SVGIcon.hpp" #include "../GUIStuff/Elements/TextParagraph.hpp" #include "../GUIStuff/ElementHelpers/LayoutHelpers.hpp" +#include "../GUIStuff/ElementHelpers/ColorPickerHelpers.hpp" +#include "../GUIStuff/ElementHelpers/CheckBoxHelpers.hpp" #include "../GUIStuff/Elements/PositionAdjustingPopupMenu.hpp" #include "../World.hpp" #include "Helpers/StringHelpers.hpp" @@ -181,15 +183,17 @@ void FileSelectScreen::main_display() { .layoutDirection = CLAY_TOP_TO_BOTTOM, }, }) { - file_view(); switch(selectedMenu) { case SelectedMenu::FILES: + file_view(); if(!editMode) create_file_button(); break; case SelectedMenu::TRASH: + file_view(); break; case SelectedMenu::SETTINGS: + settings_view(); break; } } @@ -479,51 +483,71 @@ void FileSelectScreen::title_bar() { } }); if(moreButton->get_bb().has_value() && moreOptionsMenu != MoreOptionsMenu::CLOSED) { + size_t elemCount = 0; + if(moreOptionsMenu == MoreOptionsMenu::MAIN) + elemCount = 2; + else if(moreOptionsMenu == MoreOptionsMenu::VIEW) + elemCount = 4; gui.set_z_index(gui.get_z_index() + 10, [&] { - gui.element("more options popup", moreButton->get_bb().value().top_right(), [&] { - CLAY_AUTO_ID({ - .layout = { - .sizing = {.width = CLAY_SIZING_FIT(200), .height = CLAY_SIZING_FIT(0)}, - .layoutDirection = CLAY_TOP_TO_BOTTOM - }, - .backgroundColor = convert_vec4(gui.io.theme->backColor1), - .cornerRadius = CLAY_CORNER_RADIUS(4) - }) { + dropdown_many_element_popup_layout(gui, "more options popup", { + .button = moreButton, + .clickUpAwayCallback = [&] { + gui.set_post_callback_func_high_priority([&] { // Cancel actions on other buttons + moreOptionsMenu = MoreOptionsMenu::CLOSED; + main.g.gui.set_to_layout(); + }); + }, + .entrySize = {200.0f, 30.0f}, + .entryCount = elemCount, + .entryLayout = [&] (size_t i) { if(moreOptionsMenu == MoreOptionsMenu::MAIN) { - text_transparent_option_button("Edit", "Edit", [&] { - moreOptionsMenu = MoreOptionsMenu::CLOSED; - start_edit_mode(); - }); - text_transparent_option_button("View", "View", [&] { - moreOptionsMenu = MoreOptionsMenu::VIEW; - }); + switch(i) { + case 0: { + text_transparent_option_button("Edit", "Edit", [&] { + moreOptionsMenu = MoreOptionsMenu::CLOSED; + start_edit_mode(); + }); + break; + } + case 1: { + text_transparent_option_button("View", "View", [&] { + moreOptionsMenu = MoreOptionsMenu::VIEW; + }); + break; + } + } } else if(moreOptionsMenu == MoreOptionsMenu::VIEW) { - text_transparent_option_button("Large Grid", "Large Grid", [&] { - fileViewType = FileViewType::LARGE_GRID; - moreOptionsMenu = MoreOptionsMenu::CLOSED; - }); - text_transparent_option_button("Medium Grid", "Medium Grid", [&] { - fileViewType = FileViewType::MEDIUM_GRID; - moreOptionsMenu = MoreOptionsMenu::CLOSED; - }); - text_transparent_option_button("Small Grid", "Small Grid", [&] { - fileViewType = FileViewType::SMALL_GRID; - moreOptionsMenu = MoreOptionsMenu::CLOSED; - }); - text_transparent_option_button("List", "List", [&] { - fileViewType = FileViewType::LIST; - moreOptionsMenu = MoreOptionsMenu::CLOSED; - }); - } - } - }, LayoutElement::Callbacks{ - .onClick = [&](LayoutElement* l, const InputManager::MouseButtonCallbackArgs& m) { - if(!l->mouseHovering && !m.down) { - gui.set_post_callback_func_high_priority([&] { // Cancel actions on other buttons - moreOptionsMenu = MoreOptionsMenu::CLOSED; - main.g.gui.set_to_layout(); - }); + switch(i) { + case 0: { + text_transparent_option_button("Large Grid", "Large Grid", [&] { + fileViewType = FileViewType::LARGE_GRID; + moreOptionsMenu = MoreOptionsMenu::CLOSED; + }); + break; + } + case 1: { + text_transparent_option_button("Medium Grid", "Medium Grid", [&] { + fileViewType = FileViewType::MEDIUM_GRID; + moreOptionsMenu = MoreOptionsMenu::CLOSED; + }); + break; + } + case 2: { + text_transparent_option_button("Small Grid", "Small Grid", [&] { + fileViewType = FileViewType::SMALL_GRID; + moreOptionsMenu = MoreOptionsMenu::CLOSED; + }); + break; + } + case 3: { + text_transparent_option_button("List", "List", [&] { + fileViewType = FileViewType::LIST; + moreOptionsMenu = MoreOptionsMenu::CLOSED; + }); + break; + } + } } } }); @@ -541,6 +565,7 @@ void FileSelectScreen::text_transparent_option_button(const char* id, const char text_button(gui, id, text, { .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, .wide = true, + .growHeight = true, .centered = false, .onClick = onClick }); @@ -569,7 +594,7 @@ void FileSelectScreen::main_menu() { gui.element("inner main menu element", [&] (LayoutElement*, const Clay_ElementId& lId) { CLAY(lId, { .layout = { - .sizing = {.width = CLAY_SIZING_FIXED(300.0f * mainMenuOpenAnim->get_val()), .height = CLAY_SIZING_GROW(0)}, + .sizing = {.width = CLAY_SIZING_FIXED(200.0f * mainMenuOpenAnim->get_val()), .height = CLAY_SIZING_GROW(0)}, .padding = CLAY_PADDING_ALL(gui.io.theme->padding1), .layoutDirection = CLAY_TOP_TO_BOTTOM, }, @@ -579,18 +604,18 @@ void FileSelectScreen::main_menu() { selectedMenu = SelectedMenu::FILES; update_file_list(fileList, savePath, false); mainMenuOpenAnim->animation_trigger_reverse(); - if(fileViewScrollArea) fileViewScrollArea->reset_scroll(); + if(mainViewScrollArea) mainViewScrollArea->reset_scroll(); }); icon_text_transparent_option_selected_button("Trash", "data/icons/trash.svg", "Trash", selectedMenu == SelectedMenu::TRASH, [&] { selectedMenu = SelectedMenu::TRASH; update_file_list(fileList, trashPath, true); mainMenuOpenAnim->animation_trigger_reverse(); - if(fileViewScrollArea) fileViewScrollArea->reset_scroll(); + if(mainViewScrollArea) mainViewScrollArea->reset_scroll(); }); icon_text_transparent_option_selected_button("Settings", "data/icons/RemixIcon/settings-3-line.svg", "Settings", selectedMenu == SelectedMenu::SETTINGS, [&] { selectedMenu = SelectedMenu::SETTINGS; mainMenuOpenAnim->animation_trigger_reverse(); - if(fileViewScrollArea) fileViewScrollArea->reset_scroll(); + if(mainViewScrollArea) mainViewScrollArea->reset_scroll(); }); } } @@ -602,11 +627,6 @@ void FileSelectScreen::main_menu() { } void FileSelectScreen::file_view() { - if(selectedMenu == SelectedMenu::SETTINGS) { - fileViewScrollArea = nullptr; - return; - } - auto& gui = main.g.gui; std::filesystem::path folderPath = (selectedMenu == SelectedMenu::TRASH) ? trashPath : savePath; @@ -615,14 +635,21 @@ void FileSelectScreen::file_view() { gui.element("file button", SelectableButton::Data{ .isSelected = editMode && fileList[i].selected, .onClick = [&, filePath, i] { - if(editMode) + if(selectedMenu == SelectedMenu::TRASH) { + if(!editMode) + start_edit_mode(); fileList[i].selected = !fileList[i].selected; + } else { - CustomEvents::emit_event({ - .isClient = false, - .saveThumbnail = true, - .filePathSource = filePath - }); + if(editMode) + fileList[i].selected = !fileList[i].selected; + else { + CustomEvents::emit_event({ + .isClient = false, + .saveThumbnail = true, + .filePathSource = filePath + }); + } } }, .innerContent = [&](const SelectableButton::InnerContentCallbackParameters& c){ @@ -701,7 +728,7 @@ void FileSelectScreen::file_view() { }; if(fileViewType == FileViewType::LIST) { - fileViewScrollArea = gui.element("File selector list", ManyElementScrollArea::Options{ + mainViewScrollArea = gui.element("File selector list", ManyElementScrollArea::Options{ .entryHeight = 150.0f, .entryCount = fileList.size(), .clipHorizontal = true, @@ -730,7 +757,7 @@ void FileSelectScreen::file_view() { default: break; } - fileViewScrollArea = gui.element("File selector grid", GridScrollArea::Options{ + mainViewScrollArea = gui.element("File selector grid", GridScrollArea::Options{ .entryWidth = entrySize.x(), .childAlignmentX = CLAY_ALIGN_X_LEFT, .entryHeight = entrySize.y(), @@ -743,6 +770,40 @@ void FileSelectScreen::file_view() { } } +void FileSelectScreen::settings_view() { + auto& gui = main.g.gui; + + mainViewScrollArea = gui.element("settings scroll area", ScrollArea::Options{ + .scrollVertical = true, + .clipVertical = true, + .scrollbarY = ScrollArea::ScrollbarType::NORMAL, + .innerContent = [&] (auto&) { + CLAY_AUTO_ID({ + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, + .layoutDirection = CLAY_LEFT_TO_RIGHT + }, + }) { + CLAY_AUTO_ID({ + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0, 300), .height = CLAY_SIZING_GROW(0)}, + .childGap = gui.io.theme->childGap1, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + }) { + color_picker_button_field(gui, "defaultCanvasBackgroundColor", "Default canvas background color", &main.conf.defaultCanvasBackgroundColor, { .hasAlpha = false }); + input_scalar_field(gui, "Max GUI Scale", "Max GUI Scale", &main.conf.guiScale, 1.0f, 2.0f, { + .decimalPrecision = 1, + .onEdit = [&] { main.g.window_update(); } + }); + input_scalar_field(gui, "jump transition time", "Jump transition time", &main.conf.jumpTransitionTime, 0.01f, 1000.0f, {.decimalPrecision = 2}); + checkbox_boolean_field(gui, "make all tools share same size", "Make all tools share size", &main.toolConfig.globalConf.useGlobalRelativeWidth); + } + } + } + }); +} + void FileSelectScreen::menu_black_box() { auto& gui = main.g.gui; if(!mainMenuOpenAnim->is_at_start()) { diff --git a/src/Screens/FileSelectScreen.hpp b/src/Screens/FileSelectScreen.hpp index 67ac63c..bb9a2e5 100644 --- a/src/Screens/FileSelectScreen.hpp +++ b/src/Screens/FileSelectScreen.hpp @@ -63,11 +63,12 @@ class FileSelectScreen : public Screen { GUIStuff::GUIFloatAnimation* mainMenuOpenAnim = nullptr; GUIStuff::GUIFloatAnimation* actionBarOpenAnim = nullptr; - GUIStuff::ScrollArea* fileViewScrollArea = nullptr; + GUIStuff::ScrollArea* mainViewScrollArea = nullptr; void main_display(); void main_menu(); void file_view(); + void settings_view(); void create_file_button(); void file_view_edit(); void menu_black_box(); diff --git a/src/Screens/PhoneDrawingProgramScreen.cpp b/src/Screens/PhoneDrawingProgramScreen.cpp index 9a9ced1..a6f2151 100644 --- a/src/Screens/PhoneDrawingProgramScreen.cpp +++ b/src/Screens/PhoneDrawingProgramScreen.cpp @@ -174,6 +174,20 @@ void PhoneDrawingProgramScreen::top_toolbar_remaining_area() { void PhoneDrawingProgramScreen::top_toolbar_hidden_button_popup(GUIStuff::Element* b, std::vector l) { auto& gui = main.g.gui; + l.emplace_back(TopToolbarRemainingAreaButton{ + .name = "Add Image", + .svgPath = "data/icons/RemixIcon/image-add-line.svg", + .onClick = [&] { + open_file_selector("Open File", {{"Any File", "*"}}, [&](const std::filesystem::path& p, const auto& e) { + CustomEvents::emit_event({ + .type = CustomEvents::AddFileToCanvasEvent::Type::PATH, + .filePath = p, + .pos = main.window.size.cast() / 2.0f + }); + }); + } + }); + l.emplace_back(TopToolbarRemainingAreaButton{ .name = "Canvas Color", .svgPath = "data/icons/RemixIcon/settings-3-line.svg", @@ -191,7 +205,7 @@ void PhoneDrawingProgramScreen::top_toolbar_hidden_button_popup(GUIStuff::Elemen gui.set_z_index(gui.get_z_index() + 1, [&] { dropdown_many_element_popup_layout(gui, "top toolbar hidden button popup", { .button = b, - .isOpen = &topToolbarButtonPopupOpen, + .clickAwayCallback = [&] { topToolbarButtonPopupOpen = false; }, .entrySize = {150.0f, 30.0f}, .entryCount = l.size(), .entryLayout = [&] (size_t i) { diff --git a/src/Screens/Screen.cpp b/src/Screens/Screen.cpp index aed0f13..f81a540 100644 --- a/src/Screens/Screen.cpp +++ b/src/Screens/Screen.cpp @@ -17,11 +17,45 @@ */ #include "Screen.hpp" +#include "../MainProgram.hpp" Screen::Screen(MainProgram& m): main(m) {} +Screen::NativeFilePicker Screen::nativeFilePicker; + +// You can't trust that filter wont be -1 on the platform youre on, so dont use the extension from the callback +void Screen::sdl_open_file_dialog_callback(void* userData, const char * const * fileList, int filter) { + if(!fileList) { + nativeFilePicker.isOpen = false; + return; + } + if(!(*fileList)) { + nativeFilePicker.isOpen = false; + return; + } + ExtensionFilter e; + if(filter >= 0) + e = nativeFilePicker.extensionFiltersComplete[filter]; + nativeFilePicker.postSelectionFunc(fileList[0], e); + nativeFilePicker.isOpen = false; +} + +void Screen::open_file_selector(const std::string& filePickerName, const std::vector& extensionFilters, OpenFileSelectorCallback postSelectionFunc, const std::string& fileName, bool isSaving) { + if(!nativeFilePicker.isOpen) { + nativeFilePicker.postSelectionFunc = postSelectionFunc; + nativeFilePicker.extensionFiltersComplete = extensionFilters; + nativeFilePicker.sdlFileFilters.clear(); + for(auto& e : nativeFilePicker.extensionFiltersComplete) + nativeFilePicker.sdlFileFilters.emplace_back(e.name.c_str(), e.extensions.c_str()); + if(isSaving) + SDL_ShowSaveFileDialog(sdl_open_file_dialog_callback, nullptr, main.window.sdlWindow, nativeFilePicker.sdlFileFilters.data(), nativeFilePicker.sdlFileFilters.size(), nullptr); + else + SDL_ShowOpenFileDialog(sdl_open_file_dialog_callback, nullptr, main.window.sdlWindow, nativeFilePicker.sdlFileFilters.data(), nativeFilePicker.sdlFileFilters.size(), nullptr, false); + } +} + void Screen::update() {} void Screen::gui_layout_run() {} bool Screen::app_close_requested() { return true; } diff --git a/src/Screens/Screen.hpp b/src/Screens/Screen.hpp index a27544f..156a234 100644 --- a/src/Screens/Screen.hpp +++ b/src/Screens/Screen.hpp @@ -25,6 +25,20 @@ class Screen { virtual void update(); virtual void draw(SkCanvas* canvas) = 0; + struct ExtensionFilter { + std::string name; + std::string extensions; + }; + + typedef std::function OpenFileSelectorCallback; + struct NativeFilePicker { + std::atomic isOpen = false; + std::vector extensionFiltersComplete; + std::vector sdlFileFilters; + OpenFileSelectorCallback postSelectionFunc; + }; + static NativeFilePicker nativeFilePicker; + virtual void gui_layout_run(); virtual bool app_close_requested(); virtual void input_add_file_to_canvas_callback(const CustomEvents::AddFileToCanvasEvent& addFile); @@ -53,7 +67,11 @@ class Screen { virtual void input_app_about_to_go_to_background_callback(); virtual std::optional get_text_box_start_info(); + virtual void open_file_selector(const std::string& filePickerName, const std::vector& extensionFilters, OpenFileSelectorCallback postSelectionFunc, const std::string& fileName = "", bool isSaving = false); + virtual ~Screen(); protected: + static void sdl_open_file_dialog_callback(void* userData, const char * const * fileList, int filter); + MainProgram& main; }; diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index 3904fcc..e820c07 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -71,6 +71,8 @@ #include "GUIStuff/Elements/MovableTabList.hpp" #include "GUIStuff/Elements/TextParagraph.hpp" +#include "Screens/DesktopDrawingProgramScreen.hpp" + #define UPDATE_DOWNLOAD_URL "https://infinipaint.com/download.html" #define UPDATE_NOTIFICATION_URL "https://infinipaint.com/updateNotificationVersion.txt" @@ -78,60 +80,31 @@ #include #endif -Toolbar::NativeFilePicker Toolbar::nativeFilePicker; - using namespace GUIStuff; using namespace ElementHelpers; -Toolbar::Toolbar(MainProgram& initMain): - main(initMain) +Toolbar::Toolbar(MainProgram& initMain, DesktopDrawingProgramScreen& initDrawScreen): + main(initMain), + drawScreen(initDrawScreen) {} -// You can't trust that filter wont be -1 on the platform youre on, so dont use the extension from the callback -void Toolbar::sdl_open_file_dialog_callback(void* userData, const char * const * fileList, int filter) { - if(!fileList) { - nativeFilePicker.isOpen = false; - return; - } - if(!(*fileList)) { - nativeFilePicker.isOpen = false; - return; - } - ExtensionFilter e; - if(filter >= 0) - e = nativeFilePicker.extensionFiltersComplete[filter]; - nativeFilePicker.postSelectionFunc(fileList[0], e); - nativeFilePicker.isOpen = false; +void Toolbar::open_file_selector(const std::string& filePickerName, const std::vector& extensionFilters, Screen::OpenFileSelectorCallback postSelectionFunc, const std::string& fileName, bool isSaving) { + drawScreen.open_file_selector(filePickerName, extensionFilters, postSelectionFunc, fileName, isSaving); } -void Toolbar::open_file_selector(const std::string& filePickerName, const std::vector& extensionFilters, OpenFileSelectorCallback postSelectionFunc, const std::string& fileName, bool isSaving) { - if(main.conf.useNativeFilePicker) { - if(!nativeFilePicker.isOpen) { - nativeFilePicker.postSelectionFunc = postSelectionFunc; - nativeFilePicker.extensionFiltersComplete = extensionFilters; - nativeFilePicker.sdlFileFilters.clear(); - for(auto& e : nativeFilePicker.extensionFiltersComplete) - nativeFilePicker.sdlFileFilters.emplace_back(e.name.c_str(), e.extensions.c_str()); - if(isSaving) - SDL_ShowSaveFileDialog(sdl_open_file_dialog_callback, nullptr, main.window.sdlWindow, nativeFilePicker.sdlFileFilters.data(), nativeFilePicker.sdlFileFilters.size(), nullptr); - else - SDL_ShowOpenFileDialog(sdl_open_file_dialog_callback, nullptr, main.window.sdlWindow, nativeFilePicker.sdlFileFilters.data(), nativeFilePicker.sdlFileFilters.size(), nullptr, false); - } - } - else { - filePicker.isOpen = true; - filePicker.extensionFiltersComplete = extensionFilters; - filePicker.extensionFilters.clear(); - for(auto& [name, exList] : extensionFilters) - filePicker.extensionFilters.emplace_back(exList); - filePicker.extensionSelected = extensionFilters.size() - 1; - filePicker.filePickerWindowName = filePickerName; - filePicker.postSelectionFunc = postSelectionFunc; - filePicker.fileName = ""; - filePicker.isSaving = isSaving; - filePicker.entriesScrollArea = nullptr; - file_picker_gui_refresh_entries(); - } +void Toolbar::open_file_selector_non_native(const std::string& filePickerName, const std::vector& extensionFilters, Screen::OpenFileSelectorCallback postSelectionFunc, const std::string& fileName, bool isSaving) { + filePicker.isOpen = true; + filePicker.extensionFiltersComplete = extensionFilters; + filePicker.extensionFilters.clear(); + for(auto& [name, exList] : extensionFilters) + filePicker.extensionFilters.emplace_back(exList); + filePicker.extensionSelected = extensionFilters.size() - 1; + filePicker.filePickerWindowName = filePickerName; + filePicker.postSelectionFunc = postSelectionFunc; + filePicker.fileName = ""; + filePicker.isSaving = isSaving; + filePicker.entriesScrollArea = nullptr; + file_picker_gui_refresh_entries(); } void Toolbar::color_button_left(const char* id, Vector4f* color, const ColorSelectorButtonData& colorSelectorData) { @@ -1781,10 +1754,11 @@ void Toolbar::general_settings_inner_gui() { if(!themeData.selectedThemeIndex) reload_theme_list(); - CLAY_AUTO_ID({.layout = { - .childGap = io.theme->childGap1, - .childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, - .layoutDirection = CLAY_LEFT_TO_RIGHT, + CLAY_AUTO_ID({.layout = { + .sizing = {.width = CLAY_SIZING_GROW(0)}, + .childGap = io.theme->childGap1, + .childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, + .layoutDirection = CLAY_LEFT_TO_RIGHT, } }) { text_label(gui, "Theme: "); diff --git a/src/Toolbar.hpp b/src/Toolbar.hpp index 7518b18..752dfce 100644 --- a/src/Toolbar.hpp +++ b/src/Toolbar.hpp @@ -27,8 +27,10 @@ #include #include #include +#include "Screens/Screen.hpp" class MainProgram; +class DesktopDrawingProgramScreen; class Toolbar { public: @@ -44,14 +46,9 @@ class Toolbar { TimePoint time; }; - struct ExtensionFilter { - std::string name; - std::string extensions; - }; - std::string chatMessageInput; - Toolbar(MainProgram& initMain); + Toolbar(MainProgram& initMain, DesktopDrawingProgramScreen& initDrawScreen); void update(); void layout_run(); @@ -74,8 +71,8 @@ class Toolbar { void paint_popup(Vector2f popupPos); - typedef std::function OpenFileSelectorCallback; - void open_file_selector(const std::string& filePickerName, const std::vector& extensionFilters, OpenFileSelectorCallback postSelectionFunc, const std::string& fileName = "", bool isSaving = false); + void open_file_selector(const std::string& filePickerName, const std::vector& extensionFilters, Screen::OpenFileSelectorCallback postSelectionFunc, const std::string& fileName = "", bool isSaving = false); + void open_file_selector_non_native(const std::string& filePickerName, const std::vector& extensionFilters, Screen::OpenFileSelectorCallback postSelectionFunc, const std::string& fileName = "", bool isSaving = false); void save_func(); void save_as_func(); @@ -203,7 +200,7 @@ class Toolbar { struct FilePicker { bool isOpen = false; std::string filePickerWindowName; - std::vector extensionFiltersComplete; + std::vector extensionFiltersComplete; std::vector extensionFilters; std::vector entries; std::filesystem::path currentSelectedPath; @@ -211,17 +208,9 @@ class Toolbar { bool isSaving = false; size_t extensionSelected; GUIStuff::ScrollArea* entriesScrollArea = nullptr; - OpenFileSelectorCallback postSelectionFunc; + Screen::OpenFileSelectorCallback postSelectionFunc; } filePicker; - struct NativeFilePicker { - std::atomic isOpen = false; - std::vector extensionFiltersComplete; - std::vector sdlFileFilters; - OpenFileSelectorCallback postSelectionFunc; - }; - static NativeFilePicker nativeFilePicker; - RichText::TextData build_paragraph_from_chat_message(const ChatMessage& message, float alpha); void load_icons_at(const std::filesystem::path& pathToLoad); @@ -230,4 +219,5 @@ class Toolbar { std::string serverLocalID; MainProgram& main; + DesktopDrawingProgramScreen& drawScreen; };