rofi  1.7.0
box.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2013-2021 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) {
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);
75  continue;
76  }
77  width += widget_get_desired_width(child);
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), width);
90  }
91  }
93  return width;
94 }
95 static int box_get_desired_height(widget *wid) {
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);
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), 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, widget_get_desired_height(child));
138  }
139  }
140  b->max_size = 0;
141  for (GList *iter = g_list_first(b->children); iter != NULL;
142  iter = g_list_next(iter)) {
143  widget *child = (widget *)iter->data;
144  if (!child->enabled) {
145  continue;
146  }
147  active_widgets++;
148  if (child->expand == TRUE) {
149  expanding_widgets++;
150  continue;
151  }
152  if (child->h > 0) {
153  b->max_size += child->h;
154  }
155  }
156  if (active_widgets > 0) {
157  b->max_size += (active_widgets - 1) * spacing;
158  }
159  if (b->max_size > rem_height) {
160  b->max_size = rem_height;
161  g_debug("Widgets to large (height) for box: %d %d", b->max_size,
162  b->widget.h);
163  return;
164  }
165  if (active_widgets > 0) {
166  int top = widget_padding_get_top(WIDGET(b));
167  double rem = rem_height - b->max_size;
168  int index = 0;
169  for (GList *iter = g_list_first(b->children); iter != NULL;
170  iter = g_list_next(iter)) {
171  widget *child = (widget *)iter->data;
172  if (child->enabled == FALSE) {
173  continue;
174  }
175  if (child->expand == TRUE) {
176  // Re-calculate to avoid round issues leaving one pixel left.
177  int expanding_widgets_size = (rem) / (expanding_widgets - index);
178  widget_move(child, widget_padding_get_left(WIDGET(b)), top);
179  top += expanding_widgets_size;
180  widget_resize(child, rem_width, expanding_widgets_size);
181  top += spacing;
182  rem -= expanding_widgets_size;
183  index++;
184  } else {
185  widget_move(child, widget_padding_get_left(WIDGET(b)), top);
186  top += widget_get_height(child);
187  top += spacing;
188  }
189  }
190  }
192 }
193 static void hori_calculate_size(box *b) {
195  int expanding_widgets = 0;
196  int active_widgets = 0;
197  int rem_width = widget_padding_get_remaining_width(WIDGET(b));
198  int rem_height = widget_padding_get_remaining_height(WIDGET(b));
199  for (GList *iter = g_list_first(b->children); iter != NULL;
200  iter = g_list_next(iter)) {
201  widget *child = (widget *)iter->data;
202  if (child->enabled && child->expand == FALSE) {
203  widget_resize(child,
204  widget_get_desired_width(child), // child->w,
205  rem_height);
206  }
207  }
208  b->max_size = 0;
209  for (GList *iter = g_list_first(b->children); iter != NULL;
210  iter = g_list_next(iter)) {
211  widget *child = (widget *)iter->data;
212  if (!child->enabled) {
213  continue;
214  }
215  active_widgets++;
216  if (child->expand == TRUE) {
217  expanding_widgets++;
218  continue;
219  }
220  // Size used by fixed width widgets.
221  if (child->h > 0) {
222  b->max_size += child->w;
223  }
224  }
225  b->max_size += MAX(0, ((active_widgets - 1) * spacing));
226  if (b->max_size > (rem_width)) {
227  b->max_size = rem_width;
228  g_debug("Widgets to large (width) for box: %d %d", b->max_size,
229  b->widget.w);
230  // return;
231  }
232  if (active_widgets > 0) {
233  int left = widget_padding_get_left(WIDGET(b));
234  double rem = rem_width - b->max_size;
235  int index = 0;
236  if (rem < 0) {
237  rem = 0;
238  }
239  for (GList *iter = g_list_first(b->children); iter != NULL;
240  iter = g_list_next(iter)) {
241  widget *child = (widget *)iter->data;
242  if (child->enabled == FALSE) {
243  continue;
244  }
245  if (child->expand == TRUE) {
246  // Re-calculate to avoid round issues leaving one pixel left.
247  int expanding_widgets_size = (rem) / (expanding_widgets - index);
248  widget_move(child, left, widget_padding_get_top(WIDGET(b)));
249  left += expanding_widgets_size;
250  widget_resize(child, expanding_widgets_size, rem_height);
251  left += spacing;
252  rem -= expanding_widgets_size;
253  index++;
254  } else {
255  widget_move(child, left, widget_padding_get_top(WIDGET(b)));
256  left += widget_get_width(child);
257  left += spacing;
258  }
259  }
260  }
262 }
263 
264 static void box_draw(widget *wid, cairo_t *draw) {
265  box *b = (box *)wid;
266  for (GList *iter = g_list_first(b->children); iter != NULL;
267  iter = g_list_next(iter)) {
268  widget *child = (widget *)iter->data;
269  widget_draw(child, draw);
270  }
271 }
272 
273 static void box_free(widget *wid) {
274  box *b = (box *)wid;
275 
276  for (GList *iter = g_list_first(b->children); iter != NULL;
277  iter = g_list_next(iter)) {
278  widget *child = (widget *)iter->data;
279  widget_free(child);
280  }
281  g_list_free(b->children);
282  g_free(b);
283 }
284 
285 void box_add(box *box, widget *child, gboolean expand) {
286  if (box == NULL) {
287  return;
288  }
289  // Make sure box is width/heigh enough.
291  int width = box->widget.w;
292  width =
293  MAX(width, child->w + widget_padding_get_padding_width(WIDGET(box)));
294  box->widget.w = width;
295  } else {
296  int height = box->widget.h;
297  height =
298  MAX(height, child->h + widget_padding_get_padding_height(WIDGET(box)));
299  box->widget.h = height;
300  }
301  child->expand = rofi_theme_get_boolean(child, "expand", expand);
302  g_assert(child->parent == WIDGET(box));
303  box->children = g_list_append(box->children, (void *)child);
305 }
306 
307 static void box_resize(widget *widget, short w, short h) {
308  box *b = (box *)widget;
309  if (b->widget.w != w || b->widget.h != h) {
310  b->widget.w = w;
311  b->widget.h = h;
313  }
314 }
315 
316 static widget *box_find_mouse_target(widget *wid, WidgetType type, gint x,
317  gint y) {
318  box *b = (box *)wid;
319  for (GList *iter = g_list_first(b->children); iter != NULL;
320  iter = g_list_next(iter)) {
321  widget *child = (widget *)iter->data;
322  if (!child->enabled) {
323  continue;
324  }
325  if (widget_intersect(child, x, y)) {
326  gint rx = x - child->x;
327  gint ry = y - child->y;
328  widget *target = widget_find_mouse_target(child, type, rx, ry);
329  if (target != NULL) {
330  return target;
331  }
332  }
333  }
334  return NULL;
335 }
336 
337 static void box_set_state(widget *wid, const char *state) {
338  for (GList *iter = g_list_first(((box *)wid)->children); iter != NULL;
339  iter = g_list_next(iter)) {
340  widget *child = (widget *)iter->data;
341  widget_set_state(child, state);
342  }
343 }
344 
345 box *box_create(widget *parent, const char *name, RofiOrientation type) {
346  box *b = g_malloc0(sizeof(box));
347  // Initialize widget.
348  widget_init(WIDGET(b), parent, WIDGET_TYPE_UNKNOWN, name);
349  b->type = type;
350  b->widget.draw = box_draw;
351  b->widget.free = box_free;
352  b->widget.resize = box_resize;
353  b->widget.update = box_update;
358 
359  b->type = rofi_theme_get_orientation(WIDGET(b), "orientation", b->type);
360 
362  return b;
363 }
364 
365 static void box_update(widget *wid) {
366  box *b = (box *)wid;
367  switch (b->type) {
370  break;
372  default:
374  }
375  if (wid->parent) {
376  widget_update(wid->parent);
377  }
378 }
static void vert_calculate_size(box *b)
Definition: box.c:127
static int box_get_desired_width(widget *wid)
Definition: box.c:52
static void box_set_state(widget *wid, const char *state)
Definition: box.c:337
static void box_update(widget *wid)
Definition: box.c:365
static void hori_calculate_size(box *b)
Definition: box.c:193
static void box_free(widget *wid)
Definition: box.c:273
static void box_resize(widget *widget, short w, short h)
Definition: box.c:307
#define DEFAULT_SPACING
Definition: box.c:38
static int box_get_desired_height(widget *wid)
Definition: box.c:95
static widget * box_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: box.c:316
static void box_draw(widget *wid, cairo_t *draw)
Definition: box.c:264
void box_add(box *box, widget *child, gboolean expand)
Definition: box.c:285
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition: box.c:345
int widget_get_width(widget *widget)
Definition: widget.c:468
int widget_get_desired_height(widget *wid)
Definition: widget.c:649
void widget_free(widget *wid)
Definition: widget.c:447
int widget_intersect(const widget *widget, int x, int y)
Definition: widget.c:90
int widget_get_height(widget *widget)
Definition: widget.c:459
void widget_resize(widget *widget, short w, short h)
Definition: widget.c:102
int widget_get_desired_width(widget *wid)
Definition: widget.c:658
WidgetType
Definition: widget.h:56
void widget_update(widget *widget)
Definition: widget.c:499
void widget_move(widget *widget, short x, short y)
Definition: widget.c:117
void widget_draw(widget *widget, cairo_t *d)
Definition: widget.c:157
#define WIDGET(a)
Definition: widget.h:119
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: widget.c:532
@ WIDGET_TYPE_UNKNOWN
Definition: widget.h:58
RofiOrientation
Definition: rofi-types.h:134
@ ROFI_ORIENTATION_HORIZONTAL
Definition: rofi-types.h:136
@ ROFI_ORIENTATION_VERTICAL
Definition: rofi-types.h:135
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_height)(struct _widget *)
struct _widget * parent
void(* update)(struct _widget *)
gboolean expand
void(* draw)(struct _widget *widget, cairo_t *draw)
void(* resize)(struct _widget *, short, short)
int(* get_desired_width)(struct _widget *)
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition: theme.c:830
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition: theme.c:856
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition: theme.c:1282
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition: theme.c:884
int widget_padding_get_remaining_width(const widget *wid)
Definition: widget.c:624
void widget_init(widget *wid, widget *parent, WidgetType type, const char *name)
Definition: widget.c:44
void widget_set_state(widget *widget, const char *state)
Definition: widget.c:72
int widget_padding_get_padding_width(const widget *wid)
Definition: widget.c:642
int widget_padding_get_left(const widget *wid)
Definition: widget.c:581
int widget_padding_get_padding_height(const widget *wid)
Definition: widget.c:636
int widget_padding_get_top(const widget *wid)
Definition: widget.c:603
int widget_padding_get_remaining_height(const widget *wid)
Definition: widget.c:630