add notify_status for listbox inline widget
This commit is contained in:
parent
07229e566d
commit
d9fb3b3ff9
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Inline Widget Interface Definition
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
* 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
|
||||
@ -35,6 +35,9 @@ namespace nana
|
||||
/// Returns the host widget of the indicator
|
||||
virtual ::nana::widget& host() const = 0;
|
||||
|
||||
/// Returns the position of column
|
||||
virtual std::size_t column() const = 0;
|
||||
|
||||
/// Modifies the value of a item specified by pos
|
||||
virtual void modify(index_type pos, const value_type&) const = 0;
|
||||
|
||||
@ -45,7 +48,7 @@ namespace nana
|
||||
virtual void hovered(index_type) = 0;
|
||||
};
|
||||
|
||||
template<typename Index, typename Value>
|
||||
template<typename Index, typename Status, typename Value>
|
||||
class inline_widget_notifier_interface
|
||||
{
|
||||
public:
|
||||
@ -55,6 +58,9 @@ namespace nana
|
||||
/// A type to the value of the item
|
||||
using value_type = Value;
|
||||
|
||||
/// A type to the status
|
||||
using status_type = Status;
|
||||
|
||||
/// A typedef name of a inline widget indicator
|
||||
using inline_indicator = inline_widget_indicator<index_type, value_type>;
|
||||
|
||||
@ -70,6 +76,9 @@ namespace nana
|
||||
/// A message to activate the inline widget to attach a specified item
|
||||
virtual void activate(inline_indicator&, index_type) = 0;
|
||||
|
||||
/// A message to change the status
|
||||
virtual void notify_status(status_type, bool) = 0;
|
||||
|
||||
/// A message to resize the inline widget
|
||||
virtual void resize(const size&) = 0;
|
||||
|
||||
|
||||
@ -676,8 +676,14 @@ namespace nana
|
||||
|
||||
using index_pairs = ::std::vector<index_pair>;
|
||||
|
||||
using inline_notifier_interface = detail::inline_widget_notifier_interface<index_pair, ::std::string>;
|
||||
enum class inline_widget_status{
|
||||
checked,
|
||||
checking,
|
||||
selected,
|
||||
selecting
|
||||
};
|
||||
|
||||
using inline_notifier_interface = detail::inline_widget_notifier_interface<index_pair, inline_widget_status, ::std::string>;
|
||||
|
||||
// struct essence
|
||||
//@brief: this struct gives many data for listbox,
|
||||
|
||||
@ -678,6 +678,16 @@ namespace nana
|
||||
}
|
||||
};
|
||||
|
||||
struct inline_pane
|
||||
{
|
||||
::nana::panel<false> pane_bottom; //pane for pane_widget
|
||||
::nana::panel<false> pane_widget; //pane for placing user-define widget
|
||||
std::unique_ptr<inline_notifier_interface> inline_ptr;
|
||||
inline_indicator * indicator;
|
||||
index_pair item_pos; //The item index of the inline widget
|
||||
std::size_t column_pos;
|
||||
};
|
||||
|
||||
class es_lister
|
||||
{
|
||||
public:
|
||||
@ -726,6 +736,37 @@ namespace nana
|
||||
|
||||
std::string to_string(const export_options& exp_opt) const;
|
||||
|
||||
inline_pane * get_inline_pane(const index_pair& item_pos)
|
||||
{
|
||||
for (auto p : active_panes_)
|
||||
{
|
||||
if (p && (p->item_pos == item_pos))
|
||||
return p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void emit_checked(index_pair pos)
|
||||
{
|
||||
item_proxy i(ess_, pos);
|
||||
arg_listbox arg{ i };
|
||||
wd_ptr()->events().checked.emit(arg, wd_ptr()->handle());
|
||||
|
||||
auto pane = get_inline_pane(pos);
|
||||
if (pane)
|
||||
pane->inline_ptr->notify_status(inline_widget_status::checking, i.checked());
|
||||
}
|
||||
|
||||
void emit_selected(index_pair pos)
|
||||
{
|
||||
item_proxy i(ess_, pos);
|
||||
arg_listbox arg{ i };
|
||||
wd_ptr()->events().selected.emit(arg, wd_ptr()->handle());
|
||||
|
||||
auto pane = get_inline_pane(pos);
|
||||
if (pane)
|
||||
pane->inline_ptr->notify_status(inline_widget_status::selecting, i.selected());
|
||||
}
|
||||
|
||||
// Definition is provided after struct essence
|
||||
unsigned column_content_pixels(size_type pos) const;
|
||||
@ -1121,6 +1162,14 @@ namespace nana
|
||||
return get(pos.cat)->items.at(index);
|
||||
}
|
||||
|
||||
void append_active_panes(inline_pane* p)
|
||||
{
|
||||
if (nullptr == p)
|
||||
active_panes_.clear();
|
||||
else
|
||||
active_panes_.push_back(p);
|
||||
}
|
||||
|
||||
// Removes all items of a specified category
|
||||
// It throws when the category is out of range or has an immutable model.
|
||||
void clear(size_type cat)
|
||||
@ -1463,9 +1512,7 @@ namespace nana
|
||||
if(m.flags.checked != ck)
|
||||
{
|
||||
m.flags.checked = ck;
|
||||
|
||||
arg_listbox arg{ item_proxy{ess_, pos}};
|
||||
wd_ptr()->events().checked.emit(arg, wd_ptr()->handle());
|
||||
emit_checked(pos);
|
||||
}
|
||||
++pos.item;
|
||||
}
|
||||
@ -1531,8 +1578,7 @@ namespace nana
|
||||
changed = true;
|
||||
m.flags.selected = sel;
|
||||
|
||||
arg_listbox arg{ item_proxy(ess_, i) };
|
||||
wd_ptr()->events().selected.emit(arg, wd_ptr()->handle());
|
||||
this->emit_selected(i);
|
||||
|
||||
if (m.flags.selected)
|
||||
last_selected_abs = i;
|
||||
@ -1622,18 +1668,17 @@ namespace nana
|
||||
return (for_selection ? m.flags.selected : m.flags.checked);
|
||||
};
|
||||
|
||||
auto do_cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos)
|
||||
auto do_cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos)
|
||||
{
|
||||
arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) };
|
||||
if (for_selection)
|
||||
{
|
||||
m.flags.selected = false;
|
||||
widget_->events().selected.emit(arg, widget_->handle());
|
||||
this->emit_selected(item_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.flags.checked = false;
|
||||
widget_->events().checked.emit(arg, widget_->handle());
|
||||
this->emit_checked(item_pos);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1645,7 +1690,7 @@ namespace nana
|
||||
for (auto & m : i->items)
|
||||
{
|
||||
if ((item_pos != except.item) && pred(m))
|
||||
do_cancel(m, except.cat, item_pos);
|
||||
do_cancel(m, index_pair{ except.cat, item_pos });
|
||||
|
||||
++item_pos;
|
||||
}
|
||||
@ -1661,7 +1706,7 @@ namespace nana
|
||||
for (auto & m : cat.items)
|
||||
{
|
||||
if (pred(m))
|
||||
do_cancel(m, cat_pos, item_pos);
|
||||
do_cancel(m, index_pair{ cat_pos, item_pos });
|
||||
++item_pos;
|
||||
}
|
||||
}
|
||||
@ -1671,7 +1716,7 @@ namespace nana
|
||||
for (auto & m : cat.items)
|
||||
{
|
||||
if ((item_pos != except.item) && pred(m))
|
||||
do_cancel(m, cat_pos, item_pos);
|
||||
do_cancel(m, index_pair{ cat_pos, item_pos });
|
||||
++item_pos;
|
||||
}
|
||||
}
|
||||
@ -1705,18 +1750,17 @@ namespace nana
|
||||
return (for_selection ? m.flags.selected : m.flags.checked);
|
||||
};
|
||||
|
||||
auto cancel = [this, for_selection](category_t::container::value_type& m, std::size_t cat_pos, std::size_t item_pos)
|
||||
auto cancel = [this, for_selection](category_t::container::value_type& m, const index_pair& item_pos)
|
||||
{
|
||||
arg_listbox arg{ item_proxy(ess_, index_pair(cat_pos, item_pos)) };
|
||||
if (for_selection)
|
||||
{
|
||||
m.flags.selected = false;
|
||||
widget_->events().selected.emit(arg, widget_->handle());
|
||||
this->emit_selected(item_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.flags.checked = false;
|
||||
widget_->events().checked.emit(arg, widget_->handle());
|
||||
this->emit_checked(item_pos);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1732,7 +1776,7 @@ namespace nana
|
||||
for (auto end = cat.items.end(); i != end; ++i)
|
||||
{
|
||||
if (pred(*i))
|
||||
cancel(*i, cat_pos, i - cat.items.begin());
|
||||
cancel(*i, index_pair{ cat_pos, static_cast<size_type>(i - cat.items.begin()) });
|
||||
}
|
||||
}
|
||||
++cat_pos;
|
||||
@ -1755,7 +1799,7 @@ namespace nana
|
||||
for (++i; i != end; ++i)
|
||||
{
|
||||
if (pred(*i))
|
||||
cancel(*i, cat_pos, i - cat.items.begin());
|
||||
cancel(*i, index_pair{ cat_pos, static_cast<std::size_t>(i - cat.items.begin()) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1767,7 +1811,7 @@ namespace nana
|
||||
for (auto & m : cat.items)
|
||||
{
|
||||
if (pred(m))
|
||||
cancel(m, cat_pos, item_pos);
|
||||
cancel(m, index_pair{ cat_pos, item_pos });
|
||||
|
||||
++item_pos;
|
||||
}
|
||||
@ -1814,10 +1858,7 @@ namespace nana
|
||||
if(m.flags.checked != ck)
|
||||
{
|
||||
m.flags.checked = ck;
|
||||
|
||||
arg_listbox arg{ item_proxy(ess_, index_pair(cat, index)) };
|
||||
wd_ptr()->events().checked.emit(arg, widget_->handle());
|
||||
|
||||
this->emit_checked(index_pair{cat, index});
|
||||
changed = true;
|
||||
}
|
||||
++index;
|
||||
@ -2088,6 +2129,8 @@ namespace nana
|
||||
bool single_selection_category_limited_{ false };
|
||||
bool single_check_{ false };
|
||||
bool single_check_category_limited_{ false };
|
||||
|
||||
std::vector<inline_pane*> active_panes_;
|
||||
};//end class es_lister
|
||||
|
||||
|
||||
@ -2097,6 +2140,8 @@ namespace nana
|
||||
enum class item_state{normal, highlighted, pressed, grabbed, floated};
|
||||
enum class parts{unknown = -1, header, lister, checker};
|
||||
|
||||
using inline_pane = inline_pane;
|
||||
|
||||
::nana::listbox* listbox_ptr{nullptr};
|
||||
::nana::listbox::scheme_type* scheme_ptr{nullptr};
|
||||
::nana::paint::graphics *graph{nullptr};
|
||||
@ -2131,16 +2176,6 @@ namespace nana
|
||||
}scroll;
|
||||
|
||||
|
||||
struct inline_pane
|
||||
{
|
||||
::nana::panel<false> pane_bottom; //pane for pane_widget
|
||||
::nana::panel<false> pane_widget; //pane for placing user-define widget
|
||||
std::unique_ptr<inline_notifier_interface> inline_ptr;
|
||||
inline_indicator * indicator;
|
||||
index_pair item_pos; //The item index of the inline widget
|
||||
std::size_t column_pos;
|
||||
};
|
||||
|
||||
std::map<pat::detail::abstract_factory_base*, std::deque<std::unique_ptr<inline_pane>>> inline_table, inline_buffered_table;
|
||||
|
||||
essence()
|
||||
@ -3010,6 +3045,11 @@ namespace nana
|
||||
return *ess_->lister.wd_ptr();
|
||||
}
|
||||
|
||||
std::size_t column() const override
|
||||
{
|
||||
return column_pos_;
|
||||
}
|
||||
|
||||
void modify(index_type pos, const value_type& value) const override
|
||||
{
|
||||
ess_->lister.throw_if_immutable_model(pos);
|
||||
@ -3533,15 +3573,19 @@ namespace nana
|
||||
public:
|
||||
using item_state = essence::item_state;
|
||||
using parts = essence::parts;
|
||||
using status_type = inline_notifier_interface::status_type;
|
||||
|
||||
drawer_lister_impl(essence * es)
|
||||
:essence_(es)
|
||||
{}
|
||||
|
||||
void draw(const nana::rectangle& rect) const
|
||||
void draw(const nana::rectangle& rect)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
|
||||
//clear active panes
|
||||
essence_->lister.append_active_panes(nullptr);
|
||||
|
||||
//The count of items to be drawn
|
||||
auto item_count = essence_->number_of_lister_items(true);
|
||||
if (0 == item_count)
|
||||
@ -3724,7 +3768,7 @@ namespace nana
|
||||
nana::color bgcolor,
|
||||
nana::color fgcolor,
|
||||
item_state state
|
||||
) const
|
||||
)
|
||||
{
|
||||
auto & item = cat.items[item_pos.item];
|
||||
|
||||
@ -3838,9 +3882,6 @@ namespace nana
|
||||
else
|
||||
visible_state = false;
|
||||
|
||||
::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height };
|
||||
inline_wdg->pane_widget.size(sz);
|
||||
inline_wdg->inline_ptr->resize(sz);
|
||||
|
||||
draw_column = inline_wdg->inline_ptr->whether_to_draw();
|
||||
|
||||
@ -3848,6 +3889,13 @@ namespace nana
|
||||
inline_wdg->column_pos = column_pos;
|
||||
inline_wdg->inline_ptr->activate(*inline_wdg->indicator, item_pos);
|
||||
|
||||
::nana::size sz{ wdg_w, essence_->scheme_ptr->item_height };
|
||||
inline_wdg->pane_widget.size(sz);
|
||||
inline_wdg->inline_ptr->resize(sz);
|
||||
|
||||
inline_wdg->inline_ptr->notify_status(status_type::selected, item.flags.selected);
|
||||
inline_wdg->inline_ptr->notify_status(status_type::checked, item.flags.checked);
|
||||
|
||||
inline_wdg->indicator->attach(item_pos, inline_wdg);
|
||||
|
||||
//To reduce the memory usage, the cells may not be allocated
|
||||
@ -3857,6 +3905,8 @@ namespace nana
|
||||
inline_wdg->inline_ptr->set({});
|
||||
|
||||
API::show_window(inline_wdg->pane_bottom, visible_state);
|
||||
|
||||
essence_->lister.append_active_panes(inline_wdg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4191,14 +4241,12 @@ namespace nana
|
||||
{
|
||||
item_ptr->flags.selected = sel;
|
||||
|
||||
arg_listbox arg{ item_proxy{ essence_, abs_item_pos } };
|
||||
lister.wd_ptr()->events().selected.emit(arg, lister.wd_ptr()->handle());
|
||||
lister.emit_selected(abs_item_pos);
|
||||
|
||||
if (item_ptr->flags.selected)
|
||||
{
|
||||
lister.cancel_others_if_single_enabled(true, abs_item_pos);
|
||||
essence_->lister.last_selected_abs = abs_item_pos;
|
||||
|
||||
}
|
||||
else if (essence_->lister.last_selected_abs == abs_item_pos)
|
||||
essence_->lister.last_selected_abs.set_both(npos);
|
||||
@ -4213,8 +4261,7 @@ namespace nana
|
||||
{
|
||||
item_ptr->flags.checked = ! item_ptr->flags.checked;
|
||||
|
||||
arg_listbox arg{ item_proxy{ essence_, abs_item_pos } };
|
||||
lister.wd_ptr()->events().checked.emit(arg, lister.wd_ptr()->handle());
|
||||
lister.emit_checked(abs_item_pos);
|
||||
|
||||
if (item_ptr->flags.checked)
|
||||
lister.cancel_others_if_single_enabled(false, abs_item_pos);
|
||||
@ -4479,12 +4526,13 @@ namespace nana
|
||||
|
||||
item_proxy & item_proxy::check(bool ck)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto & m = cat_->items.at(pos_.item);
|
||||
if(m.flags.checked != ck)
|
||||
{
|
||||
m.flags.checked = ck;
|
||||
arg_listbox arg{*this};
|
||||
ess_->lister.wd_ptr()->events().checked.emit(arg, ess_->lister.wd_ptr()->handle());
|
||||
ess_->lister.emit_checked(pos_);
|
||||
|
||||
ess_->update();
|
||||
}
|
||||
return *this;
|
||||
@ -4498,13 +4546,14 @@ namespace nana
|
||||
/// is ignored if no change (maybe set last_selected anyway??), but if change emit event, deselect others if need ans set/unset last_selected
|
||||
item_proxy & item_proxy::select(bool s)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
|
||||
//pos_ never represents a category if this item_proxy is available.
|
||||
auto & m = cat_->items.at(pos_.item); // a ref to the real item
|
||||
if(m.flags.selected == s) return *this; // ignore if no change
|
||||
m.flags.selected = s; // actually change selection
|
||||
|
||||
arg_listbox arg{*this};
|
||||
ess_->lister.wd_ptr()->events().selected.emit(arg, ess_->lister.wd_ptr()->handle());
|
||||
ess_->lister.emit_selected(this->pos_);
|
||||
|
||||
if (m.flags.selected)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user