1 #include <hikari/geometry.h>
2 
3 #include <hikari/configuration.h>
4 
5 #define SPLIT(n, x, y, width, height)                                          \
6   void hikari_geometry_split_##n(struct wlr_box *src,                          \
7       int width,                                                               \
8       int gap,                                                                 \
9       struct wlr_box *dst1,                                                    \
10       struct wlr_box *dst2)                                                    \
11   {                                                                            \
12     int rest = src->width - gap - width;                                       \
13                                                                                \
14     dst1->x = src->x;                                                          \
15     dst1->y = src->y;                                                          \
16     dst1->width = width;                                                       \
17     dst1->height = src->height;                                                \
18                                                                                \
19     dst2->x = src->x + width + gap;                                            \
20     dst2->y = src->y;                                                          \
21     dst2->width = rest;                                                        \
22     dst2->height = src->height;                                                \
23   }
24 
SPLIT(vertical,x,y,width,height)25 SPLIT(vertical, x, y, width, height)
26 SPLIT(horizontal, y, x, height, width)
27 #undef SPLIT
28 
29 #define DYNAMIC_SCALE(name)                                                    \
30   int hikari_geometry_scale_dynamic_##name(struct wlr_box *src,                \
31       struct wlr_box *geometry,                                                \
32       double min_scale,                                                        \
33       double max_scale,                                                        \
34       int gap)                                                                 \
35   {                                                                            \
36     int min_##name = (src->name - gap) * min_scale;                            \
37     int max_##name = (src->name - gap) * max_scale;                            \
38     int name = geometry->name;                                                 \
39                                                                                \
40     if (name < min_##name) {                                                   \
41       return min_##name;                                                       \
42     } else if (name > max_##name) {                                            \
43       return max_##name;                                                       \
44     } else {                                                                   \
45       return name;                                                             \
46     }                                                                          \
47   }
48 
49 DYNAMIC_SCALE(width)
50 DYNAMIC_SCALE(height)
51 #undef DYNAMIC_SCALE
52 
53 void
54 hikari_geometry_shrink(struct wlr_box *geometry, int gap)
55 {
56   geometry->x += gap;
57   geometry->y += gap;
58   geometry->width -= gap * 2;
59   geometry->height -= gap * 2;
60 }
61 
62 void
hikari_geometry_constrain_absolute(struct wlr_box * geometry,struct wlr_box * usable_area,int x,int y)63 hikari_geometry_constrain_absolute(
64     struct wlr_box *geometry, struct wlr_box *usable_area, int x, int y)
65 {
66   int border = hikari_configuration->border;
67 
68   int usable_max_x = usable_area->x + usable_area->width;
69   int usable_min_x = usable_area->x;
70   int usable_max_y = usable_area->y + usable_area->height;
71   int usable_min_y = usable_area->y;
72 
73   if (x + geometry->width + border > usable_max_x) {
74     geometry->x = usable_max_x - geometry->width - border;
75   } else if (x - border < usable_min_x) {
76     geometry->x = usable_min_x + border;
77   } else {
78     geometry->x = x;
79   }
80 
81   if (y + geometry->height + border > usable_max_y) {
82     geometry->y = usable_max_y - geometry->height - border;
83   } else if (y - border < usable_min_y) {
84     geometry->y = usable_min_y + border;
85   } else {
86     geometry->y = y;
87   }
88 }
89 
90 void
hikari_geometry_constrain_relative(struct wlr_box * geometry,struct wlr_box * usable_area,int x,int y)91 hikari_geometry_constrain_relative(
92     struct wlr_box *geometry, struct wlr_box *usable_area, int x, int y)
93 {
94   int border = hikari_configuration->border;
95   int gap = hikari_configuration->gap * 2 - border;
96 
97   int usable_max_x = usable_area->x + usable_area->width - gap;
98   int usable_min_x = usable_area->x - geometry->width + gap;
99   int usable_max_y = usable_area->y + usable_area->height - gap;
100   int usable_min_y = usable_area->y - geometry->height + gap;
101 
102   if (x > usable_max_x) {
103     geometry->x = usable_max_x;
104   } else if (x < usable_min_x) {
105     geometry->x = usable_min_x;
106   } else {
107     geometry->x = x;
108   }
109 
110   if (y > usable_max_y) {
111     geometry->y = usable_max_y;
112   } else if (y < usable_min_y) {
113     geometry->y = usable_min_y;
114   } else {
115     geometry->y = y;
116   }
117 }
118 
119 #define CENTER(coord, dim)                                                     \
120   static int center_##coord(                                                   \
121       struct wlr_box *geometry, struct wlr_box *usable_area)                   \
122   {                                                                            \
123     int center_usable_area_##coord = usable_area->dim / 2;                     \
124     int center_geometry_##coord = geometry->dim / 2;                           \
125                                                                                \
126     return usable_area->coord + center_usable_area_##coord -                   \
127            center_geometry_##coord;                                            \
128   }
129 
CENTER(x,width)130 CENTER(x, width)
131 CENTER(y, height)
132 #undef CENTER
133 
134 static int
135 right_x(struct wlr_box *geometry, struct wlr_box *usable_area)
136 {
137   return usable_area->x + usable_area->width - geometry->width +
138          hikari_configuration->border;
139 }
140 
141 static int
bottom_y(struct wlr_box * geometry,struct wlr_box * usable_area)142 bottom_y(struct wlr_box *geometry, struct wlr_box *usable_area)
143 {
144   return usable_area->y + usable_area->height - geometry->height +
145          hikari_configuration->border;
146 }
147 
148 void
hikari_geometry_position_bottom_left(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)149 hikari_geometry_position_bottom_left(
150     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
151 {
152   *x = usable_area->x;
153   *y = bottom_y(geometry, usable_area);
154 }
155 
156 void
hikari_geometry_position_bottom_middle(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)157 hikari_geometry_position_bottom_middle(
158     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
159 {
160   *x = center_x(geometry, usable_area);
161   *y = bottom_y(geometry, usable_area);
162 }
163 
164 void
hikari_geometry_position_bottom_right(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)165 hikari_geometry_position_bottom_right(
166     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
167 {
168   *x = right_x(geometry, usable_area);
169   *y = bottom_y(geometry, usable_area);
170 }
171 
172 void
hikari_geometry_position_center(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)173 hikari_geometry_position_center(
174     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
175 {
176   *x = center_x(geometry, usable_area);
177   *y = center_y(geometry, usable_area);
178 }
179 
180 void
hikari_geometry_position_center_left(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)181 hikari_geometry_position_center_left(
182     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
183 {
184   *x = usable_area->x;
185   *y = center_y(geometry, usable_area);
186 }
187 
188 void
hikari_geometry_position_center_right(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)189 hikari_geometry_position_center_right(
190     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
191 {
192   *x = right_x(geometry, usable_area);
193   *y = center_y(geometry, usable_area);
194 }
195 
196 void
hikari_geometry_position_top_left(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)197 hikari_geometry_position_top_left(
198     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
199 {
200   *x = usable_area->x;
201   *y = usable_area->y;
202 }
203 
204 void
hikari_geometry_position_top_middle(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)205 hikari_geometry_position_top_middle(
206     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
207 {
208   *x = center_x(geometry, usable_area);
209   *y = usable_area->y;
210 }
211 
212 void
hikari_geometry_position_top_right(struct wlr_box * geometry,struct wlr_box * usable_area,int * x,int * y)213 hikari_geometry_position_top_right(
214     struct wlr_box *geometry, struct wlr_box *usable_area, int *x, int *y)
215 {
216   *x = right_x(geometry, usable_area);
217   *y = usable_area->y;
218 }
219 
220 void
hikari_geometry_constrain_size(struct wlr_box * geometry,struct wlr_box * usable_area,struct wlr_box * constrained)221 hikari_geometry_constrain_size(struct wlr_box *geometry,
222     struct wlr_box *usable_area,
223     struct wlr_box *constrained)
224 {
225   if (geometry->x < 0) {
226     constrained->width = geometry->width + geometry->x;
227     constrained->x = 0;
228   } else {
229     int excess_width = geometry->width - (usable_area->width - geometry->x);
230 
231     if (excess_width > 0) {
232       constrained->width = geometry->width - excess_width;
233     } else {
234       constrained->width = geometry->width;
235     }
236 
237     constrained->x = geometry->x;
238   }
239 
240   if (geometry->y < 0) {
241     constrained->height = geometry->height + geometry->y;
242     constrained->y = 0;
243   } else {
244     int excess_height = geometry->height - (usable_area->height - geometry->y);
245 
246     if (excess_height > 0) {
247       constrained->height = geometry->height - excess_height;
248     } else {
249       constrained->height = geometry->height;
250     }
251 
252     constrained->y = geometry->y;
253   }
254 }
255