diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/theme.c | 41 | ||||
-rw-r--r-- | source/view.c | 227 | ||||
-rw-r--r-- | source/widgets/box.c | 45 | ||||
-rw-r--r-- | source/widgets/listview.c | 177 | ||||
-rw-r--r-- | source/widgets/textbox.c | 94 | ||||
-rw-r--r-- | source/widgets/widget.c | 19 |
6 files changed, 496 insertions, 107 deletions
diff --git a/source/theme.c b/source/theme.c index 1c4711c6..cebe29e3 100644 --- a/source/theme.c +++ b/source/theme.c @@ -386,6 +386,8 @@ static ThemeWidget *rofi_theme_find ( ThemeWidget *widget, const char *name, con if ( f != widget ) { widget = f; found = TRUE; + } else if ( exact ) { + break; } } g_free ( tname ); @@ -503,11 +505,10 @@ int rofi_theme_get_integer_exact ( const widget *widget, const char *property, i g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property ); return def; } - -Distance rofi_theme_get_distance ( const widget *widget, const char *property, int def ) +static Distance _rofi_theme_get_distance ( const widget *widget, const char *property, int def , gboolean exact) { - ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE ); - Property *p = rofi_theme_find_property ( wid, P_PADDING, property, FALSE ); + ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, exact ); + Property *p = rofi_theme_find_property ( wid, P_PADDING, property, exact ); if ( p ) { if ( p->type == P_INTEGER ) { return (Distance){ p->value.i, PW_PX, SOLID }; @@ -520,6 +521,16 @@ Distance rofi_theme_get_distance ( const widget *widget, const char *property, i return (Distance){ def, PW_PX, SOLID }; } + +Distance rofi_theme_get_distance_exact ( const widget *widget, const char *property, int def ) +{ + return _rofi_theme_get_distance ( widget, property, def , TRUE ); +} +Distance rofi_theme_get_distance ( const widget *widget, const char *property, int def ) +{ + return _rofi_theme_get_distance ( widget, property, def , FALSE); +} + int rofi_theme_get_boolean ( const widget *widget, const char *property, int def ) { ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE ); @@ -583,6 +594,28 @@ Padding rofi_theme_get_padding ( const widget *widget, const char *property, Pad g_debug ( "Theme entry: #%s %s property %s unset.", widget->name, widget->state ? widget->state : "", property ); return pad; } + +GList *rofi_theme_get_list ( const widget *widget, const char * property, const char *defaults ) +{ + ThemeWidget *wid2 = rofi_theme_find_widget ( widget->name, widget->state, TRUE ); + Property *p = rofi_theme_find_property ( wid2, P_LIST, property, TRUE); + if ( p ) { + if ( p->type == P_LIST ){ + return g_list_copy_deep ( p->value.list, g_strdup, NULL ); + } + } + char **r = defaults?g_strsplit (defaults, ",",0):NULL; + if ( r ){ + GList *l = NULL; + for ( int i =0; r[i] != NULL; i++){ + l = g_list_append(l, r[i]); + } + g_free(r); + return l; + } + return NULL; +} + ThemeHighlight rofi_theme_get_highlight ( widget *widget, const char *property, ThemeHighlight th ) { ThemeWidget *wid = rofi_theme_find_widget ( widget->name, widget->state, FALSE ); diff --git a/source/view.c b/source/view.c index 5776d845..824d2300 100644 --- a/source/view.c +++ b/source/view.c @@ -650,8 +650,8 @@ void __create_window ( MenuFlags menu_flags ) map }; - xcb_window_t box = xcb_generate_id ( xcb->connection ); - xcb_void_cookie_t cc = xcb_create_window_checked ( xcb->connection, depth->depth, box, xcb_stuff_get_root_window (), + xcb_window_t box_window = xcb_generate_id ( xcb->connection ); + xcb_void_cookie_t cc = xcb_create_window_checked ( xcb->connection, depth->depth, box_window, xcb_stuff_get_root_window ( ), 0, 0, 200, 100, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visual->visual_id, selmask, selval ); xcb_generic_error_t *error; @@ -662,7 +662,7 @@ void __create_window ( MenuFlags menu_flags ) } TICK_N ( "xcb create window" ); CacheState.gc = xcb_generate_id ( xcb->connection ); - xcb_create_gc ( xcb->connection, CacheState.gc, box, 0, 0 ); + xcb_create_gc ( xcb->connection, CacheState.gc, box_window, 0, 0 ); TICK_N ( "xcb create gc" ); // Create a drawable. @@ -684,7 +684,7 @@ void __create_window ( MenuFlags menu_flags ) pango_cairo_context_set_font_options ( p, fo ); TICK_N ( "pango cairo font setup" ); - CacheState.main_window = box; + CacheState.main_window = box_window; CacheState.flags = menu_flags; monitor_active ( &( CacheState.mon ) ); // Setup dpi @@ -708,7 +708,7 @@ void __create_window ( MenuFlags menu_flags ) } // Setup font. // Dummy widget. - container *win = container_create ( "window.box" ); + box *win = box_create ( "window.box_window", BOX_HORIZONTAL ); const char *font = rofi_theme_get_string ( WIDGET ( win ), "font", config.menu_font ); if ( font ) { PangoFontDescription *pfd = pango_font_description_from_string ( font ); @@ -730,13 +730,13 @@ void __create_window ( MenuFlags menu_flags ) TICK_N ( "textbox setup" ); // // make it an unmanaged window if ( ( ( menu_flags & MENU_NORMAL_WINDOW ) == 0 ) ) { - window_set_atom_prop ( box, xcb->ewmh._NET_WM_STATE, &( xcb->ewmh._NET_WM_STATE_ABOVE ), 1 ); + window_set_atom_prop ( box_window, xcb->ewmh._NET_WM_STATE, &( xcb->ewmh._NET_WM_STATE_ABOVE ), 1 ); uint32_t values[] = { 1 }; - xcb_change_window_attributes ( xcb->connection, box, XCB_CW_OVERRIDE_REDIRECT, values ); + xcb_change_window_attributes ( xcb->connection, box_window, XCB_CW_OVERRIDE_REDIRECT, values ); } else{ - window_set_atom_prop ( box, xcb->ewmh._NET_WM_WINDOW_TYPE, &( xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL ), 1 ); - x11_disable_decoration ( box ); + window_set_atom_prop ( box_window, xcb->ewmh._NET_WM_WINDOW_TYPE, &( xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL ), 1 ); + x11_disable_decoration ( box_window ); } TICK_N ( "setup window attributes" ); @@ -746,16 +746,16 @@ void __create_window ( MenuFlags menu_flags ) xcb->ewmh._NET_WM_STATE_FULLSCREEN, xcb->ewmh._NET_WM_STATE_ABOVE }; - window_set_atom_prop ( box, xcb->ewmh._NET_WM_STATE, atoms, sizeof ( atoms ) / sizeof ( xcb_atom_t ) ); + window_set_atom_prop ( box_window, xcb->ewmh._NET_WM_STATE, atoms, sizeof ( atoms ) / sizeof ( xcb_atom_t ) ); } TICK_N ( "setup window fullscreen" ); // Set the WM_NAME - xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, box, xcb->ewmh._NET_WM_NAME, xcb->ewmh.UTF8_STRING, 8, 4, "rofi" ); - xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, box, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 4, "rofi" ); + xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, box_window, xcb->ewmh._NET_WM_NAME, xcb->ewmh.UTF8_STRING, 8, 4, "rofi" ); + xcb_change_property ( xcb->connection, XCB_PROP_MODE_REPLACE, box_window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 4, "rofi" ); const char wm_class_name[] = "rofi\0Rofi"; - xcb_icccm_set_wm_class ( xcb->connection, box, sizeof ( wm_class_name ), wm_class_name ); + xcb_icccm_set_wm_class ( xcb->connection, box_window, sizeof ( wm_class_name ), wm_class_name ); TICK_N ( "setup window name and class" ); const char *transparency = rofi_theme_get_string ( WIDGET ( win ), "transparency", NULL ); @@ -994,7 +994,7 @@ static void rofi_view_refilter ( RofiViewState *state ) tokenize_free ( state->tokens ); state->tokens = NULL; } - if ( strlen ( state->text->text ) > 0 ) { + if ( state->text && strlen ( state->text->text ) > 0 ) { unsigned int j = 0; gchar *pattern = mode_preprocess_input ( state->sw, state->text->text ); glong plen = pattern ? g_utf8_strlen ( pattern, -1 ) : 0; @@ -1484,6 +1484,125 @@ static void rofi_view_listview_mouse_activated_cb ( listview *lv, gboolean custo state->skip_absorb = TRUE; } + +static void rofi_view_add_widget ( RofiViewState *state, widget *parent_widget, const char *parent, const char *name ) +{ + char *defaults = NULL; + widget *wid = NULL; + char *str= g_strjoin ( "." , parent, name, NULL ); + char *strbox= g_strjoin ( "." , str, "box",NULL ); + + /** + * MAINBOX + */ + if ( strcmp ( name, "mainbox") == 0 ){ + wid = (widget *)box_create ( strbox, BOX_VERTICAL ); + box_add ( (box *)parent_widget, WIDGET ( wid ), TRUE, 0 ); + defaults = "inputbar,message,listview"; + } + /** + * INPUTBAR + */ + else if ( strcmp ( name, "inputbar" ) == 0 ){ + wid = (widget *)box_create ( strbox, BOX_HORIZONTAL ); + defaults = "prompt,entry,case-indicator"; + + box_add ( (box *)parent_widget, WIDGET ( wid ), FALSE, 0 ); + } + /** + * PROMPT + */ + else if ( strcmp ( name, "prompt" ) == 0 ){ + // Prompt box. + state->prompt = textbox_create ( str, TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "" ); + rofi_view_update_prompt ( state ); + box_add ( (box *)parent_widget, WIDGET ( state->prompt ), FALSE, 1 ); + defaults = NULL; + } + /** + * CASE INDICATOR + */ + else if ( strcmp ( name, "case-indicator") == 0 ){ + state->case_indicator = textbox_create ( str, TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*" ); + // Add small separator between case indicator and text box. + box_add ( (box *)parent_widget, WIDGET ( state->case_indicator ), FALSE, 3 ); + textbox_text ( state->case_indicator, get_matching_state () ); + } + /** + * ENTRY BOX + */ + else if ( strcmp ( name, "entry" ) == 0 ){ + // Entry box + TextboxFlags tfl = TB_EDITABLE; + tfl |= ( ( state->menu_flags & MENU_PASSWORD ) == MENU_PASSWORD ) ? TB_PASSWORD : 0; + state->text = textbox_create ( str, tfl | TB_AUTOHEIGHT, NORMAL, NULL); + box_add ( (box*)parent_widget, WIDGET ( state->text ), TRUE, 2 ); + } + /** + * MESSAGE + */ + else if ( strcmp ( name, "message") == 0 ){ + char *strmsg= g_strjoin ( "." , str, "textbox",NULL ); + state->mesg_box = container_create ( strbox ); + state->mesg_tb = textbox_create ( strmsg, TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL ); + container_add ( state->mesg_box, WIDGET ( state->mesg_tb ) ); + rofi_view_reload_message_bar ( state ); + box_add ( (box*)parent_widget, WIDGET ( state->mesg_box ), FALSE, 2 ); + g_free(strmsg); + } + /** + * LISTVIEW + */ + else if ( strcmp ( name, "listview" ) == 0 ) { + state->list_view = listview_create ( str, update_callback, state, config.element_height, 0); + box_add ( (box*)parent_widget, WIDGET ( state->list_view ), TRUE, 3 ); + // Set configuration + listview_set_multi_select ( state->list_view, ( state->menu_flags & MENU_INDICATOR ) == MENU_INDICATOR ); + listview_set_scroll_type ( state->list_view, config.scroll_method ); + listview_set_mouse_activated_cb ( state->list_view, rofi_view_listview_mouse_activated_cb, state ); + + int lines = rofi_theme_get_integer ( WIDGET ( state->list_view ), "lines", config.menu_lines ); + listview_set_num_lines ( state->list_view, lines ); + listview_set_max_lines ( state->list_view, state->num_lines ); + } + /** + * SIDEBAR + */ + else if ( strcmp( name, "sidebar" ) == 0 ) { + if ( config.sidebar_mode ){ + state->sidebar_bar = box_create ( strbox, BOX_HORIZONTAL ); + box_add ( (box*)parent_widget, WIDGET ( state->sidebar_bar ), FALSE, 10 ); + state->num_modi = rofi_get_num_enabled_modi (); + state->modi = g_malloc0 ( state->num_modi * sizeof ( textbox * ) ); + char *strbutton= g_strjoin ( "." , str, "button",NULL ); + for ( unsigned int j = 0; j < state->num_modi; j++ ) { + const Mode * mode = rofi_get_mode ( j ); + state->modi[j] = textbox_create ( strbutton, TB_CENTER | TB_AUTOHEIGHT, ( mode == state->sw ) ? HIGHLIGHT : NORMAL, + mode_get_display_name ( mode ) ); + box_add ( state->sidebar_bar, WIDGET ( state->modi[j] ), TRUE, j ); + //widget_set_clicked_handler ( WIDGET ( state->modi[j] ), rofi_view_modi_clicked_cb, state ); + } + g_free(strbutton); + } + } else if ( g_ascii_strncasecmp ( name, "textbox", 7) == 0 ){ + textbox *t = textbox_create ( str, TB_WRAP, NORMAL, ""); + box_add ( (box *)parent_widget, WIDGET(t), TRUE, 0); + } else { + wid = box_create ( strbox, BOX_VERTICAL ); + box_add ( (box *)parent_widget, WIDGET ( wid ), TRUE, 0 ); + //g_error("The widget %s does not exists. Invalid layout.", name); + } + if ( wid ) { + GList *list = rofi_theme_get_list ( wid, "children",defaults); + for ( const GList *iter = list; iter != NULL; iter = g_list_next ( iter )){ + rofi_view_add_widget ( state, wid, str, (const char *)iter->data ); + } + g_list_free_full ( list, g_free ); + } + g_free(strbox); + g_free(str); +} + RofiViewState *rofi_view_create ( Mode *sw, const char *input, MenuFlags menu_flags, @@ -1511,69 +1630,23 @@ RofiViewState *rofi_view_create ( Mode *sw, // Get active monitor size. TICK_N ( "Get active monitor" ); - state->main_window = container_create ( "window.box" ); - state->main_box = box_create ( "window.mainbox.box", BOX_VERTICAL ); - container_add ( state->main_window, WIDGET ( state->main_box ) ); - - state->input_bar = box_create ( "window.mainbox.inputbar.box", BOX_HORIZONTAL ); - - // Only enable widget when sidebar is enabled. - if ( config.sidebar_mode ) { - state->sidebar_bar = box_create ( "window.mainbox.sidebar.box", BOX_HORIZONTAL ); - box_add ( state->main_box, WIDGET ( state->sidebar_bar ), FALSE, 10 ); - state->num_modi = rofi_get_num_enabled_modi (); - state->modi = g_malloc0 ( state->num_modi * sizeof ( textbox * ) ); - for ( unsigned int j = 0; j < state->num_modi; j++ ) { - const Mode * mode = rofi_get_mode ( j ); - state->modi[j] = textbox_create_full ( WIDGET_TYPE_SIDEBAR_MODI, "window.mainbox.sidebar.button", TB_CENTER | TB_AUTOHEIGHT, ( mode == state->sw ) ? HIGHLIGHT : NORMAL, - mode_get_display_name ( mode ) ); - box_add ( state->sidebar_bar, WIDGET ( state->modi[j] ), TRUE, j ); - widget_set_trigger_action_handler ( WIDGET ( state->modi[j] ), textbox_sidebar_modi_trigger_action, state ); - } - } - - int location = rofi_theme_get_position ( WIDGET ( state->main_window ), "location", config.location ); - int end = ( location == WL_SOUTH_EAST || location == WL_SOUTH || location == WL_SOUTH_WEST ); - box_add ( state->main_box, WIDGET ( state->input_bar ), FALSE, end ? 9 : 0 ); - - state->case_indicator = textbox_create ( "window.mainbox.inputbar.case-indicator", TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*" ); - // Add small separator between case indicator and text box. - box_add ( state->input_bar, WIDGET ( state->case_indicator ), FALSE, 3 ); - - // Prompt box. - state->prompt = textbox_create ( "window.mainbox.inputbar.prompt", TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "" ); - rofi_view_update_prompt ( state ); - box_add ( state->input_bar, WIDGET ( state->prompt ), FALSE, 1 ); - - // Entry box - TextboxFlags tfl = TB_EDITABLE; - tfl |= ( ( menu_flags & MENU_PASSWORD ) == MENU_PASSWORD ) ? TB_PASSWORD : 0; - state->text = textbox_create_full ( WIDGET_TYPE_EDITBOX, "window.mainbox.inputbar.entry", tfl | TB_AUTOHEIGHT, NORMAL, input ); - box_add ( state->input_bar, WIDGET ( state->text ), TRUE, 2 ); + state->main_window = box_create ( "window.box", BOX_VERTICAL ); + // Get children. + GList *list = rofi_theme_get_list ( WIDGET(state->main_window), "children", "mainbox"); + for ( const GList *iter = list; iter != NULL; iter = g_list_next ( iter )){ + rofi_view_add_widget ( state, WIDGET(state->main_window), "window", (const char *)iter->data ); + } + g_list_free_full ( list, g_free ); - textbox_text ( state->case_indicator, get_matching_state () ); - state->mesg_box = container_create ( "window.mainbox.message.box" ); - state->mesg_tb = textbox_create ( "window.mainbox.message.textbox", TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL ); - container_add ( state->mesg_box, WIDGET ( state->mesg_tb ) ); - rofi_view_reload_message_bar ( state ); - box_add ( state->main_box, WIDGET ( state->mesg_box ), FALSE, end ? 8 : 2 ); + if ( state->text && input) { + textbox_text ( state->text, input ); + } state->overlay = textbox_create ( "window.overlay", TB_AUTOWIDTH | TB_AUTOHEIGHT, URGENT, "blaat" ); state->overlay->widget.parent = WIDGET ( state->main_window ); widget_disable ( WIDGET ( state->overlay ) ); - state->list_view = listview_create ( "window.mainbox.listview", update_callback, state, config.element_height, end ); - // Set configuration - listview_set_multi_select ( state->list_view, ( state->menu_flags & MENU_INDICATOR ) == MENU_INDICATOR ); - listview_set_scroll_type ( state->list_view, config.scroll_method ); - listview_set_mouse_activated_cb ( state->list_view, rofi_view_listview_mouse_activated_cb, state ); - - int lines = rofi_theme_get_integer ( WIDGET ( state->list_view ), "lines", config.menu_lines ); - listview_set_num_lines ( state->list_view, lines ); - listview_set_max_lines ( state->list_view, state->num_lines ); - - box_add ( state->main_box, WIDGET ( state->list_view ), TRUE, 3 ); // filtered list state->line_map = g_malloc0_n ( state->num_lines, sizeof ( unsigned int ) ); @@ -1609,12 +1682,12 @@ int rofi_view_error_dialog ( const char *msg, int markup ) state->menu_flags = MENU_ERROR_DIALOG; state->finalize = process_result; - state->main_window = container_create ( "window.box" ); - state->main_box = box_create ( "window.mainbox.message.box", BOX_VERTICAL ); - container_add ( state->main_window, WIDGET ( state->main_box ) ); + state->main_window = box_create ( "window.box", BOX_VERTICAL ); + box *box = box_create ( "window.mainbox.message.box", BOX_VERTICAL ); + box_add ( state->main_window, WIDGET ( box ), TRUE, 0 ); state->text = textbox_create ( "window.mainbox.message.textbox", ( TB_AUTOHEIGHT | TB_WRAP ) + ( ( markup ) ? TB_MARKUP : 0 ), NORMAL, ( msg != NULL ) ? msg : "" ); - box_add ( state->main_box, WIDGET ( state->text ), TRUE, 1 ); + box_add ( box, WIDGET ( state->text ), TRUE, 1 ); // Make sure we enable fixed num lines when in normal window mode. if ( ( CacheState.flags & MENU_NORMAL_WINDOW ) == MENU_NORMAL_WINDOW ) { @@ -1745,12 +1818,12 @@ void rofi_view_set_overlay ( RofiViewState *state, const char *text ) // Within padding of window. x_offset -= widget_padding_get_right ( WIDGET ( state->main_window ) ); // Within the border of widget. - x_offset -= widget_padding_get_right ( WIDGET ( state->main_box ) ); - x_offset -= widget_padding_get_right ( WIDGET ( state->input_bar ) ); + //x_offset -= widget_padding_get_right ( WIDGET ( state->main_box ) ); + //x_offset -= widget_padding_get_right ( WIDGET ( state->input_bar ) ); x_offset -= widget_get_width ( WIDGET ( state->case_indicator ) ); x_offset -= widget_get_width ( WIDGET ( state->overlay ) ); int top_offset = widget_padding_get_top ( WIDGET ( state->main_window ) ); - top_offset += widget_padding_get_top ( WIDGET ( state->main_box ) ); + //top_offset += widget_padding_get_top ( WIDGET ( state->main_box ) ); widget_move ( WIDGET ( state->overlay ), x_offset, top_offset ); // We want to queue a repaint. rofi_view_queue_redraw ( ); diff --git a/source/widgets/box.c b/source/widgets/box.c index a2fc6a95..f781f3db 100644 --- a/source/widgets/box.c +++ b/source/widgets/box.c @@ -50,6 +50,42 @@ struct _box static void box_update ( widget *wid ); + +static int box_get_desired_width ( widget *wid ) +{ + box *b = (box *) wid; + int spacing = distance_get_pixel ( b->spacing, b->type == BOX_VERTICAL ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL ); + int width = 0; + if ( b->type == BOX_HORIZONTAL ) { + int active_widgets = 0; + for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { + widget * child = (widget *) iter->data; + if ( !child->enabled ) { + continue; + } + active_widgets++; + if ( child->expand == TRUE ) { + width += widget_get_desired_width ( child ); + continue; + } + width += widget_get_desired_width ( child ); + } + if ( active_widgets > 0 ) { + width += ( active_widgets - 1 ) * spacing; + } + } + else { + for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { + widget * child = (widget *) iter->data; + if ( !child->enabled ) { + continue; + } + width = MAX ( widget_get_desired_width ( child ), width ); + } + } + width += widget_padding_get_padding_width ( wid ); + return width; +} static int box_get_desired_height ( widget *wid ) { box *b = (box *) wid; @@ -160,7 +196,9 @@ static void hori_calculate_size ( box *b ) for ( GList *iter = g_list_first ( b->children ); iter != NULL; iter = g_list_next ( iter ) ) { widget * child = (widget *) iter->data; if ( child->enabled && child->expand == FALSE ) { - widget_resize ( child, child->w, rem_height ); + widget_resize ( child, + widget_get_desired_width ( child ), //child->w, + rem_height ); } } b->max_size = 0; @@ -263,7 +301,7 @@ void box_add ( box *box, widget *child, gboolean expand, int index ) child->index = rofi_theme_get_integer_exact ( child, "index", index ); child->parent = WIDGET ( box ); box->children = g_list_append ( box->children, (void *) child ); - box->children = g_list_sort ( box->children, box_sort_children ); + //box->children = g_list_sort ( box->children, box_sort_children ); widget_update ( WIDGET ( box ) ); } @@ -309,8 +347,11 @@ box * box_create ( const char *name, boxType type ) b->widget.update = box_update; b->widget.find_mouse_target = box_find_mouse_target; b->widget.get_desired_height = box_get_desired_height; + b->widget.get_desired_width = box_get_desired_width; b->widget.enabled = rofi_theme_get_boolean ( WIDGET ( b ), "enabled", TRUE ); + b->type = rofi_theme_get_boolean ( WIDGET (b), "vertical",b->type ); + b->spacing = rofi_theme_get_distance ( WIDGET ( b ), "spacing", DEFAULT_SPACING ); return b; } diff --git a/source/widgets/listview.c b/source/widgets/listview.c index 427a53c2..3398429a 100644 --- a/source/widgets/listview.c +++ b/source/widgets/listview.c @@ -37,9 +37,22 @@ #define DEFAULT_SPACING 2 +typedef enum { + LISTVIEW = 0, + BARVIEW = 1, +} ViewType; + +typedef enum { + LEFT_TO_RIGHT = 0, + RIGHT_TO_LEFT = 1 +} MoveDirection; + struct _listview { widget widget; + + ViewType type; + // RChanged // Text needs to be repainted. unsigned int rchanged; @@ -78,11 +91,19 @@ struct _listview listview_update_callback callback; void *udata; + gboolean scrollbar_scroll; + xcb_timestamp_t last_click; listview_mouse_activated_cb mouse_activated; void *mouse_activated_data; char *listview_name; + + /** Barview */ + struct { + MoveDirection direction; + unsigned int cur_visible; + } barview; }; static int listview_get_desired_height ( widget *wid ); @@ -99,6 +120,22 @@ static void listview_free ( widget *wid ) widget_free ( WIDGET ( lv->scrollbar ) ); g_free ( lv ); } +static unsigned int scroll_per_page_barview ( listview *lv ) +{ + unsigned int offset = lv->last_offset; + + // selected row is always visible. + // If selected is visible do not scroll. + if ( lv->selected < lv->last_offset ) { + offset = lv->selected; + lv->rchanged = TRUE; + } else if ( lv->selected >= (lv->last_offset + lv->barview.cur_visible ) ) { + offset = lv->selected; + lv->rchanged = TRUE; + } + return offset; + +} static unsigned int scroll_per_page ( listview * lv ) { int offset = 0; @@ -154,6 +191,84 @@ static void update_element ( listview *lv, unsigned int tb, unsigned int index, } } +static void barview_draw ( widget *wid, cairo_t *draw ) +{ + unsigned int offset = 0; + listview *lv = (listview *) wid; + offset = scroll_per_page_barview ( lv ); + lv->last_offset = offset; + int spacing_hori = distance_get_pixel ( lv->spacing, ORIENTATION_HORIZONTAL ); + + int left_offset = widget_padding_get_left ( wid ); + int right_offset = lv->widget.w - widget_padding_get_right( wid ); + int top_offset = widget_padding_get_top ( wid ); + if ( lv->cur_elements > 0 ) { + // Set new x/y possition. + unsigned int max = MIN ( lv->cur_elements, lv->req_elements - offset ); + if ( lv->rchanged ) { + int first = TRUE; + int width = lv->widget.w; + lv->barview.cur_visible = 0; + width -= widget_padding_get_padding_width ( wid ); + if ( lv->barview.direction == LEFT_TO_RIGHT ) { + for ( unsigned int i = 0; i < max&& width > 0; i++ ) { + update_element ( lv, i, i + offset, TRUE ); + int twidth = textbox_get_desired_width ( WIDGET(lv->boxes[i])); + if ( twidth >= width ) { + if ( ! first ) { + break; + } + twidth = width; + } + textbox_moveresize ( lv->boxes[i], left_offset, top_offset, twidth, lv->element_height ); + + widget_draw ( WIDGET ( lv->boxes[i] ), draw ); + width -= twidth + spacing_hori; + left_offset += twidth + spacing_hori; + first = FALSE; + lv->barview.cur_visible++ ; + } + } else { + for ( unsigned int i = 0; i < lv->cur_elements && width > 0 && i <= offset; i++ ) { + update_element ( lv, i, offset-i, TRUE ); + int twidth = textbox_get_desired_width ( WIDGET ( lv->boxes[i] )); + if ( twidth >= width ) { + if ( ! first ) { + break; + } + twidth = width; + } + right_offset -= twidth; + textbox_moveresize ( lv->boxes[i], right_offset, top_offset, twidth, lv->element_height ); + + widget_draw ( WIDGET ( lv->boxes[i] ), draw ); + width -= twidth + spacing_hori; + right_offset -= spacing_hori; + first = FALSE; + lv->barview.cur_visible++ ; + } + offset -= lv->barview.cur_visible-1; + lv->last_offset = offset; + for ( unsigned int i = 0; i < (lv->barview.cur_visible/2); i++) + { + void * temp = lv->boxes[i]; + int sw = lv->barview.cur_visible-i-1; + lv->boxes[i] = lv->boxes[sw]; + lv->boxes[sw] = temp; + } + + } + lv->rchanged = FALSE; + } + else { + for ( unsigned int i = 0; i < lv->barview.cur_visible; i++ ) { + update_element ( lv, i, i + offset, FALSE ); + widget_draw ( WIDGET ( lv->boxes[i] ), draw ); + } + } + } +} + static void listview_draw ( widget *wid, cairo_t *draw ) { unsigned int offset = 0; @@ -218,9 +333,18 @@ static void listview_draw ( widget *wid, cairo_t *draw ) } widget_draw ( WIDGET ( lv->scrollbar ), draw ); } - static WidgetTriggerActionResult listview_element_trigger_action ( widget *wid, MouseBindingListviewElementAction action, gint x, gint y, void *user_data ); +static void _listview_draw ( widget *wid, cairo_t *draw ) +{ + listview *lv = (listview *)wid; + if ( lv->type == LISTVIEW ) + { + listview_draw ( wid, draw ); + } else { + barview_draw ( wid, draw ); + } +} static void listview_recompute_elements ( listview *lv ) { unsigned int newne = 0; @@ -255,6 +379,9 @@ static void listview_recompute_elements ( listview *lv ) void listview_set_num_elements ( listview *lv, unsigned int rows ) { + if ( lv == NULL ) { + return; + } lv->req_elements = rows; listview_set_selected ( lv, lv->selected ); listview_recompute_elements ( lv ); @@ -273,6 +400,7 @@ void listview_set_selected ( listview *lv, unsigned int selected ) { if ( lv && lv->req_elements > 0 ) { lv->selected = MIN ( selected, lv->req_elements - 1 ); + lv->barview.direction = LEFT_TO_RIGHT; widget_queue_redraw ( WIDGET ( lv ) ); } } @@ -299,6 +427,10 @@ static void listview_resize ( widget *wid, short w, short h ) } widget_resize ( WIDGET ( lv->scrollbar ), widget_get_width ( WIDGET ( lv->scrollbar ) ), height ); + if ( lv->type == BARVIEW ) { + lv->max_elements = lv->menu_lines; + } + listview_recompute_elements ( lv ); widget_queue_redraw ( wid ); } @@ -385,7 +517,7 @@ listview *listview_create ( const char *name, listview_update_callback cb, void lv->listview_name = g_strdup ( name ); lv->widget.free = listview_free; lv->widget.resize = listview_resize; - lv->widget.draw = listview_draw; + lv->widget.draw = _listview_draw; lv->widget.find_mouse_target = listview_find_mouse_target; lv->widget.trigger_action = listview_trigger_action; lv->widget.get_desired_height = listview_get_desired_height; @@ -415,9 +547,14 @@ listview *listview_create ( const char *name, listview_update_callback cb, void lv->fixed_num_lines = rofi_theme_get_boolean ( WIDGET ( lv ), "fixed-height", config.fixed_num_lines ); lv->dynamic = rofi_theme_get_boolean ( WIDGET ( lv ), "dynamic", TRUE ); lv->reverse = rofi_theme_get_boolean ( WIDGET ( lv ), "reverse", reverse ); - listview_set_show_scrollbar ( lv, rofi_theme_get_boolean ( WIDGET ( lv ), "scrollbar", FALSE ) ); lv->cycle = rofi_theme_get_boolean ( WIDGET ( lv ), "cycle", config.cycle ); + lv->type = rofi_theme_get_boolean ( WIDGET (lv) , "barview", FALSE ); + if ( lv->type == LISTVIEW ) { + listview_set_show_scrollbar ( lv, rofi_theme_get_boolean ( WIDGET ( lv ), "scrollbar", FALSE ) ); + } else { + listview_set_show_scrollbar ( lv, FALSE ); + } return lv; } @@ -437,6 +574,7 @@ static void listview_nav_up_int ( listview *lv ) lv->selected = lv->req_elements; } lv->selected--; + lv->barview.direction = RIGHT_TO_LEFT; widget_queue_redraw ( WIDGET ( lv ) ); } static void listview_nav_down_int ( listview *lv ) @@ -448,7 +586,7 @@ static void listview_nav_down_int ( listview *lv ) return; } lv->selected = lv->selected < lv->req_elements - 1 ? MIN ( lv->req_elements - 1, lv->selected + 1 ) : 0; - + lv->barview.direction = LEFT_TO_RIGHT; widget_queue_redraw ( WIDGET ( lv ) ); } @@ -482,6 +620,10 @@ void listview_nav_left ( listview *lv ) if ( lv == NULL ) { return; } + if ( lv->type == BARVIEW ){ + listview_nav_up_int(lv); + return; + } if ( lv->selected >= lv->max_rows ) { lv->selected -= lv->max_rows; widget_queue_redraw ( WIDGET ( lv ) ); @@ -492,6 +634,10 @@ void listview_nav_right ( listview *lv ) if ( lv == NULL ) { return; } + if ( lv->type == BARVIEW ){ + listview_nav_down_int(lv); + return; + } if ( ( lv->selected + lv->max_rows ) < lv->req_elements ) { lv->selected += lv->max_rows; widget_queue_redraw ( WIDGET ( lv ) ); @@ -516,6 +662,18 @@ static void listview_nav_page_prev_int ( listview *lv ) if ( lv == NULL ) { return; } + if ( lv->type == BARVIEW ){ + + if ( lv->last_offset == 0 ){ + lv->selected = 0; + } else { + lv->selected = lv->last_offset-1; + } + lv->barview.direction = RIGHT_TO_LEFT; + widget_queue_redraw ( WIDGET ( lv ) ); + return; + } + if ( lv->selected < lv->max_elements ) { lv->selected = 0; } @@ -532,6 +690,14 @@ static void listview_nav_page_next_int ( listview *lv ) if ( lv->req_elements == 0 ) { return; } + if ( lv->type == BARVIEW ) { + unsigned int new = lv->last_offset+lv->barview.cur_visible; + lv->selected = MIN ( new, lv->req_elements-1); + lv->barview.direction = LEFT_TO_RIGHT; + + widget_queue_redraw ( WIDGET ( lv ) ); + return; + } lv->selected += ( lv->max_elements ); if ( lv->selected >= lv->req_elements ) { lv->selected = lv->req_elements - 1; @@ -580,6 +746,9 @@ static int listview_get_desired_height ( widget *wid ) h = MIN ( lv->menu_lines, lv->max_displayed_lines ); } } + if ( lv->type == BARVIEW ){ + h = MIN ( h, 1 ); + } if ( h == 0 ) { if ( lv->dynamic && !lv->fixed_num_lines ) { // Hide widget fully. diff --git a/source/widgets/textbox.c b/source/widgets/textbox.c index ea6c4824..6c978b12 100644 --- a/source/widgets/textbox.c +++ b/source/widgets/textbox.c @@ -137,6 +137,7 @@ textbox* textbox_create_full ( WidgetType type, const char *name, TextboxFlags f tb->widget.get_width = textbox_get_width; tb->widget.get_height = _textbox_get_height; tb->widget.get_desired_height = textbox_get_desired_height; + tb->widget.get_desired_width = textbox_get_desired_width; tb->flags = flags; tb->changed = FALSE; @@ -175,7 +176,9 @@ textbox* textbox_creat |