Element editor : hover a primitve will highlight it with a blue halo

git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@3694 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
blacksun
2015-02-09 08:57:40 +00:00
parent c5036dfb17
commit 9c6499813c
32 changed files with 1741 additions and 1443 deletions

View File

@@ -110,26 +110,26 @@ CustomElementPart *ArcEditor::currentPart() const {
*/
void ArcEditor::updateArc() {
if (!part) return;
part -> setProperty("x", x -> value());
part -> setProperty("y", y -> value());
part -> setProperty("centerX", x -> value());
part -> setProperty("centerY", y -> value());
part -> setProperty("diameter_h", h -> value());
part -> setProperty("diameter_v", v -> value());
part -> setProperty("start_angle", -start_angle -> value() + 90);
part -> setProperty("angle", -angle -> value());
part -> setProperty("startAngle", ((start_angle -> value() * -1) + 90) * 16);
part -> setProperty("spanAngle", angle -> value() * -16);
}
/// Met a jour l'abscisse du centre de l'arc et cree un objet d'annulation
void ArcEditor::updateArcX() { addChangePartCommand(tr("abscisse"), part, "x", x -> value()); }
void ArcEditor::updateArcX() { addChangePartCommand(tr("abscisse"), part, "centerX", x -> value()); }
/// Met a jour l'ordonnee du centre de l'arc et cree un objet d'annulation
void ArcEditor::updateArcY() { addChangePartCommand(tr("ordonn\351e"), part, "y", y -> value()); }
void ArcEditor::updateArcY() { addChangePartCommand(tr("ordonn\351e"), part, "centerY", y -> value()); }
/// Met a jour le diametre horizontal de l'arc et cree un objet d'annulation
void ArcEditor::updateArcH() { addChangePartCommand(tr("diam\350tre horizontal"), part, "diameter_h", h -> value()); }
/// Met a jour le diametre vertical de l'arc et cree un objet d'annulation
void ArcEditor::updateArcV() { addChangePartCommand(tr("diam\350tre vertical"), part, "diameter_v", v -> value()); }
/// Met a jour l'angle de depart de l'arc et cree un objet d'annulation
void ArcEditor::updateArcS() { addChangePartCommand(tr("angle de d\351part"), part, "start_angle", -start_angle -> value() + 90); }
void ArcEditor::updateArcS() { addChangePartCommand(tr("angle de d\351part"), part, "startAngle", ((start_angle -> value() * -1) + 90) * 16); }
/// Met a jour l'etendue de l'arc et cree un objet d'annulation
void ArcEditor::updateArcA() { addChangePartCommand(tr("angle"), part, "angle", -angle -> value()); }
void ArcEditor::updateArcA() { addChangePartCommand(tr("angle"), part, "spanAngle", angle -> value() * -16); }
/**
Met a jour le formulaire d'edition
@@ -141,8 +141,8 @@ void ArcEditor::updateForm() {
y->setValue(part->property("y").toReal());
h->setValue(part->property("diameter_h").toReal());
v->setValue(part->property("diameter_v").toReal());
start_angle -> setValue(-part -> startAngle() + 90);
angle -> setValue(-part -> angle());
start_angle -> setValue(((part->property("startAngle").toInt() / 16) - 90) * -1);
angle -> setValue(part->property("spanAngle").toInt() / -16);
activeConnections(true);
}

View File

@@ -567,8 +567,7 @@ void ChangeInformationsCommand::redo() {
ScalePartsCommand::ScalePartsCommand(ElementScene *scene, QUndoCommand * parent) :
ElementEditionCommand(scene, 0, parent),
first_redo(true)
{
}
{}
/**
Destructor

View File

@@ -849,15 +849,15 @@ ElementContent ElementScene::loadContent(const QDomDocument &xml_document, QStri
QDomElement qde = n.toElement();
if (qde.isNull()) continue;
CustomElementPart *cep;
if (qde.tagName() == "line") cep = new PartLine (element_editor, 0, 0);
else if (qde.tagName() == "rect") cep = new PartRectangle(element_editor, 0, 0);
else if (qde.tagName() == "ellipse") cep = new PartEllipse (element_editor, 0, 0);
else if (qde.tagName() == "circle") cep = new PartEllipse (element_editor, 0, 0);
else if (qde.tagName() == "polygon") cep = new PartPolygon (element_editor, 0, 0);
else if (qde.tagName() == "terminal") cep = new PartTerminal (element_editor, 0, 0);
else if (qde.tagName() == "text") cep = new PartText (element_editor, 0, 0);
else if (qde.tagName() == "input") cep = new PartTextField(element_editor, 0, 0);
else if (qde.tagName() == "arc") cep = new PartArc (element_editor, 0, 0);
if (qde.tagName() == "line") cep = new PartLine (element_editor);
else if (qde.tagName() == "rect") cep = new PartRectangle(element_editor);
else if (qde.tagName() == "ellipse") cep = new PartEllipse (element_editor);
else if (qde.tagName() == "circle") cep = new PartEllipse (element_editor);
else if (qde.tagName() == "polygon") cep = new PartPolygon (element_editor);
else if (qde.tagName() == "terminal") cep = new PartTerminal (element_editor);
else if (qde.tagName() == "text") cep = new PartText (element_editor);
else if (qde.tagName() == "input") cep = new PartTextField(element_editor);
else if (qde.tagName() == "arc") cep = new PartArc (element_editor);
else continue;
if (QGraphicsItem *qgi = dynamic_cast<QGraphicsItem *>(cep)) {
if (!qgi -> zValue()) qgi -> setZValue(z++);

View File

@@ -102,16 +102,16 @@ CustomElementPart *EllipseEditor::currentPart() const {
*/
void EllipseEditor::updateEllipse() {
if (!part) return;
part -> setProperty("x", x -> value());
part -> setProperty("y", y -> value());
part -> setProperty("centerX", x -> value());
part -> setProperty("centerY", y -> value());
part -> setProperty("diameter_h", h -> value());
part -> setProperty("diameter_v", v -> value());
}
/// Met a jour l'abscisse du centre de l'ellipse et cree un objet d'annulation
void EllipseEditor::updateEllipseX() { addChangePartCommand(tr("abscisse"), part, "x", x -> value()); }
void EllipseEditor::updateEllipseX() { addChangePartCommand(tr("abscisse"), part, "centerX", x -> value()); }
/// Met a jour l'ordonnee du centre de l'ellipse et cree un objet d'annulation
void EllipseEditor::updateEllipseY() { addChangePartCommand(tr("ordonn\351e"), part, "y", y -> value()); }
void EllipseEditor::updateEllipseY() { addChangePartCommand(tr("ordonn\351e"), part, "centerY", y -> value()); }
/// Met a jour le diametre horizontal de l'ellipse et cree un objet d'annulation
void EllipseEditor::updateEllipseH() { addChangePartCommand(tr("diam\350tre horizontal"), part, "diameter_h", h -> value()); }
/// Met a jour le diametre vertical de l'ellipse et cree un objet d'annulation
@@ -123,8 +123,8 @@ void EllipseEditor::updateEllipseV() { addChangePartCommand(tr("diam\350tre vert
void EllipseEditor::updateForm() {
if (!part) return;
activeConnections(false);
x->setValue(part->property("x").toReal());
y->setValue(part->property("y").toReal());
x->setValue(part->property("centerX").toReal());
y->setValue(part->property("centerY").toReal());
h->setValue(part->property("diameter_h").toReal());
v->setValue(part->property("diameter_v").toReal());
activeConnections(true);

View File

@@ -45,22 +45,27 @@ ESEventAddArc::~ESEventAddArc() {
* @param event
* @return
*/
bool ESEventAddArc::mousePressEvent(QGraphicsSceneMouseEvent *event) {
if (event -> button() == Qt::LeftButton) {
bool ESEventAddArc::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event -> button() == Qt::LeftButton)
{
if(!m_running) m_running = true;
QPointF pos = m_scene->snapToGrid(event -> scenePos());
//create new arc
if (!m_arc) {
m_arc = new PartArc(m_editor, 0, m_scene);
m_arc -> setRect(QRectF(pos, pos));
m_arc -> setAngle(90);
if (!m_arc)
{
m_arc = new PartArc(m_editor);
m_scene -> addItem(m_arc);
m_arc -> setPos(pos);
m_arc -> setProperty("startAngle", 0);
m_arc -> setProperty("spanAngle", 1440);
m_arc -> setProperty("antialias", true);
m_origin = pos;
return true;
}
//Add arc to scene
//At this point, m_arc is finish, we add it with an undo command
m_arc -> setRect(m_arc->rect().normalized());
m_scene -> undoStack().push(new AddPartCommand(QObject::tr("Arc"), m_scene, m_arc));
@@ -69,6 +74,7 @@ bool ESEventAddArc::mousePressEvent(QGraphicsSceneMouseEvent *event) {
return true;
}
return false;
}
@@ -120,67 +126,78 @@ bool ESEventAddArc::keyPressEvent(QKeyEvent *event) {
* @brief ESEventAddArc::updateArc
* Redraw the arc with curent value
*/
void ESEventAddArc::updateArc() {
void ESEventAddArc::updateArc()
{
qreal width = (m_mouse_pos.x() - m_origin.x())*2;
if (width < 0) width *= -1;
qreal height = (m_mouse_pos.y() - m_origin.y())*2;
if (height < 0) height *= -1;
QPointF pos_ = m_origin;
QPointF pos_ = m_arc -> mapFromScene(m_origin);
//Draw arc inverted
if (m_inverted) {
if (m_inverted)
{
//Adjust the start angle to be snapped at the origin point of draw
if (m_mouse_pos.y() > m_origin.y()) {
if (m_mouse_pos.x() > m_origin.x()) {
if (m_mouse_pos.y() > m_origin.y())
{
if (m_mouse_pos.x() > m_origin.x())
{
pos_.ry() -= height/2;
m_arc->setStartAngle(180);
m_arc->setStartAngle(2880);
}
else {
else
{
pos_.rx() -= width/2;
m_arc->setStartAngle(90);
m_arc->setStartAngle(1440);
}
}
else {
if (m_mouse_pos.x() > m_origin.x()) {
else
{
if (m_mouse_pos.x() > m_origin.x())
{
pos_.ry() -= height;
pos_.rx() -= width/2;
m_arc->setStartAngle(270);
m_arc->setStartAngle(4320);
}
else {
else
{
pos_.rx() -= width;
pos_.ry() -= height/2;
m_arc->setStartAngle(0);
}
}
}
//Draw arc non inverted
else {
else
{
//Adjust the start angle to be snapped at the origin point of draw
if (m_mouse_pos.y() > m_origin.y()) {
if (m_mouse_pos.x() > m_origin.x()) {
if (m_mouse_pos.y() > m_origin.y())
{
if (m_mouse_pos.x() > m_origin.x())
{
pos_.rx() -= width/2;
m_arc->setStartAngle(0);
}
else {
else
{
pos_.rx() -= width;
pos_.ry() -= height/2;
m_arc->setStartAngle(270);
m_arc->setStartAngle(4320);
}
}
else {
if (m_mouse_pos.x() > m_origin.x()) {
else
{
if (m_mouse_pos.x() > m_origin.x())
{
pos_.ry() -= height/2;
m_arc->setStartAngle(90);
m_arc->setStartAngle(1440);
}
else {
else
{
pos_.rx() -= width/2;
pos_.ry() -= height;
m_arc->setStartAngle(180);
m_arc->setStartAngle(2880);
}
}
}

View File

@@ -52,9 +52,10 @@ bool ESEventAddEllipse::mousePressEvent(QGraphicsSceneMouseEvent *event) {
//create new ellpise
if (!m_ellipse) {
m_ellipse = new PartEllipse(m_editor, 0, m_scene);
m_ellipse -> setRect(QRectF(pos, pos));
m_origin = pos;
m_ellipse = new PartEllipse(m_editor);
m_scene -> addItem(m_ellipse);
m_ellipse -> setPos(pos);
m_origin = m_new_pos = pos;
return true;
}
@@ -79,15 +80,16 @@ bool ESEventAddEllipse::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
updateHelpCross(event -> scenePos());
if (!m_ellipse) return false;
QPointF mouse_pos = m_scene -> snapToGrid(event -> scenePos());
QPointF pos = m_scene -> snapToGrid(event -> scenePos());
if (pos == m_new_pos) return true;
m_new_pos = pos;
qreal width = (mouse_pos.x() - m_origin.x())*2;
qreal height = (mouse_pos.y() - m_origin.y())*2;
qreal width = (m_new_pos.x() - m_origin.x())*2;
qreal height = (m_new_pos.y() - m_origin.y())*2;
//calculates the position of the rectangle so that its center is at position (0,0) of m_ellipse
QPointF center(-width/2, -height/2);
QPointF pos(m_origin.x() - width/2,
m_origin.y() - height/2);
m_ellipse -> setRect(QRectF(pos, QSizeF(width, height)));
m_ellipse -> setRect(QRectF(center, QSizeF(width, height)));
return true;
}

View File

@@ -41,7 +41,7 @@ class ESEventAddEllipse : public ESEventInterface
private:
PartEllipse *m_ellipse;
QPointF m_origin;
QPointF m_origin, m_new_pos;
};
#endif // ESEVENTADDELLIPSE_H

View File

@@ -57,8 +57,10 @@ bool ESEventAddLine::mousePressEvent(QGraphicsSceneMouseEvent *event) {
//Create new line
if (!m_line) {
m_line = new PartLine(m_editor, 0, m_scene);
m_line -> setLine(QLineF(pos, pos));
m_line = new PartLine(m_editor);
m_scene -> addItem(m_line);
m_line -> setP1(pos);
m_line -> setP2(pos);
return true;
}

View File

@@ -51,7 +51,8 @@ bool ESEventAddPolygon::mousePressEvent(QGraphicsSceneMouseEvent *event) {
//create new polygon
if (!m_polygon) {
m_polygon = new PartPolygon(m_editor, 0, m_scene);
m_polygon = new PartPolygon(m_editor);
m_scene -> addItem(m_polygon);
m_polygon -> addPoint(pos);
}

View File

@@ -44,14 +44,20 @@ ESEventAddRect::~ESEventAddRect() {
* @param event
* @return
*/
bool ESEventAddRect::mousePressEvent(QGraphicsSceneMouseEvent *event) {
if (event -> button() == Qt::LeftButton) {
bool ESEventAddRect::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event -> button() == Qt::LeftButton)
{
if(!m_running) m_running = true;
QPointF pos = m_scene->snapToGrid(event -> scenePos());
//create new rectangle
if (!m_rect) {
m_rect = new PartRectangle(m_editor, 0, m_scene);
//create new rectangle, pos isn't define,
//so m_rect.pos = 0,0 , that mean event.scenePos is in same coordinate of item
//we don't need to map point for m_rect
if (!m_rect)
{
m_rect = new PartRectangle(m_editor);
m_scene -> addItem(m_rect);
m_rect -> setRect(QRectF(pos, pos));
return true;
}
@@ -77,7 +83,7 @@ bool ESEventAddRect::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
updateHelpCross(event -> scenePos());
if (!m_rect) return false;
QRectF rect(m_rect -> rect().topLeft(), m_scene->snapToGrid(event -> scenePos()));
QRectF rect(m_rect->rectTopLeft(), m_scene->snapToGrid(event -> scenePos()));
m_rect -> setRect(rect);
return true;
}

View File

@@ -19,6 +19,7 @@
#define ESEVENTADDRECT_H
#include "eseventinterface.h"
#include <QPointF>
class ElementScene;
class PartRectangle;

View File

@@ -29,7 +29,8 @@
ESEventAddTerminal::ESEventAddTerminal(ElementScene *scene) :
ESEventInterface(scene)
{
m_terminal = new PartTerminal(m_editor, 0, m_scene);
m_terminal = new PartTerminal(m_editor);
m_scene -> addItem(m_terminal);
m_running = true;
}
@@ -63,7 +64,8 @@ bool ESEventAddTerminal::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
//Set new terminal with same rotation
Qet::Orientation ori = m_terminal -> orientation();
m_terminal = new PartTerminal(m_editor, 0, m_scene);
m_terminal = new PartTerminal(m_editor);
m_scene -> addItem(m_terminal);
m_terminal -> setOrientation(ori);
m_terminal -> setPos(m_scene -> snapToGrid(event -> scenePos()));

View File

@@ -0,0 +1,229 @@
/*
Copyright 2006-2015 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech 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.
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "abstractpartellipse.h"
/**
* @brief AbstractPartEllipse::AbstractPartEllipse
* Constructor
* @param editor : QETElementEditor of this part
* @param parent : parent item
*/
AbstractPartEllipse::AbstractPartEllipse(QETElementEditor *editor, QGraphicsItem *parent) :
CustomElementGraphicPart(editor, parent),
m_rect (QRectF(0, 0, 0, 0)),
m_start_angle (0),
m_span_angle (5760)
{}
/**
* @brief AbstractPartEllipse::~AbstractPartEllipse
* Destructor
*/
AbstractPartEllipse::~AbstractPartEllipse() {}
/**
* @brief AbstractPartEllipse::startUserTransformation
* Start the user-induced transformation, provided this primitive is contained
* within the initial_selection_rect bounding rectangle.
* @param initial_selection_rect
*/
void AbstractPartEllipse::startUserTransformation(const QRectF &initial_selection_rect)
{
Q_UNUSED(initial_selection_rect)
// we keep track of our own rectangle at the moment in scene coordinates too
saved_points_.clear();
saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight());
}
/**
* @brief AbstractPartEllipse::handleUserTransformation
* Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
* @param initial_selection_rect
* @param new_selection_rect
*/
void AbstractPartEllipse::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect)
{
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
}
/**
* @brief AbstractPartEllipse::boundingRect
* Bounding rectangle this part can fit into
* @return
*/
QRectF AbstractPartEllipse::boundingRect() const
{
qreal adjust = (SHADOWS_HEIGHT + penWeight()) / 2;
//We add 0.5 because CustomElementGraphicPart::drawShadowShape
//draw a shape bigger of 0.5 when pen weight is to 0.
if (penWeight() == 0) adjust += 0.5;
QRectF r(m_rect.normalized());
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
}
/**
* @brief AbstractPartEllipse::sceneGeometricRect
* @return the minimum, margin-less rectangle this part can fit into in scene coordinates.
* It is different from boundingRect() because it is not supposed
* to imply any margin, and it is different from shape because it is a regular
* rectangle, not a complex shape.
*/
QRectF AbstractPartEllipse::sceneGeometricRect() const {
return(mapToScene(rect()).boundingRect());
}
/**
* @brief AbstractPartEllipse::sceneTopLeft
* @return return the top left of rectangle, in scene coordinate
*/
QPointF AbstractPartEllipse::sceneTopLeft() const {
return(mapToScene(rect().topLeft()));
}
/**
* @brief AbstractPartEllipse::rect
* Returns the item's ellipse geometry as a QRectF.
*/
QRectF AbstractPartEllipse::rect() const {
return m_rect;
}
/**
* @brief AbstractPartEllipse::setRect
* Sets the item's ellipse geometry to rect.
* The rectangle's left edge defines the left edge of the ellipse,
* and the rectangle's top edge describes the top of the ellipse
* The height and width of the rectangle describe the height and width of the ellipse.
* @param rect
*/
void AbstractPartEllipse::setRect(const QRectF &rect)
{
if (rect == m_rect) return;
prepareGeometryChange();
m_rect = rect;
}
/**
* @brief AbstractPartEllipse::isUseless
* @return true if this part is irrelevant and does not deserve to be Retained / registered.
* An ellipse is relevant when is rect is not null.
*/
bool AbstractPartEllipse::isUseless() const {
return(rect().isNull());
}
/**
* @brief AbstractPartEllipse::setStartAngle
* Sets the start angle for an ellipse segment to angle, which is in 16ths of a degree.
* This angle is used together with spanAngle() for representing an ellipse segment (a pie).
* By default, the start angle is 0.
* @param start_angle
*/
void AbstractPartEllipse::setStartAngle(const int &start_angle)
{
if (m_start_angle == start_angle) return;
m_start_angle = start_angle;
update();
}
/**
* @brief AbstractPartEllipse::setSpanAngle
* Returns the span angle of an ellipse segment in 16ths of a degree.
* This angle is used together with startAngle() for representing an ellipse segment (a pie).
* By default, this function returns 5760 (360 * 16, a full ellipse).
* @param span_angle
*/
void AbstractPartEllipse::setSpanAngle(const int &span_angle)
{
if (m_span_angle == span_angle) return;
m_span_angle = span_angle;
update();
}
/**
* @brief AbstractPartEllipse::setCenterX
* Like setCenter but Y keep unchanged
* See setCenter(const QPointF &center)
* @param x
*/
void AbstractPartEllipse::setCenterX(const qreal x)
{
QPointF pos = mapToParent(m_rect.center());
pos.setX(x);
setCenter(pos);
}
/**
* @brief AbstractPartEllipse::setCenterY
* Like setCenter but X keep unchanged
* See setCenter(const QPointF &center)
* @param y
*/
void AbstractPartEllipse::setCenterY(const qreal y)
{
QPointF pos = mapToParent(m_rect.center());
pos.setY(y);
setCenter(pos);
}
/**
* @brief AbstractPartEllipse::setCenter
* This is a convenience method to setPos().
* Adjust the position of this item,
* so that the center of the rectangle is at the given position(position in parent coordinates).
* @param center
*/
void AbstractPartEllipse::setCenter(const QPointF &center)
{
QPointF pos = center - m_rect.center();
setPos(pos);
}
/**
* @brief AbstractPartEllipse::setWidth
* Set new width for rectangle.
* The center of rectangle is unchanged,
* The coordinates of the left side and right side of the rectangle change
* @param w
*/
void AbstractPartEllipse::setWidth(const qreal w)
{
qreal new_width = qAbs(w);
QRectF current_rect = rect();
current_rect.translate((new_width - current_rect.width()) / -2.0, 0.0);
current_rect.setWidth(new_width);
setRect(current_rect);
}
/**
* @brief AbstractPartEllipse::setHeight
* Set new height for rectangle
* The center of rectangle is unchanged
* The coordinates of the top side and bottom side of the rectangle change
* @param h
*/
void AbstractPartEllipse::setHeight(const qreal h)
{
qreal new_height = qAbs(h);
QRectF current_rect = rect();
current_rect.translate(0.0, (new_height - current_rect.height()) / -2.0);
current_rect.setHeight(new_height);
setRect(current_rect);
}

View File

@@ -0,0 +1,92 @@
/*
Copyright 2006-2015 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech 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.
QElectroTech 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 QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ABSTRACTPARTELLIPSE_H
#define ABSTRACTPARTELLIPSE_H
#include "customelementgraphicpart.h"
/**
* @brief The AbstractPartEllipse class
* This is the base class for all ellipse based item like ellipse, circle, arc.
* This class only provide common method for edit the ellipse like rect that contain the ellipse.
* All coordinates is in item coordinate, except pos(), center(), centerX() and centerY()
* which are in parent coordinate (or scene if no parent).
*
* In several points, this class is a copy of QGraphicsEllipseItem with some change,
* (the use of Q_PROPERTY) to be easily used with Element editor.
*/
class AbstractPartEllipse : public CustomElementGraphicPart
{
Q_OBJECT
Q_PROPERTY(int startAngle READ startAngle WRITE setStartAngle)
Q_PROPERTY(int spanAngle READ spanAngle WRITE setSpanAngle)
Q_PROPERTY(qreal centerX READ centerX WRITE setCenterX)
Q_PROPERTY(qreal centerY READ centerY WRITE setCenterY)
Q_PROPERTY(qreal diameter_h READ width WRITE setWidth)
Q_PROPERTY(qreal diameter_v READ height WRITE setHeight)
// constructors, destructor
public:
AbstractPartEllipse(QETElementEditor *editor, QGraphicsItem * parent = 0);
virtual ~AbstractPartEllipse();
private:
AbstractPartEllipse(const AbstractPartEllipse &);
// methods
public:
virtual void startUserTransformation (const QRectF &);
virtual void handleUserTransformation (const QRectF &, const QRectF &);
//Coordinates
virtual QRectF boundingRect() const;
virtual QRectF sceneGeometricRect() const;
virtual QPointF sceneTopLeft() const;
QRectF rect() const;
void setRect (const QRectF &rect);
virtual bool isUseless() const;
int startAngle() const {return m_start_angle;}
void setStartAngle (const int &start_angle);
int spanAngle () const {return m_span_angle;}
void setSpanAngle (const int &span_angle);
qreal centerX() const {return mapToScene(rect().center()).x() ;}
void setCenterX(const qreal x);
qreal centerY() const {return mapToScene(rect().center()).y();}
void setCenterY(const qreal y);
void setCenter (const QPointF &center);
qreal width() const {return rect().width();}
void setWidth(const qreal w);
qreal height() const {return rect().height();}
void setHeight (const qreal h);
protected:
QList<QPointF> saved_points_;
QRectF m_rect;
int m_start_angle;
int m_span_angle;
};
#endif // ABSTRACTPARTELLIPSE_H

View File

@@ -20,16 +20,27 @@
/**
* @brief CustomElementGraphicPart::CustomElementGraphicPart
* Default constructor.
* By default, item is selectable, send geometry change (Qt > 4.6),
* accept mouse left button and accept hover event
* @param editor QETElement editor that belong this.
*/
CustomElementGraphicPart::CustomElementGraphicPart(QETElementEditor *editor) :
CustomElementGraphicPart::CustomElementGraphicPart(QETElementEditor *editor, QGraphicsItem *parent) :
QGraphicsObject (parent),
CustomElementPart(editor),
m_hovered (false),
_linestyle(NormalStyle),
_lineweight(NormalWeight),
_filling(NoneFilling),
_color(BlackColor),
_antialiased(false)
{}
{
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptedMouseButtons(Qt::LeftButton);
setAcceptHoverEvents(true);
}
/**
* @brief CustomElementGraphicPart::~CustomElementGraphicPart
@@ -37,6 +48,36 @@ CustomElementGraphicPart::CustomElementGraphicPart(QETElementEditor *editor) :
*/
CustomElementGraphicPart::~CustomElementGraphicPart() {}
/**
* @brief CustomElementGraphicPart::drawCross
* Draw a cross at pos center
* @param center : center of cross
* @param painter : painter to use for draw cross,
* the painter state is restored at end of this method.
*/
void CustomElementGraphicPart::drawCross(const QPointF &center, QPainter *painter)
{
painter -> save();
painter -> setRenderHint(QPainter::Antialiasing, false);
painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
painter -> restore();
}
/**
* @brief CustomElementGraphicPart::penWeight
* @return the weight of pen
*/
qreal CustomElementGraphicPart::penWeight() const
{
if (_lineweight == NoneWeight || _lineweight == ThinWeight) return 0;
else if (_lineweight == NormalWeight) return 1;
else if (_lineweight == UltraWeight) return 2;
else if (_lineweight == BigWeight) return 5;
return 1;
}
/**
* @brief CustomElementGraphicPart::stylesToXml
* Write the curent style to xml element.
@@ -206,3 +247,69 @@ void CustomElementGraphicPart::applyStylesToQPainter(QPainter &painter) const
painter.setPen(pen);
painter.setBrush(brush);
}
/**
* @brief CustomElementGraphicPart::drawShadowShape
* Draw a transparent blue shadow arround the shape of this item.
* The QPainterPathStroker used to draw shadows have a width of SHADOWS_HEIGHT
* Be carefull if penWeight of this item is to 0 the outline of strock is bigger of 0.5
* @param painter : painter to use for draw this shadows
*/
void CustomElementGraphicPart::drawShadowShape(QPainter *painter)
{
//@FIXME if pen weight is 0, the strock outline is SHADOWS_HEIGHT/2 + 0.5
//may be because shape have no line weight
QPainterPathStroker strock;
strock.setWidth(SHADOWS_HEIGHT);
strock.setJoinStyle(Qt::RoundJoin);
painter->save();
QColor color(Qt::darkBlue);
color.setAlpha(50);
painter -> setBrush (QBrush (color));
painter -> setPen (Qt::NoPen);
painter -> drawPath (strock.createStroke(shape()));
painter -> restore ();
}
/**
* @brief CustomElementGraphicPart::itemChange
* Reimplemented from QGraphicsObject.
* If the item position change call updateCurrentPartEditor()
* the change is always send to QGraphicsObject
* @param change
* @param value
* @return the returned value of QGraphicsObject::itemChange
*/
QVariant CustomElementGraphicPart::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (scene())
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged)
updateCurrentPartEditor();
return(QGraphicsObject::itemChange(change, value));
}
/**
* @brief CustomElementGraphicPart::hoverEnterEvent
* Reimplemented from QGraphicsObject.
* Set m_hovered to true
* @param event
*/
void CustomElementGraphicPart::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
m_hovered = true;
QGraphicsObject::hoverEnterEvent(event);
}
/**
* @brief CustomElementGraphicPart::hoverLeaveEvent
* Reimplemented from QGraphicsObject.
* Set m_hovered to false
* @param event
*/
void CustomElementGraphicPart::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
m_hovered = false;
QGraphicsObject::hoverLeaveEvent(event);
}

View File

@@ -18,19 +18,22 @@
#ifndef CUSTOM_ELEMENT_GRAPHIC_PART_H
#define CUSTOM_ELEMENT_GRAPHIC_PART_H
#include <QObject>
#include <QGraphicsObject>
#include "customelementpart.h"
class QETElementEditor;
class QPainter;
/**
* @brief The CustomElementGraphicPart class
* This class is the base for all home-made primitive like line, rectangle, ellipse etc....
* It provides methods and enums to manage style attributes available for primitive (color, pen style, etc...)
*/
class CustomElementGraphicPart : public QObject, public CustomElementPart
class CustomElementGraphicPart : public QGraphicsObject, public CustomElementPart
{
#define SHADOWS_HEIGHT 4.0
Q_OBJECT
//Made this Q_ENUMS to be used by the Q_PROPERTY system.
@@ -62,15 +65,18 @@ class CustomElementGraphicPart : public QObject, public CustomElementPart
// constructors, destructor
public:
CustomElementGraphicPart(QETElementEditor *editor);
CustomElementGraphicPart(QETElementEditor *editor, QGraphicsItem *parent = 0);
virtual ~CustomElementGraphicPart();
static void drawCross (const QPointF &center, QPainter *painter);
//Getter and setter
LineStyle lineStyle () const {return _linestyle;}
void setLineStyle (const LineStyle ls) {_linestyle = ls;}
LineWeight lineWeight () const {return _lineweight;}
void setLineWeight (const LineWeight lw) {_lineweight = lw;}
qreal penWeight () const;
Filling filling () const {return _filling;}
void setFilling(const Filling f) {_filling = f;}
@@ -92,8 +98,14 @@ class CustomElementGraphicPart : public QObject, public CustomElementPart
void stylesFromXml(const QDomElement &);
void resetStyles ();
void applyStylesToQPainter(QPainter &) const;
void drawShadowShape (QPainter *painter);
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
// attributes
bool m_hovered;
private:
LineStyle _linestyle;
LineWeight _lineweight;

View File

@@ -18,67 +18,67 @@
#include "partarc.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@param parent Le QGraphicsItem parent de cet arc
@param scene La scene sur laquelle figure cet arc
* @brief PartArc::PartArc
* Constructor
* @param editor : QETElementEditor of this part
* @param parent : parent item
*/
PartArc::PartArc(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
CustomElementGraphicPart(editor),
QGraphicsEllipseItem(parent, scene),
_angle(-90),
start_angle(0)
PartArc::PartArc(QETElementEditor *editor, QGraphicsItem *parent) :
AbstractPartEllipse(editor, parent)
{
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptedMouseButtons(Qt::LeftButton);
}
/// Destructeur
PartArc::~PartArc() {
m_start_angle = 0;
m_span_angle = -1440;
}
/**
Dessine l'arc de cercle
@param painter QPainter a utiliser pour rendre le dessin
@param options Options pour affiner le rendu
@param widget Widget sur lequel le rendu est effectue
* @brief PartArc::~PartArc
* Destructor
*/
void PartArc::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
PartArc::~PartArc() {}
/**
* @brief PartArc::paint
* Draw this arc
* @param painter
* @param options
* @param widget
*/
void PartArc::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
{
Q_UNUSED(widget);
applyStylesToQPainter(*painter);
// enleve systematiquement la couleur de fond
//Always remove the brush
painter -> setBrush(Qt::NoBrush);
QPen t = painter -> pen();
t.setCosmetic(options && options -> levelOfDetail < 1.0);
painter -> setPen(t);
if (isSelected()) {
// dessine l'ellipse en noir
if (isSelected())
{
//Draw the ellipse in black
painter -> drawEllipse(rect());
// dessine l'arc en rouge
//Draw the arc in red
t.setColor(Qt::red);
painter -> setPen(t);
}
painter -> drawArc(rect(), start_angle * 16, _angle * 16);
if (isSelected()) {
// dessine la croix au centre de l'ellipse
painter -> setRenderHint(QPainter::Antialiasing, false);
painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
QPointF center = rect().center();
painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
}
painter -> drawArc(m_rect, m_start_angle, m_span_angle);
if (m_hovered)
drawShadowShape(painter);
if (isSelected())
drawCross(m_rect.center(), painter);
}
/**
Exporte l'arc de cercle en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant l'arc de cercle
* @brief PartArc::toXml
* Export this arc in xml
* @param xml_document : Xml document to use for create the xml element.
* @return : an xml element that describe this arc
*/
const QDomElement PartArc::toXml(QDomDocument &xml_document) const {
QDomElement xml_element = xml_document.createElement("arc");
@@ -87,144 +87,41 @@ const QDomElement PartArc::toXml(QDomDocument &xml_document) const {
xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
xml_element.setAttribute("width", QString("%1").arg(rect().width()));
xml_element.setAttribute("height", QString("%1").arg(rect().height()));
xml_element.setAttribute("start", QString("%1").arg(start_angle));
xml_element.setAttribute("angle", QString("%1").arg(_angle));
//to maintain compatibility with the previous version, we write the angle in degrees.
xml_element.setAttribute("start", QString("%1").arg(m_start_angle / 16));
xml_element.setAttribute("angle", QString("%1").arg(m_span_angle / 16));
stylesToXml(xml_element);
return(xml_element);
}
/**
Importe les proprietes d'un arc de cercle depuis un element XML
@param qde Element XML a lire
* @brief PartArc::fromXml
* Import the properties of this arc from a xml element.
* @param qde : Xml document to use.
*/
void PartArc::fromXml(const QDomElement &qde) {
stylesFromXml(qde);
setRect(
QRectF(
mapFromScene(
qde.attribute("x", "0").toDouble(),
qde.attribute("y", "0").toDouble()
),
QSizeF(
qde.attribute("width", "0").toDouble(),
qde.attribute("height", "0").toDouble()
)
)
);
setStartAngle(qde.attribute("start", "0").toInt());
setAngle(qde.attribute("angle", "-90").toInt());
m_rect = QRectF(mapFromScene(qde.attribute("x", "0").toDouble(),
qde.attribute("y", "0").toDouble()),
QSizeF(qde.attribute("width", "0").toDouble(),
qde.attribute("height", "0").toDouble()) );
m_start_angle = qde.attribute("start", "0").toInt() * 16;
m_span_angle = qde.attribute("angle", "-1440").toInt() * 16;
}
/**
@return le coin superieur gauche du rectangle dans lequel s'inscrit
l'ellipse dont fait partie cet arc, dans les coordonnees de la scene.
* @brief PartArc::shape
* @return the shape of this item
*/
QPointF PartArc::sceneTopLeft() const {
return(mapToScene(rect().topLeft()));
}
QPainterPath PartArc::shape() const
{
QPainterPath shape;
shape.arcMoveTo(m_rect, m_start_angle/16);
shape.arcTo(m_rect, m_start_angle/16, m_span_angle/16);
/**
* @brief PartArc::setX
* @param x is the center of the rect bounding this ellipse
*/
void PartArc::setX(const qreal x) {
QRectF current_rect = rect();
QPointF current_pos = mapToScene(current_rect.center());
setRect(current_rect.translated(x - current_pos.x(), 0.0));
}
QPainterPathStroker pps;
pps.setWidth(penWeight());
/**
* @brief PartArc::setY
* @param y is the center of the rect bounding this ellipse
*/
void PartArc::setY(const qreal y) {
QRectF current_rect = rect();
QPointF current_pos = mapToScene(current_rect.center());
setRect(current_rect.translated(0.0, y - current_pos.y()));
}
/**
* @brief PartArc::setWidth
* @param w is the width of the rect bounding this ellipse
*/
void PartArc::setWidth(const qreal w) {
qreal new_width = qAbs(w);
QRectF current_rect = rect();
current_rect.translate((new_width - current_rect.width()) / -2.0, 0.0);
current_rect.setWidth(new_width);
setRect(current_rect);
}
/**
* @brief PartArc::setHeight
* @param h is the heigth of the rect bounding this ellipse
*/
void PartArc::setHeight(const qreal h) {
qreal new_height = qAbs(h);
QRectF current_rect = rect();
current_rect.translate(0.0, (new_height - current_rect.height()) / -2.0);
current_rect.setHeight(new_height);
setRect(current_rect);
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartArc::itemChange(GraphicsItemChange change, const QVariant &value) {
if (scene()) {
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
updateCurrentPartEditor();
}
}
return(QGraphicsEllipseItem::itemChange(change, value));
}
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Un arc est pertinent des lors que ses dimensions et son etendue ne sont
pas nulles.
*/
bool PartArc::isUseless() const {
return(rect().isNull() || !angle());
}
/**
@return the minimum, margin-less rectangle this part can fit into, in scene
coordinates. It is different from boundingRect() because it is not supposed
to imply any margin, and it is different from shape because it is a regular
rectangle, not a complex shape.
*/
QRectF PartArc::sceneGeometricRect() const {
return(mapToScene(rect()).boundingRect());
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a initial_selection_rect bounding rectangle.
*/
void PartArc::startUserTransformation(const QRectF &initial_selection_rect) {
Q_UNUSED(initial_selection_rect)
saved_points_.clear();
saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight());
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
*/
void PartArc::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartArc::boundingRect() const {
qreal adjust = 1.5;
QRectF r(QGraphicsEllipseItem::boundingRect().normalized());
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
return (pps.createStroke(shape));
}

View File

@@ -17,79 +17,41 @@
*/
#ifndef PART_ARC_H
#define PART_ARC_H
#include <QtGui>
#include "customelementgraphicpart.h"
#include "abstractpartellipse.h"
/**
This class represents an elliptical arc primitive which may be used to
compose the drawing of an electrical element within the element editor.
* @brief The PartArc class
* This class represents an elliptical arc primitive which may be used to
* compose the drawing of an electrical element within the element editor.
*/
class PartArc : public CustomElementGraphicPart, public QGraphicsEllipseItem {
class PartArc : public AbstractPartEllipse
{
Q_OBJECT
// constructors, destructor
public:
PartArc(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
PartArc(QETElementEditor *editor, QGraphicsItem *parent = 0);
virtual ~PartArc();
private:
PartArc(const PartArc &);
// attributes
private:
int _angle;
int start_angle;
// methods
public:
enum { Type = UserType + 1101 };
/**
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
PartArc.
@return the QGraphicsItem type
* Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a PartArc.
* @return the QGraphicsItem type
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
//Name and XML
virtual QString name() const { return(QObject::tr("arc", "element part name")); }
virtual QString xmlName() const { return(QString("arc")); }
virtual const QDomElement toXml (QDomDocument &) const;
virtual void fromXml (const QDomElement &);
virtual QPointF sceneTopLeft() const;
virtual QRectF boundingRect() const;
virtual bool isUseless() const;
virtual QRectF sceneGeometricRect() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
///PROPERT
// X value
Q_PROPERTY(qreal x READ x WRITE setX)
qreal x() const {return mapToScene(rect().center()).x() ;}
void setX(const qreal x);
//Y value
Q_PROPERTY(qreal y READ y WRITE setY)
qreal y() const {return mapToScene(rect().center()).y();}
void setY(const qreal y);
// horizontal diameter
Q_PROPERTY(qreal diameter_h READ width WRITE setWidth)
qreal width() const {return rect().width();}
void setWidth(const qreal w);
// vertical diameter
Q_PROPERTY(qreal diameter_v READ height WRITE setHeight)
qreal height() const {return rect().height();}
void setHeight (const qreal h);
// start angle
Q_PROPERTY(int start_angle READ startAngle WRITE setStartAngle)
int startAngle() const {return start_angle;}
void setStartAngle(const int sa){start_angle = sa;}
// angle value
Q_PROPERTY(int angle READ angle WRITE setAngle)
int angle() const {return _angle;}
void setAngle(const int a) {_angle = a;}
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
private:
QList<QPointF> saved_points_;
virtual QPainterPath shape() const;
};
#endif

View File

@@ -18,188 +18,113 @@
#include "partellipse.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@param parent Le QGraphicsItem parent de cette ellipse
@param scene La scene sur laquelle figure cette ellipse
* @brief PartEllipse::PartEllipse
* Constructor
* @param editor : QETElementEditor of this part
* @param parent : parent item
*/
PartEllipse::PartEllipse(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : CustomElementGraphicPart(editor), QGraphicsEllipseItem(parent, scene) {
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptedMouseButtons(Qt::LeftButton);
}
/// Destructeur
PartEllipse::~PartEllipse() {
}
PartEllipse::PartEllipse(QETElementEditor *editor, QGraphicsItem *parent) :
AbstractPartEllipse(editor, parent)
{}
/**
Dessine l'ellipse
@param painter QPainter a utiliser pour rendre le dessin
@param options Options pour affiner le rendu
@param widget Widget sur lequel le rendu est effectue
* @brief PartEllipse::~PartEllipse
* Destructor
*/
void PartEllipse::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
PartEllipse::~PartEllipse() {}
/**
* @brief PartEllipse::paint
* Draw this ellpise
* @param painter
* @param options
* @param widget
*/
void PartEllipse::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
{
Q_UNUSED(widget);
applyStylesToQPainter(*painter);
QPen t = painter -> pen();
t.setCosmetic(options && options -> levelOfDetail < 1.0);
if (isSelected()) {
if (isSelected())
t.setColor(Qt::red);
}
painter -> setPen(t);
painter -> drawEllipse(rect());
if (isSelected()) {
painter -> setRenderHint(QPainter::Antialiasing, false);
painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
QPointF center = rect().center();
painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
}
if (m_hovered)
drawShadowShape(painter);
if (isSelected())
drawCross(m_rect.center(), painter);
}
/**
Exporte l'ellipse en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant l'ellipse
* @brief PartEllipse::toXml
* Export this ellipse in xml
* @param xml_document : Xml document to use for create the xml element.
* @return : an xml element that describe this ellipse
*/
const QDomElement PartEllipse::toXml(QDomDocument &xml_document) const {
const QDomElement PartEllipse::toXml(QDomDocument &xml_document) const
{
QDomElement xml_element;
if (qFuzzyCompare(rect().width(), rect().height())) {
if (qFuzzyCompare(rect().width(), rect().height()))
{
xml_element = xml_document.createElement("circle");
xml_element.setAttribute("diameter", QString("%1").arg(rect().width()));
} else {
}
else
{
xml_element = xml_document.createElement("ellipse");
xml_element.setAttribute("width", QString("%1").arg(rect().width()));
xml_element.setAttribute("height", QString("%1").arg(rect().height()));
}
QPointF top_left(sceneTopLeft());
xml_element.setAttribute("x", QString("%1").arg(top_left.x()));
xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
stylesToXml(xml_element);
return(xml_element);
}
/**
Importe les proprietes d'une ellipse depuis un element XML
@param qde Element XML a lire
* @brief PartEllipse::fromXml
* Import the properties of this ellipse from a xml element.
* @param qde : Xml document to use.
*/
void PartEllipse::fromXml(const QDomElement &qde) {
void PartEllipse::fromXml(const QDomElement &qde)
{
stylesFromXml(qde);
qreal width, height;
if (qde.tagName() == "ellipse") {
if (qde.tagName() == "ellipse")
{
width = qde.attribute("width", "0").toDouble();
height = qde.attribute("height", "0").toDouble();
} else {
}
else
width = height = qde.attribute("diameter", "0").toDouble();
}
setRect(
QRectF(
mapFromScene(
qde.attribute("x", "0").toDouble(),
qde.attribute("y", "0").toDouble()
),
QSizeF(width, height)
)
);
}
void PartEllipse::setX(const qreal x) {
QRectF current_rect = rect();
QPointF current_pos = mapToScene(current_rect.center());
setRect(current_rect.translated(x - current_pos.x(), 0.0));
}
void PartEllipse::setY(const qreal y) {
QRectF current_rect = rect();
QPointF current_pos = mapToScene(current_rect.center());
setRect(current_rect.translated(0.0, y - current_pos.y()));
}
void PartEllipse::setWidth(const qreal w) {
qreal new_width = qAbs(w);
QRectF current_rect = rect();
current_rect.translate((new_width - current_rect.width()) / -2.0, 0.0);
current_rect.setWidth(new_width);
setRect(current_rect);
}
void PartEllipse::setHeight(const qreal h) {
qreal new_height = qAbs(h);
QRectF current_rect = rect();
current_rect.translate(0.0, (new_height - current_rect.height()) / -2.0);
current_rect.setHeight(new_height);
setRect(current_rect);
m_rect = QRectF(mapFromScene(qde.attribute("x", "0").toDouble(),
qde.attribute("y", "0").toDouble()),
QSizeF(width, height));
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
* @brief PartEllipse::shape
* @return the shape of this item
*/
QVariant PartEllipse::itemChange(GraphicsItemChange change, const QVariant &value) {
if (scene()) {
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
updateCurrentPartEditor();
}
}
return(QGraphicsEllipseItem::itemChange(change, value));
}
QPainterPath PartEllipse::shape() const
{
QPainterPath shape;
shape.addEllipse(m_rect);
/**
@return le coin superieur gauche du rectangle dans lequel s'inscrit
l'ellipse, dans les coordonnees de la scene.
*/
QPointF PartEllipse::sceneTopLeft() const {
return(mapToScene(rect().topLeft()));
}
QPainterPathStroker pps;
pps.setWidth(penWeight());
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Une ellipse est pertinente des lors que ses dimensions ne sont pas nulles
*/
bool PartEllipse::isUseless() const {
return(rect().isNull());
}
/**
@return the minimum, margin-less rectangle this part can fit into, in scene
coordinates. It is different from boundingRect() because it is not supposed
to imply any margin, and it is different from shape because it is a regular
rectangle, not a complex shape.
*/
QRectF PartEllipse::sceneGeometricRect() const {
return(mapToScene(rect()).boundingRect());
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a initial_selection_rect bounding rectangle.
*/
void PartEllipse::startUserTransformation(const QRectF &initial_selection_rect) {
Q_UNUSED(initial_selection_rect)
// we keep track of our own rectangle at the moment in scene coordinates too
saved_points_.clear();
saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight());
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
*/
void PartEllipse::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartEllipse::boundingRect() const {
qreal adjust = 1.5;
QRectF r(QGraphicsEllipseItem::boundingRect().normalized());
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
return (pps.createStroke(shape));
}

View File

@@ -17,17 +17,21 @@
*/
#ifndef PART_ELLIPSE_H
#define PART_ELLIPSE_H
#include <QtGui>
#include "customelementgraphicpart.h"
#include "abstractpartellipse.h"
/**
This class represents an ellipse primitive which may be used to compose the
drawing of an electrical element within the element editor.
* @brief The PartEllipse class
* This class represents an ellipse primitive which may be used to compose the
* drawing of an electrical element within the element editor.
*/
class PartEllipse : public CustomElementGraphicPart, public QGraphicsEllipseItem {
class PartEllipse : public AbstractPartEllipse
{
Q_OBJECT
// constructors, destructor
public:
PartEllipse(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
PartEllipse(QETElementEditor *editor, QGraphicsItem * parent = 0);
virtual ~PartEllipse();
private:
@@ -37,45 +41,18 @@ class PartEllipse : public CustomElementGraphicPart, public QGraphicsEllipseItem
public:
enum { Type = UserType + 1103 };
/**
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
PartEllipse.
@return the QGraphicsItem type
* Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a PartEllipse.
* @return the QGraphicsItem type
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
//Name and XML
virtual QString name() const { return(QObject::tr("ellipse", "element part name")); }
virtual QString xmlName() const { return(QString("ellipse")); }
virtual const QDomElement toXml (QDomDocument &) const;
virtual void fromXml (const QDomElement &);
virtual QPointF sceneTopLeft() const;
virtual QRectF boundingRect() const;
virtual bool isUseless() const;
virtual QRectF sceneGeometricRect() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
///PROPERTY
// X value
Q_PROPERTY(qreal x READ x WRITE setX)
qreal x() const {return mapToScene(rect().center()).x() ;}
void setX(const qreal x);
// Y value
Q_PROPERTY(qreal y READ y WRITE setY)
qreal y() const {return mapToScene(rect().center()).y();}
void setY(const qreal y);
// horizontal diameter
Q_PROPERTY(qreal diameter_h READ width WRITE setWidth)
qreal width() const {return rect().width();}
void setWidth(const qreal w);
// vertical diameter
Q_PROPERTY(qreal diameter_v READ height WRITE setHeight)
qreal height() const {return rect().height();}
void setHeight (const qreal h);
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
private:
QList<QPointF> saved_points_;
virtual QPainterPath shape() const;
};
#endif

View File

@@ -18,148 +18,80 @@
#include "partline.h"
#include <cmath>
/**
Constructeur
@param editor L'editeur d'element concerne
@param parent Le QGraphicsItem parent de cette ligne
@param scene La scene sur laquelle figure cette ligne
* @brief PartLine::PartLine
* Constructor
* @param editor : QETElementEditor of this part
* @param parent : parent item
*/
PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
CustomElementGraphicPart(editor),
QGraphicsLineItem(parent, scene),
PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent) :
CustomElementGraphicPart(editor, parent),
first_end(Qet::None),
first_length(1.5),
second_end(Qet::None),
second_length(1.5)
{
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptedMouseButtons(Qt::LeftButton);
}
{}
/// Destructeur
PartLine::~PartLine() {
}
PartLine::~PartLine() {}
/**
@param end_type Type d'extremite
@return Le nombre de "longueurs" requises pour dessiner une extremite de type end_type
* @brief PartLine::requiredLengthForEndType
* @param end_type
* @return the number of "length" needed to draw a extremity of type Qet::EndType.
*/
uint PartLine::requiredLengthForEndType(const Qet::EndType &end_type) {
uint PartLine::requiredLengthForEndType(const Qet::EndType &end_type)
{
uint length_count_required = 0;
if (end_type == Qet::Circle || end_type == Qet::Diamond) {
if (end_type == Qet::Circle || end_type == Qet::Diamond)
length_count_required = 2;
} else if (end_type == Qet::Simple || end_type == Qet::Triangle) {
else if (end_type == Qet::Simple || end_type == Qet::Triangle)
length_count_required = 1;
}
return(length_count_required);
}
/**
Dessine la ligne
@param painter QPainter a utiliser pour rendre le dessin
@param options Options pour affiner le rendu
@param widget Widget sur lequel le rendu est effectue
* @brief PartLine::paint
* Draw this line
* @param painter
* @param options
* @param widget
*/
void PartLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
void PartLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
{
Q_UNUSED(widget);
// inutile de dessiner une ligne nulle
if (line().p1() == line().p2()) return;
if (isUseless()) return;
applyStylesToQPainter(*painter);
QPen t = painter -> pen();
t.setJoinStyle(Qt::MiterJoin);
t.setCosmetic(options && options -> levelOfDetail < 1.0);
if (isSelected()) {
if (isSelected())
t.setColor(Qt::red);
}
painter -> setPen(t);
QPointF point1(line().p1());
QPointF point2(line().p2());
if (first_end || second_end)
painter -> drawPath(path());
else
painter -> drawLine(m_line);
qreal line_length(line().length());
qreal pen_width = painter -> pen().widthF();
qreal length1 = first_length;
qreal length2 = second_length;
//debugPaint(painter);
// determine s'il faut dessiner les extremites
bool draw_1st_end, draw_2nd_end;
qreal reduced_line_length = line_length - (length1 * requiredLengthForEndType(first_end));
draw_1st_end = first_end && reduced_line_length >= 0;
if (draw_1st_end) {
reduced_line_length -= (length2 * requiredLengthForEndType(second_end));
} else {
reduced_line_length = line_length - (length2 * requiredLengthForEndType(second_end));
}
draw_2nd_end = second_end && reduced_line_length >= 0;
// dessine la premiere extremite
QPointF start_point, stop_point;
if (draw_1st_end) {
QList<QPointF> four_points1(fourEndPoints(point1, point2, length1));
if (first_end == Qet::Circle) {
painter -> drawEllipse(QRectF(four_points1[0] - QPointF(length1, length1), QSizeF(length1 * 2.0, length1 * 2.0)));
start_point = four_points1[1];
} else if (first_end == Qet::Diamond) {
painter -> drawPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3]);
start_point = four_points1[1];
} else if (first_end == Qet::Simple) {
painter -> drawPolyline(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
start_point = point1;
} else if (first_end == Qet::Triangle) {
painter -> drawPolygon(QPolygonF() << four_points1[0] << four_points1[2] << point1 << four_points1[3]);
start_point = four_points1[0];
}
// ajuste le depart selon l'epaisseur du trait
if (pen_width && (first_end == Qet::Simple || first_end == Qet::Circle)) {
start_point = QLineF(start_point, point2).pointAt(pen_width / 2.0 / line_length);
}
} else {
start_point = point1;
}
// dessine la seconde extremite
if (draw_2nd_end) {
QList<QPointF> four_points2(fourEndPoints(point2, point1, length2));
if (second_end == Qet::Circle) {
painter -> drawEllipse(QRectF(four_points2[0] - QPointF(length2, length2), QSizeF(length2 * 2.0, length2 * 2.0)));
stop_point = four_points2[1];
} else if (second_end == Qet::Diamond) {
painter -> drawPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1]);
stop_point = four_points2[1];
} else if (second_end == Qet::Simple) {
painter -> drawPolyline(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
stop_point = point2;
} else if (second_end == Qet::Triangle) {
painter -> drawPolygon(QPolygonF() << four_points2[0] << four_points2[2] << point2 << four_points2[3] << four_points2[0]);
stop_point = four_points2[0];
}
// ajuste l'arrivee selon l'epaisseur du trait
if (pen_width && (second_end == Qet::Simple || second_end == Qet::Circle)) {
stop_point = QLineF(point1, stop_point).pointAt((line_length - (pen_width / 2.0)) / line_length);
}
} else {
stop_point = point2;
}
painter -> drawLine(start_point, stop_point);
if (m_hovered)
drawShadowShape(painter);
}
/**
Exporte la ligne en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant la ligne
* @brief PartLine::toXml
* Export this line in xml
* @param xml_document : Xml document to use for create the xml element.
* @return an xml element that describe this line
*/
const QDomElement PartLine::toXml(QDomDocument &xml_document) const {
const QDomElement PartLine::toXml(QDomDocument &xml_document) const
{
QPointF p1(sceneP1());
QPointF p2(sceneP2());
@@ -178,23 +110,17 @@ const QDomElement PartLine::toXml(QDomDocument &xml_document) const {
}
/**
Importe les proprietes d'une ligne depuis un element XML
@param qde Element XML a lire
* @brief PartLine::fromXml
* Import the properties of this line from a xml element.
* @param qde : Xml document to use
*/
void PartLine::fromXml(const QDomElement &qde) {
stylesFromXml(qde);
setLine(
QLineF(
mapFromScene(
qde.attribute("x1", "0").toDouble(),
qde.attribute("y1", "0").toDouble()
),
mapFromScene(
qde.attribute("x2", "0").toDouble(),
qde.attribute("y2", "0").toDouble()
)
)
);
m_line = QLineF(mapFromScene(qde.attribute("x1", "0").toDouble(),
qde.attribute("y1", "0").toDouble()),
mapFromScene(qde.attribute("x2", "0").toDouble(),
qde.attribute("y2", "0").toDouble()));
first_end = Qet::endTypeFromString(qde.attribute("end1"));
first_length = qde.attribute("length1", "1.5").toDouble();
second_end = Qet::endTypeFromString(qde.attribute("end2"));
@@ -202,25 +128,11 @@ void PartLine::fromXml(const QDomElement &qde) {
}
/**
* @brief PartLine::setX1
* set X of P1
* @param x1
* @brief PartLine::p1
* @return the point p1 of line.
*/
void PartLine::setX1(qreal x1) {
QPointF p = line().p1();
p.setX(x1);
setLine(QLineF(p, line().p2()));
}
/**
* @brief PartLine::setY1
* set y of P1
* @param y1
*/
void PartLine::setY1(qreal y1) {
QPointF p = line().p1();
p.setY(y1);
setLine(QLineF(p, line().p2()));
QPointF PartLine::p1() const {
return m_line.p1();
}
/**
@@ -228,30 +140,19 @@ void PartLine::setY1(qreal y1) {
* set first point to P1
* @param p1
*/
void PartLine::setP1(QPointF p1) {
setLine(QLineF(p1, line().p2()));
void PartLine::setP1(const QPointF &p1)
{
if (p1 == m_line.p1()) return;
prepareGeometryChange();
m_line.setP1(p1);
}
/**
* @brief PartLine::setX2
* set x of P2
* @param x2
* @brief PartLine::p2
* @return the point p2 of line
*/
void PartLine::setX2(qreal x2) {
QPointF p = line().p2();
p.setX(x2);
setLine(QLineF(line().p1(), p));
}
/**
* @brief PartLine::setY2
* set y of P2
* @param y2
*/
void PartLine::setY2(qreal y2) {
QPointF p = line().p2();
p.setY(y2);
setLine(QLineF(line().p1(), p));
QPointF PartLine::p2() const {
return m_line.p2();
}
/**
@@ -259,105 +160,91 @@ void PartLine::setY2(qreal y2) {
* set second point to P2
* @param p2
*/
void PartLine::setP2(QPointF p2) {
setLine(QLineF(line().p1(), p2));
void PartLine::setP2(const QPointF &p2)
{
if (p2 == m_line.p2()) return;
prepareGeometryChange();
m_line.setP2(p2);
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartLine::itemChange(GraphicsItemChange change, const QVariant &value) {
if (scene()) {
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
updateCurrentPartEditor();
}
}
return(QGraphicsLineItem::itemChange(change, value));
}
/**
@return le premier point, dans les coordonnees de la scene.
* @brief PartLine::sceneP1
* @return the point p1 in scene coordinate
*/
QPointF PartLine::sceneP1() const {
return(mapToScene(line().p1()));
return(mapToScene(p1()));
}
/**
@return le second point, dans les coordonnees de la scene.
* @brief PartLine::sceneP2
* @return the point p2 in scen coordinate
*/
QPointF PartLine::sceneP2() const {
return(mapToScene(line().p2()));
return(mapToScene(p2()));
}
/**
@return la forme selectionnable de la ligne
* @brief PartLine::shape
* @return the shape of this item
*/
QPainterPath PartLine::shape() const {
QList<QPointF> points = fourShapePoints();
QPainterPath t;
t.setFillRule(Qt::WindingFill);
t.moveTo(points.at(0));
t.lineTo(points.at(1));
t.lineTo(points.at(2));
t.lineTo(points.at(3));
t.lineTo(points.at(0));
QPainterPath PartLine::shape() const
{
QPainterPath shape;
// n'en fait pas plus si la ligne se ramene a un point
if (line().p1() == line().p2()) return(t);
// ajoute un cercle pour l'extremite 1 si besoin
if (first_end) {
QPainterPath t2;
t2.addEllipse(firstEndCircleRect());
t.addPath(t2.subtracted(t));
//We calcul path only if there is an end type
//Else we just draw a line
if (first_end || second_end)
shape.addPath(path());
else
{
shape.moveTo(m_line.p1());
shape.lineTo(m_line.p2());
}
// ajoute un cercle pour l'extremite 2 si besoin
if (second_end) {
QPainterPath t2;
t2.addEllipse(secondEndCircleRect());
t.addPath(t2.subtracted(t));
}
QPainterPathStroker pps;
pps.setWidth(penWeight());
return(t);
return (pps.createStroke(shape));
}
/**
@return une liste contenant les deux points de la droite + les 4 points entourant ces deux points
* @brief PartLine::fourShapePoints
* @return a list with the two points that delimite the line
* + the four points surrounding these two points
*/
QList<QPointF> PartLine::fourShapePoints() const {
QList<QPointF> PartLine::fourShapePoints() const
{
const qreal marge = 2.0;
// on a donc A(xa , ya) et B(xb, yb)
QPointF a = line().p1();
QPointF b = line().p2();
QPointF a = m_line.p1();
QPointF b = m_line.p2();
QList<QPointF> result;
// cas particulier : la droite se ramene a un point
if (a == b) {
//Special case, the line is defined by one point
if (a == b)
{
result << QPointF(a.x() - marge, a.y() - marge);
result << QPointF(a.x() - marge, a.y() + marge);
result << QPointF(a.x() + marge, a.y() + marge);
result << QPointF(a.x() + marge, a.y() - marge);
} else {
// on calcule le vecteur AB : (xb-xa, yb-ya)
}
else
{
//We calcule the vector AB : (xb-xa, yb-ya)
QPointF v_ab = b - a;
// et la distance AB : racine des coordonnees du vecteur au carre
//And the distance AB: root of the coordinates of the vector squared
qreal ab = sqrt(pow(v_ab.x(), 2) + pow(v_ab.y(), 2));
// ensuite on definit le vecteur u(a, b) qui est egal au vecteur AB divise
// par sa longueur et multiplie par la longueur de la marge que tu veux
// laisser
//Next, we define the vector u(a, b) wich is equal to the vector AB divided
//by is length and multiplied by the length of marge.
QPointF u = v_ab / ab * marge;
// on definit le vecteur v(-b , a) qui est perpendiculaire a AB
//We define the vector v(-b, a) wich is perpendicular to AB
QPointF v(-u.y(), u.x());
QPointF m = -u + v; // on a le vecteur M = -u + v
QPointF n = -u - v; // et le vecteur N=-u-v
QPointF m = -u + v; // we have vector M = -u + v
QPointF n = -u - v; // and vector N=-u-v
QPointF h = a + m; // H = A + M
QPointF k = a + n; // K = A + N
QPointF i = b - n; // I = B - N
@@ -369,14 +256,14 @@ QList<QPointF> PartLine::fourShapePoints() const {
}
/**
@return le rectangle encadrant l'integralite de la premiere extremite
* @brief PartLine::firstEndCircleRect
* @return the rectangle bordering the entirety of the first extremity
*/
QRectF PartLine::firstEndCircleRect() const {
QList<QPointF> interesting_points = fourEndPoints(
line().p1(),
line().p2(),
first_length
);
QRectF PartLine::firstEndCircleRect() const
{
QList<QPointF> interesting_points = fourEndPoints(m_line.p1(),
m_line.p2(),
first_length);
QRectF end_rect(
interesting_points[0] - QPointF(first_length, first_length),
@@ -387,14 +274,13 @@ QRectF PartLine::firstEndCircleRect() const {
}
/**
@return le rectangle encadrant l'integralite de la seconde extremite
* @brief PartLine::secondEndCircleRect
* @return the rectangle bordering the entirety of the second extremity
*/
QRectF PartLine::secondEndCircleRect() const {
QList<QPointF> interesting_points = fourEndPoints(
line().p2(),
line().p1(),
second_length
);
QList<QPointF> interesting_points = fourEndPoints(m_line.p2(),
m_line.p1(),
second_length);
QRectF end_rect(
interesting_points[0] - QPointF(second_length, second_length),
@@ -405,13 +291,15 @@ QRectF PartLine::secondEndCircleRect() const {
}
/**
Affiche differentes composantes du dessin :
- le boundingRect
- les point speciaux a chaque extremite
- la quadrature du cercle a chaque extremite, meme si celle-ci est d'un
autre type
* @brief PartLine::debugPaint
* Display several composante of the drawing
* -the bounding rect
* -special points at each extremity
* -the quadrature of the circle at each extremity, even if itself is an other type
* @param painter
*/
void PartLine::debugPaint(QPainter *painter) {
void PartLine::debugPaint(QPainter *painter)
{
painter -> save();
painter -> setPen(Qt::gray);
painter -> drawRect(boundingRect());
@@ -421,99 +309,109 @@ void PartLine::debugPaint(QPainter *painter) {
painter -> drawRect(secondEndCircleRect());
painter -> setPen(Qt::red);
foreach(QPointF pointy, fourEndPoints(line().p1(), line().p2(), first_length)) {
foreach(QPointF pointy, fourEndPoints(p1(), p2(), first_length))
painter -> drawEllipse(pointy, 0.1, 0.1);
}
foreach(QPointF pointy, fourEndPoints(line().p2(), line().p1(), second_length)) {
foreach(QPointF pointy, fourEndPoints(p2(), p1(), second_length))
painter -> drawEllipse(pointy, 0.1, 0.1);
}
painter -> restore();
}
/**
@return le rectangle delimitant cette partie.
* @brief PartLine::boundingRect
* @return the bounding rect of this part
*/
QRectF PartLine::boundingRect() const {
QRectF r(QGraphicsLineItem::boundingRect());
QRectF PartLine::boundingRect() const
{
QRectF bound;
if (first_end || second_end)
bound = path().boundingRect();
else
bound = QRectF (m_line.p1(), m_line.p2());
// le rectangle ainsi obtenu ne doit pas avoir une dimension nulle
r.adjust(0.0, 0.0, 0.1, 0.1);
qreal adjust = (SHADOWS_HEIGHT + penWeight()) / 2;
//We add 0.5 because CustomElementGraphicPart::drawShadowShape
//draw a shape bigger of 0.5 when pen weight is to 0.
if (penWeight() == 0) adjust += 0.5;
// cas special : les embouts sortent largement du bounding rect originel
if (first_end != Qet::None) {
r = r.united(firstEndCircleRect());
}
if (second_end != Qet::None) {
r = r.united(secondEndCircleRect());
}
// la taille du bounding rect est ajustee avec une certaine marge
qreal adjust = 1.2;
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
bound = bound.normalized();
bound.adjust(-adjust, -adjust, adjust, adjust);
return bound;
}
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Une ligne est pertinente des lors que ses deux points sont differents
* @brief PartLine::isUseless
* @return true if this part is irrelevant and does not deserve to be Retained / registered.
* A line is relevant when is two point is different
*/
bool PartLine::isUseless() const {
return(sceneP1() == sceneP2());
return(m_line.p1() == m_line.p2());
}
/**
@return the minimum, margin-less rectangle this part can fit into, in scene
coordinates. It is different from boundingRect() because it is not supposed
to imply any margin, and it is different from shape because it is a regular
rectangle, not a complex shape.
* @brief PartLine::sceneGeometricRect
* @return the minimum, margin-less rectangle this part can fit into, in scene
* coordinates. It is different from boundingRect() because it is not supposed
* to imply any margin, and it is different from shape because it is a regular
* rectangle, not a complex shape.
*/
QRectF PartLine::sceneGeometricRect() const {
return(QRectF(sceneP1(), sceneP2()));
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a initial_selection_rect bounding rectangle.
* @brief PartLine::startUserTransformation
* Start the user-induced transformation, provided this primitive is contained
* within the \a initial_selection_rect bounding rectangle.
* @param initial_selection_rect
*/
void PartLine::startUserTransformation(const QRectF &initial_selection_rect) {
void PartLine::startUserTransformation(const QRectF &initial_selection_rect)
{
Q_UNUSED(initial_selection_rect)
saved_points_.clear();
saved_points_ << sceneP1() << sceneP2();
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
* @brief PartLine::handleUserTransformation
* Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
* @param initial_selection_rect
* @param new_selection_rect
*/
void PartLine::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
void PartLine::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect)
{
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
setLine(QLineF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
prepareGeometryChange();
m_line = QLineF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1)));
}
/**
@return Les quatre points interessants a l'extremite d'une droite
Ces points sont, dans l'ordre :
* O : point sur la ligne, a une distance length de l'extremite
* A : point sur la ligne a une distance 2 x length de l'extremite
* B : point a une distance length de O - O est le projete de B sur la droite
* C : point a une distance length de O - O est le projete de C sur la droite
B et C sont situes de part et d'autre de la ligne
@param end_point Extremite concernee
@param other_point Autre point permettant de definir une ligne
@param length Longueur a utiliser entre l'extremite et le point O
* @brief PartLine::fourEndPoints
* Return the four interesting point needed to draw the shape
* at extremity of line (circle, diamond, arrow, triangle)
* This points are in order :
* O : point on the line, at a distance 'length' of the extremity
* A : point on the line at a 'length' of 2x the extremity length
* B : point at a distance of length O - O is the projection of B on the line
* C : point at a distance of length O - O is the projection of C on the line
* @param end_point : The concerned extremity
* @param other_point : other needed point to define the line
* @param length : length to use between the extremity and the point O
* @return
*/
QList<QPointF> PartLine::fourEndPoints(const QPointF &end_point, const QPointF &other_point, const qreal &length) {
// vecteur et longueur de la ligne
QList<QPointF> PartLine::fourEndPoints(const QPointF &end_point, const QPointF &other_point, const qreal &length)
{
//Vector and length of the line
QPointF line_vector = end_point - other_point;
qreal line_length = sqrt(pow(line_vector.x(), 2) + pow(line_vector.y(), 2));
// vecteur unitaire et vecteur perpendiculaire
//Unitary vector and perpendicular vector
QPointF u(line_vector / line_length * length);
QPointF v(-u.y(), u.x());
// points O, A, B et C
// points O, A, B, C
QPointF o(end_point - u);
QPointF a(o - u);
QPointF b(o + v);
@@ -521,3 +419,119 @@ QList<QPointF> PartLine::fourEndPoints(const QPointF &end_point, const QPointF &
return(QList<QPointF>() << o << a << b << c);
}
/**
* @brief PartLine::path
* @return this line has a QPainterPath.
* It's notably use when this line have an end type (circle, triangle etc....),
* because return a QPainterPath with end already draw.
* Else if there isn't an end type get P1 and P2 of line is better (faster).
*/
QPainterPath PartLine::path() const
{
QPainterPath path;
QPointF point1(m_line.p1());
QPointF point2(m_line.p2());
qreal line_length(m_line.length());
qreal pen_width = penWeight();
qreal length1 = first_length;
qreal length2 = second_length;
//debugPaint(painter);
//Determine if we must to draw extremity
qreal reduced_line_length = line_length - (length1 * requiredLengthForEndType(first_end));
bool draw_1st_end = first_end && reduced_line_length >= 0;
if (draw_1st_end)
reduced_line_length -= (length2 * requiredLengthForEndType(second_end));
else
reduced_line_length = line_length - (length2 * requiredLengthForEndType(second_end));
//Draw the first extremity
QPointF start_point;
if (draw_1st_end)
{
QList<QPointF> four_points1(fourEndPoints(point1, point2, length1));
if (first_end == Qet::Circle)
{
path.addEllipse(QRectF(four_points1[0] - QPointF(length1, length1), QSizeF(length1 * 2.0, length1 * 2.0)));
start_point = four_points1[1];
}
else if (first_end == Qet::Diamond)
{
path.addPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3] << four_points1[1]);
start_point = four_points1[1];
}
else if (first_end == Qet::Simple)
{
path.addPolygon(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
start_point = point1;
}
else if (first_end == Qet::Triangle)
{
path.addPolygon(QPolygonF() << four_points1[0] << four_points1[2] << point1 << four_points1[3] << four_points1[0]);
start_point = four_points1[0];
}
//Adjust the start point according to the pen width
if (pen_width && (first_end == Qet::Simple || first_end == Qet::Circle))
start_point = QLineF(start_point, point2).pointAt(pen_width / 2.0 / line_length);
}
else
{
start_point = point1;
}
//Draw the second extremity
QPointF stop_point;
bool draw_2nd_end = second_end && reduced_line_length >= 0;
if (draw_2nd_end)
{
QList<QPointF> four_points2(fourEndPoints(point2, point1, length2));
if (second_end == Qet::Circle)
{
path.addEllipse(QRectF(four_points2[0] - QPointF(length2, length2), QSizeF(length2 * 2.0, length2 * 2.0)));
stop_point = four_points2[1];
}
else if (second_end == Qet::Diamond)
{
path.addPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1] << four_points2[2]);
stop_point = four_points2[1];
}
else if (second_end == Qet::Simple)
{
path.addPolygon(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
stop_point = point2;
}
else if (second_end == Qet::Triangle)
{/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Une ligne est pertinente des lors que ses deux points sont differents
*/
path.addPolygon(QPolygonF() << four_points2[0] << four_points2[2] << point2 << four_points2[3] << four_points2[0]);
stop_point = four_points2[0];
}
//Adjust the end point accordint to the pen width
if (pen_width && (second_end == Qet::Simple || second_end == Qet::Circle))
stop_point = QLineF(point1, stop_point).pointAt((line_length - (pen_width / 2.0)) / line_length);
}
else
{
stop_point = point2;
}
path.moveTo(start_point);
path.lineTo(stop_point);
return path;
}

View File

@@ -17,7 +17,7 @@
*/
#ifndef PART_LINE_H
#define PART_LINE_H
#include <QtGui>
#include "customelementgraphicpart.h"
#include "qet.h"
/**
@@ -29,11 +29,20 @@
drawn if the required length for their drawing is longer than the line itself.
In case there is room for a single end only, the first one get priority.
*/
class PartLine : public CustomElementGraphicPart, public QGraphicsLineItem {
class PartLine : public CustomElementGraphicPart
{
Q_OBJECT
Q_PROPERTY(QPointF p1 READ p1 WRITE setP1)
Q_PROPERTY(QPointF p2 READ p2 WRITE setP2)
Q_PROPERTY(Qet::EndType end1 READ firstEndType WRITE setFirstEndType)
Q_PROPERTY(Qet::EndType end2 READ secondEndType WRITE setSecondEndType)
Q_PROPERTY(qreal length1 READ firstEndLength WRITE setFirstEndLength)
Q_PROPERTY(qreal length2 READ secondEndLength WRITE setSecondEndLength)
// constructors, destructor
public:
PartLine(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
PartLine(QETElementEditor *, QGraphicsItem * = 0);
virtual ~PartLine();
private:
@@ -41,20 +50,15 @@ class PartLine : public CustomElementGraphicPart, public QGraphicsLineItem {
// attributes
private:
Qet::EndType first_end;
qreal first_length;
Qet::EndType second_end;
qreal second_length;
QList<QPointF> saved_points_;
// methods
public:
enum { Type = UserType + 1104 };
/**
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
PartLine.
@return the QGraphicsItem type
* Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a PartLine.
* @return the QGraphicsItem type
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
@@ -73,63 +77,33 @@ class PartLine : public CustomElementGraphicPart, public QGraphicsLineItem {
static uint requiredLengthForEndType(const Qet::EndType &);
static QList<QPointF> fourEndPoints(const QPointF &, const QPointF &, const qreal &);
///PROPERTY
// X value of the first point
Q_PROPERTY(qreal x1 READ x1 WRITE setX1)
qreal x1() const {return sceneP1().x();}
void setX1(qreal x1);
// Y value of the first point
Q_PROPERTY(qreal y1 READ y1 WRITE setY1)
qreal y1() const {return sceneP1().y();}
void setY1(qreal y1);
//pos of firts point
Q_PROPERTY(QPointF p1 READ sceneP1 WRITE setP1)
void setP1 (QPointF p1);
// X value of the second point
Q_PROPERTY(qreal x2 READ x2 WRITE setX2)
qreal x2() const {return sceneP2().x();}
void setX2(qreal x2);
// Y value of the second point
Q_PROPERTY(qreal y2 READ y2 WRITE setY2)
qreal y2() const {return sceneP2().y();}
void setY2(qreal y2);
//pos of second point
Q_PROPERTY(QPointF p2 READ sceneP2 WRITE setP2)
void setP2 (QPointF p2);
// End type of the first point
Q_PROPERTY(Qet::EndType end1 READ firstEndType WRITE setFirstEndType)
QPointF p1() const;
void setP1 (const QPointF &p1);
QPointF p2 () const;
void setP2 (const QPointF &p2);
Qet::EndType firstEndType() const {return first_end;}
void setFirstEndType(const Qet::EndType &et) {first_end = et;}
// End type of the second point
Q_PROPERTY(Qet::EndType end2 READ secondEndType WRITE setSecondEndType)
Qet::EndType secondEndType() const {return second_end;}
void setSecondEndType(const Qet::EndType &et) {second_end = et;}
// Size of end type of first point
Q_PROPERTY(qreal length1 READ firstEndLength WRITE setFirstEndLength)
qreal firstEndLength() const {return first_length;}
void setFirstEndLength(const qreal &l) {first_length = qMin(qAbs(l), line().length());}
// Size of end type of the second point
Q_PROPERTY(qreal length2 READ secondEndLength WRITE setSecondEndLength)
void setFirstEndLength(const qreal &l) {first_length = qMin(qAbs(l), m_line.length());}
qreal secondEndLength() const {return second_length;}
void setSecondEndLength(const qreal &l) {second_length = qMin(qAbs(l), line().length());}
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
void setSecondEndLength(const qreal &l) {second_length = qMin(qAbs(l), m_line.length());}
private:
QPainterPath path() const;
QList<QPointF> fourShapePoints() const;
QRectF firstEndCircleRect() const;
QRectF secondEndCircleRect() const;
void debugPaint(QPainter *);
Qet::EndType first_end;
qreal first_length;
Qet::EndType second_end;
qreal second_length;
QList<QPointF> saved_points_;
QLineF m_line;
};
#endif

View File

@@ -16,66 +16,89 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "partpolygon.h"
#include "qet.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@param parent Le QGraphicsItem parent de ce polygone
@param scene La scene sur laquelle figure ce polygone
* @brief PartPolygon::PartPolygon
* Constructor
* @param editor : editor of this item
* @param parent : parent item
*/
PartPolygon::PartPolygon(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
CustomElementGraphicPart(editor),
QGraphicsPolygonItem(parent, scene),
PartPolygon::PartPolygon(QETElementEditor *editor, QGraphicsItem *parent) :
CustomElementGraphicPart(editor, parent),
m_closed(false)
{
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptedMouseButtons(Qt::LeftButton);
}
{}
/// Destructeur
PartPolygon::~PartPolygon() {
/**
* @brief PartPolygon::~PartPolygon
*/
PartPolygon::~PartPolygon() {}
/**
* @brief PartPolygon::paint
* Draw this polygon
* @param painter
* @param options
* @param widget
*/
void PartPolygon::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
{
Q_UNUSED(widget);
applyStylesToQPainter(*painter);
QPen t = painter -> pen();
t.setCosmetic(options && options -> levelOfDetail < 1.0);
if (isSelected()) t.setColor(Qt::red);
painter -> setPen(t);
m_closed ? painter -> drawPolygon (m_polygon) :
painter -> drawPolyline(m_polygon);
if (m_hovered)
drawShadowShape(painter);
}
/**
Importe les proprietes d'un polygone depuis un element XML
@param qde Element XML a lire
* @brief PartPolygon::fromXml
* Import the properties of this polygon from a xml element
* @param qde : Xml document to use
*/
void PartPolygon::fromXml(const QDomElement &qde) {
void PartPolygon::fromXml(const QDomElement &qde)
{
stylesFromXml(qde);
int i = 1;
while(true) {
if (
QET::attributeIsAReal(qde, QString("x%1").arg(i)) &&\
QET::attributeIsAReal(qde, QString("y%1").arg(i))
) ++ i;
while(true)
{
if (QET::attributeIsAReal(qde, QString("x%1").arg(i)) &&\
QET::attributeIsAReal(qde, QString("y%1").arg(i)))
++ i;
else break;
}
QPolygonF temp_polygon;
for (int j = 1 ; j < i ; ++ j) {
temp_polygon << QPointF(
qde.attribute(QString("x%1").arg(j)).toDouble(),
qde.attribute(QString("y%1").arg(j)).toDouble()
);
for (int j = 1 ; j < i ; ++ j)
{
temp_polygon << QPointF(qde.attribute(QString("x%1").arg(j)).toDouble(),
qde.attribute(QString("y%1").arg(j)).toDouble());
}
setPolygon(temp_polygon);
m_polygon = temp_polygon;
m_closed = qde.attribute("closed") != "false";
}
/**
Exporte le polygone en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant le polygone
* @brief PartPolygon::toXml
* Export this polygin in xml
* @param xml_document : Xml document to use for create the xml element
* @return an xml element that describe this polygon
*/
const QDomElement PartPolygon::toXml(QDomDocument &xml_document) const {
const QDomElement PartPolygon::toXml(QDomDocument &xml_document) const
{
QDomElement xml_element = xml_document.createElement("polygon");
int i = 1;
foreach(QPointF point, polygon()) {
foreach(QPointF point, m_polygon) {
point = mapToScene(point);
xml_element.setAttribute(QString("x%1").arg(i), QString("%1").arg(point.x()));
xml_element.setAttribute(QString("y%1").arg(i), QString("%1").arg(point.y()));
@@ -87,101 +110,95 @@ const QDomElement PartPolygon::toXml(QDomDocument &xml_document) const {
}
/**
Dessine le polygone
@param painter QPainter a utiliser pour rendre le dessin
@param options Options pour affiner le rendu
@param widget Widget sur lequel le rendu est effectue
* @brief PartPolygon::isUseless
* @return true if this part is irrelevant and does not deserve to be Retained / registered.
* A polygon is relevant when he have 2 differents points
*/
void PartPolygon::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
Q_UNUSED(widget);
applyStylesToQPainter(*painter);
QPen t = painter -> pen();
t.setCosmetic(options && options -> levelOfDetail < 1.0);
if (isSelected()) t.setColor(Qt::red);
painter -> setPen(t);
if (m_closed) painter -> drawPolygon(polygon());
else painter -> drawPolyline(polygon());
}
bool PartPolygon::isUseless() const
{
if (m_polygon.count() < 2) return(true);
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartPolygon::itemChange(GraphicsItemChange change, const QVariant &value) {
if (scene()) {
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
updateCurrentPartEditor();
}
}
return(QGraphicsPolygonItem::itemChange(change, value));
}
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Un polygone est pertinent des lors qu'il possede deux points differents.
*/
bool PartPolygon::isUseless() const {
QPolygonF poly(polygon());
if (polygon().count() < 2) return(true);
QPointF previous_point;
for (int i = 1 ; i < poly.count() ; ++ i) {
if (poly[i] != poly[i-1]) return(false);
}
for (int i = 1 ; i < m_polygon.count() ; ++ i)
if (m_polygon[i] != m_polygon[i-1]) return(false);
return(true);
}
/**
@return the minimum, margin-less rectangle this part can fit into, in scene
coordinates. It is different from boundingRect() because it is not supposed
to imply any margin, and it is different from shape because it is a regular
rectangle, not a complex shape.
* @brief PartPolygon::sceneGeometricRect
* @return the minimum, margin-less rectangle this part can fit into, in scene
* coordinates. It is different from boundingRect() because it is not supposed
* to imply any margin, and it is different from shape because it is a regular
* rectangle, not a complex shape.
*/
QRectF PartPolygon::sceneGeometricRect() const {
return(mapToScene(polygon().boundingRect()).boundingRect());
return(mapToScene(m_polygon.boundingRect()).boundingRect());
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a initial_selection_rect bounding rectangle.
* @brief PartPolygon::startUserTransformation
* Start the user-induced transformation, provided this primitive is contained
* within the initial_selection_rect bounding rectangle.
* @param initial_selection_rect
*/
void PartPolygon::startUserTransformation(const QRectF &initial_selection_rect) {
void PartPolygon::startUserTransformation(const QRectF &initial_selection_rect)
{
Q_UNUSED(initial_selection_rect)
saved_points_ = mapToScene(polygon()).toList();
saved_points_ = mapToScene(m_polygon).toList();
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
* @brief PartPolygon::handleUserTransformation
* Handle the user-induced transformation from initial_selection_rect to new_selection_rect
* @param initial_selection_rect
* @param new_selection_rect
*/
void PartPolygon::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
void PartPolygon::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect)
{
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
setPolygon(mapFromScene(QPolygonF(mapped_points.toVector())));
m_polygon = (mapFromScene(QPolygonF(mapped_points.toVector())));
}
/**
@reimp CustomElementPart::preferredScalingMethod
This method is called by the decorator when it needs to determine the best
way to interactively scale a primitive. It is typically called when only a
single primitive is being scaled.
This reimplementation systematically returns QET::RoundScaleRatios.
* @brief PartPolygon::preferredScalingMethod
* This method is called by the decorator when it needs to determine the best
* way to interactively scale a primitive. It is typically called when only a
* single primitive is being scaled.
* @return : This reimplementation systematically returns QET::RoundScaleRatios.
*/
QET::ScalingMethod PartPolygon::preferredScalingMethod() const {
return(QET::RoundScaleRatios);
}
/**
* @brief PartPolygon::polygon
* @return the item's polygon, or an empty polygon if no polygon has been set.
*/
QPolygonF PartPolygon::polygon() const {
return m_polygon;
}
/**
* @brief PartPolygon::setPolygon
* Sets the item's polygon to be the given polygon.
* @param polygon
*/
void PartPolygon::setPolygon(const QPolygonF &polygon)
{
if (m_polygon == polygon) return;
prepareGeometryChange();
m_polygon = polygon;
}
/**
* @brief PartPolygon::addPoint
* Add new point to polygon
* @param point
*/
void PartPolygon::addPoint(const QPointF &point) {
QPolygonF poly = polygon();
poly << point;
setPolygon(poly);
void PartPolygon::addPoint(const QPointF &point)
{
prepareGeometryChange();
m_polygon << point;
}
/**
@@ -189,35 +206,59 @@ void PartPolygon::addPoint(const QPointF &point) {
* Set the last point of polygon to @point
* @param point
*/
void PartPolygon::setLastPoint(const QPointF &point) {
QPolygonF poly = polygon();
void PartPolygon::setLastPoint(const QPointF &point)
{
if (m_polygon.size())
m_polygon.pop_back();
if (poly.size())
poly.pop_back();
poly << point;
setPolygon(poly);
prepareGeometryChange();
m_polygon << point;
}
/**
* @brief PartPolygon::removeLastPoint
* Remove the last point of polygon
*/
void PartPolygon::removeLastPoint() {
QPolygonF poly = polygon();
if (poly.size())
poly.pop_back();
setPolygon(poly);
void PartPolygon::removeLastPoint()
{
if (m_polygon.size())
{
prepareGeometryChange();
m_polygon.pop_back();
}
}
/**
@return le rectangle delimitant cette partie.
* @brief PartPolygon::shape
* @return the shape of this item
*/
QRectF PartPolygon::boundingRect() const {
qreal adjust = 1.5;
QRectF r(QGraphicsPolygonItem::boundingRect());
QPainterPath PartPolygon::shape() const
{
QPainterPath shape;
shape.addPolygon(m_polygon);
if (m_closed)
shape.lineTo(m_polygon.first());
QPainterPathStroker pps;
pps.setWidth(penWeight());
return (pps.createStroke(shape));
}
/**
* @brief PartPolygon::boundingRect
* @return the bounding rect of this item
*/
QRectF PartPolygon::boundingRect() const
{
QRectF r = m_polygon.boundingRect();
qreal adjust = (SHADOWS_HEIGHT + penWeight()) / 2;
//We add 0.5 because CustomElementGraphicPart::drawShadowShape
//draw a shape bigger of 0.5 when pen weight is to 0.
if (penWeight() == 0) adjust += 0.5;
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
}

View File

@@ -17,63 +17,66 @@
*/
#ifndef PART_POLYGON_H
#define PART_POLYGON_H
#include <QtGui>
#include <QPolygonF>
#include "customelementgraphicpart.h"
/**
This class represents a polygon primitive which may be used to compose the
drawing of an electrical element within the element editor.
* @brief The PartPolygon class
* This class represents a polygon primitive which may be used to compose the
* drawing of an electrical element within the element editor.
*/
class PartPolygon : public CustomElementGraphicPart, public QGraphicsPolygonItem {
class PartPolygon : public CustomElementGraphicPart
{
Q_OBJECT
Q_PROPERTY(bool closed READ isClosed WRITE setClosed)
// constructors, destructor
public:
PartPolygon(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
PartPolygon(QETElementEditor *editor, QGraphicsItem *parent = 0);
virtual ~PartPolygon();
private:
PartPolygon(const PartPolygon &);
// attributes
private:
bool m_closed;
// methods
public:
enum { Type = UserType + 1105 };
/**
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
PartPolygon.
@return the QGraphicsItem type
* Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a PartPolygon.
* @return the QGraphicsItem type
*/
virtual int type() const { return Type; }
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
virtual QString name() const { return(QObject::tr("polygone", "element part name")); }
virtual QString xmlName() const { return(QString("polygon")); }
void fromXml(const QDomElement &);
const QDomElement toXml(QDomDocument &) const;
virtual QPainterPath shape () const;
virtual QRectF boundingRect() const;
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
virtual bool isUseless() const;
virtual QRectF sceneGeometricRect() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
virtual QET::ScalingMethod preferredScalingMethod() const;
QPolygonF polygon () const;
void setPolygon (const QPolygonF &polygon);
void addPoint (const QPointF &point);
void setLastPoint (const QPointF &point);
void removeLastPoint ();
///PROPERTY
// Closed (join the first and last point by a line)
Q_PROPERTY(bool closed READ isClosed WRITE setClosed)
bool isClosed () const {return m_closed;}
void setClosed (bool c) {m_closed = c;}
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
private:
bool m_closed;
QList<QPointF> saved_points_;
QPolygonF m_polygon;
};
#endif

View File

@@ -18,181 +18,213 @@
#include "partrectangle.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@param parent Le QGraphicsItem parent de ce rectangle
@param scene La scene sur laquelle figure ce rectangle
* @brief PartRectangle::PartRectangle
* Constructor
* @param editor the QETElementEditor of this item
* @param parent parent item
*/
PartRectangle::PartRectangle(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : CustomElementGraphicPart(editor), QGraphicsRectItem(parent, scene) {
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptedMouseButtons(Qt::LeftButton);
}
/// Destructeur
PartRectangle::~PartRectangle() {
}
PartRectangle::PartRectangle(QETElementEditor *editor, QGraphicsItem *parent) :
CustomElementGraphicPart(editor, parent)
{}
/**
Dessine le rectangle
@param painter QPainter a utiliser pour rendre le dessin
@param options Options pour affiner le rendu
@param widget Widget sur lequel le rendu est effectue
* @brief PartRectangle::~PartRectangle
*/
void PartRectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
PartRectangle::~PartRectangle() {}
/**
* @brief PartRectangle::paint
* Draw this Rectangle
* @param painter
* @param options
* @param widget
*/
void PartRectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
{
Q_UNUSED(widget);
applyStylesToQPainter(*painter);
QPen t = painter -> pen();
t.setCosmetic(options && options -> levelOfDetail < 1.0);
if (isSelected()) {
t.setColor(Qt::red);
}
// force le type de jointures pour les rectangles
if (isSelected())
t.setColor(Qt::red);
t.setJoinStyle(Qt::MiterJoin);
// force le dessin avec un trait fin si l'une des dimensions du rectangle est nulle
if (!rect().width() || !rect().height()) {
//Force the pen to width 0 if one of dimension is null
if (!rect().width() || !rect().height())
t.setWidth(0);
}
painter -> setPen(t);
painter -> drawRect(rect());
if (isSelected()) {
painter -> setRenderHint(QPainter::Antialiasing, false);
painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
QPointF center = rect().center();
painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
}
if (m_hovered)
drawShadowShape(painter);
if (isSelected())
drawCross(m_rect.center(), painter);
}
/**
Exporte le rectangle en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant le rectangle
* @brief PartRectangle::toXml
* Export this rectangle in xml
* @param xml_document : Xml document to use for create the xml element.
* @return an xml element that describe this ellipse
*/
const QDomElement PartRectangle::toXml(QDomDocument &xml_document) const {
const QDomElement PartRectangle::toXml(QDomDocument &xml_document) const
{
QDomElement xml_element = xml_document.createElement("rect");
QPointF top_left(sceneTopLeft());
xml_element.setAttribute("x", QString("%1").arg(top_left.x()));
xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
xml_element.setAttribute("width", QString("%1").arg(rect().width()));
xml_element.setAttribute("height", QString("%1").arg(rect().height()));
xml_element.setAttribute("width", QString("%1").arg(m_rect.width()));
xml_element.setAttribute("height", QString("%1").arg(m_rect.height()));
stylesToXml(xml_element);
return(xml_element);
}
/**
Importe les proprietes d'une rectangle depuis un element XML
@param qde Element XML a lire
* @brief PartRectangle::fromXml
* Import the properties of this rectangle from a xml element.
* @param qde : Xml document to use.
*/
void PartRectangle::fromXml(const QDomElement &qde) {
void PartRectangle::fromXml(const QDomElement &qde)
{
stylesFromXml(qde);
setRect(
QRectF(
mapFromScene(
qde.attribute("x", "0").toDouble(),
qde.attribute("y", "0").toDouble()
),
QSizeF(
qde.attribute("width", "0").toDouble(),
qde.attribute("height", "0").toDouble()
)
)
);
setRect(QRectF(mapFromScene(qde.attribute("x", "0").toDouble(),
qde.attribute("y", "0").toDouble()),
QSizeF(qde.attribute("width", "0").toDouble(),
qde.attribute("height", "0").toDouble())));
}
/**
* @brief PartRectangle::setX
* @param x new value
* @brief PartRectangle::rect
* @return : Returns the item's rectangle.
*/
void PartRectangle::setX(qreal x) {
QRectF current_rect = rect();
QPointF current_pos = mapToScene(current_rect.topLeft());
setRect(current_rect.translated(x - current_pos.x(), 0.0));
QRectF PartRectangle::rect() const {
return m_rect;
}
/**
* @brief PartRectangle::setY
* @param y new value
* @brief PartRectangle::setRect
* Sets the item's rectangle to be the given rectangle.
* @param rect
*/
void PartRectangle::setY(qreal y) {
QRectF current_rect = rect();
QPointF current_pos = mapToScene(current_rect.topLeft());
setRect(current_rect.translated(0.0, y - current_pos.y()));
void PartRectangle::setRect(const QRectF &rect)
{
if (rect == m_rect) return;
prepareGeometryChange();
m_rect = rect;
}
/**
* @brief PartRectangle::rectTopLeft
* @return the rectangle top left in item coordinate
*/
QPointF PartRectangle::rectTopLeft() const {
return m_rect.topLeft();
}
/**
* @brief PartRectangle::setRectTopLeft
* @param point, set the rectangle top left in item coordinate.
* The rectangle size is unchanged
*/
void PartRectangle::setRectTopLeft(const QPointF &point) {
m_rect.moveTopLeft(point);
}
/**
* @brief PartRectangle::setWidth
* Sets the width of the rectangle to the given width.
* The right edge is changed, but not the left one.
* @param w new value
*/
void PartRectangle::setWidth(qreal w) {
qreal new_width = qAbs(w);
QRectF current_rect = rect();
current_rect.setWidth(new_width);
setRect(current_rect);
void PartRectangle::setWidth(qreal w)
{
prepareGeometryChange();
m_rect.setWidth(qAbs(w));
}
/**
* @brief PartRectangle::setHeight
* Sets the height of the rectangle to the given height.
* The bottom edge is changed, but not the top one.
* @param h new value
*/
void PartRectangle::setHeight(qreal h) {
qreal new_height = qAbs(h);
QRectF current_rect = rect();
current_rect.setHeight(new_height);
setRect(current_rect);
void PartRectangle::setHeight(qreal h)
{
prepareGeometryChange();
m_rect.setHeight(qAbs(h));
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartRectangle::itemChange(GraphicsItemChange change, const QVariant &value) {
if (scene()) {
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
updateCurrentPartEditor();
}
}
return(QGraphicsRectItem::itemChange(change, value));
}
/**
@return le coin superieur gauche du rectangle, dans les coordonnees de la
scene.
*/
QPointF PartRectangle::sceneTopLeft() const {
return(mapToScene(rect().topLeft()));
}
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Un rectangle est pertinent des lors que ses dimensions ne sont pas nulles.
*/
bool PartRectangle::isUseless() const {
return(rect().isNull());
}
/**
@return the minimum, margin-less rectangle this part can fit into, in scene
coordinates. It is different from boundingRect() because it is not supposed
to imply any margin, and it is different from shape because it is a regular
rectangle, not a complex shape.
* @brief PartRectangle::sceneGeometricRect
* @return the minimum, margin-less rectangle this part can fit into, in scene
* coordinates. It is different from boundingRect() because it is not supposed
* to imply any margin, and it is different from shape because it is a regular
* rectangle, not a complex shape.
*/
QRectF PartRectangle::sceneGeometricRect() const {
return(mapToScene(rect()).boundingRect());
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a initial_selection_rect bounding rectangle.
* @brief PartRectangle::sceneTopLeft
* @return the top left of rectangle, in scene coordinate
*/
void PartRectangle::startUserTransformation(const QRectF &initial_selection_rect) {
QPointF PartRectangle::sceneTopLeft() const {
return(mapToScene(rect().topLeft()));
}
/**
* @brief PartRectangle::shape
* @return the shape of this item
*/
QPainterPath PartRectangle::shape() const
{
QPainterPath shape;
shape.addRect(m_rect);
QPainterPathStroker pps;
pps.setWidth(penWeight());
return (pps.createStroke(shape));
}
/**
* @brief PartRectangle::boundingRect
* @return Bounding rectangle this part can fit into
*/
QRectF PartRectangle::boundingRect() const
{
qreal adjust = (SHADOWS_HEIGHT + penWeight()) / 2;
//We add 0.5 because CustomElementGraphicPart::drawShadowShape
//draw a shape bigger of 0.5 when pen weight is to 0.
if (penWeight() == 0) adjust += 0.5;
QRectF r = m_rect.normalized();
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
}
/**
* @brief PartRectangle::isUseless
* @return true if this part is irrelevant and does not deserve to be Retained / registered.
* An rectangle is relevant when he's not null.
*/
bool PartRectangle::isUseless() const {
return(rect().isNull());
}
/**
* @brief PartRectangle::startUserTransformation
* Start the user-induced transformation, provided this primitive is contained
* within the initial_selection_rect bounding rectangle.
* @param initial_selection_rect
*/
void PartRectangle::startUserTransformation(const QRectF &initial_selection_rect)
{
Q_UNUSED(initial_selection_rect)
// we keep track of our own rectangle at the moment in scene coordinates too
saved_points_.clear();
@@ -200,19 +232,13 @@ void PartRectangle::startUserTransformation(const QRectF &initial_selection_rect
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
* @brief PartRectangle::handleUserTransformation
* Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
* @param initial_selection_rect
* @param new_selection_rect
*/
void PartRectangle::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
void PartRectangle::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect)
{
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartRectangle::boundingRect() const {
qreal adjust = 1.5;
QRectF r(QGraphicsRectItem::boundingRect().normalized());
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
}

View File

@@ -17,17 +17,25 @@
*/
#ifndef PART_RECTANGLE_H
#define PART_RECTANGLE_H
#include <QtGui>
#include "customelementgraphicpart.h"
/**
This class represents a rectangle primitive which may be used to compose the
drawing of an electrical element within the element editor.
* This class represents a rectangle primitive which may be used to compose the
* drawing of an electrical element within the element editor.
* All coordinates is in item coordinate, except pos()
*/
class PartRectangle : public CustomElementGraphicPart, public QGraphicsRectItem {
class PartRectangle : public CustomElementGraphicPart
{
Q_OBJECT
Q_PROPERTY(QPointF rectTopLeft READ rectTopLeft WRITE setRectTopLeft)
Q_PROPERTY(qreal width READ width WRITE setWidth)
Q_PROPERTY(qreal height READ height WRITE setHeight)
// constructors, destructor
public:
PartRectangle(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
PartRectangle(QETElementEditor *, QGraphicsItem *parent = 0);
virtual ~PartRectangle();
private:
@@ -37,45 +45,41 @@ class PartRectangle : public CustomElementGraphicPart, public QGraphicsRectItem
public:
enum { Type = UserType + 1109 };
/**
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
PartRectangle.
@return the QGraphicsItem type
* Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a PartRectangle.
* @return the QGraphicsItem type
*/
virtual int type () const { return Type; }
virtual void paint (QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
virtual QString name () const { return(QObject::tr("rectangle", "element part name")); }
virtual QString xmlName () const { return(QString("rect")); }
virtual const QDomElement toXml (QDomDocument &) const;
virtual void fromXml (const QDomElement &);
virtual QPointF sceneTopLeft() const;
virtual QRectF boundingRect() const;
virtual bool isUseless() const;
virtual QRectF sceneGeometricRect() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
///PROPERTY
// X value
Q_PROPERTY(qreal x READ x WRITE setX)
qreal x() const {return mapToScene(rect().topLeft()).x();}
void setX(qreal x);
// Y value
Q_PROPERTY(qreal y READ y WRITE setY)
qreal y() const {return mapToScene(rect().topLeft()).y();}
void setY(qreal y);
// Width value
Q_PROPERTY(qreal width READ width WRITE setWidth)
QRectF rect() const;
void setRect(const QRectF &rect);
QPointF rectTopLeft () const;
void setRectTopLeft (const QPointF &point);
qreal width () const {return rect().width();}
void setWidth (qreal w);
// Height value
Q_PROPERTY(qreal height READ height WRITE setHeight)
qreal height () const { return rect().height();}
void setHeight (qreal h);
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
virtual QRectF sceneGeometricRect() const;
virtual QPointF sceneTopLeft() const;
virtual QPainterPath shape () const;
virtual QRectF boundingRect() const;
virtual bool isUseless() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
private:
QRectF m_rect;
QList<QPointF> saved_points_;
};
#endif

View File

@@ -24,16 +24,11 @@
@param parent Le QGraphicsItem parent de cette borne
@param scene La scene sur laquelle figure cette borne
*/
PartTerminal::PartTerminal(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
CustomElementGraphicPart(editor),
QGraphicsItem(parent, scene),
PartTerminal::PartTerminal(QETElementEditor *editor, QGraphicsItem *parent) :
CustomElementGraphicPart(editor, parent),
m_orientation(Qet::North)
{
updateSecondPoint();
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setZValue(100000);
}
@@ -107,23 +102,37 @@ void PartTerminal::paint(QPainter *p, const QStyleOptionGraphicsItem *options, Q
p -> setBrush(Terminal::neutralColor);
p -> drawPoint(QPointF(0.0, 0.0));
p -> restore();
if (m_hovered)
drawShadowShape(p);
}
/**
@return le rectangle delimitant cette partie.
* @brief PartTerminal::shape
* @return the shape of this item
*/
QRectF PartTerminal::boundingRect() const {
QPointF p1, p2;
if (second_point.x() <= 0.0 && second_point.y() <= 0.0) {
p1 = second_point;
p2 = QPointF(0.0, 0.0);
} else {
p1 = QPointF(0.0, 0.0);
p2 = second_point;
QPainterPath PartTerminal::shape() const
{
QPainterPath shape;
shape.lineTo(second_point);
QPainterPathStroker pps;
pps.setWidth(1);
return (pps.createStroke(shape));
}
QRectF br;
br.setTopLeft (p1 - QPointF(2.0, 2.0));
br.setBottomRight(p2 + QPointF(2.0, 2.0));
/**
* @brief PartTerminal::boundingRect
* @return the bounding rect of this item
*/
QRectF PartTerminal::boundingRect() const
{
QRectF br(QPointF(0, 0), second_point);
br = br.normalized();
qreal adjust = (SHADOWS_HEIGHT + 1) / 2;
br.adjust(-adjust, -adjust, adjust, adjust);
return(br);
}
@@ -137,20 +146,6 @@ void PartTerminal::setOrientation(Qet::Orientation ori) {
updateSecondPoint();
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartTerminal::itemChange(GraphicsItemChange change, const QVariant &value) {
if (scene()) {
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
updateCurrentPartEditor();
}
}
return(QGraphicsItem::itemChange(change, value));
}
/**
Met a jour la position du second point en fonction de la position et de
l'orientation de la borne.

View File

@@ -17,18 +17,22 @@
*/
#ifndef PART_TERMINAL_H
#define PART_TERMINAL_H
#include "customelementgraphicpart.h"
#include "qet.h"
#include <QtGui>
/**
This class represents a terminal which may be used to compose the drawing of
an electrical element within the element editor.
*/
class PartTerminal : public CustomElementGraphicPart, public QGraphicsItem {
class PartTerminal : public CustomElementGraphicPart
{
Q_OBJECT
Q_PROPERTY(Qet::Orientation orientation READ orientation WRITE setOrientation)
public:
// constructors, destructor
PartTerminal(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
PartTerminal(QETElementEditor *editor, QGraphicsItem *parent = 0);
virtual ~PartTerminal();
private:
PartTerminal(const PartTerminal &);
@@ -42,9 +46,8 @@ class PartTerminal : public CustomElementGraphicPart, public QGraphicsItem {
public:
enum { Type = UserType + 1106 };
/**
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
PartTerminal.
@return the QGraphicsItem type
* Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a PartTerminal.
* @return the QGraphicsItem type
*/
virtual int type() const { return Type; }
virtual QString name() const { return(QObject::tr("borne", "element part name")); }
@@ -52,28 +55,17 @@ class PartTerminal : public CustomElementGraphicPart, public QGraphicsItem {
virtual void fromXml(const QDomElement &);
virtual const QDomElement toXml(QDomDocument &) const;
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
virtual QRectF boundingRect() const;
/*virtual void setProperty(const QString &, const QVariant &);
virtual QVariant property(const QString &);*/
virtual QPainterPath shape() const;
virtual QRectF boundingRect() const;
virtual bool isUseless() const;
virtual QRectF sceneGeometricRect() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
///PROPERTY
// X value
Q_PROPERTY(qreal x READ x WRITE setX)
// Y value
Q_PROPERTY(qreal y READ y WRITE setY)
// Horientation value
Q_PROPERTY(Qet::Orientation orientation READ orientation WRITE setOrientation)
Qet::Orientation orientation() const {return m_orientation;}
void setOrientation(Qet::Orientation ori);
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
private:
void updateSecondPoint();

View File

@@ -119,6 +119,22 @@ CustomElementPart *LineEditor::currentPart() const {
return(part);
}
/**
* @brief LineEditor::editedP1
* @return The edited P1 in item coordinate
*/
QPointF LineEditor::editedP1() const {
return part -> mapFromScene(x1->value(), y1->value());
}
/**
* @brief LineEditor::editedP2
* @return The edited P2 in item coordinate
*/
QPointF LineEditor::editedP2() const {
return part -> mapFromScene(x2->value(), y2->value());
}
/**
Met a jour la ligne a partir des donnees du formulaire
*/
@@ -128,28 +144,18 @@ void LineEditor::updateLine() {
part -> setProperty("length1", end1_length -> value());
part -> setProperty("end2", end2_type -> itemData(end2_type->currentIndex()));
part -> setProperty("length2", end2_length -> value());
part -> setLine(
QLineF(
part -> mapFromScene(
x1 -> value(),
y1 -> value()
),
part -> mapFromScene(
x2 -> value(),
y2 -> value()
)
)
);
part -> setProperty("p1", editedP1());
part -> setProperty("p2", editedP2());
}
/// Met a jour l'abscisse du premier point de la ligne et cree un objet d'annulation
void LineEditor::updateLineX1() { addChangePartCommand(tr("abscisse point 1"), part, "x1", x1 -> value()); }
void LineEditor::updateLineX1() { addChangePartCommand(tr("abscisse point 1"), part, "p1", editedP1()); }
/// Met a jour l'ordonnee du premier point de la ligne et cree un objet d'annulation
void LineEditor::updateLineY1() { addChangePartCommand(tr("ordonn\351e point 1"), part, "y1", y1 -> value()); }
void LineEditor::updateLineY1() { addChangePartCommand(tr("ordonn\351e point 1"), part, "p1", editedP1()); }
/// Met a jour l'abscisse du second point de la ligne et cree un objet d'annulation
void LineEditor::updateLineX2() { addChangePartCommand(tr("abscisse point 2"), part, "x2", x2 -> value()); }
void LineEditor::updateLineX2() { addChangePartCommand(tr("abscisse point 2"), part, "p2", editedP2()); }
/// Met a jour l'ordonnee du second point de la ligne et cree un objet d'annulation
void LineEditor::updateLineY2() { addChangePartCommand(tr("ordonn\351e point 2"), part, "y2", y2 -> value()); }
void LineEditor::updateLineY2() { addChangePartCommand(tr("ordonn\351e point 2"), part, "p2", editedP2()); }
/// Met a jour le type de la premiere extremite
void LineEditor::updateLineEndType1() { addChangePartCommand(tr("type fin 1"), part, "end1", end1_type -> itemData(end1_type->currentIndex())); }
/// Met a jour la longueur de la premiere extremite

View File

@@ -24,7 +24,8 @@ class StyleEditor;
/**
This class provides a widget to edit lines within the element editor.
*/
class LineEditor : public ElementItemEditor {
class LineEditor : public ElementItemEditor
{
Q_OBJECT
// constructors, destructor
public:
@@ -45,6 +46,8 @@ class LineEditor : public ElementItemEditor {
public:
virtual bool setPart(CustomElementPart *);
virtual CustomElementPart *currentPart() const;
QPointF editedP1() const;
QPointF editedP2() const;
public slots:
void updateLine();

View File

@@ -97,21 +97,28 @@ CustomElementPart *RectangleEditor::currentPart() const {
return(part);
}
/**
* @brief RectangleEditor::topLeft
* @return The edited topLeft already mapped to part coordinate
*/
QPointF RectangleEditor::editedTopLeft() const {
return part -> mapFromScene(x->value(), y->value());
}
/**
Met a jour le rectangle a partir des donnees du formulaire
*/
void RectangleEditor::updateRectangle() {
if (!part) return;
part -> setProperty("x", x -> value());
part -> setProperty("y", y -> value());
part -> setProperty("rectTopLeft", editedTopLeft());
part -> setProperty("width", w -> value());
part -> setProperty("height", h -> value());
}
/// Met a jour l'abscisse du coin superieur gauche du rectangle et cree un objet d'annulation
void RectangleEditor::updateRectangleX() { addChangePartCommand(tr("abscisse"), part, "x", x -> value()); }
void RectangleEditor::updateRectangleX() { addChangePartCommand(tr("abscisse"), part, "rectTopLeft", editedTopLeft());}
/// Met a jour l'ordonnee du coin superieur gauche du rectangle et cree un objet d'annulation
void RectangleEditor::updateRectangleY() { addChangePartCommand(tr("ordonn\351e"), part, "y", y -> value()); }
void RectangleEditor::updateRectangleY() { addChangePartCommand(tr("ordonn\351e"), part, "rectTopLeft", editedTopLeft());}
/// Met a jour la largeur du rectangle et cree un objet d'annulation
void RectangleEditor::updateRectangleW() { addChangePartCommand(tr("largeur"), part, "width", w -> value());}
/// Met a jour la hauteur du rectangle et cree un objet d'annulation
@@ -123,8 +130,9 @@ void RectangleEditor::updateRectangleH() { addChangePartCommand(tr("hauteur"),
void RectangleEditor::updateForm() {
if (!part) return;
activeConnections(false);
x->setValue(part->property("x").toReal());
y->setValue(part->property("y").toReal());
QPointF p = part->mapToScene(part->property("rectTopLeft").toPointF());
x->setValue(p.x());
y->setValue(p.y());
w->setValue(part->property("width").toReal());
h->setValue(part->property("height").toReal());
activeConnections(true);

View File

@@ -43,6 +43,7 @@ class RectangleEditor : public ElementItemEditor {
public:
virtual bool setPart(CustomElementPart *);
virtual CustomElementPart *currentPart() const;
QPointF editedTopLeft () const;
public slots:
void updateRectangle();