mirror of
https://github.com/labwc/labwc.git
synced 2025-11-04 13:30:07 -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