Element editor : move all graphics part in a single directory

git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@3628 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
blacksun
2015-01-26 08:55:43 +00:00
parent 6256468c8e
commit d40f2c23b1
21 changed files with 3 additions and 0 deletions

View File

@@ -0,0 +1,180 @@
/*
Copyright 2006-2014 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 "customelementgraphicpart.h"
/**
Ecrit les attributs de style dans un element XML
@param qde L'element XML a modifier
*/
void CustomElementGraphicPart::stylesToXml(QDomElement &qde) const {
QString css_like_styles;
css_like_styles += "line-style:";
if (_linestyle == DashedStyle) css_like_styles += "dashed";
if (_linestyle == DottedStyle) css_like_styles += "dotted";
if (_linestyle == DashdottedStyle)css_like_styles += "dashdotted";
else if (_linestyle == NormalStyle) css_like_styles += "normal";
css_like_styles += ";line-weight:";
if (_lineweight == NoneWeight) css_like_styles += "none";
else if (_lineweight == ThinWeight) css_like_styles += "thin";
else if (_lineweight == NormalWeight) css_like_styles += "normal";
else if (_lineweight == UltraWeight) css_like_styles += "hight";
else if (_lineweight == BigWeight) css_like_styles += "eleve";
css_like_styles += ";filling:";
if (_filling == NoneFilling) css_like_styles += "none";
else if (_filling == BlackFilling) css_like_styles += "black";
else if (_filling == WhiteFilling) css_like_styles += "white";
else if (_filling == GreenFilling) css_like_styles += "green";
else if (_filling == BlueFilling) css_like_styles += "blue";
else if (_filling == RedFilling) css_like_styles += "red";
css_like_styles += ";color:";
if (_color == WhiteColor) css_like_styles += "white";
else if (_color == BlackColor) css_like_styles += "black";
else if (_color == GreenColor) css_like_styles += "green";
else if (_color == RedColor) css_like_styles += "red";
else if (_color == BlueColor) css_like_styles += "blue";
qde.setAttribute("style", css_like_styles);
qde.setAttribute("antialias", _antialiased ? "true" : "false");
}
/**
Lit les attributs de style depuis un element XML
@param qde L'element XML a analyser
*/
void CustomElementGraphicPart::stylesFromXml(const QDomElement &qde) {
resetStyles();
// recupere la liste des couples style / valeur
QStringList styles = qde.attribute("style").split(";", QString::SkipEmptyParts);
// analyse chaque couple
QRegExp rx("^\\s*([a-z-]+)\\s*:\\s*([a-z-]+)\\s*$");
foreach (QString style, styles) {
if (!rx.exactMatch(style)) continue;
QString style_name = rx.cap(1);
QString style_value = rx.cap(2);
if (style_name == "line-style") {
if (style_value == "dashed") _linestyle = DashedStyle;
if (style_value == "dotted") _linestyle = DottedStyle;
if (style_value == "dashdotted") _linestyle = DashdottedStyle;
else if (style_value == "normal") _linestyle = NormalStyle;
// il n'y a pas de else car les valeurs non conformes sont ignorees (idem par la suite)
} else if (style_name == "line-weight") {
if (style_value == "none") _lineweight = NoneWeight;
else if (style_value == "thin") _lineweight = ThinWeight;
else if (style_value == "normal") _lineweight = NormalWeight;
else if (style_value == "hight") _lineweight = UltraWeight;
else if (style_value == "eleve") _lineweight = BigWeight;
} else if (style_name == "filling") {
if (style_value == "white") _filling = WhiteFilling;
else if (style_value == "black") _filling = BlackFilling;
else if (style_value == "red") _filling = RedFilling;
else if (style_value == "green") _filling = GreenFilling;
else if (style_value == "blue") _filling = BlueFilling;
else if (style_value == "none") _filling = NoneFilling;
} else if (style_name == "color") {
if (style_value == "black") _color = BlackColor;
else if (style_value == "white") _color = WhiteColor;
else if (style_value == "green") _color = GreenColor;
else if (style_value == "red") _color = RedColor;
else if (style_value == "blue") _color = BlueColor;
}
}
// recupere l'antialiasing
_antialiased = qde.attribute("antialias") == "true";
}
/**
Remet les styles par defaut
*/
void CustomElementGraphicPart::resetStyles() {
_linestyle = NormalStyle;
_lineweight = NormalWeight;
_filling = NoneFilling;
_color = BlackColor;
_antialiased = false;
}
/**
Applique les styles a un Qpainter
@param painter QPainter a modifier
*/
void CustomElementGraphicPart::applyStylesToQPainter(QPainter &painter) const {
// recupere le QPen et la QBrush du QPainter
QPen pen = painter.pen();
QBrush brush = painter.brush();
// applique le style de trait
if (_linestyle == DashedStyle) pen.setStyle(Qt::DashLine);
if (_linestyle == DashdottedStyle) pen.setStyle(Qt::DashDotLine);
if (_linestyle == DottedStyle) pen.setStyle(Qt::DotLine);
else if (_linestyle == NormalStyle) pen.setStyle(Qt::SolidLine);
// applique l'epaisseur de trait
if (_lineweight == NoneWeight) pen.setColor(QColor(0, 0, 0, 0));
else if (_lineweight == ThinWeight) pen.setWidth(0);
else if (_lineweight == NormalWeight) pen.setWidthF(1.0);
else if (_lineweight == UltraWeight) pen.setWidthF(2.0);
else if (_lineweight == BigWeight) pen.setWidthF(5.0);
// applique le remplissage
if (_filling == NoneFilling) {
brush.setStyle(Qt::NoBrush);
} else if (_filling == BlackFilling) {
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::black);
} else if (_filling == WhiteFilling) {
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::white);
} else if (_filling == GreenFilling) {
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::green);
} else if (_filling == RedFilling) {
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::red);
} else if (_filling == BlueFilling) {
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::blue);
}
// applique la couleur de trait
if (_color == WhiteColor) pen.setColor(QColor(255, 255, 255, pen.color().alpha()));
else if (_color == BlackColor) pen.setColor(QColor( 0, 0, 0, pen.color().alpha()));
else if (_color == GreenColor) pen.setColor(QColor(Qt::green));
else if (_color == RedColor) pen.setColor(QColor(Qt::red));
else if (_color == BlueColor) pen.setColor(QColor(Qt::blue));
// applique l'antialiasing
painter.setRenderHint(QPainter::Antialiasing, _antialiased);
painter.setRenderHint(QPainter::TextAntialiasing, _antialiased);
painter.setRenderHint(QPainter::SmoothPixmapTransform, _antialiased);
painter.setPen(pen);
painter.setBrush(brush);
}

View File

@@ -0,0 +1,132 @@
/*
Copyright 2006-2014 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 CUSTOM_ELEMENT_GRAPHIC_PART_H
#define CUSTOM_ELEMENT_GRAPHIC_PART_H
#include <QPainter>
#include <QObject>
#include "customelementpart.h"
#include "styleeditor.h"
class QETElementEditor;
typedef CustomElementGraphicPart CEGP;
/**
This class represents an element visual/geometric primitive. It provides
methods to manage style attributes common to most primitives.
*/
class CustomElementGraphicPart : public QObject, public CustomElementPart {
Q_OBJECT
public:
/// This enum lists the various line styles available to draw primitives.
Q_ENUMS(LineStyle)
enum LineStyle {
NormalStyle, ///< Normal line
DashedStyle, ///< Dashed line
DottedStyle, ///< Dotted line
DashdottedStyle ///< Dashdotted line
};
/// This enum lists the various line weights available to draw primitives.
Q_ENUMS(LineWeight)
enum LineWeight {
NoneWeight, ///< Invisible line
ThinWeight, ///< Thin line
NormalWeight, ///< Normal line 1px
UltraWeight, ///< Normal line 2px
BigWeight ///< Big Line
};
/// This enum lists the various filling colors available to draw primitives.
Q_ENUMS(Filling)
enum Filling {
NoneFilling, ///< No filling (i.e. transparent)
BlackFilling, ///< Black filling
WhiteFilling, ///< White filling
GreenFilling, ///< Green filling
RedFilling, ///< Red filling
BlueFilling ///< Green filling
};
/// This enum lists the various line colors available to draw primitives.
Q_ENUMS(Color)
enum Color {
BlackColor, ///< Black line
WhiteColor, ///< White line
GreenColor, ///< Green line
RedColor, ///< Red line
BlueColor ///< Blue line
};
// constructors, destructor
public:
/**
Constructor
@param editor Element editor this primitive lives in.
*/
CustomElementGraphicPart(QETElementEditor *editor) :
CustomElementPart(editor),
_linestyle(NormalStyle),
_lineweight(NormalWeight),
_filling(NoneFilling),
_color(BlackColor),
_antialiased(false)
{
};
/// Destructor
virtual ~CustomElementGraphicPart() {
};
// attributes
private:
LineStyle _linestyle;
LineWeight _lineweight;
Filling _filling ;
Color _color;
bool _antialiased;
// methods
public:
/// PROPERTY
Q_PROPERTY(LineStyle line_style READ lineStyle WRITE setLineStyle)
LineStyle lineStyle() const {return _linestyle;}
void setLineStyle(const LineStyle ls) {_linestyle = ls;}
Q_PROPERTY(LineWeight line_weight READ lineWeight WRITE setLineWeight)
LineWeight lineWeight() const {return _lineweight;}
void setLineWeight(const LineWeight lw) {_lineweight = lw;}
Q_PROPERTY(Filling filling READ filling WRITE setFilling)
Filling filling() const {return _filling;}
void setFilling(const Filling f) {_filling = f;}
Q_PROPERTY(Color color READ color WRITE setColor)
Color color() const {return _color;}
void setColor(const Color c) {_color = c;}
Q_PROPERTY(bool antialias READ antialiased WRITE setAntialiased)
bool antialiased() const {return _antialiased;}
void setAntialiased(const bool b) {_antialiased = b;}
virtual void setProperty(const char *name, const QVariant &value) {QObject::setProperty(name, value);}
virtual QVariant property(const char *name) const {return QObject::property(name);}
protected:
void stylesToXml(QDomElement &) const;
void stylesFromXml(const QDomElement &);
void resetStyles();
void applyStylesToQPainter(QPainter &) const;
};
#endif

