Remove unused variables
[TortoiseGit.git] / src / TortoiseProc / RevisionGraph / RevisionGraphDlgDraw.cpp
blob99f7e53740a22181e14316f375562b7e854ca47a
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2011, 2015 - TortoiseSVN
4 // Copyright (C) 2012-2013, 2015-2016 - 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"
37 #ifdef _DEBUG
38 #define new DEBUG_NEW
39 #undef THIS_FILE
40 static char THIS_FILE[] = __FILE__;
41 #endif
43 using namespace Gdiplus;
44 using namespace ogdf;
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 CDC * pDC = GetDC();
70 m_lfBaseFont.lfHeight = -MulDiv(m_nFontSize, GetDeviceCaps(pDC->m_hDC, LOGPIXELSY), 72);
71 ReleaseDC(pDC);
72 // use the empty font name, so GDI takes the first font which matches
73 // the specs. Maybe this will help render chinese/japanese chars correctly.
74 wcsncpy_s(m_lfBaseFont.lfFaceName, L"MS Shell Dlg 2", _countof(m_lfBaseFont.lfFaceName) - 1);
75 if (!m_apFonts[nIndex]->CreateFontIndirect(&m_lfBaseFont))
77 delete m_apFonts[nIndex];
78 m_apFonts[nIndex] = nullptr;
79 return CWnd::GetFont();
82 return m_apFonts[nIndex];
85 BOOL CRevisionGraphWnd::OnEraseBkgnd(CDC* /*pDC*/)
87 return TRUE;
90 void CRevisionGraphWnd::OnPaint()
92 CPaintDC dc(this); // device context for painting
93 CRect rect = GetClientRect();
95 if (IsUpdateJobRunning())
97 CString fetch = CString(MAKEINTRESOURCE(IDS_PROC_LOADING));
98 dc.FillSolidRect(rect, ::GetSysColor(COLOR_APPWORKSPACE));
99 dc.ExtTextOut(20, 20, ETO_CLIPPED, nullptr, fetch, nullptr);
100 CWnd::OnPaint();
101 return;
103 }else if (this->m_Graph.empty())
105 CString sNoGraphText;
106 sNoGraphText.LoadString(IDS_REVGRAPH_ERR_NOGRAPH);
107 dc.FillSolidRect(rect, RGB(255,255,255));
108 dc.ExtTextOut(20, 20, ETO_CLIPPED, nullptr, sNoGraphText, nullptr);
109 return;
112 GraphicsDevice dev;
113 dev.pDC = &dc;
114 DrawGraph(dev, rect, GetScrollPos(SB_VERT), GetScrollPos(SB_HORZ), false);
117 void CRevisionGraphWnd::ClearVisibleGlyphs (const CRect& /*rect*/)
119 #if 0
120 float glyphSize = GLYPH_SIZE * m_fZoomFactor;
122 CSyncPointer<CRevisionGraphState::TVisibleGlyphs>
123 visibleGlyphs (m_state.GetVisibleGlyphs());
125 for (size_t i = visibleGlyphs->size(), count = i; i > 0; --i)
127 const PointF& leftTop = (*visibleGlyphs)[i-1].leftTop;
128 CRect glyphRect ( static_cast<int>(leftTop.X)
129 , static_cast<int>(leftTop.Y)
130 , static_cast<int>(leftTop.X + glyphSize)
131 , static_cast<int>(leftTop.Y + glyphSize));
133 if (CRect().IntersectRect (glyphRect, rect))
135 (*visibleGlyphs)[i-1] = (*visibleGlyphs)[--count];
136 visibleGlyphs->pop_back();
139 #endif
142 void CRevisionGraphWnd::CutawayPoints (const RectF& rect, float cutLen, TCutRectangle& result)
144 result[0] = PointF (rect.X, rect.Y + cutLen);
145 result[1] = PointF (rect.X + cutLen, rect.Y);
146 result[2] = PointF (rect.GetRight() - cutLen, rect.Y);
147 result[3] = PointF (rect.GetRight(), rect.Y + cutLen);
148 result[4] = PointF (rect.GetRight(), rect.GetBottom() - cutLen);
149 result[5] = PointF (rect.GetRight() - cutLen, rect.GetBottom());
150 result[6] = PointF (rect.X + cutLen, rect.GetBottom());
151 result[7] = PointF (rect.X, rect.GetBottom() - cutLen);
154 void CRevisionGraphWnd::DrawRoundedRect (GraphicsDevice& graphics, const Color& penColor, int penWidth, const Pen* pen, const Color& fillColor, const Brush* brush, const RectF& rect, int mask)
156 enum {POINT_COUNT = 8};
158 float radius = CORNER_SIZE * m_fZoomFactor;
159 PointF points[POINT_COUNT];
160 CutawayPoints (rect, radius, points);
162 if (graphics.graphics)
164 GraphicsPath path;
166 if(mask & ROUND_UP)
168 path.AddArc (points[0].X, points[1].Y, radius, radius, 180, 90);
169 path.AddArc (points[2].X, points[2].Y, radius, radius, 270, 90);
170 }else
171 path.AddLine(points[0].X, points[1].Y, points[3].X, points[2].Y);
173 if(mask & ROUND_DOWN)
175 path.AddArc (points[5].X, points[4].Y, radius, radius, 0, 90);
176 path.AddArc (points[7].X, points[7].Y, radius, radius, 90, 90);
177 }else
179 path.AddLine(points[3].X, points[3].Y, points[4].X, points[5].Y);
180 path.AddLine(points[4].X, points[5].Y, points[7].X, points[6].Y);
183 points[0].Y -= radius / 2;
184 path.AddLine (points[7], points[0]);
186 if (brush)
187 graphics.graphics->FillPath (brush, &path);
188 if (pen)
189 graphics.graphics->DrawPath (pen, &path);
191 else if (graphics.pSVG)
192 graphics.pSVG->RoundedRectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height, penColor, penWidth, fillColor, (int)radius, mask);
195 void CRevisionGraphWnd::DrawOctangle (GraphicsDevice& graphics, const Color& penColor, int penWidth, const Pen* pen, const Color& fillColor, const Brush* brush, const RectF& rect)
197 enum {POINT_COUNT = 8};
199 // show left & right edges of low boxes as "<===>"
201 float minCutAway = min (CORNER_SIZE * m_fZoomFactor, rect.Height / 2);
203 // larger boxes: remove 25% of the shorter side
205 float suggestedCutAway = min (rect.Height, rect.Width) / 4;
207 // use the more visible one of the former two
209 PointF points[POINT_COUNT];
210 CutawayPoints (rect, max (minCutAway, suggestedCutAway), points);
212 // now, draw it
214 if (graphics.graphics)
216 if (brush)
217 graphics.graphics->FillPolygon (brush, points, POINT_COUNT);
218 if (pen)
219 graphics.graphics->DrawPolygon (pen, points, POINT_COUNT);
221 else if (graphics.pSVG)
223 graphics.pSVG->Polygon(points, POINT_COUNT, penColor, penWidth, fillColor);
229 void CRevisionGraphWnd::DrawShape (GraphicsDevice& graphics, const Color& penColor, int penWidth, const Pen* pen, const Color& fillColor, const Brush* brush, const RectF& rect, NodeShape shape)
231 switch( shape )
233 case TSVNRectangle:
234 if (graphics.graphics)
236 if (brush)
237 graphics.graphics->FillRectangle (brush, rect);
238 if (pen)
239 graphics.graphics->DrawRectangle (pen, rect);
241 else if (graphics.pSVG)
243 graphics.pSVG->RoundedRectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height, penColor, penWidth, fillColor);
245 break;
246 case TSVNRoundRect:
247 DrawRoundedRect (graphics, penColor, penWidth, pen, fillColor, brush, rect);
248 break;
249 case TSVNOctangle:
250 DrawOctangle (graphics, penColor, penWidth, pen, fillColor, brush, rect);
251 break;
252 case TSVNEllipse:
253 if (graphics.graphics)
255 if (brush)
256 graphics.graphics->FillEllipse (brush, rect);
257 if (pen)
258 graphics.graphics->DrawEllipse(pen, rect);
260 else if (graphics.pSVG)
261 graphics.pSVG->Ellipse((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height, penColor, penWidth, fillColor);
262 break;
263 default:
264 ASSERT(FALSE); //unknown type
265 return;
270 inline BYTE LimitedScaleColor (BYTE c1, BYTE c2, float factor)
272 BYTE scaled = c2 + (BYTE)((c1-c2)*factor);
273 return c1 < c2
274 ? max (c1, scaled)
275 : min (c1, scaled);
278 Color LimitedScaleColor (const Color& c1, const Color& c2, float factor)
280 return Color ( LimitedScaleColor (c1.GetA(), c2.GetA(), factor)
281 , LimitedScaleColor (c1.GetR(), c2.GetR(), factor)
282 , LimitedScaleColor (c1.GetG(), c2.GetG(), factor)
283 , LimitedScaleColor (c1.GetB(), c2.GetB(), factor));
286 inline BYTE Darken (BYTE c)
288 return c < 0xc0
289 ? (c / 3) * 2
290 : BYTE(int(2*c) - 0x100);
293 Color Darken (const Color& c)
295 return Color ( 0xff
296 , Darken (c.GetR())
297 , Darken (c.GetG())
298 , Darken (c.GetB()));
301 BYTE MaxComponentDiff (const Color& c1, const Color& c2)
303 int rDiff = abs ((int)c1.GetR() - (int)c2.GetR());
304 int gDiff = abs ((int)c1.GetG() - (int)c2.GetG());
305 int bDiff = abs ((int)c1.GetB() - (int)c2.GetB());
307 return (BYTE) max (max (rDiff, gDiff), bDiff);
310 #if 0
311 void CRevisionGraphWnd::DrawShadow (GraphicsDevice& graphics, const RectF& rect,
312 Color shadowColor, NodeShape shape)
314 // draw the shadow
316 RectF shadow = rect;
317 shadow.Offset (2, 2);
319 Pen pen (shadowColor);
320 SolidBrush brush (shadowColor);
322 DrawShape (graphics, shadowColor, 1, &pen, shadowColor, &brush, shadow, shape);
324 #endif
326 RectF CRevisionGraphWnd::TransformRectToScreen (const CRect& rect, const CSize& offset) const
328 PointF leftTop ( rect.left * m_fZoomFactor
329 , rect.top * m_fZoomFactor);
330 return RectF ( leftTop.X - offset.cx
331 , leftTop.Y - offset.cy
332 , rect.right * m_fZoomFactor - leftTop.X - 1
333 , rect.bottom * m_fZoomFactor - leftTop.Y);
337 RectF CRevisionGraphWnd::GetNodeRect (const node& node, const CSize& offset) const
339 // get node and position
341 CRect rect;
342 rect.left = (int) (this->m_GraphAttr.x(node) - m_GraphAttr.width(node)/2);
343 rect.top = (int) (this->m_GraphAttr.y(node) - m_GraphAttr.height(node)/2);
344 rect.bottom = (int)( rect.top+ m_GraphAttr.height(node));
345 rect.right = (int)(rect.left + m_GraphAttr.width(node));
347 RectF noderect (TransformRectToScreen (rect, offset));
349 // show two separate lines for touching nodes,
350 // unless the scale is too small
352 if (noderect.Height > 15.0f)
353 noderect.Height -= 1.0f;
355 // done
357 return noderect;
361 #if 0
362 RectF CRev
363 isionGraphWnd::GetBranchCover
364 ( const ILayoutNodeList* nodeList
365 , index_t nodeIndex
366 , bool upward
367 , const CSize& offset)
369 // construct a rect that covers the respective branch
371 CRect cover (0, 0, 0, 0);
372 while (nodeIndex != NO_INDEX)
374 ILayoutNodeList::SNode node = nodeList->GetNode (nodeIndex);
375 cover |= node.rect;
377 const CVisibleGraphNode* nextNode = upward
378 ? node.node->GetPrevious()
379 : node.node->GetNext();
381 nodeIndex = !nextNode ? NO_INDEX : nextNode->GetIndex();
384 // expand it just a little to make it look nicer
386 cover.InflateRect (10, 2, 10, 2);
388 // and now, transfrom it
390 return TransformRectToScreen (cover, offset);
392 #endif
394 #if 0
395 void CRevisionGraphWnd::DrawShadows (GraphicsDevice& graphics, const CRect& logRect, const CSize& offset)
397 // shadow color to use
399 Color background;
400 background.SetFromCOLORREF (GetSysColor(COLOR_WINDOW));
401 Color textColor;
402 textColor.SetFromCOLORREF (GetSysColor(COLOR_WINDOWTEXT));
404 Color shadowColor = LimitedScaleColor (background, ARGB (Color::Black), 0.5f);
406 // iterate over all visible nodes
408 CSyncPointer<const ILayoutNodeList> nodes (m_state.GetNodes());
409 for ( index_t index = nodes->GetFirstVisible (logRect)
410 ; index != NO_INDEX
411 ; index = nodes->GetNextVisible (index, logRect))
413 // get node and position
415 ILayoutNodeList::SNode node = nodes->GetNode (index);
416 RectF noderect (GetNodeRect (node, offset));
418 // actual drawing
420 switch (node.style)
422 case ILayoutNodeList::SNode::STYLE_DELETED:
423 case ILayoutNodeList::SNode::STYLE_RENAMED:
424 DrawShadow (graphics, noderect, shadowColor, TSVNOctangle);
425 break;
426 case ILayoutNodeList::SNode::STYLE_ADDED:
427 DrawShadow(graphics, noderect, shadowColor, TSVNRoundRect);
428 break;
429 case ILayoutNodeList::SNode::STYLE_LAST:
430 DrawShadow(graphics, noderect, shadowColor, TSVNEllipse);
431 break;
432 default:
433 DrawShadow(graphics, noderect, shadowColor, TSVNRectangle);
434 break;
438 #endif
441 void CRevisionGraphWnd::DrawSquare
442 ( GraphicsDevice& graphics
443 , const PointF& leftTop
444 , const Color& lightColor
445 , const Color& darkColor
446 , const Color& penColor)
448 float squareSize = MARKER_SIZE * m_fZoomFactor;
450 PointF leftBottom (leftTop.X, leftTop.Y + squareSize);
451 RectF square (leftTop, SizeF (squareSize, squareSize));
453 if (graphics.graphics)
455 LinearGradientBrush lgBrush (leftTop, leftBottom, lightColor, darkColor);
456 graphics.graphics->FillRectangle (&lgBrush, square);
457 if (squareSize > 4.0f)
459 Pen pen (penColor);
460 graphics.graphics->DrawRectangle (&pen, square);
463 else if (graphics.pSVG)
465 graphics.pSVG->GradientRectangle((int)square.X, (int)square.Y, (int)square.Width, (int)square.Height,
466 lightColor, darkColor, penColor);
470 #if 0
471 void CRevisionGraphWnd::DrawGlyph
472 ( GraphicsDevice& graphics
473 , Image* glyphs
474 , const PointF& leftTop
475 , GlyphType glyph
476 , GlyphPosition position)
478 // special case
480 if (glyph == NoGlyph)
481 return;
483 // bitmap source area
485 REAL x = ((REAL)position + (REAL)glyph) * GLYPH_BITMAP_SIZE;
487 // screen target area
489 float glyphSize = GLYPH_SIZE * m_fZoomFactor;
490 RectF target (leftTop, SizeF (glyphSize, glyphSize));
492 // scaled copy
494 if (graphics.graphics)
496 graphics.graphics->DrawImage ( glyphs
497 , target
498 , x, 0.0f, GLYPH_BITMAP_SIZE, GLYPH_BITMAP_SIZE
499 , UnitPixel, nullptr, nullptr, nullptr);
501 else if (graphics.pSVG)
503 // instead of inserting a bitmap, draw a
504 // round rectangle instead.
505 // Embedding images would blow up the resulting
506 // svg file a lot, and the round rectangle
507 // is enough IMHO.
508 // Note:
509 // images could be embedded like this:
510 // <image y="100" x="100" id="imgId1234" xlink:href="data:image/png;base64,...base64endodeddata..." height="16" width="16" />
512 graphics.pSVG->RoundedRectangle((int)target.X, (int)target.Y, (int)target.Width, (int)target.Height,
513 Color(0,0,0), 2, Color(255,255,255), (int)(target.Width/3.0));
516 #endif
518 #if 0
519 void CRevisionGraphWnd::DrawGlyphs
520 ( GraphicsDevice& graphics
521 , Image* glyphs
522 , const CVisibleGraphNode* node
523 , const PointF& center
524 , GlyphType glyph1
525 , GlyphType glyph2
526 , GlyphPosition position
527 , DWORD state1
528 , DWORD state2
529 , bool showAll)
531 // don't show collapse and cut glyths by default
533 if (!showAll && ((glyph1 == CollapseGlyph) || (glyph1 == SplitGlyph)))
534 glyph1 = NoGlyph;
535 if (!showAll && ((glyph2 == CollapseGlyph) || (glyph2 == SplitGlyph)))
536 glyph2 = NoGlyph;
538 // glyth2 shall be set only if 2 glyphs are in use
540 if (glyph1 == NoGlyph)
542 std::swap (glyph1, glyph2);
543 std::swap (state1, state2);
546 // anything to do?
548 if (glyph1 == NoGlyph)
549 return;
551 // 1 or 2 glyphs?
553 CSyncPointer<CRevisionGraphState::TVisibleGlyphs>
554 visibleGlyphs (m_state.GetVisibleGlyphs());
556 float squareSize = GLYPH_SIZE * m_fZoomFactor;
557 if (glyph2 == NoGlyph)
559 PointF leftTop (center.X - 0.5f * squareSize, center.Y - 0.5f * squareSize);
560 DrawGlyph (graphics, glyphs, leftTop, glyph1, position);
561 visibleGlyphs->push_back
562 (CRevisionGraphState::SVisibleGlyph (state1, leftTop, node));
564 else
566 PointF leftTop1 (center.X - squareSize, center.Y - 0.5f * squareSize);
567 DrawGlyph (graphics, glyphs, leftTop1, glyph1, position);
568 visibleGlyphs->push_back
569 (CRevisionGraphState::SVisibleGlyph (state1, leftTop1, node));
571 PointF leftTop2 (center.X, center.Y - 0.5f * squareSize);
572 DrawGlyph (graphics, glyphs, leftTop2, glyph2, position);
573 visibleGlyphs->push_back
574 (CRevisionGraphState::SVisibleGlyph (state2, leftTop2, node));
577 #endif
579 #if 0
580 void CRevisionGraphWnd::DrawGlyphs
581 ( GraphicsDevice& graphics
582 , Image* glyphs
583 , const CVisibleGraphNode* node
584 , const RectF& nodeRect
585 , DWORD state
586 , DWORD allowed
587 , bool upsideDown)
589 // shortcut
591 if ((state == 0) && (allowed == 0))
592 return;
594 // draw all glyphs
596 PointF topCenter (0.5f * nodeRect.GetLeft() + 0.5f * nodeRect.GetRight(), nodeRect.GetTop());
597 PointF rightCenter (nodeRect.GetRight(), 0.5f * nodeRect.GetTop() + 0.5f * nodeRect.GetBottom());
598 PointF bottomCenter (0.5f * nodeRect.GetLeft() + 0.5f * nodeRect.GetRight(), nodeRect.GetBottom());
600 DrawGlyphs ( graphics
601 , glyphs
602 , node
603 , upsideDown ? bottomCenter : topCenter
604 , (state & CGraphNodeStates::COLLAPSED_ABOVE) ? ExpandGlyph : CollapseGlyph
605 , (state & CGraphNodeStates::SPLIT_ABOVE) ? JoinGlyph : SplitGlyph
606 , upsideDown ? Below : Above
607 , CGraphNodeStates::COLLAPSED_ABOVE
608 , CGraphNodeStates::SPLIT_ABOVE
609 , (allowed & CGraphNodeStates::COLLAPSED_ABOVE) != 0);
611 DrawGlyphs ( graphics
612 , glyphs
613 , node
614 , rightCenter
615 , (state & CGraphNodeStates::COLLAPSED_RIGHT) ? ExpandGlyph : CollapseGlyph
616 , (state & CGraphNodeStates::SPLIT_RIGHT) ? JoinGlyph : SplitGlyph
617 , Right
618 , CGraphNodeStates::COLLAPSED_RIGHT
619 , CGraphNodeStates::SPLIT_RIGHT
620 , (allowed & CGraphNodeStates::COLLAPSED_RIGHT) != 0);
622 DrawGlyphs ( graphics
623 , glyphs
624 , node
625 , upsideDown ? topCenter : bottomCenter
626 , (state & CGraphNodeStates::COLLAPSED_BELOW) ? ExpandGlyph : CollapseGlyph
627 , (state & CGraphNodeStates::SPLIT_BELOW) ? JoinGlyph : SplitGlyph
628 , upsideDown ? Above : Below
629 , CGraphNodeStates::COLLAPSED_BELOW
630 , CGraphNodeStates::SPLIT_BELOW
631 , (allowed & CGraphNodeStates::COLLAPSED_BELOW) != 0);
633 #endif
635 #if 0
636 void CRevisionGraphWnd::IndicateGlyphDirection
637 ( GraphicsDevice& graphics
638 , const ILayoutNodeList* nodeList
639 , const ILayoutNodeList::SNode& node
640 , const RectF& nodeRect
641 , DWORD glyphs
642 , bool upsideDown
643 , const CSize& offset)
645 // shortcut
647 if (glyphs == 0)
648 return;
650 // where to place the indication?
652 bool indicateAbove = (glyphs & CGraphNodeStates::COLLAPSED_ABOVE) != 0;
653 bool indicateRight = (glyphs & CGraphNodeStates::COLLAPSED_RIGHT) != 0;
654 bool indicateBelow = (glyphs & CGraphNodeStates::COLLAPSED_BELOW) != 0;
656 // fill indication area a semi-transparent blend of red
657 // and the background color
659 Color color;
660 color.SetFromCOLORREF (GetSysColor(COLOR_WINDOW));
661 color.SetValue ((color.GetValue() & 0x807f7f7f) + 0x800000);
663 SolidBrush brush (color);
665 // draw the indication (only one condition should match)
667 RectF glyphCenter = (indicateAbove ^ upsideDown)
668 ? RectF (nodeRect.X, nodeRect.Y - 1.0f, 0.0f, 0.0f)
669 : RectF (nodeRect.X, nodeRect.GetBottom() - 1.0f, 0.0f, 0.0f);
671 if (indicateAbove)
673 const CVisibleGraphNode* firstAffected = node.node->GetSource();
675 assert (firstAffected);
676 RectF branchCover
677 = GetBranchCover (nodeList, firstAffected->GetIndex(), true, offset);
678 RectF::Union (branchCover, branchCover, glyphCenter);
680 if (graphics.graphics)
681 graphics.graphics->FillRectangle (&brush, branchCover);
682 else if (graphics.pSVG)
683 graphics.pSVG->RoundedRectangle((int)branchCover.X, (int)branchCover.Y, (int)branchCover.Width, (int)branchCover.Height,
684 color, 1, color);
687 if (indicateRight)
689 for ( const CVisibleGraphNode::CCopyTarget* branch
690 = node.node->GetFirstCopyTarget()
691 ; branch
692 ; branch = branch->next())
694 RectF branchCover
695 = GetBranchCover (nodeList, branch->value()->GetIndex(), false, offset);
696 if (graphics.graphics)
697 graphics.graphics->FillRectangle (&brush, branchCover);
698 else if (graphics.pSVG)
699 graphics.pSVG->RoundedRectangle((int)branchCover.X, (int)branchCover.Y, (int)branchCover.Width, (int)branchCover.Height,
700 color, 1, color);
704 if (indicateBelow)
706 const CVisibleGraphNode* firstAffected
707 = node.node->GetNext();
709 RectF branchCover
710 = GetBranchCover (nodeList, firstAffected->GetIndex(), false, offset);
711 RectF::Union (branchCover, branchCover, glyphCenter);
713 if (graphics.graphics)
714 graphics.graphics->FillRectangle (&brush, branchCover);
715 else if (graphics.pSVG)
716 graphics.pSVG->RoundedRectangle((int)branchCover.X, (int)branchCover.Y, (int)branchCover.Width, (int)branchCover.Height,
717 color, 1, color);
721 #endif
723 void CRevisionGraphWnd::DrawMarker
724 ( GraphicsDevice& graphics
725 , const RectF& noderect
726 , MarkerPosition /*position*/
727 , int /*relPosition*/
728 , const Color& penColor
729 , int num)
731 REAL width = 4*this->m_fZoomFactor<1? 1: 4*this->m_fZoomFactor;
732 Pen pen(penColor,width);
733 DrawRoundedRect(graphics, penColor, (int)width, &pen, Color(0,0,0), nullptr, noderect);
734 if (num == 1)
736 // Roman number 1
737 REAL x = max(1, 10 * this->m_fZoomFactor);
738 REAL y1 = max(1, 25 * this->m_fZoomFactor);
739 REAL y2 = max(1, 5 * this->m_fZoomFactor);
740 if(graphics.graphics)
742 graphics.graphics->DrawLine(&pen, noderect.X + x, noderect.Y - y1, noderect.X + x, noderect.Y - y2);
743 if (m_SelectedEntry2)
745 CString base(L'(');
746 base.AppendFormat(IDS_PROC_DIFF_BASE);
747 base += L')';
748 SolidBrush blackbrush(penColor);
749 Gdiplus::Font font(CAppUtils::GetLogFontName(), (REAL)m_nFontSize, FontStyleRegular);
750 graphics.graphics->DrawString(base, base.GetLength(), &font, Gdiplus::PointF(noderect.X + x + width, noderect.Y - y1), &blackbrush);
754 else if (num == 2)
756 // Roman number 2
757 REAL x1 = max(1, 5 * this->m_fZoomFactor);
758 REAL x2 = max(1, 15 * this->m_fZoomFactor);
759 REAL y1 = max(1, 25 * this->m_fZoomFactor);
760 REAL y2 = max(1, 5 * this->m_fZoomFactor);
761 if(graphics.graphics)
763 graphics.graphics->DrawLine(&pen, noderect.X + x1, noderect.Y - y1, noderect.X + x1, noderect.Y - y2);
764 graphics.graphics->DrawLine(&pen, noderect.X + x2, noderect.Y - y1, noderect.X + x2, noderect.Y - y2);
769 #if 0
770 void CRevisionGraphWnd::DrawStripes (GraphicsDevice& graphics, const CSize& offset)
772 // we need to fill this visible area of the the screen
773 // (even if there is graph in that part)
775 RectF clipRect;
776 if (graphics.graphics)
777 graphics.graphics->GetVisibleClipBounds (&clipRect);
779 // don't show stripes if we don't have multiple roots
781 CSyncPointer<const ILayoutRectList> trees (m_state.GetTrees());
782 if (trees->GetCount() < 2)
783 return;
785 // iterate over all trees
787 for ( index_t i = 0, count = trees->GetCount(); i < count; ++i)
789 // screen coordinates covered by the tree
791 CRect tree = trees->GetRect(i);
792 REAL left = tree.left * m_fZoomFactor;
793 REAL right = tree.right * m_fZoomFactor;
794 RectF rect ( left - offset.cx
795 , clipRect.Y
796 , i+1 == count ? clipRect.Width : right - left
797 , clipRect.Height);
799 // relevant?
801 if (rect.IntersectsWith (clipRect))
803 // draw the background stripe
805 Color color ( (i & 1) == 0
806 ? m_Colors.GetColor (CColors::gdpStripeColor1)
807 : m_Colors.GetColor (CColors::gdpStripeColor2));
808 if (graphics.graphics)
810 SolidBrush brush (color);
811 graphics.graphics->FillRectangle (&brush, rect);
813 else if (graphics.pSVG)
814 graphics.pSVG->RoundedRectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height,
815 color, 1, color);
819 #endif
821 PointF CRevisionGraphWnd::cutPoint(node v,double lw,PointF ps, PointF pt)
823 double x = m_GraphAttr.x(v);
824 double y = m_GraphAttr.y(v);
825 double xmin = x - this->m_GraphAttr.width(v)/2 - lw/2;
826 double xmax = x + this->m_GraphAttr.width(v)/2 + lw/2;
827 double ymin = y - this->m_GraphAttr.height(v)/2 - lw/2;
828 double ymax = y + this->m_GraphAttr.height(v)/2 + lw/2;;
830 double dx = pt.X - ps.X;
831 double dy = pt.Y - ps.Y;
833 if(dy != 0) {
834 // below
835 if(pt.Y > ymax) {
836 double t = (ymax-ps.Y) / dy;
837 x = ps.X + t * dx;
839 if(xmin <= x && x <= xmax)
840 return PointF((REAL)x, (REAL)ymax);
842 // above
843 } else if(pt.Y < ymin) {
844 double t = (ymin-ps.Y) / dy;
845 x = ps.X + t * dx;
847 if(xmin <= x && x <= xmax)
848 return PointF((REAL)x, (REAL)ymin);
852 if(dx != 0) {
853 // right
854 if(pt.X > xmax) {
855 double t = (xmax-ps.X) / dx;
856 y = ps.Y + t * dy;
858 if(ymin <= y && y <= ymax)
859 return PointF((REAL)xmax, (REAL)y);
861 // left
862 } else if(pt.X < xmin) {
863 double t = (xmin-ps.X) / dx;
864 y = ps.Y + t * dy;
866 if(ymin <= y && y <= ymax)
867 return PointF((REAL)xmin, (REAL)y);
871 return pt;
874 void CRevisionGraphWnd::DrawConnections (GraphicsDevice& graphics, const CRect& /*logRect*/, const CSize& offset)
876 CArray<PointF> points;
877 CArray<CPoint> pts;
879 if(graphics.graphics)
880 graphics.graphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
882 float penwidth = 2*m_fZoomFactor<1? 1:2*m_fZoomFactor;
883 Gdiplus::Pen pen(GetColorFromSysColor(COLOR_WINDOWTEXT), penwidth);
885 // iterate over all visible lines
886 edge e;
887 forall_edges(e, m_Graph)
889 // get connection and point position
890 const DPolyline &dpl = this->m_GraphAttr.bends(e);
892 points.RemoveAll();
893 pts.RemoveAll();
895 PointF pt;
896 pt.X = (REAL)m_GraphAttr.x(e->source());
897 pt.Y = (REAL)m_GraphAttr.y(e->source());
899 points.Add(pt);
901 ListConstIterator<DPoint> it;
902 for(it = dpl.begin(); it.valid(); ++it)
904 pt.X = (REAL)(*it).m_x;
905 pt.Y = (REAL)(*it).m_y;
906 points.Add(pt);
909 pt.X = (REAL)m_GraphAttr.x(e->target());
910 pt.Y = (REAL)m_GraphAttr.y(e->target());
912 points.Add(pt);
914 points[0] = this->cutPoint(e->source(), 1, points[0], points[1]);
915 points[points.GetCount()-1] = this->cutPoint(e->target(), 1, points[points.GetCount()-1], points[points.GetCount()-2]);
916 // draw the connection
918 for (int i = 0; i < points.GetCount(); ++i)
920 //CPoint pt;
921 points[i].X = points[i].X * this->m_fZoomFactor - offset.cx;
922 points[i].Y = points[i].Y * this->m_fZoomFactor - offset.cy;
923 //pts.Add(pt);
926 if (graphics.graphics)
927 graphics.graphics->DrawLines(&pen, points.GetData(), (INT)points.GetCount());
928 else if (graphics.pSVG)
929 graphics.pSVG->Polyline(points.GetData(), (int)points.GetCount(), Color(0,0,0), (int)penwidth);
930 else if (graphics.pGraphviz)
932 CString hash1 = L'g' + m_logEntries[e->target()->index()].ToString().Left(g_Git.GetShortHASHLength());
933 CString hash2 = L'g' + m_logEntries[e->source()->index()].ToString().Left(g_Git.GetShortHASHLength());
934 graphics.pGraphviz->DrawEdge(hash1, hash2);
937 //draw arrow
938 double dx = points[1].X - points[0].X;
939 double dy = points[1].Y - points[0].Y;
941 double len = sqrt(dx*dx + dy*dy);
942 dx = m_ArrowSize * m_fZoomFactor *dx /len;
943 dy = m_ArrowSize * m_fZoomFactor *dy /len;
945 double p1_x, p1_y, p2_x, p2_y;
946 p1_x = dx * m_ArrowCos - dy * m_ArrowSin;
947 p1_y = dx * m_ArrowSin + dy * m_ArrowCos;
949 p2_x = dx * m_ArrowCos + dy * m_ArrowSin;
950 p2_y = -dx * m_ArrowSin + dy * m_ArrowCos;
952 //graphics.graphics->DrawLine(&pen, points[0].X,points[0].Y, points[0].X +p1_x,points[0].Y+p1_y);
953 //graphics.graphics->DrawLine(&pen, points[0].X,points[0].Y, points[0].X +p2_x,points[0].Y+p2_y);
954 GraphicsPath path;
956 PointF arrows[5];
957 arrows[0].X = points[0].X;
958 arrows[0].Y = points[0].Y;
960 arrows[1].X = points[0].X + (REAL)p1_x;
961 arrows[1].Y = points[0].Y + (REAL)p1_y;
963 arrows[2].X = points[0].X + (REAL)dx*3/5;
964 arrows[2].Y = points[0].Y + (REAL)dy*3/5;
966 arrows[3].X = points[0].X + (REAL)p2_x;
967 arrows[3].Y = points[0].Y + (REAL)p2_y;
969 arrows[4].X = points[0].X;
970 arrows[4].Y = points[0].Y;
972 path.AddLines(arrows, 5);
973 path.SetFillMode(FillModeAlternate);
974 if(graphics.graphics)
975 graphics.graphics->DrawPath(&pen, &path);
976 else if(graphics.pSVG)
977 graphics.pSVG->DrawPath(arrows, 5, Color(0,0,0), (int)penwidth, Color(0,0,0));
981 void CRevisionGraphWnd::DrawTexts (GraphicsDevice& graphics, const CRect& /*logRect*/, const CSize& offset)
983 //COLORREF standardTextColor = GetSysColor(COLOR_WINDOWTEXT);
984 if (m_nFontSize <= 0)
985 return;
987 // iterate over all visible nodes
989 if (graphics.pDC)
990 graphics.pDC->SetTextAlign (TA_CENTER | TA_TOP);
992 CString fontname = CAppUtils::GetLogFontName();
994 Gdiplus::Font font(fontname, (REAL)m_nFontSize, FontStyleRegular);
995 SolidBrush blackbrush((ARGB)Color::Black);
997 DWORD revGraphUseLocalForCur = CRegDWORD(L"Software\\TortoiseGit\\TortoiseProc\\Graph\\RevGraphUseLocalForCur");
999 node v;
1000 forall_nodes(v,m_Graph)
1002 // get node and position
1004 String label=this->m_GraphAttr.labelNode(v);
1006 RectF noderect (GetNodeRect (v, offset));
1008 // draw the revision text
1009 CGitHash hash = this->m_logEntries[v->index()];
1010 double hight = noderect.Height / (!m_HashMap[hash].empty() ? m_HashMap[hash].size() : 1);
1012 if (m_HashMap.find(hash) == m_HashMap.end() || m_HashMap[hash].empty())
1014 Color background;
1015 background.SetFromCOLORREF (GetSysColor(COLOR_WINDOW));
1016 Gdiplus::Pen pen(background,1.0F);
1017 Color brightColor = LimitedScaleColor (background, RGB(255,0,0), 0.9f);
1018 Gdiplus::SolidBrush brush(brightColor);
1020 DrawRoundedRect(graphics, background,1, &pen, brightColor, &brush, noderect);
1022 if(graphics.graphics)
1024 graphics.graphics->DrawString(hash.ToString().Left(g_Git.GetShortHASHLength()),-1,
1025 &font,
1026 Gdiplus::PointF(noderect.X + this->GetLeftRightMargin()*this->m_fZoomFactor,noderect.Y+this->GetTopBottomMargin()*m_fZoomFactor),
1027 &blackbrush);
1029 if(graphics.pSVG)
1031 graphics.pSVG->Text((int)(noderect.X + this->GetLeftRightMargin() * this->m_fZoomFactor),
1032 (int)(noderect.Y + this->GetTopBottomMargin() * m_fZoomFactor + m_nFontSize),
1033 CUnicodeUtils::GetUTF8(fontname), m_nFontSize, false, false, (ARGB)Color::Black,
1034 CUnicodeUtils::GetUTF8(hash.ToString().Left(g_Git.GetShortHASHLength())));
1036 if (graphics.pGraphviz)
1038 CString shortHash = hash.ToString().Left(g_Git.GetShortHASHLength());
1039 graphics.pGraphviz->DrawNode(L'g' + shortHash, shortHash, fontname, m_nFontSize, background, brightColor, (int)noderect.Height);
1041 }else
1043 if (graphics.pGraphviz)
1045 CString id = L'g' + hash.ToString().Left(g_Git.GetShortHASHLength());
1046 graphics.pGraphviz->BeginDrawTableNode(id, fontname, m_nFontSize, (int)noderect.Height);
1049 for (size_t i = 0; i < m_HashMap[hash].size(); ++i)
1051 CString shortname;
1052 CString str = m_HashMap[hash][i];
1053 RectF rect;
1055 rect.X = (REAL)noderect.X;
1056 rect.Y = (REAL)(noderect.Y + hight*i);
1057 rect.Width = (REAL)noderect.Width;
1058 rect.Height = (REAL)hight;
1060 COLORREF colRef = RGB(224, 224, 224);
1062 CGit::REF_TYPE refType;
1063 shortname = CGit::GetShortName(str, &refType);
1064 switch (refType)
1066 case CGit::REF_TYPE::LOCAL_BRANCH:
1067 if (!revGraphUseLocalForCur && shortname == m_CurrentBranch)
1068 colRef = m_Colors.GetColor(CColors::CurrentBranch);
1069 else
1070 colRef = m_Colors.GetColor(CColors::LocalBranch);
1071 break;
1072 case CGit::REF_TYPE::REMOTE_BRANCH:
1073 colRef = m_Colors.GetColor(CColors::RemoteBranch);
1074 break;
1075 case CGit::REF_TYPE::ANNOTATED_TAG:
1076 case CGit::REF_TYPE::TAG:
1077 colRef = m_Colors.GetColor(CColors::Tag);
1078 break;
1079 case CGit::REF_TYPE::STASH:
1080 colRef = m_Colors.GetColor(CColors::Stash);
1081 break;
1082 case CGit::REF_TYPE::BISECT_GOOD:
1083 colRef = m_Colors.GetColor(CColors::BisectGood);
1084 break;
1085 case CGit::REF_TYPE::BISECT_BAD:
1086 colRef = m_Colors.GetColor(CColors::BisectBad);
1087 break;
1088 case CGit::REF_TYPE::BISECT_SKIP:
1089 colRef = m_Colors.GetColor(CColors::BisectSkip);
1090 break;
1091 case CGit::REF_TYPE::NOTES:
1092 colRef = m_Colors.GetColor(CColors::NoteNode);
1093 break;
1096 Gdiplus::Color color(GetRValue(colRef), GetGValue(colRef), GetBValue(colRef));
1097 Gdiplus::Pen pen(color);
1098 Gdiplus::SolidBrush brush(color);
1100 int mask =0;
1101 mask |= (i==0)? ROUND_UP:0;
1102 mask |= (i== m_HashMap[hash].size()-1)? ROUND_DOWN:0;
1103 this->DrawRoundedRect(graphics, color,1,&pen, color,&brush, rect,mask);
1105 if (graphics.graphics)
1107 //graphics.graphics->FillRectangle(&SolidBrush(Gdiplus::Color(GetRValue(colRef), GetGValue(colRef), GetBValue(colRef))),
1108 // rect);
1110 graphics.graphics->DrawString(shortname, shortname.GetLength(),
1111 &font,
1112 Gdiplus::PointF((REAL)(noderect.X + this->GetLeftRightMargin()*m_fZoomFactor),
1113 (REAL)(noderect.Y + this->GetTopBottomMargin()*m_fZoomFactor+ hight*i)),
1114 &blackbrush);
1116 //graphics.graphics->DrawString(shortname.GetBuffer(), shortname.GetLength(), ::new Gdiplus::Font(graphics.pDC->m_hDC), PointF(noderect.X, noderect.Y + hight * i), nullptr, nullptr);
1119 else if (graphics.pSVG)
1120 graphics.pSVG->Text((int)(noderect.X + this->GetLeftRightMargin() * m_fZoomFactor),
1121 (int)(noderect.Y + this->GetTopBottomMargin() * m_fZoomFactor + hight * i + m_nFontSize),
1122 CUnicodeUtils::GetUTF8(fontname), m_nFontSize,
1123 false, false, (ARGB)Color::Black, CUnicodeUtils::GetUTF8(shortname));
1124 else if (graphics.pGraphviz)
1125 graphics.pGraphviz->DrawTableNode(shortname, color);
1128 if (graphics.pGraphviz)
1129 graphics.pGraphviz->EndDrawTableNode();
1131 if ((m_SelectedEntry1 == v))
1132 DrawMarker(graphics, noderect, mpLeft, 0, GetColorFromSysColor(COLOR_HIGHLIGHT), 1);
1134 if ((m_SelectedEntry2 == v))
1135 DrawMarker(graphics, noderect, mpLeft, 0, Color(136,0, 21), 2);
1140 #if 0
1141 void CRevisionGraphWnd::DrawCurrentNodeGlyphs (GraphicsDevice& graphics, Image* glyphs, const CSize& offset)
1143 CSyncPointer<const ILayoutNodeList> nodeList (m_state.GetNodes());
1144 bool upsideDown
1145 = m_state.GetOptions()->GetOption<CUpsideDownLayout>()->IsActive();
1147 // don't draw glyphs if we are outside the client area
1148 // (e.g. within a scrollbar)
1150 CPoint point;
1151 GetCursorPos (&point);
1152 ScreenToClient (&point);
1153 if (!GetClientRect().PtInRect (point))
1154 return;
1156 // expansion glypths etc.
1158 m_hoverIndex = GetHitNode (point);
1159 m_hoverGlyphs = GetHoverGlyphs (point);
1161 if ((m_hoverIndex != NO_INDEX) || (m_hoverGlyphs != 0))
1163 index_t nodeIndex = m_hoverIndex == NO_INDEX
1164 ? GetHitNode (point, CSize (GLYPH_SIZE, GLYPH_SIZE / 2))
1165 : m_hoverIndex;
1167 if (nodeIndex >= nodeList->GetCount())
1168 return;
1170 ILayoutNodeList::SNode node = nodeList->GetNode (nodeIndex);
1171 RectF noderect (GetNodeRect (node, offset));
1173 DWORD flags = m_state.GetNodeStates()->GetFlags (node.node);
1175 IndicateGlyphDirection (graphics, nodeList.get(), node, noderect, m_hoverGlyphs, upsideDown, offset);
1176 DrawGlyphs (graphics, glyphs, node.node, noderect, flags, m_hoverGlyphs, upsideDown);
1179 #endif
1181 void CRevisionGraphWnd::DrawGraph(GraphicsDevice& graphics, const CRect& rect, int nVScrollPos, int nHScrollPos, bool bDirectDraw)
1183 CMemDC* memDC = nullptr;
1184 if (graphics.pDC)
1186 if (!bDirectDraw)
1188 memDC = new CMemDC (*graphics.pDC, rect);
1189 graphics.pDC = &memDC->GetDC();
1192 graphics.pDC->FillSolidRect(rect, GetSysColor(COLOR_WINDOW));
1193 graphics.pDC->SetBkMode(TRANSPARENT);
1196 // preparation & sync
1198 //CSyncPointer<CAllRevisionGraphOptions> options (m_state.GetOptions());
1199 ClearVisibleGlyphs (rect);
1201 // transform visible
1203 CSize offset (nHScrollPos, nVScrollPos);
1204 CRect logRect ( (int)(offset.cx / m_fZoomFactor)-1
1205 , (int)(offset.cy / m_fZoomFactor)-1
1206 , (int)((rect.Width() + offset.cx) / m_fZoomFactor) + 1
1207 , (int)((rect.Height() + offset.cy) / m_fZoomFactor) + 1);
1209 // draw the different components
1211 if (graphics.pDC)
1213 Graphics* gcs = Graphics::FromHDC(*graphics.pDC);
1214 graphics.graphics = gcs;
1215 gcs->SetPageUnit (UnitPixel);
1216 gcs->SetInterpolationMode (InterpolationModeHighQualityBicubic);
1217 gcs->SetSmoothingMode(SmoothingModeAntiAlias);
1218 gcs->SetClip(RectF(Gdiplus::REAL(rect.left), Gdiplus::REAL(rect.top), Gdiplus::REAL(rect.Width()), Gdiplus::REAL(rect.Height())));
1221 // if (options->GetOption<CShowTreeStripes>()->IsActive())
1222 // DrawStripes (graphics, offset);
1224 //if (m_fZoomFactor > SHADOW_ZOOM_THRESHOLD)
1225 // DrawShadows (graphics, logRect, offset);
1227 Bitmap glyphs (AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_REVGRAPHGLYPHS));
1229 DrawTexts (graphics, logRect, offset);
1230 DrawConnections (graphics, logRect, offset);
1231 //if (m_showHoverGlyphs)
1232 // DrawCurrentNodeGlyphs (graphics, &glyphs, offset);
1234 // draw preview
1236 if ((!bDirectDraw)&&(m_Preview.GetSafeHandle())&&(m_bShowOverview)&&(graphics.pDC))
1238 // draw the overview image rectangle in the top right corner
1239 CMyMemDC memDC2(graphics.pDC, true);
1240 memDC2.SetWindowOrg(0, 0);
1241 HBITMAP oldhbm = (HBITMAP)memDC2.SelectObject(&m_Preview);
1242 graphics.pDC->BitBlt(rect.Width()-m_previewWidth, rect.Height() - m_previewHeight, m_previewWidth, m_previewHeight,
1243 &memDC2, 0, 0, SRCCOPY);
1244 memDC2.SelectObject(oldhbm);
1245 // draw the border for the overview rectangle
1246 m_OverviewRect.left = rect.Width()-m_previewWidth;
1247 m_OverviewRect.top = rect.Height()- m_previewHeight;
1248 m_OverviewRect.right = rect.Width();
1249 m_OverviewRect.bottom = rect.Height();
1250 graphics.pDC->DrawEdge(&m_OverviewRect, EDGE_BUMP, BF_RECT);
1251 // now draw a rectangle where the current view is located in the overview
1253 LONG width = (long)(rect.Width() * m_previewZoom / m_fZoomFactor);
1254 LONG height = (long)(rect.Height() * m_previewZoom / m_fZoomFactor);
1255 LONG xpos = (long)(nHScrollPos * m_previewZoom / m_fZoomFactor);
1256 LONG ypos = (long)(nVScrollPos * m_previewZoom / m_fZoomFactor);
1257 RECT tempRect;
1258 tempRect.left = rect.Width()-m_previewWidth+xpos;
1259 tempRect.top = rect.Height() - m_previewHeight + ypos;
1260 tempRect.right = tempRect.left + width;
1261 tempRect.bottom = tempRect.top + height;
1262 // make sure the position rect is not bigger than the preview window itself
1263 ::IntersectRect(&m_OverviewPosRect, &m_OverviewRect, &tempRect);
1265 RectF rect2 ( (float)m_OverviewPosRect.left, (float)m_OverviewPosRect.top
1266 , (float)m_OverviewPosRect.Width(), (float)m_OverviewPosRect.Height());
1267 if (graphics.graphics)
1269 SolidBrush brush (Color (64, 0, 0, 0));
1270 graphics.graphics->FillRectangle (&brush, rect2);
1271 graphics.pDC->DrawEdge(&m_OverviewPosRect, EDGE_BUMP, BF_RECT);
1275 // flush changes to screen
1277 delete graphics.graphics;
1278 delete memDC;
1281 void CRevisionGraphWnd::SetNodeRect(GraphicsDevice& graphics, ogdf::node *pnode, CGitHash rev, int mode )
1283 //multi - line mode. One RefName is one new line
1284 CString fontname = CAppUtils::GetLogFontName();
1285 if(mode == 0)
1287 if(this->m_HashMap.find(rev) == m_HashMap.end())
1289 CString shorthash = rev.ToString().Left(g_Git.GetShortHASHLength());
1290 RectF rect;
1291 if(graphics.graphics)
1293 //GetTextExtentPoint32(graphics.pDC->m_hDC, shorthash.GetBuffer(), shorthash.GetLength(), &size);
1294 Gdiplus::Font font(fontname, (REAL)m_nFontSize, FontStyleRegular);
1295 graphics.graphics->MeasureString(shorthash, shorthash.GetLength(),
1296 &font,
1297 Gdiplus::PointF(0,0), &rect);
1299 m_GraphAttr.width(*pnode) = this->GetLeftRightMargin()*2 + rect.Width;
1300 m_GraphAttr.height(*pnode) = this->GetTopBottomMargin()*2 + rect.Height;
1302 else
1304 double xmax=0;
1305 double ymax=0;
1306 int lines =0;
1307 for (size_t i = 0; i < m_HashMap[rev].size(); ++i)
1309 RectF rect;
1310 CString shortref = m_HashMap[rev][i];
1311 shortref = CGit::GetShortName(shortref, nullptr);
1312 if(graphics.pDC)
1314 Gdiplus::Font font(fontname, (REAL)m_nFontSize, FontStyleRegular);
1315 graphics.graphics->MeasureString(shortref, shortref.GetLength(),
1316 &font,
1317 Gdiplus::PointF(0,0), &rect);
1318 if(rect.Width > xmax)
1319 xmax = rect.Width;
1320 if(rect.Height > ymax)
1321 ymax = rect.Height;
1323 ++lines;
1325 m_GraphAttr.width(*pnode) = this->GetLeftRightMargin()*2 + xmax;
1326 m_GraphAttr.height(*pnode) = (this->GetTopBottomMargin()*2 + ymax) * lines;