Files
WickedEngine/Editor/ContentBrowserWindow.cpp
T
Stanislav Denisov cdc6032380 Implement right-click open in new scene for content window (#1305)
Implement right-click open in new scene
2025-11-17 07:31:58 +01:00

450 lines
13 KiB
C++

#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");
}