Skip to content

Instantly share code, notes, and snippets.

@untodesu
Last active December 23, 2019 12:07
Show Gist options
  • Save untodesu/6abfcb11172330f3087de09561b290ac to your computer and use it in GitHub Desktop.
Save untodesu/6abfcb11172330f3087de09561b290ac to your computer and use it in GitHub Desktop.
#include "cbase.h"
#include "iclientmode.h"
#include <vector>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#define GAMEUI_ALLOW_INIT //GameUI: Idiot-proof
#include <gameui.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
// See interface.h/.cpp for specifics: basically this ensures that we actually Sys_UnloadModule the dll and that we don't call Sys_LoadModule
// over and over again.
static CDllDemandLoader GameUIDLL("GameUI");
namespace gameui
{
//-----------------------------------------------------------------------------
// Purpose: GameUI static members
//-----------------------------------------------------------------------------
std::vector<UIElementInstanceFn> GameUI::m_vInstances;
std::vector<UIElement *> GameUI::m_vpElements;
GameUI::RootPanel * GameUI::m_pRootPanel = NULL;
IGameUI * GameUI::m_pGameUI = NULL;
//-----------------------------------------------------------------------------
// Purpose: The root panel. This panel is actually being drawn instead of main menu
//-----------------------------------------------------------------------------
class GameUI::RootPanel : public Panel {
DECLARE_CLASS_SIMPLE(RootPanel, Panel);
public:
RootPanel(VPANEL parent);
protected:
virtual void ApplySchemeSettings(IScheme *scheme);
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
GameUI::RootPanel::RootPanel(VPANEL parent) : BaseClass(NULL, "GameUI_RootPanel")
{
SetParent(parent);
}
//-----------------------------------------------------------------------------
// Purpose: Apply scheme and resize itself to screen's size
//-----------------------------------------------------------------------------
void GameUI::RootPanel::ApplySchemeSettings(IScheme *scheme)
{
BaseClass::ApplySchemeSettings(scheme);
// Resize the panel to the screen size
// Otherwise, it'll just be in a little corner
int wide, tall;
surface()->GetScreenSize(wide, tall);
SetSize(wide, tall);
}
//-----------------------------------------------------------------------------
// Purpose: Create new root panel and override IGameUI to it
//-----------------------------------------------------------------------------
void GameUI::InitializeGameUI(VPANEL parent)
{
if(!m_pRootPanel) {
m_pRootPanel = new GameUI::RootPanel(parent);
LoadGameUI();
}
if(m_pGameUI) {
Msg("RefUI: IGameUI::SetMainMenuOverride -> GameUI\n");
m_pGameUI->SetMainMenuOverride(m_pRootPanel->GetVPanel());
CreatePanels();
}
}
//-----------------------------------------------------------------------------
// Purpose: De-Override IGameUI menu panel, delete root panel
//-----------------------------------------------------------------------------
void GameUI::ShutdownGameUI(void)
{
if(m_pGameUI) {
Msg("RefUI: IGameUI::SetMainMenuOverride -> 0\n");
m_pGameUI->SetMainMenuOverride((VPANEL)0);
if(m_pRootPanel) {
DeletePanels();
m_pRootPanel->SetParent((Panel *)NULL);
delete m_pRootPanel;
m_pRootPanel = NULL;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Get IGameUI from gameui.dll
//-----------------------------------------------------------------------------
bool GameUI::LoadGameUI(void)
{
if(m_pGameUI) {
return true;
}
CreateInterfaceFn gameUIFactory = GameUIDLL.GetFactory();
if(!gameUIFactory) {
return false;
}
m_pGameUI = (IGameUI *)gameUIFactory(GAMEUI_INTERFACE_VERSION, NULL);
return (m_pGameUI != NULL);
}
//-----------------------------------------------------------------------------
// Purpose: Add new panel instance function to list
//-----------------------------------------------------------------------------
void GameUI::RegisterPanel(UIElementInstanceFn pfnInstance)
{
//If already have same instance function - do absolutely NOTHING
for(size_t i = 0; i < m_vInstances.size(); i++) {
if(m_vInstances[i] == pfnInstance) {
return;
}
}
m_vInstances.push_back(pfnInstance);
}
//-----------------------------------------------------------------------------
// Purpose: Create and initialize all registered panels
//-----------------------------------------------------------------------------
void GameUI::CreatePanels(void)
{
Msg("RefUI: Initializing panels...\n");
for(size_t i = 0; i < m_vInstances.size(); i++) {
UIElementInstanceFn pfnInstance = m_vInstances[i];
if(pfnInstance) {
UIElement *element = pfnInstance();
element->SetParent(m_pRootPanel);
element->Init();
//Add new element to list
m_vpElements.push_back(element);
}
}
Msg("RefUI: Panels count: %u\n", m_vpElements.size());
}
//-----------------------------------------------------------------------------
// Purpose: Shutdown and delete all created panels
//-----------------------------------------------------------------------------
void GameUI::DeletePanels(void)
{
for(size_t i = 0; i < m_vpElements.size(); i++) {
UIElement *element = m_vpElements[i];
element->SetParent((Panel *)NULL);
element->Shutdown();
delete element;
}
//And now just clear elements list
m_vpElements.clear();
}
//-----------------------------------------------------------------------------
// Purpose: Data accessor
//-----------------------------------------------------------------------------
IGameUI * GameUI::GetGameUI(void)
{
if(!LoadGameUI()) {
return NULL;
}
return m_pGameUI;
}
//-----------------------------------------------------------------------------
// Purpose: Data accessor.
// NOTE: This also can create panels on viewport!
//-----------------------------------------------------------------------------
VPANEL GameUI::GetVPanel(bool viewport)
{
// This function can parent windows only for UI part, or for viewport
return (viewport)
? g_pClientMode->GetViewport()->GetVPanel()
: m_pRootPanel->GetVPanel();
}
//-----------------------------------------------------------------------------
// Purpose: Get named UI element
// Returns: Found element or NULL
//-----------------------------------------------------------------------------
UIElement * GameUI::GetElement(const char *elementName)
{
for(size_t i = 0; i < m_vpElements.size(); i++) {
UIElement *element = m_vpElements[i];
if(FStrEq(element->GetName(), elementName)) {
return element;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Get VGUI Localized string
//-----------------------------------------------------------------------------
void GameUI::GetLocalizedString(const char *src, wchar_t *dst, size_t dst_len)
{
size_t src_len = Q_strlen(src);
const wchar_t *value = g_pVGuiLocalize->Find(src);
if(value) {
Q_wcsncpy(dst, value, dst_len * sizeof(wchar_t));
}
else {
for(size_t i = 0; i < dst_len; i++) {
dst[i] = L'\0';
}
for(size_t i = 0; i < src_len && i < dst_len; i++) {
//Just copy shit
dst[i] = src[i];
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
UIElementHelper::UIElementHelper(UIElementInstanceFn pfnInstance)
{
GameUI::RegisterPanel(pfnInstance);
}
}
#ifndef _GAMEUI_MANAGER_H
#define _GAMEUI_MANAGER_H
#ifdef _WIN32
#pragma once
#endif
#include <vector>
#include <vgui/VGUI.h>
#include <vgui_controls/Panel.h>
#include <GameUI/IGameUI.h>
#include <gameui_element.h>
//define this if you want to allow initialization and shutdown
//#define GAMEUI_ALLOW_INIT
namespace gameui
{
using UIElementInstanceFn = UIElement *(*)(void);
//-----------------------------------------------------------------------------
// Purpose: Global static UI manager class
//-----------------------------------------------------------------------------
class GameUI {
class RootPanel; //See gameui.cpp
private:
static std::vector<UIElementInstanceFn> m_vInstances;
static std::vector<UIElement *> m_vpElements; //Shutdown will use this.
static GameUI::RootPanel * m_pRootPanel;
static IGameUI * m_pGameUI;
public:
#ifdef GAMEUI_ALLOW_INIT //GameUI: Idiot-proof
static void InitializeGameUI(vgui::VPANEL parent);
static void ShutdownGameUI(void);
static bool LoadGameUI(void);
static void RegisterPanel(UIElementInstanceFn pfnInstance);
static void CreatePanels(void);
static void DeletePanels(void);
#endif
static IGameUI * GetGameUI(void);
static vgui::VPANEL GetVPanel(bool viewport = false);
static UIElement * GetElement(const char *elementName);
static void GetLocalizedString(const char *src, wchar_t *dst, size_t dst_len);
};
//-----------------------------------------------------------------------------
// Purpose: Helper to allow programmer make classes UI elements
//-----------------------------------------------------------------------------
class UIElementHelper {
public:
UIElementHelper(UIElementInstanceFn pfnInstance);
};
//-----------------------------------------------------------------------------
// Purpose: Makes class visible to GameUI API
//-----------------------------------------------------------------------------
#define DECLARE_UIELEMENT(className) \
static UIElement * className##_Instance(void) \
{ \
return (UIElement *)(new className(NULL)); \
} \
static UIElementHelper s_##className##_Helper(className##_Instance)
//-----------------------------------------------------------------------------
// Purpose: Makes class visible to GameUI API, but with different constructor & default parent
//-----------------------------------------------------------------------------
#define DECLARE_UIELEMENT_VA_PARENT(className, ...) \
static UIElement * className##_Instance(void) \
{ \
return (UIElement *)(new className(NULL, __VA_ARGS__)); \
} \
static UIElementHelper s_##className##_Helper(className##_Instance)
//-----------------------------------------------------------------------------
// Purpose: Makes class visible to GameUI API, but with different constructor
//-----------------------------------------------------------------------------
#define DECLARE_UIELEMENT_VA(className, ...) \
static UIElement * className##_Instance(void) \
{ \
return (UIElement *)(new className(__VA_ARGS__)); \
} \
static UIElementHelper s_##className##_Helper(className##_Instance)
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment