|
|
//-----------------------------------------------------------------------------
// File: cdeviceview.cpp
//
// Desc: CDeviceView is a window class derived from CFlexWnd. It represents
// the device view window in which the device and callouts are drawn.
// Each CDeviceView only represents one view. A device that has more
// than one view should have a corresponding number of CDeviceView for it.
//
// Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#include "common.hpp"
CDeviceView::CDeviceView(CDeviceUI &ui) : m_ui(ui), m_pbmImage(NULL), m_pbmThumb(NULL), m_pbmSelThumb(NULL), m_SuperState(0), m_State(0), m_SubState(0), m_OldSuperState(0), m_OldState(0), m_OldSubState(0), m_pControlContext(NULL), m_ptszImagePath(NULL), m_bScrollEnable(FALSE), m_nScrollOffset(0), m_nViewHeight(g_sizeImage.cy), m_bForcePaint(FALSE), m_bControlHeaderClipped(FALSE), m_bActionHeaderClipped(FALSE) { ZeroMemory(m_HeaderRectControl, sizeof(m_HeaderRectControl)); ZeroMemory(m_HeaderRectAction, sizeof(m_HeaderRectAction)); m_ptNextWLOText.x = m_ptNextWLOText.y = 0; }
CDeviceView::~CDeviceView() { Unpopulate(); }
CDeviceControl *CDeviceView::NewControl() { CDeviceControl *pControl = new CDeviceControl(m_ui, *this); if (!pControl) return NULL; m_arpControl.SetAtGrow(m_arpControl.GetSize(), pControl); return pControl; }
void CDeviceView::Remove(CDeviceControl *pControl) { if (pControl == NULL) return;
int i = pControl->GetControlIndex(); if (i < 0 || i >= GetNumControls()) { assert(0); return; }
if (pControl == m_pControlContext) m_pControlContext = NULL;
if (m_arpControl[i] != NULL) delete m_arpControl[i]; m_arpControl[i] = NULL;
m_arpControl.RemoveAt(i);
Invalidate(); }
void CDeviceView::RemoveAll(BOOL bUser) { m_pControlContext = NULL;
for (int i = 0; i < GetNumControls(); i++) { if (m_arpControl[i] != NULL) delete m_arpControl[i]; m_arpControl[i] = NULL; } m_arpControl.RemoveAll();
Invalidate(); }
void CDeviceView::Unpopulate(BOOL bInternalOnly) { DisableScrollBar();
m_bScrollEnable = FALSE;
if (m_pbmImage != NULL) delete m_pbmImage; if (m_pbmThumb != NULL) delete m_pbmThumb; if (m_pbmSelThumb != NULL) delete m_pbmSelThumb; m_pbmImage = NULL; m_pbmThumb = NULL; m_pbmSelThumb = NULL; free(m_ptszImagePath); m_ptszImagePath = NULL;
if (!bInternalOnly) RemoveAll(FALSE);
for (int i = 0; i < m_arpText.GetSize(); i++) { if (m_arpText[i]) delete m_arpText[i]; m_arpText[i] = NULL; } m_arpText.RemoveAll(); }
void AssureSize(CBitmap *&pbm, SIZE to) { if (!pbm) return;
SIZE from; if (!pbm->GetSize(&from)) return;
if (from.cx >= to.cx && from.cy >= to.cy) return;
CBitmap *nbm = CBitmap::Create(to, RGB(0,0,0)); if (!nbm) return;
HDC hDC = nbm->BeginPaintInto(); pbm->Draw(hDC); nbm->EndPaintInto(hDC);
delete pbm; pbm = nbm; nbm = NULL; }
CBitmap *CDeviceView::GrabViewImage() { CBitmap *pbm = CBitmap::Create(GetClientSize(), RGB(0, 0, 0), NULL); if (!pbm) return NULL; HDC hDC = pbm->BeginPaintInto(); if (!hDC) { delete pbm; return NULL; }
OnPaint(hDC);
pbm->EndPaintInto(hDC);
return pbm; }
void CDeviceView::MakeMissingImages() { // if (m_pbmImage)
// AssureSize(m_pbmImage, g_sizeImage);
if (m_pbmThumb == NULL) { if (m_pbmImage) m_pbmThumb = m_pbmImage->CreateResizedTo(g_sizeThumb); else { CBitmap *pbmImage = GrabViewImage(); if (pbmImage) { AssureSize(pbmImage, g_sizeImage); m_pbmThumb = pbmImage->CreateResizedTo(g_sizeThumb); } delete pbmImage; } }
if (m_pbmThumb == NULL) return;
if (m_pbmSelThumb == NULL) { m_pbmSelThumb = m_pbmThumb->Dup(); if (m_pbmSelThumb != NULL) { HDC hDC = m_pbmSelThumb->BeginPaintInto(); { CPaintHelper ph(m_ui.m_uig, hDC); ph.SetPen(UIP_SELTHUMB); ph.Rectangle(0, 0, g_sizeThumb.cx, g_sizeThumb.cy, UIR_OUTLINE); } m_pbmSelThumb->EndPaintInto(hDC); } } }
void CDeviceView::OnPaint(HDC hDC) { HDC hBDC = NULL, hODC = NULL; CBitmap *pbm = NULL;
if (!InRenderMode()) { hODC = hDC; pbm = CBitmap::Create(GetClientSize(), RGB(0, 0, 0), hDC); if (pbm != NULL) { hBDC = pbm->BeginPaintInto(); if (hBDC != NULL) hDC = hBDC; } }
// Black-fill first
SIZE fillsz = GetClientSize(); RECT fillrc = {0, 0, fillsz.cx, fillsz.cy}; FillRect(hDC, &fillrc, (HBRUSH)GetStockObject(BLACK_BRUSH));
if (m_pbmImage != NULL) m_pbmImage->Blend(hDC);
BOOL bScroll = m_bScrollEnable && m_sb.m_hWnd; int sdc = 0; if (bScroll) { sdc = SaveDC(hDC); OffsetViewportOrgEx(hDC, 0, -m_nScrollOffset + g_iListHeaderHeight, NULL); } else if (m_bScrollEnable) { sdc = SaveDC(hDC); OffsetViewportOrgEx(hDC, 0, g_iListHeaderHeight, NULL); }
int miny = 0 + m_nScrollOffset; int maxy = g_sizeImage.cy + m_nScrollOffset;
int t, nt = GetNumTexts(); for (t = 0; t < nt; t++) { CDeviceViewText *pText = m_arpText[t]; if (pText != NULL && !(pText->GetMinY() > maxy || pText->GetMaxY() < miny)) pText->OnPaint(hDC); }
BOOL bCFGUIEdit = m_ui.m_uig.InEditMode(); BOOL bEitherEditMode = bCFGUIEdit; //@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
BOOL bEditLayout = m_ui.InEditMode(); bEitherEditMode = bEitherEditMode || bEditLayout; #endif
//@@END_MSINTERNAL
int c, nc = GetNumControls(); for (c = 0; c < nc; c++) if (m_arpControl[c] != NULL && m_arpControl[c]->HasOverlay() && (m_arpControl[c]->IsHighlighted() //@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
|| InMoveOverlayStateForControl(m_arpControl[c]) #endif
//@@END_MSINTERNAL
) && (bEitherEditMode || m_arpControl[c]->IsMapped())) m_arpControl[c]->DrawOverlay(hDC); for (c = 0; c < nc; c++) { CDeviceControl *pControl = m_arpControl[c]; if (pControl != NULL && (bEitherEditMode || pControl->IsMapped()) && !(pControl->GetMinY() > maxy || pControl->GetMaxY() < miny)) pControl->OnPaint(hDC); }
if (bScroll || m_bScrollEnable) { RestoreDC(hDC, sdc); sdc = 0; }
// Black fill the top portion if this is a list view
if (bScroll) { GetClientRect(&fillrc); fillrc.bottom = g_iListHeaderHeight; FillRect(hDC, &fillrc, (HBRUSH)GetStockObject(BLACK_BRUSH)); }
// Print out the headers
TCHAR tszHeader[MAX_PATH]; // Control column
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (m_arpText.GetSize() > 2) /*
//@@END_MSINTERNAL
if (m_arpText.GetSize()) //@@BEGIN_MSINTERNAL
*/ #endif
//@@END_MSINTERNAL
{ CPaintHelper ph(m_ui.m_uig, hDC); ph.SetElement(UIE_CALLOUT);
for (int i = 0; i < 2; i++) { // Check if there are two columns, break out the 2nd iteration if not 2 columns.
if (i == 1 && !(GetNumControls() > 1 && m_arpControl[0]->GetCalloutMaxRect().top == m_arpControl[1]->GetCalloutMaxRect().top)) break;
RECT rcheader; if (m_arpText.GetSize()) { // Control column
LoadString(g_hModule, IDS_LISTHEADER_CTRL, tszHeader, MAX_PATH); DrawText(hDC, tszHeader, -1, &m_HeaderRectControl[i], DT_LEFT|DT_NOPREFIX|DT_END_ELLIPSIS);
// Action column
LoadString(g_hModule, IDS_LISTHEADER_ACTION, tszHeader, MAX_PATH); DrawText(hDC, tszHeader, -1, &m_HeaderRectAction[i], DT_CENTER|DT_NOPREFIX|DT_END_ELLIPSIS); } } }
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (bEditLayout) { CPaintHelper ph(m_ui.m_uig, hDC); ph.SetElement(UIE_VIEWBORDER); RECT rect; GetClientRect(&rect);
if (bScroll) rect.right -= DEFAULTVIEWSBWIDTH; ph.Rectangle(rect); } #endif
//@@END_MSINTERNAL
if (!InRenderMode()) { if (pbm != NULL) { if (hBDC != NULL) { pbm->EndPaintInto(hBDC); pbm->Draw(hODC); } delete pbm; } } }
int CDeviceView::GetNumControls() { return m_arpControl.GetSize(); }
CDeviceControl *CDeviceView::GetControl(int nControl) { if (nControl >= 0 && nControl < GetNumControls()) return m_arpControl[nControl]; else return NULL; }
CBitmap *CDeviceView::GetImage(DVIMAGE dvi) { switch (dvi) { case DVI_IMAGE: return m_pbmImage; case DVI_THUMB: return m_pbmThumb; case DVI_SELTHUMB: return m_pbmSelThumb;
default: return NULL; } }
void CDeviceView::OnMouseOver(POINT point, WPARAM wParam) { if (m_bScrollEnable && m_sb.m_hWnd) point.y += m_nScrollOffset;
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (InEditState()) { StateEvent(point, FALSE, TRUE, wParam); return; } #endif
//@@END_MSINTERNAL
// Check if we are over a control
POINT adjPt = point; if (m_bScrollEnable) adjPt.y -= g_iListHeaderHeight; int c, nc = GetNumControls(); for (c = 0; c < nc; c++) if (m_arpControl[c] != NULL && m_arpControl[c]->HitTest(adjPt) != DCHT_NOHIT) { m_arpControl[c]->OnMouseOver(adjPt); return; }
// Check if we are over a viewtext
nc = GetNumTexts(); for (c = 0; c < nc; c++) if (m_arpText[c] != NULL && m_arpText[c]->HitTest(adjPt) != DCHT_NOHIT) { m_arpText[c]->OnMouseOver(adjPt); return; }
CFlexWnd::s_ToolTip.SetEnable(FALSE);
DEVICEUINOTIFY uin; uin.msg = DEVUINM_MOUSEOVER; uin.from = DEVUINFROM_VIEWWND; uin.mouseover.point = point; m_ui.Notify(uin); }
void CDeviceView::OnClick(POINT point, WPARAM wParam, BOOL bLeft) { if (m_bScrollEnable && m_sb.m_hWnd) point.y += m_nScrollOffset;
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (InEditState()) { StateEvent(point, TRUE, bLeft, wParam); return; } #endif
//@@END_MSINTERNAL
POINT adjPt = point; if (m_bScrollEnable) adjPt.y -= g_iListHeaderHeight; int c, nc = GetNumControls(); for (c = 0; c < nc; c++) // adjPt is the adjust click point for scrolling list view
if (m_arpControl[c] != NULL && m_arpControl[c]->HitTest(adjPt) != DCHT_NOHIT) { m_arpControl[c]->OnClick(adjPt, bLeft); return; }
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (GetNumTexts() > 2) #endif
//@@END_MSINTERNAL
{ for (c = 0; c < GetNumTexts(); ++c) if (m_arpControl[c] != NULL && m_arpText[c] != NULL) { RECT rc = m_arpText[c]->GetRect(); if (PtInRect(&rc, adjPt)) { m_arpControl[c]->OnClick(adjPt, bLeft); return; } } }
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (!bLeft && m_ui.InEditMode()) { EditMenu(point); return; } #endif
//@@END_MSINTERNAL
// Send notification
DEVICEUINOTIFY uin; uin.msg = DEVUINM_CLICK; uin.from = DEVUINFROM_VIEWWND; uin.click.bLeftButton = bLeft; m_ui.Notify(uin); }
void CDeviceView::OnDoubleClick(POINT point, WPARAM wParam, BOOL bLeft) { if (m_bScrollEnable && m_sb.m_hWnd) point.y += m_nScrollOffset;
POINT adjPt = point; if (m_bScrollEnable) adjPt.y -= g_iListHeaderHeight; int c, nc = GetNumControls(); for (c = 0; c < nc; c++) if (m_arpControl[c] != NULL && m_arpControl[c]->HitTest(adjPt) != DCHT_NOHIT) { m_arpControl[c]->OnClick(adjPt, bLeft, TRUE); return; }
for (c = 0; c < GetNumTexts(); ++c) if (m_arpControl[c] != NULL && m_arpText[c] != NULL) { RECT rc = m_arpText[c]->GetRect(); if (PtInRect(&rc, adjPt)) { m_arpControl[c]->OnClick(adjPt, bLeft, TRUE); return; } }
DEVICEUINOTIFY uin; uin.msg = DEVUINM_DOUBLECLICK; uin.from = DEVUINFROM_VIEWWND; uin.click.bLeftButton = bLeft; m_ui.Notify(uin); }
void CDeviceView::OnWheel(POINT point, WPARAM wParam) { if (!m_bScrollEnable) return;
if (m_sb.GetMin() == m_sb.GetMax()) return;
int nPage = MulDiv(m_sb.GetPage(), 9, 10) >> 1; // Half a page at a time
if ((int)wParam >= 0) m_sb.AdjustPos(-nPage); else m_sb.AdjustPos(nPage);
m_nScrollOffset = m_sb.GetPos(); Invalidate(); }
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
enum { IDEC_MOVECALLOUT = 1, IDEC_REDEFINECALLOUTMAX, IDEC_REALIGNCALLOUT, IDEC_REDEFINELINE, IDEC_RESELECTCONTROL, IDEC_REMOVECALLOUT, IDEC_SELECTIMAGES, IDEC_NEWVIEW, IDEC_NEWCALLOUT, IDEC_REMOVEALLCALLOUTS, IDEC_REMOVEVIEW, IDEC_REMOVEALLVIEWS, IDEC_SAVEOREXPORT, IDEC_SELECTOVERLAY, IDEC_MOVEOVERLAY, };
BOOL CDeviceView::InMoveOverlayStateForControl(CDeviceControl *pControl) { return m_State == IDEC_MOVEOVERLAY && m_pControlContext == pControl && pControl != NULL; }
void CDeviceView::EditMenu(POINT point, CDeviceControl *pControl) { static const struct ITEM { UINT uID; LPCTSTR tszName; } itemC[] = { {0, _T("Callout Edit Menu")}, {0, NULL}, {IDEC_MOVECALLOUT, _T("Move Callout")}, {0, NULL}, {IDEC_REDEFINECALLOUTMAX, _T("Redefine Callout Max")}, {IDEC_REALIGNCALLOUT, _T("Realign Callout")}, {IDEC_REDEFINELINE, _T("Redefine Line")}, {IDEC_SELECTOVERLAY, _T("Select Overlay")}, {IDEC_MOVEOVERLAY, _T("Move Overlay")}, {0, NULL}, {IDEC_RESELECTCONTROL, _T("Reselect Control")}, {0, NULL}, {IDEC_REMOVECALLOUT, _T("Remove Callout")}, {0,NULL} }, itemV[] = { {0, _T("View Edit Menu")}, {0, NULL}, {IDEC_SELECTIMAGES, _T("Select Image(s)")}, {0, NULL}, {IDEC_NEWVIEW, _T("New View")}, {IDEC_NEWCALLOUT, _T("New Callout")}, {0, NULL}, {IDEC_REMOVEALLCALLOUTS, _T("Remove All Callouts")}, {0, NULL}, {IDEC_REMOVEVIEW, _T("Remove View")}, {IDEC_REMOVEALLVIEWS, _T("Remove All Views")}, {0, NULL}, {IDEC_SAVEOREXPORT, _T("Save/Export")}, {0,NULL} }; static const int numitemsC = sizeof(itemC) / sizeof(ITEM) - 1; static const int numitemsV = sizeof(itemV) / sizeof(ITEM) - 1; const ITEM *item = pControl ? itemC : itemV; int numitems = pControl ? numitemsC : numitemsV;
HMENU hMenu = CreatePopupMenu();
for (int i = 0; i < numitems; i++) if (item[i].tszName == NULL) AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); else if (item[i].uID != 0) AppendMenu(hMenu, MF_STRING, item[i].uID, item[i].tszName); else AppendMenu(hMenu, MF_STRING | MF_GRAYED, 0, item[i].tszName);
m_pControlContext = pControl; CFlexWnd::s_ToolTip.SetEnable(FALSE); POINT cursor; GetCursorPos(&cursor); TrackPopupMenuEx(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON, cursor.x, cursor.y, m_hWnd, NULL);
DestroyMenu(hMenu); }
void CDeviceView::SaveOrExport() { OPENFILENAME ofn;
TCHAR tszFile[256] = _T("");
ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = m_hWnd; ofn.hInstance = g_hModule; ofn.lpstrFilter = NULL; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = tszFile; ofn.nMaxFile = 256; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = 0; ofn.lpstrTitle = NULL; ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; ofn.lpstrDefExt = _T("cpp"); ofn.lCustData = NULL; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL;
if (!GetSaveFileName(&ofn)) return;
if (FAILED(ExportCodeTo(tszFile))) MessageBox(m_hWnd, _T("Failed."), _T("Failed."), MB_OK); }
HRESULT CDeviceView::ExportCodeTo(LPCTSTR tszFile) { #ifdef UNICODE
FILE *f = _wfopen(tszFile, _T("wt")); #define fpf fwprintf
#else
FILE *f = fopen(tszFile, _T("wt")); #define fpf fprintf
#endif
if (f == NULL) return E_FAIL;
fpf(f, _T("CViewKey g_View[%d] =\n{\n"), GetNumControls()); for (int i = 0; i < GetNumControls(); i++) m_arpControl[i]->ExportCodeTo(f); fpf(f, _T("};\n"));
fclose(f);
#undef fpf
return S_OK; }
HRESULT CDeviceControl::ExportCodeTo(FILE *f) { if (f == NULL) return E_FAIL;
#ifdef UNICODE
#define fpf fwprintf
#else
#define fpf fprintf
#endif
fpf(f, _T("\t{0, 0, 0, {DIK_,\t")); switch (m_dwCalloutAlign) { case CAF_LEFT: fpf(f, _T("CAF_LEFT, ")); break; case CAF_RIGHT: fpf(f, _T("CAF_RIGHT, ")); break; case CAF_TOP: fpf(f, _T("CAF_TOP, ")); break; case CAF_BOTTOM: fpf(f, _T("CAF_BOTTOM, ")); break; case CAF_TOPLEFT: fpf(f, _T("CAF_TOPLEFT, ")); break; case CAF_TOPRIGHT: fpf(f, _T("CAF_TOPRIGHT, ")); break; case CAF_BOTTOMLEFT: fpf(f, _T("CAF_BOTTOMLEFT, ")); break; case CAF_BOTTOMRIGHT: fpf(f, _T("CAF_BOTTOMRIGHT, ")); break; case 0: default: fpf(f, _T("0,")); break; } fpf(f, _T("%s, %d, {"), RECTSTR(m_rectCalloutMax), m_nLinePoints); for (int i = 0; i < m_nLinePoints; i++) fpf(f, _T("%s,"), POINTSTR(m_rgptLinePoint[i])); fpf(f, _T("}}},\n"));
#undef fpf
return S_OK; }
LRESULT CDeviceView::OnCommand(WORD wNotifyCode, WORD wID, HWND hWnd) { // only handle menu messages
if (wNotifyCode != 0) return FALSE;
UINT cmd = (UINT)wID;
switch (cmd) { case IDEC_SAVEOREXPORT: { BOOL b; b = WriteToINI(); break; } case IDEC_MOVEOVERLAY: case IDEC_MOVECALLOUT: case IDEC_REDEFINECALLOUTMAX: case IDEC_REALIGNCALLOUT: case IDEC_REDEFINELINE: case IDEC_NEWCALLOUT: SetEditState(cmd); return TRUE;
case IDEC_RESELECTCONTROL: if (m_pControlContext) m_pControlContext->ReselectControl(); break;
case IDEC_REMOVECALLOUT: if (m_pControlContext) m_ui.NoteDeleteControl(m_pControlContext); Remove(m_pControlContext); break;
case IDEC_SELECTOVERLAY: if (m_pControlContext) m_pControlContext->SelectOverlay(); break;
case IDEC_SELECTIMAGES: SelectImages(); break;
case IDEC_NEWVIEW: m_ui.SetView(m_ui.UserNewView()); break;
case IDEC_REMOVEALLCALLOUTS: if (UserConfirm(g_hModule, m_hWnd, IDS_REMOVEALLCALLOUTS, IDS_CONFIRMREMOVEALLCALLOUTS)) { m_ui.NoteDeleteAllControlsForView(this); RemoveAll(); } break;
case IDEC_REMOVEVIEW: if (UserConfirm(g_hModule, m_hWnd, IDS_REMOVEVIEW, IDS_CONFIRMREMOVEVIEW)) { // you MUST return immediately after this call,
// as this object will have been deleted!
m_ui.NoteDeleteView(this); m_ui.Remove(this); return TRUE; } break;
case IDEC_REMOVEALLVIEWS: if (UserConfirm(g_hModule, m_hWnd, IDS_REMOVEALLVIEWS, IDS_CONFIRMREMOVEALLVIEWS)) { // you MUST return immediately after this call,
// as this object (and all other views for this device)
// will have been deleted!
m_ui.NoteDeleteAllViews(); m_ui.RemoveAll(); return TRUE; } break;
default: return FALSE; }
m_pControlContext = NULL; return TRUE; }
BOOL CDeviceView::InEditState() { return m_State != 0; }
void CDeviceView::EndEditState() { m_SuperState = 0; m_State = 0; m_SubState = 0; m_pControlContext = NULL; IndicateState(); ReleaseCapture(); }
void CDeviceView::SetEditState(UINT cmd) { m_State = cmd; m_SubState = 0;
if (m_State == 0) { EndEditState(); return; }
switch (cmd) { case IDEC_NEWCALLOUT: if (!IsUnassignedOffsetAvailable()) { FormattedMsgBox(g_hModule, m_hWnd, MB_OK | MB_ICONINFORMATION, IDS_TITLE_NONEWCONTROL, IDS_ERROR_OFFSETUNAVAIL); EndEditState(); return; } m_pControlContext = NewControl(); m_SuperState = cmd; m_State = cmd = IDEC_REDEFINECALLOUTMAX; // fallthrough
case IDEC_REDEFINECALLOUTMAX: case IDEC_REALIGNCALLOUT: case IDEC_REDEFINELINE: case IDEC_MOVECALLOUT: case IDEC_MOVEOVERLAY: break;
default: assert(0); break; }
SetCapture();
IndicateState(TRUE); }
void CDeviceView::IndicateState(BOOL bFirst) { // see what's changed since last call
BOOL bSuperStateChanged = m_SuperState != m_OldSuperState; BOOL bStateChanged = m_State != m_OldState; BOOL bSubStateChanged = m_SubState != m_OldSubState;
// save to check for next call
m_OldSuperState = m_SuperState; m_OldState = m_State; m_OldSubState = m_SubState;
// if there is no state, just end indication
if (m_State == 0) { m_ui.EndStateIndication(); return; }
// unless this is the first indication for an editing state or super state...
if (!bFirst) { // do nothing if nothing's changed
if (!(bSuperStateChanged || bStateChanged || bSubStateChanged)) return; }
// string to send to the ui for indication
TCHAR str[1024] = _T("");
// fill string as appropriate
switch (m_State) { case IDEC_REDEFINECALLOUTMAX: wsprintf(str, _T("Left click where you want to place %s corner of the callout max rect."), m_SubState == 0 ? _T("a") : _T("the opposite")); break;
case IDEC_REALIGNCALLOUT: _tcscpy(str, _T("Move the mouse to consider callout alignments within the max rect, and left click to choose the one you want.")); break;
case IDEC_REDEFINELINE: _tcscpy(str, _T("Draw a line from the callout to the corresponding device control by left clicking to add points. Right click to place the last point.")); break;
case IDEC_MOVECALLOUT: _tcscpy(str, _T("Move the entire callout around with the mouse and left click to place it.")); break;
case IDEC_MOVEOVERLAY: _tcscpy(str, _T("Move the overlay image around with the mouse and left click to place it.")); break; }
// set state indication if the string was actually filled
if (_tcslen(str) > 0) m_ui.SetStateIndication(str); }
void CDeviceView::StateEvent(POINT point, BOOL bClick, BOOL bLeft, WPARAM nKeyState) { // constrain point to view
SIZE size = GetClientSize(); const int WRAPAROUND = 10000; if (point.x < 0 || point.x > WRAPAROUND) point.x = 0; if (point.y < 0 || point.y > WRAPAROUND) point.y = 0; if (point.x >= size.cx) point.x = size.cx - 1; if (point.y >= size.cy) point.y = size.cy - 1;
switch (m_State) { case IDEC_REDEFINECALLOUTMAX: if (m_pControlContext) m_pControlContext->PlaceCalloutMaxCorner(m_SubState, point); if (bClick && bLeft) { m_SubState++; if (m_SubState == 2) EndState(); } break;
case IDEC_REALIGNCALLOUT: if (m_pControlContext) m_pControlContext->ConsiderAlignment(point); if (bClick && bLeft) { if (m_pControlContext) m_pControlContext->FinalizeAlignment(); EndState(); } break;
case IDEC_REDEFINELINE: if (m_pControlContext) m_pControlContext->SetLastLinePoint(m_SubState, point, (BOOL)(nKeyState & MK_SHIFT)); if (bClick) { if (bLeft && m_pControlContext) m_SubState = m_pControlContext->GetNextLinePointIndex(); if (!bLeft || m_pControlContext->ReachedMaxLinePoints()) EndState(); } break;
case IDEC_MOVECALLOUT: if (m_pControlContext) m_pControlContext->Position(point); if (bClick && bLeft) EndState(); break;
case IDEC_MOVEOVERLAY: if (m_pControlContext) { if (!m_pControlContext->HasOverlay()) EndState(); else m_pControlContext->PositionOverlay(point); } if (bClick && bLeft) EndState(); break;
default: assert(0); }
IndicateState(); }
void CDeviceView::EndState() { switch (m_SuperState) { case IDEC_NEWCALLOUT: switch (m_State) { case IDEC_REDEFINECALLOUTMAX: SetEditState(IDEC_REALIGNCALLOUT); break;
case IDEC_REALIGNCALLOUT: SetEditState(IDEC_REDEFINELINE); break;
case IDEC_REDEFINELINE: if (m_pControlContext) { m_pControlContext->SelectControl(); m_pControlContext->SelectOverlay();
if (m_pControlContext->HasOverlay()) SetEditState(IDEC_MOVEOVERLAY); else EndEditState(); } break;
case IDEC_MOVEOVERLAY: EndEditState(); break;
default: assert(0); break; } break;
case 0: EndEditState(); break;
default: assert(0); break; } } #endif
//@@END_MSINTERNAL
BOOL CDeviceView::DoesCalloutExistForOffset(DWORD dwOfs) { return DoesCalloutOtherThanSpecifiedExistForOffset(NULL, dwOfs); }
BOOL CDeviceView::DoesCalloutOtherThanSpecifiedExistForOffset(CDeviceControl *pOther, DWORD dwOfs) { int nc = GetNumControls(); for (int i = 0; i < nc; i++) { CDeviceControl *pControl = GetControl(i); if (pControl == NULL || pControl == pOther) continue; if (!pControl->IsOffsetAssigned()) continue; if (pControl->GetOffset() == dwOfs) return TRUE; } return FALSE; }
// This function returns the index of a control with the specified offset
int CDeviceView::GetIndexFromOfs(DWORD dwOfs) { for (int i = 0; i < GetNumControls(); ++i) if (m_arpControl[i]->GetOffset() == dwOfs) return i;
return -1; }
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
BOOL CDeviceView::WriteToINI() { // This function simply routes the call to the parent UI because the entire device info must
// be saved, not just current view.
return m_ui.WriteToINI(); } #endif
//@@END_MSINTERNAL
int CDeviceView::GetViewIndex() { return m_ui.GetViewIndex(this); }
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
void CDeviceView::SelectImages() { LPCTSTR file = GetOpenFileName( g_hModule, m_hWnd, _T("Select An Image for This View"), _T("PNG Files (*.png)\0*.png\0All Files (*.*)\0*.*\0"), _T("png"));
if (file == NULL) return;
ManualLoadImage(file); }
void CDeviceView::ManualLoadImage(LPCTSTR tszPath) { if (!tszPath) FormattedErrorBox(g_hModule, m_hWnd, IDS_TITLE_NOLOADVIEWIMAGE, IDS_NULLPATH);
LPDIRECT3DSURFACE8 pSurf = m_ui.m_uig.GetSurface3D(); // GetSurface3D() calls AddRef() on the surface.
CBitmap *pbmNewImage = CBitmap::CreateViaD3DX(tszPath, pSurf); if (pSurf) { // Release surface instance after we are done with it so we don't leak memory.
pSurf->Release(); pSurf = NULL; } if (pbmNewImage == NULL) { FormattedErrorBox(g_hModule, m_hWnd, IDS_TITLE_NOLOADVIEWIMAGE, IDS_COULDNOTCREATEIMAGEFROMFILE, tszPath); return; }
// unpopulate only this view's stuff, not the callouts
Unpopulate(TRUE);
// replace
m_pbmImage = pbmNewImage; pbmNewImage = NULL; MakeMissingImages(); m_ptszImagePath = _tcsdup(tszPath);
// redraw
Invalidate(); } #endif
//@@END_MSINTERNAL
BOOL CDeviceView::IsUnassignedOffsetAvailable() { DIDEVOBJSTRUCT os;
HRESULT hr = FillDIDeviceObjectStruct(os, m_ui.m_lpDID); if (FAILED(hr)) return FALSE;
if (os.nObjects < 1) return FALSE;
assert(os.pdoi); if (!os.pdoi) return FALSE;
for (int i = 0; i < os.nObjects; i++) { const DIDEVICEOBJECTINSTANCEW &o = os.pdoi[i];
if (!DoesCalloutExistForOffset(o.dwOfs)) return TRUE; }
return FALSE; }
CDeviceViewText *CDeviceView::AddText( HFONT f, COLORREF t, COLORREF b, const RECT &r, LPCTSTR text) { CDeviceViewText *pText = NewText(); if (!pText) return NULL;
pText->SetLook(f, t, b); pText->SetRect(r); pText->SetText(text);
return pText; }
CDeviceViewText *CDeviceView::AddText( HFONT f, COLORREF t, COLORREF b, const POINT &p, LPCTSTR text) { CDeviceViewText *pText = NewText(); if (!pText) return NULL;
pText->SetLook(f, t, b); pText->SetPosition(p); pText->SetTextAndResizeTo(text);
return pText; }
CDeviceViewText *CDeviceView::AddWrappedLineOfText( HFONT f, COLORREF t, COLORREF b, LPCTSTR text) { CDeviceViewText *pText = NewText(); if (!pText) return NULL;
pText->SetLook(f, t, b); pText->SetPosition(m_ptNextWLOText); pText->SetTextAndResizeToWrapped(text); m_ptNextWLOText.y += pText->GetHeight();
return pText; }
CDeviceViewText *CDeviceView::NewText() { CDeviceViewText *pText = new CDeviceViewText(m_ui, *this); if (!pText) return NULL; m_arpText.SetAtGrow(m_arpText.GetSize(), pText); return pText; }
// Called by PopulateListView(), after the CDeviceViewText and CDeviceControl lists are constructed.
// Returns TRUE if any label is printed with ellipses (not enough space).
BOOL CDeviceView::CalculateHeaderRect() { TCHAR tszHeader[MAX_PATH]; // Control column
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (m_arpText.GetSize() > 2) /*
//@@END_MSINTERNAL
if (m_arpText.GetSize()) //@@BEGIN_MSINTERNAL
*/ #endif
//@@END_MSINTERNAL
{ HDC hDC = CreateCompatibleDC(NULL);
if (hDC) { CPaintHelper ph(m_ui.m_uig, hDC); ph.SetElement(UIE_CALLOUT);
for (int i = 0; i < 2; i++) { // Check if there are two columns, break out the 2nd iteration if not 2 columns.
if (i == 1 && !(GetNumControls() > 1 && m_arpControl[0]->GetCalloutMaxRect().top == m_arpControl[1]->GetCalloutMaxRect().top)) break;
RECT rcheader; if (m_arpText.GetSize()) { // Action column
rcheader = m_arpText[i]->GetRect(); rcheader.bottom -= rcheader.top; rcheader.top = 0; if (i == 0) rcheader.left = 0; else rcheader.left = (g_ViewRect.right - g_ViewRect.left) >> 1; m_HeaderRectControl[i] = rcheader;
// Find out if the control header label will be clipped.
LoadString(g_hModule, IDS_LISTHEADER_CTRL, tszHeader, MAX_PATH); DrawText(hDC, tszHeader, -1, &rcheader, DT_LEFT|DT_NOPREFIX|DT_CALCRECT); if (rcheader.right > m_HeaderRectControl[i].right || rcheader.bottom > m_HeaderRectControl[i].bottom) m_bControlHeaderClipped = TRUE;
// Control column
rcheader = m_arpControl[i]->GetCalloutMaxRect(); rcheader.bottom -= rcheader.top; rcheader.top = 0; m_HeaderRectAction[i] = rcheader;
// Find out if the action header label will be clipped.
LoadString(g_hModule, IDS_LISTHEADER_ACTION, tszHeader, MAX_PATH); DrawText(hDC, tszHeader, -1, &rcheader, DT_LEFT|DT_NOPREFIX|DT_CALCRECT); if (rcheader.right > m_HeaderRectAction[i].right || rcheader.bottom > m_HeaderRectAction[i].bottom) m_bActionHeaderClipped = TRUE; } } } DeleteDC(hDC); } return m_bActionHeaderClipped || m_bControlHeaderClipped; }
int CDeviceView::GetNumTexts() { return m_arpText.GetSize(); }
CDeviceViewText *CDeviceView::GetText(int nText) { if (nText < 0 || nText >= GetNumTexts()) return NULL; return m_arpText[nText]; }
void CDeviceView::SetImage(CBitmap *&refpbm) { delete m_pbmImage; m_pbmImage = refpbm; refpbm = NULL; MakeMissingImages(); Invalidate(); }
void CDeviceView::SetImagePath(LPCTSTR tszPath) { if (m_ptszImagePath) free(m_ptszImagePath); m_ptszImagePath = NULL;
if (tszPath) m_ptszImagePath = _tcsdup(tszPath); }
void CDeviceView::CalcDimensions() { // go through all texts and controls to find the max y coord
int max = g_sizeImage.cy - g_iListHeaderHeight; int i = 0; for (; i < GetNumTexts(); i++) { CDeviceViewText *pText = GetText(i); if (!pText) continue; int ty = pText->GetMaxY(); if (ty > max) max = ty; } for (i = 0; i < GetNumControls(); i++) { CDeviceControl *pControl = GetControl(i); if (!pControl) continue; int cy = pControl->GetMaxY(); if (cy > max) max = cy; }
// set
m_nViewHeight = max; m_nScrollOffset = 0;
// enable scrollbar if view height more than window size
if (m_nViewHeight > g_sizeImage.cy - g_iListHeaderHeight) EnableScrollBar(); }
void CDeviceView::DisableScrollBar() { if (!m_sb.m_hWnd) return;
m_sb.Destroy(); }
void CDeviceView::EnableScrollBar() { if (m_sb.m_hWnd) return;
FLEXSCROLLBARCREATESTRUCT cs; cs.dwSize = sizeof(cs); cs.dwFlags = FSBF_VERT; cs.min = 0; cs.max = m_nViewHeight; cs.page = g_sizeImage.cy - g_iListHeaderHeight; cs.pos = m_nScrollOffset; cs.hWndParent = m_hWnd; cs.hWndNotify = m_hWnd; RECT rect = {g_sizeImage.cx - DEFAULTVIEWSBWIDTH, g_iListHeaderHeight, g_sizeImage.cx, g_sizeImage.cy}; cs.rect = rect; cs.bVisible = TRUE; m_sb.SetColors( m_ui.m_uig.GetBrushColor(UIE_SBTRACK), m_ui.m_uig.GetBrushColor(UIE_SBTHUMB), m_ui.m_uig.GetPenColor(UIE_SBBUTTON)); m_sb.Create(&cs); }
LRESULT CDeviceView::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_PAINT: m_bForcePaint = TRUE; return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
case WM_FLEXVSCROLL: { int code = (int)wParam; CFlexScrollBar *pSB = (CFlexScrollBar *)lParam; if (!pSB) return 0;
int nLine = 5; int nPage = MulDiv(pSB->GetPage(), 9, 10);
switch (code) { case SB_LINEUP: pSB->AdjustPos(-nLine); break; case SB_LINEDOWN: pSB->AdjustPos(nLine); break; case SB_PAGEUP: pSB->AdjustPos(-nPage); break; case SB_PAGEDOWN: pSB->AdjustPos(nPage); break; case SB_THUMBTRACK: pSB->SetPos(pSB->GetThumbPos()); break; }
m_nScrollOffset = pSB->GetPos();
Invalidate(); return 0; }
case WM_FLEXHSCROLL: assert(0); default: return CFlexWnd::WndProc(hWnd, msg, wParam, lParam); } }
void CDeviceView::ScrollToMakeControlVisible(const RECT &rc) { RECT viewrc;
if (!m_bScrollEnable) return;
GetClientRect(&viewrc); viewrc.bottom -= g_iListHeaderHeight; viewrc.top += m_nScrollOffset; viewrc.bottom += m_nScrollOffset;
// If scroll enabled, we scroll the view to make the control visible if not already so.
if (m_bScrollEnable && m_sb.m_hWnd && !(viewrc.left <= rc.left && viewrc.right >= rc.right && viewrc.top <= rc.top && viewrc.bottom >= rc.bottom)) { // If the callout is below the view window, scroll so it shows up at the bottom of the window.
if (viewrc.bottom < rc.bottom) m_sb.SetPos(m_sb.GetPos() + rc.bottom - viewrc.bottom); else m_sb.SetPos(rc.top); m_nScrollOffset = m_sb.GetPos(); Invalidate(); } }
void CDeviceView::SwapControls(int i, int j) { RECT rect; CDeviceControl *pTmpControl; CDeviceViewText *pTmpViewText;
pTmpControl = m_arpControl[i]; m_arpControl[i] = m_arpControl[j]; m_arpControl[j] = pTmpControl; pTmpViewText = m_arpText[i]; m_arpText[i] = m_arpText[j]; m_arpText[j] = pTmpViewText; // Swap the rect back so everything will display properly.
rect = m_arpControl[i]->GetCalloutMaxRect(); m_arpControl[i]->SetCalloutMaxRect(m_arpControl[j]->GetCalloutMaxRect()); m_arpControl[j]->SetCalloutMaxRect(rect); rect = m_arpText[i]->GetRect(); m_arpText[i]->SetRect(m_arpText[j]->GetRect()); m_arpText[j]->SetRect(rect); // Exchange the text rect width, so the correct width stays with the correct text.
RECT rc1 = m_arpText[i]->GetRect(); RECT rc2 = m_arpText[j]->GetRect(); // Store rc1's new width first
int iTempWidth = rc1.right - (rc2.right - rc2.left); rc2.left = rc2.right - (rc1.right - rc1.left); // Adjust rc2's width
rc1.left = iTempWidth; // Adjust rc1's width
m_arpText[i]->SetRect(rc1); m_arpText[j]->SetRect(rc2); }
// Implements a simple selection sort algorithm to sort the control array and viewtext array.
// - iStart is the starting index, inclusive.
// - iEnd is the last index, exclusive.
void CDeviceView::SortCallouts(int iStart, int iEnd) { for (int i = iStart; i < iEnd - 1; ++i) { DWORD dwSmallestOfs = m_arpControl[i]->GetOffset(); int iSmallestIndex = i; for (int j = i + 1; j < iEnd; ++j) if (m_arpControl[j]->GetOffset() < dwSmallestOfs) { dwSmallestOfs = m_arpControl[j]->GetOffset(); iSmallestIndex = j; } // Swap the smallest element with i-th element.
if (iSmallestIndex != i) SwapControls(i, iSmallestIndex); } }
void CDeviceView::SortAssigned(BOOL bSort) { // If less than 2 controls, no need for sorting.
if (m_arpControl.GetSize() < 2) return;
int iCalloutX[2] = {m_arpControl[0]->GetMinX(), m_arpControl[1]->GetMinX()}; // Callout X for the two columns
// Sort the text array and control array.
if (bSort) { // First move all the assigned controls to the first n elements.
int iNextAssignedWriteIndex = 0; for (int i = 0; i < m_arpControl.GetSize(); ++i) if (m_arpControl[i]->HasAction()) { // Swap the controls
SwapControls(i, iNextAssignedWriteIndex); ++iNextAssignedWriteIndex; // Increment the write index
}
// Sort the two parts now
SortCallouts(0, iNextAssignedWriteIndex); SortCallouts(iNextAssignedWriteIndex, m_arpControl.GetSize()); } else SortCallouts(0, m_arpControl.GetSize()); }
void CDeviceView::DoOnPaint(HDC hDC) { // Paint only if we have an update region.
if (GetUpdateRect(m_hWnd, NULL, FALSE) || m_bForcePaint) OnPaint(hDC); m_bForcePaint = FALSE; }
|