diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp index c1a0ca9e..d8253b85 100644 --- a/include/nana/basic_types.hpp +++ b/include/nana/basic_types.hpp @@ -464,6 +464,16 @@ namespace nana { top, center, bottom }; + + ///The definition of the four corners of the world + enum class direction + { + north, + south, + east, + west, + southeast + }; }//end namespace nana #endif diff --git a/include/nana/gui/element.hpp b/include/nana/gui/element.hpp index e5da56a1..b0cdc9e1 100644 --- a/include/nana/gui/element.hpp +++ b/include/nana/gui/element.hpp @@ -61,6 +61,14 @@ namespace nana virtual bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state, unsigned weight) = 0; }; + class arrow_interface + { + public: + using graph_reference = paint::graphics&; + virtual ~arrow_interface() = default; + virtual bool draw(graph_reference, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle&, element_state, direction) = 0; + }; + class provider { public: @@ -95,6 +103,9 @@ namespace nana void add_border(const std::string&, const pat::cloneable>&); border_interface* const * keeper_border(const std::string&); + + void add_arrow(const std::string&, const pat::cloneable>&); + arrow_interface* const * keeper_arrow(const std::string&); }; class crook; @@ -106,13 +117,20 @@ namespace nana } class border; - template void add_border(const std::string& name) { using factory_t = provider::factory; provider().add_border(name, pat::cloneable(factory_t())); } + + class arrow; + template + void add_arrow(const std::string& name) + { + using factory_t = provider::factory; + provider().add_arrow(name, pat::cloneable(factory_t())); + } }//end namespace element template class facade; @@ -125,8 +143,7 @@ namespace nana using graph_reference = ::nana::paint::graphics &; using state = element::crook_interface::state; - facade(); - facade(const char* name); + facade(const char* name = nullptr); facade & reverse(); facade & check(state); @@ -150,8 +167,7 @@ namespace nana { using graph_reference = ::nana::paint::graphics &; public: - facade(); - facade(const char* name); + facade(const char* name = nullptr); void switch_to(const char*); public: @@ -161,6 +177,30 @@ namespace nana element::border_interface* const * keeper_; };//end class facade + template<> + class facade + : public element::element_interface + { + using graph_reference = ::nana::paint::graphics &; + public: + enum class style + { + solid + }; + + facade(const char* name = nullptr); + + void switch_to(const char*); + void direction(::nana::direction); + public: + //Implement element_interface + bool draw(graph_reference, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle&, element_state) override; + private: + element::arrow_interface* const * keeper_; + ::nana::direction dir_{::nana::direction::north}; + };//end class facade + + namespace element { void set_bground(const char* name, const pat::cloneable&); diff --git a/source/gui/element.cpp b/source/gui/element.cpp index 693c279c..a44c95af 100644 --- a/source/gui/element.cpp +++ b/source/gui/element.cpp @@ -268,6 +268,215 @@ namespace nana return true; } }; + + class arrow_solid_triangle + : public arrow_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, direction dir) override + { + ::nana::point pos{ r.x + 3, r.y + 3 }; + switch (dir) + { + case ::nana::direction::east: + pos.x += 3; + pos.y += 1; + for (int i = 0; i < 5; ++i) + graph.line(point{ pos.x + i, pos.y + i }, point{ pos.x + i, pos.y + 8 - i }); + break; + case ::nana::direction::south: + pos.y += 3; + for (int i = 0; i < 5; ++i) + graph.line(point{ pos.x + i, pos.y + i }, point{ pos.x + 8 - i, pos.y + i }); + break; + case ::nana::direction::west: + pos.x += 5; + pos.y += 1; + for (int i = 0; i < 5; ++i) + graph.line(point{ pos.x - i, pos.y + i }, point{ pos.x - i, pos.y + 8 - i }); + break; + case ::nana::direction::north: + pos.y += 7; + for (int i = 0; i < 5; ++i) + graph.line(point{ pos.x + i, pos.y - i }, point{ pos.x + 8 - i, pos.y - i }); + break; + case direction::southeast: + pos.x += 2; + pos.y += 7; + for (int i = 0; i < 6; ++i) + graph.line(point{ pos.x + i, pos.y - i }, point{ pos.x + 5, pos.y - i }); + break; + } + return true; + } + };//end class arrow_solid_triangle + + class arrow_hollow_triangle + : public arrow_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, ::nana::direction dir) override + { + int x = r.x + 3; + int y = r.x + 3; + switch (dir) + { + case ::nana::direction::east: + x += 3; + graph.line(point{ x, y + 1 }, point{ x, y + 9 }); + graph.line(point{ x + 1, y + 2 }, point{ x + 4, y + 5 }); + graph.line(point{ x + 3, y + 6 }, point{ x + 1, y + 8 }); + break; + case direction::southeast: + x += 7; + y += 6; + graph.line(point{ x - 5 , y + 1 }, point{ x, y + 1 }); + graph.line(point{ x, y - 4 }, point{ x, y }); + graph.line(point{ x - 4, y }, point{ x - 1, y - 3 }); + break; + case direction::south: + y += 3; + graph.line(point{ x, y }, point{ x + 8, y }); + graph.line(point{ x + 1, y + 1 }, point{ x + 4, y + 4 }); + graph.line(point{ x + 7, y + 1 }, point{ x + 5, y + 3 }); + break; + case direction::west: + x += 5; + y += 1; + graph.line(point{ x, y }, point{ x, y + 8 }); + graph.line(point{ x - 4, y + 4 }, point{ x - 1, y + 1 }); + graph.line(point{ x - 3, y + 5 }, point{ x - 1, y + 7 }); + break; + case direction::north: + y += 7; + graph.line(point{ x, y }, point{ x + 8, y }); + graph.line(point{ x + 1, y - 1 }, point{ x + 4, y - 4 }); + graph.line(point{ x + 5, y - 3 }, point{ x + 7, y - 1 }); + break; + } + return true; + } + };//end class arrow_hollow_triangle + + class arrowhead + : public arrow_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, ::nana::direction dir) override + { + int x = r.x; + int y = r.y + 5; + switch (dir) + { + case direction::north: + { + x += 3; + int pixels = 1; + for (int l = 0; l < 4; ++l) + { + for (int i = 0; i < pixels; ++i) + { + if (l == 3 && i == 3) + continue; + graph.set_pixel(x + i, y); + } + + x--; + y++; + pixels += 2; + } + + graph.set_pixel(x + 1, y); + graph.set_pixel(x + 2, y); + graph.set_pixel(x + 6, y); + graph.set_pixel(x + 7, y); + } + break; + case direction::south: + { + graph.set_pixel(x, y); + graph.set_pixel(x + 1, y); + graph.set_pixel(x + 5, y); + graph.set_pixel(x + 6, y); + + ++y; + int pixels = 7; + for (int l = 0; l < 4; ++l) + { + for (int i = 0; i < pixels; ++i) + { + if (l != 0 || i != 3) + graph.set_pixel(x + i, y); + } + + x++; + y++; + pixels -= 2; + } + } + break; + } + return true; + } + };//end class arrowhead + + class arrow_double + : public arrow_interface + { + bool draw(graph_reference graph, const ::nana::color& bgcolor, const ::nana::color& fgcolor, const ::nana::rectangle& r, element_state estate, ::nana::direction dir) override + { + int x = r.x; + int y = r.y; + switch (dir) + { + case direction::east: + _m_line(graph, x + 4, y + 6, true); + _m_line(graph, x + 5, y + 7, true); + _m_line(graph, x + 6, y + 8, true); + _m_line(graph, x + 5, y + 9, true); + _m_line(graph, x + 4, y + 10, true); + break; + case direction::west: + _m_line(graph, x + 5, y + 6, true); + _m_line(graph, x + 4, y + 7, true); + _m_line(graph, x + 3, y + 8, true); + _m_line(graph, x + 4, y + 9, true); + _m_line(graph, x + 5, y + 10, true); + break; + case direction::south: + _m_line(graph, x + 5, y + 4, false); + _m_line(graph, x + 6, y + 5, false); + _m_line(graph, x + 7, y + 6, false); + _m_line(graph, x + 8, y + 5, false); + _m_line(graph, x + 9, y + 4, false); + break; + case direction::north: + _m_line(graph, x + 5, y + 6, false); + _m_line(graph, x + 6, y + 5, false); + _m_line(graph, x + 7, y + 4, false); + _m_line(graph, x + 8, y + 5, false); + _m_line(graph, x + 9, y + 6, false); + break; + default: + break; + } + return true; + } + + static void _m_line(nana::paint::graphics & graph, int x, int y, bool horizontal) + { + graph.set_pixel(x, y); + if (horizontal) + { + graph.set_pixel(x + 1, y); + graph.set_pixel(x + 4, y); + graph.set_pixel(x + 5, y); + } + else + { + graph.set_pixel(x, y + 1); + graph.set_pixel(x, y + 4); + graph.set_pixel(x, y + 5); + } + } + }; }//end namespace element template @@ -348,6 +557,11 @@ namespace nana element::add_crook("menu_crook"); element::add_border(""); + + element::add_arrow(""); + element::add_arrow("double"); + element::add_arrow("solid_triangle"); + element::add_arrow("hollow_triangle"); } return obj; } @@ -371,6 +585,16 @@ namespace nana { return _m_get(name, border_).keeper(); } + + void arrow(const std::string& name, const pat::cloneable>& factory) + { + _m_add((name.empty() ? "arrowhead" : name), arrow_, factory); + } + + element::arrow_interface * const * arrow(const std::string& name) const + { + return _m_get((name.empty() ? "arrowhead" : name), arrow_).keeper(); + } private: using lock_guard = std::lock_guard; @@ -405,6 +629,7 @@ namespace nana mutable std::recursive_mutex mutex_; item crook_; item border_; + item arrow_; }; namespace element @@ -429,17 +654,20 @@ namespace nana { return element_manager::instance().border(name); } + + void provider::add_arrow(const std::string& name, const pat::cloneable>& factory) + { + element_manager::instance().arrow(name, factory); + } + + arrow_interface* const * provider::keeper_arrow(const std::string& name) + { + return element_manager::instance().arrow(name); + } }//end namespace element //facades //template<> class facade - facade::facade() - : keeper_(element::provider().keeper_crook("")) - { - data_.check_state = state::unchecked; - data_.radio = false; - } - facade::facade(const char* name) : keeper_(element::provider().keeper_crook(name ? name : "")) { @@ -487,10 +715,6 @@ namespace nana //end class facade //class facade - facade::facade() - : facade(nullptr) - {} - facade::facade(const char* name) : keeper_(element::provider().keeper_border(name ? name : "")) {} @@ -506,6 +730,30 @@ namespace nana } //end class facade + //class facade + facade::facade(const char* name) + : keeper_(element::provider().keeper_arrow(name ? name : "")) + { + } + + void facade::switch_to(const char* name) + { + keeper_ = element::provider().keeper_arrow(name ? name : ""); + } + + void facade::direction(::nana::direction dir) + { + dir_ = dir; + } + + //Implement element_interface + bool facade::draw(graph_reference graph, const nana::color& bgcolor, const nana::color& fgcolor, const nana::rectangle& r, element_state estate) + { + graph.set_color(fgcolor); + return (*keeper_)->draw(graph, bgcolor, fgcolor, r, estate, dir_); + } + //end class facade + namespace element { void set_bground(const char* name, const pat::cloneable& obj)