1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8 PathFinder.cpp - description
9 -------------------
10 begin : Fri Jun 29 2007
11 copyright : (C) 2007 by Franz Schmid
12 email : Franz.Schmid@altmuehlnet.de
13 ***************************************************************************/
14
15 /***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23 #include "pathfinderdialog.h"
24
25 #include "fpointarray.h"
26 #include "pageitem.h"
27 #include "sccolorengine.h"
28 #include "scribusdoc.h"
29 #include "util.h"
30 #include "iconmanager.h"
31
32 #include <QPixmap>
33 #include <QPainter>
34 #include <QTransform>
35
PathFinderDialog(QWidget * parent,ScribusDoc * doc,PageItem * shape1,PageItem * shape2)36 PathFinderDialog::PathFinderDialog(QWidget* parent, ScribusDoc* doc, PageItem *shape1, PageItem *shape2) : QDialog( parent )
37 {
38 m_doc = doc;
39 setupUi(this);
40 setModal(true);
41 setWindowIcon(QIcon(IconManager::instance().loadIcon("AppIcon.png")));
42 opCombine->setText( QString() );
43 opSubtraction->setText( QString() );
44 opIntersection->setText( QString() );
45 opExclusion->setText( QString() );
46 opParts->setText( QString() );
47 opExclusion->setIcon(QIcon(IconManager::instance().loadIcon("pathexclusion.png")));
48 opIntersection->setIcon(QIcon(IconManager::instance().loadIcon("pathintersection.png")));
49 opParts->setIcon(QIcon(IconManager::instance().loadIcon("pathparts.png")));
50 opSubtraction->setIcon(QIcon(IconManager::instance().loadIcon("pathsubtraction.png")));
51 opCombine->setIcon(QIcon(IconManager::instance().loadIcon("pathunite.png")));
52 otherColorComboLine->setPixmapType(ColorCombo::fancyPixmaps);
53 otherColorComboLine->setColors(m_doc->PageColors, true);
54 otherColorComboFill->setPixmapType(ColorCombo::fancyPixmaps);
55 otherColorComboFill->setColors(m_doc->PageColors, true);
56 setCurrentComboItem(otherColorComboLine, shape1->lineColor());
57 setCurrentComboItem(otherColorComboFill, shape1->fillColor());
58 opMode = 0;
59 QTransform ms;
60 ms.rotate(shape1->rotation());
61 m_input1 = ms.map(shape1->PoLine.toQPainterPath(true));
62 if (shape1->fillEvenOdd())
63 m_input1.setFillRule(Qt::OddEvenFill);
64 else
65 m_input1.setFillRule(Qt::WindingFill);
66 double dx = shape2->xPos() - shape1->xPos();
67 double dy = shape2->yPos() - shape1->yPos();
68 QTransform mm;
69 mm.translate(dx, dy);
70 mm.rotate(shape2->rotation());
71 m_input2 = mm.map(shape2->PoLine.toQPainterPath(true));
72 if (shape2->fillEvenOdd())
73 m_input2.setFillRule(Qt::OddEvenFill);
74 else
75 m_input2.setFillRule(Qt::WindingFill);
76 result = QPainterPath();
77 m_source1 = shape1;
78 m_source2 = shape2;
79 swapped = false;
80 targetColor = 0;
81 keepItem1 = false;
82 keepItem2 = false;
83 updateAllPreviews();
84 connect(targetGetsSource1Color, SIGNAL(clicked()), this, SLOT(updateResult()));
85 connect(targetGetsSource2Color, SIGNAL(clicked()), this, SLOT(updateResult()));
86 connect(targetGetsOtherColor, SIGNAL(clicked()), this, SLOT(updateResult()));
87 connect(otherColorComboFill, SIGNAL(activated(int)), this, SLOT(updateResult()));
88 connect(keepSource1, SIGNAL(clicked()), this, SLOT(checkKeep()));
89 connect(keepSource2, SIGNAL(clicked()), this, SLOT(checkKeep()));
90 connect(opCombine, SIGNAL(clicked()), this, SLOT(newOpMode()));
91 connect(opSubtraction, SIGNAL(clicked()), this, SLOT(newOpMode()));
92 connect(opIntersection, SIGNAL(clicked()), this, SLOT(newOpMode()));
93 connect(opExclusion, SIGNAL(clicked()), this, SLOT(newOpMode()));
94 connect(opParts, SIGNAL(clicked()), this, SLOT(newOpMode()));
95 connect(swapShapes, SIGNAL(clicked()), this, SLOT(swapObjects()));
96 }
97
checkKeep()98 void PathFinderDialog::checkKeep()
99 {
100 keepItem1 = keepSource1->isChecked();
101 keepItem2 = keepSource2->isChecked();
102 }
103
newOpMode()104 void PathFinderDialog::newOpMode()
105 {
106 optionGroup->setTitle( tr("Result gets Color of:"));
107 if (opCombine->isChecked())
108 {
109 label->setText("+");
110 opMode = 0;
111 }
112 else if (opSubtraction->isChecked())
113 {
114 label->setText("-");
115 opMode = 1;
116 }
117 else if (opIntersection->isChecked())
118 {
119 label->setText(QChar(0x2229));
120 opMode = 2;
121 }
122 else if (opExclusion->isChecked())
123 {
124 label->setText(QChar(0x2206));
125 opMode = 3;
126 }
127 else if (opParts->isChecked())
128 {
129 label->setText(" ");
130 optionGroup->setTitle( tr("Intersection gets Color of:"));
131 opMode = 4;
132 }
133 updateResult();
134 }
135
swapObjects()136 void PathFinderDialog::swapObjects()
137 {
138 QPainterPath tmp = m_input1;
139 m_input1 = m_input2;
140 m_input2 = tmp;
141 PageItem* item = m_source1;
142 m_source1 = m_source2;
143 m_source2 = item;
144 swapped = !swapped;
145 updateAllPreviews();
146 }
147
updatePreview(QLabel * label,QPainterPath & path,const QColor & color,double scale)148 void PathFinderDialog::updatePreview(QLabel *label, QPainterPath &path, const QColor& color, double scale)
149 {
150 QPixmap pm(100, 100);
151 QPainter p;
152 p.begin(&pm);
153 p.setRenderHint(QPainter::Antialiasing, true);
154 QBrush b(QColor(205,205,205), IconManager::instance().loadPixmap("testfill.png"));
155 p.fillRect(0, 0, pm.width(), pm.height(), b);
156 QRectF bb = m_input1.boundingRect().united(m_input2.boundingRect());
157 p.translate(5, 5);
158 p.scale(scale, scale);
159 p.translate(-bb.x(), -bb.y());
160 p.setPen(Qt::black);
161 p.setBrush(color);
162 p.drawPath(path);
163 p.end();
164 label->setPixmap(pm);
165 }
166
updatePartPreview(const QColor & color,double scale)167 void PathFinderDialog::updatePartPreview(const QColor& color, double scale)
168 {
169 QPixmap pm(100, 100);
170 QPainter p;
171 p.begin(&pm);
172 p.setRenderHint(QPainter::Antialiasing, true);
173 QBrush b(QColor(205,205,205), IconManager::instance().loadPixmap("testfill.png"));
174 p.fillRect(0, 0, pm.width(), pm.height(), b);
175 QRectF bb = m_input1.boundingRect().united(m_input2.boundingRect());
176 p.translate(5, 5);
177 p.scale(scale, scale);
178 p.translate(-bb.x(), -bb.y());
179 p.setPen(Qt::black);
180 p.setBrush(getColorFromItem(m_source1->fillColor(), Qt::blue));
181 p.drawPath(result);
182 p.setBrush(getColorFromItem(m_source2->fillColor(), Qt::red));
183 p.drawPath(result1);
184 p.setBrush(color);
185 p.drawPath(result2);
186 p.end();
187 resultShape->setPixmap(pm);
188 }
189
updateAllPreviews()190 void PathFinderDialog::updateAllPreviews()
191 {
192 QRectF bb = m_input1.boundingRect().united(m_input2.boundingRect());
193 double scaleX = 90.0 / bb.width();
194 double scaleY = 90.0 / bb.height();
195 double scale = qMin(scaleX, scaleY);
196 updatePreview(sourceShape, m_input1, getColorFromItem(m_source1->fillColor(), Qt::blue), scale);
197 updatePreview(sourceShape2, m_input2, getColorFromItem(m_source2->fillColor(), Qt::red), scale);
198 updateResult();
199 }
200
updateResult()201 void PathFinderDialog::updateResult()
202 {
203 result = QPainterPath();
204 result1 = QPainterPath();
205 result2 = QPainterPath();
206 if (opMode == 0)
207 {
208 result = m_input1.united(m_input2);
209 }
210 else if (opMode == 1)
211 {
212 result = m_input1.subtracted(m_input2);
213 }
214 else if (opMode == 2)
215 {
216 result = m_input1.intersected(m_input2);
217 }
218 else if (opMode == 3)
219 {
220 QPainterPath part1 = m_input1.subtracted(m_input2);
221 QPainterPath part2 = m_input2.subtracted(m_input1);
222 result.addPath(part1);
223 result.addPath(part2);
224 }
225 else if (opMode == 4)
226 {
227 QPainterPath part1 = m_input1.subtracted(m_input2);
228 QPainterPath part2 = m_input2.subtracted(m_input1);
229 QPainterPath part3 = m_input1.intersected(m_input2);
230 result.addPath(part1);
231 result1.addPath(part2);
232 result2.addPath(part3);
233 }
234 QRectF bb = m_input1.boundingRect().united(m_input2.boundingRect());
235 double scaleX = 90.0 / bb.width();
236 double scaleY = 90.0 / bb.height();
237 double scale = qMin(scaleX, scaleY);
238 QColor cc = Qt::red;
239 if (targetGetsSource1Color->isChecked())
240 {
241 cc = getColorFromItem(m_source1->fillColor(), Qt::blue);
242 targetColor = 0;
243 setCurrentComboItem(otherColorComboLine, m_source1->lineColor());
244 setCurrentComboItem(otherColorComboFill, m_source1->fillColor());
245 }
246 else if (targetGetsSource2Color->isChecked())
247 {
248 targetColor = 1;
249 cc = getColorFromItem(m_source2->fillColor(), Qt::red);
250 setCurrentComboItem(otherColorComboLine, m_source2->lineColor());
251 setCurrentComboItem(otherColorComboFill, m_source2->fillColor());
252 }
253 else if (targetGetsOtherColor->isChecked())
254 {
255 cc = getColorFromItem(getOtherFillColor(), Qt::green);
256 targetColor = 2;
257 }
258 if (opMode == 4)
259 updatePartPreview(cc, scale);
260 else
261 updatePreview(resultShape, result, cc, scale);
262 }
263
getColorFromItem(const QString & color,const QColor & in)264 QColor PathFinderDialog::getColorFromItem(const QString& color, const QColor& in)
265 {
266 QColor out(in);
267 QString fill = color;
268 if (fill == CommonStrings::tr_NoneColor)
269 fill = CommonStrings::None;
270 if (fill != CommonStrings::None)
271 {
272 ScColor color = m_doc->PageColors[fill];
273 out = ScColorEngine::getDisplayColor(color, m_doc);
274 }
275 return out;
276 }
277
getOtherFillColor()278 QString PathFinderDialog::getOtherFillColor()
279 {
280 return otherColorComboFill->currentText();
281 }
282
getOtherLineColor()283 QString PathFinderDialog::getOtherLineColor()
284 {
285 return otherColorComboLine->currentText();
286 }
287