View File

@@ -0,0 +1,141 @@
/*
Copyright 2006-2014 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 "customelementpart.h"
#include "qetgraphicsitem/customelement.h"
#include "qetelementeditor.h"
/// @return le QETElementEditor auquel cet editeur appartient
QETElementEditor *CustomElementPart::elementEditor() const {
return(element_editor);
}
/**
Appelle le slot updateCurrentPartEditor de l'editeur
@see QETElementEditor::updateCurrentPartEditor()
*/
void CustomElementPart::updateCurrentPartEditor() const {
if (element_editor) {
element_editor -> updateCurrentPartEditor();
}
}
/// @return l'ElementScene contenant les parties editees par cet editeur
ElementScene *CustomElementPart::elementScene() const {
return(element_editor -> elementScene());
}
/// @return la QUndoStack a utiliser pour les annulations
QUndoStack &CustomElementPart::undoStack() const {
return(elementScene() -> undoStack());
}
/// @return this primitive as a QGraphicsItem
QGraphicsItem *CustomElementPart::toItem() {
return(dynamic_cast<QGraphicsItem *>(this));
}
/**
This method is called by the decorator when it manages only a single
primitive. This brings the possibility to implement custom behaviour, such
as text edition, points edition or specific resizing.
The default implementation does nothing.
*/
void CustomElementPart::setDecorator(ElementPrimitiveDecorator *decorator) {
Q_UNUSED(decorator)
}
/**
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.
The default implementation systematically returns
QET::SnapScalingPointToGrid
*/
QET::ScalingMethod CustomElementPart::preferredScalingMethod() const {
return(QET::SnapScalingPointToGrid);
}
/**
This method is called by the decorator when it manages only a single
primitive and it received a mouse press event.
The implementation should return true if the primitive accepts the event, false otherwise.
The default implementation returns false.
*/
bool CustomElementPart::singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *) {
return(false);
}
/**
This method is called by the decorator when it manages only a single
primitive and it received a mouse move event.
The implementation should return true if the primitive accepts the event, false otherwise.
The default implementation returns false.
*/
bool CustomElementPart::singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *) {
return(false);
}
/**
This method is called by the decorator when it manages only a single
primitive and it received a mouse release event.
The implementation should return true if the primitive accepts the event, false otherwise.
The default implementation returns false.
*/
bool CustomElementPart::singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *) {
return(false);
}
/**
This method is called by the decorator when it manages only a single
primitive and it received a mouse double click event.
The implementation should return true if the primitive accepts the event, false otherwise.
The default implementation returns false.
*/
bool CustomElementPart::singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *) {
return(false);
}
/**
Helper method to map points in CustomElementPart::handleUserTransformation()
@param initial_selection_rect Selection rectangle when the movement started, in scene coordinates
@param new_selection_rect New selection rectangle, in scene coordinates
@param points List of points when the movement started, in scene coordinates.
@return The list of points mapped from initial_selection_rect to new_selection_rect
*/
QList<QPointF> CustomElementPart::mapPoints(const QRectF &initial_selection_rect, const QRectF &new_selection_rect, const QList<QPointF> &points) {
QList<QPointF> new_points;
if (!points.count()) return(new_points);
// compare the new selection rectangle with the stored one to get the scaling ratio
qreal sx = new_selection_rect.width() / initial_selection_rect.width();
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
QPointF initial_top_left = initial_selection_rect.topLeft();
qreal new_top_left_x = new_selection_rect.x();
qreal new_top_left_y = new_selection_rect.y();
foreach (QPointF point, points) {
QPointF point_offset = point - initial_top_left;
new_points << QPointF(
new_top_left_x + (point_offset.rx() * sx),
new_top_left_y + (point_offset.y() * sy)
);
}
return(new_points);
}

View File

@@ -0,0 +1,114 @@
/*
Copyright 2006-2014 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 CUSTOM_ELEMENT_PART_H
#define CUSTOM_ELEMENT_PART_H
#include <QtGui>
#include <QtXml>
#include <QImage>
#include "qet.h"
class CustomElement;
class ElementPrimitiveDecorator;
class ElementScene;
class QETElementEditor;
/**
This abstract class represents a primitive of the visual representation of an
electrical element. The Element, FixedElement and CustomElement classes do not
embed its attributes and methods in order to remain lightweight; indeed, there
is no point for those classes to store their visual representation with
anything more complex than a QImage.
*/
class CustomElementPart {
// constructors, destructor
public:
/**
Constructor
@param editor Element editor this primitive is attached to
*/
CustomElementPart(QETElementEditor *editor) : element_editor(editor) {}
/// Destructor
virtual ~CustomElementPart() {}
private:
CustomElementPart(const CustomElementPart &);
// attributes
private:
QETElementEditor *element_editor;
// methods
public:
/**
Load the primitive from an XML element that describes it
*/
virtual void fromXml(const QDomElement &) = 0;
/**
Export the primitive as an XML element
*/
virtual const QDomElement toXml(QDomDocument &) const = 0;
/**
Set a specific property of the primitive
*/
virtual void setProperty(const char *name, const QVariant &value) = 0;
/**
Get the current value of a specific primitive property
*/
virtual QVariant property(const char *name) const = 0;
/**
@return whether the primitive appears to be useless (e.g. 0-length line)
Typically, useless primitives are discarded when saving the element.
*/
virtual bool isUseless() const = 0;
virtual QRectF sceneGeometricRect() const = 0;
/**
Inform this part a user-induced transformation is about to begin. This method can be used to save data required by handleUserTransformation().
*/
virtual void startUserTransformation(const QRectF &) = 0;
/**
Make this part fit into the provided rectangle.
*/
virtual void handleUserTransformation(const QRectF &, const QRectF &) = 0;
/// @return a pointer to the parent element editor
virtual QETElementEditor *elementEditor() const;
/**
Call the updateCurrentPartEditor() slot of the editor
@see QETElementEditor::updateCurrentPartEditor()
*/
virtual void updateCurrentPartEditor() const;
/// @return a pointer to the parent editing scene
virtual ElementScene *elementScene() const;
/// @return the element editor undo stack
virtual QUndoStack &undoStack() const;
/// @return the name of the primitive
virtual QString name() const = 0;
/// @return the name that will be used as XML tag when exporting the primitive
virtual QString xmlName() const = 0;
virtual QGraphicsItem *toItem();
virtual void setDecorator(ElementPrimitiveDecorator *);
virtual QET::ScalingMethod preferredScalingMethod() const;
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
protected:
QList<QPointF> mapPoints(const QRectF &, const QRectF &, const QList<QPointF> &);
};
#endif

View File

