#408327, improve tooltip positioning.

2007-07-13  Kristian Rietveld  <kris@imendio.com>

	#408327, improve tooltip positioning.

	* gtk/gtk.symbols: updated.

	* gtk/gtktooltip.[ch] (gtk_tooltip_position): factor out
	positioning code in here,
	(gtk_tooltip_set_tip_area): new function to set the tooltip
	area,
	(gtk_tooltip_reset), (_gtk_tooltip_handle_event): hide tooltip
	once the pointer leaves the tip area.

	* gtk/gtktreeview.[ch] (gtk_tree_view_set_tooltip_row),
	(gtk_tree_view_set_tooltip_cell): convenience functions to set
	tip area for row/column/cell.

	* tests/testtooltips.c (query_tooltip_tree_view_cb): use
	gtk_tree_view_set_tooltip_row.


svn path=/trunk/; revision=18464
This commit is contained in:
Kristian Rietveld 2007-07-13 14:25:21 +00:00 committed by Kristian Rietveld
parent 07c3dc414d
commit da989212f3
7 changed files with 275 additions and 59 deletions

View File

@ -1,3 +1,23 @@
2007-07-13 Kristian Rietveld <kris@imendio.com>
#408327, improve tooltip positioning.
* gtk/gtk.symbols: updated.
* gtk/gtktooltip.[ch] (gtk_tooltip_position): factor out
positioning code in here,
(gtk_tooltip_set_tip_area): new function to set the tooltip
area,
(gtk_tooltip_reset), (_gtk_tooltip_handle_event): hide tooltip
once the pointer leaves the tip area.
* gtk/gtktreeview.[ch] (gtk_tree_view_set_tooltip_row),
(gtk_tree_view_set_tooltip_cell): convenience functions to set
tip area for row/column/cell.
* tests/testtooltips.c (query_tooltip_tree_view_cb): use
gtk_tree_view_set_tooltip_row.
2007-07-12 Cody Russell <bratsche@gnome.org>
* gdk/win32/gdkevents-win32.c

View File

@ -4079,6 +4079,7 @@ gtk_tooltip_set_icon
gtk_tooltip_set_icon_from_stock
gtk_tooltip_set_markup
gtk_tooltip_set_text
gtk_tooltip_set_tip_area
gtk_tooltip_trigger_tooltip_query
#endif
#endif
@ -4466,6 +4467,8 @@ gtk_tree_view_set_search_entry
gtk_tree_view_set_search_equal_func
gtk_tree_view_set_search_position_func
gtk_tree_view_set_show_expanders
gtk_tree_view_set_tooltip_row
gtk_tree_view_set_tooltip_cell
gtk_tree_view_set_vadjustment
#ifndef GTK_DISABLE_DEPRECATED
gtk_tree_view_tree_to_widget_coords

View File

