1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License as published by 6 * the Free Software Foundation; either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * gtkD is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with gtkD; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 17 */ 18 19 module TestDrawingArea; 20 21 //debug = trace; 22 23 private import cairo.Context; 24 private import cairo.ImageSurface; 25 26 private import gtk.VBox; 27 private import pango.PgContext; 28 private import pango.PgLayout; 29 30 version(Tango) private import tango.io.Stdout; 31 version(Tango) private import tango.stdc.stdio; 32 else private import std.stdio; 33 34 version(Tango) private import tango.math.Math; 35 else private import std.math; 36 37 private import gtk.Widget; 38 private import gtk.MenuItem; 39 private import gtk.ComboBox; 40 private import gtk.ComboBoxText; 41 private import gtk.Menu; 42 private import gtk.Adjustment; 43 private import gtk.HBox; 44 private import gdk.Pixbuf; 45 private import gdk.Cairo; 46 private import gdk.Color; 47 private import gdk.Event; 48 49 private import pango.PgCairo; 50 private import pango.PgFontDescription; 51 52 private import gtk.DrawingArea; 53 private import gtk.Image; 54 private import gtk.SpinButton; 55 56 57 /** 58 * This tests the gtkD drawing area widget 59 */ 60 class TestDrawingArea : VBox 61 { 62 63 this() 64 { 65 debug(Tango) Stdout("TestDrawingArea.this() 1").newline; 66 super(false,4); 67 68 debug(Tango) Stdout("TestDrawingArea.this() 2").newline; 69 TestDrawing drawingArea = new TestDrawing(); 70 71 debug(Tango) Stdout("TestDrawingArea.this() 3").newline; 72 73 ComboBoxText operators = new ComboBoxText(); 74 operators.appendText("CLEAR"); 75 operators.appendText("SOURCE"); 76 operators.appendText("OVER"); 77 operators.appendText("IN"); 78 operators.appendText("OUT"); 79 operators.appendText("ATOP"); 80 operators.appendText("DEST"); 81 operators.appendText("DEST_OVER"); 82 operators.appendText("DEST_IN"); 83 operators.appendText("DEST_OUT"); 84 operators.appendText("DEST_ATOP"); 85 operators.appendText("XOR"); 86 operators.appendText("ADD"); 87 operators.appendText("SATURATE"); 88 operators.appendText("MULTIPLY"); 89 operators.appendText("SCREEN"); 90 operators.appendText("OVERLAY"); 91 operators.appendText("DARKEN"); 92 operators.appendText("LIGHTEN"); 93 operators.appendText("COLOR_DODGE"); 94 operators.appendText("COLOR_BURN"); 95 operators.appendText("HARD_LIGHT"); 96 operators.appendText("SOFT_LIGHT"); 97 operators.appendText("DIFFERENCE"); 98 operators.appendText("EXCLUSION"); 99 operators.appendText("HSL_HUE"); 100 operators.appendText("HSL_SATURATION"); 101 operators.appendText("HSL_COLOR"); 102 operators.appendText("HSL_LUMINOSITY"); 103 operators.setActive(1); 104 operators.addOnChanged(&drawingArea.onOperatorsChanged); 105 106 debug(Tango) Stdout("TestDrawingArea.this() 4").newline; 107 108 ComboBoxText primOption = new ComboBoxText(); 109 primOption.appendText("Filled Arc"); 110 primOption.appendText("Arc"); 111 primOption.appendText("Line"); 112 primOption.appendText("Point"); 113 primOption.appendText("Rectangle"); 114 primOption.appendText("Filled Rectangle"); 115 primOption.appendText("Text"); 116 primOption.appendText("Pango text"); 117 primOption.appendText("Image"); 118 primOption.appendText("Polygon"); 119 primOption.setActive(0); 120 primOption.addOnChanged(&drawingArea.onPrimOptionChanged); 121 122 debug(Tango) Stdout("TestDrawingArea.this() 5").newline; 123 124 packStart(drawingArea,true,true,0); 125 126 HBox hbox = new HBox(false,4); 127 hbox.packStart(operators,false,false,2); 128 hbox.packStart(primOption,false,false,2); 129 hbox.packStart(drawingArea.spin,false,false,2); 130 hbox.packStart(drawingArea.backSpin,false,false,2); 131 132 debug(Tango) Stdout("TestDrawingArea.this() 6").newline; 133 134 packStart(hbox, false, false, 0); 135 136 debug(Tango) Stdout("TestDrawingArea.this() END").newline; 137 } 138 139 140 class TestDrawing : DrawingArea 141 { 142 CairoOperator operator = CairoOperator.OVER; 143 ImageSurface surface; 144 Color paintColor; 145 Color black; 146 147 int width; 148 int height; 149 150 bool buttonIsDown; 151 152 string primitiveType; 153 PgFontDescription font; 154 Image image; 155 Pixbuf scaledPixbuf; 156 157 SpinButton spin; 158 SpinButton backSpin; 159 static GdkPoint[] polygonStar = [ 160 {0,4}, 161 {1,1}, 162 {4,0}, 163 {1,-1}, 164 {0,-4}, 165 {-1,-1}, 166 {-4,0}, 167 {-1,1} 168 ]; 169 170 this() 171 { 172 debug(Tango) Stdout("TestDrawing.this() 1").newline; 173 174 setSizeRequest(333,333); 175 width = getWidth(); 176 height = getHeight(); 177 178 debug(Tango) Stdout("TestDrawing.this() 2").newline; 179 180 primitiveType = "Filled Arc"; 181 font = PgFontDescription.fromString("Courier 48"); 182 183 image = new Image("images/gtkDlogo_a_small.png"); 184 scaledPixbuf = image.getPixbuf(); 185 if (scaledPixbuf is null) 186 { 187 version(Tango) Stdout("\nFailed to load image gtkDlogo_a_small.png").newline; 188 else printf("\nFailed to load image file gtkDlogo_a_small.png\n"); 189 } 190 191 paintColor = new Color(cast(ubyte)0,cast(ubyte)0,cast(ubyte)0); 192 black = new Color(cast(ubyte)0,cast(ubyte)0,cast(ubyte)0); 193 194 spin = new SpinButton(new Adjustment(30, 1, 400, 1, 10, 0),1,0); 195 sizeSpinChanged(spin); 196 spin.addOnValueChanged(&sizeSpinChanged); 197 backSpin = new SpinButton(new Adjustment(5, 4, 100, 1, 10, 0),1,0); 198 backSpin.addOnValueChanged(&backSpinChanged); 199 200 addOnDraw(&drawCallback); 201 addOnMotionNotify(&onMotionNotify); 202 addOnSizeAllocate(&onSizeAllocate); 203 addOnButtonPress(&onButtonPress); 204 addOnButtonRelease(&onButtonRelease); 205 } 206 207 void onSizeAllocate(GtkAllocation* allocation, Widget widget) 208 { 209 width = allocation.width; 210 height = allocation.height; 211 212 surface = ImageSurface.create(CairoFormat.ARGB32, width, height); 213 drawPoints(Context.create(surface)); 214 } 215 216 public bool onButtonPress(Event event, Widget widget) 217 { 218 debug(trace) version(Tango) Stdout("button DOWN").newline; 219 else writefln("button DOWN"); 220 if ( event.type == EventType.BUTTON_PRESS && event.button.button == 1 ) 221 { 222 debug(trace) version(Tango) Stdout("Button 1 down").newline; 223 else writefln("Button 1 down"); 224 buttonIsDown = true; 225 226 drawPrimitive(cast(int)event.button.x, cast(int)event.button.y); 227 } 228 return false; 229 } 230 231 public bool onButtonRelease(Event event, Widget widget) 232 { 233 debug(trace) version(Tango) Stdout("button UP").newline; 234 else writefln("button UP"); 235 if ( event.type == EventType.BUTTON_RELEASE && event.button.button == 1 ) 236 { 237 debug(trace) version(Tango) Stdout("button 1 UP").newline; 238 else writefln("Button 1 UP"); 239 buttonIsDown = false; 240 } 241 return false; 242 } 243 244 /** 245 * This will be called from the expose event call back. 246 * \bug this is called on get or loose focus - review 247 */ 248 public bool drawCallback(Context context, Widget widget) 249 { 250 //Fill the Widget with the surface we are drawing on. 251 context.setSourceSurface(surface, 0, 0); 252 context.paint(); 253 254 return true; 255 } 256 257 public bool onMotionNotify(Event event, Widget widget) 258 { 259 //printf("testWindow.mouseMoved ----------------------------- \n"); 260 if ( buttonIsDown && event.type == EventType.MOTION_NOTIFY ) 261 { 262 drawPrimitive(cast(int)event.motion.x, cast(int)event.motion.y); 263 } 264 265 return true; 266 } 267 268 static int backSpinCount = 0; 269 270 public void backSpinChanged(SpinButton spinButton) 271 { 272 273 debug(trace) version(Tango) Stdout.format("backSpinChanged - entry {}", ++backSpinCount).newline; 274 else writefln("backSpinChanged - entry %s", ++backSpinCount); 275 276 drawPoints(Context.create(surface)); 277 this.queueDraw(); 278 279 debug(trace) version(Tango) Stdout("backSpinChanged - exit").newline; 280 else writefln("backSpinChanged - exit"); 281 } 282 283 public void sizeSpinChanged(SpinButton spinButton) 284 { 285 if ( !(scaledPixbuf is null)) 286 { 287 int width = spinButton.getValueAsInt(); 288 scaledPixbuf = image.getPixbuf(); 289 290 float ww = width * scaledPixbuf.getWidth() / 30; 291 float hh = width * scaledPixbuf.getHeight() / 30; 292 293 scaledPixbuf = scaledPixbuf.scaleSimple(cast(int)ww, cast(int)hh, GdkInterpType.HYPER); 294 } 295 } 296 297 public void drawPrimitive(int x, int y) 298 { 299 int width = spin.getValueAsInt(); 300 int height = width * 3 / 4; 301 302 Context context = Context.create(surface); 303 context.setOperator(operator); 304 305 debug(trace) version(Tango) Stdout.format("primitiveType = {}", primitiveType).newline; 306 else writefln("primitiveType = %s", primitiveType); 307 308 switch ( primitiveType ) 309 { 310 case "Arc": 311 context.arc(x-width/2,y-width/2,width,0,2*PI); 312 context.stroke(); 313 break; 314 315 case "Filled Arc": 316 context.arc(x-width/4,y-width/4,width/2,0,2*PI); 317 context.fill(); 318 break; 319 320 case "Line": 321 context.moveTo(x, y); 322 context.lineTo(x+width, y); 323 context.stroke(); 324 break; 325 326 case "Point": 327 context.rectangle(x, y, 1, 1); 328 context.fill(); 329 break; 330 331 case "Rectangle": 332 context.rectangle(x-width/2, y-width/4, width, height); 333 context.stroke(); 334 break; 335 336 case "Filled Rectangle": 337 context.rectangle(x-width/2, y-width/4, width, height); 338 context.fill(); 339 break; 340 341 case "Text": 342 context.selectFontFace("FreeMono", CairoFontSlant.NORMAL, CairoFontWeight.NORMAL); 343 context.setFontSize(12); 344 context.moveTo(x, y); 345 context.showText("gtkD toolkit"); 346 break; 347 348 case "Pango text": 349 PgLayout l = PgCairo.createLayout(context); 350 PgFontDescription fd = new PgFontDescription("Sans", width); 351 352 l.setText("Gtk+ with D"); 353 l.setFontDescription(fd); 354 355 context.moveTo(x, y); 356 PgCairo.showLayout(context, l); 357 break; 358 359 case "Image": 360 if ( !(scaledPixbuf is null)) 361 { 362 version(D_Version2) 363 context.setSourcePixbuf(scaledPixbuf, x, y); 364 else 365 setSourcePixbuf(context, scaledPixbuf, x, y); 366 context.paint(); 367 } 368 break; 369 370 case "Polygon": 371 //TODO: Use Context.scale and transform ? 372 for ( int scale = 10 ; scale<= 300; scale+=15) 373 { 374 context.save(); 375 context.moveTo(polygonStar[0].x*scale/2+x, polygonStar[0].y*scale/2+y); 376 377 foreach(p; polygonStar[1 .. $]) 378 { 379 context.lineTo(p.x*scale/2+x, p.y*scale/2+y); 380 } 381 context.closePath(); 382 context.stroke(); 383 context.restore(); 384 } 385 break; 386 387 default: 388 context.arcNegative(x-2,y-2,4,0,6); 389 context.fill(); 390 break; 391 } 392 393 //Redraw the Widget. 394 this.queueDraw(); 395 } 396 397 private void drawPoints(Context context) 398 { 399 int square = backSpin.getValueAsInt(); 400 int totalcount = 0; 401 int count = 0; 402 Color color = new Color(); 403 int width = this.width; 404 int height = this.height; 405 int x = 0; 406 int y = 0; 407 408 debug(trace) version(Tango) Stdout.format("w,h = {} {}",width ,height).newline; 409 else writefln("w,h = %s %s",width ,height); 410 411 float dx = 256.0 / width; 412 float dy = 256.0 / height ; 413 float xx; 414 float yy; 415 while ( x < width || y <height ) 416 { 417 context.save(); 418 419 xx = x * dx; 420 yy = y * dy; 421 context.setSourceRgba( xx / 255, 422 yy / 255, 423 sqrt((xx*xx)+(yy*yy)) / 255, 424 1 ); 425 426 if ( square > 1 ) 427 { 428 context.rectangle(x, y, square, square); 429 context.fill(); 430 } 431 else 432 { 433 context.moveTo(x, y); 434 context.stroke(); 435 } 436 x +=square; 437 if ( x > width) 438 { 439 if ( y>height) 440 { 441 //y=0; 442 } 443 else 444 { 445 x = 0; 446 y+=square; 447 } 448 } 449 ++totalcount; 450 451 context.restore(); 452 } 453 delete color; 454 } 455 456 void onOperatorsChanged(ComboBoxText comboBoxText) 457 { 458 debug(trace) version(Tango) Stdout.format("CairoOperator = {}", comboBoxText.getActiveText()).newline; 459 else writefln("CairoOperator = %s", comboBoxText.getActiveText()); 460 switch ( comboBoxText.getActiveText() ) 461 { 462 case "CLEAR": operator = CairoOperator.CLEAR; break; 463 case "SOURCE": operator = CairoOperator.SOURCE; break; 464 case "OVER": operator = CairoOperator.OVER; break; 465 case "IN": operator = CairoOperator.IN; break; 466 case "OUT": operator = CairoOperator.OUT; break; 467 case "ATOP": operator = CairoOperator.ATOP; break; 468 case "DEST": operator = CairoOperator.DEST; break; 469 case "DEST_OVER": operator = CairoOperator.DEST_OVER; break; 470 case "DEST_IN": operator = CairoOperator.DEST_IN; break; 471 case "DEST_OUT": operator = CairoOperator.DEST_OUT; break; 472 case "DEST_ATOP": operator = CairoOperator.DEST_ATOP; break; 473 case "XOR": operator = CairoOperator.XOR; break; 474 case "ADD": operator = CairoOperator.ADD; break; 475 case "SATURATE": operator = CairoOperator.SATURATE; break; 476 case "MULTIPLY": operator = CairoOperator.MULTIPLY; break; 477 case "SCREEN": operator = CairoOperator.SCREEN; break; 478 case "OVERLAY": operator = CairoOperator.OVERLAY; break; 479 case "DARKEN": operator = CairoOperator.DARKEN; break; 480 case "LIGHTEN": operator = CairoOperator.LIGHTEN; break; 481 case "COLOR_DODGE": operator = CairoOperator.COLOR_DODGE; break; 482 case "COLOR_BURN": operator = CairoOperator.COLOR_BURN; break; 483 case "HARD_LIGHT": operator = CairoOperator.HARD_LIGHT; break; 484 case "SOFT_LIGHT": operator = CairoOperator.SOFT_LIGHT; break; 485 case "DIFFERENCE": operator = CairoOperator.DIFFERENCE; break; 486 case "EXCLUSION": operator = CairoOperator.EXCLUSION; break; 487 case "HSL_HUE": operator = CairoOperator.HSL_HUE; break; 488 case "HSL_SATURATION": operator = CairoOperator.HSL_SATURATION; break; 489 case "HSL_COLOR": operator = CairoOperator.HSL_COLOR; break; 490 case "HSL_LUMINOSITY": operator = CairoOperator.HSL_LUMINOSITY; break; 491 default: operator = CairoOperator.OVER; break; 492 } 493 } 494 495 void onPrimOptionChanged(ComboBoxText comboBoxText) 496 { 497 primitiveType = comboBoxText.getActiveText(); 498 } 499 } 500 } 501