rendered paste body<?php
error_reporting(E_ALL);
$icon_handle_xpm = array(
"16 8 3 1",
" c None",
". c #606060",
"+ c #FFFFFF",
" ",
" ",
" . . . . . ",
" + + + + + ",
" ",
" . . . . . ",
" + + + + + ",
" "
);
class HandleIcon extends GtkImage{
public function __construct($icon_data = null){
parent::__construct();
if($icon_data == null){
global $icon_handle_xpm;
$icon_data = $icon_handle_xpm;
}
$this->set_from_pixbuf(GdkPixbuf::new_from_xpm_data($icon_data));
}
}
class Button extends GtkEventBox{
protected $label;
protected $callbacks;
public function __construct($label){
parent::__construct();
$this->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse('#EEE'));
$this->label = new GtkLabel($label);
$this->add($this->label);
$this->label->modify_font(new PangoFontDescription('Sans Bold 6'));
$this->add_events(Gdk::BUTTON_PRESS_MASK);
$this->connect('button-press-event', array($this, 'button_press_event'));
$this->callbacks = array();
}
public function connect($signal, $callback){
if($signal == 'clicked'){
$this->callbacks[] = $callback;
}
else
parent::connect($signal, $callback);
}
public function button_press_event($selft, $event){
foreach($this->callbacks as $callback){
call_user_func($callback, $event);
}
return true;
}
}
class MovableWidget extends GtkEventBox{
protected $clic_point;
public function __construct(){
parent::__construct();
$this->add_events(Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK);
$this->connect('motion-notify-event', array($this, 'motion_notify_event'));
$this->connect('button-press-event', array($this, 'button_press_event'));
$this->click_point = null;
}
public function button_press_event($w, $event){
$this->get_parent()->move_top($this);
$this->click_point = array( 'x'=> $event->x, 'y'=> $event->y);
}
public function motion_notify_event($w, $event){
# no button press
if($event->state == 0)
return;
# track new position and move object
$x = $this->allocation->x + $event->x - $this->click_point['x'];
$y = $this->allocation->y + $event->y - $this->click_point['y'];
$this->get_parent()->move($this, $x, $y);
}
}
class ArchitectClassWidget extends MovableWidget{
protected $_name;
protected $properties;
protected $vbox;
protected $frame;
protected $properties_box;
protected $expended = true;
protected $id;
static $id_counter = 0;
public function __construct($name, $properties){
parent::__construct();
$this->_name = $name;
$this->properties = $properties;
$this->frame = new GtkFrame();
$this->add($this->frame);
$this->vbox = new GtkVbox();
$this->frame->add($this->vbox);
$prop_event_box = new GtkEventbox();
$this->vbox->pack_end($prop_event_box);
$prop_event_box->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse('#DDD'));
$this->properties_box = new GtkVbox();
$prop_event_box->add($this->properties_box);
$this->buildTitle($this->vbox, $name);
$this->setProperties($this->properties_box, $properties);
$this->set_size_request(150, -1);
$this->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse('#aaa'));
$this->id = ArchitectClassWidget::$id_counter++;
}
protected function buildTitle($parent, $title){
$hbox = new GtkHbox(); # title bar box
$parent->pack_start($hbox);
$hbox->pack_end($button = new Button('X'), false, false);
$button->connect('clicked', array($this, 'on_button_close'));
$hbox->pack_end($button = new Button('^'), false, false);
$button->connect('clicked', array($this, 'on_button_expand'));
global $icon_handle_xpm;
$handle = new HandleIcon();
$hbox->pack_start($handle, false, false);
$handle = new HandleIcon();
$hbox->pack_end($handle, false, false);
$hbox->pack_start($label = new GtkLabel($title), false, true);
$label->modify_font(new PangoFontDescription('Sans Bold 8'));
}
public function on_button_close(){
echo "ArchitectClassWidget::on_button_close()\n";
$this->get_parent()->link_remove($this);
$this->destroy();
}
public function on_button_expand(){
if($this->expended)
$this->properties_box->hide();
else
$this->show_all();
$this->expended = !$this->expended;
}
protected function setProperties($parent, $properties){
# remove existing labels.
foreach($parent->get_children() as $child)
$parent->remove($child);
foreach($properties as $key=>$prop){
$label = new GtkLabel();
$desc = sprintf('%s:%s', $key, $prop);
$label->set_markup($desc);
$label->set_justify(Gtk::JUSTIFY_LEFT);
$parent->pack_start($label, false, false);
}
}
public function center(){
$center = new stdClass();
$center->x = $this->allocation->x + intval($this->allocation->width/2);
$center->y = $this->allocation->y + intval($this->allocation->height/2);
return ($center);
}
function id(){
return $this->id;
}
}
class ArchitectWindow extends GtkFixed{
protected $links;
protected $widget;
public function __construct(){
parent::__construct();
$this->add_events(Gdk::EXPOSURE_MASK|Gdk::BUTTON_PRESS_MASK);
$this->connect('expose-event', array($this, 'expose_event'));
$this->connect('button-press-event', array($this, 'button_press_event'));
$this->links = array();
$this->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse("#000"));
}
public function move_top($w){
$pos = $w->allocation;
$this->remove($w);
$this->put($w,$pos->x,$pos->y);
}
public function add_link($w1, $w2){
$this->links[] = array($w1, $w2);
if(!isset($this->widgets[$w1->id()])){
$this->widgets[$w1->id()] = $w1;
}
if(!isset($this->widgets[$w2->id()])){
$this->widgets[$w2->id()] = $w2;
}
}
public function link_remove($widget){
foreach($this->widgets as $w){
if($w->id() == $widget->id())
unset($this->widgets[$widget->id()]);
}
foreach($this->links as $key=>$link){
if($link[0]->id() == $widget->id() || $link[1]->id() == $widget->id())
unset($this->links[$key]);
}
}
public function expose_event($self, $event){
if($event->count != 0)
return;
foreach($this->links as $link){
$p1 = $link[0]->center();
$p2 = $link[1]->center();
$this->window->draw_line($this->style->black_gc, $p1->x, $p1->y, $p2->x, $p2->y);
}
}
public function button_press_event($self, $event){
echo "ArchitectWindow::button_press_event()\n";
list($w1, $w2) = $this->links[0];
print_r($w1->window);
}
}
// Create a new window.
$window = new GtkWindow();
// Properly handle closing of the window.
$window->connect_simple('destroy', array('Gtk', 'main_quit'));
$architect = new ArchitectWindow();
$window->add($architect);
$core = new ArchitectClassWidget('Core', $properties = array('id' => 'integer', 'name' => 'char'));
$architect->put($core, 150, 10);
$customer = new ArchitectClassWidget('Customer', $properties = array('name' => 'char'));
$architect->put($customer, 80, 70);
$article = new ArchitectClassWidget('Article', $properties = array('desc' => 'char'));
$architect->put($article, 235, 70);
$properties = array(
'x' => 'integer',
'y' => 'integer',
'w' => 'integer',
'h' => 'integer',
'background' => 'char',
'foreground' => 'char',
'font' => 'char',
'h' => 'integer',
'desc' => 'char'
);
$big = new ArchitectClassWidget('BigObject', $properties);
$architect->put($big, 10, 130);
$architect->add_link($core, $customer);
$architect->add_link($core, $article);
$architect->add_link($customer, $big);
$window->set_size_request(400, 300);
$window->set_position(Gtk::WIN_POS_CENTER);
$window->show_all();
Gtk::main();
?>