KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > graphics > Path


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.graphics;
12
13 import org.eclipse.swt.*;
14 import org.eclipse.swt.internal.gdip.*;
15 import org.eclipse.swt.internal.win32.*;
16
17 /**
18  * Instances of this class represent paths through the two-dimensional
19  * coordinate system. Paths do not have to be continuous, and can be
20  * described using lines, rectangles, arcs, cubic or quadratic bezier curves,
21  * glyphs, or other paths.
22  * <p>
23  * Application code must explicitly invoke the <code>Path.dispose()</code>
24  * method to release the operating system resources managed by each instance
25  * when those instances are no longer required.
26  * </p>
27  * <p>
28  * This class requires the operating system's advanced graphics subsystem
29  * which may not be available on some platforms.
30  * </p>
31  *
32  * @since 3.1
33  */

34 public class Path extends Resource {
35     
36     /**
37      * the OS resource for the Path
38      * (Warning: This field is platform dependent)
39      * <p>
40      * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
41      * public API. It is marked public only so that it can be shared
42      * within the packages provided by SWT. It is not available on all
43      * platforms and should never be accessed from application code.
44      * </p>
45      */

46     public int handle;
47     
48     PointF currentPoint = new PointF(), startPoint = new PointF();
49     
50 /**
51  * Constructs a new empty Path.
52  * <p>
53  * This operation requires the operating system's advanced
54  * graphics subsystem which may not be available on some
55  * platforms.
56  * </p>
57  *
58  * @param device the device on which to allocate the path
59  *
60  * @exception IllegalArgumentException <ul>
61  * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device</li>
62  * </ul>
63  * @exception SWTException <ul>
64  * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
65  * </ul>
66  * @exception SWTError <ul>
67  * <li>ERROR_NO_HANDLES if a handle for the path could not be obtained</li>
68  * </ul>
69  *
70  * @see #dispose()
71  */

72 public Path (Device device) {
73     if (device == null) device = Device.getDevice();
74     if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
75     this.device = device;
76     device.checkGDIP();
77     handle = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
78     if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
79     if (device.tracking) device.new_Object(this);
80 }
81
82 /**
83  * Adds to the receiver a circular or elliptical arc that lies within
84  * the specified rectangular area.
85  * <p>
86  * The resulting arc begins at <code>startAngle</code> and extends
87  * for <code>arcAngle</code> degrees.
88  * Angles are interpreted such that 0 degrees is at the 3 o'clock
89  * position. A positive value indicates a counter-clockwise rotation
90  * while a negative value indicates a clockwise rotation.
91  * </p><p>
92  * The center of the arc is the center of the rectangle whose origin
93  * is (<code>x</code>, <code>y</code>) and whose size is specified by the
94  * <code>width</code> and <code>height</code> arguments.
95  * </p><p>
96  * The resulting arc covers an area <code>width + 1</code> pixels wide
97  * by <code>height + 1</code> pixels tall.
98  * </p>
99  *
100  * @param x the x coordinate of the upper-left corner of the arc
101  * @param y the y coordinate of the upper-left corner of the arc
102  * @param width the width of the arc
103  * @param height the height of the arc
104  * @param startAngle the beginning angle
105  * @param arcAngle the angular extent of the arc, relative to the start angle
106  *
107  * @exception SWTException <ul>
108  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
109  * </ul>
110  */

111 public void addArc(float x, float y, float width, float height, float startAngle, float arcAngle) {
112     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
113     if (width < 0) {
114         x = x + width;
115         width = -width;
116     }
117     if (height < 0) {
118         y = y + height;
119         height = -height;
120     }
121     if (width == 0 || height == 0 || arcAngle == 0) return;
122     if (width == height) {
123         Gdip.GraphicsPath_AddArc(handle, x, y, width, height, -startAngle, -arcAngle);
124     } else {
125         int path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
126         if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES);
127         int matrix = Gdip.Matrix_new(width, 0, 0, height, x, y);
128         if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES);
129         Gdip.GraphicsPath_AddArc(path, 0, 0, 1, 1, -startAngle, -arcAngle);
130         Gdip.GraphicsPath_Transform(path, matrix);
131         Gdip.GraphicsPath_AddPath(handle, path, true);
132         Gdip.Matrix_delete(matrix);
133         Gdip.GraphicsPath_delete(path);
134     }
135     Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
136 }
137
138 /**
139  * Adds to the receiver the path described by the parameter.
140  *
141  * @param path the path to add to the receiver
142  *
143  * @exception IllegalArgumentException <ul>
144  * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
145  * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
146  * </ul>
147  * @exception SWTException <ul>
148  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
149  * </ul>
150  */

