#include "stdafx.h" #include "ContentBrowserWindow.h" using namespace wi::ecs; using namespace wi::scene; void ContentBrowserWindow::Create(EditorComponent* _editor) { editor = _editor; control_size = 30; wi::gui::Window::Create("Content Browser"); RemoveWidget(&scrollbar_horizontal); SetVisible(false); } static const float separator = 140; void ContentBrowserWindow::Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const { wi::gui::Window::Render(canvas, cmd); if (IsVisible() && !IsCollapsed()) { ApplyScissor(canvas, scissorRect, cmd); wi::image::Params params; params.pos = XMFLOAT3(translation.x + separator, translation.y + control_size, 0); params.siz = XMFLOAT2(2, scale.y - control_size); params.color = shadow_color; wi::image::Draw(nullptr, params, cmd); } } void ContentBrowserWindow::Update(const wi::Canvas& canvas, float dt) { wi::gui::Window::Update(canvas, dt); SetShadowRadius(6); const bool gui_round_enabled = !editor->generalWnd.disableRoundCornersCheckBox.GetCheck(); constexpr float radius = 15; for (int i = 0; i < arraysize(wi::gui::Widget::sprites); ++i) { if (gui_round_enabled) { sprites[i].params.enableCornerRounding(); sprites[i].params.corners_rounding[0].radius = radius; sprites[i].params.corners_rounding[1].radius = radius; sprites[i].params.corners_rounding[2].radius = radius; sprites[i].params.corners_rounding[3].radius = radius; openFolderButton.sprites[i].params.enableCornerRounding(); openFolderButton.sprites[i].params.corners_rounding[0].radius = radius; openFolderButton.sprites[i].params.corners_rounding[1].radius = radius; openFolderButton.sprites[i].params.corners_rounding[2].radius = radius; openFolderButton.sprites[i].params.corners_rounding[3].radius = radius; } else { sprites[i].params.disableCornerRounding(); openFolderButton.sprites[i].params.disableCornerRounding(); } } for (auto& x : folderButtons) { x.font.params.h_align = wi::font::WIFALIGN_LEFT; for (auto& y : x.sprites) { if (gui_round_enabled) { y.params.enableCornerRounding(); y.params.corners_rounding[3].radius = radius; } else { y.params.disableCornerRounding(); } } x.SetShadowRadius(0); } for (auto& x : itemButtons) { if (x.sprites[wi::gui::IDLE].textureResource.IsValid()) { x.sprites[wi::gui::IDLE].params.color = wi::Color::White(); } for (auto& y : x.sprites) { if (gui_round_enabled) { y.params.enableCornerRounding(); y.params.corners_rounding[0].radius = radius; y.params.corners_rounding[1].radius = radius; y.params.corners_rounding[2].radius = radius; y.params.corners_rounding[3].radius = radius; } else { y.params.disableCornerRounding(); } } x.SetShadowRadius(4); } openFolderButton.SetShadowRadius(0); const XMFLOAT4 color_on = sprites[wi::gui::FOCUS].params.color; const XMFLOAT4 color_off = sprites[wi::gui::IDLE].params.color; for (auto& x : folderButtons) { x.sprites[wi::gui::IDLE].params.color = color_off; } if (current_selection < SELECTION_COUNT) { folderButtons[current_selection].sprites[wi::gui::IDLE].params.color = color_on; } } void ContentBrowserWindow::ResizeLayout() { wi::gui::Window::ResizeLayout(); const float padding = 4; const float width = GetWidgetAreaSize().x; float y = padding; openFolderButton.Detach(); openFolderButton.SetPos(XMFLOAT2(translation.x + padding, translation.y + scale.y - openFolderButton.GetSize().y - padding)); openFolderButton.SetSize(XMFLOAT2(separator - padding * 2, openFolderButton.GetSize().y)); openFolderButton.AttachTo(this); size_t seli = 0; for (auto& x : folderButtons) { x.Detach(); x.SetPos(XMFLOAT2(translation.x + padding, translation.y + control_size + y)); x.SetSize(XMFLOAT2(separator - padding * 2, x.GetSize().y)); y += x.GetSize().y + padding; x.AttachTo(this); seli++; if (seli == SELECTION_RECENTFOLDER_BEGIN) y += x.GetSize().y + padding; } y = padding + 10; float sep = separator + 10; float hoffset = sep; for (auto& x : itemButtons) { x.SetPos(XMFLOAT2(hoffset, y)); hoffset += x.GetSize().x + 15; if (hoffset + x.GetSize().x >= width) { hoffset = sep; y += x.GetSize().y + 40; } } } void ContentBrowserWindow::RefreshContent() { content_folder = wi::helper::GetCurrentPath() + "/Content/"; wi::helper::MakePathAbsolute(content_folder); if (!wi::helper::FileExists(content_folder)) { content_folder = wi::helper::GetCurrentPath() + "/../Content/"; wi::helper::MakePathAbsolute(content_folder); } float hei = 25; float wid = 120; for (auto& x : folderButtons) { RemoveWidget(&x); } if (!editor->recentFilenames.empty()) { wi::gui::Button& button = folderButtons[SELECTION_RECENT]; button.Create("Recently Used"); button.SetTooltip("List all recently used files, not grouped by folders."); button.SetLocalizationEnabled(false); button.SetSize(XMFLOAT2(wid, hei)); button.OnClick([this](wi::gui::EventArgs args) { SetSelection(SELECTION_RECENT); }); AddWidget(&button, wi::gui::Window::AttachmentOptions::NONE); if (current_selection == SELECTION_COUNT) { current_selection = SELECTION_RECENT; } } if (wi::helper::DirectoryExists(content_folder + "models")) { wi::gui::Button& button = folderButtons[SELECTION_MODELS]; button.Create("Models"); button.SetTooltip(content_folder + "models"); button.SetLocalizationEnabled(false); button.SetSize(XMFLOAT2(wid, hei)); button.OnClick([this](wi::gui::EventArgs args) { SetSelection(SELECTION_MODELS); }); AddWidget(&button, wi::gui::Window::AttachmentOptions::NONE); if (current_selection == SELECTION_COUNT) { current_selection = SELECTION_MODELS; } } if (wi::helper::DirectoryExists(content_folder + "scripts")) { wi::gui::Button& button = folderButtons[SELECTION_SCRIPTS]; button.Create("Scripts"); button.SetTooltip(content_folder + "scripts"); button.SetLocalizationEnabled(false); button.SetSize(XMFLOAT2(wid, hei)); button.OnClick([this](wi::gui::EventArgs args) { SetSelection(SELECTION_SCRIPTS); }); AddWidget(&button, wi::gui::Window::AttachmentOptions::NONE); if (current_selection == SELECTION_COUNT) { current_selection = SELECTION_SCRIPTS; } } for (size_t i = 0; i < editor->recentFolders.size(); ++i) { wi::gui::Button& button = folderButtons[SELECTION_RECENTFOLDER_BEGIN + i]; std::string folder = editor->recentFolders[editor->recentFolders.size() - 1 - i]; while (!folder.empty() && (folder.back() == '/' || folder.back() == '\\')) { folder.pop_back(); } auto last_slash = folder.find_last_of("/\\"); if (last_slash != folder.npos) { folder = folder.substr(last_slash); } button.Create(folder); button.SetTooltip(editor->recentFolders[editor->recentFolders.size() - 1 - i]); // full folder name! button.SetLocalizationEnabled(false); button.SetSize(XMFLOAT2(wid, hei)); button.OnClick([this, i](wi::gui::EventArgs args) { SetSelection((SELECTION)(SELECTION_RECENTFOLDER_BEGIN + i)); }); AddWidget(&button, wi::gui::Window::AttachmentOptions::NONE); if (current_selection == SELECTION_COUNT) { current_selection = (SELECTION)(SELECTION_RECENTFOLDER_BEGIN + i); } } if (current_selection != SELECTION_COUNT) { SetSelection(current_selection); } } void ContentBrowserWindow::SetSelection(SELECTION selection) { wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { current_selection = selection; for (auto& x : itemButtons) { RemoveWidget(&x); } itemButtons.clear(); RemoveWidget(&openFolderButton); openFolderButton.Create(ICON_OPEN " Go to location"); openFolderButton.SetSize(XMFLOAT2(60, 60)); switch (selection) { case SELECTION_SCRIPTS: AddItems(content_folder + "scripts/", "lua", ICON_SCRIPT); openFolderButton.OnClick([this](wi::gui::EventArgs args) { wi::helper::OpenUrl(content_folder + "scripts/"); }); AddWidget(&openFolderButton, wi::gui::Window::AttachmentOptions::NONE); break; case SELECTION_MODELS: AddItems(content_folder + "models/", "wiscene", ICON_OBJECT); AddItems(content_folder + "models/", "vrma", ICON_ANIMATION); AddItems(content_folder + "models/", "vrm", ICON_HUMANOID); AddItems(content_folder + "models/", "gltf", ICON_OBJECT); AddItems(content_folder + "models/", "glb", ICON_OBJECT); AddItems(content_folder + "models/", "fbx", ICON_OBJECT); AddItems(content_folder + "models/", "obj", ICON_OBJECT); openFolderButton.OnClick([this](wi::gui::EventArgs args) { wi::helper::OpenUrl(content_folder + "models/"); }); AddWidget(&openFolderButton, wi::gui::Window::AttachmentOptions::NONE); break; case SELECTION_RECENT: for (size_t i = 0; i < editor->recentFilenames.size(); ++i) { const std::string& filename = editor->recentFilenames[editor->recentFilenames.size() - 1 - i]; std::string ext = wi::helper::toUpper(wi::helper::GetExtensionFromFileName(filename)); if (!ext.compare("LUA")) { AddItem(filename, ICON_SCRIPT); } if (!ext.compare("WISCENE")) { AddItem(filename, ICON_OBJECT); } if (!ext.compare("VRMA")) { AddItem(filename, ICON_ANIMATION); } if (!ext.compare("VRM")) { AddItem(filename, ICON_HUMANOID); } if (!ext.compare("GLTF")) { AddItem(filename, ICON_OBJECT); } if (!ext.compare("GLB")) { AddItem(filename, ICON_OBJECT); } if (!ext.compare("FBX")) { AddItem(filename, ICON_OBJECT); } if (!ext.compare("OBJ")) { AddItem(filename, ICON_OBJECT); } } break; default: { size_t i = selection - SELECTION_RECENTFOLDER_BEGIN; i = std::min(i, editor->recentFolders.size() - 1); const std::string& folder = editor->recentFolders[editor->recentFolders.size() - 1 - i]; AddItems(folder, "wiscene", ICON_OBJECT); AddItems(folder, "vrma", ICON_ANIMATION); AddItems(folder, "vrm", ICON_HUMANOID); AddItems(folder, "gltf", ICON_OBJECT); AddItems(folder, "glb", ICON_OBJECT); AddItems(folder, "fbx", ICON_OBJECT); AddItems(folder, "obj", ICON_OBJECT); AddItems(folder, "lua", ICON_SCRIPT); openFolderButton.OnClick([folder](wi::gui::EventArgs args) { wi::helper::OpenUrl(folder); }); AddWidget(&openFolderButton, wi::gui::Window::AttachmentOptions::NONE); } break; } for (auto& x : itemButtons) { AddWidget(&x); } editor->generalWnd.RefreshTheme(); }); } void ContentBrowserWindow::AddItems(const std::string& folder, const std::string& extension, const std::string& icon) { // Folders parse: wi::helper::GetFolderNamesInDirectory(folder, [&](std::string foldername) { std::string itemname = foldername.substr(folder.size()) + "." + extension; std::string filename = foldername + "/" + itemname; if (wi::helper::FileExists(filename)) { AddItem(filename, icon); } }); // Individual items: wi::helper::GetFileNamesInDirectory(folder, [&](std::string filename) { AddItem(filename, icon); }, extension); } void ContentBrowserWindow::AddItem(const std::string& filename, const std::string& icon) { static const XMFLOAT2 siz = XMFLOAT2(240, 120); if (!wi::helper::FileExists(filename)) return; std::string itemname = wi::helper::GetFileNameFromPath(filename); std::string foldername = wi::helper::GetDirectoryFromPath(filename); std::string ext = wi::helper::toUpper(wi::helper::GetExtensionFromFileName(filename)); wi::gui::Button& button = itemButtons.emplace_back(); button.Create(icon); button.SetSize(siz); button.SetLocalizationEnabled(false); button.SetDescription(itemname); button.OnClick([this, filename](wi::gui::EventArgs args) { wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { editor->Open(filename); }); this->SetVisible(false); }); button.OnRightClick([this, filename](wi::gui::EventArgs args) { wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { editor->NewScene(); editor->Open(filename); }); this->SetVisible(false); }); button.font_description.params.h_align = wi::font::WIFALIGN_CENTER; button.font_description.params.v_align = wi::font::WIFALIGN_TOP; button.font.params.size = 42; button.SetTooltip(filename + "\nSize: " + wi::helper::GetMemorySizeText(wi::helper::FileSize(filename))); if (ext.compare("WISCENE") == 0) { wi::Archive::Header archive_header; wi::graphics::Texture archiveThumbnail = wi::Archive::PeekThumbnail(filename, &archive_header); if (archiveThumbnail.IsValid()) { for (int i = 0; i < arraysize(sprites); ++i) { button.sprites[i].textureResource.SetTexture(archiveThumbnail); } button.SetText(""); } button.SetTooltip(button.GetTooltip() + "\nVersion: " + std::to_string(archive_header.version) + (archive_header.properties.bits.compressed ? "\nCompressed : true" : "\nCompressed : false")); } else { std::string thumbnailName = foldername + "/thumbnail.png"; if (wi::helper::FileExists(thumbnailName)) { wi::Resource thumbnail = wi::resourcemanager::Load(thumbnailName); if (thumbnail.IsValid()) { for (int i = 0; i < arraysize(sprites); ++i) { button.sprites[i].textureResource = thumbnail; } button.SetText(""); } } } button.SetTooltip(button.GetTooltip() + "\n\nLeft-click: Merge into current scene\nRight-click: Open in new scene tab"); }