1 /*
2  * KDiff3 - Text Diff And Merge Tool
3  *
4  * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de
5  * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com
6  * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 
9 #include "MergeFileInfos.h"
10 
11 #include <QApplication>
12 #include <QIcon>
13 #include <QPainter>
14 #include <QPixmap>
15 #include <QStyle>
16 
17 namespace PixMapUtils
18 {
19 namespace{
20 QPixmap* s_pm_dir = nullptr;
21 QPixmap* s_pm_file = nullptr;
22 
23 QPixmap* pmNotThere;
24 QPixmap* pmNew = nullptr;
25 QPixmap* pmOld;
26 QPixmap* pmMiddle;
27 
28 QPixmap* pmLink;
29 
30 QPixmap* pmDirLink;
31 QPixmap* pmFileLink;
32 
33 QPixmap* pmNewLink;
34 QPixmap* pmOldLink;
35 QPixmap* pmMiddleLink;
36 
37 QPixmap* pmNewDir;
38 QPixmap* pmMiddleDir;
39 QPixmap* pmOldDir;
40 
41 QPixmap* pmNewDirLink;
42 QPixmap* pmMiddleDirLink;
43 QPixmap* pmOldDirLink;
44 }
colorToPixmap(const QColor & inColor)45 QPixmap colorToPixmap(const QColor &inColor)
46 {
47     QPixmap pm(16, 16);
48     QPainter p(&pm);
49     p.setPen(Qt::black);
50     p.setBrush(inColor);
51     p.drawRect(0, 0, pm.width(), pm.height());
52     return pm;
53 }
54 // Copy pm2 onto pm1, but preserve the alpha value from pm1 where pm2 is transparent.
pixCombiner(const QPixmap * pm1,const QPixmap * pm2)55 QPixmap pixCombiner(const QPixmap* pm1, const QPixmap* pm2)
56 {
57     QImage img1 = pm1->toImage().convertToFormat(QImage::Format_ARGB32);
58     QImage img2 = pm2->toImage().convertToFormat(QImage::Format_ARGB32);
59 
60     for(int y = 0; y < img1.height(); y++)
61     {
62         quint32* line1 = reinterpret_cast<quint32*>(img1.scanLine(y));
63         quint32* line2 = reinterpret_cast<quint32*>(img2.scanLine(y));
64         for(int x = 0; x < img1.width(); x++)
65         {
66             if(qAlpha(line2[x]) > 0)
67                 line1[x] = (line2[x] | 0xff000000);
68         }
69     }
70     return QPixmap::fromImage(img1);
71 }
72 
73 // like pixCombiner but let the pm1 color shine through
pixCombiner2(const QPixmap * pm1,const QPixmap * pm2)74 QPixmap pixCombiner2(const QPixmap* pm1, const QPixmap* pm2)
75 {
76     QPixmap pix = *pm1;
77     QPainter p(&pix);
78     p.setOpacity(0.5);
79     p.drawPixmap(0, 0, *pm2);
80     p.end();
81 
82     return pix;
83 }
84 
initPixmaps(const QColor & newest,const QColor & oldest,const QColor & middle,const QColor & notThere)85 void initPixmaps(const QColor& newest, const QColor& oldest, const QColor& middle, const QColor& notThere)
86 {
87     if(s_pm_dir == nullptr || s_pm_file == nullptr)
88     {
89 #include "xpm/file.xpm"
90 #include "xpm/folder.xpm"
91         const int smallIcon = qApp->style()->pixelMetric(QStyle::PM_SmallIconSize);
92         s_pm_dir = new QPixmap(QIcon::fromTheme(QStringLiteral("folder")).pixmap(smallIcon));
93         if(s_pm_dir->size() != QSize(16, 16))
94         {
95             delete s_pm_dir;
96             s_pm_dir = new QPixmap(folder_pm);
97         }
98         s_pm_file = new QPixmap(file_pm);
99     }
100 
101     if(pmNew == nullptr)
102     {
103 #include "xpm/link_arrow.xpm"
104 
105         pmNotThere = new QPixmap;
106         pmNew = new QPixmap;
107         pmOld = new QPixmap;
108         pmMiddle = new QPixmap;
109 
110         pmLink = new QPixmap(link_arrow);
111 
112         pmDirLink = new QPixmap;
113         pmFileLink = new QPixmap;
114 
115         pmNewLink = new QPixmap;
116         pmOldLink = new QPixmap;
117         pmMiddleLink = new QPixmap;
118 
119         pmNewDir = new QPixmap;
120         pmMiddleDir = new QPixmap;
121         pmOldDir = new QPixmap;
122 
123         pmNewDirLink = new QPixmap;
124         pmMiddleDirLink = new QPixmap;
125         pmOldDirLink = new QPixmap;
126     }
127 
128     *pmNotThere = colorToPixmap(notThere);
129     *pmNew = colorToPixmap(newest);
130     *pmOld = colorToPixmap(oldest);
131     *pmMiddle = colorToPixmap(middle);
132 
133     *pmDirLink = pixCombiner(s_pm_dir, pmLink);
134     *pmFileLink = pixCombiner(s_pm_file, pmLink);
135 
136     *pmNewLink = pixCombiner(pmNew, pmLink);
137     *pmOldLink = pixCombiner(pmOld, pmLink);
138     *pmMiddleLink = pixCombiner(pmMiddle, pmLink);
139 
140     *pmNewDir = pixCombiner2(pmNew, s_pm_dir);
141     *pmMiddleDir = pixCombiner2(pmMiddle, s_pm_dir);
142     *pmOldDir = pixCombiner2(pmOld, s_pm_dir);
143 
144     *pmNewDirLink = pixCombiner(pmNewDir, pmLink);
145     *pmMiddleDirLink = pixCombiner(pmMiddleDir, pmLink);
146     *pmOldDirLink = pixCombiner(pmOldDir, pmLink);
147 }
148 
getOnePixmap(e_Age eAge,bool bLink,bool bDir)149 QPixmap getOnePixmap(e_Age eAge, bool bLink, bool bDir)
150 {
151     QPixmap* ageToPm[] = {pmNew, pmMiddle, pmOld, pmNotThere, s_pm_file};
152     QPixmap* ageToPmLink[] = {pmNewLink, pmMiddleLink, pmOldLink, pmNotThere, pmFileLink};
153     QPixmap* ageToPmDir[] = {pmNewDir, pmMiddleDir, pmOldDir, pmNotThere, s_pm_dir};
154     QPixmap* ageToPmDirLink[] = {pmNewDirLink, pmMiddleDirLink, pmOldDirLink, pmNotThere, pmDirLink};
155 
156     QPixmap** ppPm = bDir ? (bLink ? ageToPmDirLink : ageToPmDir) : (bLink ? ageToPmLink : ageToPm);
157 
158     return *ppPm[eAge];
159 }
160 
161 } // namespace PixMapUtils
162