Location: PHPKode > scripts > Menu Icon > menu-icon/class-menu.php
<?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();
  }
}
?>
Return current item: Menu Icon