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