home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / libgimp / gimphelpui.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-19  |  11.4 KB  |  406 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * gimphelpui.c
  5.  * Copyright (C) 2000 Michael Natterer <mitch@gimp.org>
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *             
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include <gdk/gdkkeysyms.h>
  24. #include <gtk/gtk.h>
  25.  
  26. #include "gimpdialog.h"
  27. #include "gimphelpui.h"
  28.  
  29.  
  30. /*  local function prototypes  */
  31. static void gimp_help_callback                   (GtkWidget      *widget,
  32.                           gpointer        data);
  33. static gint gimp_help_tips_query_idle_show_help  (gpointer        data);
  34. static gint gimp_help_tips_query_widget_selected (GtkWidget      *tips_query,
  35.                           GtkWidget      *widget,
  36.                           const gchar    *tip_text,
  37.                           const gchar    *tip_private,
  38.                           GdkEventButton *event,
  39.                           gpointer        func_data);
  40. static gint gimp_help_tips_query_idle_start      (gpointer        tips_query);
  41. static void gimp_help_tips_query_start           (GtkWidget      *widget,
  42.                           gpointer        tips_query);
  43.  
  44. /*  local variables  */
  45. static GtkTooltips * tool_tips  = NULL;
  46. static GtkWidget   * tips_query = NULL;
  47.  
  48. /**********************/
  49. /*  public functions  */
  50. /**********************/
  51.  
  52. /**
  53.  * gimp_help_init:
  54.  *
  55.  * This function initializes GIMP's help system.
  56.  *
  57.  * Currently it only creates a #GtkTooltips object with gtk_tooltips_new()
  58.  * which will be used by gimp_help_set_help_data().
  59.  **/
  60. void
  61. gimp_help_init (void)
  62. {
  63.   tool_tips = gtk_tooltips_new ();
  64. }
  65.  
  66. /**
  67.  * gimp_help_free:
  68.  *
  69.  * This function frees the memory used by the #GtkTooltips created by
  70.  * gimp_help_init().
  71.  **/
  72. void
  73. gimp_help_free (void)
  74. {
  75.   gtk_object_destroy (GTK_OBJECT (tool_tips));
  76.   gtk_object_unref   (GTK_OBJECT (tool_tips));
  77. }
  78.  
  79. /**
  80.  * gimp_help_enable_tooltips:
  81.  *
  82.  * This function calls gtk_tooltips_enable().
  83.  **/
  84. void
  85. gimp_help_enable_tooltips (void)
  86. {
  87.   gtk_tooltips_enable (tool_tips);
  88. }
  89.  
  90. /**
  91.  * gimp_help_disable_tooltips:
  92.  *
  93.  * This function calls gtk_tooltips_disable().
  94.  **/
  95. void
  96. gimp_help_disable_tooltips (void)
  97. {
  98.   gtk_tooltips_disable (tool_tips);
  99. }
  100.  
  101. /**
  102.  * gimp_help_connect_help_accel:
  103.  * @widget: The widget you want to connect the help accelerator for. Will
  104.  *          be a #GtkWindow in most cases.
  105.  * @help_func: The function which will be called if the user presses "F1".
  106.  * @help_data: The data pointer which will be passed to @help_func.
  107.  *
  108.  * Note that this function is automatically called by all libgimp dialog
  109.  * constructors. You only have to call it for windows/dialogs you created
  110.  * "manually".
  111.  *
  112.  * For convenience, gimp_help_connect_help_accel() calls
  113.  * gimp_dialog_set_icon() if the passed widget is a #GtkWindow, so you
  114.  * don't have to worry about this.
  115.  **/
  116. void
  117. gimp_help_connect_help_accel (GtkWidget    *widget,
  118.                   GimpHelpFunc  help_func,
  119.                   const gchar  *help_data)
  120. {
  121.   GtkAccelGroup *accel_group;
  122.  
  123.   if (!help_func)
  124.     return;
  125.  
  126.   /*  for convenience we set the wm icon here because
  127.    *  this function is called for almost all gimp windows
  128.    */
  129.   if (GTK_IS_WINDOW (widget))
  130.     gimp_dialog_set_icon (GTK_WINDOW (widget));
  131.  
  132.   /*  set up the help signals and tips query widget
  133.    */
  134.   if (!tips_query)
  135.     {
  136.       tips_query = gtk_tips_query_new ();
  137.  
  138.       gtk_widget_set (tips_query,
  139.               "GtkTipsQuery::emit_always", TRUE,
  140.               NULL);
  141.  
  142.       gtk_signal_connect (GTK_OBJECT (tips_query), "widget_selected",
  143.               GTK_SIGNAL_FUNC (gimp_help_tips_query_widget_selected),
  144.               NULL);
  145.  
  146.       /*  FIXME: EEEEEEEEEEEEEEEEEEEEK, this is very ugly and forbidden...
  147.        *  does anyone know a way to do this tips query stuff without
  148.        *  having to attach to some parent widget???
  149.        */
  150.       tips_query->parent = widget;
  151.       gtk_widget_realize (tips_query);
  152.     }
  153.  
  154.   if (! gtk_signal_lookup ("tips_query", GTK_OBJECT (widget)->klass->type))
  155.     {
  156.       gtk_object_class_user_signal_new (GTK_OBJECT (widget)->klass,
  157.                     "tips_query",
  158.                     GTK_RUN_LAST,
  159.                     gtk_signal_default_marshaller,
  160.                     GTK_TYPE_NONE,
  161.                     0,
  162.                     NULL);
  163.  
  164.       gtk_object_class_user_signal_new (GTK_OBJECT (widget)->klass,
  165.                     "help",
  166.                     GTK_RUN_LAST,
  167.                     gtk_signal_default_marshaller,
  168.                     GTK_TYPE_NONE,
  169.                     0,
  170.                     NULL);
  171.     }
  172.  
  173.   gimp_help_set_help_data (widget, NULL, help_data);
  174.  
  175.   gtk_signal_connect (GTK_OBJECT (widget), "help",
  176.               GTK_SIGNAL_FUNC (gimp_help_callback),
  177.               (gpointer) help_func);
  178.  
  179.   gtk_signal_connect (GTK_OBJECT (widget), "tips_query",
  180.               GTK_SIGNAL_FUNC (gimp_help_tips_query_start),
  181.               (gpointer) tips_query);
  182.  
  183.   gtk_widget_add_events (widget, GDK_BUTTON_PRESS_MASK);
  184.  
  185.   /*  a new accelerator group for this widget  */
  186.   accel_group = gtk_accel_group_new ();
  187.  
  188.   /*  FIXME: does not work for some reason...
  189.   gtk_widget_add_accelerator (widget, "help", accel_group,
  190.                   GDK_F1, 0, GTK_ACCEL_LOCKED);
  191.   gtk_widget_add_accelerator (widget, "tips_query", accel_group,
  192.                   GDK_F1, GDK_SHIFT_MASK, GTK_ACCEL_LOCKED);
  193.   */
  194.  
  195.   /*  ...while using this internal stuff works  */
  196.   gtk_accel_group_add (accel_group, GDK_F1, 0, 0,
  197.                GTK_OBJECT (widget), "help");
  198.   gtk_accel_group_add (accel_group, GDK_F1, GDK_SHIFT_MASK, 0,
  199.                GTK_OBJECT (widget), "tips_query");
  200.  
  201.   gtk_accel_group_attach (accel_group, GTK_OBJECT (widget));
  202. }
  203.  
  204. /**
  205.  * gimp_help_set_help_data:
  206.  * @widget: The #GtkWidget you want to set a @tooltip and/or @help_data for.
  207.  * @tooltip: The text for this widget's tooltip.
  208.  * @help_data: The @help_data for the #GtkTipsQuery tooltips inspector.
  209.  *
  210.  * The reason why we don't use gtk_tooltips_set_tip() is that it's
  211.  * impossible to set a @private_tip (aka @help_data) without a visible
  212.  * @tooltip.
  213.  *
  214.  * This function can be called with @tooltip == #NULL. Use this feature
  215.  * if you want to set a HTML help link for a widget which shouldn't have
  216.  * a visible tooltip.
  217.  *
  218.  * You can e.g. set a @help_data string to a complete HTML page for a
  219.  * container widget (e.g. a #GtkBox). For the widgets inside the box
  220.  * you can set HTML anchors which point inside the container widget's
  221.  * help page by setting @help_data strings starting with "#".
  222.  *
  223.  * If the tooltips inspector (Shift + "F1") is invoked and the user
  224.  * clicks on one of the widgets which only contain a "#" link, the
  225.  * help system will automatically ascend the widget hierarchy until it
  226.  * finds another widget with @help_data attached and concatenates both
  227.  * to a complete help path.
  228.  **/
  229. void
  230. gimp_help_set_help_data (GtkWidget   *widget,
  231.              const gchar *tooltip,
  232.              const gchar *help_data)
  233. {
  234.   g_return_if_fail (widget != NULL);
  235.   g_return_if_fail (GTK_IS_WIDGET (widget));
  236.  
  237.   if (tooltip)
  238.     {
  239.       gtk_tooltips_set_tip (tool_tips, widget, tooltip,
  240.                 (gpointer) help_data);
  241.     }
  242.   else if (help_data)
  243.     {
  244.       gtk_object_set_data (GTK_OBJECT (widget), "gimp_help_data",
  245.                (gpointer) help_data);
  246.     }
  247. }
  248.  
  249. /**
  250.  * gimp_context_help:
  251.  *
  252.  * This function invokes the #GtkTipsQuery tooltips inspector.
  253.  *
  254.  * The mouse cursor will turn turn into a question mark and the user can
  255.  * click on any widget of the application which started the inspector.
  256.  *
  257.  * If the widget the user clicked on has a @help_data string attached
  258.  * (see gimp_help_set_help_data()), the corresponding HTML page will
  259.  * be displayed. Otherwise the help system will ascend the widget hierarchy
  260.  * until it finds an attached @help_data string (which should be the
  261.  * case at least for every window/dialog).
  262.  **/
  263. void
  264. gimp_context_help (void)
  265. {
  266.   if (tips_query)
  267.     gimp_help_tips_query_start (NULL, tips_query);
  268. }
  269.  
  270. /*********************/
  271. /*  local functions  */
  272. /*********************/
  273.  
  274. static void
  275. gimp_help_callback (GtkWidget *widget,
  276.             gpointer   data)
  277. {
  278.   GimpHelpFunc  help_function;
  279.   const gchar  *help_data;
  280.  
  281.   help_function = (GimpHelpFunc) data;
  282.   help_data     = (const gchar *) gtk_object_get_data (GTK_OBJECT (widget),
  283.                                "gimp_help_data");
  284.  
  285.   if (help_function)
  286.     (* help_function) (help_data);
  287. }
  288.  
  289. /*  Do all the actual GtkTipsQuery calls in idle functions and check for
  290.  *  some widget holding a grab before starting the query because strange
  291.  *  things happen if (1) the help browser pops up while the query has
  292.  *  grabbed the pointer or (2) the query grabs the pointer while some
  293.  *  other part of the gimp has grabbed it (e.g. a tool, eek)
  294.  */
  295.  
  296. static gint
  297. gimp_help_tips_query_idle_show_help (gpointer data)
  298. {
  299.   GtkWidget *event_widget;
  300.   GtkWidget *toplevel_widget;
  301.   GtkWidget *widget;
  302.  
  303.   GtkTooltipsData *tooltips_data;
  304.  
  305.   gchar *help_data = NULL;
  306.  
  307.   event_widget = GTK_WIDGET (data);
  308.   toplevel_widget = gtk_widget_get_toplevel (event_widget);
  309.  
  310.   /*  search for help_data in this widget's parent containers  */
  311.   for (widget = event_widget; widget; widget = widget->parent)
  312.     {
  313.       if ((tooltips_data = gtk_tooltips_data_get (widget)) &&
  314.       tooltips_data->tip_private)
  315.     {
  316.       help_data = tooltips_data->tip_private;
  317.     }
  318.       else
  319.     {
  320.       help_data = (gchar *) gtk_object_get_data (GTK_OBJECT (widget),
  321.                              "gimp_help_data");
  322.     }
  323.  
  324.       if (help_data || widget == toplevel_widget)
  325.     break;
  326.     }
  327.  
  328.   if (! help_data)
  329.     return FALSE;
  330.  
  331.   if (help_data[0] == '#')
  332.     {
  333.       gchar *help_index;
  334.  
  335.       if (widget == toplevel_widget)
  336.     return FALSE;
  337.  
  338.       help_index = help_data;
  339.       help_data  = NULL;
  340.  
  341.       for (widget = widget->parent; widget; widget = widget->parent)
  342.     {
  343.       if ((tooltips_data = gtk_tooltips_data_get (widget)) &&
  344.           tooltips_data->tip_private)
  345.         {
  346.           help_data = tooltips_data->tip_private;
  347.         }
  348.       else
  349.         {
  350.           help_data = (gchar *) gtk_object_get_data (GTK_OBJECT (widget),
  351.                              "gimp_help_data");
  352.         }
  353.  
  354.       if (help_data)
  355.         break;
  356.     }
  357.  
  358.       if (help_data)
  359.     {
  360.       gchar *help_text;
  361.  
  362.       help_text = g_strconcat (help_data, help_index, NULL);
  363.       gimp_standard_help_func (help_text);
  364.       g_free (help_text);
  365.     }
  366.     }
  367.   else
  368.     {
  369.       gimp_standard_help_func (help_data);
  370.     }
  371.  
  372.   return FALSE;
  373. }
  374.  
  375. static gint
  376. gimp_help_tips_query_widget_selected (GtkWidget      *tips_query,
  377.                       GtkWidget      *widget,
  378.                       const gchar    *tip_text,
  379.                       const gchar    *tip_private,
  380.                       GdkEventButton *event,
  381.                       gpointer        func_data)
  382. {
  383.   if (widget)
  384.     gtk_idle_add ((GtkFunction) gimp_help_tips_query_idle_show_help,
  385.           (gpointer) widget);
  386.  
  387.   return TRUE;
  388. }
  389.  
  390. static gint
  391. gimp_help_tips_query_idle_start (gpointer tips_query)
  392. {
  393.   if (! gtk_grab_get_current ())
  394.     gtk_tips_query_start_query (GTK_TIPS_QUERY (tips_query));
  395.  
  396.   return FALSE;
  397. }
  398.  
  399. static void
  400. gimp_help_tips_query_start (GtkWidget *widget,
  401.                 gpointer   tips_query)
  402. {
  403.   if (! GTK_TIPS_QUERY (tips_query)->in_query)
  404.     gtk_idle_add ((GtkFunction) gimp_help_tips_query_idle_start, tips_query);
  405. }
  406.