/* ModelBarcodeObject.cpp * * Copyright (C) 2017 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 "ModelBarcodeObject.h" #include "Size.h" #include "barcode/Backends.h" #include "glbarcode/Factory.h" #include "glbarcode/QtRenderer.h" #include #include #include #include #include #include namespace glabels { namespace model { // // Private // namespace { const QColor fillColor = QColor( 224, 224, 224, 255 ); const Distance pad = Distance::pt(4); const Distance minW = Distance::pt(18); const Distance minH = Distance::pt(18); } /// /// Constructor /// ModelBarcodeObject::ModelBarcodeObject() { 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 ); mBcStyle = barcode::Backends::defaultStyle(); mBcTextFlag = mBcStyle.canText(); mBcChecksumFlag = mBcStyle.canChecksum(); mBcFormatDigits = mBcStyle.preferedN(); mBcData = ""; mBcColorNode = ColorNode( Qt::black ); mEditorBarcode = nullptr; mEditorDefaultBarcode = nullptr; update(); // Initialize cached editor layouts } /// /// Constructor /// ModelBarcodeObject::ModelBarcodeObject( const Distance& x0, const Distance& y0, const Distance& w, const Distance& h, const barcode::Style& bcStyle, bool bcTextFlag, bool bcChecksumFlag, QString bcData, const ColorNode& bcColorNode, const QMatrix& matrix ) : ModelObject( x0, y0, w, h, matrix ) { 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 ); mBcStyle = bcStyle; mBcTextFlag = bcTextFlag; mBcChecksumFlag = bcChecksumFlag; mBcFormatDigits = mBcStyle.preferedN(); mBcData = bcData; mBcColorNode = bcColorNode; mEditorBarcode = nullptr; mEditorDefaultBarcode = nullptr; update(); // Initialize cached editor layouts } /// /// Copy constructor /// ModelBarcodeObject::ModelBarcodeObject( const ModelBarcodeObject* object ) : ModelObject(object) { mBcStyle = object->mBcStyle; mBcTextFlag = object->mBcTextFlag; mBcChecksumFlag = object->mBcChecksumFlag; mBcFormatDigits = object->mBcFormatDigits; mBcData = object->mBcData; mBcColorNode = object->mBcColorNode; mEditorBarcode = nullptr; mEditorDefaultBarcode = nullptr; update(); // Initialize cached editor layouts } /// /// Destructor /// ModelBarcodeObject::~ModelBarcodeObject() { delete mOutline; foreach( Handle* handle, mHandles ) { delete handle; } mHandles.clear(); delete mEditorBarcode; } /// /// Clone /// ModelBarcodeObject* ModelBarcodeObject::clone() const { return new ModelBarcodeObject( this ); } /// /// bcData Property Getter /// QString ModelBarcodeObject::bcData() const { return mBcData.toString(); } /// /// bcData Property Setter /// void ModelBarcodeObject::setBcData( const QString& value ) { if ( mBcData.toString() != value ) { mBcData = value; update(); emit changed(); } } /// /// bcTextFlag Property Getter /// bool ModelBarcodeObject::bcTextFlag() const { return mBcTextFlag; } /// /// bcTextFlag Property Setter /// void ModelBarcodeObject::setBcTextFlag( bool value ) { if ( mBcTextFlag != value ) { mBcTextFlag = value; update(); emit changed(); } } /// /// bcChecksumFlag Property Getter /// bool ModelBarcodeObject::bcChecksumFlag() const { return mBcChecksumFlag; } /// /// bcChecksumFlag Property Setter /// void ModelBarcodeObject::setBcChecksumFlag( bool value ) { if ( mBcChecksumFlag != value ) { mBcChecksumFlag = value; update(); emit changed(); } } /// /// Barcode Color Node Property Getter /// ColorNode ModelBarcodeObject::bcColorNode() const { return mBcColorNode; } /// /// Barcode Color Node Property Setter /// void ModelBarcodeObject::setBcColorNode( const ColorNode& value ) { if ( mBcColorNode != value ) { mBcColorNode = value; update(); emit changed(); } } /// /// Barcode Style Property Getter /// barcode::Style ModelBarcodeObject::bcStyle() const { return mBcStyle; } /// /// Barcode Style Property Setter /// void ModelBarcodeObject::setBcStyle( const barcode::Style& value ) { if ( mBcStyle != value ) { mBcStyle = value; update(); emit changed(); } } /// /// Barcode Format Digits Property Getter /// int ModelBarcodeObject::bcFormatDigits() const { return mBcFormatDigits; } /// /// Barcode Format Digits Property Setter /// void ModelBarcodeObject::setBcFormatDigits( int value ) { if ( mBcFormatDigits != value ) { mBcFormatDigits = value; update(); emit changed(); } } /// /// Draw shadow of object /// void ModelBarcodeObject::drawShadow( QPainter* painter, bool inEditor, merge::Record* record, Variables* variables ) const { // Barcodes don't support shadows. } /// /// Draw object itself /// void ModelBarcodeObject::drawObject( QPainter* painter, bool inEditor, merge::Record* record, Variables* variables ) const { QColor bcColor = mBcColorNode.color( record, variables ); if ( inEditor ) { drawBcInEditor( painter, bcColor ); } else { drawBc( painter, bcColor, record, variables ); } } /// /// Path to test for hover condition /// QPainterPath ModelBarcodeObject::hoverPath( double scale ) const { return mHoverPath; } /// /// Size updated /// void ModelBarcodeObject::sizeUpdated() { update(); } /// /// Update cached information for editor view /// void ModelBarcodeObject::update() { // // Build barcode from data // if ( mEditorBarcode ) { delete mEditorBarcode; } mEditorBarcode = glbarcode::Factory::createBarcode( mBcStyle.fullId().toStdString() ); if ( !mEditorBarcode ) { qWarning() << "Invalid barcode style" << mBcStyle.fullId() << "using \"code39\"."; mBcStyle = barcode::Backends::defaultStyle(); mEditorBarcode = glbarcode::Factory::createBarcode( mBcStyle.id().toStdString() ); } mEditorBarcode->setChecksum(mBcChecksumFlag); mEditorBarcode->setShowText(mBcTextFlag); mEditorBarcode->build( mBcData.toStdString(), mW.pt(), mH.pt() ); // // Build a place holder barcode to display in editor, if cannot display actual barcode // if ( mEditorDefaultBarcode ) { delete mEditorDefaultBarcode; } mEditorDefaultBarcode = glbarcode::Factory::createBarcode( mBcStyle.fullId().toStdString() ); if ( !mEditorDefaultBarcode ) { qWarning() << "Invalid barcode style" << mBcStyle.fullId() << "using \"code39\"."; mBcStyle = barcode::Backends::defaultStyle(); mEditorDefaultBarcode = glbarcode::Factory::createBarcode( mBcStyle.id().toStdString() ); } mEditorDefaultBarcode->setChecksum(mBcChecksumFlag); mEditorDefaultBarcode->setShowText(mBcTextFlag); mEditorDefaultBarcode->build( mBcStyle.defaultDigits().toStdString(), mW.pt(), mH.pt() ); // // Adjust size // if ( mEditorBarcode->isDataValid() ) { mW = Distance::pt( mEditorBarcode->width() ); mH = Distance::pt( mEditorBarcode->height() ); } else { mW = Distance::pt( mEditorDefaultBarcode->width() ); mH = Distance::pt( mEditorDefaultBarcode->height() ); } QPainterPath path; path.addRect( 0, 0, mW.pt(), mH.pt() ); mHoverPath = path; } /// /// Draw barcode in editor from cached information /// void ModelBarcodeObject::drawBcInEditor( QPainter* painter, const QColor& color ) const { if ( mBcData.isEmpty() ) { drawPlaceHolder( painter, color, tr("No barcode data") ); } else if ( mBcData.hasPlaceHolders() ) { drawPlaceHolder( painter, color, mBcData.toString() ); } else if ( mEditorBarcode->isDataValid() ) { painter->setPen( QPen( color ) ); glbarcode::QtRenderer renderer(painter); mEditorBarcode->render( renderer ); } else { drawPlaceHolder( painter, color, tr("Invalid barcode data") ); } } /// /// Draw barcode in final printout or preview /// void ModelBarcodeObject::drawBc( QPainter* painter, const QColor& color, merge::Record* record, Variables* variables ) const { painter->setPen( QPen( color ) ); glbarcode::Barcode* bc = glbarcode::Factory::createBarcode( mBcStyle.fullId().toStdString() ); bc->setChecksum(mBcChecksumFlag); bc->setShowText(mBcTextFlag); bc->build( mBcData.expand( record, variables ).toStdString(), mW.pt(), mH.pt() ); glbarcode::QtRenderer renderer(painter); bc->render( renderer ); } /// /// Draw barcode place holder in editor /// void ModelBarcodeObject::drawPlaceHolder( QPainter* painter, const QColor& color, const QString& text ) const { QString shortText = text.left( 32 ); // Don't let the text get out of hand // // Render box // painter->setPen( Qt::NoPen ); painter->setBrush( QBrush( fillColor ) ); painter->drawRect( QRectF( 0, 0, mW.pt(), mH.pt() ) ); // // Render default barcode // painter->setPen( QPen( color ) ); glbarcode::QtRenderer renderer(painter); mEditorDefaultBarcode->render( renderer ); // // Determine font size for text // QFont font( "Sans" ); font.setPointSizeF( 6 ); QFontMetricsF fm( font ); QRectF textRect = fm.boundingRect( shortText ); double wPts = (mW - 2*pad).pt(); double hPts = (mH - 2*pad).pt(); if ( (wPts < textRect.width()) || (hPts < textRect.height()) ) { double scaleX = wPts / textRect.width(); double scaleY = hPts / textRect.height(); font.setPointSizeF( 6 * std::min( scaleX, scaleY ) ); } // // Render hole for text (font size may have changed above) // fm = QFontMetricsF( font ); textRect = fm.boundingRect( shortText ); QRectF holeRect( (mW.pt() - textRect.width())/2 - pad.pt(), (mH.pt() - textRect.height())/2 - pad.pt(), textRect.width() + 2*pad.pt(), textRect.height() + 2*pad.pt() ); painter->setPen( Qt::NoPen ); painter->setBrush( QBrush( fillColor ) ); painter->drawRect( holeRect ); // // Render text // painter->setFont( font ); painter->setPen( QPen( color ) ); painter->drawText( QRectF( 0, 0, mW.pt(), mH.pt() ), Qt::AlignCenter, shortText ); } } }