/*
ApplicationFramework
by John Ryland
Copyright (c) 2023
*/
////////////////////////////////////////////////////////////////////////////////////
// Main Window
#include "MainWindow.h"
#include "Acknowledgements.h"
#include "Image.h"
#include "IRenderSystem.h"
#include "Application.h"
#include "imgui.h"
// #define FILE_DIALOGS 1
#ifdef FILE_DIALOGS
// Different file dialogs
# include "nfd.h"
# include "ImFileDialog.h"
# include "L2DFileDialog.h"
#endif
namespace ApplicationFramework {
MainWindow::MainWindow(IApplication& app, int width, int height, const char* title)
: Window(app, width, height, title)
{
#ifdef FILE_DIALOGS
// ImFileDialog requires you to set the CreateTexture and DeleteTexture
ifd::FileDialog::Instance().CreateTexture = [&app](uint8_t* data, int w, int h, char fmt) -> void* {
ApplicationFramework::Image textureImage;
textureImage.Init(data, w, h, 4);
return app.RenderSystem()->CreateTexture(textureImage);
};
ifd::FileDialog::Instance().DeleteTexture = [&app](void* tex) {
return app.RenderSystem()->DestroyTexture(tex);
};
#endif
}
// virtual
void MainWindow::Update()
{
ParentClass::Update();
// Dockspace app
ImGui::DockSpaceOverViewport();
ShowMenus();
ShowOverlay();
ShowStyleEditor();
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
if (show_app_metrics)
ImGui::ShowMetricsWindow(&show_app_metrics);
if (show_app_debug_log)
ImGui::ShowDebugLogWindow(&show_app_debug_log);
if (show_app_stack_tool)
ImGui::ShowStackToolWindow(&show_app_stack_tool);
if (show_app_about)
ImGui::ShowAboutWindow(&show_app_about);
if (show_acknowledgements)
Acknowledgements::Get().Show(&show_acknowledgements);
#ifdef FILE_DIALOGS
// File dialog
static char buffer[512] = { '.', '/', 0 };
if (FileDialog::file_dialog_open)
FileDialog::ShowFileDialog(&FileDialog::file_dialog_open, buffer, sizeof(buffer), FileDialog::FileDialogType::OpenFile);
//FileDialog::ShowFileDialog(&fopendia, buffer, std::size(buffer));
#endif
}
void MainWindow::AddMenus()
{
if (ImGui::BeginMenu("File"))
{
ShowFileMenu();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Edit"))
{
if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
ImGui::Separator();
if (ImGui::MenuItem("Cut", "CTRL+X")) {}
if (ImGui::MenuItem("Copy", "CTRL+C")) {}
if (ImGui::MenuItem("Paste", "CTRL+V")) {}
ImGui::EndMenu();
}
}
void MainWindow::ShowMenus()
{
if (ImGui::BeginMainMenuBar())
{
AddMenus();
if (ImGui::BeginMenu("Tools"))
{
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
const bool has_debug_tools = true;
#else
const bool has_debug_tools = false;
#endif
ImGui::MenuItem("Status Overlay", NULL, &show_app_overlay);
ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics, has_debug_tools);
ImGui::MenuItem("Debug Log", NULL, &show_app_debug_log, has_debug_tools);
ImGui::MenuItem("Stack Tool", NULL, &show_app_stack_tool, has_debug_tools);
ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
ImGui::MenuItem("Demo Window", NULL, &show_demo_window);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Help"))
{
ImGui::MenuItem("Acknowledgements", NULL, &show_acknowledgements);
ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
#ifdef FILE_DIALOGS
if (ifd::FileDialog::Instance().IsDone("ShaderOpenDialog")) {
if (ifd::FileDialog::Instance().HasResult()) {
const std::vector<std::filesystem::path>& res = ifd::FileDialog::Instance().GetResults();
for (const auto& r : res) // ShaderOpenDialog supports multiselection
printf("OPEN[%s]\n", r.u8string().c_str());
}
ifd::FileDialog::Instance().Close();
}
#endif
}
// Note that shortcuts are currently provided for display only
// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
void MainWindow::ShowFileMenu()
{
//ImGui::MenuItem("(demo menu)", NULL, false, false);
if (ImGui::MenuItem("New")) {}
if (ImGui::MenuItem("Open", "Ctrl+O"))
{
#ifdef FILE_DIALOGS
ifd::FileDialog::Instance().Open("ShaderOpenDialog", "Open a shader", "Image file (*.png;*.jpg;*.jpeg;*.bmp;*.tga){.png,.jpg,.jpeg,.bmp,.tga},.*", true);
#endif
}
if (ImGui::BeginMenu("Open Recent"))
{
ImGui::MenuItem("fish_hat.c");
ImGui::MenuItem("fish_hat.inl");
ImGui::MenuItem("fish_hat.h");
if (ImGui::BeginMenu("More.."))
{
ImGui::MenuItem("Hello");
ImGui::MenuItem("Sailor");
if (ImGui::BeginMenu("Recurse.."))
{
ShowFileMenu();
ImGui::EndMenu();
}
ImGui::EndMenu();
}
ImGui::EndMenu();
}
if (ImGui::MenuItem("Save", "Ctrl+S"))
{
#ifdef FILE_DIALOGS
nfdchar_t *outPath;
nfdresult_t res = NFD_OpenDialog("*.pro", ".", &outPath);
#endif
}
if (ImGui::MenuItem("Save As.."))
{
#ifdef FILE_DIALOGS
FileDialog::file_dialog_open = true;
#endif
}
ImGui::Separator();
if (ImGui::BeginMenu("Options"))
{
static bool enabled = true;
ImGui::MenuItem("Enabled", "", &enabled);
ImGui::BeginChild("child", ImVec2(0, 60), true);
for (int i = 0; i < 10; i++)
ImGui::Text("Scrolling Text %d", i);
ImGui::EndChild();
static float f = 0.5f;
static int n = 0;
ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
ImGui::InputFloat("Input", &f, 0.1f);
ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Colors"))
{
float sz = ImGui::GetTextLineHeight();
for (int i = 0; i < ImGuiCol_COUNT; i++)
{
const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
ImVec2 p = ImGui::GetCursorScreenPos();
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
ImGui::Dummy(ImVec2(sz, sz));
ImGui::SameLine();
ImGui::MenuItem(name);
}
ImGui::EndMenu();
}
// Here we demonstrate appending again to the "Options" menu (which we already created above)
// Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
// In a real code-base using it would make senses to use this feature from very different code locations.
if (ImGui::BeginMenu("Options")) // <-- Append!
{
static bool b = true;
ImGui::Checkbox("SomeOption", &b);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Disabled", false)) // Disabled
{
IM_ASSERT(0);
}
if (ImGui::MenuItem("Checked", NULL, true)) {}
if (ImGui::MenuItem("Quit", "Alt+F4")) {}
}
void MainWindow::ShowOverlay()
{
bool* p_open = &show_app_overlay;
if (!*p_open)
return;
ImGuiIO& io = ImGui::GetIO();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
ImVec2 pos = ImGui::GetMainViewport()->Pos;
ImVec2 siz = ImGui::GetMainViewport()->Size;
pos = ImVec2(pos.x + siz.x * 0.67f, pos.y + siz.y * 0.15f);
ImGui::SetNextWindowPos(pos, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
if (ImGui::Begin("Overlay", p_open, window_flags))
{
ImGui::Text("Mouse Position:");
if (ImGui::IsMousePosValid())
ImGui::Text("%.1f,%.1f", io.MousePos.x, io.MousePos.y);
else
ImGui::Text("<invalid>");
ImGui::Separator();
ImGui::Text("Average frame rate:");
ImGui::Text("%.1f fps (%.1f ms)", ImGui::GetIO().Framerate, 1000.0f / ImGui::GetIO().Framerate);
if (ImGui::BeginPopupContextWindow())
{
if (p_open && ImGui::MenuItem("Close"))
*p_open = false;
ImGui::EndPopup();
}
}
ImGui::End();
}
void MainWindow::ShowStyleEditor()
{
if (show_app_style_editor)
{
ImGui::Begin("UI Style Editor", &show_app_style_editor);
ImGui::ShowStyleEditor();
ImGui::End();
}
}
} // ApplicationFramework namespace