nana/include/nana/gui/widgets/tabbar.hpp
2015-09-21 23:43:00 +08:00

409 lines
12 KiB
C++
Raw Blame History

/**
* A Tabbar implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 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
* @brief A tabbar contains tab items and toolbox for scrolling, closing, selecting items.
*
*/
#ifndef NANA_GUI_WIDGET_TABBAR_HPP
#define NANA_GUI_WIDGET_TABBAR_HPP
#include "widget.hpp"
#include <nana/pat/cloneable.hpp>
#include <nana/any.hpp>
namespace nana
{
template<typename T> class tabbar;
template<typename T>
struct arg_tabbar
: public event_arg
{
tabbar<T> & widget;
T & value;
arg_tabbar(tabbar<T>& wdg, T& v)
: widget(wdg), value{ v }
{}
};
template<typename T>
struct arg_tabbar_removed : public arg_tabbar<T>
{
arg_tabbar_removed(tabbar<T>& wdg, T& v)
: arg_tabbar<T>({wdg, v})
{}
bool remove = true;
};
namespace drawerbase
{
namespace tabbar
{
template<typename T>
struct tabbar_events
: public general_events
{
typedef T value_type;
basic_event<arg_tabbar<value_type>> added;
basic_event<arg_tabbar<value_type>> activated;
basic_event<arg_tabbar<value_type>> removed;
};
class event_agent_interface
{
public:
virtual ~event_agent_interface() = default;
virtual void added(std::size_t) = 0;
virtual void activated(std::size_t) = 0;
virtual bool removed(std::size_t) = 0;
};
class item_renderer
{
public:
typedef item_renderer item_renderer_type;
typedef ::nana::paint::graphics & graph_reference;
enum state_t{disable, normal, highlight, press};
struct item_t
{
::nana::rectangle r;
::nana::color bgcolor;
::nana::color fgcolor;
};
virtual ~item_renderer() = default;
virtual void background(graph_reference, const nana::rectangle& r, const ::nana::color& bgcolor) = 0;
virtual void item(graph_reference, const item_t&, bool active, state_t) = 0;
virtual void close_fly(graph_reference, const nana::rectangle&, bool active, state_t) = 0;
virtual void add(graph_reference, const nana::rectangle&, state_t) = 0;
virtual void close(graph_reference, const nana::rectangle&, state_t) = 0;
virtual void back(graph_reference, const nana::rectangle&, state_t) = 0;
virtual void next(graph_reference, const nana::rectangle&, state_t) = 0;
virtual void list(graph_reference, const nana::rectangle&, state_t) = 0;
};
template<typename T, typename DrawerTrigger>
class event_agent
: public event_agent_interface
{
public:
typedef ::nana::arg_tabbar<T> arg_tabbar;
event_agent(::nana::tabbar<T>& tb, DrawerTrigger & dtr)
: tabbar_(tb), drawer_trigger_(dtr)
{}
void added(std::size_t pos) override
{
if(pos != npos)
{
drawer_trigger_.at_no_bound_check(pos) = T();
tabbar_.events().added.emit(arg_tabbar({ tabbar_, tabbar_[pos] }));
}
}
void activated(std::size_t pos) override
{
if(pos != npos)
tabbar_.events().activated.emit(arg_tabbar({ tabbar_, tabbar_[pos]}));
}
bool removed(std::size_t pos) override
{
if (pos != npos)
{
::nana::arg_tabbar_removed<T> arg(tabbar_, tabbar_[pos]);
tabbar_.events().removed.emit(arg);
return arg.remove;
}
return true;
}
private:
::nana::tabbar<T> & tabbar_;
DrawerTrigger& drawer_trigger_;
};
class layouter;
class trigger
: public drawer_trigger
{
public:
enum toolbox_button_t{ButtonAdd, ButtonScroll, ButtonList, ButtonClose};
trigger();
~trigger();
void activate(std::size_t);
std::size_t activated() const;
nana::any& at(std::size_t) const;
nana::any& at_no_bound_check(std::size_t) const;
const pat::cloneable<item_renderer> & ext_renderer() const;
void ext_renderer(const pat::cloneable<item_renderer>&);
void set_event_agent(event_agent_interface*);
void push_back(const nana::string&, const nana::any&);
std::size_t length() const;
bool close_fly(bool);
void relate(size_t, window);
void tab_color(std::size_t, bool is_bgcolor, const ::nana::color&);
void tab_image(size_t, const nana::paint::image&);
void text(std::size_t, const nana::string&);
nana::string text(std::size_t) const;
bool toolbox_button(toolbox_button_t, bool);
private:
void attached(widget_reference, graph_reference) override;
void detached() override;
void refresh(graph_reference) override;
void mouse_down(graph_reference, const arg_mouse&) override;
void mouse_up(graph_reference, const arg_mouse&) override;
void mouse_move(graph_reference, const arg_mouse&) override;
void mouse_leave(graph_reference, const arg_mouse&) override;
private:
layouter * layouter_;
};
}
}//end namespace drawerbase
/// Analogous to dividers in a notebook or the labels in a file cabinet
template<typename Type>
class tabbar
: public widget_object<category::widget_tag, drawerbase::tabbar::trigger, drawerbase::tabbar::tabbar_events<Type>>
{
typedef drawerbase::tabbar::trigger drawer_trigger_t;
public:
typedef Type value_type; ///< The type of element data which is stored in the tabbar.
typedef drawerbase::tabbar::item_renderer item_renderer; ///< A user-defined item renderer should be derived from this interface.
struct button_add{}; ///< The type identifies the add button of the tabbar's toolbox.
struct button_scroll{}; ///< The type identifies the scroll button of the tabbar's toolbox.
struct button_list{}; ///< The type identifies the list button of the tabbar's toolbox.
struct button_close{}; ///< The type identifies the close button of the tabbar's toolbox.
/// A template class identifies the buttons of the tabbar<61>s toolbox. Refer to notes for more details.
template<typename ButtonAdd = nana::null_type, typename ButtonScroll = nana::null_type, typename ButtonList = nana::null_type, typename ButtonClose = nana::null_type>
struct button_container
{
typedef meta::fixed_type_set<ButtonAdd, ButtonScroll, ButtonList, ButtonClose> type_set;
};
tabbar()
{
evt_agent_.reset(new drawerbase::tabbar::event_agent<value_type, drawer_trigger_t>(*this, this->get_drawer_trigger()));
this->get_drawer_trigger().set_event_agent(evt_agent_.get());
}
tabbar(window wd, bool visible)
: tabbar()
{
this->create(wd, rectangle(), visible);
}
tabbar(window wd, const nana::char_t* text, bool visible)
: tabbar(wd, ::nana::string(text), visible)
{
}
tabbar(window wd, const nana::string& text, bool visible)
: tabbar()
{
this->create(wd, rectangle(), visible);
this->caption(text);
}
tabbar(window wd, const rectangle& r = rectangle(), bool visible = true)
: tabbar()
{
this->create(wd, r, visible);
}
~tabbar()
{
this->get_drawer_trigger().set_event_agent(nullptr);
}
value_type & operator[](std::size_t pos) const
{
return static_cast<value_type&>(this->get_drawer_trigger().at_no_bound_check(pos));
}
void activate(std::size_t pos) /// Activates a tab specified by i.
{
this->get_drawer_trigger().activate(pos);
}
std::size_t activated() const
{
return this->get_drawer_trigger().activated();
}
value_type & at(std::size_t i) const /// Returns i'th element
{
return static_cast<value_type&>(this->get_drawer_trigger().at(i));
}
void close_fly(bool fly) /// Draw or not a close button in each tab.
{
if(this->get_drawer_trigger().close_fly(fly))
API::refresh_window(this->handle());
}
pat::cloneable<item_renderer>& ext_renderer() const
{
return this->get_drawer_trigger().ext_renderer();
}
void ext_renderer(const pat::cloneable<item_renderer>& ir)
{
this->get_drawer_trigger().ext_renderer(ir);
}
std::size_t length() const /// Returns the number of items.
{
return this->get_drawer_trigger().length();
}
void push_back(const nana::string& text) /// Append a new item.
{
auto & t = this->get_drawer_trigger();
t.push_back(text, value_type());
API::update_window(*this);
}
void relate(std::size_t pos, window wd) /// Binds a window to an item specified by pos, if the item is selected, shows the window, otherwise, hides it.
{
this->get_drawer_trigger().relate(pos, wd);
}
void tab_bgcolor(std::size_t i, const ::nana::color& clr)
{
this->get_drawer_trigger().tab_color(i, true, clr);
}
void tab_fgcolor(std::size_t i, const ::nana::color& clr)
{
this->get_drawer_trigger().tab_color(i, false, clr);
}
void tab_image(std::size_t i, const nana::paint::image& img)
{
this->get_drawer_trigger().tab_image(i, img);
}
/// Sets buttons of the tabbar's toolbox, refer to notes for more details.
template<typename Add, typename Scroll, typename List, typename Close>
void toolbox(const button_container<Add, Scroll, List, Close>&, bool enable)
{
typedef typename button_container<Add, Scroll, List, Close>::type_set type_set;
auto & tg = this->get_drawer_trigger();
bool redraw = false;
if(type_set::template count<button_add>::value)
redraw |= tg.toolbox_button(tg.ButtonAdd, enable);
if(type_set::template count<button_scroll>::value)
redraw |= tg.toolbox_button(tg.ButtonScroll, enable);
if(type_set::template count<button_list>::value)
redraw |= tg.toolbox_button(tg.ButtonList, enable);
if(type_set::template count<button_close>::value)
redraw |= tg.toolbox_button(tg.ButtonClose, enable);
if(redraw)
API::refresh_window(this->handle());
}
void text(std::size_t pos, const nana::string& str) /// Sets the title of the specified item, If pos is invalid, the method throws an std::out_of_range object.
{
this->get_drawer_trigger().text(pos, str);
}
nana::string text(std::size_t pos) const /// Returns a title of a specified item, If pos is invalid, the method trhows a std::out_of_range object.
{
return this->get_drawer_trigger().text(pos);
}
private:
std::unique_ptr<drawerbase::tabbar::event_agent<value_type, drawerbase::tabbar::trigger> > evt_agent_;
};
}//end namespace nana
namespace nana
{
namespace drawerbase
{
namespace tabbar_lite
{
class model;
struct events
: public general_events
{
basic_event<event_arg> selected;
};
class driver
: public drawer_trigger
{
public:
driver();
~driver();
model* get_model() const throw();
private:
//Overrides drawer_trigger's method
void attached(widget_reference, graph_reference) override;
void refresh(graph_reference) 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;
private:
model* const model_;
};
}
}//end namespace drawerbase
class tabbar_lite
: public widget_object<category::widget_tag, drawerbase::tabbar_lite::driver, drawerbase::tabbar_lite::events>
{
public:
tabbar_lite() = default;
tabbar_lite(window, bool visible = true, const::nana::rectangle& = {});
public: //capacity
std::size_t length() const;
public: //modifiers
void attach(std::size_t pos, window);
window attach(std::size_t pos) const;
void push_back(std::string text, ::nana::any par = {});
void push_front(std::string text, ::nana::any par = {});
std::size_t selected() const;
void erase(std::size_t pos, bool close_attached = true);
};
/*
namespace dev
{
/// Traits for widget classes
template<>
struct widget_traits<tabbar_lite> //deprecated
{
using event_type = drawerbase::tabbar_lite::events;
using scheme_type = ::nana::widget_colors;
};
}
*/
}
#endif