genode/repos/demo/src/app/scout/browser_window.cc

481 lines
12 KiB
C++
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief Browser window implementation
* \date 2005-10-24
* \author Norman Feske <norman.feske@genode-labs.com>
*
* This class defines the layout and user policy of a browser window.
*/
/*
* Copyright (C) 2005-2017 Genode Labs GmbH
2011-12-22 16:19:25 +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.
2011-12-22 16:19:25 +01:00
*/
#include <scout_gfx/random.h>
#include <scout/misc_math.h>
2011-12-22 16:19:25 +01:00
#include "browser_window.h"
using namespace Scout;
2011-12-22 16:19:25 +01:00
/****************************
** External graphics data **
****************************/
#define IOR_MAP _binary_ior_map_start
#define HOME_RGBA _binary_home_rgba_start
#define COVER_RGBA _binary_cover_rgba_start
#define INDEX_RGBA _binary_index_rgba_start
#define ABOUT_RGBA _binary_about_rgba_start
#define FORWARD_RGBA _binary_forward_rgba_start
#define BACKWARD_RGBA _binary_backward_rgba_start
#define SIZER_RGBA _binary_sizer_rgba_start
#define TITLEBAR_RGBA _binary_titlebar_rgba_start
extern short IOR_MAP[];
extern unsigned char HOME_RGBA[];
extern unsigned char COVER_RGBA[];
extern unsigned char INDEX_RGBA[];
extern unsigned char ABOUT_RGBA[];
extern unsigned char FORWARD_RGBA[];
extern unsigned char BACKWARD_RGBA[];
extern unsigned char SIZER_RGBA[];
extern unsigned char TITLEBAR_RGBA[];
enum {
ICON_HOME = 0,
ICON_BACKWARD = 1,
ICON_FORWARD = 2,
ICON_INDEX = 3,
ICON_ABOUT = 4,
NUM_ICONS = 5
};
/* icon graphics data */
static unsigned char *glow_icon_gfx[] = {
HOME_RGBA,
BACKWARD_RGBA,
FORWARD_RGBA,
INDEX_RGBA,
ABOUT_RGBA,
};
/* color definitions for glowing effect of the icons */
static Color glow_icon_col[] = {
Color(210, 210, 0),
Color( 0, 0, 160),
Color( 0, 0, 160),
Color( 0, 160, 0),
Color(160, 0, 0),
};
/***************
** Utilities **
***************/
/**
* Transform rgba source image to image with native pixel type
*
* If we specify an empty buffer as alpha channel (all values zero), we simply
* assign the source image data to the destination buffer. If there are valid
* values in the destination alpha channel, we paint the source image on top
* of the already present image data. This enables us to combine multiple
* rgba buffers (layers) into one destination buffer.
*/
template <typename PT>
static void extract_rgba(const unsigned char *src, int w, int h,
PT *dst_pixel, unsigned char *dst_alpha)
{
for (int i = 0; i < w*h; i++, src += 4) {
int r = src[0];
int g = src[1];
int b = src[2];
int a = src[3];
if (dst_alpha[i]) {
PT s(r, g, b);
dst_pixel[i] = PT::mix(dst_pixel[i], s, a);
dst_alpha[i] = max((int)dst_alpha[i], a);
} else {
dst_pixel[i].rgba(r, g, b);
dst_alpha[i] = a;
}
}
}
/********************
** Event handlers **
********************/
class Iconbar_event_handler : public Scout::Event_handler
2011-12-22 16:19:25 +01:00
{
private:
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
/*
* Noncopyable
*/
Iconbar_event_handler(Iconbar_event_handler const &);
Iconbar_event_handler &operator = (Iconbar_event_handler const &);
2011-12-22 16:19:25 +01:00
Fader *_fader;
Browser *_browser;
int _icon_id;
public:
/**
* Constructor
*/
Iconbar_event_handler(Fader *fader, int icon_id, Browser *browser)
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
:
_fader(fader), _browser(browser), _icon_id(icon_id)
{ }
2011-12-22 16:19:25 +01:00
/**
* Event handler interface
*/
void handle_event(Event const &ev) override
2011-12-22 16:19:25 +01:00
{
static int key_cnt;
if (ev.type == Event::PRESS) key_cnt++;
if (ev.type == Event::RELEASE) key_cnt--;
/* start movement with zero speed */
if ((ev.type != Event::PRESS) || (key_cnt != 1)) return;
/* no flashing by default */
int flash = 0;
switch (_icon_id) {
case ICON_HOME:
flash |= _browser->go_home();
break;
case ICON_BACKWARD:
flash |= _browser->go_backward();
break;
case ICON_FORWARD:
flash |= _browser->go_forward();
break;
case ICON_INDEX:
flash |= _browser->go_toc();
break;
case ICON_ABOUT:
flash |= _browser->go_about();
break;
}
/* flash clicked icon */
if (0 && flash) {
/* flash fader to the max */
_fader->step(4);
_fader->curr(190);
}
}
};
template <typename PT>
class Browser_sizer_event_handler : public Scout::Sizer_event_handler
2011-12-22 16:19:25 +01:00
{
private:
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
/*
* Noncopyable
*/
Browser_sizer_event_handler(Browser_sizer_event_handler const &);
Browser_sizer_event_handler &operator = (Browser_sizer_event_handler const &);
2011-12-22 16:19:25 +01:00
Browser_window<PT> *_browser_win;
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
Anchor *_ca = nullptr; /* original visible element */
2011-12-22 16:19:25 +01:00
/**
* Event handler interface
*/
void start_drag() override
2011-12-22 16:19:25 +01:00
{
Sizer_event_handler::start_drag();
_ca = _browser_win->curr_anchor();
}
void do_drag() override
2011-12-22 16:19:25 +01:00
{
Sizer_event_handler::do_drag();
_browser_win->go_to(_ca, 0);
}
public:
/**
* Constructor
*/
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
Browser_sizer_event_handler(Browser_window<PT> *browser_win)
:
Sizer_event_handler(browser_win), _browser_win(browser_win)
{ }
2011-12-22 16:19:25 +01:00
};
/******************************
** Browser window interface **
******************************/
template <typename PT>
Browser_window<PT>::Browser_window(Document *initial_content,
Graphics_backend &gfx_backend,
Point position, Area size,
Area max_size, Config const &config)
:
Browser(_IH + _TH), Window(gfx_backend, position, size, max_size, true),
_config(config),
_gfx_backend(gfx_backend)
2011-12-22 16:19:25 +01:00
{
/* init attributes */
_ypos = 0;
_document = initial_content;
/* init docview and history with initial document */
_docview.texture(&_texture);
_docview.voffset(doc_offset());
_history.add(initial_content);
/* init icons */
memset(_icon_fg, 0, sizeof(_icon_fg));
memset(_icon_fg_alpha, 0, sizeof(_icon_fg_alpha));
for (int i = 0; i < _NUM_ICONS; i++) {
/* convert rgba raw image to PT pixel format and alpha channel */
extract_rgba(COVER_RGBA, _IW, _IH,
_icon_fg[i][0], _icon_fg_alpha[i][0]);
/* assign back buffer, foreground and distmap to icon */
_icon[i].backbuf(_icon_backbuf[0], 1);
_icon[i].distmap(IOR_MAP, _IW*2, _IH*2);
_icon[i].foreground(_icon_fg[i][0], _icon_fg_alpha[i][0]);
_icon[i].event_handler(new Mover_event_handler(this));
/* apply foreground graphics to icon */
extract_rgba(glow_icon_gfx[i], _IW, _IH,
_icon_fg[i][0], _icon_fg_alpha[i][0]);
/* init glow icon */
Fade_icon<PT, _IW, _IH> *fadeicon = &_glow_icon[i];
fadeicon->glow(glow_icon_gfx[i], glow_icon_col[i]);
fadeicon->default_alpha(0);
fadeicon->focus_alpha(100);
fadeicon->alpha(0);
fadeicon->event_handler(new Iconbar_event_handler(fadeicon, i, this));
}
/*
* All icons share the same distmap. Therefore we need to scratch
* only one distmap to affect all icons.
*/
_icon[0].scratch(_SCRATCH);
/* create panel tile texture */
/*
* NOTE: The panel height must be the same as the icon height.
*/
using Scout::random;
2011-12-22 16:19:25 +01:00
for (int j = 0; j < _PANEL_H; j++)
for (int i = 0; i < _PANEL_W; i++) {
_panel_fg [j][i] = _icon_fg [ICON_INDEX][j][i&0x1];
_panel_fg_alpha [j][i] = _icon_fg_alpha [ICON_INDEX][j][i&0x1] + random()%3;
}
/* init panel background */
_panel.backbuf(&_panel_backbuf[0][0]);
_panel.distmap(_panel_distmap[0], _PANEL_W*2, _PANEL_H*2);
_panel.foreground(_panel_fg[0], _panel_fg_alpha[0]);
_panel.scratch(_SCRATCH);
_panel.event_handler(new Mover_event_handler(this));
/* resize handle */
_sizer.rgba(SIZER_RGBA);
_sizer.event_handler(new Browser_sizer_event_handler<PT>(this));
_sizer.alpha(100);
/* titlebar */
_titlebar.rgba(TITLEBAR_RGBA);
_titlebar.text(_document->title);
_titlebar.event_handler(new Mover_event_handler(this));
_min_size = Scout::Area(_NUM_ICONS*_IW, _IH + 250);
2011-12-22 16:19:25 +01:00
/* adopt widgets as child elements */
append(&_docview);
for (int i = 0; i <= ICON_INDEX; i++) {
append(&_icon[i]);
append(&_glow_icon[i]);
}
append(&_panel);
append(&_icon[ICON_ABOUT]);
append(&_glow_icon[ICON_ABOUT]);
append(&_shadow);
append(&_scrollbar);
if (_attr & ATTR_SIZER) append(&_sizer);
if (_attr & ATTR_TITLEBAR) append(&_titlebar);
_scrollbar.listener(this);
_content(initial_content);
}
template <typename PT>
void Browser_window<PT>::ypos_sb(int ypos, int update_scrollbar)
{
if (ypos < -(int)_docview.size().h() + (int)_size.h())
ypos = -(int)_docview.size().h() + (int)_size.h();
2011-12-22 16:19:25 +01:00
_ypos = ypos <= 0 ? ypos : 0;
_docview.geometry(Rect(Point(_docview.position().x(), _ypos),
Area(_docview.size().w(), _docview.size().h())));
2011-12-22 16:19:25 +01:00
if (update_scrollbar)
_scrollbar.view(_docview.size().h(), _size.h(), -_ypos);
2011-12-22 16:19:25 +01:00
refresh();
}
/***********************
** Browser interface **
***********************/
template <typename PT>
Element *Browser_window<PT>::_content()
{
return _docview.content();
}
template <typename PT>
void Browser_window<PT>::_content(Element *content)
{
if (!content || (content == _docview.content())) return;
content->fill_cache(_gfx_backend.front());
2011-12-22 16:19:25 +01:00
_docview.content(content);
format(_size);
2011-12-22 16:19:25 +01:00
_ypos = 0;
}
template <typename PT>
void Browser_window<PT>::format(Area size)
2011-12-22 16:19:25 +01:00
{
unsigned w = size.w();
unsigned h = size.h();
2011-12-22 16:19:25 +01:00
/* limit browser window size to valid values */
w = max(w, min_size().w());
h = max(h, min_size().h());
w = min(w, max_size().w());
h = min(h, max_size().h());
2011-12-22 16:19:25 +01:00
/* determine old scrollbar visibility */
int old_sb_visibility = (_docview.min_size().h() > _size.h());
2011-12-22 16:19:25 +01:00
/* assign new size to browser window */
_size = Scout::Area(w, h);
2011-12-22 16:19:25 +01:00
/* format document */
_docview.format_fixed_width(_size.w());
2011-12-22 16:19:25 +01:00
/* format titlebar */
_titlebar.format_fixed_width(_size.w());
2011-12-22 16:19:25 +01:00
/* determine new scrollbar visibility */
int new_sb_visibility = (_docview.min_size().h() > _size.h());
2011-12-22 16:19:25 +01:00
/* reformat docview on change of scrollbar visibility */
if (old_sb_visibility ^ new_sb_visibility) {
_docview.right_pad(new_sb_visibility ? _scrollbar.min_size().w() : 0);
_docview.format_fixed_width(_size.w());
2011-12-22 16:19:25 +01:00
}
/* position docview */
_docview.geometry(Rect(Point(0, _ypos),
Area(_docview.min_size().w(),
max(_docview.min_size().h(), _size.h()))));
2011-12-22 16:19:25 +01:00
/* start at top */
int y = 0;
/* position titlebar */
if (_attr & ATTR_TITLEBAR) {
_titlebar.geometry(Rect(Point(y, 0), Area(_size.w(), _TH)));
2011-12-22 16:19:25 +01:00
y += _TH;
}
/* position icons */
for (int i = 0; i <= ICON_INDEX; i++) {
_icon[i].geometry(Rect(Point(i*_IW, y), Area(_IW, _IH)));
_glow_icon[i].geometry(Rect(Point(i*_IW, y), Area(_IW, _IH)));
2011-12-22 16:19:25 +01:00
}
_icon[ICON_ABOUT].geometry(Rect(Point(_size.w() - _IW, y), Area(_IW, _IH)));
_glow_icon[ICON_ABOUT].geometry(Rect(Point(_size.w() - _IW, y), Area(_IW, _IH)));
2011-12-22 16:19:25 +01:00
/* the panel is the space between the left icon set and the right about icon */
int panel_x = _icon[ICON_INDEX].position().x() + _IW;
_panel.geometry(Rect(Point(panel_x, y),
Area(_icon[ICON_ABOUT].position().x() - panel_x, _IH)));
2011-12-22 16:19:25 +01:00
y += _IH;
_scrollbar.geometry(Rect(Point(w - _scrollbar.min_size().w() - _SB_XPAD, y + _SB_YPAD),
Area(_scrollbar.min_size().w(),
h - y - _SB_YPAD*2 - (_attr & ATTR_SIZER ? 8 : 0))));
_shadow.geometry(Rect(Point(0, y), Area(_size.w(), 10)));
2011-12-22 16:19:25 +01:00
if (_attr & ATTR_SIZER)
_sizer.geometry(Rect(Point(_size.w() - 32, _size.h() - 32), Area(32, 32)));
2011-12-22 16:19:25 +01:00
Window::format(_size);
2011-12-22 16:19:25 +01:00
}
template <typename PT>
Anchor *Browser_window<PT>::curr_anchor() { return find_by_y(doc_offset()); }
/**********************************
** Scrollbar listener interface **
**********************************/
template <typename PT>
void Browser_window<PT>::handle_scroll(int view_pos)
{
/*
* The handle scroll notification comes from the scrollbar,
* which already adjusted itself to the new view port.
* Therefore, we do not need to re-adjust it another time
* and call ypos() with update_scrollbar set to zero.
*/
ypos_sb(-view_pos, 0);
}
template class Browser_window<Genode::Pixel_rgb565>;