Merge branch 'hotfix-1.4.1' into develop

This commit is contained in:
Jinhao 2016-10-31 06:21:41 +08:00
commit b1ce0eaff2
26 changed files with 428 additions and 342 deletions

View File

@ -102,7 +102,7 @@
#define _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
#if (_MSC_VER == 1900) #if (_MSC_VER >= 1900)
// google: break any code that tries to use codecvt<char16_t> or codecvt<char32_t>. // google: break any code that tries to use codecvt<char16_t> or codecvt<char32_t>.
// google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support.
// google: Those definitions are for codecvt<wchar_t>::id, codecvt<unsigned short>::id and codecvt<char>::id respectively. // google: Those definitions are for codecvt<wchar_t>::id, codecvt<unsigned short>::id and codecvt<char>::id respectively.

View File

@ -85,7 +85,7 @@ namespace detail
enum class update_state enum class update_state
{ {
none, lazy, refresh none, lazy, refreshed, request_refresh
}; };
struct edge_nimbus_action struct edge_nimbus_action

View File

@ -86,7 +86,7 @@ namespace nana{
} }
//Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered.
if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh)) if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refreshed))
{ {
rd_set.emplace_back(r, action.window); rd_set.emplace_back(r, action.window);
action.rendered = true; action.rendered = true;

View File

@ -1,6 +1,6 @@
/* /*
* Window Layout Implementation * Window Layout Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -42,10 +42,16 @@ namespace detail
core_window_t * window; core_window_t * window;
rectangle r; rectangle r;
}; };
public:
static void paint(core_window_t*, bool is_redraw, bool is_child_refreshed);
static bool maproot(core_window_t*, bool have_refreshed, bool is_child_refreshed); enum class paint_operation {
none,
have_refreshed,
try_refresh
};
public:
static void paint(core_window_t*, paint_operation, bool request_refresh_children);
static bool maproot(core_window_t*, bool have_refreshed, bool request_refresh_children);
static void paste_children_to_graphics(core_window_t*, nana::paint::graphics& graph); static void paste_children_to_graphics(core_window_t*, nana::paint::graphics& graph);
@ -68,13 +74,12 @@ namespace detail
//_m_paste_children //_m_paste_children
//@brief:paste children window to the root graphics directly. just paste the visual rectangle //@brief:paste children window to the root graphics directly. just paste the visual rectangle
static void _m_paste_children(core_window_t*, bool is_child_refreshed, bool have_refreshed, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); static void _m_paste_children(core_window_t*, bool have_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos);
static void _m_paint_glass_window(core_window_t*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other); static void _m_paint_glass_window(core_window_t*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other);
//_m_notify_glasses //Notify the windows which have brground to update their background buffer.
//@brief: Notify the glass windows that are overlapped with the specified vis_rect static void _m_notify_glasses(core_window_t* const sigwd);
static void _m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& r_visual);
private: private:
struct data_section struct data_section
{ {

View File

@ -124,7 +124,7 @@ namespace detail
bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr); bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr);
void refresh_tree(core_window_t*); void refresh_tree(core_window_t*);
bool do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false); void do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false);
bool get_graphics(core_window_t*, nana::paint::graphics&); bool get_graphics(core_window_t*, nana::paint::graphics&);
bool get_visual_rectangle(core_window_t*, nana::rectangle&); bool get_visual_rectangle(core_window_t*, nana::rectangle&);

View File

@ -14,10 +14,7 @@
#ifndef NANA_GUI_WIDGETS_MENU_HPP #ifndef NANA_GUI_WIDGETS_MENU_HPP
#define NANA_GUI_WIDGETS_MENU_HPP #define NANA_GUI_WIDGETS_MENU_HPP
#include "widget.hpp" #include "widget.hpp"
#include <vector>
#include <nana/gui/timer.hpp>
#include <nana/pat/cloneable.hpp> #include <nana/pat/cloneable.hpp>
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>
namespace nana namespace nana
@ -72,25 +69,12 @@ namespace nana
menu_type *sub_menu{nullptr}; menu_type *sub_menu{nullptr};
std::string text; std::string text;
event_fn_t functor; event_fn_t event_handler;
checks style{checks::none}; checks style{checks::none};
paint::image image; paint::image image;
mutable wchar_t hotkey{0}; mutable wchar_t hotkey{0};
}; };
struct menu_type
{
typedef std::vector<menu_item_type> item_container;
typedef item_container::iterator iterator;
typedef item_container::const_iterator const_iterator;
std::vector<menu_type*> owner;
std::vector<menu_item_type> items;
unsigned max_pixels;
unsigned item_pixels;
nana::point gaps;
};
class renderer_interface class renderer_interface
{ {
public: public:
@ -158,7 +142,7 @@ namespace nana
void popup(window owner, int x, int y); ///< Popup the menu at the owner window. void popup(window owner, int x, int y); ///< Popup the menu at the owner window.
void popup_await(window owner, int x, int y); void popup_await(window owner, int x, int y);
void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item. void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item.
void destroy_answer(const std::function<void()>&); ///< Sets an answerer for the callback while the menu window is closing. void destroy_answer(std::function<void()>); ///< Sets an answerer for the callback while the menu window is closing.
void gaps(const nana::point&); ///< Sets the gap between a menu and its sub menus.(\See Note4) void gaps(const nana::point&); ///< Sets the gap between a menu and its sub menus.(\See Note4)
void goto_next(bool forward); ///< Moves the focus to the next or previous item. void goto_next(bool forward); ///< Moves the focus to the next or previous item.
bool goto_submen();///< Popup the submenu of the current item if it has a sub menu. Returns true if succeeds. bool goto_submen();///< Popup the submenu of the current item if it has a sub menu. Returns true if succeeds.
@ -177,7 +161,7 @@ namespace nana
const pat::cloneable<renderer_interface>& renderer() const; const pat::cloneable<renderer_interface>& renderer() const;
private: private:
void _m_popup(window, int x, int y, bool called_by_menubar); void _m_popup(window, const point& position, bool called_by_menubar);
private: private:
implement * impl_; implement * impl_;
}; };

View File

@ -134,6 +134,7 @@ namespace nana{ namespace widgets
std::size_t undo_max_steps() const; std::size_t undo_max_steps() const;
renderers& customized_renderers(); renderers& customized_renderers();
void clear_undo(); ///< same with undo_max_steps(0)
unsigned line_height() const; unsigned line_height() const;
unsigned screen_lines() const; unsigned screen_lines() const;
@ -148,14 +149,15 @@ namespace nana{ namespace widgets
* @param reset indicates whether to reset the text position by the pos. If this parameter is true, the text position is set by pos. If the parameter is false, it only moves the UI caret to the specified position. * @param reset indicates whether to reset the text position by the pos. If this parameter is true, the text position is set by pos. If the parameter is false, it only moves the UI caret to the specified position.
*/ */
bool move_caret(const upoint& pos, bool reset = false); bool move_caret(const upoint& pos, bool reset = false);
void move_caret_end(); void move_caret_end(bool update);
void reset_caret_pixels() const; void reset_caret_pixels() const;
void reset_caret(); void reset_caret();
void show_caret(bool isshow); void show_caret(bool isshow);
bool selected() const; bool selected() const;
bool get_selected_points(nana::upoint&, nana::upoint&) const;
bool select(bool); bool select(bool);
bool get_select_points(nana::upoint&, nana::upoint&) const;
/// Sets the end position of a selected string. /// Sets the end position of a selected string.
void set_end_caret(); void set_end_caret();

View File

@ -162,6 +162,9 @@ namespace nana
/// Read the text from a specified line. It returns true for success. /// Read the text from a specified line. It returns true for success.
bool getline(std::size_t pos, std::string&) const; bool getline(std::size_t pos, std::string&) const;
/// Read the text from a specified line with a set offset. It returns true for success.
bool getline(std::size_t line_index,std::size_t offset,std::string& text) const;
/// Gets the caret position /// Gets the caret position
/// Returns true if the caret is in the area of display, false otherwise. /// Returns true if the caret is in the area of display, false otherwise.
bool caret_pos(point& pos, bool text_coordinate) const; bool caret_pos(point& pos, bool text_coordinate) const;
@ -196,6 +199,7 @@ namespace nana
/// Returns true if some text is selected. /// Returns true if some text is selected.
bool selected() const; bool selected() const;
bool get_selected_points(nana::upoint &a, nana::upoint &b) const;
/// Selects/unselects all text. /// Selects/unselects all text.
void select(bool); void select(bool);
@ -215,6 +219,8 @@ namespace nana
textbox& from(int); textbox& from(int);
textbox& from(double); textbox& from(double);
void clear_undo();
void set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor); void set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor);
void erase_highlight(const std::string& name); void erase_highlight(const std::string& name);
void set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list<std::wstring> kw_list); void set_keywords(const std::string& name, bool case_sensitive, bool whole_word_match, std::initializer_list<std::wstring> kw_list);

View File

@ -51,6 +51,8 @@ namespace nana
bool italic() const; bool italic() const;
native_font_type handle() const; native_font_type handle() const;
void release(); void release();
bool strikeout() const;
bool underline() const;
font& operator=(const font&); font& operator=(const font&);
bool operator==(const font&) const; bool operator==(const font&) const;

View File

