VGUI2: Creating a panel: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Rewrite Template:Lang to Template:LanguageBar. This action was performed by a bot.)
 
(63 intermediate revisions by 25 users not shown)
Line 1: Line 1:
[[Category:Programming]][[Category:Tutorials]]
{{LanguageBar|VGUI2: Creating a panel}}
<h3><center>Valve Source Engine / Valve Graphical User Interface 2 (VGUI2) <br> Tutorial: How to create a panel</center></h3>


Note: This is the latest version of the tutorial.
[[Category:Programming]][[Category:Tutorials]][[Category:VGUI|C]]


=Requirements=
==Requirements==
Have read and understood (or understand):<br>
*[[VGUI Documentation]]
*[[HUD Elements]]
Can code:
*C++
*Script
This tutorial is about creating a simple interactive interface


Read:<br>
==Understanding how VGUI2 works==
[[VGUI Documentation]]<br>
[[HUD Elements]]<br>
<br>
Can code:<br>
C++ (!!!!)<br>
<br>
This tutorial is about creating a simple interactive interface.
 
=Understanding how VGUI2 works=
Every VGUI2 dialog that you see while using source based games is basically called a Panel.
Every VGUI2 dialog that you see while using source based games is basically called a Panel.


Every Panel consists of three components:
Every Panel consists of three components:
* Scheme
* Scheme
* Control Settings
* Control Settings
* Code
* Code


'''The Scheme:'''
===The Scheme===


The scheme is a general configuration file which stores information about the colours of certain elements such as buttons, combo boxes, labels, etc. A typical scheme file is SourceScheme.res, for example. If you plan to create a panel which looks like the other panels in the menu you should use the same scheme file as they do.
The scheme is a general configuration file which stores information about the colors of certain elements such as buttons, combo boxes, labels, etc. A typical scheme file is SourceScheme.res, for example. If you plan to create a panel which looks like the other panels in the menu you should use the same scheme file as they do.


'''Control Settings:'''
===Control Settings===


The control settings file stores information about the relative position of your panel and its elements.  
The control settings file stores information about the relative position of your panel and its elements.  
Line 34: Line 30:
Every panel has a very own resource file. To create a resource file, there are two ways: Either you create one on your own using an editor like notepad, or you use Valves InGame Resource Editor.
Every panel has a very own resource file. To create a resource file, there are two ways: Either you create one on your own using an editor like notepad, or you use Valves InGame Resource Editor.


'''Code:'''
===Code===


The code is the most important part of a panel, since the code decides what to do if the user clicks a button. To create and destroy the panel, you use the code. Fortunately you can set a lot more things than in the resource file(s). Code is the most important thing in this tutorial.
The code is the most important part of a panel, since the code decides what to do if the user clicks a button. To create and destroy the panel, you use the code. Fortunately you can set a lot more things than in the resource file(s). Code is the most important thing in this tutorial.


=Creating a panel=
==Creating a panel==
 
Ok, let us assume we want to create a door, for real this time. Since we are not able to create a door from scratch, the first thing we do is to step by at the building centre. What we ask for, is a basic door. It works, but we have still plans to customize it.  
Ok, let us assume we want to create a door, for real this time. Since we are not able to create a door from scratch, the first thing we do is to step by at the building centre. What we ask for, is a basic door. It works, but we have still plans to customize it.  


'''This is the place where we start:'''
===Starting Off===


The panel class is the base class of all VGUI2 elements. To get a rough overview about all the VGUI2  
The panel class is the base class of all VGUI2 elements. To get a rough overview about all the VGUI2  
Line 50: Line 47:
You can create a new file ''MyPanel.cpp'' underneath the Source Files inside the '''client''' project.
You can create a new file ''MyPanel.cpp'' underneath the Source Files inside the '''client''' project.


'''MyPanel.cpp'''
===MyPanel.cpp===
<pre>
//CMyPanel class: Tutorial example class
class CMyPanel : public vgui::Frame
{
DECLARE_CLASS_SIMPLE(CMyPanel, vgui::Frame);
//CMyPanel : This Class / vgui::Frame : BaseClass
 
CMyPanel(vgui::VPANEL parent); // Constructor
~CMyPanel(){}; // Destructor
 
protected:
//VGUI overrides:
virtual void OnTick();
virtual void OnCommand(const char* pcCommand);
 
private:
//Other used VGUI control Elements:
 
};
</pre>


<source lang="cpp">
//The following include files are necessary to allow your MyPanel.cpp to compile.
#include "cbase.h"
#include "IMyPanel.h"
using namespace vgui;
#include <vgui/IVGui.h>
#include <vgui_controls/Frame.h>
//CMyPanel class: Tutorial example class
class CMyPanel : public vgui::Frame
{
DECLARE_CLASS_SIMPLE(CMyPanel, vgui::Frame);
//CMyPanel : This Class / vgui::Frame : BaseClass
CMyPanel(vgui::VPANEL parent); // Constructor
~CMyPanel(){}; // Destructor
protected:
//VGUI overrides:
virtual void OnTick();
virtual void OnCommand(const char* pcCommand);
private:
//Other used VGUI control Elements:
};
</source>


The constructor:
The constructor:
The argument is vgui::VPANEL parent. After reading the [[VGUI Documentation]], you should know that and why every panel has a parent.  
The argument is vgui::VPANEL parent. After reading the [[VGUI Documentation]], you should know that every panel has a parent and why it has a parent.  


Underneath the above code, add:
Underneath the above code, add:
<pre>
<source lang="cpp">
// Constuctor: Initializes the Panel
// Constuctor: Initializes the Panel
CMyPanel::CMyPanel(vgui::VPANEL parent)
CMyPanel::CMyPanel(vgui::VPANEL parent)
Line 87: Line 91:
SetMouseInputEnabled( true );
SetMouseInputEnabled( true );
SetProportional( true );
SetProportional( false );
SetTitleBarVisible( true );
SetTitleBarVisible( true );
SetMinimizeButtonVisible( false );
SetMinimizeButtonVisible( false );
Line 99: Line 103:
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));


LoadControlSettings("resource/UI/MyPanel.res");
LoadControlSettings("resource/UI/mypanel.res");


vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
Line 105: Line 109:
DevMsg("MyPanel has been constructed\n");
DevMsg("MyPanel has been constructed\n");
}
}
</pre>
</source>


