phpgtk__legacy/wiki1/wiki.d/CodeSnippets.DrawingArea

24 lines
35 KiB
Text

version=pmwiki-1.0.5
newline=²
text=Here you can find :²* a nice drawing area example,²* with 2D matrix transformation : rotate, translate, scale,²* there are many classes : Point, Matrix, GxObject, GxPoint, GxRectangle, GxDrawingArea;²* this framework is not complete but the first snapshot for a drawing editor in php-gtk2,²* the main part of the code is in "timeout" function (GxDrawingAreaTest class)²* here is a snapshot : [[http://quinton.free.fr/php/gtk/wiki/drawing_area.png]]²* a more complete library can be found at : http://quinton.free.fr/php/gtk/gxlib/ ; there is now a near working brick-breaker game included as tutorial and proof of concept with this library.²²[[include:Main/CodeTable]]²<?php²/**²* Gx is a php-gtk2 graphic library - Marc Quinton - june 2006.²*/²²error_reporting(E_ALL);²²/**² *² *² * @version $Id$² * @copyright 2004² **/²class Point{² var $x;² var $y;²² function Point($x = 0, $y = 0){² $this->x = $x;² $this->y = $y;² }²² function x(){² return $this->x;² }²² function y(){² return $this->y;² }²² function vals(){² return array($this->x, $this->y);² }²² function &transform(&$view, &$screen){² $p2 = new Point();² $p2->x = intval(($this->x - $view->x) * $screen->w/$view->w);² $p2->y = intval($screen->h - ($this->y - $view->y) * ($screen->h/$view->h));² return $p2;² }²² function to_text(){² return "Point({$this->x}, {$this->y});";² }²² function in_window($window){² if($this->x < $window->x)² return false;² if($this->y < $window->y)² return false;²² if($this->x > $window->x+$window->w)² return false;² if($this->y > $window->y+$window->h)² return false;²² return true;² }²}²²²²class Matrix{²² # matrix coefs² var $m11, $m21, $m12, $m22, $v1, $v2;²² function Matrix($m11=null, $m21=null, $m12=null, $m22=null, $v1=0, $v2=0){²² if($m11 == null && $m12 == null && $m21 == null && $m22 == null)² $this->identity();² else² $this->initialize($m11, $m21, $m12, $m22, $v1, $v2);² }²² # The identity transformation² function identity(){² $this->m11 = 1;² $this->m12 = 0;² $this->m21 = 0;² $this->m22 = 1;² $this->v1 = 0;² $this->v2 = 0;² }²² # The identity transformation² function is_identity(){² if($this->coefs() == array(1,0,0,1,0,0))² return true;² else² return false;² }²² function is_near_identity($epsilon=1E-15){² $m = $this->_clone();² $m->round($epsilon);² return $m->is_identity();² }²² function initialize($m11, $m21, $m12, $m22, $v1, $v2){² $this->m11 = $m11;² $this->m12 = $m12;² $this->m21 = $m21;² $this->m22 = $m22;² $this->v1 = $v1;² $this->v2 = $v2;² }²² function translate($offx, $offy){² $this->v1+=$offx;² $this->v2+=$offy;² return true;² }²² # rotate angle in degres² function rotate($angle, $cx=0, $cy=0){² $this->rotate_radians($angle*M_PI/180, $cx, $cy);² }²² # rotate angle in degres² function rotate_radians($angle, $cx=0, $cy=0){² $s = sin($angle);² $c = cos($angle);² $offx = $cx - $c*$cx + $s*$cy;² $offy = $cy - $s*$cx - $c*$cy;²² $m = new Matrix($c, $s, -$s, $c, $offx, $offy);² $this->composite($m);² }²² # scale² function scale($x, $y=null){² $this->m11*=$x;² if($y==null)² $this->m22*=$x;² else² $this->m22*=$y;² }²² function transformPoint($x, $y=null)² {²² if(get_class($x) == 'Point'){² $p = $x;² $p2 = new Point(² $this->m11*$p->x + $this->m12*$p->y + $this->v1,² $this->m21*$p->x + $this->m22*$p->y + $this->v2² );² return($p2);² }²² return array(² ($this->m11*$x) + ($this->m12*$y) + $this->v1,² ($this->m21*$x) + ($this->m22*$y) + $this->v2² );² }²²²² /*² Return the inverse of trafo. If the matrix is singular, raise a error² */² function inverse(){²² $det = $this->m11 * $this->m22 - $this->m12 * $this->m21;²² if($det == 0.0) {² trigger_error("inverting singular matrix");² return NULL;² }²² $m11 = $this->m22 / $det;² $m12 = -$this->m12 / $det;² $m21 = -$this->m21 / $det;² $m22 = $this->m11 / $det;²² $this->initialize(² $m11, $m21, $m12, $m22,² -$m11 * $this->v1 - $m12 * $this->v2,² -$m21 * $this->v1 - $m22 * $this->v2);² }²² #² function composite(&$m){²² $this->initialize(² $this->m11 * $m->m11 + $this->m12 * $m->m21,² $this->m21 * $m->m11 + $this->m22 * $m->m21,² $this->m11 * $m->m12 + $this->m12 * $m->m22,² $this->m21 * $m->m12 + $this->m22 * $m->m22,² $this->m11 * $m->v1 + $this->m12 * $m->v2 + $this->v1,² $this->m21 * $m->v1 + $this->m22 * $m->v2 + $this->v2² );² }²² function &composite_copy(&$m){² return new Matrix(² $this->m11 * $m->m11 + $this->m12 * $m->m21,² $this->m21 * $m->m11 + $this->m22 * $m->m21,² $this->m11 * $m->m12 + $this->m12 * $m->m22,² $this->m21 * $m->m12 + $this->m22 * $m->m22,² $this->m11 * $m->v1 + $this->m12 * $m->v2 + $this->v1,² $this->m21 * $m->v1 + $this->m22 * $m->v2 + $this->v2² );² }²² function show(){² printf("|%3.3f, %3.3f, %3.3f|\n", $this->m11, $this->m12, $this->v1);² printf("|%3.3f, %3.3f, %3.3f|\n", $this->m21, $this->m22, $this->v2);² echo "\n";² }²² function _clone(){² #$m = &new Matrix($this->m11, $this->m21, $this->m12, $this->m22, $this->v1, $this->v2);² return $this;² }²² function to_text(){² return 'Matrix(' .² $this->m11 . ', ' .² $this->m21 . ', ' .² $this->m12 . ', ' .² $this->m22 . ', ' .² $this->v1 . ', ' .² $this->v2 . ');';² }²² function coefs(){² return array($this->m11, $this->m21, $this->m12, $this->m22, $this->v1, $this->v2);² }²² function equals($m){² if($this->m11 != $m->m11)² return false;² if($this->m12 != $m->m12)² return false;² if($this->m21 != $m->m21)² return false;² if($this->m22 != $m->m22)² return false;² if($this->v1 != $m->v1)² return false;² if($this->v2 != $m->v2)² return false;² return true;² }²² function near_value($val, $near, $epsilon=1.0E-15){² if($val > $near+$epsilon)² return false;² if($val < $near-$epsilon)² return false;² return true;² }²² # round floting point values of matrix coefs near 0 or 1² # usefull for identity matrix check after multiple operations (rotation, scales ....)² function round($epsilon=1E-15){² $list = array('m11', 'm21', 'm12', 'm22', 'v1', 'v2');² foreach($list as $coef_name){² $val = &$this->$coef_name;² $val = $this->near_value($val, 0, $epsilon)?0:$val;² $val = $this->near_value($val, 1, $epsilon)?1:$val;² }² }²}²²²class GxObject{² protected $transfo; # matrix transformation² function __construct($x=0,$y=0){² $this->transfo = new Matrix(1,0,0,1,-$x,-$y);² }²² function translate($x, $y){² return $this->transfo->translate($x, $y);² }²² # rotate angle in degres² function rotate($angle, $cx=0, $cy=0){² return $this->transfo->rotate($angle, $cx, $cy);² }²² # rotate angle in degres² function rotate_radians($angle, $cx=0, $cy=0){² return $this->transfo->rotate_radians($angle, $cx, $cy);² }²² # scale² function scale($x, $y=null){² return $this->transfo->scale($x, $y);² }²² function transformPoint($point)² {² $p1 = new Point($point->x, $point->y);² $p2 = $this->transfo->transformPoint($p1);² $point->x = $p2->x; $point->y = $p2->y;² return $point;² }²² function bounding_box(){² return array(0,0,0,0);² }²}²²class GxPoint extends GxObject{² var $x, $y;² function __construct($x=0, $y=0){² parent::__construct();² $this->x = $x ; $this->y=$y;² }²² function x(){² return $this->x;² }² function y(){² return $this->y;² }²² function to_text($name=''){² return "GxPoint-$name({$this->x}, {$this->y});";² }²²}²²class GxLine extends GxObject{² protected $p1, $p2;² function __construct($p1=null, $p2=null){² parent::__construct();² $this->p1 = $p1;² $this->p2 = $p2;² }²² function &p1(){² return $this->p1;² }² function &p2(){² return $this->p2;² }²}²²class GxRectangle extends GxObject{² var $x, $y, $w, $h;² function __construct($x, $y, $w, $h){² parent::__construct();² $this->x = $x;² $this->y = $y;² $this->w = $w;² $this->h = $h;² }²² function &p1(){² return $this->p1;² }² function &p2(){² return $this->p2;² }²² function center(){² $p = new Point($this->x+$this->w/2, $this->y+$this->h/2);² return $p;² }²² function transformPoint($point, $center)² {² $p1 = new Point($point->x - $center->x, $point->y-$center->y);² $p2 = $this->transfo->transformPoint($p1);² $point->x = $p2->x+$center->x; $point->y = $p2->y+$center->x;² return $point;² }²² function bounding_box(){² list($p1,$p2,$p3,$p4) = $this->transformedPoints();² $x_min = min($p1->x, $p2->x, $p3->x, $p4->x);² $y_min = min($p1->y, $p2->y, $p3->y, $p4->y);²² $x_max = max($p1->x, $p2->x, $p3->x, $p4->x);² $y_max = max($p1->y, $p2->y, $p3->y, $p4->y);²² $x = $x_min; $y=$y_min;² $w = $x_max-$x_min; $h=$y_max-$y_min;²² return array($x, $y, $w, $h);² }²² function transformedPoints(){² $center = $this->center();²² $x = $this->x; $y = $this->y;² $w = $this->w; $h = $this->h;²² $p1 = new GxPoint($x, $y);² $p2 = new GxPoint($x+$w, $y);² $p3 = new GxPoint($x+$w, $y+$h);² $p4 = new GxPoint($x, $y+$h);²² $p1 = $this->transformPoint($p1, $center);² $p2 = $this->transformPoint($p2, $center);² $p3 = $this->transformPoint($p3, $center);² $p4 = $this->transformPoint($p4, $center);²² return array($p1, $p2,$p3,$p4);² }²² function clear($da){² list($x, $y, $w, $h) = $this->bounding_box();² $da->clear($x, $y, $w, $h);² }²² function draw($da){²² list($p1,$p2,$p3,$p4) = $this->transformedPoints();² $da->draw_line($p1,$p2);² $da->draw_line($p2,$p3);² $da->draw_line($p3,$p4);² $da->draw_line($p1,$p4);² $da->draw_line($p1,$p3);² $da->draw_line($p2,$p4);²² # draw bounding_box (debug)² list($x, $y, $w, $h) = $this->bounding_box();² $da->draw_rectangle($x, $y,$w+1, $h+1);² }²}²²class GxPolyLine extends GxObject{² protected $points;²² function __construct($list= null){² parent::__construct();² if($list == null)² $this->points = array();² else² $this->points = $list;² }²² function add($point){² $this->points[] = $point;² }²² function &points(){² return $this->points;² }²}²²class GxDrawingArea extends GtkDrawingArea{²² protected $pixmap = null;²² function __construct(){² parent::__construct();²² }²² // void draw_arc(GdkGC gc, bool filled, int x, int y, int width, int height, int angle1, int angle2);² function draw_arc($x, $y, $w, $h, $angle1, $angle2){² $this->pixmap->draw_arc($this->style->black_gc, true, $x, $y, $w, $h, $angle1, $angle2);² $this->redraw($x, $y, $w, $h);² }²² function draw_rectangle($x, $y, $w, $h, $filled=false){² $this->pixmap->draw_rectangle($this->style->black_gc, $filled, $x, $y, $w, $h);² $this->redraw($x, $y, $w, $h);² }²² // MQ : devrait utiliser pango, mais n'est pas encore bien implementé dans php-gtk.² function draw_text($x, $y, $text, $clear=true){² # deprecated method ; should use GdkDrawable::draw_layout (with pango)² $w = 7*strlen($text); $h = 15;² # if($clear)² $this->clear($x,$y-$h,$w,$h);² @$this->pixmap->draw_string($this->my_font, $this->style->black_gc, $x, $y, $text);² # $this->draw_rectangle($x,$y,$w,$h);² $this->redraw($x, $y-$h, $w, $h);² }²² function draw_line($x1, $y1, $x2=null, $y2=null){² if(is_a($x1, 'GxPoint') && is_a($y1, 'GxPoint')){² $p1 = $x1;² $p2 = $y1;² $x1 = $p1->x();² $x2 = $p2->x();² $y1 = $p1->y();² $y2 = $p2->y();² }² $this->pixmap->draw_line($this->style->black_gc, $x1, $y1, $x2, $y2);² $x = min($x1,$x2);² $y = min($y1,$y2);² $w=abs($x2-$x1);² $h=abs($y2-$y1);² $this->redraw($x, $y, $w, $h);² }²² function redraw($x=null, $y=null, $w=null, $h=null){² if($x == null)² $this->queue_draw_area(0, 0, $this->w, $this->h);² else² $this->queue_draw_area($x, $y, $w, $h);² }²² function clear($x=null, $y=null, $w=null, $h=null){² if($x==null){² $x=0 ; $y=0 ; $w=$this->w ; $h=$this->h;² }² $this->pixmap->draw_rectangle($this->style->white_gc, true, $x, $y,$w, $h);² $this->redraw($x, $y, $w, $h);² }²}²²class GxDrawingAreaTest extends GxDrawingArea{²² # tests² protected $point=null;² protected $polyline=null;² protected $rectangle1;² protected $rectangle2;²² function __construct(){²² parent::__construct();²² $this->connect('expose_event' , array($this, 'expose_event'));² $this->connect('configure_event' , array($this, 'configure_event'));²² $this->connect('motion_notify_event', array($this, 'motion_notify_event'));² $this->connect('button_press_event' , array($this, 'button_press_event'));²² $this->set_events(² Gdk::EXPOSURE_MASK² | Gdk::LEAVE_NOTIFY_MASK² | Gdk::BUTTON_PRESS_MASK² | Gdk::POINTER_MOTION_MASK² | Gdk::POINTER_MOTION_HINT_MASK);²² # GDK_ALL_EVENTS_MASK²² Gtk::timeout_add(1000, array($this, 'timeout'), 1234);² $this->rectangle1 = new GxRectangle(150,150, 50, 100);² $this->rectangle2 = new GxRectangle(300,150, 100, 50);² $this->count=0;² $this->scale = 1.1;² }²²² function configure_event($widget, $event)² {² $this->w = $widget->allocation->width;² $this->h = $widget->allocation->height;²² $this->pixmap = new GdkPixmap($widget->window,² $widget->allocation->width,² $widget->allocation->height,² -1);² $this->pixmap->draw_rectangle($widget->style->white_gc,² true, 0, 0,² $widget->allocation->width,² $widget->allocation->height);² $this->point = null;² $this->polyline = new GxPolyLine();² # $this->my_font = new GdkFont("-adobe-helvetica-bold-r-normal--12-120-75-75-p-70-iso8859-1");² $this->my_font = $this->style->get_font();² $x = $widget->allocation->width/2;² $y = 15;² $this->draw_text($x, $y, 'Php-Gtk2 - Drawing Area sample test');² return true;² }²² function draw_brush($x, $y)² {² $this->draw_arc($x - 4, $y - 4, 8, 8, 0, 64 * 360);² }²² function timeout(){²² # MQ : should clear the right area, not full window² # $this->clear();²²² # display analog clock.² Gtk::timeout_add(500, array($this, 'timeout'), 1234);² $date = date('H:i:s');² $this->draw_text(15,15, $date);²² $this->count++;² if($this->count % 20 == 1){² $this->scale = 1/$this->scale;² }²² $this->rectangle1->clear($this);² $this->rectangle1->rotate(3);² # $this->rectangle1->scale($this->scale);² # $this->rectangle1->translate(5,5);² $this->rectangle1->draw($this);²²² # $this->rectangle2->rotate(-6);² # $this->rectangle2->scale(1/$this->scale);² # $this->rectangle2->draw($this);²² }²² function expose_event($widget, $event)² {² $widget->window->draw_drawable($widget->style->fg_gc[$widget->state],² $this->pixmap,² $event->area->x, $event->area->y,² $event->area->x, $event->area->y,² $event->area->width, $event->area->height);²² return false;² }²²²² function button_press_event($widget, $event)² {²² if ($event->button == 1 && $this->pixmap) {² # $this->draw_brush($widget, (int)$event->x, (int)$event->y);² $this->draw_rectangle((int)$event->x, (int)$event->y, 10, 10);² $info = sprintf('(%d:%d)', $event->x, $event->y);² $this->draw_text((int)$event->x+15, (int)$event->y-15, $info);² if($this->point != null){² $p = new GxPoint($event->x, $event->y);² # $this->draw_line($event->x, $event->y, $this->point->x(), $this->point->y());² $this->draw_line($p, $this->point);² }² $this->point = new GxPoint($event->x, $event->y);² $this->polyline->add($this->point);² }²² return true;² }²² function motion_notify_event($widget, $event)² {² $window = $event->window;² $pointer = $window->get_pointer();² $x = $pointer[0];² $y = $pointer[1];² $state = $pointer[2];²² if (($state & Gdk::BUTTON1_MASK) && $this->pixmap) {² $this->draw_brush($x, $y);² }²² return true;² }²}²²²class App extends GtkWindow²{²² function __construct($parent = null)² {² parent::__construct();²² $this->connect_simple('destroy', array('gtk', 'main_quit'));²² $this->set_title(__CLASS__);² $this->set_position(Gtk::WIN_POS_CENTER);² $this->set_default_size(-1, -1);² $this->set_border_width(8);²² $this->add($this->__create_box());² $this->show_all();² }//function __construct($parent = null)²²²² function __create_box()² {² $vbox = new GtkVBox();² $vbox->show();²² $drawing_area = new GxDrawingAreaTest();² $drawing_area->set_size_request(500, 500);² $vbox->pack_start($drawing_area);²// $drawing_area->realize();²²² return $vbox;² }//function __create_box()²}//class Scribble extends GtkWindow²²²$app = new App();²Gtk::main();²²?>²²[[include:Main/CodeTableEnd]]²
time=1150733709
diff:1149858701:1149858701:=1,704c1²< Here you can find :²< * a nice drawing area example,²< * with 2D matrix transformation : rotate, translate, scale,²< * there are many classes : Point, Matrix, GxObject, GxPoint, GxRectangle, GxDrawingArea;²< * this framework is not complete but the first snapshot for a drawing editor in php-gtk2,²< * the main part of the code is in "timeout" function (GxDrawingAreaTest class)²< ²< ²< ²< [[include:Main/CodeTable]]²< <?php²< /**²< * Gx is a php-gtk2 graphic library - Marc Quinton - june 2006.²< */²< ²< error_reporting(E_ALL);²< ²< /**²< *²< *²< * @version $Id$²< * @copyright 2004²< **/²< class Point{²< var $x;²< var $y;²< ²< function Point($x = 0, $y = 0){²< $this->x = $x;²< $this->y = $y;²< }²< ²< function x(){²< return $this->x;²< }²< ²< function y(){²< return $this->y;²< }²< ²< function vals(){²< return array($this->x, $this->y);²< }²< ²< function &transform(&$view, &$screen){²< $p2 = new Point();²< $p2->x = intval(($this->x - $view->x) * $screen->w/$view->w);²< $p2->y = intval($screen->h - ($this->y - $view->y) * ($screen->h/$view->h));²< return $p2;²< }²< ²< function to_text(){²< return "Point({$this->x}, {$this->y});";²< }²< ²< function in_window($window){²< if($this->x < $window->x)²< return false;²< if($this->y < $window->y)²< return false;²< ²< if($this->x > $window->x+$window->w)²< return false;²< if($this->y > $window->y+$window->h)²< return false;²< ²< return true;²< }²< }²< ²< ²< ²< class Matrix{²< ²< # matrix coefs²< var $m11, $m21, $m12, $m22, $v1, $v2;²< ²< function Matrix($m11=null, $m21=null, $m12=null, $m22=null, $v1=0, $v2=0){²< ²< if($m11 == null && $m12 == null && $m21 == null && $m22 == null)²< $this->identity();²< else²< $this->initialize($m11, $m21, $m12, $m22, $v1, $v2);²< }²< ²< # The identity transformation²< function identity(){²< $this->m11 = 1;²< $this->m12 = 0;²< $this->m21 = 0;²< $this->m22 = 1;²< $this->v1 = 0;²< $this->v2 = 0;²< }²< ²< # The identity transformation²< function is_identity(){²< if($this->coefs() == array(1,0,0,1,0,0))²< return true;²< else²< return false;²< }²< ²< function is_near_identity($epsilon=1E-15){²< $m = $this->_clone();²< $m->round($epsilon);²< return $m->is_identity();²< }²< ²< function initialize($m11, $m21, $m12, $m22, $v1, $v2){²< $this->m11 = $m11;²< $this->m12 = $m12;²< $this->m21 = $m21;²< $this->m22 = $m22;²< $this->v1 = $v1;²< $this->v2 = $v2;²< }²< ²< function translate($offx, $offy){²< $this->v1+=$offx;²< $this->v2+=$offy;²< return true;²< }²< ²< # rotate angle in degres²< function rotate($angle, $cx=0, $cy=0){²< $this->rotate_radians($angle*M_PI/180, $cx, $cy);²< }²< ²< # rotate angle in degres²< function rotate_radians($angle, $cx=0, $cy=0){²< $s = sin($angle);²< $c = cos($angle);²< $offx = $cx - $c*$cx + $s*$cy;²< $offy = $cy - $s*$cx - $c*$cy;²< ²< $m = new Matrix($c, $s, -$s, $c, $offx, $offy);²< $this->composite($m);²< }²< ²< # scale²< function scale($x, $y=null){²< $this->m11*=$x;²< if($y==null)²< $this->m22*=$x;²< else²< $this->m22*=$y;²< }²< ²< function transformPoint($x, $y=null)²< {²< ²< if(get_class($x) == 'Point'){²< $p = $x;²< $p2 = new Point(²< $this->m11*$p->x + $this->m12*$p->y + $this->v1,²< $this->m21*$p->x + $this->m22*$p->y + $this->v2²< );²< return($p2);²< }²< ²< return array(²< ($this->m11*$x) + ($this->m12*$y) + $this->v1,²< ($this->m21*$x) + ($this->m22*$y) + $this->v2²< );²< }²< ²< ²< ²< /*²< Return the inverse of trafo. If the matrix is singular, raise a error²< */²< function inverse(){²< ²< $det = $this->m11 * $this->m22 - $this->m12 * $this->m21;²< ²< if($det == 0.0) {²< trigger_error("inverting singular matrix");²< return NULL;²< }²< ²< $m11 = $this->m22 / $det;²< $m12 = -$this->m12 / $det;²< $m21 = -$this->m21 / $det;²< $m22 = $this->m11 / $det;²< ²< $this->initialize(²< $m11, $m21, $m12, $m22,²< -$m11 * $this->v1 - $m12 * $this->v2,²< -$m21 * $this->v1 - $m22 * $this->v2);²< }²< ²< #²< function composite(&$m){²< ²< $this->initialize(²< $this->m11 * $m->m11 + $this->m12 * $m->m21,²< $this->m21 * $m->m11 + $this->m22 * $m->m21,²< $this->m11 * $m->m12 + $this->m12 * $m->m22,²< $this->m21 * $m->m12 + $this->m22 * $m->m22,²< $this->m11 * $m->v1 + $this->m12 * $m->v2 + $this->v1,²< $this->m21 * $m->v1 + $this->m22 * $m->v2 + $this->v2²< );²< }²< ²< function &composite_copy(&$m){²< return new Matrix(²< $this->m11 * $m->m11 + $this->m12 * $m->m21,²< $this->m21 * $m->m11 + $this->m22 * $m->m21,²< $this->m11 * $m->m12 + $this->m12 * $m->m22,²< $this->m21 * $m->m12 + $this->m22 * $m->m22,²< $this->m11 * $m->v1 + $this->m12 * $m->v2 + $this->v1,²< $this->m21 * $m->v1 + $this->m22 * $m->v2 + $this->v2²< );²< }²< ²< function show(){²< printf("|%3.3f, %3.3f, %3.3f|\n", $this->m11, $this->m12, $this->v1);²< printf("|%3.3f, %3.3f, %3.3f|\n", $this->m21, $this->m22, $this->v2);²< echo "\n";²< }²< ²< function _clone(){²< #$m = &new Matrix($this->m11, $this->m21, $this->m12, $this->m22, $this->v1, $this->v2);²< return $this;²< }²< ²< function to_text(){²< return 'Matrix(' .²< $this->m11 . ', ' .²< $this->m21 . ', ' .²< $this->m12 . ', ' .²< $this->m22 . ', ' .²< $this->v1 . ', ' .²< $this->v2 . ');';²< }²< ²< function coefs(){²< return array($this->m11, $this->m21, $this->m12, $this->m22, $this->v1, $this->v2);²< }²< ²< function equals($m){²< if($this->m11 != $m->m11)²< return false;²< if($this->m12 != $m->m12)²< return false;²< if($this->m21 != $m->m21)²< return false;²< if($this->m22 != $m->m22)²< return false;²< if($this->v1 != $m->v1)²< return false;²< if($this->v2 != $m->v2)²< return false;²< return true;²< }²< ²< function near_value($val, $near, $epsilon=1.0E-15){²< if($val > $near+$epsilon)²< return false;²< if($val < $near-$epsilon)²< return false;²< return true;²< }²< ²< # round floting point values of matrix coefs near 0 or 1²< # usefull for identity matrix check after multiple operations (rotation, scales ....)²< function round($epsilon=1E-15){²< $list = array('m11', 'm21', 'm12', 'm22', 'v1', 'v2');²< foreach($list as $coef_name){²< $val = &$this->$coef_name;²< $val = $this->near_value($val, 0, $epsilon)?0:$val;²< $val = $this->near_value($val, 1, $epsilon)?1:$val;²< }²< }²< }²< ²< ²< class GxObject{²< protected $transfo; # matrix transformation²< function __construct($x=0,$y=0){²< $this->transfo = new Matrix(1,0,0,1,-$x,-$y);²< }²< ²< function translate($x, $y){²< return $this->transfo->translate($x, $y);²< }²< ²< # rotate angle in degres²< function rotate($angle, $cx=0, $cy=0){²< return $this->transfo->rotate($angle, $cx, $cy);²< }²< ²< # rotate angle in degres²< function rotate_radians($angle, $cx=0, $cy=0){²< return $this->transfo->rotate_radians($angle, $cx, $cy);²< }²< ²< # scale²< function scale($x, $y=null){²< return $this->transfo->scale($x, $y);²< }²< ²< function transformPoint($point)²< {²< $p1 = new Point($point->x, $point->y);²< $p2 = $this->transfo->transformPoint($p1);²< $point->x = $p2->x; $point->y = $p2->y;²< return $point;²< }²< ²< function bounding_box(){²< return array(0,0,0,0);²< }²< }²< ²< class GxPoint extends GxObject{²< var $x, $y;²< function __construct($x=0, $y=0){²< parent::__construct();²< $this->x = $x ; $this->y=$y;²< }²< ²< function x(){²< return $this->x;²< }²< function y(){²< return $this->y;²< }²< ²< function to_text($name=''){²< return "GxPoint-$name({$this->x}, {$this->y});";²< }²< ²< }²< ²< class GxLine extends GxObject{²< protected $p1, $p2;²< function __construct($p1=null, $p2=null){²< parent::__construct();²< $this->p1 = $p1;²< $this->p2 = $p2;²< }²< ²< function &p1(){²< return $this->p1;²< }²< function &p2(){²< return $this->p2;²< }²< }²< ²< class GxRectangle extends GxObject{²< var $x, $y, $w, $h;²< function __construct($x, $y, $w, $h){²< parent::__construct();²< $this->x = $x;²< $this->y = $y;²< $this->w = $w;²< $this->h = $h;²< }²< ²< function &p1(){²< return $this->p1;²< }²< function &p2(){²< return $this->p2;²< }²< ²< function center(){²< $p = new Point($this->x+$this->w/2, $this->y+$this->h/2);²< return $p;²< }²< ²< function transformPoint($point, $center)²< {²< $p1 = new Point($point->x - $center->x, $point->y-$center->y);²< $p2 = $this->transfo->transformPoint($p1);²< $point->x = $p2->x+$center->x; $point->y = $p2->y+$center->x;²< return $point;²< }²< ²< function bounding_box(){²< list($p1,$p2,$p3,$p4) = $this->transformedPoints();²< $x_min = min($p1->x, $p2->x, $p3->x, $p4->x);²< $y_min = min($p1->y, $p2->y, $p3->y, $p4->y);²< ²< $x_max = max($p1->x, $p2->x, $p3->x, $p4->x);²< $y_max = max($p1->y, $p2->y, $p3->y, $p4->y);²< ²< $x = $x_min; $y=$y_min;²< $w = $x_max-$x_min; $h=$y_max-$y_min;²< ²< return array($x, $y, $w, $h);²< }²< ²< function transformedPoints(){²< $center = $this->center();²< ²< $x = $this->x; $y = $this->y;²< $w = $this->w; $h = $this->h;²< ²< $p1 = new GxPoint($x, $y);²< $p2 = new GxPoint($x+$w, $y);²< $p3 = new GxPoint($x+$w, $y+$h);²< $p4 = new GxPoint($x, $y+$h);²< ²< $p1 = $this->transformPoint($p1, $center);²< $p2 = $this->transformPoint($p2, $center);²< $p3 = $this->transformPoint($p3, $center);²< $p4 = $this->transformPoint($p4, $center);²< ²< return array($p1, $p2,$p3,$p4);²< }²< ²< function clear($da){²< list($x, $y, $w, $h) = $this->bounding_box();²< $da->clear($x, $y, $w, $h);²< }²< ²< function draw($da){²< ²< list($p1,$p2,$p3,$p4) = $this->transformedPoints();²< $da->draw_line($p1,$p2);²< $da->draw_line($p2,$p3);²< $da->draw_line($p3,$p4);²< $da->draw_line($p1,$p4);²< $da->draw_line($p1,$p3);²< $da->draw_line($p2,$p4);²< ²< # draw bounding_box (debug)²< list($x, $y, $w, $h) = $this->bounding_box();²< $da->draw_rectangle($x, $y,$w+1, $h+1);²< }²< }²< ²< class GxPolyLine extends GxObject{²< protected $points;²< ²< function __construct($list= null){²< parent::__construct();²< if($list == null)²< $this->points = array();²< else²< $this->points = $list;²< }²< ²< function add($point){²< $this->points[] = $point;²< }²< ²< function &points(){²< return $this->points;²< }²< }²< ²< class GxDrawingArea extends GtkDrawingArea{²< ²< protected $pixmap = null;²< ²< function __construct(){²< parent::__construct();²< ²< }²< ²< // void draw_arc(GdkGC gc, bool filled, int x, int y, int width, int height, int angle1, int angle2);²< function draw_arc($x, $y, $w, $h, $angle1, $angle2){²< $this->pixmap->draw_arc($this->style->black_gc, true, $x, $y, $w, $h, $angle1, $angle2);²< $this->redraw($x, $y, $w, $h);²< }²< ²< function draw_rectangle($x, $y, $w, $h, $filled=false){²< $this->pixmap->draw_rectangle($this->style->black_gc, $filled, $x, $y, $w, $h);²< $this->redraw($x, $y, $w, $h);²< }²< ²< // MQ : devrait utiliser pango, mais n'est pas encore bien implementé dans php-gtk.²< function draw_text($x, $y, $text, $clear=true){²< # deprecated method ; should use GdkDrawable::draw_layout (with pango)²< $w = 7*strlen($text); $h = 15;²< # if($clear)²< $this->clear($x,$y-$h,$w,$h);²< @$this->pixmap->draw_string($this->my_font, $this->style->black_gc, $x, $y, $text);²< # $this->draw_rectangle($x,$y,$w,$h);²< $this->redraw($x, $y-$h, $w, $h);²< }²< ²< function draw_line($x1, $y1, $x2=null, $y2=null){²< if(is_a($x1, 'GxPoint') && is_a($y1, 'GxPoint')){²< $p1 = $x1;²< $p2 = $y1;²< $x1 = $p1->x();²< $x2 = $p2->x();²< $y1 = $p1->y();²< $y2 = $p2->y();²< }²< $this->pixmap->draw_line($this->style->black_gc, $x1, $y1, $x2, $y2);²< $x = min($x1,$x2);²< $y = min($y1,$y2);²< $w=abs($x2-$x1);²< $h=abs($y2-$y1);²< $this->redraw($x, $y, $w, $h);²< }²< ²< function redraw($x=null, $y=null, $w=null, $h=null){²< if($x == null)²< $this->queue_draw_area(0, 0, $this->w, $this->h);²< else²< $this->queue_draw_area($x, $y, $w, $h);²< }²< ²< function clear($x=null, $y=null, $w=null, $h=null){²< if($x==null){²< $x=0 ; $y=0 ; $w=$this->w ; $h=$this->h;²< }²< $this->pixmap->draw_rectangle($this->style->white_gc, true, $x, $y,$w, $h);²< $this->redraw($x, $y, $w, $h);²< }²< }²< ²< class GxDrawingAreaTest extends GxDrawingArea{²< ²< # tests²< protected $point=null;²< protected $polyline=null;²< protected $rectangle1;²< protected $rectangle2;²< ²< function __construct(){²< ²< parent::__construct();²< ²< $this->connect('expose_event' , array($this, 'expose_event'));²< $this->connect('configure_event' , array($this, 'configure_event'));²< ²< $this->connect('motion_notify_event', array($this, 'motion_notify_event'));²< $this->connect('button_press_event' , array($this, 'button_press_event'));²< ²< $this->set_events(²< Gdk::EXPOSURE_MASK²< | Gdk::LEAVE_NOTIFY_MASK²< | Gdk::BUTTON_PRESS_MASK²< | Gdk::POINTER_MOTION_MASK²< | Gdk::POINTER_MOTION_HINT_MASK);²< ²< # GDK_ALL_EVENTS_MASK²< ²< Gtk::timeout_add(1000, array($this, 'timeout'), 1234);²< $this->rectangle1 = new GxRectangle(150,150, 50, 100);²< $this->rectangle2 = new GxRectangle(300,150, 100, 50);²< $this->count=0;²< $this->scale = 1.1;²< }²< ²< ²< function configure_event($widget, $event)²< {²< $this->w = $widget->allocation->width;²< $this->h = $widget->allocation->height;²< ²< $this->pixmap = new GdkPixmap($widget->window,²< $widget->allocation->width,²< $widget->allocation->height,²< -1);²< $this->pixmap->draw_rectangle($widget->style->white_gc,²< true, 0, 0,²< $widget->allocation->width,²< $widget->allocation->height);²< $this->point = null;²< $this->polyline = new GxPolyLine();²< # $this->my_font = new GdkFont("-adobe-helvetica-bold-r-normal--12-120-75-75-p-70-iso8859-1");²< $this->my_font = $this->style->get_font();²< $x = $widget->allocation->width/2;²< $y = 15;²< $this->draw_text($x, $y, 'Php-Gtk2 - Drawing Area sample test');²< return true;²< }²< ²< function draw_brush($x, $y)²< {²< $this->draw_arc($x - 4, $y - 4, 8, 8, 0, 64 * 360);²< }²< ²< function timeout(){²< ²< # MQ : should clear the right area, not full window²< # $this->clear();²< ²< ²< # display analog clock.²< Gtk::timeout_add(500, array($this, 'timeout'), 1234);²< $date = date('H:i:s');²< $this->draw_text(15,15, $date);²< ²< $this->count++;²< if($this->count % 20 == 1){²< $this->scale = 1/$this->scale;²< }²< ²< $this->rectangle1->clear($this);²< $this->rectangle1->rotate(3);²< # $this->rectangle1->scale($this->scale);²< # $this->rectangle1->translate(5,5);²< $this->rectangle1->draw($this);²< ²< ²< # $this->rectangle2->rotate(-6);²< # $this->rectangle2->scale(1/$this->scale);²< # $this->rectangle2->draw($this);²< ²< }²< ²< function expose_event($widget, $event)²< {²< $widget->window->draw_drawable($widget->style->fg_gc[$widget->state],²< $this->pixmap,²< $event->area->x, $event->area->y,²< $event->area->x, $event->area->y,²< $event->area->width, $event->area->height);²< ²< return false;²< }²< ²< ²< ²< function button_press_event($widget, $event)²< {²< ²< if ($event->button == 1 && $this->pixmap) {²< # $this->draw_brush($widget, (int)$event->x, (int)$event->y);²< $this->draw_rectangle((int)$event->x, (int)$event->y, 10, 10);²< $info = sprintf('(%d:%d)', $event->x, $event->y);²< $this->draw_text((int)$event->x+15, (int)$event->y-15, $info);²< if($this->point != null){²< $p = new GxPoint($event->x, $event->y);²< # $this->draw_line($event->x, $event->y, $this->point->x(), $this->point->y());²< $this->draw_line($p, $this->point);²< }²< $this->point = new GxPoint($event->x, $event->y);²< $this->polyline->add($this->point);²< }²< ²< return true;²< }²< ²< function motion_notify_event($widget, $event)²< {²< $window = $event->window;²< $pointer = $window->get_pointer();²< $x = $pointer[0];²< $y = $pointer[1];²< $state = $pointer[2];²< ²< if (($state & Gdk::BUTTON1_MASK) && $this->pixmap) {²< $this->draw_brush($x, $y);²< }²< ²< return true;²< }²< }²< ²< ²< class App extends GtkWindow²< {²< ²< function __construct($parent = null)²< {²< parent::__construct();²< ²< $this->connect_simple('destroy', array('gtk', 'main_quit'));²< ²< $this->set_title(__CLASS__);²< $this->set_position(Gtk::WIN_POS_CENTER);²< $this->set_default_size(-1, -1);²< $this->set_border_width(8);²< ²< $this->add($this->__create_box());²< $this->show_all();²< }//function __construct($parent = null)²< ²< ²< ²< function __create_box()²< {²< $vbox = new GtkVBox();²< $vbox->show();²< ²< $drawing_area = new GxDrawingAreaTest();²< $drawing_area->set_size_request(500, 500);²< $vbox->pack_start($drawing_area);²< // $drawing_area->realize();²< ²< ²< return $vbox;²< }//function __create_box()²< }//class Scribble extends GtkWindow²< ²< ²< $app = new App();²< Gtk::main();²< ²< ?>²< ²< [[include:Main/CodeTableEnd]]²---²> Describe DrawingArea here.²\ No newline at end of file²
author=Marc Quinton
author:1149858701=Marc Quinton
host:1149858701=143.196.162.107
name=CodeSnippets.DrawingArea
host=82.234.62.122
agent=Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.12) Gecko/20060216 Debian/1.7.12-1.1ubuntu2
rev=5
diff:1149859045:1149858701:=7c7,8²< * here is a snapshot : http://quinton.free.fr/php/gtk/wiki/drawing_area.png²---²> ²> ²
author:1149859045=Marc Quinton
host:1149859045=143.196.162.107
diff:1149859174:1149859045:=7c7²< * here is a snapshot : [[http://quinton.free.fr/php/gtk/wiki/drawing_area.png]]²---²> * here is a snapshot : http://quinton.free.fr/php/gtk/wiki/drawing_area.png²
author:1149859174=Marc Quinton
host:1149859174=143.196.162.107
diff:1150205038:1149859174:=8d7²< * a more complete library can be found at : http://quinton.free.fr/php/gtk/gxlib/²
author:1150205038=Marc Quinton
host:1150205038=143.196.162.107
diff:1150733709:1150205038:=8c8²< * a more complete library can be found at : http://quinton.free.fr/php/gtk/gxlib/ ; there is now a near working brick-breaker game included as tutorial and proof of concept with this library.²---²> * a more complete library can be found at : http://quinton.free.fr/php/gtk/gxlib/²
author:1150733709=Marc Quinton
host:1150733709=82.234.62.122