|
|
//========= Copyright � 1996-2005, 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 );
Color clr = RGBToColor( GetSysColor( COLOR_3DFACE ) ); int r, g, b; r = clr.r(); g = clr.g(); b = clr.b();
// boost colors
r = (int)( (1-frac) * b ); b = min( 255, (int)(r + ( 255 - r ) * frac ) ); g = (int)( (1-frac) * g );
face = CreateSolidBrush( ColorToRGB( Color( r, g, b ) ) ); } break; case BALANCE_BAR: { float frac = m_flCurrent[ barnum ]; frac = min( 1.0f, frac ); frac = max( 0.0f, frac );
Color clr = RGBToColor( GetSysColor( COLOR_3DFACE ) ); int r, g, b; r = clr.r(); g = clr.g(); b = clr.b();
// 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( ColorToRGB( Color( 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" );
Color oldColor;
if (!isEdited( 0 )) { oldColor = RGBToColor( SetTextColor( dc, GetSysColor( COLOR_BTNTEXT ) ) ); } else { oldColor = RGBToColor( SetTextColor( dc, ColorToRGB( Color( 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, ColorToRGB( 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; }
|