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,
|
||||
|
||||
//System Code for OS
|
||||
os_tab = 0x09,
|
||||
os_shift = 0x10,
|
||||
os_ctrl = 0x11,
|
||||
os_pageup = 0x21, os_pagedown,
|
||||
|
||||
@ -424,9 +424,18 @@ namespace nana
|
||||
|
||||
struct arg_focus : public event_arg
|
||||
{
|
||||
::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?
|
||||
/// A constant to indicate how keyboard focus emitted.
|
||||
enum class reason
|
||||
{
|
||||
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
|
||||
|
||||
@ -117,8 +117,9 @@ namespace nana{
|
||||
nana::paint::graphics root_graph;
|
||||
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_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
|
||||
|
||||
@ -136,7 +136,7 @@ namespace detail
|
||||
|
||||
std::vector<core_window_t*> get_children(core_window_t*) const;
|
||||
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*);
|
||||
void capture_ignore_children(bool ignore);
|
||||
|
||||
@ -283,8 +283,14 @@ namespace API
|
||||
cursor window_cursor(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);
|
||||
|
||||
/// Returns the current keyboard focus window.
|
||||
window focus_window();
|
||||
|
||||
/// Sets the keyboard focus for a specified window.
|
||||
void focus_window(window);
|
||||
|
||||
window capture_window();
|
||||
|
||||
@ -229,6 +229,9 @@ namespace nana{ namespace widgets
|
||||
|
||||
/// Returns text position of each line that currently displays on screen
|
||||
const std::vector<upoint>& text_position() const;
|
||||
|
||||
void focus_behavior(text_focus_behavior);
|
||||
void select_behavior(bool move_to_end);
|
||||
public:
|
||||
void draw_corner();
|
||||
void render(bool focused);
|
||||
@ -249,6 +252,8 @@ namespace nana{ namespace widgets
|
||||
const upoint& caret() const;
|
||||
point caret_screen_pos() const;
|
||||
bool scroll(bool upwards, bool vertical);
|
||||
|
||||
bool focus_changed(const arg_focus&);
|
||||
bool mouse_enter(bool);
|
||||
bool mouse_move(bool left_button, const point& screen_pos);
|
||||
bool mouse_pressed(const arg_mouse& arg);
|
||||
@ -353,10 +358,13 @@ namespace nana{ namespace widgets
|
||||
|
||||
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 ignore_press;
|
||||
nana::upoint a, b;
|
||||
}select_;
|
||||
|
||||
|
||||
@ -11,6 +11,15 @@ namespace nana
|
||||
{
|
||||
namespace skeletons
|
||||
{
|
||||
enum class text_focus_behavior
|
||||
{
|
||||
none,
|
||||
select,
|
||||
select_if_tabstop,
|
||||
select_if_click,
|
||||
select_if_tabstop_or_click
|
||||
};
|
||||
|
||||
//forward declaration
|
||||
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:
|
||||
using text_focus_behavior = widgets::skeletons::text_focus_behavior;
|
||||
|
||||
using text_positions = std::vector<upoint>;
|
||||
/// The default constructor without creating the widget.
|
||||
textbox();
|
||||
@ -207,6 +209,14 @@ namespace nana
|
||||
|
||||
/// Returns the height of line in pixels
|
||||
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:
|
||||
//Overrides widget's virtual functions
|
||||
native_string_type _m_caption() const throw() override;
|
||||
|
||||
@ -255,7 +255,7 @@ namespace detail
|
||||
if ((!wd) && pre)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -479,6 +479,7 @@ namespace detail
|
||||
arg.window_handle = reinterpret_cast<window>(wd);
|
||||
arg.receiver = recv;
|
||||
arg.getting = getting;
|
||||
arg.focus_reason = arg_focus::reason::general;
|
||||
}
|
||||
|
||||
void assign_arg(arg_wheel& arg, basic_window* wd, const XEvent& evt)
|
||||
@ -701,7 +702,7 @@ namespace detail
|
||||
arg.receiver = native_window;
|
||||
arg.getting = true;
|
||||
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;
|
||||
case FocusOut:
|
||||
@ -765,7 +766,7 @@ namespace detail
|
||||
if (new_focus && !new_focus->flags.ignore_mouse_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)
|
||||
brock.wd_manager().do_lazy_refresh(kill_focus, false);
|
||||
}
|
||||
@ -1048,7 +1049,8 @@ namespace detail
|
||||
auto tstop_wd = wd_manager.tabstop(msgwnd, !argkey.shift);
|
||||
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(tstop_wd, true);
|
||||
}
|
||||
@ -1144,8 +1146,8 @@ namespace detail
|
||||
arg.ignore = false;
|
||||
arg.key = charbuf[i];
|
||||
|
||||
// When tab is pressed, only tab-eating mode is allowed
|
||||
if ((keyboard::tab == arg.key) && !(msgwnd->flags.tab & tab_type::eating))
|
||||
//Only accept tab when it is not ignored.
|
||||
if ((keyboard::tab == arg.key) && root_runtime->condition.ignore_tab)
|
||||
continue;
|
||||
|
||||
if(context.is_alt_pressed)
|
||||
@ -1185,52 +1187,61 @@ namespace detail
|
||||
nana::detail::platform_spec::instance().write_keystate(xevent.xkey);
|
||||
{
|
||||
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)
|
||||
context.is_ctrl_pressed = false;
|
||||
|
||||
msgwnd = brock.focus();
|
||||
if(msgwnd)
|
||||
{
|
||||
if(msgwnd == pressed_wd_space)
|
||||
{
|
||||
msgwnd->flags.action = mouse_action::normal;
|
||||
if (('\t' == os_code) && root_runtime->condition.ignore_tab)
|
||||
{
|
||||
root_runtime->condition.ignore_tab = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
msgwnd = brock.focus();
|
||||
if(msgwnd)
|
||||
{
|
||||
if(msgwnd == pressed_wd_space)
|
||||
{
|
||||
msgwnd->flags.action = mouse_action::normal;
|
||||
|
||||
arg_click click_arg;
|
||||
click_arg.mouse_args = nullptr;
|
||||
click_arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
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;
|
||||
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);
|
||||
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.ignore = false;
|
||||
arg.key = os_code;
|
||||
brock.get_key_state(arg);
|
||||
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)
|
||||
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);
|
||||
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.evt_code = event_code::key_release;
|
||||
|
||||
@ -549,6 +549,7 @@ namespace detail
|
||||
arg.window_handle = reinterpret_cast<window>(wd);
|
||||
arg.receiver = recv;
|
||||
arg.getting = getting;
|
||||
arg.focus_reason = arg_focus::reason::general;
|
||||
}
|
||||
|
||||
void assign_arg(arg_wheel& arg, basic_window* wd, const parameter_decoder& pmdec)
|
||||
@ -882,7 +883,7 @@ namespace detail
|
||||
arg_focus arg;
|
||||
assign_arg(arg, focus, native_window, true);
|
||||
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;
|
||||
break;
|
||||
@ -922,7 +923,7 @@ namespace detail
|
||||
{
|
||||
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)
|
||||
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);
|
||||
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)
|
||||
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);
|
||||
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.evt_code = event_code::key_release;
|
||||
@ -1414,14 +1415,16 @@ namespace detail
|
||||
if(msgwnd)
|
||||
{
|
||||
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);
|
||||
|
||||
auto tstop_wd = wd_manager.tabstop(msgwnd, is_forward);
|
||||
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(tstop_wd, true);
|
||||
}
|
||||
@ -1479,8 +1482,10 @@ namespace detail
|
||||
msgwnd = brock.focus();
|
||||
if (msgwnd && msgwnd->flags.enabled)
|
||||
{
|
||||
// When tab is pressed, only tab-eating mode is allowed
|
||||
if ((9 != wParam) || (msgwnd->flags.tab & tab_type::eating))
|
||||
auto & wd_manager = brock.wd_manager();
|
||||
|
||||
//Only accept tab when it is not ignored.
|
||||
if (VK_TAB != wParam || !root_runtime->condition.ignore_tab)
|
||||
{
|
||||
arg_keyboard arg;
|
||||
arg.evt_code = event_code::key_char;
|
||||
@ -1490,55 +1495,62 @@ namespace detail
|
||||
arg.ignore = false;
|
||||
|
||||
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.wd_manager().do_lazy_refresh(msgwnd, false);
|
||||
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case WM_KEYUP:
|
||||
if(wParam != VK_MENU) //MUST NOT BE AN ALT
|
||||
{
|
||||
msgwnd = brock.focus();
|
||||
if(msgwnd)
|
||||
if (VK_TAB == wParam && root_runtime->condition.ignore_tab)
|
||||
{
|
||||
if (msgwnd == pressed_wd_space)
|
||||
root_runtime->condition.ignore_tab = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
msgwnd = brock.focus();
|
||||
if (msgwnd)
|
||||
{
|
||||
msgwnd->flags.action = mouse_action::normal;
|
||||
|
||||
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))
|
||||
if (msgwnd == pressed_wd_space)
|
||||
{
|
||||
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);
|
||||
msgwnd->flags.action = mouse_action::normal;
|
||||
|
||||
emit_drawer(&drawer::mouse_up, msgwnd, arg, &context);
|
||||
brock.wd_manager().do_lazy_refresh(msgwnd, false);
|
||||
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;
|
||||
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()))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -925,7 +925,7 @@ namespace detail
|
||||
|
||||
//set_focus
|
||||
//@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!
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
@ -951,6 +951,7 @@ namespace detail
|
||||
arg.getting = false;
|
||||
arg.window_handle = reinterpret_cast<window>(prev_focus);
|
||||
arg.receiver = wd->root;
|
||||
arg.focus_reason = arg_focus::reason::general;
|
||||
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.getting = true;
|
||||
arg.receiver = wd->root;
|
||||
arg.focus_reason = reason;
|
||||
brock.emit(event_code::focus, wd, arg, true, brock.get_thread_context());
|
||||
|
||||
if (!root_has_been_focused)
|
||||
|
||||
@ -929,7 +929,7 @@ namespace API
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1171,7 +1171,7 @@ namespace API
|
||||
window move_tabstop(window wd, bool 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);
|
||||
return reinterpret_cast<window>(ts_wd);
|
||||
}
|
||||
|
||||
@ -1289,7 +1289,11 @@ namespace nana{ namespace widgets
|
||||
text_area_.tab_space = 4;
|
||||
text_area_.scroll_pixels = 16;
|
||||
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;
|
||||
|
||||
API::create_caret(wd, 1, line_height());
|
||||
@ -1348,11 +1352,13 @@ namespace nana{ namespace widgets
|
||||
void text_editor::erase_keyword(const ::std::wstring& kw)
|
||||
{
|
||||
for (auto i = keywords_->kwbase.begin(); i != keywords_->kwbase.end(); ++i)
|
||||
{
|
||||
if (i->text == kw)
|
||||
{
|
||||
keywords_->kwbase.erase(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void text_editor::set_accept(std::function<bool(char_type)> pred)
|
||||
@ -1624,6 +1630,47 @@ namespace nana{ namespace widgets
|
||||
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)
|
||||
{
|
||||
if((false == enter) && (false == text_area_.captured))
|
||||
@ -1649,7 +1696,7 @@ namespace nana{ namespace widgets
|
||||
auto caret_pos_before = caret();
|
||||
mouse_caret(scrpos);
|
||||
|
||||
if(select_.mode_selection != selection::mode_no_selected)
|
||||
if(select_.mode_selection != selection::mode::no_selected)
|
||||
set_end_caret();
|
||||
else if ((!select_.dragged) && (caret_pos_before != caret()))
|
||||
select_.dragged = true;
|
||||
@ -1664,8 +1711,11 @@ namespace nana{ namespace widgets
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (::nana::mouse::left_button == arg.button)
|
||||
{
|
||||
@ -1691,7 +1741,7 @@ namespace nana{ namespace widgets
|
||||
}
|
||||
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());
|
||||
@ -1699,11 +1749,12 @@ namespace nana{ namespace widgets
|
||||
}
|
||||
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();
|
||||
}
|
||||
else if (is_prev_no_selected)
|
||||
@ -1842,12 +1893,12 @@ namespace nana{ namespace widgets
|
||||
select_.b.y = static_cast<unsigned>(textbase_.lines());
|
||||
if(select_.b.y) --select_.b.y;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
select_.mode_selection = selection::mode_no_selected;
|
||||
select_.mode_selection = selection::mode::no_selected;
|
||||
if (_m_cancel_select(0))
|
||||
{
|
||||
render(true);
|
||||
@ -1924,6 +1975,16 @@ namespace nana{ namespace widgets
|
||||
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()
|
||||
{
|
||||
if(text_area_.vscroll && text_area_.hscroll)
|
||||
@ -2339,27 +2400,45 @@ namespace nana{ namespace widgets
|
||||
size_t lnsz = textbase_.getline(caret.y).size();
|
||||
switch (key) {
|
||||
case keyboard::os_arrow_left:
|
||||
if (caret.x != 0) {
|
||||
--caret.x;
|
||||
if (select_.move_to_end && (select_.a != select_.b) && (!arg.shift))
|
||||
{
|
||||
caret = select_.a;
|
||||
changed = true;
|
||||
}else {
|
||||
if (caret.y != 0) {
|
||||
--caret.y;
|
||||
caret.x = static_cast<decltype(caret.x)>(textbase_.getline(caret.y).size());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (caret.x != 0) {
|
||||
--caret.x;
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
if (caret.y != 0) {
|
||||
--caret.y;
|
||||
caret.x = static_cast<decltype(caret.x)>(textbase_.getline(caret.y).size());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case keyboard::os_arrow_right:
|
||||
if (caret.x < lnsz) {
|
||||
++caret.x;
|
||||
if (select_.move_to_end && (select_.a != select_.b) && (!arg.shift))
|
||||
{
|
||||
caret = select_.b;
|
||||
changed = true;
|
||||
}else {
|
||||
if (caret.y != nlines - 1) {
|
||||
++caret.y;
|
||||
caret.x = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (caret.x < lnsz) {
|
||||
++caret.x;
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
if (caret.y != nlines - 1) {
|
||||
++caret.y;
|
||||
caret.x = 0;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case keyboard::os_arrow_up:
|
||||
@ -2411,6 +2490,7 @@ namespace nana{ namespace widgets
|
||||
if (select_.a != caret || select_.b != caret) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (arg.shift) {
|
||||
switch (key) {
|
||||
|
||||
@ -94,14 +94,9 @@ namespace drawerbase {
|
||||
|
||||
void drawer::focus(graph_reference graph, const arg_focus& arg)
|
||||
{
|
||||
refresh(graph);
|
||||
if (!editor_->attr().multi_lines && arg.getting)
|
||||
{
|
||||
editor_->select(true);
|
||||
editor_->move_caret_end();
|
||||
}
|
||||
editor_->show_caret(arg.getting);
|
||||
editor_->reset_caret();
|
||||
if (!editor_->focus_changed(arg))
|
||||
refresh(graph);
|
||||
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
@ -590,6 +585,22 @@ namespace drawerbase {
|
||||
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()
|
||||
auto textbox::_m_caption() const throw() -> native_string_type
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user