PageRenderTime 62ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/textarea/TextAreaPainter.java

#
Java | 1500 lines | 847 code | 165 blank | 488 comment | 122 complexity | 9d554921d9af61646586fcfa8155141c MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * TextAreaPainter.java - Paints the text area
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2005 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.textarea;
  23. //{{{ Imports
  24. import javax.swing.text.*;
  25. import javax.swing.JComponent;
  26. import java.awt.event.MouseEvent;
  27. import java.awt.font.*;
  28. import java.awt.*;
  29. import java.util.*;
  30. import org.gjt.sp.jedit.buffer.IndentFoldHandler;
  31. import org.gjt.sp.jedit.buffer.JEditBuffer;
  32. import org.gjt.sp.jedit.syntax.Chunk;
  33. import org.gjt.sp.jedit.syntax.DefaultTokenHandler;
  34. import org.gjt.sp.jedit.syntax.SyntaxStyle;
  35. import org.gjt.sp.jedit.syntax.Token;
  36. import org.gjt.sp.jedit.Debug;
  37. import org.gjt.sp.util.Log;
  38. //}}}
  39. /**
  40. * The text area painter is the component responsible for displaying the
  41. * text of the current buffer. The only methods in this class that should
  42. * be called by plugins are those for adding and removing
  43. * text area extensions.
  44. *
  45. * @see #addExtension(TextAreaExtension)
  46. * @see #addExtension(int,TextAreaExtension)
  47. * @see #removeExtension(TextAreaExtension)
  48. * @see TextAreaExtension
  49. * @see TextArea
  50. *
  51. * @author Slava Pestov
  52. * @version $Id: TextAreaPainter.java 20109 2011-10-18 12:25:29Z evanpw $
  53. */
  54. public class TextAreaPainter extends JComponent implements TabExpander
  55. {
  56. //{{{ Layers
  57. /**
  58. * The lowest possible layer.
  59. * @see #addExtension(int,TextAreaExtension)
  60. * @since jEdit 4.0pre4
  61. */
  62. public static final int LOWEST_LAYER = Integer.MIN_VALUE;
  63. /**
  64. * Below selection layer. The JDiff plugin will use this.
  65. * @see #addExtension(int,TextAreaExtension)
  66. * @since jEdit 4.0pre4
  67. */
  68. public static final int BACKGROUND_LAYER = -60;
  69. /**
  70. * The line highlight and collapsed fold highlight layer.
  71. * @see #addExtension(int,TextAreaExtension)
  72. * @since jEdit 4.0pre7
  73. */
  74. public static final int LINE_BACKGROUND_LAYER = -50;
  75. /**
  76. * Below selection layer.
  77. * @see #addExtension(int,TextAreaExtension)
  78. * @since jEdit 4.0pre4
  79. */
  80. public static final int BELOW_SELECTION_LAYER = -40;
  81. /**
  82. * Selection layer. Most extensions will be above this layer, but some
  83. * (eg, JDiff) will want to be below the selection.
  84. * @see #addExtension(int,TextAreaExtension)
  85. * @since jEdit 4.0pre4
  86. */
  87. public static final int SELECTION_LAYER = -30;
  88. /**
  89. * Wrap guide layer. Most extensions will be above this layer.
  90. * @since jEdit 4.0pre4
  91. */
  92. public static final int WRAP_GUIDE_LAYER = -20;
  93. /**
  94. * Below most extensions layer.
  95. * @see #addExtension(int,TextAreaExtension)
  96. * @since jEdit 4.0pre4
  97. */
  98. public static final int BELOW_MOST_EXTENSIONS_LAYER = -10;
  99. /**
  100. * Default extension layer. This is above the wrap guide but below the
  101. * structure highlight.
  102. * @since jEdit 4.0pre4
  103. */
  104. public static final int DEFAULT_LAYER = 0;
  105. /**
  106. * Block caret layer. Most extensions will be below this layer.
  107. * @since jEdit 4.2pre1
  108. */
  109. public static final int BLOCK_CARET_LAYER = 50;
  110. /**
  111. * Bracket highlight layer. Most extensions will be below this layer.
  112. * @since jEdit 4.0pre4
  113. */
  114. public static final int BRACKET_HIGHLIGHT_LAYER = 100;
  115. /**
  116. * Text layer. Most extensions will be below this layer.
  117. * @since jEdit 4.2pre1
  118. */
  119. public static final int TEXT_LAYER = 200;
  120. /**
  121. * Caret layer. Most extensions will be below this layer.
  122. * @since jEdit 4.2pre1
  123. */
  124. public static final int CARET_LAYER = 300;
  125. /**
  126. * Highest possible layer.
  127. * @since jEdit 4.0pre4
  128. */
  129. public static final int HIGHEST_LAYER = Integer.MAX_VALUE;
  130. //}}}
  131. //{{{ setBounds() method
  132. /**
  133. * It is a bad idea to override this, but we need to get the component
  134. * event before the first repaint.
  135. */
  136. @Override
  137. public void setBounds(int x, int y, int width, int height)
  138. {
  139. if(x == getX() && y == getY() && width == getWidth()
  140. && height == getHeight())
  141. {
  142. return;
  143. }
  144. super.setBounds(x,y,width,height);
  145. textArea.recalculateVisibleLines();
  146. if(!textArea.getBuffer().isLoading())
  147. textArea.recalculateLastPhysicalLine();
  148. textArea.propertiesChanged();
  149. textArea.updateMaxHorizontalScrollWidth();
  150. textArea.scrollBarsInitialized = true;
  151. } //}}}
  152. //{{{ addNotify() method
  153. @Override
  154. public void addNotify()
  155. {
  156. super.addNotify();
  157. hiddenCursor = getToolkit().createCustomCursor(
  158. getGraphicsConfiguration()
  159. .createCompatibleImage(16,16,
  160. Transparency.BITMASK),
  161. new Point(0,0),"Hidden");
  162. } //}}}
  163. //{{{ setCursor() method
  164. /**
  165. * Change the mouse cursor.
  166. * If the cursor is hiddenCursor or TEXT_CURSOR, it is the default cursor and the cursor will not disappear
  167. * anymore while typing until {@link #resetCursor()} is called.
  168. * @param cursor the new cursor
  169. * @since jEdit 4.4pre1
  170. */
  171. public void setCursor(Cursor cursor)
  172. {
  173. defaultCursor = cursor == hiddenCursor || cursor.getType() == Cursor.TEXT_CURSOR;
  174. super.setCursor(cursor);
  175. } //}}}
  176. //{{{ setCursor() method
  177. /**
  178. * Reset the cursor to it's default value.
  179. * @since jEdit 4.4pre1
  180. */
  181. public void resetCursor()
  182. {
  183. defaultCursor = true;
  184. } //}}}
  185. //{{{ showCursor() method
  186. /**
  187. * Show the cursor if it is the default cursor
  188. */
  189. void showCursor()
  190. {
  191. if (defaultCursor)
  192. {
  193. setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
  194. }
  195. } //}}}
  196. //{{{ hideCursor() method
  197. /**
  198. * Hide the cursor if it is the default cursor
  199. */
  200. void hideCursor()
  201. {
  202. if (defaultCursor)
  203. {
  204. setCursor(hiddenCursor);
  205. }
  206. } //}}}
  207. //{{{ getFocusTraversalKeysEnabled() method
  208. /**
  209. * Makes the tab key work in Java 1.4.
  210. * @since jEdit 3.2pre4
  211. */
  212. @Override
  213. public boolean getFocusTraversalKeysEnabled()
  214. {
  215. return false;
  216. } //}}}
  217. //{{{ Getters and setters
  218. //{{{ getStyles() method
  219. /**
  220. * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
  221. * will be used to paint tokens with id = <i>n</i>.
  222. * @return an array of SyntaxStyles
  223. * @see org.gjt.sp.jedit.syntax.Token
  224. */
  225. public final SyntaxStyle[] getStyles()
  226. {
  227. return styles;
  228. } //}}}
  229. //{{{ setStyles() method
  230. /**
  231. * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
  232. * will be used to paint tokens with id = <i>n</i>.
  233. * @param styles The syntax styles
  234. * @see org.gjt.sp.jedit.syntax.Token
  235. */
  236. public final void setStyles(SyntaxStyle[] styles)
  237. {
  238. this.styles = styles;
  239. styles[Token.NULL] = new SyntaxStyle(getForeground(),null,getFont());
  240. textArea.chunkCache.invalidateAll();
  241. repaint();
  242. } //}}}
  243. //{{{ getCaretColor() method
  244. /**
  245. * Returns the caret color.
  246. */
  247. public final Color getCaretColor()
  248. {
  249. return caretColor;
  250. } //}}}
  251. //{{{ setCaretColor() method
  252. /**
  253. * Sets the caret color.
  254. * @param caretColor The caret color
  255. */
  256. public final void setCaretColor(Color caretColor)
  257. {
  258. this.caretColor = caretColor;
  259. if(textArea.getBuffer() != null)
  260. textArea.invalidateLine(textArea.getCaretLine());
  261. } //}}}
  262. //{{{ getSelectionColor() method
  263. /**
  264. * Returns the selection color.
  265. */
  266. public final Color getSelectionColor()
  267. {
  268. return selectionColor;
  269. } //}}}
  270. //{{{ setSelectionColor() method
  271. /**
  272. * Sets the selection color.
  273. * @param selectionColor The selection color
  274. */
  275. public final void setSelectionColor(Color selectionColor)
  276. {
  277. this.selectionColor = selectionColor;
  278. textArea.repaint();
  279. } //}}}
  280. //{{{ getMultipleSelectionColor() method
  281. /**
  282. * Returns the multiple selection color.
  283. * @since jEdit 4.2pre1
  284. */
  285. public final Color getMultipleSelectionColor()
  286. {
  287. return multipleSelectionColor;
  288. } //}}}
  289. //{{{ setMultipleSelectionColor() method
  290. /**
  291. * Sets the multiple selection color.
  292. * @param multipleSelectionColor The multiple selection color
  293. * @since jEdit 4.2pre1
  294. */
  295. public final void setMultipleSelectionColor(Color multipleSelectionColor)
  296. {
  297. this.multipleSelectionColor = multipleSelectionColor;
  298. textArea.repaint();
  299. } //}}}
  300. //{{{ getLineHighlightColor() method
  301. /**
  302. * Returns the line highlight color.
  303. */
  304. public final Color getLineHighlightColor()
  305. {
  306. return lineHighlightColor;
  307. } //}}}
  308. //{{{ setLineHighlightColor() method
  309. /**
  310. * Sets the line highlight color.
  311. * @param lineHighlightColor The line highlight color
  312. */
  313. public final void setLineHighlightColor(Color lineHighlightColor)
  314. {
  315. this.lineHighlightColor = lineHighlightColor;
  316. if(textArea.getBuffer() != null)
  317. textArea.invalidateLine(textArea.getCaretLine());
  318. } //}}}
  319. //{{{ isLineHighlightEnabled() method
  320. /**
  321. * Returns true if line highlight is enabled, false otherwise.
  322. */
  323. public final boolean isLineHighlightEnabled()
  324. {
  325. return lineHighlight;
  326. } //}}}
  327. //{{{ setLineHighlightEnabled() method
  328. /**
  329. * Enables or disables current line highlighting.
  330. * @param lineHighlight True if current line highlight should be enabled,
  331. * false otherwise
  332. */
  333. public final void setLineHighlightEnabled(boolean lineHighlight)
  334. {
  335. this.lineHighlight = lineHighlight;
  336. textArea.repaint();
  337. } //}}}
  338. //{{{ getSelectionFgColor() method
  339. /**
  340. * Returns the selection foreground color, if one is set.
  341. * @since jEdit 4.4.1
  342. */
  343. public final Color getSelectionFgColor()
  344. {
  345. return selectionFgColor;
  346. } //}}}
  347. //{{{ setSelectionFgColor() method
  348. /**
  349. * Sets the selection foreground color.
  350. * @param selectionFgColor The selection foreground color
  351. * @since jEdit 4.4.1
  352. */
  353. public final void setSelectionFgColor(Color selectionFgColor)
  354. {
  355. this.selectionFgColor = selectionFgColor;
  356. if (isSelectionFgColorEnabled())
  357. textArea.repaint();
  358. } //}}}
  359. //{{{ isSelectionFgColorEnabled() method
  360. /**
  361. * Returns true if selection foreground color is enabled - i.e. a specific
  362. * color is used for the selection foreground instead of the syntax highlight
  363. * color.
  364. * @since jEdit 4.4.1
  365. */
  366. public final boolean isSelectionFgColorEnabled()
  367. {
  368. return selectionFg;
  369. } //}}}
  370. //{{{ setSelectionFgColorEnabled() method
  371. /**
  372. * Enables or disables selection foreground color.
  373. * @param selectionFg True if selection foreground should be enabled,
  374. * false otherwise
  375. * @since jEdit 4.4.1
  376. */
  377. public final void setSelectionFgColorEnabled(boolean selectionFg)
  378. {
  379. this.selectionFg = selectionFg;
  380. textArea.repaint();
  381. } //}}}
  382. //{{{ getStructureHighlightColor() method
  383. /**
  384. * Returns the structure highlight color.
  385. * @since jEdit 4.2pre3
  386. */
  387. public final Color getStructureHighlightColor()
  388. {
  389. return structureHighlightColor;
  390. } //}}}
  391. //{{{ setStructureHighlightColor() method
  392. /**
  393. * Sets the structure highlight color.
  394. * @param structureHighlightColor The bracket highlight color
  395. * @since jEdit 4.2pre3
  396. */
  397. public final void setStructureHighlightColor(
  398. Color structureHighlightColor)
  399. {
  400. this.structureHighlightColor = structureHighlightColor;
  401. textArea.invalidateStructureMatch();
  402. } //}}}
  403. //{{{ isStructureHighlightEnabled() method
  404. /**
  405. * Returns true if structure highlighting is enabled, false otherwise.
  406. * @since jEdit 4.2pre3
  407. */
  408. public final boolean isStructureHighlightEnabled()
  409. {
  410. return structureHighlight;
  411. } //}}}
  412. //{{{ setStructureHighlightEnabled() method
  413. /**
  414. * Enables or disables structure highlighting.
  415. * @param structureHighlight True if structure highlighting should be
  416. * enabled, false otherwise
  417. * @since jEdit 4.2pre3
  418. */
  419. public final void setStructureHighlightEnabled(boolean structureHighlight)
  420. {
  421. this.structureHighlight = structureHighlight;
  422. textArea.invalidateStructureMatch();
  423. } //}}}
  424. //{{{ isBlockCaretEnabled() method
  425. /**
  426. * Returns true if the caret should be drawn as a block, false otherwise.
  427. */
  428. public final boolean isBlockCaretEnabled()
  429. {
  430. return blockCaret;
  431. } //}}}
  432. //{{{ setBlockCaretEnabled() method
  433. /**
  434. * Sets if the caret should be drawn as a block, false otherwise.
  435. * @param blockCaret True if the caret should be drawn as a block,
  436. * false otherwise.
  437. */
  438. public final void setBlockCaretEnabled(boolean blockCaret)
  439. {
  440. this.blockCaret = blockCaret;
  441. extensionMgr.removeExtension(caretExtension);
  442. if(blockCaret)
  443. addExtension(BLOCK_CARET_LAYER,caretExtension);
  444. else
  445. addExtension(CARET_LAYER,caretExtension);
  446. if(textArea.getBuffer() != null)
  447. textArea.invalidateLine(textArea.getCaretLine());
  448. } //}}}
  449. //{{{ isThickCaretEnabled() method
  450. /**
  451. * Returns true if the caret should be drawn with a thick line, false otherwise.
  452. * @since jEdit 4.3pre15
  453. */
  454. public final boolean isThickCaretEnabled()
  455. {
  456. return thickCaret;
  457. } //}}}
  458. //{{{ setThickCaretEnabled() method
  459. /**
  460. * Sets if the caret should be drawn with a thick line.
  461. * @param thickCaret
  462. * True if the caret should be drawn as a block, false otherwise.
  463. * @since jEdit 4.3pre15
  464. */
  465. public final void setThickCaretEnabled(boolean thickCaret)
  466. {
  467. this.thickCaret = thickCaret;
  468. if(textArea.getBuffer() != null)
  469. textArea.invalidateLine(textArea.getCaretLine());
  470. } //}}}
  471. //{{{ getEOLMarkerColor() method
  472. /**
  473. * Returns the EOL marker color.
  474. */
  475. public final Color getEOLMarkerColor()
  476. {
  477. return eolMarkerColor;
  478. } //}}}
  479. //{{{ setEOLMarkerColor() method
  480. /**
  481. * Sets the EOL marker color.
  482. * @param eolMarkerColor The EOL marker color
  483. */
  484. public final void setEOLMarkerColor(Color eolMarkerColor)
  485. {
  486. this.eolMarkerColor = eolMarkerColor;
  487. repaint();
  488. } //}}}
  489. //{{{ getEOLMarkersPainted() method
  490. /**
  491. * Returns true if EOL markers are drawn, false otherwise.
  492. */
  493. public final boolean getEOLMarkersPainted()
  494. {
  495. return eolMarkers;
  496. } //}}}
  497. //{{{ setEOLMarkersPainted() method
  498. /**
  499. * Sets if EOL markers are to be drawn.
  500. * @param eolMarkers True if EOL markers should be drawn, false otherwise
  501. */
  502. public final void setEOLMarkersPainted(boolean eolMarkers)
  503. {
  504. this.eolMarkers = eolMarkers;
  505. repaint();
  506. } //}}}
  507. //{{{ getWrapGuideColor() method
  508. /**
  509. * Returns the wrap guide color.
  510. */
  511. public final Color getWrapGuideColor()
  512. {
  513. return wrapGuideColor;
  514. } //}}}
  515. //{{{ setWrapGuideColor() method
  516. /**
  517. * Sets the wrap guide color.
  518. * @param wrapGuideColor The wrap guide color
  519. */
  520. public final void setWrapGuideColor(Color wrapGuideColor)
  521. {
  522. this.wrapGuideColor = wrapGuideColor;
  523. repaint();
  524. } //}}}
  525. //{{{ isWrapGuidePainted() method
  526. /**
  527. * Returns true if the wrap guide is drawn, false otherwise.
  528. * @since jEdit 4.0pre4
  529. */
  530. public final boolean isWrapGuidePainted()
  531. {
  532. return wrapGuide;
  533. } //}}}
  534. //{{{ setWrapGuidePainted() method
  535. /**
  536. * Sets if the wrap guide is to be drawn.
  537. * @param wrapGuide True if the wrap guide should be drawn, false otherwise
  538. */
  539. public final void setWrapGuidePainted(boolean wrapGuide)
  540. {
  541. this.wrapGuide = wrapGuide;
  542. repaint();
  543. } //}}}
  544. //{{{ getFoldLineStyle() method
  545. /**
  546. * Returns the fold line style. The first element is the style for
  547. * lines with a fold level greater than 3. The remaining elements
  548. * are for fold levels 1 to 3.
  549. */
  550. public final SyntaxStyle[] getFoldLineStyle()
  551. {
  552. return foldLineStyle;
  553. } //}}}
  554. //{{{ setFoldLineStyle() method
  555. /**
  556. * Sets the fold line style. The first element is the style for
  557. * lines with a fold level greater than 3. The remaining elements
  558. * are for fold levels 1 to 3.
  559. * @param foldLineStyle The fold line style
  560. */
  561. public final void setFoldLineStyle(SyntaxStyle[] foldLineStyle)
  562. {
  563. this.foldLineStyle = foldLineStyle;
  564. textArea.chunkCache.invalidateAll();
  565. repaint();
  566. } //}}}
  567. //{{{ setAntiAliasEnabled() method
  568. /**
  569. * As of jEdit 4.3pre4, a new JDK 1.6 subpixel antialias mode is supported.
  570. *
  571. * @since jEdit 4.2pre4
  572. */
  573. public void setAntiAlias(AntiAlias newValue)
  574. {
  575. antiAlias = newValue;
  576. updateRenderingHints();
  577. } //}}}
  578. //{{{ getAntiAlias() method
  579. /**
  580. * @return the AntiAlias value that is currently used for TextAreas.
  581. * @since jedit 4.3pre4
  582. */
  583. public AntiAlias getAntiAlias()
  584. {
  585. return antiAlias;
  586. } //}}}
  587. //{{{ setFractionalFontMetricsEnabled() method
  588. /**
  589. * Sets if fractional font metrics should be enabled. Has no effect when
  590. * running on Java 1.1.
  591. * @since jEdit 3.2pre6
  592. */
  593. public void setFractionalFontMetricsEnabled(boolean fracFontMetrics)
  594. {
  595. this.fracFontMetrics = fracFontMetrics;
  596. updateRenderingHints();
  597. } //}}}
  598. //{{{ isFractionalFontMetricsEnabled() method
  599. /**
  600. * Returns if fractional font metrics are enabled.
  601. * @since jEdit 3.2pre6
  602. */
  603. public boolean isFractionalFontMetricsEnabled()
  604. {
  605. return fracFontMetrics;
  606. } //}}}
  607. //{{{ getFontRenderContext() method
  608. /**
  609. * Returns the font render context.
  610. * @since jEdit 4.0pre4
  611. */
  612. public FontRenderContext getFontRenderContext()
  613. {
  614. return fontRenderContext;
  615. } //}}}
  616. //}}}
  617. //{{{ addExtension() method
  618. /**
  619. * Adds a text area extension, which can perform custom painting and
  620. * tool tip handling.
  621. * @param extension The extension
  622. * @since jEdit 4.0pre4
  623. */
  624. public void addExtension(TextAreaExtension extension)
  625. {
  626. extensionMgr.addExtension(DEFAULT_LAYER,extension);
  627. repaint();
  628. } //}}}
  629. //{{{ addExtension() method
  630. /**
  631. * Adds a text area extension, which can perform custom painting and
  632. * tool tip handling.
  633. * @param layer The layer to add the extension to. Note that more than
  634. * extension can share the same layer.
  635. * @param extension The extension
  636. * @since jEdit 4.0pre4
  637. */
  638. public void addExtension(int layer, TextAreaExtension extension)
  639. {
  640. extensionMgr.addExtension(layer,extension);
  641. repaint();
  642. } //}}}
  643. //{{{ removeExtension() method
  644. /**
  645. * Removes a text area extension. It will no longer be asked to
  646. * perform custom painting and tool tip handling.
  647. * @param extension The extension
  648. * @since jEdit 4.0pre4
  649. */
  650. public void removeExtension(TextAreaExtension extension)
  651. {
  652. extensionMgr.removeExtension(extension);
  653. repaint();
  654. } //}}}
  655. //{{{ getExtensions() method
  656. /**
  657. * Returns an array of registered text area extensions. Useful for
  658. * debugging purposes.
  659. * @since jEdit 4.1pre5
  660. */
  661. public TextAreaExtension[] getExtensions()
  662. {
  663. return extensionMgr.getExtensions();
  664. } //}}}
  665. //{{{ getToolTipText() method
  666. /**
  667. * Returns the tool tip to display at the specified location.
  668. * @param evt The mouse event
  669. */
  670. @Override
  671. public String getToolTipText(MouseEvent evt)
  672. {
  673. if(textArea.getBuffer().isLoading())
  674. return null;
  675. return extensionMgr.getToolTipText(evt.getX(),evt.getY());
  676. } //}}}
  677. //{{{ getFontMetrics() method
  678. /**
  679. * Returns the font metrics used by this component.
  680. */
  681. public FontMetrics getFontMetrics()
  682. {
  683. return fm;
  684. } //}}}
  685. //{{{ getLineHeight() method
  686. /**
  687. * Returns the line height as given by the font metrics plus the
  688. * added line spacing.
  689. */
  690. public int getLineHeight()
  691. {
  692. return fm.getHeight() + extraLineSpacing;
  693. } //}}}
  694. //{{{ getFontHeight() method
  695. /**
  696. * Returns the font height as given by the font metrics.
  697. */
  698. public int getFontHeight()
  699. {
  700. return fm.getHeight();
  701. } //}}}
  702. //{{{ getLineExtraSpacing() method
  703. /**
  704. * Returns the number of pixels from the start of the line to the start
  705. * of text (the extra line spacing).
  706. */
  707. public int getLineExtraSpacing()
  708. {
  709. return extraLineSpacing;
  710. } //}}}
  711. //{{{ setLineExtraSpacing() method
  712. /**
  713. * Sets extra spacing between lines in pixels.
  714. */
  715. public void setLineExtraSpacing(int spacing)
  716. {
  717. extraLineSpacing = spacing;
  718. } //}}}
  719. //{{{ setFont() method
  720. /**
  721. * Sets the font for this component. This is overridden to update the
  722. * cached font metrics and to recalculate which lines are visible.
  723. * @param font The font
  724. */
  725. @Override
  726. public void setFont(Font font)
  727. {
  728. super.setFont(font);
  729. fm = getFontMetrics(font);
  730. textArea.recalculateVisibleLines();
  731. if(textArea.getBuffer() != null
  732. && !textArea.getBuffer().isLoading())
  733. textArea.recalculateLastPhysicalLine();
  734. //textArea.propertiesChanged();
  735. } //}}}
  736. //{{{ getStringWidth() method
  737. /**
  738. * Returns the width of the given string, in pixels, using the text
  739. * area's current font.
  740. *
  741. * @since jEdit 4.2final
  742. */
  743. public float getStringWidth(String str)
  744. {
  745. if(textArea.charWidth != 0)
  746. return textArea.charWidth * str.length();
  747. else
  748. {
  749. return (float)getFont().getStringBounds(
  750. str,getFontRenderContext()).getWidth();
  751. }
  752. } //}}}
  753. //{{{ getRenderingHints() method
  754. /**
  755. * Returns the rendering hints used by the Graphics2D class; in this
  756. * case, for anti-aliasing of text.
  757. *
  758. * @since jEdit 4.5pre1
  759. */
  760. public RenderingHints getRenderingHints()
  761. {
  762. return renderingHints;
  763. } //}}}
  764. //{{{ update() method
  765. /**
  766. * Repaints the text.
  767. * @param _gfx The graphics context
  768. */
  769. @Override
  770. public void update(Graphics _gfx)
  771. {
  772. paint(_gfx);
  773. } //}}}
  774. //{{{ paint() method
  775. /**
  776. * Repaints the text.
  777. * @param _gfx The graphics context
  778. */
  779. @Override
  780. public void paint(Graphics _gfx)
  781. {
  782. assert _gfx instanceof Graphics2D;
  783. Graphics2D gfx = (Graphics2D)_gfx;
  784. gfx.setRenderingHints(renderingHints);
  785. fontRenderContext = gfx.getFontRenderContext();
  786. Rectangle clipRect = gfx.getClipBounds();
  787. int lineHeight = getLineHeight();
  788. int charHeight = getFontHeight();
  789. if(lineHeight == 0 || textArea.getBuffer().isLoading())
  790. {
  791. gfx.setColor(getBackground());
  792. gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
  793. }
  794. else
  795. {
  796. long prepareTime = System.nanoTime();
  797. // Because the clipRect's height is usually an even multiple
  798. // of the font height, we subtract 1 from it, otherwise one
  799. // too many lines will always be painted.
  800. int firstLine = clipRect.y / lineHeight;
  801. int lastLine = (clipRect.y + clipRect.height - 1) / lineHeight;
  802. gfx.setColor(getBackground());
  803. gfx.setFont(getFont());
  804. prepareTime = System.nanoTime() - prepareTime;
  805. long linesTime = System.nanoTime();
  806. int numLines = lastLine - firstLine + 1;
  807. int y = firstLine * lineHeight;
  808. gfx.fillRect(0,y,getWidth(),numLines * lineHeight);
  809. extensionMgr.paintScreenLineRange(textArea,gfx,
  810. firstLine,lastLine,
  811. y, lineHeight);
  812. linesTime = System.nanoTime() - linesTime;
  813. if(Debug.PAINT_TIMER && numLines >= 1)
  814. Log.log(Log.DEBUG,this,"repainting " + numLines + " lines took " + prepareTime + "/" + linesTime + " ns");
  815. }
  816. textArea.updateMaxHorizontalScrollWidth();
  817. } //}}}
  818. //{{{ nextTabStop() method
  819. /**
  820. * Implementation of TabExpander interface. Returns next tab stop after
  821. * a specified point.
  822. * @param x The x co-ordinate
  823. * @param tabOffset Ignored
  824. * @return The next tab stop after <i>x</i>
  825. */
  826. public float nextTabStop(float x, int tabOffset)
  827. {
  828. int ntabs = (int)(x / textArea.tabSize);
  829. return (ntabs + 1) * textArea.tabSize;
  830. } //}}}
  831. //{{{ getPreferredSize() method
  832. /**
  833. * Returns the painter's preferred size.
  834. */
  835. @Override
  836. public Dimension getPreferredSize()
  837. {
  838. Dimension dim = new Dimension();
  839. char[] foo = new char[80];
  840. for(int i = 0; i < foo.length; i++)
  841. foo[i] = ' ';
  842. dim.width = (int)getStringWidth(new String(foo));
  843. dim.height = getLineHeight() * 25;
  844. return dim;
  845. } //}}}
  846. //{{{ getMinimumSize() method
  847. /**
  848. * Returns the painter's minimum size.
  849. */
  850. @Override
  851. public Dimension getMinimumSize()
  852. {
  853. return getPreferredSize();
  854. } //}}}
  855. //{{{ Package-private members
  856. //{{{ Instance variables
  857. /* package-private since they are accessed by inner classes and we
  858. * want this to be fast */
  859. TextArea textArea;
  860. SyntaxStyle[] styles;
  861. Color caretColor;
  862. Color selectionColor;
  863. Color multipleSelectionColor;
  864. Color lineHighlightColor;
  865. Color structureHighlightColor;
  866. Color eolMarkerColor;
  867. Color wrapGuideColor;
  868. SyntaxStyle[] foldLineStyle;
  869. boolean blockCaret;
  870. boolean thickCaret;
  871. boolean lineHighlight;
  872. boolean structureHighlight;
  873. boolean eolMarkers;
  874. boolean wrapGuide;
  875. AntiAlias antiAlias;
  876. boolean fracFontMetrics;
  877. RenderingHints renderingHints;
  878. boolean selectionFg;
  879. Color selectionFgColor;
  880. // should try to use this as little as possible.
  881. FontMetrics fm;
  882. int extraLineSpacing;
  883. //}}}
  884. //{{{ TextAreaPainter constructor
  885. /**
  886. * Creates a new painter. Do not create instances of this class
  887. * directly.
  888. */
  889. TextAreaPainter(TextArea textArea)
  890. {
  891. enableEvents(AWTEvent.FOCUS_EVENT_MASK
  892. | AWTEvent.KEY_EVENT_MASK
  893. | AWTEvent.MOUSE_EVENT_MASK);
  894. this.textArea = textArea;
  895. antiAlias = new AntiAlias(0);
  896. extensionMgr = new ExtensionManager();
  897. setAutoscrolls(true);
  898. setOpaque(true);
  899. setRequestFocusEnabled(false);
  900. setDoubleBuffered(false);
  901. setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
  902. fontRenderContext = new FontRenderContext(null,false,false);
  903. addExtension(LINE_BACKGROUND_LAYER,new PaintLineBackground());
  904. addExtension(SELECTION_LAYER,new PaintSelection());
  905. addExtension(WRAP_GUIDE_LAYER,new PaintWrapGuide());
  906. addExtension(BRACKET_HIGHLIGHT_LAYER,new StructureMatcher
  907. .Highlight(textArea));
  908. addExtension(TEXT_LAYER,new PaintText());
  909. addExtension(TEXT_LAYER,new PaintSelectionText());
  910. caretExtension = new PaintCaret();
  911. extraLineSpacing = 0;
  912. } //}}}
  913. //}}}
  914. //{{{ Private members
  915. //{{{ Instance variables
  916. private final ExtensionManager extensionMgr;
  917. private final PaintCaret caretExtension;
  918. private FontRenderContext fontRenderContext;
  919. private Cursor hiddenCursor;
  920. private boolean defaultCursor = true;
  921. //}}}
  922. //{{{ updateRenderingHints() method
  923. private void updateRenderingHints()
  924. {
  925. Map<RenderingHints.Key,Object> hints = new HashMap<RenderingHints.Key,Object>();
  926. hints.put(RenderingHints.KEY_FRACTIONALMETRICS,
  927. fracFontMetrics ? RenderingHints.VALUE_FRACTIONALMETRICS_ON
  928. : RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
  929. hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, antiAlias.renderHint());
  930. if (antiAlias.val() == 0)
  931. {
  932. hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
  933. fontRenderContext = new FontRenderContext(null, antiAlias.val() > 0, fracFontMetrics);
  934. }
  935. /* Subpixel antialiasing mode */
  936. else if (antiAlias.val() > 1)
  937. {
  938. Object fontRenderHint = fracFontMetrics ?
  939. RenderingHints.VALUE_FRACTIONALMETRICS_ON :
  940. RenderingHints.VALUE_FRACTIONALMETRICS_OFF;
  941. fontRenderContext = new FontRenderContext(null, antiAlias.renderHint(),
  942. fontRenderHint);
  943. }
  944. else /** Standard Antialias Version */
  945. {
  946. hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
  947. hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  948. hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  949. fontRenderContext = new FontRenderContext(null, antiAlias.val() > 0, fracFontMetrics);
  950. }
  951. renderingHints = new RenderingHints(hints);
  952. } //}}}
  953. //}}}
  954. //{{{ Inner classes
  955. //{{{ PaintLineBackground class
  956. private class PaintLineBackground extends TextAreaExtension
  957. {
  958. //{{{ shouldPaintLineHighlight() method
  959. private boolean shouldPaintLineHighlight(int caret, int start, int end)
  960. {
  961. if(!isLineHighlightEnabled()
  962. || caret < start || caret >= end)
  963. {
  964. return false;
  965. }
  966. int count = textArea.getSelectionCount();
  967. if(count == 1)
  968. {
  969. Selection s = textArea.getSelection(0);
  970. return s.getStartLine() == s.getEndLine();
  971. }
  972. else
  973. return count == 0;
  974. } //}}}
  975. //{{{ paintValidLine() method
  976. @Override
  977. public void paintValidLine(Graphics2D gfx, int screenLine,
  978. int physicalLine, int start, int end, int y)
  979. {
  980. // minimise access$ methods
  981. TextArea textArea = TextAreaPainter.this.textArea;
  982. JEditBuffer buffer = textArea.getBuffer();
  983. //{{{ Paint line highlight and collapsed fold highlight
  984. boolean collapsedFold =
  985. physicalLine < buffer.getLineCount() - 1
  986. && buffer.isFoldStart(physicalLine)
  987. && !textArea.displayManager
  988. .isLineVisible(physicalLine + 1);
  989. SyntaxStyle foldLineStyle = null;
  990. if(collapsedFold)
  991. {
  992. int level = buffer.getFoldLevel(physicalLine + 1);
  993. if(buffer.getFoldHandler() instanceof IndentFoldHandler)
  994. level = Math.max(1,level / buffer.getIndentSize());
  995. if(level > 3)
  996. level = 0;
  997. foldLineStyle = TextAreaPainter.this.foldLineStyle[level];
  998. }
  999. int caret = textArea.getCaretPosition();
  1000. boolean paintLineHighlight = shouldPaintLineHighlight(
  1001. caret,start,end);
  1002. Color bgColor;
  1003. if(paintLineHighlight)
  1004. bgColor = lineHighlightColor;
  1005. else if(collapsedFold)
  1006. {
  1007. bgColor = foldLineStyle.getBackgroundColor();
  1008. if(bgColor == null)
  1009. bgColor = getBackground();
  1010. }
  1011. else
  1012. bgColor = getBackground();
  1013. if(paintLineHighlight || collapsedFold)
  1014. {
  1015. gfx.setColor(bgColor);
  1016. gfx.fillRect(0,y,getWidth(),getLineHeight());
  1017. } //}}}
  1018. //{{{ Paint token backgrounds
  1019. ChunkCache.LineInfo lineInfo = textArea.chunkCache
  1020. .getLineInfo(screenLine);
  1021. if(lineInfo.chunks != null)
  1022. {
  1023. float baseLine = y + getLineHeight() - (fm.getLeading()+1) - fm.getDescent();
  1024. Chunk.paintChunkBackgrounds(
  1025. lineInfo.chunks,gfx,
  1026. textArea.getHorizontalOffset(),
  1027. baseLine, getLineHeight());
  1028. } //}}}
  1029. } //}}}
  1030. } //}}}
  1031. //{{{ PaintSelection class
  1032. private class PaintSelection extends TextAreaExtension
  1033. {
  1034. //{{{ paintValidLine() method
  1035. @Override
  1036. public void paintValidLine(Graphics2D gfx, int screenLine,
  1037. int physicalLine, int start, int end, int y)
  1038. {
  1039. if(textArea.getSelectionCount() == 0)
  1040. return;
  1041. gfx.setColor(textArea.isMultipleSelectionEnabled()
  1042. ? getMultipleSelectionColor()
  1043. : getSelectionColor());
  1044. Iterator<Selection> iter = textArea.getSelectionIterator();
  1045. while(iter.hasNext())
  1046. {
  1047. Selection s = iter.next();
  1048. paintSelection(gfx,screenLine,physicalLine,y,s);
  1049. }
  1050. } //}}}
  1051. //{{{ paintSelection() method
  1052. private void paintSelection(Graphics2D gfx, int screenLine,
  1053. int physicalLine, int y, Selection s)
  1054. {
  1055. int[] selectionStartAndEnd
  1056. = textArea.selectionManager
  1057. .getSelectionStartAndEnd(
  1058. screenLine,physicalLine,s);
  1059. if(selectionStartAndEnd == null)
  1060. return;
  1061. int x1 = selectionStartAndEnd[0];
  1062. int x2 = selectionStartAndEnd[1];
  1063. gfx.fillRect(x1, y, x2 - x1, getLineHeight());
  1064. } //}}}
  1065. } //}}}
  1066. //{{{ PaintSelectionText class
  1067. private class PaintSelectionText extends TextAreaExtension
  1068. {
  1069. // All screen lines of the same physical line use the same indentation
  1070. private float indent;
  1071. private boolean indentFound = false;
  1072. //{{{ paintValidLine() method
  1073. @Override
  1074. public void paintValidLine(Graphics2D gfx, int screenLine,
  1075. int physicalLine, int start, int end, int y)
  1076. {
  1077. if(textArea.getSelectionCount() == 0)
  1078. return;
  1079. if ((! isSelectionFgColorEnabled()) || (getSelectionFgColor() == null))
  1080. return;
  1081. Iterator<Selection> iter = textArea.getSelectionIterator();
  1082. while(iter.hasNext())
  1083. {
  1084. Selection s = iter.next();
  1085. paintSelection(gfx,screenLine,physicalLine,y,s);
  1086. }
  1087. } //}}}
  1088. //{{{ paintSelection() method
  1089. private void paintSelection(Graphics2D gfx, int screenLine,
  1090. int physicalLine, int y, Selection s)
  1091. {
  1092. if ((physicalLine < s.getStartLine()) || (physicalLine > s.getEndLine()))
  1093. return;
  1094. float x = indent = textArea.getHorizontalOffset();
  1095. float baseLine = y + fm.getHeight() -
  1096. (fm.getLeading()+1) - fm.getDescent();
  1097. DefaultTokenHandler tokenHandler = new DefaultTokenHandler();
  1098. textArea.getBuffer().markTokens(physicalLine, tokenHandler);
  1099. Token token = tokenHandler.getTokens();
  1100. int lineStart = textArea.getLineStartOffset(physicalLine);
  1101. int startOffset, endOffset;
  1102. if (s instanceof Selection.Rect)
  1103. {
  1104. Selection.Rect r = (Selection.Rect)s;
  1105. startOffset = r.getStart(textArea.getBuffer(), physicalLine);
  1106. endOffset = r.getEnd(textArea.getBuffer(), physicalLine);
  1107. }
  1108. else
  1109. {
  1110. startOffset = (s.getStart() > lineStart) ? s.getStart() : lineStart;
  1111. endOffset = s.getEnd();
  1112. }
  1113. // Soft-wrap
  1114. int screenLineStart = textArea.getScreenLineStartOffset(screenLine);
  1115. int screenLineEnd = textArea.getScreenLineEndOffset(screenLine);
  1116. if (screenLineStart > startOffset)
  1117. startOffset = screenLineStart;
  1118. if (screenLineEnd < endOffset)
  1119. endOffset = screenLineEnd;
  1120. indentFound = false;
  1121. int tokenStart = lineStart;
  1122. while(token.id != Token.END)
  1123. {
  1124. int next = tokenStart + token.length;
  1125. String sub = null;
  1126. SyntaxStyle style = styles[token.id];
  1127. if (next > startOffset) // Reached selection start
  1128. {
  1129. if (tokenStart >= endOffset) // Got past selection
  1130. break;
  1131. if(style != null)
  1132. {
  1133. gfx.setFont(style.getFont());
  1134. gfx.setColor(getSelectionFgColor());
  1135. int strStart;
  1136. if (startOffset > tokenStart)
  1137. {
  1138. strStart = startOffset;
  1139. x = nextX(x, style, sub, tokenStart, startOffset);
  1140. }
  1141. else
  1142. strStart = tokenStart;
  1143. int strEnd = (endOffset > next) ? next : endOffset;
  1144. sub = textArea.getText(strStart, strEnd - strStart);
  1145. gfx.drawString(sub, x, baseLine);
  1146. x = nextX(x, style, sub, strStart, strEnd);
  1147. }
  1148. }
  1149. if (sub == null)
  1150. x = nextX(x, style, null, tokenStart, next);
  1151. tokenStart = next;
  1152. token = token.next;
  1153. if (tokenStart == screenLineStart)
  1154. x = indent;
  1155. }
  1156. } //}}}
  1157. //{{{
  1158. float nextX(float x, SyntaxStyle style, String s, int startOffset,
  1159. int endOffset)
  1160. {
  1161. if (s == null)
  1162. s = textArea.getText(startOffset, endOffset - startOffset);
  1163. if (s.equals("\t"))
  1164. {
  1165. int horzOffset = textArea.getHorizontalOffset();
  1166. x = nextTabStop(x - horzOffset, endOffset) + horzOffset;
  1167. }
  1168. else
  1169. {
  1170. if ((! indentFound) && (! s.equals(" ")))
  1171. {
  1172. indentFound = true;
  1173. indent = x;
  1174. }
  1175. Font font = (style != null) ? style.getFont() : getFont();
  1176. x += font.getStringBounds(s, getFontRenderContext()).getWidth();
  1177. }
  1178. return x;
  1179. }
  1180. } //}}}
  1181. //{{{ PaintWrapGuide class
  1182. private class PaintWrapGuide extends TextAreaExtension
  1183. {
  1184. @Override
  1185. public void paintScreenLineRange(Graphics2D gfx, int firstLine,
  1186. int lastLine, int[] physicalLines, int[] start,
  1187. int[] end, int y, int lineHeight)
  1188. {
  1189. if(textArea.wrapMargin != 0
  1190. && !textArea.wrapToWidth
  1191. && isWrapGuidePainted())
  1192. {
  1193. gfx.setColor(getWrapGuideColor());
  1194. int x = textArea.getHorizontalOffset()
  1195. + textArea.wrapMargin;
  1196. gfx.drawLine(x,y,x,y + (lastLine - firstLine
  1197. + 1) * lineHeight);
  1198. }
  1199. }
  1200. @Override
  1201. public String getToolTipText(int x, int y)
  1202. {
  1203. if(textArea.wrapMargin != 0
  1204. && !textArea.wrapToWidth
  1205. && isWrapGuidePainted())
  1206. {
  1207. int wrapGuidePos = textArea.wrapMargin
  1208. + textArea.getHorizontalOffset();
  1209. if(Math.abs(x - wrapGuidePos) < 5)
  1210. {
  1211. return String.valueOf(textArea.getBuffer()
  1212. .getProperty("maxLineLen"));
  1213. }
  1214. }
  1215. return null;
  1216. }
  1217. } //}}}
  1218. //{{{ PaintText class
  1219. private class PaintText extends TextAreaExtension
  1220. {
  1221. @Override
  1222. public void paintValidLine(Graphics2D gfx, int screenLine,
  1223. int physicalLine, int start, int end, int y)
  1224. {
  1225. ChunkCache.LineInfo lineInfo = textArea.chunkCache
  1226. .getLineInfo(screenLine);
  1227. Font defaultFont = getFont();
  1228. Color defaultColor = getForeground();
  1229. gfx.setFont(defaultFont);
  1230. gfx.setColor(defaultColor);
  1231. int x = textArea.getHorizontalOffset();
  1232. int originalX = x;
  1233. float baseLine = y + getLineHeight() - (fm.getLeading()+1) - fm.getDescent();
  1234. if(lineInfo.chunks != null)
  1235. {
  1236. x += Chunk.paintChunkList(lineInfo.chunks,
  1237. gfx,textArea.getHorizontalOffset(),
  1238. baseLine,!Debug.DISABLE_GLYPH_VECTOR);
  1239. }
  1240. JEditBuffer buffer = textArea.getBuffer();
  1241. if(!lineInfo.lastSubregion)
  1242. {
  1243. gfx.setFont(defaultFont);
  1244. gfx.setColor(eolMarkerColor);
  1245. gfx.drawString(":",Math.max(x,
  1246. textArea.getHorizontalOffset()
  1247. + textArea.wrapMargin + textArea.charWidth),
  1248. baseLine);
  1249. x += textArea.charWidth;
  1250. }
  1251. else if(physicalLine < buffer.getLineCount() - 1
  1252. && buffer.isFoldStart(physicalLine)
  1253. && !textArea.displayManager
  1254. .isLineVisible(physicalLine + 1))
  1255. {
  1256. int level = buffer.getFoldLevel(physicalLine + 1);
  1257. if(buffer.getFoldHandler() instanceof IndentFoldHandler)
  1258. level = Math.max(1,level / buffer.getIndentSize());
  1259. if(level > 3)
  1260. level = 0;
  1261. SyntaxStyle foldLineStyle = TextAreaPainter.this.foldLineStyle[level];
  1262. Font font = foldLineStyle.getFont();
  1263. gfx.setFont(font);
  1264. gfx.setColor(foldLineStyle.getForegroundColor());
  1265. int nextLine;
  1266. int nextScreenLine = screenLine + 1;
  1267. if(nextScreenLine < textArea.getVisibleLines())
  1268. {
  1269. nextLine = textArea.chunkCache.getLineInfo(nextScreenLine)
  1270. .physicalLine;
  1271. }
  1272. else
  1273. {
  1274. nextLine = textArea.displayManager
  1275. .getNextVisibleLine(physicalLine);
  1276. }
  1277. if(nextLine == -1)
  1278. nextLine = textArea.getLineCount();
  1279. int count = nextLine - physicalLine - 1;
  1280. String str = " [" + count + " lines]";
  1281. float width = getStringWidth(str);
  1282. gfx.drawString(str,x,baseLine);
  1283. x += width;
  1284. }
  1285. else if(eolMarkers)
  1286. {
  1287. gfx.setFont(defaultFont);
  1288. gfx.setColor(eolMarkerColor);
  1289. gfx.drawString(".",x,baseLine);
  1290. x += textArea.charWidth;
  1291. }
  1292. lineInfo.width = x - originalX;
  1293. }
  1294. } //}}}
  1295. //{{{ PaintCaret class
  1296. private class PaintCaret extends TextAreaExtension
  1297. {
  1298. @Override
  1299. public void paintValidLine(Graphics2D gfx, int screenLine,
  1300. int physicalLine, int start, int end, int y)
  1301. {
  1302. if(!textArea.isCaretVisible())
  1303. return;
  1304. int caret = textArea.getCaretPosition();
  1305. if(caret < start || caret >= end)
  1306. return;
  1307. int offset = caret - textArea.getLineStartOffset(physicalLine);
  1308. textArea.offsetToXY(physicalLine,
  1309. offset, textArea.offsetXY);
  1310. int caretX = textArea.offsetXY.x;
  1311. int lineHeight = getLineHeight();
  1312. int charHeight = getFontHeight();
  1313. int charOffset = lineHeight - charHeight;
  1314. gfx.setColor(caretColor);
  1315. if(textArea.isOverwriteEnabled())
  1316. {
  1317. gfx.drawLine(caretX, y + lineHeight - 1,
  1318. caretX + textArea.charWidth,
  1319. y + lineHeight - 1);
  1320. }
  1321. else if(blockCaret)
  1322. gfx.drawRect(caretX, y + charOffset, textArea.charWidth - 1, charHeight - 1);
  1323. else
  1324. {
  1325. if (thickCaret)
  1326. gfx.drawRect(caretX, y + charOffset, 1, charHeight - 1);
  1327. else
  1328. gfx.drawLine(caretX, y + charOffset, caretX,
  1329. y + charOffset + charHeight - 1);
  1330. }
  1331. }
  1332. } //}}}
  1333. //}}}
  1334. //}}}
  1335. }