mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-01-06 05:10:52 +01:00
Element editor : move all graphics part in a single directory
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@3628 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
180
sources/editor/graphicspart/customelementgraphicpart.cpp
Normal file
180
sources/editor/graphicspart/customelementgraphicpart.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "customelementgraphicpart.h"
|
||||
|
||||
/**
|
||||
Ecrit les attributs de style dans un element XML
|
||||
@param qde L'element XML a modifier
|
||||
|
||||
*/
|
||||
void CustomElementGraphicPart::stylesToXml(QDomElement &qde) const {
|
||||
QString css_like_styles;
|
||||
|
||||
css_like_styles += "line-style:";
|
||||
if (_linestyle == DashedStyle) css_like_styles += "dashed";
|
||||
if (_linestyle == DottedStyle) css_like_styles += "dotted";
|
||||
if (_linestyle == DashdottedStyle)css_like_styles += "dashdotted";
|
||||
else if (_linestyle == NormalStyle) css_like_styles += "normal";
|
||||
|
||||
css_like_styles += ";line-weight:";
|
||||
if (_lineweight == NoneWeight) css_like_styles += "none";
|
||||
else if (_lineweight == ThinWeight) css_like_styles += "thin";
|
||||
else if (_lineweight == NormalWeight) css_like_styles += "normal";
|
||||
else if (_lineweight == UltraWeight) css_like_styles += "hight";
|
||||
else if (_lineweight == BigWeight) css_like_styles += "eleve";
|
||||
|
||||
|
||||
css_like_styles += ";filling:";
|
||||
if (_filling == NoneFilling) css_like_styles += "none";
|
||||
else if (_filling == BlackFilling) css_like_styles += "black";
|
||||
else if (_filling == WhiteFilling) css_like_styles += "white";
|
||||
else if (_filling == GreenFilling) css_like_styles += "green";
|
||||
else if (_filling == BlueFilling) css_like_styles += "blue";
|
||||
else if (_filling == RedFilling) css_like_styles += "red";
|
||||
|
||||
|
||||
css_like_styles += ";color:";
|
||||
if (_color == WhiteColor) css_like_styles += "white";
|
||||
else if (_color == BlackColor) css_like_styles += "black";
|
||||
else if (_color == GreenColor) css_like_styles += "green";
|
||||
else if (_color == RedColor) css_like_styles += "red";
|
||||
else if (_color == BlueColor) css_like_styles += "blue";
|
||||
|
||||
qde.setAttribute("style", css_like_styles);
|
||||
qde.setAttribute("antialias", _antialiased ? "true" : "false");
|
||||
}
|
||||
|
||||
/**
|
||||
Lit les attributs de style depuis un element XML
|
||||
@param qde L'element XML a analyser
|
||||
*/
|
||||
void CustomElementGraphicPart::stylesFromXml(const QDomElement &qde) {
|
||||
resetStyles();
|
||||
|
||||
// recupere la liste des couples style / valeur
|
||||
QStringList styles = qde.attribute("style").split(";", QString::SkipEmptyParts);
|
||||
|
||||
// analyse chaque couple
|
||||
QRegExp rx("^\\s*([a-z-]+)\\s*:\\s*([a-z-]+)\\s*$");
|
||||
foreach (QString style, styles) {
|
||||
if (!rx.exactMatch(style)) continue;
|
||||
QString style_name = rx.cap(1);
|
||||
QString style_value = rx.cap(2);
|
||||
if (style_name == "line-style") {
|
||||
if (style_value == "dashed") _linestyle = DashedStyle;
|
||||
if (style_value == "dotted") _linestyle = DottedStyle;
|
||||
if (style_value == "dashdotted") _linestyle = DashdottedStyle;
|
||||
else if (style_value == "normal") _linestyle = NormalStyle;
|
||||
// il n'y a pas de else car les valeurs non conformes sont ignorees (idem par la suite)
|
||||
} else if (style_name == "line-weight") {
|
||||
if (style_value == "none") _lineweight = NoneWeight;
|
||||
else if (style_value == "thin") _lineweight = ThinWeight;
|
||||
else if (style_value == "normal") _lineweight = NormalWeight;
|
||||
else if (style_value == "hight") _lineweight = UltraWeight;
|
||||
else if (style_value == "eleve") _lineweight = BigWeight;
|
||||
} else if (style_name == "filling") {
|
||||
if (style_value == "white") _filling = WhiteFilling;
|
||||
else if (style_value == "black") _filling = BlackFilling;
|
||||
else if (style_value == "red") _filling = RedFilling;
|
||||
else if (style_value == "green") _filling = GreenFilling;
|
||||
else if (style_value == "blue") _filling = BlueFilling;
|
||||
else if (style_value == "none") _filling = NoneFilling;
|
||||
} else if (style_name == "color") {
|
||||
if (style_value == "black") _color = BlackColor;
|
||||
else if (style_value == "white") _color = WhiteColor;
|
||||
else if (style_value == "green") _color = GreenColor;
|
||||
else if (style_value == "red") _color = RedColor;
|
||||
else if (style_value == "blue") _color = BlueColor;
|
||||
}
|
||||
}
|
||||
|
||||
// recupere l'antialiasing
|
||||
_antialiased = qde.attribute("antialias") == "true";
|
||||
}
|
||||
|
||||
/**
|
||||
Remet les styles par defaut
|
||||
*/
|
||||
void CustomElementGraphicPart::resetStyles() {
|
||||
_linestyle = NormalStyle;
|
||||
_lineweight = NormalWeight;
|
||||
_filling = NoneFilling;
|
||||
_color = BlackColor;
|
||||
_antialiased = false;
|
||||
}
|
||||
|
||||
/**
|
||||
Applique les styles a un Qpainter
|
||||
@param painter QPainter a modifier
|
||||
*/
|
||||
void CustomElementGraphicPart::applyStylesToQPainter(QPainter &painter) const {
|
||||
// recupere le QPen et la QBrush du QPainter
|
||||
QPen pen = painter.pen();
|
||||
QBrush brush = painter.brush();
|
||||
|
||||
// applique le style de trait
|
||||
if (_linestyle == DashedStyle) pen.setStyle(Qt::DashLine);
|
||||
if (_linestyle == DashdottedStyle) pen.setStyle(Qt::DashDotLine);
|
||||
if (_linestyle == DottedStyle) pen.setStyle(Qt::DotLine);
|
||||
else if (_linestyle == NormalStyle) pen.setStyle(Qt::SolidLine);
|
||||
|
||||
// applique l'epaisseur de trait
|
||||
if (_lineweight == NoneWeight) pen.setColor(QColor(0, 0, 0, 0));
|
||||
else if (_lineweight == ThinWeight) pen.setWidth(0);
|
||||
else if (_lineweight == NormalWeight) pen.setWidthF(1.0);
|
||||
else if (_lineweight == UltraWeight) pen.setWidthF(2.0);
|
||||
else if (_lineweight == BigWeight) pen.setWidthF(5.0);
|
||||
|
||||
|
||||
|
||||
// applique le remplissage
|
||||
if (_filling == NoneFilling) {
|
||||
brush.setStyle(Qt::NoBrush);
|
||||
} else if (_filling == BlackFilling) {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::black);
|
||||
} else if (_filling == WhiteFilling) {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::white);
|
||||
} else if (_filling == GreenFilling) {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::green);
|
||||
} else if (_filling == RedFilling) {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::red);
|
||||
} else if (_filling == BlueFilling) {
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(Qt::blue);
|
||||
}
|
||||
|
||||
// applique la couleur de trait
|
||||
if (_color == WhiteColor) pen.setColor(QColor(255, 255, 255, pen.color().alpha()));
|
||||
else if (_color == BlackColor) pen.setColor(QColor( 0, 0, 0, pen.color().alpha()));
|
||||
else if (_color == GreenColor) pen.setColor(QColor(Qt::green));
|
||||
else if (_color == RedColor) pen.setColor(QColor(Qt::red));
|
||||
else if (_color == BlueColor) pen.setColor(QColor(Qt::blue));
|
||||
|
||||
|
||||
// applique l'antialiasing
|
||||
painter.setRenderHint(QPainter::Antialiasing, _antialiased);
|
||||
painter.setRenderHint(QPainter::TextAntialiasing, _antialiased);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform, _antialiased);
|
||||
|
||||
painter.setPen(pen);
|
||||
painter.setBrush(brush);
|
||||
}
|
||||
132
sources/editor/graphicspart/customelementgraphicpart.h
Normal file
132
sources/editor/graphicspart/customelementgraphicpart.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CUSTOM_ELEMENT_GRAPHIC_PART_H
|
||||
#define CUSTOM_ELEMENT_GRAPHIC_PART_H
|
||||
#include <QPainter>
|
||||
#include <QObject>
|
||||
#include "customelementpart.h"
|
||||
#include "styleeditor.h"
|
||||
class QETElementEditor;
|
||||
typedef CustomElementGraphicPart CEGP;
|
||||
/**
|
||||
This class represents an element visual/geometric primitive. It provides
|
||||
methods to manage style attributes common to most primitives.
|
||||
*/
|
||||
class CustomElementGraphicPart : public QObject, public CustomElementPart {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// This enum lists the various line styles available to draw primitives.
|
||||
Q_ENUMS(LineStyle)
|
||||
enum LineStyle {
|
||||
NormalStyle, ///< Normal line
|
||||
DashedStyle, ///< Dashed line
|
||||
DottedStyle, ///< Dotted line
|
||||
DashdottedStyle ///< Dashdotted line
|
||||
};
|
||||
|
||||
/// This enum lists the various line weights available to draw primitives.
|
||||
Q_ENUMS(LineWeight)
|
||||
enum LineWeight {
|
||||
NoneWeight, ///< Invisible line
|
||||
ThinWeight, ///< Thin line
|
||||
NormalWeight, ///< Normal line 1px
|
||||
UltraWeight, ///< Normal line 2px
|
||||
BigWeight ///< Big Line
|
||||
|
||||
};
|
||||
|
||||
/// This enum lists the various filling colors available to draw primitives.
|
||||
Q_ENUMS(Filling)
|
||||
enum Filling {
|
||||
NoneFilling, ///< No filling (i.e. transparent)
|
||||
BlackFilling, ///< Black filling
|
||||
WhiteFilling, ///< White filling
|
||||
GreenFilling, ///< Green filling
|
||||
RedFilling, ///< Red filling
|
||||
BlueFilling ///< Green filling
|
||||
};
|
||||
|
||||
/// This enum lists the various line colors available to draw primitives.
|
||||
Q_ENUMS(Color)
|
||||
enum Color {
|
||||
BlackColor, ///< Black line
|
||||
WhiteColor, ///< White line
|
||||
GreenColor, ///< Green line
|
||||
RedColor, ///< Red line
|
||||
BlueColor ///< Blue line
|
||||
};
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
/**
|
||||
Constructor
|
||||
@param editor Element editor this primitive lives in.
|
||||
*/
|
||||
CustomElementGraphicPart(QETElementEditor *editor) :
|
||||
CustomElementPart(editor),
|
||||
_linestyle(NormalStyle),
|
||||
_lineweight(NormalWeight),
|
||||
_filling(NoneFilling),
|
||||
_color(BlackColor),
|
||||
_antialiased(false)
|
||||
{
|
||||
};
|
||||
|
||||
/// Destructor
|
||||
virtual ~CustomElementGraphicPart() {
|
||||
};
|
||||
|
||||
// attributes
|
||||
private:
|
||||
LineStyle _linestyle;
|
||||
LineWeight _lineweight;
|
||||
Filling _filling ;
|
||||
Color _color;
|
||||
bool _antialiased;
|
||||
|
||||
// methods
|
||||
public:
|
||||
|
||||
/// PROPERTY
|
||||
Q_PROPERTY(LineStyle line_style READ lineStyle WRITE setLineStyle)
|
||||
LineStyle lineStyle() const {return _linestyle;}
|
||||
void setLineStyle(const LineStyle ls) {_linestyle = ls;}
|
||||
Q_PROPERTY(LineWeight line_weight READ lineWeight WRITE setLineWeight)
|
||||
LineWeight lineWeight() const {return _lineweight;}
|
||||
void setLineWeight(const LineWeight lw) {_lineweight = lw;}
|
||||
Q_PROPERTY(Filling filling READ filling WRITE setFilling)
|
||||
Filling filling() const {return _filling;}
|
||||
void setFilling(const Filling f) {_filling = f;}
|
||||
Q_PROPERTY(Color color READ color WRITE setColor)
|
||||
Color color() const {return _color;}
|
||||
void setColor(const Color c) {_color = c;}
|
||||
Q_PROPERTY(bool antialias READ antialiased WRITE setAntialiased)
|
||||
bool antialiased() const {return _antialiased;}
|
||||
void setAntialiased(const bool b) {_antialiased = b;}
|
||||
|
||||
virtual void setProperty(const char *name, const QVariant &value) {QObject::setProperty(name, value);}
|
||||
virtual QVariant property(const char *name) const {return QObject::property(name);}
|
||||
|
||||
protected:
|
||||
void stylesToXml(QDomElement &) const;
|
||||
void stylesFromXml(const QDomElement &);
|
||||
void resetStyles();
|
||||
void applyStylesToQPainter(QPainter &) const;
|
||||
};
|
||||
#endif
|
||||
141
sources/editor/graphicspart/customelementpart.cpp
Normal file
141
sources/editor/graphicspart/customelementpart.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "customelementpart.h"
|
||||
#include "qetgraphicsitem/customelement.h"
|
||||
#include "qetelementeditor.h"
|
||||
|
||||
/// @return le QETElementEditor auquel cet editeur appartient
|
||||
QETElementEditor *CustomElementPart::elementEditor() const {
|
||||
return(element_editor);
|
||||
}
|
||||
|
||||
/**
|
||||
Appelle le slot updateCurrentPartEditor de l'editeur
|
||||
@see QETElementEditor::updateCurrentPartEditor()
|
||||
*/
|
||||
void CustomElementPart::updateCurrentPartEditor() const {
|
||||
if (element_editor) {
|
||||
element_editor -> updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
|
||||
/// @return l'ElementScene contenant les parties editees par cet editeur
|
||||
ElementScene *CustomElementPart::elementScene() const {
|
||||
return(element_editor -> elementScene());
|
||||
}
|
||||
|
||||
/// @return la QUndoStack a utiliser pour les annulations
|
||||
QUndoStack &CustomElementPart::undoStack() const {
|
||||
return(elementScene() -> undoStack());
|
||||
}
|
||||
|
||||
/// @return this primitive as a QGraphicsItem
|
||||
QGraphicsItem *CustomElementPart::toItem() {
|
||||
return(dynamic_cast<QGraphicsItem *>(this));
|
||||
}
|
||||
|
||||
/**
|
||||
This method is called by the decorator when it manages only a single
|
||||
primitive. This brings the possibility to implement custom behaviour, such
|
||||
as text edition, points edition or specific resizing.
|
||||
The default implementation does nothing.
|
||||
*/
|
||||
void CustomElementPart::setDecorator(ElementPrimitiveDecorator *decorator) {
|
||||
Q_UNUSED(decorator)
|
||||
}
|
||||
|
||||
/**
|
||||
This method is called by the decorator when it needs to determine the best
|
||||
way to interactively scale a primitive. It is typically called when only a
|
||||
single primitive is being scaled.
|
||||
The default implementation systematically returns
|
||||
QET::SnapScalingPointToGrid
|
||||
*/
|
||||
QET::ScalingMethod CustomElementPart::preferredScalingMethod() const {
|
||||
return(QET::SnapScalingPointToGrid);
|
||||
}
|
||||
|
||||
/**
|
||||
This method is called by the decorator when it manages only a single
|
||||
primitive and it received a mouse press event.
|
||||
The implementation should return true if the primitive accepts the event, false otherwise.
|
||||
The default implementation returns false.
|
||||
*/
|
||||
bool CustomElementPart::singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
This method is called by the decorator when it manages only a single
|
||||
primitive and it received a mouse move event.
|
||||
The implementation should return true if the primitive accepts the event, false otherwise.
|
||||
The default implementation returns false.
|
||||
*/
|
||||
bool CustomElementPart::singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
This method is called by the decorator when it manages only a single
|
||||
primitive and it received a mouse release event.
|
||||
The implementation should return true if the primitive accepts the event, false otherwise.
|
||||
The default implementation returns false.
|
||||
*/
|
||||
bool CustomElementPart::singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
This method is called by the decorator when it manages only a single
|
||||
primitive and it received a mouse double click event.
|
||||
The implementation should return true if the primitive accepts the event, false otherwise.
|
||||
The default implementation returns false.
|
||||
*/
|
||||
bool CustomElementPart::singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
Helper method to map points in CustomElementPart::handleUserTransformation()
|
||||
@param initial_selection_rect Selection rectangle when the movement started, in scene coordinates
|
||||
@param new_selection_rect New selection rectangle, in scene coordinates
|
||||
@param points List of points when the movement started, in scene coordinates.
|
||||
@return The list of points mapped from initial_selection_rect to new_selection_rect
|
||||
*/
|
||||
QList<QPointF> CustomElementPart::mapPoints(const QRectF &initial_selection_rect, const QRectF &new_selection_rect, const QList<QPointF> &points) {
|
||||
QList<QPointF> new_points;
|
||||
if (!points.count()) return(new_points);
|
||||
|
||||
// compare the new selection rectangle with the stored one to get the scaling ratio
|
||||
qreal sx = new_selection_rect.width() / initial_selection_rect.width();
|
||||
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
|
||||
|
||||
QPointF initial_top_left = initial_selection_rect.topLeft();
|
||||
qreal new_top_left_x = new_selection_rect.x();
|
||||
qreal new_top_left_y = new_selection_rect.y();
|
||||
|
||||
foreach (QPointF point, points) {
|
||||
QPointF point_offset = point - initial_top_left;
|
||||
new_points << QPointF(
|
||||
new_top_left_x + (point_offset.rx() * sx),
|
||||
new_top_left_y + (point_offset.y() * sy)
|
||||
);
|
||||
}
|
||||
|
||||
return(new_points);
|
||||
}
|
||||
114
sources/editor/graphicspart/customelementpart.h
Normal file
114
sources/editor/graphicspart/customelementpart.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CUSTOM_ELEMENT_PART_H
|
||||
#define CUSTOM_ELEMENT_PART_H
|
||||
#include <QtGui>
|
||||
#include <QtXml>
|
||||
#include <QImage>
|
||||
#include "qet.h"
|
||||
class CustomElement;
|
||||
class ElementPrimitiveDecorator;
|
||||
class ElementScene;
|
||||
class QETElementEditor;
|
||||
|
||||
/**
|
||||
This abstract class represents a primitive of the visual representation of an
|
||||
electrical element. The Element, FixedElement and CustomElement classes do not
|
||||
embed its attributes and methods in order to remain lightweight; indeed, there
|
||||
is no point for those classes to store their visual representation with
|
||||
anything more complex than a QImage.
|
||||
*/
|
||||
class CustomElementPart {
|
||||
// constructors, destructor
|
||||
public:
|
||||
/**
|
||||
Constructor
|
||||
@param editor Element editor this primitive is attached to
|
||||
*/
|
||||
CustomElementPart(QETElementEditor *editor) : element_editor(editor) {}
|
||||
/// Destructor
|
||||
virtual ~CustomElementPart() {}
|
||||
|
||||
private:
|
||||
CustomElementPart(const CustomElementPart &);
|
||||
|
||||
// attributes
|
||||
private:
|
||||
QETElementEditor *element_editor;
|
||||
|
||||
// methods
|
||||
public:
|
||||
/**
|
||||
Load the primitive from an XML element that describes it
|
||||
*/
|
||||
virtual void fromXml(const QDomElement &) = 0;
|
||||
/**
|
||||
Export the primitive as an XML element
|
||||
*/
|
||||
virtual const QDomElement toXml(QDomDocument &) const = 0;
|
||||
/**
|
||||
Set a specific property of the primitive
|
||||
*/
|
||||
virtual void setProperty(const char *name, const QVariant &value) = 0;
|
||||
/**
|
||||
Get the current value of a specific primitive property
|
||||
*/
|
||||
virtual QVariant property(const char *name) const = 0;
|
||||
/**
|
||||
@return whether the primitive appears to be useless (e.g. 0-length line)
|
||||
Typically, useless primitives are discarded when saving the element.
|
||||
*/
|
||||
virtual bool isUseless() const = 0;
|
||||
virtual QRectF sceneGeometricRect() const = 0;
|
||||
/**
|
||||
Inform this part a user-induced transformation is about to begin. This method can be used to save data required by handleUserTransformation().
|
||||
*/
|
||||
virtual void startUserTransformation(const QRectF &) = 0;
|
||||
/**
|
||||
Make this part fit into the provided rectangle.
|
||||
*/
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &) = 0;
|
||||
/// @return a pointer to the parent element editor
|
||||
virtual QETElementEditor *elementEditor() const;
|
||||
/**
|
||||
Call the updateCurrentPartEditor() slot of the editor
|
||||
@see QETElementEditor::updateCurrentPartEditor()
|
||||
*/
|
||||
virtual void updateCurrentPartEditor() const;
|
||||
/// @return a pointer to the parent editing scene
|
||||
virtual ElementScene *elementScene() const;
|
||||
/// @return the element editor undo stack
|
||||
virtual QUndoStack &undoStack() const;
|
||||
/// @return the name of the primitive
|
||||
virtual QString name() const = 0;
|
||||
/// @return the name that will be used as XML tag when exporting the primitive
|
||||
virtual QString xmlName() const = 0;
|
||||
|
||||
virtual QGraphicsItem *toItem();
|
||||
|
||||
virtual void setDecorator(ElementPrimitiveDecorator *);
|
||||
virtual QET::ScalingMethod preferredScalingMethod() const;
|
||||
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
|
||||
protected:
|
||||
QList<QPointF> mapPoints(const QRectF &, const QRectF &, const QList<QPointF> &);
|
||||
};
|
||||
#endif
|
||||
230
sources/editor/graphicspart/partarc.cpp
Normal file
230
sources/editor/graphicspart/partarc.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "partarc.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param editor L'editeur d'element concerne
|
||||
@param parent Le QGraphicsItem parent de cet arc
|
||||
@param scene La scene sur laquelle figure cet arc
|
||||
*/
|
||||
PartArc::PartArc(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
|
||||
CustomElementGraphicPart(editor),
|
||||
QGraphicsEllipseItem(parent, scene),
|
||||
_angle(-90),
|
||||
start_angle(0)
|
||||
{
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptedMouseButtons(Qt::LeftButton);
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
PartArc::~PartArc() {
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine l'arc de cercle
|
||||
@param painter QPainter a utiliser pour rendre le dessin
|
||||
@param options Options pour affiner le rendu
|
||||
@param widget Widget sur lequel le rendu est effectue
|
||||
*/
|
||||
void PartArc::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
|
||||
Q_UNUSED(widget);
|
||||
applyStylesToQPainter(*painter);
|
||||
// enleve systematiquement la couleur de fond
|
||||
painter -> setBrush(Qt::NoBrush);
|
||||
QPen t = painter -> pen();
|
||||
t.setCosmetic(options && options -> levelOfDetail < 1.0);
|
||||
painter -> setPen(t);
|
||||
|
||||
if (isSelected()) {
|
||||
// dessine l'ellipse en noir
|
||||
painter -> drawEllipse(rect());
|
||||
|
||||
// dessine l'arc en rouge
|
||||
t.setColor(Qt::red);
|
||||
painter -> setPen(t);
|
||||
}
|
||||
|
||||
painter -> drawArc(rect(), start_angle * 16, _angle * 16);
|
||||
if (isSelected()) {
|
||||
// dessine la croix au centre de l'ellipse
|
||||
painter -> setRenderHint(QPainter::Antialiasing, false);
|
||||
painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
|
||||
QPointF center = rect().center();
|
||||
painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
|
||||
painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte l'arc de cercle en XML
|
||||
@param xml_document Document XML a utiliser pour creer l'element XML
|
||||
@return un element XML decrivant l'arc de cercle
|
||||
*/
|
||||
const QDomElement PartArc::toXml(QDomDocument &xml_document) const {
|
||||
QDomElement xml_element = xml_document.createElement("arc");
|
||||
QPointF top_left(sceneTopLeft());
|
||||
xml_element.setAttribute("x", QString("%1").arg(top_left.x()));
|
||||
xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
|
||||
xml_element.setAttribute("width", QString("%1").arg(rect().width()));
|
||||
xml_element.setAttribute("height", QString("%1").arg(rect().height()));
|
||||
xml_element.setAttribute("start", QString("%1").arg(start_angle));
|
||||
xml_element.setAttribute("angle", QString("%1").arg(_angle));
|
||||
stylesToXml(xml_element);
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
/**
|
||||
Importe les proprietes d'un arc de cercle depuis un element XML
|
||||
@param qde Element XML a lire
|
||||
*/
|
||||
void PartArc::fromXml(const QDomElement &qde) {
|
||||
stylesFromXml(qde);
|
||||
setRect(
|
||||
QRectF(
|
||||
mapFromScene(
|
||||
qde.attribute("x", "0").toDouble(),
|
||||
qde.attribute("y", "0").toDouble()
|
||||
),
|
||||
QSizeF(
|
||||
qde.attribute("width", "0").toDouble(),
|
||||
qde.attribute("height", "0").toDouble()
|
||||
)
|
||||
)
|
||||
);
|
||||
setStartAngle(qde.attribute("start", "0").toInt());
|
||||
setAngle(qde.attribute("angle", "-90").toInt());
|
||||
}
|
||||
|
||||
/**
|
||||
@return le coin superieur gauche du rectangle dans lequel s'inscrit
|
||||
l'ellipse dont fait partie cet arc, dans les coordonnees de la scene.
|
||||
*/
|
||||
QPointF PartArc::sceneTopLeft() const {
|
||||
return(mapToScene(rect().topLeft()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartArc::setX
|
||||
* @param x is the center of the rect bounding this ellipse
|
||||
*/
|
||||
void PartArc::setX(const qreal x) {
|
||||
QRectF current_rect = rect();
|
||||
QPointF current_pos = mapToScene(current_rect.center());
|
||||
setRect(current_rect.translated(x - current_pos.x(), 0.0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartArc::setY
|
||||
* @param y is the center of the rect bounding this ellipse
|
||||
*/
|
||||
void PartArc::setY(const qreal y) {
|
||||
QRectF current_rect = rect();
|
||||
QPointF current_pos = mapToScene(current_rect.center());
|
||||
setRect(current_rect.translated(0.0, y - current_pos.y()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartArc::setWidth
|
||||
* @param w is the width of the rect bounding this ellipse
|
||||
*/
|
||||
void PartArc::setWidth(const qreal w) {
|
||||
qreal new_width = qAbs(w);
|
||||
QRectF current_rect = rect();
|
||||
current_rect.translate((new_width - current_rect.width()) / -2.0, 0.0);
|
||||
current_rect.setWidth(new_width);
|
||||
setRect(current_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartArc::setHeight
|
||||
* @param h is the heigth of the rect bounding this ellipse
|
||||
*/
|
||||
void PartArc::setHeight(const qreal h) {
|
||||
qreal new_height = qAbs(h);
|
||||
QRectF current_rect = rect();
|
||||
current_rect.translate(0.0, (new_height - current_rect.height()) / -2.0);
|
||||
current_rect.setHeight(new_height);
|
||||
setRect(current_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les changements intervenant sur cette partie
|
||||
@param change Type de changement
|
||||
@param value Valeur numerique relative au changement
|
||||
*/
|
||||
QVariant PartArc::itemChange(GraphicsItemChange change, const QVariant &value) {
|
||||
if (scene()) {
|
||||
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
|
||||
updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
return(QGraphicsEllipseItem::itemChange(change, value));
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
|
||||
conservee / enregistree.
|
||||
Un arc est pertinent des lors que ses dimensions et son etendue ne sont
|
||||
pas nulles.
|
||||
*/
|
||||
bool PartArc::isUseless() const {
|
||||
return(rect().isNull() || !angle());
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates. It is different from boundingRect() because it is not supposed
|
||||
to imply any margin, and it is different from shape because it is a regular
|
||||
rectangle, not a complex shape.
|
||||
*/
|
||||
QRectF PartArc::sceneGeometricRect() const {
|
||||
return(mapToScene(rect()).boundingRect());
|
||||
}
|
||||
|
||||
/**
|
||||
Start the user-induced transformation, provided this primitive is contained
|
||||
within the \a initial_selection_rect bounding rectangle.
|
||||
*/
|
||||
void PartArc::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
saved_points_.clear();
|
||||
saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight());
|
||||
}
|
||||
|
||||
/**
|
||||
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
|
||||
*/
|
||||
void PartArc::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
|
||||
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
|
||||
setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle delimitant cette partie.
|
||||
*/
|
||||
QRectF PartArc::boundingRect() const {
|
||||
qreal adjust = 1.5;
|
||||
QRectF r(QGraphicsEllipseItem::boundingRect().normalized());
|
||||
r.adjust(-adjust, -adjust, adjust, adjust);
|
||||
return(r);
|
||||
}
|
||||
95
sources/editor/graphicspart/partarc.h
Normal file
95
sources/editor/graphicspart/partarc.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PART_ARC_H
|
||||
#define PART_ARC_H
|
||||
#include <QtGui>
|
||||
#include "customelementgraphicpart.h"
|
||||
/**
|
||||
This class represents an elliptical arc primitive which may be used to
|
||||
compose the drawing of an electrical element within the element editor.
|
||||
*/
|
||||
class PartArc : public CustomElementGraphicPart, public QGraphicsEllipseItem {
|
||||
Q_OBJECT
|
||||
// constructors, destructor
|
||||
public:
|
||||
PartArc(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
|
||||
virtual ~PartArc();
|
||||
|
||||
private:
|
||||
PartArc(const PartArc &);
|
||||
|
||||
// attributes
|
||||
private:
|
||||
int _angle;
|
||||
int start_angle;
|
||||
|
||||
// methods
|
||||
public:
|
||||
enum { Type = UserType + 1101 };
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
PartArc.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
|
||||
virtual QString name() const { return(QObject::tr("arc", "element part name")); }
|
||||
virtual QString xmlName() const { return(QString("arc")); }
|
||||
virtual const QDomElement toXml(QDomDocument &) const;
|
||||
virtual void fromXml(const QDomElement &);
|
||||
virtual QPointF sceneTopLeft() const;
|
||||
virtual QRectF boundingRect() const;
|
||||
virtual bool isUseless() const;
|
||||
virtual QRectF sceneGeometricRect() const;
|
||||
virtual void startUserTransformation(const QRectF &);
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||
|
||||
///PROPERT
|
||||
// X value
|
||||
Q_PROPERTY(qreal x READ x WRITE setX)
|
||||
qreal x() const {return mapToScene(rect().center()).x() ;}
|
||||
void setX(const qreal x);
|
||||
//Y value
|
||||
Q_PROPERTY(qreal y READ y WRITE setY)
|
||||
qreal y() const {return mapToScene(rect().center()).y();}
|
||||
void setY(const qreal y);
|
||||
// horizontal diameter
|
||||
Q_PROPERTY(qreal diameter_h READ width WRITE setWidth)
|
||||
qreal width() const {return rect().width();}
|
||||
void setWidth(const qreal w);
|
||||
// vertical diameter
|
||||
Q_PROPERTY(qreal diameter_v READ height WRITE setHeight)
|
||||
qreal height() const {return rect().height();}
|
||||
void setHeight (const qreal h);
|
||||
// start angle
|
||||
Q_PROPERTY(int start_angle READ startAngle WRITE setStartAngle)
|
||||
int startAngle() const {return start_angle;}
|
||||
void setStartAngle(const int sa){start_angle = sa;}
|
||||
// angle value
|
||||
Q_PROPERTY(int angle READ angle WRITE setAngle)
|
||||
int angle() const {return _angle;}
|
||||
void setAngle(const int a) {_angle = a;}
|
||||
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
|
||||
private:
|
||||
QList<QPointF> saved_points_;
|
||||
};
|
||||
#endif
|
||||
205
sources/editor/graphicspart/partellipse.cpp
Normal file
205
sources/editor/graphicspart/partellipse.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "partellipse.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param editor L'editeur d'element concerne
|
||||
@param parent Le QGraphicsItem parent de cette ellipse
|
||||
@param scene La scene sur laquelle figure cette ellipse
|
||||
*/
|
||||
PartEllipse::PartEllipse(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : CustomElementGraphicPart(editor), QGraphicsEllipseItem(parent, scene) {
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptedMouseButtons(Qt::LeftButton);
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
PartEllipse::~PartEllipse() {
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine l'ellipse
|
||||
@param painter QPainter a utiliser pour rendre le dessin
|
||||
@param options Options pour affiner le rendu
|
||||
@param widget Widget sur lequel le rendu est effectue
|
||||
*/
|
||||
void PartEllipse::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
|
||||
Q_UNUSED(widget);
|
||||
applyStylesToQPainter(*painter);
|
||||
QPen t = painter -> pen();
|
||||
t.setCosmetic(options && options -> levelOfDetail < 1.0);
|
||||
if (isSelected()) {
|
||||
t.setColor(Qt::red);
|
||||
}
|
||||
painter -> setPen(t);
|
||||
painter -> drawEllipse(rect());
|
||||
if (isSelected()) {
|
||||
painter -> setRenderHint(QPainter::Antialiasing, false);
|
||||
painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
|
||||
QPointF center = rect().center();
|
||||
painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
|
||||
painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte l'ellipse en XML
|
||||
@param xml_document Document XML a utiliser pour creer l'element XML
|
||||
@return un element XML decrivant l'ellipse
|
||||
*/
|
||||
const QDomElement PartEllipse::toXml(QDomDocument &xml_document) const {
|
||||
QDomElement xml_element;
|
||||
if (qFuzzyCompare(rect().width(), rect().height())) {
|
||||
xml_element = xml_document.createElement("circle");
|
||||
xml_element.setAttribute("diameter", QString("%1").arg(rect().width()));
|
||||
} else {
|
||||
xml_element = xml_document.createElement("ellipse");
|
||||
xml_element.setAttribute("width", QString("%1").arg(rect().width()));
|
||||
xml_element.setAttribute("height", QString("%1").arg(rect().height()));
|
||||
}
|
||||
QPointF top_left(sceneTopLeft());
|
||||
xml_element.setAttribute("x", QString("%1").arg(top_left.x()));
|
||||
xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
|
||||
stylesToXml(xml_element);
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
/**
|
||||
Importe les proprietes d'une ellipse depuis un element XML
|
||||
@param qde Element XML a lire
|
||||
*/
|
||||
void PartEllipse::fromXml(const QDomElement &qde) {
|
||||
stylesFromXml(qde);
|
||||
qreal width, height;
|
||||
if (qde.tagName() == "ellipse") {
|
||||
width = qde.attribute("width", "0").toDouble();
|
||||
height = qde.attribute("height", "0").toDouble();
|
||||
} else {
|
||||
width = height = qde.attribute("diameter", "0").toDouble();
|
||||
}
|
||||
setRect(
|
||||
QRectF(
|
||||
mapFromScene(
|
||||
qde.attribute("x", "0").toDouble(),
|
||||
qde.attribute("y", "0").toDouble()
|
||||
),
|
||||
QSizeF(width, height)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void PartEllipse::setX(const qreal x) {
|
||||
QRectF current_rect = rect();
|
||||
QPointF current_pos = mapToScene(current_rect.center());
|
||||
setRect(current_rect.translated(x - current_pos.x(), 0.0));
|
||||
}
|
||||
|
||||
void PartEllipse::setY(const qreal y) {
|
||||
QRectF current_rect = rect();
|
||||
QPointF current_pos = mapToScene(current_rect.center());
|
||||
setRect(current_rect.translated(0.0, y - current_pos.y()));
|
||||
}
|
||||
|
||||
void PartEllipse::setWidth(const qreal w) {
|
||||
qreal new_width = qAbs(w);
|
||||
QRectF current_rect = rect();
|
||||
current_rect.translate((new_width - current_rect.width()) / -2.0, 0.0);
|
||||
current_rect.setWidth(new_width);
|
||||
setRect(current_rect);
|
||||
}
|
||||
|
||||
void PartEllipse::setHeight(const qreal h) {
|
||||
qreal new_height = qAbs(h);
|
||||
QRectF current_rect = rect();
|
||||
current_rect.translate(0.0, (new_height - current_rect.height()) / -2.0);
|
||||
current_rect.setHeight(new_height);
|
||||
setRect(current_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les changements intervenant sur cette partie
|
||||
@param change Type de changement
|
||||
@param value Valeur numerique relative au changement
|
||||
*/
|
||||
QVariant PartEllipse::itemChange(GraphicsItemChange change, const QVariant &value) {
|
||||
if (scene()) {
|
||||
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
|
||||
updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
return(QGraphicsEllipseItem::itemChange(change, value));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le coin superieur gauche du rectangle dans lequel s'inscrit
|
||||
l'ellipse, dans les coordonnees de la scene.
|
||||
*/
|
||||
QPointF PartEllipse::sceneTopLeft() const {
|
||||
return(mapToScene(rect().topLeft()));
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
|
||||
conservee / enregistree.
|
||||
Une ellipse est pertinente des lors que ses dimensions ne sont pas nulles
|
||||
*/
|
||||
bool PartEllipse::isUseless() const {
|
||||
return(rect().isNull());
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates. It is different from boundingRect() because it is not supposed
|
||||
to imply any margin, and it is different from shape because it is a regular
|
||||
rectangle, not a complex shape.
|
||||
*/
|
||||
QRectF PartEllipse::sceneGeometricRect() const {
|
||||
return(mapToScene(rect()).boundingRect());
|
||||
}
|
||||
|
||||
/**
|
||||
Start the user-induced transformation, provided this primitive is contained
|
||||
within the \a initial_selection_rect bounding rectangle.
|
||||
*/
|
||||
void PartEllipse::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
// we keep track of our own rectangle at the moment in scene coordinates too
|
||||
saved_points_.clear();
|
||||
saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight());
|
||||
}
|
||||
|
||||
/**
|
||||
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
|
||||
*/
|
||||
void PartEllipse::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
|
||||
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
|
||||
setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle delimitant cette partie.
|
||||
*/
|
||||
QRectF PartEllipse::boundingRect() const {
|
||||
qreal adjust = 1.5;
|
||||
QRectF r(QGraphicsEllipseItem::boundingRect().normalized());
|
||||
r.adjust(-adjust, -adjust, adjust, adjust);
|
||||
return(r);
|
||||
}
|
||||
81
sources/editor/graphicspart/partellipse.h
Normal file
81
sources/editor/graphicspart/partellipse.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PART_ELLIPSE_H
|
||||
#define PART_ELLIPSE_H
|
||||
#include <QtGui>
|
||||
#include "customelementgraphicpart.h"
|
||||
/**
|
||||
This class represents an ellipse primitive which may be used to compose the
|
||||
drawing of an electrical element within the element editor.
|
||||
*/
|
||||
class PartEllipse : public CustomElementGraphicPart, public QGraphicsEllipseItem {
|
||||
Q_OBJECT
|
||||
// constructors, destructor
|
||||
public:
|
||||
PartEllipse(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
|
||||
virtual ~PartEllipse();
|
||||
|
||||
private:
|
||||
PartEllipse(const PartEllipse &);
|
||||
|
||||
// methods
|
||||
public:
|
||||
enum { Type = UserType + 1103 };
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
PartEllipse.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
|
||||
virtual QString name() const { return(QObject::tr("ellipse", "element part name")); }
|
||||
virtual QString xmlName() const { return(QString("ellipse")); }
|
||||
virtual const QDomElement toXml(QDomDocument &) const;
|
||||
virtual void fromXml(const QDomElement &);
|
||||
virtual QPointF sceneTopLeft() const;
|
||||
virtual QRectF boundingRect() const;
|
||||
virtual bool isUseless() const;
|
||||
virtual QRectF sceneGeometricRect() const;
|
||||
virtual void startUserTransformation(const QRectF &);
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||
|
||||
///PROPERTY
|
||||
// X value
|
||||
Q_PROPERTY(qreal x READ x WRITE setX)
|
||||
qreal x() const {return mapToScene(rect().center()).x() ;}
|
||||
void setX(const qreal x);
|
||||
// Y value
|
||||
Q_PROPERTY(qreal y READ y WRITE setY)
|
||||
qreal y() const {return mapToScene(rect().center()).y();}
|
||||
void setY(const qreal y);
|
||||
// horizontal diameter
|
||||
Q_PROPERTY(qreal diameter_h READ width WRITE setWidth)
|
||||
qreal width() const {return rect().width();}
|
||||
void setWidth(const qreal w);
|
||||
// vertical diameter
|
||||
Q_PROPERTY(qreal diameter_v READ height WRITE setHeight)
|
||||
qreal height() const {return rect().height();}
|
||||
void setHeight (const qreal h);
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
|
||||
private:
|
||||
QList<QPointF> saved_points_;
|
||||
};
|
||||
#endif
|
||||
523
sources/editor/graphicspart/partline.cpp
Normal file
523
sources/editor/graphicspart/partline.cpp
Normal file
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "partline.h"
|
||||
#include <cmath>
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param editor L'editeur d'element concerne
|
||||
@param parent Le QGraphicsItem parent de cette ligne
|
||||
@param scene La scene sur laquelle figure cette ligne
|
||||
*/
|
||||
PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
|
||||
CustomElementGraphicPart(editor),
|
||||
QGraphicsLineItem(parent, scene),
|
||||
first_end(Qet::None),
|
||||
first_length(1.5),
|
||||
second_end(Qet::None),
|
||||
second_length(1.5)
|
||||
{
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptedMouseButtons(Qt::LeftButton);
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
PartLine::~PartLine() {
|
||||
}
|
||||
|
||||
/**
|
||||
@param end_type Type d'extremite
|
||||
@return Le nombre de "longueurs" requises pour dessiner une extremite de type end_type
|
||||
*/
|
||||
uint PartLine::requiredLengthForEndType(const Qet::EndType &end_type) {
|
||||
uint length_count_required = 0;
|
||||
if (end_type == Qet::Circle || end_type == Qet::Diamond) {
|
||||
length_count_required = 2;
|
||||
} else if (end_type == Qet::Simple || end_type == Qet::Triangle) {
|
||||
length_count_required = 1;
|
||||
}
|
||||
return(length_count_required);
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine la ligne
|
||||
@param painter QPainter a utiliser pour rendre le dessin
|
||||
@param options Options pour affiner le rendu
|
||||
@param widget Widget sur lequel le rendu est effectue
|
||||
*/
|
||||
void PartLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
|
||||
Q_UNUSED(widget);
|
||||
// inutile de dessiner une ligne nulle
|
||||
if (line().p1() == line().p2()) return;
|
||||
applyStylesToQPainter(*painter);
|
||||
QPen t = painter -> pen();
|
||||
t.setJoinStyle(Qt::MiterJoin);
|
||||
t.setCosmetic(options && options -> levelOfDetail < 1.0);
|
||||
if (isSelected()) {
|
||||
t.setColor(Qt::red);
|
||||
}
|
||||
painter -> setPen(t);
|
||||
|
||||
QPointF point1(line().p1());
|
||||
QPointF point2(line().p2());
|
||||
|
||||
qreal line_length(line().length());
|
||||
qreal pen_width = painter -> pen().widthF();
|
||||
|
||||
qreal length1 = first_length;
|
||||
qreal length2 = second_length;
|
||||
|
||||
//debugPaint(painter);
|
||||
|
||||
// determine s'il faut dessiner les extremites
|
||||
bool draw_1st_end, draw_2nd_end;
|
||||
qreal reduced_line_length = line_length - (length1 * requiredLengthForEndType(first_end));
|
||||
draw_1st_end = first_end && reduced_line_length >= 0;
|
||||
if (draw_1st_end) {
|
||||
reduced_line_length -= (length2 * requiredLengthForEndType(second_end));
|
||||
} else {
|
||||
reduced_line_length = line_length - (length2 * requiredLengthForEndType(second_end));
|
||||
}
|
||||
draw_2nd_end = second_end && reduced_line_length >= 0;
|
||||
|
||||
// dessine la premiere extremite
|
||||
QPointF start_point, stop_point;
|
||||
if (draw_1st_end) {
|
||||
QList<QPointF> four_points1(fourEndPoints(point1, point2, length1));
|
||||
if (first_end == Qet::Circle) {
|
||||
painter -> drawEllipse(QRectF(four_points1[0] - QPointF(length1, length1), QSizeF(length1 * 2.0, length1 * 2.0)));
|
||||
start_point = four_points1[1];
|
||||
} else if (first_end == Qet::Diamond) {
|
||||
painter -> drawPolygon(QPolygonF() << four_points1[1] << four_points1[2] << point1 << four_points1[3]);
|
||||
start_point = four_points1[1];
|
||||
} else if (first_end == Qet::Simple) {
|
||||
painter -> drawPolyline(QPolygonF() << four_points1[3] << point1 << four_points1[2]);
|
||||
start_point = point1;
|
||||
|
||||
} else if (first_end == Qet::Triangle) {
|
||||
painter -> drawPolygon(QPolygonF() << four_points1[0] << four_points1[2] << point1 << four_points1[3]);
|
||||
start_point = four_points1[0];
|
||||
}
|
||||
|
||||
// ajuste le depart selon l'epaisseur du trait
|
||||
if (pen_width && (first_end == Qet::Simple || first_end == Qet::Circle)) {
|
||||
start_point = QLineF(start_point, point2).pointAt(pen_width / 2.0 / line_length);
|
||||
}
|
||||
} else {
|
||||
start_point = point1;
|
||||
}
|
||||
|
||||
// dessine la seconde extremite
|
||||
if (draw_2nd_end) {
|
||||
QList<QPointF> four_points2(fourEndPoints(point2, point1, length2));
|
||||
if (second_end == Qet::Circle) {
|
||||
painter -> drawEllipse(QRectF(four_points2[0] - QPointF(length2, length2), QSizeF(length2 * 2.0, length2 * 2.0)));
|
||||
stop_point = four_points2[1];
|
||||
} else if (second_end == Qet::Diamond) {
|
||||
painter -> drawPolygon(QPolygonF() << four_points2[2] << point2 << four_points2[3] << four_points2[1]);
|
||||
stop_point = four_points2[1];
|
||||
} else if (second_end == Qet::Simple) {
|
||||
painter -> drawPolyline(QPolygonF() << four_points2[3] << point2 << four_points2[2]);
|
||||
stop_point = point2;
|
||||
} else if (second_end == Qet::Triangle) {
|
||||
painter -> drawPolygon(QPolygonF() << four_points2[0] << four_points2[2] << point2 << four_points2[3] << four_points2[0]);
|
||||
stop_point = four_points2[0];
|
||||
}
|
||||
|
||||
// ajuste l'arrivee selon l'epaisseur du trait
|
||||
if (pen_width && (second_end == Qet::Simple || second_end == Qet::Circle)) {
|
||||
stop_point = QLineF(point1, stop_point).pointAt((line_length - (pen_width / 2.0)) / line_length);
|
||||
}
|
||||
} else {
|
||||
stop_point = point2;
|
||||
}
|
||||
|
||||
painter -> drawLine(start_point, stop_point);
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte la ligne en XML
|
||||
@param xml_document Document XML a utiliser pour creer l'element XML
|
||||
@return un element XML decrivant la ligne
|
||||
*/
|
||||
const QDomElement PartLine::toXml(QDomDocument &xml_document) const {
|
||||
|
||||
QPointF p1(sceneP1());
|
||||
QPointF p2(sceneP2());
|
||||
|
||||
QDomElement xml_element = xml_document.createElement("line");
|
||||
xml_element.setAttribute("x1", QString("%1").arg(p1.x()));
|
||||
xml_element.setAttribute("y1", QString("%1").arg(p1.y()));
|
||||
xml_element.setAttribute("x2", QString("%1").arg(p2.x()));
|
||||
xml_element.setAttribute("y2", QString("%1").arg(p2.y()));
|
||||
xml_element.setAttribute("end1", Qet::endTypeToString(first_end));
|
||||
xml_element.setAttribute("length1", QString("%1").arg(first_length));
|
||||
xml_element.setAttribute("end2", Qet::endTypeToString(second_end));
|
||||
xml_element.setAttribute("length2", QString("%1").arg(second_length));
|
||||
|
||||
stylesToXml(xml_element);
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
/**
|
||||
Importe les proprietes d'une ligne depuis un element XML
|
||||
@param qde Element XML a lire
|
||||
*/
|
||||
void PartLine::fromXml(const QDomElement &qde) {
|
||||
stylesFromXml(qde);
|
||||
setLine(
|
||||
QLineF(
|
||||
mapFromScene(
|
||||
qde.attribute("x1", "0").toDouble(),
|
||||
qde.attribute("y1", "0").toDouble()
|
||||
),
|
||||
mapFromScene(
|
||||
qde.attribute("x2", "0").toDouble(),
|
||||
qde.attribute("y2", "0").toDouble()
|
||||
)
|
||||
)
|
||||
);
|
||||
first_end = Qet::endTypeFromString(qde.attribute("end1"));
|
||||
first_length = qde.attribute("length1", "1.5").toDouble();
|
||||
second_end = Qet::endTypeFromString(qde.attribute("end2"));
|
||||
second_length = qde.attribute("length2", "1.5").toDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartLine::setX1
|
||||
* set X of P1
|
||||
* @param x1
|
||||
*/
|
||||
void PartLine::setX1(qreal x1) {
|
||||
QPointF p = line().p1();
|
||||
p.setX(x1);
|
||||
setLine(QLineF(p, line().p2()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartLine::setY1
|
||||
* set y of P1
|
||||
* @param y1
|
||||
*/
|
||||
void PartLine::setY1(qreal y1) {
|
||||
QPointF p = line().p1();
|
||||
p.setY(y1);
|
||||
setLine(QLineF(p, line().p2()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartLine::setP1
|
||||
* set first point to P1
|
||||
* @param p1
|
||||
*/
|
||||
void PartLine::setP1(QPointF p1) {
|
||||
setLine(QLineF(p1, line().p2()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartLine::setX2
|
||||
* set x of P2
|
||||
* @param x2
|
||||
*/
|
||||
void PartLine::setX2(qreal x2) {
|
||||
QPointF p = line().p2();
|
||||
p.setX(x2);
|
||||
setLine(QLineF(line().p1(), p));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartLine::setY2
|
||||
* set y of P2
|
||||
* @param y2
|
||||
*/
|
||||
void PartLine::setY2(qreal y2) {
|
||||
QPointF p = line().p2();
|
||||
p.setY(y2);
|
||||
setLine(QLineF(line().p1(), p));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartLine::setP2
|
||||
* set second point to P2
|
||||
* @param p2
|
||||
*/
|
||||
void PartLine::setP2(QPointF p2) {
|
||||
setLine(QLineF(line().p1(), p2));
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les changements intervenant sur cette partie
|
||||
@param change Type de changement
|
||||
@param value Valeur numerique relative au changement
|
||||
*/
|
||||
QVariant PartLine::itemChange(GraphicsItemChange change, const QVariant &value) {
|
||||
if (scene()) {
|
||||
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
|
||||
updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
return(QGraphicsLineItem::itemChange(change, value));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le premier point, dans les coordonnees de la scene.
|
||||
*/
|
||||
QPointF PartLine::sceneP1() const {
|
||||
return(mapToScene(line().p1()));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le second point, dans les coordonnees de la scene.
|
||||
*/
|
||||
QPointF PartLine::sceneP2() const {
|
||||
return(mapToScene(line().p2()));
|
||||
}
|
||||
|
||||
/**
|
||||
@return la forme selectionnable de la ligne
|
||||
*/
|
||||
QPainterPath PartLine::shape() const {
|
||||
QList<QPointF> points = fourShapePoints();
|
||||
QPainterPath t;
|
||||
t.setFillRule(Qt::WindingFill);
|
||||
t.moveTo(points.at(0));
|
||||
t.lineTo(points.at(1));
|
||||
t.lineTo(points.at(2));
|
||||
t.lineTo(points.at(3));
|
||||
t.lineTo(points.at(0));
|
||||
|
||||
// n'en fait pas plus si la ligne se ramene a un point
|
||||
if (line().p1() == line().p2()) return(t);
|
||||
|
||||
// ajoute un cercle pour l'extremite 1 si besoin
|
||||
if (first_end) {
|
||||
QPainterPath t2;
|
||||
t2.addEllipse(firstEndCircleRect());
|
||||
t.addPath(t2.subtracted(t));
|
||||
}
|
||||
|
||||
// ajoute un cercle pour l'extremite 2 si besoin
|
||||
if (second_end) {
|
||||
QPainterPath t2;
|
||||
t2.addEllipse(secondEndCircleRect());
|
||||
t.addPath(t2.subtracted(t));
|
||||
}
|
||||
|
||||
return(t);
|
||||
}
|
||||
|
||||
/**
|
||||
@return une liste contenant les deux points de la droite + les 4 points entourant ces deux points
|
||||
*/
|
||||
QList<QPointF> PartLine::fourShapePoints() const {
|
||||
const qreal marge = 2.0;
|
||||
// on a donc A(xa , ya) et B(xb, yb)
|
||||
QPointF a = line().p1();
|
||||
QPointF b = line().p2();
|
||||
|
||||
QList<QPointF> result;
|
||||
|
||||
// cas particulier : la droite se ramene a un point
|
||||
if (a == b) {
|
||||
result << QPointF(a.x() - marge, a.y() - marge);
|
||||
result << QPointF(a.x() - marge, a.y() + marge);
|
||||
result << QPointF(a.x() + marge, a.y() + marge);
|
||||
result << QPointF(a.x() + marge, a.y() - marge);
|
||||
} else {
|
||||
|
||||
// on calcule le vecteur AB : (xb-xa, yb-ya)
|
||||
QPointF v_ab = b - a;
|
||||
|
||||
// et la distance AB : racine des coordonnees du vecteur au carre
|
||||
qreal ab = sqrt(pow(v_ab.x(), 2) + pow(v_ab.y(), 2));
|
||||
|
||||
// ensuite on definit le vecteur u(a, b) qui est egal au vecteur AB divise
|
||||
// par sa longueur et multiplie par la longueur de la marge que tu veux
|
||||
// laisser
|
||||
QPointF u = v_ab / ab * marge;
|
||||
|
||||
// on definit le vecteur v(-b , a) qui est perpendiculaire a AB
|
||||
QPointF v(-u.y(), u.x());
|
||||
QPointF m = -u + v; // on a le vecteur M = -u + v
|
||||
QPointF n = -u - v; // et le vecteur N=-u-v
|
||||
QPointF h = a + m; // H = A + M
|
||||
QPointF k = a + n; // K = A + N
|
||||
QPointF i = b - n; // I = B - N
|
||||
QPointF j = b - m; // J = B - M
|
||||
|
||||
result << h << i << j << k;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle encadrant l'integralite de la premiere extremite
|
||||
*/
|
||||
QRectF PartLine::firstEndCircleRect() const {
|
||||
QList<QPointF> interesting_points = fourEndPoints(
|
||||
line().p1(),
|
||||
line().p2(),
|
||||
first_length
|
||||
);
|
||||
|
||||
QRectF end_rect(
|
||||
interesting_points[0] - QPointF(first_length, first_length),
|
||||
QSizeF(2.0 * first_length, 2.0 * first_length)
|
||||
);
|
||||
|
||||
return(end_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle encadrant l'integralite de la seconde extremite
|
||||
*/
|
||||
QRectF PartLine::secondEndCircleRect() const {
|
||||
QList<QPointF> interesting_points = fourEndPoints(
|
||||
line().p2(),
|
||||
line().p1(),
|
||||
second_length
|
||||
);
|
||||
|
||||
QRectF end_rect(
|
||||
interesting_points[0] - QPointF(second_length, second_length),
|
||||
QSizeF(2.0 * second_length, 2.0 * second_length)
|
||||
);
|
||||
|
||||
return(end_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
Affiche differentes composantes du dessin :
|
||||
- le boundingRect
|
||||
- les point speciaux a chaque extremite
|
||||
- la quadrature du cercle a chaque extremite, meme si celle-ci est d'un
|
||||
autre type
|
||||
*/
|
||||
void PartLine::debugPaint(QPainter *painter) {
|
||||
painter -> save();
|
||||
painter -> setPen(Qt::gray);
|
||||
painter -> drawRect(boundingRect());
|
||||
|
||||
painter -> setPen(Qt::green);
|
||||
painter -> drawRect(firstEndCircleRect());
|
||||
painter -> drawRect(secondEndCircleRect());
|
||||
|
||||
painter -> setPen(Qt::red);
|
||||
foreach(QPointF pointy, fourEndPoints(line().p1(), line().p2(), first_length)) {
|
||||
painter -> drawEllipse(pointy, 0.1, 0.1);
|
||||
}
|
||||
foreach(QPointF pointy, fourEndPoints(line().p2(), line().p1(), second_length)) {
|
||||
painter -> drawEllipse(pointy, 0.1, 0.1);
|
||||
}
|
||||
|
||||
painter -> restore();
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle delimitant cette partie.
|
||||
*/
|
||||
QRectF PartLine::boundingRect() const {
|
||||
QRectF r(QGraphicsLineItem::boundingRect());
|
||||
|
||||
// le rectangle ainsi obtenu ne doit pas avoir une dimension nulle
|
||||
r.adjust(0.0, 0.0, 0.1, 0.1);
|
||||
|
||||
// cas special : les embouts sortent largement du bounding rect originel
|
||||
if (first_end != Qet::None) {
|
||||
r = r.united(firstEndCircleRect());
|
||||
}
|
||||
|
||||
if (second_end != Qet::None) {
|
||||
r = r.united(secondEndCircleRect());
|
||||
}
|
||||
|
||||
// la taille du bounding rect est ajustee avec une certaine marge
|
||||
qreal adjust = 1.2;
|
||||
r.adjust(-adjust, -adjust, adjust, adjust);
|
||||
return(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
|
||||
conservee / enregistree.
|
||||
Une ligne est pertinente des lors que ses deux points sont differents
|
||||
*/
|
||||
bool PartLine::isUseless() const {
|
||||
return(sceneP1() == sceneP2());
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates. It is different from boundingRect() because it is not supposed
|
||||
to imply any margin, and it is different from shape because it is a regular
|
||||
rectangle, not a complex shape.
|
||||
*/
|
||||
QRectF PartLine::sceneGeometricRect() const {
|
||||
return(QRectF(sceneP1(), sceneP2()));
|
||||
}
|
||||
|
||||
/**
|
||||
Start the user-induced transformation, provided this primitive is contained
|
||||
within the \a initial_selection_rect bounding rectangle.
|
||||
*/
|
||||
void PartLine::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
saved_points_.clear();
|
||||
saved_points_ << sceneP1() << sceneP2();
|
||||
}
|
||||
|
||||
/**
|
||||
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
|
||||
*/
|
||||
void PartLine::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
|
||||
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
|
||||
setLine(QLineF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
|
||||
}
|
||||
|
||||
/**
|
||||
@return Les quatre points interessants a l'extremite d'une droite
|
||||
Ces points sont, dans l'ordre :
|
||||
* O : point sur la ligne, a une distance length de l'extremite
|
||||
* A : point sur la ligne a une distance 2 x length de l'extremite
|
||||
* B : point a une distance length de O - O est le projete de B sur la droite
|
||||
* C : point a une distance length de O - O est le projete de C sur la droite
|
||||
B et C sont situes de part et d'autre de la ligne
|
||||
@param end_point Extremite concernee
|
||||
@param other_point Autre point permettant de definir une ligne
|
||||
@param length Longueur a utiliser entre l'extremite et le point O
|
||||
*/
|
||||
QList<QPointF> PartLine::fourEndPoints(const QPointF &end_point, const QPointF &other_point, const qreal &length) {
|
||||
// vecteur et longueur de la ligne
|
||||
QPointF line_vector = end_point - other_point;
|
||||
qreal line_length = sqrt(pow(line_vector.x(), 2) + pow(line_vector.y(), 2));
|
||||
|
||||
// vecteur unitaire et vecteur perpendiculaire
|
||||
QPointF u(line_vector / line_length * length);
|
||||
QPointF v(-u.y(), u.x());
|
||||
|
||||
// points O, A, B et C
|
||||
QPointF o(end_point - u);
|
||||
QPointF a(o - u);
|
||||
QPointF b(o + v);
|
||||
QPointF c(o - v);
|
||||
|
||||
return(QList<QPointF>() << o << a << b << c);
|
||||
}
|
||||
135
sources/editor/graphicspart/partline.h
Normal file
135
sources/editor/graphicspart/partline.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PART_LINE_H
|
||||
#define PART_LINE_H
|
||||
#include <QtGui>
|
||||
#include "customelementgraphicpart.h"
|
||||
#include "qet.h"
|
||||
/**
|
||||
This class represents a line primitive which may be used to compose the
|
||||
drawing of an electrical element within the element editor. Lines may have
|
||||
specific visual ends (e.g. arrows) through the setFirstEndType and
|
||||
setSecondEndType methods. Their size can be defined using the
|
||||
setFirstEndLength and setSecondEndLength methods. Please note ends are not
|
||||
drawn if the required length for their drawing is longer than the line itself.
|
||||
In case there is room for a single end only, the first one get priority.
|
||||
*/
|
||||
class PartLine : public CustomElementGraphicPart, public QGraphicsLineItem {
|
||||
Q_OBJECT
|
||||
// constructors, destructor
|
||||
public:
|
||||
PartLine(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
|
||||
virtual ~PartLine();
|
||||
|
||||
private:
|
||||
PartLine(const PartLine &);
|
||||
|
||||
// attributes
|
||||
private:
|
||||
Qet::EndType first_end;
|
||||
qreal first_length;
|
||||
Qet::EndType second_end;
|
||||
qreal second_length;
|
||||
QList<QPointF> saved_points_;
|
||||
|
||||
// methods
|
||||
public:
|
||||
enum { Type = UserType + 1104 };
|
||||
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
PartLine.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
|
||||
virtual QString name() const { return(QObject::tr("ligne", "element part name")); }
|
||||
virtual QString xmlName() const { return(QString("line")); }
|
||||
virtual const QDomElement toXml(QDomDocument &) const;
|
||||
virtual void fromXml(const QDomElement &);
|
||||
virtual QPointF sceneP1() const;
|
||||
virtual QPointF sceneP2() const;
|
||||
virtual QPainterPath shape() const;
|
||||
virtual QRectF boundingRect() const;
|
||||
virtual bool isUseless() const;
|
||||
virtual QRectF sceneGeometricRect() const;
|
||||
virtual void startUserTransformation(const QRectF &);
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||
static uint requiredLengthForEndType(const Qet::EndType &);
|
||||
static QList<QPointF> fourEndPoints(const QPointF &, const QPointF &, const qreal &);
|
||||
|
||||
///PROPERTY
|
||||
// X value of the first point
|
||||
Q_PROPERTY(qreal x1 READ x1 WRITE setX1)
|
||||
qreal x1() const {return sceneP1().x();}
|
||||
void setX1(qreal x1);
|
||||
|
||||
// Y value of the first point
|
||||
Q_PROPERTY(qreal y1 READ y1 WRITE setY1)
|
||||
qreal y1() const {return sceneP1().y();}
|
||||
void setY1(qreal y1);
|
||||
|
||||
//pos of firts point
|
||||
Q_PROPERTY(QPointF p1 READ sceneP1 WRITE setP1)
|
||||
void setP1 (QPointF p1);
|
||||
|
||||
// X value of the second point
|
||||
Q_PROPERTY(qreal x2 READ x2 WRITE setX2)
|
||||
qreal x2() const {return sceneP2().x();}
|
||||
void setX2(qreal x2);
|
||||
|
||||
// Y value of the second point
|
||||
Q_PROPERTY(qreal y2 READ y2 WRITE setY2)
|
||||
qreal y2() const {return sceneP2().y();}
|
||||
void setY2(qreal y2);
|
||||
|
||||
//pos of second point
|
||||
Q_PROPERTY(QPointF p2 READ sceneP2 WRITE setP2)
|
||||
void setP2 (QPointF p2);
|
||||
|
||||
// End type of the first point
|
||||
Q_PROPERTY(Qet::EndType end1 READ firstEndType WRITE setFirstEndType)
|
||||
Qet::EndType firstEndType() const {return first_end;}
|
||||
void setFirstEndType(const Qet::EndType &et) {first_end = et;}
|
||||
|
||||
// End type of the second point
|
||||
Q_PROPERTY(Qet::EndType end2 READ secondEndType WRITE setSecondEndType)
|
||||
Qet::EndType secondEndType() const {return second_end;}
|
||||
void setSecondEndType(const Qet::EndType &et) {second_end = et;}
|
||||
|
||||
// Size of end type of first point
|
||||
Q_PROPERTY(qreal length1 READ firstEndLength WRITE setFirstEndLength)
|
||||
qreal firstEndLength() const {return first_length;}
|
||||
void setFirstEndLength(const qreal &l) {first_length = qMin(qAbs(l), line().length());}
|
||||
|
||||
// Size of end type of the second point
|
||||
Q_PROPERTY(qreal length2 READ secondEndLength WRITE setSecondEndLength)
|
||||
qreal secondEndLength() const {return second_length;}
|
||||
void setSecondEndLength(const qreal &l) {second_length = qMin(qAbs(l), line().length());}
|
||||
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
|
||||
private:
|
||||
QList<QPointF> fourShapePoints() const;
|
||||
QRectF firstEndCircleRect() const;
|
||||
QRectF secondEndCircleRect() const;
|
||||
void debugPaint(QPainter *);
|
||||
};
|
||||
#endif
|
||||
223
sources/editor/graphicspart/partpolygon.cpp
Normal file
223
sources/editor/graphicspart/partpolygon.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "partpolygon.h"
|
||||
#include "qet.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param editor L'editeur d'element concerne
|
||||
@param parent Le QGraphicsItem parent de ce polygone
|
||||
@param scene La scene sur laquelle figure ce polygone
|
||||
*/
|
||||
PartPolygon::PartPolygon(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
|
||||
CustomElementGraphicPart(editor),
|
||||
QGraphicsPolygonItem(parent, scene),
|
||||
m_closed(false)
|
||||
{
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptedMouseButtons(Qt::LeftButton);
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
PartPolygon::~PartPolygon() {
|
||||
}
|
||||
|
||||
/**
|
||||
Importe les proprietes d'un polygone depuis un element XML
|
||||
@param qde Element XML a lire
|
||||
*/
|
||||
void PartPolygon::fromXml(const QDomElement &qde) {
|
||||
stylesFromXml(qde);
|
||||
int i = 1;
|
||||
while(true) {
|
||||
if (
|
||||
QET::attributeIsAReal(qde, QString("x%1").arg(i)) &&\
|
||||
QET::attributeIsAReal(qde, QString("y%1").arg(i))
|
||||
) ++ i;
|
||||
else break;
|
||||
}
|
||||
|
||||
QPolygonF temp_polygon;
|
||||
for (int j = 1 ; j < i ; ++ j) {
|
||||
temp_polygon << QPointF(
|
||||
qde.attribute(QString("x%1").arg(j)).toDouble(),
|
||||
qde.attribute(QString("y%1").arg(j)).toDouble()
|
||||
);
|
||||
}
|
||||
setPolygon(temp_polygon);
|
||||
|
||||
m_closed = qde.attribute("closed") != "false";
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte le polygone en XML
|
||||
@param xml_document Document XML a utiliser pour creer l'element XML
|
||||
@return un element XML decrivant le polygone
|
||||
*/
|
||||
const QDomElement PartPolygon::toXml(QDomDocument &xml_document) const {
|
||||
QDomElement xml_element = xml_document.createElement("polygon");
|
||||
int i = 1;
|
||||
foreach(QPointF point, polygon()) {
|
||||
point = mapToScene(point);
|
||||
xml_element.setAttribute(QString("x%1").arg(i), QString("%1").arg(point.x()));
|
||||
xml_element.setAttribute(QString("y%1").arg(i), QString("%1").arg(point.y()));
|
||||
++ i;
|
||||
}
|
||||
if (!m_closed) xml_element.setAttribute("closed", "false");
|
||||
stylesToXml(xml_element);
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine le polygone
|
||||
@param painter QPainter a utiliser pour rendre le dessin
|
||||
@param options Options pour affiner le rendu
|
||||
@param widget Widget sur lequel le rendu est effectue
|
||||
*/
|
||||
void PartPolygon::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
|
||||
Q_UNUSED(widget);
|
||||
applyStylesToQPainter(*painter);
|
||||
QPen t = painter -> pen();
|
||||
t.setCosmetic(options && options -> levelOfDetail < 1.0);
|
||||
if (isSelected()) t.setColor(Qt::red);
|
||||
painter -> setPen(t);
|
||||
if (m_closed) painter -> drawPolygon(polygon());
|
||||
else painter -> drawPolyline(polygon());
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les changements intervenant sur cette partie
|
||||
@param change Type de changement
|
||||
@param value Valeur numerique relative au changement
|
||||
*/
|
||||
QVariant PartPolygon::itemChange(GraphicsItemChange change, const QVariant &value) {
|
||||
if (scene()) {
|
||||
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
|
||||
updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
return(QGraphicsPolygonItem::itemChange(change, value));
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
|
||||
conservee / enregistree.
|
||||
Un polygone est pertinent des lors qu'il possede deux points differents.
|
||||
*/
|
||||
bool PartPolygon::isUseless() const {
|
||||
QPolygonF poly(polygon());
|
||||
|
||||
if (polygon().count() < 2) return(true);
|
||||
|
||||
QPointF previous_point;
|
||||
for (int i = 1 ; i < poly.count() ; ++ i) {
|
||||
if (poly[i] != poly[i-1]) return(false);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates. It is different from boundingRect() because it is not supposed
|
||||
to imply any margin, and it is different from shape because it is a regular
|
||||
rectangle, not a complex shape.
|
||||
*/
|
||||
QRectF PartPolygon::sceneGeometricRect() const {
|
||||
return(mapToScene(polygon().boundingRect()).boundingRect());
|
||||
}
|
||||
|
||||
/**
|
||||
Start the user-induced transformation, provided this primitive is contained
|
||||
within the \a initial_selection_rect bounding rectangle.
|
||||
*/
|
||||
void PartPolygon::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
saved_points_ = mapToScene(polygon()).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
|
||||
*/
|
||||
void PartPolygon::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
|
||||
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
|
||||
setPolygon(mapFromScene(QPolygonF(mapped_points.toVector())));
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp CustomElementPart::preferredScalingMethod
|
||||
This method is called by the decorator when it needs to determine the best
|
||||
way to interactively scale a primitive. It is typically called when only a
|
||||
single primitive is being scaled.
|
||||
This reimplementation systematically returns QET::RoundScaleRatios.
|
||||
*/
|
||||
QET::ScalingMethod PartPolygon::preferredScalingMethod() const {
|
||||
return(QET::RoundScaleRatios);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartPolygon::addPoint
|
||||
* Add new point to polygon
|
||||
* @param point
|
||||
*/
|
||||
void PartPolygon::addPoint(const QPointF &point) {
|
||||
QPolygonF poly = polygon();
|
||||
poly << point;
|
||||
setPolygon(poly);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartPolygon::setLastPoint
|
||||
* Set the last point of polygon to @point
|
||||
* @param point
|
||||
*/
|
||||
void PartPolygon::setLastPoint(const QPointF &point) {
|
||||
QPolygonF poly = polygon();
|
||||
|
||||
if (poly.size())
|
||||
poly.pop_back();
|
||||
|
||||
poly << point;
|
||||
setPolygon(poly);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartPolygon::removeLastPoint
|
||||
* Remove the last point of polygon
|
||||
*/
|
||||
void PartPolygon::removeLastPoint() {
|
||||
QPolygonF poly = polygon();
|
||||
|
||||
if (poly.size())
|
||||
poly.pop_back();
|
||||
|
||||
setPolygon(poly);
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle delimitant cette partie.
|
||||
*/
|
||||
QRectF PartPolygon::boundingRect() const {
|
||||
qreal adjust = 1.5;
|
||||
QRectF r(QGraphicsPolygonItem::boundingRect());
|
||||
r.adjust(-adjust, -adjust, adjust, adjust);
|
||||
return(r);
|
||||
}
|
||||
79
sources/editor/graphicspart/partpolygon.h
Normal file
79
sources/editor/graphicspart/partpolygon.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PART_POLYGON_H
|
||||
#define PART_POLYGON_H
|
||||
#include <QtGui>
|
||||
#include "customelementgraphicpart.h"
|
||||
/**
|
||||
This class represents a polygon primitive which may be used to compose the
|
||||
drawing of an electrical element within the element editor.
|
||||
*/
|
||||
class PartPolygon : public CustomElementGraphicPart, public QGraphicsPolygonItem {
|
||||
Q_OBJECT
|
||||
// constructors, destructor
|
||||
public:
|
||||
PartPolygon(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
|
||||
virtual ~PartPolygon();
|
||||
|
||||
private:
|
||||
PartPolygon(const PartPolygon &);
|
||||
|
||||
// attributes
|
||||
private:
|
||||
bool m_closed;
|
||||
|
||||
// methods
|
||||
public:
|
||||
enum { Type = UserType + 1105 };
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
PartPolygon.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual QString name() const { return(QObject::tr("polygone", "element part name")); }
|
||||
virtual QString xmlName() const { return(QString("polygon")); }
|
||||
void fromXml(const QDomElement &);
|
||||
const QDomElement toXml(QDomDocument &) const;
|
||||
virtual QRectF boundingRect() const;
|
||||
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||
virtual bool isUseless() const;
|
||||
virtual QRectF sceneGeometricRect() const;
|
||||
virtual void startUserTransformation(const QRectF &);
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||
virtual QET::ScalingMethod preferredScalingMethod() const;
|
||||
|
||||
void addPoint (const QPointF &point);
|
||||
void setLastPoint (const QPointF &point);
|
||||
void removeLastPoint ();
|
||||
|
||||
///PROPERTY
|
||||
// Closed (join the first and last point by a line)
|
||||
Q_PROPERTY(bool closed READ isClosed WRITE setClosed)
|
||||
bool isClosed() const {return m_closed;}
|
||||
void setClosed(bool c) {m_closed = c;}
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
|
||||
private:
|
||||
QList<QPointF> saved_points_;
|
||||
};
|
||||
#endif
|
||||
218
sources/editor/graphicspart/partrectangle.cpp
Normal file
218
sources/editor/graphicspart/partrectangle.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "partrectangle.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param editor L'editeur d'element concerne
|
||||
@param parent Le QGraphicsItem parent de ce rectangle
|
||||
@param scene La scene sur laquelle figure ce rectangle
|
||||
*/
|
||||
PartRectangle::PartRectangle(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : CustomElementGraphicPart(editor), QGraphicsRectItem(parent, scene) {
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptedMouseButtons(Qt::LeftButton);
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
PartRectangle::~PartRectangle() {
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine le rectangle
|
||||
@param painter QPainter a utiliser pour rendre le dessin
|
||||
@param options Options pour affiner le rendu
|
||||
@param widget Widget sur lequel le rendu est effectue
|
||||
*/
|
||||
void PartRectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget) {
|
||||
Q_UNUSED(widget);
|
||||
applyStylesToQPainter(*painter);
|
||||
QPen t = painter -> pen();
|
||||
t.setCosmetic(options && options -> levelOfDetail < 1.0);
|
||||
if (isSelected()) {
|
||||
t.setColor(Qt::red);
|
||||
}
|
||||
|
||||
// force le type de jointures pour les rectangles
|
||||
t.setJoinStyle(Qt::MiterJoin);
|
||||
|
||||
// force le dessin avec un trait fin si l'une des dimensions du rectangle est nulle
|
||||
if (!rect().width() || !rect().height()) {
|
||||
t.setWidth(0);
|
||||
}
|
||||
|
||||
painter -> setPen(t);
|
||||
painter -> drawRect(rect());
|
||||
if (isSelected()) {
|
||||
painter -> setRenderHint(QPainter::Antialiasing, false);
|
||||
painter -> setPen((painter -> brush().color() == QColor(Qt::black) && painter -> brush().isOpaque()) ? Qt::yellow : Qt::blue);
|
||||
QPointF center = rect().center();
|
||||
painter -> drawLine(QLineF(center.x() - 2.0, center.y(), center.x() + 2.0, center.y()));
|
||||
painter -> drawLine(QLineF(center.x(), center.y() - 2.0, center.x(), center.y() + 2.0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte le rectangle en XML
|
||||
@param xml_document Document XML a utiliser pour creer l'element XML
|
||||
@return un element XML decrivant le rectangle
|
||||
*/
|
||||
const QDomElement PartRectangle::toXml(QDomDocument &xml_document) const {
|
||||
QDomElement xml_element = xml_document.createElement("rect");
|
||||
QPointF top_left(sceneTopLeft());
|
||||
xml_element.setAttribute("x", QString("%1").arg(top_left.x()));
|
||||
xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
|
||||
xml_element.setAttribute("width", QString("%1").arg(rect().width()));
|
||||
xml_element.setAttribute("height", QString("%1").arg(rect().height()));
|
||||
stylesToXml(xml_element);
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
/**
|
||||
Importe les proprietes d'une rectangle depuis un element XML
|
||||
@param qde Element XML a lire
|
||||
*/
|
||||
void PartRectangle::fromXml(const QDomElement &qde) {
|
||||
stylesFromXml(qde);
|
||||
setRect(
|
||||
QRectF(
|
||||
mapFromScene(
|
||||
qde.attribute("x", "0").toDouble(),
|
||||
qde.attribute("y", "0").toDouble()
|
||||
),
|
||||
QSizeF(
|
||||
qde.attribute("width", "0").toDouble(),
|
||||
qde.attribute("height", "0").toDouble()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartRectangle::setX
|
||||
* @param x new value
|
||||
*/
|
||||
void PartRectangle::setX(qreal x) {
|
||||
QRectF current_rect = rect();
|
||||
QPointF current_pos = mapToScene(current_rect.topLeft());
|
||||
setRect(current_rect.translated(x - current_pos.x(), 0.0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartRectangle::setY
|
||||
* @param y new value
|
||||
*/
|
||||
void PartRectangle::setY(qreal y) {
|
||||
QRectF current_rect = rect();
|
||||
QPointF current_pos = mapToScene(current_rect.topLeft());
|
||||
setRect(current_rect.translated(0.0, y - current_pos.y()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartRectangle::setWidth
|
||||
* @param w new value
|
||||
*/
|
||||
void PartRectangle::setWidth(qreal w) {
|
||||
qreal new_width = qAbs(w);
|
||||
QRectF current_rect = rect();
|
||||
current_rect.setWidth(new_width);
|
||||
setRect(current_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PartRectangle::setHeight
|
||||
* @param h new value
|
||||
*/
|
||||
void PartRectangle::setHeight(qreal h) {
|
||||
qreal new_height = qAbs(h);
|
||||
QRectF current_rect = rect();
|
||||
current_rect.setHeight(new_height);
|
||||
setRect(current_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les changements intervenant sur cette partie
|
||||
@param change Type de changement
|
||||
@param value Valeur numerique relative au changement
|
||||
*/
|
||||
QVariant PartRectangle::itemChange(GraphicsItemChange change, const QVariant &value) {
|
||||
if (scene()) {
|
||||
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
|
||||
updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
return(QGraphicsRectItem::itemChange(change, value));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le coin superieur gauche du rectangle, dans les coordonnees de la
|
||||
scene.
|
||||
*/
|
||||
QPointF PartRectangle::sceneTopLeft() const {
|
||||
return(mapToScene(rect().topLeft()));
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
|
||||
conservee / enregistree.
|
||||
Un rectangle est pertinent des lors que ses dimensions ne sont pas nulles.
|
||||
*/
|
||||
bool PartRectangle::isUseless() const {
|
||||
return(rect().isNull());
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates. It is different from boundingRect() because it is not supposed
|
||||
to imply any margin, and it is different from shape because it is a regular
|
||||
rectangle, not a complex shape.
|
||||
*/
|
||||
QRectF PartRectangle::sceneGeometricRect() const {
|
||||
return(mapToScene(rect()).boundingRect());
|
||||
}
|
||||
|
||||
/**
|
||||
Start the user-induced transformation, provided this primitive is contained
|
||||
within the \a initial_selection_rect bounding rectangle.
|
||||
*/
|
||||
void PartRectangle::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
// we keep track of our own rectangle at the moment in scene coordinates too
|
||||
saved_points_.clear();
|
||||
saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight());
|
||||
}
|
||||
|
||||
/**
|
||||
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
|
||||
*/
|
||||
void PartRectangle::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
|
||||
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
|
||||
setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle delimitant cette partie.
|
||||
*/
|
||||
QRectF PartRectangle::boundingRect() const {
|
||||
qreal adjust = 1.5;
|
||||
QRectF r(QGraphicsRectItem::boundingRect().normalized());
|
||||
r.adjust(-adjust, -adjust, adjust, adjust);
|
||||
return(r);
|
||||
}
|
||||
81
sources/editor/graphicspart/partrectangle.h
Normal file
81
sources/editor/graphicspart/partrectangle.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PART_RECTANGLE_H
|
||||
#define PART_RECTANGLE_H
|
||||
#include <QtGui>
|
||||
#include "customelementgraphicpart.h"
|
||||
/**
|
||||
This class represents a rectangle primitive which may be used to compose the
|
||||
drawing of an electrical element within the element editor.
|
||||
*/
|
||||
class PartRectangle : public CustomElementGraphicPart, public QGraphicsRectItem {
|
||||
Q_OBJECT
|
||||
// constructors, destructor
|
||||
public:
|
||||
PartRectangle(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
|
||||
virtual ~PartRectangle();
|
||||
|
||||
private:
|
||||
PartRectangle(const PartRectangle &);
|
||||
|
||||
// methods
|
||||
public:
|
||||
enum { Type = UserType + 1109 };
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
PartRectangle.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
|
||||
virtual QString name() const { return(QObject::tr("rectangle", "element part name")); }
|
||||
virtual QString xmlName() const { return(QString("rect")); }
|
||||
virtual const QDomElement toXml(QDomDocument &) const;
|
||||
virtual void fromXml(const QDomElement &);
|
||||
virtual QPointF sceneTopLeft() const;
|
||||
virtual QRectF boundingRect() const;
|
||||
virtual bool isUseless() const;
|
||||
virtual QRectF sceneGeometricRect() const;
|
||||
virtual void startUserTransformation(const QRectF &);
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||
|
||||
///PROPERTY
|
||||
// X value
|
||||
Q_PROPERTY(qreal x READ x WRITE setX)
|
||||
qreal x() const {return mapToScene(rect().topLeft()).x();}
|
||||
void setX(qreal x);
|
||||
// Y value
|
||||
Q_PROPERTY(qreal y READ y WRITE setY)
|
||||
qreal y() const {return mapToScene(rect().topLeft()).y();}
|
||||
void setY(qreal y);
|
||||
// Width value
|
||||
Q_PROPERTY(qreal width READ width WRITE setWidth)
|
||||
qreal width() const {return rect().width();}
|
||||
void setWidth(qreal w);
|
||||
// Height value
|
||||
Q_PROPERTY(qreal height READ height WRITE setHeight)
|
||||
qreal height() const { return rect().height();}
|
||||
void setHeight(qreal h);
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
|
||||
private:
|
||||
QList<QPointF> saved_points_;
|
||||
};
|
||||
#endif
|
||||
203
sources/editor/graphicspart/partterminal.cpp
Normal file
203
sources/editor/graphicspart/partterminal.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "partterminal.h"
|
||||
#include "terminal.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param editor L'editeur d'element concerne
|
||||
@param parent Le QGraphicsItem parent de cette borne
|
||||
@param scene La scene sur laquelle figure cette borne
|
||||
*/
|
||||
PartTerminal::PartTerminal(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
|
||||
CustomElementGraphicPart(editor),
|
||||
QGraphicsItem(parent, scene),
|
||||
m_orientation(Qet::North)
|
||||
{
|
||||
updateSecondPoint();
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setZValue(100000);
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
PartTerminal::~PartTerminal() {
|
||||
}
|
||||
|
||||
/**
|
||||
Importe les proprietes d'une borne depuis un element XML
|
||||
@param xml_elmt Element XML a lire
|
||||
*/
|
||||
void PartTerminal::fromXml(const QDomElement &xml_elmt) {
|
||||
// lit la position de la borne
|
||||
qreal term_x = 0.0, term_y = 0.0;
|
||||
QET::attributeIsAReal(xml_elmt, "x", &term_x);
|
||||
QET::attributeIsAReal(xml_elmt, "y", &term_y);
|
||||
setPos(QPointF(term_x, term_y));
|
||||
|
||||
// lit l'orientation de la borne
|
||||
m_orientation = Qet::orientationFromString(xml_elmt.attribute("orientation"));
|
||||
|
||||
updateSecondPoint();
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte la borne en XML
|
||||
@param xml_document Document XML a utiliser pour creer l'element XML
|
||||
@return un element XML decrivant la borne
|
||||
*/
|
||||
const QDomElement PartTerminal::toXml(QDomDocument &xml_document) const {
|
||||
QDomElement xml_element = xml_document.createElement("terminal");
|
||||
|
||||
// ecrit la position de la borne
|
||||
xml_element.setAttribute("x", QString("%1").arg(scenePos().x()));
|
||||
xml_element.setAttribute("y", QString("%1").arg(scenePos().y()));
|
||||
|
||||
// ecrit l'orientation de la borne
|
||||
xml_element.setAttribute("orientation", Qet::orientationToString(m_orientation));
|
||||
// Write name and number to XML
|
||||
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine la borne
|
||||
@param p QPainter a utiliser pour rendre le dessin
|
||||
@param options Options pour affiner le rendu
|
||||
@param widget Widget sur lequel le rendu est effectue
|
||||
*/
|
||||
void PartTerminal::paint(QPainter *p, const QStyleOptionGraphicsItem *options, QWidget *widget) {
|
||||
Q_UNUSED(widget);
|
||||
p -> save();
|
||||
|
||||
// annulation des renderhints
|
||||
p -> setRenderHint(QPainter::Antialiasing, false);
|
||||
p -> setRenderHint(QPainter::TextAntialiasing, false);
|
||||
p -> setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||
|
||||
QPen t;
|
||||
t.setWidthF(1.0);
|
||||
t.setCosmetic(options && options -> levelOfDetail < 1.0);
|
||||
|
||||
// dessin de la borne en rouge
|
||||
t.setColor(isSelected() ? Terminal::neutralColor : Qt::red);
|
||||
p -> setPen(t);
|
||||
p -> drawLine(QPointF(0.0, 0.0), second_point);
|
||||
|
||||
// dessin du point d'amarrage au conducteur en bleu
|
||||
t.setColor(isSelected() ? Qt::red : Terminal::neutralColor);
|
||||
p -> setPen(t);
|
||||
p -> setBrush(Terminal::neutralColor);
|
||||
p -> drawPoint(QPointF(0.0, 0.0));
|
||||
p -> restore();
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle delimitant cette partie.
|
||||
*/
|
||||
QRectF PartTerminal::boundingRect() const {
|
||||
QPointF p1, p2;
|
||||
if (second_point.x() <= 0.0 && second_point.y() <= 0.0) {
|
||||
p1 = second_point;
|
||||
p2 = QPointF(0.0, 0.0);
|
||||
} else {
|
||||
p1 = QPointF(0.0, 0.0);
|
||||
p2 = second_point;
|
||||
}
|
||||
QRectF br;
|
||||
br.setTopLeft (p1 - QPointF(2.0, 2.0));
|
||||
br.setBottomRight(p2 + QPointF(2.0, 2.0));
|
||||
return(br);
|
||||
}
|
||||
|
||||
/**
|
||||
Definit l'orientation de la borne
|
||||
@param ori la nouvelle orientation de la borne
|
||||
*/
|
||||
void PartTerminal::setOrientation(Qet::Orientation ori) {
|
||||
prepareGeometryChange();
|
||||
m_orientation = ori;
|
||||
updateSecondPoint();
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les changements intervenant sur cette partie
|
||||
@param change Type de changement
|
||||
@param value Valeur numerique relative au changement
|
||||
*/
|
||||
QVariant PartTerminal::itemChange(GraphicsItemChange change, const QVariant &value) {
|
||||
if (scene()) {
|
||||
if (change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged) {
|
||||
updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
return(QGraphicsItem::itemChange(change, value));
|
||||
}
|
||||
|
||||
/**
|
||||
Met a jour la position du second point en fonction de la position et de
|
||||
l'orientation de la borne.
|
||||
*/
|
||||
void PartTerminal::updateSecondPoint() {
|
||||
qreal ts = 4.0; // terminal size
|
||||
switch(m_orientation) {
|
||||
case Qet::North: second_point = QPointF(0.0, ts); break;
|
||||
case Qet::East : second_point = QPointF(-ts, 0.0); break;
|
||||
case Qet::South: second_point = QPointF(0.0, -ts); break;
|
||||
case Qet::West : second_point = QPointF(ts, 0.0); break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
|
||||
conservee / enregistree.
|
||||
Une borne est toujours pertinente ; cette fonction renvoie donc
|
||||
toujours false
|
||||
*/
|
||||
bool PartTerminal::isUseless() const {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates. It is different from boundingRect() because it is not supposed
|
||||
to imply any margin, and it is different from shape because it is a regular
|
||||
rectangle, not a complex shape.
|
||||
*/
|
||||
QRectF PartTerminal::sceneGeometricRect() const {
|
||||
return(sceneBoundingRect());
|
||||
}
|
||||
|
||||
/**
|
||||
Start the user-induced transformation, provided this primitive is contained
|
||||
within the \a initial_selection_rect bounding rectangle.
|
||||
*/
|
||||
void PartTerminal::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
saved_position_ = scenePos();
|
||||
}
|
||||
|
||||
/**
|
||||
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
|
||||
*/
|
||||
void PartTerminal::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
|
||||
QPointF mapped_point = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_position_).first();
|
||||
setPos(mapped_point);
|
||||
}
|
||||
83
sources/editor/graphicspart/partterminal.h
Normal file
83
sources/editor/graphicspart/partterminal.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PART_TERMINAL_H
|
||||
#define PART_TERMINAL_H
|
||||
#include "customelementgraphicpart.h"
|
||||
#include "qet.h"
|
||||
#include <QtGui>
|
||||
/**
|
||||
This class represents a terminal which may be used to compose the drawing of
|
||||
an electrical element within the element editor.
|
||||
*/
|
||||
class PartTerminal : public CustomElementGraphicPart, public QGraphicsItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
// constructors, destructor
|
||||
PartTerminal(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
|
||||
virtual ~PartTerminal();
|
||||
private:
|
||||
PartTerminal(const PartTerminal &);
|
||||
|
||||
// attributes
|
||||
private:
|
||||
Qet::Orientation m_orientation;
|
||||
QPointF second_point;
|
||||
|
||||
// methods
|
||||
public:
|
||||
enum { Type = UserType + 1106 };
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
PartTerminal.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual QString name() const { return(QObject::tr("borne", "element part name")); }
|
||||
virtual QString xmlName() const { return(QString("terminal")); }
|
||||
virtual void fromXml(const QDomElement &);
|
||||
virtual const QDomElement toXml(QDomDocument &) const;
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||
virtual QRectF boundingRect() const;
|
||||
|
||||
/*virtual void setProperty(const QString &, const QVariant &);
|
||||
virtual QVariant property(const QString &);*/
|
||||
virtual bool isUseless() const;
|
||||
virtual QRectF sceneGeometricRect() const;
|
||||
virtual void startUserTransformation(const QRectF &);
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||
|
||||
///PROPERTY
|
||||
// X value
|
||||
Q_PROPERTY(qreal x READ x WRITE setX)
|
||||
// Y value
|
||||
Q_PROPERTY(qreal y READ y WRITE setY)
|
||||
// Horientation value
|
||||
Q_PROPERTY(Qet::Orientation orientation READ orientation WRITE setOrientation)
|
||||
Qet::Orientation orientation() const {return m_orientation;}
|
||||
void setOrientation(Qet::Orientation ori);
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
|
||||
private:
|
||||
void updateSecondPoint();
|
||||
|
||||
private:
|
||||
QPointF saved_position_;
|
||||
};
|
||||
#endif
|
||||
481
sources/editor/graphicspart/parttext.cpp
Normal file
481
sources/editor/graphicspart/parttext.cpp
Normal file
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "parttext.h"
|
||||
#include "texteditor.h"
|
||||
#include "editorcommands.h"
|
||||
#include "elementprimitivedecorator.h"
|
||||
#include "elementscene.h"
|
||||
#include "qetapp.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param editor L'editeur d'element concerne
|
||||
@param parent Le QGraphicsItem parent de ce texte statique
|
||||
@param scene La scene sur laquelle figure ce texte statique
|
||||
*/
|
||||
PartText::PartText(QETElementEditor *editor, QGraphicsItem *parent, ElementScene *scene) :
|
||||
QGraphicsTextItem(parent, scene),
|
||||
CustomElementPart(editor),
|
||||
previous_text(),
|
||||
decorator_(0)
|
||||
{
|
||||
#if QT_VERSION >= 0x040500
|
||||
document() -> setDocumentMargin(1.0);
|
||||
#endif
|
||||
setDefaultTextColor(Qt::black);
|
||||
setFont(QETApp::diagramTextsFont());
|
||||
real_font_size_ = font().pointSize();
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptHoverEvents(true);
|
||||
setDefaultTextColor(Qt::black);
|
||||
setPlainText(QObject::tr("T", "default text when adding a text in the element editor"));
|
||||
|
||||
adjustItemPosition(1);
|
||||
// adjust textfield position after line additions/deletions
|
||||
connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
|
||||
connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
PartText::~PartText() {
|
||||
}
|
||||
|
||||
/**
|
||||
Importe les proprietes d'un texte statique depuis un element XML
|
||||
@param xml_element Element XML a lire
|
||||
*/
|
||||
void PartText::fromXml(const QDomElement &xml_element) {
|
||||
bool ok;
|
||||
int font_size = xml_element.attribute("size").toInt(&ok);
|
||||
if (!ok || font_size < 1) font_size = 20;
|
||||
|
||||
setBlack(xml_element.attribute("color") != "white");
|
||||
setProperty("size" , font_size);
|
||||
setPlainText(xml_element.attribute("text"));
|
||||
|
||||
qreal default_rotation_angle = 0.0;
|
||||
if (QET::attributeIsAReal(xml_element, "rotation", &default_rotation_angle)) {
|
||||
setRotation(default_rotation_angle);
|
||||
}
|
||||
|
||||
setPos(
|
||||
xml_element.attribute("x").toDouble(),
|
||||
xml_element.attribute("y").toDouble()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte le texte statique en XML
|
||||
@param xml_document Document XML a utiliser pour creer l'element XML
|
||||
@return un element XML decrivant le texte statique
|
||||
*/
|
||||
const QDomElement PartText::toXml(QDomDocument &xml_document) const {
|
||||
QDomElement xml_element = xml_document.createElement("text");
|
||||
xml_element.setAttribute("x", QString("%1").arg(pos().x()));
|
||||
xml_element.setAttribute("y", QString("%1").arg(pos().y()));
|
||||
xml_element.setAttribute("text", toPlainText());
|
||||
xml_element.setAttribute("size", font().pointSize());
|
||||
// angle de rotation du champ de texte
|
||||
if (rotation()) {
|
||||
xml_element.setAttribute("rotation", QString("%1").arg(rotation()));
|
||||
}
|
||||
if (!isBlack()) {
|
||||
xml_element.setAttribute("color", "white");
|
||||
}
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
/**
|
||||
@return Les coordonnees du point situe en bas a gauche du texte.
|
||||
*/
|
||||
QPointF PartText::margin() const {
|
||||
QFont used_font = font();
|
||||
QFontMetrics qfm(used_font);
|
||||
|
||||
// marge du texte
|
||||
#if QT_VERSION >= 0x040500
|
||||
qreal document_margin = document() -> documentMargin();
|
||||
#else
|
||||
// il semblerait qu'avant Qt 4.5, ceci vaille non pas 4.0 mais 2.0
|
||||
qreal document_margin = 2.0;
|
||||
#endif
|
||||
|
||||
QPointF margin(
|
||||
// marge autour du texte
|
||||
document_margin,
|
||||
// marge au-dessus du texte + distance entre le plafond du texte et la baseline
|
||||
document_margin + qfm.ascent()
|
||||
);
|
||||
return(margin);
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp QGraphicsItem::focusInEvent(QFocusEvent *)
|
||||
@param e The QFocusEvent object describing the focus gain.
|
||||
Start text edition when the item gains focus.
|
||||
*/
|
||||
void PartText::focusInEvent(QFocusEvent *e) {
|
||||
startEdition();
|
||||
QGraphicsTextItem::focusInEvent(e);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@reimp QGraphicsItem::focusOutEvent(QFocusEvent *)
|
||||
@param e The QFocusEvent object describing the focus loss.
|
||||
End text edition when the item loses focus.
|
||||
*/
|
||||
void PartText::focusOutEvent(QFocusEvent *e) {
|
||||
QGraphicsTextItem::focusOutEvent(e);
|
||||
endEdition();
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp QGraphicsTextItem::keyPressEvent()
|
||||
Used to handle the escape key when the event is delivered to the field, not
|
||||
to the decorator.
|
||||
*/
|
||||
void PartText::keyPressEvent(QKeyEvent *event) {
|
||||
if (event -> key() == Qt::Key_Escape) {
|
||||
endEdition();
|
||||
}
|
||||
else {
|
||||
QGraphicsTextItem::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Permet a l'element texte de devenir editable lorsqu'on double-clique dessus
|
||||
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
|
||||
*/
|
||||
void PartText::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
|
||||
QGraphicsTextItem::mouseDoubleClickEvent(e);
|
||||
if (e -> button() == Qt::LeftButton) {
|
||||
setEditable(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les changements intervenant sur cette partie
|
||||
@param change Type de changement
|
||||
@param value Valeur numerique relative au changement
|
||||
*/
|
||||
QVariant PartText::itemChange(GraphicsItemChange change, const QVariant &value) {
|
||||
if (change == QGraphicsItem::ItemPositionHasChanged || change == QGraphicsItem::ItemSceneHasChanged) {
|
||||
updateCurrentPartEditor();
|
||||
} else if (change == QGraphicsItem::ItemSelectedHasChanged) {
|
||||
if (value.toBool() == true) {
|
||||
updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
return(QGraphicsTextItem::itemChange(change, value));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle delimitant cette partie.
|
||||
*/
|
||||
QRectF PartText::boundingRect() const {
|
||||
QRectF r = QGraphicsTextItem::boundingRect();
|
||||
r.adjust(0.0, -1.1, 0.0, 0.0);
|
||||
return(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
|
||||
conservee / enregistree.
|
||||
Un texte statique n'est pas pertinent lorsque son texte est vide.
|
||||
*/
|
||||
bool PartText::isUseless() const {
|
||||
return(toPlainText().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates. It is different from boundingRect() because it is not supposed
|
||||
to imply any margin, and it is different from shape because it is a regular
|
||||
rectangle, not a complex shape.
|
||||
*/
|
||||
QRectF PartText::sceneGeometricRect() const {
|
||||
return(sceneBoundingRect());
|
||||
}
|
||||
|
||||
/**
|
||||
Start the user-induced transformation, provided this primitive is contained
|
||||
within the \a rect bounding rectangle.
|
||||
*/
|
||||
void PartText::startUserTransformation(const QRectF &rect) {
|
||||
Q_UNUSED(rect)
|
||||
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
|
||||
saved_font_size_ = real_font_size_;
|
||||
}
|
||||
|
||||
/**
|
||||
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
|
||||
*/
|
||||
void PartText::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
|
||||
// let's try the naive approach
|
||||
QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_point_).first();
|
||||
setPos(new_pos);
|
||||
|
||||
// adjust the font size following the vertical scale factor
|
||||
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
|
||||
qreal new_font_size = saved_font_size_ * sy;
|
||||
setProperty("real_size", qMax(1, qRound(new_font_size)));
|
||||
}
|
||||
|
||||
/**
|
||||
Dessine le texte statique.
|
||||
@param painter QPainter a utiliser pour effectuer le rendu
|
||||
@param qsogi Pptions de dessin
|
||||
@param widget Widget sur lequel on dessine (facultatif)
|
||||
*/
|
||||
void PartText::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, QWidget *widget) {
|
||||
// According to the source code of QGraphicsTextItem::paint(), this should
|
||||
// avoid the drawing of the dashed rectangle around the text.
|
||||
QStyleOptionGraphicsItem our_qsogi(*qsogi);
|
||||
our_qsogi.state = QStyle::State_None;
|
||||
|
||||
QGraphicsTextItem::paint(painter, &our_qsogi, widget);
|
||||
|
||||
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||
painter -> setPen(Qt::blue);
|
||||
painter -> drawRect(boundingRect());
|
||||
|
||||
painter -> setPen(Qt::red);
|
||||
drawPoint(painter, QPointF(0, 0));
|
||||
|
||||
painter -> setPen(Qt::green);
|
||||
drawPoint(painter, mapFromScene(pos()));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Handle context menu events.
|
||||
@param event Object describing the context menu event to handle.
|
||||
*/
|
||||
void PartText::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
/**
|
||||
Handle events generated when the mouse hovers over the decorator.
|
||||
@param event Object describing the hover event.
|
||||
*/
|
||||
void PartText::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
||||
// force the cursor when the text is being edited
|
||||
if (hasFocus() && decorator_) {
|
||||
decorator_ -> setCursor(Qt::IBeamCursor);
|
||||
}
|
||||
QGraphicsTextItem::hoverMoveEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp CustomElementPart::setDecorator(ElementPrimitiveDecorator *)
|
||||
Install or remove a sceneEventFilter on the decorator and ensure it will
|
||||
adjust itself while the text is being edited.
|
||||
*/
|
||||
void PartText::setDecorator(ElementPrimitiveDecorator *decorator) {
|
||||
if (decorator) {
|
||||
decorator -> installSceneEventFilter(this);
|
||||
// ensure the decorator will adjust itself when the text area expands or shrinks
|
||||
connect(document(), SIGNAL(contentsChanged()), decorator, SLOT(adjust()));
|
||||
}
|
||||
else {
|
||||
decorator_ -> removeSceneEventFilter(this);
|
||||
endEdition();
|
||||
}
|
||||
decorator_ = decorator;
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp QGraphicsItem::sceneEventFilter(QGraphicsItem *, QEvent *).
|
||||
Intercepts events before they reach the watched target, i.e. typically the
|
||||
primitives decorator.
|
||||
This method mainly works with key strokes (F2, escape) and double clicks to
|
||||
begin or end text edition.
|
||||
*/
|
||||
bool PartText::sceneEventFilter(QGraphicsItem *watched, QEvent *event) {
|
||||
if (watched != decorator_) return(false);
|
||||
|
||||
QPointF event_scene_pos = QET::graphicsSceneEventPos(event);
|
||||
if (!event_scene_pos.isNull()) {
|
||||
if (contains(mapFromScene(event_scene_pos))) {
|
||||
if (hasFocus()) {
|
||||
return sceneEvent(event); // manually deliver the event to this item
|
||||
return(true); // prevent this event from being delivered to any item
|
||||
} else {
|
||||
if (event -> type() == QEvent::GraphicsSceneMouseDoubleClick) {
|
||||
mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event -> type() == QEvent::KeyRelease || event -> type() == QEvent::KeyPress) {
|
||||
// Intercept F2 and escape keystrokes to focus in and out
|
||||
QKeyEvent *key_event = static_cast<QKeyEvent *>(event);
|
||||
if (!hasFocus() && key_event -> key() == Qt::Key_F2) {
|
||||
setEditable(true);
|
||||
QTextCursor qtc = textCursor();
|
||||
qtc.setPosition(qMax(0, document()->characterCount() - 1));
|
||||
setTextCursor(qtc);
|
||||
} else if (hasFocus() && key_event -> key() == Qt::Key_Escape) {
|
||||
endEdition();
|
||||
}
|
||||
if (hasFocus()) {
|
||||
sceneEvent(event); // manually deliver the event to this item
|
||||
return(true); // prevent this event from being delivered to any item
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartText::singleItemPressEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartText::singleItemMoveEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartText::singleItemReleaseEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartText::singleItemDoubleClickEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
// calling mouseDoubleClickEvent() will set this text item editable and grab keyboard focus
|
||||
if (event -> button() == Qt::LeftButton) {
|
||||
mouseDoubleClickEvent(event);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
Cette methode s'assure que la position du champ de texte est coherente
|
||||
en repositionnant son origine (c-a-d le milieu du bord gauche du champ de
|
||||
texte) a la position originale. Cela est notamment utile lorsque le champ
|
||||
de texte est agrandi ou retreci verticalement (ajout ou retrait de lignes).
|
||||
@param new_block_count Nombre de blocs dans le PartText
|
||||
*/
|
||||
void PartText::adjustItemPosition(int new_block_count) {
|
||||
Q_UNUSED(new_block_count);
|
||||
QPointF origin_offset = margin();
|
||||
|
||||
QTransform base_translation;
|
||||
base_translation.translate(-origin_offset.x(), -origin_offset.y());
|
||||
setTransform(base_translation, false);
|
||||
setTransformOriginPoint(origin_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@param editable Whether this text item should be interactively editable.
|
||||
*/
|
||||
void PartText::setEditable(bool editable) {
|
||||
if (editable) {
|
||||
setFlag(QGraphicsItem::ItemIsFocusable, true);
|
||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
||||
setFocus(Qt::MouseFocusReason);
|
||||
}
|
||||
else {
|
||||
setTextInteractionFlags(Qt::NoTextInteraction);
|
||||
setFlag(QGraphicsItem::ItemIsFocusable, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Start text edition by storing the former value of the text.
|
||||
*/
|
||||
void PartText::startEdition() {
|
||||
// !previous_text.isNull() means the text is being edited
|
||||
previous_text = toPlainText();
|
||||
}
|
||||
|
||||
/**
|
||||
End text edition, potentially generating a ChangePartCommand if the text
|
||||
has changed.
|
||||
*/
|
||||
void PartText::endEdition() {
|
||||
if (!previous_text.isNull()) {
|
||||
// the text was being edited
|
||||
QString new_text = toPlainText();
|
||||
if (previous_text != new_text) {
|
||||
// the text was changed
|
||||
ChangePartCommand *text_change = new ChangePartCommand(
|
||||
TextEditor::tr("contenu") + " " + name(),
|
||||
this,
|
||||
"text",
|
||||
previous_text,
|
||||
new_text
|
||||
);
|
||||
previous_text = QString();
|
||||
undoStack().push(text_change);
|
||||
}
|
||||
}
|
||||
|
||||
// deselectionne le texte
|
||||
QTextCursor qtc = textCursor();
|
||||
qtc.clearSelection();
|
||||
setTextCursor(qtc);
|
||||
|
||||
setEditable(false);
|
||||
if (decorator_) {
|
||||
decorator_ -> setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||
/**
|
||||
Dessine deux petites fleches pour mettre un point en valeur
|
||||
@param painter QPainter a utiliser pour effectuer le rendu
|
||||
@param point Point a dessiner
|
||||
*/
|
||||
void PartText::drawPoint(QPainter *painter, const QPointF &point) {
|
||||
qreal px = point.x();
|
||||
qreal py = point.y();
|
||||
qreal size_1 = 5.0;
|
||||
qreal size_2 = 1.0;
|
||||
painter -> drawLine(QLineF(px, py, px + size_1, py));
|
||||
painter -> drawLine(QLineF(px + size_1 - size_2, py - size_2, px + size_1, py));
|
||||
painter -> drawLine(QLineF(px + size_1 - size_2, py + size_2, px + size_1, py));
|
||||
painter -> drawLine(QLineF(px, py, px, py + size_1));
|
||||
painter -> drawLine(QLineF(px, py + size_1, px - size_2, py + size_1 - size_2));
|
||||
painter -> drawLine(QLineF(px, py + size_1, px + size_2, py + size_1 - size_2));
|
||||
}
|
||||
#endif
|
||||
111
sources/editor/graphicspart/parttext.h
Normal file
111
sources/editor/graphicspart/parttext.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PART_TEXT_H
|
||||
#define PART_TEXT_H
|
||||
#include <QtGui>
|
||||
#include "customelementpart.h"
|
||||
#include "qetapp.h"
|
||||
class TextEditor;
|
||||
class ElementPrimitiveDecorator;
|
||||
/**
|
||||
This class represents an static text primitive which may be used to compose
|
||||
the drawing of an electrical element within the element editor.
|
||||
*/
|
||||
class PartText : public QGraphicsTextItem, public CustomElementPart {
|
||||
Q_OBJECT
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
PartText(QETElementEditor *, QGraphicsItem * = 0, ElementScene * = 0);
|
||||
virtual ~PartText();
|
||||
|
||||
private:
|
||||
PartText(const PartText &);
|
||||
|
||||
// methods
|
||||
public:
|
||||
enum { Type = UserType + 1107 };
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
PartText.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual QString name() const { return(QObject::tr("texte", "element part name")); }
|
||||
virtual QString xmlName() const { return(QString("text")); }
|
||||
void fromXml(const QDomElement &);
|
||||
const QDomElement toXml(QDomDocument &) const;
|
||||
void setRotation(qreal angle) {(QGraphicsObject::setRotation(QET::correctAngle(angle)));}
|
||||
virtual bool isUseless() const;
|
||||
virtual QRectF sceneGeometricRect() const;
|
||||
virtual void startUserTransformation(const QRectF &);
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0 );
|
||||
virtual void setDecorator(ElementPrimitiveDecorator *);
|
||||
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
|
||||
///PROPERTY
|
||||
void setProperty(const char *name, const QVariant &value) {QGraphicsTextItem::setProperty(name, value);}
|
||||
QVariant property(const char *name) const {return QGraphicsTextItem::property(name);}
|
||||
// Size value
|
||||
Q_PROPERTY(qreal size READ size WRITE setSize)
|
||||
qreal size () const {return font().pointSize();}
|
||||
void setSize (qreal s) {setFont(QETApp::diagramTextsFont(s));}
|
||||
// Real size value
|
||||
Q_PROPERTY(qreal real_size READ realSize WRITE setRealSize)
|
||||
qreal realSize() const {return real_font_size_;}
|
||||
void setRealSize(qreal rs) {real_font_size_ = rs;}
|
||||
// Color value (true = black , false = white)
|
||||
Q_PROPERTY(bool color READ isBlack WRITE setBlack)
|
||||
bool isBlack() const {return defaultTextColor() == Qt::black;}
|
||||
void setBlack(bool b) {setDefaultTextColor(b ? Qt::black : Qt::white);}
|
||||
// displayed string
|
||||
Q_PROPERTY(QString text READ toPlainText WRITE setPlainText)
|
||||
|
||||
public slots:
|
||||
void adjustItemPosition(int = 0);
|
||||
void setEditable(bool);
|
||||
void startEdition();
|
||||
void endEdition();
|
||||
|
||||
protected:
|
||||
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *);
|
||||
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
|
||||
virtual bool sceneEventFilter(QGraphicsItem *, QEvent *);
|
||||
virtual void focusInEvent(QFocusEvent *);
|
||||
virtual void focusOutEvent(QFocusEvent *);
|
||||
virtual void keyPressEvent(QKeyEvent *);
|
||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
QRectF boundingRect() const;
|
||||
|
||||
private:
|
||||
QPointF margin() const;
|
||||
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||
void drawPoint(QPainter *, const QPointF &);
|
||||
#endif
|
||||
QString previous_text;
|
||||
qreal real_font_size_;
|
||||
QPointF saved_point_;
|
||||
qreal saved_font_size_;
|
||||
QGraphicsItem *decorator_;
|
||||
};
|
||||
#endif
|
||||
465
sources/editor/graphicspart/parttextfield.cpp
Normal file
465
sources/editor/graphicspart/parttextfield.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "parttextfield.h"
|
||||
#include "textfieldeditor.h"
|
||||
#include "editorcommands.h"
|
||||
#include "elementprimitivedecorator.h"
|
||||
#include "qetapp.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param editor L'editeur d'element concerne
|
||||
@param parent Le QGraphicsItem parent de ce champ de texte
|
||||
@param scene La scene sur laquelle figure ce champ de texte
|
||||
*/
|
||||
PartTextField::PartTextField(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
|
||||
QGraphicsTextItem(parent, scene),
|
||||
CustomElementPart(editor),
|
||||
follow_parent_rotations(true),
|
||||
m_tagg("none"),
|
||||
previous_text(),
|
||||
decorator_(0)
|
||||
{
|
||||
setDefaultTextColor(Qt::black);
|
||||
setFont(QETApp::diagramTextsFont());
|
||||
real_font_size_ = font().pointSize();
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptHoverEvents(true);
|
||||
setPlainText(QObject::tr("_", "default text when adding a textfield in the element editor"));
|
||||
|
||||
adjustItemPosition(1);
|
||||
// adjust textfield position after line additions/deletions
|
||||
connect(document(), SIGNAL(blockCountChanged(int)), this, SLOT(adjustItemPosition(int)));
|
||||
connect(document(), SIGNAL(contentsChanged()), this, SLOT(adjustItemPosition()));
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
PartTextField::~PartTextField() {
|
||||
}
|
||||
|
||||
/**
|
||||
Importe les proprietes d'un champ de texte depuis un element XML
|
||||
@param xml_element Element XML a lire
|
||||
*/
|
||||
void PartTextField::fromXml(const QDomElement &xml_element) {
|
||||
bool ok;
|
||||
int font_size = xml_element.attribute("size").toInt(&ok);
|
||||
if (!ok || font_size < 1) font_size = 20;
|
||||
|
||||
setProperty("size", font_size);
|
||||
setPlainText(xml_element.attribute("text"));
|
||||
|
||||
m_tagg = xml_element.attribute("tagg", "none");
|
||||
|
||||
qreal default_rotation_angle = 0.0;
|
||||
if (QET::attributeIsAReal(xml_element, "rotation", &default_rotation_angle)) {
|
||||
setRotationAngle(default_rotation_angle);
|
||||
}
|
||||
|
||||
setPos(
|
||||
xml_element.attribute("x").toDouble(),
|
||||
xml_element.attribute("y").toDouble()
|
||||
);
|
||||
|
||||
follow_parent_rotations = (xml_element.attribute("rotate") == "true");
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte le champ de texte en XML
|
||||
@param xml_document Document XML a utiliser pour creer l'element XML
|
||||
@return un element XML decrivant le champ de texte
|
||||
*/
|
||||
const QDomElement PartTextField::toXml(QDomDocument &xml_document) const {
|
||||
QDomElement xml_element = xml_document.createElement("input");
|
||||
xml_element.setAttribute("x", QString("%1").arg(pos().x()));
|
||||
xml_element.setAttribute("y", QString("%1").arg(pos().y()));
|
||||
xml_element.setAttribute("text", toPlainText());
|
||||
xml_element.setAttribute("size", font().pointSize());
|
||||
xml_element.setAttribute("tagg", m_tagg);
|
||||
|
||||
// angle de rotation du champ de texte
|
||||
if (rotation()) {
|
||||
xml_element.setAttribute("rotation", QString("%1").arg(rotation()));
|
||||
}
|
||||
// suivi (ou non) des rotations de l'element parent par le champ de texte
|
||||
if (follow_parent_rotations) {
|
||||
xml_element.setAttribute("rotate", "true");
|
||||
}
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
/**
|
||||
@return le decalage entre l'origine du QGraphicsItem et l'origine du champ de
|
||||
texte.
|
||||
*/
|
||||
QPointF PartTextField::margin() const {
|
||||
return(QPointF(0.0, boundingRect().bottom() / 2.0));
|
||||
}
|
||||
|
||||
/**
|
||||
Handle context menu events.
|
||||
@param event Object describing the context menu event to handle.
|
||||
*/
|
||||
void PartTextField::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
/**
|
||||
Handle events generated when the mouse hovers over the decorator.
|
||||
@param event Object describing the hover event.
|
||||
*/
|
||||
void PartTextField::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
||||
// force the cursor when the text is being edited
|
||||
if (hasFocus() && decorator_) {
|
||||
decorator_ -> setCursor(Qt::IBeamCursor);
|
||||
}
|
||||
QGraphicsTextItem::hoverMoveEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp QGraphicsItem::sceneEventFilter(QGraphicsItem *, QEvent *).
|
||||
Intercepts events before they reach the watched target, i.e. typically the
|
||||
primitives decorator.
|
||||
This method mainly works with key strokes (F2, escape) and double clicks to
|
||||
begin or end text edition.
|
||||
*/
|
||||
bool PartTextField::sceneEventFilter(QGraphicsItem *watched, QEvent *event) {
|
||||
if (watched != decorator_) return(false);
|
||||
|
||||
QPointF event_scene_pos = QET::graphicsSceneEventPos(event);
|
||||
if (!event_scene_pos.isNull()) {
|
||||
if (contains(mapFromScene(event_scene_pos))) {
|
||||
if (hasFocus()) {
|
||||
return sceneEvent(event); // manually deliver the event to this item
|
||||
return(true); // prevent this event from being delivered to any item
|
||||
} else {
|
||||
if (event -> type() == QEvent::GraphicsSceneMouseDoubleClick) {
|
||||
mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event -> type() == QEvent::KeyRelease || event -> type() == QEvent::KeyPress) {
|
||||
// Intercept F2 and escape keystrokes to focus in and out
|
||||
QKeyEvent *key_event = static_cast<QKeyEvent *>(event);
|
||||
if (!hasFocus() && key_event -> key() == Qt::Key_F2) {
|
||||
setEditable(true);
|
||||
QTextCursor qtc = textCursor();
|
||||
qtc.setPosition(qMax(0, document()->characterCount() - 1));
|
||||
setTextCursor(qtc);
|
||||
} else if (hasFocus() && key_event -> key() == Qt::Key_Escape) {
|
||||
endEdition();
|
||||
}
|
||||
if (hasFocus()) {
|
||||
sceneEvent(event); // manually deliver the event to this item
|
||||
return(true); // prevent this event from being delivered to any item
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
/*
|
||||
@reimp QGraphicsItem::focusInEvent(QFocusEvent *)
|
||||
@param e The QFocusEvent object describing the focus gain.
|
||||
Start text edition when the item gains focus.
|
||||
*/
|
||||
void PartTextField::focusInEvent(QFocusEvent *e) {
|
||||
startEdition();
|
||||
QGraphicsTextItem::focusInEvent(e);
|
||||
}
|
||||
|
||||
/**
|
||||
Permet a l'element texte de redevenir deplacable a la fin de l'edition de texte
|
||||
@param e Le QFocusEvent decrivant la perte de focus
|
||||
*/
|
||||
void PartTextField::focusOutEvent(QFocusEvent *e) {
|
||||
QGraphicsTextItem::focusOutEvent(e);
|
||||
endEdition();
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp QGraphicsTextItem::keyPressEvent()
|
||||
Used to handle the escape key when the event is delivered to the field, not
|
||||
to the decorator.
|
||||
*/
|
||||
void PartTextField::keyPressEvent(QKeyEvent *event) {
|
||||
if (event -> key() == Qt::Key_Escape) {
|
||||
endEdition();
|
||||
}
|
||||
else {
|
||||
QGraphicsTextItem::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Permet a l'element texte de devenir editable lorsqu'on double-clique dessus
|
||||
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
|
||||
*/
|
||||
void PartTextField::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
|
||||
QGraphicsTextItem::mouseDoubleClickEvent(e);
|
||||
if (e -> button() == Qt::LeftButton) {
|
||||
setEditable(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Gere les changements intervenant sur cette partie
|
||||
@param change Type de changement
|
||||
@param value Valeur numerique relative au changement
|
||||
*/
|
||||
QVariant PartTextField::itemChange(GraphicsItemChange change, const QVariant &value) {
|
||||
if (change == QGraphicsItem::ItemPositionHasChanged || change == QGraphicsItem::ItemSceneHasChanged) {
|
||||
updateCurrentPartEditor();
|
||||
} else if (change == QGraphicsItem::ItemSelectedHasChanged) {
|
||||
if (value.toBool() == true) {
|
||||
updateCurrentPartEditor();
|
||||
}
|
||||
}
|
||||
return(QGraphicsTextItem::itemChange(change, value));
|
||||
}
|
||||
|
||||
/**
|
||||
@return le rectangle delimitant cette partie.
|
||||
*/
|
||||
QRectF PartTextField::boundingRect() const {
|
||||
QRectF r = QGraphicsTextItem::boundingRect();
|
||||
r.adjust(0.0, -1.1, 0.0, 0.0);
|
||||
return(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@return true si cette partie n'est pas pertinente et ne merite pas d'etre
|
||||
conservee / enregistree.
|
||||
Un champ de texte est toujours pertinent ; cette fonction renvoie donc
|
||||
toujours false
|
||||
*/
|
||||
bool PartTextField::isUseless() const {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates. It is different from boundingRect() because it is not supposed
|
||||
to imply any margin, and it is different from shape because it is a regular
|
||||
rectangle, not a complex shape.
|
||||
*/
|
||||
QRectF PartTextField::sceneGeometricRect() const {
|
||||
return(sceneBoundingRect());
|
||||
}
|
||||
|
||||
/**
|
||||
Start the user-induced transformation, provided this primitive is contained
|
||||
within the \a initial_selection_rect bounding rectangle.
|
||||
*/
|
||||
void PartTextField::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
|
||||
saved_font_size_ = real_font_size_;
|
||||
}
|
||||
|
||||
/**
|
||||
Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect
|
||||
*/
|
||||
void PartTextField::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) {
|
||||
// let's try the naive approach
|
||||
QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_point_).first();
|
||||
setPos(new_pos);
|
||||
|
||||
// adjust the font size following the vertical scale factor
|
||||
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
|
||||
qreal new_font_size = saved_font_size_ * sy;
|
||||
setProperty("real_size", qMax(1, qRound(new_font_size)));
|
||||
}
|
||||
/**
|
||||
Dessine le texte statique.
|
||||
@param painter QPainter a utiliser pour effectuer le rendu
|
||||
@param qsogi Pptions de dessin
|
||||
@param widget Widget sur lequel on dessine (facultatif)
|
||||
*/
|
||||
void PartTextField::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, QWidget *widget) {
|
||||
// According to the source code of QGraphicsTextItem::paint(), this should
|
||||
// avoid the drawing of the dashed rectangle around the text.
|
||||
QStyleOptionGraphicsItem our_qsogi(*qsogi);
|
||||
our_qsogi.state = QStyle::State_None;
|
||||
|
||||
QGraphicsTextItem::paint(painter, &our_qsogi, widget);
|
||||
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||
painter -> setPen(Qt::blue);
|
||||
painter -> drawRect(boundingRect());
|
||||
|
||||
painter -> setPen(Qt::red);
|
||||
drawPoint(painter, QPointF(0, 0));
|
||||
|
||||
painter -> setPen(QColor("#800000"));
|
||||
drawPoint(painter, mapFromScene(pos()));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp CustomElementPart::setDecorator(ElementPrimitiveDecorator *)
|
||||
Install or remove a sceneEventFilter on the decorator and ensure it will
|
||||
adjust itself while the text is being edited.
|
||||
*/
|
||||
void PartTextField::setDecorator(ElementPrimitiveDecorator *decorator) {
|
||||
if (decorator) {
|
||||
decorator -> installSceneEventFilter(this);
|
||||
// ensure the decorator will adjust itself when the text area expands or shrinks
|
||||
connect(document(), SIGNAL(contentsChanged()), decorator, SLOT(adjust()));
|
||||
}
|
||||
else {
|
||||
decorator_ -> removeSceneEventFilter(this);
|
||||
endEdition();
|
||||
}
|
||||
decorator_ = decorator;
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartTextField::singleItemPressEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartTextField::singleItemMoveEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartTextField::singleItemReleaseEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartTextField::singleItemDoubleClickEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
// calling mouseDoubleClickEvent() will set this text item editable and grab keyboard focus
|
||||
if (event -> button() == Qt::LeftButton) {
|
||||
mouseDoubleClickEvent(event);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
Cette methode s'assure que la position du champ de texte est coherente
|
||||
en repositionnant son origine (c-a-d le milieu du bord gauche du champ de
|
||||
texte) a la position originale. Cela est notamment utile lorsque le champ
|
||||
de texte est agrandi ou retreci verticalement (ajout ou retrait de lignes).
|
||||
@param new_block_count Nombre de blocs dans le PartTextField
|
||||
*/
|
||||
void PartTextField::adjustItemPosition(int new_block_count) {
|
||||
Q_UNUSED(new_block_count);
|
||||
qreal origin_offset = boundingRect().bottom() / 2.0;
|
||||
|
||||
QTransform base_translation;
|
||||
base_translation.translate(0.0, -origin_offset);
|
||||
setTransform(base_translation, false);
|
||||
setTransformOriginPoint(0.0, origin_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@param editable Whether this text item should be interactively editable.
|
||||
*/
|
||||
void PartTextField::setEditable(bool editable) {
|
||||
if (editable) {
|
||||
setFlag(QGraphicsItem::ItemIsFocusable, true);
|
||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
||||
setFocus(Qt::MouseFocusReason);
|
||||
}
|
||||
else {
|
||||
setTextInteractionFlags(Qt::NoTextInteraction);
|
||||
setFlag(QGraphicsItem::ItemIsFocusable, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Start text edition by storing the former value of the text.
|
||||
*/
|
||||
void PartTextField::startEdition() {
|
||||
// !previous_text.isNull() means the text is being edited
|
||||
previous_text = toPlainText();
|
||||
}
|
||||
|
||||
/**
|
||||
End text edition, potentially generating a ChangePartCommand if the text
|
||||
has changed.
|
||||
*/
|
||||
void PartTextField::endEdition() {
|
||||
if (!previous_text.isNull()) {
|
||||
// the text was being edited
|
||||
QString new_text = toPlainText();
|
||||
if (previous_text != new_text) {
|
||||
// the text was changed
|
||||
ChangePartCommand *text_change = new ChangePartCommand(
|
||||
TextFieldEditor::tr("contenu") + " " + name(),
|
||||
this,
|
||||
"text",
|
||||
previous_text,
|
||||
new_text
|
||||
);
|
||||
previous_text = QString();
|
||||
undoStack().push(text_change);
|
||||
}
|
||||
}
|
||||
|
||||
// deselectionne le texte
|
||||
QTextCursor qtc = textCursor();
|
||||
qtc.clearSelection();
|
||||
setTextCursor(qtc);
|
||||
|
||||
setEditable(false);
|
||||
if (decorator_) {
|
||||
decorator_ -> setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||
/**
|
||||
Dessine deux petites fleches pour mettre un point en valeur
|
||||
@param painter QPainter a utiliser pour effectuer le rendu
|
||||
@param point Point a dessiner
|
||||
*/
|
||||
void PartTextField::drawPoint(QPainter *painter, const QPointF &point) {
|
||||
qreal px = point.x();
|
||||
qreal py = point.y();
|
||||
qreal size_1 = 5.0;
|
||||
qreal size_2 = 1.0;
|
||||
painter -> drawLine(QLineF(px, py, px + size_1, py));
|
||||
painter -> drawLine(QLineF(px + size_1 - size_2, py - size_2, px + size_1, py));
|
||||
painter -> drawLine(QLineF(px + size_1 - size_2, py + size_2, px + size_1, py));
|
||||
painter -> drawLine(QLineF(px, py, px, py + size_1));
|
||||
painter -> drawLine(QLineF(px, py + size_1, px - size_2, py + size_1 - size_2));
|
||||
painter -> drawLine(QLineF(px, py + size_1, px + size_2, py + size_1 - size_2));
|
||||
}
|
||||
#endif
|
||||
126
sources/editor/graphicspart/parttextfield.h
Normal file
126
sources/editor/graphicspart/parttextfield.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright 2006-2014 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PART_TEXTFIELD_H
|
||||
#define PART_TEXTFIELD_H
|
||||
#include <QtGui>
|
||||
#include "customelementpart.h"
|
||||
#include "qetapp.h"
|
||||
class TextFieldEditor;
|
||||
class QETElementEditor;
|
||||
class ElementPrimitiveDecorator;
|
||||
/**
|
||||
This class represents an editable text field which may be used to compose the
|
||||
drawing of an electrical element within the element editor. Users may specify
|
||||
a default value. The field will remain editable once the element is added onto
|
||||
a diagram. lorsque l'element sera pose sur un schema.
|
||||
*/
|
||||
class PartTextField : public QGraphicsTextItem, public CustomElementPart {
|
||||
Q_OBJECT
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
PartTextField(QETElementEditor *, QGraphicsItem * = 0, QGraphicsScene * = 0);
|
||||
virtual ~PartTextField();
|
||||
|
||||
private:
|
||||
PartTextField(const PartTextField &);
|
||||
|
||||
// attributes
|
||||
bool follow_parent_rotations;
|
||||
QString m_tagg;
|
||||
|
||||
// methods
|
||||
public:
|
||||
enum { Type = UserType + 1108 };
|
||||
/**
|
||||
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a
|
||||
PartTextField.
|
||||
@return the QGraphicsItem type
|
||||
*/
|
||||
virtual int type() const { return Type; }
|
||||
virtual QString name() const { return(QObject::tr("champ de texte", "element part name")); }
|
||||
virtual QString xmlName() const { return(QString("input")); }
|
||||
void fromXml(const QDomElement &);
|
||||
const QDomElement toXml(QDomDocument &) const;
|
||||
virtual bool isUseless() const;
|
||||
virtual QRectF sceneGeometricRect() const;
|
||||
virtual void startUserTransformation(const QRectF &);
|
||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0 );
|
||||
virtual void setDecorator(ElementPrimitiveDecorator *);
|
||||
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
virtual bool singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||
|
||||
///PROPERTY
|
||||
virtual void setProperty(const char *name, const QVariant &value) {QGraphicsTextItem::setProperty(name, value);}
|
||||
virtual QVariant property(const char *name) const {return QGraphicsTextItem::property(name);}
|
||||
|
||||
// displayed text
|
||||
Q_PROPERTY(QString text READ toPlainText WRITE setPlainText)
|
||||
// font size
|
||||
Q_PROPERTY(int size READ size WRITE setSize)
|
||||
int size() const {return font().pointSize();}
|
||||
void setSize (const int value) {setFont(QETApp::diagramTextsFont(value)); real_font_size_ = value;}
|
||||
// real size
|
||||
Q_PROPERTY(qreal real_size READ realSize WRITE setRealSize)
|
||||
qreal realSize() const {return real_font_size_;}
|
||||
void setRealSize(const qreal size) {real_font_size_ = size;}
|
||||
// angle of text
|
||||
Q_PROPERTY(qreal rotation_angle READ rotation WRITE setRotationAngle)
|
||||
void setRotationAngle(const qreal &angle) {setRotation(QET::correctAngle(angle));}
|
||||
// follow parent rotation
|
||||
Q_PROPERTY(bool rotate READ followParentRotations WRITE setFollowParentRotations)
|
||||
bool followParentRotations() const {return follow_parent_rotations;}
|
||||
void setFollowParentRotations(bool i) {follow_parent_rotations = i;}
|
||||
// tagg of text
|
||||
Q_PROPERTY(QString tagg READ tagg WRITE setTagg)
|
||||
QString tagg() const {return m_tagg;}
|
||||
void setTagg(const QString &tagg) {m_tagg = tagg;}
|
||||
|
||||
|
||||
public slots:
|
||||
void adjustItemPosition(int = 0);
|
||||
void setEditable(bool);
|
||||
void startEdition();
|
||||
void endEdition();
|
||||
|
||||
protected:
|
||||
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *);
|
||||
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
|
||||
virtual bool sceneEventFilter(QGraphicsItem *, QEvent *);
|
||||
virtual void focusInEvent(QFocusEvent *);
|
||||
virtual void focusOutEvent(QFocusEvent *);
|
||||
virtual void keyPressEvent(QKeyEvent *);
|
||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
|
||||
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||
QRectF boundingRect() const;
|
||||
|
||||
private:
|
||||
QPointF margin() const;
|
||||
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||
void drawPoint(QPainter *, const QPointF &);
|
||||
#endif
|
||||
QString previous_text;
|
||||
qreal real_font_size_;
|
||||
QPointF saved_point_;
|
||||
qreal saved_font_size_;
|
||||
QGraphicsItem *decorator_;
|
||||
};
|
||||
#endif
|
||||
Reference in New Issue
Block a user