rofi  1.6.1
box.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2013-2020 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 <config.h>
32 #include <stdio.h>
33 #include "widgets/widget.h"
35 #include "widgets/box.h"
36 #include "theme.h"
37 
39 #define DEFAULT_SPACING 2
40 
41 struct _box
42 {
45  int max_size;
46  // RofiPadding between elements
48 
49  GList *children;
50 };
51 
52 static void box_update ( widget *wid );
53 
54 static int box_get_desired_width ( widget *wid )
55 {
56  box *b = (box *) wid;
57  int spacing = distance_get_pixel ( b->spacing, b->type );
58  int width = 0;
59 
60  // Allow user to override.
61  RofiDistance w = rofi_theme_get_distance ( wid, "width", 0 );
63  if ( width > 0 ) {
64  return width;
65  }
66 
67  if ( b->type == ROFI_ORIENTATION_HORIZONTAL ) {
68  int active_widgets = 0;
69  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
70  widget * child = (widget *) iter->data;
71  if ( !child->enabled ) {
72  continue;
73  }
74  active_widgets++;
75  if ( child->expand == TRUE ) {
76  width += widget_get_desired_width ( child );
77  continue;
78  }
79  width += widget_get_desired_width ( child );
80  }
81  if ( active_widgets > 0 ) {
82  width += ( active_widgets - 1 ) * spacing;
83  }
84  }
85  else {
86  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
87  widget * child = (widget *) iter->data;
88  if ( !child->enabled ) {
89  continue;
90  }
91  width = MAX ( widget_get_desired_width ( child ), width );
92  }
93  }
94  width += widget_padding_get_padding_width ( wid );
95  return width;
96 }
97 static int box_get_desired_height ( widget *wid )
98 {
99  box *b = (box *) wid;
100  int spacing = distance_get_pixel ( b->spacing, b->type );
101  int height = 0;
102  if ( b->type == ROFI_ORIENTATION_VERTICAL ) {
103  int active_widgets = 0;
104  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
105  widget * child = (widget *) iter->data;
106  if ( !child->enabled ) {
107  continue;
108  }
109  active_widgets++;
110  height += widget_get_desired_height ( child );
111  }
112  if ( active_widgets > 0 ) {
113  height += ( active_widgets - 1 ) * spacing;
114  }
115  }
116  else {
117  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
118  widget * child = (widget *) iter->data;
119  if ( !child->enabled ) {
120  continue;
121  }
122  height = MAX ( widget_get_desired_height ( child ), height );
123  }
124  }
125  height += widget_padding_get_padding_height ( wid );
126  return height;
127 }
128 
129 static void vert_calculate_size ( box *b )
130 {
132  int expanding_widgets = 0;
133  int active_widgets = 0;
134  int rem_width = widget_padding_get_remaining_width ( WIDGET ( b ) );
135  int rem_height = widget_padding_get_remaining_height ( WIDGET ( b ) );
136  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
137  widget * child = (widget *) iter->data;
138  if ( child->enabled && child->expand == FALSE ) {
139  widget_resize ( child, rem_width, widget_get_desired_height ( child ) );
140  }
141  }
142  b->max_size = 0;
143  for ( GList *iter = g_list_first ( b->children ); iter != NULL; 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, 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; iter = g_list_next ( iter ) ) {
170  widget * child = (widget *) iter->data;
171  if ( child->enabled == FALSE ) {
172  continue;
173  }
174  if ( child->expand == TRUE ) {
175  // Re-calculate to avoid round issues leaving one pixel left.
176  int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
177  widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
178  top += expanding_widgets_size;
179  widget_resize ( child, rem_width, expanding_widgets_size );
180  top += spacing;
181  rem -= expanding_widgets_size;
182  index++;
183  }
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 )
194 {
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; 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; iter = g_list_next ( iter ) ) {
210  widget * child = (widget *) iter->data;
211  if ( !child->enabled ) {
212  continue;
213  }
214  active_widgets++;
215  if ( child->expand == TRUE ) {
216  expanding_widgets++;
217  continue;
218  }
219  // Size used by fixed width widgets.
220  if ( child->h > 0 ) {
221  b->max_size += child->w;
222  }
223  }
224  b->max_size += MAX ( 0, ( ( active_widgets - 1 ) * spacing ) );
225  if ( b->max_size > ( rem_width ) ) {
226  b->max_size = rem_width;
227  g_debug ( "Widgets to large (width) for box: %d %d", b->max_size, b->widget.w );
228  //return;
229  }
230  if ( active_widgets > 0 ) {
231  int left = widget_padding_get_left ( WIDGET ( b ) );
232  double rem = rem_width - b->max_size;
233  int index = 0;
234  if ( rem < 0 ) {
235  rem = 0;
236  }
237  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
238  widget * child = (widget *) iter->data;
239  if ( child->enabled == FALSE ) {
240  continue;
241  }
242  if ( child->expand == TRUE ) {
243  // Re-calculate to avoid round issues leaving one pixel left.
244  int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
245  widget_move ( child, left, widget_padding_get_top ( WIDGET ( b ) ) );
246  left += expanding_widgets_size;
247  widget_resize ( child, expanding_widgets_size, rem_height );
248  left += spacing;
249  rem -= expanding_widgets_size;
250  index++;
251  }
252  else {
253  widget_move ( child, left, widget_padding_get_top ( WIDGET ( b ) ) );
254  left += widget_get_width ( child );
255  left += spacing;
256  }
257  }
258  }
260 }
261 
262 static void box_draw ( widget *wid, cairo_t *draw )
263 {
264  box *b = (box *) wid;
265  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
266  widget * child = (widget *) iter->data;
267  widget_draw ( child, draw );
268  }
269 }
270 
271 static void box_free ( widget *wid )
272 {
273  box *b = (box *) wid;
274 
275  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
276  widget * child = (widget *) iter->data;
277  widget_free ( child );
278  }
279  g_list_free ( b->children );
280  g_free ( b );
281 }
282 
283 void box_add ( box *box, widget *child, gboolean expand )
284 {
285  if ( box == NULL ) {
286  return;
287  }
288  // Make sure box is width/heigh enough.
289  if ( box->type == ROFI_ORIENTATION_VERTICAL ) {
290  int width = box->widget.w;
291  width = MAX ( width, child->w + widget_padding_get_padding_width ( WIDGET ( box ) ) );
292  box->widget.w = width;
293  }
294  else {
295  int height = box->widget.h;
296  height = MAX ( height, child->h + widget_padding_get_padding_height ( WIDGET ( box ) ) );
297  box->widget.h = height;
298  }
299  child->expand = rofi_theme_get_boolean ( child, "expand", expand );
300  g_assert ( child->parent == WIDGET ( box ) );
301  box->children = g_list_append ( box->children, (void *) child );
302  widget_update ( WIDGET ( box ) );
303 }
304 
305 static void box_resize ( widget *widget, short w, short h )
306 {
307  box *b = (box *) widget;
308  if ( b->widget.w != w || b->widget.h != h ) {
309  b->widget.w = w;
310  b->widget.h = h;
311  widget_update ( widget );
312  }
313 }
314 
315 static widget *box_find_mouse_target ( widget *wid, WidgetType type, gint x, gint y )
316 {
317  box *b = (box *) wid;
318  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
319  widget * child = (widget *) iter->data;
320  if ( !child->enabled ) {
321  continue;
322  }
323  if ( widget_intersect ( child, x, y ) ) {
324  gint rx = x - child->x;
325  gint ry = y - child->y;
326  widget *target = widget_find_mouse_target ( child, type, rx, ry );
327  if ( target != NULL ) {
328  return target;
329  }
330  }
331  }
332  return NULL;
333 }
334 
335 static void box_set_state ( widget *wid, const char *state )
336 {
337  for ( GList *iter = g_list_first ( ( (box *) wid )->children ); iter != NULL; iter = g_list_next ( iter ) ) {
338  widget * child = (widget *) iter->data;
339  widget_set_state ( child, state );
340  }
341 }
342 
343 box * box_create ( widget *parent, const char *name, RofiOrientation type )
344 {
345  box *b = g_malloc0 ( sizeof ( box ) );
346  // Initialize widget.
347  widget_init ( WIDGET ( b ), parent, WIDGET_TYPE_UNKNOWN, name );
348  b->type = type;
349  b->widget.draw = box_draw;
350  b->widget.free = box_free;
351  b->widget.resize = box_resize;
352  b->widget.update = box_update;
357 
358  b->type = rofi_theme_get_orientation ( WIDGET ( b ), "orientation", b->type );
359 
360  b->spacing = rofi_theme_get_distance ( WIDGET ( b ), "spacing", DEFAULT_SPACING );
361  return b;
362 }
363 
364 static void box_update ( widget *wid )
365 {
366  box *b = (box *) wid;
367  switch ( b->type )
368  {
370  vert_calculate_size ( b );
371  break;
373  default:
374  hori_calculate_size ( b );
375  }
376  if ( wid->parent ) {
377  widget_update ( wid->parent );
378  }
379 }
Definition: box.c:41
WidgetType
Definition: widget.h:56
widget_find_mouse_target_cb find_mouse_target
RofiDistance spacing
Definition: box.c:47
void widget_update(widget *widget)
Definition: widget.c:397
static int box_get_desired_height(widget *wid)
Definition: box.c:97
int widget_padding_get_padding_width(const widget *wid)
Definition: widget.c:544
void(* resize)(struct _widget *, short, short)
int widget_padding_get_top(const widget *wid)
Definition: widget.c:502
void widget_set_state(widget *widget, const char *state)
Definition: widget.c:93
struct _widget * parent
int widget_get_width(widget *widget)
Definition: widget.c:362
void widget_free(widget *wid)
Definition: widget.c:339
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition: theme.c:785
GList * children
Definition: box.c:49
void(* draw)(struct _widget *widget, cairo_t *draw)
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition: theme.c:763
int(* get_desired_width)(struct _widget *)
void widget_draw(widget *widget, cairo_t *d)
Definition: widget.c:185
int widget_intersect(const widget *widget, int x, int y)
Definition: widget.c:110
gboolean enabled
void widget_move(widget *widget, short x, short y)
Definition: widget.c:140
static void hori_calculate_size(box *b)
Definition: box.c:193
void(* set_state)(struct _widget *, const char *)
void widget_resize(widget *widget, short w, short h)
Definition: widget.c:123
static void vert_calculate_size(box *b)
Definition: box.c:129
RofiOrientation type
Definition: box.c:44
static void box_set_state(widget *wid, const char *state)
Definition: box.c:335
static void box_draw(widget *wid, cairo_t *draw)
Definition: box.c:262
#define DEFAULT_SPACING
Definition: box.c:39
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition: box.c:343
int widget_padding_get_remaining_height(const widget *wid)
Definition: widget.c:530
RofiOrientation
Definition: rofi-types.h:137
static void box_resize(widget *widget, short w, short h)
Definition: box.c:305
void(* free)(struct _widget *widget)
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition: theme.c:1026
int max_size
Definition: box.c:45
int widget_get_desired_width(widget *wid)
Definition: widget.c:562
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition: theme.c:801
#define WIDGET(a)
Definition: widget.h:115
static void box_free(widget *wid)
Definition: box.c:271
int widget_padding_get_remaining_width(const widget *wid)
Definition: widget.c:523
void widget_init(widget *wid, widget *parent, WidgetType type, const char *name)
Definition: widget.c:74
int(* get_desired_height)(struct _widget *)
int widget_get_desired_height(widget *wid)
Definition: widget.c:552
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: widget.c:433
static widget * box_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: box.c:315
int widget_padding_get_padding_height(const widget *wid)
Definition: widget.c:537
void(* update)(struct _widget *)
static void box_update(widget *wid)
Definition: box.c:364
static int box_get_desired_width(widget *wid)
Definition: box.c:54
void box_add(box *box, widget *child, gboolean expand)
Definition: box.c:283
widget widget
Definition: box.c:43
int widget_padding_get_left(const widget *wid)
Definition: widget.c:482
gboolean expand
int widget_get_height(widget *widget)
Definition: widget.c:352