summaryrefslogtreecommitdiff
path: root/vguimatsurface/Cursor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vguimatsurface/Cursor.cpp')
-rw-r--r--vguimatsurface/Cursor.cpp565
1 files changed, 565 insertions, 0 deletions
diff --git a/vguimatsurface/Cursor.cpp b/vguimatsurface/Cursor.cpp
new file mode 100644
index 0000000..5451541
--- /dev/null
+++ b/vguimatsurface/Cursor.cpp
@@ -0,0 +1,565 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Methods associated with the cursor
+//
+// $Revision: $
+// $NoKeywords: $
+//===========================================================================//
+
+#if !defined( _X360 )
+ #define OEMRESOURCE //for OCR_* cursor junk
+ #include "winlite.h"
+#endif
+#include <appframework/ilaunchermgr.h>
+
+#if defined( USE_SDL )
+#undef M_PI
+#include "SDL.h"
+#endif
+
+#include "tier0/dbg.h"
+#include "tier0/vcrmode.h"
+#include "tier0/icommandline.h"
+#include "tier1/utldict.h"
+#include "Cursor.h"
+#include "vguimatsurface.h"
+#include "MatSystemSurface.h"
+#include "filesystem.h"
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+#if defined( USE_SDL )
+#include "materialsystem/imaterialsystem.h"
+#endif
+
+#include "inputsystem/iinputsystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+#if defined( USE_SDL )
+static SDL_Cursor *s_pDefaultCursor[ dc_last ];
+static SDL_Cursor *s_hCurrentCursor = NULL;
+static SDL_Cursor *s_hCurrentlySetCursor = NULL;
+#elif defined( WIN32 )
+static HICON s_pDefaultCursor[ dc_last ];
+static HICON s_hCurrentCursor = NULL;
+#endif
+static bool s_bCursorLocked = false;
+static bool s_bCursorVisible = true;
+static int s_nForceCursorVisibleCount = 0;
+static bool s_bSoftwareCursorActive = false;
+static int s_nSoftwareCursorTexture = -1;
+static float s_fSoftwareCursorOffsetX = 0;
+static float s_fSoftwareCursorOffsetY = 0;
+static int s_rnSoftwareCursorID[20];
+static float s_rfSoftwareCursorOffset[20][2];
+static bool s_bSoftwareCursorsInitialized = false;
+
+extern CMatSystemSurface g_MatSystemSurface;
+
+//-----------------------------------------------------------------------------
+// Initializes cursors
+//-----------------------------------------------------------------------------
+void InitCursors()
+{
+ // load up all default cursors
+#if defined( USE_SDL )
+
+ s_pDefaultCursor[ dc_none ] = NULL;
+ s_pDefaultCursor[ dc_arrow ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_ARROW );
+ s_pDefaultCursor[ dc_ibeam ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_IBEAM );
+ s_pDefaultCursor[ dc_hourglass ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_WAIT );
+ s_pDefaultCursor[ dc_crosshair ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_CROSSHAIR );
+ s_pDefaultCursor[ dc_waitarrow ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_WAITARROW );
+ s_pDefaultCursor[ dc_sizenwse ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENWSE );
+ s_pDefaultCursor[ dc_sizenesw ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENESW );
+ s_pDefaultCursor[ dc_sizewe ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZEWE );
+ s_pDefaultCursor[ dc_sizens ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENS );
+ s_pDefaultCursor[ dc_sizeall ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZEALL );
+ s_pDefaultCursor[ dc_no ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_NO );
+ s_pDefaultCursor[ dc_hand ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_HAND );
+
+ s_hCurrentCursor = s_pDefaultCursor[ dc_arrow ];
+
+#elif defined( WIN32 )
+
+ s_pDefaultCursor[ dc_none ] = NULL;
+ s_pDefaultCursor[ dc_arrow ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_NORMAL);
+ s_pDefaultCursor[ dc_ibeam ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_IBEAM);
+ s_pDefaultCursor[ dc_hourglass ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_WAIT);
+ s_pDefaultCursor[ dc_crosshair ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_CROSS);
+ s_pDefaultCursor[ dc_waitarrow ] =(HICON)LoadCursor(NULL, (LPCTSTR)32650);
+ s_pDefaultCursor[ dc_up ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_UP);
+ s_pDefaultCursor[ dc_sizenwse ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENWSE);
+ s_pDefaultCursor[ dc_sizenesw ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENESW);
+ s_pDefaultCursor[ dc_sizewe ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZEWE);
+ s_pDefaultCursor[ dc_sizens ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENS);
+ s_pDefaultCursor[ dc_sizeall ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZEALL);
+ s_pDefaultCursor[ dc_no ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_NO);
+ s_pDefaultCursor[ dc_hand ] =(HICON)LoadCursor(NULL, (LPCTSTR)32649);
+
+ s_hCurrentCursor = s_pDefaultCursor[ dc_arrow ];
+
+#endif
+
+ s_bCursorLocked = false;
+ s_bCursorVisible = true;
+ s_nForceCursorVisibleCount = 0;
+}
+
+
+#define USER_CURSOR_MASK 0x80000000
+
+#ifdef WIN32
+//-----------------------------------------------------------------------------
+// Purpose: Simple manager for user loaded windows cursors in vgui
+//-----------------------------------------------------------------------------
+class CUserCursorManager
+{
+public:
+ void Shutdown();
+ vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID );
+ bool LookupCursor( vgui::HCursor cursor, HCURSOR& handle );
+private:
+ CUtlDict< HCURSOR, int > m_UserCursors;
+};
+
+void CUserCursorManager::Shutdown()
+{
+ for ( int i = m_UserCursors.First() ; i != m_UserCursors.InvalidIndex(); i = m_UserCursors.Next( i ) )
+ {
+ ::DestroyCursor( m_UserCursors[ i ] );
+ }
+ m_UserCursors.RemoveAll();
+}
+
+vgui::HCursor CUserCursorManager::CreateCursorFromFile( char const *curOrAniFile, char const *pPathID )
+{
+ char fn[ 512 ];
+ Q_strncpy( fn, curOrAniFile, sizeof( fn ) );
+ Q_strlower( fn );
+ Q_FixSlashes( fn );
+
+ int cursorIndex = m_UserCursors.Find( fn );
+ if ( cursorIndex != m_UserCursors.InvalidIndex() )
+ {
+ return cursorIndex | USER_CURSOR_MASK;
+ }
+
+ g_pFullFileSystem->GetLocalCopy( fn );
+
+ char fullpath[ 512 ];
+ g_pFullFileSystem->RelativePathToFullPath( fn, pPathID, fullpath, sizeof( fullpath ) );
+
+ HCURSOR newCursor = (HCURSOR)LoadCursorFromFile( fullpath );
+ cursorIndex = m_UserCursors.Insert( fn, newCursor );
+ return cursorIndex | USER_CURSOR_MASK;
+}
+
+bool CUserCursorManager::LookupCursor( vgui::HCursor cursor, HCURSOR& handle )
+{
+ if ( !( (int)cursor & USER_CURSOR_MASK ) )
+ {
+ handle = 0;
+ return false;
+ }
+
+ int cursorIndex = (int)cursor & ~USER_CURSOR_MASK;
+ if ( !m_UserCursors.IsValidIndex( cursorIndex ) )
+ {
+ handle = 0;
+ return false;
+ }
+
+ handle = m_UserCursors[ cursorIndex ];
+ return true;
+}
+
+static CUserCursorManager g_UserCursors;
+#endif
+
+vgui::HCursor Cursor_CreateCursorFromFile( char const *curOrAniFile, char const *pPathID )
+{
+#ifdef WIN32
+ return g_UserCursors.CreateCursorFromFile( curOrAniFile, pPathID );
+#else
+ return dc_user;
+#endif
+}
+
+
+void Cursor_ClearUserCursors()
+{
+#ifdef WIN32
+ g_UserCursors.Shutdown();
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes all the textures for software cursors
+//-----------------------------------------------------------------------------
+int InitSoftwareCursorTexture( const char *pchFilename )
+{
+ if( !pchFilename || !*pchFilename )
+ return -1;
+
+ int nTextureID = g_MatSystemSurface.DrawGetTextureId( pchFilename );
+ if( nTextureID == -1 )
+ {
+ nTextureID = g_MatSystemSurface.CreateNewTextureID();
+ g_MatSystemSurface.DrawSetTextureFile( nTextureID, pchFilename, true, false );
+ }
+ return nTextureID;
+}
+
+void InitSoftwareCursors()
+{
+ if( s_bSoftwareCursorsInitialized )
+ return;
+
+ memset( s_rfSoftwareCursorOffset, 0, sizeof( s_rfSoftwareCursorOffset ) );
+
+ s_rnSoftwareCursorID[dc_none] = -1;
+ s_rnSoftwareCursorID[dc_arrow] =InitSoftwareCursorTexture( "vgui/cursors/arrow" );
+ s_rnSoftwareCursorID[dc_ibeam] =InitSoftwareCursorTexture( "vgui/cursors/ibeam" );
+ s_rnSoftwareCursorID[dc_hourglass]=InitSoftwareCursorTexture( "vgui/cursors/hourglass" );
+ s_rnSoftwareCursorID[dc_crosshair]=InitSoftwareCursorTexture( "vgui/cursors/crosshair" );
+ s_rnSoftwareCursorID[dc_waitarrow]=InitSoftwareCursorTexture( "vgui/cursors/waitarrow" );
+ s_rnSoftwareCursorID[dc_up] =InitSoftwareCursorTexture( "vgui/cursors/up" );
+ s_rnSoftwareCursorID[dc_sizenwse] =InitSoftwareCursorTexture( "vgui/cursors/sizenwse" );
+ s_rnSoftwareCursorID[dc_sizenesw] =InitSoftwareCursorTexture( "vgui/cursors/sizenesw" );
+ s_rnSoftwareCursorID[dc_sizewe] =InitSoftwareCursorTexture( "vgui/cursors/sizewe" );
+ s_rnSoftwareCursorID[dc_sizens] =InitSoftwareCursorTexture( "vgui/cursors/sizens" );
+ s_rnSoftwareCursorID[dc_sizeall] =InitSoftwareCursorTexture( "vgui/cursors/sizeall" );
+ s_rnSoftwareCursorID[dc_no] =InitSoftwareCursorTexture( "vgui/cursors/no" );
+ s_rnSoftwareCursorID[dc_hand] =InitSoftwareCursorTexture( "vgui/cursors/hand" );
+
+ // handle the cursor hotspots not being at their origin
+ s_rfSoftwareCursorOffset[dc_arrow][0] = -0.1;
+ s_rfSoftwareCursorOffset[dc_arrow][1] = -0.1;
+ s_rfSoftwareCursorOffset[dc_ibeam][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_ibeam][1] = -0.8;
+ s_rfSoftwareCursorOffset[dc_hourglass][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_hourglass][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_crosshair][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_crosshair][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_waitarrow][0] = -0.1;
+ s_rfSoftwareCursorOffset[dc_waitarrow][1] = -0.1;
+ s_rfSoftwareCursorOffset[dc_up][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_up][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizenwse][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizenwse][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizenesw][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizenesw][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizewe][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizewe][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizens][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizens][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizeall][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_sizeall][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_no][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_no][1] = -0.5;
+ s_rfSoftwareCursorOffset[dc_hand][0] = -0.5;
+ s_rfSoftwareCursorOffset[dc_hand][1] = -0.5;
+
+ s_bSoftwareCursorsInitialized = true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Selects a cursor
+//-----------------------------------------------------------------------------
+void CursorSelect(HCursor hCursor)
+{
+ if ( ( hCursor == dc_alwaysvisible_push ) || ( hCursor == dc_alwaysvisible_pop ) )
+ {
+ // CConPanel in engine/console.cpp does a SetCursor(null). So when the TF2 chat window pops up
+ // and there are console commands showing and fading out in the top left, our chat window
+ // will have a cursor show/hide fight with them. So the cursor flickers or doesn't show up
+ // at all. Unfortunately on Linux, it's even worse since we recenter the mouse when it's
+ // not shown - so we added this API call which causes cursor.cpp to always show the cursor.
+ s_nForceCursorVisibleCount += ( hCursor == dc_alwaysvisible_push ? 1 : -1 );
+ Assert( s_nForceCursorVisibleCount >= 0 );
+
+ if( ( s_nForceCursorVisibleCount && !s_bCursorVisible ) ||
+ ( !s_nForceCursorVisibleCount && s_bCursorVisible ) )
+ {
+ ActivateCurrentCursor();
+ }
+ return;
+ }
+
+ if (s_bCursorLocked)
+ return;
+
+#if defined( WIN32 ) && !defined( USE_SDL )
+ s_bCursorVisible = true;
+ switch (hCursor)
+ {
+ case dc_user:
+ case dc_none:
+ case dc_blank:
+ s_bCursorVisible = false;
+ break;
+
+ case dc_arrow:
+ case dc_waitarrow:
+ case dc_ibeam:
+ case dc_hourglass:
+ case dc_crosshair:
+ case dc_up:
+ case dc_sizenwse:
+ case dc_sizenesw:
+ case dc_sizewe:
+ case dc_sizens:
+ case dc_sizeall:
+ case dc_no:
+ case dc_hand:
+ if( !s_bSoftwareCursorActive )
+ {
+ s_hCurrentCursor = s_pDefaultCursor[hCursor];
+ }
+ else
+ {
+ s_nSoftwareCursorTexture = s_rnSoftwareCursorID[ hCursor ];
+ s_fSoftwareCursorOffsetX = s_rfSoftwareCursorOffset[ hCursor ][0];
+ s_fSoftwareCursorOffsetY = s_rfSoftwareCursorOffset[ hCursor ][1];
+ }
+ break;
+
+ default:
+ {
+ HCURSOR custom = 0;
+ if ( g_UserCursors.LookupCursor( hCursor, custom ) && custom != 0 )
+ {
+ s_hCurrentCursor = custom;
+ }
+ else
+ {
+ s_bCursorVisible = false;
+ Assert(0);
+ }
+ }
+ break;
+ }
+
+ ActivateCurrentCursor();
+
+#elif defined( USE_SDL )
+
+ switch (hCursor)
+ {
+ case dc_user:
+ case dc_none:
+ case dc_blank:
+ s_bCursorVisible = false;
+ break;
+
+ default:
+ // We don't support custom cursors at the moment (but could, if necessary).
+ // Fall through and use the arrow for now...
+ Assert(0);
+ hCursor = dc_arrow;
+
+ case dc_arrow:
+ case dc_waitarrow:
+ case dc_ibeam:
+ case dc_hourglass:
+ case dc_crosshair:
+ case dc_up:
+ case dc_sizenwse:
+ case dc_sizenesw:
+ case dc_sizewe:
+ case dc_sizens:
+ case dc_sizeall:
+ case dc_no:
+ case dc_hand:
+ s_bCursorVisible = true;
+ if( !s_bSoftwareCursorActive )
+ {
+ s_hCurrentCursor = s_pDefaultCursor[hCursor];
+ }
+ else
+ {
+ s_nSoftwareCursorTexture = s_rnSoftwareCursorID[ hCursor ];
+ s_fSoftwareCursorOffsetX = s_rfSoftwareCursorOffset[ hCursor ][0];
+ s_fSoftwareCursorOffsetY = s_rfSoftwareCursorOffset[ hCursor ][1];
+ }
+ break;
+ }
+
+ ActivateCurrentCursor();
+
+#else
+#error
+#endif
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Hides the hardware cursor
+//-----------------------------------------------------------------------------
+void HideHardwareCursor()
+{
+#if defined( WIN32 ) && !defined( USE_SDL )
+ ::SetCursor(NULL);
+#elif defined( USE_SDL )
+ //if ( s_hCurrentlySetCursor != s_pDefaultCursor[ dc_none ] )
+ {
+ s_hCurrentlySetCursor = s_pDefaultCursor[ dc_none ];
+ g_pLauncherMgr->SetMouseCursor( s_hCurrentlySetCursor );
+ g_pLauncherMgr->SetMouseVisible( false );
+ }
+#else
+#error
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Activates the current cursor
+//-----------------------------------------------------------------------------
+void ActivateCurrentCursor()
+{
+ if( s_bSoftwareCursorActive )
+ {
+ HideHardwareCursor();
+ return;
+ }
+
+ if ( s_bCursorVisible || ( s_nForceCursorVisibleCount > 0 ) )
+ {
+#if defined( WIN32 ) && !defined( USE_SDL )
+ ::SetCursor(s_hCurrentCursor);
+#elif defined( USE_SDL )
+ if (s_hCurrentlySetCursor != s_hCurrentCursor )
+ {
+ s_hCurrentlySetCursor = s_hCurrentCursor;
+ g_pLauncherMgr->SetMouseCursor( s_hCurrentlySetCursor );
+ g_pLauncherMgr->SetMouseVisible( true );
+ }
+#else
+#error
+#endif
+ }
+ else
+ {
+ HideHardwareCursor();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: prevents vgui from changing the cursor
+//-----------------------------------------------------------------------------
+void LockCursor( bool bEnable )
+{
+ s_bCursorLocked = bEnable;
+ ActivateCurrentCursor();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: unlocks the cursor state
+//-----------------------------------------------------------------------------
+bool IsCursorLocked()
+{
+ return s_bCursorLocked;
+}
+
+
+//-----------------------------------------------------------------------------
+// handles mouse movement
+//-----------------------------------------------------------------------------
+void CursorSetPos( void *hwnd, int x, int y )
+{
+#if defined( USE_SDL )
+ if ( s_bCursorVisible )
+#endif
+ g_pInputSystem->SetCursorPosition( x, y );
+}
+
+void CursorGetPos(void *hwnd, int &x, int &y)
+{
+#if defined ( USE_SDL ) && !defined( PLATFORM_WINDOWS )
+ if ( s_bCursorVisible )
+ {
+ SDL_GetMouseState( &x, &y );
+
+ int windowHeight = 0;
+ int windowWidth = 0;
+ //unsigned int ignored;
+ SDL_GetWindowSize( ( SDL_Window * )g_pLauncherMgr->GetWindowRef(), &windowWidth, &windowHeight );
+
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ int rx, ry, width, height;
+ pRenderContext->GetViewport( rx, ry, width, height );
+
+ if ( !s_bSoftwareCursorActive && (width != windowWidth || height != windowHeight ) )
+ {
+ // scale the x/y back into the co-ords of the back buffer, not the scaled up window
+ //DevMsg( "Mouse x:%d y:%d %d %d %d %d\n", x, y, width, windowWidth, height, abs( height - windowHeight ) );
+ x = x * (float)width/windowWidth;
+ y = y * (float)height/windowHeight;
+ }
+ }
+ else
+ {
+ // cursor is invisible, just say we have it pinned to the middle of the screen
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ int rx, ry, width, height;
+ pRenderContext->GetViewport( rx, ry, width, height );
+ x = rx + width/2;
+ y = ry + height/2;
+ //printf( "Mouse(inv) x:%d y:%d %d %d\n", x, y, width, height );
+ }
+#else
+ POINT pt;
+
+ // Default implementation
+ VCRHook_GetCursorPos( &pt );
+ VCRHook_ScreenToClient((HWND)hwnd, &pt);
+ x = pt.x; y = pt.y;
+#endif
+}
+
+
+void EnableSoftwareCursor( bool bEnable )
+{
+ if( bEnable )
+ InitSoftwareCursors();
+
+ bool bWasEnabled = s_bSoftwareCursorActive;
+ s_bSoftwareCursorActive = bEnable;
+
+ // set the cursor to the arrow (or none if appropriate) if we're activating the
+ // software cursor. VGUI will likely update it again soon, but this will give
+ // us some kind of cursor in the meantime
+ if( !bWasEnabled && bEnable )
+ {
+ if( s_bCursorVisible )
+ CursorSelect( dc_arrow );
+ }
+}
+
+bool ShouldDrawSoftwareCursor()
+{
+ return s_bSoftwareCursorActive && s_bCursorVisible;
+}
+
+int GetSoftwareCursorTexture( float *px, float *py )
+{
+ if( px && py )
+ {
+ *px = s_fSoftwareCursorOffsetX;
+ *py = s_fSoftwareCursorOffsetY;
+ }
+ return s_nSoftwareCursorTexture;
+}
+
+