karbon

vpatterntool.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 "vpatterntool.h"
00021 
00022 #include <qtoolbutton.h>
00023 #include <qframe.h>
00024 #include <qhbuttongroup.h>
00025 #include <qlayout.h>
00026 #include <qfileinfo.h>
00027 #include <qlabel.h>
00028 #include <qcursor.h>
00029 
00030 #include <kiconloader.h>
00031 #include <koIconChooser.h>
00032 #include <kfiledialog.h>
00033 #include <kmessagebox.h>
00034 
00035 #include <karbon_factory.h>
00036 #include <karbon_resourceserver.h>
00037 #include <karbon_view.h>
00038 #include <karbon_part.h>
00039 #include <render/vpainter.h>
00040 #include <render/vpainterfactory.h>
00041 #include <core/vselection.h>
00042 #include <core/vfill.h>
00043 #include <core/vstroke.h>
00044 #include <commands/vfillcmd.h>
00045 #include <commands/vstrokecmd.h>
00046 #include <widgets/vstrokefillpreview.h>
00047 
00048 VPatternWidget::VPatternWidget( QPtrList<KoIconItem>* patterns, VTool*, QWidget* parent )
00049     : KDialogBase( parent, "", true, i18n( "Choose Pattern" ), Ok | Cancel ), m_pattern( 0 )
00050 {
00051     QWidget *base = new QWidget( this );
00052     QVBoxLayout* layout = new QVBoxLayout( base );
00053     layout->addWidget( m_patternChooser = new KoIconChooser( QSize( 32, 32 ), base ) );
00054     layout->addWidget( m_buttonGroup = new QHButtonGroup( base ) );
00055     m_buttonGroup->insert( m_importPatternButton = new QToolButton( m_buttonGroup ) );
00056     m_buttonGroup->insert( m_deletePatternButton = new QToolButton( m_buttonGroup ) );
00057     m_patternChooser->setFixedSize( 180, 120 );
00058     m_importPatternButton->setIconSet( SmallIconSet( "14_layer_newlayer" ) );
00059     m_importPatternButton->setTextLabel( i18n( "Import" ) );
00060     m_deletePatternButton->setIconSet( SmallIconSet("14_layer_deletelayer" ) );
00061     m_deletePatternButton->setTextLabel( i18n( "Delete" ) );
00062 
00063     m_buttonGroup->setInsideMargin( 3 );
00064     m_importPatternButton->setEnabled( true );
00065     m_deletePatternButton->setEnabled( false );
00066 
00067     //setFrameStyle( Box | Sunken );
00068     layout->setMargin( 3 );
00069 
00070     connect( m_buttonGroup, SIGNAL( clicked( int ) ), this, SLOT( slotButtonClicked( int ) ) );
00071     connect( m_patternChooser, SIGNAL( selected( KoIconItem* ) ), this, SLOT( patternSelected( KoIconItem* ) ) );
00072 
00073     KoIconItem* item;
00074     for( item = patterns->first(); item; item = patterns->next() )
00075         m_patternChooser->addItem( item );
00076     m_pattern = (VPattern*)patterns->first();
00077 
00078     setMainWidget( base );
00079 } // VPatternWidget::VPatternWidget
00080 
00081 VPatternWidget::~VPatternWidget()
00082 {
00083 } // VPatternWidget::~VPatternWidget
00084 
00085 VPattern* VPatternWidget::selectedPattern()
00086 {
00087     return m_pattern;
00088 } // VPatternWidget::selectedPattern
00089 
00090 void VPatternWidget::importPattern()
00091 {
00092     VPattern* pattern = KarbonFactory::rServer()->addPattern( KFileDialog::getOpenFileName( QString::null,
00093         "*.jpg *.gif *.png *.tif *.xpm *.bmp", this, i18n( "Choose Pattern to Add" ) ) );
00094     if( pattern )
00095         m_patternChooser->addItem( pattern );
00096 } // VPatternWidget::importPattern
00097 
00098 void VPatternWidget::deletePattern()
00099 {
00100     m_patternChooser->removeItem( m_pattern );
00101     KarbonFactory::rServer()->removePattern( m_pattern );
00102     m_patternChooser->updateContents();
00103     m_pattern = static_cast<VPattern*>( m_patternChooser->currentItem() );
00104 } // VPatternWidget::deletePattern
00105 
00106 void VPatternWidget::slotButtonClicked( int id )
00107 {
00108     switch( id )
00109     {
00110         case 0: importPattern();
00111                 break;
00112         case 1: deletePattern();
00113                 break;
00114     }
00115 } // VPatternWidget::slotButtonClicked
00116 
00117 void VPatternWidget::patternSelected( KoIconItem* item )
00118 {
00119     m_pattern = (VPattern*)item;
00120     m_deletePatternButton->setEnabled( QFileInfo( m_pattern->tilename() ).isWritable() );
00121 } // VPatternWidget::patternSelected
00122 
00123 VPatternTool::VPatternTool( KarbonView *view )
00124     : VTool( view, "tool_pattern" ), m_state( normal ), m_handleSize( 3 ), m_active( false )
00125 {
00126     QPtrList<KoIconItem> patterns = KarbonFactory::rServer()->patterns();
00127     m_optionsWidget = new VPatternWidget( &patterns, this );
00128     registerTool( this );
00129 } // VPatternTool::VPatternTool
00130 
00131 VPatternTool::~VPatternTool()
00132 {
00133     delete m_optionsWidget;
00134 } // VPatternTool::~VPatternTool
00135 
00136 void
00137 VPatternTool::activate()
00138 {
00139     m_active = true;
00140     m_state = normal;
00141     VTool::activate();
00142     view()->statusMessage()->setText( i18n( "Pattern" ) );
00143     view()->setCursor( QCursor( Qt::crossCursor ) );
00144 
00145     if( view() )
00146     {
00147         // disable selection handles
00148         view()->part()->document().selection()->showHandle( false );
00149         // connect to the stroke-fill-preview to get notice when the stroke or fill gets selected
00150         VStrokeFillPreview* preview = view()->strokeFillPreview();
00151         if( preview )
00152         {
00153             connect( preview, SIGNAL( fillSelected() ), this, SLOT( targetChanged() ) );
00154             connect( preview, SIGNAL( strokeSelected() ), this, SLOT( targetChanged() ) );
00155         }
00156         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00157     }
00158 }
00159 
00160 void
00161 VPatternTool::deactivate()
00162 {
00163     m_active = false;
00164 
00165     if( view() )
00166     {
00167         // enable selection handles
00168         view()->part()->document().selection()->showHandle( true );
00169         VStrokeFillPreview* preview = view()->strokeFillPreview();
00170         if( preview )
00171         {
00172             disconnect( preview, SIGNAL( fillSelected() ), this, SLOT( targetChanged() ) );
00173             disconnect( preview, SIGNAL( strokeSelected() ), this, SLOT( targetChanged() ) );
00174         }
00175         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00176     }
00177 }
00178 
00179 
00180 QString 
00181 VPatternTool::contextHelp()
00182 {
00183     QString s = i18n( "<qt><b>Pattern tool:</b><br>" );
00184     s += i18n( "<i>Click</i> on the pattern you want in the chooser.<br>" );
00185     s += i18n( "<i>Click and drag</i> to choose the pattern vector.</qt>" );
00186     s += i18n( "<i>Press i or Shift+i</i> to decrease or increase the handle size.<br>" );
00187     return s;
00188 } // VPatternTool::contextHelp
00189 
00190 void VPatternTool::draw()
00191 {
00192     if( ! view() || view()->part()->document().selection()->objects().count() == 0 )
00193         return;
00194 
00195     VPainter *painter = view()->painterFactory()->editpainter();
00196     painter->setRasterOp( Qt::NotROP );
00197 
00198     painter->setPen( Qt::DotLine );
00199     
00200     // differentiate between moving a handle and creating a complete new vector
00201     if( m_state == moveOrigin || m_state == moveVector )
00202     {
00203         painter->newPath();
00204         painter->moveTo( m_fixed );
00205         painter->lineTo( m_current );
00206         painter->strokePath();
00207         // draw the handle rects
00208         painter->drawNode( m_fixed, m_handleSize );
00209         painter->drawNode( m_current, m_handleSize );
00210     }
00211     else if( m_state == createNew )
00212     {
00213         painter->newPath();
00214         painter->moveTo( first() );
00215         painter->lineTo( m_current );
00216         painter->strokePath();
00217         // draw the handle rects
00218         painter->drawNode( first(), m_handleSize );
00219         painter->drawNode( m_current, m_handleSize );
00220     }
00221 } // VPatternTool::draw
00222 
00223 bool 
00224 VPatternTool::getPattern( VPattern &pattern )
00225 {
00226     if( ! view() ) 
00227         return false;
00228     
00229     // determine if stroke of fill is selected for editing
00230     //VStrokeFillPreview *preview = view()->strokeFillPreview();
00231     //bool strokeSelected = ( preview && preview->strokeIsSelected() );
00232     bool strokeSelected = false; // FIXME: stroke patterns don't work
00233 
00234     VSelection* selection = view()->part()->document().selection();
00235     if( selection->objects().count() != 1 ) 
00236         return false;
00237     
00238     VObject *obj = selection->objects().getFirst();
00239     // get the pattern of the first selected object, if any
00240     if( strokeSelected && obj->stroke()->type() == VStroke::patt )
00241         pattern = obj->stroke()->pattern();
00242     else if( ! strokeSelected && obj->fill()->type() == VFill::patt )
00243         pattern = obj->fill()->pattern();
00244     else
00245         return false;
00246     
00247     return true;
00248 }
00249 
00250 void 
00251 VPatternTool::draw( VPainter* painter )
00252 {
00253     if( ! m_active )
00254         return;
00255 
00256     if( m_state != normal )
00257         return;
00258 
00259     if( ! getPattern( m_pattern ) )
00260         return;
00261 
00262     KoPoint s = m_pattern.origin();
00263     KoPoint e = m_pattern.vector();
00264 
00265     // save the handle rects for later inside testing
00266     m_origin = KoRect( s.x()-m_handleSize, s.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize );
00267     m_vector = KoRect( e.x()-m_handleSize, e.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize );
00268 
00269     painter->setPen( Qt::blue.light() );
00270     painter->setBrush( Qt::blue.light() );
00271     painter->setRasterOp( Qt::XorROP );
00272 
00273     // draw the pattern vector
00274     painter->newPath();
00275     painter->moveTo( s );
00276     painter->lineTo( e );
00277     painter->strokePath();
00278     
00279     // draw the handle rects
00280     painter->drawNode( m_origin.center(), m_handleSize );
00281     painter->drawNode( m_vector.center(), m_handleSize );
00282 }
00283 
00284 void
00285 VPatternTool::mouseDrag()
00286 {
00287     if( m_state == normal ) 
00288         return;
00289 
00290     draw();
00291 
00292     m_current = last();
00293 
00294     draw();
00295 } // VPatternTool::mouseDrag
00296 
00297 void
00298 VPatternTool::mouseButtonPress()
00299 {
00300     m_current = first();
00301 
00302     // set the apropriate editing state
00303     if( m_origin.contains( m_current ) )
00304     {
00305         m_state = moveOrigin;
00306         m_fixed = m_vector.center();
00307     }
00308     else if( m_vector.contains( m_current ) )
00309     {
00310         m_state = moveVector;
00311         m_fixed = m_origin.center();
00312     }
00313     else 
00314         m_state = createNew;
00315 } // VPatternTool::mouseButtonPress
00316 
00317 void
00318 VPatternTool::mouseButtonRelease()
00319 {
00320     m_state = normal;
00321 
00322     if( view()->part()->document().selection()->objects().count() == 0 ) 
00323         return;
00324 
00325     // save old pattern position
00326     VPattern oldPattern = m_pattern;
00327 
00328     if( first() == last() )
00329     {
00330         if( showDialog() != QDialog::Accepted )
00331             return;
00332     }
00333     else if( !m_optionsWidget->selectedPattern() )
00334         KMessageBox::error( 0L, i18n( "Please select a pattern." ), "" );
00335 
00336     bool strokeSelected = false;
00337 
00338     // determine the target from the stroke-fill-preview-widget
00339     //VStrokeFillPreview* preview = view()->strokeFillPreview();
00340     //if( preview && preview->strokeIsSelected() ) // FIXME: stroke patterns don't work
00341     //  strokeSelected = true;
00342 
00343     // calculate a sane intial position for the new pattern
00344     if( view()->part()->document().selection()->objects().count() == 1 )
00345     {
00346         VObject *obj = view()->part()->document().selection()->objects().getFirst();
00347 
00348         if( ( ! strokeSelected && obj->fill()->type() != VFill::patt ) || (strokeSelected &&  obj->stroke()->type() != VStroke::patt ) )
00349         {
00350             KoRect bbox = obj->boundingBox();
00351             oldPattern.setOrigin( bbox.bottomLeft() + 0.5*(bbox.topLeft()-bbox.bottomLeft()) );
00352             oldPattern.setVector( bbox.bottomRight() + 0.5*(bbox.topRight()-bbox.bottomRight()) );
00353         }
00354     }
00355 
00356     VPattern m_pattern = *m_optionsWidget->selectedPattern();
00357 
00358     // use the old pattern position
00359     m_pattern.setOrigin( oldPattern.origin() );
00360     m_pattern.setVector( oldPattern.vector() );
00361 
00362     if( ! strokeSelected )
00363     {
00364         VFill fill;
00365         fill.pattern() = m_pattern;
00366         fill.setType( VFill::patt );
00367         view()->part()->addCommand(
00368             new VFillCmd( &view()->part()->document(), fill, "14_pattern" ), true );
00369     }
00370     else
00371     {
00372         VStroke stroke;
00373         stroke.pattern() = m_pattern;
00374         stroke.setType( VStroke::patt );
00375         view()->part()->addCommand(
00376             new VStrokeCmd( &view()->part()->document(), &stroke, "14_pattern" ), true );
00377     }
00378 } // VPatternTool::mouseButtonRelease
00379 
00380 void
00381 VPatternTool::mouseDragRelease()
00382 {
00383     if( ! view() || m_state == normal )
00384         return;
00385 
00386     if( view()->part()->document().selection()->objects().count() == 0 )
00387     {
00388         draw();
00389         return;
00390     }
00391 
00392     if( !m_optionsWidget->selectedPattern() )
00393     {
00394         draw();
00395         KMessageBox::error( 0L, i18n( "Please select a pattern." ), "" );
00396         return;
00397     }
00398     //m_pattern = *m_optionsWidget->selectedPattern();
00399 
00400     if( m_state == moveOrigin )
00401         m_pattern.setOrigin( last() );
00402     else if( m_state == moveVector )
00403         m_pattern.setVector( last() );
00404     else if( m_state == createNew )
00405     {
00406         m_pattern.setOrigin( first() );
00407         m_pattern.setVector( last() );
00408     }
00409 
00410     m_state = normal;
00411 
00412     VStrokeFillPreview* preview = view()->strokeFillPreview();
00413     if( ! preview )
00414         return;
00415 
00416     //if( ! preview->strokeIsSelected() ) // FIXME: stroke patterns don't work
00417     {
00418         VFill fill;
00419         fill.pattern() = m_pattern;
00420         fill.setType( VFill::patt );
00421         view()->part()->addCommand(
00422             new VFillCmd( &view()->part()->document(), fill, "14_pattern" ), true );
00423     }
00424     /*
00425     else
00426     {
00427         VStroke stroke;
00428         stroke.pattern() = m_pattern;
00429         stroke.setType( VStroke::patt );
00430         view()->part()->addCommand(
00431             new VStrokeCmd( &view()->part()->document(), &stroke, "14_pattern" ), true );
00432     }
00433     */
00434 } // VPatternTool::mouseDragRelease
00435 
00436 void
00437 VPatternTool::cancel()
00438 {
00439     // Erase old object:
00440     if( isDragging() )
00441         draw();
00442     m_state = normal;
00443 }
00444 
00445 bool
00446 VPatternTool::showDialog() const
00447 {
00448     return m_optionsWidget->exec() == QDialog::Accepted;
00449 }
00450 
00451 void
00452 VPatternTool::setup( KActionCollection *collection )
00453 {
00454     m_action = static_cast<KRadioAction *>(collection -> action( name() ) );
00455 
00456     if( m_action == 0 )
00457     {
00458         m_action = new KRadioAction( i18n( "Pattern Tool" ), "14_pattern", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() );
00459         m_action->setToolTip( i18n( "Pattern" ) );
00460         m_action->setExclusiveGroup( "misc" );
00461         //m_ownAction = true;
00462     }
00463 }
00464 
00465 void
00466 VPatternTool::setCursor() const
00467 {
00468     if( !view() ) return;
00469 
00470     // set a different cursor if mouse is inside the handle rects
00471     if( m_origin.contains( last() ) || m_vector.contains( last() ) )
00472         view()->setCursor( QCursor( Qt::SizeAllCursor ) );
00473     else
00474         view()->setCursor( QCursor( Qt::arrowCursor ) );
00475 }
00476 
00477 bool 
00478 VPatternTool::keyReleased( Qt::Key key )
00479 {
00480     // increase/decrease the handle size
00481     switch( key )
00482     {
00483         case Qt::Key_I:
00484             if( shiftPressed() ) 
00485                 m_handleSize++;
00486             else if( m_handleSize > 3 )
00487                 m_handleSize--;
00488         break;
00489         default: return false;
00490     }
00491 
00492     if( view() )
00493         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00494 
00495     return true;
00496 }
00497 
00498 void 
00499 VPatternTool::targetChanged()
00500 {
00501     if( view() ) 
00502         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00503 }
00504 
00505 #include "vpatterntool.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys