<?php
/**
* easy way to create menu with optionnal icons
* @author Jonathan Gotti <nathan at the-ring dot homelinux dot net>
* @copyleft (l) 2003-2004 Jonathan Gotti
* @package GUI
* @subpackage extended widgets
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @date 2004-06-08
* @changelog 2005-04-05 now add_menu_item() accept underscored string as additional accelkey (see $label param)
* 2005-01-02 (by Brian) now accel key is still available in the label even when adding an icon
* 2004-10-09 add support for array(gdkpixmap,gdkmask) AND xpmdatas
* 2004-08-12 now menuitem with shortcuts and no parents are attached to the ALT modifier key
* instead of CTRL (because that's the default behaviour in most modern apps)
* 2004-07-01 now support checkmenuitem new ensure unique keyid for items
*/
class menu{
var $bar;
/** the gdkwindow used to create pixmaps */
var $gdkwindow;
/** the accel group to manage accelkeys */
var $accel_group;
/** used for easy access to menus */
var $menus;
/** used for easy access to menuitems */
var $items;
/**
*constructor function
*@param gdkwindow $gdkwindow
*@param gtkaccelgroup $accel_group
*@return menu object
**/
function menu($gdkwindow=null,$accel_group=null){
if(is_a($gdkwindow,'gdkwindow'))
$this->gdkwindow = &$gdkwindow;
$this->bar = &new GtkMenuBar();
$this->bar->set_shadow_type(GTK_SHADOW_ETCHED_IN);
if(is_a($accel_group,'GtkAccelGroup')){
$this->accel_group = &$accel_group;
}else{
$this->accel_group = &new GtkAccelGroup();
}
# showvar($GLOBALS['MAIN']);
}
/**
*add an handlebox as box propertie
*and pack the bar into it so you will need to pack $this->box instead of $this->bar
*/
function add_handlebox(){
$this->box = &new Gtkhandlebox();
$this->box->add($this->bar);
}
/**
*will add a separator to $parent menu
*@param string $parent the parent menu keyindex
*/
function add_sep($parent){
$this->add_menu_item('SEP',$parent);
}
/**
*add an item to the menu
*@param string $key is the keyindex to acces the item inside the objects
*@param string $parent the parent's keyindex
*@param mixed $label the text to display for this item
* (can be null to get a separator or an array
* array(string label, key_symbol accelkey | string underscored key ('_k') [,GdkModifierType]) )
*@param mixed $callback the function name or array(object,methodname) to call on select
*@param string $imgfile optionnal file path to an icon
* (ADD support to array(gdkpixmap,gdkmask) and xpmdatas at 2004-10-09)
*@param bool $sensitive
*@param bool $is_checkmenuitem
*@param bool $is_checked
*/
function add_menu_item($key,$parent,$label=null,$callback=null,$imgfile=null,
$sensitive=TRUE,$is_checkmenuitem=FALSE,$is_checked=FALSE){
while($this->items[$key]){ # ensure a unike keyid
preg_match("!(\d+)$!",$key,$m);
$int=$m[1];
if(is_numeric($int))
$key = substr($key,0,- strlen($int)).($int+1);
else
$key.='1';
}
if( (!$label)&& $this->menus[$parent]){
$this->items[$key] = &new gtkmenuitem();
$this->items[$key]->set_sensitive(FALSE);
$this->menus[$parent]->append($this->items[$key]);
return;
}elseif(is_array($label)){
$acckey = $label[1];
if(count($label)==3)
$modifier = $label[2];
$label = $label[0];
}
if(!$is_checkmenuitem){
$this->items[$key]= &new gtkmenuitem($label);
}else{
$this->items[$key]= &new gtkcheckmenuitem($label);
$this->items[$key]->set_active($is_checked);
}
$lb = $this->items[$key]->child;
# add icon if needed
if(is_string($imgfile) && file_exists($imgfile)){
$this->check_gdkwindow();
if($img = Gdk::pixmap_create_from_xpm($this->gdkwindow,null,$imgfile)){
$img = &new GtkPixmap($img[0], $img[1]);
$this->items[$key]->remove($lb);
$box = &new gtkhbox();
$box->pack_start($img,0,0,2);
$box->pack_start($lb,1,1,2); # bryan changed to keep accelkey displayed
$this->items[$key]->add($box);
}
}elseif(is_array($imgfile)){ # add support for array(gdkpixmap,gdkmask) AND xpmdatas 2004-10-09
if(count($imgfile)>2){ # assume we have xpmdatas
$this->check_gdkwindow();
$imgfile = Gdk::pixmap_create_from_xpm_d($this->gdkwindow,null,$imgfile);
}
if($img = &new gtkpixmap($imgfile[0], $imgfile[1])){
$this->items[$key]->remove($lb);
$box = &new gtkhbox();
$box->pack_start($img,0,0,2);
$box->pack_start($lb,1,1,2);
$this->items[$key]->add($box);
}
}
if(!$sensitive)# forgotten sensitivity check (2004-12-18)
$this->items[$key]->set_sensitive(FALSE);
# adding to parent menu
if(!$parent){
$this->bar->append($this->items[$key]);
}else{
if(! $this->items[$parent]){
echo "[ERROR] menu::add_menu_item to non-existent parent '$parent'\n";
return FALSE;
}
if(! $this->menus[$parent]){
$this->menus[$parent] = &new GtkMenu();
$this->items[$parent]->set_submenu($this->menus[$parent]);
}
$this->menus[$parent]->append($this->items[$key]);
}
# add accellkey if needed
if(substr_count($label,'_')||$acckey){
if(! isset($acckey) ){
$acckey = $lb->parse_uline($label);
}elseif(is_string($acckey)){ # 2005-04-05 now accept underscored string as accelkey
$acckey = $lb->parse_uline($acckey);
$lb->set_text($label);
}
if(! isset($modifier)){
if($parent===null && $callback===null){
$this->items[$key]->add_accelerator('activate_item',$this->accel_group,
$acckey,GDK_MOD1_MASK,GTK_ACCEL_VISIBLE);
}else{
$this->items[$key]->add_accelerator('activate',$this->accel_group,
$acckey,GDK_CONTROL_MASK,GTK_ACCEL_VISIBLE);
}
}else{
$this->items[$key]->add_accelerator('activate',$this->accel_group,
$acckey,$modifier,GTK_ACCEL_VISIBLE);
}
}
#connect to callback
if($callback)
$this->items[$key]->connect('activate',$callback,$key);
}
/**
* more complex menuitem connection to improve usability
* still offer only the activate signal support
* @since 2005-01-28
* @param string $itemkey the menuitem key of the menuitem you want to connect
* @param mixed $vars pass as many parameter to the callback function as you need
* (exactly as a normal connect)
* @todo never tested so test this method
*/
function on_activate_item($itemkey){
# get all additional vars
for($i=1;$i<func_num_args();$i++){
$args[$i]= &func_get_arg($i);
$str .= '$args['.$i.'],';
}
$str = substr($str,0,-1);
eval('$cb = $this->entry->connect("activate",'.$str.');');
return $cb;
}
/**
*@access private
*/
function check_gdkwindow(){
if(! $this->gdkwindow){
$this->bar->realize();
$this->gdkwindow = $this->bar->window;
}
}
function destroy(){
if($this->box)
$this->box->destroy();
else
$this->bar->destroy();
}
}
?>