demotool/ui-sync.cc

286 lines
7 KiB
C++

#include "externals.hh"
#include "common.hh"
#include "ui.hh"
#include "ui-actions.hh"
#include "ui-app.hh"
#include "ui-overrides.hh"
#include "ui-sync.hh"
#include "ui-utilities.hh"
/*= T_SyncInputData_ =========================================================*/
namespace {
class T_SyncInputData_ : public sov::A_SyncData
{
private:
T_AutoArray< float* , 16 > ptr_;
public:
void setFromOverride( A_SyncOverride const& sov ) noexcept;
float operator[]( uint32_t index ) const noexcept override;
bool set( uint32_t index , float value ) noexcept override;
T_OwnPtr< sov::A_SyncData > clone( ) const noexcept override;
};
void T_SyncInputData_::setFromOverride(
A_SyncOverride const& sov ) noexcept
{
auto const& iPos{ sov.inputPositions() };
const auto np{ iPos.size( ) };
ptr_.ensureCapacity( np );
ptr_.clear( );
auto& inputs{ Common::Sync( ).inputs( ) };
for ( auto i = 0u ; i < np ; i ++ ) {
ptr_.add( &inputs[ iPos[ i ] ] );
}
}
float T_SyncInputData_::operator[](
const uint32_t index ) const noexcept
{
return *ptr_[ index ];
}
bool T_SyncInputData_::set(
const uint32_t index ,
const float value ) noexcept
{
*ptr_[ index ] = value;
return true;
}
T_OwnPtr< sov::A_SyncData > T_SyncInputData_::clone( ) const noexcept
{
return NewOwned< T_SyncInputData_ >( *this );
}
} // namespace <anon>
/*= T_UISync =================================================================*/
T_UISync::T_UISync( )
{
UI::Main( ).addAction( T_UIAction{ "Save curves" , []() {
if ( Common::Sync( ).curvesFileChanged( ) ) {
UI::Main( ).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 ) {
Common::Sync( ).saveCurves( );
}
} , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } );
} else {
Common::Sync( ).saveCurves( );
}
} }.setEnabledCheck( []() {
return Common::Sync( ).curvesModified( );
} ).setIcon( ICON_FA_FLOPPY_O )
.setShortcut( T_KeyboardShortcut{ 's' , E_KbdMod::CTRL } ) );
//-----------------------------------------------------------------------------
UI::Main( ).addAction( T_UIAction{ "Reload curves" , []() {
UI::Main( ).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 ) {
Common::Sync( ).loadCurves( );
}
} , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } );
} }.setEnabledCheck( []() {
return Common::Sync( ).curvesModified( );
} ).setIcon( ICON_FA_DOWNLOAD )
.setShortcut( T_KeyboardShortcut{ 'r' ,
{ E_KbdMod::CTRL , E_KbdMod::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 );
}
T_UISync::~T_UISync( )
{
UI::Main( ).clearMouseDelegate( );
}
/*----------------------------------------------------------------------------*/
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 ,
T_SyncInputData_& data ,
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( ) );
Common::Sync( ).setOverridesActive( ov.enabled( ) ,
ipos.size( ) , &ipos[ 0 ] );
}
if ( !enabled ) {
PushDisabled( );
}
Indent( );
PushItemWidth( -1 );
data.setFromOverride( ov );
(UI::Sync( ).uiFor( ov ))( ov , data , counter , sb );
PopItemWidth( );
Unindent( );
if ( !enabled ) {
PopDisabled( );
}
}
} // namespace <anon>
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& , sov::A_SyncData& ,
uint32_t& , T_StringBuilder& ) {
ImGui::Text( "(missing UI)" );
return false;
};
}
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_AutoArray< bool , 32 > stack;
T_SyncInputData_ data;
T_StringBuilder temp;
uint32_t counter{ 0 };
bool found{ false };
using T_Ove_ = T_SyncOverrideVisitor::T_Element;
Common::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;
}
found = true;
return HandleOverrideSection_( sos , exit , stack );
}
if ( exit ) {
HandleOverride_( *element.value< A_SyncOverride* >( ) ,
data , counter , temp );
found = true;
}
return true;
} );
if ( !found ) {
Text( "No overrides have been defined." );
}
End( );
}
/*----------------------------------------------------------------------------*/
void T_UISync::updateTime( ) noexcept
{
auto& s{ Common::Sync( ) };
if ( s.playing( ) ) {
const float time( SDL_GetTicks( ) * 1e-3f );
if ( playingPrevious_ ) {
s.timeDelta( time - lastFrame_ );
}
lastFrame_ = time;
}
playingPrevious_ = s.playing( );
}
/*----------------------------------------------------------------------------*/
void T_UISync::delegateMouse(
T_String const& id ,
P_MouseCtrl delegate ) noexcept
{
mouseDelegateName_ = id;
mouseDelegate_ = std::move( delegate );
UI::Main( ).setMouseDelegate( this );
}
void T_UISync::clearMouseDelegate( ) noexcept
{
mouseDelegateName_ = T_String{ };
mouseDelegate_ = P_MouseCtrl{ };
UI::Main( ).clearMouseDelegate( );
}
void T_UISync::handleDragAndDrop(
ImVec2 const& move ,
T_KbdMods modifiers ,
T_MouseButtons buttons ) noexcept
{
if ( mouseDelegate_ ) {
mouseDelegate_->handleDragAndDrop( move , modifiers , buttons );
}
}
void T_UISync::handleWheel(
const float wheel ,
T_KbdMods modifiers ,
T_MouseButtons buttons ) noexcept
{
if ( mouseDelegate_ ) {
mouseDelegate_->handleWheel( wheel , modifiers , buttons );
}
}