@@ -0,0 +1,230 @@
/*
Copyright 2006-2014 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 "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
*/
PartArc::PartArc(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
CustomElementGraphicPart(editor),
QGraphicsEllipseItem(parent, scene),
_angle(-90),
start_angle(0)
{
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptedMouseButtons(Qt::LeftButton);
}
/// Destructeur
PartArc::~PartArc() {
}
/**
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
*/
void PartArc::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
Q_UNUSED(widget);
applyStylesToQPainter(*painter);
// enleve systematiquement la couleur de fond
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
painter -> drawEllipse(rect());
// dessine l'arc en rouge
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));
}
}
/**
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
*/
const QDomElement PartArc::toXml(QDomDocument &xml_document) const {
QDomElement xml_element = xml_document.createElement("arc");
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("start", QString("%1").arg(start_angle));
xml_element.setAttribute("angle", QString("%1").arg(_angle));
stylesToXml(xml_element);
return(xml_element);
}
/**
Importe les proprietes d'un arc de cercle depuis un element XML
@param qde Element XML a lire
*/
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());
}
/**
@return le coin superieur gauche du rectangle dans lequel s'inscrit
l'ellipse dont fait partie cet arc, dans les coordonnees de la scene.
*/
QPointF PartArc::sceneTopLeft() const {
return(mapToScene(rect().topLeft()));
}
/**
* @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));
}
/**
* @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);
}

View File

@@ -0,0 +1,95 @@
/*
Copyright 2006-2014 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 PART_ARC_H
#define PART_ARC_H
#include <QtGui>
#include "customelementgraphicpart.h"
/**
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 {
Q_OBJECT
// constructors, destructor
public:
PartArc(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 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
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
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_;
};
#endif

View File

@@ -0,0 +1,205 @@
/*
Copyright 2006-2014 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 "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
*/
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() {
}
/**
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
*/
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()) {
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));
}
}
/**
Exporte l'ellipse en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant l'ellipse
*/
const QDomElement PartEllipse::toXml(QDomDocument &xml_document) const {
QDomElement xml_element;
if (qFuzzyCompare(rect().width(), rect().height())) {
xml_element = xml_document.createElement("circle");
xml_element.setAttribute("diameter", QString("%1").arg(rect().width()));
} 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
*/
void PartEllipse::fromXml(const QDomElement &qde) {
stylesFromXml(qde);
qreal width, height;
if (qde.tagName() == "ellipse") {
width = qde.attribute("width", "0").toDouble();
height = qde.attribute("height", "0").toDouble();
} 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);
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartEllipse::itemChange(GraphicsItemChange change, const QVariant &value) {
if (scene()) {
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
updateCurrentPartEditor();
}
}
return(QGraphicsEllipseItem::itemChange(change, value));
}
/**
@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()));
}
/**
@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);
}

View File

@@ -0,0 +1,81 @@
/*
Copyright 2006-2014 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 PART_ELLIPSE_H
#define PART_ELLIPSE_H
#include <QtGui>
#include "customelementgraphicpart.h"
/**
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 {
Q_OBJECT
// constructors, destructor
public:
PartEllipse(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
virtual ~PartEllipse();
private:
PartEllipse(const PartEllipse &);
// methods
public:
enum { Type = UserType + 1103 };
/**
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);
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_;
};
#endif

View File

@@ -0,0 +1,523 @@
/*
Copyright 2006-2014 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 "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
*/
PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
CustomElementGraphicPart(editor),
QGraphicsLineItem(parent, scene),
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() {
}
/**
@param end_type Type d'extremite
@return Le nombre de "longueurs" requises pour dessiner une extremite de type end_type
*/
uint PartLine::requiredLengthForEndType(const Qet::EndType &end_type) {
uint length_count_required = 0;
if (end_type == Qet::Circle || end_type == Qet::Diamond) {
length_count_required = 2;
} 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
*/
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;
applyStylesToQPainter(*painter);
QPen t = painter -> pen();
t.setJoinStyle(Qt::MiterJoin);
t.setCosmetic(options && options -> levelOfDetail < 1.0);
if (isSelected()) {
t.setColor(Qt::red);
}
painter -> setPen(t);
QPointF point1(line().p1());
QPointF point2(line().p2());
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);
}
/**
Exporte la ligne en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant la ligne
*/
const QDomElement PartLine::toXml(QDomDocument &xml_document) const {
QPointF p1(sceneP1());
QPointF p2(sceneP2());
QDomElement xml_element = xml_document.createElement("line");
xml_element.setAttribute("x1", QString("%1").arg(p1.x()));
xml_element.setAttribute("y1", QString("%1").arg(p1.y()));
xml_element.setAttribute("x2", QString("%1").arg(p2.x()));
xml_element.setAttribute("y2", QString("%1").arg(p2.y()));
xml_element.setAttribute("end1", Qet::endTypeToString(first_end));
xml_element.setAttribute("length1", QString("%1").arg(first_length));
xml_element.setAttribute("end2", Qet::endTypeToString(second_end));
xml_element.setAttribute("length2", QString("%1").arg(second_length));
stylesToXml(xml_element);
return(xml_element);
}
/**
Importe les proprietes d'une ligne depuis un element XML
@param qde Element XML a lire
*/
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()
)
)
);
first_end = Qet::endTypeFromString(qde.attribute("end1"));
first_length = qde.attribute("length1", "1.5").toDouble();
second_end = Qet::endTypeFromString(qde.attribute("end2"));
second_length = qde.attribute("length2", "1.5").toDouble();
}
/**
* @brief PartLine::setX1
* set X of P1
* @param x1
*/
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()));
}
/**
* @brief PartLine::setP1
* set first point to P1
* @param p1
*/
void PartLine::setP1(QPointF p1) {
setLine(QLineF(p1, line().p2()));
}
/**
* @brief PartLine::setX2
* set x of P2
* @param x2
*/
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));
}
/**
* @brief PartLine::setP2
* set second point to P2
* @param p2
*/
void PartLine::setP2(QPointF p2) {
setLine(QLineF(line().p1(), 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.
*/
QPointF PartLine::sceneP1() const {
return(mapToScene(line().p1()));
}
/**
@return le second point, dans les coordonnees de la scene.
*/
QPointF PartLine::sceneP2() const {
return(mapToScene(line().p2()));
}
/**
@return la forme selectionnable de la ligne
*/
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));
// 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));
}
// ajoute un cercle pour l'extremite 2 si besoin
if (second_end) {
QPainterPath t2;
t2.addEllipse(secondEndCircleRect());
t.addPath(t2.subtracted(t));
}
return(t);
}
/**
@return une liste contenant les deux points de la droite + les 4 points entourant ces deux points
*/
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();
QList<QPointF> result;
// cas particulier : la droite se ramene a un 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)
QPointF v_ab = b - a;
// et la distance AB : racine des coordonnees du vecteur au carre
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
QPointF u = v_ab / ab * marge;
// on definit le vecteur v(-b , a) qui est perpendiculaire a 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 h = a + m; // H = A + M
QPointF k = a + n; // K = A + N
QPointF i = b - n; // I = B - N
QPointF j = b - m; // J = B - M
result << h << i << j << k;
}
return(result);
}
/**
@return le rectangle encadrant l'integralite de la premiere extremite
*/
QRectF PartLine::firstEndCircleRect() const {
QList<QPointF> interesting_points = fourEndPoints(
line().p1(),
line().p2(),
first_length
);
QRectF end_rect(
interesting_points[0] - QPointF(first_length, first_length),
QSizeF(2.0 * first_length, 2.0 * first_length)
);
return(end_rect);
}
/**
@return le rectangle encadrant l'integralite de la seconde extremite
*/
QRectF PartLine::secondEndCircleRect() const {
QList<QPointF> interesting_points = fourEndPoints(
line().p2(),
line().p1(),
second_length
);
QRectF end_rect(
interesting_points[0] - QPointF(second_length, second_length),
QSizeF(2.0 * second_length, 2.0 * second_length)
);
return(end_rect);
}
/**
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
*/
void PartLine::debugPaint(QPainter *painter) {
painter -> save();
painter -> setPen(Qt::gray);
painter -> drawRect(boundingRect());
painter -> setPen(Qt::green);
painter -> drawRect(firstEndCircleRect());
painter -> drawRect(secondEndCircleRect());
painter -> setPen(Qt::red);
foreach(QPointF pointy, fourEndPoints(line().p1(), line().p2(), first_length)) {
painter -> drawEllipse(pointy, 0.1, 0.1);
}
foreach(QPointF pointy, fourEndPoints(line().p2(), line().p1(), second_length)) {
painter -> drawEllipse(pointy, 0.1, 0.1);
}
painter -> restore();
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartLine::boundingRect() const {
QRectF r(QGraphicsLineItem::boundingRect());
// le rectangle ainsi obtenu ne doit pas avoir une dimension nulle
r.adjust(0.0, 0.0, 0.1, 0.1);
// 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);
}
/**
@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
*/
bool PartLine::isUseless() const {
return(sceneP1() == sceneP2());
}
/**
@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.
*/
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
*/
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))));
}
/**
@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
*/
QList<QPointF> PartLine::fourEndPoints(const QPointF &end_point, const QPointF &other_point, const qreal &length) {
// vecteur et longueur de la ligne
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
QPointF u(line_vector / line_length * length);
QPointF v(-u.y(), u.x());
// points O, A, B et C
QPointF o(end_point - u);
QPointF a(o - u);
QPointF b(o + v);
QPointF c(o - v);
return(QList<QPointF>() << o << a << b << c);
}

