summaryrefslogtreecommitdiff
path: root/utils/hlfaceposer/mxexpressionslider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hlfaceposer/mxexpressionslider.cpp')
-rw-r--r--utils/hlfaceposer/mxexpressionslider.cpp723
1 files changed, 723 insertions, 0 deletions
diff --git a/utils/hlfaceposer/mxexpressionslider.cpp b/utils/hlfaceposer/mxexpressionslider.cpp
new file mode 100644
index 0000000..0e82fc9
--- /dev/null
+++ b/utils/hlfaceposer/mxexpressionslider.cpp
@@ -0,0 +1,723 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include <stdio.h>
+#include <windows.h>
+#include "mxExpressionSlider.h"
+#include "expressiontool.h"
+#include "mathlib/mathlib.h"
+#include "hlfaceposer.h"
+#include "choreowidgetdrawhelper.h"
+
+mxExpressionSlider::mxExpressionSlider (mxWindow *parent, int x, int y, int w, int h, int id )
+ : mxWindow( parent, x, y, w, h )
+{
+ setId( id );
+ setType( MX_SLIDER );
+
+ FacePoser_AddWindowStyle( this, WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
+
+ m_flMin[ 0 ] = 0.0;
+ m_flMax[ 0 ] = 1.0f;
+ m_nTicks[ 0 ] = 20;
+ m_flCurrent[ 0 ] = 0.0f;
+
+ m_flMin[ 1 ] = 0.0;
+ m_flMax[ 1 ] = 1.0f;
+ m_nTicks[ 1 ] = 20;
+ m_flCurrent[ 1 ] = 0.5f;
+
+ m_flSetting[ 0 ] = 0.0;
+ m_flSetting[ 1 ] = 0.0;
+
+ m_bIsEdited[ 0 ] = false;
+ m_bIsEdited[ 1 ] = false;
+
+ m_bDraggingThumb = false;
+ m_nCurrentBar = 0;
+
+ m_bPaired = false;
+
+ m_nTitleWidth = 120;
+ m_bDrawTitle = true;
+
+ m_pInfluence = new mxCheckBox( this, 2, 4, 12, 12, "", IDC_INFLUENCE );
+}
+
+mxExpressionSlider::~mxExpressionSlider( void )
+{
+}
+
+void mxExpressionSlider::SetTitleWidth( int width )
+{
+ m_nTitleWidth = width;
+ redraw();
+}
+
+void mxExpressionSlider::SetDrawTitle( bool drawTitle )
+{
+ m_bDrawTitle = drawTitle;
+ redraw();
+}
+
+
+void mxExpressionSlider::SetMode( bool paired )
+{
+ if ( m_bPaired != paired )
+ {
+ m_bPaired = paired;
+ redraw();
+ }
+}
+
+void mxExpressionSlider::BoundValue( void )
+{
+ for ( int i = 0; i < NUMBARS; i++ )
+ {
+ if ( m_flCurrent[ i ] > m_flMax[ i ] )
+ {
+ m_flCurrent[ i ] = m_flMax[ i ];
+ }
+ if ( m_flCurrent[ i ] < m_flMin[ i ] )
+ {
+ m_flCurrent[ i ] = m_flMin[ i ];
+ }
+ }
+}
+
+
+void mxExpressionSlider::setValue( int barnum, float value )
+{
+ if (m_flSetting[ barnum ] == value && m_bIsEdited[ barnum ] == false)
+ return;
+
+ m_flSetting[ barnum ] = value;
+ m_bIsEdited[ barnum ] = false;
+
+ if (m_bPaired)
+ {
+ if (m_flSetting[ 0 ] < m_flSetting[ 1 ])
+ {
+ m_flCurrent[ 0 ] = m_flSetting[ 1 ];
+ m_flCurrent[ 1 ] = 1.0 - (m_flSetting[ 0 ] / m_flSetting[ 1 ]) * 0.5;
+ }
+ else if (m_flSetting[ 0 ] > m_flSetting[ 1 ])
+ {
+ m_flCurrent[ 0 ] = m_flSetting[ 0 ];
+ m_flCurrent[ 1 ] = (m_flSetting[ 1 ] / m_flSetting[ 0 ]) * 0.5;
+ }
+ else
+ {
+ m_flCurrent[ 0 ] = m_flSetting[ 0 ];
+ m_flCurrent[ 1 ] = 0.5;
+ }
+ }
+ else
+ {
+ m_flCurrent[ barnum ] = value;
+ }
+
+ BoundValue();
+ // FIXME: delay this until all sliders are set
+ if (!m_bPaired || barnum == 1)
+ redraw();
+}
+
+void mxExpressionSlider::setRange( int barnum, float min, float max, int ticks /*= 100*/ )
+{
+ m_flMin[ barnum ] = min;
+ m_flMax[ barnum ] = max;
+
+ Assert( m_flMax[ barnum ] > m_flMin[ barnum ] );
+
+ m_nTicks[ barnum ] = ticks;
+
+ BoundValue();
+
+ redraw();
+}
+
+void mxExpressionSlider::setInfluence( float value )
+{
+ bool bWasChecked = m_pInfluence->isChecked( );
+ bool bNowChecked = value > 0.0f ? true : false;
+ if (bNowChecked != bWasChecked)
+ {
+ m_pInfluence->setChecked( bNowChecked );
+ redraw();
+ }
+}
+
+float mxExpressionSlider::getRawValue( int barnum ) const
+{
+ return m_flCurrent[ barnum ];
+}
+
+float mxExpressionSlider::getValue( int barnum ) const
+{
+ float scale = 1.0;
+ if (m_bPaired)
+ {
+ // if it's paired, this is assuming that m_flCurrent[0] holds the max value,
+ // and m_flCurrent[1] is a weighting from 0 to 1, with 0.5 being even
+ if (barnum == 0 && m_flCurrent[ 1 ] > 0.5)
+ {
+ scale = (1.0 - m_flCurrent[ 1 ]) / 0.5;
+ }
+ else if (barnum == 1 && m_flCurrent[ 1 ] < 0.5)
+ {
+ scale = (m_flCurrent[ 1 ] / 0.5);
+ }
+ }
+
+ return m_flCurrent[ 0 ] * scale;
+}
+
+float mxExpressionSlider::getMinValue( int barnum ) const
+{
+ return m_flMin[ barnum ];
+}
+
+float mxExpressionSlider::getMaxValue( int barnum ) const
+{
+ return m_flMax[ barnum ];
+}
+
+float mxExpressionSlider::getInfluence( ) const
+{
+ return m_pInfluence->isChecked() ? 1.0f : 0.0f;
+}
+
+void mxExpressionSlider::setEdited( int barnum, bool isEdited )
+{
+ if (m_bIsEdited[ barnum ] == isEdited)
+ return;
+
+ m_bIsEdited[ barnum ] = isEdited;
+ redraw();
+}
+
+bool mxExpressionSlider::isEdited( int barnum ) const
+{
+ return (m_bIsEdited[ barnum ]);
+}
+
+void mxExpressionSlider::GetSliderRect( RECT& rc )
+{
+ HWND wnd = (HWND)getHandle();
+ if ( !wnd )
+ return;
+
+ GetClientRect( wnd, &rc );
+
+ if ( m_bDrawTitle )
+ {
+ rc.left += m_nTitleWidth;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &rc -
+//-----------------------------------------------------------------------------
+void mxExpressionSlider::GetBarRect( RECT &rcBar )
+{
+ RECT rc;
+ GetSliderRect( rc );
+
+ rcBar = rc;
+
+ InflateRect( &rcBar, -10, 0 );
+ rcBar.top += 5;
+ rcBar.bottom = rcBar.top + 2;
+
+ int midy = ( rcBar.top + rcBar.bottom ) / 2;
+ rcBar.top = midy - 1;
+ rcBar.bottom = midy + 1;
+}
+
+
+void mxExpressionSlider::GetThumbRect( int barnum, RECT &rcThumb )
+{
+ RECT rc;
+ GetSliderRect( rc );
+
+ RECT rcBar = rc;
+ GetBarRect( rcBar );
+
+ float frac = 0.0f;
+
+ if ( m_flMax[ barnum ] - m_flMin[ barnum ] > 0 )
+ {
+ frac = (m_flCurrent[ barnum ] - m_flMin[ barnum ]) / ( m_flMax[ barnum ] - m_flMin[ barnum ] );
+ }
+
+ int tickmark = (int)( frac * m_nTicks[ barnum ] + 0.5 );
+ tickmark = min( m_nTicks[ barnum ], tickmark );
+ tickmark = max( 0, tickmark );
+
+ int thumbwidth = 20;
+ int thumbheight = 14;
+ int xoffset = -thumbwidth / 2;
+ int yoffset = -thumbheight / 2 + 2;
+
+ int leftedge = rcBar.left + (int)( (float)( rcBar.right - rcBar.left ) * (float)(tickmark) / (float)m_nTicks[ barnum ] );
+
+ rcThumb.left = leftedge + xoffset;
+ rcThumb.right = rcThumb.left + thumbwidth;
+ rcThumb.top = rcBar.top + yoffset;
+ rcThumb.bottom = rcThumb.top + thumbheight;
+}
+
+void mxExpressionSlider::DrawBar( HDC& dc )
+{
+ RECT rcBar;
+
+ GetBarRect( rcBar );
+
+ HPEN oldPen;
+
+ HPEN shadow;
+ HBRUSH face;
+ HPEN hilight;
+
+ shadow = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DSHADOW ) );
+ hilight = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
+ face = CreateSolidBrush( GetSysColor( COLOR_3DFACE ) );
+
+ oldPen = (HPEN)SelectObject( dc, hilight );
+
+ MoveToEx( dc, rcBar.left, rcBar.bottom, NULL );
+ LineTo( dc, rcBar.left, rcBar.top );
+ LineTo( dc, rcBar.right, rcBar.top );
+
+ SelectObject( dc, shadow );
+
+ LineTo( dc, rcBar.right, rcBar.bottom );
+ LineTo( dc, rcBar.left, rcBar.bottom );
+
+ rcBar.left += 1;
+ //rcBar.right -= 1;
+ rcBar.top += 1;
+ rcBar.bottom -= 1;
+
+ FillRect( dc, &rcBar, face );
+
+ SelectObject( dc, oldPen );
+
+ DeleteObject( face );
+ DeleteObject( shadow );
+ DeleteObject( hilight );
+}
+
+void mxExpressionSlider::DrawThumb( int barnum, HDC& dc )
+{
+ RECT rcThumb;
+
+ GetThumbRect( barnum, rcThumb );
+
+ // Draw it
+
+
+ HPEN oldPen;
+
+ HPEN shadow;
+ HBRUSH face;
+ HPEN hilight;
+
+ shadow = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DDKSHADOW ) );
+ hilight = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
+
+ switch ( barnum )
+ {
+ default:
+ case MAGNITUDE_BAR:
+ {
+ float frac;
+ if (m_flCurrent[ barnum ] < 0)
+ {
+ frac = m_flCurrent[ barnum ] / m_flMin[ barnum ];
+ }
+ else
+ {
+ frac = m_flCurrent[ barnum ] / m_flMax[ barnum ];
+ }
+ frac = min( 1.0f, frac );
+ frac = max( 0.0f, frac );
+
+ COLORREF clr = GetSysColor( COLOR_3DFACE );
+ int r, g, b;
+ r = GetRValue( clr );
+ g = GetRValue( clr );
+ b = GetRValue( clr );
+
+ // boost colors
+ r = (int)( (1-frac) * b );
+ b = min( 255, (int)(r + ( 255 - r ) * frac ) );
+ g = (int)( (1-frac) * g );
+
+ face = CreateSolidBrush( RGB( r, g, b ) );
+ }
+ break;
+ case BALANCE_BAR:
+ {
+ float frac = m_flCurrent[ barnum ];
+ frac = min( 1.0f, frac );
+ frac = max( 0.0f, frac );
+
+ COLORREF clr = GetSysColor( COLOR_3DFACE );
+ int r, g, b;
+ r = GetRValue( clr );
+ g = GetRValue( clr );
+ b = GetRValue( clr );
+
+ // boost colors toward red if we are not at 0.5
+ float boost = 2.0 * ( fabs( frac - 0.5f ) );
+
+ r = r + ( 255 - r ) * boost;
+ g = ( 1 - boost ) * g;
+ b = ( 1 - boost ) * b;
+
+ face = CreateSolidBrush( RGB( r, g, b ) );
+ }
+ break;
+ }
+
+ //rcThumb.left += 1;
+ //rcThumb.right -= 1;
+ //rcThumb.top += 1;
+ //rcThumb.bottom -= 1;
+
+ //FillRect( dc, &rcThumb, face );
+ POINT region[3];
+ int cPoints = 3;
+
+ InflateRect( &rcThumb, -2, 0 );
+
+// int height = rcThumb.bottom - rcThumb.top;
+// int offset = height / 2 + 1;
+ int offset = 2;
+
+ switch ( barnum )
+ {
+ case MAGNITUDE_BAR:
+ default:
+ {
+ region[ 0 ].x = rcThumb.left;
+ region[ 0 ].y = rcThumb.top;
+
+ region[ 1 ].x = rcThumb.right;
+ region[ 1 ].y = rcThumb.top;
+
+ region[ 2 ].x = ( rcThumb.left + rcThumb.right ) / 2;
+ region[ 2 ].y = rcThumb.bottom - offset;
+ }
+ break;
+ case BALANCE_BAR:
+ {
+ region[ 0 ].x = ( rcThumb.left + rcThumb.right ) / 2;
+ region[ 0 ].y = rcThumb.top + offset;
+
+ region[ 1 ].x = rcThumb.left;
+ region[ 1 ].y = rcThumb.bottom;
+
+ region[ 2 ].x = rcThumb.right;
+ region[ 2 ].y = rcThumb.bottom;
+
+ }
+ break;
+ }
+
+ HRGN rgn = CreatePolygonRgn( region, cPoints, ALTERNATE );
+
+ int oldPF = SetPolyFillMode( dc, ALTERNATE );
+ FillRgn( dc, rgn, face );
+ SetPolyFillMode( dc, oldPF );
+
+ DeleteObject( rgn );
+
+ oldPen = (HPEN)SelectObject( dc, hilight );
+
+ MoveToEx( dc, region[0].x, region[0].y, NULL );
+ LineTo( dc, region[1].x, region[1].y );
+ SelectObject( dc, shadow );
+ LineTo( dc, region[2].x, region[2].y );
+ SelectObject( dc, hilight );
+ LineTo( dc, region[0].x, region[0].y );
+
+ SelectObject( dc, oldPen );
+
+ DeleteObject( face );
+ DeleteObject( shadow );
+ DeleteObject( hilight );
+}
+
+void mxExpressionSlider::DrawTitle( HDC &dc )
+{
+ if ( !m_bDrawTitle )
+ return;
+
+ HWND wnd = (HWND)getHandle();
+ if ( !wnd )
+ return;
+
+ RECT rc;
+ GetClientRect( wnd, &rc );
+ rc.right = m_nTitleWidth;
+ rc.left += 16;
+
+ InflateRect( &rc, -5, -2 );
+
+ char sz[ 128 ];
+ sprintf( sz, "%s", getLabel() );
+
+ HFONT fnt, oldfont;
+
+ fnt = CreateFont(
+ -12 // H
+ , 0 // W
+ , 0 // Escapement
+ , 0 // Orient
+ , FW_NORMAL // Wt. (BOLD)
+ , 0 // Ital.
+ , 0 // Underl.
+ , 0 // SO
+ , ANSI_CHARSET // Charset
+ , OUT_TT_PRECIS // Out prec.
+ , CLIP_DEFAULT_PRECIS // Clip prec.
+ , PROOF_QUALITY // Qual.
+ , VARIABLE_PITCH | FF_DONTCARE // Pitch and Fam.
+ , "Arial" );
+
+ COLORREF oldColor;
+
+ if (!isEdited( 0 ))
+ {
+ oldColor = SetTextColor( dc, GetSysColor( COLOR_BTNTEXT ) );
+ }
+ else
+ {
+ oldColor = SetTextColor( dc, RGB( 255, 0, 0 ) );
+ }
+ int oldMode = SetBkMode( dc, TRANSPARENT );
+ oldfont = (HFONT)SelectObject( dc, fnt );
+
+ DrawText( dc, sz, -1, &rc, DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_LEFT | DT_WORD_ELLIPSIS );
+
+ SelectObject( dc, oldfont );
+ DeleteObject( fnt );
+ SetBkMode( dc, oldMode );
+ SetTextColor( dc, oldColor );
+}
+
+void mxExpressionSlider::redraw()
+{
+ HWND wnd = (HWND)getHandle();
+ if ( !wnd )
+ return;
+
+ HDC finalDC = GetDC( wnd );
+ if ( !finalDC )
+ return;
+
+ RECT rc;
+ GetClientRect( wnd, &rc );
+
+ int w = rc.right - rc.left;
+ int h = rc.bottom - rc.top;
+
+ HDC dc = CreateCompatibleDC( finalDC );
+ HBITMAP oldbm, bm;
+
+ bm = CreateCompatibleBitmap( finalDC, w, h );
+
+ oldbm = (HBITMAP)SelectObject( dc, bm );
+
+ HBRUSH br = CreateSolidBrush( GetSysColor( COLOR_3DFACE ) );
+
+ FillRect( dc, &rc, br );
+
+ DeleteObject( br );
+
+ DrawTitle( dc );
+
+ DrawBar( dc );
+
+ // Draw slider
+ for ( int i = ( m_bPaired ? 1 : 0 ); i >= 0 ; i-- )
+ {
+ DrawThumb( i, dc );
+ }
+
+ BitBlt( finalDC, 0, 0, w, h, dc, 0, 0, SRCCOPY );
+
+ SelectObject( dc, oldbm );
+
+ DeleteObject( bm );
+
+ DeleteDC( dc );
+
+ ReleaseDC( wnd, finalDC );
+ ValidateRect( wnd, &rc );
+}
+
+void mxExpressionSlider::MoveThumb( int barnum, int xpos, bool finish )
+{
+ RECT rcBar;
+
+ GetBarRect( rcBar );
+
+ if ( xpos < rcBar.left )
+ {
+ m_flCurrent[ barnum ] = m_flMin[ barnum ];
+ }
+ else if ( xpos > rcBar.right )
+ {
+ m_flCurrent[ barnum ] = m_flMax[ barnum ];
+ }
+ else
+ {
+ float frac = (float)( xpos - rcBar.left ) / (float)( rcBar.right - rcBar.left );
+ // snap slider to nearest "tick" so that it get drawn in the correct place
+ int curtick = (int)( frac * m_nTicks[ 0 ] + 0.5);
+ m_flCurrent[ barnum ] = m_flMin[ barnum ] + ((float)curtick / (float)m_nTicks[ 0 ]) * (m_flMax[ barnum ] - m_flMin[ barnum ]);
+ }
+
+ // update equivalent setting
+ m_flSetting[ 0 ] = getValue( 0 );
+ m_flSetting[ 1 ] = getValue( 1 );
+
+ m_bIsEdited[ 0 ] = true;
+ m_bIsEdited[ 1 ] = true;
+
+ // Send message to parent
+ HWND parent = (HWND)( getParent() ? getParent()->getHandle() : NULL );
+ if ( parent )
+ {
+ LPARAM lp;
+ WPARAM wp;
+
+ wp = MAKEWPARAM( finish ? SB_ENDSCROLL : SB_THUMBPOSITION, barnum );
+ lp = (long)getHandle();
+
+ SendMessage( parent, WM_HSCROLL, wp, lp );
+ }
+
+ BoundValue();
+ redraw();
+}
+
+bool mxExpressionSlider::PaintBackground( void )
+{
+ return false;
+}
+
+int mxExpressionSlider::handleEvent( mxEvent *event )
+{
+ int iret = 0;
+ switch ( event->event )
+ {
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ iret = 0;
+ break;
+ case IDC_INFLUENCE:
+ {
+ SetFocus( (HWND)getHandle() );
+
+ setEdited( 0, false );
+ setEdited( 1, false );
+
+ // Send message to parent
+ HWND parent = (HWND)( getParent() ? getParent()->getHandle() : NULL );
+ if ( parent )
+ {
+ LPARAM lp;
+ WPARAM wp;
+
+ wp = MAKEWPARAM( SB_ENDSCROLL, m_nCurrentBar );
+ lp = (long)getHandle();
+
+ SendMessage( parent, WM_HSCROLL, wp, lp );
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case mxEvent::MouseDown:
+ {
+ SetFocus( (HWND)getHandle() );
+
+ if ( !m_bDraggingThumb )
+ {
+ RECT rcThumb;
+ POINT pt;
+
+ pt.x = (short)event->x;
+ pt.y = (short)event->y;
+
+ m_nCurrentBar = ( event->buttons & mxEvent::MouseRightButton ) ? BALANCE_BAR : MAGNITUDE_BAR;
+ GetThumbRect( m_nCurrentBar, rcThumb );
+
+ if ( PtInRect( &rcThumb, pt ) )
+ {
+ m_bDraggingThumb = true;
+ }
+
+ // Snap position if they didn't click on the thumb itself
+#if 0
+ else
+ {
+ m_bDraggingThumb = true;
+ MoveThumb( m_nCurrentBar, (short)event->x, false );
+ }
+#endif
+ }
+ iret = 1;
+ }
+ break;
+ case mxEvent::MouseDrag:
+ case mxEvent::MouseMove:
+ {
+ if ( m_bDraggingThumb )
+ {
+ m_pInfluence->setChecked( true );
+ MoveThumb( m_nCurrentBar, (short)event->x, false );
+ iret = 1;
+ }
+ }
+ break;
+ case mxEvent::MouseUp:
+ {
+ if ( m_bDraggingThumb )
+ {
+ m_pInfluence->setChecked( true );
+ m_bDraggingThumb = false;
+ MoveThumb( m_nCurrentBar, (short)event->x, true );
+ m_nCurrentBar = 0;
+ }
+ iret = 1;
+ }
+ break;
+ case mxEvent::KeyDown:
+ {
+ if ( event->key == VK_RETURN ||
+ event->key == 'S' )
+ {
+ // See if there is an event in the flex animation window
+ g_pExpressionTool->OnSetSingleKeyFromFlex( getLabel() );
+ }
+ }
+ break;
+ }
+
+ return iret;
+}