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