1
2#include "config.h"
3#include "layoutoverlay.h"
4#include "gtkwidgetprivate.h"
5#include "gtkcssstyleprivate.h"
6#include "gtkcssnodeprivate.h"
7#include "gtkcssnumbervalueprivate.h"
8#include "gtknative.h"
9
10struct _GtkLayoutOverlay
11{
12 GtkInspectorOverlay parent_instance;
13};
14
15struct _GtkLayoutOverlayClass
16{
17 GtkInspectorOverlayClass parent_class;
18};
19
20G_DEFINE_TYPE (GtkLayoutOverlay, gtk_layout_overlay, GTK_TYPE_INSPECTOR_OVERLAY)
21
22
23static int
24get_number (GtkCssValue *value)
25{
26 double d = _gtk_css_number_value_get (number: value, one_hundred_percent: 100);
27
28 if (d < 1)
29 return ceil (x: d);
30 else
31 return floor (x: d);
32}
33
34static void
35get_box_margin (GtkCssStyle *style,
36 GtkBorder *margin)
37{
38 margin->top = get_number (value: style->size->margin_top);
39 margin->left = get_number (value: style->size->margin_left);
40 margin->bottom = get_number (value: style->size->margin_bottom);
41 margin->right = get_number (value: style->size->margin_right);
42}
43
44static void
45get_box_border (GtkCssStyle *style,
46 GtkBorder *border)
47{
48 border->top = get_number (value: style->border->border_top_width);
49 border->left = get_number (value: style->border->border_left_width);
50 border->bottom = get_number (value: style->border->border_bottom_width);
51 border->right = get_number (value: style->border->border_right_width);
52}
53
54static void
55get_box_padding (GtkCssStyle *style,
56 GtkBorder *border)
57{
58 border->top = get_number (value: style->size->padding_top);
59 border->left = get_number (value: style->size->padding_left);
60 border->bottom = get_number (value: style->size->padding_bottom);
61 border->right = get_number (value: style->size->padding_right);
62}
63
64static void
65recurse_child_widgets (GtkWidget *widget,
66 GtkSnapshot *snapshot)
67{
68 int width = gtk_widget_get_width (widget);
69 int height = gtk_widget_get_height (widget);
70 gboolean needs_clip;
71 GtkCssStyle *style;
72 GtkWidget *child;
73 GtkBorder boxes[4];
74 const GdkRGBA colors[4] = {
75 {0.7, 0.0, 0.7, 0.6}, /* Padding */
76 {0.0, 0.0, 0.0, 0.0}, /* Border */
77 {0.7, 0.7, 0.0, 0.6}, /* CSS Margin */
78 {0.7, 0.0, 0.0, 0.6}, /* Widget Margin */
79 };
80 int i;
81
82 if (!gtk_widget_get_mapped (widget))
83 return;
84
85 G_STATIC_ASSERT (G_N_ELEMENTS (boxes) == G_N_ELEMENTS (colors));
86
87 style = gtk_css_node_get_style (cssnode: gtk_widget_get_css_node (widget));
88 get_box_padding (style, border: &boxes[0]);
89 get_box_border (style, border: &boxes[1]);
90 get_box_margin (style, margin: &boxes[2]);
91
92 /* TODO: Eh, left = start? RTL? */
93 boxes[3].left = gtk_widget_get_margin_start (widget);
94 boxes[3].top = gtk_widget_get_margin_top (widget);
95 boxes[3].right = gtk_widget_get_margin_end (widget);
96 boxes[3].bottom = gtk_widget_get_margin_bottom (widget);
97
98 /* width/height are the content size and we're going to grow that
99 * as we're drawing the boxes, as well as offset the origin.
100 * Right now we're at the widget's own origin.
101 */
102 gtk_snapshot_save (snapshot);
103 gtk_snapshot_push_debug (snapshot, message: "Widget layout debugging");
104
105 for (i = 0; i < G_N_ELEMENTS (boxes); i ++)
106 {
107 const GdkRGBA *color = &colors[i];
108 const GtkBorder *box = &boxes[i];
109
110 if (gdk_rgba_is_clear (rgba: color))
111 goto next;
112
113 if (box->top > 0)
114 gtk_snapshot_append_color (snapshot, color,
115 bounds: &GRAPHENE_RECT_INIT ( 0, - box->top, width, box->top));
116 if (box->right > 0)
117 gtk_snapshot_append_color (snapshot, color,
118 bounds: &GRAPHENE_RECT_INIT (width, 0, box->right, height));
119 if (box->bottom > 0)
120 gtk_snapshot_append_color (snapshot, color,
121 bounds: &GRAPHENE_RECT_INIT (0, height, width, box->bottom));
122 if (box->left > 0)
123 gtk_snapshot_append_color (snapshot, color,
124 bounds: &GRAPHENE_RECT_INIT (- box->left, 0, box->left, height));
125
126next:
127 /* Grow box + offset */
128 width += box->left + box->right;
129 height += box->top + box->bottom;
130 gtk_snapshot_translate (snapshot, point: &GRAPHENE_POINT_INIT (- box->left, - box->top));
131 }
132
133 gtk_snapshot_pop (snapshot);
134
135
136 needs_clip = gtk_widget_get_overflow (widget) == GTK_OVERFLOW_HIDDEN &&
137 gtk_widget_get_first_child (widget) != NULL;
138
139 if (needs_clip)
140 gtk_snapshot_push_clip (snapshot,
141 bounds: &GRAPHENE_RECT_INIT (0, 0, gtk_widget_get_width (widget), gtk_widget_get_height (widget)));
142
143 /* Recurse into child widgets */
144 for (child = gtk_widget_get_first_child (widget);
145 child != NULL;
146 child = gtk_widget_get_next_sibling (widget: child))
147 {
148 gtk_snapshot_save (snapshot);
149 gtk_snapshot_transform (snapshot, transform: child->priv->transform);
150
151 recurse_child_widgets (widget: child, snapshot);
152
153 gtk_snapshot_restore (snapshot);
154 }
155
156 if (needs_clip)
157 gtk_snapshot_pop (snapshot);
158
159 gtk_snapshot_restore (snapshot);
160}
161
162static void
163gtk_layout_overlay_snapshot (GtkInspectorOverlay *overlay,
164 GtkSnapshot *snapshot,
165 GskRenderNode *node,
166 GtkWidget *widget)
167{
168 recurse_child_widgets (widget, snapshot);
169}
170
171static void
172gtk_layout_overlay_init (GtkLayoutOverlay *self)
173{
174
175}
176
177static void
178gtk_layout_overlay_class_init (GtkLayoutOverlayClass *klass)
179{
180 GtkInspectorOverlayClass *overlay_class = (GtkInspectorOverlayClass *)klass;
181
182 overlay_class->snapshot = gtk_layout_overlay_snapshot;
183}
184
185GtkInspectorOverlay *
186gtk_layout_overlay_new (void)
187{
188 return g_object_new (GTK_TYPE_LAYOUT_OVERLAY, NULL);
189}
190

source code of gtk/gtk/inspector/layoutoverlay.c