View File

@@ -0,0 +1,135 @@
/*
Copyright 2006-2014 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 PART_LINE_H
#define PART_LINE_H
#include <QtGui>
#include "customelementgraphicpart.h"
#include "qet.h"
/**
This class represents a line primitive which may be used to compose the
drawing of an electrical element within the element editor. Lines may have
specific visual ends (e.g. arrows) through the setFirstEndType and
setSecondEndType methods. Their size can be defined using the
setFirstEndLength and setSecondEndLength methods. Please note ends are not
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 {
Q_OBJECT
// constructors, destructor
public:
PartLine(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
virtual ~PartLine();
private:
PartLine(const PartLine &);
// 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
*/
virtual int type() const { return Type; }
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
virtual QString name() const { return(QObject::tr("ligne", "element part name")); }
virtual QString xmlName() const { return(QString("line")); }
virtual const QDomElement toXml(QDomDocument &) const;
virtual void fromXml(const QDomElement &);
virtual QPointF sceneP1() const;
virtual QPointF sceneP2() const;
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 &);
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)
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)
qreal secondEndLength() const {return second_length;}
void setSecondEndLength(const qreal &l) {second_length = qMin(qAbs(l), line().length());}
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
private:
QList<QPointF> fourShapePoints() const;
QRectF firstEndCircleRect() const;
QRectF secondEndCircleRect() const;
void debugPaint(QPainter *);
};
#endif

View File

@@ -0,0 +1,223 @@
/*
Copyright 2006-2014 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 "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
*/
PartPolygon::PartPolygon(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
CustomElementGraphicPart(editor),
QGraphicsPolygonItem(parent, scene),
m_closed(false)
{
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptedMouseButtons(Qt::LeftButton);
}
/// Destructeur
PartPolygon::~PartPolygon() {
}
/**
Importe les proprietes d'un polygone depuis un element XML
@param qde Element XML a lire
*/
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;
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()
);
}
setPolygon(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
*/
const QDomElement PartPolygon::toXml(QDomDocument &xml_document) const {
QDomElement xml_element = xml_document.createElement("polygon");
int i = 1;
foreach(QPointF point, 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()));
++ i;
}
if (!m_closed) xml_element.setAttribute("closed", "false");
stylesToXml(xml_element);
return(xml_element);
}
/**
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
*/
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());
}
/**
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);
}
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.
*/
QRectF PartPolygon::sceneGeometricRect() const {
return(mapToScene(polygon().boundingRect()).boundingRect());
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a initial_selection_rect bounding rectangle.
*/
void PartPolygon::startUserTransformation(const QRectF &initial_selection_rect) {
Q_UNUSED(initial_selection_rect)
saved_points_ = mapToScene(polygon()).toList();
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a 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())));
}
/**
@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.
*/
QET::ScalingMethod PartPolygon::preferredScalingMethod() const {
return(QET::RoundScaleRatios);
}
/**
* @brief PartPolygon::addPoint
* Add new point to polygon
* @param point
*/
void PartPolygon::addPoint(const QPointF &point) {
QPolygonF poly = polygon();
poly << point;
setPolygon(poly);
}
/**
* @brief PartPolygon::setLastPoint
* Set the last point of polygon to @point
* @param point
*/
void PartPolygon::setLastPoint(const QPointF &point) {
QPolygonF poly = polygon();
if (poly.size())
poly.pop_back();
poly << point;
setPolygon(poly);
}
/**
* @brief PartPolygon::removeLastPoint
* Remove the last point of polygon
*/
void PartPolygon::removeLastPoint() {
QPolygonF poly = polygon();
if (poly.size())
poly.pop_back();
setPolygon(poly);
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartPolygon::boundingRect() const {
qreal adjust = 1.5;
QRectF r(QGraphicsPolygonItem::boundingRect());
r.adjust(-adjust, -adjust, adjust, adjust);
return(r);
}

View File

@@ -0,0 +1,79 @@
/*
Copyright 2006-2014 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 PART_POLYGON_H
#define PART_POLYGON_H
#include <QtGui>
#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.
*/
class PartPolygon : public CustomElementGraphicPart, public QGraphicsPolygonItem {
Q_OBJECT
// constructors, destructor
public:
PartPolygon(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 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
*/
virtual int type() const { return Type; }
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 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;
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:
QList<QPointF> saved_points_;
};
#endif

View File

@@ -0,0 +1,218 @@
/*
Copyright 2006-2014 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 "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
*/
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() {
}
/**
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
*/
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
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()) {
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));
}
}
/**
Exporte le rectangle en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant le rectangle
*/
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()));
stylesToXml(xml_element);
return(xml_element);
}
/**
Importe les proprietes d'une rectangle depuis un element XML
@param qde Element XML a lire
*/
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()
)
)
);
}
/**
* @brief PartRectangle::setX
* @param x new value
*/
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));
}
/**
* @brief PartRectangle::setY
* @param y new value
*/
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()));
}
/**
* @brief PartRectangle::setWidth
* @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);
}
/**
* @brief PartRectangle::setHeight
* @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);
}
/**
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.
*/
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.
*/
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();
saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight());
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a 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

@@ -0,0 +1,81 @@
/*
Copyright 2006-2014 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 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.
*/
class PartRectangle : public CustomElementGraphicPart, public QGraphicsRectItem {
Q_OBJECT
// constructors, destructor
public:
PartRectangle(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
virtual ~PartRectangle();
private:
PartRectangle(const PartRectangle &);
// methods
public:
enum { Type = UserType + 1109 };
/**
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)
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 &);
private:
QList<QPointF> saved_points_;
};
#endif

View File

@@ -0,0 +1,203 @@
/*
Copyright 2006-2014 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 "partterminal.h"
#include "terminal.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@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),
m_orientation(Qet::North)
{
updateSecondPoint();
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setZValue(100000);
}
/// Destructeur
PartTerminal::~PartTerminal() {
}
/**
Importe les proprietes d'une borne depuis un element XML
@param xml_elmt Element XML a lire
*/
void PartTerminal::fromXml(const QDomElement &xml_elmt) {
// lit la position de la borne
qreal term_x = 0.0, term_y = 0.0;
QET::attributeIsAReal(xml_elmt, "x", &term_x);
QET::attributeIsAReal(xml_elmt, "y", &term_y);
setPos(QPointF(term_x, term_y));
// lit l'orientation de la borne
m_orientation = Qet::orientationFromString(xml_elmt.attribute("orientation"));
updateSecondPoint();
}
/**
Exporte la borne en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant la borne
*/
const QDomElement PartTerminal::toXml(QDomDocument &xml_document) const {
QDomElement xml_element = xml_document.createElement("terminal");
// ecrit la position de la borne
xml_element.setAttribute("x", QString("%1").arg(scenePos().x()));
xml_element.setAttribute("y", QString("%1").arg(scenePos().y()));
// ecrit l'orientation de la borne
xml_element.setAttribute("orientation", Qet::orientationToString(m_orientation));
// Write name and number to XML
return(xml_element);
}
/**
Dessine la borne
@param p QPainter a utiliser pour rendre le dessin
@param options Options pour affiner le rendu
@param widget Widget sur lequel le rendu est effectue
*/
void PartTerminal::paint(QPainter *p, const QStyleOptionGraphicsItem *options, QWidget *widget) {
Q_UNUSED(widget);
p -> save();
// annulation des renderhints
p -> setRenderHint(QPainter::Antialiasing, false);
p -> setRenderHint(QPainter::TextAntialiasing, false);
p -> setRenderHint(QPainter::SmoothPixmapTransform, false);
QPen t;
t.setWidthF(1.0);
t.setCosmetic(options && options -> levelOfDetail < 1.0);
// dessin de la borne en rouge
t.setColor(isSelected() ? Terminal::neutralColor : Qt::red);
p -> setPen(t);
p -> drawLine(QPointF(0.0, 0.0), second_point);
// dessin du point d'amarrage au conducteur en bleu
t.setColor(isSelected() ? Qt::red : Terminal::neutralColor);
p -> setPen(t);
p -> setBrush(Terminal::neutralColor);
p -> drawPoint(QPointF(0.0, 0.0));
p -> restore();
}
/**
@return le rectangle delimitant cette partie.
*/
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;
}
QRectF br;
br.setTopLeft (p1 - QPointF(2.0, 2.0));
br.setBottomRight(p2 + QPointF(2.0, 2.0));
return(br);
}
/**
Definit l'orientation de la borne
@param ori la nouvelle orientation de la borne
*/
void PartTerminal::setOrientation(Qet::Orientation ori) {
prepareGeometryChange();
m_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.
*/
void PartTerminal::updateSecondPoint() {
qreal ts = 4.0; // terminal size
switch(m_orientation) {
case Qet::North: second_point = QPointF(0.0, ts); break;
case Qet::East : second_point = QPointF(-ts, 0.0); break;
case Qet::South: second_point = QPointF(0.0, -ts); break;
case Qet::West : second_point = QPointF(ts, 0.0); break;
}
}
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Une borne est toujours pertinente ; cette fonction renvoie donc
toujours false
*/
bool PartTerminal::isUseless() const {
return(false);
}
/**
@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 PartTerminal::sceneGeometricRect() const {
return(sceneBoundingRect());
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a initial_selection_rect bounding rectangle.
*/
void PartTerminal::startUserTransformation(const QRectF &initial_selection_rect) {
Q_UNUSED(initial_selection_rect)
saved_position_ = scenePos();
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
*/
void PartTerminal::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
QPointF mapped_point = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_position_).first();
setPos(mapped_point);
}