@ -54,11 +54,17 @@ namespace threads
struct task_signal; struct task_signal;
class impl; class impl;
pool(const pool&) = delete;
pool& operator=(const pool&) = delete;
public: public:
pool(); ///< Creates a group of threads. pool(); ///< Creates a group of threads.
pool(pool&&);
pool(std::size_t thread_number); ///< Creates a number of threads specifed by thread_number. pool(std::size_t thread_number); ///< Creates a number of threads specifed by thread_number.
~pool(); ///< waits for the all running tasks till they are finished and skips all the queued tasks. ~pool(); ///< waits for the all running tasks till they are finished and skips all the queued tasks.
pool& operator=(pool&&);
template<typename Function> template<typename Function>
void push(const Function& f) void push(const Function& f)
{ {

View File

@ -58,6 +58,15 @@ namespace detail
proc_.filter_proc = 0; proc_.filter_proc = 0;
} }
~msg_dispatcher()
{
if(thrd_ && thrd_->joinable())
{
is_work_ = false;
thrd_->join();
}
}
void set(timer_proc_type timer_proc, event_proc_type event_proc, event_filter_type filter) void set(timer_proc_type timer_proc, event_proc_type event_proc, event_filter_type filter)
{ {
proc_.timer_proc = timer_proc; proc_.timer_proc = timer_proc;

View File

@ -323,7 +323,7 @@ namespace nana
{ {
for (auto wd = this; wd; wd = wd->parent) for (auto wd = this; wd; wd = wd->parent)
{ {
if (basic_window::update_state::refresh == wd->other.upd_state) if (basic_window::update_state::refreshed == wd->other.upd_state)
return true; return true;
} }
return false; return false;

View File

@ -569,7 +569,10 @@ namespace detail
break; break;
msgwnd = wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); msgwnd = wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y);
if(nullptr == msgwnd) break;
pressed_wd = nullptr;
if(nullptr == msgwnd)
break;
if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
brock.erase_menu(true); brock.erase_menu(true);
@ -578,7 +581,9 @@ namespace detail
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {
bool dbl_click = (last_mouse_down_window == msgwnd) && (xevent.xbutton.time - last_mouse_down_time <= 400); pressed_wd = msgwnd;
const bool dbl_click = (last_mouse_down_window == msgwnd) && (xevent.xbutton.time - last_mouse_down_time <= 400);
last_mouse_down_time = xevent.xbutton.time; last_mouse_down_time = xevent.xbutton.time;
last_mouse_down_window = msgwnd; last_mouse_down_window = msgwnd;
@ -597,17 +602,12 @@ namespace detail
auto retain = msgwnd->annex.events_ptr; auto retain = msgwnd->annex.events_ptr;
context.event_window = msgwnd; context.event_window = msgwnd;
pressed_wd = nullptr;
msgwnd->set_action(mouse_action::pressed); msgwnd->set_action(mouse_action::pressed);
arg_mouse arg; arg_mouse arg;
assign_arg(arg, msgwnd, ButtonPress, xevent); assign_arg(arg, msgwnd, ButtonPress, xevent);
arg.evt_code = dbl_click ? event_code::dbl_click : event_code::mouse_down; arg.evt_code = dbl_click ? event_code::dbl_click : event_code::mouse_down;
if(brock.emit(arg.evt_code, msgwnd, arg, true, &context)) if (brock.emit(arg.evt_code, msgwnd, arg, true, &context))
{ {
if (wd_manager.available(msgwnd))
{
pressed_wd = msgwnd;
//If a root window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. //If a root window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event.
if (msgwnd->root != native_interface::get_focus_window()) if (msgwnd->root != native_interface::get_focus_window())
{ {
@ -618,7 +618,8 @@ namespace detail
wd_manager.do_lazy_refresh(msgwnd, false); wd_manager.do_lazy_refresh(msgwnd, false);
} }
} }
} else
pressed_wd = nullptr;
} }
break; break;
case ButtonRelease: case ButtonRelease:
@ -1157,7 +1158,9 @@ namespace detail
} }
++(context->event_pump_ref_count); ++(context->event_pump_ref_count);
wd_manager().internal_lock().revert();
auto & lock = wd_manager().internal_lock();
lock.revert();
native_window_type owner_native = 0; native_window_type owner_native = 0;
core_window_t * owner = 0; core_window_t * owner = 0;
@ -1183,7 +1186,8 @@ namespace detail
native_interface::enable_window(owner_native, true); native_interface::enable_window(owner_native, true);
} }
wd_manager().internal_lock().forward(); lock.forward();
if(0 == --(context->event_pump_ref_count)) if(0 == --(context->event_pump_ref_count))
{ {
if(0 == modal_window || 0 == context->window_count) if(0 == modal_window || 0 == context->window_count)
@ -1203,17 +1207,7 @@ namespace detail
{ {
thread_context* thrd = get_thread_context(0); thread_context* thrd = get_thread_context(0);
if(thrd && thrd->event_window) if(thrd && thrd->event_window)
{ thrd->event_window->other.upd_state = core_window_t::update_state::refreshed;
//the state none should be tested, becuase in an event, there would be draw after an update,
//if the none is not tested, the draw after update will not be refreshed.
switch(thrd->event_window->other.upd_state)
{
case core_window_t::update_state::none:
case core_window_t::update_state::lazy:
thrd->event_window->other.upd_state = core_window_t::update_state::refresh;
default: break;
}
}
} }
//Dynamically set a cursor for a window //Dynamically set a cursor for a window

View File

@ -919,7 +919,13 @@ namespace detail
break; break;
msgwnd = wd_manager.find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); msgwnd = wd_manager.find_window(native_window, pmdec.mouse.x, pmdec.mouse.y);
if ((nullptr == msgwnd) || (pressed_wd && (msgwnd != pressed_wd)))
//Don't take care about whether msgwnd is equal to the pressed_wd.
//
//pressed_wd will remains when opens a no-actived window in an mouse_down event(like combox popups the drop-list).
//After the no-actived window is closed, the window doesn't respond to the mouse click other than pressed_wd.
pressed_wd = nullptr;
if (nullptr == msgwnd)
break; break;
//if event on the menubar, just remove the menu if it is not associating with the menubar //if event on the menubar, just remove the menu if it is not associating with the menubar
@ -1691,17 +1697,7 @@ namespace detail
{ {
auto* thrd = get_thread_context(0); auto* thrd = get_thread_context(0);
if (thrd && thrd->event_window) if (thrd && thrd->event_window)
{ thrd->event_window->other.upd_state = core_window_t::update_state::refreshed;
//the state none should be tested, becuase in an event, there would be draw after an update,
//if the none is not tested, the draw after update will not be refreshed.
switch (thrd->event_window->other.upd_state)
{
case core_window_t::update_state::none:
case core_window_t::update_state::lazy:
thrd->event_window->other.upd_state = core_window_t::update_state::refresh;
default: break;
}
}
} }
//Dynamically set a cursor for a window //Dynamically set a cursor for a window

View File

@ -391,7 +391,7 @@ namespace nana
bool drawer::_m_lazy_decleared() const bool drawer::_m_lazy_decleared() const
{ {
return (basic_window::update_state::refresh == data_impl_->window_handle->other.upd_state); return (basic_window::update_state::refreshed == data_impl_->window_handle->other.upd_state);
} }
drawer::method_state& drawer::_m_mth_state(int pos) drawer::method_state& drawer::_m_mth_state(int pos)

View File

@ -22,26 +22,26 @@ namespace nana
namespace detail namespace detail
{ {
//class window_layout //class window_layout
void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed) void window_layout::paint(core_window_t* wd, paint_operation operation, bool req_refresh_children)
{ {
if (is_redraw && wd->flags.refreshing) if (wd->flags.refreshing && (paint_operation::try_refresh == operation))
return; return;
if (nullptr == wd->effect.bground) if (nullptr == wd->effect.bground)
{ {
if (is_redraw && (!wd->drawer.graphics.empty())) if ((paint_operation::try_refresh == operation) && (!wd->drawer.graphics.empty()))
{ {
wd->flags.refreshing = true; wd->flags.refreshing = true;
wd->drawer.refresh(); wd->drawer.refresh();
wd->flags.refreshing = false; wd->flags.refreshing = false;
} }
maproot(wd, is_redraw, is_child_refreshed); maproot(wd, (paint_operation::none != operation), req_refresh_children);
} }
else else
_m_paint_glass_window(wd, is_redraw, is_child_refreshed, false, true); _m_paint_glass_window(wd, (paint_operation::try_refresh == operation), req_refresh_children, false, true);
} }
bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool is_child_refreshed) bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool req_refresh_children)
{ {
auto check_opaque = wd->seek_non_lite_widget_ancestor(); auto check_opaque = wd->seek_non_lite_widget_ancestor();
if (check_opaque && check_opaque->flags.refreshing) if (check_opaque && check_opaque->flags.refreshing)
@ -56,7 +56,7 @@ namespace nana
if (category::flags::lite_widget != wd->other.category) if (category::flags::lite_widget != wd->other.category)
graph.bitblt(vr, wd->drawer.graphics, nana::point(vr.x - wd->pos_root.x, vr.y - wd->pos_root.y)); graph.bitblt(vr, wd->drawer.graphics, nana::point(vr.x - wd->pos_root.x, vr.y - wd->pos_root.y));
_m_paste_children(wd, is_child_refreshed, have_refreshed, vr, graph, nana::point()); _m_paste_children(wd, have_refreshed, req_refresh_children, vr, graph, nana::point());
if (wd->parent) if (wd->parent)
{ {
@ -81,11 +81,11 @@ namespace nana
graph.bitblt(el.r, (el.window->drawer.graphics), p_src); graph.bitblt(el.r, (el.window->drawer.graphics), p_src);
} }
_m_paste_children(el.window, is_child_refreshed, false, el.r, graph, nana::point{}); _m_paste_children(el.window, false, req_refresh_children, el.r, graph, nana::point{});
} }
} }
} }
_m_notify_glasses(wd, vr); _m_notify_glasses(wd);
return true; return true;
} }
return false; return false;
@ -255,8 +255,8 @@ namespace nana
if (category::flags::lite_widget != child->other.category) if (category::flags::lite_widget != child->other.category)
glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, child->drawer.graphics, {ovlp.position() - child->pos_owner}); glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, child->drawer.graphics, {ovlp.position() - child->pos_owner});
ovlp.x += wd->pos_root.x; ovlp.x += wd->parent->pos_root.x;
ovlp.y += wd->pos_root.y; ovlp.y += wd->parent->pos_root.y;
_m_paste_children(child, false, false, ovlp, glass_buffer, rpos); _m_paste_children(child, false, false, ovlp, glass_buffer, rpos);
} }
} }
@ -267,7 +267,7 @@ namespace nana
//_m_paste_children //_m_paste_children
//@brief:paste children window to the root graphics directly. just paste the visual rectangle //@brief:paste children window to the root graphics directly. just paste the visual rectangle
void window_layout::_m_paste_children(core_window_t* wd, bool is_child_refreshed, bool have_refreshed, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) void window_layout::_m_paste_children(core_window_t* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos)
{ {
nana::rectangle rect; nana::rectangle rect;
for (auto child : wd->children) for (auto child : wd->children)
@ -278,7 +278,7 @@ namespace nana
if (category::flags::root == child->other.category) if (category::flags::root == child->other.category)
{ {
paint(child, is_child_refreshed, is_child_refreshed); paint(child, (req_refresh_children ? paint_operation::try_refresh : paint_operation::none), req_refresh_children);
continue; continue;
} }
@ -289,7 +289,7 @@ namespace nana
bool have_child_refreshed = false; bool have_child_refreshed = false;
if (category::flags::lite_widget != child->other.category) if (category::flags::lite_widget != child->other.category)
{ {
if (is_child_refreshed && (false == child->flags.refreshing)) if (req_refresh_children && (false == child->flags.refreshing))
{ {
have_child_refreshed = true; have_child_refreshed = true;
child->flags.refreshing = true; child->flags.refreshing = true;
@ -300,13 +300,13 @@ namespace nana
graph.bitblt(nana::rectangle(rect.x - graph_rpos.x, rect.y - graph_rpos.y, rect.width, rect.height), graph.bitblt(nana::rectangle(rect.x - graph_rpos.x, rect.y - graph_rpos.y, rect.width, rect.height),
child->drawer.graphics, nana::point(rect.x - child->pos_root.x, rect.y - child->pos_root.y)); child->drawer.graphics, nana::point(rect.x - child->pos_root.x, rect.y - child->pos_root.y));
} }
_m_paste_children(child, is_child_refreshed, have_child_refreshed, rect, graph, graph_rpos); _m_paste_children(child, req_refresh_children, have_child_refreshed, rect, graph, graph_rpos);
} }
} }
else else
{ {
//If have_refreshed, the glass should be notified. //Update the glass window's background if the parent have_refreshed.
_m_paint_glass_window(child, false, is_child_refreshed, have_refreshed, false); _m_paint_glass_window(child, have_refreshed, req_refresh_children, true, false);
} }
} }
} }
@ -353,16 +353,14 @@ namespace nana
} }
if (notify_other) if (notify_other)
_m_notify_glasses(wd, vr); _m_notify_glasses(wd);
} }
} }
//_m_notify_glasses /// Notify the glass windows that are overlapped with the specified visual rectangle.
//@brief: Notify the glass windows that are overlapped with the specified vis_rect /// If a child window of sigwd is a glass window, it doesn't to be notified.
void window_layout::_m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& /*r_visual*/) void window_layout::_m_notify_glasses(core_window_t* const sigwd)
{ {
typedef category::flags cat_flags;
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension); nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
for (auto wd : data_sect.effects_bground_windows) for (auto wd : data_sect.effects_bground_windows)
{ {
@ -377,6 +375,8 @@ namespace nana
} }
else if (sigwd != wd->parent) else if (sigwd != wd->parent)
{ {
using cat_flags = category::flags;
if (wd->parent && (cat_flags::lite_widget == wd->parent->other.category)) if (wd->parent && (cat_flags::lite_widget == wd->parent->other.category))
{ {
//Test if sigwd is an ancestor of the glass window, and there are lite widgets //Test if sigwd is an ancestor of the glass window, and there are lite widgets

View File

@ -335,7 +335,7 @@ namespace detail
void window_manager::revertible_mutex::revert() void window_manager::revertible_mutex::revert()
{ {
if(impl_->thread.ref && (impl_->thread.tid == nana::system::this_thread_id())) if(impl_->thread.tid == nana::system::this_thread_id())
{ {
std::size_t cnt = impl_->thread.ref; std::size_t cnt = impl_->thread.ref;
@ -346,24 +346,30 @@ namespace detail
for (std::size_t i = 0; i < cnt; ++i) for (std::size_t i = 0; i < cnt; ++i)
impl_->mutex.unlock(); impl_->mutex.unlock();
} }
else
throw std::runtime_error("The revert is not allowed");
} }
void window_manager::revertible_mutex::forward() void window_manager::revertible_mutex::forward()
{ {
impl_->mutex.lock(); impl_->mutex.lock();
if(impl_->invoke_stack.size()) if(impl_->invoke_stack.size())
{ {
auto thr = impl_->invoke_stack.back(); auto thr = impl_->invoke_stack.back();
impl_->invoke_stack.pop_back();
if(thr.tid == nana::system::this_thread_id()) if(thr.tid == nana::system::this_thread_id())
{ {
impl_->invoke_stack.pop_back();
for (std::size_t i = 0; i < thr.ref; ++i) for (std::size_t i = 0; i < thr.ref; ++i)
impl_->mutex.lock(); impl_->mutex.lock();
impl_->thread = thr; impl_->thread = thr;
} }
else else
throw std::runtime_error("Nana.GUI: The forward is not matched."); throw std::runtime_error("The forward is not matched. Please report this issue");
} }
impl_->mutex.unlock(); impl_->mutex.unlock();
} }
//end class revertible_mutex //end class revertible_mutex
@ -759,6 +765,10 @@ namespace detail
arg.window_handle = reinterpret_cast<window>(wd); arg.window_handle = reinterpret_cast<window>(wd);
arg.x = x; arg.x = x;
arg.y = y; arg.y = y;
if (wd->effect.bground)
wd->other.upd_state = basic_window::update_state::request_refresh;
brock.emit(event_code::move, wd, arg, true, brock.get_thread_context()); brock.emit(event_code::move, wd, arg, true, brock.get_thread_context());
return true; return true;
} }
@ -803,6 +813,9 @@ namespace detail
_m_move_core(wd, delta); _m_move_core(wd, delta);
moved = true; moved = true;
if ((!size_changed) && wd->effect.bground)
wd->other.upd_state = basic_window::update_state::request_refresh;
arg_move arg; arg_move arg;
arg.window_handle = reinterpret_cast<window>(wd); arg.window_handle = reinterpret_cast<window>(wd);
arg.x = r.x; arg.x = r.x;
@ -989,26 +1002,28 @@ namespace detail
if (wd->displayed()) if (wd->displayed())
{ {
using paint_operation = window_layer::paint_operation;
if(forced || (false == wd->belong_to_lazy())) if(forced || (false == wd->belong_to_lazy()))
{ {
if (!wd->flags.refreshing) if (!wd->flags.refreshing)
{ {
window_layer::paint(wd, redraw, false); window_layer::paint(wd, (redraw ? paint_operation::try_refresh : paint_operation::none), false);
this->map(wd, forced, update_area); this->map(wd, forced, update_area);
return true; return true;
} }
else if (forced) else if (forced)
{ {
window_layer::paint(wd, false, false); window_layer::paint(wd, paint_operation::none, false);
this->map(wd, true, update_area); this->map(wd, true, update_area);
return true; return true;
} }
} }
else if (redraw) else if (redraw)
window_layer::paint(wd, true, false); window_layer::paint(wd, paint_operation::try_refresh, false);
if (wd->other.upd_state == core_window_t::update_state::lazy) if (wd->other.upd_state == core_window_t::update_state::lazy)
wd->other.upd_state = core_window_t::update_state::refresh; wd->other.upd_state = core_window_t::update_state::refreshed;
} }
return true; return true;
} }
@ -1020,43 +1035,43 @@ namespace detail
//It's not worthy to redraw if visible is false //It's not worthy to redraw if visible is false
if (impl_->wd_register.available(wd) && wd->displayed()) if (impl_->wd_register.available(wd) && wd->displayed())
window_layer::paint(wd, true, true); window_layer::paint(wd, window_layer::paint_operation::try_refresh, true);
} }
//do_lazy_refresh //do_lazy_refresh
//@brief: defined a behavior of flush the screen //@brief: defined a behavior of flush the screen
//@return: it returns true if the wnd is available void window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree)
bool window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree)
{ {
//Thread-Safe Required! //Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_); std::lock_guard<mutex_type> lock(mutex_);
if (false == impl_->wd_register.available(wd)) if (false == impl_->wd_register.available(wd))
return false; return;
//It's not worthy to redraw if visible is false //It's not worthy to redraw if visible is false
if(wd->visible && (!wd->is_draw_through())) if(wd->visible && (!wd->is_draw_through()))
{ {
using paint_operation = window_layer::paint_operation;
if (wd->visible_parents()) if (wd->visible_parents())
{ {
if ((wd->other.upd_state == core_window_t::update_state::refresh) || force_copy_to_screen) if ((wd->other.upd_state == core_window_t::update_state::refreshed) || (wd->other.upd_state == core_window_t::update_state::request_refresh) || force_copy_to_screen)
{ {
window_layer::paint(wd, false, refresh_tree); window_layer::paint(wd, (wd->other.upd_state == core_window_t::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree);
this->map(wd, force_copy_to_screen); this->map(wd, force_copy_to_screen);
} }
else if (effects::edge_nimbus::none != wd->effect.edge_nimbus) else if (effects::edge_nimbus::none != wd->effect.edge_nimbus)
{ {
//The window is still mapped because of edge nimbus effect. //The window is still mapped because of edge nimbus effect.
//Avoid duplicate copy if action state is not changed and the window is not focused. //Avoid duplicate copy if action state is not changed and the window is not focused.
if ((wd->flags.action != wd->flags.action_before) || (bedrock::instance().focus() == wd)) if (wd->flags.action != wd->flags.action_before)
this->map(wd, true); this->map(wd, true);
} }
} }
else else
window_layer::paint(wd, true, refresh_tree); //only refreshing if it has an invisible parent window_layer::paint(wd, paint_operation::try_refresh, refresh_tree); //only refreshing if it has an invisible parent
} }
wd->other.upd_state = core_window_t::update_state::none; wd->other.upd_state = core_window_t::update_state::none;
return true; return;
} }
//get_graphics //get_graphics

View File

@ -991,7 +991,6 @@ namespace API
} }
void modal_window(window wd) void modal_window(window wd)
{
{ {
auto const iwd = reinterpret_cast<basic_window*>(wd); auto const iwd = reinterpret_cast<basic_window*>(wd);
internal_scope_guard isg; internal_scope_guard isg;
@ -1009,16 +1008,14 @@ namespace API
} }
else else
return; return;
}
//modal has to guarantee that does not lock the mutex of window_manager before invokeing the pump_event,
//otherwise, the modal will prevent the other thread access the window.
restrict::bedrock.pump_event(wd, true); restrict::bedrock.pump_event(wd, true);
} }
void wait_for(window wd) void wait_for(window wd)
{ {
if (wd) internal_scope_guard lock;
if (restrict::wd_manager().available(reinterpret_cast<basic_window*>(wd)))
restrict::bedrock.pump_event(wd, false); restrict::bedrock.pump_event(wd, false);
} }

