1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
#include "deco-theme.hpp"
#include <wayfire/core.hpp>
#include <wayfire/opengl.hpp>
#include <config.h>
namespace wf
{
namespace decor
{
/** Create a new theme with the default parameters */
decoration_theme_t::decoration_theme_t()
{}
/** @return The available height for displaying the title */
int decoration_theme_t::get_title_height() const
{
return title_height;
}
/** @return The available border for resizing */
int decoration_theme_t::get_border_size() const
{
return border_size;
}
/** @return The available border for resizing */
void decoration_theme_t::set_buttons(button_type_t flags)
{
button_flags = flags;
}
/**
* Fill the given rectangle with the background color(s).
*
* @param fb The target framebuffer, must have been bound already
* @param rectangle The rectangle to redraw.
* @param scissor The GL scissor rectangle to use.
* @param active Whether to use active or inactive colors
*/
void decoration_theme_t::render_background(const wf::scene::render_instruction_t& data,
wf::geometry_t rectangle, bool active) const
{
wf::color_t color = active ? active_color : inactive_color;
data.pass->add_rect(color, data.target, rectangle, data.damage);
}
/**
* Render the given text on a cairo_surface_t with the given size.
* The caller is responsible for freeing the memory afterwards.
*/
cairo_surface_t*decoration_theme_t::render_text(std::string text,
int width, int height) const
{
const auto format = CAIRO_FORMAT_ARGB32;
auto surface = cairo_image_surface_create(format, width, height);
if (height == 0)
{
return surface;
}
wf::color_t color = font_color;
auto cr = cairo_create(surface);
const float font_scale = 0.8;
const float font_size = height * font_scale;
PangoFontDescription *font_desc;
PangoLayout *layout;
// render text
font_desc = pango_font_description_from_string(((std::string)font).c_str());
pango_font_description_set_absolute_size(font_desc, font_size * PANGO_SCALE);
layout = pango_cairo_create_layout(cr);
pango_layout_set_font_description(layout, font_desc);
pango_layout_set_text(layout, text.c_str(), text.size());
cairo_set_source_rgba(cr, color.r, color.g, color.b, color.a);
pango_cairo_show_layout(cr, layout);
pango_font_description_free(font_desc);
g_object_unref(layout);
cairo_destroy(cr);
return surface;
}
cairo_surface_t*decoration_theme_t::get_button_surface(button_type_t button,
const button_state_t& state) const
{
cairo_surface_t *button_surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, state.width, state.height);
auto cr = cairo_create(button_surface);
cairo_set_antialias(cr, CAIRO_ANTIALIAS_BEST);
/* Clear the button background */
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_rectangle(cr, 0, 0, state.width, state.height);
cairo_fill(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
/** A gray that looks good on light and dark themes */
color_t base = {0.60, 0.60, 0.63, 0.36};
/**
* We just need the alpha component.
* r == g == b == 0.0 will be directly set
*/
double line = 0.27;
double hover = 0.27;
/** Coloured base on hover/press. Don't compare float to 0 */
if (fabs(state.hover_progress) > 1e-3)
{
switch (button)
{
case BUTTON_CLOSE:
base = {242.0 / 255.0, 80.0 / 255.0, 86.0 / 255.0, 0.63};
break;
case BUTTON_TOGGLE_MAXIMIZE:
base = {57.0 / 255.0, 234.0 / 255.0, 73.0 / 255.0, 0.63};
break;
case BUTTON_MINIMIZE:
base = {250.0 / 255.0, 198.0 / 255.0, 54.0 / 255.0, 0.63};
break;
default:
assert(false);
}
line *= 2.0;
}
/** Draw the base */
cairo_set_source_rgba(cr,
base.r + 0.0 * state.hover_progress,
base.g + 0.0 * state.hover_progress,
base.b + 0.0 * state.hover_progress,
base.a + hover * state.hover_progress);
cairo_arc(cr, state.width / 2, state.height / 2,
state.width / 2, 0, 2 * M_PI);
cairo_fill(cr);
/** Draw the border */
cairo_set_line_width(cr, state.border);
cairo_set_source_rgba(cr, 0.00, 0.00, 0.00, line);
// This renders great on my screen (110 dpi 1376x768 lcd screen)
// How this would appear on a Hi-DPI screen is questionable
double r = state.width / 2 - 0.5 * state.border;
cairo_arc(cr, state.width / 2, state.height / 2, r, 0, 2 * M_PI);
cairo_stroke(cr);
/** Draw the icon */
cairo_set_source_rgba(cr, 0.00, 0.00, 0.00, line / 2);
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
switch (button)
{
case BUTTON_CLOSE:
cairo_set_line_width(cr, 1.5 * state.border);
cairo_move_to(cr, 1.0 * state.width / 4.0,
1.0 * state.height / 4.0);
cairo_line_to(cr, 3.0 * state.width / 4.0,
3.0 * state.height / 4.0); // '\' part of x
cairo_move_to(cr, 3.0 * state.width / 4.0,
1.0 * state.height / 4.0);
cairo_line_to(cr, 1.0 * state.width / 4.0,
3.0 * state.height / 4.0); // '/' part of x
cairo_stroke(cr);
break;
case BUTTON_TOGGLE_MAXIMIZE:
cairo_set_line_width(cr, 1.5 * state.border);
cairo_rectangle(
cr, // Context
state.width / 4.0, state.height / 4.0, // (x, y)
state.width / 2.0, state.height / 2.0 // w x h
);
cairo_stroke(cr);
break;
case BUTTON_MINIMIZE:
cairo_set_line_width(cr, 1.75 * state.border);
cairo_move_to(cr, 1.0 * state.width / 4.0,
state.height / 2.0);
cairo_line_to(cr, 3.0 * state.width / 4.0,
state.height / 2.0);
cairo_stroke(cr);
break;
default:
assert(false);
}
cairo_fill(cr);
cairo_destroy(cr);
return button_surface;
}
}
}
|