// File: src/FileBrowser.cpp #include "FileBrowser.h" #include namespace OX { FileBrowser::FileBrowser() = default; FileBrowser::~FileBrowser() = default; void FileBrowser::SetFilter(const std::string &f) { _filter = f; } void FileBrowser::SetFileSelectedCallback(FileSelectedCallback cb) { _onFileSelected = std::move(cb); } void FileBrowser::Draw(const char *title) { ImGui::Begin(title); // --- toolbar now contains back button, inline path, filter & view toggle all on one row --- DrawToolbar(); // main content auto root = AssetManager::GetFileTree(); std::function(std::shared_ptr, const std::string &)> find = [&](auto node, const std::string &path)-> std::shared_ptr { if (node->path == path) return node; for (auto &c: node->children) { if (c->isDirectory) { if (auto f = find(c, path)) return f; } } return nullptr; }; auto node = find(root, _currentPath); if (!node) { ImGui::TextColored(ImGui::GetStyle().Colors[ImGuiCol_TextDisabled], "Path not found: %s", _currentPath.c_str()); } else if (_gridMode) { DrawGridView(node); } else { DrawListView(node); } ImGui::End(); } // ——— Combined toolbar & inline path ——— void FileBrowser::DrawToolbar() { // back button if (_currentPath != "res://") { if (ImGui::Button("Back")) { auto pos = _currentPath.find_last_of('/'); _currentPath = (pos != std::string::npos && pos > 6) ? _currentPath.substr(0, pos) : "res://"; } } ImGui::SameLine(); // inline, non-interactive path text ImGui::Text("%s", _currentPath.c_str()); ImGui::SameLine(); // filter input takes all remaining space float avail = ImGui::GetContentRegionAvail().x; ImGui::PushItemWidth(avail * 0.5f); //ImGui::InputTextWithHint("##filter", "Filter files...", _filter.c_str(), ImGuiInputTextFlags_AutoSelectAll); ImGui::PopItemWidth(); ImGui::SameLine(); // grid/list toggle if (_gridMode) { if (ImGui::Button("List View")) _gridMode = false; } else { if (ImGui::Button("Grid View")) _gridMode = true; } ImGui::Separator(); } // ——— Polished grid view ——— void FileBrowser::DrawGridView(const std::shared_ptr &node) { const float cellW = _cfg.thumbnailSize + _cfg.padding * 2; ImVec2 avail = ImGui::GetContentRegionAvail(); int cols = std::max(1, int(avail.x / cellW)); ImGui::BeginChild("GridRegion", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysUseWindowPadding); ImGui::Columns(cols, nullptr, false); for (auto &c: node->children) { if (!_filter.empty() && !PassesFilter(c->name)) continue; if (!c) return; ImGui::PushID(c->path.c_str()); ImGui::BeginGroup(); // invisible button as hit target ImVec2 btnSize(cellW, _cfg.thumbnailSize + _cfg.labelHeight + _cfg.padding); ImGui::InvisibleButton("cell", btnSize); bool hovered = ImGui::IsItemHovered(); bool clicked = ImGui::IsItemClicked(); // background rect ImVec2 mn = ImGui::GetItemRectMin(); ImVec2 mx = ImGui::GetItemRectMax(); ImU32 bg = hovered ? _cfg.highlightColor : _cfg.bgColor; ImGui::GetWindowDrawList() ->AddRectFilled(mn, mx, bg, 4.0f); // thumbnail or icon ImGui::SetCursorScreenPos({mn.x + _cfg.padding, mn.y + _cfg.padding}); if (c->isDirectory) { ImGui::Image(GetIconTexture(*c), {_cfg.thumbnailSize, _cfg.thumbnailSize}); } else { auto asset = AssetManager::Get(c->path); if (asset && asset->GetTypeName() == "texture2D") { auto tex = std::static_pointer_cast(asset); ImGui::Image((ImTextureID) (intptr_t) tex->GetID(), {_cfg.thumbnailSize, _cfg.thumbnailSize}, {0, 1}, {1, 0}); } else { ImGui::Dummy({_cfg.thumbnailSize, _cfg.thumbnailSize}); } } // label ImGui::SetCursorScreenPos({mn.x + _cfg.padding, mx.y - _cfg.labelHeight}); ImGui::PushTextWrapPos(mx.x); ImGui::TextUnformatted(c->name.c_str()); ImGui::PopTextWrapPos(); // click handling if (clicked) { if (c->isDirectory) { _currentPath = c->path; } else if (_onFileSelected) { _onFileSelected(c->path); } } ImGui::EndGroup(); ImGui::NextColumn(); ImGui::PopID(); } ImGui::Columns(1); ImGui::EndChild(); } // ——— Simple list view ——— void FileBrowser::DrawListView(const std::shared_ptr &node) { ImGui::BeginChild("ListRegion", ImVec2(0, 0), false); for (auto &c: node->children) { if (!_filter.empty() && !PassesFilter(c->name)) continue; if (ImGui::Selectable(c->name.c_str(), false, ImGuiSelectableFlags_AllowDoubleClick)) { if (ImGui::IsMouseDoubleClicked(0)) { if (c->isDirectory) { _currentPath = c->path; } else if (_onFileSelected) { _onFileSelected(c->path); } } } } ImGui::EndChild(); } bool FileBrowser::PassesFilter(const std::string &name) const { return _filter.empty() || (name.find(_filter) != std::string::npos); } ImTextureID FileBrowser::GetIconTexture(const ResourceTreeNode &node) { return 0; } } // namespace OX