/****************************************************************************** * 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 #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); }