mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-12-18 13:30:34 +01:00
Implemented a primitive decorator, allowing groups of primitives to be easily resized.
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@2027 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
@@ -44,6 +44,61 @@ QUndoStack &CustomElementPart::undoStack() const {
|
|||||||
return(elementScene() -> undoStack());
|
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 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()
|
Helper method to map points in CustomElementPart::handleUserTransformation()
|
||||||
@param initial_selection_rect Selection rectangle when the movement started, in scene coordinates
|
@param initial_selection_rect Selection rectangle when the movement started, in scene coordinates
|
||||||
|
|||||||
@@ -21,8 +21,10 @@
|
|||||||
#include <QtXml>
|
#include <QtXml>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
class CustomElement;
|
class CustomElement;
|
||||||
class QETElementEditor;
|
class ElementPrimitiveDecorator;
|
||||||
class ElementScene;
|
class ElementScene;
|
||||||
|
class QETElementEditor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This abstract class represents a primitive of the visual representation of an
|
This abstract class represents a primitive of the visual representation of an
|
||||||
electrical element. The Element, FixedElement and CustomElement classes do not
|
electrical element. The Element, FixedElement and CustomElement classes do not
|
||||||
@@ -95,6 +97,14 @@ class CustomElementPart {
|
|||||||
/// @return the name that will be used as XML tag when exporting the primitive
|
/// @return the name that will be used as XML tag when exporting the primitive
|
||||||
virtual QString xmlName() const = 0;
|
virtual QString xmlName() const = 0;
|
||||||
|
|
||||||
|
virtual QGraphicsItem *toItem();
|
||||||
|
|
||||||
|
virtual void setDecorator(ElementPrimitiveDecorator *);
|
||||||
|
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||||
|
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||||
|
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||||
|
virtual bool singleItemDoubleClickEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QList<QPointF> mapPoints(const QRectF &, const QRectF &, const QList<QPointF> &);
|
QList<QPointF> mapPoints(const QRectF &, const QRectF &, const QList<QPointF> &);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -684,3 +684,104 @@ void ChangeInformationsCommand::undo() {
|
|||||||
void ChangeInformationsCommand::redo() {
|
void ChangeInformationsCommand::redo() {
|
||||||
editor_scene_ -> setInformations(new_informations_);
|
editor_scene_ -> setInformations(new_informations_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor
|
||||||
|
@param scene Modified ElementScene
|
||||||
|
@param parent Parent QUndoCommand
|
||||||
|
*/
|
||||||
|
ScalePartsCommand::ScalePartsCommand(ElementScene *scene, QUndoCommand * parent) :
|
||||||
|
ElementEditionCommand(scene, 0, parent),
|
||||||
|
first_redo(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Destructor
|
||||||
|
*/
|
||||||
|
ScalePartsCommand::~ScalePartsCommand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Undo the scaling operation
|
||||||
|
*/
|
||||||
|
void ScalePartsCommand::undo() {
|
||||||
|
scale(new_rect_, original_rect_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Redo the scaling operation
|
||||||
|
*/
|
||||||
|
void ScalePartsCommand::redo() {
|
||||||
|
if (first_redo) {
|
||||||
|
first_redo = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scale(original_rect_, new_rect_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the element editor/scene the command should take place on
|
||||||
|
*/
|
||||||
|
ElementScene *ScalePartsCommand::elementScene() const {
|
||||||
|
return(editor_scene_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set \a primitives as the list of primitives to be scaled by this command
|
||||||
|
*/
|
||||||
|
void ScalePartsCommand::setScaledPrimitives(const QList<CustomElementPart *> &primitives) {
|
||||||
|
scaled_primitives_ = primitives;
|
||||||
|
adjustText();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the list of primitives to be scaled by this command
|
||||||
|
*/
|
||||||
|
QList<CustomElementPart *> ScalePartsCommand::scaledPrimitives() const {
|
||||||
|
return(scaled_primitives_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Define the transformation applied by this command
|
||||||
|
@param original_rect Bounding rectangle for all scaled primitives before the operation
|
||||||
|
@param original_rect Bounding rectangle for all scaled primitives after the operation
|
||||||
|
*/
|
||||||
|
void ScalePartsCommand::setTransformation(const QRectF &original_rect, const QRectF &new_rect) {
|
||||||
|
original_rect_ = original_rect;
|
||||||
|
new_rect_ = new_rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the transformation applied by this command. The returned rectangles
|
||||||
|
are the bounding rectangles for all scaled primitives respectively before
|
||||||
|
and after the operation.
|
||||||
|
*/
|
||||||
|
QPair<QRectF, QRectF> ScalePartsCommand::transformation() {
|
||||||
|
return(QPair<QRectF, QRectF>(original_rect_, new_rect_));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Apply the scaling operation from \a before to \a after.
|
||||||
|
*/
|
||||||
|
void ScalePartsCommand::scale(const QRectF &before, const QRectF &after) {
|
||||||
|
if (!scaled_primitives_.count()) return;
|
||||||
|
if (before == after) return;
|
||||||
|
if (!before.width() || !before.height()) return; // cowardly flee division by zero FIXME?
|
||||||
|
|
||||||
|
foreach (CustomElementPart *part_item, scaled_primitives_) {
|
||||||
|
part_item -> startUserTransformation(before);
|
||||||
|
part_item -> handleUserTransformation(before, after);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Generate the text describing what this command does exactly.
|
||||||
|
*/
|
||||||
|
void ScalePartsCommand::adjustText() {
|
||||||
|
if (scaled_primitives_.count() == 1) {
|
||||||
|
setText(QObject::tr("redimensionnement %1", "undo caption -- %1 is the resized primitive type name").arg(scaled_primitives_.first() -> name()));
|
||||||
|
} else {
|
||||||
|
setText(QObject::tr("redimensionnement de %1 primitives", "undo caption -- %1 always > 1").arg(scaled_primitives_.count()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -391,4 +391,42 @@ class ChangeInformationsCommand : public ElementEditionCommand {
|
|||||||
/// New information
|
/// New information
|
||||||
QString new_informations_;
|
QString new_informations_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
This command scales primitives when editing an electrical element.
|
||||||
|
*/
|
||||||
|
class ScalePartsCommand : public ElementEditionCommand {
|
||||||
|
// constructors, destructor
|
||||||
|
public:
|
||||||
|
ScalePartsCommand(ElementScene * = 0, QUndoCommand * = 0);
|
||||||
|
virtual ~ScalePartsCommand();
|
||||||
|
private:
|
||||||
|
ScalePartsCommand(const ScalePartsCommand &);
|
||||||
|
|
||||||
|
// methods
|
||||||
|
public:
|
||||||
|
virtual void undo();
|
||||||
|
virtual void redo();
|
||||||
|
ElementScene *elementScene() const;
|
||||||
|
void setScaledPrimitives(const QList<CustomElementPart *> &);
|
||||||
|
QList<CustomElementPart *> scaledPrimitives() const;
|
||||||
|
void setTransformation(const QRectF &, const QRectF &);
|
||||||
|
QPair<QRectF, QRectF> transformation();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void scale(const QRectF &before, const QRectF &after);
|
||||||
|
void adjustText();
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
private:
|
||||||
|
/// List of moved primitives
|
||||||
|
QList<CustomElementPart *> scaled_primitives_;
|
||||||
|
/// original rect items fit in
|
||||||
|
QRectF original_rect_;
|
||||||
|
/// new rect items should fit in
|
||||||
|
QRectF new_rect_;
|
||||||
|
/// Prevent the first call to redo()
|
||||||
|
bool first_redo;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
614
sources/editor/elementprimitivedecorator.cpp
Normal file
614
sources/editor/elementprimitivedecorator.cpp
Normal file
@@ -0,0 +1,614 @@
|
|||||||
|
#include "elementprimitivedecorator.h"
|
||||||
|
#include "elementscene.h"
|
||||||
|
#include "customelementpart.h"
|
||||||
|
#include "editorcommands.h"
|
||||||
|
#include "qet.h"
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QGraphicsSceneHoverEvent>
|
||||||
|
#include <QStyleOptionGraphicsItem>
|
||||||
|
#include <QGraphicsScene>
|
||||||
|
#include <QTransform>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor
|
||||||
|
@param parent Parent QGraphicsItem
|
||||||
|
*/
|
||||||
|
ElementPrimitiveDecorator::ElementPrimitiveDecorator(QGraphicsItem *parent):
|
||||||
|
QGraphicsObject(parent)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Destructor
|
||||||
|
*/
|
||||||
|
ElementPrimitiveDecorator::~ElementPrimitiveDecorator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the internal bouding rect, i.e. the smallest rectangle containing
|
||||||
|
the bounding rectangle of every selected item.
|
||||||
|
*/
|
||||||
|
QRectF ElementPrimitiveDecorator::internalBoundingRect() const {
|
||||||
|
if (!decorated_items_.count() || !scene()) return(QRectF());
|
||||||
|
|
||||||
|
QRectF rect = getSceneBoundingRect(decorated_items_.first() -> toItem());
|
||||||
|
foreach (CustomElementPart *item, decorated_items_) {
|
||||||
|
rect = rect.united(getSceneBoundingRect(item -> toItem()));
|
||||||
|
}
|
||||||
|
return(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the outer bounds of the decorator as a rectangle.
|
||||||
|
*/
|
||||||
|
QRectF ElementPrimitiveDecorator::boundingRect() const {
|
||||||
|
const qreal additional_margin = 2.5;
|
||||||
|
|
||||||
|
QRectF rect = effective_bounding_rect_;
|
||||||
|
rect.adjust(-additional_margin, -additional_margin, additional_margin, additional_margin);
|
||||||
|
return(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Paint the contents of an item in local coordinates, using \a painter, with
|
||||||
|
respect to \a option and
|
||||||
|
@param option The option parameter provides style options for the item, such
|
||||||
|
as its state, exposed area and its level-of-detail hints.
|
||||||
|
@param The widget argument is optional. If provided, it points to the
|
||||||
|
widget that is being painted on; otherwise, it is 0. For cached painting,
|
||||||
|
widget is always 0.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
|
||||||
|
Q_UNUSED(option)
|
||||||
|
Q_UNUSED(widget)
|
||||||
|
painter -> save();
|
||||||
|
|
||||||
|
// paint the original bounding rect
|
||||||
|
painter -> setPen(Qt::DashLine);
|
||||||
|
//QGraphicsItemGroup::paint(painter, option, widget);
|
||||||
|
painter -> drawRect(modified_bounding_rect_);
|
||||||
|
drawSquares(painter, option, widget);
|
||||||
|
|
||||||
|
// uncomment to draw the real bouding rect (=adjusted internal bounding rect)
|
||||||
|
// painter -> setBrush(QBrush(QColor(240, 0, 0, 127)));
|
||||||
|
// painter -> drawRect(boundingRect());
|
||||||
|
painter -> restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@param items the new list of items this decorator is suposed to manipulate.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::setItems(const QList<CustomElementPart *> &items) {
|
||||||
|
if (CustomElementPart *single_item = singleItem()) {
|
||||||
|
if (items.count() == 1 && items.first() == single_item) {
|
||||||
|
// no actual change
|
||||||
|
goto end_setItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// break any connection between the former single selected item (if any) and
|
||||||
|
// the decorator
|
||||||
|
single_item -> setDecorator(0);
|
||||||
|
if (QGraphicsObject *single_object = dynamic_cast<QGraphicsObject *>(single_item)) {
|
||||||
|
disconnect(single_object, 0, this, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decorated_items_ = items;
|
||||||
|
|
||||||
|
// when only a single primitive is selected, the decorator behaves specially
|
||||||
|
// to enable extra features, such as text edition, internal points movements,
|
||||||
|
// etc.
|
||||||
|
if (CustomElementPart *single_item = singleItem()) {
|
||||||
|
single_item -> setDecorator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
end_setItems:
|
||||||
|
adjust();
|
||||||
|
show();
|
||||||
|
grabKeyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@param items the new list of items this decorator is suposed to manipulate.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::setItems(const QList<QGraphicsItem *> &items) {
|
||||||
|
QList<CustomElementPart *> primitives;
|
||||||
|
foreach (QGraphicsItem *item, items) {
|
||||||
|
if (CustomElementPart *part_item = dynamic_cast<CustomElementPart *>(item)) {
|
||||||
|
primitives << part_item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setItems(primitives);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the list of items this decorator is supposed to manipulate
|
||||||
|
*/
|
||||||
|
QList<CustomElementPart *> ElementPrimitiveDecorator::items() const {
|
||||||
|
return(decorated_items_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the list of items this decorator is supposed to manipulate
|
||||||
|
*/
|
||||||
|
QList<QGraphicsItem *> ElementPrimitiveDecorator::graphicsItems() const {
|
||||||
|
QList<QGraphicsItem *> list;
|
||||||
|
foreach (CustomElementPart *part_item, decorated_items_) {
|
||||||
|
if (QGraphicsItem *item = dynamic_cast<QGraphicsItem *>(part_item)) {
|
||||||
|
list << item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adjust the visual decorator according to the currently assigned items.
|
||||||
|
It is notably called by setItems().
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::adjust() {
|
||||||
|
saveOriginalBoundingRect();
|
||||||
|
modified_bounding_rect_ = original_bounding_rect_;
|
||||||
|
adjustEffectiveBoundingRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Handle events generated when the mouse hovers over the decorator.
|
||||||
|
@param event Object describing the hover event.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
||||||
|
QList<QRectF> rects = getResizingSquares();
|
||||||
|
QPointF pos = event -> pos();
|
||||||
|
|
||||||
|
if (rects.at(QET::ResizeFromTopLeftCorner).contains(pos) || rects.at(QET::ResizeFromBottomRightCorner).contains(pos)) {
|
||||||
|
setCursor(Qt::SizeFDiagCursor);
|
||||||
|
} else if (rects.at(QET::ResizeFromTopRightCorner).contains(pos) || rects.at(QET::ResizeFromBottomLeftCorner).contains(pos)) {
|
||||||
|
setCursor(Qt::SizeBDiagCursor);
|
||||||
|
} else if (rects.at(QET::ResizeFromTopCenterCorner).contains(pos) || rects.at(QET::ResizeFromBottomCenterCorner).contains(pos)) {
|
||||||
|
setCursor(Qt::SizeVerCursor);
|
||||||
|
} else if (rects.at(QET::ResizeFromMiddleLeftCorner).contains(pos) || rects.at(QET::ResizeFromMiddleRightCorner).contains(pos)) {
|
||||||
|
setCursor(Qt::SizeHorCursor);
|
||||||
|
} else if (internalBoundingRect().contains(pos)) {
|
||||||
|
setCursor(Qt::SizeAllCursor);
|
||||||
|
} else {
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Handle event generated when mouse buttons are pressed.
|
||||||
|
@param event Object describing the mouse event
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
|
qDebug() << Q_FUNC_INFO << event << zValue();
|
||||||
|
QList<QRectF> rects = getResizingSquares();
|
||||||
|
QPointF pos = event -> pos();
|
||||||
|
|
||||||
|
current_operation_square_ = resizingSquareAtPos(pos);
|
||||||
|
bool accept = false;
|
||||||
|
if (current_operation_square_ != QET::NoOperation) {
|
||||||
|
accept = true;
|
||||||
|
} else {
|
||||||
|
if (internalBoundingRect().contains(pos)) {
|
||||||
|
if (CustomElementPart *single_item = singleItem()) {
|
||||||
|
bool event_accepted = single_item -> singleItemPressEvent(this, event);
|
||||||
|
if (event_accepted) {
|
||||||
|
event -> ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_operation_square_ = QET::MoveArea;
|
||||||
|
accept = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accept) {
|
||||||
|
if (current_operation_square_ > QET::NoOperation) {
|
||||||
|
first_pos_ = latest_pos_ = mapToScene(rects.at(current_operation_square_).center());
|
||||||
|
} else {
|
||||||
|
first_pos_ = decorated_items_.at(0) -> toItem() -> scenePos();
|
||||||
|
latest_pos_ = event -> scenePos();
|
||||||
|
mouse_offset_ = event -> scenePos() - first_pos_;
|
||||||
|
}
|
||||||
|
startMovement();
|
||||||
|
event -> accept();
|
||||||
|
} else {
|
||||||
|
event -> ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Handle events generated when mouse buttons are double clicked.
|
||||||
|
@param event Object describing the mouse event
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
|
//QGraphicsObject::mouseDoubleClickEvent(event);
|
||||||
|
if (CustomElementPart *single_item = singleItem()) {
|
||||||
|
bool event_accepted = single_item -> singleItemDoubleClickEvent(this, event);
|
||||||
|
if (event_accepted) {
|
||||||
|
event -> ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Handle event generated when the mouse is moved and the decorator is the mouse grabber item.
|
||||||
|
@param event Object describing the mouse event
|
||||||
|
@see QGraphicsScene::mouseGrabberItem()
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
|
QList<QRectF> rects = getResizingSquares();
|
||||||
|
|
||||||
|
QPointF scene_pos = event -> scenePos();
|
||||||
|
QPointF movement = scene_pos - latest_pos_;
|
||||||
|
|
||||||
|
// snap the movement to a non-visible grid when scaling selection
|
||||||
|
if (mustSnapToGrid(event)) {
|
||||||
|
// We now want some point belonging to the selection to be snapped to this rounded position
|
||||||
|
if (current_operation_square_ > QET::NoOperation) {
|
||||||
|
// real, non-rounded movement from the mouse press event
|
||||||
|
QPointF global_movement = scene_pos - first_pos_;
|
||||||
|
|
||||||
|
// real, rounded movement from the mouse press event
|
||||||
|
QPointF rounded_global_movement = snapConstPointToGrid(global_movement);
|
||||||
|
|
||||||
|
// rounded position of the current mouse move event
|
||||||
|
QPointF rounded_scene_pos = first_pos_ + rounded_global_movement;
|
||||||
|
|
||||||
|
// when scaling the selection, consider the center of the currently dragged resizing rectangle
|
||||||
|
QPointF current_position = mapToScene(rects.at(current_operation_square_).center());
|
||||||
|
// determine the final, effective movement
|
||||||
|
movement = rounded_scene_pos - current_position;
|
||||||
|
} else if (current_operation_square_ == QET::MoveArea) {
|
||||||
|
// when moving the selection, consider the position of the first selected item
|
||||||
|
QPointF current_position = scene_pos - mouse_offset_;
|
||||||
|
QPointF rounded_current_position = snapConstPointToGrid(current_position);
|
||||||
|
movement = rounded_current_position - decorated_items_.at(0) -> toItem() -> scenePos();
|
||||||
|
} else {
|
||||||
|
if (CustomElementPart *single_item = singleItem()) {
|
||||||
|
bool event_accepted = single_item -> singleItemMoveEvent(this, event);
|
||||||
|
if (event_accepted) {
|
||||||
|
event -> ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF bounding_rect = modified_bounding_rect_;
|
||||||
|
applyMovementToRect(current_operation_square_, movement, modified_bounding_rect_);
|
||||||
|
if (modified_bounding_rect_ != bounding_rect) {
|
||||||
|
adjustEffectiveBoundingRect();
|
||||||
|
}
|
||||||
|
latest_pos_ = event -> scenePos();
|
||||||
|
|
||||||
|
if (current_operation_square_ == QET::MoveArea) {
|
||||||
|
translateItems(movement);
|
||||||
|
} else {
|
||||||
|
scaleItems(original_bounding_rect_, modified_bounding_rect_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Handle event generated when a mouse buttons are releaseis moved and the
|
||||||
|
decorator is the mouse grabber item.
|
||||||
|
@param event Object describing the mouse event
|
||||||
|
@see QGraphicsScene::mouseGrabberItem()
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
|
Q_UNUSED(event)
|
||||||
|
|
||||||
|
ElementEditionCommand *command = 0;
|
||||||
|
if (current_operation_square_ > QET::NoOperation) {
|
||||||
|
ScalePartsCommand *scale_command = new ScalePartsCommand();
|
||||||
|
scale_command -> setScaledPrimitives(items());
|
||||||
|
scale_command -> setTransformation(
|
||||||
|
mapToScene(original_bounding_rect_).boundingRect(),
|
||||||
|
mapToScene(modified_bounding_rect_).boundingRect()
|
||||||
|
);
|
||||||
|
command = scale_command;
|
||||||
|
} else if (current_operation_square_ == QET::MoveArea) {
|
||||||
|
QPointF movement = mapToScene(modified_bounding_rect_.topLeft()) - mapToScene(original_bounding_rect_.topLeft());
|
||||||
|
if (!movement.isNull()) {
|
||||||
|
MovePartsCommand *move_command = new MovePartsCommand(movement, 0, graphicsItems());
|
||||||
|
command = move_command;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (CustomElementPart *single_item = singleItem()) {
|
||||||
|
bool event_accepted = single_item -> singleItemReleaseEvent(this, event);
|
||||||
|
if (event_accepted) {
|
||||||
|
event -> ignore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command) {
|
||||||
|
emit(actionFinished(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_operation_square_ != QET::NoOperation) {
|
||||||
|
adjust();
|
||||||
|
}
|
||||||
|
|
||||||
|
current_operation_square_ = QET::NoOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize an ElementPrimitiveDecorator
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::init() {
|
||||||
|
//setAcceptedMouseButtons(Qt::LeftButton);
|
||||||
|
grid_step_x_ = grid_step_y_ = 1;
|
||||||
|
setAcceptHoverEvents(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Save the original bounding rectangle.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::saveOriginalBoundingRect() {
|
||||||
|
original_bounding_rect_ = internalBoundingRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adjust the effective bounding rect. This method should be called after the
|
||||||
|
modified_bouding_rect_ attribute was modified.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::adjustEffectiveBoundingRect() {
|
||||||
|
prepareGeometryChange();
|
||||||
|
effective_bounding_rect_ = modified_bounding_rect_ | effective_bounding_rect_;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Start a movement (i.e. either a move or scaling operation)
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::startMovement() {
|
||||||
|
adjust();
|
||||||
|
|
||||||
|
foreach(CustomElementPart *item, decorated_items_) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "starting movement with rect" << original_bounding_rect_ << "i.e. in scene coordinates " << mapToScene(original_bounding_rect_).boundingRect();
|
||||||
|
item -> startUserTransformation(mapToScene(original_bounding_rect_).boundingRect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Apply the movement described by \a movement_type and \a movement to \a rect.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::applyMovementToRect(int movement_type, const QPointF &movement, QRectF &rect) {
|
||||||
|
qreal new_value;
|
||||||
|
QPointF new_point;
|
||||||
|
|
||||||
|
switch (movement_type) {
|
||||||
|
case QET::MoveArea:
|
||||||
|
rect.translate(movement.x(), movement.y());
|
||||||
|
break;
|
||||||
|
case QET::ResizeFromTopLeftCorner:
|
||||||
|
new_point = rect.topLeft() + movement;
|
||||||
|
rect.setTopLeft(new_point);
|
||||||
|
break;
|
||||||
|
case QET::ResizeFromTopCenterCorner:
|
||||||
|
new_value = rect.top() + movement.y();
|
||||||
|
rect.setTop(new_value);
|
||||||
|
break;
|
||||||
|
case QET::ResizeFromTopRightCorner:
|
||||||
|
new_point = rect.topRight() + movement;
|
||||||
|
rect.setTopRight(new_point);
|
||||||
|
break;
|
||||||
|
case QET::ResizeFromMiddleLeftCorner:
|
||||||
|
new_value = rect.left() + movement.x();
|
||||||
|
rect.setLeft(new_value);
|
||||||
|
break;
|
||||||
|
case QET::ResizeFromMiddleRightCorner:
|
||||||
|
new_value = rect.right() + movement.x();
|
||||||
|
rect.setRight(new_value);
|
||||||
|
break;
|
||||||
|
case QET::ResizeFromBottomLeftCorner:
|
||||||
|
new_point = rect.bottomLeft() + movement;
|
||||||
|
rect.setBottomLeft(new_point);
|
||||||
|
break;
|
||||||
|
case QET::ResizeFromBottomCenterCorner:
|
||||||
|
new_value = rect.bottom() + movement.y();
|
||||||
|
rect.setBottom(new_value);
|
||||||
|
break;
|
||||||
|
case QET::ResizeFromBottomRightCorner:
|
||||||
|
new_point = rect.bottomRight() + movement;
|
||||||
|
rect.setBottomRight(new_point);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomElementPart *ElementPrimitiveDecorator::singleItem() const {
|
||||||
|
if (decorated_items_.count() == 1) {
|
||||||
|
return(decorated_items_.first());
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Translated the managed items by the \a movement
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::translateItems(const QPointF &movement) {
|
||||||
|
if (!decorated_items_.count()) return;
|
||||||
|
|
||||||
|
foreach(QGraphicsItem *qgi, graphicsItems()) {
|
||||||
|
// this is a naive, proof-of-concept implementation; we actually need to take
|
||||||
|
// the grid into account and create a command object in mouseReleaseEvent()
|
||||||
|
qgi -> moveBy(movement.x(), movement.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Scale the managed items, provided they originally fit within \a
|
||||||
|
original_rect and they should now fit \a new_rect
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::scaleItems(const QRectF &original_rect, const QRectF &new_rect) {
|
||||||
|
if (!decorated_items_.count()) return;
|
||||||
|
if (original_rect == new_rect) return;
|
||||||
|
if (!original_rect.width() || !original_rect.height()) return; // cowardly flee division by zero FIXME?
|
||||||
|
|
||||||
|
QRectF scene_original_rect = mapToScene(original_rect).boundingRect();
|
||||||
|
QRectF scene_new_rect = mapToScene(new_rect).boundingRect();
|
||||||
|
qDebug() << Q_FUNC_INFO << "from " << original_rect << " to " << new_rect;
|
||||||
|
qDebug() << Q_FUNC_INFO << "from " << scene_original_rect << " to " << scene_new_rect << "(scene coordinates)";
|
||||||
|
|
||||||
|
foreach(CustomElementPart *item, decorated_items_) {
|
||||||
|
item -> handleUserTransformation(scene_original_rect, scene_new_rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the bounding rectangle of \a item, in scene coordinates
|
||||||
|
*/
|
||||||
|
QRectF ElementPrimitiveDecorator::getSceneBoundingRect(QGraphicsItem *item) const {
|
||||||
|
if (!item) return(QRectF());
|
||||||
|
return(item -> mapRectToScene(item -> boundingRect()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Draw all known resizing squares using \a painter.
|
||||||
|
@param option The option parameter provides style options for the item, such
|
||||||
|
as its state, exposed area and its level-of-detail hints.
|
||||||
|
@param The widget argument is optional. If provided, it points to the
|
||||||
|
widget that is being painted on; otherwise, it is 0. For cached painting,
|
||||||
|
widget is always 0.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::drawSquares(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
|
||||||
|
foreach (QRectF rect, getResizingSquares()) {
|
||||||
|
drawResizeSquare(painter, option, widget, rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Draw the provided resizing square \a rect using \a painter.
|
||||||
|
@param option The option parameter provides style options for the item, such
|
||||||
|
as its state, exposed area and its level-of-detail hints.
|
||||||
|
@param The widget argument is optional. If provided, it points to the
|
||||||
|
widget that is being painted on; otherwise, it is 0. For cached painting,
|
||||||
|
widget is always 0.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::drawResizeSquare(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget, const QRectF &rect) {
|
||||||
|
QColor inner(0xFF, 0xFF, 0xFF);
|
||||||
|
QColor outer(0x00, 0x61, 0xFF);
|
||||||
|
if (decorated_items_.count() > 1) {
|
||||||
|
outer = QColor(0x1A, 0x5C, 0x14);
|
||||||
|
}
|
||||||
|
drawGenericSquare(painter, option, widget, rect, inner, outer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Draw a generic square \a rect using \a painter.
|
||||||
|
@param inner Color used to fill the square
|
||||||
|
@param outer Color usd to draw the outline
|
||||||
|
@param option The option parameter provides style options for the item, such
|
||||||
|
as its state, exposed area and its level-of-detail hints.
|
||||||
|
@param The widget argument is optional. If provided, it points to the
|
||||||
|
widget that is being painted on; otherwise, it is 0. For cached painting,
|
||||||
|
widget is always 0.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::drawGenericSquare(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget, const QRectF &rect, const QColor &inner, const QColor &outer) {
|
||||||
|
Q_UNUSED(option)
|
||||||
|
Q_UNUSED(widget)
|
||||||
|
// 1.0px will end up to level_of_details px once rendered
|
||||||
|
// qreal level_of_details = option->levelOfDetailFromTransform(painter -> transform());
|
||||||
|
|
||||||
|
painter -> save();
|
||||||
|
painter -> setBrush(QBrush(inner));
|
||||||
|
QPen square_pen(QBrush(outer), 2.0, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
|
||||||
|
square_pen.setCosmetic(true);
|
||||||
|
painter -> setPen(square_pen);
|
||||||
|
painter -> drawRect(rect);
|
||||||
|
painter -> restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return A list containing all known resizing squares, based on the
|
||||||
|
modified_bounding_rect_ attribute. They are ordered following
|
||||||
|
QET::OperationAreas, so it is possible to use positive values from this enum
|
||||||
|
to fetch the corresponding square in the list.
|
||||||
|
@see QET::OperationAreas
|
||||||
|
*/
|
||||||
|
QList<QRectF> ElementPrimitiveDecorator::getResizingSquares() {
|
||||||
|
QRectF primitive_rect = modified_bounding_rect_;
|
||||||
|
QRectF half_primitive_rect1 = primitive_rect;
|
||||||
|
half_primitive_rect1.setHeight(half_primitive_rect1.height() / 2.0);
|
||||||
|
QRectF half_primitive_rect2 = primitive_rect;
|
||||||
|
half_primitive_rect2.setWidth(half_primitive_rect2.width() / 2.0);
|
||||||
|
|
||||||
|
QList<QRectF> rects;
|
||||||
|
|
||||||
|
rects << getGenericSquare(primitive_rect.topLeft());
|
||||||
|
rects << getGenericSquare(half_primitive_rect2.topRight());
|
||||||
|
rects << getGenericSquare(primitive_rect.topRight());
|
||||||
|
rects << getGenericSquare(half_primitive_rect1.bottomLeft());
|
||||||
|
rects << getGenericSquare(half_primitive_rect1.bottomRight());
|
||||||
|
rects << getGenericSquare(primitive_rect.bottomLeft());
|
||||||
|
rects << getGenericSquare(half_primitive_rect2.bottomRight());
|
||||||
|
rects << getGenericSquare(primitive_rect.bottomRight());
|
||||||
|
|
||||||
|
/// TODO cache the rects instead of calculating them again and again?
|
||||||
|
return(rects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the square to be drawn to represent \a position
|
||||||
|
*/
|
||||||
|
QRectF ElementPrimitiveDecorator::getGenericSquare(const QPointF &position) {
|
||||||
|
const qreal square_half_size = 0.5;
|
||||||
|
return(
|
||||||
|
QRectF(
|
||||||
|
position.x() - square_half_size,
|
||||||
|
position.y() - square_half_size,
|
||||||
|
square_half_size * 2.0,
|
||||||
|
square_half_size * 2.0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the index of the square containing the \a position point or -1 if
|
||||||
|
none matches.
|
||||||
|
*/
|
||||||
|
int ElementPrimitiveDecorator::resizingSquareAtPos(const QPointF &position) {
|
||||||
|
QList<QRectF> rects = getResizingSquares();
|
||||||
|
int current_square = QET::NoOperation;
|
||||||
|
for (int i = 0 ; i < rects.count() ; ++ i) {
|
||||||
|
if (rects.at(i).contains(position)) {
|
||||||
|
current_square = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(current_square);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Round the coordinates of \a point so it is snapped to the grid defined by the
|
||||||
|
grid_step_x_ and grid_step_y_ attributes.
|
||||||
|
*/
|
||||||
|
QPointF ElementPrimitiveDecorator::snapConstPointToGrid(const QPointF &point) const {
|
||||||
|
return(
|
||||||
|
QPointF(
|
||||||
|
qRound(point.x() / grid_step_x_) * grid_step_x_,
|
||||||
|
qRound(point.y() / grid_step_y_) * grid_step_y_
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Round the coordinates of \a point so it is snapped to the grid defined by the
|
||||||
|
grid_step_x_ and grid_step_y_ attributes.
|
||||||
|
*/
|
||||||
|
void ElementPrimitiveDecorator::snapPointToGrid(QPointF &point) const {
|
||||||
|
point.rx() = qRound(point.x() / grid_step_x_) * grid_step_x_;
|
||||||
|
point.ry() = qRound(point.y() / grid_step_y_) * grid_step_y_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return whether the current operation should take the grid into account
|
||||||
|
according to the state of the provided \a event
|
||||||
|
*/
|
||||||
|
bool ElementPrimitiveDecorator::mustSnapToGrid(QGraphicsSceneMouseEvent *event) {
|
||||||
|
return(!(event -> modifiers() & Qt::ControlModifier));
|
||||||
|
}
|
||||||
90
sources/editor/elementprimitivedecorator.h
Normal file
90
sources/editor/elementprimitivedecorator.h
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#ifndef ELEMENTPRIMITIVEDECORATOR_H
|
||||||
|
#define ELEMENTPRIMITIVEDECORATOR_H
|
||||||
|
#include <QGraphicsObject>
|
||||||
|
class ElementEditionCommand;
|
||||||
|
class ElementScene;
|
||||||
|
class CustomElementPart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
This class represents a decorator rendered above selected items so users
|
||||||
|
can manipulate (move, resize, ...) them.
|
||||||
|
|
||||||
|
The implementation considers four kinds of bounding rects:
|
||||||
|
- the actual, effective bounding rect as returned by the boundingRect() method
|
||||||
|
- the original bounding rect, i.e. the rect containing all selected items at
|
||||||
|
the beginning of operations (or after a command object was generated)
|
||||||
|
- the new bounding rect, after the user moved or resized items
|
||||||
|
- the former bounding rect, due to implementation details
|
||||||
|
*/
|
||||||
|
class ElementPrimitiveDecorator : public QGraphicsObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ElementPrimitiveDecorator(QGraphicsItem * = 0);
|
||||||
|
virtual ~ElementPrimitiveDecorator();
|
||||||
|
|
||||||
|
enum { Type = UserType + 2200 };
|
||||||
|
|
||||||
|
// methods
|
||||||
|
QRectF internalBoundingRect() const;
|
||||||
|
virtual QRectF boundingRect () const;
|
||||||
|
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0);
|
||||||
|
virtual int type() const { return Type; }
|
||||||
|
void setItems(const QList<QGraphicsItem *> &);
|
||||||
|
void setItems(const QList<CustomElementPart *> &);
|
||||||
|
QList<CustomElementPart *> items() const;
|
||||||
|
QList<QGraphicsItem *> graphicsItems() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void adjust();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void actionFinished(ElementEditionCommand *);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void hoverMoveEvent(QGraphicsSceneHoverEvent *);
|
||||||
|
void mousePressEvent(QGraphicsSceneMouseEvent *);
|
||||||
|
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
|
||||||
|
void mouseMoveEvent(QGraphicsSceneMouseEvent *);
|
||||||
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
|
||||||
|
QPointF snapConstPointToGrid(const QPointF &) const;
|
||||||
|
void snapPointToGrid(QPointF &) const;
|
||||||
|
bool mustSnapToGrid(QGraphicsSceneMouseEvent *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
void saveOriginalBoundingRect();
|
||||||
|
void adjustEffectiveBoundingRect();
|
||||||
|
void startMovement();
|
||||||
|
void applyMovementToRect(int, const QPointF &, QRectF &);
|
||||||
|
CustomElementPart *singleItem() const;
|
||||||
|
void translateItems(const QPointF &);
|
||||||
|
void scaleItems(const QRectF &, const QRectF &);
|
||||||
|
QRectF getSceneBoundingRect(QGraphicsItem *) const;
|
||||||
|
void drawSquares(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||||
|
void drawResizeSquare(QPainter *, const QStyleOptionGraphicsItem *, QWidget *, const QRectF &);
|
||||||
|
void drawGenericSquare(QPainter *, const QStyleOptionGraphicsItem *, QWidget *, const QRectF &, const QColor &, const QColor &);
|
||||||
|
QList<QRectF> getResizingSquares();
|
||||||
|
QRectF getGenericSquare(const QPointF &);
|
||||||
|
int resizingSquareAtPos(const QPointF &);
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
private:
|
||||||
|
QList<CustomElementPart *> decorated_items_;
|
||||||
|
QRectF effective_bounding_rect_; ///< actual, effective bounding rect -- never shrinks
|
||||||
|
QRectF original_bounding_rect_; ///< original bounding rect
|
||||||
|
QRectF modified_bounding_rect_; ///< new bounding rect, after the user moved or resized items
|
||||||
|
|
||||||
|
/**
|
||||||
|
Index of the square leading the current operation (resizing, etc.) or -1 if no
|
||||||
|
operation is occurring, -2 for a move operation.
|
||||||
|
*/
|
||||||
|
int current_operation_square_;
|
||||||
|
int grid_step_x_; ///< Grid horizontal step
|
||||||
|
int grid_step_y_; ///< Grid horizontal step
|
||||||
|
QPointF first_pos_; ///< First point involved within the current resizing operation
|
||||||
|
QPointF latest_pos_; ///< Latest point involved within the current resizing operation
|
||||||
|
QPointF mouse_offset_; ///< Offset between the mouse position and the point to be snapped to grid when moving selection
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "elementscene.h"
|
#include "elementscene.h"
|
||||||
#include "qetelementeditor.h"
|
#include "qetelementeditor.h"
|
||||||
|
#include "elementprimitivedecorator.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "partline.h"
|
#include "partline.h"
|
||||||
#include "partrectangle.h"
|
#include "partrectangle.h"
|
||||||
@@ -44,17 +45,22 @@ ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) :
|
|||||||
_hotspot(15, 35),
|
_hotspot(15, 35),
|
||||||
internal_connections(false),
|
internal_connections(false),
|
||||||
qgi_manager(this),
|
qgi_manager(this),
|
||||||
element_editor(editor)
|
element_editor(editor),
|
||||||
|
decorator_(0)
|
||||||
{
|
{
|
||||||
setItemIndexMethod(NoIndex);
|
setItemIndexMethod(NoIndex);
|
||||||
current_polygon = NULL;
|
current_polygon = NULL;
|
||||||
setGrid(1, 1);
|
setGrid(1, 1);
|
||||||
initPasteArea();
|
initPasteArea();
|
||||||
undo_stack.setClean();
|
undo_stack.setClean();
|
||||||
|
decorator_lock_ = new QMutex(QMutex::NonRecursive);
|
||||||
|
connect(&undo_stack, SIGNAL(indexChanged(int)), this, SLOT(managePrimitivesGroups()));
|
||||||
|
connect(this, SIGNAL(selectionChanged()), this, SLOT(managePrimitivesGroups()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructeur
|
/// Destructeur
|
||||||
ElementScene::~ElementScene() {
|
ElementScene::~ElementScene() {
|
||||||
|
delete decorator_lock_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -187,25 +193,7 @@ void ElementScene::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
|
|||||||
break;
|
break;
|
||||||
case Normal:
|
case Normal:
|
||||||
default:
|
default:
|
||||||
QList<QGraphicsItem *> selected_items = selectedItems();
|
QGraphicsScene::mouseMoveEvent(e);
|
||||||
if (!selected_items.isEmpty()) {
|
|
||||||
// mouvement de souris realise depuis le dernier press event
|
|
||||||
QPointF mouse_movement = e -> scenePos() - moving_press_pos;
|
|
||||||
|
|
||||||
// application de ce mouvement a la fsi_pos enregistre dans le dernier press event
|
|
||||||
QPointF new_fsi_pos = fsi_pos + mouse_movement;
|
|
||||||
|
|
||||||
// snap eventuel de la nouvelle fsi_pos
|
|
||||||
if (mustSnapToGrid(e)) snapToGrid(new_fsi_pos);
|
|
||||||
|
|
||||||
// difference entre la fsi_pos finale et la fsi_pos courante = mouvement a appliquer
|
|
||||||
|
|
||||||
QPointF current_fsi_pos = selected_items.first() -> scenePos();
|
|
||||||
QPointF final_movement = new_fsi_pos - current_fsi_pos;
|
|
||||||
foreach(QGraphicsItem *qgi, selected_items) {
|
|
||||||
qgi -> moveBy(final_movement.x(), final_movement.y());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (behavior == Polygon && current_polygon != NULL) {
|
} else if (behavior == Polygon && current_polygon != NULL) {
|
||||||
temp_polygon = current_polygon -> polygon();
|
temp_polygon = current_polygon -> polygon();
|
||||||
@@ -263,16 +251,6 @@ void ElementScene::mousePressEvent(QGraphicsSceneMouseEvent *e) {
|
|||||||
case Normal:
|
case Normal:
|
||||||
default:
|
default:
|
||||||
QGraphicsScene::mousePressEvent(e);
|
QGraphicsScene::mousePressEvent(e);
|
||||||
// gestion des deplacements de parties
|
|
||||||
if (!selectedItems().isEmpty()) {
|
|
||||||
fsi_pos = selectedItems().first() -> scenePos();
|
|
||||||
moving_press_pos = e -> scenePos();
|
|
||||||
moving_parts_ = true;
|
|
||||||
} else {
|
|
||||||
fsi_pos = QPoint();
|
|
||||||
moving_press_pos = QPoint();
|
|
||||||
moving_parts_ = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else QGraphicsScene::mousePressEvent(e);
|
} else QGraphicsScene::mousePressEvent(e);
|
||||||
}
|
}
|
||||||
@@ -358,12 +336,6 @@ void ElementScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) {
|
|||||||
case Normal:
|
case Normal:
|
||||||
default:
|
default:
|
||||||
// detecte les deplacements de parties
|
// detecte les deplacements de parties
|
||||||
if (!selectedItems().isEmpty() && moving_parts_) {
|
|
||||||
QPointF movement = selectedItems().first() -> scenePos() - fsi_pos;
|
|
||||||
if (!movement.isNull()) {
|
|
||||||
undo_stack.push(new MovePartsCommand(movement, this, selectedItems()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QGraphicsScene::mouseReleaseEvent(e);
|
QGraphicsScene::mouseReleaseEvent(e);
|
||||||
moving_parts_ = false;
|
moving_parts_ = false;
|
||||||
}
|
}
|
||||||
@@ -657,7 +629,7 @@ QRectF ElementScene::borderRect() const {
|
|||||||
*/
|
*/
|
||||||
QRectF ElementScene::sceneContent() const {
|
QRectF ElementScene::sceneContent() const {
|
||||||
qreal adjustment = 5.0;
|
qreal adjustment = 5.0;
|
||||||
return(itemsBoundingRect().unite(borderRect()).adjusted(-adjustment, -adjustment, adjustment, adjustment));
|
return(elementContentBoundingRect(items()).unite(borderRect()).adjusted(-adjustment, -adjustment, adjustment, adjustment));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -666,7 +638,7 @@ QRectF ElementScene::sceneContent() const {
|
|||||||
l'element.
|
l'element.
|
||||||
*/
|
*/
|
||||||
bool ElementScene::borderContainsEveryParts() const {
|
bool ElementScene::borderContainsEveryParts() const {
|
||||||
return(borderRect().contains(itemsBoundingRect()));
|
return(borderRect().contains(elementContentBoundingRect(items())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -800,7 +772,10 @@ void ElementScene::slot_delete() {
|
|||||||
|
|
||||||
// efface tout ce qui est selectionne
|
// efface tout ce qui est selectionne
|
||||||
undo_stack.push(new DeletePartsCommand(this, selected_items));
|
undo_stack.push(new DeletePartsCommand(this, selected_items));
|
||||||
|
|
||||||
|
// removing items does not trigger QGraphicsScene::selectionChanged()
|
||||||
emit(partsRemoved());
|
emit(partsRemoved());
|
||||||
|
emit(selectionChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -825,7 +800,7 @@ void ElementScene::slot_editSizeHotSpot() {
|
|||||||
hotspot_editor -> setElementHeight(static_cast<uint>(height() / 10));
|
hotspot_editor -> setElementHeight(static_cast<uint>(height() / 10));
|
||||||
hotspot_editor -> setHotspot(hotspot());
|
hotspot_editor -> setHotspot(hotspot());
|
||||||
hotspot_editor -> setOldHotspot(hotspot());
|
hotspot_editor -> setOldHotspot(hotspot());
|
||||||
hotspot_editor -> setPartsRect(itemsBoundingRect());
|
hotspot_editor -> setPartsRect(elementContentBoundingRect(items()));
|
||||||
hotspot_editor -> setPartsRectEnabled(true);
|
hotspot_editor -> setPartsRectEnabled(true);
|
||||||
hotspot_editor -> setReadOnly(is_read_only);
|
hotspot_editor -> setReadOnly(is_read_only);
|
||||||
dialog_layout -> addWidget(hotspot_editor);
|
dialog_layout -> addWidget(hotspot_editor);
|
||||||
@@ -1021,6 +996,19 @@ void ElementScene::slot_sendBackward() {
|
|||||||
emit(partsZValueChanged());
|
emit(partsZValueChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the list of primitives currently present on the scene.
|
||||||
|
*/
|
||||||
|
QList<CustomElementPart *> ElementScene::primitives() const {
|
||||||
|
QList<CustomElementPart *> primitives_list;
|
||||||
|
foreach (QGraphicsItem *item, items()) {
|
||||||
|
if (CustomElementPart *primitive = dynamic_cast<CustomElementPart *>(item)) {
|
||||||
|
primitives_list << primitive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(primitives_list);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@param include_terminals true pour inclure les bornes, false sinon
|
@param include_terminals true pour inclure les bornes, false sinon
|
||||||
@return les parties de l'element ordonnes par zValue croissante
|
@return les parties de l'element ordonnes par zValue croissante
|
||||||
@@ -1032,7 +1020,13 @@ QList<QGraphicsItem *> ElementScene::zItems(bool include_terminals) const {
|
|||||||
// enleve les bornes
|
// enleve les bornes
|
||||||
QList<QGraphicsItem *> terminals;
|
QList<QGraphicsItem *> terminals;
|
||||||
foreach(QGraphicsItem *qgi, all_items_list) {
|
foreach(QGraphicsItem *qgi, all_items_list) {
|
||||||
if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
if (
|
||||||
|
qgi -> type() == ElementPrimitiveDecorator::Type ||
|
||||||
|
qgi -> type() == QGraphicsRectItem::Type
|
||||||
|
) {
|
||||||
|
all_items_list.removeAt(all_items_list.indexOf(qgi));
|
||||||
|
}
|
||||||
|
else if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
||||||
all_items_list.removeAt(all_items_list.indexOf(qgi));
|
all_items_list.removeAt(all_items_list.indexOf(qgi));
|
||||||
terminals << qgi;
|
terminals << qgi;
|
||||||
}
|
}
|
||||||
@@ -1089,9 +1083,12 @@ void ElementScene::reset() {
|
|||||||
@return le boundingRect de ces parties, exprime dans les coordonnes de la
|
@return le boundingRect de ces parties, exprime dans les coordonnes de la
|
||||||
scene
|
scene
|
||||||
*/
|
*/
|
||||||
QRectF ElementScene::elementContentBoundingRect(const ElementContent &content) {
|
QRectF ElementScene::elementContentBoundingRect(const ElementContent &content) const {
|
||||||
QRectF bounding_rect;
|
QRectF bounding_rect;
|
||||||
foreach(QGraphicsItem *qgi, content) {
|
foreach(QGraphicsItem *qgi, content) {
|
||||||
|
// skip non-primitives QGraphicsItems (paste area, selection decorator)
|
||||||
|
if (qgi -> type() == ElementPrimitiveDecorator::Type) continue;
|
||||||
|
if (qgi -> type() == QGraphicsRectItem::Type) continue;
|
||||||
bounding_rect |= qgi -> sceneBoundingRect();
|
bounding_rect |= qgi -> sceneBoundingRect();
|
||||||
}
|
}
|
||||||
return(bounding_rect);
|
return(bounding_rect);
|
||||||
@@ -1225,7 +1222,7 @@ ElementContent ElementScene::loadContent(const QDomDocument &xml_document, QStri
|
|||||||
ElementContent ElementScene::addContent(const ElementContent &content, QString *error_message) {
|
ElementContent ElementScene::addContent(const ElementContent &content, QString *error_message) {
|
||||||
Q_UNUSED(error_message);
|
Q_UNUSED(error_message);
|
||||||
foreach(QGraphicsItem *part, content) {
|
foreach(QGraphicsItem *part, content) {
|
||||||
addItem(part);
|
addPrimitive(part);
|
||||||
}
|
}
|
||||||
return(content);
|
return(content);
|
||||||
}
|
}
|
||||||
@@ -1249,11 +1246,20 @@ ElementContent ElementScene::addContentAtPos(const ElementContent &content, cons
|
|||||||
// ajoute les parties avec le decalage adequat
|
// ajoute les parties avec le decalage adequat
|
||||||
foreach(QGraphicsItem *part, content) {
|
foreach(QGraphicsItem *part, content) {
|
||||||
part -> setPos(part -> pos() + offset);
|
part -> setPos(part -> pos() + offset);
|
||||||
addItem(part);
|
addPrimitive(part);
|
||||||
}
|
}
|
||||||
return(content);
|
return(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Add a primitive to the scene by wrapping it within an
|
||||||
|
ElementPrimitiveDecorator group.
|
||||||
|
*/
|
||||||
|
void ElementScene::addPrimitive(QGraphicsItem *primitive) {
|
||||||
|
if (!primitive) return;
|
||||||
|
addItem(primitive);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initialise la zone de collage
|
Initialise la zone de collage
|
||||||
*/
|
*/
|
||||||
@@ -1300,3 +1306,61 @@ bool ElementScene::mustSnapToGrid(QGraphicsSceneMouseEvent *e) {
|
|||||||
bool ElementScene::zValueLessThan(QGraphicsItem *item1, QGraphicsItem *item2) {
|
bool ElementScene::zValueLessThan(QGraphicsItem *item1, QGraphicsItem *item2) {
|
||||||
return(item1-> zValue() < item2 -> zValue());
|
return(item1-> zValue() < item2 -> zValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Ensure the decorator is adequately shown, hidden or updated so it always
|
||||||
|
represents the current selection.
|
||||||
|
*/
|
||||||
|
void ElementScene::managePrimitivesGroups() {
|
||||||
|
if (!decorator_lock_ -> tryLock()) return;
|
||||||
|
|
||||||
|
if (!decorator_) {
|
||||||
|
decorator_ = new ElementPrimitiveDecorator();
|
||||||
|
connect(decorator_, SIGNAL(actionFinished(ElementEditionCommand*)), this, SLOT(stackAction(ElementEditionCommand *)));
|
||||||
|
addItem(decorator_);
|
||||||
|
decorator_ -> hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QGraphicsItem *> selected_items;
|
||||||
|
foreach (QGraphicsItem *item, items()) {
|
||||||
|
if (item -> type() == ElementPrimitiveDecorator::Type) continue;
|
||||||
|
if (item -> type() == QGraphicsRectItem::Type) continue;
|
||||||
|
if (item -> isSelected()) {
|
||||||
|
selected_items << item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// TODO export the above code to a proper method
|
||||||
|
|
||||||
|
|
||||||
|
// should we hide the decorator?
|
||||||
|
if (!selected_items.count()) {
|
||||||
|
decorator_ -> hide();
|
||||||
|
} else {
|
||||||
|
decorator_ -> setZValue(1000000);
|
||||||
|
decorator_ -> setPos(0, 0);
|
||||||
|
decorator_ -> setItems(selected_items);
|
||||||
|
}
|
||||||
|
decorator_lock_ -> unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Push the provided \a command on the undo stack.
|
||||||
|
*/
|
||||||
|
void ElementScene::stackAction(ElementEditionCommand *command) {
|
||||||
|
if (command -> elementScene()) {
|
||||||
|
if (command -> elementScene() != this) return;
|
||||||
|
} else {
|
||||||
|
command -> setElementScene(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!command -> elementView()) {
|
||||||
|
foreach (QGraphicsView *view, views()) {
|
||||||
|
if (ElementView *element_view = dynamic_cast<ElementView *>(view)) {
|
||||||
|
command -> setElementView(element_view);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
undoStack().push(command);
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@
|
|||||||
#include "orientationsetwidget.h"
|
#include "orientationsetwidget.h"
|
||||||
#include "qgimanager.h"
|
#include "qgimanager.h"
|
||||||
#include "elementcontent.h"
|
#include "elementcontent.h"
|
||||||
|
class CustomElementPart;
|
||||||
|
class ElementEditionCommand;
|
||||||
|
class ElementPrimitiveDecorator;
|
||||||
class QETElementEditor;
|
class QETElementEditor;
|
||||||
class PartLine;
|
class PartLine;
|
||||||
class PartRectangle;
|
class PartRectangle;
|
||||||
@@ -95,6 +98,9 @@ class ElementScene : public QGraphicsScene {
|
|||||||
/// Variables to handle copy/paste with offset
|
/// Variables to handle copy/paste with offset
|
||||||
QString last_copied_;
|
QString last_copied_;
|
||||||
|
|
||||||
|
/// Decorator item displayed when at least one item is selected
|
||||||
|
ElementPrimitiveDecorator *decorator_;
|
||||||
|
|
||||||
///< Size of the horizontal grid step
|
///< Size of the horizontal grid step
|
||||||
int x_grid;
|
int x_grid;
|
||||||
///< Size of the vertical grid step
|
///< Size of the vertical grid step
|
||||||
@@ -123,6 +129,7 @@ class ElementScene : public QGraphicsScene {
|
|||||||
virtual QRectF boundingRectFromXml(const QDomDocument &);
|
virtual QRectF boundingRectFromXml(const QDomDocument &);
|
||||||
virtual void fromXml(const QDomDocument &, const QPointF & = QPointF(), bool = true, ElementContent * = 0);
|
virtual void fromXml(const QDomDocument &, const QPointF & = QPointF(), bool = true, ElementContent * = 0);
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
virtual QList<CustomElementPart *> primitives() const;
|
||||||
virtual QList<QGraphicsItem *> zItems(bool = false) const;
|
virtual QList<QGraphicsItem *> zItems(bool = false) const;
|
||||||
virtual ElementContent selectedContent() const;
|
virtual ElementContent selectedContent() const;
|
||||||
virtual void getPasteArea(const QRectF &);
|
virtual void getPasteArea(const QRectF &);
|
||||||
@@ -149,15 +156,17 @@ class ElementScene : public QGraphicsScene {
|
|||||||
virtual void endCurrentBehavior(const QGraphicsSceneMouseEvent *);
|
virtual void endCurrentBehavior(const QGraphicsSceneMouseEvent *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRectF elementContentBoundingRect(const ElementContent &);
|
QRectF elementContentBoundingRect(const ElementContent &) const;
|
||||||
bool applyInformations(const QDomDocument &, QString * = 0);
|
bool applyInformations(const QDomDocument &, QString * = 0);
|
||||||
ElementContent loadContent(const QDomDocument &, QString * = 0);
|
ElementContent loadContent(const QDomDocument &, QString * = 0);
|
||||||
ElementContent addContent(const ElementContent &, QString * = 0);
|
ElementContent addContent(const ElementContent &, QString * = 0);
|
||||||
ElementContent addContentAtPos(const ElementContent &, const QPointF &, QString * = 0);
|
ElementContent addContentAtPos(const ElementContent &, const QPointF &, QString * = 0);
|
||||||
|
void addPrimitive(QGraphicsItem *);
|
||||||
void initPasteArea();
|
void initPasteArea();
|
||||||
void snapToGrid(QPointF &);
|
void snapToGrid(QPointF &);
|
||||||
bool mustSnapToGrid(QGraphicsSceneMouseEvent *);
|
bool mustSnapToGrid(QGraphicsSceneMouseEvent *);
|
||||||
static bool zValueLessThan(QGraphicsItem *, QGraphicsItem *);
|
static bool zValueLessThan(QGraphicsItem *, QGraphicsItem *);
|
||||||
|
QMutex *decorator_lock_;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void slot_move();
|
void slot_move();
|
||||||
@@ -183,6 +192,8 @@ class ElementScene : public QGraphicsScene {
|
|||||||
void slot_raise();
|
void slot_raise();
|
||||||
void slot_lower();
|
void slot_lower();
|
||||||
void slot_sendBackward();
|
void slot_sendBackward();
|
||||||
|
void managePrimitivesGroups();
|
||||||
|
void stackAction(ElementEditionCommand *);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ PartArc::PartArc(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene
|
|||||||
_angle(-90),
|
_angle(-90),
|
||||||
start_angle(0)
|
start_angle(0)
|
||||||
{
|
{
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
@param scene La scene sur laquelle figure ce cercle
|
@param scene La scene sur laquelle figure ce cercle
|
||||||
*/
|
*/
|
||||||
PartCircle::PartCircle(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsEllipseItem(parent, scene), CustomElementGraphicPart(editor) {
|
PartCircle::PartCircle(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsEllipseItem(parent, scene), CustomElementGraphicPart(editor) {
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
@param scene La scene sur laquelle figure cette ellipse
|
@param scene La scene sur laquelle figure cette ellipse
|
||||||
*/
|
*/
|
||||||
PartEllipse::PartEllipse(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsEllipseItem(parent, scene), CustomElementGraphicPart(editor) {
|
PartEllipse::PartEllipse(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsEllipseItem(parent, scene), CustomElementGraphicPart(editor) {
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsSce
|
|||||||
second_end(QET::None),
|
second_end(QET::None),
|
||||||
second_length(1.5)
|
second_length(1.5)
|
||||||
{
|
{
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ PartPolygon::PartPolygon(QETElementEditor *editor, QGraphicsItem *parent, QGraph
|
|||||||
CustomElementGraphicPart(editor),
|
CustomElementGraphicPart(editor),
|
||||||
closed(false)
|
closed(false)
|
||||||
{
|
{
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
@param scene La scene sur laquelle figure ce rectangle
|
@param scene La scene sur laquelle figure ce rectangle
|
||||||
*/
|
*/
|
||||||
PartRectangle::PartRectangle(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsRectItem(parent, scene), CustomElementGraphicPart(editor) {
|
PartRectangle::PartRectangle(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsRectItem(parent, scene), CustomElementGraphicPart(editor) {
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ PartTerminal::PartTerminal(QETElementEditor *editor, QGraphicsItem *parent, QGra
|
|||||||
_orientation(QET::North)
|
_orientation(QET::North)
|
||||||
{
|
{
|
||||||
updateSecondPoint();
|
updateSecondPoint();
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "parttext.h"
|
#include "parttext.h"
|
||||||
#include "texteditor.h"
|
#include "texteditor.h"
|
||||||
#include "editorcommands.h"
|
#include "editorcommands.h"
|
||||||
|
#include "elementprimitivedecorator.h"
|
||||||
#include "elementscene.h"
|
#include "elementscene.h"
|
||||||
#include "qetapp.h"
|
#include "qetapp.h"
|
||||||
|
|
||||||
@@ -29,17 +30,21 @@
|
|||||||
*/
|
*/
|
||||||
PartText::PartText(QETElementEditor *editor, QGraphicsItem *parent, ElementScene *scene) :
|
PartText::PartText(QETElementEditor *editor, QGraphicsItem *parent, ElementScene *scene) :
|
||||||
QGraphicsTextItem(parent, scene),
|
QGraphicsTextItem(parent, scene),
|
||||||
CustomElementPart(editor)
|
CustomElementPart(editor),
|
||||||
|
previous_text(),
|
||||||
|
decorator_(0)
|
||||||
{
|
{
|
||||||
#if QT_VERSION >= 0x040500
|
#if QT_VERSION >= 0x040500
|
||||||
document() -> setDocumentMargin(1.0);
|
document() -> setDocumentMargin(1.0);
|
||||||
#endif
|
#endif
|
||||||
setDefaultTextColor(Qt::black);
|
setDefaultTextColor(Qt::black);
|
||||||
setFont(QETApp::diagramTextsFont());
|
setFont(QETApp::diagramTextsFont());
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
real_font_size_ = font().pointSize();
|
||||||
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
setAcceptHoverEvents(true);
|
||||||
setDefaultTextColor(Qt::black);
|
setDefaultTextColor(Qt::black);
|
||||||
setPlainText(QObject::tr("T", "default text when adding a text in the element editor"));
|
setPlainText(QObject::tr("T", "default text when adding a text in the element editor"));
|
||||||
|
|
||||||
@@ -63,7 +68,7 @@ void PartText::fromXml(const QDomElement &xml_element) {
|
|||||||
if (!ok || font_size < 1) font_size = 20;
|
if (!ok || font_size < 1) font_size = 20;
|
||||||
|
|
||||||
setBlack(xml_element.attribute("color") != "white");
|
setBlack(xml_element.attribute("color") != "white");
|
||||||
setFont(QETApp::diagramTextsFont(font_size));
|
setProperty("size" , font_size);
|
||||||
setPlainText(xml_element.attribute("text"));
|
setPlainText(xml_element.attribute("text"));
|
||||||
|
|
||||||
qreal default_rotation_angle = 0.0;
|
qreal default_rotation_angle = 0.0;
|
||||||
@@ -153,31 +158,24 @@ QPointF PartText::margin() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Permet a l'element texte de redevenir deplacable a la fin de l'edition de texte
|
@reimp QGraphicsItem::focusInEvent(QFocusEvent *)
|
||||||
@param e Le QFocusEvent decrivant la perte de focus
|
@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) {
|
void PartText::focusOutEvent(QFocusEvent *e) {
|
||||||
QGraphicsTextItem::focusOutEvent(e);
|
QGraphicsTextItem::focusOutEvent(e);
|
||||||
if (previous_text != toPlainText()) {
|
endEdition();
|
||||||
undoStack().push(
|
|
||||||
new ChangePartCommand(
|
|
||||||
TextEditor::tr("contenu") + " " + name(),
|
|
||||||
this,
|
|
||||||
"text",
|
|
||||||
previous_text,
|
|
||||||
toPlainText()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
previous_text = toPlainText();
|
|
||||||
}
|
|
||||||
|
|
||||||
// deselectionne le texte
|
|
||||||
QTextCursor qtc = textCursor();
|
|
||||||
qtc.clearSelection();
|
|
||||||
setTextCursor(qtc);
|
|
||||||
|
|
||||||
setTextInteractionFlags(Qt::NoTextInteraction);
|
|
||||||
setFlag(QGraphicsItem::ItemIsFocusable, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,11 +183,10 @@ void PartText::focusOutEvent(QFocusEvent *e) {
|
|||||||
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
|
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
|
||||||
*/
|
*/
|
||||||
void PartText::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
|
void PartText::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
|
||||||
setFlag(QGraphicsItem::ItemIsFocusable, true);
|
|
||||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
|
||||||
previous_text = toPlainText();
|
|
||||||
QGraphicsTextItem::mouseDoubleClickEvent(e);
|
QGraphicsTextItem::mouseDoubleClickEvent(e);
|
||||||
setFocus(Qt::MouseFocusReason);
|
if (e -> button() == Qt::LeftButton) {
|
||||||
|
setEditable(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -212,6 +209,11 @@ void PartText::setProperty(const QString &property, const QVariant &value) {
|
|||||||
} else if (property == "size") {
|
} else if (property == "size") {
|
||||||
if (!value.canConvert(QVariant::Int)) return;
|
if (!value.canConvert(QVariant::Int)) return;
|
||||||
setFont(QETApp::diagramTextsFont(value.toInt()));
|
setFont(QETApp::diagramTextsFont(value.toInt()));
|
||||||
|
real_font_size_ = value.toInt();
|
||||||
|
} else if (property == "real_size") {
|
||||||
|
if (!value.canConvert(QVariant::Double)) return;
|
||||||
|
setFont(QETApp::diagramTextsFont(value.toInt()));
|
||||||
|
real_font_size_ = value.toDouble();
|
||||||
} else if (property == "text") {
|
} else if (property == "text") {
|
||||||
setPlainText(value.toString());
|
setPlainText(value.toString());
|
||||||
} else if (property == "rotation angle") {
|
} else if (property == "rotation angle") {
|
||||||
@@ -241,6 +243,8 @@ QVariant PartText::property(const QString &property) {
|
|||||||
return(pos().y());
|
return(pos().y());
|
||||||
} else if (property == "size") {
|
} else if (property == "size") {
|
||||||
return(font().pointSize());
|
return(font().pointSize());
|
||||||
|
} else if (property == "real_size") {
|
||||||
|
return(real_font_size_);
|
||||||
} else if (property == "text") {
|
} else if (property == "text") {
|
||||||
return(toPlainText());
|
return(toPlainText());
|
||||||
} else if (property == "rotation angle") {
|
} else if (property == "rotation angle") {
|
||||||
@@ -292,7 +296,7 @@ bool PartText::isUseless() const {
|
|||||||
void PartText::startUserTransformation(const QRectF &rect) {
|
void PartText::startUserTransformation(const QRectF &rect) {
|
||||||
Q_UNUSED(rect)
|
Q_UNUSED(rect)
|
||||||
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
|
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
|
||||||
saved_font_size_ = font().pointSize();
|
saved_font_size_ = real_font_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,12 +307,10 @@ void PartText::handleUserTransformation(const QRectF &initial_selection_rect, co
|
|||||||
QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_point_).first();
|
QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_point_).first();
|
||||||
setPos(new_pos);
|
setPos(new_pos);
|
||||||
|
|
||||||
// adjust the font size following the smallest scale factor
|
// adjust the font size following the vertical scale factor
|
||||||
qreal sx = new_selection_rect.width() / initial_selection_rect.width();
|
|
||||||
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
|
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
|
||||||
qreal smallest_scale_factor = sx > sy ? sy : sx;
|
qreal new_font_size = saved_font_size_ * sy;
|
||||||
qreal new_font_size = saved_font_size_ * smallest_scale_factor;
|
setProperty("real_size", qMax(1, qRound(new_font_size)));
|
||||||
setProperty("size", qMax(1, qRound(new_font_size)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -318,7 +320,12 @@ void PartText::handleUserTransformation(const QRectF &initial_selection_rect, co
|
|||||||
@param widget Widget sur lequel on dessine (facultatif)
|
@param widget Widget sur lequel on dessine (facultatif)
|
||||||
*/
|
*/
|
||||||
void PartText::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, QWidget *widget) {
|
void PartText::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, QWidget *widget) {
|
||||||
QGraphicsTextItem::paint(painter, qsogi, 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
|
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||||
painter -> setPen(Qt::blue);
|
painter -> setPen(Qt::blue);
|
||||||
@@ -332,6 +339,124 @@ void PartText::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, Q
|
|||||||
#endif
|
#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 (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();
|
||||||
|
}
|
||||||
|
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
|
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
|
en repositionnant son origine (c-a-d le milieu du bord gauche du champ de
|
||||||
@@ -349,6 +474,59 @@ void PartText::adjustItemPosition(int new_block_count) {
|
|||||||
setTransformOriginPoint(origin_offset);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef QET_DEBUG_EDITOR_TEXTS
|
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||||
/**
|
/**
|
||||||
Dessine deux petites fleches pour mettre un point en valeur
|
Dessine deux petites fleches pour mettre un point en valeur
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#include "customelementpart.h"
|
#include "customelementpart.h"
|
||||||
class TextEditor;
|
class TextEditor;
|
||||||
|
class ElementPrimitiveDecorator;
|
||||||
/**
|
/**
|
||||||
This class represents an static text primitive which may be used to compose
|
This class represents an static text primitive which may be used to compose
|
||||||
the drawing of an electrical element within the element editor.
|
the drawing of an electrical element within the element editor.
|
||||||
@@ -59,10 +60,23 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
|
|||||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0 );
|
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 *);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void adjustItemPosition(int = 0);
|
void adjustItemPosition(int = 0);
|
||||||
|
void setEditable(bool);
|
||||||
|
void startEdition();
|
||||||
|
void endEdition();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *);
|
||||||
|
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
|
||||||
|
virtual bool sceneEventFilter(QGraphicsItem *, QEvent *);
|
||||||
|
virtual void focusInEvent(QFocusEvent *);
|
||||||
virtual void focusOutEvent(QFocusEvent *);
|
virtual void focusOutEvent(QFocusEvent *);
|
||||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
|
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
|
||||||
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
|
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||||
@@ -74,7 +88,9 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
|
|||||||
void drawPoint(QPainter *, const QPointF &);
|
void drawPoint(QPainter *, const QPointF &);
|
||||||
#endif
|
#endif
|
||||||
QString previous_text;
|
QString previous_text;
|
||||||
|
qreal real_font_size_;
|
||||||
QPointF saved_point_;
|
QPointF saved_point_;
|
||||||
int saved_font_size_;
|
qreal saved_font_size_;
|
||||||
|
QGraphicsItem *decorator_;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "parttextfield.h"
|
#include "parttextfield.h"
|
||||||
#include "textfieldeditor.h"
|
#include "textfieldeditor.h"
|
||||||
#include "editorcommands.h"
|
#include "editorcommands.h"
|
||||||
|
#include "elementprimitivedecorator.h"
|
||||||
#include "qetapp.h"
|
#include "qetapp.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,14 +30,18 @@
|
|||||||
PartTextField::PartTextField(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
|
PartTextField::PartTextField(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
|
||||||
QGraphicsTextItem(parent, scene),
|
QGraphicsTextItem(parent, scene),
|
||||||
CustomElementPart(editor),
|
CustomElementPart(editor),
|
||||||
follow_parent_rotations(true)
|
follow_parent_rotations(true),
|
||||||
|
previous_text(),
|
||||||
|
decorator_(0)
|
||||||
{
|
{
|
||||||
setDefaultTextColor(Qt::black);
|
setDefaultTextColor(Qt::black);
|
||||||
setFont(QETApp::diagramTextsFont());
|
setFont(QETApp::diagramTextsFont());
|
||||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
real_font_size_ = font().pointSize();
|
||||||
|
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||||
#endif
|
#endif
|
||||||
|
setAcceptHoverEvents(true);
|
||||||
setPlainText(QObject::tr("_", "default text when adding a textfield in the element editor"));
|
setPlainText(QObject::tr("_", "default text when adding a textfield in the element editor"));
|
||||||
|
|
||||||
adjustItemPosition(1);
|
adjustItemPosition(1);
|
||||||
@@ -58,7 +63,7 @@ void PartTextField::fromXml(const QDomElement &xml_element) {
|
|||||||
int font_size = xml_element.attribute("size").toInt(&ok);
|
int font_size = xml_element.attribute("size").toInt(&ok);
|
||||||
if (!ok || font_size < 1) font_size = 20;
|
if (!ok || font_size < 1) font_size = 20;
|
||||||
|
|
||||||
setFont(QETApp::diagramTextsFont(font_size));
|
setProperty("size", font_size);
|
||||||
setPlainText(xml_element.attribute("text"));
|
setPlainText(xml_element.attribute("text"));
|
||||||
|
|
||||||
qreal default_rotation_angle = 0.0;
|
qreal default_rotation_angle = 0.0;
|
||||||
@@ -134,32 +139,83 @@ QPointF PartTextField::margin() const {
|
|||||||
return(QPointF(0.0, boundingRect().bottom() / 2.0));
|
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 (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();
|
||||||
|
}
|
||||||
|
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
|
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
|
@param e Le QFocusEvent decrivant la perte de focus
|
||||||
*/
|
*/
|
||||||
void PartTextField::focusOutEvent(QFocusEvent *e) {
|
void PartTextField::focusOutEvent(QFocusEvent *e) {
|
||||||
QGraphicsTextItem::focusOutEvent(e);
|
QGraphicsTextItem::focusOutEvent(e);
|
||||||
if (previous_text != toPlainText()) {
|
endEdition();
|
||||||
undoStack().push(
|
|
||||||
new ChangePartCommand(
|
|
||||||
TextFieldEditor::tr("contenu") + " " + name(),
|
|
||||||
this,
|
|
||||||
"text",
|
|
||||||
previous_text,
|
|
||||||
toPlainText()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
previous_text = toPlainText();
|
|
||||||
}
|
|
||||||
|
|
||||||
// deselectionne le texte
|
|
||||||
QTextCursor qtc = textCursor();
|
|
||||||
qtc.clearSelection();
|
|
||||||
setTextCursor(qtc);
|
|
||||||
|
|
||||||
setTextInteractionFlags(Qt::NoTextInteraction);
|
|
||||||
setFlag(QGraphicsItem::ItemIsFocusable, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,11 +223,10 @@ void PartTextField::focusOutEvent(QFocusEvent *e) {
|
|||||||
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
|
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
|
||||||
*/
|
*/
|
||||||
void PartTextField::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
|
void PartTextField::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
|
||||||
setFlag(QGraphicsItem::ItemIsFocusable, true);
|
|
||||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
|
||||||
previous_text = toPlainText();
|
|
||||||
QGraphicsTextItem::mouseDoubleClickEvent(e);
|
QGraphicsTextItem::mouseDoubleClickEvent(e);
|
||||||
setFocus(Qt::MouseFocusReason);
|
if (e -> button() == Qt::LeftButton) {
|
||||||
|
setEditable(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -194,6 +249,11 @@ void PartTextField::setProperty(const QString &property, const QVariant &value)
|
|||||||
} else if (property == "size") {
|
} else if (property == "size") {
|
||||||
if (!value.canConvert(QVariant::Int)) return;
|
if (!value.canConvert(QVariant::Int)) return;
|
||||||
setFont(QETApp::diagramTextsFont(value.toInt()));
|
setFont(QETApp::diagramTextsFont(value.toInt()));
|
||||||
|
real_font_size_ = value.toInt();
|
||||||
|
} else if (property == "real_size") {
|
||||||
|
if (!value.canConvert(QVariant::Double)) return;
|
||||||
|
setFont(QETApp::diagramTextsFont(value.toInt()));
|
||||||
|
real_font_size_ = value.toDouble();
|
||||||
} else if (property == "text") {
|
} else if (property == "text") {
|
||||||
setPlainText(value.toString());
|
setPlainText(value.toString());
|
||||||
} else if (property == "rotation angle") {
|
} else if (property == "rotation angle") {
|
||||||
@@ -223,6 +283,8 @@ QVariant PartTextField::property(const QString &property) {
|
|||||||
return(pos().y());
|
return(pos().y());
|
||||||
} else if (property == "size") {
|
} else if (property == "size") {
|
||||||
return(font().pointSize());
|
return(font().pointSize());
|
||||||
|
} else if (property == "real_size") {
|
||||||
|
return(real_font_size_);
|
||||||
} else if (property == "text") {
|
} else if (property == "text") {
|
||||||
return(toPlainText());
|
return(toPlainText());
|
||||||
} else if (property == "rotation angle") {
|
} else if (property == "rotation angle") {
|
||||||
@@ -275,7 +337,7 @@ bool PartTextField::isUseless() const {
|
|||||||
void PartTextField::startUserTransformation(const QRectF &initial_selection_rect) {
|
void PartTextField::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||||
Q_UNUSED(initial_selection_rect)
|
Q_UNUSED(initial_selection_rect)
|
||||||
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
|
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
|
||||||
saved_font_size_ = font().pointSize();
|
saved_font_size_ = real_font_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -286,12 +348,10 @@ void PartTextField::handleUserTransformation(const QRectF &initial_selection_rec
|
|||||||
QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_point_).first();
|
QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList<QPointF>() << saved_point_).first();
|
||||||
setPos(new_pos);
|
setPos(new_pos);
|
||||||
|
|
||||||
// adjust the font size following the smallest scale factor
|
// adjust the font size following the vertical scale factor
|
||||||
qreal sx = new_selection_rect.width() / initial_selection_rect.width();
|
|
||||||
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
|
qreal sy = new_selection_rect.height() / initial_selection_rect.height();
|
||||||
qreal smallest_scale_factor = sx > sy ? sy : sx;
|
qreal new_font_size = saved_font_size_ * sy;
|
||||||
qreal new_font_size = saved_font_size_ * smallest_scale_factor;
|
setProperty("real_size", qMax(1, qRound(new_font_size)));
|
||||||
setProperty("size", qMax(1, qRound(new_font_size)));
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
Dessine le texte statique.
|
Dessine le texte statique.
|
||||||
@@ -300,8 +360,12 @@ void PartTextField::handleUserTransformation(const QRectF &initial_selection_rec
|
|||||||
@param widget Widget sur lequel on dessine (facultatif)
|
@param widget Widget sur lequel on dessine (facultatif)
|
||||||
*/
|
*/
|
||||||
void PartTextField::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, QWidget *widget) {
|
void PartTextField::paint(QPainter *painter, const QStyleOptionGraphicsItem *qsogi, QWidget *widget) {
|
||||||
QGraphicsTextItem::paint(painter, qsogi, 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
|
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||||
painter -> setPen(Qt::blue);
|
painter -> setPen(Qt::blue);
|
||||||
painter -> drawRect(boundingRect());
|
painter -> drawRect(boundingRect());
|
||||||
@@ -314,6 +378,64 @@ void PartTextField::paint(QPainter *painter, const QStyleOptionGraphicsItem *qso
|
|||||||
#endif
|
#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
|
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
|
en repositionnant son origine (c-a-d le milieu du bord gauche du champ de
|
||||||
@@ -331,6 +453,59 @@ void PartTextField::adjustItemPosition(int new_block_count) {
|
|||||||
setTransformOriginPoint(0.0, origin_offset);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef QET_DEBUG_EDITOR_TEXTS
|
#ifdef QET_DEBUG_EDITOR_TEXTS
|
||||||
/**
|
/**
|
||||||
Dessine deux petites fleches pour mettre un point en valeur
|
Dessine deux petites fleches pour mettre un point en valeur
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "customelementpart.h"
|
#include "customelementpart.h"
|
||||||
class TextFieldEditor;
|
class TextFieldEditor;
|
||||||
class QETElementEditor;
|
class QETElementEditor;
|
||||||
|
class ElementPrimitiveDecorator;
|
||||||
/**
|
/**
|
||||||
This class represents an editable text field which may be used to compose the
|
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
|
drawing of an electrical element within the element editor. Users may specify
|
||||||
@@ -65,10 +66,23 @@ class PartTextField : public QGraphicsTextItem, public CustomElementPart {
|
|||||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0 );
|
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 *);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void adjustItemPosition(int = 0);
|
void adjustItemPosition(int = 0);
|
||||||
|
void setEditable(bool);
|
||||||
|
void startEdition();
|
||||||
|
void endEdition();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *);
|
||||||
|
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
|
||||||
|
virtual bool sceneEventFilter(QGraphicsItem *, QEvent *);
|
||||||
|
virtual void focusInEvent(QFocusEvent *);
|
||||||
virtual void focusOutEvent(QFocusEvent *);
|
virtual void focusOutEvent(QFocusEvent *);
|
||||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
|
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
|
||||||
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
|
virtual QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||||
@@ -80,7 +94,9 @@ class PartTextField : public QGraphicsTextItem, public CustomElementPart {
|
|||||||
void drawPoint(QPainter *, const QPointF &);
|
void drawPoint(QPainter *, const QPointF &);
|
||||||
#endif
|
#endif
|
||||||
QString previous_text;
|
QString previous_text;
|
||||||
|
qreal real_font_size_;
|
||||||
QPointF saved_point_;
|
QPointF saved_point_;
|
||||||
int saved_font_size_;
|
qreal saved_font_size_;
|
||||||
|
QGraphicsItem *decorator_;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "qet.h"
|
#include "qet.h"
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <QGraphicsSceneContextMenuEvent>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Permet de convertir une chaine de caracteres ("n", "s", "e" ou "w")
|
Permet de convertir une chaine de caracteres ("n", "s", "e" ou "w")
|
||||||
@@ -577,3 +578,59 @@ bool QET::writeXmlFile(QDomDocument &xml_doc, const QString &filepath, QString *
|
|||||||
|
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@return the scene position where \a event occurred, provided it is
|
||||||
|
QGraphicsScene-related event; otherwise, this function returns a null
|
||||||
|
QPointF.
|
||||||
|
*/
|
||||||
|
QPointF QET::graphicsSceneEventPos(QEvent *event) {
|
||||||
|
QPointF event_scene_pos;
|
||||||
|
if (event -> type() < QEvent::GraphicsSceneContextMenu) return(event_scene_pos);
|
||||||
|
if (event -> type() > QEvent::GraphicsSceneWheel) return(event_scene_pos);
|
||||||
|
|
||||||
|
switch (event -> type()) {
|
||||||
|
case QEvent::GraphicsSceneContextMenu: {
|
||||||
|
QGraphicsSceneContextMenuEvent *qgs_event = static_cast<QGraphicsSceneContextMenuEvent *>(event);
|
||||||
|
event_scene_pos = qgs_event -> scenePos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::GraphicsSceneDragEnter:
|
||||||
|
case QEvent::GraphicsSceneDragLeave:
|
||||||
|
case QEvent::GraphicsSceneDragMove:
|
||||||
|
case QEvent::GraphicsSceneDrop: {
|
||||||
|
QGraphicsSceneDragDropEvent *qgs_event = static_cast<QGraphicsSceneDragDropEvent *>(event);
|
||||||
|
event_scene_pos = qgs_event -> scenePos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::GraphicsSceneHelp: {
|
||||||
|
QGraphicsSceneHelpEvent *qgs_event = static_cast<QGraphicsSceneHelpEvent *>(event);
|
||||||
|
event_scene_pos = qgs_event -> scenePos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QEvent::GraphicsSceneHoverEnter:
|
||||||
|
case QEvent::GraphicsSceneHoverLeave:
|
||||||
|
case QEvent::GraphicsSceneHoverMove: {
|
||||||
|
QGraphicsSceneHoverEvent *qgs_event = static_cast<QGraphicsSceneHoverEvent *>(event);
|
||||||
|
event_scene_pos = qgs_event -> scenePos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::GraphicsSceneMouseDoubleClick:
|
||||||
|
case QEvent::GraphicsSceneMouseMove:
|
||||||
|
case QEvent::GraphicsSceneMousePress:
|
||||||
|
case QEvent::GraphicsSceneMouseRelease: {
|
||||||
|
QGraphicsSceneMouseEvent *qgs_event = static_cast<QGraphicsSceneMouseEvent *>(event);
|
||||||
|
event_scene_pos = qgs_event -> scenePos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::GraphicsSceneWheel: {
|
||||||
|
QGraphicsSceneWheelEvent *qgs_event = static_cast<QGraphicsSceneWheelEvent *>(event);
|
||||||
|
event_scene_pos = qgs_event -> scenePos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return(event_scene_pos);
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,6 +43,22 @@ namespace QET {
|
|||||||
ToNorthWest
|
ToNorthWest
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// List areas related to some common operations
|
||||||
|
enum OperationAreas {
|
||||||
|
ChangeInnerPoints = -4,
|
||||||
|
RotateArea = -3,
|
||||||
|
MoveArea = -2,
|
||||||
|
NoOperation = -1,
|
||||||
|
ResizeFromTopLeftCorner = 0,
|
||||||
|
ResizeFromTopCenterCorner = 1,
|
||||||
|
ResizeFromTopRightCorner = 2,
|
||||||
|
ResizeFromMiddleLeftCorner = 3,
|
||||||
|
ResizeFromMiddleRightCorner = 4,
|
||||||
|
ResizeFromBottomLeftCorner = 5,
|
||||||
|
ResizeFromBottomCenterCorner = 6,
|
||||||
|
ResizeFromBottomRightCorner = 7
|
||||||
|
};
|
||||||
|
|
||||||
/// Known kinds of conductor segments
|
/// Known kinds of conductor segments
|
||||||
enum ConductorSegmentType {
|
enum ConductorSegmentType {
|
||||||
Horizontal = 1, ///< Horizontal segment
|
Horizontal = 1, ///< Horizontal segment
|
||||||
@@ -149,5 +165,6 @@ namespace QET {
|
|||||||
bool compareCanonicalFilePaths(const QString &, const QString &);
|
bool compareCanonicalFilePaths(const QString &, const QString &);
|
||||||
QString titleBlockColumnLengthToString(const TitleBlockColumnLength &);
|
QString titleBlockColumnLengthToString(const TitleBlockColumnLength &);
|
||||||
bool writeXmlFile(QDomDocument &, const QString &, QString * = 0);
|
bool writeXmlFile(QDomDocument &, const QString &, QString * = 0);
|
||||||
|
QPointF graphicsSceneEventPos(QEvent *);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user