/* * A Tabbar Implementation * Copyright(C) 2003-2013 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/tabbar.hpp */ #include #include #include #include #include namespace nana { namespace drawerbase { namespace tabbar { struct item_t { window relative{nullptr}; paint::image img; nana::string text; any value; ::nana::expr_color bgcolor; ::nana::expr_color fgcolor; }; class def_renderer : public item_renderer { private: virtual void background(graph_reference graph, const nana::rectangle& r, const ::nana::expr_color& bgcolor) { if(bgcolor_ != bgcolor) { bgcolor_ = bgcolor; dark_bgcolor_ = ::nana::expr_color{ colors::black }.blend(bgcolor, 0.1); blcolor_ = ::nana::expr_color{ colors::black }.blend(bgcolor, 0.5); ilcolor_ = ::nana::expr_color{ colors::white }.blend(bgcolor, 0.1); } graph.rectangle(true, bgcolor); } virtual void item(graph_reference graph, const item_t& m, bool active, state_t sta) { //* const nana::rectangle & r = m.r; expr_color bgcolor; expr_color blcolor; expr_color dark_bgcolor; if(m.bgcolor.invisible()) { bgcolor = bgcolor_; blcolor = blcolor_; dark_bgcolor = dark_bgcolor_; } else { bgcolor = m.bgcolor; blcolor = expr_color{ colors::black }.blend(m.bgcolor, 0.5); //dark_bgcolor = nana::paint::graphics::mix(m.bgcolor, 0, 0.9); //deprecated dark_bgcolor = expr_color{ colors::black }.blend(m.bgcolor, 0.1); } auto round_r = r; round_r.height += 2; graph.round_rectangle(round_r, 3, 3, blcolor, true, colors::white); auto beg = bgcolor; auto end = dark_bgcolor; if(active) { if (m.bgcolor.invisible()) beg = ilcolor_; else beg = expr_color{ m.bgcolor }.blend(colors::white, 0.5); end = bgcolor; } if (sta == item_renderer::highlight) beg.blend(colors::white, 0.5); //graph.shadow_rectangle(r.x + 2, r.y + 2, r.width - 4, r.height - 2, beg, end, true); //deprecated graph.gradual_rectangle(round_r.pare_off(2), beg, end, true); } virtual void add(graph_reference graph, const nana::rectangle& r, state_t sta) { int x = r.x + (static_cast(r.width) - 14) / 2; int y = r.y + (static_cast(r.height) - 14) / 2; ::nana::expr_color clr; switch(sta) { case item_renderer::highlight: clr = { colors::white }; break; case item_renderer::press: clr = { 0xA0, 0xA0, 0xA0 }; break; case item_renderer::disable: clr = { 0x80, 0x80, 0x80 }; break; default: clr = { 0xF0, 0xF0, 0xF0 }; } graph.rectangle(r, true, bgcolor_); nana::paint::gadget::cross(graph, x, y, 14, 6, clr); } virtual void close(graph_reference graph, const nana::rectangle& r, state_t sta) { nana::paint::gadget::close_16_pixels(graph, r.x + (r.width - 16) / 2, r.y + (r.height - 16) / 2, 1, colors::black); if(item_renderer::highlight == sta) graph.rectangle(r, false, {0xa0, 0xa0, 0xa0}); } virtual void close_fly(graph_reference graph, const nana::rectangle& r, bool active, state_t sta) { using namespace nana::paint; ::nana::expr_color clr{ colors::black }; if (sta == item_renderer::highlight) { ::nana::expr_color bgcolor{ 0xCC, 0xD2, 0xDD }; ::nana::expr_color rect_clr{0x9d, 0xa3, 0xab}; graph.round_rectangle(r, 1, 1, rect_clr, false, {}); nana::rectangle draw_r(r); graph.rectangle(draw_r.pare_off(1), false, ::nana::expr_color{ rect_clr }.blend(bgcolor, 0.8)); graph.rectangle(draw_r.pare_off(1), false, ::nana::expr_color{ rect_clr }.blend(bgcolor, 0.4)); graph.rectangle(draw_r.pare_off(1), false, ::nana::expr_color{ rect_clr }.blend(bgcolor, 0.2)); } else if (!active) clr = ::nana::expr_color{ 0x92, 0x99, 0xA4 }; gadget::close_16_pixels(graph, r.x - (16 - r.width) / 2, r.y - (16 - r.height) / 2, 1, clr); } virtual void back(graph_reference graph, const nana::rectangle& r, state_t sta) { using namespace nana::paint::gadget; _m_draw_arrow(graph, r, sta, directions::to_west); } virtual void next(graph_reference graph, const nana::rectangle& r, state_t sta) { using namespace nana::paint::gadget; _m_draw_arrow(graph, r, sta, directions::to_east); } virtual void list(graph_reference graph, const nana::rectangle& r, state_t sta) { using namespace nana::paint::gadget; _m_draw_arrow(graph, r, sta, directions::to_south); } private: void _m_draw_arrow(graph_reference graph, const nana::rectangle& r, state_t sta, nana::paint::gadget::directions::t dir) { using namespace nana::paint::gadget; ::nana::expr_color fgcolor(colors::black); int style = 1; if(sta == item_renderer::disable) { style = 0; fgcolor = { 0x80, 0x80, 0x80 }; } arrow_16_pixels(graph, r.x + (r.width - 16) / 2, r.y + (r.height - 16) / 2, fgcolor, style, dir); if(item_renderer::highlight == sta) graph.rectangle(r, false, { 0xA0, 0xA0, 0xA0 }); } private: ::nana::expr_color bgcolor_; ::nana::expr_color dark_bgcolor_; ::nana::expr_color blcolor_; ::nana::expr_color ilcolor_; }; class toolbox { struct button_tag { bool visible; bool enable; }; public: enum button_t{ButtonAdd, ButtonScrollBack, ButtonScrollNext, ButtonList, ButtonClose, ButtonSize}; toolbox() : close_fly_(false) { for(int i = ButtonAdd; i < ButtonSize; ++i) { buttons_[i].visible = true; buttons_[i].enable = true; } buttons_[0].enable = false; buttons_[3].enable = false; buttons_[4].enable = false; } nana::rectangle area(button_t btn, unsigned height) const { nana::rectangle r(-1, 0, 0, 0); if((btn == ButtonAdd) || (btn == ButtonClose && close_fly_)) return r; int x = 0; for(int i = ButtonScrollBack; i < ButtonSize; ++i) { if(btn != i) { if(i != ButtonAdd && buttons_[i].visible && buttons_[i].enable) x += item_pixels(); } else { r.x = x; r.width = item_pixels(); r.height = height; return r; } } return r; } bool renderable(button_t btn) const { if(ButtonAdd <= btn && btn < ButtonSize) { if((btn == ButtonClose) && close_fly_) return false; return (buttons_[btn].visible && buttons_[btn].enable); } return false; } bool visible(button_t btn, bool vs) { if(buttons_[btn].visible != vs) { buttons_[btn].visible = vs; return true; } return false; } bool visible(button_t btn) const { return buttons_[btn].visible; } bool close_fly(bool fly) { if(close_fly_ != fly) { close_fly_ = fly; return true; } return false; } bool close_fly() const { return close_fly_; } bool enable(button_t btn) const { return buttons_[btn].enable; } bool enable(button_t btn, bool enb) { if(buttons_[btn].enable != enb) { buttons_[btn].enable = enb; return true; } return false; } unsigned width() const { unsigned pixels = 0; for(int i = ButtonScrollBack; i < ButtonSize; ++i) { if(renderable(static_cast(i))) { if((i != ButtonClose) || (close_fly_ == false)) pixels += item_pixels(); } } return pixels; } unsigned item_pixels() const { return 18; } button_t which(int x) const { for(int i = ButtonAdd; i < ButtonSize; ++i) { if((i == ButtonClose && close_fly_) || (i == ButtonAdd)) continue; if(renderable(static_cast(i))) { if(0 <= x && x < static_cast(item_pixels())) return static_cast(i); else x -= static_cast(item_pixels()); } } return ButtonSize; } private: bool close_fly_; button_tag buttons_[ButtonSize]; }; // class layouter { public: typedef std::list::iterator iterator; typedef std::list::const_iterator const_iterator; nana::any& at(std::size_t i) { if(i < list_.size()) return at_no_bound_check(i); throw std::out_of_range("Nana.GUI.tabbar::at() is out of range"); } iterator iterator_at(std::size_t pos) { auto i = list_.begin(); std::advance(i, pos); return i; } const_iterator iterator_at(std::size_t pos) const { auto i = list_.cbegin(); std::advance(i, pos); return i; } nana::any& at_no_bound_check(std::size_t pos) { return iterator_at(pos)->value; } const nana::any& at(std::size_t pos) const { if(pos < list_.size()) return at_no_bound_check(pos); throw std::out_of_range("Nana.GUI.tabbar::at() const is out of range"); } const nana::any& at_no_bound_check(std::size_t pos) const { return iterator_at(pos)->value; } toolbox & toolbox_object() { return toolbox_; } window widget_handle() const { return basis_.wd; } void attach(window wd, nana::paint::graphics& graph) { basis_.wd = wd; basis_.graph = &graph; } void detach() { basis_.graph = 0; } const pat::cloneable & ext_renderer() const { return basis_.renderer; } void ext_renderer(const pat::cloneable& ir) { basis_.renderer = ir; } void event_agent(event_agent_interface* evt) { evt_agent_ = evt; } void push_back(const nana::string& text, const nana::any & value) { item_t m; m.text = text; m.value = value; list_.push_back(m); activate(static_cast(list_.size() - 1)); render(); } std::size_t length() const { return list_.size(); } bool erase(std::size_t pos) { if(pos < list_.size()) { if ((nullptr == evt_agent_) || evt_agent_->removed(pos)) { list_.erase(iterator_at(pos)); _m_adjust(); if(pos < basis_.active) { --basis_.active; if(basis_.scroll_pixels > basis_.item_pixels) basis_.scroll_pixels -= basis_.item_pixels; else basis_.scroll_pixels = 0; } else { auto count = list_.size(); if (pos == count) basis_.active = pos = count - 1; count *= basis_.item_pixels; if (count > static_cast(_m_itembar_right())) basis_.scroll_pixels = static_cast(count)-static_cast(_m_itembar_right()); else basis_.scroll_pixels = 0; } if(evt_agent_) evt_agent_->activated(basis_.active); return true; } } return false; } void render() { _m_adjust(); _m_render(); } bool press() { trace_.state = item_renderer::press; return (trace_.what != trace_.null); } bool active_by_trace() { return ((trace_.what == trace_.item) && (trace_.item_part != trace_.close)? activate(trace_.u.index) : false); } bool release() { trace_.state = item_renderer::highlight; return true; } bool leave() { trace_.state = item_renderer::normal; if(trace_.what != trace_.null) { trace_.what = trace_.null; return true; } return false; } void track() { int left, right; if(_m_item_pos(basis_.active, left, right)) { if(left < 0) basis_.scroll_pixels -= static_cast(-left); else if(right > _m_itembar_right()) basis_.scroll_pixels += static_cast(right - _m_itembar_right()); } } bool trace(int x, int y) { trace_.state = item_renderer::highlight; if(basis_.graph == 0) return false; int ibar_end = _m_itembar_right(); trace_tag::item_t item_part = trace_.item_part; std::size_t index = _m_where_itembar(x, y, ibar_end); if(index != npos) { if((trace_.what != trace_.item) || (trace_.u.index != index) || (item_part != trace_.item_part)) { trace_.what = trace_.item; trace_.u.index = index; return true; } return false; } if(toolbox_.renderable(toolbox_.ButtonAdd)) { if(ibar_end <= x && x < ibar_end + static_cast(toolbox_.item_pixels())) { if((trace_.what != trace_.toolbox) || (trace_.u.button != toolbox::ButtonAdd)) { trace_.what = trace_.toolbox; trace_.u.button = toolbox::ButtonAdd; return true; } return false; } } int tbpos = _m_toolbox_pos(); if(tbpos <= x) { toolbox::button_t t = toolbox_.which(x - tbpos); if(trace_.what != trace_.toolbox || trace_.u.button != t) { trace_.what = trace_.toolbox; trace_.u.button = t; return true; } return false; } if(trace_.what != trace_.null) { trace_.what = trace_.null; return true; } return false; } bool activate(std::size_t pos) { if(pos < list_.size() && (pos != basis_.active)) { API::show_window(iterator_at(pos)->relative, true); if(basis_.active < list_.size()) API::show_window(iterator_at(basis_.active)->relative, false); basis_.active = pos; track(); if(evt_agent_) evt_agent_->activated(pos); return true; } return false; } std::size_t active() const { return basis_.active; } void relate(std::size_t pos, window wd) { if(pos < list_.size()) { iterator_at(pos)->relative = wd; API::show_window(wd, basis_.active == pos); } } bool tab_color(std::size_t pos, bool is_bgcolor, const ::nana::expr_color& clr) { if(pos < list_.size()) { auto & m = *iterator_at(pos); auto & m_clr = (is_bgcolor ? m.bgcolor : m.fgcolor); if (m_clr != clr) { m_clr = clr; return true; } } return false; } bool tab_image(std::size_t pos, const nana::paint::image& img) { if(pos > list_.size()) return false; auto & m = *iterator_at(pos); if(img) m.img = img; else m.img.close(); return true; } bool text(std::size_t pos, const nana::string& str) { if(pos < list_.size()) { auto & m = *iterator_at(pos); if(m.text != str) { m.text = str; return true; } } return false; } nana::string text(std::size_t pos) const { if(pos < list_.size()) return iterator_at(pos)->text; return nana::string(); } bool toolbox_answer(const arg_mouse& arg) { if(trace_.what == trace_.toolbox) { if(toolbox_.renderable(trace_.u.button)) { switch(trace_.u.button) { case toolbox::ButtonAdd: if(event_code::mouse_up == arg.evt_code) return _m_add_tab(npos); break; case toolbox::ButtonScrollBack: if(event_code::mouse_down == arg.evt_code) return _m_scroll(true); break; case toolbox::ButtonScrollNext: if(event_code::mouse_down == arg.evt_code) return _m_scroll(false); break; case toolbox::ButtonList: if (event_code::mouse_down == arg.evt_code) { _m_open_menulister(); return true; } break; case toolbox::ButtonClose: if (event_code::mouse_up == arg.evt_code) { if(this->erase(basis_.active)) { track(); return true; } } break; default: break; } } } else if((trace_.what == trace_.item) && (trace_.item_part == trace_.close)) { if(event_code::mouse_up == arg.evt_code) { if(this->erase(trace_.u.index)) { track(); trace(arg.pos.x, arg.pos.y); return true; } } } return false; } private: //Fundation bool _m_nextable() const { return (basis_.scroll_pixels + _m_itembar_right() < basis_.item_pixels * list_.size()); } bool _m_add_tab(std::size_t pos) { item_t m; if((pos == npos) || (pos >= list_.size())) { this->list_.push_back(m); pos = static_cast(list_.size() - 1); } else list_.insert(iterator_at(pos), m); basis_.active = pos; if(evt_agent_) { evt_agent_->added(pos); evt_agent_->activated(pos); } return true; } bool _m_scroll(bool left) { if(left) { if(basis_.scroll_pixels) { unsigned i = basis_.scroll_pixels / basis_.item_pixels; if(i > 1) basis_.scroll_pixels = (i - 1) * basis_.item_pixels; else basis_.scroll_pixels = 0; return true; } } else { auto scale = static_cast(_m_itembar_right()); auto take = static_cast(list_.size() * basis_.item_pixels); if(take > scale) { auto i = (basis_.scroll_pixels + scale) / basis_.item_pixels; i += (basis_.scroll_pixels % basis_.item_pixels ? 2 : 1); auto px = i * basis_.item_pixels; if(px > take) px = take; basis_.scroll_pixels = px - scale; return true; } } return false; } void _m_open_menulister() { menulister_.clear(); auto f = std::bind(&layouter::_m_click_menulister, this, std::placeholders::_1); for(auto & m : list_) menulister_.append(m.text, f); auto r = toolbox_.area(toolbox_.ButtonList, basis_.graph->height()); r.x += _m_toolbox_pos(); menulister_.popup(basis_.wd, r.x, r.bottom()); } void _m_click_menulister(nana::menu::item_proxy& ip) { if(this->activate(ip.index())) API::refresh_window(basis_.wd); } //the begin pos of toolbox int _m_toolbox_pos() const { int tbpos = static_cast(basis_.graph->width()) - static_cast(_m_toolbox_pixels()); return (tbpos < 0 ? 0 : tbpos); } unsigned _m_toolbox_pixels() const { return toolbox_.width(); } int _m_itembar_right() const { int right = _m_toolbox_pos(); if(toolbox_.renderable(toolbox_.ButtonAdd)) right -= static_cast(toolbox_.item_pixels()); int end = static_cast(list_.size() * basis_.item_pixels); return (end < right ? end : right); } nana::rectangle _m_close_fly_area(int x) { return nana::rectangle(x + basis_.item_pixels - 18, (basis_.graph->height() - 14) / 2, 14, 14); } bool _m_item_pos(std::size_t index, int &left, int &right) const { if(index < list_.size()) { left = static_cast(index * basis_.item_pixels); left -= static_cast(basis_.scroll_pixels); right = left + basis_.item_pixels; return true; } return false; } std::size_t _m_where_itembar(int x, int y, int end) { if(x < 0 || x >= end) return npos; int left = -static_cast(basis_.scroll_pixels); std::size_t i = 0, size = list_.size(); for(; i != size; ++i) { if(left >= end) { i = npos; break; } if(left <= x && x < left + static_cast(basis_.item_pixels)) break; left += basis_.item_pixels; } if(i < list_.size()) { trace_.item_part = trace_.body; if(toolbox_.close_fly()) { nana::rectangle r = _m_close_fly_area(left); if((r.x <= x && x < r.x + static_cast(r.width)) && (r.y <= y && y < r.y + static_cast(r.height))) trace_.item_part = trace_.close; } return i; } return npos; } nana::rectangle _m_toolbox_area(toolbox::button_t btn) const { nana::rectangle r(0, 0, toolbox_.item_pixels(), basis_.graph->height()); if(btn == toolbox_.ButtonAdd) { int end = _m_itembar_right(); if(static_cast(list_.size() * basis_.item_pixels) < end) r.x = static_cast(list_.size() * basis_.item_pixels); else r.x = end; } else if(toolbox_.ButtonClose == btn && toolbox_.close_fly()) { r.x = -1; r.width = r.height = 0; } else r = toolbox_.area(btn, basis_.graph->height()); return r; } void _m_adjust() { if((nullptr == basis_.graph) || (0 == list_.size())) return; //adjust the number of pixels of item. bool scrollable = toolbox_.renderable(toolbox_.ButtonScrollBack); if(scrollable) { toolbox_.visible(toolbox_.ButtonScrollBack, false); toolbox_.visible(toolbox_.ButtonScrollNext, false); } unsigned beside = _m_toolbox_pixels(); if(toolbox_.renderable(toolbox_.ButtonAdd)) beside += toolbox_.item_pixels(); unsigned pixels = basis_.graph->width(); if(pixels <= beside) return; unsigned each_pixels = static_cast((pixels - beside) / list_.size()); if(each_pixels > basis_.max_pixels) each_pixels = basis_.max_pixels; else if(each_pixels < basis_.min_pixels) each_pixels = basis_.min_pixels; unsigned total = static_cast(each_pixels * list_.size()); if(total > pixels - beside && toolbox_.enable(toolbox_.ButtonScrollBack)) { toolbox_.visible(toolbox_.ButtonScrollBack, true); toolbox_.visible(toolbox_.ButtonScrollNext, true); beside = _m_toolbox_pixels(); if(toolbox_.renderable(toolbox_.ButtonAdd)) beside += toolbox_.item_pixels(); if(pixels <= beside) return; each_pixels = static_cast((pixels - beside) / list_.size()); if(each_pixels > basis_.max_pixels) each_pixels = basis_.max_pixels; else if(each_pixels < basis_.min_pixels) each_pixels = basis_.min_pixels; } else basis_.scroll_pixels = 0; if(each_pixels != basis_.item_pixels) basis_.item_pixels = each_pixels; if(scrollable != toolbox_.renderable(toolbox_.ButtonScrollBack)) basis_.scroll_pixels = static_cast(list_.size() * basis_.item_pixels) - _m_itembar_right(); } item_renderer::state_t _m_state(unsigned index) const { return ((trace_.what == trace_.item) && (trace_.u.index == index) ? item_renderer::highlight : item_renderer::normal); } item_renderer::state_t _m_state(toolbox::button_t kind) const { return ((trace_.what == trace_.toolbox && trace_.u.button == kind) ? item_renderer::highlight : item_renderer::normal); } void _m_render() { if(!basis_.renderer || (nullptr == basis_.graph)) return; auto bgcolor = API::bgcolor(basis_.wd); auto fgcolor = API::fgcolor(basis_.wd); item_renderer::item_t m = { basis_.graph->size() }; basis_.renderer->background(*basis_.graph, m.r, bgcolor); //the max number of pixels of tabs. int pixels = static_cast(m.r.width - _m_toolbox_pixels()); m.r.x = -static_cast(basis_.scroll_pixels); m.r.width = basis_.item_pixels; unsigned index = 0; bool is_close_fly = toolbox_.visible(toolbox_.ButtonClose) && toolbox_.enable(toolbox_.ButtonClose) && toolbox_.close_fly(); item_renderer::item_t active_m; for(auto i = list_.cbegin(); i != list_.cend(); ++i, ++index) { if(m.r.x >= pixels) break; if(m.r.x + static_cast(basis_.item_pixels) > 0) { m.bgcolor = i->bgcolor; m.fgcolor = i->fgcolor; if(index == this->basis_.active) active_m = m; const item_t & item = *i; basis_.renderer->item(*basis_.graph, m, (index == basis_.active), _m_state(index)); if(is_close_fly) { item_renderer::state_t sta = item_renderer::normal; if(trace_.what == trace_.item && trace_.item_part == trace_.close && index == trace_.u.index) sta = item_renderer::highlight; basis_.renderer->close_fly(*basis_.graph, _m_close_fly_area(m.r.x), (index == basis_.active), sta); } if(false == item.img.empty()) item.img.stretch(item.img.size(), *basis_.graph, nana::rectangle(m.r.x + 4, (m.r.height - 16) / 2, 16, 16)); if(item.text.size()) { nana::size ts = basis_.graph->text_extent_size(item.text); basis_.graph->set_text_color(m.fgcolor.invisible() ? fgcolor : m.fgcolor); nana::paint::text_renderer tr(*basis_.graph); tr.render({ m.r.x + 24, m.r.y + static_cast(m.r.height - ts.height) / 2 }, item.text.c_str(), item.text.length(), basis_.item_pixels - 24 - 18, true); } } m.r.x += static_cast(basis_.item_pixels); } _m_render_toolbox(bgcolor); int bottom = static_cast(basis_.graph->height()) - 1; if(_m_nextable()) { int x = _m_itembar_right(); if (x > 0) { basis_.graph->line({ x - 2, 0 }, { x - 2, bottom }, { 0x80, 0x80, 0x80 }); basis_.graph->line({ x - 1, 0 }, { x - 1, bottom }, {0xf0, 0xf0, 0xf0}); } } basis_.graph->set_color({ 0x80, 0x80, 0x80 }); int right = static_cast(basis_.graph->width()); int end = active_m.r.x + static_cast(active_m.r.width); if(0 < active_m.r.x && active_m.r.x < right) basis_.graph->line({ 0, bottom }, { active_m.r.x, bottom }); if(0 <= end && end < right) basis_.graph->line({ end, bottom }, { right, bottom }); } void _m_render_toolbox(const ::nana::expr_color& bgcolor) { bool backable = (basis_.scroll_pixels != 0); int xbase = _m_toolbox_pos(); basis_.graph->rectangle({ xbase, 0, _m_toolbox_pixels(), basis_.graph->height() }, true, bgcolor); for(int i = toolbox::ButtonAdd; i < toolbox::ButtonSize; ++i) { toolbox::button_t btn = static_cast(i); if(toolbox_.renderable(btn) == false) continue; nana::rectangle r = _m_toolbox_area(btn); if(toolbox_.ButtonAdd != btn) r.x += xbase; item_renderer::state_t state = item_renderer::normal; if((trace_.what == trace_.toolbox) && (trace_.u.button == btn)) state = trace_.state; switch(btn) { case toolbox::ButtonScrollBack: basis_.renderer->back(*basis_.graph, r, (backable ? state : item_renderer::disable)); break; case toolbox::ButtonScrollNext: basis_.renderer->next(*basis_.graph, r, (_m_nextable() ? state : item_renderer::disable)); break; case toolbox::ButtonList: basis_.renderer->list(*basis_.graph, r, state); break; case toolbox::ButtonClose: basis_.renderer->close(*basis_.graph, r, state); break; case toolbox::ButtonAdd: basis_.renderer->add(*basis_.graph, r, state); break; default: break; } } } private: std::list list_; event_agent_interface* evt_agent_ = nullptr; toolbox toolbox_; ::nana::menu menulister_; struct trace_tag { enum t{null, item, toolbox}; enum item_t{body, close}; t what; item_t item_part; //it is valid while "what" is item. item_renderer::state_t state; union { std::size_t index; toolbox::button_t button; }u; trace_tag():what(null), state(item_renderer::normal) {} }trace_; struct basis_tag { window wd{nullptr}; nana::paint::graphics * graph{nullptr}; pat::cloneable renderer; unsigned max_pixels{250}; unsigned min_pixels{100}; unsigned item_pixels{max_pixels}; unsigned scroll_pixels{0}; std::size_t active{npos}; basis_tag():renderer{ def_renderer() } {} }basis_; }; //class trigger trigger::trigger() : layouter_(new layouter) {} trigger::~trigger() { delete layouter_; } void trigger::activate(std::size_t pos) { if(layouter_->activate(pos)) API::refresh_window(layouter_->widget_handle()); } std::size_t trigger::activated() const { return layouter_->active(); } nana::any& trigger::at(std::size_t i) const { return layouter_->at(i); } nana::any& trigger::at_no_bound_check(std::size_t i) const { return layouter_->at_no_bound_check(i); } const pat::cloneable & trigger::ext_renderer() const { return layouter_->ext_renderer(); } void trigger::ext_renderer(const pat::cloneable& ir) { layouter_->ext_renderer(ir); } void trigger::set_event_agent(event_agent_interface* evt) { layouter_->event_agent(evt); } void trigger::push_back(const nana::string& text, const nana::any& value) { layouter_->push_back(text, value); } std::size_t trigger::length() const { return layouter_->length(); } bool trigger::close_fly(bool fly) { return layouter_->toolbox_object().close_fly(fly); } void trigger::relate(std::size_t i, window wd) { layouter_->relate(i, wd); } void trigger::tab_color(std::size_t i, bool is_bgcolor, const ::nana::expr_color& clr) { if(layouter_->tab_color(i, is_bgcolor, clr)) API::refresh_window(layouter_->widget_handle()); } void trigger::tab_image(std::size_t i, const nana::paint::image& img) { if(layouter_->tab_image(i, img)) API::refresh_window(layouter_->widget_handle()); } void trigger::text(std::size_t i, const nana::string& str) { if(layouter_->text(i, str)) API::refresh_window(layouter_->widget_handle()); } nana::string trigger::text(std::size_t i) const { return layouter_->text(i); } bool trigger::toolbox_button(toolbox_button_t btn, bool enable) { toolbox::button_t tb = toolbox::ButtonSize; toolbox & tbobj = layouter_->toolbox_object(); switch(btn) { case trigger::ButtonAdd: tb = toolbox::ButtonAdd; break; case trigger::ButtonList: tb = toolbox::ButtonList; break; case trigger::ButtonClose: tb = toolbox::ButtonClose; break; case trigger::ButtonScroll: tbobj.enable(toolbox::ButtonScrollBack, enable); return tbobj.enable(tbobj.ButtonScrollNext, enable); } return (tb != toolbox::ButtonSize ? tbobj.enable(tb, enable) : false); } void trigger::attached(widget_reference widget, graph_reference graph) { layouter_->attach(widget, graph); } void trigger::detached() { layouter_->detach(); } void trigger::refresh(graph_reference) { layouter_->render(); } void trigger::mouse_down(graph_reference, const arg_mouse& arg) { if(layouter_->press()) { if(false == layouter_->active_by_trace()) layouter_->toolbox_answer(arg); layouter_->render(); API::lazy_refresh(); } } void trigger::mouse_up(graph_reference, const arg_mouse& arg) { bool rd = layouter_->release(); rd |= layouter_->toolbox_answer(arg); if(rd) { layouter_->render(); API::lazy_refresh(); } } void trigger::mouse_move(graph_reference, const arg_mouse& arg) { if(layouter_->trace(arg.pos.x, arg.pos.y)) { layouter_->render(); API::lazy_refresh(); } } void trigger::mouse_leave(graph_reference, const arg_mouse&) { if(layouter_->leave()) { layouter_->render(); API::lazy_refresh(); } } //end class trigger }//end namespace tabbar }//end namespace drawerbase }//end namespace nana