PageRenderTime 20ms CodeModel.GetById 1ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/syntax/Chunk.java

#
Java | 323 lines | 193 code | 45 blank | 85 comment | 48 complexity | 4f67871b46771ae58abcc09502751ee0 MD5 | raw file
  1/*
  2 * Chunk.java - A syntax token with extra information required for painting it
  3 * on screen
  4 * :tabSize=8:indentSize=8:noTabs=false:
  5 * :folding=explicit:collapseFolds=1:
  6 *
  7 * Copyright (C) 2001, 2002 Slava Pestov
  8 *
  9 * This program is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU General Public License
 11 * as published by the Free Software Foundation; either version 2
 12 * of the License, or any later version.
 13 *
 14 * This program is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17 * GNU General Public License for more details.
 18 *
 19 * You should have received a copy of the GNU General Public License
 20 * along with this program; if not, write to the Free Software
 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 22 */
 23
 24package org.gjt.sp.jedit.syntax;
 25
 26//{{{ Imports
 27import javax.swing.text.*;
 28import java.awt.font.*;
 29import java.awt.geom.*;
 30import java.awt.*;
 31
 32import org.gjt.sp.jedit.Debug;
 33//}}}
 34
 35/**
 36 * A syntax token with extra information required for painting it
 37 * on screen.
 38 * @since jEdit 4.1pre1
 39 */
 40public class Chunk extends Token
 41{
 42	//{{{ paintChunkList() method
 43	/**
 44	 * Paints a chunk list.
 45	 * @param chunks The chunk list
 46	 * @param gfx The graphics context
 47	 * @param x The x co-ordinate
 48	 * @param y The y co-ordinate
 49	 * @return The width of the painted text
 50	 * @since jEdit 4.2pre1
 51	 */
 52	public static float paintChunkList(Chunk chunks,
 53		Graphics2D gfx, float x, float y, boolean glyphVector)
 54	{
 55		Rectangle clipRect = gfx.getClipBounds();
 56
 57		float _x = 0.0f;
 58
 59		while(chunks != null)
 60		{
 61			// only paint visible chunks
 62			if(x + _x + chunks.width > clipRect.x
 63				&& x + _x < clipRect.x + clipRect.width)
 64			{
 65				// Useful for debugging purposes
 66				if(Debug.CHUNK_PAINT_DEBUG)
 67				{
 68					gfx.draw(new Rectangle2D.Float(x + _x,y - 10,
 69						chunks.width,10));
 70				}
 71
 72				if(chunks.accessable && chunks.visible)
 73				{
 74					gfx.setFont(chunks.style.getFont());
 75					gfx.setColor(chunks.style.getForegroundColor());
 76
 77					if(glyphVector && chunks.gv != null)
 78						gfx.drawGlyphVector(chunks.gv,x + _x,y);
 79					else if(chunks.str != null)
 80					{
 81						gfx.drawString(chunks.str,
 82							(int)(x + _x),(int)y);
 83					}
 84				}
 85			}
 86
 87			_x += chunks.width;
 88			chunks = (Chunk)chunks.next;
 89		}
 90
 91		return _x;
 92	} //}}}
 93
 94	//{{{ paintChunkBackgrounds() method
 95	/**
 96	 * Paints the background highlights of a chunk list.
 97	 * @param chunks The chunk list
 98	 * @param gfx The graphics context
 99	 * @param x The x co-ordinate
100	 * @param y The y co-ordinate
101	 * @return The width of the painted backgrounds
102	 * @since jEdit 4.2pre1
103	 */
104	public static float paintChunkBackgrounds(Chunk chunks,
105		Graphics2D gfx, float x, float y)
106	{
107		Rectangle clipRect = gfx.getClipBounds();
108
109		float _x = 0.0f;
110
111		FontMetrics forBackground = gfx.getFontMetrics();
112
113		int ascent = forBackground.getAscent();
114		int height = forBackground.getHeight();
115
116		while(chunks != null)
117		{
118			// only paint visible chunks
119			if(x + _x + chunks.width > clipRect.x
120				&& x + _x < clipRect.x + clipRect.width)
121			{
122				if(chunks.accessable)
123				{
124					//{{{ Paint token background color if necessary
125					Color bgColor = chunks.background;
126					if(bgColor != null)
127					{
128						gfx.setColor(bgColor);
129
130						gfx.fill(new Rectangle2D.Float(
131							x + _x,y - ascent,
132							_x + chunks.width - _x,
133							height));
134					} //}}}
135				}
136			}
137
138			_x += chunks.width;
139			chunks = (Chunk)chunks.next;
140		}
141
142		return _x;
143	} //}}}
144
145	//{{{ offsetToX() method
146	/**
147	 * Converts an offset in a chunk list into an x co-ordinate.
148	 * @param chunks The chunk list
149	 * @param offset The offset
150	 * @since jEdit 4.1pre1
151	 */
152	public static float offsetToX(Chunk chunks, int offset)
153	{
154		if(chunks != null && offset < chunks.offset)
155		{
156			throw new ArrayIndexOutOfBoundsException(offset + " < "
157				+ chunks.offset);
158		}
159
160		float x = 0.0f;
161
162		while(chunks != null)
163		{
164			if(chunks.accessable && offset < chunks.offset + chunks.length)
165				return x + chunks.offsetToX(offset - chunks.offset);
166
167			x += chunks.width;
168			chunks = (Chunk)chunks.next;
169		}
170
171		return x;
172	} //}}}
173
174	//{{{ xToOffset() method
175	/**
176	 * Converts an x co-ordinate in a chunk list into an offset.
177	 * @param chunks The chunk list
178	 * @param x The x co-ordinate
179	 * @param round Round up to next letter if past the middle of a letter?
180	 * @return The offset within the line, or -1 if the x co-ordinate is too
181	 * far to the right
182	 * @since jEdit 4.1pre1
183	 */
184	public static int xToOffset(Chunk chunks, float x, boolean round)
185	{
186		float _x = 0.0f;
187
188		while(chunks != null)
189		{
190			if(chunks.accessable && x < _x + chunks.width)
191				return chunks.xToOffset(x - _x,round);
192
193			_x += chunks.width;
194			chunks = (Chunk)chunks.next;
195		}
196
197		return -1;
198	} //}}}
199
200	//{{{ Instance variables
201	public boolean accessable;
202	public boolean visible;
203	public boolean initialized;
204
205	// set up after init()
206	public SyntaxStyle style;
207	// this is either style.getBackgroundColor() or
208	// styles[defaultID].getBackgroundColor()
209	public Color background;
210	public float width;
211	public GlyphVector gv;
212	public String str;
213	//}}}
214
215	//{{{ Chunk constructor
216	public Chunk(float width, int offset, ParserRuleSet rules)
217	{
218		super(Token.NULL,offset,0,rules);
219		this.width = width;
220	} //}}}
221
222	//{{{ Chunk constructor
223	public Chunk(byte id, int offset, int length, ParserRuleSet rules,
224		SyntaxStyle[] styles, byte defaultID)
225	{
226		super(id,offset,length,rules);
227		accessable = true;
228		style = styles[id];
229		background = style.getBackgroundColor();
230		if(background == null)
231			background = styles[defaultID].getBackgroundColor();
232	} //}}}
233
234	//{{{ getPositions() method
235	public final float[] getPositions()
236	{
237		if(gv == null)
238			return null;
239
240		if(positions == null)
241			positions = gv.getGlyphPositions(0,length,null);
242
243		return positions;
244	} //}}}
245
246	//{{{ offsetToX() method
247	public final float offsetToX(int offset)
248	{
249		if(!visible)
250			return 0.0f;
251		else
252			return getPositions()[offset * 2];
253	} //}}}
254
255	//{{{ xToOffset() method
256	public final int xToOffset(float x, boolean round)
257	{
258		if(!visible)
259		{
260			if(round && width - x < x)
261				return offset + length;
262			else
263				return offset;
264		}
265		else
266		{
267			float[] pos = getPositions();
268
269			for(int i = 0; i < length; i++)
270			{
271				float glyphX = pos[i*2];
272				float nextX = (i == length - 1
273					? width : pos[i*2+2]);
274
275				if(nextX > x)
276				{
277					if(!round || nextX - x > x - glyphX)
278						return offset + i;
279					else
280						return offset + i + 1;
281				}
282			}
283		}
284
285		// wtf?
286		return -1;
287	} //}}}
288
289	//{{{ init() method
290	public void init(Segment seg, TabExpander expander, float x,
291		FontRenderContext fontRenderContext)
292	{
293		initialized = true;
294
295		if(!accessable)
296		{
297			// do nothing
298		}
299		else if(length == 1 && seg.array[seg.offset + offset] == '\t')
300		{
301			visible = false;
302			float newX = expander.nextTabStop(x,offset + length);
303			width = newX - x;
304		}
305		else
306		{
307			visible = true;
308
309			str = new String(seg.array,seg.offset + offset,length);
310			
311			Rectangle2D logicalBounds;
312			gv = style.getFont().createGlyphVector(
313				fontRenderContext, str);
314			logicalBounds = gv.getLogicalBounds();
315
316			width = (float)logicalBounds.getWidth();
317		}
318	} //}}}
319
320	//{{{ Private members
321	private float[] positions;
322	//}}}
323}