Merge branch 'hotfix-1.4.1' into develop
This commit is contained in:
commit
b1ce0eaff2
@ -102,7 +102,7 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#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: 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.
|
||||
|
@ -85,7 +85,7 @@ namespace detail
|
||||
|
||||
enum class update_state
|
||||
{
|
||||
none, lazy, refresh
|
||||
none, lazy, refreshed, request_refresh
|
||||
};
|
||||
|
||||
struct edge_nimbus_action
|
||||
|
@ -86,7 +86,7 @@ namespace nana{
|
||||
}
|
||||
|
||||
//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);
|
||||
action.rendered = true;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -42,10 +42,16 @@ namespace detail
|
||||
core_window_t * window;
|
||||
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);
|
||||
|
||||
@ -68,13 +74,12 @@ namespace detail
|
||||
|
||||
//_m_paste_children
|
||||
//@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);
|
||||
|
||||
//_m_notify_glasses
|
||||
//@brief: Notify the glass windows that are overlapped with the specified vis_rect
|
||||
static void _m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& r_visual);
|
||||
//Notify the windows which have brground to update their background buffer.
|
||||
static void _m_notify_glasses(core_window_t* const sigwd);
|
||||
private:
|
||||
struct data_section
|
||||
{
|
||||
|
@ -124,7 +124,7 @@ namespace detail
|
||||
bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr);
|
||||
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_visual_rectangle(core_window_t*, nana::rectangle&);
|
||||
|
@ -14,10 +14,7 @@
|
||||
#ifndef NANA_GUI_WIDGETS_MENU_HPP
|
||||
#define NANA_GUI_WIDGETS_MENU_HPP
|
||||
#include "widget.hpp"
|
||||
#include <vector>
|
||||
#include <nana/gui/timer.hpp>
|
||||
#include <nana/pat/cloneable.hpp>
|
||||
|
||||
#include <nana/push_ignore_diagnostic>
|
||||
|
||||
namespace nana
|
||||
@ -72,25 +69,12 @@ namespace nana
|
||||
|
||||
menu_type *sub_menu{nullptr};
|
||||
std::string text;
|
||||
event_fn_t functor;
|
||||
event_fn_t event_handler;
|
||||
checks style{checks::none};
|
||||
paint::image image;
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -158,7 +142,7 @@ namespace nana
|
||||
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 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 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.
|
||||
@ -177,7 +161,7 @@ namespace nana
|
||||
const pat::cloneable<renderer_interface>& renderer() const;
|
||||
|
||||
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:
|
||||
implement * impl_;
|
||||
};
|
||||
|
@ -134,6 +134,7 @@ namespace nana{ namespace widgets
|
||||
std::size_t undo_max_steps() const;
|
||||
|
||||
renderers& customized_renderers();
|
||||
void clear_undo(); ///< same with undo_max_steps(0)
|
||||
|
||||
unsigned line_height() 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.
|
||||
*/
|
||||
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();
|
||||
void show_caret(bool isshow);
|
||||
|
||||
bool selected() const;
|
||||
bool get_selected_points(nana::upoint&, nana::upoint&) const;
|
||||
|
||||
bool select(bool);
|
||||
bool get_select_points(nana::upoint&, nana::upoint&) const;
|
||||
|
||||
/// Sets the end position of a selected string.
|
||||
void set_end_caret();
|
||||
|
@ -162,6 +162,9 @@ namespace nana
|
||||
/// Read the text from a specified line. It returns true for success.
|
||||
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
|
||||
/// Returns true if the caret is in the area of display, false otherwise.
|
||||
bool caret_pos(point& pos, bool text_coordinate) const;
|
||||
@ -196,6 +199,7 @@ namespace nana
|
||||
|
||||
/// Returns true if some text is selected.
|
||||
bool selected() const;
|
||||
bool get_selected_points(nana::upoint &a, nana::upoint &b) const;
|
||||
|
||||
/// Selects/unselects all text.
|
||||
void select(bool);
|
||||
@ -215,6 +219,8 @@ namespace nana
|
||||
textbox& from(int);
|
||||
textbox& from(double);
|
||||
|
||||
void clear_undo();
|
||||
|
||||
void set_highlight(const std::string& name, const ::nana::color& fgcolor, const ::nana::color& bgcolor);
|
||||
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);
|
||||
|
@ -51,6 +51,8 @@ namespace nana
|
||||
bool italic() const;
|
||||
native_font_type handle() const;
|
||||
void release();
|
||||
bool strikeout() const;
|
||||
bool underline() const;
|
||||
|
||||
font& operator=(const font&);
|
||||
bool operator==(const font&) const;
|
||||
|
@ -54,11 +54,17 @@ namespace threads
|
||||
|
||||
struct task_signal;
|
||||
class impl;
|
||||
|
||||
pool(const pool&) = delete;
|
||||
pool& operator=(const pool&) = delete;
|
||||
public:
|
||||
pool(); ///< Creates a group of threads.
|
||||
pool(pool&&);
|
||||
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& operator=(pool&&);
|
||||
|
||||
template<typename Function>
|
||||
void push(const Function& f)
|
||||
{
|
||||
|
@ -58,6 +58,15 @@ namespace detail
|
||||
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)
|
||||
{
|
||||
proc_.timer_proc = timer_proc;
|
||||
|
@ -323,7 +323,7 @@ namespace nana
|
||||
{
|
||||
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 false;
|
||||
|
@ -567,9 +567,12 @@ namespace detail
|
||||
|
||||
if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5)
|
||||
break;
|
||||
|
||||
|
||||
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))
|
||||
brock.erase_menu(true);
|
||||
@ -578,7 +581,9 @@ namespace detail
|
||||
|
||||
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_window = msgwnd;
|
||||
|
||||
@ -597,28 +602,24 @@ namespace detail
|
||||
auto retain = msgwnd->annex.events_ptr;
|
||||
context.event_window = msgwnd;
|
||||
|
||||
pressed_wd = nullptr;
|
||||
|
||||
msgwnd->set_action(mouse_action::pressed);
|
||||
arg_mouse arg;
|
||||
assign_arg(arg, msgwnd, ButtonPress, xevent);
|
||||
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))
|
||||
//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())
|
||||
{
|
||||
pressed_wd = msgwnd;
|
||||
//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())
|
||||
{
|
||||
//call the drawer mouse up event for restoring the surface graphics
|
||||
msgwnd->set_action(mouse_action::normal);
|
||||
//call the drawer mouse up event for restoring the surface graphics
|
||||
msgwnd->set_action(mouse_action::normal);
|
||||
|
||||
draw_invoker(&drawer::mouse_up, msgwnd, arg, &context);
|
||||
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
}
|
||||
draw_invoker(&drawer::mouse_up, msgwnd, arg, &context);
|
||||
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
pressed_wd = nullptr;
|
||||
}
|
||||
break;
|
||||
case ButtonRelease:
|
||||
@ -1157,7 +1158,9 @@ namespace detail
|
||||
}
|
||||
|
||||
++(context->event_pump_ref_count);
|
||||
wd_manager().internal_lock().revert();
|
||||
|
||||
auto & lock = wd_manager().internal_lock();
|
||||
lock.revert();
|
||||
|
||||
native_window_type owner_native = 0;
|
||||
core_window_t * owner = 0;
|
||||
@ -1182,8 +1185,9 @@ namespace detail
|
||||
owner->flags.enabled = true;
|
||||
native_interface::enable_window(owner_native, true);
|
||||
}
|
||||
|
||||
wd_manager().internal_lock().forward();
|
||||
|
||||
lock.forward();
|
||||
|
||||
if(0 == --(context->event_pump_ref_count))
|
||||
{
|
||||
if(0 == modal_window || 0 == context->window_count)
|
||||
@ -1203,17 +1207,7 @@ namespace detail
|
||||
{
|
||||
thread_context* thrd = get_thread_context(0);
|
||||
if(thrd && thrd->event_window)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
}
|
||||
thrd->event_window->other.upd_state = core_window_t::update_state::refreshed;
|
||||
}
|
||||
|
||||
//Dynamically set a cursor for a window
|
||||
|
@ -919,7 +919,13 @@ namespace detail
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
//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);
|
||||
if (thrd && thrd->event_window)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
}
|
||||
thrd->event_window->other.upd_state = core_window_t::update_state::refreshed;
|
||||
}
|
||||
|
||||
//Dynamically set a cursor for a window
|
||||
|
@ -391,7 +391,7 @@ namespace nana
|
||||
|
||||
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)
|
||||
|
@ -22,26 +22,26 @@ namespace nana
|
||||
namespace detail
|
||||
{
|
||||
//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;
|
||||
|
||||
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->drawer.refresh();
|
||||
wd->flags.refreshing = false;
|
||||
}
|
||||
maproot(wd, is_redraw, is_child_refreshed);
|
||||
maproot(wd, (paint_operation::none != operation), req_refresh_children);
|
||||
}
|
||||
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();
|
||||
if (check_opaque && check_opaque->flags.refreshing)
|
||||
@ -56,7 +56,7 @@ namespace nana
|
||||
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));
|
||||
|
||||
_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)
|
||||
{
|
||||
@ -81,11 +81,11 @@ namespace nana
|
||||
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 false;
|
||||
@ -255,8 +255,8 @@ namespace nana
|
||||
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});
|
||||
|
||||
ovlp.x += wd->pos_root.x;
|
||||
ovlp.y += wd->pos_root.y;
|
||||
ovlp.x += wd->parent->pos_root.x;
|
||||
ovlp.y += wd->parent->pos_root.y;
|
||||
_m_paste_children(child, false, false, ovlp, glass_buffer, rpos);
|
||||
}
|
||||
}
|
||||
@ -267,7 +267,7 @@ namespace nana
|
||||
|
||||
//_m_paste_children
|
||||
//@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;
|
||||
for (auto child : wd->children)
|
||||
@ -278,7 +278,7 @@ namespace nana
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ namespace nana
|
||||
bool have_child_refreshed = false;
|
||||
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;
|
||||
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),
|
||||
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
|
||||
{
|
||||
//If have_refreshed, the glass should be notified.
|
||||
_m_paint_glass_window(child, false, is_child_refreshed, have_refreshed, false);
|
||||
//Update the glass window's background if the parent have_refreshed.
|
||||
_m_paint_glass_window(child, have_refreshed, req_refresh_children, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -353,16 +353,14 @@ namespace nana
|
||||
}
|
||||
|
||||
if (notify_other)
|
||||
_m_notify_glasses(wd, vr);
|
||||
_m_notify_glasses(wd);
|
||||
}
|
||||
}
|
||||
|
||||
//_m_notify_glasses
|
||||
//@brief: Notify the glass windows that are overlapped with the specified vis_rect
|
||||
void window_layout::_m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& /*r_visual*/)
|
||||
/// Notify the glass windows that are overlapped with the specified visual rectangle.
|
||||
/// 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)
|
||||
{
|
||||
typedef category::flags cat_flags;
|
||||
|
||||
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
|
||||
for (auto wd : data_sect.effects_bground_windows)
|
||||
{
|
||||
@ -377,6 +375,8 @@ namespace nana
|
||||
}
|
||||
else if (sigwd != wd->parent)
|
||||
{
|
||||
using cat_flags = category::flags;
|
||||
|
||||
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
|
||||
|
@ -335,7 +335,7 @@ namespace detail
|
||||
|
||||
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;
|
||||
|
||||
@ -346,24 +346,30 @@ namespace detail
|
||||
for (std::size_t i = 0; i < cnt; ++i)
|
||||
impl_->mutex.unlock();
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("The revert is not allowed");
|
||||
}
|
||||
|
||||
void window_manager::revertible_mutex::forward()
|
||||
{
|
||||
impl_->mutex.lock();
|
||||
|
||||
if(impl_->invoke_stack.size())
|
||||
{
|
||||
auto thr = impl_->invoke_stack.back();
|
||||
|
||||
impl_->invoke_stack.pop_back();
|
||||
|
||||
if(thr.tid == nana::system::this_thread_id())
|
||||
{
|
||||
impl_->invoke_stack.pop_back();
|
||||
for (std::size_t i = 0; i < thr.ref; ++i)
|
||||
impl_->mutex.lock();
|
||||
impl_->thread = thr;
|
||||
}
|
||||
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();
|
||||
}
|
||||
//end class revertible_mutex
|
||||
@ -759,6 +765,10 @@ namespace detail
|
||||
arg.window_handle = reinterpret_cast<window>(wd);
|
||||
arg.x = x;
|
||||
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());
|
||||
return true;
|
||||
}
|
||||
@ -803,6 +813,9 @@ namespace detail
|
||||
_m_move_core(wd, delta);
|
||||
moved = true;
|
||||
|
||||
if ((!size_changed) && wd->effect.bground)
|
||||
wd->other.upd_state = basic_window::update_state::request_refresh;
|
||||
|
||||
arg_move arg;
|
||||
arg.window_handle = reinterpret_cast<window>(wd);
|
||||
arg.x = r.x;
|
||||
@ -989,26 +1002,28 @@ namespace detail
|
||||
|
||||
if (wd->displayed())
|
||||
{
|
||||
using paint_operation = window_layer::paint_operation;
|
||||
|
||||
if(forced || (false == wd->belong_to_lazy()))
|
||||
{
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
else if (forced)
|
||||
{
|
||||
window_layer::paint(wd, false, false);
|
||||
window_layer::paint(wd, paint_operation::none, false);
|
||||
this->map(wd, true, update_area);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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)
|
||||
wd->other.upd_state = core_window_t::update_state::refresh;
|
||||
wd->other.upd_state = core_window_t::update_state::refreshed;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1020,43 +1035,43 @@ namespace detail
|
||||
|
||||
//It's not worthy to redraw if visible is false
|
||||
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
|
||||
//@brief: defined a behavior of flush the screen
|
||||
//@return: it returns true if the wnd is available
|
||||
bool window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree)
|
||||
void window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree)
|
||||
{
|
||||
//Thread-Safe Required!
|
||||
std::lock_guard<mutex_type> lock(mutex_);
|
||||
|
||||
if (false == impl_->wd_register.available(wd))
|
||||
return false;
|
||||
return;
|
||||
|
||||
//It's not worthy to redraw if visible is false
|
||||
if(wd->visible && (!wd->is_draw_through()))
|
||||
{
|
||||
using paint_operation = window_layer::paint_operation;
|
||||
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);
|
||||
}
|
||||
else if (effects::edge_nimbus::none != wd->effect.edge_nimbus)
|
||||
{
|
||||
//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.
|
||||
if ((wd->flags.action != wd->flags.action_before) || (bedrock::instance().focus() == wd))
|
||||
if (wd->flags.action != wd->flags.action_before)
|
||||
this->map(wd, true);
|
||||
}
|
||||
}
|
||||
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;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
//get_graphics
|
||||
|
@ -992,33 +992,30 @@ namespace API
|
||||
|
||||
void modal_window(window wd)
|
||||
{
|
||||
auto const iwd = reinterpret_cast<basic_window*>(wd);
|
||||
internal_scope_guard isg;
|
||||
|
||||
if (!restrict::wd_manager().available(iwd))
|
||||
return;
|
||||
|
||||
if ((iwd->other.category == category::flags::root) && (iwd->flags.modal == false))
|
||||
{
|
||||
auto const iwd = reinterpret_cast<basic_window*>(wd);
|
||||
internal_scope_guard isg;
|
||||
|
||||
if (!restrict::wd_manager().available(iwd))
|
||||
return;
|
||||
|
||||
if ((iwd->other.category == category::flags::root) && (iwd->flags.modal == false))
|
||||
{
|
||||
iwd->flags.modal = true;
|
||||
iwd->flags.modal = true;
|
||||
#if defined(NANA_X11)
|
||||
interface_type::set_modal(iwd->root);
|
||||
interface_type::set_modal(iwd->root);
|
||||
#endif
|
||||
restrict::wd_manager().show(iwd, true);
|
||||
}
|
||||
else
|
||||
return;
|
||||
restrict::wd_manager().show(iwd, true);
|
||||
}
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A group widget implementation
|
||||
* 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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -36,6 +36,8 @@ namespace nana{
|
||||
unsigned gap{2};
|
||||
std::string usr_div_str;
|
||||
|
||||
nana::size caption_dimension;
|
||||
|
||||
std::vector<std::unique_ptr<checkbox>> options;
|
||||
radio_group * radio_logic{nullptr};
|
||||
|
||||
@ -60,19 +62,18 @@ namespace nana{
|
||||
|
||||
void update_div()
|
||||
{
|
||||
::nana::size sz = caption.measure(1000);
|
||||
caption_dimension = caption.measure(1000);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "vert margin=[0," << gap << "," << gap + 5 << "," << gap << "]"
|
||||
<< " <weight=" << sz.height << " <weight=5> <" << field_title << " weight=" << sz.width + 1 << "> >"
|
||||
<< "<<vert margin=5 " << field_options << ">";
|
||||
std::string div = "vert margin=[0," + std::to_string(gap) + "," + std::to_string(gap + 5) + "," + std::to_string(gap) + "]";
|
||||
div += "<weight=" + std::to_string(caption_dimension.height) + " <weight=5><" + field_title + " weight=" + std::to_string(caption_dimension.width + 1) + ">>";
|
||||
div += "<<vert margin=5 " + std::string(field_options) + ">";
|
||||
|
||||
if (!usr_div_str.empty())
|
||||
ss << "<" << usr_div_str << ">>";
|
||||
div += "<" + usr_div_str + ">>";
|
||||
else
|
||||
ss << ">";
|
||||
div += ">";
|
||||
|
||||
place_content.div(ss.str().c_str());
|
||||
place_content.div(div.c_str());
|
||||
|
||||
if (options.empty())
|
||||
place_content.field_display(field_options, false);
|
||||
@ -202,25 +203,23 @@ namespace nana{
|
||||
outter.collocate();
|
||||
|
||||
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);
|
||||
|
||||
::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 !!
|
||||
dw.draw([this, sz, bg, pbg](paint::graphics& graph)
|
||||
dw.draw([this](paint::graphics& graph)
|
||||
{
|
||||
auto gap_px = impl_->gap - 1;
|
||||
|
||||
graph.rectangle(true, pbg);
|
||||
graph.round_rectangle(rectangle(point(gap_px, sz.height / 2),
|
||||
nana::size(graph.width() - 2 * gap_px, graph.height() - sz.height / 2 - gap_px)
|
||||
graph.rectangle(true, API::bgcolor(this->parent()));
|
||||
graph.round_rectangle(rectangle(point(gap_px, impl_->caption_dimension.height / 2),
|
||||
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());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,15 @@
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/menu.hpp>
|
||||
#include <nana/gui/timer.hpp>
|
||||
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <nana/gui/element.hpp>
|
||||
#include <nana/gui/wvl.hpp>
|
||||
#include <nana/paint/text_renderer.hpp>
|
||||
#include <cctype> //introduces tolower
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
@ -27,6 +30,20 @@ namespace nana
|
||||
{
|
||||
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
|
||||
inline bool good_checks(checks s)
|
||||
{
|
||||
@ -83,8 +100,8 @@ namespace nana
|
||||
flags.checked = false;
|
||||
}
|
||||
|
||||
menu_item_type::menu_item_type(std::string text, const event_fn_t& f)
|
||||
: text(std::move(text)), functor(f)
|
||||
menu_item_type::menu_item_type(std::string text, const event_fn_t& fn)
|
||||
: text(std::move(text)), event_handler(fn)
|
||||
{
|
||||
flags.enabled = true;
|
||||
flags.splitter = false;
|
||||
@ -153,10 +170,10 @@ namespace nana
|
||||
|
||||
//Stretchs menu icon only when it doesn't fit, center it otherwise.
|
||||
//Contributed by kmribti(pr#102)
|
||||
nana::point ipos = pos;
|
||||
ipos.x += (image_px - img.size().width ) / 2;
|
||||
ipos.y += (image_px - img.size().height) / 2;
|
||||
img.paste(graph, ipos);
|
||||
img.paste(graph, {
|
||||
pos.x + static_cast<int>(image_px - img.size().width) / 2,
|
||||
pos.y + static_cast<int>(image_px - img.size().height) / 2
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
typedef menu_item_type item_type;
|
||||
|
||||
typedef menu_type::item_container::value_type::event_fn_t event_fn_t;
|
||||
typedef menu_type::item_container::iterator iterator;
|
||||
typedef menu_type::item_container::const_iterator const_iterator;
|
||||
using item_type = menu_item_type;
|
||||
using event_fn_t = item_type::event_fn_t;
|
||||
using iterator = menu_type::item_container::iterator;
|
||||
|
||||
menu_builder()
|
||||
{
|
||||
@ -206,40 +221,42 @@ namespace nana
|
||||
if(good_checks(s))
|
||||
{
|
||||
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;
|
||||
|
||||
item_type & m = root_.items[index];
|
||||
item_type & m = *(root_.items[pos]);
|
||||
|
||||
if(check && (checks::option == m.style))
|
||||
{
|
||||
if(index)
|
||||
//find a splitter in front of pos
|
||||
if (pos > 0)
|
||||
{
|
||||
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);
|
||||
if (root_.items[--pos]->flags.splitter)
|
||||
{
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}while(pos > 0);
|
||||
}
|
||||
|
||||
for(std::size_t i = index + 1; i < root_.items.size(); ++i)
|
||||
while (pos < root_.items.size())
|
||||
{
|
||||
item_type & el = root_.items[i];
|
||||
item_type & el = *(root_.items[pos++]);
|
||||
if(el.flags.splitter) break;
|
||||
|
||||
if(checks::option == el.style)
|
||||
el.flags.checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
m.flags.checked = check;
|
||||
}
|
||||
|
||||
@ -248,25 +265,12 @@ namespace nana
|
||||
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)
|
||||
{
|
||||
if(root_.items.size() > pos)
|
||||
{
|
||||
menu_item_type & item = root_.items[pos];
|
||||
if(item.sub_menu == nullptr)
|
||||
auto & item = *(root_.items[pos]);
|
||||
if(!item.sub_menu)
|
||||
{
|
||||
item.sub_menu = ⊂
|
||||
sub.owner.emplace_back(&root_);
|
||||
@ -281,17 +285,17 @@ namespace nana
|
||||
for(auto i : root_.owner)
|
||||
for(auto & m : i->items)
|
||||
{
|
||||
if(m.sub_menu == &root_)
|
||||
m.sub_menu = nullptr;
|
||||
if(m->sub_menu == &root_)
|
||||
m->sub_menu = nullptr;
|
||||
}
|
||||
|
||||
for(auto & m : root_.items)
|
||||
{
|
||||
if(m.sub_menu)
|
||||
for(auto i = m.sub_menu->owner.begin(); i != m.sub_menu->owner.end();)
|
||||
if(m->sub_menu)
|
||||
for(auto i = m->sub_menu->owner.begin(); i != m->sub_menu->owner.end();)
|
||||
{
|
||||
if((*i) == &root_)
|
||||
i = m.sub_menu->owner.erase(i);
|
||||
i = m->sub_menu->owner.erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
@ -318,8 +322,6 @@ namespace nana
|
||||
public:
|
||||
using item_proxy = menu_item_type::item_proxy;
|
||||
|
||||
renderer_interface * renderer;
|
||||
|
||||
menu_drawer()
|
||||
{
|
||||
state_.active = npos;
|
||||
@ -329,9 +331,16 @@ namespace nana
|
||||
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)
|
||||
@ -364,10 +373,12 @@ namespace nana
|
||||
|
||||
void refresh(graph_reference graph)
|
||||
{
|
||||
if (nullptr == menu_) return;
|
||||
if (!(mbuilder_ && menu_))
|
||||
return;
|
||||
|
||||
_m_adjust_window_size();
|
||||
|
||||
auto renderer = mbuilder_->renderer().get();
|
||||
renderer->background(graph, *widget_);
|
||||
|
||||
const unsigned item_h_px = _m_item_height();
|
||||
@ -376,12 +387,13 @@ namespace nana
|
||||
|
||||
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;
|
||||
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);
|
||||
item_r.y += 2;
|
||||
@ -389,24 +401,24 @@ namespace nana
|
||||
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
|
||||
renderer->item(*graph_, item_r, attr);
|
||||
|
||||
//Draw text, the text is transformed from orignal for hotkey character
|
||||
wchar_t hotkey;
|
||||
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)
|
||||
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);
|
||||
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, item_ptr->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)
|
||||
item_ptr->hotkey = hotkey;
|
||||
if (item_ptr->flags.enabled)
|
||||
{
|
||||
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;
|
||||
@ -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);
|
||||
|
||||
item_r.y += item_r.height + 1;
|
||||
@ -438,11 +450,14 @@ namespace nana
|
||||
bool goto_next(bool forword)
|
||||
{
|
||||
state_.nullify_mouse = true;
|
||||
if (menu_->items.empty())
|
||||
|
||||
auto & items = menu_->items;
|
||||
|
||||
if (items.empty())
|
||||
return false;
|
||||
|
||||
auto pos = state_.active;
|
||||
const auto lastpos = menu_->items.size() - 1;
|
||||
const auto lastpos = items.size() - 1;
|
||||
|
||||
bool end = false;
|
||||
while(true)
|
||||
@ -477,7 +492,8 @@ namespace nana
|
||||
--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;
|
||||
}
|
||||
|
||||
@ -497,13 +513,14 @@ namespace nana
|
||||
{
|
||||
if (!state_.nullify_mouse)
|
||||
{
|
||||
auto & items = menu_->items;
|
||||
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) && items.at(state_.active)->sub_menu && state_.sub_window)
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
@ -512,11 +529,6 @@ namespace nana
|
||||
return false;
|
||||
}
|
||||
|
||||
void data(menu_type & menu)
|
||||
{
|
||||
menu_ = & menu;
|
||||
}
|
||||
|
||||
menu_type* data() const
|
||||
{
|
||||
return menu_;
|
||||
@ -532,19 +544,20 @@ namespace nana
|
||||
if (npos == state_.active)
|
||||
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)
|
||||
{
|
||||
pos.x = static_cast<int>(graph_->width()) - 2;
|
||||
pos.y = 2;
|
||||
|
||||
auto index = state_.active;
|
||||
for (auto & m : menu_->items)
|
||||
for (auto & m : items)
|
||||
{
|
||||
if (0 == index--)
|
||||
break;
|
||||
|
||||
if (m.flags.splitter)
|
||||
if (m->flags.splitter)
|
||||
{
|
||||
pos.y += 2;
|
||||
continue;
|
||||
@ -566,15 +579,16 @@ namespace nana
|
||||
std::size_t index = 0;
|
||||
for(auto & m : menu_->items)
|
||||
{
|
||||
if (std::tolower(m.hotkey) != key)
|
||||
auto item_ptr = m.get();
|
||||
if (std::tolower(m->hotkey) != key)
|
||||
{
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!m.flags.splitter)
|
||||
if (!item_ptr->flags.splitter)
|
||||
{
|
||||
if(m.sub_menu)
|
||||
if (item_ptr->sub_menu)
|
||||
{
|
||||
state_.active = index;
|
||||
state_.active_timestamp = nana::system::timestamp();
|
||||
@ -582,13 +596,13 @@ namespace nana
|
||||
API::refresh_window(*widget_);
|
||||
return 2;
|
||||
}
|
||||
else if(m.flags.enabled)
|
||||
else if (item_ptr->flags.enabled)
|
||||
{
|
||||
fn_close_tree_();
|
||||
if (m.functor)
|
||||
if (item_ptr->event_handler)
|
||||
{
|
||||
item_proxy ip(index, m);
|
||||
m.functor.operator()(ip);
|
||||
item_proxy ip(index, *item_ptr);
|
||||
item_ptr->event_handler.operator()(ip);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -618,9 +632,9 @@ namespace nana
|
||||
|
||||
int pos = detail_.border.y;
|
||||
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))
|
||||
return index;
|
||||
else if(y < pos)
|
||||
@ -641,13 +655,13 @@ namespace nana
|
||||
{
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
if(size.width > menu_->max_pixels)
|
||||
if (size.width > menu_->max_pixels)
|
||||
size.width = menu_->max_pixels;
|
||||
|
||||
return size;
|
||||
@ -688,14 +702,15 @@ namespace nana
|
||||
pos.y = scr_area.bottom() - static_cast<int>(size.height);
|
||||
if(pos.y < scr_area.y) pos.y = scr_area.y;
|
||||
|
||||
auto owner = API::get_owner_window(*widget_);
|
||||
API::calc_window_point(owner, pos);
|
||||
API::calc_window_point(API::get_owner_window(*widget_), pos);
|
||||
widget_->move(pos.x, pos.y);
|
||||
}
|
||||
private:
|
||||
widget *widget_{nullptr};
|
||||
paint::graphics *graph_{nullptr};
|
||||
menu_type *menu_{nullptr};
|
||||
|
||||
menu_builder* mbuilder_{ nullptr };
|
||||
menu_type* menu_{ nullptr };
|
||||
|
||||
std::function<void()> fn_close_tree_;
|
||||
|
||||
@ -723,7 +738,7 @@ namespace nana
|
||||
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.
|
||||
//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>()),
|
||||
@ -731,8 +746,8 @@ namespace nana
|
||||
event_focus_{ nullptr }
|
||||
{
|
||||
caption("nana menu window");
|
||||
get_drawer_trigger().close_menu_tree([this]{ this->_m_close_all(); });
|
||||
get_drawer_trigger().renderer = rdptr;
|
||||
get_drawer_trigger().set_run(mbuilder, menu_data, [this]{ this->_m_close_all(); });
|
||||
|
||||
state_.owner_menubar = state_.self_submenu = false;
|
||||
state_.auto_popup_submenu = true;
|
||||
|
||||
@ -740,7 +755,7 @@ namespace nana
|
||||
submenu_.object = nullptr;
|
||||
|
||||
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();
|
||||
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_)
|
||||
{
|
||||
API::activate_window(this->parent());
|
||||
@ -771,7 +784,7 @@ namespace nana
|
||||
}
|
||||
|
||||
auto & events = this->events();
|
||||
events.destroy.connect_unignorable([this]{
|
||||
events.destroy.connect_unignorable([this](const arg_destroy&){
|
||||
_m_destroy();
|
||||
});
|
||||
|
||||
@ -881,7 +894,7 @@ namespace nana
|
||||
if ((npos == active) || !menu)
|
||||
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)
|
||||
return;
|
||||
@ -892,35 +905,18 @@ namespace nana
|
||||
}
|
||||
else if (checks::option == item.style)
|
||||
{
|
||||
//Forward Looks for a splitter
|
||||
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;
|
||||
get_drawer_trigger().mbuilder().checked(active, true);
|
||||
}
|
||||
|
||||
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
|
||||
//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.functor.operator()(ip);
|
||||
item.event_handler.operator()(ip);
|
||||
}
|
||||
}
|
||||
private:
|
||||
@ -1035,7 +1031,7 @@ namespace nana
|
||||
menu_ptr->gaps = drawer.data()->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;
|
||||
submenu_.child = &mwnd;
|
||||
submenu_.child->submenu_.parent = this;
|
||||
@ -1043,7 +1039,7 @@ namespace nana
|
||||
|
||||
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);
|
||||
if (forced)
|
||||
mwnd.goto_next(true);
|
||||
@ -1100,7 +1096,7 @@ namespace nana
|
||||
};
|
||||
|
||||
drawerbase::menu::menu_builder mbuilder;
|
||||
drawerbase::menu::menu_window * uiobj;
|
||||
drawerbase::menu::menu_window * window_ptr;
|
||||
std::function<void()> destroy_answer;
|
||||
std::map<std::size_t, info> sub_container;
|
||||
};
|
||||
@ -1108,7 +1104,7 @@ namespace nana
|
||||
menu::menu()
|
||||
:impl_(new implement)
|
||||
{
|
||||
impl_->uiobj = nullptr;
|
||||
impl_->window_ptr = nullptr;
|
||||
}
|
||||
|
||||
menu::~menu()
|
||||
@ -1123,32 +1119,34 @@ namespace nana
|
||||
|
||||
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);
|
||||
return item_proxy(size() - 1, impl_->mbuilder.data().items.back());
|
||||
impl_->mbuilder.data().items.emplace_back(new item_type(std::move(text_utf8, callback));
|
||||
return item_proxy(size() - 1, *impl_->mbuilder.data().items.back());
|
||||
}
|
||||
|
||||
void menu::append_splitter()
|
||||
{
|
||||
impl_->mbuilder.data().items.emplace_back();
|
||||
impl_->mbuilder.data().items.emplace_back(new item_type);
|
||||
}
|
||||
|
||||
void menu::clear()
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
impl_->mbuilder.data().items.clear();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
auto & items = impl_->mbuilder.data().items;
|
||||
if(index < items.size())
|
||||
items.erase(items.begin() + index);
|
||||
@ -1156,7 +1154,7 @@ namespace nana
|
||||
|
||||
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)
|
||||
@ -1202,22 +1200,22 @@ namespace nana
|
||||
|
||||
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)
|
||||
{
|
||||
_m_popup(wd, x, y, false);
|
||||
if (impl_->uiobj)
|
||||
API::wait_for(impl_->uiobj->handle());
|
||||
_m_popup(wd, { x, y }, false);
|
||||
if (impl_->window_ptr)
|
||||
API::wait_for(impl_->window_ptr->handle());
|
||||
}
|
||||
|
||||
void menu::close()
|
||||
{
|
||||
if(impl_->uiobj)
|
||||
if (impl_->window_ptr)
|
||||
{
|
||||
impl_->uiobj->close();
|
||||
impl_->uiobj = nullptr;
|
||||
impl_->window_ptr->close();
|
||||
impl_->window_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1233,17 +1231,17 @@ namespace nana
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -1253,18 +1251,18 @@ namespace nana
|
||||
|
||||
void menu::goto_next(bool forward)
|
||||
{
|
||||
if(impl_->uiobj)
|
||||
impl_->uiobj->goto_next(forward);
|
||||
if (impl_->window_ptr)
|
||||
impl_->window_ptr->goto_next(forward);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
return (impl_->uiobj ? impl_->uiobj->submenu(false) : false);
|
||||
return (impl_->window_ptr ? impl_->window_ptr->submenu(false) : false);
|
||||
}
|
||||
|
||||
std::size_t menu::size() const
|
||||
@ -1274,13 +1272,13 @@ namespace nana
|
||||
|
||||
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()
|
||||
{
|
||||
if (impl_->uiobj)
|
||||
impl_->uiobj->pick();
|
||||
if (impl_->window_ptr)
|
||||
impl_->window_ptr->pick();
|
||||
}
|
||||
|
||||
menu& menu::max_pixels(unsigned px)
|
||||
@ -1315,19 +1313,19 @@ namespace nana
|
||||
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())
|
||||
{
|
||||
close();
|
||||
|
||||
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;
|
||||
impl_->window_ptr = &(form_loader<drawerbase::menu::menu_window, false>()(wd, false, pos, impl_->mbuilder, impl_->mbuilder.data()));
|
||||
impl_->window_ptr->events().destroy.connect_unignorable([this](const arg_destroy&){
|
||||
impl_->window_ptr = nullptr;
|
||||
if (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
|
||||
|
@ -20,7 +20,7 @@ namespace nana
|
||||
public:
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1574,7 +1574,8 @@ namespace nana{ namespace widgets
|
||||
_m_handle_move_key(arg);
|
||||
break;
|
||||
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();
|
||||
break;
|
||||
default:
|
||||
@ -1746,6 +1747,13 @@ namespace nana{ namespace widgets
|
||||
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&
|
||||
{
|
||||
return impl_->customized_renderers;
|
||||
@ -1797,7 +1805,7 @@ namespace nana{ namespace widgets
|
||||
if (select_all)
|
||||
{
|
||||
select(true);
|
||||
move_caret_end();
|
||||
move_caret_end(false);
|
||||
renderred = true;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
//move_caret
|
||||
//Set caret position through text coordinate
|
||||
bool text_editor::move_caret(const upoint& crtpos, bool reset_caret)
|
||||
{
|
||||
const unsigned line_pixels = line_height();
|
||||
@ -2036,11 +2042,14 @@ namespace nana{ namespace widgets
|
||||
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());
|
||||
if(points_.caret.y) --points_.caret.y;
|
||||
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
|
||||
@ -2064,6 +2073,25 @@ namespace nana{ namespace widgets
|
||||
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()
|
||||
{
|
||||
bool new_sel_end = (select_.b != points_.caret);
|
||||
@ -2096,25 +2124,6 @@ namespace nana{ namespace widgets
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
nana::upoint a, b;
|
||||
if(get_select_points(a, b))
|
||||
if (get_selected_points(a, b))
|
||||
{
|
||||
if (ignore_when_select_all)
|
||||
{
|
||||
@ -3045,7 +3054,7 @@ namespace nana{ namespace widgets
|
||||
nana::upoint text_editor::_m_erase_select()
|
||||
{
|
||||
nana::upoint a, b;
|
||||
if (get_select_points(a, b))
|
||||
if (get_selected_points(a, b))
|
||||
{
|
||||
auto & textbase = this->textbase();
|
||||
if(a.y != b.y)
|
||||
@ -3076,7 +3085,7 @@ namespace nana{ namespace widgets
|
||||
std::wstring text;
|
||||
|
||||
nana::upoint a, b;
|
||||
if (get_select_points(a, b))
|
||||
if (get_selected_points(a, b))
|
||||
{
|
||||
auto & textbase = this->textbase();
|
||||
if (a.y != b.y)
|
||||
@ -3167,7 +3176,7 @@ namespace nana{ namespace widgets
|
||||
bool text_editor::_m_cancel_select(int align)
|
||||
{
|
||||
nana::upoint a, b;
|
||||
if (get_select_points(a, b))
|
||||
if (get_selected_points(a, b))
|
||||
{
|
||||
switch(align)
|
||||
{
|
||||
@ -3262,7 +3271,7 @@ namespace nana{ namespace widgets
|
||||
const bool at_left = (select_.b < select_.a);
|
||||
|
||||
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))
|
||||
{//forward
|
||||
undo_ptr->set_caret_pos();
|
||||
@ -3458,7 +3467,7 @@ namespace nana{ namespace widgets
|
||||
const wchar_t *sbegin = nullptr, *send = nullptr;
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -69,10 +69,10 @@ namespace drawerbase {
|
||||
auto scheme = API::dev::get_scheme(wdg);
|
||||
|
||||
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()));
|
||||
editor_->textbase().set_event_agent(evt_agent_.get());
|
||||
editor_->set_event(evt_agent_.get());
|
||||
|
||||
_m_text_area(graph.width(), graph.height());
|
||||
|
||||
@ -260,8 +260,11 @@ namespace drawerbase {
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().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();
|
||||
API::update_window(this->handle());
|
||||
@ -319,6 +322,25 @@ namespace drawerbase {
|
||||
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
|
||||
bool textbox::caret_pos(point& pos, bool text_coordinate) const
|
||||
{
|
||||
@ -358,7 +380,7 @@ namespace drawerbase {
|
||||
if(editor)
|
||||
{
|
||||
if(at_caret == false)
|
||||
editor->move_caret_end();
|
||||
editor->move_caret_end(false);
|
||||
|
||||
editor->put(to_wstring(text));
|
||||
API::update_window(this->handle());
|
||||
@ -461,6 +483,13 @@ namespace drawerbase {
|
||||
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)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
@ -476,7 +505,7 @@ namespace drawerbase {
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor)
|
||||
editor->get_select_points(points.first, points.second);
|
||||
editor->get_selected_points(points.first, points.second);
|
||||
|
||||
return points;
|
||||
}
|
||||
@ -539,6 +568,11 @@ namespace drawerbase {
|
||||
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)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
|
@ -46,6 +46,7 @@ namespace nana
|
||||
|
||||
void pump()
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
detail::bedrock::instance().pump_event(nullptr, false);
|
||||
}
|
||||
|
||||
|
@ -156,6 +156,18 @@ namespace paint
|
||||
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
|
||||
{
|
||||
if(empty()) return nullptr;
|
||||
|
@ -356,11 +356,28 @@ namespace threads
|
||||
{
|
||||
}
|
||||
|
||||
pool::pool(pool&& other)
|
||||
: pool()
|
||||
{
|
||||
std::swap(impl_, other.impl_);
|
||||
}
|
||||
|
||||
pool::pool(std::size_t 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()
|
||||
{
|
||||
delete impl_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user