306 lines
11 KiB
C++
306 lines
11 KiB
C++
#include "EditorUI.h"
|
|
|
|
// FileBrowser implementation
|
|
FileBrowser::FileBrowser() {
|
|
currentPath = fs::current_path();
|
|
projectRoot = currentPath;
|
|
}
|
|
|
|
void FileBrowser::refresh() {
|
|
entries.clear();
|
|
try {
|
|
for (const auto& entry : fs::directory_iterator(currentPath)) {
|
|
// Skip hidden files if not showing them
|
|
std::string filename = entry.path().filename().string();
|
|
if (!showHiddenFiles && !filename.empty() && filename[0] == '.') {
|
|
continue;
|
|
}
|
|
|
|
// Apply search filter if any
|
|
if (!matchesFilter(entry)) {
|
|
continue;
|
|
}
|
|
|
|
entries.push_back(entry);
|
|
}
|
|
// Sort: folders first, then alphabetically
|
|
std::sort(entries.begin(), entries.end(), [](const auto& a, const auto& b) {
|
|
if (a.is_directory() != b.is_directory()) {
|
|
return a.is_directory() > b.is_directory();
|
|
}
|
|
return a.path().filename().string() < b.path().filename().string();
|
|
});
|
|
} catch (...) {
|
|
}
|
|
needsRefresh = false;
|
|
}
|
|
|
|
void FileBrowser::navigateUp() {
|
|
if (currentPath.has_parent_path() && currentPath != currentPath.root_path()) {
|
|
// Don't go above project root
|
|
if (currentPath != projectRoot) {
|
|
navigateTo(currentPath.parent_path());
|
|
}
|
|
}
|
|
}
|
|
|
|
void FileBrowser::navigateTo(const fs::path& path) {
|
|
if (fs::is_directory(path)) {
|
|
// Add to history
|
|
if (historyIndex < 0 || pathHistory.empty() || pathHistory[historyIndex] != currentPath) {
|
|
// Clear forward history
|
|
if (historyIndex >= 0 && historyIndex < (int)pathHistory.size() - 1) {
|
|
pathHistory.erase(pathHistory.begin() + historyIndex + 1, pathHistory.end());
|
|
}
|
|
pathHistory.push_back(currentPath);
|
|
historyIndex = (int)pathHistory.size() - 1;
|
|
}
|
|
|
|
currentPath = path;
|
|
needsRefresh = true;
|
|
}
|
|
}
|
|
|
|
void FileBrowser::navigateBack() {
|
|
if (historyIndex > 0) {
|
|
historyIndex--;
|
|
currentPath = pathHistory[historyIndex];
|
|
needsRefresh = true;
|
|
}
|
|
}
|
|
|
|
void FileBrowser::navigateForward() {
|
|
if (historyIndex < (int)pathHistory.size() - 1) {
|
|
historyIndex++;
|
|
currentPath = pathHistory[historyIndex];
|
|
needsRefresh = true;
|
|
}
|
|
}
|
|
|
|
void FileBrowser::setProjectRoot(const fs::path& root) {
|
|
projectRoot = root;
|
|
currentPath = root;
|
|
pathHistory.clear();
|
|
historyIndex = -1;
|
|
needsRefresh = true;
|
|
}
|
|
|
|
FileCategory FileBrowser::getFileCategory(const fs::directory_entry& entry) const {
|
|
if (entry.is_directory()) return FileCategory::Folder;
|
|
|
|
std::string ext = entry.path().extension().string();
|
|
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
|
|
|
// Scene files
|
|
if (ext == ".modu" || ext == ".scene") return FileCategory::Scene;
|
|
|
|
// Model files
|
|
if (ext == ".fbx" || ext == ".obj" || ext == ".gltf" || ext == ".glb" ||
|
|
ext == ".dae" || ext == ".blend" || ext == ".3ds" || ext == ".ply" ||
|
|
ext == ".stl" || ext == ".x" || ext == ".md5mesh" || ext == ".rmesh") {
|
|
return FileCategory::Model;
|
|
}
|
|
|
|
// Material files
|
|
if (ext == ".mat") return FileCategory::Material;
|
|
|
|
// Texture files
|
|
if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp" ||
|
|
ext == ".tga" || ext == ".dds" || ext == ".hdr") {
|
|
return FileCategory::Texture;
|
|
}
|
|
|
|
// Shader files
|
|
if (ext == ".glsl" || ext == ".vert" || ext == ".frag" || ext == ".hlsl" ||
|
|
ext == ".shader") {
|
|
return FileCategory::Shader;
|
|
}
|
|
|
|
// Script files
|
|
if (ext == ".cpp" || ext == ".c" || ext == ".h" || ext == ".hpp" ||
|
|
ext == ".lua" || ext == ".py" || ext == ".cs") {
|
|
return FileCategory::Script;
|
|
}
|
|
|
|
// Audio files
|
|
if (ext == ".wav" || ext == ".mp3" || ext == ".ogg" || ext == ".flac") {
|
|
return FileCategory::Audio;
|
|
}
|
|
|
|
// Text files
|
|
if (ext == ".txt" || ext == ".md" || ext == ".json" || ext == ".xml" ||
|
|
ext == ".yaml" || ext == ".ini" || ext == ".cfg") {
|
|
return FileCategory::Text;
|
|
}
|
|
|
|
return FileCategory::Unknown;
|
|
}
|
|
|
|
const char* FileBrowser::getFileIcon(const fs::directory_entry& entry) const {
|
|
FileCategory category = getFileCategory(entry);
|
|
switch (category) {
|
|
case FileCategory::Folder: return "folder";
|
|
case FileCategory::Scene: return "scene";
|
|
case FileCategory::Model: return "model";
|
|
case FileCategory::Material: return "material";
|
|
case FileCategory::Texture: return "image";
|
|
case FileCategory::Shader: return "shader";
|
|
case FileCategory::Script: return "code";
|
|
case FileCategory::Audio: return "audio";
|
|
case FileCategory::Text: return "text";
|
|
default: return "file";
|
|
}
|
|
}
|
|
|
|
bool FileBrowser::isModelFile(const fs::directory_entry& entry) const {
|
|
return getFileCategory(entry) == FileCategory::Model;
|
|
}
|
|
|
|
bool FileBrowser::isSceneFile(const fs::directory_entry& entry) const {
|
|
return getFileCategory(entry) == FileCategory::Scene;
|
|
}
|
|
|
|
bool FileBrowser::isTextureFile(const fs::directory_entry& entry) const {
|
|
return getFileCategory(entry) == FileCategory::Texture;
|
|
}
|
|
|
|
bool FileBrowser::isOBJFile(const fs::directory_entry& entry) const {
|
|
if (entry.is_directory()) return false;
|
|
std::string ext = entry.path().extension().string();
|
|
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
|
return ext == ".obj";
|
|
}
|
|
|
|
bool FileBrowser::matchesFilter(const fs::directory_entry& entry) const {
|
|
if (searchFilter.empty()) return true;
|
|
|
|
std::string filename = entry.path().filename().string();
|
|
std::string filterLower = searchFilter;
|
|
std::string filenameLower = filename;
|
|
|
|
std::transform(filterLower.begin(), filterLower.end(), filterLower.begin(), ::tolower);
|
|
std::transform(filenameLower.begin(), filenameLower.end(), filenameLower.begin(), ::tolower);
|
|
|
|
return filenameLower.find(filterLower) != std::string::npos;
|
|
}
|
|
|
|
void applyModernTheme() {
|
|
ImGuiStyle& style = ImGui::GetStyle();
|
|
ImVec4* colors = style.Colors;
|
|
|
|
ImVec4 slate = ImVec4(0.09f, 0.10f, 0.12f, 1.00f);
|
|
ImVec4 panel = ImVec4(0.11f, 0.12f, 0.14f, 1.00f);
|
|
ImVec4 overlay = ImVec4(0.07f, 0.08f, 0.10f, 0.98f);
|
|
ImVec4 accent = ImVec4(0.33f, 0.63f, 0.98f, 1.00f);
|
|
ImVec4 accentMuted = ImVec4(0.25f, 0.46f, 0.78f, 1.00f);
|
|
ImVec4 highlight = ImVec4(0.18f, 0.23f, 0.30f, 1.00f);
|
|
|
|
colors[ImGuiCol_Text] = ImVec4(0.87f, 0.89f, 0.92f, 1.00f);
|
|
colors[ImGuiCol_TextDisabled] = ImVec4(0.52f, 0.56f, 0.62f, 1.00f);
|
|
|
|
colors[ImGuiCol_WindowBg] = panel;
|
|
colors[ImGuiCol_ChildBg] = ImVec4(0.10f, 0.11f, 0.13f, 1.00f);
|
|
colors[ImGuiCol_PopupBg] = overlay;
|
|
colors[ImGuiCol_Border] = ImVec4(0.21f, 0.24f, 0.28f, 0.60f);
|
|
colors[ImGuiCol_BorderShadow] = ImVec4(0, 0, 0, 0);
|
|
colors[ImGuiCol_MenuBarBg] = ImVec4(0.06f, 0.07f, 0.08f, 1.00f);
|
|
|
|
colors[ImGuiCol_Header] = highlight;
|
|
colors[ImGuiCol_HeaderHovered] = ImVec4(0.22f, 0.28f, 0.36f, 1.00f);
|
|
colors[ImGuiCol_HeaderActive] = ImVec4(0.24f, 0.44f, 0.72f, 1.00f);
|
|
|
|
colors[ImGuiCol_Button] = ImVec4(0.17f, 0.19f, 0.22f, 1.00f);
|
|
colors[ImGuiCol_ButtonHovered] = ImVec4(0.23f, 0.27f, 0.33f, 1.00f);
|
|
colors[ImGuiCol_ButtonActive] = ImVec4(0.26f, 0.36f, 0.46f, 1.00f);
|
|
|
|
colors[ImGuiCol_FrameBg] = ImVec4(0.14f, 0.15f, 0.18f, 1.00f);
|
|
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.20f, 0.22f, 0.27f, 1.00f);
|
|
colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.32f, 0.41f, 1.00f);
|
|
|
|
colors[ImGuiCol_TitleBg] = ImVec4(0.06f, 0.07f, 0.08f, 1.00f);
|
|
colors[ImGuiCol_TitleBgActive] = ImVec4(0.10f, 0.12f, 0.14f, 1.00f);
|
|
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.04f, 0.05f, 0.06f, 1.00f);
|
|
|
|
colors[ImGuiCol_Tab] = ImVec4(0.12f, 0.13f, 0.15f, 1.00f);
|
|
colors[ImGuiCol_TabHovered] = ImVec4(0.20f, 0.28f, 0.38f, 1.00f);
|
|
colors[ImGuiCol_TabActive] = ImVec4(0.16f, 0.19f, 0.23f, 1.00f);
|
|
colors[ImGuiCol_TabUnfocused] = ImVec4(0.09f, 0.10f, 0.12f, 1.00f);
|
|
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.13f, 0.15f, 0.18f, 1.00f);
|
|
|
|
colors[ImGuiCol_Separator] = ImVec4(0.18f, 0.20f, 0.24f, 1.00f);
|
|
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.24f, 0.32f, 0.42f, 1.00f);
|
|
colors[ImGuiCol_SeparatorActive] = ImVec4(0.30f, 0.44f, 0.60f, 1.00f);
|
|
|
|
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.07f, 0.08f, 0.10f, 1.00f);
|
|
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.21f, 0.23f, 0.27f, 1.00f);
|
|
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.26f, 0.30f, 0.36f, 1.00f);
|
|
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.30f, 0.36f, 0.44f, 1.00f);
|
|
|
|
colors[ImGuiCol_CheckMark] = accent;
|
|
colors[ImGuiCol_SliderGrab] = accent;
|
|
colors[ImGuiCol_SliderGrabActive] = accentMuted;
|
|
|
|
colors[ImGuiCol_ResizeGrip] = ImVec4(0.22f, 0.26f, 0.33f, 1.00f);
|
|
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.32f, 0.46f, 0.62f, 0.80f);
|
|
colors[ImGuiCol_ResizeGripActive] = accent;
|
|
|
|
colors[ImGuiCol_DockingPreview] = ImVec4(0.33f, 0.63f, 0.98f, 0.60f);
|
|
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.05f, 0.06f, 0.07f, 1.00f);
|
|
|
|
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.33f, 0.63f, 0.98f, 0.25f);
|
|
colors[ImGuiCol_NavHighlight] = accent;
|
|
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.15f, 0.17f, 0.20f, 1.00f);
|
|
|
|
style.WindowRounding = 5.0f;
|
|
style.ChildRounding = 5.0f;
|
|
style.FrameRounding = 6.0f;
|
|
style.PopupRounding = 6.0f;
|
|
style.ScrollbarRounding = 10.0f;
|
|
style.GrabRounding = 6.0f;
|
|
style.TabRounding = 6.0f;
|
|
|
|
style.WindowPadding = ImVec2(10.0f, 10.0f);
|
|
style.FramePadding = ImVec2(9.0f, 5.0f);
|
|
style.ItemSpacing = ImVec2(10.0f, 6.0f);
|
|
style.ItemInnerSpacing = ImVec2(6.0f, 4.0f);
|
|
style.IndentSpacing = 18.0f;
|
|
|
|
style.WindowBorderSize = 1.0f;
|
|
style.FrameBorderSize = 1.0f;
|
|
style.PopupBorderSize = 1.0f;
|
|
style.TabBorderSize = 1.0f;
|
|
}
|
|
|
|
void setupDockspace(const std::function<void()>& menuBarContent) {
|
|
static bool dockspaceOpen = true;
|
|
static ImGuiDockNodeFlags dockspaceFlags = ImGuiDockNodeFlags_None;
|
|
|
|
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
|
|
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
|
ImGui::SetNextWindowPos(viewport->WorkPos);
|
|
ImGui::SetNextWindowSize(viewport->WorkSize);
|
|
ImGui::SetNextWindowViewport(viewport->ID);
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
|
windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
|
|
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
|
|
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
|
ImGui::Begin("DockSpace", &dockspaceOpen, windowFlags);
|
|
ImGui::PopStyleVar(3);
|
|
|
|
if (ImGui::BeginMenuBar()) {
|
|
if (menuBarContent) {
|
|
menuBarContent();
|
|
}
|
|
ImGui::EndMenuBar();
|
|
}
|
|
|
|
ImGuiID dockspaceId = ImGui::GetID("MainDockspace");
|
|
ImGui::DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockspaceFlags);
|
|
|
|
ImGui::End();
|
|
}
|