1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2011, 2012, 2014 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "pspp-widget-facade.h"
26 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
29 inset_rectangle (const GdkRectangle *src,
30 const GtkBorder *inset,
33 dst->x = src->x + inset->left;
34 dst->y = src->y + inset->top;
35 dst->width = MAX (1, src->width - inset->left - inset->right);
36 dst->height = MAX (1, src->height - inset->top - inset->bottom);
40 thicken_border (gint x, gint y, GtkBorder *border)
49 facade_get_style (GtkWidget *base,
53 GString path, class_path;
59 gtk_widget_path (base, NULL, &path.str, NULL);
60 path.len = path.allocated_len = strlen (path.str);
62 gtk_widget_class_path (base, NULL, &class_path.str, NULL);
63 class_path.len = class_path.allocated_len = strlen (class_path.str);
65 va_start (args, type1);
66 for (type = final_type = type1; type != 0; type = va_arg (args, GType))
68 const gchar *type_name = g_type_name (type);
69 g_string_append_printf (&path, ".%s", type_name);
70 g_string_append_printf (&class_path, ".%s", type_name);
75 style = gtk_rc_get_style_by_paths (gtk_widget_get_settings (base),
76 path.str, class_path.str, final_type);
79 free (class_path.str);
85 facade_hbox_get_base_size_request (gint border_width,
88 GtkRequisition *request)
90 request->width = border_width * 2;
92 request->width += spacing * (n_children - 1);
94 request->height = border_width * 2;
98 facade_hbox_add_child_size_request (gint hbox_border_width,
99 const GtkRequisition *child_request,
101 GtkRequisition *request)
103 request->width += child_request->width + child_padding * 2;
104 request->height = MAX (request->height,
105 hbox_border_width * 2 + child_request->height);
109 facade_arrow_get_size_request (gint xpad,
111 GtkRequisition *request)
113 #define MIN_ARROW_SIZE 15
114 request->width = MIN_ARROW_SIZE + xpad * 2;
115 request->height = MIN_ARROW_SIZE + ypad * 2;
119 facade_alignment_get_size_request (gint border_width,
124 const GtkRequisition *child_request,
125 GtkRequisition *request)
127 request->width = (border_width * 2 + padding_left + padding_right
128 + child_request->width);
129 request->height = (border_width * 2 + padding_top + padding_bottom
130 + child_request->height);
134 facade_label_get_size_request (gint xpad,
138 GtkRequisition *request)
142 layout = facade_label_get_layout (base, text);
143 facade_label_get_size_request_from_layout (xpad, ypad, layout, request);
144 g_object_unref (layout);
148 facade_label_get_size_request_from_layout (gint xpad,
151 GtkRequisition *request)
153 PangoRectangle logical_rect;
155 pango_layout_get_extents (layout, NULL, &logical_rect);
156 request->width = xpad * 2 + PANGO_PIXELS (logical_rect.width);
157 request->height = ypad * 2 + PANGO_PIXELS (logical_rect.height);
161 facade_label_get_layout (GtkWidget *base,
164 PangoAlignment alignment;
168 rtl = gtk_widget_get_direction (base) == GTK_TEXT_DIR_RTL;
169 alignment = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
171 layout = gtk_widget_create_pango_layout (base, text);
172 pango_layout_set_alignment (layout, alignment);
178 facade_button_get_inner_border (GtkStyle *button_style,
179 GtkBorder *inner_border)
181 GtkBorder *tmp_border;
183 gtk_style_get (button_style, GTK_TYPE_BUTTON,
184 "inner-border", &tmp_border,
189 *inner_border = *tmp_border;
190 gtk_border_free (tmp_border);
194 static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
195 *inner_border = default_inner_border;
200 facade_button_get_size_request (gint border_width,
202 GtkStyle *button_style,
203 const GtkRequisition *child_request,
204 GtkRequisition *request)
206 GtkBorder inner_border;
211 gtk_style_get (button_style, GTK_TYPE_BUTTON,
212 "focus-line-width", &focus_width,
213 "focus-padding", &focus_pad,
215 facade_button_get_inner_border (button_style, &inner_border);
217 common_width = 2 * (border_width + focus_width + focus_pad);
218 request->width = (common_width
219 + 2 * button_style->xthickness
220 + inner_border.left + inner_border.right
221 + child_request->width);
222 request->height = (common_width
223 + 2 * button_style->ythickness
224 + inner_border.top + inner_border.bottom
225 + child_request->height);
229 facade_button_get_focus_inset (gint border_width,
231 GtkStyle *button_style,
232 GtkBorder *focus_inset)
234 facade_button_get_inner_border (button_style, focus_inset);
235 thicken_border (border_width + button_style->xthickness,
236 border_width + button_style->ythickness,
241 facade_button_get_label_inset (gint border_width,
243 GtkStyle *button_style,
244 GtkBorder *label_inset)
249 facade_button_get_focus_inset (border_width, base, button_style,
252 gtk_style_get (button_style, GTK_TYPE_BUTTON,
253 "focus-line-width", &focus_width,
254 "focus-padding", &focus_pad,
256 thicken_border (focus_width + focus_pad,
257 focus_width + focus_pad,
262 get_layout_location (GtkWidget *base,
263 const GdkRectangle *label_area,
272 PangoRectangle logical;
275 if (gtk_widget_get_direction (base) == GTK_TEXT_DIR_RTL)
276 xalign = 1.0 - xalign;
278 pango_layout_get_pixel_extents (layout, NULL, &logical);
280 facade_label_get_size_request_from_layout (xpad, ypad, layout, &req);
282 *x = floor (label_area->x + xpad + xalign * (label_area->width - req.width));
284 if (gtk_widget_get_direction (base) == GTK_TEXT_DIR_LTR)
285 *x = MAX (*x, label_area->x + xpad);
287 *x = MIN (*x, label_area->x + label_area->width - xpad);
290 /* bgo#315462 - For single-line labels, *do* align the requisition with
291 * respect to the allocation, even if we are under-allocated. For multi-line
292 * labels, always show the top of the text when they are under-allocated.
293 * The rationale is this:
295 * - Single-line labels appear in GtkButtons, and it is very easy to get them
296 * to be smaller than their requisition. The button may clip the label,
297 * but the label will still be able to show most of itself and the focus
298 * rectangle. Also, it is fairly easy to read a single line of clipped
301 * - Multi-line labels should not be clipped to showing "something in the
302 * middle". You want to read the first line, at least, to get some
305 if (pango_layout_get_line_count (layout) == 1)
306 *y = floor (label_area->y + ypad
307 + (label_area->height - req.height) * yalign);
309 *y = floor (label_area->y + ypad
310 + MAX (((label_area->height - req.height) * yalign),
315 facade_button_render (GtkWidget *base,
317 const GdkRectangle *button_area,
319 GtkStyle *button_style,
320 GtkStateType state_type,
322 GtkStyle *label_style,
329 GdkRectangle label_area;
334 /* Paint the button. */
335 gtk_paint_box (button_style, cr,
337 GTK_SHADOW_OUT, base, "button",
338 button_area->x + border_width,
339 button_area->y + border_width,
340 button_area->width - border_width * 2,
341 button_area->height - border_width * 2);
343 /* Figure out where the label should go. */
344 facade_button_get_label_inset (border_width, base, button_style, &inset);
345 inset_rectangle (button_area, &inset, &label_area);
347 /* Paint the label. */
348 layout = facade_label_get_layout (base, label);
349 get_layout_location (base, &label_area, layout, xpad, ypad, xalign, yalign,
352 gtk_paint_layout (label_style, cr, state_type, FALSE,
353 base, "label", x, y, layout);
355 g_object_unref (layout);