1 | #include "demo2layout.h" |
2 | #include "four_point_transform.h" |
3 | |
4 | struct _Demo2Layout |
5 | { |
6 | GtkLayoutManager parent_instance; |
7 | |
8 | float position; |
9 | float offset; |
10 | }; |
11 | |
12 | struct _Demo2LayoutClass |
13 | { |
14 | GtkLayoutManagerClass parent_class; |
15 | }; |
16 | |
17 | G_DEFINE_TYPE (Demo2Layout, demo2_layout, GTK_TYPE_LAYOUT_MANAGER) |
18 | |
19 | static void |
20 | demo2_layout_measure (GtkLayoutManager *layout_manager, |
21 | GtkWidget *widget, |
22 | GtkOrientation orientation, |
23 | int for_size, |
24 | int *minimum, |
25 | int *natural, |
26 | int *minimum_baseline, |
27 | int *natural_baseline) |
28 | { |
29 | GtkWidget *child; |
30 | int minimum_size = 0; |
31 | int natural_size = 0; |
32 | |
33 | for (child = gtk_widget_get_first_child (widget); |
34 | child != NULL; |
35 | child = gtk_widget_get_next_sibling (widget: child)) |
36 | { |
37 | int child_min = 0, child_nat = 0; |
38 | |
39 | if (!gtk_widget_should_layout (widget: child)) |
40 | continue; |
41 | |
42 | gtk_widget_measure (widget: child, orientation, for_size: -1, |
43 | minimum: &child_min, natural: &child_nat, |
44 | NULL, NULL); |
45 | minimum_size = MAX (minimum_size, child_min); |
46 | natural_size = MAX (natural_size, child_nat); |
47 | } |
48 | |
49 | *minimum = minimum_size; |
50 | *natural = 3 * natural_size; |
51 | } |
52 | |
53 | |
54 | #define RADIANS(angle) ((angle)*M_PI/180.0); |
55 | |
56 | /* Spherical coordinates */ |
57 | #define SX(r,t,p) ((r) * sin (t) * cos (p)) |
58 | #define SZ(r,t,p) ((r) * sin (t) * sin (p)) |
59 | #define SY(r,t,p) ((r) * cos (t)) |
60 | |
61 | static double |
62 | map_offset (double x) |
63 | { |
64 | x = fmod (x: x, y: 180.0); |
65 | if (x < 0.0) |
66 | x += 180.0; |
67 | |
68 | return x; |
69 | } |
70 | |
71 | static void |
72 | demo2_layout_allocate (GtkLayoutManager *layout_manager, |
73 | GtkWidget *widget, |
74 | int width, |
75 | int height, |
76 | int baseline) |
77 | { |
78 | GtkWidget *child; |
79 | GtkRequisition child_req; |
80 | int i, j, k; |
81 | float x0, y0; |
82 | float w, h; |
83 | graphene_point3d_t p1, p2, p3, p4; |
84 | graphene_point3d_t q1, q2, q3, q4; |
85 | double t_1, t_2, p_1, p_2; |
86 | double r; |
87 | graphene_matrix_t m; |
88 | GskTransform *transform; |
89 | double position = DEMO2_LAYOUT (ptr: layout_manager)->position; |
90 | double offset = DEMO2_LAYOUT (ptr: layout_manager)->offset; |
91 | |
92 | /* for simplicity, assume all children are the same size */ |
93 | gtk_widget_get_preferred_size (widget: gtk_widget_get_first_child (widget), minimum_size: &child_req, NULL); |
94 | w = child_req.width; |
95 | h = child_req.height; |
96 | |
97 | r = 300; |
98 | x0 = y0 = 300; |
99 | |
100 | for (child = gtk_widget_get_first_child (widget), i = 0; |
101 | child != NULL; |
102 | child = gtk_widget_get_next_sibling (widget: child), i++) |
103 | { |
104 | j = i / 36; |
105 | k = i % 36; |
106 | |
107 | gtk_widget_set_child_visible (widget: child, FALSE); |
108 | |
109 | graphene_point3d_init (p: &p1, x: w, y: h, z: 1.); |
110 | graphene_point3d_init (p: &p2, x: w, y: 0., z: 1.); |
111 | graphene_point3d_init (p: &p3, x: 0., y: 0., z: 1.); |
112 | graphene_point3d_init (p: &p4, x: 0., y: h, z: 1.); |
113 | |
114 | t_1 = RADIANS (map_offset (offset + 10 * j)); |
115 | t_2 = RADIANS (map_offset (offset + 10 * (j + 1))); |
116 | p_1 = RADIANS (position + 10 * k); |
117 | p_2 = RADIANS (position + 10 * (k + 1)); |
118 | |
119 | if (t_2 < t_1) |
120 | continue; |
121 | |
122 | if (SZ (r, t_1, p_1) > 0 || |
123 | SZ (r, t_2, p_1) > 0 || |
124 | SZ (r, t_1, p_2) > 0 || |
125 | SZ (r, t_2, p_2) > 0) |
126 | continue; |
127 | |
128 | gtk_widget_set_child_visible (widget: child, TRUE); |
129 | |
130 | graphene_point3d_init (p: &q1, x: x0 + SX (r, t_1, p_1), y: y0 + SY (r, t_1, p_1), SZ (r, t_1, p_1)); |
131 | graphene_point3d_init (p: &q2, x: x0 + SX (r, t_2, p_1), y: y0 + SY (r, t_2, p_1), SZ (r, t_2, p_1)); |
132 | graphene_point3d_init (p: &q3, x: x0 + SX (r, t_2, p_2), y: y0 + SY (r, t_2, p_2), SZ (r, t_2, p_2)); |
133 | graphene_point3d_init (p: &q4, x: x0 + SX (r, t_1, p_2), y: y0 + SY (r, t_1, p_2), SZ (r, t_1, p_2)); |
134 | |
135 | /* Get a matrix that moves p1 -> q1, p2 -> q2, ... */ |
136 | perspective_3d (p1: &p1, p2: &p2, p3: &p3, p4: &p4, |
137 | q1: &q1, q2: &q2, q3: &q3, q4: &q4, |
138 | m: &m); |
139 | |
140 | transform = gsk_transform_matrix (NULL, matrix: &m); |
141 | |
142 | /* Since our matrix was built for transforming points with z = 1, |
143 | * prepend a translation to the z = 1 plane. |
144 | */ |
145 | transform = gsk_transform_translate_3d (next: transform, |
146 | point: &GRAPHENE_POINT3D_INIT (0, 0, 1)); |
147 | |
148 | gtk_widget_allocate (widget: child, width: w, height: h, baseline: -1, transform); |
149 | } |
150 | } |
151 | |
152 | static GtkSizeRequestMode |
153 | demo2_layout_get_request_mode (GtkLayoutManager *layout_manager, |
154 | GtkWidget *widget) |
155 | { |
156 | return GTK_SIZE_REQUEST_CONSTANT_SIZE; |
157 | } |
158 | |
159 | static void |
160 | demo2_layout_class_init (Demo2LayoutClass *klass) |
161 | { |
162 | GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (ptr: klass); |
163 | |
164 | layout_class->get_request_mode = demo2_layout_get_request_mode; |
165 | layout_class->measure = demo2_layout_measure; |
166 | layout_class->allocate = demo2_layout_allocate; |
167 | } |
168 | |
169 | static void |
170 | demo2_layout_init (Demo2Layout *self) |
171 | { |
172 | } |
173 | |
174 | GtkLayoutManager * |
175 | demo2_layout_new (void) |
176 | { |
177 | return g_object_new (DEMO2_TYPE_LAYOUT, NULL); |
178 | } |
179 | |
180 | void |
181 | demo2_layout_set_position (Demo2Layout *layout, |
182 | float position) |
183 | { |
184 | layout->position = position; |
185 | } |
186 | |
187 | float |
188 | demo2_layout_get_position (Demo2Layout *layout) |
189 | { |
190 | return layout->position; |
191 | } |
192 | |
193 | void |
194 | demo2_layout_set_offset (Demo2Layout *layout, |
195 | float offset) |
196 | { |
197 | layout->offset = offset; |
198 | } |
199 | |
200 | float |
201 | demo2_layout_get_offset (Demo2Layout *layout) |
202 | { |
203 | return layout->offset; |
204 | } |
205 | |