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 | |
10 | struct _GtkLayoutOverlay |
11 | { |
12 | GtkInspectorOverlay parent_instance; |
13 | }; |
14 | |
15 | struct _GtkLayoutOverlayClass |
16 | { |
17 | GtkInspectorOverlayClass parent_class; |
18 | }; |
19 | |
20 | G_DEFINE_TYPE (GtkLayoutOverlay, gtk_layout_overlay, GTK_TYPE_INSPECTOR_OVERLAY) |
21 | |
22 | |
23 | static int |
24 | get_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 | |
34 | static void |
35 | get_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 | |
44 | static void |
45 | get_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 | |
54 | static void |
55 | get_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 | |
64 | static void |
65 | recurse_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 | |
126 | next: |
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 | |
162 | static void |
163 | gtk_layout_overlay_snapshot (GtkInspectorOverlay *overlay, |
164 | GtkSnapshot *snapshot, |
165 | GskRenderNode *node, |
166 | GtkWidget *widget) |
167 | { |
168 | recurse_child_widgets (widget, snapshot); |
169 | } |
170 | |
171 | static void |
172 | gtk_layout_overlay_init (GtkLayoutOverlay *self) |
173 | { |
174 | |
175 | } |
176 | |
177 | static void |
178 | gtk_layout_overlay_class_init (GtkLayoutOverlayClass *klass) |
179 | { |
180 | GtkInspectorOverlayClass *overlay_class = (GtkInspectorOverlayClass *)klass; |
181 | |
182 | overlay_class->snapshot = gtk_layout_overlay_snapshot; |
183 | } |
184 | |
185 | GtkInspectorOverlay * |
186 | gtk_layout_overlay_new (void) |
187 | { |
188 | return g_object_new (GTK_TYPE_LAYOUT_OVERLAY, NULL); |
189 | } |
190 | |