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 * Copyright (C) 2007 by Franz Schmid *
9 * franz.schmid@altmuehlnet.de *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
25 ****************************************************************************/
26
27 #if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
28 #define _USE_MATH_DEFINES
29 #endif
30 #include <cmath>
31 #include <QPainterPathStroker>
32
33 #include "pathstroker.h"
34
35 #include "appmodes.h"
36 #include "commonstrings.h"
37 #include "pageitem_polygon.h"
38 #include "scribuscore.h"
39 #include "scribusdoc.h"
40 #include "selection.h"
41 #include "util.h"
42
43
44
pathstroker_getPluginAPIVersion()45 int pathstroker_getPluginAPIVersion()
46 {
47 return PLUGIN_API_VERSION;
48 }
49
pathstroker_getPlugin()50 ScPlugin* pathstroker_getPlugin()
51 {
52 PathStrokerPlugin* plug = new PathStrokerPlugin();
53 Q_CHECK_PTR(plug);
54 return plug;
55 }
56
pathstroker_freePlugin(ScPlugin * plugin)57 void pathstroker_freePlugin(ScPlugin* plugin)
58 {
59 PathStrokerPlugin* plug = qobject_cast<PathStrokerPlugin*>(plugin);
60 Q_ASSERT(plug);
61 delete plug;
62 }
63
PathStrokerPlugin()64 PathStrokerPlugin::PathStrokerPlugin()
65 {
66 // Set action info in languageChange, so we only have to do
67 // it in one place.
68 languageChange();
69 }
70
~PathStrokerPlugin()71 PathStrokerPlugin::~PathStrokerPlugin() {};
72
languageChange()73 void PathStrokerPlugin::languageChange()
74 {
75 // Note that we leave the unused members unset. They'll be initialised
76 // with their default ctors during construction.
77 // Action name
78 m_actionInfo.name = "PathStroker";
79 // Action text for menu, including accel
80 m_actionInfo.text = tr("Create Path from Stroke");
81 // Menu
82 m_actionInfo.menu = "ItemPathOps";
83 m_actionInfo.parentMenu = "Item";
84 m_actionInfo.subMenuName = tr("Path Tools");
85 m_actionInfo.enabledOnStartup = false;
86 m_actionInfo.notSuitableFor.append(PageItem::Line);
87 m_actionInfo.notSuitableFor.append(PageItem::TextFrame);
88 m_actionInfo.notSuitableFor.append(PageItem::ImageFrame);
89 m_actionInfo.notSuitableFor.append(PageItem::PathText);
90 m_actionInfo.notSuitableFor.append(PageItem::LatexFrame);
91 m_actionInfo.notSuitableFor.append(PageItem::Symbol);
92 m_actionInfo.notSuitableFor.append(PageItem::RegularPolygon);
93 m_actionInfo.notSuitableFor.append(PageItem::Arc);
94 m_actionInfo.notSuitableFor.append(PageItem::Spiral);
95 m_actionInfo.forAppMode.append(modeNormal);
96 m_actionInfo.needsNumObjects = 1;
97 }
98
fullTrName() const99 QString PathStrokerPlugin::fullTrName() const
100 {
101 return QObject::tr("PathStroker");
102 }
103
getAboutData() const104 const ScActionPlugin::AboutData* PathStrokerPlugin::getAboutData() const
105 {
106 AboutData* about = new AboutData;
107 Q_CHECK_PTR(about);
108 about->authors = QString::fromUtf8("Franz Schmid <Franz.Schmid@altmuehlnet.de>");
109 about->shortDescription = tr("Create Path from Stroke");
110 about->description = tr("Converts the stroke of a Path to a filled Path.");
111 // about->version
112 // about->releaseDate
113 // about->copyright
114 about->license = "GPL";
115 return about;
116 }
117
deleteAboutData(const AboutData * about) const118 void PathStrokerPlugin::deleteAboutData(const AboutData* about) const
119 {
120 Q_ASSERT(about);
121 delete about;
122 }
123
run(ScribusDoc * doc,const QString &)124 bool PathStrokerPlugin::run(ScribusDoc* doc, const QString&)
125 {
126 ScribusDoc* currDoc = doc;
127 if (currDoc == nullptr)
128 currDoc = ScCore->primaryMainWindow()->doc;
129 if (currDoc->m_Selection->count() > 0)
130 {
131 QVector<double> m_array;
132 PageItem *currItem = currDoc->m_Selection->itemAt(0);
133 FPointArray path = currItem->PoLine;
134 QPainterPath pp;
135 if (currItem->itemType() == PageItem::PolyLine)
136 pp = path.toQPainterPath(false);
137 else
138 pp = path.toQPainterPath(true);
139 if (currItem->NamedLStyle.isEmpty())
140 {
141 QPainterPathStroker stroke;
142 stroke.setCapStyle(currItem->lineEnd());
143 stroke.setJoinStyle(currItem->lineJoin());
144 if (currItem->lineStyle() == Qt::SolidLine)
145 stroke.setDashPattern(currItem->lineStyle());
146 else
147 {
148 getDashArray(currItem->lineStyle(), 1, m_array);
149 stroke.setDashPattern(m_array);
150 }
151 stroke.setWidth(currItem->lineWidth());
152 QPainterPath result = stroke.createStroke(pp).simplified();
153 if (currItem->startArrowIndex() != 0)
154 {
155 FPoint Start = currItem->PoLine.point(0);
156 for (int xx = 1; xx < currItem->PoLine.size(); xx += 2)
157 {
158 FPoint Vector = currItem->PoLine.point(xx);
159 if ((Start.x() != Vector.x()) || (Start.y() != Vector.y()))
160 {
161 double r = atan2(Start.y()-Vector.y(),Start.x()-Vector.x())*(180.0/M_PI);
162 QTransform arrowTrans;
163 FPointArray arrow = currDoc->arrowStyles().at(currItem->startArrowIndex()-1).points.copy();
164 arrowTrans.translate(Start.x(), Start.y());
165 arrowTrans.rotate(r);
166 arrowTrans.scale(currItem->startArrowScale() / 100.0, currItem->startArrowScale() / 100.0);
167 arrowTrans.scale(currItem->lineWidth(), currItem->lineWidth());
168 arrow.map(arrowTrans);
169 result.addPath(arrow.toQPainterPath(true));
170 break;
171 }
172 }
173 }
174 if (currItem->endArrowIndex() != 0)
175 {
176 FPoint End = currItem->PoLine.point(currItem->PoLine.size()-2);
177 for (uint xx = currItem->PoLine.size()-1; xx > 0; xx -= 2)
178 {
179 FPoint Vector = currItem->PoLine.point(xx);
180 if ((End.x() != Vector.x()) || (End.y() != Vector.y()))
181 {
182 double r = atan2(End.y()-Vector.y(),End.x()-Vector.x())*(180.0/M_PI);
183 QTransform arrowTrans;
184 FPointArray arrow = currDoc->arrowStyles().at(currItem->endArrowIndex()-1).points.copy();
185 arrowTrans.translate(End.x(), End.y());
186 arrowTrans.rotate(r);
187 arrowTrans.scale(currItem->endArrowScale() / 100.0, currItem->endArrowScale() / 100.0);
188 arrowTrans.scale(currItem->lineWidth(), currItem->lineWidth());
189 arrow.map(arrowTrans);
190 result.addPath(arrow.toQPainterPath(true));
191 break;
192 }
193 }
194 }
195 currDoc->m_Selection->clear();
196 PageItem* newItem = currDoc->convertItemTo(currItem, PageItem::Polygon);
197 newItem->setLineWidth(0);
198 newItem->setLineStyle(Qt::SolidLine);
199 newItem->setFillColor(newItem->lineColor());
200 newItem->setFillShade(newItem->lineShade());
201 newItem->setFillTransparency(newItem->lineTransparency());
202 newItem->setFillBlendmode(newItem->lineBlendmode());
203 FPointArray points;
204 points.fromQPainterPath(result);
205 newItem->PoLine = points;
206 newItem->ClipEdited = true;
207 newItem->FrameType = 3;
208 currDoc->adjustItemSize(newItem);
209 newItem->OldB2 = newItem->width();
210 newItem->OldH2 = newItem->height();
211 newItem->updateClip();
212 newItem->ContourLine = newItem->PoLine.copy();
213 newItem->setFillEvenOdd(false);
214 currDoc->m_Selection->addItem(newItem);
215 }
216 else
217 {
218 currDoc->m_Selection->clear();
219 multiLine ml = currDoc->docLineStyles[currItem->NamedLStyle];
220 bool first = true;
221 for (int it = ml.size()-1; it > -1; it--)
222 {
223 if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
224 {
225 QPainterPathStroker stroke;
226 stroke.setCapStyle(static_cast<Qt::PenCapStyle>(ml[it].LineEnd));
227 stroke.setJoinStyle(static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
228 if (static_cast<Qt::PenStyle>(ml[it].Dash) == Qt::SolidLine)
229 stroke.setDashPattern(static_cast<Qt::PenStyle>(ml[it].Dash));
230 else
231 {
232 getDashArray(static_cast<Qt::PenStyle>(ml[it].Dash), 1, m_array);
233 stroke.setDashPattern(m_array);
234 }
235 stroke.setWidth(ml[it].Width);
236 QPainterPath result = stroke.createStroke(pp).simplified();
237 PageItem* newItem;
238 if (first)
239 {
240 newItem = currDoc->convertItemTo(currItem, PageItem::Polygon);
241 }
242 else
243 {
244 newItem = new PageItem_Polygon(*currItem);
245 newItem->convertTo(PageItem::Polygon);
246 currDoc->Items->append(newItem);
247 }
248 first = false;
249 newItem->setLineStyle(Qt::SolidLine);
250 newItem->setFillColor(ml[it].Color);
251 newItem->setFillShade(ml[it].Shade);
252 newItem->setFillTransparency(newItem->lineTransparency());
253 newItem->setFillBlendmode(newItem->lineBlendmode());
254 newItem->setLineColor(CommonStrings::None);
255 newItem->setCustomLineStyle("");
256 FPointArray points;
257 points.fromQPainterPath(result);
258 newItem->PoLine = points;
259 newItem->ClipEdited = true;
260 newItem->FrameType = 3;
261 currDoc->adjustItemSize(newItem);
262 newItem->OldB2 = newItem->width();
263 newItem->OldH2 = newItem->height();
264 newItem->updateClip();
265 newItem->ContourLine = newItem->PoLine.copy();
266 newItem->setFillEvenOdd(false);
267 currDoc->m_Selection->addItem(newItem);
268 }
269 }
270 if (currItem->startArrowIndex() != 0)
271 {
272 FPoint Start = currItem->PoLine.point(0);
273 for (int xx = 1; xx < currItem->PoLine.size(); xx += 2)
274 {
275 FPoint Vector = currItem->PoLine.point(xx);
276 if ((Start.x() != Vector.x()) || (Start.y() != Vector.y()))
277 {
278 double r = atan2(Start.y()-Vector.y(),Start.x()-Vector.x())*(180.0/M_PI);
279 QTransform arrowTrans;
280 FPointArray arrow = currDoc->arrowStyles().at(currItem->startArrowIndex()-1).points.copy();
281 arrowTrans.translate(Start.x(), Start.y());
282 arrowTrans.rotate(r);
283 arrowTrans.scale(currItem->startArrowScale() / 100.0, currItem->startArrowScale() / 100.0);
284 arrowTrans.scale(currItem->lineWidth(), currItem->lineWidth());
285 arrow.map(arrowTrans);
286 PageItem* newItem = new PageItem_Polygon(*currItem);
287 currDoc->Items->append(newItem);
288 newItem->setLineWidth(0);
289 newItem->setLineStyle(Qt::SolidLine);
290 newItem->setCustomLineStyle("");
291 newItem->setFillColor(newItem->lineColor());
292 newItem->setFillShade(newItem->lineShade());
293 newItem->setFillTransparency(newItem->lineTransparency());
294 newItem->setFillBlendmode(newItem->lineBlendmode());
295 newItem->PoLine = arrow;
296 newItem->ClipEdited = true;
297 newItem->FrameType = 3;
298 currDoc->adjustItemSize(newItem);
299 newItem->OldB2 = newItem->width();
300 newItem->OldH2 = newItem->height();
301 newItem->updateClip();
302 newItem->ContourLine = newItem->PoLine.copy();
303 newItem->setFillEvenOdd(true);
304 currDoc->m_Selection->addItem(newItem);
305 break;
306 }
307 }
308 }
309 if (currItem->endArrowIndex() != 0)
310 {
311 FPoint End = currItem->PoLine.point(currItem->PoLine.size()-2);
312 for (uint xx = currItem->PoLine.size()-1; xx > 0; xx -= 2)
313 {
314 FPoint Vector = currItem->PoLine.point(xx);
315 if ((End.x() != Vector.x()) || (End.y() != Vector.y()))
316 {
317 double r = atan2(End.y()-Vector.y(),End.x()-Vector.x())*(180.0/M_PI);
318 QTransform arrowTrans;
319 FPointArray arrow = currDoc->arrowStyles().at(currItem->endArrowIndex()-1).points.copy();
320 arrowTrans.translate(End.x(), End.y());
321 arrowTrans.rotate(r);
322 arrowTrans.scale(currItem->endArrowScale() / 100.0, currItem->endArrowScale() / 100.0);
323 arrowTrans.scale(currItem->lineWidth(), currItem->lineWidth());
324 arrow.map(arrowTrans);
325 PageItem* newItem = new PageItem_Polygon(*currItem);
326 currDoc->Items->append(newItem);
327 newItem->setLineWidth(0);
328 newItem->setLineStyle(Qt::SolidLine);
329 newItem->setCustomLineStyle("");
330 newItem->setFillColor(newItem->lineColor());
331 newItem->setFillShade(newItem->lineShade());
332 newItem->setFillTransparency(newItem->lineTransparency());
333 newItem->setFillBlendmode(newItem->lineBlendmode());
334 newItem->PoLine = arrow;
335 newItem->ClipEdited = true;
336 newItem->FrameType = 3;
337 currDoc->adjustItemSize(newItem);
338 newItem->OldB2 = newItem->width();
339 newItem->OldH2 = newItem->height();
340 newItem->updateClip();
341 newItem->ContourLine = newItem->PoLine.copy();
342 newItem->setFillEvenOdd(true);
343 currDoc->m_Selection->addItem(newItem);
344 break;
345 }
346 }
347 }
348 if (currDoc->m_Selection->count() > 1)
349 currDoc->itemSelection_GroupObjects(false, false);
350 currDoc->m_Selection->itemAt(0)->emitAllToGUI();
351 }
352 currDoc->changed();
353 }
354 return true;
355 }
356