108
void KarbonPencilTool::mousePressEvent( KoPointerEvent *event )
107
void KarbonPencilTool::mousePressEvent(KoPointerEvent *event)
112
110
m_shape = new KoPathShape();
113
m_shape->setShapeId( KoPathShapeId );
114
m_shape->setBorder( currentBorder() );
111
m_shape->setShapeId(KoPathShapeId);
112
m_shape->setBorder(currentBorder());
115
113
m_points.clear();
117
115
QPointF point = event->point;
118
116
m_existingStartPoint = endPointAtPosition(point);
119
117
if (m_existingStartPoint)
120
118
point = m_existingStartPoint->parent()->shapeToDocument(m_existingStartPoint->point());
126
void KarbonPencilTool::mouseMoveEvent( KoPointerEvent *event )
124
void KarbonPencilTool::mouseMoveEvent(KoPointerEvent *event)
128
if( event->buttons() & Qt::LeftButton )
129
addPoint( event->point );
126
if (event->buttons() & Qt::LeftButton)
127
addPoint(event->point);
131
129
KoPathPoint * endPoint = endPointAtPosition(event->point);
132
130
if (m_hoveredPoint != endPoint) {
133
131
if (m_hoveredPoint) {
134
132
QPointF nodePos = m_hoveredPoint->parent()->shapeToDocument(m_hoveredPoint->point());
135
m_canvas->updateCanvas(handlePaintRect(nodePos));
133
canvas()->updateCanvas(handlePaintRect(nodePos));
137
135
m_hoveredPoint = endPoint;
138
136
if (m_hoveredPoint) {
139
137
QPointF nodePos = m_hoveredPoint->parent()->shapeToDocument(m_hoveredPoint->point());
140
m_canvas->updateCanvas(handlePaintRect(nodePos));
138
canvas()->updateCanvas(handlePaintRect(nodePos));
145
void KarbonPencilTool::mouseReleaseEvent( KoPointerEvent *event )
143
void KarbonPencilTool::mouseReleaseEvent(KoPointerEvent *event)
150
148
QPointF point = event->point;
151
149
m_existingEndPoint = endPointAtPosition(point);
152
150
if (m_existingEndPoint)
153
151
point = m_existingEndPoint->parent()->shapeToDocument(m_existingEndPoint->point());
156
finish( event->modifiers() & Qt::ShiftModifier );
154
finish(event->modifiers() & Qt::ShiftModifier);
158
156
m_existingStartPoint = 0;
159
157
m_existingEndPoint = 0;
160
158
m_hoveredPoint = 0;
162
160
// the original path may be different from the one added
163
m_canvas->updateCanvas( m_shape->boundingRect() );
161
canvas()->updateCanvas(m_shape->boundingRect());
166
164
m_points.clear();
193
190
m_hoveredPoint = 0;
196
void KarbonPencilTool::addPoint( const QPointF & point )
193
void KarbonPencilTool::addPoint(const QPointF & point)
201
198
// do a moveTo for the first point added
202
if( m_points.empty() )
203
m_shape->moveTo( point );
199
if (m_points.empty())
200
m_shape->moveTo(point);
204
201
// do not allow coincident points
205
else if( point != m_points.last() )
206
m_shape->lineTo( point );
202
else if (point != m_points.last())
203
m_shape->lineTo(point);
210
m_points.append( point );
211
m_canvas->updateCanvas( m_shape->boundingRect() );
207
m_points.append(point);
208
canvas()->updateCanvas(m_shape->boundingRect());
214
qreal KarbonPencilTool::lineAngle( const QPointF &p1, const QPointF &p2 )
211
qreal KarbonPencilTool::lineAngle(const QPointF &p1, const QPointF &p2)
216
qreal angle = atan2( p2.y() - p1.y(), p2.x() - p1.x() );
213
qreal angle = atan2(p2.y() - p1.y(), p2.x() - p1.x());
220
217
return angle * 180.0 / M_PI;
223
void KarbonPencilTool::finish( bool closePath )
220
void KarbonPencilTool::finish(bool closePath)
225
if( m_points.count() < 2 )
222
if (m_points.count() < 2)
228
225
KoPathShape * path = 0;
229
226
QList<QPointF> complete;
230
227
QList<QPointF> *points = &m_points;
232
if( m_mode == ModeStraight || m_optimizeRaw || m_optimizeCurve )
229
if (m_mode == ModeStraight || m_optimizeRaw || m_optimizeCurve) {
234
230
float combineAngle;
236
if( m_mode == ModeStraight )
232
if (m_mode == ModeStraight)
237
233
combineAngle = m_combineAngle;
239
235
combineAngle = 0.50f;
241
237
//Add the first two points
242
complete.append( m_points[0] );
243
complete.append( m_points[1] );
238
complete.append(m_points[0]);
239
complete.append(m_points[1]);
245
241
//Now we need to get the angle of the first line
246
float lastAngle = lineAngle( complete[0], complete[1] );
242
float lastAngle = lineAngle(complete[0], complete[1]);
248
244
uint pointCount = m_points.count();
249
for( uint i = 2; i < pointCount; ++i )
251
float angle = lineAngle( complete.last(), m_points[i] );
252
if( qAbs( angle - lastAngle ) < combineAngle )
245
for (uint i = 2; i < pointCount; ++i) {
246
float angle = lineAngle(complete.last(), m_points[i]);
247
if (qAbs(angle - lastAngle) < combineAngle)
253
248
complete.removeLast();
254
complete.append( m_points[i] );
249
complete.append(m_points[i]);
255
250
lastAngle = angle;
326
314
QWidget * KarbonPencilTool::createOptionWidget()
328
316
QWidget *optionWidget = new QWidget();
329
QVBoxLayout * layout = new QVBoxLayout( optionWidget );
331
QHBoxLayout *modeLayout = new QHBoxLayout( optionWidget );
332
modeLayout->setSpacing( 3 );
333
QLabel *modeLabel = new QLabel( i18n( "Precision:" ), optionWidget );
334
KComboBox * modeBox = new KComboBox( optionWidget );
335
modeBox->addItem( i18nc( "The raw line data", "Raw" ) );
336
modeBox->addItem( i18n( "Curve" ) );
337
modeBox->addItem( i18n( "Straight" ) );
338
modeLayout->addWidget( modeLabel );
339
modeLayout->addWidget( modeBox, 1 );
340
layout->addLayout( modeLayout );
342
QStackedWidget * stackedWidget = new QStackedWidget( optionWidget );
344
QWidget * rawBox = new QWidget( stackedWidget );
345
QVBoxLayout * rawLayout = new QVBoxLayout( rawBox );
346
QCheckBox * optimizeRaw = new QCheckBox( i18n( "Optimize" ), rawBox );
347
rawLayout->addWidget( optimizeRaw );
348
rawLayout->setContentsMargins( 0, 0, 0, 0 );
350
QWidget * curveBox = new QWidget( stackedWidget );
351
QHBoxLayout * curveLayout = new QHBoxLayout( curveBox );
352
QCheckBox * optimizeCurve = new QCheckBox( i18n( "Optimize" ), curveBox );
353
KDoubleNumInput * fittingError = new KDoubleNumInput( 0.0, 400.0, m_fittingError, curveBox, 0.50, 3 );
354
fittingError->setToolTip( i18n( "Exactness:" ) );
355
curveLayout->addWidget( optimizeCurve );
356
curveLayout->addWidget( fittingError );
357
curveLayout->setContentsMargins( 0, 0, 0, 0 );
359
QWidget * straightBox = new QWidget( stackedWidget );
360
QVBoxLayout * straightLayout = new QVBoxLayout( straightBox );
361
KDoubleNumInput * combineAngle = new KDoubleNumInput( 0.0, 360.0, m_combineAngle, straightBox, 0.50, 3 );
362
combineAngle->setSuffix( " deg" );
363
combineAngle->setLabel( i18n( "Combine angle:" ), Qt::AlignLeft|Qt::AlignVCenter );
364
straightLayout->addWidget( combineAngle );
365
straightLayout->setContentsMargins( 0, 0, 0, 0 );
367
stackedWidget->addWidget( rawBox );
368
stackedWidget->addWidget( curveBox );
369
stackedWidget->addWidget( straightBox );
370
layout->addWidget( stackedWidget, 1 );
371
layout->addStretch( 1 );
373
connect( modeBox, SIGNAL(activated(int)), stackedWidget, SLOT(setCurrentIndex(int)));
374
connect( modeBox, SIGNAL(activated(int)), this, SLOT(selectMode(int)));
375
connect( optimizeRaw, SIGNAL(stateChanged(int)), this, SLOT(setOptimize(int)));
376
connect( optimizeCurve, SIGNAL(stateChanged(int)), this, SLOT(setOptimize(int)));
377
connect( fittingError, SIGNAL(valueChanged(double)), this, SLOT(setDelta(double)));
378
connect( combineAngle, SIGNAL(valueChanged(double)), this, SLOT(setDelta(double)));
380
modeBox->setCurrentIndex( m_mode );
381
stackedWidget->setCurrentIndex( m_mode );
317
QVBoxLayout * layout = new QVBoxLayout(optionWidget);
319
QHBoxLayout *modeLayout = new QHBoxLayout(optionWidget);
320
modeLayout->setSpacing(3);
321
QLabel *modeLabel = new QLabel(i18n("Precision:"), optionWidget);
322
KComboBox * modeBox = new KComboBox(optionWidget);
323
modeBox->addItem(i18nc("The raw line data", "Raw"));
324
modeBox->addItem(i18n("Curve"));
325
modeBox->addItem(i18n("Straight"));
326
modeLayout->addWidget(modeLabel);
327
modeLayout->addWidget(modeBox, 1);
328
layout->addLayout(modeLayout);
330
QStackedWidget * stackedWidget = new QStackedWidget(optionWidget);
332
QWidget * rawBox = new QWidget(stackedWidget);
333
QVBoxLayout * rawLayout = new QVBoxLayout(rawBox);
334
QCheckBox * optimizeRaw = new QCheckBox(i18n("Optimize"), rawBox);
335
rawLayout->addWidget(optimizeRaw);
336
rawLayout->setContentsMargins(0, 0, 0, 0);
338
QWidget * curveBox = new QWidget(stackedWidget);
339
QHBoxLayout * curveLayout = new QHBoxLayout(curveBox);
340
QCheckBox * optimizeCurve = new QCheckBox(i18n("Optimize"), curveBox);
341
KDoubleNumInput * fittingError = new KDoubleNumInput(0.0, 400.0, m_fittingError, curveBox, 0.50, 3);
342
fittingError->setToolTip(i18n("Exactness:"));
343
curveLayout->addWidget(optimizeCurve);
344
curveLayout->addWidget(fittingError);
345
curveLayout->setContentsMargins(0, 0, 0, 0);
347
QWidget * straightBox = new QWidget(stackedWidget);
348
QVBoxLayout * straightLayout = new QVBoxLayout(straightBox);
349
KDoubleNumInput * combineAngle = new KDoubleNumInput(0.0, 360.0, m_combineAngle, straightBox, 0.50, 3);
350
combineAngle->setSuffix(" deg");
351
combineAngle->setLabel(i18n("Combine angle:"), Qt::AlignLeft | Qt::AlignVCenter);
352
straightLayout->addWidget(combineAngle);
353
straightLayout->setContentsMargins(0, 0, 0, 0);
355
stackedWidget->addWidget(rawBox);
356
stackedWidget->addWidget(curveBox);
357
stackedWidget->addWidget(straightBox);
358
layout->addWidget(stackedWidget, 1);
359
layout->addStretch(1);
361
connect(modeBox, SIGNAL(activated(int)), stackedWidget, SLOT(setCurrentIndex(int)));
362
connect(modeBox, SIGNAL(activated(int)), this, SLOT(selectMode(int)));
363
connect(optimizeRaw, SIGNAL(stateChanged(int)), this, SLOT(setOptimize(int)));
364
connect(optimizeCurve, SIGNAL(stateChanged(int)), this, SLOT(setOptimize(int)));
365
connect(fittingError, SIGNAL(valueChanged(double)), this, SLOT(setDelta(double)));
366
connect(combineAngle, SIGNAL(valueChanged(double)), this, SLOT(setDelta(double)));
368
modeBox->setCurrentIndex(m_mode);
369
stackedWidget->setCurrentIndex(m_mode);
383
371
return optionWidget;
386
void KarbonPencilTool::selectMode( int mode )
374
void KarbonPencilTool::selectMode(int mode)
388
m_mode = static_cast<PencilMode>( mode );
376
m_mode = static_cast<PencilMode>(mode);
391
void KarbonPencilTool::setOptimize( int state )
379
void KarbonPencilTool::setOptimize(int state)
393
if( m_mode == ModeRaw )
381
if (m_mode == ModeRaw)
394
382
m_optimizeRaw = state == Qt::Checked ? true : false;
396
384
m_optimizeCurve = state == Qt::Checked ? true : false;
399
void KarbonPencilTool::setDelta( double delta )
387
void KarbonPencilTool::setDelta(double delta)
401
if( m_mode == ModeCurve )
389
if (m_mode == ModeCurve)
402
390
m_fittingError = delta;
403
else if( m_mode == ModeStraight )
391
else if (m_mode == ModeStraight)
404
392
m_combineAngle = delta;
407
395
KoLineBorder * KarbonPencilTool::currentBorder()
409
KoLineBorder * border = new KoLineBorder( m_canvas->resourceProvider()->activeBorder() );
410
border->setColor( m_canvas->resourceProvider()->foregroundColor().toQColor() );
397
KoLineBorder * border = new KoLineBorder(canvas()->resourceManager()->activeBorder());
398
border->setColor(canvas()->resourceManager()->foregroundColor().toQColor());
414
KoPathPoint* KarbonPencilTool::endPointAtPosition( const QPointF &position )
402
KoPathPoint* KarbonPencilTool::endPointAtPosition(const QPointF &position)
416
404
QRectF roi = handleGrabRect(position);
417
QList<KoShape *> shapes = m_canvas->shapeManager()->shapesAt(roi);
405
QList<KoShape *> shapes = canvas()->shapeManager()->shapesAt(roi);
419
407
KoPathPoint * nearestPoint = 0;
420
408
qreal minDistance = HUGE_VAL;
421
uint grabSensitivity = m_canvas->resourceProvider()->grabSensitivity();
422
qreal maxDistance = m_canvas->viewConverter()->viewToDocumentX(grabSensitivity);
409
uint grabSensitivity = canvas()->resourceManager()->grabSensitivity();
410
qreal maxDistance = canvas()->viewConverter()->viewToDocumentX(grabSensitivity);
424
412
foreach(KoShape *shape, shapes) {
425
413
KoPathShape * path = dynamic_cast<KoPathShape*>(shape);
462
450
// do not allow connecting to the same point twice
463
451
if (pointAtStart == pointAtEnd)
466
454
// we have hit an existing path point on start/finish
467
455
// what we now do is:
468
456
// 1. combine the new created path with the ones we hit on start/finish
469
457
// 2. merge the endpoints of the corresponding subpaths
471
uint newPointCount = pathShape->pointCountSubpath(0);
459
uint newPointCount = pathShape->subpathPointCount(0);
472
460
KoPathPointIndex newStartPointIndex(0, 0);
473
KoPathPointIndex newEndPointIndex(0, newPointCount-1);
461
KoPathPointIndex newEndPointIndex(0, newPointCount - 1);
474
462
KoPathPoint * newStartPoint = pathShape->pointByIndex(newStartPointIndex);
475
463
KoPathPoint * newEndPoint = pathShape->pointByIndex(newEndPointIndex);
477
465
KoPathShape * startShape = pointAtStart ? pointAtStart->parent() : 0;
478
466
KoPathShape * endShape = pointAtEnd ? pointAtEnd->parent() : 0;
480
468
// combine with the path we hit on start
481
KoPathPointIndex startIndex(-1,-1);
469
KoPathPointIndex startIndex(-1, -1);
482
470
if (pointAtStart) {
483
471
startIndex = startShape->pathPointIndex(pointAtStart);
484
472
pathShape->combine(startShape);
485
pathShape->moveSubpath(0, pathShape->subpathCount()-1);
473
pathShape->moveSubpath(0, pathShape->subpathCount() - 1);
487
475
// combine with the path we hit on finish
488
KoPathPointIndex endIndex(-1,-1);
476
KoPathPointIndex endIndex(-1, -1);
489
477
if (pointAtEnd) {
490
478
endIndex = endShape->pathPointIndex(pointAtEnd);
491
479
if (endShape != startShape) {