// ServoGraph.cpp: implementation of the CServoGraph class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ServoGraph.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CServoGraph::CServoGraph() { m_hWnd = NULL; m_crBkgnd = RGB(255,255,255); m_pHighItem = nullptr; m_hWndTooltip = nullptr; } CServoGraph::~CServoGraph() { for (auto& item : m_images) { if (item.hBitmap != nullptr) { ::DeleteObject(item.hBitmap); } } } BOOL CServoGraph::RegisterWndClass() { WNDCLASS wc; wc.lpszClassName = BYSERVOGRAPH_CLASS; wc.hInstance = AfxGetInstanceHandle(); wc.lpfnWndProc = WindowProc; wc.hCursor = ::LoadCursor(NULL, IDC_ARROW); wc.hIcon = 0; wc.lpszMenuName = NULL; wc.hbrBackground = NULL; wc.style = CS_GLOBALCLASS|CS_DBLCLKS; wc.cbClsExtra = 0; wc.cbWndExtra = 0; // ×¢²á×Ô¶¨ÒåÀà return (::RegisterClass(&wc) != 0); } CServoGraph* CServoGraph::Hook(HWND hWnd) { CServoGraph* pServoGraph = (CServoGraph*)GetProp(hWnd, BYSTAG_SERVOGRAPH); if(pServoGraph == NULL) { pServoGraph = new CServoGraph; pServoGraph->m_hWnd = hWnd; SetProp(hWnd, BYSTAG_SERVOGRAPH, (HANDLE)pServoGraph); } return pServoGraph; } void CServoGraph::Release() { if (m_hWndTooltip != NULL) { ::DestroyWindow(m_hWndTooltip); m_hWndTooltip = NULL; } // delete delete this; } void CServoGraph::Notify(int nCode, int dwData, int dwData1/* = 0*/, int dwData2/* = 0*/) { HWND hParent; hParent = GetParent(m_hWnd); if(hParent != NULL) { BYSERVOGRAPH_NMHDR iii_nmhdr; iii_nmhdr.nmhdr.hwndFrom = m_hWnd; iii_nmhdr.nmhdr.idFrom = GetWindowLong(m_hWnd, GWL_ID); iii_nmhdr.nmhdr.code = nCode; iii_nmhdr.dwData = dwData; iii_nmhdr.dwData1 = dwData1; iii_nmhdr.dwData2 = dwData2; SendMessage(hParent, WM_NOTIFY, (WPARAM)iii_nmhdr.nmhdr.idFrom, (LPARAM)&iii_nmhdr); } } //////////////////////////////// // À¹½Ø´°¿ÚÏûÏ¢º¯Êý LRESULT CALLBACK CServoGraph::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CServoGraph* pServoGraph = (CServoGraph *)GetProp(hWnd, BYSTAG_SERVOGRAPH); if(pServoGraph == NULL && uMsg != WM_NCCREATE) { return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } // Èç¹ûHookÔòÏìÓ¦ÏûÏ¢ ASSERT(hWnd); switch(uMsg) { case WM_NCCREATE: return OnNcCreate(hWnd, wParam, lParam); case WM_DESTROY: return pServoGraph->OnDestroy(wParam, lParam); case WM_PAINT: return pServoGraph->OnPaint(wParam, lParam); case WM_TIMER: return pServoGraph->OnTimer(wParam, lParam); case WM_MOUSEMOVE: return pServoGraph->OnMouseMove(wParam, lParam); case WM_LBUTTONDOWN: return pServoGraph->OnLButtonDown(wParam, lParam); case WM_GETDLGCODE: return DLGC_WANTALLKEYS; default: break; } return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } /////////////////////////////// // WM_NCCREATE // ´°¿Ú´´½¨Ç°µÄ³õʼ»¯¹¤×÷ LRESULT CServoGraph::OnNcCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { CServoGraph* pServoGraph = (CServoGraph *)GetProp(hWnd, BYSTAG_SERVOGRAPH); ASSERT(pServoGraph == NULL); Hook(hWnd); return ::DefWindowProc(hWnd, WM_NCCREATE, wParam, lParam); } /////////////////////////////// // WM_DESTROY LRESULT CServoGraph::OnDestroy(WPARAM wParam, LPARAM lParam) { Release(); return ::DefWindowProc(m_hWnd, WM_DESTROY, wParam, lParam); } /////////////////////////////// // WM_TIMER LRESULT CServoGraph::OnTimer(WPARAM wParam, LPARAM lParam) { if (wParam == 1) { POINT pt; GetCursorPos(&pt); ::ScreenToClient(m_hWnd, &pt); void* pLastHighItem = m_pHighItem; int nHitCode = HitTest(pt, m_pHighItem); if (m_pHighItem != pLastHighItem) { ::InvalidateRect(m_hWnd, NULL, TRUE); } if (m_pHighItem == nullptr) { ::KillTimer(m_hWnd, 1); } } return ::DefWindowProc(m_hWnd, WM_TIMER, wParam, lParam); } /////////////////////////////// // WM_MOUSEMOVE LRESULT CServoGraph::OnMouseMove(WPARAM wParam, LPARAM lParam) { POINT pt; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); void* pLastHighItem = m_pHighItem; int nHitCode = HitTest(pt, m_pHighItem); if (m_pHighItem != pLastHighItem) { ::InvalidateRect(m_hWnd, NULL, TRUE); } if (m_pHighItem != NULL) { ::KillTimer(m_hWnd, 1); ::SetTimer(m_hWnd, 1, 100, NULL); } return ::DefWindowProc(m_hWnd, WM_MOUSEMOVE, wParam, lParam); } /* * WM_LBUTTONDOWN * Êó±ê×ó¼ü°´Ï */ LRESULT CServoGraph::OnLButtonDown(WPARAM wParam, LPARAM lParam) { POINT pt, ptNew; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); BOOL bButtonUp = FALSE; int nClickIndex = -1; void* pPressItem = nullptr; void* pTempItem = nullptr; HitTest(pt, pPressItem); // ²¶×½Êó±êÏûÏ¢£¬¼ì²âÊÇ·ñÍ϶¯ if (pPressItem != NULL) { ::KillTimer(m_hWnd, 1); if (::GetCapture() == NULL) { SetCapture(m_hWnd); ASSERT(m_hWnd == GetCapture()); AfxLockTempMaps(); for (;;) { MSG msg; VERIFY(::GetMessage(&msg, NULL, 0, 0)); if (GetCapture() != m_hWnd) break; switch (msg.message) { case WM_MOUSEMOVE: break; case WM_LBUTTONUP: ptNew = msg.pt; ::ScreenToClient(m_hWnd, &ptNew); HitTest(ptNew, pTempItem); if (pPressItem == pTempItem) { bButtonUp = TRUE; } goto ExitLoop; case WM_KEYDOWN: if (msg.wParam == VK_ESCAPE) { goto ExitLoop; } break; default: DispatchMessage(&msg); break; } } ExitLoop: ReleaseCapture(); ::InvalidateRect(m_hWnd, NULL, TRUE); if (bButtonUp) { Notify((int)BYSERVOGRAPH_ITEM_CLICKED, ((INDICATEBOX*)pPressItem)->id); } AfxUnlockTempMaps(FALSE); } } return ::DefWindowProc(m_hWnd, WM_LBUTTONDOWN, wParam, lParam); } /////////////////////////////// // WM_PAINT LRESULT CServoGraph::OnPaint(WPARAM wParam, LPARAM lParam) { HDC hDC, hMemDC; HBITMAP hBitmap; RECT rcClient; CString strText; HFONT hFont; HBRUSH hBrushBK; // BeginPaint PAINTSTRUCT ps; hDC = BeginPaint(m_hWnd, &ps); GetClientRect(m_hWnd, &rcClient); hMemDC = ::CreateCompatibleDC(hDC); hBitmap = ::CreateCompatibleBitmap(hDC, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top); ::SelectObject(hMemDC, hBitmap); hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); ::SelectObject(hMemDC, hFont); // ±³¾°ÑÕÉ« hBrushBK = CreateSolidBrush( m_crBkgnd ); ::FillRect(hMemDC, &rcClient, hBrushBK); DeleteObject(hBrushBK); // »­IMAGE HDC hDCTemp = ::CreateCompatibleDC(hMemDC); for (auto& item : m_images) { // ÔØÈëBMP if (item.hBitmap == nullptr) { item.hBitmap = (HBITMAP)LoadImage(AfxGetInstanceHandle(), item.szPath, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE); if (item.hBitmap != nullptr) { BITMAP bitmap; ::GetObject(item.hBitmap, sizeof(BITMAP), &bitmap); item.bmWidth = bitmap.bmWidth; item.bmHeight = bitmap.bmHeight; } } if (item.hBitmap != nullptr) { ::SelectObject(hDCTemp, item.hBitmap); ::BitBlt(hMemDC, item.x, item.y, item.bmWidth, item.bmHeight, hDCTemp, 0, 0, SRCCOPY); } } ::DeleteDC(hDCTemp); // »­±³¾°Ö¸Ê¾ for (auto& item : m_indicateBkgnds) { HBRUSH hbrBkgnd = CreateSolidBrush(item.backgroundColor); ::FillRect(hMemDC, &item.rect, hbrBkgnd); ::DeleteObject(hbrBkgnd); } // »­Ö¸Ê¾¿ò ::SetBkMode(hMemDC, TRANSPARENT); for (auto& item : m_indicateBoxs) { RECT rcItem; rcItem.left = item.x - item.box1Width / 2; rcItem.top = item.y - item.box1Width / 2; rcItem.right = rcItem.left + item.box1Width; rcItem.bottom = rcItem.top + item.box1Width; HBRUSH hbrFrame = CreateSolidBrush(m_pHighItem == &item ? item.box1FrameColor[1] : item.box1FrameColor[0]); HBRUSH hbrBkgnd = CreateSolidBrush(item.box1BackgroundColor); ::FillRect(hMemDC, &rcItem, hbrBkgnd); ::FrameRect(hMemDC, &rcItem, hbrFrame); ::DeleteObject(hbrBkgnd); ::DeleteObject(hbrFrame); if (item.bBox2Visible) { rcItem.left = item.x - item.box2Width / 2; rcItem.top = item.y - item.box2Width / 2; rcItem.right = rcItem.left + item.box2Width; rcItem.bottom = rcItem.top + item.box2Width; hbrFrame = CreateSolidBrush(item.box2FrameColor); hbrBkgnd = CreateSolidBrush(item.box2BackgroundColor); ::FillRect(hMemDC, &rcItem, hbrBkgnd); ::FrameRect(hMemDC, &rcItem, hbrFrame); ::DeleteObject(hbrBkgnd); ::DeleteObject(hbrFrame); } // text ::DrawText(hMemDC, item.szText, strlen(item.szText), &rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); } // EndPaint ::BitBlt(hDC, 0, 0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, hMemDC, 0, 0, SRCCOPY); EndPaint(m_hWnd, &ps); ::DeleteObject(hBitmap); ::DeleteDC(hMemDC); return 1; } void CServoGraph::SetBkgndColor(COLORREF cr) { m_crBkgnd = cr; } void CServoGraph::SetResDir(CString strDir) { m_strResDir = strDir; } void CServoGraph::AddImage(int id, char* pszPath, int x, int y) { if (GetImage(id) != nullptr) return; IMAGE image; memset(&image, 0, sizeof(IMAGE)); image.id = id; strcpy_s(image.szPath, MAX_PATH, pszPath); image.x = x; image.y = y; m_images.push_back(image); } CServoGraph::IMAGE* CServoGraph::GetImage(int id) { for (auto& item : m_images) { if (item.id == id) return &item; } return nullptr; } void CServoGraph::AddIndicateBox(int id, int x, int y, int width) { INDICATEBOX ib; ib.id = id; ib.x = x; ib.y = y; ib.box1Width = width; ib.box1FrameColor[0] = RGB(22, 22, 22); ib.box1FrameColor[1] = RGB(255, 127, 39); ib.box1BackgroundColor = RGB(245, 245, 245); ib.box2Width = width - 10; m_indicateBoxs.push_back(ib); } void CServoGraph::AddIndicateBox(int id, int x, int y, int width, COLORREF crFrame1, COLORREF crFrame2, COLORREF crBackground) { INDICATEBOX ib; ib.id = id; ib.x = x; ib.y = y; ib.box1Width = width; ib.box1FrameColor[0] = crFrame1; ib.box1FrameColor[1] = crFrame2; ib.box1BackgroundColor = crBackground; ib.box2Width = width - 10; m_indicateBoxs.push_back(ib); } void CServoGraph::AddIndicateBoxContext(int id, void* pContext) { INDICATEBOX* pib = GetIndicateBox(id); if (pib != nullptr) { pib->m_contexts.push_back(pContext); } } BOOL CServoGraph::RemoveIndicateBoxContext(int id, void* pContext) { INDICATEBOX* pib = GetIndicateBox(id); if (pib != nullptr) { for (auto iter = pib->m_contexts.begin(); iter != pib->m_contexts.end(); iter++) { if ((*iter) == pContext) { pib->m_contexts.erase(iter); return TRUE; } } } return FALSE; } BOOL CServoGraph::RemoveIndicateBoxAllContext(int id) { INDICATEBOX* pib = GetIndicateBox(id); if (pib != nullptr) { pib->m_contexts.clear(); return TRUE; } return FALSE; } const std::vector& CServoGraph::GetIndicateBoxContexts(int id) { static std::vector empty; INDICATEBOX* pib = GetIndicateBox(id); if (pib == nullptr) return empty; return pib->m_contexts; } bool CServoGraph::IsIndicateBoxContextsEmpty(int id) { INDICATEBOX* pib = GetIndicateBox(id); if (pib != nullptr) { return pib->m_contexts.empty(); } return true; } void CServoGraph::ShowIndicateBoxInterior(int id, COLORREF color) { INDICATEBOX* pib = GetIndicateBox(id); if (pib != nullptr) { pib->bBox2Visible = true; pib->box2FrameColor = RGB(128, 128, 128); pib->box2BackgroundColor = color; InvalidateRect(m_hWnd, NULL, TRUE); } } void CServoGraph::HideIndicateBoxInterior(int id) { INDICATEBOX* pib = GetIndicateBox(id); if (pib != nullptr) { pib->bBox2Visible = false; InvalidateRect(m_hWnd, NULL, TRUE); } } CServoGraph::INDICATEBOX* CServoGraph::GetIndicateBox(int id) { for (auto& item : m_indicateBoxs) { if (item.id == id) return &item; } return nullptr; } void CServoGraph::AddIndicateBkgnd(int id, int left, int top, int width, int height, COLORREF color) { INDICATEBKGND ibk; ibk.id = id; ibk.rect.left = left; ibk.rect.top = top; ibk.rect.right = ibk.rect.left + width; ibk.rect.bottom = ibk.rect.top + height;; ibk.backgroundColor = color; m_indicateBkgnds.push_back(ibk); } void CServoGraph::SetIndicateBkgndColor(int id, COLORREF color) { INDICATEBKGND* pibk = GetIndicateBkgnd(id); if (pibk != nullptr) { pibk->backgroundColor = color; InvalidateRect(m_hWnd, nullptr, TRUE); } } CServoGraph::INDICATEBKGND* CServoGraph::GetIndicateBkgnd(int id) { for (auto& item : m_indicateBkgnds) { if (item.id == id) return &item; } return nullptr; } /* * ¼ì²â×ø±êµãËùÔÚµÄÏî * ·µ»Ø, TYGTLITEM */ int CServoGraph::HitTest(POINT pt, OUT void*& pItem) { // ¼ì²âÊÇ·ñÔÚij¸ö×ÓÏî int nRet = HMGRAPH_HT_NOWHERE; pItem = NULL; RECT rcItem; for (int i = 0; i < m_indicateBoxs.size(); i++) { auto& item = m_indicateBoxs.at(i); GetIndicateBoxRect(&item, &rcItem); if (::PtInRect(&rcItem, pt)) { pItem = &item; nRet = HMGRAPH_HT_ITEM; break; } } return nRet; } void CServoGraph::GetIndicateBoxRect(INDICATEBOX* pBox, LPRECT lprcBox) { lprcBox->left = pBox->x - pBox->box1Width / 2; lprcBox->top = pBox->y - pBox->box1Width / 2; lprcBox->right = lprcBox->left + pBox->box1Width; lprcBox->bottom = lprcBox->top + pBox->box1Width; } BOOL CServoGraph::GetIndicateBoxRect(int id, LPRECT lprcBox) { INDICATEBOX* pBox = GetIndicateBox(id); if (pBox == nullptr) return FALSE; GetIndicateBoxRect(pBox, lprcBox); return TRUE; } HWND CServoGraph::GetSafeWnd() { return m_hWnd; } void CServoGraph::SetBoxText(int id, const char* pszText, const char* pszTooltip) { if (m_hWndTooltip == NULL) { m_hWndTooltip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWnd, NULL, NULL, NULL); ::SendMessage(m_hWndTooltip, TTM_SETMAXTIPWIDTH, 0, 500); } INDICATEBOX* pBox = GetIndicateBox(id); if (pBox != nullptr) { strcpy_s(pBox->szText, sizeof(pBox->szText), pszText); // tooltip TOOLINFO tti; memset(&tti, 0, sizeof(TOOLINFO)); tti.cbSize = sizeof(TOOLINFO); tti.uFlags = TTF_SUBCLASS; tti.hwnd = m_hWnd; GetIndicateBoxRect(pBox, &tti.rect); tti.uId = id; tti.lpszText = (LPSTR)pszTooltip; SendMessage(m_hWndTooltip, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&tti); } }