diff --git a/doc/rofi-keys.5 b/doc/rofi-keys.5 index b810f09f..ed190e45 100644 --- a/doc/rofi-keys.5 +++ b/doc/rofi-keys.5 @@ -262,7 +262,7 @@ Go to the next column Select previous entry .PP -\fBDefault\fP: Up,Control+p,ISO\_Left\_Tab +\fBDefault\fP: Up,Control+p .SS \fBkb\-row\-down\fP .PP @@ -276,7 +276,21 @@ Select next entry Go to next row, if one left, accept it, if no left next mode. .PP -\fBDefault\fP: Tab +\fBDefault\fP: + +.SS \fBkb\-element\-next\fP +.PP +Go to next row. + +.PP +\fBDefault\fP: Tab + +.SS \fBkb\-element\-prev\fP +.PP +Go to previous row. + +.PP +\fBDefault\fP: ISO\_Left\_Tab .SS \fBkb\-page\-prev\fP .PP diff --git a/doc/rofi-keys.5.markdown b/doc/rofi-keys.5.markdown index 9fff1baa..ab4c7e7d 100644 --- a/doc/rofi-keys.5.markdown +++ b/doc/rofi-keys.5.markdown @@ -183,7 +183,7 @@ Go to the next column ### **kb-row-up** Select previous entry -**Default**: Up,Control+p,ISO_Left_Tab +**Default**: Up,Control+p ### **kb-row-down** Select next entry @@ -193,7 +193,17 @@ Select next entry ### **kb-row-tab** Go to next row, if one left, accept it, if no left next mode. -**Default**: Tab +**Default**: + +### **kb-element-next** +Go to next row. + +**Default**: Tab + +### **kb-element-prev** +Go to previous row. + +**Default**: ISO_Left_Tab ### **kb-page-prev** Go to the previous page diff --git a/doc/rofi-theme.5 b/doc/rofi-theme.5 index a3eaa950..797b027d 100644 --- a/doc/rofi-theme.5 +++ b/doc/rofi-theme.5 @@ -1278,6 +1278,9 @@ Indicate how elements are stacked. Horizontal implements the dmenu style. \fBreverse\fP: boolean Reverse the ordering (top down to bottom up). .IP \(bu 2 +\fBflow\fP: orientation +The order the elements are layed out. Vertical is the original 'column' view. +.IP \(bu 2 \fBfixed\-columns\fP: boolean Do not reduce the number of columns shown when number of visible elements is not enough to fill them all. diff --git a/doc/rofi-theme.5.markdown b/doc/rofi-theme.5.markdown index 4f2a6460..f82e8017 100644 --- a/doc/rofi-theme.5.markdown +++ b/doc/rofi-theme.5.markdown @@ -794,6 +794,8 @@ The following properties are currently supported: Indicate how elements are stacked. Horizontal implements the dmenu style. * **reverse**: boolean Reverse the ordering (top down to bottom up). +* **flow**: orientation + The order the elements are layed out. Vertical is the original 'column' view. * **fixed-columns**: boolean Do not reduce the number of columns shown when number of visible elements is not enough to fill them all. diff --git a/include/keyb.h b/include/keyb.h index 1ae11176..ad34e5e5 100644 --- a/include/keyb.h +++ b/include/keyb.h @@ -101,6 +101,8 @@ typedef enum { ROW_UP, ROW_DOWN, ROW_TAB, + ELEMENT_NEXT, + ELEMENT_PREV, PAGE_PREV, PAGE_NEXT, ROW_FIRST, diff --git a/include/widgets/listview.h b/include/widgets/listview.h index f7ebec66..8653f05e 100644 --- a/include/widgets/listview.h +++ b/include/widgets/listview.h @@ -111,6 +111,21 @@ void listview_set_selected(listview *lv, unsigned int selected); */ unsigned int listview_get_selected(listview *lv); +/** + * @param lv The listview handle + * + * Move the selection next element. + * - Wrap around. + */ +void listview_nav_next(listview *lv); +/** + * @param lv The listview handle + * + * Move the selection previous element. + * - Wrap around. + */ +void listview_nav_prev(listview *lv); + /** * @param lv The listview handle * diff --git a/source/keyb.c b/source/keyb.c index 46e208ea..34878ee0 100644 --- a/source/keyb.c +++ b/source/keyb.c @@ -26,10 +26,10 @@ */ #include -#include #include "nkutils-bindings.h" #include "rofi.h" #include "xrmoptions.h" +#include typedef struct { guint id; @@ -145,7 +145,7 @@ ActionBindingEntry rofi_bindings[] = { .comment = "Go to the next column"}, {.id = ROW_UP, .name = "kb-row-up", - .binding = "Up,Control+p,ISO_Left_Tab", + .binding = "Up,Control+p", .comment = "Select previous entry"}, {.id = ROW_DOWN, .name = "kb-row-down", @@ -153,9 +153,17 @@ ActionBindingEntry rofi_bindings[] = { .comment = "Select next entry"}, {.id = ROW_TAB, .name = "kb-row-tab", - .binding = "Tab", + .binding = "", .comment = "Go to next row, if one left, accept it, if no left next mode."}, + {.id = ELEMENT_NEXT, + .name = "kb-element-next", + .binding = "Tab", + .comment = "Go to next element (in logical order)."}, + {.id = ELEMENT_PREV, + .name = "kb-element-prev", + .binding = "ISO_Left_Tab", + .comment = "Go to next previous element (in logical order)."}, {.id = PAGE_PREV, .name = "kb-page-prev", .binding = "Page_Up", diff --git a/source/view.c b/source/view.c index 6df1fa70..27d99593 100644 --- a/source/view.c +++ b/source/view.c @@ -1362,6 +1362,12 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) { state->retv = MENU_CANCEL; state->quit = TRUE; break; + case ELEMENT_NEXT: + listview_nav_next(state->list_view); + break; + case ELEMENT_PREV: + listview_nav_prev(state->list_view); + break; case ROW_UP: listview_nav_up(state->list_view); break; diff --git a/source/widgets/listview.c b/source/widgets/listview.c index a94ab31e..7e07341c 100644 --- a/source/widgets/listview.c +++ b/source/widgets/listview.c @@ -71,6 +71,9 @@ struct _listview { // RChanged // Text needs to be repainted. unsigned int rchanged; + + // The direction we pack the widgets. + RofiOrientation pack_direction; // Administration unsigned int cur_page; @@ -433,30 +436,53 @@ static void listview_draw(widget *wid, cairo_t *draw) { } } for (unsigned int i = 0; i < max; i++) { - unsigned int ex = - left_offset + ((i) / lv->max_rows) * (element_width + spacing_hori); + if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) { + unsigned int ex = left_offset + ((i) % lv->cur_columns) * + (element_width + spacing_hori); + unsigned int ey = 0; + if (lv->reverse) { + ey = wid->h - + (widget_padding_get_bottom(wid) + + ((i) / lv->cur_columns) * + (lv->element_height + spacing_vert)) - + lv->element_height; - if ((i) / lv->max_rows == (lv->cur_columns - 1)) { - ex += d; - } - if (lv->reverse) { - unsigned int ey = - wid->h - - (widget_padding_get_bottom(wid) + - ((i) % lv->max_rows) * (lv->element_height + spacing_vert)) - - lv->element_height; + if ((i) / lv->cur_columns == (lv->cur_columns - 1)) { + ex += d; + } + } else { + ey = top_offset + + ((i) / lv->cur_columns) * (lv->element_height + spacing_vert); + + if ((i) / lv->cur_columns == (lv->cur_columns - 1)) { + ex += d; + } + } widget_move(WIDGET(lv->boxes[i].box), ex, ey); widget_resize(WIDGET(lv->boxes[i].box), element_width, lv->element_height); + } else { - unsigned int ey = - top_offset + - ((i) % lv->max_rows) * (lv->element_height + spacing_vert); + unsigned int ex = left_offset + ((i) / lv->max_rows) * + (element_width + spacing_hori); + + if ((i) / lv->max_rows == (lv->cur_columns - 1)) { + ex += d; + } + unsigned int ey = 0; + if (lv->reverse) { + ey = wid->h - + (widget_padding_get_bottom(wid) + + ((i) % lv->max_rows) * (lv->element_height + spacing_vert)) - + lv->element_height; + } else { + ey = top_offset + + ((i) % lv->max_rows) * (lv->element_height + spacing_vert); + } widget_move(WIDGET(lv->boxes[i].box), ex, ey); widget_resize(WIDGET(lv->boxes[i].box), element_width, lv->element_height); } - update_element(lv, i, i + offset, TRUE); widget_draw(WIDGET(lv->boxes[i].box), draw); } @@ -494,7 +520,14 @@ static void listview_recompute_elements(listview *lv) { } if (!(lv->fixed_columns) && lv->req_elements < lv->max_elements) { newne = lv->req_elements; - lv->cur_columns = (lv->req_elements + (lv->max_rows - 1)) / lv->max_rows; + if (lv->pack_direction == ROFI_ORIENTATION_VERTICAL) { + lv->cur_columns = (lv->req_elements + (lv->max_rows - 1)) / lv->max_rows; + } else { + lv->cur_columns = lv->menu_columns; + if (lv->req_elements < lv->menu_columns) { + lv->cur_columns = lv->req_elements; + } + } } else { newne = MIN(lv->req_elements, lv->max_elements); lv->cur_columns = lv->menu_columns; @@ -709,6 +742,8 @@ listview *listview_create(widget *parent, const char *name, config.fixed_num_lines); lv->dynamic = rofi_theme_get_boolean(WIDGET(lv), "dynamic", TRUE); lv->reverse = rofi_theme_get_boolean(WIDGET(lv), "reverse", reverse); + lv->pack_direction = + rofi_theme_get_orientation(WIDGET(lv), "flow", ROFI_ORIENTATION_VERTICAL); lv->cycle = rofi_theme_get_boolean(WIDGET(lv), "cycle", config.cycle); lv->fixed_columns = rofi_theme_get_boolean(WIDGET(lv), "fixed-columns", FALSE); @@ -756,11 +791,44 @@ static void listview_nav_down_int(listview *lv) { lv->barview.direction = LEFT_TO_RIGHT; widget_queue_redraw(WIDGET(lv)); } +void listview_nav_next(listview *lv) { + if (lv == NULL) { + return; + } + listview_nav_down_int(lv); +} +void listview_nav_prev(listview *lv) { + if (lv == NULL) { + return; + } + listview_nav_up_int(lv); +} + +static void listview_nav_column_left_int(listview *lv) { + if (lv->selected >= lv->cur_columns) { + lv->selected -= lv->cur_columns; + widget_queue_redraw(WIDGET(lv)); + } +} +static void listview_nav_column_right_int(listview *lv) { + if ((lv->selected + lv->cur_columns) < lv->req_elements) { + lv->selected += lv->cur_columns; + widget_queue_redraw(WIDGET(lv)); + } +} void listview_nav_up(listview *lv) { if (lv == NULL) { return; } + if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) { + if (lv->reverse) { + listview_nav_column_right_int(lv); + } else { + listview_nav_column_left_int(lv); + } + return; + } if (lv->reverse) { listview_nav_down_int(lv); } else { @@ -771,6 +839,14 @@ void listview_nav_down(listview *lv) { if (lv == NULL) { return; } + if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) { + if (lv->reverse) { + listview_nav_column_left_int(lv); + } else { + listview_nav_column_right_int(lv); + } + return; + } if (lv->reverse) { listview_nav_up_int(lv); } else { @@ -782,6 +858,13 @@ void listview_nav_left(listview *lv) { if (lv == NULL) { return; } + if (lv->max_rows == 0) { + return; + } + if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) { + listview_nav_up_int(lv); + return; + } if (lv->type == BARVIEW) { listview_nav_up_int(lv); return; @@ -798,6 +881,10 @@ void listview_nav_right(listview *lv) { if (lv->max_rows == 0) { return; } + if (lv->pack_direction == ROFI_ORIENTATION_HORIZONTAL) { + listview_nav_down_int(lv); + return; + } if (lv->type == BARVIEW) { listview_nav_down_int(lv); return; diff --git a/test/mode-test.c b/test/mode-test.c index de19b47a..6cb9e68e 100644 --- a/test/mode-test.c +++ b/test/mode-test.c @@ -117,7 +117,7 @@ END_TEST START_TEST(test_mode_num_items) { unsigned int rows = mode_get_num_entries(&help_keys_mode); - ck_assert_int_eq(rows, 74); + ck_assert_int_eq(rows, 76); for (unsigned int i = 0; i < rows; i++) { int state = 0; GList *list = NULL;