mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
parent
49e0036471
commit
7c79bfc903
@ -31,35 +31,35 @@ void Decorator::Window::draw(Decorator::Canvas_base &canvas,
|
||||
draw_behind_fn.draw_behind(canvas, *this, canvas.clip());
|
||||
|
||||
_draw_corner(canvas, Rect(p1, corner), _border_size, true, true,
|
||||
element(Element::TOP_LEFT).color());
|
||||
_window_elem_attr(Element::TOP_LEFT));
|
||||
|
||||
_draw_corner(canvas, Rect(Point(p1.x(), p2.y() - _corner_size + 1), corner),
|
||||
_border_size, true, false,
|
||||
element(Element::BOTTOM_LEFT).color());
|
||||
_window_elem_attr(Element::BOTTOM_LEFT));
|
||||
|
||||
_draw_corner(canvas, Rect(Point(p2.x() - _corner_size + 1, p1.y()), corner),
|
||||
_border_size, false, true,
|
||||
element(Element::TOP_RIGHT).color());
|
||||
_window_elem_attr(Element::TOP_RIGHT));
|
||||
|
||||
_draw_corner(canvas, Rect(Point(p2.x() - _corner_size + 1, p2.y() - _corner_size + 1), corner),
|
||||
_border_size, false, false,
|
||||
element(Element::BOTTOM_RIGHT).color());
|
||||
_window_elem_attr(Element::BOTTOM_RIGHT));
|
||||
|
||||
_draw_raised_box(canvas, Rect(Point(p1.x() + _corner_size, p1.y()),
|
||||
Area(rect.w() - 2*_corner_size, _border_size)),
|
||||
element(Element::TOP).color());
|
||||
_window_elem_attr(Element::TOP));
|
||||
|
||||
_draw_raised_box(canvas, Rect(Point(p1.x() + _corner_size, p2.y() - _border_size + 1),
|
||||
Area(rect.w() - 2*_corner_size, _border_size)),
|
||||
element(Element::BOTTOM).color());
|
||||
_window_elem_attr(Element::BOTTOM));
|
||||
|
||||
_draw_raised_box(canvas, Rect(Point(p1.x(), p1.y() + _corner_size),
|
||||
Area(_border_size, rect.h() - 2*_corner_size)),
|
||||
element(Element::LEFT).color());
|
||||
_window_elem_attr(Element::LEFT));
|
||||
|
||||
_draw_raised_box(canvas, Rect(Point(p2.x() - _border_size + 1, p1.y() + _corner_size),
|
||||
Area(_border_size, rect.h() - 2*_corner_size)),
|
||||
element(Element::RIGHT).color());
|
||||
_window_elem_attr(Element::RIGHT));
|
||||
|
||||
Rect controls_rect(Point(p1.x() + _border_size, p1.y() + _border_size),
|
||||
Area(rect.w() - 2*_border_size, _title_height));
|
||||
@ -118,7 +118,7 @@ void Decorator::Window::draw(Decorator::Canvas_base &canvas,
|
||||
Rect title_rect(left_pos, Area(right_pos.x() - left_pos.x() + _icon_size.w(),
|
||||
_title_height));
|
||||
|
||||
_draw_title_box(canvas, title_rect, element(Element::TITLE).color());
|
||||
_draw_title_box(canvas, title_rect, _window_elem_attr(Element::TITLE));
|
||||
|
||||
char const * const text = _title.string();
|
||||
|
||||
@ -128,7 +128,9 @@ void Decorator::Window::draw(Decorator::Canvas_base &canvas,
|
||||
/*
|
||||
* Position the text in the center of the window.
|
||||
*/
|
||||
Point const window_centered_text_pos = controls_rect.center(label_area) - Point(0, 1);
|
||||
int const title_yshift = element(Element::TITLE).pressed() ? 0 : -1;
|
||||
Point const window_centered_text_pos = controls_rect.center(label_area)
|
||||
+ Point(0, title_yshift);
|
||||
|
||||
/*
|
||||
* Horizontal position of the title text
|
||||
@ -259,17 +261,31 @@ bool Decorator::Window::update(Genode::Xml_node window_node)
|
||||
updated |= (new_controls != _controls);
|
||||
_controls = new_controls;
|
||||
|
||||
try {
|
||||
Xml_node highlight = window_node.sub_node("highlight");
|
||||
Xml_node const highlight = window_node.has_sub_node("highlight")
|
||||
? window_node.sub_node("highlight")
|
||||
: Xml_node("<highlight/>");
|
||||
|
||||
for (unsigned i = 0; i < num_elements(); i++)
|
||||
updated |= _apply_state(_elements[i].type(),
|
||||
highlight.has_sub_node(_elements[i].type_name()));
|
||||
} catch (...) {
|
||||
for (unsigned i = 0; i < num_elements(); i++) {
|
||||
|
||||
/* window node has no "highlight" sub node, reset highlighting */
|
||||
for (unsigned i = 0; i < num_elements(); i++)
|
||||
updated |= _apply_state(_elements[i].type(), false);
|
||||
Window_element &element = _elements[i];
|
||||
|
||||
Window_element::State state = element.state();
|
||||
|
||||
state.highlighted = false;
|
||||
state.pressed = false;
|
||||
state.focused = _focused;
|
||||
|
||||
highlight.for_each_sub_node([&] (Xml_node node) {
|
||||
|
||||
if (node.type() == element.type_name()) {
|
||||
state.highlighted = true;
|
||||
|
||||
if (node.attribute_value("pressed", false))
|
||||
state.pressed = true;
|
||||
}
|
||||
});
|
||||
|
||||
updated |= element.apply_state(state);
|
||||
}
|
||||
|
||||
return updated;
|
||||
|
@ -112,8 +112,8 @@ class Decorator::Window : public Window_base
|
||||
static unsigned const _border_size = 4;
|
||||
static unsigned const _title_height = 16;
|
||||
|
||||
|
||||
Color _bright = { 255, 255, 255, 64 };
|
||||
Color _dimmed = { 0, 0, 0, 24 };
|
||||
Color _dark = { 0, 0, 0, 127 };
|
||||
|
||||
Color _base_color = _config.base_color(_title);
|
||||
@ -161,9 +161,10 @@ class Decorator::Window : public Window_base
|
||||
|
||||
unsigned num_elements() const { return sizeof(_elements)/sizeof(Element); }
|
||||
|
||||
bool _apply_state(Window::Element::Type type, bool highlighted)
|
||||
bool _apply_state(Window::Element::Type type,
|
||||
Window::Element::State const &state)
|
||||
{
|
||||
return element(type).apply_state(_focused, highlighted, _base_color);
|
||||
return element(type).apply_state(state);
|
||||
}
|
||||
|
||||
typedef Config::Window_control Control;
|
||||
@ -225,6 +226,12 @@ class Decorator::Window : public Window_base
|
||||
** Drawing utilities **
|
||||
***********************/
|
||||
|
||||
struct Attr
|
||||
{
|
||||
Color color;
|
||||
bool pressed;
|
||||
};
|
||||
|
||||
void _draw_hline(Canvas_base &canvas, Point pos, unsigned w,
|
||||
bool at_left, bool at_right,
|
||||
unsigned border, Color color) const
|
||||
@ -247,20 +254,23 @@ class Decorator::Window : public Window_base
|
||||
Point(pos.x(), y2)), color);
|
||||
}
|
||||
|
||||
void _draw_raised_frame(Canvas_base &canvas, Rect rect) const
|
||||
void _draw_raised_frame(Canvas_base &canvas, Rect rect, bool pressed) const
|
||||
{
|
||||
_draw_hline(canvas, rect.p1(), rect.w(), true, true, 0, _bright);
|
||||
_draw_vline(canvas, rect.p1(), rect.h(), true, true, 0, _bright);
|
||||
Color const top_left_color = pressed ? _dimmed : _bright;
|
||||
|
||||
_draw_hline(canvas, rect.p1(), rect.w(), true, true, 0, top_left_color);
|
||||
_draw_vline(canvas, rect.p1(), rect.h(), true, true, 0, top_left_color);
|
||||
|
||||
_draw_hline(canvas, Point(rect.p1().x(), rect.p2().y()), rect.w(),
|
||||
true, true, 0, _dark);
|
||||
_draw_vline(canvas, Point(rect.p2().x(), rect.p1().y()), rect.h(),
|
||||
true, true, 0, _dark);
|
||||
}
|
||||
|
||||
void _draw_raised_box(Canvas_base &canvas, Rect rect, Color color) const
|
||||
void _draw_raised_box(Canvas_base &canvas, Rect rect, Attr attr) const
|
||||
{
|
||||
canvas.draw_box(rect, color);
|
||||
_draw_raised_frame(canvas, rect);
|
||||
canvas.draw_box(rect, attr.color);
|
||||
_draw_raised_frame(canvas, rect, attr.pressed);
|
||||
}
|
||||
|
||||
static Color _mix_colors(Color c1, Color c2, int alpha)
|
||||
@ -270,7 +280,7 @@ class Decorator::Window : public Window_base
|
||||
(c1.b*alpha + c2.b*(255 - alpha)) >> 8);
|
||||
}
|
||||
|
||||
void _draw_title_box(Canvas_base &canvas, Rect rect, Color color) const
|
||||
void _draw_title_box(Canvas_base &canvas, Rect rect, Attr attr) const
|
||||
{
|
||||
/*
|
||||
* Produce gradient such that the upper half becomes brighter and
|
||||
@ -284,7 +294,8 @@ class Decorator::Window : public Window_base
|
||||
|
||||
int const mid_y = rect.h() / 2;
|
||||
|
||||
Color const white(255, 255, 255), black(0, 0, 0);
|
||||
Color const upper_color = attr.pressed ? Color(0, 0, 0) : Color(255, 255, 255);
|
||||
Color const lower_color = attr.pressed ? Color(127, 127, 127) : Color(0, 0, 0);
|
||||
|
||||
for (unsigned i = 0; i < rect.h(); i++) {
|
||||
|
||||
@ -294,20 +305,19 @@ class Decorator::Window : public Window_base
|
||||
? (ascent*(mid_y - i)) >> 8
|
||||
: (ascent*(i - mid_y)) >> 8;
|
||||
|
||||
Color const line_color =
|
||||
_mix_colors(upper_half ? white : black, color, alpha);
|
||||
Color const mix_color = upper_half ? upper_color : lower_color;
|
||||
Color const line_color = _mix_colors(mix_color, attr.color, alpha);
|
||||
|
||||
canvas.draw_box(Rect(rect.p1() + Point(0, i),
|
||||
Area(rect.w(), 1)), line_color);
|
||||
}
|
||||
|
||||
_draw_raised_frame(canvas, rect);
|
||||
_draw_raised_frame(canvas, rect, attr.pressed);
|
||||
}
|
||||
|
||||
void _draw_corner(Canvas_base &canvas, Rect const rect,
|
||||
unsigned const border,
|
||||
bool const left, bool const top,
|
||||
Color color) const
|
||||
bool const left, bool const top, Attr const attr) const
|
||||
{
|
||||
bool const bottom = !top;
|
||||
bool const right = !left;
|
||||
@ -319,21 +329,23 @@ class Decorator::Window : public Window_base
|
||||
int const w = rect.w();
|
||||
int const h = rect.h();
|
||||
|
||||
Color const top_left_color = attr.pressed ? _dimmed : _bright;
|
||||
|
||||
canvas.draw_box(Rect(Point(x1, top ? y1 : y2 - border + 1),
|
||||
Area(w, border)), color);
|
||||
Area(w, border)), attr.color);
|
||||
|
||||
canvas.draw_box(Rect(Point(left ? x1 : x2 - border + 1,
|
||||
top ? y1 + border : y1),
|
||||
Area(border, h - border)), color);
|
||||
Area(border, h - border)), attr.color);
|
||||
|
||||
/* top bright line */
|
||||
_draw_hline(canvas, rect.p1(), w,
|
||||
top || left, top || right, border, _bright);
|
||||
top || left, top || right, border, top_left_color);
|
||||
|
||||
/* inner horizontal line */
|
||||
int y = top ? y1 + border - 1 : y2 - border + 1;
|
||||
_draw_hline(canvas, Point(x1, y), w, right, left, w - border,
|
||||
top ? _dark : _bright);
|
||||
top ? _dark : top_left_color);
|
||||
|
||||
/* bottom line */
|
||||
_draw_hline(canvas, Point(x1, y2), w,
|
||||
@ -341,29 +353,35 @@ class Decorator::Window : public Window_base
|
||||
|
||||
/* left bright line */
|
||||
_draw_vline(canvas, rect.p1(), h,
|
||||
left || top, left || bottom, border, _bright);
|
||||
left || top, left || bottom, border, top_left_color);
|
||||
|
||||
/* inner vertical line */
|
||||
int x = left ? x1 + border - 1 : x2 - border + 1;
|
||||
_draw_vline(canvas, Point(x, y1), h, bottom, top, h - border + 1,
|
||||
left ? _dark : _bright);
|
||||
left ? _dark : top_left_color);
|
||||
|
||||
/* right line */
|
||||
_draw_vline(canvas, Point(x2, y1), h,
|
||||
right || top, right || bottom, border, _dark);
|
||||
}
|
||||
|
||||
Color _window_control_color(Control window_control) const
|
||||
Attr _window_elem_attr(Element::Type type) const
|
||||
{
|
||||
return Attr { .color = element(type).color(),
|
||||
.pressed = element(type).pressed() };
|
||||
}
|
||||
|
||||
Attr _window_control_attr(Control const &window_control) const
|
||||
{
|
||||
switch (window_control.type()) {
|
||||
case Control::TYPE_CLOSER: return element(Element::CLOSER).color();
|
||||
case Control::TYPE_MAXIMIZER: return element(Element::MAXIMIZER).color();
|
||||
case Control::TYPE_MINIMIZER: return element(Element::MINIMIZER).color();
|
||||
case Control::TYPE_UNMAXIMIZER: return element(Element::UNMAXIMIZER).color();
|
||||
case Control::TYPE_TITLE: return element(Element::TITLE).color();
|
||||
case Control::TYPE_CLOSER: return _window_elem_attr(Element::CLOSER);
|
||||
case Control::TYPE_MAXIMIZER: return _window_elem_attr(Element::MAXIMIZER);
|
||||
case Control::TYPE_MINIMIZER: return _window_elem_attr(Element::MINIMIZER);
|
||||
case Control::TYPE_UNMAXIMIZER: return _window_elem_attr(Element::UNMAXIMIZER);
|
||||
case Control::TYPE_TITLE: return _window_elem_attr(Element::TITLE);
|
||||
case Control::TYPE_UNDEFINED: break;
|
||||
};
|
||||
return Color(0, 0, 0);
|
||||
return Attr { .color = Color(0, 0, 0), .pressed = false };
|
||||
}
|
||||
|
||||
Texture_id _window_control_texture(Control window_control) const
|
||||
@ -385,7 +403,7 @@ class Decorator::Window : public Window_base
|
||||
void _draw_window_control(Canvas_base &canvas, Rect rect,
|
||||
Control control) const
|
||||
{
|
||||
_draw_title_box(canvas, rect, _window_control_color(control));
|
||||
_draw_title_box(canvas, rect, _window_control_attr(control));
|
||||
|
||||
canvas.draw_texture(rect.p1() + Point(1,1),
|
||||
_window_control_texture(control));
|
||||
|
@ -35,6 +35,22 @@ class Decorator::Window_element : public Animator::Item
|
||||
TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,
|
||||
CLOSER, MAXIMIZER, MINIMIZER, UNMAXIMIZER, UNDEFINED };
|
||||
|
||||
struct State
|
||||
{
|
||||
bool focused;
|
||||
bool highlighted;
|
||||
bool pressed;
|
||||
Color base_color;
|
||||
|
||||
bool operator == (State const &other) const
|
||||
{
|
||||
return focused == other.focused
|
||||
&& highlighted == other.highlighted
|
||||
&& pressed == other.pressed
|
||||
&& base_color == other.base_color;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
static Color _add(Color c1, Color c2)
|
||||
@ -44,12 +60,16 @@ class Decorator::Window_element : public Animator::Item
|
||||
Genode::min(c1.b + c2.b, 255));
|
||||
}
|
||||
|
||||
static Color _sub(Color c1, Color c2)
|
||||
{
|
||||
return Color(Genode::max(c1.r - c2.r, 0),
|
||||
Genode::max(c1.g - c2.g, 0),
|
||||
Genode::max(c1.b - c2.b, 0));
|
||||
}
|
||||
|
||||
Type const _type;
|
||||
|
||||
/*
|
||||
* Rememeber base color to detect when it changes
|
||||
*/
|
||||
Color _base_color { };
|
||||
State _state { };
|
||||
|
||||
/*
|
||||
* Color value in 8.4 fixpoint format. We use four bits to
|
||||
@ -58,52 +78,37 @@ class Decorator::Window_element : public Animator::Item
|
||||
*/
|
||||
Lazy_value<int> _r { }, _g { }, _b { };
|
||||
|
||||
bool _focused = false;
|
||||
bool _highlighted = false;
|
||||
|
||||
static Color _dst_color(bool focused, bool highlighted, Color base)
|
||||
static Color _dst_color(State const &state)
|
||||
{
|
||||
Color result = base;
|
||||
Color result = state.base_color;
|
||||
|
||||
if (focused)
|
||||
if (state.focused)
|
||||
result = _add(result, Color(70, 70, 70));
|
||||
|
||||
if (highlighted)
|
||||
if (state.highlighted)
|
||||
result = _add(result, Color(65, 60, 55));
|
||||
|
||||
if (state.pressed)
|
||||
result = _sub(result, Color(10, 10, 10));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned _anim_steps(bool focused, bool highlighted) const
|
||||
unsigned _anim_steps(State const &state) const
|
||||
{
|
||||
/* quick fade-in when gaining the focus or hover highlight */
|
||||
if ((!_focused && focused) || (!_highlighted && highlighted))
|
||||
/* immediately respond when pressing or releasing an element */
|
||||
if (_state.pressed != state.pressed)
|
||||
return 0;
|
||||
|
||||
/* medium fade-in when gaining the focus or hover highlight */
|
||||
if ((!_state.focused && state.focused)
|
||||
|| (!_state.highlighted && state.highlighted))
|
||||
return 15;
|
||||
|
||||
/* slow fade-out when leaving focus or hover highlight */
|
||||
return 20;
|
||||
}
|
||||
|
||||
bool _apply_state(bool focused, bool highlighted, Color base_color)
|
||||
{
|
||||
_base_color = base_color;
|
||||
|
||||
Color const dst_color = _dst_color(focused, highlighted, base_color);
|
||||
unsigned const steps = _anim_steps(focused, highlighted);
|
||||
|
||||
_r.dst(dst_color.r << 4, steps);
|
||||
_g.dst(dst_color.g << 4, steps);
|
||||
_b.dst(dst_color.b << 4, steps);
|
||||
|
||||
/* schedule animation */
|
||||
animate();
|
||||
|
||||
_focused = focused;
|
||||
_highlighted = highlighted;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Window_element(Type type, Animator &animator, Color base_color)
|
||||
@ -111,7 +116,10 @@ class Decorator::Window_element : public Animator::Item
|
||||
Animator::Item(animator),
|
||||
_type(type)
|
||||
{
|
||||
_apply_state(false, false, base_color);
|
||||
apply_state(State{ .focused = false,
|
||||
.highlighted = false,
|
||||
.pressed = false,
|
||||
.base_color = base_color });
|
||||
}
|
||||
|
||||
Type type() const { return _type; }
|
||||
@ -142,15 +150,30 @@ class Decorator::Window_element : public Animator::Item
|
||||
/**
|
||||
* \return true if state has changed
|
||||
*/
|
||||
bool apply_state(bool focused, bool highlighted, Color base_color)
|
||||
bool apply_state(State state)
|
||||
{
|
||||
if (_focused == focused && _highlighted == highlighted
|
||||
&& base_color == _base_color)
|
||||
if (_state == state)
|
||||
return false;
|
||||
|
||||
return _apply_state(focused, highlighted, base_color);
|
||||
Color const dst_color = _dst_color(state);
|
||||
unsigned const steps = _anim_steps(state);
|
||||
|
||||
_r.dst(dst_color.r << 4, steps);
|
||||
_g.dst(dst_color.g << 4, steps);
|
||||
_b.dst(dst_color.b << 4, steps);
|
||||
|
||||
/* schedule animation */
|
||||
animate();
|
||||
|
||||
_state = state;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
State state() const { return _state; }
|
||||
|
||||
bool pressed() const { return _state.pressed; }
|
||||
|
||||
/**
|
||||
* Animator::Item interface
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user