Drop unused code
[TortoiseGit.git] / src / TortoiseProc / RevisionGraph / RevisionGraphDlgDraw.cpp
blobd763cf89e74c55d5665df03d29f4e2afdf81309c
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2011, 2015 - TortoiseSVN
4 // Copyright (C) 2012-2013, 2015-2018 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "TortoiseProc.h"
22 #include "MyMemDC.h"
23 #include "RevisionGraphDlg.h"
24 #include "Git.h"
25 #include "TempFile.h"
26 #include "UnicodeUtils.h"
27 #include "TGitPath.h"
28 //#include "SVNInfo.h"
29 //#include "SVNDiff.h"
30 #include "RevisionGraphWnd.h"
31 //#include "IRevisionGraphLayout.h"
32 //#include "UpsideDownLayout.h"
33 //#include "ShowTreeStripes.h"
34 #include "registry.h"
35 #include "UnicodeUtils.h"
36 #include "DPIAware.h"
38 #ifdef _DEBUG
39 #define new DEBUG_NEW
40 #undef THIS_FILE
41 static char THIS_FILE[] = __FILE__;
42 #endif
44 using namespace Gdiplus;
46 Color GetColorFromSysColor(int nIndex)
48 Color color;
49 color.SetFromCOLORREF(GetSysColor(nIndex));
50 return color;
53 /************************************************************************/
54 /* Graphing functions */
55 /************************************************************************/
56 CFont* CRevisionGraphWnd::GetFont(BOOL bItalic /*= FALSE*/, BOOL bBold /*= FALSE*/)
58 int nIndex = 0;
59 if (bBold)
60 nIndex |= 1;
61 if (bItalic)
62 nIndex |= 2;
63 if (!m_apFonts[nIndex])
65 m_apFonts[nIndex] = new CFont;
66 m_lfBaseFont.lfWeight = bBold ? FW_BOLD : FW_NORMAL;
67 m_lfBaseFont.lfItalic = (BYTE) bItalic;
68 m_lfBaseFont.lfStrikeOut = (BYTE) FALSE;
69 m_lfBaseFont.lfHeight = -CDPIAware::Instance().PointsToPixelsY(m_nFontSize);
70 // use the empty font name, so GDI takes the first font which matches
71 // the specs. Maybe this will help render chinese/japanese chars correctly.
72 wcsncpy_s(m_lfBaseFont.lfFaceName, L"MS Shell Dlg 2", _countof(m_lfBaseFont.lfFaceName) - 1);
73 if (!m_apFonts[nIndex]->CreateFontIndirect(&m_lfBaseFont))
75 delete m_apFonts[nIndex];
76 m_apFonts[nIndex] = nullptr;
77 return CWnd::GetFont();
80 return m_apFonts[nIndex];
83 BOOL CRevisionGraphWnd::OnEraseBkgnd(CDC* /*pDC*/)
85 return TRUE;
88 void CRevisionGraphWnd::OnPaint()
90 CPaintDC dc(this); // device context for painting
91 CRect rect = GetClientRect();
93 if (IsUpdateJobRunning())
95 CString fetch = CString(MAKEINTRESOURCE(IDS_PROC_LOADING));
96 dc.FillSolidRect(rect, ::GetSysColor(COLOR_APPWORKSPACE));
97 dc.ExtTextOut(20, 20, ETO_CLIPPED, nullptr, fetch, nullptr);
98 CWnd::OnPaint();
99 return;
101 }else if (this->m_Graph.empty())
103 CString sNoGraphText;
104 sNoGraphText.LoadString(IDS_REVGRAPH_ERR_NOGRAPH);
105 dc.FillSolidRect(rect, RGB(255,255,255));
106 dc.ExtTextOut(20, 20, ETO_CLIPPED, nullptr, sNoGraphText, nullptr);
107 return;
110 GraphicsDevice dev;
111 dev.pDC = &dc;
112 DrawGraph(dev, rect, GetScrollPos(SB_VERT), GetScrollPos(SB_HORZ), false);
115 void CRevisionGraphWnd::CutawayPoints (const RectF& rect, float cutLen, TCutRectangle& result)
117 result[0] = PointF (rect.X, rect.Y + cutLen);
118 result[1] = PointF (rect.X + cutLen, rect.Y);
119 result[2] = PointF (rect.GetRight() - cutLen, rect.Y);
120 result[3] = PointF (rect.GetRight(), rect.Y + cutLen);
121 result[4] = PointF (rect.GetRight(), rect.GetBottom() - cutLen);
122 result[5] = PointF (rect.GetRight() - cutLen, rect.GetBottom());
123 result[6] = PointF (rect.X + cutLen, rect.GetBottom());
124 result[7] = PointF (rect.X, rect.GetBottom() - cutLen);
127 void CRevisionGraphWnd::DrawRoundedRect (GraphicsDevice& graphics, const Color& penColor, int penWidth, const Pen* pen, const Color& fillColor, const Brush* brush, const RectF& rect, int mask)
129 enum {POINT_COUNT = 8};
131 float radius = CORNER_SIZE * m_fZoomFactor;
132 PointF points[POINT_COUNT];
133 CutawayPoints (rect, radius, points);
135 if (graphics.graphics)
137 GraphicsPath path;
139 if(mask & ROUND_UP)
141 path.AddArc (points[0].X, points[1].Y, radius, radius, 180, 90);
142 path.AddArc (points[2].X, points[2].Y, radius, radius, 270, 90);
143 }else
144 path.AddLine(points[0].X, points[1].Y, points[3].X, points[2].Y);
146 if(mask & ROUND_DOWN)
148 path.AddArc (points[5].X, points[4].Y, radius, radius, 0, 90);
149 path.AddArc (points[7].X, points[7].Y, radius, radius, 90, 90);
150 }else
152 path.AddLine(points[3].X, points[3].Y, points[4].X, points[5].Y);
153 path.AddLine(points[4].X, points[5].Y, points[7].X, points[6].Y);
156 points[0].Y -= radius / 2;
157 path.AddLine (points[7], points[0]);
159 if (brush)
160 graphics.graphics->FillPath (brush, &path);
161 if (pen)
162 graphics.graphics->DrawPath (pen, &path);
164 else if (graphics.pSVG)
165 graphics.pSVG->RoundedRectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height, penColor, penWidth, fillColor, (int)radius, mask);
168 void CRevisionGraphWnd::DrawOctangle (GraphicsDevice& graphics, const Color& penColor, int penWidth, const Pen* pen, const Color& fillColor, const Brush* brush, const RectF& rect)
170 enum {POINT_COUNT = 8};
172 // show left & right edges of low boxes as "<===>"
174 float minCutAway = min (CORNER_SIZE * m_fZoomFactor, rect.Height / 2);
176 // larger boxes: remove 25% of the shorter side
178 float suggestedCutAway = min (rect.Height, rect.Width) / 4;
180 // use the more visible one of the former two
182 PointF points[POINT_COUNT];
183 CutawayPoints (rect, max (minCutAway, suggestedCutAway), points);
185 // now, draw it
187 if (graphics.graphics)
189 if (brush)
190 graphics.graphics->FillPolygon (brush, points, POINT_COUNT);
191 if (pen)
192 graphics.graphics->DrawPolygon (pen, points, POINT_COUNT);
194 else if (graphics.pSVG)
196 graphics.pSVG->Polygon(points, POINT_COUNT, penColor, penWidth, fillColor);
200 inline BYTE LimitedScaleColor (BYTE c1, BYTE c2, float factor)
202 BYTE scaled = c2 + (BYTE)((c1-c2)*factor);
203 return c1 < c2
204 ? max (c1, scaled)
205 : min (c1, scaled);
208 Color LimitedScaleColor (const Color& c1, const Color& c2, float factor)
210 return Color ( LimitedScaleColor (c1.GetA(), c2.GetA(), factor)
211 , LimitedScaleColor (c1.GetR(), c2.GetR(), factor)
212 , LimitedScaleColor (c1.GetG(), c2.GetG(), factor)
213 , LimitedScaleColor (c1.GetB(), c2.GetB(), factor));
216 RectF CRevisionGraphWnd::TransformRectToScreen (const CRect& rect, const CSize& offset) const
218 PointF leftTop ( rect.left * m_fZoomFactor
219 , rect.top * m_fZoomFactor);
220 return RectF ( leftTop.X - offset.cx
221 , leftTop.Y - offset.cy
222 , rect.right * m_fZoomFactor - leftTop.X - 1
223 , rect.bottom * m_fZoomFactor - leftTop.Y);
227 RectF CRevisionGraphWnd::GetNodeRect(const ogdf::node& node, const CSize& offset) const
229 // get node and position
231 CRect rect;
232 rect.left = (int) (this->m_GraphAttr.x(node) - m_GraphAttr.width(node)/2);
233 rect.top = (int) (this->m_GraphAttr.y(node) - m_GraphAttr.height(node)/2);
234 rect.bottom = (int)( rect.top+ m_GraphAttr.height(node));
235 rect.right = (int)(rect.left + m_GraphAttr.width(node));
237 RectF noderect (TransformRectToScreen (rect, offset));
239 // show two separate lines for touching nodes,
240 // unless the scale is too small
242 if (noderect.Height > 15.0f)
243 noderect.Height -= 1.0f;
245 // done
247 return noderect;
250 void CRevisionGraphWnd::DrawSquare
251 ( GraphicsDevice& graphics
252 , const PointF& leftTop
253 , const Color& lightColor
254 , const Color& darkColor
255 , const Color& penColor)
257 float squareSize = MARKER_SIZE * m_fZoomFactor;
259 PointF leftBottom (leftTop.X, leftTop.Y + squareSize);
260 RectF square (leftTop, SizeF (squareSize, squareSize));
262 if (graphics.graphics)
264 LinearGradientBrush lgBrush (leftTop, leftBottom, lightColor, darkColor);
265 graphics.graphics->FillRectangle (&lgBrush, square);
266 if (squareSize > 4.0f)
268 Pen pen (penColor);
269 graphics.graphics->DrawRectangle (&pen, square);
272 else if (graphics.pSVG)
274 graphics.pSVG->GradientRectangle((int)square.X, (int)square.Y, (int)square.Width, (int)square.Height,
275 lightColor, darkColor, penColor);
279 void CRevisionGraphWnd::DrawMarker
280 ( GraphicsDevice& graphics
281 , const RectF& noderect
282 , MarkerPosition /*position*/
283 , int /*relPosition*/
284 , const Color& penColor
285 , int num)
287 REAL width = 4*this->m_fZoomFactor<1? 1: 4*this->m_fZoomFactor;
288 Pen pen(penColor,width);
289 DrawRoundedRect(graphics, penColor, (int)width, &pen, Color(0,0,0), nullptr, noderect);
290 if (num == 1)
292 // Roman number 1
293 REAL x = max(1, 10 * this->m_fZoomFactor);
294 REAL y1 = max(1, 25 * this->m_fZoomFactor);
295 REAL y2 = max(1, 5 * this->m_fZoomFactor);
296 if(graphics.graphics)
298 graphics.graphics->DrawLine(&pen, noderect.X + x, noderect.Y - y1, noderect.X + x, noderect.Y - y2);
299 if (m_SelectedEntry2)
301 CString base(L'(');
302 base.AppendFormat(IDS_PROC_DIFF_BASE);
303 base += L')';
304 SolidBrush blackbrush(penColor);
305 Gdiplus::Font font(CAppUtils::GetLogFontName(), (REAL)m_nFontSize, FontStyleRegular);
306 graphics.graphics->DrawString(base, base.GetLength(), &font, Gdiplus::PointF(noderect.X + x + width, noderect.Y - y1), &blackbrush);
310 else if (num == 2)
312 // Roman number 2
313 REAL x1 = max(1, 5 * this->m_fZoomFactor);
314 REAL x2 = max(1, 15 * this->m_fZoomFactor);
315 REAL y1 = max(1, 25 * this->m_fZoomFactor);
316 REAL y2 = max(1, 5 * this->m_fZoomFactor);
317 if(graphics.graphics)
319 graphics.graphics->DrawLine(&pen, noderect.X + x1, noderect.Y - y1, noderect.X + x1, noderect.Y - y2);
320 graphics.graphics->DrawLine(&pen, noderect.X + x2, noderect.Y - y1, noderect.X + x2, noderect.Y - y2);
325 PointF CRevisionGraphWnd::cutPoint(ogdf::node v, double lw, PointF ps, PointF pt)
327 double x = m_GraphAttr.x(v);
328 double y = m_GraphAttr.y(v);
329 double xmin = x - this->m_GraphAttr.width(v)/2 - lw/2;
330 double xmax = x + this->m_GraphAttr.width(v)/2 + lw/2;
331 double ymin = y - this->m_GraphAttr.height(v)/2 - lw/2;
332 double ymax = y + this->m_GraphAttr.height(v)/2 + lw/2;;
334 double dx = pt.X - ps.X;
335 double dy = pt.Y - ps.Y;
337 if(dy != 0) {
338 // below
339 if(pt.Y > ymax) {
340 double t = (ymax-ps.Y) / dy;
341 x = ps.X + t * dx;
343 if(xmin <= x && x <= xmax)
344 return PointF((REAL)x, (REAL)ymax);
346 // above
347 } else if(pt.Y < ymin) {
348 double t = (ymin-ps.Y) / dy;
349 x = ps.X + t * dx;
351 if(xmin <= x && x <= xmax)
352 return PointF((REAL)x, (REAL)ymin);
356 if(dx != 0) {
357 // right
358 if(pt.X > xmax) {
359 double t = (xmax-ps.X) / dx;
360 y = ps.Y + t * dy;
362 if(ymin <= y && y <= ymax)
363 return PointF((REAL)xmax, (REAL)y);
365 // left
366 } else if(pt.X < xmin) {
367 double t = (xmin-ps.X) / dx;
368 y = ps.Y + t * dy;
370 if(ymin <= y && y <= ymax)
371 return PointF((REAL)xmin, (REAL)y);
375 return pt;
378 void CRevisionGraphWnd::DrawConnections (GraphicsDevice& graphics, const CRect& /*logRect*/, const CSize& offset)
380 CArray<PointF> points;
381 CArray<CPoint> pts;
383 if(graphics.graphics)
384 graphics.graphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
386 float penwidth = 2*m_fZoomFactor<1? 1:2*m_fZoomFactor;
387 Gdiplus::Pen pen(GetColorFromSysColor(COLOR_WINDOWTEXT), penwidth);
389 // iterate over all visible lines
390 ogdf::edge e;
391 forall_edges(e, m_Graph)
393 // get connection and point position
394 const auto& dpl = this->m_GraphAttr.bends(e);
396 points.RemoveAll();
397 pts.RemoveAll();
399 PointF pt;
400 pt.X = (REAL)m_GraphAttr.x(e->source());
401 pt.Y = (REAL)m_GraphAttr.y(e->source());
403 points.Add(pt);
405 for (auto it = dpl.begin(); it.valid(); ++it)
407 pt.X = (REAL)(*it).m_x;
408 pt.Y = (REAL)(*it).m_y;
409 points.Add(pt);
412 pt.X = (REAL)m_GraphAttr.x(e->target());
413 pt.Y = (REAL)m_GraphAttr.y(e->target());
415 points.Add(pt);
417 points[0] = this->cutPoint(e->source(), 1, points[0], points[1]);
418 points[points.GetCount()-1] = this->cutPoint(e->target(), 1, points[points.GetCount()-1], points[points.GetCount()-2]);
419 // draw the connection
421 for (int i = 0; i < points.GetCount(); ++i)
423 //CPoint pt;
424 points[i].X = points[i].X * this->m_fZoomFactor - offset.cx;
425 points[i].Y = points[i].Y * this->m_fZoomFactor - offset.cy;
426 //pts.Add(pt);
429 if (graphics.graphics)
430 graphics.graphics->DrawLines(&pen, points.GetData(), (INT)points.GetCount());
431 else if (graphics.pSVG)
432 graphics.pSVG->Polyline(points.GetData(), (int)points.GetCount(), Color(0,0,0), (int)penwidth);
433 else if (graphics.pGraphviz)
435 CString hash1 = L'g' + m_logEntries[e->target()->index()].ToString().Left(g_Git.GetShortHASHLength());
436 CString hash2 = L'g' + m_logEntries[e->source()->index()].ToString().Left(g_Git.GetShortHASHLength());
437 graphics.pGraphviz->DrawEdge(hash1, hash2);
440 //draw arrow
441 double dx = points[1].X - points[0].X;
442 double dy = points[1].Y - points[0].Y;
444 double len = sqrt(dx*dx + dy*dy);
445 dx = m_ArrowSize * m_fZoomFactor *dx /len;
446 dy = m_ArrowSize * m_fZoomFactor *dy /len;
448 double p1_x, p1_y, p2_x, p2_y;
449 p1_x = dx * m_ArrowCos - dy * m_ArrowSin;
450 p1_y = dx * m_ArrowSin + dy * m_ArrowCos;
452 p2_x = dx * m_ArrowCos + dy * m_ArrowSin;
453 p2_y = -dx * m_ArrowSin + dy * m_ArrowCos;
455 //graphics.graphics->DrawLine(&pen, points[0].X,points[0].Y, points[0].X +p1_x,points[0].Y+p1_y);
456 //graphics.graphics->DrawLine(&pen, points[0].X,points[0].Y, points[0].X +p2_x,points[0].Y+p2_y);
457 GraphicsPath path;
459 PointF arrows[5];
460 arrows[0].X = points[0].X;
461 arrows[0].Y = points[0].Y;
463 arrows[1].X = points[0].X + (REAL)p1_x;
464 arrows[1].Y = points[0].Y + (REAL)p1_y;
466 arrows[2].X = points[0].X + (REAL)dx*3/5;
467 arrows[2].Y = points[0].Y + (REAL)dy*3/5;
469 arrows[3].X = points[0].X + (REAL)p2_x;
470 arrows[3].Y = points[0].Y + (REAL)p2_y;
472 arrows[4].X = points[0].X;
473 arrows[4].Y = points[0].Y;
475 path.AddLines(arrows, 5);
476 path.SetFillMode(FillModeAlternate);
477 if(graphics.graphics)
478 graphics.graphics->DrawPath(&pen, &path);
479 else if(graphics.pSVG)
480 graphics.pSVG->DrawPath(arrows, 5, Color(0,0,0), (int)penwidth, Color(0,0,0));
484 void CRevisionGraphWnd::DrawTexts (GraphicsDevice& graphics, const CRect& /*logRect*/, const CSize& offset)
486 //COLORREF standardTextColor = GetSysColor(COLOR_WINDOWTEXT);
487 if (m_nFontSize <= 0)
488 return;
490 // iterate over all visible nodes
492 if (graphics.pDC)
493 graphics.pDC->SetTextAlign (TA_CENTER | TA_TOP);
495 CString fontname = CAppUtils::GetLogFontName();
497 Gdiplus::Font font(fontname, (REAL)m_nFontSize, FontStyleRegular);
498 SolidBrush blackbrush((ARGB)Color::Black);
500 DWORD revGraphUseLocalForCur = CRegDWORD(L"Software\\TortoiseGit\\TortoiseProc\\Graph\\RevGraphUseLocalForCur");
502 ogdf::node v;
503 forall_nodes(v,m_Graph)
505 // get node and position
506 RectF noderect (GetNodeRect (v, offset));
508 // draw the revision text
509 CGitHash hash = this->m_logEntries[v->index()];
510 double hight = noderect.Height / (!m_HashMap[hash].empty() ? m_HashMap[hash].size() : 1);
512 if (m_HashMap.find(hash) == m_HashMap.end() || m_HashMap[hash].empty())
514 Color background;
515 background.SetFromCOLORREF (GetSysColor(COLOR_WINDOW));
516 Gdiplus::Pen pen(background,1.0F);
517 Color brightColor = LimitedScaleColor (background, RGB(255,0,0), 0.9f);
518 Gdiplus::SolidBrush brush(brightColor);
520 DrawRoundedRect(graphics, background,1, &pen, brightColor, &brush, noderect);
522 if(graphics.graphics)
524 graphics.graphics->DrawString(hash.ToString().Left(g_Git.GetShortHASHLength()),-1,
525 &font,
526 Gdiplus::PointF(noderect.X + this->GetLeftRightMargin()*this->m_fZoomFactor,noderect.Y+this->GetTopBottomMargin()*m_fZoomFactor),
527 &blackbrush);
529 if(graphics.pSVG)
531 graphics.pSVG->Text((int)(noderect.X + this->GetLeftRightMargin() * this->m_fZoomFactor),
532 (int)(noderect.Y + this->GetTopBottomMargin() * m_fZoomFactor + m_nFontSize),
533 CUnicodeUtils::GetUTF8(fontname), m_nFontSize, false, false, (ARGB)Color::Black,
534 CUnicodeUtils::GetUTF8(hash.ToString().Left(g_Git.GetShortHASHLength())));
536 if (graphics.pGraphviz)
538 CString shortHash = hash.ToString().Left(g_Git.GetShortHASHLength());
539 graphics.pGraphviz->DrawNode(L'g' + shortHash, shortHash, fontname, m_nFontSize, background, brightColor, (int)noderect.Height);
541 }else
543 if (graphics.pGraphviz)
545 CString id = L'g' + hash.ToString().Left(g_Git.GetShortHASHLength());
546 graphics.pGraphviz->BeginDrawTableNode(id, fontname, m_nFontSize, (int)noderect.Height);
549 for (size_t i = 0; i < m_HashMap[hash].size(); ++i)
551 CString shortname;
552 CString str = m_HashMap[hash][i];
553 RectF rect;
555 rect.X = (REAL)noderect.X;
556 rect.Y = (REAL)(noderect.Y + hight*i);
557 rect.Width = (REAL)noderect.Width;
558 rect.Height = (REAL)hight;
560 COLORREF colRef = m_Colors.GetColor(CColors::OtherRef);
562 CGit::REF_TYPE refType;
563 shortname = CGit::GetShortName(str, &refType);
564 switch (refType)
566 case CGit::REF_TYPE::LOCAL_BRANCH:
567 if (!revGraphUseLocalForCur && shortname == m_CurrentBranch)
568 colRef = m_Colors.GetColor(CColors::CurrentBranch);
569 else
570 colRef = m_Colors.GetColor(CColors::LocalBranch);
571 break;
572 case CGit::REF_TYPE::REMOTE_BRANCH:
573 colRef = m_Colors.GetColor(CColors::RemoteBranch);
574 break;
575 case CGit::REF_TYPE::ANNOTATED_TAG:
576 case CGit::REF_TYPE::TAG:
577 colRef = m_Colors.GetColor(CColors::Tag);
578 break;
579 case CGit::REF_TYPE::STASH:
580 colRef = m_Colors.GetColor(CColors::Stash);
581 break;
582 case CGit::REF_TYPE::BISECT_GOOD:
583 colRef = m_Colors.GetColor(CColors::BisectGood);
584 break;
585 case CGit::REF_TYPE::BISECT_BAD:
586 colRef = m_Colors.GetColor(CColors::BisectBad);
587 break;
588 case CGit::REF_TYPE::BISECT_SKIP:
589 colRef = m_Colors.GetColor(CColors::BisectSkip);
590 break;
591 case CGit::REF_TYPE::NOTES:
592 colRef = m_Colors.GetColor(CColors::NoteNode);
593 break;
596 Gdiplus::Color color(GetRValue(colRef), GetGValue(colRef), GetBValue(colRef));
597 Gdiplus::Pen pen(color);
598 Gdiplus::SolidBrush brush(color);
600 int mask =0;
601 mask |= (i==0)? ROUND_UP:0;
602 mask |= (i== m_HashMap[hash].size()-1)? ROUND_DOWN:0;
603 this->DrawRoundedRect(graphics, color,1,&pen, color,&brush, rect,mask);
605 if (graphics.graphics)
607 //graphics.graphics->FillRectangle(&SolidBrush(Gdiplus::Color(GetRValue(colRef), GetGValue(colRef), GetBValue(colRef))),
608 // rect);
610 graphics.graphics->DrawString(shortname, shortname.GetLength(),
611 &font,
612 Gdiplus::PointF((REAL)(noderect.X + this->GetLeftRightMargin()*m_fZoomFactor),
613 (REAL)(noderect.Y + this->GetTopBottomMargin()*m_fZoomFactor+ hight*i)),
614 &blackbrush);
616 //graphics.graphics->DrawString(shortname.GetBuffer(), shortname.GetLength(), ::new Gdiplus::Font(graphics.pDC->m_hDC), PointF(noderect.X, noderect.Y + hight * i), nullptr, nullptr);
619 else if (graphics.pSVG)
620 graphics.pSVG->Text((int)(noderect.X + this->GetLeftRightMargin() * m_fZoomFactor),
621 (int)(noderect.Y + this->GetTopBottomMargin() * m_fZoomFactor + hight * i + m_nFontSize),
622 CUnicodeUtils::GetUTF8(fontname), m_nFontSize,
623 false, false, (ARGB)Color::Black, CUnicodeUtils::GetUTF8(shortname));
624 else if (graphics.pGraphviz)
625 graphics.pGraphviz->DrawTableNode(shortname, color);
628 if (graphics.pGraphviz)
629 graphics.pGraphviz->EndDrawTableNode();
631 if ((m_SelectedEntry1 == v))
632 DrawMarker(graphics, noderect, mpLeft, 0, GetColorFromSysColor(COLOR_HIGHLIGHT), 1);
634 if ((m_SelectedEntry2 == v))
635 DrawMarker(graphics, noderect, mpLeft, 0, Color(136,0, 21), 2);
639 void CRevisionGraphWnd::DrawGraph(GraphicsDevice& graphics, const CRect& rect, int nVScrollPos, int nHScrollPos, bool bDirectDraw)
641 CMemDC* memDC = nullptr;
642 if (graphics.pDC)
644 if (!bDirectDraw)
646 memDC = new CMemDC (*graphics.pDC, rect);
647 graphics.pDC = &memDC->GetDC();
650 graphics.pDC->FillSolidRect(rect, GetSysColor(COLOR_WINDOW));
651 graphics.pDC->SetBkMode(TRANSPARENT);
654 // transform visible
656 CSize offset (nHScrollPos, nVScrollPos);
657 CRect logRect ( (int)(offset.cx / m_fZoomFactor)-1
658 , (int)(offset.cy / m_fZoomFactor)-1
659 , (int)((rect.Width() + offset.cx) / m_fZoomFactor) + 1
660 , (int)((rect.Height() + offset.cy) / m_fZoomFactor) + 1);
662 // draw the different components
664 if (graphics.pDC)
666 Graphics* gcs = Graphics::FromHDC(*graphics.pDC);
667 graphics.graphics = gcs;
668 gcs->SetPageUnit (UnitPixel);
669 gcs->SetInterpolationMode (InterpolationModeHighQualityBicubic);
670 gcs->SetSmoothingMode(SmoothingModeAntiAlias);
671 gcs->SetClip(RectF(Gdiplus::REAL(rect.left), Gdiplus::REAL(rect.top), Gdiplus::REAL(rect.Width()), Gdiplus::REAL(rect.Height())));
674 Bitmap glyphs (AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_REVGRAPHGLYPHS));
676 DrawTexts (graphics, logRect, offset);
677 DrawConnections (graphics, logRect, offset);
679 // draw preview
680 if ((!bDirectDraw)&&(m_Preview.GetSafeHandle())&&(m_bShowOverview)&&(graphics.pDC))
682 // draw the overview image rectangle in the top right corner
683 CMyMemDC memDC2(graphics.pDC, true);
684 memDC2.SetWindowOrg(0, 0);
685 HBITMAP oldhbm = (HBITMAP)memDC2.SelectObject(&m_Preview);
686 graphics.pDC->BitBlt(rect.Width()-m_previewWidth, rect.Height() - m_previewHeight, m_previewWidth, m_previewHeight,
687 &memDC2, 0, 0, SRCCOPY);
688 memDC2.SelectObject(oldhbm);
689 // draw the border for the overview rectangle
690 m_OverviewRect.left = rect.Width()-m_previewWidth;
691 m_OverviewRect.top = rect.Height()- m_previewHeight;
692 m_OverviewRect.right = rect.Width();
693 m_OverviewRect.bottom = rect.Height();
694 graphics.pDC->DrawEdge(&m_OverviewRect, EDGE_BUMP, BF_RECT);
695 // now draw a rectangle where the current view is located in the overview
697 LONG width = (long)(rect.Width() * m_previewZoom / m_fZoomFactor);
698 LONG height = (long)(rect.Height() * m_previewZoom / m_fZoomFactor);
699 LONG xpos = (long)(nHScrollPos * m_previewZoom / m_fZoomFactor);
700 LONG ypos = (long)(nVScrollPos * m_previewZoom / m_fZoomFactor);
701 RECT tempRect;
702 tempRect.left = rect.Width()-m_previewWidth+xpos;
703 tempRect.top = rect.Height() - m_previewHeight + ypos;
704 tempRect.right = tempRect.left + width;
705 tempRect.bottom = tempRect.top + height;
706 // make sure the position rect is not bigger than the preview window itself
707 ::IntersectRect(&m_OverviewPosRect, &m_OverviewRect, &tempRect);
709 RectF rect2 ( (float)m_OverviewPosRect.left, (float)m_OverviewPosRect.top
710 , (float)m_OverviewPosRect.Width(), (float)m_OverviewPosRect.Height());
711 if (graphics.graphics)
713 SolidBrush brush (Color (64, 0, 0, 0));
714 graphics.graphics->FillRectangle (&brush, rect2);
715 graphics.pDC->DrawEdge(&m_OverviewPosRect, EDGE_BUMP, BF_RECT);
719 // flush changes to screen
721 delete graphics.graphics;
722 delete memDC;
725 void CRevisionGraphWnd::SetNodeRect(GraphicsDevice& graphics, ogdf::node *pnode, CGitHash rev, int mode )
727 //multi - line mode. One RefName is one new line
728 CString fontname = CAppUtils::GetLogFontName();
729 if(mode == 0)
731 if(this->m_HashMap.find(rev) == m_HashMap.end())
733 CString shorthash = rev.ToString().Left(g_Git.GetShortHASHLength());
734 RectF rect;
735 if(graphics.graphics)
737 //GetTextExtentPoint32(graphics.pDC->m_hDC, shorthash.GetBuffer(), shorthash.GetLength(), &size);
738 Gdiplus::Font font(fontname, (REAL)m_nFontSize, FontStyleRegular);
739 graphics.graphics->MeasureString(shorthash, shorthash.GetLength(),
740 &font,
741 Gdiplus::PointF(0,0), &rect);
743 m_GraphAttr.width(*pnode) = this->GetLeftRightMargin()*2 + rect.Width;
744 m_GraphAttr.height(*pnode) = this->GetTopBottomMargin()*2 + rect.Height;
746 else
748 double xmax=0;
749 double ymax=0;
750 int lines =0;
751 for (size_t i = 0; i < m_HashMap[rev].size(); ++i)
753 RectF rect;
754 CString shortref = m_HashMap[rev][i];
755 shortref = CGit::GetShortName(shortref, nullptr);
756 if(graphics.pDC)
758 Gdiplus::Font font(fontname, (REAL)m_nFontSize, FontStyleRegular);
759 graphics.graphics->MeasureString(shortref, shortref.GetLength(),
760 &font,
761 Gdiplus::PointF(0,0), &rect);
762 if(rect.Width > xmax)
763 xmax = rect.Width;
764 if(rect.Height > ymax)
765 ymax = rect.Height;
767 ++lines;
769 m_GraphAttr.width(*pnode) = this->GetLeftRightMargin()*2 + xmax;
770 m_GraphAttr.height(*pnode) = (this->GetTopBottomMargin()*2 + ymax) * lines;