View File

@@ -0,0 +1,83 @@
/*
Copyright 2006-2014 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 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 {
Q_OBJECT
public:
// constructors, destructor
PartTerminal(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
virtual ~PartTerminal();
private:
PartTerminal(const PartTerminal &);
// attributes
private:
Qet::Orientation m_orientation;
QPointF second_point;
// methods
public:
enum { Type = UserType + 1106 };
/**
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")); }
virtual QString xmlName() const { return(QString("terminal")); }
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 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();
private:
QPointF saved_position_;
};
#endif

View File

@@ -0,0 +1,481 @@
/*
Copyright 2006-2014 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 "parttext.h"
#include "texteditor.h"
#include "editorcommands.h"
#include "elementprimitivedecorator.h"
#include "elementscene.h"
#include "qetapp.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@param parent Le QGraphicsItem parent de ce texte statique
@param scene La scene sur laquelle figure ce texte statique
*/
PartText::PartText(QETElementEditor *editor, QGraphicsItem *parent, ElementScene *scene) :
QGraphicsTextItem(parent, scene),
CustomElementPart(editor),
previous_text(),
decorator_(0)
{
#if QT_VERSION >= 0x040500
document() -> setDocumentMargin(1.0);
#endif
setDefaultTextColor(Qt::black);
setFont(QETApp::diagramTextsFont());
real_font_size_ = font().pointSize();
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptHoverEvents(true);
setDefaultTextColor(Qt::black);
setPlainText(QObject::tr("T", "default text when adding a text in the element editor"));
adjustItemPosition(1);
// adjust textfield position after line additions/deletions
connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
}
/// Destructeur
PartText::~PartText() {
}
/**
Importe les proprietes d'un texte statique depuis un element XML
@param xml_element Element XML a lire
*/
void PartText::fromXml(const QDomElement &xml_element) {
bool ok;
int font_size = xml_element.attribute("size").toInt(&ok);
if (!ok || font_size < 1) font_size = 20;
setBlack(xml_element.attribute("color") != "white");
setProperty("size" , font_size);
setPlainText(xml_element.attribute("text"));
qreal default_rotation_angle = 0.0;
if (QET::attributeIsAReal(xml_element, "rotation", &default_rotation_angle)) {
setRotation(default_rotation_angle);
}
setPos(
xml_element.attribute("x").toDouble(),
xml_element.attribute("y").toDouble()
);
}
/**
Exporte le texte statique en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant le texte statique
*/
const QDomElement PartText::toXml(QDomDocument &xml_document) const {
QDomElement xml_element = xml_document.createElement("text");
xml_element.setAttribute("x", QString("%1").arg(pos().x()));
xml_element.setAttribute("y", QString("%1").arg(pos().y()));
xml_element.setAttribute("text", toPlainText());
xml_element.setAttribute("size", font().pointSize());
// angle de rotation du champ de texte
if (rotation()) {
xml_element.setAttribute("rotation", QString("%1").arg(rotation()));
}
if (!isBlack()) {
xml_element.setAttribute("color", "white");
}
return(xml_element);
}
/**
@return Les coordonnees du point situe en bas a gauche du texte.
*/
QPointF PartText::margin() const {
QFont used_font = font();
QFontMetrics qfm(used_font);
// marge du texte
#if QT_VERSION >= 0x040500
qreal document_margin = document() -> documentMargin();
#else
// il semblerait qu'avant Qt 4.5, ceci vaille non pas 4.0 mais 2.0
qreal document_margin = 2.0;
#endif
QPointF margin(
// marge autour du texte
document_margin,
// marge au-dessus du texte + distance entre le plafond du texte et la baseline
document_margin + qfm.ascent()
);
return(margin);
}
/**
@reimp QGraphicsItem::focusInEvent(QFocusEvent *)
@param e The QFocusEvent object describing the focus gain.
Start text edition when the item gains focus.
*/
void PartText::focusInEvent(QFocusEvent *e) {
startEdition();
QGraphicsTextItem::focusInEvent(e);
}
/**
@reimp QGraphicsItem::focusOutEvent(QFocusEvent *)
@param e The QFocusEvent object describing the focus loss.
End text edition when the item loses focus.
*/
void PartText::focusOutEvent(QFocusEvent *e) {
QGraphicsTextItem::focusOutEvent(e);
endEdition();
}
/**
@reimp QGraphicsTextItem::keyPressEvent()
Used to handle the escape key when the event is delivered to the field, not
to the decorator.
*/
void PartText::keyPressEvent(QKeyEvent *event) {
if (event -> key() == Qt::Key_Escape) {
endEdition();
}
else {
QGraphicsTextItem::keyPressEvent(event);
}
}
/**
Permet a l'element texte de devenir editable lorsqu'on double-clique dessus
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
*/
void PartText::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
QGraphicsTextItem::mouseDoubleClickEvent(e);
if (e -> button() == Qt::LeftButton) {
setEditable(true);
}
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartText::itemChange(GraphicsItemChange change, const QVariant &value) {
if (change == QGraphicsItem::ItemPositionHasChanged || change == QGraphicsItem::ItemSceneHasChanged) {
updateCurrentPartEditor();
} else if (change == QGraphicsItem::ItemSelectedHasChanged) {
if (value.toBool() == true) {
updateCurrentPartEditor();
}
}
return(QGraphicsTextItem::itemChange(change, value));
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartText::boundingRect() const {
QRectF r = QGraphicsTextItem::boundingRect();
r.adjust(0.0, -1.1, 0.0, 0.0);
return(r);
}
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Un texte statique n'est pas pertinent lorsque son texte est vide.
*/
bool PartText::isUseless() const {
return(toPlainText().isEmpty());
}
/**
@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 PartText::sceneGeometricRect() const {
return(sceneBoundingRect());
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a rect bounding rectangle.
*/
void PartText::startUserTransformation(const QRectF &rect) {
Q_UNUSED(rect)
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
saved_font_size_ = real_font_size_;
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
*/
void PartText::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
// let's try the naive approach
QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_point_).first();
setPos(new_pos);
// adjust the font size following the vertical scale factor
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
qreal new_font_size = saved_font_size_ * sy;
setProperty("real_size", qMax(1, qRound(new_font_size)));
}
/**
Dessine le texte statique.
@param painter QPainter a utiliser pour effectuer le rendu
@param qsogi Pptions de dessin
@param widget Widget sur lequel on dessine (facultatif)
*/
void PartText::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, QWidget *widget) {
// According to the source code of QGraphicsTextItem::paint(), this should
// avoid the drawing of the dashed rectangle around the text.
QStyleOptionGraphicsItem our_qsogi(*qsogi);
our_qsogi.state = QStyle::State_None;
QGraphicsTextItem::paint(painter, &our_qsogi, widget);
#ifdef QET_DEBUG_EDITOR_TEXTS
painter -> setPen(Qt::blue);
painter -> drawRect(boundingRect());
painter -> setPen(Qt::red);
drawPoint(painter, QPointF(0, 0));
painter -> setPen(Qt::green);
drawPoint(painter, mapFromScene(pos()));
#endif
}
/**
Handle context menu events.
@param event Object describing the context menu event to handle.
*/
void PartText::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
Q_UNUSED(event);
}
/**
Handle events generated when the mouse hovers over the decorator.
@param event Object describing the hover event.
*/
void PartText::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
// force the cursor when the text is being edited
if (hasFocus() && decorator_) {
decorator_ -> setCursor(Qt::IBeamCursor);
}
QGraphicsTextItem::hoverMoveEvent(event);
}
/**
@reimp CustomElementPart::setDecorator(ElementPrimitiveDecorator *)
Install or remove a sceneEventFilter on the decorator and ensure it will
adjust itself while the text is being edited.
*/
void PartText::setDecorator(ElementPrimitiveDecorator *decorator) {
if (decorator) {
decorator -> installSceneEventFilter(this);
// ensure the decorator will adjust itself when the text area expands or shrinks
connect(document(), SIGNAL(contentsChanged()), decorator, SLOT(adjust()));
}
else {
decorator_ -> removeSceneEventFilter(this);
endEdition();
}
decorator_ = decorator;
}
/**
@reimp QGraphicsItem::sceneEventFilter(QGraphicsItem *, QEvent *).
Intercepts events before they reach the watched target, i.e. typically the
primitives decorator.
This method mainly works with key strokes (F2, escape) and double clicks to
begin or end text edition.
*/
bool PartText::sceneEventFilter(QGraphicsItem *watched, QEvent *event) {
if (watched != decorator_) return(false);
QPointF event_scene_pos = QET::graphicsSceneEventPos(event);
if (!event_scene_pos.isNull()) {
if (contains(mapFromScene(event_scene_pos))) {
if (hasFocus()) {
return sceneEvent(event); // manually deliver the event to this item
return(true); // prevent this event from being delivered to any item
} else {
if (event -> type() == QEvent::GraphicsSceneMouseDoubleClick) {
mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
}
}
}
}
else if (event -> type() == QEvent::KeyRelease || event -> type() == QEvent::KeyPress) {
// Intercept F2 and escape keystrokes to focus in and out
QKeyEvent *key_event = static_cast<QKeyEvent *>(event);
if (!hasFocus() && key_event -> key() == Qt::Key_F2) {
setEditable(true);
QTextCursor qtc = textCursor();
qtc.setPosition(qMax(0, document()->characterCount() - 1));
setTextCursor(qtc);
} else if (hasFocus() && key_event -> key() == Qt::Key_Escape) {
endEdition();
}
if (hasFocus()) {
sceneEvent(event); // manually deliver the event to this item
return(true); // prevent this event from being delivered to any item
}
}
return(false);
}
/**
Accept the mouse \a event relayed by \a decorator if this text item has focus.
*/
bool PartText::singleItemPressEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
Q_UNUSED(decorator)
Q_UNUSED(event)
return(hasFocus());
}
/**
Accept the mouse \a event relayed by \a decorator if this text item has focus.
*/
bool PartText::singleItemMoveEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
Q_UNUSED(decorator)
Q_UNUSED(event)
return(hasFocus());
}
/**
Accept the mouse \a event relayed by \a decorator if this text item has focus.
*/
bool PartText::singleItemReleaseEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
Q_UNUSED(decorator)
Q_UNUSED(event)
return(hasFocus());
}
/**
Accept the mouse \a event relayed by \a decorator if this text item has focus.
*/
bool PartText::singleItemDoubleClickEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
Q_UNUSED(decorator)
// calling mouseDoubleClickEvent() will set this text item editable and grab keyboard focus
if (event -> button() == Qt::LeftButton) {
mouseDoubleClickEvent(event);
return(true);
}
return(false);
}
/**
Cette methode s'assure que la position du champ de texte est coherente
en repositionnant son origine (c-a-d le milieu du bord gauche du champ de
texte) a la position originale. Cela est notamment utile lorsque le champ
de texte est agrandi ou retreci verticalement (ajout ou retrait de lignes).
@param new_block_count Nombre de blocs dans le PartText
*/
void PartText::adjustItemPosition(int new_block_count) {
Q_UNUSED(new_block_count);
QPointF origin_offset = margin();
QTransform base_translation;
base_translation.translate(-origin_offset.x(), -origin_offset.y());
setTransform(base_translation, false);
setTransformOriginPoint(origin_offset);
}
/**
@param editable Whether this text item should be interactively editable.
*/
void PartText::setEditable(bool editable) {
if (editable) {
setFlag(QGraphicsItem::ItemIsFocusable, true);
setTextInteractionFlags(Qt::TextEditorInteraction);
setFocus(Qt::MouseFocusReason);
}
else {
setTextInteractionFlags(Qt::NoTextInteraction);
setFlag(QGraphicsItem::ItemIsFocusable, false);
}
}
/**
Start text edition by storing the former value of the text.
*/
void PartText::startEdition() {
// !previous_text.isNull() means the text is being edited
previous_text = toPlainText();
}
/**
End text edition, potentially generating a ChangePartCommand if the text
has changed.
*/
void PartText::endEdition() {
if (!previous_text.isNull()) {
// the text was being edited
QString new_text = toPlainText();
if (previous_text != new_text) {
// the text was changed
ChangePartCommand *text_change = new ChangePartCommand(
TextEditor::tr("contenu") + " " + name(),
this,
"text",
previous_text,
new_text
);
previous_text = QString();
undoStack().push(text_change);
}
}
// deselectionne le texte
QTextCursor qtc = textCursor();
qtc.clearSelection();
setTextCursor(qtc);
setEditable(false);
if (decorator_) {
decorator_ -> setFocus();
}
}
#ifdef QET_DEBUG_EDITOR_TEXTS
/**
Dessine deux petites fleches pour mettre un point en valeur
@param painter QPainter a utiliser pour effectuer le rendu
@param point Point a dessiner
*/
void PartText::drawPoint(QPainter *painter, const QPointF &point) {
qreal px = point.x();
qreal py = point.y();
qreal size_1 = 5.0;
qreal size_2 = 1.0;
painter -> drawLine(QLineF(px, py, px + size_1, py));
painter -> drawLine(QLineF(px + size_1 - size_2, py - size_2, px + size_1, py));
painter -> drawLine(QLineF(px + size_1 - size_2, py + size_2, px + size_1, py));
painter -> drawLine(QLineF(px, py, px, py + size_1));
painter -> drawLine(QLineF(px, py + size_1, px - size_2, py + size_1 - size_2));
painter -> drawLine(QLineF(px, py + size_1, px + size_2, py + size_1 - size_2));
}
#endif

