/* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */

/*
 * GImageView
 * Copyright (C) 2001 Takuro Ashie
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * $Id$
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <glib/gi18n.h>
#include <gtk/gtk.h>

#include "utils_menu.h"


static void   cb_get_data_from_menuitem (GtkWidget    *widget,
                                         gint         *conf);
static void   menu_shell_deactivated    (GtkMenuShell *menu_shell,
                                         gpointer      data);



/*
 *  menu_count_ifactory_entry_num:
 *     @ Count NULL terminated GtkItemFactoryEntry array length.
 *
 *  Return : length of array.
 */
gint
menu_count_ifactory_entry_num (GtkItemFactoryEntry *entries)
{
   gint i;

   if (!entries) return -1;

   for (i = 0; entries[i].path; i++) {continue;}
   return i;
}


static void
cb_menu_destroy (GtkWidget *widget, GtkItemFactory *factory)
{
   g_return_if_fail (factory);
   g_return_if_fail (GTK_IS_ITEM_FACTORY (factory));

   g_object_unref (G_OBJECT (factory));
}


/*
 *  menu_create:
 *     @ Create menu bar widget.
 *
 *  window    : Window widget that attach accel group.
 *  entries   : Menu item entries.
 *  n_entries : Number of menu items.
 *  path      : Root menu path.
 *  data      : User data for menu callback.
 *  Return    : Menubar widget.
 */
GtkWidget *
menubar_create (GtkWidget *window,
                GtkItemFactoryEntry *entries,
                guint n_entries,
                const gchar *path,
                gpointer data)
{
   GtkItemFactory *factory;
   GtkAccelGroup *accel_group;
   GtkWidget *widget;

   accel_group = gtk_accel_group_new ();
   factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, path, accel_group);
#ifdef ENABLE_NLS
   gtk_item_factory_set_translate_func (factory, (GtkTranslateFunc) gettext,
                                        NULL, NULL);
#endif /* ENABLE_NLS */
   gtk_item_factory_create_items (factory, n_entries, entries, data);
   gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);

   widget = gtk_item_factory_get_widget (factory, path);
   g_signal_connect (G_OBJECT (widget), "destroy",
                     G_CALLBACK (cb_menu_destroy), factory);

   return widget;
}


/*
 *  menu_create_items:
 *     @ Create menu item for menu widget (like a popup menu).
 *
 *  window    : Window widget that attach accel group.
 *  entries   : Menu item entries.
 *  n_entries : Number of menu items.
 *  path      : Root menu path.
 *  data      : User data for menu callback.
 *  Return    : menu widget.
 */
GtkWidget *
menu_create_items (GtkWidget *window,
                   GtkItemFactoryEntry *entries,
                   guint n_entries,
                   const gchar *path,
                   gpointer data)
{
   GtkItemFactory *factory;
   GtkAccelGroup *accel_group = NULL;
   GtkWidget *widget;

   if (window)
      accel_group = gtk_accel_group_new ();

   factory = gtk_item_factory_new (GTK_TYPE_MENU, path, accel_group);
#ifdef ENABLE_NLS
   gtk_item_factory_set_translate_func (factory, (GtkTranslateFunc) gettext,
                                        NULL, NULL);
#endif /* ENABLE_NLS */
   gtk_item_factory_create_items (factory, n_entries, entries, data);

   if (window)
      gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);

   widget = gtk_item_factory_get_widget (factory, path);
   g_signal_connect (G_OBJECT (widget), "destroy",
                     G_CALLBACK (cb_menu_destroy), factory);

   return widget;
}


void
menu_item_set_sensitive (GtkWidget *widget, gchar *path, gboolean sensitive)
{
   GtkWidget *menuitem;
   GtkItemFactory *ifactory;

   ifactory = gtk_item_factory_from_widget (widget);
   menuitem = gtk_item_factory_get_item (ifactory, path);
   gtk_widget_set_sensitive (menuitem, sensitive);
}


/*
 *  menu_set_check_item:
 *     @ Set check menu item's value (TRUE or FALSE).
 *
 *  widget : Menu widget that contains check menu item.
 *  path   : Menu path to check menu item.
 *  active : Value for set.
 */
