void CKademlia::StatsAddClosestDistance(CUInt128 uDist){ if (uDist.Get32BitChunk(0) > 0){ uint32_t nToAdd = (0xFFFFFFFF / uDist.Get32BitChunk(0)) / 2; if (m_liStatsEstUsersProbes.Find(nToAdd) == NULL) m_liStatsEstUsersProbes.AddHead(nToAdd); } if (m_liStatsEstUsersProbes.GetCount() > 100) m_liStatsEstUsersProbes.RemoveTail(); }
void CKademlia::StatsAddClosestDistance(const CUInt128& distance) { if (distance.Get32BitChunk(0) > 0) { uint32_t toAdd = (0xFFFFFFFF / distance.Get32BitChunk(0)) / 2; std::list<uint32_t>::iterator it = m_statsEstUsersProbes.begin(); for (; it != m_statsEstUsersProbes.end(); ++it) { if (*it == toAdd) { break; } } if (it == m_statsEstUsersProbes.end()) { m_statsEstUsersProbes.push_front(toAdd); } } if (m_statsEstUsersProbes.size() > 100) { m_statsEstUsersProbes.pop_back(); } }
void CKadLookupGraph::OnPaint() { m_aNodesDrawRects.RemoveAll(); CPaintDC pdc(this); CRect rcClnt; GetClientRect(&rcClnt); if (rcClnt.IsRectEmpty()) return; CMemDC dc(&pdc, rcClnt); CPen* pOldPen = dc.SelectObject(&m_penAxis); if (g_xpStyle.IsThemeActive() && g_xpStyle.IsAppThemed()) { HTHEME hTheme = g_xpStyle.OpenThemeData(NULL, L"ListView"); if (hTheme) { g_xpStyle.DrawThemeBackground(hTheme, dc.m_hDC, 3, 0, &rcClnt, NULL); g_xpStyle.CloseThemeData(hTheme); } } else { dc.Rectangle(&rcClnt); } rcClnt.DeflateRect(1, 1, 1, 1); dc.FillSolidRect(rcClnt, GetSysColor(COLOR_WINDOW)); rcClnt.DeflateRect(1, 1, 1, 1); COLORREF crOldTextColor = dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); CFont* pOldFont = dc.SelectObject(AfxGetMainWnd()->GetFont()); if (!m_bInitializedFontMetrics) { TEXTMETRIC tm; dc.GetTextMetrics(&tm); // why is 'tm.tmMaxCharWidth' and 'tm.tmAveCharWidth' that wrong? CRect rcLabel; dc.DrawText(_T("888"), 3, &rcLabel, DT_CALCRECT); m_iMaxNumLabelWidth = rcLabel.Width(); if (m_iMaxNumLabelWidth <= 0) m_iMaxNumLabelWidth = 3*8; m_iMaxLabelHeight = tm.tmHeight; if (m_iMaxLabelHeight <= 0) m_iMaxLabelHeight = 8; m_bInitializedFontMetrics = true; } int iLeftBorder = 3; int iRightBorder = 8; int iTopBorder = m_iMaxLabelHeight; int iBottomBorder = m_iMaxLabelHeight; int iBaseLineX = iLeftBorder; int iBaseLineY = rcClnt.bottom - iBottomBorder; UINT uHistWidth = rcClnt.Width() - iLeftBorder - iRightBorder; UINT uHistHeight = rcClnt.Height() - iTopBorder - iBottomBorder; if (uHistHeight == 0) { dc.SelectObject(pOldFont); dc.SetTextColor(crOldTextColor); return; } dc.MoveTo(iBaseLineX, rcClnt.top + iTopBorder); dc.LineTo(iBaseLineX, iBaseLineY); dc.LineTo(iBaseLineX + uHistWidth, iBaseLineY); dc.SelectObject(&m_penAux); CRect rcLabel(rcClnt); rcLabel.left = iBaseLineX; rcLabel.bottom = m_iMaxLabelHeight; dc.DrawText(m_strYaxis, m_strYaxis.GetLength(), &rcLabel, DT_LEFT | DT_TOP | DT_NOCLIP); rcLabel = rcClnt; rcLabel.top = rcClnt.bottom - m_iMaxLabelHeight + 1; dc.DrawText(m_strXaxis, m_strXaxis.GetLength(), &rcLabel, DT_RIGHT | DT_BOTTOM | DT_NOCLIP); if (m_pLookupHistory != NULL && m_pLookupHistory->GetHistoryEntries().GetCount() >= 1) { // How many nodes can we show without scrolling? sint32 uMaxNodes = uHistWidth / NODE_ENTRY_WIDTH; uint32 uNodeEntryWidth = 0; if (m_pLookupHistory->GetHistoryEntries().GetCount() > uMaxNodes /*|| !m_pLookupHistory->IsSearchStopped()*/) uNodeEntryWidth = NODE_ENTRY_WIDTH; // While the search is running, use a fixed width else uNodeEntryWidth = uHistWidth / m_pLookupHistory->GetHistoryEntries().GetCount(); // when the search is finished, use all available screen space sint32 iVisibleNodes = min(uMaxNodes, m_pLookupHistory->GetHistoryEntries().GetCount()); // Set the scaling. 3 times the highest distance of the 1/3 closest nodes is the max distance CArray<CUInt128> aClosest; for (int i = 1; i <= iVisibleNodes; i++) { if (aClosest.GetCount() < ((iVisibleNodes / 3 == 0) ? 1 : (iVisibleNodes / 3))) aClosest.Add(m_pLookupHistory->GetHistoryEntries()[m_pLookupHistory->GetHistoryEntries().GetCount() - i]->m_uDistance); else { int iReplace = -1; for (int j = 0; j < aClosest.GetCount(); j++) { if ((iReplace == (-1) && aClosest[j] > m_pLookupHistory->GetHistoryEntries()[m_pLookupHistory->GetHistoryEntries().GetCount() - i]->m_uDistance) || (iReplace >= 0 && aClosest[j] > aClosest[iReplace])) { iReplace = j; } } if (iReplace >= 0) aClosest[iReplace] = m_pLookupHistory->GetHistoryEntries()[m_pLookupHistory->GetHistoryEntries().GetCount() - i]->m_uDistance; } } CUInt128 uTmpScalingDistance((ULONG)0); for (int j = 0; j < aClosest.GetCount(); j++) { if (aClosest[j] > uTmpScalingDistance) uTmpScalingDistance = aClosest[j]; } // Convert it to uint64 by cutting of the less significant bits for easier and fast calculating uint64 uScalingDistance = 0; uint8 byStartChunk; for (byStartChunk = 0; byStartChunk < 3; byStartChunk++) { if (uTmpScalingDistance.Get32BitChunk(byStartChunk) > 0) { uScalingDistance = ((uint64)uTmpScalingDistance.Get32BitChunk(byStartChunk) << 32) + (uint64)uTmpScalingDistance.Get32BitChunk(byStartChunk + 1); break; } } if (uScalingDistance == 0) { byStartChunk = 2; uScalingDistance = uTmpScalingDistance.Get32BitChunk(3); } uScalingDistance /= (uHistHeight - NODE_ENTRY_HEIGHT); uScalingDistance *= 3; ASSERT(uScalingDistance > 0); if (uScalingDistance == 0) uScalingDistance = 1; //if (m_bDbgLog) // AddDebugLogLine(false, _T("KadGraph: Considering %u of %u Nodes, 1/3 Max Distance found: %s"), iVisibleNodes, m_pLookupHistory->GetHistoryEntries().GetCount(), uTmpScalingDistance.ToHexString()); CUInt128 uMaxScalingDistance(uTmpScalingDistance); uMaxScalingDistance.Add(uTmpScalingDistance); uMaxScalingDistance.Add(uTmpScalingDistance); // wow, what a mess, now lets collect drawing points for (int i = 1; i <= iVisibleNodes; i++) { CUInt128 uTmpDist = m_pLookupHistory->GetHistoryEntries()[m_pLookupHistory->GetHistoryEntries().GetCount() - i]->m_uDistance; uint64 uDrawYPos; if (uTmpDist > uMaxScalingDistance) uDrawYPos = iTopBorder; else { uDrawYPos = (((uint64)uTmpDist.Get32BitChunk(byStartChunk) << 32) + (uint64)uTmpDist.Get32BitChunk(byStartChunk + 1)); if (uDrawYPos > 0) uDrawYPos /= uScalingDistance; uDrawYPos = (iBaseLineY - NODE_ENTRY_HEIGHT) - uDrawYPos; } //if (m_bDbgLog) // AddDebugLogLine(false, _T("KadGraph: Drawing Node %u of %u, Distance: %s, Y-Pos: %u"), (iVisibleNodes - i) + 1, iVisibleNodes, uTmpDist.ToHexString(), uDrawYPos); ASSERT( uDrawYPos <= (uHistHeight) ); uint32 nXOffset = 0; //if (uMaxNodes > iVisibleNodes && !m_pLookupHistory->IsSearchStopped()) // Fixed width for ongoing searches // nXOffset = NODE_ENTRY_WIDTH * (uMaxNodes - iVisibleNodes); CPoint pointNode(uHistWidth - nXOffset - (i * uNodeEntryWidth), (uint32)uDrawYPos); m_aNodesDrawRects.Add(CRect(pointNode, CSize(NODE_ENTRY_WIDTH, NODE_ENTRY_HEIGHT))); } ASSERT( iVisibleNodes == m_aNodesDrawRects.GetCount() ); // find HotItem (if any) m_iHotItemIdx = (-1); CPoint ptCursor; if (GetCursorPos(&ptCursor)) { CRect rectWnd; GetWindowRect(&rectWnd); if (rectWnd.PtInRect(ptCursor)) { ScreenToClient(&ptCursor); m_iHotItemIdx = CheckHotItem(ptCursor); } } m_pToolTip->Activate(m_iHotItemIdx >= 0 ? TRUE : FALSE); UpdateToolTip(); CArray<bool> abHotItemConnected; if (m_iHotItemIdx >= 0) { abHotItemConnected.SetSize(iVisibleNodes); for (int i = 0; i < iVisibleNodes; i++) abHotItemConnected[i] = (m_iHotItemIdx == i); } // start drawing, beginning with the arrowClines connecting the nodes // if possible use GDI+ for Anti Aliasing extern bool g_bGdiPlusInstalled; ULONG_PTR gdiplusToken = 0; Gdiplus::GdiplusStartupInput gdiplusStartupInput; if (g_bGdiPlusInstalled && Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) == Gdiplus::Ok) { { Gdiplus::Graphics gdipGraphic(dc); gdipGraphic.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); Gdiplus::AdjustableArrowCap gdipArrow(6, 4); Gdiplus::Pen gdipPenGray(Gdiplus::Color(192, 192, 192), 0.8f); gdipPenGray.SetCustomEndCap(&gdipArrow); Gdiplus::Pen gdipPenDarkGray(Gdiplus::Color(100, 100, 100), 0.8f); gdipPenDarkGray.SetCustomEndCap(&gdipArrow); Gdiplus::Pen gdipPenRed(Gdiplus::Color(255, 32, 32), 0.8f); gdipPenRed.SetCustomEndCap(&gdipArrow); for (int i = 0; i < iVisibleNodes; i++) { const CLookupHistory::SLookupHistoryEntry* sEntry = m_pLookupHistory->GetHistoryEntries()[m_pLookupHistory->GetHistoryEntries().GetCount() - (i + 1)]; for (int j = 0; j < sEntry->m_liReceivedFromIdx.GetCount(); j++) { int iIdx = sEntry->m_liReceivedFromIdx[j]; if (iIdx >= m_pLookupHistory->GetHistoryEntries().GetCount() - iVisibleNodes) { CPoint pFrom = m_aNodesDrawRects[m_pLookupHistory->GetHistoryEntries().GetCount() - (iIdx + 1)].CenterPoint(); CPoint pointTo = m_aNodesDrawRects[i].CenterPoint(); Gdiplus::Pen* pen; if (m_pLookupHistory->GetHistoryEntries().GetCount() - (iIdx + 1) == m_iHotItemIdx) { abHotItemConnected[i] = true; pen = &gdipPenRed; } else if (i == m_iHotItemIdx) { abHotItemConnected[m_pLookupHistory->GetHistoryEntries().GetCount() - (iIdx + 1)] = true; pen = &gdipPenDarkGray; } else pen = &gdipPenGray; gdipGraphic.DrawLine(pen, pFrom.x, pFrom.y, pointTo.x, pointTo.y); } } } } Gdiplus::GdiplusShutdown(gdiplusToken); } else { for (int i = 0; i < iVisibleNodes; i++) { const CLookupHistory::SLookupHistoryEntry* sEntry = m_pLookupHistory->GetHistoryEntries()[m_pLookupHistory->GetHistoryEntries().GetCount() - (i + 1)]; for (int j = 0; j < sEntry->m_liReceivedFromIdx.GetCount(); j++) { int iIdx = sEntry->m_liReceivedFromIdx[j]; if (iIdx >= m_pLookupHistory->GetHistoryEntries().GetCount() - iVisibleNodes) { CPoint pFrom = m_aNodesDrawRects[m_pLookupHistory->GetHistoryEntries().GetCount() - (iIdx + 1)].CenterPoint(); CPoint pointTo = m_aNodesDrawRects[i].CenterPoint(); if (m_pLookupHistory->GetHistoryEntries().GetCount() - (iIdx + 1) == m_iHotItemIdx) { abHotItemConnected[i] = true; dc.SelectObject(&m_penRed); } else { if (i == m_iHotItemIdx) abHotItemConnected[m_pLookupHistory->GetHistoryEntries().GetCount() - (iIdx + 1)] = true; dc.SelectObject(&m_penAux); } POINT aptPoly[3]; POINT pBase; float vecLine[2]; float vecLeft[2]; int nWidth = 4; // set to point aptPoly[0].x = pointTo.x; aptPoly[0].y = pointTo.y; // build the line vector vecLine[0] = (float) aptPoly[0].x - pFrom.x; vecLine[1] = (float) aptPoly[0].y - pFrom.y; // build the arrow base vector - normal to the line vecLeft[0] = -vecLine[1]; vecLeft[1] = vecLine[0]; // setup length parameters float fLength = (float) sqrt(vecLine[0] * vecLine[0] + vecLine[1] * vecLine[1]); float th = nWidth / (2.0f * fLength); float ta = nWidth / (2.0f * (tanf(0.3f) / 2.0f) * fLength); // find the base of the arrow pBase.x = (int) (aptPoly[0].x + -ta * vecLine[0]); pBase.y = (int) (aptPoly[0].y + -ta * vecLine[1]); // build the points on the sides of the arrow aptPoly[1].x = (int) (pBase.x + th * vecLeft[0]); aptPoly[1].y = (int) (pBase.y + th * vecLeft[1]); aptPoly[2].x = (int) (pBase.x + -th * vecLeft[0]); aptPoly[2].y = (int) (pBase.y + -th * vecLeft[1]); dc.MoveTo(pFrom); dc.LineTo(aptPoly[0].x, aptPoly[0].y); dc.Polygon(aptPoly, 3); } } } } // draw the nodes images for (int i = 0; i < iVisibleNodes; i++) { CPoint pointNode = m_aNodesDrawRects[i].CenterPoint(); pointNode.x -= 8; pointNode.y -= 8; uint8 byIconIdx = 0; const CLookupHistory::SLookupHistoryEntry* sEntry = m_pLookupHistory->GetHistoryEntries()[m_pLookupHistory->GetHistoryEntries().GetCount() - (i + 1)]; if (sEntry->m_dwAskedContactsTime > 0) { if (sEntry->m_uRespondedContact > 0) byIconIdx = sEntry->m_bProvidedCloser ? 0 : 1; // green or blue else if (sEntry->m_dwAskedContactsTime + SEC2MS(3) < ::GetTickCount()) byIconIdx = 3; // red else byIconIdx = 2; // yellow } else if (sEntry->m_bForcedInteresting) byIconIdx = 2; else ASSERT( false ); if (m_iHotItemIdx >= 0 && !abHotItemConnected[i]) m_iml.DrawEx(&dc, byIconIdx, pointNode, CSize(0, 0), CLR_NONE, GetSysColor(COLOR_WINDOW), ILD_BLEND50); else m_iml.Draw(&dc, byIconIdx, pointNode, ILD_NORMAL); if (sEntry->m_dwAskedSearchItemTime > 0) { // Draw the Icon indicating that we asked this Node for results // enough space above? if not below CPoint pointIndicator = pointNode; if (pointIndicator.y - 16 - 4 >= iTopBorder) pointIndicator.y -= 20; else pointIndicator.y += 20; switch (m_pLookupHistory->GetType()) { case Kademlia::CSearch::FILE: case Kademlia::CSearch::KEYWORD: case Kademlia::CSearch::NOTES: { int nOverlayImage = 0; if (sEntry->m_uRespondedSearchItem > 0) nOverlayImage = 1; else if (sEntry->m_dwAskedSearchItemTime + SEC2MS(5) < ::GetTickCount()) nOverlayImage = 2; m_iml.Draw(&dc, 4, pointIndicator, ILD_NORMAL | INDEXTOOVERLAYMASK(nOverlayImage)); break; } case Kademlia::CSearch::STOREFILE: m_iml.Draw(&dc, 6, pointIndicator, ILD_NORMAL); break; case Kademlia::CSearch::STOREKEYWORD: case Kademlia::CSearch::STORENOTES: m_iml.Draw(&dc, 5, pointIndicator, ILD_NORMAL); break; /* Nothing to show case CSearch::NODE: case CSearch::NODECOMPLETE: case CSearch::NODESPECIAL: case CSearch::NODEFWCHECKUDP: case CSearch::FINDBUDDY: default:*/ } } } } m_bDbgLog = false; dc.SelectObject(pOldPen); dc.SelectObject(pOldFont); dc.SetTextColor(crOldTextColor); }