The first lines are pretty easy to understand. SetScheme is used to set the source scheme, which is the standard scheme for Half-Life 2. We get a pointer to the scheme by calling LoadSchemeFromFile(...). The LoadControlSettings function is used to load the control settings resolution file. The last line is explained in the VGUI2 documentation.
The first lines are pretty easy to understand. SetScheme is used to set the source scheme, which is the standard scheme for Half-Life 2. We get a pointer to the scheme by calling LoadSchemeFromFile(...). The LoadControlSettings function is used to load the control settings resolution file. The last line is explained in the VGUI2 documentation.
The SetProportional( false ); function decides to make the panel big or small, having it set to true will cause your panel to have big fonts, controls etc.
Finally, if you're going to edit it with the VGUI Build Mode Editor, you will need precreate the directory it goes into, and posibly give your resource an all-lower-case name [See also the Discussion page]


Underneath the above code, add:
Underneath the above code, add:
<pre>
<source lang="cpp">
//Class: CMyPanelInterface Class. Used for construction.
//Class: CMyPanelInterface Class. Used for construction.
class CMyPanelInterface : public IMyPanel
class CMyPanelInterface : public IMyPanel
Line 137: Line 145:
IMyPanel* mypanel = (IMyPanel*)&g_MyPanel;
IMyPanel* mypanel = (IMyPanel*)&g_MyPanel;


</pre>
void CMyPanel::OnTick()
{
BaseClass::OnTick();
}
 
void CMyPanel::OnCommand(const char* pcCommand)
{
BaseClass::OnCommand(pcCommand);
}
</source>


Next you can create ''IMyPanel.h'' in the same folder.
Next you can create ''IMyPanel.h'' in the same folder.


'''IMyPanel.h'''
===IMyPanel.h===
<pre>
<source lang="cpp">


// IMyPanel.h
// IMyPanel.h
Line 153: Line 170:


extern IMyPanel* mypanel;
extern IMyPanel* mypanel;
</pre>
</source>


=Calling the panel=
==Calling the panel==


To call the panel, we add a few lines to the '''vgui_int.cpp''' file. Vgui_int.cpp includes functions which call all the panels. The VGui_CreateGlobalPanels() function is where the addition takes place.
To call the panel, we add a few lines to the '''vgui_int.cpp''' file. Vgui_int.cpp includes functions which call all the panels. The VGui_CreateGlobalPanels() function is where the addition takes place.
Line 163: Line 180:
I assume that you want to create a panel for the game.
I assume that you want to create a panel for the game.


So, after including the panel, you should add
So, after including the panel, you should add at VGui_CreateGlobalPanels() the following:


<pre>mypanel->Create(gameParent);</pre>
<source lang="cpp">mypanel->Create(gameParent);</source>


and
and check to see if gameParent has been declared at the top of the function, if it hasn't then add


<pre>mypanel->Destroy();</pre>
<source lang="cpp">VPANEL gameParent = enginevgui->GetPanel( PANEL_CLIENTDLL );</source>
''Note: To have your screen appear in-game like the Counter-Strike buy menus or team selection menus, change '' '''PANEL_CLIENTDLL''' ''to'' '''PANEL_INGAMESCREENS''' '', otherwise it will be visible only when you press Escape to go to the game menu.''


''Note: Dont forget to add


to the VGui_Shutdown() function.
<source lang="cpp">#include "IMyPanel.h"</source>
 
to vgui_int.cpp file.
 
Then add this line into the VGui_Shutdown() function.
 
<source lang="cpp">mypanel->Destroy();</source>


If you plan to create a panel for the main menu, you need to put this into the construction function (''VGui_CreateGlobalPanels()''):
If you plan to create a panel for the main menu, you need to put this into the construction function (''VGui_CreateGlobalPanels()''):


<pre>VPANEL GameUiDll = enginevgui->GetPanel( PANEL_GAMEUIDLL);
<source lang="cpp">VPANEL GameUiDll = enginevgui->GetPanel( PANEL_GAMEUIDLL);
mypanel->Create(GameUiDll);
mypanel->Create(GameUiDll);
</pre>
</source>


This will cause the panel to appear when you start your mod.
This will cause the panel to appear when you start your mod.


=The control settings=
Everything is working, so start the game, and chcek if you see your panel. Now you have the chance to press CTRL+ALT+SHIFT+B in order to use the VGUI2 Builder. You can drag around the panel and set some properties as well as adding some elements. Do not forget to save your work afterwards.


=Adding elements=
==Adding elements==
There are two ways to add new elements. The one way is to use the VGUI2 Builder. Since the VGUI2 Builder doesn’t come with all the essential elements, you should add elements in your code. Therefore, you have the choice in-between 50 elements, individually stored in the vgui_controls folder. Indeed, even this is pretty easy. You add a pointer into the class declaration. Here is an example:
There are two ways to add new elements. One is to use the VGUI2 Builder (Press CTRL+SHIFT+ALT+B to open it). Since the VGUI2 Builder doesn’t come with all the essential elements, you should add elements in your code. Therefore, you have the choice in-between 50 elements, individually stored in the vgui_controls folder. Indeed, even this is pretty easy. You add a pointer into the class declaration. Here is an example:


<pre>vgui::TextEntry* m_pMyTextEntry; // Panel class declaration, private section</pre>
<source lang="cpp">vgui::TextEntry* m_pTime; // Panel class declaration, private section</source>


Add this to the panels constructor:
Add this to the panels constructor:


<pre>
<source lang="cpp">
m_pMyTextEntry = new vgui::TextEntry(this, "MyTextEntry");
m_pTime = new vgui::TextEntry(this, "MyTextEntry");
m_pTime->SetPos(15, 310);
m_pTime->SetPos(15, 310);
m_pTime->SetSize(50, 20);
m_pTime->SetSize(50, 20);
</pre>
</source>
 
You'll also have to add the following include to get the constructors for TextEntry:
 
<source lang="cpp">#include <vgui_controls/TextEntry.h></source>
 
==Making it open with pressing a new option at the main menu==
It is time to make it appear after pressing a new option that we will add to the main menu. On this example, we will use a variable which allows us to set the state of our panel, combined with a button. Here is the example:
 
===MyPanel.cpp===
 