View File

@@ -0,0 +1,111 @@
/*
Copyright 2006-2014 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 PART_TEXT_H
#define PART_TEXT_H
#include <QtGui>
#include "customelementpart.h"
#include "qetapp.h"
class TextEditor;
class ElementPrimitiveDecorator;
/**
This class represents an static text primitive which may be used to compose
the drawing of an electrical element within the element editor.
*/
class PartText : public QGraphicsTextItem, public CustomElementPart {
Q_OBJECT
// constructors, destructor
public:
PartText(QETElementEditor *, QGraphicsItem * = 0, ElementScene * = 0);
virtual ~PartText();
private:
PartText(const PartText &);
// methods
public:
enum { Type = UserType + 1107 };
/**
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
PartText.
@return the QGraphicsItem type
*/
virtual int type() const { return Type; }
virtual QString name() const { return(QObject::tr("texte", "element part name")); }
virtual QString xmlName() const { return(QString("text")); }
void fromXml(const QDomElement &);
const QDomElement toXml(QDomDocument &) const;
void setRotation(qreal angle) {(QGraphicsObject::setRotation(QET::correctAngle(angle)));}
virtual bool isUseless() const;
virtual QRectF sceneGeometricRect() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0 );
virtual void setDecorator(ElementPrimitiveDecorator *);
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
///PROPERTY
void setProperty(const char *name, const QVariant &value) {QGraphicsTextItem::setProperty(name, value);}
QVariant property(const char *name) const {return QGraphicsTextItem::property(name);}
// Size value
Q_PROPERTY(qreal size READ size WRITE setSize)
qreal size () const {return font().pointSize();}
void setSize (qreal s) {setFont(QETApp::diagramTextsFont(s));}
// Real size value
Q_PROPERTY(qreal real_size READ realSize WRITE setRealSize)
qreal realSize() const {return real_font_size_;}
void setRealSize(qreal rs) {real_font_size_ = rs;}
// Color value (true = black , false = white)
Q_PROPERTY(bool color READ isBlack WRITE setBlack)
bool isBlack() const {return defaultTextColor() == Qt::black;}
void setBlack(bool b) {setDefaultTextColor(b ? Qt::black : Qt::white);}
// displayed string
Q_PROPERTY(QString text READ toPlainText WRITE setPlainText)
public slots:
void adjustItemPosition(int = 0);
void setEditable(bool);
void startEdition();
void endEdition();
protected:
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *);
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
virtual bool sceneEventFilter(QGraphicsItem *, QEvent *);
virtual void focusInEvent(QFocusEvent *);
virtual void focusOutEvent(QFocusEvent *);
virtual void keyPressEvent(QKeyEvent *);
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
QRectF boundingRect() const;
private:
QPointF margin() const;
#ifdef QET_DEBUG_EDITOR_TEXTS
void drawPoint(QPainter *, const QPointF &);
#endif
QString previous_text;
qreal real_font_size_;
QPointF saved_point_;
qreal saved_font_size_;
QGraphicsItem *decorator_;
};
#endif