@ -64,8 +64,11 @@ struct _GtkTooltip
guint timeout_id;
guint browse_mode_timeout_id;
GdkRectangle tip_area;
guint browse_mode_enabled : 1;
guint keyboard_mode_enabled : 1;
guint tip_area_set : 1;
};
struct _GtkTooltipClass
@ -327,6 +330,37 @@ gtk_tooltip_set_custom (GtkTooltip *tooltip,
tooltip->custom_widget = NULL;
}
/**
* gtk_tooltip_set_tip_area:
* @tooltip: a #GtkTooltip
* @rect: a #GdkRectangle
*
* Sets the area of the widget, where the contents of this tooltip apply,
* to be @rect (in widget coordinates). This is especially useful for
* properly setting tooltips on #GtkTreeView rows and cells, #GtkIconViews,
* etc.
*
* For setting tooltips on #GtkTreeView, please refer to the convenience
* functions for this: gtk_tree_view_set_tooltip_row() and
* gtk_tree_view_set_tooltip_cell().
*
* Since: 2.12
*/
void
gtk_tooltip_set_tip_area (GtkTooltip *tooltip,
GdkRectangle *rect)
{
g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
if (!rect)
tooltip->tip_area_set = FALSE;
else
{
tooltip->tip_area_set = TRUE;
tooltip->tip_area = *rect;
}
}
/**
* gtk_tooltip_trigger_tooltip_query:
* @display: a #GdkDisplay
@ -367,6 +401,7 @@ gtk_tooltip_reset (GtkTooltip *tooltip)
gtk_tooltip_set_markup (tooltip, NULL);
gtk_tooltip_set_icon (tooltip, NULL);
gtk_tooltip_set_custom (tooltip, NULL);
gtk_tooltip_set_tip_area (tooltip, NULL);
}
static gboolean
@ -633,6 +668,76 @@ gtk_tooltip_run_requery (GtkWidget **widget,
return return_value;
}
static void
gtk_tooltip_position (GtkTooltip *tooltip,
GdkDisplay *display,
GtkWidget *new_tooltip_widget)
{
gint x, y;
GdkScreen *screen;
tooltip->tooltip_widget = new_tooltip_widget;
/* Position the tooltip */
/* FIXME: should we swap this when RTL is enabled? */
if (tooltip->keyboard_mode_enabled)
{
gdk_window_get_origin (new_tooltip_widget->window, &x, &y);
if (GTK_WIDGET_NO_WINDOW (new_tooltip_widget))
{
x += new_tooltip_widget->allocation.x;
y += new_tooltip_widget->allocation.y;
}
/* For keyboard mode we position the tooltip below the widget,
* right of the center of the widget.
*/
x += new_tooltip_widget->allocation.width / 2;
y += new_tooltip_widget->allocation.height + 4;
}
else
{
guint cursor_size;
x = tooltip->last_x;
y = tooltip->last_y;
/* For mouse mode, we position the tooltip right of the cursor,
* a little below the cursor's center.
*/
cursor_size = gdk_display_get_default_cursor_size (display);
x += cursor_size / 2;
y += cursor_size / 2;
}
screen = gtk_widget_get_screen (new_tooltip_widget);
/* Show it */
if (tooltip->current_window)
{
gint monitor_num;
GdkRectangle monitor;
GtkRequisition requisition;
gtk_widget_size_request (GTK_WIDGET (tooltip->current_window),
&requisition);
monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
if (x + requisition.width > monitor.x + monitor.width)
x -= x - (monitor.x + monitor.width) + requisition.width;
else if (x < monitor.x)
x = monitor.x;
if (y + requisition.height > monitor.y + monitor.height)
y -= y - (monitor.y + monitor.height) + requisition.height;
gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y);
gtk_widget_show (GTK_WIDGET (tooltip->current_window));
}
}
static void
gtk_tooltip_show_tooltip (GdkDisplay *display)
{
@ -687,40 +792,9 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window);
}
/* Position the tooltip */
/* FIXME: should we swap this when RTL is enabled? */
if (tooltip->keyboard_mode_enabled)
{
gdk_window_get_origin (tooltip_widget->window, &x, &y);
if (GTK_WIDGET_NO_WINDOW (tooltip_widget))
{
x += tooltip_widget->allocation.x;
y += tooltip_widget->allocation.y;
}
/* For keyboard mode we position the tooltip below the widget,
* right of the center of the widget.
*/
x += tooltip_widget->allocation.width / 2;
y += tooltip_widget->allocation.height + 4;
}
else
{
guint cursor_size;
x = tooltip->last_x;
y = tooltip->last_y;
/* For mouse mode, we position the tooltip right of the cursor,
* a little below the cursor's center.
*/
cursor_size = gdk_display_get_default_cursor_size (display);
x += cursor_size / 2;
y += cursor_size / 2;
}
screen = gtk_widget_get_screen (tooltip_widget);
/* FIXME: should use tooltip->current_window iso tooltip->window */
if (screen != gtk_widget_get_screen (tooltip->window))
{
g_signal_handlers_disconnect_by_func (display,
@ -733,32 +807,7 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
G_CALLBACK (gtk_tooltip_display_closed), tooltip);
}
tooltip->tooltip_widget = tooltip_widget;
/* Show it */
if (tooltip->current_window)
{
gint monitor_num;
GdkRectangle monitor;
GtkRequisition requisition;
gtk_widget_size_request (GTK_WIDGET (tooltip->current_window),
&requisition);
monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
if (x + requisition.width > monitor.x + monitor.width)
x -= x - (monitor.x + monitor.width) + requisition.width;
else if (x < monitor.x)
x = monitor.x;
if (y + requisition.height > monitor.y + monitor.height)
y -= y - (monitor.y + monitor.height) + requisition.height;
gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y);
gtk_widget_show (GTK_WIDGET (tooltip->current_window));
}
gtk_tooltip_position (tooltip, display, tooltip_widget);
/* Now a tooltip is visible again on the display, make sure browse
* mode is enabled.
@ -1063,11 +1112,32 @@ _gtk_tooltip_handle_event (GdkEvent *event)
case GDK_SCROLL:
if (current_tooltip)
{
gboolean tip_area_set;
GdkRectangle tip_area;
gboolean hide_tooltip;
tip_area_set = current_tooltip->tip_area_set;
tip_area = current_tooltip->tip_area;
return_value = gtk_tooltip_run_requery (&has_tooltip_widget,
current_tooltip,
&x, &y);
if (!return_value)
/* Requested to be hidden? */
hide_tooltip = !return_value;
/* Is the pointer above another widget now? */
if (GTK_TOOLTIP_VISIBLE (current_tooltip))
hide_tooltip |= has_tooltip_widget != current_tooltip->tooltip_widget;
/* Did the pointer move out of the previous "context area"? */
if (tip_area_set)
hide_tooltip |= (x <= tip_area.x
|| x >= tip_area.x + tip_area.width
|| y <= tip_area.y
|| y >= tip_area.y + tip_area.height);
if (hide_tooltip)
gtk_tooltip_hide_tooltip (current_tooltip);
else
gtk_tooltip_start_delay (display);