View File

@ -1,7 +1,7 @@
/** /**
* A group widget implementation * A group widget implementation
* Nana C++ Library(http://www.nanaro.org) * Nana C++ Library(http://www.nanaro.org)
* Copyright(C) 2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2015-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -36,6 +36,8 @@ namespace nana{
unsigned gap{2}; unsigned gap{2};
std::string usr_div_str; std::string usr_div_str;
nana::size caption_dimension;
std::vector<std::unique_ptr<checkbox>> options; std::vector<std::unique_ptr<checkbox>> options;
radio_group * radio_logic{nullptr}; radio_group * radio_logic{nullptr};
@ -60,19 +62,18 @@ namespace nana{
void update_div() void update_div()
{ {
::nana::size sz = caption.measure(1000); caption_dimension = caption.measure(1000);
std::stringstream ss; std::string div = "vert margin=[0," + std::to_string(gap) + "," + std::to_string(gap + 5) + "," + std::to_string(gap) + "]";
ss << "vert margin=[0," << gap << "," << gap + 5 << "," << gap << "]" div += "<weight=" + std::to_string(caption_dimension.height) + " <weight=5><" + field_title + " weight=" + std::to_string(caption_dimension.width + 1) + ">>";
<< " <weight=" << sz.height << " <weight=5> <" << field_title << " weight=" << sz.width + 1 << "> >" div += "<<vert margin=5 " + std::string(field_options) + ">";
<< "<<vert margin=5 " << field_options << ">";
if (!usr_div_str.empty()) if (!usr_div_str.empty())
ss << "<" << usr_div_str << ">>"; div += "<" + usr_div_str + ">>";
else else
ss << ">"; div += ">";
place_content.div(ss.str().c_str()); place_content.div(div.c_str());
if (options.empty()) if (options.empty())
place_content.field_display(field_options, false); place_content.field_display(field_options, false);
@ -202,25 +203,23 @@ namespace nana{
outter.collocate(); outter.collocate();
color pbg = API::bgcolor(this->parent()); color pbg = API::bgcolor(this->parent());
impl_->caption.bgcolor(pbg.blend(colors::black, 0.975));
color bg = pbg.blend(colors::black, 0.950);
bgcolor(bg); impl_->caption.bgcolor(pbg.blend(colors::black, 0.975));
this->bgcolor(pbg.blend(colors::black, 0.950));
drawing dw(*this); drawing dw(*this);
::nana::size sz = impl_->caption.measure(1000);
// This drawing function is owner by the onwer of dw (the outer panel of the group widget), not by dw !! // This drawing function is owner by the onwer of dw (the outer panel of the group widget), not by dw !!
dw.draw([this, sz, bg, pbg](paint::graphics& graph) dw.draw([this](paint::graphics& graph)
{ {
auto gap_px = impl_->gap - 1; auto gap_px = impl_->gap - 1;
graph.rectangle(true, pbg); graph.rectangle(true, API::bgcolor(this->parent()));
graph.round_rectangle(rectangle(point(gap_px, sz.height / 2), graph.round_rectangle(rectangle(point(gap_px, impl_->caption_dimension.height / 2),
nana::size(graph.width() - 2 * gap_px, graph.height() - sz.height / 2 - gap_px) nana::size(graph.width() - 2 * gap_px, graph.height() - impl_->caption_dimension.height / 2 - gap_px)
), ),
3, 3, colors::gray_border, true, bg); 3, 3, colors::gray_border, true, this->bgcolor());
}); });
} }

View File

@ -14,12 +14,15 @@
*/ */
#include <nana/gui/widgets/menu.hpp> #include <nana/gui/widgets/menu.hpp>
#include <nana/gui/timer.hpp>
#include <nana/system/platform.hpp> #include <nana/system/platform.hpp>
#include <nana/gui/element.hpp> #include <nana/gui/element.hpp>
#include <nana/gui/wvl.hpp> #include <nana/gui/wvl.hpp>
#include <nana/paint/text_renderer.hpp> #include <nana/paint/text_renderer.hpp>
#include <cctype> //introduces tolower #include <cctype> //introduces tolower
#include <map> #include <map>
#include <vector>
namespace nana namespace nana
{ {
@ -27,6 +30,20 @@ namespace nana
{ {
namespace menu namespace menu
{ {
struct menu_type
{
using item_type = menu_item_type;
using item_container = std::vector<std::unique_ptr<item_type>>;
using iterator = item_container::iterator;
std::vector<menu_type*> owner;
item_container items;
unsigned max_pixels;
unsigned item_pixels;
nana::point gaps;
};
//A helper function to check the style parameter //A helper function to check the style parameter
inline bool good_checks(checks s) inline bool good_checks(checks s)
{ {
@ -83,8 +100,8 @@ namespace nana
flags.checked = false; flags.checked = false;
} }
menu_item_type::menu_item_type(std::string text, const event_fn_t& f) menu_item_type::menu_item_type(std::string text, const event_fn_t& fn)
: text(std::move(text)), functor(f) : text(std::move(text)), event_handler(fn)
{ {
flags.enabled = true; flags.enabled = true;
flags.splitter = false; flags.splitter = false;
@ -153,10 +170,10 @@ namespace nana
//Stretchs menu icon only when it doesn't fit, center it otherwise. //Stretchs menu icon only when it doesn't fit, center it otherwise.
//Contributed by kmribti(pr#102) //Contributed by kmribti(pr#102)
nana::point ipos = pos; img.paste(graph, {
ipos.x += (image_px - img.size().width ) / 2; pos.x + static_cast<int>(image_px - img.size().width) / 2,
ipos.y += (image_px - img.size().height) / 2; pos.y + static_cast<int>(image_px - img.size().height) / 2
img.paste(graph, ipos); });
} }
void item_text(graph_reference graph, const nana::point& pos, const std::string& text, unsigned text_pixels, const attr& at) void item_text(graph_reference graph, const nana::point& pos, const std::string& text, unsigned text_pixels, const attr& at)
@ -183,11 +200,9 @@ namespace nana
: noncopyable : noncopyable
{ {
public: public:
typedef menu_item_type item_type; using item_type = menu_item_type;
using event_fn_t = item_type::event_fn_t;
typedef menu_type::item_container::value_type::event_fn_t event_fn_t; using iterator = menu_type::item_container::iterator;
typedef menu_type::item_container::iterator iterator;
typedef menu_type::item_container::const_iterator const_iterator;
menu_builder() menu_builder()
{ {
@ -206,40 +221,42 @@ namespace nana
if(good_checks(s)) if(good_checks(s))
{ {
if(root_.items.size() > index) if(root_.items.size() > index)
root_.items[index].style = s; root_.items[index]->style = s;
} }
} }
void checked(std::size_t index, bool check) void checked(std::size_t pos, bool check)
{ {
if (root_.items.size() <= index) if (root_.items.size() <= pos)
return; return;
item_type & m = root_.items[index]; item_type & m = *(root_.items[pos]);
if(check && (checks::option == m.style)) if(check && (checks::option == m.style))
{ {
if(index) //find a splitter in front of pos
if (pos > 0)
{ {
std::size_t i = index;
do do
{ {
item_type& el = root_.items[--i]; if (root_.items[--pos]->flags.splitter)
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]; ++pos;
break;
}
}while(pos > 0);
}
while (pos < root_.items.size())
{
item_type & el = *(root_.items[pos++]);
if(el.flags.splitter) break; if(el.flags.splitter) break;
if(checks::option == el.style) if(checks::option == el.style)
el.flags.checked = false; el.flags.checked = false;
} }
} }
m.flags.checked = check; m.flags.checked = check;
} }
@ -248,25 +265,12 @@ namespace nana
return root_; return root_;
} }
const menu_type& data() const
{
return root_;
}
void insert(std::size_t pos, std::string&& text, const event_fn_t& fn)
{
if(pos < root_.items.size())
root_.items.emplace(root_.items.begin() + pos, std::move(text), std::ref(fn));
else
root_.items.emplace_back(std::move(text), std::ref(fn));
}
bool set_sub_menu(std::size_t pos, menu_type &sub) bool set_sub_menu(std::size_t pos, menu_type &sub)
{ {
if(root_.items.size() > pos) if(root_.items.size() > pos)
{ {
menu_item_type & item = root_.items[pos]; auto & item = *(root_.items[pos]);
if(item.sub_menu == nullptr) if(!item.sub_menu)
{ {
item.sub_menu = &sub; item.sub_menu = &sub;
sub.owner.emplace_back(&root_); sub.owner.emplace_back(&root_);
@ -281,17 +285,17 @@ namespace nana
for(auto i : root_.owner) for(auto i : root_.owner)
for(auto & m : i->items) for(auto & m : i->items)
{ {
if(m.sub_menu == &root_) if(m->sub_menu == &root_)
m.sub_menu = nullptr; m->sub_menu = nullptr;
} }
for(auto & m : root_.items) for(auto & m : root_.items)
{ {
if(m.sub_menu) if(m->sub_menu)
for(auto i = m.sub_menu->owner.begin(); i != m.sub_menu->owner.end();) for(auto i = m->sub_menu->owner.begin(); i != m->sub_menu->owner.end();)
{ {
if((*i) == &root_) if((*i) == &root_)
i = m.sub_menu->owner.erase(i); i = m->sub_menu->owner.erase(i);
else else
++i; ++i;
} }
@ -318,8 +322,6 @@ namespace nana
public: public:
using item_proxy = menu_item_type::item_proxy; using item_proxy = menu_item_type::item_proxy;
renderer_interface * renderer;
menu_drawer() menu_drawer()
{ {
state_.active = npos; state_.active = npos;
@ -329,9 +331,16 @@ namespace nana
detail_.border.x = detail_.border.y = 2; detail_.border.x = detail_.border.y = 2;
} }
void close_menu_tree(std::function<void()> && fn) void set_run(menu_builder& mbuilder, menu_type& menu, std::function<void()> && menu_tree_destroyer)
{ {
fn_close_tree_ = std::move(fn); mbuilder_ = &mbuilder;
menu_ = &menu;
fn_close_tree_ = std::move(menu_tree_destroyer);
}
menu_builder& mbuilder()
{
return *mbuilder_;
} }
void attached(widget_reference widget, graph_reference graph) void attached(widget_reference widget, graph_reference graph)
@ -364,10 +373,12 @@ namespace nana
void refresh(graph_reference graph) void refresh(graph_reference graph)
{ {
if (nullptr == menu_) return; if (!(mbuilder_ && menu_))
return;
_m_adjust_window_size(); _m_adjust_window_size();
auto renderer = mbuilder_->renderer().get();
renderer->background(graph, *widget_); renderer->background(graph, *widget_);
const unsigned item_h_px = _m_item_height(); const unsigned item_h_px = _m_item_height();
@ -376,12 +387,13 @@ namespace nana
unsigned strpixels = item_r.width - 60; unsigned strpixels = item_r.width - 60;
int text_top_off = (item_h_px - graph.text_extent_size(L"jh({[").height) / 2; int text_top_off = static_cast<int>(item_h_px - graph.text_extent_size(L"jh({[").height) / 2;
std::size_t pos = 0; std::size_t pos = 0;
for (auto & m : menu_->items) for (auto & m : menu_->items)
{ {
if (m.flags.splitter) auto item_ptr = m.get();
if (item_ptr->flags.splitter)
{ {
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph.width()) - 1, item_r.y }, colors::gray_border); graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph.width()) - 1, item_r.y }, colors::gray_border);
item_r.y += 2; item_r.y += 2;
@ -389,24 +401,24 @@ namespace nana
continue; continue;
} }
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m); renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, *item_ptr);
//Draw item background //Draw item background
renderer->item(*graph_, item_r, attr); renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character //Draw text, the text is transformed from orignal for hotkey character
wchar_t hotkey; wchar_t hotkey;
std::string::size_type hotkey_pos; std::string::size_type hotkey_pos;
auto text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos); auto text = API::transform_shortkey_text(item_ptr->text, hotkey, &hotkey_pos);
if (m.image.empty() == false) if (item_ptr->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_image(graph, nana::point(item_r.x + 5, item_r.y + static_cast<int>(item_h_px - image_px) / 2 - 1), image_px, item_ptr->image);
renderer->item_text(graph, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr); renderer->item_text(graph, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if (hotkey) if (hotkey)
{ {
m.hotkey = hotkey; item_ptr->hotkey = hotkey;
if (m.flags.enabled) if (item_ptr->flags.enabled)
{ {
auto off_px = (hotkey_pos ? graph.text_extent_size(text.c_str(), hotkey_pos).width : 0); auto off_px = (hotkey_pos ? graph.text_extent_size(text.c_str(), hotkey_pos).width : 0);
auto hotkey_px = graph.text_extent_size(text.c_str() + hotkey_pos, 1).width; auto hotkey_px = graph.text_extent_size(text.c_str() + hotkey_pos, 1).width;
@ -421,7 +433,7 @@ namespace nana
} }
} }
if (m.sub_menu) if (item_ptr->sub_menu)
renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr); renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1; item_r.y += item_r.height + 1;
@ -438,11 +450,14 @@ namespace nana
bool goto_next(bool forword) bool goto_next(bool forword)
{ {
state_.nullify_mouse = true; state_.nullify_mouse = true;
if (menu_->items.empty())
auto & items = menu_->items;
if (items.empty())
return false; return false;
auto pos = state_.active; auto pos = state_.active;
const auto lastpos = menu_->items.size() - 1; const auto lastpos = items.size() - 1;
bool end = false; bool end = false;
while(true) while(true)
@ -477,7 +492,8 @@ namespace nana
--pos; --pos;
} }
if(! menu_->items.at(pos).flags.splitter && menu_->items.at(pos).flags.enabled) auto item_ptr = items.at(pos).get();
if (!item_ptr->flags.splitter && item_ptr->flags.enabled)
break; break;
} }
@ -497,13 +513,14 @@ namespace nana
{ {
if (!state_.nullify_mouse) if (!state_.nullify_mouse)
{ {
auto & items = menu_->items;
std::size_t index = _m_get_index_by_pos(pos.x, pos.y); std::size_t index = _m_get_index_by_pos(pos.x, pos.y);
if (index != state_.active) if (index != state_.active)
{ {
if ((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window) if ((index == npos) && items.at(state_.active)->sub_menu && state_.sub_window)
return false; return false;
state_.active = (index != npos && menu_->items.at(index).flags.splitter) ? npos : index; state_.active = (index != npos && items.at(index)->flags.splitter) ? npos : index;
state_.active_timestamp = nana::system::timestamp(); state_.active_timestamp = nana::system::timestamp();
return true; return true;
} }
@ -512,11 +529,6 @@ namespace nana
return false; return false;
} }
void data(menu_type & menu)
{
menu_ = & menu;
}
menu_type* data() const menu_type* data() const
{ {
return menu_; return menu_;
@ -532,19 +544,20 @@ namespace nana
if (npos == state_.active) if (npos == state_.active)
return nullptr; return nullptr;
auto sub = menu_->items.at(state_.active).sub_menu; auto & items = menu_->items;
auto sub = items.at(state_.active)->sub_menu;
if (sub) if (sub)
{ {
pos.x = static_cast<int>(graph_->width()) - 2; pos.x = static_cast<int>(graph_->width()) - 2;
pos.y = 2; pos.y = 2;
auto index = state_.active; auto index = state_.active;
for (auto & m : menu_->items) for (auto & m : items)
{ {
if (0 == index--) if (0 == index--)
break; break;
if (m.flags.splitter) if (m->flags.splitter)
{ {
pos.y += 2; pos.y += 2;
continue; continue;
@ -566,15 +579,16 @@ namespace nana
std::size_t index = 0; std::size_t index = 0;
for(auto & m : menu_->items) for(auto & m : menu_->items)
{ {
if (std::tolower(m.hotkey) != key) auto item_ptr = m.get();
if (std::tolower(m->hotkey) != key)
{ {
++index; ++index;
continue; continue;
} }
if(!m.flags.splitter) if (!item_ptr->flags.splitter)
{ {
if(m.sub_menu) if (item_ptr->sub_menu)
{ {
state_.active = index; state_.active = index;
state_.active_timestamp = nana::system::timestamp(); state_.active_timestamp = nana::system::timestamp();
@ -582,13 +596,13 @@ namespace nana
API::refresh_window(*widget_); API::refresh_window(*widget_);
return 2; return 2;
} }
else if(m.flags.enabled) else if (item_ptr->flags.enabled)
{ {
fn_close_tree_(); fn_close_tree_();
if (m.functor) if (item_ptr->event_handler)
{ {
item_proxy ip(index, m); item_proxy ip(index, *item_ptr);
m.functor.operator()(ip); item_ptr->event_handler.operator()(ip);
} }
return 1; return 1;
} }
@ -618,9 +632,9 @@ namespace nana
int pos = detail_.border.y; int pos = detail_.border.y;
std::size_t index = 0; std::size_t index = 0;
for(auto & m : menu_->items) for (auto & m : menu_->items)
{ {
unsigned h = (m.flags.splitter ? 1 : _m_item_height()); unsigned h = (m->flags.splitter ? 1 : _m_item_height());
if(pos <= y && y < static_cast<int>(pos + h)) if(pos <= y && y < static_cast<int>(pos + h))
return index; return index;
else if(y < pos) else if(y < pos)
@ -641,13 +655,13 @@ namespace nana
{ {
nana::size size; nana::size size;
if(menu_->items.size()) if (menu_->items.size())
{ {
for(auto & m : menu_->items) for (auto & m : menu_->items)
{ {
if(false == m.flags.splitter) if(false == m->flags.splitter)
{ {
nana::size item_size = graph_->text_extent_size(m.text); nana::size item_size = graph_->text_extent_size(m->text);
if(size.width < item_size.width) if(size.width < item_size.width)
size.width = item_size.width; size.width = item_size.width;
} }
@ -659,7 +673,7 @@ namespace nana
size.height = static_cast<unsigned>(menu_->items.size() - size.height) * _m_item_height() + size.height + static_cast<unsigned>(menu_->items.size() - 1); size.height = static_cast<unsigned>(menu_->items.size() - size.height) * _m_item_height() + size.height + static_cast<unsigned>(menu_->items.size() - 1);
} }
if(size.width > menu_->max_pixels) if (size.width > menu_->max_pixels)
size.width = menu_->max_pixels; size.width = menu_->max_pixels;
return size; return size;
@ -688,14 +702,15 @@ namespace nana
pos.y = scr_area.bottom() - static_cast<int>(size.height); pos.y = scr_area.bottom() - static_cast<int>(size.height);
if(pos.y < scr_area.y) pos.y = scr_area.y; if(pos.y < scr_area.y) pos.y = scr_area.y;
auto owner = API::get_owner_window(*widget_); API::calc_window_point(API::get_owner_window(*widget_), pos);
API::calc_window_point(owner, pos);
widget_->move(pos.x, pos.y); widget_->move(pos.x, pos.y);
} }
private: private:
widget *widget_{nullptr}; widget *widget_{nullptr};
paint::graphics *graph_{nullptr}; paint::graphics *graph_{nullptr};
menu_type *menu_{nullptr};
menu_builder* mbuilder_{ nullptr };
menu_type* menu_{ nullptr };
std::function<void()> fn_close_tree_; std::function<void()> fn_close_tree_;
@ -723,7 +738,7 @@ namespace nana
using item_type = menu_builder::item_type; using item_type = menu_builder::item_type;
menu_window(window wd, bool is_wd_parent_menu, const point& pos, renderer_interface * rdptr) menu_window(window wd, bool is_wd_parent_menu, const point& pos, menu_builder& mbuilder, menu_type& menu_data)
//add a is_wd_parent_menu to determine whether the menu wants the focus. //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 //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>()), : base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()),
@ -731,8 +746,8 @@ namespace nana
event_focus_{ nullptr } event_focus_{ nullptr }
{ {
caption("nana menu window"); caption("nana menu window");
get_drawer_trigger().close_menu_tree([this]{ this->_m_close_all(); }); get_drawer_trigger().set_run(mbuilder, menu_data, [this]{ this->_m_close_all(); });
get_drawer_trigger().renderer = rdptr;
state_.owner_menubar = state_.self_submenu = false; state_.owner_menubar = state_.self_submenu = false;
state_.auto_popup_submenu = true; state_.auto_popup_submenu = true;
@ -740,7 +755,7 @@ namespace nana
submenu_.object = nullptr; submenu_.object = nullptr;
state_.mouse_pos = API::cursor_position(); state_.mouse_pos = API::cursor_position();
events().mouse_move.connect_unignorable([this]{ events().mouse_move.connect_unignorable([this](const arg_mouse&){
nana::point pos = API::cursor_position(); nana::point pos = API::cursor_position();
if (pos != state_.mouse_pos) if (pos != state_.mouse_pos)
{ {
@ -754,10 +769,8 @@ namespace nana
}); });
} }
void popup(menu_type& menu, bool owner_menubar) void popup(bool owner_menubar)
{ {
get_drawer_trigger().data(menu);
if (!want_focus_) if (!want_focus_)
{ {
API::activate_window(this->parent()); API::activate_window(this->parent());
@ -771,7 +784,7 @@ namespace nana
} }
auto & events = this->events(); auto & events = this->events();
events.destroy.connect_unignorable([this]{ events.destroy.connect_unignorable([this](const arg_destroy&){
_m_destroy(); _m_destroy();
}); });
@ -881,7 +894,7 @@ namespace nana
if ((npos == active) || !menu) if ((npos == active) || !menu)
return; return;
menu_item_type & item = menu->items.at(active); menu_item_type & item = *(menu->items.at(active));
if ((!item.flags.enabled) || item.flags.splitter || item.sub_menu) if ((!item.flags.enabled) || item.flags.splitter || item.sub_menu)
return; return;
@ -892,35 +905,18 @@ namespace nana
} }
else if (checks::option == item.style) else if (checks::option == item.style)
{ {
//Forward Looks for a splitter get_drawer_trigger().mbuilder().checked(active, true);
auto pos = active;
while (pos)
{
if (menu->items.at(--pos).flags.splitter)
break;
}
for (; pos < menu->items.size(); ++pos)
{
menu_item_type & im = menu->items.at(pos);
if (im.flags.splitter) break;
if ((checks::option == im.style) && im.flags.checked)
im.flags.checked = false;
}
item.flags.checked = true;
} }
this->_m_close_all(); //means deleting this; this->_m_close_all(); //means deleting this;
//The deleting operation has moved here, because item.functor.operator()(ip) //The deleting operation has moved here, because item.event_handler.operator()(ip)
//may create a window, which make a killing focus for menu window, if so the close_all //may create a window, which make a killing focus for menu window, if so the close_all
//operation preformences after item.functor.operator()(ip), that would be deleting this object twice! //operation preformences after item.event_handler.operator()(ip), that would be deleting this object twice!
if (item.functor) if (item.event_handler)
{ {
item_type::item_proxy ip(active, item); item_type::item_proxy ip(active, item);
item.functor.operator()(ip); item.event_handler.operator()(ip);
} }
} }
private: private:
@ -1035,7 +1031,7 @@ namespace nana
menu_ptr->gaps = drawer.data()->gaps; menu_ptr->gaps = drawer.data()->gaps;
pos += menu_ptr->gaps; pos += menu_ptr->gaps;
menu_window & mwnd = form_loader<menu_window, false>()(handle(), true, pos, drawer.renderer); menu_window & mwnd = form_loader<menu_window, false>()(handle(), true, pos, drawer.mbuilder(), *menu_ptr);
mwnd.state_.self_submenu = true; mwnd.state_.self_submenu = true;
submenu_.child = &mwnd; submenu_.child = &mwnd;
submenu_.child->submenu_.parent = this; submenu_.child->submenu_.parent = this;
@ -1043,7 +1039,7 @@ namespace nana
API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none); API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none);
mwnd.popup(*menu_ptr, state_.owner_menubar); mwnd.popup(state_.owner_menubar);
drawer.set_sub_window(true); drawer.set_sub_window(true);
if (forced) if (forced)
mwnd.goto_next(true); mwnd.goto_next(true);
@ -1100,7 +1096,7 @@ namespace nana
}; };
drawerbase::menu::menu_builder mbuilder; drawerbase::menu::menu_builder mbuilder;
drawerbase::menu::menu_window * uiobj; drawerbase::menu::menu_window * window_ptr;
std::function<void()> destroy_answer; std::function<void()> destroy_answer;
std::map<std::size_t, info> sub_container; std::map<std::size_t, info> sub_container;
}; };
@ -1108,7 +1104,7 @@ namespace nana
menu::menu() menu::menu()
:impl_(new implement) :impl_(new implement)
{ {
impl_->uiobj = nullptr; impl_->window_ptr = nullptr;
} }
menu::~menu() menu::~menu()
@ -1123,32 +1119,34 @@ namespace nana
auto menu::append(std::string text_utf8, const menu::event_fn_t& f) -> item_proxy auto menu::append(std::string text_utf8, const menu::event_fn_t& f) -> item_proxy
{ {
impl_->mbuilder.data().items.emplace_back(std::move(text_utf8), f); impl_->mbuilder.data().items.emplace_back(new item_type(std::move(text_utf8, callback));
return item_proxy(size() - 1, impl_->mbuilder.data().items.back()); return item_proxy(size() - 1, *impl_->mbuilder.data().items.back());
} }
void menu::append_splitter() void menu::append_splitter()
{ {
impl_->mbuilder.data().items.emplace_back(); impl_->mbuilder.data().items.emplace_back(new item_type);
} }
void menu::clear() void menu::clear()
{ {
internal_scope_guard lock;
impl_->mbuilder.data().items.clear(); impl_->mbuilder.data().items.clear();
} }
void menu::enabled(std::size_t index, bool enable) void menu::enabled(std::size_t index, bool enable)
{ {
impl_->mbuilder.data().items.at(index).flags.enabled = enable; impl_->mbuilder.data().items.at(index)->flags.enabled = enable;
} }
bool menu::enabled(std::size_t index) const bool menu::enabled(std::size_t index) const
{ {
return impl_->mbuilder.data().items.at(index).flags.enabled; return impl_->mbuilder.data().items.at(index)->flags.enabled;
} }
void menu::erase(std::size_t index) void menu::erase(std::size_t index)
{ {
internal_scope_guard lock;
auto & items = impl_->mbuilder.data().items; auto & items = impl_->mbuilder.data().items;
if(index < items.size()) if(index < items.size())
items.erase(items.begin() + index); items.erase(items.begin() + index);
@ -1156,7 +1154,7 @@ namespace nana
void menu::image(std::size_t index, const paint::image& img) void menu::image(std::size_t index, const paint::image& img)
{ {
impl_->mbuilder.data().items.at(index).image = img; impl_->mbuilder.data().items.at(index)->image = img;
} }
void menu::text(std::size_t index, std::string text_utf8) void menu::text(std::size_t index, std::string text_utf8)
@ -1202,22 +1200,22 @@ namespace nana
void menu::popup(window wd, int x, int y) void menu::popup(window wd, int x, int y)
{ {
_m_popup(wd, x, y, false); _m_popup(wd, { x, y }, false);
} }
void menu::popup_await(window wd, int x, int y) void menu::popup_await(window wd, int x, int y)
{ {
_m_popup(wd, x, y, false); _m_popup(wd, { x, y }, false);
if (impl_->uiobj) if (impl_->window_ptr)
API::wait_for(impl_->uiobj->handle()); API::wait_for(impl_->window_ptr->handle());
} }
void menu::close() void menu::close()
{ {
if(impl_->uiobj) if (impl_->window_ptr)
{ {
impl_->uiobj->close(); impl_->window_ptr->close();
impl_->uiobj = nullptr; impl_->window_ptr = nullptr;
} }
} }
@ -1233,17 +1231,17 @@ namespace nana
bool menu::checked(std::size_t index) const bool menu::checked(std::size_t index) const
{ {
return impl_->mbuilder.data().items.at(index).flags.checked; return impl_->mbuilder.data().items.at(index)->flags.checked;
} }
void menu::answerer(std::size_t index, const event_fn_t& fn) void menu::answerer(std::size_t index, const event_fn_t& fn)
{ {
impl_->mbuilder.data().items.at(index).functor = fn; impl_->mbuilder.data().items.at(index)->event_handler = fn;
} }
void menu::destroy_answer(const std::function<void()>& fn) void menu::destroy_answer(std::function<void()> fn)
{ {
impl_->destroy_answer = fn; impl_->destroy_answer = std::move(fn);
} }
void menu::gaps(const nana::point& pos) void menu::gaps(const nana::point& pos)
@ -1253,18 +1251,18 @@ namespace nana
void menu::goto_next(bool forward) void menu::goto_next(bool forward)
{ {
if(impl_->uiobj) if (impl_->window_ptr)
impl_->uiobj->goto_next(forward); impl_->window_ptr->goto_next(forward);
} }
bool menu::goto_submen() bool menu::goto_submen()
{ {
return (impl_->uiobj ? impl_->uiobj->submenu(true) : false); return (impl_->window_ptr ? impl_->window_ptr->submenu(true) : false);
} }
bool menu::exit_submenu() bool menu::exit_submenu()
{ {
return (impl_->uiobj ? impl_->uiobj->submenu(false) : false); return (impl_->window_ptr ? impl_->window_ptr->submenu(false) : false);
} }
std::size_t menu::size() const std::size_t menu::size() const
@ -1274,13 +1272,13 @@ namespace nana
int menu::send_shortkey(wchar_t key) int menu::send_shortkey(wchar_t key)
{ {
return (impl_->uiobj ? impl_->uiobj->send_shortkey(key) : 0); return (impl_->window_ptr ? impl_->window_ptr->send_shortkey(key) : 0);
} }
void menu::pick() void menu::pick()
{ {
if (impl_->uiobj) if (impl_->window_ptr)
impl_->uiobj->pick(); impl_->window_ptr->pick();
} }
menu& menu::max_pixels(unsigned px) menu& menu::max_pixels(unsigned px)
@ -1315,19 +1313,19 @@ namespace nana
impl_->mbuilder.renderer(rd); impl_->mbuilder.renderer(rd);
} }
void menu::_m_popup(window wd, int x, int y, bool called_by_menubar) void menu::_m_popup(window wd, const point& pos, bool called_by_menubar)
{ {
if (impl_->mbuilder.data().items.size()) if (impl_->mbuilder.data().items.size())
{ {
close(); close();
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, false, point(x, y), &(*impl_->mbuilder.renderer()))); impl_->window_ptr = &(form_loader<drawerbase::menu::menu_window, false>()(wd, false, pos, impl_->mbuilder, impl_->mbuilder.data()));
impl_->uiobj->events().destroy.connect_unignorable([this]{ impl_->window_ptr->events().destroy.connect_unignorable([this](const arg_destroy&){
impl_->uiobj = nullptr; impl_->window_ptr = nullptr;
if (impl_->destroy_answer) if (impl_->destroy_answer)
impl_->destroy_answer(); impl_->destroy_answer();
}); });
impl_->uiobj->popup(impl_->mbuilder.data(), called_by_menubar); impl_->window_ptr->popup(called_by_menubar);
} }
} }
//end class menu //end class menu

View File

@ -20,7 +20,7 @@ namespace nana
public: public:
static void popup(menu& m, window wd, int x, int y) static void popup(menu& m, window wd, int x, int y)
{ {
m._m_popup(wd, x, y, true); m._m_popup(wd, { x, y }, true);
} }
}; };

View File

@ -1574,7 +1574,8 @@ namespace nana{ namespace widgets
_m_handle_move_key(arg); _m_handle_move_key(arg);
break; break;
case keyboard::os_del: case keyboard::os_del:
if (this->attr().editable) // send delete to set_accept function
if (this->attr().editable && (!impl_->capacities.pred_acceptive || impl_->capacities.pred_acceptive(key)))
del(); del();
break; break;
default: default:
@ -1746,6 +1747,13 @@ namespace nana{ namespace widgets
return impl_->undo.max_steps(); return impl_->undo.max_steps();
} }
void text_editor::clear_undo()
{
auto size = impl_->undo.max_steps();
impl_->undo.max_steps(0);
impl_->undo.max_steps(size);
}
auto text_editor::customized_renderers() -> renderers& auto text_editor::customized_renderers() -> renderers&
{ {
return impl_->customized_renderers; return impl_->customized_renderers;
@ -1797,7 +1805,7 @@ namespace nana{ namespace widgets
if (select_all) if (select_all)
{ {
select(true); select(true);
move_caret_end(); move_caret_end(false);
renderred = true; renderred = true;
//If the text widget is focused by clicking mouse button, the selected text will be cancelled //If the text widget is focused by clicking mouse button, the selected text will be cancelled
@ -1991,8 +1999,6 @@ namespace nana{ namespace widgets
return str; return str;
} }
//move_caret
//Set caret position through text coordinate
bool text_editor::move_caret(const upoint& crtpos, bool reset_caret) bool text_editor::move_caret(const upoint& crtpos, bool reset_caret)
{ {
const unsigned line_pixels = line_height(); const unsigned line_pixels = line_height();
@ -2036,11 +2042,14 @@ namespace nana{ namespace widgets
return false; return false;
} }
void text_editor::move_caret_end() void text_editor::move_caret_end(bool update)
{ {
points_.caret.y = static_cast<unsigned>(impl_->textbase.lines()); points_.caret.y = static_cast<unsigned>(impl_->textbase.lines());
if(points_.caret.y) --points_.caret.y; if(points_.caret.y) --points_.caret.y;
points_.caret.x = static_cast<unsigned>(impl_->textbase.getline(points_.caret.y).size()); points_.caret.x = static_cast<unsigned>(impl_->textbase.getline(points_.caret.y).size());
if (update)
this->move_caret(points_.caret, false);
} }
void text_editor::reset_caret_pixels() const void text_editor::reset_caret_pixels() const
@ -2064,6 +2073,25 @@ namespace nana{ namespace widgets
return (select_.a != select_.b); return (select_.a != select_.b);
} }
bool text_editor::get_selected_points(nana::upoint &a, nana::upoint &b) const
{
if (select_.a == select_.b)
return false;
if (select_.a < select_.b)
{
a = select_.a;
b = select_.b;
}
else
{
a = select_.b;
b = select_.a;
}
return true;
}
void text_editor::set_end_caret() void text_editor::set_end_caret()
{ {
bool new_sel_end = (select_.b != points_.caret); bool new_sel_end = (select_.b != points_.caret);
@ -2096,25 +2124,6 @@ namespace nana{ namespace widgets
return false; return false;
} }
bool text_editor::get_select_points(nana::upoint& a, nana::upoint& b) const
{
if (select_.a == select_.b)
return false;
if (select_.a < select_.b)
{
a = select_.a;
b = select_.b;
}
else
{
a = select_.b;
b = select_.a;
}
return true;
}
bool text_editor::hit_text_area(const point& pos) const bool text_editor::hit_text_area(const point& pos) const
{ {
return _m_text_area().is_hit(pos); return _m_text_area().is_hit(pos);
@ -2123,7 +2132,7 @@ namespace nana{ namespace widgets
bool text_editor::hit_select_area(nana::upoint pos, bool ignore_when_select_all) const bool text_editor::hit_select_area(nana::upoint pos, bool ignore_when_select_all) const
{ {
nana::upoint a, b; nana::upoint a, b;
if(get_select_points(a, b)) if (get_selected_points(a, b))
{ {
if (ignore_when_select_all) if (ignore_when_select_all)
{ {
@ -3045,7 +3054,7 @@ namespace nana{ namespace widgets
nana::upoint text_editor::_m_erase_select() nana::upoint text_editor::_m_erase_select()
{ {
nana::upoint a, b; nana::upoint a, b;
if (get_select_points(a, b)) if (get_selected_points(a, b))
{ {
auto & textbase = this->textbase(); auto & textbase = this->textbase();
if(a.y != b.y) if(a.y != b.y)
@ -3076,7 +3085,7 @@ namespace nana{ namespace widgets
std::wstring text; std::wstring text;
nana::upoint a, b; nana::upoint a, b;
if (get_select_points(a, b)) if (get_selected_points(a, b))
{ {
auto & textbase = this->textbase(); auto & textbase = this->textbase();
if (a.y != b.y) if (a.y != b.y)
@ -3167,7 +3176,7 @@ namespace nana{ namespace widgets
bool text_editor::_m_cancel_select(int align) bool text_editor::_m_cancel_select(int align)
{ {
nana::upoint a, b; nana::upoint a, b;
if (get_select_points(a, b)) if (get_selected_points(a, b))
{ {
switch(align) switch(align)
{ {
@ -3262,7 +3271,7 @@ namespace nana{ namespace widgets
const bool at_left = (select_.b < select_.a); const bool at_left = (select_.b < select_.a);
nana::upoint a, b; nana::upoint a, b;
get_select_points(a, b); get_selected_points(a, b);
if (caret.y < a.y || (caret.y == a.y && caret.x < a.x)) if (caret.y < a.y || (caret.y == a.y && caret.x < a.x))
{//forward {//forward
undo_ptr->set_caret_pos(); undo_ptr->set_caret_pos();
@ -3458,7 +3467,7 @@ namespace nana{ namespace widgets
const wchar_t *sbegin = nullptr, *send = nullptr; const wchar_t *sbegin = nullptr, *send = nullptr;
nana::upoint a, b; nana::upoint a, b;
if (get_select_points(a, b)) if (get_selected_points(a, b))
{ {
if (a.y < text_coord.y && text_coord.y < b.y) if (a.y < text_coord.y && text_coord.y < b.y)
{ {

View File

@ -69,10 +69,10 @@ namespace drawerbase {
auto scheme = API::dev::get_scheme(wdg); auto scheme = API::dev::get_scheme(wdg);
editor_ = new text_editor(wd, graph, dynamic_cast<::nana::widgets::skeletons::text_editor_scheme*>(scheme)); editor_ = new text_editor(wd, graph, dynamic_cast<::nana::widgets::skeletons::text_editor_scheme*>(scheme));
editor_->textbase().set_event_agent(evt_agent_.get());
editor_->set_event(evt_agent_.get());
evt_agent_.reset(new event_agent(static_cast<::nana::textbox&>(wdg), editor_->text_position())); evt_agent_.reset(new event_agent(static_cast<::nana::textbox&>(wdg), editor_->text_position()));
editor_->textbase().set_event_agent(evt_agent_.get());
editor_->set_event(evt_agent_.get());
_m_text_area(graph.width(), graph.height()); _m_text_area(graph.width(), graph.height());
@ -261,7 +261,10 @@ namespace drawerbase {
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if (editor) if (editor)
{ {
editor->text(to_wstring(str), end_caret); editor->text(to_wstring(str), false);
if (end_caret)
editor->move_caret_end(true);
editor->textbase().reset(); editor->textbase().reset();
API::update_window(this->handle()); API::update_window(this->handle());
@ -319,6 +322,25 @@ namespace drawerbase {
return false; return false;
} }
bool textbox::getline(std::size_t line_index,std::size_t start_point,std::string& text) const
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
if(editor)
{
std::wstring line_text;
if(editor->getline(line_index,line_text))
{
if(line_text.length() >= start_point)
{
text = to_utf8(line_text.substr(start_point));
return true;
}
}
}
return false;
}
/// Gets the caret position /// Gets the caret position
bool textbox::caret_pos(point& pos, bool text_coordinate) const bool textbox::caret_pos(point& pos, bool text_coordinate) const
{ {
@ -358,7 +380,7 @@ namespace drawerbase {
if(editor) if(editor)
{ {
if(at_caret == false) if(at_caret == false)
editor->move_caret_end(); editor->move_caret_end(false);
editor->put(to_wstring(text)); editor->put(to_wstring(text));
API::update_window(this->handle()); API::update_window(this->handle());
@ -461,6 +483,13 @@ namespace drawerbase {
return (editor ? editor->selected() : false); return (editor ? editor->selected() : false);
} }
bool textbox::get_selected_points(nana::upoint &a, nana::upoint &b) const
{
internal_scope_guard lock;
auto editor = get_drawer_trigger().editor();
return (editor ? editor->get_selected_points(a, b) : false);
}
void textbox::select(bool yes) void textbox::select(bool yes)
{ {
internal_scope_guard lock; internal_scope_guard lock;
@ -476,7 +505,7 @@ namespace drawerbase {
internal_scope_guard lock; internal_scope_guard lock;
auto editor = get_drawer_trigger().editor(); auto editor = get_drawer_trigger().editor();
if (editor) if (editor)
editor->get_select_points(points.first, points.second); editor->get_selected_points(points.first, points.second);
return points; return points;
} }
@ -539,6 +568,11 @@ namespace drawerbase {
return *this; return *this;
} }
void textbox::clear_undo()
{
get_drawer_trigger().editor()->clear_undo();
}
void textbox::set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor) void textbox::set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor)
{ {
internal_scope_guard lock; internal_scope_guard lock;

View File

@ -46,6 +46,7 @@ namespace nana
void pump() void pump()
{ {
internal_scope_guard lock;
detail::bedrock::instance().pump_event(nullptr, false); detail::bedrock::instance().pump_event(nullptr, false);
} }

View File

@ -156,6 +156,18 @@ namespace paint
return (impl_->font_ptr->italic); return (impl_->font_ptr->italic);
} }
bool font::underline() const
{
if(empty()) return false;
return (impl_->font_ptr->underline);
}
bool font::strikeout() const
{
if(empty()) return false;
return (impl_->font_ptr->strikeout);
}
native_font_type font::handle() const native_font_type font::handle() const
{ {
if(empty()) return nullptr; if(empty()) return nullptr;

View File

@ -356,11 +356,28 @@ namespace threads
{ {
} }
pool::pool(pool&& other)
: pool()
{
std::swap(impl_, other.impl_);
}
pool::pool(std::size_t thread_number) pool::pool(std::size_t thread_number)
: impl_(new impl(thread_number)) : impl_(new impl(thread_number))
{ {
} }
pool& pool::operator=(pool&& other)
{
if(this != &other)
{
delete impl_;
impl_ = other.impl_;
other.impl_ = new impl(4);
}
return *this;
}
pool::~pool() pool::~pool()
{ {
delete impl_; delete impl_;