Tooltips progress



Last week I've been working on the tooltips implementation, using the
callback-based approach/interface discussed earlier on this mailing list.
The basics are working already including keyboard support and custom
windows.  Before I can finalize a patch for reviewal, I have some comments
and questions.


In a follow up to his original mail, Tim is talking about adding the
following function:

  gdk_display_force_query_display (GdkDisplay *);

I am not sure if this really belongs in GdkDisplay.  Currently I have a:

  gtk_widget_force_query_tooltip (GtkWidget *widget);

which works just fine for forcably updating a tooltip, in both keyboard
and mouse mode.  I guess most people will usually know which widget's
tooltip to update.  Opinions?


Currently, we are using the following query-tooltips signal:

  gboolean (*query_tooltip)     (GtkWidget           *widget,
                                 gint                 x,
                                 gint                 y,
                                 GtkTooltip          *tooltip);

But if a user sets a custom using gtk_widget_set_custom_window(), we don't
have to pass a GtkTooltip around.  So currently I just set the tooltip
field to NULL, so the user knows he has to use his own custom tooltip
window (and we assume he has a reference to that).  Is this okay or do
we want to change this?  We could also move the _set_custom_window()
functions into GtkTooltip for example.


Implementing GtkTreeView tooltips in your application is now pretty easy,
just set up a query_tooltip callback and call gtk_tree_view_get_path_at_pos()
with the coordinates which are provided to you (but if x == -1, the keyboard
mode is enabled and then you should really call gtk_tree_view_get_cursor()).

Would this be sufficient, or do we want to add some special API for supporting
tooltips in the tree view, like having GtkTreeView implement the query
tooltip callback and have tooltip-markup properties on cell renderers.
Personally I think implementing the query-tooltip yourself is easy enough
for people to do and also really flexible, so there's no need for more API.


Since we re-query for a tooltip on mouse motion, I was wondering what we
should do in keyboard mode if a key is pressed in, for example, GtkTreeView.
A key press there might change the cursor and we might want to update the
tooltip contents.  Do we want stock GTK+ to take care of this, or should the
user do this himself?  (For example by calling gtk_widget_force_tooltip_query
from the GtkTreeSelection::changed callback).


Attached is some sample code using the new API.  Opinions, comments,
suggestions are appreciated.


thanks,

-kris.
#include <gtk/gtk.h>


static gboolean
query_tooltip_cb (GtkWidget  *widget,
		  gint        x,
		  gint        y,
		  GtkTooltip *tooltip,
		  gpointer    data)
{
  gtk_tooltip_set_markup (tooltip, gtk_button_get_label (GTK_BUTTON (widget)));

  return TRUE;
}

static gboolean
query_tooltip_custom_cb (GtkWidget  *widget,
			 gint        x,
			 gint        y,
			 GtkTooltip *tooltip,
			 gpointer    data)
{
  GtkWindow *window = GTK_WINDOW (data);

  /* ... can manipulate window here ... */

  return TRUE;
}

static gboolean
query_tooltip_tree_view_cb (GtkWidget  *widget,
			    gint        x,
			    gint        y,
			    GtkTooltip *tooltip,
			    gpointer    data)
{
  GtkTreeIter iter;
  GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
  GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
  GtkTreePath *path = NULL;
  gchar *tmp;

  char buffer[512];

  if (x == -1)
    {
      /* Keyboard mode */
      gtk_tree_view_get_cursor (tree_view, &path, NULL);

      if (!path)
	return FALSE;
    }
  else
    {
      /* Mouse mode */
      if (!gtk_tree_view_get_path_at_pos (tree_view, x, y, &path, NULL, NULL, NULL))
        return FALSE;
    }

  gtk_tree_model_get_iter (model, &iter, path);
  gtk_tree_model_get (model, &iter, 0, &tmp, -1);

  snprintf (buffer, 511, "<b>Path %s:</b> %s",
	    gtk_tree_path_to_string (path), tmp);
  gtk_tooltip_set_markup (tooltip, buffer);

  gtk_tree_path_free (path);
  g_free (tmp);

  return TRUE;
}

