8 #include <yui/Libyui_config.h>
11 #include "ygtklinklabel.h"
13 static guint link_clicked_signal;
15 G_DEFINE_TYPE (
YGtkLinkLabel, ygtk_link_label, GTK_TYPE_WIDGET)
19 gtk_widget_set_has_window(GTK_WIDGET(label), FALSE);
22 static void ygtk_link_label_realize (GtkWidget *widget)
24 GTK_WIDGET_CLASS (ygtk_link_label_parent_class)->realize (widget);
25 GdkWindowAttr attributes;
27 gtk_widget_get_allocation(widget, &alloc);
28 attributes.x = alloc.x;
29 attributes.y = alloc.y;
30 attributes.width = alloc.width;
31 attributes.height = alloc.height;
32 attributes.window_type = GDK_WINDOW_CHILD;
33 attributes.wclass = GDK_INPUT_OUTPUT;
34 attributes.event_mask = gtk_widget_get_events (widget) |
35 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
36 gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
37 attributes.cursor = gdk_cursor_new_for_display (
38 gtk_widget_get_display (widget), GDK_HAND2);
41 label->link_window = gdk_window_new (gtk_widget_get_window(widget), &attributes, attributes_mask);
42 gdk_window_set_user_data (label->link_window, widget);
43 GdkRGBA white = { 1, 1, 1, 1 };
44 gdk_window_set_background_rgba(label->link_window, &white);
45 g_object_unref (G_OBJECT(attributes.cursor));
48 static void ygtk_link_label_unrealize (GtkWidget *widget)
51 if (label->link_window) {
52 gdk_window_set_user_data (label->link_window, NULL);
53 gdk_window_destroy (label->link_window);
54 label->link_window = NULL;
56 GTK_WIDGET_CLASS (ygtk_link_label_parent_class)->unrealize (widget);
59 static void ygtk_link_label_map (GtkWidget *widget)
63 gtk_widget_queue_resize (widget);
64 GTK_WIDGET_CLASS (ygtk_link_label_parent_class)->map (widget);
67 static void ygtk_link_label_clear_layout (
YGtkLinkLabel *label)
70 g_object_unref (label->layout);
73 if (label->link_layout) {
74 g_object_unref (label->link_layout);
75 label->link_layout = NULL;
79 static void ygtk_link_label_ensure_layout (
YGtkLinkLabel *label)
81 GtkWidget *widget = GTK_WIDGET (label);
83 label->layout = gtk_widget_create_pango_layout (widget, label->text);
84 pango_layout_set_single_paragraph_mode (label->layout, TRUE);
85 pango_layout_set_ellipsize (label->layout, PANGO_ELLIPSIZE_END);
87 if (!label->link_layout) {
88 label->link_layout = gtk_widget_create_pango_layout (widget, label->link);
89 PangoAttrList *attrbs = pango_attr_list_new();
90 pango_attr_list_insert (attrbs, pango_attr_underline_new (PANGO_UNDERLINE_SINGLE));
91 pango_attr_list_insert (attrbs, pango_attr_foreground_new (0, 0, 0xffff));
92 pango_layout_set_attributes (label->link_layout, attrbs);
93 pango_attr_list_unref (attrbs);
97 static void ygtk_link_label_finalize (GObject *
object)
100 g_free (label->text);
101 g_free (label->link);
102 ygtk_link_label_clear_layout (label);
103 G_OBJECT_CLASS (ygtk_link_label_parent_class)->finalize (
object);
106 static void ygtk_link_label_size_request (GtkWidget *widget,
107 GtkRequisition *requisition)
110 ygtk_link_label_ensure_layout (label);
111 requisition->width = requisition->height = 0;
112 GtkStyleContext *style_ctx;
113 style_ctx = gtk_widget_get_style_context(widget);
116 PangoContext *context;
117 PangoFontMetrics *metrics;
118 gint ascent, descent;
119 context = pango_layout_get_context (label->layout);
120 metrics = pango_context_get_metrics (context, gtk_style_context_get_font(style_ctx, GTK_STATE_FLAG_NORMAL),
121 pango_context_get_language (context));
122 ascent = pango_font_metrics_get_ascent (metrics);
123 descent = pango_font_metrics_get_descent (metrics);
124 pango_font_metrics_unref (metrics);
125 requisition->height = PANGO_PIXELS (ascent + descent);
130 ygtk_link_label_get_preferred_width (GtkWidget *widget,
134 GtkRequisition requisition;
135 ygtk_link_label_size_request (widget, &requisition);
136 *minimal_width = *natural_width = requisition.width;
140 ygtk_link_label_get_preferred_height (GtkWidget *widget,
141 gint *minimal_height,
142 gint *natural_height)
144 GtkRequisition requisition;
145 ygtk_link_label_size_request (widget, &requisition);
146 *minimal_height = *natural_height = requisition.height;
151 static void ygtk_link_label_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
153 GTK_WIDGET_CLASS (ygtk_link_label_parent_class)->size_allocate (widget, allocation);
156 gint width = allocation->width * PANGO_SCALE;
157 PangoRectangle logical;
158 pango_layout_set_width (label->layout, -1);
159 pango_layout_get_extents (label->layout, NULL, &logical);
160 if (label->link_window) {
161 if (*label->text && (logical.width > width || label->link_always_visible)) {
162 PangoRectangle link_logical;
163 pango_layout_get_extents (label->link_layout, NULL, &link_logical);
164 gint link_width = link_logical.width / PANGO_SCALE;
166 width = width - link_logical.width - SPACING*PANGO_SCALE;
167 if (logical.width < width && label->link_always_visible)
168 x = allocation->x + logical.width/PANGO_SCALE + SPACING;
170 x = allocation->x + (allocation->width - link_width);
171 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
172 x = (2*allocation->x + allocation->width) - (x + link_width);
173 gdk_window_move_resize (label->link_window, x,
174 allocation->y, link_width, allocation->height);
175 if (logical.width > width)
176 pango_layout_set_width (label->layout, width);
177 gdk_window_show (label->link_window);
180 gdk_window_hide (label->link_window);
184 static gboolean ygtk_link_label_on_draw (GtkWidget *widget, cairo_t *cr)
187 ygtk_link_label_ensure_layout (label);
189 GtkStyleContext *style = gtk_widget_get_style_context(widget);
190 if (gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget))) {
192 gint width = gtk_widget_get_allocated_width (widget);
193 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) {
194 PangoRectangle extent;
195 pango_layout_get_extents (label->layout, NULL, &extent);
196 x = width - extent.width/PANGO_SCALE;
198 gtk_render_layout (style, cr, x, 0, label->layout);
201 if (gtk_cairo_should_draw_window(cr, label->link_window)) {
202 gtk_cairo_transform_to_window (cr, widget, label->link_window);
203 gtk_render_layout (style, cr, 0, 0, label->link_layout);
208 static gboolean ygtk_link_label_button_press_event (GtkWidget *widget, GdkEventButton *event)
210 g_signal_emit (widget, link_clicked_signal, 0, NULL);
215 const gchar *text,
const gchar *link, gboolean link_always_visible)
217 g_free (label->text);
218 label->text = g_strdup (text);
220 g_free (label->link);
221 label->link = g_strdup (link);
223 label->link_always_visible = link_always_visible;
224 ygtk_link_label_clear_layout (label);
225 gtk_widget_queue_resize (GTK_WIDGET (label));
228 GtkWidget *ygtk_link_label_new (
const gchar *text,
const gchar *link)
230 YGtkLinkLabel *label = g_object_new (YGTK_TYPE_LINK_LABEL, NULL);
231 ygtk_link_label_set_text (label, text, link, TRUE);
232 return (GtkWidget *) label;
237 ygtk_link_label_parent_class = g_type_class_peek_parent (klass);
239 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
240 widget_class->realize = ygtk_link_label_realize;
241 widget_class->unrealize = ygtk_link_label_unrealize;
242 widget_class->map = ygtk_link_label_map;
244 widget_class->get_preferred_height = ygtk_link_label_get_preferred_height;
245 widget_class->get_preferred_width = ygtk_link_label_get_preferred_width;
247 widget_class->size_allocate = ygtk_link_label_size_allocate;
248 widget_class->draw = ygtk_link_label_on_draw;
249 widget_class->button_press_event = ygtk_link_label_button_press_event;
251 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
252 gobject_class->finalize = ygtk_link_label_finalize;
254 link_clicked_signal = g_signal_new (
"link-clicked",
255 G_TYPE_FROM_CLASS (G_OBJECT_CLASS (klass)), G_SIGNAL_RUN_LAST,
257 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);