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 
00334     if( !m_optionsWidget->selectedPattern() )
00335     {
00336         KMessageBox::error( 0L, i18n( "Please select a pattern." ), "" );
00337         return;
00338     }
00339 
00340     bool strokeSelected = false;
00341 
00342     // determine the target from the stroke-fill-preview-widget
00343     //VStrokeFillPreview* preview = view()->strokeFillPreview();
00344     //if( preview && preview->strokeIsSelected() ) // FIXME: stroke patterns don't work
00345     //  strokeSelected = true;
00346 
00347     // calculate a sane intial position for the new pattern
00348     if( view()->part()->document().selection()->objects().count() == 1 )
00349     {
00350         VObject *obj = view()->part()->document().selection()->objects().getFirst();
00351 
00352         if( ( ! strokeSelected && obj->fill()->type() != VFill::patt ) || (strokeSelected &&  obj->stroke()->type() != VStroke::patt ) )
00353         {
00354             KoRect bbox = obj->boundingBox();
00355             oldPattern.setOrigin( bbox.bottomLeft() + 0.5*(bbox.topLeft()-bbox.bottomLeft()) );
00356             oldPattern.setVector( bbox.bottomRight() + 0.5*(bbox.topRight()-bbox.bottomRight()) );
00357         }
00358     }
00359 
00360     m_pattern = *m_optionsWidget->selectedPattern();
00361 
00362     // use the old pattern position
00363     m_pattern.setOrigin( oldPattern.origin() );
00364     m_pattern.setVector( oldPattern.vector() );
00365 
00366     if( ! strokeSelected )
00367     {
00368         VFill fill;
00369         fill.pattern() = m_pattern;
00370         fill.setType( VFill::patt );
00371         view()->part()->addCommand(
00372             new VFillCmd( &view()->part()->document(), fill, "14_pattern" ), true );
00373     }
00374     else
00375     {
00376         VStroke stroke;
00377         stroke.pattern() = m_pattern;
00378         stroke.setType( VStroke::patt );
00379         view()->part()->addCommand(
00380             new VStrokeCmd( &view()->part()->document(), &stroke, "14_pattern" ), true );
00381     }
00382 } // VPatternTool::mouseButtonRelease
00383 
00384 void
00385 VPatternTool::mouseDragRelease()
00386 {
00387     if( ! view() || m_state == normal )
00388         return;
00389 
00390     if( view()->part()->document().selection()->objects().count() == 0 )
00391     {
00392         draw();
00393         return;
00394     }
00395 
00396     if( !m_optionsWidget->selectedPattern() )
00397     {
00398         draw();
00399         KMessageBox::error( 0L, i18n( "Please select a pattern." ), "" );
00400         return;
00401     }
00402     //m_pattern = *m_optionsWidget->selectedPattern();
00403 
00404     if( m_state == moveOrigin )
00405         m_pattern.setOrigin( last() );
00406     else if( m_state == moveVector )
00407         m_pattern.setVector( last() );
00408     else if( m_state == createNew )
00409     {
00410         m_pattern.setOrigin( first() );
00411         m_pattern.setVector( last() );
00412     }
00413 
00414     m_state = normal;
00415 
00416     VStrokeFillPreview* preview = view()->strokeFillPreview();
00417     if( ! preview )
00418         return;
00419 
00420     //if( ! preview->strokeIsSelected() ) // FIXME: stroke patterns don't work
00421     {
00422         VFill fill;
00423         fill.pattern() = m_pattern;
00424         fill.setType( VFill::patt );
00425         view()->part()->addCommand(
00426             new VFillCmd( &view()->part()->document(), fill, "14_pattern" ), true );
00427     }
00428     /*
00429     else
00430     {
00431         VStroke stroke;
00432         stroke.pattern() = m_pattern;
00433         stroke.setType( VStroke::patt );
00434         view()->part()->addCommand(
00435             new VStrokeCmd( &view()->part()->document(), &stroke, "14_pattern" ), true );
00436     }
00437     */
00438 } // VPatternTool::mouseDragRelease
00439 
00440 void
00441 VPatternTool::cancel()
00442 {
00443     // Erase old object:
00444     if( isDragging() )
00445         draw();
00446     m_state = normal;
00447 }
00448 
00449 bool
00450 VPatternTool::showDialog() const
00451 {
00452     return m_optionsWidget->exec() == QDialog::Accepted;
00453 }
00454 
00455 void
00456 VPatternTool::setup( KActionCollection *collection )
00457 {
00458     m_action = static_cast<KRadioAction *>(collection -> action( name() ) );
00459 
00460     if( m_action == 0 )
00461     {
00462         m_action = new KRadioAction( i18n( "Pattern Tool" ), "14_pattern", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() );
00463         m_action->setToolTip( i18n( "Pattern" ) );
00464         m_action->setExclusiveGroup( "misc" );
00465         //m_ownAction = true;
00466     }
00467 }
00468 
00469 void
00470 VPatternTool::setCursor() const
00471 {
00472     if( !view() ) return;
00473 
00474     // set a different cursor if mouse is inside the handle rects
00475     if( m_origin.contains( last() ) || m_vector.contains( last() ) )
00476         view()->setCursor( QCursor( Qt::SizeAllCursor ) );
00477     else
00478         view()->setCursor( QCursor( Qt::arrowCursor ) );
00479 }
00480 
00481 bool 
00482 VPatternTool::keyReleased( Qt::Key key )
00483 {
00484     // increase/decrease the handle size
00485     switch( key )
00486     {
00487         case Qt::Key_I:
00488             if( shiftPressed() ) 
00489                 m_handleSize++;
00490             else if( m_handleSize > 3 )
00491                 m_handleSize--;
00492         break;
00493         default: return false;
00494     }
00495 
00496     if( view() )
00497         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00498 
00499     return true;
00500 }
00501 
00502 void 
00503 VPatternTool::targetChanged()
00504 {
00505     if( view() ) 
00506         view()->repaintAll( view()->part()->document().selection()->boundingBox() );
00507 }
00508 
00509 #include "vpatterntool.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys