hl2_src-leak-2017/src/vgui2/src/Surface.cpp

4083 lines
112 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#define WIN32_LEAN_AND_MEAN
#define OEMRESOURCE
// SRC only
#define PROTECTED_THINGS_DISABLE
#include <windows.h>
#include <imm.h>
#include <zmouse.h>
#include <shellapi.h>
#pragma warning( disable : 4201 )
#include <mmsystem.h>
#pragma warning( default : 4201 )
#include <oleidl.h>
#include <stdio.h>
#include <basetypes.h>
#include <vgui/VGUI.h>
#include <vgui/Dar.h>
#include <vgui/IClientPanel.h>
#include <vgui/ISurface.h>
#include <vgui/IInputInternal.h>
#include <vgui/IPanel.h>
#include <vgui/ISystem.h>
#include <vgui/ILocalize.h>
#include <vgui/IHTML.h>
#include <vgui/IVGui.h>
#include <vgui/IPanel.h>
#include <vgui/IScheme.h>
#include <vgui/Cursor.h>
#include <vgui/KeyCode.h>
#include <KeyValues.h>
#include <vgui/MouseCode.h>
#include "vgui_internal.h"
#include "bitmap.h"
#include "VPanel.h"
#include "utlvector.h"
#include "utlsymbol.h"
#include "tier1/utldict.h"
#include "filesystem.h"
#include "SteamBootStrapper.h"
#include "vgui_surfacelib/Win32Font.h"
#include "vgui_surfacelib/FontManager.h"
#include "vgui_key_translation.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifdef PlaySound
#undef PlaySound
#endif
#ifdef CreateFont
#undef CreateFont
#endif
using namespace vgui;
#define PLAT(vpanel) (((VPanel *)vpanel)->Plat())
namespace vgui
{
class SurfacePlat
{
public:
HWND hwnd;
HDC hdc;
HDC hwndDC;
HDC textureDC;
HGLRC hglrc;
HRGN clipRgn;
HBITMAP bitmap;
int bitmapSize[2];
int restoreInfo[4];
bool isFullscreen;
bool disabled; // whether the window can take user input
int fullscreenInfo[3];
VPanel *embeddedPanel;
bool isToolbar; // whether it has an icon in the tool tray or not
HICON notifyIcon;
VPANEL notifyPanel;
HPanel lastKeyFocusIndex; // index to the last panel to have the focus
};
class Texture
{
public:
int _id;
HBITMAP _bitmap;
HBITMAP _maskBitmap;
bool _bMask;
HICON _icon;
int _wide;
int _tall;
void *_dib;
void *_maskDib;
const char *_filename;
};
}
//-----------------------------------------------------------------------------
// Purpose: Implementation of ISurface for use running under windows, renders using GDI
// This is not used in the game, EngineSurface is used instead
//-----------------------------------------------------------------------------
class CWin32Surface : public ISurface
{
public:
friend class CIconImage;
CWin32Surface();
~CWin32Surface();
virtual void Shutdown();
virtual void RunFrame();
virtual VPANEL GetEmbeddedPanel();
virtual void SetEmbeddedPanel( VPANEL panel);
// initializes the surface with the current window state
virtual void SetCurrentContextPanel(VPANEL panel);
virtual void PushMakeCurrent(VPANEL panel,bool useInsets);
virtual void PopMakeCurrent(VPANEL panel);
virtual void DrawSetColor(int r, int g, int b, int a);
virtual void DrawSetColor(Color col);
virtual void DrawFilledRect(int x0, int y0, int x1, int y1);
virtual void DrawFilledRectFastFade( int x0, int y0, int x1, int y1, int fadeStartPt, int fadeEndPt, unsigned int alpha0, unsigned int alpha1, bool bHorizontal );
virtual void DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal );
virtual void DrawFilledRectArray( IntRect *pRects, int numRects );
virtual void DrawOutlinedRect(int x0, int y0, int x1, int y1);
virtual void DrawLine(int x0, int y0, int x1, int y1);
virtual void DrawPolyLine(int *px, int *py, int numPoints);
virtual void DrawSetTextFont(HFont font);
virtual void DrawSetTextColor(int r, int g, int b, int a);
virtual void DrawSetTextColor(Color col);
virtual void DrawSetTextPos(int x, int y);
virtual void DrawSetTextScale(float sx, float sy);
virtual void DrawPrintText(const wchar_t *, int textLen, FontDrawType_t drawType = FONT_DRAW_DEFAULT);
virtual void DrawUnicodeChar(wchar_t wch, FontDrawType_t drawType = FONT_DRAW_DEFAULT );
virtual void DrawUnicodeString( const wchar_t *pwString, FontDrawType_t drawType = FONT_DRAW_DEFAULT );
virtual void DrawGetTextPos(int& x,int& y);
virtual bool DrawGetTextureFile(int id, char *filename, int maxlen );
virtual int DrawGetTextureId( char const *filename );
virtual void DrawSetTextureFile(int id, const char *filename, int hardwareFilter, bool forceReload = false);
virtual void DrawSetTexture(int id);
virtual void DrawSetTextureRGBA(int id, const unsigned char *rgba, int wide, int tall, int hardwareFilter, bool forceReload = false);
virtual void DrawSetTextureRGBAEx(int id, const unsigned char *rgba, int wide, int tall, ImageFormat imageFormat );
virtual void DrawGetTextureSize(int id, int &wide, int &tall);
virtual IVguiMatInfo *DrawGetTextureMatInfoFactory( int id ) { return NULL; }
virtual void DrawTexturedRect(int x0, int y0, int x1, int y1);
virtual int CreateNewTextureID( bool procedural );
virtual bool IsTextureIDValid(int id);
virtual void FreeTextureData( Texture *pTexture );
virtual bool DeleteTextureByID(int id);
virtual void DrawFlushText();
virtual IHTML *CreateHTMLWindow(vgui::IHTMLEvents *events, VPANEL context);
virtual void PaintHTMLWindow(IHTML *htmlwin);
virtual void DeleteHTMLWindow(IHTML *htmlwin);
virtual VPANEL GetNotifyPanel();
virtual void SetNotifyIcon(VPANEL context, HTexture icon, VPANEL panelToReceiveMessages, const char *text);
virtual void SetPanelForInput( VPANEL vpanel );
virtual void GetScreenSize(int &wide, int &tall);
virtual void SetAsTopMost(VPANEL panel, bool state);
virtual void BringToFront(VPANEL panel);
virtual void SetForegroundWindow(VPANEL panel);
virtual void SetPanelVisible(VPANEL panel, bool visible);
virtual void SetMinimized(VPANEL panel, bool state);
virtual bool IsMinimized(VPANEL panel);
virtual void FlashWindow(VPANEL panel, bool state);
virtual void SetTitle(VPANEL panel, const wchar_t *title);
virtual void SetAsToolBar(VPANEL panel, bool state);
virtual bool SupportsFeature(SurfaceFeature_e feature);
virtual void SetTopLevelFocus(VPANEL panel);
virtual int GetPopupCount();
virtual VPANEL GetPopup(int index);
virtual void AddPanel(VPANEL panel);
virtual void ReleasePanel(VPANEL panel);
virtual void CreatePopup(VPANEL panel, bool minimised, bool showTaskbarIcon, bool disabled, bool mouseInput, bool kbInput );
virtual bool RecreateContext(VPANEL panel);
virtual void EnableMouseCapture(VPANEL panel, bool state);
virtual bool ShouldPaintChildPanel(VPANEL childPanel);
virtual void MovePopupToFront(VPANEL panel);
virtual void MovePopupToBack(VPANEL panel);
virtual void SwapBuffers(VPANEL panel);
virtual void Invalidate(VPANEL panel);
virtual void SetCursor(HCursor cursor);
virtual void SetCursorAlwaysVisible( bool visible ) {}
virtual void ApplyChanges();
virtual bool IsWithin(int x, int y);
virtual bool HasFocus();
virtual void GetWorkspaceBounds(int &x, int &y, int &wide, int &tall);
virtual void SolveTraverse(VPANEL panel, bool forceApplySchemeSettings);
virtual void PaintTraverse(VPANEL panel);
virtual void RestrictPaintToSinglePanel(VPANEL panel);
virtual void SetModalPanel(VPANEL );
virtual VPANEL GetModalPanel();
virtual void UnlockCursor();
virtual void LockCursor();
virtual void SetTranslateExtendedKeys(bool state);
virtual VPANEL GetTopmostPopup();
// sound
virtual void PlaySound(const char *fileName);
// fonts
virtual HFont CreateFont();
virtual bool SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin = 0, int nRangeMax = 0);
virtual int GetFontTall(HFont font);
virtual int GetFontTallRequested(HFont font);
virtual int GetFontAscent(HFont font, wchar_t wch);
virtual void GetCharABCwide(HFont font, int ch, int &a, int &b, int &c);
virtual int GetCharacterWidth(HFont font, int ch);
virtual void GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall);
virtual bool AddCustomFontFile(const char *fontName, const char *fontFileName);
virtual bool AddBitmapFontFile(const char *fontFileName);
virtual void SetBitmapFontName( const char *pName, const char *pFontFilename );
virtual const char *GetBitmapFontName( const char *pName );
virtual bool SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags);
virtual bool IsFontAdditive(HFont font);
virtual void PrecacheFontCharacters(HFont font, const wchar_t *pCharacters);
virtual void ClearTemporaryFontCache( void );
virtual const char *GetFontName( HFont font );
virtual const char *GetFontFamilyName( HFont font );
virtual bool IsCursorVisible() { return true; }
// gets the absolute coordinates of the screen (in screen space)
void GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall);
// methods
void setFocus(VPANEL panel);
void GetProportionalBase( int &width, int &height ) { width = BASE_WIDTH; height = BASE_HEIGHT; }
virtual void CalculateMouseVisible();
virtual bool NeedKBInput();
// we use the default IInput cursor functions
virtual bool HasCursorPosFunctions() { return false; }
virtual void SurfaceGetCursorPos(int &x, int &y) {}
virtual void SurfaceSetCursorPos(int x, int y){}
virtual void SetAllowHTMLJavaScript( bool state );
// SRC specific interfaces
virtual void DrawTexturedLine( const Vertex_t &a, const Vertex_t &b );
virtual void DrawOutlinedCircle(int x, int y, int radius, int segments) ;
virtual void DrawTexturedPolyLine( const Vertex_t *p,int n ) ; // (Note: this connects the first and last points).
virtual void DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 );
virtual void DrawTexturedPolygon(int n, Vertex_t *pVertices, bool bClipVertices = true);
virtual const wchar_t *GetTitle(VPANEL panel);
virtual void LockCursor( bool state );
virtual bool IsCursorLocked( void ) const;
virtual void SetWorkspaceInsets( int left, int top, int right, int bottom );
// Lower level char drawing code, call DrawGet then pass in info to DrawRender (NOT SUPPORTED BY DEFAULT SURFACE )!!!
virtual bool DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info );
virtual void DrawRenderCharFromInfo( const CharRenderInfo& info );
// alpha multipliers not yet implemented
virtual void DrawSetAlphaMultiplier( float alpha /* [0..1] */ ) {}
virtual float DrawGetAlphaMultiplier() { return 1.0f; }
// Here's where the app systems get to learn about each other
virtual bool Connect( CreateInterfaceFn factory );
virtual void Disconnect();
// Here's where systems can access other interfaces implemented by this object
// Returns NULL if it doesn't implement the requested interface
virtual void *QueryInterface( const char *pInterfaceName );
// Init, shutdown
virtual InitReturnVal_t Init();
//virtual void Shutdown();
// screen size changing
void OnScreenSizeChanged( int nOldWidth, int nOldHeight )
{
}
// We don't support this for non material system surfaces (we could)
virtual vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID )
{
Assert( 0 );
return dc_arrow;
}
virtual void PaintTraverseEx(VPANEL panel, bool paintPopups = false )
{
PaintTraverse( panel );
}
virtual float GetZPos() const
{
return 0.0f;
}
virtual IImage *GetIconImageForFullPath( char const *pFullPath );
virtual const char *GetResolutionKey( void ) const
{
Assert( 0 );
return NULL;
}
virtual bool ForceScreenSizeOverride( bool bState, int wide, int tall );
// LocalToScreen, ParentLocalToScreen fixups for explicit PaintTraverse calls on Panels not at 0, 0 position
virtual bool ForceScreenPosOffset( bool bState, int x, int y );
virtual void OffsetAbsPos( int &x, int &y );
virtual bool IsScreenSizeOverrideActive( void );
virtual bool IsScreenPosOverrideActive( void );
void GetKernedCharWidth( HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &flabcA )
{
Assert( 0 );
wide = 0.0f;
flabcA = 0.0f;
}
// split screen state changed, etc.
void ResetFontCaches()
{
}
virtual void DestroyTextureID( int id );
virtual int GetTextureNumFrames( int id );
virtual void DrawSetTextureFrame( int id, int nFrame, unsigned int *pFrameCache );
virtual void DrawUpdateRegionTextureRGBA( int nTextureID, int x, int y, const unsigned char *pchData, int wide, int tall, ImageFormat imageFormat )
{
}
virtual bool BHTMLWindowNeedsPaint(IHTML *htmlwin)
{
return false;
}
virtual const char *GetWebkitHTMLUserAgentString();
virtual void *Deprecated_AccessChromeHTMLController() { return NULL; }
virtual void SetFullscreenViewport( int x, int y, int w, int h ) OVERRIDE
{
m_nFullscreenViewportX = x;
m_nFullscreenViewportY = y;
m_nFullscreenViewportWidth = w;
m_nFullscreenViewportHeight = h;
m_pFullscreenRenderTarget = NULL;
}
virtual void GetFullscreenViewport( int & x, int & y, int & w, int & h ) OVERRIDE
{
x = m_nFullscreenViewportX;
y = m_nFullscreenViewportY;
w = m_nFullscreenViewportWidth;
h = m_nFullscreenViewportHeight;
}
virtual void PushFullscreenViewport();
virtual void PopFullscreenViewport();
// software cursors aren't available in tools
virtual void SetSoftwareCursor( bool bUseSoftwareCursor ) OVERRIDE {}
virtual void PaintSoftwareCursor() OVERRIDE {}
private:
CUtlDict< IImage *, unsigned short > m_FileTypeImages;
enum { BASE_HEIGHT = 480, BASE_WIDTH = 640 };
bool LoadTGA(Texture *texture, const char *filename);
bool LoadBMP(Texture *texture, const char *filename);
void InternalThinkTraverse(VPANEL panel);
void InternalSolveTraverse(VPANEL panel);
void InternalSchemeSettingsTraverse(VPANEL panel, bool forceApplySchemeSettings);
VPANEL GetContextPanelForChildPanel(VPANEL childPanel);
void initStaticData();
// sets the current line drawing color, called by DrawSetTextColor
void SetLineColor(Color col);
VPANEL _embeddedPanel; // main panel
VPANEL _notifyPanel;
VPANEL _currentContextPanel;
HTexture _notifyIcon;
Dar<VPANEL> _popupList; // list of panels that have their own win32 window
HICON _currentCursor;
OSVERSIONINFO m_WindowsVersion;
bool m_bSupportsUnicode;
CUtlVector<CUtlSymbol> m_CustomFontFileNames;
// current font info
HFont m_hCurrentFont;
CWin32Font *m_pActiveFont;
HPEN pen; // the pen used to draw lines
bool _needKB;
bool _needMouse;
int m_TextPos[2];
Texture *m_pCurrentTexture;
static bool TextureLessFunc(const Texture &lhs, const Texture &rhs);
Texture *GetTextureById(int id);
Texture *AllocTextureForId(int id);
int GetNumTextures();
CUtlRBTree<Texture, int> m_VGuiSurfaceTextures;
struct ScreenOverride_t
{
ScreenOverride_t() : m_bActive( false )
{
m_nValue[ 0 ] = m_nValue[ 1 ] = 0;
}
bool m_bActive;
int m_nValue[ 2 ];
};
ScreenOverride_t m_ScreenSizeOverride;
ScreenOverride_t m_ScreenPosOverride;
bool m_bAllowJavaScript;
int m_nFullscreenViewportX;
int m_nFullscreenViewportY;
int m_nFullscreenViewportWidth;
int m_nFullscreenViewportHeight;
ITexture *m_pFullscreenRenderTarget;
};
CWin32Surface g_Surface;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CWin32Surface, ISurface, VGUI_SURFACE_INTERFACE_VERSION, g_Surface);
//!! these defines duplicated in Surface_Win32.cpp
#define WM_MY_TRAY_NOTIFICATION (WM_USER+1)
static UINT staticShutdownMsg = 0;
static HICON staticDefaultCursor[20];
static WNDCLASS staticWndclass = { NULL };
static ATOM staticWndclassAtom = 0;
static bool staticStaticDataInitialized = false;
static bool staticSurfaceAvailable;
// these functions defined below
static LRESULT CALLBACK staticProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam);
static void staticNotifyIconProc(HWND hwnd, WPARAM wparam, LPARAM lparam);
#ifdef DEBUG_TIMING
#define START_TIMER() \
float paintTime;\
static LARGE_INTEGER ticksPerSecond = { 0 };\
if (!ticksPerSecond.QuadPart)\
{\
QueryPerformanceFrequency(&ticksPerSecond);\
}\
LARGE_INTEGER Start, end;\
QueryPerformanceCounter(&Start);
#define END_TIMER(x) \
QueryPerformanceCounter(&end);\
paintTime = (float)(((end.QuadPart - Start.QuadPart) * 1000000) / ticksPerSecond.QuadPart) / 1000;\
if (paintTime > 1.0f) Msg(x, paintTime);
#else
#define START_TIMER()
#define END_TIMER(x)
#endif // DEBUG_TIMING
//-----------------------------------------------------------------------------
// Purpose: Handles drag and drop
//-----------------------------------------------------------------------------
class CSurfaceDragDropTarget : public IDropTarget
{
public:
CSurfaceDragDropTarget()
{
_refCount = 0;
_dragData = NULL;
OleInitialize(NULL);
}
private:
unsigned int _refCount;
KeyValues *_dragData;
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{
if (riid == IID_IDropTarget)
{
*ppvObject = (IDropTarget *)this;
return S_OK;
}
return E_NOINTERFACE;
}
virtual ULONG STDMETHODCALLTYPE AddRef( void)
{
return ++_refCount;
}
virtual ULONG STDMETHODCALLTYPE Release( void)
{
return --_refCount;
}
virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
if (_dragData)
{
_dragData->deleteThis();
}
_dragData = calculateData(pDataObject);
return DragOver(grfKeyState, pt, pdwEffect);
}
virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
*pdwEffect = DROPEFFECT_NONE;
if (!_dragData || !g_pIVgui->IsRunning())
return S_OK;
// get the panel the mouse is over
VPANEL mouseOver = g_pInput->GetMouseOver();
if (mouseOver)
{
// check to see if the panel will accept this message
if (((VPanel *)mouseOver)->Client()->RequestInfo(_dragData))
{
*pdwEffect = DROPEFFECT_COPY;
}
}
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE DragLeave()
{
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
{
*pdwEffect = DROPEFFECT_NONE;
if (!_dragData || !g_pIVgui->IsRunning())
return S_OK;
// get the panel the mouse is over
VPANEL target = (VPANEL)_dragData->GetPtr("AcceptPanel");
if (target && _dragData)
{
// check to see if the panel will accept this message
g_pIVgui->PostMessage(target, _dragData, NULL);
_dragData = NULL;
}
if (_dragData)
{
_dragData->deleteThis();
}
_dragData = NULL;
return S_OK;
}
// internal methods
virtual KeyValues *calculateData(IDataObject *pDataObject)
{
KeyValues *dragData = NULL;
// check on the type of data
FORMATETC format =
{
CF_TEXT,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
STGMEDIUM storage;
if (pDataObject->GetData(&format, &storage) == S_OK)
{
// we got some data
if (storage.tymed == TYMED_HGLOBAL)
{
const char *buf = (const char *)GlobalLock(storage.hGlobal);
dragData = new KeyValues("DragDrop", "type", "text", "text", buf);
GlobalUnlock(storage.hGlobal);
}
ReleaseStgMedium(&storage);
}
else
{
// try getting a file
format.cfFormat = CF_HDROP;
if (pDataObject->GetData(&format, &storage) == S_OK && storage.tymed == TYMED_HGLOBAL)
{
dragData = new KeyValues("DragDrop", "type", "files");
KeyValues *fileList = dragData->FindKey("list", true);
// parse out the file list
HDROP hdrop = (HDROP)GlobalLock(storage.hGlobal);
char namebuf[32], buf[512];
int count = DragQueryFile(hdrop, 0xFFFFFFFF, buf, 511);
for (int i = 0; i < count; i++)
{
Q_snprintf(namebuf, sizeof( namebuf ), "%d", i);
DragQueryFile(hdrop, i, buf, 511);
fileList->SetString(namebuf, buf);
}
GlobalUnlock(storage.hGlobal);
}
}
return dragData;
}
};
static CSurfaceDragDropTarget staticDragDropTarget;
bool CWin32Surface::TextureLessFunc(const Texture &lhs, const Texture &rhs)
{
return lhs._id < rhs._id;
}
Texture *CWin32Surface::GetTextureById(int id)
{
Texture findTex = { id };
int index = m_VGuiSurfaceTextures.Find(findTex);
if (m_VGuiSurfaceTextures.IsValidIndex(index))
{
return &m_VGuiSurfaceTextures[index];
}
return NULL;
}
Texture *CWin32Surface::AllocTextureForId(int id)
{
Texture newTex = { id };
int index = m_VGuiSurfaceTextures.Insert(newTex);
return &m_VGuiSurfaceTextures[index];
}
int CWin32Surface::GetNumTextures()
{
return m_VGuiSurfaceTextures.Count();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
static void staticGenerateIconForTexture(Texture *texture, HDC hdc)
{
// see if there is an iconic version of the texture file first
char buf[256];
Q_snprintf(buf, sizeof( buf ), "%s.ico", texture->_filename);
texture->_icon = (HICON)::LoadImage(NULL, buf, IMAGE_ICON, 16, 16, LR_LOADFROMFILE | LR_DEFAULTSIZE);
if (texture->_icon)
return;
if (texture->_wide > 32 || texture->_tall > 32)
return;
// generate an icon from the tga
// generate the AND plane based on the alpha
uchar planeAND[32 * 32 / 8];
/* !! disabled until verified
//
// from the alpha of the bitmap, generate a bitmask
//
uchar *ptr = (uchar *)texture->_dib + 3; // jump to alpha portion
uchar *ptrEnd = (uchar *)texture->_dib + (texture->_wide * texture->_tall * 4);
uchar *andPtr = planeAND;
while (ptr < ptrEnd)
{
// Start all empty
*andPtr = 0;
// assume the number of pixel is a multiple of 8
// if the alpha is high enough, then mask out the pixel
// it's two bits per pixel, strangely enough
if (*ptr > 127) { *andPtr |= 0x03; } ptr += 4;
if (*ptr > 127) { *andPtr |= 0x0C; } ptr += 4;
if (*ptr > 127) { *andPtr |= 0x30; } ptr += 4;
if (*ptr > 127) { *andPtr |= 0xC0; } ptr += 4;
andPtr++;
}
*/
memset(planeAND, 0x00, sizeof(planeAND));
HBITMAP mask = ::CreateBitmap(texture->_wide, texture->_tall, 1, 1, planeAND);
// create the icon
ICONINFO iconInfo;
iconInfo.fIcon = TRUE;
iconInfo.xHotspot = 8;
iconInfo.yHotspot = 8;
iconInfo.hbmMask = mask;
iconInfo.hbmColor = texture->_bitmap;
texture->_icon = ::CreateIconIndirect(&iconInfo);
::DeleteObject(mask);
}
//-----------------------------------------------------------------------------
// Purpose: Constructor, basic variable initialization
//-----------------------------------------------------------------------------
CWin32Surface::CWin32Surface() : m_VGuiSurfaceTextures(0, 128, TextureLessFunc)
{
_currentCursor = NULL;
m_pCurrentTexture = NULL;
initStaticData();
staticSurfaceAvailable = false;
m_bAllowJavaScript = false;
m_hCurrentFont = 0;
pen = NULL;
_needKB = true;
_needMouse = true;
HRESULT hr;
// this step is IMPORTANT , it turns "on" COM
if (FAILED(hr = CoInitialize(NULL)))
{
// failed
}
// get our version info
m_WindowsVersion.dwOSVersionInfoSize = sizeof(m_WindowsVersion);
GetVersionEx(&m_WindowsVersion);
if (m_WindowsVersion.dwMajorVersion >= 5)
{
m_bSupportsUnicode = true;
}
else
{
m_bSupportsUnicode = false;
}
m_TextPos[0] = m_TextPos[1] = 0;
m_nFullscreenViewportX = m_nFullscreenViewportY = 0;
m_nFullscreenViewportWidth = m_nFullscreenViewportHeight = 0;
m_pFullscreenRenderTarget = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CWin32Surface::~CWin32Surface()
{
// ensure we don't try and process any more windows messages
staticSurfaceAvailable = false;
// free all the textures
for (int i = 0; i < m_VGuiSurfaceTextures.MaxElement(); i++)
{
if (!m_VGuiSurfaceTextures.IsValidIndex(i))
continue;
Texture *texture = &m_VGuiSurfaceTextures[i];
if (texture->_bitmap)
{
::DeleteObject(texture->_bitmap);
}
if (texture->_maskBitmap)
{
::DeleteObject(texture->_maskBitmap);
}
if (texture->_icon)
{
::DestroyIcon(texture->_icon);
}
}
CoUninitialize(); // turn com off
}
//-----------------------------------------------------------------------------
// Purpose: Shuts down app
//-----------------------------------------------------------------------------
void CWin32Surface::Shutdown()
{
for ( int i = m_FileTypeImages.First(); i != m_FileTypeImages.InvalidIndex(); i = m_FileTypeImages.Next( i ) )
{
delete m_FileTypeImages[ i ];
}
m_FileTypeImages.RemoveAll();
// free the fonts
FontManager().ClearAllFonts();
// release any custom font files
{for (int i = 0; i < m_CustomFontFileNames.Count(); i++)
{
::RemoveFontResource(m_CustomFontFileNames[i].String());
}}
m_CustomFontFileNames.RemoveAll();
// ensure we don't try and process windows messages during Shutdown
staticSurfaceAvailable = false;
// release any panels still with surfaces
while (GetPopupCount())
{
ReleasePanel(GetPopup(0));
}
// kill our windows instance
::UnregisterClass("Surface", ::GetModuleHandle(NULL));
staticWndclassAtom = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
VPANEL CWin32Surface::GetEmbeddedPanel()
{
return _embeddedPanel;
}
// SRC specific interfaces
void CWin32Surface::DrawTexturedLine( const Vertex_t &a, const Vertex_t &b )
{
}
void CWin32Surface::DrawOutlinedCircle(int x, int y, int radius, int segments)
{
}
void CWin32Surface::DrawTexturedPolyLine( const Vertex_t *p,int n )
{
}
void CWin32Surface::DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 )
{
}
void CWin32Surface::DrawTexturedPolygon(int n, Vertex_t *pVertices, bool bClipVertices /*= true*/)
{
NOTE_UNUSED( bClipVertices );
POINT *pt;
HDC hdc = PLAT(_currentContextPanel)->hdc;
pt = (POINT *)malloc(sizeof(POINT) * n);
if(pt)
{
for(int i=0;i<n;i++)
{
pt[i].x= pVertices[i].m_Position.x;
pt[i].y= pVertices[i].m_Position.y;
}
COLORREF pencolor = ::GetTextColor(hdc);
COLORREF brushcolor = ::GetBkColor(hdc);
//Set the pen color to the current brush color to avoid strange outlines on our polygons
DrawSetTextColor(GetRValue(brushcolor),GetGValue(brushcolor),GetBValue(brushcolor),255);
//create a brush
HBRUSH hbrush = ::CreateSolidBrush(brushcolor);
HBRUSH oldBrush = (HBRUSH)::SelectObject(hdc, hbrush);
::Polygon(hdc, pt, n);
::SelectObject(hdc, oldBrush);
::DeleteObject(hbrush);
free(pt);
//restore pen colour
DrawSetTextColor(GetRValue(pencolor),GetGValue(pencolor),GetBValue(pencolor),255);
}
}
const wchar_t *CWin32Surface::GetTitle(VPANEL panel)
{
return L"";
}
void CWin32Surface::LockCursor( bool state )
{
}
bool CWin32Surface::IsCursorLocked( void ) const
{
return false;
}
void CWin32Surface::SetWorkspaceInsets( int left, int top, int right, int bottom )
{
}
//-----------------------------------------------------------------------------
// Connect, disconnect...
//-----------------------------------------------------------------------------
bool CWin32Surface::Connect( CreateInterfaceFn factory )
{
return true;
}
void CWin32Surface::Disconnect()
{
}
//-----------------------------------------------------------------------------
// Access to other interfaces...
//-----------------------------------------------------------------------------
void *CWin32Surface::QueryInterface( const char *pInterfaceName )
{
return NULL;
}
//-----------------------------------------------------------------------------
// Initialization and shutdown...
//-----------------------------------------------------------------------------
InitReturnVal_t CWin32Surface::Init( void )
{
return INIT_FAILED;
}
//-----------------------------------------------------------------------------
// Purpose: Sets up the panel for use
// Input : *embeddedPanel - Main panel that becomes the top of the hierarchy
//-----------------------------------------------------------------------------
void CWin32Surface::SetEmbeddedPanel( VPANEL panel )
{
_embeddedPanel = panel;
staticSurfaceAvailable = true;
SetCurrentContextPanel(panel);
CreatePopup(panel, false, true, false, true, true);
// send a message to ourselves every 50ms (20Hz) so that we don't block in the message queue too long
::SetTimer(PLAT(_currentContextPanel)->hwnd, 0, 50, (TIMERPROC) NULL);
// fonts initialization
char language[64];
if (g_pSystem->GetRegistryString("HKEY_CURRENT_USER\\Software\\Valve\\Source\\Language", language, sizeof(language)-1))
{
FontManager().SetLanguage(language);
}
else
{
FontManager().SetLanguage("english");
}
}
// Lower level char drawing code, call DrawGet then pass in info to DrawRender
bool CWin32Surface::DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info )
{
// Only supported in engine renderer!
Assert( 0 );
info.valid = false;
return false;
}
void CWin32Surface::DrawRenderCharFromInfo( const CharRenderInfo& info )
{
Assert( 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Sets the current drawing context
//-----------------------------------------------------------------------------
void CWin32Surface::SetCurrentContextPanel(VPANEL panel)
{
_currentContextPanel = panel;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
VPANEL CWin32Surface::GetContextPanelForChildPanel(VPANEL childPanel)
{
VPANEL contextPanel = childPanel;
while (contextPanel && !PLAT(contextPanel))
{
contextPanel = (VPANEL)((VPanel *)contextPanel)->GetParent();
}
return contextPanel;
}
// static currently used win32 Paint info
static ::PAINTSTRUCT s_CurrentPaintStruct;
void CWin32Surface::PushMakeCurrent(VPANEL panel, bool useInsets)
{
// find the win32 window context from the hierarchy
VPANEL currentContextPanel = GetContextPanelForChildPanel(panel);
SetCurrentContextPanel(currentContextPanel);
// clear the current active font so that it will be reset
m_pActiveFont = NULL;
if (!currentContextPanel)
{
// no drawing context found, something is seriously wrong
Msg( "Warning: VPanel with no drawing context\n" );
}
int inset[4];
//!! need to make the inset part of VPanel
((VPanel *)panel)->Client()->GetInset(inset[0],inset[1],inset[2],inset[3]);
if(!useInsets)
{
inset[0]=0;
inset[1]=0;
inset[2]=0;
inset[3]=0;
}
int absThis[4];
((VPanel *)_currentContextPanel)->GetAbsPos(absThis[0], absThis[1]);
((VPanel *)_currentContextPanel)->GetSize(absThis[2], absThis[3]);
absThis[2] += absThis[0];
absThis[3] += absThis[1];
int absPanel[4];
((VPanel *)panel)->GetAbsPos(absPanel[0], absPanel[1]);
((VPanel *)panel)->GetSize(absPanel[2], absPanel[3]);
absPanel[2] += absPanel[0];
absPanel[3] += absPanel[1];
int clipRect[4];
((VPanel *)panel)->Client()->GetClipRect(clipRect[0],clipRect[1],clipRect[2],clipRect[3]);
if ( _currentContextPanel == panel )
{
// this panel has it's own window, so use screen space
::SetViewportOrgEx(PLAT(_currentContextPanel)->hdc,0+inset[0],0+inset[1],null);
}
else
{
// child window, so set win32 up so all subsequent drawing calls are done in local space
::SetViewportOrgEx(PLAT(_currentContextPanel)->hdc,(absPanel[0]+inset[0])-absThis[0],(absPanel[1]+inset[1])-absThis[1],null);
}
// setup clipping
// get and translate clipRect into surface space, then factor in inset
int x0 = clipRect[0] - absThis[0];
int y0 = clipRect[1] - absThis[1];
int x1 = (clipRect[2] - absThis[0]) - inset[2];
int y1 = (clipRect[3] - absThis[1]) - inset[3];
//set the rect and select to make it current
::SetRectRgn(PLAT(_currentContextPanel)->clipRgn,x0,y0,x1,y1);
::SelectObject(PLAT(_currentContextPanel)->hdc, PLAT(_currentContextPanel)->clipRgn);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::PopMakeCurrent(VPANEL panel)
{
if (panel == _currentContextPanel)
{
// reset the current panel to be the main panel
SetCurrentContextPanel(_embeddedPanel);
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::GetScreenSize(int &wide, int &tall)
{
if ( m_ScreenSizeOverride.m_bActive )
{
wide = m_ScreenSizeOverride.m_nValue[ 0 ];
tall = m_ScreenSizeOverride.m_nValue[ 1 ];
return;
}
VPANEL context = _embeddedPanel;
if (context)
{
wide = ::GetDeviceCaps(PLAT(context)->hdc, HORZRES);
tall = ::GetDeviceCaps(PLAT(context)->hdc, VERTRES);
}
}
bool CWin32Surface::ForceScreenSizeOverride( bool bState, int wide, int tall )
{
bool bWasSet = m_ScreenSizeOverride.m_bActive;
m_ScreenSizeOverride.m_bActive = bState;
m_ScreenSizeOverride.m_nValue[ 0 ] = wide;
m_ScreenSizeOverride.m_nValue[ 1 ] = tall;
return bWasSet;
}
// LocalToScreen, ParentLocalToScreen fixups for explicit PaintTraverse calls on Panels not at 0, 0 position
bool CWin32Surface::ForceScreenPosOffset( bool bState, int x, int y )
{
bool bWasSet = m_ScreenPosOverride.m_bActive;
m_ScreenPosOverride.m_bActive = bState;
m_ScreenPosOverride.m_nValue[ 0 ] = x;
m_ScreenPosOverride.m_nValue[ 1 ] = y;
return bWasSet;
}
void CWin32Surface::OffsetAbsPos( int &x, int &y )
{
if ( !m_ScreenPosOverride.m_bActive )
return;
x += m_ScreenPosOverride.m_nValue[ 0 ];
y += m_ScreenPosOverride.m_nValue[ 1 ];
}
bool CWin32Surface::IsScreenSizeOverrideActive( void )
{
return ( m_ScreenSizeOverride.m_bActive );
}
bool CWin32Surface::IsScreenPosOverrideActive( void )
{
return ( m_ScreenPosOverride.m_bActive );
}
void CWin32Surface::DestroyTextureID( int id )
{
// not implemented
}
int CWin32Surface::GetTextureNumFrames( int id )
{
// not implemented
return 0;
}
void CWin32Surface::DrawSetTextureFrame( int id, int nFrame, unsigned int *pFrameCache )
{
// not implemented
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
VPANEL CWin32Surface::GetNotifyPanel()
{
return _notifyPanel;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::SetNotifyIcon(VPANEL context, HTexture iconID, VPANEL panelToReceiveMessages, const char *text)
{
context = GetContextPanelForChildPanel(context);
if (!context)
return;
if (!text)
{
text = "";
}
// things haven't changed so just update the tooltip
if (_notifyIcon == iconID && _notifyPanel == panelToReceiveMessages && context && PLAT(context)->notifyIcon)
{
::NOTIFYICONDATA iconData =
{
sizeof(iconData),
PLAT(context)->hwnd,
1, // icon ID
NIF_TIP, // modify tooltip only
WM_MY_TRAY_NOTIFICATION, // callback message
PLAT(context)->notifyIcon, // icon handle
"", // tooltip text
};
strncpy(iconData.szTip, text, 63);
iconData.szTip[63] = '\0';
::Shell_NotifyIcon(NIM_MODIFY, &iconData);
return;
}
_notifyIcon = iconID;
_notifyPanel = panelToReceiveMessages;
DWORD dwMessage = NIM_MODIFY;
if (!iconID)
{
dwMessage = NIM_DELETE;
PLAT(context)->notifyIcon = NULL;
}
else if (!PLAT(context)->notifyIcon)
{
dwMessage = NIM_ADD;
}
// make sure the icon has been loaded
Texture *texture = NULL;
if (iconID)
{
texture = GetTextureById(iconID);
if (!texture->_icon)
{
// generate an icon for the texture
staticGenerateIconForTexture(texture, PLAT(_currentContextPanel)->hdc);
}
}
// get the icon
if (texture)
{
PLAT(context)->notifyIcon = texture->_icon;
}
::NOTIFYICONDATA iconData =
{
sizeof(iconData),
PLAT(context)->hwnd,
1, // icon ID
NIF_ICON | NIF_TIP | NIF_MESSAGE, // items used
WM_MY_TRAY_NOTIFICATION, // callback message
PLAT(context)->notifyIcon, // icon handle
"", // tooltip text
};
strncpy(iconData.szTip, text, 63);
iconData.szTip[63] = '\0';
BOOL success = ::Shell_NotifyIcon(dwMessage, &iconData);
if (iconID && !success)
{
DWORD err = GetLastError();
Msg("error: SetNotifyIcon(%d) failed\n", err);
}
}
void CWin32Surface::DrawSetColor(int r,int g,int b,int a)
{
SetBkColor(PLAT(_currentContextPanel)->hdc,RGB(r,g,b));
}
void CWin32Surface::DrawSetColor(Color col)
{
DrawSetColor(col[0], col[1], col[2], col[3]);
}
void CWin32Surface::DrawSetTextPos(int x, int y)
{
MoveToEx(PLAT(_currentContextPanel)->hdc,x,y,null);
m_TextPos[0] = x;
m_TextPos[1] = y;
}
void CWin32Surface::DrawGetTextPos(int& x,int& y)
{
x = m_TextPos[0];
y = m_TextPos[1];
}
void CWin32Surface::DrawSetTextFont(HFont font)
{
Assert(font);
// make the font current
m_hCurrentFont = font;
// m_FontAmalgams[m_hCurrentFont].GetFontForChar('a')->SetAsActiveFont(_currentContextPanel->Plat()->hdc);
}
void CWin32Surface::DrawFilledRect(int x0,int y0,int x1,int y1)
{
// trick to draw filled rectangles using current background color
RECT rect = { x0, y0, x1, y1};
ExtTextOut(PLAT(_currentContextPanel)->hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
}
void CWin32Surface::DrawFilledRectArray( IntRect *pRects, int numRects )
{
int i;
for( i = 0; i < numRects; i++ )
{
DrawFilledRect( pRects[i].x0, pRects[i].y0, pRects[i].x1, pRects[i].y1 );
}
}
void CWin32Surface::DrawOutlinedRect(int x0,int y0,int x1,int y1)
{
// draw an outline of a rectangle using 4 filledRect
DrawFilledRect(x0,y0,x1,y0+1); // top
DrawFilledRect(x0,y1-1,x1,y1); // bottom
DrawFilledRect(x0,y0+1,x0+1,y1-1); // left
DrawFilledRect(x1-1,y0+1,x1,y1-1); // right
}
void CWin32Surface::DrawLine(int x0,int y0,int x1,int y1)
{
POINT pt[2];
CONST POINT *p=pt;
pt[0].x=x0;
pt[0].y=y0;
pt[1].x=x1;
pt[1].y=y1;
// MoveToEx(_currentContextPanel->Plat()->hdc,x0,y0,NULL);
// LineTo(_currentContextPanel->Plat()->hdc,x1,y1);
Polyline(PLAT(_currentContextPanel)->hdc,p , 2);
}
void CWin32Surface::DrawPolyLine(int *px, int *py, int numPoints)
{
POINT *pt;
pt = (POINT *)malloc(sizeof(POINT) * numPoints);
if(pt)
{
for(int i=0;i<numPoints;i++)
{
pt[i].x= px[i];
pt[i].y= py[i];
}
Polyline(PLAT(_currentContextPanel)->hdc, pt , numPoints);
free(pt);
}
}
void CWin32Surface::DrawSetTextColor(int r,int g,int b,int a)
{
// set the draw color for lines
SetLineColor(Color(r,g,b,a));
SetTextColor(PLAT(_currentContextPanel)->hdc,RGB(r,g,b));
}
void CWin32Surface::DrawSetTextColor(Color col)
{
// set the draw color for lines
SetLineColor(col);
// end then for text
DrawSetTextColor(col[0], col[1], col[2], col[3]);
}
void CWin32Surface::SetLineColor(Color col)
{
HPEN tmp=pen;
pen = CreatePen(PS_SOLID,0,RGB(col[0], col[1], col[2]));
if(pen)
{
SelectObject(PLAT(_currentContextPanel)->hdc, pen );
}
// you must delete the pen AFTER a new one is selected
if(tmp)
{
DeleteObject(tmp);
}
}
void CWin32Surface::DrawPrintText(const wchar_t *text, int textLen, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT*/)
{
Assert(text);
if (!text)
return;
if (textLen < 1)
return;
for (int i = 0; i < textLen; i++)
{
DrawUnicodeChar(text[i]);
}
// ExtTextOut(_currentContextPanel->Plat()->hdc, 0, 0, 0, NULL, text, textLen, NULL);
}
void CWin32Surface::DrawUnicodeString( const wchar_t *pwString, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT*/)
{
Assert( pwString );
if ( !pwString )
return;
while ( wchar_t ch = *pwString++ )
{
DrawUnicodeChar( ch );
}
}
//-----------------------------------------------------------------------------
// Purpose: draws single unicode character at the current position with the
// current font & color
//-----------------------------------------------------------------------------
void CWin32Surface::DrawUnicodeChar(wchar_t wch, FontDrawType_t drawType /*= FONT_DRAW_DEFAULT*/)
{
// set the current font
CWin32Font *winFont = FontManager().GetFontForChar(m_hCurrentFont, wch);
if (!winFont)
return;
if (m_pActiveFont != winFont)
{
winFont->SetAsActiveFont(PLAT(_currentContextPanel)->hdc);
m_pActiveFont = winFont;
}
if (m_bSupportsUnicode)
{
ExtTextOutW(PLAT(_currentContextPanel)->hdc, 0, 0, 0, NULL, &wch, 1, NULL);
}
else
{
char mbcs[6] = { 0 };
::WideCharToMultiByte(CP_ACP, 0, &wch, 1, mbcs, sizeof(mbcs), NULL, NULL);
ExtTextOutA(PLAT(_currentContextPanel)->hdc, 0, 0, 0, NULL, mbcs, strlen(mbcs), NULL);
}
}
//-----------------------------------------------------------------------------
// Purpose: allocates a new texture id
//-----------------------------------------------------------------------------
int CWin32Surface::CreateNewTextureID( bool procedural )
{
//!! hack, arbitrary base
static int staticBindIndex = 2700;
return staticBindIndex++;
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the texture id has a valid texture bound to it
//-----------------------------------------------------------------------------
bool CWin32Surface::IsTextureIDValid(int id)
{
return (GetTextureById(id) != NULL);
}
//-----------------------------------------------------------------------------
// Purpose: clear up alloced resources on a texture
//-----------------------------------------------------------------------------
void CWin32Surface::FreeTextureData( vgui::Texture *pTexture )
{
if ( pTexture->_bitmap )
{
::DeleteObject( pTexture->_bitmap );
}
// if ( pTexture->m_bitmapScaled )
// {
// ::DeleteObject( pTexture->m_bitmapScaled );
// }
if ( pTexture->_maskBitmap )
{
::DeleteObject( pTexture->_maskBitmap );
}
if ( pTexture->_icon )
{
::DestroyIcon( pTexture->_icon );
}
// if ( pTexture->rgba )
// delete[] pTexture->rgba;
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the texture id has a valid texture bound to it
//-----------------------------------------------------------------------------
bool CWin32Surface::DeleteTextureByID(int id)
{
#if defined( PS3OVERLAYUI_EXPORTS )
AUTO_LOCK( m_MutexTextureData );
#endif
Texture findTex = { id };
int index = m_VGuiSurfaceTextures.Find(findTex);
if (m_VGuiSurfaceTextures.IsValidIndex(index))
{
Texture *texture = &m_VGuiSurfaceTextures[index];
FreeTextureData( texture );
m_VGuiSurfaceTextures.RemoveAt(index);
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: does nothing, since we don't need this optimization in win32
//-----------------------------------------------------------------------------
void CWin32Surface::DrawFlushText()
{
}
//-----------------------------------------------------------------------------
// Purpose: create a html helper object
//-----------------------------------------------------------------------------
IHTML *CWin32Surface::CreateHTMLWindow(vgui::IHTMLEvents *events, VPANEL context )
{
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: delete an html helper object
//-----------------------------------------------------------------------------
void CWin32Surface::DeleteHTMLWindow(IHTML *htmlwin)
{
}
//-----------------------------------------------------------------------------
// Purpose: tell a html window to update its backing texture
//-----------------------------------------------------------------------------
void CWin32Surface::PaintHTMLWindow(IHTML *htmlwin)
{
}
//-----------------------------------------------------------------------------
void CWin32Surface::SetAllowHTMLJavaScript( bool state )
{
}
//-----------------------------------------------------------------------------
// Purpose: sets the current active texture
//-----------------------------------------------------------------------------
void CWin32Surface::DrawSetTexture(int id)
{
Texture *texture = GetTextureById(id);
m_pCurrentTexture = texture;
}
HBITMAP staticCreateBitmapHandle(int wide, int tall, HDC hdc, int bpp, void **dib);
//-----------------------------------------------------------------------------
// Purpose: maps a texture from memory to an id, and uploads it into the engine
//-----------------------------------------------------------------------------
void CWin32Surface::DrawSetTextureRGBA(int id,const unsigned char* rgba,int wide,int tall, int hardwareFilter, bool forceReload)
{
DrawSetTextureRGBAEx( id, rgba, wide, tall, IMAGE_FORMAT_RGBA8888 );
}
//-----------------------------------------------------------------------------
// Purpose: maps a texture from memory to an id, and uploads it into the engine
//-----------------------------------------------------------------------------
void CWin32Surface::DrawSetTextureRGBAEx(int id,const unsigned char* rgba,int wide,int tall, ImageFormat imageFormat )
{
Texture *texture = GetTextureById(id);
if (texture)
{
if (texture->_bitmap)
{
::DeleteObject(texture->_bitmap);
}
if (texture->_maskBitmap)
{
::DeleteObject(texture->_maskBitmap);
}
}
if (!texture)
{
// allocate a new texture
texture = AllocTextureForId(id);
memset(texture, 0, sizeof(Texture));
}
{
// no texture or forced load the new texture
texture->_id = id;
texture->_filename =NULL;
texture->_wide = wide;
texture->_tall = tall;
texture->_icon = NULL;
texture->_dib = NULL;
texture->_bitmap = staticCreateBitmapHandle(texture->_wide,
texture->_tall, PLAT(_currentContextPanel)->hdc, 32, &texture->_dib );
// copy over the texture data
memcpy(texture->_dib,rgba,wide*tall*4);
}
m_pCurrentTexture = texture;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : id -
// *filename -
// maxlen -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWin32Surface::DrawGetTextureFile(int id, char *filename, int maxlen )
{
Texture *texture = GetTextureById(id);
if ( !texture )
return false;
Q_strncpy( filename, texture->_filename, maxlen );
return true;
}
int CWin32Surface::DrawGetTextureId( char const *filename )
{
int i = m_VGuiSurfaceTextures.FirstInorder();
while ( i != m_VGuiSurfaceTextures.InvalidIndex() )
{
Texture *texture = &m_VGuiSurfaceTextures[i];
if ( !Q_stricmp( filename, texture->_filename ) )
return texture->_id;
i = m_VGuiSurfaceTextures.NextInorder( i );
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose: Maps a texture file to an id, and makes it the current drawing texture
// tries to load as a .tga first, and if not found as a .bmp
//-----------------------------------------------------------------------------
void CWin32Surface::DrawSetTextureFile(int id, const char *filename, int hardwareFilter, bool forceReload /*= false*/)
{
Texture *texture = GetTextureById(id);
if (!texture || stricmp(filename, texture->_filename) || forceReload )
{
// no texture, or the filename is different; load the new texture
if (!texture)
{
// allocate a new texture
texture = AllocTextureForId(id);
memset(texture, 0, sizeof(Texture));
}
if (texture)
{
if (texture->_bitmap)
{
::DeleteObject(texture->_bitmap);
}
if (texture->_maskBitmap)
{
::DeleteObject(texture->_maskBitmap);
}
}
texture->_id = id;
texture->_filename = filename;
// try and find the file
bool success = LoadTGA(texture, filename);
if (!success)
{
// strip off the vgui/ and try again
const char *psz = Q_stristr(filename, "vgui/");
if (psz)
{
success = LoadTGA(texture, filename + strlen("vgui/"));
}
}
if (!success)
{
Msg("Error: texture file '%s' does not exist or is invalid\n", filename);
return;
}
}
m_pCurrentTexture = texture;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::DrawTexturedRect(int x0,int y0,int x1,int y1)
{
if (m_pCurrentTexture == null)
{
return;
}
if (PLAT(_currentContextPanel)->textureDC == null)
{
return;
}
HBITMAP bitmap = m_pCurrentTexture->_bitmap;
int wide = m_pCurrentTexture->_wide;
int tall = m_pCurrentTexture->_tall;
HGDIOBJ oldObject;
if (m_pCurrentTexture->_bMask)
{
HBITMAP bitmap_mask = m_pCurrentTexture->_maskBitmap;
// draw the mask first to clear out the background to black
oldObject = ::SelectObject(PLAT(_currentContextPanel)->textureDC, bitmap_mask);
::StretchBlt(PLAT(_currentContextPanel)->hdc,x0,y0,x1-x0,y1-y0,PLAT(_currentContextPanel)->textureDC,0,0,wide,tall,SRCAND);
// draw over the 'black areas' with the bitmap
::SelectObject(PLAT(_currentContextPanel)->textureDC, bitmap);
::StretchBlt(PLAT(_currentContextPanel)->hdc,x0,y0,x1-x0,y1-y0,PLAT(_currentContextPanel)->textureDC,0,0,wide,tall,SRCPAINT);
}
else
{
oldObject = ::SelectObject(PLAT(_currentContextPanel)->textureDC, bitmap);
::StretchBlt(PLAT(_currentContextPanel)->hdc,x0,y0,x1-x0,y1-y0,PLAT(_currentContextPanel)->textureDC,0,0,wide,tall,SRCCOPY);
}
::SelectObject(PLAT(_currentContextPanel)->textureDC, oldObject);
// test code, should be used in win98/win2k for true alpha
// BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 255, 0 };
// ::AlphaBlend(PLAT(_currentContextPanel)->hdc,x0,y0,x1-x0,y1-y0,PLAT(_currentContextPanel)->textureDC,0,0,wide,tall,blendFunction);
}
//-----------------------------------------------------------------------------
// Purpose: Called by vgui to get texture dimensions
//-----------------------------------------------------------------------------
void CWin32Surface::DrawGetTextureSize(int id, int &wide, int &tall)
{
Texture *texture = GetTextureById(id);
if (!texture)
return;
wide = texture->_wide;
tall = texture->_tall;
}
#pragma pack(1)
typedef struct
{
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
} tga_header_t;
#pragma pack()
HBITMAP staticCreateBitmapHandle(int wide, int tall, HDC hdc, int bpp, void **dib)
{
BITMAPINFOHEADER bitmapInfoHeader;
memset(&bitmapInfoHeader, 0, sizeof(bitmapInfoHeader));
bitmapInfoHeader.biSize = sizeof(bitmapInfoHeader);
bitmapInfoHeader.biWidth = wide;
bitmapInfoHeader.biHeight = -tall;
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = bpp;
bitmapInfoHeader.biCompression = BI_RGB;
HBITMAP hRet;
hRet = CreateDIBSection(hdc, (BITMAPINFO*)&bitmapInfoHeader, DIB_RGB_COLORS, dib, 0, 0);
if ( !hRet )
Error( "staticCreateBitmapHandle: can't create DIB" );
return hRet;
}
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWin32Surface::LoadBMP(Texture *texture, const char *filename)
{
// try load the tga
char buf[1024];
_snprintf(buf, sizeof(buf), "%s.bmp", filename);
FileHandle_t file = g_pFullFileSystem->Open(buf, "rb", NULL);
if (!file)
return false;
bool success = false;
// Parse bitmap
BITMAPFILEHEADER bmfHeader;
DWORD dwBitsSize, dwFileSize;
LPBITMAPINFO lpbmi;
dwFileSize = g_pFullFileSystem->Size( file );
g_pFullFileSystem->Read( &bmfHeader, sizeof(bmfHeader), file );
if (bmfHeader.bfType == DIB_HEADER_MARKER)
{
dwBitsSize = dwFileSize - sizeof(bmfHeader);
HGLOBAL hDIB = ::GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize );
char *pDIB = (LPSTR)::GlobalLock((HGLOBAL)hDIB);
{
int i, j;
g_pFullFileSystem->Read(pDIB, dwBitsSize, file );
lpbmi = (LPBITMAPINFO)pDIB;
// we now have a block of memory, rgba
// throw a bitmap header on it and register it in windows
texture->_wide = lpbmi->bmiHeader.biWidth;
texture->_tall = lpbmi->bmiHeader.biHeight;
texture->_icon = NULL;
texture->_bMask = false;
texture->_bitmap = staticCreateBitmapHandle(
texture->_wide,
texture->_tall,
PLAT(_currentContextPanel)->hdc,
32, &texture->_dib );
unsigned char *rgba = (unsigned char *)( pDIB + sizeof( BITMAPINFOHEADER ) + 256 * sizeof( RGBQUAD ) );
// Copy raw data
for (j = 0; j < texture->_tall; j++)
{
for (i = 0; i <texture->_wide; i++)
{
int y = (texture->_tall - j - 1);
int offs = ( y * texture->_wide + i);
int offsdest = (j * texture->_wide + i) * 4;
unsigned char *src = ((unsigned char *)rgba) + offs;
char *dst = ((char*)texture->_dib) + offsdest;
dst[0] = lpbmi->bmiColors[ *src ].rgbRed;
dst[1] = lpbmi->bmiColors[ *src ].rgbGreen;
dst[2] = lpbmi->bmiColors[ *src ].rgbBlue;
dst[3] = (unsigned char)255;
}
}
success = true;
}
::GlobalUnlock( hDIB);
::GlobalFree((HGLOBAL) hDIB);
}
g_pFullFileSystem->Close(file);
return success;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWin32Surface::LoadTGA(Texture *texture, const char *filename)
{
bool invertAlpha = false;
// try load the tga
char buf[1024];
_snprintf(buf, sizeof(buf), "%s.tga", filename);
FileHandle_t file = g_pFullFileSystem->Open(buf, "rb", NULL);
if (!file)
{
return LoadBMP( texture, filename );
}
// read the header
tga_header_t tgaHeader;
g_pFullFileSystem->Read(&tgaHeader, sizeof(tgaHeader), file);
if (tgaHeader.image_type != 2 && tgaHeader.image_type != 10)
{
g_pIVgui->DPrintf2("Error: texture file '%s' has invalid image_type %d\n", filename, tgaHeader.image_type);
return false;
}
if (tgaHeader.colormap_type != 0)
{
return false;
}
if (tgaHeader.pixel_size != 24 && tgaHeader.pixel_size !=32)
{
return false;
}
if (tgaHeader.id_length != 0)
{
g_pFullFileSystem->Seek( file, tgaHeader.id_length, FILESYSTEM_SEEK_CURRENT );
}
// allocate memory for the destination
uchar *rgba = (unsigned char *)malloc(tgaHeader.width * tgaHeader.height * 4);
int column, row;
uchar *ptr;
bool bMask = false;
if (tgaHeader.image_type == 2)
{
for (row = tgaHeader.height - 1; row >= 0; row--)
{
ptr = ((uchar *)rgba) + (row * tgaHeader.width * 4);
for (column = 0; column < tgaHeader.width; column++)
{
switch (tgaHeader.pixel_size)
{
case 24:
{
g_pFullFileSystem->Read(ptr + 2, 1, file);
g_pFullFileSystem->Read(ptr + 1, 1, file);
g_pFullFileSystem->Read(ptr + 0, 1, file);
ptr[3] = 255;
if (invertAlpha)
{
ptr[3] = 0;
}
ptr += 4;
break;
}
case 32:
{
g_pFullFileSystem->Read(ptr + 2, 1, file);
g_pFullFileSystem->Read(ptr + 1, 1, file);
g_pFullFileSystem->Read(ptr + 0, 1, file);
g_pFullFileSystem->Read(ptr + 3, 1, file);
if (!invertAlpha)
{
// if it's 0, then it's going to be zeroed out
if (ptr[3] == 0)
{
ptr[3] = 255;
}
else
{
// anything besides 0 will be shown
ptr[3] = 0;
}
//ptr[3] = 255 - ptr[3];
}
bMask = true;
ptr += 4;
break;
}
}
}
}
}
else
{
uchar packetHeader, packetSize, j, color[4];
for(row = tgaHeader.height - 1; row >= 0; row--)
{
ptr = ((uchar*)rgba) + row * tgaHeader.width * 4;
for(column=0;column<tgaHeader.width;)
{
g_pFullFileSystem->Read(&packetHeader, 1, file);
packetSize = 1 + (packetHeader & 0x7f);
if (packetHeader & 0x80)
{
switch (tgaHeader.pixel_size)
{
case 24:
{
g_pFullFileSystem->Read(color + 2, 1, file);
g_pFullFileSystem->Read(color + 1, 1, file);
g_pFullFileSystem->Read(color + 0, 1, file);
if (invertAlpha)
{
color[3] = 0;
}
else
{
color[3] = 255;
}
break;
}
case 32:
{
g_pFullFileSystem->Read(color + 2, 1, file);
g_pFullFileSystem->Read(color + 1, 1, file);
g_pFullFileSystem->Read(color + 0, 1, file);
g_pFullFileSystem->Read(color + 3, 1, file);
bMask = true;
if (invertAlpha)
{
color[3] = 255 - color[3];
}
break;
}
}
for (j = 0; j < packetSize; j++)
{
ptr[0] = color[0];
ptr[1] = color[1];
ptr[2] = color[2];
ptr[3] = color[3];
ptr += 4;
column++;
if (column == tgaHeader.width)
{
column = 0;
if (row > 0)
{
row--;
}
else
{
goto breakOut;
}
ptr = ((uchar*)rgba) + (row * tgaHeader.width * 4);
}
}
}
else
{
for (j = 0; j < packetSize; j++)
{
switch (tgaHeader.pixel_size)
{
case 24:
{
g_pFullFileSystem->Read(ptr + 2, 1, file);
g_pFullFileSystem->Read(ptr + 1, 1, file);
g_pFullFileSystem->Read(ptr + 0, 1, file);
ptr[3] = 255;
if (invertAlpha)
{
ptr[3] = 0;
}
else
{
ptr[3] = 255;
}
ptr += 4;
break;
}
case 32:
{
g_pFullFileSystem->Read(ptr + 2, 1, file);
g_pFullFileSystem->Read(ptr + 1, 1, file);
g_pFullFileSystem->Read(ptr + 0, 1, file);
g_pFullFileSystem->Read(ptr + 3, 1, file);
if (invertAlpha)
{
ptr[3]=255-ptr[3];
}
ptr += 4;
break;
}
}
column++;
if (column == tgaHeader.width)
{
column = 0;
if(row > 0)
{
row--;
}
else
{
goto breakOut;
}
ptr = ((uchar*)rgba) + row * tgaHeader.width * 4;
}
}
}
}
}
breakOut:;
}
g_pFullFileSystem->Close(file);
// we now have a block of memory, rgba
// throw a bitmap header on it and register it in windows
texture->_wide = tgaHeader.width;
texture->_tall = tgaHeader.height;
texture->_icon = NULL;
texture->_bitmap = staticCreateBitmapHandle(tgaHeader.width, tgaHeader.height, PLAT(_currentContextPanel)->hdc, 32, &texture->_dib);
texture->_bMask = bMask;
if (bMask)
texture->_maskBitmap = staticCreateBitmapHandle(tgaHeader.width, tgaHeader.height, PLAT(_currentContextPanel)->hdc, 32, &texture->_maskDib);
else
texture->_maskBitmap = NULL;
for (int j = 0; j < texture->_tall; j++)
{
for (int i = 0; i < texture->_wide; i++)
{
int offs = (j * texture->_wide + i) * 4;
char *src = ((char*)rgba) + offs;
char *dst = ((char*)texture->_dib) + offs;
if (bMask)
{
char *maskDst = ((char*) texture->_maskDib) + offs;
// if there's value here, then it needs to be cleared
if (src[3])
{
// mask will be & with background, so it needs to be 0xFF
maskDst[0] = maskDst[1] = maskDst[2] = maskDst[3] = -1;;
// clear the art in the bitmap because it's not going to display and will be | with background
dst[0] = dst[1] = dst[2] = dst[3] = 0;
}
else
{
// this will clear the background before drawing this bitmap
maskDst[0] = maskDst[1] = maskDst[2] = maskDst[3] = 0x00;
// copy over the art
dst[0] = src[2];
dst[1] = src[1];
dst[2] = src[0];
dst[3] = src[3];
}
}
else
{
dst[0] = src[2];
dst[1] = src[1];
dst[2] = src[0];
dst[3] = src[3];
}
}
}
free(rgba);
return true;
}
//-----------------------------------------------------------------------------
// Purpose: brings the current surface to the foreground
//-----------------------------------------------------------------------------
void CWin32Surface::BringToFront(VPANEL panel)
{
// force the panel to the top of the windows z-order
panel = GetContextPanelForChildPanel(panel);
if (panel && PLAT(panel))
{
// this should trigger a WM_SETFOCUS message which will move the window to the top
::SetActiveWindow(PLAT(panel)->hwnd);
}
}
//-----------------------------------------------------------------------------
// Purpose: puts the thread that created the specified window into the foreground
// and activates the window.
//-----------------------------------------------------------------------------
void CWin32Surface::SetForegroundWindow(VPANEL panel)
{
if (panel && PLAT(panel))
{
::SetForegroundWindow(PLAT(panel)->hwnd);
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::MovePopupToFront(VPANEL panel)
{
_popupList.MoveElementToEnd(panel);
g_pIVgui->PostMessage(panel, new KeyValues("OnMovedPopupToFront"), NULL);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::MovePopupToBack(VPANEL panel)
{
}
//-----------------------------------------------------------------------------
// Purpose:
// HWND_TOPMOST - Places the window above all non-topmost windows.
// The window maintains its topmost position even when it is deactivated.
// HWND_NOTOPMOST - Places the window above all non-topmost windows (that is, behind
// all topmost windows). This flag has no effect if the window is already a non-topmost window.
//-----------------------------------------------------------------------------
void CWin32Surface::SetAsTopMost(VPANEL panel, bool state)
{
panel = GetContextPanelForChildPanel(panel);
DWORD style=SWP_NOMOVE|SWP_NOSIZE;
if (PLAT(panel)->disabled)
{
style |= SWP_NOACTIVATE;
}
if (state)
{
SetFocus(PLAT(panel)->hwnd);
SetWindowPos(PLAT(panel)->hwnd,HWND_TOPMOST,0,0,0,0,style );
}
else
{
SetWindowPos(PLAT(panel)->hwnd,HWND_NOTOPMOST,0,0,0,0,style );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::SetPanelVisible(VPANEL panel, bool visible)
{
// if the panel has an attached window we need to set it's style
if (PLAT(panel))
{
if (visible)
{
// show the window
::ShowWindow(PLAT(panel)->hwnd, SW_SHOWNA);
}
else
{
// hide the window
::ShowWindow(PLAT(panel)->hwnd, SW_HIDE);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Flashes the window icon in the taskbar, to get the users attention
// Input : flashCount - number of times to flash the window
//-----------------------------------------------------------------------------
void CWin32Surface::FlashWindow(VPANEL panel, bool state)
{
if (!PLAT(panel))
return;
::FlashWindow(PLAT(panel)->hwnd, state);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::SetTopLevelFocus(VPANEL panel)
{
// this is handled by WM_FOCUS messages instead of directly
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::SetMinimized(VPANEL panel, bool state)
{
if (PLAT(panel))
{
if (state)
{
::ShowWindow(PLAT(panel)->hwnd, SW_MINIMIZE);
}
else
{
::ShowWindow(PLAT(panel)->hwnd, SW_SHOWNORMAL);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the window is minimized
//-----------------------------------------------------------------------------
bool CWin32Surface::IsMinimized(VPANEL panel)
{
if (PLAT(panel)->hwnd)
{
return ::IsIconic(PLAT(panel)->hwnd);
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::SetTitle(VPANEL panel, const wchar_t *title)
{
panel = GetContextPanelForChildPanel(panel);
if (panel)
{
if (m_bSupportsUnicode)
{
SetWindowTextW(PLAT(panel)->hwnd, title);
}
else
{
char mbcs[512];
::WideCharToMultiByte(CP_ACP, 0, title, -1, mbcs, sizeof(mbcs), NULL, NULL);
SetWindowTextA(PLAT(panel)->hwnd, mbcs);
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::SetAsToolBar(VPANEL panel, bool state)
{
panel = GetContextPanelForChildPanel(panel);
if (panel && PLAT(panel))
{
if (state)
{
::SetWindowLong(PLAT(panel)->hwnd, GWL_EXSTYLE, ::GetWindowLong(PLAT(panel)->hwnd, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
}
else
{
::SetWindowLong(PLAT(panel)->hwnd, GWL_EXSTYLE, ::GetWindowLong(PLAT(panel)->hwnd, GWL_EXSTYLE) & ~WS_EX_TOOLWINDOW);
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CWin32Surface::GetPopupCount()
{
return _popupList.GetCount();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
VPANEL CWin32Surface::GetPopup(int index)
{
return _popupList[index];
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::CreatePopup(VPANEL panel, bool minimised, bool showTaskbarIcon, bool disabled, bool mouseInput, bool kbInput )
{
if (((VPanel *)panel)->IsPopup() && PLAT(panel))
{
// it's already a popup so bail
return;
}
// make sure it's in the hierarchy
if (!((VPanel *)panel)->GetParent() && panel != _embeddedPanel)
{
((VPanel *)panel)->SetParent((VPanel *)_embeddedPanel);
}
int x,y,wide,tall;
((VPanel *)panel)->GetPos(x, y);
((VPanel *)panel)->GetSize(wide, tall);
((VPanel *)panel)->SetPopup(true);
((VPanel *)panel)->SetKeyBoardInputEnabled(kbInput);
((VPanel *)panel)->SetMouseInputEnabled(mouseInput);
// find our parent window if we have one
HWND hwndParent = NULL;
VPANEL pParent = GetContextPanelForChildPanel(panel);
if (pParent && pParent != _embeddedPanel)
{
hwndParent = PLAT(pParent)->hwnd;
}
//create the window and initialize platform specific data
//window is initial a popup and not visible
//when ApplyChanges is called the window will be shown unless
//it SetVisible(false) is called
SurfacePlat *plat = new SurfacePlat;
((VPanel *)panel)->SetPlat(plat);
// WS_SYSMENU and WS_MINIMIZEBOX flags are there simply to make icon appear in taskbar
// WS_EX_TOOLWINDOW hides the taskbar/ALT-TAB button
DWORD style=0,style_ex=0;
if (!showTaskbarIcon)
{
style = WS_POPUP | WS_CLIPCHILDREN;
style_ex= WS_EX_TOOLWINDOW;
if (!hwndParent)
{
hwndParent = PLAT(_embeddedPanel)->hwnd;
}
}
else
{
style = WS_POPUP | WS_SYSMENU | WS_MINIMIZEBOX | WS_CLIPCHILDREN;
}
if (panel != _embeddedPanel && ((VPanel *)panel)->IsVisible())
{
style |= WS_VISIBLE;
}
if(disabled)
{
style |= WS_DISABLED;
}
if ( minimised )
{
style |= WS_MINIMIZE;
}
plat->hwnd = CreateWindowEx(style_ex, "Surface", "", style, x, y, wide, tall, hwndParent, NULL, GetModuleHandle(NULL), NULL);
plat->clipRgn = CreateRectRgn(0,0,64,64);
plat->hdc = CreateCompatibleDC(NULL);
plat->hwndDC = NULL;
plat->bitmap = null;
plat->bitmapSize[0] = 0;
plat->bitmapSize[1] = 0;
plat->isFullscreen = false;
plat->embeddedPanel = (VPanel *)panel;
plat->disabled=disabled;
plat->notifyIcon = NULL;
plat->textureDC = NULL;
::SetBkMode(plat->hdc, TRANSPARENT);
::SetWindowLong(plat->hwnd, GWL_USERDATA, (LONG)g_pIVgui->PanelToHandle(panel));
::SetTextAlign(plat->hdc, TA_LEFT | TA_TOP | TA_UPDATECP);
if (!((VPanel *)panel)->IsVisible() || panel == _embeddedPanel)
{
SetPanelVisible(panel, false);
}
// create the context
RecreateContext(panel);
::RegisterDragDrop(plat->hwnd, &staticDragDropTarget);
// add the panel to the popup list
if (!_popupList.HasElement(panel))
{
_popupList.AddElement(panel);
}
else
{
// somehow getting added twice, fundamental problem
_asm int 3;
}
// hack, force a windows sound to be played
// the first time PlaySound is called there is 300ms hang, so this forces it to happen at startup
// instead of while the user is trying to do something
// we can't do this before a window created else it'll hang
static bool first = true;
if (first)
{
// double startTime = system()->GetCurrentTime();
::PlaySoundA("", NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT | SND_NOSTOP | SND_NOWAIT);
// double endTime = system()->GetCurrentTime();
// ivgui()->DPrintf2("PlaySound() : %dms\n", (int)((endTime - startTime) * 1000));
first = false;
}
//!! hack to set a valid current context panel
SetCurrentContextPanel(_embeddedPanel);
}
//-----------------------------------------------------------------------------
// Purpose: Called when a panel is created
//-----------------------------------------------------------------------------
void CWin32Surface::AddPanel(VPANEL panel)
{
}
//-----------------------------------------------------------------------------
// Purpose: Called when a panel gets deleted
//-----------------------------------------------------------------------------
void CWin32Surface::ReleasePanel(VPANEL panel)
{
_popupList.RemoveElement(panel);
if (panel == _currentContextPanel)
{
_currentContextPanel = _embeddedPanel;
}
if (PLAT(panel))
{
SurfacePlat *plat = PLAT(panel);
// release drag/drop
::RevokeDragDrop(plat->hwnd);
// remove notify icons
if (plat->notifyIcon)
{
SetNotifyIcon(panel, NULL, NULL, NULL);
}
// hide the panel
SetPanelVisible(panel, false);
// free all the windows/bitmap/DC handles we are using
::SetWindowLong(plat->hwnd, GWL_USERDATA, (LONG)-1);
::SetWindowPos(plat->hwnd, HWND_BOTTOM, 0, 0, 1, 1, SWP_NOREDRAW|SWP_HIDEWINDOW);
// free the window context
if ( plat->bitmap )
{
::DeleteObject( plat->bitmap );
}
if ( plat->textureDC )
{
::DeleteDC( plat->textureDC );
}
if (plat->hwndDC)
{
::ReleaseDC( plat->hwnd, plat->hwndDC );
}
::DeleteDC( plat->hdc );
::DestroyWindow( plat->hwnd );
::DeleteObject( plat->clipRgn );
// don't free staticWndclassAtom, because it is shared amongst surfaces,
// and is automatically freed when the application terminates
delete plat;
((VPanel *)panel)->SetPlat(NULL);
}
}
//-----------------------------------------------------------------------------
// Purpose: Applies any changes to the panel into the underline wnidow
//-----------------------------------------------------------------------------
bool CWin32Surface::RecreateContext(VPANEL panel)
{
if (panel && PLAT(panel))
{
SurfacePlat *plat = PLAT(panel);
int wide,tall;
((VPanel *)panel)->GetSize(wide,tall);
// rebuild bitmap only if necessary
// simple scheme to prevent excessive allocations by allocating only when
// bigger. It also adds in 100 extra for subsequent sizings
// it will also realloc if the size is 200 smaller to shrink memory usage
if ((wide > plat->bitmapSize[0])
|| (tall > plat->bitmapSize[1])
|| (wide < (plat->bitmapSize[0] - 200))
|| (tall < (plat->bitmapSize[1] - 200)))
{
if (plat->bitmap != null)
{
::DeleteObject(plat->bitmap);
}
plat->hwndDC = GetDC(plat->hwnd);
plat->bitmap = ::CreateCompatibleBitmap(plat->hwndDC, wide + 100, tall + 100);
plat->bitmapSize[0] = wide + 100;
plat->bitmapSize[1] = tall + 100;
if (plat->textureDC)
{
::DeleteDC(plat->textureDC);
}
::SelectObject(plat->hdc, plat->bitmap);
plat->textureDC = ::CreateCompatibleDC(plat->hdc);
::ReleaseDC(plat->hwnd, plat->hwndDC);
plat->hwndDC = NULL;
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::EnableMouseCapture(VPANEL panel, bool state)
{
VPANEL contextPanel = GetContextPanelForChildPanel(panel);
if (state)
{
::SetCapture(PLAT(contextPanel)->hwnd);
}
else
{
::ReleaseCapture();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWin32Surface::ShouldPaintChildPanel(VPANEL childPanel)
{
// don't Paint children as part of the normal process, handle them in with WM_PAINT messages instead
return !((VPanel *)childPanel)->IsPopup();
}
//-----------------------------------------------------------------------------
// Purpose: Called after a Paint to display the new buffer
//-----------------------------------------------------------------------------
void CWin32Surface::SwapBuffers(VPANEL panel)
{
if (PLAT(panel))
{
START_TIMER();
SurfacePlat *plat = PLAT(panel);
int wide,tall;
((VPanel *)panel)->GetSize(wide,tall);
plat->hwndDC = ::GetDC(plat->hwnd);
// reset origin and clipping then blit
::SetRectRgn(plat->clipRgn, 0, 0, wide, tall);
::SelectObject(plat->hdc, plat->clipRgn);
::SetViewportOrgEx(plat->hdc, 0, 0, NULL);
::BitBlt(plat->hwndDC, 0, 0, wide, tall, plat->hdc, 0, 0, SRCCOPY);
::ReleaseDC(plat->hwnd, plat->hwndDC);
plat->hwndDC = NULL;
END_TIMER("SwapBuffers time: %.2fms\n");
}
}
//-----------------------------------------------------------------------------
// Purpose: Called every frame to change to window state if necessary
//-----------------------------------------------------------------------------
void CWin32Surface::ApplyChanges()
{
for (int i = 0; i < GetPopupCount(); i++)
{
VPANEL panel = GetPopup(i);
if (!PLAT(panel))
continue;
SurfacePlat *Plat = PLAT(panel);
// force the main panel to be invisible
if (panel == GetEmbeddedPanel())
{
::ShowWindow(Plat->hwnd, SW_HIDE);
continue;
}
// hide and skip by invisible panels
if (!((VPanel *)panel)->IsVisible())
{
::ShowWindow(Plat->hwnd, SW_HIDE);
continue;
}
RECT rect;
int x, y, wide, tall, sx, sy, swide, stall;
// get how big the win32 window
::GetWindowRect(Plat->hwnd, &rect);
sx = rect.left;
sy = rect.top;
swide = rect.right-rect.left;
stall = rect.bottom-rect.top;
// how big is the embedded VPanel
((VPanel *)panel)->GetPos(x, y);
((VPanel *)panel)->GetSize(wide, tall);
// if they are not the same, then adjust the win32 window so it is
if ((x != sx) || (y != sy) || (wide != swide) || (tall != stall))
{
::SetWindowPos(Plat->hwnd, null, x, y, wide, tall, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
if ( sx > 0 || sy > 0 ) // only message for moves that are on the screen
{
g_pIVgui->PostMessage(panel, new KeyValues("Move"), NULL );
}
}
// check to see if the win32 window is visible
if (::GetWindowLong(Plat->hwnd, GWL_STYLE) & WS_VISIBLE)
{
//check to see if embedded VPanel is not visible, if so then hide the win32 window
if (!((VPanel *)panel)->IsVisible())
{
::ShowWindow(Plat->hwnd, SW_HIDE);
}
}
else // win32 window is hidden
{
//check to see if embedded VPanel is visible, if so then show the win32 window
if (((VPanel *)panel)->IsVisible())
{
::ShowWindow(Plat->hwnd, SW_SHOWNA);
}
}
//if the win32 window changed size and is visible, then the context needs to be recreated
if (((wide != swide) || (tall != stall)) && ((VPanel *)panel)->IsVisible())
{
RecreateContext(panel);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: recurses the panels calculating absolute positions
// parents must be solved before children
//-----------------------------------------------------------------------------
void CWin32Surface::InternalSolveTraverse(VPANEL panel)
{
// solve the parent
((VPanel *)panel)->Solve();
// now we can solve the children
for (int i = 0; i < ((VPanel *)panel)->GetChildCount(); i++)
{
VPanel *child = ((VPanel *)panel)->GetChild(i);
if (child->IsVisible())
{
InternalSolveTraverse((VPANEL)child);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: recurses the panels giving them a chance to do a user-defined think,
// PerformLayout and ApplySchemeSettings
// must be done child before parent
//-----------------------------------------------------------------------------
void CWin32Surface::InternalThinkTraverse(VPANEL panel)
{
// parent
((VPanel *)panel)->Client()->Think();
// then the children...
for (int i = 0; i < ((VPanel *)panel)->GetChildCount(); i++)
{
VPanel *child = ((VPanel *)panel)->GetChild(i);
if (child->IsVisible())
{
InternalThinkTraverse((VPANEL)child);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: recurses the panels giving them a chance to do a ApplySchemeSettings
// must be done child before parent
//-----------------------------------------------------------------------------
void CWin32Surface::InternalSchemeSettingsTraverse(VPANEL panel, bool forceApplySchemeSettings)
{
// think the children...
for (int i = 0; i < ((VPanel *)panel)->GetChildCount(); i++)
{
VPanel *child = ((VPanel *)panel)->GetChild(i);
if ( forceApplySchemeSettings || child->IsVisible() )
{
InternalSchemeSettingsTraverse((VPANEL)child, forceApplySchemeSettings);
}
}
// ... then the parent
((VPanel *)panel)->Client()->PerformApplySchemeSettings();
}
//-----------------------------------------------------------------------------
// Purpose: Walks through the panel tree calling Solve() on them all, in order
//-----------------------------------------------------------------------------
void CWin32Surface::SolveTraverse(VPANEL panel, bool forceApplySchemeSettings)
{
// ignore visibility for this
InternalSchemeSettingsTraverse(panel,forceApplySchemeSettings); // do apply scheme settings, child to parent
if (!((VPanel *)panel)->IsVisible())
return;
InternalThinkTraverse(panel);
InternalSolveTraverse(panel);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWin32Surface::PaintTraverse(VPANEL panel)
{
START_TIMER();
((VPanel *)panel)->Client()->PaintTraverse(false,true);
END_TIMER("Paint time: %.2fms\n");
}
// FIXME: write these functions!
void CWin32Surface::RestrictPaintToSinglePanel(VPANEL panel)
{
}
void CWin32Surface::SetModalPanel(VPANEL )
{
}
VPANEL CWin32Surface::GetModalPanel()
{
return 0;
}
void CWin32Surface::UnlockCursor()
{
}
void CWin32Surface::LockCursor()
{
}
void CWin32Surface::SetTranslateExtendedKeys(bool state)
{
}
VPANEL CWin32Surface::GetTopmostPopup()
{
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Checks to see if the mouse should be visible or not
//-----------------------------------------------------------------------------
void CWin32Surface::CalculateMouseVisible()
{
int i;
_needMouse = false;
_needKB = false;
for(i = 0 ; i < g_pSurface->GetPopupCount() ; i++ )
{
VPanel *pop = (VPanel *)g_pSurface->GetPopup( i ) ;
bool isVisible=pop->IsVisible();
VPanel *p= pop->GetParent();
while(p && isVisible)
{
if( p->IsVisible()==false)
{
isVisible=false;
break;
}
p=p->GetParent();
}
if(isVisible)
{
_needMouse |= pop->IsMouseInputEnabled();
_needKB |= pop->IsKeyBoardInputEnabled();
}
}
if (_needMouse)
{
SetCursor(vgui::dc_arrow);
UnlockCursor();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWin32Surface::NeedKBInput()
{
return _needKB;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the current cursor
//-----------------------------------------------------------------------------
void CWin32Surface::SetCursor(HCursor cursor)
{
switch (cursor)
{
case dc_none:
case dc_arrow:
case dc_ibeam:
case dc_hourglass:
case dc_waitarrow:
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:
{
_currentCursor = staticDefaultCursor[cursor];
break;
}
case dc_user:
{
break;
}
case dc_blank: // don't touch the cursor, just stick with what windows is currently using
{
return;
break;
}
}
::SetCursor(_currentCursor);
}
//-----------------------------------------------------------------------------
// Purpose: Forces the window to be redrawn
//-----------------------------------------------------------------------------
void CWin32Surface::Invalidate(VPANEL panel)
{
panel = GetContextPanelForChildPanel(panel);
if (panel && PLAT(panel) && ((VPanel *)panel)->IsVisible())
{
// last parm must be false so WM_ERASEBKGND is not generated, that should
// only be generated by windows
InvalidateRect(PLAT(panel)->hwnd, NULL, false);
}
}
//-----------------------------------------------------------------------------
// Purpose: Checks to see if any of the windows have focus
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWin32Surface::HasFocus()
{
HWND focus = ::GetFocus();
if (!focus)
return false;
// see if any of the windows on the surface have the focus
for (int i = 0; i < GetPopupCount(); i++)
{
VPANEL panel = GetPopup(i);
if (focus == PLAT(panel)->hwnd)
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if the cursor is over this surface
// Uses the windows call to do this, instead of doing it procedurally
//-----------------------------------------------------------------------------
bool CWin32Surface::IsWithin(int x,int y)
{
POINT pnt={x,y};
HWND hwnd = WindowFromPoint(pnt);
for (int i = 0; i < GetPopupCount(); i++)
{
if (PLAT(GetPopup(i))->hwnd == hwnd)
{
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: handles a set focus message
//-----------------------------------------------------------------------------
void CWin32Surface::setFocus(VPANEL panel)
{
// reset the focus to the last focused panel
panel = GetContextPanelForChildPanel(panel);
if (panel && PLAT(panel))
{
// make sure we have a valid panel
VPANEL focus = panel;
if (focus && ((VPanel *)focus)->HasParent((VPanel *)panel))
{
// Must be a child of the modal surface, if set
if ( g_pInput->GetAppModalSurface() && !((VPanel *)focus)->HasParent((VPanel *)g_pInput->GetAppModalSurface()) )
{
// trying to set focus to something that's not the modal panel, set it back
SetForegroundWindow(g_pInput->GetAppModalSurface());
}
else
{
// make sure focus is at top of list
// the subfocus will be automatically calculated in IInput::RunFrame()
((VPanel *)focus)->MoveToFront();
return;
}
}
}
// let the main panel get focus as the default
if (panel)
{
((VPanel *)panel)->Client()->RequestFocus(0);
}
}
struct FontRangeItem_t
{
const char *name;
int lowerRange;
int upperRange;
};
FontRangeItem_t g_FontRanges[] =
{
{ "Basic Latin", 0x0000, 0x007F },
{ "Latin-1 Supplement", 0x0080, 0x00FF },
{ "Latin Extended-A", 0x0100, 0x017F },
{ "Latin Extended-B", 0x0180, 0x024F },
{ "IPA Extensions", 0x0250, 0x02AF },
{ "Spacing Modifier Letters", 0x02B0, 0x02FF },
{ "Combining Diacritical Marks", 0x0300, 0x036F },
{ "Greek", 0x0370, 0x03FF },
{ "Cyrillic", 0x0400, 0x04FF },
{ "Armenian", 0x0530, 0x058F },
{ "Hebrew", 0x0590, 0x05FF },
{ "Arabic", 0x0600, 0x06FF },
{ "Syriac", 0x0700, 0x074F },
{ "Thaana", 0x0780, 0x07BF },
{ "Devanagari", 0x0900, 0x097F },
{ "Bengali", 0x0980, 0x09FF },
{ "Gurmukhi", 0x0A00, 0x0A7F },
{ "Gujarati", 0x0A80, 0x0AFF },
{ "Oriya", 0x0B00, 0x0B7F },
{ "Tamil", 0x0B80, 0x0BFF },
{ "Telugu", 0x0C00, 0x0C7F },
{ "Kannada", 0x0C80, 0x0CFF },
{ "Malayalam", 0x0D00, 0x0D7F },
{ "Sinhala", 0x0D80, 0x0DFF },
{ "Thai", 0x0E00, 0x0E7F },
{ "Lao", 0x0E80, 0x0EFF },
{ "Tibetan", 0x0F00, 0x0FBF },
{ "Myanmar", 0x1000, 0x109F },
{ "Georgian", 0x10A0, 0x10FF },
{ "Hangul Jamo", 0x1100, 0x11FF },
{ "Ethiopic", 0x1200, 0x137F },
{ "Cherokee", 0x13A0, 0x13FF },
{ "Unified Canadian Aboriginal Syllabics", 0x1400, 0x167F },
{ "Ogham", 0x1680, 0x169F },
{ "Runic", 0x16A0, 0x16FF },
{ "Khmer", 0x1780, 0x17FF },
{ "Mongolian", 0x1800, 0x18AF },
{ "Latin Extended Additional", 0x1E00, 0x1EFF },
{ "Greek Extended", 0x1F00, 0x1FFF },
{ "General Punctuation", 0x2000, 0x206F },
{ "Superscripts and Subscripts", 0x2070, 0x209F },
{ "Currency Symbols", 0x20A0, 0x20CF },
{ "Combining Diacritical Marks for Symbols",0x20D0, 0x20FF },
{ "Letterlike Symbols", 0x2100, 0x214F },
{ "Number Forms", 0x2150, 0x218F },
{ "Arrows", 0x2190, 0x21FF },
{ "Mathematical Operators", 0x2200, 0x22FF },
{ "Miscellaneous Technical", 0x2300, 0x23FF },
{ "Control Pictures", 0x2400, 0x243F },
{ "Optical Character Recognition", 0x2440, 0x245F },
{ "Enclosed Alphanumerics", 0x2460, 0x24FF },
{ "Box Drawing", 0x2500, 0x257F },
{ "Block Elements", 0x2580, 0x259F },
{ "Geometric Shapes", 0x25A0, 0x25FF },
{ "Miscellaneous Symbols", 0x2600, 0x26FF },
{ "Dingbats", 0x2700, 0x27BF },
{ "Braille Patterns", 0x2800, 0x28FF },
{ "CJK Radicals Supplement", 0x2E80, 0x2EFF },
{ "KangXi Radicals", 0x2F00, 0x2FDF },
{ "Ideographic Description Characters", 0x2FF0, 0x2FFF },
{ "CJK Symbols and Punctuation", 0x3000, 0x303F },
{ "Hiragana", 0x3040, 0x309F },
{ "Katakana", 0x30A0, 0x30FF },
{ "Bopomofo", 0x3100, 0x312F },
{ "Hangul Compatibility Jamo", 0x3130, 0x318F },
{ "Kanbun", 0x3190, 0x319F },
{ "Bopomofo Extended", 0x31A0, 0x31BF },
{ "Enclosed CJK Letters and Months", 0x3200, 0x32FF },
{ "CJK Compatibility", 0x3300, 0x33FF },
{ "CJK Unified Ideographs Extension A", 0x3400, 0x4DB5 },
{ "CJK Unified Ideographs", 0x4E00, 0x9FFF },
{ "Yi Syllables", 0xA000, 0xA48F },
{ "Yi Radicals", 0xA490, 0xA4CF },
{ "Hangul Syllables", 0xAC00, 0xD7A3 },
{ "-- surrogates --", 0xD800, 0xDBFF },
{ "CJK Compatibility Ideographs", 0xF900, 0xFAFF },
{ "Alphabetic Presentation Forms", 0xFB00, 0xFB4F },
{ "Arabic Presentation Forms-A", 0xFB50, 0xFDFF },
{ "Combining Half Marks", 0xFE20, 0xFE2F },
{ "CJK Compatibility Forms", 0xFE30, 0xFE4F },
{ "Small Form Variants", 0xFE50, 0xFE6F },
{ "Arabic Presentation Forms-B", 0xFE70, 0xFEFF },
{ "Halfwidth and Fullwidth Forms", 0xFF00, 0xFFEF },
{ "Specials", 0xFFF0, 0xFFFF },
};
//-----------------------------------------------------------------------------
// Purpose: creates a new empty font
//-----------------------------------------------------------------------------
HFont CWin32Surface::CreateFont()
{
return FontManager().CreateFont();
}
//-----------------------------------------------------------------------------
// Purpose: adds glyphs to a font created by CreateFont()
//-----------------------------------------------------------------------------
bool CWin32Surface::SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin, int nRangeMax)
{
return FontManager().SetFontGlyphSet(font, windowsFontName, tall, weight, blur, scanlines, flags, nRangeMin, nRangeMax);
}
//-----------------------------------------------------------------------------
// Purpose: returns the max height of a font
//-----------------------------------------------------------------------------
int CWin32Surface::GetFontTall(HFont font)
{
return FontManager().GetFontTall(font);
}
//-----------------------------------------------------------------------------
// Purpose: returns the requested height of a font
//-----------------------------------------------------------------------------
int CWin32Surface::GetFontTallRequested(HFont font)
{
return FontManager().GetFontTallRequested(font);
}
//-----------------------------------------------------------------------------
// Purpose: returns the max height of a font
//-----------------------------------------------------------------------------
int CWin32Surface::GetFontAscent(HFont font, wchar_t wch)
{
return FontManager().GetFontAscent(font,wch);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : font -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWin32Surface::IsFontAdditive(HFont font)
{
return FontManager().IsFontAdditive(font);
}
//-----------------------------------------------------------------------------
// Purpose: returns the abc widths of a single character
//-----------------------------------------------------------------------------
void CWin32Surface::GetCharABCwide(HFont font, int ch, int &a, int &b, int &c)
{
FontManager().GetCharABCwide(font, ch, a, b, c);
}
//-----------------------------------------------------------------------------
// Purpose: returns the pixel width of a single character
//-----------------------------------------------------------------------------
int CWin32Surface::GetCharacterWidth(HFont font, int ch)
{
return FontManager().GetCharacterWidth(font, ch);
}
//-----------------------------------------------------------------------------
// Purpose: returns the area of a text string, including newlines
//-----------------------------------------------------------------------------
void CWin32Surface::GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall)
{
FontManager().GetTextSize(font, text, wide, tall);
}
//-----------------------------------------------------------------------------
// Purpose: adds a custom font file (only supports true type font files (.ttf) for now)
//-----------------------------------------------------------------------------
bool CWin32Surface::AddCustomFontFile(const char *fontName, const char *fontFileName)
{
char fullPath[ MAX_PATH ];
g_pFullFileSystem->GetLocalPath(fontFileName, fullPath, sizeof( fullPath ));
m_CustomFontFileNames.AddToTail(fontFileName);
return (::AddFontResource(fullPath) > 0);
}
//-----------------------------------------------------------------------------
// Purpose: Pre-compiled bitmap font support for game engine - not implemented for GDI
//-----------------------------------------------------------------------------
bool CWin32Surface::AddBitmapFontFile(const char *fontFileName)
{
Assert( 0 );
return false;
}
void CWin32Surface::SetBitmapFontName( const char *pName, const char *pFontFilename )
{
Assert( 0 );
}
const char *CWin32Surface::GetBitmapFontName( const char *pName )
{
Assert( 0 );
return NULL;
}
bool CWin32Surface::SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags)
{
Assert( 0 );
return false;
}
void CWin32Surface::PrecacheFontCharacters(HFont font, const wchar_t *pCharacters)
{
Assert( 0 );
}
void CWin32Surface::ClearTemporaryFontCache( void )
{
Assert( 0 );
}
const char *CWin32Surface::GetFontName( HFont font )
{
return FontManager().GetFontName( font );
}
const char *CWin32Surface::GetFontFamilyName( HFont font )
{
return FontManager().GetFontFamilyName( font );
}
void CWin32Surface::DrawSetTextScale(float sx, float sy)
{
Assert( 0 );
}
void CWin32Surface::SetPanelForInput( VPANEL vpanel )
{
Assert( 0 );
}
void CWin32Surface::DrawFilledRectFastFade( int x0, int y0, int x1, int y1, int fadeStartPt, int fadeEndPt, unsigned int alpha0, unsigned int alpha1, bool bHorizontal )
{
Assert( 0 );
}
void CWin32Surface::DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal )
{
Assert( 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Returns the bounds of the usable workspace area
//-----------------------------------------------------------------------------
void CWin32Surface::GetWorkspaceBounds(int &x, int &y, int &wide, int &tall)
{
RECT rcScreen;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScreen, 0);
x = rcScreen.left;
y = rcScreen.top;
wide = rcScreen.right - x;
tall = rcScreen.bottom - y;
}
//-----------------------------------------------------------------------------
// Purpose: gets the absolute coordinates of the screen (in screen space)
//-----------------------------------------------------------------------------
void CWin32Surface::GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall)
{
// always work in full window screen space
x = 0;
y = 0;
GetScreenSize(wide, tall);
}
//-----------------------------------------------------------------------------
// Purpose: Plays a sound
// Input : *fileName - name of the wav file
//-----------------------------------------------------------------------------
void CWin32Surface::PlaySound(const char *fileName)
{
char localPath[MAX_PATH];
if (!g_pFullFileSystem->GetLocalPath(fileName, localPath, sizeof(localPath)))
return;
g_pFullFileSystem->GetLocalCopy(localPath);
::PlaySoundA(localPath, NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT | SND_NOSTOP | SND_NOWAIT);
}
bool GetIconSize( ICONINFO& iconInfo, int& w, int& h )
{
w = h = 0;
HBITMAP bitmap = iconInfo.hbmColor;
BITMAP bm;
if ( 0 == GetObject((HGDIOBJ)bitmap, sizeof(BITMAP), (LPVOID)&bm) )
{
return false;
}
w = bm.bmWidth;
h = bm.bmHeight;
return true;
}
class CIconImage : public IImage
{
public:
CIconImage( HICON hIcon ) : m_hIcon( CopyIcon( hIcon ) )
{
m_Pos.x = m_Pos.y = 0;
ICONINFO iconInfo;
if ( 0 != GetIconInfo( m_hIcon, &iconInfo ) )
{
int w, h;
GetIconSize( iconInfo, w, h );
m_Size.cx = w;
m_Size.cy = h;
}
else
{
m_Size.cx = 0;
m_Size.cy = 0;
}
}
// virtual destructor
virtual ~CIconImage()
{
DestroyIcon( m_hIcon );
}
// Call to Paint the image
// Image will draw within the current panel context at the specified position
virtual void Paint()
{
if ( !m_hIcon )
return;
if ( !m_Size.cx || !m_Size.cy )
return;
HDC hdc = PLAT(g_Surface._currentContextPanel)->hdc;
// Translate position to screen space based on surface state...
int x, y;
x = m_Pos.x;
y = m_Pos.y;
DrawIconEx
(
hdc,
x, y,
m_hIcon,
m_Size.cx, m_Size.cy,
0,
NULL,
DI_NORMAL
);
}
// Set the position of the image
virtual void SetPos(int x, int y)
{
m_Pos.x = x;
m_Pos.y = y;
}
// Gets the size of the content
virtual void GetContentSize(int &wide, int &tall)
{
wide = m_Size.cx;
tall = m_Size.cy;
}
// Get the size the image will actually draw in (usually defaults to the content size)
virtual void GetSize(int &wide, int &tall)
{
GetContentSize( wide, tall );
}
// Sets the size of the image
virtual void SetSize(int wide, int tall)
{
// Nothing
}
// Set the draw color
virtual void SetColor(Color col)
{
// Nothing
}
virtual bool Evict() { return false; }
virtual int GetNumFrames() { return 0; }
virtual void SetFrame( int nFrame ) {}
virtual HTexture GetID() { return 0; }
virtual void SetRotation( int iRotation ) { return; };
private:
HICON m_hIcon;
POINT m_Pos;
SIZE m_Size;
};
static bool ShouldMakeUnique( char const *extension )
{
if ( !Q_stricmp( extension, "cur" ) )
return true;
if ( !Q_stricmp( extension, "ani" ) )
return true;
return false;
}
IImage *CWin32Surface::GetIconImageForFullPath( char const *pFullPath )
{
IImage *newIcon = NULL;
SHFILEINFO info = { 0 };
DWORD_PTR dwResult = SHGetFileInfo(
pFullPath,
0,
&info,
sizeof( info ),
SHGFI_TYPENAME | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SHELLICONSIZE
);
if ( dwResult )
{
if ( info.szTypeName[ 0 ] != 0 )
{
char ext[ 32 ];
Q_ExtractFileExtension( pFullPath, ext, sizeof( ext ) );
char lookup[ 512 ];
Q_snprintf( lookup, sizeof( lookup ), "%s", ShouldMakeUnique( ext ) ? pFullPath : info.szTypeName );
// Now check the dictionary
unsigned short idx = m_FileTypeImages.Find( lookup );
if ( idx == m_FileTypeImages.InvalidIndex() )
{
newIcon = new CIconImage( info.hIcon );
idx = m_FileTypeImages.Insert( lookup, newIcon );
}
newIcon = m_FileTypeImages[ idx ];
}
DestroyIcon( info.hIcon );
}
return newIcon;
}
//-----------------------------------------------------------------------------
// Purpose: Handles windows message pump
//-----------------------------------------------------------------------------
void CWin32Surface::RunFrame()
{
::MSG msg;
if (!g_pIVgui->GetShouldVGuiControlSleep())
{
// if vgui doesn't control sleeping, then make sure we don't block in this loop
if (!::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
return;
}
// always get at least one message
// this means it will block until input
// there is a timer set to force this loop to run at least 20Hz, which should be fine for the desktop
do
{
BOOL ret = ::GetMessage(&msg, NULL, 0, 0);
if (ret == 0)
break;
if (ret == -1)
{
g_pIVgui->Stop();
break;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE));
}
//-----------------------------------------------------------------------------
// Purpose: cap bits
//-----------------------------------------------------------------------------
bool CWin32Surface::SupportsFeature(SurfaceFeature_e feature)
{
switch (feature)
{
case ISurface::ESCAPE_KEY:
case ISurface::ANTIALIASED_FONTS:
case ISurface::OPENING_NEW_HTML_WINDOWS:
case ISurface::FRAME_MINIMIZE_MAXIMIZE:
case ISurface::DIRECT_HWND_RENDER:
return true;
case ISurface::DROPSHADOW_FONTS:
case ISurface::OUTLINE_FONTS:
default:
return false;
};
}
//-----------------------------------------------------------------------------
// Purpose: Initializes all the static data for the app
// Should be only called during load time
//-----------------------------------------------------------------------------
void CWin32Surface::initStaticData()
{
//load up all default cursors, this gets called everytime a Surface is created, but
//who cares
staticDefaultCursor[dc_none] =null;
staticDefaultCursor[dc_arrow] =(HICON)LoadCursor(null,(LPCTSTR)OCR_NORMAL);
staticDefaultCursor[dc_ibeam] =(HICON)LoadCursor(null,(LPCTSTR)OCR_IBEAM);
staticDefaultCursor[dc_hourglass]=(HICON)LoadCursor(null,(LPCTSTR)OCR_WAIT);
staticDefaultCursor[dc_waitarrow]=(HICON)LoadCursor(null,(LPCTSTR)OCR_APPSTARTING);
staticDefaultCursor[dc_crosshair]=(HICON)LoadCursor(null,(LPCTSTR)OCR_CROSS);
staticDefaultCursor[dc_up] =(HICON)LoadCursor(null,(LPCTSTR)OCR_UP);
staticDefaultCursor[dc_sizenwse] =(HICON)LoadCursor(null,(LPCTSTR)OCR_SIZENWSE);
staticDefaultCursor[dc_sizenesw] =(HICON)LoadCursor(null,(LPCTSTR)OCR_SIZENESW);
staticDefaultCursor[dc_sizewe] =(HICON)LoadCursor(null,(LPCTSTR)OCR_SIZEWE);
staticDefaultCursor[dc_sizens] =(HICON)LoadCursor(null,(LPCTSTR)OCR_SIZENS);
staticDefaultCursor[dc_sizeall] =(HICON)LoadCursor(null,(LPCTSTR)OCR_SIZEALL);
staticDefaultCursor[dc_no] =(HICON)LoadCursor(null,(LPCTSTR)OCR_NO);
staticDefaultCursor[dc_hand] =(HICON)LoadCursor(null,(LPCTSTR)32649);
// make and register a very simple Window Class
memset( &staticWndclass,0,sizeof(staticWndclass) );
staticWndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
staticWndclass.lpfnWndProc = staticProc;
staticWndclass.hInstance = GetModuleHandle(NULL);
// Get the resource ID of the icon group from the environment...default to 101.
DWORD wIconID = 101;
const char *sIconResourceID = getenv(szSteamBootStrapperIconIdEnvVar);
if ( sIconResourceID )
{
DWORD wTmpIconID = 0;
if ( sscanf(sIconResourceID, "%u", &wTmpIconID) == 1 && wTmpIconID > 101 )
{
wIconID = wTmpIconID;
}
}
staticWndclass.hIcon = ::LoadIcon(staticWndclass.hInstance, MAKEINTRESOURCE(wIconID));
staticWndclass.lpszClassName = "Surface";
staticWndclassAtom = ::RegisterClass( &staticWndclass );
// register our global Shutdown command
staticShutdownMsg = ::RegisterWindowMessage("ShutdownValvePlatform");
}
//-----------------------------------------------------------------------------
// Purpose: our basic user agent string when doing http requests from the client for webkit
//-----------------------------------------------------------------------------
const char *CWin32Surface::GetWebkitHTMLUserAgentString()
{
return "Valve Client";
}
//-----------------------------------------------------------------------------
// Purpose: Handle switching in and out of "render to fullscreen" mode. We don't
// actually support this mode in tools.
//-----------------------------------------------------------------------------
void CWin32Surface::PushFullscreenViewport()
{
AssertMsg( false, "Fullscreen viewport mode is unimplemented in CWin32Surface" );
}
void CWin32Surface::PopFullscreenViewport()
{
}
//-----------------------------------------------------------------------------
// Purpose: Handles windows messages sent to the notify tray icon
//-----------------------------------------------------------------------------
static void staticNotifyIconProc(HWND hwnd, WPARAM wparam, LPARAM lparam)
{
switch (lparam)
{
case WM_LBUTTONDOWN:
{
// notify the window of the double click
if (g_Surface.GetNotifyPanel())
{
g_pIVgui->PostMessage(g_pSurface->GetNotifyPanel(), new KeyValues("NotifyIconMsg", "msg", "WM_LBUTTONDOWN"), NULL);
}
break;
}
case WM_LBUTTONDBLCLK:
{
//HACK: always bring us to front if the user double clicks the icon
::SetForegroundWindow(hwnd);
// notify the window of the double click
if (g_pSurface->GetNotifyPanel())
{
g_pIVgui->PostMessage(g_pSurface->GetNotifyPanel(), new KeyValues("NotifyIconMsg", "msg", "LBUTTONDBLCLK"), NULL);
}
break;
}
case WM_RBUTTONUP: // win95/98/NT
case WM_CONTEXTMENU: // win2k/ME
{
// display context menu
if (g_pSurface->GetNotifyPanel())
{
g_pIVgui->PostMessage(g_pSurface->GetNotifyPanel(), new KeyValues("NotifyIconMsg", "msg", "CONTEXTMENU"), NULL);
}
break;
}
default:
break;
}
}
static KeyCode g_iPreviousKeyCode = KEY_NONE;
static void PostCursorMoved( HWND hwnd, LPARAM lparam )
{
POINT pt;
pt.x = (short)LOWORD(lparam);
pt.y = (short)HIWORD(lparam);
::ClientToScreen( hwnd, &pt);
g_pInput->InternalCursorMoved(pt.x, pt.y);
}
static LRESULT CALLBACK staticProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
static UINT s_uTaskbarRestart;
VPANEL panel = NULL;
IClientPanel *client = NULL;
if (staticSurfaceAvailable)
{
panel = g_pIVgui->HandleToPanel(::GetWindowLong(hwnd, GWL_USERDATA));
if (panel)
{
client = ((VPanel *)panel)->Client();
}
}
// special case msg handle
if (msg == staticShutdownMsg)
{
// we're being notified that we have to Shutdown
g_pIVgui->ShutdownMessage(lparam);
return ::DefWindowProc(hwnd,msg,wparam,lparam);
}
if (msg == WM_ENDSESSION && wparam == TRUE)
{
// system is being shutdown
// after this message is processed, the app will be terminated
// so all necessary shutdown functions need to occur now
if (g_pSurface->GetEmbeddedPanel())
{
g_pIPanel->SendMessage(g_pSurface->GetEmbeddedPanel(), new KeyValues("WindowsEndSession"), NULL);
}
return 0;
}
if (!panel)
{
return ::DefWindowProc(hwnd,msg,wparam,lparam);
}
bool sendToDefWindowProc = true;
// md: temporarily disabled until the infinite recursion gets fixed.
if ( ImmIsUIMessage( NULL, msg, wparam, lparam ) )
{
sendToDefWindowProc = false;
}
switch (msg)
{
case MS_WM_XBUTTONDOWN:
{
PostCursorMoved( hwnd, lparam );
MouseCode code = ( HIWORD( wparam ) == 1 ) ? MOUSE_4 : MOUSE_5;
g_pInput->SetMouseCodeState( code, BUTTON_PRESSED );
g_pInput->InternalMousePressed( code );
break;
}
case MS_WM_XBUTTONUP:
{
PostCursorMoved( hwnd, lparam );
MouseCode code = ( HIWORD( wparam ) == 1 ) ? MOUSE_4 : MOUSE_5;
g_pInput->SetMouseCodeState( code, BUTTON_RELEASED );
g_pInput->InternalMouseReleased( code );
break;
}
case MS_WM_XBUTTONDBLCLK:
{
PostCursorMoved( hwnd, lparam );
MouseCode code = ( HIWORD( wparam ) == 1 ) ? MOUSE_4 : MOUSE_5;
g_pInput->SetMouseCodeState( code, BUTTON_DOUBLECLICKED );
g_pInput->InternalMouseDoublePressed( code );
break;
}
case WM_CREATE:
{
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
break;
}
case WM_CLOSE:
{
// tell the panel to close
g_pIVgui->PostMessage(panel, new KeyValues("Close"), NULL);
// don't Run default message pump, as that destroys the window
return 0;
}
case WM_MY_TRAY_NOTIFICATION:
{
staticNotifyIconProc(hwnd, wparam, lparam);
break;
}
case WM_SETFOCUS:
{
g_Surface.setFocus(panel);
//g_pIVgui->DPrintf("Set Focus %s %p\n", client->GetName(), panel);
break;
}
case WM_KILLFOCUS:
{
g_Surface.setFocus(NULL);
break;
}
case WM_APP:
{
g_Surface.setFocus(NULL);
break;
}
case WM_SETCURSOR:
{
//!! SetCursor(staticCurrentCursor);
break;
}
case WM_MOUSEMOVE:
{
POINT pt;
pt.x = (short)LOWORD(lparam);
pt.y = (short)HIWORD(lparam);
// This code catches the case when a WM_LBUTTONUP is lost
bool bLMButtonDown = wparam & MK_LBUTTON;
bool bRMButtonDown = wparam & MK_RBUTTON;
bool bMMButtonDown = wparam & MK_MBUTTON;
if ( !bLMButtonDown && g_pInput->IsMouseDown( MOUSE_LEFT ) )
{
g_pInput->SetMouseCodeState( MOUSE_LEFT, BUTTON_RELEASED );
g_pInput->InternalMouseReleased(MOUSE_LEFT);
}
if ( !bRMButtonDown && g_pInput->IsMouseDown( MOUSE_RIGHT ) )
{
g_pInput->SetMouseCodeState( MOUSE_LEFT, BUTTON_RELEASED );
g_pInput->InternalMouseReleased(MOUSE_LEFT);
}
if ( !bMMButtonDown && g_pInput->IsMouseDown( MOUSE_MIDDLE ) )
{
g_pInput->SetMouseCodeState( MOUSE_MIDDLE, BUTTON_RELEASED );
g_pInput->InternalMouseReleased(MOUSE_MIDDLE);
}
::ClientToScreen((HWND)hwnd, &pt);
g_pInput->InternalCursorMoved(pt.x, pt.y);
break;
}
case WM_LBUTTONDOWN:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_LEFT, BUTTON_PRESSED );
g_pInput->InternalMousePressed(MOUSE_LEFT);
break;
}
case WM_RBUTTONDOWN:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_RIGHT, BUTTON_PRESSED );
g_pInput->InternalMousePressed(MOUSE_RIGHT);
break;
}
case WM_MBUTTONDOWN:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_MIDDLE, BUTTON_PRESSED );
g_pInput->InternalMousePressed(MOUSE_MIDDLE);
break;
}
case WM_LBUTTONDBLCLK:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_LEFT, BUTTON_DOUBLECLICKED );
g_pInput->InternalMouseDoublePressed( MOUSE_LEFT );
break;
}
case WM_RBUTTONDBLCLK:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_RIGHT, BUTTON_DOUBLECLICKED );
g_pInput->InternalMouseDoublePressed( MOUSE_RIGHT );
break;
}
case WM_MBUTTONDBLCLK:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_MIDDLE, BUTTON_DOUBLECLICKED );
g_pInput->InternalMouseDoublePressed( MOUSE_MIDDLE );
break;
}
case WM_LBUTTONUP:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_LEFT, BUTTON_RELEASED );
g_pInput->InternalMouseReleased( MOUSE_LEFT );
break;
}
case WM_RBUTTONUP:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_RIGHT, BUTTON_RELEASED );
g_pInput->InternalMouseReleased( MOUSE_RIGHT );
break;
}
case WM_MBUTTONUP:
{
PostCursorMoved( hwnd, lparam );
g_pInput->SetMouseCodeState( MOUSE_MIDDLE, BUTTON_RELEASED );
g_pInput->InternalMouseReleased( MOUSE_MIDDLE );
break;
}
case WM_MOUSEWHEEL:
{
g_pInput->InternalMouseWheeled(((short)HIWORD(wparam))/WHEEL_DELTA);
break;
}
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
int code = wparam;
g_iPreviousKeyCode = KeyCode_VirtualKeyToVGUI( code );
bool bRepeating = ( lparam & ( 1<<30 ) ) != 0;
if ( !bRepeating )
{
g_pInput->SetKeyCodeState( g_iPreviousKeyCode, BUTTON_PRESSED );
g_pInput->InternalKeyCodePressed( g_iPreviousKeyCode );
}
g_pInput->InternalKeyCodeTyped( g_iPreviousKeyCode );
// Deal with toggles
if ( !bRepeating )
{
if ( code == VK_CAPITAL || code == VK_SCROLL || code == VK_NUMLOCK )
{
ButtonCode_t toggleCode;
switch( code )
{
default: case VK_CAPITAL: toggleCode = KEY_CAPSLOCKTOGGLE; break;
case VK_SCROLL: toggleCode = KEY_SCROLLLOCKTOGGLE; break;
case VK_NUMLOCK: toggleCode = KEY_NUMLOCKTOGGLE; break;
};
SHORT wState = GetKeyState( code );
bool bToggleState = ( wState & 0x1 ) != 0;
if ( bToggleState )
{
g_pInput->SetKeyCodeState( toggleCode, BUTTON_PRESSED );
g_pInput->InternalKeyCodePressed( toggleCode );
}
else
{
g_pInput->SetKeyCodeState( toggleCode, BUTTON_RELEASED );
g_pInput->InternalKeyCodeReleased( toggleCode );
}
}
}
break;
}
case WM_SYSCHAR:
case WM_CHAR:
{
int unichar = wparam;
g_pInput->InternalKeyTyped(unichar);
break;
}
case WM_KEYUP:
case WM_SYSKEYUP:
{
KeyCode code = KeyCode_VirtualKeyToVGUI( wparam );
g_pInput->SetKeyCodeState( code, BUTTON_RELEASED );
g_pInput->InternalKeyCodeReleased( code );
break;
}
case WM_ERASEBKGND:
{
//since the vgui Invalidate call does not erase the background
//this will only be called when windows itselfs wants a Repaint.
//this is the desired behavior because this call will for the
//surface and all its children to end up being repainted, which
//is what you want when windows wants you to Repaint the surface,
//but not what you want when say a control wants to be painted
//VPanel::Repaint will always Invalidate the surface so it will
//get a WM_PAINT, but that does not necessarily mean you want
//the whole surface painted
//simply this means.. this call only happens when windows wants the Repaint
//and WM_PAINT gets called just after this to do the real painting
client->Repaint();
// vgui::g_pIVgui->DPrintf( "WM_ERASEBKGND(%X)\n", panel );
break;
}
case WM_PAINT:
{
//surface was by repainted vgui or by windows itself, do the repainting all repainting
//will goes through here and nowhere else
// post Paint messages to the que
// panel->SolveTraverse();
// post a message to Paint the window
// vgui::g_pIVgui->DPrintf( "WM_PAINT(%X)\n", panel );
// g_pInput->PostMessage( panel, new KeyValues("Paint"), NULL );
// this relies on platTick() being called BEFORE dispatchMessages(), so that painting occurs
// on the same frame that the WM_PAINT message is received
// double startTime, solveTime, paintTime;
// OLD CODE
// check that the panel is visible all the way to the root
bool IsVisible=g_pIPanel->IsVisible(panel);
VPANEL p= g_pIPanel->GetParent(panel);
// drill down the heirachy checking that everything is visible
while(p && IsVisible)
{
if( g_pIPanel->IsVisible(p)==false)
{
IsVisible=false;
break;
}
p=g_pIPanel->GetParent(p);
}
if( IsVisible )
{
PAINTSTRUCT ps;
::BeginPaint(hwnd,&ps);
// startTime = system()->GetCurrentTime();
g_Surface.SolveTraverse(panel, false);
// solveTime = system()->GetCurrentTime();
g_Surface.PaintTraverse(panel);
// paintTime = system()->GetCurrentTime();
::EndPaint(hwnd,&ps);
}
// debug timing code
// ivgui()->DPrintf2("Paint timings (%.3f %.3f)\n", (float)(solveTime - startTime), (float)(paintTime - solveTime));
/* char dbtxt[200];
Q_snprintf(dbtxt,200,"paint:%p -- %p\n",hwnd,g_Surface.GetHTMLWindow(0)->GetIEHWND());
OutputDebugString( dbtxt );
*/
//clear the update rectangle so it does not get another Repaint
::ValidateRect(hwnd, NULL);
break;
}
default:
{
if (msg == s_uTaskbarRestart)
{
// notify window to re-add taskbar icons
g_pIVgui->PostMessage(panel, new KeyValues("TaskbarRestart"), NULL);
}
break;
}
}
if ( sendToDefWindowProc )
{
return DefWindowProc(hwnd,msg,wparam,lparam);
}
return TRUE;
}