00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <math.h>
00021
00022 #include <qcursor.h>
00023 #include <qevent.h>
00024 #include <qlabel.h>
00025 #include <qgroupbox.h>
00026 #include <qcombobox.h>
00027 #include <qcheckbox.h>
00028 #include <qvbox.h>
00029 #include <qwidgetstack.h>
00030
00031 #include <klocale.h>
00032 #include <knuminput.h>
00033
00034
00035 #include <karbon_part.h>
00036 #include <karbon_view.h>
00037
00038 #include <core/vcolor.h>
00039 #include <core/vcomposite.h>
00040 #include <core/vfill.h>
00041 #include <core/vstroke.h>
00042 #include <core/vglobal.h>
00043 #include <core/vselection.h>
00044 #include <core/vcursor.h>
00045 #include <render/vpainter.h>
00046 #include <render/vpainterfactory.h>
00047 #include "vpenciltool.h"
00048 #include <commands/vshapecmd.h>
00049
00050 #include "vcurvefit.h"
00051
00052 #include "vpenciltool.moc"
00053
00054 VPencilOptionsWidget::VPencilOptionsWidget( KarbonView*view, QWidget* parent, const char* name )
00055 : KDialogBase( parent, name, true, i18n( "Pencil Settings" ), Ok | Cancel ), m_view( view )
00056 {
00057 QVBox *vbox = new QVBox( this );
00058
00059 m_combo = new QComboBox( vbox );
00060
00061 m_combo->insertItem( i18n( "Raw" ) );
00062 m_combo->insertItem( i18n( "Curve" ) );
00063 m_combo->insertItem( i18n( "Straight" ) );
00064
00065 m_widgetStack = new QWidgetStack( vbox );
00066
00067 QGroupBox *group1 = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), m_widgetStack );
00068 m_widgetStack->addWidget( group1, 1 );
00069 m_optimizeRaw = new QCheckBox( i18n( "Optimize" ), group1 );
00070
00071 group1->setInsideMargin( 4 );
00072 group1->setInsideSpacing( 2 );
00073
00074 QGroupBox *group2 = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), m_widgetStack );
00075 m_widgetStack->addWidget( group2, 2 );
00076
00077 QVBox *vbox2 = new QVBox( group2 );
00078
00079 m_optimizeCurve = new QCheckBox( i18n( "Optimize" ), vbox2 );
00080 m_fittingError = new KDoubleNumInput( 0.0, 400.0, 4.00, 0.50, 3, vbox2 );
00081 m_fittingError->setLabel( i18n( "Exactness:" ) );
00082
00083 group2->setInsideMargin( 4 );
00084 group2->setInsideSpacing( 2 );
00085
00086 QGroupBox *group3 = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), m_widgetStack );
00087 m_widgetStack->addWidget( group3, 3 );
00088
00089 m_combineAngle = new KDoubleNumInput( 0.0, 360.0, 0.10, 0.50, 3, group3 );
00090 m_combineAngle->setSuffix( " deg" );
00091 m_combineAngle->setLabel( i18n( "Combine angle:" ) );
00092
00093 group3->setInsideMargin( 4 );
00094 group3->setInsideSpacing( 2 );
00095
00096 connect( m_combo, SIGNAL( activated( int ) ), this, SLOT( selectMode() ) );
00097
00098
00099 m_mode = VPencilTool::CURVE;
00100 selectMode();
00101
00102 m_optimizeCurve->setChecked( true );
00103 m_optimizeRaw->setChecked( true );
00104
00105 setMainWidget( vbox );
00106 }
00107
00108 float VPencilOptionsWidget::combineAngle()
00109 {
00110 return m_combineAngle->value();
00111 }
00112
00113 bool VPencilOptionsWidget::optimize()
00114 {
00115 return ( m_optimizeRaw->isChecked() || m_optimizeCurve->isChecked() );
00116 }
00117
00118 float VPencilOptionsWidget::fittingError()
00119 {
00120 return m_fittingError->value();
00121 }
00122
00123 void VPencilOptionsWidget::selectMode()
00124 {
00125 m_widgetStack->raiseWidget( m_combo->currentItem() + 1 );
00126
00127 switch( m_combo->currentItem() )
00128 {
00129 case 0: m_mode = VPencilTool::RAW; break;
00130 case 1: m_mode = VPencilTool::CURVE; break;
00131 case 2: m_mode = VPencilTool::STRAIGHT; break;
00132 }
00133 }
00134
00135 int VPencilOptionsWidget::currentMode(){
00136 return m_mode;
00137 }
00138
00139
00140
00141 VPencilTool::VPencilTool( KarbonView *view )
00142 : VTool( view, "tool_pencil" )
00143 {
00144 m_Points.setAutoDelete( true );
00145 m_optionWidget = new VPencilOptionsWidget( view );
00146 registerTool( this );
00147 m_mode = CURVE;
00148 m_optimize = true;
00149 m_combineAngle = 3.0f;
00150 m_cursor = new QCursor( VCursor::createCursor( VCursor::CrossHair ) );
00151 }
00152
00153 VPencilTool::~VPencilTool()
00154 {
00155 delete m_cursor;
00156 }
00157
00158 QString
00159 VPencilTool::contextHelp()
00160 {
00161 QString s = i18n( "<qt><b>Pencil tool:</b><br>" );
00162 s += i18n( "- <i>Click</i> to begin drawing, release when you have finished.");
00163 s += i18n( "- Press <i>Enter</i> or <i>double click</i> to end the polyline.</qt>" );
00164
00165 return s;
00166 }
00167
00168 void
00169 VPencilTool::activate()
00170 {
00171 VTool::activate();
00172 view()->statusMessage()->setText( i18n( "Pencil Tool" ) );
00173 view()->setCursor( *m_cursor );
00174 view()->part()->document().selection()->showHandle( false );
00175
00176 m_Points.clear();
00177 m_close = false;
00178 }
00179
00180 void
00181 VPencilTool::deactivate()
00182 {
00183 m_Points.removeLast();
00184 m_Points.removeLast();
00185
00186 VPath* line = 0L;
00187
00188 QPtrList<KoPoint> complete;
00189 QPtrList<KoPoint> *points = &m_Points;
00190
00191 if( m_Points.count() > 1 )
00192 {
00193 if( m_optimize || m_mode == STRAIGHT )
00194 {
00195 complete.setAutoDelete( true );
00196 m_Points.setAutoDelete( false );
00197
00198 float cangle;
00199
00200 if( m_mode == STRAIGHT )
00201 cangle = m_combineAngle;
00202 else
00203 cangle = 0.50f;
00204
00205 #define ANGLE(P0,P1)\
00206 atan((P1)->y()-(P0)->y())/((P1)->x()-(P0)->x())*(180/M_PI)
00207
00208
00209 complete.append( m_Points.first() );
00210 complete.append( m_Points.next() );
00211
00212
00213 float langle = ANGLE( complete.at( 0 ), complete.at( 1 ) );
00214
00215 KoPoint *nextp = NULL;
00216 while( ( nextp = m_Points.next() ) )
00217 {
00218 float angle = ANGLE( complete.last(), nextp );
00219 if( QABS( angle - langle ) < cangle )
00220 complete.removeLast();
00221 complete.append(nextp);
00222 langle=angle;
00223 }
00224 m_Points.clear();
00225 m_Points.setAutoDelete(true);
00226
00227 points = &complete;
00228 }
00229
00230 switch(m_mode)
00231 {
00232 case CURVE:
00233 {
00234 line = bezierFit( *points, m_optionWidget->fittingError() );
00235 break;
00236 }
00237 case STRAIGHT:
00238 case RAW:
00239 {
00240 line = new VPath( 0L );
00241 KoPoint* p1 = (*points).first();
00242 KoPoint* plast = p1;
00243 line->moveTo( *p1 );
00244
00245 KoPoint* pnext = 0L;
00246
00247 while( ( pnext = (*points).next() ) )
00248 {
00249 line->lineTo( *pnext );
00250 plast = pnext;
00251 }
00252 break;
00253 }
00254 }
00255
00256 if( shiftPressed() )
00257 line->close();
00258 }
00259
00260 if( line )
00261 {
00262 VShapeCmd* cmd = new VShapeCmd(
00263 &view()->part()->document(),
00264 i18n( "Pencil" ),
00265 line,
00266 "14_pencil" );
00267
00268 view()->part()->addCommand( cmd, true );
00269 }
00270 }
00271
00272 void
00273 VPencilTool::draw()
00274 {
00275 VPainter* painter = view()->painterFactory()->editpainter();
00276 painter->setRasterOp( Qt::NotROP );
00277
00278 m_mode = m_optionWidget->currentMode();
00279 m_optimize = m_optionWidget->optimize();
00280 m_combineAngle = m_optionWidget->combineAngle();
00281
00282 if( m_Points.count() > 1 )
00283 {
00284 VPath line( 0L );
00285 line.moveTo( *m_Points.first() );
00286
00287 KoPoint *pnext;
00288 while((pnext=m_Points.next())){
00289 line.lineTo( *pnext );
00290 }
00291
00292 line.setState( VObject::edit );
00293 line.draw( painter, &line.boundingBox() );
00294 }
00295
00296 }
00297
00298
00299 void
00300 VPencilTool::mouseMove()
00301 {
00302 }
00303
00304 void
00305 VPencilTool::mouseButtonPress()
00306 {
00307 m_Points.append( new KoPoint( last() ) );
00308
00309 draw();
00310 }
00311
00312 void
00313 VPencilTool::mouseButtonRelease()
00314 {
00315 m_Points.append( new KoPoint( last() ) );
00316 draw();
00317 accept();
00318 return;
00319 }
00320
00321 void
00322 VPencilTool::mouseButtonDblClick()
00323 {
00324 accept();
00325 }
00326
00327 void
00328 VPencilTool::mouseDrag()
00329 {
00330 if( m_Points.count() != 0 )
00331 {
00332 draw();
00333
00334 m_Points.append( new KoPoint( last() ) );
00335
00336 draw();
00337 }
00338 }
00339
00340 void
00341 VPencilTool::mouseDragRelease()
00342 {
00343 mouseButtonRelease();
00344 }
00345
00346 void
00347 VPencilTool::mouseDragShiftPressed()
00348 {
00349 }
00350
00351 void
00352 VPencilTool::mouseDragCtrlPressed()
00353 {
00354
00355 }
00356
00357 void
00358 VPencilTool::mouseDragShiftReleased()
00359 {
00360 }
00361
00362 void
00363 VPencilTool::mouseDragCtrlReleased()
00364 {
00365 }
00366
00367 void
00368 VPencilTool::cancel()
00369 {
00370 draw();
00371
00372 m_Points.clear();
00373 }
00374
00375 void
00376 VPencilTool::cancelStep()
00377 {
00378 draw();
00379
00380 m_Points.clear();
00381
00382 draw();
00383 }
00384
00385 void
00386 VPencilTool::accept()
00387 {
00388 deactivate();
00389 activate();
00390 }
00391
00392 bool
00393 VPencilTool::showDialog() const
00394 {
00395 return m_optionWidget->exec() == QDialog::Accepted;
00396 }
00397
00398 void
00399 VPencilTool::setup( KActionCollection *collection )
00400 {
00401 m_action = static_cast<KRadioAction *>(collection -> action( name() ) );
00402
00403 if( m_action == 0 )
00404 {
00405 m_action = new KRadioAction( i18n( "Pencil Tool" ), "14_pencil", Qt::SHIFT+Qt::Key_P, this, SLOT( activate() ), collection, name() );
00406 m_action->setToolTip( i18n( "Pencil" ) );
00407 m_action->setExclusiveGroup( "freehand" );
00408
00409 }
00410 }
00411