construct the inline widget for listbox

This commit is contained in:
Jinhao 2015-06-14 21:48:35 +08:00
parent 36b3e6e6cc
commit 1822fafd79
15 changed files with 472 additions and 179 deletions

View File

@ -115,6 +115,8 @@ namespace detail
bool belong_to_lazy() const;
bool is_draw_through() const; ///< Determines whether it is a draw-through window.
basic_window * seek_non_lite_widget_ancestor() const;
public:
//Override event_holder
bool set_events(const std::shared_ptr<general_events>&) override;

View File

@ -40,6 +40,8 @@ namespace detail
struct thread_context;
class flag_guard;
~bedrock();
void pump_event(window, bool is_modal);
void map_thread_root_buffer(core_window_t*, bool forced);

View File

@ -116,6 +116,7 @@ namespace API
void window_icon(window, const paint::image&);
bool empty_window(window); ///< Determines whether a window is existing.
bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window.
bool is_destroying(window); ///< Determines whether a window is destroying
void enable_dropfiles(window, bool);
/// \brief Retrieves the native window of a Nana.GUI window.

View File

@ -0,0 +1,52 @@
/**
* A Inline Widget Interface Definition
* 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/detail/inline_widget.hpp
*
*/
#ifndef NANA_GUI_INLINE_WIDGETS_HPP
#define NANA_GUI_INLINE_WIDGETS_HPP
#include "../../basis.hpp"
namespace nana
{
namespace detail
{
template<typename Index, typename Value>
class inline_widget_indicator
{
public:
using index_type = Index;
using value_type = Value;
virtual ~inline_widget_indicator() = default;
private:
virtual void modify(index_type, const value_type&) const = 0;
};
template<typename Index, typename Value>
class inline_widget_interface
{
public:
using index_type = Index;
using value_type = Value;
using inline_indicator = inline_widget_indicator<index_type, value_type>;
using factory_interface = inline_widget_interface;
virtual ~inline_widget_interface() = default;
virtual void create(window) = 0;
virtual void activate(inline_indicator&, index_type) = 0;
virtual void resize(const size&) = 0;
virtual void set(const value_type&) = 0;
};
}
}
#endif

View File

@ -0,0 +1,89 @@
/**
* A Inline Widget Manager 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/detail/inline_widget_manager.hpp
*
*/
#ifndef NANA_GUI_INLINE_WIDGET_MANAGER_HPP
#define NANA_GUI_INLINE_WIDGET_MANAGER_HPP
#include "inline_widget.hpp"
#include <nana/pat/abstract_factory.hpp>
#include "../panel.hpp"
#include <vector>
namespace nana
{
namespace detail
{
template<typename Index, typename Value>
class inline_widget_manager
{
using index_type = Index;
using value_type = Value;
using indicator_type = inline_widget_indicator<value_type>;
using inline_widget = inline_widget_interface<index_type, value_type>;
using factory = pat::abstract_factory<inline_widget>;
struct widget_holder
{
panel<false> docker;
std::unique_ptr<inline_widget> widget_ptr;
};
public:
void set_window(window wd)
{
window_handle_ = wd;
}
void set_factory(std::unique_ptr<factory> fac)
{
factory_.swap(fac);
}
void place(point pos, const size& dimension, const size & visible_size, const indicator_type& indicator, index_type index)
{
auto holder = _m_append();
holder->docker.move({ pos, visible_size });
holder->widget_ptr->move({ point(), dimension });
holder->widget_ptr->activate(indicator, index);
}
private:
widget_holder* _m_append()
{
if (swap_widgets_.empty())
{
widgets_.emplace_back();
widgets_.back().swap(swap_widgets_.back());
swap_widgets_.pop_back();
}
else
{
widgets_.emplace_back(new widget_holder);
auto & holder = widgets_.back();
holder->docker.create(window_handle_, false);
holder->widget_ptr.swap(factory_->create());
holder->widget_ptr->create(holder->docker->handle());
}
return widgets_.back().get();
}
private:
window window_handle_{nullptr};
std::unique_ptr<factory> factory_;
std::vector<std::unique_ptr<widget_holder>> widgets_;
std::vector<std::unique_ptr<widget_holder>> swap_widgets_;
};
}
}
#endif

