From 1781e77e3922e415b9db2ed7f04b91c36bac79e7 Mon Sep 17 00:00:00 2001 From: 5cript Date: Fri, 26 Jan 2018 02:36:10 +0100 Subject: [PATCH 1/3] Added convenient proxy, that allows the user to disable items directly after creation. --- include/nana/gui/widgets/toolbar.hpp | 224 +++--- source/gui/widgets/toolbar.cpp | 998 ++++++++++++++------------- 2 files changed, 618 insertions(+), 604 deletions(-) diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index d92c7f8a..1feb84a9 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -1,108 +1,116 @@ -/** - * A Toolbar Implementation - * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - * @file: nana/gui/widgets/toolbar.hpp - */ - -#ifndef NANA_GUI_WIDGET_TOOLBAR_HPP -#define NANA_GUI_WIDGET_TOOLBAR_HPP -#include - -#include "widget.hpp" - -namespace nana -{ - class toolbar; - - struct arg_toolbar - : public event_arg - { - toolbar& widget; - std::size_t button; - - arg_toolbar(toolbar&, std::size_t); - }; - - namespace drawerbase - { - namespace toolbar - { - struct toolbar_events - : public general_events - { - basic_event selected; ///< A mouse click on a control button. - basic_event enter; ///< The mouse enters a control button. - basic_event leave; ///< The mouse leaves a control button. - }; - - struct item_type; - class item_container; - - class drawer - : public drawer_trigger - { - struct drawer_impl_type; - - public: - using size_type = std::size_t; - - drawer(); - ~drawer(); - - item_container& items() const; - void scale(unsigned); - private: - void refresh(graph_reference) override; - void attached(widget_reference, graph_reference) override; - void detached() override; - void mouse_move(graph_reference, const arg_mouse&) override; - void mouse_leave(graph_reference, const arg_mouse&) override; - void mouse_down(graph_reference, const arg_mouse&) override; - void mouse_up(graph_reference, const arg_mouse&) override; - private: - size_type _m_which(point, bool want_if_disabled) const; - void _m_calc_pixels(item_type*, bool force); - private: - ::nana::toolbar* widget_; - drawer_impl_type* impl_; - }; - - }//end namespace toolbar - }//end namespace drawerbase - - /// Control bar that contains buttons for controlling - class toolbar - : public widget_object - { - public: - using size_type = std::size_t; ///< A type to count the number of elements. - - toolbar() = default; - toolbar(window, bool visible, bool detached=false); - toolbar(window, const rectangle& = rectangle(), bool visible = true, bool detached = false); - - void separate(); ///< Adds a separator. - void append(const ::std::string& text, const nana::paint::image& img); ///< Adds a control button. - void append(const ::std::string& text); ///< Adds a control button. - bool enable(size_type index) const; - void enable(size_type index, bool enable_state); - void scale(unsigned s); ///< Sets the scale of control button. - - /// Enable to place buttons at right part. After calling it, every new button is right aligned. - void go_right(); - - bool detached() { return detached_; }; - - private: - bool detached_; - }; -}//end namespace nana -#include - -#endif +/** + * A Toolbar Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/toolbar.hpp + */ + +#ifndef NANA_GUI_WIDGET_TOOLBAR_HPP +#define NANA_GUI_WIDGET_TOOLBAR_HPP +#include + +#include "widget.hpp" + +namespace nana +{ + class toolbar; + + struct arg_toolbar + : public event_arg + { + toolbar& widget; + std::size_t button; + + arg_toolbar(toolbar&, std::size_t); + }; + + namespace drawerbase + { + namespace toolbar + { + struct item_proxy + { + nana::toolbar& widget; + std::size_t button; + + void enable(bool enable_state) const; + }; + + struct toolbar_events + : public general_events + { + basic_event selected; ///< A mouse click on a control button. + basic_event enter; ///< The mouse enters a control button. + basic_event leave; ///< The mouse leaves a control button. + }; + + struct item_type; + class item_container; + + class drawer + : public drawer_trigger + { + struct drawer_impl_type; + + public: + using size_type = std::size_t; + + drawer(); + ~drawer(); + + item_container& items() const; + void scale(unsigned); + private: + void refresh(graph_reference) override; + void attached(widget_reference, graph_reference) override; + void detached() override; + void mouse_move(graph_reference, const arg_mouse&) override; + void mouse_leave(graph_reference, const arg_mouse&) override; + void mouse_down(graph_reference, const arg_mouse&) override; + void mouse_up(graph_reference, const arg_mouse&) override; + private: + size_type _m_which(point, bool want_if_disabled) const; + void _m_calc_pixels(item_type*, bool force); + private: + ::nana::toolbar* widget_; + drawer_impl_type* impl_; + }; + + }//end namespace toolbar + }//end namespace drawerbase + + /// Control bar that contains buttons for controlling + class toolbar + : public widget_object + { + public: + using size_type = std::size_t; ///< A type to count the number of elements. + + toolbar() = default; + toolbar(window, bool visible, bool detached=false); + toolbar(window, const rectangle& = rectangle(), bool visible = true, bool detached = false); + + void separate(); ///< Adds a separator. + drawerbase::toolbar::item_proxy append(const ::std::string& text, const nana::paint::image& img); ///< Adds a control button. + drawerbase::toolbar::item_proxy append(const ::std::string& text); ///< Adds a control button. + bool enable(size_type index) const; + void enable(size_type index, bool enable_state); + void scale(unsigned s); ///< Sets the scale of control button. + + /// Enable to place buttons at right part. After calling it, every new button is right aligned. + void go_right(); + + bool detached() { return detached_; }; + + private: + bool detached_; + }; +}//end namespace nana +#include + +#endif diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index 953e4796..0ed983ca 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -1,496 +1,502 @@ -/* - * A Toolbar Implementation - * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - * @file: nana/gui/widgets/toolbar.cpp - * @contributors: - * kmribti(pr#105) - */ - -#include -#include - -#include - -namespace nana -{ - arg_toolbar::arg_toolbar(toolbar& tbar, std::size_t btn) - : widget(tbar), button{btn} - {} - - namespace drawerbase - { - namespace toolbar - { - struct item_type - { - enum kind{ button, container}; - - typedef std::size_t size_type; - - std::string text; - nana::paint::image image; - unsigned pixels{0}; - unsigned position{ 0 }; // last item position. - nana::size textsize; - bool enable{true}; - - kind type; - - item_type(const std::string& text, const nana::paint::image& img, kind type) - :text(text), image(img), type(type) - {} - }; - - - - class item_container - { - public: - using container_type = std::vector; - using size_type = container_type::size_type; - - ~item_container() - { - for(auto ptr : cont_) - delete ptr; - } - - void insert(size_type pos, std::string text, const nana::paint::image& img, item_type::kind type) - { - item_type* m = new item_type(std::move(text), img, type); - - if(pos < cont_.size()) - cont_.insert(cont_.begin() + pos, m); - else - cont_.push_back(m); - } - - void push_back(const std::string& text, const nana::paint::image& img) - { - insert(cont_.size(), text, img, item_type::kind::button); - } - - void push_back(const std::string& text) - { - insert(cont_.size(), text, nana::paint::image(), item_type::kind::button); - } - - //Contributed by kmribti(pr#105) - void go_right() noexcept - { - right_ = cont_.size(); - } - - //Contributed by kmribti(pr#105) - size_t right() const noexcept - { - return right_; - } - - void insert(size_type pos) - { - if(pos < cont_.size()) - cont_.insert(cont_.begin() + pos, static_cast(nullptr)); //both works in C++0x and C++2003 - else - cont_.push_back(nullptr); - } - - void separate() - { - cont_.push_back(nullptr); - } - - size_type size() const noexcept - { - return cont_.size(); - } - - container_type& container() noexcept - { - return cont_; - } - - item_type * at(size_type pos) - { - return cont_.at(pos); - } - private: - container_type cont_; - size_t right_{ npos }; - }; - - class item_renderer - { - public: - enum class state_t{normal, highlighted, selected}; - const static unsigned extra_size = 6; - - item_renderer(nana::paint::graphics& graph, bool textout, unsigned scale, const ::nana::color& bgcolor) - :graph(graph), textout(textout), scale(scale), bgcolor(bgcolor) - {} - - void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state) - { - //draw background - if (state != state_t::normal) - { - nana::rectangle background_r(x, y, width, height); - graph.rectangle(background_r, false, static_cast(0x3399FF)); - - if (state_t::highlighted == state || state_t::selected == state) - graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast(state_t::selected == state ? 0x99CCFF : 0xC0DDFC), true); - } - - if(!item.image.empty()) - { - auto imgsize = item.image.size(); - - if (imgsize.width > scale) imgsize.width = scale; - if (imgsize.height > scale) imgsize.height = scale; - - nana::point pos( - x + static_cast(scale + extra_size - imgsize.width) / 2, - y + static_cast(height - imgsize.height) / 2); - - item.image.paste(::nana::rectangle{ imgsize }, graph, pos); - if(item.enable == false) - { - nana::paint::graphics gh(imgsize); - gh.bitblt(::nana::rectangle{ imgsize }, graph, pos); - gh.rgb_to_wb(); - gh.paste(graph, pos.x, pos.y); - } - else if (state == state_t::normal) - { - graph.blend(nana::rectangle(pos, imgsize), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25); - } - - x += scale; - width -= scale; - } - - if(textout) - { - graph.string({ x + static_cast(width - item.textsize.width) / 2, y + static_cast(height - item.textsize.height) / 2 }, item.text); - } - } - - protected: - nana::paint::graphics& graph; - bool textout; - unsigned scale; - ::nana::color bgcolor; - }; - - struct drawer::drawer_impl_type - { - event_handle event_size{ nullptr }; - paint::graphics* graph_ptr{ nullptr }; - - unsigned scale{16}; - bool textout{false}; - size_type which{npos}; - item_renderer::state_t state{item_renderer::state_t::normal}; - - item_container items; - ::nana::tooltip tooltip; - }; - - //class drawer - drawer::drawer() - : impl_(new drawer_impl_type) - { - } - - drawer::~drawer() - { - delete impl_; - } - - item_container& drawer::items() const - { - return impl_->items; - } - - void drawer::scale(unsigned s) - { - impl_->scale = s; - - for(auto m : impl_->items.container()) - _m_calc_pixels(m, true); - } - - void drawer::refresh(graph_reference graph) - { - int x = 2, y = 2; - - auto bgcolor = API::bgcolor(widget_->handle()); - graph.palette(true, bgcolor); - graph.gradual_rectangle(rectangle{ graph.size() }, bgcolor.blend(colors::white, 0.1), bgcolor.blend(colors::black, 0.05), true); - - item_renderer ir(graph, impl_->textout, impl_->scale, bgcolor); - size_type index = 0; - - for (auto item : impl_->items.container()) - { - if (item) - { - _m_calc_pixels(item, false); - item->position = x; - ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal)); - x += item->pixels; - } - else - { - x += 2; - graph.line({ x, y + 2 }, { x, y + static_cast(impl_->scale + ir.extra_size) - 4 }, static_cast(0x808080)); - x += 4; - } - ++index; - - //Reset the x position of items which are right aligned - //Contributed by kmribti(pr#105) - if (index == impl_->items.right() && index < impl_->items.size()) - { - unsigned total_x = 0; - for (size_t i = index; i < impl_->items.size(); i++) { - if (impl_->items.at(i) == nullptr) { - total_x += 8; // we assume that separator has width = 8. - } - else { - _m_calc_pixels(impl_->items.at(i), false); - total_x += impl_->items.at(i)->pixels; - } - } - - x = graph.size().width - total_x - 4; - } - } - } - - void drawer::attached(widget_reference widget, graph_reference graph) - { - impl_->graph_ptr = &graph; - - widget_ = static_cast< ::nana::toolbar*>(&widget); - widget.caption("nana toolbar"); - - if (widget_->detached()) return; - - impl_->event_size = API::events(widget.parent()).resized.connect_unignorable([this](const arg_resized& arg) - { - auto wd = widget_->handle(); - API::window_size(wd, nana::size(arg.width, widget_->size().height)); - API::update_window(wd); - }); - } - - void drawer::detached() - { - API::umake_event(impl_->event_size); - impl_->event_size = nullptr; - impl_->graph_ptr = nullptr; - } - - void drawer::mouse_move(graph_reference graph, const arg_mouse& arg) - { - if (arg.left_button) - return; - - size_type which = _m_which(arg.pos, true); - if(impl_->which != which) - { - auto & container = impl_->items.container(); - if (impl_->which != npos && container.at(impl_->which)->enable) - { - ::nana::arg_toolbar arg{ *widget_, impl_->which }; - widget_->events().leave.emit(arg, widget_->handle()); - } - - impl_->which = which; - if (which == npos || container.at(which)->enable) - { - impl_->state = item_renderer::state_t::highlighted; - - refresh(graph); - API::dev::lazy_refresh(); - - if (impl_->state == item_renderer::state_t::highlighted) - { - ::nana::arg_toolbar arg{ *widget_, which }; - widget_->events().enter.emit(arg, widget_->handle()); - } - } - - if(which != npos) - impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(container.begin() + which))->text, 0); - else - impl_->tooltip.close(); - } - } - - void drawer::mouse_leave(graph_reference graph, const arg_mouse&) - { - if(impl_->which != npos) - { - size_type which = impl_->which; - - impl_->which = npos; - refresh(graph); - API::dev::lazy_refresh(); - - if (which != npos && impl_->items.at(which)->enable) - { - ::nana::arg_toolbar arg{ *widget_, which }; - widget_->events().leave.emit(arg, widget_->handle()); - } - } - impl_->tooltip.close(); - } - - void drawer::mouse_down(graph_reference graph, const arg_mouse&) - { - impl_->tooltip.close(); - if(impl_->which != npos && (impl_->items.at(impl_->which)->enable)) - { - impl_->state = item_renderer::state_t::selected; - refresh(graph); - API::dev::lazy_refresh(); - } - } - - void drawer::mouse_up(graph_reference graph, const arg_mouse& arg) - { - if(impl_->which != npos) - { - size_type which = _m_which(arg.pos, false); - if(impl_->which == which) - { - ::nana::arg_toolbar arg{ *widget_, which }; - widget_->events().selected.emit(arg, widget_->handle()); - - impl_->state = item_renderer::state_t::highlighted; - } - else - { - impl_->which = which; - impl_->state = (which == npos ? item_renderer::state_t::normal : item_renderer::state_t::highlighted); - } - - refresh(graph); - API::dev::lazy_refresh(); - } - } - - drawer::size_type drawer::_m_which(point pos, bool want_if_disabled) const - { - if (pos.x < 2 || pos.y < 2 || pos.y >= static_cast(impl_->scale + item_renderer::extra_size + 2)) return npos; - - pos.x -= 2; - - std::size_t index = 0; - for(auto m: impl_->items.container()) - { - unsigned x = static_cast(pos.x); - if (m && x >= m->position && x <= (m->position+m->pixels)) - return (((!m) || (!m->enable && !want_if_disabled)) ? npos : index); - - ++index; - } - return npos; - } - - void drawer::_m_calc_pixels(item_type* item, bool force) - { - if (item && (force || (0 == item->pixels))) - { - if (item->text.size()) - item->textsize = impl_->graph_ptr->text_extent_size(item->text); - - if (item->image.empty() == false) - item->pixels = impl_->scale + item_renderer::extra_size; - - if (item->textsize.width && impl_->textout) - item->pixels += item->textsize.width + 8; - } - } - //class drawer - }//end namespace toolbar - }//end namespace drawerbase - - //class toolbar - toolbar::toolbar(window wd, bool visible, bool detached) : - detached_(detached) - { - create(wd, rectangle(), visible); - } - - toolbar::toolbar(window wd, const rectangle& r, bool visible, bool detached) : - detached_(detached) - { - create(wd, r, visible); - } - - //Contributed by kmribti(pr#105) - void toolbar::go_right() - { - get_drawer_trigger().items().go_right(); - } - - void toolbar::separate() - { - get_drawer_trigger().items().separate(); - API::refresh_window(handle()); - } - - void toolbar::append(const std::string& text, const nana::paint::image& img) - { - get_drawer_trigger().items().push_back(text, img); - API::refresh_window(handle()); - } - - void toolbar::append(const std::string& text) - { - get_drawer_trigger().items().push_back(text, {}); - API::refresh_window(this->handle()); - } - - bool toolbar::enable(size_type pos) const - { - auto & items = get_drawer_trigger().items(); - - if (items.size() <= pos) - return false; - - auto m = items.at(pos); - return (m && m->enable); - } - - void toolbar::enable(size_type pos, bool eb) - { - auto & items = get_drawer_trigger().items(); - - if (items.size() > pos) - { - auto m = items.at(pos); - if (m && (m->enable != eb)) - { - m->enable = eb; - API::refresh_window(this->handle()); - } - } - } - - void toolbar::scale(unsigned s) - { - get_drawer_trigger().scale(s); - API::refresh_window(handle()); - } - //end class toolbar -}//end namespace nana +/* + * A Toolbar Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file: nana/gui/widgets/toolbar.cpp + * @contributors: + * kmribti(pr#105) + */ + +#include +#include + +#include + +namespace nana +{ + arg_toolbar::arg_toolbar(toolbar& tbar, std::size_t btn) + : widget(tbar), button{btn} + {} + + namespace drawerbase + { + namespace toolbar + { + struct item_type + { + enum kind{ button, container}; + + typedef std::size_t size_type; + + std::string text; + nana::paint::image image; + unsigned pixels{0}; + unsigned position{ 0 }; // last item position. + nana::size textsize; + bool enable{true}; + + kind type; + + item_type(const std::string& text, const nana::paint::image& img, kind type) + :text(text), image(img), type(type) + {} + }; + + class item_container + { + public: + using container_type = std::vector; + using size_type = container_type::size_type; + + ~item_container() + { + for(auto ptr : cont_) + delete ptr; + } + + void insert(size_type pos, std::string text, const nana::paint::image& img, item_type::kind type) + { + item_type* m = new item_type(std::move(text), img, type); + + if(pos < cont_.size()) + cont_.insert(cont_.begin() + pos, m); + else + cont_.push_back(m); + } + + void push_back(const std::string& text, const nana::paint::image& img) + { + insert(cont_.size(), text, img, item_type::kind::button); + } + + void push_back(const std::string& text) + { + insert(cont_.size(), text, nana::paint::image(), item_type::kind::button); + } + + //Contributed by kmribti(pr#105) + void go_right() noexcept + { + right_ = cont_.size(); + } + + //Contributed by kmribti(pr#105) + size_t right() const noexcept + { + return right_; + } + + void insert(size_type pos) + { + if(pos < cont_.size()) + cont_.insert(cont_.begin() + pos, static_cast(nullptr)); //both works in C++0x and C++2003 + else + cont_.push_back(nullptr); + } + + void separate() + { + cont_.push_back(nullptr); + } + + size_type size() const noexcept + { + return cont_.size(); + } + + container_type& container() noexcept + { + return cont_; + } + + item_type * at(size_type pos) + { + return cont_.at(pos); + } + private: + container_type cont_; + size_t right_{ npos }; + }; + + class item_renderer + { + public: + enum class state_t{normal, highlighted, selected}; + const static unsigned extra_size = 6; + + item_renderer(nana::paint::graphics& graph, bool textout, unsigned scale, const ::nana::color& bgcolor) + :graph(graph), textout(textout), scale(scale), bgcolor(bgcolor) + {} + + void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state) + { + //draw background + if (state != state_t::normal) + { + nana::rectangle background_r(x, y, width, height); + graph.rectangle(background_r, false, static_cast(0x3399FF)); + + if (state_t::highlighted == state || state_t::selected == state) + graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast(state_t::selected == state ? 0x99CCFF : 0xC0DDFC), true); + } + + if(!item.image.empty()) + { + auto imgsize = item.image.size(); + + if (imgsize.width > scale) imgsize.width = scale; + if (imgsize.height > scale) imgsize.height = scale; + + nana::point pos( + x + static_cast(scale + extra_size - imgsize.width) / 2, + y + static_cast(height - imgsize.height) / 2); + + item.image.paste(::nana::rectangle{ imgsize }, graph, pos); + if(item.enable == false) + { + nana::paint::graphics gh(imgsize); + gh.bitblt(::nana::rectangle{ imgsize }, graph, pos); + gh.rgb_to_wb(); + gh.paste(graph, pos.x, pos.y); + } + else if (state == state_t::normal) + { + graph.blend(nana::rectangle(pos, imgsize), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25); + } + + x += scale; + width -= scale; + } + + if(textout) + { + graph.string({ x + static_cast(width - item.textsize.width) / 2, y + static_cast(height - item.textsize.height) / 2 }, item.text); + } + } + + protected: + nana::paint::graphics& graph; + bool textout; + unsigned scale; + ::nana::color bgcolor; + }; + + struct drawer::drawer_impl_type + { + event_handle event_size{ nullptr }; + paint::graphics* graph_ptr{ nullptr }; + + unsigned scale{16}; + bool textout{false}; + size_type which{npos}; + item_renderer::state_t state{item_renderer::state_t::normal}; + + item_container items; + ::nana::tooltip tooltip; + }; + + //class drawer + drawer::drawer() + : impl_(new drawer_impl_type) + { + } + + drawer::~drawer() + { + delete impl_; + } + + item_container& drawer::items() const + { + return impl_->items; + } + + void drawer::scale(unsigned s) + { + impl_->scale = s; + + for(auto m : impl_->items.container()) + _m_calc_pixels(m, true); + } + + void drawer::refresh(graph_reference graph) + { + int x = 2, y = 2; + + auto bgcolor = API::bgcolor(widget_->handle()); + graph.palette(true, bgcolor); + graph.gradual_rectangle(rectangle{ graph.size() }, bgcolor.blend(colors::white, 0.1), bgcolor.blend(colors::black, 0.05), true); + + item_renderer ir(graph, impl_->textout, impl_->scale, bgcolor); + size_type index = 0; + + for (auto item : impl_->items.container()) + { + if (item) + { + _m_calc_pixels(item, false); + item->position = x; + ir(x, y, item->pixels, impl_->scale + ir.extra_size, *item, (index == impl_->which ? impl_->state : item_renderer::state_t::normal)); + x += item->pixels; + } + else + { + x += 2; + graph.line({ x, y + 2 }, { x, y + static_cast(impl_->scale + ir.extra_size) - 4 }, static_cast(0x808080)); + x += 4; + } + ++index; + + //Reset the x position of items which are right aligned + //Contributed by kmribti(pr#105) + if (index == impl_->items.right() && index < impl_->items.size()) + { + unsigned total_x = 0; + for (size_t i = index; i < impl_->items.size(); i++) { + if (impl_->items.at(i) == nullptr) { + total_x += 8; // we assume that separator has width = 8. + } + else { + _m_calc_pixels(impl_->items.at(i), false); + total_x += impl_->items.at(i)->pixels; + } + } + + x = graph.size().width - total_x - 4; + } + } + } + + void drawer::attached(widget_reference widget, graph_reference graph) + { + impl_->graph_ptr = &graph; + + widget_ = static_cast< ::nana::toolbar*>(&widget); + widget.caption("nana toolbar"); + + if (widget_->detached()) return; + + impl_->event_size = API::events(widget.parent()).resized.connect_unignorable([this](const arg_resized& arg) + { + auto wd = widget_->handle(); + API::window_size(wd, nana::size(arg.width, widget_->size().height)); + API::update_window(wd); + }); + } + + void drawer::detached() + { + API::umake_event(impl_->event_size); + impl_->event_size = nullptr; + impl_->graph_ptr = nullptr; + } + + void drawer::mouse_move(graph_reference graph, const arg_mouse& arg) + { + if (arg.left_button) + return; + + size_type which = _m_which(arg.pos, true); + if(impl_->which != which) + { + auto & container = impl_->items.container(); + if (impl_->which != npos && container.at(impl_->which)->enable) + { + ::nana::arg_toolbar arg{ *widget_, impl_->which }; + widget_->events().leave.emit(arg, widget_->handle()); + } + + impl_->which = which; + if (which == npos || container.at(which)->enable) + { + impl_->state = item_renderer::state_t::highlighted; + + refresh(graph); + API::dev::lazy_refresh(); + + if (impl_->state == item_renderer::state_t::highlighted) + { + ::nana::arg_toolbar arg{ *widget_, which }; + widget_->events().enter.emit(arg, widget_->handle()); + } + } + + if(which != npos) + impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(container.begin() + which))->text, 0); + else + impl_->tooltip.close(); + } + } + + void drawer::mouse_leave(graph_reference graph, const arg_mouse&) + { + if(impl_->which != npos) + { + size_type which = impl_->which; + + impl_->which = npos; + refresh(graph); + API::dev::lazy_refresh(); + + if (which != npos && impl_->items.at(which)->enable) + { + ::nana::arg_toolbar arg{ *widget_, which }; + widget_->events().leave.emit(arg, widget_->handle()); + } + } + impl_->tooltip.close(); + } + + void drawer::mouse_down(graph_reference graph, const arg_mouse&) + { + impl_->tooltip.close(); + if(impl_->which != npos && (impl_->items.at(impl_->which)->enable)) + { + impl_->state = item_renderer::state_t::selected; + refresh(graph); + API::dev::lazy_refresh(); + } + } + + void drawer::mouse_up(graph_reference graph, const arg_mouse& arg) + { + if(impl_->which != npos) + { + size_type which = _m_which(arg.pos, false); + if(impl_->which == which) + { + ::nana::arg_toolbar arg{ *widget_, which }; + widget_->events().selected.emit(arg, widget_->handle()); + + impl_->state = item_renderer::state_t::highlighted; + } + else + { + impl_->which = which; + impl_->state = (which == npos ? item_renderer::state_t::normal : item_renderer::state_t::highlighted); + } + + refresh(graph); + API::dev::lazy_refresh(); + } + } + + drawer::size_type drawer::_m_which(point pos, bool want_if_disabled) const + { + if (pos.x < 2 || pos.y < 2 || pos.y >= static_cast(impl_->scale + item_renderer::extra_size + 2)) return npos; + + pos.x -= 2; + + std::size_t index = 0; + for(auto m: impl_->items.container()) + { + unsigned x = static_cast(pos.x); + if (m && x >= m->position && x <= (m->position+m->pixels)) + return (((!m) || (!m->enable && !want_if_disabled)) ? npos : index); + + ++index; + } + return npos; + } + + void drawer::_m_calc_pixels(item_type* item, bool force) + { + if (item && (force || (0 == item->pixels))) + { + if (item->text.size()) + item->textsize = impl_->graph_ptr->text_extent_size(item->text); + + if (item->image.empty() == false) + item->pixels = impl_->scale + item_renderer::extra_size; + + if (item->textsize.width && impl_->textout) + item->pixels += item->textsize.width + 8; + } + } + //class drawer + + // Item Proxy + void item_proxy::enable(bool enable_state) const + { + widget.enable(button, enable_state); + } + }//end namespace toolbar + }//end namespace drawerbase + + //class toolbar + toolbar::toolbar(window wd, bool visible, bool detached) : + detached_(detached) + { + create(wd, rectangle(), visible); + } + + toolbar::toolbar(window wd, const rectangle& r, bool visible, bool detached) : + detached_(detached) + { + create(wd, r, visible); + } + + //Contributed by kmribti(pr#105) + void toolbar::go_right() + { + get_drawer_trigger().items().go_right(); + } + + void toolbar::separate() + { + get_drawer_trigger().items().separate(); + API::refresh_window(handle()); + } + + drawerbase::toolbar::item_proxy toolbar::append(const std::string& text, const nana::paint::image& img) + { + get_drawer_trigger().items().push_back(text, img); + API::refresh_window(handle()); + return {*this, get_drawer_trigger().items().size() - 1u}; + } + + drawerbase::toolbar::item_proxy toolbar::append(const std::string& text) + { + get_drawer_trigger().items().push_back(text, {}); + API::refresh_window(this->handle()); + return {*this, get_drawer_trigger().items().size() - 1u}; + } + + bool toolbar::enable(size_type pos) const + { + auto & items = get_drawer_trigger().items(); + + if (items.size() <= pos) + return false; + + auto m = items.at(pos); + return (m && m->enable); + } + + void toolbar::enable(size_type pos, bool eb) + { + auto & items = get_drawer_trigger().items(); + + if (items.size() > pos) + { + auto m = items.at(pos); + if (m && (m->enable != eb)) + { + m->enable = eb; + API::refresh_window(this->handle()); + } + } + } + + void toolbar::scale(unsigned s) + { + get_drawer_trigger().scale(s); + API::refresh_window(handle()); + } + //end class toolbar +}//end namespace nana From 18ff787947086fb948b3708fa7d194f6db740671 Mon Sep 17 00:00:00 2001 From: 5cript Date: Fri, 26 Jan 2018 02:38:33 +0100 Subject: [PATCH 2/3] Whitespace to Tabs. --- include/nana/gui/widgets/toolbar.hpp | 6 +++--- source/gui/widgets/toolbar.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index 1feb84a9..3116042d 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -35,10 +35,10 @@ namespace nana { struct item_proxy { - nana::toolbar& widget; - std::size_t button; + nana::toolbar& widget; + std::size_t button; - void enable(bool enable_state) const; + void enable(bool enable_state) const; }; struct toolbar_events diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index 0ed983ca..1c36d355 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -421,10 +421,10 @@ namespace nana //class drawer // Item Proxy - void item_proxy::enable(bool enable_state) const - { - widget.enable(button, enable_state); - } + void item_proxy::enable(bool enable_state) const + { + widget.enable(button, enable_state); + } }//end namespace toolbar }//end namespace drawerbase From 46f03638a2582d41c5b23b22ac2e7c557a914876 Mon Sep 17 00:00:00 2001 From: 5cript Date: Fri, 26 Jan 2018 02:41:04 +0100 Subject: [PATCH 3/3] Removed wrong const. --- include/nana/gui/widgets/toolbar.hpp | 2 +- source/gui/widgets/toolbar.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nana/gui/widgets/toolbar.hpp b/include/nana/gui/widgets/toolbar.hpp index 3116042d..cc0f4e24 100644 --- a/include/nana/gui/widgets/toolbar.hpp +++ b/include/nana/gui/widgets/toolbar.hpp @@ -38,7 +38,7 @@ namespace nana nana::toolbar& widget; std::size_t button; - void enable(bool enable_state) const; + void enable(bool enable_state); }; struct toolbar_events diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index 1c36d355..d34fc524 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -421,7 +421,7 @@ namespace nana //class drawer // Item Proxy - void item_proxy::enable(bool enable_state) const + void item_proxy::enable(bool enable_state) { widget.enable(button, enable_state); }