Files
Client/Library/dxx8/samples/Multimedia/DirectInput/DIConfig/cdeviceui.cpp
LGram16 e067522598 Initial commit: ROW Client source code
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>
2025-11-29 16:24:34 +09:00

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);
}