Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
390 lines
8.5 KiB
C++
390 lines
8.5 KiB
C++
/******************************************************************************
|
|
* File: CDeviceUI.cpp
|
|
*
|
|
* Desc:
|
|
*
|
|
* CDeviceUI is a helper that holds all the views and a bunch of
|
|
* information for a specific device. It has a CFlexWnd whose
|
|
* handler it sets to the CDeviceView for the current view,
|
|
* thus reusing one window to implement multiple pages.
|
|
*
|
|
* All CDeviceViews and CDeviceControls have a reference to the CDeviceUI
|
|
* that created them (m_ui). Thus, they also have access to the
|
|
* CUIGlobals, since CDeviceUI has a reference to them (m_ui.m_uig).
|
|
* CDeviceUI also provides the following read-only public variables
|
|
* for convenience, all referring to the device this CDeviceUI
|
|
* represents:
|
|
*
|
|
* const DIDEVICEINSTANCEW &m_didi;
|
|
* const LPDIRECTINPUTDEVICE8W &m_lpDID;
|
|
* const DIDEVOBJSTRUCT &m_os;
|
|
*
|
|
* See usefuldi.h for a description of DIDEVOBJSTRUCT.
|
|
*
|
|
* CDeviceUI communicates to the rest of the UI via the CDeviceUINotify
|
|
* abstract base class. Another class (in our case CDIDeviceActionConfigPage)
|
|
* must derive from CDeviceUINotify, and define the DeviceUINotify() and
|
|
* IsControlMapped() virtual functions. This derived class must be passed as
|
|
* the last parameter to CDeviceUI's Init() function. All the views and
|
|
* controls within the views notify the UI of user actions via m_ui.Notify(),
|
|
* so that all actionformat manipulation can be done in the page class. The
|
|
* views and controls themselves never touch the actionformat. See the
|
|
* DEVICEUINOTIFY structure below for information on the parameter passed
|
|
* through Notify()/DeviceUINotify().
|
|
*
|
|
* Copyright (C) 1999-2001 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "common.hpp"
|
|
#include <dinputd.h>
|
|
#include "configwnd.h"
|
|
|
|
#define DIPROP_MAPFILE MAKEDIPROP(0xFFFD)
|
|
|
|
CDeviceUI::CDeviceUI(CUIGlobals &uig, IDIConfigUIFrameWindow &uif) :
|
|
m_uig(uig), m_UIFrame(uif),
|
|
m_didi(m_priv_didi), m_lpDID(m_priv_lpDID), m_os(m_priv_os),
|
|
m_pCurView(NULL),
|
|
m_pNotify(NULL), m_hWnd(NULL), m_bInEditMode(FALSE)
|
|
{
|
|
m_priv_lpDID = NULL;
|
|
}
|
|
|
|
CDeviceUI::~CDeviceUI()
|
|
{
|
|
Unpopulate();
|
|
}
|
|
|
|
HRESULT CDeviceUI::Init(const DIDEVICEINSTANCEW &didi, LPDIRECTINPUTDEVICE8W lpDID, HWND hWnd, CDeviceUINotify *pNotify)
|
|
{tracescope(__ts, _T("CDeviceUI::Init()...\n"));
|
|
// save the params
|
|
m_priv_didi = didi;
|
|
m_priv_lpDID = lpDID;
|
|
m_pNotify = pNotify;
|
|
m_hWnd = hWnd;
|
|
|
|
// fail if we don't have lpDID
|
|
if (m_lpDID == NULL)
|
|
{
|
|
etrace(_T("CDeviceUI::Init() was passed a NULL lpDID!\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
// fill the devobjstruct
|
|
HRESULT hr = FillDIDeviceObjectStruct(m_priv_os, lpDID);
|
|
if (FAILED(hr))
|
|
{
|
|
etrace1(_T("FillDIDeviceObjectStruct() failed, returning 0x%08x\n"), hr);
|
|
return hr;
|
|
}
|
|
|
|
// view rect needs to be set before populating so the views are
|
|
// created with the correct dimensions
|
|
m_ViewRect = g_ViewRect;
|
|
|
|
// populate
|
|
hr = PopulateAppropriately(*this);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// if there are no views, return
|
|
if (GetNumViews() < 1)
|
|
{
|
|
Unpopulate();
|
|
return E_FAIL;
|
|
}
|
|
|
|
// show the first view
|
|
SetView(0);
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CDeviceUI::Unpopulate()
|
|
{
|
|
m_pCurView = NULL;
|
|
|
|
for (int i = 0; i < GetNumViews(); i++)
|
|
{
|
|
if (m_arpView[i] != NULL)
|
|
delete m_arpView[i];
|
|
m_arpView[i] = NULL;
|
|
}
|
|
m_arpView.RemoveAll();
|
|
|
|
Invalidate();
|
|
}
|
|
|
|
void CDeviceUI::SetView(int nView)
|
|
{
|
|
if (nView >= 0 && nView < GetNumViews())
|
|
SetView(m_arpView[nView]);
|
|
}
|
|
|
|
void CDeviceUI::SetView(CDeviceView *pView)
|
|
{
|
|
if (m_pCurView != NULL)
|
|
ShowWindow(m_pCurView->m_hWnd, SW_HIDE);
|
|
|
|
m_pCurView = pView;
|
|
|
|
if (m_pCurView != NULL)
|
|
ShowWindow(m_pCurView->m_hWnd, SW_SHOW);
|
|
}
|
|
|
|
CDeviceView *CDeviceUI::GetView(int nView)
|
|
{
|
|
if (nView >= 0 && nView < GetNumViews())
|
|
return m_arpView[nView];
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
CDeviceView *CDeviceUI::GetCurView()
|
|
{
|
|
return m_pCurView;
|
|
}
|
|
|
|
int CDeviceUI::GetViewIndex(CDeviceView *pView)
|
|
{
|
|
if (GetNumViews() == 0)
|
|
return -1;
|
|
|
|
for (int i = 0; i < GetNumViews(); i++)
|
|
if (m_arpView[i] == pView)
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
int CDeviceUI::GetCurViewIndex()
|
|
{
|
|
return GetViewIndex(m_pCurView);
|
|
}
|
|
|
|
// gets the thumbnail for the specified view,
|
|
// using the selected version if the view is selected
|
|
CBitmap *CDeviceUI::GetViewThumbnail(int nView)
|
|
{
|
|
return GetViewThumbnail(nView, GetView(nView) == GetCurView());
|
|
}
|
|
|
|
// gets the thumbnail for the specified view,
|
|
// specifiying whether or not we want the selected version
|
|
CBitmap *CDeviceUI::GetViewThumbnail(int nView, BOOL bSelected)
|
|
{
|
|
CDeviceView *pView = GetView(nView);
|
|
if (pView == NULL)
|
|
return NULL;
|
|
|
|
return pView->GetImage(bSelected ? DVI_SELTHUMB : DVI_THUMB);
|
|
}
|
|
|
|
void CDeviceUI::DoForAllControls(DEVCTRLCALLBACK callback, LPVOID pVoid, BOOL bFixed)
|
|
{
|
|
int nv = GetNumViews();
|
|
for (int v = 0; v < nv; v++)
|
|
{
|
|
CDeviceView *pView = GetView(v);
|
|
if (pView == NULL)
|
|
continue;
|
|
|
|
int nc = pView->GetNumControls();
|
|
for (int c = 0; c < nc; c++)
|
|
{
|
|
CDeviceControl *pControl = pView->GetControl(c);
|
|
if (pControl == NULL)
|
|
continue;
|
|
|
|
callback(pControl, pVoid, bFixed);
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef struct _DFCIAO {
|
|
DWORD dwOffset;
|
|
DEVCTRLCALLBACK callback;
|
|
LPVOID pVoid;
|
|
} DFCIAO;
|
|
|
|
void DoForControlIfAtOffset(CDeviceControl *pControl, LPVOID pVoid, BOOL bFixed)
|
|
{
|
|
DFCIAO &dfciao = *((DFCIAO *)pVoid);
|
|
|
|
if (pControl->GetOffset() == dfciao.dwOffset)
|
|
dfciao.callback(pControl, dfciao.pVoid, bFixed);
|
|
}
|
|
|
|
void CDeviceUI::DoForAllControlsAtOffset(DWORD dwOffset, DEVCTRLCALLBACK callback, LPVOID pVoid, BOOL bFixed)
|
|
{
|
|
DFCIAO dfciao;
|
|
dfciao.dwOffset = dwOffset;
|
|
dfciao.callback = callback;
|
|
dfciao.pVoid = pVoid;
|
|
DoForAllControls(DoForControlIfAtOffset, &dfciao, bFixed);
|
|
}
|
|
|
|
void SetControlCaptionTo(CDeviceControl *pControl, LPVOID pVoid, BOOL bFixed)
|
|
{
|
|
pControl->SetCaption((LPCTSTR)pVoid, bFixed);
|
|
}
|
|
|
|
void CDeviceUI::SetAllControlCaptionsTo(LPCTSTR tszCaption)
|
|
{
|
|
DoForAllControls(SetControlCaptionTo, (LPVOID)tszCaption);
|
|
}
|
|
|
|
void CDeviceUI::SetCaptionForControlsAtOffset(DWORD dwOffset, LPCTSTR tszCaption, BOOL bFixed)
|
|
{
|
|
DoForAllControlsAtOffset(dwOffset, SetControlCaptionTo, (LPVOID)tszCaption, bFixed);
|
|
}
|
|
|
|
void CDeviceUI::Invalidate()
|
|
{
|
|
if (m_pCurView != NULL)
|
|
m_pCurView->Invalidate();
|
|
}
|
|
|
|
void CDeviceUI::SetEditMode(BOOL bEdit)
|
|
{
|
|
if (bEdit == m_bInEditMode)
|
|
return;
|
|
|
|
m_bInEditMode = bEdit;
|
|
Invalidate();
|
|
}
|
|
|
|
|
|
void CDeviceUI::SetDevice(LPDIRECTINPUTDEVICE8W lpDID)
|
|
{
|
|
m_priv_lpDID = lpDID;
|
|
}
|
|
|
|
BOOL CDeviceUI::IsControlMapped(CDeviceControl *pControl)
|
|
{
|
|
if (pControl == NULL || m_pNotify == NULL)
|
|
return FALSE;
|
|
|
|
return m_pNotify->IsControlMapped(pControl);
|
|
}
|
|
|
|
void CDeviceUI::Remove(CDeviceView *pView)
|
|
{
|
|
if (pView == NULL)
|
|
return;
|
|
|
|
int i = GetViewIndex(pView);
|
|
if (i < 0 || i >= GetNumViews())
|
|
{
|
|
assert(0);
|
|
return;
|
|
}
|
|
|
|
if (pView == m_pCurView)
|
|
m_pCurView = NULL;
|
|
|
|
if (m_arpView[i] != NULL)
|
|
{
|
|
m_arpView[i]->RemoveAll();
|
|
delete m_arpView[i];
|
|
}
|
|
m_arpView[i] = NULL;
|
|
|
|
m_arpView.RemoveAt(i);
|
|
|
|
if (m_arpView.GetSize() < 1)
|
|
RequireAtLeastOneView();
|
|
else if (m_pCurView == NULL)
|
|
{
|
|
SetView(0);
|
|
NumViewsChanged();
|
|
}
|
|
}
|
|
|
|
void CDeviceUI::RemoveAll()
|
|
{
|
|
m_pCurView = NULL;
|
|
|
|
for (int i = 0; i < GetNumViews(); i++)
|
|
{
|
|
if (m_arpView[i] != NULL)
|
|
delete m_arpView[i];
|
|
m_arpView[i] = NULL;
|
|
}
|
|
m_arpView.RemoveAll();
|
|
|
|
RequireAtLeastOneView();
|
|
}
|
|
|
|
CDeviceView *CDeviceUI::NewView()
|
|
{
|
|
// allocate new view, continuing on if it fails
|
|
CDeviceView *pView = new CDeviceView(*this);
|
|
if (pView == NULL)
|
|
return NULL;
|
|
|
|
// add view to array
|
|
m_arpView.SetAtGrow(m_arpView.GetSize(), pView);
|
|
|
|
// create view
|
|
pView->Create(m_hWnd, m_ViewRect, FALSE);
|
|
|
|
// let the page update to indicate viewness
|
|
NumViewsChanged();
|
|
|
|
return pView;
|
|
}
|
|
|
|
CDeviceView *CDeviceUI::UserNewView()
|
|
{
|
|
CDeviceView *pView = NewView();
|
|
if (!pView)
|
|
return NULL;
|
|
|
|
pView->AddWrappedLineOfText(
|
|
(HFONT)m_uig.GetFont(UIE_PICCUSTOMTEXT),
|
|
m_uig.GetTextColor(UIE_PICCUSTOMTEXT),
|
|
m_uig.GetBkColor(UIE_PICCUSTOMTEXT),
|
|
_T("Customize This View"));
|
|
|
|
pView->MakeMissingImages();
|
|
|
|
Invalidate();
|
|
|
|
return pView;
|
|
}
|
|
|
|
void CDeviceUI::RequireAtLeastOneView()
|
|
{
|
|
if (GetNumViews() > 0)
|
|
return;
|
|
|
|
CDeviceView *pView = NewView();
|
|
if (!pView)
|
|
return;
|
|
|
|
pView->AddWrappedLineOfText(
|
|
(HFONT)m_uig.GetFont(UIE_PICCUSTOMTEXT),
|
|
m_uig.GetTextColor(UIE_PICCUSTOMTEXT),
|
|
m_uig.GetBkColor(UIE_PICCUSTOMTEXT),
|
|
_T("Customize This View"));
|
|
pView->AddWrappedLineOfText(
|
|
(HFONT)m_uig.GetFont(UIE_PICCUSTOM2TEXT),
|
|
m_uig.GetTextColor(UIE_PICCUSTOM2TEXT),
|
|
m_uig.GetBkColor(UIE_PICCUSTOM2TEXT),
|
|
_T("The UI requires at least one view per device"));
|
|
|
|
pView->MakeMissingImages();
|
|
|
|
SetView(pView);
|
|
}
|
|
|
|
void CDeviceUI::NumViewsChanged()
|
|
{
|
|
DEVICEUINOTIFY uin;
|
|
uin.msg = DEVUINM_NUMVIEWSCHANGED;
|
|
Notify(uin);
|
|
}
|
|
|