void
menu_check_item_set_active (GtkWidget *widget, gchar *path, gboolean active)
{
   GtkWidget *menuitem;
   GtkItemFactory *ifactory;

   ifactory = gtk_item_factory_from_widget (widget);
   menuitem = gtk_item_factory_get_item (ifactory, path);
   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menuitem), active);
}


/*
 *  menu_set_check_item:
 *     @ Set check menu item's value (TRUE or FALSE).
 *
 *  widget : Menu widget that contains check menu item.
 *  path   : Menu path to check menu item.
 *  active : Value for set.
 */
gboolean
menu_check_item_get_active (GtkWidget *widget, gchar *path)
{
   GtkWidget *menuitem;
   GtkItemFactory *ifactory;

   ifactory = gtk_item_factory_from_widget (widget);
   menuitem = gtk_item_factory_get_item (ifactory, path);
   return GTK_CHECK_MENU_ITEM(menuitem)->active;
}


/*
 *  menu_set_submenu:
 *     @ Set sub menu.
 *
 *  widget  : Menu widget to set sub menu.
 *  path    : Menu path to check menu item.
 *  submenu : Submenu widget.
 */
void
menu_set_submenu (GtkWidget *widget, const gchar *path, GtkWidget *submenu)
{
   GtkWidget *menuitem;
   GtkItemFactory *ifactory;

   ifactory = gtk_item_factory_from_widget (widget);
   menuitem = gtk_item_factory_get_item (ifactory, path);
   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem), submenu);
}


GtkWidget *
menu_get_submenu (GtkWidget *widget, const gchar *path)
{
   GtkWidget *menuitem;
   GtkItemFactory *ifactory;

   ifactory = gtk_item_factory_from_widget (widget);
   menuitem = gtk_item_factory_get_item (ifactory, path);
   g_return_val_if_fail (menuitem, NULL);
   return GTK_MENU_ITEM(menuitem)->submenu;
}


/*
 *  menu_remove_submenu:
 *     @ Set sub menu.
 *
 *  widget  : Menu widget to set sub menu.
 *  path    : Menu path to check menu item.
 *  submenu : Submenu widget.
 */
void
menu_remove_submenu (GtkWidget *widget, const gchar *path, GtkWidget *submenu)
{
   GtkWidget *menuitem;
   GtkItemFactory *ifactory;

   ifactory = gtk_item_factory_from_widget (widget);
   menuitem = gtk_item_factory_get_item (ifactory, path);
   gtk_menu_item_remove_submenu (GTK_MENU_ITEM (menuitem));
}



/******************************************************************************
 *
 *   option menu
 *
 ******************************************************************************/
/*
 *  create_option_menu_simple:
 *     @ Create option menu widget. Return val will store to data.
 *
 *  menu_items : Menu entries.
 *  def_val    : Default value.
 *  data       : Pointer to gint for store return value when a menuitem has been
 *               selected.
 *  Return     : Option menu widget.
 */
GtkWidget *
create_option_menu_simple (const gchar **menu_items, gint def_val, gint *data)
{
   GtkWidget *option_menu;
   GtkWidget *menu_item;
   GtkWidget *menu;
   gint i;

   option_menu = gtk_option_menu_new();
   menu = gtk_menu_new();

   for (i = 0; menu_items[i]; i++) {
      menu_item = gtk_menu_item_new_with_label (_(menu_items[i]));
      g_object_set_data (G_OBJECT (menu_item), "num", GINT_TO_POINTER(i));
      g_signal_connect(G_OBJECT(menu_item), "activate",
                       G_CALLBACK(cb_get_data_from_menuitem),
                       data);
      gtk_menu_append (GTK_MENU(menu), menu_item);
      gtk_widget_show (menu_item);
   }
   gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
   gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), def_val);

   return option_menu;
}


/*
 *  create_option_menu:
 *     @ Create option menu widget.
 *
 *  menu_items : Menu entries.
 *  def_val    : Default value.
 *  func       : Callback function for each menu items.
 *  data       : Pointer to user data for callback function.
 *  Return     : Option menu widget.
 */
