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 PangoFontDescription *font_desc;
114 style_ctx = gtk_widget_get_style_context(widget);
117 PangoContext *context;
118 PangoFontMetrics *metrics;
119 gint ascent, descent;
120 context = pango_layout_get_context (label->layout);
121 gtk_style_context_get (style_ctx, GTK_STATE_FLAG_NORMAL,
"font", &font_desc, NULL);
122 metrics = pango_context_get_metrics (context, font_desc,
123 pango_context_get_language (context));
124 ascent = pango_font_metrics_get_ascent (metrics);
125 descent = pango_font_metrics_get_descent (metrics);
126 pango_font_metrics_unref (metrics);
127 requisition->height = PANGO_PIXELS (ascent + descent);
132 ygtk_link_label_get_preferred_width (GtkWidget *widget,
136 GtkRequisition requisition;
137 ygtk_link_label_size_request (widget, &requisition);
138 *minimal_width = *natural_width = requisition.width;
142 ygtk_link_label_get_preferred_height (GtkWidget *widget,
143 gint *minimal_height,
144 gint *natural_height)
146 GtkRequisition requisition;
147 ygtk_link_label_size_request (widget, &requisition);
148 *minimal_height = *natural_height = requisition.height;
153 static void ygtk_link_label_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
155 GTK_WIDGET_CLASS (ygtk_link_label_parent_class)->size_allocate (widget, allocation);
158 gint width = allocation->width * PANGO_SCALE;
159 PangoRectangle logical;
160 pango_layout_set_width (label->layout, -1);
161 pango_layout_get_extents (label->layout, NULL, &logical);
162 if (label->link_window) {
163 if (*label->text && (logical.width > width || label->link_always_visible)) {
164 PangoRectangle link_logical;
165 pango_layout_get_extents (label->link_layout, NULL, &link_logical);
166 gint link_width = link_logical.width / PANGO_SCALE;
168 width = width - link_logical.width - SPACING*PANGO_SCALE;
169 if (logical.width < width && label->link_always_visible)
170 x = allocation->x + logical.width/PANGO_SCALE + SPACING;
172 x = allocation->x + (allocation->width - link_width);
173 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
174 x = (2*allocation->x + allocation->width) - (x + link_width);
175 gdk_window_move_resize (label->link_window, x,
176 allocation->y, link_width, allocation->height);
177 if (logical.width > width)
178 pango_layout_set_width (label->layout, width);
179 gdk_window_show (label->link_window);
182 gdk_window_hide (label->link_window);
186 static gboolean ygtk_link_label_on_draw (GtkWidget *widget, cairo_t *cr)
189 ygtk_link_label_ensure_layout (label);
191 GtkStyleContext *style = gtk_widget_get_style_context(widget);
192 if (gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget))) {
194 gint width = gtk_widget_get_allocated_width (widget);
195 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) {
196 PangoRectangle extent;
197 pango_layout_get_extents (label->layout, NULL, &extent);
198 x = width - extent.width/PANGO_SCALE;
200 gtk_render_layout (style, cr, x, 0, label->layout);
203 if (gtk_cairo_should_draw_window(cr, label->link_window)) {
204 gtk_cairo_transform_to_window (cr, widget, label->link_window);
205 gtk_render_layout (style, cr, 0, 0, label->link_layout);
210 static gboolean ygtk_link_label_button_press_event (GtkWidget *widget, GdkEventButton *event)
212 g_signal_emit (widget, link_clicked_signal, 0, NULL);
217 const gchar *text,
const gchar *link, gboolean link_always_visible)
219 g_free (label->text);
220 label->text = g_strdup (text);
222 g_free (label->link);
223 label->link = g_strdup (link);
225 label->link_always_visible = link_always_visible;
226 ygtk_link_label_clear_layout (label);
227 gtk_widget_queue_resize (GTK_WIDGET (label));
230 GtkWidget *ygtk_link_label_new (
const gchar *text,
const gchar *link)
232 YGtkLinkLabel *label = g_object_new (YGTK_TYPE_LINK_LABEL, NULL);
233 ygtk_link_label_set_text (label, text, link, TRUE);
234 return (GtkWidget *) label;
239 ygtk_link_label_parent_class = g_type_class_peek_parent (klass);
241 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
242 widget_class->realize = ygtk_link_label_realize;
243 widget_class->unrealize = ygtk_link_label_unrealize;
244 widget_class->map = ygtk_link_label_map;
246 widget_class->get_preferred_height = ygtk_link_label_get_preferred_height;
247 widget_class->get_preferred_width = ygtk_link_label_get_preferred_width;
249 widget_class->size_allocate = ygtk_link_label_size_allocate;
250 widget_class->draw = ygtk_link_label_on_draw;
251 widget_class->button_press_event = ygtk_link_label_button_press_event;
253 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
254 gobject_class->finalize = ygtk_link_label_finalize;
256 link_clicked_signal = g_signal_new (
"link-clicked",
257 G_TYPE_FROM_CLASS (G_OBJECT_CLASS (klass)), G_SIGNAL_RUN_LAST,
259 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);