//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "tabwindow.h" #include "ChoreoWidgetDrawHelper.h" #include "hlfaceposer.h" //----------------------------------------------------------------------------- // Purpose: Constructor // Input : *parent - // x - // y - // w - // h - // id - // style - //----------------------------------------------------------------------------- CTabWindow::CTabWindow( mxWindow *parent, int x, int y, int w, int h, int id /*= 0*/, int style /*=0*/ ) : mxWindow( parent, x, y, w, h, "", style ) { setId( id ); m_nSelected = -1; m_nRowHeight = 20; m_nRowsRequired = 1; m_nTabWidth = 80; m_nPixelDelta = 3; m_bInverted = false; m_bRightJustify = false; SetColor( COLOR_BG, GetSysColor( COLOR_BTNFACE ) ); SetColor( COLOR_FG, GetSysColor( COLOR_INACTIVECAPTION ) ); SetColor( COLOR_FG_SELECTED, GetSysColor( COLOR_ACTIVECAPTION ) ); SetColor( COLOR_HILITE, GetSysColor( COLOR_3DSHADOW ) ); SetColor( COLOR_HILITE_SELECTED, GetSysColor( COLOR_3DHILIGHT ) ); SetColor( COLOR_TEXT, GetSysColor( COLOR_CAPTIONTEXT ) ); SetColor( COLOR_TEXT_SELECTED, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ); FacePoser_AddWindowStyle( this, WS_CLIPCHILDREN | WS_CLIPSIBLINGS ); } //----------------------------------------------------------------------------- // Purpose: // Output : CTabWindow::~CTabWindow //----------------------------------------------------------------------------- CTabWindow::~CTabWindow ( void ) { removeAll(); } //----------------------------------------------------------------------------- // Purpose: // Input : index - // clr - //----------------------------------------------------------------------------- void CTabWindow::SetColor( int index, COLORREF clr ) { if ( index < 0 || index >= NUM_COLORS ) return; m_Colors[ index ] = clr; } void CTabWindow::SetInverted( bool invert ) { m_bInverted = invert; RecomputeLayout( w2() ); } void CTabWindow::SetRightJustify( bool rightjustify ) { m_bRightJustify = true; RecomputeLayout( w2() ); } //----------------------------------------------------------------------------- // Purpose: Tabs are sized to string content // Input : rcClient - // tabRect - // tabNum - //----------------------------------------------------------------------------- void CTabWindow::GetTabRect( const RECT& rcClient, RECT& tabRect, int tabNum ) { tabRect = m_Items[ tabNum ].rect; } //----------------------------------------------------------------------------- // Purpose: // Input : drawHelper - // rcClient - // tabnum - // selected - //----------------------------------------------------------------------------- void CTabWindow::DrawTab( CChoreoWidgetDrawHelper& drawHelper, RECT& rcClient, int tabnum, bool selected ) { RECT rcTab; if ( tabnum < 0 || tabnum >= m_Items.Size() ) return; GetTabRect( rcClient, rcTab, tabnum ); COLORREF fgcolor = m_Colors[ selected ? COLOR_FG_SELECTED : COLOR_FG ]; COLORREF hilightcolor = m_Colors[ selected ? COLOR_HILITE_SELECTED : COLOR_HILITE ]; COLORREF text = m_Colors[ selected ? COLOR_TEXT_SELECTED : COLOR_TEXT ]; // Create a trapezoid/paralleogram POINT region[4]; int cPoints = 4; OffsetRect( &rcTab, 0, m_bInverted ? 1 : -1 ); if ( m_bInverted ) { region[ 0 ].x = rcTab.left - m_nPixelDelta; region[ 0 ].y = rcTab.top; region[ 1 ].x = rcTab.right + m_nPixelDelta; region[ 1 ].y = rcTab.top; region[ 2 ].x = rcTab.right - m_nPixelDelta; region[ 2 ].y = rcTab.bottom; region[ 3 ].x = rcTab.left + m_nPixelDelta; region[ 3 ].y = rcTab.bottom; } else { region[ 0 ].x = rcTab.left + m_nPixelDelta; region[ 0 ].y = rcTab.top; region[ 1 ].x = rcTab.right - m_nPixelDelta; region[ 1 ].y = rcTab.top; region[ 2 ].x = rcTab.right + m_nPixelDelta; region[ 2 ].y = rcTab.bottom; region[ 3 ].x = rcTab.left - m_nPixelDelta; region[ 3 ].y = rcTab.bottom; } HDC dc = drawHelper.GrabDC(); HRGN rgn = CreatePolygonRgn( region, cPoints, ALTERNATE ); int oldPF = SetPolyFillMode( dc, ALTERNATE ); HBRUSH brBg = CreateSolidBrush( fgcolor ); HBRUSH brBorder = CreateSolidBrush( hilightcolor ); //HBRUSH brInset = CreateSolidBrush( fgcolor ); FillRgn( dc, rgn, brBg ); FrameRgn( dc, rgn, brBorder, 1, 1 ); SetPolyFillMode( dc, oldPF ); DeleteObject( rgn ); DeleteObject( brBg ); DeleteObject( brBorder ); //DeleteObject( brInset ); // Position label InflateRect( &rcTab, -5, 0 ); OffsetRect( &rcTab, 2, 0 ); // Draw label drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, text, rcTab, "%s%s", getPrefix( tabnum ), getLabel( tabnum ) ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTabWindow::redraw( void ) { CChoreoWidgetDrawHelper drawHelper( this, m_Colors[ COLOR_BG ] ); int liney = m_bInverted ? 1 : h2() - 2; drawHelper.DrawColoredLine( m_Colors[ COLOR_HILITE ], PS_SOLID, 1, 0, liney, w(), liney ); RECT rc; drawHelper.GetClientRect( rc ); // Draw non-selected first for ( int i = 0 ; i < m_Items.Size(); i++ ) { if ( i == m_nSelected ) continue; DrawTab( drawHelper, rc, i ); } // Draw selected last, so that it appears to pop to top of z order if ( m_nSelected >= 0 && m_nSelected < m_Items.Size() ) { DrawTab( drawHelper, rc, m_nSelected, true ); } } //----------------------------------------------------------------------------- // Purpose: // Input : mx - // my - // Output : int //----------------------------------------------------------------------------- int CTabWindow::GetItemUnderMouse( int mx, int my ) { RECT rcClient; GetClientRect( (HWND)getHandle(), &rcClient ); for ( int i = 0; i < m_Items.Size() ; i++ ) { RECT rcTab; GetTabRect( rcClient, rcTab, i ); if ( mx < rcTab.left || mx > rcTab.right || my < rcTab.top || my > rcTab.bottom ) { continue; } return i; } return -1; } //----------------------------------------------------------------------------- // Purpose: // Input : *event - // Output : int CTabWindow::handleEvent //----------------------------------------------------------------------------- int CTabWindow::handleEvent (mxEvent *event) { int iret = 0; switch ( event->event ) { case mxEvent::MouseDown: { int item = GetItemUnderMouse( (short)event->x, (short)event->y ); if ( item != -1 ) { m_nSelected = item; redraw(); // Send CBN_SELCHANGE WM_COMMAND message to parent HWND parent = (HWND)( getParent() ? getParent()->getHandle() : NULL ); if ( parent ) { LPARAM lp; WPARAM wp; wp = MAKEWPARAM( getId(), CBN_SELCHANGE ); lp = (long)getHandle(); PostMessage( parent, WM_COMMAND, wp, lp ); } iret = 1; } if ( event->buttons & mxEvent::MouseRightButton ) { ShowRightClickMenu( (short)event->x, (short)event->y ); iret = 1; } } break; case mxEvent::Size: { RecomputeLayout( w2() ); } break; } return iret; } //----------------------------------------------------------------------------- // Purpose: Add string to table // Input : *item - //----------------------------------------------------------------------------- void CTabWindow::add( const char *item ) { m_Items.AddToTail(); CETItem *p = &m_Items[ m_Items.Size() - 1 ]; Assert( p ); Q_memset( &p->rect, 0, sizeof( p->rect) ); strcpy( p->m_szString, item ); p->m_szPrefix[ 0 ] = 0; m_nSelected = min( m_nSelected, m_Items.Size() - 1 ); m_nSelected = max( m_nSelected, 0 ); RecomputeLayout( w2() ); redraw(); } void CTabWindow::setPrefix( int item, char const *prefix ) { if ( item < 0 || item >= m_Items.Size() ) return; Q_strncpy( m_Items[ item ].m_szPrefix, prefix, sizeof( m_Items[ item ].m_szPrefix ) ); // RecomputeLayout( w2() ); } //----------------------------------------------------------------------------- // Purpose: Change selected item // Input : index - //----------------------------------------------------------------------------- void CTabWindow::select( int index ) { if ( index < 0 || index >= m_Items.Size() ) return; m_nSelected = index; redraw(); } //----------------------------------------------------------------------------- // Purpose: Remove a string // Input : index - //----------------------------------------------------------------------------- void CTabWindow::remove( int index ) { if ( index < 0 || index >= m_Items.Size() ) return; m_Items.Remove( index ); m_nSelected = min( m_nSelected, m_Items.Size() - 1 ); m_nSelected = max( m_nSelected, 0 ); RecomputeLayout( w2() ); redraw(); } //----------------------------------------------------------------------------- // Purpose: Clear out everything //----------------------------------------------------------------------------- void CTabWindow::removeAll() { m_nSelected = -1; m_Items.RemoveAll(); RecomputeLayout( w2() ); redraw(); } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CTabWindow::getItemCount () const { return m_Items.Size(); } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CTabWindow::getSelectedIndex () const { // Convert based on override index return m_nSelected; } char const *CTabWindow::getLabel( int item ) { if ( item < 0 || item >= m_Items.Count() ) return ""; return m_Items[ item ].m_szString; } char const *CTabWindow::getPrefix( int item ) { if ( item < 0 || item >= m_Items.Count() ) return ""; return m_Items[ item ].m_szPrefix; } void CTabWindow::SetRowHeight( int rowheight ) { m_nRowHeight = rowheight; RecomputeLayout( w2() ); redraw(); } int CTabWindow::GetBestHeight( int width ) { return RecomputeLayout( width, false ) * m_nRowHeight; } int CTabWindow::RecomputeLayout( int windowWidth, bool dolayout /*=true*/ ) { // Draw non-selected first int curedge = m_nPixelDelta + 1; int curtop = 0; if ( m_bRightJustify ) { curedge = windowWidth - ( m_nPixelDelta + 1 ) - 5; } int startedge = curedge; int currentrow = 0; for ( int i = 0 ; i < m_Items.Size(); i++ ) { CETItem *p = &m_Items[ i ]; RECT rc; int textwidth = CChoreoWidgetDrawHelper::CalcTextWidth( "Arial", 9, FW_NORMAL, "%s%s", p->m_szPrefix, p->m_szString ) + 15; if ( !m_bRightJustify ) { // Starting column if ( curedge + textwidth > windowWidth ) { curedge = startedge; curtop += m_nRowHeight; currentrow++; } rc.left = curedge; rc.right = curedge + textwidth; rc.top = curtop + 2; rc.bottom = curtop + m_nRowHeight; curedge += textwidth; p->rect = rc; } else { // Starting column if ( curedge - textwidth < 0 ) { curedge = startedge; curtop += m_nRowHeight; currentrow++; } rc.left = curedge - textwidth; rc.right = curedge; rc.top = curtop; rc.bottom = curtop + m_nRowHeight - 2; curedge -= textwidth; } if ( dolayout ) { p->rect = rc; } } if ( dolayout ) { m_nRowsRequired = currentrow + 1; } return currentrow + 1; }