GtkWidget *
create_option_menu (const gchar **menu_items, gint def_val,
                    gpointer func, gpointer data)
{
   GtkWidget *option_menu;
   GtkWidget *menu_item;
   GtkWidget *menu;
   gint i;

   option_menu = gtk_option_menu_new();
   gtk_widget_set_name (option_menu, "/ThumbWin/DispModeOptionMenu");
   menu = gtk_menu_new();

   for (i = 0; menu_items[i]; i++) {
      menu_item = gtk_menu_item_new_with_label (_(menu_items[i]));
      g_object_set_data (G_OBJECT (menu_item), "num", GINT_TO_POINTER(i));
      g_signal_connect(G_OBJECT(menu_item), "activate",
                       G_CALLBACK(func),
                       data);
      gtk_menu_append (GTK_MENU(menu), menu_item);
      gtk_widget_show (menu_item);
   }
   gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
   gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), def_val);

   return option_menu;
}



/******************************************************************************
 *
 *   modal popup menu
 *
 ******************************************************************************/
static void
cb_get_data_from_menuitem (GtkWidget *widget, gint *conf)
{
   *conf = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "num"));
}


void
menu_modal_cb (gpointer data, guint action, GtkWidget *menuitem)
{
   g_object_set_data (G_OBJECT (menuitem->parent), "return_val",
                      GINT_TO_POINTER (action));
}


static void
menu_shell_deactivated (GtkMenuShell *menu_shell, gpointer data)
{
   gtk_main_quit ();
}


/*
 *  menu_popup_modal:
 *     @runs the popup menu modally and returns the callback_action value of the
 *      selected item entry, or -1 if none..
 *
 *  popup     : GtkMenu widget to popup.
 *  pos_func  :
 *  pos_data  :
 *  event     :
 *  user_data : not used yet.
 *  Return    : selected value.
 */
gint
menu_popup_modal (GtkWidget *popup,
                  GtkMenuPositionFunc pos_func,
                  gpointer pos_data,
                  GdkEventButton *event,
                  gpointer user_data)
{
   guint id;
   guint button;
   guint32 timestamp;
   gint retval;

   g_return_val_if_fail (popup != NULL, -1);
   g_return_val_if_fail (GTK_IS_WIDGET (popup), -1);

   g_object_set_data (G_OBJECT (popup), "return_val", GINT_TO_POINTER (-1));

   id = g_signal_connect (G_OBJECT (popup), "deactivate",
                          G_CALLBACK (menu_shell_deactivated),
                          NULL);

   if (event) {
      button = event->button;
      timestamp = event->time;
   } else {
      button = 0;
      timestamp = GDK_CURRENT_TIME;
   }

   gtk_menu_popup (GTK_MENU (popup), NULL, NULL,
                   pos_func, pos_data, button, timestamp);
   gtk_grab_add (popup);
   gtk_main ();
   gtk_grab_remove (popup);

   g_signal_handler_disconnect (G_OBJECT (popup), id);

   retval = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (popup),
                                                "return_val"));
   return retval;
}


void
menu_calc_popup_position (GtkMenu *menu, gint *x_ret, gint *y_ret,
                          gboolean *push_in,
                          gpointer data)
{
   GdkWindow *window = data;
   gint x = 0, y = 0, w = 0, h = 0, cursor_x = 0, cursor_y = 0;
   GdkModifierType mask;

   g_return_if_fail (x_ret && y_ret);
   g_return_if_fail (window);

   gdk_window_get_pointer (window, &cursor_x, &cursor_y, &mask);

   gdk_window_get_origin (window, &x, &y);
   gdk_window_get_size (window, &w, &h);

   if (cursor_x < 0 || cursor_x > w || cursor_y < 0 || cursor_y > h)
   {
      *x_ret = x + w / 2;
      *y_ret = y + h / 2;
   } else {
      *x_ret = x + cursor_x;
      *y_ret = y + cursor_y;
   }
}
