/* * \brief Widget that handles hovered/selected state and hosts a child widget * \author Norman Feske * \date 2009-09-11 */ /* * Copyright (C) 2014-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _BUTTON_WIDGET_H_ #define _BUTTON_WIDGET_H_ /* demo includes */ #include #include /* local includes */ #include "widget.h" #include "scratch_surface.h" namespace Menu_view { struct Button_widget; } struct Menu_view::Button_widget : Widget, Animator::Item { bool hovered = false; bool selected = false; Texture const * default_texture = nullptr; Texture const * hovered_texture = nullptr; Lazy_value blend { }; Padding padding { 9, 9, 2, 1 }; Area _space() const { return Area(margin.horizontal() + padding.horizontal(), margin.vertical() + padding.vertical()); } static bool _enabled(Xml_node node, char const *attr) { return node.attribute_value(attr, false); } Button_widget(Widget_factory &factory, Xml_node node, Unique_id unique_id) : Widget(factory, node, unique_id), Animator::Item(factory.animator) { margin = { 4, 4, 4, 4 }; } void update(Xml_node node) { bool const new_hovered = _enabled(node, "hovered"); bool const new_selected = _enabled(node, "selected"); if (new_selected) { default_texture = _factory.styles.texture(node, "selected"); hovered_texture = _factory.styles.texture(node, "hselected"); } else { default_texture = _factory.styles.texture(node, "default"); hovered_texture = _factory.styles.texture(node, "hovered"); } if (new_hovered != hovered) { if (new_hovered) { blend.dst(255 << 8, 3); } else { blend.dst(0, 20); } animated(blend != blend.dst()); } hovered = new_hovered; selected = new_selected; _update_children(node); _children.for_each([&] (Widget &child) { child.geometry(Rect(Point(margin.left + padding.left, margin.top + padding.top), child.min_size())); }); } Area min_size() const override { /* determine minimum child size */ Area child_min_size(300, 10); _children.for_each([&] (Widget const &child) { child_min_size = child.min_size(); }); /* don't get smaller than the background texture */ Area const texture_size = default_texture->size(); return Area(max(_space().w() + child_min_size.w(), texture_size.w()), max(_space().h() + child_min_size.h(), texture_size.h())); } void draw(Surface &pixel_surface, Surface &alpha_surface, Point at) const { static Scratch_surface scratch(_factory.alloc); Area const texture_size = default_texture->size(); Rect const texture_rect(Point(0, 0), texture_size); /* * Mix from_texture and to_texture according to the blend value */ scratch.reset(texture_size); scratch.apply([&] (Surface &pixel, Surface &alpha) { Icon_painter::paint(pixel, texture_rect, *default_texture, 255); Icon_painter::paint(alpha, texture_rect, *default_texture, 255); Icon_painter::paint(pixel, texture_rect, *hovered_texture, blend >> 8); Icon_painter::paint(alpha, texture_rect, *hovered_texture, blend >> 8); }); /* * Apply blended texture to target surface */ Icon_painter::paint(pixel_surface, Rect(at, _animated_geometry.area()), scratch.texture(), 255); Icon_painter::paint(alpha_surface, Rect(at, _animated_geometry.area()), scratch.texture(), 255); if (selected) at = at + Point(0, 1); _draw_children(pixel_surface, alpha_surface, at); } void _layout() override { _children.for_each([&] (Widget &w) { w.size(Area(geometry().w() - _space().w(), geometry().h() - _space().h())); }); } /****************************** ** Animator::Item interface ** ******************************/ void animate() override { blend.animate(); animated(blend != blend.dst()); } private: /** * Noncopyable */ Button_widget(Button_widget const &); Button_widget &operator = (Button_widget const &); }; #endif /* _BUTTON_WIDGET_H_ */