mirror of
https://github.com/php/php-gtk-src.git
synced 2026-03-24 17:22:10 +01:00
187 lines
5.3 KiB
PHP
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();
|
|
?>
|
|
|
|
|
|
|
|
|