Merge branch 'hotfixes-1.0.2' into develop

Conflicts:
	include/nana/gui/detail/basic_window.hpp
	include/nana/gui/widgets/listbox.hpp
	source/gui/detail/linux_X11/bedrock.cpp
	source/gui/detail/win32/bedrock.cpp
	source/gui/detail/window_layout.cpp
	source/gui/detail/window_manager.cpp
	source/gui/widgets/listbox.cpp
	source/gui/widgets/toolbar.cpp
This commit is contained in:
Jinhao
2015-07-11 13:35:22 +08:00
43 changed files with 2614 additions and 760 deletions

View File

@@ -151,7 +151,7 @@ namespace nana{ namespace drawerbase
void trigger::key_char(graph_reference, const arg_keyboard& arg)
{
if(arg.key == static_cast<char_t>(keyboard::enter))
if (static_cast<char_t>(keyboard::enter) == arg.key || static_cast<char_t>(keyboard::space) == arg.key)
emit_click();
}

View File

@@ -18,6 +18,8 @@
#include <nana/gui/widgets/skeletons/text_editor.hpp>
#include <nana/gui/widgets/skeletons/textbase_export_interface.hpp>
#include <iterator>
namespace nana
{
arg_combox::arg_combox(combox& wdg): widget(wdg)

View File

@@ -402,18 +402,20 @@ namespace nana
return{};
}
void create(nana::string&& text, unsigned pixels)
size_type create(nana::string&& text, unsigned pixels)
{
cont_.emplace_back(std::move(text), pixels, static_cast<size_type>(cont_.size()));
return cont_.back().index;
}
void item_width(size_type pos, unsigned width)
{
for(auto & m : cont_)
{
if(m.index == pos)
{
m.pixels = width;
}
return;
}
}
unsigned item_width(size_type pos) const
@@ -1606,31 +1608,7 @@ namespace nana
}
/// set all items in cat to selection sel, emiting events, actualizing last_selected_abs, but not check for single_selection_
bool categ_selected(size_type cat, bool sel)
{
bool changed = false;
auto & items = _m_at(cat)->items;
index_pair pos(cat, 0);
for(auto & m : items)
{
if(m.flags.selected != sel)
{
m.flags.selected = sel;
arg_listbox arg{ item_proxy(ess_, pos), sel };
wd_ptr()->events().selected.emit(arg);
changed = true;
if (sel) // not check for single_selection_
last_selected_abs = pos;
else if (last_selected_abs == pos)
last_selected_abs.set_both(npos);
}
++pos.item;
}
return changed;
}
void categ_selected(size_type cat, bool sel);
void reverse_categ_selected(size_type categ)
{
@@ -1658,9 +1636,22 @@ namespace nana
/// absolute position of the last displayed item
index_pair last_displ() const
{
return absolute ( last_displ() );
return absolute ( last() );
}
/// can be used as the absolute position of the first absolute item, or as the display pos of the first displayed item
index_pair first() const
{
index_pair fst{0,npos};
good_item(fst,fst);
return fst;
}
/// absolute position of the first displayed item
index_pair first_displ() const
{
return absolute ( first() );
}
bool good(size_type cat) const
{
return (cat < list_.size());
@@ -1670,32 +1661,32 @@ namespace nana
{
return ((pos.cat < list_.size()) && (pos.item < size_item(pos.cat)));
}
/// if good return the same item (in arg item), or just the next cat and true, but If fail return false
bool good_item(index_pair pos, index_pair& item) const
{
if (!good(pos.cat))
return false;
return false; // cat out of range
if (pos.is_category())
{
item = pos;
if (0 == pos.cat)
item.item = 0;
return true;
item = pos; // return the cat self
if (0 == pos.cat) // but for cat 0 return first item
item.item = 0; // let check this is good
else
return true;
}
auto i = _m_at(pos.cat);
auto i = _m_at(pos.cat); // pos is not a cat and i point to it cat
if (pos.item < i->items.size())
{
item = pos;
item = pos; // good item, return it
return true;
}
if (++i == list_.end())
if (++i == list_.end()) // item out of range and no more cat
return false;
item.cat = pos.cat + 1;
item.cat = pos.cat + 1; // select the next cat
item.item = npos;
return true;
}
@@ -1703,7 +1694,7 @@ namespace nana
///Translate relative position (position in display) into absolute position (original data order)
size_type absolute(const index_pair& display_pos) const
{
if(sorted_index_ == npos)
if(sorted_index_ == npos || display_pos.item == npos)
return display_pos.item ;
auto & catobj = *_m_at(display_pos.cat);
@@ -2202,7 +2193,7 @@ namespace nana
}
else
{
new_where.second = (y - header_visible_px() + 1) / item_size;
new_where.second = ((y + 1) - header_visible_px()) / item_size; // y>1 !
new_where.first = parts::lister;
if(checkable)
{
@@ -2324,6 +2315,27 @@ namespace nana
}
}
unsigned auto_width(size_type pos, unsigned max = 3000) /// \todo introduce parametr max_header_width
{
unsigned max_w{ 0 };
for (const auto &cat : lister.cat_container())
for (const auto &it : cat.items)
{
if (pos >= it.cells.size()) continue;
// precalcule text geometry
unsigned ts = static_cast<unsigned> (graph->text_extent_size(it.cells[pos].text).width);
if (max_w < ts)
max_w = ts;
}
if (!max_w) return 0;
unsigned ext_w = scheme_ptr->ext_w;
if (pos == 0 && checkable) // only before the first column (display_order=0 ?)
ext_w += 18;
header.item_width(pos, max_w + ext_w + 1 < max ? max_w + ext_w + 1 : max);
return max_w;
}
inline_pane * open_inline(pat::abstract_factory<inline_notifier_interface>* factory, inline_indicator* indicator)
{
std::unique_ptr<inline_pane> pane_ptr;
@@ -2494,7 +2506,7 @@ namespace nana
}
}
nana::string es_lister::to_string(const export_options& exp_opt) const
nana::string es_lister::to_string(const export_options& exp_opt) const
{
nana::string list_str;
bool first{true};
@@ -2515,6 +2527,17 @@ namespace nana
return list_str ;
}
void es_lister::categ_selected(size_type cat, bool sel)
{
cat_proxy cpx{ess_,cat};
for (item_proxy &it : cpx )
{
if (it.selected() != sel)
it.select(sel);
}
last_selected_abs = last_selected_dpl = index_pair {cat, npos};
}
class drawer_header_impl
{
@@ -3450,6 +3473,14 @@ namespace nana
void trigger::dbl_click(graph_reference graph, const arg_mouse&)
{
if (essence_->pointer_where.first == essence_t::parts::header)
if (cursor::size_we == essence_->lister.wd_ptr()->cursor())
{
if (essence(). auto_width(drawer_header_->item_spliter() )) // ? in order
essence().update();
return;
}
if (essence_->pointer_where.first != essence_t::parts::lister)
return;
@@ -3518,21 +3549,35 @@ namespace nana
if (! scrl.make_page_scroll(!up))
return;
essence_->lister.select_for_all(false);
if (up)
item_proxy {essence_, essence_->scroll_y_abs()}.select(true);
else
{
index_pair idx{essence_->scroll_y_dpl()};
index_pair idx{essence_->scroll_y_dpl()};
if (!up)
essence_->lister.forward(idx, scrl.range()-1, idx);
item_proxy::from_display(essence_,idx).select(true);
}
if (idx.is_item())
item_proxy::from_display(essence_, idx).select(true);
else
if(!essence_->lister.single_selection())
essence_->lister.categ_selected(idx.cat, true);
essence_->trace_last_selected_item ();
break;
}
case keyboard::os_home:
{
essence_->lister.select_for_all(false);
item_proxy::from_display(essence_, {0,0}).select(true);
index_pair frst{essence_->lister.first()};
if (frst.is_item())
item_proxy::from_display(essence_, frst).select(true);
else
if(!essence_->lister.single_selection())
essence_->lister.categ_selected(frst.cat, true);
essence_->trace_last_selected_item ();
break;
}
case keyboard::os_end:
essence_->lister.select_for_all(false);
item_proxy::from_display(essence_, essence_->lister.last()).select(true);
@@ -3584,7 +3629,7 @@ namespace nana
{
auto i = ess_->lister.cat_container().begin();
std::advance(i, pos.cat);
cat_ = &(*i);
cat_ = &(*i); // what is pos is a cat?
}
}
@@ -3617,6 +3662,7 @@ namespace nana
m.flags.checked = ck;
arg_listbox arg{*this, ck};
ess_->lister.wd_ptr()->events().checked.emit(arg);
ess_->update();
}
return *this;
}
@@ -3629,7 +3675,7 @@ 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)
{
auto & m = cat_->items.at(pos_.item); // a ref to the real item
auto & m = cat_->items.at(pos_.item); // a ref to the real item // what is pos is a cat?
if(m.flags.selected == s) return *this; // ignore if no change
m.flags.selected = s; // actually change selection
@@ -3646,6 +3692,7 @@ namespace nana
ess_->update();
ess_->update();
return *this;
}
@@ -3865,6 +3912,24 @@ namespace nana
}
}
cat_proxy & cat_proxy::select(bool sel)
{
for (item_proxy &it : *this )
it.select(sel);
ess_->lister.last_selected_abs =
ess_->lister.last_selected_dpl = index_pair {this->pos_, npos};
return *this;
}
bool cat_proxy::selected() const
{
for (item_proxy &it : *this )
if (!it.selected())
return false;
return true;
}
auto cat_proxy::columns() const -> size_type
{
return ess_->header.cont().size();
@@ -3907,6 +3972,11 @@ namespace nana
//Behavior of a container
item_proxy cat_proxy::begin() const
{
auto i = ess_->lister.cat_container().begin();
std::advance(i, pos_);
if (i->items.empty())
return end();
return item_proxy(ess_, index_pair(pos_, 0));
}
@@ -4121,11 +4191,12 @@ namespace nana
_m_ess().set_auto_draw(ad);
}
void listbox::append_header(nana::string text, unsigned width)
listbox::size_type listbox::append_header(nana::string text, unsigned width)
{
auto & ess = _m_ess();
ess.header.create(std::move(text), width);
listbox::size_type index = ess.header.create(std::move(text), width);
ess.update();
return index;
}
listbox& listbox::header_width(size_type pos, unsigned pixels)
@@ -4135,6 +4206,13 @@ namespace nana
ess.update();
return *this;
}
unsigned listbox::auto_width(size_type pos, unsigned max)
{
auto & ess = _m_ess();
unsigned max_w = ess.auto_width(pos, max);
ess.update();
return max_w;
}
unsigned listbox::header_width(size_type pos) const
{

View File

@@ -114,7 +114,7 @@ namespace nana
{
if(at.item_state == state::active)
{
graph.rectangle(r, false, {0xa8, 0xd8, 0xeb});
graph.rectangle(r, false, static_cast<color_rgb>(0xa8d8eb));
nana::point points[4] = {
nana::point(r.x, r.y),
nana::point(r.x + r.width - 1, r.y),
@@ -144,9 +144,9 @@ namespace nana
}
}
void item_image(graph_reference graph, const nana::point& pos, const paint::image& img)
void item_image(graph_reference graph, const nana::point& pos, unsigned image_px, const paint::image& img)
{
img.paste(graph, pos.x, pos.y);
img.stretch(rectangle{ img.size() }, graph, rectangle{ pos, ::nana::size(image_px, image_px) });
}
void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at)
@@ -200,35 +200,35 @@ namespace nana
void checked(std::size_t index, bool check)
{
if(root_.items.size() > index)
if (root_.items.size() <= index)
return;
item_type & m = root_.items[index];
if(check && (checks::option == m.style))
{
item_type & m = root_.items[index];
if(check && (checks::option == m.style))
if(index)
{
if(index)
std::size_t i = index;
do
{
std::size_t i = index;
do
{
item_type& el = root_.items[--i];
if(el.flags.splitter) break;
if(checks::option == el.style)
el.flags.checked = false;
}while(i);
}
for(std::size_t i = index + 1; i < root_.items.size(); ++i)
{
item_type & el = root_.items[i];
item_type& el = root_.items[--i];
if(el.flags.splitter) break;
if(checks::option == el.style)
el.flags.checked = false;
}
}while(i);
}
for(std::size_t i = index + 1; i < root_.items.size(); ++i)
{
item_type & el = root_.items[i];
if(el.flags.splitter) break;
if(checks::option == el.style)
el.flags.checked = false;
}
m.flags.checked = check;
}
m.flags.checked = check;
}
menu_type& data()
@@ -304,7 +304,7 @@ namespace nana
: public drawer_trigger
{
public:
typedef menu_item_type::item_proxy item_proxy;
using item_proxy = menu_item_type::item_proxy;
renderer_interface * renderer;
@@ -330,12 +330,12 @@ namespace nana
detail_.monitor_pos = API::cursor_position();
}
void mouse_move(graph_reference, const arg_mouse& arg)
void mouse_move(graph_reference graph, const arg_mouse& arg)
{
state_.nullify_mouse = false;
if(track_mouse(arg.pos.x, arg.pos.y))
if(track_mouse(arg.pos))
{
draw();
refresh(graph);
API::lazy_refresh();
}
}
@@ -350,9 +350,70 @@ namespace nana
state_.nullify_mouse = false;
}
void refresh(graph_reference)
void refresh(graph_reference graph)
{
draw();
if (nullptr == menu_) return;
_m_adjust_window_size();
renderer->background(graph, *widget_);
const unsigned item_h_px = _m_item_height();
const unsigned image_px = item_h_px - 2;
nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px);
unsigned strpixels = item_r.width - 60;
int text_top_off = (item_h_px - graph.text_extent_size(STR("jh({[")).height) / 2;
std::size_t pos = 0;
for (auto & m : menu_->items)
{
if (m.flags.splitter)
{
graph_->set_color(colors::gray_border);
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph.width()) - 1, item_r.y });
item_r.y += 2;
++pos;
continue;
}
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
//Draw item background
renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character
nana::char_t hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
if (m.image.empty() == false)
renderer->item_image(graph, nana::point(item_r.x + 5, item_r.y + static_cast<int>(item_h_px - image_px) / 2 - 1), image_px, m.image);
renderer->item_text(graph, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if (hotkey)
{
m.hotkey = hotkey;
if (m.flags.enabled)
{
unsigned off_w = (hotkey_pos ? graph.text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
nana::size hotkey_size = graph.text_extent_size(text.c_str() + hotkey_pos, 1);
int x = item_r.x + 40 + off_w;
int y = item_r.y + text_top_off + hotkey_size.height;
graph_->set_color(colors::black);
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
}
}
if (m.sub_menu)
renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1;
++pos;
}
}
std::size_t active() const
@@ -411,21 +472,21 @@ namespace nana
state_.active = pos;
state_.sub_window = false;
draw();
refresh(*graph_);
return true;
}
return false;
}
bool track_mouse(int x, int y)
bool track_mouse(const ::nana::point& pos)
{
if(state_.nullify_mouse == false)
if (!state_.nullify_mouse)
{
std::size_t index = _m_get_index_by_pos(x, y);
if(index != state_.active)
std::size_t index = _m_get_index_by_pos(pos.x, pos.y);
if (index != state_.active)
{
if((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window)
if ((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window)
return false;
state_.active = (index != npos && menu_->items.at(index).flags.splitter) ? npos : index;
@@ -433,6 +494,7 @@ namespace nana
return true;
}
}
return false;
}
@@ -451,29 +513,35 @@ namespace nana
state_.sub_window = subw;
}
menu_type* retrive_sub_menu(nana::point& pos, std::size_t interval) const
menu_type* get_sub(nana::point& pos, unsigned long& tmstamp) const
{
if(state_.active != npos && (nana::system::timestamp() - state_.active_timestamp >= interval))
if (npos == state_.active)
return nullptr;
auto sub = menu_->items.at(state_.active).sub_menu;
if (sub)
{
pos.x = graph_->width() - 2;
pos.x = static_cast<int>(graph_->width()) - 2;
pos.y = 2;
std::size_t index = 0;
for(auto & m : menu_->items)
auto index = state_.active;
for (auto & m : menu_->items)
{
if(false == m.flags.splitter)
if (m.flags.splitter)
{
if(index == state_.active)
break;
pos.y += _m_item_height() + 1;
}
else
pos.y += 2;
continue;
}
++index;
if (0 == index)
break;
pos.y += _m_item_height() + 1;
--index;
}
return (menu_->items.at(state_.active).sub_menu);
tmstamp = state_.active_timestamp;
return sub;
}
return nullptr;
}
@@ -498,8 +566,7 @@ namespace nana
state_.active = index;
state_.active_timestamp = nana::system::timestamp();
draw();
API::update_window(*widget_);
API::refresh_window(*widget_);
return 2;
}
else if(m.flags.enabled)
@@ -514,71 +581,6 @@ namespace nana
}
return 0;
}
void draw() const
{
if(nullptr == menu_) return;
_m_adjust_window_size();
renderer->background(*graph_, *widget_);
const unsigned item_h_px = _m_item_height();
nana::rectangle item_r(2, 2, graph_->width() - 4, item_h_px);
unsigned strpixels = item_r.width - 60;
int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2;
std::size_t pos = 0;
for(auto & m : menu_->items)
{
if(m.flags.splitter)
{
graph_->set_color(colors::gray_border);
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph_->width()) - 1, item_r.y });
item_r.y += 2;
++pos;
continue;
}
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
//Draw item background
renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character
nana::char_t hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
if(m.image.empty() == false)
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image);
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if(hotkey)
{
m.hotkey = hotkey;
if(m.flags.enabled)
{
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
int x = item_r.x + 40 + off_w;
int y = item_r.y + text_top_off + hotkey_size.height;
graph_->set_color(colors::black);
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
}
}
if(m.sub_menu)
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1;
++pos;
}
}
private:
static renderer_interface::attr _m_make_renderer_attr(bool active, const menu_item_type & m)
{
@@ -683,10 +685,10 @@ namespace nana
struct state
{
std::size_t active;
unsigned long active_timestamp;
unsigned long sub_window: 1;
unsigned long nullify_mouse: 1;
std::size_t active;
unsigned active_timestamp;
bool sub_window: 1;
bool nullify_mouse: 1;
}state_;
struct widget_detail
@@ -699,15 +701,18 @@ namespace nana
class menu_window
: public widget_object<category::root_tag, menu_drawer>
{
typedef menu_drawer drawer_type;
typedef widget_object<category::root_tag, menu_drawer> base_type;
using drawer_type = menu_drawer;
using base_type = widget_object<category::root_tag, menu_drawer>;
public:
typedef menu_builder::item_type item_type;
using item_type = menu_builder::item_type;
menu_window(window wd, const point& pos, renderer_interface * rdptr)
menu_window(window wd, bool is_wd_parent_menu, const point& pos, renderer_interface * rdptr)
//add a is_wd_parent_menu to determine whether the menu wants the focus.
//if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed
: base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()),
want_focus_(nullptr == wd || (API::focus_window() != wd)),
event_focus_(nullptr)
want_focus_{ (!wd) || ((!is_wd_parent_menu) && (API::focus_window() != wd)) },
event_focus_{ nullptr }
{
caption(STR("nana menu window"));
get_drawer_trigger().close_menu_tree([this]{ this->_m_close_all(); });
@@ -718,7 +723,19 @@ namespace nana
submenu_.child = submenu_.parent = nullptr;
submenu_.object = nullptr;
_m_make_mouse_event();
state_.mouse_pos = API::cursor_position();
events().mouse_move.connect_unignorable([this]{
nana::point pos = API::cursor_position();
if (pos != state_.mouse_pos)
{
menu_window * root = this;
while (root->submenu_.parent)
root = root->submenu_.parent;
root->state_.auto_popup_submenu = true;
state_.mouse_pos = pos;
}
});
}
void popup(menu_type& menu, bool owner_menubar)
@@ -745,13 +762,19 @@ namespace nana
_m_key_down(arg);
});
events().mouse_up.connect_unignorable([this]{
pick();
events().mouse_down.connect_unignorable([this](const arg_mouse& arg)
{
this->_m_open_sub(0); //Try to open submenu immediately
});
events().mouse_up.connect_unignorable([this](const arg_mouse& arg){
if (arg.left_button)
pick();
});
timer_.interval(100);
timer_.elapse([this]{
this->_m_check_repeatly();
this->_m_open_sub(500); //Try to open submenu
});
timer_.start();
@@ -797,29 +820,27 @@ namespace nana
bool submenu(bool enter)
{
menu_window * object = this;
while (object->submenu_.child)
object = object->submenu_.child;
menu_window * menu_wd = this;
while (menu_wd->submenu_.child)
menu_wd = menu_wd->submenu_.child;
state_.auto_popup_submenu = false;
if (enter)
if (!enter)
{
if (object->submenu_.parent)
if (menu_wd->submenu_.parent)
{
auto & sub = object->submenu_.parent->submenu_;
auto & sub = menu_wd->submenu_.parent->submenu_;
sub.child = nullptr;
sub.object = nullptr;
object->close();
menu_wd->close();
return true;
}
return false;
}
nana::point pos;
menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0);
return object->_m_show_submenu(sbm, pos, true);
return menu_wd->_m_manipulate_sub(0, true);
}
int send_shortkey(nana::char_t key)
@@ -965,63 +986,51 @@ namespace nana
}
}
void _m_make_mouse_event()
bool _m_manipulate_sub(unsigned long delay_ms, bool forced)
{
state_.mouse_pos = API::cursor_position();
events().mouse_move.connect_unignorable([this]{
_m_mouse_event();
});
}
auto & drawer = get_drawer_trigger();
::nana::point pos;
unsigned long tmstamp;
void _m_mouse_event()
{
nana::point pos = API::cursor_position();
if(pos != state_.mouse_pos)
auto menu_ptr = drawer.get_sub(pos, tmstamp);
if (menu_ptr == submenu_.object)
return false;
if (menu_ptr && (::nana::system::timestamp() - tmstamp < delay_ms))
return false;
if (submenu_.object && (menu_ptr != submenu_.object))
{
menu_window * root = this;
while(root->submenu_.parent)
root = root->submenu_.parent;
root->state_.auto_popup_submenu = true;
state_.mouse_pos = pos;
}
}
bool _m_show_submenu(menu_type* sbm, nana::point pos, bool forced)
{
auto & mdtrigger = get_drawer_trigger();
if(submenu_.object && (sbm != submenu_.object))
{
mdtrigger.set_sub_window(false);
drawer.set_sub_window(false);
submenu_.child->close();
submenu_.child = nullptr;
submenu_.object = nullptr;
}
if(sbm)
if (menu_ptr)
{
menu_window * root = this;
while(root->submenu_.parent)
while (root->submenu_.parent)
root = root->submenu_.parent;
if((submenu_.object == nullptr) && sbm && (forced || root->state_.auto_popup_submenu))
if ((submenu_.object == nullptr) && menu_ptr && (forced || root->state_.auto_popup_submenu))
{
sbm->item_pixels = mdtrigger.data()->item_pixels;
sbm->gaps = mdtrigger.data()->gaps;
pos.x += sbm->gaps.x;
pos.y += sbm->gaps.y;
menu_ptr->item_pixels = drawer.data()->item_pixels;
menu_ptr->gaps = drawer.data()->gaps;
pos += menu_ptr->gaps;
menu_window & mwnd = form_loader<menu_window, false>()(handle(), pos, mdtrigger.renderer);
menu_window & mwnd = form_loader<menu_window, false>()(handle(), true, pos, drawer.renderer);
mwnd.state_.self_submenu = true;
submenu_.child = & mwnd;
submenu_.child = &mwnd;
submenu_.child->submenu_.parent = this;
submenu_.object = sbm;
submenu_.object = menu_ptr;
API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none);
mwnd.popup(*sbm, state_.owner_menubar);
mdtrigger.set_sub_window(true);
if(forced)
mwnd.popup(*menu_ptr, state_.owner_menubar);
drawer.set_sub_window(true);
if (forced)
mwnd.goto_next(true);
return true;
@@ -1030,17 +1039,16 @@ namespace nana
return false;
}
void _m_check_repeatly()
void _m_open_sub(unsigned delay_ms) //check_repeatly
{
if(state_.auto_popup_submenu)
{
nana::point pos = API::cursor_position();
auto pos = API::cursor_position();
drawer_type& drawer = get_drawer_trigger();
API::calc_window_point(handle(), pos);
drawer.track_mouse(pos.x, pos.y);
menu_type* sbm = drawer.retrive_sub_menu(pos, 500);
_m_show_submenu(sbm, pos, false);
get_drawer_trigger().track_mouse(pos);
_m_manipulate_sub(delay_ms, false);
}
}
private:
@@ -1293,7 +1301,7 @@ namespace nana
{
close();
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, point(x, y), &(*impl_->mbuilder.renderer())));
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, false, point(x, y), &(*impl_->mbuilder.renderer())));
impl_->uiobj->events().destroy.connect_unignorable([this]{
impl_->uiobj = nullptr;
if (impl_->destroy_answer)

View File

@@ -89,6 +89,15 @@ namespace nana
{
return unknown_;
}
bool trigger::stoped() const
{
return stop_;
}
bool trigger::stop(bool s)
{
std::swap(s,stop_);
return s;
}
void trigger::refresh(graph_reference)
{
@@ -197,5 +206,13 @@ namespace nana
{
return get_drawer_trigger().unknown();
}
bool progress::stop(bool s)
{
return get_drawer_trigger().stop(s);
}
bool progress::stoped() const
{
return get_drawer_trigger().stoped();
}
//end class progress
}//end namespace nana

View File

@@ -1482,6 +1482,8 @@ namespace nana{ namespace widgets
behavior_->pre_calc_lines(width_pixels());
_m_scrollbar();
move_caret(points_.caret);
return true;
}

View File

@@ -11,10 +11,10 @@
*/
#include <nana/gui/widgets/toolbar.hpp>
#include <vector>
#include <stdexcept>
#include <nana/gui/tooltip.hpp>
#include <vector>
namespace nana
{
arg_toolbar::arg_toolbar(toolbar& tbar, std::size_t btn)
@@ -25,13 +25,6 @@ namespace nana
{
namespace toolbar
{
struct listitem
{
nana::string text;
nana::paint::image image;
bool enable;
};
struct item_type
{
enum kind{ button, container};
@@ -43,28 +36,23 @@ namespace nana
unsigned pixels{0};
nana::size textsize;
bool enable{true};
window other{nullptr};
kind type;
std::function<void(size_type, size_type)> answer;
std::vector<listitem> children;
item_type(const nana::string& text, const nana::paint::image& img, kind type)
:text(text), image(img), type(type)
{}
};
class container
{
container(const container&) = delete;
container& operator=(const container&) = delete;
public:
typedef std::vector<item_type*>::size_type size_type;
typedef std::vector<item_type*>::iterator iterator;
typedef std::vector<item_type*>::const_iterator const_iterator;
container() = default;
~container()
class item_container
{
public:
using container_type = std::vector<item_type*>;
using size_type = container_type::size_type;
~item_container()
{
for(auto ptr : cont_)
delete ptr;
@@ -98,7 +86,7 @@ namespace nana
cont_.push_back(nullptr);
}
void push_back()
void separate()
{
cont_.push_back(nullptr);
}
@@ -108,35 +96,17 @@ namespace nana
return cont_.size();
}
item_type* at(size_type n)
container_type& container()
{
if(n < cont_.size())
return cont_[n];
throw std::out_of_range("toolbar: bad index!");
return cont_;
}
iterator begin()
item_type * at(size_type pos)
{
return cont_.begin();
}
iterator end()
{
return cont_.end();
}
const_iterator begin() const
{
return cont_.cbegin();
}
const_iterator end() const
{
return cont_.cend();
return cont_.at(pos);
}
private:
std::vector<item_type*> cont_;
container_type cont_;
};
class item_renderer
@@ -152,38 +122,36 @@ namespace nana
void operator()(int x, int y, unsigned width, unsigned height, item_type& item, state_t state)
{
//draw background
if(state != state_t::normal)
graph.rectangle({ x, y, width, height }, false, { 0x33, 0x99, 0xFF });
switch(state)
if (state != state_t::normal)
{
case state_t::highlighted:
graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0xC0, 0xDD, 0xFC }, true);
break;
case state_t::selected:
graph.gradual_rectangle({ x + 1, y + 1, width - 2, height - 2 }, bgcolor, { 0x99, 0xCC, 0xFF }, true);
default: break;
nana::rectangle background_r(x, y, width, height);
graph.rectangle(background_r, false, static_cast<color_rgb>(0x3399FF));
if (state_t::highlighted == state || state_t::selected == state)
graph.gradual_rectangle(background_r.pare_off(1), bgcolor, static_cast<color_rgb>(state_t::selected == state ? 0x99CCFF : 0xC0DDFC), true);
}
if(item.image.empty() == false)
if(!item.image.empty())
{
nana::size size = item.image.size();
if(size.width > scale) size.width = scale;
if(size.height > scale) size.height = scale;
auto imgsize = item.image.size();
if (imgsize.width > scale) imgsize.width = scale;
if (imgsize.height > scale) imgsize.height = scale;
nana::point pos(x, y);
pos.x += static_cast<int>(scale + extra_size - size.width) / 2;
pos.y += static_cast<int>(height - size.height) / 2;
pos.x += static_cast<int>(scale + extra_size - imgsize.width) / 2;
pos.y += static_cast<int>(height - imgsize.height) / 2;
item.image.paste(::nana::rectangle{ size }, graph, pos);
item.image.paste(::nana::rectangle{ imgsize }, graph, pos);
if(item.enable == false)
{
nana::paint::graphics gh(size);
gh.bitblt(::nana::rectangle{ size }, graph, pos);
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, size), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25);
graph.blend(nana::rectangle(pos, imgsize), ::nana::color(0xc0, 0xdd, 0xfc).blend(bgcolor, 0.5), 0.25);
x += scale;
width -= scale;
@@ -204,13 +172,15 @@ namespace nana
struct drawer::drawer_impl_type
{
event_handle event_size{nullptr};
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};
container cont;
item_container items;
::nana::tooltip tooltip;
};
@@ -225,116 +195,118 @@ namespace nana
delete impl_;
}
void drawer::append(const nana::string& text, const nana::paint::image& img)
item_container& drawer::items() const
{
impl_->cont.push_back(text, img);
}
void drawer::append()
{
impl_->cont.push_back();
}
bool drawer::enable(drawer::size_type n) const
{
if(impl_->cont.size() > n)
{
auto item = impl_->cont.at(n);
return (item && item->enable);
}
return false;
}
bool drawer::enable(size_type n, bool eb)
{
if(impl_->cont.size() > n)
{
item_type * item = impl_->cont.at(n);
if(item && (item->enable != eb))
{
item->enable = eb;
return true;
}
}
return false;
return impl_->items;
}
void drawer::scale(unsigned s)
{
impl_->scale = s;
for(auto m : impl_->cont)
_m_fill_pixels(m, true);
for(auto m : impl_->items.container())
_m_calc_pixels(m, true);
}
void drawer::refresh(graph_reference)
void drawer::refresh(graph_reference graph)
{
_m_draw();
int x = 2, y = 2;
auto bgcolor = API::bgcolor(widget_->handle());
graph.set_text_color(bgcolor);
graph.gradual_rectangle(rectangle{ graph.size() }, bgcolor.blend(colors::white, 0.9), bgcolor.blend(colors::black, 0.95), 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);
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<int>(impl_->scale + ir.extra_size) - 4 }, static_cast<color_rgb>(0x808080));
x += 4;
}
++index;
}
}
void drawer::attached(widget_reference widget, graph_reference graph)
{
graph_ = &graph;
impl_->graph_ptr = &graph;
widget_ = static_cast< ::nana::toolbar*>(&widget);
widget.caption(STR("Nana Toolbar"));
impl_->event_size = widget.events().resized.connect_unignorable(std::bind(&drawer::_m_owner_sized, this, std::placeholders::_1));
widget.caption(L"Nana Toolbar");
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 == false)
if (arg.left_button)
return;
size_type which = _m_which(arg.pos, true);
if(impl_->which != which)
{
size_type which = _m_which(arg.pos.x, arg.pos.y, true);
if(impl_->which != which)
auto & container = impl_->items.container();
if (impl_->which != npos && container.at(impl_->which)->enable)
{
if (impl_->which != npos && impl_->cont.at(impl_->which)->enable)
{
::nana::arg_toolbar arg{ *widget_, impl_->which };
widget_->events().leave.emit(arg);
}
impl_->which = which;
if(which == npos || impl_->cont.at(which)->enable)
{
impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted);
_m_draw();
API::lazy_refresh();
if (impl_->state == item_renderer::state_t::highlighted)
{
::nana::arg_toolbar arg{ *widget_, which };
widget_->events().enter.emit(arg);
}
}
if(which != npos)
impl_->tooltip.show(widget_->handle(), nana::point(arg.pos.x, arg.pos.y + 20), (*(impl_->cont.begin() + which))->text, 0);
else
impl_->tooltip.close();
::nana::arg_toolbar arg{ *widget_, impl_->which };
widget_->events().leave.emit(arg);
}
impl_->which = which;
if (which == npos || container.at(which)->enable)
{
impl_->state = (arg.left_button ? item_renderer::state_t::selected : item_renderer::state_t::highlighted);
refresh(graph);
API::lazy_refresh();
if (impl_->state == item_renderer::state_t::highlighted)
{
::nana::arg_toolbar arg{ *widget_, which };
widget_->events().enter.emit(arg);
}
}
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, const arg_mouse&)
void drawer::mouse_leave(graph_reference graph, const arg_mouse&)
{
if(impl_->which != npos)
{
size_type which = impl_->which;
impl_->which = npos;
_m_draw();
refresh(graph);
API::lazy_refresh();
if (which != npos && impl_->cont.at(which)->enable)
if (which != npos && impl_->items.at(which)->enable)
{
::nana::arg_toolbar arg{ *widget_, which };
widget_->events().leave.emit(arg);
@@ -343,22 +315,22 @@ namespace nana
impl_->tooltip.close();
}
void drawer::mouse_down(graph_reference, const arg_mouse&)
void drawer::mouse_down(graph_reference graph, const arg_mouse&)
{
impl_->tooltip.close();
if(impl_->which != npos && (impl_->cont.at(impl_->which)->enable))
if(impl_->which != npos && (impl_->items.at(impl_->which)->enable))
{
impl_->state = item_renderer::state_t::selected;
_m_draw();
refresh(graph);
API::lazy_refresh();
}
}
void drawer::mouse_up(graph_reference, const arg_mouse& arg)
void drawer::mouse_up(graph_reference graph, const arg_mouse& arg)
{
if(impl_->which != npos)
{
size_type which = _m_which(arg.pos.x, arg.pos.y, false);
size_type which = _m_which(arg.pos, false);
if(impl_->which == which)
{
::nana::arg_toolbar arg{ *widget_, which };
@@ -372,89 +344,47 @@ namespace nana
impl_->state = (which == npos ? item_renderer::state_t::normal : item_renderer::state_t::highlighted);
}
_m_draw();
refresh(graph);
API::lazy_refresh();
}
}
drawer::size_type drawer::_m_which(int x, int y, bool want_if_disabled) const
drawer::size_type drawer::_m_which(point pos, bool want_if_disabled) const
{
if(x < 2 || y < 2 || y >= static_cast<int>(impl_->scale + item_renderer::extra_size + 2)) return npos;
if (pos.x < 2 || pos.y < 2 || pos.y >= static_cast<int>(impl_->scale + item_renderer::extra_size + 2)) return npos;
x -= 2;
pos.x -= 2;
size_type pos = 0;
for(auto m: impl_->cont)
std::size_t index = 0;
for(auto m: impl_->items.container())
{
bool compart = (nullptr == m);
auto px = static_cast<const int>(m ? m->pixels : 3);
if(x < static_cast<int>(compart ? 3 : m->pixels))
return ((compart || (m->enable == false && want_if_disabled == false)) ? npos : pos);
if(pos.x < px)
return (((!m) || (!m->enable && !want_if_disabled)) ? npos : index);
x -= (compart ? 3 : m->pixels);
pos.x -= px;
++pos;
++index;
}
return npos;
}
void drawer::_m_draw_background(const ::nana::color& clr)
void drawer::_m_calc_pixels(item_type* item, bool force)
{
graph_->gradual_rectangle(::nana::rectangle{ graph_->size() }, clr.blend(colors::white, 0.9), clr.blend(colors::black, 0.95), true);
}
void drawer::_m_draw()
{
int x = 2, y = 2;
auto bgcolor = API::bgcolor(widget_->handle());
graph_->set_text_color(bgcolor);
_m_draw_background(bgcolor);
item_renderer ir(*graph_, impl_->textout, impl_->scale, bgcolor);
size_type index = 0;
for(auto item : impl_->cont)
if (item && (force || (0 == item->pixels)))
{
if(item)
{
_m_fill_pixels(item, false);
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
{
graph_->line({ x + 2, y + 2 }, { x + 2, y + static_cast<int>(impl_->scale + ir.extra_size) - 4 }, { 0x80, 0x80, 0x80 });
x += 6;
}
++index;
}
}
if (item->text.size())
item->textsize = impl_->graph_ptr->text_extent_size(item->text);
void drawer::_m_owner_sized(const arg_resized& arg)
{
auto wd = widget_->handle();
API::window_size(wd, nana::size(arg.width, widget_->size().height));
_m_draw();
API::update_window(wd);
}
void drawer::_m_fill_pixels(item_type* item, bool force)
{
if(item && (force || (0 == item->pixels)))
{
if(item->text.size())
item->textsize = graph_->text_extent_size(item->text);
if(item->image.empty() == false)
if (item->image.empty() == false)
item->pixels = impl_->scale + item_renderer::extra_size;
if(item->textsize.width && impl_->textout)
if (item->textsize.width && impl_->textout)
item->pixels += item->textsize.width + 8;
}
}
//};//class drawer
//class drawer
}//end namespace toolbar
}//end namespace drawerbase
@@ -469,33 +399,48 @@ namespace nana
create(wd, r, visible);
}
void toolbar::append()
void toolbar::separate()
{
get_drawer_trigger().append();
get_drawer_trigger().items().separate();
API::refresh_window(handle());
}
void toolbar::append(const nana::string& text, const nana::paint::image& img)
{
get_drawer_trigger().append(text, img);
get_drawer_trigger().items().push_back(text, img);
API::refresh_window(handle());
}
void toolbar::append(const nana::string& text)
{
get_drawer_trigger().append(text, nana::paint::image());
get_drawer_trigger().items().push_back(text, {});
API::refresh_window(this->handle());
}
bool toolbar::enable(size_type n) const
bool toolbar::enable(size_type pos) const
{
return get_drawer_trigger().enable(n);
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 n, bool eb)
void toolbar::enable(size_type pos, bool eb)
{
if(get_drawer_trigger().enable(n, eb))
API::refresh_window(this->handle());
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)
@@ -503,5 +448,5 @@ namespace nana
get_drawer_trigger().scale(s);
API::refresh_window(handle());
}
//}; class toolbar
//end class toolbar
}//end namespace nana