View File

@ -45,6 +45,9 @@ void gtk_tooltip_set_icon_from_stock (GtkTooltip *tooltip,
void gtk_tooltip_set_custom (GtkTooltip *tooltip,
GtkWidget *custom_widget);
void gtk_tooltip_set_tip_area (GtkTooltip *tooltip,
GdkRectangle *rect);
void gtk_tooltip_trigger_tooltip_query (GdkDisplay *display);

View File

@ -42,6 +42,7 @@
#include "gtkentry.h"
#include "gtkframe.h"
#include "gtktreemodelsort.h"
#include "gtktooltip.h"
#include "gtkprivate.h"
#include "gtkalias.h"
@ -15171,5 +15172,112 @@ gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
return tree_view->priv->level_indentation;
}
/**
* gtk_tree_view_set_tooltip_row:
* @tree_view: a #GtkTreeView
* @tooltip: a #GtkTooltip
* @path: a #GtkTreePath
*
* Sets the tip area of @tooltip to be the area covered by the row at @path.
* See also gtk_tooltip_set_tip_area().
*
* Since: 2.12
*/
void
gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
GtkTooltip *tooltip,
GtkTreePath *path)
{
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
}
/**
* gtk_tree_view_set_tooltip_cell:
* @tree_view: a #GtkTreeView
* @tooltip: a #GtkTooltip
* @path: a #GtkTreePath or %NULL
* @column: a #GtkTreeViewColumn or %NULL
* @cell: a #GtkCellRendererText or %NULL
*
* Sets the tip area of @tooltip to the area @path, @column and @cell have
* in common. For example if @path is %NULL and @column is set, the tip
* area will be set to the full area covered by @column. See also
* gtk_tooltip_set_tip_area().
*
* Since: 2.12
*/
void
gtk_tree_view_set_tooltip_cell (GtkTreeView *tree_view,
GtkTooltip *tooltip,
GtkTreePath *path,
GtkTreeViewColumn *column,
GtkCellRenderer *cell)
{
GdkRectangle rect;
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
if (column)
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
if (cell)
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
/* Determine x values. */
if (column && cell)
{
GdkRectangle tmp;
gint start, width;
gtk_tree_view_get_cell_area (tree_view, NULL, column, &tmp);
gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
/* FIXME: a need a path here to correctly correct for indent */
gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
tmp.x + start, 0,
&rect.x, NULL);
rect.width = width;
}
else if (column)
{
GdkRectangle tmp;
gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
tmp.x, 0,
&rect.x, NULL);
rect.width = tmp.width;
}
else
{
rect.x = GTK_WIDGET (tree_view)->allocation.x;
rect.width = GTK_WIDGET (tree_view)->allocation.width;
}
/* Determine y values. */
if (path)
{
GdkRectangle tmp;
gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
0, tmp.y,
NULL, &rect.y);
rect.height = tmp.height;
}
else
{
rect.y = 0;
rect.height = tree_view->priv->vadjustment->page_size;
}
gtk_tooltip_set_tip_area (tooltip, &rect);
}
#define __GTK_TREE_VIEW_C__
#include "gtkaliasdef.c"

View File

@ -402,6 +402,16 @@ void gtk_tree_view_set_level_indentation (GtkTreeView
gint indentation);
gint gtk_tree_view_get_level_indentation (GtkTreeView *tree_view);
/* Convenience functions for setting tooltips */
void gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
GtkTooltip *tooltip,
GtkTreePath *path);
void gtk_tree_view_set_tooltip_cell (GtkTreeView *tree_view,
GtkTooltip *tooltip,
GtkTreePath *path,
GtkTreeViewColumn *column,
GtkCellRenderer *cell);
G_END_DECLS

View File

@ -135,6 +135,8 @@ query_tooltip_tree_view_cb (GtkWidget *widget,
g_snprintf (buffer, 511, "<b>Path %s:</b> %s", pathstring, tmp);
gtk_tooltip_set_markup (tooltip, buffer);
gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
gtk_tree_path_free (path);
g_free (pathstring);
g_free (tmp);