Extending GtkMenu class for Popup menu dialog

GtkWidget popup menu example Here is a quick way to build a popup menu supporting event registration from a GtkWidget. Menu items are passed to the class constructor as a list of labels. This class emits activate signals with full context (x,y coordinates, button ...).

See example below for basic usage.

Details

  1. create Gtk standard stuff,
  2. create a Popup menu in a single a simple line with 3 items (Edit, Cut, Paste),
  3. connect an "activate" callback
  4. some items can be unsensitive depending on application context,
  5. set parent widget ; this widget must contain a Window to register some buttons events. No warning about that in this current code, but could be done,
  6. look at activate callback ; complete event context is available, containing (x,y) coordinates ; may be usefull in some usages.

Example

<?php
# include class code here


// Create a normal window
$wnd = new GtkWindow();  // note 1

$menu = new PopupMenu($menu = array('Edit', 'Cut', 'Paste')); // note 2
$menu->connect('activate', 'activate_callback');              // note 3
$menu->set_sensitive('Cut', false);                           // note 4
$menu->set_parent($wnd);                                      // note 5


// Standard stuff // note 1
$wnd->connect_simple('destroy', array('Gtk', 'main_quit'));
$wnd->show_all();
Gtk::main();

function
activate_callback($signal_name, $context, $user_data) { // note 6
 
$reason = $context['key'];
  echo
"popup activate : $reason\n";
 
# print_r($context);
}
?>

Class code source

<?php
class PopupMenu extends GtkMenu {
  protected
$items;
  protected
$menu_items;
  protected
$signal;
  protected
$parent_widget;

  function
__construct($items, $parent_widget=null) {
   
parent::__construct();
   
$this->items = $items;
   
$this->menu_items = array();
   
$this->parent_widget = $parent_widget;
   
$this->signal = new Gnope_FileExplorer_Signal();
   
$this->build($items);
  }

  protected function
build($items) {
    foreach(
$items as $item){
     
# key and label may be different ...
     
$label = $item;
     
$key = $item;
     
$this->append($key, $label);
    }

    if(
$this->parent_widget != null)
      
$this->set_parent($this->parent_widget);

   
$this->show_all();
  }

 
/**
   *
   * Set parent handler for popup window ;
   * - set event mask to receive button_press_mask,
   * - and register signal "button-press-event".
   *
   */
  
public function set_parent($parent_widget){
    
$this->parent_widget = $parent_widget;
    
$this->parent_widget->set_events(
       
$this->parent_widget->get_events() | Gdk::BUTTON_PRESS_MASK);
    
$this->parent_widget->connect('button-press-event', array($this, 'popup'), $this);
   }

 
/**
    * append a GtkMenuitem to this widget ;
    *
    */
 
public function append($key, $label) {
   
$this->menu_items[$key] = new GtkMenuItem($label);
   
$this->menu_items[$key]->connect_simple('activate',
      array(
$this, 'menu_activate'),
      array(
'key'=>$key, 'label' => $label));
   
parent::append($this->menu_items[$key]);
  }

 
# should be protected
 
function menu_activate($userdata) {
   
$context = array(
     
'event'  => $this->popup_event,
     
'key'    => $userdata['key'],
     
'label'  => $userdata['label']
    );
   
$this->signal->emmit('activate', $context);
  }

 
/**
   *  Signal registration with Gnope_FileExplorer_Signal class
   *
   */
 
public function connect($signal, $method, $user_data = null) {
    return
$this->signal->connect($signal, $method, $user_data);
  }

  public function
connect_simple($signal, $method, $user_data = null) {
    return
$this->connect($signal, $method, $user_data);
  }

 
/**
   * registrer to signal event in a window and then
   * call this popup method :
   *
   * ex :
   *
   *  $window->set_events($window->get_events()
   *    | Gdk::BUTTON_PRESS_MASK);
   *  $window->connect('button-press-event',
   *    array($menu, 'popup'), $user_data);
   *
   * target widget can be :
  * - GtkWindow
  * - GtkDrawingArea
  *  -maybe GtkTreeView
  *
  */
 
public function popup($window, $event, $userdata) {
   
# only popup menu if button 3 is pressed.
   
if ($event->button == 3) {
   
# register event to emit complete event information upon menu
    # selection, including (x,y) coordinates and so on ...
   
$this->popup_event = $event;
   
# show popup menu.
   
parent::popup();
    }
  }

 
/**
   * Buttons can be activated or deactivated on demand.
   *
   */
 
public function set_sensitive($item_key, $bool) {
    if (isset(
$this->menu_items[$item_key]))
     
$this->menu_items[$item_key]->set_sensitive($bool);
  }
}
?>

Updates

  • added Popup::set_parent() method to avoid simplify event and signal registration. This is done by this method.
AllegatoDimensione
popup-menu-oo.php_.txt3.68 KB