1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 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 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.graphics.Region; 14 15 import java.lang.all; 16 17 18 import org.eclipse.swt.SWT; 19 import org.eclipse.swt.graphics.Resource; 20 import org.eclipse.swt.graphics.Point; 21 import org.eclipse.swt.graphics.Rectangle; 22 import org.eclipse.swt.graphics.Device; 23 import org.eclipse.swt.internal.gtk.OS; 24 25 26 /** 27 * Instances of this class represent areas of an x-y coordinate 28 * system that are aggregates of the areas covered by a number 29 * of polygons. 30 * <p> 31 * Application code must explicitly invoke the <code>Region.dispose()</code> 32 * method to release the operating system resources managed by each instance 33 * when those instances are no longer required. 34 * </p> 35 * 36 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a> 37 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 38 */ 39 public final class Region : Resource { 40 /** 41 * the OS resource for the region 42 * (Warning: This field is platform dependent) 43 * <p> 44 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT 45 * public API. It is marked public only so that it can be shared 46 * within the packages provided by SWT. It is not available on all 47 * platforms and should never be accessed from application code. 48 * </p> 49 */ 50 public GdkRegion* handle; 51 52 /** 53 * Constructs a new empty region. 54 * 55 * @exception SWTError <ul> 56 * <li>ERROR_NO_HANDLES if a handle could not be obtained for region creation</li> 57 * </ul> 58 */ 59 public this() { 60 this(null); 61 } 62 63 /** 64 * Constructs a new empty region. 65 * <p> 66 * You must dispose the region when it is no longer required. 67 * </p> 68 * 69 * @param device the device on which to allocate the region 70 * 71 * @exception IllegalArgumentException <ul> 72 * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> 73 * </ul> 74 * @exception SWTError <ul> 75 * <li>ERROR_NO_HANDLES if a handle could not be obtained for region creation</li> 76 * </ul> 77 * 78 * @see #dispose 79 * 80 * @since 3.0 81 */ 82 public this(Device device) { 83 super(device); 84 handle = OS.gdk_region_new(); 85 if (handle is null) SWT.error(SWT.ERROR_NO_HANDLES); 86 init_(); 87 } 88 89 this(Device device, GdkRegion* handle) { 90 super(device); 91 this.handle = handle; 92 } 93 94 /** 95 * Adds the given polygon to the collection of polygons 96 * the receiver maintains to describe its area. 97 * 98 * @param pointArray points that describe the polygon to merge with the receiver 99 * 100 * @exception IllegalArgumentException <ul> 101 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 102 * </ul> 103 * @exception SWTException <ul> 104 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 105 * </ul> 106 * 107 * @since 3.0 108 * 109 */ 110 public void add (int[] pointArray) { 111 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 112 if (pointArray is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 113 /* 114 * Bug in GTK. If gdk_region_polygon() is called with one point, 115 * it segment faults. The fix is to make sure that it is called 116 * with enough points for a polygon. 117 */ 118 if (pointArray.length < 6) return; 119 auto polyRgn = OS.gdk_region_polygon(cast(GdkPoint*)pointArray.ptr, 120 cast(int)/*64bit*/pointArray.length / 2, OS.GDK_EVEN_ODD_RULE); 121 OS.gdk_region_union(handle, polyRgn); 122 OS.gdk_region_destroy(polyRgn); 123 } 124 125 /** 126 * Adds the given rectangle to the collection of polygons 127 * the receiver maintains to describe its area. 128 * 129 * @param rect the rectangle to merge with the receiver 130 * 131 * @exception IllegalArgumentException <ul> 132 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 133 * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> 134 * </ul> 135 * @exception SWTException <ul> 136 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 137 * </ul> 138 */ 139 public void add(Rectangle rect) { 140 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 141 if (rect is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 142 add (rect.x, rect.y, rect.width, rect.height); 143 } 144 145 /** 146 * Adds the given rectangle to the collection of polygons 147 * the receiver maintains to describe its area. 148 * 149 * @param x the x coordinate of the rectangle 150 * @param y the y coordinate of the rectangle 151 * @param width the width coordinate of the rectangle 152 * @param height the height coordinate of the rectangle 153 * 154 * @exception IllegalArgumentException <ul> 155 * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> 156 * </ul> 157 * @exception SWTException <ul> 158 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 159 * </ul> 160 * 161 * @since 3.1 162 */ 163 public void add(int x, int y, int width, int height) { 164 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 165 if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 166 GdkRectangle* gdkRect = new GdkRectangle(); 167 gdkRect.x = x; 168 gdkRect.y = y; 169 gdkRect.width = width; 170 gdkRect.height = height; 171 OS.gdk_region_union_with_rect(handle, gdkRect); 172 } 173 174 /** 175 * Adds all of the polygons which make up the area covered 176 * by the argument to the collection of polygons the receiver 177 * maintains to describe its area. 178 * 179 * @param region the region to merge 180 * 181 * @exception IllegalArgumentException <ul> 182 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 183 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 184 * </ul> 185 * @exception SWTException <ul> 186 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 187 * </ul> 188 */ 189 public void add(Region region) { 190 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 191 if (region is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 192 if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 193 OS.gdk_region_union(handle, region.handle); 194 } 195 196 /** 197 * Returns <code>true</code> if the point specified by the 198 * arguments is inside the area specified by the receiver, 199 * and <code>false</code> otherwise. 200 * 201 * @param x the x coordinate of the point to test for containment 202 * @param y the y coordinate of the point to test for containment 203 * @return <code>true</code> if the region contains the point and <code>false</code> otherwise 204 * 205 * @exception SWTException <ul> 206 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 207 * </ul> 208 */ 209 public bool contains(int x, int y) { 210 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 211 return cast(bool)OS.gdk_region_point_in(handle, x, y); 212 } 213 214 /** 215 * Returns <code>true</code> if the given point is inside the 216 * area specified by the receiver, and <code>false</code> 217 * otherwise. 218 * 219 * @param pt the point to test for containment 220 * @return <code>true</code> if the region contains the point and <code>false</code> otherwise 221 * 222 * @exception IllegalArgumentException <ul> 223 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 224 * </ul> 225 * @exception SWTException <ul> 226 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 227 * </ul> 228 */ 229 public bool contains(Point pt) { 230 if (pt is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 231 return contains(pt.x, pt.y); 232 } 233 234 override 235 void destroy() { 236 OS.gdk_region_destroy(handle); 237 handle = null; 238 } 239 240 /** 241 * Compares the argument to the receiver, and returns true 242 * if they represent the <em>same</em> object using a class 243 * specific comparison. 244 * 245 * @param object the object to compare with this object 246 * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise 247 * 248 * @see #hashCode 249 */ 250 public override equals_t opEquals(Object object) { 251 if (this is object) return true; 252 if ( auto region = cast(Region)object ){ 253 return handle is region.handle; 254 } 255 return false; 256 } 257 258 /** 259 * Returns a rectangle which represents the rectangular 260 * union of the collection of polygons the receiver 261 * maintains to describe its area. 262 * 263 * @return a bounding rectangle for the region 264 * 265 * @exception SWTException <ul> 266 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 267 * </ul> 268 * 269 * @see Rectangle#union 270 */ 271 public Rectangle getBounds() { 272 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 273 GdkRectangle* gdkRect = new GdkRectangle(); 274 OS.gdk_region_get_clipbox(handle, gdkRect); 275 return new Rectangle(gdkRect.x, gdkRect.y, gdkRect.width, gdkRect.height); 276 } 277 278 public static Region gtk_new(Device device, GdkRegion* handle) { 279 return new Region(device, handle); 280 } 281 282 /** 283 * Returns an integer hash code for the receiver. Any two 284 * objects that return <code>true</code> when passed to 285 * <code>equals</code> must return the same value for this 286 * method. 287 * 288 * @return the receiver's hash 289 * 290 * @see #equals 291 */ 292 public override hash_t toHash() { 293 return cast(hash_t)handle; 294 } 295 296 /** 297 * Intersects the given rectangle to the collection of polygons 298 * the receiver maintains to describe its area. 299 * 300 * @param rect the rectangle to intersect with the receiver 301 * 302 * @exception IllegalArgumentException <ul> 303 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 304 * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> 305 * </ul> 306 * @exception SWTException <ul> 307 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 308 * </ul> 309 * 310 * @since 3.0 311 */ 312 public void intersect(Rectangle rect) { 313 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 314 if (rect is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 315 intersect (rect.x, rect.y, rect.width, rect.height); 316 } 317 318 /** 319 * Intersects the given rectangle to the collection of polygons 320 * the receiver maintains to describe its area. 321 * 322 * @param x the x coordinate of the rectangle 323 * @param y the y coordinate of the rectangle 324 * @param width the width coordinate of the rectangle 325 * @param height the height coordinate of the rectangle 326 * 327 * @exception IllegalArgumentException <ul> 328 * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> 329 * </ul> 330 * @exception SWTException <ul> 331 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 332 * </ul> 333 * 334 * @since 3.1 335 */ 336 public void intersect(int x, int y, int width, int height) { 337 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 338 if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 339 GdkRectangle* gdkRect = new GdkRectangle(); 340 gdkRect.x = x; 341 gdkRect.y = y; 342 gdkRect.width = width; 343 gdkRect.height = height; 344 auto rectRgn = OS.gdk_region_rectangle(gdkRect); 345 OS.gdk_region_intersect(handle, rectRgn); 346 OS.gdk_region_destroy(rectRgn); 347 } 348 349 /** 350 * Intersects all of the polygons which make up the area covered 351 * by the argument to the collection of polygons the receiver 352 * maintains to describe its area. 353 * 354 * @param region the region to intersect 355 * 356 * @exception IllegalArgumentException <ul> 357 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 358 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 359 * </ul> 360 * @exception SWTException <ul> 361 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 362 * </ul> 363 * 364 * @since 3.0 365 */ 366 public void intersect(Region region) { 367 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 368 if (region is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 369 if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 370 OS.gdk_region_intersect(handle, region.handle); 371 } 372 373 /** 374 * Returns <code>true</code> if the rectangle described by the 375 * arguments intersects with any of the polygons the receiver 376 * maintains to describe its area, and <code>false</code> otherwise. 377 * 378 * @param x the x coordinate of the origin of the rectangle 379 * @param y the y coordinate of the origin of the rectangle 380 * @param width the width of the rectangle 381 * @param height the height of the rectangle 382 * @return <code>true</code> if the rectangle intersects with the receiver, and <code>false</code> otherwise 383 * 384 * @exception SWTException <ul> 385 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 386 * </ul> 387 * 388 * @see Rectangle#intersects(Rectangle) 389 */ 390 public bool intersects (int x, int y, int width, int height) { 391 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 392 GdkRectangle* gdkRect = new GdkRectangle(); 393 gdkRect.x = x; 394 gdkRect.y = y; 395 gdkRect.width = width; 396 gdkRect.height = height; 397 return OS.gdk_region_rect_in(handle, gdkRect) !is OS.GDK_OVERLAP_RECTANGLE_OUT; 398 } 399 /** 400 * Returns <code>true</code> if the given rectangle intersects 401 * with any of the polygons the receiver maintains to describe 402 * its area and <code>false</code> otherwise. 403 * 404 * @param rect the rectangle to test for intersection 405 * @return <code>true</code> if the rectangle intersects with the receiver, and <code>false</code> otherwise 406 * 407 * @exception IllegalArgumentException <ul> 408 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 409 * </ul> 410 * @exception SWTException <ul> 411 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 412 * </ul> 413 * 414 * @see Rectangle#intersects(Rectangle) 415 */ 416 public bool intersects(Rectangle rect) { 417 if (rect is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 418 return intersects(rect.x, rect.y, rect.width, rect.height); 419 } 420 421 /** 422 * Returns <code>true</code> if the region has been disposed, 423 * and <code>false</code> otherwise. 424 * <p> 425 * This method gets the dispose state for the region. 426 * When a region has been disposed, it is an error to 427 * invoke any other method using the region. 428 * 429 * @return <code>true</code> when the region is disposed, and <code>false</code> otherwise 430 */ 431 public override bool isDisposed() { 432 return handle is null; 433 } 434 435 /** 436 * Returns <code>true</code> if the receiver does not cover any 437 * area in the (x, y) coordinate plane, and <code>false</code> if 438 * the receiver does cover some area in the plane. 439 * 440 * @return <code>true</code> if the receiver is empty, and <code>false</code> otherwise 441 * 442 * @exception SWTException <ul> 443 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 444 * </ul> 445 */ 446 public bool isEmpty() { 447 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 448 return cast(bool)OS.gdk_region_empty(handle); 449 } 450 451 /** 452 * Subtracts the given polygon from the collection of polygons 453 * the receiver maintains to describe its area. 454 * 455 * @param pointArray points that describe the polygon to merge with the receiver 456 * 457 * @exception IllegalArgumentException <ul> 458 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 459 * </ul> 460 * @exception SWTException <ul> 461 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 462 * </ul> 463 * 464 * @since 3.0 465 */ 466 public void subtract (int[] pointArray) { 467 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 468 if (pointArray is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 469 /* 470 * Bug in GTK. If gdk_region_polygon() is called with one point, 471 * it segment faults. The fix is to make sure that it is called 472 * with enough points for a polygon. 473 */ 474 if (pointArray.length < 6) return; 475 auto polyRgn = OS.gdk_region_polygon( cast(GdkPoint*)pointArray.ptr, 476 cast(int)/*64bit*/pointArray.length / 2, OS.GDK_EVEN_ODD_RULE); 477 OS.gdk_region_subtract(handle, polyRgn); 478 OS.gdk_region_destroy(polyRgn); 479 } 480 481 /** 482 * Subtracts the given rectangle from the collection of polygons 483 * the receiver maintains to describe its area. 484 * 485 * @param rect the rectangle to subtract from the receiver 486 * 487 * @exception IllegalArgumentException <ul> 488 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 489 * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> 490 * </ul> 491 * @exception SWTException <ul> 492 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 493 * </ul> 494 * 495 * @since 3.0 496 */ 497 public void subtract(Rectangle rect) { 498 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 499 if (rect is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 500 subtract (rect.x, rect.y, rect.width, rect.height); 501 } 502 503 /** 504 * Subtracts the given rectangle from the collection of polygons 505 * the receiver maintains to describe its area. 506 * 507 * @param x the x coordinate of the rectangle 508 * @param y the y coordinate of the rectangle 509 * @param width the width coordinate of the rectangle 510 * @param height the height coordinate of the rectangle 511 * 512 * @exception IllegalArgumentException <ul> 513 * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> 514 * </ul> 515 * @exception SWTException <ul> 516 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 517 * </ul> 518 * 519 * @since 3.1 520 */ 521 public void subtract(int x, int y, int width, int height) { 522 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 523 if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 524 GdkRectangle* gdkRect = new GdkRectangle(); 525 gdkRect.x = x; 526 gdkRect.y = y; 527 gdkRect.width = width; 528 gdkRect.height = height; 529 auto rectRgn = OS.gdk_region_rectangle(gdkRect); 530 OS.gdk_region_subtract(handle, rectRgn); 531 OS.gdk_region_destroy(rectRgn); 532 } 533 534 /** 535 * Subtracts all of the polygons which make up the area covered 536 * by the argument from the collection of polygons the receiver 537 * maintains to describe its area. 538 * 539 * @param region the region to subtract 540 * 541 * @exception IllegalArgumentException <ul> 542 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 543 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 544 * </ul> 545 * @exception SWTException <ul> 546 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 547 * </ul> 548 * 549 * @since 3.0 550 */ 551 public void subtract(Region region) { 552 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 553 if (region is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 554 if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 555 OS.gdk_region_subtract(handle, region.handle); 556 } 557 558 /** 559 * Translate all of the polygons the receiver maintains to describe 560 * its area by the specified point. 561 * 562 * @param x the x coordinate of the point to translate 563 * @param y the y coordinate of the point to translate 564 * 565 * @exception SWTException <ul> 566 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 567 * </ul> 568 * 569 * @since 3.1 570 */ 571 public void translate (int x, int y) { 572 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 573 OS.gdk_region_offset (handle, x, y); 574 } 575 576 /** 577 * Translate all of the polygons the receiver maintains to describe 578 * its area by the specified point. 579 * 580 * @param pt the point to translate 581 * 582 * @exception IllegalArgumentException <ul> 583 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> 584 * </ul> 585 * @exception SWTException <ul> 586 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 587 * </ul> 588 * 589 * @since 3.1 590 */ 591 public void translate (Point pt) { 592 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 593 if (pt is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 594 translate (pt.x, pt.y); 595 } 596 597 /** 598 * Returns a string containing a concise, human-readable 599 * description of the receiver. 600 * 601 * @return a string representation of the receiver 602 */ 603 public override String toString () { 604 if (isDisposed()) return "Region {*DISPOSED*}"; 605 return Format( "Region {{{}}", handle ); 606 } 607 }