rofi 1.7.7
box.c
Go to the documentation of this file.
1/*
2 * rofi
3 *
4 * MIT/X11 License
5 * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
29#define G_LOG_DOMAIN "Widgets.Box"
30
31#include "widgets/box.h"
32#include "theme.h"
34#include "widgets/widget.h"
35#include <stdio.h>
36
38#define DEFAULT_SPACING 2
39
40struct _box {
44 // RofiPadding between elements
46
47 GList *children;
48};
49
50static void box_update(widget *wid);
51
52static int box_get_desired_width(widget *wid, const int height) {
53 box *b = (box *)wid;
54 int spacing = distance_get_pixel(b->spacing, b->type);
55 int width = 0;
56
57 // Allow user to override.
58 RofiDistance w = rofi_theme_get_distance(wid, "width", 0);
60 if (width > 0) {
61 return width;
62 }
63
65 int active_widgets = 0;
66 for (GList *iter = g_list_first(b->children); iter != NULL;
67 iter = g_list_next(iter)) {
68 widget *child = (widget *)iter->data;
69 if (!child->enabled) {
70 continue;
71 }
72 active_widgets++;
73 if (child->expand == TRUE) {
74 width += widget_get_desired_width(child, height);
75 continue;
76 }
77 width += widget_get_desired_width(child, height);
78 }
79 if (active_widgets > 0) {
80 width += (active_widgets - 1) * spacing;
81 }
82 } else {
83 for (GList *iter = g_list_first(b->children); iter != NULL;
84 iter = g_list_next(iter)) {
85 widget *child = (widget *)iter->data;
86 if (!child->enabled) {
87 continue;
88 }
89 width = MAX(widget_get_desired_width(child, height), width);
90 }
91 }
93 return width;
94}
95static int box_get_desired_height(widget *wid, const int width) {
96 box *b = (box *)wid;
97 int spacing = distance_get_pixel(b->spacing, b->type);
98 int height = 0;
99 int nw = width - widget_padding_get_padding_width(wid);
101 int active_widgets = 0;
102 for (GList *iter = g_list_first(b->children); iter != NULL;
103 iter = g_list_next(iter)) {
104 widget *child = (widget *)iter->data;
105 if (!child->enabled) {
106 continue;
107 }
108 active_widgets++;
109 height += widget_get_desired_height(child, nw);
110 }
111 if (active_widgets > 0) {
112 height += (active_widgets - 1) * spacing;
113 }
114 } else {
115 for (GList *iter = g_list_first(b->children); iter != NULL;
116 iter = g_list_next(iter)) {
117 widget *child = (widget *)iter->data;
118 if (!child->enabled) {
119 continue;
120 }
121 height = MAX(widget_get_desired_height(child, nw), height);
122 }
123 }
125 return height;
126}
127
128static void vert_calculate_size(box *b) {
130 int expanding_widgets = 0;
131 int active_widgets = 0;
132 int rem_width = widget_padding_get_remaining_width(WIDGET(b));
133 int rem_height = widget_padding_get_remaining_height(WIDGET(b));
134 for (GList *iter = g_list_first(b->children); iter != NULL;
135 iter = g_list_next(iter)) {
136 widget *child = (widget *)iter->data;
137 if (child->enabled && child->expand == FALSE) {
138 widget_resize(child, rem_width,
139 widget_get_desired_height(child, rem_width));
140 }
141 }
142 b->max_size = 0;
143 for (GList *iter = g_list_first(b->children); iter != NULL;
144 iter = g_list_next(iter)) {
145 widget *child = (widget *)iter->data;
146 if (!child->enabled) {
147 continue;
148 }
149 active_widgets++;
150 if (child->expand == TRUE) {
151 expanding_widgets++;
152 continue;
153 }
154 if (child->h > 0) {
155 b->max_size += child->h;
156 }
157 }
158 if (active_widgets > 0) {
159 b->max_size += (active_widgets - 1) * spacing;
160 }
161 if (b->max_size > rem_height) {
162 b->max_size = rem_height;
163 g_debug("Widgets to large (height) for box: %d %d", b->max_size,
164 b->widget.h);
165 return;
166 }
167 if (active_widgets > 0) {
168 int top = widget_padding_get_top(WIDGET(b));
169 double rem = rem_height - b->max_size;
170 int index = 0;
171 for (GList *iter = g_list_first(b->children); iter != NULL;
172 iter = g_list_next(iter)) {
173 widget *child = (widget *)iter->data;
174 if (child->enabled == FALSE) {
175 continue;
176 }
177 if (child->expand == TRUE) {
178 // Re-calculate to avoid round issues leaving one pixel left.
179 int expanding_widgets_size = (rem) / (expanding_widgets - index);
181 top += expanding_widgets_size;
182 widget_resize(child, rem_width, expanding_widgets_size);
183 top += spacing;
184 rem -= expanding_widgets_size;
185 index++;
186 } else {
188 top += widget_get_height(child);
189 top += spacing;
190 }
191 }
192 }
194}
195static void hori_calculate_size(box *b) {
197 int expanding_widgets = 0;
198 int active_widgets = 0;
199 int rem_width = widget_padding_get_remaining_width(WIDGET(b));
200 int rem_height = widget_padding_get_remaining_height(WIDGET(b));
201 for (GList *iter = g_list_first(b->children); iter != NULL;
202 iter = g_list_next(iter)) {
203 widget *child = (widget *)iter->data;
204 if (child->enabled && child->expand == FALSE) {
205 widget_resize(child,
206 widget_get_desired_width(child, rem_height), // child->w,
207 rem_height);
208 }
209 }
210 b->max_size = 0;
211 for (GList *iter = g_list_first(b->children); iter != NULL;
212 iter = g_list_next(iter)) {
213 widget *child = (widget *)iter->data;
214 if (!child->enabled) {
215 continue;
216 }
217 active_widgets++;
218 if (child->expand == TRUE) {
219 expanding_widgets++;
220 continue;
221 }
222 // Size used by fixed width widgets.
223 if (child->h > 0) {
224 b->max_size += child->w;
225 }
226 }
227 b->max_size += MAX(0, ((active_widgets - 1) * spacing));
228 if (b->max_size > (rem_width)) {
229 b->max_size = rem_width;
230 g_debug("Widgets to large (width) for box: %d %d", b->max_size,
231 b->widget.w);
232 // return;
233 }
234 if (active_widgets > 0) {
235 int left = widget_padding_get_left(WIDGET(b));
236 double rem = rem_width - b->max_size;
237 int index = 0;
238 if (rem < 0) {
239 rem = 0;
240 }
241 for (GList *iter = g_list_first(b->children); iter != NULL;
242 iter = g_list_next(iter)) {
243 widget *child = (widget *)iter->data;
244 if (child->enabled == FALSE) {
245 continue;
246 }
247 if (child->expand == TRUE) {
248 // Re-calculate to avoid round issues leaving one pixel left.
249 int expanding_widgets_size = (rem) / (expanding_widgets - index);
250 widget_move(child, left, widget_padding_get_top(WIDGET(b)));
251 left += expanding_widgets_size;
252 widget_resize(child, expanding_widgets_size, rem_height);
253 left += spacing;
254 rem -= expanding_widgets_size;
255 index++;
256 } else {
257 widget_move(child, left, widget_padding_get_top(WIDGET(b)));
258 left += widget_get_width(child);
259 left += spacing;
260 }
261 }
262 }
264}
265
266static void box_draw(widget *wid, cairo_t *draw) {
267 box *b = (box *)wid;
268 for (GList *iter = g_list_first(b->children); iter != NULL;
269 iter = g_list_next(iter)) {
270 widget *child = (widget *)iter->data;
271 widget_draw(child, draw);
272 }
273}
274
275static void box_free(widget *wid) {
276 box *b = (box *)wid;
277
278 for (GList *iter = g_list_first(b->children); iter != NULL;
279 iter = g_list_next(iter)) {
280 widget *child = (widget *)iter->data;
281 widget_free(child);
282 }
283 g_list_free(b->children);
284 g_free(b);
285}
286
287void box_add(box *wid, widget *child, gboolean expand) {
288 if (wid == NULL) {
289 return;
290 }
291 // Make sure box is width/heigh enough.
292 if (wid->type == ROFI_ORIENTATION_VERTICAL) {
293 int width = wid->widget.w;
294 width =
295 MAX(width, child->w + widget_padding_get_padding_width(WIDGET(wid)));
296 wid->widget.w = width;
297 } else {
298 int height = wid->widget.h;
299 height =
300 MAX(height, child->h + widget_padding_get_padding_height(WIDGET(wid)));
301 wid->widget.h = height;
302 }
303 child->expand = rofi_theme_get_boolean(child, "expand", expand);
304 g_assert(child->parent == WIDGET(wid));
305 wid->children = g_list_append(wid->children, (void *)child);
306 widget_update(WIDGET(wid));
307}
308
309static void box_resize(widget *wid, short w, short h) {
310 box *b = (box *)wid;
311 if (b->widget.w != w || b->widget.h != h) {
312 b->widget.w = w;
313 b->widget.h = h;
314 widget_update(wid);
315 }
316}
317
319 gint y) {
320 box *b = (box *)wid;
321 for (GList *iter = g_list_first(b->children); iter != NULL;
322 iter = g_list_next(iter)) {
323 widget *child = (widget *)iter->data;
324 if (!child->enabled) {
325 continue;
326 }
327 if (widget_intersect(child, x, y)) {
328 gint rx = x - child->x;
329 gint ry = y - child->y;
330 widget *target = widget_find_mouse_target(child, type, rx, ry);
331 if (target != NULL) {
332 return target;
333 }
334 }
335 }
336 return NULL;
337}
338
339static void box_set_state(widget *wid, const char *state) {
340 for (GList *iter = g_list_first(((box *)wid)->children); iter != NULL;
341 iter = g_list_next(iter)) {
342 widget *child = (widget *)iter->data;
343 widget_set_state(child, state);
344 }
345}
346
347box *box_create(widget *parent, const char *name, RofiOrientation type) {
348 box *b = g_malloc0(sizeof(box));
349 // Initialize widget.
350 widget_init(WIDGET(b), parent, WIDGET_TYPE_UNKNOWN, name);
351 b->type = type;
352 b->widget.draw = box_draw;
353 b->widget.free = box_free;
360
361 b->type = rofi_theme_get_orientation(WIDGET(b), "orientation", b->type);
362
364 return b;
365}
366
367static void box_update(widget *wid) {
368 box *b = (box *)wid;
369 switch (b->type) {
372 break;
374 default:
376 }
377 if (wid->parent) {
378 widget_update(wid->parent);
379 }
380}
static void vert_calculate_size(box *b)
Definition box.c:128
static int box_get_desired_width(widget *wid, const int height)
Definition box.c:52
static void box_set_state(widget *wid, const char *state)
Definition box.c:339
static void box_update(widget *wid)
Definition box.c:367
static void hori_calculate_size(box *b)
Definition box.c:195
static void box_resize(widget *wid, short w, short h)
Definition box.c:309
static void box_free(widget *wid)
Definition box.c:275
#define DEFAULT_SPACING
Definition box.c:38
static widget * box_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition box.c:318
static int box_get_desired_height(widget *wid, const int width)
Definition box.c:95
static void box_draw(widget *wid, cairo_t *draw)
Definition box.c:266
void box_add(box *wid, widget *child, gboolean expand)
Definition box.c:287
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition box.c:347
void widget_move(widget *wid, short x, short y)
Definition widget.c:102
void widget_free(widget *wid)
Definition widget.c:415
void widget_draw(widget *wid, cairo_t *d)
Definition widget.c:135
int widget_get_width(widget *wid)
Definition widget.c:436
int widget_get_height(widget *wid)
Definition widget.c:427
void widget_update(widget *wid)
Definition widget.c:467
WidgetType
Definition widget.h:56
int widget_get_desired_width(widget *wid, const int height)
Definition widget.c:643
void widget_resize(widget *wid, short w, short h)
Definition widget.c:87
#define WIDGET(a)
Definition widget.h:119
int widget_get_desired_height(widget *wid, const int width)
Definition widget.c:634
int widget_intersect(const widget *wid, int x, int y)
Definition widget.c:75
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition widget.c:500
@ WIDGET_TYPE_UNKNOWN
Definition widget.h:58
RofiOrientation
Definition rofi-types.h:139
@ ROFI_ORIENTATION_HORIZONTAL
Definition rofi-types.h:141
@ ROFI_ORIENTATION_VERTICAL
Definition rofi-types.h:140
Definition box.c:40
widget widget
Definition box.c:41
RofiDistance spacing
Definition box.c:45
RofiOrientation type
Definition box.c:42
GList * children
Definition box.c:47
int max_size
Definition box.c:43
void(* free)(struct _widget *widget)
void(* set_state)(struct _widget *, const char *)
widget_find_mouse_target_cb find_mouse_target
gboolean enabled
int(* get_desired_width)(struct _widget *, const int height)
int(* get_desired_height)(struct _widget *, const int width)
struct _widget * parent
void(* update)(struct _widget *)
gboolean expand
void(* draw)(struct _widget *widget, cairo_t *draw)
void(* resize)(struct _widget *, short, short)
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition theme.c:1405
int rofi_theme_get_boolean(const widget *wid, const char *property, int def)
Definition theme.c:901
RofiOrientation rofi_theme_get_orientation(const widget *wid, const char *property, RofiOrientation def)
Definition theme.c:929
RofiDistance rofi_theme_get_distance(const widget *wid, const char *property, int def)
Definition theme.c:875
int widget_padding_get_remaining_width(const widget *wid)
Definition widget.c:609
void widget_set_state(widget *wid, const char *state)
Definition widget.c:58
void widget_init(widget *wid, widget *parent, WidgetType type, const char *name)
Definition widget.c:35
int widget_padding_get_padding_width(const widget *wid)
Definition widget.c:627
int widget_padding_get_left(const widget *wid)
Definition widget.c:566
int widget_padding_get_padding_height(const widget *wid)
Definition widget.c:621
int widget_padding_get_top(const widget *wid)
Definition widget.c:588
int widget_padding_get_remaining_height(const widget *wid)
Definition widget.c:615