On start, add at the top under <vgui_controls/Frame.h> the following include, so we can add buttons at the code for our panel:
 
<source lang="cpp">
#include <vgui_controls/Button.h>
</source>


=Other stuff=
Add this variable into the private declaration. It will allows you to create later a button for the panel so it can close it:
Let's do some console stuff. For example, we could need a variable which allows us to set the state of our panel. <br>Here is an example:  


'''MyPanel.cpp'''
<source lang="cpp">
private:
//Other used VGUI control Elements:
Button *m_pCloseButton;
</source>


Underneath all of the other code, add:
Underneath all of the other code, add:


<pre>
<source lang="cpp">
ConVar cl_showmypanel("cl_showmypanel", "1", FCVAR_CLIENTDLL, "Sets the state of myPanel <state>");</pre>
ConVar cl_showmypanel("cl_showmypanel", "0", FCVAR_CLIENTDLL, "Sets the state of myPanel <state>");</source>


This code doesn’t need some explanation, so we continue by adding a method to our class:
This line defines a new CVAR that it will make show or hide our new panel. Now continue by adding the following line at OnTick():


<pre>void CMyPanel::OnTick()
<source lang="cpp">
void CMyPanel::OnTick()
{
{
BaseClass::OnTick();
BaseClass::OnTick();
SetVisible(cl_showmypanel.GetBool()); //CL_SHOWMYPANEL / 1 BY DEFAULT
SetVisible(cl_showmypanel.GetBool()); //CL_SHOWMYPANEL / 1 BY DEFAULT
}</pre>
}</source>
 
On next, add a command to toggle the panel on or off:


A command to toggle the panel on or off:
<source lang="cpp">
<pre>
CON_COMMAND(ToggleMyPanel, "Toggles myPanel on or off")
CON_COMMAND(ToggleMyPanel, "Toggles myPanel on or off")
{
{
cl_showmypanel.SetValue(!cl_showmypanel.GetBool());
cl_showmypanel.SetValue(!cl_showmypanel.GetBool());
};
};
</pre>
</source>


=InterActive Elements=
In the last part of this tutorial we will add a button that it will make close the panel on pressing it. Add the following at the OnCommand() part:
In the last part of this tutorial we will add some functionality to a button.


<pre>
<source lang="cpp">
void CMyPanel::OnCommand(const char* pcCommand)
void CMyPanel::OnCommand(const char* pcCommand)
{
{
BaseClass::OnCommand(pcCommand);
if(!Q_stricmp(pcCommand, "turnoff"))
if(!Q_stricmp(pcCommand, "turnoff"))
cl_showmypanel.SetValue(0);
cl_showmypanel.SetValue(0);
}
}
</pre>
</source>
 
You can add a button (using the built-in editor) and set the command value of the button to "turnoff". If the player clicks this button, well, the panel disappers.


=Main Menu=
This will recieve the command "turnoff" that gets sent when we press the button, and on next, it will set cl_showmypanel to 0, closing the panel.


To link to your new panel from the main menu, open up '''GameMenu.res''' in your ''/resource/'' folder. Add:
Create the button itself at the panels constructor (you can do it too at the RES file, but coding it will allow you to have more customization options):


<pre>
<source lang="cpp">
"5"
m_pCloseButton = new Button(this, "Button", "Close", this, "turnoff");
{
m_pCloseButton->SetPos(433, 472);
"label" "My Panel"
m_pCloseButton->SetDepressedSound("common/bugreporter_succeeded.wav");
"command" "engine ToggleMyPanel"
m_pCloseButton->SetReleasedSound("ui/buttonclick.wav");
"notmulti" "1"
</source>
}
</pre>


And change <code>ConVar cl_showmypanel("cl_showmypanel", "1", FCVAR_CLIENTDLL, "Sets the state of myPanel <state>");</code>
We are creating a button that is parented with the panel, is called "Button", it has written on it "Close", it sends the command "turnoff", it is set to appear at botton right of our panel, and it will make two sounds, one when pressed, and another when released.


To: <code>ConVar cl_showmypanel("cl_showmypanel", "0", FCVAR_CLIENTDLL, "Sets the state of myPanel <state>");</code>
Now add <source lang="cpp">mypanel->Activate();</source> underneath <source lang="cpp">cl_showmypanel.SetValue(!cl_showmypanel.GetBool());</source>. This will
focus (bring it at the front of the screen, over all the panels) on your panel. To be able use the Activate() command, you will need to add in '''MyPanel.cpp'''.:


So that it won't pop up before the user clicks it.
<source lang="cpp">
 
You may also want to add <code>mypanel->Activate();</code> underneath <code>cl_showmypanel.SetValue(!cl_showmypanel.GetBool());</code>. This will
focus on your panel. To be able to use the Activate() command, you will need to add:
 
<pre>
void Activate( void )
void Activate( void )
{
{
Line 267: Line 302:
}
}
}
}
</pre>
</source>


Underneath:
Underneath:


<pre>
<source lang="cpp">
void Destroy( void )
void Destroy( void )
{
{
Line 280: Line 315:
}
}
}
}
</pre>
</source>


In '''MyPanel.cpp'''.
And add in '''IMyPanel.h'''.:


And add:
<source lang="cpp">
 
<pre>
virtual void Activate( void ) = 0;
virtual void Activate( void ) = 0;
</pre>
</source>


Underneath:
Underneath:
<source lang="cpp">
virtual void Destroy( void ) = 0;
</source>
==Main Menu and the panel res file==
To open to your new panel from the main menu, open up '''GameMenu.res''' in your ''/resource/'' folder, and add:


