File indexing completed on 2024-05-12 15:27:33
0001 /*************************************************************************** 0002 File : TextLabel.cpp 0003 Project : LabPlot 0004 Description : Text label supporting reach text and latex formatting 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2009 Tilman Benkert (thzs@gmx.net) 0007 Copyright : (C) 2012-2018 Alexander Semke (alexander.semke@web.de) 0008 Copyright : (C) 2019 by Stefan Gerlach (stefan.gerlach@uni.kn) 0009 ***************************************************************************/ 0010 0011 /*************************************************************************** 0012 * * 0013 * This program is free software; you can redistribute it and/or modify * 0014 * it under the terms of the GNU General Public License as published by * 0015 * the Free Software Foundation; either version 2 of the License, or * 0016 * (at your option) any later version. * 0017 * * 0018 * This program is distributed in the hope that it will be useful, * 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0021 * GNU General Public License for more details. * 0022 * * 0023 * You should have received a copy of the GNU General Public License * 0024 * along with this program; if not, write to the Free Software * 0025 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0026 * Boston, MA 02110-1301 USA * 0027 * * 0028 ***************************************************************************/ 0029 0030 #include "TextLabel.h" 0031 #include "Worksheet.h" 0032 #include "TextLabelPrivate.h" 0033 #include "backend/lib/commandtemplates.h" 0034 #include "backend/lib/XmlStreamReader.h" 0035 0036 #include <QApplication> 0037 #include <QBuffer> 0038 #include <QDesktopWidget> 0039 #include <QGraphicsScene> 0040 #include <QGraphicsSceneMouseEvent> 0041 #include <QKeyEvent> 0042 #include <QMenu> 0043 #include <QPainter> 0044 #include <QTextCharFormat> 0045 #include <QTextDocument> 0046 #include <QTextCursor> 0047 #include <QtConcurrent/QtConcurrentRun> 0048 0049 #include <QIcon> 0050 #include <KConfig> 0051 #include <KConfigGroup> 0052 #include <KLocalizedString> 0053 0054 /** 0055 * \class TextLabel 0056 * \brief A label supporting rendering of html- and tex-formatted texts. 0057 * 0058 * The label is aligned relative to the specified position. 0059 * The position can be either specified by providing the x- and y- coordinates 0060 * in parent's coordinate system, or by specifying one of the predefined position 0061 * flags (\c HorizontalPosition, \c VerticalPosition). 0062 */ 0063 0064 TextLabel::TextLabel(const QString& name, Type type) 0065 : WorksheetElement(name, AspectType::TextLabel), d_ptr(new TextLabelPrivate(this)), m_type(type) { 0066 0067 init(); 0068 } 0069 0070 TextLabel::TextLabel(const QString &name, TextLabelPrivate *dd, Type type) 0071 : WorksheetElement(name, AspectType::TextLabel), d_ptr(dd), m_type(type) { 0072 0073 init(); 0074 } 0075 0076 TextLabel::Type TextLabel::type() const { 0077 return m_type; 0078 } 0079 0080 void TextLabel::init() { 0081 Q_D(TextLabel); 0082 0083 QString groupName; 0084 switch (m_type) { 0085 case Type::General: 0086 groupName = "TextLabel"; 0087 break; 0088 case Type::PlotTitle: 0089 groupName = "PlotTitle"; 0090 break; 0091 case Type::AxisTitle: 0092 groupName = "AxisTitle"; 0093 break; 0094 case Type::PlotLegendTitle: 0095 groupName = "PlotLegendTitle"; 0096 break; 0097 } 0098 0099 const KConfig config; 0100 DEBUG(" config has group \"" << STDSTRING(groupName) << "\": " << config.hasGroup(groupName)); 0101 // group is always valid if you call config.group(..; 0102 KConfigGroup group; 0103 if (config.hasGroup(groupName)) 0104 group = config.group(groupName); 0105 0106 // non-default settings 0107 d->staticText.setTextFormat(Qt::RichText); 0108 // explicitly set no wrap mode for text label to avoid unnecessary line breaks 0109 QTextOption textOption; 0110 textOption.setWrapMode(QTextOption::NoWrap); 0111 d->staticText.setTextOption(textOption); 0112 0113 if (m_type == Type::PlotTitle || m_type == Type::PlotLegendTitle) { 0114 d->position.verticalPosition = WorksheetElement::VerticalPosition::Top; 0115 d->verticalAlignment = WorksheetElement::VerticalAlignment::Bottom; 0116 } else if (m_type == Type::AxisTitle) { 0117 d->position.horizontalPosition = WorksheetElement::HorizontalPosition::Custom; 0118 d->position.verticalPosition = WorksheetElement::VerticalPosition::Custom; 0119 } 0120 0121 // read settings from config if group exists 0122 if (group.isValid()) { 0123 //properties common to all types 0124 d->textWrapper.teXUsed = group.readEntry("TeXUsed", d->textWrapper.teXUsed); 0125 d->teXFont.setFamily(group.readEntry("TeXFontFamily", d->teXFont.family())); 0126 d->teXFont.setPointSize(group.readEntry("TeXFontSize", d->teXFont.pointSize())); 0127 d->fontColor = group.readEntry("TeXFontColor", d->fontColor); 0128 d->backgroundColor = group.readEntry("TeXBackgroundColor", d->backgroundColor); 0129 d->rotationAngle = group.readEntry("Rotation", d->rotationAngle); 0130 0131 //border 0132 d->borderShape = (TextLabel::BorderShape)group.readEntry("BorderShape", (int)d->borderShape); 0133 d->borderPen = QPen(group.readEntry("BorderColor", d->borderPen.color()), 0134 group.readEntry("BorderWidth", d->borderPen.width()), 0135 (Qt::PenStyle) group.readEntry("BorderStyle", (int)(d->borderPen.style()))); 0136 d->borderOpacity = group.readEntry("BorderOpacity", d->borderOpacity); 0137 0138 //position and alignment relevant properties 0139 d->position.point.setX( group.readEntry("PositionXValue", d->position.point.x()) ); 0140 d->position.point.setY( group.readEntry("PositionYValue", d->position.point.y()) ); 0141 d->position.horizontalPosition = (HorizontalPosition) group.readEntry("PositionX", (int)d->position.horizontalPosition); 0142 d->position.verticalPosition = (VerticalPosition) group.readEntry("PositionY", (int)d->position.verticalPosition); 0143 d->horizontalAlignment = (WorksheetElement::HorizontalAlignment) group.readEntry("HorizontalAlignment", static_cast<int>(d->horizontalAlignment)); 0144 d->verticalAlignment = (WorksheetElement::VerticalAlignment) group.readEntry("VerticalAlignment", static_cast<int>(d->verticalAlignment)); 0145 } 0146 0147 DEBUG("CHECK: default/run time image resolution: " << d->teXImageResolution << '/' << QApplication::desktop()->physicalDpiX()); 0148 0149 connect(&d->teXImageFutureWatcher, &QFutureWatcher<QImage>::finished, this, &TextLabel::updateTeXImage); 0150 } 0151 0152 //no need to delete the d-pointer here - it inherits from QGraphicsItem 0153 //and is deleted during the cleanup in QGraphicsScene 0154 TextLabel::~TextLabel() = default; 0155 0156 QGraphicsItem* TextLabel::graphicsItem() const { 0157 return d_ptr; 0158 } 0159 0160 void TextLabel::setParentGraphicsItem(QGraphicsItem* item) { 0161 Q_D(TextLabel); 0162 d->setParentItem(item); 0163 d->updatePosition(); 0164 } 0165 0166 void TextLabel::retransform() { 0167 Q_D(TextLabel); 0168 d->retransform(); 0169 } 0170 0171 void TextLabel::handleResize(double horizontalRatio, double verticalRatio, bool pageResize) { 0172 DEBUG("TextLabel::handleResize()"); 0173 Q_UNUSED(pageResize); 0174 Q_D(TextLabel); 0175 0176 double ratio = 0; 0177 if (horizontalRatio > 1.0 || verticalRatio > 1.0) 0178 ratio = qMax(horizontalRatio, verticalRatio); 0179 else 0180 ratio = qMin(horizontalRatio, verticalRatio); 0181 0182 d->teXFont.setPointSizeF(d->teXFont.pointSizeF() * ratio); 0183 d->updateText(); 0184 0185 //TODO: doesn't seem to work 0186 QTextDocument doc; 0187 doc.setHtml(d->textWrapper.text); 0188 QTextCursor cursor(&doc); 0189 cursor.select(QTextCursor::Document); 0190 QTextCharFormat fmt = cursor.charFormat(); 0191 QFont font = fmt.font(); 0192 font.setPointSizeF(font.pointSizeF() * ratio); 0193 fmt.setFont(font); 0194 cursor.setCharFormat(fmt); 0195 } 0196 0197 /*! 0198 Returns an icon to be used in the project explorer. 0199 */ 0200 QIcon TextLabel::icon() const{ 0201 return QIcon::fromTheme("draw-text"); 0202 } 0203 0204 QMenu* TextLabel::createContextMenu() { 0205 QMenu* menu = WorksheetElement::createContextMenu(); 0206 QAction* firstAction = menu->actions().at(1); //skip the first action because of the "title-action" 0207 0208 if (!visibilityAction) { 0209 visibilityAction = new QAction(i18n("Visible"), this); 0210 visibilityAction->setCheckable(true); 0211 connect(visibilityAction, &QAction::triggered, this, &TextLabel::visibilityChanged); 0212 } 0213 0214 visibilityAction->setChecked(isVisible()); 0215 menu->insertAction(firstAction, visibilityAction); 0216 menu->insertSeparator(firstAction); 0217 0218 return menu; 0219 } 0220 0221 /* ============================ getter methods ================= */ 0222 CLASS_SHARED_D_READER_IMPL(TextLabel, TextLabel::TextWrapper, text, textWrapper) 0223 CLASS_SHARED_D_READER_IMPL(TextLabel, QColor, fontColor, fontColor); 0224 CLASS_SHARED_D_READER_IMPL(TextLabel, QColor, backgroundColor, backgroundColor); 0225 CLASS_SHARED_D_READER_IMPL(TextLabel, QFont, teXFont, teXFont); 0226 CLASS_SHARED_D_READER_IMPL(TextLabel, TextLabel::PositionWrapper, position, position); 0227 BASIC_SHARED_D_READER_IMPL(TextLabel, WorksheetElement::HorizontalAlignment, horizontalAlignment, horizontalAlignment); 0228 BASIC_SHARED_D_READER_IMPL(TextLabel, WorksheetElement::VerticalAlignment, verticalAlignment, verticalAlignment); 0229 BASIC_SHARED_D_READER_IMPL(TextLabel, qreal, rotationAngle, rotationAngle); 0230 0231 BASIC_SHARED_D_READER_IMPL(TextLabel, TextLabel::BorderShape, borderShape, borderShape) 0232 CLASS_SHARED_D_READER_IMPL(TextLabel, QPen, borderPen, borderPen) 0233 BASIC_SHARED_D_READER_IMPL(TextLabel, qreal, borderOpacity, borderOpacity) 0234 0235 /* ============================ setter methods and undo commands ================= */ 0236 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetText, TextLabel::TextWrapper, textWrapper, updateText); 0237 void TextLabel::setText(const TextWrapper &textWrapper) { 0238 Q_D(TextLabel); 0239 if ( (textWrapper.text != d->textWrapper.text) || (textWrapper.teXUsed != d->textWrapper.teXUsed) ) 0240 exec(new TextLabelSetTextCmd(d, textWrapper, ki18n("%1: set label text"))); 0241 } 0242 0243 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetTeXFont, QFont, teXFont, updateText); 0244 void TextLabel::setTeXFont(const QFont& font) { 0245 Q_D(TextLabel); 0246 if (font != d->teXFont) 0247 exec(new TextLabelSetTeXFontCmd(d, font, ki18n("%1: set TeX main font"))); 0248 } 0249 0250 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetTeXFontColor, QColor, fontColor, updateText); 0251 void TextLabel::setFontColor(const QColor color) { 0252 Q_D(TextLabel); 0253 if (color != d->fontColor) 0254 exec(new TextLabelSetTeXFontColorCmd(d, color, ki18n("%1: set font color"))); 0255 } 0256 0257 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetTeXBackgroundColor, QColor, backgroundColor, updateText); 0258 void TextLabel::setBackgroundColor(const QColor color) { 0259 Q_D(TextLabel); 0260 if (color != d->backgroundColor) 0261 exec(new TextLabelSetTeXBackgroundColorCmd(d, color, ki18n("%1: set background color"))); 0262 } 0263 0264 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetPosition, TextLabel::PositionWrapper, position, retransform); 0265 void TextLabel::setPosition(const PositionWrapper& pos) { 0266 Q_D(TextLabel); 0267 if (pos.point != d->position.point || pos.horizontalPosition != d->position.horizontalPosition || pos.verticalPosition != d->position.verticalPosition) 0268 exec(new TextLabelSetPositionCmd(d, pos, ki18n("%1: set position"))); 0269 0270 } 0271 0272 /*! 0273 sets the position without undo/redo-stuff 0274 */ 0275 void TextLabel::setPosition(QPointF point) { 0276 Q_D(TextLabel); 0277 if (point != d->position.point) { 0278 d->position.point = point; 0279 retransform(); 0280 } 0281 } 0282 0283 /*! 0284 * position is set to invalid if the parent item is not drawn on the scene 0285 * (e.g. axis is not drawn because it's outside plot ranges -> don't draw axis' title label) 0286 */ 0287 void TextLabel::setPositionInvalid(bool invalid) { 0288 Q_D(TextLabel); 0289 if (invalid != d->positionInvalid) 0290 d->positionInvalid = invalid; 0291 } 0292 0293 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetRotationAngle, qreal, rotationAngle, recalcShapeAndBoundingRect); 0294 void TextLabel::setRotationAngle(qreal angle) { 0295 Q_D(TextLabel); 0296 if (angle != d->rotationAngle) 0297 exec(new TextLabelSetRotationAngleCmd(d, angle, ki18n("%1: set rotation angle"))); 0298 } 0299 0300 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetHorizontalAlignment, TextLabel::HorizontalAlignment, horizontalAlignment, retransform); 0301 void TextLabel::setHorizontalAlignment(const WorksheetElement::HorizontalAlignment hAlign) { 0302 Q_D(TextLabel); 0303 if (hAlign != d->horizontalAlignment) 0304 exec(new TextLabelSetHorizontalAlignmentCmd(d, hAlign, ki18n("%1: set horizontal alignment"))); 0305 } 0306 0307 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetVerticalAlignment, WorksheetElement::VerticalAlignment, verticalAlignment, retransform); 0308 void TextLabel::setVerticalAlignment(const TextLabel::VerticalAlignment vAlign) { 0309 Q_D(TextLabel); 0310 if (vAlign != d->verticalAlignment) 0311 exec(new TextLabelSetVerticalAlignmentCmd(d, vAlign, ki18n("%1: set vertical alignment"))); 0312 } 0313 0314 //Border 0315 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetBorderShape, TextLabel::BorderShape, borderShape, updateBorder) 0316 void TextLabel::setBorderShape(TextLabel::BorderShape shape) { 0317 Q_D(TextLabel); 0318 if (shape != d->borderShape) 0319 exec(new TextLabelSetBorderShapeCmd(d, shape, ki18n("%1: set border shape"))); 0320 } 0321 0322 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetBorderPen, QPen, borderPen, update) 0323 void TextLabel::setBorderPen(const QPen &pen) { 0324 Q_D(TextLabel); 0325 if (pen != d->borderPen) 0326 exec(new TextLabelSetBorderPenCmd(d, pen, ki18n("%1: set border"))); 0327 } 0328 0329 STD_SETTER_CMD_IMPL_F_S(TextLabel, SetBorderOpacity, qreal, borderOpacity, update) 0330 void TextLabel::setBorderOpacity(qreal opacity) { 0331 Q_D(TextLabel); 0332 if (opacity != d->borderOpacity) 0333 exec(new TextLabelSetBorderOpacityCmd(d, opacity, ki18n("%1: set border opacity"))); 0334 } 0335 0336 //misc 0337 STD_SWAP_METHOD_SETTER_CMD_IMPL_F(TextLabel, SetVisible, bool, swapVisible, retransform); 0338 void TextLabel::setVisible(bool on) { 0339 Q_D(TextLabel); 0340 exec(new TextLabelSetVisibleCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible"))); 0341 } 0342 0343 bool TextLabel::isVisible() const { 0344 Q_D(const TextLabel); 0345 return d->isVisible(); 0346 } 0347 0348 void TextLabel::setPrinting(bool on) { 0349 Q_D(TextLabel); 0350 d->m_printing = on; 0351 } 0352 0353 void TextLabel::updateTeXImage() { 0354 Q_D(TextLabel); 0355 d->updateTeXImage(); 0356 } 0357 0358 //############################################################################## 0359 //###### SLOTs for changes triggered via QActions in the context menu ######## 0360 //############################################################################## 0361 void TextLabel::visibilityChanged() { 0362 Q_D(const TextLabel); 0363 this->setVisible(!d->isVisible()); 0364 } 0365 0366 //############################################################################## 0367 //####################### Private implementation ############################### 0368 //############################################################################## 0369 TextLabelPrivate::TextLabelPrivate(TextLabel* owner) : q(owner) { 0370 setFlag(QGraphicsItem::ItemIsSelectable); 0371 setFlag(QGraphicsItem::ItemIsMovable); 0372 setFlag(QGraphicsItem::ItemSendsGeometryChanges); 0373 setFlag(QGraphicsItem::ItemIsFocusable); 0374 setAcceptHoverEvents(true); 0375 } 0376 0377 QString TextLabelPrivate::name() const { 0378 return q->name(); 0379 } 0380 0381 /*! 0382 calculates the position and the bounding box of the label. Called on geometry or text changes. 0383 */ 0384 void TextLabelPrivate::retransform() { 0385 if (suppressRetransform) 0386 return; 0387 0388 if (position.horizontalPosition != WorksheetElement::HorizontalPosition::Custom 0389 || position.verticalPosition != WorksheetElement::VerticalPosition::Custom) 0390 updatePosition(); 0391 0392 double x = position.point.x(); 0393 double y = position.point.y(); 0394 0395 //determine the size of the label in scene units. 0396 double w, h; 0397 if (textWrapper.teXUsed) { 0398 //image size is in pixel, convert to scene units 0399 w = teXImage.width()*teXImageScaleFactor; 0400 h = teXImage.height()*teXImageScaleFactor; 0401 } 0402 else { 0403 //size is in points, convert to scene units 0404 w = staticText.size().width()*scaleFactor; 0405 h = staticText.size().height()*scaleFactor; 0406 } 0407 0408 //depending on the alignment, calculate the new GraphicsItem's position in parent's coordinate system 0409 QPointF itemPos; 0410 switch (horizontalAlignment) { 0411 case WorksheetElement::HorizontalAlignment::Left: 0412 itemPos.setX(x - w/2); 0413 break; 0414 case WorksheetElement::HorizontalAlignment::Center: 0415 itemPos.setX(x); 0416 break; 0417 case WorksheetElement::HorizontalAlignment::Right: 0418 itemPos.setX(x + w/2); 0419 break; 0420 } 0421 0422 switch (verticalAlignment) { 0423 case WorksheetElement::VerticalAlignment::Top: 0424 itemPos.setY(y - h/2); 0425 break; 0426 case WorksheetElement::VerticalAlignment::Center: 0427 itemPos.setY(y); 0428 break; 0429 case WorksheetElement::VerticalAlignment::Bottom: 0430 itemPos.setY(y + h/2); 0431 break; 0432 } 0433 0434 suppressItemChangeEvent = true; 0435 setPos(itemPos); 0436 suppressItemChangeEvent = false; 0437 0438 boundingRectangle.setX(-w/2); 0439 boundingRectangle.setY(-h/2); 0440 boundingRectangle.setWidth(w); 0441 boundingRectangle.setHeight(h); 0442 0443 updateBorder(); 0444 0445 emit q->changed(); 0446 } 0447 0448 /*! 0449 calculates the position of the label, when the position relative to the parent was specified (left, right, etc.) 0450 */ 0451 void TextLabelPrivate::updatePosition() { 0452 //determine the parent item 0453 QRectF parentRect; 0454 QGraphicsItem* parent = parentItem(); 0455 if (parent) { 0456 parentRect = parent->boundingRect(); 0457 } else { 0458 if (!scene()) 0459 return; 0460 0461 parentRect = scene()->sceneRect(); 0462 } 0463 0464 if (position.horizontalPosition != WorksheetElement::HorizontalPosition::Custom) { 0465 if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Left) 0466 position.point.setX( parentRect.x() ); 0467 else if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Center) 0468 position.point.setX( parentRect.x() + parentRect.width()/2 ); 0469 else if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Right) 0470 position.point.setX( parentRect.x() + parentRect.width() ); 0471 } 0472 0473 if (position.verticalPosition != WorksheetElement::VerticalPosition::Custom) { 0474 if (position.verticalPosition == WorksheetElement::VerticalPosition::Top) 0475 position.point.setY( parentRect.y() ); 0476 else if (position.verticalPosition == WorksheetElement::VerticalPosition::Center) 0477 position.point.setY( parentRect.y() + parentRect.height()/2 ); 0478 else if (position.verticalPosition == WorksheetElement::VerticalPosition::Bottom) 0479 position.point.setY( parentRect.y() + parentRect.height() ); 0480 } 0481 0482 emit q->positionChanged(position); 0483 } 0484 0485 /*! 0486 updates the static text. 0487 */ 0488 void TextLabelPrivate::updateText() { 0489 if (suppressRetransform) 0490 return; 0491 0492 if (textWrapper.teXUsed) { 0493 TeXRenderer::Formatting format; 0494 format.fontColor = fontColor; 0495 format.backgroundColor = backgroundColor; 0496 format.fontSize = teXFont.pointSize(); 0497 format.fontFamily = teXFont.family(); 0498 format.dpi = teXImageResolution; 0499 QFuture<QImage> future = QtConcurrent::run(TeXRenderer::renderImageLaTeX, textWrapper.text, &teXRenderSuccessful, format); 0500 teXImageFutureWatcher.setFuture(future); 0501 0502 //don't need to call retransorm() here since it is done in updateTeXImage 0503 //when the asynchronous rendering of the image is finished. 0504 } else { 0505 staticText.setText(textWrapper.text); 0506 0507 //the size of the label was most probably changed. 0508 //call retransform() to recalculate the position and the bounding box of the label 0509 retransform(); 0510 } 0511 } 0512 0513 void TextLabelPrivate::updateTeXImage() { 0514 teXImage = teXImageFutureWatcher.result(); 0515 retransform(); 0516 DEBUG("teXRenderSuccessful =" << teXRenderSuccessful); 0517 emit q->teXImageUpdated(teXRenderSuccessful); 0518 } 0519 0520 void TextLabelPrivate::updateBorder() { 0521 borderShapePath = QPainterPath(); 0522 switch (borderShape) { 0523 case TextLabel::BorderShape::NoBorder: 0524 break; 0525 case TextLabel::BorderShape::Rect: 0526 borderShapePath.addRect(boundingRectangle); 0527 break; 0528 case TextLabel::BorderShape::Ellipse: { 0529 const double xs = boundingRectangle.x(); 0530 const double ys = boundingRectangle.y(); 0531 const double w = boundingRectangle.width(); 0532 const double h = boundingRectangle.height(); 0533 borderShapePath.addEllipse(xs - 0.1 * w, ys - 0.1 * h, 1.2 * w, 1.2 * h); 0534 break; 0535 } 0536 case TextLabel::BorderShape::RoundSideRect: { 0537 const double xs = boundingRectangle.x(); 0538 const double ys = boundingRectangle.y(); 0539 const double w = boundingRectangle.width(); 0540 const double h = boundingRectangle.height(); 0541 borderShapePath.moveTo(xs, ys); 0542 borderShapePath.lineTo(xs + w, ys); 0543 borderShapePath.quadTo(xs + w + h/2, ys + h/2, xs + w, ys + h); 0544 borderShapePath.lineTo(xs, ys + h); 0545 borderShapePath.quadTo(xs - h/2, ys + h/2, xs, ys); 0546 break; 0547 } 0548 case TextLabel::BorderShape::RoundCornerRect: { 0549 const double xs = boundingRectangle.x(); 0550 const double ys = boundingRectangle.y(); 0551 const double w = boundingRectangle.width(); 0552 const double h = boundingRectangle.height(); 0553 borderShapePath.moveTo(xs + h * 0.2, ys); 0554 borderShapePath.lineTo(xs + w - h * 0.2, ys); 0555 borderShapePath.quadTo(xs + w, ys, xs + w, ys + h * 0.2); 0556 borderShapePath.lineTo(xs + w, ys + h - 0.2 * h); 0557 borderShapePath.quadTo(xs + w, ys + h, xs + w - 0.2 * h, ys + h); 0558 borderShapePath.lineTo(xs + 0.2 * h, ys + h); 0559 borderShapePath.quadTo(xs, ys + h, xs, ys + h - 0.2 * h); 0560 borderShapePath.lineTo(xs, ys + 0.2 * h); 0561 borderShapePath.quadTo(xs, ys, xs + 0.2 * h, ys); 0562 break; 0563 } 0564 case TextLabel::BorderShape::InwardsRoundCornerRect: { 0565 const double xs = boundingRectangle.x(); 0566 const double ys = boundingRectangle.y(); 0567 const double w = boundingRectangle.width(); 0568 const double h = boundingRectangle.height(); 0569 borderShapePath.moveTo(xs, ys - 0.3 * h); 0570 borderShapePath.lineTo(xs + w, ys - 0.3 * h); 0571 borderShapePath.quadTo(xs + w, ys, xs + w + 0.3 * h, ys); 0572 borderShapePath.lineTo(xs + w + 0.3 * h, ys + h); 0573 borderShapePath.quadTo(xs + w, ys + h, xs + w, ys + h + 0.3 * h); 0574 borderShapePath.lineTo(xs, ys + h + 0.3 * h); 0575 borderShapePath.quadTo(xs, ys + h, xs - 0.3 * h, ys + h); 0576 borderShapePath.lineTo(xs - 0.3 * h, ys); 0577 borderShapePath.quadTo(xs, ys, xs, ys - 0.3 * h); 0578 break; 0579 } 0580 case TextLabel::BorderShape::DentedBorderRect: { 0581 const double xs = boundingRectangle.x(); 0582 const double ys = boundingRectangle.y(); 0583 const double w = boundingRectangle.width(); 0584 const double h = boundingRectangle.height(); 0585 borderShapePath.moveTo(xs - 0.2 * h, ys - 0.2 * h); 0586 borderShapePath.quadTo(xs + w / 2, ys, xs + w + 0.2 * h, ys - 0.2 * h); 0587 borderShapePath.quadTo(xs + w, ys + h / 2, xs + w + 0.2 * h, ys + h + 0.2 * h); 0588 borderShapePath.quadTo(xs + w / 2, ys + h, xs - 0.2 * h, ys + h + 0.2 * h); 0589 borderShapePath.quadTo(xs, ys + h / 2, xs - 0.2 * h, ys - 0.2 * h); 0590 break; 0591 } 0592 case TextLabel::BorderShape::Cuboid: { 0593 const double xs = boundingRectangle.x(); 0594 const double ys = boundingRectangle.y(); 0595 const double w = boundingRectangle.width(); 0596 const double h = boundingRectangle.height(); 0597 borderShapePath.moveTo(xs, ys); 0598 borderShapePath.lineTo(xs + w, ys); 0599 borderShapePath.lineTo(xs + w, ys + h); 0600 borderShapePath.lineTo(xs, ys + h); 0601 borderShapePath.lineTo(xs, ys); 0602 borderShapePath.lineTo(xs + 0.3 * h, ys - 0.2 * h); 0603 borderShapePath.lineTo(xs + w + 0.3 * h, ys - 0.2 * h); 0604 borderShapePath.lineTo(xs + w, ys); 0605 borderShapePath.moveTo(xs + w, ys + h); 0606 borderShapePath.lineTo(xs + w + 0.3 * h, ys + h - 0.2 * h); 0607 borderShapePath.lineTo(xs + w + 0.3 * h, ys - 0.2 * h); 0608 break; 0609 } 0610 case TextLabel::BorderShape::UpPointingRectangle: { 0611 const double xs = boundingRectangle.x(); 0612 const double ys = boundingRectangle.y(); 0613 const double w = boundingRectangle.width(); 0614 const double h = boundingRectangle.height(); 0615 borderShapePath.moveTo(xs + h * 0.2, ys); 0616 borderShapePath.lineTo(xs + w / 2 - 0.2 * h, ys); 0617 borderShapePath.lineTo(xs + w / 2, ys - 0.2 * h); 0618 borderShapePath.lineTo(xs + w / 2 + 0.2 * h, ys); 0619 borderShapePath.lineTo(xs + w - h * 0.2, ys); 0620 borderShapePath.quadTo(xs + w, ys, xs + w, ys + h * 0.2); 0621 borderShapePath.lineTo(xs + w, ys + h - 0.2 * h); 0622 borderShapePath.quadTo(xs + w, ys + h, xs + w - 0.2 * h, ys + h); 0623 borderShapePath.lineTo(xs + 0.2 * h, ys + h); 0624 borderShapePath.quadTo(xs, ys + h, xs, ys + h - 0.2 * h); 0625 borderShapePath.lineTo(xs, ys + 0.2 * h); 0626 borderShapePath.quadTo(xs, ys, xs + 0.2 * h, ys); 0627 break; 0628 } 0629 case (TextLabel::BorderShape::DownPointingRectangle): { 0630 const double xs = boundingRectangle.x(); 0631 const double ys = boundingRectangle.y(); 0632 const double w = boundingRectangle.width(); 0633 const double h = boundingRectangle.height(); 0634 borderShapePath.moveTo(xs +h * 0.2, ys); 0635 borderShapePath.lineTo(xs + w - h * 0.2, ys); 0636 borderShapePath.quadTo(xs + w, ys, xs + w, ys + h * 0.2); 0637 borderShapePath.lineTo(xs + w, ys + h - 0.2 * h); 0638 borderShapePath.quadTo(xs + w, ys + h, xs + w - 0.2 * h, ys + h); 0639 borderShapePath.lineTo(xs + w / 2 + 0.2 * h, ys + h); 0640 borderShapePath.lineTo(xs + w / 2, ys + h + 0.2 * h); 0641 borderShapePath.lineTo(xs + w / 2 - 0.2 * h, ys + h); 0642 borderShapePath.lineTo(xs + 0.2 * h, ys + h); 0643 borderShapePath.quadTo(xs, ys + h, xs, ys + h - 0.2 * h); 0644 borderShapePath.lineTo(xs, ys + 0.2 * h); 0645 borderShapePath.quadTo(xs, ys, xs + 0.2 * h, ys); 0646 break; 0647 } 0648 case (TextLabel::BorderShape::LeftPointingRectangle): { 0649 const double xs = boundingRectangle.x(); 0650 const double ys = boundingRectangle.y(); 0651 const double w = boundingRectangle.width(); 0652 const double h = boundingRectangle.height(); 0653 borderShapePath.moveTo(xs + h*0.2, ys); 0654 borderShapePath.lineTo(xs + w - h * 0.2, ys); 0655 borderShapePath.quadTo(xs + w, ys, xs + w, ys + h * 0.2); 0656 borderShapePath.lineTo(xs + w, ys + h - 0.2 * h); 0657 borderShapePath.quadTo(xs + w, ys + h, xs + w - 0.2 * h, ys + h); 0658 borderShapePath.lineTo(xs + 0.2 * h, ys + h); 0659 borderShapePath.quadTo(xs, ys + h, xs, ys + h - 0.2 * h); 0660 borderShapePath.lineTo(xs, ys + h / 2 + 0.2 * h); 0661 borderShapePath.lineTo(xs - 0.2 * h, ys + h / 2); 0662 borderShapePath.lineTo(xs, ys + h / 2 - 0.2 * h); 0663 borderShapePath.lineTo(xs, ys + 0.2 * h); 0664 borderShapePath.quadTo(xs, ys, xs + 0.2 * h, ys); 0665 break; 0666 } 0667 case (TextLabel::BorderShape::RightPointingRectangle): { 0668 const double xs = boundingRectangle.x(); 0669 const double ys = boundingRectangle.y(); 0670 const double w = boundingRectangle.width(); 0671 const double h = boundingRectangle.height(); 0672 borderShapePath.moveTo(xs + h * 0.2, ys); 0673 borderShapePath.lineTo(xs + w - h * 0.2, ys); 0674 borderShapePath.quadTo(xs + w, ys, xs + w, ys + h * 0.2); 0675 borderShapePath.lineTo(xs + w, ys + h / 2 - 0.2 * h); 0676 borderShapePath.lineTo(xs + w + 0.2 * h, ys + h / 2); 0677 borderShapePath.lineTo(xs + w, ys + h / 2 + 0.2 * h); 0678 borderShapePath.lineTo(xs + w, ys + h - 0.2 * h); 0679 borderShapePath.quadTo(xs + w, ys + h, xs + w - 0.2 * h, ys + h); 0680 borderShapePath.lineTo(xs + 0.2 * h, ys + h); 0681 borderShapePath.quadTo(xs, ys + h, xs, ys + h - 0.2 * h); 0682 borderShapePath.lineTo(xs, ys + 0.2 * h); 0683 borderShapePath.quadTo(xs, ys, xs + 0.2 * h, ys); 0684 break; 0685 } 0686 } 0687 0688 recalcShapeAndBoundingRect(); 0689 } 0690 0691 bool TextLabelPrivate::swapVisible(bool on) { 0692 bool oldValue = isVisible(); 0693 0694 //When making a graphics item invisible, it gets deselected in the scene. 0695 //In this case we don't want to deselect the item in the project explorer. 0696 //We need to supress the deselection in the view. 0697 auto* worksheet = static_cast<Worksheet*>(q->parent(AspectType::Worksheet)); 0698 worksheet->suppressSelectionChangedEvent(true); 0699 setVisible(on); 0700 worksheet->suppressSelectionChangedEvent(false); 0701 0702 emit q->changed(); 0703 emit q->visibleChanged(on); 0704 return oldValue; 0705 } 0706 0707 /*! 0708 Returns the outer bounds of the item as a rectangle. 0709 */ 0710 QRectF TextLabelPrivate::boundingRect() const { 0711 return transformedBoundingRectangle; 0712 } 0713 0714 /*! 0715 Returns the shape of this item as a QPainterPath in local coordinates. 0716 */ 0717 QPainterPath TextLabelPrivate::shape() const { 0718 return labelShape; 0719 } 0720 0721 /*! 0722 recalculates the outer bounds and the shape of the label. 0723 */ 0724 void TextLabelPrivate::recalcShapeAndBoundingRect() { 0725 prepareGeometryChange(); 0726 0727 QMatrix matrix; 0728 matrix.rotate(-rotationAngle); 0729 labelShape = QPainterPath(); 0730 if (borderShape != TextLabel::BorderShape::NoBorder) { 0731 labelShape.addPath(WorksheetElement::shapeFromPath(borderShapePath, borderPen)); 0732 transformedBoundingRectangle = matrix.mapRect(labelShape.boundingRect()); 0733 } else { 0734 labelShape.addRect(boundingRectangle); 0735 transformedBoundingRectangle = matrix.mapRect(boundingRectangle); 0736 } 0737 0738 labelShape = matrix.map(labelShape); 0739 } 0740 0741 void TextLabelPrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { 0742 Q_UNUSED(option) 0743 Q_UNUSED(widget) 0744 0745 if (positionInvalid || textWrapper.text.isEmpty()) 0746 return; 0747 0748 painter->save(); 0749 painter->rotate(-rotationAngle); 0750 0751 //draw the text 0752 if (textWrapper.teXUsed) { 0753 if (boundingRect().width() != 0.0 && boundingRect().height() != 0.0) 0754 painter->drawImage(boundingRect(), teXImage); 0755 } else { 0756 // don't set pen color, the color is already in the HTML code 0757 //painter->setPen(fontColor); 0758 painter->scale(scaleFactor, scaleFactor); 0759 qreal w = staticText.size().width(); 0760 qreal h = staticText.size().height(); 0761 //staticText.setPerformanceHint(QStaticText::AggressiveCaching); 0762 //QDEBUG(Q_FUNC_INFO << ", Drawing text:" << staticText.text()) 0763 painter->drawStaticText(QPointF(-w/2., -h/2.), staticText); 0764 } 0765 painter->restore(); 0766 0767 //draw the border 0768 if (borderShape != TextLabel::BorderShape::NoBorder) { 0769 painter->save(); 0770 painter->setPen(borderPen); 0771 painter->setOpacity(borderOpacity); 0772 0773 painter->rotate(-rotationAngle); 0774 painter->drawPath(borderShapePath); 0775 painter->restore(); 0776 } 0777 0778 if (m_hovered && !isSelected() && !m_printing) { 0779 painter->setPen(QPen(QApplication::palette().color(QPalette::Shadow), 2, Qt::SolidLine)); 0780 painter->drawPath(labelShape); 0781 } 0782 0783 if (isSelected() && !m_printing) { 0784 painter->setPen(QPen(QApplication::palette().color(QPalette::Highlight), 2, Qt::SolidLine)); 0785 painter->drawPath(labelShape); 0786 } 0787 } 0788 0789 QVariant TextLabelPrivate::itemChange(GraphicsItemChange change, const QVariant &value) { 0790 if (suppressItemChangeEvent) 0791 return value; 0792 0793 if (change == QGraphicsItem::ItemPositionChange) { 0794 //convert item's center point in parent's coordinates 0795 TextLabel::PositionWrapper tempPosition; 0796 tempPosition.point = positionFromItemPosition(value.toPointF()); 0797 tempPosition.horizontalPosition = WorksheetElement::HorizontalPosition::Custom; 0798 tempPosition.verticalPosition = WorksheetElement::VerticalPosition::Custom; 0799 0800 //emit the signals in order to notify the UI. 0801 //we don't set the position related member variables during the mouse movements. 0802 //this is done on mouse release events only. 0803 emit q->positionChanged(tempPosition); 0804 } 0805 0806 return QGraphicsItem::itemChange(change, value); 0807 } 0808 0809 void TextLabelPrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { 0810 //convert position of the item in parent coordinates to label's position 0811 QPointF point = positionFromItemPosition(pos()); 0812 if (point != position.point) { 0813 //position was changed -> set the position related member variables 0814 suppressRetransform = true; 0815 TextLabel::PositionWrapper tempPosition; 0816 tempPosition.point = point; 0817 tempPosition.horizontalPosition = WorksheetElement::HorizontalPosition::Custom; 0818 tempPosition.verticalPosition = WorksheetElement::VerticalPosition::Custom; 0819 q->setPosition(tempPosition); 0820 suppressRetransform = false; 0821 } 0822 0823 QGraphicsItem::mouseReleaseEvent(event); 0824 } 0825 0826 void TextLabelPrivate::keyPressEvent(QKeyEvent* event) { 0827 if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right 0828 || event->key() == Qt::Key_Up ||event->key() == Qt::Key_Down) { 0829 const int delta = 5; 0830 QPointF point = positionFromItemPosition(pos()); 0831 WorksheetElement::PositionWrapper tempPosition; 0832 0833 if (event->key() == Qt::Key_Left) { 0834 point.setX(point.x() - delta); 0835 tempPosition.horizontalPosition = WorksheetElement::HorizontalPosition::Custom; 0836 tempPosition.verticalPosition = position.verticalPosition; 0837 } else if (event->key() == Qt::Key_Right) { 0838 point.setX(point.x() + delta); 0839 tempPosition.horizontalPosition = WorksheetElement::HorizontalPosition::Custom; 0840 tempPosition.verticalPosition = position.verticalPosition; 0841 } else if (event->key() == Qt::Key_Up) { 0842 point.setY(point.y() - delta); 0843 tempPosition.horizontalPosition = position.horizontalPosition; 0844 tempPosition.verticalPosition = WorksheetElement::VerticalPosition::Custom; 0845 } else if (event->key() == Qt::Key_Down) { 0846 point.setY(point.y() + delta); 0847 tempPosition.horizontalPosition = position.horizontalPosition; 0848 tempPosition.verticalPosition = WorksheetElement::VerticalPosition::Custom; 0849 } 0850 0851 tempPosition.point = point; 0852 q->setPosition(tempPosition); 0853 } 0854 0855 QGraphicsItem::keyPressEvent(event); 0856 } 0857 0858 /*! 0859 * converts label's position to GraphicsItem's position. 0860 */ 0861 QPointF TextLabelPrivate::positionFromItemPosition(QPointF itemPos) { 0862 double x = itemPos.x(); 0863 double y = itemPos.y(); 0864 double w, h; 0865 QPointF tmpPosition; 0866 if (textWrapper.teXUsed) { 0867 w = teXImage.width()*scaleFactor; 0868 h = teXImage.height()*scaleFactor; 0869 } else { 0870 w = staticText.size().width()*scaleFactor; 0871 h = staticText.size().height()*scaleFactor; 0872 } 0873 0874 //depending on the alignment, calculate the new position 0875 switch (horizontalAlignment) { 0876 case WorksheetElement::HorizontalAlignment::Left: 0877 tmpPosition.setX(x + w/2); 0878 break; 0879 case WorksheetElement::HorizontalAlignment::Center: 0880 tmpPosition.setX(x); 0881 break; 0882 case WorksheetElement::HorizontalAlignment::Right: 0883 tmpPosition.setX(x - w/2); 0884 break; 0885 } 0886 0887 switch (verticalAlignment) { 0888 case WorksheetElement::VerticalAlignment::Top: 0889 tmpPosition.setY(y + h/2); 0890 break; 0891 case WorksheetElement::VerticalAlignment::Center: 0892 tmpPosition.setY(y); 0893 break; 0894 case WorksheetElement::VerticalAlignment::Bottom: 0895 tmpPosition.setY(y - h/2); 0896 break; 0897 } 0898 0899 return tmpPosition; 0900 } 0901 0902 void TextLabelPrivate::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { 0903 q->createContextMenu()->exec(event->screenPos()); 0904 } 0905 0906 void TextLabelPrivate::hoverEnterEvent(QGraphicsSceneHoverEvent*) { 0907 if (!isSelected()) { 0908 m_hovered = true; 0909 emit q->hovered(); 0910 update(); 0911 } 0912 } 0913 0914 void TextLabelPrivate::hoverLeaveEvent(QGraphicsSceneHoverEvent*) { 0915 if (m_hovered) { 0916 m_hovered = false; 0917 emit q->unhovered(); 0918 update(); 0919 } 0920 } 0921 0922 //############################################################################## 0923 //################## Serialization/Deserialization ########################### 0924 //############################################################################## 0925 //! Save as XML 0926 void TextLabel::save(QXmlStreamWriter* writer) const { 0927 Q_D(const TextLabel); 0928 0929 writer->writeStartElement( "textLabel" ); 0930 writeBasicAttributes(writer); 0931 writeCommentElement(writer); 0932 0933 //geometry 0934 writer->writeStartElement( "geometry" ); 0935 writer->writeAttribute( "x", QString::number(d->position.point.x()) ); 0936 writer->writeAttribute( "y", QString::number(d->position.point.y()) ); 0937 writer->writeAttribute( "horizontalPosition", QString::number(static_cast<int>(d->position.horizontalPosition)) ); 0938 writer->writeAttribute( "verticalPosition", QString::number(static_cast<int>(d->position.verticalPosition)) ); 0939 writer->writeAttribute( "horizontalAlignment", QString::number(static_cast<int>(d->horizontalAlignment)) ); 0940 writer->writeAttribute( "verticalAlignment", QString::number(static_cast<int>(d->verticalAlignment)) ); 0941 writer->writeAttribute( "rotationAngle", QString::number(d->rotationAngle) ); 0942 writer->writeAttribute( "visible", QString::number(d->isVisible()) ); 0943 writer->writeEndElement(); 0944 0945 writer->writeStartElement( "text" ); 0946 writer->writeCharacters( d->textWrapper.text ); 0947 writer->writeEndElement(); 0948 0949 writer->writeStartElement( "format" ); 0950 writer->writeAttribute( "teXUsed", QString::number(d->textWrapper.teXUsed) ); 0951 WRITE_QFONT(d->teXFont); 0952 writer->writeAttribute( "fontColor_r", QString::number(d->fontColor.red()) ); 0953 writer->writeAttribute( "fontColor_g", QString::number(d->fontColor.green()) ); 0954 writer->writeAttribute( "fontColor_b", QString::number(d->fontColor.blue()) ); 0955 writer->writeEndElement(); 0956 0957 //border 0958 writer->writeStartElement("border"); 0959 writer->writeAttribute("borderShape", QString::number(static_cast<int>(d->borderShape))); 0960 WRITE_QPEN(d->borderPen); 0961 writer->writeAttribute("borderOpacity", QString::number(d->borderOpacity)); 0962 writer->writeEndElement(); 0963 0964 if (d->textWrapper.teXUsed) { 0965 writer->writeStartElement("teXImage"); 0966 QByteArray ba; 0967 QBuffer buffer(&ba); 0968 buffer.open(QIODevice::WriteOnly); 0969 d->teXImage.save(&buffer, "PNG"); 0970 writer->writeCharacters(ba.toBase64()); 0971 writer->writeEndElement(); 0972 } 0973 0974 writer->writeEndElement(); // close "textLabel" section 0975 } 0976 0977 //! Load from XML 0978 bool TextLabel::load(XmlStreamReader* reader, bool preview) { 0979 if (!readBasicAttributes(reader)) 0980 return false; 0981 0982 Q_D(TextLabel); 0983 KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used"); 0984 QXmlStreamAttributes attribs; 0985 QString str; 0986 bool teXImageFound = false; 0987 0988 while (!reader->atEnd()) { 0989 reader->readNext(); 0990 if (reader->isEndElement() && reader->name() == "textLabel") 0991 break; 0992 0993 if (!reader->isStartElement()) 0994 continue; 0995 0996 if (!preview && reader->name() == "comment") { 0997 if (!readCommentElement(reader)) return false; 0998 } else if (!preview && reader->name() == "geometry") { 0999 attribs = reader->attributes(); 1000 1001 str = attribs.value("x").toString(); 1002 if (str.isEmpty()) 1003 reader->raiseWarning(attributeWarning.subs("x").toString()); 1004 else 1005 d->position.point.setX(str.toDouble()); 1006 1007 str = attribs.value("y").toString(); 1008 if (str.isEmpty()) 1009 reader->raiseWarning(attributeWarning.subs("y").toString()); 1010 else 1011 d->position.point.setY(str.toDouble()); 1012 1013 READ_INT_VALUE("horizontalPosition", position.horizontalPosition, WorksheetElement::HorizontalPosition); 1014 READ_INT_VALUE("verticalPosition", position.verticalPosition, WorksheetElement::VerticalPosition); 1015 READ_INT_VALUE("horizontalAlignment", horizontalAlignment, WorksheetElement::HorizontalAlignment); 1016 READ_INT_VALUE("verticalAlignment", verticalAlignment, WorksheetElement::VerticalAlignment); 1017 READ_DOUBLE_VALUE("rotationAngle", rotationAngle); 1018 1019 str = attribs.value("visible").toString(); 1020 if (str.isEmpty()) 1021 reader->raiseWarning(attributeWarning.subs("visible").toString()); 1022 else 1023 d->setVisible(str.toInt()); 1024 } else if (!preview && reader->name() == "text") { 1025 d->textWrapper.text = reader->readElementText(); 1026 } else if (!preview && reader->name() == "format") { 1027 attribs = reader->attributes(); 1028 1029 READ_INT_VALUE("teXUsed", textWrapper.teXUsed, bool); 1030 READ_QFONT(d->teXFont); 1031 1032 str = attribs.value("fontColor_r").toString(); 1033 if (str.isEmpty()) 1034 reader->raiseWarning(attributeWarning.subs("fontColor_r").toString()); 1035 else 1036 d->fontColor.setRed( str.toInt() ); 1037 1038 str = attribs.value("fontColor_g").toString(); 1039 if (str.isEmpty()) 1040 reader->raiseWarning(attributeWarning.subs("fontColor_g").toString()); 1041 else 1042 d->fontColor.setGreen( str.toInt() ); 1043 1044 str = attribs.value("fontColor_b").toString(); 1045 if (str.isEmpty()) 1046 reader->raiseWarning(attributeWarning.subs("fontColor_b").toString()); 1047 else 1048 d->fontColor.setBlue( str.toInt() ); 1049 } else if (!preview && reader->name() == "border") { 1050 attribs = reader->attributes(); 1051 READ_INT_VALUE("borderShape", borderShape, BorderShape); 1052 READ_QPEN(d->borderPen); 1053 READ_DOUBLE_VALUE("borderOpacity", borderOpacity); 1054 } else if (!preview && reader->name() == "teXImage") { 1055 reader->readNext(); 1056 QString content = reader->text().toString().trimmed(); 1057 QByteArray ba = QByteArray::fromBase64(content.toLatin1()); 1058 teXImageFound = d->teXImage.loadFromData(ba); 1059 } else { // unknown element 1060 reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString())); 1061 if (!reader->skipToEndElement()) return false; 1062 } 1063 } 1064 1065 if (preview) 1066 return true; 1067 1068 //in case we use latex and the image was stored (older versions of LabPlot didn't save the image)and loaded, 1069 //we just need to retransform. 1070 //otherwise, we set the static text and retransform in updateText() 1071 if ( !(d->textWrapper.teXUsed && teXImageFound) ) 1072 d->updateText(); 1073 else 1074 retransform(); 1075 1076 return true; 1077 } 1078 1079 //############################################################################## 1080 //######################### Theme management ################################## 1081 //############################################################################## 1082 void TextLabel::loadThemeConfig(const KConfig& config) { 1083 Q_D(TextLabel); 1084 1085 KConfigGroup group = config.group("Label"); 1086 d->fontColor = group.readEntry("FontColor", QColor(Qt::black)); // used when it's latex text 1087 d->backgroundColor = group.readEntry("BackgroundColor", QColor(Qt::white)); // used when it's latex text 1088 1089 if (!d->textWrapper.teXUsed && !d->textWrapper.text.isEmpty()) { 1090 // TODO: Replace QTextEdit by QTextDocument, because this does not contain the graphical stuff 1091 // to set the color in a html text, a qTextEdit must be used 1092 QTextEdit te; 1093 te.setHtml(d->textWrapper.text); 1094 te.selectAll(); 1095 te.setTextColor(d->fontColor); 1096 //te.setTextBackgroundColor(backgroundColor); // for plain text no background color supported, due to bug https://bugreports.qt.io/browse/QTBUG-25420 1097 1098 // update the text. also in the Widget to which is connected 1099 TextWrapper wrapper(te.toHtml(), false, true); 1100 setText(wrapper); 1101 } 1102 1103 // otherwise when changing theme while the textlabel dock is visible, the 1104 // color comboboxes do not change the color 1105 backgroundColorChanged(d->backgroundColor); 1106 fontColorChanged(d->fontColor); 1107 1108 group = config.group("CartesianPlot"); 1109 QPen pen = this->borderPen(); 1110 pen.setColor(group.readEntry("BorderColor", pen.color())); 1111 pen.setStyle((Qt::PenStyle)(group.readEntry("BorderStyle", (int) pen.style()))); 1112 pen.setWidthF(group.readEntry("BorderWidth", pen.widthF())); 1113 this->setBorderPen(pen); 1114 this->setBorderOpacity(group.readEntry("BorderOpacity", this->borderOpacity())); 1115 } 1116 1117 void TextLabel::saveThemeConfig(const KConfig& config) { 1118 KConfigGroup group = config.group("Label"); 1119 //TODO 1120 // group.writeEntry("TeXFontColor", (QColor) this->fontColor()); 1121 }