karbon

vtexttool.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 <math.h>
00021 
00022 #include <qcheckbox.h>
00023 #include <qcombobox.h>
00024 #include <qcursor.h>
00025 #include <qlabel.h>
00026 #include <qlayout.h>
00027 #include <qlineedit.h>
00028 #include <qpainter.h>
00029 #include <qpixmap.h>
00030 #include <qpushbutton.h>
00031 #include <qtabwidget.h>
00032 
00033 #include <kdebug.h>
00034 #include <kfontcombo.h>
00035 #include <kfontdialog.h>
00036 #include <kiconloader.h>
00037 #include <knuminput.h>
00038 #include <kglobalsettings.h>
00039 
00040 #include <karbon_view.h>
00041 #include <karbon_part.h>
00042 #include <core/vdocument.h>
00043 #include <core/vglobal.h>
00044 #include <core/vselection.h>
00045 #include <core/vfill.h>
00046 #include <core/vgroup.h>
00047 #include <core/vstroke.h>
00048 #include <core/vcursor.h>
00049 #include <render/vpainterfactory.h>
00050 #include <render/vkopainter.h>
00051 #include "vtexttool.h"
00052 
00053 
00054 static void
00055 traceShape( VKoPainter* p, int x, int y, int w, int h )
00056 {
00057     p->newPath();
00058     p->moveTo( KoPoint( x + w , y + h ) );
00059     p->lineTo( KoPoint( x + w / 3, y + h ) );
00060     p->lineTo( KoPoint( x + w / 3, y + h / 3 ) );
00061     p->lineTo( KoPoint( x + w , y + h / 3 ) );
00062     p->lineTo( KoPoint( x + w , y + h ) );
00063 
00064     p->moveTo( KoPoint( x , y ) );
00065     p->lineTo( KoPoint( x + ( w / 3 ) * 2, y ) );
00066     p->lineTo( KoPoint( x + ( w / 3 ) * 2, y + ( h / 3 ) * 2 ) );
00067     p->lineTo( KoPoint( x , y + ( h / 3 ) * 2 ) );
00068     p->lineTo( KoPoint( x , y ) );
00069 }
00070 
00071 ShadowPreview::ShadowPreview( ShadowWidget* parent )
00072         : QWidget( parent ), m_parent( parent )
00073 {
00074     setBackgroundMode( Qt::NoBackground );
00075     setMinimumSize( 60, 60 );
00076 
00077     connect( this, SIGNAL( changed( int, int, bool ) ), m_parent, SLOT( setShadowValues( int, int, bool ) ) );
00078 }
00079 
00080 ShadowPreview::~ShadowPreview()
00081 {
00082 }
00083 
00084 void
00085 ShadowPreview::mouseReleaseEvent( QMouseEvent* e )
00086 {
00087     int dx = e->x() - width() / 2;
00088     int dy = e->y() - height() / 2;
00089 
00090     float fd = sqrt( double( dx * dx + dy * dy ) );
00091     int a;
00092 
00093     if( fd == 0 )
00094         a = 0;
00095     else if( dy == 0 && dx < 0 )
00096         a = 180;
00097     else
00098     {
00099         float r = acos( dx / fd );
00100         a = int( ( dy <= 0 ? r : VGlobal::twopi - r ) / VGlobal::twopi * 360. );
00101     }
00102 
00103     emit changed( a, ( int ) fd, m_parent->isTranslucent() );
00104 }
00105 
00106 void
00107 ShadowPreview::paintEvent( QPaintEvent* )
00108 {
00109     int w = width() - 4;
00110     int h = height() - 4;
00111     int d = m_parent->shadowDistance();
00112     int a = 360 - m_parent->shadowAngle();
00113 
00114     QPixmap pm( w, h );
00115     VKoPainter p( &pm, w, h );
00116     VColor color( VColor::rgb );
00117 
00118     VFill fill;
00119     KIconLoader il;
00120     fill.pattern() = VPattern( il.iconPath( "karbon.png", KIcon::Small ) );
00121     fill.setType( VFill::patt );
00122 
00123     p.newPath();
00124     p.moveTo( KoPoint( 0, 0 ) );
00125     p.lineTo( KoPoint( 0, h ) );
00126     p.lineTo( KoPoint( w, h ) );
00127     p.lineTo( KoPoint( w, 0 ) );
00128     p.lineTo( KoPoint( 0, 0 ) );
00129     p.setBrush( fill );
00130     p.fillPath();
00131 
00132     color.set( 1., 1., 1. );
00133     color.setOpacity( .5 );
00134     p.setBrush( VFill( color ) );
00135     p.fillPath();
00136 
00137     if( m_parent->isTranslucent() )
00138     {
00139         color.set( 0., 0., 0. );
00140         color.setOpacity( .3 );
00141     }
00142     else
00143     {
00144         color.set( .3, .3, .3 );
00145         color.setOpacity( 1. );
00146     }
00147 
00148     p.setPen( VStroke( color ) );
00149     p.setBrush( VFill( color ) );
00150 
00151     traceShape(
00152         &p,
00153         int( w / 4 + d * cos( a / 360. * VGlobal::twopi ) ),
00154         int( h / 4 + d * sin( a / 360. * VGlobal::twopi ) ), int( w / 2 ), int( h / 2 ) );
00155 
00156     p.strokePath();
00157     p.fillPath();
00158 
00159     color.set( 0., 0., 1. );
00160     color.setOpacity( 1. );
00161     p.setBrush( VFill( color ) );
00162     color.set( 0., 0., .5 );
00163     p.setPen( VStroke( color ) );
00164     traceShape( &p, w / 4, h / 4, w / 2, h / 2 );
00165     p.strokePath();
00166     p.fillPath();
00167 
00168     if( !m_parent->useShadow() )
00169     {
00170         p.newPath();
00171         p.moveTo( KoPoint( 0, 0 ) );
00172         p.lineTo( KoPoint( 0, h ) );
00173         p.lineTo( KoPoint( w, h ) );
00174         p.lineTo( KoPoint( w, 0 ) );
00175         p.lineTo( KoPoint( 0, 0 ) );
00176         VColor c( colorGroup().background() );
00177         c.setOpacity( .8 );
00178         p.setBrush( VFill( c ) );
00179         p.fillPath();
00180     }
00181 
00182     p.end();
00183 
00184     QPainter painter( this );
00185     painter.drawPixmap( 2, 2, pm );
00186     painter.setPen( colorGroup().light() );
00187     painter.moveTo( 1, height() - 1 );
00188     painter.lineTo( 1, 1 );
00189     painter.lineTo( width() - 1, 1 );
00190     painter.lineTo( width() - 1, height() - 1 );
00191     painter.lineTo( 1, height() - 1 );
00192     painter.setPen( colorGroup().dark() );
00193     painter.moveTo( 0, height() - 1 );
00194     painter.lineTo( 0, 0 );
00195     painter.lineTo( width() - 1, 0 );
00196     painter.moveTo( width() - 2, 2 );
00197     painter.lineTo( width() - 2, height() - 2 );
00198     painter.lineTo( 2, height() - 2 );
00199     painter.setPen( Qt::black );
00200     painter.drawLine( width() / 2 - 2, height() / 2, width() / 2 + 2, height() / 2 );
00201     painter.drawLine( width() / 2, height() / 2 - 2, width() / 2, height() / 2 + 2 );
00202 }
00203 
00204 ShadowWidget::ShadowWidget( QWidget* parent, const char* name, int angle, int distance, bool translucent )
00205         : QGroupBox( parent, name )
00206 {
00207     setTitle( i18n( "Shadow" ) );
00208     setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
00209 
00210     QGridLayout* layout = new QGridLayout( this );
00211     layout->addRowSpacing( 0, 12 );
00212     layout->setMargin( 3 );
00213     layout->setSpacing( 2 );
00214     layout->setColStretch( 0, 1 );
00215     layout->setColStretch( 1, 0 );
00216     layout->setColStretch( 2, 2 );
00217     layout->addMultiCellWidget( m_preview = new ShadowPreview( this ), 1, 3, 0, 0 );
00218     layout->addWidget( new QLabel( i18n( "Angle:" ), this ), 1, 1 );
00219     layout->addWidget( m_angle = new KIntNumInput( this ), 1, 2 );
00220     layout->addWidget( new QLabel( i18n( "Distance:" ), this ), 2, 1 );
00221     layout->addWidget( m_distance = new KIntNumInput( this ), 2, 2 );
00222     layout->addWidget( m_useShadow = new QCheckBox( i18n( "Shadow" ), this ), 3, 1 );
00223     layout->addWidget( m_translucent = new QCheckBox( i18n( "Draw translucent shadow" ), this ), 3, 2 );
00224     m_distance->setRange( 1, 37, 1, true );
00225     m_angle->setRange( 0, 360, 10, true );
00226     m_angle->setValue( angle );
00227     m_distance->setValue( distance );
00228     m_translucent->setChecked( translucent );
00229 
00230     connect( m_angle, SIGNAL( valueChanged( int ) ), this, SLOT( updatePreview( int ) ) );
00231     connect( m_distance, SIGNAL( valueChanged( int ) ), this, SLOT( updatePreview( int ) ) );
00232     connect( m_useShadow, SIGNAL( clicked() ), this, SLOT( updatePreview() ) );
00233     connect( m_translucent, SIGNAL( clicked() ), this, SLOT( updatePreview() ) );
00234 
00235     updatePreview();
00236 }
00237 
00238 ShadowWidget::~ShadowWidget()
00239 {
00240 }
00241 
00242 void
00243 ShadowWidget::setUseShadow( bool use )
00244 {
00245     m_useShadow->setChecked( use );
00246     updatePreview();
00247 }
00248 
00249 bool ShadowWidget::useShadow()
00250 {
00251     return m_useShadow->isChecked();
00252 }
00253 
00254 void
00255 ShadowWidget::setShadowAngle( int angle )
00256 {
00257     m_angle->setValue( angle );
00258     m_preview->repaint();
00259 }
00260 
00261 int
00262 ShadowWidget::shadowAngle()
00263 {
00264     return m_angle->value();
00265 }
00266 
00267 void
00268 ShadowWidget::setShadowDistance( int distance )
00269 {
00270     m_distance->setValue( distance );
00271     m_preview->repaint();
00272 }
00273 
00274 int
00275 ShadowWidget::shadowDistance()
00276 {
00277     return m_distance->value();
00278 }
00279 
00280 void
00281 ShadowWidget::setTranslucent( bool translucent )
00282 {
00283     m_translucent->setChecked( translucent );
00284     m_preview->repaint();
00285 }
00286 
00287 bool ShadowWidget::isTranslucent()
00288 {
00289     return m_translucent->isChecked();
00290 }
00291 
00292 void
00293 ShadowWidget::setShadowValues( int angle, int distance, bool translucent )
00294 {
00295     m_angle->setValue( angle );
00296     m_distance->setValue( distance );
00297     m_translucent->setChecked( translucent );
00298     updatePreview();
00299 }
00300 
00301 void
00302 ShadowWidget::updatePreview( int )
00303 {
00304     m_preview->repaint();
00305 }
00306 
00307 void
00308 ShadowWidget::updatePreview()
00309 {
00310     m_preview->repaint();
00311     bool ok = m_useShadow->isChecked();
00312     m_angle->setEnabled( ok );
00313     m_distance->setEnabled( ok );
00314     m_translucent->setEnabled( ok );
00315 }
00316 
00317 VTextOptionsWidget::VTextOptionsWidget( VTextTool* tool, QWidget *parent )
00318     : KDialogBase( parent, "", true, i18n( "Text" ), Ok | Cancel ), m_tool( tool )
00319 {
00320     //setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
00321     //setFrameStyle( Box | Sunken );
00322     QWidget *base = new QWidget( this );
00323     QVBoxLayout* mainLayout = new QVBoxLayout( base );
00324     mainLayout->setMargin( 3 );
00325 
00326     mainLayout->add( m_tabWidget = new QTabWidget( base ) );
00327 
00328     m_tabWidget->setFont( QFont( KGlobalSettings::generalFont().family() , 8 ) );
00329 
00330     QWidget* textWidget = new QWidget( m_tabWidget );
00331 
00332     QGridLayout* textLayout = new QGridLayout( textWidget );
00333 
00334     QStringList list;
00335     KFontChooser::getFontList( list, KFontChooser::SmoothScalableFonts );
00336 
00337     textLayout->setMargin( 3 );
00338     textLayout->setSpacing( 2 );
00339     textLayout->addMultiCellWidget( m_fontCombo = new KFontCombo( list, textWidget ), 0, 0, 0, 2 );
00340     textLayout->addWidget( m_fontSize = new KIntNumInput( textWidget ), 1, 0 );
00341     textLayout->addWidget( m_boldCheck = new QCheckBox( i18n( "Bold" ), textWidget ), 1, 1 );
00342     textLayout->addWidget( m_italicCheck = new QCheckBox( i18n( "Italic" ), textWidget ), 1, 2 );
00343     textLayout->addMultiCellWidget( m_textEditor = new QLineEdit( textWidget ), 2, 2, 0, 2 );
00344 
00345     m_tabWidget->addTab( textWidget, i18n( "Text" ) );
00346 
00347     QWidget* posWidget = new QWidget( m_tabWidget );
00348     
00349     QGridLayout* posLayout = new QGridLayout( posWidget );
00350     textLayout->setMargin( 3 );
00351     posLayout->setSpacing( 2 );
00352     posLayout->addWidget( new QLabel( i18n( "Alignment:" ), posWidget ), 0, 0 );
00353     posLayout->addWidget( m_textAlignment = new QComboBox( posWidget ), 0, 1 );
00354     posLayout->addWidget( new QLabel( i18n( "Position:" ), posWidget ), 1, 0 );
00355     posLayout->addWidget( m_textPosition = new QComboBox( posWidget ), 1, 1 );
00356     posLayout->addWidget( new QLabel( i18n( "Offset:" ), posWidget ), 2, 0 );
00357     posLayout->addWidget( m_textOffset = new KDoubleNumInput( posWidget ), 2, 1 );
00358     posLayout->setColStretch( 0, 0 );
00359     posLayout->setColStretch( 1, 1 );
00360     
00361     m_tabWidget->addTab( posWidget, i18n( "Position" ) );
00362 
00363     QWidget* fxWidget = new QWidget( m_tabWidget );
00364 
00365     QVBoxLayout* fxLayout = new QVBoxLayout( fxWidget );
00366 
00367     fxLayout->setMargin( 3 );
00368     fxLayout->setSpacing( 2 );
00369     fxLayout->add( m_shadow = new ShadowWidget( fxWidget, 0L, 315, 4, true ) );
00370 
00371     QHBoxLayout* fxLayout2 = new QHBoxLayout( fxLayout );
00372 
00373     fxLayout2->setSpacing( 2 );
00374     fxLayout2->addWidget( m_editBasePath = new QPushButton( i18n( "Edit Base Path" ), fxWidget ) );
00375     fxLayout2->addWidget( m_convertToShapes = new QPushButton( i18n( "Convert to Shapes" ), fxWidget ) );
00376 
00377     m_tabWidget->addTab( fxWidget, i18n( "Effects" ) );
00378 
00379     m_fontCombo->setCurrentText( KGlobalSettings::generalFont().family() );
00380 
00381     m_fontSize->setValue( 12 );
00382     m_fontSize->setSuffix( " pt" );
00383 
00384     m_textEditor->setMinimumHeight( 100 );
00385     m_textEditor->setText( i18n( "New text") );
00386     m_textEditor->selectAll();
00387 
00388     m_convertToShapes->setEnabled( true );
00389 
00390     m_textAlignment->insertItem( i18n( "Horizontal alignment", "Left") );
00391     m_textAlignment->insertItem( i18n( "Horizontal alignment", "Center") );
00392     m_textAlignment->insertItem( i18n( "Horizontal alignment", "Right") );
00393 
00394     m_textPosition->insertItem( i18n( "Vertical alignment", "Above") );
00395     m_textPosition->insertItem( i18n( "Vertical alignment", "On") );
00396     m_textPosition->insertItem( i18n( "Vertical alignment", "Under") );
00397 
00398     m_textOffset->setRange( 0.0, 100.0, 1.0, true );
00399 
00400     connect( m_fontCombo, SIGNAL( activated( int ) ), this, SLOT( valueChanged( int ) ) );
00401     connect( m_boldCheck, SIGNAL( stateChanged( int ) ), this, SLOT( valueChanged( int ) ) );
00402     connect( m_italicCheck, SIGNAL( stateChanged( int ) ), this, SLOT( valueChanged( int ) ) );
00403     connect( m_fontSize, SIGNAL( valueChanged( int ) ), this, SLOT( valueChanged( int ) ) );
00404     connect( m_textPosition, SIGNAL( activated( int ) ), this, SLOT( valueChanged( int ) ) );
00405     connect( m_textAlignment, SIGNAL( activated( int ) ), this, SLOT( valueChanged( int ) ) );
00406     connect( m_textOffset, SIGNAL( valueChanged( double ) ), this, SLOT( valueChanged( double ) ) );
00407     connect( m_textEditor, SIGNAL( returnPressed() ), this, SLOT( accept() ) );
00408     connect( m_textEditor, SIGNAL( textChanged( const QString& ) ), this, SLOT( textChanged( const QString& ) ) );
00409     connect( m_editBasePath, SIGNAL( clicked() ), this, SLOT( editBasePath() ) );
00410     connect( m_convertToShapes, SIGNAL( clicked() ), this, SLOT( convertToShapes() ) );
00411     connect( this, SIGNAL( cancelClicked() ), this, SLOT( cancel() ) );
00412 
00413     setMainWidget( base );
00414     setFixedSize( baseSize() );
00415 }
00416 
00417 VTextOptionsWidget::~VTextOptionsWidget()
00418 {
00419 }
00420 
00421 void
00422 VTextOptionsWidget::valueChanged( int )
00423 {
00424     m_fontCombo->setBold( m_boldCheck->isChecked() );
00425     m_fontCombo->setItalic( m_italicCheck->isChecked() );
00426 
00427     m_textEditor->setFont( QFont( m_fontCombo->currentText(), m_fontSize->value(), ( m_boldCheck->isChecked() ? 75 : 50 ), m_italicCheck->isChecked() ) );
00428 
00429     if( m_tool && isVisible() ) 
00430         m_tool->textChanged();
00431 }
00432 
00433 void
00434 VTextOptionsWidget::valueChanged( double )
00435 {
00436     if( m_tool && isVisible() ) 
00437         m_tool->textChanged();
00438 }
00439 
00440 void
00441 VTextOptionsWidget::accept()
00442 {
00443     if( m_tool )
00444         m_tool->accept();
00445     hide();
00446 }
00447 
00448 void
00449 VTextOptionsWidget::cancel()
00450 {
00451     if( m_tool )
00452         m_tool->cancel();
00453 }
00454 
00455 void
00456 VTextOptionsWidget::textChanged( const QString& )
00457 {
00458     if( m_tool && isVisible() )
00459         m_tool->textChanged();
00460 }
00461 
00462 void
00463 VTextOptionsWidget::editBasePath()
00464 {
00465     if( m_tool )
00466         m_tool->editBasePath();
00467 }
00468 
00469 void
00470 VTextOptionsWidget::convertToShapes()
00471 {
00472     if( m_tool )
00473         m_tool->convertToShapes();
00474 }
00475 
00476 void
00477 VTextOptionsWidget::setFont( const QFont& font )
00478 {
00479     m_fontCombo->setCurrentText( font.family() );
00480 
00481     m_boldCheck->setChecked( font.bold() );
00482 
00483     m_italicCheck->setChecked( font.italic() );
00484 
00485     m_fontSize->setValue( font.pointSize() );
00486 
00487     m_fontCombo->setBold( m_boldCheck->isChecked() );
00488     m_fontCombo->setItalic( m_italicCheck->isChecked() );
00489 
00490     m_textEditor->setFont( QFont( m_fontCombo->currentText(), m_fontSize->value(), ( m_boldCheck->isChecked() ? 75 : 50 ), m_italicCheck->isChecked() ) );
00491 }
00492 
00493 QFont VTextOptionsWidget::font()
00494 {
00495     return QFont( m_fontCombo->currentText(), m_fontSize->value(), ( m_boldCheck->isChecked() ? 75 : 50 ), m_italicCheck->isChecked() );
00496 }
00497 
00498 void
00499 VTextOptionsWidget::setText( const QString& text )
00500 {
00501     m_textEditor->setText( text );
00502 }
00503 
00504 QString VTextOptionsWidget::text()
00505 {
00506     return m_textEditor->text();
00507 }
00508 
00509 void
00510 VTextOptionsWidget::setPosition( VText::Position position )
00511 {
00512     m_textPosition->setCurrentItem( position );
00513 }
00514 
00515 VText::Position VTextOptionsWidget::position()
00516 {
00517     return ( VText::Position ) m_textPosition->currentItem();
00518 }
00519 
00520 void
00521 VTextOptionsWidget::setAlignment( VText::Alignment alignment )
00522 {
00523     m_textAlignment->setCurrentItem( alignment );
00524 }
00525 
00526 VText::Alignment VTextOptionsWidget::alignment()
00527 {
00528     return ( VText::Alignment ) m_textAlignment->currentItem();
00529 }
00530 
00531 void 
00532 VTextOptionsWidget::setOffset( double offset )
00533 {
00534     if( offset < 0.0 ) offset = 0.0;
00535     if( offset > 100.0 ) offset = 100.0;
00536 
00537     m_textOffset->setValue( offset );
00538 }
00539 double 
00540 VTextOptionsWidget::offset()
00541 {
00542     return m_textOffset->value();
00543 }
00544 
00545 void
00546 VTextOptionsWidget::setUseShadow( bool state )
00547 {
00548     m_shadow->setUseShadow( state );
00549 }
00550 
00551 bool VTextOptionsWidget::useShadow()
00552 {
00553     return m_shadow->useShadow();
00554 }
00555 
00556 void
00557 VTextOptionsWidget::setShadow( int angle, int distance, bool translucent )
00558 {
00559     m_shadow->setShadowValues( angle, distance, translucent );
00560 }
00561 
00562 bool VTextOptionsWidget::translucentShadow()
00563 {
00564     return m_shadow->isTranslucent();
00565 }
00566 
00567 int
00568 VTextOptionsWidget::shadowAngle()
00569 {
00570     return m_shadow->shadowAngle();
00571 }
00572 
00573 int
00574 VTextOptionsWidget::shadowDistance()
00575 {
00576     return m_shadow->shadowDistance();
00577 }
00578 
00579 void 
00580 VTextOptionsWidget::initialize( VObject &text )
00581 {
00582     if( m_tool )
00583         m_tool->visit( text );
00584 }
00585 
00586 VTextTool::VTextTool( KarbonView *view )
00587         : VTool( view, "tool_text" )
00588 {
00589     m_optionsWidget = new VTextOptionsWidget( this, 0L );
00590     m_text = 0L;
00591     m_editedText = 0L;
00592     registerTool( this );
00593     m_cursor = new QCursor( VCursor::createCursor( VCursor::CrossHair ) );
00594 }
00595 
00596 VTextTool::~VTextTool()
00597 {
00598     delete m_optionsWidget;
00599     delete m_editedText;
00600     delete m_cursor;
00601 }
00602 
00603 QString VTextTool::contextHelp()
00604 {
00605     QString s = i18n( "<qt><b>Text Tool</b><br>" );
00606     s += i18n("<i>Click</i> on document to place horizontal text.<br>" );
00607     s += i18n("<i>Click and drag</i> in document to place directional text.<br>" );
00608     s += i18n("<i>Click</i> on a selected path object to place text along its outline.<br>" );
00609     s += i18n("<i>Click</i> on a selected text object to change it.<br></qt>" );
00610 
00611     return s;
00612 }
00613 
00614 void
00615 VTextTool::activate()
00616 {
00617     VTool::activate();
00618     view()->statusMessage()->setText( i18n( "Text Tool" ) );
00619     view()->setCursor( *m_cursor );
00620 
00621     m_creating = true;
00622     m_text = 0L;
00623     delete m_editedText;
00624     m_editedText = 0L;
00625 }
00626 
00627 void
00628 VTextTool::deactivate()
00629 {
00630 }
00631 
00632 void
00633 VTextTool::draw( VPainter* painter )
00634 {
00635     if( m_editedText )
00636         m_editedText->draw( painter, &m_editedText->boundingBox() );
00637 }
00638 
00639 void
00640 VTextTool::drawPathCreation()
00641 {
00642     VPainter * painter = view()->painterFactory()->editpainter();
00643 
00644     painter->setZoomFactor( view()->zoom() );
00645 
00646     painter->setRasterOp( Qt::NotROP );
00647     painter->newPath();
00648     painter->setPen( Qt::DotLine );
00649     painter->setBrush( Qt::NoBrush );
00650 
00651     painter->moveTo( first() );
00652     painter->lineTo( m_last );
00653     painter->strokePath();
00654 }
00655 
00656 void
00657 VTextTool::drawEditedText()
00658 {
00659     if( m_editedText ) 
00660         view()->repaintAll( m_editedText->boundingBox() );
00661 }
00662 
00663 void
00664 VTextTool::mouseButtonPress()
00665 {
00666     m_last = first();
00667     drawPathCreation();
00668     m_stepwise = false;
00669 }
00670 
00671 void
00672 VTextTool::mouseButtonRelease()
00673 {
00674     if( ! view() ) 
00675         return;
00676 
00677     VSelection* selection = view()->part()->document().selection();
00678     VObject* selObj = selection->objects().getFirst();
00679 
00680     // initialize dialog with single selected object
00681     if( selection->objects().count() == 1 && selObj->boundingBox().contains( last() ) )
00682         m_optionsWidget->initialize( *selObj );
00683     else 
00684     {
00685         // use a default horizontal path when just clicking
00686         VSubpath path( 0L );
00687         path.moveTo( first() );
00688         path.lineTo( KoPoint( first().x()+10, first().y() ) );
00689     
00690         if( ! createText( path ) )
00691             return;
00692     }
00693 
00694     if( dynamic_cast<VText*>( selObj ) && selObj->boundingBox().contains( last() ) )
00695         m_optionsWidget->setCaption( i18n( "Change Text") );
00696     else 
00697         m_optionsWidget->setCaption( i18n( "Insert Text") );
00698 
00699     m_optionsWidget->show();
00700 }
00701 
00702 void
00703 VTextTool::mouseDrag()
00704 {
00705     drawPathCreation();
00706 
00707     if( m_stepwise && shiftPressed() )
00708     {
00709         KoPoint act = last();
00710         KoPoint dst = act - first();
00711  
00712         double angle = atan2( dst.y(), dst.x() );
00713         if( angle < 0 )
00714             angle += VGlobal::twopi;
00715 
00716         // calculate previuos and next modulo 45 degree step 
00717         double prevStep = angle - fmod( angle, VGlobal::pi_2 / 2.0f );
00718         double nextStep = prevStep + VGlobal::pi_2 / 2.0f;
00719         // calculate distance between first and last point
00720         double length = sqrt( dst.x()*dst.x() + dst.y()*dst.y() );
00721 
00722         // use nearest step
00723         if( angle - prevStep < nextStep - angle )
00724         {
00725             m_last.setX( first().x() + length * cos( prevStep ) );
00726             m_last.setY( first().y() + length * sin( prevStep ) );
00727         }
00728         else
00729         {
00730             m_last.setX( first().x() + length * cos( nextStep ) );
00731             m_last.setY( first().y() + length * sin( nextStep ) );
00732         }
00733     }
00734     else
00735         m_last = last();
00736 
00737     drawPathCreation();
00738 }
00739 
00740 void
00741 VTextTool::mouseDragRelease()
00742 {
00743     drawPathCreation();
00744 
00745     if( m_creating && m_editedText )
00746     {
00747         drawEditedText();
00748         delete m_editedText;
00749         m_editedText = 0L;
00750     }
00751 
00752     // use dragged path to create text along
00753     VSubpath path( 0L );
00754     path.moveTo( first() );
00755     path.lineTo( m_last );
00756 
00757     if( createText( path ) )
00758     {
00759         m_optionsWidget->setCaption( i18n( "Insert Text") );
00760         m_optionsWidget->show();
00761     }
00762 }
00763 
00764 bool
00765 VTextTool::createText( VSubpath &path )
00766 {
00767     // no original text is used
00768     m_text = 0L;
00769     delete m_editedText;
00770 
00771     m_editedText = new VText( m_optionsWidget->font(), path, m_optionsWidget->position(), m_optionsWidget->alignment(), m_optionsWidget->text() );
00772     
00773     if( ! m_editedText ) 
00774         return false;
00775 
00776     m_editedText->setState( VObject::edit );
00777 
00778 #ifdef HAVE_KARBONTEXT
00779     m_editedText->traceText();
00780 #endif
00781 
00782     // yes, we are creating a new text object
00783     m_creating = true;
00784 
00785     return true;
00786 }
00787 
00788 void
00789 VTextTool::textChanged()
00790 {
00791     if( !m_editedText )
00792         return;
00793 
00794     if( !m_creating && m_text && m_text->state() != VObject::hidden )
00795     {
00796         // hide the original text if we are changing it
00797         m_text->setState( VObject::hidden );
00798         view()->repaintAll( m_text->boundingBox() );
00799     }
00800     else
00801         view()->repaintAll( m_editedText->boundingBox() );
00802 
00803     m_editedText->setText( m_optionsWidget->text() );
00804     m_editedText->setFont( m_optionsWidget->font() );
00805     m_editedText->setPosition( m_optionsWidget->position() );
00806     m_editedText->setAlignment( m_optionsWidget->alignment() );
00807     m_editedText->setOffset( 0.01 * m_optionsWidget->offset()  );
00808 #ifdef HAVE_KARBONTEXT
00809     m_editedText->traceText();
00810 #endif
00811 
00812     drawEditedText();
00813 }
00814 
00815 void
00816 VTextTool::accept()
00817 {
00818     if( !m_editedText )
00819         return;
00820 
00821     VTextCmd* cmd;
00822 
00823     if( !m_creating )
00824     {
00825         cmd = new VTextCmd(
00826                   &view()->part()->document(),
00827                   i18n( "Change Text" ),
00828                   m_text,
00829                   m_editedText->font(),
00830                   m_editedText->basePath(),
00831                   m_editedText->position(),
00832                   m_editedText->alignment(),
00833                   m_editedText->offset(),
00834                   m_editedText->text(),
00835                   m_optionsWidget->useShadow(),
00836                   m_optionsWidget->shadowAngle(),
00837                   m_optionsWidget->shadowDistance(),
00838                   m_optionsWidget->translucentShadow() );
00839     }
00840     else
00841     {
00842         VText *newText = m_editedText->clone();
00843         newText->setUseShadow( m_optionsWidget->useShadow() );
00844         newText->setShadow( m_optionsWidget->shadowAngle(), m_optionsWidget->shadowDistance(), m_optionsWidget->translucentShadow() );
00845 
00846         cmd = new VTextCmd(
00847                   &view()->part()->document(),
00848                   i18n( "Insert Text" ),
00849                   newText );
00850 
00851         delete m_editedText;
00852         m_editedText = 0L;
00853     }
00854 
00855     view()->part()->addCommand( cmd, true );
00856     view()->part()->repaintAllViews();
00857     m_creating = false;
00858 }
00859 
00860 void
00861 VTextTool::cancel()
00862 {
00863     if( m_text )
00864     {
00865         // show original text if we canceled changing it
00866         m_text->setState( VObject::selected );
00867         view()->repaintAll( m_text->boundingBox() );
00868     }
00869     else
00870         drawPathCreation();
00871 
00872     delete m_editedText;
00873     m_editedText = 0L;
00874 }
00875 
00876 void
00877 VTextTool::editBasePath()
00878 {
00879     if( !m_editedText )
00880         return;
00881 
00882     view()->part()->document().selection()->clear();
00883     view()->part()->document().selection()->append( &m_editedText->basePath() );
00884     view()->part()->repaintAllViews();
00885 }
00886 
00887 void
00888 VTextTool::convertToShapes()
00889 {
00890     if( !m_text )
00891         return;
00892 
00893     VTextToCompositeCmd* cmd = new VTextToCompositeCmd(
00894                                    &view()->part()->document(),
00895                                    i18n( "Text Conversion" ),
00896                                    m_text );
00897 
00898     view()->part()->addCommand( cmd, true );
00899 
00900     m_creating = false;
00901 
00902     delete m_editedText;
00903 
00904     m_text = 0L;
00905     m_editedText = 0L;
00906 }
00907 
00908 void
00909 VTextTool::visitVPath( VPath& composite )
00910 {
00911     if( composite.paths().count() == 0 )
00912         return;
00913 
00914     if( createText( *composite.paths().getFirst() ) )
00915         drawEditedText();
00916 }
00917 
00918 void
00919 VTextTool::visitVSubpath( VSubpath& path )
00920 {
00921     if( createText( path ) )
00922         drawEditedText();
00923 }
00924 
00925 void
00926 VTextTool::visitVText( VText& text )
00927 {
00928     m_text = &text;
00929     delete m_editedText;
00930     m_editedText = text.clone();
00931 
00932     m_optionsWidget->setFont( text.font() );
00933     m_optionsWidget->setText( text.text() );
00934     m_optionsWidget->setPosition( text.position() );
00935     m_optionsWidget->setAlignment( text.alignment() );
00936     m_optionsWidget->setOffset( text.offset() * 100.0 );
00937     m_optionsWidget->setUseShadow( text.useShadow() );
00938     m_optionsWidget->setShadow( text.shadowAngle(), text.shadowDistance(), text.translucentShadow() );
00939     m_creating = false;
00940     m_text->setState( VObject::hidden );
00941     m_editedText->setState( VObject::edit );
00942 }
00943 
00944 VTextTool::VTextCmd::VTextCmd( VDocument* doc, const QString& name, VText* text )
00945         : VCommand( doc, name, "14_text" ), m_text( text )
00946 {
00947     m_textModifications = 0L;
00948 
00949     m_executed = false;
00950 }
00951 
00952 VTextTool::VTextCmd::VTextCmd( VDocument* doc, const QString& name, VText* text,
00953                                const QFont &newFont, const VSubpath& newBasePath, VText::Position newPosition, VText::Alignment newAlignment, double newOffset, const QString& newText,
00954                                bool newUseShadow, int newShadowAngle, int newShadowDistance, bool newTranslucentShadow )
00955         : VCommand( doc, name, "14_text" ), m_text( text )
00956 {
00957     m_textModifications = new VTextModifPrivate();
00958     m_textModifications->newFont = newFont;
00959     m_textModifications->oldFont = text->font();
00960     m_textModifications->newBasePath = newBasePath;
00961     m_textModifications->oldBasePath = text->basePath();
00962     m_textModifications->newPosition = newPosition;
00963     m_textModifications->oldPosition = text->position();
00964     m_textModifications->newAlignment = newAlignment;
00965     m_textModifications->oldAlignment = text->alignment();
00966     m_textModifications->newOffset = newOffset;
00967     m_textModifications->oldOffset = text->offset();
00968     m_textModifications->newText = newText;
00969     m_textModifications->oldText = text->text();
00970     m_textModifications->newUseShadow = newUseShadow;
00971     m_textModifications->oldUseShadow = text->useShadow();
00972     m_textModifications->newShadowAngle = newShadowAngle;
00973     m_textModifications->oldShadowAngle = text->shadowAngle();
00974     m_textModifications->newShadowDistance = newShadowDistance;
00975     m_textModifications->oldShadowDistance = text->shadowDistance();
00976     m_textModifications->newTranslucentShadow = newTranslucentShadow;
00977     m_textModifications->oldTranslucentShadow = text->translucentShadow();
00978 
00979     m_executed = false;
00980 }
00981 
00982 VTextTool::VTextCmd::~VTextCmd()
00983 {
00984     delete m_textModifications;
00985 }
00986 
00987 void
00988 VTextTool::VTextCmd::execute()
00989 {
00990     if( !m_text )
00991         return;
00992 
00993     if( !m_textModifications )
00994     {
00995         if( m_text->state() == VObject::deleted )
00996             m_text->setState( VObject::normal );
00997         else
00998         {
00999             m_text->setState( VObject::normal );
01000             document()->append( m_text );
01001             document()->selection()->clear();
01002             document()->selection()->append( m_text );
01003         }
01004     }
01005     else
01006     {
01007         m_text->setFont( m_textModifications->newFont );
01008         m_text->setBasePath( m_textModifications->newBasePath );
01009         m_text->setPosition( m_textModifications->newPosition );
01010         m_text->setAlignment( m_textModifications->newAlignment );
01011         m_text->setOffset( m_textModifications->newOffset );
01012         m_text->setText( m_textModifications->newText );
01013         m_text->setUseShadow( m_textModifications->newUseShadow );
01014         m_text->setShadow( m_textModifications->newShadowAngle, m_textModifications->newShadowDistance, m_textModifications->newTranslucentShadow );
01015 
01016 #ifdef HAVE_KARBONTEXT
01017         m_text->traceText();
01018 #endif
01019 
01020         m_text->setState( VObject::normal );
01021     }
01022 
01023     m_executed = true;
01024 
01025     setSuccess( true );
01026 }
01027 
01028 void
01029 VTextTool::VTextCmd::unexecute()
01030 {
01031     if( !m_text )
01032         return;
01033 
01034     if( !m_textModifications )
01035     {
01036         document()->selection()->take( *m_text );
01037         m_text->setState( VObject::deleted );
01038     }
01039     else
01040     {
01041         m_text->setFont( m_textModifications->oldFont );
01042         m_text->setBasePath( m_textModifications->oldBasePath );
01043         m_text->setPosition( m_textModifications->oldPosition );
01044         m_text->setAlignment( m_textModifications->oldAlignment );
01045         m_text->setOffset( m_textModifications->oldOffset );
01046         m_text->setText( m_textModifications->oldText );
01047         m_text->setUseShadow( m_textModifications->oldUseShadow );
01048         m_text->setShadow( m_textModifications->oldShadowAngle, m_textModifications->oldShadowDistance, m_textModifications->oldTranslucentShadow );
01049 
01050 #ifdef HAVE_KARBONTEXT
01051         m_text->traceText();
01052 #endif
01053 
01054         m_text->setState( VObject::normal );
01055     }
01056 
01057     m_executed = false;
01058 
01059     setSuccess( false );
01060 }
01061 
01062 VTextTool::VTextToCompositeCmd::VTextToCompositeCmd( VDocument* doc, const QString& name, VText* text )
01063         : VCommand( doc, name, "14_text" ), m_text( text ), m_group( 0L ), m_executed( false )
01064 {
01065 }
01066 
01067 VTextTool::VTextToCompositeCmd::~VTextToCompositeCmd()
01068 {
01069 }
01070 
01071 void
01072 VTextTool::VTextToCompositeCmd::execute()
01073 {
01074     if( !m_text )
01075         return;
01076 
01077     if( !m_group )
01078     {
01079         m_group = m_text->toVGroup();
01080         document()->append( m_group );
01081     }
01082 
01083     m_text->setState( VObject::deleted );
01084     m_group->setState( VObject::normal );
01085     document()->selection()->clear();
01086     document()->selection()->append( m_group );
01087 
01088     m_executed = true;
01089 
01090     setSuccess( true );
01091 }
01092 
01093 void
01094 VTextTool::VTextToCompositeCmd::unexecute()
01095 {
01096     if( !m_text )
01097         return;
01098 
01099     m_text->setState( VObject::normal );
01100 
01101     document()->selection()->take( *m_group );
01102 
01103     m_group->setState( VObject::deleted );
01104 
01105     m_executed = false;
01106 
01107     setSuccess( false );
01108 }
01109 
01110 bool
01111 VTextTool::showDialog() const
01112 {
01113     VSelection* selection = view()->part()->document().selection();
01114 
01115     // initialize dialog with single selected object
01116     if( selection->objects().count() == 1 )
01117         m_optionsWidget->initialize( *selection->objects().getFirst());
01118     else 
01119         return false;
01120 
01121     if( dynamic_cast<VText*>( selection->objects().getFirst() ) )
01122         m_optionsWidget->setCaption(i18n( "Change Text") );
01123     else 
01124         m_optionsWidget->setCaption(i18n( "Insert Text") );
01125 
01126     m_optionsWidget->show();
01127     return true;
01128 }
01129 
01130 void 
01131 VTextTool::mouseDragShiftPressed()
01132 {
01133     m_stepwise = true;
01134     mouseDrag();
01135 }
01136 
01137 void 
01138 VTextTool::mouseDragShiftReleased()
01139 {
01140     m_stepwise = false;
01141     mouseDrag();
01142 }
01143 
01144 void
01145 VTextTool::setup( KActionCollection *collection )
01146 {
01147     m_action = static_cast<KRadioAction *>(collection -> action( name() ) );
01148 
01149     if( m_action == 0 )
01150     {
01151         m_action = new KRadioAction( i18n( "Text Tool" ), "14_text", Qt::SHIFT+Qt::Key_T, this, SLOT( activate() ), collection, name() );
01152         m_action->setToolTip( i18n( "Text Tool" ) );
01153         m_action->setExclusiveGroup( "misc" );
01154         //m_ownAction = true;
01155     }
01156 }
01157 
01158 #include "vtexttool.moc"
01159 
KDE Home | KDE Accessibility Home | Description of Access Keys