Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .github/resource/JetBrains.png
Binary file not shown.
Binary file modified .github/resource/Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Editor/Include/Editor/Panel/AssetsPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace Editor {
void RenderDirectoryTree(const std::filesystem::path& inDirectory, const char* inLabel);
void RenderDirectoryContents();
void RenderEntry(const AssetFileEntry& inEntry);
void RenderEntryContextMenu(const AssetFileEntry& inEntry, const char* inPopupId);
void RenderBackgroundMenu();
void RenderModals();
void HandleKeyboardShortcuts();
Expand Down
74 changes: 74 additions & 0 deletions Editor/Include/Editor/Theme/Theme.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once

#include <imgui.h>

namespace Editor {
class Theme final {
public:
Theme();
Theme(const Theme& inOther);
Theme(Theme&& inOther) noexcept;
~Theme();

Theme& operator=(const Theme& inOther);
Theme& operator=(Theme&& inOther) noexcept;

void Apply() const;

Theme& SetTextColor(const ImVec4& inColor);
Theme& SetTextDisabledColor(const ImVec4& inColor);
Theme& SetWindowBackgroundColor(const ImVec4& inColor);
Theme& SetPopupBackgroundColor(const ImVec4& inColor);
Theme& SetSurfaceColor(const ImVec4& inColor);
Theme& SetSurfaceHoveredColor(const ImVec4& inColor);
Theme& SetSurfaceActiveColor(const ImVec4& inColor);
Theme& SetAccentColor(const ImVec4& inColor);
Theme& SetAccentHoveredColor(const ImVec4& inColor);
Theme& SetAccentActiveColor(const ImVec4& inColor);
Theme& SetOnAccentColor(const ImVec4& inColor);
Theme& SetWarningColor(const ImVec4& inColor);
Theme& SetErrorColor(const ImVec4& inColor);

const ImVec4& GetTextColor() const;
const ImVec4& GetTextDisabledColor() const;
const ImVec4& GetWindowBackgroundColor() const;
const ImVec4& GetPopupBackgroundColor() const;
const ImVec4& GetSurfaceColor() const;
const ImVec4& GetSurfaceHoveredColor() const;
const ImVec4& GetSurfaceActiveColor() const;
const ImVec4& GetAccentColor() const;
const ImVec4& GetAccentHoveredColor() const;
const ImVec4& GetAccentActiveColor() const;
const ImVec4& GetOnAccentColor() const;
const ImVec4& GetWarningColor() const;
const ImVec4& GetErrorColor() const;

private:
ImVec4 textColor;
ImVec4 textDisabledColor;
ImVec4 windowBackgroundColor;
ImVec4 popupBackgroundColor;
ImVec4 surfaceColor;
ImVec4 surfaceHoveredColor;
ImVec4 surfaceActiveColor;
ImVec4 accentColor;
ImVec4 accentHoveredColor;
ImVec4 accentActiveColor;
ImVec4 onAccentColor;
ImVec4 warningColor;
ImVec4 errorColor;
};

class ThemeSwitcher final {
public:
ThemeSwitcher() = delete;
~ThemeSwitcher() = delete;

static const Theme& GetCurrentTheme();
static void SwitchTheme(Theme inTheme);
static void ApplyCurrentTheme();

private:
static Theme currentTheme;
};
}
5 changes: 5 additions & 0 deletions Editor/Include/Editor/Widget/IconWidgets.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
#include <string>
#include <string_view>

struct ImVec2;

namespace Editor::Widgets {
std::string Label(const char* inIcon, std::string_view inText);
std::string Label(const char* inIcon, std::string_view inText, std::string_view inId);
bool IconButton(const char* inId, const char* inIcon, const char* inTooltip);
bool PrimaryButton(const char* inLabel, const ImVec2& inSize);
void PushWarningTextColor();
void PushErrorTextColor();
}
Binary file added Editor/Resource/Image/Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 2 additions & 14 deletions Editor/Src/EditorApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <Core/Paths.h>
#include <Editor/EditorApplication.h>
#include <Editor/Panel/EditorPanelNames.h>
#include <Editor/Theme/Theme.h>
#include <Editor/Utils/ImGuiCompatibility.h>
#include <Editor/Widget/TablerIcons.h>
#include <Runtime/Engine.h>
Expand Down Expand Up @@ -71,19 +72,6 @@ namespace Editor::Internal {
return inDesc.mode == EditorApplicationMode::projectHub ? projectHubWindowHeight : defaultWindowHeight;
}

static void SetDarkStyle()
{
ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
style.WindowRounding = 0.0f;
style.ChildRounding = 2.0f;
style.FrameRounding = 2.0f;
style.PopupRounding = 2.0f;
style.ScrollbarRounding = 2.0f;
style.GrabRounding = 2.0f;
style.TabRounding = 2.0f;
}

static void LoadIconFonts(ImFontAtlas& inFontAtlas, float inSizePixels)
{
static ImVector<ImWchar> glyphRanges;
Expand Down Expand Up @@ -244,7 +232,7 @@ namespace Editor {
defaultFontConfig.SizePixels = Internal::defaultFontSize;
io.FontDefault = io.Fonts->AddFontDefaultVector(&defaultFontConfig);
Internal::LoadIconFonts(*io.Fonts, Internal::defaultFontSize);
Internal::SetDarkStyle();
ThemeSwitcher::ApplyCurrentTheme();
}

void EditorApplication::ShutdownImGui()
Expand Down
8 changes: 4 additions & 4 deletions Editor/Src/Frame/EditorFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,16 +316,16 @@ namespace Editor {
ImGui::Separator();
ImGui::BeginChild("LogEntries", ImVec2(0.0f, 0.0f), false, ImGuiWindowFlags_HorizontalScrollbar);
for (const auto& entry : entries) {
ImVec4 color = ImGui::GetStyleColorVec4(ImGuiCol_Text);
const char* levelIcon = Icons::Tabler::infoCircle;
if (entry.level == Core::LogLevel::warning) {
color = ImVec4(1.0f, 0.78f, 0.25f, 1.0f);
Widgets::PushWarningTextColor();
levelIcon = Icons::Tabler::alertTriangle;
} else if (entry.level == Core::LogLevel::error) {
color = ImVec4(1.0f, 0.35f, 0.32f, 1.0f);
Widgets::PushErrorTextColor();
levelIcon = Icons::Tabler::circleX;
} else {
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
}
ImGui::PushStyleColor(ImGuiCol_Text, color);
ImGui::TextUnformatted(std::format("{} [{}][{}][{}] {}", levelIcon, entry.time, Internal::LevelString(entry.level), entry.tag, entry.content).c_str());
ImGui::PopStyleColor();
}
Expand Down
41 changes: 9 additions & 32 deletions Editor/Src/Frame/ProjectHubFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,6 @@ namespace Editor::ProjectHub::Internal {
constexpr float actionButtonHeight = 58.0f;
constexpr float recentProjectHeight = 68.0f;
constexpr float contentSpacing = 12.0f;
const ImVec4 windowBackground(0.055f, 0.063f, 0.078f, 1.0f);
const ImVec4 cardBackground(0.09f, 0.102f, 0.125f, 1.0f);
const ImVec4 cardHovered(0.125f, 0.145f, 0.18f, 1.0f);
const ImVec4 accent(0.25f, 0.49f, 0.96f, 1.0f);
const ImVec4 accentHovered(0.31f, 0.55f, 1.0f, 1.0f);
const ImVec4 secondaryButton(0.12f, 0.137f, 0.17f, 1.0f);
const ImVec4 secondaryButtonHovered(0.16f, 0.18f, 0.22f, 1.0f);

static bool RenderActionButton(const char* inLabel, const ImVec2& inSize, const ImVec4& inColor, const ImVec4& inHoveredColor)
{
ImGui::PushStyleColor(ImGuiCol_Button, inColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, inHoveredColor);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, inHoveredColor);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 9.0f);
const bool clicked = ImGui::Button(inLabel, inSize);
ImGui::PopStyleVar();
ImGui::PopStyleColor(3);
return clicked;
}

static bool RenderRecentProject(const RecentProjectInfo& inProject)
{
Expand All @@ -57,8 +38,8 @@ namespace Editor::ProjectHub::Internal {
const bool hovered = ImGui::IsItemHovered();

ImDrawList* drawList = ImGui::GetWindowDrawList();
drawList->AddRectFilled(cardMin, cardMax, ImGui::GetColorU32(hovered ? cardHovered : cardBackground), 8.0f);
drawList->AddText(ImVec2(cardMin.x + 16.0f, cardMin.y + 26.0f), ImGui::GetColorU32(accent), Icons::Tabler::folder);
drawList->AddRectFilled(cardMin, cardMax, ImGui::GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 8.0f);
drawList->AddText(ImVec2(cardMin.x + 16.0f, cardMin.y + 26.0f), ImGui::GetColorU32(ImGuiCol_CheckMark), Icons::Tabler::folder);
drawList->PushClipRect(ImVec2(cardMin.x + 46.0f, cardMin.y), ImVec2(cardMax.x - 38.0f, cardMax.y), true);
drawList->AddText(ImVec2(cardMin.x + 46.0f, cardMin.y + 13.0f), ImGui::GetColorU32(ImGuiCol_Text), inProject.name.c_str());
drawList->AddText(ImVec2(cardMin.x + 46.0f, cardMin.y + 38.0f), ImGui::GetColorU32(ImGuiCol_TextDisabled), inProject.path.c_str());
Expand Down Expand Up @@ -150,7 +131,6 @@ namespace Editor {
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ProjectHub::Internal::windowBackground);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(26.0f, 24.0f));
ImGui::Begin(
Expand All @@ -161,7 +141,6 @@ namespace Editor {
| ImGuiWindowFlags_NoSavedSettings
| ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar(2);
ImGui::PopStyleColor();

RenderActionBar(inWindow, inRhiType);
ImGui::Dummy(ImVec2(0.0f, 22.0f));
Expand All @@ -175,15 +154,15 @@ namespace Editor {
const float spacing = ImGui::GetStyle().ItemSpacing.x;
const float buttonWidth = (ImGui::GetContentRegionAvail().x - spacing) * 0.5f;
const std::string openLabel = Widgets::Label(Icons::Tabler::folderOpen, "Open");
if (ProjectHub::Internal::RenderActionButton(openLabel.c_str(), ImVec2(buttonWidth, ProjectHub::Internal::actionButtonHeight), ProjectHub::Internal::accent, ProjectHub::Internal::accentHovered)) {
if (Widgets::PrimaryButton(openLabel.c_str(), ImVec2(buttonWidth, ProjectHub::Internal::actionButtonHeight))) {
if (const auto selectedDirectory = PlatformUtils::SelectDirectory("Open Explosion Project")) {
OpenProject(inWindow, *selectedDirectory, inRhiType);
}
}

ImGui::SameLine();
const std::string createLabel = Widgets::Label(Icons::Tabler::plus, "Create");
if (ProjectHub::Internal::RenderActionButton(createLabel.c_str(), ImVec2(buttonWidth, ProjectHub::Internal::actionButtonHeight), ProjectHub::Internal::secondaryButton, ProjectHub::Internal::secondaryButtonHovered)) {
if (ImGui::Button(createLabel.c_str(), ImVec2(buttonWidth, ProjectHub::Internal::actionButtonHeight))) {
statusMessage.clear();
ImGui::OpenPopup("##CreateProjectPopup");
}
Expand All @@ -200,7 +179,7 @@ namespace Editor {

if (!statusMessage.empty()) {
const std::string statusLabel = Widgets::Label(Icons::Tabler::circleX, statusMessage);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.42f, 0.42f, 1.0f));
Widgets::PushErrorTextColor();
ImGui::TextWrapped("%s", statusLabel.c_str());
ImGui::PopStyleColor();
ImGui::Dummy(ImVec2(0.0f, 7.0f));
Expand All @@ -218,10 +197,10 @@ namespace Editor {
if (recentProjects.empty()) {
const ImVec2 emptyMin = ImGui::GetCursorScreenPos();
const ImVec2 emptyMax(emptyMin.x + ImGui::GetContentRegionAvail().x, emptyMin.y + 118.0f);
ImGui::GetWindowDrawList()->AddRectFilled(emptyMin, emptyMax, ImGui::GetColorU32(ProjectHub::Internal::cardBackground), 8.0f);
ImGui::GetWindowDrawList()->AddRectFilled(emptyMin, emptyMax, ImGui::GetColorU32(ImGuiCol_FrameBg), 8.0f);
const char* title = "No recent projects";
const char* description = "Open an existing project or create a new one.";
ImGui::GetWindowDrawList()->AddText(ImVec2(emptyMin.x + 16.0f, emptyMin.y + 51.0f), ImGui::GetColorU32(ProjectHub::Internal::accent), Icons::Tabler::folderOff);
ImGui::GetWindowDrawList()->AddText(ImVec2(emptyMin.x + 16.0f, emptyMin.y + 51.0f), ImGui::GetColorU32(ImGuiCol_CheckMark), Icons::Tabler::folderOff);
ImGui::GetWindowDrawList()->AddText(ImVec2(emptyMin.x + 46.0f, emptyMin.y + 31.0f), ImGui::GetColorU32(ImGuiCol_Text), title);
ImGui::GetWindowDrawList()->AddText(ImVec2(emptyMin.x + 46.0f, emptyMin.y + 59.0f), ImGui::GetColorU32(ImGuiCol_TextDisabled), description);
ImGui::Dummy(ImVec2(0.0f, 118.0f));
Expand All @@ -238,7 +217,6 @@ namespace Editor {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(ImVec2(456.0f, 0.0f), ImGuiCond_Appearing);
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.075f, 0.086f, 0.105f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(24.0f, 22.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 11.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
Expand Down Expand Up @@ -289,7 +267,7 @@ namespace Editor {
if (!statusMessage.empty()) {
ImGui::Dummy(ImVec2(0.0f, 9.0f));
const std::string statusLabel = Widgets::Label(Icons::Tabler::circleX, statusMessage);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.42f, 0.42f, 1.0f));
Widgets::PushErrorTextColor();
ImGui::TextWrapped("%s", statusLabel.c_str());
ImGui::PopStyleColor();
}
Expand All @@ -304,7 +282,7 @@ namespace Editor {
}
ImGui::SameLine();
const std::string confirmLabel = Widgets::Label(Icons::Tabler::check, "Create##Confirm");
if (ProjectHub::Internal::RenderActionButton(confirmLabel.c_str(), ImVec2(88.0f, 36.0f), ProjectHub::Internal::accent, ProjectHub::Internal::accentHovered)) {
if (Widgets::PrimaryButton(confirmLabel.c_str(), ImVec2(88.0f, 36.0f))) {
const CreateProjectResult result = CreateProject();
if (result.success) {
statusMessage.clear();
Expand All @@ -317,7 +295,6 @@ namespace Editor {
ImGui::EndPopup();
}
ImGui::PopStyleVar(4);
ImGui::PopStyleColor();
}

CreateProjectResult ProjectHubFrame::CreateProject()
Expand Down
66 changes: 36 additions & 30 deletions Editor/Src/Panel/AssetsPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Created by johnk on 2026/7/18.
//

#include <algorithm>
#include <format>
#include <system_error>

Expand Down Expand Up @@ -89,11 +88,12 @@ namespace Editor {
RenderToolbar();
RenderBreadcrumbs();
if (!statusMessage.empty()) {
const ImVec4 color = statusIsError
? ImVec4(1.0f, 0.35f, 0.32f, 1.0f)
: ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
const std::string statusLabel = Widgets::Label(statusIsError ? Icons::Tabler::circleX : Icons::Tabler::infoCircle, statusMessage);
ImGui::PushStyleColor(ImGuiCol_Text, color);
if (statusIsError) {
Widgets::PushErrorTextColor();
} else {
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
}
ImGui::TextWrapped("%s", statusLabel.c_str());
ImGui::PopStyleColor();
}
Expand Down Expand Up @@ -260,31 +260,7 @@ namespace Editor {
if (inEntry.directory) {
HandleDropTarget(inEntry.path);
}
if (ImGui::BeginPopupContextItem("AssetEntryMenu")) {
selectedPath = inEntry.path;
const std::string openLabel = Widgets::Label(Icons::Tabler::externalLink, "Open");
if (ImGui::MenuItem(openLabel.c_str(), nullptr, false, inEntry.directory)) {
NavigateTo(inEntry.path);
}
ImGui::Separator();
const std::string cutLabel = Widgets::Label(Icons::Tabler::cut, "Cut");
if (ImGui::MenuItem(cutLabel.c_str(), "Ctrl+X")) {
SetClipboard(inEntry.path, ClipboardMode::move);
}
const std::string copyLabel = Widgets::Label(Icons::Tabler::copy, "Copy");
if (ImGui::MenuItem(copyLabel.c_str(), "Ctrl+C")) {
SetClipboard(inEntry.path, ClipboardMode::copy);
}
const std::string renameLabel = Widgets::Label(Icons::Tabler::edit, "Rename");
if (ImGui::MenuItem(renameLabel.c_str(), "F2")) {
OpenRenamePopup(inEntry.path);
}
const std::string deleteLabel = Widgets::Label(Icons::Tabler::trash, "Delete");
if (ImGui::MenuItem(deleteLabel.c_str(), "Delete")) {
OpenDeletePopup(inEntry.path);
}
ImGui::EndPopup();
}
RenderEntryContextMenu(inEntry, "AssetEntryMenu");

ImGui::TableSetColumnIndex(1);
ImGui::TextUnformatted(Internal::EntryType(inEntry).c_str());
Expand All @@ -297,6 +273,36 @@ namespace Editor {
ImGui::PopID();
}

void AssetsPanel::RenderEntryContextMenu(const AssetFileEntry& inEntry, const char* inPopupId)
{
if (!ImGui::BeginPopupContextItem(inPopupId)) {
return;
}
selectedPath = inEntry.path;
const std::string openLabel = Widgets::Label(Icons::Tabler::externalLink, "Open");
if (ImGui::MenuItem(openLabel.c_str(), nullptr, false, inEntry.directory)) {
NavigateTo(inEntry.path);
}
ImGui::Separator();
const std::string cutLabel = Widgets::Label(Icons::Tabler::cut, "Cut");
if (ImGui::MenuItem(cutLabel.c_str(), "Ctrl+X")) {
SetClipboard(inEntry.path, ClipboardMode::move);
}
const std::string copyLabel = Widgets::Label(Icons::Tabler::copy, "Copy");
if (ImGui::MenuItem(copyLabel.c_str(), "Ctrl+C")) {
SetClipboard(inEntry.path, ClipboardMode::copy);
}
const std::string renameLabel = Widgets::Label(Icons::Tabler::edit, "Rename");
if (ImGui::MenuItem(renameLabel.c_str(), "F2")) {
OpenRenamePopup(inEntry.path);
}
const std::string deleteLabel = Widgets::Label(Icons::Tabler::trash, "Delete");
if (ImGui::MenuItem(deleteLabel.c_str(), "Delete")) {
OpenDeletePopup(inEntry.path);
}
ImGui::EndPopup();
}

void AssetsPanel::RenderBackgroundMenu()
{
if (!ImGui::BeginPopupContextWindow("AssetBackgroundMenu", ImGuiPopupFlags_MouseButtonRight | ImGuiPopupFlags_NoOpenOverItems)) {
Expand Down
Loading
Loading