Factor out AppGLFW base class

The intention here is to get rid of scaffolding in the consumer
application class and allow to focus on the "important bits".
This commit is contained in:
Maximilian Kueffner
2025-08-17 21:30:00 +02:00
parent e21ddb1246
commit 88cc7363c6
12 changed files with 225 additions and 123 deletions
+5 -15
View File
@@ -6,14 +6,12 @@ set(CMAKE_VERBOSE_MAKEFILE ON)
set(CXX_STANDARD 20) set(CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED true) set(CXX_STANDARD_REQUIRED true)
set(imgui_DIR ${PROJECT_SOURCE_DIR}/modules/imgui)
set(glfw_DIR ${PROJECT_SOURCE_DIR}/modules/glfw) set(glfw_DIR ${PROJECT_SOURCE_DIR}/modules/glfw)
set(pfd_DIR ${PROJECT_SOURCE_DIR}/modules/portable-file-dialogs) set(pfd_DIR ${PROJECT_SOURCE_DIR}/modules/portable-file-dialogs)
set(spdlog_DIR ${PROJECT_SOURCE_DIR}/modules/spdlog) set(spdlog_DIR ${PROJECT_SOURCE_DIR}/modules/spdlog)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
message(STATUS "IMGUI:\t" ${imgui_DIR})
message(STATUS "GLFW:\t" ${glfw_DIR}) message(STATUS "GLFW:\t" ${glfw_DIR})
message(STATUS "PFD:\t\t" ${pfd_DIR}) message(STATUS "PFD:\t\t" ${pfd_DIR})
message(STATUS "SPDLOG:\t" ${spdlog_DIR}) message(STATUS "SPDLOG:\t" ${spdlog_DIR})
@@ -38,17 +36,10 @@ add_subdirectory(src)
add_subdirectory(lib) add_subdirectory(lib)
set(SRC set(SRC
src/AppGLFW.cpp src/MyApp.cpp
src/views/PixelariumImageView.cpp src/views/PixelariumImageView.cpp
src/viewmodels/ImageViewFactory.cpp src/viewmodels/ImageViewFactory.cpp
src/main.cpp src/main.cpp)
${imgui_DIR}/imgui.cpp
${imgui_DIR}/imgui_demo.cpp
${imgui_DIR}/imgui_draw.cpp
${imgui_DIR}/imgui_tables.cpp
${imgui_DIR}/imgui_widgets.cpp
${imgui_DIR}/backends/imgui_impl_opengl3.cpp
${imgui_DIR}/backends/imgui_impl_glfw.cpp)
#==================== #====================
# needed for the spdlogger implemntation # needed for the spdlogger implemntation
@@ -63,16 +54,15 @@ target_link_libraries(${PROJECT_NAME}
PRIVATE pixelariumimagelib PRIVATE pixelariumimagelib
PRIVATE pixelariumrenderlib PRIVATE pixelariumrenderlib
PRIVATE pixelariumutilslib PRIVATE pixelariumutilslib
PRIVATE pixelariumresourcelib) PRIVATE pixelariumresourcelib
PUBLIC pixelariumapplicationlib)
target_include_directories(${PROJECT_NAME} target_include_directories(${PROJECT_NAME}
PUBLIC ${PROJECT_SOURCE_DIR}/src PUBLIC ${PROJECT_SOURCE_DIR}/src
PUBLIC ${PROJECT_SOURCE_DIR}/lib PUBLIC ${PROJECT_SOURCE_DIR}/lib
PUBLIC ${PROJECT_SOURCE_DIR}/lib/imaging PUBLIC ${PROJECT_SOURCE_DIR}/lib/imaging
PUBLIC ${PROJECT_SOURCE_DIR}/lib/app
PUBLIC ${spdlog_DIR}/include PUBLIC ${spdlog_DIR}/include
PUBLIC ${imgui_DIR}
PUBLIC ${imgui_DIR}/backends
PUBLIC ${glfw_INCLUDE_DIR}
PUBLIC ${pfd_DIR} PUBLIC ${pfd_DIR}
PUBLIC ${LIBCZI_INCLUDE_DIR} PUBLIC ${LIBCZI_INCLUDE_DIR}
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
+1
View File
@@ -2,3 +2,4 @@ add_subdirectory(utilities)
add_subdirectory(imaging) add_subdirectory(imaging)
add_subdirectory(rendering) add_subdirectory(rendering)
add_subdirectory(resources) add_subdirectory(resources)
add_subdirectory(app)
+30 -44
View File
@@ -1,21 +1,16 @@
#include "AppGLFW.hpp" #include "AppGLFW.hpp"
#include <format>
#include <memory>
#include "imaging/PixelariumImage.hpp"
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h" #include "imgui_impl_opengl3.h"
#include "portable-file-dialogs.h" #include "uiresources_app.h"
#include "rendering/CvMatRender.hpp"
#include "uiresources.h"
#include "utilities/ILog.hpp"
#include "views/PixelariumImageView.hpp"
using namespace pixelarium::imaging; static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
}
void pixelarium::ui::AppGLFW::InitMainWindow() void pixelarium::application::AppGLFW::InitMainWindow()
{ {
glfwSetErrorCallback(glfw_error_callback); glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit()) if (!glfwInit())
@@ -100,7 +95,7 @@ void pixelarium::ui::AppGLFW::InitMainWindow()
ImGui_ImplOpenGL3_Init(glsl_version); ImGui_ImplOpenGL3_Init(glsl_version);
} }
int pixelarium::ui::AppGLFW::Run() int pixelarium::application::AppGLFW::RunInternal()
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
(void)io; (void)io;
@@ -115,20 +110,8 @@ int pixelarium::ui::AppGLFW::Run()
ImGui::DockSpaceOverViewport(ImGui::GetID("Backspace")); ImGui::DockSpaceOverViewport(ImGui::GetID("Backspace"));
this->MenuBar(); this->MenuBar();
if (demop_) ImGui::ShowDemoWindow(&this->demop_);
// if (this->image_view_) this->Run();
// {
// this->image_view_->ShowImage();
// }
if (ImGui::BeginListBox("ListBox"))
{
pool_.EnumerateResources([](size_t id, const imaging::PixelariumImage&) -> void
{ ImGui::Selectable(std::format("Image {}", id).c_str()); });
ImGui::EndListBox();
}
// Rendering // Rendering
ImGui::Render(); ImGui::Render();
@@ -146,6 +129,7 @@ int pixelarium::ui::AppGLFW::Run()
glfwSwapBuffers(this->window); glfwSwapBuffers(this->window);
} }
// Cleanup // Cleanup
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown(); ImGui_ImplGlfw_Shutdown();
@@ -157,7 +141,7 @@ int pixelarium::ui::AppGLFW::Run()
return 0; return 0;
} }
void pixelarium::ui::AppGLFW::MenuBar() void pixelarium::application::AppGLFW::MenuBar()
{ {
if (ImGui::BeginMainMenuBar()) if (ImGui::BeginMainMenuBar())
{ {
@@ -179,34 +163,36 @@ void pixelarium::ui::AppGLFW::MenuBar()
ImGui::EndCombo(); ImGui::EndCombo();
} }
ImGui::MenuItem(SHOWIMGUIDEMOS, NULL, &this->demop_); // consumer main menu bar entries
this->MenuBarOptionsColumn1();
ImGui::EndMenu(); ImGui::EndMenu();
} }
// file menu // consumer menu bar columns
if (ImGui::BeginMenu(FILEMENUNAME)) this->MenuBarOptionsColumn2();
{ this->MenuBarOptionsColumn3();
if (ImGui::MenuItem("Load File")) this->MenuBarOptionsColumn4();
{ this->MenuBarOptionsColumn5();
this->LoadImageProt();
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar(); ImGui::EndMainMenuBar();
} }
} }
void pixelarium::ui::AppGLFW::LoadImageProt() void pixelarium::application::AppGLFW::LogLevelSelect()
{ {
size_t last_id{}; if (ImGui::BeginCombo(LOGLEVELSELECT, LOGLEVELS[log_level_].data()))
auto res{pfd::open_file("Load Inputs", pfd::path::home(), {"All Files", "*"}, pfd::opt::multiselect).result()};
for (auto& p : res)
{ {
this->logger_.Debug(std::format("{}: Creating image {}", __FUNCTION__, p)); for (int n = 0; n < static_cast<int>(LOGLEVELS.size()); n++)
{
last_id = image_view_model_->AddImage(std::make_unique<PixelariumImage>(p)); bool is_selected = (LOGLEVELS[log_level_] == LOGLEVELS[n]);
if (ImGui::Selectable(LOGLEVELS[n].data(), is_selected))
{
log_level_ = n;
this->logger_.ChangeLevel(static_cast<utils::log::LogLevel>(1 << log_level_));
}
if (is_selected) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
} }
} }
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include <GLFW/glfw3.h>
#include <memory>
#include "imgui.h"
#include "utilities/ILog.hpp"
namespace pixelarium::application
{
class AppGLFW
{
public:
explicit AppGLFW(std::unique_ptr<utils::log::ILog>& log) : logger_(*log) { this->InitMainWindow(); }
void Start() { this->RunInternal(); }
protected:
virtual void MenuBarOptionsColumn1() {}
virtual void MenuBarOptionsColumn2() {}
virtual void MenuBarOptionsColumn3() {}
virtual void MenuBarOptionsColumn4() {}
virtual void MenuBarOptionsColumn5() {}
virtual void Run() {}
utils::log::ILog& logger_;
private:
int RunInternal();
void InitMainWindow();
void MenuBar();
void LogLevelSelect();
int log_level_{0};
GLFWwindow* window = nullptr;
ImGuiWindowFlags window_flags_ = 0;
};
} // namespace pixelarium::application
+36
View File
@@ -0,0 +1,36 @@
set(imgui_DIR ${PROJECT_SOURCE_DIR}/modules/imgui)
# set(glfw_DIR ${PROJECT_SOURCE_DIR}/modules/glfw)
message(STATUS "IMGUI:\t" ${imgui_DIR})
# message(STATUS "GLFW:\t" ${glfw_DIR})
# add_directory(${glfw_DIR})
set(PIXELARIUM_TITLE ${CMAKE_PROJECT_NAME})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/uiresources_app.h.in
${CMAKE_BINARY_DIR}/uiresources_app.h @ONLY)
set(APPLIBSRC
AppGLFW.cpp
${imgui_DIR}/imgui.cpp
${imgui_DIR}/imgui_demo.cpp
${imgui_DIR}/imgui_draw.cpp
${imgui_DIR}/imgui_tables.cpp
${imgui_DIR}/imgui_widgets.cpp
${imgui_DIR}/backends/imgui_impl_opengl3.cpp
${imgui_DIR}/backends/imgui_impl_glfw.cpp)
set(APPLIBNAME pixelariumapplicationlib)
add_library(${APPLIBNAME}
STATIC ${APPLIBSRC})
target_link_libraries(${APPLIBNAME}
PRIVATE pixelariumutilslib)
target_include_directories(${APPLIBNAME}
PUBLIC ${CMAKE_BINARY_DIR}
PUBLIC ${PROJECT_SOURCE_DIR}/lib
PUBLIC ${imgui_DIR}
PUBLIC ${imgui_DIR}/backends
PUBLIC ${glfw_INCLUDE_DIR})
@@ -1,13 +1,13 @@
#pragma once #pragma once
/*-- Gets filled in during the cmake configuration step --*/
#include <array> #include <array>
#include <string_view> #include <string_view>
#cmakedefine PIXELARIUM_TITLE "@PIXELARIUM_TITLE@" #cmakedefine PIXELARIUM_TITLE "@PIXELARIUM_TITLE@"
#define MAINMENUNAME "Menu" #define MAINMENUNAME "Menu"
#define FILEMENUNAME "File" #define FILEMENUNAME "File"
#define LOGLEVELSELECT "Log Level" #define LOGLEVELSELECT "Log Level"
#define SHOWIMGUIDEMOS "ImGui Demos"
inline constexpr std::array<std::string_view, 5> LOGLEVELS = {"Trace", "Debug", "Info", "Warning", "Error"}; inline constexpr std::array<std::string_view, 5> LOGLEVELS = {"Trace", "Debug", "Info", "Warning", "Error"};
-55
View File
@@ -1,55 +0,0 @@
#pragma once
#include <GLFW/glfw3.h>
#include <cstdio>
#include <format>
#include <memory>
#include "PixelariumImage.hpp"
#include "imgui.h"
#include "rendering/CvMatRender.hpp"
#include "resources/resource.hpp"
#include "utilities/ILog.hpp"
#include "viewmodels/ImageViewFactory.hpp"
#include "views/PixelariumImageView.hpp"
namespace pixelarium::ui
{
class AppGLFW
{
public:
AppGLFW(std::unique_ptr<utils::log::ILog>& log, std::unique_ptr<pixelarium::resources::ImageResourcePool>& pool)
: logger_(*log), pool_(*pool)
{
image_view_model_ = std::make_unique<ImageViewFactory>(pool_);
this->InitMainWindow();
}
int Run();
private:
void InitMainWindow();
void MenuBar();
void LoadImageProt();
private:
utils::log::ILog& logger_;
resources::ImageResourcePool& pool_;
GLFWwindow* window = nullptr;
ImGuiWindowFlags window_flags_ = 0;
// std::shared_ptr<pixelarium::imaging::PixelariumImage> img_;
// std::shared_ptr<pixelarium::ui::PixelariumImageView> image_view_;
std::unique_ptr<ImageViewFactory> image_view_model_;
// pixelarium::render::CvMatRender render_;
bool imagep_{false};
bool demop_{false};
int log_level_{0};
ImVec2 curr_dim_;
};
static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
}
} // namespace pixelarium::ui
+2 -4
View File
@@ -1,6 +1,4 @@
set(PIXELARIUM_TITLE ${CMAKE_PROJECT_NAME})
message(STATUS "Configuring Resources") message(STATUS "Configuring Resources")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/uiresources.h.in configure_file(${CMAKE_CURRENT_SOURCE_DIR}/uiresources_local.h.in
${CMAKE_BINARY_DIR}/uiresources.h @ONLY) ${CMAKE_BINARY_DIR}/uiresources_local.h @ONLY)
+58
View File
@@ -0,0 +1,58 @@
#include "MyApp.hpp"
#include <format>
#include <memory>
#include "imaging/PixelariumImage.hpp"
#include "imgui.h"
#include "portable-file-dialogs.h"
#include "uiresources_app.h"
#include "uiresources_local.h"
#include "utilities/ILog.hpp"
using namespace pixelarium::imaging;
void pixelarium::ui::MyApp::MenuBarOptionsColumn1() { ImGui::MenuItem(SHOWIMGUIDEMOS, NULL, &this->demop_); }
void pixelarium::ui::MyApp::MenuBarOptionsColumn2()
{
if (ImGui::BeginMenu(FILEMENUNAME))
{
if (ImGui::MenuItem("Load File"))
{
this->LoadImageProt();
}
ImGui::EndMenu();
}
}
void pixelarium::ui::MyApp::Run()
{
if (demop_) ImGui::ShowDemoWindow(&this->demop_);
// if (this->image_view_)
// {
// this->image_view_->ShowImage();
// }
if (ImGui::BeginListBox("ListBox"))
{
pool_.EnumerateResources([](size_t id, const imaging::PixelariumImage&) -> void
{ ImGui::Selectable(std::format("Image {}", id).c_str()); });
ImGui::EndListBox();
}
}
void pixelarium::ui::MyApp::LoadImageProt()
{
size_t last_id{};
auto res{pfd::open_file("Load Inputs", pfd::path::home(), {"All Files", "*"}, pfd::opt::multiselect).result()};
for (auto& p : res)
{
this->logger_.Debug(std::format("{}: Creating image {}", __FUNCTION__, p));
last_id = image_view_model_->AddImage(std::make_unique<PixelariumImage>(p));
}
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <GLFW/glfw3.h>
#include <memory>
#include "AppGLFW.hpp"
#include "imgui.h"
#include "resources/resource.hpp"
#include "utilities/ILog.hpp"
#include "viewmodels/ImageViewFactory.hpp"
namespace pixelarium::ui
{
class MyApp : public application::AppGLFW
{
public:
MyApp(std::unique_ptr<utils::log::ILog>& log, std::unique_ptr<pixelarium::resources::ImageResourcePool>& pool)
: application::AppGLFW(log), pool_(*pool)
{
image_view_model_ = std::make_unique<ImageViewFactory>(pool_);
}
protected:
void MenuBarOptionsColumn1() override;
void MenuBarOptionsColumn2() override;
void Run() override;
private:
void LoadImageProt();
private:
resources::ImageResourcePool& pool_;
std::unique_ptr<ImageViewFactory> image_view_model_;
bool imagep_{false};
bool demop_{false};
int log_level_{0};
ImVec2 curr_dim_;
};
} // namespace pixelarium::ui
+3 -3
View File
@@ -1,7 +1,7 @@
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include "AppGLFW.hpp" #include "MyApp.hpp"
#include "resources/resource.hpp" #include "resources/resource.hpp"
#include "uiresources.h" #include "uiresources.h"
#include "utilities/ILog.hpp" #include "utilities/ILog.hpp"
@@ -23,7 +23,7 @@ int main(int argc, char** argv)
logger->ChangeLevel(utils::log::LogLevel::Debug); logger->ChangeLevel(utils::log::LogLevel::Debug);
auto image_pool{std::make_unique<resources::ImageResourcePool>()}; auto image_pool{std::make_unique<resources::ImageResourcePool>()};
auto app = pixelarium::ui::AppGLFW(logger, image_pool); pixelarium::ui::MyApp app = pixelarium::ui::MyApp(logger, image_pool);
return app.Run(); app.Start();
} }
+10
View File
@@ -0,0 +1,10 @@
#pragma once
/*-- Gets filled in during the cmake configuration step --*/
// #cmakedefine PIXELARIUM_TITLE "@PIXELARIUM_TITLE@"
// #define MAINMENUNAME "Menu"
// #define FILEMENUNAME "File"
// #define LOGLEVELSELECT "Log Level"
#define SHOWIMGUIDEMOS "ImGui Demos"