From d9b82db5d431e490150bf6b487f0fa45e32859a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Wed, 22 Nov 2017 14:13:02 +0100 Subject: [PATCH] Window - Modal dialogs --- main.cc | 1 + window.cc | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- window.hh | 46 +++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/main.cc b/main.cc index 240f7b8..13c2c1b 100644 --- a/main.cc +++ b/main.cc @@ -261,6 +261,7 @@ void T_Main::render( ) glClear( GL_COLOR_BUFFER_BIT ); } + Globals::Window( ).handleDialogs( ); glUseProgram( 0 ); glBindProgramPipeline( 0 ); Globals::Textures( ).reset( ); diff --git a/window.cc b/window.cc index 44b6895..572138f 100644 --- a/window.cc +++ b/window.cc @@ -3,6 +3,84 @@ #include "imgui_impl_sdl.h" #include + +/*= A_ModalDialog ============================================================*/ + +A_ModalDialog::A_ModalDialog( + char const* const id ) noexcept + : id_{ id , uint32_t( strlen( id ) + 1 ) } +{} + +A_ModalDialog::~A_ModalDialog( ) +{ } + +void A_ModalDialog::initDialog( ) noexcept +{} + +void A_ModalDialog::onCancel( ) noexcept +{ } + +bool A_ModalDialog::draw( ) noexcept +{ + using namespace ImGui; + if ( !open_ ) { + OpenPopup( id_.data( ) ); + open_ = true; + } + + initDialog( ); + if ( initialSize_ ) { + SetNextWindowSize( *initialSize_ , ImGuiCond_Appearing ); + } + + bool ok{ false }; + bool keep{ BeginPopupModal( id_.data( ) , nullptr , ImGuiWindowFlags_NoResize ) }; + if ( keep ) { + const bool canUseOK{ drawDialog( ) }; + + const ImVec2 ws( GetWindowContentRegionMax( ) ); + auto const& style( GetStyle( ) ); + const float innerWidth{ ws.x - 2 * style.FramePadding.x }; + constexpr float nButtons{ 2.f }; + const ImVec2 buttonSize{ std::max( 40.f , + ( innerWidth - nButtons * style.FramePadding.x ) / nButtons ) , + 0.f + }; + + if ( !canUseOK ) { + PushItemFlag( ImGuiItemFlags_Disabled , true ); + PushStyleVar( ImGuiStyleVar_Alpha , + GetStyle( ).Alpha * .5f ); + } + if ( Button( "OK" , buttonSize ) ) { + ok = true; + keep = false; + } + if ( !canUseOK ) { + PopItemFlag( ); + PopStyleVar( ); + } + SameLine( 0 ); + keep = !Button( "Cancel" , buttonSize ) && keep; + + if ( !keep ) { + CloseCurrentPopup( ); + } + EndPopup( ); + } + if ( !keep ) { + if ( ok ) { + onOK( ); + } else { + onCancel( ); + } + } + return keep; +} + + +/*= T_Window =================================================================*/ + namespace { #include "font-awesome.inl" @@ -11,8 +89,7 @@ static const ImWchar IconsRanges_[] = { ICON_MAX_FA , 0 }; -} - +} // namespace T_Window::T_Window( ) { @@ -95,3 +172,15 @@ void T_Window::swap( ) const { SDL_GL_SwapWindow( window ); } + +void T_Window::handleDialogs( ) noexcept +{ + const auto nDialogs{ modals_.size( ) }; + for ( auto i = 0u ; i < nDialogs ; i ++ ) { + const bool keep{ modals_[ i ]->draw( ) }; + assert( keep || i + 1 == nDialogs ); + if ( !keep ) { + modals_.removeLast( ); + } + } +} diff --git a/window.hh b/window.hh index 53aa4e6..9007e91 100644 --- a/window.hh +++ b/window.hh @@ -4,6 +4,47 @@ #endif +// Base class for a modal dialog that can be pushed to the window's modal +// stack. +class A_ModalDialog +{ + private: + const T_String id_; + bool open_{ false }; + T_Optional< ImVec2 > initialSize_; + + protected: + A_ModalDialog( char const* id ) noexcept; + + void setInitialSize( const float width , + const float height ) noexcept + { initialSize_.setNew( width , height ); } + + // Initialisation, called right before the window is opened. + // Does nothing by default. + virtual void initDialog( ) noexcept; + + // Draw the dialog box's contents, returns true if the OK button + // should be enabled. + virtual bool drawDialog( ) noexcept = 0; + + // Handlers for both OK and Cancel. The former must be overridden, + // the latter defaults to "do nothing". + virtual void onOK( ) noexcept = 0; + virtual void onCancel( ) noexcept; + + public: + NO_COPY( A_ModalDialog ); + NO_MOVE( A_ModalDialog ); + virtual ~A_ModalDialog( ); + + // Draw and handle the dialog box. Returns true if it must be kept, + // or false if it must be removed from the stack. + bool draw( ) noexcept; +}; +using P_ModalDialog = T_OwnPtr< A_ModalDialog >; + + struct T_Window { T_Window( ); @@ -15,6 +56,10 @@ struct T_Window void swap( ) const; + void pushDialog( P_ModalDialog dialog ) noexcept + { modals_.add( std::move( dialog ) ); } + void handleDialogs( ) noexcept; + ImFont* defaultFont( ) const noexcept { return defaultFont_; } ImFont* smallFont( ) const noexcept @@ -25,5 +70,6 @@ struct T_Window SDL_GLContext gl; ImFont* defaultFont_; ImFont* smallFont_; + T_AutoArray< P_ModalDialog , 8 > modals_; };