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