rofi 1.7.5
listview.c
Go to the documentation of this file.
1/*
2 * rofi
3 *
4 * MIT/X11 License
5 * Copyright © 2013-2022 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/box.h>
31#include <widgets/icon.h>
32#include <widgets/listview.h>
33#include <widgets/scrollbar.h>
34#include <widgets/textbox.h>
35#include <widgets/widget.h>
36
37#include "settings.h"
38#include "theme.h"
39
40#include "timings.h"
41
43#define DEFAULT_SPACING 2
44
49#define LISTVIEW ROFI_ORIENTATION_VERTICAL
51#define BARVIEW ROFI_ORIENTATION_HORIZONTAL
52
57typedef enum { LEFT_TO_RIGHT = 0, RIGHT_TO_LEFT = 1 } MoveDirection;
58
65
66struct _listview {
68
70
71 // RChanged
72 // Text needs to be repainted.
73 unsigned int rchanged;
74
75 // The direction we pack the widgets.
77 // Administration
78
79 unsigned int cur_page;
80 unsigned int last_offset;
81 unsigned int selected;
82
83 unsigned int element_height;
84 unsigned int max_rows;
85 unsigned int max_elements;
86
87 //
88 gboolean fixed_columns;
89 unsigned int cur_columns;
90 unsigned int req_elements;
91 unsigned int cur_elements;
92
94 unsigned int menu_lines;
95 unsigned int max_displayed_lines;
96 unsigned int menu_columns;
97 unsigned int fixed_num_lines;
98 unsigned int dynamic;
99 unsigned int eh;
100 unsigned int reverse;
102 gboolean filtered;
103
104 gboolean cycle;
105
107
110
112 void *udata;
113
115 void *sc_udata;
116
118
119 xcb_timestamp_t last_click;
122
124
125 PangoEllipsizeMode emode;
127 struct {
129 unsigned int cur_visible;
131};
137const char *const listview_theme_prop_names[][3] = {
139 {"normal.normal", "selected.normal", "alternate.normal"},
141 {"normal.urgent", "selected.urgent", "alternate.urgent"},
143 {"normal.active", "selected.active", "alternate.active"},
144};
145
147 widget *w = WIDGET(r.box);
148 TextBoxFontType t = tbft & STATE_MASK;
149 if (w == NULL) {
150 return;
151 }
152 // ACTIVE has priority over URGENT if both set.
153 if (t == (URGENT | ACTIVE)) {
154 t = ACTIVE;
155 }
156 switch ((tbft & FMOD_MASK)) {
157 case HIGHLIGHT:
159 break;
160 case ALT:
162 break;
163 default:
165 break;
166 }
167}
169 const char *label) {
171 if (strcasecmp(label, "element-icon") == 0) {
172 row->icon = icon_create(WIDGET(wid), "element-icon");
173 box_add((box *)wid, WIDGET(row->icon), FALSE);
174 } else if (strcasecmp(label, "element-text") == 0) {
175 row->textbox =
176 textbox_create(WIDGET(wid), WIDGET_TYPE_TEXTBOX_TEXT, "element-text",
177 TB_AUTOHEIGHT | flags, NORMAL, "DDD", 0, 0);
178 box_add((box *)wid, WIDGET(row->textbox), TRUE);
179 } else if (strcasecmp(label, "element-index") == 0) {
180 row->index =
181 textbox_create(WIDGET(wid), WIDGET_TYPE_TEXTBOX_TEXT, "element-index",
182 TB_AUTOHEIGHT, NORMAL, " ", 0, 0);
183 box_add((box *)wid, WIDGET(row->index), FALSE);
184 } else {
185 widget *wid2 = (widget *)box_create(wid, label, ROFI_ORIENTATION_VERTICAL);
186 box_add((box *)wid, WIDGET(wid2), TRUE);
187 GList *list = rofi_theme_get_list_strings(
188 WIDGET(wid2),
189 "children"); // rofi_theme_get_list(WIDGET(wid2), "children", "");
190 for (GList *iter = g_list_first(list); iter != NULL;
191 iter = g_list_next(iter)) {
192 listview_add_widget(lv, row, wid2, (const char *)iter->data);
193 }
194 }
195}
196
198 row->box = box_create(WIDGET(lv), "element", ROFI_ORIENTATION_HORIZONTAL);
200 GList *list = NULL;
201 list = rofi_theme_get_list_strings(WIDGET(row->box), "children");
202 if (list == NULL) {
203 if (config.show_icons) {
204 list = g_list_append(list, g_strdup("element-icon"));
205 list = g_list_append(list, g_strdup("element-text"));
206 } else {
207 list = g_list_append(list, g_strdup("element-text"));
208 }
209 }
210
211 row->textbox = NULL;
212 row->icon = NULL;
213 row->index = NULL;
214
215 for (GList *iter = g_list_first(list); iter != NULL;
216 iter = g_list_next(iter)) {
217 listview_add_widget(lv, row, WIDGET(row->box), (const char *)iter->data);
218 }
219 g_list_free_full(list, g_free);
220}
221
222static int listview_get_desired_height(widget *wid, const int width);
223
224static void listview_free(widget *wid) {
225 listview *lv = (listview *)wid;
226 for (unsigned int i = 0; i < lv->cur_elements; i++) {
227 widget_free(WIDGET(lv->boxes[i].box));
228 }
229 g_free(lv->boxes);
230
231 g_free(lv->listview_name);
233 g_free(lv);
234}
235static unsigned int scroll_per_page_barview(listview *lv) {
236 unsigned int offset = lv->last_offset;
237
238 // selected row is always visible.
239 // If selected is visible do not scroll.
240 if (lv->selected < lv->last_offset) {
241 offset = lv->selected;
242 lv->rchanged = TRUE;
243 } else if (lv->selected >= (lv->last_offset + lv->barview.cur_visible)) {
244 offset = lv->selected;
245 lv->rchanged = TRUE;
246 }
247 return offset;
248}
249static unsigned int scroll_per_page(listview *lv) {
250 int offset = 0;
251
252 // selected row is always visible.
253 // If selected is visible do not scroll.
254 if (((lv->selected - (lv->last_offset)) < (lv->max_elements)) &&
255 (lv->selected >= (lv->last_offset))) {
256 offset = lv->last_offset;
257 } else {
258 // Do paginating
259 unsigned int page =
260 (lv->max_elements > 0) ? (lv->selected / lv->max_elements) : 0;
261 offset = page * lv->max_elements;
262 if (page != lv->cur_page) {
263 lv->cur_page = page;
264 lv->rchanged = TRUE;
265 }
266 // Set the position
267 // scrollbar_set_handle ( lv->scrollbar, page * lv->max_elements );
268 }
269 return offset;
270}
271
272static unsigned int scroll_continious(listview *lv) {
273 unsigned int middle = (lv->max_rows - ((lv->max_rows & 1) == 0)) / 2;
274 unsigned int offset = 0;
275 if (lv->selected > middle) {
276 if (lv->selected < (lv->req_elements - (lv->max_rows - middle))) {
277 offset = lv->selected - middle;
278 }
279 // Don't go below zero.
280 else if (lv->req_elements > lv->max_rows) {
281 offset = lv->req_elements - lv->max_rows;
282 }
283 }
284 if (offset != lv->cur_page) {
285 // scrollbar_set_handle ( lv->scrollbar, offset );
286 lv->cur_page = offset;
287 lv->rchanged = TRUE;
288 }
289 return offset;
290}
291
292static void update_element(listview *lv, unsigned int tb, unsigned int index,
293 gboolean full) {
294 // Select drawing mode
295 TextBoxFontType type = (index & 1) == 0 ? NORMAL : ALT;
296 type = (index) == lv->selected ? HIGHLIGHT : type;
297
298 if (lv->boxes[tb].index) {
299 if (index < 10) {
300 char str[2] = {((index + 1) % 10) + '0', '\0'};
301 textbox_text(lv->boxes[tb].index, str);
302 } else {
303 textbox_text(lv->boxes[tb].index, " ");
304 }
305 }
306 if (lv->callback) {
307 lv->callback(lv->boxes[tb].textbox, lv->boxes[tb].icon, index, lv->udata,
308 &type, full);
309 listview_set_state(lv->boxes[tb], type);
310 }
311}
312
313static void barview_draw(widget *wid, cairo_t *draw) {
314 unsigned int offset = 0;
315 listview *lv = (listview *)wid;
316 offset = scroll_per_page_barview(lv);
317 lv->last_offset = offset;
318 int spacing_hori =
320
321 int left_offset = widget_padding_get_left(wid);
322 int right_offset = lv->widget.w - widget_padding_get_right(wid);
323 int top_offset = widget_padding_get_top(wid);
324 if (lv->cur_elements > 0) {
325 // Set new x/y position.
326 unsigned int max = MIN(lv->cur_elements, lv->req_elements - offset);
327 if (lv->rchanged) {
328 int first = TRUE;
329 int width = lv->widget.w;
330 lv->barview.cur_visible = 0;
332 if (lv->barview.direction == LEFT_TO_RIGHT) {
333 for (unsigned int i = 0; i < max && width > 0; i++) {
334 update_element(lv, i, i + offset, TRUE);
335 int twidth = widget_get_desired_width(WIDGET(lv->boxes[i].box),
336 lv->element_height);
337 if (twidth >= width) {
338 if (!first) {
339 break;
340 }
341 twidth = width;
342 }
343 widget_move(WIDGET(lv->boxes[i].box), left_offset, top_offset);
344 widget_resize(WIDGET(lv->boxes[i].box), twidth, lv->element_height);
345
346 widget_draw(WIDGET(lv->boxes[i].box), draw);
347 width -= twidth + spacing_hori;
348 left_offset += twidth + spacing_hori;
349 first = FALSE;
350 lv->barview.cur_visible++;
351 }
352 } else {
353 for (unsigned int i = 0;
354 i < lv->cur_elements && width > 0 && i <= offset; i++) {
355 update_element(lv, i, offset - i, TRUE);
356 int twidth = widget_get_desired_width(WIDGET(lv->boxes[i].box),
357 lv->element_height);
358 if (twidth >= width) {
359 if (!first) {
360 break;
361 }
362 twidth = width;
363 }
364 right_offset -= twidth;
365 widget_move(WIDGET(lv->boxes[i].box), right_offset, top_offset);
366 widget_resize(WIDGET(lv->boxes[i].box), twidth, lv->element_height);
367
368 widget_draw(WIDGET(lv->boxes[i].box), draw);
369 width -= twidth + spacing_hori;
370 right_offset -= spacing_hori;
371 first = FALSE;
372 lv->barview.cur_visible++;
373 }
374 offset -= lv->barview.cur_visible - 1;
375 lv->last_offset = offset;
376 for (unsigned int i = 0; i < (lv->barview.cur_visible / 2); i++) {
377 _listview_row temp = lv->boxes[i];
378 int sw = lv->barview.cur_visible - i - 1;
379 lv->boxes[i] = lv->boxes[sw];
380 lv->boxes[sw] = temp;
381 }
382 }
383 lv->rchanged = FALSE;
384 } else {
385 for (unsigned int i = 0; i < lv->barview.cur_visible; i++) {
386 update_element(lv, i, i + offset, TRUE);
387 widget_draw(WIDGET(lv->boxes[i].box), draw);
388 }
389 }
390 }
391}
392
393static void listview_draw(widget *wid, cairo_t *draw) {
394 unsigned int offset = 0;
395 listview *lv = (listview *)wid;
397 offset = scroll_continious(lv);
398 } else {
399 offset = scroll_per_page(lv);
400 }
401 // Set these all together to make sure they update consistently.
404 if (lv->reverse) {
406 } else {
408 }
409 lv->last_offset = offset;
411 int spacing_hori =
413
414 int left_offset = widget_padding_get_left(wid);
415 int top_offset = widget_padding_get_top(wid);
416 /*
417 if ( lv->scrollbar->widget.index == 0 ) {
418 left_offset += spacing_hori + lv->scrollbar->widget.w;
419 }
420 */
421 if (lv->cur_elements > 0 && lv->max_rows > 0) {
422 // Set new x/y position.
423 unsigned int max = MIN(lv->cur_elements, lv->req_elements - offset);
424 if (lv->rchanged) {
425 unsigned int width = lv->widget.w;
427 if (widget_enabled(WIDGET(lv->scrollbar))) {
428 width -= spacing_hori;
429 width -= widget_get_width(WIDGET(lv->scrollbar));
430 }
431 unsigned int element_width =
432 (width - spacing_hori * (lv->cur_columns - 1)) / lv->cur_columns;
433
434 int d = width - (element_width + spacing_hori) * (lv->cur_columns - 1) -
435 element_width;
436 if (lv->cur_columns > 1) {
437 int diff = d / (lv->cur_columns - 1);
438 if (diff >= 1) {
439 spacing_hori += 1;
440 d -= lv->cur_columns - 1;
441 }
442 }
443 for (unsigned int i = 0; i < max; i++) {
445 unsigned int ex = left_offset + ((i) % lv->cur_columns) *
446 (element_width + spacing_hori);
447 unsigned int ey = 0;
448 if (lv->reverse) {
449 ey = wid->h -
451 ((i) / lv->cur_columns) *
452 (lv->element_height + spacing_vert)) -
453 lv->element_height;
454
455 if ((i) / lv->cur_columns == (lv->cur_columns - 1)) {
456 ex += d;
457 }
458 } else {
459 ey = top_offset +
460 ((i) / lv->cur_columns) * (lv->element_height + spacing_vert);
461
462 if ((i) / lv->cur_columns == (lv->cur_columns - 1)) {
463 ex += d;
464 }
465 }
466 widget_move(WIDGET(lv->boxes[i].box), ex, ey);
467 widget_resize(WIDGET(lv->boxes[i].box), element_width,
468 lv->element_height);
469
470 } else {
471 unsigned int ex = left_offset + ((i) / lv->max_rows) *
472 (element_width + spacing_hori);
473
474 if ((i) / lv->max_rows == (lv->cur_columns - 1)) {
475 ex += d;
476 }
477 unsigned int ey = 0;
478 if (lv->reverse) {
479 ey = wid->h -
481 ((i) % lv->max_rows) * (lv->element_height + spacing_vert)) -
482 lv->element_height;
483 } else {
484 ey = top_offset +
485 ((i) % lv->max_rows) * (lv->element_height + spacing_vert);
486 }
487 widget_move(WIDGET(lv->boxes[i].box), ex, ey);
488 widget_resize(WIDGET(lv->boxes[i].box), element_width,
489 lv->element_height);
490 }
491 update_element(lv, i, i + offset, TRUE);
492 widget_draw(WIDGET(lv->boxes[i].box), draw);
493 }
494 lv->rchanged = FALSE;
495 } else {
496 for (unsigned int i = 0; i < max; i++) {
497 update_element(lv, i, i + offset, TRUE);
498 widget_draw(WIDGET(lv->boxes[i].box), draw);
499 }
500 }
501 }
502 widget_draw(WIDGET(lv->scrollbar), draw);
503}
507 gint x, gint y, void *user_data);
508static gboolean listview_element_motion_notify(widget *wid, gint x, gint y);
509
510static void _listview_draw(widget *wid, cairo_t *draw) {
511 listview *lv = (listview *)wid;
512 if (lv->type == LISTVIEW) {
513 listview_draw(wid, draw);
514 } else {
515 barview_draw(wid, draw);
516 }
517}
522 unsigned int newne = 0;
523 if (lv->max_rows == 0) {
524 return;
525 }
526 if (!(lv->fixed_columns) && lv->req_elements < lv->max_elements) {
527 newne = lv->req_elements;
529 lv->cur_columns = (lv->req_elements + (lv->max_rows - 1)) / lv->max_rows;
530 } else {
531 lv->cur_columns = lv->menu_columns;
532 if (lv->req_elements < lv->menu_columns) {
533 lv->cur_columns = lv->req_elements;
534 }
535 }
536 } else {
537 newne = MIN(lv->req_elements, lv->max_elements);
538 lv->cur_columns = lv->menu_columns;
539 }
540 for (unsigned int i = newne; i < lv->cur_elements; i++) {
541 widget_free(WIDGET(lv->boxes[i].box));
542 }
543 lv->boxes = g_realloc(lv->boxes, newne * sizeof(_listview_row));
544 if (newne > 0) {
545 for (unsigned int i = lv->cur_elements; i < newne; i++) {
546 listview_create_row(lv, &(lv->boxes[i]));
547 widget *wid = WIDGET(lv->boxes[i].box);
549 lv);
550 if (wid != NULL) {
552 }
553
555 }
556 }
557 lv->rchanged = TRUE;
558 lv->cur_elements = newne;
559}
560
561void listview_set_num_elements(listview *lv, unsigned int rows) {
562 if (lv == NULL) {
563 return;
564 }
565 TICK_N("listview_set_num_elements");
566 lv->req_elements = rows;
567 if (lv->require_input && !lv->filtered) {
568 lv->req_elements = 0;
569 }
571 TICK_N("Set selected");
573 TICK_N("recompute elements");
575 TICK_N("queue redraw");
576}
577
579 if (lv != NULL) {
580 return lv->selected;
581 }
582 return 0;
583}
584
585void listview_set_selected(listview *lv, unsigned int selected) {
586 if (lv && lv->req_elements > 0) {
587 lv->selected = MIN(selected, lv->req_elements - 1);
590 lv->sc_callback(lv, lv->selected, lv->sc_udata);
591 } else if (lv->req_elements == 0) {
592 lv->sc_callback(lv, UINT32_MAX, lv->sc_udata);
593 }
594}
595
596static void listview_resize(widget *wid, short w, short h) {
597 listview *lv = (listview *)wid;
598 lv->widget.w = MAX(0, w);
599 lv->widget.h = MAX(0, h);
600 int height = lv->widget.h - widget_padding_get_padding_height(WIDGET(lv));
602 lv->max_rows = (spacing_vert + height) / (lv->element_height + spacing_vert);
603 lv->max_elements = lv->max_rows * lv->menu_columns;
604
609
611 height);
612
613 if (lv->type == BARVIEW) {
614 lv->max_elements = lv->menu_lines;
615 }
616
619}
620
622 gint y) {
623 widget *target = NULL;
624 gint rx, ry;
625 listview *lv = (listview *)wid;
626 if (widget_enabled(WIDGET(lv->scrollbar)) &&
627 widget_intersect(WIDGET(lv->scrollbar), x, y)) {
628 rx = x - widget_get_x_pos(WIDGET(lv->scrollbar));
629 ry = y - widget_get_y_pos(WIDGET(lv->scrollbar));
630 target = widget_find_mouse_target(WIDGET(lv->scrollbar), type, rx, ry);
631 }
632
633 unsigned int max = MIN(lv->cur_elements, lv->req_elements - lv->last_offset);
634 unsigned int i;
635 for (i = 0; i < max && target == NULL; i++) {
636 widget *w = WIDGET(lv->boxes[i].box);
637 if (widget_intersect(w, x, y)) {
638 rx = x - widget_get_x_pos(w);
639 ry = y - widget_get_y_pos(w);
640 target = widget_find_mouse_target(w, type, rx, ry);
641 }
642 }
643
644 return target;
645}
646
649 G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y,
650 G_GNUC_UNUSED void *user_data) {
651 listview *lv = (listview *)wid;
652 switch (action) {
653 case SCROLL_LEFT:
655 break;
656 case SCROLL_RIGHT:
658 break;
659 case SCROLL_DOWN:
661 break;
662 case SCROLL_UP:
663 listview_nav_up(lv);
664 break;
665 }
667}
668
670 widget *wid, MouseBindingListviewElementAction action, G_GNUC_UNUSED gint x,
671 G_GNUC_UNUSED gint y, void *user_data) {
672 listview *lv = (listview *)user_data;
673 unsigned int max = MIN(lv->cur_elements, lv->req_elements - lv->last_offset);
674 unsigned int i;
675 for (i = 0; i < max && WIDGET(lv->boxes[i].box) != wid; i++) {
676 }
677 if (i == max) {
679 }
680
681 gboolean custom = FALSE;
682 switch (action) {
685 break;
687 custom = TRUE;
688 /* FALLTHRU */
691 lv->mouse_activated(lv, custom, lv->mouse_activated_data);
692 break;
693 }
695}
696
698 G_GNUC_UNUSED gint x,
699 G_GNUC_UNUSED gint y) {
700 listview *lv = (listview *)wid->parent;
701 unsigned int max = MIN(lv->cur_elements, lv->req_elements - lv->last_offset);
702 unsigned int i;
703 for (i = 0; i < max && WIDGET(lv->boxes[i].box) != wid; i++) {
704 }
705 if (i < max && (lv->last_offset + i) != listview_get_selected(lv)) {
707 }
708 return TRUE;
709}
710
711listview *listview_create(widget *parent, const char *name,
712 listview_update_callback cb, void *udata,
713 unsigned int eh, gboolean reverse) {
714 listview *lv = g_malloc0(sizeof(listview));
715 widget_init(WIDGET(lv), parent, WIDGET_TYPE_LISTVIEW, name);
716 lv->listview_name = g_strdup(name);
723 lv->eh = eh;
724
725 lv->emode = PANGO_ELLIPSIZE_END;
726 lv->scrollbar = scrollbar_create(WIDGET(lv), "scrollbar");
727 // Calculate height of an element.
728 //
729 _listview_row row;
730 listview_create_row(lv, &row);
731 // FIXME: hack to scale hight correctly.
732 if (lv->eh > 1 && row.textbox) {
733 char buff[lv->eh * 2 + 1];
734 memset(buff, '\0', lv->eh * 2 + 1);
735 for (unsigned int i = 0; i < (lv->eh - 1); i++) {
736 buff[i * 2] = 'a';
737 buff[i * 2 + 1] = '\n';
738 };
739 textbox_moveresize(row.textbox, 0, 0, 100000000, -1);
740 textbox_text(row.textbox, buff);
741 }
742 // Make textbox very wide.
744 widget_free(WIDGET(row.box));
745
746 lv->callback = cb;
747 lv->udata = udata;
748
749 // Some settings.
751 lv->menu_columns =
753 lv->fixed_num_lines = rofi_theme_get_boolean(WIDGET(lv), "fixed-height",
755 lv->dynamic = rofi_theme_get_boolean(WIDGET(lv), "dynamic", TRUE);
756 lv->reverse = rofi_theme_get_boolean(WIDGET(lv), "reverse", reverse);
757 lv->pack_direction =
759 lv->cycle = rofi_theme_get_boolean(WIDGET(lv), "cycle", config.cycle);
760 lv->fixed_columns =
761 rofi_theme_get_boolean(WIDGET(lv), "fixed-columns", FALSE);
762
763 lv->require_input =
764 rofi_theme_get_boolean(WIDGET(lv), "require-input", FALSE);
765 lv->type = rofi_theme_get_orientation(WIDGET(lv), "layout",
767 if (lv->type == LISTVIEW) {
769 lv, rofi_theme_get_boolean(WIDGET(lv), "scrollbar", FALSE));
770 } else {
772 }
773 return lv;
774}
775
781 if (lv == NULL) {
782 return;
783 }
784 if (lv->req_elements == 0 || (lv->selected == 0 && !lv->cycle)) {
785 return;
786 }
787 if (lv->selected == 0) {
788 lv->selected = lv->req_elements;
789 }
790 lv->selected--;
792
793 lv->sc_callback(lv, lv->selected, lv->sc_udata);
795}
797 if (lv == NULL) {
798 return;
799 }
800 if (lv->req_elements == 0 ||
801 (lv->selected == (lv->req_elements - 1) && !lv->cycle)) {
802 return;
803 }
804 lv->selected = lv->selected < lv->req_elements - 1
805 ? MIN(lv->req_elements - 1, lv->selected + 1)
806 : 0;
808 lv->sc_callback(lv, lv->selected, lv->sc_udata);
810}
812 if (lv == NULL) {
813 return;
814 }
816}
818 if (lv == NULL) {
819 return;
820 }
822}
823
825 if (lv->selected >= lv->cur_columns) {
826 lv->selected -= lv->cur_columns;
827 lv->sc_callback(lv, lv->selected, lv->sc_udata);
829 }
830}
832 if ((lv->selected + lv->cur_columns) < lv->req_elements) {
833 lv->selected += lv->cur_columns;
834 lv->sc_callback(lv, lv->selected, lv->sc_udata);
836 }
837}
838
840 if (lv == NULL) {
841 return;
842 }
844 if (lv->reverse) {
846 } else {
848 }
849 return;
850 }
851 if (lv->reverse) {
853 } else {
855 }
856}
858 if (lv == NULL) {
859 return;
860 }
862 if (lv->reverse) {
864 } else {
866 }
867 return;
868 }
869 if (lv->reverse) {
871 } else {
873 }
874}
875
877 if (lv == NULL) {
878 return;
879 }
880 if (lv->max_rows == 0) {
881 return;
882 }
885 return;
886 }
887 if (lv->type == BARVIEW) {
889 return;
890 }
891 if (lv->selected >= lv->max_rows) {
892 lv->selected -= lv->max_rows;
893 lv->sc_callback(lv, lv->selected, lv->sc_udata);
895 }
896}
898 if (lv == NULL) {
899 return;
900 }
901 if (lv->max_rows == 0) {
902 return;
903 }
906 return;
907 }
908 if (lv->type == BARVIEW) {
910 return;
911 }
912 if ((lv->selected + lv->max_rows) < lv->req_elements) {
913 lv->selected += lv->max_rows;
914 lv->sc_callback(lv, lv->selected, lv->sc_udata);
916 } else if (lv->selected < (lv->req_elements - 1)) {
917 // We do not want to move to last item, UNLESS the last column is only
918 // partially filled, then we still want to move column and select last
919 // entry. First check the column we are currently in.
920 int col = lv->selected / lv->max_rows;
921 // Check total number of columns.
922 int ncol = lv->req_elements / lv->max_rows;
923 // If there is an extra column, move.
924 if (col != ncol) {
925 lv->selected = lv->req_elements - 1;
926 lv->sc_callback(lv, lv->selected, lv->sc_udata);
928 }
929 }
930}
931
933 if (lv == NULL) {
934 return;
935 }
936 if (lv->type == BARVIEW) {
937 if (lv->last_offset == 0) {
938 lv->selected = 0;
939 } else {
940 lv->selected = lv->last_offset - 1;
941 }
944 return;
945 }
946
947 if (lv->selected < lv->max_elements) {
948 lv->selected = 0;
949 } else {
950 lv->selected -= (lv->max_elements);
951 }
952 lv->sc_callback(lv, lv->selected, lv->sc_udata);
954}
956 if (lv == NULL) {
957 return;
958 }
959 if (lv->req_elements == 0) {
960 return;
961 }
962 if (lv->type == BARVIEW) {
963 unsigned int new = lv->last_offset + lv->barview.cur_visible;
964 lv->selected = MIN(new, lv->req_elements - 1);
966
967 lv->sc_callback(lv, lv->selected, lv->sc_udata);
969 return;
970 }
971 lv->selected += (lv->max_elements);
972 if (lv->selected >= lv->req_elements) {
973 lv->selected = lv->req_elements - 1;
974 }
975 lv->sc_callback(lv, lv->selected, lv->sc_udata);
977}
978
980 if (lv == NULL) {
981 return;
982 }
983 if (lv->reverse) {
985 } else {
987 }
988}
990 if (lv == NULL) {
991 return;
992 }
993 if (lv->reverse) {
995 } else {
997 }
998}
999
1001 G_GNUC_UNUSED const int width) {
1002 listview *lv = (listview *)wid;
1003 if (lv == NULL || lv->widget.enabled == FALSE) {
1004 return 0;
1005 }
1007 int h = lv->menu_lines;
1008 if (!(lv->fixed_num_lines)) {
1009 if (lv->dynamic) {
1010 h = MIN(lv->menu_lines, lv->req_elements);
1011 } else {
1012 h = MIN(lv->menu_lines, lv->max_displayed_lines);
1013 }
1014 }
1015 if (lv->type == BARVIEW) {
1016 h = MIN(h, 1);
1017 }
1018 if (h == 0) {
1019 if (lv->dynamic && !lv->fixed_num_lines) {
1020 // Hide widget fully.
1021 return 0;
1022 }
1024 }
1025 int height = widget_padding_get_padding_height(WIDGET(lv));
1026 height += h * (lv->element_height + spacing) - spacing;
1027 return height;
1028}
1029
1030void listview_set_show_scrollbar(listview *lv, gboolean enabled) {
1031 if (lv) {
1032 if (enabled) {
1034 } else {
1036 }
1038 }
1039}
1040
1042 if (lv) {
1043 lv->scroll_type = type;
1044 }
1045}
1046
1049 void *udata) {
1050 if (lv) {
1051 lv->mouse_activated = cb;
1052 lv->mouse_activated_data = udata;
1053 }
1054}
1055void listview_set_num_lines(listview *lv, unsigned int num_lines) {
1056 if (lv) {
1057 lv->menu_lines = num_lines;
1058 }
1059}
1060
1061void listview_set_max_lines(listview *lv, unsigned int max_lines) {
1062 if (lv) {
1063 lv->max_displayed_lines = max_lines;
1064 }
1065}
1066
1068 if (lv) {
1069 return lv->fixed_num_lines;
1070 }
1071 return FALSE;
1072}
1074 if (lv) {
1075 lv->fixed_num_lines = TRUE;
1076 }
1077}
1078
1080 if (lv) {
1081 lv->emode = PANGO_ELLIPSIZE_START;
1082 for (unsigned int i = 0; i < lv->cur_elements; i++) {
1084 }
1085 }
1086}
1087
1089 if (lv) {
1090 PangoEllipsizeMode mode = lv->emode;
1091 if (mode == PANGO_ELLIPSIZE_START) {
1092 mode = PANGO_ELLIPSIZE_MIDDLE;
1093 } else if (mode == PANGO_ELLIPSIZE_MIDDLE) {
1094 mode = PANGO_ELLIPSIZE_END;
1095 } else if (mode == PANGO_ELLIPSIZE_END) {
1096 mode = PANGO_ELLIPSIZE_START;
1097 }
1098 lv->emode = mode;
1099 for (unsigned int i = 0; i < lv->cur_elements; i++) {
1100 textbox_set_ellipsize(lv->boxes[i].textbox, mode);
1101 }
1102 }
1103}
1104
1105void listview_set_filtered(listview *lv, gboolean filtered) {
1106 if (lv) {
1107 lv->filtered = filtered;
1108 }
1109}
1110
1112 listview *lv, listview_selection_changed_callback cb, void *udata) {
1113 lv->sc_callback = cb;
1114 lv->sc_udata = udata;
1115}
MouseBindingListviewElementAction
Definition keyb.h:159
MouseBindingListviewAction
Definition keyb.h:149
@ ACCEPT_HOVERED_ENTRY
Definition keyb.h:161
@ ACCEPT_HOVERED_CUSTOM
Definition keyb.h:162
@ SELECT_HOVERED_ENTRY
Definition keyb.h:160
@ SCROLL_LEFT
Definition keyb.h:150
@ SCROLL_DOWN
Definition keyb.h:152
@ SCROLL_RIGHT
Definition keyb.h:151
@ SCROLL_UP
Definition keyb.h:153
void scrollbar_set_max_value(scrollbar *sb, unsigned int max)
Definition scrollbar.c:132
scrollbar * scrollbar_create(widget *parent, const char *name)
Definition scrollbar.c:103
void scrollbar_set_handle(scrollbar *sb, unsigned int pos)
Definition scrollbar.c:138
void scrollbar_set_handle_length(scrollbar *sb, unsigned int pos_length)
Definition scrollbar.c:144
#define TICK_N(a)
Definition timings.h:69
TextboxFlags
Definition textbox.h:89
TextBoxFontType
Definition textbox.h:100
void textbox_set_ellipsize(textbox *tb, PangoEllipsizeMode mode)
Definition textbox.c:981
textbox * textbox_create(widget *parent, WidgetType type, const char *name, TextboxFlags flags, TextBoxFontType tbft, const char *text, double xalign, double yalign)
Definition textbox.c:186
void textbox_moveresize(textbox *tb, int x, int y, int w, int h)
Definition textbox.c:393
void textbox_text(textbox *tb, const char *text)
Definition textbox.c:358
@ TB_AUTOHEIGHT
Definition textbox.h:90
@ URGENT
Definition textbox.h:104
@ ACTIVE
Definition textbox.h:106
@ HIGHLIGHT
Definition textbox.h:115
@ NORMAL
Definition textbox.h:102
@ STATE_MASK
Definition textbox.h:119
@ ALT
Definition textbox.h:113
@ FMOD_MASK
Definition textbox.h:117
void box_add(box *box, widget *child, gboolean expand)
Definition box.c:286
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition box.c:346
icon * icon_create(widget *parent, const char *name)
Definition icon.c:153
void listview_nav_page_next(listview *lv)
Definition listview.c:989
void listview_set_fixed_num_lines(listview *lv)
Definition listview.c:1073
void listview_set_num_lines(listview *lv, unsigned int num_lines)
Definition listview.c:1055
void listview_set_show_scrollbar(listview *lv, gboolean enabled)
Definition listview.c:1030
void listview_set_num_elements(listview *lv, unsigned int rows)
Definition listview.c:561
void listview_nav_right(listview *lv)
Definition listview.c:897
void listview_set_mouse_activated_cb(listview *lv, listview_mouse_activated_cb cb, void *udata)
Definition listview.c:1047
void listview_toggle_ellipsizing(listview *lv)
Definition listview.c:1088
void listview_set_selected(listview *lv, unsigned int selected)
Definition listview.c:585
void listview_set_max_lines(listview *lv, unsigned int max_lines)
Definition listview.c:1061
listview * listview_create(widget *parent, const char *name, listview_update_callback cb, void *udata, unsigned int eh, gboolean reverse)
Definition listview.c:711
void listview_nav_left(listview *lv)
Definition listview.c:876
void listview_set_scroll_type(listview *lv, ScrollType type)
Definition listview.c:1041
void(* listview_selection_changed_callback)(listview *lv, unsigned int index, void *udata)
Definition listview.h:78
gboolean listview_get_fixed_num_lines(listview *lv)
Definition listview.c:1067
void listview_set_ellipsize_start(listview *lv)
Definition listview.c:1079
void listview_nav_prev(listview *lv)
Definition listview.c:817
unsigned int listview_get_selected(listview *lv)
Definition listview.c:578
ScrollType
Definition listview.h:49
void(* listview_mouse_activated_cb)(listview *, gboolean, void *)
Definition listview.h:84
void(* listview_update_callback)(textbox *tb, icon *ico, unsigned int entry, void *udata, TextBoxFontType *type, gboolean full)
Definition listview.h:67
void listview_set_filtered(listview *lv, gboolean filtered)
Definition listview.c:1105
void listview_nav_up(listview *lv)
Definition listview.c:839
void listview_nav_next(listview *lv)
Definition listview.c:811
void listview_nav_page_prev(listview *lv)
Definition listview.c:979
void listview_set_selection_changed_callback(listview *lv, listview_selection_changed_callback cb, void *udata)
Definition listview.c:1111
void listview_nav_down(listview *lv)
Definition listview.c:857
@ LISTVIEW_SCROLL_CONTINIOUS
Definition listview.h:53
void widget_queue_redraw(widget *wid)
Definition widget.c:487
gboolean widget_enabled(widget *widget)
Definition widget.c:116
int widget_get_width(widget *widget)
Definition widget.c:446
void widget_free(widget *wid)
Definition widget.c:425
static void widget_disable(widget *widget)
Definition widget.h:170
int widget_intersect(const widget *widget, int x, int y)
Definition widget.c:75
void widget_resize(widget *widget, short w, short h)
Definition widget.c:87
WidgetType
Definition widget.h:56
static void widget_enable(widget *widget)
Definition widget.h:178
int widget_get_desired_width(widget *wid, const int height)
Definition widget.c:653
void widget_move(widget *widget, short x, short y)
Definition widget.c:102
int widget_get_y_pos(widget *widget)
Definition widget.c:461
void widget_draw(widget *widget, cairo_t *d)
Definition widget.c:135
#define WIDGET(a)
Definition widget.h:119
WidgetTriggerActionResult
Definition widget.h:76
void widget_set_type(widget *widget, WidgetType type)
Definition widget.c:109
void widget_set_trigger_action_handler(widget *wid, widget_trigger_action_cb cb, void *cb_data)
Definition widget.c:557
int widget_get_desired_height(widget *wid, const int width)
Definition widget.c:644
int widget_get_x_pos(widget *widget)
Definition widget.c:455
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition widget.c:510
@ WIDGET_TYPE_LISTVIEW_ELEMENT
Definition widget.h:62
@ WIDGET_TYPE_TEXTBOX_TEXT
Definition widget.h:70
@ WIDGET_TYPE_LISTVIEW
Definition widget.h:60
@ WIDGET_TRIGGER_ACTION_RESULT_HANDLED
Definition widget.h:80
@ WIDGET_TRIGGER_ACTION_RESULT_IGNORED
Definition widget.h:78
MoveDirection
Definition listview.c:57
@ RIGHT_TO_LEFT
Definition listview.c:57
@ LEFT_TO_RIGHT
Definition listview.c:57
static void listview_nav_column_right_int(listview *lv)
Definition listview.c:831
static unsigned int scroll_per_page(listview *lv)
Definition listview.c:249
static void listview_nav_up_int(listview *lv)
Definition listview.c:780
static unsigned int scroll_per_page_barview(listview *lv)
Definition listview.c:235
#define BARVIEW
Definition listview.c:51
const char *const listview_theme_prop_names[][3]
Definition listview.c:137
static WidgetTriggerActionResult listview_element_trigger_action(widget *wid, MouseBindingListviewElementAction action, gint x, gint y, void *user_data)
static gboolean listview_element_motion_notify(widget *wid, gint x, gint y)
static void listview_nav_page_next_int(listview *lv)
Definition listview.c:955
static void listview_resize(widget *wid, short w, short h)
Definition listview.c:596
static widget * listview_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition listview.c:621
static void _listview_draw(widget *wid, cairo_t *draw)
Definition listview.c:510
static void listview_nav_page_prev_int(listview *lv)
Definition listview.c:932
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:648
static void listview_recompute_elements(listview *lv)
Definition listview.c:521
#define DEFAULT_SPACING
Definition listview.c:43
static void listview_add_widget(listview *lv, _listview_row *row, widget *wid, const char *label)
Definition listview.c:168
static void barview_draw(widget *wid, cairo_t *draw)
Definition listview.c:313
static void listview_free(widget *wid)
Definition listview.c:224
static void listview_nav_column_left_int(listview *lv)
Definition listview.c:824
static void listview_nav_down_int(listview *lv)
Definition listview.c:796
#define LISTVIEW
Definition listview.c:49
static void listview_create_row(listview *lv, _listview_row *row)
Definition listview.c:197
static void listview_draw(widget *wid, cairo_t *draw)
Definition listview.c:393
static int listview_get_desired_height(widget *wid, const int width)
static unsigned int scroll_continious(listview *lv)
Definition listview.c:272
static void update_element(listview *lv, unsigned int tb, unsigned int index, gboolean full)
Definition listview.c:292
static void listview_set_state(_listview_row r, TextBoxFontType tbft)
Definition listview.c:146
RofiOrientation
Definition rofi-types.h:141
@ ROFI_ORIENTATION_HORIZONTAL
Definition rofi-types.h:143
@ ROFI_ORIENTATION_VERTICAL
Definition rofi-types.h:142
Settings config
#define DEFAULT_MENU_COLUMNS
Definition settings.h:192
unsigned int fixed_num_lines
Definition settings.h:90
gboolean show_icons
Definition settings.h:62
unsigned int cycle
Definition settings.h:116
Definition box.c:40
Definition icon.c:39
textbox * index
Definition listview.c:62
icon * icon
Definition listview.c:63
textbox * textbox
Definition listview.c:61
unsigned int cur_columns
Definition listview.c:89
void * mouse_activated_data
Definition listview.c:121
gboolean cycle
Definition listview.c:104
unsigned int rchanged
Definition listview.c:73
unsigned int max_rows
Definition listview.c:84
unsigned int cur_page
Definition listview.c:79
unsigned int menu_columns
Definition listview.c:96
unsigned int max_displayed_lines
Definition listview.c:95
widget widget
Definition listview.c:67
void * udata
Definition listview.c:112
PangoEllipsizeMode emode
Definition listview.c:125
unsigned int cur_visible
Definition listview.c:129
listview_update_callback callback
Definition listview.c:111
listview_mouse_activated_cb mouse_activated
Definition listview.c:120
void * sc_udata
Definition listview.c:115
unsigned int req_elements
Definition listview.c:90
xcb_timestamp_t last_click
Definition listview.c:119
unsigned int element_height
Definition listview.c:83
unsigned int last_offset
Definition listview.c:80
unsigned int cur_elements
Definition listview.c:91
unsigned int dynamic
Definition listview.c:98
MoveDirection direction
Definition listview.c:128
char * listview_name
Definition listview.c:123
gboolean filtered
Definition listview.c:102
scrollbar * scrollbar
Definition listview.c:109
unsigned int max_elements
Definition listview.c:85
gboolean require_input
Definition listview.c:101
unsigned int fixed_num_lines
Definition listview.c:97
unsigned int reverse
Definition listview.c:100
listview_selection_changed_callback sc_callback
Definition listview.c:114
RofiDistance spacing
Definition listview.c:93
gboolean fixed_columns
Definition listview.c:88
RofiOrientation type
Definition listview.c:69
unsigned int selected
Definition listview.c:81
unsigned int eh
Definition listview.c:99
ScrollType scroll_type
Definition listview.c:106
struct _listview::@3 barview
gboolean scrollbar_scroll
Definition listview.c:117
RofiOrientation pack_direction
Definition listview.c:76
_listview_row * boxes
Definition listview.c:108
unsigned int menu_lines
Definition listview.c:94
void(* free)(struct _widget *widget)
widget_find_mouse_target_cb find_mouse_target
gboolean enabled
widget_trigger_action_cb trigger_action
int(* get_desired_height)(struct _widget *, const int width)
struct _widget * parent
void(* draw)(struct _widget *widget, cairo_t *draw)
gboolean(* motion_notify)(struct _widget *, gint x, gint y)
void(* resize)(struct _widget *, short, short)
GList * rofi_theme_get_list_strings(const widget *widget, const char *property)
Definition theme.c:1267
RofiDistance rofi_theme_get_distance(const widget *widget, const char *property, int def)
Definition theme.c:877
int rofi_theme_get_boolean(const widget *widget, const char *property, int def)
Definition theme.c:903
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition theme.c:1415
RofiOrientation rofi_theme_get_orientation(const widget *widget, const char *property, RofiOrientation def)
Definition theme.c:932
int rofi_theme_get_integer(const widget *widget, const char *property, int def)
Definition theme.c:840
MenuFlags flags
Definition view.c:107
void widget_init(widget *wid, widget *parent, WidgetType type, const char *name)
Definition widget.c:34
void widget_set_state(widget *widget, const char *state)
Definition widget.c:57
int widget_padding_get_padding_width(const widget *wid)
Definition widget.c:637
int widget_padding_get_left(const widget *wid)
Definition widget.c:576
int widget_padding_get_right(const widget *wid)
Definition widget.c:586
int widget_padding_get_padding_height(const widget *wid)
Definition widget.c:631
int widget_padding_get_top(const widget *wid)
Definition widget.c:598
int widget_padding_get_bottom(const widget *wid)
Definition widget.c:608