Files
php-gtk-src/demos/examples/cairo_support.php
2008-07-31 15:05:03 +00:00

187 lines
5.3 KiB
PHP

<?php
class Clock extends GtkDrawingArea {
public $__gsignals = array(
'time_changed' => array(
GObject::SIGNAL_RUN_FIRST, GObject::TYPE_NONE,
array(GObject::TYPE_LONG, GObject::TYPE_LONG)
),
);
private $time;
private $minute_offset = 0;
private $dragging = false;
public function __construct() {
parent::__construct();
$this->connect('expose-event', array($this, 'expose'));
$this->connect('button-press-event', array($this, 'button_press'));
$this->connect('button-release-event', array($this, 'button_release'));
$this->connect('motion-notify-event', array($this, 'motion_notify'));
$this->add_events(Gdk::BUTTON_PRESS_MASK |
Gdk::BUTTON_RELEASE_MASK |
Gdk::POINTER_MOTION_MASK);
$this->update();
Gtk::timeout_add(1000, array($this, 'update'));
}
public function expose($widget, $event) {
$context = $this->window->cairo_create();
$context->rectangle($event->area->x, $event->area->y,
$event->area->width, $event->area->height);
$context->clip();
$this->draw($context);
}
public function update() {
$this->time = getdate();
$this->redraw_canvas();
return true;
}
protected function redraw_canvas() {
if($this->window) {
$alloc = $this->get_allocation();
$rect = new GdkRectangle($alloc->x, $alloc->y, $alloc->width, $alloc->height);
$this->window->invalidate_rect($rect, true);
$this->queue_draw_area($alloc->x, $alloc->y, $alloc->width, $alloc->height);
$this->window->process_updates(true);
}
}
public function motion_notify($widget, $event) {
if($this->dragging) {
$x =$event->x - ($this->get_allocation()->width / 2);
$y = $event->y - ($this->get_allocation()->height / 2);
$phi = atan2($x, -$y);
if($phi < 0) {
$phi += pi() * 2;
}
$hour = $this->time['hours'];
$minute = $phi * 30 / pi();
$this->minute_offset = $minute - $this->time['minutes'];
$this->redraw_canvas();
$this->emit('time_changed', $hour, $minute);
}
}
public function button_press($widget, $event) {
$minutes = $this->time['minutes'] + $this->minute_offset;
$px = $event->x - $widget->get_allocation()->width / 2;
$py = $widget->get_allocation()->height / 2 - $event->y;
$lx = sin(pi() / 30 * $minutes);
$ly = cos(pi() / 30 * $minutes);
$u = $lx * $px + $ly * $py;
if ($u < 0)
return;
$d2 = pow($px - $u * $lx, 2) + pow($py - $u * $ly, 2);
if(d2 < 25) {
$this->dragging = true;
echo "got minute hand\n";
}
}
public function button_release($widget, $event) {
if($this->dragging) {
$this->motion_notify($widget, $event);
$this->dragging = false;
}
}
public function draw($context) {
$rect = $this->get_allocation();
$x = $rect->x + $rect->width / 2.0;
$y = $rect->y + $rect->height / 2.0;
$radius = min($rect->width / 2.0, $rect->height / 2.0) - 5;
// clock background
$context->arc($x, $y, $radius, 0, 2.0 * pi());
$context->setSourceRgb(1, 1, 1);
$context->fillPreserve();
$context->setSourceRgb(0, 0, 0);
$context->stroke();
// clock ticks
foreach(range(1, 12) as $i) {
$context->save();
if($i % 3 == 0) {
$inset = 0.2 * $radius;
} else {
$inset = 0.1 * $radius;
$context->setLineWidth(0.5 * $context->getLineWidth());
}
$context->moveTo($x + ($radius - $inset) * cos($i * pi() / 6.0),
$y + ($radius - $inset) * sin($i * pi() / 6.0));
$context->lineTo($x + $radius * cos($i * pi() / 6.0),
$y + $radius * sin($i * pi() / 6.0));
$context->stroke();
$context->restore();
}
// clock hands
$hours = $this->time['hours'];
$minutes = $this->time['minutes'] + $this->minute_offset;
$seconds = $this->time['seconds'];
// hour hand
//the hour hand is rotated 30 degrees (pi/6 r) per hour + 1/2 a degree (pi/360) per minute
$context->save();
$context->setLineWidth(2.5 * $context->getLineWidth());
$context->moveTo($x, $y);
$context->lineTo($x + $radius / 2 * sin(
pi() / 6 * $hours + pi() / 360 * $minutes),
$y + $radius / 2 * - cos(
pi() / 6 * $hours + pi() / 360 * $minutes));
$context->stroke();
$context->restore();
// minute hand
// the minute hand is rotated 6 degrees (pi/30 r) per minute
$context->moveTo($x, $y);
$context->lineTo($x + $radius * 0.75 * sin(pi() / 30 * $minutes),
$y + $radius * 0.75 * - cos(pi() / 30 * $minutes));
$context->stroke();
// seconds hand
$context->save();
$context->setSourceRgb(1, 0, 0); // red
$context->moveTo($x, $y);
$context->lineTo($x + $radius * 0.7 * sin(pi() / 30 * $seconds),
$y + $radius * 0.7 * - cos(pi() / 30 * $seconds));
$context->stroke();
$context->restore();
}
}
Gobject::register_type('Clock');
function time_changed_cb($widget, $hours, $minutes) {
echo "time-changed - $hours:$minutes\n";
}
$window = new GtkWindow();
$clock = new Clock();
$window->add($clock);
$window->connect_simple('destroy', array('Gtk', 'main_quit'));
$clock->connect('time_changed', 'time_changed_cb');
$window->show_all();
Gtk::main();
?>