View File

@@ -0,0 +1,465 @@
/*
Copyright 2006-2014 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 "parttextfield.h"
#include "textfieldeditor.h"
#include "editorcommands.h"
#include "elementprimitivedecorator.h"
#include "qetapp.h"
/**
Constructeur
@param editor L'editeur d'element concerne
@param parent Le QGraphicsItem parent de ce champ de texte
@param scene La scene sur laquelle figure ce champ de texte
*/
PartTextField::PartTextField(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
QGraphicsTextItem(parent, scene),
CustomElementPart(editor),
follow_parent_rotations(true),
m_tagg("none"),
previous_text(),
decorator_(0)
{
setDefaultTextColor(Qt::black);
setFont(QETApp::diagramTextsFont());
real_font_size_ = font().pointSize();
setFlags(QGraphicsItem::ItemIsSelectable);
#if QT_VERSION >= 0x040600
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
#endif
setAcceptHoverEvents(true);
setPlainText(QObject::tr("_", "default text when adding a textfield in the element editor"));
adjustItemPosition(1);
// adjust textfield position after line additions/deletions
connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
}
/// Destructeur
PartTextField::~PartTextField() {
}
/**
Importe les proprietes d'un champ de texte depuis un element XML
@param xml_element Element XML a lire
*/
void PartTextField::fromXml(const QDomElement &xml_element) {
bool ok;
int font_size = xml_element.attribute("size").toInt(&ok);
if (!ok || font_size < 1) font_size = 20;
setProperty("size", font_size);
setPlainText(xml_element.attribute("text"));
m_tagg = xml_element.attribute("tagg", "none");
qreal default_rotation_angle = 0.0;
if (QET::attributeIsAReal(xml_element, "rotation", &default_rotation_angle)) {
setRotationAngle(default_rotation_angle);
}
setPos(
xml_element.attribute("x").toDouble(),
xml_element.attribute("y").toDouble()
);
follow_parent_rotations = (xml_element.attribute("rotate") == "true");
}
/**
Exporte le champ de texte en XML
@param xml_document Document XML a utiliser pour creer l'element XML
@return un element XML decrivant le champ de texte
*/
const QDomElement PartTextField::toXml(QDomDocument &xml_document) const {
QDomElement xml_element = xml_document.createElement("input");
xml_element.setAttribute("x", QString("%1").arg(pos().x()));
xml_element.setAttribute("y", QString("%1").arg(pos().y()));
xml_element.setAttribute("text", toPlainText());
xml_element.setAttribute("size", font().pointSize());
xml_element.setAttribute("tagg", m_tagg);
// angle de rotation du champ de texte
if (rotation()) {
xml_element.setAttribute("rotation", QString("%1").arg(rotation()));
}
// suivi (ou non) des rotations de l'element parent par le champ de texte
if (follow_parent_rotations) {
xml_element.setAttribute("rotate", "true");
}
return(xml_element);
}
/**
@return le decalage entre l'origine du QGraphicsItem et l'origine du champ de
texte.
*/
QPointF PartTextField::margin() const {
return(QPointF(0.0, boundingRect().bottom() / 2.0));
}
/**
Handle context menu events.
@param event Object describing the context menu event to handle.
*/
void PartTextField::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
Q_UNUSED(event);
}
/**
Handle events generated when the mouse hovers over the decorator.
@param event Object describing the hover event.
*/
void PartTextField::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
// force the cursor when the text is being edited
if (hasFocus() && decorator_) {
decorator_ -> setCursor(Qt::IBeamCursor);
}
QGraphicsTextItem::hoverMoveEvent(event);
}
/**
@reimp QGraphicsItem::sceneEventFilter(QGraphicsItem *, QEvent *).
Intercepts events before they reach the watched target, i.e. typically the
primitives decorator.
This method mainly works with key strokes (F2, escape) and double clicks to
begin or end text edition.
*/
bool PartTextField::sceneEventFilter(QGraphicsItem *watched, QEvent *event) {
if (watched != decorator_) return(false);
QPointF event_scene_pos = QET::graphicsSceneEventPos(event);
if (!event_scene_pos.isNull()) {
if (contains(mapFromScene(event_scene_pos))) {
if (hasFocus()) {
return sceneEvent(event); // manually deliver the event to this item
return(true); // prevent this event from being delivered to any item
} else {
if (event -> type() == QEvent::GraphicsSceneMouseDoubleClick) {
mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
}
}
}
}
else if (event -> type() == QEvent::KeyRelease || event -> type() == QEvent::KeyPress) {
// Intercept F2 and escape keystrokes to focus in and out
QKeyEvent *key_event = static_cast<QKeyEvent *>(event);
if (!hasFocus() && key_event -> key() == Qt::Key_F2) {
setEditable(true);
QTextCursor qtc = textCursor();
qtc.setPosition(qMax(0, document()->characterCount() - 1));
setTextCursor(qtc);
} else if (hasFocus() && key_event -> key() == Qt::Key_Escape) {
endEdition();
}
if (hasFocus()) {
sceneEvent(event); // manually deliver the event to this item
return(true); // prevent this event from being delivered to any item
}
}
return(false);
}
/*
@reimp QGraphicsItem::focusInEvent(QFocusEvent *)
@param e The QFocusEvent object describing the focus gain.
Start text edition when the item gains focus.
*/
void PartTextField::focusInEvent(QFocusEvent *e) {
startEdition();
QGraphicsTextItem::focusInEvent(e);
}
/**
Permet a l'element texte de redevenir deplacable a la fin de l'edition de texte
@param e Le QFocusEvent decrivant la perte de focus
*/
void PartTextField::focusOutEvent(QFocusEvent *e) {
QGraphicsTextItem::focusOutEvent(e);
endEdition();
}
/**
@reimp QGraphicsTextItem::keyPressEvent()
Used to handle the escape key when the event is delivered to the field, not
to the decorator.
*/
void PartTextField::keyPressEvent(QKeyEvent *event) {
if (event -> key() == Qt::Key_Escape) {
endEdition();
}
else {
QGraphicsTextItem::keyPressEvent(event);
}
}
/**
Permet a l'element texte de devenir editable lorsqu'on double-clique dessus
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
*/
void PartTextField::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
QGraphicsTextItem::mouseDoubleClickEvent(e);
if (e -> button() == Qt::LeftButton) {
setEditable(true);
}
}
/**
Gere les changements intervenant sur cette partie
@param change Type de changement
@param value Valeur numerique relative au changement
*/
QVariant PartTextField::itemChange(GraphicsItemChange change, const QVariant &value) {
if (change == QGraphicsItem::ItemPositionHasChanged || change == QGraphicsItem::ItemSceneHasChanged) {
updateCurrentPartEditor();
} else if (change == QGraphicsItem::ItemSelectedHasChanged) {
if (value.toBool() == true) {
updateCurrentPartEditor();
}
}
return(QGraphicsTextItem::itemChange(change, value));
}
/**
@return le rectangle delimitant cette partie.
*/
QRectF PartTextField::boundingRect() const {
QRectF r = QGraphicsTextItem::boundingRect();
r.adjust(0.0, -1.1, 0.0, 0.0);
return(r);
}
/**
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
conservee / enregistree.
Un champ de texte est toujours pertinent ; cette fonction renvoie donc
toujours false
*/
bool PartTextField::isUseless() const {
return(false);
}
/**
@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 PartTextField::sceneGeometricRect() const {
return(sceneBoundingRect());
}
/**
Start the user-induced transformation, provided this primitive is contained
within the \a initial_selection_rect bounding rectangle.
*/
void PartTextField::startUserTransformation(const QRectF &initial_selection_rect) {
Q_UNUSED(initial_selection_rect)
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
saved_font_size_ = real_font_size_;
}
/**
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
*/
void PartTextField::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
// let's try the naive approach
QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_point_).first();
setPos(new_pos);
// adjust the font size following the vertical scale factor
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
qreal new_font_size = saved_font_size_ * sy;
setProperty("real_size", qMax(1, qRound(new_font_size)));
}
/**
Dessine le texte statique.
@param painter QPainter a utiliser pour effectuer le rendu
@param qsogi Pptions de dessin
@param widget Widget sur lequel on dessine (facultatif)
*/
void PartTextField::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, QWidget *widget) {
// According to the source code of QGraphicsTextItem::paint(), this should
// avoid the drawing of the dashed rectangle around the text.
QStyleOptionGraphicsItem our_qsogi(*qsogi);
our_qsogi.state = QStyle::State_None;
QGraphicsTextItem::paint(painter, &our_qsogi, widget);
#ifdef QET_DEBUG_EDITOR_TEXTS
painter -> setPen(Qt::blue);
painter -> drawRect(boundingRect());
painter -> setPen(Qt::red);
drawPoint(painter, QPointF(0, 0));
painter -> setPen(QColor("#800000"));
drawPoint(painter, mapFromScene(pos()));
#endif
}
/**
@reimp CustomElementPart::setDecorator(ElementPrimitiveDecorator *)
Install or remove a sceneEventFilter on the decorator and ensure it will
adjust itself while the text is being edited.
*/
void PartTextField::setDecorator(ElementPrimitiveDecorator *decorator) {
if (decorator) {
decorator -> installSceneEventFilter(this);
// ensure the decorator will adjust itself when the text area expands or shrinks
connect(document(), SIGNAL(contentsChanged()), decorator, SLOT(adjust()));
}
else {
decorator_ -> removeSceneEventFilter(this);
endEdition();
}
decorator_ = decorator;
}
/**
Accept the mouse \a event relayed by \a decorator if this text item has focus.
*/
bool PartTextField::singleItemPressEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
Q_UNUSED(decorator)
Q_UNUSED(event)
return(hasFocus());
}
/**
Accept the mouse \a event relayed by \a decorator if this text item has focus.
*/
bool PartTextField::singleItemMoveEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
Q_UNUSED(decorator)
Q_UNUSED(event)
return(hasFocus());
}
/**
Accept the mouse \a event relayed by \a decorator if this text item has focus.
*/
bool PartTextField::singleItemReleaseEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
Q_UNUSED(decorator)
Q_UNUSED(event)
return(hasFocus());
}
/**
Accept the mouse \a event relayed by \a decorator if this text item has focus.
*/
bool PartTextField::singleItemDoubleClickEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
Q_UNUSED(decorator)
// calling mouseDoubleClickEvent() will set this text item editable and grab keyboard focus
if (event -> button() == Qt::LeftButton) {
mouseDoubleClickEvent(event);
return(true);
}
return(false);
}
/**
Cette methode s'assure que la position du champ de texte est coherente
en repositionnant son origine (c-a-d le milieu du bord gauche du champ de
texte) a la position originale. Cela est notamment utile lorsque le champ
de texte est agrandi ou retreci verticalement (ajout ou retrait de lignes).
@param new_block_count Nombre de blocs dans le PartTextField
*/
void PartTextField::adjustItemPosition(int new_block_count) {
Q_UNUSED(new_block_count);
qreal origin_offset = boundingRect().bottom() / 2.0;
QTransform base_translation;
base_translation.translate(0.0, -origin_offset);
setTransform(base_translation, false);
setTransformOriginPoint(0.0, origin_offset);
}
/**
@param editable Whether this text item should be interactively editable.
*/
void PartTextField::setEditable(bool editable) {
if (editable) {
setFlag(QGraphicsItem::ItemIsFocusable, true);
setTextInteractionFlags(Qt::TextEditorInteraction);
setFocus(Qt::MouseFocusReason);
}
else {
setTextInteractionFlags(Qt::NoTextInteraction);
setFlag(QGraphicsItem::ItemIsFocusable, false);
}
}
/**
Start text edition by storing the former value of the text.
*/
void PartTextField::startEdition() {
// !previous_text.isNull() means the text is being edited
previous_text = toPlainText();
}
/**
End text edition, potentially generating a ChangePartCommand if the text
has changed.
*/
void PartTextField::endEdition() {
if (!previous_text.isNull()) {
// the text was being edited
QString new_text = toPlainText();
if (previous_text != new_text) {
// the text was changed
ChangePartCommand *text_change = new ChangePartCommand(
TextFieldEditor::tr("contenu") + " " + name(),
this,
"text",
previous_text,
new_text
);
previous_text = QString();
undoStack().push(text_change);
}
}
// deselectionne le texte
QTextCursor qtc = textCursor();
qtc.clearSelection();
setTextCursor(qtc);
setEditable(false);
if (decorator_) {
decorator_ -> setFocus();
}
}
#ifdef QET_DEBUG_EDITOR_TEXTS
/**
Dessine deux petites fleches pour mettre un point en valeur
@param painter QPainter a utiliser pour effectuer le rendu
@param point Point a dessiner
*/
void PartTextField::drawPoint(QPainter *painter, const QPointF &point) {
qreal px = point.x();
qreal py = point.y();
qreal size_1 = 5.0;
qreal size_2 = 1.0;
painter -> drawLine(QLineF(px, py, px + size_1, py));
painter -> drawLine(QLineF(px + size_1 - size_2, py - size_2, px + size_1, py));
painter -> drawLine(QLineF(px + size_1 - size_2, py + size_2, px + size_1, py));
painter -> drawLine(QLineF(px, py, px, py + size_1));
painter -> drawLine(QLineF(px, py + size_1, px - size_2, py + size_1 - size_2));
painter -> drawLine(QLineF(px, py + size_1, px + size_2, py + size_1 - size_2));
}
#endif

