File indexing completed on 2024-05-19 03:49:34

0001 /*
0002     File                 : TextLabel.h
0003     Project              : LabPlot
0004     Description          : Text label supporting reach text and latex formatting
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2009 Tilman Benkert <thzs@gmx.net>
0007     SPDX-FileCopyrightText: 2012-2023 Alexander Semke <alexander.semke@web.de>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #ifndef TEXTLABEL_H
0012 #define TEXTLABEL_H
0013 
0014 #include "backend/lib/macros.h"
0015 #include "backend/worksheet/WorksheetElement.h"
0016 #include "tools/TeXRenderer.h"
0017 
0018 #include <QTextEdit>
0019 
0020 class QBrush;
0021 class QFont;
0022 class TextLabelPrivate;
0023 class CartesianPlot;
0024 class QPen;
0025 
0026 class TextLabel : public WorksheetElement {
0027     Q_OBJECT
0028 
0029 public:
0030     enum class Type { General, PlotTitle, AxisTitle, PlotLegendTitle, InfoElementLabel };
0031     enum class Mode { Text, LaTeX, Markdown };
0032     enum class BorderShape {
0033         NoBorder,
0034         Rect,
0035         Ellipse,
0036         RoundSideRect,
0037         RoundCornerRect,
0038         InwardsRoundCornerRect,
0039         DentedBorderRect,
0040         Cuboid,
0041         UpPointingRectangle,
0042         DownPointingRectangle,
0043         LeftPointingRectangle,
0044         RightPointingRectangle
0045     };
0046 
0047     // The text is always in HMTL format
0048     struct TextWrapper {
0049         TextWrapper() = default;
0050         TextWrapper(const QString& text, TextLabel::Mode mode, bool html)
0051             : mode(mode) {
0052             if (mode == TextLabel::Mode::Text)
0053                 this->text = createHtml(text, html);
0054             else // LaTeX and markdown use plain string
0055                 this->text = text;
0056         }
0057         TextWrapper(const QString& text)
0058             : mode(TextLabel::Mode::Text) {
0059             // assume text is not HTML yet
0060             this->text = createHtml(text, false);
0061         }
0062         TextWrapper(const QString& text, bool html, QString& placeholder)
0063             : allowPlaceholder(true)
0064             , textPlaceholder(placeholder) {
0065             this->text = createHtml(text, html);
0066         }
0067         TextWrapper(const QString& text, TextLabel::Mode mode, bool html, bool allowPlaceholder)
0068             : allowPlaceholder(allowPlaceholder) {
0069             TextWrapper(text, mode, html);
0070         }
0071         QString createHtml(QString text, bool isHtml) {
0072             if (isHtml || text.isEmpty())
0073                 return text;
0074 
0075             QTextEdit te(text);
0076             // the html does not contain any colors!
0077             return te.toHtml();
0078         }
0079 
0080         bool isHtml() const {
0081             return text.startsWith(QStringLiteral("<!DOCTYPE HTML"));
0082         }
0083 
0084         bool operator!=(const TextWrapper& other) const {
0085             return (text != other.text || mode != other.mode || allowPlaceholder != other.allowPlaceholder
0086                     || ((allowPlaceholder || other.allowPlaceholder) && textPlaceholder != other.textPlaceholder));
0087         }
0088 
0089         bool operator==(TextWrapper& other) const {
0090             return (text == other.text && mode == other.mode && allowPlaceholder == other.allowPlaceholder
0091                     && ((allowPlaceholder || other.allowPlaceholder) && textPlaceholder == other.textPlaceholder));
0092         }
0093 
0094         QString text;
0095         TextLabel::Mode mode{TextLabel::Mode::Text};
0096         /*! Determines if the Textlabel can have a placeholder or not.
0097          * Depending on this variable in the LabelWidget between
0098          * the text and the placeholder text can be switched
0099          */
0100         bool allowPlaceholder{false};
0101         QString textPlaceholder{QLatin1String("")}; // text with placeholders
0102     };
0103 
0104     explicit TextLabel(const QString& name, Type = Type::General);
0105     TextLabel(const QString& name, CartesianPlot*, Type = Type::General);
0106     ~TextLabel() override;
0107 
0108     Type type() const;
0109     QIcon icon() const override;
0110 
0111     void save(QXmlStreamWriter*) const override;
0112     bool load(XmlStreamReader*, bool preview) override;
0113     void loadThemeConfig(const KConfig&) override;
0114     void saveThemeConfig(const KConfig&) override;
0115 
0116     CLASS_D_ACCESSOR_DECL(TextWrapper, text, Text)
0117     BASIC_D_ACCESSOR_DECL(QColor, fontColor, FontColor)
0118     BASIC_D_ACCESSOR_DECL(QColor, backgroundColor, BackgroundColor)
0119     CLASS_D_ACCESSOR_DECL(TextWrapper, textPlaceholder, PlaceholderText)
0120     BASIC_D_ACCESSOR_DECL(QColor, teXFontColor, TeXFontColor)
0121     BASIC_D_ACCESSOR_DECL(QColor, teXBackgroundColor, TeXBackgroundColor)
0122     CLASS_D_ACCESSOR_DECL(QFont, teXFont, TeXFont)
0123 
0124     BASIC_D_ACCESSOR_DECL(BorderShape, borderShape, BorderShape)
0125     CLASS_D_ACCESSOR_DECL(QPen, borderPen, BorderPen)
0126     BASIC_D_ACCESSOR_DECL(qreal, borderOpacity, BorderOpacity)
0127 
0128     void setZoomFactor(double);
0129     QRectF size();
0130     QPointF findNearestGluePoint(QPointF scenePoint);
0131     int gluePointCount();
0132     struct GluePoint {
0133 #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0)) // we need a default constructor for QVector
0134         GluePoint() = default;
0135 #endif
0136         GluePoint(QPointF point, QString name)
0137             : point(point)
0138             , name(name) {
0139         }
0140         QPointF point;
0141         QString name;
0142     };
0143 
0144     GluePoint gluePointAt(int index);
0145 
0146     void retransform() override;
0147     void handleResize(double horizontalRatio, double verticalRatio, bool pageResize) override;
0148 
0149     typedef TextLabelPrivate Private;
0150 
0151 private Q_SLOTS:
0152     void updateTeXImage();
0153 
0154 protected:
0155     TextLabel(const QString& name, TextLabelPrivate*, Type = Type::General);
0156 
0157 private:
0158     Q_DECLARE_PRIVATE(TextLabel)
0159     void init();
0160 
0161     Type m_type;
0162 
0163 Q_SIGNALS:
0164     void textWrapperChanged(const TextLabel::TextWrapper&);
0165     void teXFontSizeChanged(const int);
0166     void teXFontChanged(const QFont);
0167     void fontColorChanged(const QColor);
0168     void backgroundColorChanged(const QColor);
0169 
0170     void borderShapeChanged(TextLabel::BorderShape);
0171     void borderPenChanged(QPen&);
0172     void borderOpacityChanged(float);
0173 
0174     void teXImageUpdated(const TeXRenderer::Result&);
0175 };
0176 
0177 #endif