[prev in list] [next in list] [prev in thread] [next in thread] 

List:       koffice-devel
Subject:    Re: text-on-shapes and EnhancedPathShape's text-areas attribute
From:       Marijn Kruisselbrink <m.kruisselbrink () student ! tue ! nl>
Date:       2010-09-21 22:01:24
Message-ID: 201009220001.24949.m.kruisselbrink () student ! tue ! nl
[Download RAW message or body]

On Tuesday 21 September 2010 22:10:40 Thomas Zander wrote:
> On Tuesday 21. September 2010 20.45.35 Marijn Kruisselbrink wrote:
> > Hmm, okay. Then I guess we'll just have to hope we'll still remember all
> > the places we made use of the assumption that never more than one
> > decorator will exist if we ever do come up with a usecase for multiple
> > decorators on one shape.
>
> Oh, we will have multiple decorators for one shape. Thats clear in my mind.
> Sorry if I was not being clear.
> The point that I wanted to make is that if you decorate Shape S1 with D1
> and decorate D1 with D2 which is a TextOnShape based docorator, then
> whatever S1 looks like is completely irrelevant to D2.
> Hence you only need to every do one parent().
Hmm, okay. I'm not entirely convinced, but for now it will do.

> > Anyway, attached is my attempt to implement option (b).
>
> Actually, from your explanation below it seems you implemented (c) ;-)
Ah, okay; I didn't quite understood what the difference was between (b) and 
(c).


> Maybe you can add a setter instead, something like
> KoTextOnShapeContainer::setPreferredTextRect(const QRectF &rect);
> and this rect would be used.
> This would simply be a proxy method but it can also store the rect so a
> later creation of the shape can properly set the size.
> Rationale; the text shape member can be null, this is an implementation
> detail that should not be exposed to the world.
Yeah, this was the other implementation I considered. I didn't do it that way 
at first because having a simple QRectF for the text area would not be 
flexible enough for some of the other usecases thorsten suggested, like 
having text that is rotated relative to the content shape. But yeah, not 
exposing the internal text shape is at least closer to a proper API, so I 
changed it that way.
One thing I'm not quite sure about yet is if maybe setPreferredTextRect should 
also set the resizing behavior to TextFollowsPrefferedTextRect. On one hand 
in probably all cases that you call setPreferredTextRect you'll want that 
rect to atually be used, but on the other hand it might also be a bit 
confusing to have one method that changes two properties.

> I'd say this is a new feature, so for after 2.3 is branched off. But I like
> it for sure.
Yes, I agree. Attached an updated version of my patch, but I guess I'll also 
post it to reviewboard by the time 2.3 is branched off to get a proper 
shipit :)

Marijn


["enhancedpathshape-textareas2.diff" (text/x-diff)]

diff --git a/libs/flake/KoTextOnShapeContainer.cpp \
b/libs/flake/KoTextOnShapeContainer.cpp index 82c0ca5..4749013 100644
--- a/libs/flake/KoTextOnShapeContainer.cpp
+++ b/libs/flake/KoTextOnShapeContainer.cpp
@@ -39,6 +39,7 @@ public:
     KoShape *content; // the original shape
     KoShape *textShape;
     KoTextOnShapeContainer::ResizeBehavior resizeBehavior;
+    QRectF preferredTextRect;
 };
 
 class KoTextOnShapeContainerModel : public SimpleShapeContainerModel
