summaryrefslogtreecommitdiff
path: root/vgui2/src
diff options
context:
space:
mode:
Diffstat (limited to 'vgui2/src')
-rw-r--r--vgui2/src/Bitmap.cpp272
-rw-r--r--vgui2/src/Border.cpp270
-rw-r--r--vgui2/src/IMessageListener.h43
-rw-r--r--vgui2/src/ImageBorder.cpp223
-rw-r--r--vgui2/src/ImageBorder.h69
-rw-r--r--vgui2/src/InputWin32.cpp3198
-rw-r--r--vgui2/src/LocalizedStringTable.cpp1060
-rw-r--r--vgui2/src/MemoryBitmap.cpp174
-rw-r--r--vgui2/src/Memorybitmap.h67
-rw-r--r--vgui2/src/MessageListener.cpp112
-rw-r--r--vgui2/src/ScalableImageBorder.cpp272
-rw-r--r--vgui2/src/ScalableImageBorder.h78
-rw-r--r--vgui2/src/Scheme.cpp1532
-rw-r--r--vgui2/src/Surface.cpp4082
-rw-r--r--vgui2/src/System.cpp1151
-rw-r--r--vgui2/src/VGUI_Border.h82
-rw-r--r--vgui2/src/VPanel.cpp782
-rw-r--r--vgui2/src/VPanel.h146
-rw-r--r--vgui2/src/VPanelWrapper.cpp362
-rw-r--r--vgui2/src/bitmap.h64
-rw-r--r--vgui2/src/fileimage.cpp211
-rw-r--r--vgui2/src/fileimage.h95
-rw-r--r--vgui2/src/keyrepeat.cpp177
-rw-r--r--vgui2/src/system_posix.cpp809
-rw-r--r--vgui2/src/vgui.cpp1195
-rw-r--r--vgui2/src/vgui_dll.vpc125
-rw-r--r--vgui2/src/vgui_internal.cpp68
-rw-r--r--vgui2/src/vgui_internal.h50
-rw-r--r--vgui2/src/vgui_key_translation.cpp42
-rw-r--r--vgui2/src/vgui_key_translation.h20
-rw-r--r--vgui2/src/xbox/xbox.def3
31 files changed, 16834 insertions, 0 deletions
diff --git a/vgui2/src/Bitmap.cpp b/vgui2/src/Bitmap.cpp
new file mode 100644
index 0000000..4d4a71e
--- /dev/null
+++ b/vgui2/src/Bitmap.cpp
@@ -0,0 +1,272 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <vgui/ISurface.h>
+#include "bitmap.h"
+#include "vgui_internal.h"
+#include "filesystem.h"
+#include "tier1/utlbuffer.h"
+#include <tier0/dbg.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : *filename - image file to load
+//-----------------------------------------------------------------------------
+Bitmap::Bitmap(const char *filename, bool hardwareFiltered)
+{
+ _filtered = hardwareFiltered;
+
+ int size = strlen(filename) + 1;
+ _filename = (char *)malloc( size );
+ Assert( _filename );
+
+ Q_snprintf( _filename, size, "%s", filename );
+
+ _bProcedural = false;
+
+ if ( Q_stristr( filename, ".pic" ) )
+ {
+ _bProcedural = true;
+ }
+
+ _id = 0;
+ _uploaded = false;
+ _color = Color(255, 255, 255, 255);
+ _pos[0] = _pos[1] = 0;
+ _valid = true;
+ _wide = 0;
+ _tall = 0;
+ nFrameCache = 0;
+ _rotation = 0;
+
+ ForceUpload();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+Bitmap::~Bitmap()
+{
+ Evict();
+
+ if ( _filename )
+ {
+ free( _filename );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void Bitmap::GetSize(int &wide, int &tall)
+{
+ wide = 0;
+ tall = 0;
+
+ if ( !_valid )
+ return;
+
+ // if a size has not been set, get it from the texture
+ if ( 0 == _wide && 0 ==_tall )
+ {
+ g_pSurface->DrawGetTextureSize(_id, _wide, _tall);
+
+ }
+ wide = _wide;
+ tall = _tall;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: size of the bitmap
+//-----------------------------------------------------------------------------
+void Bitmap::GetContentSize(int &wide, int &tall)
+{
+ GetSize(wide, tall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: ignored
+//-----------------------------------------------------------------------------
+void Bitmap::SetSize(int x, int y)
+{
+// AssertMsg( _filtered, "Bitmap::SetSize called on non-hardware filtered texture. Bitmap can't be scaled; you don't want to be calling this." );
+ _wide = x;
+ _tall = y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void Bitmap::SetPos(int x, int y)
+{
+ _pos[0] = x;
+ _pos[1] = y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void Bitmap::SetColor(Color col)
+{
+ _color = col;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the file name of the bitmap
+//-----------------------------------------------------------------------------
+const char *Bitmap::GetName()
+{
+ return _filename;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Renders the loaded image, uploading it if necessary
+// Assumes a valid image is always returned from uploading
+//-----------------------------------------------------------------------------
+void Bitmap::Paint()
+{
+ if ( !_valid )
+ return;
+
+ // if we don't have an _id then lets make one
+ if ( !_id )
+ {
+ _id = g_pSurface->CreateNewTextureID();
+ }
+
+ // if we have not uploaded yet, lets go ahead and do so
+ if ( !_uploaded )
+ {
+ ForceUpload();
+ }
+
+ // set the texture current, set the color, and draw the biatch
+ g_pSurface->DrawSetColor( _color[0], _color[1], _color[2], _color[3] );
+ g_pSurface->DrawSetTexture( _id );
+
+ if ( _wide == 0 )
+ {
+ GetSize( _wide, _tall);
+ }
+
+ if ( _rotation == ROTATED_UNROTATED )
+ {
+ g_pSurface->DrawTexturedRect(_pos[0], _pos[1], _pos[0] + _wide, _pos[1] + _tall);
+ }
+ else
+ {
+ vgui::Vertex_t verts[4];
+ verts[0].m_Position.Init( 0, 0 );
+ verts[1].m_Position.Init( _wide, 0 );
+ verts[2].m_Position.Init( _wide, _tall );
+ verts[3].m_Position.Init( 0, _tall );
+
+ switch ( _rotation )
+ {
+ case ROTATED_CLOCKWISE_90:
+ verts[0].m_TexCoord.Init( 1, 0 );
+ verts[1].m_TexCoord.Init( 1, 1 );
+ verts[2].m_TexCoord.Init( 0, 1 );
+ verts[3].m_TexCoord.Init( 0, 0 );
+ break;
+
+ case ROTATED_ANTICLOCKWISE_90:
+ verts[0].m_TexCoord.Init( 0, 1 );
+ verts[1].m_TexCoord.Init( 0, 0 );
+ verts[2].m_TexCoord.Init( 1, 0 );
+ verts[3].m_TexCoord.Init( 1, 1 );
+ break;
+
+ case ROTATED_FLIPPED:
+ verts[0].m_TexCoord.Init( 1, 1 );
+ verts[1].m_TexCoord.Init( 0, 1 );
+ verts[2].m_TexCoord.Init( 0, 0 );
+ verts[3].m_TexCoord.Init( 1, 0 );
+ break;
+
+ default:
+ case ROTATED_UNROTATED:
+ break;
+ }
+
+ g_pSurface->DrawTexturedPolygon( 4, verts );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: ensures the bitmap has been uploaded
+//-----------------------------------------------------------------------------
+void Bitmap::ForceUpload()
+{
+ if ( !_valid || _uploaded )
+ return;
+
+ if ( !_id )
+ {
+ _id = g_pSurface->CreateNewTextureID( _bProcedural );
+ }
+
+ if ( !_bProcedural )
+ {
+ g_pSurface->DrawSetTextureFile( _id, _filename, _filtered, false );
+ }
+
+ _uploaded = true;
+ _valid = g_pSurface->IsTextureIDValid( _id );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+HTexture Bitmap::GetID()
+{
+ return _id;
+}
+
+bool Bitmap::Evict()
+{
+ if ( _id != 0 )
+ {
+ g_pSurface->DestroyTextureID( _id );
+ // purposely not resetting _valid to match existing silly logic
+ // either a Paint() or ForceUpload() will re-establish
+ _id = 0;
+ _uploaded = false;
+ return true;
+ }
+ return false;
+}
+
+int Bitmap::GetNumFrames()
+{
+ if ( !_valid )
+ return 0;
+
+ return g_pSurface->GetTextureNumFrames( _id );
+}
+
+void Bitmap::SetFrame( int nFrame )
+{
+ if ( !_valid )
+ return;
+
+ // the frame cache is critical to cheapen the cost of this call
+ g_pSurface->DrawSetTextureFrame( _id, nFrame, &nFrameCache );
+}
+
+
+
+
+
diff --git a/vgui2/src/Border.cpp b/vgui2/src/Border.cpp
new file mode 100644
index 0000000..de7cfff
--- /dev/null
+++ b/vgui2/src/Border.cpp
@@ -0,0 +1,270 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdio.h>
+#include <string.h>
+
+#include "vgui/IPanel.h"
+#include "vgui/IScheme.h"
+#include "vgui/ISurface.h"
+
+#include "VGUI_Border.h"
+#include "vgui_internal.h"
+#include "VPanel.h"
+#include "KeyValues.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+Border::Border()
+{
+ _inset[0]=0;
+ _inset[1]=0;
+ _inset[2]=0;
+ _inset[3]=0;
+ _name = NULL;
+ m_eBackgroundType = IBorder::BACKGROUND_FILLED;
+
+ memset(_sides, 0, sizeof(_sides));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+Border::~Border()
+{
+ delete [] _name;
+
+ for (int i = 0; i < 4; i++)
+ {
+ delete [] _sides[i].lines;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Border::SetInset(int left,int top,int right,int bottom)
+{
+ _inset[SIDE_LEFT] = left;
+ _inset[SIDE_TOP] = top;
+ _inset[SIDE_RIGHT] = right;
+ _inset[SIDE_BOTTOM] = bottom;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Border::GetInset(int& left,int& top,int& right,int& bottom)
+{
+ left = _inset[SIDE_LEFT];
+ top = _inset[SIDE_TOP];
+ right = _inset[SIDE_RIGHT];
+ bottom = _inset[SIDE_BOTTOM];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Border::Paint(int x, int y, int wide, int tall)
+{
+ Paint(x, y, wide, tall, -1, 0, 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the border with the specified size
+//-----------------------------------------------------------------------------
+void Border::Paint(int x, int y, int wide, int tall, int breakSide, int breakStart, int breakEnd)
+{
+ // iterate through and draw all lines
+ // draw left
+ int i;
+ for (i = 0; i < _sides[SIDE_LEFT].count; i++)
+ {
+ line_t *line = &(_sides[SIDE_LEFT].lines[i]);
+ g_pSurface->DrawSetColor(line->col[0], line->col[1], line->col[2], line->col[3]);
+
+ if (breakSide == SIDE_LEFT)
+ {
+ // split into two section
+ if (breakStart > 0)
+ {
+ // draw before the break Start
+ g_pSurface->DrawFilledRect(x + i, y + line->startOffset, x + i + 1, y + breakStart);
+ }
+
+ if (breakEnd < (tall - line->endOffset))
+ {
+ // draw after break end
+ g_pSurface->DrawFilledRect(x + i, y + breakEnd + 1, x + i + 1, tall - line->endOffset);
+ }
+ }
+ else
+ {
+ g_pSurface->DrawFilledRect(x + i, y + line->startOffset, x + i + 1, tall - line->endOffset);
+ }
+ }
+
+ // draw top
+ for (i = 0; i < _sides[SIDE_TOP].count; i++)
+ {
+ line_t *line = &(_sides[SIDE_TOP].lines[i]);
+ g_pSurface->DrawSetColor(line->col[0], line->col[1], line->col[2], line->col[3]);
+
+ if (breakSide == SIDE_TOP)
+ {
+ // split into two section
+ if (breakStart > 0)
+ {
+ // draw before the break Start
+ g_pSurface->DrawFilledRect(x + line->startOffset, y + i, x + breakStart, y + i + 1);
+ }
+
+ if (breakEnd < (wide - line->endOffset))
+ {
+ // draw after break end
+ g_pSurface->DrawFilledRect(x + breakEnd + 1, y + i, wide - line->endOffset, y + i + 1);
+ }
+ }
+ else
+ {
+ g_pSurface->DrawFilledRect(x + line->startOffset, y + i, wide - line->endOffset, y + i + 1);
+ }
+ }
+
+ // draw right
+ for (i = 0; i < _sides[SIDE_RIGHT].count; i++)
+ {
+ line_t *line = &(_sides[SIDE_RIGHT].lines[i]);
+ g_pSurface->DrawSetColor(line->col[0], line->col[1], line->col[2], line->col[3]);
+ g_pSurface->DrawFilledRect(wide - (i+1), y + line->startOffset, (wide - (i+1)) + 1, tall - line->endOffset);
+ }
+
+ // draw bottom
+ for (i = 0; i < _sides[SIDE_BOTTOM].count; i++)
+ {
+ line_t *line = &(_sides[SIDE_BOTTOM].lines[i]);
+ g_pSurface->DrawSetColor(line->col[0], line->col[1], line->col[2], line->col[3]);
+ g_pSurface->DrawFilledRect(x + line->startOffset, tall - (i+1), wide - line->endOffset, (tall - (i+1)) + 1);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Border::Paint(VPANEL panel)
+{
+ // get panel size
+ int wide, tall;
+ ((VPanel *)panel)->GetSize(wide, tall);
+ Paint(0, 0, wide, tall, -1, 0, 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Border::ApplySchemeSettings(IScheme *pScheme, KeyValues *inResourceData)
+{
+ // load inset information
+ const char *insetString = inResourceData->GetString("inset", "0 0 0 0");
+
+ int left, top, right, bottom;
+ GetInset(left, top, right, bottom);
+ sscanf(insetString, "%d %d %d %d", &left, &top, &right, &bottom);
+ SetInset(left, top, right, bottom);
+
+ // get the border information from the scheme
+ ParseSideSettings(SIDE_LEFT, inResourceData->FindKey("Left"),pScheme);
+ ParseSideSettings(SIDE_TOP, inResourceData->FindKey("Top"),pScheme);
+ ParseSideSettings(SIDE_RIGHT, inResourceData->FindKey("Right"),pScheme);
+ ParseSideSettings(SIDE_BOTTOM, inResourceData->FindKey("Bottom"),pScheme);
+
+ m_eBackgroundType = (backgroundtype_e)inResourceData->GetInt("backgroundtype");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: parses scheme data
+//-----------------------------------------------------------------------------
+void Border::ParseSideSettings(int side_index, KeyValues *inResourceData, IScheme *pScheme)
+{
+ if (!inResourceData)
+ return;
+
+ // count the numeber of lines in the side
+ int count = 0;
+ KeyValues *kv;
+ for (kv = inResourceData->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey())
+ {
+ count++;
+ }
+
+ // allocate memory
+ _sides[side_index].count = count;
+ _sides[side_index].lines = new line_t[count];
+
+ // iterate through the keys
+ //!! this loads in order, ignoring key names
+ int index = 0;
+ for (kv = inResourceData->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey())
+ {
+ line_t *line = &(_sides[side_index].lines[index]);
+
+ // this is the color name, get that from the color table
+ const char *col = kv->GetString("color", NULL);
+ line->col = pScheme->GetColor(col, Color(0, 0, 0, 0));
+
+ col = kv->GetString("offset", NULL);
+ int Start = 0, end = 0;
+ if (col)
+ {
+ sscanf(col, "%d %d", &Start, &end);
+ }
+ line->startOffset = Start;
+ line->endOffset = end;
+
+ index++;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+const char *Border::GetName()
+{
+ if (_name)
+ return _name;
+ return "";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void Border::SetName(const char *name)
+{
+ if (_name)
+ {
+ delete [] _name;
+ }
+
+ int len = Q_strlen(name) + 1;
+ _name = new char[ len ];
+ Q_strncpy( _name, name, len );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IBorder::backgroundtype_e Border::GetBackgroundType()
+{
+ return m_eBackgroundType;
+}
+
diff --git a/vgui2/src/IMessageListener.h b/vgui2/src/IMessageListener.h
new file mode 100644
index 0000000..0ff6fc0
--- /dev/null
+++ b/vgui2/src/IMessageListener.h
@@ -0,0 +1,43 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef IMESSAGELISTENER_H
+#define IMESSAGELISTENER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+
+class KeyValues;
+
+namespace vgui
+{
+
+enum MessageSendType_t
+{
+ MESSAGE_SENT = 0,
+ MESSAGE_POSTED,
+ MESSAGE_RECEIVED
+};
+
+class VPanel;
+
+
+class IMessageListener
+{
+public:
+ virtual void Message( VPanel* pSender, VPanel* pReceiver,
+ KeyValues* pKeyValues, MessageSendType_t type ) = 0;
+};
+
+IMessageListener* MessageListener();
+
+}
+
+#endif // IMESSAGELISTENER_H
diff --git a/vgui2/src/ImageBorder.cpp b/vgui2/src/ImageBorder.cpp
new file mode 100644
index 0000000..51cb0fd
--- /dev/null
+++ b/vgui2/src/ImageBorder.cpp
@@ -0,0 +1,223 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdio.h>
+#include <string.h>
+
+#include <vgui_controls/Panel.h>
+#include "vgui/IPanel.h"
+#include "vgui/IScheme.h"
+#include "vgui/ISurface.h"
+
+#include "vgui_internal.h"
+#include "ImageBorder.h"
+#include "KeyValues.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+ImageBorder::ImageBorder()
+{
+ _name = NULL;
+ m_eBackgroundType = IBorder::BACKGROUND_TEXTURED;
+
+ m_pszImageName = NULL;
+ m_iTextureID = g_pSurface->CreateNewTextureID();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+ImageBorder::~ImageBorder()
+{
+ if ( vgui::surface() && m_iTextureID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iTextureID );
+ m_iTextureID = -1;
+ }
+
+ delete [] _name;
+ if ( m_pszImageName )
+ {
+ delete [] m_pszImageName;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ImageBorder::SetImage(const char *imageName)
+{
+ if ( m_pszImageName )
+ {
+ delete [] m_pszImageName;
+ m_pszImageName = NULL;
+ }
+
+ if (*imageName)
+ {
+ int len = Q_strlen(imageName) + 1 + 5; // 5 for "vgui/"
+ delete [] m_pszImageName;
+ m_pszImageName = new char[ len ];
+ Q_snprintf( m_pszImageName, len, "vgui/%s", imageName );
+
+ g_pSurface->DrawSetTextureFile( m_iTextureID, m_pszImageName, true, false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ImageBorder::SetInset(int left,int top,int right,int bottom)
+{
+ _inset[SIDE_LEFT] = left;
+ _inset[SIDE_TOP] = top;
+ _inset[SIDE_RIGHT] = right;
+ _inset[SIDE_BOTTOM] = bottom;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ImageBorder::GetInset(int& left,int& top,int& right,int& bottom)
+{
+ left = _inset[SIDE_LEFT];
+ top = _inset[SIDE_TOP];
+ right = _inset[SIDE_RIGHT];
+ bottom = _inset[SIDE_BOTTOM];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ImageBorder::Paint(int x, int y, int wide, int tall)
+{
+ Paint(x, y, wide, tall, -1, 0, 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the border with the specified size
+//-----------------------------------------------------------------------------
+void ImageBorder::Paint(int x, int y, int wide, int tall, int breakSide, int breakStart, int breakEnd)
+{
+ if ( !m_pszImageName || !m_pszImageName[0] )
+ return;
+
+ g_pSurface->DrawSetColor( 255, 255, 255, 255 );
+ g_pSurface->DrawSetTexture( m_iTextureID );
+
+ float uvx = 0;
+ float uvy = 0;
+ float uvw = 1.0;
+ float uvh = 1.0;
+ Vector2D uv11( uvx, uvy );
+ Vector2D uv21( uvx+uvw, uvy );
+ Vector2D uv22( uvx+uvw, uvy+uvh );
+ Vector2D uv12( uvx, uvy+uvh );
+
+ if ( m_bTiled )
+ {
+ int imageWide, imageTall;
+ g_pSurface->DrawGetTextureSize( m_iTextureID, imageWide, imageTall );
+
+ int y = 0;
+ while ( y < tall )
+ {
+ int x = 0;
+ while (x < wide)
+ {
+ vgui::Vertex_t verts[4];
+ verts[0].Init( Vector2D( x, y ), uv11 );
+ verts[1].Init( Vector2D( x+imageWide, y ), uv21 );
+ verts[2].Init( Vector2D( x+imageWide, y+imageTall ), uv22 );
+ verts[3].Init( Vector2D( x, y+imageTall ), uv12 );
+
+ g_pSurface->DrawTexturedPolygon( 4, verts );
+
+ x += imageWide;
+ }
+
+ y += imageTall;
+ }
+ }
+ else
+ {
+ vgui::Vertex_t verts[4];
+ verts[0].Init( Vector2D( x, y ), uv11 );
+ verts[1].Init( Vector2D( x+wide, y ), uv21 );
+ verts[2].Init( Vector2D( x+wide, y+tall ), uv22 );
+ verts[3].Init( Vector2D( x, y+tall ), uv12 );
+
+ g_pSurface->DrawTexturedPolygon( 4, verts );
+ }
+
+ g_pSurface->DrawSetTexture(0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ImageBorder::Paint(VPANEL panel)
+{
+ // get panel size
+ int wide, tall;
+ ipanel()->GetSize( panel, wide, tall );
+ Paint(0, 0, wide, tall, -1, 0, 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ImageBorder::ApplySchemeSettings(IScheme *pScheme, KeyValues *inResourceData)
+{
+ m_eBackgroundType = (backgroundtype_e)inResourceData->GetInt("backgroundtype");
+ m_bTiled = inResourceData->GetInt( "tiled" );
+
+ const char *imageName = inResourceData->GetString("image", "");
+ SetImage( imageName );
+
+ m_bPaintFirst = inResourceData->GetInt("paintfirst", true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+const char *ImageBorder::GetName()
+{
+ if (_name)
+ return _name;
+ return "";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void ImageBorder::SetName(const char *name)
+{
+ if (_name)
+ {
+ delete [] _name;
+ }
+
+ int len = Q_strlen(name) + 1;
+ _name = new char[ len ];
+ Q_strncpy( _name, name, len );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IBorder::backgroundtype_e ImageBorder::GetBackgroundType()
+{
+ return m_eBackgroundType;
+}
+
diff --git a/vgui2/src/ImageBorder.h b/vgui2/src/ImageBorder.h
new file mode 100644
index 0000000..25e9e86
--- /dev/null
+++ b/vgui2/src/ImageBorder.h
@@ -0,0 +1,69 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core implementation of vgui
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef IMAGE_BORDER_H
+#define IMAGE_BORDER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui/IBorder.h>
+#include <vgui/IScheme.h>
+#include <vgui/IPanel.h>
+#include <Color.h>
+
+class KeyValues;
+
+//-----------------------------------------------------------------------------
+// Purpose: Custom border that renders itself with images
+//-----------------------------------------------------------------------------
+class ImageBorder : public vgui::IBorder
+{
+public:
+ ImageBorder();
+ ~ImageBorder();
+
+ virtual void Paint(vgui::VPANEL panel);
+ virtual void Paint(int x0, int y0, int x1, int y1);
+ virtual void Paint(int x0, int y0, int x1, int y1, int breakSide, int breakStart, int breakStop);
+ virtual void SetInset(int left, int top, int right, int bottom);
+ virtual void GetInset(int &left, int &top, int &right, int &bottom);
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme, KeyValues *inResourceData);
+
+ virtual const char *GetName();
+ virtual void SetName(const char *name);
+ virtual backgroundtype_e GetBackgroundType();
+
+ virtual bool PaintFirst( void ) { return m_bPaintFirst; }
+
+protected:
+ void SetImage(const char *imageName);
+
+protected:
+ int _inset[4];
+
+private:
+ // protected copy constructor to prevent use
+ ImageBorder(ImageBorder&);
+
+ char *_name;
+
+ backgroundtype_e m_eBackgroundType;
+
+ friend class VPanel;
+
+ int m_iTextureID;
+ bool m_bTiled;
+
+ char *m_pszImageName;
+ bool m_bPaintFirst;
+};
+
+#endif // IMAGE_BORDER_H
diff --git a/vgui2/src/InputWin32.cpp b/vgui2/src/InputWin32.cpp
new file mode 100644
index 0000000..a9a037f
--- /dev/null
+++ b/vgui2/src/InputWin32.cpp
@@ -0,0 +1,3198 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#if defined( WIN32 ) && !defined( _X360 )
+#include <windows.h>
+#include <imm.h>
+#define DO_IME
+#endif
+
+#include <string.h>
+
+#include "vgui_internal.h"
+#include "VPanel.h"
+#include "utlvector.h"
+#include <KeyValues.h>
+#include "tier0/vcrmode.h"
+
+#include <vgui/VGUI.h>
+#include <vgui/ISystem.h>
+#include <vgui/IClientPanel.h>
+#include <vgui/IInputInternal.h>
+#include <vgui/IPanel.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/KeyCode.h>
+#include <vgui/MouseCode.h>
+#include "vgui/Cursor.h"
+#include <vgui/keyrepeat.h>
+
+#include "utllinkedlist.h"
+#include "tier0/icommandline.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+/*
+> Subject: RE: l4d2 & motd
+>
+> From: Alfred Reynolds
+> I'd go with the if it ain't broke don't touch it route, might as well
+> leave win32 as is and just knobble the asserts where we know we won't implement it.
+>
+>> From: Mike Sartain
+>> Well now that's interesting. Is it ok to remove it for win32 then?
+>>
+>>> From: Alfred Reynolds
+>>> We never did the IME work, AFAIK it only ever worked on the game's
+>>> console in game which isn't useful for users. So, no demand, hard
+>>> (actually, really hard) to implement so it wasn't done.
+>>>
+>>>> From: Mike Sartain
+>>>> There are also a bunch of IME Language functions in
+>>>> vgui2/src/inputwin32.cpp that are NYI on Linux as well - but it looks
+>>>> like those haven't ever been implemented on OSX either. Alfred, what
+>>>> is the story there?
+*/
+#if 0 // !defined( DO_IME ) && !defined( _X360 )
+#define ASSERT_IF_IME_NYI() Assert( !"IME Support NYI" )
+#else
+#define ASSERT_IF_IME_NYI()
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+bool IsDispatchingMessageQueue( void );
+
+using namespace vgui;
+
+class CInputSystem : public IInputInternal
+{
+public:
+ CInputSystem();
+ ~CInputSystem();
+
+ virtual void RunFrame();
+
+ virtual void PanelDeleted(VPANEL panel);
+
+ virtual void UpdateMouseFocus(int x, int y);
+ virtual void SetMouseFocus(VPANEL newMouseFocus);
+
+ virtual void SetCursorPos(int x, int y);
+ virtual void UpdateCursorPosInternal( int x, int y );
+ virtual void GetCursorPos(int &x, int &y);
+ virtual void SetCursorOveride(HCursor cursor);
+ virtual HCursor GetCursorOveride();
+
+
+ virtual void SetMouseCapture(VPANEL panel);
+
+ virtual VPANEL GetFocus();
+ virtual VPANEL GetCalculatedFocus();
+ virtual VPANEL GetMouseOver();
+
+ virtual bool WasMousePressed(MouseCode code);
+ virtual bool WasMouseDoublePressed(MouseCode code);
+ virtual bool IsMouseDown(MouseCode code);
+ virtual bool WasMouseReleased(MouseCode code);
+ virtual bool WasKeyPressed(KeyCode code);
+ virtual bool IsKeyDown(KeyCode code);
+ virtual bool WasKeyTyped(KeyCode code);
+ virtual bool WasKeyReleased(KeyCode code);
+
+ virtual void GetKeyCodeText(KeyCode code, char *buf, int buflen);
+
+ virtual bool InternalCursorMoved(int x,int y); //expects input in surface space
+ virtual bool InternalMousePressed(MouseCode code);
+ virtual bool InternalMouseDoublePressed(MouseCode code);
+ virtual bool InternalMouseReleased(MouseCode code);
+ virtual bool InternalMouseWheeled(int delta);
+ virtual bool InternalKeyCodePressed(KeyCode code);
+ virtual void InternalKeyCodeTyped(KeyCode code);
+ virtual void InternalKeyTyped(wchar_t unichar);
+ virtual bool InternalKeyCodeReleased(KeyCode code);
+ virtual void SetKeyCodeState( KeyCode code, bool bPressed );
+ virtual void SetMouseCodeState( MouseCode code, MouseCodeState_t state );
+ virtual void UpdateButtonState( const InputEvent_t &event );
+
+ virtual VPANEL GetAppModalSurface();
+ // set the modal dialog panel.
+ // all events will go only to this panel and its children.
+ virtual void SetAppModalSurface(VPANEL panel);
+ // release the modal dialog panel
+ // do this when your modal dialog finishes.
+ virtual void ReleaseAppModalSurface();
+
+ // returns true if the specified panel is a child of the current modal panel
+ // if no modal panel is set, then this always returns TRUE
+ virtual bool IsChildOfModalPanel(VPANEL panel, bool checkModalSubTree = true );
+
+ // Creates/ destroys "input" contexts, which contains information
+ // about which controls have mouse + key focus, for example.
+ virtual HInputContext CreateInputContext();
+ virtual void DestroyInputContext( HInputContext context );
+
+ // Associates a particular panel with an input context
+ // Associating NULL is valid; it disconnects the panel from the context
+ virtual void AssociatePanelWithInputContext( HInputContext context, VPANEL pRoot );
+
+ // Activates a particular input context, use DEFAULT_INPUT_CONTEXT
+ // to get the one normally used by VGUI
+ virtual void ActivateInputContext( HInputContext context );
+ virtual void PostCursorMessage( );
+ virtual void HandleExplicitSetCursor( );
+
+ virtual void ResetInputContext( HInputContext context );
+
+ virtual void GetCursorPosition( int &x, int &y );
+
+ virtual void SetIMEWindow( void *hwnd );
+ virtual void *GetIMEWindow();
+
+ // Change keyboard layout type
+ virtual void OnChangeIME( bool forward );
+ virtual int GetCurrentIMEHandle();
+ virtual int GetEnglishIMEHandle();
+
+ // Returns the Language Bar label (Chinese, Korean, Japanese, Russion, Thai, etc.)
+ virtual void GetIMELanguageName( wchar_t *buf, int unicodeBufferSizeInBytes );
+ // Returns the short code for the language (EN, CH, KO, JP, RU, TH, etc. ).
+ virtual void GetIMELanguageShortCode( wchar_t *buf, int unicodeBufferSizeInBytes );
+
+ // Call with NULL dest to get item count
+ virtual int GetIMELanguageList( LanguageItem *dest, int destcount );
+ virtual int GetIMEConversionModes( ConversionModeItem *dest, int destcount );
+ virtual int GetIMESentenceModes( SentenceModeItem *dest, int destcount );
+
+ virtual void OnChangeIMEByHandle( int handleValue );
+ virtual void OnChangeIMEConversionModeByHandle( int handleValue );
+ virtual void OnChangeIMESentenceModeByHandle( int handleValue );
+
+ virtual void OnInputLanguageChanged();
+ virtual void OnIMEStartComposition();
+ virtual void OnIMEComposition( int flags );
+ virtual void OnIMEEndComposition();
+
+ virtual void OnIMEShowCandidates();
+ virtual void OnIMEChangeCandidates();
+ virtual void OnIMECloseCandidates();
+
+ virtual void OnIMERecomputeModes();
+
+ virtual int GetCandidateListCount();
+ virtual void GetCandidate( int num, wchar_t *dest, int destSizeBytes );
+ virtual int GetCandidateListSelectedItem();
+ virtual int GetCandidateListPageSize();
+ virtual int GetCandidateListPageStart();
+
+ virtual void SetCandidateWindowPos( int x, int y );
+ virtual bool GetShouldInvertCompositionString();
+ virtual bool CandidateListStartsAtOne();
+
+ virtual void SetCandidateListPageStart( int start );
+
+ // Passes in a keycode which allows hitting other mouse buttons w/o cancelling capture mode
+ virtual void SetMouseCaptureEx(VPANEL panel, MouseCode captureStartMouseCode );
+
+ virtual void RegisterKeyCodeUnhandledListener( VPANEL panel );
+ virtual void UnregisterKeyCodeUnhandledListener( VPANEL panel );
+
+ // Posts unhandled message to all interested panels
+ virtual void OnKeyCodeUnhandled( int keyCode );
+
+ // Assumes subTree is a child panel of the root panel for the vgui contect
+ // if restrictMessagesToSubTree is true, then mouse and kb messages are only routed to the subTree and it's children and mouse/kb focus
+ // can only be on one of the subTree children, if a mouse click occurs outside of the subtree, and "UnhandledMouseClick" message is sent to unhandledMouseClickListener panel
+ // if it's set
+ // if restrictMessagesToSubTree is false, then mouse and kb messages are routed as normal except that they are not routed down into the subtree
+ // however, if a mouse click occurs outside of the subtree, and "UnhandleMouseClick" message is sent to unhandledMouseClickListener panel
+ // if it's set
+ virtual void SetModalSubTree( VPANEL subTree, VPANEL unhandledMouseClickListener, bool restrictMessagesToSubTree = true );
+ virtual void ReleaseModalSubTree();
+ virtual VPANEL GetModalSubTree();
+
+ // These toggle whether the modal subtree is exclusively receiving messages or conversely whether it's being excluded from receiving messages
+ virtual void SetModalSubTreeReceiveMessages( bool state );
+ virtual bool ShouldModalSubTreeReceiveMessages() const;
+
+ virtual VPANEL GetMouseCapture();
+
+ virtual VPANEL GetMouseFocus();
+private:
+
+ VPanel *GetMouseFocusIgnoringModalSubtree();
+
+ void InternalSetCompositionString( const wchar_t *compstr );
+ void InternalShowCandidateWindow();
+ void InternalHideCandidateWindow();
+ void InternalUpdateCandidateWindow();
+
+ bool PostKeyMessage(KeyValues *message);
+
+ void DestroyCandidateList();
+ void CreateNewCandidateList();
+
+ VPanel *CalculateNewKeyFocus();
+
+ void PostModalSubTreeMessage( VPanel *subTree, bool state );
+ // returns true if the specified panel is a child of the current modal panel
+ // if no modal panel is set, then this always returns TRUE
+ bool IsChildOfModalSubTree(VPANEL panel);
+
+ void SurfaceSetCursorPos( int x, int y );
+ void SurfaceGetCursorPos( int &x, int &y );
+
+ struct InputContext_t
+ {
+ VPANEL _rootPanel;
+
+ bool _mousePressed[MOUSE_COUNT];
+ bool _mouseDoublePressed[MOUSE_COUNT];
+ bool _mouseDown[MOUSE_COUNT];
+ bool _mouseReleased[MOUSE_COUNT];
+ bool _keyPressed[BUTTON_CODE_COUNT];
+ bool _keyTyped[BUTTON_CODE_COUNT];
+ bool _keyDown[BUTTON_CODE_COUNT];
+ bool _keyReleased[BUTTON_CODE_COUNT];
+
+ VPanel *_keyFocus;
+ VPanel *_oldMouseFocus;
+ VPanel *_mouseFocus; // the panel that has the current mouse focus - same as _mouseOver unless _mouseCapture is set
+ VPanel *_mouseOver; // the panel that the mouse is currently over, NULL if not over any vgui item
+
+ VPanel *_mouseCapture; // the panel that has currently captured mouse focus
+ MouseCode m_MouseCaptureStartCode; // The Mouse button which was pressed to initiate mouse capture
+ VPanel *_appModalPanel; // the modal dialog panel.
+
+ int m_nCursorX;
+ int m_nCursorY;
+
+ int m_nLastPostedCursorX;
+ int m_nLastPostedCursorY;
+
+ int m_nExternallySetCursorX;
+ int m_nExternallySetCursorY;
+ bool m_bSetCursorExplicitly;
+
+ CUtlVector< VPanel * > m_KeyCodeUnhandledListeners;
+
+ VPanel *m_pModalSubTree;
+ VPanel *m_pUnhandledMouseClickListener;
+ bool m_bRestrictMessagesToModalSubTree;
+
+ CKeyRepeatHandler m_keyRepeater;
+ };
+
+ void InitInputContext( InputContext_t *pContext );
+ InputContext_t *GetInputContext( HInputContext context );
+ void PanelDeleted(VPANEL focus, InputContext_t &context);
+
+ HCursor _cursorOverride;
+
+ const char *_keyTrans[KEY_LAST];
+
+ InputContext_t m_DefaultInputContext;
+ HInputContext m_hContext; // current input context
+
+ CUtlLinkedList< InputContext_t, HInputContext > m_Contexts;
+
+#ifdef DO_IME
+ void *_imeWnd;
+ CANDIDATELIST *_imeCandidates;
+#endif
+
+ int m_nDebugMessages;
+};
+
+CInputSystem g_Input;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CInputSystem, IInput, VGUI_INPUT_INTERFACE_VERSION, g_Input); // export IInput to everyone else, not IInputInternal!
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CInputSystem, IInputInternal, VGUI_INPUTINTERNAL_INTERFACE_VERSION, g_Input); // for use in external surfaces only! (like the engine surface)
+
+namespace vgui
+{
+vgui::IInputInternal *g_pInput = &g_Input;
+}
+
+
+CInputSystem::CInputSystem()
+{
+ m_nDebugMessages = -1;
+#ifdef DO_IME
+ _imeWnd = null;
+ _imeCandidates = null;
+#endif
+ InitInputContext( &m_DefaultInputContext );
+ m_hContext = DEFAULT_INPUT_CONTEXT;
+
+ // build key to text translation table
+ // first byte unshifted key
+ // second byte shifted key
+ // the rest is the name of the key
+ _keyTrans[KEY_0] ="0)KEY_0";
+ _keyTrans[KEY_1] ="1!KEY_1";
+ _keyTrans[KEY_2] ="2@KEY_2";
+ _keyTrans[KEY_3] ="3#KEY_3";
+ _keyTrans[KEY_4] ="4$KEY_4";
+ _keyTrans[KEY_5] ="5%KEY_5";
+ _keyTrans[KEY_6] ="6^KEY_6";
+ _keyTrans[KEY_7] ="7&KEY_7";
+ _keyTrans[KEY_8] ="8*KEY_8";
+ _keyTrans[KEY_9] ="9(KEY_9";
+ _keyTrans[KEY_A] ="aAKEY_A";
+ _keyTrans[KEY_B] ="bBKEY_B";
+ _keyTrans[KEY_C] ="cCKEY_C";
+ _keyTrans[KEY_D] ="dDKEY_D";
+ _keyTrans[KEY_E] ="eEKEY_E";
+ _keyTrans[KEY_F] ="fFKEY_F";
+ _keyTrans[KEY_G] ="gGKEY_G";
+ _keyTrans[KEY_H] ="hHKEY_H";
+ _keyTrans[KEY_I] ="iIKEY_I";
+ _keyTrans[KEY_J] ="jJKEY_J";
+ _keyTrans[KEY_K] ="kKKEY_K";
+ _keyTrans[KEY_L] ="lLKEY_L"", L";
+ _keyTrans[KEY_M] ="mMKEY_M";
+ _keyTrans[KEY_N] ="nNKEY_N";
+ _keyTrans[KEY_O] ="oOKEY_O";
+ _keyTrans[KEY_P] ="pPKEY_P";
+ _keyTrans[KEY_Q] ="qQKEY_Q";
+ _keyTrans[KEY_R] ="rRKEY_R";
+ _keyTrans[KEY_S] ="sSKEY_S";
+ _keyTrans[KEY_T] ="tTKEY_T";
+ _keyTrans[KEY_U] ="uUKEY_U";
+ _keyTrans[KEY_V] ="vVKEY_V";
+ _keyTrans[KEY_W] ="wWKEY_W";
+ _keyTrans[KEY_X] ="xXKEY_X";
+ _keyTrans[KEY_Y] ="yYKEY_Y";
+ _keyTrans[KEY_Z] ="zZKEY_Z";
+ _keyTrans[KEY_PAD_0] ="0\0KEY_PAD_0";
+ _keyTrans[KEY_PAD_1] ="1\0KEY_PAD_1";
+ _keyTrans[KEY_PAD_2] ="2\0KEY_PAD_2";
+ _keyTrans[KEY_PAD_3] ="3\0KEY_PAD_3";
+ _keyTrans[KEY_PAD_4] ="4\0KEY_PAD_4";
+ _keyTrans[KEY_PAD_5] ="5\0KEY_PAD_5";
+ _keyTrans[KEY_PAD_6] ="6\0KEY_PAD_6";
+ _keyTrans[KEY_PAD_7] ="7\0KEY_PAD_7";
+ _keyTrans[KEY_PAD_8] ="8\0KEY_PAD_8";
+ _keyTrans[KEY_PAD_9] ="9\0KEY_PAD_9";
+ _keyTrans[KEY_PAD_DIVIDE] ="//KEY_PAD_DIVIDE";
+ _keyTrans[KEY_PAD_MULTIPLY] ="**KEY_PAD_MULTIPLY";
+ _keyTrans[KEY_PAD_MINUS] ="--KEY_PAD_MINUS";
+ _keyTrans[KEY_PAD_PLUS] ="++KEY_PAD_PLUS";
+ _keyTrans[KEY_PAD_ENTER] ="\0\0KEY_PAD_ENTER";
+ _keyTrans[KEY_PAD_DECIMAL] =".\0KEY_PAD_DECIMAL"", L";
+ _keyTrans[KEY_LBRACKET] ="[{KEY_LBRACKET";
+ _keyTrans[KEY_RBRACKET] ="]}KEY_RBRACKET";
+ _keyTrans[KEY_SEMICOLON] =";:KEY_SEMICOLON";
+ _keyTrans[KEY_APOSTROPHE] ="'\"KEY_APOSTROPHE";
+ _keyTrans[KEY_BACKQUOTE] ="`~KEY_BACKQUOTE";
+ _keyTrans[KEY_COMMA] =",<KEY_COMMA";
+ _keyTrans[KEY_PERIOD] =".>KEY_PERIOD";
+ _keyTrans[KEY_SLASH] ="/?KEY_SLASH";
+ _keyTrans[KEY_BACKSLASH] ="\\|KEY_BACKSLASH";
+ _keyTrans[KEY_MINUS] ="-_KEY_MINUS";
+ _keyTrans[KEY_EQUAL] ="=+KEY_EQUAL"", L";
+ _keyTrans[KEY_ENTER] ="\0\0KEY_ENTER";
+ _keyTrans[KEY_SPACE] =" KEY_SPACE";
+ _keyTrans[KEY_BACKSPACE] ="\0\0KEY_BACKSPACE";
+ _keyTrans[KEY_TAB] ="\0\0KEY_TAB";
+ _keyTrans[KEY_CAPSLOCK] ="\0\0KEY_CAPSLOCK";
+ _keyTrans[KEY_NUMLOCK] ="\0\0KEY_NUMLOCK";
+ _keyTrans[KEY_ESCAPE] ="\0\0KEY_ESCAPE";
+ _keyTrans[KEY_SCROLLLOCK] ="\0\0KEY_SCROLLLOCK";
+ _keyTrans[KEY_INSERT] ="\0\0KEY_INSERT";
+ _keyTrans[KEY_DELETE] ="\0\0KEY_DELETE";
+ _keyTrans[KEY_HOME] ="\0\0KEY_HOME";
+ _keyTrans[KEY_END] ="\0\0KEY_END";
+ _keyTrans[KEY_PAGEUP] ="\0\0KEY_PAGEUP";
+ _keyTrans[KEY_PAGEDOWN] ="\0\0KEY_PAGEDOWN";
+ _keyTrans[KEY_BREAK] ="\0\0KEY_BREAK";
+ _keyTrans[KEY_LSHIFT] ="\0\0KEY_LSHIFT";
+ _keyTrans[KEY_RSHIFT] ="\0\0KEY_RSHIFT";
+ _keyTrans[KEY_LALT] ="\0\0KEY_LALT";
+ _keyTrans[KEY_RALT] ="\0\0KEY_RALT";
+ _keyTrans[KEY_LCONTROL] ="\0\0KEY_LCONTROL"", L";
+ _keyTrans[KEY_RCONTROL] ="\0\0KEY_RCONTROL"", L";
+ _keyTrans[KEY_LWIN] ="\0\0KEY_LWIN";
+ _keyTrans[KEY_RWIN] ="\0\0KEY_RWIN";
+ _keyTrans[KEY_APP] ="\0\0KEY_APP";
+ _keyTrans[KEY_UP] ="\0\0KEY_UP";
+ _keyTrans[KEY_LEFT] ="\0\0KEY_LEFT";
+ _keyTrans[KEY_DOWN] ="\0\0KEY_DOWN";
+ _keyTrans[KEY_RIGHT] ="\0\0KEY_RIGHT";
+ _keyTrans[KEY_F1] ="\0\0KEY_F1";
+ _keyTrans[KEY_F2] ="\0\0KEY_F2";
+ _keyTrans[KEY_F3] ="\0\0KEY_F3";
+ _keyTrans[KEY_F4] ="\0\0KEY_F4";
+ _keyTrans[KEY_F5] ="\0\0KEY_F5";
+ _keyTrans[KEY_F6] ="\0\0KEY_F6";
+ _keyTrans[KEY_F7] ="\0\0KEY_F7";
+ _keyTrans[KEY_F8] ="\0\0KEY_F8";
+ _keyTrans[KEY_F9] ="\0\0KEY_F9";
+ _keyTrans[KEY_F10] ="\0\0KEY_F10";
+ _keyTrans[KEY_F11] ="\0\0KEY_F11";
+ _keyTrans[KEY_F12] ="\0\0KEY_F12";
+}
+
+CInputSystem::~CInputSystem()
+{
+ DestroyCandidateList();
+}
+
+//-----------------------------------------------------------------------------
+// Resets an input context
+//-----------------------------------------------------------------------------
+void CInputSystem::InitInputContext( InputContext_t *pContext )
+{
+ pContext->_rootPanel = NULL;
+ pContext->_keyFocus = NULL;
+ pContext->_oldMouseFocus = NULL;
+ pContext->_mouseFocus = NULL;
+ pContext->_mouseOver = NULL;
+ pContext->_mouseCapture = NULL;
+ pContext->_appModalPanel = NULL;
+
+ pContext->m_nCursorX = pContext->m_nCursorY = 0;
+ pContext->m_nLastPostedCursorX = pContext->m_nLastPostedCursorY = -9999;
+ pContext->m_nExternallySetCursorX = pContext->m_nExternallySetCursorY = 0;
+ pContext->m_bSetCursorExplicitly = false;
+
+ // zero mouse and keys
+ memset(pContext->_mousePressed, 0, sizeof(pContext->_mousePressed));
+ memset(pContext->_mouseDoublePressed, 0, sizeof(pContext->_mouseDoublePressed));
+ memset(pContext->_mouseDown, 0, sizeof(pContext->_mouseDown));
+ memset(pContext->_mouseReleased, 0, sizeof(pContext->_mouseReleased));
+ memset(pContext->_keyPressed, 0, sizeof(pContext->_keyPressed));
+ memset(pContext->_keyTyped, 0, sizeof(pContext->_keyTyped));
+ memset(pContext->_keyDown, 0, sizeof(pContext->_keyDown));
+ memset(pContext->_keyReleased, 0, sizeof(pContext->_keyReleased));
+
+ pContext->m_MouseCaptureStartCode = (MouseCode)-1;
+
+ pContext->m_KeyCodeUnhandledListeners.RemoveAll();
+
+ pContext->m_pModalSubTree = NULL;
+ pContext->m_pUnhandledMouseClickListener = NULL;
+ pContext->m_bRestrictMessagesToModalSubTree = false;
+}
+
+void CInputSystem::ResetInputContext( HInputContext context )
+{
+ // FIXME: Needs to release various keys, mouse buttons, etc...?
+ // At least needs to cause things to lose focus
+ InitInputContext( GetInputContext(context) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates/ destroys "input" contexts, which contains information
+// about which controls have mouse + key focus, for example.
+//-----------------------------------------------------------------------------
+HInputContext CInputSystem::CreateInputContext()
+{
+ HInputContext i = m_Contexts.AddToTail();
+ InitInputContext( &m_Contexts[i] );
+ return i;
+}
+
+void CInputSystem::DestroyInputContext( HInputContext context )
+{
+ Assert( context != DEFAULT_INPUT_CONTEXT );
+ if ( m_hContext == context )
+ {
+ ActivateInputContext( DEFAULT_INPUT_CONTEXT );
+ }
+ m_Contexts.Remove(context);
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the current input context
+//-----------------------------------------------------------------------------
+CInputSystem::InputContext_t *CInputSystem::GetInputContext( HInputContext context )
+{
+ if (context == DEFAULT_INPUT_CONTEXT)
+ return &m_DefaultInputContext;
+ return &m_Contexts[context];
+}
+
+
+//-----------------------------------------------------------------------------
+// Associates a particular panel with an input context
+// Associating NULL is valid; it disconnects the panel from the context
+//-----------------------------------------------------------------------------
+void CInputSystem::AssociatePanelWithInputContext( HInputContext context, VPANEL pRoot )
+{
+ // Changing the root panel should invalidate keysettings, etc.
+ if (GetInputContext(context)->_rootPanel != pRoot)
+ {
+ ResetInputContext( context );
+ GetInputContext(context)->_rootPanel = pRoot;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Activates a particular input context, use DEFAULT_INPUT_CONTEXT
+// to get the one normally used by VGUI
+//-----------------------------------------------------------------------------
+void CInputSystem::ActivateInputContext( HInputContext context )
+{
+ Assert( (context == DEFAULT_INPUT_CONTEXT) || m_Contexts.IsValidIndex(context) );
+ m_hContext = context;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInputSystem::RunFrame()
+{
+ if ( m_nDebugMessages == -1 )
+ {
+ m_nDebugMessages = CommandLine()->FindParm( "-vguifocus" ) ? 1 : 0;
+ }
+
+ InputContext_t *pContext = GetInputContext(m_hContext);
+
+ // tick whoever has the focus
+ if (pContext->_keyFocus)
+ {
+ // when modal dialogs are up messages only get sent to the dialogs children.
+ if (IsChildOfModalPanel((VPANEL)pContext->_keyFocus))
+ {
+ g_pIVgui->PostMessage((VPANEL)pContext->_keyFocus, new KeyValues("KeyFocusTicked"), NULL);
+ }
+ }
+
+ // tick whoever has the focus
+ if (pContext->_mouseFocus)
+ {
+ // when modal dialogs are up messages only get sent to the dialogs children.
+ if (IsChildOfModalPanel((VPANEL)pContext->_mouseFocus))
+ {
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseFocusTicked"), NULL);
+ }
+ }
+ // Mouse has wandered "off" the modal panel, just force a regular arrow cursor until it wanders back within the proper bounds
+ else if ( pContext->_appModalPanel )
+ {
+ g_pSurface->SetCursor( vgui::dc_arrow );
+ }
+
+ //clear mouse and key states
+ int i;
+ for (i = 0; i < MOUSE_COUNT; i++)
+ {
+ pContext->_mousePressed[i] = 0;
+ pContext->_mouseDoublePressed[i] = 0;
+ pContext->_mouseReleased[i] = 0;
+ }
+ for (i = 0; i < BUTTON_CODE_COUNT; i++)
+ {
+ pContext->_keyPressed[i] = 0;
+ pContext->_keyTyped[i] = 0;
+ pContext->_keyReleased[i] = 0;
+ }
+
+ VPanel *wantedKeyFocus = CalculateNewKeyFocus();
+
+ // make sure old and new focus get painted
+ if (pContext->_keyFocus != wantedKeyFocus)
+ {
+ if (pContext->_keyFocus != NULL)
+ {
+ pContext->_keyFocus->Client()->InternalFocusChanged(true);
+
+ // there may be out of order operations here, since we're directly calling SendMessage,
+ // but we need to have focus messages happen immediately, since otherwise mouse events
+ // happen out of order - more specifically, they happen before the focus changes
+
+ // send a message to the window saying that it's losing focus
+ {
+ MEM_ALLOC_CREDIT();
+ KeyValues *pMessage = new KeyValues( "KillFocus" );
+ KeyValues::AutoDelete autodelete_pMessage( pMessage );
+ pMessage->SetPtr( "newPanel", wantedKeyFocus );
+ pContext->_keyFocus->SendMessage( pMessage, 0 );
+ }
+
+ if ( pContext->_keyFocus )
+ {
+ pContext->_keyFocus->Client()->Repaint();
+ }
+
+ // repaint the nearest popup as well, since it will need to redraw after losing focus
+ VPanel *dlg = pContext->_keyFocus;
+ while (dlg && !dlg->IsPopup())
+ {
+ dlg = dlg->GetParent();
+ }
+ if (dlg)
+ {
+ dlg->Client()->Repaint();
+ }
+ }
+ if (wantedKeyFocus != NULL)
+ {
+ wantedKeyFocus->Client()->InternalFocusChanged(false);
+
+ // there may be out of order operations here, since we're directly calling SendMessage,
+ // but we need to have focus messages happen immediately, since otherwise mouse events
+ // happen out of order - more specifically, they happen before the focus changes
+
+ // send a message to the window saying that it's gaining focus
+ {
+ MEM_ALLOC_CREDIT();
+ KeyValues *pMsg = new KeyValues("SetFocus");
+ KeyValues::AutoDelete autodelete_pMsg( pMsg );
+ wantedKeyFocus->SendMessage( pMsg, 0 );
+ }
+ wantedKeyFocus->Client()->Repaint();
+
+ // repaint the nearest popup as well, since it will need to redraw after gaining focus
+ VPanel *dlg = wantedKeyFocus;
+ while (dlg && !dlg->IsPopup())
+ {
+ dlg = dlg->GetParent();
+ }
+ if (dlg)
+ {
+ dlg->Client()->Repaint();
+ }
+ }
+
+ if ( m_nDebugMessages > 0 )
+ {
+ g_pIVgui->DPrintf2( "changing kb focus from %s to %s\n",
+ pContext->_keyFocus ? pContext->_keyFocus->GetName() : "(no name)",
+ wantedKeyFocus ? wantedKeyFocus->GetName() : "(no name)" );
+ }
+
+ // accept the focus request
+ pContext->_keyFocus = wantedKeyFocus;
+ if (pContext->_keyFocus)
+ {
+ pContext->_keyFocus->MoveToFront();
+ }
+ }
+
+ // Pump any key repeats
+ KeyCode repeatCode = pContext->m_keyRepeater.KeyRepeated();
+ if (repeatCode)
+ {
+ InternalKeyCodePressed( repeatCode );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate the new key focus
+//-----------------------------------------------------------------------------
+VPanel *CInputSystem::CalculateNewKeyFocus()
+{
+ InputContext_t *pContext = GetInputContext(m_hContext);
+
+ // get the top-order panel
+ VPanel *wantedKeyFocus = NULL;
+
+ VPanel *pRoot = (VPanel *)pContext->_rootPanel;
+ VPanel *top = pRoot;
+ if ( g_pSurface->GetPopupCount() > 0 )
+ {
+ // find the highest-level window that is both visible and a popup
+ int nIndex = g_pSurface->GetPopupCount();
+
+ while ( nIndex )
+ {
+ top = (VPanel *)g_pSurface->GetPopup( --nIndex );
+
+ // traverse the hierarchy and check if the popup really is visible
+ if (top &&
+ // top->IsPopup() && // These are right out of of the popups list!!!
+ top->IsVisible() &&
+ top->IsKeyBoardInputEnabled() &&
+ !g_pSurface->IsMinimized((VPANEL)top) &&
+ IsChildOfModalSubTree( (VPANEL)top ) &&
+ (!pRoot || top->HasParent( pRoot )) )
+ {
+ bool bIsVisible = top->IsVisible();
+ VPanel *p = top->GetParent();
+ // drill down the hierarchy checking that everything is visible
+ while(p && bIsVisible)
+ {
+ if( p->IsVisible()==false)
+ {
+ bIsVisible = false;
+ break;
+ }
+ p=p->GetParent();
+ }
+
+ if ( bIsVisible && !g_pSurface->IsMinimized( (VPANEL)top ) )
+ break;
+ }
+
+ top = pRoot;
+ }
+ }
+
+ if (top)
+ {
+ // ask the top-level panel for what it considers to be the current focus
+ wantedKeyFocus = (VPanel *)top->Client()->GetCurrentKeyFocus();
+ if (!wantedKeyFocus)
+ {
+ wantedKeyFocus = top;
+ }
+ }
+
+ // check to see if any of this surfaces panels have the focus
+ if (!g_pSurface->HasFocus())
+ {
+ wantedKeyFocus=NULL;
+ }
+
+ // check if we are in modal state,
+ // and if we are make sure this panel is a child of us.
+ if (!IsChildOfModalPanel((VPANEL)wantedKeyFocus))
+ {
+ wantedKeyFocus=NULL;
+ }
+
+ return wantedKeyFocus;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInputSystem::PanelDeleted(VPANEL vfocus, InputContext_t &context)
+{
+ VPanel *focus = (VPanel *)vfocus;
+ if (context._keyFocus == focus)
+ {
+ if ( m_nDebugMessages > 0 )
+ {
+ g_pIVgui->DPrintf2( "removing kb focus %s\n",
+ context._keyFocus ? context._keyFocus->GetName() : "(no name)" );
+ }
+ context._keyFocus = NULL;
+ }
+ if (context._mouseOver == focus)
+ {
+ /*
+ if ( m_nDebugMessages > 0 )
+ {
+ g_pIVgui->DPrintf2( "removing kb focus %s\n",
+ context._keyFocus ? pcontext._keyFocus->GetName() : "(no name)" );
+ }
+ */
+ context._mouseOver = NULL;
+ }
+ if (context._oldMouseFocus == focus)
+ {
+ context._oldMouseFocus = NULL;
+ }
+ if (context._mouseFocus == focus)
+ {
+ context._mouseFocus = NULL;
+ }
+
+ // NOTE: These two will only ever happen for the default context at the moment
+ if (context._mouseCapture == focus)
+ {
+ SetMouseCapture(NULL);
+ context._mouseCapture = NULL;
+ }
+ if (context._appModalPanel == focus)
+ {
+ ReleaseAppModalSurface();
+ }
+ if ( context.m_pUnhandledMouseClickListener == focus )
+ {
+ context.m_pUnhandledMouseClickListener = NULL;
+ }
+ if ( context.m_pModalSubTree == focus )
+ {
+ context.m_pModalSubTree = NULL;
+ context.m_bRestrictMessagesToModalSubTree = false;
+ }
+
+ context.m_KeyCodeUnhandledListeners.FindAndRemove( focus );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *focus -
+//-----------------------------------------------------------------------------
+void CInputSystem::PanelDeleted(VPANEL focus)
+{
+ HInputContext i;
+ for (i = m_Contexts.Head(); i != m_Contexts.InvalidIndex(); i = m_Contexts.Next(i) )
+ {
+ PanelDeleted( focus, m_Contexts[i] );
+ }
+ PanelDeleted( focus, m_DefaultInputContext );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the new mouse focus
+// won't override _mouseCapture settings
+// Input : newMouseFocus -
+//-----------------------------------------------------------------------------
+void CInputSystem::SetMouseFocus(VPANEL newMouseFocus)
+{
+ // check if we are in modal state,
+ // and if we are make sure this panel is a child of us.
+ if (!IsChildOfModalPanel(newMouseFocus))
+ {
+ return;
+ }
+
+ bool wantsMouse, isPopup; // = popup->GetMouseInput();
+ VPanel *panel = (VPanel *)newMouseFocus;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+
+ wantsMouse = false;
+ if ( newMouseFocus )
+ {
+ do
+ {
+ wantsMouse = panel->IsMouseInputEnabled();
+ isPopup = panel->IsPopup();
+ panel = panel->GetParent();
+ }
+ while ( wantsMouse && !isPopup && panel && panel->GetParent() ); // only consider panels that want mouse input
+ }
+
+ // if this panel doesn't want mouse input don't let it get focus
+ if (newMouseFocus && !wantsMouse)
+ {
+ return;
+ }
+
+ if ((VPANEL)pContext->_mouseOver != newMouseFocus || (!pContext->_mouseCapture && (VPANEL)pContext->_mouseFocus != newMouseFocus) )
+ {
+ pContext->_oldMouseFocus = pContext->_mouseOver;
+ pContext->_mouseOver = (VPanel *)newMouseFocus;
+
+ //tell the old panel with the mouseFocus that the cursor exited
+ if ( pContext->_oldMouseFocus != NULL )
+ {
+ // only notify of entry if the mouse is not captured or we're the captured panel
+ if ( !pContext->_mouseCapture || pContext->_oldMouseFocus == pContext->_mouseCapture )
+ {
+ g_pIVgui->PostMessage( (VPANEL)pContext->_oldMouseFocus, new KeyValues( "CursorExited" ), NULL );
+ }
+ }
+
+ //tell the new panel with the mouseFocus that the cursor entered
+ if ( pContext->_mouseOver != NULL )
+ {
+ // only notify of entry if the mouse is not captured or we're the captured panel
+ if ( !pContext->_mouseCapture || pContext->_mouseOver == pContext->_mouseCapture )
+ {
+ g_pIVgui->PostMessage( (VPANEL)pContext->_mouseOver, new KeyValues( "CursorEntered" ), NULL );
+ }
+ }
+
+ // set where the mouse is currently over
+ // mouse capture overrides destination
+ VPanel *newFocus = pContext->_mouseCapture ? pContext->_mouseCapture : pContext->_mouseOver;
+
+ if ( m_nDebugMessages > 0 )
+ {
+ g_pIVgui->DPrintf2( "changing mouse focus from %s to %s\n",
+ pContext->_mouseFocus ? pContext->_mouseFocus->GetName() : "(no name)",
+ newFocus ? newFocus->GetName() : "(no name)" );
+ }
+
+
+ pContext->_mouseFocus = newFocus;
+ }
+}
+
+VPanel *CInputSystem::GetMouseFocusIgnoringModalSubtree()
+{
+ // find the panel that has the focus
+ VPanel *focus = NULL;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+
+ int x, y;
+ x = pContext->m_nCursorX;
+ y = pContext->m_nCursorY;
+
+ if (!pContext->_rootPanel)
+ {
+ if (g_pSurface->IsCursorVisible() && g_pSurface->IsWithin(x, y))
+ {
+ // faster version of code below
+ // checks through each popup in order, top to bottom windows
+ for (int i = g_pSurface->GetPopupCount() - 1; i >= 0; i--)
+ {
+ VPanel *popup = (VPanel *)g_pSurface->GetPopup(i);
+ VPanel *panel = popup;
+ bool wantsMouse = panel->IsMouseInputEnabled();
+ bool isVisible = !g_pSurface->IsMinimized((VPANEL)panel);
+
+ while ( isVisible && panel && panel->GetParent() ) // only consider panels that want mouse input
+ {
+ isVisible = panel->IsVisible();
+ panel = panel->GetParent();
+ }
+
+
+ if ( wantsMouse && isVisible )
+ {
+ focus = (VPanel *)popup->Client()->IsWithinTraverse(x, y, false);
+ if (focus)
+ break;
+ }
+ }
+ if (!focus)
+ {
+ focus = (VPanel *)((VPanel *)g_pSurface->GetEmbeddedPanel())->Client()->IsWithinTraverse(x, y, false);
+ }
+ }
+ }
+ else
+ {
+ focus = (VPanel *)((VPanel *)(pContext->_rootPanel))->Client()->IsWithinTraverse(x, y, false);
+ }
+
+
+ // check if we are in modal state,
+ // and if we are make sure this panel is a child of us.
+ if ( !IsChildOfModalPanel((VPANEL)focus, false ))
+ {
+ // should this be _appModalPanel?
+ focus = NULL;
+ }
+
+ return focus;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculates which panel the cursor is currently over and sets it up
+// as the current mouse focus.
+//-----------------------------------------------------------------------------
+void CInputSystem::UpdateMouseFocus(int x, int y)
+{
+ // find the panel that has the focus
+ VPanel *focus = NULL;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+
+ if (g_pSurface->IsCursorVisible() && g_pSurface->IsWithin(x, y))
+ {
+ // faster version of code below
+ // checks through each popup in order, top to bottom windows
+ int c = g_pSurface->GetPopupCount();
+ for (int i = c - 1; i >= 0; i--)
+ {
+ VPanel *popup = (VPanel *)g_pSurface->GetPopup(i);
+ VPanel *panel = popup;
+
+ if ( pContext->_rootPanel && !popup->HasParent((VPanel*)pContext->_rootPanel) )
+ {
+ // if we have a root panel, only consider popups that belong to it
+ continue;
+ }
+#if defined( _DEBUG )
+ char const *pchName = popup->GetName();
+ NOTE_UNUSED( pchName );
+#endif
+ bool wantsMouse = panel->IsMouseInputEnabled() && IsChildOfModalSubTree( (VPANEL)panel );
+ if ( !wantsMouse )
+ continue;
+
+ bool isVisible = !g_pSurface->IsMinimized((VPANEL)panel);
+ if ( !isVisible )
+ continue;
+
+ while ( isVisible && panel && panel->GetParent() ) // only consider panels that want mouse input
+ {
+ isVisible = panel->IsVisible();
+ panel = panel->GetParent();
+ }
+
+
+ if ( !wantsMouse || !isVisible )
+ continue;
+
+ focus = (VPanel *)popup->Client()->IsWithinTraverse(x, y, false);
+ if (focus)
+ break;
+ }
+ if (!focus)
+ {
+ focus = (VPanel *)((VPanel *)g_pSurface->GetEmbeddedPanel())->Client()->IsWithinTraverse(x, y, false);
+ }
+ }
+
+ // mouse focus debugging code
+ /*
+ static VPanel *oldFocus = (VPanel *)0x0001;
+ if (oldFocus != focus)
+ {
+ oldFocus = focus;
+ if (focus)
+ {
+ g_pIVgui->DPrintf2("mouse over: (%s, %s)\n", focus->GetName(), focus->GetClassName());
+ }
+ else
+ {
+ g_pIVgui->DPrintf2("mouse over: (NULL)\n");
+ }
+ }
+ */
+
+ // check if we are in modal state,
+ // and if we are make sure this panel is a child of us.
+ if (!IsChildOfModalPanel((VPANEL)focus))
+ {
+ // should this be _appModalPanel?
+ focus = NULL;
+ }
+
+ SetMouseFocus((VPANEL)focus);
+}
+
+// Passes in a keycode which allows hitting other mouse buttons w/o cancelling capture mode
+void CInputSystem::SetMouseCaptureEx(VPANEL panel, MouseCode captureStartMouseCode )
+{
+ // This sets m_MouseCaptureStartCode to -1, so we set the real value afterward
+ SetMouseCapture( panel );
+
+ // check if we are in modal state,
+ // and if we are make sure this panel is a child of us.
+ if (!IsChildOfModalPanel(panel))
+ {
+ return;
+ }
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ Assert( pContext );
+ pContext->m_MouseCaptureStartCode = captureStartMouseCode;
+}
+
+VPANEL CInputSystem::GetMouseCapture()
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ return (VPANEL)pContext->_mouseCapture;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets or releases the mouse capture
+// Input : panel - pointer to the panel to get mouse capture
+// a NULL panel means that you want to clear the mouseCapture
+// MouseCaptureLost is sent to the panel that loses the mouse capture
+//-----------------------------------------------------------------------------
+void CInputSystem::SetMouseCapture(VPANEL panel)
+{
+ // check if we are in modal state,
+ // and if we are make sure this panel is a child of us.
+ if (!IsChildOfModalPanel(panel))
+ {
+ return;
+ }
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ Assert( pContext );
+
+ pContext->m_MouseCaptureStartCode = (MouseCode)-1;
+
+ // send a message if the panel is losing mouse capture
+ if (pContext->_mouseCapture && panel != (VPANEL)pContext->_mouseCapture)
+ {
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("MouseCaptureLost"), NULL);
+ }
+
+ if (panel == NULL)
+ {
+ if (pContext->_mouseCapture != NULL)
+ {
+ g_pSurface->EnableMouseCapture((VPANEL)pContext->_mouseCapture, false);
+ }
+ }
+ else
+ {
+ g_pSurface->EnableMouseCapture(panel, true);
+ }
+
+ pContext->_mouseCapture = (VPanel *)panel;
+}
+
+// returns true if the specified panel is a child of the current modal panel
+// if no modal panel is set, then this always returns TRUE
+bool CInputSystem::IsChildOfModalSubTree(VPANEL panel)
+{
+ if ( !panel )
+ return true;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ( pContext->m_pModalSubTree )
+ {
+ // If panel is child of modal subtree, the allow messages to route to it if restrict messages is set
+ bool isChildOfModal = ((VPanel *)panel)->HasParent(pContext->m_pModalSubTree );
+ if ( isChildOfModal )
+ {
+ return pContext->m_bRestrictMessagesToModalSubTree;
+ }
+ // If panel is not a child of modal subtree, then only allow messages if we're not restricting them to the modal subtree
+ else
+ {
+ return !pContext->m_bRestrictMessagesToModalSubTree;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: check if we are in modal state,
+// and if we are make sure this panel has the modal panel as a parent
+//-----------------------------------------------------------------------------
+bool CInputSystem::IsChildOfModalPanel(VPANEL panel, bool checkModalSubTree /*= true*/ )
+{
+ // NULL is ok.
+ if (!panel)
+ return true;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+
+ // if we are in modal state, make sure this panel is a child of us.
+ if (pContext->_appModalPanel)
+ {
+ if (!((VPanel *)panel)->HasParent(pContext->_appModalPanel))
+ {
+ return false;
+ }
+ }
+
+ if ( !checkModalSubTree )
+ return true;
+
+ // Defer to modal subtree logic instead...
+ return IsChildOfModalSubTree( panel );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VPANEL CInputSystem::GetFocus()
+{
+ return (VPANEL)( GetInputContext( m_hContext )->_keyFocus );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VPANEL CInputSystem::GetCalculatedFocus()
+{
+ return (VPANEL) CalculateNewKeyFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VPANEL CInputSystem::GetMouseOver()
+{
+ return (VPANEL)( GetInputContext( m_hContext )->_mouseOver );
+}
+
+VPANEL CInputSystem::GetMouseFocus()
+{
+ return (VPANEL)( GetInputContext( m_hContext )->_mouseFocus );
+}
+
+bool CInputSystem::WasMousePressed( MouseCode code )
+{
+ return GetInputContext( m_hContext )->_mousePressed[ code - MOUSE_FIRST ];
+}
+
+bool CInputSystem::WasMouseDoublePressed( MouseCode code )
+{
+ return GetInputContext( m_hContext )->_mouseDoublePressed[ code - MOUSE_FIRST ];
+}
+
+bool CInputSystem::IsMouseDown( MouseCode code )
+{
+ return GetInputContext( m_hContext )->_mouseDown[ code - MOUSE_FIRST ];
+}
+
+bool CInputSystem::WasMouseReleased( MouseCode code )
+{
+ return GetInputContext( m_hContext )->_mouseReleased[ code - MOUSE_FIRST ];
+}
+
+bool CInputSystem::WasKeyPressed( KeyCode code )
+{
+ return GetInputContext( m_hContext )->_keyPressed[ code - KEY_FIRST ];
+}
+
+bool CInputSystem::IsKeyDown( KeyCode code )
+{
+ return GetInputContext( m_hContext )->_keyDown[ code - KEY_FIRST ];
+}
+
+bool CInputSystem::WasKeyTyped( KeyCode code )
+{
+ return GetInputContext( m_hContext )->_keyTyped[ code - KEY_FIRST ];
+}
+
+bool CInputSystem::WasKeyReleased( KeyCode code )
+{
+ // changed from: only return true if the key was released and the passed in panel matches the keyFocus
+ return GetInputContext( m_hContext )->_keyReleased[ code - KEY_FIRST ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Cursor position; this is the current position read from the input queue.
+// We need to set it because client code may read this during Mouse Pressed
+// events, etc.
+//-----------------------------------------------------------------------------
+void CInputSystem::UpdateCursorPosInternal( int x, int y )
+{
+ // Windows sends a CursorMoved message even when you haven't actually
+ // moved the cursor, this means we are going into this fxn just by clicking
+ // in the window. We only want to execute this code if we have actually moved
+ // the cursor while dragging. So this code has been added to check
+ // if we have actually moved from our previous position.
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ( pContext->m_nCursorX == x && pContext->m_nCursorY == y )
+ return;
+
+ pContext->m_nCursorX = x;
+ pContext->m_nCursorY = y;
+
+ // Cursor has moved, so make sure the mouseFocus is current
+ UpdateMouseFocus( x, y );
+}
+
+
+//-----------------------------------------------------------------------------
+// This is called by panels to teleport the cursor
+//-----------------------------------------------------------------------------
+void CInputSystem::SetCursorPos( int x, int y )
+{
+ if ( IsDispatchingMessageQueue() )
+ {
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ pContext->m_nExternallySetCursorX = x;
+ pContext->m_nExternallySetCursorY = y;
+ pContext->m_bSetCursorExplicitly = true;
+ }
+ else
+ {
+ SurfaceSetCursorPos( x, y );
+ }
+}
+
+
+void CInputSystem::GetCursorPos(int &x, int &y)
+{
+ if ( IsDispatchingMessageQueue() )
+ {
+ GetCursorPosition( x, y );
+ }
+ else
+ {
+ SurfaceGetCursorPos( x, y );
+ }
+}
+
+
+// Here for backward compat
+void CInputSystem::GetCursorPosition( int &x, int &y )
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ x = pContext->m_nCursorX;
+ y = pContext->m_nCursorY;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Converts a key code into a full key name
+//-----------------------------------------------------------------------------
+void CInputSystem::GetKeyCodeText(KeyCode code, char *buf, int buflen)
+{
+ if (!buf)
+ return;
+
+ // copy text into buf up to buflen in length
+ // skip 2 in _keyTrans because the first two are for GetKeyCodeChar
+ for (int i = 0; i < buflen; i++)
+ {
+ char ch = _keyTrans[code][i+2];
+ buf[i] = ch;
+ if (ch == 0)
+ break;
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Low-level cursor getting/setting functions
+//-----------------------------------------------------------------------------
+void CInputSystem::SurfaceSetCursorPos(int x, int y)
+{
+ if ( g_pSurface->HasCursorPosFunctions() ) // does the surface export cursor functions for us to use?
+ {
+ g_pSurface->SurfaceSetCursorPos(x,y);
+ }
+ else
+ {
+ // translate into coordinates relative to surface
+ int px, py, pw, pt;
+ g_pSurface->GetAbsoluteWindowBounds(px, py, pw, pt);
+ x += px;
+ y += py;
+ // set windows cursor pos
+#ifdef WIN32
+ ::SetCursorPos(x, y);
+#else
+ // From Alfred on 8/15/2012.
+ // For l4d2, the vguimatsurface/cursor.cpp functions fire in the engine, the vgui2 ones
+ // should be dormant (this isn't true for Steam however).
+ //
+ // If we ever do need to implement this, look at SDL_GetMouseState(), etc.
+ Assert( !"CInputSystem::SurfaceSetCursorPos NYI" );
+#endif
+ }
+}
+
+void CInputSystem::SurfaceGetCursorPos( int &x, int &y )
+{
+#ifndef _X360 // X360TBD
+ if ( g_pSurface->HasCursorPosFunctions() ) // does the surface export cursor functions for us to use?
+ {
+ g_pSurface->SurfaceGetCursorPos( x,y );
+ }
+ else
+ {
+#ifdef WIN32
+ // get mouse position in windows
+ POINT pnt;
+ VCRHook_GetCursorPos(&pnt);
+ x = pnt.x;
+ y = pnt.y;
+
+ // translate into coordinates relative to surface
+ int px, py, pw, pt;
+ g_pSurface->GetAbsoluteWindowBounds(px, py, pw, pt);
+ x -= px;
+ y -= py;
+#else
+ // From Alfred on 8/15/2012.
+ // For l4d2, the vguimatsurface/cursor.cpp functions fire in the engine, the vgui2 ones
+ // should be dormant (this isn't true for Steam however).
+ Assert( !"CInputSystem::SurfaceGetCursorPos NYI" );
+ x = 0;
+ y = 0;
+#endif
+ }
+#else
+ x = 0;
+ y = 0;
+#endif
+}
+
+void CInputSystem::SetCursorOveride(HCursor cursor)
+{
+ _cursorOverride = cursor;
+}
+
+HCursor CInputSystem::GetCursorOveride()
+{
+ return _cursorOverride;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when we've detected cursor has moved via a windows message
+//-----------------------------------------------------------------------------
+bool CInputSystem::InternalCursorMoved(int x, int y)
+{
+ g_pIVgui->PostMessage((VPANEL) MESSAGE_CURSOR_POS, new KeyValues("SetCursorPosInternal", "xpos", x, "ypos", y), NULL);
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure the windows cursor is in the right place after processing input
+//-----------------------------------------------------------------------------
+void CInputSystem::HandleExplicitSetCursor( )
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+
+ if ( pContext->m_bSetCursorExplicitly )
+ {
+ pContext->m_nCursorX = pContext->m_nExternallySetCursorX;
+ pContext->m_nCursorY = pContext->m_nExternallySetCursorY;
+ pContext->m_bSetCursorExplicitly = false;
+
+ // NOTE: This forces a cursor moved message to be posted next time
+ pContext->m_nLastPostedCursorX = pContext->m_nLastPostedCursorY = -9999;
+
+ SurfaceSetCursorPos( pContext->m_nCursorX, pContext->m_nCursorY );
+ UpdateMouseFocus( pContext->m_nCursorX, pContext->m_nCursorY );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when we've detected cursor has moved via a windows message
+//-----------------------------------------------------------------------------
+void CInputSystem::PostCursorMessage( )
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+
+ if ( pContext->m_bSetCursorExplicitly )
+ {
+ // NOTE m_bSetCursorExplicitly will be reset to false in HandleExplicitSetCursor
+ pContext->m_nCursorX = pContext->m_nExternallySetCursorX;
+ pContext->m_nCursorY = pContext->m_nExternallySetCursorY;
+ }
+
+ if ( pContext->m_nLastPostedCursorX == pContext->m_nCursorX && pContext->m_nLastPostedCursorY == pContext->m_nCursorY )
+ return;
+
+ pContext->m_nLastPostedCursorX = pContext->m_nCursorX;
+ pContext->m_nLastPostedCursorY = pContext->m_nCursorY;
+
+ if ( pContext->_mouseCapture )
+ {
+ if (!IsChildOfModalPanel((VPANEL)pContext->_mouseCapture))
+ return;
+
+ // the panel with mouse capture gets all messages
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("CursorMoved", "xpos", pContext->m_nCursorX, "ypos", pContext->m_nCursorY), NULL);
+ }
+ else if (pContext->_mouseFocus != NULL)
+ {
+ // mouse focus is current from UpdateMouse focus
+ // so the appmodal check has already been made.
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("CursorMoved", "xpos", pContext->m_nCursorX, "ypos", pContext->m_nCursorY), NULL);
+ }
+}
+
+bool CInputSystem::InternalMousePressed(MouseCode code)
+{
+ // True means we've processed the message and other code shouldn't see this message
+ bool bFilter = false;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ VPanel *pTargetPanel = pContext->_mouseOver;
+ if ( pContext->_mouseCapture && IsChildOfModalPanel((VPANEL)pContext->_mouseCapture))
+ {
+ // The faked mouse wheel button messages are specifically ignored by vgui
+ if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
+ return true;
+
+ bFilter = true;
+
+ bool captureLost = code == pContext->m_MouseCaptureStartCode || pContext->m_MouseCaptureStartCode == (MouseCode)-1;
+
+ // the panel with mouse capture gets all messages
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("MousePressed", "code", code), NULL);
+ pTargetPanel = pContext->_mouseCapture;
+
+ if ( captureLost )
+ {
+ // this has to happen after MousePressed so the panel doesn't Think it got a mouse press after it lost capture
+ SetMouseCapture(NULL);
+ }
+ }
+ else if ( (pContext->_mouseFocus != NULL) && IsChildOfModalPanel((VPANEL)pContext->_mouseFocus) )
+ {
+ // The faked mouse wheel button messages are specifically ignored by vgui
+ if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
+ return true;
+
+ bFilter = true;
+
+ // tell the panel with the mouseFocus that the mouse was presssed
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MousePressed", "code", code), NULL);
+// g_pIVgui->DPrintf2("MousePressed: (%s, %s)\n", _mouseFocus->GetName(), _mouseFocus->GetClassName());
+ pTargetPanel = pContext->_mouseFocus;
+ }
+ else if ( pContext->m_pModalSubTree && pContext->m_pUnhandledMouseClickListener )
+ {
+ VPanel *p = GetMouseFocusIgnoringModalSubtree();
+ if ( p )
+ {
+ bool isChildOfModal = IsChildOfModalSubTree( (VPANEL)p );
+ bool isUnRestricted = !pContext->m_bRestrictMessagesToModalSubTree;
+
+ if ( isUnRestricted != isChildOfModal )
+ {
+ // The faked mouse wheel button messages are specifically ignored by vgui
+ if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
+ return true;
+
+ g_pIVgui->PostMessage( ( VPANEL )pContext->m_pUnhandledMouseClickListener, new KeyValues( "UnhandledMouseClick", "code", code ), NULL );
+ pTargetPanel = pContext->m_pUnhandledMouseClickListener;
+ bFilter = true;
+ }
+ }
+ }
+
+
+ // check if we are in modal state,
+ // and if we are make sure this panel is a child of us.
+ if ( IsChildOfModalPanel( (VPANEL)pTargetPanel ) )
+ {
+ g_pSurface->SetTopLevelFocus( (VPANEL)pTargetPanel );
+ }
+
+ return bFilter;
+}
+
+bool CInputSystem::InternalMouseDoublePressed(MouseCode code)
+{
+ // True means we've processed the message and other code shouldn't see this message
+ bool bFilter = false;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ VPanel *pTargetPanel = pContext->_mouseOver;
+ if ( pContext->_mouseCapture && IsChildOfModalPanel((VPANEL)pContext->_mouseCapture))
+ {
+ // The faked mouse wheel button messages are specifically ignored by vgui
+ if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
+ return true;
+
+ // the panel with mouse capture gets all messages
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("MouseDoublePressed", "code", code), NULL);
+ pTargetPanel = pContext->_mouseCapture;
+ bFilter = true;
+ }
+ else if ( (pContext->_mouseFocus != NULL) && IsChildOfModalPanel((VPANEL)pContext->_mouseFocus))
+ {
+ // The faked mouse wheel button messages are specifically ignored by vgui
+ if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
+ return true;
+
+ // tell the panel with the mouseFocus that the mouse was double presssed
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseDoublePressed", "code", code), NULL);
+ pTargetPanel = pContext->_mouseFocus;
+ bFilter = true;
+ }
+
+ // check if we are in modal state,
+ // and if we are make sure this panel is a child of us.
+ if (IsChildOfModalPanel((VPANEL)pTargetPanel))
+ {
+ g_pSurface->SetTopLevelFocus((VPANEL)pTargetPanel);
+ }
+
+ return bFilter;
+}
+
+bool CInputSystem::InternalMouseReleased( MouseCode code )
+{
+ // True means we've processed the message and other code shouldn't see this message
+ bool bFilter = false;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if (pContext->_mouseCapture && IsChildOfModalPanel((VPANEL)pContext->_mouseCapture))
+ {
+ // The faked mouse wheel button messages are specifically ignored by vgui
+ if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
+ return true;
+
+ // the panel with mouse capture gets all messages
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("MouseReleased", "code", code), NULL );
+ bFilter = true;
+ }
+ else if ((pContext->_mouseFocus != NULL) && IsChildOfModalPanel((VPANEL)pContext->_mouseFocus))
+ {
+ // The faked mouse wheel button messages are specifically ignored by vgui
+ if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
+ return true;
+
+ //tell the panel with the mouseFocus that the mouse was release
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseReleased", "code", code), NULL );
+ bFilter = true;
+ }
+
+ return bFilter;
+}
+
+bool CInputSystem::InternalMouseWheeled(int delta)
+{
+ // True means we've processed the message and other code shouldn't see this message
+ bool bFilter = false;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ((pContext->_mouseFocus != NULL) && IsChildOfModalPanel((VPANEL)pContext->_mouseFocus))
+ {
+ // the mouseWheel works with the mouseFocus, not the keyFocus
+ g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseWheeled", "delta", delta), NULL);
+ bFilter = true;
+ }
+ return bFilter;
+}
+
+//-----------------------------------------------------------------------------
+// Updates the internal key/mouse state associated with the current input context without sending messages
+//-----------------------------------------------------------------------------
+void CInputSystem::SetMouseCodeState( MouseCode code, MouseCodeState_t state )
+{
+ if ( !IsMouseCode( code ) )
+ return;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ switch( state )
+ {
+ case BUTTON_RELEASED:
+ pContext->_mouseReleased[ code - MOUSE_FIRST ] = 1;
+ break;
+
+ case BUTTON_PRESSED:
+ pContext->_mousePressed[ code - MOUSE_FIRST ] = 1;
+ break;
+
+ case BUTTON_DOUBLECLICKED:
+ pContext->_mouseDoublePressed[ code - MOUSE_FIRST ] = 1;
+ break;
+ }
+
+ pContext->_mouseDown[ code - MOUSE_FIRST ] = ( state != BUTTON_RELEASED );
+}
+
+void CInputSystem::SetKeyCodeState( KeyCode code, bool bPressed )
+{
+ if ( !IsKeyCode( code ) && !IsJoystickCode( code ) )
+ return;
+
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ( bPressed )
+ {
+ //set key state
+ pContext->_keyPressed[ code - KEY_FIRST ] = 1;
+ }
+ else
+ {
+ // set key state
+ pContext->_keyReleased[ code - KEY_FIRST ] = 1;
+ }
+ pContext->_keyDown[ code - KEY_FIRST ] = bPressed;
+}
+
+void CInputSystem::UpdateButtonState( const InputEvent_t &event )
+{
+ switch( event.m_nType )
+ {
+ case IE_ButtonPressed:
+ case IE_ButtonReleased:
+ case IE_ButtonDoubleClicked:
+ {
+ // NOTE: data2 is the virtual key code (data1 contains the scan-code one)
+ ButtonCode_t code = (ButtonCode_t)event.m_nData2;
+
+ // FIXME: Workaround hack
+ if ( IsKeyCode( code ) || IsJoystickCode( code ) )
+ {
+ SetKeyCodeState( code, ( event.m_nType != IE_ButtonReleased ) );
+ break;
+ }
+
+ if ( IsMouseCode( code ) )
+ {
+ MouseCodeState_t state;
+ state = ( event.m_nType == IE_ButtonReleased ) ? vgui::BUTTON_RELEASED : vgui::BUTTON_PRESSED;
+ if ( event.m_nType == IE_ButtonDoubleClicked )
+ {
+ state = vgui::BUTTON_DOUBLECLICKED;
+ }
+
+ SetMouseCodeState( code, state );
+ break;
+ }
+ }
+ break;
+ }
+}
+
+bool CInputSystem::InternalKeyCodePressed( KeyCode code )
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+
+ // mask out bogus keys
+ if ( !IsKeyCode( code ) && !IsJoystickCode( code ) )
+ return false;
+
+ bool bFilter = PostKeyMessage( new KeyValues("KeyCodePressed", "code", code ) );
+ if ( bFilter )
+ {
+ // Only notice the key down for repeating if we actually used the key
+ pContext->m_keyRepeater.KeyDown( code );
+ }
+ return bFilter;
+}
+
+void CInputSystem::InternalKeyCodeTyped( KeyCode code )
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ // mask out bogus keys
+ if ( !IsKeyCode( code ) && !IsJoystickCode( code ) )
+ return;
+
+ // set key state
+ pContext->_keyTyped[ code - KEY_FIRST ] = 1;
+
+ // tell the current focused panel that a key was typed
+ PostKeyMessage(new KeyValues("KeyCodeTyped", "code", code));
+}
+
+void CInputSystem::InternalKeyTyped(wchar_t unichar)
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ // set key state
+ if( unichar <= KEY_LAST )
+ {
+ pContext->_keyTyped[unichar]=1;
+ }
+
+ // tell the current focused panel that a key was typed
+ PostKeyMessage(new KeyValues("KeyTyped", "unichar", unichar));
+}
+
+bool CInputSystem::InternalKeyCodeReleased( KeyCode code )
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+
+ // mask out bogus keys
+ if ( !IsKeyCode( code ) && !IsJoystickCode( code ) )
+ return false;
+
+ pContext->m_keyRepeater.KeyUp( code );
+
+ return PostKeyMessage(new KeyValues("KeyCodeReleased", "code", code));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: posts a message to the key focus if it's valid
+//-----------------------------------------------------------------------------
+bool CInputSystem::PostKeyMessage(KeyValues *message)
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if( (pContext->_keyFocus!= NULL) && IsChildOfModalPanel((VPANEL)pContext->_keyFocus))
+ {
+#ifdef _X360
+ g_pIVgui->PostMessage((VPANEL) MESSAGE_CURRENT_KEYFOCUS, message, NULL );
+#else
+ //tell the current focused panel that a key was released
+ g_pIVgui->PostMessage((VPANEL)pContext->_keyFocus, message, NULL );
+#endif
+ return true;
+ }
+
+ message->deleteThis();
+ return false;
+}
+
+VPANEL CInputSystem::GetAppModalSurface()
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ return (VPANEL)pContext->_appModalPanel;
+}
+
+void CInputSystem::SetAppModalSurface(VPANEL panel)
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ pContext->_appModalPanel = (VPanel *)panel;
+}
+
+
+void CInputSystem::ReleaseAppModalSurface()
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ pContext->_appModalPanel = NULL;
+}
+
+
+#ifdef DO_IME
+
+enum LANGFLAG
+{
+ ENGLISH,
+ TRADITIONAL_CHINESE,
+ JAPANESE,
+ KOREAN,
+ SIMPLIFIED_CHINESE,
+ UNKNOWN,
+
+ NUM_IMES_SUPPORTED
+} LangFlag;
+
+struct LanguageIds
+{
+ // char const *idname;
+ unsigned short id;
+ int languageflag;
+ wchar_t const *shortcode;
+ wchar_t const *displayname;
+ bool invertcomposition;
+};
+
+LanguageIds g_LanguageIds[] =
+{
+ { 0x0000, UNKNOWN, L"", L"Neutral" },
+ { 0x007f, UNKNOWN, L"", L"Invariant" },
+ { 0x0400, UNKNOWN, L"", L"User Default Language" },
+ { 0x0800, UNKNOWN, L"", L"System Default Language" },
+ { 0x0436, UNKNOWN, L"AF", L"Afrikaans" },
+ { 0x041c, UNKNOWN, L"SQ", L"Albanian" },
+ { 0x0401, UNKNOWN, L"AR", L"Arabic (Saudi Arabia)" },
+ { 0x0801, UNKNOWN, L"AR", L"Arabic (Iraq)" },
+ { 0x0c01, UNKNOWN, L"AR", L"Arabic (Egypt)" },
+ { 0x1001, UNKNOWN, L"AR", L"Arabic (Libya)" },
+ { 0x1401, UNKNOWN, L"AR", L"Arabic (Algeria)" },
+ { 0x1801, UNKNOWN, L"AR", L"Arabic (Morocco)" },
+ { 0x1c01, UNKNOWN, L"AR", L"Arabic (Tunisia)" },
+ { 0x2001, UNKNOWN, L"AR", L"Arabic (Oman)" },
+ { 0x2401, UNKNOWN, L"AR", L"Arabic (Yemen)" },
+ { 0x2801, UNKNOWN, L"AR", L"Arabic (Syria)" },
+ { 0x2c01, UNKNOWN, L"AR", L"Arabic (Jordan)" },
+ { 0x3001, UNKNOWN, L"AR", L"Arabic (Lebanon)" },
+ { 0x3401, UNKNOWN, L"AR", L"Arabic (Kuwait)" },
+ { 0x3801, UNKNOWN, L"AR", L"Arabic (U.A.E.)" },
+ { 0x3c01, UNKNOWN, L"AR", L"Arabic (Bahrain)" },
+ { 0x4001, UNKNOWN, L"AR", L"Arabic (Qatar)" },
+ { 0x042b, UNKNOWN, L"HY", L"Armenian" },
+ { 0x042c, UNKNOWN, L"AZ", L"Azeri (Latin)" },
+ { 0x082c, UNKNOWN, L"AZ", L"Azeri (Cyrillic)" },
+ { 0x042d, UNKNOWN, L"ES", L"Basque" },
+ { 0x0423, UNKNOWN, L"BE", L"Belarusian" },
+ { 0x0445, UNKNOWN, L"", L"Bengali (India)" },
+ { 0x141a, UNKNOWN, L"", L"Bosnian (Bosnia and Herzegovina)" },
+ { 0x0402, UNKNOWN, L"BG", L"Bulgarian" },
+ { 0x0455, UNKNOWN, L"", L"Burmese" },
+ { 0x0403, UNKNOWN, L"CA", L"Catalan" },
+ { 0x0404, TRADITIONAL_CHINESE, L"CHT", L"#IME_0404", true },
+ { 0x0804, SIMPLIFIED_CHINESE, L"CHS", L"#IME_0804", true },
+ { 0x0c04, UNKNOWN, L"CH", L"Chinese (Hong Kong SAR, PRC)" },
+ { 0x1004, UNKNOWN, L"CH", L"Chinese (Singapore)" },
+ { 0x1404, UNKNOWN, L"CH", L"Chinese (Macao SAR)" },
+ { 0x041a, UNKNOWN, L"HR", L"Croatian" },
+ { 0x101a, UNKNOWN, L"HR", L"Croatian (Bosnia and Herzegovina)" },
+ { 0x0405, UNKNOWN, L"CZ", L"Czech" },
+ { 0x0406, UNKNOWN, L"DK", L"Danish" },
+ { 0x0465, UNKNOWN, L"MV", L"Divehi" },
+ { 0x0413, UNKNOWN, L"NL", L"Dutch (Netherlands)" },
+ { 0x0813, UNKNOWN, L"BE", L"Dutch (Belgium)" },
+ { 0x0409, ENGLISH, L"EN", L"#IME_0409" },
+ { 0x0809, ENGLISH, L"EN", L"English (United Kingdom)" },
+ { 0x0c09, ENGLISH, L"EN", L"English (Australian)" },
+ { 0x1009, ENGLISH, L"EN", L"English (Canadian)" },
+ { 0x1409, ENGLISH, L"EN", L"English (New Zealand)" },
+ { 0x1809, ENGLISH, L"EN", L"English (Ireland)" },
+ { 0x1c09, ENGLISH, L"EN", L"English (South Africa)" },
+ { 0x2009, ENGLISH, L"EN", L"English (Jamaica)" },
+ { 0x2409, ENGLISH, L"EN", L"English (Caribbean)" },
+ { 0x2809, ENGLISH, L"EN", L"English (Belize)" },
+ { 0x2c09, ENGLISH, L"EN", L"English (Trinidad)" },
+ { 0x3009, ENGLISH, L"EN", L"English (Zimbabwe)" },
+ { 0x3409, ENGLISH, L"EN", L"English (Philippines)" },
+ { 0x0425, UNKNOWN, L"ET", L"Estonian" },
+ { 0x0438, UNKNOWN, L"FO", L"Faeroese" },
+ { 0x0429, UNKNOWN, L"FA", L"Farsi" },
+ { 0x040b, UNKNOWN, L"FI", L"Finnish" },
+ { 0x040c, UNKNOWN, L"FR", L"#IME_040c" },
+ { 0x080c, UNKNOWN, L"FR", L"French (Belgian)" },
+ { 0x0c0c, UNKNOWN, L"FR", L"French (Canadian)" },
+ { 0x100c, UNKNOWN, L"FR", L"French (Switzerland)" },
+ { 0x140c, UNKNOWN, L"FR", L"French (Luxembourg)" },
+ { 0x180c, UNKNOWN, L"FR", L"French (Monaco)" },
+ { 0x0456, UNKNOWN, L"GL", L"Galician" },
+ { 0x0437, UNKNOWN, L"KA", L"Georgian" },
+ { 0x0407, UNKNOWN, L"DE", L"#IME_0407" },
+ { 0x0807, UNKNOWN, L"DE", L"German (Switzerland)" },
+ { 0x0c07, UNKNOWN, L"DE", L"German (Austria)" },
+ { 0x1007, UNKNOWN, L"DE", L"German (Luxembourg)" },
+ { 0x1407, UNKNOWN, L"DE", L"German (Liechtenstein)" },
+ { 0x0408, UNKNOWN, L"GR", L"Greek" },
+ { 0x0447, UNKNOWN, L"IN", L"Gujarati" },
+ { 0x040d, UNKNOWN, L"HE", L"Hebrew" },
+ { 0x0439, UNKNOWN, L"HI", L"Hindi" },
+ { 0x040e, UNKNOWN, L"HU", L"Hungarian" },
+ { 0x040f, UNKNOWN, L"IS", L"Icelandic" },
+ { 0x0421, UNKNOWN, L"ID", L"Indonesian" },
+ { 0x0434, UNKNOWN, L"", L"isiXhosa/Xhosa (South Africa)" },
+ { 0x0435, UNKNOWN, L"", L"isiZulu/Zulu (South Africa)" },
+ { 0x0410, UNKNOWN, L"IT", L"#IME_0410" },
+ { 0x0810, UNKNOWN, L"IT", L"Italian (Switzerland)" },
+ { 0x0411, JAPANESE, L"JP", L"#IME_0411" },
+ { 0x044b, UNKNOWN, L"IN", L"Kannada" },
+ { 0x0457, UNKNOWN, L"IN", L"Konkani" },
+ { 0x0412, KOREAN, L"KR", L"#IME_0412" },
+ { 0x0812, UNKNOWN, L"KR", L"Korean (Johab)" },
+ { 0x0440, UNKNOWN, L"KZ", L"Kyrgyz." },
+ { 0x0426, UNKNOWN, L"LV", L"Latvian" },
+ { 0x0427, UNKNOWN, L"LT", L"Lithuanian" },
+ { 0x0827, UNKNOWN, L"LT", L"Lithuanian (Classic)" },
+ { 0x042f, UNKNOWN, L"MK", L"FYRO Macedonian" },
+ { 0x043e, UNKNOWN, L"MY", L"Malay (Malaysian)" },
+ { 0x083e, UNKNOWN, L"MY", L"Malay (Brunei Darussalam)" },
+ { 0x044c, UNKNOWN, L"IN", L"Malayalam (India)" },
+ { 0x0481, UNKNOWN, L"", L"Maori (New Zealand)" },
+ { 0x043a, UNKNOWN, L"", L"Maltese (Malta)" },
+ { 0x044e, UNKNOWN, L"IN", L"Marathi" },
+ { 0x0450, UNKNOWN, L"MN", L"Mongolian" },
+ { 0x0414, UNKNOWN, L"NO", L"Norwegian (Bokmal)" },
+ { 0x0814, UNKNOWN, L"NO", L"Norwegian (Nynorsk)" },
+ { 0x0415, UNKNOWN, L"PL", L"Polish" },
+ { 0x0416, UNKNOWN, L"PT", L"Portuguese (Brazil)" },
+ { 0x0816, UNKNOWN, L"PT", L"Portuguese (Portugal)" },
+ { 0x0446, UNKNOWN, L"IN", L"Punjabi" },
+ { 0x046b, UNKNOWN, L"", L"Quechua (Bolivia)" },
+ { 0x086b, UNKNOWN, L"", L"Quechua (Ecuador)" },
+ { 0x0c6b, UNKNOWN, L"", L"Quechua (Peru)" },
+ { 0x0418, UNKNOWN, L"RO", L"Romanian" },
+ { 0x0419, UNKNOWN, L"RU", L"#IME_0419" },
+ { 0x044f, UNKNOWN, L"IN", L"Sanskrit" },
+ { 0x043b, UNKNOWN, L"", L"Sami, Northern (Norway)" },
+ { 0x083b, UNKNOWN, L"", L"Sami, Northern (Sweden)" },
+ { 0x0c3b, UNKNOWN, L"", L"Sami, Northern (Finland)" },
+ { 0x103b, UNKNOWN, L"", L"Sami, Lule (Norway)" },
+ { 0x143b, UNKNOWN, L"", L"Sami, Lule (Sweden)" },
+ { 0x183b, UNKNOWN, L"", L"Sami, Southern (Norway)" },
+ { 0x1c3b, UNKNOWN, L"", L"Sami, Southern (Sweden)" },
+ { 0x203b, UNKNOWN, L"", L"Sami, Skolt (Finland)" },
+ { 0x243b, UNKNOWN, L"", L"Sami, Inari (Finland)" },
+ { 0x0c1a, UNKNOWN, L"SR", L"Serbian (Cyrillic)" },
+ { 0x1c1a, UNKNOWN, L"SR", L"Serbian (Cyrillic, Bosnia, and Herzegovina)" },
+ { 0x081a, UNKNOWN, L"SR", L"Serbian (Latin)" },
+ { 0x181a, UNKNOWN, L"SR", L"Serbian (Latin, Bosnia, and Herzegovina)" },
+ { 0x046c, UNKNOWN, L"", L"Sesotho sa Leboa/Northern Sotho (South Africa)" },
+ { 0x0432, UNKNOWN, L"", L"Setswana/Tswana (South Africa)" },
+ { 0x041b, UNKNOWN, L"SK", L"Slovak" },
+ { 0x0424, UNKNOWN, L"SI", L"Slovenian" },
+ { 0x040a, UNKNOWN, L"ES", L"#IME_040a" },
+ { 0x080a, UNKNOWN, L"ES", L"Spanish (Mexican)" },
+ { 0x0c0a, UNKNOWN, L"ES", L"Spanish (Spain, Modern Sort)" },
+ { 0x100a, UNKNOWN, L"ES", L"Spanish (Guatemala)" },
+ { 0x140a, UNKNOWN, L"ES", L"Spanish (Costa Rica)" },
+ { 0x180a, UNKNOWN, L"ES", L"Spanish (Panama)" },
+ { 0x1c0a, UNKNOWN, L"ES", L"Spanish (Dominican Republic)" },
+ { 0x200a, UNKNOWN, L"ES", L"Spanish (Venezuela)" },
+ { 0x240a, UNKNOWN, L"ES", L"Spanish (Colombia)" },
+ { 0x280a, UNKNOWN, L"ES", L"Spanish (Peru)" },
+ { 0x2c0a, UNKNOWN, L"ES", L"Spanish (Argentina)" },
+ { 0x300a, UNKNOWN, L"ES", L"Spanish (Ecuador)" },
+ { 0x340a, UNKNOWN, L"ES", L"Spanish (Chile)" },
+ { 0x380a, UNKNOWN, L"ES", L"Spanish (Uruguay)" },
+ { 0x3c0a, UNKNOWN, L"ES", L"Spanish (Paraguay)" },
+ { 0x400a, UNKNOWN, L"ES", L"Spanish (Bolivia)" },
+ { 0x440a, UNKNOWN, L"ES", L"Spanish (El Salvador)" },
+ { 0x480a, UNKNOWN, L"ES", L"Spanish (Honduras)" },
+ { 0x4c0a, UNKNOWN, L"ES", L"Spanish (Nicaragua)" },
+ { 0x500a, UNKNOWN, L"ES", L"Spanish (Puerto Rico)" },
+ { 0x0430, UNKNOWN, L"", L"Sutu" },
+ { 0x0441, UNKNOWN, L"KE", L"Swahili (Kenya)" },
+ { 0x041d, UNKNOWN, L"SV", L"Swedish" },
+ { 0x081d, UNKNOWN, L"SV", L"Swedish (Finland)" },
+ { 0x045a, UNKNOWN, L"SY", L"Syriac" },
+ { 0x0449, UNKNOWN, L"IN", L"Tamil" },
+ { 0x0444, UNKNOWN, L"RU", L"Tatar (Tatarstan)" },
+ { 0x044a, UNKNOWN, L"IN", L"Telugu" },
+ { 0x041e, UNKNOWN, L"TH", L"#IME_041e" },
+ { 0x041f, UNKNOWN, L"TR", L"Turkish" },
+ { 0x0422, UNKNOWN, L"UA", L"Ukrainian" },
+ { 0x0420, UNKNOWN, L"PK", L"Urdu (Pakistan)" },
+ { 0x0820, UNKNOWN, L"IN", L"Urdu (India)" },
+ { 0x0443, UNKNOWN, L"UZ", L"Uzbek (Latin)" },
+ { 0x0843, UNKNOWN, L"UZ", L"Uzbek (Cyrillic)" },
+ { 0x042a, UNKNOWN, L"VN", L"Vietnamese" },
+ { 0x0452, UNKNOWN, L"", L"Welsh (United Kingdom)" },
+};
+
+static LanguageIds *GetLanguageInfo( unsigned short id )
+{
+ for ( int j = 0; j < sizeof( g_LanguageIds ) / sizeof( g_LanguageIds[ 0 ] ); ++j )
+ {
+ if ( g_LanguageIds[ j ].id == id )
+ {
+ return &g_LanguageIds[ j ];
+ break;
+ }
+ }
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CIMEDlg message handlers
+static bool IsIDInList( unsigned short id, int count, HKL *list )
+{
+ for ( int i = 0; i < count; ++i )
+ {
+ if ( LOWORD( list[ i ] ) == id )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static const wchar_t *GetLanguageName( unsigned short id )
+{
+ wchar_t const *name = L"???";
+ for ( int j = 0; j < sizeof( g_LanguageIds ) / sizeof( g_LanguageIds[ 0 ] ); ++j )
+ {
+ if ( g_LanguageIds[ j ].id == id )
+ {
+ name = g_LanguageIds[ j ].displayname;
+ break;
+ }
+ }
+ return name;
+}
+
+#endif // DO_IME
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *hwnd -
+//-----------------------------------------------------------------------------
+void CInputSystem::SetIMEWindow( void *hwnd )
+{
+#ifdef DO_IME
+ _imeWnd = hwnd;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void *CInputSystem::GetIMEWindow()
+{
+#ifdef DO_IME
+ return _imeWnd;
+#else
+ return NULL;
+#endif
+}
+
+#ifdef DO_IME
+static void SpewIMEInfo( int langid )
+{
+ LanguageIds *info = GetLanguageInfo( langid );
+ if ( info )
+ {
+ wchar_t const *name = info->shortcode ? info->shortcode : L"???";
+ wchar_t outstr[ 512 ];
+ V_swprintf_safe( outstr, L"IME language changed to: %s", name );
+ OutputDebugStringW( outstr );
+ OutputDebugStringW( L"\n" );
+ }
+}
+#endif // DO_IME
+
+// Change keyboard layout type
+void CInputSystem::OnChangeIME( bool forward )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ HKL currentKb = GetKeyboardLayout( 0 );
+
+ UINT numKBs = GetKeyboardLayoutList( 0, NULL );
+ if ( numKBs > 0 )
+ {
+ HKL *list = new HKL[ numKBs ];
+
+ GetKeyboardLayoutList( numKBs, list );
+
+ int oldKb = 0;
+ CUtlVector< HKL > selections;
+
+ for ( unsigned int i = 0; i < numKBs; ++i )
+ {
+ BOOL first = !IsIDInList( LOWORD( list[ i ] ), i, list );
+
+ if ( !first )
+ continue;
+
+ selections.AddToTail( list[ i ] );
+ if ( list[ i ] == currentKb )
+ {
+ oldKb = selections.Count() - 1;
+ }
+ }
+
+ oldKb += forward ? 1 : -1;
+ if ( oldKb < 0 )
+ {
+ oldKb = max( 0, selections.Count() - 1 );
+ }
+ else if ( oldKb >= selections.Count() )
+ {
+ oldKb = 0;
+ }
+
+ ActivateKeyboardLayout( selections[ oldKb ], 0 );
+
+ int langid = LOWORD( selections[ oldKb ] );
+ SpewIMEInfo( langid );
+
+ delete[] list;
+ }
+#endif
+}
+
+int CInputSystem::GetCurrentIMEHandle()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ HKL hkl = (HKL)GetKeyboardLayout( 0 );
+ return (int)hkl;
+#else
+ return 0;
+#endif
+}
+
+int CInputSystem::GetEnglishIMEHandle()
+{
+#ifdef DO_IME
+ HKL hkl = (HKL)0x04090409;
+ return (int)hkl;
+#else
+ return 0;
+#endif
+}
+
+void CInputSystem::OnChangeIMEByHandle( int handleValue )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ HKL hkl = (HKL)handleValue;
+
+ ActivateKeyboardLayout( hkl, 0 );
+
+ int langid = LOWORD( hkl);
+
+ SpewIMEInfo( langid );
+#endif
+}
+
+ // Returns the Language Bar label (Chinese, Korean, Japanese, Russion, Thai, etc.)
+void CInputSystem::GetIMELanguageName( wchar_t *buf, int unicodeBufferSizeInBytes )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ wchar_t const *name = GetLanguageName( LOWORD( GetKeyboardLayout( 0 ) ) );
+ wcsncpy( buf, name, unicodeBufferSizeInBytes / sizeof( wchar_t ) - 1 );
+ buf[ unicodeBufferSizeInBytes / sizeof( wchar_t ) - 1 ] = L'\0';
+#else
+ buf[0] = L'\0';
+#endif
+}
+ // Returns the short code for the language (EN, CH, KO, JP, RU, TH, etc. ).
+void CInputSystem::GetIMELanguageShortCode( wchar_t *buf, int unicodeBufferSizeInBytes )
+{
+#ifdef DO_IME
+ LanguageIds *info = GetLanguageInfo( LOWORD( GetKeyboardLayout( 0 ) ) );
+ if ( !info )
+ {
+ buf[ 0 ] = L'\0';
+ }
+ else
+ {
+ wcsncpy( buf, info->shortcode, unicodeBufferSizeInBytes / sizeof( wchar_t ) - 1 );
+ buf[ unicodeBufferSizeInBytes / sizeof( wchar_t ) - 1 ] = L'\0';
+ }
+#else
+ buf[0] = L'\0';
+#endif
+}
+
+// Call with NULL dest to get item count
+int CInputSystem::GetIMELanguageList( LanguageItem *dest, int destcount )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ int iret = 0;
+
+ UINT numKBs = GetKeyboardLayoutList( 0, NULL );
+ if ( numKBs > 0 )
+ {
+ HKL *list = new HKL[ numKBs ];
+
+ GetKeyboardLayoutList( numKBs, list );
+
+ CUtlVector< HKL > selections;
+
+ for ( unsigned int i = 0; i < numKBs; ++i )
+ {
+ BOOL first = !IsIDInList( LOWORD( list[ i ] ), i, list );
+
+ if ( !first )
+ continue;
+
+ selections.AddToTail( list[ i ] );
+ }
+
+ iret = selections.Count();
+ if ( dest )
+ {
+ for ( int i = 0; i < min(iret,destcount); ++i )
+ {
+ HKL hkl = selections[ i ];
+
+ IInput::LanguageItem *p = &dest[ i ];
+
+ LanguageIds *info = GetLanguageInfo( LOWORD( hkl ) );
+
+ memset( p, 0, sizeof( IInput::LanguageItem ) );
+
+ wcsncpy( p->shortname, info->shortcode, sizeof( p->shortname ) / sizeof( wchar_t ) );
+ p->shortname[ sizeof( p->shortname ) / sizeof( wchar_t ) - 1 ] = L'\0';
+
+ wcsncpy( p->menuname, info->displayname, sizeof( p->menuname ) / sizeof( wchar_t ) );
+ p->menuname[ sizeof( p->menuname ) / sizeof( wchar_t ) - 1 ] = L'\0';
+
+ p->handleValue = (int)hkl;
+ p->active = ( hkl == GetKeyboardLayout( 0 ) ) ? true : false;
+ }
+ }
+
+ delete[] list;
+ }
+ return iret;
+#else
+ return 0;
+#endif
+}
+
+/*
+// Flag for effective options in conversion mode
+BOOL fConvMode[NUM_IMES_SUPPORTED][13] =
+{
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // EN
+ {1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0}, // Trad CH
+ {1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1}, // Japanese
+ {1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // Kor
+ {1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}, // Simp CH
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // UNK(same as EN)
+}
+
+// Flag for effective options in sentence mode
+BOOL fSentMode[NUM_IMES_SUPPORTED][6] =
+{
+ {0, 0, 0, 0, 0, 0}, // EN
+ {0, 1, 0, 0, 0, 0}, // Trad CH
+ {1, 1, 1, 1, 1, 1}, // Japanese
+ {0, 0, 0, 0, 0, 0}, // Kor
+ {0, 0, 0, 0, 0, 0} // Simp CH
+ {0, 0, 0, 0, 0, 0}, // UNK(same as EN)
+};
+
+// Conversion mode message
+DWORD dwConvModeMsg[13] = {
+ IME_CMODE_ALPHANUMERIC, IME_CMODE_NATIVE, IME_CMODE_KATAKANA,
+ IME_CMODE_LANGUAGE, IME_CMODE_FULLSHAPE, IME_CMODE_ROMAN,
+ IME_CMODE_CHARCODE, IME_CMODE_HANJACONVERT, IME_CMODE_SOFTKBD,
+ IME_CMODE_NOCONVERSION, IME_CMODE_EUDC, IME_CMODE_SYMBOL,
+ IME_CMODE_FIXED};
+
+// Sentence mode message
+DWORD dwSentModeMsg[6] = {
+ IME_SMODE_NONE, IME_SMODE_PLAURALCLAUSE, IME_SMODE_SINGLECONVERT,
+ IME_SMODE_AUTOMATIC, IME_SMODE_PHRASEPREDICT, IME_SMODE_CONVERSATION };
+
+// ENGLISH,
+// TRADITIONAL_CHINESE,
+// JAPANESE,
+// KOREAN,
+// SIMPLIFIED_CHINESE,
+// UNKNOWN,
+*/
+
+#ifdef DO_IME
+
+struct IMESettingsTransform
+{
+ IMESettingsTransform( unsigned int cmr, unsigned int cma, unsigned int smr, unsigned int sma ) :
+ cmode_remove( cmr ),
+ cmode_add( cma ),
+ smode_remove( smr ),
+ smode_add( sma )
+ {
+ }
+
+ void Apply( HWND hwnd )
+ {
+ HIMC hImc = ImmGetContext( hwnd );
+ if ( hImc )
+ {
+ DWORD dwConvMode, dwSentMode;
+
+ ImmGetConversionStatus( hImc, &dwConvMode, &dwSentMode );
+
+ dwConvMode &= ~cmode_remove;
+ dwSentMode &= ~smode_remove;
+
+ ImmSetConversionStatus( hImc, dwConvMode, dwSentMode );
+
+ dwConvMode |= cmode_add;
+ dwSentMode |= smode_add;
+
+ ImmSetConversionStatus( hImc, dwConvMode, dwSentMode );
+
+ ImmReleaseContext( hwnd, hImc );
+ }
+ }
+
+ bool ConvMatches( DWORD convFlags )
+ {
+ // To match, the active flags have to have none of the remove flags and have to have all of the "add" flags
+ if ( convFlags & cmode_remove )
+ return false;
+
+ if ( ( convFlags & cmode_add ) == cmode_add )
+ {
+ return true;
+ }
+ return false;
+ }
+
+ bool SentMatches( DWORD sentFlags )
+ {
+ // To match, the active flags have to have none of the remove flags and have to have all of the "add" flags
+ if ( sentFlags & smode_remove )
+ return false;
+
+ if ( ( sentFlags & smode_add ) == smode_add )
+ {
+ return true;
+ }
+ return false;
+ }
+
+ unsigned int cmode_remove;
+ unsigned int cmode_add;
+ unsigned int smode_remove;
+ unsigned int smode_add;
+};
+
+static IMESettingsTransform g_ConversionMode_CHT_ToChinese(
+ IME_CMODE_ALPHANUMERIC,
+ IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
+ 0,
+ 0 );
+static IMESettingsTransform g_ConversionMode_CHT_ToEnglish(
+ IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
+ IME_CMODE_ALPHANUMERIC,
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_CHS_ToChinese(
+ IME_CMODE_ALPHANUMERIC,
+ IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
+ 0,
+ 0 );
+static IMESettingsTransform g_ConversionMode_CHS_ToEnglish(
+ IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
+ IME_CMODE_ALPHANUMERIC,
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_KO_ToKorean(
+ IME_CMODE_ALPHANUMERIC,
+ IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_KO_ToEnglish(
+ IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
+ IME_CMODE_ALPHANUMERIC,
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_JP_Hiragana(
+ IME_CMODE_ALPHANUMERIC | IME_CMODE_KATAKANA,
+ IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE,
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_JP_DirectInput(
+ IME_CMODE_NATIVE | ( IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE ) | IME_CMODE_FULLSHAPE | IME_CMODE_ROMAN,
+ IME_CMODE_ALPHANUMERIC,
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_JP_FullwidthKatakana(
+ IME_CMODE_ALPHANUMERIC,
+ IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE | IME_CMODE_ROMAN | IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE,
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_JP_HalfwidthKatakana(
+ IME_CMODE_ALPHANUMERIC | IME_CMODE_FULLSHAPE,
+ IME_CMODE_NATIVE | IME_CMODE_ROMAN | ( IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE ),
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_JP_FullwidthAlphanumeric(
+ IME_CMODE_NATIVE | ( IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE ),
+ IME_CMODE_ALPHANUMERIC | IME_CMODE_FULLSHAPE | IME_CMODE_ROMAN,
+ 0,
+ 0 );
+
+static IMESettingsTransform g_ConversionMode_JP_HalfwidthAlphanumeric(
+ IME_CMODE_NATIVE | ( IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE ) | IME_CMODE_FULLSHAPE,
+ IME_CMODE_ALPHANUMERIC | IME_CMODE_ROMAN,
+ 0,
+ 0 );
+
+#endif // DO_IME
+
+int CInputSystem::GetIMEConversionModes( ConversionModeItem *dest, int destcount )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ if ( dest )
+ {
+ memset( dest, 0, destcount * sizeof( ConversionModeItem ) );
+ }
+
+ DWORD dwConvMode = 0, dwSentMode = 0;
+
+ HIMC hImc = ImmGetContext( ( HWND )GetIMEWindow() );
+ if ( hImc )
+ {
+ ImmGetConversionStatus( hImc, &dwConvMode, &dwSentMode );
+ ImmReleaseContext( ( HWND )GetIMEWindow(), hImc );
+ }
+
+ LanguageIds *info = GetLanguageInfo( LOWORD( GetKeyboardLayout( 0 ) ) );
+ switch ( info->languageflag )
+ {
+ default:
+ return 0;
+ case TRADITIONAL_CHINESE:
+ // This is either native or alphanumeric
+ if ( dest )
+ {
+ ConversionModeItem *item;
+ int i = 0;
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_Chinese", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_CHT_ToChinese;
+ item->active = g_ConversionMode_CHT_ToChinese.ConvMatches( dwConvMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_English", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_CHT_ToEnglish;
+ item->active = g_ConversionMode_CHT_ToEnglish.ConvMatches( dwConvMode );
+ }
+ return 2;
+ case JAPANESE:
+ // There are 6 Japanese modes
+ if ( dest )
+ {
+ ConversionModeItem *item;
+
+ int i = 0;
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_Hiragana", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_JP_Hiragana;
+ item->active = g_ConversionMode_JP_Hiragana.ConvMatches( dwConvMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_FullWidthKatakana", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_JP_FullwidthKatakana;
+ item->active = g_ConversionMode_JP_FullwidthKatakana.ConvMatches( dwConvMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_FullWidthAlphanumeric", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_JP_FullwidthAlphanumeric;
+ item->active = g_ConversionMode_JP_FullwidthAlphanumeric.ConvMatches( dwConvMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_HalfWidthKatakana", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_JP_HalfwidthKatakana;
+ item->active = g_ConversionMode_JP_HalfwidthKatakana.ConvMatches( dwConvMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_HalfWidthAlphanumeric", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_JP_HalfwidthAlphanumeric;
+ item->active = g_ConversionMode_JP_HalfwidthAlphanumeric.ConvMatches( dwConvMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_English", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_JP_DirectInput;
+ item->active = g_ConversionMode_JP_DirectInput.ConvMatches( dwConvMode );
+
+ }
+ return 6;
+ case KOREAN:
+ // This is either native or alphanumeric
+ if ( dest )
+ {
+ ConversionModeItem *item;
+ int i = 0;
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_Korean", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_KO_ToKorean;
+ item->active = g_ConversionMode_KO_ToKorean.ConvMatches( dwConvMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_English", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_KO_ToEnglish;
+ item->active = g_ConversionMode_KO_ToEnglish.ConvMatches( dwConvMode );
+ }
+ return 2;
+ case SIMPLIFIED_CHINESE:
+ // This is either native or alphanumeric
+ if ( dest )
+ {
+ ConversionModeItem *item;
+ int i = 0;
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_Chinese", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_CHS_ToChinese;
+ item->active = g_ConversionMode_CHS_ToChinese.ConvMatches( dwConvMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_English", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_ConversionMode_CHS_ToChinese;
+ item->active = g_ConversionMode_CHS_ToChinese.ConvMatches( dwConvMode );
+ }
+ return 2;
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef DO_IME
+
+static IMESettingsTransform g_SentenceMode_JP_None(
+ 0,
+ 0,
+ IME_SMODE_PLAURALCLAUSE | IME_SMODE_SINGLECONVERT | IME_SMODE_AUTOMATIC | IME_SMODE_PHRASEPREDICT | IME_SMODE_CONVERSATION,
+ IME_SMODE_NONE );
+
+static IMESettingsTransform g_SentenceMode_JP_General(
+ 0,
+ 0,
+ IME_SMODE_NONE | IME_SMODE_PLAURALCLAUSE | IME_SMODE_SINGLECONVERT | IME_SMODE_AUTOMATIC | IME_SMODE_CONVERSATION,
+ IME_SMODE_PHRASEPREDICT
+ );
+
+static IMESettingsTransform g_SentenceMode_JP_BiasNames(
+ 0,
+ 0,
+ IME_SMODE_NONE | IME_SMODE_PHRASEPREDICT | IME_SMODE_SINGLECONVERT | IME_SMODE_AUTOMATIC | IME_SMODE_CONVERSATION,
+ IME_SMODE_PLAURALCLAUSE
+ );
+
+static IMESettingsTransform g_SentenceMode_JP_BiasSpeech(
+ 0,
+ 0,
+ IME_SMODE_NONE | IME_SMODE_PHRASEPREDICT | IME_SMODE_SINGLECONVERT | IME_SMODE_AUTOMATIC | IME_SMODE_PLAURALCLAUSE,
+ IME_SMODE_CONVERSATION
+ );
+
+#endif // _X360
+
+int CInputSystem::GetIMESentenceModes( SentenceModeItem *dest, int destcount )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ if ( dest )
+ {
+ memset( dest, 0, destcount * sizeof( SentenceModeItem ) );
+ }
+
+ DWORD dwConvMode = 0, dwSentMode = 0;
+
+ HIMC hImc = ImmGetContext( ( HWND )GetIMEWindow() );
+ if ( hImc )
+ {
+ ImmGetConversionStatus( hImc, &dwConvMode, &dwSentMode );
+ ImmReleaseContext( ( HWND )GetIMEWindow(), hImc );
+ }
+
+ LanguageIds *info = GetLanguageInfo( LOWORD( GetKeyboardLayout( 0 ) ) );
+ switch ( info->languageflag )
+ {
+ default:
+ return 0;
+// case TRADITIONAL_CHINESE:
+// break;
+ case JAPANESE:
+ // There are 4 Japanese sentence modes
+ if ( dest )
+ {
+ SentenceModeItem *item;
+
+ int i = 0;
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_General", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_SentenceMode_JP_General;
+ item->active = g_SentenceMode_JP_General.SentMatches( dwSentMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_BiasNames", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_SentenceMode_JP_BiasNames;
+ item->active = g_SentenceMode_JP_BiasNames.SentMatches( dwSentMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_BiasSpeech", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_SentenceMode_JP_BiasSpeech;
+ item->active = g_SentenceMode_JP_BiasSpeech.SentMatches( dwSentMode );
+
+ item = &dest[ i++ ];
+ wcsncpy( item->menuname, L"#IME_NoConversion", sizeof( item->menuname ) / sizeof( wchar_t ) );
+ item->handleValue = (int)&g_SentenceMode_JP_None;
+ item->active = g_SentenceMode_JP_None.SentMatches( dwSentMode );
+ }
+ return 4;
+ }
+#endif
+
+ return 0;
+}
+
+void CInputSystem::OnChangeIMEConversionModeByHandle( int handleValue )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ if ( handleValue == 0 )
+ return;
+
+ IMESettingsTransform *txform = ( IMESettingsTransform * )handleValue;
+ txform->Apply( (HWND)GetIMEWindow() );
+#endif
+}
+
+void CInputSystem::OnChangeIMESentenceModeByHandle( int handleValue )
+{
+}
+
+void CInputSystem::OnInputLanguageChanged()
+{
+}
+
+void CInputSystem::OnIMEStartComposition()
+{
+}
+
+#ifdef DO_IME
+void DescribeIMEFlag( char const *string, bool value )
+{
+ if ( value )
+ {
+ Msg( " %s\n", string );
+ }
+}
+
+#define IMEDesc( x ) DescribeIMEFlag( #x, flags & x );
+#endif // DO_IME
+
+void CInputSystem::OnIMEComposition( int flags )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ /*
+ Msg( "OnIMEComposition\n" );
+
+ IMEDesc( VGUI_GCS_COMPREADSTR );
+ IMEDesc( VGUI_GCS_COMPREADATTR );
+ IMEDesc( VGUI_GCS_COMPREADCLAUSE );
+ IMEDesc( VGUI_GCS_COMPSTR );
+ IMEDesc( VGUI_GCS_COMPATTR );
+ IMEDesc( VGUI_GCS_COMPCLAUSE );
+ IMEDesc( VGUI_GCS_CURSORPOS );
+ IMEDesc( VGUI_GCS_DELTASTART );
+ IMEDesc( VGUI_GCS_RESULTREADSTR );
+ IMEDesc( VGUI_GCS_RESULTREADCLAUSE );
+ IMEDesc( VGUI_GCS_RESULTSTR );
+ IMEDesc( VGUI_GCS_RESULTCLAUSE );
+ IMEDesc( VGUI_CS_INSERTCHAR );
+ IMEDesc( VGUI_CS_NOMOVECARET );
+ */
+
+ HIMC hIMC = ImmGetContext( ( HWND )GetIMEWindow() );
+ if ( hIMC )
+ {
+ if ( flags & VGUI_GCS_RESULTSTR )
+ {
+ wchar_t tempstr[ 32 ];
+
+ int len = ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, (LPVOID)tempstr, sizeof( tempstr ) );
+ if ( len > 0 )
+ {
+ if ((len % 2) != 0)
+ len++;
+ int numchars = len / sizeof( wchar_t );
+
+ for ( int i = 0; i < numchars; ++i )
+ {
+ InternalKeyTyped( tempstr[ i ] );
+ }
+ }
+ }
+ if ( flags & VGUI_GCS_COMPSTR )
+ {
+ wchar_t tempstr[ 256 ];
+
+ int len = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, (LPVOID)tempstr, sizeof( tempstr ) );
+ if ( len > 0 )
+ {
+ if ((len % 2) != 0)
+ len++;
+ int numchars = len / sizeof( wchar_t );
+ tempstr[ numchars ] = L'\0';
+
+ InternalSetCompositionString( tempstr );
+ }
+ }
+
+ ImmReleaseContext( ( HWND )GetIMEWindow(), hIMC );
+ }
+#endif
+}
+
+void CInputSystem::OnIMEEndComposition()
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ( pContext )
+ {
+ // tell the current focused panel that a key was typed
+ PostKeyMessage( new KeyValues( "DoCompositionString", "string", L"" ) );
+ }
+}
+
+void CInputSystem::DestroyCandidateList()
+{
+#ifdef DO_IME
+ if ( _imeCandidates )
+ {
+ delete[] (char *)_imeCandidates;
+ _imeCandidates = null;
+ }
+#endif
+}
+
+void CInputSystem::OnIMEShowCandidates()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ DestroyCandidateList();
+ CreateNewCandidateList();
+
+ InternalShowCandidateWindow();
+#endif
+}
+
+void CInputSystem::OnIMECloseCandidates()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ InternalHideCandidateWindow();
+ DestroyCandidateList();
+#endif
+}
+
+void CInputSystem::OnIMEChangeCandidates()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ DestroyCandidateList();
+ CreateNewCandidateList();
+
+ InternalUpdateCandidateWindow();
+#endif
+}
+
+void CInputSystem::CreateNewCandidateList()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ Assert( !_imeCandidates );
+
+ HIMC hImc = ImmGetContext( ( HWND )GetIMEWindow() );
+ if ( hImc )
+ {
+ DWORD numCandidates = 0;
+
+ DWORD bytes = ImmGetCandidateListCountW( hImc, &numCandidates );
+ if ( numCandidates > 0 )
+ {
+ DWORD buflen = bytes + 1;
+
+ char *buf = new char[ buflen ];
+ Q_memset( buf, 0, buflen );
+
+ CANDIDATELIST *list = ( CANDIDATELIST *)buf;
+ DWORD copyBytes = ImmGetCandidateListW( hImc, 0, list, buflen );
+ if ( copyBytes > 0 )
+ {
+ _imeCandidates = list;
+ }
+ else
+ {
+ delete[] buf;
+ }
+ }
+ ImmReleaseContext( ( HWND )GetIMEWindow(), hImc );
+ }
+#endif
+}
+
+int CInputSystem::GetCandidateListCount()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ if ( !_imeCandidates )
+ return 0;
+
+ return (int)_imeCandidates->dwCount;
+#else
+ return 0;
+#endif
+}
+
+void CInputSystem::GetCandidate( int num, wchar_t *dest, int destSizeBytes )
+{
+ ASSERT_IF_IME_NYI();
+
+ dest[ 0 ] = L'\0';
+#ifdef DO_IME
+ if ( num < 0 || num >= (int)_imeCandidates->dwCount )
+ {
+ return;
+ }
+
+ DWORD offset = *( DWORD *)( (char *)( _imeCandidates->dwOffset + num ) );
+ wchar_t *s = ( wchar_t *)( (char *)_imeCandidates + offset );
+
+ wcsncpy( dest, s, destSizeBytes / sizeof( wchar_t ) - 1 );
+ dest[ destSizeBytes / sizeof( wchar_t ) - 1 ] = L'\0';
+#endif
+}
+
+int CInputSystem::GetCandidateListSelectedItem()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ if ( !_imeCandidates )
+ return 0;
+
+ return (int)_imeCandidates->dwSelection;
+#else
+ return 0;
+#endif
+}
+
+int CInputSystem::GetCandidateListPageSize()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ if ( !_imeCandidates )
+ return 0;
+ return (int)_imeCandidates->dwPageSize;
+#else
+ return 0;
+#endif
+}
+
+int CInputSystem::GetCandidateListPageStart()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ if ( !_imeCandidates )
+ return 0;
+ return (int)_imeCandidates->dwPageStart;
+#else
+ return 0;
+#endif
+}
+
+void CInputSystem::SetCandidateListPageStart( int start )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ HIMC hImc = ImmGetContext( ( HWND )GetIMEWindow() );
+ if ( hImc )
+ {
+ ImmNotifyIME( hImc, NI_SETCANDIDATE_PAGESTART, 0, start );
+ ImmReleaseContext( ( HWND )GetIMEWindow(), hImc );
+ }
+#endif
+}
+
+void CInputSystem::OnIMERecomputeModes()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CInputSystem::CandidateListStartsAtOne()
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ DWORD prop = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
+ if ( prop & IME_PROP_CANDLIST_START_FROM_1 )
+ {
+ return true;
+ }
+#endif
+ return false;
+}
+
+void CInputSystem::SetCandidateWindowPos( int x, int y )
+{
+ ASSERT_IF_IME_NYI();
+
+#ifdef DO_IME
+ POINT point;
+ CANDIDATEFORM Candidate;
+
+ point.x = x;
+ point.y = y;
+
+ HIMC hIMC = ImmGetContext( ( HWND )GetIMEWindow() );
+ if ( hIMC )
+ {
+ // Set candidate window position near caret position
+ Candidate.dwIndex = 0;
+ Candidate.dwStyle = CFS_FORCE_POSITION;
+ Candidate.ptCurrentPos.x = point.x;
+ Candidate.ptCurrentPos.y = point.y;
+ ImmSetCandidateWindow( hIMC, &Candidate );
+
+ ImmReleaseContext( ( HWND )GetIMEWindow(),hIMC );
+ }
+#endif
+}
+
+void CInputSystem::InternalSetCompositionString( const wchar_t *compstr )
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ( pContext )
+ {
+ // tell the current focused panel that a key was typed
+ PostKeyMessage( new KeyValues( "DoCompositionString", "string", compstr ) );
+ }
+}
+
+void CInputSystem::InternalShowCandidateWindow()
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ( pContext )
+ {
+ PostKeyMessage( new KeyValues( "DoShowIMECandidates" ) );
+ }
+}
+
+void CInputSystem::InternalHideCandidateWindow()
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ( pContext )
+ {
+ PostKeyMessage( new KeyValues( "DoHideIMECandidates" ) );
+ }
+}
+
+void CInputSystem::InternalUpdateCandidateWindow()
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if ( pContext )
+ {
+ PostKeyMessage( new KeyValues( "DoUpdateIMECandidates" ) );
+ }
+}
+
+bool CInputSystem::GetShouldInvertCompositionString()
+{
+#ifdef DO_IME
+ LanguageIds *info = GetLanguageInfo( LOWORD( GetKeyboardLayout( 0 ) ) );
+ if ( !info )
+ return false;
+
+ // Only Chinese (simplified and traditional)
+ return info->invertcomposition;
+#else
+ return false;
+#endif
+}
+
+void CInputSystem::RegisterKeyCodeUnhandledListener( VPANEL panel )
+{
+ if ( !panel )
+ return;
+
+ InputContext_t *pContext = GetInputContext(m_hContext);
+ if ( !pContext )
+ return;
+
+ VPanel *listener = (VPanel *)panel;
+
+ if ( pContext->m_KeyCodeUnhandledListeners.Find( listener ) == pContext->m_KeyCodeUnhandledListeners.InvalidIndex() )
+ {
+ pContext->m_KeyCodeUnhandledListeners.AddToTail( listener );
+ }
+}
+
+void CInputSystem::UnregisterKeyCodeUnhandledListener( VPANEL panel )
+{
+ if ( !panel )
+ return;
+
+ InputContext_t *pContext = GetInputContext(m_hContext);
+ if ( !pContext )
+ return;
+
+ VPanel *listener = (VPanel *)panel;
+
+ pContext->m_KeyCodeUnhandledListeners.FindAndRemove( listener );
+}
+
+
+// Posts unhandled message to all interested panels
+void CInputSystem::OnKeyCodeUnhandled( int keyCode )
+{
+ InputContext_t *pContext = GetInputContext(m_hContext);
+ if ( !pContext )
+ return;
+
+ int c = pContext->m_KeyCodeUnhandledListeners.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ VPanel *listener = pContext->m_KeyCodeUnhandledListeners[ i ];
+ g_pIVgui->PostMessage((VPANEL)listener, new KeyValues( "KeyCodeUnhandled", "code", keyCode ), NULL );
+ }
+}
+
+void CInputSystem::PostModalSubTreeMessage( VPanel *subTree, bool state )
+{
+ InputContext_t *pContext = GetInputContext( m_hContext );
+ if( pContext->m_pModalSubTree == NULL )
+ return;
+
+ //tell the current focused panel that a key was released
+ KeyValues *kv = new KeyValues( "ModalSubTree", "state", state ? 1 : 0 );
+ g_pIVgui->PostMessage( (VPANEL)pContext->m_pModalSubTree, kv, NULL );
+}
+
+// Assumes subTree is a child panel of the root panel for the vgui contect
+// if restrictMessagesToSubTree is true, then mouse and kb messages are only routed to the subTree and it's children and mouse/kb focus
+// can only be on one of the subTree children, if a mouse click occurs outside of the subtree, and "UnhandledMouseClick" message is sent to unhandledMouseClickListener panel
+// if it's set
+// if restrictMessagesToSubTree is false, then mouse and kb messages are routed as normal except that they are not routed down into the subtree
+// however, if a mouse click occurs outside of the subtree, and "UnhandleMouseClick" message is sent to unhandledMouseClickListener panel
+// if it's set
+void CInputSystem::SetModalSubTree( VPANEL subTree, VPANEL unhandledMouseClickListener, bool restrictMessagesToSubTree /*= true*/ )
+{
+ InputContext_t *pContext = GetInputContext(m_hContext);
+ if ( !pContext )
+ return;
+
+ if ( pContext->m_pModalSubTree &&
+ pContext->m_pModalSubTree != (VPanel *)subTree )
+ {
+ ReleaseModalSubTree();
+ }
+
+ if ( !subTree )
+ return;
+
+ pContext->m_pModalSubTree = (VPanel *)subTree;
+ pContext->m_pUnhandledMouseClickListener = (VPanel *)unhandledMouseClickListener;
+ pContext->m_bRestrictMessagesToModalSubTree = restrictMessagesToSubTree;
+
+ PostModalSubTreeMessage( pContext->m_pModalSubTree, true );
+}
+
+void CInputSystem::ReleaseModalSubTree()
+{
+ InputContext_t *pContext = GetInputContext(m_hContext);
+ if ( !pContext )
+ return;
+
+ if ( pContext->m_pModalSubTree )
+ {
+ PostModalSubTreeMessage( pContext->m_pModalSubTree, false );
+ }
+
+ pContext->m_pModalSubTree = NULL;
+ pContext->m_pUnhandledMouseClickListener = NULL;
+ pContext->m_bRestrictMessagesToModalSubTree = false;
+
+}
+
+VPANEL CInputSystem::GetModalSubTree()
+{
+ InputContext_t *pContext = GetInputContext(m_hContext);
+ if ( !pContext )
+ return 0;
+
+ return (VPANEL)pContext->m_pModalSubTree;
+}
+
+// These toggle whether the modal subtree is exclusively receiving messages or conversely whether it's being excluded from receiving messages
+void CInputSystem::SetModalSubTreeReceiveMessages( bool state )
+{
+ InputContext_t *pContext = GetInputContext(m_hContext);
+ if ( !pContext )
+ return;
+
+ Assert( pContext->m_pModalSubTree );
+ if ( !pContext->m_pModalSubTree )
+ return;
+
+ pContext->m_bRestrictMessagesToModalSubTree = state;
+
+}
+
+bool CInputSystem::ShouldModalSubTreeReceiveMessages() const
+{
+ InputContext_t *pContext = const_cast< CInputSystem * >( this )->GetInputContext(m_hContext);
+ if ( !pContext )
+ return true;
+
+ return pContext->m_bRestrictMessagesToModalSubTree;
+}
diff --git a/vgui2/src/LocalizedStringTable.cpp b/vgui2/src/LocalizedStringTable.cpp
new file mode 100644
index 0000000..4e34164
--- /dev/null
+++ b/vgui2/src/LocalizedStringTable.cpp
@@ -0,0 +1,1060 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+
+#pragma warning( disable: 4018 ) // '==' : signed/unsigned mismatch in rbtree
+#if defined( WIN32 ) && !defined( _X360 )
+#include <windows.h>
+#elif defined( POSIX )
+#include <iconv.h>
+
+#endif
+#include <wchar.h>
+
+#include "filesystem.h"
+
+#include "vgui_internal.h"
+#include "vgui/ILocalize.h"
+#include "vgui/ISystem.h"
+#include "vgui/ISurface.h"
+
+#include "tier1/utlvector.h"
+#include "tier1/utlrbtree.h"
+#include "tier1/utlsymbol.h"
+#include "tier1/utlstring.h"
+#include "UnicodeFileHelpers.h"
+#include "tier0/icommandline.h"
+#include "byteswap.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+#define MAX_LOCALIZED_CHARS 4096
+
+//-----------------------------------------------------------------------------
+//
+// Internal implementation
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Purpose: Maps token names to localized unicode strings
+//-----------------------------------------------------------------------------
+class CLocalizedStringTable : public vgui::ILocalize
+{
+public:
+ CLocalizedStringTable();
+ ~CLocalizedStringTable();
+
+ // adds the contents of a file to the localization table
+ virtual bool AddFile( const char *fileName, const char *pPathID, bool bIncludeFallbackSearchPaths );
+
+ // saves the entire contents of the token tree to the file
+ bool SaveToFile( const char *fileName );
+
+ // adds a single name/unicode string pair to the table
+ void AddString(const char *tokenName, wchar_t *unicodeString, const char *fileName);
+
+ // Finds the localized text for pName
+ wchar_t *Find(const char *pName);
+
+ // finds the index of a token by token name
+ StringIndex_t FindIndex(const char *pName);
+
+ // Remove all strings in the table.
+ void RemoveAll();
+
+ // iteration functions
+ StringIndex_t GetFirstStringIndex();
+
+ // returns the next index, or INVALID_LOCALIZE_STRING_INDEX if no more strings available
+ StringIndex_t GetNextStringIndex(StringIndex_t index);
+
+ // gets the values from the index
+ const char *GetNameByIndex(StringIndex_t index);
+ wchar_t *GetValueByIndex(StringIndex_t index);
+ const char *GetFileNameByIndex(StringIndex_t index);
+
+ // sets the value in the index
+ // has bad memory characteristics, should only be used in the editor
+ void SetValueByIndex(StringIndex_t index, wchar_t *newValue);
+
+ // iterates the filenames
+ int GetLocalizationFileCount();
+ const char *GetLocalizationFileName(int index);
+
+ // returns whether a file has already been loaded
+ bool LocalizationFileIsLoaded( const char *name );
+
+ const char *FindAsUTF8( const char *pchTokenName );
+
+ virtual void ConstructString(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const char *tokenName, KeyValues *localizationVariables);
+ virtual void ConstructString(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, StringIndex_t unlocalizedTextSymbol, KeyValues *localizationVariables);
+
+private:
+ // for development only, reloads localization files
+ virtual void ReloadLocalizationFiles( );
+
+ bool AddAllLanguageFiles( const char *baseFileName );
+
+ void BuildFastValueLookup();
+ void DiscardFastValueLookup();
+ int FindExistingValueIndex( const wchar_t *value );
+
+ char m_szLanguage[64];
+ bool m_bUseOnlyLongestLanguageString;
+
+ struct localizedstring_t
+ {
+ StringIndex_t nameIndex;
+ // nameIndex == INVALID_LOCALIZE_STRING_INDEX is used only for searches and implies
+ // that pszValueString will be used from union fields.
+ union
+ {
+ StringIndex_t valueIndex; // Used when nameIndex != INVALID_LOCALIZE_STRING_INDEX
+ char const * pszValueString; // Used only if nameIndex == INVALID_LOCALIZE_STRING_INDEX
+ };
+ CUtlSymbol filename;
+ };
+
+ // Stores the symbol lookup
+ CUtlRBTree<localizedstring_t, StringIndex_t> m_Lookup;
+
+ // stores the string data
+ CUtlVector<char> m_Names;
+ CUtlVector<wchar_t> m_Values;
+ CUtlSymbol m_CurrentFile;
+
+ struct LocalizationFileInfo_t
+ {
+ CUtlSymbol symName;
+ CUtlSymbol symPathID;
+ bool bIncludeFallbacks;
+
+ static bool LessFunc( const LocalizationFileInfo_t& lhs, const LocalizationFileInfo_t& rhs )
+ {
+ int iresult = Q_stricmp( lhs.symPathID.String(), rhs.symPathID.String() );
+ if ( iresult != 0 )
+ {
+ return iresult == -1;
+ }
+
+ return Q_stricmp( lhs.symName.String(), rhs.symName.String() ) < 0;
+ }
+ };
+
+ CUtlVector< LocalizationFileInfo_t > m_LocalizationFiles;
+
+ struct fastvalue_t
+ {
+ int valueindex;
+ const wchar_t *search;
+
+ static CLocalizedStringTable *s_pTable;
+ };
+
+ CUtlRBTree< fastvalue_t, int > m_FastValueLookup;
+
+ static CLocalizedStringTable *s_pTable;
+
+ // Less function, for sorting strings
+ static bool SymLess( localizedstring_t const& i1, localizedstring_t const& i2 );
+
+ static bool FastValueLessFunc( const fastvalue_t& lhs, const fastvalue_t& rhs );
+};
+
+// global instance of table
+CLocalizedStringTable g_StringTable;
+
+// expose the interface
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR_WITH_NAMESPACE(CLocalizedStringTable, vgui::, ILocalize, VGUI_LOCALIZE_INTERFACE_VERSION, g_StringTable);
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CLocalizedStringTable::CLocalizedStringTable() :
+ m_Lookup( 0, 0, SymLess ), m_Names( 1024 ), m_Values( 2048 ), m_FastValueLookup( 0, 0, FastValueLessFunc )
+{
+ m_bUseOnlyLongestLanguageString = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CLocalizedStringTable::~CLocalizedStringTable()
+{
+ m_Names.Purge();
+ m_Values.Purge();
+ m_LocalizationFiles.Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds the contents of a file
+//-----------------------------------------------------------------------------
+bool CLocalizedStringTable::AddFile( const char *szFileName, const char *pPathID, bool bIncludeFallbackSearchPaths )
+{
+ // use the correct file based on the chosen language
+ static const char *const LANGUAGE_STRING = "%language%";
+ static const char *const ENGLISH_STRING = "english";
+ static const int MAX_LANGUAGE_NAME_LENGTH = 64;
+ char language[MAX_LANGUAGE_NAME_LENGTH];
+ char fileName[MAX_PATH];
+ int offs = 0;
+ bool success = false;
+
+ memset( language, 0, sizeof(language) );
+
+ Q_strncpy( fileName, szFileName, sizeof( fileName ) );
+
+ // Lowercase the *relative* portion of the filename,
+ // in case people look for "Resource/file.txt" etc. We always
+ // use lowercase filenames for files in the game filesystem.
+ V_strlower( fileName );
+
+ const char *langptr = strstr(szFileName, LANGUAGE_STRING);
+ if (langptr)
+ {
+ // LOAD THE ENGLISH FILE FIRST
+ // always load the file to make sure we're not missing any strings
+ // copy out the initial part of the string
+ offs = langptr - szFileName;
+ strncpy(fileName, szFileName, offs);
+ fileName[offs] = 0;
+
+ if ( vgui::g_pSystem->CommandLineParamExists("-all_languages") )
+ {
+ m_bUseOnlyLongestLanguageString = true;
+ return AddAllLanguageFiles( fileName );
+ }
+
+ // append "english" as our default language
+ Q_strncat(fileName, ENGLISH_STRING, sizeof( fileName ), COPY_ALL_CHARACTERS );
+
+ // append the end of the initial string
+ offs += strlen(LANGUAGE_STRING);
+ Q_strncat(fileName, szFileName + offs, sizeof( fileName ), COPY_ALL_CHARACTERS);
+
+ success = AddFile( fileName, pPathID, bIncludeFallbackSearchPaths );
+
+ bool bValid;
+ if ( IsPC() )
+ {
+ bValid = vgui::g_pSystem->GetRegistryString( "HKEY_CURRENT_USER\\Software\\Valve\\Source\\Language", language, sizeof(language)-1 );
+ }
+ else
+ {
+ Q_strncpy( language, XBX_GetLanguageString(), sizeof( language ) );
+ bValid = true;
+ }
+
+ // LOAD THE LOCALIZED FILE IF IT'S NOT ENGLISH
+ // append the language
+ if ( bValid )
+ {
+ if ( strlen(language) != 0 && stricmp(language, ENGLISH_STRING) != 0 )
+ {
+ // copy out the initial part of the string
+ offs = langptr - szFileName;
+ strncpy(fileName, szFileName, offs);
+ fileName[offs] = 0;
+
+ Q_strncat(fileName, language, sizeof( fileName ), COPY_ALL_CHARACTERS);
+
+ // append the end of the initial string
+ offs += strlen(LANGUAGE_STRING);
+ Q_strncat(fileName, szFileName + offs, sizeof( fileName ), COPY_ALL_CHARACTERS );
+
+ success &= AddFile( fileName, pPathID, bIncludeFallbackSearchPaths );
+ }
+ }
+ return success;
+ }
+
+ // store the localization file name if it doesn't already exist
+ LocalizationFileInfo_t search;
+ search.symName = fileName;
+ search.symPathID = pPathID ? pPathID : "";
+ search.bIncludeFallbacks = bIncludeFallbackSearchPaths;
+
+ int lfc = m_LocalizationFiles.Count();
+ for ( int lf = 0; lf < lfc; ++lf )
+ {
+ LocalizationFileInfo_t& entry = m_LocalizationFiles[ lf ];
+ if ( !Q_stricmp( entry.symName.String(), fileName ) )
+ {
+ m_LocalizationFiles.Remove( lf );
+ break;
+ }
+ }
+
+ m_LocalizationFiles.AddToTail( search );
+
+ // This will give us a list of paths from highest to lowest precedence: e.g.:
+ // for "GAME" when running -game episodic, it'll show:
+ // "basedir/episodic/;basedir/hl2"
+ // We do this manually instead of just asking for the first match to support bIncludeFallbackSearchPaths
+ char searchPaths[ MAX_PATH*50 ] = { 0 }; // allow for 50 search paths
+
+ Verify( g_pFullFileSystem->GetSearchPath( pPathID, true, searchPaths, sizeof( searchPaths ) ) < sizeof(searchPaths) );
+
+ CUtlSymbolTable pathStrings;
+ CUtlVector< CUtlSymbol > searchList;
+
+ bool bIsFullPath = false;
+ if ( V_IsAbsolutePath( fileName ) )
+ {
+ bIsFullPath = true;
+ CUtlSymbol sym = pathStrings.AddString( fileName );
+ searchList.AddToHead( sym );
+ }
+ else
+ {
+ // We want to walk them in reverse order so newer files are "overrides" for older ones, so we add them to a list in reverse order
+ for ( char *path = strtok( searchPaths, ";" ); path; path = strtok( NULL, ";" ) )
+ {
+ if ( IsX360() && ( g_pFullFileSystem->GetDVDMode() == DVDMODE_STRICT ) && !V_stristr( path, ".zip" ) )
+ {
+ // only want zip paths
+ continue;
+ }
+
+ char fullpath[MAX_PATH];
+ V_strcpy_safe( fullpath, path );
+ V_AppendSlash( fullpath, sizeof(fullpath) );
+ V_strcat_safe( fullpath, fileName );
+ Q_FixSlashes( fullpath );
+ //Q_strlower( fullpath ); // NO! This screws up Linux
+
+ CUtlSymbol sym = pathStrings.AddString( fullpath );
+ // With bIncludeFallbackSearchPaths we iterate overriding as we go, so push them in reverse order so the
+ // highest precendence search paths have the highest precendence. Otherwise push them in order, as we'll
+ // only process the first one.
+ if ( !bIncludeFallbackSearchPaths )
+ {
+ searchList.AddToTail( sym );
+ }
+ else
+ {
+ searchList.AddToHead( sym );
+ }
+ }
+ }
+
+ bool first = true;
+ bool bLoadedAtLeastOne = false;
+
+ for ( int sp = 0; sp < searchList.Count(); ++sp )
+ {
+ const char *fullpath = pathStrings.String( searchList[ sp ] );
+
+ // parse out the file
+ FileHandle_t file = g_pFullFileSystem->Open( fullpath, "rb" );
+ if (!file)
+ {
+ continue;
+ }
+
+ if ( first )
+ {
+ first = false;
+ }
+ else if ( !bIncludeFallbackSearchPaths )
+ {
+ g_pFullFileSystem->Close(file);
+ break;
+ }
+
+ bLoadedAtLeastOne = true;
+
+ // this is an optimization so that the filename string doesn't have to get converted to a symbol for each key/value
+ m_CurrentFile = fullpath;
+
+ // read into a memory block
+ int fileSize = g_pFullFileSystem->Size(file);
+ int bufferSize = g_pFullFileSystem->GetOptimalReadSize( file, fileSize + sizeof(ucs2) );
+ ucs2 *memBlock = (ucs2 *)g_pFullFileSystem->AllocOptimalReadBuffer(file, bufferSize);
+ bool bReadOK = ( g_pFullFileSystem->ReadEx(memBlock, bufferSize, fileSize, file) != 0 );
+
+ // finished with file
+ g_pFullFileSystem->Close(file);
+
+ // null-terminate the stream
+ memBlock[fileSize / sizeof(ucs2)] = 0x0000;
+
+ // check the first character, make sure this a little-endian unicode file
+ ucs2 *data = memBlock;
+ ucs2 signature = LittleShort( data[0] );
+ if ( !bReadOK || signature != 0xFEFF )
+ {
+ Msg( "Ignoring non-unicode close caption file %s\n", fullpath );
+ g_pFullFileSystem->FreeOptimalReadBuffer( memBlock );
+ return false;
+ }
+
+ // ensure little-endian unicode reads correctly on all platforms
+ CByteswap byteSwap;
+ byteSwap.SetTargetBigEndian( false );
+ byteSwap.SwapBufferToTargetEndian( data, data, fileSize / sizeof(ucs2) );
+
+ // skip past signature
+ data++;
+
+ // parse out a token at a time
+ enum states_e
+ {
+ STATE_BASE, // looking for base settings
+ STATE_TOKENS, // reading in unicode tokens
+ };
+
+ bool bQuoted;
+ bool bEnglishFile = false;
+ if ( strstr(fullpath, "_english.txt") )
+ {
+ bEnglishFile = true;
+ }
+
+ bool spew = false;
+ if ( CommandLine()->FindParm( "-ccsyntax" ) )
+ {
+ spew = true;
+ }
+
+ BuildFastValueLookup();
+
+ states_e state = STATE_BASE;
+ while (1)
+ {
+ // read the key and the value
+ ucs2 keytoken[128];
+ ucs2 *pchNewdata = ReadUnicodeToken(data, keytoken, ARRAYSIZE(keytoken), bQuoted);
+ if (!keytoken[0])
+ break; // we've hit the null terminator
+
+ // convert the token to a string
+ char key[128];
+ V_UCS2ToUTF8(keytoken, key, static_cast<int>( sizeof(key) ));
+ data = pchNewdata;
+
+ // if we have a C++ style comment, read to end of line and continue
+ if (!strnicmp(key, "//", 2))
+ {
+ data = ReadToEndOfLine(data);
+ continue;
+ }
+
+ if ( spew )
+ {
+ Msg( "%s\n", key );
+ }
+
+ ucs2 valuetoken[ MAX_LOCALIZED_CHARS ];
+ data = ReadUnicodeToken(data, valuetoken, MAX_LOCALIZED_CHARS, bQuoted);
+ if (!valuetoken[0] && !bQuoted)
+ break; // we've hit the null terminator
+
+ if (state == STATE_BASE)
+ {
+ if (!stricmp(key, "Language"))
+ {
+ // copy out our language setting
+ char value[MAX_LOCALIZED_CHARS];
+ V_UCS2ToUTF8(valuetoken, value, sizeof(value));
+ strncpy(m_szLanguage, value, sizeof(m_szLanguage) - 1);
+ }
+ else if (!stricmp(key, "Tokens"))
+ {
+ state = STATE_TOKENS;
+ }
+ else if (!stricmp(key, "}"))
+ {
+ // we've hit the end
+ break;
+ }
+ }
+ else if (state == STATE_TOKENS)
+ {
+ if (!stricmp(key, "}"))
+ {
+ // end of tokens
+ state = STATE_BASE;
+ }
+ else
+ {
+ // skip our [english] beginnings (in non-english files)
+ if ( (bEnglishFile) || (!bEnglishFile && strnicmp(key, "[english]", 9)))
+ {
+ // Check for a conditional tag
+ bool bAccepted = true;
+ ucs2 conditional[ MAX_LOCALIZED_CHARS ];
+ ucs2 *tempData = ReadUnicodeToken(data, conditional, MAX_LOCALIZED_CHARS, bQuoted);
+ if ( !bQuoted && conditional[0] == L'[' && conditional[1] == L'$' ) // wcsstr( conditional, L"[$" ) )
+ {
+ // Evaluate the conditional tag
+ char cond[MAX_LOCALIZED_CHARS];
+ V_UCS2ToUTF8(conditional, cond, sizeof(cond));
+ bAccepted = EvaluateConditional( cond );
+
+ // Robin: HACK: Cheesy support for language-based filtering. Main has much better
+ // support for this, in all KV files, so this will be obsoleted in post-TF2 products.
+ char *pszKey = &cond[2];
+ bool bNot = false;
+ if ( pszKey[0] == '!' )
+ {
+ bNot = true;
+ pszKey++;
+ }
+ // Trim off the ]
+ if ( pszKey && pszKey[0] )
+ {
+ pszKey[ V_strlen(pszKey)-1 ] = '\0';
+ if ( !V_stricmp( pszKey, "ENGLISH" ) ||
+ !V_stricmp( pszKey, "JAPANESE" ) ||
+ !V_stricmp( pszKey, "GERMAN" ) ||
+ !V_stricmp( pszKey, "FRENCH" ) ||
+ !V_stricmp( pszKey, "SPANISH" ) ||
+ !V_stricmp( pszKey, "ITALIAN" ) ||
+ !V_stricmp( pszKey, "KOREAN" ) ||
+ !V_stricmp( pszKey, "TCHINESE" ) ||
+ !V_stricmp( pszKey, "PORTUGUESE" ) ||
+ !V_stricmp( pszKey, "SCHINESE" ) ||
+ !V_stricmp( pszKey, "POLISH" ) ||
+ !V_stricmp( pszKey, "RUSSIAN" ) )
+ {
+ // the language symbols are true if we are in that language
+ // english is assumed when no language is present
+ const char *pLanguageString;
+#ifdef _X360
+ pLanguageString = XBX_GetLanguageString();
+#else
+ static ConVarRef cl_language( "cl_language" );
+ pLanguageString = cl_language.GetString();
+#endif
+ if ( !pLanguageString || !pLanguageString[0] )
+ {
+ pLanguageString = "english";
+ }
+ bool bMatched = ( !V_stricmp( pszKey, pLanguageString ) );
+ bAccepted = (bMatched && !bNot) || (!bMatched && bNot);
+ }
+ }
+
+ data = tempData;
+ }
+ if ( bAccepted )
+ {
+ wchar_t fullString[MAX_LOCALIZED_CHARS+1];
+ int i = 0;
+ for ( i = 0; i < MAX_LOCALIZED_CHARS && valuetoken[i] != 0; i++ )
+ fullString[i] = valuetoken[i]; // explode the ucs2 into a wchar_t wide buffer
+ fullString[i] = 0;
+
+ // add the string to the table
+ AddString(key, fullString, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ g_pFullFileSystem->FreeOptimalReadBuffer( memBlock );
+ }
+
+ if ( !bLoadedAtLeastOne )
+ {
+ Warning("CLocalizedStringTable::AddFile() failed to load file \"%s\".\n", szFileName );
+ }
+
+ DiscardFastValueLookup();
+ m_CurrentFile = UTL_INVAL_SYMBOL;
+ return bLoadedAtLeastOne;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Load all the localized language strings, and uses the longest string from each language
+//-----------------------------------------------------------------------------
+bool CLocalizedStringTable::AddAllLanguageFiles( const char *baseFileName )
+{
+ bool success = true;
+
+ // work out the path the files are in
+ char szFilePath[MAX_PATH];
+ Q_strncpy( szFilePath, baseFileName, sizeof(szFilePath) );
+ char *lastSlash = strrchr( szFilePath, '\\' );
+ if (!lastSlash)
+ {
+ lastSlash = strrchr( szFilePath, '/' );
+ }
+ if (lastSlash)
+ {
+ lastSlash[1] = 0;
+ }
+ else
+ {
+ szFilePath[0] = 0;
+ }
+
+ // iterate through and add all the languages (for development)
+ // the longest string out of all the languages will be used
+ char szSearchPath[MAX_PATH];
+ Q_snprintf( szSearchPath, sizeof(szSearchPath), "%s*.txt", baseFileName );
+
+ FileFindHandle_t hFind = NULL;
+ const char *file = g_pFullFileSystem->FindFirst( szSearchPath, &hFind );
+ while ( file )
+ {
+ // re-add in the search path
+ char szFile[MAX_PATH];
+ Q_snprintf( szFile, sizeof(szFile), "%s%s", szFilePath, file );
+
+ // add the file
+ success &= AddFile( szFile, NULL, true );
+
+ // next file
+ file = g_pFullFileSystem->FindNext( hFind );
+ }
+ g_pFullFileSystem->FindClose( hFind );
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: saves the entire contents of the token tree to the file
+//-----------------------------------------------------------------------------
+bool CLocalizedStringTable::SaveToFile( const char *szFileName )
+{
+ // parse out the file
+ FileHandle_t file = g_pFullFileSystem->Open(szFileName, "wb");
+ if (!file)
+ return false;
+
+ // only save the symbols relevant to this file
+ CUtlSymbol fileName = szFileName;
+
+ // write litte-endian unicode marker
+ unsigned short marker = 0xFEFF;
+ marker = LittleShort( marker );
+ g_pFullFileSystem->Write(&marker, sizeof( marker ), file);
+
+ const char *startStr = "\"lang\"\r\n{\r\n\"Language\" \"English\"\r\n\"Tokens\"\r\n{\r\n";
+ const char *endStr = "}\r\n}\r\n";
+
+ // write out the first string
+ static wchar_t unicodeString[1024];
+ int strLength = ConvertANSIToUnicode(startStr, unicodeString, sizeof(unicodeString));
+ if (!strLength)
+ return false;
+
+ g_pFullFileSystem->Write(unicodeString, wcslen( unicodeString ) * sizeof(wchar_t), file);
+
+ // convert our spacing characters to unicode
+// wchar_t unicodeSpace = L' ';
+ wchar_t unicodeQuote = L'\"';
+ wchar_t unicodeCR = L'\r';
+ wchar_t unicodeNewline = L'\n';
+ wchar_t unicodeTab = L'\t';
+
+ // write out all the key/value pairs
+ for (StringIndex_t idx = GetFirstStringIndex(); idx != INVALID_LOCALIZE_STRING_INDEX; idx = GetNextStringIndex(idx))
+ {
+ // only write strings that belong in this file
+ if (fileName != m_Lookup[idx].filename)
+ continue;
+
+ const char *name = GetNameByIndex(idx);
+ wchar_t *value = GetValueByIndex(idx);
+
+ // convert the name to a unicode string
+ ConvertANSIToUnicode(name, unicodeString, sizeof(unicodeString));
+
+ g_pFullFileSystem->Write(&unicodeTab, sizeof(wchar_t), file);
+
+ // write out
+ g_pFullFileSystem->Write(&unicodeQuote, sizeof(wchar_t), file);
+ g_pFullFileSystem->Write(unicodeString, wcslen( unicodeString ) * sizeof(wchar_t), file);
+ g_pFullFileSystem->Write(&unicodeQuote, sizeof(wchar_t), file);
+
+ g_pFullFileSystem->Write(&unicodeTab, sizeof(wchar_t), file);
+ g_pFullFileSystem->Write(&unicodeTab, sizeof(wchar_t), file);
+
+ g_pFullFileSystem->Write(&unicodeQuote, sizeof(wchar_t), file);
+ g_pFullFileSystem->Write(value, wcslen(value) * sizeof(wchar_t), file);
+ g_pFullFileSystem->Write(&unicodeQuote, sizeof(wchar_t), file);
+
+ g_pFullFileSystem->Write(&unicodeCR, sizeof(wchar_t), file);
+ g_pFullFileSystem->Write(&unicodeNewline, sizeof(wchar_t), file);
+ }
+
+ // write end string
+ strLength = ConvertANSIToUnicode(endStr, unicodeString, sizeof(unicodeString));
+ g_pFullFileSystem->Write(unicodeString, strLength * sizeof(wchar_t), file);
+
+ g_pFullFileSystem->Close(file);
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: for development, reloads localization files
+//-----------------------------------------------------------------------------
+void CLocalizedStringTable::ReloadLocalizationFiles( )
+{
+ // re-add all the localization files
+ for (int i = 0; i < m_LocalizationFiles.Count(); i++)
+ {
+ LocalizationFileInfo_t& entry = m_LocalizationFiles[ i ];
+ AddFile
+ (
+ entry.symName.String(),
+ entry.symPathID.String()[0] ? entry.symPathID.String() : NULL,
+ entry.bIncludeFallbacks
+ );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Used to sort strings
+//-----------------------------------------------------------------------------
+bool CLocalizedStringTable::SymLess(localizedstring_t const &i1, localizedstring_t const &i2)
+{
+ const char *str1 = (i1.nameIndex == INVALID_LOCALIZE_STRING_INDEX) ? i1.pszValueString :
+ &g_StringTable.m_Names[i1.nameIndex];
+ const char *str2 = (i2.nameIndex == INVALID_LOCALIZE_STRING_INDEX) ? i2.pszValueString :
+ &g_StringTable.m_Names[i2.nameIndex];
+
+ return stricmp(str1, str2) < 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Finds a string in the table
+//-----------------------------------------------------------------------------
+wchar_t *CLocalizedStringTable::Find(const char *pName)
+{
+ StringIndex_t idx = FindIndex(pName);
+ if (idx == INVALID_LOCALIZE_STRING_INDEX)
+ return NULL;
+
+ return &m_Values[m_Lookup[idx].valueIndex];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finds a string in the table
+//-----------------------------------------------------------------------------
+const char *CLocalizedStringTable::FindAsUTF8( const char *pchTokenName )
+{
+ wchar_t *pwch = Find( pchTokenName );
+ if ( !pwch )
+ return pchTokenName;
+
+ static char rgchT[2048];
+ Q_UnicodeToUTF8( pwch, rgchT, sizeof( rgchT ) );
+ return rgchT;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: finds the index of a token by token name
+//-----------------------------------------------------------------------------
+StringIndex_t CLocalizedStringTable::FindIndex(const char *pName)
+{
+ if (!pName)
+ return NULL;
+
+ // strip the pound character (which is used elsewhere to indicate that it's a string that should be translated)
+ if (pName[0] == '#')
+ {
+ pName++;
+ }
+
+ // Passing this special invalid symbol makes the comparison function
+ // use the string passed in the context
+ localizedstring_t invalidItem;
+ invalidItem.nameIndex = INVALID_LOCALIZE_STRING_INDEX;
+ invalidItem.pszValueString = pName;
+ return m_Lookup.Find( invalidItem );
+}
+
+//-----------------------------------------------------------------------------
+// Finds and/or creates a symbol based on the string
+//-----------------------------------------------------------------------------
+void CLocalizedStringTable::AddString(const char *pString, wchar_t *pValue, const char *fileName)
+{
+ if (!pString)
+ return;
+
+ MEM_ALLOC_CREDIT();
+
+ // see if the value is already in our string table
+ int valueIndex = FindExistingValueIndex( pValue );
+ if ( valueIndex == INVALID_LOCALIZE_STRING_INDEX )
+ {
+ int len = wcslen( pValue ) + 1;
+ valueIndex = m_Values.AddMultipleToTail( len );
+ memcpy( &m_Values[valueIndex], pValue, len * sizeof(wchar_t) );
+ }
+
+ // see if the key is already in the table
+ StringIndex_t stridx = FindIndex( pString );
+ localizedstring_t item;
+ item.nameIndex = stridx;
+
+ if ( stridx == INVALID_LOCALIZE_STRING_INDEX )
+ {
+ // didn't find, insert the string into the vector.
+ int len = strlen(pString) + 1;
+ stridx = m_Names.AddMultipleToTail( len );
+ memcpy( &m_Names[stridx], pString, len * sizeof(char) );
+
+ item.nameIndex = stridx;
+ item.valueIndex = valueIndex;
+ item.filename = fileName ? fileName : m_CurrentFile;
+
+ m_Lookup.Insert( item );
+ }
+ else
+ {
+ // it's already in the table
+
+ if ( m_bUseOnlyLongestLanguageString )
+ {
+ // check which string is longer
+ wchar_t *newValue = pValue;
+ wchar_t *oldValue = GetValueByIndex( stridx );
+
+ // get the width of the string, using just the first font
+ int newWide, oldWide, tall;
+ vgui::g_pSurface->GetTextSize( 1, newValue, newWide, tall );
+ vgui::g_pSurface->GetTextSize( 1, oldValue, oldWide, tall );
+
+ // if the new one is shorter, don't let it be added
+ if (newWide < oldWide)
+ return;
+ }
+
+ // replace the current item
+ item.nameIndex = GetNameByIndex( stridx ) - &m_Names[ 0 ];
+ item.valueIndex = valueIndex;
+ item.filename = fileName ? fileName : m_CurrentFile;
+ m_Lookup[ stridx ] = item;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Remove all symbols in the table.
+//-----------------------------------------------------------------------------
+void CLocalizedStringTable::RemoveAll()
+{
+ m_Lookup.RemoveAll();
+ m_Names.RemoveAll();
+ m_Values.RemoveAll();
+ m_LocalizationFiles.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: iteration functions
+//-----------------------------------------------------------------------------
+StringIndex_t CLocalizedStringTable::GetFirstStringIndex()
+{
+ return m_Lookup.FirstInorder();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the next index, or INVALID_LOCALIZE_STRING_INDEX if no more strings available
+//-----------------------------------------------------------------------------
+StringIndex_t CLocalizedStringTable::GetNextStringIndex(StringIndex_t index)
+{
+ StringIndex_t idx = m_Lookup.NextInorder(index);
+ if (idx == m_Lookup.InvalidIndex())
+ return INVALID_LOCALIZE_STRING_INDEX;
+ return idx;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the name of the localization string by index
+//-----------------------------------------------------------------------------
+const char *CLocalizedStringTable::GetNameByIndex(StringIndex_t index)
+{
+ localizedstring_t &lstr = m_Lookup[index];
+ return &m_Names[lstr.nameIndex];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the localized string value by index
+//-----------------------------------------------------------------------------
+wchar_t *CLocalizedStringTable::GetValueByIndex(StringIndex_t index)
+{
+ if (index == INVALID_LOCALIZE_STRING_INDEX)
+ return NULL;
+
+ localizedstring_t &lstr = m_Lookup[index];
+ return &m_Values[lstr.valueIndex];
+}
+
+
+CLocalizedStringTable *CLocalizedStringTable::s_pTable = NULL;
+
+bool CLocalizedStringTable::FastValueLessFunc( const fastvalue_t& lhs, const fastvalue_t& rhs )
+{
+ Assert( s_pTable );
+
+ const wchar_t *w1 = lhs.search ? lhs.search : &s_pTable->m_Values[ lhs.valueindex ];
+ const wchar_t *w2 = rhs.search ? rhs.search : &s_pTable->m_Values[ rhs.valueindex ];
+
+ return ( wcscmp( w1, w2 ) < 0 ) ? true : false;
+}
+
+void CLocalizedStringTable::BuildFastValueLookup()
+{
+ m_FastValueLookup.RemoveAll();
+ s_pTable = this;
+
+ // Build it
+ int c = m_Lookup.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ fastvalue_t val;
+ val.valueindex = m_Lookup[ i ].valueIndex;
+ val.search = NULL;
+
+ m_FastValueLookup.Insert( val );
+ }
+}
+
+void CLocalizedStringTable::DiscardFastValueLookup()
+{
+ m_FastValueLookup.RemoveAll();
+ s_pTable = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CLocalizedStringTable::FindExistingValueIndex( const wchar_t *value )
+{
+ if ( !s_pTable )
+ return INVALID_LOCALIZE_STRING_INDEX;
+
+ fastvalue_t val;
+ val.valueindex = -1;
+ val.search = value;
+
+ int idx = m_FastValueLookup.Find( val );
+ if ( idx != m_FastValueLookup.InvalidIndex() )
+ {
+ return m_FastValueLookup[ idx ].valueindex;
+ }
+ return INVALID_LOCALIZE_STRING_INDEX;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns which file a string was loaded from
+//-----------------------------------------------------------------------------
+const char *CLocalizedStringTable::GetFileNameByIndex(StringIndex_t index)
+{
+ localizedstring_t &lstr = m_Lookup[index];
+ return lstr.filename.String();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the value in the index
+//-----------------------------------------------------------------------------
+void CLocalizedStringTable::SetValueByIndex(StringIndex_t index, wchar_t *newValue)
+{
+ // get the existing string
+ localizedstring_t &lstr = m_Lookup[index];
+ wchar_t *wstr = &m_Values[lstr.valueIndex];
+
+ // see if the new string will fit within the old memory
+ int newLen = wcslen(newValue);
+ int oldLen = wcslen(wstr);
+
+ if (newLen > oldLen)
+ {
+ // it won't fit, so allocate new memory - this is wasteful, but only happens in edit mode
+ lstr.valueIndex = m_Values.AddMultipleToTail(newLen + 1);
+ memcpy(&m_Values[lstr.valueIndex], newValue, (newLen + 1) * sizeof(wchar_t));
+ }
+ else
+ {
+ // copy the string into the old position
+ wcscpy(wstr, newValue);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns number of localization files currently loaded
+//-----------------------------------------------------------------------------
+int CLocalizedStringTable::GetLocalizationFileCount()
+{
+ return m_LocalizationFiles.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns localization filename by index
+//-----------------------------------------------------------------------------
+const char *CLocalizedStringTable::GetLocalizationFileName(int index)
+{
+ return m_LocalizationFiles[index].symName.String();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether a localization file has been loaded already
+//-----------------------------------------------------------------------------
+bool CLocalizedStringTable::LocalizationFileIsLoaded(const char *name)
+{
+ int c = m_LocalizationFiles.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ if ( !Q_stricmp( m_LocalizationFiles[ i ].symName.String(), name ) )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructs a string, inserting variables where necessary
+//-----------------------------------------------------------------------------
+void CLocalizedStringTable::ConstructString(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const char *tokenName, KeyValues *localizationVariables)
+{
+ StringIndex_t index = FindIndex(tokenName);
+
+ if (index != INVALID_LOCALIZE_STRING_INDEX)
+ {
+ ConstructString(unicodeOutput, unicodeBufferSizeInBytes, index, localizationVariables);
+ }
+ else
+ {
+ // string not found, just return the token name
+ ConvertANSIToUnicode(tokenName, unicodeOutput, unicodeBufferSizeInBytes);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructs a string, inserting variables where necessary
+//-----------------------------------------------------------------------------
+void CLocalizedStringTable::ConstructString(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, StringIndex_t unlocalizedTextSymbol, KeyValues *localizationVariables)
+{
+ if (unicodeBufferSizeInBytes < 1)
+ return;
+
+ unicodeOutput[0] = 0;
+ const wchar_t *searchPos = GetValueByIndex(unlocalizedTextSymbol);
+ if (!searchPos)
+ {
+ wcsncpy(unicodeOutput, L"[unknown string]", unicodeBufferSizeInBytes / sizeof(wchar_t));
+ return;
+ }
+
+ ILocalize::ConstructString( unicodeOutput, unicodeBufferSizeInBytes, searchPos, localizationVariables );
+}
diff --git a/vgui2/src/MemoryBitmap.cpp b/vgui2/src/MemoryBitmap.cpp
new file mode 100644
index 0000000..d6c585b
--- /dev/null
+++ b/vgui2/src/MemoryBitmap.cpp
@@ -0,0 +1,174 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#if !defined(_STATIC_LINKED) || defined(_VGUI_DLL)
+
+#include <vgui/ISurface.h>
+
+#include "Memorybitmap.h"
+#include "vgui_internal.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : *filename - image file to load
+//-----------------------------------------------------------------------------
+MemoryBitmap::MemoryBitmap(unsigned char *texture,int wide, int tall)
+{
+ _texture=texture;
+ _id = 0;
+ _uploaded = false;
+ _color = Color(255, 255, 255, 255);
+ _pos[0] = _pos[1] = 0;
+ _valid = true;
+ _w = wide;
+ _h = tall;
+ ForceUpload(texture,wide,tall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+MemoryBitmap::~MemoryBitmap()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void MemoryBitmap::GetSize(int &wide, int &tall)
+{
+ wide = 0;
+ tall = 0;
+
+ if (!_valid)
+ return;
+
+ g_pSurface->DrawGetTextureSize(_id, wide, tall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: size of the bitmap
+//-----------------------------------------------------------------------------
+void MemoryBitmap::GetContentSize(int &wide, int &tall)
+{
+ GetSize(wide, tall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: ignored
+//-----------------------------------------------------------------------------
+void MemoryBitmap::SetSize(int x, int y)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void MemoryBitmap::SetPos(int x, int y)
+{
+ _pos[0] = x;
+ _pos[1] = y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void MemoryBitmap::SetColor(Color col)
+{
+ _color = col;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the file name of the bitmap
+//-----------------------------------------------------------------------------
+const char *MemoryBitmap::GetName()
+{
+ return "MemoryBitmap";
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Renders the loaded image, uploading it if necessary
+// Assumes a valid image is always returned from uploading
+//-----------------------------------------------------------------------------
+void MemoryBitmap::Paint()
+{
+ if (!_valid)
+ return;
+
+ // if we don't have an _id then lets make one
+ if (!_id)
+ {
+ _id = g_pSurface->CreateNewTextureID( true );
+ }
+
+ // if we have not uploaded yet, lets go ahead and do so
+ if (!_uploaded)
+ {
+ ForceUpload(_texture,_w,_h);
+ }
+
+ //set the texture current, set the color, and draw the biatch
+ g_pSurface->DrawSetTexture(_id);
+ g_pSurface->DrawSetColor(_color[0], _color[1], _color[2], _color[3]);
+
+ int wide, tall;
+ GetSize(wide, tall);
+ g_pSurface->DrawTexturedRect(_pos[0], _pos[1], _pos[0] + wide, _pos[1] + tall);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: ensures the bitmap has been uploaded
+//-----------------------------------------------------------------------------
+void MemoryBitmap::ForceUpload(unsigned char *texture,int wide, int tall)
+{
+ _texture=texture;
+ _w = wide;
+ _h = tall;
+
+ if (!_valid)
+ return;
+
+// if (_uploaded)
+// return;
+
+ if(_w==0 || _h==0)
+ return;
+
+ if (!_id)
+ {
+ _id = g_pSurface->CreateNewTextureID( true );
+ }
+/* drawSetTextureRGBA(IE->textureID,static_cast<const char *>(lpvBits), w, h);
+*/
+ g_pSurface->DrawSetTextureRGBA(_id, _texture, _w, _h, false, true);
+ _uploaded = true;
+
+ _valid = g_pSurface->IsTextureIDValid(_id);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+HTexture MemoryBitmap::GetID()
+{
+ return _id;
+}
+
+#endif // _STATIC_LINKED && _VGUI_DLL
+
diff --git a/vgui2/src/Memorybitmap.h b/vgui2/src/Memorybitmap.h
new file mode 100644
index 0000000..10606a6
--- /dev/null
+++ b/vgui2/src/Memorybitmap.h
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef MEMORYBITMAP_H
+#define MEMORYBITMAP_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui/IImage.h>
+#include <Color.h>
+
+namespace vgui
+{
+
+typedef unsigned long HTexture;
+
+//-----------------------------------------------------------------------------
+// Purpose: Holds a single image created from a chunk of memory, internal to vgui only
+//-----------------------------------------------------------------------------
+class MemoryBitmap: public IImage
+{
+public:
+ MemoryBitmap(unsigned char *texture,int wide, int tall);
+ ~MemoryBitmap();
+
+ // IImage implementation
+ virtual void Paint();
+ virtual void GetSize(int &wide, int &tall);
+ virtual void GetContentSize(int &wide, int &tall);
+ virtual void SetPos(int x, int y);
+ virtual void SetSize(int x, int y);
+ virtual void SetColor(Color col);
+
+ virtual bool Evict() { return false; }
+ virtual int GetNumFrames() { return 0; }
+ virtual void SetFrame( int nFrame ) {}
+ virtual HTexture GetID(); // returns the texture id
+ virtual void SetRotation( int iRotation ) { return; };
+
+ // methods
+ void ForceUpload(unsigned char *texture,int wide, int tall); // ensures the bitmap has been uploaded
+ const char *GetName();
+ bool IsValid()
+ {
+ return _valid;
+ }
+
+private:
+ HTexture _id;
+ bool _uploaded;
+ bool _valid;
+ unsigned char *_texture;
+ int _pos[2];
+ Color _color;
+ int _w,_h; // size of the texture
+};
+
+} // namespace vgui
+
+#endif // MEMORYBITMAP_H
diff --git a/vgui2/src/MessageListener.cpp b/vgui2/src/MessageListener.cpp
new file mode 100644
index 0000000..17b468a
--- /dev/null
+++ b/vgui2/src/MessageListener.cpp
@@ -0,0 +1,112 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "IMessageListener.h"
+#include "VPanel.h"
+#include "vgui_internal.h"
+
+#include <KeyValues.h>
+#include "vgui/IClientPanel.h"
+#include "vgui/IVGui.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+namespace vgui
+{
+
+//-----------------------------------------------------------------------------
+// Implementation of the message listener
+//-----------------------------------------------------------------------------
+class CMessageListener : public IMessageListener
+{
+public:
+ virtual void Message( VPanel* pSender, VPanel* pReceiver, KeyValues* pKeyValues, MessageSendType_t type );
+};
+
+void CMessageListener::Message( VPanel* pSender, VPanel* pReceiver, KeyValues* pKeyValues, MessageSendType_t type )
+{
+ char const *pSenderName = "NULL";
+ if (pSender)
+ pSenderName = pSender->Client()->GetName();
+
+ char const *pSenderClass = "NULL";
+ if (pSender)
+ pSenderClass = pSender->Client()->GetClassName();
+
+ char const *pReceiverName = "unknown name";
+ if (pReceiver)
+ pReceiverName = pReceiver->Client()->GetName();
+
+ char const *pReceiverClass = "unknown class";
+ if (pReceiver)
+ pReceiverClass = pReceiver->Client()->GetClassName();
+
+ // FIXME: Make a bunch of filters here
+
+ // filter out key focus messages
+ if (!strcmp (pKeyValues->GetName(), "KeyFocusTicked"))
+ {
+ return;
+ }
+ // filter out mousefocus messages
+ else if (!strcmp (pKeyValues->GetName(), "MouseFocusTicked"))
+ {
+ return;
+ }
+ // filter out cursor movement messages
+ else if (!strcmp (pKeyValues->GetName(), "CursorMoved"))
+ {
+ return;
+ }
+ // filter out cursor entered messages
+ else if (!strcmp (pKeyValues->GetName(), "CursorEntered"))
+ {
+ return;
+ }
+ // filter out cursor exited messages
+ else if (!strcmp (pKeyValues->GetName(), "CursorExited"))
+ {
+ return;
+ }
+ // filter out MouseCaptureLost messages
+ else if (!strcmp (pKeyValues->GetName(), "MouseCaptureLost"))
+ {
+ return;
+ }
+ // filter out MousePressed messages
+ else if (!strcmp (pKeyValues->GetName(), "MousePressed"))
+ {
+ return;
+ }
+ // filter out MouseReleased messages
+ else if (!strcmp (pKeyValues->GetName(), "MouseReleased"))
+ {
+ return;
+ }
+ // filter out Tick messages
+ else if (!strcmp (pKeyValues->GetName(), "Tick"))
+ {
+ return;
+ }
+
+ Msg( "%s : (%s (%s) - > %s (%s)) )\n",
+ pKeyValues->GetName(), pSenderClass, pSenderName, pReceiverClass, pReceiverName );
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton instance
+//-----------------------------------------------------------------------------
+static CMessageListener s_MessageListener;
+IMessageListener *MessageListener()
+{
+ return &s_MessageListener;
+}
+
+} \ No newline at end of file
diff --git a/vgui2/src/ScalableImageBorder.cpp b/vgui2/src/ScalableImageBorder.cpp
new file mode 100644
index 0000000..bfa5606
--- /dev/null
+++ b/vgui2/src/ScalableImageBorder.cpp
@@ -0,0 +1,272 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdio.h>
+#include <string.h>
+
+#include <vgui_controls/Panel.h>
+#include "vgui/IPanel.h"
+#include "vgui/IScheme.h"
+#include "vgui/ISurface.h"
+
+#include "vgui_internal.h"
+#include "ScalableImageBorder.h"
+#include "KeyValues.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+ScalableImageBorder::ScalableImageBorder()
+{
+ _inset[0]=0;
+ _inset[1]=0;
+ _inset[2]=0;
+ _inset[3]=0;
+ _name = NULL;
+ m_eBackgroundType = IBorder::BACKGROUND_TEXTURED;
+
+ m_iSrcCornerHeight = 0;
+ m_iSrcCornerWidth = 0;
+ m_iCornerHeight = 0;
+ m_iCornerWidth = 0;
+ m_pszImageName = NULL;
+ m_iTextureID = g_pSurface->CreateNewTextureID();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+ScalableImageBorder::~ScalableImageBorder()
+{
+ if ( vgui::surface() && m_iTextureID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iTextureID );
+ m_iTextureID = -1;
+ }
+
+ delete [] _name;
+ if ( m_pszImageName )
+ {
+ delete [] m_pszImageName;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ScalableImageBorder::SetImage(const char *imageName)
+{
+ if ( m_pszImageName )
+ {
+ delete [] m_pszImageName;
+ m_pszImageName = NULL;
+ }
+
+ if (*imageName)
+ {
+ int len = Q_strlen(imageName) + 1 + 5; // 5 for "vgui/"
+ delete [] m_pszImageName;
+ m_pszImageName = new char[ len ];
+ Q_snprintf( m_pszImageName, len, "vgui/%s", imageName );
+
+ g_pSurface->DrawSetTextureFile( m_iTextureID, m_pszImageName, true, false);
+
+ // get image dimensions, compare to m_iSrcCornerHeight, m_iSrcCornerWidth
+ int wide,tall;
+ g_pSurface->DrawGetTextureSize( m_iTextureID, wide, tall );
+
+ m_flCornerWidthPercent = ( wide > 0 ) ? ( (float)m_iSrcCornerWidth / (float)wide ) : 0;
+ m_flCornerHeightPercent = ( tall > 0 ) ? ( (float)m_iSrcCornerHeight / (float)tall ) : 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ScalableImageBorder::SetInset(int left,int top,int right,int bottom)
+{
+ _inset[SIDE_LEFT] = left;
+ _inset[SIDE_TOP] = top;
+ _inset[SIDE_RIGHT] = right;
+ _inset[SIDE_BOTTOM] = bottom;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ScalableImageBorder::GetInset(int& left,int& top,int& right,int& bottom)
+{
+ left = _inset[SIDE_LEFT];
+ top = _inset[SIDE_TOP];
+ right = _inset[SIDE_RIGHT];
+ bottom = _inset[SIDE_BOTTOM];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ScalableImageBorder::Paint(int x, int y, int wide, int tall)
+{
+ Paint(x, y, wide, tall, -1, 0, 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the border with the specified size
+//-----------------------------------------------------------------------------
+void ScalableImageBorder::Paint(int x, int y, int wide, int tall, int breakSide, int breakStart, int breakEnd)
+{
+ if ( !m_pszImageName || !m_pszImageName[0] )
+ return;
+
+ g_pSurface->DrawSetColor( m_Color );
+ g_pSurface->DrawSetTexture( m_iTextureID );
+
+ float uvx = 0;
+ float uvy = 0;
+ float uvw, uvh;
+
+ float drawW, drawH;
+
+ int row, col;
+ for ( row=0;row<3;row++ )
+ {
+ x = 0;
+ uvx = 0;
+
+ if ( row == 0 || row == 2 )
+ {
+ //uvh - row 0 or 2, is src_corner_height
+ uvh = m_flCornerHeightPercent;
+ drawH = m_iCornerHeight;
+ }
+ else
+ {
+ //uvh - row 1, is tall - ( 2 * src_corner_height ) ( min 0 )
+ uvh = max( 1.f - 2.f * m_flCornerHeightPercent, 0.0f );
+ drawH = max( 0, ( tall - 2 * m_iCornerHeight ) );
+ }
+
+ for ( col=0;col<3;col++ )
+ {
+ if ( col == 0 || col == 2 )
+ {
+ //uvw - col 0 or 2, is src_corner_width
+ uvw = m_flCornerWidthPercent;
+ drawW = m_iCornerWidth;
+ }
+ else
+ {
+ //uvw - col 1, is wide - ( 2 * src_corner_width ) ( min 0 )
+ uvw = max( 1.f - 2.f * m_flCornerWidthPercent, 0.0f );
+ drawW = max( 0, ( wide - 2 * m_iCornerWidth ) );
+ }
+
+ Vector2D uv11( uvx, uvy );
+ Vector2D uv21( uvx+uvw, uvy );
+ Vector2D uv22( uvx+uvw, uvy+uvh );
+ Vector2D uv12( uvx, uvy+uvh );
+
+ vgui::Vertex_t verts[4];
+ verts[0].Init( Vector2D( x, y ), uv11 );
+ verts[1].Init( Vector2D( x+drawW, y ), uv21 );
+ verts[2].Init( Vector2D( x+drawW, y+drawH ), uv22 );
+ verts[3].Init( Vector2D( x, y+drawH ), uv12 );
+
+ g_pSurface->DrawTexturedPolygon( 4, verts );
+
+ x += drawW;
+ uvx += uvw;
+ }
+
+ y += drawH;
+ uvy += uvh;
+ }
+
+ g_pSurface->DrawSetTexture(0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ScalableImageBorder::Paint(VPANEL panel)
+{
+ // get panel size
+ int wide, tall;
+ ipanel()->GetSize( panel, wide, tall );
+ Paint(0, 0, wide, tall, -1, 0, 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ScalableImageBorder::ApplySchemeSettings(IScheme *pScheme, KeyValues *inResourceData)
+{
+ m_eBackgroundType = (backgroundtype_e)inResourceData->GetInt("backgroundtype");
+
+ m_iSrcCornerHeight = inResourceData->GetInt( "src_corner_height" );
+ m_iSrcCornerWidth = inResourceData->GetInt( "src_corner_width" );
+ m_iCornerHeight = inResourceData->GetInt( "draw_corner_height" );
+ m_iCornerWidth = inResourceData->GetInt( "draw_corner_width" );
+
+ // scale the x and y up to our screen co-ords
+ m_iCornerHeight = scheme()->GetProportionalScaledValue( m_iCornerHeight);
+ m_iCornerWidth = scheme()->GetProportionalScaledValue(m_iCornerWidth);
+
+ const char *imageName = inResourceData->GetString("image", "");
+ SetImage( imageName );
+
+ m_bPaintFirst = inResourceData->GetInt("paintfirst", true );
+
+ const char *col = inResourceData->GetString("color", NULL);
+ if ( col && col[0] )
+ {
+ m_Color = pScheme->GetColor(col, Color(255, 255, 255, 255));
+ }
+ else
+ {
+ m_Color = Color(255, 255, 255, 255);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+const char *ScalableImageBorder::GetName()
+{
+ if (_name)
+ return _name;
+ return "";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void ScalableImageBorder::SetName(const char *name)
+{
+ if (_name)
+ {
+ delete [] _name;
+ }
+
+ int len = Q_strlen(name) + 1;
+ _name = new char[ len ];
+ Q_strncpy( _name, name, len );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IBorder::backgroundtype_e ScalableImageBorder::GetBackgroundType()
+{
+ return m_eBackgroundType;
+}
+
diff --git a/vgui2/src/ScalableImageBorder.h b/vgui2/src/ScalableImageBorder.h
new file mode 100644
index 0000000..d1df631
--- /dev/null
+++ b/vgui2/src/ScalableImageBorder.h
@@ -0,0 +1,78 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core implementation of vgui
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SCALABLE_IMAGE_BORDER_H
+#define SCALABLE_IMAGE_BORDER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui/IBorder.h>
+#include <vgui/IScheme.h>
+#include <vgui/IPanel.h>
+#include <Color.h>
+
+class KeyValues;
+
+//-----------------------------------------------------------------------------
+// Purpose: Custom border that renders itself with images
+//-----------------------------------------------------------------------------
+class ScalableImageBorder : public vgui::IBorder
+{
+public:
+ ScalableImageBorder();
+ ~ScalableImageBorder();
+
+ virtual void Paint(vgui::VPANEL panel);
+ virtual void Paint(int x0, int y0, int x1, int y1);
+ virtual void Paint(int x0, int y0, int x1, int y1, int breakSide, int breakStart, int breakStop);
+ virtual void SetInset(int left, int top, int right, int bottom);
+ virtual void GetInset(int &left, int &top, int &right, int &bottom);
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme, KeyValues *inResourceData);
+
+ virtual const char *GetName();
+ virtual void SetName(const char *name);
+ virtual backgroundtype_e GetBackgroundType();
+
+ virtual bool PaintFirst( void ) { return m_bPaintFirst; }
+
+protected:
+ void SetImage(const char *imageName);
+
+protected:
+ int _inset[4];
+
+private:
+ // protected copy constructor to prevent use
+ ScalableImageBorder(ScalableImageBorder&);
+
+ char *_name;
+
+ backgroundtype_e m_eBackgroundType;
+
+ friend class VPanel;
+
+ int m_iSrcCornerHeight; // in pixels, how tall is the corner inside the image
+ int m_iSrcCornerWidth; // same for width
+ int m_iCornerHeight; // output size of the corner height in pixels
+ int m_iCornerWidth; // same for width
+
+ int m_iTextureID;
+
+ float m_flCornerWidthPercent; // corner width as percentage of image width
+ float m_flCornerHeightPercent; // same for height
+
+ char *m_pszImageName;
+ bool m_bPaintFirst;
+
+ Color m_Color;
+};
+
+#endif // SCALABLE_IMAGE_BORDER_H
diff --git a/vgui2/src/Scheme.cpp b/vgui2/src/Scheme.cpp
new file mode 100644
index 0000000..f41a695
--- /dev/null
+++ b/vgui2/src/Scheme.cpp
@@ -0,0 +1,1532 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include <stdio.h>
+#include <math.h>
+
+#include <vgui/VGUI.h>
+#include <vgui/IScheme.h>
+#include <KeyValues.h>
+#include <vgui/ISurface.h>
+#include <vgui/IPanel.h>
+#include <vgui/ISystem.h>
+#include <vstdlib/IKeyValuesSystem.h>
+#include <vgui/IVGui.h>
+
+#include "tier1/utlvector.h"
+#include "tier1/utlrbtree.h"
+#include "tier1/utldict.h"
+#include "VGUI_Border.h"
+#include "ScalableImageBorder.h"
+#include "ImageBorder.h"
+#include "vgui_internal.h"
+#include "bitmap.h"
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+#define FONT_ALIAS_NAME_LENGTH 64
+
+//-----------------------------------------------------------------------------
+// Purpose: Implementation of global scheme interface
+//-----------------------------------------------------------------------------
+class CScheme : public IScheme
+{
+public:
+ CScheme();
+
+ // gets a string from the default settings section
+ virtual const char *GetResourceString(const char *stringName);
+
+ // returns a pointer to an existing border
+ virtual IBorder *GetBorder(const char *borderName);
+
+ // returns a pointer to an existing font
+ virtual HFont GetFont(const char *fontName, bool proportional);
+
+ // m_pkvColors
+ virtual Color GetColor( const char *colorName, Color defaultColor);
+
+
+ void Shutdown( bool full );
+ void LoadFromFile( VPANEL sizingPanel, const char *filename, const char *tag, KeyValues *inKeys );
+
+ // Gets at the scheme's name
+ const char *GetName() { return tag; }
+ const char *GetFileName() { return fileName; }
+
+ char const *GetFontName( const HFont& font );
+
+ void ReloadFontGlyphs();
+
+ VPANEL GetSizingPanel() { return m_SizingPanel; }
+
+ void SpewFonts();
+
+ bool GetFontRange( const char *fontname, int &nMin, int &nMax );
+ void SetFontRange( const char *fontname, int nMin, int nMax );
+
+ // Get the number of borders
+ virtual int GetBorderCount() const;
+
+ // Get the border at the given index
+ virtual IBorder *GetBorderAtIndex( int iIndex );
+
+ // Get the number of fonts
+ virtual int GetFontCount() const;
+
+ // Get the font at the given index
+ virtual HFont GetFontAtIndex( int iIndex );
+
+ // Get color data
+ virtual const KeyValues *GetColorData() const;
+
+private:
+ const char *LookupSchemeSetting(const char *pchSetting);
+ const char *GetMungedFontName( const char *fontName, const char *scheme, bool proportional);
+ void LoadFonts();
+ void LoadBorders();
+ HFont FindFontInAliasList( const char *fontName );
+ int GetMinimumFontHeightForCurrentLanguage();
+
+ char fileName[256];
+ char tag[64];
+
+ KeyValues *m_pData;
+ KeyValues *m_pkvBaseSettings;
+ KeyValues *m_pkvColors;
+ int m_nColorCount;
+
+ struct SchemeBorder_t
+ {
+ IBorder *border;
+ int borderSymbol;
+ bool bSharedBorder;
+ };
+ CUtlVector<SchemeBorder_t> m_BorderList;
+ IBorder *m_pBaseBorder; // default border to use if others not found
+ KeyValues *m_pkvBorders;
+#pragma pack(1)
+ struct fontalias_t
+ {
+ CUtlSymbol _trueFontName;
+ unsigned short _font : 15;
+ unsigned short m_bProportional : 1;
+ };
+#pragma pack()
+ friend struct fontalias_t;
+
+ CUtlDict< fontalias_t, int > m_FontAliases;
+ VPANEL m_SizingPanel;
+ int m_nScreenWide;
+ int m_nScreenTall;
+
+ struct fontrange_t
+ {
+ int _min;
+ int _max;
+ };
+ CUtlDict< fontrange_t, int > m_FontRanges;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Implementation of global scheme interface
+//-----------------------------------------------------------------------------
+class CSchemeManager : public ISchemeManager
+{
+public:
+ CSchemeManager();
+ ~CSchemeManager();
+
+ // loads a scheme from a file
+ // first scheme loaded becomes the default scheme, and all subsequent loaded scheme are derivitives of that
+ // tag is friendly string representing the name of the loaded scheme
+ virtual HScheme LoadSchemeFromFile(const char *fileName, const char *tag);
+ // first scheme loaded becomes the default scheme, and all subsequent loaded scheme are derivitives of that
+ virtual HScheme LoadSchemeFromFileEx( VPANEL sizingPanel, const char *fileName, const char *tag);
+
+ // reloads the schemes from the file
+ virtual void ReloadSchemes();
+ virtual void ReloadFonts();
+
+ // returns a handle to the default (first loaded) scheme
+ virtual HScheme GetDefaultScheme();
+
+ // returns a handle to the scheme identified by "tag"
+ virtual HScheme GetScheme(const char *tag);
+
+ // returns a pointer to an image
+ virtual IImage *GetImage(const char *imageName, bool hardwareFiltered);
+ virtual HTexture GetImageID(const char *imageName, bool hardwareFiltered);
+
+ virtual IScheme *GetIScheme( HScheme scheme );
+
+ virtual void Shutdown( bool full );
+
+ // gets the proportional coordinates for doing screen-size independant panel layouts
+ // use these for font, image and panel size scaling (they all use the pixel height of the display for scaling)
+ virtual int GetProportionalScaledValue(int normalizedValue);
+ virtual int GetProportionalNormalizedValue(int scaledValue);
+
+ // gets the proportional coordinates for doing screen-size independant panel layouts
+ // use these for font, image and panel size scaling (they all use the pixel height of the display for scaling)
+ virtual int GetProportionalScaledValueEx( HScheme scheme, int normalizedValue );
+ virtual int GetProportionalNormalizedValueEx( HScheme scheme, int scaledValue );
+
+ virtual bool DeleteImage( const char *pImageName );
+
+ // gets the proportional coordinates for doing screen-size independant panel layouts
+ // use these for font, image and panel size scaling (they all use the pixel height of the display for scaling)
+ int GetProportionalScaledValueEx( CScheme *pScheme, int normalizedValue );
+ int GetProportionalNormalizedValueEx( CScheme *pScheme, int scaledValue );
+
+ void SpewFonts();
+
+private:
+
+ int GetProportionalScaledValue_( int rootWide, int rootTall, int normalizedValue );
+ int GetProportionalNormalizedValue_( int rootWide, int rootTall, int scaledValue );
+
+ // Search for already-loaded schemes
+ HScheme FindLoadedScheme(const char *fileName);
+
+ CUtlVector<CScheme *> m_Schemes;
+
+ static const char *s_pszSearchString;
+ struct CachedBitmapHandle_t
+ {
+ Bitmap *pBitmap;
+ };
+ static bool BitmapHandleSearchFunc(const CachedBitmapHandle_t &, const CachedBitmapHandle_t &);
+ CUtlRBTree<CachedBitmapHandle_t, int> m_Bitmaps;
+};
+
+const char *CSchemeManager::s_pszSearchString = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose: search function for stored bitmaps
+//-----------------------------------------------------------------------------
+bool CSchemeManager::BitmapHandleSearchFunc(const CachedBitmapHandle_t &lhs, const CachedBitmapHandle_t &rhs)
+{
+ // a NULL bitmap indicates to use the search string instead
+ if (lhs.pBitmap && rhs.pBitmap)
+ {
+ return stricmp(lhs.pBitmap->GetName(), rhs.pBitmap->GetName()) > 0;
+ }
+ else if (lhs.pBitmap)
+ {
+ return stricmp(lhs.pBitmap->GetName(), s_pszSearchString) > 0;
+ }
+ return stricmp(s_pszSearchString, rhs.pBitmap->GetName()) > 0;
+}
+
+
+
+CSchemeManager g_Scheme;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CSchemeManager, ISchemeManager, VGUI_SCHEME_INTERFACE_VERSION, g_Scheme);
+
+
+namespace vgui
+{
+vgui::ISchemeManager *g_pScheme = &g_Scheme;
+} // namespace vgui
+
+CON_COMMAND( vgui_spew_fonts, "" )
+{
+ g_Scheme.SpewFonts();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CSchemeManager::CSchemeManager()
+{
+ // 0th element is null, since that would be an invalid handle
+ CScheme *nullScheme = new CScheme();
+ m_Schemes.AddToTail(nullScheme);
+ m_Bitmaps.SetLessFunc(&BitmapHandleSearchFunc);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CSchemeManager::~CSchemeManager()
+{
+ int i;
+ for ( i = 0; i < m_Schemes.Count(); i++ )
+ {
+ delete m_Schemes[i];
+ }
+ m_Schemes.RemoveAll();
+
+ for ( i = 0; i < m_Bitmaps.MaxElement(); i++ )
+ {
+ if (m_Bitmaps.IsValidIndex(i))
+ {
+ delete m_Bitmaps[i].pBitmap;
+ }
+ }
+ m_Bitmaps.RemoveAll();
+
+ Shutdown( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reload the fonts in all schemes
+//-----------------------------------------------------------------------------
+void CSchemeManager::ReloadFonts()
+{
+ for (int i = 1; i < m_Schemes.Count(); i++)
+ {
+ m_Schemes[i]->ReloadFontGlyphs();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Converts the handle into an interface
+//-----------------------------------------------------------------------------
+IScheme *CSchemeManager::GetIScheme( HScheme scheme )
+{
+ if ( scheme >= (unsigned long)m_Schemes.Count() )
+ {
+ AssertOnce( !"Invalid scheme requested." );
+ return NULL;
+ }
+ else
+ {
+ return m_Schemes[scheme];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSchemeManager::Shutdown( bool full )
+{
+ // Full shutdown kills the null scheme
+ for( int i = full ? 0 : 1; i < m_Schemes.Count(); i++ )
+ {
+ m_Schemes[i]->Shutdown( full );
+ }
+
+ if ( full )
+ {
+ m_Schemes.RemoveAll();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: loads a scheme from disk
+//-----------------------------------------------------------------------------
+HScheme CSchemeManager::FindLoadedScheme(const char *fileName)
+{
+ // Find the scheme in the list of already loaded schemes
+ for (int i = 1; i < m_Schemes.Count(); i++)
+ {
+ char const *schemeFileName = m_Schemes[i]->GetFileName();
+ if (!stricmp(schemeFileName, fileName))
+ return i;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CScheme::CScheme()
+{
+ fileName[ 0 ] = 0;
+ tag[ 0 ] = 0;
+
+ m_pData = NULL;
+ m_pkvBaseSettings = NULL;
+ m_pkvColors = NULL;
+ m_nColorCount = 0;
+
+ m_pBaseBorder = NULL; // default border to use if others not found
+ m_pkvBorders = NULL;
+ m_SizingPanel = 0;
+ m_nScreenWide = -1;
+ m_nScreenTall = -1;
+}
+
+// first scheme loaded becomes the default scheme, and all subsequent loaded scheme are derivitives of that
+HScheme CSchemeManager::LoadSchemeFromFileEx( VPANEL sizingPanel, const char *fileName, const char *tag)
+{
+ // Look to see if we've already got this scheme...
+ HScheme hScheme = FindLoadedScheme(fileName);
+ if (hScheme != 0)
+ {
+ CScheme *pScheme = static_cast< CScheme * >( GetIScheme( hScheme ) );
+ if ( IsPC() && pScheme )
+ {
+ pScheme->ReloadFontGlyphs();
+ }
+ return hScheme;
+ }
+
+ KeyValues *data;
+ data = new KeyValues("Scheme");
+
+ data->UsesEscapeSequences( true ); // VGUI uses this
+
+ // Look first in game directory
+ bool result = data->LoadFromFile( g_pFullFileSystem, fileName, "GAME" );
+ if ( !result )
+ {
+ // look in any directory
+ result = data->LoadFromFile( g_pFullFileSystem, fileName, NULL );
+ }
+
+ if (!result)
+ {
+ data->deleteThis();
+ return 0;
+ }
+
+ if ( IsX360() )
+ {
+ data->ProcessResolutionKeys( g_pSurface->GetResolutionKey() );
+ }
+ if ( IsPC() )
+ {
+ ConVarRef cl_hud_minmode( "cl_hud_minmode", true );
+ if ( cl_hud_minmode.IsValid() && cl_hud_minmode.GetBool() )
+ {
+ data->ProcessResolutionKeys( "_minmode" );
+ }
+ }
+ if( g_pIVgui->GetVRMode() )
+ {
+ data->ProcessResolutionKeys( "_vrmode" );
+ }
+
+ CScheme *newScheme = new CScheme();
+ newScheme->LoadFromFile( sizingPanel, fileName, tag, data );
+
+ return m_Schemes.AddToTail(newScheme);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: loads a scheme from disk
+//-----------------------------------------------------------------------------
+HScheme CSchemeManager::LoadSchemeFromFile(const char *fileName, const char *tag)
+{
+ return LoadSchemeFromFileEx( 0, fileName, tag );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Table of scheme file entries, translation from old goldsrc schemes to new src schemes
+//-----------------------------------------------------------------------------
+struct SchemeEntryTranslation_t
+{
+ const char *pchNewEntry;
+ const char *pchOldEntry;
+ const char *pchDefaultValue;
+};
+SchemeEntryTranslation_t g_SchemeTranslation[] =
+{
+ { "Border.Bright", "BorderBright", "200 200 200 196" }, // the lit side of a control
+ { "Border.Dark" "BorderDark", "40 40 40 196" }, // the dark/unlit side of a control
+ { "Border.Selection" "BorderSelection", "0 0 0 196" }, // the additional border color for displaying the default/selected button
+
+ { "Button.TextColor", "ControlFG", "White" },
+ { "Button.BgColor", "ControlBG", "Blank" },
+ { "Button.ArmedTextColor", "ControlFG" },
+ { "Button.ArmedBgColor", "ControlBG" },
+ { "Button.DepressedTextColor", "ControlFG" },
+ { "Button.DepressedBgColor", "ControlBG" },
+ { "Button.FocusBorderColor", "0 0 0 255" },
+
+ { "CheckButton.TextColor", "BaseText" },
+ { "CheckButton.SelectedTextColor", "BrightControlText" },
+ { "CheckButton.BgColor", "CheckBgColor" },
+ { "CheckButton.Border1", "CheckButtonBorder1" },
+ { "CheckButton.Border2", "CheckButtonBorder2" },
+ { "CheckButton.Check", "CheckButtonCheck" },
+
+ { "ComboBoxButton.ArrowColor", "LabelDimText" },
+ { "ComboBoxButton.ArmedArrowColor", "MenuButton/ArmedArrowColor" },
+ { "ComboBoxButton.BgColor", "MenuButton/ButtonBgColor" },
+ { "ComboBoxButton.DisabledBgColor", "ControlBG" },
+
+ { "Frame.TitleTextInsetX", NULL, "32" },
+ { "Frame.ClientInsetX", NULL, "8" },
+ { "Frame.ClientInsetY", NULL, "6" },
+ { "Frame.BgColor", "BgColor" },
+ { "Frame.OutOfFocusBgColor", "BgColor" },
+ { "Frame.FocusTransitionEffectTime",NULL, "0" },
+ { "Frame.TransitionEffectTime", NULL, "0" },
+ { "Frame.AutoSnapRange", NULL, "8" },
+ { "FrameGrip.Color1", "BorderBright" },
+ { "FrameGrip.Color2", "BorderSelection" },
+ { "FrameTitleButton.FgColor", "TitleButtonFgColor" },
+ { "FrameTitleButton.BgColor", "TitleButtonBgColor" },
+ { "FrameTitleButton.DisabledFgColor", "TitleButtonDisabledFgColor" },
+ { "FrameTitleButton.DisabledBgColor", "TitleButtonDisabledBgColor" },
+ { "FrameSystemButton.FgColor", "TitleBarBgColor" },
+ { "FrameSystemButton.BgColor", "TitleBarBgColor" },
+ { "FrameSystemButton.Icon", "TitleBarIcon" },
+ { "FrameSystemButton.DisabledIcon", "TitleBarDisabledIcon" },
+ { "FrameTitleBar.Font", NULL, "Default" },
+ { "FrameTitleBar.TextColor", "TitleBarFgColor" },
+ { "FrameTitleBar.BgColor", "TitleBarBgColor" },
+ { "FrameTitleBar.DisabledTextColor","TitleBarDisabledFgColor" },
+ { "FrameTitleBar.DisabledBgColor", "TitleBarDisabledBgColor" },
+
+ { "GraphPanel.FgColor", "BrightControlText" },
+ { "GraphPanel.BgColor", "WindowBgColor" },
+
+ { "Label.TextDullColor", "LabelDimText" },
+ { "Label.TextColor", "BaseText" },
+ { "Label.TextBrightColor", "BrightControlText" },
+ { "Label.SelectedTextColor", "BrightControlText" },
+ { "Label.BgColor", "LabelBgColor" },
+ { "Label.DisabledFgColor1", "DisabledFgColor1" },
+ { "Label.DisabledFgColor2", "DisabledFgColor2" },
+
+ { "ListPanel.TextColor", "WindowFgColor" },
+ { "ListPanel.TextBgColor", "Menu/ArmedBgColor" },
+ { "ListPanel.BgColor", "ListBgColor" },
+ { "ListPanel.SelectedTextColor", "ListSelectionFgColor" },
+ { "ListPanel.SelectedBgColor", "Menu/ArmedBgColor" },
+ { "ListPanel.SelectedOutOfFocusBgColor","SelectionBG2" },
+ { "ListPanel.EmptyListInfoTextColor", "LabelDimText" },
+ { "ListPanel.DisabledTextColor", "LabelDimText" },
+ { "ListPanel.DisabledSelectedTextColor","ListBgColor" },
+
+ { "Menu.TextColor", "Menu/FgColor" },
+ { "Menu.BgColor", "Menu/BgColor" },
+ { "Menu.ArmedTextColor", "Menu/ArmedFgColor" },
+ { "Menu.ArmedBgColor", "Menu/ArmedBgColor" },
+ { "Menu.TextInset", NULL, "6" },
+
+ { "Panel.FgColor", "FgColor" },
+ { "Panel.BgColor", "BgColor" },
+
+ { "ProgressBar.FgColor", "BrightControlText" },
+ { "ProgressBar.BgColor", "WindowBgColor" },
+
+ { "PropertySheet.TextColor", "FgColorDim" },
+ { "PropertySheet.SelectedTextColor", "BrightControlText" },
+ { "PropertySheet.TransitionEffectTime", NULL, "0" },
+
+ { "RadioButton.TextColor", "FgColor" },
+ { "RadioButton.SelectedTextColor", "BrightControlText" },
+
+ { "RichText.TextColor", "WindowFgColor" },
+ { "RichText.BgColor", "WindowBgColor" },
+ { "RichText.SelectedTextColor", "SelectionFgColor" },
+ { "RichText.SelectedBgColor", "SelectionBgColor" },
+
+ { "ScrollBar.Wide", NULL, "19" },
+
+ { "ScrollBarButton.FgColor", "DimBaseText" },
+ { "ScrollBarButton.BgColor", "ControlBG" },
+ { "ScrollBarButton.ArmedFgColor", "BaseText" },
+ { "ScrollBarButton.ArmedBgColor", "ControlBG" },
+ { "ScrollBarButton.DepressedFgColor", "BaseText" },
+ { "ScrollBarButton.DepressedBgColor", "ControlBG" },
+
+ { "ScrollBarSlider.FgColor", "ScrollBarSlider/ScrollBarSliderFgColor" },
+ { "ScrollBarSlider.BgColor", "ScrollBarSlider/ScrollBarSliderBgColor" },
+
+ { "SectionedListPanel.HeaderTextColor", "SectionTextColor" },
+ { "SectionedListPanel.HeaderBgColor", "BuddyListBgColor" },
+ { "SectionedListPanel.DividerColor", "SectionDividerColor" },
+ { "SectionedListPanel.TextColor", "BuddyButton/FgColor1" },
+ { "SectionedListPanel.BrightTextColor", "BuddyButton/ArmedFgColor1" },
+ { "SectionedListPanel.BgColor", "BuddyListBgColor" },
+ { "SectionedListPanel.SelectedTextColor", "BuddyButton/ArmedFgColor1" },
+ { "SectionedListPanel.SelectedBgColor", "BuddyButton/ArmedBgColor" },
+ { "SectionedListPanel.OutOfFocusSelectedTextColor", "BuddyButton/ArmedFgColor2" },
+ { "SectionedListPanel.OutOfFocusSelectedBgColor", "SelectionBG2" },
+
+ { "Slider.NobColor", "SliderTickColor" },
+ { "Slider.TextColor", "Slider/SliderFgColor" },
+ { "Slider.TrackColor", "SliderTrackColor"},
+ { "Slider.DisabledTextColor1", "DisabledFgColor1" },
+ { "Slider.DisabledTextColor2", "DisabledFgColor2" },
+
+ { "TextEntry.TextColor", "WindowFgColor" },
+ { "TextEntry.BgColor", "WindowBgColor" },
+ { "TextEntry.CursorColor", "TextCursorColor" },
+ { "TextEntry.DisabledTextColor","WindowDisabledFgColor" },
+ { "TextEntry.DisabledBgColor", "ControlBG" },
+ { "TextEntry.SelectedTextColor","SelectionFgColor" },
+ { "TextEntry.SelectedBgColor", "SelectionBgColor" },
+ { "TextEntry.OutOfFocusSelectedBgColor", "SelectionBG2" },
+ { "TextEntry.FocusEdgeColor", "BorderSelection" },
+
+ { "ToggleButton.SelectedTextColor", "BrightControlText" },
+
+ { "Tooltip.TextColor", "BorderSelection" },
+ { "Tooltip.BgColor", "SelectionBG" },
+
+ { "TreeView.BgColor", "ListBgColor" },
+
+ { "WizardSubPanel.BgColor", "SubPanelBgColor" },
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: loads a scheme from from disk into memory
+//-----------------------------------------------------------------------------
+void CScheme::LoadFromFile( VPANEL sizingPanel, const char *inFilename, const char *inTag, KeyValues *inKeys )
+{
+ COM_TimestampedLog( "CScheme::LoadFromFile( %s )", inFilename );
+
+ Q_strncpy(fileName, inFilename, sizeof(fileName) );
+
+ m_SizingPanel = sizingPanel;
+
+ m_pData = inKeys;
+ m_pkvBaseSettings = m_pData->FindKey("BaseSettings", true);
+ m_pkvColors = m_pData->FindKey("Colors", true);
+
+ // override the scheme name with the tag name
+ KeyValues *name = m_pData->FindKey("Name", true);
+ name->SetString("Name", inTag);
+
+ if ( inTag )
+ {
+ Q_strncpy( tag, inTag, sizeof( tag ) );
+ }
+ else
+ {
+ Assert( "You need to name the scheme!" );
+ Q_strncpy( tag, "default", sizeof( tag ) );
+ }
+
+ // translate format from goldsrc scheme to new scheme
+ for (int i = 0; i < ARRAYSIZE(g_SchemeTranslation); i++)
+ {
+ if (!m_pkvBaseSettings->FindKey(g_SchemeTranslation[i].pchNewEntry, false))
+ {
+ const char *pchColor;
+
+ if (g_SchemeTranslation[i].pchOldEntry)
+ {
+ pchColor = LookupSchemeSetting(g_SchemeTranslation[i].pchOldEntry);
+ }
+ else
+ {
+ pchColor = g_SchemeTranslation[i].pchDefaultValue;
+ }
+
+ Assert( pchColor );
+
+ m_pkvBaseSettings->SetString(g_SchemeTranslation[i].pchNewEntry, pchColor);
+ }
+ }
+
+ // need to copy tag before loading fonts
+ LoadFonts();
+ LoadBorders();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CScheme::GetFontRange( const char *fontname, int &nMin, int &nMax )
+{
+ int i = m_FontRanges.Find( fontname );
+ if ( i != m_FontRanges.InvalidIndex() )
+ {
+ nMin = m_FontRanges[i]._min;
+ nMax = m_FontRanges[i]._max;
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CScheme::SetFontRange( const char *fontname, int nMin, int nMax )
+{
+ int i = m_FontRanges.Find( fontname );
+ if ( i != m_FontRanges.InvalidIndex() )
+ {
+ m_FontRanges[i]._min = nMin;
+ m_FontRanges[i]._max = nMax;
+ return;
+ }
+
+ // not already in our list
+ int iNew = m_FontRanges.Insert( fontname );
+
+ m_FontRanges[iNew]._min = nMin;
+ m_FontRanges[iNew]._max = nMax;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds all the font specifications to the surface
+//-----------------------------------------------------------------------------
+void CScheme::LoadFonts()
+{
+ bool bValid = false;
+ char language[64];
+ memset( language, 0, sizeof( language ) );
+
+ // get our language
+ if ( IsPC() )
+ {
+ bValid = vgui::g_pSystem->GetRegistryString( "HKEY_CURRENT_USER\\Software\\Valve\\Source\\Language", language, sizeof( language ) - 1 );
+ }
+ else
+ {
+ Q_strncpy( language, XBX_GetLanguageString(), sizeof( language ) );
+ bValid = true;
+ }
+
+ if ( !bValid )
+ {
+ Q_strncpy( language, "english", sizeof( language ) );
+ }
+
+ // add our custom fonts
+ for (KeyValues *kv = m_pData->FindKey("CustomFontFiles", true)->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey())
+ {
+ const char *fontFile = kv->GetString();
+ if (fontFile && *fontFile)
+ {
+ g_pSurface->AddCustomFontFile( NULL, fontFile );
+ }
+ else
+ {
+ // we have a block to read
+ int nRangeMin = 0, nRangeMax = 0;
+ const char *pszName = NULL;
+ bool bUseRange = false;
+
+ for ( KeyValues *pData = kv->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
+ {
+ const char *pszKey = pData->GetName();
+ if ( !Q_stricmp( pszKey, "font" ) )
+ {
+ fontFile = pData->GetString();
+ }
+ else if ( !Q_stricmp( pszKey, "name" ) )
+ {
+ pszName = pData->GetString();
+ }
+ else
+ {
+ // we must have a language
+ if ( Q_stricmp( language, pszKey ) == 0 ) // matches the language we're running?
+ {
+ // get the range
+ KeyValues *pRange = pData->FindKey( "range" );
+ if ( pRange )
+ {
+ bUseRange = true;
+ sscanf( pRange->GetString(), "%x %x", &nRangeMin, &nRangeMax );
+
+ if ( nRangeMin > nRangeMax )
+ {
+ int nTemp = nRangeMin;
+ nRangeMin = nRangeMax;
+ nRangeMax = nTemp;
+ }
+ }
+ }
+ }
+ }
+
+ if ( fontFile && *fontFile )
+ {
+ g_pSurface->AddCustomFontFile( pszName, fontFile );
+
+ if ( bUseRange )
+ {
+ SetFontRange( pszName, nRangeMin, nRangeMax );
+ }
+ }
+ }
+ }
+
+ // add bitmap fonts
+ for (KeyValues *kv = m_pData->FindKey("BitmapFontFiles", true)->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey())
+ {
+ const char *fontFile = kv->GetString();
+ if (fontFile && *fontFile)
+ {
+ bool bSuccess = g_pSurface->AddBitmapFontFile( fontFile );
+ if ( bSuccess )
+ {
+ // refer to the font by a user specified symbol
+ g_pSurface->SetBitmapFontName( kv->GetName(), fontFile );
+ }
+ }
+ }
+
+ // create the fonts
+ for (KeyValues *kv = m_pData->FindKey("Fonts", true)->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey())
+ {
+ for ( int i = 0; i < 2; i++ )
+ {
+ // create the base font
+ bool proportionalFont = static_cast<bool>( i );
+ const char *fontName = GetMungedFontName( kv->GetName(), tag, proportionalFont ); // first time it adds a normal font, and then a proportional one
+ HFont font = g_pSurface->CreateFont();
+
+ int j = m_FontAliases.Insert( fontName );
+ m_FontAliases[j]._trueFontName = kv->GetName();
+ m_FontAliases[j]._font = font;
+ m_FontAliases[j].m_bProportional = proportionalFont;
+ }
+ }
+
+ // load in the font glyphs
+ ReloadFontGlyphs();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reloads all scheme fonts
+//-----------------------------------------------------------------------------
+void CScheme::ReloadFontGlyphs()
+{
+ COM_TimestampedLog( "ReloadFontGlyphs(): Start" );
+
+ // get our current resolution
+ if ( m_SizingPanel != 0 )
+ {
+ g_pIPanel->GetSize( m_SizingPanel, m_nScreenWide, m_nScreenTall );
+ }
+ else
+ {
+ g_pSurface->GetScreenSize( m_nScreenWide, m_nScreenTall );
+ }
+
+ // check our language; some have minimum sizes
+ int minimumFontHeight = GetMinimumFontHeightForCurrentLanguage();
+
+ // add the data to all the fonts
+ KeyValues *fonts = m_pData->FindKey("Fonts", true);
+ FOR_EACH_DICT_FAST( m_FontAliases, i )
+ {
+ KeyValues *kv = fonts->FindKey( m_FontAliases[i]._trueFontName.String(), true );
+
+ // walk through creating adding the first matching glyph set to the font
+ for (KeyValues *fontdata = kv->GetFirstSubKey(); fontdata != NULL; fontdata = fontdata->GetNextKey())
+ {
+ // skip over fonts not meant for this resolution
+ int fontYResMin = 0, fontYResMax = 0;
+ sscanf(fontdata->GetString("yres", ""), "%d %d", &fontYResMin, &fontYResMax);
+ if (fontYResMin)
+ {
+ if (!fontYResMax)
+ {
+ fontYResMax = fontYResMin;
+ }
+ // check the range
+ if (m_nScreenTall < fontYResMin || m_nScreenTall > fontYResMax)
+ continue;
+ }
+
+ int flags = 0;
+ if (fontdata->GetInt( "italic" ))
+ {
+ flags |= ISurface::FONTFLAG_ITALIC;
+ }
+ if (fontdata->GetInt( "underline" ))
+ {
+ flags |= ISurface::FONTFLAG_UNDERLINE;
+ }
+ if (fontdata->GetInt( "strikeout" ))
+ {
+ flags |= ISurface::FONTFLAG_STRIKEOUT;
+ }
+ if (fontdata->GetInt( "symbol" ))
+ {
+ flags |= ISurface::FONTFLAG_SYMBOL;
+ }
+ if (fontdata->GetInt( "antialias" ) && g_pSurface->SupportsFeature(ISurface::ANTIALIASED_FONTS))
+ {
+ flags |= ISurface::FONTFLAG_ANTIALIAS;
+ }
+ if (fontdata->GetInt( "dropshadow" ) && g_pSurface->SupportsFeature(ISurface::DROPSHADOW_FONTS))
+ {
+ flags |= ISurface::FONTFLAG_DROPSHADOW;
+ }
+ if (fontdata->GetInt( "outline" ) && g_pSurface->SupportsFeature(ISurface::OUTLINE_FONTS))
+ {
+ flags |= ISurface::FONTFLAG_OUTLINE;
+ }
+ if (fontdata->GetInt( "custom" ))
+ {
+ flags |= ISurface::FONTFLAG_CUSTOM;
+ }
+ if (fontdata->GetInt( "bitmap" ))
+ {
+ flags |= ISurface::FONTFLAG_BITMAP;
+ }
+ if (fontdata->GetInt( "rotary" ))
+ {
+ flags |= ISurface::FONTFLAG_ROTARY;
+ }
+ if (fontdata->GetInt( "additive" ))
+ {
+ flags |= ISurface::FONTFLAG_ADDITIVE;
+ }
+
+ int tall = fontdata->GetInt( "tall" );
+ int blur = fontdata->GetInt( "blur" );
+ int scanlines = fontdata->GetInt( "scanlines" );
+ float scalex = fontdata->GetFloat( "scalex", 1.0f );
+ float scaley = fontdata->GetFloat( "scaley", 1.0f );
+
+ // only grow this font if it doesn't have a resolution filter specified
+ if ( ( !fontYResMin && !fontYResMax ) && m_FontAliases[i].m_bProportional )
+ {
+ tall = g_Scheme.GetProportionalScaledValueEx( this, tall );
+ blur = g_Scheme.GetProportionalScaledValueEx( this, blur );
+ scanlines = g_Scheme.GetProportionalScaledValueEx( this, scanlines );
+ scalex = g_Scheme.GetProportionalScaledValueEx( this, scalex * 10000.0f ) * 0.0001f;
+ scaley = g_Scheme.GetProportionalScaledValueEx( this, scaley * 10000.0f ) * 0.0001f;
+ }
+
+ // clip the font size so that fonts can't be too big
+ if ( tall > 127 )
+ {
+ tall = 127;
+ }
+
+ // check our minimum font height
+ if ( tall < minimumFontHeight )
+ {
+ tall = minimumFontHeight;
+ }
+
+ if ( flags & ISurface::FONTFLAG_BITMAP )
+ {
+ // add the new set
+ g_pSurface->SetBitmapFontGlyphSet(
+ m_FontAliases[i]._font,
+ g_pSurface->GetBitmapFontName( fontdata->GetString( "name" ) ),
+ scalex,
+ scaley,
+ flags);
+ }
+ else
+ {
+ int nRangeMin, nRangeMax;
+
+ if ( GetFontRange( fontdata->GetString( "name" ), nRangeMin, nRangeMax ) )
+ {
+ // add the new set
+ g_pSurface->SetFontGlyphSet(
+ m_FontAliases[i]._font,
+ fontdata->GetString( "name" ),
+ tall,
+ fontdata->GetInt( "weight" ),
+ blur,
+ scanlines,
+ flags,
+ nRangeMin,
+ nRangeMax);
+ }
+ else
+ {
+ // add the new set
+ g_pSurface->SetFontGlyphSet(
+ m_FontAliases[i]._font,
+ fontdata->GetString( "name" ),
+ tall,
+ fontdata->GetInt( "weight" ),
+ blur,
+ scanlines,
+ flags);
+ }
+ }
+
+ // don't add any more
+ break;
+ }
+ }
+
+ COM_TimestampedLog( "ReloadFontGlyphs(): End" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: create the Border objects from the scheme data
+//-----------------------------------------------------------------------------
+void CScheme::LoadBorders()
+{
+ m_pkvBorders = m_pData->FindKey("Borders", true);
+ {for ( KeyValues *kv = m_pkvBorders->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey())
+ {
+ if (kv->GetDataType() == KeyValues::TYPE_STRING)
+ {
+ // it's referencing another border, ignore for now
+ }
+ else
+ {
+ int i = m_BorderList.AddToTail();
+
+ IBorder *border = NULL;
+ const char *pszBorderType = kv->GetString( "bordertype", NULL );
+ if ( pszBorderType && pszBorderType[0] )
+ {
+ if ( !stricmp(pszBorderType,"image") )
+ {
+ border = new ImageBorder();
+ }
+ else if ( !stricmp(pszBorderType,"scalable_image") )
+ {
+ border = new ScalableImageBorder();
+ }
+ else
+ {
+ Assert(0);
+ // Fall back to the base border type. See below.
+ pszBorderType = NULL;
+ }
+ }
+
+ if ( !pszBorderType || !pszBorderType[0] )
+ {
+ border = new Border();
+ }
+
+ border->SetName(kv->GetName());
+ border->ApplySchemeSettings(this, kv);
+
+ m_BorderList[i].border = border;
+ m_BorderList[i].bSharedBorder = false;
+ m_BorderList[i].borderSymbol = kv->GetNameSymbol();
+ }
+ }}
+
+ // iterate again to get the border references
+ for ( KeyValues *kv = m_pkvBorders->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey())
+ {
+ if (kv->GetDataType() == KeyValues::TYPE_STRING)
+ {
+ // it's referencing another border, find it
+ Border *border = (Border *)GetBorder(kv->GetString());
+// const char *str = kv->GetName();
+ Assert(border);
+
+ // add an entry that just references the existing border
+ int i = m_BorderList.AddToTail();
+ m_BorderList[i].border = border;
+ m_BorderList[i].bSharedBorder = true;
+ m_BorderList[i].borderSymbol = kv->GetNameSymbol();
+ }
+ }
+
+ m_pBaseBorder = GetBorder("BaseBorder");
+}
+
+void CScheme::SpewFonts( void )
+{
+ Msg( "Scheme: %s (%s)\n", GetName(), GetFileName() );
+ FOR_EACH_DICT_FAST( m_FontAliases, i )
+ {
+ const fontalias_t& FontAlias = m_FontAliases[ i ];
+ uint32 Font = FontAlias._font;
+ const char *szFontName = g_pSurface->GetFontName( Font );
+ const char *szFontFamilyName = g_pSurface->GetFontFamilyName( Font );
+ const char *szTrueFontName = FontAlias._trueFontName.String();
+ const char *szFontAlias = m_FontAliases.GetElementName( i );
+
+ Msg( " %2d: HFont:0x%8.8x, %s, %s, font:%s, tall:%d(%d). %s\n",
+ i,
+ Font,
+ szTrueFontName ? szTrueFontName : "??",
+ szFontAlias ? szFontAlias : "??",
+ szFontName ? szFontName : "??",
+ g_pSurface->GetFontTall( Font ),
+ g_pSurface->GetFontTallRequested( Font ),
+ szFontFamilyName ? szFontFamilyName : "" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: reloads the scheme from the file
+//-----------------------------------------------------------------------------
+void CSchemeManager::ReloadSchemes()
+{
+ int count = m_Schemes.Count();
+ Shutdown( false );
+
+ // reload the scheme
+ for (int i = 1; i < count; i++)
+ {
+ LoadSchemeFromFile(m_Schemes[i]->GetFileName(), m_Schemes[i]->GetName());
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: kills all the schemes
+//-----------------------------------------------------------------------------
+void CScheme::Shutdown( bool full )
+{
+ for (int i = 0; i < m_BorderList.Count(); i++)
+ {
+ // delete if it's not shared
+ if (!m_BorderList[i].bSharedBorder)
+ {
+ IBorder *border = m_BorderList[i].border;
+ delete border;
+ }
+ }
+
+ m_pBaseBorder = NULL;
+ m_BorderList.RemoveAll();
+ m_pkvBorders = NULL;
+
+ if (full && m_pData)
+ {
+ m_pData->deleteThis();
+ m_pData = NULL;
+ delete this;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a handle to the default (first loaded) scheme
+//-----------------------------------------------------------------------------
+HScheme CSchemeManager::GetDefaultScheme()
+{
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a handle to the scheme identified by "tag"
+//-----------------------------------------------------------------------------
+HScheme CSchemeManager::GetScheme(const char *tag)
+{
+ for (int i=1;i<m_Schemes.Count();i++)
+ {
+ if ( !stricmp(tag,m_Schemes[i]->GetName()) )
+ {
+ return i;
+ }
+ }
+ return 1; // default scheme
+}
+
+int CSchemeManager::GetProportionalScaledValue_( int rootWide, int rootTall, int normalizedValue )
+{
+ int proH, proW;
+ g_pSurface->GetProportionalBase( proW, proH );
+ double scale = (double)rootTall / (double)proH;
+
+ return (int)( normalizedValue * scale );
+}
+
+int CSchemeManager::GetProportionalNormalizedValue_( int rootWide, int rootTall, int scaledValue )
+{
+ int proH, proW;
+ g_pSurface->GetProportionalBase( proW, proH );
+ float scale = (float)rootTall / (float)proH;
+
+ return (int)( scaledValue / scale );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: converts a value into proportional mode
+//-----------------------------------------------------------------------------
+int CSchemeManager::GetProportionalScaledValue(int normalizedValue)
+{
+ int wide, tall;
+ g_pSurface->GetScreenSize( wide, tall );
+ return GetProportionalScaledValue_( wide, tall, normalizedValue );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: converts a value out of proportional mode
+//-----------------------------------------------------------------------------
+int CSchemeManager::GetProportionalNormalizedValue(int scaledValue)
+{
+ int wide, tall;
+ g_pSurface->GetScreenSize( wide, tall );
+ return GetProportionalNormalizedValue_( wide, tall, scaledValue );
+}
+
+// gets the proportional coordinates for doing screen-size independant panel layouts
+// use these for font, image and panel size scaling (they all use the pixel height of the display for scaling)
+int CSchemeManager::GetProportionalScaledValueEx( CScheme *pScheme, int normalizedValue )
+{
+ VPANEL sizing = pScheme->GetSizingPanel();
+ if ( !sizing )
+ {
+ return GetProportionalScaledValue( normalizedValue );
+ }
+
+ int w, h;
+ g_pIPanel->GetSize( sizing, w, h );
+ return GetProportionalScaledValue_( w, h, normalizedValue );
+}
+
+int CSchemeManager::GetProportionalNormalizedValueEx( CScheme *pScheme, int scaledValue )
+{
+ VPANEL sizing = pScheme->GetSizingPanel();
+ if ( !sizing )
+ {
+ return GetProportionalNormalizedValue( scaledValue );
+ }
+
+ int w, h;
+ g_pIPanel->GetSize( sizing, w, h );
+ return GetProportionalNormalizedValue_( w, h, scaledValue );
+}
+
+int CSchemeManager::GetProportionalScaledValueEx( HScheme scheme, int normalizedValue )
+{
+ IScheme *pscheme = GetIScheme( scheme );
+ if ( !pscheme )
+ {
+ Assert( 0 );
+ return GetProportionalScaledValue( normalizedValue );
+ }
+
+ CScheme *p = static_cast< CScheme * >( pscheme );
+ return GetProportionalScaledValueEx( p, normalizedValue );
+}
+
+int CSchemeManager::GetProportionalNormalizedValueEx( HScheme scheme, int scaledValue )
+{
+ IScheme *pscheme = GetIScheme( scheme );
+ if ( !pscheme )
+ {
+ Assert( 0 );
+ return GetProportionalNormalizedValue( scaledValue );
+ }
+
+ CScheme *p = static_cast< CScheme * >( pscheme );
+ return GetProportionalNormalizedValueEx( p, scaledValue );
+}
+
+void CSchemeManager::SpewFonts( void )
+{
+ for ( int i = 1; i < m_Schemes.Count(); i++ )
+ {
+ m_Schemes[i]->SpewFonts();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CScheme::GetResourceString(const char *stringName)
+{
+ return m_pkvBaseSettings->GetString(stringName);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a pointer to an image
+//-----------------------------------------------------------------------------
+IImage *CSchemeManager::GetImage(const char *imageName, bool hardwareFiltered)
+{
+ if ( !imageName || strlen(imageName) <= 0 ) // frame icons and the like are in the scheme file and may not be defined, so if this is null then fail silently
+ {
+ return NULL;
+ }
+
+ // set up to search for the bitmap
+ CachedBitmapHandle_t searchBitmap;
+ searchBitmap.pBitmap = NULL;
+
+ // Prepend 'vgui/'. Resource files try to load images assuming they live in the vgui directory.
+ // Used to do this in Bitmap::Bitmap, moved so that the s_pszSearchString is searching for the
+ // filename with 'vgui/' already added.
+ char szFileName[MAX_PATH];
+
+ //if ( Q_IsAbsolutePath(imageName) )
+ //{
+ // Q_strncpy( szFileName, imageName, sizeof(szFileName) );
+ //}
+ //else
+ {
+ if ( Q_stristr( imageName, ".pic" ) )
+ {
+ Q_snprintf( szFileName, sizeof(szFileName), "%s", imageName );
+ }
+ else
+ {
+ Q_snprintf( szFileName, sizeof(szFileName), "vgui/%s", imageName );
+ }
+ }
+
+ s_pszSearchString = szFileName;
+ int i = m_Bitmaps.Find( searchBitmap );
+ if (m_Bitmaps.IsValidIndex( i ) )
+ {
+ return m_Bitmaps[i].pBitmap;
+ }
+
+ // couldn't find the image, try and load it
+ CachedBitmapHandle_t hBitmap = { new Bitmap( szFileName, hardwareFiltered ) };
+ m_Bitmaps.Insert( hBitmap );
+ return hBitmap.pBitmap;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+HTexture CSchemeManager::GetImageID(const char *imageName, bool hardwareFiltered)
+{
+ IImage *img = GetImage(imageName, hardwareFiltered);
+ return ((Bitmap *)img)->GetID();
+}
+
+//-----------------------------------------------------------------------------
+// Delete a managed image
+//-----------------------------------------------------------------------------
+bool CSchemeManager::DeleteImage( const char *pImageName )
+{
+ if ( !pImageName )
+ {
+ // nothing to do
+ return false;
+ }
+
+ // set up to search for the bitmap
+ CachedBitmapHandle_t searchBitmap;
+ searchBitmap.pBitmap = NULL;
+
+ // Prepend 'vgui/'. Resource files try to load images assuming they live in the vgui directory.
+ // Used to do this in Bitmap::Bitmap, moved so that the s_pszSearchString is searching for the
+ // filename with 'vgui/' already added.
+ char szFileName[256];
+ if ( Q_stristr( pImageName, ".pic" ) )
+ {
+ Q_snprintf( szFileName, sizeof(szFileName), "%s", pImageName );
+ }
+ else
+ {
+ Q_snprintf( szFileName, sizeof(szFileName), "vgui/%s", pImageName );
+ }
+ s_pszSearchString = szFileName;
+
+ int i = m_Bitmaps.Find( searchBitmap );
+ if ( !m_Bitmaps.IsValidIndex( i ) )
+ {
+ // not found
+ return false;
+ }
+
+ // no way to know if eviction occured, assume it does
+ m_Bitmaps[i].pBitmap->Evict();
+ delete m_Bitmaps[i].pBitmap;
+ m_Bitmaps.RemoveAt( i );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a pointer to an existing border
+//-----------------------------------------------------------------------------
+IBorder *CScheme::GetBorder(const char *borderName)
+{
+ int symbol = KeyValuesSystem()->GetSymbolForString(borderName);
+ for (int i = 0; i < m_BorderList.Count(); i++)
+ {
+ if (m_BorderList[i].borderSymbol == symbol)
+ {
+ return m_BorderList[i].border;
+ }
+ }
+
+ return m_pBaseBorder;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the number of borders
+//-----------------------------------------------------------------------------
+int CScheme::GetBorderCount() const
+{
+ return m_BorderList.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the border at the given index
+//-----------------------------------------------------------------------------
+IBorder *CScheme::GetBorderAtIndex( int iIndex )
+{
+ if ( !m_BorderList.IsValidIndex( iIndex ) )
+ return NULL;
+
+ return m_BorderList[ iIndex ].border;
+}
+
+//-----------------------------------------------------------------------------
+// Finds a font in the alias list
+//-----------------------------------------------------------------------------
+HFont CScheme::FindFontInAliasList( const char *fontName )
+{
+ int i = m_FontAliases.Find( fontName );
+ if ( i != m_FontAliases.InvalidIndex() )
+ {
+ return m_FontAliases[i]._font;
+ }
+
+ // No dice
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : font -
+// Output : char const
+//-----------------------------------------------------------------------------
+char const *CScheme::GetFontName( const HFont& font )
+{
+ for (int i = m_FontAliases.Count(); --i >= 0; )
+ {
+ HFont fnt = (HFont)m_FontAliases[i]._font;
+ if ( fnt == font )
+ return m_FontAliases[i]._trueFontName.String();
+ }
+
+ return "<Unknown font>";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a pointer to an existing font, proportional=false means use default
+//-----------------------------------------------------------------------------
+HFont CScheme::GetFont( const char *fontName, bool proportional )
+{
+ // First look in the list of aliases...
+ return FindFontInAliasList( GetMungedFontName( fontName, tag, proportional ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:Get the number of fonts
+//-----------------------------------------------------------------------------
+int CScheme::GetFontCount() const
+{
+ return m_FontAliases.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the font at the given index
+//-----------------------------------------------------------------------------
+HFont CScheme::GetFontAtIndex( int iIndex )
+{
+ if ( !m_FontAliases.IsValidIndex( iIndex ) )
+ return INVALID_FONT;
+
+ return m_FontAliases[ iIndex ]._font;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a char string of the munged name this font is stored as in the font manager
+//-----------------------------------------------------------------------------
+const char *CScheme::GetMungedFontName( const char *fontName, const char *scheme, bool proportional )
+{
+ static char mungeBuffer[ 64 ];
+ if ( scheme )
+ {
+ Q_snprintf( mungeBuffer, sizeof( mungeBuffer ), "%s%s-%s", fontName, scheme, proportional ? "p" : "no" );
+ }
+ else
+ {
+ Q_snprintf( mungeBuffer, sizeof( mungeBuffer ), "%s-%s", fontName, proportional ? "p" : "no" ); // we don't want the "(null)" snprintf appends
+ }
+ return mungeBuffer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets a color from the scheme file
+//-----------------------------------------------------------------------------
+Color CScheme::GetColor(const char *colorName, Color defaultColor)
+{
+ const char *pchT = LookupSchemeSetting(colorName);
+ if (!pchT)
+ return defaultColor;
+
+ int r = 0, g = 0, b = 0, a = 0;
+ if (sscanf(pchT, "%d %d %d %d", &r, &g, &b, &a) >= 3)
+ return Color(r, g, b, a);
+
+ return defaultColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the color at the given index
+//-----------------------------------------------------------------------------
+const KeyValues *CScheme::GetColorData() const
+{
+ return m_pkvColors;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: recursively looks up a setting
+//-----------------------------------------------------------------------------
+const char *CScheme::LookupSchemeSetting(const char *pchSetting)
+{
+ // try parse out the color
+ int r, g, b, a = 0;
+ int res = sscanf(pchSetting, "%d %d %d %d", &r, &g, &b, &a);
+ if (res >= 3)
+ {
+ return pchSetting;
+ }
+
+ // check the color area first
+ const char *colStr = m_pkvColors->GetString(pchSetting, NULL);
+ if (colStr)
+ return colStr;
+
+ // check base settings
+ colStr = m_pkvBaseSettings->GetString(pchSetting, NULL);
+ if (colStr)
+ {
+ return LookupSchemeSetting(colStr);
+ }
+
+ return pchSetting;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the minimum font height for the current language
+//-----------------------------------------------------------------------------
+int CScheme::GetMinimumFontHeightForCurrentLanguage()
+{
+ char language[64];
+ bool bValid;
+ if ( IsPC() )
+ {
+ bValid = vgui::g_pSystem->GetRegistryString( "HKEY_CURRENT_USER\\Software\\Valve\\Source\\Language", language, sizeof(language)-1 );
+ }
+ else
+ {
+ Q_strncpy( language, XBX_GetLanguageString(), sizeof( language ) );
+ bValid = true;
+ }
+
+ if ( bValid )
+ {
+ if (!stricmp(language, "korean")
+ || !stricmp(language, "tchinese")
+ || !stricmp(language, "schinese")
+ || !stricmp(language, "japanese"))
+ {
+ // the bitmap-based fonts for these languages simply don't work with a pt. size of less than 9 (13 pixels)
+ return 13;
+ }
+
+ if ( !stricmp(language, "thai" ) )
+ {
+ // thai has problems below 18 pts
+ return 18;
+ }
+ }
+
+ // no special minimum height required
+ return 0;
+}
diff --git a/vgui2/src/Surface.cpp b/vgui2/src/Surface.cpp
new file mode 100644
index 0000000..2f62320
--- /dev/null
+++ b/vgui2/src/Surface.cpp
@@ -0,0 +1,4082 @@
+//========= 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;
+}
diff --git a/vgui2/src/System.cpp b/vgui2/src/System.cpp
new file mode 100644
index 0000000..381396f
--- /dev/null
+++ b/vgui2/src/System.cpp
@@ -0,0 +1,1151 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#if !defined( _X360 )
+#define WIN32_LEAN_AND_MEAN
+#define OEMRESOURCE
+#include <windows.h>
+#include <shellapi.h>
+#include <shlwapi.h>
+#include <shlobj.h>
+#endif
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/stat.h>
+
+
+#ifdef ShellExecute
+#undef ShellExecute
+#endif
+
+#ifdef GetCurrentTime
+#undef GetCurrentTime
+#endif
+
+#ifdef GetTickCount
+#undef GetTickCount
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui/ISystem.h>
+#include <KeyValues.h>
+#include <vgui/IInputInternal.h>
+#include <vgui/ISurface.h>
+#include "tier0/vcrmode.h"
+#include "filesystem.h"
+
+#include "vgui_internal.h"
+#include "filesystem_helpers.h"
+#include "vgui_key_translation.h"
+#include "filesystem.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+#define PROTECTED_THINGS_DISABLE
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+
+
+#ifndef _X360
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Service Windows routines
+//
+//////////////////////////////////////////////////////////////////////////
+
+static BOOL CALLBACK GetMainApplicationWindowHWND_EnumProc( HWND hWnd, LPARAM lParam )
+{
+ // Return TRUE to continue enumeration or FALSE to stop
+
+ // Given window thread/process id
+ DWORD dwProcessId, dwThreadId;
+ dwThreadId = GetWindowThreadProcessId( hWnd, &dwProcessId );
+
+ // Our thread/process id
+ DWORD dwOurProcessId;
+ dwOurProcessId = GetCurrentProcessId();
+
+ // Foreign process
+ if ( dwOurProcessId != dwProcessId )
+ return TRUE;
+ // Service window
+ if ( !IsWindowVisible( hWnd ) || !IsWindowEnabled( hWnd ) )
+ return TRUE;
+
+ // Assume that we found it
+ *( HWND * )lParam = hWnd;
+ return FALSE; // stop enumeration
+}
+
+static HWND GetMainApplicationWindowHWND()
+{
+ HWND hWnd = NULL;
+
+ //
+ // Pass 1: calling on a GUI thread
+ //
+ DWORD dwThreadId = GetCurrentThreadId();
+
+ GUITHREADINFO gti;
+ memset( &gti, 0, sizeof( gti ) );
+ gti.cbSize = sizeof( gti );
+ GetGUIThreadInfo( dwThreadId, &gti );
+
+ hWnd = gti.hwndActive;
+ for ( HWND hParent = hWnd ? GetParent( hWnd ) : hWnd;
+ hParent; hWnd = hParent, hParent = GetParent( hWnd ) )
+ continue;
+
+ if ( hWnd )
+ return hWnd;
+
+ //
+ // Pass 2: non-GUI thread requiring the main winow
+ //
+ EnumWindows( GetMainApplicationWindowHWND_EnumProc, ( LPARAM ) &hWnd );
+ if ( hWnd )
+ return hWnd;
+
+ // Failed to find the window by all means...
+ return NULL;
+}
+
+
+#endif // #ifndef _X360
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// ISystem implementation
+//
+//////////////////////////////////////////////////////////////////////////
+
+
+using namespace vgui;
+
+SHORT System_GetKeyState( int virtualKeyCode )
+{
+#ifndef _X360
+ return VCRHook_GetKeyState(virtualKeyCode);
+#else
+ return 0;
+#endif
+}
+
+class CSystem : public ISystem
+{
+public:
+ CSystem();
+ ~CSystem();
+
+ virtual void Shutdown();
+ virtual void RunFrame();
+
+ virtual long GetTimeMillis();
+
+ // returns the time at the start of the frame
+ virtual double GetFrameTime();
+
+ // returns the current time
+ virtual double GetCurrentTime();
+
+ virtual void ShellExecute(const char *command, const char *file);
+
+ virtual int GetClipboardTextCount();
+ virtual void SetClipboardText(const char *text, int textLen);
+ virtual void SetClipboardText(const wchar_t *text, int textLen);
+ virtual int GetClipboardText(int offset, char *buf, int bufLen);
+ virtual int GetClipboardText(int offset, wchar_t *buf, int bufLen);
+
+ virtual void SetClipboardImage( void *pWnd, int x1, int y1, int x2, int y2 );
+
+ virtual bool SetRegistryString(const char *key, const char *value);
+ virtual bool GetRegistryString(const char *key, char *value, int valueLen);
+ virtual bool SetRegistryInteger(const char *key, int value);
+ virtual bool GetRegistryInteger(const char *key, int &value);
+ virtual bool DeleteRegistryKey(const char *keyName);
+
+ virtual bool SetWatchForComputerUse(bool state);
+ virtual double GetTimeSinceLastUse();
+ virtual int GetAvailableDrives(char *buf, int bufLen);
+ virtual double GetFreeDiskSpace(const char *path);
+
+ virtual KeyValues *GetUserConfigFileData(const char *dialogName, int dialogID);
+ virtual void SetUserConfigFile(const char *fileName, const char *pathName);
+ virtual void SaveUserConfigFile();
+
+ virtual bool CommandLineParamExists(const char *commandName);
+ virtual bool GetCommandLineParamValue(const char *paramName, char *value, int valueBufferSize);
+ virtual const char *GetFullCommandLine();
+ virtual bool GetCurrentTimeAndDate(int *year, int *month, int *dayOfWeek, int *day, int *hour, int *minute, int *second);
+
+ // shortcut (.lnk) modification functions
+ virtual bool CreateShortcut(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory, const char *iconFile);
+ virtual bool GetShortcutTarget(const char *linkFileName, char *targetPath, char *arguments, int destBufferSizes);
+ virtual bool ModifyShortcutTarget(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory);
+
+ virtual KeyCode KeyCode_VirtualKeyToVGUI( int keyCode );
+ virtual const char *GetDesktopFolderPath();
+ virtual void ShellExecuteEx( const char *command, const char *file, const char *pParams );
+private:
+ // auto-away data
+ bool m_bStaticWatchForComputerUse;
+ HHOOK m_hStaticKeyboardHook;
+ HHOOK m_hStaticMouseHook;
+ double m_StaticLastComputerUseTime;
+ int m_iStaticMouseOldX, m_iStaticMouseOldY;
+
+ // timer data
+ double m_flFrameTime;
+ KeyValues *m_pUserConfigData;
+ char m_szFileName[MAX_PATH];
+ char m_szPathID[MAX_PATH];
+
+};
+
+
+CSystem g_System;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CSystem, ISystem, VGUI_SYSTEM_INTERFACE_VERSION, g_System);
+
+namespace vgui
+{
+vgui::ISystem *g_pSystem = &g_System;
+}
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CSystem::CSystem()
+{
+ m_bStaticWatchForComputerUse = false;
+ m_hStaticKeyboardHook = NULL;
+ m_hStaticMouseHook = NULL;
+ m_StaticLastComputerUseTime = 0.0;
+ m_iStaticMouseOldX = m_iStaticMouseOldY = -1;
+ m_flFrameTime = 0.0;
+ m_pUserConfigData = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CSystem::~CSystem()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSystem::Shutdown()
+{
+ if (m_pUserConfigData)
+ {
+ m_pUserConfigData->deleteThis();
+ m_pUserConfigData = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles all the per frame actions
+//-----------------------------------------------------------------------------
+void CSystem::RunFrame()
+{
+ // record the current frame time
+ m_flFrameTime = GetCurrentTime();
+
+ if (m_bStaticWatchForComputerUse)
+ {
+ // check for mouse movement
+ int x, y;
+ g_pInput->GetCursorPos(x, y);
+ // allow a little slack for jittery mice, don't reset until it's moved more than fifty pixels
+ if (abs((x + y) - (m_iStaticMouseOldX + m_iStaticMouseOldY)) > 50)
+ {
+ m_StaticLastComputerUseTime = GetTimeMillis() / 1000.0;
+ m_iStaticMouseOldX = x;
+ m_iStaticMouseOldY = y;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the time at the start of the frame
+//-----------------------------------------------------------------------------
+double CSystem::GetFrameTime()
+{
+ return m_flFrameTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the current time
+//-----------------------------------------------------------------------------
+double CSystem::GetCurrentTime()
+{
+ return Plat_FloatTime();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the current time in milliseconds
+//-----------------------------------------------------------------------------
+long CSystem::GetTimeMillis()
+{
+ return (long)(GetCurrentTime() * 1000);
+}
+
+void CSystem::ShellExecute( const char *command, const char *file )
+{
+#ifndef _X360
+ ::ShellExecuteA(NULL, command, file, NULL, NULL, SW_SHOWNORMAL);
+#endif
+}
+
+void CSystem::ShellExecuteEx( const char *command, const char *file, const char *pParams )
+{
+#ifndef _X360
+ ::ShellExecuteA(NULL, command, file, pParams, NULL, SW_SHOWNORMAL);
+#endif
+}
+
+
+void CSystem::SetClipboardImage( void *pWnd, int x1, int y1, int x2, int y2 )
+{
+#ifndef _X360
+ if ( x2 <= x1 || y2 <= y1 )
+ return;
+
+ // Main app window
+ HWND hWnd = ( HWND ) ( pWnd );
+ if ( !hWnd )
+ hWnd = GetMainApplicationWindowHWND();
+ if ( !hWnd )
+ return;
+
+ // Prepare the blit
+ HBITMAP hBmMem = NULL;
+ {
+ // Device contexts
+ HDC hDc = GetDC( hWnd );
+ HDC hDcMem = CreateCompatibleDC( hDc );
+ hBmMem = CreateCompatibleBitmap( hDc, x2 - x1, y2 - y1 );
+ HBITMAP hBmOld = ( HBITMAP ) SelectObject( hDcMem, hBmMem );
+ BitBlt( hDcMem, 0, 0, x2 - x1, y2 - y1, hDc, x1, y1, SRCCOPY );
+ SelectObject( hDcMem, hBmOld );
+ DeleteDC( hDcMem );
+ ReleaseDC( hWnd, hDc );
+ // hBmMem now holds the image.
+ }
+
+ if ( !OpenClipboard( GetDesktopWindow() ) )
+ return;
+
+ EmptyClipboard();
+
+ if (hBmMem)
+ {
+ SetClipboardData(CF_BITMAP, hBmMem);
+ }
+
+ CloseClipboard();
+#endif
+}
+
+void CSystem::SetClipboardText(const char *text, int textLen)
+{
+#ifndef _X360
+ if (!text)
+ return;
+
+ if (textLen <= 0)
+ return;
+
+ if (!OpenClipboard(GetDesktopWindow() ))
+ return;
+
+ EmptyClipboard();
+
+ HANDLE hmem = GlobalAlloc(GMEM_MOVEABLE, textLen + 1);
+ if (hmem)
+ {
+ void *ptr = GlobalLock(hmem);
+ if (ptr != null)
+ {
+ memset(ptr, 0, textLen + 1);
+ memcpy(ptr, text, textLen);
+ GlobalUnlock(hmem);
+
+ SetClipboardData(CF_TEXT, hmem);
+ }
+ }
+
+ CloseClipboard();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Puts unicode text into the clipboard
+//-----------------------------------------------------------------------------
+void CSystem::SetClipboardText(const wchar_t *text, int textLen)
+{
+#ifndef _X360
+ if (!text)
+ return;
+
+ if (textLen <= 0)
+ return;
+
+ BOOL cb = OpenClipboard(GetDesktopWindow() );
+ if (!cb)
+ return;
+
+ EmptyClipboard();
+
+ HANDLE hmem = GlobalAlloc(GMEM_MOVEABLE, (textLen + 1) * sizeof(wchar_t));
+ if (hmem)
+ {
+ void *ptr = GlobalLock(hmem);
+ if (ptr != null)
+ {
+ memset(ptr, 0, (textLen + 1) * sizeof(wchar_t));
+ memcpy(ptr, text, textLen * sizeof(wchar_t));
+ GlobalUnlock(hmem);
+
+ SetClipboardData( CF_UNICODETEXT, hmem );
+ }
+ }
+
+ CloseClipboard();
+#endif
+}
+
+int CSystem::GetClipboardTextCount()
+{
+#ifndef _X360
+ int count = 0;
+
+ if ( VCRGetMode() != VCR_Playback )
+ {
+ if (OpenClipboard(GetDesktopWindow() ))
+ {
+ HANDLE hmem = GetClipboardData(CF_TEXT);
+ if (hmem)
+ {
+ count = GlobalSize(hmem);
+ }
+
+ CloseClipboard();
+ }
+ }
+ VCRGenericValue( "clipboard", &count, sizeof( count ) );
+
+ return count;
+#else
+ return 0;
+#endif
+}
+
+int CSystem::GetClipboardText(int offset, char *buf, int bufLen)
+{
+#ifndef _X360
+ int count = 0;
+ if ( buf && bufLen > 0 && VCRGetMode() != VCR_Playback )
+ {
+ if (OpenClipboard(GetDesktopWindow()))
+ {
+ HANDLE hmem = GetClipboardData(CF_UNICODETEXT);
+ if (hmem)
+ {
+ int len = GlobalSize(hmem);
+ count = len - offset;
+ if (count <= 0)
+ {
+ count = 0;
+ }
+ else
+ {
+ if (bufLen < count)
+ {
+ count = bufLen;
+ }
+ void *ptr = GlobalLock(hmem);
+ if (ptr)
+ {
+ memcpy(buf, ((char *)ptr) + offset, count);
+ GlobalUnlock(hmem);
+ }
+ }
+ }
+
+ CloseClipboard();
+ }
+ }
+ VCRGenericValue( "cb", &count, sizeof( count ) );
+ VCRGenericValue( "cb", buf, count );
+
+ return count;
+#else
+ return 0;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Retrieves unicode text from the clipboard
+//-----------------------------------------------------------------------------
+int CSystem::GetClipboardText(int offset, wchar_t *buf, int bufLen)
+{
+#ifndef _X360
+ int retVal = 0;
+ if ( buf && bufLen > 0 && VCRGetMode() != VCR_Playback )
+ {
+ if (OpenClipboard( GetDesktopWindow() ) )
+ {
+ HANDLE hmem = GetClipboardData(CF_UNICODETEXT);
+ if (hmem)
+ {
+ int len = GlobalSize(hmem);
+ int count = len - offset;
+ if (count > 0)
+ {
+ if (bufLen < count)
+ {
+ count = bufLen;
+ }
+ void *ptr = GlobalLock(hmem);
+ if (ptr)
+ {
+ memcpy(buf, ((wchar_t *)ptr) + offset, count);
+ retVal = count / sizeof(wchar_t);
+ GlobalUnlock(hmem);
+ }
+ }
+ }
+ }
+
+ CloseClipboard();
+ }
+
+ VCRGenericValue( "cb", &retVal, sizeof( retVal ) );
+ VCRGenericValue( "cb", buf, retVal*sizeof(wchar_t) );
+
+ return retVal;
+#else
+ return 0;
+#endif
+}
+
+static bool staticSplitRegistryKey(const char *key, char *key0, int key0Len, char *key1, int key1Len)
+{
+ if(key==null)
+ {
+ return false;
+ }
+
+ int len=strlen(key);
+ if(len<=0)
+ {
+ return false;
+ }
+
+ int Start=-1;
+ for(int i=len-1;i>=0;i--)
+ {
+ if(key[i]=='\\')
+ {
+ break;
+ }
+ else
+ {
+ Start=i;
+ }
+ }
+
+ if(Start==-1)
+ {
+ return false;
+ }
+
+ vgui_strcpy(key0,Start+1,key);
+ vgui_strcpy(key1,(len-Start)+1,key+Start);
+
+ return true;
+}
+
+bool CSystem::SetRegistryString(const char *key, const char *value)
+{
+#ifndef _X360
+ HKEY hKey;
+
+ HKEY hSlot = HKEY_CURRENT_USER;
+ if (!strncmp(key, "HKEY_LOCAL_MACHINE", 18))
+ {
+ hSlot = HKEY_LOCAL_MACHINE;
+ key += 19;
+ }
+ else if (!strncmp(key, "HKEY_CURRENT_USER", 17))
+ {
+ hSlot = HKEY_CURRENT_USER;
+ key += 18;
+ }
+
+ char key0[256], key1[256];
+ if (!staticSplitRegistryKey(key, key0, sizeof(key0), key1, sizeof(key1)))
+ {
+ return false;
+ }
+
+ if(VCRHook_RegCreateKeyEx(hSlot,key0,null,null,REG_OPTION_NON_VOLATILE, value ? KEY_WRITE : KEY_ALL_ACCESS,null,&hKey,null)!=ERROR_SUCCESS)
+ {
+ return false;
+ }
+
+ if (VCRHook_RegSetValueEx(hKey, key1, NULL, REG_SZ, (uchar*)value, strlen(value) + 1) == ERROR_SUCCESS)
+ {
+ VCRHook_RegCloseKey(hKey);
+ return true;
+ }
+
+ VCRHook_RegCloseKey(hKey);
+#endif
+
+ return false;
+}
+
+bool CSystem::GetRegistryString(const char *key, char *value, int valueLen)
+{
+#ifndef _X360
+ if (!value)
+ return false;
+ value[0] = 0;
+
+ HKEY hKey;
+
+ HKEY hSlot = HKEY_CURRENT_USER;
+ if (!strncmp(key, "HKEY_LOCAL_MACHINE", 18))
+ {
+ hSlot = HKEY_LOCAL_MACHINE;
+ key += 19;
+ }
+ else if (!strncmp(key, "HKEY_CURRENT_USER", 17))
+ {
+ hSlot = HKEY_CURRENT_USER;
+ key += 18;
+ }
+
+ char key0[256],key1[256];
+ if(!staticSplitRegistryKey(key,key0,256,key1,256))
+ {
+ return false;
+ }
+
+ if(VCRHook_RegOpenKeyEx(hSlot,key0,null,KEY_READ,&hKey)!=ERROR_SUCCESS)
+ {
+ return false;
+ }
+
+ ulong len=valueLen;
+ if(VCRHook_RegQueryValueEx(hKey,key1,null,null,(uchar*)value,&len)==ERROR_SUCCESS)
+ {
+ VCRHook_RegCloseKey(hKey);
+ return true;
+ }
+
+ VCRHook_RegCloseKey(hKey);
+#endif
+
+ return false;
+}
+
+bool CSystem::SetRegistryInteger(const char *key, int value)
+{
+#ifndef _X360
+ HKEY hKey;
+ HKEY hSlot = HKEY_CURRENT_USER;
+ if (!strncmp(key, "HKEY_LOCAL_MACHINE", 18))
+ {
+ hSlot = HKEY_LOCAL_MACHINE;
+ key += 19;
+ }
+ else if (!strncmp(key, "HKEY_CURRENT_USER", 17))
+ {
+ hSlot = HKEY_CURRENT_USER;
+ key += 18;
+ }
+
+ char key0[256],key1[256];
+ if(!staticSplitRegistryKey(key,key0,256,key1,256))
+ {
+ return false;
+ }
+
+ if(VCRHook_RegCreateKeyEx(hSlot,key0,null,null,REG_OPTION_NON_VOLATILE,KEY_WRITE,null,&hKey,null)!=ERROR_SUCCESS)
+ {
+ return false;
+ }
+
+ if(VCRHook_RegSetValueEx(hKey,key1,null,REG_DWORD,(uchar*)&value,4)==ERROR_SUCCESS)
+ {
+ VCRHook_RegCloseKey(hKey);
+ return true;
+ }
+
+ VCRHook_RegCloseKey(hKey);
+#endif
+ return false;
+}
+
+bool CSystem::GetRegistryInteger(const char *key, int &value)
+{
+#ifndef _X360
+ HKEY hKey;
+ HKEY hSlot = HKEY_CURRENT_USER;
+ if (!strncmp(key, "HKEY_LOCAL_MACHINE", 18))
+ {
+ hSlot = HKEY_LOCAL_MACHINE;
+ key += 19;
+ }
+ else if (!strncmp(key, "HKEY_CURRENT_USER", 17))
+ {
+ hSlot = HKEY_CURRENT_USER;
+ key += 18;
+ }
+
+ char key0[256],key1[256];
+ if(!staticSplitRegistryKey(key,key0,256,key1,256))
+ {
+ return false;
+ }
+
+ if(VCRHook_RegOpenKeyEx(hSlot,key0,null,KEY_READ,&hKey)!=ERROR_SUCCESS)
+ {
+ return false;
+ }
+
+ ulong len=4;
+ if(VCRHook_RegQueryValueEx(hKey,key1,null,null,(uchar*)&value,&len)==ERROR_SUCCESS)
+ {
+ VCRHook_RegCloseKey(hKey);
+ return true;
+ }
+
+ VCRHook_RegCloseKey(hKey);
+#endif
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: recursively deletes a registry key and all it's subkeys
+//-----------------------------------------------------------------------------
+bool CSystem::DeleteRegistryKey(const char *key)
+{
+#ifndef _X360
+ HKEY hSlot = HKEY_CURRENT_USER;
+ if (!strncmp(key, "HKEY_LOCAL_MACHINE", 18))
+ {
+ hSlot = HKEY_LOCAL_MACHINE;
+ key += 19;
+ }
+ else if (!strncmp(key, "HKEY_CURRENT_USER", 17))
+ {
+ hSlot = HKEY_CURRENT_USER;
+ key += 18;
+ }
+
+ if (SHDeleteKey(hSlot, key) == ERROR_SUCCESS)
+ {
+ return true;
+ }
+#endif
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets whether or not the app watches for global computer use
+//-----------------------------------------------------------------------------
+bool CSystem::SetWatchForComputerUse(bool state)
+{
+ if (state == m_bStaticWatchForComputerUse)
+ return true;
+
+ m_bStaticWatchForComputerUse = state;
+
+ if (m_bStaticWatchForComputerUse)
+ {
+ // enable watching
+ }
+ else
+ {
+ // disable watching
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the time, in seconds, since the last computer use.
+//-----------------------------------------------------------------------------
+double CSystem::GetTimeSinceLastUse()
+{
+ if (m_bStaticWatchForComputerUse)
+ {
+ return (GetTimeMillis() / 1000.0) - m_StaticLastComputerUseTime;
+ }
+
+ return 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the drives a user has available on their system
+//-----------------------------------------------------------------------------
+int CSystem::GetAvailableDrives(char *buf, int bufLen)
+{
+#if defined( _X360 ) || defined ( OSX )
+ return 0;
+#else // Windows
+ return GetLogicalDriveStrings( bufLen, buf );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the amount of available disk space, in bytes, on the specified path
+//-----------------------------------------------------------------------------
+double CSystem::GetFreeDiskSpace(const char *path)
+{
+ char buf[_MAX_PATH];
+ strcpy(buf, path);
+ // strip of to first slash (to make it look like 'x:\')
+ char *slash = strstr(buf, "\\");
+ if (slash)
+ {
+ slash[1] = 0;
+ }
+
+ ULARGE_INTEGER userFreeBytes, totalBytes, totalFreeBytes;
+ if (::GetDiskFreeSpaceEx(buf, &userFreeBytes, &totalBytes, &totalFreeBytes))
+ {
+ return (double)userFreeBytes.QuadPart;
+ }
+ return 0.0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: user config
+//-----------------------------------------------------------------------------
+KeyValues *CSystem::GetUserConfigFileData(const char *dialogName, int dialogID)
+{
+ if (!m_pUserConfigData)
+ return NULL;
+
+ Assert(dialogName && *dialogName);
+
+ if (dialogID)
+ {
+ char buf[256];
+ Q_snprintf(buf, sizeof(buf), "%s_%d", dialogName, dialogID);
+ dialogName = buf;
+ }
+
+ return m_pUserConfigData->FindKey(dialogName, true);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the name of the config file to save/restore from. Settings are loaded immediately.
+//-----------------------------------------------------------------------------
+void CSystem::SetUserConfigFile(const char *fileName, const char *pathName)
+{
+ if (!m_pUserConfigData)
+ {
+ m_pUserConfigData = new KeyValues("UserConfigData");
+ }
+
+ strncpy(m_szFileName, fileName, sizeof(m_szFileName) - 1);
+ strncpy(m_szPathID, pathName, sizeof(m_szPathID) - 1);
+
+ // open
+ m_pUserConfigData->UsesEscapeSequences( true ); // VGUI may use this
+ m_pUserConfigData->LoadFromFile(g_pFullFileSystem, m_szFileName, m_szPathID);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: saves all the current settings to the user config file
+//-----------------------------------------------------------------------------
+void CSystem::SaveUserConfigFile()
+{
+ if (m_pUserConfigData)
+ {
+ m_pUserConfigData->SaveToFile(g_pFullFileSystem, m_szFileName, m_szPathID);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether or not the parameter was on the command line
+//-----------------------------------------------------------------------------
+bool CSystem::CommandLineParamExists(const char *paramName)
+{
+ const char *cmdLine = GetFullCommandLine();
+ const char *loc = strstr(cmdLine, paramName);
+ return (loc != NULL);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the string following a command line param
+//-----------------------------------------------------------------------------
+bool CSystem::GetCommandLineParamValue(const char *paramName, char *value, int valueBufferSize)
+{
+ const char *cmdLine = GetFullCommandLine();
+ const char *loc = strstr(cmdLine, paramName);
+ if (!loc)
+ return false;
+
+ loc += strlen(paramName);
+
+ char token[512];
+ ParseFile(loc, token, NULL);
+
+ strncpy(value, token, valueBufferSize - 1);
+ value[valueBufferSize - 1] = 0;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the name of the currently running exe
+//-----------------------------------------------------------------------------
+const char *CSystem::GetFullCommandLine()
+{
+ return VCRHook_GetCommandLine();
+}
+
+
+KeyCode CSystem::KeyCode_VirtualKeyToVGUI( int keyCode )
+{
+ return ::KeyCode_VirtualKeyToVGUI( keyCode );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the current local time and date
+//-----------------------------------------------------------------------------
+bool CSystem::GetCurrentTimeAndDate(int *year, int *month, int *dayOfWeek, int *day, int *hour, int *minute, int *second)
+{
+ SYSTEMTIME time;
+ GetLocalTime(&time);
+ if (year)
+ {
+ *year = time.wYear;
+ }
+ if (month)
+ {
+ *month = time.wMonth;
+ }
+ if (dayOfWeek)
+ {
+ *dayOfWeek = time.wDayOfWeek;
+ }
+ if (day)
+ {
+ *day = time.wDay;
+ }
+ if (hour)
+ {
+ *hour = time.wHour;
+ }
+ if (minute)
+ {
+ *minute = time.wMinute;
+ }
+ if (second)
+ {
+ *second = time.wSecond;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a shortcut file
+//-----------------------------------------------------------------------------
+bool CSystem::CreateShortcut(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory, const char *iconFile)
+{
+#ifndef _X360
+ bool bSuccess = false;
+ char temp[MAX_PATH];
+ strcpy(temp, linkFileName);
+
+ // make sure it doesn't already exist
+ struct _stat statBuf;
+ if (_stat(linkFileName, &statBuf) != -1)
+ return false;
+
+ // Create the ShellLink object
+ IShellLink *psl;
+ HRESULT hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &psl);
+ if (SUCCEEDED(hres))
+ {
+ // Set the target information from the link object
+ psl->SetPath(targetPath);
+ psl->SetArguments(arguments);
+ if (workingDirectory && *workingDirectory)
+ {
+ psl->SetWorkingDirectory(workingDirectory);
+ }
+ if (iconFile && *iconFile)
+ {
+ psl->SetIconLocation(iconFile, 0);
+ }
+
+ // Bind the ShellLink object to the Persistent File
+ IPersistFile *ppf;
+ hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
+ if (SUCCEEDED(hres))
+ {
+ wchar_t wsz[MAX_PATH];
+ // Get a UNICODE wide string wsz from the link path
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, temp, -1, wsz, MAX_PATH);
+ hres = ppf->Save(wsz, TRUE);
+ if (SUCCEEDED(hres))
+ {
+ bSuccess = true;
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ return bSuccess;
+#else
+ return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: retrieves shortcut (.lnk) information
+//-----------------------------------------------------------------------------
+bool CSystem::GetShortcutTarget(const char *linkFileName, char *targetPath, char *arguments, int destBufferSizes)
+{
+#ifndef _X360
+ char temp[MAX_PATH];
+ strcpy(temp, linkFileName);
+ strlwr(temp);
+
+ targetPath[0] = 0;
+ arguments[0] = 0;
+
+ // Create the ShellLink object
+ IShellLink *psl;
+ HRESULT hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &psl);
+ if (SUCCEEDED(hres))
+ {
+ IPersistFile *ppf;
+ // Bind the ShellLink object to the Persistent File
+ hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
+ if (SUCCEEDED(hres))
+ {
+ wchar_t wsz[MAX_PATH];
+ // Get a UNICODE wide string wsz from the link path
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, temp, -1, wsz, MAX_PATH);
+
+ // Read the link into the persistent file
+ hres = ppf->Load(wsz, 0);
+
+ if (SUCCEEDED(hres))
+ {
+ //Read the target information from the link object
+ //UNC paths are supported (SLGP_UNCPRIORITY)
+ psl->GetPath(targetPath, destBufferSizes, NULL, SLGP_UNCPRIORITY);
+
+ //Read the arguments from the link object
+ psl->GetArguments(arguments, destBufferSizes);
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ return (targetPath[0] != 0);
+#else
+ return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets shortcut (.lnk) information
+//-----------------------------------------------------------------------------
+bool CSystem::ModifyShortcutTarget(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory)
+{
+#ifndef _X360
+ bool bSuccess = false;
+ char temp[MAX_PATH];
+ strcpy(temp, linkFileName);
+ strlwr(temp);
+
+ // Create the ShellLink object
+ IShellLink *psl;
+ HRESULT hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &psl);
+ if (SUCCEEDED(hres))
+ {
+ IPersistFile *ppf;
+ // Bind the ShellLink object to the Persistent File
+ hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
+ if (SUCCEEDED(hres))
+ {
+ wchar_t wsz[MAX_PATH];
+ // Get a UNICODE wide string wsz from the link path
+ MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, temp, -1, wsz, MAX_PATH);
+
+ // Read the link into the persistent file
+ hres = ppf->Load(wsz, 0);
+
+ if (SUCCEEDED(hres))
+ {
+ // Set the target information from the link object
+ psl->SetPath(targetPath);
+ psl->SetArguments(arguments);
+ psl->SetWorkingDirectory(workingDirectory);
+ bSuccess = true;
+ ppf->Save(wsz, TRUE);
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ return bSuccess;
+#else
+ return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the full path of the current user's desktop folder
+//-----------------------------------------------------------------------------
+const char *CSystem::GetDesktopFolderPath()
+{
+#ifndef _X360
+ static char folderPath[MAX_PATH];
+ folderPath[0] = 0;
+
+ // try the custom regkey
+ if ( GetRegistryString( "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\Desktop", folderPath, sizeof(folderPath) )
+ && strlen(folderPath) > 6 )
+ {
+ return folderPath;
+ }
+
+
+ // try the default
+ if ( ::SHGetSpecialFolderPath( NULL, folderPath, CSIDL_DESKTOP, false )
+ && strlen(folderPath) > 6 )
+ {
+ return folderPath;
+ }
+#endif
+ return NULL;
+}
diff --git a/vgui2/src/VGUI_Border.h b/vgui2/src/VGUI_Border.h
new file mode 100644
index 0000000..9c2f2e5
--- /dev/null
+++ b/vgui2/src/VGUI_Border.h
@@ -0,0 +1,82 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core implementation of vgui
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef VGUI_BORDER_H
+#define VGUI_BORDER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui/IBorder.h>
+#include <vgui/IScheme.h>
+#include <Color.h>
+
+class KeyValues;
+
+namespace vgui
+{
+
+//-----------------------------------------------------------------------------
+// Purpose: Interface to panel borders
+// Borders have a close relationship with panels
+//-----------------------------------------------------------------------------
+class Border : public IBorder
+{
+public:
+ Border();
+ ~Border();
+
+ virtual void Paint(VPANEL panel);
+ virtual void Paint(int x0, int y0, int x1, int y1);
+ virtual void Paint(int x0, int y0, int x1, int y1, int breakSide, int breakStart, int breakStop);
+ virtual void SetInset(int left, int top, int right, int bottom);
+ virtual void GetInset(int &left, int &top, int &right, int &bottom);
+
+ virtual void ApplySchemeSettings(IScheme *pScheme, KeyValues *inResourceData);
+
+ virtual const char *GetName();
+ virtual void SetName(const char *name);
+ virtual backgroundtype_e GetBackgroundType();
+
+ virtual bool PaintFirst( void ) { return false; }
+
+protected:
+ int _inset[4];
+
+private:
+ // protected copy constructor to prevent use
+ Border(Border&);
+
+ void ParseSideSettings(int side_index, KeyValues *inResourceData, IScheme *pScheme);
+
+ char *_name;
+
+ // border drawing description
+ struct line_t
+ {
+ Color col;
+ int startOffset;
+ int endOffset;
+ };
+
+ struct side_t
+ {
+ int count;
+ line_t *lines;
+ };
+
+ side_t _sides[4]; // left, top, right, bottom
+ backgroundtype_e m_eBackgroundType;
+
+ friend class VPanel;
+};
+
+} // namespace vgui
+
+#endif // VGUI_BORDER_H
diff --git a/vgui2/src/VPanel.cpp b/vgui2/src/VPanel.cpp
new file mode 100644
index 0000000..dcdfb81
--- /dev/null
+++ b/vgui2/src/VPanel.cpp
@@ -0,0 +1,782 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdio.h>
+
+#include <vgui/IPanel.h>
+#include <vgui/IClientPanel.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/Cursor.h>
+
+#include "vgui_internal.h"
+#include "VPanel.h"
+
+#include "tier0/minidump.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+
+// Lame copy from Panel
+enum PinCorner_e
+{
+ PIN_TOPLEFT = 0,
+ PIN_TOPRIGHT,
+ PIN_BOTTOMLEFT,
+ PIN_BOTTOMRIGHT,
+
+ // For sibling pinning
+ PIN_CENTER_TOP,
+ PIN_CENTER_RIGHT,
+ PIN_CENTER_BOTTOM,
+ PIN_CENTER_LEFT,
+
+ NUM_PIN_POINTS,
+};
+
+float PinDeltas[NUM_PIN_POINTS][2] =
+{
+ { 0, 0 }, // PIN_TOPLEFT,
+ { 1, 0 }, // PIN_TOPRIGHT,
+ { 0, 1 }, // PIN_BOTTOMLEFT,
+ { 1, 1 }, // PIN_BOTTOMRIGHT,
+ { 0.5, 0 }, // PIN_CENTER_TOP,
+ { 1, 0.5 }, // PIN_CENTER_RIGHT,
+ { 0.5, 1 }, // PIN_CENTER_BOTTOM,
+ { 0, 0.5 }, // PIN_CENTER_LEFT,
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VPanel::VPanel()
+{
+ _pos[0] = _pos[1] = 0;
+ _absPos[0] = _absPos[1] = 0;
+ _size[0] = _size[1] = 0;
+
+ _minimumSize[0] = 0;
+ _minimumSize[1] = 0;
+
+ _zpos = 0;
+
+ _inset[0] = _inset[1] = _inset[2] = _inset[3] = 0;
+ _clipRect[0] = _clipRect[1] = _clipRect[2] = _clipRect[3] = 0;
+
+ _visible = true;
+ _enabled = true;
+ _clientPanel = NULL;
+ _parent = NULL;
+ _plat = NULL;
+ _popup = false;
+ _isTopmostPopup = false;
+ _hPanel = INVALID_PANEL;
+
+ _mouseInput = true; // by default you want mouse and kb input to this panel
+ _kbInput = true;
+
+ _pinsibling = NULL;
+ _pinsibling_my_corner = PIN_TOPLEFT;
+ _pinsibling_their_corner = PIN_TOPLEFT;
+
+ m_nThinkTraverseLevel = 0;
+ _clientPanelHandle = vgui::INVALID_PANEL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VPanel::~VPanel()
+{
+ // Someone just deleted their parent Panel while it was being used in InternalSolveTraverse().
+ // This will cause a difficult to debug crash, so we spew out the panel name here in hopes
+ // it will help track down the offender.
+ if ( m_nThinkTraverseLevel != 0 )
+ {
+ Warning( "Deleting in-use vpanel: %s/%s %p.\n", GetName(), GetClassName(), this );
+#ifdef STAGING_ONLY
+ DebuggerBreak();
+#endif
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::TraverseLevel( int val )
+{
+ // Bump up our traverse level.
+ m_nThinkTraverseLevel += m_nThinkTraverseLevel;
+
+ // Bump up our client panel traverse level.
+ if ( Client() )
+ {
+ VPANEL vp = g_pVGui->HandleToPanel( _clientPanelHandle );
+ if ( vp == vgui::INVALID_PANEL )
+ {
+ // This is really bad - we have a Client() pointer that is invalid.
+ Warning( "Panel '%s/%s' has invalid client: %p.\n", GetName(), GetClassName(), Client() );
+#ifdef STAGING_ONLY
+ DebuggerBreak();
+#endif
+ }
+
+ if ( Client()->GetVPanel() )
+ {
+ VPanel *vpanel = (VPanel *)Client()->GetVPanel();
+ vpanel->m_nThinkTraverseLevel += vpanel->m_nThinkTraverseLevel;
+ }
+ }
+
+ // This doesn't work. It appears we add all kinds of children to various panels in the
+ // InternalThinkTraverse functions, and that means the refcount is 0 when added, and
+ // then drops to -1 when we decrement the traverse level.
+#if 0
+ // Bump up our children traverse levels.
+ CUtlVector< VPanel * > &children = GetChildren();
+ for ( int i = 0; i < children.Count(); ++i )
+ {
+ VPanel *child = children[ i ];
+ if ( child )
+ child->m_nThinkTraverseLevel = Max( child->m_nThinkTraverseLevel + val, 0 );
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::Init(IClientPanel *attachedClientPanel)
+{
+ _clientPanel = attachedClientPanel;
+ _clientPanelHandle = g_pVGui->PanelToHandle( attachedClientPanel ? attachedClientPanel->GetVPanel() : 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::Solve()
+{
+ short basePos[2];
+ basePos[0] = _pos[0];
+ basePos[1] = _pos[1];
+
+ int baseSize[2];
+ GetSize( baseSize[0], baseSize[1] );
+
+ VPanel *parent = GetParent();
+ if (IsPopup())
+ {
+ // if we're a popup, draw at the highest level
+ parent = (VPanel *)g_pSurface->GetEmbeddedPanel();
+ }
+
+ int pabs[2];
+ if ( parent )
+ {
+ parent->GetAbsPos(pabs[0], pabs[1]);
+ }
+
+ if ( _pinsibling )
+ {
+ _pinsibling->Solve();
+
+ int sibPos[2];
+ int sibSize[2];
+ _pinsibling->GetInternalAbsPos( sibPos[0], sibPos[1] );
+ _pinsibling->GetSize( sibSize[0], sibSize[1] );
+
+ for ( int i = 0; i < 2; i++ )
+ {
+ if ( parent )
+ {
+ sibPos[i] -= pabs[i];
+ }
+
+ // Determine which direction positive values move in. For center pins, we use screen relative signs.
+ int iSign = 1;
+ if ( i == 0 && (_pinsibling_their_corner == PIN_CENTER_LEFT || _pinsibling_their_corner == PIN_TOPLEFT || _pinsibling_their_corner == PIN_BOTTOMLEFT) )
+ {
+ iSign = -1;
+ }
+ else if ( i == 1 && (_pinsibling_their_corner == PIN_CENTER_TOP || _pinsibling_their_corner == PIN_TOPLEFT || _pinsibling_their_corner == PIN_TOPRIGHT) )
+ {
+ iSign = -1;
+ }
+
+ int iPos = sibPos[i] + (sibSize[i] * PinDeltas[_pinsibling_their_corner][i]);
+ iPos -= (baseSize[i] * PinDeltas[_pinsibling_my_corner][i]);
+ iPos += basePos[i] * iSign;
+
+ basePos[i] = iPos;
+ }
+ }
+
+ int absX = basePos[0];
+ int absY = basePos[1];
+ _absPos[0] = basePos[0];
+ _absPos[1] = basePos[1];
+
+ // put into parent space
+ int pinset[4] = {0, 0, 0, 0};
+ if ( parent )
+ {
+ parent->GetInset( pinset[0], pinset[1], pinset[2], pinset[3] );
+
+ absX += pabs[0] + pinset[0];
+ absY += pabs[1] + pinset[1];
+
+ _absPos[0] = clamp( absX, -32767, 32767 );
+ _absPos[1] = clamp( absY, -32767, 32767 );
+ }
+
+ // set initial bounds
+ _clipRect[0] = _absPos[0];
+ _clipRect[1] = _absPos[1];
+
+ int absX2 = absX + baseSize[0];
+ int absY2 = absY + baseSize[1];
+ _clipRect[2] = clamp( absX2, -32767, 32767 );
+ _clipRect[3] = clamp( absY2, -32767, 32767 );
+
+ // clip to parent, if we're not a popup
+ if ( parent && !IsPopup() )
+ {
+ int pclip[4];
+ parent->GetClipRect(pclip[0], pclip[1], pclip[2], pclip[3]);
+
+ if (_clipRect[0] < pclip[0])
+ {
+ _clipRect[0] = pclip[0];
+ }
+
+ if (_clipRect[1] < pclip[1])
+ {
+ _clipRect[1] = pclip[1];
+ }
+
+ if(_clipRect[2] > pclip[2])
+ {
+ _clipRect[2] = pclip[2] - pinset[2];
+ }
+
+ if(_clipRect[3] > pclip[3])
+ {
+ _clipRect[3] = pclip[3] - pinset[3];
+ }
+
+ if ( _clipRect[0] > _clipRect[2] )
+ {
+ _clipRect[2] = _clipRect[0];
+ }
+
+ if ( _clipRect[1] > _clipRect[3] )
+ {
+ _clipRect[3] = _clipRect[1];
+ }
+ }
+
+ Assert( _clipRect[0] <= _clipRect[2] );
+ Assert( _clipRect[1] <= _clipRect[3] );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::SetPos(int x, int y)
+{
+ _pos[0] = x;
+ _pos[1] = y;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::GetPos(int &x, int &y)
+{
+ x = _pos[0];
+ y = _pos[1];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::SetSize(int wide,int tall)
+{
+ if (wide<_minimumSize[0])
+ {
+ wide=_minimumSize[0];
+ }
+ if (tall<_minimumSize[1])
+ {
+ tall=_minimumSize[1];
+ }
+
+ if (_size[0] == wide && _size[1] == tall)
+ return;
+
+ _size[0]=wide;
+ _size[1]=tall;
+
+ Client()->OnSizeChanged(wide, tall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::GetSize(int& wide,int& tall)
+{
+ wide=_size[0];
+ tall=_size[1];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::SetMinimumSize(int wide,int tall)
+{
+ _minimumSize[0]=wide;
+ _minimumSize[1]=tall;
+
+ // check if we're currently smaller than the new minimum size
+ int currentWidth = _size[0];
+ if (currentWidth < wide)
+ {
+ currentWidth = wide;
+ }
+ int currentHeight = _size[1];
+ if (currentHeight < tall)
+ {
+ currentHeight = tall;
+ }
+
+ // resize to new minimum size if necessary
+ if (currentWidth != _size[0] || currentHeight != _size[1])
+ {
+ SetSize(currentWidth, currentHeight);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::GetMinimumSize(int &wide, int &tall)
+{
+ wide = _minimumSize[0];
+ tall = _minimumSize[1];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::SetVisible(bool state)
+{
+ if (_visible == state)
+ return;
+
+ // need to tell the surface (in case special window processing needs to occur)
+ g_pSurface->SetPanelVisible((VPANEL)this, state);
+
+ _visible = state;
+
+ if( IsPopup() )
+ {
+ vgui::g_pSurface->CalculateMouseVisible();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::SetEnabled(bool state)
+{
+ _enabled = state;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool VPanel::IsVisible()
+{
+ return _visible;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool VPanel::IsEnabled()
+{
+ return _enabled;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::GetAbsPos(int &x, int &y)
+{
+ x = _absPos[0];
+ y = _absPos[1];
+
+ g_pSurface->OffsetAbsPos( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::GetInternalAbsPos(int &x, int &y)
+{
+ x = _absPos[0];
+ y = _absPos[1];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::GetClipRect(int &x0, int &y0, int &x1, int &y1)
+{
+ x0 = _clipRect[0];
+ y0 = _clipRect[1];
+ x1 = _clipRect[2];
+ y1 = _clipRect[3];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::SetInset(int left, int top, int right, int bottom)
+{
+ _inset[0] = left;
+ _inset[1] = top;
+ _inset[2] = right;
+ _inset[3] = bottom;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::GetInset(int &left, int &top, int &right, int &bottom)
+{
+ left = _inset[0];
+ top = _inset[1];
+ right = _inset[2];
+ bottom = _inset[3];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VPanel::SetParent(VPanel *newParent)
+{
+ if (this == newParent)
+ return;
+
+ if (_parent == newParent)
+ return;
+
+ if (_parent != NULL)
+ {
+ _parent->_childDar.RemoveElement(this);
+ _parent = null;
+ }
+
+ if (newParent != NULL)
+ {
+ _parent = newParent;
+ _parent->_childDar.PutElement(this);
+ SetZPos(_zpos); // re-sort parent's panel order if necessary
+ if (_parent->Client())
+ {
+ _parent->Client()->OnChildAdded((VPANEL)this);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int VPanel::GetChildCount()
+{
+ return _childDar.GetCount();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VPanel *VPanel::GetChild(int index)
+{
+ return _childDar[index];
+}
+
+CUtlVector< VPanel *> &VPanel::GetChildren()
+{
+ return _childDar;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VPanel *VPanel::GetParent()
+{
+ return _parent;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the Z position of a panel and reorders it appropriately
+//-----------------------------------------------------------------------------
+void VPanel::SetZPos(int z)
+{
+ _zpos = z;
+
+ if (_parent)
+ {
+ // find the child in the list
+ int childCount = _parent->GetChildCount();
+ int i;
+ for (i = 0; i < childCount; i++)
+ {
+ if (_parent->GetChild(i) == this)
+ break;
+ }
+
+ if (i == childCount)
+ return;
+
+ while (1)
+ {
+ VPanel *prevChild = NULL, *nextChild = NULL;
+
+ if ( i > 0 )
+ {
+ prevChild = _parent->GetChild( i - 1 );
+ }
+ if ( i <(childCount - 1) )
+ {
+ nextChild = _parent->GetChild( i + 1 );
+ }
+
+ // check either side of the child to see if it should move
+ if ( i > 0 && prevChild && ( prevChild->_zpos > _zpos ) )
+ {
+ // swap with the lower
+ _parent->_childDar.SetElementAt(prevChild, i);
+ _parent->_childDar.SetElementAt(this, i - 1);
+ i--;
+ }
+ else if (i < (childCount - 1) && nextChild && ( nextChild->_zpos < _zpos ) )
+ {
+ // swap with the higher
+ _parent->_childDar.SetElementAt(nextChild, i);
+ _parent->_childDar.SetElementAt(this, i + 1);
+ i++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the z position of this panel
+//-----------------------------------------------------------------------------
+int VPanel::GetZPos()
+{
+ return _zpos;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Moves the panel to the front of the z-order
+//-----------------------------------------------------------------------------
+void VPanel::MoveToFront(void)
+{
+ g_pSurface->MovePopupToFront((VPANEL)this);
+
+ if (_parent)
+ {
+ // move this panel to the end of it's parents list
+ _parent->_childDar.MoveElementToEnd(this);
+
+ // Validate the Z order
+ int i = _parent->_childDar.GetCount() - 2;
+ while (i >= 0)
+ {
+ if (_parent->_childDar[i]->_zpos > _zpos)
+ {
+ // we can't be in front of this; swap positions
+ _parent->_childDar.SetElementAt(_parent->_childDar[i], i + 1);
+ _parent->_childDar.SetElementAt(this, i);
+
+ // check the next value
+ i--;
+ }
+ else
+ {
+ // order valid
+ break;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Moves the panel to the back of the z-order
+//-----------------------------------------------------------------------------
+void VPanel::MoveToBack()
+{
+ if (_parent)
+ {
+ // move this panel to the end of it's parents list
+ _parent->_childDar.RemoveElement(this);
+ _parent->_childDar.InsertElementAt(this, 0);
+
+ // Validate the Z order
+ int i = 1;
+ while (i < _parent->_childDar.GetCount())
+ {
+ if (_parent->_childDar[i]->_zpos < _zpos)
+ {
+ // we can't be behind this; swap positions
+ _parent->_childDar.SetElementAt(_parent->_childDar[i], i - 1);
+ _parent->_childDar.SetElementAt(this, i);
+
+ // check the next value
+ i++;
+ }
+ else
+ {
+ // order valid
+ break;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Iterates up the hierarchy looking to see if a panel has the specified ancestor
+//-----------------------------------------------------------------------------
+bool VPanel::HasParent(VPanel *potentialParent)
+{
+ if (this == potentialParent)
+ return true;
+
+ if (_parent)
+ {
+ return _parent->HasParent(potentialParent);
+ }
+
+ return false;
+}
+
+SurfacePlat *VPanel::Plat()
+{
+ return _plat;
+}
+
+void VPanel::SetPlat(SurfacePlat *Plat)
+{
+ _plat = Plat;
+}
+
+bool VPanel::IsPopup()
+{
+ return _popup;
+}
+
+void VPanel::SetPopup(bool state)
+{
+ _popup = state;
+}
+
+bool VPanel::IsTopmostPopup() const
+{
+ return _isTopmostPopup;
+}
+
+void VPanel::SetTopmostPopup( bool bEnable )
+{
+ _isTopmostPopup = bEnable;
+}
+
+bool VPanel::IsFullyVisible()
+{
+ // recursively check to see if the panel and all it's parents are visible
+ VPanel *panel = this;
+ while (panel)
+ {
+ if (!panel->_visible)
+ {
+ return false;
+ }
+
+ panel = panel->_parent;
+ }
+
+ // we're visible all the way up the hierarchy
+ return true;
+}
+
+const char *VPanel::GetName()
+{
+ return Client()->GetName();
+}
+
+const char *VPanel::GetClassName()
+{
+ return Client()->GetClassName();
+}
+
+HScheme VPanel::GetScheme()
+{
+ return Client()->GetScheme();
+}
+
+
+void VPanel::SendMessage(KeyValues *params, VPANEL ifrompanel)
+{
+ Client()->OnMessage(params, ifrompanel);
+}
+
+
+void VPanel::SetKeyBoardInputEnabled(bool state)
+{
+ _kbInput = state;
+}
+
+void VPanel::SetMouseInputEnabled(bool state)
+{
+ _mouseInput = state;
+}
+
+bool VPanel::IsKeyBoardInputEnabled()
+{
+ return _kbInput;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool VPanel::IsMouseInputEnabled()
+{
+ return _mouseInput;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sibling pins
+//-----------------------------------------------------------------------------
+void VPanel::SetSiblingPin(VPanel *newSibling, byte iMyCornerToPin, byte iSiblingCornerToPinTo )
+{
+ _pinsibling = newSibling;
+ _pinsibling_my_corner = iMyCornerToPin;
+ _pinsibling_their_corner = iSiblingCornerToPinTo;
+}
diff --git a/vgui2/src/VPanel.h b/vgui2/src/VPanel.h
new file mode 100644
index 0000000..754fcfd
--- /dev/null
+++ b/vgui2/src/VPanel.h
@@ -0,0 +1,146 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef VPANEL_H
+#define VPANEL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/Dar.h>
+#include <vgui/IPanel.h>
+
+#ifdef GetClassName
+#undef GetClassName
+#endif
+
+namespace vgui
+{
+
+ class SurfaceBase;
+ class IClientPanel;
+ struct SerialPanel_t;
+
+ //-----------------------------------------------------------------------------
+ // Purpose: VGUI private implementation of panel
+ //-----------------------------------------------------------------------------
+ class VPanel
+ {
+ public:
+ VPanel();
+ virtual ~VPanel();
+
+ virtual void Init(IClientPanel *attachedClientPanel);
+
+ virtual SurfacePlat *Plat();
+ virtual void SetPlat(SurfacePlat *pl);
+
+ virtual HPanel GetHPanel() { return _hPanel; } // safe pointer handling
+ virtual void SetHPanel(HPanel hPanel) { _hPanel = hPanel; }
+
+ virtual bool IsPopup();
+ virtual void SetPopup(bool state);
+ virtual bool IsFullyVisible();
+
+ virtual void SetPos(int x, int y);
+ virtual void GetPos(int &x, int &y);
+ virtual void SetSize(int wide,int tall);
+ virtual void GetSize(int& wide,int& tall);
+ virtual void SetMinimumSize(int wide,int tall);
+ virtual void GetMinimumSize(int& wide,int& tall);
+ virtual void SetZPos(int z);
+ virtual int GetZPos();
+
+ virtual void GetAbsPos(int &x, int &y);
+ virtual void GetClipRect(int &x0, int &y0, int &x1, int &y1);
+ virtual void SetInset(int left, int top, int right, int bottom);
+ virtual void GetInset(int &left, int &top, int &right, int &bottom);
+
+ virtual void Solve();
+
+ virtual void SetVisible(bool state);
+ virtual void SetEnabled(bool state);
+ virtual bool IsVisible();
+ virtual bool IsEnabled();
+ virtual void SetParent(VPanel *newParent);
+ virtual int GetChildCount();
+ virtual VPanel *GetChild(int index);
+ virtual VPanel *GetParent();
+ virtual void MoveToFront();
+ virtual void MoveToBack();
+ virtual bool HasParent(VPanel *potentialParent);
+
+ virtual CUtlVector< VPanel * > &GetChildren();
+
+ // gets names of the object (for debugging purposes)
+ virtual const char *GetName();
+ virtual const char *GetClassName();
+
+ virtual HScheme GetScheme();
+
+ // handles a message
+ virtual void SendMessage(KeyValues *params, VPANEL ifromPanel);
+
+ // wrapper to get Client panel interface
+ virtual IClientPanel *Client() { return _clientPanel; }
+
+ // input interest
+ virtual void SetKeyBoardInputEnabled(bool state);
+ virtual void SetMouseInputEnabled(bool state);
+ virtual bool IsKeyBoardInputEnabled();
+ virtual bool IsMouseInputEnabled();
+
+ virtual bool IsTopmostPopup() const;
+ virtual void SetTopmostPopup( bool bEnable );
+
+ // sibling pins
+ virtual void SetSiblingPin(VPanel *newSibling, byte iMyCornerToPin = 0, byte iSiblingCornerToPinTo = 0 );
+
+ public:
+ virtual void GetInternalAbsPos(int &x, int &y);
+ virtual void TraverseLevel( int val );
+
+ private:
+ Dar<VPanel*> _childDar;
+ VPanel *_parent;
+ SurfacePlat *_plat; // platform-specific data
+ HPanel _hPanel;
+
+ // our companion Client panel
+ IClientPanel *_clientPanel;
+
+ short _pos[2];
+ short _size[2];
+ short _minimumSize[2];
+
+ short _inset[4];
+ short _clipRect[4];
+ short _absPos[2];
+
+ short _zpos; // z-order position
+
+ bool _visible : 1;
+ bool _enabled : 1;
+ bool _popup : 1;
+ bool _mouseInput : 1; // used for popups
+ bool _kbInput : 1;
+ bool _isTopmostPopup : 1;
+
+ VPanel *_pinsibling;
+ byte _pinsibling_my_corner;
+ byte _pinsibling_their_corner;
+
+ int m_nMessageContextId;
+ int m_nThinkTraverseLevel;
+ HPanel _clientPanelHandle; // Temp to check if _clientPanel is valid.
+ };
+
+}
+
+
+#endif // VPANEL_H
diff --git a/vgui2/src/VPanelWrapper.cpp b/vgui2/src/VPanelWrapper.cpp
new file mode 100644
index 0000000..d733e8c
--- /dev/null
+++ b/vgui2/src/VPanelWrapper.cpp
@@ -0,0 +1,362 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <assert.h>
+
+#include "VPanel.h"
+#include "vgui_internal.h"
+
+#include <vgui/IClientPanel.h>
+#include <vgui/IPanel.h>
+#include <vgui/ISurface.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Protects internal VPanel through the versionable interface IPanel
+//-----------------------------------------------------------------------------
+class VPanelWrapper : public vgui::IPanel
+{
+public:
+ virtual void Init(VPANEL vguiPanel, IClientPanel *panel)
+ {
+ ((VPanel *)vguiPanel)->Init(panel);
+ }
+
+ // returns a pointer to the Client panel
+ virtual IClientPanel *Client(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->Client();
+ }
+
+ // methods
+ virtual void SetPos(VPANEL vguiPanel, int x, int y)
+ {
+ ((VPanel *)vguiPanel)->SetPos(x, y);
+ }
+
+ virtual void GetPos(VPANEL vguiPanel, int &x, int &y)
+ {
+ ((VPanel *)vguiPanel)->GetPos(x, y);
+ }
+
+ virtual void SetSize(VPANEL vguiPanel, int wide,int tall)
+ {
+ ((VPanel *)vguiPanel)->SetSize(wide, tall);
+ }
+
+ virtual void GetSize(VPANEL vguiPanel, int &wide, int &tall)
+ {
+ ((VPanel *)vguiPanel)->GetSize(wide, tall);
+ }
+
+ virtual void SetMinimumSize(VPANEL vguiPanel, int wide, int tall)
+ {
+ ((VPanel *)vguiPanel)->SetMinimumSize(wide, tall);
+ }
+
+ virtual void GetMinimumSize(VPANEL vguiPanel, int &wide, int &tall)
+ {
+ ((VPanel *)vguiPanel)->GetMinimumSize(wide, tall);
+ }
+
+ virtual void SetZPos(VPANEL vguiPanel, int z)
+ {
+ ((VPanel *)vguiPanel)->SetZPos(z);
+ }
+
+ virtual int GetZPos(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->GetZPos();
+ }
+
+ virtual void GetAbsPos(VPANEL vguiPanel, int &x, int &y)
+ {
+ ((VPanel *)vguiPanel)->GetAbsPos(x, y);
+ }
+
+ virtual void GetClipRect(VPANEL vguiPanel, int &x0, int &y0, int &x1, int &y1)
+ {
+ ((VPanel *)vguiPanel)->GetClipRect(x0, y0, x1, y1);
+ }
+
+ virtual void SetInset(VPANEL vguiPanel, int left, int top, int right, int bottom)
+ {
+ ((VPanel *)vguiPanel)->SetInset(left, top, right, bottom);
+ }
+
+ virtual void GetInset(VPANEL vguiPanel, int &left, int &top, int &right, int &bottom)
+ {
+ ((VPanel *)vguiPanel)->GetInset(left, top, right, bottom);
+ }
+
+ virtual void SetVisible(VPANEL vguiPanel, bool state)
+ {
+ ((VPanel *)vguiPanel)->SetVisible(state);
+ }
+
+ virtual void SetEnabled(VPANEL vguiPanel, bool state)
+ {
+ ((VPanel *)vguiPanel)->SetEnabled(state);
+ }
+
+ virtual bool IsVisible(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->IsVisible();
+ }
+
+ virtual bool IsEnabled(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->IsEnabled();
+ }
+
+ // Used by the drag/drop manager to always draw on top
+ virtual bool IsTopmostPopup( VPANEL vguiPanel )
+ {
+ return ((VPanel *)vguiPanel)->IsTopmostPopup();
+ }
+
+ virtual void SetTopmostPopup( VPANEL vguiPanel, bool state )
+ {
+ return ((VPanel *)vguiPanel)->SetTopmostPopup( state );
+ }
+
+ virtual void SetParent(VPANEL vguiPanel, VPANEL newParent)
+ {
+ ((VPanel *)vguiPanel)->SetParent((VPanel *)newParent);
+ }
+
+ virtual int GetChildCount(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->GetChildCount();
+ }
+
+ virtual VPANEL GetChild(VPANEL vguiPanel, int index)
+ {
+ return (VPANEL)((VPanel *)vguiPanel)->GetChild(index);
+ }
+
+ virtual CUtlVector< VPANEL > &GetChildren( VPANEL vguiPanel )
+ {
+ return (CUtlVector< VPANEL > &)((VPanel *)vguiPanel)->GetChildren();
+ }
+
+ virtual VPANEL GetParent(VPANEL vguiPanel)
+ {
+ return (VPANEL)((VPanel *)vguiPanel)->GetParent();
+ }
+
+ virtual void MoveToFront(VPANEL vguiPanel)
+ {
+ ((VPanel *)vguiPanel)->MoveToFront();
+ }
+
+ virtual void MoveToBack(VPANEL vguiPanel)
+ {
+ ((VPanel *)vguiPanel)->MoveToBack();
+ }
+
+ virtual bool HasParent(VPANEL vguiPanel, VPANEL potentialParent)
+ {
+ if (!vguiPanel)
+ return false;
+
+ return ((VPanel *)vguiPanel)->HasParent((VPanel *)potentialParent);
+ }
+
+ virtual bool IsPopup(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->IsPopup();
+ }
+
+ virtual void SetPopup(VPANEL vguiPanel, bool state)
+ {
+ ((VPanel *)vguiPanel)->SetPopup(state);
+ }
+
+ virtual bool IsFullyVisible( VPANEL vguiPanel )
+ {
+ return ((VPanel *)vguiPanel)->IsFullyVisible();
+ }
+
+ // calculates the panels current position within the hierarchy
+ virtual void Solve(VPANEL vguiPanel)
+ {
+ ((VPanel *)vguiPanel)->Solve();
+ }
+
+ // used by ISurface to store platform-specific data
+ virtual SurfacePlat *Plat(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->Plat();
+ }
+
+ virtual void SetPlat(VPANEL vguiPanel, SurfacePlat *Plat)
+ {
+ ((VPanel *)vguiPanel)->SetPlat(Plat);
+ }
+
+ virtual const char *GetName(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->GetName();
+ }
+
+ virtual const char *GetClassName(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->GetClassName();
+ }
+
+ virtual HScheme GetScheme(VPANEL vguiPanel)
+ {
+ return ((VPanel *)vguiPanel)->GetScheme();
+ }
+
+ virtual bool IsProportional(VPANEL vguiPanel)
+ {
+ return Client(vguiPanel)->IsProportional();
+ }
+
+ virtual bool IsAutoDeleteSet(VPANEL vguiPanel)
+ {
+ return Client(vguiPanel)->IsAutoDeleteSet();
+ }
+
+ virtual void DeletePanel(VPANEL vguiPanel)
+ {
+ Client(vguiPanel)->DeletePanel();
+ }
+
+ virtual void SendMessage(VPANEL vguiPanel, KeyValues *params, VPANEL ifrompanel)
+ {
+ ((VPanel *)vguiPanel)->SendMessage(params, ifrompanel);
+ }
+
+ virtual void Think(VPANEL vguiPanel)
+ {
+ Client(vguiPanel)->Think();
+ }
+
+ virtual void PerformApplySchemeSettings(VPANEL vguiPanel)
+ {
+ Client(vguiPanel)->PerformApplySchemeSettings();
+ }
+
+ virtual void PaintTraverse(VPANEL vguiPanel, bool forceRepaint, bool allowForce)
+ {
+ Client(vguiPanel)->PaintTraverse(forceRepaint, allowForce);
+ }
+
+ virtual void Repaint(VPANEL vguiPanel)
+ {
+ Client(vguiPanel)->Repaint();
+ }
+
+ virtual VPANEL IsWithinTraverse(VPANEL vguiPanel, int x, int y, bool traversePopups)
+ {
+ return Client(vguiPanel)->IsWithinTraverse(x, y, traversePopups);
+ }
+
+ virtual void OnChildAdded(VPANEL vguiPanel, VPANEL child)
+ {
+ Client(vguiPanel)->OnChildAdded(child);
+ }
+
+ virtual void OnSizeChanged(VPANEL vguiPanel, int newWide, int newTall)
+ {
+ Client(vguiPanel)->OnSizeChanged(newWide, newTall);
+ }
+
+ virtual void InternalFocusChanged(VPANEL vguiPanel, bool lost)
+ {
+ Client(vguiPanel)->InternalFocusChanged(lost);
+ }
+
+ virtual bool RequestInfo(VPANEL vguiPanel, KeyValues *outputData)
+ {
+ return Client(vguiPanel)->RequestInfo(outputData);
+ }
+
+ virtual void RequestFocus(VPANEL vguiPanel, int direction = 0)
+ {
+ Client(vguiPanel)->RequestFocus(direction);
+ }
+
+ virtual bool RequestFocusPrev(VPANEL vguiPanel, VPANEL existingPanel)
+ {
+ return Client(vguiPanel)->RequestFocusPrev(existingPanel);
+ }
+
+ virtual bool RequestFocusNext(VPANEL vguiPanel, VPANEL existingPanel)
+ {
+ return Client(vguiPanel)->RequestFocusNext(existingPanel);
+ }
+
+ virtual VPANEL GetCurrentKeyFocus(VPANEL vguiPanel)
+ {
+ return Client(vguiPanel)->GetCurrentKeyFocus();
+ }
+
+ virtual int GetTabPosition(VPANEL vguiPanel)
+ {
+ return Client(vguiPanel)->GetTabPosition();
+ }
+
+ virtual Panel *GetPanel(VPANEL vguiPanel, const char *moduleName)
+ {
+ if (!vguiPanel)
+ return NULL;
+
+ if (vguiPanel == g_pSurface->GetEmbeddedPanel())
+ return NULL;
+
+ // assert that the specified vpanel is from the same module as requesting the cast
+ if ( !vguiPanel || V_stricmp(GetModuleName(vguiPanel), moduleName) )
+ {
+ // assert(!("GetPanel() used to retrieve a Panel * from a different dll than which which it was created. This is bad, you can't pass Panel * across dll boundaries else you'll break the versioning. Please only use a VPANEL."));
+ // this is valid for now
+ return NULL;
+ }
+ return Client(vguiPanel)->GetPanel();
+ }
+
+ virtual const char *GetModuleName(VPANEL vguiPanel)
+ {
+ return Client(vguiPanel)->GetModuleName();
+ }
+
+ virtual void SetKeyBoardInputEnabled( VPANEL vguiPanel, bool state )
+ {
+ ((VPanel *)vguiPanel)->SetKeyBoardInputEnabled(state);
+ }
+
+ virtual void SetMouseInputEnabled( VPANEL vguiPanel, bool state )
+ {
+ ((VPanel *)vguiPanel)->SetMouseInputEnabled(state);
+ }
+
+ virtual bool IsMouseInputEnabled( VPANEL vguiPanel )
+ {
+ return ((VPanel *)vguiPanel)->IsMouseInputEnabled();
+ }
+
+ virtual bool IsKeyBoardInputEnabled( VPANEL vguiPanel )
+ {
+ return ((VPanel *)vguiPanel)->IsKeyBoardInputEnabled();
+ }
+
+ virtual void SetSiblingPin(VPANEL vguiPanel, VPANEL newSibling, byte iMyCornerToPin = 0, byte iSiblingCornerToPinTo = 0 )
+ {
+ return ((VPanel *)vguiPanel)->SetSiblingPin( (VPanel *)newSibling, iMyCornerToPin, iSiblingCornerToPinTo );
+ }
+
+};
+
+EXPOSE_SINGLE_INTERFACE(VPanelWrapper, IPanel, VGUI_PANEL_INTERFACE_VERSION);
+
diff --git a/vgui2/src/bitmap.h b/vgui2/src/bitmap.h
new file mode 100644
index 0000000..f75275d
--- /dev/null
+++ b/vgui2/src/bitmap.h
@@ -0,0 +1,64 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BITMAP_H
+#define BITMAP_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/IImage.h>
+#include <Color.h>
+
+namespace vgui
+{
+
+//-----------------------------------------------------------------------------
+// Purpose: Holds a single image, internal to vgui only
+//-----------------------------------------------------------------------------
+class Bitmap : public IImage
+{
+public:
+ Bitmap( const char *filename, bool hardwareFiltered );
+ ~Bitmap();
+
+ // IImage implementation
+ virtual void Paint();
+ virtual void GetSize( int &wide, int &tall );
+ virtual void GetContentSize( int &wide, int &tall );
+ virtual void SetSize( int x, int y );
+ virtual void SetPos( int x, int y );
+ virtual void SetColor( Color col );
+ virtual bool Evict();
+ virtual int GetNumFrames();
+ virtual void SetFrame( int nFrame );
+ virtual HTexture GetID(); // returns the texture id
+ virtual void SetRotation( int iRotation ) { _rotation = iRotation; }
+
+ // methods
+ void ForceUpload(); // ensures the bitmap has been uploaded
+ const char *GetName();
+ bool IsValid() { return _valid; }
+
+private:
+ HTexture _id;
+ bool _uploaded;
+ bool _valid;
+ char *_filename;
+ int _pos[2];
+ Color _color;
+ bool _filtered;
+ int _wide,_tall;
+ bool _bProcedural;
+ unsigned int nFrameCache;
+ int _rotation;
+};
+
+} // namespace vgui
+
+#endif // BITMAP_H
diff --git a/vgui2/src/fileimage.cpp b/vgui2/src/fileimage.cpp
new file mode 100644
index 0000000..b28c50a
--- /dev/null
+++ b/vgui2/src/fileimage.cpp
@@ -0,0 +1,211 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include <string.h>
+#include "fileimage.h"
+
+#include "winlite.h"
+#include "vgui_internal.h"
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// TGA header.
+#pragma pack(1)
+ class TGAFileHeader
+ {
+ public:
+ unsigned char m_IDLength;
+ unsigned char m_ColorMapType;
+ unsigned char m_ImageType;
+ unsigned short m_CMapStart;
+ unsigned short m_CMapLength;
+ unsigned char m_CMapDepth;
+ unsigned short m_XOffset;
+ unsigned short m_YOffset;
+ unsigned short m_Width;
+ unsigned short m_Height;
+ unsigned char m_PixelDepth;
+ unsigned char m_ImageDescriptor;
+ };
+#pragma pack()
+
+
+
+// ---------------------------------------------------------------------------------------- //
+// FileImageStream_Memory.
+// ---------------------------------------------------------------------------------------- //
+FileImageStream_Memory::FileImageStream_Memory(void *pData, int dataLen)
+{
+ m_pData = (unsigned char*)pData;
+ m_DataLen = dataLen;
+ m_CurPos = 0;
+ m_bError = false;
+}
+
+void FileImageStream_Memory::Read(void *pData, int len)
+{
+ unsigned char *pOut;
+ int i;
+
+ pOut = (unsigned char*)pData;
+ for(i=0; i < len; i++)
+ {
+ if(m_CurPos < m_DataLen)
+ {
+ pOut[i] = m_pData[m_CurPos];
+ ++m_CurPos;
+ }
+ else
+ {
+ pOut[i] = 0;
+ m_bError = true;
+ }
+ }
+}
+
+bool FileImageStream_Memory::ErrorStatus()
+{
+ bool ret=m_bError;
+ m_bError=false;
+ return ret;
+}
+
+
+
+// ---------------------------------------------------------------------------------------- //
+// Encode/decode functions.
+// ---------------------------------------------------------------------------------------- //
+static void WriteRun(unsigned char *pColor, FileHandle_t fp, int runLength)
+{
+ unsigned char runCount;
+
+ runCount = runLength - 1;
+ runCount |= (1 << 7);
+ g_pFullFileSystem->Write( &runCount, 1, fp );
+ g_pFullFileSystem->Write( pColor, 4, fp );
+}
+
+
+// Load in a 32-bit TGA file.
+bool Load32BitTGA(
+ FileImageStream *fp,
+ FileImage *pImage)
+{
+ TGAFileHeader hdr;
+ char dummyChar;
+ int i, x, y;
+ long color;
+ int runLength, curOut;
+ unsigned char *pLine;
+ unsigned char packetHeader;
+
+
+ pImage->Term();
+
+ // Read and verify the header.
+ fp->Read(&hdr, sizeof(hdr));
+ if(hdr.m_PixelDepth != 32 || hdr.m_ImageType != 10)
+ return false;
+
+ // Skip the ID area..
+ for(i=0; i < hdr.m_IDLength; i++)
+ fp->Read(&dummyChar, 1);
+
+ pImage->m_Width = hdr.m_Width;
+ pImage->m_Height = hdr.m_Height;
+ pImage->m_pData = new unsigned char[hdr.m_Width * hdr.m_Height * 4];
+ if(!pImage->m_pData)
+ return false;
+
+ // Read in the data..
+ for(y=pImage->m_Height-1; y >= 0; y--)
+ {
+ pLine = &pImage->m_pData[y*pImage->m_Width*4];
+
+ curOut = 0;
+ while(curOut < pImage->m_Width)
+ {
+ fp->Read(&packetHeader, 1);
+
+ runLength = (int)(packetHeader & ~(1 << 7)) + 1;
+ if(curOut + runLength > pImage->m_Width)
+ return false;
+
+ if(packetHeader & (1 << 7))
+ {
+ fp->Read(&color, 4);
+ for(x=0; x < runLength; x++)
+ {
+ *((long*)pLine) = color;
+ pLine += 4;
+ }
+ }
+ else
+ {
+ for(x=0; x < runLength; x++)
+ {
+ fp->Read(&color, 4);
+ *((long*)pLine) = color;
+ pLine += 4;
+ }
+ }
+
+ curOut += runLength;
+ }
+ }
+
+ return true;
+}
+
+
+// Write a 32-bit TGA file.
+void Save32BitTGA(
+ FileHandle_t fp,
+ FileImage *pImage)
+{
+ TGAFileHeader hdr;
+ int y, runStart, x;
+ unsigned char *pLine;
+
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.m_PixelDepth = 32;
+ hdr.m_ImageType = 10; // Run-length encoded RGB.
+ hdr.m_Width = pImage->m_Width;
+ hdr.m_Height = pImage->m_Height;
+
+ g_pFullFileSystem->Write(&hdr, sizeof(hdr), fp );
+
+ // Lines are written bottom-up.
+ for(y=pImage->m_Height-1; y >= 0; y--)
+ {
+ pLine = &pImage->m_pData[y*pImage->m_Width*4];
+
+ runStart = 0;
+ for(x=0; x < pImage->m_Width; x++)
+ {
+ if((x - runStart) >= 128 ||
+ *((long*)&pLine[runStart*4]) != *((long*)&pLine[x*4]))
+ {
+ // Encode this Run.
+ WriteRun(&pLine[runStart*4], fp, x - runStart);
+ runStart = x;
+ }
+ }
+
+ // Encode the last Run.
+ if(x - runStart > 0)
+ {
+ WriteRun(&pLine[runStart*4], fp, x - runStart);
+ }
+ }
+}
+
+
diff --git a/vgui2/src/fileimage.h b/vgui2/src/fileimage.h
new file mode 100644
index 0000000..182f0d5
--- /dev/null
+++ b/vgui2/src/fileimage.h
@@ -0,0 +1,95 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef __FILEIMAGE_H__
+#define __FILEIMAGE_H__
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <stdio.h>
+
+typedef void *FileHandle_t;
+
+class FileImageStream
+{
+public:
+ virtual void Read(void *pOut, int len)=0;
+
+ // Returns true if there were any Read errors.
+ // Clears error status.
+ virtual bool ErrorStatus()=0;
+};
+
+
+// Use to read out of a memory buffer..
+class FileImageStream_Memory : public FileImageStream
+{
+public:
+ FileImageStream_Memory(void *pData, int dataLen);
+
+ virtual void Read(void *pOut, int len);
+ virtual bool ErrorStatus();
+
+
+private:
+ unsigned char *m_pData;
+ int m_DataLen;
+ int m_CurPos;
+ bool m_bError;
+};
+
+
+
+// Generic image representation..
+class FileImage
+{
+public:
+ FileImage()
+ {
+ Clear();
+ }
+
+ ~FileImage()
+ {
+ Term();
+ }
+
+ void Term()
+ {
+ if(m_pData)
+ delete [] m_pData;
+
+ Clear();
+ }
+
+ // Clear the structure without deallocating.
+ void Clear()
+ {
+ m_Width = m_Height = 0;
+ m_pData = NULL;
+ }
+
+ int m_Width, m_Height;
+ unsigned char *m_pData;
+};
+
+
+// Functions to load/save FileImages.
+bool Load32BitTGA(
+ FileImageStream *fp,
+ FileImage *pImage);
+
+void Save32BitTGA(
+ FileHandle_t fp,
+ FileImage *pImage);
+
+
+#endif
+
+
diff --git a/vgui2/src/keyrepeat.cpp b/vgui2/src/keyrepeat.cpp
new file mode 100644
index 0000000..db129e6
--- /dev/null
+++ b/vgui2/src/keyrepeat.cpp
@@ -0,0 +1,177 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "inputsystem/InputEnums.h"
+
+#include "vgui/KeyCode.h"
+#include "vgui/keyrepeat.h"
+#include "tier0/dbg.h"
+
+// memdbgon must be the last include file in a .cpp file
+#include "tier0/memdbgon.h"
+
+//#define DEBUG_REPEATS
+
+#ifdef DEBUG_REPEATS
+#define DbgRepeat(...) ConMsg( __VA_ARGS__ )
+#else
+#define DbgRepeat(...)
+#endif
+
+using namespace vgui;
+
+vgui::KeyCode g_iCodesForAliases[FM_NUM_KEYREPEAT_ALIASES] =
+{
+ KEY_XBUTTON_UP,
+ KEY_XBUTTON_DOWN,
+ KEY_XBUTTON_LEFT,
+ KEY_XBUTTON_RIGHT
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Map joystick codes to our internal ones
+//-----------------------------------------------------------------------------
+static int GetIndexForCode( vgui::KeyCode code )
+{
+ KeyCode localCode = GetBaseButtonCode( code );
+
+ switch ( localCode )
+ {
+ case KEY_XBUTTON_DOWN:
+ case KEY_XSTICK1_DOWN:
+ case KEY_XSTICK2_DOWN:
+ return KR_ALIAS_DOWN; break;
+ case KEY_XBUTTON_UP:
+ case KEY_XSTICK1_UP:
+ case KEY_XSTICK2_UP:
+ return KR_ALIAS_UP; break;
+ case KEY_XBUTTON_LEFT:
+ case KEY_XSTICK1_LEFT:
+ case KEY_XSTICK2_LEFT:
+ return KR_ALIAS_LEFT; break;
+ case KEY_XBUTTON_RIGHT:
+ case KEY_XSTICK1_RIGHT:
+ case KEY_XSTICK2_RIGHT:
+ return KR_ALIAS_RIGHT; break;
+ default:
+ break;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+CKeyRepeatHandler::CKeyRepeatHandler()
+{
+ Reset();
+ for ( int i = 0; i < FM_NUM_KEYREPEAT_ALIASES; i++ )
+ {
+ m_flRepeatTimes[i] = 0.16;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear all state
+//-----------------------------------------------------------------------------
+void CKeyRepeatHandler::Reset()
+{
+ DbgRepeat( "KeyRepeat: Reset\n" );
+
+ memset( m_bAliasDown, 0, sizeof( m_bAliasDown ) );
+ m_bHaveKeyDown = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CKeyRepeatHandler::KeyDown( vgui::KeyCode code )
+{
+ int joyStick = GetJoystickForCode( code );
+ int iIndex = GetIndexForCode(code);
+ if ( iIndex == -1 )
+ return;
+
+ if ( m_bAliasDown[ joyStick ][ iIndex ] )
+ return;
+
+ DbgRepeat( "KeyRepeat: KeyDown %d(%d)\n", joyStick, iIndex );
+
+ Reset();
+ m_bAliasDown[ joyStick ][ iIndex ] = true;
+ m_flNextKeyRepeat[ joyStick ] = Plat_FloatTime() + 0.4;
+ m_bHaveKeyDown = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CKeyRepeatHandler::KeyUp( vgui::KeyCode code )
+{
+ int joyStick = GetJoystickForCode( code );
+ int iIndex = GetIndexForCode(code);
+ if ( iIndex == -1 )
+ return;
+
+ DbgRepeat( "KeyRepeat: KeyUp %d(%d)\n", joyStick, iIndex );
+
+ m_bAliasDown[ joyStick ][ iIndex ] = false;
+
+ m_bHaveKeyDown = false;
+ for ( int i = 0; i < FM_NUM_KEYREPEAT_ALIASES; i++ )
+ {
+ for ( int j = 0; j < MAX_JOYSTICKS; j++ )
+ {
+ if ( m_bAliasDown[ j ][ i ] )
+ {
+ m_bHaveKeyDown = true;
+ break;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+vgui::KeyCode CKeyRepeatHandler::KeyRepeated( void )
+{
+ if ( IsPC() )
+ return BUTTON_CODE_NONE;
+
+ if ( !m_bHaveKeyDown )
+ return BUTTON_CODE_NONE;
+
+ float currentTime = Plat_FloatTime();
+
+ for ( int j = 0; j < MAX_JOYSTICKS; j++ )
+ {
+ if ( m_flNextKeyRepeat[ j ] < currentTime )
+ {
+ for ( int i = 0; i < FM_NUM_KEYREPEAT_ALIASES; i++ )
+ {
+ if ( m_bAliasDown[ j ][ i ] )
+ {
+ m_flNextKeyRepeat[ j ] = currentTime + m_flRepeatTimes[i];
+ DbgRepeat( "KeyRepeat: Repeat %d(%d)\n", j, i );
+
+ return ButtonCodeToJoystickButtonCode( g_iCodesForAliases[i], j );
+ }
+ }
+ }
+ }
+
+ return BUTTON_CODE_NONE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CKeyRepeatHandler::SetKeyRepeatTime( vgui::KeyCode code, float flRepeat )
+{
+ int iIndex = GetIndexForCode(code);
+ Assert( iIndex != -1 );
+ m_flRepeatTimes[ iIndex ] = flRepeat;
+}
diff --git a/vgui2/src/system_posix.cpp b/vgui2/src/system_posix.cpp
new file mode 100644
index 0000000..251cbb2
--- /dev/null
+++ b/vgui2/src/system_posix.cpp
@@ -0,0 +1,809 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <vgui/VGUI.h>
+#include <vgui/ISystem.h>
+#include <KeyValues.h>
+#include <vgui/IInputInternal.h>
+#include <vgui/ISurface.h>
+#include "tier0/vcrmode.h"
+#include "tier1/fmtstr.h"
+#include "filesystem.h"
+
+#include "vgui_internal.h"
+#include "filesystem_helpers.h"
+#include "vgui_key_translation.h"
+#include "filesystem.h"
+
+#ifdef OSX
+#include <Carbon/Carbon.h>
+#elif defined(LINUX)
+#include <sys/vfs.h>
+#endif
+
+#ifdef USE_SDL
+#include "SDL_clipboard.h"
+#include "SDL_error.h"
+#endif
+
+#define PROTECTED_THINGS_DISABLE
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+uint16 System_GetKeyState( int virtualKeyCode )
+{
+#ifndef _XBOX
+ return g_pVCR->Hook_GetKeyState(virtualKeyCode);
+#else
+ return 0;
+#endif
+}
+
+class CSystem : public ISystem
+{
+public:
+ CSystem();
+ ~CSystem();
+
+ virtual void Shutdown();
+ virtual void RunFrame();
+
+ virtual long GetTimeMillis();
+
+ // returns the time at the start of the frame
+ virtual double GetFrameTime();
+
+ // returns the current time
+ virtual double GetCurrentTime();
+
+ virtual void ShellExecute(const char *command, const char *file);
+
+ virtual int GetClipboardTextCount();
+ virtual void SetClipboardText(const char *text, int textLen);
+ virtual void SetClipboardText(const wchar_t *text, int textLen);
+ virtual int GetClipboardText(int offset, char *buf, int bufLen);
+ virtual int GetClipboardText(int offset, wchar_t *buf, int bufLen);
+
+ virtual void SetClipboardImage( void *pWnd, int x1, int y1, int x2, int y2 );
+
+ virtual bool SetRegistryString(const char *key, const char *value);
+ virtual bool GetRegistryString(const char *key, char *value, int valueLen);
+ virtual bool SetRegistryInteger(const char *key, int value);
+ virtual bool GetRegistryInteger(const char *key, int &value);
+ virtual bool DeleteRegistryKey(const char *keyName);
+
+ virtual bool SetWatchForComputerUse(bool state);
+ virtual double GetTimeSinceLastUse();
+ virtual int GetAvailableDrives(char *buf, int bufLen);
+ virtual double GetFreeDiskSpace(const char *path);
+
+ virtual KeyValues *GetUserConfigFileData(const char *dialogName, int dialogID);
+ virtual void SetUserConfigFile(const char *fileName, const char *pathName);
+ virtual void SaveUserConfigFile();
+
+ virtual bool CommandLineParamExists(const char *commandName);
+ virtual bool GetCommandLineParamValue(const char *paramName, char *value, int valueBufferSize);
+ virtual const char *GetFullCommandLine();
+ virtual bool GetCurrentTimeAndDate(int *year, int *month, int *dayOfWeek, int *day, int *hour, int *minute, int *second);
+
+ // shortcut (.lnk) modification functions
+ virtual bool CreateShortcut(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory, const char *iconFile);
+ virtual bool GetShortcutTarget(const char *linkFileName, char *targetPath, char *arguments, int destBufferSizes);
+ virtual bool ModifyShortcutTarget(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory);
+
+ virtual KeyCode KeyCode_VirtualKeyToVGUI( int keyCode );
+ virtual int KeyCode_VGUIToVirtualKey( KeyCode keyCode );
+// virtual MouseCode MouseCode_VirtualKeyToVGUI( int keyCode );
+// virtual int MouseCode_VGUIToVirtualKey( MouseCode keyCode );
+ virtual const char *GetDesktopFolderPath();
+ virtual const char *GetStartMenuFolderPath();
+ virtual const char *GetAllUserDesktopFolderPath();
+ virtual const char *GetAllUserStartMenuFolderPath();
+
+ virtual void ShellExecuteEx( const char *command, const char *file, const char *pParams );
+#ifdef DBGFLAG_VALIDATE
+ virtual void Validate( CValidator &validator, char *pchName );
+#endif
+
+private:
+ void SaveRegistryToFile( bool bForce = false );
+ bool m_bStaticWatchForComputerUse;
+ double m_StaticLastComputerUseTime;
+ int m_iStaticMouseOldX, m_iStaticMouseOldY;
+ // timer data
+ double m_flFrameTime;
+ KeyValues *m_pUserConfigData;
+ char m_szFileName[MAX_PATH];
+ char m_szPathID[MAX_PATH];
+
+ KeyValues *m_pRegistry;
+ double m_flRegistrySaveTime;
+ bool m_bRegistryDirty;
+
+ char m_szRegistryPath[ MAX_PATH ];
+#ifdef OSX
+ PasteboardRef m_PasteBoardRef;
+#endif
+
+};
+
+
+CSystem g_System;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CSystem, ISystem, VGUI_SYSTEM_INTERFACE_VERSION, g_System);
+
+namespace vgui
+{
+vgui::ISystem *g_pSystem = &g_System;
+}
+
+#define REGISTRY_NAME "cfg/registry.vdf"
+#define REGISTRY_SAVE_INTERVAL 30
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CSystem::CSystem()
+{
+ m_bStaticWatchForComputerUse = false;
+ m_flFrameTime = 0.0;
+ m_flRegistrySaveTime = 0.0;
+ m_bRegistryDirty = false;
+ m_pUserConfigData = NULL;
+#ifdef OSX
+ PasteboardCreate( kPasteboardClipboard, &m_PasteBoardRef );
+#endif
+
+ Q_snprintf( m_szRegistryPath, sizeof(m_szRegistryPath), "%s", REGISTRY_NAME );
+
+ m_pRegistry = new KeyValues( "registry" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CSystem::~CSystem()
+{
+ SaveRegistryToFile( true );
+#ifdef OSX
+ CFRelease( m_PasteBoardRef );
+#endif
+}
+
+void CSystem::SaveRegistryToFile( bool bForce )
+{
+ /*if ( m_pRegistry && ( m_bRegistryDirty || bForce ) && g_pFullFileSystem )
+ {
+ m_pRegistry->SaveToFile( g_pFullFileSystem, m_szRegistryPath, "MOD" );
+ }*/
+ m_bRegistryDirty = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSystem::Shutdown()
+{
+ if (m_pUserConfigData)
+ {
+ m_pUserConfigData->deleteThis();
+ }
+ SaveRegistryToFile( true );
+ if ( m_pRegistry )
+ {
+ m_pRegistry->deleteThis();
+ }
+ m_pRegistry = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles all the per frame actions
+//-----------------------------------------------------------------------------
+void CSystem::RunFrame()
+{
+ // record the current frame time
+ m_flFrameTime = GetCurrentTime();
+
+ if (m_bStaticWatchForComputerUse)
+ {
+ // check for mouse movement
+ int x, y;
+ g_pInput->GetCursorPos(x, y);
+ // allow a little slack for jittery mice, don't reset until it's moved more than fifty pixels
+ if (abs((x + y) - (m_iStaticMouseOldX + m_iStaticMouseOldY)) > 50)
+ {
+ m_StaticLastComputerUseTime = Plat_MSTime();
+ m_iStaticMouseOldX = x;
+ m_iStaticMouseOldY = y;
+ }
+ }
+
+ if ( m_flFrameTime - m_flRegistrySaveTime > REGISTRY_SAVE_INTERVAL )
+ {
+ m_flRegistrySaveTime = m_flFrameTime;
+ SaveRegistryToFile();
+// Registry_RunFrame();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the time at the start of the frame
+//-----------------------------------------------------------------------------
+double CSystem::GetFrameTime()
+{
+ return m_flFrameTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the current time
+//-----------------------------------------------------------------------------
+double CSystem::GetCurrentTime()
+{
+ return Plat_FloatTime();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the current time in milliseconds
+//-----------------------------------------------------------------------------
+long CSystem::GetTimeMillis()
+{
+ return (long)(Plat_MSTime() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Legacy stub to allow ShellExecute( "open", "file" ) -- doesn't otherwise work
+//-----------------------------------------------------------------------------
+void CSystem::ShellExecute(const char *command, const char *file)
+{
+ if ( V_strcmp( command, "open" ) != 0 )
+ {
+ // Nope
+ Assert( !"This legacy command is only supported in the form of open <foo>" );
+ return;
+ }
+
+#ifdef OSX
+ const char *szCommand = "open";
+#else
+ const char *szCommand = "xdg-open";
+#endif
+
+ pid_t pid = fork();
+ if ( pid == 0 )
+ {
+ // Child
+#ifdef LINUX
+ // Escape steam runtime if necessary
+ const char *szSteamRuntime = getenv( "STEAM_RUNTIME" );
+ if ( szSteamRuntime )
+ {
+ unsetenv( "STEAM_RUNTIME" );
+
+ const char *szSystemLibraryPath = getenv( "SYSTEM_LD_LIBRARY_PATH" );
+ const char *szSystemPath = getenv( "SYSTEM_PATH" );
+ if ( szSystemLibraryPath )
+ {
+ setenv( "LD_LIBRARY_PATH", szSystemLibraryPath, 1 );
+ }
+ if ( szSystemPath )
+ {
+ setenv( "PATH", szSystemPath, 1 );
+ }
+ }
+#endif
+ execlp( szCommand, szCommand, file, (char *)0 );
+ Assert( !"execlp failed" );
+ }
+}
+
+void CSystem::ShellExecuteEx( const char *command, const char *file, const char *pParams )
+{
+ NOTE_UNUSED( pParams );
+ ShellExecute( command, file );
+}
+
+void CSystem::SetClipboardText(const char *text, int textLen)
+{
+#ifdef OSX
+ PasteboardSynchronize( m_PasteBoardRef );
+ PasteboardClear( m_PasteBoardRef );
+ CFDataRef theData = CFDataCreate( kCFAllocatorDefault, (const UInt8*)text, textLen );
+ PasteboardPutItemFlavor( m_PasteBoardRef, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), theData, 0 );
+ CFRelease( theData );
+#elif defined( USE_SDL )
+ if ( Q_strlen( text ) <= textLen )
+ {
+ if ( SDL_SetClipboardText( text ) )
+ {
+ Msg( "SDL_SetClipboardText failed: %s\n", SDL_GetError() );
+ }
+ }
+ else
+ {
+ char *ClipText = ( char *)malloc( textLen + 1 );
+ if ( ClipText )
+ {
+ Q_strncpy( ClipText, text, textLen + 1 );
+ if ( SDL_SetClipboardText( ClipText ) )
+ {
+ Msg( "SDL_SetClipboardText failed: %s\n", SDL_GetError() );
+ }
+ free( ClipText );
+ }
+ }
+#endif
+}
+
+void CSystem::SetClipboardImage( void *pWnd, int x1, int y1, int x2, int y2 )
+{
+ Assert( false );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Puts unicode text into the clipboard
+//-----------------------------------------------------------------------------
+void CSystem::SetClipboardText(const wchar_t *text, int textLen)
+{
+ char *charStr = (char *)malloc( textLen * 4 );
+
+ Q_UnicodeToUTF8( text, charStr, textLen*4 );
+
+#ifdef OSX
+ PasteboardSynchronize( m_PasteBoardRef );
+ PasteboardClear( m_PasteBoardRef );
+
+ CFDataRef theData = CFDataCreate( kCFAllocatorDefault, (const UInt8*)charStr, Q_strlen(charStr) );
+ PasteboardPutItemFlavor( m_PasteBoardRef, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), theData, 0 );
+ CFRelease( theData );
+#elif defined( USE_SDL )
+ SetClipboardText( charStr, Q_strlen( charStr ) );
+#endif
+
+ free( charStr );
+}
+
+int CSystem::GetClipboardTextCount()
+{
+#ifdef OSX
+ ItemCount count;
+ PasteboardSynchronize( m_PasteBoardRef );
+
+ OSStatus err = PasteboardGetItemCount( m_PasteBoardRef, &count );
+ if ( err != noErr )
+ return 0;
+
+ if ( count <= 0 )
+ return 0;
+
+ PasteboardItemID ItemID;
+ // always use the last item on the clipboard for any cut and paste data
+ err = PasteboardGetItemIdentifier( m_PasteBoardRef, count, &ItemID );
+ if ( err != noErr )
+ return 0;
+ CFDataRef outData;
+ err = PasteboardCopyItemFlavorData ( m_PasteBoardRef, ItemID, CFSTR ("public.utf8-plain-text"), &outData);
+ if ( err != noErr )
+ return 0;
+
+ int copyLen = CFDataGetLength( outData );
+ CFRelease( outData );
+ return (int)copyLen + 1;
+#elif defined( USE_SDL )
+ int Count = 0;
+
+ if ( SDL_HasClipboardText() )
+ {
+ char *text = SDL_GetClipboardText();
+
+ if ( text )
+ {
+ Count = Q_strlen( text ) + 1;
+ SDL_free( text );
+ }
+ }
+
+ return Count;
+#else
+ return 0;
+#endif
+}
+
+int CSystem::GetClipboardText(int offset, char *buf, int bufLen)
+{
+ Assert( !offset );
+
+#ifdef OSX
+ ItemCount count;
+ PasteboardSynchronize( m_PasteBoardRef );
+
+ OSStatus err = PasteboardGetItemCount( m_PasteBoardRef, &count );
+ if ( err != noErr )
+ return 0;
+
+ char *pchOutData;
+ PasteboardItemID ItemID;
+ // pull the last item from the clipboard
+ err = PasteboardGetItemIdentifier( m_PasteBoardRef, count, &ItemID );
+ if ( err != noErr )
+ return 0;
+ CFDataRef outData;
+ err = PasteboardCopyItemFlavorData ( m_PasteBoardRef, ItemID, CFSTR ("public.utf8-plain-text"), &outData);
+ if ( err != noErr )
+ return 0;
+ pchOutData = (char *)CFDataGetBytePtr(outData );
+ int copyLen = MIN( CFDataGetLength( outData ), bufLen ) ;
+ if ( pchOutData )
+ memcpy( buf, pchOutData, copyLen );
+ CFRelease( outData );
+ return copyLen;
+#elif defined( USE_SDL )
+ if( SDL_HasClipboardText() )
+ {
+ char *text = SDL_GetClipboardText();
+
+ if ( text )
+ {
+ Q_strncpy( buf, text, bufLen );
+ SDL_free( text );
+ return Q_strlen( buf );
+ }
+ }
+
+ return 0;
+#else
+ return 0;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Retrieves unicode text from the clipboard
+//-----------------------------------------------------------------------------
+int CSystem::GetClipboardText(int offset, wchar_t *buf, int bufLen)
+{
+ Assert( !offset );
+
+ char *outputUTF8 = (char *)malloc( bufLen*4 );
+ int ret = GetClipboardText( offset, outputUTF8, bufLen );
+
+ if ( ret )
+ {
+ Q_UTF8ToUnicode( outputUTF8, buf, bufLen );
+ }
+ else if( bufLen > 0 )
+ {
+ buf[ 0 ] = 0;
+ }
+
+ free( outputUTF8 );
+ return ret;
+}
+
+
+bool CSystem::SetRegistryString(const char *key, const char *value)
+{
+ m_bRegistryDirty = true;
+ m_pRegistry->SetString( key, value );
+ return true;
+}
+
+bool CSystem::GetRegistryString(const char *key, char *value, int valueLen)
+{
+ const char *pchVal = m_pRegistry->GetString( key );
+ if ( pchVal )
+ Q_strncpy( value, pchVal, valueLen );
+ return pchVal != NULL;
+}
+
+bool CSystem::SetRegistryInteger(const char *key, int value)
+{
+ m_bRegistryDirty = true;
+ m_pRegistry->SetInt( key, value );
+ return false;
+}
+
+bool CSystem::GetRegistryInteger(const char *key, int &value)
+{
+ value = m_pRegistry->GetInt( key );
+ return value != 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: recursively deletes a registry key and all it's subkeys
+//-----------------------------------------------------------------------------
+bool CSystem::DeleteRegistryKey(const char *key)
+{
+ Assert( false );
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets whether or not the app watches for global computer use
+//-----------------------------------------------------------------------------
+bool CSystem::SetWatchForComputerUse(bool state)
+{
+ if (state == m_bStaticWatchForComputerUse)
+ return true;
+
+ m_bStaticWatchForComputerUse = state;
+
+ if (m_bStaticWatchForComputerUse)
+ {
+ // enable watching
+ }
+ else
+ {
+ // disable watching
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the time, in seconds, since the last computer use.
+//-----------------------------------------------------------------------------
+double CSystem::GetTimeSinceLastUse()
+{
+ if (m_bStaticWatchForComputerUse)
+ {
+ return ( Plat_MSTime() - m_StaticLastComputerUseTime ) / 1000.0f;
+ }
+
+ return 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the drives a user has available on thier system
+//-----------------------------------------------------------------------------
+int CSystem::GetAvailableDrives(char *buf, int bufLen)
+{
+ Assert( false );
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the amount of available disk space, in bytes, on the specified path
+//-----------------------------------------------------------------------------
+double CSystem::GetFreeDiskSpace(const char *path)
+{
+ struct statfs64 buf;
+ int ret = statfs64( path, &buf );
+ if ( ret < 0 )
+ return 0.0;
+ return (double) ( buf.f_bsize * buf.f_bfree );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: user config
+//-----------------------------------------------------------------------------
+KeyValues *CSystem::GetUserConfigFileData(const char *dialogName, int dialogID)
+{
+ if (!m_pUserConfigData)
+ return NULL;
+
+ Assert(dialogName && *dialogName);
+
+ if (dialogID)
+ {
+ char buf[256];
+ Q_snprintf(buf, sizeof(buf), "%s_%d", dialogName, dialogID);
+ dialogName = buf;
+ }
+
+ return m_pUserConfigData->FindKey(dialogName, true);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the name of the config file to save/restore from. Settings are loaded immediately.
+//-----------------------------------------------------------------------------
+void CSystem::SetUserConfigFile(const char *fileName, const char *pathName)
+{
+ //m_pRegistry->LoadFromFile( g_pFullFileSystem, m_szRegistryPath, NULL );
+
+ if (!m_pUserConfigData)
+ {
+ m_pUserConfigData = new KeyValues("UserConfigData");
+ }
+ else
+ {
+ // delete all the existing keys so when we reload from the new file we don't
+ // get duplicate entries in our key value
+ m_pUserConfigData->Clear();
+ }
+
+ Q_strncpy(m_szFileName, fileName, sizeof(m_szFileName));
+ Q_strncpy(m_szPathID, pathName, sizeof(m_szPathID));
+
+ // open
+ m_pUserConfigData->UsesEscapeSequences( true ); // VGUI may use this
+ m_pUserConfigData->LoadFromFile(g_pFullFileSystem, m_szFileName, m_szPathID);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: saves all the current settings to the user config file
+//-----------------------------------------------------------------------------
+void CSystem::SaveUserConfigFile()
+{
+ if (m_pUserConfigData)
+ {
+ m_pUserConfigData->SaveToFile(g_pFullFileSystem, m_szFileName, m_szPathID);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether or not the parameter was on the command line
+//-----------------------------------------------------------------------------
+bool CSystem::CommandLineParamExists(const char *paramName)
+{
+ if ( Q_strstr( Plat_GetCommandLine(), paramName ) )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the string following a command line param
+//-----------------------------------------------------------------------------
+bool CSystem::GetCommandLineParamValue(const char *paramName, char *value, int valueBufferSize)
+{
+ Assert( false );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the name of the currently running exe
+//-----------------------------------------------------------------------------
+const char *CSystem::GetFullCommandLine()
+{
+ return VCRHook_GetCommandLine();
+}
+
+
+KeyCode CSystem::KeyCode_VirtualKeyToVGUI( int keyCode )
+{
+ return ::KeyCode_VirtualKeyToVGUI( keyCode );
+}
+
+int CSystem::KeyCode_VGUIToVirtualKey( KeyCode keyCode )
+{
+ return ::KeyCode_VGUIToVirtualKey( keyCode );
+}
+
+/*MouseCode CSystem::MouseCode_VirtualKeyToVGUI( int keyCode )
+{
+ return ::MouseCode_VirtualKeyToVGUI( keyCode );
+}
+
+int CSystem::MouseCode_VGUIToVirtualKey( MouseCode mouseCode )
+{
+ return ::MouseCode_VGUIToVirtualKey( mouseCode );
+}*/
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the current local time and date
+//-----------------------------------------------------------------------------
+bool CSystem::GetCurrentTimeAndDate(int *year, int *month, int *dayOfWeek, int *day, int *hour, int *minute, int *second)
+{
+ time_t t = time( NULL );
+ struct tm *now = localtime( &t );
+ if ( now )
+ {
+ if ( year ) *year = now->tm_year + 1900;
+ if ( month ) *month = now->tm_mon + 1;
+ if ( dayOfWeek ) *dayOfWeek = now->tm_wday;
+ if ( day ) *day = now->tm_mday;
+ if ( hour ) *hour = now->tm_hour;
+ if ( minute ) *minute = now->tm_min;
+ if ( second ) *second = now->tm_sec;
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a shortcut file
+//-----------------------------------------------------------------------------
+bool CSystem::CreateShortcut(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory, const char *iconFile)
+{
+ Assert( false );
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: retrieves shortcut (.lnk) information
+//-----------------------------------------------------------------------------
+bool CSystem::GetShortcutTarget(const char *linkFileName, char *targetPath, char *arguments, int destBufferSizes)
+{
+ Assert( false );
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets shortcut (.lnk) information
+//-----------------------------------------------------------------------------
+bool CSystem::ModifyShortcutTarget(const char *linkFileName, const char *targetPath, const char *arguments, const char *workingDirectory)
+{
+ Assert( false );
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the full path of the current user's desktop folder
+//-----------------------------------------------------------------------------
+const char *CSystem::GetDesktopFolderPath()
+{
+ Assert( false );
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the full path of the all user's desktop folder
+//-----------------------------------------------------------------------------
+const char *CSystem::GetAllUserDesktopFolderPath()
+{
+ Assert( false );
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the full path of the current user's start->program files
+//-----------------------------------------------------------------------------
+const char *CSystem::GetStartMenuFolderPath()
+{
+ Assert( false );
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the full path of the all user's start->program files
+//-----------------------------------------------------------------------------
+const char *CSystem::GetAllUserStartMenuFolderPath()
+{
+ Assert( false );
+ return NULL;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Ensure that all of our internal structures are consistent, and
+// account for all memory that we've allocated.
+// Input: validator - Our global validator object
+// pchName - Our name (typically a member var in our container)
+//-----------------------------------------------------------------------------
+#ifdef DBGFLAG_VALIDATE
+void CSystem::Validate( CValidator &validator, char *pchName )
+{
+ VALIDATE_SCOPE();
+ ValidatePtr( m_pUserConfigData );
+}
+
+
+void Validate_System( CValidator &validator )
+{
+ ValidateObj( g_System );
+}
+#endif
diff --git a/vgui2/src/vgui.cpp b/vgui2/src/vgui.cpp
new file mode 100644
index 0000000..3508b1a
--- /dev/null
+++ b/vgui2/src/vgui.cpp
@@ -0,0 +1,1195 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core implementation of vgui
+//
+// $NoKeywords: $
+//===========================================================================//
+
+
+#if defined( WIN32 ) && !defined( _X360 )
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include <vgui/VGUI.h>
+#include <vgui/Dar.h>
+#include <vgui/IInputInternal.h>
+#include <vgui/IPanel.h>
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/IClientPanel.h>
+#include <vgui/IScheme.h>
+#include <KeyValues.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <tier0/dbg.h>
+#include <tier1/utlhandletable.h>
+#include "vgui_internal.h"
+#include "VPanel.h"
+#include "IMessageListener.h"
+#include "tier3/tier3.h"
+#include "utllinkedlist.h"
+#include "utlpriorityqueue.h"
+#include "utlvector.h"
+#include "tier0/vprof.h"
+#include "tier0/icommandline.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+#undef GetCursorPos // protected_things.h defines this, and it makes it so we can't access g_pInput->GetCursorPos.
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+using namespace vgui;
+static const int WARN_PANEL_NUMBER = 32768; // in DEBUG if more panels than this are created then throw an Assert, helps catch panel leaks
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Single item in the message queue
+//-----------------------------------------------------------------------------
+struct MessageItem_t
+{
+ KeyValues *_params; // message data
+ // _params->GetName() is the message name
+
+ HPanel _messageTo; // the panel this message is to be sent to
+ HPanel _from; // the panel this message is from (if any)
+ float _arrivalTime; // time at which the message should be passed on to the recipient
+
+ int _messageID; // incrementing message index
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool PriorityQueueComp(const MessageItem_t& x, const MessageItem_t& y)
+{
+ if (x._arrivalTime > y._arrivalTime)
+ {
+ return true;
+ }
+ else if (x._arrivalTime < y._arrivalTime)
+ {
+ return false;
+ }
+
+ // compare messageID's to ensure we have the messages in the correct order
+ return (x._messageID > y._messageID);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Implementation of core vgui functionality
+//-----------------------------------------------------------------------------
+class CVGui : public CTier3AppSystem< IVGui >
+{
+ typedef CTier3AppSystem< IVGui > BaseClass;
+
+public:
+ CVGui();
+ ~CVGui();
+
+//-----------------------------------------------------------------------------
+ // SRC specific stuff
+ // 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();
+ // End of specific interface
+//-----------------------------------------------------------------------------
+
+
+ virtual void RunFrame();
+
+ virtual void Start()
+ {
+ m_bRunning = true;
+ }
+
+ // signals vgui to Stop running
+ virtual void Stop()
+ {
+ m_bRunning = false;
+ }
+
+ // returns true if vgui is current active
+ virtual bool IsRunning()
+ {
+ return m_bRunning;
+ }
+
+ virtual void ShutdownMessage(unsigned int shutdownID);
+
+ // safe-pointer handle methods
+ virtual VPANEL AllocPanel();
+ virtual void FreePanel(VPANEL ipanel);
+ virtual HPanel PanelToHandle(VPANEL panel);
+ virtual VPANEL HandleToPanel(HPanel index);
+ virtual void MarkPanelForDeletion(VPANEL panel);
+
+ virtual void AddTickSignal(VPANEL panel, int intervalMilliseconds = 0);
+ virtual void AddTickSignalToHead( VPANEL panel, int intervalMilliseconds = 0 ) OVERRIDE;
+ virtual void RemoveTickSignal(VPANEL panel );
+
+
+ // message pump method
+ virtual void PostMessage(VPANEL target, KeyValues *params, VPANEL from, float delaySeconds = 0.0f);
+
+ virtual void SetSleep( bool state ) { m_bDoSleep = state; };
+ virtual bool GetShouldVGuiControlSleep() { return m_bDoSleep; }
+
+ virtual void DPrintf(const char *format, ...);
+ virtual void DPrintf2(const char *format, ...);
+ virtual void SpewAllActivePanelNames();
+
+ // Creates/ destroys vgui contexts, which contains information
+ // about which controls have mouse + key focus, for example.
+ virtual HContext CreateContext();
+ virtual void DestroyContext( HContext context );
+
+ // Associates a particular panel with a vgui context
+ // Associating NULL is valid; it disconnects the panel from the context
+ virtual void AssociatePanelWithContext( HContext context, VPANEL pRoot );
+
+ // Activates a particular input context, use DEFAULT_VGUI_CONTEXT
+ // to get the one normally used by VGUI
+ virtual void ActivateContext( HContext context );
+
+ // enables VR mode
+ virtual void SetVRMode( bool bVRMode ) OVERRIDE
+ {
+ m_bVRMode = bVRMode;
+ }
+ virtual bool GetVRMode() OVERRIDE
+ {
+ return m_bVRMode;
+ }
+
+ bool IsDispatchingMessages( void )
+ {
+ return m_InDispatcher;
+ }
+
+private:
+ // VGUI contexts
+ struct Context_t
+ {
+ HInputContext m_hInputContext;
+ };
+
+ struct Tick_t
+ {
+ VPanel *panel;
+ int interval;
+ int nexttick;
+ bool bMarkDeleted;
+ // Debugging
+ char panelname[ 64 ];
+ };
+
+ Tick_t* CreateNewTick( VPANEL panel, int intervalMilliseconds );
+
+ // Returns the current context
+ Context_t *GetContext( HContext context );
+
+ void PanelCreated(VPanel *panel);
+ void PanelDeleted(VPanel *panel);
+ bool DispatchMessages();
+ void DestroyAllContexts( );
+ void ClearMessageQueues();
+ inline bool IsReentrant() const
+ {
+ return m_nReentrancyCount > 0;
+ }
+
+ // safe panel handle stuff
+ CUtlHandleTable< VPanel, 20 > m_HandleTable;
+ int m_iCurrentMessageID;
+
+ bool m_bRunning : 1;
+ bool m_bDoSleep : 1;
+ bool m_InDispatcher : 1;
+ bool m_bDebugMessages : 1;
+ bool m_bVRMode : 1;
+ bool m_bCanRemoveTickSignal : 1;
+ int m_nReentrancyCount;
+
+ CUtlVector< Tick_t * > m_TickSignalVec;
+ CUtlLinkedList< Context_t > m_Contexts;
+
+ HContext m_hContext;
+ Context_t m_DefaultContext;
+
+#ifdef DEBUG
+ int m_iDeleteCount, m_iDeletePanelCount;
+#endif
+
+ // message queue. holds all vgui messages generated by windows events
+ CUtlLinkedList<MessageItem_t, ushort> m_MessageQueue;
+
+ // secondary message queue, holds all vgui messages generated by vgui
+ CUtlLinkedList<MessageItem_t, ushort> m_SecondaryQueue;
+
+ // timing queue, holds all the messages that have to arrive at a specified time
+ CUtlPriorityQueue<MessageItem_t> m_DelayedMessageQueue;
+};
+
+CVGui g_VGui;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CVGui, IVGui, VGUI_IVGUI_INTERFACE_VERSION, g_VGui);
+
+bool IsDispatchingMessageQueue( void )
+{
+ return g_VGui.IsDispatchingMessages();
+}
+
+namespace vgui
+{
+IVGui *g_pIVgui = &g_VGui;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CVGui::CVGui() : m_DelayedMessageQueue(0, 4, PriorityQueueComp)
+{
+ m_bRunning = false;
+ m_InDispatcher = false;
+ m_bDebugMessages = false;
+ m_bDoSleep = true;
+ m_bVRMode = false;
+ m_bCanRemoveTickSignal = true;
+ m_nReentrancyCount = 0;
+ m_hContext = DEFAULT_VGUI_CONTEXT;
+ m_DefaultContext.m_hInputContext = DEFAULT_INPUT_CONTEXT;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CVGui::~CVGui()
+{
+#ifdef _DEBUG
+ int nCount = m_HandleTable.GetHandleCount();
+ int nActualCount = 0;
+ for ( int i = 0; i < nCount; ++i )
+ {
+ UtlHandle_t h = m_HandleTable.GetHandleFromIndex( i );
+ if ( m_HandleTable.IsHandleValid( h ) )
+ {
+ ++nActualCount;
+ }
+ }
+
+ if ( nActualCount > 0 )
+ {
+ Msg("Memory leak: panels left in CVGui::m_PanelList: %d\n", nActualCount );
+ }
+#endif // _DEBUG
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Dumps out list of all active panels
+//-----------------------------------------------------------------------------
+void CVGui::SpewAllActivePanelNames()
+{
+ int nCount = m_HandleTable.GetHandleCount();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ UtlHandle_t h = m_HandleTable.GetHandleFromIndex( i );
+ if ( m_HandleTable.IsHandleValid( h ) )
+ {
+ VPanel *pPanel = m_HandleTable.GetHandle( h );
+ Msg("\tpanel '%s' of type '%s' leaked\n", g_pIPanel->GetName( (VPANEL)pPanel ), ((VPanel *)pPanel)->GetClassName());
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates/ destroys "input" contexts, which contains information
+// about which controls have mouse + key focus, for example.
+//-----------------------------------------------------------------------------
+HContext CVGui::CreateContext()
+{
+ HContext i = m_Contexts.AddToTail();
+ m_Contexts[i].m_hInputContext = g_pInput->CreateInputContext();
+ return i;
+}
+
+void CVGui::DestroyContext( HContext context )
+{
+ Assert( context != DEFAULT_VGUI_CONTEXT );
+
+ if ( m_hContext == context )
+ {
+ ActivateContext( DEFAULT_VGUI_CONTEXT );
+ }
+
+ g_pInput->DestroyInputContext( GetContext(context)->m_hInputContext );
+ m_Contexts.Remove(context);
+}
+
+void CVGui::DestroyAllContexts( )
+{
+ HContext next;
+ HContext i = m_Contexts.Head();
+ while (i != m_Contexts.InvalidIndex())
+ {
+ next = m_Contexts.Next(i);
+ DestroyContext( i );
+ i = next;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the current context
+//-----------------------------------------------------------------------------
+CVGui::Context_t *CVGui::GetContext( HContext context )
+{
+ if (context == DEFAULT_VGUI_CONTEXT)
+ return &m_DefaultContext;
+ return &m_Contexts[context];
+}
+
+
+//-----------------------------------------------------------------------------
+// Associates a particular panel with a context
+// Associating NULL is valid; it disconnects the panel from the context
+//-----------------------------------------------------------------------------
+void CVGui::AssociatePanelWithContext( HContext context, VPANEL pRoot )
+{
+ Assert( context != DEFAULT_VGUI_CONTEXT );
+ g_pInput->AssociatePanelWithInputContext( GetContext(context)->m_hInputContext, pRoot );
+}
+
+
+//-----------------------------------------------------------------------------
+// Activates a particular context, use DEFAULT_VGUI_CONTEXT
+// to get the one normally used by VGUI
+//-----------------------------------------------------------------------------
+void CVGui::ActivateContext( HContext context )
+{
+ Assert( (context == DEFAULT_VGUI_CONTEXT) || m_Contexts.IsValidIndex(context) );
+
+ if ( m_hContext != context )
+ {
+ // Clear out any messages queues that may be full...
+ if ( !IsReentrant() )
+ {
+ DispatchMessages();
+ }
+
+ m_hContext = context;
+ g_pInput->ActivateInputContext( GetContext(m_hContext)->m_hInputContext );
+
+ if ( context != DEFAULT_VGUI_CONTEXT && !IsReentrant() )
+ {
+ g_pInput->RunFrame( );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Runs a single vgui frame, pumping all message to panels
+//-----------------------------------------------------------------------------
+void CVGui::RunFrame()
+{
+ // NOTE: This can happen when running in Maya waiting for modal dialogs
+ bool bIsReentrant = m_InDispatcher;
+ if ( bIsReentrant )
+ {
+ ++m_nReentrancyCount;
+ }
+
+#ifdef DEBUG
+// memory allocation debug helper
+// DPrintf( "Delete Count:%i,%i\n", m_iDeleteCount, m_iDeletePanelCount );
+// m_iDeleteCount = m_iDeletePanelCount = 0;
+#endif
+
+ // this will generate all key and mouse events as well as make a real repaint
+ {
+ VPROF( "surface()->RunFrame()" );
+ g_pSurface->RunFrame();
+ }
+
+ // give the system a chance to process
+ {
+ VPROF( "system()->RunFrame()" );
+ g_pSystem->RunFrame();
+ }
+
+ // update cursor positions
+ if ( IsPC() && !IsReentrant() )
+ {
+ VPROF( "update cursor positions" );
+ int cursorX, cursorY;
+ g_pInput->GetCursorPosition(cursorX, cursorY);
+
+ // this does the actual work given a x,y and a surface
+ g_pInput->UpdateMouseFocus(cursorX, cursorY);
+
+ }
+
+ if ( !bIsReentrant )
+ {
+ VPROF( "input()->RunFrame()" );
+ g_pInput->RunFrame();
+ }
+
+ // messenging
+ if ( !bIsReentrant )
+ {
+ VPROF( "messaging" );
+
+ // send all the messages waiting in the queue
+ DispatchMessages();
+
+ // Do the OnTicks before purging messages, since in previous code they were posted after dispatch and wouldn't hit
+ // until next frame
+ int time = g_pSystem->GetTimeMillis();
+
+ m_bCanRemoveTickSignal = false;
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - Ticks", __FUNCTION__ );
+ // directly invoke tick all who asked to be ticked
+ int count = m_TickSignalVec.Count();
+ for (int i = count - 1; i >= 0; i-- )
+ {
+ Tick_t *t = m_TickSignalVec[i];
+ if ( t->bMarkDeleted )
+ continue;
+
+ if ( t->interval != 0 )
+ {
+ if ( time < t->nexttick )
+ continue;
+
+ t->nexttick = time + t->interval;
+ }
+
+ t->panel->Client()->OnTick();
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s - Ticks: %s", __FUNCTION__, t->panel->Client()->GetName() );
+ }
+
+ m_bCanRemoveTickSignal = true;
+
+ // get count again. panels could be added to tick vector in OnTick
+ count = m_TickSignalVec.Count();
+
+ // Remove all panels that tried to remove tick in OnTick
+ for (int i = count - 1; i >= 0; i-- )
+ {
+ Tick_t *t = m_TickSignalVec[i];
+ if ( t->bMarkDeleted )
+ {
+ m_TickSignalVec.Remove( i );
+ delete t;
+ }
+ }
+ }
+
+ {
+ VPROF( "SolveTraverse" );
+ // make sure the hierarchy is up to date
+ g_pSurface->SolveTraverse(g_pSurface->GetEmbeddedPanel());
+ g_pSurface->ApplyChanges();
+#ifdef WIN32
+ Assert( IsX360() || ( IsPC() && _heapchk() == _HEAPOK ) );
+#endif
+ }
+
+ if ( bIsReentrant )
+ {
+ --m_nReentrancyCount;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+VPANEL CVGui::AllocPanel()
+{
+#ifdef DEBUG
+ m_iDeleteCount++;
+#endif
+
+ VPanel *panel = new VPanel;
+ PanelCreated(panel);
+ return (VPANEL)panel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVGui::FreePanel(VPANEL ipanel)
+{
+ PanelDeleted((VPanel *)ipanel);
+ delete (VPanel *)ipanel;
+#ifdef DEBUG
+ m_iDeleteCount--;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the safe index of the panel
+//-----------------------------------------------------------------------------
+HPanel CVGui::PanelToHandle(VPANEL panel)
+{
+ if (panel)
+ return ((VPanel*)panel)->GetHPanel();
+ return INVALID_PANEL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the panel at the specified index
+//-----------------------------------------------------------------------------
+VPANEL CVGui::HandleToPanel(HPanel index)
+{
+ if ( !m_HandleTable.IsHandleValid( index ) )
+ {
+ return NULL;
+ }
+ return (VPANEL)m_HandleTable.GetHandle( (UtlHandle_t)index );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called whenever a panel is constructed
+//-----------------------------------------------------------------------------
+void CVGui::PanelCreated(VPanel *panel)
+{
+ UtlHandle_t h = m_HandleTable.AddHandle();
+ m_HandleTable.SetHandle( h, panel );
+
+#if DUMP_PANEL_LIST
+ int nCount = m_HandleTable.GetHandleCount();
+ int nActualCount = 0;
+ for ( int i = 0; i < nCount; ++i )
+ {
+ UtlHandle_t h = m_HandleTable.GetHandleFromIndex( i );
+ if ( m_HandleTable.IsHandleValid( h ) )
+ {
+ ++nActualCount;
+ }
+ }
+
+ if ( nActualCount >= WARN_PANEL_NUMBER )
+ {
+ FILE *file1 = fopen("panellist.txt", "w");
+ if (file1 != NULL)
+ {
+ fprintf(file1, "Too many panels...listing them all.\n");
+ int panelIndex;
+ for (panelIndex = 0; panelIndex < nCount; ++panelIndex)
+ {
+ UtlHandle_t h = m_HandleTable.GetHandleFromIndex( i );
+ VPanel *pPanel = m_HandleTable.GetHandle( h );
+ IClientPanel *ipanel = ( pPanel ) ? pPanel->Client() : NULL;
+ if ( ipanel )
+ fprintf(file1, "panel %d: name: %s classname: %s\n", panelIndex, ipanel->GetName(), ipanel->GetClassName());
+ else
+ fprintf(file1, "panel %d: can't get ipanel\n", panelIndex);
+ }
+
+ fclose(file1);
+ }
+ }
+
+ Assert( nActualCount < WARN_PANEL_NUMBER );
+#endif // DUMP_PANEL_LIST
+
+ ((VPanel *)panel)->SetHPanel( h );
+
+ g_pSurface->AddPanel((VPANEL)panel);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: instantly stops the app from pointing to the focus'd object
+// used when an object is being deleted
+//-----------------------------------------------------------------------------
+void CVGui::PanelDeleted(VPanel *focus)
+{
+ Assert( focus );
+ g_pSurface->ReleasePanel((VPANEL)focus);
+ g_pInput->PanelDeleted((VPANEL)focus);
+
+ // remove from safe handle list
+ UtlHandle_t h = ((VPanel *)focus)->GetHPanel();
+
+ Assert( m_HandleTable.IsHandleValid(h) );
+ if ( m_HandleTable.IsHandleValid(h) )
+ {
+ m_HandleTable.RemoveHandle( h );
+ }
+
+ ((VPanel *)focus)->SetHPanel( INVALID_PANEL );
+
+ // remove from tick signal dar
+ RemoveTickSignal( (VPANEL)focus );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates or updates a tick signal for a panel. Returns NULL if already ticking.
+//-----------------------------------------------------------------------------
+CVGui::Tick_t* CVGui::CreateNewTick( VPANEL panel, int intervalMilliseconds )
+{
+ Tick_t *t;
+ // See if it's already in list
+ int count = m_TickSignalVec.Count();
+ for (int i = 0; i < count; i++ )
+ {
+ Tick_t *t = m_TickSignalVec[i];
+ if ( t->panel == (VPanel *)panel )
+ {
+ // Go ahead and update intervals
+ t->interval = intervalMilliseconds;
+ t->nexttick = g_pSystem->GetTimeMillis() + t->interval;
+
+ // Somebody added this panel back to the tick list, don't delete it
+ t->bMarkDeleted = false;
+ return NULL;
+ }
+ }
+
+ // Add to list
+ t = new Tick_t;
+
+ t->panel = (VPanel *)panel;
+ t->interval = intervalMilliseconds;
+ t->nexttick = g_pSystem->GetTimeMillis() + t->interval;
+ t->bMarkDeleted = false;
+
+ if ( strlen( ((VPanel *)panel)->Client()->GetName() ) > 0 )
+ {
+ strncpy( t->panelname, ((VPanel *)panel)->Client()->GetName(), sizeof( t->panelname ) );
+ }
+ else
+ {
+ strncpy( t->panelname, ((VPanel *)panel)->Client()->GetClassName(), sizeof( t->panelname ) );
+ }
+
+ return t;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds the panel to the tail of a tick signal list, so the panel receives a message every frame
+//-----------------------------------------------------------------------------
+void CVGui::AddTickSignal(VPANEL panel, int intervalMilliseconds /*=0*/ )
+{
+ Tick_t* t = CreateNewTick( panel, intervalMilliseconds );
+
+ if ( t )
+ {
+ // add the element to the end list
+ m_TickSignalVec.AddToTail( t );
+ // panel is removed from list when deleted
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds the panel to the head of a tick signal list, so the panel receives a message every frame
+//-----------------------------------------------------------------------------
+void CVGui::AddTickSignalToHead(VPANEL panel, int intervalMilliseconds /*=0*/ )
+{
+ Tick_t* t = CreateNewTick( panel, intervalMilliseconds );
+
+ if ( t )
+ {
+ // simply add the element to the head list
+ m_TickSignalVec.AddToHead( t );
+ // panel is removed from list when deleted
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVGui::RemoveTickSignal( VPANEL panel )
+{
+ VPanel *search = (VPanel *)panel;
+
+ // remove from tick signal dar
+ int count = m_TickSignalVec.Count();
+
+ for (int i = 0; i < count; i++ )
+ {
+ Tick_t *tick = m_TickSignalVec[i];
+ if ( tick->panel == search )
+ {
+ if ( m_bCanRemoveTickSignal )
+ {
+ m_TickSignalVec.Remove( i );
+ delete tick;
+ }
+ else
+ {
+ tick->bMarkDeleted = true;
+ }
+
+ return;
+ }
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: message pump
+// loops through and sends all active messages
+// note that more messages may be posted during the process
+//-----------------------------------------------------------------------------
+bool CVGui::DispatchMessages()
+{
+ int time = g_pSystem->GetTimeMillis();
+
+ m_InDispatcher = true;
+ bool doneWork = (m_MessageQueue.Count() > 12);
+
+ bool bUsingDelayedQueue = (m_DelayedMessageQueue.Count() > 0);
+
+ // Need two passes because we send the mouse move message after all
+ // other messages are done, but the mouse move message may itself generate
+ // some more messages
+ int nPassCount = 0;
+ while ( nPassCount < 2 )
+ {
+ while (m_MessageQueue.Count() > 0 || (m_SecondaryQueue.Count() > 0) || bUsingDelayedQueue)
+ {
+ // get the first message
+ MessageItem_t *messageItem = NULL;
+ int messageIndex = 0;
+
+ // use the secondary queue until it empties. empty it after each message in the
+ // primary queue. this makes primary messages completely resolve
+ bool bUsingSecondaryQueue = (m_SecondaryQueue.Count() > 0);
+ if (bUsingSecondaryQueue)
+ {
+ doneWork = true;
+ messageIndex = m_SecondaryQueue.Head();
+ messageItem = &m_SecondaryQueue[messageIndex];
+ }
+ else if (bUsingDelayedQueue)
+ {
+ if (m_DelayedMessageQueue.Count() >0)
+ {
+ messageItem = (MessageItem_t*)&m_DelayedMessageQueue.ElementAtHead();
+ }
+ if (!messageItem || messageItem->_arrivalTime > time)
+ {
+ // no more items in the delayed message queue, move to the system queue
+ bUsingDelayedQueue = false;
+ continue;
+ }
+ }
+ else
+ {
+ messageIndex = m_MessageQueue.Head();
+ messageItem = &m_MessageQueue[messageIndex];
+ }
+
+ // message debug code
+
+ if ( m_bDebugMessages )
+ {
+ const char *qname = bUsingSecondaryQueue ? "Secondary" : "Primary";
+
+ if (strcmp(messageItem->_params->GetName(), "Tick")
+ && strcmp(messageItem->_params->GetName(), "MouseFocusTicked")
+ && strcmp(messageItem->_params->GetName(), "KeyFocusTicked")
+ && strcmp(messageItem->_params->GetName(), "CursorMoved"))
+ {
+ if (!stricmp(messageItem->_params->GetName(), "command"))
+ {
+ g_pIVgui->DPrintf2( "%s Queue dispatching command( %s, %s -- %i )\n", qname, messageItem->_params->GetName(), messageItem->_params->GetString("command"), messageItem->_messageID );
+ }
+ else
+ {
+ g_pIVgui->DPrintf2( "%s Queue dispatching( %s -- %i )\n", qname ,messageItem->_params->GetName(), messageItem->_messageID );
+ }
+ }
+ }
+
+ // send it
+ KeyValues *params = messageItem->_params;
+
+ // Deal with special internal cursor movement messages
+ if ( messageItem->_messageTo == 0xFFFFFFFF )
+ {
+ if ( !Q_stricmp( params->GetName(), "SetCursorPosInternal" ) )
+ {
+ int nXPos = params->GetInt( "xpos", 0 );
+ int nYPos = params->GetInt( "ypos", 0 );
+ g_pInput->UpdateCursorPosInternal( nXPos, nYPos );
+ }
+ }
+#ifdef _X360
+ else if ( messageItem->_messageTo == 0xFFFFFFFE ) // special tag to always give message to the active key focus
+ {
+ VPanel *vto = (VPanel *) g_pInput->GetCalculatedFocus();
+ if (vto)
+ {
+ vto->SendMessage(params, g_pIVgui->HandleToPanel(messageItem->_from));
+ }
+ }
+#endif
+ else
+ {
+ VPanel *vto = (VPanel *)g_pIVgui->HandleToPanel(messageItem->_messageTo);
+ if (vto)
+ {
+ // Msg("Sending message: %s to %s\n", params ? params->GetName() : "\"\"", vto->GetName() ? vto->GetName() : "\"\"");
+ vto->SendMessage(params, g_pIVgui->HandleToPanel(messageItem->_from));
+ }
+ }
+
+ // free the keyvalues memory
+ // we can't reference the messageItem pointer anymore since the queue might have moved in memory
+ if (params)
+ {
+ params->deleteThis();
+ }
+
+ // remove it from the queue
+ if (bUsingSecondaryQueue)
+ {
+ m_SecondaryQueue.Remove(messageIndex);
+ }
+ else if (bUsingDelayedQueue)
+ {
+ m_DelayedMessageQueue.RemoveAtHead();
+ }
+ else
+ {
+ m_MessageQueue.Remove(messageIndex);
+ }
+ }
+
+ ++nPassCount;
+ if ( nPassCount == 1 )
+ {
+ // Specifically post the current mouse position as a message
+ g_pInput->PostCursorMessage();
+ }
+ }
+
+ // Make sure the windows cursor is in the right place after processing input
+ // Needs to be done here because a message provoked by the cursor moved
+ // message may move the cursor also
+ g_pInput->HandleExplicitSetCursor( );
+
+ m_InDispatcher = false;
+ return doneWork;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVGui::MarkPanelForDeletion(VPANEL panel)
+{
+ PostMessage(panel, new KeyValues("Delete"), NULL);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a message to the queue to be sent to a user
+//-----------------------------------------------------------------------------
+void CVGui::PostMessage(VPANEL target, KeyValues *params, VPANEL from, float delay)
+{
+ // Ignore all messages in re-entrant mode
+ if ( IsReentrant() )
+ {
+ Assert( 0 );
+ if (params)
+ {
+ params->deleteThis();
+ }
+ return;
+ }
+
+ if (!target)
+ {
+ if (params)
+ {
+ params->deleteThis();
+ }
+ return;
+ }
+
+ MessageItem_t messageItem;
+
+#ifdef _X360
+ // Special coded target that will always send the message to the key focus
+ // this is needed since we might send two messages on a tice, and the first
+ // could change the focus.
+ if( target == (VPANEL) MESSAGE_CURRENT_KEYFOCUS )
+ {
+ messageItem._messageTo = 0xFFFFFFFE;
+ }
+ else
+#endif
+ {
+ messageItem._messageTo = (target != (VPANEL) MESSAGE_CURSOR_POS ) ? g_pIVgui->PanelToHandle(target) : 0xFFFFFFFF;
+ }
+ messageItem._params = params;
+ Assert(params->GetName());
+ messageItem._from = g_pIVgui->PanelToHandle(from);
+ messageItem._arrivalTime = 0;
+ messageItem._messageID = m_iCurrentMessageID++;
+
+ /* message debug code
+ //if ( stricmp(messageItem._params->GetName(),"CursorMoved") && stricmp(messageItem._params->GetName(),"KeyFocusTicked"))
+ {
+ g_pIVgui->DPrintf2( "posting( %s -- %i )\n", messageItem._params->GetName(), messageItem._messageID );
+ }
+ */
+
+ // add the message to the correct message queue
+ if (delay > 0.0f)
+ {
+ messageItem._arrivalTime = g_pSystem->GetTimeMillis() + (delay * 1000);
+ m_DelayedMessageQueue.Insert(messageItem);
+ }
+ else if (m_InDispatcher)
+ {
+ m_SecondaryQueue.AddToTail(messageItem);
+ }
+ else
+ {
+ m_MessageQueue.AddToTail(messageItem);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVGui::ShutdownMessage(unsigned int shutdownID)
+{
+ // broadcast Shutdown to all the top level windows, and see if any take notice
+ VPANEL panel = g_pSurface->GetEmbeddedPanel();
+ for (int i = 0; i < ((VPanel *)panel)->GetChildCount(); i++)
+ {
+ g_pIVgui->PostMessage((VPANEL)((VPanel *)panel)->GetChild(i), new KeyValues("ShutdownRequest", "id", shutdownID), NULL);
+ }
+
+ // post to the top level window as well
+ g_pIVgui->PostMessage(panel, new KeyValues("ShutdownRequest", "id", shutdownID), NULL);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clears all the memory queues and free's their memory
+//-----------------------------------------------------------------------------
+void CVGui::ClearMessageQueues()
+{
+ Assert(!m_InDispatcher);
+
+ {FOR_EACH_LL( m_MessageQueue, i )
+ {
+ if (m_MessageQueue[i]._params)
+ {
+ m_MessageQueue[i]._params->deleteThis();
+ }
+ }}
+ m_MessageQueue.RemoveAll();
+
+ // secondary message queue, holds all vgui messages generated by vgui
+ {FOR_EACH_LL( m_SecondaryQueue, i )
+ {
+ if (m_SecondaryQueue[i]._params)
+ {
+ m_SecondaryQueue[i]._params->deleteThis();
+ }
+ }}
+ m_SecondaryQueue.RemoveAll();
+
+ // timing queue, holds all the messages that have to arrive at a specified time
+ while (m_DelayedMessageQueue.Count() > 0)
+ {
+ if (m_DelayedMessageQueue.ElementAtHead()._params)
+ {
+ m_DelayedMessageQueue.ElementAtHead()._params->deleteThis();
+ }
+ m_DelayedMessageQueue.RemoveAtHead();
+ }
+}
+
+/*
+static void*(*staticMalloc)(size_t size)=malloc;
+static void(*staticFree)(void* memblock)=free;
+
+static int g_iMemoryBlocksAllocated = 0;
+
+void *operator new(size_t size)
+{
+ g_iMemoryBlocksAllocated += 1;
+ return staticMalloc(size);
+}
+
+void operator delete(void* memblock)
+{
+ if (!memblock)
+ return;
+
+ g_iMemoryBlocksAllocated -= 1;
+
+ if (g_iMemoryBlocksAllocated < 0)
+ {
+ int x = 3;
+ }
+
+ staticFree(memblock);
+}
+
+void *operator new [] (size_t size)
+{
+ return staticMalloc(size);
+}
+
+void operator delete [] (void *pMem)
+{
+ staticFree(pMem);
+}
+*/
+
+void CVGui::DPrintf(const char* format,...)
+{
+ char buf[2048];
+ va_list argList;
+
+ va_start(argList,format);
+ Q_vsnprintf(buf,sizeof( buf ), format,argList);
+ va_end(argList);
+
+#ifdef WIN32
+ ::OutputDebugString(buf);
+#else
+ Msg( "%s", buf );
+#endif
+}
+
+void CVGui::DPrintf2(const char* format,...)
+{
+ char buf[2048];
+ va_list argList;
+ static int ctr=0;
+
+ Q_snprintf(buf,sizeof( buf ), "%d:",ctr++ );
+
+ va_start(argList,format);
+ Q_vsnprintf(buf+strlen(buf),sizeof( buf )-strlen(buf),format,argList);
+ va_end(argList);
+
+#ifdef WIN32
+ ::OutputDebugString(buf);
+#else
+ Msg( "%s", buf );
+#endif
+}
+
+void vgui::vgui_strcpy(char* dst,int dstLen,const char* src)
+{
+ Assert(dst!=null);
+ Assert(dstLen>=0);
+ Assert(src!=null);
+
+ int srcLen=strlen(src)+1;
+ if(srcLen>dstLen)
+ {
+ srcLen=dstLen;
+ }
+
+ memcpy(dst,src,srcLen-1);
+ dst[srcLen-1]=0;
+}
+
+//-----------------------------------------------------------------------------
+ // HL2/TFC specific stuff
+//-----------------------------------------------------------------------------
+// Here's where the app systems get to learn about each other
+//-----------------------------------------------------------------------------
+bool CVGui::Connect( CreateInterfaceFn factory )
+{
+ if ( !BaseClass::Connect( factory ) )
+ return false;
+
+ if ( !g_pFullFileSystem || !g_pVGuiLocalize )
+ {
+ Warning( "IVGui unable to connect to required interfaces!\n" );
+ return false;
+ }
+
+ return VGui_InternalLoadInterfaces( &factory, 1 );
+}
+
+void CVGui::Disconnect()
+{
+ // FIXME: Blat out interface pointers
+ BaseClass::Disconnect();
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+InitReturnVal_t CVGui::Init()
+{
+ m_hContext = DEFAULT_VGUI_CONTEXT;
+ m_bDebugMessages = CommandLine()->FindParm( "-vguimessages" ) ? true : false;
+
+ InitReturnVal_t nRetVal = BaseClass::Init();
+ if ( nRetVal != INIT_OK )
+ return nRetVal;
+
+ return INIT_OK;
+}
+
+void CVGui::Shutdown()
+{
+ g_pSystem->SaveUserConfigFile();
+
+ DestroyAllContexts();
+ ClearMessageQueues();
+
+ g_pSystem->Shutdown();
+ g_pScheme->Shutdown(true);
+
+ if ( !g_pSurface->QueryInterface( MAT_SYSTEM_SURFACE_INTERFACE_VERSION ) )
+ {
+ g_pSurface->Shutdown();
+ }
+
+ BaseClass::Shutdown();
+}
+
+//-----------------------------------------------------------------------------
+// Here's where systems can access other interfaces implemented by this object
+// Returns NULL if it doesn't implement the requested interface
+//-----------------------------------------------------------------------------
+void *CVGui::QueryInterface( const char *pInterfaceName )
+{
+ // FIXME: Should this go here?
+ // Access other global interfaces exposed by this system...
+ CreateInterfaceFn vguiFactory = Sys_GetFactoryThis();
+ return vguiFactory( pInterfaceName, NULL );
+}
diff --git a/vgui2/src/vgui_dll.vpc b/vgui2/src/vgui_dll.vpc
new file mode 100644
index 0000000..e92dea6
--- /dev/null
+++ b/vgui2/src/vgui_dll.vpc
@@ -0,0 +1,125 @@
+//-----------------------------------------------------------------------------
+// VGUI_DLL.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+$Macro OUTBINNAME "vgui2"
+
+$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE;..\include"
+ $AdditionalIncludeDirectories "$BASE;$SRCDIR\thirdparty"
+ $PreprocessorDefinitions "$BASE;DONT_PROTECT_FILEIO_FUNCTIONS"
+// $TreatWchar_tAsBuiltinType "No"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Imm32.lib Shlwapi.lib odbc32.lib odbccp32.lib winmm.lib" [$WIN32]
+ $SystemLibraries "iconv" [$OSXALL] //||$LINUXALL]
+ $SystemFrameworks "Carbon" [$OSXALL]
+ }
+}
+
+$Project "vgui2"
+{
+ $Folder "Source Files"
+ {
+ $File "Bitmap.cpp"
+ $File "Border.cpp"
+ $File "ScalableImageBorder.cpp"
+ $File "ImageBorder.cpp"
+ $File "fileimage.cpp"
+ $File "$SRCDIR\public\filesystem_helpers.cpp"
+ $File "$SRCDIR\public\filesystem_init.cpp"
+ $File "InputWin32.cpp"
+ $File "LocalizedStringTable.cpp"
+ $File "MemoryBitmap.cpp"
+ $File "Memorybitmap.h"
+ $File "MessageListener.cpp"
+ $File "Scheme.cpp"
+ $File "Surface.cpp" [$WIN32]
+ $File "System.cpp" [$WINDOWS||$X360]
+ $File "system_posix.cpp" [$POSIX]
+ $File "$SRCDIR\public\UnicodeFileHelpers.cpp"
+ $File "vgui.cpp"
+ $File "vgui_internal.cpp"
+ $File "vgui_key_translation.cpp"
+ $File "VPanel.cpp"
+ $File "VPanelWrapper.cpp"
+ $File "keyrepeat.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "bitmap.h"
+ $File "fileimage.h"
+ $File "IMessageListener.h"
+ $File "vgui_internal.h"
+ $File "vgui_key_translation.h"
+ $File "VPanel.h"
+ }
+
+ $Folder "Public Header Files"
+ {
+ $File "$SRCDIR\public\tier0\basetypes.h"
+ $File "$SRCDIR\public\Color.h"
+ $File "$SRCDIR\public\vgui\Cursor.h"
+ $File "$SRCDIR\public\filesystem.h"
+ $File "$SRCDIR\common\vgui_surfacelib\FontAmalgam.h"
+ $File "$SRCDIR\common\vgui_surfacelib\FontManager.h"
+ $File "$SRCDIR\public\tier1\interface.h"
+ $File "$SRCDIR\public\vgui\KeyCode.h"
+ $File "$SRCDIR\common\SteamBootStrapper.h"
+ $File "$SRCDIR\public\tier1\strtools.h"
+ $File "$SRCDIR\public\UnicodeFileHelpers.h"
+ $File "$SRCDIR\public\tier1\utlbuffer.h"
+ $File "$SRCDIR\public\tier1\utllinkedlist.h"
+ $File "$SRCDIR\public\tier1\utlmemory.h"
+ $File "$SRCDIR\public\tier1\utlpriorityqueue.h"
+ $File "$SRCDIR\public\tier1\utlrbtree.h"
+ $File "$SRCDIR\public\tier1\utlvector.h"
+ $File "$SRCDIR\public\mathlib\vector2d.h"
+ $File "$SRCDIR\public\vgui\VGUI.h"
+ $File "$SRCDIR\public\vstdlib\vstdlib.h"
+ $File "$SRCDIR\common\vgui_surfacelib\Win32Font.h"
+ $File "$SRCDIR\public\vgui\KeyRepeat.h"
+ }
+
+ $Folder "Interfaces"
+ {
+ $File "$SRCDIR\public\appframework\IAppSystem.h"
+ $File "$SRCDIR\public\vgui\IBorder.h"
+ $File "$SRCDIR\public\vgui\IClientPanel.h"
+ $File "$SRCDIR\public\vgui\IHTML.h"
+ $File "$SRCDIR\public\vgui\IImage.h"
+ $File "$SRCDIR\public\vgui\IInput.h"
+ $File "$SRCDIR\public\vgui\ILocalize.h"
+ $File "$SRCDIR\public\vgui\IPanel.h"
+ $File "$SRCDIR\public\vgui\IScheme.h"
+ $File "$SRCDIR\public\vgui\ISurface.h"
+ $File "$SRCDIR\public\vgui\ISystem.h"
+ $File "$SRCDIR\public\vgui\IVGui.h"
+ $File "$SRCDIR\public\vgui\IVguiMatInfo.h"
+ $File "$SRCDIR\public\vgui\IVguiMatInfoVar.h"
+ $File "VGUI_Border.h"
+ $File "ScalableImageBorder.h"
+ $File "ImageBorder.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib vgui_surfacelib
+ $Lib tier2
+ $Lib tier3
+ $ImpLib SDL2 [$SDL]
+ }
+
+}
diff --git a/vgui2/src/vgui_internal.cpp b/vgui2/src/vgui_internal.cpp
new file mode 100644
index 0000000..ffcc63a
--- /dev/null
+++ b/vgui2/src/vgui_internal.cpp
@@ -0,0 +1,68 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core implementation of vgui
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "vgui_internal.h"
+
+#include <vgui/ISurface.h>
+#include <vgui/ILocalize.h>
+#include <vgui/IPanel.h>
+#include "filesystem.h"
+#include <vstdlib/IKeyValuesSystem.h>
+
+#include <stdio.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+namespace vgui
+{
+
+ISurface *g_pSurface = NULL;
+IPanel *g_pIPanel = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+static void *InitializeInterface( char const *interfaceName, CreateInterfaceFn *factoryList, int numFactories )
+{
+ void *retval;
+
+ for ( int i = 0; i < numFactories; i++ )
+ {
+ CreateInterfaceFn factory = factoryList[ i ];
+ if ( !factory )
+ continue;
+
+ retval = factory( interfaceName, NULL );
+ if ( retval )
+ return retval;
+ }
+
+ // No provider for requested interface!!!
+ // assert( !"No provider for requested interface!!!" );
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool VGui_InternalLoadInterfaces( CreateInterfaceFn *factoryList, int numFactories )
+{
+ // loads all the interfaces
+ g_pSurface = (ISurface *)InitializeInterface(VGUI_SURFACE_INTERFACE_VERSION, factoryList, numFactories );
+// g_pKeyValues = (IKeyValues *)InitializeInterface(KEYVALUES_INTERFACE_VERSION, factoryList, numFactories );
+ g_pIPanel = (IPanel *)InitializeInterface(VGUI_PANEL_INTERFACE_VERSION, factoryList, numFactories );
+
+ if (g_pSurface && /*g_pKeyValues &&*/ g_pIPanel)
+ return true;
+
+ return false;
+}
+
+} // namespace vgui
diff --git a/vgui2/src/vgui_internal.h b/vgui2/src/vgui_internal.h
new file mode 100644
index 0000000..65d2bfb
--- /dev/null
+++ b/vgui2/src/vgui_internal.h
@@ -0,0 +1,50 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Wraps pointers to basic vgui interfaces
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef VGUI_INTERNAL_H
+#define VGUI_INTERNAL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include "interface.h"
+#include "tier3/tier3.h"
+#include "xbox/xboxstubs.h"
+
+namespace vgui
+{
+
+bool VGui_InternalLoadInterfaces( CreateInterfaceFn *factoryList, int numFactories );
+
+// <vgui/IInputInternal.h> header
+extern class IInputInternal *g_pInput;
+
+// <vgui/IScheme.h> header
+extern class ISchemeManager *g_pScheme;
+
+// <vgui/ISurface.h> header
+extern class ISurface *g_pSurface;
+
+// <vgui/ISystem.h> header
+extern class ISystem *g_pSystem;
+
+// <vgui/IVGui.h> header
+extern class IVGui *g_pIVgui;
+
+// <vgui/IPanel.h> header
+extern class IPanel *g_pIPanel;
+
+// methods
+void vgui_strcpy(char *dst, int dstLen, const char *src);
+} // namespace vgui
+
+
+
+
+#endif // VGUI_INTERNAL_H
diff --git a/vgui2/src/vgui_key_translation.cpp b/vgui2/src/vgui_key_translation.cpp
new file mode 100644
index 0000000..0377a5d
--- /dev/null
+++ b/vgui2/src/vgui_key_translation.cpp
@@ -0,0 +1,42 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#if defined( WIN32 ) && !defined( _X360 )
+#include <wtypes.h>
+#include <winuser.h>
+#include "xbox/xboxstubs.h"
+#endif
+#include "tier0/dbg.h"
+#include "vgui_key_translation.h"
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+#ifdef POSIX
+#define VK_RETURN -1
+#endif
+
+#include "tier2/tier2.h"
+#include "inputsystem/iinputsystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+vgui::KeyCode KeyCode_VirtualKeyToVGUI( int key )
+{
+ // Some tools load vgui for localization and never use input
+ if ( !g_pInputSystem )
+ return KEY_NONE;
+ return g_pInputSystem->VirtualKeyToButtonCode( key );
+}
+
+int KeyCode_VGUIToVirtualKey( vgui::KeyCode code )
+{
+ // Some tools load vgui for localization and never use input
+ if ( !g_pInputSystem )
+ return VK_RETURN;
+
+ return g_pInputSystem->ButtonCodeToVirtualKey( code );
+}
diff --git a/vgui2/src/vgui_key_translation.h b/vgui2/src/vgui_key_translation.h
new file mode 100644
index 0000000..3d08435
--- /dev/null
+++ b/vgui2/src/vgui_key_translation.h
@@ -0,0 +1,20 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef VGUI_KEY_TRANSLATION_H
+#define VGUI_KEY_TRANSLATION_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/KeyCode.h>
+
+// Convert from Windows scan codes to VGUI key codes.
+vgui::KeyCode KeyCode_VirtualKeyToVGUI( int key );
+int KeyCode_VGUIToVirtualKey( vgui::KeyCode keycode );
+
+
+#endif // VGUI_KEY_TRANSLATION_H
diff --git a/vgui2/src/xbox/xbox.def b/vgui2/src/xbox/xbox.def
new file mode 100644
index 0000000..6ccbe24
--- /dev/null
+++ b/vgui2/src/xbox/xbox.def
@@ -0,0 +1,3 @@
+LIBRARY vgui2_360.dll
+EXPORTS
+ CreateInterface @1