mirror of
				https://github.com/labwc/labwc.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	theme: create hover button fallbacks
...by copying the non-hover variant and adding a transparent overlay. Co-authored-by: @johanmalm
This commit is contained in:
		
							parent
							
								
									d207e97992
								
							
						
					
					
						commit
						27de4e6398
					
				
					 6 changed files with 150 additions and 0 deletions
				
			
		| 
						 | 
					@ -47,4 +47,14 @@ void set_cairo_color(cairo_t *cairo, float *color);
 | 
				
			||||||
/* Draws a border with a specified line width */
 | 
					/* Draws a border with a specified line width */
 | 
				
			||||||
void draw_cairo_border(cairo_t *cairo, struct wlr_fbox fbox, double line_width);
 | 
					void draw_cairo_border(cairo_t *cairo, struct wlr_fbox fbox, double line_width);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct lab_data_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct surface_context {
 | 
				
			||||||
 | 
						bool is_duplicate;
 | 
				
			||||||
 | 
						cairo_surface_t *surface;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct surface_context get_cairo_surface_from_lab_data_buffer(
 | 
				
			||||||
 | 
						struct lab_data_buffer *buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* LABWC_GRAPHIC_HELPERS_H */
 | 
					#endif /* LABWC_GRAPHIC_HELPERS_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,15 @@
 | 
				
			||||||
#ifndef LABWC_STRING_HELPERS_H
 | 
					#ifndef LABWC_STRING_HELPERS_H
 | 
				
			||||||
#define LABWC_STRING_HELPERS_H
 | 
					#define LABWC_STRING_HELPERS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * trim_last_field() - Trim last field of string splitting on provided delim
 | 
				
			||||||
 | 
					 * @buf: string to trim
 | 
				
			||||||
 | 
					 * @delim: delimitator
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Example: With delim='_' and buf="foo_bar_baz" the return value is "foo_bar"
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void trim_last_field(char *buf, char delim);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * string_strip - strip white space left and right
 | 
					 * string_strip - strip white space left and right
 | 
				
			||||||
 * Note: this function does a left skip, so the returning pointer cannot be
 | 
					 * Note: this function does a left skip, so the returning pointer cannot be
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,6 +129,8 @@ buffer_create_wrap(void *pixel_data, uint32_t width, uint32_t height,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct lab_data_buffer *buffer = znew(*buffer);
 | 
						struct lab_data_buffer *buffer = znew(*buffer);
 | 
				
			||||||
	wlr_buffer_init(&buffer->base, &data_buffer_impl, width, height);
 | 
						wlr_buffer_init(&buffer->base, &data_buffer_impl, width, height);
 | 
				
			||||||
 | 
						buffer->unscaled_width = width;
 | 
				
			||||||
 | 
						buffer->unscaled_height = height;
 | 
				
			||||||
	buffer->data = pixel_data;
 | 
						buffer->data = pixel_data;
 | 
				
			||||||
	buffer->format = DRM_FORMAT_ARGB8888;
 | 
						buffer->format = DRM_FORMAT_ARGB8888;
 | 
				
			||||||
	buffer->stride = stride;
 | 
						buffer->stride = stride;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,8 +3,10 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <cairo.h>
 | 
					#include <cairo.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
#include <wlr/types/wlr_scene.h>
 | 
					#include <wlr/types/wlr_scene.h>
 | 
				
			||||||
#include <wlr/util/box.h>
 | 
					#include <wlr/util/box.h>
 | 
				
			||||||
 | 
					#include "buffer.h"
 | 
				
			||||||
#include "common/graphic-helpers.h"
 | 
					#include "common/graphic-helpers.h"
 | 
				
			||||||
#include "common/mem.h"
 | 
					#include "common/mem.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,3 +87,32 @@ set_cairo_color(cairo_t *cairo, float *c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	cairo_set_source_rgba(cairo, c[0], c[1], c[2], c[3]);
 | 
						cairo_set_source_rgba(cairo, c[0], c[1], c[2], c[3]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct surface_context
 | 
				
			||||||
 | 
					get_cairo_surface_from_lab_data_buffer(struct lab_data_buffer *buffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Handle CAIRO_FORMAT_ARGB32 buffers */
 | 
				
			||||||
 | 
						if (buffer->cairo) {
 | 
				
			||||||
 | 
							return (struct surface_context){
 | 
				
			||||||
 | 
								.is_duplicate = false,
 | 
				
			||||||
 | 
								.surface = cairo_get_target(buffer->cairo),
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Handle DRM_FORMAT_ARGB8888 buffers */
 | 
				
			||||||
 | 
						int w = buffer->unscaled_width;
 | 
				
			||||||
 | 
						int h = buffer->unscaled_height;
 | 
				
			||||||
 | 
						cairo_surface_t *surface =
 | 
				
			||||||
 | 
							cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
 | 
				
			||||||
 | 
						if (!surface) {
 | 
				
			||||||
 | 
							return (struct surface_context){0};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						unsigned char *data = cairo_image_surface_get_data(surface);
 | 
				
			||||||
 | 
						cairo_surface_flush(surface);
 | 
				
			||||||
 | 
						memcpy(data, buffer->data, h * buffer->stride);
 | 
				
			||||||
 | 
						cairo_surface_mark_dirty(surface);
 | 
				
			||||||
 | 
						return (struct surface_context){
 | 
				
			||||||
 | 
							.is_duplicate = true,
 | 
				
			||||||
 | 
							.surface = surface,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,15 @@
 | 
				
			||||||
#include "common/mem.h"
 | 
					#include "common/mem.h"
 | 
				
			||||||
#include "common/string-helpers.h"
 | 
					#include "common/string-helpers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					trim_last_field(char *buf, char delim)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *p = strrchr(buf, delim);
 | 
				
			||||||
 | 
						if (p) {
 | 
				
			||||||
 | 
							*p = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
rtrim(char **s)
 | 
					rtrim(char **s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										89
									
								
								src/theme.c
									
										
									
									
									
								
							
							
						
						
									
										89
									
								
								src/theme.c
									
										
									
									
									
								
							| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define _POSIX_C_SOURCE 200809L
 | 
					#define _POSIX_C_SOURCE 200809L
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
#include <cairo.h>
 | 
					#include <cairo.h>
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include <drm_fourcc.h>
 | 
					#include <drm_fourcc.h>
 | 
				
			||||||
| 
						 | 
					@ -56,6 +57,61 @@ drop(struct lab_data_buffer **buffer)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					create_hover_fallback(struct theme *theme, struct lab_data_buffer **hover_buffer,
 | 
				
			||||||
 | 
							struct lab_data_buffer *icon_buffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						assert(icon_buffer);
 | 
				
			||||||
 | 
						assert(!*hover_buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct surface_context icon =
 | 
				
			||||||
 | 
							get_cairo_surface_from_lab_data_buffer(icon_buffer);
 | 
				
			||||||
 | 
						int icon_width = cairo_image_surface_get_width(icon.surface);
 | 
				
			||||||
 | 
						int icon_height = cairo_image_surface_get_height(icon.surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: need to somehow respect rounded corners */
 | 
				
			||||||
 | 
						int width = SSD_BUTTON_WIDTH;
 | 
				
			||||||
 | 
						int height = theme->title_height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (width && height) {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Proportionately increase size of hover_buffer if the
 | 
				
			||||||
 | 
							 * non-hover 'donor' buffer is larger than the allocated space.
 | 
				
			||||||
 | 
							 * It will get scaled down again by wlroots when rendered and as
 | 
				
			||||||
 | 
							 * required by the current output scale.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * This ensures that icons > width or > height keep their aspect
 | 
				
			||||||
 | 
							 * ratio and are rendered the same as without the hover overlay.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							double scale = MAX((double)icon_width / width,
 | 
				
			||||||
 | 
									(double)icon_height / height);
 | 
				
			||||||
 | 
							if (scale > 1.0f) {
 | 
				
			||||||
 | 
								width = (double)width * scale;
 | 
				
			||||||
 | 
								height = (double)height * scale;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*hover_buffer = buffer_create_cairo(width, height, 1.0, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cairo_t *cairo = (*hover_buffer)->cairo;
 | 
				
			||||||
 | 
						cairo_surface_t *surf = cairo_get_target(cairo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Background */
 | 
				
			||||||
 | 
						cairo_set_source_surface(cairo, icon.surface,
 | 
				
			||||||
 | 
							(width - icon_width) / 2, (height - icon_height) / 2);
 | 
				
			||||||
 | 
						cairo_paint(cairo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Overlay (non-multiplied alpha) */
 | 
				
			||||||
 | 
						set_cairo_color(cairo, (float[4]) { 0.5f, 0.5f, 0.5f, 0.3f});
 | 
				
			||||||
 | 
						cairo_rectangle(cairo, 0, 0, width, height);
 | 
				
			||||||
 | 
						cairo_fill(cairo);
 | 
				
			||||||
 | 
						cairo_surface_flush(surf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (icon.is_duplicate) {
 | 
				
			||||||
 | 
							cairo_surface_destroy(icon.surface);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * We use the following button filename schema: "BUTTON [TOGGLED] [STATE]"
 | 
					 * We use the following button filename schema: "BUTTON [TOGGLED] [STATE]"
 | 
				
			||||||
 * with the words separted by underscore, and the following meaning:
 | 
					 * with the words separted by underscore, and the following meaning:
 | 
				
			||||||
| 
						 | 
					@ -204,6 +260,39 @@ load_buttons(struct theme *theme)
 | 
				
			||||||
				b->fallback_button, b->inactive.rgba);
 | 
									b->fallback_button, b->inactive.rgba);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If hover-icons do not exist, add fallbacks by coping the non-hover
 | 
				
			||||||
 | 
						 * variant (base) and then adding an overlay.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						for (size_t i = 0; i < ARRAY_SIZE(buttons); i++) {
 | 
				
			||||||
 | 
							struct button *hover_button = &buttons[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!strstr(hover_button->name, "_hover")) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* If name=='foo_hover', basename='foo' */
 | 
				
			||||||
 | 
							char basename[64]  = {0};
 | 
				
			||||||
 | 
							snprintf(basename, sizeof(basename), "%s", hover_button->name);
 | 
				
			||||||
 | 
							trim_last_field(basename, '_');
 | 
				
			||||||
 | 
							for (size_t j = 0; j < ARRAY_SIZE(buttons); j++) {
 | 
				
			||||||
 | 
								struct button *base = &buttons[j];
 | 
				
			||||||
 | 
								if (!strcmp(basename, base->name)) {
 | 
				
			||||||
 | 
									if (!*hover_button->active.buffer) {
 | 
				
			||||||
 | 
										create_hover_fallback(theme,
 | 
				
			||||||
 | 
											hover_button->active.buffer,
 | 
				
			||||||
 | 
											*base->active.buffer);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (!*hover_button->inactive.buffer) {
 | 
				
			||||||
 | 
										create_hover_fallback(theme,
 | 
				
			||||||
 | 
											hover_button->inactive.buffer,
 | 
				
			||||||
 | 
											*base->inactive.buffer);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue