rofi  1.5.1
box.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2013-2017 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 
28 #define G_LOG_DOMAIN "Widgets.Box"
29 
30 #include <config.h>
31 #include <stdio.h>
32 #include "widgets/widget.h"
34 #include "widgets/box.h"
35 #include "theme.h"
36 
38 #define DEFAULT_SPACING 2
39 
40 struct _box
41 {
44  int max_size;
45  // RofiPadding between elements
47 
48  GList *children;
49 };
50 
51 static void box_update ( widget *wid );
52 
53 static int box_get_desired_width ( widget *wid )
54 {
55  box *b = (box *) wid;
56  int spacing = distance_get_pixel ( b->spacing, b->type );
57  int width = 0;
58 
59  // Allow user to override.
60  RofiDistance w = rofi_theme_get_distance ( wid, "width", 0 );
62  if ( width > 0 ) {
63  return width ;
64  }
65 
66  if ( b->type == ROFI_ORIENTATION_HORIZONTAL ) {
67  int active_widgets = 0;
68  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
69  widget * child = (widget *) iter->data;
70  if ( !child->enabled ) {
71  continue;
72  }
73  active_widgets++;
74  if ( child->expand == TRUE ) {
75  width += widget_get_desired_width ( child );
76  continue;
77  }
78  width += widget_get_desired_width ( child );
79  }
80  if ( active_widgets > 0 ) {
81  width += ( active_widgets - 1 ) * spacing;
82  }
83  }
84  else {
85  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
86  widget * child = (widget *) iter->data;
87  if ( !child->enabled ) {
88  continue;
89  }
90  width = MAX ( widget_get_desired_width ( child ), width );
91  }
92  }
93  width += widget_padding_get_padding_width ( wid );
94  return width;
95 }
96 static int box_get_desired_height ( widget *wid )
97 {
98  box *b = (box *) wid;
99  int spacing = distance_get_pixel ( b->spacing, b->type );
100  int height = 0;
101  if ( b->type == ROFI_ORIENTATION_VERTICAL ) {
102  int active_widgets = 0;
103  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
104  widget * child = (widget *) iter->data;
105  if ( !child->enabled ) {
106  continue;
107  }
108  active_widgets++;
109  if ( child->expand == TRUE ) {
110  height += widget_get_desired_height ( child );
111  continue;
112  }
113  height += widget_get_desired_height ( child );
114  }
115  if ( active_widgets > 0 ) {
116  height += ( active_widgets - 1 ) * spacing;
117  }
118  }
119  else {
120  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
121  widget * child = (widget *) iter->data;
122  if ( !child->enabled ) {
123  continue;
124  }
125  height = MAX ( widget_get_desired_height ( child ), height );
126  }
127  }
128  height += widget_padding_get_padding_height ( wid );
129  return height;
130 }
131 
132 static void vert_calculate_size ( box *b )
133 {
135  int expanding_widgets = 0;
136  int active_widgets = 0;
137  int rem_width = widget_padding_get_remaining_width ( WIDGET ( b ) );
138  int rem_height = widget_padding_get_remaining_height ( WIDGET ( b ) );
139  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
140  widget * child = (widget *) iter->data;
141  if ( child->enabled && child->expand == FALSE ) {
142  widget_resize ( child, rem_width, widget_get_desired_height ( child ) );
143  }
144  }
145  b->max_size = 0;
146  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
147  widget * child = (widget *) iter->data;
148  if ( !child->enabled ) {
149  continue;
150  }
151  active_widgets++;
152  if ( child->expand == TRUE ) {
153  expanding_widgets++;
154  continue;
155  }
156  if ( child->h > 0 ) {
157  b->max_size += child->h;
158  }
159  }
160  if ( active_widgets > 0 ) {
161  b->max_size += ( active_widgets - 1 ) * spacing;
162  }
163  if ( b->max_size > rem_height ) {
164  b->max_size = rem_height;
165  g_debug ( "Widgets to large (height) for box: %d %d", b->max_size, b->widget.h );
166  return;
167  }
168  if ( active_widgets > 0 ) {
169  int top = widget_padding_get_top ( WIDGET ( b ) );
170  double rem = rem_height - b->max_size;
171  int index = 0;
172  for ( GList *iter = g_list_first ( b->children ); iter != NULL; 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 );
180  widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
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  }
187  else {
188  widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
189  top += widget_get_height ( child );
190  top += spacing;
191  }
192  }
193  }
195 }
196 static void hori_calculate_size ( box *b )
197 {
199  int expanding_widgets = 0;
200  int active_widgets = 0;
201  int rem_width = widget_padding_get_remaining_width ( WIDGET ( b ) );
202  int rem_height = widget_padding_get_remaining_height ( WIDGET ( b ) );
203  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
204  widget * child = (widget *) iter->data;
205  if ( child->enabled && child->expand == FALSE ) {
206  widget_resize ( child,
207  widget_get_desired_width ( child ), //child->w,
208  rem_height );
209  }
210  }
211  b->max_size = 0;
212  for ( GList *iter = g_list_first ( b->children ); iter != NULL; 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, 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  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 box * box_create ( widget *parent, const char *name, RofiOrientation type )
336 {
337  box *b = g_malloc0 ( sizeof ( box ) );
338  // Initialize widget.
339  widget_init ( WIDGET ( b ), parent, WIDGET_TYPE_UNKNOWN, name );
340  b->type = type;
341  b->widget.draw = box_draw;
342  b->widget.free = box_free;
343  b->widget.resize = box_resize;
344  b->widget.update = box_update;
348 
349  b->type = rofi_theme_get_orientation ( WIDGET ( b ), "orientation", b->type );
350 
351  b->spacing = rofi_theme_get_distance ( WIDGET ( b ), "spacing", DEFAULT_SPACING );
352  return b;
353 }
354 
355 static void box_update ( widget *wid )
356 {
357  box *b = (box *) wid;
358  switch ( b->type )
359  {
361  vert_calculate_size ( b );
362  break;
364  default:
365  hori_calculate_size ( b );
366  }
367 }
Definition: box.c:40
WidgetType
Definition: widget.h:56
widget_find_mouse_target_cb find_mouse_target
RofiDistance spacing
Definition: box.c:46
void widget_update(widget *widget)
Definition: widget.c:411
static int box_get_desired_height(widget *wid)
Definition: box.c:96
int widget_padding_get_padding_width(const widget *wid)
Definition: widget.c:548
void(* resize)(struct _widget *, short, short)
int widget_padding_get_top(const widget *wid)
Definition: widget.c:506
struct _widget * parent
int widget_get_width(widget *widget)
Definition: widget.c:377
void widget_free(widget *wid)
Definition: widget.c:355
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition: theme.c:571
GList * children
Definition: box.c:48
void(* draw)(struct _widget *widget, cairo_t *draw)
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition: theme.c:549
int(* get_desired_width)(struct _widget *)
void widget_draw(widget *widget, cairo_t *d)
Definition: widget.c:140
int widget_intersect(const widget *widget, int x, int y)
Definition: widget.c:68
gboolean enabled
void widget_move(widget *widget, short x, short y)
Definition: widget.c:98
static void hori_calculate_size(box *b)
Definition: box.c:196
void widget_resize(widget *widget, short w, short h)
Definition: widget.c:82
static void vert_calculate_size(box *b)
Definition: box.c:132
RofiOrientation type
Definition: box.c:43
static void box_draw(widget *wid, cairo_t *draw)
Definition: box.c:262
#define DEFAULT_SPACING
Definition: box.c:38
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition: box.c:335
int widget_padding_get_remaining_height(const widget *wid)
Definition: widget.c:534
RofiOrientation
Definition: rofi-types.h:105
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:735
int max_size
Definition: box.c:44
int widget_get_desired_width(widget *wid)
Definition: widget.c:566
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition: theme.c:587
#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:527
void widget_init(widget *wid, widget *parent, WidgetType type, const char *name)
Definition: widget.c:37
int(* get_desired_height)(struct _widget *)
int widget_get_desired_height(widget *wid)
Definition: widget.c:556
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: widget.c:442
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:541
void(* update)(struct _widget *)
static void box_update(widget *wid)
Definition: box.c:355
static int box_get_desired_width(widget *wid)
Definition: box.c:53
void box_add(box *box, widget *child, gboolean expand)
Definition: box.c:283
widget widget
Definition: box.c:42
int widget_padding_get_left(const widget *wid)
Definition: widget.c:486
gboolean expand
int widget_get_height(widget *widget)
Definition: widget.c:367