mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-12-19 14:50:53 +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:
@@ -18,6 +18,7 @@
|
||||
#include "parttextfield.h"
|
||||
#include "textfieldeditor.h"
|
||||
#include "editorcommands.h"
|
||||
#include "elementprimitivedecorator.h"
|
||||
#include "qetapp.h"
|
||||
|
||||
/**
|
||||
@@ -29,14 +30,18 @@
|
||||
PartTextField::PartTextField(QETElementEditor *editor, QGraphicsItem *parent, QGraphicsScene *scene) :
|
||||
QGraphicsTextItem(parent, scene),
|
||||
CustomElementPart(editor),
|
||||
follow_parent_rotations(true)
|
||||
follow_parent_rotations(true),
|
||||
previous_text(),
|
||||
decorator_(0)
|
||||
{
|
||||
setDefaultTextColor(Qt::black);
|
||||
setFont(QETApp::diagramTextsFont());
|
||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
||||
real_font_size_ = font().pointSize();
|
||||
setFlags(QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptHoverEvents(true);
|
||||
setPlainText(QObject::tr("_", "default text when adding a textfield in the element editor"));
|
||||
|
||||
adjustItemPosition(1);
|
||||
@@ -58,7 +63,7 @@ void PartTextField::fromXml(const QDomElement &xml_element) {
|
||||
int font_size = xml_element.attribute("size").toInt(&ok);
|
||||
if (!ok || font_size < 1) font_size = 20;
|
||||
|
||||
setFont(QETApp::diagramTextsFont(font_size));
|
||||
setProperty("size", font_size);
|
||||
setPlainText(xml_element.attribute("text"));
|
||||
|
||||
qreal default_rotation_angle = 0.0;
|
||||
@@ -134,32 +139,83 @@ QPointF PartTextField::margin() const {
|
||||
return(QPointF(0.0, boundingRect().bottom() / 2.0));
|
||||
}
|
||||
|
||||
/**
|
||||
Handle context menu events.
|
||||
@param event Object describing the context menu event to handle.
|
||||
*/
|
||||
void PartTextField::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
/**
|
||||
Handle events generated when the mouse hovers over the decorator.
|
||||
@param event Object describing the hover event.
|
||||
*/
|
||||
void PartTextField::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
||||
// force the cursor when the text is being edited
|
||||
if (hasFocus() && decorator_) {
|
||||
decorator_ -> setCursor(Qt::IBeamCursor);
|
||||
}
|
||||
QGraphicsTextItem::hoverMoveEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp QGraphicsItem::sceneEventFilter(QGraphicsItem *, QEvent *).
|
||||
Intercepts events before they reach the watched target, i.e. typically the
|
||||
primitives decorator.
|
||||
This method mainly works with key strokes (F2, escape) and double clicks to
|
||||
begin or end text edition.
|
||||
*/
|
||||
bool PartTextField::sceneEventFilter(QGraphicsItem *watched, QEvent *event) {
|
||||
if (watched != decorator_) return(false);
|
||||
|
||||
QPointF event_scene_pos = QET::graphicsSceneEventPos(event);
|
||||
if (!event_scene_pos.isNull()) {
|
||||
if (contains(mapFromScene(event_scene_pos))) {
|
||||
if (hasFocus()) {
|
||||
return sceneEvent(event); // manually deliver the event to this item
|
||||
return(true); // prevent this event from being delivered to any item
|
||||
} else {
|
||||
if (event -> type() == QEvent::GraphicsSceneMouseDoubleClick) {
|
||||
mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event -> type() == QEvent::KeyRelease || event -> type() == QEvent::KeyPress) {
|
||||
// Intercept F2 and escape keystrokes to focus in and out
|
||||
QKeyEvent *key_event = static_cast<QKeyEvent *>(event);
|
||||
if (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
|
||||
@param e Le QFocusEvent decrivant la perte de focus
|
||||
*/
|
||||
void PartTextField::focusOutEvent(QFocusEvent *e) {
|
||||
QGraphicsTextItem::focusOutEvent(e);
|
||||
if (previous_text != toPlainText()) {
|
||||
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);
|
||||
endEdition();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,11 +223,10 @@ void PartTextField::focusOutEvent(QFocusEvent *e) {
|
||||
@param e Le QGraphicsSceneMouseEvent qui decrit le double-clic
|
||||
*/
|
||||
void PartTextField::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e) {
|
||||
setFlag(QGraphicsItem::ItemIsFocusable, true);
|
||||
setTextInteractionFlags(Qt::TextEditorInteraction);
|
||||
previous_text = toPlainText();
|
||||
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") {
|
||||
if (!value.canConvert(QVariant::Int)) return;
|
||||
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") {
|
||||
setPlainText(value.toString());
|
||||
} else if (property == "rotation angle") {
|
||||
@@ -223,6 +283,8 @@ QVariant PartTextField::property(const QString &property) {
|
||||
return(pos().y());
|
||||
} else if (property == "size") {
|
||||
return(font().pointSize());
|
||||
} else if (property == "real_size") {
|
||||
return(real_font_size_);
|
||||
} else if (property == "text") {
|
||||
return(toPlainText());
|
||||
} else if (property == "rotation angle") {
|
||||
@@ -275,7 +337,7 @@ bool PartTextField::isUseless() const {
|
||||
void PartTextField::startUserTransformation(const QRectF &initial_selection_rect) {
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
saved_point_ = pos(); // scene coordinates, no need to mapFromScene()
|
||||
saved_font_size_ = 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();
|
||||
setPos(new_pos);
|
||||
|
||||
// adjust the font size following the smallest scale factor
|
||||
qreal sx = new_selection_rect.width() / initial_selection_rect.width();
|
||||
// adjust the font size following the vertical scale factor
|
||||
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_ * smallest_scale_factor;
|
||||
setProperty("size", qMax(1, qRound(new_font_size)));
|
||||
qreal new_font_size = saved_font_size_ * sy;
|
||||
setProperty("real_size", qMax(1, qRound(new_font_size)));
|
||||
}
|
||||
/**
|
||||
Dessine le texte statique.
|
||||
@@ -300,8 +360,12 @@ void PartTextField::handleUserTransformation(const QRectF &initial_selection_rec
|
||||
@param widget Widget sur lequel on dessine (facultatif)
|
||||
*/
|
||||
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
|
||||
painter -> setPen(Qt::blue);
|
||||
painter -> drawRect(boundingRect());
|
||||
@@ -314,6 +378,64 @@ void PartTextField::paint(QPainter *painter, const QStyleOptionGraphicsItem *qso
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@reimp CustomElementPart::setDecorator(ElementPrimitiveDecorator *)
|
||||
Install or remove a sceneEventFilter on the decorator and ensure it will
|
||||
adjust itself while the text is being edited.
|
||||
*/
|
||||
void PartTextField::setDecorator(ElementPrimitiveDecorator *decorator) {
|
||||
if (decorator) {
|
||||
decorator -> installSceneEventFilter(this);
|
||||
// ensure the decorator will adjust itself when the text area expands or shrinks
|
||||
connect(document(), SIGNAL(contentsChanged()), decorator, SLOT(adjust()));
|
||||
}
|
||||
else {
|
||||
decorator_ -> removeSceneEventFilter(this);
|
||||
endEdition();
|
||||
}
|
||||
decorator_ = decorator;
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartTextField::singleItemPressEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartTextField::singleItemMoveEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartTextField::singleItemReleaseEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
Q_UNUSED(event)
|
||||
return(hasFocus());
|
||||
}
|
||||
|
||||
/**
|
||||
Accept the mouse \a event relayed by \a decorator if this text item has focus.
|
||||
*/
|
||||
bool PartTextField::singleItemDoubleClickEvent(ElementPrimitiveDecorator *decorator, QGraphicsSceneMouseEvent *event) {
|
||||
Q_UNUSED(decorator)
|
||||
// calling mouseDoubleClickEvent() will set this text item editable and grab keyboard focus
|
||||
if (event -> button() == Qt::LeftButton) {
|
||||
mouseDoubleClickEvent(event);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**
|
||||
Cette methode s'assure que la position du champ de texte est coherente
|
||||
en repositionnant son origine (c-a-d le milieu du bord gauche du champ de
|
||||
@@ -331,6 +453,59 @@ void PartTextField::adjustItemPosition(int new_block_count) {
|
||||
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
|
||||
/**
|
||||
Dessine deux petites fleches pour mettre un point en valeur
|
||||
|
||||
Reference in New Issue
Block a user