@@ -92,7 +93,7 @@ void KoTextOnShapeContainerModel::containerChanged(KoShapeContainer \
*container,  Q_ASSERT(container == q);
     containerData->content->setSize(q->size());
     KoShape *text = containerData->textShape;
-    if (text) {
+    if (text && q->resizeBehavior() != \
KoTextOnShapeContainer::TextFollowsPreferredTextRect) {  text->setSize(q->size());
     }
     lock = false;
@@ -108,7 +109,7 @@ void KoTextOnShapeContainerModel::proposeMove(KoShape *child, \
QPointF &move)  
 void KoTextOnShapeContainerModel::childChanged(KoShape *child, KoShape::ChangeType \
type)  {
-    if (lock) {
+    if (lock || q->resizeBehavior() == \
KoTextOnShapeContainer::TextFollowsPreferredTextRect) {  return;
     }
     lock = true;
@@ -156,8 +157,15 @@ KoTextOnShapeContainer::KoTextOnShapeContainer(KoShape \
*childShape, KoResourceMa  if (factory) { // not installed, thats too bad, but \
allowed  d->textShape = factory->createDefaultShape(documentResources);
         Q_ASSERT(d->textShape); // would be a bug in the text shape;
-        d->textShape->setSize(size());
+        if (d->resizeBehavior == TextFollowsPreferredTextRect) {
+            d->textShape->setSize(d->preferredTextRect.size());
+        } else {
+            d->textShape->setSize(size());
+        }
         d->textShape->setTransformation(childShape->transformation());
+        if (d->resizeBehavior == TextFollowsPreferredTextRect) {
+            d->textShape->setPosition(d->preferredTextRect.topLeft());
+        }
         KoTextShapeDataBase *shapeData = \
qobject_cast<KoTextShapeDataBase*>(d->textShape->userData());  Q_ASSERT(shapeData); \
// would be a bug in kotext  shapeData->setVerticalAlignment(Qt::AlignVCenter);
@@ -168,9 +176,16 @@ KoTextOnShapeContainer::KoTextOnShapeContainer(KoShape \
*childShape, KoResourceMa  } else {
         kWarning(30006) << "Text shape factory not found";
     }
+
     setToolDelegates(delegates);
 }
 
+KoShape* KoTextOnShapeContainer::textShape()
+{
+    Q_D(KoTextOnShapeContainer);
+    return d->textShape;
+}
+
 KoTextOnShapeContainer::~KoTextOnShapeContainer()
 {
     Q_D(KoTextOnShapeContainer);
@@ -220,6 +235,10 @@ void KoTextOnShapeContainer::setResizeBehavior(ResizeBehavior \
resizeBehavior)  return;
     }
     d->resizeBehavior = resizeBehavior;
+    if (d->resizeBehavior == TextFollowsPreferredTextRect && d->textShape) {
+        d->textShape->setPosition(d->preferredTextRect.topLeft());
+        d->textShape->setSize(d->preferredTextRect.size());
+    }
     d->model->containerChanged(this, KoShape::SizeChanged);
 }
 
@@ -229,6 +248,22 @@ KoTextOnShapeContainer::ResizeBehavior \
KoTextOnShapeContainer::resizeBehavior()  return d->resizeBehavior;
 }
 
+void KoTextOnShapeContainer::setPreferredTextRect(const QRectF &rect)
+{
+    Q_D(KoTextOnShapeContainer);
+    d->preferredTextRect = rect;
+    if (d->resizeBehavior == TextFollowsPreferredTextRect && d->textShape) {
+        d->textShape->setPosition(rect.topLeft());
+        d->textShape->setSize(rect.size());
+    }
+}
+
+QRectF KoTextOnShapeContainer::preferredTextRect() const
+{
+    Q_D(const KoTextOnShapeContainer);
+    return d->preferredTextRect;
+}
+
 void KoTextOnShapeContainer::setTextAlignment(Qt::Alignment alignment)
 {
     Q_D(KoTextOnShapeContainer);
diff --git a/libs/flake/KoTextOnShapeContainer.h \
b/libs/flake/KoTextOnShapeContainer.h index 6a340af..ac44af4 100644
--- a/libs/flake/KoTextOnShapeContainer.h
+++ b/libs/flake/KoTextOnShapeContainer.h
@@ -56,7 +56,8 @@ public:
     enum ResizeBehavior {
         TextFollowsContentSize, ///< Text area is same size as content, extra text \
                will be clipped
         ContentFollowsTextSize, ///< Content shape will get resized if text \
                grows/shrinks
-        IndependendSizes        ///< The text can get bigger than the content
+        IndependendSizes,       ///< The text can get bigger than the content
+        TextFollowsPreferredTextRect ///< The size/position of the text area will \
follow the preferredTextRect property  };
 
     /**
@@ -72,6 +73,19 @@ public:
      */
     ResizeBehavior resizeBehavior() const;
 
+    /**
+     * Set the current prefered text rectangle. This rect contains the coordinates \
of +     * the embedded text shape relative to the content shape. This value is \
ignored if +     * resizeBehavior is not TextFollowsPreferredTextRect.
+     * @param rect the new preferred text rectangle
+     */
+    void setPreferredTextRect(const QRectF &rect);
+
+    /**
+     * Returns the current prefered text rectangle.
+     */
+    QRectF preferredTextRect() const;
+
     /** Sets the alignment of the text. */
     void setTextAlignment(Qt::Alignment alignment);
     /** Returns the alignment of all text */
@@ -92,6 +106,11 @@ public:
     virtual void saveOdfChildElements(KoShapeSavingContext &context) const;
 
     /**
+     * Returns the embedded text shape.
+     */
+    KoShape* textShape();
+
+    /**
      * Try to load text-on-shape from \a element and wrap \a shape with it.
      * In ODF certain shape-types can have a "text:p" child-element which
      * translates in KOffice design to it ending up with a
diff --git a/plugins/pathshapes/enhancedpath/EnhancedPathShape.cpp \
b/plugins/pathshapes/enhancedpath/EnhancedPathShape.cpp index aee21a1..543aaa8 100644
--- a/plugins/pathshapes/enhancedpath/EnhancedPathShape.cpp
+++ b/plugins/pathshapes/enhancedpath/EnhancedPathShape.cpp
@@ -61,6 +61,7 @@ void EnhancedPathShape::reset()
     m_viewMatrix.reset();
     m_viewBoxOffset = QPointF();
     clear();
+    m_textArea.clear();
 }
 
 void EnhancedPathShape::moveHandleAction(int handleId, const QPointF & point, \
Qt::KeyboardModifiers modifiers) @@ -185,6 +186,14 @@ qreal \
EnhancedPathShape::evaluateReference(const QString &reference)  return res;
 }
 
+qreal EnhancedPathShape::evaluateConstantOrReference(const QString &val)
+{
+    bool ok = true;
+    qreal res = val.toDouble(&ok);
+    if (ok) return res;
+    return evaluateReference(val);
+}
+
 void EnhancedPathShape::modifyReference(const QString &reference, qreal value)
 {
     if (reference.isEmpty())
@@ -346,6 +355,8 @@ void EnhancedPathShape::saveOdf(KoShapeSavingContext &context) \
const  modifiers += QString::number(modifier) + ' ';
         context.xmlWriter().addAttribute("draw:modifiers", modifiers.trimmed());
 
+        context.xmlWriter().addAttribute("draw:text-areas", m_textArea.join(" "));
+
         QString path;
         foreach (EnhancedPathCommand * c, m_commands)
             path += c->toString() + ' ';
@@ -391,6 +402,8 @@ bool EnhancedPathShape::loadOdf(const KoXmlElement & element, \
KoShapeLoadingCont  addModifiers(modifiers);
         }
 
+        m_textArea = enhancedGeometry.attributeNS(KoXmlNS::draw, "text-areas", \
"").split(' '); +
         KoXmlElement grandChild;
         forEachElement(grandChild, enhancedGeometry) {
             if (grandChild.namespaceURI() != KoXmlNS::draw)
@@ -446,7 +459,7 @@ bool EnhancedPathShape::loadOdf(const KoXmlElement & element, \
                KoShapeLoadingCont
     pos.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x", QString())));
     pos.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y", QString())));
     setPosition(pos);
-
+    
     loadOdfAttributes(element, context, OdfMandatories | OdfTransformation | \
OdfAdditionalAttributes | OdfCommonChildElements);  
     KoTextOnShapeContainer::tryWrapShape(this, element, context);
@@ -497,3 +510,31 @@ void EnhancedPathShape::setMirrorVertically(bool \
mirrorVertically)  m_mirrorVertically = mirrorVertically;
     }
 }
+
+void EnhancedPathShape::shapeChanged(ChangeType type, KoShape *shape)
+{
+    KoParameterShape::shapeChanged(type, shape);
+
+    if (!shape || shape == this) {
+        if (type == ParentChanged || type == ParameterChanged) {
+            updateTextArea();
+        }
+    }
+}
+
+void EnhancedPathShape::updateTextArea()
+{
+    KoTextOnShapeContainer* tosContainer = \
dynamic_cast<KoTextOnShapeContainer*>(parent()); +    if (tosContainer) {
+        tosContainer->setResizeBehavior(KoTextOnShapeContainer::TextFollowsPreferredTextRect);
 +        QRectF r = m_viewBox;
+        if (m_textArea.size() >= 4) {
+            r.setLeft(evaluateConstantOrReference(m_textArea[0]));
+            r.setTop(evaluateConstantOrReference(m_textArea[1]));
+            r.setRight(evaluateConstantOrReference(m_textArea[2]));
+            r.setBottom(evaluateConstantOrReference(m_textArea[3]));
+        }
+        r = m_viewMatrix.mapRect(r).translated(m_viewBoxOffset);
+        tosContainer->setPreferredTextRect(r);
+    }
+}
diff --git a/plugins/pathshapes/enhancedpath/EnhancedPathShape.h \
b/plugins/pathshapes/enhancedpath/EnhancedPathShape.h index 0014af9..85dbb9d 100644
--- a/plugins/pathshapes/enhancedpath/EnhancedPathShape.h
+++ b/plugins/pathshapes/enhancedpath/EnhancedPathShape.h
@@ -60,6 +60,14 @@ public:
     qreal evaluateReference(const QString &reference);
 
     /**
+     * Evaluates the given constant or reference to a identifier, modifier
+     * or formula.
+     * @param val the value to evaluate
+     * @return the result of the evaluation
+     */
+    qreal evaluateConstantOrReference(const QString &val);
+
+    /**
      * Attempts to modify a given reference.
      *
      * Only modifiers can me modified, others silently ignore the attempt.
@@ -110,6 +118,8 @@ protected:
     virtual void saveOdf(KoShapeSavingContext &context) const;
     // from KoShape
     virtual bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext \
&context); +    //from KoShape
+    virtual void shapeChanged(ChangeType type, KoShape *shape = 0);
     // from KoParameterShape
     virtual void moveHandleAction(int handleId, const QPointF &point, \
Qt::KeyboardModifiers modifiers = Qt::NoModifier);  // from KoParameterShape
@@ -125,6 +135,9 @@ private:
     /// Adds a new command
     void addCommand(const QString &command, bool triggerUpdate);
 
+    /// Updates the size and position of an optionally existing text-on-shape text \
area +    void updateTextArea();
+
     typedef QMap<QString, EnhancedPathFormula*> FormulaStore;
     typedef QList<qreal> ModifierStore;
     typedef QMap<QString, EnhancedPathParameter*> ParameterStore;
@@ -133,6 +146,7 @@ private:
     QRectF m_viewBound;   ///< the bounding box of the path in viewbox coordinates
     QTransform m_viewMatrix; ///< matrix to convert from viewbox coordinates to \
shape coordinates  QPointF m_viewBoxOffset;
+    QStringList m_textArea;
     QList<EnhancedPathCommand*> m_commands; ///< the commands creating the outline
     QList<EnhancedPathHandle*> m_enhancedHandles; ///< the handles for modifiying \
the shape  FormulaStore m_formulae;     ///< the formulae



_______________________________________________
koffice-devel mailing list
koffice-devel@kde.org
https://mail.kde.org/mailman/listinfo/koffice-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic