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 
40 struct _box {
43  int max_size;
44  // RofiPadding between elements
46 
47  GList *children;
48 };
49 
50 static void box_update(widget *wid);
51 
52 static 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 }
95 static 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  if (b->type == ROFI_ORIENTATION_VERTICAL) {
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  }
123  height += widget_padding_get_padding_height(wid);
124  return height;
125 }
126 
127 static 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);
179  widget_move(child, widget_padding_get_left(WIDGET(b)), top);
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 {
186  widget_move(child, widget_padding_get_left(WIDGET(b)), top);
187  top += widget_get_height(child);
188  top += spacing;
189  }
190  }
191  }
193 }
194 static 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 
265 static 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 
274 static 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 
286 void 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 
308 static 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 
317 static widget *box_find_mouse_target(widget *wid, WidgetType type, gint x,
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 
338 static 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 
346 box *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;
353  b->widget.resize = box_resize;
354  b->widget.update = box_update;
359 
360  b->type = rofi_theme_get_orientation(WIDGET(b), "orientation", b->type);
361 
363  return b;
364 }
365 
366 static 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
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: widget.c:510
int widget_get_desired_height(widget *wid, const int width)
Definition: widget.c:644
@ 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