mirror of
				https://github.com/labwc/labwc.git
				synced 2025-10-29 05:40:24 -04:00 
			
		
		
		
	theme: add button padding and spacing (#2127)
While at it, separate corner width from button width. Both are independed and having them separately improves readability.
This commit is contained in:
		
							parent
							
								
									8850368ab9
								
							
						
					
					
						commit
						824b0fa4e3
					
				
					 13 changed files with 105 additions and 39 deletions
				
			
		|  | @ -47,12 +47,18 @@ labwc-config(5). | |||
| # THEME ELEMENTS | ||||
| 
 | ||||
| *border.width* | ||||
| 	Line width (integer) of border border drawn around window frames. | ||||
| 	Line width (integer) of border drawn around window frames. | ||||
| 	Default is 1. | ||||
| 
 | ||||
| *padding.width* | ||||
| 	Horizontal padding size, in pixels, between border and first | ||||
| 	button on the left/right. | ||||
| 	Default is 0. | ||||
| 
 | ||||
| *padding.height* | ||||
| 	Vertical padding size, used for spacing out elements in the window | ||||
| 	decorations. Default is 3. | ||||
| 	Vertical padding size, in pixels, used for spacing out elements | ||||
| 	in the window decorations. | ||||
| 	Default is 3. | ||||
| 
 | ||||
| *titlebar.height* | ||||
| 	Window title bar height. | ||||
|  | @ -122,6 +128,10 @@ labwc-config(5). | |||
| 	Width of a titlebar button, in pixels. | ||||
| 	Default is 26. | ||||
| 
 | ||||
| *window.button.spacing* | ||||
| 	Space between titlebar buttons, in pixels. | ||||
| 	Default is 0. | ||||
| 
 | ||||
| *window.active.button.unpressed.image.color* | ||||
| 	Color of the images in titlebar buttons in their default, unpressed, | ||||
| 	state. This element is for the focused window. | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| 
 | ||||
| # general | ||||
| border.width: 1 | ||||
| padding.width: 0 | ||||
| padding.height: 3 | ||||
| 
 | ||||
| # The following options has no default, but fallbacks back to | ||||
|  | @ -29,8 +30,9 @@ window.active.label.text.color: #000000 | |||
| window.inactive.label.text.color: #000000 | ||||
| window.label.text.justify: center | ||||
| 
 | ||||
| # window button width | ||||
| # window button width and spacing | ||||
| window.button.width: 26 | ||||
| window.button.spacing: 0 | ||||
| 
 | ||||
| # window buttons | ||||
| window.active.button.unpressed.image.color: #000000 | ||||
|  |  | |||
|  | @ -79,6 +79,7 @@ struct wlr_scene_node; | |||
|  */ | ||||
| struct ssd *ssd_create(struct view *view, bool active); | ||||
| struct border ssd_get_margin(const struct ssd *ssd); | ||||
| int ssd_get_corner_width(void); | ||||
| void ssd_update_margin(struct ssd *ssd); | ||||
| void ssd_set_active(struct ssd *ssd, bool active); | ||||
| void ssd_update_title(struct ssd *ssd); | ||||
|  |  | |||
|  | @ -27,7 +27,14 @@ struct theme_snapping_overlay { | |||
| 
 | ||||
| struct theme { | ||||
| 	int border_width; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * the space between title bar border and | ||||
| 	 * buttons on the left/right/top | ||||
| 	 */ | ||||
| 	int padding_width; | ||||
| 	int padding_height; | ||||
| 
 | ||||
| 	int title_height; | ||||
| 	int menu_overlap_x; | ||||
| 	int menu_overlap_y; | ||||
|  | @ -48,6 +55,8 @@ struct theme { | |||
| 
 | ||||
| 	/* button width */ | ||||
| 	int window_button_width; | ||||
| 	/* the space between buttons */ | ||||
| 	int window_button_spacing; | ||||
| 
 | ||||
| 	/* button colors */ | ||||
| 	float window_active_button_menu_unpressed_image_color[4]; | ||||
|  |  | |||
|  | @ -538,6 +538,7 @@ const char *view_get_string_prop(struct view *view, const char *prop); | |||
| void view_update_title(struct view *view); | ||||
| void view_update_app_id(struct view *view); | ||||
| void view_reload_ssd(struct view *view); | ||||
| int view_get_min_width(void); | ||||
| 
 | ||||
| void view_set_shade(struct view *view, bool shaded); | ||||
| 
 | ||||
|  |  | |||
|  | @ -220,8 +220,7 @@ snap_shrink_to_next_edge(struct view *view, | |||
| 
 | ||||
| 	*geo = view->pending; | ||||
| 	uint32_t resize_edges; | ||||
| 	int min_view_width = rc.theme->window_button_width * ( | ||||
| 		wl_list_length(&rc.title_buttons_left) + wl_list_length(&rc.title_buttons_right)); | ||||
| 	int min_width = view_get_min_width(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * First shrink the view along the relevant edge. The maximum shrink | ||||
|  | @ -230,12 +229,12 @@ snap_shrink_to_next_edge(struct view *view, | |||
| 	 */ | ||||
| 	switch (direction) { | ||||
| 	case VIEW_EDGE_RIGHT: | ||||
| 		geo->width = MAX(geo->width / 2, min_view_width); | ||||
| 		geo->width = MAX(geo->width / 2, min_width); | ||||
| 		geo->x = view->pending.x + view->pending.width - geo->width; | ||||
| 		resize_edges = WLR_EDGE_LEFT; | ||||
| 		break; | ||||
| 	case VIEW_EDGE_LEFT: | ||||
| 		geo->width = MAX(geo->width / 2, min_view_width); | ||||
| 		geo->width = MAX(geo->width / 2, min_width); | ||||
| 		resize_edges = WLR_EDGE_RIGHT; | ||||
| 		break; | ||||
| 	case VIEW_EDGE_DOWN: | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ ssd_border_create(struct ssd *ssd) | |||
| 	int width = view->current.width; | ||||
| 	int height = view_effective_height(view, /* use_pending */ false); | ||||
| 	int full_width = width + 2 * theme->border_width; | ||||
| 	int corner_width = ssd_get_corner_width(); | ||||
| 
 | ||||
| 	float *color; | ||||
| 	struct wlr_scene_tree *parent; | ||||
|  | @ -48,8 +49,8 @@ ssd_border_create(struct ssd *ssd) | |||
| 		add_scene_rect(&subtree->parts, LAB_SSD_PART_BOTTOM, parent, | ||||
| 			full_width, theme->border_width, 0, height, color); | ||||
| 		add_scene_rect(&subtree->parts, LAB_SSD_PART_TOP, parent, | ||||
| 			width - 2 * theme->window_button_width, theme->border_width, | ||||
| 			theme->border_width + theme->window_button_width, | ||||
| 			width - 2 * corner_width, theme->border_width, | ||||
| 			theme->border_width + corner_width, | ||||
| 			-(ssd->titlebar.height + theme->border_width), color); | ||||
| 	} FOR_EACH_END | ||||
| 
 | ||||
|  | @ -93,6 +94,7 @@ ssd_border_update(struct ssd *ssd) | |||
| 	int width = view->current.width; | ||||
| 	int height = view_effective_height(view, /* use_pending */ false); | ||||
| 	int full_width = width + 2 * theme->border_width; | ||||
| 	int corner_width = ssd_get_corner_width(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * From here on we have to cover the following border scenarios: | ||||
|  | @ -121,10 +123,10 @@ ssd_border_update(struct ssd *ssd) | |||
| 		: 0; | ||||
| 	int top_width = ssd->titlebar.height <= 0 || ssd->state.was_squared | ||||
| 		? full_width | ||||
| 		: width - 2 * theme->window_button_width; | ||||
| 		: width - 2 * corner_width; | ||||
| 	int top_x = ssd->titlebar.height <= 0 || ssd->state.was_squared | ||||
| 		? 0 | ||||
| 		: theme->border_width + theme->window_button_width; | ||||
| 		: theme->border_width + corner_width; | ||||
| 
 | ||||
| 	struct ssd_part *part; | ||||
| 	struct wlr_scene_rect *rect; | ||||
|  |  | |||
|  | @ -76,8 +76,9 @@ ssd_extents_update(struct ssd *ssd) | |||
| 	int full_height = height + theme->border_width * 2 + ssd->titlebar.height; | ||||
| 	int full_width = width + 2 * theme->border_width; | ||||
| 	int extended_area = SSD_EXTENDED_AREA; | ||||
| 	int corner_width = ssd_get_corner_width(); | ||||
| 	int corner_size = extended_area + theme->border_width + | ||||
| 		MIN(theme->window_button_width, width) / 2; | ||||
| 		MIN(corner_width, width) / 2; | ||||
| 	int side_width = full_width + extended_area * 2 - corner_size * 2; | ||||
| 	int side_height = full_height + extended_area * 2 - corner_size * 2; | ||||
| 
 | ||||
|  |  | |||
|  | @ -116,6 +116,7 @@ ssd_titlebar_create(struct ssd *ssd) | |||
| 	struct view *view = ssd->view; | ||||
| 	struct theme *theme = view->server->theme; | ||||
| 	int width = view->current.width; | ||||
| 	int corner_width = ssd_get_corner_width(); | ||||
| 
 | ||||
| 	float *color; | ||||
| 	struct wlr_scene_tree *parent; | ||||
|  | @ -144,25 +145,25 @@ ssd_titlebar_create(struct ssd *ssd) | |||
| 
 | ||||
| 		/* Background */ | ||||
| 		add_scene_rect(&subtree->parts, LAB_SSD_PART_TITLEBAR, parent, | ||||
| 			width - theme->window_button_width * 2, theme->title_height, | ||||
| 			theme->window_button_width, 0, color); | ||||
| 			width - corner_width * 2, theme->title_height, | ||||
| 			corner_width, 0, color); | ||||
| 		add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_LEFT, parent, | ||||
| 			corner_top_left, -rc.theme->border_width, -rc.theme->border_width); | ||||
| 		add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT, parent, | ||||
| 			corner_top_right, width - theme->window_button_width, | ||||
| 			corner_top_right, width - corner_width, | ||||
| 			-rc.theme->border_width); | ||||
| 
 | ||||
| 		/* Buttons */ | ||||
| 		struct title_button *b; | ||||
| 		int x = 0; | ||||
| 		int x = theme->padding_width; | ||||
| 		wl_list_for_each(b, &rc.title_buttons_left, link) { | ||||
| 			add_button(ssd, subtree, b->type, x); | ||||
| 			x += theme->window_button_width; | ||||
| 			x += theme->window_button_width + theme->window_button_spacing; | ||||
| 		} | ||||
| 
 | ||||
| 		x = width; | ||||
| 		x = width - theme->padding_width + theme->window_button_spacing; | ||||
| 		wl_list_for_each_reverse(b, &rc.title_buttons_right, link) { | ||||
| 			x -= theme->window_button_width; | ||||
| 			x -= theme->window_button_width + theme->window_button_spacing; | ||||
| 			add_button(ssd, subtree, b->type, x); | ||||
| 		} | ||||
| 	} FOR_EACH_END | ||||
|  | @ -197,11 +198,12 @@ set_squared_corners(struct ssd *ssd, bool enable) | |||
| { | ||||
| 	struct view *view = ssd->view; | ||||
| 	int width = view->current.width; | ||||
| 	int corner_width = ssd_get_corner_width(); | ||||
| 	struct theme *theme = view->server->theme; | ||||
| 
 | ||||
| 	struct ssd_part *part; | ||||
| 	struct ssd_sub_tree *subtree; | ||||
| 	int x = enable ? 0 : theme->window_button_width; | ||||
| 	int x = enable ? 0 : corner_width; | ||||
| 
 | ||||
| 	FOR_EACH_STATE(ssd, subtree) { | ||||
| 		part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR); | ||||
|  | @ -252,18 +254,23 @@ static void | |||
| update_visible_buttons(struct ssd *ssd) | ||||
| { | ||||
| 	struct view *view = ssd->view; | ||||
| 	int width = view->current.width; | ||||
| 	int width = view->current.width - (2 * view->server->theme->padding_width); | ||||
| 	int button_width = view->server->theme->window_button_width; | ||||
| 	int button_spacing = view->server->theme->window_button_spacing; | ||||
| 	int button_count_left = wl_list_length(&rc.title_buttons_left); | ||||
| 	int button_count_right = wl_list_length(&rc.title_buttons_right); | ||||
| 
 | ||||
| 	/* Make sure infinite loop never occurs */ | ||||
| 	assert(button_width > 0); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The corner-left button is lastly removed as it's usually a window | ||||
| 	 * menu button (or an app icon button in the future). | ||||
| 	 */ | ||||
| 	while (width < button_width * (button_count_left + button_count_right)) { | ||||
| 	while (width < | ||||
| 		((button_width * (button_count_left + button_count_right)) + | ||||
| 			(MAX((button_count_right - 1), 0) * button_spacing) + | ||||
| 			(MAX((button_count_left - 1), 0) * button_spacing))) { | ||||
| 		if (button_count_left > button_count_right) { | ||||
| 			button_count_left--; | ||||
| 		} else { | ||||
|  | @ -299,6 +306,7 @@ ssd_titlebar_update(struct ssd *ssd) | |||
| { | ||||
| 	struct view *view = ssd->view; | ||||
| 	int width = view->current.width; | ||||
| 	int corner_width = ssd_get_corner_width(); | ||||
| 	struct theme *theme = view->server->theme; | ||||
| 
 | ||||
| 	bool maximized = view->maximized == VIEW_AXIS_BOTH; | ||||
|  | @ -335,27 +343,29 @@ ssd_titlebar_update(struct ssd *ssd) | |||
| 	struct ssd_part *part; | ||||
| 	struct ssd_sub_tree *subtree; | ||||
| 	struct title_button *b; | ||||
| 	int bg_offset = maximized || squared ? 0 : theme->window_button_width; | ||||
| 	int bg_offset = maximized || squared ? 0 : corner_width; | ||||
| 	FOR_EACH_STATE(ssd, subtree) { | ||||
| 		part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR); | ||||
| 		wlr_scene_rect_set_size( | ||||
| 			wlr_scene_rect_from_node(part->node), | ||||
| 			width - bg_offset * 2, theme->title_height); | ||||
| 
 | ||||
| 		x = 0; | ||||
| 		x = theme->padding_width; | ||||
| 		wl_list_for_each(b, &rc.title_buttons_left, link) { | ||||
| 			part = ssd_get_part(&subtree->parts, b->type); | ||||
| 			wlr_scene_node_set_position(part->node, x, 0); | ||||
| 			x += theme->window_button_width; | ||||
| 			x += theme->window_button_width + theme->window_button_spacing; | ||||
| 		} | ||||
| 
 | ||||
| 		x = width - theme->window_button_width; | ||||
| 		x = width - corner_width; | ||||
| 		part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT); | ||||
| 		wlr_scene_node_set_position(part->node, x, -rc.theme->border_width); | ||||
| 
 | ||||
| 		x = width - theme->padding_width + theme->window_button_spacing; | ||||
| 		wl_list_for_each_reverse(b, &rc.title_buttons_right, link) { | ||||
| 			part = ssd_get_part(&subtree->parts, b->type); | ||||
| 			x -= theme->window_button_width + theme->window_button_spacing; | ||||
| 			wlr_scene_node_set_position(part->node, x, 0); | ||||
| 			x -= theme->window_button_width; | ||||
| 		} | ||||
| 	} FOR_EACH_END | ||||
| 	ssd_update_title(ssd); | ||||
|  | @ -457,19 +467,23 @@ get_title_offsets(struct ssd *ssd, int *offset_left, int *offset_right) | |||
| { | ||||
| 	struct ssd_sub_tree *subtree = &ssd->titlebar.active; | ||||
| 	int button_width = ssd->view->server->theme->window_button_width; | ||||
| 	*offset_left = 0; | ||||
| 	*offset_right = 0; | ||||
| 	int button_spacing = ssd->view->server->theme->window_button_spacing; | ||||
| 	int padding_width = ssd->view->server->theme->padding_width; | ||||
| 	*offset_left = padding_width; | ||||
| 	*offset_right = padding_width; | ||||
| 
 | ||||
| 	struct title_button *b; | ||||
| 	wl_list_for_each(b, &rc.title_buttons_left, link) { | ||||
| 		struct ssd_part *part = ssd_get_part(&subtree->parts, b->type); | ||||
| 		if (part->node->enabled) { | ||||
| 			*offset_left += *offset_left > padding_width ? button_spacing : 0; | ||||
| 			*offset_left += button_width; | ||||
| 		} | ||||
| 	} | ||||
| 	wl_list_for_each_reverse(b, &rc.title_buttons_right, link) { | ||||
| 		struct ssd_part *part = ssd_get_part(&subtree->parts, b->type); | ||||
| 		if (part->node->enabled) { | ||||
| 			*offset_right += *offset_right > padding_width ? button_spacing : 0; | ||||
| 			*offset_right += button_width; | ||||
| 		} | ||||
| 	} | ||||
|  | @ -603,10 +617,10 @@ bool | |||
| ssd_should_be_squared(struct ssd *ssd) | ||||
| { | ||||
| 	struct view *view = ssd->view; | ||||
| 	int button_width = view->server->theme->window_button_width; | ||||
| 	int corner_width = ssd_get_corner_width(); | ||||
| 
 | ||||
| 	return (view_is_tiled_and_notify_tiled(view) | ||||
| 			|| view->current.width < button_width * 2) | ||||
| 			|| view->current.width < corner_width * 2) | ||||
| 		&& view->maximized != VIEW_AXIS_BOTH; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -205,6 +205,13 @@ ssd_get_margin(const struct ssd *ssd) | |||
| 	return ssd ? ssd->margin : (struct border){ 0 }; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| ssd_get_corner_width(void) | ||||
| { | ||||
| 	/* ensure a minimum corner width */ | ||||
| 	return MAX(rc.corner_radius, 5); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| ssd_update_margin(struct ssd *ssd) | ||||
| { | ||||
|  |  | |||
							
								
								
									
										12
									
								
								src/theme.c
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								src/theme.c
									
										
									
									
									
								
							|  | @ -566,7 +566,9 @@ theme_builtin(struct theme *theme, struct server *server) | |||
| 	theme->window_label_text_justify = parse_justification("Center"); | ||||
| 	theme->menu_title_text_justify = parse_justification("Center"); | ||||
| 
 | ||||
| 	theme->padding_width = 0; | ||||
| 	theme->window_button_width = 26; | ||||
| 	theme->window_button_spacing = 0; | ||||
| 
 | ||||
| 	parse_hexstr("#000000", | ||||
| 		theme->window_active_button_menu_unpressed_image_color); | ||||
|  | @ -682,6 +684,9 @@ entry(struct theme *theme, const char *key, const char *value) | |||
| 	if (match_glob(key, "border.width")) { | ||||
| 		theme->border_width = atoi(value); | ||||
| 	} | ||||
| 	if (match_glob(key, "padding.width")) { | ||||
| 		theme->padding_width = atoi(value); | ||||
| 	} | ||||
| 	if (match_glob(key, "padding.height")) { | ||||
| 		theme->padding_height = atoi(value); | ||||
| 	} | ||||
|  | @ -745,6 +750,9 @@ entry(struct theme *theme, const char *key, const char *value) | |||
| 			theme->window_button_width = 1; | ||||
| 		} | ||||
| 	} | ||||
| 	if (match_glob(key, "window.button.spacing")) { | ||||
| 		theme->window_button_spacing = atoi(value); | ||||
| 	} | ||||
| 
 | ||||
| 	/* universal button */ | ||||
| 	if (match_glob(key, "window.active.button.unpressed.image.color")) { | ||||
|  | @ -1198,10 +1206,12 @@ out: | |||
| static void | ||||
| create_corners(struct theme *theme) | ||||
| { | ||||
| 	int corner_width = ssd_get_corner_width(); | ||||
| 
 | ||||
| 	struct wlr_box box = { | ||||
| 		.x = 0, | ||||
| 		.y = 0, | ||||
| 		.width = theme->window_button_width + theme->border_width, | ||||
| 		.width = corner_width + theme->border_width, | ||||
| 		.height = theme->title_height + theme->border_width, | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										16
									
								
								src/view.c
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								src/view.c
									
										
									
									
									
								
							|  | @ -617,8 +617,7 @@ view_adjust_size(struct view *view, int *w, int *h) | |||
| { | ||||
| 	assert(view); | ||||
| 	struct view_size_hints hints = view_get_size_hints(view); | ||||
| 	int min_view_width = rc.theme->window_button_width * ( | ||||
| 		wl_list_length(&rc.title_buttons_left) + wl_list_length(&rc.title_buttons_right)); | ||||
| 	int min_width = view_get_min_width(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * "If a base size is not provided, the minimum size is to be | ||||
|  | @ -641,7 +640,7 @@ view_adjust_size(struct view *view, int *w, int *h) | |||
| 	 * This is currently always the case for xdg-shell views. | ||||
| 	 */ | ||||
| 	if (hints.min_width < 1) { | ||||
| 		hints.min_width = min_view_width; | ||||
| 		hints.min_width = min_width; | ||||
| 	} | ||||
| 	if (hints.min_height < 1) { | ||||
| 		hints.min_height = LAB_MIN_VIEW_HEIGHT; | ||||
|  | @ -2279,6 +2278,17 @@ view_reload_ssd(struct view *view) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| int | ||||
| view_get_min_width(void) | ||||
| { | ||||
| 	int button_count_left = wl_list_length(&rc.title_buttons_left); | ||||
| 	int button_count_right =  wl_list_length(&rc.title_buttons_right); | ||||
| 	return (rc.theme->window_button_width * (button_count_left + button_count_right)) + | ||||
| 		(rc.theme->window_button_spacing * MAX((button_count_right - 1), 0)) + | ||||
| 		(rc.theme->window_button_spacing * MAX((button_count_left - 1), 0)) + | ||||
| 		(2 * rc.theme->padding_width); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| view_toggle_keybinds(struct view *view) | ||||
| { | ||||
|  |  | |||
|  | @ -606,15 +606,15 @@ handle_map_request(struct wl_listener *listener, void *data) | |||
| static void | ||||
| check_natural_geometry(struct view *view) | ||||
| { | ||||
| 	int min_width = view_get_min_width(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Some applications (example: Thonny) don't set a reasonable | ||||
| 	 * un-maximized size when started maximized. Try to detect this | ||||
| 	 * and set a fallback size. | ||||
| 	 */ | ||||
| 	int min_view_width = rc.theme->window_button_width * ( | ||||
| 		wl_list_length(&rc.title_buttons_left) + wl_list_length(&rc.title_buttons_right)); | ||||
| 	if (!view_is_floating(view) | ||||
| 			&& (view->natural_geometry.width < min_view_width | ||||
| 			&& (view->natural_geometry.width < min_width | ||||
| 			|| view->natural_geometry.height < LAB_MIN_VIEW_HEIGHT)) { | ||||
| 		view_set_fallback_natural_geometry(view); | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jens Peters
						Jens Peters