static GtkTreeModel *
create_model (void)
{
  GtkTreeStore *store;
  GtkTreeIter iter;

  store = gtk_tree_store_new (1, G_TYPE_STRING);

  /* A tree store with some random words ... */
  gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
				     0, "File Manager", -1);
  gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
				     0, "Gossip", -1);
  gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
				     0, "System Settings", -1);
  gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
				     0, "The GIMP", -1);
  gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
				     0, "Terminal", -1);
  gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
				     0, "Word Processor", -1);

  return GTK_TREE_MODEL (store);
}

static void
selection_changed_cb (GtkTreeSelection *selection,
		      GtkWidget        *tree_view)
{
  gtk_widget_force_query_tooltip (tree_view);
}

int
main (int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *box;
  GtkWidget *button;

  GtkWidget *tooltip_window;
  GtkWidget *tooltip_button;

  GtkWidget *tree_view;
  GtkTreeViewColumn *column;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Tooltips test");
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
  g_signal_connect (window, "delete_event",
		    G_CALLBACK (gtk_main_quit), NULL);

  box = gtk_vbox_new (FALSE, 3);
  gtk_container_add (GTK_CONTAINER (window), box);

  /* A check button using the tooltip-markup property */
  button = gtk_check_button_new_with_label ("This one uses the tooltip-markup property");
  g_object_set (button, "tooltip-markup", "Hello, I am a static tooltip.", NULL);
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);

  /* A check button using the query-tooltip signal */
  button = gtk_check_button_new_with_label ("I use the query-tooltip signal");
  g_object_set (button, "has-tooltip", TRUE, NULL);
  g_signal_connect (button, "query-tooltip",
		    G_CALLBACK (query_tooltip_cb), NULL);
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);

  /* Another one, just the same */
  button = gtk_check_button_new_with_label ("I am just more of the same");
  g_object_set (button, "has-tooltip", TRUE, NULL);
  g_signal_connect (button, "query-tooltip",
		    G_CALLBACK (query_tooltip_cb), NULL);
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);

  /* Another one, with a custom tooltip window */
  button = gtk_check_button_new_with_label ("This one has a custom tooltip window!");
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);

  tooltip_window = gtk_window_new (GTK_WINDOW_POPUP);
  tooltip_button = gtk_label_new ("blaat!");
  gtk_container_add (GTK_CONTAINER (tooltip_window), tooltip_button);
  gtk_widget_show (tooltip_button);

  gtk_widget_set_tooltip_window (button, GTK_WINDOW (tooltip_window));
  g_signal_connect (button, "query-tooltip",
		    G_CALLBACK (query_tooltip_custom_cb), tooltip_window);
  g_object_set (button, "has-tooltip", TRUE, NULL);

  /* Testcases from Kris without a tree view don't exist. */
  tree_view = gtk_tree_view_new_with_model (create_model ());
  gtk_widget_set_size_request (tree_view, 200, 240);

  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
					       0, "Test",
					       gtk_cell_renderer_text_new (),
					       "text", 0,
					       NULL);

  g_object_set (tree_view, "has-tooltip", TRUE, NULL);
  g_signal_connect (tree_view, "query-tooltip",
		    G_CALLBACK (query_tooltip_tree_view_cb), NULL);
  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
		    "changed", G_CALLBACK (selection_changed_cb), tree_view);

  /* Set a tooltip on the column */
  column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 0);
  gtk_tree_view_column_set_clickable (column, TRUE);
  g_object_set (column->button, "tooltip-markup", "Header", NULL);

  gtk_box_pack_start (GTK_BOX (box), tree_view, FALSE, FALSE, 0);

  /* Done! */
  gtk_widget_show_all (window);

  gtk_main ();

  return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]