rofi  1.5.2
listview.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 #include <config.h>
29 #include <glib.h>
30 #include <widgets/widget.h>
31 #include <widgets/textbox.h>
32 #include <widgets/listview.h>
33 #include <widgets/scrollbar.h>
34 
35 #include "settings.h"
36 #include "theme.h"
37 
39 #define DEFAULT_SPACING 2
40 
44 typedef enum
45 {
50 } ViewType;
51 
55 typedef enum
56 {
60 
61 struct _listview
62 {
64 
66 
67  // RChanged
68  // Text needs to be repainted.
69  unsigned int rchanged;
70  // Administration
71 
72  unsigned int cur_page;
73  unsigned int last_offset;
74  unsigned int selected;
75 
76  unsigned int element_height;
77  unsigned int element_width;
78  unsigned int max_rows;
79  unsigned int max_elements;
80 
81  //
82  unsigned int cur_columns;
83  unsigned int req_elements;
84  unsigned int cur_elements;
85 
87  unsigned int menu_lines;
88  unsigned int max_displayed_lines;
89  unsigned int menu_columns;
90  unsigned int fixed_num_lines;
91  unsigned int dynamic;
92  unsigned int eh;
93  unsigned int reverse;
94  gboolean cycle;
95  gboolean multi_select;
96 
98 
101 
103  void *udata;
104 
106 
107  xcb_timestamp_t last_click;
110 
112 
114  struct
115  {
117  unsigned int cur_visible;
118  } barview;
119 };
120 
121 static int listview_get_desired_height ( widget *wid );
122 
123 static void listview_free ( widget *wid )
124 {
125  listview *lv = (listview *) wid;
126  for ( unsigned int i = 0; i < lv->cur_elements; i++ ) {
127  widget_free ( WIDGET ( lv->boxes [i] ) );
128  }
129  g_free ( lv->boxes );
130 
131  g_free ( lv->listview_name );
132  widget_free ( WIDGET ( lv->scrollbar ) );
133  g_free ( lv );
134 }
135 static unsigned int scroll_per_page_barview ( listview *lv )
136 {
137  unsigned int offset = lv->last_offset;
138 
139  // selected row is always visible.
140  // If selected is visible do not scroll.
141  if ( lv->selected < lv->last_offset ) {
142  offset = lv->selected;
143  lv->rchanged = TRUE;
144  }
145  else if ( lv->selected >= ( lv->last_offset + lv->barview.cur_visible ) ) {
146  offset = lv->selected;
147  lv->rchanged = TRUE;
148  }
149  return offset;
150 }
151 static unsigned int scroll_per_page ( listview * lv )
152 {
153  int offset = 0;
154 
155  // selected row is always visible.
156  // If selected is visible do not scroll.
157  if ( ( ( lv->selected - ( lv->last_offset ) ) < ( lv->max_elements ) ) && ( lv->selected >= ( lv->last_offset ) ) ) {
158  offset = lv->last_offset;
159  }
160  else{
161  // Do paginating
162  unsigned int page = ( lv->max_elements > 0 ) ? ( lv->selected / lv->max_elements ) : 0;
163  offset = page * lv->max_elements;
164  if ( page != lv->cur_page ) {
165  lv->cur_page = page;
166  lv->rchanged = TRUE;
167  }
168  // Set the position
169  //scrollbar_set_handle ( lv->scrollbar, page * lv->max_elements );
170  }
171  return offset;
172 }
173 
174 static unsigned int scroll_continious ( listview *lv )
175 {
176  unsigned int middle = ( lv->max_rows - ( ( lv->max_rows & 1 ) == 0 ) ) / 2;
177  unsigned int offset = 0;
178  if ( lv->selected > middle ) {
179  if ( lv->selected < ( lv->req_elements - ( lv->max_rows - middle ) ) ) {
180  offset = lv->selected - middle;
181  }
182  // Don't go below zero.
183  else if ( lv->req_elements > lv->max_rows ) {
184  offset = lv->req_elements - lv->max_rows;
185  }
186  }
187  if ( offset != lv->cur_page ) {
188  //scrollbar_set_handle ( lv->scrollbar, offset );
189  lv->cur_page = offset;
190  lv->rchanged = TRUE;
191  }
192  return offset;
193 }
194 
195 static void update_element ( listview *lv, unsigned int tb, unsigned int index, gboolean full )
196 {
197  // Select drawing mode
198  TextBoxFontType type = ( index & 1 ) == 0 ? NORMAL : ALT;
199  type = ( index ) == lv->selected ? HIGHLIGHT : type;
200 
201  if ( lv->callback ) {
202  lv->callback ( lv->boxes[tb], index, lv->udata, type, full );
203  }
204 }
205 
206 static void barview_draw ( widget *wid, cairo_t *draw )
207 {
208  unsigned int offset = 0;
209  listview *lv = (listview *) wid;
210  offset = scroll_per_page_barview ( lv );
211  lv->last_offset = offset;
212  int spacing_hori = distance_get_pixel ( lv->spacing, ROFI_ORIENTATION_HORIZONTAL );
213 
214  int left_offset = widget_padding_get_left ( wid );
215  int right_offset = lv->widget.w - widget_padding_get_right ( wid );
216  int top_offset = widget_padding_get_top ( wid );
217  if ( lv->cur_elements > 0 ) {
218  // Set new x/y position.
219  unsigned int max = MIN ( lv->cur_elements, lv->req_elements - offset );
220  if ( lv->rchanged ) {
221  int first = TRUE;
222  int width = lv->widget.w;
223  lv->barview.cur_visible = 0;
224  width -= widget_padding_get_padding_width ( wid );
225  if ( lv->barview.direction == LEFT_TO_RIGHT ) {
226  for ( unsigned int i = 0; i < max && width > 0; i++ ) {
227  update_element ( lv, i, i + offset, TRUE );
228  int twidth = textbox_get_desired_width ( WIDGET ( lv->boxes[i] ) );
229  if ( twidth >= width ) {
230  if ( !first ) {
231  break;
232  }
233  twidth = width;
234  }
235  textbox_moveresize ( lv->boxes[i], left_offset, top_offset, twidth, lv->element_height );
236 
237  widget_draw ( WIDGET ( lv->boxes[i] ), draw );
238  width -= twidth + spacing_hori;
239  left_offset += twidth + spacing_hori;
240  first = FALSE;
241  lv->barview.cur_visible++;
242  }
243  }
244  else {
245  for ( unsigned int i = 0; i < lv->cur_elements && width > 0 && i <= offset; i++ ) {
246  update_element ( lv, i, offset - i, TRUE );
247  int twidth = textbox_get_desired_width ( WIDGET ( lv->boxes[i] ) );
248  if ( twidth >= width ) {
249  if ( !first ) {
250  break;
251  }
252  twidth = width;
253  }
254  right_offset -= twidth;
255  textbox_moveresize ( lv->boxes[i], right_offset, top_offset, twidth, lv->element_height );
256 
257  widget_draw ( WIDGET ( lv->boxes[i] ), draw );
258  width -= twidth + spacing_hori;
259  right_offset -= spacing_hori;
260  first = FALSE;
261  lv->barview.cur_visible++;
262  }
263  offset -= lv->barview.cur_visible - 1;
264  lv->last_offset = offset;
265  for ( unsigned int i = 0; i < ( lv->barview.cur_visible / 2 ); i++ ) {
266  void * temp = lv->boxes[i];
267  int sw = lv->barview.cur_visible - i - 1;
268  lv->boxes[i] = lv->boxes[sw];
269  lv->boxes[sw] = temp;
270  }
271  }
272  lv->rchanged = FALSE;
273  }
274  else {
275  for ( unsigned int i = 0; i < lv->barview.cur_visible; i++ ) {
276  update_element ( lv, i, i + offset, FALSE );
277  widget_draw ( WIDGET ( lv->boxes[i] ), draw );
278  }
279  }
280  }
281 }
282 
283 static void listview_draw ( widget *wid, cairo_t *draw )
284 {
285  unsigned int offset = 0;
286  listview *lv = (listview *) wid;
288  offset = scroll_continious ( lv );
289  }
290  else {
291  offset = scroll_per_page ( lv );
292  }
293  // Set these all together to make sure they update consistently.
296  if ( lv->reverse ) {
297  scrollbar_set_handle ( lv->scrollbar, lv->req_elements - lv->selected - 1 );
298  }
299  else {
301  }
302  lv->last_offset = offset;
303  int spacing_vert = distance_get_pixel ( lv->spacing, ROFI_ORIENTATION_VERTICAL );
304  int spacing_hori = distance_get_pixel ( lv->spacing, ROFI_ORIENTATION_HORIZONTAL );
305 
306  int left_offset = widget_padding_get_left ( wid );
307  int top_offset = widget_padding_get_top ( wid );
308  /*
309  if ( lv->scrollbar->widget.index == 0 ) {
310  left_offset += spacing_hori + lv->scrollbar->widget.w;
311  }
312  */
313  if ( lv->cur_elements > 0 && lv->max_rows > 0 ) {
314  // Set new x/y position.
315  unsigned int max = MIN ( lv->cur_elements, lv->req_elements - offset );
316  if ( lv->rchanged ) {
317  unsigned int width = lv->widget.w - spacing_hori * ( lv->cur_columns - 1 );
318  width -= widget_padding_get_padding_width ( wid );
319  if ( widget_enabled ( WIDGET ( lv->scrollbar ) ) ) {
320  width -= spacing_hori;
321  width -= widget_get_width ( WIDGET ( lv->scrollbar ) );
322  }
323  unsigned int element_width = ( width ) / lv->cur_columns;
324  for ( unsigned int i = 0; i < max; i++ ) {
325  unsigned int ex = left_offset + ( ( i ) / lv->max_rows ) * ( element_width + spacing_hori );
326  if ( lv->reverse ) {
327  unsigned int ey = wid->h - ( widget_padding_get_bottom ( wid ) + ( ( i ) % lv->max_rows ) * ( lv->element_height + spacing_vert ) ) - lv->element_height;
328  textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height );
329  }
330  else {
331  unsigned int ey = top_offset + ( ( i ) % lv->max_rows ) * ( lv->element_height + spacing_vert );
332  textbox_moveresize ( lv->boxes[i], ex, ey, element_width, lv->element_height );
333  }
334 
335  update_element ( lv, i, i + offset, TRUE );
336  widget_draw ( WIDGET ( lv->boxes[i] ), draw );
337  }
338  lv->rchanged = FALSE;
339  }
340  else {
341  for ( unsigned int i = 0; i < max; i++ ) {
342  update_element ( lv, i, i + offset, FALSE );
343  widget_draw ( WIDGET ( lv->boxes[i] ), draw );
344  }
345  }
346  }
347  widget_draw ( WIDGET ( lv->scrollbar ), draw );
348 }
349 static WidgetTriggerActionResult listview_element_trigger_action ( widget *wid, MouseBindingListviewElementAction action, gint x, gint y, void *user_data );
350 
351 static void _listview_draw ( widget *wid, cairo_t *draw )
352 {
353  listview *lv = (listview *) wid;
354  if ( lv->type == LISTVIEW ) {
355  listview_draw ( wid, draw );
356  }
357  else {
358  barview_draw ( wid, draw );
359  }
360 }
362 {
363  unsigned int newne = 0;
364  if ( lv->max_rows == 0 ) {
365  return;
366  }
367  if ( lv->req_elements < lv->max_elements ) {
368  newne = lv->req_elements;
369  lv->cur_columns = ( lv->req_elements + ( lv->max_rows - 1 ) ) / lv->max_rows;
370  }
371  else {
372  newne = lv->max_elements;
373  lv->cur_columns = lv->menu_columns;
374  }
375  for ( unsigned int i = newne; i < lv->cur_elements; i++ ) {
376  widget_free ( WIDGET ( lv->boxes[i] ) );
377  }
378  lv->boxes = g_realloc ( lv->boxes, newne * sizeof ( textbox* ) );
379  if ( newne > 0 ) {
380  for ( unsigned int i = lv->cur_elements; i < newne; i++ ) {
382  flags |= ( ( config.show_icons ) ? TB_ICON : 0 );
383  lv->boxes[i] = textbox_create ( WIDGET ( lv ), WIDGET_TYPE_LISTVIEW_ELEMENT, "element", flags, NORMAL, "", 0, 0 );
385  }
386  }
387  lv->rchanged = TRUE;
388  lv->cur_elements = newne;
389 }
390 
391 void listview_set_num_elements ( listview *lv, unsigned int rows )
392 {
393  if ( lv == NULL ) {
394  return;
395  }
396  lv->req_elements = rows;
397  listview_set_selected ( lv, lv->selected );
399  widget_queue_redraw ( WIDGET ( lv ) );
400 }
401 
402 unsigned int listview_get_selected ( listview *lv )
403 {
404  if ( lv != NULL ) {
405  return lv->selected;
406  }
407  return 0;
408 }
409 
410 void listview_set_selected ( listview *lv, unsigned int selected )
411 {
412  if ( lv && lv->req_elements > 0 ) {
413  lv->selected = MIN ( selected, lv->req_elements - 1 );
415  widget_queue_redraw ( WIDGET ( lv ) );
416  }
417 }
418 
419 static void listview_resize ( widget *wid, short w, short h )
420 {
421  listview *lv = (listview *) wid;
422  lv->widget.w = MAX ( 0, w );
423  lv->widget.h = MAX ( 0, h );
424  int height = lv->widget.h - widget_padding_get_padding_height ( WIDGET ( lv ) );
425  int spacing_vert = distance_get_pixel ( lv->spacing, ROFI_ORIENTATION_VERTICAL );
426  lv->max_rows = ( spacing_vert + height ) / ( lv->element_height + spacing_vert );
427  lv->max_elements = lv->max_rows * lv->menu_columns;
428 
429  if ( /*lv->scrollbar->widget.index ==*/ 0 ) {
430  widget_move ( WIDGET ( lv->scrollbar ),
431  widget_padding_get_left ( WIDGET ( lv ) ),
432  widget_padding_get_top ( WIDGET ( lv ) ) );
433  }
434  else {
435  widget_move ( WIDGET ( lv->scrollbar ),
437  widget_padding_get_top ( WIDGET ( lv ) ) );
438  }
439  widget_resize ( WIDGET ( lv->scrollbar ), widget_get_width ( WIDGET ( lv->scrollbar ) ), height );
440 
441  if ( lv->type == BARVIEW ) {
442  lv->max_elements = lv->menu_lines;
443  }
444 
446  widget_queue_redraw ( wid );
447 }
448 
449 static widget *listview_find_mouse_target ( widget *wid, WidgetType type, gint x, gint y )
450 {
451  widget *target = NULL;
452  gint rx, ry;
453  listview *lv = (listview *) wid;
454  if ( widget_enabled ( WIDGET ( lv->scrollbar ) ) && widget_intersect ( WIDGET ( lv->scrollbar ), x, y ) ) {
455  rx = x - widget_get_x_pos ( WIDGET ( lv->scrollbar ) );
456  ry = y - widget_get_y_pos ( WIDGET ( lv->scrollbar ) );
457  target = widget_find_mouse_target ( WIDGET ( lv->scrollbar ), type, rx, ry );
458  }
459 
460  unsigned int max = MIN ( lv->cur_elements, lv->req_elements - lv->last_offset );
461  unsigned int i;
462  for ( i = 0; i < max && target == NULL; i++ ) {
463  widget *w = WIDGET ( lv->boxes[i] );
464  if ( widget_intersect ( w, x, y ) ) {
465  rx = x - widget_get_x_pos ( w );
466  ry = y - widget_get_y_pos ( w );
467  target = widget_find_mouse_target ( w, type, rx, ry );
468  }
469  }
470 
471  return target;
472 }
473 
474 static WidgetTriggerActionResult listview_trigger_action ( widget *wid, MouseBindingListviewAction action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data )
475 {
476  listview *lv = (listview *) wid;
477  switch ( action )
478  {
479  case SCROLL_LEFT:
480  listview_nav_left ( lv );
481  break;
482  case SCROLL_RIGHT:
483  listview_nav_right ( lv );
484  break;
485  case SCROLL_DOWN:
486  listview_nav_down ( lv );
487  break;
488  case SCROLL_UP:
489  listview_nav_up ( lv );
490  break;
491  }
493 }
494 
495 static WidgetTriggerActionResult listview_element_trigger_action ( widget *wid, MouseBindingListviewElementAction action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, void *user_data )
496 {
497  listview *lv = (listview *) user_data;
498  unsigned int max = MIN ( lv->cur_elements, lv->req_elements - lv->last_offset );
499  unsigned int i;
500  for ( i = 0; i < max && WIDGET ( lv->boxes[i] ) != wid; i++ ) {
501  }
502  if ( i == max ) {
504  }
505 
506  gboolean custom = FALSE;
507  switch ( action )
508  {
510  listview_set_selected ( lv, lv->last_offset + i );
511  break;
513  custom = TRUE;
514  /* FALLTHRU */
516  listview_set_selected ( lv, lv->last_offset + i );
517  lv->mouse_activated ( lv, custom, lv->mouse_activated_data );
518  break;
519  }
521 }
522 
523 listview *listview_create ( widget *parent, const char *name, listview_update_callback cb, void *udata, unsigned int eh, gboolean reverse )
524 {
525  listview *lv = g_malloc0 ( sizeof ( listview ) );
526  widget_init ( WIDGET ( lv ), parent, WIDGET_TYPE_LISTVIEW, name );
527  lv->listview_name = g_strdup ( name );
528  lv->widget.free = listview_free;
530  lv->widget.draw = _listview_draw;
534  lv->eh = eh;
535 
536  lv->scrollbar = scrollbar_create ( WIDGET ( lv ), "scrollbar" );
537  // Calculate height of an element.
538  //
539  textbox *tb = textbox_create ( WIDGET ( lv ), WIDGET_TYPE_LISTVIEW_ELEMENT, "element", 0, NORMAL, "", 0, 0 );
541  widget_free ( WIDGET ( tb ) );
542 
543  lv->callback = cb;
544  lv->udata = udata;
545 
546  // Some settings.
547  lv->spacing = rofi_theme_get_distance ( WIDGET ( lv ), "spacing", DEFAULT_SPACING );
548  lv->menu_columns = rofi_theme_get_integer ( WIDGET ( lv ), "columns", config.menu_columns );
549  lv->fixed_num_lines = rofi_theme_get_boolean ( WIDGET ( lv ), "fixed-height", config.fixed_num_lines );
550  lv->dynamic = rofi_theme_get_boolean ( WIDGET ( lv ), "dynamic", TRUE );
551  lv->reverse = rofi_theme_get_boolean ( WIDGET ( lv ), "reverse", reverse );
552  lv->cycle = rofi_theme_get_boolean ( WIDGET ( lv ), "cycle", config.cycle );
553 
555  if ( lv->type == LISTVIEW ) {
556  listview_set_show_scrollbar ( lv, rofi_theme_get_boolean ( WIDGET ( lv ), "scrollbar", FALSE ) );
557  }
558  else {
559  listview_set_show_scrollbar ( lv, FALSE );
560  }
561  return lv;
562 }
563 
568 static void listview_nav_up_int ( listview *lv )
569 {
570  if ( lv == NULL ) {
571  return;
572  }
573  if ( lv->req_elements == 0 || ( lv->selected == 0 && !lv->cycle ) ) {
574  return;
575  }
576  if ( lv->selected == 0 ) {
577  lv->selected = lv->req_elements;
578  }
579  lv->selected--;
581  widget_queue_redraw ( WIDGET ( lv ) );
582 }
583 static void listview_nav_down_int ( listview *lv )
584 {
585  if ( lv == NULL ) {
586  return;
587  }
588  if ( lv->req_elements == 0 || ( lv->selected == ( lv->req_elements - 1 ) && !lv->cycle ) ) {
589  return;
590  }
591  lv->selected = lv->selected < lv->req_elements - 1 ? MIN ( lv->req_elements - 1, lv->selected + 1 ) : 0;
593  widget_queue_redraw ( WIDGET ( lv ) );
594 }
595 
597 {
598  if ( lv == NULL ) {
599  return;
600  }
601  if ( lv->reverse ) {
602  listview_nav_down_int ( lv );
603  }
604  else {
605  listview_nav_up_int ( lv );
606  }
607 }
609 {
610  if ( lv == NULL ) {
611  return;
612  }
613  if ( lv->reverse ) {
614  listview_nav_up_int ( lv );
615  }
616  else {
617  listview_nav_down_int ( lv );
618  }
619 }
620 
622 {
623  if ( lv == NULL ) {
624  return;
625  }
626  if ( lv->type == BARVIEW ) {
627  listview_nav_up_int ( lv );
628  return;
629  }
630  if ( lv->selected >= lv->max_rows ) {
631  lv->selected -= lv->max_rows;
632  widget_queue_redraw ( WIDGET ( lv ) );
633  }
634 }
636 {
637  if ( lv == NULL ) {
638  return;
639  }
640  if ( lv->type == BARVIEW ) {
641  listview_nav_down_int ( lv );
642  return;
643  }
644  if ( ( lv->selected + lv->max_rows ) < lv->req_elements ) {
645  lv->selected += lv->max_rows;
646  widget_queue_redraw ( WIDGET ( lv ) );
647  }
648  else if ( lv->selected < ( lv->req_elements - 1 ) ) {
649  // We do not want to move to last item, UNLESS the last column is only
650  // partially filled, then we still want to move column and select last entry.
651  // First check the column we are currently in.
652  int col = lv->selected / lv->max_rows;
653  // Check total number of columns.
654  int ncol = lv->req_elements / lv->max_rows;
655  // If there is an extra column, move.
656  if ( col != ncol ) {
657  lv->selected = lv->req_elements - 1;
658  widget_queue_redraw ( WIDGET ( lv ) );
659  }
660  }
661 }
662 
664 {
665  if ( lv == NULL ) {
666  return;
667  }
668  if ( lv->type == BARVIEW ) {
669  if ( lv->last_offset == 0 ) {
670  lv->selected = 0;
671  }
672  else {
673  lv->selected = lv->last_offset - 1;
674  }
676  widget_queue_redraw ( WIDGET ( lv ) );
677  return;
678  }
679 
680  if ( lv->selected < lv->max_elements ) {
681  lv->selected = 0;
682  }
683  else{
684  lv->selected -= ( lv->max_elements );
685  }
686  widget_queue_redraw ( WIDGET ( lv ) );
687 }
689 {
690  if ( lv == NULL ) {
691  return;
692  }
693  if ( lv->req_elements == 0 ) {
694  return;
695  }
696  if ( lv->type == BARVIEW ) {
697  unsigned int new = lv->last_offset + lv->barview.cur_visible;
698  lv->selected = MIN ( new, lv->req_elements - 1 );
700 
701  widget_queue_redraw ( WIDGET ( lv ) );
702  return;
703  }
704  lv->selected += ( lv->max_elements );
705  if ( lv->selected >= lv->req_elements ) {
706  lv->selected = lv->req_elements - 1;
707  }
708  widget_queue_redraw ( WIDGET ( lv ) );
709 }
710 
712 {
713  if ( lv == NULL ) {
714  return;
715  }
716  if ( lv->reverse ) {
718  }
719  else {
721  }
722 }
724 {
725  if ( lv == NULL ) {
726  return;
727  }
728  if ( lv->reverse ) {
730  }
731  else {
733  }
734 }
735 
737 {
738  listview *lv = (listview *) wid;
739  if ( lv == NULL || lv->widget.enabled == FALSE ) {
740  return 0;
741  }
743  int h = lv->menu_lines;
744  if ( !( lv->fixed_num_lines ) ) {
745  if ( lv->dynamic ) {
746  h = MIN ( lv->menu_lines, lv->req_elements );
747  }
748  else {
749  h = MIN ( lv->menu_lines, lv->max_displayed_lines );
750  }
751  }
752  if ( lv->type == BARVIEW ) {
753  h = MIN ( h, 1 );
754  }
755  if ( h == 0 ) {
756  if ( lv->dynamic && !lv->fixed_num_lines ) {
757  // Hide widget fully.
758  return 0;
759  }
760  return widget_padding_get_padding_height ( WIDGET ( lv ) );
761  }
762  int height = widget_padding_get_padding_height ( WIDGET ( lv ) );
763  height += h * ( lv->element_height + spacing ) - spacing;
764  return height;
765 }
766 
767 void listview_set_show_scrollbar ( listview *lv, gboolean enabled )
768 {
769  if ( lv ) {
770  if ( enabled ) {
771  widget_enable ( WIDGET ( lv->scrollbar ) );
772  }
773  else {
774  widget_disable ( WIDGET ( lv->scrollbar ) );
775  }
777  }
778 }
779 
781 {
782  if ( lv ) {
783  lv->scroll_type = type;
784  }
785 }
786 
788 {
789  if ( lv ) {
790  lv->mouse_activated = cb;
791  lv->mouse_activated_data = udata;
792  }
793 }
794 void listview_set_multi_select ( listview *lv, gboolean enable )
795 {
796  if ( lv ) {
797  lv->multi_select = enable;
798  }
799 }
800 void listview_set_num_lines ( listview *lv, unsigned int num_lines )
801 {
802  if ( lv ) {
803  lv->menu_lines = num_lines;
804  }
805 }
806 
807 unsigned int listview_get_num_lines ( listview *lv )
808 {
809  if ( lv ) {
810  return lv->menu_lines;
811  }
812  return 0;
813 }
814 void listview_set_max_lines ( listview *lv, unsigned int max_lines )
815 {
816  if ( lv ) {
817  lv->max_displayed_lines = max_lines;
818  }
819 }
820 
822 {
823  if ( lv ) {
824  return lv->fixed_num_lines;
825  }
826  return FALSE;
827 }
829 {
830  if ( lv ) {
831  lv->fixed_num_lines = TRUE;
832  }
833 }
gboolean cycle
Definition: listview.c:94
void listview_set_selected(listview *lv, unsigned int selected)
Definition: listview.c:410
char * listview_name
Definition: listview.c:111
static unsigned int scroll_continious(listview *lv)
Definition: listview.c:174
unsigned int menu_columns
Definition: listview.c:89
unsigned int cycle
Definition: settings.h:126
WidgetType
Definition: widget.h:56
textbox ** boxes
Definition: listview.c:99
int widget_padding_get_bottom(const widget *wid)
Definition: widget.c:527
listview_update_callback callback
Definition: listview.c:102
unsigned int max_rows
Definition: listview.c:78
MoveDirection
Definition: listview.c:55
widget_find_mouse_target_cb find_mouse_target
listview * listview_create(widget *parent, const char *name, listview_update_callback cb, void *udata, unsigned int eh, gboolean reverse)
Definition: listview.c:523
static void listview_resize(widget *wid, short w, short h)
Definition: listview.c:419
unsigned int selected
Definition: listview.c:74
unsigned int menu_lines
Definition: listview.c:87
static WidgetTriggerActionResult listview_element_trigger_action(widget *wid, MouseBindingListviewElementAction action, gint x, gint y, void *user_data)
unsigned int cur_elements
Definition: listview.c:84
void listview_nav_up(listview *lv)
Definition: listview.c:596
void listview_nav_page_prev(listview *lv)
Definition: listview.c:711
void(* listview_update_callback)(textbox *tb, unsigned int entry, void *udata, TextBoxFontType type, gboolean full)
Definition: listview.h:64
unsigned int listview_get_num_lines(listview *lv)
Definition: listview.c:807
unsigned int menu_columns
Definition: settings.h:67
static void update_element(listview *lv, unsigned int tb, unsigned int index, gboolean full)
Definition: listview.c:195
void listview_set_num_elements(listview *lv, unsigned int rows)
Definition: listview.c:391
int widget_padding_get_padding_width(const widget *wid)
Definition: widget.c:559
unsigned int max_elements
Definition: listview.c:79
void(* resize)(struct _widget *, short, short)
unsigned int cur_visible
Definition: listview.c:117
MoveDirection direction
Definition: listview.c:116
int widget_padding_get_top(const widget *wid)
Definition: widget.c:517
xcb_timestamp_t last_click
Definition: listview.c:107
unsigned int dynamic
Definition: listview.c:91
void listview_set_scroll_type(listview *lv, ScrollType type)
Definition: listview.c:780
int widget_get_width(widget *widget)
Definition: widget.c:388
void widget_free(widget *wid)
Definition: widget.c:365
static void listview_free(widget *wid)
Definition: listview.c:123
unsigned int rchanged
Definition: listview.c:69
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition: theme.c:572
MouseBindingListviewAction
Definition: keyb.h:145
void widget_set_trigger_action_handler(widget *wid, widget_trigger_action_cb cb, void *cb_data)
Definition: widget.c:479
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition: theme.c:550
void(* draw)(struct _widget *widget, cairo_t *draw)
ScrollType
Definition: listview.h:47
void widget_draw(widget *widget, cairo_t *d)
Definition: widget.c:142
textbox * textbox_create(widget *parent, WidgetType type, const char *name, TextboxFlags flags, TextBoxFontType tbft, const char *text, double xalign, double yalign)
Definition: textbox.c:166
unsigned int eh
Definition: listview.c:92
void widget_disable(widget *widget)
Definition: widget.c:133
int widget_intersect(const widget *widget, int x, int y)
Definition: widget.c:70
scrollbar * scrollbar_create(widget *parent, const char *name)
Definition: scrollbar.c:102
void scrollbar_set_handle(scrollbar *sb, unsigned int pos)
Definition: scrollbar.c:139
void listview_nav_right(listview *lv)
Definition: listview.c:635
ViewType type
Definition: listview.c:65
void listview_set_show_scrollbar(listview *lv, gboolean enabled)
Definition: listview.c:767
MouseBindingListviewElementAction
Definition: keyb.h:156
void listview_set_mouse_activated_cb(listview *lv, listview_mouse_activated_cb cb, void *udata)
Definition: listview.c:787
void listview_set_num_lines(listview *lv, unsigned int num_lines)
Definition: listview.c:800
Definition: textbox.h:107
scrollbar * scrollbar
Definition: listview.c:100
gboolean enabled
void widget_move(widget *widget, short x, short y)
Definition: widget.c:100
TextboxFlags
Definition: textbox.h:79
#define DEFAULT_SPACING
Definition: listview.c:39
unsigned int cur_page
Definition: listview.c:72
void * udata
Definition: listview.c:103
void widget_resize(widget *widget, short w, short h)
Definition: widget.c:84
static void listview_recompute_elements(listview *lv)
Definition: listview.c:361
widget_trigger_action_cb trigger_action
static widget * listview_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: listview.c:449
static void listview_nav_page_next_int(listview *lv)
Definition: listview.c:688
void widget_queue_redraw(widget *wid)
Definition: widget.c:432
gboolean widget_enabled(widget *widget)
Definition: widget.c:116
void scrollbar_set_handle_length(scrollbar *sb, unsigned int pos_length)
Definition: scrollbar.c:146
unsigned int element_height
Definition: listview.c:76
unsigned int listview_get_selected(listview *lv)
Definition: listview.c:402
void(* listview_mouse_activated_cb)(listview *, gboolean, void *)
Definition: listview.h:69
unsigned int req_elements
Definition: listview.c:83
struct _listview::@1 barview
TextBoxFontType
Definition: textbox.h:93
unsigned int element_width
Definition: listview.c:77
unsigned int reverse
Definition: listview.c:93
Definition: textbox.h:96
void listview_set_multi_select(listview *lv, gboolean enable)
Definition: listview.c:794
static int listview_get_desired_height(widget *wid)
Definition: listview.c:736
static void listview_nav_page_prev_int(listview *lv)
Definition: listview.c:663
void textbox_moveresize(textbox *tb, int x, int y, int w, int h)
Definition: textbox.c:352
static void _listview_draw(widget *wid, cairo_t *draw)
Definition: listview.c:351
void listview_set_fixed_num_lines(listview *lv)
Definition: listview.c:828
static unsigned int scroll_per_page_barview(listview *lv)
Definition: listview.c:135
MenuFlags flags
Definition: view.c:108
void(* free)(struct _widget *widget)
static WidgetTriggerActionResult listview_trigger_action(widget *wid, MouseBindingListviewAction action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data)
Definition: listview.c:474
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition: theme.c:736
static void barview_draw(widget *wid, cairo_t *draw)
Definition: listview.c:206
RofiDistance spacing
Definition: listview.c:86
ViewType
Definition: listview.c:44
ScrollType scroll_type
Definition: listview.c:97
WidgetTriggerActionResult
Definition: widget.h:77
void listview_nav_page_next(listview *lv)
Definition: listview.c:723
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition: theme.c:588
void widget_enable(widget *widget)
Definition: widget.c:124
static void listview_draw(widget *wid, cairo_t *draw)
Definition: listview.c:283
unsigned int max_displayed_lines
Definition: listview.c:88
listview_mouse_activated_cb mouse_activated
Definition: listview.c:108
widget widget
Definition: listview.c:63
void * mouse_activated_data
Definition: listview.c:109
#define WIDGET(a)
Definition: widget.h:115
gboolean show_icons
Definition: settings.h:78
int widget_padding_get_right(const widget *wid)
Definition: widget.c:507
unsigned int cur_columns
Definition: listview.c:82
void scrollbar_set_max_value(scrollbar *sb, unsigned int max)
Definition: scrollbar.c:132
int widget_get_x_pos(widget *widget)
Definition: widget.c:398
void widget_init(widget *wid, widget *parent, WidgetType type, const char *name)
Definition: widget.c:37
static void listview_nav_down_int(listview *lv)
Definition: listview.c:583
void listview_set_max_lines(listview *lv, unsigned int max_lines)
Definition: listview.c:814
Settings config
int textbox_get_estimated_height(const textbox *tb, int eh)
Definition: textbox.c:927
unsigned int fixed_num_lines
Definition: listview.c:90
int(* get_desired_height)(struct _widget *)
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition: widget.c:453
int widget_padding_get_padding_height(const widget *wid)
Definition: widget.c:552
gboolean listview_get_fixed_num_lines(listview *lv)
Definition: listview.c:821
void listview_nav_left(listview *lv)
Definition: listview.c:621
int textbox_get_desired_width(widget *wid)
Definition: textbox.c:932
unsigned int fixed_num_lines
Definition: settings.h:108
void listview_nav_down(listview *lv)
Definition: listview.c:608
gboolean scrollbar_scroll
Definition: listview.c:105
int rofi_theme_get_integer(const widget *widget, const char *property, int def)
Definition: theme.c:534
static unsigned int scroll_per_page(listview *lv)
Definition: listview.c:151
gboolean multi_select
Definition: listview.c:95
unsigned int last_offset
Definition: listview.c:73
int widget_get_y_pos(widget *widget)
Definition: widget.c:405
static void listview_nav_up_int(listview *lv)
Definition: listview.c:568
int widget_padding_get_left(const widget *wid)
Definition: widget.c:497