From f447aed034f41fe229808bf594386f0b2f7a2a49 Mon Sep 17 00:00:00 2001 From: Jim Evins Date: Sat, 28 May 2016 18:50:02 -0400 Subject: [PATCH] Added line object implementation. --- glabels/CMakeLists.txt | 2 + glabels/LabelEditor.cpp | 16 ++- glabels/LabelModelLineObject.cpp | 199 +++++++++++++++++++++++++++++++ glabels/LabelModelLineObject.h | 94 +++++++++++++++ glabels/LabelModelObject.cpp | 10 +- glabels/MainWindow.cpp | 3 +- glabels/ObjectEditor.cpp | 67 ++++++++++- glabels/ObjectEditor.h | 2 + glabels/XmlLabelCreator.cpp | 35 +++++- glabels/XmlLabelParser.cpp | 35 +++++- glabels/ui/ObjectEditor.ui | 83 +++++++------ 11 files changed, 501 insertions(+), 45 deletions(-) create mode 100644 glabels/LabelModelLineObject.cpp create mode 100644 glabels/LabelModelLineObject.h diff --git a/glabels/CMakeLists.txt b/glabels/CMakeLists.txt index b4a91c0..5ba9916 100644 --- a/glabels/CMakeLists.txt +++ b/glabels/CMakeLists.txt @@ -37,6 +37,7 @@ set (glabels_sources LabelModelObject.cpp LabelModelBoxObject.cpp LabelModelEllipseObject.cpp + LabelModelLineObject.cpp LabelModelShapeObject.cpp LabelRegion.cpp MainWindow.cpp @@ -80,6 +81,7 @@ set (glabels_qobject_headers LabelModelObject.h LabelModelBoxObject.h LabelModelEllipseObject.h + LabelModelLineObject.h LabelModelShapeObject.h MainWindow.h MergeView.h diff --git a/glabels/LabelEditor.cpp b/glabels/LabelEditor.cpp index 6a964d2..a6dcb9d 100644 --- a/glabels/LabelEditor.cpp +++ b/glabels/LabelEditor.cpp @@ -29,6 +29,7 @@ #include "LabelModelObject.h" #include "LabelModelBoxObject.h" #include "LabelModelEllipseObject.h" +#include "LabelModelLineObject.h" #include "UndoRedoModel.h" #include "Settings.h" #include "Cursors.h" @@ -339,6 +340,19 @@ LabelEditor::createEllipseMode() } +/// +/// Create line mode +/// +void +LabelEditor::createLineMode() +{ + setCursor( Cursors::Line() ); + + mCreateObjectType = Line; + mState = CreateIdle; +} + + /// /// Resize Event Handler /// @@ -475,7 +489,7 @@ LabelEditor::mousePressEvent( QMouseEvent* event ) mCreateObject = new LabelModelEllipseObject(); break; case Line: - // mCreateObject = new LabelModelLineObject(); + mCreateObject = new LabelModelLineObject(); break; case Image: // mCreateObject = new LabelModelImageObject(); diff --git a/glabels/LabelModelLineObject.cpp b/glabels/LabelModelLineObject.cpp new file mode 100644 index 0000000..eb14288 --- /dev/null +++ b/glabels/LabelModelLineObject.cpp @@ -0,0 +1,199 @@ +/* LabelModelLineObject.cpp + * + * Copyright (C) 2013-2016 Jim Evins + * + * This file is part of gLabels-qt. + * + * gLabels-qt is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gLabels-qt 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gLabels-qt. If not, see . + */ + +#include "LabelModelLineObject.h" + +#include +#include + + +namespace +{ + const double slopPixels = 2; +} + + +/// +/// Constructor +/// +LabelModelLineObject::LabelModelLineObject() +{ + mOutline = 0; + + mHandles << new HandleP1( this ); + mHandles << new HandleP2( this ); + + mLineWidth = 1.0; + mLineColorNode = ColorNode( QColor( 0, 0, 0 ) ); +} + + +/// +/// Copy constructor +/// +LabelModelLineObject::LabelModelLineObject( const LabelModelLineObject* object ) : LabelModelObject(object) +{ + mLineWidth = object->mLineWidth; + mLineColorNode = object->mLineColorNode; +} + + +/// +/// Destructor +/// +LabelModelLineObject::~LabelModelLineObject() +{ + foreach( Handle* handle, mHandles ) + { + delete handle; + } + mHandles.clear(); +} + + +/// +/// Clone +/// +LabelModelLineObject* LabelModelLineObject::clone() const +{ + return new LabelModelLineObject( this ); +} + + +/// +/// Line Width Property Getter +/// +glabels::Distance LabelModelLineObject::lineWidth( void ) const +{ + return mLineWidth; +} + + +/// +/// Line Width Property Setter +/// +void LabelModelLineObject::setLineWidth( const glabels::Distance& value ) +{ + if ( mLineWidth != value ) + { + mLineWidth = value; + emit changed(); + } +} + + +/// +/// Line Color Node Property Getter +/// +ColorNode LabelModelLineObject::lineColorNode( void ) const +{ + return mLineColorNode; +} + + +/// +/// Line Color Node Property Setter +/// +void LabelModelLineObject::setLineColorNode( const ColorNode& value ) +{ + if ( mLineColorNode != value ) + { + mLineColorNode = value; + emit changed(); + } +} + + +/// +/// Can Line Color Capability Implementation +/// +bool LabelModelLineObject::canLineColor() +{ + return true; +} + + +/// +/// Can Line Width Capability Implementation +/// +bool LabelModelLineObject::canLineWidth() +{ + return true; +} + + +/// +/// Draw shadow of object +/// +void LabelModelLineObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const +{ + QColor lineColor = mLineColorNode.color( record ); + QColor shadowColor = mShadowColorNode.color( record ); + + shadowColor.setAlphaF( mShadowOpacity ); + + if ( lineColor.alpha() ) + { + painter->setPen( QPen( shadowColor, mLineWidth.pt() ) ); + painter->drawLine( 0, 0, mW.pt(), mH.pt() ); + } +} + + +/// +/// Draw object itself +/// +void LabelModelLineObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const +{ + QColor lineColor = mLineColorNode.color( record ); + + painter->setPen( QPen( lineColor, mLineWidth.pt() ) ); + painter->drawLine( 0, 0, mW.pt(), mH.pt() ); +} + + +/// +/// Path to test for hover condition +/// +QPainterPath LabelModelLineObject::hoverPath( double scale ) const +{ + QPainterPath path; + + if ( mLineColorNode.color().alpha() ) + { + // + // Build a thin rectangle representing line + // + double rPts = mLineWidth.pt()/2 + slopPixels / scale; + + double lengthPts = sqrt( mW.pt()*mW.pt() + mH.pt()*mH.pt() ); + double dx = mH.pt() / lengthPts; // horizontal pitch of perpendicular line + double dy = mW.pt() / lengthPts; // vertical pitch of perpendicular line + + path.moveTo( rPts*dx, - rPts*dy ); + path.lineTo( mW.pt() + rPts*dx, mH.pt() - rPts*dy ); + path.lineTo( mW.pt() - rPts*dx, mH.pt() + rPts*dy ); + path.lineTo( - rPts*dx, rPts*dy ); + + path.closeSubpath(); + } + + return path; +} diff --git a/glabels/LabelModelLineObject.h b/glabels/LabelModelLineObject.h new file mode 100644 index 0000000..412033d --- /dev/null +++ b/glabels/LabelModelLineObject.h @@ -0,0 +1,94 @@ +/* LabelModelLineObject.h + * + * Copyright (C) 2013-2016 Jim Evins + * + * This file is part of gLabels-qt. + * + * gLabels-qt is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gLabels-qt 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gLabels-qt. If not, see . + */ + +#ifndef LabelModelLineObject_h +#define LabelModelLineObject_h + +#include "LabelModelObject.h" + + +/// +/// Label Model Line Object +/// +class LabelModelLineObject : public LabelModelObject +{ + Q_OBJECT + + /////////////////////////////////////////////////////////////// + // Lifecycle Methods + /////////////////////////////////////////////////////////////// +public: + LabelModelLineObject(); + LabelModelLineObject( const LabelModelLineObject* object ); + virtual ~LabelModelLineObject(); + + + /////////////////////////////////////////////////////////////// + // Object duplication + /////////////////////////////////////////////////////////////// + virtual LabelModelLineObject* clone() const; + + + /////////////////////////////////////////////////////////////// + // Property Implementations + /////////////////////////////////////////////////////////////// +public: + // + // Line Property: lineWidth + // + virtual glabels::Distance lineWidth( void ) const; + virtual void setLineWidth( const glabels::Distance& value ); + + + // + // Line Property: lineColorNode + // + virtual ColorNode lineColorNode( void ) const; + virtual void setLineColorNode( const ColorNode& value ); + + + /////////////////////////////////////////////////////////////// + // Capability Implementations + /////////////////////////////////////////////////////////////// +public: + virtual bool canLineColor(); + virtual bool canLineWidth(); + + + /////////////////////////////////////////////////////////////// + // Drawing operations + /////////////////////////////////////////////////////////////// +protected: + virtual void drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const; + virtual void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const; + virtual QPainterPath hoverPath( double scale ) const; + + + /////////////////////////////////////////////////////////////// + // Private Members + /////////////////////////////////////////////////////////////// +protected: + glabels::Distance mLineWidth; + ColorNode mLineColorNode; + +}; + + +#endif // LabelModelLineObject_h diff --git a/glabels/LabelModelObject.cpp b/glabels/LabelModelObject.cpp index cbb3b26..eec422f 100644 --- a/glabels/LabelModelObject.cpp +++ b/glabels/LabelModelObject.cpp @@ -86,7 +86,15 @@ LabelModelObject::LabelModelObject( const LabelModelObject* object ) { mHandles.append( handle->clone( this ) ); } - mOutline = object->mOutline->clone( this ); + + if ( object->mOutline ) + { + mOutline = object->mOutline->clone( this ); + } + else + { + mOutline = 0; + } mMatrix = object->mMatrix; } diff --git a/glabels/MainWindow.cpp b/glabels/MainWindow.cpp index d3df0b4..88cc421 100644 --- a/glabels/MainWindow.cpp +++ b/glabels/MainWindow.cpp @@ -1235,7 +1235,8 @@ void MainWindow::objectsCreateBox() /// void MainWindow::objectsCreateLine() { - qDebug() << "ACTION: objects->Create->Line"; + mUndoRedoModel->checkpoint( tr("Create Line") ); + mLabelEditor->createLineMode(); } diff --git a/glabels/ObjectEditor.cpp b/glabels/ObjectEditor.cpp index 8849758..f50ee80 100644 --- a/glabels/ObjectEditor.cpp +++ b/glabels/ObjectEditor.cpp @@ -25,6 +25,7 @@ #include "LabelModelObject.h" #include "LabelModelBoxObject.h" #include "LabelModelEllipseObject.h" +#include "LabelModelLineObject.h" #include "UndoRedoModel.h" #include "Merge/Merge.h" @@ -140,6 +141,26 @@ void ObjectEditor::loadRectSizePage() } +void ObjectEditor::loadLineSizePage() +{ + if ( mObject ) + { + mBlocked = true; + + sizeLineLengthSpin->setDecimals( mSpinDigits ); + sizeLineLengthSpin->setSingleStep( mSpinStep ); + sizeLineLengthSpin->setSuffix( " " + mUnits.toIdString() ); + + double w = mObject->w().inUnits(mUnits); + double h = mObject->h().inUnits(mUnits); + sizeLineLengthSpin->setValue( sqrt( w*w + h*h ) ); + sizeLineAngleSpin->setValue( (180/M_PI)*atan2( h, w ) ); + + mBlocked = false; + } +} + + void ObjectEditor::loadShadowPage() { if ( mObject ) @@ -213,12 +234,13 @@ void ObjectEditor::onSelectionChanged() if ( dynamic_cast(mObject) ) { titleImageLabel->setPixmap( QPixmap(":icons/24x24/actions/glabels-box.png") ); - titleLabel->setText( "Box object properties" ); + titleLabel->setText( tr("Box object properties") ); notebook->addTab( lineFillPage, "line/fill" ); notebook->addTab( posSizePage, "position/size" ); notebook->addTab( shadowPage, "shadow" ); + fillFrame->setVisible( true ); sizeRectFrame->setVisible( true ); sizeResetImageButton->setVisible( false ); sizeLineFrame->setVisible( false ); @@ -233,12 +255,13 @@ void ObjectEditor::onSelectionChanged() else if ( dynamic_cast(mObject) ) { titleImageLabel->setPixmap( QPixmap(":icons/24x24/actions/glabels-ellipse.png") ); - titleLabel->setText( "Ellipse object properties" ); + titleLabel->setText( tr("Ellipse object properties") ); notebook->addTab( lineFillPage, "line/fill" ); notebook->addTab( posSizePage, "position/size" ); notebook->addTab( shadowPage, "shadow" ); + fillFrame->setVisible( true ); sizeRectFrame->setVisible( true ); sizeResetImageButton->setVisible( false ); sizeLineFrame->setVisible( false ); @@ -250,6 +273,27 @@ void ObjectEditor::onSelectionChanged() setEnabled( true ); } + else if ( dynamic_cast(mObject) ) + { + titleImageLabel->setPixmap( QPixmap(":icons/24x24/actions/glabels-line.png") ); + titleLabel->setText( tr("Line object properties") ); + + notebook->addTab( lineFillPage, "line/fill" ); + notebook->addTab( posSizePage, "position/size" ); + notebook->addTab( shadowPage, "shadow" ); + + fillFrame->setVisible( false ); + sizeRectFrame->setVisible( false ); + sizeResetImageButton->setVisible( false ); + sizeLineFrame->setVisible( true ); + + loadLineFillPage(); + loadPositionPage(); + loadLineSizePage(); + loadShadowPage(); + + setEnabled( true ); + } else { Q_ASSERT_X( false, "ObjectEditor::onSelectionChanged", "Invalid object" ); @@ -288,6 +332,7 @@ void ObjectEditor::onObjectChanged() { loadLineFillPage(); loadRectSizePage(); + loadLineSizePage(); loadShadowPage(); } } @@ -392,6 +437,24 @@ void ObjectEditor::onRectSizeControlsChanged() } +void ObjectEditor::onLineSizeControlsChanged() +{ + if ( !mBlocked ) + { + mBlocked = true; + + mUndoRedoModel->checkpoint( tr("Size") ); + + glabels::Distance spinLength = glabels::Distance(sizeLineLengthSpin->value(), mUnits); + double spinAngleRads = (M_PI/180)*sizeLineAngleSpin->value(); + + mObject->setSize( spinLength*cos(spinAngleRads), spinLength*sin(spinAngleRads) ); + + mBlocked = false; + } +} + + void ObjectEditor::onShadowControlsChanged() { if ( !mBlocked ) diff --git a/glabels/ObjectEditor.h b/glabels/ObjectEditor.h index 673de42..6df4f2a 100644 --- a/glabels/ObjectEditor.h +++ b/glabels/ObjectEditor.h @@ -59,6 +59,7 @@ private: void loadLineFillPage(); void loadPositionPage(); void loadRectSizePage(); + void loadLineSizePage(); void loadShadowPage(); @@ -77,6 +78,7 @@ private slots: void onFillControlsChanged(); void onPositionControlsChanged(); void onRectSizeControlsChanged(); + void onLineSizeControlsChanged(); void onShadowControlsChanged(); void onChanged(); diff --git a/glabels/XmlLabelCreator.cpp b/glabels/XmlLabelCreator.cpp index e4902d8..9eefaba 100644 --- a/glabels/XmlLabelCreator.cpp +++ b/glabels/XmlLabelCreator.cpp @@ -24,7 +24,7 @@ #include "LabelModelObject.h" #include "LabelModelBoxObject.h" #include "LabelModelEllipseObject.h" -//#include "LabelObjectLine.h" +#include "LabelModelLineObject.h" //#include "LabelObjectImage.h" //#include "LabelObjectBarcode.h" #include "Merge/None.h" @@ -133,6 +133,10 @@ XmlLabelCreator::addObjectsToNode( QDomElement &parent, const QList(object) ) + { + createObjectLineNode( parent, lineObject ); + } // TODO: other object types else { @@ -233,7 +237,34 @@ XmlLabelCreator::createObjectEllipseNode( QDomElement &parent, const LabelModelE void XmlLabelCreator::createObjectLineNode( QDomElement &parent, const LabelModelLineObject* object ) { - // TODO + QDomDocument doc = parent.ownerDocument(); + QDomElement node = doc.createElement( "Object-line" ); + parent.appendChild( node ); + + /* position attrs */ + glabels::XmlUtil::setLengthAttr( node, "x", object->x0() ); + glabels::XmlUtil::setLengthAttr( node, "y", object->y0() ); + + /* size attrs */ + glabels::XmlUtil::setLengthAttr( node, "dx", object->w() ); + glabels::XmlUtil::setLengthAttr( node, "dy", object->h() ); + + /* line attrs */ + glabels::XmlUtil::setLengthAttr( node, "line_width", object->lineWidth() ); + if ( object->lineColorNode().fieldFlag() ) + { + glabels::XmlUtil::setStringAttr( node, "line_color_field", object->lineColorNode().key() ); + } + else + { + glabels::XmlUtil::setUIntAttr( node, "line_color", object->lineColorNode().rgba() ); + } + + /* affine attrs */ + createAffineAttrs( node, object ); + + /* shadow attrs */ + createShadowAttrs( node, object ); } diff --git a/glabels/XmlLabelParser.cpp b/glabels/XmlLabelParser.cpp index d752238..b9f8032 100644 --- a/glabels/XmlLabelParser.cpp +++ b/glabels/XmlLabelParser.cpp @@ -24,7 +24,7 @@ #include "LabelModelObject.h" #include "LabelModelBoxObject.h" #include "LabelModelEllipseObject.h" -//#include "LabelObjectLine.h" +#include "LabelModelLineObject.h" //#include "LabelObjectImage.h" //#include "LabelObjectBarcode.h" #include "Merge/Factory.h" @@ -266,11 +266,11 @@ XmlLabelParser::parseObjects( const QDomElement &node ) { list.append( parseObjectEllipseNode( child.toElement() ) ); } -#if 0 else if ( tagName == "Object-line" ) { list.append( parseObjectLineNode( child.toElement() ) ); } +#if 0 else if ( tagName == "Object-image" ) { list.append( parseObjectImageNode( child.toElement() ) ); @@ -399,7 +399,36 @@ XmlLabelParser::parseObjectEllipseNode( const QDomElement &node ) LabelModelLineObject* XmlLabelParser::parseObjectLineNode( const QDomElement &node ) { - return 0; + using namespace glabels; + + LabelModelLineObject* object = new LabelModelLineObject(); + + + /* position attrs */ + object->setX0( XmlUtil::getLengthAttr( node, "x", 0.0 ) ); + object->setY0( XmlUtil::getLengthAttr( node, "y", 0.0 ) ); + + /* size attrs */ + object->setW( XmlUtil::getLengthAttr( node, "dx", 0 ) ); + object->setH( XmlUtil::getLengthAttr( node, "dy", 0 ) ); + + /* line attrs */ + object->setLineWidth( XmlUtil::getLengthAttr( node, "line_width", 1.0 ) ); + { + QString key = XmlUtil::getStringAttr( node, "line_color_field", "" ); + bool field_flag = !key.isEmpty(); + uint32_t color = XmlUtil::getUIntAttr( node, "line_color", 0 ); + + object->setLineColorNode( ColorNode( field_flag, color, key ) ); + } + + /* affine attrs */ + parseAffineAttrs( node, object ); + + /* shadow attrs */ + parseShadowAttrs( node, object ); + + return object; } diff --git a/glabels/ui/ObjectEditor.ui b/glabels/ui/ObjectEditor.ui index 916db70..ccae3f8 100644 --- a/glabels/ui/ObjectEditor.ui +++ b/glabels/ui/ObjectEditor.ui @@ -944,7 +944,7 @@ - + Fill @@ -1253,6 +1253,18 @@ ° + + 1 + + + -180.000000000000000 + + + 180.000000000000000 + + + 0.100000000000000 + @@ -1948,8 +1960,8 @@ onPositionControlsChanged() - 90 - 112 + 153 + 132 399 @@ -2021,38 +2033,6 @@ - - sizeLineLengthSpin - valueChanged(double) - ObjectEditor - onChanged() - - - 129 - 391 - - - 395 - 568 - - - - - sizeLineAngleSpin - valueChanged(double) - ObjectEditor - onChanged() - - - 113 - 437 - - - 404 - 628 - - - shadowEnableCheck toggled(bool) @@ -2133,6 +2113,38 @@ + + sizeLineLengthSpin + valueChanged(double) + ObjectEditor + onLineSizeControlsChanged() + + + 144 + 386 + + + 5 + 471 + + + + + sizeLineAngleSpin + valueChanged(double) + ObjectEditor + onLineSizeControlsChanged() + + + 120 + 437 + + + 1 + 510 + + + onChanged() @@ -2142,5 +2154,6 @@ onPositionControlsChanged() onRectSizeControlsChanged() onShadowControlsChanged() + onLineSizeControlsChanged()