rofi 1.7.5
box.c
Go to the documentation of this file.
1/*
2 * rofi
3 *
4 * MIT/X11 License
5 * Copyright © 2013-2022 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;
100 int active_widgets = 0;
101 for (GList *iter = g_list_first(b->children); iter != NULL;
102 iter = g_list_next(iter)) {
103 widget *child = (widget *)iter->data;
104 if (!child->enabled) {
105 continue;
106 }
107 active_widgets++;
108 height += widget_get_desired_height(child, width);
109 }
110 if (active_widgets > 0) {
111 height += (active_widgets - 1) * spacing;
112 }
113 } else {
114 for (GList *iter = g_list_first(b->children); iter != NULL;
115 iter = g_list_next(iter)) {
116 widget *child = (widget *)iter->data;
117 if (!child->enabled) {
118 continue;
119 }
120 height = MAX(widget_get_desired_height(child, width), height);
121 }
122 }
124 return height;
125}
126
127static void vert_calculate_size(box *b) {
129 int expanding_widgets = 0;
130 int active_widgets = 0;
131 int rem_width = widget_padding_get_remaining_width(WIDGET(b));
132 int rem_height = widget_padding_get_remaining_height(WIDGET(b));
133 for (GList *iter = g_list_first(b->children); iter != NULL;
134 iter = g_list_next(iter)) {
135 widget *child = (widget *)iter->data;
136 if (child->enabled && child->expand == FALSE) {
137 widget_resize(child, rem_width,
138 widget_get_desired_height(child, rem_width));
139 }
140 }
141 b->max_size = 0;
142 for (GList *iter = g_list_first(b->children); iter != NULL;
143 iter = g_list_next(iter)) {
144 widget *child = (widget *)iter->data;
145 if (!child->enabled) {
146 continue;
147 }
148 active_widgets++;
149 if (child->expand == TRUE) {
150 expanding_widgets++;
151 continue;
152 }
153 if (child->h > 0) {
154 b->max_size += child->h;
155 }
156 }
157 if (active_widgets > 0) {
158 b->max_size += (active_widgets - 1) * spacing;
159 }
160 if (b->max_size > rem_height) {
161 b->max_size = rem_height;
162 g_debug("Widgets to large (height) for box: %d %d", b->max_size,
163 b->widget.h);
164 return;
165 }
166 if (active_widgets > 0) {
167 int top = widget_padding_get_top(WIDGET(b));
168 double rem = rem_height - b->max_size;
169 int index = 0;
170 for (GList *iter = g_list_first(b->children); iter != NULL;
171 iter = g_list_next(iter)) {
172 widget *child = (widget *)iter->data;
173 if (child->enabled == FALSE) {
174 continue;
175 }
176 if (child->expand == TRUE) {
177 // Re-calculate to avoid round issues leaving one pixel left.
178 int expanding_widgets_size = (rem) / (expanding_widgets - index);
180 top += expanding_widgets_size;
181 widget_resize(child, rem_width, expanding_widgets_size);
182 top += spacing;
183 rem -= expanding_widgets_size;
184 index++;
185 } else {
187 top += widget_get_height(child);
188 top += spacing;
189 }
190 }
191 }
193}
194static void hori_calculate_size(box *b) {
196 int expanding_widgets = 0;
197 int active_widgets = 0;
198 int rem_width = widget_padding_get_remaining_width(WIDGET(b));
199 int rem_height = widget_padding_get_remaining_height(WIDGET(b));
200 for (GList *iter = g_list_first(b->children); iter != NULL;
201 iter = g_list_next(iter)) {
202 widget *child = (widget *)iter->data;
203 if (child->enabled && child->expand == FALSE) {
204 widget_resize(child,
205 widget_get_desired_width(child, rem_height), // child->w,
206 rem_height);
207 }
208 }
209 b->max_size = 0;
210 for (GList *iter = g_list_first(b->children); iter != NULL;
211 iter = g_list_next(iter)) {
212 widget *child = (widget *)iter->data;
213 if (!child->enabled) {
214 continue;
215 }
216 active_widgets++;
217 if (child->expand == TRUE) {
218 expanding_widgets++;
219 continue;
220 }
221 // Size used by fixed width widgets.
222 if (child->h > 0) {
223 b->max_size += child->w;
224 }
225 }
226 b->max_size += MAX(0, ((active_widgets - 1) * spacing));
227 if (b->max_size > (rem_width)) {
228 b->max_size = rem_width;
229 g_debug("Widgets to large (width) for box: %d %d", b->max_size,
230 b->widget.w);
231 // return;
232 }
233 if (active_widgets > 0) {
234 int left = widget_padding_get_left(WIDGET(b));
235 double rem = rem_width - b->max_size;
236 int index = 0;
237 if (rem < 0) {
238 rem = 0;
239 }
240 for (GList *iter = g_list_first(b->children); iter != NULL;
241 iter = g_list_next(iter)) {
242 widget *child = (widget *)iter->data;
243 if (child->enabled == FALSE) {
244 continue;
245 }
246 if (child->expand == TRUE) {
247 // Re-calculate to avoid round issues leaving one pixel left.
248 int expanding_widgets_size = (rem) / (expanding_widgets - index);
249 widget_move(child, left, widget_padding_get_top(WIDGET(b)));
250 left += expanding_widgets_size;
251 widget_resize(child, expanding_widgets_size, rem_height);
252 left += spacing;
253 rem -= expanding_widgets_size;
254 index++;
255 } else {
256 widget_move(child, left, widget_padding_get_top(WIDGET(b)));
257 left += widget_get_width(child);
258 left += spacing;
259 }
260 }
261 }
263}
264
265static void box_draw(widget *wid, cairo_t *draw) {
266 box *b = (box *)wid;
267 for (GList *iter = g_list_first(b->children); iter != NULL;
268 iter = g_list_next(iter)) {
269 widget *child = (widget *)iter->data;
270 widget_draw(child, draw);
271 }
272}
273
274static void box_free(widget *wid) {
275 box *b = (box *)wid;
276
277 for (GList *iter = g_list_first(b->children); iter != NULL;
278 iter = g_list_next(iter)) {
279 widget *child = (widget *)iter->data;
280 widget_free(child);
281 }
282 g_list_free(b->children);
283 g_free(b);
284}
285
286void box_add(box *box, widget *child, gboolean expand) {
287 if (box == NULL) {
288 return;
289 }
290 // Make sure box is width/heigh enough.
292 int width = box->widget.w;
293 width =
294 MAX(width, child->w + widget_padding_get_padding_width(WIDGET(box)));
295 box->widget.w = width;
296 } else {
297 int height = box->widget.h;
298 height =
299 MAX(height, child->h + widget_padding_get_padding_height(WIDGET(box)));
300 box->widget.h = height;
301 }
302 child->expand = rofi_theme_get_boolean(child, "expand", expand);
303 g_assert(child->parent == WIDGET(box));
304 box->children = g_list_append(box->children, (void *)child);
306}
307
308static void box_resize(widget *widget, short w, short h) {
309 box *b = (box *)widget;
310 if (b->widget.w != w || b->widget.h != h) {
311 b->widget.w = w;
312 b->widget.h = h;
314 }
315}
316
318 gint y) {
319 box *b = (box *)wid;
320 for (GList *iter = g_list_first(b->children); iter != NULL;
321 iter = g_list_next(iter)) {
322 widget *child = (widget *)iter->data;
323 if (!child->enabled) {
324 continue;
325 }
326 if (widget_intersect(child, x, y)) {
327 gint rx = x - child->x;
328 gint ry = y - child->y;
329 widget *target = widget_find_mouse_target(child, type, rx, ry);
330 if (target != NULL) {
331 return target;
332 }
333 }
334 }
335 return NULL;
336}
337
338static void box_set_state(widget *wid, const char *state) {
339 for (GList *iter = g_list_first(((box *)wid)->children); iter != NULL;
340 iter = g_list_next(iter)) {
341 widget *child = (widget *)iter->data;
342 widget_set_state(child, state);
343 }
344}
345
346box *box_create(widget *parent, const char *name, RofiOrientation type) {
347 box *b = g_malloc0(sizeof(box));
348 // Initialize widget.
349 widget_init(WIDGET(b), parent, WIDGET_TYPE_UNKNOWN, name);
350 b->type = type;
351 b->widget.draw = box_draw;
352 b->widget.free = box_free;
359
360 b->type = rofi_theme_get_orientation(WIDGET(b), "orientation", b->type);
361
363 return b;
364}
365
366static void box_update(widget *wid) {
367 box *b = (box *)wid;
368 switch (b->type) {
371 break;
373 default:
375 }
376 if (wid->parent) {
377 widget_update(wid->parent);
378 }
379}
static void vert_calculate_size(box *b)
Definition box.c:127
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:338
static void box_update(widget *wid)
Definition box.c:366
static void hori_calculate_size(box *b)
Definition box.c:194
static void box_free(widget *wid)
Definition box.c:274
static void box_resize(widget *widget, short w, short h)
Definition box.c:308
#define DEFAULT_SPACING
Definition box.c:38
static widget * box_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition box.c:317
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:265
void box_add(box *box, widget *child, gboolean expand)
Definition box.c:286
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition box.c:346
int widget_get_width(widget *widget)
Definition widget.c:446
void widget_free(widget *wid)
Definition widget.c:425
int widget_intersect(const widget *widget, int x, int y)
Definition widget.c:75
int widget_get_height(widget *widget)
Definition widget.c:437
void widget_resize(widget *widget, short w, short h)
Definition widget.c:87
WidgetType
Definition widget.h:56
void widget_update(widget *widget)
Definition widget.c:477
int widget_get_desired_width(widget *wid, const int height)
Definition widget.c:653
void widget_move(widget *widget, short x, short y)
Definition widget.c:102
void widget_draw(widget *widget, cairo_t *d)
Definition widget.c:135
#define WIDGET(a)
Definition widget.h:119
int widget_get_desired_height(widget *wid, const int width)
Definition widget.c:644
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition widget.c:510
@ WIDGET_TYPE_UNKNOWN
Definition widget.h:58
RofiOrientation
Definition rofi-types.h:141
@ ROFI_ORIENTATION_HORIZONTAL
Definition rofi-types.h:143
@ ROFI_ORIENTATION_VERTICAL
Definition rofi-types.h:142
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)
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition theme.c:877
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition theme.c:903
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition theme.c:1415
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition theme.c:932
int widget_padding_get_remaining_width(const widget *wid)
Definition widget.c:619
void widget_init(widget *wid, widget *parent, WidgetType type, const char *name)
Definition widget.c:34
void widget_set_state(widget *widget, const char *state)
Definition widget.c:57
int widget_padding_get_padding_width(const widget *wid)
Definition widget.c:637
int widget_padding_get_left(const widget *wid)
Definition widget.c:576
int widget_padding_get_padding_height(const widget *wid)
Definition widget.c:631
int widget_padding_get_top(const widget *wid)
Definition widget.c:598
int widget_padding_get_remaining_height(const widget *wid)
Definition widget.c:625