151 public void addPath(Path path) {
152     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
153     if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
154     if (path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
155     //TODO - expose connect?
156
Gdip.GraphicsPath_AddPath(handle, path.handle, false);
157     currentPoint.X = path.currentPoint.X;
158     currentPoint.Y = path.currentPoint.Y;
159 }
160
161 /**
162  * Adds to the receiver the rectangle specified by x, y, width and height.
163  *
164  * @param x the x coordinate of the rectangle to add
165  * @param y the y coordinate of the rectangle to add
166  * @param width the width of the rectangle to add
167  * @param height the height of the rectangle to add
168  *
169  * @exception SWTException <ul>
170  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
171  * </ul>
172  */

173 public void addRectangle(float x, float y, float width, float height) {
174     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
175     RectF rect = new RectF();
176     rect.X = x;
177     rect.Y = y;
178     rect.Width = width;
179     rect.Height = height;
180     Gdip.GraphicsPath_AddRectangle(handle, rect);
181     currentPoint.X = x;
182     currentPoint.Y = y;
183 }
184
185 /**
186  * Adds to the receiver the pattern of glyphs generated by drawing
187  * the given string using the given font starting at the point (x, y).
188  *
189  * @param string the text to use
190  * @param x the x coordinate of the starting point
191  * @param y the y coordinate of the starting point
192  * @param font the font to use
193  *
194  * @exception IllegalArgumentException <ul>
195  * <li>ERROR_NULL_ARGUMENT - if the font is null</li>
196  * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
197  * </ul>
198  * @exception SWTException <ul>
199  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
200  * </ul>
201  */

202 public void addString(String JavaDoc string, float x, float y, Font font) {
203     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
204     if (font == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
205     if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
206     int length = string.length();
207     char[] buffer = new char[length];
208     string.getChars(0, length, buffer, 0);
209     int hDC = device.internal_new_GC(null);
210     int gdipFont = GC.createGdipFont(hDC, font.handle);
211     PointF point = new PointF();
212     point.X = x - (Gdip.Font_GetSize(gdipFont) / 6);
213     point.Y = y;
214     int family = Gdip.FontFamily_new();
215     Gdip.Font_GetFamily(gdipFont, family);
216     int style = Gdip.Font_GetStyle(gdipFont);
217     float size = Gdip.Font_GetSize(gdipFont);
218     Gdip.GraphicsPath_AddString(handle, buffer, length, family, style, size, point, 0);
219     Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
220     Gdip.FontFamily_delete(family);
221     Gdip.Font_delete(gdipFont);
222     device.internal_dispose_GC(hDC, null);
223 }
224
225 /**
226  * Closes the current sub path by adding to the receiver a line
227  * from the current point of the path back to the starting point
228  * of the sub path.
229  *
230  * @exception SWTException <ul>
231  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
232  * </ul>
233  */

234 public void close() {
235     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
236     Gdip.GraphicsPath_CloseFigure(handle);
237     /*
238     * Feature in GDI+. CloseFigure() does affect the last
239     * point, so GetLastPoint() does not return the starting
240     * point of the subpath after calling CloseFigure(). The
241     * fix is to remember the subpath starting point and use
242     * it instead.
243     */

244     currentPoint.X = startPoint.X;
245     currentPoint.Y = startPoint.Y;
246 }
247
248 /**
249  * Returns <code>true</code> if the specified point is contained by
250  * the receiver and false otherwise.
251  * <p>
252  * If outline is <code>true</code>, the point (x, y) checked for containment in
253  * the receiver's outline. If outline is <code>false</code>, the point is
254  * checked to see if it is contained within the bounds of the (closed) area
255  * covered by the receiver.
256  *
257  * @param x the x coordinate of the point to test for containment
258  * @param y the y coordinate of the point to test for containment
259  * @param gc the GC to use when testing for containment
260  * @param outline controls whether to check the outline or contained area of the path
261  * @return <code>true</code> if the path contains the point and <code>false</code> otherwise
262  *
263  * @exception IllegalArgumentException <ul>
264  * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
265  * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li>
266  * </ul>
267  * @exception SWTException <ul>
268  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
269  * </ul>
270  */

271 public boolean contains(float x, float y, GC gc, boolean outline) {
272     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
273     if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
274     if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
275     //TODO - should use GC transformation
276
gc.initGdip();
277     gc.checkGC(GC.LINE_CAP | GC.LINE_JOIN | GC.LINE_STYLE | GC.LINE_WIDTH);
278     int mode = OS.GetPolyFillMode(gc.handle) == OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate;
279     Gdip.GraphicsPath_SetFillMode(handle, mode);
280     if (outline) {
281         return Gdip.GraphicsPath_IsOutlineVisible(handle, x, y, gc.data.gdipPen, gc.data.gdipGraphics);
282     } else {
283         return Gdip.GraphicsPath_IsVisible(handle, x, y, gc.data.gdipGraphics);
284     }
285 }
286
287 /**
288  * Adds to the receiver a cubic bezier curve based on the parameters.
289  *
290  * @param cx1 the x coordinate of the first control point of the spline
291  * @param cy1 the y coordinate of the first control of the spline
292  * @param cx2 the x coordinate of the second control of the spline
293  * @param cy2 the y coordinate of the second control of the spline
294  * @param x the x coordinate of the end point of the spline
295  * @param y the y coordinate of the end point of the spline
296  *
297  * @exception SWTException <ul>
298  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
299  * </ul>
300  */

301 public void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) {
302     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
303     Gdip.GraphicsPath_AddBezier(handle, currentPoint.X, currentPoint.Y, cx1, cy1, cx2, cy2, x, y);
304     Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
305 }
306
307 /**
308  * Disposes of the operating system resources associated with
309  * the Path. Applications must dispose of all Paths that
310  * they allocate.
311  */

312 public void dispose() {
313     if (handle == 0) return;
314     if (device.isDisposed()) return;
315     Gdip.GraphicsPath_delete(handle);
316     handle = 0;
317     if (device.tracking) device.dispose_Object(this);
318     device = null;
319 }
320
321 /**
322  * Replaces the first four elements in the parameter with values that
323  * describe the smallest rectangle that will completely contain the
324  * receiver (i.e. the bounding box).
325  *
326  * @param bounds the array to hold the result
327  *
328  * @exception IllegalArgumentException <ul>
329  * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
330  * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the bounding box</li>
331  * </ul>
332  * @exception SWTException <ul>
333  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
334  * </ul>
335  */

336 public void getBounds(float[] bounds) {
337     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
338     if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
339     if (bounds.length < 4) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
340     RectF rect = new RectF();
341     Gdip.GraphicsPath_GetBounds(handle, rect, 0, 0);
342     bounds[0] = rect.X;
343     bounds[1] = rect.Y;
344     bounds[2] = rect.Width;
345     bounds[3] = rect.Height;
346 }
347
348 /**
349  * Replaces the first two elements in the parameter with values that
350  * describe the current point of the path.
351  *
352  * @param point the array to hold the result
353  *
354  * @exception IllegalArgumentException <ul>
355  * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
356  * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the end point</li>
357  * </ul>
358  * @exception SWTException <ul>
359  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
360  * </ul>
361  */

362 public void getCurrentPoint(float[] point) {
363     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
364     if (point == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
365     if (point.length < 2) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
366     point[0] = currentPoint.X;
367     point[1] = currentPoint.Y;
368 }
369
370 /**
371  * Returns a device independent representation of the receiver.
372  *
373  * @return the PathData for the receiver
374  *
375  * @exception SWTException <ul>
376  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
377  * </ul>
378  *
379  * @see PathData
380  */

381 public PathData getPathData() {
382     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
383     int count = Gdip.GraphicsPath_GetPointCount(handle);
384     byte[] gdipTypes = new byte[count];
385     float[] points = new float[count * 2];
386     Gdip.GraphicsPath_GetPathTypes(handle, gdipTypes, count);
387     Gdip.GraphicsPath_GetPathPoints(handle, points, count);
388     byte[] types = new byte[count * 2];
389     int index = 0, typesIndex = 0;
390     while (index < count) {
391         byte type = gdipTypes[index];
392         boolean close = false;
393         switch (type & Gdip.PathPointTypePathTypeMask) {
394             case Gdip.PathPointTypeStart:
395                 types[typesIndex++] = SWT.PATH_MOVE_TO;
396                 close = (type & Gdip.PathPointTypeCloseSubpath) != 0;
397                 index += 1;
398                 break;
399             case Gdip.PathPointTypeLine:
400                 types[typesIndex++] = SWT.PATH_LINE_TO;
401                 close = (type & Gdip.PathPointTypeCloseSubpath) != 0;
402                 index += 1;
403                 break;
404             case Gdip.PathPointTypeBezier:
405                 types[typesIndex++] = SWT.PATH_CUBIC_TO;
406                 close = (gdipTypes[index + 2] & Gdip.PathPointTypeCloseSubpath) != 0;
407                 index += 3;
408                 break;
409             default:
410                 index++;
411         }
412         if (close) {
413             types[typesIndex++] = SWT.PATH_CLOSE;
414         }
415     }
416     if (typesIndex != types.length) {
417         byte[] newTypes = new byte[typesIndex];
418         System.arraycopy(types, 0, newTypes, 0, typesIndex);
419         types = newTypes;
420     }
421     PathData result = new PathData();
422     result.types = types;
423     result.points = points;
424     return result;
425 }
426
427 /**
428  * Adds to the receiver a line from the current point to
429  * the point specified by (x, y).
430  *
431  * @param x the x coordinate of the end of the line to add
432  * @param y the y coordinate of the end of the line to add
433  *
434  * @exception SWTException <ul>
435  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
436  * </ul>
437  */

438 public void lineTo(float x, float y) {
439     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
440     Gdip.GraphicsPath_AddLine(handle, currentPoint.X, currentPoint.Y, x, y);
441     Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
442 }
443
444 /**
445  * Returns <code>true</code> if the Path has been disposed,
446  * and <code>false</code> otherwise.
447  * <p>
448  * This method gets the dispose state for the Path.
449  * When a Path has been disposed, it is an error to
450  * invoke any other method using the Path.
451  *
452  * @return <code>true</code> when the Path is disposed, and <code>false</code> otherwise
453  */

454 public boolean isDisposed() {
455     return handle == 0;
456 }
457
458 /**
459  * Sets the current point of the receiver to the point
460  * specified by (x, y). Note that this starts a new
461  * sub path.
462  *
463  * @param x the x coordinate of the new end point
464  * @param y the y coordinate of the new end point
465  *
466  * @exception SWTException <ul>
467  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
468  * </ul>
469  */

470 public void moveTo(float x, float y) {
471     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
472     Gdip.GraphicsPath_StartFigure(handle);
473     currentPoint.X = startPoint.X = x;
474     currentPoint.Y = startPoint.Y = y;
475 }
476
477 /**
478  * Adds to the receiver a quadratic curve based on the parameters.
479  *
480  * @param cx the x coordinate of the control point of the spline
481  * @param cy the y coordinate of the control point of the spline
482  * @param x the x coordinate of the end point of the spline
483  * @param y the y coordinate of the end point of the spline
484  *
485  * @exception SWTException <ul>
486  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
487  * </ul>
488  */

489 public void quadTo(float cx, float cy, float x, float y) {
490     if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
491     float cx1 = currentPoint.X + 2 * (cx - currentPoint.X) / 3;
492     float cy1 = currentPoint.Y + 2 * (cy - currentPoint.Y) / 3;
493     float cx2 = cx1 + (x - currentPoint.X) / 3;
494     float cy2 = cy1 + (y - currentPoint.Y) / 3;
495     Gdip.GraphicsPath_AddBezier(handle, currentPoint.X, currentPoint.Y, cx1, cy1, cx2, cy2, x, y);
496     Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
497 }
498
499 /**
500  * Returns a string containing a concise, human-readable
501  * description of the receiver.
502  *
503  * @return a string representation of the receiver
504  */

505 public String JavaDoc toString() {
506     if (isDisposed()) return "Path {*DISPOSED*}";
507     return "Path {" + handle + "}";
508 }
509
510 }
511
Popular Tags