diff --git a/Sources/OvEditor/include/OvEditor/Core/EditorActions.h b/Sources/OvEditor/include/OvEditor/Core/EditorActions.h index 973473694..b205a9acd 100644 --- a/Sources/OvEditor/include/OvEditor/Core/EditorActions.h +++ b/Sources/OvEditor/include/OvEditor/Core/EditorActions.h @@ -19,6 +19,7 @@ #define EDITOR_EVENT(target) OvCore::Global::ServiceLocator::Get().target #define EDITOR_CONTEXT(instance) OvCore::Global::ServiceLocator::Get().GetContext().instance #define EDITOR_PANEL(type, id) OvCore::Global::ServiceLocator::Get().GetPanelsManager().GetPanelAs(id) +#define EDITOR_UI_SCALE EDITOR_CONTEXT(uiManager)->GetScale() namespace tinyxml2 { diff --git a/Sources/OvEditor/include/OvEditor/Settings/EFontSize.h b/Sources/OvEditor/include/OvEditor/Settings/EFontSize.h deleted file mode 100644 index 867d03090..000000000 --- a/Sources/OvEditor/include/OvEditor/Settings/EFontSize.h +++ /dev/null @@ -1,30 +0,0 @@ -/** -* @project: Overload -* @author: Overload Tech. -* @licence: MIT -*/ - -#pragma once - -namespace OvEditor::Settings -{ - enum class EFontSize - { - SMALL = 0, - MEDIUM = 1, - BIG = 2, - DEFAULT = MEDIUM - }; - - constexpr std::string_view GetFontID(EFontSize p_size) - { - switch (p_size) - { - case EFontSize::SMALL: return "Small"; - case EFontSize::MEDIUM: return "Medium"; - case EFontSize::BIG: return "Big"; - } - - return {}; - } -} diff --git a/Sources/OvEditor/include/OvEditor/Settings/EditorSettings.h b/Sources/OvEditor/include/OvEditor/Settings/EditorSettings.h index 531cea012..788b15213 100644 --- a/Sources/OvEditor/include/OvEditor/Settings/EditorSettings.h +++ b/Sources/OvEditor/include/OvEditor/Settings/EditorSettings.h @@ -8,7 +8,6 @@ #include -#include #include #include @@ -99,7 +98,8 @@ namespace OvEditor::Settings inline static Property ScalingSnapUnit = { 1.0f }; inline static Property ColorTheme = { static_cast(OvUI::Styling::EStyle::DEFAULT_DARK) }; inline static Property ConsoleMaxLogs = { 500 }; - inline static Property FontSize = { static_cast(EFontSize::DEFAULT) }; + inline static Property UIScale = { 100 }; + inline static Property BetaDpiAwarenessDialogPresented = { false }; inline static Property CodeEditorCommand = { "code {workdir} --goto {path}" }; inline static Property RegenerateScriptingProjectFilesOnStartup = { true }; }; diff --git a/Sources/OvEditor/src/OvEditor/Core/Context.cpp b/Sources/OvEditor/src/OvEditor/Core/Context.cpp index 91de825ed..6c50e96c9 100644 --- a/Sources/OvEditor/src/OvEditor/Core/Context.cpp +++ b/Sources/OvEditor/src/OvEditor/Core/Context.cpp @@ -15,6 +15,7 @@ #include #include #include +#include using namespace OvCore::Global; using namespace OvCore::ResourceManagement; @@ -117,25 +118,22 @@ OvEditor::Core::Context::Context(const std::filesystem::path& p_projectFolder) : std::filesystem::create_directories(Utils::FileSystem::kEditorDataPath); - uiManager = std::make_unique(window->GetGlfwWindow(), + uiManager = std::make_unique( + *window, static_cast(OvEditor::Settings::EditorSettings::ColorTheme.Get()) ); - const auto fontPath = editorAssetsPath / "Fonts" / "Ruda-Bold.ttf"; - if (!std::filesystem::exists(OvEditor::Utils::FileSystem::kLayoutFilePath)) { const auto defaultLayoutPath = std::filesystem::current_path() / "Config" / "layout.ini"; uiManager->ResetLayout(defaultLayoutPath.string()); } - uiManager->LoadFont(std::string{ Settings::GetFontID(Settings::EFontSize::BIG) }, fontPath.string(), 18); - uiManager->LoadFont(std::string{ Settings::GetFontID(Settings::EFontSize::MEDIUM) }, fontPath.string(), 15); - uiManager->LoadFont(std::string{ Settings::GetFontID(Settings::EFontSize::SMALL) }, fontPath.string(), 12); - uiManager->UseFont(std::string{ Settings::GetFontID( - static_cast(Settings::EditorSettings::FontSize.Get()) - ) }); - + const auto fontPath = editorAssetsPath / "Fonts" / "Ruda-Bold.ttf"; + uiManager->LoadFont("Ruda-Bold", fontPath.string(), 15); + uiManager->UseFont("Ruda-Bold"); + const int uiScale = Settings::EditorSettings::UIScale.Get(); + uiManager->SetScale(uiScale == 0 ? std::nullopt : std::make_optional(uiScale / 100.0f)); uiManager->SetEditorLayoutSaveFilename(OvEditor::Utils::FileSystem::kLayoutFilePath.string()); uiManager->SetEditorLayoutAutosaveFrequency(60.0f); uiManager->EnableEditorLayoutSave(true); diff --git a/Sources/OvEditor/src/OvEditor/Core/ProjectHub.cpp b/Sources/OvEditor/src/OvEditor/Core/ProjectHub.cpp index e3db7b4c4..2d1cb3aba 100644 --- a/Sources/OvEditor/src/OvEditor/Core/ProjectHub.cpp +++ b/Sources/OvEditor/src/OvEditor/Core/ProjectHub.cpp @@ -45,10 +45,14 @@ namespace OvEditor::Core SetSize({ 1000, 580 }); SetPosition({ 0.f, 0.f }); - auto& openProjectButton = CreateWidget("Open Project"); - auto& newProjectButton = CreateWidget("New Project"); - auto& pathField = CreateWidget(""); - m_goButton = &CreateWidget("GO"); + auto& actionBar = CreateWidget(); + actionBar.horizontal = true; + actionBar.stretchWidget = 2; + + auto& openProjectButton = actionBar.CreateWidget("Open Project"); + auto& newProjectButton = actionBar.CreateWidget("New Project"); + auto& pathField = actionBar.CreateWidget(""); + m_goButton = &actionBar.CreateWidget("GO"); pathField.ContentChangedEvent += [this, &pathField](std::string p_content) { pathField.content = std::filesystem::path{ @@ -118,7 +122,7 @@ namespace OvEditor::Core auto& columns = CreateWidget>(); - columns.widths = { 750, 500 }; + columns.widths = { -1, 0 }; // Sanitize the project registry before displaying it, so we avoid showing // corrupted/deleted projects. @@ -162,11 +166,8 @@ namespace OvEditor::Core void Draw() override { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 50.f, 50.f }); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.f); - OvUI::Panels::PanelWindow::Draw(); - - ImGui::PopStyleVar(2); + ImGui::PopStyleVar(1); } private: @@ -281,19 +282,43 @@ void OvEditor::Core::ProjectHub::SetupContext() /* Graphics context creation */ m_driver = std::make_unique(OvRendering::Settings::DriverSettings{ false }); - m_uiManager = std::make_unique(m_window->GetGlfwWindow(), + // DPI awareness BETA option + const auto windowContentScale = m_window->GetContentScale(); + const auto unifiedWindowContentScale = std::max(windowContentScale.first, windowContentScale.second); + + if (!Settings::EditorSettings::BetaDpiAwarenessDialogPresented.Get() && unifiedWindowContentScale > 1.0f) + { + Settings::EditorSettings::BetaDpiAwarenessDialogPresented.Set(true); + const auto dpiAwarenessDialog = OvWindowing::Dialogs::MessageBox( + "High DPI Monitor Detected", + "Overload has detected that you might be running the editor from a high DPI monitor.\n\n" + "Support for automatic DPI-scaling is currently in BETA and might result in weird spacings, " + "icon sizes, layouts, and window sizes.\n\n" + "Do you want to enable automatic DPI scaling anyway?\n\n" + "(You can change this setting anytime from the menu bar: Settings > Appearance)", + OvWindowing::Dialogs::MessageBox::EMessageType::QUESTION, + OvWindowing::Dialogs::MessageBox::EButtonLayout::YES_NO + ); + switch (dpiAwarenessDialog.GetUserAction()) + { + case OvWindowing::Dialogs::MessageBox::EUserAction::YES: + Settings::EditorSettings::UIScale.Set(0); + default: break; + } + } + + m_uiManager = std::make_unique( + *m_window, static_cast(OvEditor::Settings::EditorSettings::ColorTheme.Get()) ); const auto fontPath = std::filesystem::current_path() / "Data" / "Editor" / "Fonts" / "Ruda-Bold.ttf"; - m_uiManager->LoadFont(std::string{ Settings::GetFontID(Settings::EFontSize::BIG) }, fontPath.string(), 20); - m_uiManager->LoadFont(std::string{ Settings::GetFontID(Settings::EFontSize::MEDIUM) }, fontPath.string(), 18); - m_uiManager->LoadFont(std::string{ Settings::GetFontID(Settings::EFontSize::SMALL) }, fontPath.string(), 16); - m_uiManager->UseFont(std::string{ Settings::GetFontID( - static_cast(Settings::EditorSettings::FontSize.Get()) - ) }); - + m_uiManager->LoadFont("Ruda-Bold", fontPath.string(), 18); + m_uiManager->UseFont("Ruda-Bold"); + const int uiScale = Settings::EditorSettings::UIScale.Get(); + m_uiManager->SetScale(uiScale == 0 ? std::nullopt : std::make_optional(uiScale / 100.0f)); m_uiManager->EnableEditorLayoutSave(false); m_uiManager->EnableDocking(false); } + diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetProperties.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetProperties.cpp index a5712132f..e7085bb03 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetProperties.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetProperties.cpp @@ -56,12 +56,12 @@ OvEditor::Panels::AssetProperties::AssetProperties m_settings = &CreateWidget("Settings"); m_settings->neverDisabled = true; m_settingsColumns = &m_settings->CreateWidget>(); - m_settingsColumns->widths[0] = 150; + m_settingsColumns->widths[0] = 150 * EDITOR_UI_SCALE; m_info = &CreateWidget("Info"); m_info->neverDisabled = true; m_infoColumns = &m_info->CreateWidget>(); - m_infoColumns->widths[0] = 150; + m_infoColumns->widths[0] = 150 * EDITOR_UI_SCALE; m_settings->enabled = m_info->enabled = false; } @@ -178,7 +178,7 @@ void OvEditor::Panels::AssetProperties::CreateHeaderButtons() void OvEditor::Panels::AssetProperties::CreateAssetSelector() { auto& columns = CreateWidget>(); - columns.widths[0] = 150; + columns.widths[0] = 150 * EDITOR_UI_SCALE; m_assetSelector = &OvCore::Helpers::GUIDrawer::DrawAsset(columns, "Target", m_resource, &m_targetChanged); const auto& widgets = columns.GetWidgets(); widgets[widgets.size() - 1].first->neverDisabled = true; diff --git a/Sources/OvEditor/src/OvEditor/Panels/Console.cpp b/Sources/OvEditor/src/OvEditor/Panels/Console.cpp index 9e18832fd..e97de39e3 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/Console.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/Console.cpp @@ -56,7 +56,6 @@ OvEditor::Panels::Console::Console allowHorizontalScrollbar = true; auto& clearButton = CreateWidget("Clear"); - clearButton.size = { 50.f, 0.f }; clearButton.idleBackgroundColor = { 0.5f, 0.f, 0.f }; clearButton.ClickedEvent += std::bind(&Console::Clear, this); clearButton.lineBreak = false; diff --git a/Sources/OvEditor/src/OvEditor/Panels/Inspector.cpp b/Sources/OvEditor/src/OvEditor/Panels/Inspector.cpp index a5d686a0a..6eed3e963 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/Inspector.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/Inspector.cpp @@ -346,7 +346,7 @@ void OvEditor::Panels::Inspector::_DrawComponent(AComponent& p_component, int p_ auto& columns = header.CreateWidget>(); columns.SetID("comp_" + p_component.GetName()); - columns.widths[0] = 200; + columns.widths[0] = 200 * EDITOR_UI_SCALE; p_component.OnInspector(columns); } @@ -379,7 +379,7 @@ void OvEditor::Panels::Inspector::_DrawBehaviour(Behaviour& p_behaviour, int p_i auto& columns = header.CreateWidget>(); columns.SetID("bhv_" + p_behaviour.name); - columns.widths[0] = 200; + columns.widths[0] = 200 * EDITOR_UI_SCALE; p_behaviour.OnInspector(columns); } diff --git a/Sources/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp b/Sources/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp index 0e7454228..204dec742 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/MaterialEditor.cpp @@ -263,7 +263,7 @@ void OvEditor::Panels::MaterialEditor::CreateHeaderButtons() void OvEditor::Panels::MaterialEditor::CreateMaterialSelector() { auto& columns = CreateWidget>(); - columns.widths[0] = 150; + columns.widths[0] = 150 * EDITOR_UI_SCALE; m_targetMaterialText = &GUIDrawer::DrawMaterial(columns, "Material", m_target, &m_materialDroppedEvent); const auto& widgets = columns.GetWidgets(); widgets[widgets.size() - 1].first->neverDisabled = true; @@ -273,7 +273,7 @@ void OvEditor::Panels::MaterialEditor::CreateMaterialSelector() void OvEditor::Panels::MaterialEditor::CreateShaderSelector() { auto& columns = m_settings->CreateWidget>(); - columns.widths[0] = 150; + columns.widths[0] = 150 * EDITOR_UI_SCALE; m_shaderText = &GUIDrawer::DrawShader(columns, "Shader", m_shader, &m_shaderDroppedEvent); } @@ -282,12 +282,12 @@ void OvEditor::Panels::MaterialEditor::CreateMaterialSettings() m_materialPipelineState = &m_settings->CreateWidget("Pipeline State"); m_materialPipelineState->neverDisabled = true; m_materialPipelineStateColumns = &m_materialPipelineState->CreateWidget>(); - m_materialPipelineStateColumns->widths[0] = 150; + m_materialPipelineStateColumns->widths[0] = 150 * EDITOR_UI_SCALE; m_materialSettings = &m_settings->CreateWidget("Settings"); m_materialSettings->neverDisabled = true; m_materialSettingsColumns = &m_materialSettings->CreateWidget>(); - m_materialSettingsColumns->widths[0] = 150; + m_materialSettingsColumns->widths[0] = 150 * EDITOR_UI_SCALE; } void OvEditor::Panels::MaterialEditor::CreateMaterialFeatures() @@ -295,7 +295,7 @@ void OvEditor::Panels::MaterialEditor::CreateMaterialFeatures() m_materialFeatures = &m_settings->CreateWidget("Features"); m_materialFeatures->neverDisabled = true; m_materialFeaturesColumns = &m_materialFeatures->CreateWidget>(); - m_materialFeaturesColumns->widths[0] = 150; + m_materialFeaturesColumns->widths[0] = 150 * EDITOR_UI_SCALE; } void OvEditor::Panels::MaterialEditor::CreateMaterialProperties() @@ -303,7 +303,7 @@ void OvEditor::Panels::MaterialEditor::CreateMaterialProperties() m_materialProperties = &m_settings->CreateWidget("Properties"); m_materialProperties->neverDisabled = true; m_materialPropertiesColumns = &m_materialProperties->CreateWidget>(); - m_materialPropertiesColumns->widths[0] = 150; + m_materialPropertiesColumns->widths[0] = 150 * EDITOR_UI_SCALE; } void OvEditor::Panels::MaterialEditor::GenerateMaterialSettingsContent() diff --git a/Sources/OvEditor/src/OvEditor/Panels/MenuBar.cpp b/Sources/OvEditor/src/OvEditor/Panels/MenuBar.cpp index f91460abd..7a8d85b55 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/MenuBar.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/MenuBar.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "OvEditor/Core/EditorActions.h" #include "OvEditor/Panels/AssetView.h" @@ -34,6 +35,7 @@ #include "OvEditor/Panels/SceneView.h" #include "OvEditor/Settings/EditorSettings.h" #include "OvEditor/Utils/ActorCreationMenu.h" +#include "OvUI/Widgets/Selection/CheckBox.h" using namespace OvUI::Panels; using namespace OvUI::Widgets; @@ -74,10 +76,10 @@ void OvEditor::Panels::MenuBar::HandleShortcuts(float p_deltaTime) void OvEditor::Panels::MenuBar::InitializeSettingsMenu() { - auto& themeButton = m_settingsMenu->CreateWidget("Editor Theme"); - themeButton.CreateWidget("Some themes may require a restart"); + auto& appearanceButton = m_settingsMenu->CreateWidget("Appearance"); + appearanceButton.CreateWidget("Some themes may require a restart"); - auto& colorTheme = themeButton.CreateWidget(static_cast(Settings::EditorSettings::ColorTheme.Get())); + auto& colorTheme = appearanceButton.CreateWidget(static_cast(Settings::EditorSettings::ColorTheme.Get())); colorTheme.choices = { { static_cast(OvUI::Styling::EStyle::IM_CLASSIC_STYLE), "ImGui Classic"}, { static_cast(OvUI::Styling::EStyle::IM_DARK_STYLE), "ImGui Dark"}, @@ -92,17 +94,16 @@ void OvEditor::Panels::MenuBar::InitializeSettingsMenu() EDITOR_CONTEXT(uiManager)->ApplyStyle(static_cast(p_value)); }; - auto& fontSizeMenu = m_settingsMenu->CreateWidget("Font Size"); - auto& fontSizeSelector = fontSizeMenu.CreateWidget(static_cast(Settings::EditorSettings::FontSize.Get())); - fontSizeSelector.choices = { - { static_cast(Settings::EFontSize::SMALL), "Small"}, - { static_cast(Settings::EFontSize::MEDIUM), "Medium"}, - { static_cast(Settings::EFontSize::BIG), "Big"} + auto& uiScale = appearanceButton.CreateWidget(static_cast(Settings::EditorSettings::UIScale.Get())); + uiScale.choices = { + { 0, "[BETA] Automatic (DPI Aware)"}, + { 100, "100%"}, + { 150, "150%"}, + { 200, "200%"}, }; - fontSizeSelector.ValueChangedEvent += [this](int p_value) { - Settings::EditorSettings::FontSize = p_value; - const auto fontID = std::string{ Settings::GetFontID(static_cast(p_value)) }; - EDITOR_CONTEXT(uiManager)->UseFont(fontID); + uiScale.ValueChangedEvent += [this](int p_value) { + Settings::EditorSettings::UIScale = p_value; + EDITOR_CONTEXT(uiManager)->SetScale(p_value == 0 ? std::nullopt : std::make_optional(p_value / 100.0f)); }; m_settingsMenu->CreateWidget("Spawn actors at origin", "", true, true).ValueChangedEvent += EDITOR_BIND(SetActorSpawnAtOrigin, std::placeholders::_1); @@ -204,7 +205,6 @@ void OvEditor::Panels::MenuBar::InitializeSettingsMenu() { Settings::EditorSettings::CodeEditorCommand = p_value; }; - } void OvEditor::Panels::MenuBar::CreateFileMenu() diff --git a/Sources/OvEditor/src/OvEditor/Panels/ProjectSettings.cpp b/Sources/OvEditor/src/OvEditor/Panels/ProjectSettings.cpp index c1bdc2b32..1cbdea3ce 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/ProjectSettings.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/ProjectSettings.cpp @@ -47,7 +47,7 @@ OvEditor::Panels::ProjectSettings::ProjectSettings(const std::string & p_title, /* Physics settings */ auto& root = CreateWidget("Physics"); auto& columns = root.CreateWidget>(); - columns.widths[0] = 125; + columns.widths[0] = 125 * EDITOR_UI_SCALE; GUIDrawer::DrawScalar(columns, "Gravity", GenerateGatherer("gravity"), GenerateProvider("gravity"), 0.1f, GUIDrawer::_MIN_FLOAT, GUIDrawer::_MAX_FLOAT); } @@ -56,7 +56,7 @@ OvEditor::Panels::ProjectSettings::ProjectSettings(const std::string & p_title, /* Build settings */ auto& generationRoot = CreateWidget("Build"); auto& columns = generationRoot.CreateWidget>(); - columns.widths[0] = 125; + columns.widths[0] = 125 * EDITOR_UI_SCALE; GUIDrawer::CreateTitle(columns, "Build Type"); auto& comboBox = columns.CreateWidget(m_projectFile.Get("build_type")); @@ -74,7 +74,7 @@ OvEditor::Panels::ProjectSettings::ProjectSettings(const std::string & p_title, /* Windowing settings */ auto& windowingRoot = CreateWidget("Windowing"); auto& columns = windowingRoot.CreateWidget>(); - columns.widths[0] = 125; + columns.widths[0] = 125 * EDITOR_UI_SCALE; GUIDrawer::DrawScalar(columns, "Resolution X", GenerateGatherer("x_resolution"), GenerateProvider("x_resolution"), 1, 0, 10000); GUIDrawer::DrawScalar(columns, "Resolution Y", GenerateGatherer("y_resolution"), GenerateProvider("y_resolution"), 1, 0, 10000); @@ -86,7 +86,7 @@ OvEditor::Panels::ProjectSettings::ProjectSettings(const std::string & p_title, /* Rendering settings */ auto& renderingRoot = CreateWidget("Rendering"); auto& columns = renderingRoot.CreateWidget>(); - columns.widths[0] = 125; + columns.widths[0] = 125 * EDITOR_UI_SCALE; GUIDrawer::DrawBoolean(columns, "Vertical Sync.", GenerateGatherer("vsync"), GenerateProvider("vsync")); GUIDrawer::DrawBoolean(columns, "Multi-sampling", GenerateGatherer("multisampling"), GenerateProvider("multisampling")); @@ -97,7 +97,7 @@ OvEditor::Panels::ProjectSettings::ProjectSettings(const std::string & p_title, /* Scene Management settings */ auto& gameRoot = CreateWidget("Scene Management"); auto& columns = gameRoot.CreateWidget>(); - columns.widths[0] = 125; + columns.widths[0] = 125 * EDITOR_UI_SCALE; GUIDrawer::DrawScene(columns, "Start scene", GenerateGatherer("start_scene"), GenerateProvider("start_scene")); } diff --git a/Sources/OvEditor/src/OvEditor/Settings/EditorSettings.cpp b/Sources/OvEditor/src/OvEditor/Settings/EditorSettings.cpp index 124880bd1..d2ebd899e 100644 --- a/Sources/OvEditor/src/OvEditor/Settings/EditorSettings.cpp +++ b/Sources/OvEditor/src/OvEditor/Settings/EditorSettings.cpp @@ -44,8 +44,9 @@ void OvEditor::Settings::EditorSettings::Save() iniFile.Add("rotation_snap_unit", RotationSnapUnit.Get()); iniFile.Add("scaling_snap_unit", ScalingSnapUnit.Get()); iniFile.Add("color_theme", ColorTheme.Get()); + iniFile.Add("ui_scale", UIScale.Get()); + iniFile.Add("beta_dpi_awareness_dialog_presented", BetaDpiAwarenessDialogPresented.Get()); iniFile.Add("console_max_logs", ConsoleMaxLogs.Get()); - iniFile.Add("font_size", FontSize.Get()); iniFile.Add("code_editor_command", CodeEditorCommand.Get()); iniFile.Add("always_regenerate_scripting_symbols", RegenerateScriptingProjectFilesOnStartup.Get()); iniFile.Rewrite(); @@ -65,8 +66,9 @@ void OvEditor::Settings::EditorSettings::Load() LoadIniEntry(iniFile, "rotation_snap_unit", RotationSnapUnit); LoadIniEntry(iniFile, "scaling_snap_unit", ScalingSnapUnit); LoadIniEntry(iniFile, "color_theme", ColorTheme); + LoadIniEntry(iniFile, "ui_scale", UIScale); + LoadIniEntry(iniFile, "beta_dpi_awareness_dialog_presented", BetaDpiAwarenessDialogPresented); LoadIniEntry(iniFile, "console_max_logs", ConsoleMaxLogs); - LoadIniEntry(iniFile, "font_size", FontSize); LoadIniEntry(iniFile, "code_editor_command", CodeEditorCommand); LoadIniEntry(iniFile, "always_regenerate_scripting_symbols", RegenerateScriptingProjectFilesOnStartup); } diff --git a/Sources/OvGame/src/OvGame/Core/Context.cpp b/Sources/OvGame/src/OvGame/Core/Context.cpp index f997f3618..71ec0644c 100644 --- a/Sources/OvGame/src/OvGame/Core/Context.cpp +++ b/Sources/OvGame/src/OvGame/Core/Context.cpp @@ -113,14 +113,15 @@ OvGame::Core::Context::Context() : basePSO }); - uiManager = std::make_unique(window->GetGlfwWindow(), OvUI::Styling::EStyle::DEFAULT_DARK); + uiManager = std::make_unique( + *window, + OvUI::Styling::EStyle::DEFAULT_DARK + ); const auto fontPath = engineAssetsPath / "Fonts" / "Ruda-Bold.ttf"; - uiManager->LoadFont("Ruda_Big", fontPath.string(), 16); - uiManager->LoadFont("Ruda_Small", fontPath.string(), 12); - uiManager->LoadFont("Ruda_Medium", fontPath.string(), 14); - uiManager->UseFont("Ruda_Medium"); + uiManager->LoadFont("Ruda-Bold", fontPath.string(), 15); + uiManager->UseFont("Ruda-Bold"); uiManager->EnableEditorLayoutSave(false); uiManager->EnableDocking(false); diff --git a/Sources/OvUI/include/OvUI/Core/UIManager.h b/Sources/OvUI/include/OvUI/Core/UIManager.h index f8fa7608c..89ae70134 100644 --- a/Sources/OvUI/include/OvUI/Core/UIManager.h +++ b/Sources/OvUI/include/OvUI/Core/UIManager.h @@ -6,11 +6,18 @@ #pragma once +#include "OvTools/Eventing/Event.h" +#include #include #include -#include "OvUI/Modules/Canvas.h" -#include "OvUI/Styling/EStyle.h" +#include +#include + +namespace OvWindowing +{ + class Window; +} namespace OvUI::Core { @@ -21,17 +28,17 @@ namespace OvUI::Core { public: /** - * Create the UI manager. Will setup ImGui internally\ - * @param p_glfwWindow + * Create the UI manager. Will setup ImGui internally + * @param p_window * @param p_style * @param p_glslVersion (Ex: #version 450) */ - UIManager(GLFWwindow* p_glfwWindow, Styling::EStyle p_style = Styling::EStyle::IM_DARK_STYLE, std::string_view p_glslVersion = "#version 450"); + UIManager(OvWindowing::Window& p_window, Styling::EStyle p_style = Styling::EStyle::IM_DARK_STYLE, std::string_view p_glslVersion = "#version 450"); /** * Destroy the UI manager. Will handle ImGui destruction internally */ - ~UIManager(); + virtual ~UIManager(); /** * Apply a new style to the UI elements @@ -63,6 +70,17 @@ namespace OvUI::Core */ void UseDefaultFont(); + /** + * Set the UI scale + * @param p_scale + */ + void SetScale(std::optional p_scale = std::nullopt); + + /** + * Returns the scale of the UI + */ + float GetScale() const; + /** * Allow the user to enable/disable .ini generation to save his editor layout * @param p_value @@ -96,11 +114,11 @@ namespace OvUI::Core */ void EnableDocking(bool p_value); - /** - * Reset the UI layout to the given configuration file - * @param p_config - */ - void ResetLayout(const std::string & p_config) const; + /** + * Reset the UI layout to the given configuration file + * @param p_config + */ + void ResetLayout(const std::string & p_config) const; /** * Enable or disable mouse input in ImGui. @@ -132,13 +150,15 @@ namespace OvUI::Core void Render(); private: - void PushCurrentFont(); - void PopCurrentFont(); - - private: + OvWindowing::Window& m_window; + OvTools::Eventing::ListenerID m_contentScaleChangedListener; bool m_dockingState; + Styling::EStyle m_currentStyle; + float m_scale; + bool m_dpiAware; + bool m_refreshStyle = false; Modules::Canvas* m_currentCanvas = nullptr; std::unordered_map m_fonts; std::string m_layoutSaveFilename = "imgui.ini"; }; -} \ No newline at end of file +} diff --git a/Sources/OvUI/premake5.lua b/Sources/OvUI/premake5.lua index 4cc35d7f6..a3dcc968d 100644 --- a/Sources/OvUI/premake5.lua +++ b/Sources/OvUI/premake5.lua @@ -21,6 +21,8 @@ project "OvUI" -- Overload SDK "%{wks.location}/Sources/OvMaths/include", "%{wks.location}/Sources/OvTools/include", + "%{wks.location}/Sources/OvDebug/include", + "%{wks.location}/Sources/OvWindowing/include", -- Current Project "include" diff --git a/Sources/OvUI/src/OvUI/Core/UIManager.cpp b/Sources/OvUI/src/OvUI/Core/UIManager.cpp index b6362b6bc..8af20252c 100644 --- a/Sources/OvUI/src/OvUI/Core/UIManager.cpp +++ b/Sources/OvUI/src/OvUI/Core/UIManager.cpp @@ -4,8 +4,14 @@ * @licence: MIT */ +#include "OvDebug/Logger.h" +#include #include #include +#include + +#include +#include namespace { @@ -28,7 +34,8 @@ namespace } } -OvUI::Core::UIManager::UIManager(GLFWwindow* p_glfwWindow, Styling::EStyle p_style, std::string_view p_glslVersion) +OvUI::Core::UIManager::UIManager(OvWindowing::Window& p_window, Styling::EStyle p_style, std::string_view p_glslVersion) : + m_window(p_window) { ImGui::CreateContext(); @@ -37,12 +44,21 @@ OvUI::Core::UIManager::UIManager(GLFWwindow* p_glfwWindow, Styling::EStyle p_sty ApplyStyle(p_style); - ImGui_ImplGlfw_InitForOpenGL(p_glfwWindow, true); + ImGui_ImplGlfw_InitForOpenGL(m_window.GetGlfwWindow(), true); ImGui_ImplOpenGL3_Init(p_glslVersion.data()); + + m_contentScaleChangedListener = m_window.ContentScaleChangedEvent += [this](float x, float y) { + if (m_dpiAware) + { + SetScale(); // Recompute scale based on content scale + } + }; } OvUI::Core::UIManager::~UIManager() { + m_window.ContentScaleChangedEvent -= m_contentScaleChangedListener; + ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); @@ -50,7 +66,11 @@ OvUI::Core::UIManager::~UIManager() void OvUI::Core::UIManager::ApplyStyle(Styling::EStyle p_style) { - ImGui::GetStyle() = GetStyle(p_style); + m_currentStyle = p_style; + auto style = GetStyle(p_style); + style.FontScaleMain = m_scale; + style.ScaleAllSizes(m_scale); + ImGui::GetStyle() = style; } bool OvUI::Core::UIManager::LoadFont(const std::string& p_id, const std::string & p_path, float p_fontSize) @@ -99,6 +119,34 @@ void OvUI::Core::UIManager::UseDefaultFont() ImGui::GetIO().FontDefault = nullptr; } +void OvUI::Core::UIManager::SetScale(std::optional p_scale) +{ + m_dpiAware = !p_scale.has_value(); + + if (m_dpiAware) + { + const auto contentScale = m_window.GetContentScale(); + m_scale = std::max(contentScale.first, contentScale.second); + } + else + { + m_scale = p_scale.value(); + } + + if (m_scale < 1.0f) + { + OVLOG_WARNING("UI scale values lower than 1.0f are not supported!"); + m_scale = 1.0f; + } + + ApplyStyle(m_currentStyle); +} + +float OvUI::Core::UIManager::GetScale() const +{ + return m_scale; +} + void OvUI::Core::UIManager::EnableEditorLayoutSave(bool p_value) { if (p_value) @@ -149,7 +197,7 @@ void OvUI::Core::UIManager::EnableDocking(bool p_value) void OvUI::Core::UIManager::ResetLayout(const std::string& p_config) const { - ImGui::LoadIniSettingsFromDisk(p_config.c_str()); + ImGui::LoadIniSettingsFromDisk(p_config.c_str()); } bool OvUI::Core::UIManager::IsDockingEnabled() const @@ -178,12 +226,3 @@ void OvUI::Core::UIManager::Render() } } -void OvUI::Core::UIManager::PushCurrentFont() -{ - -} - -void OvUI::Core::UIManager::PopCurrentFont() -{ - -} \ No newline at end of file diff --git a/Sources/OvWindowing/include/OvWindowing/Window.h b/Sources/OvWindowing/include/OvWindowing/Window.h index 160f6f6ce..f665a6bd4 100644 --- a/Sources/OvWindowing/include/OvWindowing/Window.h +++ b/Sources/OvWindowing/include/OvWindowing/Window.h @@ -9,6 +9,8 @@ #include #include +#include + #include #include #include @@ -33,6 +35,7 @@ namespace OvWindowing /* Window events */ OvTools::Eventing::Event ResizeEvent; OvTools::Eventing::Event FramebufferResizeEvent; + OvTools::Eventing::Event ContentScaleChangedEvent; OvTools::Eventing::Event MoveEvent; OvTools::Eventing::Event CursorMoveEvent; OvTools::Eventing::Event<> MinimizeEvent; @@ -282,6 +285,11 @@ namespace OvWindowing */ int32_t GetRefreshRate() const; + /** + * Returns the window content scale (ratio between current DPI and platform's default DPI) + */ + std::pair GetContentScale() const; + /** * Return GLFW window */ @@ -296,6 +304,7 @@ namespace OvWindowing void BindScrollCallback() const; void BindResizeCallback() const; void BindFramebufferResizeCallback() const; + void BindContentScaleCallback() const; void BindCursorMoveCallback() const; void BindMoveCallback() const; void BindIconifyCallback() const; diff --git a/Sources/OvWindowing/src/OvWindowing/Window.cpp b/Sources/OvWindowing/src/OvWindowing/Window.cpp index 373f34aa2..6ebae6d01 100644 --- a/Sources/OvWindowing/src/OvWindowing/Window.cpp +++ b/Sources/OvWindowing/src/OvWindowing/Window.cpp @@ -48,6 +48,7 @@ OvWindowing::Window::Window(const Context::Device& p_device, const Settings::Win BindResizeCallback(); BindCursorMoveCallback(); BindFramebufferResizeCallback(); + BindContentScaleCallback(); BindMoveCallback(); BindFocusCallback(); @@ -315,6 +316,13 @@ int32_t OvWindowing::Window::GetRefreshRate() const return m_refreshRate; } +std::pair OvWindowing::Window::GetContentScale() const +{ + std::pair scale; + glfwGetWindowContentScale(m_glfwWindow, &scale.first, &scale.second); + return scale; +} + GLFWwindow* OvWindowing::Window::GetGlfwWindow() const { return m_glfwWindow; @@ -434,6 +442,21 @@ void OvWindowing::Window::BindFramebufferResizeCallback() const glfwSetFramebufferSizeCallback(m_glfwWindow, framebufferResizeCallback); } +void OvWindowing::Window::BindContentScaleCallback() const +{ + auto contentScaleCallback = [](GLFWwindow* p_window, float p_x, float p_y) + { + Window* windowInstance = FindInstance(p_window); + + if (windowInstance) + { + windowInstance->ContentScaleChangedEvent.Invoke(p_x, p_y); + } + }; + + glfwSetWindowContentScaleCallback(m_glfwWindow, contentScaleCallback); +} + void OvWindowing::Window::BindCursorMoveCallback() const { auto cursorMoveCallback = [](GLFWwindow* p_window, double p_x, double p_y)