Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

822 lines
21 KiB

/******************************************************************************
* 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-2000 Microsoft Corporation. All Rights Reserved.
*
***************************************************************************/
#include "common.hpp"
#include <dinputd.h>
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
#include <initguid.h>
#include "..\dx8\dimap\dimap.h"
#endif
//@@END_MSINTERNAL
#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)
{
//@@BEGIN_MSINTERNAL
// should be unnecessary, but wtheck...
//@@END_MSINTERNAL
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();
}
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
BOOL CDeviceUI::WriteToINI()
{
// JACK: do not remove this
class dumpandcleardeletenotes {
public:
dumpandcleardeletenotes(CDeviceUI &ui) : bFailed(FALSE), m_ui(ui) {m_ui.DumpDeleteNotes();}
~dumpandcleardeletenotes() {if (!bFailed) m_ui.ClearDeleteNotes();}
void SetFailed() {bFailed = TRUE;}
private:
BOOL bFailed;
CDeviceUI &m_ui;
} ___dacdn(*this);
int failure__ids;
BOOL bFailed = FALSE;
#define FAILURE(ids) {___dacdn.SetFailed(); failure__ids = ids; bFailed = TRUE; goto cleanup;}
HINSTANCE hInst = NULL;
LPFNGETCLASSOBJECT fpClassFactory = NULL;
LPDIRECTINPUTMAPPERVENDORW lpDiMap = NULL;
IClassFactory *pDiMapCF = NULL;
// Writes the callout information to INI file
// Get INI path first
HRESULT hr;
TCHAR szIniPath[MAX_PATH];
DIPROPSTRING dips;
LPDIRECTINPUT8 lpDI = NULL;
LPDIRECTINPUTDEVICE8 lpDID = NULL;
GUID guid;
BOOL bUsedDefault;
int r;
DWORD dwError;
DWORD diver = DIRECTINPUT_VERSION;
DIDEVICEIMAGEINFOW *pDelImgInfo = NULL;
hr = DirectInput8Create(g_hModule, diver, IID_IDirectInput8, (LPVOID*)&lpDI, NULL);
if (FAILED(hr))
FAILURE(IDS_DICREATEFAILED);
GetDeviceInstanceGuid(guid);
hr = lpDI->CreateDevice(guid, &lpDID, NULL);
if (FAILED(hr))
FAILURE(IDS_CREATEDEVICEFAILED);
// Check device type. If this is keyboard or mouse, don't need to saving anything.
if ((m_priv_didi.dwDevType & 0xFF) == DI8DEVTYPE_KEYBOARD ||
(m_priv_didi.dwDevType & 0xFF) == DI8DEVTYPE_MOUSE)
FAILURE(0); // Fail silently. Do not display any error dialog
ZeroMemory(&dips, sizeof(dips));
dips.diph.dwSize = sizeof(dips);
dips.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dips.diph.dwObj = 0;
dips.diph.dwHow = DIPH_DEVICE;
hr = lpDID->GetProperty(DIPROP_MAPFILE, &dips.diph);
if (FAILED(hr))
FAILURE(IDS_GETPROPMAPFILEFAILED);
#ifdef UNICODE
lstrcpy(szIniPath, dips.wsz);
#else
r = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK|WC_DEFAULTCHAR, dips.wsz, -1, szIniPath, MAX_PATH, _T("0"), &bUsedDefault);
dwError = GetLastError();
if (0 == r)
FAILURE(IDS_WCTOMBFAILED);
#endif
if (lstrlen(szIniPath) < 1)
FAILURE(IDS_NOMAPFILEPATH);
{
int i;
//////// Got map file name. Now write information to the file in 2 steps: ////////
//////// write deleted views, write remaining views. ////////
// Prepare deleted views array
if (GetNumDeleteNotes())
{
pDelImgInfo = new DIDEVICEIMAGEINFOW[GetNumDeleteNotes()];
if (!pDelImgInfo) FAILURE(IDS_ERROR_OUTOFMEMORY);
for (int iDelIndex = 0; iDelIndex < GetNumDeleteNotes(); ++iDelIndex)
{
UIDELETENOTE Del;
GetDeleteNote(Del, iDelIndex);
pDelImgInfo[iDelIndex].dwFlags = DIDIFT_DELETE | (Del.eType == UIDNT_VIEW ? DIDIFT_CONFIGURATION : DIDIFT_OVERLAY);
pDelImgInfo[iDelIndex].dwViewID = Del.nViewIndex;
pDelImgInfo[iDelIndex].dwObjID = Del.dwObjID;
}
}
// Initialize DIMAP class
hInst = LoadLibrary(_T("DIMAP.DLL"));
if (hInst)
fpClassFactory = (LPFNGETCLASSOBJECT)GetProcAddress(hInst,"DllGetClassObject");
if (!fpClassFactory)
FAILURE(IDS_ERROR_CANTLOADDIMAP);
hr = fpClassFactory(IID_IDirectInputMapClsFact, IID_IClassFactory, (void**)&pDiMapCF);
if (FAILED(hr)) FAILURE(IDS_ERROR_CANTLOADDIMAP);
hr = pDiMapCF->CreateInstance(NULL, IID_IDirectInputMapVendorIW, (void**)&lpDiMap); // Create mapper object
if (FAILED(hr)) FAILURE(IDS_ERROR_CANTLOADDIMAP);
hr = lpDiMap->Initialize(&guid, dips.wsz, 0); // Initialize with the INI file name
if (FAILED(hr)) FAILURE(IDS_ERROR_CANTLOADDIMAP);
// Prepare DIACTIONFORMAT for writing.
DIDEVICEIMAGEINFOHEADERW ImgInfoHdr;
LPDIACTIONFORMATW lpNewActFormat = NULL;
// We can get the DIACTIONFORMAT for this device from the main CConfigWnd object.
hr = m_UIFrame.GetActionFormatFromInstanceGuid(&lpNewActFormat, guid);
if (FAILED(hr) || !lpNewActFormat)
FAILURE(0);
for (DWORD dwAct = 0; dwAct < lpNewActFormat->dwNumActions; ++dwAct)
lpNewActFormat->rgoAction[dwAct].dwHow |= DIAH_HWDEFAULT;
// Prepare DIDEVICEIMAGEINFOHEADER for writing.
// Compute the number of DIDEVICEIMAGEINFO that we will need to fill out.
DWORD dwNumImgInfo = 0;
for (int i = 0; i < GetNumViews(); ++i)
dwNumImgInfo += GetView(i)->GetNumControls() + 1; // The view itself is one element.
ImgInfoHdr.dwSize = sizeof(ImgInfoHdr);
ImgInfoHdr.dwSizeImageInfo = sizeof(DIDEVICEIMAGEINFOW);
ImgInfoHdr.dwcViews = GetNumViews();
ImgInfoHdr.dwcAxes = 0; // Not needed for writing.
ImgInfoHdr.dwcButtons = 0; // Not needed for writing.
ImgInfoHdr.dwcPOVs = 0; // Not needed for writing.
// Send delete array first, but only if there is something to delete
if (GetNumDeleteNotes())
{
ImgInfoHdr.dwBufferSize =
ImgInfoHdr.dwBufferUsed = GetNumDeleteNotes() * sizeof(DIDEVICEIMAGEINFOW);
ImgInfoHdr.lprgImageInfoArray = pDelImgInfo;
hr = lpDiMap->WriteVendorFile(lpNewActFormat, &ImgInfoHdr, 0); // Write it
if (FAILED(hr))
{
if (hr == E_ACCESSDENIED)
{
FAILURE(IDS_WRITEVENDORFILE_ACCESSDENIED);
}
else
{
FAILURE(IDS_ERROR_WRITEVENDORFILE_FAILED);
}
}
}
// Update a few fields for writing remaining views.
ImgInfoHdr.dwBufferSize =
ImgInfoHdr.dwBufferUsed = dwNumImgInfo * sizeof(DIDEVICEIMAGEINFOW);
ImgInfoHdr.lprgImageInfoArray = new DIDEVICEIMAGEINFOW[dwNumImgInfo];
if (!ImgInfoHdr.lprgImageInfoArray)
FAILURE(IDS_ERROR_OUTOFMEMORY);
// Get a default image filename so that if a view doesn't have one, we'll use the default.
// For now, default image is the image used by the first view for which an image exists.
TCHAR tszDefImgPath[MAX_PATH] = _T("");
for (int iCurrView = 0; iCurrView < GetNumViews(); ++iCurrView)
{
CDeviceView *pView = GetView(iCurrView);
if (pView->GetImagePath())
{
lstrcpy(tszDefImgPath, pView->GetImagePath());
break;
}
}
DWORD dwNextWriteOffset = 0; // This is the index that the next write operation will write to.
int dwViewImgOffset = 0; // This is the index to be used for the next configuration image.
// Now we fill in the DIDEVICEIMAGEINFO array by going through each view
for (int iCurrView = 0; iCurrView < GetNumViews(); ++iCurrView)
{
CDeviceView *pView = GetView(iCurrView);
// Convert image path from T to unicode
#ifndef UNICODE
WCHAR wszImagePath[MAX_PATH];
if (pView->GetImagePath())
MultiByteToWideChar(CP_ACP, 0, pView->GetImagePath(), -1, wszImagePath, MAX_PATH);
else
MultiByteToWideChar(CP_ACP, 0, tszDefImgPath, -1, wszImagePath, MAX_PATH);
wcscpy(ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].tszImagePath, wszImagePath);
#else
if (pView->GetImagePath())
wcscpy(ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].tszImagePath, pView->GetImagePath());
else
wcscpy(ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].tszImagePath, tszDefImgPath); // String with a space
#endif
ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].dwViewID = dwViewImgOffset; // Points to the view offset
ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].dwFlags = DIDIFT_CONFIGURATION;
++dwNextWriteOffset; // Increment the write index
// Now iterate through the controls within this view
for (int iCurrCtrl = 0; iCurrCtrl < pView->GetNumControls(); ++iCurrCtrl)
{
CDeviceControl *pCtrl = pView->GetControl(iCurrCtrl);
pCtrl->FillImageInfo(&ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset]); // Fill in control info
ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].dwViewID = dwViewImgOffset; // Points to the view offset
++dwNextWriteOffset; // Increment the write index
}
++dwViewImgOffset; // Increment dwViewImgOffset once per view
}
// Write to vendor file
hr = lpDiMap->WriteVendorFile(lpNewActFormat, &ImgInfoHdr, 0);
delete[] ImgInfoHdr.lprgImageInfoArray;
if (FAILED(hr))
{
if (hr == E_ACCESSDENIED)
{
FAILURE(IDS_WRITEVENDORFILE_ACCESSDENIED);
}
else
{
FAILURE(IDS_ERROR_WRITEVENDORFILE_FAILED);
}
}
// Recreate the device instances to get the change
DEVICEUINOTIFY uin;
uin.msg = DEVUINM_RENEWDEVICE;
Notify(uin);
}
cleanup:
delete[] pDelImgInfo;
if (lpDiMap)
lpDiMap->Release();
if (pDiMapCF)
pDiMapCF->Release();
if (lpDID != NULL)
lpDID->Release();
if (lpDI != NULL)
lpDI->Release();
if (hInst)
FreeLibrary(hInst);
lpDiMap = NULL;
pDiMapCF = NULL;
lpDID = NULL;
lpDI = NULL;
hInst = NULL;
if (!bFailed)
FormattedMsgBox(g_hModule, m_hWnd, MB_OK | MB_ICONINFORMATION, IDS_MSGBOXTITLE_WRITEINISUCCEEDED, IDS_WROTEINITO, m_didi.tszInstanceName, szIniPath);
else
{
switch (failure__ids)
{
case 0:
break; // Case for keyboards and mice where we don't want any msg box to pop up.
case IDS_GETPROPVIDPIDFAILED:
case IDS_GETPROPMAPFILEFAILED:
case IDS_WRITEVENDORFILE_ACCESSDENIED:
FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_WRITEVENDORFILE_ACCESSDENIED);
break;
case IDS_ERROR_WRITEVENDORFILE_FAILED:
FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, failure__ids, hr);
break;
case IDS_ERROR_INIREAD:
FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_ERROR_INIREAD);
break;
case IDS_DICREATEFAILED:
FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_DICREATEFAILED, diver, hr);
break;
case IDS_CREATEDEVICEFAILED:
FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_CREATEDEVICEFAILED, GUIDSTR(guid), hr);
break;
case IDS_WCTOMBFAILED:
FormattedLastErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_WCTOMBFAILED, IDS_WCTOMBFAILED);
break;
case IDS_NOMAPFILEPATH:
FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_NOMAPFILEPATH);
break;
case IDS_ERROR_OUTOFMEMORY:
FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_ERROR_OUTOFMEMORY);
break;
default:
FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_ERRORUNKNOWN);
break;
}
}
return FALSE;
#undef FAILURE
}
#endif
//@@END_MSINTERNAL
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);
}
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
void CDeviceUI::NoteDeleteView(CDeviceView *pView)
{
assert(pView != NULL);
if (pView)
NoteDeleteView(pView->GetViewIndex());
}
void CDeviceUI::NoteDeleteControl(CDeviceControl *pControl)
{
assert(pControl != NULL);
if (pControl)
NoteDeleteControl(pControl->GetViewIndex(),
pControl->GetControlIndex(),
pControl->GetOffset());
}
void CDeviceUI::NoteDeleteView(int nView)
{
NoteDeleteAllControlsForView(GetView(nView));
int last = m_DeleteNotes.GetSize();
m_DeleteNotes.SetSize(last + 1);
UIDELETENOTE &uidn = m_DeleteNotes[last];
uidn.eType = UIDNT_VIEW;
uidn.nViewIndex = nView;
}
void CDeviceUI::NoteDeleteControl(int nView, int nControl, DWORD dwObjID)
{
int last = m_DeleteNotes.GetSize();
m_DeleteNotes.SetSize(last + 1);
UIDELETENOTE &uidn = m_DeleteNotes[last];
uidn.eType = UIDNT_CONTROL;
uidn.nViewIndex = nView;
uidn.nControlIndex = nControl;
uidn.dwObjID = dwObjID;
}
int CDeviceUI::GetNumDeleteNotes()
{
return m_DeleteNotes.GetSize();
}
BOOL CDeviceUI::GetDeleteNote(UIDELETENOTE &uidn, int i)
{
if (i >= 0 && i < GetNumDeleteNotes())
{
uidn = m_DeleteNotes[i];
return TRUE;
}
return FALSE;
}
void CDeviceUI::ClearDeleteNotes()
{
m_DeleteNotes.RemoveAll();
}
void CDeviceUI::DumpDeleteNotes()
{
utilstr s, suffix;
suffix.Format(_T("for device %s"), QSAFESTR(m_didi.tszInstanceName));
int n = GetNumDeleteNotes();
if (!n)
{
s.Format(_T("No DeleteNotes %s\n\n"), suffix.Get());
trace(s.Get());
return;
}
s.Format(_T("%d DeleteNotes %s...\n"), n, suffix.Get());
tracescope(__ts, s.Get());
for (int i = 0; i < n; i++)
{
UIDELETENOTE uidn;
GetDeleteNote(uidn, i);
switch (uidn.eType)
{
case UIDNT_VIEW:
s.Format(_T("%02d: View %d\n"), i, uidn.nViewIndex);
break;
case UIDNT_CONTROL:
s.Format(_T("%02d: Control %d on View %d, dwObjID = 0x%08x (%d)\n"),
i, uidn.nControlIndex, uidn.nViewIndex, uidn.dwObjID, uidn.dwObjID);
break;
}
trace(s.Get());
}
trace(_T("\n"));
}
void CDeviceUI::NoteDeleteAllControlsForView(CDeviceView *pView)
{
if (!pView)
return;
for (int i = 0; i < pView->GetNumControls(); i++)
NoteDeleteControl(pView->GetControl(i));
}
void CDeviceUI::NoteDeleteAllViews()
{
for (int i = 0; i < GetNumViews(); i++)
NoteDeleteView(GetView(i));
}
#endif
//@@END_MSINTERNAL