karbon

vgradienttool.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001, 2002, 2003 The Karbon Developers
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <qcursor.h>
00021 #include <qlabel.h>
00022 
00023 #include <klocale.h>
00024 
00025 #include <karbon_part.h>
00026 #include <karbon_view.h>
00027 #include <karbon_factory.h>
00028 #include <render/vpainter.h>
00029 #include <render/vpainterfactory.h>
00030 #include "vgradienttool.h"
00031 #include <widgets/vgradienttabwidget.h>
00032 #include <commands/vfillcmd.h>
00033 #include <commands/vstrokecmd.h>
00034 #include <core/vstroke.h>
00035 #include <core/vselection.h>
00036 #include <widgets/vstrokefillpreview.h>
00037 
00038 #include <kdebug.h>
00039 
00040 VGradientTool::VGradientOptionsWidget::VGradientOptionsWidget( VGradient& gradient )
00041     : KDialogBase( 0L, "", true, i18n( "Edit Gradient" ), Ok | Cancel )
00042 {
00043     m_gradientWidget = new VGradientTabWidget( gradient, KarbonFactory::rServer(), this );
00044     setMainWidget( m_gradientWidget );
00045     setFixedSize( baseSize() );
00046 }
00047 
00048 VGradientTool::VGradientTool( KarbonView *view )
00049     : VTool( view, "gradienttool" ), m_state( normal ), m_handleSize( 3 ), m_active( false )
00050 {
00051     setName( "tool_gradient" );
00052     m_optionsWidget = new VGradientOptionsWidget( m_gradient );
00053     registerTool( this );
00054 }
00055 
00056 VGradientTool::~VGradientTool()
00057 {
00058     delete m_optionsWidget;
00059 }
00060 
00061 void
00062 VGradientTool::activate()
00063 {
00064     m_active = true;
00065     m_state = normal;
00066     view()->statusMessage()->setText( i18n( "Gradient" ) );
00067     view()->setCursor( QCursor( Qt::crossCursor ) );
00068     VTool::activate();
00069 
00070     if( view() )
00071     {
00072         // disable selection handles
00073         view()->part()->document().selection()->showHandle( false );
00074         // connect to the stroke-fill-preview to get notice when the stroke or fill gets selected
00075         VStrokeFillPreview* preview = view()->strokeFillPreview();
00076         if( preview )
00077         {
00078             connect( preview, SIGNAL( fillSelected() ), this, SLOT( targetChanged() ) );
00079             connect( preview, SIGNAL( strokeSelected() ), this, SLOT( targetChanged() ) );
00080         }
00081         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00082     }
00083 }
00084 
00085 void
00086 VGradientTool::deactivate()
00087 {
00088     m_active = false;
00089 
00090     if( view() )
00091     {
00092         // enable selection handles
00093         view()->part()->document().selection()->showHandle( true );
00094         VStrokeFillPreview* preview = view()->strokeFillPreview();
00095         if( preview )
00096         {
00097             disconnect( preview, SIGNAL( fillSelected() ), this, SLOT( targetChanged() ) );
00098             disconnect( preview, SIGNAL( strokeSelected() ), this, SLOT( targetChanged() ) );
00099         }
00100         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00101     }
00102 }
00103 
00104 QString
00105 VGradientTool::statusText()
00106 {
00107     return i18n( "Gradient Tool" );
00108 }
00109 
00110 QString 
00111 VGradientTool::contextHelp()
00112 {
00113     QString s = i18n( "<qt><b>Gradient tool:</b><br>" );
00114     s += i18n( "<i>Click and drag</i> to choose the gradient vector.<br>" );
00115     s += i18n( "<i>Click and drag</i> a gradient vector handle to change the gradient vector.<br>" );
00116     s += i18n( "<i>Shift click and drag</i> to move the radial gradient focal point.<br>" );
00117     s += i18n( "<i>Press i or Shift+i</i> to decrease or increase the handle size.<br>" );
00118     s += i18n( "<br><b>Gradient editing:</b><br>" );
00119     s += i18n( "<i>Click and drag</i> to move points.<br>" );
00120     s += i18n( "<i>Double click</i> on a color point to edit it.<br>" );
00121     s += i18n( "<i>Right click</i> on a color point to remove it.</qt>" );
00122     return s;
00123 }
00124 
00125 bool 
00126 VGradientTool::getGradient( VGradient &gradient )
00127 {
00128     if( ! view() ) 
00129         return false;
00130     
00131     // determine if stroke of fill is selected for editing
00132     VStrokeFillPreview *preview = view()->strokeFillPreview();
00133     bool strokeSelected = ( preview && preview->strokeIsSelected() );
00134         
00135     VSelection* selection = view()->part()->document().selection();
00136     if( selection->objects().count() != 1 ) 
00137         return false;
00138     
00139     VObject *obj = selection->objects().getFirst();
00140     // get the gradient of the first selected object, if any
00141     if( strokeSelected && obj->stroke()->type() == VStroke::grad )
00142         gradient = obj->stroke()->gradient();
00143     else if( ! strokeSelected && obj->fill()->type() == VFill::grad )
00144         gradient = obj->fill()->gradient();
00145     else
00146         return false;
00147     
00148     return true;
00149 }
00150 
00151 bool
00152 VGradientTool::getOpacity( double &opacity )
00153 {
00154     if( ! view() ) 
00155         return false;
00156     
00157     // determine if stroke of fill is selected for editing
00158     VStrokeFillPreview *preview = view()->strokeFillPreview();
00159     bool strokeSelected = ( preview && preview->strokeIsSelected() );
00160         
00161     VSelection* selection = view()->part()->document().selection();
00162     if( selection->objects().count() != 1 ) 
00163         return false;
00164     
00165     VObject *obj = selection->objects().getFirst();
00166     // get the opacity of the first selected object, if any
00167     if( strokeSelected && obj->stroke()->type() == VStroke::grad )
00168         opacity = obj->stroke()->color().opacity();
00169     else if( ! strokeSelected && obj->fill()->type() == VFill::grad )
00170         opacity = obj->fill()->color().opacity();
00171     else return false;
00172     
00173     return true;
00174 }
00175 
00176 void 
00177 VGradientTool::draw( VPainter* painter )
00178 {
00179     if( ! m_active )
00180         return;
00181 
00182     if( m_state != normal )
00183         return;
00184 
00185     if( ! getGradient( m_gradient ) )
00186         return;
00187 
00188     KoPoint s = m_gradient.origin();
00189     KoPoint e = m_gradient.vector();
00190     KoPoint f = m_gradient.focalPoint();
00191 
00192     // save the handle rects for later inside testing
00193     m_origin = KoRect( s.x()-m_handleSize, s.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize );
00194     m_vector = KoRect( e.x()-m_handleSize, e.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize );
00195     m_center = KoRect( f.x()-m_handleSize, f.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize );
00196 
00197     painter->setPen( Qt::blue.light() );
00198     painter->setBrush( Qt::blue.light() );
00199     painter->setRasterOp( Qt::XorROP );
00200 
00201     // draw the gradient vector
00202     painter->newPath();
00203     painter->moveTo( s );
00204     painter->lineTo( e );
00205     painter->strokePath();
00206     
00207     if( m_gradient.type() == VGradient::radial )
00208     {
00209         // draw the focal point cross
00210         double size = (double)m_handleSize / view()->zoom();
00211         KoPoint focal = m_center.center();
00212         KoRect cross = KoRect( focal.x()-3*size, focal.y()-3*size, 6*size, 6*size );
00213         painter->newPath();
00214         painter->moveTo( cross.topLeft() );
00215         painter->lineTo( cross.bottomRight() );
00216         painter->strokePath();
00217         painter->newPath();
00218         painter->moveTo( cross.bottomLeft() );
00219         painter->lineTo( cross.topRight() );
00220         painter->strokePath();
00221     }
00222     // draw the handle rects
00223     painter->drawNode( m_origin.center(), m_handleSize );
00224     painter->drawNode( m_vector.center(), m_handleSize );
00225 }
00226 
00227 void
00228 VGradientTool::draw()
00229 {
00230     if( ! view() || view()->part()->document().selection()->objects().count() == 0 )
00231         return;
00232 
00233     VPainter *painter = view()->painterFactory()->editpainter();
00234     painter->setRasterOp( Qt::NotROP );
00235 
00236     painter->setPen( Qt::DotLine );
00237     painter->newPath();
00238     
00239     // differentiate between moving a handle and creating a complete new vector
00240     if( m_state == moveOrigin || m_state == moveVector )
00241     {
00242         painter->moveTo( m_fixed );
00243         painter->lineTo( m_current );
00244         // draw the handle rects
00245         painter->drawNode( m_fixed, m_handleSize );
00246         painter->drawNode( m_current, m_handleSize );
00247     }
00248     else if( m_state == createNew )
00249     {
00250         painter->moveTo( first() );
00251         painter->lineTo( m_current );
00252         // draw the handle rects
00253         painter->drawNode( first(), m_handleSize );
00254         painter->drawNode( m_current, m_handleSize );
00255     }
00256     else if( m_state == moveCenter )
00257     {
00258         // draw the focal point cross
00259         double size = (double)m_handleSize / view()->zoom();
00260         KoRect cross = KoRect( m_current.x()-3*size, m_current.y()-3*size, 6*size, 6*size );
00261         painter->moveTo( cross.topLeft() );
00262         painter->lineTo( cross.bottomRight() );
00263         painter->strokePath();
00264         painter->newPath();
00265         painter->moveTo( cross.bottomLeft() );
00266         painter->lineTo( cross.topRight() );
00267     }
00268 
00269     painter->strokePath();
00270 }
00271 
00272 void
00273 VGradientTool::mouseDrag()
00274 {
00275     if( m_state == normal ) 
00276         return;
00277 
00278     // undo old line
00279     draw();
00280 
00281     m_current = last();
00282 
00283     draw();
00284 }
00285 
00286 void
00287 VGradientTool::mouseButtonPress()
00288 {
00289     m_current = first();
00290 
00291     // set the apropriate editing state
00292     if( m_center.contains( m_current ) && shiftPressed())
00293     {
00294         m_state = moveCenter;
00295     }
00296     else if( m_origin.contains( m_current ) )
00297     {
00298         m_state = moveOrigin;
00299         m_fixed = m_vector.center();
00300     }
00301     else if( m_vector.contains( m_current ) )
00302     {
00303         m_state = moveVector;
00304         m_fixed = m_origin.center();
00305     }
00306     else 
00307         m_state = createNew;
00308 }
00309 
00310 void
00311 VGradientTool::mouseButtonRelease()
00312 {
00313     m_state = normal;
00314 
00315     if( ! view() || view()->part()->document().selection()->objects().count() == 0 ) 
00316         return;
00317 
00318     // save old gradient position
00319     VGradient oldGradient = m_gradient;
00320 
00321     bool strokeSelected = false;
00322 
00323     // determine the target from the stroke-fill-preview-widget
00324     VStrokeFillPreview* preview = view()->strokeFillPreview();
00325     if( preview && preview->strokeIsSelected() )
00326         strokeSelected = true;
00327 
00328     if( first() == last() )
00329     {
00330         m_optionsWidget->gradientWidget()->setGradient( m_gradient );
00331         if( strokeSelected )
00332         {
00333             m_optionsWidget->gradientWidget()->setTarget( VGradientTabWidget::STROKE );
00334             m_optionsWidget->gradientWidget()->setOpacity( 1.0 );
00335         }
00336         else
00337         {
00338             m_optionsWidget->gradientWidget()->setTarget( VGradientTabWidget::FILL );
00339             double opacity;
00340             if( getOpacity( opacity ) )
00341                 m_optionsWidget->gradientWidget()->setOpacity( opacity );
00342         }
00343         
00344         if( ! showDialog() )
00345             return;
00346         
00347         m_gradient = m_optionsWidget->gradientWidget()->gradient();
00348 
00349         // if the gradient dialog was shown and accepted, determine the target from the dialog
00350         strokeSelected = ( m_optionsWidget->gradientWidget()->target() == VGradientTabWidget::STROKE );
00351     }
00352 
00353     // calculate a sane intial position for the new gradient
00354     if( view()->part()->document().selection()->objects().count() == 1 )
00355     {
00356         VObject *obj = view()->part()->document().selection()->objects().getFirst();
00357 
00358         if( ( ! strokeSelected && obj->fill()->type() != VFill::grad ) 
00359         || ( strokeSelected && obj->stroke()->type() != VStroke::grad ) )
00360         {
00361             KoRect bbox = obj->boundingBox();
00362             switch( m_gradient.type() )
00363             {
00364                 case VGradient::linear:
00365                     oldGradient.setOrigin( bbox.bottomLeft() + 0.5*(bbox.bottomRight()-bbox.bottomLeft()) );
00366                     oldGradient.setVector( bbox.topLeft() + 0.5*(bbox.topRight()-bbox.topLeft()) );
00367                     oldGradient.setFocalPoint( bbox.center() );
00368                 break;
00369                 case VGradient::radial:
00370                     oldGradient.setOrigin( bbox.center() );
00371                     oldGradient.setVector( bbox.topLeft() + 0.5*(bbox.topRight()-bbox.topLeft()) );
00372                     oldGradient.setFocalPoint( bbox.center() );
00373                 break;
00374                 case VGradient::conic:
00375                     oldGradient.setOrigin( bbox.center() );
00376                     oldGradient.setVector( bbox.topLeft() + 0.5*(bbox.topRight()-bbox.topLeft()) );
00377                     oldGradient.setFocalPoint( bbox.center() );
00378                 break;
00379             }
00380         }
00381     }
00382 
00383     // workaround for a libart 2.3.10 bug
00384     if( oldGradient.origin() == oldGradient.vector() )
00385         oldGradient.vector().rx()+=1;
00386 
00387     // use the old gradient position
00388     m_gradient.setVector( oldGradient.vector() );
00389     m_gradient.setOrigin( oldGradient.origin() );
00390     m_gradient.setFocalPoint( oldGradient.focalPoint() );
00391 
00392     if( ! strokeSelected )
00393     {
00394         VFill fill;
00395         fill.gradient() = m_gradient;
00396         fill.setType( VFill::grad );
00397         VColor c = fill.color();
00398         c.setOpacity( m_optionsWidget->gradientWidget()->opacity() );
00399         fill.setColor( c, false );
00400         view()->part()->addCommand(
00401             new VFillCmd( &view()->part()->document(), fill, "14_gradient" ), true );
00402     }
00403     else
00404     {
00405         view()->part()->addCommand(
00406             new VStrokeCmd( &view()->part()->document(), &m_gradient ), true );
00407     }
00408 }
00409 
00410 void
00411 VGradientTool::mouseDragRelease()
00412 {
00413     if( ! view() || m_state == normal ) 
00414         return;
00415 
00416     if( view()->part()->document().selection()->objects().count() == 0 )
00417     {
00418         draw();
00419         return;
00420     }
00421 
00422     if( m_state == moveOrigin )
00423         m_gradient.setOrigin( last() );
00424     else if( m_state == moveVector )
00425         m_gradient.setVector( last() );
00426     else if( m_state == moveCenter )
00427         m_gradient.setFocalPoint( last() );
00428     else if( m_state == createNew )
00429     {
00430         m_gradient.setOrigin( first() );
00431         m_gradient.setFocalPoint( first() );
00432         m_gradient.setVector( last() );
00433     }
00434 
00435     m_state = normal;
00436 
00437     VStrokeFillPreview* preview = view()->strokeFillPreview();
00438     if( ! preview )
00439         return;
00440 
00441     if( ! preview->strokeIsSelected() )
00442     {
00443         VFill fill;
00444         fill.gradient() = m_gradient;
00445         fill.setType( VFill::grad );
00446         VColor c = fill.color();
00447         c.setOpacity( m_optionsWidget->gradientWidget()->opacity() );
00448         fill.setColor( c, false );
00449         view()->part()->addCommand(
00450             new VFillCmd( &view()->part()->document(), fill, "14_gradient" ), true );
00451     }
00452     else
00453         view()->part()->addCommand(
00454             new VStrokeCmd( &view()->part()->document(), &m_gradient ), true );
00455 }
00456 
00457 void
00458 VGradientTool::cancel()
00459 {
00460     // Erase old object:
00461     if( isDragging() )
00462         draw();
00463     m_state = normal;
00464 }
00465 
00466 bool
00467 VGradientTool::showDialog() const
00468 {
00469     return m_optionsWidget->exec() == QDialog::Accepted;
00470 }
00471 
00472 void
00473 VGradientTool::setup( KActionCollection *collection )
00474 {
00475     m_action = static_cast<KRadioAction *>(collection -> action( name() ) );
00476 
00477     if( m_action == 0 )
00478     {
00479         m_action = new KRadioAction( i18n( "Gradient Tool" ), "14_gradient", Qt::Key_G, this, SLOT( activate() ), collection, name() );
00480         m_action->setToolTip( i18n( "Gradient" ) );
00481         m_action->setExclusiveGroup( "misc" );
00482         //m_ownAction = true;
00483     }
00484 }
00485 
00486 void
00487 VGradientTool::setCursor() const
00488 {
00489     if( !view() ) return;
00490 
00491     // set a different cursor if mouse is inside the handle rects
00492     if( m_origin.contains( last() ) || m_vector.contains( last() ) || m_center.contains( last() ) )
00493         view()->setCursor( QCursor( Qt::SizeAllCursor ) );
00494     else
00495         view()->setCursor( QCursor( Qt::arrowCursor ) );
00496 }
00497 
00498 bool 
00499 VGradientTool::keyReleased( Qt::Key key )
00500 {
00501     // increase/decrease the handle size
00502     switch( key )
00503     {
00504         case Qt::Key_I:
00505             if( shiftPressed() ) 
00506                 m_handleSize++;
00507             else if( m_handleSize > 3 )
00508                 m_handleSize--;
00509         break;
00510         default: return false;
00511     }
00512 
00513     if( view() )
00514         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00515 
00516     return true;
00517 }
00518 
00519 void 
00520 VGradientTool::targetChanged()
00521 {
00522     if( view() ) 
00523         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00524 }
00525 
00526 #include "vgradienttool.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys