/* This file is part of the KDE libraries SPDX-FileCopyrightText: 2007 Mirko Stocker SPDX-FileCopyrightText: 2003-2005 Hamish Rodda SPDX-FileCopyrightText: 2001 Christoph Cullmann SPDX-FileCopyrightText: 2001 Joseph Wenninger SPDX-FileCopyrightText: 1999 Jochen Wilhelmy SPDX-License-Identifier: LGPL-2.0-only */ #ifndef KATE_RENDERER_H #define KATE_RENDERER_H #include "kateconfig.h" #include "ktexteditor/range.h" #include #include #include #include namespace KTextEditor { class DocumentPrivate; class ViewPrivate; class Attribute; } class KateRendererConfig; namespace Kate { class TextFolding; class TextLine; } class KateTextLayout; class KateLineLayout; typedef QExplicitlySharedDataPointer AttributePtr; namespace KTextEditor { enum class caretStyles { Line, Block, Underline, Half, }; } /** * Handles all of the work of rendering the text * (used for the views and printing) * **/ class KateRenderer { public: /** * Style of Caret * * The caret is displayed as a vertical bar (Line), a filled box * (Block), a horizontal bar (Underline), or a half-height filled * box (Half). The default is Line. * * Line Block Underline Half * * ## _ ######### _ _ * ## __| | #####| |# __| | __| | * ## / _' | ##/ _' |# / _' | / _' | * ##| (_| | #| (#| |# | (_| | #| (#| |# * ## \__,_| ##\__,_|# \__,_| ##\__,_|# * ## ######### ######### ######### */ /** * Constructor * @param doc document to render * @param folding folding information * @param view view which is output (0 for example for rendering to print) */ explicit KateRenderer(KTextEditor::DocumentPrivate *doc, Kate::TextFolding &folding, KTextEditor::ViewPrivate *view = nullptr); KateRenderer(const KateRenderer &) = delete; KateRenderer &operator=(const KateRenderer &) = delete; /** * Returns the document to which this renderer is bound */ KTextEditor::DocumentPrivate *doc() const { return m_doc; } /** * Returns the folding info to which this renderer is bound * @return folding info */ Kate::TextFolding &folding() const { return m_folding; } /** * Returns the view to which this renderer is bound */ KTextEditor::ViewPrivate *view() const { return m_view; } /** * update the highlighting attributes * (for example after an hl change or after hl config changed) */ void updateAttributes(); /** * Determine whether the caret (text cursor) will be drawn. * @return should it be drawn? */ inline bool drawCaret() const { return m_drawCaret; } /** * Set whether the caret (text cursor) will be drawn. * @param drawCaret should caret be drawn? */ void setDrawCaret(bool drawCaret); /** * The style of the caret (text cursor) to be painted. * @return caretStyle */ inline KTextEditor::caretStyles caretStyle() const { return m_caretStyle; } /** * Set the style of caret to be painted. * @param style style to set */ void setCaretStyle(KTextEditor::caretStyles style); /** * Set a \a brush with which to override drawing of the caret. Set to QColor() to clear. */ void setCaretOverrideColor(const QColor &color); /** * @returns whether tabs should be shown (ie. a small mark * drawn to identify a tab) * @return tabs should be shown */ inline bool showTabs() const { return m_showTabs; } /** * Set whether a mark should be painted to help identifying tabs. * @param showTabs show the tabs? */ void setShowTabs(bool showTabs); /** * Set which spaces should be rendered */ void setShowSpaces(KateDocumentConfig::WhitespaceRendering showSpaces); /** * @returns whether which spaces should be rendered */ inline KateDocumentConfig::WhitespaceRendering showSpaces() const { return m_showSpaces; } /** * Update marker size shown. */ void updateMarkerSize(); /** * @returns whether non-printable spaces should be shown */ inline bool showNonPrintableSpaces() const { return m_showNonPrintableSpaces; } /** * Set whether box should be drawn around non-printable spaces */ void setShowNonPrintableSpaces(const bool showNonPrintableSpaces); /** * Sets the width of the tab. Helps performance. * @param tabWidth new tab width */ void setTabWidth(int tabWidth); /** * @returns whether indent lines should be shown * @return indent lines should be shown */ bool showIndentLines() const; /** * Set whether a guide should be painted to help identifying indent lines. * @param showLines show the indent lines? */ void setShowIndentLines(bool showLines); /** * Sets the width of the tab. Helps performance. * @param indentWidth new indent width */ void setIndentWidth(int indentWidth); /** * Show the view's selection? * @return show sels? */ inline bool showSelections() const { return m_showSelections; } /** * Set whether the view's selections should be shown. * The default is true. * @param showSelections show the selections? */ void setShowSelections(bool showSelections); /** * Change to a different font (soon to be font set?) */ void increaseFontSizes(qreal step = 1.0) const; void decreaseFontSizes(qreal step = 1.0) const; void resetFontSizes() const; /** * Access currently used font. * @return current font */ const QFont ¤tFont() const { return m_font; } /** * Access currently used font metrics. * @return current font metrics */ const QFontMetricsF ¤tFontMetrics() const { return m_fontMetrics; } /** * @return whether the renderer is configured to paint in a * printer-friendly fashion. */ bool isPrinterFriendly() const; /** * Configure this renderer to paint in a printer-friendly fashion. * * Sets the other options appropriately if true. */ void setPrinterFriendly(bool printerFriendly); /** * Text width & height calculation functions... */ void layoutLine(KateLineLayout *line, int maxwidth = -1, bool cacheLayout = false) const; /** * This is a smaller QString::isRightToLeft(). It's also marked as internal to kate * instead of internal to Qt, so we can modify. This method searches for the first * strong character in the paragraph and then returns its direction. In case of a * line without any strong characters, the direction is forced to be LTR. * * Back in KDE 4.1 this method counted chars, which lead to unwanted side effects. * (see https://bugs.kde.org/show_bug.cgi?id=178594). As this function is internal * the way it work will probably change between releases. Be warned! */ static bool isLineRightToLeft(QStringView str); /** * The ultimate decoration creation function. * * \param selectionsOnly return decorations for selections and/or dynamic highlighting. */ QList decorationsForLine(const Kate::TextLine &textLine, int line, bool selectionsOnly = false) const; // Width calculators qreal spaceWidth() const; /** * Returns the x position of cursor \p col on the line \p range. */ int cursorToX(const KateTextLayout &range, int col, bool returnPastLine = false) const; /// \overload int cursorToX(const KateTextLayout &range, const KTextEditor::Cursor pos, bool returnPastLine = false) const; /** * Returns the real cursor which is occupied by the specified x value, or that closest to it. * If \p returnPastLine is true, the column will be extrapolated out with the assumption * that the extra characters are spaces. */ KTextEditor::Cursor xToCursor(const KateTextLayout &range, int x, bool returnPastLine = false) const; // Font height uint fontHeight() const; // Line height int lineHeight() const; // Document height uint documentHeight() const; // Selection boundaries bool getSelectionBounds(int line, int lineLength, int &start, int &end) const; /** * Flags to customize the paintTextLine function behavior */ enum PaintTextLineFlag { /** * Skip drawing the dashed underline at the start of a folded block of text? */ SkipDrawFirstInvisibleLineUnderlined = 0x1, /** * Skip drawing the line selection * This is useful when we are drawing the draggable pixmap for drag event */ SkipDrawLineSelection = 0x2 }; Q_DECLARE_FLAGS(PaintTextLineFlags, PaintTextLineFlag) /** * This is the ultimate function to perform painting of a text line. * * The text line is painted from the upper limit of (0,0). To move that, * apply a transform to your painter. * * @param paint painter to use * @param range layout to use in painting this line * @param textClipRect clip rect for text to not paint lines outside the visible area. * @param xStart starting width in pixels. * @param xEnd ending width in pixels. * @param cursor position of the caret, if placed on the current line. * @param flags flags for customizing the drawing of the line */ void paintTextLine(QPainter &paint, KateLineLayout *range, int xStart, int xEnd, const QRectF &textClipRect = QRectF(), const KTextEditor::Cursor *cursor = nullptr, PaintTextLineFlags flags = PaintTextLineFlags()); /** * Paint the background of a line * * Split off from the main @ref paintTextLine method to make it smaller. As it's being * called only once per line it shouldn't noticably affect performance and it * helps readability a LOT. * * @param paint painter to use * @param layout layout to use in painting this line * @param currentViewLine if one of the view lines is the current line, set * this to the index; otherwise -1. * @param xStart starting width in pixels. * @param xEnd ending width in pixels. */ void paintTextLineBackground(QPainter &paint, KateLineLayout *layout, int currentViewLine, int xStart, int xEnd); void paintTextBackground(QPainter &paint, KateLineLayout *layout, const QList &selRanges, const QBrush &br, int xStart) const; /** * This takes an in index, and returns all the attributes for it. * For example, if you have a ktextline, and want the KTextEditor::Attribute * for a given position, do: * * attribute(myktextline->attribute(position)); */ const AttributePtr &attribute(uint pos) const; AttributePtr specificAttribute(int context) const; /** * Paints a range of text into @a d. This function is mainly used to paint the pixmap * when dragging text. * * Please note that this will not paint the selection background but only the text. * * @param d the paint device * @param startLine start line * @param xStart start pos on @a startLine in pixels * @param endLine end line * @param xEnd end pos on @a endLine in pixels * @param scale the amount of scaling to apply. Default is 1.0, negative values are not supported */ void paintSelection(QPaintDevice *d, int startLine, int xStart, int endLine, int xEnd, int viewWidth, qreal scale = 1.0); private: /** * Paint a trailing space on position (x, y). */ void paintSpaces(QPainter &paint, const QPointF *points, const int count) const; /** * Paint a tab stop marker on position (x, y). */ void paintTabstop(QPainter &paint, qreal x, qreal y) const; /** * Paint a non-breaking space marker on position (x, y). */ void paintNonBreakSpace(QPainter &paint, qreal x, qreal y) const; /** * Paint non printable spaces bounding box */ void paintNonPrintableSpaces(QPainter &paint, qreal x, qreal y, const QChar &chr); /** Paint a SciTE-like indent marker. */ void paintIndentMarker(QPainter &paint, uint x, int line); static void assignSelectionBrushesFromAttribute(QTextLayout::FormatRange &target, const KTextEditor::Attribute &attribute); void paintCaret(KTextEditor::Cursor cursor, KateLineLayout *range, QPainter &paint, int xStart, int xEnd); // update font height void updateFontHeight(); bool hasCustomLineHeight() const; KTextEditor::DocumentPrivate *const m_doc; Kate::TextFolding &m_folding; KTextEditor::ViewPrivate *const m_view; // cache of config values int m_tabWidth; int m_indentWidth; int m_fontHeight; float m_fontAscent; // if we are at bracket, this will have the X for the opener int m_currentBracketX = -1; // The bracket range, if we are at a bracket KTextEditor::Range m_currentBracketRange = KTextEditor::Range::invalid(); // some internal flags KTextEditor::caretStyles m_caretStyle; bool m_drawCaret; bool m_showSelections; bool m_showTabs; KateDocumentConfig::WhitespaceRendering m_showSpaces = KateDocumentConfig::None; float m_markerSize; bool m_showNonPrintableSpaces; bool m_printerFriendly; QColor m_caretOverrideColor; QList m_attributes; /** * Configuration */ public: void updateConfig(); inline KateRendererConfig *config() const { return m_config.get(); } private: std::unique_ptr const m_config; /** * cached font, was perhaps adjusted for current DPIs */ QFont m_font; /** * cached font metrics */ QFontMetricsF m_fontMetrics; }; #endif