rendered paste body<?php error_reporting(E_ALL);class Actions { protected $actions; function __construct(){ } function add($name, $label, $tooltip, $stock_id){ # key array is $name; $name is for the programmer. $this->actions[$name] = new GtkAction($name, $label, $tooltip, $stock_id); } function get($key){ if(!isset($this->actions[$key])){ trigger_error('action not found :' . $key); return null; } return $this->actions[$key]; } function exists($key){ return isset($this->actions[$key]); } function create_tool_item($key){ if(!isset($this->actions[$key])){ trigger_error('can create tool item ; action not found :' . $key); return null; } $tooltips = Tooltips::instance(); $action = $this->get($key); $widget = $action->create_tool_item(); $tooltips->set_tip($widget, $action->get_property('tooltip')); return $widget; } function create_menu_item($key){ if(!isset($this->actions[$key])){ trigger_error('can create menu item ; action not found :' . $key); return null; } $tooltips = Tooltips::instance(); $action = $this->get($key); $widget = $action->create_menu_item(); $tooltips->set_tip($widget, $action->get_property('tooltip')); return $widget; } public function connect($signal, $function, $userdata=null){ foreach($this->actions as $action){ $action->connect($signal, $function, $userdata); } } public function connect_simple($signal, $function, $userdata=null){ foreach($this->actions as $action){ $action->connect_simple($signal, $function, $userdata); } }}## for sources see Callicore project :# http://callicore.net/# http://websvn.bluga.net/wsvn/Callicore/desktop/trunk/?rev=0&sc=0#class Tooltips extends GtkTooltips{ /** * singleton instance for this class * @var $singleton instanceof Tooltips */ static protected $singleton; /** * switches on to allow construct to occur * @var $check bool */ static protected $check = FALSE; /** * public function __construct * * @return void */ public function __construct() { if(self::$check == FALSE) { throw new Exception('Tooltips is a singleton class - use Tooltips::instance() to retrieve the current object'); } self::$singleton = $this; parent::__construct(); self::$singleton = $this; $this->set_delay(500); $this->enable(); } /** * public function set_tip * * overrides original function and does gettext, also * fixes tooltips for GtkToolItem stuff * * @param object $wiget instanceof GtkObject * @return void */ public function set_tip($widget, $tooltip) { if($widget instanceof GtkToolItem) { $widget->set_tooltip($this, $tooltip); } else { parent::set_tip($widget, $tooltip); } return; } /** * static public function instance * * this is how you "construct" a Tooltips object * * @return object instanceof Tooltips */ static public function instance() { if(is_null(self::$singleton)) { self::$check = TRUE; self::$singleton = new Tooltips(); self::$check = FALSE; } return self::$singleton; } /** * public function __clone() * * disable cloning of a singleton * * @return void */ public function __clone() { throw new Exception(Writer::i18n('Cannot clone singleton object %s', 'Tooltips')); return; }}/** * Toolbar class extended from GtkToolbar * * - builds buttons from a description array * - description array can take attributes : (label, tip, icon) * - array keys are used by programmer for switching in signal callbacks, * - tooltips are build * - you can registrer to "clicked" signal just as if it was toolbar that was clicked. * * public methods : * - __construct($specs) : builds a Toolbar with specs array. * - connect($signal, $func, $userdata), * - connect_simple($signal, $func, $userdata) : overrides GtkToolbar signal registration * handles "clicked" signal internaly * * protected methods : * signals : * * - "clicked" : this signal is emited (relayed) from toolbar buttons. * callback signature : void function function ($toolbar, $button_id, $userdata=null) * * specs array format : * * $spec = array('File', 'Open', 'Quit'); # simple format * * $spec = array( * 'File' => array( * 'label' => 'your label' * 'tip' => 'your tip info' * 'icon' => Gtk::STOCK_* icon or a image file * ); * * if icon is not a stock icon and not a regular file, it defaults to Gtk::STOCK_MISSING_IMAGE * * */class Toolbar extends GtkToolbar{ protected $specs; protected $buttons; protected $signal; protected $actions; function __construct($specs, $actions=null){ parent::__construct(); $this->specs = $specs; $this->buttons = array(); $this->actions = $actions; $this->buildUI($specs, $this->actions); } /** * construct toolbar managed objects (GtkToolButton) * */ protected function buildUI($specs, $actions){ static $count=0; # count buttons group; add a toolbar space if not first group. foreach($specs as $group_key=>$group){ if($count>0) $this->insert(new GtkSeparatorToolItem(), -1); foreach($group as $_key=>$item){ $action = $actions->get($item); if($actions->exists($item)){ $button = $actions->create_tool_item($item); $this->insert($button, -1); } else { # setup default values $key = $_key; $label = $_key; $icon = $_key; $tip = $_key; # create a default button $button = $this->buttons[$key] = $this->create_button($label, $icon, $tip); $this->insert($button, -1); } } $count++; } } /** * Create toolbar buttons with rigth parameters (label, icon, tip) * and register tooltip feature. * */ protected function create_button($label, $icon, $tip, $use_stock_image=true){ $tooltips = Tooltips::instance(); # this does not work ; need to be a global variable or a singleton instance. # $tooltips = new GtkTooltips(); if(file_exists($icon)){ $img = GtkImage::new_from_file($icon); $button = new GtkToolButton($img, $label); $button->set_tooltip($tooltips, $tip); } else { $stock_image_name = 'Gtk::STOCK_'.strtoupper($icon); if(!defined($stock_image_name)) $stock_image_name = 'Gtk::STOCK_MISSING_IMAGE'; $button = GtkToolButton::new_from_stock(constant($stock_image_name)); $button->set_label($label); $button->set_tooltip($tooltips, $tip); } return $button; } /** * public function connect($signal, $func, $userdata=null) * * if signal is "clicked", need to setup a callback with this signature * * void function callback($toolbar, $button_id, $userdata=null) * * else give signal registration to parent (GtkToolbar class) */ public function connect($signal, $func, $userdata=null){ # build a "relay" for signal callback ; # the goal is to call a callback with user-defined context if($signal == 'clicked'){ $_userdata = array( 'userdata' => &$userdata, 'func' => &$func ); foreach($this->buttons as $key=>$button){ $_userdata['button'] = $key; $button->connect($signal, array($this, 'button_signal_clicked') , $_userdata); } } else parent::connect($signal, $func, $userdata); } /** * see connect method below. * */ public function connect_simple($signal, $func, $userdata=null){ if($signal == 'clicked'){ $_userdata = array( 'userdata' => &$userdata, 'func' => &$func ); foreach($this->buttons as $button){ $_userdata['button'] = $key; $button->connect_simple($signal, array($this, 'button_signal_clicked'), $_userdata); } } else parent::connect_simple($signal, $func, $userdata); } /** * call user callback with signature : * void function callback($toolbar, $button_id, $userdata=null) * * note : this method should be protected but can be called if protected outside of this class. * */ public function button_signal_clicked($toolbar, $userdata){ # call user callback with right parametrers $userdata['func']($toolbar, $button_id=$userdata['button'], $userdata['userdata']); }}class Menubar extends GtkMenubar{ protected $specs; protected $actions; function __construct($specs, $actions){ parent::__construct(); $this->specs = $specs; $this->actions = $actions; $this->buildUI($specs, $actions); } protected function buildUI($specs, $actions){ }}class App extends GtkWindow{ protected $menubar; protected $toolbar; protected $statusbar; protected $actions; function __construct(){ parent::__construct(); $this->buildUI(); $this->main_window_setup(); $this->initial_setup(); $this->show_all(); } protected function buildUI(){ $this->actions_initialize(); $this->menubar = $this->create_menubar($this->actions); $this->toolbar = $this->create_toolbar($this->actions); $this->statusbar = new GtkStatusbar(); $vbox = new GtkVbox; $this->add($vbox); $vbox->pack_start($this->menubar, 0, 0); $vbox->pack_start($this->toolbar, 0, 0); $vbox->pack_end($this->statusbar, 0, 0); } # user defines setup; protected function initial_setup(){ # set Cut, Paste unsensitive $this->actions->get('edit_cut')->set_sensitive(false); $this->actions->get('edit_paste')->set_sensitive(false); } protected function main_window_setup(){ $this->set_title('App class test'); $this->set_size_request(600, 500); $this->connect_simple('destroy', array($this, 'on_destroy')); $this->set_position(Gtk::WIN_POS_CENTER); } protected function actions_initialize(){ $this->actions = new Actions(); # actions manager. # in order : name, Label, tooltip, stock_icon; $this->actions->add('file_new', 'New', 'New', Gtk::STOCK_NEW); $this->actions->add('file_open', 'Open', 'Open ...', Gtk::STOCK_OPEN); $this->actions->add('file_close', 'Close', 'Close', Gtk::STOCK_CLOSE); $this->actions->add('file_quit', 'Quit', 'Quit', Gtk::STOCK_QUIT); $this->actions->add('edit_cut', 'Cut', 'Cut', Gtk::STOCK_CUT); $this->actions->add('edit_copy', 'Copy', 'Copy', Gtk::STOCK_COPY); $this->actions->add('edit_paste', 'Paste', 'Paste', Gtk::STOCK_PASTE); } protected function create_menubar(&$actions){ $specs = array( 'file' => array('file_new', 'file_open', 'file_close', '---', 'file_quit'), 'edit' => array('edit_cut', 'edit_copy', 'edit_paste') ); $menubar = new Menubar($specs, $this->actions); return $menubar; } protected function create_toolbar(&$actions){ $specs = array( 'file' => array('file_new', 'file_open', 'file_close', 'file_quit'), 'edit' => array('edit_cut', 'edit_copy', 'edit_paste') ); return new Toolbar($specs, $this->actions); } public function on_destroy(){ Gtk::main_quit(); } # user callback synopsys : void function action_activate($action, $action_name, $userdata=null) public function connect($signal, $func, $userdata=null){ if($signal == 'activate'){ $_userdata = array( 'userdata' => &$userdata, 'func' => &$func, ); return $this->actions->connect($signal, array($this, 'on_activate'), $_userdata); } return parent::connect($signal, $function, $userdata); } public function on_activate($action, $userdata){ # call user callback with right parametrers $userdata['func']($action, $action->get_name(), $userdata['userdata']); }}$app = new App();$app->connect('activate', 'action_activate', null);Gtk::main();function action_activate($action, $action_name, $userdata=null){ echo "action activate : $action_name\n"; if($action_name== 'file_quit') Gtk::main_quit();}?>