From 27306808fb37bb3f9289f62289cc46d2fcbade0f Mon Sep 17 00:00:00 2001 From: Jim Evins Date: Thu, 29 Dec 2016 14:59:22 -0500 Subject: [PATCH] Initial implementation of text object. --- glabels/CMakeLists.txt | 3 + glabels/EnumUtil.cpp | 121 ++++++++ glabels/EnumUtil.h | 44 +++ glabels/LabelEditor.cpp | 18 +- glabels/LabelModelObject.cpp | 32 ++ glabels/LabelModelObject.h | 9 + glabels/LabelModelTextObject.cpp | 502 +++++++++++++++++++++++++++++++ glabels/LabelModelTextObject.h | 171 +++++++++++ glabels/MainWindow.cpp | 3 +- glabels/ObjectEditor.cpp | 77 +++++ glabels/ObjectEditor.h | 7 + glabels/XmlLabelCreator.cpp | 69 ++++- glabels/XmlLabelCreator.h | 2 +- glabels/XmlLabelParser.cpp | 89 +++++- glabels/XmlLabelParser.h | 2 +- glabels/ui/ObjectEditor.ui | 104 ++++--- 16 files changed, 1202 insertions(+), 51 deletions(-) create mode 100644 glabels/EnumUtil.cpp create mode 100644 glabels/EnumUtil.h create mode 100644 glabels/LabelModelTextObject.cpp create mode 100644 glabels/LabelModelTextObject.h diff --git a/glabels/CMakeLists.txt b/glabels/CMakeLists.txt index 5fdd1c2..2de2816 100644 --- a/glabels/CMakeLists.txt +++ b/glabels/CMakeLists.txt @@ -25,6 +25,7 @@ set (glabels_sources ColorPaletteButtonItem.cpp ColorSwatch.cpp Cursors.cpp + EnumUtil.cpp FieldButton.cpp FieldMenu.cpp FieldMenuItem.cpp @@ -40,6 +41,7 @@ set (glabels_sources LabelModelImageObject.cpp LabelModelLineObject.cpp LabelModelShapeObject.cpp + LabelModelTextObject.cpp LabelRegion.cpp MainWindow.cpp MergeView.cpp @@ -85,6 +87,7 @@ set (glabels_qobject_headers LabelModelImageObject.h LabelModelLineObject.h LabelModelShapeObject.h + LabelModelTextObject.h MainWindow.h MergeView.h ObjectEditor.h diff --git a/glabels/EnumUtil.cpp b/glabels/EnumUtil.cpp new file mode 100644 index 0000000..80c0ec8 --- /dev/null +++ b/glabels/EnumUtil.cpp @@ -0,0 +1,121 @@ +/* EnumUtil.cpp + * + * Copyright (C) 2015 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 "EnumUtil.h" + + +namespace EnumUtil +{ + + QString weightToString( QFont::Weight weight ) + { + switch (weight) + { + case QFont::Bold: + return "bold"; + break; + default: + return "normal"; + break; + } + } + + + QFont::Weight stringToWeight( const QString& string ) + { + if ( string == "bold" ) + { + return QFont::Bold; + } + else + { + return QFont::Normal; + } + } + + + QString hAlignToString( Qt::Alignment align ) + { + switch (align) + { + case Qt::AlignRight: + return "right"; + break; + case Qt::AlignHCenter: + return "center"; + break; + default: + return "left"; + break; + } + } + + + Qt::Alignment stringToHAlign( const QString& string ) + { + if ( string == "right" ) + { + return Qt::AlignRight; + } + else if ( string == "center" ) + { + return Qt::AlignHCenter; + } + else + { + return Qt::AlignLeft; + } + } + + + QString vAlignToString( Qt::Alignment align ) + { + switch (align) + { + case Qt::AlignBottom: + return "bottom"; + break; + case Qt::AlignVCenter: + return "center"; + break; + default: + return "top"; + break; + } + } + + + Qt::Alignment stringToVAlign( const QString& string ) + { + if ( string == "bottom" ) + { + return Qt::AlignBottom; + } + else if ( string == "center" ) + { + return Qt::AlignVCenter; + } + else + { + return Qt::AlignTop; + } + } + +} diff --git a/glabels/EnumUtil.h b/glabels/EnumUtil.h new file mode 100644 index 0000000..8e729fb --- /dev/null +++ b/glabels/EnumUtil.h @@ -0,0 +1,44 @@ +/* FileUtil.h + * + * Copyright (C) 2015 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 EnumUtil_h +#define EnumUtil_h + +#include +#include +#include + + +namespace EnumUtil +{ + + QString weightToString( QFont::Weight weight ); + QFont::Weight stringToWeight( const QString& string ); + + QString hAlignToString( Qt::Alignment align ); + Qt::Alignment stringToHAlign( const QString& string ); + + QString vAlignToString( Qt::Alignment align ); + Qt::Alignment stringToVAlign( const QString& string ); + +} + + +#endif // EnumUtil_h diff --git a/glabels/LabelEditor.cpp b/glabels/LabelEditor.cpp index 422e9af..af2fc96 100644 --- a/glabels/LabelEditor.cpp +++ b/glabels/LabelEditor.cpp @@ -30,6 +30,7 @@ #include "LabelModelEllipseObject.h" #include "LabelModelImageObject.h" #include "LabelModelLineObject.h" +#include "LabelModelTextObject.h" #include "UndoRedoModel.h" #include "Settings.h" #include "Cursors.h" @@ -363,6 +364,19 @@ LabelEditor::createLineMode() } +/// +/// Create text mode +/// +void +LabelEditor::createTextMode() +{ + setCursor( Cursors::Text() ); + + mCreateObjectType = Text; + mState = CreateIdle; +} + + /// /// Resize Event Handler /// @@ -505,7 +519,7 @@ LabelEditor::mousePressEvent( QMouseEvent* event ) mCreateObject = new LabelModelImageObject(); break; case Text: - // mCreateObject = new LabelModelTextObject(); + mCreateObject = new LabelModelTextObject(); break; case Barcode: // mCreateObject = new LabelModelBarcodeObject(); @@ -705,7 +719,7 @@ LabelEditor::mouseReleaseEvent( QMouseEvent* event ) switch (mCreateObjectType) { case Text: - mCreateObject->setSize( 0, 0 ); + mCreateObject->setSize( 72, 36 ); break; case Line: mCreateObject->setSize( 72, 0 ); diff --git a/glabels/LabelModelObject.cpp b/glabels/LabelModelObject.cpp index b6837f0..e77ade4 100644 --- a/glabels/LabelModelObject.cpp +++ b/glabels/LabelModelObject.cpp @@ -203,6 +203,7 @@ void LabelModelObject::setW( const glabels::Distance& value ) if ( mW != value ) { mW = value; + sizeUpdated(); emit changed(); } } @@ -225,6 +226,7 @@ void LabelModelObject::setH( const glabels::Distance& value ) if ( mH != value ) { mH = value; + sizeUpdated(); emit changed(); } } @@ -362,6 +364,25 @@ void LabelModelObject::setShadowColorNode( const ColorNode& value ) } +/// +/// Virtual Text Property Default Getter +/// (Overridden by concrete class) +/// +QString LabelModelObject::text() const +{ + return ""; +} + + +/// +/// Virtual Text Property Default Setter +/// (Overridden by concrete class) +/// +void LabelModelObject::setText( const QString& value ) +{ +} + + /// /// Virtual Font Family Property Default Getter /// (Overridden by concrete class) @@ -804,6 +825,7 @@ void LabelModelObject::setSize( const glabels::Distance& w, mW = w; mH = h; + sizeUpdated(); emit changed(); } @@ -844,6 +866,7 @@ void LabelModelObject::setWHonorAspect( const glabels::Distance& w ) mW = w; mH = h; + sizeUpdated(); emit changed(); } } @@ -862,6 +885,7 @@ void LabelModelObject::setHHonorAspect( const glabels::Distance& h ) mW = w; mH = h; + sizeUpdated(); emit changed(); } } @@ -1039,3 +1063,11 @@ void LabelModelObject::drawSelectionHighlight( QPainter* painter, double scale ) painter->restore(); } + + +/// +/// Default sizeUpdated implementation. +/// +void LabelModelObject::sizeUpdated() +{ +} diff --git a/glabels/LabelModelObject.h b/glabels/LabelModelObject.h index 2829db2..7e4c4d7 100644 --- a/glabels/LabelModelObject.h +++ b/glabels/LabelModelObject.h @@ -161,6 +161,13 @@ public: // Text Properties Virtual Interface /////////////////////////////////////////////////////////////// public: + // + // Virtual Text Property: text + // + virtual QString text() const; + virtual void setText( const QString &value ); + + // // Virtual Text Property: fontFamily // @@ -346,6 +353,8 @@ protected: virtual void drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const = 0; virtual QPainterPath hoverPath( double scale ) const = 0; + virtual void sizeUpdated(); + /////////////////////////////////////////////////////////////// // Protected Members diff --git a/glabels/LabelModelTextObject.cpp b/glabels/LabelModelTextObject.cpp new file mode 100644 index 0000000..ab700b6 --- /dev/null +++ b/glabels/LabelModelTextObject.cpp @@ -0,0 +1,502 @@ +/* LabelModelTextObject.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 "LabelModelTextObject.h" + +#include +#include +#include +#include +#include + + +namespace +{ + const double marginPts = 3; +} + + +/// +/// Constructor +/// +LabelModelTextObject::LabelModelTextObject() +{ + mOutline = new Outline( this ); + + mHandles << new HandleNorthWest( this ); + mHandles << new HandleNorth( this ); + mHandles << new HandleNorthEast( this ); + mHandles << new HandleEast( this ); + mHandles << new HandleSouthEast( this ); + mHandles << new HandleSouth( this ); + mHandles << new HandleSouthWest( this ); + mHandles << new HandleWest( this ); + + mText = ""; + mFontFamily = "Sans"; + mFontSize = 10; + mFontWeight = QFont::Normal; + mFontItalicFlag = false; + mFontUnderlineFlag = false; + mTextColorNode = ColorNode( QColor( 0, 0, 0 ) ); + mTextHAlign = Qt::AlignLeft; + mTextVAlign = Qt::AlignTop; + mTextLineSpacing = 1; +} + + +/// +/// Copy constructor +/// +LabelModelTextObject::LabelModelTextObject( const LabelModelTextObject* object ) : LabelModelObject(object) +{ + mText = object->mText; + mFontFamily = object->mFontFamily; + mFontSize = object->mFontSize; + mFontWeight = object->mFontWeight; + mFontItalicFlag = object->mFontItalicFlag; + mFontUnderlineFlag = object->mFontUnderlineFlag; + mTextColorNode = object->mTextColorNode; + mTextHAlign = object->mTextHAlign; + mTextVAlign = object->mTextVAlign; + mTextLineSpacing = object->mTextLineSpacing; +} + + +/// +/// Destructor +/// +LabelModelTextObject::~LabelModelTextObject() +{ + delete mOutline; + + foreach( Handle* handle, mHandles ) + { + delete handle; + } + mHandles.clear(); +} + + +/// +/// Clone +/// +LabelModelTextObject* LabelModelTextObject::clone() const +{ + return new LabelModelTextObject( this ); +} + + +/// +/// Text Property Getter +/// +QString LabelModelTextObject::text( void ) const +{ + return mText; +} + + +/// +/// Text Property Setter +/// +void LabelModelTextObject::setText( const QString& value ) +{ + if ( mText != value ) + { + mText = value; + update(); + emit changed(); + } +} + + +/// +/// FontFamily Property Getter +/// +QString LabelModelTextObject::fontFamily( void ) const +{ + return mFontFamily; +} + + +/// +/// FontFamily Property Setter +/// +void LabelModelTextObject::setFontFamily( const QString& value ) +{ + if ( mFontFamily != value ) + { + mFontFamily = value; + update(); + emit changed(); + } +} + + +/// +/// FontSize Property Getter +/// +double LabelModelTextObject::fontSize( void ) const +{ + return mFontSize; +} + + +/// +/// FontSize Property Setter +/// +void LabelModelTextObject::setFontSize( double value ) +{ + if ( mFontSize != value ) + { + mFontSize = value; + update(); + emit changed(); + } +} + + +/// +/// FontWeight Property Getter +/// +QFont::Weight LabelModelTextObject::fontWeight( void ) const +{ + return mFontWeight; +} + + +/// +/// FontWeight Property Setter +/// +void LabelModelTextObject::setFontWeight( QFont::Weight value ) +{ + if ( mFontWeight != value ) + { + mFontWeight = value; + update(); + emit changed(); + } +} + + +/// +/// FontItalicFlag Property Getter +/// +bool LabelModelTextObject::fontItalicFlag( void ) const +{ + return mFontItalicFlag; +} + + +/// +/// FontItalicFlag Property Setter +/// +void LabelModelTextObject::setFontItalicFlag( bool value ) +{ + if ( mFontItalicFlag != value ) + { + mFontItalicFlag = value; + update(); + emit changed(); + } +} + + +/// +/// FontUnderlineFlag Property Getter +/// +bool LabelModelTextObject::fontUnderlineFlag( void ) const +{ + return mFontUnderlineFlag; +} + + +/// +/// FontUnderlineFlag Property Setter +/// +void LabelModelTextObject::setFontUnderlineFlag( bool value ) +{ + if ( mFontUnderlineFlag != value ) + { + mFontUnderlineFlag = value; + update(); + emit changed(); + } +} + + +/// +/// Text Color Node Property Getter +/// +ColorNode LabelModelTextObject::textColorNode( void ) const +{ + return mTextColorNode; +} + + +/// +/// Text Color Node Property Setter +/// +void LabelModelTextObject::setTextColorNode( const ColorNode& value ) +{ + if ( mTextColorNode != value ) + { + mTextColorNode = value; + update(); + emit changed(); + } +} + + +/// +/// TextHAlign Property Getter +/// +Qt::Alignment LabelModelTextObject::textHAlign( void ) const +{ + return mTextHAlign; +} + + +/// +/// TextHAlign Property Setter +/// +void LabelModelTextObject::setTextHAlign( Qt::Alignment value ) +{ + if ( mTextHAlign != value ) + { + mTextHAlign = value; + update(); + emit changed(); + } +} + + +/// +/// TextVAlign Property Getter +/// +Qt::Alignment LabelModelTextObject::textVAlign( void ) const +{ + return mTextVAlign; +} + + +/// +/// TextVAlign Property Setter +/// +void LabelModelTextObject::setTextVAlign( Qt::Alignment value ) +{ + if ( mTextVAlign != value ) + { + mTextVAlign = value; + update(); + emit changed(); + } +} + + +/// +/// TextLineSpacing Property Getter +/// +double LabelModelTextObject::textLineSpacing( void ) const +{ + return mTextLineSpacing; +} + + +/// +/// TextLineSpacing Property Setter +/// +void LabelModelTextObject::setTextLineSpacing( double value ) +{ + if ( mTextLineSpacing != value ) + { + mTextLineSpacing = value; + update(); + emit changed(); + } +} + + +/// +// Can Text Capability Implementation +/// +bool LabelModelTextObject::canText() +{ + return true; +} + + +/// +/// Draw shadow of object +/// +void LabelModelTextObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record ) const +{ + QColor textColor = mTextColorNode.color( record ); + + if ( textColor.alpha() ) + { + QColor shadowColor = mShadowColorNode.color( record ); + shadowColor.setAlphaF( mShadowOpacity ); + + if ( inEditor ) + { + drawTextReal( painter, shadowColor ); + } + } +} + + +/// +/// Draw object itself +/// +void LabelModelTextObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record ) const +{ + QColor textColor = mTextColorNode.color( record ); + + if ( inEditor ) + { + drawTextReal( painter, textColor ); + } +} + + +/// +/// Path to test for hover condition +/// +QPainterPath LabelModelTextObject::hoverPath( double scale ) const +{ + return mHoverPath; +} + + +/// +/// Size updated +/// +void LabelModelTextObject::sizeUpdated() +{ + update(); +} + + +/// +/// Update cached information +/// +void LabelModelTextObject::update() +{ + QFont font; + font.setFamily( mFontFamily ); + font.setPointSizeF( mFontSize ); + font.setWeight( mFontWeight ); + font.setItalic( mFontItalicFlag ); + font.setUnderline( mFontUnderlineFlag ); + + QTextOption textOption; + textOption.setAlignment( mTextHAlign ); + textOption.setWrapMode( QTextOption::WordWrap ); + + QFontMetricsF fontMetrics( font ); + double dy = fontMetrics.lineSpacing() * mTextLineSpacing; + + QString displayText = mText.isEmpty() ? tr("Text") : mText; + QTextDocument document( displayText ); + + qDeleteAll( mEditorLayouts ); + mEditorLayouts.clear(); + + // Pass #1 -- do initial layouts + double x = 0; + double y = 0; + QRectF boundingRect; + for ( int i = 0; i < document.blockCount(); i++ ) + { + QTextLayout* layout = new QTextLayout( document.findBlockByNumber(i).text() ); + + layout->setFont( font ); + layout->setTextOption( textOption ); + layout->setCacheEnabled(true); + + layout->beginLayout(); + for ( QTextLine l = layout->createLine(); l.isValid(); l = layout->createLine() ) + { + l.setLineWidth( mW.pt() - 2*marginPts ); + l.setPosition( QPointF( x, y ) ); + y += dy; + } + layout->endLayout(); + + mEditorLayouts.append( layout ); + + boundingRect = layout->boundingRect().united( boundingRect ); + } + double h = boundingRect.height(); + + + // Pass #2 -- adjust layout positions for vertical alignment and create hover path + x = marginPts; + switch ( mTextVAlign ) + { + case Qt::AlignVCenter: + y = mH.pt()/2 - h/2; + break; + case Qt::AlignBottom: + y = mH.pt() - h - marginPts; + break; + default: + y = marginPts; + break; + } + QPainterPath hoverPath; // new empty hover path + foreach ( QTextLayout* layout, mEditorLayouts ) + { + for ( int j = 0; j < layout->lineCount(); j++ ) + { + QTextLine l = layout->lineAt(j); + l.setPosition( QPointF( x, y ) ); + y += dy; + + hoverPath.addRect( l.naturalTextRect() ); // add to new hover path + } + } + + mHoverPath = hoverPath; // save new hover path +} + + +/// +/// Actually draw text +/// +void LabelModelTextObject::drawTextReal( QPainter* painter, const QColor& color ) const +{ + if ( mText.isEmpty() ) + { + QColor mutedColor = color; + mutedColor.setAlphaF( 0.5 * color.alphaF() ); + painter->setPen( QPen( mutedColor ) ); + } + else + { + painter->setPen( QPen( color ) ); + } + + foreach ( QTextLayout* layout, mEditorLayouts ) + { + layout->draw( painter, QPointF( 0, 0 ) ); + } +} diff --git a/glabels/LabelModelTextObject.h b/glabels/LabelModelTextObject.h new file mode 100644 index 0000000..d649917 --- /dev/null +++ b/glabels/LabelModelTextObject.h @@ -0,0 +1,171 @@ +/* LabelModelTextObject.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 LabelModelTextObject_h +#define LabelModelTextObject_h + +#include "LabelModelObject.h" + +#include + + +/// +/// Label Model Line Object +/// +class LabelModelTextObject : public LabelModelObject +{ + Q_OBJECT + + /////////////////////////////////////////////////////////////// + // Lifecycle Methods + /////////////////////////////////////////////////////////////// +public: + LabelModelTextObject(); + LabelModelTextObject( const LabelModelTextObject* object ); + virtual ~LabelModelTextObject(); + + + /////////////////////////////////////////////////////////////// + // Object duplication + /////////////////////////////////////////////////////////////// + virtual LabelModelTextObject* clone() const; + + + /////////////////////////////////////////////////////////////// + // Property Implementations + /////////////////////////////////////////////////////////////// +public: + // + // Text Property: text + // + virtual QString text() const; + virtual void setText( const QString &value ); + + + // + // Text Property: fontFamily + // + virtual QString fontFamily() const; + virtual void setFontFamily( const QString &value ); + + + // + // Text Property: fontSize + // + virtual double fontSize() const; + virtual void setFontSize( double value ); + + + // + // Text Property: fontWeight + // + virtual QFont::Weight fontWeight() const; + virtual void setFontWeight( QFont::Weight value ); + + + // + // Text Property: fontItalicFlag + // + virtual bool fontItalicFlag() const; + virtual void setFontItalicFlag( bool value ); + + + // + // Text Property: fontUnderlineFlag + // + virtual bool fontUnderlineFlag() const; + virtual void setFontUnderlineFlag( bool value ); + + + // + // Text Property: textColorNode + // + virtual ColorNode textColorNode() const; + virtual void setTextColorNode( const ColorNode &value ); + + + // + // Text Property: textHAlign + // + virtual Qt::Alignment textHAlign() const; + virtual void setTextHAlign( Qt::Alignment value ); + + + // + // Text Property: textVAlign + // + virtual Qt::Alignment textVAlign() const; + virtual void setTextVAlign( Qt::Alignment value ); + + + // + // Text Property: textLineSpacing + // + virtual double textLineSpacing() const; + virtual void setTextLineSpacing( double value ); + + + /////////////////////////////////////////////////////////////// + // Capability Implementations + /////////////////////////////////////////////////////////////// +public: + virtual bool canText(); + + + /////////////////////////////////////////////////////////////// + // 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 methods + /////////////////////////////////////////////////////////////// +private: + virtual void sizeUpdated(); + void update(); + void drawTextReal( QPainter* painter, const QColor& color ) const; + + + /////////////////////////////////////////////////////////////// + // Private Members + /////////////////////////////////////////////////////////////// +private: + QString mText; + QString mFontFamily; + double mFontSize; + QFont::Weight mFontWeight; + bool mFontItalicFlag; + bool mFontUnderlineFlag; + ColorNode mTextColorNode; + Qt::Alignment mTextHAlign; + Qt::Alignment mTextVAlign; + double mTextLineSpacing; + + QList mEditorLayouts; + QPainterPath mHoverPath; + +}; + + +#endif // LabelModelTextObject_h diff --git a/glabels/MainWindow.cpp b/glabels/MainWindow.cpp index 1da9e49..964808c 100644 --- a/glabels/MainWindow.cpp +++ b/glabels/MainWindow.cpp @@ -1231,7 +1231,8 @@ void MainWindow::objectsArrowMode() /// void MainWindow::objectsCreateText() { - qDebug() << "ACTION: objects->Create->Text"; + mUndoRedoModel->checkpoint( tr("Create Text") ); + mLabelEditor->createTextMode(); } diff --git a/glabels/ObjectEditor.cpp b/glabels/ObjectEditor.cpp index bdaf74d..7181c8e 100644 --- a/glabels/ObjectEditor.cpp +++ b/glabels/ObjectEditor.cpp @@ -27,6 +27,7 @@ #include "LabelModelEllipseObject.h" #include "LabelModelImageObject.h" #include "LabelModelLineObject.h" +#include "LabelModelTextObject.h" #include "UndoRedoModel.h" #include "Merge/Merge.h" @@ -46,8 +47,19 @@ ObjectEditor::ObjectEditor( QWidget *parent ) { setupUi( this ); + textHAlignGroup = new QButtonGroup( this ); + textHAlignGroup->addButton( textHAlignLeftToggle, Qt::AlignLeft ); + textHAlignGroup->addButton( textHAlignCenterToggle, Qt::AlignHCenter ); + textHAlignGroup->addButton( textHAlignRightToggle, Qt::AlignRight ); + + textVAlignGroup = new QButtonGroup( this ); + textVAlignGroup->addButton( textVAlignTopToggle, Qt::AlignTop ); + textVAlignGroup->addButton( textVAlignMiddleToggle, Qt::AlignVCenter ); + textVAlignGroup->addButton( textVAlignBottomToggle, Qt::AlignBottom ); + lineColorButton->init( "No line", QColor(0,0,0,0), QColor(0,0,0,255) ); fillColorButton->init( "No fill", QColor(0,0,0,0), QColor(0,0,0,255) ); + textColorButton->init( "Default", QColor(0,0,0,255), QColor(0,0,0,255) ); shadowColorButton->init( "Default", QColor(0,0,0,255), QColor(0,0,0,255) ); imageFieldCombo->setName( "Key" ); @@ -187,6 +199,28 @@ void ObjectEditor::loadLineSizePage() } +void ObjectEditor::loadTextPage() +{ + if ( mObject ) + { + mBlocked = true; + + textFontFamilyCombo->setCurrentText( mObject->fontFamily() ); + textFontSizeSpin->setValue( mObject->fontSize() ); + textFontBoldToggle->setChecked( mObject->fontWeight() == QFont::Bold ); + textFontItalicToggle->setChecked( mObject->fontItalicFlag() ); + textFontUnderlineToggle->setChecked( mObject->fontUnderlineFlag() ); + textColorButton->setColorNode( mObject->textColorNode() ); + textHAlignGroup->button( mObject->textHAlign() )->setChecked( true ); + textVAlignGroup->button( mObject->textVAlign() )->setChecked( true ); + textLineSpacingSpin->setValue( mObject->textLineSpacing() ); + textEdit->setText( mObject->text() ); + + mBlocked = false; + } +} + + void ObjectEditor::loadShadowPage() { if ( mObject ) @@ -339,6 +373,25 @@ void ObjectEditor::onSelectionChanged() setEnabled( true ); } + else if ( dynamic_cast(mObject) ) + { + titleImageLabel->setPixmap( QPixmap(":icons/24x24/actions/glabels-text.png") ); + titleLabel->setText( tr("Text object properties") ); + + notebook->addTab( textPage, "text" ); + notebook->addTab( posSizePage, "position/size" ); + notebook->addTab( shadowPage, "shadow" ); + + sizeRectFrame->setVisible( true ); + sizeResetImageButton->setVisible( false ); + sizeLineFrame->setVisible( false ); + + loadTextPage(); + loadPositionPage(); + loadShadowPage(); + + setEnabled( true ); + } else { Q_ASSERT_X( false, "ObjectEditor::onSelectionChanged", "Invalid object" ); @@ -524,6 +577,30 @@ void ObjectEditor::onLineSizeControlsChanged() } +void ObjectEditor::onTextControlsChanged() +{ + if ( !mBlocked ) + { + mBlocked = true; + + mUndoRedoModel->checkpoint( tr("Text") ); + + mObject->setFontFamily( textFontFamilyCombo->currentText() ); + mObject->setFontSize( textFontSizeSpin->value() ); + mObject->setFontWeight( textFontBoldToggle->isChecked() ? QFont::Bold : QFont::Normal ); + mObject->setFontItalicFlag( textFontItalicToggle->isChecked() ); + mObject->setFontUnderlineFlag( textFontUnderlineToggle->isChecked() ); + mObject->setTextColorNode( textColorButton->colorNode() ); + mObject->setTextHAlign( Qt::AlignmentFlag( textHAlignGroup->checkedId() ) ); + mObject->setTextVAlign( Qt::AlignmentFlag( textVAlignGroup->checkedId() ) ); + mObject->setTextLineSpacing( textLineSpacingSpin->value() ); + mObject->setText( textEdit->toPlainText() ); + + mBlocked = false; + } +} + + void ObjectEditor::onShadowControlsChanged() { if ( !mBlocked ) diff --git a/glabels/ObjectEditor.h b/glabels/ObjectEditor.h index c986eb7..84c43c0 100644 --- a/glabels/ObjectEditor.h +++ b/glabels/ObjectEditor.h @@ -23,6 +23,8 @@ #include "ui_ObjectEditor.h" #include "libglabels/Distance.h" +#include + // Forward references class LabelModel; @@ -61,6 +63,7 @@ private: void loadPositionPage(); void loadRectSizePage(); void loadLineSizePage(); + void loadTextPage(); void loadShadowPage(); @@ -82,6 +85,7 @@ private slots: void onPositionControlsChanged(); void onRectSizeControlsChanged(); void onLineSizeControlsChanged(); + void onTextControlsChanged(); void onShadowControlsChanged(); void onChanged(); @@ -98,6 +102,9 @@ private: int mSpinDigits; double mSpinStep; + QButtonGroup* textHAlignGroup; + QButtonGroup* textVAlignGroup; + bool mBlocked; }; diff --git a/glabels/XmlLabelCreator.cpp b/glabels/XmlLabelCreator.cpp index 9eefaba..3ec05e6 100644 --- a/glabels/XmlLabelCreator.cpp +++ b/glabels/XmlLabelCreator.cpp @@ -25,14 +25,18 @@ #include "LabelModelBoxObject.h" #include "LabelModelEllipseObject.h" #include "LabelModelLineObject.h" -//#include "LabelObjectImage.h" -//#include "LabelObjectBarcode.h" +#include "LabelModelImageObject.h" +#include "LabelModelTextObject.h" +//#include "LabelModelBarcodeObject.h" +#include "EnumUtil.h" #include "Merge/None.h" #include "libglabels/XmlTemplateCreator.h" #include "libglabels/XmlUtil.h" #include #include +#include +#include #include @@ -92,6 +96,7 @@ XmlLabelCreator::createDoc( QDomDocument& doc, const LabelModel* label ) QDomElement root = doc.createElement( "Glabels-document" ); doc.appendChild( root ); + glabels::XmlUtil::setStringAttr( root, "version", "4.0" ); glabels::XmlTemplateCreator().createTemplateNode( root, label->tmplate() ); @@ -137,6 +142,10 @@ XmlLabelCreator::addObjectsToNode( QDomElement &parent, const QList(object) ) + { + createObjectTextNode( parent, textObject ); + } // TODO: other object types else { @@ -285,14 +294,64 @@ XmlLabelCreator::createObjectBarcodeNode( QDomElement &parent, const LabelModelB void XmlLabelCreator::createObjectTextNode( QDomElement &parent, const LabelModelTextObject* object ) { - // TODO + QDomDocument doc = parent.ownerDocument(); + QDomElement node = doc.createElement( "Object-text" ); + 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, "w", object->w() ); + glabels::XmlUtil::setLengthAttr( node, "h", object->h() ); + + /* color attr */ + if ( object->textColorNode().fieldFlag() ) + { + glabels::XmlUtil::setStringAttr( node, "color_field", object->textColorNode().key() ); + } + else + { + glabels::XmlUtil::setUIntAttr( node, "color", object->textColorNode().rgba() ); + } + + /* font attrs */ + glabels::XmlUtil::setStringAttr( node, "font_family", object->fontFamily() ); + glabels::XmlUtil::setDoubleAttr( node, "font_size", object->fontSize() ); + glabels::XmlUtil::setStringAttr( node, "font_weight", EnumUtil::weightToString( object->fontWeight() ) ); + glabels::XmlUtil::setBoolAttr( node, "font_italic", object->fontItalicFlag() ); + glabels::XmlUtil::setBoolAttr( node, "font_underline", object->fontUnderlineFlag() ); + + /* text attrs */ + glabels::XmlUtil::setDoubleAttr( node, "line_spacing", object->textLineSpacing() ); + glabels::XmlUtil::setStringAttr( node, "align", EnumUtil::hAlignToString( object->textHAlign() ) ); + glabels::XmlUtil::setStringAttr( node, "valign", EnumUtil::vAlignToString( object->textVAlign() ) ); + + /* affine attrs */ + createAffineAttrs( node, object ); + + /* shadow attrs */ + createShadowAttrs( node, object ); + + /* serialize text contents */ + QTextDocument document( object->text() ); + int nBlocks = document.blockCount(); + for ( int iBlock = 0; iBlock < nBlocks; iBlock++ ) + { + createPNode( node, document.findBlockByNumber(iBlock).text() ); + } } void -XmlLabelCreator::createObjectTopLevelSpanNode( QDomElement &parent, const LabelModelTextObject* object ) +XmlLabelCreator::createPNode( QDomElement &parent, const QString& blockText ) { - // TODO + QDomDocument doc = parent.ownerDocument(); + QDomElement node = doc.createElement( "p" ); + parent.appendChild( node ); + + node.appendChild( doc.createTextNode( blockText ) ); } diff --git a/glabels/XmlLabelCreator.h b/glabels/XmlLabelCreator.h index d1428f0..8326d64 100644 --- a/glabels/XmlLabelCreator.h +++ b/glabels/XmlLabelCreator.h @@ -59,7 +59,7 @@ private: static void createObjectImageNode( QDomElement &parent, const LabelModelImageObject* object ); static void createObjectBarcodeNode( QDomElement &parent, const LabelModelBarcodeObject* object ); static void createObjectTextNode( QDomElement &parent, const LabelModelTextObject* object ); - static void createObjectTopLevelSpanNode( QDomElement &parent, const LabelModelTextObject* object ); + static void createPNode( QDomElement &parent, const QString& blockText ); static void createAffineAttrs( QDomElement &node, const LabelModelObject* object ); static void createShadowAttrs( QDomElement &node, const LabelModelObject* object ); static void createMergeNode( QDomElement &parent, const LabelModel* label ); diff --git a/glabels/XmlLabelParser.cpp b/glabels/XmlLabelParser.cpp index b9f8032..ed191da 100644 --- a/glabels/XmlLabelParser.cpp +++ b/glabels/XmlLabelParser.cpp @@ -25,8 +25,10 @@ #include "LabelModelBoxObject.h" #include "LabelModelEllipseObject.h" #include "LabelModelLineObject.h" +#include "LabelModelTextObject.h" //#include "LabelObjectImage.h" //#include "LabelObjectBarcode.h" +#include "EnumUtil.h" #include "Merge/Factory.h" #include "libglabels/XmlTemplateParser.h" #include "libglabels/XmlUtil.h" @@ -34,6 +36,8 @@ #include #include #include +#include +#include #include @@ -200,6 +204,12 @@ XmlLabelParser::parseRootNode( const QDomElement &node ) { using namespace glabels; + QString version = XmlUtil::getStringAttr( node, "version", "" ); + if ( version != "4.0" ) + { + qWarning() << "TODO: compatability mode."; + } + LabelModel* label = new LabelModel(); /* Pass 1, extract data nodes to pre-load cache. */ @@ -270,6 +280,10 @@ XmlLabelParser::parseObjects( const QDomElement &node ) { list.append( parseObjectLineNode( child.toElement() ) ); } + else if ( tagName == "Object-text" ) + { + list.append( parseObjectTextNode( child.toElement() ) ); + } #if 0 else if ( tagName == "Object-image" ) { @@ -279,10 +293,6 @@ XmlLabelParser::parseObjects( const QDomElement &node ) { list.append( parseObjectBarcodeNode( child.toElement() ) ); } - else if ( tagName == "Object-text" ) - { - list.append( parseObjectTextNode( child.toElement() ) ); - } #endif else if ( !child.isComment() ) { @@ -449,13 +459,78 @@ XmlLabelParser::parseObjectBarcodeNode( const QDomElement &node ) LabelModelTextObject* XmlLabelParser::parseObjectTextNode( const QDomElement &node ) { - return 0; + using namespace glabels; + + LabelModelTextObject* object = new LabelModelTextObject(); + + + /* 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, "w", 0 ) ); + object->setH( XmlUtil::getLengthAttr( node, "h", 0 ) ); + + /* color attr */ + { + QString key = XmlUtil::getStringAttr( node, "color_field", "" ); + bool field_flag = !key.isEmpty(); + uint32_t color = XmlUtil::getUIntAttr( node, "color", 0 ); + + object->setTextColorNode( ColorNode( field_flag, color, key ) ); + } + + /* font attrs */ + object->setFontFamily( XmlUtil::getStringAttr( node, "font_family", "Sans" ) ); + object->setFontSize( XmlUtil::getDoubleAttr( node, "font_size", 10 ) ); + object->setFontWeight( EnumUtil::stringToWeight( XmlUtil::getStringAttr( node, "font_weight", "normal" ) ) ); + object->setFontItalicFlag( XmlUtil::getBoolAttr( node, "font_italic", false ) ); + object->setFontUnderlineFlag( XmlUtil::getBoolAttr( node, "font_underline", false ) ); + + /* text attrs */ + object->setTextLineSpacing( XmlUtil::getDoubleAttr( node, "line_spacing", 1 ) ); + object->setTextHAlign( EnumUtil::stringToHAlign( XmlUtil::getStringAttr( node, "align", "left" ) ) ); + object->setTextVAlign( EnumUtil::stringToVAlign( XmlUtil::getStringAttr( node, "valign", "top" ) ) ); + + /* affine attrs */ + parseAffineAttrs( node, object ); + + /* shadow attrs */ + parseShadowAttrs( node, object ); + + /* deserialize contents. */ + QTextDocument document; + QTextCursor cursor( &document ); + bool firstBlock = true; + for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() ) + { + QString tagName = child.toElement().tagName(); + + if ( tagName == "p" ) + { + if ( !firstBlock ) + { + cursor.insertBlock(); + } + firstBlock = false; + cursor.insertText( parsePNode( child.toElement() ) ); + } + else if ( !child.isComment() ) + { + qWarning() << "Unexpected" << node.tagName() << "child:" << tagName; + } + } + object->setText( document.toPlainText() ); + + return object; } -void -XmlLabelParser::parseTopLevelSpanNode( const QDomElement &node, LabelModelTextObject* object ) +QString +XmlLabelParser::parsePNode( const QDomElement &node ) { + return node.text(); } diff --git a/glabels/XmlLabelParser.h b/glabels/XmlLabelParser.h index f12f9ec..66ac126 100644 --- a/glabels/XmlLabelParser.h +++ b/glabels/XmlLabelParser.h @@ -59,7 +59,7 @@ private: static LabelModelImageObject* parseObjectImageNode( const QDomElement &node ); static LabelModelBarcodeObject* parseObjectBarcodeNode( const QDomElement &node ); static LabelModelTextObject* parseObjectTextNode( const QDomElement &node ); - static void parseTopLevelSpanNode( const QDomElement &node, LabelModelTextObject* object ); + static QString parsePNode( const QDomElement &node ); static void parseAffineAttrs( const QDomElement &node, LabelModelObject* object ); static void parseShadowAttrs( const QDomElement &node, LabelModelObject* object ); static void parseMergeNode( const QDomElement &node, LabelModel* label ); diff --git a/glabels/ui/ObjectEditor.ui b/glabels/ui/ObjectEditor.ui index 5732a7a..23cb08e 100644 --- a/glabels/ui/ObjectEditor.ui +++ b/glabels/ui/ObjectEditor.ui @@ -70,7 +70,7 @@ - 2 + 0 @@ -106,6 +106,9 @@ true + + true + false @@ -123,6 +126,9 @@ true + + true + @@ -137,6 +143,9 @@ true + + true + @@ -162,6 +171,9 @@ true + + true + false @@ -179,6 +191,9 @@ true + + true + @@ -193,6 +208,9 @@ true + + true + @@ -207,7 +225,14 @@ - + + + 3.000000000000000 + + + 0.010000000000000 + + @@ -352,7 +377,17 @@ - + + + 0 + + + 1.000000000000000 + + + 1.000000000000000 + + @@ -1519,7 +1554,7 @@ textFontFamilyCombo currentIndexChanged(int) ObjectEditor - onChanged() + onTextControlsChanged() 254 @@ -1535,7 +1570,7 @@ textFontSizeSpin valueChanged(double) ObjectEditor - onChanged() + onTextControlsChanged() 128 @@ -1551,7 +1586,7 @@ textFontBoldToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 125 @@ -1567,7 +1602,7 @@ textFontItalicToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 172 @@ -1583,7 +1618,7 @@ textFontUnderlineToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 236 @@ -1599,7 +1634,7 @@ textColorButton colorChanged() ObjectEditor - onChanged() + onTextControlsChanged() 138 @@ -1615,7 +1650,7 @@ textHAlignLeftToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 154 @@ -1631,7 +1666,7 @@ textHAlignCenterToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 219 @@ -1647,7 +1682,7 @@ textHAlignRightToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 271 @@ -1663,7 +1698,7 @@ textVAlignTopToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 161 @@ -1679,7 +1714,7 @@ textVAlignMiddleToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 209 @@ -1695,7 +1730,7 @@ textVAlignBottomToggle toggled(bool) ObjectEditor - onChanged() + onTextControlsChanged() 271 @@ -1711,7 +1746,7 @@ textLineSpacingSpin valueChanged(double) ObjectEditor - onChanged() + onTextControlsChanged() 180 @@ -1723,22 +1758,6 @@ - - textEdit - textChanged() - ObjectEditor - onChanged() - - - 271 - 538 - - - 394 - 543 - - - textInsertFieldButton keySelected() @@ -2130,8 +2149,8 @@ onImageFileButtonClicked() - 321 - 119 + 190 + 161 394 @@ -2155,6 +2174,22 @@ + + textEdit + textChanged() + ObjectEditor + onTextControlsChanged() + + + 341 + 539 + + + 398 + 553 + + + onChanged() @@ -2167,5 +2202,6 @@ onLineSizeControlsChanged() onImageFileButtonClicked() onImageKeySelected(QString) + onTextControlsChanged()