]> Pileus Git - ~andy/gtk/blob - tests/testtooltips.c
#408327, improve tooltip positioning.
[~andy/gtk] / tests / testtooltips.c
1 /* testtooltips.c: Test application for GTK+ >= 2.12 tooltips code
2  *
3  * Copyright (C) 2006-2007  Imendio AB
4  * Contact: Kristian Rietveld <kris@imendio.com>
5  *
6  * This work is provided "as is"; redistribution and modification
7  * in whole or in part, in any medium, physical or electronic is
8  * permitted without restriction.
9  *
10  * This work is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  *
14  * In no event shall the authors or contributors be liable for any
15  * direct, indirect, incidental, special, exemplary, or consequential
16  * damages (including, but not limited to, procurement of substitute
17  * goods or services; loss of use, data, or profits; or business
18  * interruption) however caused and on any theory of liability, whether
19  * in contract, strict liability, or tort (including negligence or
20  * otherwise) arising in any way out of the use of this software, even
21  * if advised of the possibility of such damage.
22  */
23
24 #include <gtk/gtk.h>
25
26 static gboolean
27 query_tooltip_cb (GtkWidget  *widget,
28                   gint        x,
29                   gint        y,
30                   gboolean    keyboard_tip,
31                   GtkTooltip *tooltip,
32                   gpointer    data)
33 {
34   gtk_tooltip_set_markup (tooltip, gtk_button_get_label (GTK_BUTTON (widget)));
35   gtk_tooltip_set_icon_from_stock (tooltip, GTK_STOCK_DELETE,
36                                    GTK_ICON_SIZE_MENU);
37
38   return TRUE;
39 }
40
41 static gboolean
42 query_tooltip_custom_cb (GtkWidget  *widget,
43                          gint        x,
44                          gint        y,
45                          gboolean    keyboard_tip,
46                          GtkTooltip *tooltip,
47                          gpointer    data)
48 {
49   GdkColor color = { 0, 0, 65535 };
50   GtkWindow *window = gtk_widget_get_tooltip_window (widget);
51
52   gtk_widget_modify_bg (GTK_WIDGET (window), GTK_STATE_NORMAL, &color);
53
54   return TRUE;
55 }
56
57 static gboolean
58 query_tooltip_text_view_cb (GtkWidget  *widget,
59                             gint        x,
60                             gint        y,
61                             gboolean    keyboard_tip,
62                             GtkTooltip *tooltip,
63                             gpointer    data)
64 {
65   GtkTextTag *tag = data;
66   GtkTextIter iter;
67   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
68
69   if (keyboard_tip)
70     {
71       gint offset;
72
73       g_object_get (text_view->buffer, "cursor-position", &offset, NULL);
74       gtk_text_buffer_get_iter_at_offset (text_view->buffer, &iter, offset);
75     }
76   else
77     {
78       gint bx, by, trailing;
79
80       gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_TEXT,
81                                              x, y, &bx, &by);
82       gtk_text_view_get_iter_at_position (text_view, &iter, &trailing, bx, by);
83     }
84
85   if (gtk_text_iter_has_tag (&iter, tag))
86     gtk_tooltip_set_text (tooltip, "Tooltip on text tag");
87   else
88    return FALSE;
89
90   return TRUE;
91 }
92
93 static gboolean
94 query_tooltip_tree_view_cb (GtkWidget  *widget,
95                             gint        x,
96                             gint        y,
97                             gboolean    keyboard_tip,
98                             GtkTooltip *tooltip,
99                             gpointer    data)
100 {
101   GtkTreeIter iter;
102   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
103   GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
104   GtkTreePath *path = NULL;
105   gchar *tmp;
106   gchar *pathstring;
107
108   char buffer[512];
109
110   if (keyboard_tip)
111     {
112       /* Keyboard mode */
113       gtk_tree_view_get_cursor (tree_view, &path, NULL);
114
115       if (!path)
116         return FALSE;
117     }
118   else
119     {
120       gint bin_x, bin_y;
121
122       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y,
123                                                          &bin_x, &bin_y);
124
125       /* Mouse mode */
126       if (!gtk_tree_view_get_path_at_pos (tree_view, bin_x, bin_y,
127                                           &path, NULL, NULL, NULL))
128         return FALSE;
129     }
130
131   gtk_tree_model_get_iter (model, &iter, path);
132   gtk_tree_model_get (model, &iter, 0, &tmp, -1);
133   pathstring = gtk_tree_path_to_string (path);
134
135   g_snprintf (buffer, 511, "<b>Path %s:</b> %s", pathstring, tmp);
136   gtk_tooltip_set_markup (tooltip, buffer);
137
138   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
139
140   gtk_tree_path_free (path);
141   g_free (pathstring);
142   g_free (tmp);
143
144   return TRUE;
145 }
146
147 static GtkTreeModel *
148 create_model (void)
149 {
150   GtkTreeStore *store;
151   GtkTreeIter iter;
152
153   store = gtk_tree_store_new (1, G_TYPE_STRING);
154
155   /* A tree store with some random words ... */
156   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
157                                      0, "File Manager", -1);
158   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
159                                      0, "Gossip", -1);
160   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
161                                      0, "System Settings", -1);
162   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
163                                      0, "The GIMP", -1);
164   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
165                                      0, "Terminal", -1);
166   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
167                                      0, "Word Processor", -1);
168
169   return GTK_TREE_MODEL (store);
170 }
171
172 static void
173 selection_changed_cb (GtkTreeSelection *selection,
174                       GtkWidget        *tree_view)
175 {
176   gtk_widget_trigger_tooltip_query (tree_view);
177 }
178
179 static struct Rectangle
180 {
181   gint x;
182   gint y;
183   gfloat r;
184   gfloat g;
185   gfloat b;
186   const char *tooltip;
187 }
188 rectangles[] =
189 {
190   { 10, 10, 0.0, 0.0, 0.9, "Blue box!" },
191   { 200, 170, 1.0, 0.0, 0.0, "Red thing" },
192   { 100, 50, 0.8, 0.8, 0.0, "Yellow thing" }
193 };
194
195 static gboolean
196 query_tooltip_drawing_area_cb (GtkWidget  *widget,
197                                gint        x,
198                                gint        y,
199                                gboolean    keyboard_tip,
200                                GtkTooltip *tooltip,
201                                gpointer    data)
202 {
203   gint i;
204
205   if (keyboard_tip)
206     return FALSE;
207
208   for (i = 0; i < G_N_ELEMENTS (rectangles); i++)
209     {
210       struct Rectangle *r = &rectangles[i];
211
212       if (r->x < x && x < r->x + 50
213           && r->y < y && y < r->y + 50)
214         {
215           gtk_tooltip_set_markup (tooltip, r->tooltip);
216           return TRUE;
217         }
218     }
219
220   return FALSE;
221 }
222
223 static gboolean
224 drawing_area_expose (GtkWidget      *drawing_area,
225                      GdkEventExpose *event,
226                      gpointer        data)
227 {
228   gint i;
229   cairo_t *cr;
230
231   gdk_window_get_pointer (drawing_area->window, NULL, NULL, NULL);
232
233   cr = gdk_cairo_create (drawing_area->window);
234
235   cairo_rectangle (cr, 0, 0,
236                    drawing_area->allocation.width,
237                    drawing_area->allocation.height);
238   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
239   cairo_fill (cr);
240
241   for (i = 0; i < G_N_ELEMENTS (rectangles); i++)
242     {
243       struct Rectangle *r = &rectangles[i];
244
245       cairo_rectangle (cr, r->x, r->y, 50, 50);
246       cairo_set_source_rgb (cr, r->r, r->g, r->b);
247       cairo_stroke (cr);
248
249       cairo_rectangle (cr, r->x, r->y, 50, 50);
250       cairo_set_source_rgba (cr, r->r, r->g, r->b, 0.5);
251       cairo_fill (cr);
252     }
253
254   cairo_destroy (cr);
255
256   return FALSE;
257 }
258
259 int
260 main (int argc, char *argv[])
261 {
262   GtkWidget *window;
263   GtkWidget *box;
264   GtkWidget *drawing_area;
265   GtkWidget *button;
266
267   GtkWidget *tooltip_window;
268   GtkWidget *tooltip_button;
269
270   GtkWidget *tree_view;
271   GtkTreeViewColumn *column;
272
273   GtkWidget *text_view;
274   GtkTextBuffer *buffer;
275   GtkTextIter iter;
276   GtkTextTag *tag;
277
278   gchar *text, *markup;
279
280   gtk_init (&argc, &argv);
281
282   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
283   gtk_window_set_title (GTK_WINDOW (window), "Tooltips test");
284   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
285   g_signal_connect (window, "delete_event",
286                     G_CALLBACK (gtk_main_quit), NULL);
287
288   box = gtk_vbox_new (FALSE, 3);
289   gtk_container_add (GTK_CONTAINER (window), box);
290
291   /* A check button using the tooltip-markup property */
292   button = gtk_check_button_new_with_label ("This one uses the tooltip-markup property");
293   gtk_widget_set_tooltip_text (button, "Hello, I am a static tooltip.");
294   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
295
296   text = gtk_widget_get_tooltip_text (button);
297   markup = gtk_widget_get_tooltip_markup (button);
298   g_assert (g_str_equal ("Hello, I am a static tooltip.", text));
299   g_assert (g_str_equal ("Hello, I am a static tooltip.", markup));
300   g_free (text); g_free (markup);
301
302   /* A check button using the query-tooltip signal */
303   button = gtk_check_button_new_with_label ("I use the query-tooltip signal");
304   g_object_set (button, "has-tooltip", TRUE, NULL);
305   g_signal_connect (button, "query-tooltip",
306                     G_CALLBACK (query_tooltip_cb), NULL);
307   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
308
309   /* A label */
310   button = gtk_label_new ("I am just a label");
311   gtk_label_set_selectable (GTK_LABEL (button), FALSE);
312   gtk_widget_set_tooltip_text (button, "Label & and tooltip");
313   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
314
315   text = gtk_widget_get_tooltip_text (button);
316   markup = gtk_widget_get_tooltip_markup (button);
317   g_assert (g_str_equal ("Label & and tooltip", text));
318   g_assert (g_str_equal ("Label &amp; and tooltip", markup));
319   g_free (text); g_free (markup);
320
321   /* A selectable label */
322   button = gtk_label_new ("I am a selectable label");
323   gtk_label_set_selectable (GTK_LABEL (button), TRUE);
324   gtk_widget_set_tooltip_markup (button, "<b>Another</b> Label tooltip");
325   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
326
327   text = gtk_widget_get_tooltip_text (button);
328   markup = gtk_widget_get_tooltip_markup (button);
329   g_assert (g_str_equal ("Another Label tooltip", text));
330   g_assert (g_str_equal ("<b>Another</b> Label tooltip", markup));
331   g_free (text); g_free (markup);
332
333   /* Another one, with a custom tooltip window */
334   button = gtk_check_button_new_with_label ("This one has a custom tooltip window!");
335   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
336
337   tooltip_window = gtk_window_new (GTK_WINDOW_POPUP);
338   tooltip_button = gtk_label_new ("blaat!");
339   gtk_container_add (GTK_CONTAINER (tooltip_window), tooltip_button);
340   gtk_widget_show (tooltip_button);
341
342   gtk_widget_set_tooltip_window (button, GTK_WINDOW (tooltip_window));
343   g_signal_connect (button, "query-tooltip",
344                     G_CALLBACK (query_tooltip_custom_cb), NULL);
345   g_object_set (button, "has-tooltip", TRUE, NULL);
346
347   /* An insensitive button */
348   button = gtk_button_new_with_label ("This one is insensitive");
349   gtk_widget_set_sensitive (button, FALSE);
350   g_object_set (button, "tooltip-text", "Insensitive!", NULL);
351   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
352
353   /* Testcases from Kris without a tree view don't exist. */
354   tree_view = gtk_tree_view_new_with_model (create_model ());
355   gtk_widget_set_size_request (tree_view, 200, 240);
356
357   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
358                                                0, "Test",
359                                                gtk_cell_renderer_text_new (),
360                                                "text", 0,
361                                                NULL);
362
363   g_object_set (tree_view, "has-tooltip", TRUE, NULL);
364   g_signal_connect (tree_view, "query-tooltip",
365                     G_CALLBACK (query_tooltip_tree_view_cb), NULL);
366   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
367                     "changed", G_CALLBACK (selection_changed_cb), tree_view);
368
369   /* Set a tooltip on the column */
370   column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 0);
371   gtk_tree_view_column_set_clickable (column, TRUE);
372   g_object_set (column->button, "tooltip-text", "Header", NULL);
373
374   gtk_box_pack_start (GTK_BOX (box), tree_view, FALSE, FALSE, 2);
375
376   /* And a text view for Matthias */
377   buffer = gtk_text_buffer_new (NULL);
378
379   gtk_text_buffer_get_end_iter (buffer, &iter);
380   gtk_text_buffer_insert (buffer, &iter, "Hello, the text ", -1);
381
382   tag = gtk_text_buffer_create_tag (buffer, "bold", NULL);
383   g_object_set (tag, "weight", PANGO_WEIGHT_BOLD, NULL);
384
385   gtk_text_buffer_get_end_iter (buffer, &iter);
386   gtk_text_buffer_insert_with_tags (buffer, &iter, "in bold", -1, tag, NULL);
387
388   gtk_text_buffer_get_end_iter (buffer, &iter);
389   gtk_text_buffer_insert (buffer, &iter, " has a tooltip!", -1);
390
391   text_view = gtk_text_view_new_with_buffer (buffer);
392   gtk_widget_set_size_request (text_view, 200, 50);
393
394   g_object_set (text_view, "has-tooltip", TRUE, NULL);
395   g_signal_connect (text_view, "query-tooltip",
396                     G_CALLBACK (query_tooltip_text_view_cb), tag);
397
398   gtk_box_pack_start (GTK_BOX (box), text_view, FALSE, FALSE, 2);
399
400   /* Drawing area */
401   drawing_area = gtk_drawing_area_new ();
402   gtk_widget_set_size_request (drawing_area, 320, 240);
403   g_object_set (drawing_area, "has-tooltip", TRUE, NULL);
404   g_signal_connect (drawing_area, "expose_event",
405                     G_CALLBACK (drawing_area_expose), NULL);
406   g_signal_connect (drawing_area, "query-tooltip",
407                     G_CALLBACK (query_tooltip_drawing_area_cb), NULL);
408   gtk_box_pack_start (GTK_BOX (box), drawing_area, FALSE, FALSE, 2);
409
410   /* Done! */
411   gtk_widget_show_all (window);
412
413   gtk_main ();
414
415   return 0;
416 }