904 lines
23 KiB
C++
904 lines
23 KiB
C++
|
|
#include <nana/gui/widgets/slider.hpp>
|
|
#include <nana/paint/pixel_buffer.hpp>
|
|
#include <cstring> //memcpy
|
|
|
|
namespace nana
|
|
{
|
|
arg_slider::arg_slider(slider& wdg)
|
|
: widget(wdg)
|
|
{}
|
|
|
|
namespace drawerbase
|
|
{
|
|
namespace slider
|
|
{
|
|
|
|
class interior_renderer
|
|
: public renderer_interface
|
|
{
|
|
private:
|
|
void background(window, graph_reference graph, bool transparent, const scheme& schm) override
|
|
{
|
|
if (!transparent)
|
|
graph.rectangle(true, schm.background);
|
|
}
|
|
|
|
void bar(window, graph_reference graph, const data_bar& data, const scheme& schm) override
|
|
{
|
|
auto area = data.area;
|
|
|
|
if (data.vert)
|
|
{
|
|
area.x = area.width / 2 - 2;
|
|
area.width = 4;
|
|
}
|
|
else
|
|
{
|
|
area.y = area.height / 2 - 2;
|
|
area.height = 4;
|
|
}
|
|
|
|
graph.rectangle(area, false, schm.color_bar);
|
|
}
|
|
|
|
void adorn(window, graph_reference graph, const data_adorn& data, const scheme& schm) override
|
|
{
|
|
rectangle area{
|
|
data.bound.x, data.fixedpos + static_cast<int>(data.block / 2) - 1,
|
|
static_cast<unsigned>(data.bound.y - data.bound.x) , 2
|
|
};
|
|
|
|
if (data.vert)
|
|
area.shift();
|
|
|
|
graph.rectangle(area, true, schm.color_adorn);
|
|
|
|
}
|
|
|
|
void vernier(window, graph_reference graph, const data_vernier& data, const scheme& schm) override
|
|
{
|
|
if (data.vert)
|
|
_m_draw_vernier_vert(graph, data, schm);
|
|
else
|
|
_m_draw_vernier_horz(graph, data, schm);
|
|
}
|
|
|
|
void slider(window, graph_reference graph, mouse_action mouse_act, const data_slider& data, const scheme& schm) override
|
|
{
|
|
nana::rectangle area{ graph.size() };
|
|
|
|
if (data.vert)
|
|
{
|
|
area.y = static_cast<int>(data.pos);
|
|
area.height = data.weight;
|
|
}
|
|
else
|
|
{
|
|
area.x = static_cast<int>(data.pos);
|
|
area.width = data.weight;
|
|
}
|
|
|
|
color rgb = schm.color_slider;
|
|
if (mouse_action::normal != mouse_act)
|
|
rgb = schm.color_slider_highlighted;
|
|
|
|
graph.frame_rectangle(area, rgb + static_cast<color_rgb>(0x0d0d0d), 1);
|
|
graph.rectangle(area.pare_off(1), true, rgb);
|
|
|
|
area.height /= 2;
|
|
graph.rectangle(area, true, rgb + static_cast<color_rgb>(0x101010));
|
|
}
|
|
private:
|
|
void _m_draw_vernier_horz(graph_reference graph, const data_vernier& data, const scheme& schm)
|
|
{
|
|
const unsigned arrow_weight = 5;
|
|
|
|
unsigned arrow_pxbuf[] = {
|
|
0x7F, 0x00, 0x00, 0x00, 0x00,
|
|
0x7F, 0x7F, 0x00, 0x00, 0x00,
|
|
0x7F, 0x7F, 0x7F, 0x00, 0x00,
|
|
0x7F, 0x7F, 0x7F, 0x7F, 0x00,
|
|
0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
|
|
0x7F, 0x7F, 0x7F, 0x7F, 0x00,
|
|
0x7F, 0x7F, 0x7F, 0x00, 0x00,
|
|
0x7F, 0x7F, 0x00, 0x00, 0x00,
|
|
0x7F, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
const size arrow_size{ arrow_weight, 9 };
|
|
|
|
const auto label_size = graph.text_extent_size(data.text) + size{ schm.vernier_text_margin * 2, 0 };
|
|
|
|
paint::graphics graph_vern{ label_size };
|
|
graph_vern.rectangle(true, schm.color_vernier);
|
|
|
|
int arrow_pos;
|
|
|
|
point label_pos{ data.position, static_cast<int>(graph.height() - label_size.height) / 2 };
|
|
|
|
if (static_cast<int>(label_size.width + arrow_weight) > data.position)
|
|
{
|
|
label_pos.x += arrow_weight;
|
|
arrow_pos = data.position;
|
|
}
|
|
else
|
|
{
|
|
label_pos.x -= label_size.width + arrow_weight;
|
|
arrow_pos = data.position - arrow_weight;
|
|
}
|
|
|
|
graph_vern.blend(rectangle{ label_size }, graph, label_pos, 0.5);
|
|
|
|
|
|
unsigned arrow_color = 0x7F | schm.color_vernier.get_color().argb().value;
|
|
for (auto & color : arrow_pxbuf)
|
|
{
|
|
if (color == 0x7F)
|
|
color = arrow_color;
|
|
}
|
|
|
|
if (label_pos.x > data.position)
|
|
{
|
|
for (::nana::size::value_type l = 0; l < arrow_size.height; ++l)
|
|
{
|
|
auto ptr = arrow_pxbuf + l * arrow_size.width;
|
|
|
|
for (::nana::size::value_type x = 0; x < arrow_size.width / 2; ++x)
|
|
std::swap(ptr[x], ptr[(arrow_size.width - 1) - x]);
|
|
}
|
|
}
|
|
|
|
paint::pixel_buffer pxbuf{ arrow_size.width, arrow_size.height };
|
|
pxbuf.alpha_channel(true);
|
|
pxbuf.put(reinterpret_cast<unsigned char*>(arrow_pxbuf), arrow_size.width, arrow_size.height, 32, arrow_size.width * 4, false);
|
|
|
|
pxbuf.paste(rectangle{ arrow_size }, graph.handle(), { arrow_pos, label_pos.y + static_cast<int>(label_size.height - arrow_size.height) / 2 });
|
|
|
|
label_pos.x += static_cast<int>(schm.vernier_text_margin);
|
|
graph.string(label_pos, data.text, schm.color_vernier_text);
|
|
}
|
|
|
|
void _m_draw_vernier_vert(graph_reference graph, const data_vernier& data, const scheme& schm)
|
|
{
|
|
const unsigned arrow_weight = 5;
|
|
|
|
unsigned arrow_pxbuf[] = {
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x00,
|
|
0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
const size arrow_size{ 9, arrow_weight};
|
|
|
|
const size label_size = (graph.text_extent_size(data.text) + size{ schm.vernier_text_margin * 2, 0 }).shift();
|
|
|
|
paint::graphics graph_vern{ label_size };
|
|
|
|
paint::graphics graph_horz{ size(label_size).shift() };
|
|
graph_horz.rectangle(true, schm.color_vernier);
|
|
graph_horz.string({ static_cast<int>(schm.vernier_text_margin), static_cast<int>(graph_horz.height() - label_size.width) / 2 }, data.text, schm.color_vernier_text);
|
|
|
|
paint::pixel_buffer{ graph_horz.handle(), 0, graph_horz.height() }.rotate(90, colors::white).paste(graph_vern.handle(), {});
|
|
|
|
int arrow_pos;
|
|
|
|
point label_pos{ static_cast<int>(graph.width() - label_size.width) / 2, data.position };
|
|
|
|
if (static_cast<int>(label_size.height + arrow_weight) > (data.end_position - data.position))
|
|
{
|
|
label_pos.y -= arrow_weight + label_size.height;
|
|
arrow_pos = data.position - arrow_weight;
|
|
|
|
const unsigned line_bytes = arrow_size.width * sizeof(unsigned);
|
|
for (size::value_type l = 0; l < arrow_size.height / 2; ++l)
|
|
{
|
|
auto swap_x = arrow_pxbuf + l* arrow_size.width;
|
|
auto swap_y = arrow_pxbuf + (arrow_size.height - 1 - l) * arrow_size.width;
|
|
|
|
unsigned tmp[9];
|
|
std::memcpy(tmp, swap_x, line_bytes);
|
|
std::memcpy(swap_x, swap_y, line_bytes);
|
|
std::memcpy(swap_y, tmp, line_bytes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
label_pos.y += arrow_weight;
|
|
arrow_pos = data.position;
|
|
}
|
|
|
|
graph_vern.blend(rectangle{ label_size }, graph, label_pos, 0.5);
|
|
|
|
|
|
unsigned arrow_color = 0x7F | schm.color_vernier.get_color().argb().value;
|
|
for (auto & color : arrow_pxbuf)
|
|
{
|
|
if (color == 0x7F)
|
|
color = arrow_color;
|
|
}
|
|
|
|
|
|
paint::pixel_buffer pxbuf{ arrow_size.width, arrow_size.height };
|
|
pxbuf.alpha_channel(true);
|
|
pxbuf.put(reinterpret_cast<unsigned char*>(arrow_pxbuf), arrow_size.width, arrow_size.height, 32, arrow_size.width * 4, false);
|
|
|
|
pxbuf.paste(rectangle{ arrow_size }, graph.handle(), { label_pos.x + static_cast<int>(label_size.width - arrow_size.width) / 2, arrow_pos });
|
|
|
|
label_pos.y += static_cast<int>(schm.vernier_text_margin);
|
|
}
|
|
};
|
|
|
|
class trigger::model
|
|
{
|
|
struct attrib_rep
|
|
{
|
|
seekdir seek_dir;
|
|
bool is_draw_adorn;
|
|
|
|
unsigned vmax;
|
|
double vcur;
|
|
double adorn_pos;
|
|
|
|
renderer_interface::data_slider slider;
|
|
};
|
|
public:
|
|
enum class parts{none, bar, slider};
|
|
|
|
using graph_reference = drawer_trigger::graph_reference;
|
|
|
|
model()
|
|
{
|
|
other_.wd = nullptr;
|
|
other_.widget = nullptr;
|
|
|
|
proto_.renderer = pat::cloneable<renderer_interface>{interior_renderer{}};
|
|
|
|
attr_.seek_dir = seekdir::bilateral;
|
|
|
|
attr_.is_draw_adorn = false;
|
|
attr_.vcur = 0;
|
|
attr_.vmax = 10;
|
|
|
|
attr_.slider.vert = false;
|
|
attr_.slider.border_weight = 1;
|
|
attr_.slider.pos = 0;
|
|
attr_.slider.weight = 8;
|
|
}
|
|
|
|
void seek_direction(seekdir sd)
|
|
{
|
|
attr_.seek_dir = sd;
|
|
}
|
|
|
|
window handle() const
|
|
{
|
|
return other_.wd;
|
|
}
|
|
|
|
void attached(nana::slider& wdg, graph_reference)
|
|
{
|
|
other_.wd = wdg.handle();
|
|
other_.widget = &wdg;
|
|
|
|
_m_mk_slider_pos_by_value();
|
|
}
|
|
|
|
pat::cloneable<renderer_interface>& renderer()
|
|
{
|
|
return proto_.renderer;
|
|
}
|
|
|
|
void vernier(std::function<std::string(unsigned maximum, unsigned cursor_value)> vernier_string)
|
|
{
|
|
proto_.vernier = vernier_string;
|
|
}
|
|
|
|
void draw(graph_reference graph)
|
|
{
|
|
if(!graph.size().empty())
|
|
{
|
|
proto_.renderer->background(other_.wd, graph, API::dev::copy_transparent_background(other_.wd, graph), other_.widget->scheme());
|
|
_m_draw_elements(graph);
|
|
}
|
|
}
|
|
|
|
const attrib_rep & attribute() const
|
|
{
|
|
return attr_;
|
|
}
|
|
|
|
bool vertical(bool vert)
|
|
{
|
|
if (vert != attr_.slider.vert)
|
|
{
|
|
attr_.slider.vert = vert;
|
|
_m_mk_slider_pos_by_value();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void maximum(unsigned m)
|
|
{
|
|
if(m == 0) m = 1;
|
|
|
|
if (attr_.vmax == m)
|
|
return;
|
|
|
|
attr_.vmax = m;
|
|
if(attr_.vcur > m)
|
|
{
|
|
attr_.vcur = m;
|
|
_m_emit_value_changed();
|
|
}
|
|
|
|
_m_mk_slider_pos_by_value();
|
|
API::refresh_window(other_.wd);
|
|
}
|
|
|
|
bool vcur(unsigned v)
|
|
{
|
|
if(attr_.vmax < v)
|
|
v = attr_.vmax;
|
|
|
|
if(attr_.vcur != v)
|
|
{
|
|
attr_.vcur = v;
|
|
this->_m_mk_slider_pos_by_value();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void resize()
|
|
{
|
|
_m_mk_slider_pos_by_value();
|
|
attr_.adorn_pos = attr_.slider.pos;
|
|
}
|
|
|
|
parts seek_where(::nana::point pos) const
|
|
{
|
|
nana::rectangle r = _m_bar_area();
|
|
|
|
if (attr_.slider.vert)
|
|
{
|
|
std::swap(pos.x, pos.y);
|
|
std::swap(r.width, r.height);
|
|
}
|
|
|
|
int sdpos = _m_slider_pos();
|
|
if (sdpos <= pos.x && pos.x < sdpos + static_cast<int>(attr_.slider.weight))
|
|
return parts::slider;
|
|
|
|
sdpos = static_cast<int>(attr_.slider.weight) / 2;
|
|
|
|
if (sdpos <= pos.x && pos.x < sdpos + static_cast<int>(r.width))
|
|
{
|
|
if(pos.y < r.bottom())
|
|
return parts::bar;
|
|
}
|
|
return parts::none;
|
|
}
|
|
|
|
//set_slider_pos
|
|
//move the slider to a position where a mouse click on WhereBar.
|
|
bool set_slider_pos(::nana::point pos)
|
|
{
|
|
if(attr_.slider.vert)
|
|
std::swap(pos.x, pos.y);
|
|
|
|
pos.x -= _m_slider_refpos();
|
|
if(pos.x < 0)
|
|
return false;
|
|
|
|
if(pos.x > static_cast<int>(_m_range()))
|
|
pos.x = static_cast<int>(_m_range());
|
|
|
|
auto attr_pos = attr_.slider.pos;
|
|
double dx = _m_evaluate_by_seekdir(pos.x);
|
|
|
|
attr_.slider.pos = dx;
|
|
attr_.adorn_pos = dx;
|
|
_m_mk_slider_value_by_pos();
|
|
|
|
return (attr_.slider.pos != attr_pos);
|
|
}
|
|
|
|
void set_slider_refpos(::nana::point pos)
|
|
{
|
|
if (attr_.slider.vert)
|
|
std::swap(pos.x, pos.y);
|
|
|
|
slider_state_.mouse_state = ::nana::mouse_action::pressed;
|
|
slider_state_.snap_pos = static_cast<int>(attr_.slider.pos);
|
|
slider_state_.refpos = pos;
|
|
API::set_capture(other_.wd, true);
|
|
}
|
|
|
|
bool release_slider()
|
|
{
|
|
if(::nana::mouse_action::pressed == slider_state_.mouse_state)
|
|
{
|
|
API::release_capture(other_.wd);
|
|
|
|
if (other_.wd != API::find_window(API::cursor_position()))
|
|
{
|
|
slider_state_.mouse_state = ::nana::mouse_action::normal;
|
|
attr_.is_draw_adorn = false;
|
|
}
|
|
else
|
|
slider_state_.mouse_state = ::nana::mouse_action::hovered;
|
|
|
|
_m_mk_slider_value_by_pos();
|
|
_m_mk_slider_pos_by_value();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool if_trace_slider() const
|
|
{
|
|
return (::nana::mouse_action::pressed == slider_state_.mouse_state);
|
|
}
|
|
|
|
bool move_slider(const ::nana::point& pos)
|
|
{
|
|
int adorn_pos = slider_state_.snap_pos + (attr_.slider.vert ? pos.y : pos.x) - slider_state_.refpos.x;
|
|
|
|
if (adorn_pos > 0)
|
|
{
|
|
int range = static_cast<int>(_m_range());
|
|
if (adorn_pos > range)
|
|
adorn_pos = range;
|
|
}
|
|
else
|
|
adorn_pos = 0;
|
|
|
|
double dstpos = _m_evaluate_by_seekdir(adorn_pos);
|
|
attr_.is_draw_adorn = true;
|
|
|
|
if(dstpos != attr_.slider.pos)
|
|
{
|
|
attr_.slider.pos = dstpos;
|
|
attr_.adorn_pos = dstpos;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool move_adorn(const ::nana::point& pos)
|
|
{
|
|
double xpos = (attr_.slider.vert ? pos.y : pos.x) - _m_slider_refpos();
|
|
|
|
auto range = static_cast<int>(_m_range());
|
|
if (xpos > range)
|
|
xpos = range;
|
|
|
|
int adorn_pos = static_cast<int>(attr_.adorn_pos);
|
|
xpos = _m_evaluate_by_seekdir(xpos);
|
|
|
|
attr_.adorn_pos = xpos;
|
|
attr_.is_draw_adorn = true;
|
|
|
|
if (::nana::mouse_action::normal == slider_state_.mouse_state)
|
|
slider_state_.mouse_state = ::nana::mouse_action::hovered;
|
|
|
|
return (adorn_pos != static_cast<int>(xpos));
|
|
}
|
|
|
|
unsigned move_step(bool forward)
|
|
{
|
|
unsigned cmpvalue = static_cast<unsigned>(attr_.vcur);
|
|
auto value = cmpvalue;
|
|
if(forward)
|
|
{
|
|
if (value)
|
|
--value;
|
|
}
|
|
else if (value < attr_.vmax)
|
|
++value;
|
|
|
|
attr_.vcur = value;
|
|
if (cmpvalue != value)
|
|
{
|
|
_m_mk_slider_pos_by_value();
|
|
API::refresh_window(other_.wd);
|
|
|
|
_m_emit_value_changed();
|
|
}
|
|
|
|
return cmpvalue;
|
|
}
|
|
|
|
unsigned adorn() const
|
|
{
|
|
return _m_value_by_pos(attr_.adorn_pos);
|
|
}
|
|
|
|
bool reset_adorn()
|
|
{
|
|
//Test if the slider is captured, the operation should be ignored. Because the mouse_leave always be generated even through
|
|
//the slider is captured.
|
|
if((::nana::mouse_action::pressed == slider_state_.mouse_state) && (API::capture_window() == this->other_.wd))
|
|
return false;
|
|
|
|
slider_state_.mouse_state = ::nana::mouse_action::normal;
|
|
attr_.is_draw_adorn = false;
|
|
if(attr_.adorn_pos != attr_.slider.pos)
|
|
{
|
|
attr_.adorn_pos = attr_.slider.pos;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
void _m_emit_value_changed() const
|
|
{
|
|
other_.widget->events().value_changed.emit(::nana::arg_slider{ *other_.widget }, other_.widget->handle());
|
|
}
|
|
|
|
::nana::rectangle _m_bar_area() const
|
|
{
|
|
auto sz = other_.widget->size();
|
|
|
|
nana::rectangle area{ sz };
|
|
if (attr_.slider.vert)
|
|
{
|
|
area.y = attr_.slider.weight / 2 - attr_.slider.border_weight;
|
|
area.height = (static_cast<int>(sz.height) > (area.y << 1) ? sz.height - (area.y << 1) : 0);
|
|
}
|
|
else
|
|
{
|
|
area.x = attr_.slider.weight / 2 - attr_.slider.border_weight;
|
|
area.width = (static_cast<int>(sz.width) > (area.x << 1) ? sz.width - (area.x << 1) : 0);
|
|
}
|
|
return area;
|
|
}
|
|
|
|
unsigned _m_range() const
|
|
{
|
|
nana::rectangle r = _m_bar_area();
|
|
return (attr_.slider.vert ? r.height : r.width) - attr_.slider.border_weight * 2;
|
|
}
|
|
|
|
double _m_evaluate_by_seekdir(double pos) const
|
|
{
|
|
if (seekdir::bilateral != attr_.seek_dir)
|
|
{
|
|
if ((seekdir::backward == attr_.seek_dir) == (pos < attr_.slider.pos))
|
|
pos = attr_.slider.pos;
|
|
}
|
|
return (pos < 0 ? 0 : pos);
|
|
}
|
|
|
|
int _m_slider_refpos() const
|
|
{
|
|
return static_cast<int>(attr_.slider.weight / 2);
|
|
}
|
|
|
|
int _m_slider_pos() const
|
|
{
|
|
return static_cast<int>(_m_range() * attr_.vcur / attr_.vmax);
|
|
}
|
|
|
|
void _m_mk_slider_value_by_pos()
|
|
{
|
|
auto range = _m_range();
|
|
if (range)
|
|
{
|
|
auto cmpvalue = static_cast<int>(attr_.vcur);
|
|
if (attr_.slider.vert)
|
|
attr_.vcur = (range - attr_.slider.pos) * attr_.vmax;
|
|
else
|
|
attr_.vcur = (attr_.slider.pos * attr_.vmax);
|
|
|
|
attr_.vcur /= range;
|
|
if (cmpvalue != static_cast<int>(attr_.vcur))
|
|
_m_emit_value_changed();
|
|
}
|
|
}
|
|
|
|
void _m_mk_slider_pos_by_value()
|
|
{
|
|
const auto range = _m_range();
|
|
attr_.slider.pos = double(range) * attr_.vcur / attr_.vmax;
|
|
|
|
if (attr_.slider.vert)
|
|
attr_.slider.pos = range - attr_.slider.pos;
|
|
|
|
if(::nana::mouse_action::normal == slider_state_.mouse_state)
|
|
attr_.adorn_pos = attr_.slider.pos;
|
|
}
|
|
|
|
unsigned _m_value_by_pos(double pos) const
|
|
{
|
|
const auto range = _m_range();
|
|
|
|
if (0 == range)
|
|
return 0;
|
|
|
|
return static_cast<unsigned>((attr_.slider.vert ? range - pos : pos) * attr_.vmax / range);
|
|
}
|
|
|
|
void _m_draw_elements(graph_reference graph)
|
|
{
|
|
auto & scheme = other_.widget->scheme();
|
|
|
|
renderer_interface::data_bar bar;
|
|
|
|
bar.vert = attr_.slider.vert;
|
|
bar.border_weight = attr_.slider.border_weight;
|
|
bar.area = _m_bar_area();
|
|
|
|
if (bar.area.empty())
|
|
return;
|
|
|
|
proto_.renderer->bar(other_.wd, graph, bar, scheme);
|
|
|
|
//adorn
|
|
renderer_interface::data_adorn adorn;
|
|
adorn.vert = bar.vert;
|
|
if (adorn.vert)
|
|
{
|
|
adorn.bound.x = static_cast<int>(attr_.adorn_pos + attr_.slider.border_weight + bar.area.y);
|
|
adorn.bound.y = static_cast<int>(graph.height()) - static_cast<int>(attr_.slider.border_weight + bar.area.y);
|
|
}
|
|
else
|
|
{
|
|
adorn.bound.x = bar.area.x + attr_.slider.border_weight;
|
|
adorn.bound.y = adorn.bound.x + static_cast<int>(attr_.adorn_pos);
|
|
}
|
|
|
|
adorn.vcur_scale = static_cast<unsigned>(attr_.slider.pos);
|
|
adorn.block = (bar.vert ? bar.area.width : bar.area.height) - attr_.slider.border_weight * 2;
|
|
adorn.fixedpos = static_cast<int>((bar.vert ? bar.area.x : bar.area.y) + attr_.slider.border_weight);
|
|
|
|
proto_.renderer->adorn(other_.wd, graph, adorn, scheme);
|
|
|
|
//Draw slider
|
|
proto_.renderer->slider(other_.wd, graph, slider_state_.mouse_state, attr_.slider, scheme);
|
|
|
|
//adorn textbox
|
|
if (proto_.vernier && attr_.is_draw_adorn)
|
|
{
|
|
renderer_interface::data_vernier vern;
|
|
vern.vert = attr_.slider.vert;
|
|
vern.knob_weight = attr_.slider.weight;
|
|
|
|
auto vadorn = _m_value_by_pos(attr_.adorn_pos);
|
|
proto_.vernier(attr_.vmax, vadorn).swap(vern.text);
|
|
if(vern.text.size())
|
|
{
|
|
vern.position = adorn.bound.x;
|
|
if (!adorn.vert)
|
|
vern.position += static_cast<int>(attr_.adorn_pos);
|
|
|
|
vern.end_position = adorn.bound.y;
|
|
proto_.renderer->vernier(other_.wd, graph, vern, scheme);
|
|
}
|
|
}
|
|
}
|
|
private:
|
|
attrib_rep attr_;
|
|
|
|
struct other_tag
|
|
{
|
|
window wd;
|
|
nana::slider * widget;
|
|
}other_;
|
|
|
|
struct prototype_tag
|
|
{
|
|
pat::cloneable<slider::renderer_interface> renderer;
|
|
std::function<std::string(unsigned maximum, unsigned vernier_value)> vernier;
|
|
}proto_;
|
|
|
|
struct slider_state_tag
|
|
{
|
|
int snap_pos;
|
|
::nana::point refpos; //a point for slider when the mouse was clicking on slider.
|
|
::nana::mouse_action mouse_state{ ::nana::mouse_action::normal };
|
|
}slider_state_;
|
|
};
|
|
|
|
//class trigger
|
|
trigger::trigger()
|
|
: model_ptr_(new model)
|
|
{}
|
|
|
|
trigger::~trigger()
|
|
{
|
|
delete model_ptr_;
|
|
}
|
|
|
|
auto trigger::get_model() const -> model*
|
|
{
|
|
return model_ptr_;
|
|
}
|
|
|
|
void trigger::attached(widget_reference widget, graph_reference graph)
|
|
{
|
|
model_ptr_->attached(static_cast< ::nana::slider&>(widget), graph);
|
|
}
|
|
|
|
void trigger::refresh(graph_reference graph)
|
|
{
|
|
model_ptr_->draw(graph);
|
|
}
|
|
|
|
void trigger::mouse_down(graph_reference graph, const arg_mouse& arg)
|
|
{
|
|
using parts = model::parts;
|
|
auto what = model_ptr_->seek_where(arg.pos);
|
|
if(parts::bar == what || parts::slider == what)
|
|
{
|
|
bool updated = model_ptr_->set_slider_pos(arg.pos);
|
|
model_ptr_->set_slider_refpos(arg.pos);
|
|
if (updated)
|
|
{
|
|
model_ptr_->draw(graph);
|
|
API::dev::lazy_refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
void trigger::mouse_up(graph_reference graph, const arg_mouse&)
|
|
{
|
|
if (model_ptr_->release_slider())
|
|
{
|
|
model_ptr_->draw(graph);
|
|
API::dev::lazy_refresh();
|
|
}
|
|
}
|
|
|
|
void trigger::mouse_move(graph_reference graph, const arg_mouse& arg)
|
|
{
|
|
bool updated = false;
|
|
if (model_ptr_->if_trace_slider())
|
|
{
|
|
updated = model_ptr_->move_slider(arg.pos);
|
|
updated |= model_ptr_->set_slider_pos(arg.pos);
|
|
}
|
|
else
|
|
{
|
|
if (model::parts::none != model_ptr_->seek_where(arg.pos))
|
|
updated = model_ptr_->move_adorn(arg.pos);
|
|
else
|
|
updated = model_ptr_->reset_adorn();
|
|
}
|
|
|
|
if (updated)
|
|
{
|
|
model_ptr_->draw(graph);
|
|
API::dev::lazy_refresh();
|
|
}
|
|
}
|
|
|
|
void trigger::mouse_leave(graph_reference graph, const arg_mouse&)
|
|
{
|
|
if (model_ptr_->reset_adorn())
|
|
{
|
|
model_ptr_->draw(graph);
|
|
API::dev::lazy_refresh();
|
|
}
|
|
}
|
|
|
|
void trigger::resized(graph_reference graph, const arg_resized&)
|
|
{
|
|
model_ptr_->resize();
|
|
model_ptr_->draw(graph);
|
|
API::dev::lazy_refresh();
|
|
}
|
|
//end class trigger
|
|
}//end namespace slider
|
|
}//end namespace drawerbase
|
|
|
|
//class slider
|
|
slider::slider(){}
|
|
|
|
slider::slider(window wd, bool visible)
|
|
{
|
|
create(wd, rectangle(), visible);
|
|
}
|
|
|
|
slider::slider(window wd, const rectangle& r, bool visible)
|
|
{
|
|
create(wd, r, visible);
|
|
}
|
|
|
|
void slider::seek(seekdir sd)
|
|
{
|
|
get_drawer_trigger().get_model()->seek_direction(sd);
|
|
}
|
|
|
|
void slider::vertical(bool v)
|
|
{
|
|
if(get_drawer_trigger().get_model()->vertical(v))
|
|
API::refresh_window(this->handle());
|
|
}
|
|
|
|
bool slider::vertical() const
|
|
{
|
|
return get_drawer_trigger().get_model()->attribute().slider.vert;
|
|
}
|
|
|
|
void slider::maximum(unsigned m)
|
|
{
|
|
get_drawer_trigger().get_model()->maximum(m);
|
|
}
|
|
|
|
unsigned slider::maximum() const
|
|
{
|
|
if (empty())
|
|
return 0;
|
|
|
|
return get_drawer_trigger().get_model()->attribute().vmax;
|
|
}
|
|
|
|
void slider::value(unsigned v)
|
|
{
|
|
if(handle())
|
|
{
|
|
if(get_drawer_trigger().get_model()->vcur(v))
|
|
API::refresh_window(handle());
|
|
}
|
|
}
|
|
|
|
unsigned slider::value() const
|
|
{
|
|
if (empty())
|
|
return 0;
|
|
|
|
return static_cast<unsigned>(get_drawer_trigger().get_model()->attribute().vcur);
|
|
}
|
|
|
|
unsigned slider::move_step(bool forward)
|
|
{
|
|
if (empty())
|
|
return 0;
|
|
|
|
return this->get_drawer_trigger().get_model()->move_step(forward);
|
|
}
|
|
|
|
unsigned slider::adorn() const
|
|
{
|
|
if(empty())
|
|
return 0;
|
|
|
|
return get_drawer_trigger().get_model()->adorn();
|
|
}
|
|
|
|
const pat::cloneable<slider::renderer_interface>& slider::renderer()
|
|
{
|
|
return get_drawer_trigger().get_model()->renderer();
|
|
}
|
|
|
|
void slider::renderer(const pat::cloneable<slider::renderer_interface>& rd)
|
|
{
|
|
get_drawer_trigger().get_model()->renderer() = rd;
|
|
}
|
|
|
|
void slider::vernier(std::function<std::string(unsigned maximum, unsigned cursor_value)> vernier_string)
|
|
{
|
|
get_drawer_trigger().get_model()->vernier(vernier_string);
|
|
}
|
|
|
|
void slider::transparent(bool enabled)
|
|
{
|
|
if(enabled)
|
|
API::effects_bground(*this, effects::bground_transparent(0), 0.0);
|
|
else
|
|
API::effects_bground_remove(*this);
|
|
}
|
|
|
|
bool slider::transparent() const
|
|
{
|
|
return API::is_transparent_background(*this);
|
|
}
|
|
//end class slider
|
|
}//end namespace nana
|