improve picture widget stretchable mode

This commit is contained in:
Jinhao 2015-02-23 18:05:18 +08:00
parent d7a0d6f7d3
commit 022f7168c0
3 changed files with 170 additions and 17 deletions

View File

@ -17,6 +17,8 @@
namespace nana namespace nana
{ {
class picture;
namespace drawerbase namespace drawerbase
{ {
namespace picture namespace picture
@ -25,6 +27,7 @@ namespace nana
class drawer : public drawer_trigger class drawer : public drawer_trigger
{ {
friend class ::nana::picture;
public: public:
drawer(); drawer();
~drawer(); ~drawer();
@ -32,7 +35,7 @@ namespace nana
private: private:
void refresh(graph_reference) override; void refresh(graph_reference) override;
void _m_draw_background(); void _m_draw_background();
public: private:
implement * const impl_; implement * const impl_;
}; };
}//end namespace picture }//end namespace picture
@ -47,12 +50,19 @@ namespace nana
picture(window, bool visible); picture(window, bool visible);
picture(window, const rectangle& ={}, bool visible = true); picture(window, const rectangle& ={}, bool visible = true);
void load(nana::paint::image); void load(::nana::paint::image, const rectangle& valid_area = {});
/// Sets the align of image.
void align(align, align_v);
/// Enables the image to be stretched to the widget size.
void stretchable(unsigned left, unsigned top, unsigned right, unsigned bottom); void stretchable(unsigned left, unsigned top, unsigned right, unsigned bottom);
/// Enables/disable the image to be stretched without changing aspect ratio.
void stretchable(bool);
/// Fills a gradual-change color in background. If One of colors is invisible or clr_from is equal to clr_to, it draws background in bgcolor. /// Fills a gradual-change color in background. If One of colors is invisible or clr_from is equal to clr_to, it draws background in bgcolor.
void set_gradual_background(const ::nana::color& clr_from, const ::nana::color& clr_to, bool horizontal); void set_gradual_background(const color& clr_from, const color& clr_to, bool horizontal);
void transparent(bool); void transparent(bool);
bool transparent() const; bool transparent() const;
}; };

View File

@ -246,6 +246,19 @@ namespace nana
result_s = ref_s; result_s = ref_s;
} }
size fit_zoom(const size& input_s, size ref_s)
{
double rate_input = double(input_s.width) / double(input_s.height);
double rate_ref = double(ref_s.width) / double(ref_s.height);
if (rate_input < rate_ref)
ref_s.width = static_cast<unsigned>(ref_s.height * rate_input);
else if (rate_input > rate_ref)
ref_s.height = static_cast<unsigned>(ref_s.width / rate_input);
return ref_s;
}
void zoom(const rectangle& ref, const rectangle& scaled, const rectangle& ref_dst, rectangle& r) void zoom(const rectangle& ref, const rectangle& scaled, const rectangle& ref_dst, rectangle& r)
{ {
double rate_x = (scaled.x - ref.x) / double(ref.width); double rate_x = (scaled.x - ref.x) / double(ref.width);

View File

@ -38,7 +38,11 @@ namespace nana
struct back_image_tag struct back_image_tag
{ {
paint::image image; paint::image image;
std::unique_ptr<element::bground> bground; rectangle valid_area;
::nana::align align_horz{ ::nana::align::left };
::nana::align_v align_vert{ ::nana::align_v::top };
std::unique_ptr<element::bground> bground; //If it is not a null ptr, the widget is stretchable mode
bool stretchable{ false }; //If it is true, the widget is stretchable mode without changing aspect ratio.
}backimg; }backimg;
}; };
@ -63,13 +67,92 @@ namespace nana
if (!graph.changed()) if (!graph.changed())
return; return;
if (!impl_->backimg.bground) auto graphsize = graph.size();
auto & backimg = impl_->backimg;
if (!backimg.bground)
{ {
_m_draw_background(); auto valid_area = backimg.valid_area;
impl_->backimg.image.paste(graph, 0, 0); if (valid_area.empty())
valid_area = backimg.image.size();
if (backimg.stretchable)
{
auto fit_size = fit_zoom({ valid_area.width, valid_area.height }, graphsize);
//::nana::point pos{ int(graphsize.width - fit_size.width), int(graphsize.height - fit_size.height) };
::nana::point pos;
if (fit_size.width != graphsize.width)
{
switch (backimg.align_horz)
{
case ::nana::align::left: break;
case ::nana::align::center:
pos.x = (int(graphsize.width) - int(fit_size.width)) / 2;
break;
case ::nana::align::right:
pos.x = int(graphsize.width) - int(fit_size.width);
break;
}
}
else if (fit_size.height != graphsize.height)
{
switch (backimg.align_vert)
{
case ::nana::align_v::top: break;
case ::nana::align_v::center:
pos.y = (int(graphsize.height) - int(fit_size.height)) / 2;
break;
case ::nana::align_v::bottom:
pos.y = int(graphsize.height) - int(fit_size.height);
break;
}
}
if (fit_size.width < graphsize.width || fit_size.height < graphsize.height)
_m_draw_background();
backimg.image.stretch(valid_area, graph, { pos, fit_size });
}
else
{
//The point in which position the image to be drawn.
::nana::point pos;
switch (backimg.align_horz)
{
case ::nana::align::left: break;
case ::nana::align::center:
pos.x = (int(graphsize.width) - int(valid_area.width)) / 2;
break;
case ::nana::align::right:
pos.x = int(graphsize.width) - int(valid_area.width);
break;
}
switch (backimg.align_vert)
{
case ::nana::align_v::top: break;
case ::nana::align_v::center:
pos.y = (int(graphsize.height) - int(valid_area.height)) / 2;
break;
case ::nana::align_v::bottom:
pos.y = int(graphsize.height) - int(valid_area.height);
break;
}
if (valid_area.width < graphsize.width || valid_area.height < graphsize.height)
_m_draw_background();
backimg.image.paste(valid_area, graph, pos);
}
} }
else else
impl_->backimg.bground->draw(graph, {}, {}, graph.size(), element_state::normal); {
color invalid_clr_for_call;
backimg.bground->draw(graph, invalid_clr_for_call, invalid_clr_for_call, graphsize, element_state::normal);
}
graph.setsta(); graph.setsta();
} }
@ -105,16 +188,40 @@ namespace nana
create(wd, r, visible); create(wd, r, visible);
} }
void picture::load(nana::paint::image img) void picture::load(::nana::paint::image img, const ::nana::rectangle& valid_area)
{ {
internal_scope_guard lock;
auto& backimg = get_drawer_trigger().impl_->backimg; auto& backimg = get_drawer_trigger().impl_->backimg;
backimg.image = std::move(img); backimg.image = std::move(img);
backimg.valid_area = valid_area;
if (backimg.bground) if (backimg.bground)
backimg.bground->image(backimg.image, true, {}); backimg.bground->image(backimg.image, true, valid_area);
get_drawer_trigger().impl_->graph_ptr->set_changed(); if (handle())
API::refresh_window(*this); {
get_drawer_trigger().impl_->graph_ptr->set_changed();
API::refresh_window(*this);
}
}
void picture::align(::nana::align horz, align_v vert)
{
internal_scope_guard lock;
auto& backimg = get_drawer_trigger().impl_->backimg;
if (backimg.align_horz == horz && backimg.align_vert == vert)
return;
backimg.align_horz = horz;
backimg.align_vert = vert;
if (handle())
{
get_drawer_trigger().impl_->graph_ptr->set_changed();
API::refresh_window(*this);
}
} }
void picture::stretchable(unsigned left, unsigned top, unsigned right, unsigned bottom) void picture::stretchable(unsigned left, unsigned top, unsigned right, unsigned bottom)
@ -122,17 +229,37 @@ namespace nana
if (!handle()) if (!handle())
return; return;
internal_scope_guard lock;
auto & backimg = get_drawer_trigger().impl_->backimg; auto & backimg = get_drawer_trigger().impl_->backimg;
if (!backimg.bground) if (!backimg.bground)
{ {
backimg.bground.reset(new element::bground); backimg.bground.reset(new element::bground);
backimg.bground->states({ element_state::normal }); backimg.bground->states({ element_state::normal });
backimg.bground->image(backimg.image, true, {}); backimg.bground->image(backimg.image, true, backimg.valid_area);
} }
backimg.bground->stretch_parts(left, top, right, bottom); backimg.bground->stretch_parts(left, top, right, bottom);
get_drawer_trigger().impl_->graph_ptr->set_changed(); backimg.stretchable = false;
API::refresh_window(*this); if (handle())
{
get_drawer_trigger().impl_->graph_ptr->set_changed();
API::refresh_window(*this);
}
}
void picture::stretchable(bool enables)
{
internal_scope_guard lock;
auto & backimg = get_drawer_trigger().impl_->backimg;
backimg.bground.reset();
backimg.stretchable = enables;
if (handle())
{
get_drawer_trigger().impl_->graph_ptr->set_changed();
API::refresh_window(*this);
}
} }
void picture::set_gradual_background(const ::nana::color& from, const ::nana::color& to, bool horizontal) void picture::set_gradual_background(const ::nana::color& from, const ::nana::color& to, bool horizontal)
@ -141,8 +268,11 @@ namespace nana
bground.gradual_from = from; bground.gradual_from = from;
bground.gradual_to = to; bground.gradual_to = to;
bground.horizontal = horizontal; bground.horizontal = horizontal;
get_drawer_trigger().impl_->graph_ptr->set_changed(); if (handle())
API::refresh_window(*this); {
get_drawer_trigger().impl_->graph_ptr->set_changed();
API::refresh_window(*this);
}
} }
void picture::transparent(bool enabled) void picture::transparent(bool enabled)