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.
7
/**************************************************************************
8
* Copyright (C) 2008 by Franz Schmid *
9
* franz.schmid@altmuehlnet.de *
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. *
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. *
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
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25
***************************************************************************/
27
#include "meshdistortiondialog.h"
29
#include <QPainterPath>
30
#include <QGraphicsItem>
32
#include "commonstrings.h"
33
#include "fpointarray.h"
35
#include "sccolorengine.h"
36
#include "scpattern.h"
37
#include "selection.h"
38
#include "util_icon.h"
39
//#include "util_math.h"
41
NodeItem::NodeItem(QRectF geom, uint num, MeshDistortionDialog *parent) : QGraphicsEllipseItem(geom)
45
setBrush(Qt::NoBrush);
46
setPen(QPen(Qt::red, 2.0));
47
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
49
setAcceptsHoverEvents(true);
54
void NodeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
57
if (option->state & QStyle::State_Selected)
59
painter->setBrush(Qt::red);
60
painter->setPen(QPen(Qt::red, qMax(0.1, 1.0 / option->levelOfDetail)));
64
painter->setBrush(Qt::NoBrush);
65
painter->setPen(QPen(Qt::red, qMax(0.2, 2.0 / option->levelOfDetail)));
67
painter->drawEllipse(rect());
70
void NodeItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
74
QGraphicsItem::mousePressEvent(event);
77
void NodeItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
80
if ((mouseMoving) && (mousePressed))
81
dialog->updateMesh(true);
82
QGraphicsItem::mouseMoveEvent(event);
85
void NodeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
87
if ((mouseMoving) && (mousePressed))
88
dialog->updateMesh(false);
91
QGraphicsItem::mouseReleaseEvent(event);
94
void NodeItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
99
qApp->changeOverrideCursor(QCursor(Qt::SizeAllCursor));
101
qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
104
void NodeItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
107
p.addEllipse(rect());
109
qApp->changeOverrideCursor(QCursor(Qt::SizeAllCursor));
111
qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
114
void NodeItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
116
qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
119
MeshDistortionDialog::MeshDistortionDialog(QWidget* parent, ScribusDoc *doc) : QDialog(parent)
123
setWindowIcon(QIcon(loadIcon("AppIcon.png")));
124
buttonZoomOut->setIcon(QIcon(loadIcon("16/zoom-out.png")));
125
buttonZoomIn->setIcon(QIcon(loadIcon("16/zoom-in.png")));
128
double gx, gy, gh, gw;
129
doc->m_Selection->setGroupRect();
130
doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
131
uint selectedItemCount = doc->m_Selection->count();
132
w4 = qMax(gw, gh) / 2.0;
134
ww = qMax(gw, gh) * 2.0;
135
QStack<PageItem*> groupStack;
136
QStack<QGraphicsPathItem*> groupStack2;
137
QStack<PageItem*> groupStack3;
139
for (uint i = 0; i < selectedItemCount; ++i)
141
currItem = doc->m_Selection->itemAt(i);
142
FPointArray path = currItem->PoLine;
143
deltaX = ((w2 - gw) / 2.0) + w4;
144
deltaY = ((w2 - gh) / 2.0) + w4;
146
if (currItem->itemType() == PageItem::PolyLine)
147
pp = path.toQPainterPath(false);
149
pp = path.toQPainterPath(true);
150
QGraphicsPathItem* pItem = new QGraphicsPathItem(pp, groupStack2.top());
151
if (groupStack2.top() == 0)
153
scene.addItem(pItem);
154
pItem->setPos(currItem->xPos() - gx + deltaX, currItem->yPos() - gy + deltaY);
155
pItem->rotate(currItem->rotation());
159
PageItem* parent = groupStack3.top();
161
mm.rotate(-parent->rotation());
162
mm.translate(-parent->xPos(), -parent->yPos());
163
pItem->setPos(mm.map(QPointF(currItem->xPos(), currItem->yPos())));
165
QPainterPath pathO = pp;
167
mmO.translate(-w4, -w4);
168
pathO = pItem->mapToScene(pathO);
169
pathO = mmO.map(pathO);
170
Geom::Piecewise<D2<Geom::SBasis> > path_a_pw;
171
if (currItem->itemType() == PageItem::PolyLine)
172
path_a_pw = QPainterPath2Piecewise(pathO, false);
174
path_a_pw = QPainterPath2Piecewise(pathO, true);
175
origPath.append(path_a_pw);
177
origPathItem.append(pItem);
178
if (((currItem->fillColor() == CommonStrings::None) && (currItem->GrType == 0)) || (currItem->controlsGroup()))
179
pItem->setBrush(Qt::NoBrush);
182
if (currItem->GrType != 0)
184
if (currItem->GrType != 8)
187
double x1 = currItem->GrStartX;
188
double y1 = currItem->GrStartY;
189
double x2 = currItem->GrEndX;
190
double y2 = currItem->GrEndY;
191
switch (currItem->GrType)
198
pat = QLinearGradient(x1, y1, x2, y2);
202
pat = QRadialGradient(x1, y1, sqrt(pow(x2 - x1, 2) + pow(y2 - y1,2)), x1, y1);
205
QList<VColorStop*> colorStops = currItem->fill_gradient.colorStops();
207
for( int offset = 0 ; offset < colorStops.count() ; offset++ )
209
qStopColor = colorStops[ offset ]->color;
210
int h, s, v, sneu, vneu;
211
int shad = colorStops[offset]->shade;
212
qStopColor.getHsv(&h, &s, &v);
213
sneu = s * shad / 100;
214
vneu = 255 - ((255 - v) * shad / 100);
215
qStopColor.setHsv(h, sneu, vneu);
216
qStopColor.setAlphaF(colorStops[offset]->opacity);
217
pat.setColorAt(colorStops[ offset ]->rampPoint, qStopColor);
219
pItem->setBrush(pat);
221
else if ((currItem->GrType == 8) && (!currItem->pattern().isEmpty()) && (doc->docPatterns.contains(currItem->pattern())))
223
double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation;
224
currItem->patternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation);
226
qmatrix.translate(patternOffsetX, patternOffsetY);
227
qmatrix.rotate(patternRotation);
228
qmatrix.scale(patternScaleX / 100.0, patternScaleY / 100.0);
229
QImage pat = *doc->docPatterns[currItem->pattern()].getPattern();
230
QBrush brush = QBrush(pat);
231
brush.setMatrix(qmatrix);
232
pItem->setBrush(brush);
237
QColor paint = ScColorEngine::getShadeColorProof(doc->PageColors[currItem->fillColor()], doc, currItem->fillShade());
238
paint.setAlphaF(1.0 - currItem->fillTransparency());
239
pItem->setBrush(paint);
242
if ((currItem->lineColor() == CommonStrings::None) || (currItem->controlsGroup()))
243
pItem->setPen(Qt::NoPen);
246
QColor paint = ScColorEngine::getShadeColorProof(doc->PageColors[currItem->lineColor()], doc, currItem->lineShade());
247
paint.setAlphaF(1.0 - currItem->lineTransparency());
248
pItem->setPen(QPen(paint, currItem->lineWidth(), currItem->lineStyle(), currItem->lineEnd(), currItem->lineJoin()));
250
if (currItem->controlsGroup())
252
groupStack.push(currItem->groupsLastItem);
253
groupStack2.push(pItem);
254
groupStack3.push(currItem);
255
pItem->setFlags(QGraphicsItem::ItemClipsChildrenToShape);
257
if (groupStack.count() != 0)
259
while (currItem == groupStack.top())
264
if (groupStack.count() == 0)
269
for(unsigned dim = 0; dim < 2; dim++)
273
const int depth = sb2[dim].us*sb2[dim].vs;
274
sb2[dim].resize(depth, Linear2d(0));
276
handles.resize(sb2[0].vs*sb2[0].us*4);
277
origHandles.resize(sb2[0].vs*sb2[0].us*4);
279
for(unsigned vi = 0; vi < sb2[0].vs; vi++)
281
for(unsigned ui = 0; ui < sb2[0].us; ui++)
283
for(unsigned iv = 0; iv < 2; iv++)
285
for(unsigned iu = 0; iu < 2; iu++)
287
handles[ii++] = Geom::Point((2*(iu+ui)/(2.*ui+1)+1)*w4, (2*(iv+vi)/(2.*vi+1)+1)*w4);
292
Geom::Point dir(1,-2);
293
for(unsigned dim = 0; dim < 2; dim++)
295
Geom::Point dir(0,0);
297
for(unsigned vi = 0; vi < sb2[dim].vs; vi++)
299
for(unsigned ui = 0; ui < sb2[dim].us; ui++)
301
for(unsigned iv = 0; iv < 2; iv++)
303
for(unsigned iu = 0; iu < 2; iu++)
305
unsigned corner = iu + 2*iv;
306
unsigned i = ui + vi*sb2[dim].us;
307
Geom::Point base((2*(iu+ui)/(2.*ui+1)+1)*w4, (2*(iv+vi)/(2.*vi+1)+1)*w4);
308
if(vi == 0 && ui == 0)
309
base = Geom::Point(w4, w4);
310
double dl = dot((handles[corner+4*i] - base), dir)/dot(dir,dir);
311
sb2[dim][i][corner] = dl/(ww/2.0)*pow(4.0f,((int)(ui+vi)));
318
D2sb2d2QPainterPath(&pathG, sb2, 9, ww);
319
pItemG = new QGraphicsPathItem(pathG);
320
pItemG->setPen(QPen(Qt::black));
321
pItemG->setBrush(Qt::NoBrush);
322
pItemG->setZValue(8888888);
323
scene.addItem(pItemG);
324
for(unsigned i = 0; i < handles.size(); i++)
326
origHandles[i] = handles[i];
327
double x = handles[i][Geom::X];
328
double y = handles[i][Geom::Y];
329
NodeItem* pItemN = new NodeItem(QRectF(x-4.0, y-4.0, 8.0, 8.0), i, this);
330
scene.addItem(pItemN);
331
nodeItems.append(pItemN);
333
previewLabel->setRenderHint(QPainter::Antialiasing);
334
previewLabel->setScene(&scene);
336
connect(buttonZoomIn, SIGNAL(clicked()), this, SLOT(doZoomIn()));
337
connect(buttonZoomOut, SIGNAL(clicked()), this, SLOT(doZoomOut()));
338
connect(resetButton, SIGNAL(clicked()), this, SLOT(doReset()));
341
void MeshDistortionDialog::showEvent(QShowEvent *e)
343
QDialog::showEvent(e);
346
QRectF scR = scene.itemsBoundingRect().adjusted(-50, -50, 50, 50);
347
previewLabel->fitInView(scR, Qt::KeepAspectRatio);
348
scene.setSceneRect(scR);
354
void MeshDistortionDialog::doZoomIn()
356
previewLabel->scale(2.0, 2.0);
360
void MeshDistortionDialog::doZoomOut()
362
previewLabel->scale(0.5, 0.5);
366
void MeshDistortionDialog::doReset()
369
for(int n = 0; n < nodeItems.count(); n++)
371
if (nodeItems.at(n)->isSelected())
374
handles[nodeItems.at(n)->handle] = origHandles[nodeItems.at(n)->handle];
379
for(unsigned i = 0; i < handles.size(); i++)
381
handles[i] = origHandles[i];
388
void MeshDistortionDialog::adjustHandles()
390
double sc = previewLabel->matrix().m11();
391
for(int n = 0; n < nodeItems.count(); n++)
393
double x = handles[n][Geom::X];
394
double y = handles[n][Geom::Y];
395
QPointF mm = nodeItems.at(n)->mapFromScene(QPointF(x - 4.0 / sc, y - 4.0 / sc));
396
nodeItems.at(n)->setRect(QRectF(mm.x(), mm.y(), 8.0 / sc, 8.0 / sc));
400
void MeshDistortionDialog::updateMesh(bool gridOnly)
402
for(int n = 0; n < nodeItems.count(); n++)
404
QPointF mm = nodeItems.at(n)->mapToScene(nodeItems.at(n)->rect().center());
405
Geom::Point mouse(mm.x(), mm.y());
408
Geom::Point dir(1,-2);
409
for(unsigned dim = 0; dim < 2; dim++)
411
Geom::Point dir(0,0);
413
for(unsigned vi = 0; vi < sb2[dim].vs; vi++)
415
for(unsigned ui = 0; ui < sb2[dim].us; ui++)
417
for(unsigned iv = 0; iv < 2; iv++)
419
for(unsigned iu = 0; iu < 2; iu++)
421
unsigned corner = iu + 2*iv;
422
unsigned i = ui + vi*sb2[dim].us;
423
Geom::Point base((2*(iu+ui)/(2.*ui+1)+1)*w4, (2*(iv+vi)/(2.*vi+1)+1)*w4);
424
if(vi == 0 && ui == 0)
425
base = Geom::Point(w4, w4);
426
double dl = dot((handles[corner+4*i] - base), dir)/dot(dir,dir);
427
sb2[dim][i][corner] = dl/(ww/2.0)*pow(4.0f,((int)(ui+vi)));
433
if ((!gridOnly) || (origPathItem.count() < 20))
435
if (origPathItem.count() > 19)
436
qApp->changeOverrideCursor(QCursor(Qt::WaitCursor));
437
for (int a = 0; a < origPathItem.count(); a++)
439
QGraphicsPathItem* pItem = origPathItem[a];
440
Geom::Piecewise<D2<Geom::SBasis> > path_a_pw = origPath[a];
441
Piecewise<D2<SBasis> > output;
442
for(unsigned i = 0; i < path_a_pw.size(); i++)
444
D2<SBasis> B = path_a_pw[i];
446
D2<SBasis> tB = compose_each(sb2, B);
447
B = B*(ww/2.0) + Geom::Point(w4, w4);
448
tB = tB*(ww/2.0) + Geom::Point(w4, w4);
449
output.concat(Piecewise<D2<SBasis> >(tB));
452
Piecewise2QPainterPath(&pathP, output);
453
pathP = pItem->mapFromScene(pathP);
454
pItem->setPath(pathP);
456
if (origPathItem.count() > 19)
457
qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
460
D2sb2d2QPainterPath(&pathG, sb2, 9, ww);
461
pItemG->setPath(pathG);
464
void MeshDistortionDialog::updateAndExit()
466
qApp->changeOverrideCursor(QCursor(Qt::WaitCursor));
467
for (int a = 0; a < origPathItem.count(); a++)
469
Geom::Piecewise<D2<Geom::SBasis> > path_a_pw;
470
QGraphicsPathItem* pItem = origPathItem[a];
471
QPainterPath path = pItem->path();
472
FPointArray outputPath;
473
outputPath.fromQPainterPath(path);
474
PageItem *currItem = m_doc->m_Selection->itemAt(a);
475
currItem->PoLine = outputPath;
476
currItem->Frame = false;
477
currItem->ClipEdited = true;
478
currItem->FrameType = 3;
479
m_doc->AdjustItemSize(currItem);
480
currItem->OldB2 = currItem->width();
481
currItem->OldH2 = currItem->height();
482
currItem->updateClip();
483
currItem->ContourLine = currItem->PoLine.copy();
485
qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));