diff --git a/glabels/Handles.cpp b/glabels/Handles.cpp index d336bcf..781f3aa 100644 --- a/glabels/Handles.cpp +++ b/glabels/Handles.cpp @@ -24,6 +24,7 @@ #include "LabelModelObject.h" #include +#include namespace @@ -39,8 +40,8 @@ namespace /// /// Handle Constructor /// -glabels::Handle::Handle( LabelModelObject* owner ) - : mOwner(owner) +glabels::Handle::Handle( LabelModelObject* owner, Location location ) + : mOwner(owner), mLocation(location) { } @@ -53,6 +54,24 @@ glabels::Handle::~Handle() } +/// +/// Handle owner +/// +glabels::LabelModelObject* glabels::Handle::owner() const +{ + return mOwner; +} + + +/// +/// Handle location +/// +glabels::Handle::Location glabels::Handle::location() const +{ + return mLocation; +} + + /// /// Draw Handle at x,y /// @@ -62,16 +81,12 @@ void glabels::Handle::drawAt( QPainter* painter, double x, double y ) const painter->translate( x, y ); - /* Render at a scale of 1:1 in pixels, while preserving translations and rotations. */ - QTransform t = painter->transform(); - painter->setTransform( QTransform( 1, t.m12(), t.m13(), - t.m21(), 1, t.m23(), - t.m31(), t.m32(), t.m33() ) ); + double s = 1.0 / painter->transform().m11(); - painter->setPen( QPen( handleOutlineColor, handleOutlineWidthPixels ) ); + painter->setPen( QPen( handleOutlineColor, s*handleOutlineWidthPixels ) ); painter->setBrush( handleFillColor ); - painter->drawRect( -handlePixels/2, -handlePixels/2, handlePixels, handlePixels ); + painter->drawRect( QRectF( -s*handlePixels/2.0, -s*handlePixels/2.0, s*handlePixels, s*handlePixels ) ); painter->restore(); } @@ -93,11 +108,46 @@ QPainterPath glabels::Handle::pathAt( double scale, double x, double y ) const } +/// +/// HandleNorthWest Constructor +/// +glabels::HandleNorthWest::HandleNorthWest( LabelModelObject* owner ) + : Handle( owner, NW ) +{ +} + + +/// +/// HandleNorthWest Destructor +/// +glabels::HandleNorthWest::~HandleNorthWest() +{ +} + + +/// +/// Draw HandleNorthWest +/// +void glabels::HandleNorthWest::draw( QPainter* painter ) const +{ + drawAt( painter, 0, 0 ); +} + + +/// +/// HandleNorthWest Path +/// +QPainterPath glabels::HandleNorthWest::path( double scale ) const +{ + return pathAt( scale, 0, 0 ); +} + + /// /// HandleNorth Constructor /// glabels::HandleNorth::HandleNorth( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, N ) { } @@ -132,7 +182,7 @@ QPainterPath glabels::HandleNorth::path( double scale ) const /// HandleNorthEast Constructor /// glabels::HandleNorthEast::HandleNorthEast( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, NE ) { } @@ -167,7 +217,7 @@ QPainterPath glabels::HandleNorthEast::path( double scale ) const /// HandleEast Constructor /// glabels::HandleEast::HandleEast( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, E ) { } @@ -202,7 +252,7 @@ QPainterPath glabels::HandleEast::path( double scale ) const /// HandleSouthEast Constructor /// glabels::HandleSouthEast::HandleSouthEast( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, SE ) { } @@ -237,7 +287,7 @@ QPainterPath glabels::HandleSouthEast::path( double scale ) const /// HandleSouth Constructor /// glabels::HandleSouth::HandleSouth( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, S ) { } @@ -272,7 +322,7 @@ QPainterPath glabels::HandleSouth::path( double scale ) const /// HandleSouthWest Constructor /// glabels::HandleSouthWest::HandleSouthWest( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, SW ) { } @@ -299,7 +349,7 @@ void glabels::HandleSouthWest::draw( QPainter* painter ) const /// QPainterPath glabels::HandleSouthWest::path( double scale ) const { - return pathAt( scale, 0, mOwner->w() ); + return pathAt( scale, 0, mOwner->h() ); } @@ -307,7 +357,7 @@ QPainterPath glabels::HandleSouthWest::path( double scale ) const /// HandleWest Constructor /// glabels::HandleWest::HandleWest( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, W ) { } @@ -338,46 +388,11 @@ QPainterPath glabels::HandleWest::path( double scale ) const } -/// -/// HandleNorthWest Constructor -/// -glabels::HandleNorthWest::HandleNorthWest( LabelModelObject* owner ) - : Handle(owner) -{ -} - - -/// -/// HandleNorthWest Destructor -/// -glabels::HandleNorthWest::~HandleNorthWest() -{ -} - - -/// -/// Draw HandleNorthWest -/// -void glabels::HandleNorthWest::draw( QPainter* painter ) const -{ - drawAt( painter, 0, 0 ); -} - - -/// -/// HandleNorthWest Path -/// -QPainterPath glabels::HandleNorthWest::path( double scale ) const -{ - return pathAt( scale, 0, 0 ); -} - - /// /// HandleP1 Constructor /// glabels::HandleP1::HandleP1( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, P1 ) { } @@ -412,7 +427,7 @@ QPainterPath glabels::HandleP1::path( double scale ) const /// HandleP2 Constructor /// glabels::HandleP2::HandleP2( LabelModelObject* owner ) - : Handle(owner) + : Handle( owner, P2 ) { } diff --git a/glabels/Handles.h b/glabels/Handles.h index 82da785..9d41db1 100644 --- a/glabels/Handles.h +++ b/glabels/Handles.h @@ -37,14 +37,28 @@ namespace glabels /// class Handle { + //////////////////////////// + // Location enumeration + //////////////////////////// + public: + enum Location { NW, N, NE, E, SE, S, SW, W, P1, P2 }; + + //////////////////////////// // Lifecycle Methods //////////////////////////// protected: - Handle( LabelModelObject* owner ); + Handle( LabelModelObject* owner, Location location ); public: virtual ~Handle(); + + //////////////////////////// + // Attribue Methods + //////////////////////////// + LabelModelObject* owner() const; + Location location() const; + //////////////////////////// // Drawing Methods @@ -62,6 +76,7 @@ namespace glabels //////////////////////////// protected: LabelModelObject* mOwner; + Location mLocation; }; diff --git a/glabels/LabelModelBoxObject.cpp b/glabels/LabelModelBoxObject.cpp index d177eae..0e85c8b 100644 --- a/glabels/LabelModelBoxObject.cpp +++ b/glabels/LabelModelBoxObject.cpp @@ -64,12 +64,12 @@ namespace glabels if ( lineColor.alpha() ) { /* Has FILL and OUTLINE: adjust size to account for line width. */ - painter->drawRect( -mLineWidth/2, -mLineWidth/2, mW+mLineWidth, mH+mLineWidth ); + painter->drawRect( QRectF( -mLineWidth/2, -mLineWidth/2, mW+mLineWidth, mH+mLineWidth ) ); } else { /* Has FILL, but no OUTLINE. */ - painter->drawRect( 0, 0, mW, mH ); + painter->drawRect( QRectF( 0, 0, mW, mH ) ); } } else @@ -80,7 +80,7 @@ namespace glabels painter->setPen( QPen( shadowColor, mLineWidth ) ); painter->setBrush( Qt::NoBrush ); - painter->drawRect( 0, 0, mW, mH ); + painter->drawRect( QRectF( 0, 0, mW, mH ) ); } } @@ -99,7 +99,8 @@ namespace glabels painter->setPen( QPen( lineColor, mLineWidth ) ); painter->setBrush( fillColor ); - painter->drawRect( 0, 0, mW, mH ); + + painter->drawRect( QRectF( 0, 0, mW, mH ) ); } diff --git a/glabels/Outline.cpp b/glabels/Outline.cpp index fdbadb6..2cedc6d 100644 --- a/glabels/Outline.cpp +++ b/glabels/Outline.cpp @@ -28,7 +28,7 @@ namespace { - const qreal dashSize = 1; + const qreal dashSize = 2; const double slopPixels = 2; const double outlineWidthPixels = 1; @@ -78,10 +78,10 @@ void glabels::Outline::draw( QPainter* painter ) const painter->setBrush( Qt::NoBrush ); painter->setPen( mPen1 ); - painter->drawRect( 0, 0, mOwner->w(), mOwner->h() ); + painter->drawRect( QRectF( 0, 0, mOwner->w(), mOwner->h() ) ); painter->setPen( mPen2 ); - painter->drawRect( 0, 0, mOwner->w(), mOwner->h() ); + painter->drawRect( QRectF( 0, 0, mOwner->w(), mOwner->h() ) ); painter->restore(); } diff --git a/glabels/View.cpp b/glabels/View.cpp index a79c6ee..e8fd640 100644 --- a/glabels/View.cpp +++ b/glabels/View.cpp @@ -282,6 +282,10 @@ glabels::View::paintEvent( QPaintEvent* event ) { QPainter painter( this ); + painter.setRenderHint( QPainter::Antialiasing, true ); + painter.setRenderHint( QPainter::TextAntialiasing, true ); + painter.setRenderHint( QPainter::SmoothPixmapTransform, true ); + painter.scale( mZoom, mZoom ); drawBgLayer( &painter ); @@ -327,9 +331,11 @@ glabels::View::mouseMoveEvent( QMouseEvent* event ) transform.scale( mZoom, mZoom ); - qreal xWorld, yWorld; - transform.inverted().map( event->x(), event->y(), &xWorld, &yWorld ); + QPointF pWorld = transform.inverted().map( event->posF() ); + double xWorld = pWorld.x(); + double yWorld = pWorld.y(); + /* * Emit signal regardless of mode */ @@ -375,7 +381,8 @@ glabels::View::mouseMoveEvent( QMouseEvent* event ) break; case ArrowResize: - /* @TODO handle resize motion */ + handleResizeMotion( xWorld, yWorld ); + update(); break; default: @@ -435,10 +442,11 @@ glabels::View::mousePressEvent( QMouseEvent* event ) transform.scale( mZoom, mZoom ); - qreal xWorld, yWorld; - transform.inverted().map( event->x(), event->y(), &xWorld, &yWorld ); - + QPointF pWorld = transform.inverted().map( event->posF() ); + double xWorld = pWorld.x(); + double yWorld = pWorld.y(); + if ( event->button() & Qt::LeftButton ) { // @@ -452,7 +460,14 @@ glabels::View::mousePressEvent( QMouseEvent* event ) if ( mModel->isSelectionAtomic() && (handle = mModel->handleAt( mZoom, xWorld, yWorld )) != 0 ) { - // TODO PREP RESIZE + // + // Start an object resize + // + mResizeObject = handle->owner(); + mResizeHandle = handle; + mResizeHonorAspect = event->modifiers() & Qt::ControlModifier; + + mState = ArrowResize; } else if ( (object = mModel->objectAt( mZoom, xWorld, yWorld )) != 0 ) { @@ -536,10 +551,11 @@ glabels::View::mouseReleaseEvent( QMouseEvent* event ) transform.scale( mZoom, mZoom ); - qreal xWorld, yWorld; - transform.inverted().map( event->x(), event->y(), &xWorld, &yWorld ); - + QPointF pWorld = transform.inverted().map( event->posF() ); + double xWorld = pWorld.x(); + double yWorld = pWorld.y(); + if ( event->button() & Qt::LeftButton ) { // @@ -552,6 +568,10 @@ glabels::View::mouseReleaseEvent( QMouseEvent* event ) switch (mState) { + case ArrowResize: + mState = IdleState; + break; + case ArrowSelectRegion: mSelectRegionVisible = false; mSelectRegion.setX2( xWorld ); @@ -593,6 +613,140 @@ glabels::View::leaveEvent( QEvent* event ) } +/// +/// Handle resize motion +/// +void +glabels::View::handleResizeMotion( double xWorld, double yWorld ) +{ + QPointF p( xWorld, yWorld ); + Handle::Location location = mResizeHandle->location(); + + /* + * Change to item relative coordinates + */ + p -= QPointF( mResizeObject->x0(), mResizeObject->y0() ); + p = mResizeObject->matrix().map( p ); + + /* + * Initialize origin and 2 corners in object relative coordinates. + */ + double x0 = 0.0; + double y0 = 0.0; + + double x1 = 0.0; + double y1 = 0.0; + + double x2 = mResizeObject->w(); + double y2 = mResizeObject->h(); + + /* + * Calculate new size + */ + double w, h; + switch ( location ) + { + case Handle::NW: + w = std::max( x2 - p.x(), 0.0 ); + h = std::max( y2 - p.y(), 0.0 ); + break; + case Handle::N: + w = x2 - x1; + h = std::max( y2 - p.y(), 0.0 ); + break; + case Handle::NE: + w = std::max( p.x() - x1, 0.0 ); + h = std::max( y2 - p.y(), 0.0 ); + break; + case Handle::E: + w = std::max( p.x() - x1, 0.0 ); + h = y2 - y1; + break; + case Handle::SE: + w = std::max( p.x() - x1, 0.0 ); + h = std::max( p.y() - y1, 0.0 ); + break; + case Handle::S: + w = x2 - x1; + h = std::max( p.y() - y1, 0.0 ); + break; + case Handle::SW: + w = std::max( x2 - p.x(), 0.0 ); + h = std::max( p.y() - y1, 0.0 ); + break; + case Handle::W: + w = std::max( x2 - p.x(), 0.0 ); + h = y2 - y1; + break; + case Handle::P1: + x1 = p.x(); + y1 = p.y(); + w = x2 - p.x(); + h = y2 - p.y(); + x0 = x0 + x1; + y0 = y0 + y1; + break; + case Handle::P2: + w = p.x() - x1; + h = p.y() - y1; + x0 = x0 + x1; + y0 = y0 + y1; + break; + default: + Q_ASSERT_X( false, "View::handleResizeMotion", "Invalid Handle Location" ); + } + + /* + * Set size + */ + if ( !(location == Handle::P1) && !(location == Handle::P2) ) + { + if ( mResizeHonorAspect ) + { + mResizeObject->setSizeHonorAspect( w, h ); + } + else + { + mResizeObject->setSize( w, h ); + } + + /* + * Adjust origin, if needed. + */ + switch ( location ) + { + case Handle::NW: + x0 += x2 - mResizeObject->w(); + y0 += y2 - mResizeObject->h(); + break; + case Handle::N: + case Handle::NE: + y0 += y2 - mResizeObject->h(); + break; + case Handle::W: + case Handle::SW: + x0 += x2 - mResizeObject->w(); + break; + defaule: + break; + } + } + else + { + mResizeObject->setSize( w, h ); + } + + /* + * Put new origin back into world coordinates and set. + */ + QTransform inverseMatrix = mResizeObject->matrix().inverted(); + QPointF p0( x0, y0 ); + p0 = inverseMatrix.map( p0 ); + p0 += QPointF( mResizeObject->x0(), mResizeObject->y0() ); + mResizeObject->setPosition( p0.x(), p0.y() ); +} + + /// /// Draw Background Layer /// diff --git a/glabels/View.h b/glabels/View.h index 8eb3a3b..df4a76d 100644 --- a/glabels/View.h +++ b/glabels/View.h @@ -32,6 +32,7 @@ namespace glabels // Forward References class LabelModel; class LabelModelObject; + class Handle; /// @@ -134,9 +135,7 @@ namespace glabels void drawHighlightLayer( QPainter* painter ); void drawSelectRegionLayer( QPainter* painter ); - void handleResizeMotion( QPainter* painter, - double xPixels, - double yPixels ); + void handleResizeMotion( double xWorld, double yWorld ); ///////////////////////////////////// @@ -189,7 +188,9 @@ namespace glabels double mMoveLastY; /* ArrowResize state */ - /* @TODO */ + LabelModelObject* mResizeObject; + Handle* mResizeHandle; + bool mResizeHonorAspect; /* CreateDrag state */ bool mInObjectCreateMode;