1/* Fixed Layout
2 * #Keywords: GtkLayoutManager
3 *
4 * GtkFixed is a container that allows placing and transforming
5 * widgets manually.
6 */
7
8#include <gtk/gtk.h>
9
10/* This enumeration determines the paint order */
11enum {
12 FACE_BACK,
13 FACE_LEFT,
14 FACE_BOTTOM,
15 FACE_RIGHT,
16 FACE_TOP,
17 FACE_FRONT,
18
19 N_FACES
20};
21
22/* Map face widgets to CSS classes */
23static struct {
24 GtkWidget *face;
25 const char *css_class;
26} faces[N_FACES] = {
27 [FACE_BACK] = { NULL, "back", },
28 [FACE_LEFT] = { NULL, .css_class: "left", },
29 [FACE_RIGHT] = { NULL, .css_class: "right", },
30 [FACE_TOP] = { NULL, .css_class: "top", },
31 [FACE_BOTTOM] = { NULL, .css_class: "bottom", },
32 [FACE_FRONT] = { NULL, .css_class: "front", },
33};
34
35static GtkWidget *
36create_faces (void)
37{
38 GtkWidget *fixed = gtk_fixed_new ();
39 int face_size = 200;
40 float w, h, d, p;
41
42 gtk_widget_set_overflow (widget: fixed, overflow: GTK_OVERFLOW_VISIBLE);
43
44 w = (float) face_size / 2.f;
45 h = (float) face_size / 2.f;
46 d = (float) face_size / 2.f;
47 p = face_size * 3.f;
48
49 for (int i = 0; i < N_FACES; i++)
50 {
51 GskTransform *transform = NULL;
52
53 /* Add a face */
54 faces[i].face = gtk_frame_new (NULL);
55 gtk_widget_set_size_request (widget: faces[i].face, width: face_size, height: face_size);
56 gtk_widget_add_css_class (widget: faces[i].face, css_class: faces[i].css_class);
57 gtk_fixed_put (GTK_FIXED (fixed), widget: faces[i].face, x: 0, y: 0);
58
59 /* Set up the transformation for each face */
60 transform = gsk_transform_translate (next: transform, point: &GRAPHENE_POINT_INIT (w, h));
61 transform = gsk_transform_perspective (next: transform, depth: p);
62 transform = gsk_transform_rotate_3d (next: transform, angle: -30.f, axis: graphene_vec3_x_axis ());
63 transform = gsk_transform_rotate_3d (next: transform, angle: 135.f, axis: graphene_vec3_y_axis ());
64 transform = gsk_transform_translate_3d (next: transform, point: &GRAPHENE_POINT3D_INIT (0, 0, -face_size / 6.f));
65
66 switch (i)
67 {
68 case FACE_FRONT:
69 transform = gsk_transform_rotate_3d (next: transform, angle: 0.f, axis: graphene_vec3_y_axis ());
70 break;
71
72 case FACE_BACK:
73 transform = gsk_transform_rotate_3d (next: transform, angle: -180.f, axis: graphene_vec3_y_axis ());
74 break;
75
76 case FACE_RIGHT:
77 transform = gsk_transform_rotate_3d (next: transform, angle: 90.f, axis: graphene_vec3_y_axis ());
78 break;
79
80 case FACE_LEFT:
81 transform = gsk_transform_rotate_3d (next: transform, angle: -90.f, axis: graphene_vec3_y_axis ());
82 break;
83
84 case FACE_TOP:
85 transform = gsk_transform_rotate_3d (next: transform, angle: 90.f, axis: graphene_vec3_x_axis ());
86 break;
87
88 case FACE_BOTTOM:
89 transform = gsk_transform_rotate_3d (next: transform, angle: -90.f, axis: graphene_vec3_x_axis ());
90 break;
91
92 default:
93 break;
94 }
95
96 transform = gsk_transform_translate_3d (next: transform, point: &GRAPHENE_POINT3D_INIT (0, 0, d));
97 transform = gsk_transform_translate_3d (next: transform, point: &GRAPHENE_POINT3D_INIT (-w, -h, 0));
98
99 gtk_fixed_set_child_transform (GTK_FIXED (fixed), widget: faces[i].face, transform);
100 gsk_transform_unref (self: transform);
101 }
102
103 return fixed;
104}
105
106static GtkWidget *demo_window = NULL;
107static GtkCssProvider *provider = NULL;
108
109static void
110close_window (GtkWidget *widget)
111{
112 /* Reset the state */
113 for (int i = 0; i < N_FACES; i++)
114 faces[i].face = NULL;
115
116 gtk_style_context_remove_provider_for_display (display: gdk_display_get_default (),
117 GTK_STYLE_PROVIDER (provider));
118 provider = NULL;
119
120 demo_window = NULL;
121}
122
123static GtkWidget *
124create_demo_window (GtkWidget *do_widget)
125{
126 GtkWidget *window, *sw, *fixed, *cube;
127
128 window = gtk_window_new ();
129 gtk_window_set_display (GTK_WINDOW (window), display: gtk_widget_get_display (widget: do_widget));
130 gtk_window_set_title (GTK_WINDOW (window), title: "Fixed Layout");
131 gtk_window_set_default_size (GTK_WINDOW (window), width: 600, height: 400);
132 g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
133
134 sw = gtk_scrolled_window_new ();
135 gtk_window_set_child (GTK_WINDOW (window), child: sw);
136
137 fixed = gtk_fixed_new ();
138 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: fixed);
139 gtk_widget_set_halign (GTK_WIDGET (fixed), align: GTK_ALIGN_CENTER);
140 gtk_widget_set_valign (GTK_WIDGET (fixed), align: GTK_ALIGN_CENTER);
141
142 cube = create_faces ();
143 gtk_fixed_put (GTK_FIXED (fixed), widget: cube, x: 0, y: 0);
144 gtk_widget_set_overflow (widget: fixed, overflow: GTK_OVERFLOW_VISIBLE);
145
146 provider = gtk_css_provider_new ();
147 gtk_css_provider_load_from_resource (css_provider: provider, resource_path: "/fixed/fixed.css");
148 gtk_style_context_add_provider_for_display (display: gdk_display_get_default (),
149 GTK_STYLE_PROVIDER (provider),
150 priority: 800);
151 g_object_unref (object: provider);
152
153 return window;
154}
155
156GtkWidget*
157do_fixed (GtkWidget *do_widget)
158{
159 if (demo_window == NULL)
160 demo_window = create_demo_window (do_widget);
161
162 if (!gtk_widget_get_visible (widget: demo_window))
163 gtk_widget_show (widget: demo_window);
164 else
165 gtk_window_destroy (GTK_WINDOW (demo_window));
166
167 return demo_window;
168}
169

source code of gtk/demos/gtk-demo/fixed.c