rofi  1.5.4
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 
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  if ( child->expand == TRUE ) {
111  height += widget_get_desired_height ( child );
112  continue;
113  }
114  height += widget_get_desired_height ( child );
115  }
116  if ( active_widgets > 0 ) {
117  height += ( active_widgets - 1 ) * spacing;
118  }
119  }
120  else {
121  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
122  widget * child = (widget *) iter->data;
123  if ( !child->enabled ) {
124  continue;
125  }
126  height = MAX ( widget_get_desired_height ( child ), height );
127  }
128  }
129  height += widget_padding_get_padding_height ( wid );
130  return height;
131 }
132 
133 static void vert_calculate_size ( box *b )
134 {
136  int expanding_widgets = 0;
137  int active_widgets = 0;
138  int rem_width = widget_padding_get_remaining_width ( WIDGET ( b ) );
139  int rem_height = widget_padding_get_remaining_height ( WIDGET ( b ) );
140  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
141  widget * child = (widget *) iter->data;
142  if ( child->enabled && child->expand == FALSE ) {
143  widget_resize ( child, rem_width, widget_get_desired_height ( child ) );
144  }
145  }
146  b->max_size = 0;
147  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
148  widget * child = (widget *) iter->data;
149  if ( !child->enabled ) {
150  continue;
151  }
152  active_widgets++;
153  if ( child->expand == TRUE ) {
154  expanding_widgets++;
155  continue;
156  }
157  if ( child->h > 0 ) {
158  b->max_size += child->h;
159  }
160  }
161  if ( active_widgets > 0 ) {
162  b->max_size += ( active_widgets - 1 ) * spacing;
163  }
164  if ( b->max_size > rem_height ) {
165  b->max_size = rem_height;
166  g_debug ( "Widgets to large (height) for box: %d %d", b->max_size, b->widget.h );
167  return;
168  }
169  if ( active_widgets > 0 ) {
170  int top = widget_padding_get_top ( WIDGET ( b ) );
171  double rem = rem_height - b->max_size;
172  int index = 0;
173  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
174  widget * child = (widget *) iter->data;
175  if ( child->enabled == FALSE ) {
176  continue;
177  }
178  if ( child->expand == TRUE ) {
179  // Re-calculate to avoid round issues leaving one pixel left.
180  int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
181  widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
182  top += expanding_widgets_size;
183  widget_resize ( child, rem_width, expanding_widgets_size );
184  top += spacing;
185  rem -= expanding_widgets_size;
186  index++;
187  }
188  else {
189  widget_move ( child, widget_padding_get_left ( WIDGET ( b ) ), top );
190  top += widget_get_height ( child );
191  top += spacing;
192  }
193  }
194  }
196 }
197 static void hori_calculate_size ( box *b )
198 {
200  int expanding_widgets = 0;
201  int active_widgets = 0;
202  int rem_width = widget_padding_get_remaining_width ( WIDGET ( b ) );
203  int rem_height = widget_padding_get_remaining_height ( WIDGET ( b ) );
204  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
205  widget * child = (widget *) iter->data;
206  if ( child->enabled && child->expand == FALSE ) {
207  widget_resize ( child,
208  widget_get_desired_width ( child ), //child->w,
209  rem_height );
210  }
211  }
212  b->max_size = 0;
213  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
214  widget * child = (widget *) iter->data;
215  if ( !child->enabled ) {
216  continue;
217  }
218  active_widgets++;
219  if ( child->expand == TRUE ) {
220  expanding_widgets++;
221  continue;
222  }
223  // Size used by fixed width widgets.
224  if ( child->h > 0 ) {
225  b->max_size += child->w;
226  }
227  }
228  b->max_size += MAX ( 0, ( ( active_widgets - 1 ) * spacing ) );
229  if ( b->max_size > ( rem_width ) ) {
230  b->max_size = rem_width;
231  g_debug ( "Widgets to large (width) for box: %d %d", b->max_size, b->widget.w );
232  return;
233  }
234  if ( active_widgets > 0 ) {
235  int left = widget_padding_get_left ( WIDGET ( b ) );
236  double rem = rem_width - b->max_size;
237  int index = 0;
238  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
239  widget * child = (widget *) iter->data;
240  if ( child->enabled == FALSE ) {
241  continue;
242  }
243  if ( child->expand == TRUE ) {
244  // Re-calculate to avoid round issues leaving one pixel left.
245  int expanding_widgets_size = ( rem ) / ( expanding_widgets - index );
246  widget_move ( child, left, widget_padding_get_top ( WIDGET ( b ) ) );
247  left += expanding_widgets_size;
248  widget_resize ( child, expanding_widgets_size, rem_height );
249  left += spacing;
250  rem -= expanding_widgets_size;
251  index++;
252  }
253  else {
254  widget_move ( child, left, widget_padding_get_top ( WIDGET ( b ) ) );
255  left += widget_get_width ( child );
256  left += spacing;
257  }
258  }
259  }
261 }
262 
263 static void box_draw ( widget *wid, cairo_t *draw )
264 {
265  box *b = (box *) wid;
266  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
267  widget * child = (widget *) iter->data;
268  widget_draw ( child, draw );
269  }
270 }
271 
272 static void box_free ( widget *wid )
273 {
274  box *b = (box *) wid;
275 
276  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
277  widget * child = (widget *) iter->data;
278  widget_free ( child );
279  }
280  g_list_free ( b->children );
281  g_free ( b );
282 }
283 
284 void box_add ( box *box, widget *child, gboolean expand )
285 {
286  if ( box == NULL ) {
287  return;
288  }
289  // Make sure box is width/heigh enough.
290  if ( box->type == ROFI_ORIENTATION_VERTICAL ) {
291  int width = box->widget.w;
292  width = MAX ( width, child->w + widget_padding_get_padding_width ( WIDGET ( box ) ) );
293  box->widget.w = width;
294  }
295  else {
296  int height = box->widget.h;
297  height = MAX ( height, child->h + widget_padding_get_padding_height ( WIDGET ( box ) ) );
298  box->widget.h = height;
299  }
300  child->expand = rofi_theme_get_boolean ( child, "expand", expand );
301  g_assert ( child->parent == WIDGET ( box ) );
302  box->children = g_list_append ( box->children, (void *) child );
303  widget_update ( WIDGET ( box ) );
304 }
305 
306 static void box_resize ( widget *widget, short w, short h )
307 {
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;
312  widget_update ( widget );
313  }
314 }
315 
316 static widget *box_find_mouse_target ( widget *wid, WidgetType type, gint x, gint y )
317 {
318  box *b = (box *) wid;
319  for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) {
320  widget * child = (widget *) iter->data;
321  if ( !child->enabled ) {
322  continue;
323  }
324  if ( widget_intersect ( child, x, y ) ) {
325  gint rx = x - child->x;
326  gint ry = y - child->y;
327  widget *target = widget_find_mouse_target ( child, type, rx, ry );
328  if ( target != NULL ) {
329  return target;
330  }
331  }
332  }
333  return NULL;
334 }
335 
336 box * box_create ( widget *parent, const char *name, RofiOrientation type )
337 {
338  box *b = g_malloc0 ( sizeof ( box ) );
339  // Initialize widget.
340  widget_init ( WIDGET ( b ), parent, WIDGET_TYPE_UNKNOWN, name );
341  b->type = type;
342  b->widget.draw = box_draw;
343  b->widget.free = box_free;
344  b->widget.resize = box_resize;
345  b->widget.update = box_update;
349 
350  b->type = rofi_theme_get_orientation ( WIDGET ( b ), "orientation", b->type );
351 
352  b->spacing = rofi_theme_get_distance ( WIDGET ( b ), "spacing", DEFAULT_SPACING );
353  return b;
354 }
355 
356 static void box_update ( widget *wid )
357 {
358  box *b = (box *) wid;
359  switch ( b->type )
360  {
362  vert_calculate_size ( b );
363  break;
365  default:
366  hori_calculate_size ( b );
367  }
368 }
WIDGET
#define WIDGET(a)
Definition: widget.h:115
WidgetType
WidgetType
Definition: widget.h:57
WIDGET_TYPE_UNKNOWN
@ WIDGET_TYPE_UNKNOWN
Definition: widget.h:59
_widget::enabled
gboolean enabled
Definition: widget-internal.h:58
_box::children
GList * children
Definition: box.c:49
_widget::expand
gboolean expand
Definition: widget-internal.h:60
ROFI_ORIENTATION_VERTICAL
@ ROFI_ORIENTATION_VERTICAL
Definition: rofi-types.h:107
widget_get_height
int widget_get_height(widget *widget)
Definition: widget.c:378
_widget::get_desired_width
int(* get_desired_width)(struct _widget *)
Definition: widget-internal.h:82
distance_get_pixel
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition: theme.c:765
box_create
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition: box.c:336
_widget::get_desired_height
int(* get_desired_height)(struct _widget *)
Definition: widget-internal.h:81
rofi_theme_get_distance
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition: theme.c:579
rofi_theme_get_boolean
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition: theme.c:601
widget_get_width
int widget_get_width(widget *widget)
Definition: widget.c:388
widget_find_mouse_target
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: widget.c:453
box_add
void box_add(box *box, widget *child, gboolean expand)
Definition: box.c:284
widget_padding_get_remaining_height
int widget_padding_get_remaining_height(const widget *wid)
Definition: widget.c:545
widget_update
void widget_update(widget *widget)
Definition: widget.c:422
widget_padding_get_remaining_width
int widget_padding_get_remaining_width(const widget *wid)
Definition: widget.c:538
vert_calculate_size
static void vert_calculate_size(box *b)
Definition: box.c:133
box_resize
static void box_resize(widget *widget, short w, short h)
Definition: box.c:306
_widget::draw
void(* draw)(struct _widget *widget, cairo_t *draw)
Definition: widget-internal.h:72
rofi_theme_get_orientation
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition: theme.c:617
box_draw
static void box_draw(widget *wid, cairo_t *draw)
Definition: box.c:263
theme.h
box.h
widget_free
void widget_free(widget *wid)
Definition: widget.c:365
RofiDistance
Definition: rofi-types.h:93
_widget::free
void(* free)(struct _widget *widget)
Definition: widget-internal.h:92
box_free
static void box_free(widget *wid)
Definition: box.c:272
widget_get_desired_width
int widget_get_desired_width(widget *wid)
Definition: widget.c:577
_widget::y
short y
Definition: widget-internal.h:42
_box::max_size
int max_size
Definition: box.c:45
_box::type
RofiOrientation type
Definition: box.c:44
hori_calculate_size
static void hori_calculate_size(box *b)
Definition: box.c:197
widget.h
_widget::x
short x
Definition: widget-internal.h:40
widget_padding_get_top
int widget_padding_get_top(const widget *wid)
Definition: widget.c:517
_widget::parent
struct _widget * parent
Definition: widget-internal.h:64
_box::widget
widget widget
Definition: box.c:43
widget_intersect
int widget_intersect(const widget *widget, int x, int y)
Definition: widget.c:70
box_get_desired_width
static int box_get_desired_width(widget *wid)
Definition: box.c:54
_box
Definition: box.c:42
widget_move
void widget_move(widget *widget, short x, short y)
Definition: widget.c:100
_widget::h
short h
Definition: widget-internal.h:46
box_update
static void box_update(widget *wid)
Definition: box.c:356
widget_init
void widget_init(widget *wid, widget *parent, WidgetType type, const char *name)
Definition: widget.c:37
_widget::w
short w
Definition: widget-internal.h:44
widget-internal.h
box_get_desired_height
static int box_get_desired_height(widget *wid)
Definition: box.c:97
widget_draw
void widget_draw(widget *widget, cairo_t *d)
Definition: widget.c:142
_widget::find_mouse_target
widget_find_mouse_target_cb find_mouse_target
Definition: widget-internal.h:85
DEFAULT_SPACING
#define DEFAULT_SPACING
Definition: box.c:39
widget_padding_get_left
int widget_padding_get_left(const widget *wid)
Definition: widget.c:497
_widget::resize
void(* resize)(struct _widget *, short, short)
Definition: widget-internal.h:74
widget_get_desired_height
int widget_get_desired_height(widget *wid)
Definition: widget.c:567
_box::spacing
RofiDistance spacing
Definition: box.c:47
box_find_mouse_target
static widget * box_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: box.c:316
widget_resize
void widget_resize(widget *widget, short w, short h)
Definition: widget.c:84
_widget::update
void(* update)(struct _widget *)
Definition: widget-internal.h:76
ROFI_ORIENTATION_HORIZONTAL
@ ROFI_ORIENTATION_HORIZONTAL
Definition: rofi-types.h:108
RofiOrientation
RofiOrientation
Definition: rofi-types.h:106
widget_padding_get_padding_width
int widget_padding_get_padding_width(const widget *wid)
Definition: widget.c:559
widget_padding_get_padding_height
int widget_padding_get_padding_height(const widget *wid)
Definition: widget.c:552
_widget
Definition: widget-internal.h:36