283 lines
7.9 KiB
C++
283 lines
7.9 KiB
C++
/*
|
|
* \brief Window decorator that can be styled - theme handling
|
|
* \author Norman Feske
|
|
* \date 2015-11-12
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2015 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU General Public License version 2.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <os/texture_rgb888.h>
|
|
#include <nitpicker_gfx/text_painter.h>
|
|
#include <util/xml_node.h>
|
|
#include <decorator/xml_utils.h>
|
|
|
|
/* gems includes */
|
|
#include <gems/file.h>
|
|
#include <gems/png_image.h>
|
|
|
|
/* demo includes */
|
|
#include <scout_gfx/icon_painter.h>
|
|
|
|
/* local includes */
|
|
#include "theme.h"
|
|
|
|
|
|
enum Texture_id { TEXTURE_ID_DEFAULT, TEXTURE_ID_CLOSER, TEXTURE_ID_MAXIMIZER };
|
|
|
|
|
|
struct Texture_from_png_file
|
|
{
|
|
typedef Genode::Texture<Genode::Pixel_rgb888> Texture;
|
|
|
|
File png_file;
|
|
Png_image png_image { png_file.data<void>() };
|
|
Texture &texture { *png_image.texture<Genode::Pixel_rgb888>() };
|
|
|
|
Texture_from_png_file(char const *path, Genode::Allocator &alloc)
|
|
:
|
|
png_file(path, alloc)
|
|
{ }
|
|
};
|
|
|
|
|
|
static Genode::Texture<Genode::Pixel_rgb888> const &
|
|
texture_by_id(Texture_id texture_id, Genode::Allocator &alloc)
|
|
{
|
|
if (texture_id == TEXTURE_ID_DEFAULT) {
|
|
static Texture_from_png_file texture("theme/default.png", alloc);
|
|
return texture.texture;
|
|
}
|
|
|
|
if (texture_id == TEXTURE_ID_CLOSER) {
|
|
static Texture_from_png_file texture("theme/closer.png", alloc);
|
|
return texture.texture;
|
|
}
|
|
|
|
if (texture_id == TEXTURE_ID_MAXIMIZER) {
|
|
static Texture_from_png_file texture("theme/maximizer.png", alloc);
|
|
return texture.texture;
|
|
}
|
|
|
|
struct Invalid_texture_id { };
|
|
throw Invalid_texture_id();
|
|
}
|
|
|
|
|
|
static Genode::Texture<Genode::Pixel_rgb888> const &
|
|
texture_by_element_type(Decorator::Theme::Element_type type, Genode::Allocator &alloc)
|
|
{
|
|
switch (type) {
|
|
case Decorator::Theme::ELEMENT_TYPE_CLOSER:
|
|
return texture_by_id(TEXTURE_ID_CLOSER, alloc);
|
|
|
|
case Decorator::Theme::ELEMENT_TYPE_MAXIMIZER:
|
|
return texture_by_id(TEXTURE_ID_MAXIMIZER, alloc);
|
|
}
|
|
struct Invalid_element_type { };
|
|
throw Invalid_element_type();
|
|
};
|
|
|
|
|
|
static Text_painter::Font const &title_font(Genode::Allocator &alloc)
|
|
{
|
|
static File tff_file("theme/font.tff", alloc);
|
|
static Text_painter::Font font(tff_file.data<char>());
|
|
|
|
return font;
|
|
}
|
|
|
|
|
|
static Genode::Xml_node metadata(Genode::Allocator &alloc)
|
|
{
|
|
static File file("theme/metadata", alloc);
|
|
|
|
return Genode::Xml_node(file.data<char>(), file.size());
|
|
}
|
|
|
|
|
|
Decorator::Area Decorator::Theme::background_size() const
|
|
{
|
|
Genode::Texture<Pixel_rgb888> const &texture = texture_by_id(TEXTURE_ID_DEFAULT, _alloc);
|
|
|
|
return texture.size();
|
|
}
|
|
|
|
|
|
struct Margins_from_metadata : Decorator::Theme::Margins
|
|
{
|
|
Margins_from_metadata(char const *sub_node, Genode::Allocator &alloc)
|
|
{
|
|
Genode::Xml_node aura = metadata(alloc).sub_node(sub_node);
|
|
top = aura.attribute_value("top", 0UL);
|
|
bottom = aura.attribute_value("bottom", 0UL);
|
|
left = aura.attribute_value("left", 0UL);
|
|
right = aura.attribute_value("right", 0UL);
|
|
}
|
|
};
|
|
|
|
|
|
Decorator::Theme::Margins Decorator::Theme::aura_margins() const
|
|
{
|
|
static Margins_from_metadata aura("aura", _alloc);
|
|
return aura;
|
|
}
|
|
|
|
|
|
Decorator::Theme::Margins Decorator::Theme::decor_margins() const
|
|
{
|
|
static Margins_from_metadata decor("decor", _alloc);
|
|
return decor;
|
|
}
|
|
|
|
|
|
Decorator::Rect Decorator::Theme::title_geometry() const
|
|
{
|
|
static Rect rect = rect_attribute(metadata(_alloc).sub_node("title"));
|
|
return rect;
|
|
}
|
|
|
|
|
|
Decorator::Rect Decorator::Theme::element_geometry(Element_type type) const
|
|
{
|
|
if (type == ELEMENT_TYPE_CLOSER) {
|
|
static Rect rect(point_attribute(metadata(_alloc).sub_node("closer")),
|
|
texture_by_id(TEXTURE_ID_CLOSER, _alloc).size());
|
|
return rect;
|
|
}
|
|
|
|
if (type == ELEMENT_TYPE_MAXIMIZER) {
|
|
static Rect rect(point_attribute(metadata(_alloc).sub_node("maximizer")),
|
|
texture_by_id(TEXTURE_ID_MAXIMIZER, _alloc).size());
|
|
return rect;
|
|
}
|
|
|
|
struct Invalid_element_type { };
|
|
throw Invalid_element_type();
|
|
}
|
|
|
|
|
|
void Decorator::Theme::draw_background(Decorator::Pixel_surface pixel_surface,
|
|
Decorator::Alpha_surface alpha_surface,
|
|
unsigned alpha) const
|
|
{
|
|
Genode::Texture<Pixel_rgb888> const &texture = texture_by_id(TEXTURE_ID_DEFAULT, _alloc);
|
|
|
|
typedef Genode::Surface_base::Point Point;
|
|
typedef Genode::Surface_base::Rect Rect;
|
|
|
|
unsigned const left = aura_margins().left + decor_margins().left;
|
|
unsigned const right = aura_margins().right + decor_margins().right;
|
|
|
|
unsigned const middle = left + right < pixel_surface.size().w()
|
|
? pixel_surface.size().w() - left - right
|
|
: 0;
|
|
|
|
Rect const orig_clip = pixel_surface.clip();
|
|
|
|
/* left */
|
|
if (left) {
|
|
Rect curr_clip = Rect(Point(0, 0), Area(left, pixel_surface.size().h()));
|
|
pixel_surface.clip(curr_clip);
|
|
alpha_surface.clip(curr_clip);
|
|
|
|
Rect const rect(Point(0, 0), pixel_surface.size());
|
|
|
|
Icon_painter::paint(pixel_surface, rect, texture, alpha);
|
|
Icon_painter::paint(alpha_surface, rect, texture, alpha);
|
|
}
|
|
|
|
/* middle */
|
|
if (middle) {
|
|
Rect curr_clip = Rect(Point(left, 0), Area(middle, pixel_surface.size().h()));
|
|
pixel_surface.clip(curr_clip);
|
|
alpha_surface.clip(curr_clip);
|
|
|
|
Rect const rect(Point(0, 0), pixel_surface.size());
|
|
|
|
Icon_painter::paint(pixel_surface, rect, texture, alpha);
|
|
Icon_painter::paint(alpha_surface, rect, texture, alpha);
|
|
}
|
|
|
|
/* right */
|
|
if (right) {
|
|
Rect curr_clip = Rect(Point(left + middle, 0), Area(right, pixel_surface.size().h()));
|
|
pixel_surface.clip(curr_clip);
|
|
alpha_surface.clip(curr_clip);
|
|
|
|
Point at(0, 0);
|
|
Area size = pixel_surface.size();
|
|
|
|
if (texture.size().w() > pixel_surface.size().w()) {
|
|
at = Point((int)pixel_surface.size().w() - (int)texture.size().w(), 0);
|
|
size = Area(texture.size().w(), size.h());
|
|
}
|
|
|
|
Icon_painter::paint(pixel_surface, Rect(at, size), texture, alpha);
|
|
Icon_painter::paint(alpha_surface, Rect(at, size), texture, alpha);
|
|
}
|
|
|
|
pixel_surface.clip(orig_clip);
|
|
}
|
|
|
|
|
|
void Decorator::Theme::draw_title(Decorator::Pixel_surface pixel_surface,
|
|
Decorator::Alpha_surface alpha_surface,
|
|
char const *title) const
|
|
{
|
|
Text_painter::Font const &font = title_font(_alloc);
|
|
|
|
Area const label_area(font.str_w(title), font.str_h(title));
|
|
Rect const surface_rect(Point(0, 0), pixel_surface.size());
|
|
Rect const title_rect = absolute(title_geometry(), surface_rect);
|
|
Point const centered_text_pos = title_rect.center(label_area) - Point(0, 1);
|
|
|
|
Text_painter::paint(pixel_surface, centered_text_pos, font,
|
|
Genode::Color(0, 0, 0), title);
|
|
}
|
|
|
|
|
|
void Decorator::Theme::draw_element(Decorator::Pixel_surface pixel_surface,
|
|
Decorator::Alpha_surface alpha_surface,
|
|
Element_type element_type,
|
|
unsigned alpha) const
|
|
{
|
|
Genode::Texture<Pixel_rgb888> const &texture =
|
|
texture_by_element_type(element_type, _alloc);
|
|
|
|
Rect const surface_rect(Point(0, 0), pixel_surface.size());
|
|
Rect const element_rect = element_geometry(element_type);
|
|
Point const pos = absolute(element_rect.p1(), surface_rect);
|
|
Rect const rect(pos, element_rect.area());
|
|
|
|
Icon_painter::paint(pixel_surface, rect, texture, alpha);
|
|
Icon_painter::paint(alpha_surface, rect, texture, alpha);
|
|
}
|
|
|
|
|
|
Decorator::Point Decorator::Theme::absolute(Decorator::Point pos,
|
|
Decorator::Rect win_rect) const
|
|
{
|
|
Area const theme_size = background_size();
|
|
|
|
int x = pos.x();
|
|
int y = pos.y();
|
|
|
|
if (x > (int)theme_size.w()/2) x = win_rect.w() - theme_size.w() + x;
|
|
if (y > (int)theme_size.h()/2) y = win_rect.h() - theme_size.h() + y;
|
|
|
|
return win_rect.p1() + Point(x, y);
|
|
}
|
|
|
|
|
|
Decorator::Rect Decorator::Theme::absolute(Decorator::Rect rect,
|
|
Decorator::Rect win_rect) const
|
|
{
|
|
return Rect(absolute(rect.p1(), win_rect), absolute(rect.p2(), win_rect));
|
|
}
|