diff --git a/Makefile b/Makefile index 6829ce6..3d10813 100644 --- a/Makefile +++ b/Makefile @@ -38,10 +38,14 @@ COMMON = \ opcomp.cc \ opmgr.cc \ \ + ui.cc \ ui-actions.cc \ ui-colorgrading.cc \ ui-dialogs.cc \ ui-imgui-sdl.cc \ + ui-overrides.cc \ + ui-sequencer.cc \ + ui-sync.cc \ ui-utilities.cc \ # END COMMON @@ -49,7 +53,6 @@ DEMO = \ demo.cc \ main.cc \ opemu.cc \ - ui-sequencer.cc \ # END DEMO PARSERCHECK = \ diff --git a/globals.cc b/globals.cc index f0a2347..cd9f6c7 100644 --- a/globals.cc +++ b/globals.cc @@ -2,24 +2,16 @@ #include "globals.hh" #include "filewatcher.hh" -#include "odbg.hh" #include "opcomp.hh" #include "ops.hh" #include "profiling.hh" -#include "shaders.hh" #include "sync.hh" -#include "texture.hh" #include "undo.hh" -#include "window.hh" T_OwnPtr< T_FilesWatcher > Globals::watcher_; -T_OwnPtr< T_Window > Globals::window_; T_OwnPtr< T_Profiler > Globals::profiler_; T_OwnPtr< T_SyncManager > Globals::sync_; -T_OwnPtr< T_TextureManager > Globals::textures_; -T_OwnPtr< T_ShaderManager > Globals::shaders_; -T_OwnPtr< T_OutputDebugger > Globals::odbg_; T_OwnPtr< T_ScriptManager > Globals::ops_; T_OwnPtr< T_UndoManager > Globals::undo_; @@ -27,12 +19,8 @@ T_OwnPtr< T_UndoManager > Globals::undo_; void Globals::Init( ) { watcher_ = NewOwned< T_FilesWatcher >( ); - window_ = NewOwned< T_Window >( ); profiler_ = NewOwned< T_Profiler >( ); sync_ = NewOwned< T_SyncManager >( ); - textures_ = NewOwned< T_TextureManager >( ); - shaders_ = NewOwned< T_ShaderManager >( ); - odbg_ = NewOwned< T_OutputDebugger >( ); ops_ = NewOwned< T_ScriptManager >( ); undo_ = NewOwned< T_UndoManager >( ); } @@ -41,11 +29,7 @@ void Globals::Shutdown( ) { undo_.clear( ); ops_.clear( ); - odbg_.clear( ); - shaders_.clear( ); - textures_.clear( ); sync_.clear( ); profiler_.clear( ); - window_.clear( ); watcher_.clear( ); } diff --git a/globals.hh b/globals.hh index e35866b..395007c 100644 --- a/globals.hh +++ b/globals.hh @@ -4,12 +4,8 @@ #endif -struct T_Window; struct T_FilesWatcher; struct T_Profiler; -struct T_TextureManager; -struct T_ShaderManager; -struct T_OutputDebugger; struct T_SyncManager; struct T_ScriptManager; class T_UndoManager; @@ -21,23 +17,15 @@ struct Globals static void Shutdown( ); static T_FilesWatcher& Watcher( ) { return *watcher_; } - static T_Window& Window( ) { return *window_; } static T_Profiler& Profiler( ) { return *profiler_; } static T_SyncManager& Sync( ) { return *sync_; } - static T_TextureManager& Textures( ) { return *textures_; } - static T_ShaderManager& Shaders( ) { return *shaders_; } - static T_OutputDebugger& ODbg( ) { return *odbg_; } static T_ScriptManager& Ops( ) { return *ops_; } static T_UndoManager& Undo( ) { return *undo_; } private: static T_OwnPtr< T_FilesWatcher > watcher_; - static T_OwnPtr< T_Window > window_; static T_OwnPtr< T_Profiler > profiler_; static T_OwnPtr< T_SyncManager > sync_; - static T_OwnPtr< T_ShaderManager > shaders_; - static T_OwnPtr< T_TextureManager > textures_; - static T_OwnPtr< T_OutputDebugger > odbg_; static T_OwnPtr< T_ScriptManager > ops_; static T_OwnPtr< T_UndoManager > undo_; }; diff --git a/main.cc b/main.cc index 78d5ec1..6daba33 100644 --- a/main.cc +++ b/main.cc @@ -9,7 +9,9 @@ #include "opemu.hh" #include "rendertarget.hh" #include "sync.hh" +#include "ui.hh" #include "ui-sequencer.hh" +#include "ui-sync.hh" #include "ui-utilities.hh" #include "undo.hh" @@ -50,46 +52,8 @@ struct T_Main T_Main::T_Main( ) { Globals::Init( ); + UI::Init( ); prevSize = ImVec2( -1 , -1 ); - - // FIXME: should be somewhere else - T_UIAction saveCurves{ "Save curves" , []() { - if ( Globals::Sync( ).curvesFileChanged( ) ) { - Globals::Window( ).msgbox( - "Curves file changed" , - "The file containing the curves has been modified " - "on the disk. These changes will be overwritten. " - "Do you want to continue?" , - []( auto b ) { - if ( b == T_MessageBox::BT_YES ) { - Globals::Sync( ).saveCurves( ); - } - } , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } ); - } else { - Globals::Sync( ).saveCurves( ); - } - } }; - saveCurves.setEnabledCheck( []() { return Globals::Sync( ).curvesModified( ); } ) - .setIcon( ICON_FA_FLOPPY_O ) - .setShortcut( T_KeyboardShortcut{ 's' , E_KeyboardModifier::CTRL } ); - Globals::Window( ).addAction( std::move( saveCurves ) ); - - T_UIAction reloadCurves{ "Reload curves" , []() { - Globals::Window( ).msgbox( - "Reload curves?" , - "Changes you made to the curves will be lost. Do you " - "want to continue?" , - []( auto b ) { - if ( b == T_MessageBox::BT_YES ) { - Globals::Sync( ).loadCurves( ); - } - } , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } ); - } }; - reloadCurves.setEnabledCheck( []() { return Globals::Sync( ).curvesModified( ); } ) - .setIcon( ICON_FA_DOWNLOAD ) - .setShortcut( T_KeyboardShortcut{ 'r' , - { E_KeyboardModifier::CTRL , E_KeyboardModifier::SHIFT } } ); - Globals::Window( ).addAction( std::move( reloadCurves ) ); } void T_Main::mainLoop( ) @@ -121,7 +85,7 @@ void T_Main::mainLoop( ) } Globals::Watcher( ).check( ); - Globals::Shaders( ).update( ); + UI::Shaders( ).update( ); glFinish( ); p.startFrame( ); @@ -132,7 +96,7 @@ void T_Main::mainLoop( ) makeUI( ); render( ); p.end( "Full frame" ); - Globals::Window( ).swap( ); + UI::Window( ).swap( ); p.endFrame( ); } } @@ -141,6 +105,7 @@ void T_Main::mainLoop( ) T_Main::~T_Main( ) { demo.clear( ); + UI::Shutdown( ); Globals::Shutdown( ); } @@ -180,7 +145,7 @@ void T_Main::startIteration( ) } } - Globals::Window( ).startFrame( capture , mouseInitial ); + UI::Window( ).startFrame( capture , mouseInitial ); ImGui::GetIO( ).MouseDrawCursor = true; } @@ -222,11 +187,11 @@ void T_Main::handleCapture( ) capture = false; CaptureMouseFromApp( false ); SDL_SetRelativeMouseMode( SDL_FALSE ); - Globals::Window( ).warpMouse( mouseInitial ); + UI::Window( ).warpMouse( mouseInitial ); SetMouseCursor( ImGuiMouseCursor_Arrow ); } else if ( capture ) { SetMouseCursor( ImGuiMouseCursor_Move ); - Globals::Sync( ).handleDragAndDrop( mouseMove , kb , mb ); + UI::Sync( ).handleDragAndDrop( mouseMove , kb , mb ); } else if ( appCanGrab && mb ) { capture = true; mouseInitial = GetMousePos( ); @@ -236,7 +201,7 @@ void T_Main::handleCapture( ) } if ( ( appCanGrab || capture ) && io.MouseWheel ) { - Globals::Sync( ).handleWheel( io.MouseWheel , kb , mb ); + UI::Sync( ).handleWheel( io.MouseWheel , kb , mb ); } } @@ -244,12 +209,11 @@ void T_Main::makeUI( ) { using namespace ImGui; auto& undo( Globals::Undo( ) ); - auto& sync( Globals::Sync( ) ); bool eSequencer{ sequencer }; if ( BeginMainMenuBar( ) ) { if ( BeginMenu( "File" ) ) { - Globals::Window( ).actionMenu( "Save curves" ); - Globals::Window( ).actionMenu( "Reload curves" ); + UI::Window( ).actionMenu( "Save curves" ); + UI::Window( ).actionMenu( "Reload curves" ); Separator( ); if ( MenuItem( "Undo" , "C-z" , false , undo.canUndo( ) ) ) { undo.undo( ); @@ -265,14 +229,14 @@ void T_Main::makeUI( ) } if ( BeginMenu( "Views" ) ) { MenuItemCheckbox( "Input overrides" , - &sync.overridesWindowEnabled( ) ); + &UI::Sync( ).overridesWindowEnabled( ) ); MenuItemCheckbox( "Output debugger" , - &Globals::ODbg( ).uiEnabled( ) ); + &UI::ODbg( ).uiEnabled( ) ); MenuItemCheckbox( "Profiler" , &Globals::Profiler( ).uiEnabled( ) ); MenuItemCheckbox( "Sequencer" , &eSequencer ); MenuItemCheckbox( "Shaders" , - &Globals::Shaders( ).uiEnabled( ) ); + &UI::Shaders( ).uiEnabled( ) ); EndMenu( ); } EndMainMenuBar( ); @@ -285,9 +249,9 @@ void T_Main::makeUI( ) } Globals::Profiler( ).makeUI( ); - Globals::ODbg( ).makeUI( ); - Globals::Shaders( ).makeUI( ); - Globals::Sync( ).makeOverridesWindow( ); + UI::ODbg( ).makeUI( ); + UI::Shaders( ).makeUI( ); + UI::Sync( ).makeOverridesWindow( ); if ( sequencer && !sequencer->display( ) ) { sequencer.clear( ); } @@ -300,8 +264,8 @@ void T_Main::render( ) Globals::Profiler( ).start( "Debug" ); T_Rendertarget::MainOutput( ); - if ( Globals::ODbg( ).isActive( ) ) { - Globals::ODbg( ).debugOutput( ); + if ( UI::ODbg( ).isActive( ) ) { + UI::ODbg( ).debugOutput( ); } glFinish( ); Globals::Profiler( ).end( "Debug" ); @@ -311,10 +275,10 @@ void T_Main::render( ) glClear( GL_COLOR_BUFFER_BIT ); } - Globals::Window( ).handleDialogs( ); + UI::Window( ).handleDialogs( ); glUseProgram( 0 ); glBindProgramPipeline( 0 ); - Globals::Textures( ).reset( ); + UI::Textures( ).reset( ); glClearColor( 0 , 0 , 0 , 1 ); ImGui::Render( ); } diff --git a/odbg.cc b/odbg.cc index a3282a5..a8e2517 100644 --- a/odbg.cc +++ b/odbg.cc @@ -1,6 +1,6 @@ #include "externals.hh" #include "odbg.hh" -#include "globals.hh" +#include "ui.hh" namespace { @@ -108,7 +108,7 @@ void T_OutputDebugger::debugOutput( ) return; } - auto& tm( Globals::Textures( ) ); + auto& tm( UI::Textures( ) ); glBindTextureUnit( 0 , info.id ); glBindSampler( 0 , tm.sampler( "nearest-border" )->id( ) ); @@ -138,7 +138,7 @@ void T_OutputDebugger::registerSubmode( sb << shader << ".glsl" << '\0'; submodes_[ int( mode ) ].add( T_Submode_{ name , - Globals::Shaders( ).pipeline({ + UI::Shaders( ).pipeline({ "fullscreen.v.glsl" , sb.data( ) }) , setup } ); diff --git a/opemu.cc b/opemu.cc index 8f9aeb0..c818e26 100644 --- a/opemu.cc +++ b/opemu.cc @@ -1,6 +1,7 @@ #include "externals.hh" #include "opemu.hh" #include "globals.hh" +#include "ui.hh" #include "profiling.hh" #include "rendertarget.hh" #include "sync.hh" @@ -69,7 +70,7 @@ struct T_RunGuard glUseProgram( 0 ); glBindProgramPipeline( 0 ); glBindFramebuffer( GL_FRAMEBUFFER , 0 ); - Globals::Textures( ).reset( ); + UI::Textures( ).reset( ); } }; } @@ -436,7 +437,7 @@ void T_OpContext::run( } pipelines[ plIndex ] = NewOwned< T_ShaderPipeline >( - Globals::Shaders( ).pipeline( progNames , instr.args[ 0 ] + 1 ) ); + UI::Shaders( ).pipeline( progNames , instr.args[ 0 ] + 1 ) ); break; } @@ -446,7 +447,7 @@ void T_OpContext::run( throw X_OpFailure{ instr , "invalid argument" }; } programs.add( NewOwned< T_ShaderProgram >( - Globals::Shaders( ).program( program.progNames[ instr.args[ 0 ] ] ) ) ); + UI::Shaders( ).program( program.progNames[ instr.args[ 0 ] ] ) ) ); wreg = programs.size( ); break; } @@ -551,7 +552,7 @@ void T_OpContext::run( throw X_OpFailure{ instr , "invalid sampler" }; } - Globals::Textures( ).bind( instr.args[ 0 ] , + UI::Textures( ).bind( instr.args[ 0 ] , *textures[ svt - 1 ] , *samplers[ svs - 1 ] ); break; } @@ -710,7 +711,7 @@ void T_OpContext::run( if ( svt == 0 || svt > textures.size( ) || !textures[ svt - 1 ] ) { throw X_OpFailure{ instr , "invalid texture" }; } - Globals::ODbg( ).registerTexture( *textures[ svt - 1 ] , + UI::ODbg( ).registerTexture( *textures[ svt - 1 ] , E_ODbgMode( instr.args[ 0 ] ) , program.uiStrings[ instr.args[ 1 ] ] ); break; diff --git a/shaders.cc b/shaders.cc index dd73669..62bedfe 100644 --- a/shaders.cc +++ b/shaders.cc @@ -1,6 +1,7 @@ #include "externals.hh" #include "shaders.hh" #include "globals.hh" +#include "ui.hh" #include "ui-utilities.hh" #include @@ -214,14 +215,14 @@ T_ShaderProgram::T_ShaderProgram( : id_( id ) { if ( id_ ) { - Globals::Shaders( ).programs_[ id_ - 1 ].saReferences ++; + UI::Shaders( ).programs_[ id_ - 1 ].saReferences ++; } } T_ShaderProgram::~T_ShaderProgram( ) { if ( id_ ) { - Globals::Shaders( ).dereferenceProgram( id_ - 1 ); + UI::Shaders( ).dereferenceProgram( id_ - 1 ); } } @@ -230,11 +231,11 @@ T_ShaderProgram& T_ShaderProgram::operator=( { if ( this != &other ) { if ( id_ ) { - Globals::Shaders( ).dereferenceProgram( id_ - 1 ); + UI::Shaders( ).dereferenceProgram( id_ - 1 ); } id_ = other.id_; if ( id_ ) { - Globals::Shaders( ).programs_[ id_ - 1 ].saReferences ++; + UI::Shaders( ).programs_[ id_ - 1 ].saReferences ++; } } return *this; @@ -245,7 +246,7 @@ T_ShaderProgram& T_ShaderProgram::operator=( { if ( this != &other ) { if ( id_ ) { - Globals::Shaders( ).dereferenceProgram( id_ - 1 ); + UI::Shaders( ).dereferenceProgram( id_ - 1 ); } id_ = other.id_; other.id_ = T_String{}; @@ -255,7 +256,7 @@ T_ShaderProgram& T_ShaderProgram::operator=( bool T_ShaderProgram::valid( ) const noexcept { - return id_ && Globals::Shaders( ).programs_[ id_ - 1 ].id != 0; + return id_ && UI::Shaders( ).programs_[ id_ - 1 ].id != 0; } void T_ShaderProgram::enable( ) const @@ -264,7 +265,7 @@ void T_ShaderProgram::enable( ) const return; } - auto const& p( Globals::Shaders( ).programs_[ id_ - 1 ] ); + auto const& p( UI::Shaders( ).programs_[ id_ - 1 ] ); if ( p.id ) { glBindProgramPipeline( 0 ); glUseProgram( p.id ); @@ -274,7 +275,7 @@ void T_ShaderProgram::enable( ) const GLuint T_ShaderProgram::id( ) const { if ( id_ ) { - return Globals::Shaders( ).programs_[ id_ - 1 ].id; + return UI::Shaders( ).programs_[ id_ - 1 ].id; } else { return 0; } @@ -283,7 +284,7 @@ GLuint T_ShaderProgram::id( ) const T_Optional< E_ShaderType > T_ShaderProgram::type( ) const { if ( id_ ) { - return Globals::Shaders( ).programs_[ id_ - 1 ].code.type; + return UI::Shaders( ).programs_[ id_ - 1 ].code.type; } else { return {}; } @@ -292,7 +293,7 @@ T_Optional< E_ShaderType > T_ShaderProgram::type( ) const T_String T_ShaderProgram::name( ) const { if ( id_ ) { - return Globals::Shaders( ).programs_[ id_ - 1 ].name; + return UI::Shaders( ).programs_[ id_ - 1 ].name; } else { return {}; } @@ -321,14 +322,14 @@ T_ShaderPipeline::T_ShaderPipeline( T_String id ) noexcept : id_( std::move( id ) ) { if ( id_ ) { - Globals::Shaders( ).pipelines_.get( id_ )->references ++; + UI::Shaders( ).pipelines_.get( id_ )->references ++; } } T_ShaderPipeline::~T_ShaderPipeline( ) { if ( id_ ) { - Globals::Shaders( ).dereferencePipeline( id_ ); + UI::Shaders( ).dereferencePipeline( id_ ); } } @@ -337,11 +338,11 @@ T_ShaderPipeline& T_ShaderPipeline::operator=( { if ( this != &other ) { if ( id_ ) { - Globals::Shaders( ).dereferencePipeline( id_ ); + UI::Shaders( ).dereferencePipeline( id_ ); } id_ = other.id_; if ( id_ ) { - Globals::Shaders( ).pipelines_.get( id_ )->references ++; + UI::Shaders( ).pipelines_.get( id_ )->references ++; } } return *this; @@ -352,7 +353,7 @@ T_ShaderPipeline& T_ShaderPipeline::operator=( { if ( this != &other ) { if ( id_ ) { - Globals::Shaders( ).dereferencePipeline( id_ ); + UI::Shaders( ).dereferencePipeline( id_ ); } id_ = other.id_; other.id_ = T_String{}; @@ -363,7 +364,7 @@ T_ShaderPipeline& T_ShaderPipeline::operator=( bool T_ShaderPipeline::valid( ) const noexcept { return id_ - && Globals::Shaders( ).pipelines_.get( id_ )->id != 0; + && UI::Shaders( ).pipelines_.get( id_ )->id != 0; } void T_ShaderPipeline::enable( ) const @@ -372,7 +373,7 @@ void T_ShaderPipeline::enable( ) const return; } - auto const* pl( Globals::Shaders( ).pipelines_.get( id_ ) ); + auto const* pl( UI::Shaders( ).pipelines_.get( id_ ) ); if ( pl && pl->id ) { glUseProgram( 0 ); glBindProgramPipeline( pl->id ); @@ -382,7 +383,7 @@ void T_ShaderPipeline::enable( ) const GLuint T_ShaderPipeline::id( ) const { if ( id_ ) { - return Globals::Shaders( ).pipelines_.get( id_ )->id; + return UI::Shaders( ).pipelines_.get( id_ )->id; } else { return 0; } @@ -395,7 +396,7 @@ GLuint T_ShaderPipeline::program( return 0; } - auto const& sm( Globals::Shaders( ) ); + auto const& sm( UI::Shaders( ) ); auto const& pl( *sm.pipelines_.get( id_ ) ); for ( auto const& pn : pl.programs ) { auto const* pos( sm.programIndex_.get( pn ) ); diff --git a/sync.cc b/sync.cc index 2a4e0ec..de56571 100644 --- a/sync.cc +++ b/sync.cc @@ -10,18 +10,6 @@ #include using ebcl::T_SRDParserConfig; -namespace { - -const std::map< std::string , T_SyncSegment::E_SegmentType > SegmentTypes_( ([] { - std::map< std::string , T_SyncSegment::E_SegmentType > t; - t.emplace( "linear" , T_SyncSegment::LINEAR ); - t.emplace( "ramp" , T_SyncSegment::RAMP ); - t.emplace( "smooth" , T_SyncSegment::SMOOTH ); - return t; -})()); - -} - /*= SRD parser for the curves ================================================*/ @@ -432,40 +420,6 @@ void A_SyncOverride::setup( ) noexcept id_ = std::move( sb ); } -char const* A_SyncOverride::buildLabel( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - sb.clear( ) << "temp label " << counter << '\0'; - counter ++; - return sb.data( ); -} - - -void A_SyncOverride::makeUI( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - - if ( Checkbox( &title_[ 0 ] , &enabled_ ) ) { - Globals::Sync( ).setOverridesActive( enabled_ , inputPos_.size( ) , &inputPos_[ 0 ] ); - } - if ( !enabled_ ) { - PushItemFlag( ImGuiItemFlags_Disabled , true ); - PushStyleVar( ImGuiStyleVar_Alpha , GetStyle( ).Alpha * 0.5f ); - } - Indent( ); - PushItemWidth( -1 ); - makeEditWidgets( counter , sb ); - PopItemWidth( ); - Unindent( ); - if ( !enabled_ ) { - PopItemFlag( ); - PopStyleVar( ); - } -} - /*= T_SyncOverrideSection ====================================================*/ @@ -486,33 +440,6 @@ void T_SyncOverrideSection::merge( } } -void T_SyncOverrideSection::makeUI( - uint32_t& counter , - T_StringBuilder& tempSb , - const bool topLevel ) noexcept -{ - const bool display( topLevel - ? ImGui::CollapsingHeader( &cTitle[ 0 ] ) - : ImGui::TreeNode( &cTitle[ 0 ] ) ); - if ( !display ) { - return; - } - - for ( auto& os : subsections ) { - os->makeUI( counter , tempSb ); - } - if ( subsections.size( ) && overrides.size( ) ) { - ImGui::Separator( ); - } - for ( auto& ov : overrides ) { - ov->makeUI( counter , tempSb ); - } - - if ( !topLevel ) { - ImGui::TreePop( ); - } -} - T_SyncOverrideSection& T_SyncOverrideSection::section( T_String const& name ) noexcept { @@ -803,7 +730,6 @@ void T_SyncManager::updateValues( ) void T_SyncManager::clearOverrides( ) noexcept { - mouseDelegate_ = nullptr; soRoot_.subsections.clear( ); soRoot_.overrides.clear( ); soTable_.clear( ); @@ -866,52 +792,3 @@ void T_SyncManager::visitOverrides( { soVisitor_.visitor.visit( &soRoot_ , visitor ); } - -/*------------------------------------------------------------------------------*/ - -void T_SyncManager::makeOverridesWindow( ) -{ - if ( !ovWindow_ ) { - return; - } - - using namespace ImGui; - auto const& dspSize( GetIO( ).DisplaySize ); - SetNextWindowSize( ImVec2( dspSize.x * .25f , dspSize.y * .66f - 20 ) , ImGuiSetCond_Appearing ); - SetNextWindowPos( ImVec2( 0 , 20 ) , ImGuiSetCond_Appearing ); - Begin( "Input overrides" , &ovWindow_ , - ImGuiWindowFlags_NoCollapse ); - - if ( soRoot_.subsections.empty( ) ) { - Text( "No overrides have been defined." ); - } else { - T_StringBuilder temp; - uint32_t counter{ 0 }; - for ( auto& section : soRoot_.subsections ) { - section->makeUI( counter , temp , true ); - } - } - End( ); -} - -/*------------------------------------------------------------------------------*/ - -void T_SyncManager::handleDragAndDrop( - ImVec2 const& move , - T_KeyboardModifiers modifiers , - T_MouseButtons buttons ) noexcept -{ - if ( mouseDelegate_ ) { - mouseDelegate_->handleDragAndDrop( move , modifiers , buttons ); - } -} - -void T_SyncManager::handleWheel( - const float wheel , - T_KeyboardModifiers modifiers , - T_MouseButtons buttons ) noexcept -{ - if ( mouseDelegate_ ) { - mouseDelegate_->handleWheel( wheel , modifiers , buttons ); - } -} diff --git a/sync.hh b/sync.hh index e069f1e..d3516d7 100644 --- a/sync.hh +++ b/sync.hh @@ -1,7 +1,6 @@ #pragma once #include "filewatcher.hh" #include "utilities.hh" -#include "ui-mousectrl.hh" #include #include @@ -189,18 +188,6 @@ class A_SyncOverride A_SyncOverride( char const* type , T_String const& title ) noexcept; - // Build a temporary label for use with ImGui. The label is valid - // until the next call to buildLabel(), as it is in fact stored - // in the string builder. - char const* buildLabel( - uint32_t& counter , - T_StringBuilder& sb ) noexcept; - - // Draw the UI for that specific override. - virtual void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept = 0; - public: A_SyncOverride( ) = delete; virtual ~A_SyncOverride( ) = 0; @@ -208,9 +195,13 @@ class A_SyncOverride T_String const& type( ) const noexcept { return type_; } - ebcl::T_Set< T_String > const& inputNames( ) const noexcept + auto const& inputNames( ) const noexcept { return inputs_; } + auto const& inputPositions( ) const noexcept + { return inputPos_; } + bool& enabled( ) noexcept + { return enabled_; } bool enabled( ) const noexcept { return enabled_; } @@ -228,12 +219,6 @@ class A_SyncOverride // the inputs have been added. virtual void setup( ) noexcept; - // Draw the title, enable button and editor. The counter and temporary - // string builder are used to generate "fake" labels for ImGui. - virtual void makeUI( - uint32_t& counter , - T_StringBuilder& sb ) noexcept; - // Create a clone of the current override. virtual T_OwnPtr< A_SyncOverride > clone( ) const noexcept = 0; }; @@ -288,7 +273,7 @@ struct T_SyncOverrideVisitor // Synchronisation manager; handles all the synchronization data and makes it // work together. -struct T_SyncManager : public virtual A_MouseCtrl +struct T_SyncManager { T_SyncManager( ); @@ -391,30 +376,6 @@ struct T_SyncManager : public virtual A_MouseCtrl void updateValues( ); - // --------------------------------------------------------------------- - // User interface - - bool& overridesWindowEnabled( ) noexcept - { return ovWindow_; } - void makeOverridesWindow( ); - - void delegateMouse( A_MouseCtrl& delegate ) noexcept - { mouseDelegate_ = &delegate; } - void clearMouseDelegate( ) noexcept - { mouseDelegate_ = nullptr; } - bool isCurrentDelegate( A_MouseCtrl const& delegate ) noexcept - { return mouseDelegate_ == &delegate; } - - void handleDragAndDrop( - ImVec2 const& move , - T_KeyboardModifiers modifiers , - T_MouseButtons buttons ) noexcept override; - void handleWheel( - float wheel , - T_KeyboardModifiers modifiers , - T_MouseButtons buttons ) noexcept override; - - // --------------------------------------------------------------------- // Private data @@ -434,11 +395,8 @@ struct T_SyncManager : public virtual A_MouseCtrl T_SyncCurves curves_; // Curves storage T_Array< P_SyncCurveCache > curveCaches_; // Cache for curve segments - bool ovWindow_{ false }; // Overrides window T_SyncOverrideSection soRoot_; // Root for overrides T_SyncOverrideVisitor soVisitor_; T_KeyValueTable< T_String , A_SyncOverride* > soTable_; // Table of sync overrides, by ID - - A_MouseCtrl* mouseDelegate_{ nullptr }; // Delegate for mouse actions }; diff --git a/syncoverrides.cc b/syncoverrides.cc index 14b8a9b..f21a09a 100644 --- a/syncoverrides.cc +++ b/syncoverrides.cc @@ -641,24 +641,6 @@ T_Float::T_Float( inputs_.add( input ); } -void T_Float::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - float v[ 1 ] = { - Globals::Sync( ).inputs( )[ inputPos_[ 0 ] ] - }; - - char const* const label( buildLabel( counter , sb ) ); - const bool changed( slider( ) - ? SliderFloat( label , v , min( ) , max( ) , decimals( ) , power( ) ) - : DragFloat( label , v , step( ) , min( ) , max( ) , decimals( ) , power( ) ) ); - if ( changed ) { - Globals::Sync( ).inputs( )[ inputPos_[ 0 ] ] = v[ 0 ]; - } -} - P_SyncOverride T_Float::clone( ) const noexcept { auto c{ NewOwned< T_Float >( inputs_[ 0 ] , &title_[ 0 ] ) }; @@ -679,28 +661,6 @@ T_Float2::T_Float2( inputs_.add( input1 ); } -void T_Float2::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - auto& sinp( Globals::Sync( ).inputs( ) ); - float v[ 2 ]; - for ( auto i = 0 ; i < 2 ; i ++ ) { - v[ i ] = sinp[ inputPos_[ i ] ]; - } - - char const* const label( buildLabel( counter , sb ) ); - const bool changed( slider( ) - ? SliderFloat2( label , v , min( ) , max( ) , decimals( ) , power( ) ) - : DragFloat2( label , v , step( ) , min( ) , max( ) , decimals( ) , power( ) ) ); - if ( changed ) { - for ( auto i = 0 ; i < 2 ; i ++ ) { - sinp[ inputPos_[ i ] ] = v[ i ]; - } - } -} - P_SyncOverride T_Float2::clone( ) const noexcept { auto c{ NewOwned< T_Float2 >( inputs_[ 0 ] , inputs_[ 1 ] , &title_[ 0 ] ) }; @@ -723,28 +683,6 @@ T_Float3::T_Float3( inputs_.add( input2 ); } -void T_Float3::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - auto& sinp( Globals::Sync( ).inputs( ) ); - float v[ 3 ]; - for ( auto i = 0 ; i < 3 ; i ++ ) { - v[ i ] = sinp[ inputPos_[ i ] ]; - } - - char const* const label( buildLabel( counter , sb ) ); - const bool changed( slider( ) - ? SliderFloat3( label , v , min( ) , max( ) , decimals( ) , power( ) ) - : DragFloat3( label , v , step( ) , min( ) , max( ) , decimals( ) , power( ) ) ); - if ( changed ) { - for ( auto i = 0 ; i < 3 ; i ++ ) { - sinp[ inputPos_[ i ] ] = v[ i ]; - } - } -} - P_SyncOverride T_Float3::clone( ) const noexcept { auto c{ NewOwned< T_Float3 >( inputs_[ 0 ] , inputs_[ 1 ] , @@ -770,28 +708,6 @@ T_Float4::T_Float4( inputs_.add( input3 ); } -void T_Float4::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - auto& sinp( Globals::Sync( ).inputs( ) ); - float v[ 4 ]; - for ( auto i = 0 ; i < 4 ; i ++ ) { - v[ i ] = sinp[ inputPos_[ i ] ]; - } - - char const* const label( buildLabel( counter , sb ) ); - const bool changed( slider( ) - ? SliderFloat4( label , v , min( ) , max( ) , decimals( ) , power( ) ) - : DragFloat4( label , v , step( ) , min( ) , max( ) , decimals( ) , power( ) ) ); - if ( changed ) { - for ( auto i = 0 ; i < 4 ; i ++ ) { - sinp[ inputPos_[ i ] ] = v[ i ]; - } - } -} - P_SyncOverride T_Float4::clone( ) const noexcept { auto c{ NewOwned< T_Float4 >( inputs_[ 0 ] , inputs_[ 1 ] , @@ -838,24 +754,6 @@ T_Integer::T_Integer( inputs_.add( input ); } -void T_Integer::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - int32_t v[ 1 ] = { - int32_t( Globals::Sync( ).inputs( )[ inputPos_[ 0 ] ] ) - }; - - char const* const label( buildLabel( counter , sb ) ); - const bool changed( slider( ) - ? SliderInt( label , v , min( ) , max( ) ) - : DragInt( label , v , step( ) , min( ) , max( ) ) ); - if ( changed ) { - Globals::Sync( ).inputs( )[ inputPos_[ 0 ] ] = v[ 0 ]; - } -} - P_SyncOverride T_Integer::clone( ) const noexcept { auto c{ NewOwned< T_Integer >( inputs_[ 0 ] , &title_[ 0 ] ) }; @@ -876,28 +774,6 @@ T_Integer2::T_Integer2( inputs_.add( input1 ); } -void T_Integer2::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - auto& sinp( Globals::Sync( ).inputs( ) ); - int32_t v[ 2 ]; - for ( auto i = 0 ; i < 2 ; i ++ ) { - v[ i ] = sinp[ inputPos_[ i ] ]; - } - - char const* const label( buildLabel( counter , sb ) ); - const bool changed( slider( ) - ? SliderInt2( label , v , min( ) , max( ) ) - : DragInt2( label , v , step( ) , min( ) , max( ) ) ); - if ( changed ) { - for ( auto i = 0 ; i < 2 ; i ++ ) { - sinp[ inputPos_[ i ] ] = v[ i ]; - } - } -} - P_SyncOverride T_Integer2::clone( ) const noexcept { auto c{ NewOwned< T_Integer2 >( inputs_[ 0 ] , inputs_[ 1 ] , &title_[ 0 ] ) }; @@ -920,28 +796,6 @@ T_Integer3::T_Integer3( inputs_.add( input2 ); } -void T_Integer3::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - auto& sinp( Globals::Sync( ).inputs( ) ); - int32_t v[ 3 ]; - for ( auto i = 0 ; i < 3 ; i ++ ) { - v[ i ] = sinp[ inputPos_[ i ] ]; - } - - char const* const label( buildLabel( counter , sb ) ); - const bool changed( slider( ) - ? SliderInt3( label , v , min( ) , max( ) ) - : DragInt3( label , v , step( ) , min( ) , max( ) ) ); - if ( changed ) { - for ( auto i = 0 ; i < 3 ; i ++ ) { - sinp[ inputPos_[ i ] ] = v[ i ]; - } - } -} - P_SyncOverride T_Integer3::clone( ) const noexcept { auto c{ NewOwned< T_Integer3 >( inputs_[ 0 ] , inputs_[ 1 ] , @@ -967,28 +821,6 @@ T_Integer4::T_Integer4( inputs_.add( input3 ); } -void T_Integer4::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - auto& sinp( Globals::Sync( ).inputs( ) ); - int32_t v[ 4 ]; - for ( auto i = 0 ; i < 4 ; i ++ ) { - v[ i ] = sinp[ inputPos_[ i ] ]; - } - - char const* const label( buildLabel( counter , sb ) ); - const bool changed( slider( ) - ? SliderInt4( label , v , min( ) , max( ) ) - : DragInt4( label , v , step( ) , min( ) , max( ) ) ); - if ( changed ) { - for ( auto i = 0 ; i < 4 ; i ++ ) { - sinp[ inputPos_[ i ] ] = v[ i ]; - } - } -} - P_SyncOverride T_Integer4::clone( ) const noexcept { auto c{ NewOwned< T_Integer4 >( inputs_[ 0 ] , inputs_[ 1 ] , @@ -1012,30 +844,6 @@ T_ColorGrading::T_ColorGrading( inputs_.add( iBlue ); } -void T_ColorGrading::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - using namespace ImGui; - auto& sinp{ Globals::Sync( ).inputs( ) }; - float v[ 3 ]; - for ( auto i = 0 ; i < 3 ; i ++ ) { - v[ i ] = sinp[ inputPos_[ i ] ]; - } - - char const* const label{ buildLabel( counter , sb ) }; - const bool changed{ ColorGradingControls( - label , - &v[ 0 ] , &v[ 1 ] , &v[ 2 ] , - base( ) , unit( ) ) }; - - if ( changed ) { - for ( auto i = 0 ; i < 3 ; i ++ ) { - sinp[ inputPos_[ i ] ] = v[ i ]; - } - } -} - bool T_ColorGrading::setBase( const float v ) noexcept { @@ -1187,7 +995,7 @@ bool T_CamOverride::checkValidConfig( ) noexcept /*------------------------------------------------------------------------------*/ T_CamOverride::E_SetState T_CamOverride::setVector( - T_Optional< T_VectorConfig_ >& vector , + T_Optional< T_VectorConfig >& vector , T_String const& inX , T_String const& inY , T_String const& inZ ) noexcept @@ -1206,151 +1014,3 @@ T_CamOverride::E_SetState T_CamOverride::setVector( inputs_.add( inZ ); return S_OK; } - -/*------------------------------------------------------------------------------*/ - -void T_CamOverride::makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept -{ - auto& sync( Globals::Sync( ) ); - auto& sinp( sync.inputs( ) ); - auto const& fc( *fovConfig_ ); - - if ( !enabled( ) || !prevEnabled_ ) { - // Set field of view / near plane - if ( fc.mode == FM_FOV ) { - camera_.fieldOfView( sinp[ inputPos_[ fc.inputIndex ] ] ); - } else { - camera_.nearPlane( sinp[ inputPos_[ fc.inputIndex ] ] ); - } - - // Set camera parameters - const glm::vec3 lookAt{ vectorFromInputs( *target_ ) }; - if ( camMode_ == CM_ANGLES ) { - const glm::vec3 angles{ vectorFromInputs( *angles_ ) }; - const float distance{ sinp[ inputPos_[ *distance_ ] ] }; - camera_.camera( lookAt , angles , distance ); - } else { - const glm::vec3 position{ vectorFromInputs( *position_ ) }; - const glm::vec3 up{ vectorFromInputs( *upVector_ ) }; - camera_.camera( lookAt , position , up ); - } - } - prevEnabled_ = enabled( ); - - // Draw UI - char const* const name( buildLabel( counter , sb ) ); - bool mouseHandler{ sync.isCurrentDelegate( *this ) }; - using namespace ImGui; - PushItemWidth( 0 ); // Compensate for -1 - PushID( GetCurrentWindow( )->GetID( name ) ); - const bool handlerChanged{ Checkbox( "Mouse control" , &mouseHandler ) }; - Separator( ); - const auto changes{ camera_.makeUI( ) }; - PopID( ); - PopItemWidth( ); - - if ( handlerChanged ) { - if ( mouseHandler ) { - sync.delegateMouse( *this ); - } else { - sync.clearMouseDelegate( ); - } - } - - if ( changes & T_Camera::E_Changes::FOV ) { - if ( fc.mode == FM_FOV ) { - sinp[ inputPos_[ fc.inputIndex ] ] = camera_.fieldOfView( ); - } else { - sinp[ inputPos_[ fc.inputIndex ] ] = camera_.nearPlane( ); - } - } - if ( changes & T_Camera::E_Changes::MATRIX ) { - inputsFromVector( *target_ , camera_.lookAt( ) ); - if ( camMode_ == CM_ANGLES ) { - inputsFromVector( *angles_ , camera_.angles( ) ); - sinp[ inputPos_[ *distance_ ] ] = camera_.distance( ); - } else { - inputsFromVector( *position_ , camera_.position( ) ); - inputsFromVector( *upVector_ , camera_.upVector( ) ); - } - } -} - -glm::vec3 T_CamOverride::vectorFromInputs( - T_VectorConfig_ const& vc ) noexcept -{ - auto& sinp( Globals::Sync( ).inputs( ) ); - return glm::vec3{ - sinp[ inputPos_[ vc.x ] ] , - sinp[ inputPos_[ vc.y ] ] , - sinp[ inputPos_[ vc.z ] ] }; -} - -void T_CamOverride::inputsFromVector( - T_VectorConfig_ const& vc , - glm::vec3 const& v ) noexcept -{ - auto& sinp( Globals::Sync( ).inputs( ) ); - sinp[ inputPos_[ vc.x ] ] = v.x; - sinp[ inputPos_[ vc.y ] ] = v.y; - sinp[ inputPos_[ vc.z ] ] = v.z; -} - -/*------------------------------------------------------------------------------*/ - -void T_CamOverride::handleDragAndDrop( - ImVec2 const& move , - T_KeyboardModifiers modifiers , - T_MouseButtons buttons ) noexcept -{ - auto& sync( Globals::Sync( ) ); - if ( !enabled( ) ) { - sync.clearMouseDelegate( ); - return; - } - camera_.handleDragAndDrop( move , modifiers , buttons ); - - auto& sinp( sync.inputs( ) ); - inputsFromVector( *target_ , camera_.lookAt( ) ); - if ( camMode_ == CM_ANGLES ) { - inputsFromVector( *angles_ , camera_.angles( ) ); - sinp[ inputPos_[ *distance_ ] ] = camera_.distance( ); - } else { - inputsFromVector( *position_ , camera_.position( ) ); - inputsFromVector( *upVector_ , camera_.upVector( ) ); - } -} - -void T_CamOverride::handleWheel( - const float wheel , - T_KeyboardModifiers modifiers , - T_MouseButtons buttons ) noexcept -{ - auto& sync( Globals::Sync( ) ); - if ( !enabled( ) ) { - sync.clearMouseDelegate( ); - return; - } - camera_.handleWheel( wheel , modifiers , buttons ); - - auto& sinp( sync.inputs( ) ); - if ( modifiers & E_KeyboardModifier::SHIFT ) { - auto const& fc( *fovConfig_ ); - if ( fc.mode == FM_FOV ) { - sinp[ inputPos_[ fc.inputIndex ] ] = camera_.fieldOfView( ); - } else { - sinp[ inputPos_[ fc.inputIndex ] ] = camera_.nearPlane( ); - } - } else { - inputsFromVector( *target_ , camera_.lookAt( ) ); - if ( camMode_ == CM_ANGLES ) { - inputsFromVector( *angles_ , camera_.angles( ) ); - sinp[ inputPos_[ *distance_ ] ] = camera_.distance( ); - } else { - inputsFromVector( *position_ , camera_.position( ) ); - inputsFromVector( *upVector_ , camera_.upVector( ) ); - } - } -} diff --git a/syncoverrides.hh b/syncoverrides.hh index d982008..201a03f 100644 --- a/syncoverrides.hh +++ b/syncoverrides.hh @@ -53,10 +53,6 @@ class A_Float : public A_SyncOverride // Single float values class T_Float : public A_Float { - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; public: T_Float( T_String const& input , T_String const& title ) noexcept; @@ -67,10 +63,6 @@ class T_Float : public A_Float // 2 float values class T_Float2 : public A_Float { - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; public: T_Float2( T_String const& input0 , T_String const& input1 , @@ -82,10 +74,6 @@ class T_Float2 : public A_Float // 3 float values class T_Float3 : public A_Float { - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; public: T_Float3( T_String const& input0 , T_String const& input1 , @@ -98,10 +86,6 @@ class T_Float3 : public A_Float // 4 float values class T_Float4 : public A_Float { - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; public: T_Float4( T_String const& input0 , T_String const& input1 , @@ -155,10 +139,6 @@ class A_Integer : public A_SyncOverride // Single integers class T_Integer : public A_Integer { - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; public: T_Integer( T_String const& input , T_String const& title ) noexcept; @@ -169,10 +149,6 @@ class T_Integer : public A_Integer // 2 integers class T_Integer2 : public A_Integer { - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; public: T_Integer2( T_String const& input0 , T_String const& input1 , @@ -184,10 +160,6 @@ class T_Integer2 : public A_Integer // 3 integers class T_Integer3 : public A_Integer { - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; public: T_Integer3( T_String const& input0 , T_String const& input1 , @@ -200,10 +172,6 @@ class T_Integer3 : public A_Integer // 4 integers class T_Integer4 : public A_Integer { - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; public: T_Integer4( T_String const& input0 , T_String const& input1 , @@ -223,11 +191,6 @@ class T_ColorGrading : public A_SyncOverride T_Optional< float > base_; T_Optional< float > unit_; - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; - public: T_ColorGrading( T_String const& iRed , T_String const& iGreen , @@ -246,7 +209,7 @@ class T_ColorGrading : public A_SyncOverride /*= CAMERA CONTROLS ============================================================*/ -class T_CamOverride : public A_SyncOverride , public virtual A_MouseCtrl +class T_CamOverride : public A_SyncOverride { public: enum E_SetState { @@ -255,57 +218,60 @@ class T_CamOverride : public A_SyncOverride , public virtual A_MouseCtrl S_INPUTS , // Duplicate inputs }; - private: - enum E_CamMode_ { + enum E_CamMode { CM_INVALID , CM_ANGLES , CM_VECTORS }; - enum E_FovMode_ { + enum E_FovMode { FM_INVALID , FM_FOV , FM_NEARPLANE , }; - struct T_FovConfig_ + struct T_FovConfig { - E_FovMode_ mode; + E_FovMode mode; uint32_t inputIndex; - T_FovConfig_( E_FovMode_ mode , uint32_t idx ) noexcept + T_FovConfig( E_FovMode mode , uint32_t idx ) noexcept : mode( mode ) , inputIndex( idx ) { assert( mode != FM_INVALID ); } }; - struct T_VectorConfig_ + struct T_VectorConfig { uint32_t x , y , z; - T_VectorConfig_( uint32_t x , uint32_t y , uint32_t z ) noexcept + T_VectorConfig( uint32_t x , uint32_t y , + uint32_t z ) noexcept : x(x),y(y),z(z) {} }; - T_Optional< T_FovConfig_ > fovConfig_; - T_Optional< T_VectorConfig_ > target_; + private: + T_Optional< T_FovConfig > fovConfig_; + T_Optional< T_VectorConfig > target_; - T_Optional< T_VectorConfig_ > upVector_; - T_Optional< T_VectorConfig_ > position_; + T_Optional< T_VectorConfig > upVector_; + T_Optional< T_VectorConfig > position_; - T_Optional< T_VectorConfig_ > angles_; + T_Optional< T_VectorConfig > angles_; T_Optional< uint32_t > distance_; - E_CamMode_ camMode_; + E_CamMode camMode_; T_Camera camera_; bool prevEnabled_{ false }; public: T_CamOverride( T_String const& title ) noexcept; - P_SyncOverride clone( ) const noexcept override; + //---------------------------------------------------------------------- + // Set configuration + E_SetState setFieldOfView( T_String const& input ) noexcept; E_SetState setNearPlane( @@ -332,44 +298,52 @@ class T_CamOverride : public A_SyncOverride , public virtual A_MouseCtrl E_SetState setDistance( T_String const& input ) noexcept; + //---------------------------------------------------------------------- + // Check configuration + bool isFovConfigured( ) const noexcept { return fovConfig_; } bool isTargetConfigured( ) const noexcept { return target_; } bool checkValidConfig( ) noexcept; + //---------------------------------------------------------------------- + // Read configuration + + T_FovConfig const& fovConfig( ) const noexcept + { return *fovConfig_; } + T_VectorConfig const& target( ) const noexcept + { return *target_; } + E_CamMode mode( ) const noexcept + { return camMode_; } + + auto const& angles( ) const noexcept + { return *angles_; } + auto const& distance( ) const noexcept + { return *distance_; } + + auto const& position( ) const noexcept + { return *position_; } + auto const& up( ) const noexcept + { return *upVector_; } + + //---------------------------------------------------------------------- + // State + T_Camera& camData( ) noexcept { return camera_; } T_Camera const& camData( ) const noexcept { return camera_; } - void handleDragAndDrop( - ImVec2 const& move , - T_KeyboardModifiers modifiers , - T_MouseButtons buttons ) noexcept override; - void handleWheel( - float wheel , - T_KeyboardModifiers modifiers , - T_MouseButtons buttons ) noexcept override; + bool& prevEnabled( ) noexcept + { return prevEnabled_; } private: E_SetState setVector( - T_Optional< T_VectorConfig_ >& vector , + T_Optional< T_VectorConfig >& vector , T_String const& inX , T_String const& inY , T_String const& inZ ) noexcept; - - protected: - void makeEditWidgets( - uint32_t& counter , - T_StringBuilder& sb ) noexcept override; - - private: - glm::vec3 vectorFromInputs( - T_VectorConfig_ const& inputs ) noexcept; - void inputsFromVector( - T_VectorConfig_ const& inputs , - glm::vec3 const& vector ) noexcept; }; diff --git a/texture.cc b/texture.cc index 469eba0..33aa792 100644 --- a/texture.cc +++ b/texture.cc @@ -1,6 +1,6 @@ #include "externals.hh" #include "texture.hh" -#include "globals.hh" +#include "ui.hh" #include "odbg.hh" #include "ui-utilities.hh" @@ -84,7 +84,7 @@ T_Texture::T_Texture( T_Texture::~T_Texture( ) { if ( debugIndex_ != -1 ) { - auto& odbg( Globals::ODbg( ) ); + auto& odbg( UI::ODbg( ) ); assert( odbg.outputs_[ debugIndex_ ].id == id_ ); assert( odbg.nRegistered_ > 0 ); odbg.outputs_[ debugIndex_ ].id = 0; diff --git a/ui-mousectrl.hh b/ui-mousectrl.hh index 7e5584a..b18f798 100644 --- a/ui-mousectrl.hh +++ b/ui-mousectrl.hh @@ -21,5 +21,6 @@ class A_MouseCtrl T_MouseButtons buttons ) noexcept = 0; }; +using P_MouseCtrl = T_OwnPtr< A_MouseCtrl >; inline A_MouseCtrl::~A_MouseCtrl() {} diff --git a/ui-overrides.cc b/ui-overrides.cc new file mode 100644 index 0000000..e424bb4 --- /dev/null +++ b/ui-overrides.cc @@ -0,0 +1,426 @@ +#include "externals.hh" +#include "globals.hh" +#include "ui.hh" +#include "ui-colorgrading.hh" +#include "ui-overrides.hh" +#include "ui-sync.hh" + +#include + + +namespace sov { + +namespace { + +char const* BuildLabel_( + uint32_t& counter , + T_StringBuilder& sb ) noexcept +{ + sb.clear( ) << "##temp label " << counter << '\0'; + counter ++; + return sb.data( ); +} + +} // namespace + + +/*= FLOAT OVERRIDES ==========================================================*/ + +M_DECL_SOVUI( Float ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_Float& >( ovp ) }; + float v[ 1 ] = { + Globals::Sync( ).inputs( )[ ov.inputPositions( )[ 0 ] ] + }; + + char const* const label( BuildLabel_( counter , sb ) ); + const bool changed( ov.slider( ) + ? SliderFloat( label , v , ov.min( ) , ov.max( ) , + ov.decimals( ) , ov.power( ) ) + : DragFloat( label , v , ov.step( ) , ov.min( ) , + ov.max( ) , ov.decimals( ) , ov.power( ) ) ); + if ( changed ) { + Globals::Sync( ).inputs( )[ ov.inputPositions( )[ 0 ] ] = v[ 0 ]; + } +} + +M_DECL_SOVUI( Float2 ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_Float2& >( ovp ) }; + auto& sinp( Globals::Sync( ).inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + float v[ 2 ]; + for ( auto i = 0 ; i < 2 ; i ++ ) { + v[ i ] = sinp[ ovip[ i ] ]; + } + + char const* const label( BuildLabel_( counter , sb ) ); + const bool changed( ov.slider( ) + ? SliderFloat2( label , v , ov.min( ) , ov.max( ) , + ov.decimals( ) , ov.power( ) ) + : DragFloat2( label , v , ov.step( ) , ov.min( ) , + ov.max( ) , ov.decimals( ) , ov.power( ) ) ); + if ( changed ) { + for ( auto i = 0 ; i < 2 ; i ++ ) { + sinp[ ovip[ i ] ] = v[ i ]; + } + } +} + +M_DECL_SOVUI( Float3 ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_Float3& >( ovp ) }; + auto& sinp( Globals::Sync( ).inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + float v[ 3 ]; + for ( auto i = 0 ; i < 3 ; i ++ ) { + v[ i ] = sinp[ ovip[ i ] ]; + } + + char const* const label( BuildLabel_( counter , sb ) ); + const bool changed( ov.slider( ) + ? SliderFloat3( label , v , ov.min( ) , ov.max( ) , + ov.decimals( ) , ov.power( ) ) + : DragFloat3( label , v , ov.step( ) , ov.min( ) , + ov.max( ) , ov.decimals( ) , ov.power( ) ) ); + if ( changed ) { + for ( auto i = 0 ; i < 3 ; i ++ ) { + sinp[ ovip[ i ] ] = v[ i ]; + } + } +} + +M_DECL_SOVUI( Float4 ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_Float4& >( ovp ) }; + auto& sinp( Globals::Sync( ).inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + float v[ 4 ]; + for ( auto i = 0 ; i < 4 ; i ++ ) { + v[ i ] = sinp[ ovip[ i ] ]; + } + + char const* const label( BuildLabel_( counter , sb ) ); + const bool changed( ov.slider( ) + ? SliderFloat4( label , v , ov.min( ) , ov.max( ) , + ov.decimals( ) , ov.power( ) ) + : DragFloat4( label , v , ov.step( ) , ov.min( ) , + ov.max( ) , ov.decimals( ) , ov.power( ) ) ); + if ( changed ) { + for ( auto i = 0 ; i < 4 ; i ++ ) { + sinp[ ovip[ i ] ] = v[ i ]; + } + } +} + + +/*= INTEGER OVERRIDES ========================================================*/ + +M_DECL_SOVUI( Integer ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_Integer& >( ovp ) }; + auto& sinp( Globals::Sync( ).inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + int32_t v[ 1 ] = { + int32_t( sinp[ ovip[ 0 ] ] ) + }; + + char const* const label( BuildLabel_( counter , sb ) ); + const bool changed( ov.slider( ) + ? SliderInt( label , v , ov.min( ) , ov.max( ) ) + : DragInt( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) ); + if ( changed ) { + sinp[ ovip[ 0 ] ] = v[ 0 ]; + } +} + +M_DECL_SOVUI( Integer2 ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_Integer2& >( ovp ) }; + auto& sinp( Globals::Sync( ).inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + int32_t v[ 2 ]; + for ( auto i = 0 ; i < 2 ; i ++ ) { + v[ i ] = sinp[ ovip[ i ] ]; + } + + char const* const label( BuildLabel_( counter , sb ) ); + const bool changed( ov.slider( ) + ? SliderInt2( label , v , ov.min( ) , ov.max( ) ) + : DragInt2( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) ); + if ( changed ) { + for ( auto i = 0 ; i < 2 ; i ++ ) { + sinp[ ovip[ i ] ] = v[ i ]; + } + } +} + +M_DECL_SOVUI( Integer3 ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_Integer3& >( ovp ) }; + auto& sinp( Globals::Sync( ).inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + int32_t v[ 3 ]; + for ( auto i = 0 ; i < 3 ; i ++ ) { + v[ i ] = sinp[ ovip[ i ] ]; + } + + char const* const label( BuildLabel_( counter , sb ) ); + const bool changed( ov.slider( ) + ? SliderInt3( label , v , ov.min( ) , ov.max( ) ) + : DragInt3( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) ); + if ( changed ) { + for ( auto i = 0 ; i < 3 ; i ++ ) { + sinp[ ovip[ i ] ] = v[ i ]; + } + } +} + +M_DECL_SOVUI( Integer4 ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_Integer4& >( ovp ) }; + auto& sinp( Globals::Sync( ).inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + int32_t v[ 4 ]; + for ( auto i = 0 ; i < 4 ; i ++ ) { + v[ i ] = sinp[ ovip[ i ] ]; + } + + char const* const label( BuildLabel_( counter , sb ) ); + const bool changed( ov.slider( ) + ? SliderInt4( label , v , ov.min( ) , ov.max( ) ) + : DragInt4( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) ); + if ( changed ) { + for ( auto i = 0 ; i < 4 ; i ++ ) { + sinp[ ovip[ i ] ] = v[ i ]; + } + } +} + + +/*= COLOR GRADING OVERRIDES ==================================================*/ + +M_DECL_SOVUI( ColorGrading ) +{ + using namespace ImGui; + auto& ov{ dynamic_cast< T_ColorGrading& >( ovp ) }; + auto& sinp{ Globals::Sync( ).inputs( ) }; + auto const& ovip{ ov.inputPositions( ) }; + float v[ 3 ]; + for ( auto i = 0 ; i < 3 ; i ++ ) { + v[ i ] = sinp[ ovip[ i ] ]; + } + + char const* const label{ BuildLabel_( counter , sb ) }; + const bool changed{ ColorGradingControls( + label , + &v[ 0 ] , &v[ 1 ] , &v[ 2 ] , + ov.base( ) , ov.unit( ) ) }; + + if ( changed ) { + for ( auto i = 0 ; i < 3 ; i ++ ) { + sinp[ ovip[ i ] ] = v[ i ]; + } + } +} + + +/*= CAMERA OVERRIDES =========================================================*/ + +namespace { + +glm::vec3 VectorFromInputs_( + T_CamOverride::T_VectorConfig const& vc , + T_AutoArray< uint32_t , 8 > const& ovip ) noexcept +{ + auto& sinp( Globals::Sync( ).inputs( ) ); + return glm::vec3{ + sinp[ ovip[ vc.x ] ] , + sinp[ ovip[ vc.y ] ] , + sinp[ ovip[ vc.z ] ] }; +} + +void InputsFromVector_( + T_CamOverride::T_VectorConfig const& vc , + T_AutoArray< uint32_t , 8 > const& ovip , + glm::vec3 const& v ) noexcept +{ + auto& sinp( Globals::Sync( ).inputs( ) ); + sinp[ ovip[ vc.x ] ] = v.x; + sinp[ ovip[ vc.y ] ] = v.y; + sinp[ ovip[ vc.z ] ] = v.z; +} + +/*------------------------------------------------------------------------------*/ + +struct T_MouseCam_ : public virtual A_MouseCtrl +{ + T_Camera& camera; + T_CamOverride& ov; + + T_MouseCam_( T_Camera& cam , + T_CamOverride& ov ) noexcept + : camera( cam ) , ov( ov ) + { } + + void handleDragAndDrop( + ImVec2 const& move , + T_KeyboardModifiers modifiers , + T_MouseButtons buttons ) noexcept override; + + void handleWheel( + float wheel , + T_KeyboardModifiers modifiers , + T_MouseButtons buttons ) noexcept override; +}; + +/*------------------------------------------------------------------------------*/ + +void T_MouseCam_::handleDragAndDrop( + ImVec2 const& move , + T_KeyboardModifiers modifiers , + T_MouseButtons buttons ) noexcept +{ + auto& sync( Globals::Sync( ) ); + if ( !ov.enabled( ) ) { + UI::Sync( ).clearMouseDelegate( ); + return; + } + + camera.handleDragAndDrop( move , modifiers , buttons ); + + auto& sinp( sync.inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + InputsFromVector_( ov.target( ) , ovip , camera.lookAt( ) ); + if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) { + InputsFromVector_( ov.angles( ) , ovip , camera.angles( ) ); + sinp[ ovip[ ov.distance( ) ] ] = camera.distance( ); + } else { + InputsFromVector_( ov.position( ) , ovip , camera.position( ) ); + InputsFromVector_( ov.up( ) , ovip , camera.upVector( ) ); + } +} + +void T_MouseCam_::handleWheel( + const float wheel , + T_KeyboardModifiers modifiers , + T_MouseButtons buttons ) noexcept +{ + auto& sync( Globals::Sync( ) ); + if ( !ov.enabled( ) ) { + UI::Sync( ).clearMouseDelegate( ); + return; + } + + camera.handleWheel( wheel , modifiers , buttons ); + + auto& sinp( sync.inputs( ) ); + auto const& ovip{ ov.inputPositions( ) }; + if ( modifiers & E_KeyboardModifier::SHIFT ) { + auto const& fc( ov.fovConfig( ) ); + if ( fc.mode == T_CamOverride::FM_FOV ) { + sinp[ ovip[ fc.inputIndex ] ] = camera.fieldOfView( ); + } else { + sinp[ ovip[ fc.inputIndex ] ] = camera.nearPlane( ); + } + } else { + InputsFromVector_( ov.target( ) , ovip , camera.lookAt( ) ); + if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) { + InputsFromVector_( ov.angles( ) , ovip , camera.angles( ) ); + sinp[ ovip[ ov.distance( ) ] ] = camera.distance( ); + } else { + InputsFromVector_( ov.position( ) , ovip , camera.position( ) ); + InputsFromVector_( ov.up( ) , ovip , camera.upVector( ) ); + } + } +} + +} // namespace + +M_DECL_SOVUI( Camera ) +{ + auto& ov{ dynamic_cast< T_CamOverride& >( ovp ) }; + auto& sync{ Globals::Sync( ) }; + auto& sinp{ sync.inputs( ) }; + auto& camera{ ov.camData( ) }; + auto const& ovip{ ov.inputPositions( ) }; + auto const& fc{ ov.fovConfig( ) }; + + if ( !ov.enabled( ) || !ov.prevEnabled( ) ) { + // Set field of view / near plane + if ( fc.mode == T_CamOverride::FM_FOV ) { + camera.fieldOfView( sinp[ ovip[ fc.inputIndex ] ] ); + } else { + camera.nearPlane( sinp[ ovip[ fc.inputIndex ] ] ); + } + + // Set camera parameters + const glm::vec3 lookAt{ VectorFromInputs_( + ov.target( ) , ovip ) }; + if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) { + const glm::vec3 angles{ VectorFromInputs_( + ov.angles( ) , ovip ) }; + const float distance{ sinp[ ovip[ ov.distance( ) ] ] }; + camera.camera( lookAt , angles , distance ); + } else { + const glm::vec3 position{ VectorFromInputs_( + ov.position( ) , ovip ) }; + const glm::vec3 up{ VectorFromInputs_( + ov.up( ) , ovip ) }; + camera.camera( lookAt , position , up ); + } + } + ov.prevEnabled( ) = ov.enabled( ); + + // Draw UI + char const* const name( BuildLabel_( counter , sb ) ); + auto& sui{ UI::Sync( ) }; + bool mouseHandler{ sui.isCurrentDelegate( ov.id( ) ) }; + using namespace ImGui; + PushItemWidth( 0 ); // Compensate for -1 + PushID( GetCurrentWindow( )->GetID( name ) ); + const bool handlerChanged{ Checkbox( "Mouse control" , &mouseHandler ) }; + Separator( ); + const auto changes{ camera.makeUI( ) }; + PopID( ); + PopItemWidth( ); + + if ( handlerChanged ) { + if ( mouseHandler ) { + sui.delegateMouse( ov.id( ) , + NewOwned< T_MouseCam_ >( camera , ov ) ); + } else { + sui.clearMouseDelegate( ); + } + } + + // Update values + if ( changes & T_Camera::E_Changes::FOV ) { + if ( fc.mode == T_CamOverride::FM_FOV ) { + sinp[ ovip[ fc.inputIndex ] ] = camera.fieldOfView( ); + } else { + sinp[ ovip[ fc.inputIndex ] ] = camera.nearPlane( ); + } + } + if ( changes & T_Camera::E_Changes::MATRIX ) { + InputsFromVector_( ov.target( ) , ovip , camera.lookAt( ) ); + if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) { + InputsFromVector_( ov.angles( ) , ovip , camera.angles( ) ); + sinp[ ovip[ ov.distance( ) ] ] = camera.distance( ); + } else { + InputsFromVector_( ov.position( ) , ovip , camera.position( ) ); + InputsFromVector_( ov.up( ) , ovip , camera.upVector( ) ); + } + } +} + + +} // namespace sov diff --git a/ui-overrides.hh b/ui-overrides.hh new file mode 100644 index 0000000..323d858 --- /dev/null +++ b/ui-overrides.hh @@ -0,0 +1,25 @@ +#pragma once +#include "syncoverrides.hh" + +#define M_DECL_SOVUI(NAME) \ + void UI##NAME( A_SyncOverride& ovp , \ + uint32_t& counter , \ + T_StringBuilder& sb ) noexcept + +namespace sov { + + M_DECL_SOVUI( Float ); + M_DECL_SOVUI( Float2 ); + M_DECL_SOVUI( Float3 ); + M_DECL_SOVUI( Float4 ); + + M_DECL_SOVUI( Integer ); + M_DECL_SOVUI( Integer2 ); + M_DECL_SOVUI( Integer3 ); + M_DECL_SOVUI( Integer4 ); + + M_DECL_SOVUI( ColorGrading ); + + M_DECL_SOVUI( Camera ); + +} // namespace sovui diff --git a/ui-sequencer.cc b/ui-sequencer.cc index 49480e4..b49151d 100644 --- a/ui-sequencer.cc +++ b/ui-sequencer.cc @@ -4,6 +4,7 @@ #include "globals.hh" #include "window.hh" #include "syncedit.hh" +#include "ui.hh" #include "ui-utilities.hh" #define IMGUI_DEFINE_MATH_OPERATORS @@ -326,7 +327,7 @@ void T_SyncViewImpl_::displayToolbar( ) noexcept ToolbarSeparator( ); if ( ToolbarButton( ICON_FA_CLOCK_O , BtSize , "Change duration and time units." ) ) { - Globals::Window( ).pushDialog( NewOwned< T_ChangeDurationDialog_ >( + UI::Window( ).pushDialog( NewOwned< T_ChangeDurationDialog_ >( sync.durationUnits( ) , sync.durationUnitSize( ) ) ); } @@ -499,7 +500,7 @@ void T_SyncViewImpl_::sequencerHeader( GetColorU32( ImVec4{ 1 , 1 , 1 , .5 } ) ); } - PushFont( Globals::Window( ).smallFont( ) ); + PushFont( UI::Window( ).smallFont( ) ); PushStyleColor( ImGuiCol_Text , ColHeaderText ); auto pos{ startBarPos }; auto bar{ startBar }; diff --git a/ui-sync.cc b/ui-sync.cc new file mode 100644 index 0000000..5dd2dd7 --- /dev/null +++ b/ui-sync.cc @@ -0,0 +1,191 @@ +#include "externals.hh" +#include "globals.hh" +#include "ui.hh" +#include "ui-actions.hh" +#include "ui-overrides.hh" +#include "ui-sync.hh" +#include "ui-utilities.hh" +#include "window.hh" + + +/*= T_UISync =================================================================*/ + +T_UISync::T_UISync( ) +{ + UI::Window( ).newAction( "Save curves" , []() { + if ( Globals::Sync( ).curvesFileChanged( ) ) { + UI::Window( ).msgbox( + "Curves file changed" , + "The file containing the curves has been modified " + "on the disk. These changes will be overwritten. " + "Do you want to continue?" , + []( auto b ) { + if ( b == T_MessageBox::BT_YES ) { + Globals::Sync( ).saveCurves( ); + } + } , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } ); + } else { + Globals::Sync( ).saveCurves( ); + } + } ).setEnabledCheck( []() { + return Globals::Sync( ).curvesModified( ); + } ).setIcon( ICON_FA_FLOPPY_O ) + .setShortcut( T_KeyboardShortcut{ 's' , E_KeyboardModifier::CTRL } ); + //----------------------------------------------------------------------------- + UI::Window( ).newAction( "Reload curves" , []() { + UI::Window( ).msgbox( + "Reload curves?" , + "Changes you made to the curves will be lost. Do you " + "want to continue?" , + []( auto b ) { + if ( b == T_MessageBox::BT_YES ) { + Globals::Sync( ).loadCurves( ); + } + } , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } ); + } ).setEnabledCheck( []() { + return Globals::Sync( ).curvesModified( ); + } ).setIcon( ICON_FA_DOWNLOAD ) + .setShortcut( T_KeyboardShortcut{ 'r' , + { E_KeyboardModifier::CTRL , E_KeyboardModifier::SHIFT } } ); + //----------------------------------------------------------------------------- + const auto addui{ [this]( char const* type , F_Override ov ) { + const bool ok{ sovuis_.add( T_String{ type } , std::move( ov ) ) }; + assert( ok ); (void)ok; + } }; + addui( "float" , sov::UIFloat ); + addui( "float2" , sov::UIFloat2 ); + addui( "float3" , sov::UIFloat3 ); + addui( "float4" , sov::UIFloat4 ); + addui( "int" , sov::UIInteger ); + addui( "int2" , sov::UIInteger2 ); + addui( "int3" , sov::UIInteger3 ); + addui( "int4" , sov::UIInteger4 ); + addui( "cg" , sov::UIColorGrading ); + addui( "cam" , sov::UICamera ); +} + +/*----------------------------------------------------------------------------*/ + +namespace { + +bool HandleOverrideSection_( + T_SyncOverrideSection& sos , + bool exit , + T_AutoArray< bool , 32 >& stack ) +{ + if ( exit ) { + assert( !stack.empty( ) ); + if ( stack.last( ) && stack.size( ) > 1 ) { + ImGui::TreePop( ); + } + stack.removeLast( ); + return true; + } + + const bool display( stack.empty( ) + ? ImGui::CollapsingHeader( &sos.cTitle[ 0 ] ) + : ImGui::TreeNode( &sos.cTitle[ 0 ] ) ); + stack.add( display ); + return display; +} + +void HandleOverride_( + A_SyncOverride& ov , + uint32_t& counter , + T_StringBuilder& sb ) noexcept +{ + using namespace ImGui; + + bool& enabled{ ov.enabled( ) }; + if ( Checkbox( &ov.title( )[ 0 ] , &enabled ) ) { + auto const& ipos( ov.inputPositions( ) ); + Globals::Sync( ).setOverridesActive( ov.enabled( ) , + ipos.size( ) , &ipos[ 0 ] ); + } + if ( !enabled ) { + PushDisabled( ); + } + Indent( ); + PushItemWidth( -1 ); + (UI::Sync( ).uiFor( ov ))( ov , counter , sb ); + PopItemWidth( ); + Unindent( ); + if ( !enabled ) { + PopDisabled( ); + } +} + +} // namespace + +T_UISync::F_Override T_UISync::uiFor( + A_SyncOverride& target ) const noexcept +{ + auto const* const rv{ sovuis_.get( target.type( ) ) }; + return rv ? *rv : []( A_SyncOverride& , uint32_t& , T_StringBuilder& ) { + ImGui::Text( "(missing UI)" ); + }; +} + +void T_UISync::makeOverridesWindow( ) +{ + if ( !ovWindow_ ) { + return; + } + + using namespace ImGui; + auto const& dspSize( GetIO( ).DisplaySize ); + SetNextWindowSize( ImVec2( dspSize.x * .25f , dspSize.y * .66f - 20 ) , ImGuiSetCond_Appearing ); + SetNextWindowPos( ImVec2( 0 , 20 ) , ImGuiSetCond_Appearing ); + Begin( "Input overrides" , &ovWindow_ , + ImGuiWindowFlags_NoCollapse ); + + T_StringBuilder temp; + uint32_t counter{ 0 }; + T_AutoArray< bool , 32 > stack; + bool found{ false }; + using T_Ove_ = T_SyncOverrideVisitor::T_Element; + Globals::Sync( ).visitOverrides( [&]( T_Ove_ element , bool exit ) { + // Display sections + if ( element.hasType< T_SyncOverrideSection* >( ) ) { + auto& sos( *element.value< T_SyncOverrideSection* >( ) ); + if ( sos.title == "*root*" ) { + return true; + } + return HandleOverrideSection_( sos , exit , stack ); + } + if ( exit ) { + HandleOverride_( *element.value< A_SyncOverride* >( ) , + counter , temp ); + found = true; + } + return true; + } ); + + if ( !found ) { + Text( "No overrides have been defined." ); + } + + End( ); +} + +/*----------------------------------------------------------------------------*/ + +void T_UISync::handleDragAndDrop( + ImVec2 const& move , + T_KeyboardModifiers modifiers , + T_MouseButtons buttons ) noexcept +{ + if ( mouseDelegate_ ) { + mouseDelegate_->handleDragAndDrop( move , modifiers , buttons ); + } +} + +void T_UISync::handleWheel( + const float wheel , + T_KeyboardModifiers modifiers , + T_MouseButtons buttons ) noexcept +{ + if ( mouseDelegate_ ) { + mouseDelegate_->handleWheel( wheel , modifiers , buttons ); + } +} diff --git a/ui-sync.hh b/ui-sync.hh new file mode 100644 index 0000000..e357cff --- /dev/null +++ b/ui-sync.hh @@ -0,0 +1,55 @@ +#pragma once +#include "sync.hh" +#include "ui-mousectrl.hh" + + +class T_UISync : public A_MouseCtrl +{ + public: + + using F_Override = std::function< + void( A_SyncOverride& , uint32_t& , T_StringBuilder& ) >; + + T_UISync( ); + + bool& overridesWindowEnabled( ) noexcept + { return ovWindow_; } + void makeOverridesWindow( ); + + F_Override uiFor( A_SyncOverride& target ) const noexcept; + + //---------------------------------------------------------------------- + + void delegateMouse( T_String const& id , + P_MouseCtrl delegate ) noexcept + { + mouseDelegateName_ = id; + mouseDelegate_ = std::move( delegate ); + } + + void clearMouseDelegate( ) noexcept + { + mouseDelegateName_ = T_String{ }; + mouseDelegate_ = P_MouseCtrl{ }; + } + + bool isCurrentDelegate( T_String const& delegate ) noexcept + { return mouseDelegateName_ == delegate; } + + //---------------------------------------------------------------------- + + void handleDragAndDrop( + ImVec2 const& move , + T_KeyboardModifiers modifiers , + T_MouseButtons buttons ) noexcept override; + void handleWheel( + float wheel , + T_KeyboardModifiers modifiers , + T_MouseButtons buttons ) noexcept override; + + private: + bool ovWindow_{ false }; + T_String mouseDelegateName_{ }; + T_OwnPtr< A_MouseCtrl > mouseDelegate_{ }; + T_KeyValueTable< T_String , F_Override > sovuis_; +}; diff --git a/ui.cc b/ui.cc new file mode 100644 index 0000000..72234aa --- /dev/null +++ b/ui.cc @@ -0,0 +1,54 @@ +#include "externals.hh" +#include "odbg.hh" +#include "shaders.hh" +#include "texture.hh" +#include "ui.hh" +#include "ui-sync.hh" +#include "window.hh" + + +namespace { + +struct UIData_ +{ + T_Window window; + T_TextureManager textures; + T_ShaderManager shaders; + T_OutputDebugger odbg; + T_UISync sync; +}; + +std::aligned_storage_t< sizeof( UIData_ ) , alignof( UIData_ ) > Instance_; + +} // namespace + +/*----------------------------------------------------------------------------*/ + +void UI::Init( ) noexcept +{ + new ((char*)&Instance_) UIData_( ); +} + +void UI::Shutdown( ) noexcept +{ + ((UIData_*)(char*)&Instance_)->~UIData_( ); +} + +/*----------------------------------------------------------------------------*/ + +#define M_GET_( P ) ((UIData_*)(char*)&Instance_)->P + +T_Window& UI::Window( ) noexcept + { return M_GET_( window ); } + +T_TextureManager& UI::Textures( ) noexcept + { return M_GET_( textures ); } + +T_ShaderManager& UI::Shaders( ) noexcept + { return M_GET_( shaders ); } + +T_OutputDebugger& UI::ODbg( ) noexcept + { return M_GET_( odbg ); } + +T_UISync& UI::Sync( ) noexcept + { return M_GET_( sync ); } diff --git a/ui.hh b/ui.hh new file mode 100644 index 0000000..5589c93 --- /dev/null +++ b/ui.hh @@ -0,0 +1,29 @@ +#pragma once +#ifndef REAL_BUILD +# include "externals.hh" +#endif + +struct T_Window; +struct T_TextureManager; +struct T_ShaderManager; +struct T_OutputDebugger; +struct T_UISync; + + +struct UI : public ebcl::A_PrivateImplementation +{ + public: + static void Init( ) noexcept; + static void Shutdown( ) noexcept; + + static T_Window& Window( ) noexcept; + static T_TextureManager& Textures( ) noexcept; + static T_ShaderManager& Shaders( ) noexcept; + static T_OutputDebugger& ODbg( ) noexcept; + static T_UISync& Sync( ) noexcept; + + private: + UI( ) noexcept; + NO_COPY( UI ); + NO_MOVE( UI ); +}; diff --git a/window.hh b/window.hh index dd41d06..176da4e 100644 --- a/window.hh +++ b/window.hh @@ -33,6 +33,15 @@ struct T_Window void actionMenu( T_String const& id ) const noexcept; void actionButton( T_String const& id ) const noexcept; + template< typename... Args > + T_UIAction& newAction( Args&&... args ) + { + T_UIAction a{ std::forward< Args >( args ) ... }; + T_String id{ a.id }; + addAction( std::move( a ) ); + return *actions_.get( id ); + } + //---------------------------------------------------------------------- ImFont* defaultFont( ) const noexcept