fix and improve the internal handle of focus change
enhanced textbox behavior of focus change
This commit is contained in:
parent
a839cf8deb
commit
569eb49a5c
@ -95,6 +95,7 @@ namespace nana
|
|||||||
undo = substitute,
|
undo = substitute,
|
||||||
|
|
||||||
//System Code for OS
|
//System Code for OS
|
||||||
|
os_tab = 0x09,
|
||||||
os_shift = 0x10,
|
os_shift = 0x10,
|
||||||
os_ctrl = 0x11,
|
os_ctrl = 0x11,
|
||||||
os_pageup = 0x21, os_pagedown,
|
os_pageup = 0x21, os_pagedown,
|
||||||
|
|||||||
@ -424,9 +424,18 @@ namespace nana
|
|||||||
|
|
||||||
struct arg_focus : public event_arg
|
struct arg_focus : public event_arg
|
||||||
{
|
{
|
||||||
::nana::window window_handle; ///< A handle to the event window
|
/// A constant to indicate how keyboard focus emitted.
|
||||||
::nana::native_window_type receiver; ///< it is a native window handle, and specified which window receives focus
|
enum class reason
|
||||||
bool getting; ///< the window received focus?
|
{
|
||||||
|
general, ///< the focus is received by OS native window manager.
|
||||||
|
tabstop, ///< the focus is received by pressing tab.
|
||||||
|
mouse_press ///< the focus is received by pressing a mouse button.
|
||||||
|
};
|
||||||
|
|
||||||
|
::nana::window window_handle; ///< A handle to the event window
|
||||||
|
::nana::native_window_type receiver; ///< it is a native window handle, and specified which window receives focus
|
||||||
|
bool getting; ///< the window received focus?
|
||||||
|
reason focus_reason; ///< determines how the widget receives keyboard focus, it is ignored when 'getting' is equal to false
|
||||||
};
|
};
|
||||||
|
|
||||||
struct arg_keyboard : public event_arg
|
struct arg_keyboard : public event_arg
|
||||||
|
|||||||
@ -117,8 +117,9 @@ namespace nana{
|
|||||||
nana::paint::graphics root_graph;
|
nana::paint::graphics root_graph;
|
||||||
shortkey_container shortkeys;
|
shortkey_container shortkeys;
|
||||||
|
|
||||||
struct condition_tag
|
struct condition_rep
|
||||||
{
|
{
|
||||||
|
bool ignore_tab{ false }; //ignore tab when the focus is changed by pressing tab.
|
||||||
core_window_t* pressed{nullptr}; //The handle to a window which has been pressed by pressing left button of mouse.
|
core_window_t* pressed{nullptr}; //The handle to a window which has been pressed by pressing left button of mouse.
|
||||||
core_window_t* pressed_by_space{ nullptr }; //The handle to a window which has been pressed by pressing spacebar.
|
core_window_t* pressed_by_space{ nullptr }; //The handle to a window which has been pressed by pressing spacebar.
|
||||||
core_window_t* hovered{nullptr}; //the latest window that mouse moved
|
core_window_t* hovered{nullptr}; //the latest window that mouse moved
|
||||||
|
|||||||
@ -136,7 +136,7 @@ namespace detail
|
|||||||
|
|
||||||
std::vector<core_window_t*> get_children(core_window_t*) const;
|
std::vector<core_window_t*> get_children(core_window_t*) const;
|
||||||
bool set_parent(core_window_t* wd, core_window_t* new_parent);
|
bool set_parent(core_window_t* wd, core_window_t* new_parent);
|
||||||
core_window_t* set_focus(core_window_t*, bool root_has_been_focused);
|
core_window_t* set_focus(core_window_t*, bool root_has_been_focused, arg_focus::reason);
|
||||||
|
|
||||||
core_window_t* capture_redirect(core_window_t*);
|
core_window_t* capture_redirect(core_window_t*);
|
||||||
void capture_ignore_children(bool ignore);
|
void capture_ignore_children(bool ignore);
|
||||||
|
|||||||
@ -283,8 +283,14 @@ namespace API
|
|||||||
cursor window_cursor(window);
|
cursor window_cursor(window);
|
||||||
|
|
||||||
void activate_window(window);
|
void activate_window(window);
|
||||||
|
|
||||||
|
/// Determines whether the specified window will get the keyboard focus when its root window gets native system focus.
|
||||||
bool is_focus_ready(window);
|
bool is_focus_ready(window);
|
||||||
|
|
||||||
|
/// Returns the current keyboard focus window.
|
||||||
window focus_window();
|
window focus_window();
|
||||||
|
|
||||||
|
/// Sets the keyboard focus for a specified window.
|
||||||
void focus_window(window);
|
void focus_window(window);
|
||||||
|
|
||||||
window capture_window();
|
window capture_window();
|
||||||
|
|||||||
@ -229,6 +229,9 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
/// Returns text position of each line that currently displays on screen
|
/// Returns text position of each line that currently displays on screen
|
||||||
const std::vector<upoint>& text_position() const;
|
const std::vector<upoint>& text_position() const;
|
||||||
|
|
||||||
|
void focus_behavior(text_focus_behavior);
|
||||||
|
void select_behavior(bool move_to_end);
|
||||||
public:
|
public:
|
||||||
void draw_corner();
|
void draw_corner();
|
||||||
void render(bool focused);
|
void render(bool focused);
|
||||||
@ -249,6 +252,8 @@ namespace nana{ namespace widgets
|
|||||||
const upoint& caret() const;
|
const upoint& caret() const;
|
||||||
point caret_screen_pos() const;
|
point caret_screen_pos() const;
|
||||||
bool scroll(bool upwards, bool vertical);
|
bool scroll(bool upwards, bool vertical);
|
||||||
|
|
||||||
|
bool focus_changed(const arg_focus&);
|
||||||
bool mouse_enter(bool);
|
bool mouse_enter(bool);
|
||||||
bool mouse_move(bool left_button, const point& screen_pos);
|
bool mouse_move(bool left_button, const point& screen_pos);
|
||||||
bool mouse_pressed(const arg_mouse& arg);
|
bool mouse_pressed(const arg_mouse& arg);
|
||||||
@ -353,10 +358,13 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
struct selection
|
struct selection
|
||||||
{
|
{
|
||||||
enum mode_selection_t{mode_no_selected, mode_mouse_selected, mode_method_selected};
|
enum class mode{ no_selected, mouse_selected, method_selected };
|
||||||
|
|
||||||
mode_selection_t mode_selection;
|
text_focus_behavior behavior;
|
||||||
|
bool move_to_end;
|
||||||
|
mode mode_selection;
|
||||||
bool dragged;
|
bool dragged;
|
||||||
|
bool ignore_press;
|
||||||
nana::upoint a, b;
|
nana::upoint a, b;
|
||||||
}select_;
|
}select_;
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,15 @@ namespace nana
|
|||||||
{
|
{
|
||||||
namespace skeletons
|
namespace skeletons
|
||||||
{
|
{
|
||||||
|
enum class text_focus_behavior
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
select,
|
||||||
|
select_if_tabstop,
|
||||||
|
select_if_click,
|
||||||
|
select_if_tabstop_or_click
|
||||||
|
};
|
||||||
|
|
||||||
//forward declaration
|
//forward declaration
|
||||||
class text_editor;
|
class text_editor;
|
||||||
|
|
||||||
|
|||||||
@ -98,6 +98,8 @@ namespace nana
|
|||||||
:public widget_object<category::widget_tag, drawerbase::textbox::drawer, drawerbase::textbox::textbox_events, ::nana::widgets::skeletons::text_editor_scheme>
|
:public widget_object<category::widget_tag, drawerbase::textbox::drawer, drawerbase::textbox::textbox_events, ::nana::widgets::skeletons::text_editor_scheme>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using text_focus_behavior = widgets::skeletons::text_focus_behavior;
|
||||||
|
|
||||||
using text_positions = std::vector<upoint>;
|
using text_positions = std::vector<upoint>;
|
||||||
/// The default constructor without creating the widget.
|
/// The default constructor without creating the widget.
|
||||||
textbox();
|
textbox();
|
||||||
@ -207,6 +209,14 @@ namespace nana
|
|||||||
|
|
||||||
/// Returns the height of line in pixels
|
/// Returns the height of line in pixels
|
||||||
unsigned line_pixels() const;
|
unsigned line_pixels() const;
|
||||||
|
|
||||||
|
/// Sets the behavior when textbox gets focus.
|
||||||
|
void focus_behavior(text_focus_behavior);
|
||||||
|
|
||||||
|
/// Sets the caret move behavior when the content of textbox is selected.
|
||||||
|
/// E.g. Whether caret moves to left of selected content or moves to left of last position when left arrow key is pressed.
|
||||||
|
/// @param move_to_end determines whether to move caret to left of selected_content or to left of last position.
|
||||||
|
void select_behavior(bool move_to_end);
|
||||||
protected:
|
protected:
|
||||||
//Overrides widget's virtual functions
|
//Overrides widget's virtual functions
|
||||||
native_string_type _m_caption() const throw() override;
|
native_string_type _m_caption() const throw() override;
|
||||||
|
|||||||
@ -255,7 +255,7 @@ namespace detail
|
|||||||
if ((!wd) && pre)
|
if ((!wd) && pre)
|
||||||
{
|
{
|
||||||
internal_scope_guard lock;
|
internal_scope_guard lock;
|
||||||
wd_manager().set_focus(pre, false);
|
wd_manager().set_focus(pre, false, arg_focus::reason::general);
|
||||||
wd_manager().update(pre, true, false);
|
wd_manager().update(pre, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -479,6 +479,7 @@ namespace detail
|
|||||||
arg.window_handle = reinterpret_cast<window>(wd);
|
arg.window_handle = reinterpret_cast<window>(wd);
|
||||||
arg.receiver = recv;
|
arg.receiver = recv;
|
||||||
arg.getting = getting;
|
arg.getting = getting;
|
||||||
|
arg.focus_reason = arg_focus::reason::general;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assign_arg(arg_wheel& arg, basic_window* wd, const XEvent& evt)
|
void assign_arg(arg_wheel& arg, basic_window* wd, const XEvent& evt)
|
||||||
@ -701,7 +702,7 @@ namespace detail
|
|||||||
arg.receiver = native_window;
|
arg.receiver = native_window;
|
||||||
arg.getting = true;
|
arg.getting = true;
|
||||||
if(!brock.emit(event_code::focus, focus, arg, true, &context))
|
if(!brock.emit(event_code::focus, focus, arg, true, &context))
|
||||||
brock.wd_manager().set_focus(msgwnd, true);
|
brock.wd_manager().set_focus(msgwnd, true, arg_focus::reason::general);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FocusOut:
|
case FocusOut:
|
||||||
@ -765,7 +766,7 @@ namespace detail
|
|||||||
if (new_focus && !new_focus->flags.ignore_mouse_focus)
|
if (new_focus && !new_focus->flags.ignore_mouse_focus)
|
||||||
{
|
{
|
||||||
context.event_window = new_focus;
|
context.event_window = new_focus;
|
||||||
auto kill_focus = brock.wd_manager().set_focus(new_focus, false);
|
auto kill_focus = brock.wd_manager().set_focus(new_focus, false, arg_focus::reason::mouse_press);
|
||||||
if (kill_focus != new_focus)
|
if (kill_focus != new_focus)
|
||||||
brock.wd_manager().do_lazy_refresh(kill_focus, false);
|
brock.wd_manager().do_lazy_refresh(kill_focus, false);
|
||||||
}
|
}
|
||||||
@ -1048,7 +1049,8 @@ namespace detail
|
|||||||
auto tstop_wd = wd_manager.tabstop(msgwnd, !argkey.shift);
|
auto tstop_wd = wd_manager.tabstop(msgwnd, !argkey.shift);
|
||||||
if (tstop_wd)
|
if (tstop_wd)
|
||||||
{
|
{
|
||||||
wd_manager.set_focus(tstop_wd, false);
|
root_runtime->condition.ignore_tab = true;
|
||||||
|
wd_manager.set_focus(tstop_wd, false, arg_focus::reason::tabstop);
|
||||||
wd_manager.do_lazy_refresh(msgwnd, false);
|
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||||
wd_manager.do_lazy_refresh(tstop_wd, true);
|
wd_manager.do_lazy_refresh(tstop_wd, true);
|
||||||
}
|
}
|
||||||
@ -1144,8 +1146,8 @@ namespace detail
|
|||||||
arg.ignore = false;
|
arg.ignore = false;
|
||||||
arg.key = charbuf[i];
|
arg.key = charbuf[i];
|
||||||
|
|
||||||
// When tab is pressed, only tab-eating mode is allowed
|
//Only accept tab when it is not ignored.
|
||||||
if ((keyboard::tab == arg.key) && !(msgwnd->flags.tab & tab_type::eating))
|
if ((keyboard::tab == arg.key) && root_runtime->condition.ignore_tab)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(context.is_alt_pressed)
|
if(context.is_alt_pressed)
|
||||||
@ -1185,52 +1187,61 @@ namespace detail
|
|||||||
nana::detail::platform_spec::instance().write_keystate(xevent.xkey);
|
nana::detail::platform_spec::instance().write_keystate(xevent.xkey);
|
||||||
{
|
{
|
||||||
auto os_code = os_code_from_keysym(::XLookupKeysym(&xevent.xkey, 0));
|
auto os_code = os_code_from_keysym(::XLookupKeysym(&xevent.xkey, 0));
|
||||||
if(keyboard::alt != os_code)
|
if(keyboard::alt != os_code) //MUST NOT BE AN ALT
|
||||||
{
|
{
|
||||||
if(0x11 == os_code)
|
if(0x11 == os_code)
|
||||||
context.is_ctrl_pressed = false;
|
context.is_ctrl_pressed = false;
|
||||||
|
|
||||||
msgwnd = brock.focus();
|
if (('\t' == os_code) && root_runtime->condition.ignore_tab)
|
||||||
if(msgwnd)
|
{
|
||||||
{
|
root_runtime->condition.ignore_tab = false;
|
||||||
if(msgwnd == pressed_wd_space)
|
}
|
||||||
{
|
else
|
||||||
msgwnd->flags.action = mouse_action::normal;
|
{
|
||||||
|
|
||||||
arg_click click_arg;
|
msgwnd = brock.focus();
|
||||||
click_arg.mouse_args = nullptr;
|
if(msgwnd)
|
||||||
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
|
{
|
||||||
|
if(msgwnd == pressed_wd_space)
|
||||||
|
{
|
||||||
|
msgwnd->flags.action = mouse_action::normal;
|
||||||
|
|
||||||
auto retain = msgwnd->together.events_ptr;
|
arg_click click_arg;
|
||||||
if (brock.emit(event_code::click, msgwnd, click_arg, true, &context))
|
click_arg.mouse_args = nullptr;
|
||||||
{
|
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||||
arg_mouse arg;
|
|
||||||
arg.alt = false;
|
|
||||||
arg.button = ::nana::mouse::left_button;
|
|
||||||
arg.ctrl = false;
|
|
||||||
arg.evt_code = event_code::mouse_up;
|
|
||||||
arg.left_button = true;
|
|
||||||
arg.mid_button = false;
|
|
||||||
arg.pos.x = 0;
|
|
||||||
arg.pos.y = 0;
|
|
||||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
|
||||||
|
|
||||||
emit_drawer(&drawer::mouse_up, msgwnd, arg, &context);
|
auto retain = msgwnd->together.events_ptr;
|
||||||
brock.wd_manager().do_lazy_refresh(msgwnd, false);
|
if (brock.emit(event_code::click, msgwnd, click_arg, true, &context))
|
||||||
}
|
{
|
||||||
pressed_wd_space = nullptr;
|
arg_mouse arg;
|
||||||
}
|
arg.alt = false;
|
||||||
else
|
arg.button = ::nana::mouse::left_button;
|
||||||
{
|
arg.ctrl = false;
|
||||||
arg_keyboard arg;
|
arg.evt_code = event_code::mouse_up;
|
||||||
arg.evt_code = event_code::key_release;
|
arg.left_button = true;
|
||||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
arg.mid_button = false;
|
||||||
arg.ignore = false;
|
arg.pos.x = 0;
|
||||||
arg.key = os_code;
|
arg.pos.y = 0;
|
||||||
brock.get_key_state(arg);
|
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||||
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
|
||||||
}
|
emit_drawer(&drawer::mouse_up, msgwnd, arg, &context);
|
||||||
}
|
brock.wd_manager().do_lazy_refresh(msgwnd, false);
|
||||||
|
}
|
||||||
|
pressed_wd_space = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arg_keyboard arg;
|
||||||
|
|
||||||
|
arg.evt_code = event_code::key_release;
|
||||||
|
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||||
|
arg.ignore = false;
|
||||||
|
arg.key = os_code;
|
||||||
|
brock.get_key_state(arg);
|
||||||
|
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(os_code < keyboard::os_arrow_left || keyboard::os_arrow_down < os_code)
|
if(os_code < keyboard::os_arrow_left || keyboard::os_arrow_down < os_code)
|
||||||
brock.delay_restore(2); //Restores while key release
|
brock.delay_restore(2); //Restores while key release
|
||||||
@ -1245,7 +1256,7 @@ namespace detail
|
|||||||
{
|
{
|
||||||
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
|
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
|
||||||
if (set_focus)
|
if (set_focus)
|
||||||
brock.wd_manager().set_focus(msgwnd, false);
|
brock.wd_manager().set_focus(msgwnd, false, arg_focus::reason::general);
|
||||||
|
|
||||||
arg_keyboard arg;
|
arg_keyboard arg;
|
||||||
arg.evt_code = event_code::key_release;
|
arg.evt_code = event_code::key_release;
|
||||||
|
|||||||
@ -549,6 +549,7 @@ namespace detail
|
|||||||
arg.window_handle = reinterpret_cast<window>(wd);
|
arg.window_handle = reinterpret_cast<window>(wd);
|
||||||
arg.receiver = recv;
|
arg.receiver = recv;
|
||||||
arg.getting = getting;
|
arg.getting = getting;
|
||||||
|
arg.focus_reason = arg_focus::reason::general;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assign_arg(arg_wheel& arg, basic_window* wd, const parameter_decoder& pmdec)
|
void assign_arg(arg_wheel& arg, basic_window* wd, const parameter_decoder& pmdec)
|
||||||
@ -882,7 +883,7 @@ namespace detail
|
|||||||
arg_focus arg;
|
arg_focus arg;
|
||||||
assign_arg(arg, focus, native_window, true);
|
assign_arg(arg, focus, native_window, true);
|
||||||
if (!brock.emit(event_code::focus, focus, arg, true, &context))
|
if (!brock.emit(event_code::focus, focus, arg, true, &context))
|
||||||
brock.wd_manager().set_focus(msgwnd, true);
|
brock.wd_manager().set_focus(msgwnd, true, arg_focus::reason::general);
|
||||||
}
|
}
|
||||||
def_window_proc = true;
|
def_window_proc = true;
|
||||||
break;
|
break;
|
||||||
@ -922,7 +923,7 @@ namespace detail
|
|||||||
{
|
{
|
||||||
if (msgwnd->flags.take_active && !msgwnd->flags.ignore_mouse_focus)
|
if (msgwnd->flags.take_active && !msgwnd->flags.ignore_mouse_focus)
|
||||||
{
|
{
|
||||||
auto killed = brock.wd_manager().set_focus(msgwnd, false);
|
auto killed = brock.wd_manager().set_focus(msgwnd, false, arg_focus::reason::mouse_press);
|
||||||
if (killed != msgwnd)
|
if (killed != msgwnd)
|
||||||
brock.wd_manager().do_lazy_refresh(killed, false);
|
brock.wd_manager().do_lazy_refresh(killed, false);
|
||||||
}
|
}
|
||||||
@ -964,7 +965,7 @@ namespace detail
|
|||||||
auto new_focus = (msgwnd->flags.take_active ? msgwnd : msgwnd->other.active_window);
|
auto new_focus = (msgwnd->flags.take_active ? msgwnd : msgwnd->other.active_window);
|
||||||
if (new_focus && (!new_focus->flags.ignore_mouse_focus))
|
if (new_focus && (!new_focus->flags.ignore_mouse_focus))
|
||||||
{
|
{
|
||||||
auto kill_focus = brock.wd_manager().set_focus(new_focus, false);
|
auto kill_focus = brock.wd_manager().set_focus(new_focus, false, arg_focus::reason::mouse_press);
|
||||||
if (kill_focus != new_focus)
|
if (kill_focus != new_focus)
|
||||||
brock.wd_manager().do_lazy_refresh(kill_focus, false);
|
brock.wd_manager().do_lazy_refresh(kill_focus, false);
|
||||||
}
|
}
|
||||||
@ -1383,7 +1384,7 @@ namespace detail
|
|||||||
|
|
||||||
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
|
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
|
||||||
if (set_focus)
|
if (set_focus)
|
||||||
brock.wd_manager().set_focus(msgwnd, false);
|
brock.wd_manager().set_focus(msgwnd, false, arg_focus::reason::general);
|
||||||
|
|
||||||
arg_keyboard arg;
|
arg_keyboard arg;
|
||||||
arg.evt_code = event_code::key_release;
|
arg.evt_code = event_code::key_release;
|
||||||
@ -1414,14 +1415,16 @@ namespace detail
|
|||||||
if(msgwnd)
|
if(msgwnd)
|
||||||
{
|
{
|
||||||
auto & wd_manager = brock.wd_manager();
|
auto & wd_manager = brock.wd_manager();
|
||||||
if((VK_TAB == wParam) && (!msgwnd->visible || (false == (msgwnd->flags.tab & tab_type::eating)))) //Tab
|
|
||||||
|
if ((VK_TAB == wParam) && (!msgwnd->visible || (false == (msgwnd->flags.tab & tab_type::eating)))) //Tab
|
||||||
{
|
{
|
||||||
bool is_forward = (::GetKeyState(VK_SHIFT) >= 0);
|
bool is_forward = (::GetKeyState(VK_SHIFT) >= 0);
|
||||||
|
|
||||||
auto tstop_wd = wd_manager.tabstop(msgwnd, is_forward);
|
auto tstop_wd = wd_manager.tabstop(msgwnd, is_forward);
|
||||||
if (tstop_wd)
|
if (tstop_wd)
|
||||||
{
|
{
|
||||||
wd_manager.set_focus(tstop_wd, false);
|
root_runtime->condition.ignore_tab = true;
|
||||||
|
wd_manager.set_focus(tstop_wd, false, arg_focus::reason::tabstop);
|
||||||
wd_manager.do_lazy_refresh(msgwnd, false);
|
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||||
wd_manager.do_lazy_refresh(tstop_wd, true);
|
wd_manager.do_lazy_refresh(tstop_wd, true);
|
||||||
}
|
}
|
||||||
@ -1479,8 +1482,10 @@ namespace detail
|
|||||||
msgwnd = brock.focus();
|
msgwnd = brock.focus();
|
||||||
if (msgwnd && msgwnd->flags.enabled)
|
if (msgwnd && msgwnd->flags.enabled)
|
||||||
{
|
{
|
||||||
// When tab is pressed, only tab-eating mode is allowed
|
auto & wd_manager = brock.wd_manager();
|
||||||
if ((9 != wParam) || (msgwnd->flags.tab & tab_type::eating))
|
|
||||||
|
//Only accept tab when it is not ignored.
|
||||||
|
if (VK_TAB != wParam || !root_runtime->condition.ignore_tab)
|
||||||
{
|
{
|
||||||
arg_keyboard arg;
|
arg_keyboard arg;
|
||||||
arg.evt_code = event_code::key_char;
|
arg.evt_code = event_code::key_char;
|
||||||
@ -1490,55 +1495,62 @@ namespace detail
|
|||||||
arg.ignore = false;
|
arg.ignore = false;
|
||||||
|
|
||||||
msgwnd->together.events_ptr->key_char.emit(arg);
|
msgwnd->together.events_ptr->key_char.emit(arg);
|
||||||
if ((false == arg.ignore) && brock.wd_manager().available(msgwnd))
|
if ((false == arg.ignore) && wd_manager.available(msgwnd))
|
||||||
brock.emit_drawer(event_code::key_char, msgwnd, arg, &context);
|
brock.emit_drawer(event_code::key_char, msgwnd, arg, &context);
|
||||||
|
|
||||||
brock.wd_manager().do_lazy_refresh(msgwnd, false);
|
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
case WM_KEYUP:
|
case WM_KEYUP:
|
||||||
if(wParam != VK_MENU) //MUST NOT BE AN ALT
|
if(wParam != VK_MENU) //MUST NOT BE AN ALT
|
||||||
{
|
{
|
||||||
msgwnd = brock.focus();
|
if (VK_TAB == wParam && root_runtime->condition.ignore_tab)
|
||||||
if(msgwnd)
|
|
||||||
{
|
{
|
||||||
if (msgwnd == pressed_wd_space)
|
root_runtime->condition.ignore_tab = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msgwnd = brock.focus();
|
||||||
|
if (msgwnd)
|
||||||
{
|
{
|
||||||
msgwnd->flags.action = mouse_action::normal;
|
if (msgwnd == pressed_wd_space)
|
||||||
|
|
||||||
arg_click click_arg;
|
|
||||||
click_arg.mouse_args = nullptr;
|
|
||||||
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
|
|
||||||
|
|
||||||
auto retain = msgwnd->together.events_ptr;
|
|
||||||
if (brock.emit(event_code::click, msgwnd, click_arg, true, &context))
|
|
||||||
{
|
{
|
||||||
arg_mouse arg;
|
msgwnd->flags.action = mouse_action::normal;
|
||||||
arg.alt = false;
|
|
||||||
arg.button = ::nana::mouse::left_button;
|
|
||||||
arg.ctrl = false;
|
|
||||||
arg.evt_code = event_code::mouse_up;
|
|
||||||
arg.left_button = true;
|
|
||||||
arg.mid_button = false;
|
|
||||||
arg.pos.x = 0;
|
|
||||||
arg.pos.y = 0;
|
|
||||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
|
||||||
|
|
||||||
emit_drawer(&drawer::mouse_up, msgwnd, arg, &context);
|
arg_click click_arg;
|
||||||
brock.wd_manager().do_lazy_refresh(msgwnd, false);
|
click_arg.mouse_args = nullptr;
|
||||||
|
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||||
|
|
||||||
|
auto retain = msgwnd->together.events_ptr;
|
||||||
|
if (brock.emit(event_code::click, msgwnd, click_arg, true, &context))
|
||||||
|
{
|
||||||
|
arg_mouse arg;
|
||||||
|
arg.alt = false;
|
||||||
|
arg.button = ::nana::mouse::left_button;
|
||||||
|
arg.ctrl = false;
|
||||||
|
arg.evt_code = event_code::mouse_up;
|
||||||
|
arg.left_button = true;
|
||||||
|
arg.mid_button = false;
|
||||||
|
arg.pos.x = 0;
|
||||||
|
arg.pos.y = 0;
|
||||||
|
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||||
|
|
||||||
|
emit_drawer(&drawer::mouse_up, msgwnd, arg, &context);
|
||||||
|
brock.wd_manager().do_lazy_refresh(msgwnd, false);
|
||||||
|
}
|
||||||
|
pressed_wd_space = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arg_keyboard arg;
|
||||||
|
arg.evt_code = event_code::key_release;
|
||||||
|
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||||
|
arg.key = static_cast<wchar_t>(wParam);
|
||||||
|
brock.get_key_state(arg);
|
||||||
|
arg.ignore = false;
|
||||||
|
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
||||||
}
|
}
|
||||||
pressed_wd_space = nullptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arg_keyboard arg;
|
|
||||||
arg.evt_code = event_code::key_release;
|
|
||||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
|
||||||
arg.key = static_cast<wchar_t>(wParam);
|
|
||||||
brock.get_key_state(arg);
|
|
||||||
arg.ignore = false;
|
|
||||||
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1625,7 +1637,7 @@ namespace detail
|
|||||||
if ((!wd) && pre && (pre->root != get_menu()))
|
if ((!wd) && pre && (pre->root != get_menu()))
|
||||||
{
|
{
|
||||||
internal_scope_guard lock;
|
internal_scope_guard lock;
|
||||||
wd_manager().set_focus(pre, false);
|
wd_manager().set_focus(pre, false, arg_focus::reason::general);
|
||||||
wd_manager().update(pre, true, false);
|
wd_manager().update(pre, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -925,7 +925,7 @@ namespace detail
|
|||||||
|
|
||||||
//set_focus
|
//set_focus
|
||||||
//@brief: set a keyboard focus to a window. this may fire a focus event.
|
//@brief: set a keyboard focus to a window. this may fire a focus event.
|
||||||
window_manager::core_window_t* window_manager::set_focus(core_window_t* wd, bool root_has_been_focused)
|
window_manager::core_window_t* window_manager::set_focus(core_window_t* wd, bool root_has_been_focused, arg_focus::reason reason)
|
||||||
{
|
{
|
||||||
//Thread-Safe Required!
|
//Thread-Safe Required!
|
||||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||||
@ -951,6 +951,7 @@ namespace detail
|
|||||||
arg.getting = false;
|
arg.getting = false;
|
||||||
arg.window_handle = reinterpret_cast<window>(prev_focus);
|
arg.window_handle = reinterpret_cast<window>(prev_focus);
|
||||||
arg.receiver = wd->root;
|
arg.receiver = wd->root;
|
||||||
|
arg.focus_reason = arg_focus::reason::general;
|
||||||
brock.emit(event_code::focus, prev_focus, arg, true, brock.get_thread_context());
|
brock.emit(event_code::focus, prev_focus, arg, true, brock.get_thread_context());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -968,6 +969,7 @@ namespace detail
|
|||||||
arg.window_handle = reinterpret_cast<window>(wd);
|
arg.window_handle = reinterpret_cast<window>(wd);
|
||||||
arg.getting = true;
|
arg.getting = true;
|
||||||
arg.receiver = wd->root;
|
arg.receiver = wd->root;
|
||||||
|
arg.focus_reason = reason;
|
||||||
brock.emit(event_code::focus, wd, arg, true, brock.get_thread_context());
|
brock.emit(event_code::focus, wd, arg, true, brock.get_thread_context());
|
||||||
|
|
||||||
if (!root_has_been_focused)
|
if (!root_has_been_focused)
|
||||||
|
|||||||
@ -929,7 +929,7 @@ namespace API
|
|||||||
|
|
||||||
void focus_window(window wd)
|
void focus_window(window wd)
|
||||||
{
|
{
|
||||||
restrict::wd_manager().set_focus(reinterpret_cast<basic_window*>(wd), false);
|
restrict::wd_manager().set_focus(reinterpret_cast<basic_window*>(wd), false, arg_focus::reason::general);
|
||||||
restrict::wd_manager().update(reinterpret_cast<basic_window*>(wd), false, false);
|
restrict::wd_manager().update(reinterpret_cast<basic_window*>(wd), false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1171,7 +1171,7 @@ namespace API
|
|||||||
window move_tabstop(window wd, bool next)
|
window move_tabstop(window wd, bool next)
|
||||||
{
|
{
|
||||||
basic_window* ts_wd = restrict::wd_manager().tabstop(reinterpret_cast<basic_window*>(wd), next);
|
basic_window* ts_wd = restrict::wd_manager().tabstop(reinterpret_cast<basic_window*>(wd), next);
|
||||||
restrict::wd_manager().set_focus(ts_wd, false);
|
restrict::wd_manager().set_focus(ts_wd, false, arg_focus::reason::general);
|
||||||
restrict::wd_manager().update(ts_wd, false, false);
|
restrict::wd_manager().update(ts_wd, false, false);
|
||||||
return reinterpret_cast<window>(ts_wd);
|
return reinterpret_cast<window>(ts_wd);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1289,7 +1289,11 @@ namespace nana{ namespace widgets
|
|||||||
text_area_.tab_space = 4;
|
text_area_.tab_space = 4;
|
||||||
text_area_.scroll_pixels = 16;
|
text_area_.scroll_pixels = 16;
|
||||||
text_area_.hscroll = text_area_.vscroll = 0;
|
text_area_.hscroll = text_area_.vscroll = 0;
|
||||||
select_.mode_selection = selection::mode_no_selected;
|
|
||||||
|
select_.behavior = text_focus_behavior::select_if_tabstop_or_click;
|
||||||
|
select_.move_to_end = false;
|
||||||
|
select_.mode_selection = selection::mode::no_selected;
|
||||||
|
select_.ignore_press = false;
|
||||||
select_.dragged = false;
|
select_.dragged = false;
|
||||||
|
|
||||||
API::create_caret(wd, 1, line_height());
|
API::create_caret(wd, 1, line_height());
|
||||||
@ -1348,11 +1352,13 @@ namespace nana{ namespace widgets
|
|||||||
void text_editor::erase_keyword(const ::std::wstring& kw)
|
void text_editor::erase_keyword(const ::std::wstring& kw)
|
||||||
{
|
{
|
||||||
for (auto i = keywords_->kwbase.begin(); i != keywords_->kwbase.end(); ++i)
|
for (auto i = keywords_->kwbase.begin(); i != keywords_->kwbase.end(); ++i)
|
||||||
|
{
|
||||||
if (i->text == kw)
|
if (i->text == kw)
|
||||||
{
|
{
|
||||||
keywords_->kwbase.erase(i);
|
keywords_->kwbase.erase(i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void text_editor::set_accept(std::function<bool(char_type)> pred)
|
void text_editor::set_accept(std::function<bool(char_type)> pred)
|
||||||
@ -1624,6 +1630,47 @@ namespace nana{ namespace widgets
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool text_editor::focus_changed(const arg_focus& arg)
|
||||||
|
{
|
||||||
|
bool renderred = false;
|
||||||
|
|
||||||
|
if (arg.getting && (select_.a == select_.b)) //Do not change the selected text
|
||||||
|
{
|
||||||
|
bool select_all = false;
|
||||||
|
switch (select_.behavior)
|
||||||
|
{
|
||||||
|
case text_focus_behavior::select:
|
||||||
|
select_all = true;
|
||||||
|
break;
|
||||||
|
case text_focus_behavior::select_if_click:
|
||||||
|
select_all = (arg_focus::reason::mouse_press == arg.focus_reason);
|
||||||
|
break;
|
||||||
|
case text_focus_behavior::select_if_tabstop:
|
||||||
|
select_all = (arg_focus::reason::tabstop == arg.focus_reason);
|
||||||
|
break;
|
||||||
|
case text_focus_behavior::select_if_tabstop_or_click:
|
||||||
|
select_all = (arg_focus::reason::tabstop == arg.focus_reason || arg_focus::reason::mouse_press == arg.focus_reason);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select_all)
|
||||||
|
{
|
||||||
|
select(true);
|
||||||
|
move_caret_end();
|
||||||
|
renderred = true;
|
||||||
|
|
||||||
|
//If the text widget is focused by clicking mouse button, the selected text will be cancelled
|
||||||
|
//by the subsequent mouse down event. In this situation, the subsequent mouse down event should
|
||||||
|
//be ignored.
|
||||||
|
select_.ignore_press = (arg_focus::reason::mouse_press == arg.focus_reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
show_caret(arg.getting);
|
||||||
|
reset_caret();
|
||||||
|
return renderred;
|
||||||
|
}
|
||||||
|
|
||||||
bool text_editor::mouse_enter(bool enter)
|
bool text_editor::mouse_enter(bool enter)
|
||||||
{
|
{
|
||||||
if((false == enter) && (false == text_area_.captured))
|
if((false == enter) && (false == text_area_.captured))
|
||||||
@ -1649,7 +1696,7 @@ namespace nana{ namespace widgets
|
|||||||
auto caret_pos_before = caret();
|
auto caret_pos_before = caret();
|
||||||
mouse_caret(scrpos);
|
mouse_caret(scrpos);
|
||||||
|
|
||||||
if(select_.mode_selection != selection::mode_no_selected)
|
if(select_.mode_selection != selection::mode::no_selected)
|
||||||
set_end_caret();
|
set_end_caret();
|
||||||
else if ((!select_.dragged) && (caret_pos_before != caret()))
|
else if ((!select_.dragged) && (caret_pos_before != caret()))
|
||||||
select_.dragged = true;
|
select_.dragged = true;
|
||||||
@ -1664,8 +1711,11 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
if (event_code::mouse_down == arg.evt_code)
|
if (event_code::mouse_down == arg.evt_code)
|
||||||
{
|
{
|
||||||
if (!hit_text_area(arg.pos))
|
if (select_.ignore_press || (!hit_text_area(arg.pos)))
|
||||||
|
{
|
||||||
|
select_.ignore_press = false;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (::nana::mouse::left_button == arg.button)
|
if (::nana::mouse::left_button == arg.button)
|
||||||
{
|
{
|
||||||
@ -1691,7 +1741,7 @@ namespace nana{ namespace widgets
|
|||||||
}
|
}
|
||||||
points_.shift_begin_caret = points_.caret;
|
points_.shift_begin_caret = points_.caret;
|
||||||
}
|
}
|
||||||
select_.mode_selection = selection::mode_mouse_selected;
|
select_.mode_selection = selection::mode::mouse_selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
text_area_.border_renderer(graph_, _m_bgcolor());
|
text_area_.border_renderer(graph_, _m_bgcolor());
|
||||||
@ -1699,11 +1749,12 @@ namespace nana{ namespace widgets
|
|||||||
}
|
}
|
||||||
else if (event_code::mouse_up == arg.evt_code)
|
else if (event_code::mouse_up == arg.evt_code)
|
||||||
{
|
{
|
||||||
auto is_prev_no_selected = (select_.mode_selection == selection::mode_no_selected);
|
select_.ignore_press = false;
|
||||||
|
auto is_prev_no_selected = (select_.mode_selection == selection::mode::no_selected);
|
||||||
|
|
||||||
if (select_.mode_selection == selection::mode_mouse_selected)
|
if (select_.mode_selection == selection::mode::mouse_selected)
|
||||||
{
|
{
|
||||||
select_.mode_selection = selection::mode_no_selected;
|
select_.mode_selection = selection::mode::no_selected;
|
||||||
set_end_caret();
|
set_end_caret();
|
||||||
}
|
}
|
||||||
else if (is_prev_no_selected)
|
else if (is_prev_no_selected)
|
||||||
@ -1842,12 +1893,12 @@ namespace nana{ namespace widgets
|
|||||||
select_.b.y = static_cast<unsigned>(textbase_.lines());
|
select_.b.y = static_cast<unsigned>(textbase_.lines());
|
||||||
if(select_.b.y) --select_.b.y;
|
if(select_.b.y) --select_.b.y;
|
||||||
select_.b.x = static_cast<unsigned>(textbase_.getline(select_.b.y).size());
|
select_.b.x = static_cast<unsigned>(textbase_.getline(select_.b.y).size());
|
||||||
select_.mode_selection = selection::mode_method_selected;
|
select_.mode_selection = selection::mode::method_selected;
|
||||||
render(true);
|
render(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
select_.mode_selection = selection::mode_no_selected;
|
select_.mode_selection = selection::mode::no_selected;
|
||||||
if (_m_cancel_select(0))
|
if (_m_cancel_select(0))
|
||||||
{
|
{
|
||||||
render(true);
|
render(true);
|
||||||
@ -1924,6 +1975,16 @@ namespace nana{ namespace widgets
|
|||||||
return text_position_;
|
return text_position_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void text_editor::focus_behavior(text_focus_behavior behavior)
|
||||||
|
{
|
||||||
|
select_.behavior = behavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
void text_editor::select_behavior(bool move_to_end)
|
||||||
|
{
|
||||||
|
select_.move_to_end = move_to_end;
|
||||||
|
}
|
||||||
|
|
||||||
void text_editor::draw_corner()
|
void text_editor::draw_corner()
|
||||||
{
|
{
|
||||||
if(text_area_.vscroll && text_area_.hscroll)
|
if(text_area_.vscroll && text_area_.hscroll)
|
||||||
@ -2339,27 +2400,45 @@ namespace nana{ namespace widgets
|
|||||||
size_t lnsz = textbase_.getline(caret.y).size();
|
size_t lnsz = textbase_.getline(caret.y).size();
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case keyboard::os_arrow_left:
|
case keyboard::os_arrow_left:
|
||||||
if (caret.x != 0) {
|
if (select_.move_to_end && (select_.a != select_.b) && (!arg.shift))
|
||||||
--caret.x;
|
{
|
||||||
|
caret = select_.a;
|
||||||
changed = true;
|
changed = true;
|
||||||
}else {
|
}
|
||||||
if (caret.y != 0) {
|
else
|
||||||
--caret.y;
|
{
|
||||||
caret.x = static_cast<decltype(caret.x)>(textbase_.getline(caret.y).size());
|
if (caret.x != 0) {
|
||||||
|
--caret.x;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (caret.y != 0) {
|
||||||
|
--caret.y;
|
||||||
|
caret.x = static_cast<decltype(caret.x)>(textbase_.getline(caret.y).size());
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case keyboard::os_arrow_right:
|
case keyboard::os_arrow_right:
|
||||||
if (caret.x < lnsz) {
|
if (select_.move_to_end && (select_.a != select_.b) && (!arg.shift))
|
||||||
++caret.x;
|
{
|
||||||
|
caret = select_.b;
|
||||||
changed = true;
|
changed = true;
|
||||||
}else {
|
}
|
||||||
if (caret.y != nlines - 1) {
|
else
|
||||||
++caret.y;
|
{
|
||||||
caret.x = 0;
|
if (caret.x < lnsz) {
|
||||||
|
++caret.x;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (caret.y != nlines - 1) {
|
||||||
|
++caret.y;
|
||||||
|
caret.x = 0;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case keyboard::os_arrow_up:
|
case keyboard::os_arrow_up:
|
||||||
@ -2411,6 +2490,7 @@ namespace nana{ namespace widgets
|
|||||||
if (select_.a != caret || select_.b != caret) {
|
if (select_.a != caret || select_.b != caret) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
if (arg.shift) {
|
if (arg.shift) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
|||||||
@ -94,14 +94,9 @@ namespace drawerbase {
|
|||||||
|
|
||||||
void drawer::focus(graph_reference graph, const arg_focus& arg)
|
void drawer::focus(graph_reference graph, const arg_focus& arg)
|
||||||
{
|
{
|
||||||
refresh(graph);
|
if (!editor_->focus_changed(arg))
|
||||||
if (!editor_->attr().multi_lines && arg.getting)
|
refresh(graph);
|
||||||
{
|
|
||||||
editor_->select(true);
|
|
||||||
editor_->move_caret_end();
|
|
||||||
}
|
|
||||||
editor_->show_caret(arg.getting);
|
|
||||||
editor_->reset_caret();
|
|
||||||
API::lazy_refresh();
|
API::lazy_refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,6 +585,22 @@ namespace drawerbase {
|
|||||||
return (editor ? editor->line_height() : 0);
|
return (editor ? editor->line_height() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void textbox::focus_behavior(text_focus_behavior behavior)
|
||||||
|
{
|
||||||
|
internal_scope_guard lock;
|
||||||
|
auto editor = get_drawer_trigger().editor();
|
||||||
|
if (editor)
|
||||||
|
editor->focus_behavior(behavior);
|
||||||
|
}
|
||||||
|
|
||||||
|
void textbox::select_behavior(bool move_to_end)
|
||||||
|
{
|
||||||
|
internal_scope_guard lock;
|
||||||
|
auto editor = get_drawer_trigger().editor();
|
||||||
|
if (editor)
|
||||||
|
editor->select_behavior(move_to_end);
|
||||||
|
}
|
||||||
|
|
||||||
//Override _m_caption for caption()
|
//Override _m_caption for caption()
|
||||||
auto textbox::_m_caption() const throw() -> native_string_type
|
auto textbox::_m_caption() const throw() -> native_string_type
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user