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