View File

@ -15,9 +15,10 @@
#ifndef NANA_GUI_WIDGETS_LISTBOX_HPP
#define NANA_GUI_WIDGETS_LISTBOX_HPP
#include "widget.hpp"
#include "detail/inline_widget.hpp"
#include <nana/pat/abstract_factory.hpp>
#include <nana/concepts.hpp>
#include <nana/key_type.hpp>
//#include <nana/paint/graphics.hpp>
#include <functional>
#include <initializer_list>
@ -29,7 +30,58 @@ namespace nana
{
namespace listbox
{
using size_type = std::size_t ;
using size_type = std::size_t;
/// usefull for both absolute and display (sorted) positions
struct index_pair
{
size_type cat; //The pos of category
size_type item; //the pos of item in a category.
index_pair(size_type cat_pos = 0, size_type item_pos = 0)
: cat(cat_pos),
item(item_pos)
{}
bool empty() const
{
return (npos == cat);
}
void set_both(size_type n)
{
cat = item = n;
}
bool is_category() const
{
return (npos != cat && npos == item);
}
bool is_item() const
{
return (npos != cat && npos != item);
}
bool operator==(const index_pair& r) const
{
return (r.cat == cat && r.item == item);
}
bool operator!=(const index_pair& r) const
{
return !this->operator==(r);
}
bool operator>(const index_pair& r) const
{
return (cat > r.cat) || (cat == r.cat && item > r.item);
}
};
using selection = std::vector<index_pair>;
using inline_interface = detail::inline_widget_interface<index_pair, std::wstring>;
struct cell
{
@ -114,55 +166,6 @@ namespace nana
std::size_t pos_{0};
};
/// usefull for both absolute and display (sorted) positions
struct index_pair
{
size_type cat; //The pos of category
size_type item; //the pos of item in a category.
index_pair(size_type cat_pos = 0, size_type item_pos = 0)
: cat(cat_pos),
item(item_pos)
{}
bool empty() const
{
return (npos == cat);
}
void set_both(size_type n)
{
cat = item = n;
}
bool is_category() const
{
return (npos != cat && npos == item);
}
bool is_item() const
{
return (npos != cat && npos != item);
}
bool operator==(const index_pair& r) const
{
return (r.cat == cat && r.item == item);
}
bool operator!=(const index_pair& r) const
{
return !this->operator==(r);
}
bool operator>(const index_pair& r) const
{
return (cat > r.cat) || (cat == r.cat && item > r.item);
}
};
typedef std::vector<index_pair> selection;
//struct essence_t
//@brief: this struct gives many data for listbox,
// the state of the struct does not effect on member funcions, therefore all data members are public.
@ -344,6 +347,8 @@ namespace nana
: public std::iterator < std::input_iterator_tag, cat_proxy >
{
public:
using inline_interface = drawerbase::listbox::inline_interface;
cat_proxy() = default;
cat_proxy(essence_t*, size_type pos);
cat_proxy(essence_t*, category_t*);
@ -423,6 +428,8 @@ namespace nana
/// Behavior of Iterator
bool operator!=(const cat_proxy&) const;
void inline_factory(size_type column, pat::cloneable<pat::abstract_factory<inline_interface>> factory);
private:
void _m_append(std::vector<cell> && cells);
void _m_cat_by_pos();
@ -499,6 +506,7 @@ By \a clicking on a header the list get \a reordered, first up, and then down al
using cell = drawerbase::listbox::cell;
using export_options= drawerbase::listbox::export_options;
using columns_indexs= drawerbase::listbox::size_type;
using inline_interface = drawerbase::listbox::inline_interface;
public:
listbox() = default;
listbox(window, bool visible);

View File

@ -19,16 +19,15 @@
namespace nana
{
template<bool Vert> class scroll;
template<bool Vert> class scroll; //forward declaration
template<bool Vert>
struct arg_scroll
: public event_arg
{
scroll<Vert> & widget;
window window_handle;
arg_scroll(scroll<Vert> & wdg)
: widget(wdg)
arg_scroll(window wd)
: window_handle{ wd }
{}
};
@ -36,11 +35,10 @@ namespace nana
{
namespace scroll
{
template<bool Vert>
struct scroll_events
: public general_events
{
basic_event<arg_scroll<Vert>> value_changed;
basic_event<arg_scroll> value_changed;
};
enum class buttons
@ -313,7 +311,7 @@ namespace nana
private:
void _m_emit_value_changed()
{
widget_->events().value_changed.emit(::nana::arg_scroll<Vertical>(*widget_));
widget_->events().value_changed.emit({ widget_->handle() });
}
void _m_tick()
@ -335,7 +333,7 @@ namespace nana
/// Provides a way to display an object which is larger than the window's client area.
template<bool Vertical>
class scroll // add a widget scheme?
: public widget_object<category::widget_tag, drawerbase::scroll::trigger<Vertical>, drawerbase::scroll::scroll_events<Vertical>>
: public widget_object<category::widget_tag, drawerbase::scroll::trigger<Vertical>, drawerbase::scroll::scroll_events>
{
typedef widget_object<category::widget_tag, drawerbase::scroll::trigger<Vertical> > base_type;
public:
@ -448,7 +446,6 @@ namespace nana
{
return this->make_step(forward, range() - 1);
}
};//end class scroll
}//end namespace nana
#endif

View File

@ -0,0 +1,52 @@
/*
* A Generic Abstract Factory Pattern Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 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/pat/abstract_factory.hpp
* @description: A generic easy-to-use abstract factory pattern implementation
*/
#ifndef NANA_PAT_ABSFACTORY_HPP
#define NANA_PAT_ABSFACTORY_HPP
#include <memory>
namespace nana
{
namespace pat
{
template<typename Interface>
class abstract_factory
{
public:
using interface_type = Interface;
virtual ~abstract_factory() = default;
virtual std::unique_ptr<interface_type> create() = 0;
};
namespace detail
{
template<typename T, typename Interface>
class abs_factory
: public abstract_factory<Interface>
{
std::unique_ptr<Interface> create() override
{
return std::unique_ptr<Interface>{ new T };
}
};
}//end namespace detail
template<typename Type>
pat::cloneable<abstract_factory<typename Type::factory_interface>> make_factory()
{
return detail::abs_factory<Type, typename Type::factory_interface>();
}
}//end namespace pat
}//end namespace nana
#endif

View File

@ -298,6 +298,15 @@ namespace nana
return false;
}
basic_window * basic_window::seek_non_lite_widget_ancestor() const
{
auto anc = this->parent;
while (anc && (category::flags::lite_widget == anc->other.category))
anc = anc->parent;
return anc;
}
void basic_window::_m_init_pos_and_size(basic_window* parent, const rectangle& r)
{
pos_owner = pos_root = r;

View File

@ -64,6 +64,26 @@ namespace nana
bedrock::instance().evt_operation.cancel(evt);
}
class bedrock::flag_guard
{
public:
flag_guard(bedrock* brock, core_window_t * wd)
: brock_{ brock }, wd_(wd)
{
wd_->flags.refreshing = true;
}
~flag_guard()
{
if (brock_->wd_manager.available((wd_)))
wd_->flags.refreshing = false;
}
private:
bedrock *const brock_;
core_window_t *const wd_;
};
void bedrock::event_expose(core_window_t * wd, bool exposed)
{
if (nullptr == wd) return;
@ -79,11 +99,8 @@ namespace nana
{
if (category::flags::root != wd->other.category)
{
//If the wd->parent is a lite_widget then find a parent until it is not a lite_widget
wd = wd->parent;
while (category::flags::lite_widget == wd->other.category)
wd = wd->parent;
//find an ancestor until it is not a lite_widget
wd = wd->seek_non_lite_widget_ancestor();
}
else if (category::flags::frame == wd->other.category)
wd = wd_manager.find_window(wd->root, wd->pos_root.x, wd->pos_root.y);
@ -162,6 +179,9 @@ namespace nana
auto retain = wd->together.events_ptr;
auto evts_ptr = retain.get();
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
switch (evt_code)
{
case event_code::click:
@ -214,9 +234,9 @@ namespace nana
}
(wd->drawer.*drawer_event_fn)(*arg);
if (!draw_only)
evt_addr->emit(*arg);
break;
}
case event_code::mouse_wheel:

View File

@ -1473,9 +1473,7 @@ namespace detail
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore not decleared
}
brock.wd_manager.destroy(msgwnd);
nana::detail::platform_spec::instance().release_window_icon(msgwnd->root);
break;
case WM_NCDESTROY:

View File

@ -1,7 +1,7 @@
/*
* Window Layout Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
* 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
@ -24,12 +24,14 @@ namespace nana
//class window_layout
void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed)
{
if (wd->flags.refreshing)
return;
if (nullptr == wd->effect.bground)
{
if (is_redraw)
{
if (wd->flags.refreshing) return;
wd->flags.refreshing = true;
wd->drawer.refresh();
wd->flags.refreshing = false;
@ -42,6 +44,10 @@ namespace nana
bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool is_child_refreshed)
{
auto check_opaque = wd->seek_non_lite_widget_ancestor();
if (check_opaque && check_opaque->flags.refreshing)
return true;
nana::rectangle vr;
if (read_visual_rectangle(wd, vr))
{

View File

@ -1333,14 +1333,16 @@ namespace detail
delete wd->together.caret;
wd->together.caret = nullptr;
}
arg_destroy arg;
arg.window_handle = reinterpret_cast<window>(wd);
brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context());
//Delete the children widgets.
for (auto i = wd->children.rbegin(), end = wd->children.rend(); i != end; ++i)
_m_destroy(*i);
wd->children.clear();
arg_destroy arg;
arg.window_handle = reinterpret_cast<window>(wd);
brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context());
_m_disengage(wd, nullptr);
wndlayout_type::enable_effects_bground(wd, false);

View File

@ -374,6 +374,16 @@ namespace API
return restrict::window_manager.available(reinterpret_cast<restrict::core_window_t*>(wd));
}
bool is_destroying(window wd)
{
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
internal_scope_guard lock;
if (!restrict::window_manager.available(iwd))
return false;
return iwd->flags.destroying;
}
void enable_dropfiles(window wd, bool enb)
{
internal_scope_guard lock;
@ -534,12 +544,9 @@ namespace API
internal_scope_guard lock;
if(restrict::window_manager.move(iwd, x, y, false))
{
if(category::flags::root != iwd->other.category)
{
do{
iwd = iwd->parent;
} while (category::flags::lite_widget == iwd->other.category);
}
if (category::flags::root != iwd->other.category)
iwd = iwd->seek_non_lite_widget_ancestor();
restrict::window_manager.update(iwd, false, false);
}
}
@ -551,11 +558,8 @@ namespace API
if(restrict::window_manager.move(iwd, r))
{
if (category::flags::root != iwd->other.category)
{
do{
iwd = iwd->parent;
} while (category::flags::lite_widget == iwd->other.category);
}
iwd = iwd->seek_non_lite_widget_ancestor();
restrict::window_manager.update(iwd, false, false);
}
}
@ -624,11 +628,8 @@ namespace API
if(restrict::window_manager.size(iwd, sz, false, false))
{
if (category::flags::root != iwd->other.category)
{
do{
iwd = iwd->parent;
} while (category::flags::lite_widget == iwd->other.category);
}
iwd = iwd->seek_non_lite_widget_ancestor();
restrict::window_manager.update(iwd, false, false);
}
}

View File

@ -13,6 +13,7 @@
#include <nana/gui/widgets/listbox.hpp>
#include <nana/gui/widgets/scroll.hpp>
#include <nana/gui/widgets/panel.hpp>
#include <nana/gui/layout_utility.hpp>
#include <nana/gui/element.hpp>
@ -408,9 +409,6 @@ namespace nana
void item_width(size_type pos, unsigned width)
{
if (pos >= cont_.size())
return;
for(auto & m : cont_)
{
if(m.index == pos)
@ -661,6 +659,8 @@ namespace nana
//A cat may have a key object to identify the category
std::shared_ptr<nana::detail::key_interface> key_ptr;
std::deque<pat::cloneable<pat::abstract_factory<inline_interface>>> factories;
category_t() = default;
category_t(nana::string str)
@ -946,9 +946,15 @@ namespace nana
return _m_at(pos.cat)->items.at(index);
}
const category_t::container::value_type& at(const index_pair& pos) const
{
return at(pos);
auto index = pos.item;
if (sorted_index_ != npos)
index = absolute(pos);
return _m_at(pos.cat)->items.at(index);
}
void clear(size_type cat)
@ -1879,6 +1885,7 @@ namespace nana
bool single_check_category_limited_{ false };
};//end class es_lister
//struct essence_t
//@brief: this struct gives many data for listbox,
// the state of the struct does not effect on member funcions, therefore all data members are public.
@ -1887,6 +1894,23 @@ namespace nana
enum class item_state{normal, highlighted, pressed, grabbed, floated};
enum class parts{unknown = -1, header, lister, checker};
class inline_indicator
: public ::nana::detail::inline_widget_indicator<index_pair, std::wstring>
{
public:
inline_indicator(essence_t* ess)
: ess_{ess}
{
}
void modify(index_type pos, const value_type& value) const override
{
ess_->lister.at(pos).cells;
}
private:
essence_t * const ess_;
};
::nana::listbox::scheme_type* scheme_ptr{nullptr};
::nana::paint::graphics *graph{nullptr};
bool auto_draw{true};
@ -1923,6 +1947,15 @@ namespace nana
nana::scroll<false> h;
}scroll;
struct inline_pane
{
::nana::panel<false> pane;
std::unique_ptr<inline_interface> inline_ptr;
};
std::map<void*, std::deque<std::unique_ptr<inline_pane>>> inline_table, inline_buffered_table;
essence_t()
{
scroll.offset_x = 0;
@ -2107,11 +2140,11 @@ namespace nana
{
scroll.h.create(wd, r);
API::take_active(scroll.h.handle(), false, wd);
scroll.h.events().mouse_move.connect_unignorable([this](const nana::arg_mouse& arg){
_m_answer_scroll(arg);
});
scroll.h.events().mouse_up.connect_unignorable([this](const nana::arg_mouse& arg){
_m_answer_scroll(arg);
scroll.h.events().value_changed.connect_unignorable([this](const ::nana::arg_scroll& arg)
{
scroll.offset_x = static_cast<int>(scroll.h.value());
API::refresh_window(this->lister.wd_ptr()->handle());
});
}
else
@ -2126,13 +2159,20 @@ namespace nana
if(scroll.v.empty())
{
scroll.v.create(wd, r);
API::take_active(scroll.v.handle(), false, wd); // install value_changed() not mouse_move ????
API::take_active(scroll.v.handle(), false, wd);
scroll.v.events().value_changed([this](const ::nana::arg_scroll<true>& arg)
scroll.v.events().value_changed([this](const ::nana::arg_scroll& arg)
{
_m_answer_scroll_value(arg);
});
index_pair item;
if (!lister.forward(item, scroll.v.value(), item)) return;
if (item == scroll.offset_y_dpl)
return;
set_scroll_y_dpl(item);
API::refresh_window(this->lister.wd_ptr()->handle());
});
}
else
scroll.v.move(r);
@ -2141,7 +2181,7 @@ namespace nana
else if(!scroll.v.empty())
{
scroll.v.close();
set_scroll_y_dpl({0,0}); // scroll.offset_y.set_both(0);
set_scroll_y_dpl({0,0});
nana::rectangle r;
if(rect_header(r))
@ -2311,63 +2351,43 @@ namespace nana
for(const auto& hd : header.cont())
{
if(false == hd.visible) continue;
x += hd.pixels;
x += static_cast<int>(hd.pixels);
if(x > 0)
seqs.push_back(hd.index);
if(x >= static_cast<int>(lister_w))
break;
}
}
private:
void _m_answer_scroll(const arg_mouse& arg)
{
if(arg.evt_code == event_code::mouse_move && arg.left_button == false) return;
bool update = false;
if(arg.window_handle == scroll.v.handle())
inline_pane * open_inline(pat::abstract_factory<inline_interface>* factory)
{
std::unique_ptr<inline_pane> pane_ptr;
auto i = inline_buffered_table.find(factory);
if (i != inline_buffered_table.end())
{
index_pair item;
if(lister.forward(item, scroll.v.value(), item))
{
if (item != scroll.offset_y_dpl)
{
set_scroll_y_dpl ( item );
update = true;
}
}
}
else if(arg.window_handle == scroll.h.handle())
{
if(scroll.offset_x != static_cast<int>(scroll.h.value()))
{
scroll.offset_x = static_cast<int>(scroll.h.value());
update = true;
}
if (!i->second.empty())
pane_ptr = std::move(i->second.front());
}
if(update)
API::refresh_window(lister.wd_ptr()->handle());
if (!pane_ptr)
{
pane_ptr.reset(new inline_pane);
pane_ptr->pane.create(this->lister.wd_ptr()->handle());
pane_ptr->inline_ptr = factory->create();
pane_ptr->inline_ptr->create(pane_ptr->pane);
}
auto ptr = pane_ptr.get();
inline_table[factory].emplace_back(std::move(pane_ptr));
return ptr;
}
void _m_answer_scroll_value(const ::nana::arg_scroll<true>& arg)
{
index_pair item;
if( !lister.forward(item, scroll.v.value(), item)) return;
if (item == scroll.offset_y_dpl)
return;
set_scroll_y_dpl ( item );
API::refresh_window(lister.wd_ptr()->handle());
}
};
};
void es_lister::scroll_refresh()
{
ess_->scroll_y_dpl_refresh();
}
void es_lister::move_select(bool upwards, bool unselect_previous, bool trace_selected)
{
auto next_selected_dpl = relative_pair ( last_selected_abs); // last_selected_dpl; // ??
@ -2709,8 +2729,6 @@ namespace nana
void draw(const nana::rectangle& rect) const
{
// essence_->scroll_y_dpl_refresh() ; // ????
internal_scope_guard lock;
size_type n = essence_->number_of_lister_items(true);
@ -2752,6 +2770,8 @@ namespace nana
auto state = item_state::normal;
essence_->inline_buffered_table.swap(essence_->inline_table);
//Here we draw the root categ (0) or a first item if the first drawing is not a categ.(item!=npos))
if(idx.cat == 0 || !idx.is_category())
{
@ -2767,7 +2787,7 @@ namespace nana
if(n-- == 0) break;
state = (tracker == idx ? item_state::highlighted : item_state::normal);
_m_draw_item(i_categ->items[lister.absolute(index_pair(idx.cat, offs)) ], x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state);
_m_draw_item(*i_categ, i_categ->items[lister.absolute(index_pair(idx.cat, offs)) ], x, y, txtoff, header_w, rect, subitems, bgcolor,fgcolor, state);
y += essence_->item_size;
}
@ -2794,12 +2814,14 @@ namespace nana
if(n-- == 0) break;
state = (idx == tracker ? item_state::highlighted : item_state::normal);
_m_draw_item(i_categ->items[ lister.absolute(index_pair(idx.cat, pos))], x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state);
_m_draw_item(*i_categ, i_categ->items[ lister.absolute(index_pair(idx.cat, pos))], x, y, txtoff, header_w, rect, subitems, bgcolor, fgcolor, state);
y += essence_->item_size;
++idx.item;
}
}
essence_->inline_buffered_table.clear();
if (y < rect.y + static_cast<int>(rect.height))
{
essence_->graph->set_color(bgcolor);
@ -2848,7 +2870,7 @@ namespace nana
}
}
void _m_draw_item(const item_t& item, int x, int y, int txtoff, unsigned width, const nana::rectangle& r, const std::vector<size_type>& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const
void _m_draw_item(const category_t& cat, const item_t& item, const int x, const int y, const int txtoff, unsigned width, const nana::rectangle& r, const std::vector<size_type>& seqs, nana::color bgcolor, nana::color fgcolor, item_state state) const
{
if (item.flags.selected) // fetch the "def" colors
bgcolor = essence_->scheme_ptr->item_selected;
@ -2858,7 +2880,6 @@ namespace nana
if(!item.fgcolor.invisible())
fgcolor = item.fgcolor;
auto graph = essence_->graph;
if (item_state::highlighted == state) // and blend it if "highlighted"
{
if (item.flags.selected)
@ -2870,6 +2891,7 @@ namespace nana
unsigned show_w = width - essence_->scroll.offset_x;
if(show_w >= r.width) show_w = r.width;
auto graph = essence_->graph;
//draw the background
graph->set_color(bgcolor);
graph->rectangle(rectangle{ r.x, y, show_w, essence_->item_size }, true);
@ -2878,12 +2900,11 @@ namespace nana
unsigned extreme_text = x;
bool first = true;
for(size_type display_order{0}; display_order < seqs.size(); ++display_order) // get the cell (column) index in the order headers are displayed
for (size_type display_order{ 0 }; display_order < seqs.size(); ++display_order) // get the cell (column) index in the order headers are displayed
{
auto index = seqs[display_order];
const auto & header = essence_->header.column(index); // deduce the corresponding header which is in a kind of dislay order
auto it_bgcolor = bgcolor;
const auto & header = essence_->header.column(index); // deduce the corresponding header which is in a kind of dislay order
auto it_bgcolor = bgcolor;
if ((item.cells.size() > index) && (header.pixels > 5)) // process only if the cell is visible
{
@ -2893,27 +2914,28 @@ namespace nana
if (m_cell.custom_format && (!m_cell.custom_format->bgcolor.invisible())) // adapt to costum format if need
{
it_bgcolor = m_cell.custom_format->bgcolor;
if (item.flags.selected)
it_bgcolor = it_bgcolor.blend( bgcolor , 0.5) ;
it_bgcolor = m_cell.custom_format->bgcolor;
if (item.flags.selected)
it_bgcolor = it_bgcolor.blend(bgcolor, 0.5);
if (item_state::highlighted == state)
it_bgcolor = it_bgcolor.blend(::nana::color(0x99, 0xde, 0xfd), 0.8);
graph->set_color(it_bgcolor);
it_bgcolor = it_bgcolor.blend(static_cast<color_rgb>(0x99defd), 0.8);
graph->set_color(it_bgcolor);
graph->rectangle(rectangle{ item_xpos, y, header.pixels, essence_->item_size }, true);
cell_txtcolor = m_cell.custom_format->fgcolor;
}
int ext_w = 5;
if(first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?)
if (first && essence_->checkable) // draw the checkbox if need, only before the first column (display_order=0 ?)
{
ext_w += 18;
element_state estate = element_state::normal;
if(essence_->pointer_where.first == parts::checker)
if (essence_->pointer_where.first == parts::checker)
{
switch(state)
switch (state)
{
case item_state::highlighted:
estate = element_state::hovered; break;
@ -2924,7 +2946,7 @@ namespace nana
}
using state = facade<element::crook>::state;
crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked);
crook_renderer_.check(item.flags.checked ? state::checked : state::unchecked);
crook_renderer_.draw(*graph, bgcolor, fgcolor, essence_->checkarea(item_xpos, y), estate);
}
@ -2933,7 +2955,7 @@ namespace nana
if (item.img)
{
nana::rectangle img_r(item.img_show_size);
img_r.x = static_cast<int>(ext_w) + item_xpos + static_cast<int>(16 - item.img_show_size.width) / 2;
img_r.x = static_cast<int>(ext_w)+item_xpos + static_cast<int>(16 - item.img_show_size.width) / 2;
img_r.y = y + static_cast<int>(essence_->item_size - item.img_show_size.height) / 2;
item.img.stretch(item.img.size(), *graph, img_r);
}
@ -2946,27 +2968,34 @@ namespace nana
if (ts.width + ext_w > header.pixels) // it was an excess
{
//The text is painted over the next subitem // here beging the ...
int xpos = item_xpos + static_cast<int>(header.pixels) - static_cast<int>(essence_->suspension_width);
int xpos = item_xpos + static_cast<int>(header.pixels) - static_cast<int>(essence_->suspension_width);
graph->set_color(it_bgcolor); // litter rect with the item bg end ...
graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true);
graph->set_text_color(cell_txtcolor);
graph->rectangle(rectangle{ xpos, y + 2, essence_->suspension_width, essence_->item_size - 4 }, true);
graph->string(point{ xpos, y + 2 }, STR("..."));
//Erase the part that over the next subitem.
if ( display_order + 1 < seqs.size() ) // this is not the last column
{
graph->set_color(bgcolor); // we need to erase the excess, because some cell may not draw text over
graph->rectangle(rectangle{item_xpos + static_cast<int>(header.pixels), y + 2,
ts.width + ext_w - header.pixels, essence_->item_size - 4}, true);
}
extreme_text = std::max (extreme_text, item_xpos + ext_w + ts.width);
if (display_order + 1 < seqs.size()) // this is not the last column
{
graph->set_color(bgcolor); // we need to erase the excess, because some cell may not draw text over
graph->rectangle(rectangle{ item_xpos + static_cast<int>(header.pixels), y + 2,
ts.width + ext_w - header.pixels, essence_->item_size - 4 }, true);
}
extreme_text = std::max(extreme_text, item_xpos + ext_w + ts.width);
}
}
graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast<int>(essence_->item_size) - 1 }, { 0xEB, 0xF4, 0xF9 });
graph->line({ item_xpos - 1, y }, { item_xpos - 1, y + static_cast<int>(essence_->item_size) - 1 }, static_cast<color_rgb>(0xEBF4F9));
item_xpos += header.pixels;
auto inline_wdg = _m_get_pane(cat, index);
if (inline_wdg)
{
inline_wdg->pane.move({ item_xpos, y, header.pixels, essence_->item_size });
inline_wdg->inline_ptr->resize({ header.pixels, essence_->item_size });
//inline_wdg->inline_ptr->activate()
}
item_xpos += static_cast<int>(header.pixels);
if (display_order + 1 >= seqs.size() && static_cast<int>(extreme_text) > item_xpos)
{
graph->set_color(item.bgcolor);
@ -2980,6 +3009,17 @@ namespace nana
_m_draw_border(r.x, y, show_w);
}
essence_t::inline_pane * _m_get_pane(const category_t& cat, std::size_t pos) const
{
if (pos < cat.factories.size())
{
auto & factory = cat.factories[pos];
if (factory)
return essence_->open_inline(factory.get());
}
return nullptr;
}
void _m_draw_border(int x, int y, unsigned width) const
{
//Draw selecting inner rectangle
@ -3024,6 +3064,9 @@ namespace nana
void trigger::draw()
{
if (API::is_destroying(essence_->lister.wd_ptr()->handle()))
return;
nana::rectangle r;
if(essence_->header.visible() && essence_->rect_header(r))
@ -3890,6 +3933,17 @@ namespace nana
return ! this->operator==(r);
}
void cat_proxy::inline_factory(size_type column, pat::cloneable<pat::abstract_factory<inline_interface>> factory)
{
if (column >= ess_->header.cont().size())
throw std::out_of_range("listbox.cat_proxy.inline_factory: invalid column index");
if (column >= cat_->factories.size())
cat_->factories.resize(column + 1);
cat_->factories[column] = std::move(factory);
}
void cat_proxy::_m_append(std::vector<cell> && cells)
{
//check invalid cells