<pre>
<pre>
virtual void Destroy( void ) = 0;
"5"//Actually this number must be in order with the rest of elements
{
"label" "My Panel"
"command" "engine ToggleMyPanel"
"notmulti" "1" //Add this only if you don't want to show this option while on a multiplayer game ("notsingle" "1" for singleplayer)
}
</pre>
</pre>
(There are more examples of the possible variables [[GameMenu|here]]).
This adds on the position 5 a new option called My Panel, that on press, it will send the command "ToggleMyPanel".
And for the last step, create your panel RES design (this tutorial creates one at the ui folder inside resource). You can use the following as example:
<div style="max-height:30em; overflow:auto;"><pre>
"resource/ui/mypanel.res"
{
"MyPanel"
{
"ControlName" "CMyPanel"
"fieldName" "MyPanel"
"xpos" "797"
"ypos" "301"
"wide" "512"
"tall" "512"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"settitlebarvisible" "1"
"title" "MOD OPTIONS"
}
"frame_topGrip"
{
"ControlName" "Panel"
"fieldName" "frame_topGrip"
"xpos" "8"
"ypos" "0"
"wide" "496"
"tall" "5"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_bottomGrip"
{
"ControlName" "Panel"
"fieldName" "frame_bottomGrip"
"xpos" "8"
"ypos" "507"
"wide" "486"
"tall" "5"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_leftGrip"
{
"ControlName" "Panel"
"fieldName" "frame_leftGrip"
"xpos" "0"
"ypos" "8"
"wide" "5"
"tall" "496"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_rightGrip"
{
"ControlName" "Panel"
"fieldName" "frame_rightGrip"
"xpos" "507"
"ypos" "8"
"wide" "5"
"tall" "486"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_tlGrip"
{
"ControlName" "Panel"
"fieldName" "frame_tlGrip"
"xpos" "0"
"ypos" "0"
"wide" "8"
"tall" "8"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_trGrip"
{
"ControlName" "Panel"
"fieldName" "frame_trGrip"
"xpos" "504"
"ypos" "0"
"wide" "8"
"tall" "8"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_blGrip"
{
"ControlName" "Panel"
"fieldName" "frame_blGrip"
"xpos" "0"
"ypos" "504"
"wide" "8"
"tall" "8"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_brGrip"
{
"ControlName" "Panel"
"fieldName" "frame_brGrip"
"xpos" "494"
"ypos" "494"
"wide" "18"
"tall" "18"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_caption"
{
"ControlName" "Panel"
"fieldName" "frame_caption"
"xpos" "3"
"ypos" "-16"
"wide" "502"
"tall" "23"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
}
"frame_minimize"
{
"ControlName" "Button"
"fieldName" "frame_minimize"
"xpos" "0"
"ypos" "0"
"wide" "18"
"tall" "18"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "0"
"enabled" "1"
"tabPosition" "0"
"labelText" "0"
"textAlignment" "north-west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"centerwrap" "0"
"textinsetx" "2"
"textinsety" "1"
"auto_wide_tocontents" "0"
"use_proportional_insets" "0"
"Default" "0"
}
"frame_maximize"
{
"ControlName" "Button"
"fieldName" "frame_maximize"
"xpos" "0"
"ypos" "0"
"wide" "18"
"tall" "18"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "0"
"enabled" "1"
"tabPosition" "0"
"labelText" "1"
"textAlignment" "north-west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"centerwrap" "0"
"textinsetx" "2"
"textinsety" "1"
"auto_wide_tocontents" "0"
"use_proportional_insets" "0"
"Default" "0"
}
"frame_mintosystray"
{
"ControlName" "Button"
"fieldName" "frame_mintosystray"
"xpos" "0"
"ypos" "0"
"wide" "18"
"tall" "18"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "0"
"enabled" "1"
"tabPosition" "0"
"labelText" "o"
"textAlignment" "north-west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"centerwrap" "0"
"textinsetx" "2"
"textinsety" "1"
"auto_wide_tocontents" "0"
"use_proportional_insets" "0"
"command" "MinimizeToSysTray"
"Default" "0"
}
"frame_close"
{
"ControlName" "Button"
"fieldName" "frame_close"
"xpos" "487"
"ypos" "8"
"wide" "18"
"tall" "18"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"labelText" "r"
"textAlignment" "north-west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"centerwrap" "0"
"textinsetx" "2"
"textinsety" "1"
"auto_wide_tocontents" "0"
"use_proportional_insets" "0"
"Default" "0"
"command" "turnoff"
}
"frame_menu"
{
"ControlName" "FrameSystemButton"
"fieldName" "frame_menu"
"xpos" "7"
"ypos" "8"
"wide" "18"
"tall" "18"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"textAlignment" "west"
"dulltext" "0"
"brighttext" "0"
"wrap" "0"
"centerwrap" "0"
"textinsetx" "0"
"textinsety" "0"
"auto_wide_tocontents" "0"
"use_proportional_insets" "0"
"Default" "0"
}
"BuildModeDialog"
{
"ControlName" "BuildModeDialog"
"fieldName" "BuildModeDialog"
"xpos" "327"
"ypos" "301"
"wide" "300"
"tall" "420"
"autoResize" "0"
"pinCorner" "0"
"RoundedCorners" "15"
"pin_corner_to_sibling" "0"
"pin_to_sibling_corner" "0"
"visible" "1"
"enabled" "1"
"tabPosition" "0"
"settitlebarvisible" "1"
"title" "#Frame_Untitled"
}
}
</pre></div>
==Final result==
This is how it should look at the end both your Cpp and header files:
'''MyPanel.cpp'''
<div style="max-height:30em; overflow:auto;">
<source lang="cpp">
//The following include files are necessary to allow your MyPanel.cpp to compile.
#include "cbase.h"
#include "IMyPanel.h"
using namespace vgui;
#include <vgui/IVGui.h>
#include <vgui_controls/Frame.h>
#include <vgui_controls/Button.h>
//CMyPanel class: Tutorial example class
class CMyPanel : public vgui::Frame
{
DECLARE_CLASS_SIMPLE(CMyPanel, vgui::Frame);
//CMyPanel : This Class / vgui::Frame : BaseClass
CMyPanel(vgui::VPANEL parent); // Constructor
~CMyPanel(){}; // Destructor
protected:
//VGUI overrides:
virtual void OnTick();
virtual void OnCommand(const char* pcCommand);
private:
//Other used VGUI control Elements:
Button *m_pCloseButton;
};
// Constuctor: Initializes the Panel
CMyPanel::CMyPanel(vgui::VPANEL parent)
: BaseClass(NULL, "MyPanel")
{
SetParent(parent);
SetKeyBoardInputEnabled(true);
SetMouseInputEnabled(true);
SetProportional(false);
SetTitleBarVisible(true);
SetMinimizeButtonVisible(false);
SetMaximizeButtonVisible(false);
SetCloseButtonVisible(false);
SetSizeable(false);
SetMoveable(false);
SetVisible(true);
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
LoadControlSettings("resource/UI/playermodelsel.res");
vgui::ivgui()->AddTickSignal(GetVPanel(), 100);
DevMsg("MyPanel has been constructed\n");
//Button done
m_pCloseButton = new Button(this, "Button", "Close", this, "turnoff");
m_pCloseButton->SetPos(433, 472);
m_pCloseButton->SetDepressedSound("common/bugreporter_succeeded.wav");
m_pCloseButton->SetReleasedSound("ui/buttonclick.wav");
}
//Class: CMyPanelInterface Class. Used for construction.
class CMyPanelInterface : public MyPanel
{
private:
CMyPanel *MyPanel;
public:
CMyPanelInterface()
{
MyPanel = NULL;
}
void Create(vgui::VPANEL parent)
{
MyPanel = new CMyPanel(parent);
}
void Destroy()
{
if (MyPanel)
{
MyPanel->SetParent((vgui::Panel *)NULL);
delete MyPanel;
}
}
void Activate(void)
{
if (MyPanel)
{
MyPanel->Activate();
}
}
};
static CMyPanelInterface g_MyPanel;
MyPanel* mypanel = (MyPanel*)&g_MyPanel;
ConVar cl_showmypanel("cl_showmypanel", "0", FCVAR_CLIENTDLL, "Sets the state of myPanel <state>");
void CMyPanel::OnTick()
{
BaseClass::OnTick();
SetVisible(cl_showmypanel.GetBool());
}
CON_COMMAND(OpenTestPanelFenix, "Toggles testpanelfenix on or off")
{
cl_showmypanel.SetValue(!cl_showmypanel.GetBool());
mypanel->Activate();
};
void CMyPanel::OnCommand(const char* pcCommand)
{
BaseClass::OnCommand(pcCommand);
if (!Q_stricmp(pcCommand, "turnoff"))
cl_showmypanel.SetValue(0);
}
</source></div>
'''IMyPanel.h'''
<source lang="cpp">
class MyPanel
{
public:
virtual void Create(vgui::VPANEL parent) = 0;
virtual void Destroy(void) = 0;
virtual void Activate(void) = 0;
};
extern MyPanel* mypanel;
</source>
Now compile your files, boot your mod, and press the new option that it should appear at the main menu. If everything goes fine, a panel will open, and pressing the button "Close" will close it. You can also close it by pressing again the main menu option, since we made it toggle.
==Makefile changes on Linux==
In source-sdk-2013/mp/src/game/client/client_linux32_hl2mp.mak (for multiplayer), you need to add a mention of your new file to the list of files to be built, and then a recipe to build it.
First, add the .cpp file to the list to be built:
<source lang="make">
CPPFILES= \
    MyPanel.cpp \
    ../../common/compiledcaptionswap.cpp \
    ../../common/language.cpp \
    ...
</source>
Then, down near  the "recipe" for vgui_int.cpp, add the following recipe to build MyPanel:
<source lang="make">
ifneq (clean, $(findstring clean, $(MAKECMDGOALS)))
-include $(OBJ_DIR)/MyPanel.P
endif


In '''IMyPanel.h'''.
$(OBJ_DIR)/MyPanel.o : $(PWD)/MyPanel.cpp $(PWD)/client_linux32_hl2mp.mak $(SRCROOT)/devtools/makefile_base_posix.mak
        $(PRE_COMPILE_FILE)
        $(COMPILE_FILE) $(POST_COMPILE_FILE)
</source>


If you want the user to be able to close your panel without having to click the My Panel menu option, add a Button with the command "ToggleMyPanel" to your panel.
==See also==
* [[Modifying Source GameUI]] is a lighter dose of creating your own UI.
* [[VGUI2: Non RES-File Controls|Non RES-File Controls]] are controls that can be compiled in code instead of RES files like in Half-Life 1

Latest revision as of 17:42, 18 July 2025

English (en)Español (es)中文 (zh)Translate (Translate)

Requirements

Have read and understood (or understand):

Can code:

  • C++
  • Script

This tutorial is about creating a simple interactive interface

Understanding how VGUI2 works

Every VGUI2 dialog that you see while using source based games is basically called a Panel.

Every Panel consists of three components:

  • Scheme
  • Control Settings
  • Code

The Scheme

The scheme is a general configuration file which stores information about the colors of certain elements such as buttons, combo boxes, labels, etc. A typical scheme file is SourceScheme.res, for example. If you plan to create a panel which looks like the other panels in the menu you should use the same scheme file as they do.

Control Settings

The control settings file stores information about the relative position of your panel and its elements.

Every panel has a very own resource file. To create a resource file, there are two ways: Either you create one on your own using an editor like notepad, or you use Valves InGame Resource Editor.

Code

The code is the most important part of a panel, since the code decides what to do if the user clicks a button. To create and destroy the panel, you use the code. Fortunately you can set a lot more things than in the resource file(s). Code is the most important thing in this tutorial.

Creating a panel

Ok, let us assume we want to create a door, for real this time. Since we are not able to create a door from scratch, the first thing we do is to step by at the building centre. What we ask for, is a basic door. It works, but we have still plans to customize it.

Starting Off

The panel class is the base class of all VGUI2 elements. To get a rough overview about all the VGUI2 elements, have a look into the vgui_elements folder. Of course, we don't just buy some wood in our local building centre.

The important class is the EditablePanel class that inherits from the Panel class. Our panel will be a new class which inherits from the EditablePanel class. This results in several advantages: We can code methods related to the content of the panel, we can overwrite the methods of the base classes and do much more useful stuff.

You can create a new file MyPanel.cpp underneath the Source Files inside the client project.

MyPanel.cpp

 //The following include files are necessary to allow your MyPanel.cpp to compile.
 #include "cbase.h"
 #include "IMyPanel.h"
 using namespace vgui;
 #include <vgui/IVGui.h>
 #include <vgui_controls/Frame.h>
 
 //CMyPanel class: Tutorial example class
 class CMyPanel : public vgui::Frame
 {
 	DECLARE_CLASS_SIMPLE(CMyPanel, vgui::Frame); 
 	//CMyPanel : This Class / vgui::Frame : BaseClass
 
 	CMyPanel(vgui::VPANEL parent); 	// Constructor
 	~CMyPanel(){};				// Destructor
 
 protected:
 	//VGUI overrides:
 	virtual void OnTick();
 	virtual void OnCommand(const char* pcCommand);
 
 private:
 	//Other used VGUI control Elements:
 
 };

The constructor: The argument is vgui::VPANEL parent. After reading the VGUI Documentation, you should know that every panel has a parent and why it has a parent.

Underneath the above code, add:

// Constuctor: Initializes the Panel
CMyPanel::CMyPanel(vgui::VPANEL parent)
: BaseClass(NULL, "MyPanel")
{
	SetParent( parent );
	
	SetKeyBoardInputEnabled( true );
	SetMouseInputEnabled( true );
	
	SetProportional( false );
	SetTitleBarVisible( true );
	SetMinimizeButtonVisible( false );
	SetMaximizeButtonVisible( false );
	SetCloseButtonVisible( false );
	SetSizeable( false );
	SetMoveable( false );
	SetVisible( true );


	SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));

	LoadControlSettings("resource/UI/mypanel.res");

	vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
	
	DevMsg("MyPanel has been constructed\n");
}

The first lines are pretty easy to understand. SetScheme is used to set the source scheme, which is the standard scheme for Half-Life 2. We get a pointer to the scheme by calling LoadSchemeFromFile(...). The LoadControlSettings function is used to load the control settings resolution file. The last line is explained in the VGUI2 documentation.

The SetProportional( false ); function decides to make the panel big or small, having it set to true will cause your panel to have big fonts, controls etc.

Finally, if you're going to edit it with the VGUI Build Mode Editor, you will need precreate the directory it goes into, and posibly give your resource an all-lower-case name [See also the Discussion page]

Underneath the above code, add:

//Class: CMyPanelInterface Class. Used for construction.
class CMyPanelInterface : public IMyPanel
{
private:
	CMyPanel *MyPanel;
public:
	CMyPanelInterface()
	{
		MyPanel = NULL;
	}
	void Create(vgui::VPANEL parent)
	{
		MyPanel = new CMyPanel(parent);
	}
	void Destroy()
	{
		if (MyPanel)
		{
			MyPanel->SetParent( (vgui::Panel *)NULL);
			delete MyPanel;
		}
	}
};
static CMyPanelInterface g_MyPanel;
IMyPanel* mypanel = (IMyPanel*)&g_MyPanel;

void CMyPanel::OnTick()
{
	BaseClass::OnTick();
}

void CMyPanel::OnCommand(const char* pcCommand)
{
	BaseClass::OnCommand(pcCommand);
}

Next you can create IMyPanel.h in the same folder.

IMyPanel.h

// IMyPanel.h
class IMyPanel
{
public:
	virtual void		Create( vgui::VPANEL parent ) = 0;
	virtual void		Destroy( void ) = 0;
};

extern IMyPanel* mypanel;

Calling the panel

To call the panel, we add a few lines to the vgui_int.cpp file. Vgui_int.cpp includes functions which call all the panels. The VGui_CreateGlobalPanels() function is where the addition takes place.

This is the point, where you have to decide when the panel should show up. Either you create a panel that can be accessed during the game, or you create a panel for the main menu.

I assume that you want to create a panel for the game.

So, after including the panel, you should add at VGui_CreateGlobalPanels() the following:

mypanel->Create(gameParent);

and check to see if gameParent has been declared at the top of the function, if it hasn't then add

VPANEL gameParent = enginevgui->GetPanel( PANEL_CLIENTDLL );

Note: To have your screen appear in-game like the Counter-Strike buy menus or team selection menus, change PANEL_CLIENTDLL to PANEL_INGAMESCREENS , otherwise it will be visible only when you press Escape to go to the game menu.

Note: Dont forget to add

#include "IMyPanel.h"

to vgui_int.cpp file.

Then add this line into the VGui_Shutdown() function.

mypanel->Destroy();

If you plan to create a panel for the main menu, you need to put this into the construction function (VGui_CreateGlobalPanels()):

VPANEL GameUiDll = enginevgui->GetPanel( PANEL_GAMEUIDLL);
mypanel->Create(GameUiDll);

This will cause the panel to appear when you start your mod.


Adding elements

There are two ways to add new elements. One is to use the VGUI2 Builder (Press CTRL+SHIFT+ALT+B to open it). Since the VGUI2 Builder doesn’t come with all the essential elements, you should add elements in your code. Therefore, you have the choice in-between 50 elements, individually stored in the vgui_controls folder. Indeed, even this is pretty easy. You add a pointer into the class declaration. Here is an example:

vgui::TextEntry* m_pTime; // Panel class declaration, private section

Add this to the panels constructor:

m_pTime = new vgui::TextEntry(this, "MyTextEntry");
m_pTime->SetPos(15, 310);
m_pTime->SetSize(50, 20);

You'll also have to add the following include to get the constructors for TextEntry:

#include <vgui_controls/TextEntry.h>

Making it open with pressing a new option at the main menu

It is time to make it appear after pressing a new option that we will add to the main menu. On this example, we will use a variable which allows us to set the state of our panel, combined with a button. Here is the example:

MyPanel.cpp

On start, add at the top under <vgui_controls/Frame.h> the following include, so we can add buttons at the code for our panel:

#include <vgui_controls/Button.h>

Add this variable into the private declaration. It will allows you to create later a button for the panel so it can close it:

private:
	//Other used VGUI control Elements:
	Button *m_pCloseButton;

Underneath all of the other code, add:

ConVar cl_showmypanel("cl_showmypanel", "0", FCVAR_CLIENTDLL, "Sets the state of myPanel <state>");

This line defines a new CVAR that it will make show or hide our new panel. Now continue by adding the following line at OnTick():

void CMyPanel::OnTick()
{
	BaseClass::OnTick();
	SetVisible(cl_showmypanel.GetBool()); //CL_SHOWMYPANEL / 1 BY DEFAULT
}

On next, add a command to toggle the panel on or off:

CON_COMMAND(ToggleMyPanel, "Toggles myPanel on or off")
{
	cl_showmypanel.SetValue(!cl_showmypanel.GetBool());
};

In the last part of this tutorial we will add a button that it will make close the panel on pressing it. Add the following at the OnCommand() part:

void CMyPanel::OnCommand(const char* pcCommand)
{
	BaseClass::OnCommand(pcCommand);
	if(!Q_stricmp(pcCommand, "turnoff"))
		cl_showmypanel.SetValue(0);
}

This will recieve the command "turnoff" that gets sent when we press the button, and on next, it will set cl_showmypanel to 0, closing the panel.

Create the button itself at the panels constructor (you can do it too at the RES file, but coding it will allow you to have more customization options):

m_pCloseButton = new Button(this, "Button", "Close", this, "turnoff");
m_pCloseButton->SetPos(433, 472);
m_pCloseButton->SetDepressedSound("common/bugreporter_succeeded.wav");
m_pCloseButton->SetReleasedSound("ui/buttonclick.wav");

We are creating a button that is parented with the panel, is called "Button", it has written on it "Close", it sends the command "turnoff", it is set to appear at botton right of our panel, and it will make two sounds, one when pressed, and another when released.

Now add

mypanel->Activate();

underneath

cl_showmypanel.SetValue(!cl_showmypanel.GetBool());

. This will

focus (bring it at the front of the screen, over all the panels) on your panel. To be able use the Activate() command, you will need to add in MyPanel.cpp.:

	void Activate( void )
	{
		if ( MyPanel )
		{
			MyPanel->Activate();
		}
	}

Underneath:

	void Destroy( void )
	{
		if ( MyPanel )
		{
			MyPanel->SetParent( (vgui::Panel *)NULL );
			delete MyPanel;
		}
	}

And add in IMyPanel.h.:

virtual void		Activate( void ) = 0;

Underneath:

virtual void		Destroy( void ) = 0;

Main Menu and the panel res file

To open to your new panel from the main menu, open up GameMenu.res in your /resource/ folder, and add:

	"5"//Actually this number must be in order with the rest of elements
	{
		"label" "My Panel"
		"command" "engine ToggleMyPanel"
		"notmulti" "1" //Add this only if you don't want to show this option while on a multiplayer game ("notsingle" "1" for singleplayer)
	}

(There are more examples of the possible variables here).

This adds on the position 5 a new option called My Panel, that on press, it will send the command "ToggleMyPanel".

And for the last step, create your panel RES design (this tutorial creates one at the ui folder inside resource). You can use the following as example:

"resource/ui/mypanel.res"
{
	"MyPanel"
	{
		"ControlName"		"CMyPanel"
		"fieldName"		"MyPanel"
		"xpos"		"797"
		"ypos"		"301"
		"wide"		"512"
		"tall"		"512"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
		"settitlebarvisible"		"1"
		"title"		"MOD OPTIONS"
	}
	"frame_topGrip"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_topGrip"
		"xpos"		"8"
		"ypos"		"0"
		"wide"		"496"
		"tall"		"5"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_bottomGrip"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_bottomGrip"
		"xpos"		"8"
		"ypos"		"507"
		"wide"		"486"
		"tall"		"5"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_leftGrip"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_leftGrip"
		"xpos"		"0"
		"ypos"		"8"
		"wide"		"5"
		"tall"		"496"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_rightGrip"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_rightGrip"
		"xpos"		"507"
		"ypos"		"8"
		"wide"		"5"
		"tall"		"486"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_tlGrip"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_tlGrip"
		"xpos"		"0"
		"ypos"		"0"
		"wide"		"8"
		"tall"		"8"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_trGrip"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_trGrip"
		"xpos"		"504"
		"ypos"		"0"
		"wide"		"8"
		"tall"		"8"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_blGrip"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_blGrip"
		"xpos"		"0"
		"ypos"		"504"
		"wide"		"8"
		"tall"		"8"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_brGrip"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_brGrip"
		"xpos"		"494"
		"ypos"		"494"
		"wide"		"18"
		"tall"		"18"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_caption"
	{
		"ControlName"		"Panel"
		"fieldName"		"frame_caption"
		"xpos"		"3"
		"ypos"		"-16"
		"wide"		"502"
		"tall"		"23"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
	}
	"frame_minimize"
	{
		"ControlName"		"Button"
		"fieldName"		"frame_minimize"
		"xpos"		"0"
		"ypos"		"0"
		"wide"		"18"
		"tall"		"18"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"0"
		"enabled"		"1"
		"tabPosition"		"0"
		"labelText"		"0"
		"textAlignment"		"north-west"
		"dulltext"		"0"
		"brighttext"		"0"
		"wrap"		"0"
		"centerwrap"		"0"
		"textinsetx"		"2"
		"textinsety"		"1"
		"auto_wide_tocontents"		"0"
		"use_proportional_insets"		"0"
		"Default"		"0"
	}
	"frame_maximize"
	{
		"ControlName"		"Button"
		"fieldName"		"frame_maximize"
		"xpos"		"0"
		"ypos"		"0"
		"wide"		"18"
		"tall"		"18"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"0"
		"enabled"		"1"
		"tabPosition"		"0"
		"labelText"		"1"
		"textAlignment"		"north-west"
		"dulltext"		"0"
		"brighttext"		"0"
		"wrap"		"0"
		"centerwrap"		"0"
		"textinsetx"		"2"
		"textinsety"		"1"
		"auto_wide_tocontents"		"0"
		"use_proportional_insets"		"0"
		"Default"		"0"
	}
	"frame_mintosystray"
	{
		"ControlName"		"Button"
		"fieldName"		"frame_mintosystray"
		"xpos"		"0"
		"ypos"		"0"
		"wide"		"18"
		"tall"		"18"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"0"
		"enabled"		"1"
		"tabPosition"		"0"
		"labelText"		"o"
		"textAlignment"		"north-west"
		"dulltext"		"0"
		"brighttext"		"0"
		"wrap"		"0"
		"centerwrap"		"0"
		"textinsetx"		"2"
		"textinsety"		"1"
		"auto_wide_tocontents"		"0"
		"use_proportional_insets"		"0"
		"command"		"MinimizeToSysTray"
		"Default"		"0"
	}
	"frame_close"
	{
		"ControlName"		"Button"
		"fieldName"		"frame_close"
		"xpos"		"487"
		"ypos"		"8"
		"wide"		"18"
		"tall"		"18"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
		"labelText"		"r"
		"textAlignment"		"north-west"
		"dulltext"		"0"
		"brighttext"		"0"
		"wrap"		"0"
		"centerwrap"		"0"
		"textinsetx"		"2"
		"textinsety"		"1"
		"auto_wide_tocontents"		"0"
		"use_proportional_insets"		"0"
		"Default"		"0"
		"command"	"turnoff"
	}
	"frame_menu"
	{
		"ControlName"		"FrameSystemButton"
		"fieldName"		"frame_menu"
		"xpos"		"7"
		"ypos"		"8"
		"wide"		"18"
		"tall"		"18"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
		"textAlignment"		"west"
		"dulltext"		"0"
		"brighttext"		"0"
		"wrap"		"0"
		"centerwrap"		"0"
		"textinsetx"		"0"
		"textinsety"		"0"
		"auto_wide_tocontents"		"0"
		"use_proportional_insets"		"0"
		"Default"		"0"
	}
	"BuildModeDialog"
	{
		"ControlName"		"BuildModeDialog"
		"fieldName"		"BuildModeDialog"
		"xpos"		"327"
		"ypos"		"301"
		"wide"		"300"
		"tall"		"420"
		"autoResize"		"0"
		"pinCorner"		"0"
		"RoundedCorners"		"15"
		"pin_corner_to_sibling"		"0"
		"pin_to_sibling_corner"		"0"
		"visible"		"1"
		"enabled"		"1"
		"tabPosition"		"0"
		"settitlebarvisible"		"1"
		"title"		"#Frame_Untitled"
	}
}

Final result

This is how it should look at the end both your Cpp and header files:

MyPanel.cpp

//The following include files are necessary to allow your MyPanel.cpp to compile.
#include "cbase.h"
#include "IMyPanel.h"
using namespace vgui;
#include <vgui/IVGui.h>
#include <vgui_controls/Frame.h>
#include <vgui_controls/Button.h>

//CMyPanel class: Tutorial example class
class CMyPanel : public vgui::Frame
{
	DECLARE_CLASS_SIMPLE(CMyPanel, vgui::Frame);
	//CMyPanel : This Class / vgui::Frame : BaseClass

	CMyPanel(vgui::VPANEL parent); 	// Constructor
	~CMyPanel(){};				// Destructor

protected:
	//VGUI overrides:
	virtual void OnTick();
	virtual void OnCommand(const char* pcCommand);

private:
	//Other used VGUI control Elements:
	Button *m_pCloseButton;
};

// Constuctor: Initializes the Panel
CMyPanel::CMyPanel(vgui::VPANEL parent)
	: BaseClass(NULL, "MyPanel")
{
	SetParent(parent);

	SetKeyBoardInputEnabled(true);
	SetMouseInputEnabled(true);

	SetProportional(false);
	SetTitleBarVisible(true);
	SetMinimizeButtonVisible(false);
	SetMaximizeButtonVisible(false);
	SetCloseButtonVisible(false);
	SetSizeable(false);
	SetMoveable(false);
	SetVisible(true);


	SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));

	LoadControlSettings("resource/UI/playermodelsel.res");

	vgui::ivgui()->AddTickSignal(GetVPanel(), 100);

	DevMsg("MyPanel has been constructed\n");

	//Button done
	m_pCloseButton = new Button(this, "Button", "Close", this, "turnoff");
	m_pCloseButton->SetPos(433, 472);
	m_pCloseButton->SetDepressedSound("common/bugreporter_succeeded.wav");
	m_pCloseButton->SetReleasedSound("ui/buttonclick.wav");
}

//Class: CMyPanelInterface Class. Used for construction.
class CMyPanelInterface : public MyPanel
{
private:
	CMyPanel *MyPanel;
public:
	CMyPanelInterface()
	{
		MyPanel = NULL;
	}
	void Create(vgui::VPANEL parent)
	{
		MyPanel = new CMyPanel(parent);
	}
	void Destroy()
	{
		if (MyPanel)
		{
			MyPanel->SetParent((vgui::Panel *)NULL);
			delete MyPanel;
		}
	}
	void Activate(void)
	{
		if (MyPanel)
		{
			MyPanel->Activate();
		}
	}
};
static CMyPanelInterface g_MyPanel;
MyPanel* mypanel = (MyPanel*)&g_MyPanel;

ConVar cl_showmypanel("cl_showmypanel", "0", FCVAR_CLIENTDLL, "Sets the state of myPanel <state>");

void CMyPanel::OnTick()
{
	BaseClass::OnTick();
	SetVisible(cl_showmypanel.GetBool());
}

CON_COMMAND(OpenTestPanelFenix, "Toggles testpanelfenix on or off")
{
	cl_showmypanel.SetValue(!cl_showmypanel.GetBool());
	mypanel->Activate();
};

void CMyPanel::OnCommand(const char* pcCommand)
{
	BaseClass::OnCommand(pcCommand);

	if (!Q_stricmp(pcCommand, "turnoff"))
		cl_showmypanel.SetValue(0);
}

IMyPanel.h

class MyPanel
{
public:
	virtual void		Create(vgui::VPANEL parent) = 0;
	virtual void		Destroy(void) = 0;
	virtual void		Activate(void) = 0;
};

extern MyPanel* mypanel;

Now compile your files, boot your mod, and press the new option that it should appear at the main menu. If everything goes fine, a panel will open, and pressing the button "Close" will close it. You can also close it by pressing again the main menu option, since we made it toggle.

Makefile changes on Linux

In source-sdk-2013/mp/src/game/client/client_linux32_hl2mp.mak (for multiplayer), you need to add a mention of your new file to the list of files to be built, and then a recipe to build it.

First, add the .cpp file to the list to be built:

CPPFILES= \
    MyPanel.cpp \
    ../../common/compiledcaptionswap.cpp \
    ../../common/language.cpp \
    ...

Then, down near the "recipe" for vgui_int.cpp, add the following recipe to build MyPanel:

ifneq (clean, $(findstring clean, $(MAKECMDGOALS)))
-include $(OBJ_DIR)/MyPanel.P
endif

$(OBJ_DIR)/MyPanel.o : $(PWD)/MyPanel.cpp $(PWD)/client_linux32_hl2mp.mak $(SRCROOT)/devtools/makefile_base_posix.mak
        $(PRE_COMPILE_FILE)
        $(COMPILE_FILE) $(POST_COMPILE_FILE)

See also