PageRenderTime 101ms CodeModel.GetById 90ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 316 lines | 195 code | 39 blank | 82 comment | 57 complexity | d5b6d97b0cde164f742778d1c8ea40bf 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.*;
 31import java.util.ArrayList;
 32import org.gjt.sp.jedit.syntax.*;
 33import org.gjt.sp.jedit.Buffer;
 34import org.gjt.sp.util.Log;
 35//}}}
 36
 37/**
 38 * A syntax token with extra information required for painting it
 39 * on screen.
 40 * @since jEdit 4.1pre1
 41 */
 42public class Chunk extends Token
 43{
 44	//{{{ paintChunkList() method
 45	/**
 46	 * Paints a chunk list.
 47	 * @param lineText The line text
 48	 * @param chunks The chunk list
 49	 * @param gfx The graphics context
 50	 * @param x The x co-ordinate
 51	 * @param y The y co-ordinate
 52	 * @param background The background color of the painting area,
 53	 * used for the background color hack
 54	 * @return The width of the painted text
 55	 * @since jEdit 4.1pre1
 56	 */
 57	public static float paintChunkList(Segment lineText, Chunk chunks,
 58		Graphics2D gfx, float x, float y, Color background,
 59		boolean glyphVector)
 60	{
 61		FontMetrics forBackground = gfx.getFontMetrics();
 62
 63		float _x = 0.0f;
 64
 65		for(;;)
 66		{
 67			if(chunks == null)
 68				return _x;
 69
 70			//{{{ find run of chunks with the same token type
 71			Chunk start = chunks;
 72			float width = 0.0f;
 73			int length = 0;
 74			while(chunks != null
 75				&& start.style == chunks.style
 76				&& (start.visible == chunks.visible)
 77				&& (start.accessable == chunks.accessable))
 78			{
 79				length += chunks.length;
 80				width += chunks.width;
 81				chunks = (Chunk)chunks.next;
 82			} //}}}
 83
 84			// Useful for debugging purposes
 85			//gfx.draw(new Rectangle2D.Float(x + _x,y - 10,
 86			//	width,10));
 87
 88			if(start.accessable)
 89			{
 90				//{{{ Paint token background color if necessary
 91				Color bgColor = start.style.getBackgroundColor();
 92				if(bgColor != null)
 93				{
 94					// Workaround for bug in Graphics2D in
 95					// JDK1.4 under Windows; calling
 96					// setPaintMode() does not reset
 97					// graphics mode.
 98					Graphics2D xorGfx = (Graphics2D)gfx.create();
 99					xorGfx.setXORMode(background);
100					xorGfx.setColor(bgColor);
101
102					xorGfx.fill(new Rectangle2D.Float(
103						x + _x,y - forBackground.getAscent(),
104						_x + width - _x,forBackground.getHeight()));
105
106					xorGfx.dispose();
107				} //}}}
108
109				//{{{ If there is text in this chunk, paint it
110				if(start.visible)
111				{
112					gfx.setFont(start.style.getFont());
113					gfx.setColor(start.style.getForegroundColor());
114
115					if(glyphVector && start.gv != null
116						&& start.next == chunks)
117						gfx.drawGlyphVector(start.gv,x + _x,y);
118					else
119					{
120						gfx.drawChars(lineText.array,
121							lineText.offset
122							+ start.offset,length,
123							(int)(x + _x),(int)y);
124					}
125				} //}}}
126			}
127
128			_x += width;
129		}
130
131		// for return statement see top of for() loop...
132	} //}}}
133
134	//{{{ offsetToX() method
135	/**
136	 * Converts an offset in a chunk list into an x co-ordinate.
137	 * @param chunks The chunk list
138	 * @param offset The offset
139	 * @since jEdit 4.1pre1
140	 */
141	public static float offsetToX(Chunk chunks, int offset)
142	{
143		if(chunks != null && offset < chunks.offset)
144		{
145			throw new ArrayIndexOutOfBoundsException(offset + " < "
146				+ chunks.offset);
147		}
148
149		float x = 0.0f;
150
151		while(chunks != null)
152		{
153			if(chunks.accessable && offset < chunks.offset + chunks.length)
154				return x + chunks.offsetToX(offset - chunks.offset);
155
156			x += chunks.width;
157			chunks = (Chunk)chunks.next;
158		}
159
160		return x;
161	} //}}}
162
163	//{{{ xToOffset() method
164	/**
165	 * Converts an x co-ordinate in a chunk list into an offset.
166	 * @param chunks The chunk list
167	 * @param x The x co-ordinate
168	 * @param round Round up to next letter if past the middle of a letter?
169	 * @return The offset within the line, or -1 if the x co-ordinate is too
170	 * far to the right
171	 * @since jEdit 4.1pre1
172	 */
173	public static int xToOffset(Chunk chunks, float x, boolean round)
174	{
175		float _x = 0.0f;
176
177		while(chunks != null)
178		{
179			if(chunks.accessable && x < _x + chunks.width)
180				return chunks.xToOffset(x - _x,round);
181
182			_x += chunks.width;
183			chunks = (Chunk)chunks.next;
184		}
185
186		return -1;
187	} //}}}
188
189	//{{{ Instance variables
190	public boolean accessable;
191	public boolean visible;
192
193	public boolean monospaced;
194	public float charWidth;
195
196	// set up after init()
197	public SyntaxStyle style;
198	public float width;
199	public GlyphVector gv;
200	//}}}
201
202	//{{{ Chunk constructor
203	public Chunk(float width, int offset, ParserRuleSet rules)
204	{
205		super(Token.NULL,offset,0,rules);
206		this.width = width;
207	} //}}}
208
209	//{{{ Chunk constructor
210	public Chunk(byte id, int offset, int length, ParserRuleSet rules)
211	{
212		super(id,offset,length,rules);
213		accessable = true;
214	} //}}}
215
216	//{{{ getPositions() method
217	public final float[] getPositions()
218	{
219		if(gv == null)
220			return null;
221
222		if(positions == null)
223			positions = gv.getGlyphPositions(0,length,null);
224
225		return positions;
226	} //}}}
227
228	//{{{ offsetToX() method
229	public final float offsetToX(int offset)
230	{
231		if(!visible)
232			return 0.0f;
233		else if(monospaced)
234			return offset * charWidth;
235		else
236			return getPositions()[offset * 2];
237	} //}}}
238
239	//{{{ xToOffset() method
240	public final int xToOffset(float x, boolean round)
241	{
242		if(!visible)
243		{
244			if(round && width - x < x)
245				return offset + length;
246			else
247				return offset;
248		}
249		else if(monospaced)
250		{
251			x = Math.max(0,x);
252			float remainder = x % charWidth;
253			int i = (int)(x / charWidth);
254			if(round && remainder > charWidth / 2)
255				return offset + i + 1;
256			else
257				return offset + i;
258		}
259		else
260		{
261			float[] pos = getPositions();
262
263			for(int i = 0; i < length; i++)
264			{
265				float glyphX = pos[i*2];
266				float nextX = (i == length - 1
267					? width : pos[i*2+2]);
268
269				if(nextX > x)
270				{
271					if(!round || nextX - x > x - glyphX)
272						return offset + i;
273					else
274						return offset + i + 1;
275				}
276			}
277		}
278
279		// wtf?
280		return -1;
281	} //}}}
282
283	//{{{ init() method
284	public void init(Segment seg, TabExpander expander, float x,
285		SyntaxStyle[] styles, FontRenderContext fontRenderContext,
286		byte defaultID, float charWidth)
287	{
288		style = styles[(id == Token.WHITESPACE || id == Token.TAB)
289			? defaultID : id];
290
291		if(length == 1 && seg.array[seg.offset + offset] == '\t')
292		{
293			visible = false;
294			float newX = expander.nextTabStop(x,offset + length);
295			width = newX - x;
296		}
297		else if(charWidth != 0.0f)
298		{
299			visible = monospaced = true;
300			this.charWidth = charWidth;
301			width = charWidth * length;
302		}
303		else
304		{
305			visible = true;
306			String str = new String(seg.array,seg.offset + offset,length);
307			gv = style.getFont().createGlyphVector(
308				fontRenderContext,str);
309			width = (float)gv.getLogicalBounds().getWidth();
310		}
311	} //}}}
312
313	//{{{ Private members
314	private float[] positions;
315	//}}}
316}