Merge branch 'hotfix-1.4.1' into develop
This commit is contained in:
commit
b1ce0eaff2
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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&);
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 = ⊂
|
item.sub_menu = ⊂
|
||||||
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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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_;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user