File indexing completed on 2024-04-28 15:30:36

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2007 Mirko Stocker <me@misto.ch>
0004     SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org>
0005     SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
0006     SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
0007     SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
0008 
0009     SPDX-License-Identifier: LGPL-2.0-only
0010 */
0011 
0012 #ifndef KATE_RENDERER_H
0013 #define KATE_RENDERER_H
0014 
0015 #include "kateconfig.h"
0016 #include <ktexteditor/attribute.h>
0017 
0018 #include <QFlags>
0019 #include <QFont>
0020 #include <QFontMetricsF>
0021 #include <QTextLine>
0022 
0023 namespace KTextEditor
0024 {
0025 class DocumentPrivate;
0026 }
0027 namespace KTextEditor
0028 {
0029 class ViewPrivate;
0030 }
0031 class KateRendererConfig;
0032 namespace Kate
0033 {
0034 class TextFolding;
0035 class TextLineData;
0036 typedef std::shared_ptr<TextLineData> TextLine;
0037 }
0038 
0039 class KateTextLayout;
0040 class KateLineLayout;
0041 typedef QExplicitlySharedDataPointer<KateLineLayout> KateLineLayoutPtr;
0042 
0043 /**
0044  * Handles all of the work of rendering the text
0045  * (used for the views and printing)
0046  *
0047  **/
0048 class KateRenderer
0049 {
0050 public:
0051     /**
0052      * Style of Caret
0053      *
0054      * The caret is displayed as a vertical bar (Line), a filled box
0055      * (Block), a horizontal bar (Underline), or a half-height filled
0056      * box (Half). The default is Line.
0057      *
0058      *     Line           Block          Underline           Half
0059      *
0060      * ##     _         #########              _                _
0061      * ##  __| |        #####| |#           __| |            __| |
0062      * ## / _' |        ##/ _' |#          / _' |           / _' |
0063      * ##| (_| |        #| (#| |#         | (_| |         #| (#| |#
0064      * ## \__,_|        ##\__,_|#          \__,_|         ##\__,_|#
0065      * ##               #########        #########        #########
0066      */
0067     enum caretStyles { Line, Block, Underline, Half };
0068 
0069     /**
0070      * Constructor
0071      * @param doc document to render
0072      * @param folding folding information
0073      * @param view view which is output (0 for example for rendering to print)
0074      */
0075     explicit KateRenderer(KTextEditor::DocumentPrivate *doc, Kate::TextFolding &folding, KTextEditor::ViewPrivate *view = nullptr);
0076 
0077     KateRenderer(const KateRenderer &) = delete;
0078     KateRenderer &operator=(const KateRenderer &) = delete;
0079 
0080     /**
0081      * Returns the document to which this renderer is bound
0082      */
0083     KTextEditor::DocumentPrivate *doc() const
0084     {
0085         return m_doc;
0086     }
0087 
0088     /**
0089      * Returns the folding info to which this renderer is bound
0090      * @return folding info
0091      */
0092     Kate::TextFolding &folding() const
0093     {
0094         return m_folding;
0095     }
0096 
0097     /**
0098      * Returns the view to which this renderer is bound
0099      */
0100     KTextEditor::ViewPrivate *view() const
0101     {
0102         return m_view;
0103     }
0104 
0105     /**
0106      * update the highlighting attributes
0107      * (for example after an hl change or after hl config changed)
0108      */
0109     void updateAttributes();
0110 
0111     /**
0112      * Determine whether the caret (text cursor) will be drawn.
0113      * @return should it be drawn?
0114      */
0115     inline bool drawCaret() const
0116     {
0117         return m_drawCaret;
0118     }
0119 
0120     /**
0121      * Set whether the caret (text cursor) will be drawn.
0122      * @param drawCaret should caret be drawn?
0123      */
0124     void setDrawCaret(bool drawCaret);
0125 
0126     /**
0127      * The style of the caret (text cursor) to be painted.
0128      * @return caretStyle
0129      */
0130     inline KateRenderer::caretStyles caretStyle() const
0131     {
0132         return m_caretStyle;
0133     }
0134 
0135     /**
0136      * Set the style of caret to be painted.
0137      * @param style style to set
0138      */
0139     void setCaretStyle(KateRenderer::caretStyles style);
0140 
0141     /**
0142      * Set a \a brush with which to override drawing of the caret.  Set to QColor() to clear.
0143      */
0144     void setCaretOverrideColor(const QColor &color);
0145 
0146     /**
0147      * @returns whether tabs should be shown (ie. a small mark
0148      * drawn to identify a tab)
0149      * @return tabs should be shown
0150      */
0151     inline bool showTabs() const
0152     {
0153         return m_showTabs;
0154     }
0155 
0156     /**
0157      * Set whether a mark should be painted to help identifying tabs.
0158      * @param showTabs show the tabs?
0159      */
0160     void setShowTabs(bool showTabs);
0161 
0162     /**
0163      * Set which spaces should be rendered
0164      */
0165     void setShowSpaces(KateDocumentConfig::WhitespaceRendering showSpaces);
0166 
0167     /**
0168      * @returns whether which spaces should be rendered
0169      */
0170     inline KateDocumentConfig::WhitespaceRendering showSpaces() const
0171     {
0172         return m_showSpaces;
0173     }
0174 
0175     /**
0176      * Update marker size shown.
0177      */
0178     void updateMarkerSize();
0179 
0180     /**
0181      * @returns whether non-printable spaces should be shown
0182      */
0183     inline bool showNonPrintableSpaces() const
0184     {
0185         return m_showNonPrintableSpaces;
0186     }
0187 
0188     /**
0189      * Set whether box should be drawn around non-printable spaces
0190      */
0191     void setShowNonPrintableSpaces(const bool showNonPrintableSpaces);
0192 
0193     /**
0194      * Sets the width of the tab. Helps performance.
0195      * @param tabWidth new tab width
0196      */
0197     void setTabWidth(int tabWidth);
0198 
0199     /**
0200      * @returns whether indent lines should be shown
0201      * @return indent lines should be shown
0202      */
0203     bool showIndentLines() const;
0204 
0205     /**
0206      * Set whether a guide should be painted to help identifying indent lines.
0207      * @param showLines show the indent lines?
0208      */
0209     void setShowIndentLines(bool showLines);
0210 
0211     /**
0212      * Sets the width of the tab. Helps performance.
0213      * @param indentWidth new indent width
0214      */
0215     void setIndentWidth(int indentWidth);
0216 
0217     /**
0218      * Show the view's selection?
0219      * @return show sels?
0220      */
0221     inline bool showSelections() const
0222     {
0223         return m_showSelections;
0224     }
0225 
0226     /**
0227      * Set whether the view's selections should be shown.
0228      * The default is true.
0229      * @param showSelections show the selections?
0230      */
0231     void setShowSelections(bool showSelections);
0232 
0233     /**
0234      * Change to a different font (soon to be font set?)
0235      */
0236     void increaseFontSizes(qreal step = 1.0) const;
0237     void decreaseFontSizes(qreal step = 1.0) const;
0238     void resetFontSizes() const;
0239 
0240     /**
0241      * Access currently used font.
0242      * @return current font
0243      */
0244     const QFont &currentFont() const
0245     {
0246         return m_font;
0247     }
0248 
0249     /**
0250      * Access currently used font metrics.
0251      * @return current font metrics
0252      */
0253     const QFontMetricsF &currentFontMetrics() const
0254     {
0255         return m_fontMetrics;
0256     }
0257 
0258     /**
0259      * @return whether the renderer is configured to paint in a
0260      * printer-friendly fashion.
0261      */
0262     bool isPrinterFriendly() const;
0263 
0264     /**
0265      * Configure this renderer to paint in a printer-friendly fashion.
0266      *
0267      * Sets the other options appropriately if true.
0268      */
0269     void setPrinterFriendly(bool printerFriendly);
0270 
0271     /**
0272      * Text width & height calculation functions...
0273      */
0274     void layoutLine(KateLineLayoutPtr line, int maxwidth = -1, bool cacheLayout = false) const;
0275 
0276     /**
0277      * This is a smaller QString::isRightToLeft(). It's also marked as internal to kate
0278      * instead of internal to Qt, so we can modify. This method searches for the first
0279      * strong character in the paragraph and then returns its direction. In case of a
0280      * line without any strong characters, the direction is forced to be LTR.
0281      *
0282      * Back in KDE 4.1 this method counted chars, which lead to unwanted side effects.
0283      * (see https://bugs.kde.org/show_bug.cgi?id=178594). As this function is internal
0284      * the way it work will probably change between releases. Be warned!
0285      */
0286     static bool isLineRightToLeft(KateLineLayoutPtr lineLayout);
0287 
0288     /**
0289      * The ultimate decoration creation function.
0290      *
0291      * \param selectionsOnly return decorations for selections and/or dynamic highlighting.
0292      */
0293     QVector<QTextLayout::FormatRange> decorationsForLine(const Kate::TextLine &textLine, int line, bool selectionsOnly = false) const;
0294 
0295     // Width calculators
0296     qreal spaceWidth() const;
0297 
0298     /**
0299      * Returns the x position of cursor \p col on the line \p range.
0300      */
0301     int cursorToX(const KateTextLayout &range, int col, bool returnPastLine = false) const;
0302     /// \overload
0303     int cursorToX(const KateTextLayout &range, const KTextEditor::Cursor pos, bool returnPastLine = false) const;
0304 
0305     /**
0306      * Returns the real cursor which is occupied by the specified x value, or that closest to it.
0307      * If \p returnPastLine is true, the column will be extrapolated out with the assumption
0308      * that the extra characters are spaces.
0309      */
0310     KTextEditor::Cursor xToCursor(const KateTextLayout &range, int x, bool returnPastLine = false) const;
0311 
0312     // Font height
0313     uint fontHeight() const;
0314 
0315     // Line height
0316     int lineHeight() const;
0317 
0318     // Document height
0319     uint documentHeight() const;
0320 
0321     // Selection boundaries
0322     bool getSelectionBounds(int line, int lineLength, int &start, int &end) const;
0323 
0324     /**
0325      * Flags to customize the paintTextLine function behavior
0326      */
0327     enum PaintTextLineFlag {
0328         /**
0329          * Skip drawing the dashed underline at the start of a folded block of text?
0330          */
0331         SkipDrawFirstInvisibleLineUnderlined = 0x1,
0332         /**
0333          * Skip drawing the line selection
0334          * This is useful when we are drawing the draggable pixmap for drag event
0335          */
0336         SkipDrawLineSelection = 0x2
0337     };
0338     Q_DECLARE_FLAGS(PaintTextLineFlags, PaintTextLineFlag)
0339 
0340     /**
0341      * This is the ultimate function to perform painting of a text line.
0342      *
0343      * The text line is painted from the upper limit of (0,0).  To move that,
0344      * apply a transform to your painter.
0345      *
0346      * @param paint           painter to use
0347      * @param range           layout to use in painting this line
0348      * @param xStart          starting width in pixels.
0349      * @param xEnd            ending width in pixels.
0350      * @param cursor          position of the caret, if placed on the current line.
0351      * @param flags           flags for customizing the drawing of the line
0352      */
0353     void paintTextLine(QPainter &paint,
0354                        KateLineLayoutPtr range,
0355                        int xStart,
0356                        int xEnd,
0357                        const KTextEditor::Cursor *cursor = nullptr,
0358                        PaintTextLineFlags flags = PaintTextLineFlags());
0359 
0360     /**
0361      * Paint the background of a line
0362      *
0363      * Split off from the main @ref paintTextLine method to make it smaller. As it's being
0364      * called only once per line it shouldn't noticably affect performance and it
0365      * helps readability a LOT.
0366      *
0367      * @param paint           painter to use
0368      * @param layout          layout to use in painting this line
0369      * @param currentViewLine if one of the view lines is the current line, set
0370      *                        this to the index; otherwise -1.
0371      * @param xStart          starting width in pixels.
0372      * @param xEnd            ending width in pixels.
0373      */
0374     void paintTextLineBackground(QPainter &paint, KateLineLayoutPtr layout, int currentViewLine, int xStart, int xEnd);
0375 
0376     void paintTextBackground(QPainter &paint, KateLineLayoutPtr layout, const QVector<QTextLayout::FormatRange> &selRanges, const QBrush &br) const;
0377 
0378     /**
0379      * This takes an in index, and returns all the attributes for it.
0380      * For example, if you have a ktextline, and want the KTextEditor::Attribute
0381      * for a given position, do:
0382      *
0383      *   attribute(myktextline->attribute(position));
0384      */
0385     KTextEditor::Attribute::Ptr attribute(uint pos) const;
0386     KTextEditor::Attribute::Ptr specificAttribute(int context) const;
0387 
0388     /**
0389      * Paints a range of text into @a d. This function is mainly used to paint the pixmap
0390      * when dragging text.
0391      *
0392      * Please note that this will not paint the selection background but only the text.
0393      *
0394      * @param d                 the paint device
0395      * @param startLine         start line
0396      * @param xStart            start pos on @a startLine in pixels
0397      * @param endLine           end line
0398      * @param xEnd              end pos on @a endLine in pixels
0399      * @param scale             the amount of scaling to apply. Default is 1.0, negative values are not supported
0400      */
0401     void paintSelection(QPaintDevice *d, int startLine, int xStart, int endLine, int xEnd, qreal scale = 1.0);
0402 
0403 private:
0404     /**
0405      * Paint a trailing space on position (x, y).
0406      */
0407     void paintSpaces(QPainter &paint, const QPointF *points, const int count) const;
0408     /**
0409      * Paint a tab stop marker on position (x, y).
0410      */
0411     void paintTabstop(QPainter &paint, qreal x, qreal y) const;
0412 
0413     /**
0414      * Paint a non-breaking space marker on position (x, y).
0415      */
0416     void paintNonBreakSpace(QPainter &paint, qreal x, qreal y) const;
0417 
0418     /**
0419      * Paint non printable spaces bounding box
0420      */
0421     void paintNonPrintableSpaces(QPainter &paint, qreal x, qreal y, const QChar &chr);
0422 
0423     /** Paint a SciTE-like indent marker. */
0424     void paintIndentMarker(QPainter &paint, uint x, int line);
0425 
0426     static void assignSelectionBrushesFromAttribute(QTextLayout::FormatRange &target, const KTextEditor::Attribute &attribute);
0427 
0428     void paintCaret(const KTextEditor::Cursor &cursor, const KateLineLayoutPtr &range, QPainter &paint, int xStart, int xEnd);
0429 
0430     // update font height
0431     void updateFontHeight();
0432 
0433     bool hasCustomLineHeight() const;
0434 
0435     KTextEditor::DocumentPrivate *const m_doc;
0436     Kate::TextFolding &m_folding;
0437     KTextEditor::ViewPrivate *const m_view;
0438 
0439     // cache of config values
0440     int m_tabWidth;
0441     int m_indentWidth;
0442     int m_fontHeight;
0443     float m_fontAscent;
0444 
0445     // if we are at bracket, this will have the X for the opener
0446     int m_currentOpenBracketX = -1;
0447     // if we are at bracket, this will have the X for the closer
0448     int m_currentCloseBracketX = -1;
0449     // The bracket range, if we are at a bracket
0450     KTextEditor::Range m_currentBracketRange = KTextEditor::Range::invalid();
0451 
0452     // some internal flags
0453     KateRenderer::caretStyles m_caretStyle;
0454     bool m_drawCaret;
0455     bool m_showSelections;
0456     bool m_showTabs;
0457     KateDocumentConfig::WhitespaceRendering m_showSpaces = KateDocumentConfig::None;
0458     float m_markerSize;
0459     bool m_showNonPrintableSpaces;
0460     bool m_printerFriendly;
0461     QColor m_caretOverrideColor;
0462 
0463     QVector<KTextEditor::Attribute::Ptr> m_attributes;
0464 
0465     /**
0466      * Configuration
0467      */
0468 public:
0469     inline KateRendererConfig *config() const
0470     {
0471         return m_config.get();
0472     }
0473 
0474     void updateConfig();
0475 
0476 private:
0477     std::unique_ptr<KateRendererConfig> const m_config;
0478 
0479     /**
0480      * cached font, was perhaps adjusted for current DPIs
0481      */
0482     QFont m_font;
0483 
0484     /**
0485      * cached font metrics
0486      */
0487     QFontMetricsF m_fontMetrics;
0488 };
0489 
0490 #endif