genode/repos/gems/src/app/themed_decorator/theme.cc

326 lines
9.2 KiB
C++
Raw Normal View History

2015-11-11 16:54:08 +01:00
/*
* \brief Window decorator that can be styled - theme handling
* \author Norman Feske
* \date 2015-11-12
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
2015-11-11 16:54:08 +01:00
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
2015-11-11 16:54:08 +01:00
*/
/* Genode includes */
#include <os/texture_rgb888.h>
#include <nitpicker_gfx/tff_font.h>
2015-11-11 16:54:08 +01:00
#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;
2015-11-11 16:54:08 +01:00
Texture &texture { *png_image.texture<Genode::Pixel_rgb888>() };
Texture_from_png_file(Genode::Ram_allocator &ram, Genode::Region_map &rm,
Genode::Allocator &alloc, char const *path)
2015-11-11 16:54:08 +01:00
:
png_file(path, alloc), png_image(ram, rm, alloc, png_file.data<void>())
2015-11-11 16:54:08 +01:00
{ }
};
static Genode::Texture<Genode::Pixel_rgb888> const &
texture_by_id(Genode::Ram_allocator &ram, Genode::Region_map &rm,
Genode::Allocator &alloc, Texture_id texture_id)
2015-11-11 16:54:08 +01:00
{
if (texture_id == TEXTURE_ID_DEFAULT) {
static Texture_from_png_file texture(ram, rm, alloc, "theme/default.png");
2015-11-11 16:54:08 +01:00
return texture.texture;
}
if (texture_id == TEXTURE_ID_CLOSER) {
static Texture_from_png_file texture(ram, rm, alloc, "theme/closer.png");
2015-11-11 16:54:08 +01:00
return texture.texture;
}
if (texture_id == TEXTURE_ID_MAXIMIZER) {
static Texture_from_png_file texture(ram, rm, alloc, "theme/maximizer.png");
2015-11-11 16:54:08 +01:00
return texture.texture;
}
struct Invalid_texture_id { };
throw Invalid_texture_id();
}
static Genode::Texture<Genode::Pixel_rgb888> const &
texture_by_element_type(Genode::Ram_allocator &ram, Genode::Region_map &rm,
Genode::Allocator &alloc, Decorator::Theme::Element_type type)
2015-11-11 16:54:08 +01:00
{
switch (type) {
case Decorator::Theme::ELEMENT_TYPE_CLOSER:
return texture_by_id(ram, rm, alloc, TEXTURE_ID_CLOSER);
2015-11-11 16:54:08 +01:00
case Decorator::Theme::ELEMENT_TYPE_MAXIMIZER:
return texture_by_id(ram, rm, alloc, TEXTURE_ID_MAXIMIZER);
2015-11-11 16:54:08 +01:00
}
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 Tff_font::Allocated_glyph_buffer glyph_buffer(tff_file.data<char>(), alloc);
static Tff_font font(tff_file.data<char>(), glyph_buffer);
2015-11-11 16:54:08 +01:00
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
{
if (decor_margins().none() && aura_margins().none())
return Decorator::Area(0, 0);
Genode::Texture<Pixel_rgb888> const &texture =
texture_by_id(_ram, _rm, _alloc, TEXTURE_ID_DEFAULT);
2015-11-11 16:54:08 +01:00
return texture.size();
}
struct Margins_from_metadata : Decorator::Theme::Margins
{
Margins_from_metadata(char const *sub_node, Genode::Allocator &alloc)
:
Decorator::Theme::Margins()
2015-11-11 16:54:08 +01:00
{
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 Genode::Xml_node node = metadata(_alloc);
static Rect rect = node.has_sub_node("title")
? rect_attribute(node.sub_node("title"))
: Rect(Point(0, 0), Area(0, 0));
2015-11-11 16:54:08 +01:00
return rect;
}
static Decorator::Rect
element_geometry(Genode::Ram_allocator &ram, Genode::Region_map &rm,
Genode::Allocator &alloc, char const *sub_node_type,
Texture_id texture_id)
{
using namespace Decorator;
static Genode::Xml_node const node = metadata(alloc);
if (!node.has_sub_node(sub_node_type))
return Rect(Point(0, 0), Area(0, 0));
return Rect(point_attribute(node.sub_node(sub_node_type)),
texture_by_id(ram, rm, alloc, texture_id).size());
}
2015-11-11 16:54:08 +01:00
Decorator::Rect Decorator::Theme::element_geometry(Element_type type) const
{
if (type == ELEMENT_TYPE_CLOSER)
return ::element_geometry(_ram, _rm, _alloc, "closer", TEXTURE_ID_CLOSER);
if (type == ELEMENT_TYPE_MAXIMIZER)
return ::element_geometry(_ram, _rm, _alloc, "maximizer", TEXTURE_ID_MAXIMIZER);
2015-11-11 16:54:08 +01:00
struct Invalid_element_type { };
throw Invalid_element_type();
}
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
void Decorator::Theme::draw_background(Decorator::Pixel_surface &pixel_surface,
Decorator::Alpha_surface &alpha_surface,
Area const area, unsigned alpha) const
2015-11-11 16:54:08 +01:00
{
/*
* Back out early there is neither a decor nor an aura. In this case, we
* prevent accessing the 'default.png' file. So we can skip it from the
* theme.
*/
if (!background_size().valid())
return;
Genode::Texture<Pixel_rgb888> const &texture =
texture_by_id(_ram, _rm, _alloc, TEXTURE_ID_DEFAULT);
2015-11-11 16:54:08 +01:00
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 < area.w()
? area.w() - left - right
2015-11-11 16:54:08 +01:00
: 0;
Rect const orig_clip = pixel_surface.clip();
/* left */
if (left) {
Rect curr_clip = Rect(Point(0, 0), Area(left, area.h()));
2015-11-11 16:54:08 +01:00
pixel_surface.clip(curr_clip);
alpha_surface.clip(curr_clip);
Rect const rect(Point(0, 0), area);
2015-11-11 16:54:08 +01:00
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, area.h()));
2015-11-11 16:54:08 +01:00
pixel_surface.clip(curr_clip);
alpha_surface.clip(curr_clip);
Rect const rect(Point(0, 0), area);
2015-11-11 16:54:08 +01:00
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, area.h()));
2015-11-11 16:54:08 +01:00
pixel_surface.clip(curr_clip);
alpha_surface.clip(curr_clip);
Point at(0, 0);
Area size = area;
2015-11-11 16:54:08 +01:00
if (texture.size().w() > area.w()) {
at = Point((int)area.w() - (int)texture.size().w(), 0);
2015-11-11 16:54:08 +01:00
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);
}
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
void Decorator::Theme::draw_title(Decorator::Pixel_surface &pixel_surface,
Decorator::Alpha_surface &,
Area const area, char const *title) const
2015-11-11 16:54:08 +01:00
{
/* skip title drawing if the metadata lacks a title declaration */
if (!title_geometry().area().valid())
return;
2015-11-11 16:54:08 +01:00
Text_painter::Font const &font = title_font(_alloc);
Area const label_area(font.string_width(title).decimal(),
font.bounding_box().h());
Rect const target_rect(Point(0, 0), area);
Rect const title_rect = absolute(title_geometry(), target_rect);
Point const pos = title_rect.center(label_area) - Point(0, 1);
2015-11-11 16:54:08 +01:00
Text_painter::paint(pixel_surface, Text_painter::Position(pos.x(), pos.y()),
font, Genode::Color(0, 0, 0), title);
2015-11-11 16:54:08 +01:00
}
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
void Decorator::Theme::draw_element(Decorator::Pixel_surface &pixel_surface,
Decorator::Alpha_surface &alpha_surface,
Area area,
2015-11-11 16:54:08 +01:00
Element_type element_type,
unsigned alpha) const
{
if (!element_geometry(element_type).area().valid())
return;
2015-11-11 16:54:08 +01:00
Genode::Texture<Pixel_rgb888> const &texture =
texture_by_element_type(_ram, _rm, _alloc, element_type);
2015-11-11 16:54:08 +01:00
Rect const target_rect(Point(0, 0), area);
2015-11-11 16:54:08 +01:00
Rect const element_rect = element_geometry(element_type);
Point const pos = absolute(element_rect.p1(), target_rect);
2015-11-11 16:54:08 +01:00
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));
}