// 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<void*>& CServoGraph::GetIndicateBoxContexts(int id)
|
{
|
static std::vector<void*> 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);
|
}
|
}
|