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 ¤tFont() const 0245 { 0246 return m_font; 0247 } 0248 0249 /** 0250 * Access currently used font metrics. 0251 * @return current font metrics 0252 */ 0253 const QFontMetricsF ¤tFontMetrics() 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