| | |
| | | m_nMagneticLinHoz = 0; |
| | | m_nMagneticLinVer = 0; |
| | | m_hFontTitle = nullptr; |
| | | m_nIndicatorSize = 10; |
| | | m_nIndicatorMargin = 3; |
| | | |
| | | } |
| | | |
| | |
| | | |
| | | m_crItemIdText[0] = CColorTransfer::ApproximateColor(m_crItemNameText[0], -0.3f); |
| | | m_crItemIdText[1] = CColorTransfer::ApproximateColor(m_crItemNameText[1], -0.3f); |
| | | } |
| | | |
| | | void CEqsGraphWnd::SetIndicatorSize(int nSize) |
| | | { |
| | | if (nSize > 0) { |
| | | m_nIndicatorSize = nSize; |
| | | } |
| | | } |
| | | |
| | | void CEqsGraphWnd::SetIndicatorMargin(int nMargin) |
| | | { |
| | | if (nMargin >= 0) { |
| | | m_nIndicatorMargin = nMargin; |
| | | } |
| | | } |
| | | |
| | | void CEqsGraphWnd::EnableScroll(BOOL bEnable) |
| | |
| | | |
| | | void CEqsGraphWnd::SetOnListener(EqsGraphListener& listener) |
| | | { |
| | | m_listener.onConnectPin = listener.onConnectPin; |
| | | m_listener.onCheckConnectPin = listener.onCheckConnectPin; |
| | | m_listener.onDisconnectPin = listener.onDisconnectPin; |
| | | m_listener.onDeleteEqItem = listener.onDeleteEqItem; |
| | | m_listener.onEqItemPosChanged = listener.onEqItemPosChanged; |
| | | m_listener.onDblckEqItem = listener.onDblckEqItem; |
| | | m_listener.onRclickEqItem = listener.onRclickEqItem; |
| | | m_listener.onSelectEqItem = listener.onSelectEqItem; |
| | | m_listener = listener; |
| | | } |
| | | |
| | | BOOL CEqsGraphWnd::SetCurSel(int nSel) |
| | |
| | | return 0; |
| | | } |
| | | |
| | | void CEqsGraphWnd::SetManualRoute(PIN* pOutPin, PIN* pInPin, BOOL bUp) |
| | | { |
| | | if (pOutPin == NULL || pInPin == NULL) { |
| | | return; |
| | | } |
| | | if (pOutPin->pItem == NULL || pInPin->pItem == NULL) { |
| | | return; |
| | | } |
| | | |
| | | if (pOutPin->pConnectedPin != pInPin) { |
| | | pOutPin->pConnectedPin = pInPin; |
| | | pInPin->pConnectedPin = pOutPin; |
| | | } |
| | | |
| | | POINT pt1, pt2; |
| | | if (!GetPinPoint(pOutPin, &pt1) || !GetPinPoint(pInPin, &pt2)) { |
| | | return; |
| | | } |
| | | |
| | | RECT rc1, rc2; |
| | | GetItemRect(pOutPin->pItem, &rc1); |
| | | GetItemRect(pInPin->pItem, &rc2); |
| | | ::OffsetRect(&rc1, +m_nOffsetX, +m_nOffsetY); |
| | | ::OffsetRect(&rc2, +m_nOffsetX, +m_nOffsetY); |
| | | pt1.x += m_nOffsetX; |
| | | pt1.y += m_nOffsetY; |
| | | pt2.x += m_nOffsetX; |
| | | pt2.y += m_nOffsetY; |
| | | |
| | | int nMargin = 12; |
| | | int x1 = pt1.x + 10 + pOutPin->nIndex * nMargin; |
| | | int xEnd = pt2.x - 5; |
| | | int x2 = xEnd - (PINWIDTH + 12); |
| | | int y1; |
| | | if (bUp) { |
| | | int topY = min(rc1.top, rc2.top); |
| | | y1 = topY - 30 - pOutPin->nIndex * 6; |
| | | } |
| | | else { |
| | | int bottomY = max(rc1.bottom, rc2.bottom); |
| | | y1 = bottomY + 30 + pOutPin->nIndex * 6; |
| | | } |
| | | |
| | | pOutPin->ptConnectedLine[0].x = pt1.x; |
| | | pOutPin->ptConnectedLine[0].y = pt1.y; |
| | | pOutPin->ptConnectedLine[1].x = x1; |
| | | pOutPin->ptConnectedLine[1].y = pt1.y; |
| | | pOutPin->ptConnectedLine[2].x = x1; |
| | | pOutPin->ptConnectedLine[2].y = y1; |
| | | pOutPin->ptConnectedLine[3].x = x2; |
| | | pOutPin->ptConnectedLine[3].y = y1; |
| | | pOutPin->ptConnectedLine[4].x = x2; |
| | | pOutPin->ptConnectedLine[4].y = pt2.y; |
| | | pOutPin->ptConnectedLine[5].x = xEnd; |
| | | pOutPin->ptConnectedLine[5].y = pt2.y; |
| | | pOutPin->nLinePtCount = 6; |
| | | } |
| | | |
| | | // 删除Item, 如果pin有连接,注意先断开 |
| | | int CEqsGraphWnd::DeleteItem(EQITEM* pItem) |
| | | { |
| | |
| | | // 如果没有缓存线条的POINT,则先计算并缓存 |
| | | ASSERT(pOwnerPin); |
| | | |
| | | bool canDraw = (pGraphics != nullptr && pPen != nullptr); |
| | | |
| | | int nPinCount = ((CPtrArray*)pOwnerPin->pItem->pOutPins)->GetSize(); |
| | | int nArrowLen = 8; |
| | | int nStartMinX = 8; |
| | |
| | | pOwnerPin->nLinePtCount = 6; |
| | | } |
| | | else { |
| | | int baseY = max(lpRect1->bottom, lpRect2->bottom) + 30; |
| | | y1 = baseY + pOwnerPin->nIndex * nMargin; |
| | | x2 = min(lpRect1->left, lpRect2->left) - 30; |
| | | y1 = max(lpRect1->bottom, lpRect2->bottom) + 30; |
| | | pOwnerPin->ptConnectedLine[0].x = lpPt1->x; |
| | | pOwnerPin->ptConnectedLine[0].y = lpPt1->y; |
| | | pOwnerPin->ptConnectedLine[1].x = x1; |
| | |
| | | } |
| | | } |
| | | |
| | | if (!canDraw) { |
| | | return; |
| | | } |
| | | |
| | | if (pOwnerPin->nLinePtCount >= 2) { |
| | | const int kJumpRadius = 6; |
| | | for (int i = 0; i < pOwnerPin->nLinePtCount - 1; i++) { |
| | | pGraphics->DrawLine(pPen, pOwnerPin->ptConnectedLine[i].x - m_nOffsetX, pOwnerPin->ptConnectedLine[i].y - m_nOffsetY, |
| | | pOwnerPin->ptConnectedLine[i + 1].x - m_nOffsetX, pOwnerPin->ptConnectedLine[i + 1].y - m_nOffsetY); |
| | | POINT a = pOwnerPin->ptConnectedLine[i]; |
| | | POINT b = pOwnerPin->ptConnectedLine[i + 1]; |
| | | bool isHorizontal = (a.y == b.y); |
| | | bool jumped = false; |
| | | |
| | | if (isHorizontal) { |
| | | int y = a.y; |
| | | int xMin = min(a.x, b.x); |
| | | int xMax = max(a.x, b.x); |
| | | bool found = false; |
| | | int hitX = 0; |
| | | int x1 = 0; |
| | | int x2 = 0; |
| | | for (const auto& seg : m_verticalSegments) { |
| | | bool segVertical = (seg.a.x == seg.b.x); |
| | | if (!segVertical) { |
| | | continue; |
| | | } |
| | | int vx = seg.a.x; |
| | | int vyMin = min(seg.a.y, seg.b.y); |
| | | int vyMax = max(seg.a.y, seg.b.y); |
| | | if (vx > xMin + 1 && vx < xMax - 1 |
| | | && y > vyMin + 1 && y < vyMax - 1) { |
| | | hitX = vx; |
| | | found = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (found) { |
| | | x1 = hitX - kJumpRadius; |
| | | x2 = hitX + kJumpRadius; |
| | | if (x1 <= xMin) x1 = xMin + 1; |
| | | if (x2 >= xMax) x2 = xMax - 1; |
| | | if (x2 <= x1) { |
| | | found = false; |
| | | } |
| | | } |
| | | |
| | | if (found) { |
| | | pGraphics->DrawLine(pPen, a.x - m_nOffsetX, a.y - m_nOffsetY, |
| | | x1 - m_nOffsetX, y - m_nOffsetY); |
| | | |
| | | Gdiplus::Rect arcRect(x1 - m_nOffsetX, y - kJumpRadius - m_nOffsetY, kJumpRadius * 2, kJumpRadius * 2); |
| | | pGraphics->DrawArc(pPen, arcRect, 180.0f, -180.0f); |
| | | |
| | | pGraphics->DrawLine(pPen, x2 - m_nOffsetX, y - m_nOffsetY, |
| | | b.x - m_nOffsetX, b.y - m_nOffsetY); |
| | | jumped = true; |
| | | } |
| | | } |
| | | if (!jumped) { |
| | | pGraphics->DrawLine(pPen, a.x - m_nOffsetX, a.y - m_nOffsetY, |
| | | b.x - m_nOffsetX, b.y - m_nOffsetY); |
| | | } |
| | | |
| | | } |
| | | |
| | | DrawArrow(pGraphics, pBrush, pPen, pOwnerPin->ptConnectedLine[pOwnerPin->nLinePtCount-1].x - m_nOffsetX, |
| | |
| | | GetItemRect(m_pCurItem, &rcItem); |
| | | |
| | | if (::GetCapture() == NULL) { |
| | | const int kDragThreshold = 3; // debounce: click should not trigger line recalculation |
| | | bool bDragging = false; |
| | | SetCapture(m_hWnd); |
| | | ASSERT(m_hWnd == GetCapture()); |
| | | AfxLockTempMaps(); |
| | |
| | | case WM_MOUSEMOVE: |
| | | ptNew = msg.pt; |
| | | ::ScreenToClient(m_hWnd, &ptNew); |
| | | if (!bDragging) { |
| | | if (abs(ptNew.x - pt.x) >= kDragThreshold || abs(ptNew.y - pt.y) >= kDragThreshold) { |
| | | bDragging = true; |
| | | } |
| | | else { |
| | | break; |
| | | } |
| | | } |
| | | rcNewItem.left = rcItem.left + (ptNew.x - pt.x); |
| | | rcNewItem.right = rcItem.right + (ptNew.x - pt.x); |
| | | rcNewItem.top = rcItem.top + (ptNew.y - pt.y); |
| | |
| | | case WM_LBUTTONUP: |
| | | ptNew = msg.pt; |
| | | ::ScreenToClient(m_hWnd, &ptNew); |
| | | if (!bDragging) { |
| | | ReleaseCapture(); |
| | | goto ExitLoop; |
| | | } |
| | | m_pCurItem->rect.left = m_nMagneticLinVer > 0 ? m_nMagneticLinVer : (rcItem.left + (ptNew.x - pt.x) + m_nOffsetX); |
| | | m_pCurItem->rect.right = m_pCurItem->rect.left + (rcItem.right - rcItem.left); |
| | | m_pCurItem->rect.top = m_nMagneticLinHoz > 0 ? m_nMagneticLinHoz : (rcItem.top + (ptNew.y - pt.y) + m_nOffsetY); |
| | |
| | | ::DrawText(hMemDC, pItem->text, (int)strlen(pItem->text), &rcItem, |
| | | DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); |
| | | |
| | | // 多个指示灯:左上角,按 4 列 × 2 行排列 |
| | | const int indicatorSize = 10; |
| | | const int indicatorMargin = 3; |
| | | const int indicatorsPerRow = 4; |
| | | // indicators vertical column layout |
| | | const int indicatorSize = m_nIndicatorSize; |
| | | const int indicatorMargin = m_nIndicatorMargin; |
| | | const int indicatorX = rcItem.left + 5; |
| | | |
| | | for (int k = 0; k < EQITEM_INDICATOR_COUNT; ++k) { |
| | | BYTE indicatorState = pItem->nIndicatorState[k]; |
| | |
| | | continue; |
| | | } |
| | | |
| | | int row = k / indicatorsPerRow; |
| | | int col = k % indicatorsPerRow; |
| | | |
| | | RECT rcIndicator; |
| | | rcIndicator.left = rcItem.left + 5 + col * (indicatorSize + indicatorMargin); |
| | | rcIndicator.top = rcItem.top + 5 + row * (indicatorSize + indicatorMargin); |
| | | rcIndicator.left = indicatorX; |
| | | rcIndicator.top = rcItem.top + 5 + k * (indicatorSize + indicatorMargin); |
| | | rcIndicator.right = rcIndicator.left + indicatorSize; |
| | | rcIndicator.bottom = rcIndicator.top + indicatorSize; |
| | | |
| | | |
| | | // 画高亮/灰色方块 |
| | | RECT rcInner = rcIndicator; |
| | | ::InflateRect(&rcInner, -1, -1); |
| | | ::FillRect(hMemDC, &rcInner, indicatorState == INDICATOR_STATE_HIGHLIGHT |
| | |
| | | ::SelectObject(hMemDC, hFontOld); |
| | | } |
| | | |
| | | // 预先计算所有连接线的点并收集垂直线段,用于跳线判断 |
| | | m_verticalSegments.clear(); |
| | | for (int i = 0; i < nItemCount; i++) { |
| | | EQITEM* pItem = (EQITEM*)m_arItem.GetAt(i); |
| | | if (pItem->nFlashFlag == 1) { |
| | | continue; |
| | | } |
| | | |
| | | PIN* pPin = NULL; |
| | | CPtrArray* pPins = (CPtrArray*)pItem->pOutPins; |
| | | RECT rcItem1, rcItem2; |
| | | for (int j = 0; j < pPins->GetSize(); j++) { |
| | | pPin = (PIN*)pPins->GetAt(j); |
| | | if (pPin->pConnectedPin != NULL) { |
| | | POINT pt1, pt2; |
| | | if (GetPinPoint(pPin, &pt1) && GetPinPoint(pPin->pConnectedPin, &pt2)) { |
| | | GetItemRect(pItem, &rcItem1); |
| | | GetItemRect(pPin->pConnectedPin->pItem, &rcItem2); |
| | | DrawPinConnectedLine(nullptr, nullptr, nullptr, &pt1, &pt2, &rcItem1, &rcItem2, pPin); |
| | | if (pPin->nLinePtCount >= 2) { |
| | | for (int k = 0; k < pPin->nLinePtCount - 1; k++) { |
| | | POINT a = pPin->ptConnectedLine[k]; |
| | | POINT b = pPin->ptConnectedLine[k + 1]; |
| | | if (a.x == b.x) { |
| | | LineSeg seg; |
| | | seg.a = a; |
| | | seg.b = b; |
| | | m_verticalSegments.push_back(seg); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 再绘制连接线 |
| | | for (int i = 0; i < nItemCount; i++) { |
| | | EQITEM* pItem = (EQITEM*)m_arItem.GetAt(i); |