Last active
August 18, 2024 06:06
-
-
Save OverShifted/13aec504dfe376dcc2171e8b7451c5b5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <filesystem> | |
#include <imgui.h> | |
#define BIT(x) (1 << x) | |
std::pair<bool, uint32_t> DirectoryTreeViewRecursive(const std::filesystem::path& path, uint32_t* count, int* selection_mask) | |
{ | |
ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth; | |
bool any_node_clicked = false; | |
uint32_t node_clicked = 0; | |
for (const auto& entry : std::filesystem::directory_iterator(path)) | |
{ | |
ImGuiTreeNodeFlags node_flags = base_flags; | |
const bool is_selected = (*selection_mask & BIT(*count)) != 0; | |
if (is_selected) | |
node_flags |= ImGuiTreeNodeFlags_Selected; | |
std::string name = entry.path().string(); | |
auto lastSlash = name.find_last_of("/\\"); | |
lastSlash = lastSlash == String::npos ? 0 : lastSlash + 1; | |
name = name.substr(lastSlash, name.size() - lastSlash); | |
bool entryIsFile = !std::filesystem::is_directory(entry.path()); | |
if (entryIsFile) | |
node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; | |
bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)(*count), node_flags, name.c_str()); | |
if (ImGui::IsItemClicked()) | |
{ | |
node_clicked = *count; | |
any_node_clicked = true; | |
} | |
(*count)--; | |
if (!entryIsFile) | |
{ | |
if (node_open) | |
{ | |
auto clickState = DirectoryTreeViewRecursive(entry.path(), count, selection_mask); | |
if (!any_node_clicked) | |
{ | |
any_node_clicked = clickState.first; | |
node_clicked = clickState.second; | |
} | |
ImGui::TreePop(); | |
} | |
else | |
{ | |
for (const auto& e : std::filesystem::recursive_directory_iterator(entry.path())) | |
(*count)--; | |
} | |
} | |
} | |
return { any_node_clicked, node_clicked }; | |
} | |
void OnImGui(std::string directoryPath) | |
{ | |
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 0.0f, 0.0f }); | |
ImGui::Begin("Assets"); | |
if (ImGui::CollapsingHeader("Assets")) | |
{ | |
uint32_t count = 0; | |
for (const auto& entry : std::filesystem::recursive_directory_iterator(directoryPath)) | |
count++; | |
static int selection_mask = 0; | |
auto clickState = DirectoryTreeViewRecursive(directoryPath, &count, &selection_mask); | |
if (clickState.first) | |
{ | |
// Update selection state | |
// (process outside of tree loop to avoid visual inconsistencies during the clicking frame) | |
if (ImGui::GetIO().KeyCtrl) | |
selection_mask ^= BIT(clickState.second); // CTRL+click to toggle | |
else //if (!(selection_mask & (1 << clickState.second))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection | |
selection_mask = BIT(clickState.second); // Click to single-select | |
} | |
} | |
ImGui::End(); | |
ImGui::PopStyleVar(); | |
} |
I think a good optimization trick from what you said about this with performance, is that you could cache what files and folders are showing, than refresh the cache everytime you maximize a folder / edit a file.
Edit*: When I get around to attempting to add this into my project, I can try to add a caching system and than hopefully share how I did it.
@Stanlyhalo We can also just move the blocking IO to a separate thread. As I think that's what most editors do, Assuming how complicated maintaining a valid cache of the filesystem can be. (Not to mention most OSes do that built-in)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Oh its just
#define BIT(x) (1 << x)