/*
GameEngine and Editor
by John Ryland
Copyright (c) 2023
*/
////////////////////////////////////////////////////////////////////////////////////
// File Browser
#include "FileBrowser.h"
#include "FileWatch.hpp"
#include "imgui.h"
#include <thread>
#include <string>
#include <regex>
#include <iostream>
#include <unordered_set>
using FileWatcher = filewatch::FileWatch<std::string>;
namespace GameEngine {
FileBrowser::FileBrowser(ApplicationFramework::IApplication& app)
: m_application(app)
{
}
FileBrowser::~FileBrowser()
{
}
void FileBrowser::AddShowMenuItem()
{
ImGui::MenuItem("Show File Browser", NULL, &m_open);
}
struct DirectoryNode
{
std::string FullPath;
std::string FileName;
std::vector<DirectoryNode> Children;
std::unique_ptr<FileWatcher> Watcher;
bool IsDirectory; // children.count != 0 ? empty dir
bool NeedsRefresh;
};
void RecursivelyAddDirectoryNodes(DirectoryNode& parentNode, std::filesystem::directory_iterator directoryIterator)
{
for (const std::filesystem::directory_entry& entry : directoryIterator)
{
DirectoryNode& childNode = parentNode.Children.emplace_back();
childNode.FullPath = std::filesystem::absolute(entry.path()).u8string();
childNode.FileName = entry.path().filename().u8string();
childNode.IsDirectory = entry.is_directory();
childNode.NeedsRefresh = false;
if (childNode.IsDirectory)
{
childNode.Watcher = std::make_unique<FileWatcher>(childNode.FullPath, std::regex(".*"), [&childNode](const std::string& file, const filewatch::Event eventType)
{
childNode.NeedsRefresh = true;
});
RecursivelyAddDirectoryNodes(childNode, std::filesystem::directory_iterator(entry));
}
}
auto moveDirectoriesToFront = [](const DirectoryNode& a, const DirectoryNode& b) { return (a.IsDirectory > b.IsDirectory); };
std::sort(parentNode.Children.begin(), parentNode.Children.end(), moveDirectoriesToFront);
}
DirectoryNode CreateDirectryNodeTreeFromPath(const std::filesystem::path& rootPath)
{
DirectoryNode rootNode;
rootNode.FullPath = rootPath.u8string();
rootNode.FileName = rootPath.filename().u8string();
if (rootNode.IsDirectory = std::filesystem::is_directory(rootPath); rootNode.IsDirectory)
RecursivelyAddDirectoryNodes(rootNode, std::filesystem::directory_iterator(rootPath));
return rootNode;
}
void RecursivelyDisplayDirectoryNode(const DirectoryNode& parentNode)
{
ImGui::PushID(&parentNode);
if (parentNode.IsDirectory)
{
int flags = (parentNode.NeedsRefresh) ? ImGuiTreeNodeFlags_Selected : 0;
if (ImGui::TreeNodeEx(parentNode.FileName.c_str(), ImGuiTreeNodeFlags_SpanFullWidth | flags))
{
for (const DirectoryNode& childNode : parentNode.Children)
RecursivelyDisplayDirectoryNode(childNode);
ImGui::TreePop();
}
}
else
{
if (ImGui::TreeNodeEx(parentNode.FileName.c_str(), ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_SpanFullWidth))
{
// ... handle file click interaction
}
}
ImGui::PopID();
}
/*
void RecursivelyDirectlyDisplayDirectoryNode(const DirectoryNode& parentNode)
{
ImGui::PushID(&parentNode);
if (parentNode.IsDirectory)
{
if (ImGui::TreeNodeEx(parentNode.FileName.c_str(), ImGuiTreeNodeFlags_SpanFullWidth))
{
for (const DirectoryNode& childNode : parentNode.Children)
RecursivelyDirectlyDisplayDirectoryNode(childNode);
ImGui::TreePop();
}
}
else
{
if (ImGui::TreeNodeEx(parentNode.FileName.c_str(), ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_SpanFullWidth))
{
// ... handle file click interaction
}
}
ImGui::PopID();
}
void RecursivelyDirectlyDisplayDirectoryNode(const std::filesystem::path& rootPath)
{
DirectoryNode rootNode;
rootNode.FullPath = rootPath.u8string();
rootNode.FileName = rootPath.filename().u8string();
if (rootNode.IsDirectory = std::filesystem::is_directory(rootPath); rootNode.IsDirectory)
RecursivelyDirectlyDisplayDirectoryNode(rootNode, std::filesystem::directory_iterator(rootPath));
}
*/
static DirectoryNode rootNode = CreateDirectryNodeTreeFromPath("src");//L"C:/SomeFolder");
void FileBrowser::Update()
{
if (m_open)
{
if (ImGui::Begin("File Browser", &m_open))
//RecursivelyDirectlyDisplayDirectoryNode(".");
RecursivelyDisplayDirectoryNode(rootNode);
ImGui::End();
}
}
void FileBrowser::Initialize()
{
}
void FileBrowser::Shutdown()
{
}
/*
void PluginManager::SetPluginDirectory(const char* pluginDirectoryName)
{
mPluginDirectoryName = pluginDirectoryName;
mFileWatcher = std::make_unique<FileWatcher>(pluginDirectoryName, std::regex(".*"), [this](const std::string& file, const filewatch::Event eventType)
{
std::string pluginName = details::PluginNameFromFileName(file);
if (!pluginName.empty() && eventType == filewatch::Event::added)
{
mPendingAdd = true;
}
if (!pluginName.empty() && eventType == filewatch::Event::modified && mPendingAdd != true)
{
}
mNeedReload = true;
});
}
void PluginManager::LoadPlugins()
{
// Get the set of plugin file names now currently on disk
std::unordered_map<std::string, std::string> pluginFileNames;
for (const auto& entry : std::filesystem::directory_iterator(mPluginDirectoryName))
{
std::string fileName = entry.path();
std::string pluginName = details::PluginNameFromFileName(fileName);
if (!pluginName.empty())
pluginFileNames[pluginName] = fileName;
}
}
*/
} // GameEngine namespace