View File

@@ -0,0 +1,126 @@
/*
Copyright 2006-2014 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 PART_TEXTFIELD_H
#define PART_TEXTFIELD_H
#include <QtGui>
#include "customelementpart.h"
#include "qetapp.h"
class TextFieldEditor;
class QETElementEditor;
class ElementPrimitiveDecorator;
/**
This class represents an editable text field which may be used to compose the
drawing of an electrical element within the element editor. Users may specify
a default value. The field will remain editable once the element is added onto
a diagram. lorsque l'element sera pose sur un schema.
*/
class PartTextField : public QGraphicsTextItem, public CustomElementPart {
Q_OBJECT
// constructors, destructor
public:
PartTextField(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
virtual ~PartTextField();
private:
PartTextField(const PartTextField &);
// attributes
bool follow_parent_rotations;
QString m_tagg;
// methods
public:
enum { Type = UserType + 1108 };
/**
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
PartTextField.
@return the QGraphicsItem type
*/
virtual int type() const { return Type; }
virtual QString name() const { return(QObject::tr("champ de texte", "element part name")); }
virtual QString xmlName() const { return(QString("input")); }
void fromXml(const QDomElement &);
const QDomElement toXml(QDomDocument &) const;
virtual bool isUseless() const;
virtual QRectF sceneGeometricRect() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0 );
virtual void setDecorator(ElementPrimitiveDecorator *);
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
///PROPERTY
virtual void setProperty(const char *name, const QVariant &value) {QGraphicsTextItem::setProperty(name, value);}
virtual QVariant property(const char *name) const {return QGraphicsTextItem::property(name);}
// displayed text
Q_PROPERTY(QString text READ toPlainText WRITE setPlainText)
// font size
Q_PROPERTY(int size READ size WRITE setSize)
int size() const {return font().pointSize();}
void setSize (const int value) {setFont(QETApp::diagramTextsFont(value)); real_font_size_ = value;}
// real size
Q_PROPERTY(qreal real_size READ realSize WRITE setRealSize)
qreal realSize() const {return real_font_size_;}
void setRealSize(const qreal size) {real_font_size_ = size;}
// angle of text
Q_PROPERTY(qreal rotation_angle READ rotation WRITE setRotationAngle)
void setRotationAngle(const qreal &angle) {setRotation(QET::correctAngle(angle));}
// follow parent rotation
Q_PROPERTY(bool rotate READ followParentRotations WRITE setFollowParentRotations)
bool followParentRotations() const {return follow_parent_rotations;}
void setFollowParentRotations(bool i) {follow_parent_rotations = i;}
// tagg of text
Q_PROPERTY(QString tagg READ tagg WRITE setTagg)
QString tagg() const {return m_tagg;}
void setTagg(const QString &tagg) {m_tagg = tagg;}
public slots:
void adjustItemPosition(int = 0);
void setEditable(bool);
void startEdition();
void endEdition();
protected:
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *);
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
virtual bool sceneEventFilter(QGraphicsItem *, QEvent *);
virtual void focusInEvent(QFocusEvent *);
virtual void focusOutEvent(QFocusEvent *);
virtual void keyPressEvent(QKeyEvent *);
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
QRectF boundingRect() const;
private:
QPointF margin() const;
#ifdef QET_DEBUG_EDITOR_TEXTS
void drawPoint(QPainter *, const QPointF &);
#endif
QString previous_text;
qreal real_font_size_;
QPointF saved_point_;
qreal saved_font_size_;
QGraphicsItem *decorator_;
};
#endif