refactor scroll

This commit is contained in:
Jinhao
2018-12-05 06:36:40 +08:00
parent ab2d39397f
commit f4c71db98b
2 changed files with 123 additions and 135 deletions

View File

@@ -67,30 +67,30 @@ namespace nana
class drawer class drawer
{ {
public: public:
struct states enum class states
{ {
enum{ none, highlight, actived, selected }; none, highlight, actived, selected
}; };
using graph_reference = paint::graphics&; using graph_reference = paint::graphics&;
const static unsigned fixedsize = 16; // make it part of a new "metric" in the widget_scheme const static unsigned fixedsize = 16; // make it part of a new "metric" in the widget_scheme
drawer(metrics_type& m); drawer(bool vert);
void set_vertical(bool);
buttons what(graph_reference, const point&); buttons what(graph_reference, const point&);
void scroll_delta_pos(graph_reference, int); void scroll_delta_pos(graph_reference, int);
void auto_scroll(); void auto_scroll();
void draw(graph_reference, buttons); void draw(graph_reference);
private: private:
bool _m_check() const; bool _m_check() const;
void _m_adjust_scroll(graph_reference); void _m_adjust_scroll(graph_reference);
void _m_background(graph_reference); void _m_background(graph_reference);
void _m_button_frame(graph_reference, ::nana::rectangle, int state); void _m_button_frame(graph_reference, ::nana::rectangle, states state);
void _m_draw_scroll(graph_reference, int state); void _m_draw_scroll(graph_reference, states state);
void _m_draw_button(graph_reference, ::nana::rectangle, buttons what, int state); void _m_draw_button(graph_reference, ::nana::rectangle, buttons what, states state);
private: public:
metrics_type &metrics_; metrics_type metrics;
bool vertical_; bool const vert;
}; };
template<bool Vertical> template<bool Vertical>
@@ -101,35 +101,34 @@ namespace nana
typedef metrics_type::size_type size_type; typedef metrics_type::size_type size_type;
trigger() trigger()
: graph_(nullptr), drawer_(metrics_) : graph_(nullptr), drawer_(Vertical)
{ {
drawer_.set_vertical(Vertical);
} }
const metrics_type& metrics() const const metrics_type& metrics() const
{ {
return metrics_; return drawer_.metrics;
} }
void peak(size_type s) void peak(size_type s)
{ {
if (graph_ && (metrics_.peak != s)) if (graph_ && (drawer_.metrics.peak != s))
{ {
metrics_.peak = s; drawer_.metrics.peak = s;
API::refresh_window(widget_->handle()); API::refresh_window(widget_->handle());
} }
} }
void value(size_type s) void value(size_type s)
{ {
if (metrics_.range > metrics_.peak) if (drawer_.metrics.range > drawer_.metrics.peak)
s = 0; s = 0;
else if (s + metrics_.range > metrics_.peak) else if (s + drawer_.metrics.range > drawer_.metrics.peak)
s = metrics_.peak - metrics_.range; s = drawer_.metrics.peak - drawer_.metrics.range;
if (graph_ && (metrics_.value != s)) if (graph_ && (drawer_.metrics.value != s))
{ {
metrics_.value = s; drawer_.metrics.value = s;
_m_emit_value_changed(); _m_emit_value_changed();
API::refresh_window(*widget_); API::refresh_window(*widget_);
@@ -138,16 +137,16 @@ namespace nana
void range(size_type s) void range(size_type s)
{ {
if (graph_ && (metrics_.range != s)) if (graph_ && (drawer_.metrics.range != s))
{ {
metrics_.range = s; drawer_.metrics.range = s;
API::refresh_window(widget_->handle()); API::refresh_window(widget_->handle());
} }
} }
void step(size_type s) void step(size_type s)
{ {
metrics_.step = (s ? s : 1); drawer_.metrics.step = (s ? s : 1);
} }
bool make_step(bool forward, unsigned multiple) bool make_step(bool forward, unsigned multiple)
@@ -155,12 +154,12 @@ namespace nana
if (!graph_) if (!graph_)
return false; return false;
size_type step = (multiple > 1 ? metrics_.step * multiple : metrics_.step); size_type step = (multiple > 1 ? drawer_.metrics.step * multiple : drawer_.metrics.step);
size_type value = metrics_.value; size_type value = drawer_.metrics.value;
if (forward) if (forward)
{ {
size_type maxv = metrics_.peak - metrics_.range; size_type maxv = drawer_.metrics.peak - drawer_.metrics.range;
if (metrics_.peak > metrics_.range && value < maxv) if (drawer_.metrics.peak > drawer_.metrics.range && value < maxv)
{ {
if (maxv - value >= step) if (maxv - value >= step)
value += step; value += step;
@@ -175,8 +174,8 @@ namespace nana
else else
value = 0; value = 0;
} }
size_type cmpvalue = metrics_.value; size_type cmpvalue = drawer_.metrics.value;
metrics_.value = value; drawer_.metrics.value = value;
if (value != cmpvalue) if (value != cmpvalue)
{ {
_m_emit_value_changed(); _m_emit_value_changed();
@@ -202,47 +201,42 @@ namespace nana
void refresh(graph_reference graph) override void refresh(graph_reference graph) override
{ {
drawer_.draw(graph, metrics_.what); drawer_.draw(graph);
} }
void resized(graph_reference graph, const ::nana::arg_resized&) override void resized(graph_reference graph, const ::nana::arg_resized&) override
{ {
drawer_.draw(graph, metrics_.what); drawer_.draw(graph);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
void mouse_enter(graph_reference graph, const ::nana::arg_mouse& arg) override void mouse_enter(graph_reference graph, const ::nana::arg_mouse& arg) override
{ {
metrics_.what = drawer_.what(graph, arg.pos); drawer_.metrics.what = drawer_.what(graph, arg.pos);
drawer_.draw(graph, metrics_.what); drawer_.draw(graph);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override void mouse_move(graph_reference graph, const ::nana::arg_mouse& arg) override
{ {
bool redraw = false; if (drawer_.metrics.pressed && (drawer_.metrics.what == buttons::scroll))
if (metrics_.pressed && (metrics_.what == buttons::scroll))
{ {
size_type cmpvalue = metrics_.value; size_type cmpvalue = drawer_.metrics.value;
drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x)); drawer_.scroll_delta_pos(graph, (Vertical ? arg.pos.y : arg.pos.x));
if (cmpvalue != metrics_.value) if (cmpvalue != drawer_.metrics.value)
_m_emit_value_changed(); _m_emit_value_changed();
redraw = true;
} }
else else
{ {
buttons what = drawer_.what(graph, arg.pos); buttons what = drawer_.what(graph, arg.pos);
if (metrics_.what != what) if (drawer_.metrics.what == what)
{ return; //no change, don't redraw
redraw = true;
metrics_.what = what; drawer_.metrics.what = what;
}
}
if (redraw)
{
drawer_.draw(graph, metrics_.what);
API::dev::lazy_refresh();
} }
drawer_.draw(graph);
API::dev::lazy_refresh();
} }
void dbl_click(graph_reference graph, const arg_mouse& arg) override void dbl_click(graph_reference graph, const arg_mouse& arg) override
@@ -254,33 +248,33 @@ namespace nana
{ {
if (arg.left_button) if (arg.left_button)
{ {
metrics_.pressed = true; drawer_.metrics.pressed = true;
metrics_.what = drawer_.what(graph, arg.pos); drawer_.metrics.what = drawer_.what(graph, arg.pos);
switch (metrics_.what) switch (drawer_.metrics.what)
{ {
case buttons::first: case buttons::first:
case buttons::second: case buttons::second:
make_step(metrics_.what == buttons::second, 1); make_step(drawer_.metrics.what == buttons::second, 1);
timer_.interval(1000); timer_.interval(1000);
timer_.start(); timer_.start();
break; break;
case buttons::scroll: case buttons::scroll:
widget_->set_capture(true); widget_->set_capture(true);
metrics_.scroll_mouse_offset = (Vertical ? arg.pos.y : arg.pos.x) - metrics_.scroll_pos; drawer_.metrics.scroll_mouse_offset = (Vertical ? arg.pos.y : arg.pos.x) - drawer_.metrics.scroll_pos;
break; break;
case buttons::forward: case buttons::forward:
case buttons::backward: case buttons::backward:
{ {
size_type cmpvalue = metrics_.value; size_type cmpvalue = drawer_.metrics.value;
drawer_.auto_scroll(); drawer_.auto_scroll();
if (cmpvalue != metrics_.value) if (cmpvalue != drawer_.metrics.value)
_m_emit_value_changed(); _m_emit_value_changed();
} }
break; break;
default: //Ignore buttons::none default: //Ignore buttons::none
break; break;
} }
drawer_.draw(graph, metrics_.what); drawer_.draw(graph);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
} }
@@ -291,18 +285,18 @@ namespace nana
widget_->release_capture(); widget_->release_capture();
metrics_.pressed = false; drawer_.metrics.pressed = false;
metrics_.what = drawer_.what(graph, arg.pos); drawer_.metrics.what = drawer_.what(graph, arg.pos);
drawer_.draw(graph, metrics_.what); drawer_.draw(graph);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
void mouse_leave(graph_reference graph, const arg_mouse&) override void mouse_leave(graph_reference graph, const arg_mouse&) override
{ {
if (metrics_.pressed) return; if (drawer_.metrics.pressed) return;
metrics_.what = buttons::none; drawer_.metrics.what = buttons::none;
drawer_.draw(graph, buttons::none); drawer_.draw(graph);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
@@ -310,7 +304,7 @@ namespace nana
{ {
if (make_step(arg.upwards == false, 3)) if (make_step(arg.upwards == false, 3))
{ {
drawer_.draw(graph, metrics_.what); drawer_.draw(graph);
API::dev::lazy_refresh(); API::dev::lazy_refresh();
} }
} }
@@ -322,14 +316,13 @@ namespace nana
void _m_tick() void _m_tick()
{ {
make_step(metrics_.what == buttons::second, 1); make_step(drawer_.metrics.what == buttons::second, 1);
API::refresh_window(widget_->handle()); API::refresh_window(widget_->handle());
timer_.interval(100); timer_.interval(100);
} }
private: private:
::nana::scroll<Vertical> * widget_; ::nana::scroll<Vertical> * widget_;
nana::paint::graphics * graph_; nana::paint::graphics * graph_;
metrics_type metrics_;
drawer drawer_; drawer drawer_;
timer timer_; timer timer_;
}; };

View File

@@ -33,21 +33,16 @@ namespace nana
//end struct metrics_type //end struct metrics_type
//class drawer //class drawer
drawer::drawer(metrics_type& m) drawer::drawer(bool vert) :
:metrics_(m) vert(vert)
{} {}
void drawer::set_vertical(bool v)
{
vertical_ = v;
}
buttons drawer::what(graph_reference graph, const point& screen_pos) buttons drawer::what(graph_reference graph, const point& screen_pos)
{ {
unsigned scale; unsigned scale;
int pos; int pos;
if(vertical_) if(vert)
{ {
scale = graph.height(); scale = graph.height();
pos = screen_pos.y; pos = screen_pos.y;
@@ -64,15 +59,15 @@ namespace nana
if (pos > static_cast<int>(scale) - bound_pos) if (pos > static_cast<int>(scale) - bound_pos)
return buttons::second; return buttons::second;
if(metrics_.scroll_length) if(metrics.scroll_length)
{ {
if(metrics_.scroll_pos + static_cast<int>(fixedsize) <= pos && pos < metrics_.scroll_pos + static_cast<int>(fixedsize + metrics_.scroll_length)) if(metrics.scroll_pos + static_cast<int>(fixedsize) <= pos && pos < metrics.scroll_pos + static_cast<int>(fixedsize + metrics.scroll_length))
return buttons::scroll; return buttons::scroll;
} }
if(static_cast<int>(fixedsize) <= pos && pos < metrics_.scroll_pos) if(static_cast<int>(fixedsize) <= pos && pos < metrics.scroll_pos)
return buttons::forward; return buttons::forward;
else if(metrics_.scroll_pos + static_cast<int>(metrics_.scroll_length) <= pos && pos < static_cast<int>(scale - fixedsize)) else if(metrics.scroll_pos + static_cast<int>(metrics.scroll_length) <= pos && pos < static_cast<int>(scale - fixedsize))
return buttons::backward; return buttons::backward;
return buttons::none; return buttons::none;
@@ -80,39 +75,39 @@ namespace nana
void drawer::scroll_delta_pos(graph_reference graph, int mouse_pos) void drawer::scroll_delta_pos(graph_reference graph, int mouse_pos)
{ {
if(mouse_pos + metrics_.scroll_mouse_offset == metrics_.scroll_pos) return; if(mouse_pos + metrics.scroll_mouse_offset == metrics.scroll_pos) return;
unsigned scale = vertical_ ? graph.height() : graph.width(); unsigned scale = vert ? graph.height() : graph.width();
if(scale > fixedsize * 2) if(scale > fixedsize * 2)
{ {
int pos = mouse_pos - metrics_.scroll_mouse_offset; int pos = mouse_pos - metrics.scroll_mouse_offset;
const unsigned scroll_area = static_cast<unsigned>(scale - fixedsize * 2 - metrics_.scroll_length); const unsigned scroll_area = static_cast<unsigned>(scale - fixedsize * 2 - metrics.scroll_length);
if(pos < 0) if(pos < 0)
pos = 0; pos = 0;
else if(pos > static_cast<int>(scroll_area)) else if(pos > static_cast<int>(scroll_area))
pos = static_cast<int>(scroll_area); pos = static_cast<int>(scroll_area);
metrics_.scroll_pos = pos; metrics.scroll_pos = pos;
auto value_max = metrics_.peak - metrics_.range; auto value_max = metrics.peak - metrics.range;
//Check scroll_area to avoiding division by zero. //Check scroll_area to avoiding division by zero.
if (scroll_area) if (scroll_area)
metrics_.value = static_cast<std::size_t>(pos * (static_cast<double>(value_max) / scroll_area)); //converting to double to avoid overflow. metrics.value = static_cast<std::size_t>(pos * (static_cast<double>(value_max) / scroll_area)); //converting to double to avoid overflow.
if (metrics_.value < value_max) if (metrics.value < value_max)
{ {
//converting to double to avoid overflow. //converting to double to avoid overflow.
auto const px_per_value = static_cast<double>(scroll_area) / value_max; auto const px_per_value = static_cast<double>(scroll_area) / value_max;
int selfpos = static_cast<int>(metrics_.value * px_per_value); int selfpos = static_cast<int>(metrics.value * px_per_value);
int nextpos = static_cast<int>((metrics_.value + 1) * px_per_value); int nextpos = static_cast<int>((metrics.value + 1) * px_per_value);
if(selfpos != nextpos && (pos - selfpos > nextpos - pos)) if(selfpos != nextpos && (pos - selfpos > nextpos - pos))
++metrics_.value; ++metrics.value;
} }
else else
metrics_.value = value_max; metrics.value = value_max;
} }
} }
@@ -121,46 +116,46 @@ namespace nana
if (!_m_check()) if (!_m_check())
return; return;
if(buttons::forward == metrics_.what) if(buttons::forward == metrics.what)
{ //backward { //backward
if(metrics_.value <= metrics_.range) if(metrics.value <= metrics.range)
metrics_.value = 0; metrics.value = 0;
else else
metrics_.value -= (metrics_.range-1); metrics.value -= (metrics.range-1);
} }
else if(buttons::backward == metrics_.what) else if(buttons::backward == metrics.what)
{ {
if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range) if(metrics.peak - metrics.range - metrics.value <= metrics.range)
metrics_.value = metrics_.peak - metrics_.range; metrics.value = metrics.peak - metrics.range;
else else
metrics_.value += (metrics_.range-1); metrics.value += (metrics.range-1);
} }
} }
void drawer::draw(graph_reference graph, buttons what) void drawer::draw(graph_reference graph)
{ {
if(false == metrics_.pressed || metrics_.what != buttons::scroll) if(false == metrics.pressed || metrics.what != buttons::scroll)
_m_adjust_scroll(graph); _m_adjust_scroll(graph);
_m_background(graph); _m_background(graph);
rectangle_rotator r(vertical_, ::nana::rectangle{ graph.size() }); rectangle_rotator r(vert, ::nana::rectangle{ graph.size() });
r.x_ref() = static_cast<int>(r.w() - fixedsize); r.x_ref() = static_cast<int>(r.w() - fixedsize);
r.w_ref() = fixedsize; r.w_ref() = fixedsize;
int state = ((_m_check() == false || what == buttons::none) ? states::none : states::highlight); auto state = ((_m_check() == false || metrics.what == buttons::none) ? states::none : states::highlight);
int moused_state = (_m_check() ? (metrics_.pressed ? states::selected : states::actived) : states::none); auto moused_state = (_m_check() ? (metrics.pressed ? states::selected : states::actived) : states::none);
auto result = r.result(); auto result = r.result();
//draw first //draw first
_m_draw_button(graph, { 0, 0, result.width, result.height }, buttons::first, (buttons::first == what ? moused_state : state)); _m_draw_button(graph, { 0, 0, result.width, result.height }, buttons::first, (buttons::first == metrics.what ? moused_state : state));
//draw second //draw second
_m_draw_button(graph, result, buttons::second, (buttons::second == what ? moused_state : state)); _m_draw_button(graph, result, buttons::second, (buttons::second == metrics.what ? moused_state : state));
//draw scroll //draw scroll
_m_draw_scroll(graph, (buttons::scroll == what ? moused_state : states::highlight)); _m_draw_scroll(graph, (buttons::scroll == metrics.what ? moused_state : states::highlight));
} }
//private: //private:
@@ -168,19 +163,19 @@ namespace nana
{ {
graph.rectangle(true, {0xf0, 0xf0, 0xf0}); graph.rectangle(true, {0xf0, 0xf0, 0xf0});
if (!metrics_.pressed || !_m_check()) if (!metrics.pressed || !_m_check())
return; return;
nana::rectangle_rotator r(vertical_, ::nana::rectangle{ graph.size() }); nana::rectangle_rotator r(vert, ::nana::rectangle{ graph.size() });
if(metrics_.what == buttons::forward) if(metrics.what == buttons::forward)
{ {
r.x_ref() = static_cast<int>(fixedsize); r.x_ref() = static_cast<int>(fixedsize);
r.w_ref() = metrics_.scroll_pos; r.w_ref() = metrics.scroll_pos;
} }
else if(buttons::backward == metrics_.what) else if(buttons::backward == metrics.what)
{ {
r.x_ref() = static_cast<int>(fixedsize + metrics_.scroll_pos + metrics_.scroll_length); r.x_ref() = static_cast<int>(fixedsize + metrics.scroll_pos + metrics.scroll_length);
r.w_ref() = static_cast<unsigned>((vertical_ ? graph.height() : graph.width()) - (fixedsize * 2 + metrics_.scroll_pos + metrics_.scroll_length)); r.w_ref() = static_cast<unsigned>((vert ? graph.height() : graph.width()) - (fixedsize * 2 + metrics.scroll_pos + metrics.scroll_length));
} }
else else
return; return;
@@ -190,9 +185,9 @@ namespace nana
graph.rectangle(result, true, static_cast<color_rgb>(0xDCDCDC)); graph.rectangle(result, true, static_cast<color_rgb>(0xDCDCDC));
} }
void drawer::_m_button_frame(graph_reference graph, rectangle r, int state) void drawer::_m_button_frame(graph_reference graph, rectangle r, states state)
{ {
if (!state) if (states::none == state)
return; return;
::nana::color clr{0x97, 0x97, 0x97}; //highlight ::nana::color clr{0x97, 0x97, 0x97}; //highlight
@@ -210,7 +205,7 @@ namespace nana
graph.palette(false, clr); graph.palette(false, clr);
r.pare_off(2); r.pare_off(2);
if(vertical_) if(vert)
{ {
unsigned half = r.width / 2; unsigned half = r.width / 2;
graph.rectangle({ r.x + static_cast<int>(r.width - half), r.y, half, r.height }, true); graph.rectangle({ r.x + static_cast<int>(r.width - half), r.y, half, r.height }, true);
@@ -222,19 +217,19 @@ namespace nana
graph.rectangle({r.x, r.y + static_cast<int>(r.height - half), r.width, half}, true); graph.rectangle({r.x, r.y + static_cast<int>(r.height - half), r.width, half}, true);
r.height -= half; r.height -= half;
} }
graph.gradual_rectangle(r, colors::white, clr, !vertical_); graph.gradual_rectangle(r, colors::white, clr, !vert);
} }
bool drawer::_m_check() const bool drawer::_m_check() const
{ {
return (metrics_.scroll_length && metrics_.range && (metrics_.peak > metrics_.range)); return (metrics.scroll_length && metrics.range && (metrics.peak > metrics.range));
} }
void drawer::_m_adjust_scroll(graph_reference graph) void drawer::_m_adjust_scroll(graph_reference graph)
{ {
if(metrics_.range == 0 || metrics_.peak <= metrics_.range) return; if(metrics.range == 0 || metrics.peak <= metrics.range) return;
unsigned pixels = vertical_ ? graph.height() : graph.width(); unsigned pixels = vert ? graph.height() : graph.width();
int pos = 0; int pos = 0;
unsigned len = 0; unsigned len = 0;
@@ -242,38 +237,38 @@ namespace nana
if(pixels > fixedsize * 2) if(pixels > fixedsize * 2)
{ {
pixels -= (fixedsize * 2); pixels -= (fixedsize * 2);
len = static_cast<unsigned>(pixels * metrics_.range / metrics_.peak); len = static_cast<unsigned>(pixels * metrics.range / metrics.peak);
if(len < fixedsize) if(len < fixedsize)
len = fixedsize; len = fixedsize;
if(metrics_.value) if(metrics.value)
{ {
pos = static_cast<int>(pixels - len); pos = static_cast<int>(pixels - len);
if(metrics_.value + metrics_.range >= metrics_.peak) if(metrics.value + metrics.range >= metrics.peak)
metrics_.value = metrics_.peak - metrics_.range; metrics.value = metrics.peak - metrics.range;
else else
pos = static_cast<int>((metrics_.value * pos) /(metrics_.peak - metrics_.range)); pos = static_cast<int>((metrics.value * pos) /(metrics.peak - metrics.range));
} }
} }
metrics_.scroll_pos = pos; metrics.scroll_pos = pos;
metrics_.scroll_length = len; metrics.scroll_length = len;
} }
void drawer::_m_draw_scroll(graph_reference graph, int state) void drawer::_m_draw_scroll(graph_reference graph, states state)
{ {
if(_m_check()) if(_m_check())
{ {
rectangle_rotator r(vertical_, rectangle{ graph.size() }); rectangle_rotator r(vert, rectangle{ graph.size() });
r.x_ref() = static_cast<int>(fixedsize + metrics_.scroll_pos); r.x_ref() = static_cast<int>(fixedsize + metrics.scroll_pos);
r.w_ref() = static_cast<unsigned>(metrics_.scroll_length); r.w_ref() = static_cast<unsigned>(metrics.scroll_length);
_m_button_frame(graph, r.result(), state); _m_button_frame(graph, r.result(), state);
} }
} }
void drawer::_m_draw_button(graph_reference graph, rectangle r, buttons what, int state) void drawer::_m_draw_button(graph_reference graph, rectangle r, buttons what, states state)
{ {
if(_m_check()) if(_m_check())
_m_button_frame(graph, r, state); _m_button_frame(graph, r, state);
@@ -287,7 +282,7 @@ namespace nana
direction dir; direction dir;
if (buttons::second == what) if (buttons::second == what)
{ {
if (vertical_) if (vert)
{ {
r.y = top; r.y = top;
dir = direction::south; dir = direction::south;
@@ -299,9 +294,9 @@ namespace nana
} }
} }
else else
dir = vertical_ ? direction::north : direction::west; dir = vert ? direction::north : direction::west;
if (vertical_) if (vert)
r.x = left / 2; r.x = left / 2;
else else
r.y = top / 2; r.y = top / 2;