//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "hlfaceposer.h" #include "faceposertoolwindow.h" #include "UtlVector.h" #include "tier1/strtools.h" #include "MDLViewer.h" #include "choreowidgetdrawhelper.h" #include "StudioModel.h" #include "faceposer_models.h" extern MDLViewer *g_MDLViewer; static CUtlVector< IFacePoserToolWindow * > g_Tools; IFacePoserToolWindow *IFacePoserToolWindow::s_pActiveTool = NULL; bool IFacePoserToolWindow::s_bToolsCanDraw; static CUtlVector< IFacePoserToolWindow * > s_NeedRedraw; IFacePoserToolWindow::IFacePoserToolWindow( char const *toolname, char const *displaynameroot ) { m_bAutoProcess = false; m_bUseForMainWindowTitle = false; SetToolName( toolname ); m_szPrefix[0]=0; m_szSuffix[0]=0; SetDisplayNameRoot( displaynameroot ); g_Tools.AddToTail( this ); m_nToolFrameCount = 0; } mxWindow *IFacePoserToolWindow::GetMxWindow( void ) { return dynamic_cast< mxWindow * >( this ); } IFacePoserToolWindow *IFacePoserToolWindow::GetActiveTool( void ) { if ( s_pActiveTool ) return s_pActiveTool; if ( GetToolCount() > 0 ) return GetTool( 0 ); return NULL; } void IFacePoserToolWindow::SetActiveTool( IFacePoserToolWindow *tool ) { if ( tool != s_pActiveTool && s_pActiveTool ) { InvalidateRect( (HWND)s_pActiveTool->GetMxWindow()->getHandle(), NULL, TRUE ); InvalidateRect( (HWND)tool->GetMxWindow()->getHandle(), NULL, TRUE ); } s_pActiveTool = tool; } void IFacePoserToolWindow::Think( float dt ) { } //----------------------------------------------------------------------------- // Purpose: // Input : *name - //----------------------------------------------------------------------------- void IFacePoserToolWindow::SetToolName( char const *name ) { Q_strncpy( m_szToolName, name, sizeof( m_szToolName ) ); } //----------------------------------------------------------------------------- // Purpose: // Output : char const //----------------------------------------------------------------------------- char const *IFacePoserToolWindow::GetToolName( void ) const { return m_szToolName; } //----------------------------------------------------------------------------- // Purpose: // Input : *name - //----------------------------------------------------------------------------- void IFacePoserToolWindow::SetDisplayNameRoot( char const *name ) { Q_snprintf( m_szDisplayRoot, sizeof( m_szDisplayRoot ), "%s", name ); ComputeNewTitle(); } //----------------------------------------------------------------------------- // Purpose: // Output : char const //----------------------------------------------------------------------------- char const *IFacePoserToolWindow::GetDisplayNameRoot( void ) const { return m_szDisplayRoot; } //----------------------------------------------------------------------------- // Purpose: // Input : *suffix - //----------------------------------------------------------------------------- void IFacePoserToolWindow::SetSuffix( char const *suffix ) { Q_snprintf( m_szSuffix, sizeof( m_szSuffix ), "%s", suffix ); ComputeNewTitle(); } //----------------------------------------------------------------------------- // Purpose: // Input : *prefix - //----------------------------------------------------------------------------- void IFacePoserToolWindow::SetPrefix( char const *prefix ) { Q_snprintf( m_szPrefix, sizeof( m_szPrefix ), "%s", prefix ); ComputeNewTitle(); } //----------------------------------------------------------------------------- // Purpose: // Output : char const //----------------------------------------------------------------------------- char const *IFacePoserToolWindow::GetWindowTitle( void ) const { return m_szWindowTitle; } //----------------------------------------------------------------------------- // Purpose: // Input : use - //----------------------------------------------------------------------------- void IFacePoserToolWindow::SetUseForMainWindowTitle( bool use ) { m_bUseForMainWindowTitle = use; if ( use ) { g_MDLViewer->setLabel( m_szWindowTitle ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void IFacePoserToolWindow::ComputeNewTitle( void ) { Q_snprintf( m_szWindowTitle, sizeof( m_szWindowTitle ), "%s%s%s", m_szPrefix, m_szDisplayRoot, m_szSuffix ); if ( GetMxWindow() ) { GetMxWindow()->setLabel( m_szWindowTitle ); } if ( !m_bUseForMainWindowTitle ) return; g_MDLViewer->setLabel( m_szWindowTitle ); } IFacePoserToolWindow::~IFacePoserToolWindow( void ) { g_Tools.FindAndRemove( this ); } struct ToolTranslate { char const *toolname; float xfrac; float yfrac; float wfrac; float hfrac; bool locked; }; static ToolTranslate s_ToolTranslate[]= { { "3D View", 0.0, 0.0, 0.4, 0.5, false }, { "ControlPanel", 0.4, 0.0, 0.2, 0.25, false }, { "FlexPanel", 0.6, 0.0, 0.4, 0.25, false }, { "RampTool", 0.4, 0.25, 0.6, 0.25, false }, { "CChoreoView", 0.0, 0.5, 1.0, 0.45, false }, // { "Status Window", 0.0, 0.85, 1.0, 0.15, false }, }; static bool TranslateToolPos( char const *toolname, int workspacew, int workspaceh, int& x, int& y, int &w, int &h, bool& locked ) { int c = ARRAYSIZE( s_ToolTranslate ); for ( int i = 0; i < c; ++i ) { ToolTranslate& tt = s_ToolTranslate[ i ]; if ( !Q_stricmp( toolname, tt.toolname ) ) { x = (int)((float)workspacew * tt.xfrac + 0.5f ); y = (int)((float)workspaceh * tt.yfrac + 0.5f ); w = (int)((float)workspacew * tt.wfrac + 0.5f ); h = (int)((float)workspaceh * tt.hfrac + 0.5f ); locked = tt.locked; return true; } } return false; } static int s_nToolCount = 0; void IFacePoserToolWindow::LoadPosition( void ) { bool visible; bool locked; bool zoomed; int x, y, w, h; FacePoser_LoadWindowPositions( GetToolName(), visible, x, y, w, h, locked, zoomed ); if ( w == 0 || h == 0 ) { int idx = g_Tools.Find( this ); Assert( idx != g_Tools.InvalidIndex() ); if ( idx == 0 ) { s_nToolCount = 0; } zoomed = false; locked = false; visible = true; // Just do a simple tiling w = g_MDLViewer->w2() * 0.5; h = g_MDLViewer->h2() * 0.5; x = g_MDLViewer->w2() * 0.25f + s_nToolCount * 20; y = s_nToolCount * 20; bool translated = TranslateToolPos ( GetToolName(), g_MDLViewer->w2(), g_MDLViewer->h2(), x, y, w, h, locked ); if ( !translated ) { ++s_nToolCount; visible = false; } } GetMxWindow()->setBounds( x, y, w, h ); if ( locked ^ IsLocked() ) { ToggleLockedState(); } GetMxWindow()->setVisible( visible ); } void IFacePoserToolWindow::SavePosition( void ) { bool visible; int xpos, ypos, width, height; visible = GetMxWindow()->isVisible(); xpos = GetMxWindow()->x(); ypos = GetMxWindow()->y(); width = GetMxWindow()->w(); height = GetMxWindow()->h(); // xpos and ypos are screen space POINT pt; pt.x = xpos; pt.y = ypos; // Convert from screen space to relative to client area of parent window so // the setBounds == MoveWindow call will offset to the same location if ( GetMxWindow()->getParent() ) { ScreenToClient( (HWND)GetMxWindow()->getParent()->getHandle(), &pt ); xpos = (short)pt.x; ypos = (short)pt.y; } FacePoser_SaveWindowPositions( GetToolName(), visible, xpos, ypos, width, height, IsLocked(), false ); } int IFacePoserToolWindow::GetToolCount( void ) { return g_Tools.Count(); } IFacePoserToolWindow *IFacePoserToolWindow::GetTool( int index ) { return g_Tools[ index ]; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void IFacePoserToolWindow::InitTools( void ) { int c = GetToolCount(); int i; for ( i = 0; i < c ; i++ ) { IFacePoserToolWindow *tool = GetTool( i ); FacePoser_MakeToolWindow( tool->GetMxWindow(), true ); tool->GetMxWindow()->setLabel( tool->GetWindowTitle() ); } } void IFacePoserToolWindow::ShutdownTools( void ) { int c = GetToolCount(); int i; for ( i = 0; i < c ; i++ ) { IFacePoserToolWindow *tool = GetTool( i ); tool->Shutdown(); } } //----------------------------------------------------------------------------- // Purpose: // Input : dt - //----------------------------------------------------------------------------- void IFacePoserToolWindow::ToolThink( float dt ) { int c = GetToolCount(); int i; for ( i = 0; i < c ; i++ ) { IFacePoserToolWindow *tool = GetTool( i ); tool->Think( dt ); } // Don't self animate, all animation driven by thinking of various tools now if ( !ShouldAutoProcess() ) { c = models->Count(); for ( i = 0; i < c; i++ ) { StudioModel *m = models->GetStudioModel( i ); if ( m ) { m->AdvanceFrame ( dt ); } } } } bool IFacePoserToolWindow::IsLocked( void ) { mxWindow *w = GetMxWindow(); if ( !w ) return false; return !FacePoser_HasWindowStyle( w, WS_SYSMENU ); } void IFacePoserToolWindow::ToggleLockedState( void ) { mxWindow *w = GetMxWindow(); if ( !w ) return; bool visible = w->isVisible(); bool islocked = IsLocked(); if ( islocked ) { FacePoser_MakeToolWindow( w, true ); } else { FacePoser_RemoveWindowStyle( w, WS_OVERLAPPEDWINDOW ); FacePoser_AddWindowExStyle( w, WS_EX_OVERLAPPEDWINDOW ); } w->setVisible( false ); // If visible, force it to redraw, etc. if ( visible ) { w->setVisible( true ); } } #define LOCK_INSET 2 #define LOCK_SIZE 8 void IFacePoserToolWindow:: GetLockRect( RECT& rc ) { mxWindow *w = GetMxWindow(); Assert( w ); if ( !w ) return; GetCloseRect( rc ); OffsetRect( &rc, - ( LOCK_SIZE + 2 * LOCK_INSET ), 0 ); } void IFacePoserToolWindow::GetCloseRect( RECT& rc ) { mxWindow *w = GetMxWindow(); Assert( w ); if ( !w ) return; rc.right = w->w2() - LOCK_INSET; rc.left = rc.right - LOCK_SIZE; rc.top = LOCK_INSET; rc.bottom = rc.top + LOCK_SIZE; } bool IFacePoserToolWindow::HandleToolEvent( mxEvent *event ) { bool handled = false; switch ( event->event ) { default: break; case mxEvent::Close: { g_MDLViewer->UpdateWindowMenu(); handled = true; } break; case mxEvent::ParentNotify: { mxWindow *w = GetMxWindow(); if ( w ) { HWND wnd = (HWND)w->getHandle(); SetFocus( wnd ); SetWindowPos( wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); SetActiveTool( this ); } handled = true; } break; case mxEvent::PosChanged: { SetActiveTool( this ); mxWindow *w = GetMxWindow(); if ( w ) { SetFocus( (HWND)w->getHandle() ); } handled = true; } break; case mxEvent::MouseDown: case mxEvent::MouseUp: { bool isup = event->event == mxEvent::MouseUp; mxWindow *w = GetMxWindow(); if ( !isup && w ) { SetFocus( (HWND)w->getHandle() ); SetWindowPos( (HWND)w->getHandle(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); SetActiveTool( this ); } if ( w && IsLocked() ) { RECT captionRect; captionRect.left = 0; captionRect.right = w->w2(); captionRect.top = 0; captionRect.bottom = GetCaptionHeight(); POINT pt; pt.x = (short)event->x; pt.y = (short)event->y; if ( PtInRect( &captionRect, pt ) ) { handled = !isup; // Right button anywhere if ( event->buttons & mxEvent::MouseRightButton ) { if ( isup ) { ToggleLockedState(); } } // Left button on lock icon RECT lockRect, closeRect; GetLockRect( lockRect ); GetCloseRect( closeRect ); if ( PtInRect( &lockRect, pt ) ) { if ( isup ) { ToggleLockedState(); } } if ( PtInRect( &closeRect, pt ) ) { if ( isup ) { w->setVisible( !w->isVisible() ); g_MDLViewer->UpdateWindowMenu(); } } } } } break; case mxEvent::NCMouseUp: { if ( event->buttons & mxEvent::MouseRightButton ) { ToggleLockedState(); handled = true; } } break; case mxEvent::NCMouseDown: case mxEvent::Focus: { SetActiveTool( this ); // don't mark handled = true, do this passively } break; } return handled; } void IFacePoserToolWindow::HandleToolRedraw( CChoreoWidgetDrawHelper& helper ) { if ( !IsLocked() ) return; mxWindow *w = GetMxWindow(); if ( !w ) return; ++m_nToolFrameCount; RECT lockRect, closeRect; GetLockRect( lockRect ); GetCloseRect( closeRect ); RECT captionRect; helper.GetClientRect( captionRect ); RECT rcClient = captionRect; captionRect.bottom = captionRect.top + LOCK_SIZE + 2 * LOCK_INSET; Color textColor = RGBToColor( GetSysColor( COLOR_MENUTEXT ) ); //GetSysColor( COLOR_INACTIVECAPTIONTEXT ); if ( IsActiveTool() ) { helper.DrawFilledRect( RGBToColor( GetSysColor( COLOR_ACTIVECAPTION ) ), captionRect ); } else { helper.DrawFilledRect( RGBToColor( GetSysColor( COLOR_INACTIVECAPTION ) ), captionRect ); } captionRect.top += 1; InflateRect( &captionRect, -LOCK_INSET, 0 ); helper.DrawColoredText( "Small Fonts", 9, FW_NORMAL, textColor, captionRect, GetWindowTitle() ); //RECT rcFrame = captionRect; //rcFrame.left = rcFrame.right - 50; //rcFrame.right = rcFrame.left + 30; // helper.DrawColoredText( "Small Fonts", 9, FW_NORMAL, textColor, rcFrame, va( "%i", m_nToolFrameCount ) ); lockRect.bottom++; OffsetRect( &lockRect, 1, 1 ); helper.DrawColoredTextCharset( "Marlett", 8, FW_NORMAL, SYMBOL_CHARSET, textColor, lockRect, "v" ); closeRect.bottom++; helper.DrawOutlinedRect( textColor, PS_SOLID, 1, closeRect ); OffsetRect( &closeRect, 1, 1 ); helper.DrawColoredTextCharset( "Marlett", 8, FW_NORMAL, SYMBOL_CHARSET, textColor, closeRect, "r" ); rcClient.top += captionRect.bottom; helper.StartClipping( rcClient ); } int IFacePoserToolWindow::GetCaptionHeight( void ) { if ( !IsLocked() ) return 0; return LOCK_SIZE + 2 * LOCK_INSET; } //----------------------------------------------------------------------------- // Purpose: // Input : autoprocess - //----------------------------------------------------------------------------- void IFacePoserToolWindow::SetAutoProcess( bool autoprocess ) { m_bAutoProcess = autoprocess; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool IFacePoserToolWindow::GetAutoProcess( void ) const { return m_bAutoProcess; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool IFacePoserToolWindow::IsActiveTool( void ) { if ( this == s_pActiveTool ) return true; return false; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool IFacePoserToolWindow::IsAnyToolScrubbing( void ) { int c = GetToolCount(); int i; for ( i = 0; i < c ; i++ ) { IFacePoserToolWindow *tool = GetTool( i ); if ( tool->IsScrubbing() ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool IFacePoserToolWindow::IsAnyToolProcessing( void ) { int c = GetToolCount(); int i; for ( i = 0; i < c ; i++ ) { IFacePoserToolWindow *tool = GetTool( i ); if ( tool->IsProcessing() ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool IFacePoserToolWindow::ShouldAutoProcess( void ) { IFacePoserToolWindow *tool = GetActiveTool(); if ( !tool ) return false; return tool->GetAutoProcess(); } void IFacePoserToolWindow::EnableToolRedraw( bool enabled ) { MDLCACHE_CRITICAL_SECTION_( g_pMDLCache ); s_bToolsCanDraw = enabled; if ( s_bToolsCanDraw ) { int c = s_NeedRedraw.Count(); int i; for ( i = 0; i < c; i++ ) { IFacePoserToolWindow *tool = s_NeedRedraw[ i ]; tool->GetMxWindow()->redraw(); } s_NeedRedraw.Purge(); } } bool IFacePoserToolWindow::ToolCanDraw() { if ( !s_bToolsCanDraw ) { if ( s_NeedRedraw.Find( this ) == s_NeedRedraw.InvalidIndex() ) { s_NeedRedraw.AddToTail( this ); } return false; } return true; } void IFacePoserToolWindow::OnModelChanged() { } void IFacePoserToolWindow::ModelChanged() { int c = GetToolCount(); int i; for ( i = 0; i < c ; i++ ) { IFacePoserToolWindow *tool = GetTool( i ); tool->OnModelChanged(); } }