331 lines
7.6 KiB
C++
331 lines
7.6 KiB
C++
/*
|
|
* \brief Scrollbar implementation
|
|
* \date 2005-10-24
|
|
* \author Norman Feske <norman.feske@genode-labs.com>
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2005-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.
|
|
*/
|
|
|
|
#include <scout/tick.h>
|
|
|
|
#include "scrollbar.h"
|
|
|
|
using namespace Scout;
|
|
|
|
#define SLIDER_RGBA _binary_slider_rgba_start
|
|
#define UPARROW_RGBA _binary_uparrow_rgba_start
|
|
#define DNARROW_RGBA _binary_downarrow_rgba_start
|
|
|
|
extern unsigned char SLIDER_RGBA[];
|
|
extern unsigned char UPARROW_RGBA[];
|
|
extern unsigned char DNARROW_RGBA[];
|
|
|
|
|
|
/********************
|
|
** Event handlers **
|
|
********************/
|
|
|
|
template <typename PT>
|
|
class Arrow_event_handler : public Event_handler, public Tick
|
|
{
|
|
private:
|
|
|
|
/*
|
|
* Noncopyable
|
|
*/
|
|
Arrow_event_handler(Arrow_event_handler const &);
|
|
Arrow_event_handler &operator = (Arrow_event_handler const &);
|
|
|
|
/**
|
|
* Constants
|
|
*/
|
|
static const int _max_speed = 16*256;
|
|
|
|
Scrollbar<PT> *_sb;
|
|
Fade_icon<PT, 32, 32> *_icon;
|
|
unsigned char *_rgba;
|
|
int _direction;
|
|
int _curr_speed = 0;
|
|
int _dst_speed = 0;
|
|
int _view_pos = 0;
|
|
int _accel = 1;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Arrow_event_handler(Scrollbar<PT> *sb,
|
|
Fade_icon<PT, 32, 32> *icon,
|
|
int direction,
|
|
unsigned char *rgba)
|
|
:
|
|
_sb(sb), _icon(icon), _rgba(rgba), _direction(direction)
|
|
{ }
|
|
|
|
/**
|
|
* Event handler interface
|
|
*/
|
|
void handle_event(Event const &ev) override
|
|
{
|
|
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)) {
|
|
|
|
/* press icon (slight vertical shift, darker shadow) */
|
|
_icon->rgba(_rgba, 1, 3);
|
|
_icon->refresh();
|
|
|
|
_curr_speed = _direction*256;
|
|
_dst_speed = _direction*_max_speed;
|
|
_accel = 16;
|
|
_view_pos = _sb->view_pos() << 8;
|
|
schedule(10);
|
|
}
|
|
|
|
if ((ev.type == Event::RELEASE) && (key_cnt == 0)) {
|
|
|
|
/* release icon */
|
|
_icon->rgba(_rgba);
|
|
_icon->refresh();
|
|
|
|
_accel = 64;
|
|
_dst_speed = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tick interface
|
|
*/
|
|
int on_tick() override
|
|
{
|
|
/* accelerate */
|
|
if (_curr_speed < _dst_speed)
|
|
_curr_speed = min(_curr_speed + _accel, _dst_speed);
|
|
|
|
/* decelerate */
|
|
if (_curr_speed > _dst_speed)
|
|
_curr_speed = max(_curr_speed - _accel, _dst_speed);
|
|
|
|
/* soft stopping on boundaries */
|
|
while ((_curr_speed < 0) && (_view_pos > 0)
|
|
&& (_curr_speed*_curr_speed > _view_pos*_accel*4))
|
|
_curr_speed = min(0, _curr_speed + _accel*4);
|
|
|
|
int max_pos;
|
|
while ((_curr_speed > 0)
|
|
&& ((max_pos = (_sb->real_size() - _sb->view_size())*256 - _view_pos) > 0)
|
|
&& (_curr_speed*_curr_speed > max_pos*_accel*4))
|
|
_curr_speed = max(0, _curr_speed - _accel*4);
|
|
|
|
/* move view position with current speed */
|
|
_view_pos = max(0, _view_pos + _curr_speed);
|
|
|
|
/* set new view position */
|
|
int old_view_pos = _sb->view_pos();
|
|
_sb->view(_sb->real_size(), _sb->view_size(), _view_pos>>8);
|
|
if (old_view_pos != _sb->view_pos())
|
|
_sb->notify_listener();
|
|
|
|
/* keep ticking as long as we are on speed */
|
|
return (_curr_speed != 0);
|
|
}
|
|
};
|
|
|
|
|
|
template <typename PT>
|
|
class Slider_event_handler : public Event_handler
|
|
{
|
|
private:
|
|
|
|
/*
|
|
* Noncopyable
|
|
*/
|
|
Slider_event_handler(Slider_event_handler const &);
|
|
Slider_event_handler &operator = (Slider_event_handler const &);
|
|
|
|
Scrollbar<PT> *_sb;
|
|
Fade_icon<PT, 32, 32> *_icon;
|
|
unsigned char *_rgba;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Slider_event_handler(Scrollbar<PT> *sb,
|
|
Fade_icon<PT, 32, 32> *icon,
|
|
unsigned char *rgba)
|
|
:
|
|
_sb(sb), _icon(icon), _rgba(rgba)
|
|
{ }
|
|
|
|
/**
|
|
* Event handler interface
|
|
*/
|
|
void handle_event(Event const &ev) override
|
|
{
|
|
static int key_cnt;
|
|
static int curr_my, orig_my;
|
|
static int orig_slider_pos;
|
|
|
|
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)) {
|
|
|
|
/* press icon (slight vertical shift, darker shadow) */
|
|
_icon->rgba(_rgba, 1, 3);
|
|
_icon->refresh();
|
|
|
|
orig_my = curr_my = ev.mouse_position.y();
|
|
orig_slider_pos = _sb->slider_pos();
|
|
}
|
|
|
|
if ((ev.type == Event::RELEASE) && (key_cnt == 0)) {
|
|
|
|
/* release icon */
|
|
_icon->rgba(_rgba);
|
|
_icon->refresh();
|
|
}
|
|
|
|
if (key_cnt && (ev.mouse_position.y() != curr_my)) {
|
|
curr_my = ev.mouse_position.y();
|
|
_sb->slider_pos(orig_slider_pos + curr_my - orig_my);
|
|
_sb->notify_listener();
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/*************************
|
|
** Scrollbar interface **
|
|
*************************/
|
|
|
|
template <typename PT>
|
|
Scrollbar<PT>::Scrollbar()
|
|
{
|
|
/* init scrollbar elements */
|
|
_slider.rgba(SLIDER_RGBA);
|
|
_uparrow.rgba(UPARROW_RGBA);
|
|
_dnarrow.rgba(DNARROW_RGBA);
|
|
|
|
_uparrow.alpha(0);
|
|
_dnarrow.alpha(0);
|
|
_slider .alpha(0);
|
|
|
|
append(&_uparrow);
|
|
append(&_dnarrow);
|
|
append(&_slider);
|
|
|
|
_min_size = Area(sb_elem_w, sb_elem_h*3);
|
|
|
|
/* define event handlers for scrollbar elements */
|
|
_uparrow.event_handler(new Arrow_event_handler<PT>(this, &_uparrow, -1, UPARROW_RGBA));
|
|
_dnarrow.event_handler(new Arrow_event_handler<PT>(this, &_dnarrow, 1, DNARROW_RGBA));
|
|
_slider.event_handler(new Slider_event_handler<PT>(this, &_slider, SLIDER_RGBA));
|
|
}
|
|
|
|
|
|
template <typename PT>
|
|
int Scrollbar<PT>::slider_size()
|
|
{
|
|
return max((unsigned)sb_elem_h, ((_size.h() - sb_elem_h*2)*_view_size)/_real_size);
|
|
}
|
|
|
|
|
|
template <typename PT>
|
|
int Scrollbar<PT>::slider_pos()
|
|
{
|
|
int real_range = _real_size - _view_size;
|
|
int slider_range = _size.h() - sb_elem_h*2 - slider_size();
|
|
int pos = real_range ? (slider_range*_view_pos)/real_range : 0;
|
|
|
|
return pos + sb_elem_h;
|
|
}
|
|
|
|
|
|
template <typename PT>
|
|
void Scrollbar<PT>::slider_pos(int pos)
|
|
{
|
|
int slider_bg_h = _size.h() - sb_elem_h*2;
|
|
|
|
_view_pos = ((pos - sb_elem_h)*_real_size)/slider_bg_h;
|
|
_view_pos = max(0, min(_view_pos, _real_size - _view_size));
|
|
|
|
_slider.geometry(Rect(Point(0, slider_pos()), Area(sb_elem_w, slider_size())));
|
|
}
|
|
|
|
|
|
template <typename PT>
|
|
void Scrollbar<PT>::view(int real_size, int view_size, int view_pos)
|
|
{
|
|
_real_size = real_size;
|
|
_view_size = min(view_size, real_size);
|
|
_view_pos = max(0, min(view_pos, _real_size - _view_size));
|
|
|
|
geometry(Rect(_position, _size));
|
|
}
|
|
|
|
|
|
template <typename PT>
|
|
void Scrollbar<PT>::notify_listener()
|
|
{
|
|
if (_listener)
|
|
_listener->handle_scroll(_view_pos);
|
|
}
|
|
|
|
|
|
/***********************
|
|
** Element interface **
|
|
***********************/
|
|
|
|
template <typename PT>
|
|
void Scrollbar<PT>::geometry(Rect rect)
|
|
{
|
|
Element::geometry(rect);
|
|
|
|
int new_visibility = _visible();
|
|
|
|
if (new_visibility) {
|
|
_uparrow.geometry(Rect(Point(0, 0), Area(sb_elem_w, sb_elem_h)));
|
|
_dnarrow.geometry(Rect(Point(0, rect.h() - sb_elem_h),
|
|
Area(sb_elem_w, sb_elem_h)));
|
|
_slider. geometry(Rect(Point(0, slider_pos()),
|
|
Area(sb_elem_w, slider_size())));
|
|
}
|
|
|
|
if (_visibility ^ new_visibility) {
|
|
int alpha = new_visibility ? _uparrow.default_alpha() : 0;
|
|
int speed = new_visibility ? 3 : 2;
|
|
_uparrow.fade_to(alpha, speed);
|
|
_dnarrow.fade_to(alpha, speed);
|
|
_slider. fade_to(alpha, speed);
|
|
}
|
|
|
|
_visibility = new_visibility;
|
|
}
|
|
|
|
|
|
template <typename PT>
|
|
Element *Scrollbar<PT>::find(Point position)
|
|
{
|
|
if (_visibility)
|
|
return Parent_element::find(position);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
template class Scrollbar<Genode::Pixel_rgb565>;
|