mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-01-27 21:39:57 +01:00
Merge sources dir branch devel to trunk
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@2613 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
1631
sources/qetgraphicsitem/conductor.cpp
Normal file
1631
sources/qetgraphicsitem/conductor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
170
sources/qetgraphicsitem/conductor.h
Normal file
170
sources/qetgraphicsitem/conductor.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 CONDUCTOR_H
|
||||
#define CONDUCTOR_H
|
||||
#include <QtGui>
|
||||
#include "terminal.h"
|
||||
#include "conductorprofile.h"
|
||||
#include "conductorproperties.h"
|
||||
#include "qetdiagrameditor.h"
|
||||
class ConductorSegment;
|
||||
class ConductorTextItem;
|
||||
class Element;
|
||||
typedef QPair<QPointF, Qt::Corner> ConductorBend;
|
||||
typedef QHash<Qt::Corner, ConductorProfile> ConductorProfilesGroup;
|
||||
/**
|
||||
This class represents a conductor, i.e. a wire between two element
|
||||
terminals.
|
||||
*/
|
||||
class Conductor : public QObject, public QGraphicsPathItem {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
Conductor(Terminal *, Terminal *, Diagram * = 0);
|
||||
virtual ~Conductor();
|
||||
|
||||
private:
|
||||
Conductor(const Conductor &);
|
||||
|
||||
// attributes
|
||||
public:
|
||||
enum { Type = UserType + 1001 };
|
||||
enum Highlight { None, Normal, Alert };
|
||||
|
||||
/// First terminal the wire is attached to
|
||||
Terminal *terminal1;
|
||||
/// Second terminal the wire is attached to
|
||||
Terminal *terminal2;
|
||||
|
||||
// methods
|
||||
public:
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
Conductor.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
void destroy();
|
||||
/// @return true if this conductor is destroyed
|
||||
bool isDestroyed() const { return(destroyed_); }
|
||||
Diagram *diagram() const;
|
||||
ConductorTextItem *textItem() const;
|
||||
void updatePath(const QRectF & = QRectF());
|
||||
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||
QRectF boundingRect() const;
|
||||
virtual QPainterPath shape() const;
|
||||
virtual qreal nearDistance() const;
|
||||
virtual QPainterPath nearShape() const;
|
||||
virtual QPainterPath variableShape(const qreal &) const;
|
||||
virtual bool isNearConductor(const QPointF &);
|
||||
qreal length();
|
||||
ConductorSegment *middleSegment();
|
||||
bool containsPoint(const QPointF &) const;
|
||||
QString text() const;
|
||||
void setText(const QString &);
|
||||
static bool valideXml(QDomElement &);
|
||||
bool fromXml(QDomElement &);
|
||||
QDomElement toXml(QDomDocument &, QHash<Terminal *, int> &) const;
|
||||
const QList<ConductorSegment *> segmentsList() const;
|
||||
void setProperties(const ConductorProperties &);
|
||||
ConductorProperties properties() const;
|
||||
void setProfile(const ConductorProfile &, Qt::Corner);
|
||||
ConductorProfile profile(Qt::Corner) const;
|
||||
void setProfiles(const ConductorProfilesGroup &);
|
||||
ConductorProfilesGroup profiles() const;
|
||||
void readProperties();
|
||||
void adjustTextItemPosition();
|
||||
virtual Highlight highlight() const;
|
||||
virtual void setHighlighted(Highlight);
|
||||
void autoText();
|
||||
QSet<Conductor *> relatedPotentialConductors(QList <Terminal *> *t_list=0);
|
||||
QETDiagramEditor* diagramEditor() const;
|
||||
|
||||
public slots:
|
||||
void displayedTextChanged();
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *);
|
||||
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *);
|
||||
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
|
||||
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
|
||||
private:
|
||||
/// Functional properties
|
||||
ConductorProperties properties_;
|
||||
/// Whether this conductor is still valid
|
||||
bool destroyed_;
|
||||
/// Text input for non simple, non-singleline conductors
|
||||
ConductorTextItem *text_item;
|
||||
/// Segments composing the conductor
|
||||
ConductorSegment *segments;
|
||||
/// Attributs related to mouse interaction
|
||||
QPointF press_point;
|
||||
bool moving_point;
|
||||
bool moving_segment;
|
||||
int moved_point;
|
||||
qreal previous_z_value;
|
||||
ConductorSegment *moved_segment;
|
||||
QPointF before_mov_text_pos_;
|
||||
/// Whether the conductor was manually modified by users
|
||||
bool modified_path;
|
||||
/// Whether the current profile should be saved as soon as possible
|
||||
bool has_to_save_profile;
|
||||
/// conductor profile: "photography" of what the conductor is supposed to look
|
||||
/// like - there is one profile per kind of traject
|
||||
ConductorProfilesGroup conductor_profiles;
|
||||
/// QPen et QBrush objects used to draw conductors
|
||||
static QPen conductor_pen;
|
||||
static QBrush conductor_brush;
|
||||
static QBrush square_brush;
|
||||
static bool pen_and_brush_initialized;
|
||||
/// Scale factor to render square used to move segments
|
||||
qreal segments_squares_scale_;
|
||||
/// Define whether and how the conductor should be highlighted
|
||||
Highlight must_highlight_;
|
||||
|
||||
private:
|
||||
void segmentsToPath();
|
||||
void saveProfile(bool = true);
|
||||
void generateConductorPath(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation);
|
||||
void updateConductorPath(const QPointF &, QET::Orientation, const QPointF &, QET::Orientation);
|
||||
uint segmentsCount(QET::ConductorSegmentType = QET::Both) const;
|
||||
QList<QPointF> segmentsToPoints() const;
|
||||
QSet<Conductor *> relatedConductors() const;
|
||||
QList<ConductorBend> bends() const;
|
||||
QList<QPointF> junctions() const;
|
||||
void pointsToSegments(QList<QPointF>);
|
||||
bool hasClickedOn(QPointF, QPointF) const;
|
||||
void calculateTextItemPosition();
|
||||
Qt::Corner currentPathType() const;
|
||||
void deleteSegments();
|
||||
static int getCoeff(const qreal &, const qreal &);
|
||||
static int getSign(const qreal &);
|
||||
QHash<ConductorSegmentProfile *, qreal> shareOffsetBetweenSegments(const qreal &offset, const QList<ConductorSegmentProfile *> &, const qreal & = 0.01) const;
|
||||
static QPointF extendTerminal(const QPointF &, QET::Orientation, qreal = 9.0);
|
||||
static qreal conductor_bound(qreal, qreal, qreal, qreal = 0.0);
|
||||
static qreal conductor_bound(qreal, qreal, bool);
|
||||
static Qt::Corner movementType(const QPointF &, const QPointF &);
|
||||
static QPointF movePointIntoPolygon(const QPointF &, const QPainterPath &);
|
||||
};
|
||||
#endif
|
||||
223
sources/qetgraphicsitem/conductortextitem.cpp
Normal file
223
sources/qetgraphicsitem/conductortextitem.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 "conductortextitem.h"
|
||||
#include "conductor.h"
|
||||
#include "diagramcommands.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param parent_conductor Conducteur auquel ce texte est rattache
|
||||
@param parent_diagram Schema auquel ce texte et son conducteur parent sont rattaches
|
||||
*/
|
||||
ConductorTextItem::ConductorTextItem(Conductor *parent_conductor, Diagram *parent_diagram) :
|
||||
DiagramTextItem(parent_conductor, parent_diagram),
|
||||
parent_conductor_(parent_conductor),
|
||||
moved_by_user_(false),
|
||||
rotate_by_user_(false),
|
||||
first_move_(true)
|
||||
{
|
||||
// par defaut, les DiagramTextItem sont Selectable et Movable
|
||||
// cela nous convient, on ne touche pas a ces flags
|
||||
}
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param text Le texte affiche par le champ de texte
|
||||
@param parent_conductor Conducteur auquel ce texte est rattache
|
||||
@param parent_diagram Schema auquel ce texte et son conducteur parent sont rattaches
|
||||
*/
|
||||
ConductorTextItem::ConductorTextItem(const QString &text, Conductor *parent_conductor, Diagram *parent_diagram) :
|
||||
DiagramTextItem(text, parent_conductor, parent_diagram),
|
||||
parent_conductor_(parent_conductor),
|
||||
moved_by_user_(false),
|
||||
rotate_by_user_(false),
|
||||
first_move_(true)
|
||||
{
|
||||
// par defaut, les DiagramTextItem sont Selectable et Movable
|
||||
// cela nous convient, on ne touche pas a ces flags
|
||||
}
|
||||
|
||||
/**
|
||||
Destructeur
|
||||
*/
|
||||
ConductorTextItem::~ConductorTextItem() {
|
||||
}
|
||||
|
||||
/**
|
||||
@return le conducteur parent de ce champ de texte, ou 0 si celui-ci n'en a
|
||||
pas
|
||||
*/
|
||||
Conductor *ConductorTextItem::parentConductor() const {
|
||||
return(parent_conductor_);
|
||||
}
|
||||
|
||||
/**
|
||||
Permet de lire le texte a mettre dans le champ a partir d'un element XML.
|
||||
Cette methode se base sur la position du champ pour assigner ou non la
|
||||
valeur a ce champ.
|
||||
@param e L'element XML representant le champ de texte
|
||||
*/
|
||||
void ConductorTextItem::fromXml(const QDomElement &e) {
|
||||
setPlainText(e.attribute("text"));
|
||||
|
||||
qreal user_pos_x, user_pos_y;
|
||||
if (
|
||||
QET::attributeIsAReal(e, "userx", &user_pos_x) &&
|
||||
QET::attributeIsAReal(e, "usery", &user_pos_y)
|
||||
) {
|
||||
setPos(user_pos_x, user_pos_y);
|
||||
}
|
||||
|
||||
setRotationAngle(e.attribute("rotation").toDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
@param document Le document XML a utiliser
|
||||
@return L'element XML representant ce champ de texte
|
||||
*/
|
||||
QDomElement ConductorTextItem::toXml(QDomDocument &document) const {
|
||||
QDomElement result = document.createElement("input");
|
||||
result.setAttribute("userx", QString("%1").arg(pos().x()));
|
||||
result.setAttribute("usery", QString("%1").arg(pos().y()));
|
||||
result.setAttribute("text", toPlainText());
|
||||
if (rotationAngle()) {
|
||||
result.setAttribute("rotation", QString("%1").arg(rotationAngle()));
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si ce champ de texte a ete explictement deplace par
|
||||
l'utilisateur, false sinon
|
||||
*/
|
||||
bool ConductorTextItem::wasMovedByUser() const {
|
||||
return(moved_by_user_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ConductorTextItem::wasRotateByUser
|
||||
* @return true if text was explicit moved by user else false
|
||||
*/
|
||||
bool ConductorTextItem::wasRotateByUser() const {
|
||||
return(rotate_by_user_);
|
||||
}
|
||||
|
||||
/**
|
||||
@param moved_by_user true pour que la position du texte soit consideree
|
||||
comme ayant ete definie par l'utilisateur (et donc soit sauvegardee), false
|
||||
pour remettre le texte a sa position originelle
|
||||
*/
|
||||
void ConductorTextItem::forceMovedByUser(bool moved_by_user) {
|
||||
if (moved_by_user == moved_by_user_) return;
|
||||
|
||||
moved_by_user_ = moved_by_user;
|
||||
if (!moved_by_user && parent_conductor_) {
|
||||
parent_conductor_ -> adjustTextItemPosition();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ConductorTextItem::forceRotateByUser
|
||||
* @param rotate_by_user true pour que la rotation du texte soit consideree
|
||||
comme ayant ete definie par l'utilisateur (et donc soit sauvegardee), false
|
||||
pour remettre le texte a sont angle originelle
|
||||
*/
|
||||
void ConductorTextItem::forceRotateByUser(bool rotate_by_user) {
|
||||
if (rotate_by_user == rotate_by_user_) return;
|
||||
|
||||
rotate_by_user_ = rotate_by_user;
|
||||
if (!rotate_by_user && parent_conductor_) {
|
||||
parent_conductor_ -> adjustTextItemPosition();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les clics de souris lies au champ de texte
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void ConductorTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
|
||||
before_mov_pos_ = pos();
|
||||
}
|
||||
first_move_ = true;
|
||||
DiagramTextItem::mousePressEvent(e);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les mouvements de souris lies au champ de texte
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void ConductorTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (textInteractionFlags() & Qt::TextEditable) {
|
||||
QGraphicsTextItem::mouseMoveEvent(e);
|
||||
} else if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
|
||||
if (first_move_) {
|
||||
mouse_to_origin_movement_ = before_mov_pos_ - mapToParent(e -> buttonDownPos(Qt::LeftButton));
|
||||
}
|
||||
|
||||
QPointF intended_pos = mapToParent(e -> pos()) + mouse_to_origin_movement_;
|
||||
// si ce texte est attache a un conducteur, alors ses mouvements seront
|
||||
// limites a une certaine distance du trace de ce conducteur
|
||||
if (parent_conductor_) {
|
||||
if (parent_conductor_ -> isNearConductor(intended_pos)) {
|
||||
setPos(intended_pos);
|
||||
parent_conductor_ -> setHighlighted(Conductor::Normal);
|
||||
} else {
|
||||
parent_conductor_ -> setHighlighted(Conductor::Alert);
|
||||
}
|
||||
}
|
||||
|
||||
} else e -> ignore();
|
||||
|
||||
if (first_move_) {
|
||||
first_move_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le relachement de souris
|
||||
Cette methode cree un objet d'annulation pour le deplacement
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void ConductorTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (flags() & QGraphicsItem::ItemIsMovable) {
|
||||
if (Diagram *diagram_ptr = diagram()) {
|
||||
// on cree un objet d'annulation correspondant au deplacement qui s'acheve
|
||||
QPointF applied_movement = pos() - before_mov_pos_;
|
||||
|
||||
if (!applied_movement.isNull()) {
|
||||
// on cree un objet d'annulation seulement pour ce champ de texte
|
||||
MoveConductorsTextsCommand *undo_object = new MoveConductorsTextsCommand(diagram_ptr);
|
||||
undo_object -> addTextMovement(this, before_mov_pos_, pos(), moved_by_user_);
|
||||
|
||||
// on active le flag indiquant que ce champ de texte a ete explicitement repositionne par l'utilisateur
|
||||
moved_by_user_ = true;
|
||||
|
||||
diagram_ptr -> undoStack().push(undo_object);
|
||||
}
|
||||
|
||||
if (parent_conductor_) {
|
||||
parent_conductor_ -> setHighlighted(Conductor::None);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(e -> modifiers() & Qt::ControlModifier)) {
|
||||
QGraphicsTextItem::mouseReleaseEvent(e);
|
||||
}
|
||||
}
|
||||
69
sources/qetgraphicsitem/conductortextitem.h
Normal file
69
sources/qetgraphicsitem/conductortextitem.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 CONDUCTOR_TEXT_ITEM_H
|
||||
#define CONDUCTOR_TEXT_ITEM_H
|
||||
#include "diagramtextitem.h"
|
||||
class Conductor;
|
||||
/**
|
||||
This class represents a text item attached to a parent conductor.
|
||||
It may be moved and edited by users.
|
||||
It may also be rotated to any angle.
|
||||
Its movements are however limited to a particular distance around its
|
||||
parent conductor.
|
||||
*/
|
||||
class ConductorTextItem : public DiagramTextItem {
|
||||
Q_OBJECT
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
ConductorTextItem(Conductor * = 0, Diagram * = 0);
|
||||
ConductorTextItem(const QString &, Conductor * = 0, Diagram * = 0);
|
||||
virtual ~ConductorTextItem();
|
||||
private:
|
||||
ConductorTextItem(const ConductorTextItem &);
|
||||
|
||||
// attributes
|
||||
public:
|
||||
enum { Type = UserType + 1006 };
|
||||
Conductor *parentConductor() const;
|
||||
virtual void fromXml(const QDomElement &);
|
||||
virtual QDomElement toXml(QDomDocument &) const;
|
||||
|
||||
// methods
|
||||
public:
|
||||
virtual int type() const { return Type; }
|
||||
virtual bool wasMovedByUser() const;
|
||||
virtual bool wasRotateByUser() const;
|
||||
virtual void forceMovedByUser(bool);
|
||||
virtual void forceRotateByUser(bool);
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
|
||||
|
||||
// attributes
|
||||
private:
|
||||
Conductor *parent_conductor_;
|
||||
bool moved_by_user_;
|
||||
bool rotate_by_user_;
|
||||
QPointF before_mov_pos_;
|
||||
bool first_move_;
|
||||
QPointF mouse_to_origin_movement_;
|
||||
};
|
||||
#endif
|
||||
808
sources/qetgraphicsitem/customelement.cpp
Normal file
808
sources/qetgraphicsitem/customelement.cpp
Normal file
@@ -0,0 +1,808 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 "customelement.h"
|
||||
#include "elementtextitem.h"
|
||||
#include "diagram.h"
|
||||
#include "qetapp.h"
|
||||
#include "partline.h"
|
||||
#include "elementdefinition.h"
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
Constructeur de la classe CustomElement. Permet d'instancier un element
|
||||
utilisable comme un element fixe a la difference que l'element perso est
|
||||
construit a partir d'une description au format XML. Celle-ci est recuperee
|
||||
a l'emplacement indique.
|
||||
@param location Emplacement de la definition d'element a utiliser
|
||||
@param qgi Le QGraphicsItem parent de cet element
|
||||
@param s Le Schema affichant cet element
|
||||
@param state Un pointeur facultatif vers un entier. La valeur de cet entier
|
||||
sera changee de maniere a refleter le deroulement de l'instanciation :
|
||||
- 0 : L'instanciation a reussi
|
||||
- 1 : l'emplacement n'a pas permis d'acceder a une definition d'element
|
||||
- 2 : la definition n'etait pas lisible
|
||||
- 3 : la definition n'etait pas valide / exploitable / utilisable
|
||||
- 4 : Le document XML n'est pas un element "definition"
|
||||
- 5 : Les attributs de la definition ne sont pas presents et / ou valides
|
||||
- 6 : La definition est vide
|
||||
- 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
|
||||
- 8 : Aucune partie du dessin n'a pu etre chargee
|
||||
*/
|
||||
CustomElement::CustomElement(const ElementsLocation &location, QGraphicsItem *qgi, Diagram *s, int *state) :
|
||||
FixedElement(qgi, s),
|
||||
elmt_state(-1),
|
||||
location_(location),
|
||||
forbid_antialiasing(false)
|
||||
{
|
||||
// recupere la definition de l'element
|
||||
ElementsCollectionItem *element_item = QETApp::collectionItem(location);
|
||||
ElementDefinition *element_definition;
|
||||
if (
|
||||
!element_item ||\
|
||||
!element_item -> isElement() ||\
|
||||
!(element_definition = qobject_cast<ElementDefinition *>(element_item))
|
||||
) {
|
||||
if (state) *state = 1;
|
||||
elmt_state = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!element_definition -> isReadable()) {
|
||||
if (state) *state = 2;
|
||||
elmt_state = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (element_definition -> isNull()) {
|
||||
if (state) *state = 3;
|
||||
elmt_state = 3;
|
||||
return;
|
||||
}
|
||||
|
||||
buildFromXml(element_definition -> xml(), &elmt_state);
|
||||
if (state) *state = elmt_state;
|
||||
if (elmt_state) return;
|
||||
|
||||
if (state) *state = 0;
|
||||
elmt_state = 0;
|
||||
}
|
||||
|
||||
CustomElement::CustomElement(const QDomElement &xml_def_elmt, QGraphicsItem *qgi, Diagram *s, int *state) : FixedElement(qgi, s) {
|
||||
int elmt_state = -1;
|
||||
buildFromXml(xml_def_elmt, &elmt_state);
|
||||
if (state) *state = elmt_state;
|
||||
}
|
||||
|
||||
/**
|
||||
Construit l'element personnalise a partir d'un element XML representant sa
|
||||
definition.
|
||||
@param xml_def_elmt
|
||||
@param state Un pointeur facultatif vers un entier. La valeur de cet entier
|
||||
sera changee de maniere a refleter le deroulement de l'instanciation :
|
||||
- 0 : La construction s'est bien passee
|
||||
- 4 : Le document XML n'est pas un element "definition"
|
||||
- 5 : Les attributs de la definition ne sont pas presents et / ou valides
|
||||
- 6 : La definition est vide
|
||||
- 7 : L'analyse d'un element XML decrivant une partie du dessin de l'element a echoue
|
||||
- 8 : Aucune partie du dessin n'a pu etre chargee
|
||||
@return true si le chargement a reussi, false sinon
|
||||
*/
|
||||
bool CustomElement::buildFromXml(const QDomElement &xml_def_elmt, int *state) {
|
||||
|
||||
if (xml_def_elmt.tagName() != "definition" || xml_def_elmt.attribute("type") != "element") {
|
||||
if (state) *state = 4;
|
||||
return(false);
|
||||
}
|
||||
|
||||
// verifie basiquement que la version actuelle est capable de lire ce fichier
|
||||
if (xml_def_elmt.hasAttribute("version")) {
|
||||
bool conv_ok;
|
||||
qreal element_version = xml_def_elmt.attribute("version").toDouble(&conv_ok);
|
||||
if (conv_ok && QET::version.toDouble() < element_version) {
|
||||
std::cerr << qPrintable(
|
||||
QObject::tr("Avertissement : l'\351l\351ment "
|
||||
" a \351t\351 enregistr\351 avec une version"
|
||||
" ult\351rieure de QElectroTech.")
|
||||
) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// ces attributs doivent etre presents et valides
|
||||
int w, h, hot_x, hot_y;
|
||||
if (
|
||||
!QET::attributeIsAnInteger(xml_def_elmt, QString("width"), &w) ||\
|
||||
!QET::attributeIsAnInteger(xml_def_elmt, QString("height"), &h) ||\
|
||||
!QET::attributeIsAnInteger(xml_def_elmt, QString("hotspot_x"), &hot_x) ||\
|
||||
!QET::attributeIsAnInteger(xml_def_elmt, QString("hotspot_y"), &hot_y) ||\
|
||||
!validOrientationAttribute(xml_def_elmt)
|
||||
) {
|
||||
if (state) *state = 5;
|
||||
return(false);
|
||||
}
|
||||
|
||||
// on peut d'ores et deja specifier la taille et le hotspot
|
||||
setSize(w, h);
|
||||
setHotspot(QPoint(hot_x, hot_y));
|
||||
setInternalConnections(xml_def_elmt.attribute("ic") == "true");
|
||||
|
||||
// la definition est supposee avoir des enfants
|
||||
if (xml_def_elmt.firstChild().isNull()) {
|
||||
if (state) *state = 6;
|
||||
return(false);
|
||||
}
|
||||
|
||||
// initialisation du QPainter (pour dessiner l'element)
|
||||
QPainter qp;
|
||||
qp.begin(&drawing);
|
||||
|
||||
QPainter low_zoom_qp;
|
||||
low_zoom_qp.begin(&low_zoom_drawing);
|
||||
QPen tmp;
|
||||
tmp.setWidthF(1.0); // ligne vaudou pour prise en compte du setCosmetic - ne pas enlever
|
||||
tmp.setCosmetic(true);
|
||||
low_zoom_qp.setPen(tmp);
|
||||
|
||||
// extrait les noms de la definition XML
|
||||
names.fromXml(xml_def_elmt);
|
||||
setToolTip(name());
|
||||
|
||||
// parcours des enfants de la definition : parties du dessin
|
||||
int parsed_elements_count = 0;
|
||||
for (QDomNode node = xml_def_elmt.firstChild() ; !node.isNull() ; node = node.nextSibling()) {
|
||||
QDomElement elmts = node.toElement();
|
||||
if (elmts.isNull()) continue;
|
||||
if (elmts.tagName() == "description") {
|
||||
// gestion de la description graphique de l'element
|
||||
// = parcours des differentes parties du dessin
|
||||
for (QDomNode n = node.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
|
||||
QDomElement qde = n.toElement();
|
||||
if (qde.isNull()) continue;
|
||||
if (parseElement(qde, qp)) {
|
||||
++ parsed_elements_count;
|
||||
QString current_tag = qde.tagName();
|
||||
if (current_tag != "terminal" && current_tag != "input") {
|
||||
forbid_antialiasing = true;
|
||||
parseElement(qde, low_zoom_qp);
|
||||
forbid_antialiasing = false;
|
||||
}
|
||||
} else {
|
||||
if (state) *state = 7;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fin du dessin
|
||||
qp.end();
|
||||
low_zoom_qp.end();
|
||||
|
||||
// il doit y avoir au moins un element charge
|
||||
if (!parsed_elements_count) {
|
||||
if (state) *state = 8;
|
||||
return(false);
|
||||
} else {
|
||||
if (state) *state = 0;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Destructeur
|
||||
*/
|
||||
CustomElement::~CustomElement() {
|
||||
}
|
||||
|
||||
/// @return la liste des bornes de cet element
|
||||
QList<Terminal *> CustomElement::terminals() const {
|
||||
return(list_terminals);
|
||||
}
|
||||
|
||||
/// @return la liste des conducteurs rattaches a cet element
|
||||
QList<Conductor *> CustomElement::conductors() const {
|
||||
QList<Conductor *> conductors;
|
||||
foreach(Terminal *t, list_terminals) conductors << t -> conductors();
|
||||
return(conductors);
|
||||
}
|
||||
|
||||
/// @return la liste des textes de cet element
|
||||
QList<ElementTextItem *> CustomElement::texts() const {
|
||||
return(list_texts_);
|
||||
}
|
||||
|
||||
/**
|
||||
@return Le nombre de bornes que l'element possede
|
||||
*/
|
||||
int CustomElement::terminalsCount() const {
|
||||
return(list_terminals.size());
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine le composant sur le Diagram
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element
|
||||
@param options Les options graphiques
|
||||
*/
|
||||
void CustomElement::paint(QPainter *qp, const QStyleOptionGraphicsItem *options) {
|
||||
if (options && options -> levelOfDetail < 1.0) {
|
||||
low_zoom_drawing.play(qp);
|
||||
} else {
|
||||
drawing.play(qp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse et prend en compte un element XML decrivant une partie du dessin
|
||||
de l'element perso. Si l'analyse reussit, la partie est ajoutee au dessin.
|
||||
Cette partie peut etre une borne, une ligne, une ellipse, un cercle, un arc
|
||||
de cercle ou un polygone. Cette methode renvoie false si l'analyse
|
||||
d'une de ces formes echoue. Si l'analyse reussit ou dans le cas d'une forme
|
||||
inconnue, cette methode renvoie true. A l'exception des bornes, toutes les
|
||||
formes peuvent avoir un attribut style. @see setPainterStyle
|
||||
@param e L'element XML a analyser
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element perso
|
||||
@return true si l'analyse reussit, false sinon
|
||||
*/
|
||||
bool CustomElement::parseElement(QDomElement &e, QPainter &qp) {
|
||||
if (e.tagName() == "terminal") return(parseTerminal(e));
|
||||
else if (e.tagName() == "line") return(parseLine(e, qp));
|
||||
else if (e.tagName() == "rect") return(parseRect(e, qp));
|
||||
else if (e.tagName() == "ellipse") return(parseEllipse(e, qp));
|
||||
else if (e.tagName() == "circle") return(parseCircle(e, qp));
|
||||
else if (e.tagName() == "arc") return(parseArc(e, qp));
|
||||
else if (e.tagName() == "polygon") return(parsePolygon(e, qp));
|
||||
else if (e.tagName() == "text") return(parseText(e, qp));
|
||||
else if (e.tagName() == "input") return(parseInput(e));
|
||||
else return(true); // on n'est pas chiant, on ignore l'element inconnu
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer une ligne. Si l'analyse
|
||||
reussit, la ligne est ajoutee au dessin.
|
||||
La ligne est definie par les attributs suivants :
|
||||
- x1, y1 : reels, coordonnees d'une extremite de la ligne
|
||||
- x2, y2 : reels, coordonnees de l'autre extremite de la ligne
|
||||
|
||||
@param e L'element XML a analyser
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element perso
|
||||
@return true si l'analyse reussit, false sinon
|
||||
*/
|
||||
bool CustomElement::parseLine(QDomElement &e, QPainter &qp) {
|
||||
// verifie la presence et la validite des attributs obligatoires
|
||||
qreal x1, y1, x2, y2;
|
||||
if (!QET::attributeIsAReal(e, QString("x1"), &x1)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("y1"), &y1)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("x2"), &x2)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("y2"), &y2)) return(false);
|
||||
|
||||
QET::EndType first_end = QET::endTypeFromString(e.attribute("end1"));
|
||||
QET::EndType second_end = QET::endTypeFromString(e.attribute("end2"));
|
||||
qreal length1, length2;
|
||||
if (!QET::attributeIsAReal(e, QString("length1"), &length1)) length1 = 1.5;
|
||||
if (!QET::attributeIsAReal(e, QString("length2"), &length2)) length2 = 1.5;
|
||||
|
||||
qp.save();
|
||||
setPainterStyle(e, qp);
|
||||
QPen t = qp.pen();
|
||||
t.setJoinStyle(Qt::MiterJoin);
|
||||
qp.setPen(t);
|
||||
|
||||
QLineF line(x1, y1, x2, y2);
|
||||
QPointF point1(line.p1());
|
||||
QPointF point2(line.p2());
|
||||
|
||||
qreal line_length(line.length());
|
||||
qreal pen_width = qp.pen().widthF();
|
||||
|
||||
// determine s'il faut dessiner les extremites
|
||||
bool draw_1st_end, draw_2nd_end;
|
||||
qreal reduced_line_length = line_length - (length1 * PartLine::requiredLengthForEndType(first_end));
|
||||
draw_1st_end = first_end && reduced_line_length >= 0;
|
||||
if (draw_1st_end) {
|
||||
reduced_line_length -= (length2 * PartLine::requiredLengthForEndType(second_end));
|
||||
} else {
|
||||
reduced_line_length = line_length - (length2 * PartLine::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(PartLine::fourEndPoints(point1, point2, length1));
|
||||
if (first_end == QET::Circle) {
|
||||
qp.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) {
|
||||
qp.drawPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3]);
|
||||
start_point = four_points1[1];
|
||||
} else if (first_end == QET::Simple) {
|
||||
qp.drawPolyline(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
|
||||
start_point = point1;
|
||||
|
||||
} else if (first_end == QET::Triangle) {
|
||||
qp.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(PartLine::fourEndPoints(point2, point1, length2));
|
||||
if (second_end == QET::Circle) {
|
||||
qp.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) {
|
||||
qp.drawPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1]);
|
||||
stop_point = four_points2[1];
|
||||
} else if (second_end == QET::Simple) {
|
||||
qp.drawPolyline(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
|
||||
stop_point = point2;
|
||||
} else if (second_end == QET::Triangle) {
|
||||
qp.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;
|
||||
}
|
||||
|
||||
qp.drawLine(start_point, stop_point);
|
||||
|
||||
qp.restore();
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer un rectangle. Si l'analyse
|
||||
reussit, le rectangle est ajoute au dessin.
|
||||
Le rectangle est defini par les attributs suivants :
|
||||
- x : abscisse du coin superieur gauche du rectangle
|
||||
- y : ordonnee du coin superieur gauche du rectangle
|
||||
- width : largeur du rectangle
|
||||
- height : hauteur du rectangle
|
||||
|
||||
@param e L'element XML a analyser
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element perso
|
||||
@return true si l'analyse reussit, false sinon
|
||||
*/
|
||||
bool CustomElement::parseRect(QDomElement &e, QPainter &qp) {
|
||||
// verifie la presence des attributs obligatoires
|
||||
qreal rect_x, rect_y, rect_w, rect_h;
|
||||
if (!QET::attributeIsAReal(e, QString("x"), &rect_x)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("y"), &rect_y)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("width"), &rect_w)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("height"), &rect_h)) return(false);
|
||||
qp.save();
|
||||
setPainterStyle(e, qp);
|
||||
|
||||
// force le type de jointures pour les rectangles
|
||||
QPen p = qp.pen();
|
||||
p.setJoinStyle(Qt::MiterJoin);
|
||||
qp.setPen(p);
|
||||
|
||||
qp.drawRect(QRectF(rect_x, rect_y, rect_w, rect_h));
|
||||
qp.restore();
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer un cercle. Si l'analyse
|
||||
reussit, le cercle est ajoute au dessin.
|
||||
Le cercle est defini par les attributs suivants :
|
||||
- x : abscisse du coin superieur gauche de la quadrature du cercle
|
||||
- y : ordonnee du coin superieur gauche de la quadrature du cercle
|
||||
- diameter : diametre du cercle
|
||||
|
||||
@param e L'element XML a analyser
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element perso
|
||||
@return true si l'analyse reussit, false sinon
|
||||
*/
|
||||
bool CustomElement::parseCircle(QDomElement &e, QPainter &qp) {
|
||||
// verifie la presence des attributs obligatoires
|
||||
qreal cercle_x, cercle_y, cercle_r;
|
||||
if (!QET::attributeIsAReal(e, QString("x"), &cercle_x)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("y"), &cercle_y)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("diameter"), &cercle_r)) return(false);
|
||||
qp.save();
|
||||
setPainterStyle(e, qp);
|
||||
qp.drawEllipse(QRectF(cercle_x, cercle_y, cercle_r, cercle_r));
|
||||
qp.restore();
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer une ellipse. Si l'analyse
|
||||
reussit, l'ellipse est ajoutee au dessin.
|
||||
L'ellipse est definie par les attributs suivants :
|
||||
- x : abscisse du coin superieur gauche du rectangle dans lequel s'inscrit l'ellipse
|
||||
- y : ordonnee du coin superieur gauche du rectangle dans lequel s'inscrit l'ellipse
|
||||
- width : dimension de la diagonale horizontale de l'ellipse
|
||||
- height : dimension de la diagonale verticale de l'ellipse
|
||||
|
||||
@param e L'element XML a analyser
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element perso
|
||||
@return true si l'analyse reussit, false sinon
|
||||
*/
|
||||
bool CustomElement::parseEllipse(QDomElement &e, QPainter &qp) {
|
||||
// verifie la presence des attributs obligatoires
|
||||
qreal ellipse_x, ellipse_y, ellipse_l, ellipse_h;
|
||||
if (!QET::attributeIsAReal(e, QString("x"), &ellipse_x)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("y"), &ellipse_y)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("width"), &ellipse_l)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("height"), &ellipse_h)) return(false);
|
||||
qp.save();
|
||||
setPainterStyle(e, qp);
|
||||
qp.drawEllipse(QRectF(ellipse_x, ellipse_y, ellipse_l, ellipse_h));
|
||||
qp.restore();
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer un arc de cercle. Si l'analyse
|
||||
reussit, l'arc de cercle est ajoute au dessin.
|
||||
L'arc de cercle est defini par les quatres parametres d'une ellipse (en fait
|
||||
l'ellipse dans laquelle s'inscrit l'arc de cercle) auxquels s'ajoutent les
|
||||
attributs suivants :
|
||||
- start : angle de depart : l'angle "0 degre" est a trois heures
|
||||
- angle : etendue (en degres) de l'arc de cercle ; une valeur positive
|
||||
va dans le sens contraire des aiguilles d'une montre
|
||||
|
||||
@param e L'element XML a analyser
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element perso
|
||||
@return true si l'analyse reussit, false sinon
|
||||
*/
|
||||
bool CustomElement::parseArc(QDomElement &e, QPainter &qp) {
|
||||
// verifie la presence des attributs obligatoires
|
||||
qreal arc_x, arc_y, arc_l, arc_h, arc_s, arc_a;
|
||||
if (!QET::attributeIsAReal(e, QString("x"), &arc_x)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("y"), &arc_y)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("width"), &arc_l)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("height"), &arc_h)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("start"), &arc_s)) return(false);
|
||||
if (!QET::attributeIsAReal(e, QString("angle"), &arc_a)) return(false);
|
||||
|
||||
qp.save();
|
||||
setPainterStyle(e, qp);
|
||||
qp.drawArc(QRectF(arc_x, arc_y, arc_l, arc_h), (int)(arc_s * 16), (int)(arc_a * 16));
|
||||
qp.restore();
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer un polygone. Si l'analyse
|
||||
reussit, le polygone est ajoute au dessin.
|
||||
Le polygone est defini par une serie d'attributs x1, x2, ..., xn et autant
|
||||
d'attributs y1, y2, ..., yn representant les coordonnees des differents
|
||||
points du polygone.
|
||||
Il est possible d'obtenir un polygone non ferme en utilisant closed="false"
|
||||
@param e L'element XML a analyser
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element perso
|
||||
@return true si l'analyse reussit, false sinon
|
||||
*/
|
||||
bool CustomElement::parsePolygon(QDomElement &e, QPainter &qp) {
|
||||
int i = 1;
|
||||
while(true) {
|
||||
if (QET::attributeIsAReal(e, QString("x%1").arg(i)) && QET::attributeIsAReal(e, QString("y%1").arg(i))) ++ i;
|
||||
else break;
|
||||
}
|
||||
if (i < 3) return(false);
|
||||
QVector<QPointF> points(i-1);
|
||||
for (int j = 1 ; j < i ; ++ j) {
|
||||
points.insert(
|
||||
j - 1,
|
||||
QPointF(
|
||||
e.attribute(QString("x%1").arg(j)).toDouble(),
|
||||
e.attribute(QString("y%1").arg(j)).toDouble()
|
||||
)
|
||||
);
|
||||
}
|
||||
qp.save();
|
||||
setPainterStyle(e, qp);
|
||||
if (e.attribute("closed") == "false") qp.drawPolyline(points.data(), i-1);
|
||||
else qp.drawPolygon(points.data(), i-1);
|
||||
qp.restore();
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer un texte. Si l'analyse
|
||||
reussit, le texte est ajoute au dessin.
|
||||
Le texte est defini par une position, une chaine de caracteres et une
|
||||
taille.
|
||||
@param e L'element XML a analyser
|
||||
@param qp Le QPainter a utiliser pour dessiner l'element perso
|
||||
@return true si l'analyse reussit, false sinon
|
||||
*/
|
||||
bool CustomElement::parseText(QDomElement &e, QPainter &qp) {
|
||||
qreal pos_x, pos_y;
|
||||
int size;
|
||||
if (
|
||||
!QET::attributeIsAReal(e, "x", &pos_x) ||\
|
||||
!QET::attributeIsAReal(e, "y", &pos_y) ||\
|
||||
!QET::attributeIsAnInteger(e, "size", &size) ||\
|
||||
!e.hasAttribute("text")
|
||||
) return(false);
|
||||
|
||||
qp.save();
|
||||
setPainterStyle(e, qp);
|
||||
|
||||
// determine la police a utiliser et en recupere les metriques associees
|
||||
QFont used_font = QETApp::diagramTextsFont(size);
|
||||
QFontMetrics qfm(used_font);
|
||||
QColor text_color = (e.attribute("color") != "white"? Qt::black : Qt::white);
|
||||
|
||||
// instancie un QTextDocument (comme la classe QGraphicsTextItem) pour
|
||||
// generer le rendu graphique du texte
|
||||
QTextDocument text_document;
|
||||
text_document.setDefaultFont(used_font);
|
||||
text_document.setPlainText(e.attribute("text"));
|
||||
|
||||
// Se positionne aux coordonnees indiquees dans la description du texte
|
||||
qp.setTransform(QTransform(), false);
|
||||
qp.translate(pos_x, pos_y);
|
||||
|
||||
// Pivote le systeme de coordonnees du QPainter pour effectuer le rendu
|
||||
// dans le bon sens
|
||||
qreal default_rotation_angle = 0.0;
|
||||
if (QET::attributeIsAReal(e, "rotation", &default_rotation_angle)) {
|
||||
qp.rotate(default_rotation_angle);
|
||||
}
|
||||
|
||||
/*
|
||||
Deplace le systeme de coordonnees du QPainter pour effectuer le rendu au
|
||||
bon endroit ; note : on soustrait l'ascent() de la police pour
|
||||
determiner le coin superieur gauche du texte alors que la position
|
||||
indiquee correspond a la baseline.
|
||||
*/
|
||||
QPointF qpainter_offset(0.0, -qfm.ascent());
|
||||
|
||||
// ajuste le decalage selon la marge du document texte
|
||||
#if QT_VERSION >= 0x040500
|
||||
text_document.setDocumentMargin(0.0);
|
||||
#else
|
||||
// il semblerait qu'avant Qt 4.5, le documentMargin vaille 2.0 (et pas 4.0)
|
||||
qpainter_offset.rx() -= 2.0;
|
||||
qpainter_offset.ry() -= 2.0;
|
||||
#endif
|
||||
|
||||
qp.translate(qpainter_offset);
|
||||
|
||||
// force the palette used to render the QTextDocument
|
||||
QAbstractTextDocumentLayout::PaintContext ctx;
|
||||
ctx.palette.setColor(QPalette::Text, text_color);
|
||||
text_document.documentLayout() -> draw(&qp, ctx);
|
||||
|
||||
qp.restore();
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer un champ de texte editable par
|
||||
l'utilisateur. Si l'analyse reussit, le champ est ajoute au dessin.
|
||||
Le texte est defini par :
|
||||
- une position
|
||||
- une chaine de caracteres facultative utilisee comme valeur par defaut
|
||||
- une taille
|
||||
- le fait de subir les rotations de l'element ou non
|
||||
@param e L'element XML a analyser
|
||||
@return Un pointeur vers l'objet ElementTextItem ainsi cree si l'analyse reussit, 0 sinon
|
||||
*/
|
||||
ElementTextItem *CustomElement::parseInput(QDomElement &e) {
|
||||
qreal pos_x, pos_y;
|
||||
int size;
|
||||
if (
|
||||
!QET::attributeIsAReal(e, "x", &pos_x) ||\
|
||||
!QET::attributeIsAReal(e, "y", &pos_y) ||\
|
||||
!QET::attributeIsAnInteger(e, "size", &size)
|
||||
) return(0);
|
||||
|
||||
ElementTextItem *eti = new ElementTextItem(e.attribute("text"), this);
|
||||
eti -> setFont(QETApp::diagramTextsFont(size));
|
||||
|
||||
// position du champ de texte
|
||||
eti -> setOriginalPos(QPointF(pos_x, pos_y));
|
||||
eti -> setPos(pos_x, pos_y);
|
||||
|
||||
// rotation du champ de texte
|
||||
qreal original_rotation_angle = 0.0;
|
||||
QET::attributeIsAReal(e, "rotation", &original_rotation_angle);
|
||||
eti -> setOriginalRotationAngle(original_rotation_angle);
|
||||
eti -> setRotationAngle(original_rotation_angle);
|
||||
|
||||
// comportement du champ lorsque son element parent est pivote
|
||||
eti -> setFollowParentRotations(e.attribute("rotate") == "true");
|
||||
|
||||
list_texts_ << eti;
|
||||
|
||||
return(eti);
|
||||
}
|
||||
|
||||
/**
|
||||
Analyse un element XML suppose representer une borne. Si l'analyse
|
||||
reussit, la borne est ajoutee a l'element.
|
||||
Une borne est definie par les attributs suivants :
|
||||
- x, y : coordonnees de la borne
|
||||
- orientation : orientation de la borne = Nord (n), Sud (s), Est (e) ou Ouest (w)
|
||||
|
||||
@param e L'element XML a analyser
|
||||
@return Un pointeur vers l'objet Terminal ainsi cree, 0 sinon
|
||||
*/
|
||||
Terminal *CustomElement::parseTerminal(QDomElement &e) {
|
||||
// verifie la presence et la validite des attributs obligatoires
|
||||
qreal terminalx, terminaly;
|
||||
QET::Orientation terminalo;
|
||||
if (!QET::attributeIsAReal(e, QString("x"), &terminalx)) return(0);
|
||||
if (!QET::attributeIsAReal(e, QString("y"), &terminaly)) return(0);
|
||||
if (!e.hasAttribute("orientation")) return(0);
|
||||
if (e.attribute("orientation") == "n") terminalo = QET::North;
|
||||
else if (e.attribute("orientation") == "s") terminalo = QET::South;
|
||||
else if (e.attribute("orientation") == "e") terminalo = QET::East;
|
||||
else if (e.attribute("orientation") == "w") terminalo = QET::West;
|
||||
else return(0);
|
||||
Terminal *new_terminal = new Terminal(terminalx, terminaly, terminalo, this, qobject_cast<Diagram *>(scene()));
|
||||
new_terminal -> setZValue(420); // valeur arbitraire pour maintenir les bornes au-dessus des champs de texte
|
||||
list_terminals << new_terminal;
|
||||
return(new_terminal);
|
||||
}
|
||||
|
||||
/**
|
||||
Active / desactive l'antialiasing sur un QPainter
|
||||
@param qp Le QPainter a modifier
|
||||
@param aa Booleen a true pour activer l'antialiasing, a false pour le desactiver
|
||||
*/
|
||||
void CustomElement::setQPainterAntiAliasing(QPainter &qp, bool aa) {
|
||||
if (forbid_antialiasing) aa = false;
|
||||
qp.setRenderHint(QPainter::Antialiasing, aa);
|
||||
qp.setRenderHint(QPainter::TextAntialiasing, aa);
|
||||
qp.setRenderHint(QPainter::SmoothPixmapTransform, aa);
|
||||
}
|
||||
|
||||
/**
|
||||
Verifie si l'attribut "orientation" de l'element XML e correspond bien a la
|
||||
syntaxe decrivant les orientations possibles pour un element.
|
||||
Cette syntaxe comprend exactement 4 lettres :
|
||||
- une pour le Nord
|
||||
- une pour l'Est
|
||||
- une pour le Sud
|
||||
- une pour l'Ouest
|
||||
|
||||
Pour chaque orientation, on indique si elle est :
|
||||
- l'orientation par defaut : d
|
||||
- une orientation autorisee : y
|
||||
- une orientation interdire : n
|
||||
|
||||
Exemple : "dnny" represente un element par defaut oriente vers le nord et qui
|
||||
peut etre oriente vers l'ouest mais pas vers le sud ou vers l'est.
|
||||
@param e Element XML
|
||||
@return true si l'attribut "orientation" est valide, false sinon
|
||||
*/
|
||||
bool CustomElement::validOrientationAttribute(const QDomElement &e) {
|
||||
int ori = e.attribute("orientation").toInt();
|
||||
if(ori >= 0 && ori <=3) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Applique les parametres de style definis dans l'attribut "style" de
|
||||
l'element XML e au QPainter qp
|
||||
Les styles possibles sont :
|
||||
- line-style : style du trait
|
||||
- dashed : trait en pointilles (tirets)
|
||||
- dashdotted : Traits et points
|
||||
- dotted : trait en pointilles (points)
|
||||
- normal : trait plein [par defaut]
|
||||
- line-weight : epaiseur du trait
|
||||
- thin : trait fin
|
||||
- normal : trait d'epaisseur 1 [par defaut]
|
||||
- filling : remplissage de la forme
|
||||
- white : remplissage blanc
|
||||
- black : remplissage noir
|
||||
- red : remplissage rouge
|
||||
- blue : remplissage bleu
|
||||
- green : remplissage vert
|
||||
- none : pas de remplissage [par defaut]
|
||||
- color : couleur du trait et du texte
|
||||
- white : trait noir [par defaut]
|
||||
- black : trait blanc
|
||||
- red : trait rouge
|
||||
- blue : trait bleu
|
||||
- green : trait vert
|
||||
|
||||
Les autres valeurs ne sont pas prises en compte.
|
||||
@param e L'element XML a parser
|
||||
@param qp Le QPainter a modifier en fonction des styles
|
||||
*/
|
||||
void CustomElement::setPainterStyle(QDomElement &e, QPainter &qp) {
|
||||
// recupere le QPen et la QBrush du QPainter
|
||||
QPen pen = qp.pen();
|
||||
QBrush brush = qp.brush();
|
||||
|
||||
// attributs par defaut
|
||||
pen.setJoinStyle(Qt::BevelJoin);
|
||||
pen.setCapStyle(Qt::SquareCap);
|
||||
|
||||
// recupere la liste des couples style / valeur
|
||||
QStringList styles = e.attribute("style").split(";", QString::SkipEmptyParts);
|
||||
|
||||
// agit sur le QPen et la QBrush en fonction des valeurs rencontrees
|
||||
QRegExp rx("^\\s*([a-z-]+)\\s*:\\s*([a-z-]+)\\s*$");
|
||||
foreach (QString style, styles) {
|
||||
if (rx.exactMatch(style)) {
|
||||
QString style_name = rx.cap(1);
|
||||
QString style_value = rx.cap(2);
|
||||
if (style_name == "line-style") {
|
||||
if (style_value == "dashed") pen.setStyle(Qt::DashLine);
|
||||
else if (style_value == "dotted") pen.setStyle(Qt::DotLine);
|
||||
else if (style_value == "dashdotted") pen.setStyle(Qt::DashDotLine);
|
||||
else if (style_value == "normal") pen.setStyle(Qt::SolidLine);
|
||||
} else if (style_name == "line-weight") {
|
||||
if (style_value == "thin") pen.setWidth(0);
|
||||
else if (style_value == "normal") pen.setWidthF(1.0);
|
||||
else if (style_value == "none") pen.setColor(QColor(0, 0, 0, 0));
|
||||
} else if (style_name == "filling") {
|
||||
if (style_value == "white") {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::white);
|
||||
} else if (style_value == "black") {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::black);
|
||||
} else if (style_value == "blue") {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::blue);
|
||||
} else if (style_value == "red") {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::red);
|
||||
} else if (style_value == "green") {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::green);
|
||||
} else if (style_value == "none") {
|
||||
brush.setStyle(Qt::NoBrush);
|
||||
}
|
||||
} else if (style_name == "color") {
|
||||
if (style_value == "black") {
|
||||
pen.setColor(QColor(0, 0, 0, pen.color().alpha()));
|
||||
} else if (style_value == "white") {
|
||||
pen.setColor(QColor(255, 255, 255, pen.color().alpha()));
|
||||
} else if (style_value == "red") {
|
||||
pen.setColor(Qt::red);
|
||||
}else if (style_value == "blue") {
|
||||
pen.setColor(Qt::blue);
|
||||
}else if (style_value == "green") {
|
||||
pen.setColor(Qt::green);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// affectation du QPen et de la QBrush modifies au QPainter
|
||||
qp.setPen(pen);
|
||||
qp.setBrush(brush);
|
||||
|
||||
// mise en place (ou non) de l'antialiasing
|
||||
setQPainterAntiAliasing(qp, e.attribute("antialias") == "true");
|
||||
}
|
||||
132
sources/qetgraphicsitem/customelement.h
Normal file
132
sources/qetgraphicsitem/customelement.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Copyright 2006-2013 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_H
|
||||
#define CUSTOM_ELEMENT_H
|
||||
#include "fixedelement.h"
|
||||
#include <QtGui>
|
||||
#include "nameslist.h"
|
||||
#include "elementslocation.h"
|
||||
class ElementTextItem;
|
||||
class Terminal;
|
||||
/**
|
||||
This class represents an electrical element; it may be used like a fixed
|
||||
element, the difference being that the CustomElement reads its description
|
||||
(names, drawing, behavior) from an XML document.
|
||||
*/
|
||||
class CustomElement : public FixedElement {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
CustomElement(const ElementsLocation &, QGraphicsItem * = 0, Diagram * = 0, int * = 0);
|
||||
CustomElement(const QDomElement &, QGraphicsItem * = 0, Diagram * = 0, int * = 0);
|
||||
virtual ~CustomElement();
|
||||
|
||||
private:
|
||||
CustomElement(const CustomElement &);
|
||||
|
||||
// attributes
|
||||
protected:
|
||||
int elmt_state; // hold the error code in case the instanciation fails, or 0 if everything went well
|
||||
NamesList names;
|
||||
ElementsLocation location_;
|
||||
QPicture drawing;
|
||||
QPicture low_zoom_drawing;
|
||||
QList<Terminal *> list_terminals;
|
||||
QList<ElementTextItem *> list_texts_;
|
||||
bool forbid_antialiasing;
|
||||
|
||||
// methods
|
||||
public:
|
||||
virtual QList<Terminal *> terminals() const;
|
||||
virtual QList<Conductor *> conductors() const;
|
||||
virtual QList<ElementTextItem *> texts() const;
|
||||
virtual int terminalsCount() const;
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *);
|
||||
QString typeId() const;
|
||||
ElementsLocation location() const;
|
||||
bool isNull() const;
|
||||
int state() const;
|
||||
QString name() const;
|
||||
|
||||
protected:
|
||||
virtual bool buildFromXml(const QDomElement &, int * = 0);
|
||||
virtual bool parseElement(QDomElement &, QPainter &);
|
||||
virtual bool parseLine(QDomElement &, QPainter &);
|
||||
virtual bool parseRect(QDomElement &, QPainter &);
|
||||
virtual bool parseEllipse(QDomElement &, QPainter &);
|
||||
virtual bool parseCircle(QDomElement &, QPainter &);
|
||||
virtual bool parseArc(QDomElement &, QPainter &);
|
||||
virtual bool parsePolygon(QDomElement &, QPainter &);
|
||||
virtual bool parseText(QDomElement &, QPainter &);
|
||||
virtual ElementTextItem *parseInput(QDomElement &);
|
||||
virtual Terminal *parseTerminal(QDomElement &);
|
||||
virtual void setQPainterAntiAliasing(QPainter &, bool);
|
||||
virtual bool validOrientationAttribute(const QDomElement &);
|
||||
virtual void setPainterStyle(QDomElement &, QPainter &);
|
||||
};
|
||||
|
||||
/**
|
||||
@return The element type ID; considering a CustomElement, this means the
|
||||
@location of its XML description.
|
||||
@see location()
|
||||
*/
|
||||
inline QString CustomElement::typeId() const {
|
||||
return(location_.path());
|
||||
}
|
||||
|
||||
/**
|
||||
@return the location of the XML document describing this element.
|
||||
*/
|
||||
inline ElementsLocation CustomElement::location() const {
|
||||
return(location_);
|
||||
}
|
||||
|
||||
/**
|
||||
@return true if this element is null, i.e. if its XML description could not
|
||||
be loaded.
|
||||
*/
|
||||
inline bool CustomElement::isNull() const {
|
||||
return(elmt_state);
|
||||
}
|
||||
|
||||
/**
|
||||
@return An integer representing the state of this element:
|
||||
- 0: instantiation succeeded
|
||||
- 1: the file does not exist
|
||||
- 2: the file could not be opened
|
||||
- 3: The file is not a valid XML document
|
||||
- 4: The XML document does not have a "definition" root element.
|
||||
- 5: The definition attributes are missing or invalid
|
||||
- 6: The definition is empty
|
||||
- 7: The parsing of an XML element describing an element drawing primitive failed
|
||||
- 8: No primitive could be loadedAucune partie du dessin n'a pu etre chargee
|
||||
*/
|
||||
inline int CustomElement::state() const {
|
||||
return(elmt_state);
|
||||
}
|
||||
|
||||
/**
|
||||
@return The name of this element.
|
||||
*/
|
||||
inline QString CustomElement::name() const {
|
||||
return(names.name(location_.baseName()));
|
||||
}
|
||||
|
||||
#endif
|
||||
222
sources/qetgraphicsitem/diagramimageitem.cpp
Normal file
222
sources/qetgraphicsitem/diagramimageitem.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 "diagramimageitem.h"
|
||||
#include "diagramcommands.h"
|
||||
|
||||
/**
|
||||
* @brief DiagramImageItem::DiagramImageItem
|
||||
* Constructor without pixmap
|
||||
* @param parent_item the parent graphics item
|
||||
*/
|
||||
DiagramImageItem::DiagramImageItem(QetGraphicsItem *parent_item):
|
||||
QetGraphicsItem(parent_item)
|
||||
{
|
||||
setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DiagramImageItem::DiagramImageItem
|
||||
* Constructor with pixmap
|
||||
* @param pixmap the pixmap to be draw
|
||||
* @param parent_item the parent graphic item
|
||||
*/
|
||||
DiagramImageItem::DiagramImageItem(const QPixmap &pixmap, QetGraphicsItem *parent_item):
|
||||
QetGraphicsItem(parent_item),
|
||||
pixmap_(pixmap)
|
||||
{
|
||||
setTransformOriginPoint(boundingRect().center());
|
||||
setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DiagramImageItem::~DiagramImageItem
|
||||
* Destructor
|
||||
*/
|
||||
DiagramImageItem::~DiagramImageItem() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DiagramImageItem::paint
|
||||
* Draw the pixmap.
|
||||
* @param painter the Qpainter to use for draw the pixmap
|
||||
* @param option the style option
|
||||
* @param widget the QWidget where we draw the pixmap
|
||||
*/
|
||||
void DiagramImageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
|
||||
painter -> drawPixmap(pixmap_.rect(),pixmap_);
|
||||
|
||||
if (isSelected()) {
|
||||
painter -> save();
|
||||
// Annulation des renderhints
|
||||
painter -> setRenderHint(QPainter::Antialiasing, false);
|
||||
painter -> setRenderHint(QPainter::TextAntialiasing, false);
|
||||
painter -> setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||
// Dessin du cadre de selection en noir a partir du boundingrect
|
||||
QPen t(Qt::black);
|
||||
t.setStyle(Qt::DashLine);
|
||||
painter -> setPen(t);
|
||||
painter -> drawRect(boundingRect());
|
||||
painter -> restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DiagramImageItem::setScale
|
||||
* @param scale the value of @scale must be betwen 1 and 200
|
||||
*/
|
||||
void DiagramImageItem::PreviewScale(int scale) {
|
||||
if (scale >= 1 && scale <= 200) {
|
||||
qreal new_scale = scale;
|
||||
new_scale /= 100;
|
||||
setScale(new_scale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Edit the image with ....
|
||||
*/
|
||||
void DiagramImageItem::editProperty() {
|
||||
if (diagram() -> isReadOnly()) return;
|
||||
//the range for scale image and divisor factor
|
||||
int min_range = 1;
|
||||
int max_range = 200;
|
||||
int factor_range = 100;
|
||||
|
||||
//the dialog
|
||||
QDialog property_dialog;
|
||||
property_dialog.setWindowTitle(tr("\311diter les propri\351t\351s d'une image", "window title"));
|
||||
//the main layout
|
||||
QVBoxLayout *dialog_layout = new QVBoxLayout(&property_dialog);
|
||||
|
||||
//GroupBox for resizer image
|
||||
QGroupBox *resize_groupe = new QGroupBox(tr("Dimension de l'image", "image size"));
|
||||
dialog_layout -> addWidget(resize_groupe);
|
||||
QHBoxLayout *resize_layout = new QHBoxLayout(resize_groupe);
|
||||
|
||||
//slider
|
||||
QSlider *slider = new QSlider(Qt::Horizontal, &property_dialog);
|
||||
slider->setRange(min_range, max_range);
|
||||
qreal scale_= scale();
|
||||
slider -> setValue(scale_*factor_range);
|
||||
//spinbox
|
||||
QSpinBox *spin_box = new QSpinBox(&property_dialog);
|
||||
spin_box -> setRange(min_range, max_range);
|
||||
spin_box -> setValue(scale_*factor_range);
|
||||
spin_box -> setSuffix(" %");
|
||||
//synchro slider with spinbox
|
||||
connect(slider, SIGNAL(valueChanged(int)), spin_box, SLOT(setValue(int)));
|
||||
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(PreviewScale(int)));
|
||||
connect(spin_box, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
|
||||
//add slider and spinbox to layout
|
||||
resize_layout -> addWidget(slider);
|
||||
resize_layout -> addWidget(spin_box);
|
||||
|
||||
//dialog button, box
|
||||
QDialogButtonBox *dbb = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
dialog_layout -> addWidget(dbb);
|
||||
connect(dbb, SIGNAL(accepted()), &property_dialog, SLOT(accept()));
|
||||
connect(dbb, SIGNAL(rejected()), &property_dialog, SLOT(reject()));
|
||||
//dialog is accepted...
|
||||
if (property_dialog.exec() == QDialog::Accepted) {
|
||||
qreal new_scale = slider -> value();
|
||||
new_scale /= factor_range;
|
||||
if (scale_ != new_scale) diagram()->undoStack().push(new ImageResizerCommand(this, scale_, new_scale));
|
||||
}
|
||||
//...or not
|
||||
else setScale(scale_);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DiagramImageItem::setPixmap
|
||||
* Set the new pixmap to be draw
|
||||
* @param pixmap the new pixmap
|
||||
*/
|
||||
void DiagramImageItem::setPixmap(const QPixmap &pixmap) {
|
||||
pixmap_ = pixmap;
|
||||
setTransformOriginPoint(boundingRect().center());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DiagramImageItem::boundingRect
|
||||
* the outer bounds of the item as a rectangle,
|
||||
* if no pixmap are set, return a default QRectF
|
||||
* @return a QRectF represent the bounding rectangle
|
||||
*/
|
||||
QRectF DiagramImageItem::boundingRect() const {
|
||||
if (!pixmap_.isNull()) {
|
||||
return (QRectF(pixmap_.rect()));
|
||||
} else {
|
||||
QRectF bound;
|
||||
return (bound);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Load the image from this xml element
|
||||
@param e xml element that define an image
|
||||
*/
|
||||
bool DiagramImageItem::fromXml(const QDomElement &e) {
|
||||
if (e.tagName() != "image") return (false);
|
||||
QDomNode image_node = e.firstChild();
|
||||
if (!image_node.isText()) return (false);
|
||||
|
||||
//load xml image to QByteArray
|
||||
QByteArray array;
|
||||
array = QByteArray::fromBase64(e.text().toAscii());
|
||||
|
||||
//Set QPixmap from the @array
|
||||
QPixmap pixmap;
|
||||
pixmap.loadFromData(array);
|
||||
setPixmap(pixmap);
|
||||
|
||||
setScale(e.attribute("size").toDouble());
|
||||
applyRotation(e.attribute("rotation").toDouble());
|
||||
setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
@param document Le document XML a utiliser
|
||||
@return L'element XML representant l'image
|
||||
*/
|
||||
QDomElement DiagramImageItem::toXml(QDomDocument &document) const {
|
||||
QDomElement result = document.createElement("image");
|
||||
//write some attribute
|
||||
result.setAttribute("x", QString("%1").arg(pos().x()));
|
||||
result.setAttribute("y", QString("%1").arg(pos().y()));
|
||||
result.setAttribute("rotation", QString("%1").arg(rotation()));
|
||||
result.setAttribute("size", QString("%1").arg(scale()));
|
||||
|
||||
//write the pixmap in the xml element after he was been transformed to base64
|
||||
QByteArray array;
|
||||
QBuffer buffer(&array);
|
||||
buffer.open(QIODevice::ReadWrite);
|
||||
pixmap_.save(&buffer, "PNG");
|
||||
QDomText base64 = document.createTextNode(array.toBase64());
|
||||
result.appendChild(base64);
|
||||
|
||||
return(result);
|
||||
}
|
||||
67
sources/qetgraphicsitem/diagramimageitem.h
Normal file
67
sources/qetgraphicsitem/diagramimageitem.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 DIAGRAM_IMAGE_ITEM_H
|
||||
#define DIAGRAM_IMAGE_ITEM_H
|
||||
#include <QtGui>
|
||||
#include "qetgraphicsitem.h"
|
||||
|
||||
/**
|
||||
This class represents a selectable, movable and editable image on a
|
||||
diagram.
|
||||
@see QGraphicsItem::GraphicsItemFlags
|
||||
*/
|
||||
class DiagramImageItem : public QetGraphicsItem {
|
||||
Q_OBJECT
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
DiagramImageItem(QetGraphicsItem * = 0);
|
||||
DiagramImageItem(const QPixmap &pixmap, QetGraphicsItem * = 0);
|
||||
virtual ~DiagramImageItem();
|
||||
|
||||
// attributes
|
||||
public:
|
||||
enum { Type = UserType + 1007 };
|
||||
|
||||
// methods
|
||||
public:
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
DiagramImageItem
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
|
||||
virtual bool fromXml(const QDomElement &);
|
||||
virtual QDomElement toXml(QDomDocument &) const;
|
||||
virtual void editProperty();
|
||||
void setPixmap(const QPixmap &pixmap);
|
||||
virtual QRectF boundingRect() const;
|
||||
|
||||
protected:
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void PreviewScale(int);
|
||||
|
||||
protected:
|
||||
QPixmap pixmap_;
|
||||
};
|
||||
#endif
|
||||
328
sources/qetgraphicsitem/diagramtextitem.cpp
Normal file
328
sources/qetgraphicsitem/diagramtextitem.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 "diagramtextitem.h"
|
||||
#include "diagramcommands.h"
|
||||
#include "qet.h"
|
||||
#include "qetapp.h"
|
||||
|
||||
#include "richtext/richtexteditor_p.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param parent Le QGraphicsItem parent du champ de texte
|
||||
@param parent_diagram Le schema auquel appartient le champ de texte
|
||||
*/
|
||||
DiagramTextItem::DiagramTextItem(QGraphicsItem *parent, Diagram *parent_diagram) :
|
||||
QGraphicsTextItem(parent, parent_diagram),
|
||||
previous_text_(),
|
||||
rotation_angle_(0.0)
|
||||
{
|
||||
//set Zvalue at 10 to be upper than the DiagramImageItem
|
||||
setZValue(10);
|
||||
setDefaultTextColor(Qt::black);
|
||||
setFont(QETApp::diagramTextsFont());
|
||||
setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable()));
|
||||
}
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param text Le texte affiche par le champ de texte
|
||||
@param parent Le QGraphicsItem parent du champ de texte
|
||||
@param parent_diagram Le schema auquel appartient le champ de texte
|
||||
*/
|
||||
DiagramTextItem::DiagramTextItem(const QString &text, QGraphicsItem *parent, Diagram *parent_diagram) :
|
||||
QGraphicsTextItem(text, parent, parent_diagram),
|
||||
previous_text_(text),
|
||||
rotation_angle_(0.0)
|
||||
{
|
||||
//set Zvalue at 10 to be upper than the DiagramImageItem
|
||||
setZValue(10);
|
||||
setDefaultTextColor(Qt::black);
|
||||
setFont(QETApp::diagramTextsFont());
|
||||
setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable()));
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
DiagramTextItem::~DiagramTextItem() {
|
||||
}
|
||||
|
||||
/**
|
||||
@return le Diagram auquel ce texte appartient, ou 0 si ce texte n'est
|
||||
rattache a aucun schema
|
||||
*/
|
||||
Diagram *DiagramTextItem::diagram() const {
|
||||
return(qobject_cast<Diagram *>(scene()));
|
||||
}
|
||||
|
||||
/**
|
||||
@return l'angle de rotation actuel de ce texte
|
||||
*/
|
||||
qreal DiagramTextItem::rotationAngle() const {
|
||||
return(rotation_angle_);
|
||||
}
|
||||
|
||||
/**
|
||||
Permet de tourner le texte a un angle donne de maniere absolue.
|
||||
Un angle de 0 degres correspond a un texte horizontal non retourne.
|
||||
@param rotation Nouvel angle de rotation de ce texte
|
||||
@see applyRotation
|
||||
*/
|
||||
void DiagramTextItem::setRotationAngle(const qreal &rotation) {
|
||||
qreal applied_rotation = QET::correctAngle(rotation);
|
||||
applyRotation(applied_rotation - rotation_angle_);
|
||||
rotation_angle_ = applied_rotation;
|
||||
}
|
||||
|
||||
/**
|
||||
Permet de tourner le texte de maniere relative.
|
||||
L'angle added_rotation est ajoute a l'orientation actuelle du texte.
|
||||
@param added_rotation Angle a ajouter a la rotation actuelle
|
||||
@see applyRotation
|
||||
*/
|
||||
void DiagramTextItem::rotateBy(const qreal &added_rotation) {
|
||||
qreal applied_added_rotation = QET::correctAngle(added_rotation);
|
||||
rotation_angle_ = QET::correctAngle(rotation_angle_ + applied_added_rotation);
|
||||
applyRotation(applied_added_rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
Traduit en coordonnees de la scene un mouvement / vecteur initialement
|
||||
exprime en coordonnees locales.
|
||||
@param movement Vecteur exprime en coordonnees locales
|
||||
@return le meme vecteur, exprime en coordonnees de la scene
|
||||
*/
|
||||
QPointF DiagramTextItem::mapMovementToScene(const QPointF &movement) const {
|
||||
// on definit deux points en coordonnees locales
|
||||
QPointF local_origin(0.0, 0.0);
|
||||
QPointF local_movement_point(movement);
|
||||
|
||||
// on les mappe sur la scene
|
||||
QPointF scene_origin(mapToScene(local_origin));
|
||||
QPointF scene_movement_point(mapToScene(local_movement_point));
|
||||
|
||||
// on calcule le vecteur represente par ces deux points
|
||||
return(scene_movement_point - scene_origin);
|
||||
}
|
||||
|
||||
/**
|
||||
Traduit en coordonnees locales un mouvement / vecteur initialement
|
||||
exprime en coordonnees de la scene.
|
||||
@param movement Vecteur exprime en coordonnees de la scene
|
||||
@return le meme vecteur, exprime en coordonnees locales
|
||||
*/
|
||||
QPointF DiagramTextItem::mapMovementFromScene(const QPointF &movement) const {
|
||||
// on definit deux points sur la scene
|
||||
QPointF scene_origin(0.0, 0.0);
|
||||
QPointF scene_movement_point(movement);
|
||||
|
||||
// on les mappe sur ce QGraphicsItem
|
||||
QPointF local_origin(mapFromScene(scene_origin));
|
||||
QPointF local_movement_point(mapFromScene(scene_movement_point));
|
||||
|
||||
// on calcule le vecteur represente par ces deux points
|
||||
return(local_movement_point - local_origin);
|
||||
}
|
||||
|
||||
/**
|
||||
Traduit en coordonnees de l'item parent un mouvement / vecteur initialement
|
||||
exprime en coordonnees locales.
|
||||
@param movement Vecteur exprime en coordonnees locales
|
||||
@return le meme vecteur, exprime en coordonnees du parent
|
||||
*/
|
||||
QPointF DiagramTextItem::mapMovementToParent(const QPointF &movement) const {
|
||||
// on definit deux points en coordonnees locales
|
||||
QPointF local_origin(0.0, 0.0);
|
||||
QPointF local_movement_point(movement);
|
||||
|
||||
// on les mappe sur la scene
|
||||
QPointF parent_origin(mapToParent(local_origin));
|
||||
QPointF parent_movement_point(mapToParent(local_movement_point));
|
||||
|
||||
// on calcule le vecteur represente par ces deux points
|
||||
return(parent_movement_point - parent_origin);
|
||||
}
|
||||
|
||||
/**
|
||||
Traduit en coordonnees locales un mouvement / vecteur initialement
|
||||
exprime en coordonnees du parent.
|
||||
@param movement Vecteur exprime en coordonnees du parent
|
||||
@return le meme vecteur, exprime en coordonnees locales
|
||||
*/
|
||||
QPointF DiagramTextItem::mapMovementFromParent(const QPointF &movement) const {
|
||||
// on definit deux points sur le parent
|
||||
QPointF parent_origin(0.0, 0.0);
|
||||
QPointF parent_movement_point(movement);
|
||||
|
||||
// on les mappe sur ce QGraphicsItem
|
||||
QPointF local_origin(mapFromParent(parent_origin));
|
||||
QPointF local_movement_point(mapFromParent(parent_movement_point));
|
||||
|
||||
// on calcule le vecteur represente par ces deux points
|
||||
return(local_movement_point - local_origin);
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine le champ de texte.
|
||||
Cette methode delegue simplement le travail a QGraphicsTextItem::paint apres
|
||||
avoir desactive l'antialiasing.
|
||||
@param painter Le QPainter a utiliser pour dessiner le champ de texte
|
||||
@param option Les options de style pour le champ de texte
|
||||
@param widget Le QWidget sur lequel on dessine
|
||||
*/
|
||||
void DiagramTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
|
||||
painter -> setRenderHint(QPainter::Antialiasing, false);
|
||||
QGraphicsTextItem::paint(painter, option, widget);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere la prise de focus du champ de texte
|
||||
@param e Objet decrivant la prise de focus
|
||||
*/
|
||||
void DiagramTextItem::focusInEvent(QFocusEvent *e) {
|
||||
QGraphicsTextItem::focusInEvent(e);
|
||||
|
||||
// empeche le deplacement du texte pendant son edition
|
||||
setFlag(QGraphicsItem::ItemIsMovable, false);
|
||||
|
||||
// memorise le texte avant que l'utilisateur n'y touche
|
||||
previous_text_ = toHtml();
|
||||
// cela permettra de determiner si l'utilisateur a modifie le texte a la fin de l'edition
|
||||
}
|
||||
|
||||
/**
|
||||
Gere la perte de focus du champ de texte
|
||||
@param e Objet decrivant la perte de focus
|
||||
*/
|
||||
void DiagramTextItem::focusOutEvent(QFocusEvent *e) {
|
||||
QGraphicsTextItem::focusOutEvent(e);
|
||||
|
||||
// signale la modification du texte si besoin
|
||||
if (toPlainText() != previous_text_) {
|
||||
emit(diagramTextChanged(this, previous_text_, toHtml()));
|
||||
previous_text_ = toHtml();
|
||||
}
|
||||
|
||||
// deselectionne le texte
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.clearSelection();
|
||||
setTextCursor(cursor);
|
||||
|
||||
// hack a la con pour etre re-entrant
|
||||
setTextInteractionFlags(Qt::NoTextInteraction);
|
||||
|
||||
// autorise de nouveau le deplacement du texte
|
||||
setFlag(QGraphicsItem::ItemIsMovable, true);
|
||||
QTimer::singleShot(0, this, SIGNAL(lostFocus()));
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les double-clics sur ce champ de texte.
|
||||
@param event un QGraphicsSceneMouseEvent decrivant le double-clic
|
||||
*/
|
||||
void DiagramTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if (!(textInteractionFlags() & Qt::TextEditable)) {
|
||||
// rend le champ de texte editable
|
||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
||||
|
||||
// edite le champ de texte
|
||||
setFocus(Qt::MouseFocusReason);
|
||||
} else {
|
||||
QGraphicsTextItem::mouseDoubleClickEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Effectue la rotation du texte en elle-meme
|
||||
Pour les DiagramTextItem, la rotation s'effectue autour du point (0, 0).
|
||||
Cette methode peut toutefois etre redefinie dans des classes filles
|
||||
@param angle Angle de la rotation a effectuer
|
||||
*/
|
||||
void DiagramTextItem::applyRotation(const qreal &angle) {
|
||||
setRotation(QET::correctAngle(rotation()+angle));
|
||||
}
|
||||
|
||||
/**
|
||||
Change la position du champ de texte en veillant a ce qu'il
|
||||
reste sur la grille du schema auquel il appartient.
|
||||
@param p Nouvelles coordonnees de l'element
|
||||
*/
|
||||
void DiagramTextItem::setPos(const QPointF &p) {
|
||||
if (p == pos()) return;
|
||||
// pas la peine de positionner sur la grille si l'element n'est pas sur un Diagram
|
||||
if (scene()) {
|
||||
// arrondit l'abscisse a 10 px pres
|
||||
int p_x = qRound(p.x() / (Diagram::xGrid * 1.0)) * Diagram::xGrid;
|
||||
// arrondit l'ordonnee a 10 px pres
|
||||
int p_y = qRound(p.y() / (Diagram::yGrid * 1.0)) * Diagram::yGrid;
|
||||
QGraphicsTextItem::setPos(p_x, p_y);
|
||||
} else QGraphicsTextItem::setPos(p);
|
||||
}
|
||||
|
||||
/**
|
||||
Change la position du champ de texte en veillant a ce que l'il
|
||||
reste sur la grille du schema auquel il appartient.
|
||||
@param x Nouvelle abscisse de l'element
|
||||
@param y Nouvelle ordonnee de l'element
|
||||
*/
|
||||
void DiagramTextItem::setPos(qreal x, qreal y) {
|
||||
setPos(QPointF(x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
@return la position du champ de texte
|
||||
*/
|
||||
QPointF DiagramTextItem::pos() const {
|
||||
return(QGraphicsTextItem::pos());
|
||||
}
|
||||
|
||||
/// Rend le champ de texte non focusable
|
||||
void DiagramTextItem::setNonFocusable() {
|
||||
setFlag(QGraphicsTextItem::ItemIsFocusable, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief DiagramTextItem::setHtmlText
|
||||
* @param txt
|
||||
*/
|
||||
void DiagramTextItem::setHtmlText(const QString &txt) {
|
||||
setHtml( txt );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Edit the text with HtmlEditor
|
||||
*/
|
||||
void DiagramTextItem::edit() {
|
||||
//Open the HtmlEditor
|
||||
qdesigner_internal::RichTextEditorDialog *editor = new qdesigner_internal::RichTextEditorDialog();
|
||||
// connect the in/out
|
||||
connect(editor, SIGNAL(applyEditText(const QString &)), this, SLOT(setHtmlText(const QString &)));
|
||||
// load the Html txt
|
||||
editor->setText( toHtml() );
|
||||
// show
|
||||
editor->show();
|
||||
}
|
||||
|
||||
85
sources/qetgraphicsitem/diagramtextitem.h
Normal file
85
sources/qetgraphicsitem/diagramtextitem.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 DIAGRAM_TEXT_ITEM_H
|
||||
#define DIAGRAM_TEXT_ITEM_H
|
||||
#include <QtGui>
|
||||
#include "diagram.h"
|
||||
/**
|
||||
This class represents a selectable, movable and editable text field on a
|
||||
diagram.
|
||||
@see QGraphicsItem::GraphicsItemFlags
|
||||
*/
|
||||
class DiagramTextItem : public QGraphicsTextItem {
|
||||
Q_OBJECT
|
||||
// constructors, destructor
|
||||
public:
|
||||
DiagramTextItem(QGraphicsItem * = 0, Diagram * = 0);
|
||||
DiagramTextItem(const QString &, QGraphicsItem * = 0, Diagram * = 0);
|
||||
virtual ~DiagramTextItem();
|
||||
|
||||
// attributes
|
||||
public:
|
||||
enum { Type = UserType + 1004 };
|
||||
|
||||
// methods
|
||||
public:
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
DiagramTextItem
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
Diagram *diagram() const;
|
||||
virtual void fromXml(const QDomElement &) = 0;
|
||||
virtual QDomElement toXml(QDomDocument &) const = 0;
|
||||
virtual void setPos(const QPointF &);
|
||||
virtual void setPos(qreal, qreal);
|
||||
virtual QPointF pos() const;
|
||||
qreal rotationAngle() const;
|
||||
void setRotationAngle(const qreal &);
|
||||
void rotateBy(const qreal &);
|
||||
void edit();
|
||||
QPointF mapMovementToScene(const QPointF &) const;
|
||||
QPointF mapMovementFromScene(const QPointF &) const;
|
||||
QPointF mapMovementToParent(const QPointF &) const;
|
||||
QPointF mapMovementFromParent(const QPointF &) const;
|
||||
|
||||
protected:
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||
virtual void focusInEvent(QFocusEvent *);
|
||||
virtual void focusOutEvent(QFocusEvent *);
|
||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void applyRotation(const qreal &);
|
||||
|
||||
signals:
|
||||
/// signal emitted when the text field loses focus
|
||||
void lostFocus();
|
||||
/// signal emitted after text was changed
|
||||
void diagramTextChanged(DiagramTextItem *, const QString &, const QString &);
|
||||
|
||||
public slots:
|
||||
void setNonFocusable();
|
||||
void setHtmlText(const QString &);
|
||||
|
||||
private:
|
||||
/// Previous text value
|
||||
QString previous_text_;
|
||||
/// angle of rotation of the text field
|
||||
qreal rotation_angle_;
|
||||
};
|
||||
#endif
|
||||
444
sources/qetgraphicsitem/element.cpp
Normal file
444
sources/qetgraphicsitem/element.cpp
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 "element.h"
|
||||
#include "qetapp.h"
|
||||
#include "diagram.h"
|
||||
#include "conductor.h"
|
||||
#include "elementtextitem.h"
|
||||
#include "diagramcommands.h"
|
||||
#include <QtDebug>
|
||||
|
||||
/**
|
||||
Constructeur pour un element sans scene ni parent
|
||||
*/
|
||||
Element::Element(QGraphicsItem *parent, Diagram *scene) :
|
||||
QetGraphicsItem(parent),
|
||||
internal_connections_(false),
|
||||
must_highlight_(false)
|
||||
{
|
||||
setZValue(10);
|
||||
}
|
||||
|
||||
/**
|
||||
Destructeur
|
||||
*/
|
||||
Element::~Element() {
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si l'element est mis en evidence
|
||||
*/
|
||||
bool Element::isHighlighted() const {
|
||||
return(must_highlight_);
|
||||
}
|
||||
|
||||
/**
|
||||
@param hl true pour mettre l'element en evidence, false sinon
|
||||
*/
|
||||
void Element::setHighlighted(bool hl) {
|
||||
must_highlight_ = hl;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
Methode principale de dessin de l'element
|
||||
@param painter Le QPainter utilise pour dessiner l'elment
|
||||
@param options Les options de style a prendre en compte
|
||||
@param widget Le widget sur lequel on dessine
|
||||
*/
|
||||
void Element::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
|
||||
|
||||
#ifndef Q_WS_WIN
|
||||
// corrige un bug de rendu ne se produisant que lors du rendu sur QGraphicsScene sous X11 au zoom par defaut
|
||||
static bool must_correct_rendering_bug = QETApp::settings().value("correct-rendering", false).toBool();
|
||||
if (must_correct_rendering_bug) {
|
||||
Diagram *dia = diagram();
|
||||
if (dia && options -> levelOfDetail == 1.0 && widget) {
|
||||
// calcule la rotation qu'a subi l'element
|
||||
qreal applied_rotation = 90.0 * orientation();
|
||||
if (applied_rotation == 90.0) painter -> translate(1.0, -1.0);
|
||||
else if (applied_rotation == 180.0) painter -> translate(-1.0, -1.0);
|
||||
else if (applied_rotation == 270.0) painter -> translate(-1.0, 1.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (must_highlight_) drawHighlight(painter, options);
|
||||
|
||||
// Dessin de l'element lui-meme
|
||||
paint(painter, options);
|
||||
|
||||
// Dessin du cadre de selection si necessaire
|
||||
if (isSelected()) drawSelection(painter, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@return Le rectangle delimitant le contour de l'element
|
||||
*/
|
||||
QRectF Element::boundingRect() const {
|
||||
return(QRectF(QPointF(-hotspot_coord.x(), -hotspot_coord.y()), dimensions));
|
||||
}
|
||||
|
||||
/**
|
||||
Definit la taille de l'element sur le schema. Les tailles doivent etre
|
||||
des multiples de 10 ; si ce n'est pas le cas, les dimensions indiquees
|
||||
seront arrrondies aux dizaines superieures.
|
||||
@param wid Largeur de l'element
|
||||
@param hei Hauteur de l'element
|
||||
@return La taille finale de l'element
|
||||
*/
|
||||
QSize Element::setSize(int wid, int hei) {
|
||||
prepareGeometryChange();
|
||||
// chaque dimension indiquee est arrondie a la dizaine superieure
|
||||
while (wid % 10) ++ wid;
|
||||
while (hei % 10) ++ hei;
|
||||
// les dimensions finales sont conservees et retournees
|
||||
return(dimensions = QSize(wid, hei));
|
||||
}
|
||||
|
||||
/**
|
||||
@return la taille de l'element sur le schema
|
||||
*/
|
||||
QSize Element::size() const {
|
||||
return(dimensions);
|
||||
}
|
||||
|
||||
/**
|
||||
Definit le hotspot de l'element par rapport au coin superieur gauche de son rectangle delimitant.
|
||||
Necessite que la taille ait deja ete definie
|
||||
@param hs Coordonnees du hotspot
|
||||
*/
|
||||
QPoint Element::setHotspot(QPoint hs) {
|
||||
// la taille doit avoir ete definie
|
||||
prepareGeometryChange();
|
||||
if (dimensions.isNull()) hotspot_coord = QPoint(0, 0);
|
||||
else {
|
||||
// les coordonnees indiquees ne doivent pas depasser les dimensions de l'element
|
||||
int hsx = qMin(hs.x(), dimensions.width());
|
||||
int hsy = qMin(hs.y(), dimensions.height());
|
||||
hotspot_coord = QPoint(hsx, hsy);
|
||||
}
|
||||
return(hotspot_coord);
|
||||
}
|
||||
|
||||
/**
|
||||
@return Le hotspot courant de l'element
|
||||
*/
|
||||
QPoint Element::hotspot() const {
|
||||
return(hotspot_coord);
|
||||
}
|
||||
|
||||
/**
|
||||
Selectionne l'element
|
||||
*/
|
||||
void Element::select() {
|
||||
setSelected(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Deselectionne l'element
|
||||
*/
|
||||
void Element::deselect() {
|
||||
setSelected(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@return La pixmap de l'element
|
||||
*/
|
||||
QPixmap Element::pixmap() {
|
||||
if (preview.isNull()) updatePixmap(); // on genere la pixmap si ce n'est deja fait
|
||||
return(preview);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Element::rotateBy
|
||||
* this methode is redefined for handle child item
|
||||
* @param angle
|
||||
*/
|
||||
void Element::rotateBy(const qreal &angle) {
|
||||
qreal applied_angle = QET::correctAngle(angle);
|
||||
applyRotation(applied_angle + rotation());
|
||||
|
||||
//update the path of conductor
|
||||
foreach(QGraphicsItem *qgi, childItems()) {
|
||||
if (Terminal *p = qgraphicsitem_cast<Terminal *>(qgi)) {
|
||||
p -> updateConductor();
|
||||
}
|
||||
}
|
||||
|
||||
// repositionne les textes de l'element qui ne comportent pas l'option "FollowParentRotations"
|
||||
foreach(ElementTextItem *eti, texts()) {
|
||||
if (!eti -> followParentRotations()) {
|
||||
// on souhaite pivoter le champ de texte par rapport a son centre
|
||||
QPointF eti_center = eti -> boundingRect().center();
|
||||
// pour ce faire, on repere la position de son centre par rapport a son parent
|
||||
QPointF parent_eti_center_before = eti -> mapToParent(eti_center);
|
||||
// on applique ensuite une simple rotation contraire, qui sera donc appliquee sur le milieu du cote gauche du champ de texte
|
||||
eti -> rotateBy(-applied_angle);
|
||||
// on regarde ensuite la nouvelle position du centre du champ de texte par rapport a son parent
|
||||
QPointF parent_eti_center_after = eti -> mapToParent(eti_center);
|
||||
// on determine la translation a appliquer
|
||||
QPointF eti_translation = parent_eti_center_before - parent_eti_center_after;
|
||||
// on applique cette translation
|
||||
eti -> setPos(eti -> pos() + eti_translation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*** Methodes protegees ***/
|
||||
|
||||
/**
|
||||
Dessine un petit repere (axes x et y) relatif a l'element
|
||||
@param painter Le QPainter a utiliser pour dessiner les axes
|
||||
@param options Les options de style a prendre en compte
|
||||
*/
|
||||
void Element::drawAxes(QPainter *painter, const QStyleOptionGraphicsItem *options) {
|
||||
Q_UNUSED(options);
|
||||
painter -> setPen(Qt::blue);
|
||||
painter -> drawLine(0, 0, 10, 0);
|
||||
painter -> drawLine(7,-3, 10, 0);
|
||||
painter -> drawLine(7, 3, 10, 0);
|
||||
painter -> setPen(Qt::red);
|
||||
painter -> drawLine(0, 0, 0, 10);
|
||||
painter -> drawLine(0, 10,-3, 7);
|
||||
painter -> drawLine(0, 10, 3, 7);
|
||||
}
|
||||
|
||||
/*** Methodes privees ***/
|
||||
|
||||
/**
|
||||
Dessine le cadre de selection de l'element de maniere systematiquement non antialiasee.
|
||||
@param painter Le QPainter a utiliser pour dessiner les bornes.
|
||||
@param options Les options de style a prendre en compte
|
||||
*/
|
||||
void Element::drawSelection(QPainter *painter, const QStyleOptionGraphicsItem *options) {
|
||||
Q_UNUSED(options);
|
||||
painter -> save();
|
||||
// Annulation des renderhints
|
||||
painter -> setRenderHint(QPainter::Antialiasing, false);
|
||||
painter -> setRenderHint(QPainter::TextAntialiasing, false);
|
||||
painter -> setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||
// Dessin du cadre de selection en gris
|
||||
QPen t;
|
||||
t.setColor(Qt::gray);
|
||||
t.setStyle(Qt::DashDotLine);
|
||||
painter -> setPen(t);
|
||||
// Le dessin se fait a partir du rectangle delimitant
|
||||
painter -> drawRoundRect(boundingRect().adjusted(1, 1, -1, -1), 10, 10);
|
||||
painter -> restore();
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine le cadre de selection de l'element de maniere systematiquement non antialiasee.
|
||||
@param painter Le QPainter a utiliser pour dessiner les bornes.
|
||||
@param options Les options de style a prendre en compte
|
||||
*/
|
||||
void Element::drawHighlight(QPainter *painter, const QStyleOptionGraphicsItem *options) {
|
||||
Q_UNUSED(options);
|
||||
painter -> save();
|
||||
|
||||
qreal gradient_radius = qMin(boundingRect().width(), boundingRect().height()) / 2.0;
|
||||
QRadialGradient gradient(
|
||||
boundingRect().center(),
|
||||
gradient_radius,
|
||||
boundingRect().center()
|
||||
);
|
||||
gradient.setColorAt(0.0, QColor::fromRgb(69, 137, 255, 255));
|
||||
gradient.setColorAt(1.0, QColor::fromRgb(69, 137, 255, 0));
|
||||
QBrush brush(gradient);
|
||||
|
||||
painter -> setPen(Qt::NoPen);
|
||||
painter -> setBrush(brush);
|
||||
// Le dessin se fait a partir du rectangle delimitant
|
||||
painter -> drawRoundRect(boundingRect().adjusted(1, 1, -1, -1), 10, 10);
|
||||
painter -> restore();
|
||||
}
|
||||
|
||||
/**
|
||||
Fonction initialisant et dessinant la pixmap de l'element.
|
||||
*/
|
||||
void Element::updatePixmap() {
|
||||
// Pixmap transparente faisant la taille de base de l'element
|
||||
preview = QPixmap(dimensions);
|
||||
preview.fill(QColor(255, 255, 255, 0));
|
||||
// QPainter sur la pixmap, avec antialiasing
|
||||
QPainter p(&preview);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
// Translation de l'origine du repere de la pixmap
|
||||
p.translate(hotspot_coord);
|
||||
// L'element se dessine sur la pixmap
|
||||
paint(&p, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Permet de savoir si un element XML (QDomElement) represente bien un element
|
||||
@param e Le QDomElement a valide
|
||||
@return true si l'element XML est un Element, false sinon
|
||||
*/
|
||||
bool Element::valideXml(QDomElement &e) {
|
||||
// verifie le nom du tag
|
||||
if (e.tagName() != "element") return(false);
|
||||
|
||||
// verifie la presence des attributs minimaux
|
||||
if (!e.hasAttribute("type")) return(false);
|
||||
if (!e.hasAttribute("x")) return(false);
|
||||
if (!e.hasAttribute("y")) return(false);
|
||||
|
||||
bool conv_ok;
|
||||
// parse l'abscisse
|
||||
e.attribute("x").toDouble(&conv_ok);
|
||||
if (!conv_ok) return(false);
|
||||
|
||||
// parse l'ordonnee
|
||||
e.attribute("y").toDouble(&conv_ok);
|
||||
if (!conv_ok) return(false);
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Methode d'import XML. Cette methode est appelee lors de l'import de contenu
|
||||
XML (coller, import, ouverture de fichier...) afin que l'element puisse
|
||||
gerer lui-meme l'importation de ses bornes. Ici, comme cette classe est
|
||||
caracterisee par un nombre fixe de bornes, l'implementation exige de
|
||||
retrouver exactement ses bornes dans le fichier XML.
|
||||
@param e L'element XML a analyser.
|
||||
@param table_id_adr Reference vers la table de correspondance entre les IDs
|
||||
du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
|
||||
ajouter les bons couples (id, adresse).
|
||||
@return true si l'import a reussi, false sinon
|
||||
|
||||
*/
|
||||
bool Element::fromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr, bool handle_inputs_rotation) {
|
||||
/*
|
||||
les bornes vont maintenant etre recensees pour associer leurs id a leur adresse reelle
|
||||
ce recensement servira lors de la mise en place des fils
|
||||
*/
|
||||
QList<QDomElement> liste_terminals;
|
||||
foreach(QDomElement qde, QET::findInDomElement(e, "terminals", "terminal")) {
|
||||
if (Terminal::valideXml(qde)) liste_terminals << qde;
|
||||
}
|
||||
|
||||
QHash<int, Terminal *> priv_id_adr;
|
||||
int terminals_non_trouvees = 0;
|
||||
foreach(QGraphicsItem *qgi, childItems()) {
|
||||
if (Terminal *p = qgraphicsitem_cast<Terminal *>(qgi)) {
|
||||
bool terminal_trouvee = false;
|
||||
foreach(QDomElement qde, liste_terminals) {
|
||||
if (p -> fromXml(qde)) {
|
||||
priv_id_adr.insert(qde.attribute("id").toInt(), p);
|
||||
terminal_trouvee = true;
|
||||
// We used to break here, because we did not expect
|
||||
// several terminals to share the same position.
|
||||
// Of course, it finally happened.
|
||||
}
|
||||
}
|
||||
if (!terminal_trouvee) ++ terminals_non_trouvees;
|
||||
}
|
||||
}
|
||||
|
||||
if (terminals_non_trouvees > 0) {
|
||||
return(false);
|
||||
} else {
|
||||
// verifie que les associations id / adr n'entrent pas en conflit avec table_id_adr
|
||||
foreach(int id_trouve, priv_id_adr.keys()) {
|
||||
if (table_id_adr.contains(id_trouve)) {
|
||||
// cet element possede un id qui est deja reference (= conflit)
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
// copie des associations id / adr
|
||||
foreach(int id_trouve, priv_id_adr.keys()) {
|
||||
table_id_adr.insert(id_trouve, priv_id_adr.value(id_trouve));
|
||||
}
|
||||
}
|
||||
|
||||
// importe les valeurs des champs de texte
|
||||
QList<QDomElement> inputs = QET::findInDomElement(e, "inputs", "input");
|
||||
foreach(QGraphicsItem *qgi, childItems()) {
|
||||
if (ElementTextItem *eti = qgraphicsitem_cast<ElementTextItem *>(qgi)) {
|
||||
foreach(QDomElement input, inputs) eti -> fromXml(input);
|
||||
}
|
||||
}
|
||||
|
||||
// position, selection
|
||||
setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
|
||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
||||
|
||||
// orientation
|
||||
bool conv_ok;
|
||||
int read_ori = e.attribute("orientation").toInt(&conv_ok);
|
||||
if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = 0;
|
||||
if (handle_inputs_rotation) {
|
||||
rotateBy(90*read_ori);
|
||||
} else {
|
||||
applyRotation(90*read_ori);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Permet d'exporter l'element en XML
|
||||
@param document Document XML a utiliser
|
||||
@param table_adr_id Table de correspondance entre les adresses des bornes
|
||||
et leur id dans la representation XML ; cette table completee par cette
|
||||
methode
|
||||
@return L'element XML representant cet element electrique
|
||||
*/
|
||||
QDomElement Element::toXml(QDomDocument &document, QHash<Terminal *, int> &table_adr_id) const {
|
||||
QDomElement element = document.createElement("element");
|
||||
|
||||
// type
|
||||
element.setAttribute("type", typeId());
|
||||
|
||||
// position, selection et orientation
|
||||
element.setAttribute("x", QString("%1").arg(pos().x()));
|
||||
element.setAttribute("y", QString("%1").arg(pos().y()));
|
||||
element.setAttribute("orientation", QString("%1").arg(orientation()));
|
||||
|
||||
/* recupere le premier id a utiliser pour les bornes de cet element */
|
||||
int id_terminal = 0;
|
||||
if (!table_adr_id.isEmpty()) {
|
||||
// trouve le plus grand id
|
||||
int max_id_t = -1;
|
||||
foreach (int id_t, table_adr_id.values()) {
|
||||
if (id_t > max_id_t) max_id_t = id_t;
|
||||
}
|
||||
id_terminal = max_id_t + 1;
|
||||
}
|
||||
|
||||
// enregistrement des bornes de l'appareil
|
||||
QDomElement xml_terminals = document.createElement("terminals");
|
||||
// pour chaque enfant de l'element
|
||||
foreach(Terminal *t, terminals()) {
|
||||
// alors on enregistre la borne
|
||||
QDomElement terminal = t -> toXml(document);
|
||||
terminal.setAttribute("id", id_terminal);
|
||||
table_adr_id.insert(t, id_terminal ++);
|
||||
xml_terminals.appendChild(terminal);
|
||||
}
|
||||
element.appendChild(xml_terminals);
|
||||
|
||||
// enregistrement des champ de texte de l'appareil
|
||||
QDomElement inputs = document.createElement("inputs");
|
||||
foreach(ElementTextItem *eti, texts()) {
|
||||
inputs.appendChild(eti -> toXml(document));
|
||||
}
|
||||
element.appendChild(inputs);
|
||||
|
||||
return(element);
|
||||
}
|
||||
152
sources/qetgraphicsitem/element.h
Normal file
152
sources/qetgraphicsitem/element.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 ELEMENT_H
|
||||
#define ELEMENT_H
|
||||
#include <QtGui>
|
||||
#include "terminal.h"
|
||||
#include "qetgraphicsitem.h"
|
||||
class Diagram;
|
||||
class ElementTextItem;
|
||||
/**
|
||||
This is the base class for electrical elements.
|
||||
*/
|
||||
class Element : public QetGraphicsItem {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
Element(QGraphicsItem * = 0, Diagram * = 0);
|
||||
virtual ~Element();
|
||||
|
||||
private:
|
||||
Element(const Element &);
|
||||
|
||||
// attributes
|
||||
public:
|
||||
enum { Type = UserType + 1000 };
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
QSize dimensions;
|
||||
QPoint hotspot_coord;
|
||||
QPixmap preview;
|
||||
|
||||
// methods
|
||||
public:
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into an
|
||||
Element.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
|
||||
// pure virtual methods to be defined in derived classes
|
||||
/// @return the list of terminals for this element
|
||||
virtual QList<Terminal *> terminals() const = 0;
|
||||
/// @return the list of conductors attached to this element
|
||||
virtual QList<Conductor *> conductors() const = 0;
|
||||
/// @return the list of text items attached to this element
|
||||
virtual QList<ElementTextItem *> texts() const = 0;
|
||||
/// @return the current number of terminals of this element
|
||||
virtual int terminalsCount() const = 0;
|
||||
/// @return the minimum number of terminals for this element
|
||||
virtual int minTerminalsCount() const = 0;
|
||||
/// @return the maximum number of terminals for this element
|
||||
virtual int maxTerminalsCount() const = 0;
|
||||
/**
|
||||
Draw this element
|
||||
*/
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *) = 0;
|
||||
/// @return This element type ID
|
||||
virtual QString typeId() const = 0;
|
||||
/// @return the human name for this element
|
||||
virtual QString name() const = 0;
|
||||
|
||||
virtual bool isHighlighted() const;
|
||||
virtual void setHighlighted(bool);
|
||||
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||
QRectF boundingRect() const;
|
||||
QSize setSize(int, int);
|
||||
QSize size() const;
|
||||
QPixmap pixmap();
|
||||
|
||||
// methods related to the hotspot
|
||||
QPoint setHotspot(QPoint);
|
||||
QPoint hotspot() const;
|
||||
|
||||
// selection-related methods
|
||||
void select();
|
||||
void deselect();
|
||||
|
||||
// methods related to internal connections
|
||||
bool internalConnections();
|
||||
void setInternalConnections(bool);
|
||||
virtual void rotateBy(const qreal &);
|
||||
|
||||
// methods related to XML import/export
|
||||
static bool valideXml(QDomElement &);
|
||||
virtual bool fromXml(QDomElement &, QHash<int, Terminal *> &, bool = false);
|
||||
virtual QDomElement toXml(QDomDocument &, QHash<Terminal *, int> &) const;
|
||||
|
||||
// orientation-related methods
|
||||
int orientation() const;
|
||||
|
||||
protected:
|
||||
void drawAxes(QPainter *, const QStyleOptionGraphicsItem *);
|
||||
|
||||
private:
|
||||
bool internal_connections_;
|
||||
bool must_highlight_;
|
||||
void drawSelection(QPainter *, const QStyleOptionGraphicsItem *);
|
||||
void drawHighlight(QPainter *, const QStyleOptionGraphicsItem *);
|
||||
void updatePixmap();
|
||||
};
|
||||
|
||||
/**
|
||||
Indicate whether this element allows internal connections, i.e. whether its
|
||||
terminals can be linked together using a conductor.
|
||||
@return true if internal connections are accepted, false otherwise
|
||||
*/
|
||||
inline bool Element::internalConnections() {
|
||||
return(internal_connections_);
|
||||
}
|
||||
|
||||
/**
|
||||
Specify whether this element allows internal connections, i.e. whether its
|
||||
terminals can be linked together using a conductor.
|
||||
@return true for internal connections to be accepted, false otherwise
|
||||
*/
|
||||
inline void Element::setInternalConnections(bool ic) {
|
||||
internal_connections_ = ic;
|
||||
}
|
||||
|
||||
/**
|
||||
Indicate the current orientation of this element
|
||||
O = 0°
|
||||
1 = 90°
|
||||
2 = 180°
|
||||
3 = 270°
|
||||
@return the current orientation of this element
|
||||
*/
|
||||
inline int Element::orientation() const {
|
||||
return(QET::correctAngle(rotation())/90);
|
||||
}
|
||||
|
||||
#endif
|
||||
310
sources/qetgraphicsitem/elementtextitem.cpp
Normal file
310
sources/qetgraphicsitem/elementtextitem.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
Copyright 2006-2012 Xavier Guerrin
|
||||
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 "elementtextitem.h"
|
||||
#include "diagram.h"
|
||||
#include "diagramcommands.h"
|
||||
#include "element.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param parent_element Le QGraphicsItem parent du champ de texte
|
||||
@param parent_diagram Le schema auquel appartient le champ de texte
|
||||
*/
|
||||
ElementTextItem::ElementTextItem(Element *parent_element, Diagram *parent_diagram) :
|
||||
DiagramTextItem(parent_element, parent_diagram),
|
||||
parent_element_(parent_element),
|
||||
follow_parent_rotations(false),
|
||||
original_rotation_angle_(0.0),
|
||||
first_move_(true)
|
||||
{
|
||||
// par defaut, les DiagramTextItem sont Selectable et Movable
|
||||
// cela nous convient, on ne touche pas a ces flags
|
||||
|
||||
adjustItemPosition(1);
|
||||
// ajuste la position du QGraphicsItem lorsque le QTextDocument change
|
||||
connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
|
||||
connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
|
||||
}
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param parent_element L'element parent du champ de texte
|
||||
@param parent_diagram Le schema auquel appartient le champ de texte
|
||||
@param text Le texte affiche par le champ de texte
|
||||
*/
|
||||
ElementTextItem::ElementTextItem(const QString &text, Element *parent_element, Diagram *parent_diagram) :
|
||||
DiagramTextItem(text, parent_element, parent_diagram),
|
||||
parent_element_(parent_element),
|
||||
follow_parent_rotations(false),
|
||||
original_rotation_angle_(0.0),
|
||||
first_move_(true)
|
||||
{
|
||||
// par defaut, les DiagramTextItem sont Selectable et Movable
|
||||
// cela nous convient, on ne touche pas a ces flags
|
||||
|
||||
adjustItemPosition(1);
|
||||
// ajuste la position du QGraphicsItem lorsque le QTextDocument change
|
||||
connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
|
||||
connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
ElementTextItem::~ElementTextItem() {
|
||||
}
|
||||
|
||||
/**
|
||||
@return L'element parent de ce champ de texte, ou 0 si celui-ci n'en a pas.
|
||||
*/
|
||||
Element *ElementTextItem::parentElement() const {
|
||||
return(parent_element_);
|
||||
}
|
||||
|
||||
/**
|
||||
Modifie la position du champ de texte
|
||||
@param pos La nouvelle position du champ de texte
|
||||
*/
|
||||
void ElementTextItem::setPos(const QPointF &pos) {
|
||||
QGraphicsTextItem::setPos(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
Modifie la position du champ de texte
|
||||
@param x La nouvelle abscisse du champ de texte
|
||||
@param y La nouvelle ordonnee du champ de texte
|
||||
*/
|
||||
void ElementTextItem::setPos(qreal x, qreal y) {
|
||||
setPos(QPointF(x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
@return La position (bidouillee) du champ de texte
|
||||
*/
|
||||
QPointF ElementTextItem::pos() const {
|
||||
return(QGraphicsTextItem::pos());
|
||||
}
|
||||
|
||||
/**
|
||||
Permet de lire le texte a mettre dans le champ a partir d'un element XML.
|
||||
Cette methode se base sur la position du champ pour assigner ou non la
|
||||
valeur a ce champ.
|
||||
@param e L'element XML representant le champ de texte
|
||||
*/
|
||||
void ElementTextItem::fromXml(const QDomElement &e) {
|
||||
QPointF _pos = pos();
|
||||
if (
|
||||
qFuzzyCompare(qreal(e.attribute("x").toDouble()), _pos.x()) &&
|
||||
qFuzzyCompare(qreal(e.attribute("y").toDouble()), _pos.y())
|
||||
) {
|
||||
setPlainText(e.attribute("text"));
|
||||
|
||||
qreal user_pos_x, user_pos_y;
|
||||
if (
|
||||
QET::attributeIsAReal(e, "userx", &user_pos_x) &&
|
||||
QET::attributeIsAReal(e, "usery", &user_pos_y)
|
||||
) {
|
||||
setPos(user_pos_x, user_pos_y);
|
||||
}
|
||||
|
||||
qreal xml_rotation_angle;
|
||||
if (QET::attributeIsAReal(e, "userrotation", &xml_rotation_angle)) {
|
||||
setRotationAngle(xml_rotation_angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@param document Le document XML a utiliser
|
||||
@return L'element XML representant ce champ de texte
|
||||
*/
|
||||
QDomElement ElementTextItem::toXml(QDomDocument &document) const {
|
||||
QDomElement result = document.createElement("input");
|
||||
|
||||
result.setAttribute("x", QString("%1").arg(originalPos().x()));
|
||||
result.setAttribute("y", QString("%1").arg(originalPos().y()));
|
||||
|
||||
if (pos() != originalPos()) {
|
||||
result.setAttribute("userx", QString("%1").arg(pos().x()));
|
||||
result.setAttribute("usery", QString("%1").arg(pos().y()));
|
||||
}
|
||||
|
||||
result.setAttribute("text", toPlainText());
|
||||
|
||||
if (rotationAngle() != originalRotationAngle()) {
|
||||
result.setAttribute("userrotation", QString("%1").arg(rotationAngle()));
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
@param p Position originale / de reference pour ce champ
|
||||
Cette position est utilisee lors de l'export en XML
|
||||
*/
|
||||
void ElementTextItem::setOriginalPos(const QPointF &p) {
|
||||
original_position = p;
|
||||
}
|
||||
|
||||
/**
|
||||
@return la position originale / de reference pour ce champ
|
||||
*/
|
||||
QPointF ElementTextItem::originalPos() const {
|
||||
return(original_position);
|
||||
}
|
||||
|
||||
/**
|
||||
Definit l'angle de rotation original de ce champ de texte
|
||||
@param rotation_angle un angle de rotation
|
||||
*/
|
||||
void ElementTextItem::setOriginalRotationAngle(const qreal &rotation_angle) {
|
||||
original_rotation_angle_ = QET::correctAngle(rotation_angle);
|
||||
}
|
||||
|
||||
/**
|
||||
@return l'angle de rotation original de ce champ de texte
|
||||
*/
|
||||
qreal ElementTextItem::originalRotationAngle() const {
|
||||
return(original_rotation_angle_);
|
||||
}
|
||||
|
||||
/**
|
||||
Set the font used to render the text item to \a font.
|
||||
*/
|
||||
void ElementTextItem::setFont(const QFont &font) {
|
||||
DiagramTextItem::setFont(font);
|
||||
adjustItemPosition(1);
|
||||
}
|
||||
|
||||
/**
|
||||
Cette methode s'assure que la position de l'ElementTextItem est coherente
|
||||
en ajustant :
|
||||
* la transformation de base qui permet de considerer que l'origine
|
||||
correspond au milieu du bord gauche du champ de texte
|
||||
* l'origine utilisee lors des appels a setRotation et setScale
|
||||
@param new_block_count Nombre de blocs dans l'ElementTextItem
|
||||
*/
|
||||
void ElementTextItem::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);
|
||||
}
|
||||
|
||||
/**
|
||||
Effetue la rotation du texte en elle-meme
|
||||
Pour les ElementTextItem, la rotation s'effectue autour du milieu du bord
|
||||
gauche du champ de texte.
|
||||
@param angle Angle de la rotation a effectuer
|
||||
*/
|
||||
void ElementTextItem::applyRotation(const qreal &angle) {
|
||||
QGraphicsTextItem::setRotation(QGraphicsTextItem::rotation() + angle);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le clic sur le champ de texte
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void ElementTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
||||
first_move_ = true;
|
||||
if (e -> modifiers() & Qt::ControlModifier) {
|
||||
setSelected(!isSelected());
|
||||
}
|
||||
DiagramTextItem::mousePressEvent(e);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les mouvements de souris lies au champ de texte
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void ElementTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (textInteractionFlags() & Qt::TextEditable) {
|
||||
DiagramTextItem::mouseMoveEvent(e);
|
||||
} else if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) {
|
||||
QPointF old_pos = pos();
|
||||
/*
|
||||
Utiliser e -> pos() directement aurait pour effet de positionner
|
||||
l'origine du champ de texte a la position indiquee par le curseur,
|
||||
ce qui n'est pas l'effet recherche
|
||||
Au lieu de cela, on applique a la position actuelle le vecteur
|
||||
definissant le mouvement effectue depuis la derniere position
|
||||
cliquee avec le bouton gauche
|
||||
*/
|
||||
QPointF movement = e -> pos() - e -> buttonDownPos(Qt::LeftButton);
|
||||
|
||||
/*
|
||||
Les methodes pos() et setPos() travaillent toujours avec les
|
||||
coordonnees de l'item parent (ou de la scene s'il n'y a pas d'item
|
||||
parent). On n'oublie donc pas de mapper le mouvement fraichement
|
||||
calcule sur l'item parent avant de l'appliquer.
|
||||
*/
|
||||
QPointF parent_movement = mapMovementToParent(movement);
|
||||
setPos(pos() + parent_movement);
|
||||
|
||||
Diagram *diagram_ptr = diagram();
|
||||
if (diagram_ptr) {
|
||||
if (first_move_) {
|
||||
// on signale le debut d'un deplacement d'ElementTextItems au schema parent
|
||||
int moved_texts_count = diagram_ptr -> beginMoveElementTexts(this);
|
||||
|
||||
// s'il n'y a qu'un seul texte deplace, on met en valeur l'element parent
|
||||
if (moved_texts_count == 1 && parent_element_) {
|
||||
parent_element_ -> setHighlighted(true);
|
||||
parent_element_ -> update();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Comme setPos() n'est pas oblige d'appliquer exactement la
|
||||
valeur qu'on lui fournit, on calcule le mouvement reellement
|
||||
applique.
|
||||
*/
|
||||
QPointF effective_movement = pos() - old_pos;
|
||||
QPointF scene_effective_movement = mapMovementToScene(mapMovementFromParent(effective_movement));
|
||||
|
||||
// on applique le mouvement subi aux autres textes a deplacer
|
||||
diagram_ptr -> continueMoveElementTexts(scene_effective_movement);
|
||||
}
|
||||
} else e -> ignore();
|
||||
|
||||
if (first_move_) {
|
||||
first_move_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le relachement de souris
|
||||
Cette methode cree un objet d'annulation pour le deplacement
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void ElementTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (Diagram *diagram_ptr = diagram()) {
|
||||
// on arrete de mettre en valeur l'element parent
|
||||
if (parent_element_) {
|
||||
if (parent_element_ -> isHighlighted()) {
|
||||
parent_element_ -> setHighlighted(false);
|
||||
}
|
||||
}
|
||||
|
||||
diagram_ptr -> endMoveElementTexts();
|
||||
}
|
||||
if (!(e -> modifiers() & Qt::ControlModifier)) {
|
||||
QGraphicsTextItem::mouseReleaseEvent(e);
|
||||
}
|
||||
}
|
||||
96
sources/qetgraphicsitem/elementtextitem.h
Normal file
96
sources/qetgraphicsitem/elementtextitem.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2006-2012 Xavier Guerrin
|
||||
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 ELEMENT_TEXT_ITEM_H
|
||||
#define ELEMENT_TEXT_ITEM_H
|
||||
#include "diagramtextitem.h"
|
||||
#include <QtXml>
|
||||
class Diagram;
|
||||
class Element;
|
||||
/**
|
||||
This class represents a text item attached to an element. Users can change its
|
||||
value, adjust its position (defined relatively to its parent element), and
|
||||
direct it to any angle.
|
||||
*/
|
||||
class ElementTextItem : public DiagramTextItem {
|
||||
Q_OBJECT
|
||||
// constructors, destructor
|
||||
public:
|
||||
ElementTextItem(Element * = 0, Diagram * = 0);
|
||||
ElementTextItem(const QString &, Element * = 0, Diagram * = 0);
|
||||
virtual ~ElementTextItem();
|
||||
|
||||
// attributes
|
||||
public:
|
||||
enum { Type = UserType + 1003 };
|
||||
|
||||
private:
|
||||
Element *parent_element_;
|
||||
bool follow_parent_rotations;
|
||||
QPointF original_position;
|
||||
qreal original_rotation_angle_;
|
||||
bool first_move_;
|
||||
|
||||
// methods
|
||||
public:
|
||||
virtual int type() const { return Type; }
|
||||
Element *parentElement() const;
|
||||
/// @return the rectangle defining the bounds of this text item
|
||||
virtual QRectF boundingRect() const { return(QGraphicsTextItem::boundingRect().adjusted(0.0, -1.1, 0.0, 0.0)); }
|
||||
bool followParentRotations() const;
|
||||
void setFollowParentRotations(bool);
|
||||
void fromXml(const QDomElement &);
|
||||
QDomElement toXml(QDomDocument &) const;
|
||||
void setPos(const QPointF &);
|
||||
void setPos(qreal, qreal);
|
||||
virtual QPointF pos() const;
|
||||
void setOriginalPos(const QPointF &);
|
||||
QPointF originalPos() const;
|
||||
void setOriginalRotationAngle(const qreal &);
|
||||
qreal originalRotationAngle() const;
|
||||
virtual void setFont(const QFont &);
|
||||
|
||||
public slots:
|
||||
void adjustItemPosition(int = 0);
|
||||
|
||||
protected:
|
||||
virtual void applyRotation(const qreal &);
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
|
||||
};
|
||||
|
||||
/**
|
||||
Element text items can optionally be applied a counter-rotation when their
|
||||
parent element is rotated, thus preserving their readability.
|
||||
@return whether this text item follows the rotations of its parent element.
|
||||
*/
|
||||
inline bool ElementTextItem::followParentRotations() const {
|
||||
return(follow_parent_rotations);
|
||||
}
|
||||
|
||||
/**
|
||||
Element text items can optionally be applied a counter-rotation when their
|
||||
parent element is rotated, thus preserving their readability.
|
||||
@param frp whether this text item should follow the rotations of its parent
|
||||
element.
|
||||
*/
|
||||
inline void ElementTextItem::setFollowParentRotations(bool frp) {
|
||||
follow_parent_rotations = frp;
|
||||
}
|
||||
|
||||
#endif
|
||||
43
sources/qetgraphicsitem/fixedelement.cpp
Normal file
43
sources/qetgraphicsitem/fixedelement.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2006-2012 Xavier Guerrin
|
||||
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 "fixedelement.h"
|
||||
/**
|
||||
Constructeur
|
||||
*/
|
||||
FixedElement::FixedElement(QGraphicsItem *parent, Diagram *scene) : Element(parent, scene) {
|
||||
}
|
||||
|
||||
/**
|
||||
Destructeur
|
||||
*/
|
||||
FixedElement::~FixedElement() {
|
||||
}
|
||||
|
||||
/**
|
||||
@return Le nombre minimal de bornes que l'element peut avoir
|
||||
*/
|
||||
int FixedElement::minTerminalsCount() const {
|
||||
return(terminalsCount());
|
||||
}
|
||||
|
||||
/**
|
||||
@return Le nombre maximal de bornes que l'element peut avoir
|
||||
*/
|
||||
int FixedElement::maxTerminalsCount() const {
|
||||
return(terminalsCount());
|
||||
}
|
||||
42
sources/qetgraphicsitem/fixedelement.h
Normal file
42
sources/qetgraphicsitem/fixedelement.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright 2006-2012 Xavier Guerrin
|
||||
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 ELEMENTFIXE_H
|
||||
#define ELEMENTFIXE_H
|
||||
#include "element.h"
|
||||
/**
|
||||
This class represents an element having a fixed number of terminals.
|
||||
*/
|
||||
class FixedElement : public Element {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
FixedElement(QGraphicsItem * = 0, Diagram * = 0);
|
||||
virtual ~FixedElement();
|
||||
|
||||
// methods
|
||||
public:
|
||||
int minTerminalsCount() const;
|
||||
int maxTerminalsCount() const;
|
||||
virtual int terminalsCount() const = 0;
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *) = 0;
|
||||
virtual QString typeId() const = 0;
|
||||
virtual QString name() const = 0;
|
||||
};
|
||||
#endif
|
||||
191
sources/qetgraphicsitem/ghostelement.cpp
Normal file
191
sources/qetgraphicsitem/ghostelement.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
Copyright 2006-2012 Xavier Guerrin
|
||||
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 "ghostelement.h"
|
||||
#include "qet.h"
|
||||
#include "terminal.h"
|
||||
#include "elementtextitem.h"
|
||||
#include "diagramcommands.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param location Emplacement de la definition d'element a utiliser
|
||||
@param qgi Le QGraphicsItem parent de cet element
|
||||
@param d Le schema affichant cet element
|
||||
*/
|
||||
GhostElement::GhostElement(
|
||||
const ElementsLocation &location,
|
||||
QGraphicsItem *qgi,
|
||||
Diagram *d
|
||||
) :
|
||||
CustomElement(location, qgi, d)
|
||||
{
|
||||
QString tooltip_string = QString(
|
||||
tr("<u>\311l\351ment manquant\240:</u> %1")
|
||||
).arg(location_.toString());
|
||||
setToolTip(tooltip_string);
|
||||
}
|
||||
|
||||
/**
|
||||
Destructeur
|
||||
*/
|
||||
GhostElement::~GhostElement() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@param e L'element XML a analyser.
|
||||
@param table_id_adr Reference vers la table de correspondance entre les IDs
|
||||
du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
|
||||
ajouter les bons couples (id, adresse).
|
||||
@return true si l'import a reussi, false sinon
|
||||
*/
|
||||
bool GhostElement::fromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr, bool handle_inputs_rotation) {
|
||||
// instancie les bornes decrites dans l'element XML
|
||||
terminalsFromXml(e, table_id_adr);
|
||||
|
||||
// instancie les champs de texte decrits dans l'element XML
|
||||
foreach(QDomElement qde, QET::findInDomElement(e, "inputs", "input")) {
|
||||
qde.setAttribute("size", 9); // arbitraire
|
||||
if (ElementTextItem *new_input = CustomElement::parseInput(qde)) {
|
||||
new_input -> fromXml(qde);
|
||||
}
|
||||
qde.removeAttribute("size");
|
||||
}
|
||||
|
||||
/*
|
||||
maintenant que l'element fantome connait toutes les bornes et tous les
|
||||
champs de texte, on peut determiner une taille appropriee
|
||||
*/
|
||||
QRect final_bounding_rect = minimalBoundingRect().united(childrenBoundingRect()).toAlignedRect();
|
||||
setSize(final_bounding_rect.width(), final_bounding_rect.height());
|
||||
setHotspot(QPoint() - final_bounding_rect.topLeft());
|
||||
setInternalConnections(true);
|
||||
|
||||
// on peut desormais confectionner le rendu de l'element
|
||||
generateDrawings();
|
||||
|
||||
// position, selection
|
||||
setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
|
||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
||||
|
||||
// orientation
|
||||
bool conv_ok;
|
||||
int read_ori = e.attribute("orientation").toInt(&conv_ok);
|
||||
if (!conv_ok || read_ori < 0 || read_ori > 3) read_ori = 0;
|
||||
if (handle_inputs_rotation) {
|
||||
rotateBy(90*read_ori);
|
||||
} else {
|
||||
applyRotation(90*read_ori);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@return le bounding rect minimum, utilise si l'element fantome n'a ni champ
|
||||
de texte ni borne.
|
||||
*/
|
||||
QRectF GhostElement::minimalBoundingRect() const {
|
||||
return(
|
||||
QRectF(
|
||||
QPointF(-10.0, -10.0),
|
||||
QSizeF(20.0, 20.0)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere l'import des bornes
|
||||
@param e L'element XML a analyser.
|
||||
@param table_id_adr Reference vers la table de correspondance entre les IDs
|
||||
du fichier XML et les adresses en memoire. Si l'import reussit, il faut y
|
||||
ajouter les bons couples (id, adresse).
|
||||
@return true si l'import a reussi, false sinon
|
||||
*/
|
||||
bool GhostElement::terminalsFromXml(QDomElement &e, QHash<int, Terminal *> &table_id_adr) {
|
||||
// instancie les bornes decrites dans l'element XML
|
||||
foreach(QDomElement qde, QET::findInDomElement(e, "terminals", "terminal")) {
|
||||
if (!Terminal::valideXml(qde)) continue;
|
||||
|
||||
// modifie certains attributs pour que l'analyse par la classe CustomElement reussisse
|
||||
int previous_x_value = qde.attribute("x").toInt();
|
||||
int previous_y_value = qde.attribute("y").toInt();
|
||||
int previous_ori_value = qde.attribute("orientation").toInt();
|
||||
|
||||
qreal x_add = 0.0, y_add = 0.0;
|
||||
if (previous_ori_value == QET::North) y_add = -Terminal::terminalSize;
|
||||
else if (previous_ori_value == QET::East) x_add = Terminal::terminalSize;
|
||||
else if (previous_ori_value == QET::South) y_add = Terminal::terminalSize;
|
||||
else if (previous_ori_value == QET::West) x_add = -Terminal::terminalSize;
|
||||
qde.setAttribute("x", previous_x_value + x_add);
|
||||
qde.setAttribute("y", previous_y_value + y_add);
|
||||
qde.setAttribute("orientation", QET::orientationToString(static_cast<QET::Orientation>(previous_ori_value)));
|
||||
|
||||
if (Terminal *new_terminal = CustomElement::parseTerminal(qde)) {
|
||||
table_id_adr.insert(qde.attribute("id").toInt(), new_terminal);
|
||||
}
|
||||
|
||||
// restaure les attributs modifies
|
||||
qde.setAttribute("x", previous_x_value);
|
||||
qde.setAttribute("y", previous_y_value);
|
||||
qde.setAttribute("orientation", previous_ori_value);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
Genere les rendus de l'element fantome : il s'agit d'un rectangle
|
||||
representant grosso modo l'espace que devait prendre l'element initial.
|
||||
En son centre est dessine un point d'interrogation. Une petite croix indique
|
||||
le point de saisie de l'element.
|
||||
*/
|
||||
void GhostElement::generateDrawings() {
|
||||
// style de dessin
|
||||
QPen t(QBrush(Qt::black), 1.0);
|
||||
|
||||
// rendu normal
|
||||
QPainter qp;
|
||||
qp.begin(&drawing);
|
||||
qp.setPen(t);
|
||||
qp.setRenderHint(QPainter::Antialiasing, false);
|
||||
generateDrawing(&qp);
|
||||
qp.end();
|
||||
|
||||
// rendu low_zoom
|
||||
QPainter low_zoom_qp;
|
||||
low_zoom_qp.begin(&low_zoom_drawing);
|
||||
t.setCosmetic(true);
|
||||
low_zoom_qp.setRenderHint(QPainter::Antialiasing, false);
|
||||
low_zoom_qp.setPen(t);
|
||||
generateDrawing(&low_zoom_qp);
|
||||
low_zoom_qp.end();
|
||||
}
|
||||
|
||||
/**
|
||||
Genere un rendu de l'element fantome
|
||||
@see generateDrawings
|
||||
*/
|
||||
void GhostElement::generateDrawing(QPainter *painter) {
|
||||
// une petite croix indique le point de saisie de l'element
|
||||
painter -> drawLine(QLineF(-1.0, 0.0, 1.0, 0.0));
|
||||
painter -> drawLine(QLineF(0.0, -1.0, 0.0, 1.0));
|
||||
|
||||
// rectangle avec un point d'interrogation au centre
|
||||
QRectF drawn_rect = boundingRect().adjusted(4.0, 4.0, -4.0, -4.0);
|
||||
painter -> drawRect(drawn_rect);
|
||||
painter -> drawText(drawn_rect, Qt::AlignHCenter | Qt::AlignVCenter, "?");
|
||||
}
|
||||
53
sources/qetgraphicsitem/ghostelement.h
Normal file
53
sources/qetgraphicsitem/ghostelement.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2006-2012 Xavier Guerrin
|
||||
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 GHOST_ELEMENT_H
|
||||
#define GHOST_ELEMENT_H
|
||||
#include "customelement.h"
|
||||
class Diagram;
|
||||
class QGraphicsItem;
|
||||
class ElementsLocation;
|
||||
class Terminal;
|
||||
/**
|
||||
The GhostElement class inherits CustomElement. A GhostElement aims at
|
||||
visually replacing a CustomElement whose definition could not be loaded.
|
||||
This way, instead of not loading an element, thus potentially losing its
|
||||
position, its orientation, its child text items and conductors, one can
|
||||
substitute a GhostElement. The GhostElement will extrapolate the position
|
||||
of terminals and text items from the rest of the diagram. It is visually
|
||||
rendered using a simple rectangle.
|
||||
*/
|
||||
class GhostElement : public CustomElement {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
// constructor, destructor
|
||||
public:
|
||||
GhostElement(const ElementsLocation &, QGraphicsItem * = 0, Diagram * = 0);
|
||||
virtual ~GhostElement();
|
||||
|
||||
// methods
|
||||
public:
|
||||
virtual bool fromXml(QDomElement &, QHash<int, Terminal *> &, bool = false);
|
||||
|
||||
protected:
|
||||
QRectF minimalBoundingRect() const;
|
||||
bool terminalsFromXml(QDomElement &, QHash<int, Terminal *> &);
|
||||
void generateDrawings();
|
||||
void generateDrawing(QPainter *);
|
||||
};
|
||||
#endif
|
||||
140
sources/qetgraphicsitem/independenttextitem.cpp
Normal file
140
sources/qetgraphicsitem/independenttextitem.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright 2006-2012 Xavier Guerrin
|
||||
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 "independenttextitem.h"
|
||||
#include "diagram.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param parent_diagram Le schema auquel est rattache le champ de texte
|
||||
*/
|
||||
IndependentTextItem::IndependentTextItem(Diagram *parent_diagram) :
|
||||
DiagramTextItem(0, parent_diagram),
|
||||
first_move_(true)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param text Le texte affiche par le champ de texte
|
||||
@param parent_diagram Le schema auquel est rattache le champ de texte
|
||||
*/
|
||||
IndependentTextItem::IndependentTextItem(const QString &text, Diagram *parent_diagram) :
|
||||
DiagramTextItem(text, 0, parent_diagram),
|
||||
first_move_(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
IndependentTextItem::~IndependentTextItem() {
|
||||
}
|
||||
|
||||
/**
|
||||
Permet de lire le texte a mettre dans le champ a partir d'un element XML.
|
||||
Cette methode se base sur la position du champ pour assigner ou non la
|
||||
valeur a ce champ.
|
||||
@param e L'element XML representant le champ de texte
|
||||
*/
|
||||
void IndependentTextItem::fromXml(const QDomElement &e) {
|
||||
setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble());
|
||||
setHtml(e.attribute("text"));
|
||||
setRotationAngle(e.attribute("rotation").toDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
@param document Le document XML a utiliser
|
||||
@return L'element XML representant ce champ de texte
|
||||
*/
|
||||
QDomElement IndependentTextItem::toXml(QDomDocument &document) const {
|
||||
QDomElement result = document.createElement("input");
|
||||
result.setAttribute("x", QString("%1").arg(pos().x()));
|
||||
result.setAttribute("y", QString("%1").arg(pos().y()));
|
||||
result.setAttribute("text", toHtml());
|
||||
if (rotationAngle()) {
|
||||
result.setAttribute("rotation", QString("%1").arg(rotationAngle()));
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le clic sur le champ de texte
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void IndependentTextItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
||||
first_move_ = true;
|
||||
if (e -> modifiers() & Qt::ControlModifier) {
|
||||
setSelected(!isSelected());
|
||||
}
|
||||
DiagramTextItem::mousePressEvent(e);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les mouvements de souris lies au champ de texte
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void IndependentTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (textInteractionFlags() & Qt::TextEditable) {
|
||||
DiagramTextItem::mouseMoveEvent(e);
|
||||
} else if ((flags() & QGraphicsItem::ItemIsMovable) && isSelected() && (e -> buttons() & Qt::LeftButton)) {
|
||||
// le champ de texte est en train d'etre deplace
|
||||
Diagram *diagram_ptr = diagram();
|
||||
if (diagram_ptr) {
|
||||
if (first_move_) {
|
||||
// il s'agit du premier mouvement du deplacement, on le signale
|
||||
// au schema parent
|
||||
diagram_ptr -> beginMoveElements(this);
|
||||
}
|
||||
}
|
||||
|
||||
// on applique le mouvement impose par la souris
|
||||
QPointF old_pos = pos();
|
||||
if (first_move_) {
|
||||
mouse_to_origin_movement_ = old_pos - e -> buttonDownScenePos(Qt::LeftButton);
|
||||
}
|
||||
QPointF expected_pos = e-> scenePos() + mouse_to_origin_movement_;
|
||||
setPos(expected_pos); // setPos() will snap the expected position to the grid
|
||||
|
||||
// on calcule le mouvement reellement applique par setPos()
|
||||
QPointF effective_movement = pos() - old_pos;
|
||||
if (diagram_ptr) {
|
||||
// on signale le mouvement ainsi applique au schema parent, qui
|
||||
// l'appliquera aux autres items selectionnes selon son bon vouloir
|
||||
diagram_ptr -> continueMoveElements(effective_movement);
|
||||
}
|
||||
} else e -> ignore();
|
||||
|
||||
if (first_move_) {
|
||||
first_move_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Gere le relachement de souris
|
||||
Cette methode a ete reimplementee pour tenir a jour la liste des elements
|
||||
et conducteurs a deplacer au niveau du schema.
|
||||
@param e Objet decrivant l'evenement souris
|
||||
*/
|
||||
void IndependentTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (flags() & QGraphicsItem::ItemIsMovable) {
|
||||
if (Diagram *diagram_ptr = diagram()) {
|
||||
diagram_ptr -> endMoveElements();
|
||||
}
|
||||
}
|
||||
if (!(e -> modifiers() & Qt::ControlModifier)) {
|
||||
DiagramTextItem::mouseReleaseEvent(e);
|
||||
}
|
||||
}
|
||||
58
sources/qetgraphicsitem/independenttextitem.h
Normal file
58
sources/qetgraphicsitem/independenttextitem.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2006-2012 Xavier Guerrin
|
||||
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 INDEPENDENT_TEXT_ITEM_H
|
||||
#define INDEPENDENT_TEXT_ITEM_H
|
||||
#include <QtGui>
|
||||
#include "diagramtextitem.h"
|
||||
/**
|
||||
This class represents an independent text field on a particular diagram.
|
||||
It may be moved, edited, and rotated.
|
||||
*/
|
||||
class IndependentTextItem : public DiagramTextItem {
|
||||
Q_OBJECT
|
||||
// constructors, destructor
|
||||
public:
|
||||
IndependentTextItem(Diagram * = 0);
|
||||
IndependentTextItem(const QString &, Diagram* = 0);
|
||||
virtual ~IndependentTextItem();
|
||||
|
||||
// attributes
|
||||
public:
|
||||
enum { Type = UserType + 1005 };
|
||||
|
||||
// methods
|
||||
public:
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into an
|
||||
IndependentTextItem.
|
||||
@return le type de QGraphicsItem
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual void fromXml(const QDomElement &);
|
||||
virtual QDomElement toXml(QDomDocument &) const;
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
|
||||
|
||||
private:
|
||||
bool first_move_;
|
||||
QPointF mouse_to_origin_movement_;
|
||||
};
|
||||
#endif
|
||||
155
sources/qetgraphicsitem/qetgraphicsitem.cpp
Normal file
155
sources/qetgraphicsitem/qetgraphicsitem.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 "qetgraphicsitem.h"
|
||||
|
||||
/**
|
||||
* @brief QetGraphicsItem::QetGraphicsItem Default constructor
|
||||
* @param uuid, uuid of the item
|
||||
* @param diagram, diagram aka QGraphicsScene of the item
|
||||
* @param parent, Parent Item
|
||||
*/
|
||||
QetGraphicsItem::QetGraphicsItem(QGraphicsItem *parent):
|
||||
QGraphicsObject(parent),
|
||||
first_move_(true)
|
||||
{
|
||||
}
|
||||
|
||||
QetGraphicsItem::~QetGraphicsItem()
|
||||
{}
|
||||
|
||||
void QetGraphicsItem::editProperty(){}
|
||||
|
||||
/**
|
||||
* @brief QetGraphicsItem::diagram
|
||||
*return the diagram of this item
|
||||
*/
|
||||
Diagram* QetGraphicsItem::diagram() const{
|
||||
return(qobject_cast<Diagram *>(scene()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QetGraphicsItem::setPos
|
||||
*set the position of the item to p
|
||||
* @param p the new position of item
|
||||
*/
|
||||
void QetGraphicsItem::setPos(const QPointF &p) {
|
||||
if (p == pos()) return;
|
||||
if (scene()) {
|
||||
// arrondit l'abscisse a 10 px pres
|
||||
int p_x = qRound(p.x() / (Diagram::xGrid * 1.0)) * Diagram::xGrid;
|
||||
// arrondit l'ordonnee a 10 px pres
|
||||
int p_y = qRound(p.y() / (Diagram::yGrid * 1.0)) * Diagram::yGrid;
|
||||
QGraphicsItem::setPos(p_x, p_y);
|
||||
} else QGraphicsItem::setPos(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QetGraphicsItem::setPos
|
||||
*set the position of the item
|
||||
* @param x new abscisse of item
|
||||
* @param y new ordonne of item
|
||||
*/
|
||||
void QetGraphicsItem::setPos(qreal x, qreal y) {
|
||||
setPos(QPointF(x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
Permet de tourner l'item de maniere relative.
|
||||
L'angle added_rotation est ajoute a l'orientation actuelle du image.
|
||||
@param added_rotation Angle a ajouter a la rotation actuelle
|
||||
@see applyRotation
|
||||
*/
|
||||
void QetGraphicsItem::rotateBy(const qreal &added_rotation) {
|
||||
qreal applied_added_rotation = QET::correctAngle(added_rotation + rotation());
|
||||
applyRotation(applied_added_rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
Effectue la rotation de l'item en lui même
|
||||
Cette methode peut toutefois etre redefinie dans des classes filles
|
||||
@param angle Angle de la rotation a effectuer
|
||||
*/
|
||||
void QetGraphicsItem::applyRotation(const qreal &angle) {
|
||||
setRotation(QET::correctAngle(angle));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QetGraphicsItem::mousePressEvent
|
||||
*handle the mouse click
|
||||
* @param e
|
||||
*/
|
||||
void QetGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
||||
first_move_ = true;
|
||||
if (e -> modifiers() & Qt::ControlModifier) {
|
||||
setSelected(!isSelected());
|
||||
}
|
||||
QGraphicsItem::mousePressEvent(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QetGraphicsItem::mouseDoubleClickEvent
|
||||
*handle the mouse double click
|
||||
* @param e
|
||||
*/
|
||||
void QetGraphicsItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
|
||||
Q_UNUSED (e);
|
||||
editProperty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QetGraphicsItem::mouseMoveEvent
|
||||
*handle mouse movement
|
||||
* @param e
|
||||
*/
|
||||
void QetGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (isSelected() && e -> buttons() & Qt::LeftButton) {
|
||||
//Item is moving
|
||||
if(diagram() && first_move_) {
|
||||
//It's the first movement, we signal it to parent diagram
|
||||
diagram() -> beginMoveElements(this);
|
||||
}
|
||||
|
||||
//we apply the mouse movement
|
||||
QPointF old_pos = pos();
|
||||
if (first_move_) {
|
||||
mouse_to_origin_movement_ = old_pos - e -> buttonDownScenePos(Qt::LeftButton);
|
||||
}
|
||||
QPointF expected_pos = e -> scenePos() + mouse_to_origin_movement_;
|
||||
setPos(expected_pos); // setPos() will snap the expected position to the grid
|
||||
|
||||
//we calcul the real movement apply by setPos()
|
||||
QPointF effective_movement = pos() - old_pos;
|
||||
if (diagram()) {
|
||||
//we signal the real movement apply to diagram,
|
||||
//who he apply to other selected item
|
||||
diagram() -> continueMoveElements(effective_movement);
|
||||
}
|
||||
} else e -> ignore();
|
||||
|
||||
if (first_move_) first_move_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QetGraphicsItem::mouseReleaseEvent
|
||||
*handle mouse release click
|
||||
* @param e
|
||||
*/
|
||||
void QetGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
|
||||
if (diagram()) diagram() -> endMoveElements();
|
||||
if (!(e -> modifiers() & Qt::ControlModifier)) QGraphicsItem::mouseReleaseEvent(e);
|
||||
}
|
||||
58
sources/qetgraphicsitem/qetgraphicsitem.h
Normal file
58
sources/qetgraphicsitem/qetgraphicsitem.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2006-2013 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 QETGRAPHICSITEM_H
|
||||
#define QETGRAPHICSITEM_H
|
||||
|
||||
#include "diagram.h"
|
||||
|
||||
class QetGraphicsItem : public QGraphicsObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//constructor destructor
|
||||
QetGraphicsItem(QGraphicsItem *parent = 0);
|
||||
virtual ~QetGraphicsItem() = 0;
|
||||
|
||||
//abstarct methode
|
||||
virtual void editProperty ();
|
||||
|
||||
//public methode
|
||||
Diagram* diagram() const;
|
||||
virtual void setPos(const QPointF &p);
|
||||
virtual void setPos(qreal x, qreal y);
|
||||
virtual void rotateBy(const qreal &);
|
||||
virtual void applyRotation(const qreal &);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
//protected method
|
||||
protected:
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent *e);
|
||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e);
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *e);
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *e);
|
||||
|
||||
protected:
|
||||
bool first_move_;
|
||||
QPointF mouse_to_origin_movement_;
|
||||
|
||||
};
|
||||
|
||||
#endif // QETGRAPHICSITEM_H
|
||||
Reference in New Issue
Block a user