4
* ChangableHighlightPainter.java - A highlight painter whose color you can
7
* This library is distributed under a modified BSD license. See the included
8
* RSyntaxTextArea.License.txt file for details.
10
package org.fife.ui.rtextarea;
12
import java.awt.AlphaComposite;
13
import java.awt.Color;
14
import java.awt.Composite;
15
import java.awt.Graphics;
16
import java.awt.Graphics2D;
17
import java.awt.Paint;
18
import java.awt.Rectangle;
19
import java.awt.Shape;
20
import java.awt.SystemColor;
21
import java.io.IOException;
22
import java.io.ObjectInputStream;
23
import java.io.ObjectOutputStream;
24
import java.io.Serializable;
25
import javax.swing.plaf.TextUI;
26
import javax.swing.text.BadLocationException;
27
import javax.swing.text.JTextComponent;
28
import javax.swing.text.LayeredHighlighter;
29
import javax.swing.text.Position;
30
import javax.swing.text.View;
34
* An extension of <code>LayerPainter</code> that allows the user to
35
* change several of its properties:
38
* <li>Its color/fill style (can use a <code>GradientPaint</code>, for
40
* <li>Whether the edges of a painted highlight are rounded.</li>
41
* <li>Whether painted highlights have translucency.</li>
44
* @author Robert Futrell
47
public class ChangeableHighlightPainter
48
extends LayeredHighlighter.LayerPainter implements Serializable {
52
* The <code>Paint</code>/<code>Color</code> of this highlight.
57
* Whether selections have rounded edges.
59
private boolean roundedEdges;
62
* The alpha composite used to render with translucency.
64
private transient AlphaComposite alphaComposite;
67
* The alpha value used in computing translucency. This should stay in the
68
* range <code>0.0f</code> (completely invisible) to <code>1.0f</code>
69
* (completely opaque).
74
private static final int ARCWIDTH = 8;
75
private static final int ARCHEIGHT = 8;
79
* Creates a new <code>ChangableHighlightPainter</code> that paints
80
* highlights with the text area's selection color (i.e., behaves exactly
82
* <code>javax.swing.text.DefaultHighlighter.DefaultHighlightPainter
85
public ChangeableHighlightPainter() {
91
* Creates a new highlight painter using the specified <code>Paint</code>
92
* without rounded edges.
94
* @param paint The <code>Paint</code> (usually a
95
* <code>java.awt.Color</code>) with which to paint the
98
public ChangeableHighlightPainter(Paint paint) {
104
* Creates a new highlight painter.
106
* @param paint The <code>Paint</code> (usually a
107
* <code>java.awt.Color</code>) with which to paint the
109
* @param rounded Whether to use rounded edges on the highlights.
111
public ChangeableHighlightPainter(Paint paint, boolean rounded) {
112
this(paint, rounded, 1.0f);
117
* Creates a new highlight painter.
119
* @param paint The <code>Paint</code> (usually a
120
* <code>java.awt.Color</code>) with which to paint the
122
* @param rounded Whether to use rounded edges on the highlights.
123
* @param alpha The alpha value to use when painting highlights. This
124
* value should be in the range <code>0.0f</code> (completely
125
* transparent) through <code>1.0f</code> (opaque).
127
public ChangeableHighlightPainter(Paint paint, boolean rounded,
130
setRoundedEdges(rounded);
136
* Returns the alpha value used in computing the translucency of these
137
* highlights. A value of <code>1.0f</code> (the default) means that no
138
* translucency is used; there is no performance hit for this value. For
139
* all other values (<code>[0.0f..1.0f)</code>), there will be a
142
* @return The alpha value.
145
public float getAlpha() {
151
* Returns the alpha composite to use when rendering highlights with this
154
* @return The alpha composite.
156
private AlphaComposite getAlphaComposite() {
157
if (alphaComposite==null)
158
alphaComposite = AlphaComposite.getInstance(
159
AlphaComposite.SRC_OVER, alpha);
160
return alphaComposite;
165
* Returns the <code>Paint</code> (usually a <code>java.awt.Color</code>)
166
* being used to paint highlights.
168
* @return The <code>Paint</code>.
171
public Paint getPaint() {
177
* Returns whether rounded edges are used when painting selections with
178
* this highlight painter.
180
* @return Whether rounded edges are used.
181
* @see #setRoundedEdges
183
public boolean getRoundedEdges() {
189
* Paints a highlight.
191
* @param g the graphics context
192
* @param offs0 the starting model offset >= 0
193
* @param offs1 the ending model offset >= offs1
194
* @param bounds the bounding box for the highlight
195
* @param c the editor
197
public void paint(Graphics g, int offs0, int offs1, Shape bounds,
200
Rectangle alloc = bounds.getBounds();
202
// Set up translucency if necessary.
203
Graphics2D g2d = (Graphics2D)g;
204
Composite originalComposite = null;
205
if (getAlpha()<1.0f) {
206
originalComposite = g2d.getComposite();
207
g2d.setComposite(getAlphaComposite());
212
// Determine locations.
213
TextUI mapper = c.getUI();
214
Rectangle p0 = mapper.modelToView(c, offs0);
215
Rectangle p1 = mapper.modelToView(c, offs1);
216
Paint paint = getPaint();
218
g2d.setColor(c.getSelectionColor());
222
// Entire highlight is on one line.
224
Rectangle r = p0.union(p1);
225
g2d.fillRect(r.x, r.y, r.width, r.height);
228
// Highlight spans lines.
230
int p0ToMarginWidth = alloc.x + alloc.width - p0.x;
231
g2d.fillRect(p0.x, p0.y, p0ToMarginWidth, p0.height);
232
if ((p0.y + p0.height) != p1.y) {
233
g2d.fillRect(alloc.x, p0.y + p0.height, alloc.width,
234
p1.y - (p0.y + p0.height));
236
g2d.fillRect(alloc.x, p1.y, (p1.x - alloc.x), p1.height);
239
} catch (BadLocationException e) {
243
// Restore state from before translucency if necessary.
245
g2d.setComposite(originalComposite);
252
* Paints a portion of a highlight.
254
* @param g the graphics context
255
* @param offs0 the starting model offset >= 0
256
* @param offs1 the ending model offset >= offs1
257
* @param bounds the bounding box of the view, which is not
258
* necessarily the region to paint.
259
* @param c the editor
260
* @param view View painting for
261
* @return region drawing occurred in
264
public Shape paintLayer(Graphics g, int offs0, int offs1,
265
Shape bounds, JTextComponent c, View view) {
268
// Set up translucency if necessary.
269
Graphics2D g2d = (Graphics2D)g;
270
Composite originalComposite = null;
271
if (getAlpha()<1.0f) {
272
originalComposite = g2d.getComposite();
273
g2d.setComposite(getAlphaComposite());
276
// Set the color (our own if defined, otherwise text area's).
277
Paint paint = getPaint();
279
g2d.setColor(c.getSelectionColor());
283
// This special case isn't needed for most standard Swing Views (which
284
// always return a width of 1 for modelToView() calls), but it is
285
// needed for RSTA views, which actually return the width of chars for
286
// modelToView calls. But this should be faster anyway, as we
287
// short-circuit and do only one modelToView() for one offset.
290
Shape s = view.modelToView(offs0, bounds,
291
Position.Bias.Forward);
292
Rectangle r = s.getBounds();
293
g.drawLine(r.x, r.y, r.x, r.y+r.height);
295
} catch (BadLocationException ble) {
296
ble.printStackTrace(); // Never happens
301
// Contained in view, can just use bounds.
302
if (offs0==view.getStartOffset() && offs1==view.getEndOffset()) {
305
if (bounds instanceof Rectangle)
306
alloc = (Rectangle)bounds;
308
alloc = bounds.getBounds();
310
g2d.fillRect(alloc.x, alloc.y, alloc.width, alloc.height);
312
// Restore state from before translucency if necessary.
314
g2d.setComposite(originalComposite);
320
// Should only render part of View.
325
Shape shape = view.modelToView(offs0, Position.Bias.Forward,
326
offs1,Position.Bias.Backward,
328
Rectangle r = (shape instanceof Rectangle) ?
329
(Rectangle)shape : shape.getBounds();
331
g2d.fillRoundRect(r.x,r.y, r.width,r.height, ARCWIDTH,
335
g2d.fillRect(r.x, r.y, r.width, r.height);
338
// Restore state from before translucency if necessary.
340
g2d.setComposite(originalComposite);
344
} catch (BadLocationException ble) {
345
ble.printStackTrace();
347
// Restore state from before translucency if necessary.
349
g2d.setComposite(originalComposite);
361
* Deserializes a painter.
363
* @param s The stream to read from.
364
* @throws ClassNotFoundException
365
* @throws IOException
367
private void readObject(ObjectInputStream s)
368
throws ClassNotFoundException, IOException {
369
s.defaultReadObject();
370
// We cheat and always serialize the Paint as a Color. "-1" means
371
// no Paint (i.e. use system selection color when painting).
372
int rgb = s.readInt();
373
paint = rgb==-1 ? null : new Color(rgb);
374
alphaComposite = null; // Keep FindBugs happy. This will get set later
379
* Sets the alpha value used in rendering highlights. If this value is
380
* <code>1.0f</code> (the default), the highlights are rendered completely
381
* opaque. This behavior matches that of
382
* <code>DefaultHighlightPainter</code> and imposes no performance hit. If
383
* this value is below <code>1.0f</code>, it represents how opaque the
384
* highlight will be. There will be a small performance hit for values
385
* less than <code>1.0f</code>.
387
* @param alpha The new alpha value to use for transparency.
390
public void setAlpha(float alpha) {
392
this.alpha = Math.max(alpha, 0.0f);
393
this.alpha = Math.min(1.0f, alpha);
394
alphaComposite = null; // So it is recreated with new alpha.
399
* Sets the <code>Paint</code> (usually a <code>java.awt.Color</code>)
400
* used to paint this highlight.
402
* @param paint The new <code>Paint</code>.
405
public void setPaint(Paint paint) {
411
* Sets whether rounded edges are used when painting this highlight.
413
* @param rounded Whether rounded edges should be used.
414
* @see #getRoundedEdges
416
public void setRoundedEdges(boolean rounded) {
417
roundedEdges = rounded;
422
* Serializes this painter.
424
* @param s The stream to write to.
425
* @throws IOException If an IO error occurs.
427
private void writeObject(ObjectOutputStream s) throws IOException {
428
s.defaultWriteObject();
429
int rgb = -1; // No Paint -> Use JTextComponent's selection color
431
// NOTE: We cheat and always serialize the Paint as a Color.
432
// This is (practically) always the case anyway.
433
Color c = (paint instanceof Color) ? ((Color)paint) :
434
SystemColor.textHighlight;
b'\\ No newline at end of file'