c298a43b2f
git-svn-id: https://svn.code.sf.net/p/qlscribe/svn/trunk@147 cac9541e-1b8d-4bfa-827e-589bba606050
375 lines
10 KiB
C++
375 lines
10 KiB
C++
/* qlscribe - Qt based application to print lightScribe discs
|
|
|
|
Copyright (C) 2009 Vyacheslav Kononenko <vyacheslav@kononenko.net>
|
|
|
|
This program 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 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
$Id$ */
|
|
|
|
#include "qlightroundtextitem.h"
|
|
#include "qdialogroundtext.h"
|
|
#include "qcdscene.h"
|
|
#include "qdialogsettings.h"
|
|
|
|
#include <QPainter>
|
|
#include <QFontMetrics>
|
|
#include <QStyleOptionGraphicsItem>
|
|
#include <QMessageBox>
|
|
#include <QXmlStreamWriter>
|
|
#include <QTextLayout>
|
|
#include <QGraphicsSceneMouseEvent>
|
|
|
|
#include <math.h>
|
|
|
|
QLightRoundTextItem::QLightRoundTextItem( QGraphicsItem *parent )
|
|
: QAbstractGraphicsShapeItem( parent ),
|
|
m_radius( 40.0 ),
|
|
m_angle( 0.0 ),
|
|
m_alignment( Qt::AlignLeft ),
|
|
m_outside( true )
|
|
{
|
|
setBrush( Qt::black );
|
|
}
|
|
|
|
const QFont & QLightRoundTextItem::font() const
|
|
{
|
|
return m_font;
|
|
}
|
|
|
|
const QString & QLightRoundTextItem::text() const
|
|
{
|
|
return m_text;
|
|
}
|
|
|
|
double QLightRoundTextItem::radius() const
|
|
{
|
|
return m_radius;
|
|
}
|
|
|
|
double QLightRoundTextItem::angle() const
|
|
{
|
|
return m_angle;
|
|
}
|
|
|
|
Qt::Alignment QLightRoundTextItem::alignment() const
|
|
{
|
|
return m_alignment;
|
|
}
|
|
|
|
bool QLightRoundTextItem::outside() const
|
|
{
|
|
return m_outside;
|
|
}
|
|
|
|
void QLightRoundTextItem::setFont( const QFont &font )
|
|
{
|
|
prepareGeometryChange();
|
|
m_font = font;
|
|
}
|
|
|
|
void QLightRoundTextItem::setText( const QString &text )
|
|
{
|
|
prepareGeometryChange();
|
|
m_text = text;
|
|
}
|
|
|
|
void QLightRoundTextItem::setRadius( double radius )
|
|
{
|
|
prepareGeometryChange();
|
|
m_radius = radius;
|
|
}
|
|
|
|
void QLightRoundTextItem::setAngle( double angle )
|
|
{
|
|
prepareGeometryChange();
|
|
m_angle = angle;
|
|
}
|
|
|
|
void QLightRoundTextItem::setAlignment( Qt::Alignment alignment )
|
|
{
|
|
prepareGeometryChange();
|
|
m_alignment = alignment;
|
|
}
|
|
|
|
void QLightRoundTextItem::setOutside( bool outside )
|
|
{
|
|
prepareGeometryChange();
|
|
m_outside = outside;
|
|
}
|
|
|
|
QRectF QLightRoundTextItem::boundingRect() const
|
|
{
|
|
double height = m_radius;
|
|
if( m_outside ) {
|
|
QFontMetrics mcs( m_font );
|
|
height += ( mcs.height() * 2 ) / 3;
|
|
}
|
|
height += 1; // pad
|
|
return QRectF( -height, -height, 2 * height, 2 * height );
|
|
}
|
|
|
|
QPainterPath QLightRoundTextItem::shape() const
|
|
{
|
|
QFont font( m_font );
|
|
font.setPointSizeF( m_font.pointSizeF() / 2 );
|
|
QFontMetrics mcs( font );
|
|
double arcAngle = 0.0;
|
|
const double pad = 1;
|
|
|
|
for( int i = 0; i < m_text.size(); ++i )
|
|
arcAngle += mcs.width( m_text[ i ] );
|
|
|
|
double height = ( mcs.height() * 2 ) / 3;
|
|
double in, out;
|
|
if( m_outside ) {
|
|
in = m_radius - pad;
|
|
out = m_radius + height + pad;
|
|
} else {
|
|
in = m_radius - height - pad;
|
|
out = m_radius + pad;
|
|
}
|
|
arcAngle /= in * 3.14159 / 180.0;
|
|
double padAngle = pad * 180.0 / ( in * 3.14159 );
|
|
|
|
int sign = m_outside ? 1 : -1;
|
|
|
|
double angle = m_angle;
|
|
switch( m_alignment ) {
|
|
case Qt::AlignCenter :
|
|
case Qt::AlignHCenter :
|
|
angle -= sign * arcAngle / 2;
|
|
break;
|
|
case Qt::AlignRight :
|
|
angle -= sign * arcAngle;
|
|
break;
|
|
}
|
|
|
|
QPainterPath path;
|
|
double radAngle = ( angle - sign * padAngle ) * 3.14159 / 180.0;
|
|
path.moveTo( sign * out * sin( radAngle ), -sign * out * cos( radAngle ) );
|
|
path.arcTo( -out, -out, out * 2, out * 2,
|
|
sign * ( 90 + padAngle ) - angle,
|
|
-sign * ( arcAngle + 2 * padAngle ) );
|
|
path.arcTo( -in, -in, in * 2, in * 2,
|
|
sign * ( 90 - padAngle - arcAngle ) - angle,
|
|
sign * ( arcAngle + 2 * padAngle ) );
|
|
path.closeSubpath();
|
|
|
|
return path;
|
|
}
|
|
|
|
|
|
void QLightRoundTextItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
|
|
{
|
|
Q_UNUSED( option );
|
|
Q_UNUSED( widget );
|
|
if( !painter || !m_radius ) return;
|
|
painter->save();
|
|
|
|
QFont font( m_font );
|
|
font.setPointSizeF( m_font.pointSizeF() / 2 );
|
|
painter->setFont( font );
|
|
|
|
//painter->drawEllipse( - m_radius, - m_radius, m_radius * 2, m_radius * 2 );
|
|
|
|
QFontMetrics mcs( font );
|
|
|
|
const double radi = m_radius - ( m_outside ? 0 : mcs.xHeight() );
|
|
const double diam = 2 * radi;
|
|
double angle = m_angle * 3.14159 / 180.0;
|
|
switch( m_alignment ) {
|
|
case Qt::AlignCenter :
|
|
case Qt::AlignHCenter :
|
|
angle += mcs.width( m_text ) / diam * ( m_outside ? -1 : 1 );
|
|
break;
|
|
case Qt::AlignRight :
|
|
angle += mcs.width( m_text ) / radi * ( m_outside ? -1 : 1 );
|
|
break;
|
|
}
|
|
|
|
QTransform trans;
|
|
trans.rotateRadians( angle );
|
|
painter->setRenderHint( QPainter::TextAntialiasing, true );
|
|
painter->setWorldTransform( trans, true );
|
|
|
|
QPen p;
|
|
p.setBrush( brush() );
|
|
painter->setPen( p );
|
|
painter->setBrush( Qt::NoBrush );
|
|
|
|
int prevWidth = 0;
|
|
for( int i = 0; i < m_text.size(); ++i ) {
|
|
QChar ch = m_text[ i ];
|
|
|
|
double d = ( prevWidth + mcs.width( ch ) ) / diam;
|
|
trans.reset();
|
|
trans.rotateRadians( m_outside ? d : -d );
|
|
painter->setWorldTransform( trans, true );
|
|
|
|
prevWidth = mcs.width( ch );
|
|
|
|
painter->drawText( int( -prevWidth / 2.0 ),
|
|
int( m_outside ? -m_radius : m_radius ),
|
|
ch );
|
|
}
|
|
painter->restore();
|
|
if (option->state & QStyle::State_Selected) {
|
|
painter->setPen( QPen( option->palette.windowText(), 0, Qt::DashLine ) );
|
|
painter->setBrush(Qt::NoBrush);
|
|
painter->drawPath( shape() );
|
|
}
|
|
}
|
|
|
|
inline
|
|
double distance( const QPointF &p1, const QPointF &p2 )
|
|
{
|
|
QPointF d = p1 - p2;
|
|
return sqrt( d.x() * d.x() + d.y() * d.y() );
|
|
}
|
|
|
|
inline
|
|
double angle( const QPointF &p1, const QPointF &p2 )
|
|
{
|
|
QPointF d = p1 - p2;
|
|
return atan2( d.y(), d.x() ) * 180.0 / 3.14159;
|
|
}
|
|
|
|
void QLightRoundTextItem::mouseMoveEvent( QGraphicsSceneMouseEvent *event )
|
|
{
|
|
if( event->buttons() & Qt::LeftButton ) {
|
|
double dradi = distance( scenePos(), event->lastScenePos() ) - distance( scenePos(), event->scenePos() );
|
|
double dangle = ::angle( scenePos(), event->lastScenePos() ) - ::angle( scenePos(), event->scenePos() );
|
|
|
|
prepareGeometryChange();
|
|
m_radius -= dradi;
|
|
m_angle -= dangle;
|
|
if( m_angle > 360.0 ) m_angle -= 360.0;
|
|
if( m_angle < 0.0 ) m_angle += 360.0;
|
|
|
|
static_cast<QCDScene *>( scene() )->itemMoved();
|
|
} else
|
|
event->ignore();
|
|
}
|
|
|
|
|
|
RegisterController< QShapeControllerRoundText > regControllerRoundText;
|
|
|
|
QString QShapeControllerRoundText::name() const
|
|
{
|
|
return "roundText";
|
|
}
|
|
|
|
QString QShapeControllerRoundText::menuName() const
|
|
{
|
|
return QObject::tr( "Round Text", "QShapeControllerRoundText name" );
|
|
}
|
|
|
|
QGraphicsItem *QShapeControllerRoundText::create() const
|
|
{
|
|
QLightRoundTextItem *item = new QLightRoundTextItem;
|
|
item->setFont( QDialogSettings::defaultFont() );
|
|
return item;
|
|
}
|
|
|
|
QItemDialog *QShapeControllerRoundText::createDialog( QWidget *parent ) const
|
|
{
|
|
return new QDialogRoundText( parent );
|
|
}
|
|
|
|
void QShapeControllerRoundText::replace( QGraphicsItem *item, const QString &from, const QString &to ) const
|
|
{
|
|
QLightRoundTextItem *textItem = static_cast< QLightRoundTextItem * >( item );
|
|
bool placeHolder = textItem->text().left( 1 ) == "?" && textItem->text().right( 1 ) == "?";
|
|
|
|
bool replace = false;
|
|
if( from.isEmpty() )
|
|
replace = placeHolder;
|
|
else
|
|
replace = textItem->text() == ( placeHolder ? QString( "?%1?" ).arg( from ) : from );
|
|
|
|
if( replace )
|
|
textItem->setText( to );
|
|
}
|
|
|
|
void QShapeControllerRoundText::writeData( QXmlStreamWriter &writer, const QGraphicsItem *item ) const
|
|
{
|
|
const QLightRoundTextItem *textItem = static_cast< const QLightRoundTextItem * >( item );
|
|
writer.writeEmptyElement( "pos" );
|
|
writer.writeAttribute( QXmlStreamAttribute( "x", QString::number( textItem->pos().x() ) ) );
|
|
writer.writeAttribute( QXmlStreamAttribute( "y", QString::number( textItem->pos().y() ) ) );
|
|
writer.writeAttribute( QXmlStreamAttribute( "z", QString::number( textItem->zValue() ) ) );
|
|
|
|
writer.writeTextElement( "radius", QString::number( textItem->radius() ) );
|
|
writer.writeTextElement( "angle", QString::number( textItem->angle() ) );
|
|
writer.writeTextElement( "alignment", QString::number( textItem->alignment() ) );
|
|
writer.writeTextElement( "location", QString::number( textItem->outside() ) );
|
|
writer.writeTextElement( "font", textItem->font().toString() );
|
|
writer.writeTextElement( "color", textItem->brush().color().name() );
|
|
writer.writeTextElement( "text", textItem->text() );
|
|
}
|
|
|
|
void QShapeControllerRoundText::readData( const QString &element,
|
|
const QXmlStreamAttributes &attrs,
|
|
const QString &data,
|
|
QGraphicsItem *item ) const
|
|
{
|
|
QLightRoundTextItem *textItem = static_cast< QLightRoundTextItem * >( item );
|
|
|
|
if( element == "pos" ) {
|
|
textItem->setPos( attrs.value( "x" ).toString().toDouble(),
|
|
attrs.value( "y" ).toString().toDouble() );
|
|
textItem->setZValue( attrs.value( "z" ).toString().toDouble() );
|
|
return;
|
|
}
|
|
|
|
if( element == "font" ) {
|
|
QFont font;
|
|
font.fromString( data );
|
|
textItem->setFont( font );
|
|
return;
|
|
}
|
|
|
|
if( element == "color" ) {
|
|
textItem->setBrush( QColor( data ) );
|
|
return;
|
|
}
|
|
|
|
if( element == "text" ) {
|
|
textItem->setText( data );
|
|
return;
|
|
}
|
|
|
|
if( element == "location" ) {
|
|
textItem->setOutside( data.toInt() );
|
|
return;
|
|
}
|
|
|
|
if( element == "radius" ) {
|
|
textItem->setRadius( data.toDouble() );
|
|
return;
|
|
}
|
|
|
|
if( element == "angle" ) {
|
|
textItem->setAngle( data.toDouble() );
|
|
return;
|
|
}
|
|
|
|
if( element == "alignment" ) {
|
|
textItem->setAlignment( Qt::Alignment( data.toInt() ) );
|
|
return;
|
|
}
|
|
}
|
|
|