/* This file is part of the KDE project Copyright (C) 2005 Thorsten Zachmann Copyright (C) 2005 Casper Boemann Rasmussen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KoGuides.h" #include #include #include #include #include #include #include #include #include #include #include "KoGuideLineDia.h" class KoGuides::Popup : public TDEPopupMenu { public: Popup( KoGuides * guides ) { m_title = insertTitle( i18n( "Guide Line" ) ); m_delete = insertItem( i18n( "&Delete" ), guides, TQ_SLOT( slotRemove() ) ); m_seperator = insertSeparator(); m_pos = insertItem( i18n( "&Set Position..." ), guides, TQ_SLOT( slotChangePosition() ) ); } void update( int count ) { if ( count == 1 ) { changeTitle( m_title, i18n( "Guide Line" ) ); setItemVisible( m_seperator, true ); setItemVisible( m_pos, true ); } else { changeTitle( m_title, i18n( "Guide Lines" ) ); setItemVisible( m_seperator, false ); setItemVisible( m_pos, false ); } } private: int m_title; int m_delete; int m_seperator; int m_pos; }; const KoGuides::SnapStatus KoGuides::SNAP_NONE = 0; const KoGuides::SnapStatus KoGuides::SNAP_HORIZ = 1; const KoGuides::SnapStatus KoGuides::SNAP_VERT = 2; const KoGuides::SnapStatus KoGuides::SNAP_BOTH = 3; KoGuides::KoGuides( KoView *view, KoZoomHandler *zoomHandler ) : m_view( view ) , m_zoomHandler( zoomHandler ) { m_popup = new Popup( this ); m_mouseSelected = false; } KoGuides::~KoGuides() { delete m_popup; } void KoGuides::paintGuides( TQPainter &painter ) { //painter.setRasterOp( NotROP ); const KoPageLayout& pl = m_view->koDocument()->pageLayout(); int width = TQMAX( m_view->canvas()->width(), m_zoomHandler->zoomItX( pl.ptWidth ) ); int height = TQMAX( m_view->canvas()->height(), m_zoomHandler->zoomItY( pl.ptHeight ) ); for ( int i = 0; i < GL_END; ++i ) { TQValueList::iterator it = m_guideLines[i].begin(); for ( ; it != m_guideLines[i].end(); ++it ) { if ( !( *it )->automatic || ( *it )->snapping ) // dont paint autoStyle guides when they are not snapping { if ( ( *it )->snapping ) painter.setPen( TQPen( green, 0, DotLine ) ); else if ( ( *it )->selected ) painter.setPen( TQPen( red, 0, DotLine ) ); else painter.setPen( TQPen( blue, 0, DotLine ) ); painter.save(); if ( ( *it )->orientation == TQt::Vertical ) { painter.translate( m_zoomHandler->zoomItX( ( *it )->position ), 0 ); painter.drawLine( 0, 0, 0, height ); } else { painter.translate( 0, m_zoomHandler->zoomItY( ( *it )->position ) ); painter.drawLine( 0, 0, width, 0 ); } painter.restore(); } } } } bool KoGuides::mousePressEvent( TQMouseEvent *e ) { bool eventProcessed = true; bool changed = false; m_mouseSelected = false; KoPoint p( mapFromScreen( e->pos() ) ); KoGuideLine * guideLine = find( p, m_zoomHandler->unzoomItY( 2 ) ); if ( guideLine ) { m_lastPoint = e->pos(); if ( e->button() == TQt::LeftButton || e->button() == TQt::RightButton ) { if ( e->button() == TQt::LeftButton ) { m_mouseSelected = true; } if ( e->state() & TQt::ControlButton ) { if ( guideLine->selected ) { unselect( guideLine ); m_mouseSelected = false; } else { select( guideLine ); } changed = true; } else if ( ! guideLine->selected ) { unselectAll(); select( guideLine ); changed = true; } } } else { if ( !( e->state() & TQt::ControlButton ) ) { changed = unselectAll(); } eventProcessed = false; } if ( changed || hasSelected() ) { emit moveGuides( true ); } if ( changed ) { paint(); } if ( changed && ! hasSelected() ) { emit moveGuides( false ); } if ( e->button() == TQt::RightButton && hasSelected() ) { m_popup->update( m_guideLines[GL_SELECTED].count() ); m_popup->exec( TQCursor::pos() ); emit moveGuides( false ); } return eventProcessed; } bool KoGuides::mouseMoveEvent( TQMouseEvent *e ) { bool eventProcessed = false; if ( m_mouseSelected ) { TQPoint p( e->pos() ); p -= m_lastPoint; m_lastPoint = e->pos(); moveSelectedBy( p ); paint(); emit guideLinesChanged( m_view ); eventProcessed = true; } else if ( e->state() == TQt::NoButton ) { KoPoint p( mapFromScreen( e->pos() ) ); KoGuideLine * guideLine = find( p, m_zoomHandler->unzoomItY( 2 ) ); if ( guideLine ) { m_view->canvas()->setCursor( guideLine->orientation == TQt::Vertical ? TQt::sizeHorCursor : TQt::sizeVerCursor ); eventProcessed = true; } } return eventProcessed; } bool KoGuides::mouseReleaseEvent( TQMouseEvent *e ) { bool eventProcessed = false; if ( m_mouseSelected ) { KoPoint p( mapFromScreen( e->pos() ) ); if ( m_guideLines[GL_SELECTED].count() == 1 ) { int x1, y1, x2, y2; m_view->canvas()->rect().coords( &x1, &y1, &x2, &y2 ); TQPoint gp( m_view->canvas()->mapFromGlobal( e->globalPos() ) ); if ( m_guideLines[GL_SELECTED].first()->orientation == TQt::Vertical ) { if ( gp.x() < x1 || gp.x() > x2 ) removeSelected(); } else { if ( gp.y() < y1 || gp.y() > y2 ) removeSelected(); } } KoGuideLine * guideLine = find( p, m_zoomHandler->unzoomItY( 2 ) ); if ( guideLine ) { m_view->canvas()->setCursor( guideLine->orientation == TQt::Vertical ? TQt::sizeHorCursor : TQt::sizeVerCursor ); } m_mouseSelected = false; eventProcessed = true; emit guideLinesChanged( m_view ); } emit moveGuides( false ); return eventProcessed; } bool KoGuides::keyPressEvent( TQKeyEvent *e ) { bool eventProcessed = false; switch( e->key() ) { case TQt::Key_Delete: if ( hasSelected() ) { removeSelected(); paint(); emit guideLinesChanged( m_view ); eventProcessed = true; } break; default: break; } return eventProcessed; } void KoGuides::setGuideLines( const TQValueList &horizontalPos, const TQValueList &verticalPos ) { removeSelected(); TQValueList::iterator it = m_guideLines[GL].begin(); for ( ; it != m_guideLines[GL].end(); ++it ) { delete ( *it ); } m_guideLines[GL].clear(); TQValueList::ConstIterator posIt = horizontalPos.begin(); for ( ; posIt != horizontalPos.end(); ++posIt ) { KoGuideLine *guideLine = new KoGuideLine( TQt::Horizontal, *posIt, false ); m_guideLines[GL].append( guideLine ); } posIt = verticalPos.begin(); for ( ; posIt != verticalPos.end(); ++posIt ) { KoGuideLine *guideLine = new KoGuideLine( TQt::Vertical, *posIt, false ); m_guideLines[GL].append( guideLine ); } paint(); } void KoGuides::setAutoGuideLines( const TQValueList &horizontalPos, const TQValueList &verticalPos ) { TQValueList::iterator it = m_guideLines[GL_AUTOMATIC].begin(); for ( ; it != m_guideLines[GL_AUTOMATIC].end(); ++it ) { delete ( *it ); } m_guideLines[GL_AUTOMATIC].clear(); TQValueList::ConstIterator posIt = horizontalPos.begin(); for ( ; posIt != horizontalPos.end(); ++posIt ) { KoGuideLine *guideLine = new KoGuideLine( TQt::Horizontal, *posIt, true ); m_guideLines[GL_AUTOMATIC].append( guideLine ); } posIt = verticalPos.begin(); for ( ; posIt != verticalPos.end(); ++posIt ) { KoGuideLine *guideLine = new KoGuideLine( TQt::Vertical, *posIt, true ); m_guideLines[GL_AUTOMATIC].append( guideLine ); } } void KoGuides::getGuideLines( TQValueList &horizontalPos, TQValueList &verticalPos ) const { horizontalPos.clear(); verticalPos.clear(); TQValueList::const_iterator it = m_guideLines[GL].begin(); for ( ; it != m_guideLines[GL].end(); ++it ) { if ( ( *it )->orientation == TQt::Horizontal ) { horizontalPos.append( ( *it )->position ); } else { verticalPos.append( ( *it )->position ); } } it = m_guideLines[GL_SELECTED].begin(); for ( ; it != m_guideLines[GL_SELECTED].end(); ++it ) { if ( ( *it )->orientation == TQt::Horizontal ) { horizontalPos.append( ( *it )->position ); } else { verticalPos.append( ( *it )->position ); } } } void KoGuides::snapToGuideLines( KoRect &rect, int snap, SnapStatus &snapStatus, KoPoint &diff ) { if( !(snapStatus & SNAP_VERT)) diff.setX(10000); if( !(snapStatus & SNAP_HORIZ)) diff.setY(10000); for ( int i = 0; i < GL_END; ++i ) { TQValueList::const_iterator it = m_guideLines[i].begin(); for ( ; it != m_guideLines[i].end(); ++it ) { if ( ( *it )->orientation == TQt::Horizontal ) { double tmp = (*it)->position - rect.top(); if ( snapStatus & SNAP_HORIZ || TQABS( tmp ) < m_zoomHandler->unzoomItY( snap ) ) { if(TQABS( tmp ) < TQABS(diff.y())) { diff.setY( tmp ); snapStatus |= SNAP_HORIZ; } } tmp = (*it)->position - rect.bottom(); if ( snapStatus & SNAP_HORIZ || TQABS( tmp ) < m_zoomHandler->unzoomItY( snap ) ) { if(TQABS( tmp ) < TQABS(diff.y())) { diff.setY( tmp ); snapStatus |= SNAP_HORIZ; } } } else { double tmp = (*it)->position - rect.left(); if ( snapStatus & SNAP_VERT || TQABS( tmp ) < m_zoomHandler->unzoomItX( snap ) ) { if(TQABS( tmp ) < TQABS(diff.x())) { diff.setX( tmp ); snapStatus |= SNAP_VERT; } } tmp = (*it)->position - rect.right(); if ( snapStatus & SNAP_VERT || TQABS( tmp ) < m_zoomHandler->unzoomItX( snap ) ) { if(TQABS( tmp ) < TQABS(diff.x())) { diff.setX( tmp ); snapStatus |= SNAP_VERT; } } } } } if(!(snapStatus & SNAP_VERT)) diff.setX( 0 ); if(!(snapStatus & SNAP_HORIZ)) diff.setY( 0 ); } void KoGuides::snapToGuideLines( KoPoint &pos, int snap, SnapStatus &snapStatus, KoPoint &diff ) { if( !(snapStatus & SNAP_VERT)) diff.setX(10000); if( !(snapStatus & SNAP_HORIZ)) diff.setY(10000); for ( int i = 0; i < GL_END; ++i ) { TQValueList::const_iterator it = m_guideLines[i].begin(); for ( ; it != m_guideLines[i].end(); ++it ) { if ( ( *it )->orientation == TQt::Horizontal ) { double tmp = (*it)->position - pos.y(); if ( snapStatus & SNAP_HORIZ || TQABS( tmp ) < m_zoomHandler->unzoomItY( snap ) ) { if(TQABS( tmp ) < TQABS(diff.y())) { diff.setY( tmp ); snapStatus |= SNAP_HORIZ; } } } else { double tmp = (*it)->position - pos.x(); if ( snapStatus & SNAP_VERT || TQABS( tmp ) < m_zoomHandler->unzoomItX( snap ) ) { if(TQABS( tmp ) < TQABS(diff.x())) { diff.setX( tmp ); snapStatus |= SNAP_VERT; } } } } } if(!(snapStatus & SNAP_VERT)) diff.setX( 0 ); if(!(snapStatus & SNAP_HORIZ)) diff.setY( 0 ); } void KoGuides::repaintSnapping( const KoRect &snappedRect ) { bool needRepaint = false; for ( int i = 0; i < GL_END; ++i ) { TQValueList::const_iterator it = m_guideLines[i].begin(); for ( ; it != m_guideLines[i].end(); ++it ) { if ( ( *it )->orientation == TQt::Horizontal ) { if ( virtuallyEqual( snappedRect.top(), (*it)->position ) || virtuallyEqual( snappedRect.bottom(), ( *it )->position ) ) { if ( ! ( *it )->snapping ) { ( *it )->snapping = true; needRepaint = true; } } else if ( ( *it )->snapping ) { ( *it )->snapping = false; needRepaint = true; } } else { if ( virtuallyEqual( snappedRect.left(), (*it)->position ) || virtuallyEqual( snappedRect.right(), ( *it )->position ) ) { if ( ! ( *it )->snapping ) { ( *it )->snapping = true; needRepaint = true; } } else if ( ( *it )->snapping ) { ( *it )->snapping = false; needRepaint = true; } } } } if ( needRepaint ) { emit paintGuides( true ); paint(); emit paintGuides( false ); } } void KoGuides::repaintSnapping( const KoPoint &snappedPoint, SnapStatus snapStatus ) { bool needRepaint = false; for ( int i = 0; i < GL_END; ++i ) { TQValueList::const_iterator it = m_guideLines[i].begin(); for ( ; it != m_guideLines[i].end(); ++it ) { if ( ( *it )->orientation == TQt::Horizontal && ( snapStatus & SNAP_HORIZ ) ) { if( virtuallyEqual( snappedPoint.y(), (*it)->position ) ) { if ( ! ( *it )->snapping ) { ( *it )->snapping = true; needRepaint = true; } } else if ( ( *it )->snapping ) { ( *it )->snapping = false; needRepaint = true; } } else { if ( snapStatus & SNAP_VERT ) { if( virtuallyEqual( snappedPoint.x(), (*it)->position ) ) { if ( ! ( *it )->snapping ) { ( *it )->snapping = true; needRepaint = true; } } else if ( ( *it )->snapping ) { ( *it )->snapping = false; needRepaint = true; } } } } } if ( needRepaint ) { emit paintGuides( true ); paint(); emit paintGuides( false ); } } void KoGuides::repaintAfterSnapping() { bool needRepaint = false; for ( int i = 0; i < GL_END; ++i ) { TQValueList::const_iterator it = m_guideLines[i].begin(); for ( ; it != m_guideLines[i].end(); ++it ) { if ( ( *it )->snapping ) { needRepaint = true; ( *it )->snapping = false; } } } if ( needRepaint ) { emit paintGuides( true ); paint(); emit paintGuides( false ); } } void KoGuides::diffNextGuide( KoRect &rect, KoPoint &diff ) { for ( int i = 0; i < GL_END; ++i ) { TQValueList::const_iterator it = m_guideLines[i].begin(); for ( ; it != m_guideLines[i].end(); ++it ) { if ( ( *it )->orientation == TQt::Horizontal ) { double moveyl = ( *it )->position - rect.top(); double moveyr = ( *it )->position - rect.bottom(); if ( diff.y() > 0 ) { if ( moveyl < diff.y() && moveyl > 1E-10 ) { diff.setY( moveyl ); } if ( moveyr < diff.y() && moveyr > 1E-10 ) { diff.setY( moveyr ); } } else if ( diff.y() < 0 ) { if ( moveyl > diff.y() && moveyl < -1E-10 ) { diff.setY( moveyl ); } if ( moveyr > diff.y() && moveyr < -1E-10 ) { diff.setY( moveyr ); } } } else { double movexl = ( *it )->position - rect.left(); double movexr = ( *it )->position - rect.right(); if ( diff.x() > 0 ) { if ( movexl < diff.x() && movexl > 1E-10 ) { diff.setX( movexl ); } if ( ( movexr < diff.x() ) && movexr > 1E-10 ) { diff.setX( movexr ); } } else if ( diff.x() < 0 ) { if ( movexl > diff.x() && movexl < -1E-10 ) { diff.setX( movexl ); } if ( movexr > diff.x() && movexr < -1E-10 ) { diff.setX( movexr ); } } } } } } void KoGuides::moveGuide( const TQPoint &pos, bool horizontal, int rulerWidth ) { int x = pos.x() - rulerWidth; int y = pos.y() - rulerWidth; TQPoint p( x, y ); if ( !m_insertGuide ) { if ( ! horizontal && x > 0 ) { m_insertGuide = true; add( TQt::Vertical, p ); } else if ( horizontal && y > 0 ) { m_insertGuide = true; add( TQt::Horizontal, p ); } if ( m_insertGuide ) { TQMouseEvent e( TQEvent::MouseButtonPress, p, TQt::LeftButton, TQt::LeftButton ); mousePressEvent( &e ); } } else { TQMouseEvent e( TQEvent::MouseMove, p, TQt::NoButton, TQt::LeftButton ); mouseMoveEvent( &e ); } } void KoGuides::addGuide( const TQPoint &pos, bool /* horizontal */, int rulerWidth ) { int x = pos.x() - rulerWidth; int y = pos.y() - rulerWidth; TQPoint p( x, y ); m_insertGuide = false; TQMouseEvent e( TQEvent::MouseButtonRelease, p, TQt::LeftButton, TQt::LeftButton ); mouseReleaseEvent( &e ); } void KoGuides::slotChangePosition() { KoPoint p( mapFromScreen( m_lastPoint ) ); KoGuideLine * guideLine = find( p, m_zoomHandler->unzoomItY( 2 ) ); const KoPageLayout& pl = m_view->koDocument()->pageLayout(); double max = 0.0; if ( guideLine->orientation == TQt::Vertical ) { max = TQMAX( pl.ptWidth, m_zoomHandler->unzoomItX( m_view->canvas()->size().width() + m_view->canvasXOffset() - 1 ) ); } else { max = TQMAX( pl.ptHeight, m_zoomHandler->unzoomItY( m_view->canvas()->size().height() + m_view->canvasYOffset() - 1 ) ); } KoGuideLineDia dia( 0, guideLine->position, 0.0, max, m_view->koDocument()->unit() ); if ( dia.exec() == TQDialog::Accepted ) { guideLine->position = dia.pos(); paint(); emit guideLinesChanged( m_view ); } } void KoGuides::slotRemove() { removeSelected(); paint(); } void KoGuides::paint() { m_view->canvas()->repaint( false ); } void KoGuides::add( TQt::Orientation o, TQPoint &pos ) { KoPoint p( mapFromScreen( pos ) ); KoGuideLine *guideLine = new KoGuideLine( o, o == TQt::Vertical ? p.x(): p.y() ); m_guideLines[GL].append( guideLine ); } void KoGuides::select( KoGuideLine *guideLine ) { guideLine->selected = true; if ( m_guideLines[GL].remove( guideLine ) == 1 ) { m_guideLines[GL_SELECTED].append( guideLine ); } } void KoGuides::unselect( KoGuideLine *guideLine ) { guideLine->selected = false; if ( m_guideLines[GL_SELECTED].remove( guideLine ) == 1 ) { m_guideLines[GL].append( guideLine ); } } bool KoGuides::unselectAll() { bool selected = m_guideLines[GL_SELECTED].empty() == false; TQValueList::iterator it = m_guideLines[GL_SELECTED].begin(); for ( ; it != m_guideLines[GL_SELECTED].end(); ++it ) { ( *it )->selected = false; m_guideLines[GL].append( *it ); } m_guideLines[GL_SELECTED].clear(); return selected; } void KoGuides::removeSelected() { TQValueList::iterator it = m_guideLines[GL_SELECTED].begin(); for ( ; it != m_guideLines[GL_SELECTED].end(); ++it ) { delete ( *it ); } m_guideLines[GL_SELECTED].clear(); } bool KoGuides::hasSelected() { return m_guideLines[GL_SELECTED].empty() == false; } KoGuides::KoGuideLine * KoGuides::find( KoPoint &p, double diff ) { TQValueList::iterator it = m_guideLines[GL_SELECTED].begin(); for ( ; it != m_guideLines[GL_SELECTED].end(); ++it ) { if ( ( *it )->orientation == TQt::Vertical && TQABS( ( *it )->position - p.x() ) < diff ) { return *it; } if ( ( *it )->orientation == TQt::Horizontal && TQABS( ( *it )->position - p.y() ) < diff ) { return *it; } } it = m_guideLines[GL].begin(); for ( ; it != m_guideLines[GL].end(); ++it ) { if ( ( *it )->orientation == TQt::Vertical && TQABS( ( *it )->position - p.x() ) < diff ) { return *it; } if ( ( *it )->orientation == TQt::Horizontal && TQABS( ( *it )->position - p.y() ) < diff ) { return *it; } } return 0; } void KoGuides::moveSelectedBy( TQPoint &p ) { KoPoint point( m_zoomHandler->unzoomPoint( p ) ); if ( m_guideLines[GL_SELECTED].count() > 1 ) { const KoPageLayout& pl = m_view->koDocument()->pageLayout(); double right = TQMAX( pl.ptWidth, m_zoomHandler->unzoomItX( m_view->canvas()->width() + m_view->canvasXOffset() - 1 ) ); double bottom = TQMAX( pl.ptHeight, m_zoomHandler->unzoomItY( m_view->canvas()->height() + m_view->canvasYOffset() - 1 ) ); TQValueList::iterator it = m_guideLines[GL_SELECTED].begin(); for ( ; it != m_guideLines[GL_SELECTED].end(); ++it ) { if ( ( *it )->orientation == TQt::Vertical ) { double tmp = ( *it )->position + point.x(); if ( tmp < 0 ) { point.setX( point.x() - tmp ); } else if ( tmp > right ) { point.setX( point.x() - ( tmp - right ) ); } } else { double tmp = ( *it )->position + point.y(); if ( tmp < 0 ) { point.setY( point.y() - tmp ); } else if ( tmp > bottom ) { point.setY( point.y() - ( tmp - bottom ) ); } } } } TQValueList::iterator it = m_guideLines[GL_SELECTED].begin(); for ( ; it != m_guideLines[GL_SELECTED].end(); ++it ) { ( *it )->snapping = false; if ( ( *it )->orientation == TQt::Vertical && p.x() != 0 ) { ( *it )->position = ( *it )->position + point.x(); } else if ( ( *it )->orientation == TQt::Horizontal && p.y() != 0 ) { ( *it )->position = ( *it )->position + point.y(); } } } KoPoint KoGuides::mapFromScreen( const TQPoint & pos ) { int x = pos.x() + m_view->canvasXOffset(); int y = pos.y() + m_view->canvasYOffset(); double xf = m_zoomHandler->unzoomItX( x ); double yf = m_zoomHandler->unzoomItY( y ); return KoPoint( xf, yf ); } TQPoint KoGuides::mapToScreen( const KoPoint & pos ) { int x = m_zoomHandler->zoomItX( pos.x() ) - m_view->canvasXOffset(); int y = m_zoomHandler->zoomItY( pos.y() ) - m_view->canvasYOffset(); return TQPoint( x, y ); } #include "KoGuides.moc"