Files
WickedEngine/Editor/App_Windows.cpp
T
2022-08-20 18:32:16 +02:00

321 lines
8.1 KiB
C++

#include "stdafx.h"
#include "Editor.h"
// Use the C++ standard templated min/max
#define NOMINMAX
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <exception>
#include <future>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <filesystem>
#include "winrt/Windows.ApplicationModel.h"
#include "winrt/Windows.ApplicationModel.Core.h"
#include "winrt/Windows.ApplicationModel.Activation.h"
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Graphics.Display.h"
#include "winrt/Windows.System.h"
#include "winrt/Windows.UI.Core.h"
#include "winrt/Windows.UI.Input.h"
#include "winrt/Windows.UI.ViewManagement.h"
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Foundation.Collections.h>
using namespace winrt::Windows::ApplicationModel;
using namespace winrt::Windows::ApplicationModel::Core;
using namespace winrt::Windows::ApplicationModel::Activation;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Input;
using namespace winrt::Windows::UI::ViewManagement;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::Storage;
winrt::fire_and_forget copy_folder(StorageFolder src, StorageFolder dst)
{
auto items = co_await src.GetItemsAsync();
for (auto item : items)
{
if (item.IsOfType(StorageItemTypes::File))
{
StorageFile file = item.as<StorageFile>();
try {
file.CopyAsync(dst);
}
catch (...) {
// file already exists, we don't want to overwrite
}
}
else if (item.IsOfType(StorageItemTypes::Folder))
{
StorageFolder src_child = item.as<StorageFolder>();
auto dst_child = co_await dst.CreateFolderAsync(item.Name(), CreationCollisionOption::OpenIfExists);
if (dst_child)
{
copy_folder(src_child, dst_child);
}
}
}
};
winrt::fire_and_forget uwp_copy_assets()
{
// On UWP we will copy the base content from application folder to 3D Objects directory
// for easy access to the user:
StorageFolder location = KnownFolders::Objects3D();
// Objects3D/WickedEngine
auto destfolder = co_await location.CreateFolderAsync(L"WickedEngine", CreationCollisionOption::OpenIfExists);
std::string rootdir = std::filesystem::current_path().string() + "\\";
std::wstring wstr;
// scripts:
{
wi::helper::StringConvert(rootdir + "scripts\\", wstr);
auto src = co_await StorageFolder::GetFolderFromPathAsync(wstr.c_str());
if (src)
{
auto dst = co_await destfolder.CreateFolderAsync(L"scripts", CreationCollisionOption::OpenIfExists);
if (dst)
{
copy_folder(src, dst);
}
}
}
// models:
{
wi::helper::StringConvert(rootdir + "models\\", wstr);
auto src = co_await StorageFolder::GetFolderFromPathAsync(wstr.c_str());
if (src)
{
auto dst = co_await destfolder.CreateFolderAsync(L"models", CreationCollisionOption::OpenIfExists);
if (dst)
{
copy_folder(src, dst);
}
}
}
// Documentation:
{
wi::helper::StringConvert(rootdir + "Documentation\\", wstr);
auto src = co_await StorageFolder::GetFolderFromPathAsync(wstr.c_str());
if (src)
{
auto dst = destfolder.CreateFolderAsync(L"Documentation", CreationCollisionOption::OpenIfExists).get();
if (dst)
{
copy_folder(src, dst);
}
}
}
}
class ViewProvider : public winrt::implements<ViewProvider, IFrameworkView>
{
public:
// IFrameworkView methods
void Initialize(CoreApplicationView const& applicationView)
{
applicationView.Activated({ this, &ViewProvider::OnActivated });
CoreApplication::Suspending({ this, &ViewProvider::OnSuspending });
CoreApplication::Resuming({ this, &ViewProvider::OnResuming });
uwp_copy_assets();
//wi::Timer timer;
//if (editor.config.Open("config.ini"))
//{
// editor.allow_hdr = editor.config.GetBool("allow_hdr");
// wi::backlog::post("config.ini loaded in " + std::to_string(timer.elapsed_milliseconds()) + " milliseconds\n");
//}
}
void Uninitialize() noexcept
{
}
void SetWindow(CoreWindow const& window)
{
window.SizeChanged({ this, &ViewProvider::OnWindowSizeChanged });
window.VisibilityChanged({ this, &ViewProvider::OnVisibilityChanged });
window.Closed([this](auto&&, auto&&) { m_exit = true; });
auto dispatcher = CoreWindow::GetForCurrentThread().Dispatcher();
dispatcher.AcceleratorKeyActivated({ this, &ViewProvider::OnAcceleratorKeyActivated });
auto navigation = SystemNavigationManager::GetForCurrentView();
// UWP on Xbox One triggers a back request whenever the B button is pressed
// which can result in the app being suspended if unhandled
navigation.BackRequested([](const winrt::Windows::Foundation::IInspectable&, const BackRequestedEventArgs& args)
{
args.Handled(true);
});
auto currentDisplayInformation = DisplayInformation::GetForCurrentView();
currentDisplayInformation.DpiChanged({ this, &ViewProvider::OnDpiChanged });
DisplayInformation::DisplayContentsInvalidated({ this, &ViewProvider::OnDisplayContentsInvalidated });
m_DPI = currentDisplayInformation.LogicalDpi();
m_logicalWidth = window.Bounds().Width;
m_logicalHeight = window.Bounds().Height;
editor.SetWindow(&window);
}
void Load(winrt::hstring const&) noexcept
{
}
void Run()
{
while (!m_exit)
{
if (m_visible)
{
editor.Run();
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
}
else
{
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
protected:
// Event handlers
void OnActivated(CoreApplicationView const& /*applicationView*/, IActivatedEventArgs const& args)
{
CoreWindow::GetForCurrentThread().Activate();
}
void OnSuspending(IInspectable const& /*sender*/, SuspendingEventArgs const& args)
{
auto deferral = args.SuspendingOperation().GetDeferral();
auto f = std::async(std::launch::async, [this, deferral]()
{
deferral.Complete();
});
}
void OnResuming(IInspectable const& /*sender*/, IInspectable const& /*args*/)
{
}
void OnWindowSizeChanged(CoreWindow const& sender, WindowSizeChangedEventArgs const& /*args*/)
{
editor.SetWindow(&sender);
}
void OnVisibilityChanged(CoreWindow const& /*sender*/, VisibilityChangedEventArgs const& args)
{
m_visible = args.Visible();
}
void OnAcceleratorKeyActivated(CoreDispatcher const&, AcceleratorKeyEventArgs const& args)
{
if (args.EventType() == CoreAcceleratorKeyEventType::SystemKeyDown
&& args.VirtualKey() == VirtualKey::Enter
&& args.KeyStatus().IsMenuKeyDown
&& !args.KeyStatus().WasKeyDown)
{
// Implements the classic ALT+ENTER fullscreen toggle
auto view = ApplicationView::GetForCurrentView();
if (view.IsFullScreenMode())
view.ExitFullScreenMode();
else
view.TryEnterFullScreenMode();
args.Handled(true);
}
if (args.EventType() == CoreAcceleratorKeyEventType::Character && args.VirtualKey() != VirtualKey::Enter)
{
wchar_t c = (wchar_t)args.VirtualKey();
if (c == '\b')
{
wi::gui::TextInputField::DeleteFromInput();
}
else
{
wi::gui::TextInputField::AddInput(c);
}
}
}
void OnDpiChanged(DisplayInformation const& sender, IInspectable const& /*args*/)
{
editor.SetWindow(&CoreWindow::GetForCurrentThread());
}
void OnDisplayContentsInvalidated(DisplayInformation const& /*sender*/, IInspectable const& /*args*/)
{
}
private:
bool m_exit = false;
bool m_visible = true;
float m_DPI = 96;
float m_logicalWidth = 800;
float m_logicalHeight = 600;
Editor editor;
inline int ConvertDipsToPixels(float dips) const noexcept
{
return int(dips * m_DPI / 96.f + 0.5f);
}
inline float ConvertPixelsToDips(int pixels) const noexcept
{
return (float(pixels) * 96.f / m_DPI);
}
};
class ViewProviderFactory : public winrt::implements<ViewProviderFactory, IFrameworkViewSource>
{
public:
IFrameworkView CreateView()
{
return winrt::make<ViewProvider>();
}
};
// Entry point
int WINAPI wWinMain(
_In_ HINSTANCE /*hInstance*/,
_In_ HINSTANCE /*hPrevInstance*/,
_In_ LPWSTR /*lpCmdLine*/,
_In_ int /*nCmdShow*/
)
{
auto viewProviderFactory = winrt::make<ViewProviderFactory>();
CoreApplication::Run(viewProviderFactory);
return 0;
}