Merge branch 'hotfixes-1.0.1' into develop
Conflicts: .gitignore include/nana/deploy.hpp source/deploy.cpp source/gui/widgets/listbox.cpp
This commit is contained in:
@@ -347,6 +347,7 @@ namespace nana
|
||||
flags.destroying = false;
|
||||
flags.borderless = false;
|
||||
flags.make_bground_declared = false;
|
||||
flags.ignore_menubar_focus = false;
|
||||
|
||||
visible = false;
|
||||
|
||||
@@ -355,7 +356,6 @@ namespace nana
|
||||
effect.bground_fade_rate = 0;
|
||||
|
||||
together.caret = nullptr;
|
||||
together.attached_events = nullptr;
|
||||
|
||||
extra_width = extra_height = 0;
|
||||
|
||||
@@ -368,16 +368,15 @@ namespace nana
|
||||
|
||||
bool basic_window::set_events(const std::shared_ptr<general_events>& p)
|
||||
{
|
||||
if (together.attached_events)
|
||||
if (together.events_ptr)
|
||||
return false;
|
||||
together.events_ptr = p;
|
||||
together.attached_events = p.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
general_events * basic_window::get_events() const
|
||||
{
|
||||
return together.attached_events;
|
||||
return together.events_ptr.get();
|
||||
}
|
||||
//end struct basic_window
|
||||
}//end namespace detail
|
||||
|
||||
@@ -146,6 +146,9 @@ namespace nana
|
||||
|
||||
void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg)
|
||||
{
|
||||
auto retain = wd->together.events_ptr;
|
||||
auto evts_ptr = retain.get();
|
||||
|
||||
switch (evt_code)
|
||||
{
|
||||
case event_code::click:
|
||||
@@ -162,35 +165,36 @@ namespace nana
|
||||
|
||||
void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&);
|
||||
::nana::basic_event<arg_mouse>* evt_addr;
|
||||
|
||||
switch (evt_code)
|
||||
{
|
||||
case event_code::click:
|
||||
drawer_event_fn = &drawer::click;
|
||||
evt_addr = &wd->together.attached_events->click;
|
||||
evt_addr = &evts_ptr->click;
|
||||
break;
|
||||
case event_code::dbl_click:
|
||||
drawer_event_fn = &drawer::dbl_click;
|
||||
evt_addr = &wd->together.attached_events->dbl_click;
|
||||
evt_addr = &evts_ptr->dbl_click;
|
||||
break;
|
||||
case event_code::mouse_enter:
|
||||
drawer_event_fn = &drawer::mouse_enter;
|
||||
evt_addr = &wd->together.attached_events->mouse_enter;
|
||||
evt_addr = &evts_ptr->mouse_enter;
|
||||
break;
|
||||
case event_code::mouse_move:
|
||||
drawer_event_fn = &drawer::mouse_move;
|
||||
evt_addr = &wd->together.attached_events->mouse_move;
|
||||
evt_addr = &evts_ptr->mouse_move;
|
||||
break;
|
||||
case event_code::mouse_leave:
|
||||
drawer_event_fn = &drawer::mouse_leave;
|
||||
evt_addr = &wd->together.attached_events->mouse_leave;
|
||||
evt_addr = &evts_ptr->mouse_leave;
|
||||
break;
|
||||
case event_code::mouse_down:
|
||||
drawer_event_fn = &drawer::mouse_down;
|
||||
evt_addr = &wd->together.attached_events->mouse_down;
|
||||
evt_addr = &evts_ptr->mouse_down;
|
||||
break;
|
||||
case event_code::mouse_up:
|
||||
drawer_event_fn = &drawer::mouse_up;
|
||||
evt_addr = &wd->together.attached_events->mouse_up;
|
||||
evt_addr = &evts_ptr->mouse_up;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid mouse event code");
|
||||
@@ -209,7 +213,7 @@ namespace nana
|
||||
{
|
||||
wd->drawer.mouse_wheel(*arg);
|
||||
if (!draw_only)
|
||||
wd->together.attached_events->mouse_wheel.emit(*arg);
|
||||
evts_ptr->mouse_wheel.emit(*arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -229,19 +233,19 @@ namespace nana
|
||||
{
|
||||
case event_code::key_press:
|
||||
drawer_event_fn = &drawer::key_press;
|
||||
evt_addr = &wd->together.attached_events->key_press;
|
||||
evt_addr = &evts_ptr->key_press;
|
||||
break;
|
||||
case event_code::key_char:
|
||||
drawer_event_fn = &drawer::key_char;
|
||||
evt_addr = &wd->together.attached_events->key_char;
|
||||
evt_addr = &evts_ptr->key_char;
|
||||
break;
|
||||
case event_code::key_release:
|
||||
drawer_event_fn = &drawer::key_release;
|
||||
evt_addr = &wd->together.attached_events->key_release;
|
||||
evt_addr = &evts_ptr->key_release;
|
||||
break;
|
||||
case event_code::shortkey:
|
||||
drawer_event_fn = &drawer::shortkey;
|
||||
evt_addr = &wd->together.attached_events->shortkey;
|
||||
evt_addr = &evts_ptr->shortkey;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid keyboard event code");
|
||||
@@ -256,7 +260,7 @@ namespace nana
|
||||
{
|
||||
auto arg = dynamic_cast<const arg_expose*>(&event_arg);
|
||||
if (arg)
|
||||
wd->together.attached_events->expose.emit(*arg);
|
||||
evts_ptr->expose.emit(*arg);
|
||||
}
|
||||
break;
|
||||
case event_code::focus:
|
||||
@@ -266,7 +270,7 @@ namespace nana
|
||||
{
|
||||
wd->drawer.focus(*arg);
|
||||
if (!draw_only)
|
||||
wd->together.attached_events->focus.emit(*arg);
|
||||
evts_ptr->focus.emit(*arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -277,7 +281,7 @@ namespace nana
|
||||
{
|
||||
wd->drawer.move(*arg);
|
||||
if (!draw_only)
|
||||
wd->together.attached_events->move.emit(*arg);
|
||||
evts_ptr->move.emit(*arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -288,7 +292,7 @@ namespace nana
|
||||
{
|
||||
wd->drawer.resizing(*arg);
|
||||
if (!draw_only)
|
||||
wd->together.attached_events->resizing.emit(*arg);
|
||||
evts_ptr->resizing.emit(*arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -299,7 +303,7 @@ namespace nana
|
||||
{
|
||||
wd->drawer.resized(*arg);
|
||||
if (!draw_only)
|
||||
wd->together.attached_events->resized.emit(*arg);
|
||||
evts_ptr->resized.emit(*arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -309,9 +313,9 @@ namespace nana
|
||||
auto arg = dynamic_cast<const arg_unload*>(&event_arg);
|
||||
if (arg && (wd->other.category == category::flags::root))
|
||||
{
|
||||
auto evt_ptr = dynamic_cast<events_root_extension*>(wd->together.attached_events);
|
||||
if (evt_ptr)
|
||||
evt_ptr->unload.emit(*arg);
|
||||
auto evt_root = dynamic_cast<events_root_extension*>(evts_ptr);
|
||||
if (evt_root)
|
||||
evt_root->unload.emit(*arg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -320,7 +324,7 @@ namespace nana
|
||||
{
|
||||
auto arg = dynamic_cast<const arg_destroy*>(&event_arg);
|
||||
if (arg)
|
||||
wd->together.attached_events->destroy.emit(*arg);
|
||||
evts_ptr->destroy.emit(*arg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Bedrock Selector
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Nana Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <nana/detail/linux_X11/platform_spec.hpp>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
typedef detail::edge_nimbus_renderer<detail::bedrock::core_window_t> edge_nimbus_renderer_t;
|
||||
@@ -351,12 +349,13 @@ namespace nana
|
||||
{
|
||||
if(p)
|
||||
{
|
||||
auto i = std::find(dynamic_drawing_objects_.begin(), dynamic_drawing_objects_.end(), p);
|
||||
if (i != dynamic_drawing_objects_.end())
|
||||
{
|
||||
delete (*i);
|
||||
dynamic_drawing_objects_.erase(i);
|
||||
}
|
||||
for (auto i = dynamic_drawing_objects_.begin(); i != dynamic_drawing_objects_.end(); ++i)
|
||||
if (*i == p)
|
||||
{
|
||||
delete (*i);
|
||||
dynamic_drawing_objects_.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,6 @@ namespace nana
|
||||
reinterpret_cast<detail::docker_interface*>(evt)->get_event()->remove(evt);
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t events_operation::size() const
|
||||
{
|
||||
lock_guard lock(mutex_);
|
||||
return register_.size();
|
||||
}
|
||||
//end namespace events_operation
|
||||
}//end namespace detail
|
||||
}//end namespace nana
|
||||
@@ -102,27 +102,18 @@ namespace detail
|
||||
{
|
||||
struct thread_context_cache
|
||||
{
|
||||
unsigned tid;
|
||||
thread_context *object;
|
||||
unsigned tid{ 0 };
|
||||
thread_context *object{ nullptr };
|
||||
}tcontext;
|
||||
|
||||
cache_type()
|
||||
{
|
||||
tcontext.tid = 0;
|
||||
tcontext.object = nullptr;
|
||||
}
|
||||
}cache;
|
||||
|
||||
struct menu_tag
|
||||
{
|
||||
menu_tag()
|
||||
:taken_window(nullptr), window(nullptr), owner(nullptr), has_keyboard(false)
|
||||
{}
|
||||
|
||||
core_window_t* taken_window;
|
||||
native_window_type window;
|
||||
native_window_type owner;
|
||||
bool has_keyboard;
|
||||
core_window_t* taken_window{ nullptr };
|
||||
bool delay_restore{ false };
|
||||
native_window_type window{ nullptr };
|
||||
native_window_type owner{ nullptr };
|
||||
bool has_keyboard{ false };
|
||||
}menu;
|
||||
|
||||
struct keyboard_tracking_state_tag
|
||||
@@ -282,14 +273,39 @@ namespace detail
|
||||
|
||||
void bedrock::set_menubar_taken(core_window_t* wd)
|
||||
{
|
||||
auto pre = impl_->menu.taken_window;
|
||||
impl_->menu.taken_window = wd;
|
||||
|
||||
//assigning of a nullptr taken window is to restore the focus of pre taken
|
||||
if ((!wd) && pre)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
wd_manager.set_focus(pre, false);
|
||||
wd_manager.update(pre, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
bedrock::core_window_t* bedrock::get_menubar_taken()
|
||||
//0:Enable delay, 1:Cancel, 2:Restores, 3: Restores when menu is destroying
|
||||
void bedrock::delay_restore(int state)
|
||||
{
|
||||
core_window_t* wd = impl_->menu.taken_window;
|
||||
impl_->menu.taken_window = nullptr;
|
||||
return wd;
|
||||
switch (state)
|
||||
{
|
||||
case 0: //Enable
|
||||
break;
|
||||
case 1: //Cancel
|
||||
break;
|
||||
case 2: //Restore if key released
|
||||
//restores the focus when menu is closed by pressing keyboard
|
||||
if (!impl_->menu.window)
|
||||
set_menubar_taken(nullptr);
|
||||
break;
|
||||
case 3: //Restores if destroying
|
||||
//when the menu is destroying, restores the focus if delay restore is not declared
|
||||
if (!impl_->menu.delay_restore)
|
||||
set_menubar_taken(nullptr);
|
||||
}
|
||||
|
||||
impl_->menu.delay_restore = (0 == state);
|
||||
}
|
||||
|
||||
bool bedrock::close_menu_if_focus_other_window(native_window_type wd)
|
||||
@@ -304,7 +320,7 @@ namespace detail
|
||||
else
|
||||
return false;
|
||||
}
|
||||
remove_menu();
|
||||
erase_menu(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -314,7 +330,7 @@ namespace detail
|
||||
{
|
||||
if(menu_window && impl_->menu.window != menu_window)
|
||||
{
|
||||
remove_menu();
|
||||
erase_menu(true);
|
||||
impl_->menu.window = menu_window;
|
||||
impl_->menu.owner = native_interface::get_owner_window(menu_window);
|
||||
impl_->menu.has_keyboard = has_keyboard;
|
||||
@@ -338,21 +354,13 @@ namespace detail
|
||||
return impl_->menu.window;
|
||||
}
|
||||
|
||||
void bedrock::remove_menu()
|
||||
void bedrock::erase_menu(bool try_destroy)
|
||||
{
|
||||
if(impl_->menu.window)
|
||||
if (impl_->menu.window)
|
||||
{
|
||||
native_window_type delwin = impl_->menu.window;
|
||||
impl_->menu.window = impl_->menu.owner = nullptr;
|
||||
impl_->menu.has_keyboard = false;
|
||||
native_interface::close_window(delwin);
|
||||
}
|
||||
}
|
||||
if (try_destroy)
|
||||
native_interface::close_window(impl_->menu.window);
|
||||
|
||||
void bedrock::empty_menu()
|
||||
{
|
||||
if(impl_->menu.window)
|
||||
{
|
||||
impl_->menu.window = impl_->menu.owner = nullptr;
|
||||
impl_->menu.has_keyboard = false;
|
||||
}
|
||||
@@ -363,6 +371,7 @@ namespace detail
|
||||
XKeyEvent xkey;
|
||||
nana::detail::platform_spec::instance().read_keystate(xkey);
|
||||
arg.ctrl = (xkey.state & ControlMask);
|
||||
arg.shift = (xkey.state & ShiftMask);
|
||||
}
|
||||
|
||||
bool bedrock::set_keyboard_shortkey(bool yes)
|
||||
@@ -372,6 +381,11 @@ namespace detail
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool bedrock::whether_keyboard_shortkey() const
|
||||
{
|
||||
return impl_->keyboard_tracking_state.has_shortkey_occured;
|
||||
}
|
||||
|
||||
element_store& bedrock::get_element_store() const
|
||||
{
|
||||
return impl_->estore;
|
||||
@@ -569,7 +583,7 @@ namespace detail
|
||||
delete msg.u.mouse_drop.files;
|
||||
arg.pos.x = msg.u.mouse_drop.x - msgwd->pos_root.x;
|
||||
arg.pos.y = msg.u.mouse_drop.y - msgwd->pos_root.y;
|
||||
msgwd->together.attached_events->mouse_dropfiles.emit(arg);
|
||||
msgwd->together.events_ptr->mouse_dropfiles.emit(arg);
|
||||
brock.wd_manager.do_lazy_refresh(msgwd, false);
|
||||
}
|
||||
break;
|
||||
@@ -700,8 +714,8 @@ namespace detail
|
||||
msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y);
|
||||
if(nullptr == msgwnd) break;
|
||||
|
||||
if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
|
||||
brock.remove_menu();
|
||||
if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
|
||||
brock.erase_menu(true);
|
||||
else
|
||||
brock.close_menu_if_focus_other_window(msgwnd->root);
|
||||
|
||||
@@ -719,12 +733,11 @@ namespace detail
|
||||
if(kill_focus != new_focus)
|
||||
brock.wd_manager.do_lazy_refresh(kill_focus, false);
|
||||
}
|
||||
auto retain = msgwnd->together.events_ptr;
|
||||
msgwnd->root_widget->other.attribute.root->context.focus_changed = false;
|
||||
|
||||
context.event_window = msgwnd;
|
||||
|
||||
pressed_wd = nullptr;
|
||||
//make_eventinfo(ei, msgwnd, message, xevent);
|
||||
msgwnd->flags.action = mouse_action::pressed;
|
||||
arg_mouse arg;
|
||||
assign_arg(arg, msgwnd, ButtonPress, xevent);
|
||||
@@ -753,7 +766,7 @@ namespace detail
|
||||
nana::point mspos{xevent.xbutton.x, xevent.xbutton.y};
|
||||
while(msgwnd)
|
||||
{
|
||||
if(msgwnd->together.attached_events->mouse_wheel.length() != 0)
|
||||
if(msgwnd->together.events_ptr->mouse_wheel.length() != 0)
|
||||
{
|
||||
mspos -= msgwnd->pos_root;
|
||||
arg_wheel arg;
|
||||
@@ -774,6 +787,8 @@ namespace detail
|
||||
msgwnd->flags.action = mouse_action::normal;
|
||||
if(msgwnd->flags.enabled)
|
||||
{
|
||||
auto retain = msgwnd->together.events_ptr;
|
||||
|
||||
arg_mouse arg;
|
||||
assign_arg(arg, msgwnd, message, xevent);
|
||||
|
||||
@@ -795,27 +810,29 @@ namespace detail
|
||||
{
|
||||
if(hit)
|
||||
msgwnd->flags.action = mouse_action::over;
|
||||
|
||||
auto retain = msgwnd->together.events_ptr;
|
||||
auto evt_ptr = retain.get();
|
||||
|
||||
auto events_ptr = msgwnd->together.events_ptr;
|
||||
arg.evt_code = event_code::mouse_up;
|
||||
emit_drawer(&drawer::mouse_up, msgwnd, arg, &context);
|
||||
|
||||
if(fire_click)
|
||||
{
|
||||
arg.evt_code = event_code::click;
|
||||
msgwnd->together.attached_events->click.emit(arg);
|
||||
evt_ptr->click.emit(arg);
|
||||
}
|
||||
|
||||
if (brock.wd_manager.available(msgwnd))
|
||||
{
|
||||
arg.evt_code = event_code::mouse_up;
|
||||
msgwnd->together.attached_events->mouse_up.emit(arg);
|
||||
evt_ptr->mouse_up.emit(arg);
|
||||
}
|
||||
}
|
||||
else if(fire_click)
|
||||
{
|
||||
arg.evt_code = event_code::click;
|
||||
msgwnd->together.attached_events->click.emit(arg);
|
||||
msgwnd->together.events_ptr->click.emit(arg);
|
||||
}
|
||||
brock.wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
}
|
||||
@@ -828,8 +845,11 @@ namespace detail
|
||||
if(brock.wd_manager.available(msgwnd))
|
||||
{
|
||||
//The msgwnd may be destroyed if the window is destroyed by calling native interface of close_window().
|
||||
if(msgwnd->root == brock.get_menu())
|
||||
brock.empty_menu();
|
||||
if (msgwnd->root == brock.get_menu())
|
||||
{
|
||||
brock.erase_menu(false);
|
||||
brock.delay_restore(3); //Restores if delay_restore not decleared
|
||||
}
|
||||
|
||||
spec.remove(native_window);
|
||||
brock.wd_manager.destroy(msgwnd);
|
||||
@@ -928,6 +948,9 @@ namespace detail
|
||||
nana::detail::platform_spec::instance().write_keystate(xevent.xkey);
|
||||
if(msgwnd->flags.enabled)
|
||||
{
|
||||
if (brock.get_menu())
|
||||
brock.delay_restore(0); //Enable delay restore
|
||||
|
||||
if(msgwnd->root != brock.get_menu())
|
||||
msgwnd = brock.focus();
|
||||
|
||||
@@ -961,8 +984,8 @@ namespace detail
|
||||
else
|
||||
{
|
||||
nana::detail::platform_scope_guard psg;
|
||||
status = XLookupBoth;
|
||||
len = ::XLookupString(&xevent.xkey, keybuf, 32, &keysym, 0);
|
||||
status = XLookupKeySym;
|
||||
keysym = ::XLookupKeysym(&xevent.xkey, 0);
|
||||
}
|
||||
|
||||
keybuf[len] = 0;
|
||||
@@ -999,7 +1022,9 @@ namespace detail
|
||||
context.platform.keychar = keychar;
|
||||
if(keychar == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab
|
||||
{
|
||||
auto the_next = brock.wd_manager.tabstop(msgwnd, true);
|
||||
arg_keyboard argkey;
|
||||
brock.get_key_state(argkey);
|
||||
auto the_next = brock.wd_manager.tabstop(msgwnd, !argkey.shift);
|
||||
if(the_next)
|
||||
{
|
||||
brock.wd_manager.set_focus(the_next, false);
|
||||
@@ -1010,12 +1035,31 @@ namespace detail
|
||||
else if(keyboard::alt == keychar)
|
||||
{
|
||||
context.is_alt_pressed = true;
|
||||
if (brock.whether_keyboard_shortkey() == false)
|
||||
{
|
||||
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
|
||||
if (msgwnd)
|
||||
{
|
||||
bool focused = (brock.focus() == msgwnd);
|
||||
arg_keyboard arg;
|
||||
arg.evt_code = event_code::key_press;
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
arg.ignore = false;
|
||||
arg.key = static_cast<nana::char_t>(keychar);
|
||||
brock.get_key_state(arg);
|
||||
brock.emit(event_code::key_press, msgwnd, arg, true, &context);
|
||||
|
||||
msgwnd->root_widget->flags.ignore_menubar_focus = (focused && (brock.focus() != msgwnd));
|
||||
}
|
||||
else
|
||||
brock.erase_menu(true);
|
||||
}
|
||||
}
|
||||
else if(keychar)
|
||||
else
|
||||
{
|
||||
arg_keyboard arg;
|
||||
arg.ignore = false;
|
||||
arg.key = keychar;
|
||||
arg.key = keychar ? keychar : xevent.xkey.keycode;
|
||||
arg.evt_code = event_code::key_press;
|
||||
brock.get_key_state(arg);
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
@@ -1061,7 +1105,7 @@ namespace detail
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
brock.get_key_state(arg);
|
||||
|
||||
msgwnd->together.attached_events->key_char.emit(arg);
|
||||
msgwnd->together.events_ptr->key_char.emit(arg);
|
||||
if(arg.ignore == false && brock.wd_manager.available(msgwnd))
|
||||
brock.emit_drawer(event_code::key_char, msgwnd, arg, &context);
|
||||
}
|
||||
@@ -1092,11 +1136,35 @@ namespace detail
|
||||
brock.get_key_state(arg);
|
||||
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
||||
}
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
}
|
||||
else
|
||||
{
|
||||
context.is_alt_pressed = false;
|
||||
brock.set_keyboard_shortkey(false);
|
||||
if (brock.set_keyboard_shortkey(false) == false)
|
||||
{
|
||||
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
|
||||
if (msgwnd)
|
||||
{
|
||||
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
|
||||
if (set_focus)
|
||||
brock.wd_manager.set_focus(msgwnd, false);
|
||||
|
||||
arg_keyboard arg;
|
||||
arg.evt_code = event_code::key_release;
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
arg.ignore = false;
|
||||
arg.key = static_cast<nana::char_t>(context.platform.keychar);
|
||||
brock.get_key_state(arg);
|
||||
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
||||
|
||||
if (!set_focus)
|
||||
{
|
||||
brock.set_menubar_taken(nullptr);
|
||||
msgwnd->root_widget->flags.ignore_menubar_focus = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <nana/config.hpp>
|
||||
#include PLATFORM_SPEC_HPP
|
||||
#include <nana/gui/detail/native_window_interface.hpp>
|
||||
#include <nana/gui/screen.hpp>
|
||||
#if defined(NANA_WINDOWS)
|
||||
#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED)
|
||||
#include <nana/std_mutex.hpp>
|
||||
@@ -35,10 +36,10 @@ namespace nana{
|
||||
#if defined(NANA_WINDOWS)
|
||||
static HICON icon(const nana::paint::image& img)
|
||||
{
|
||||
paint::detail::image_ico * ico = dynamic_cast<paint::detail::image_ico*>(img.image_ptr_.get());
|
||||
auto ico = dynamic_cast<paint::detail::image_ico*>(img.image_ptr_.get());
|
||||
if(ico && ico->ptr())
|
||||
return *(ico->ptr());
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -51,17 +52,13 @@ namespace nana{
|
||||
{
|
||||
struct window_extra_t
|
||||
{
|
||||
HICON ico;
|
||||
|
||||
window_extra_t()
|
||||
: ico(0)
|
||||
{}
|
||||
HICON ico{nullptr};
|
||||
};
|
||||
|
||||
typedef std::map<native_window_type, window_extra_t> map_t;
|
||||
|
||||
private:
|
||||
tray_manager(){}
|
||||
tray_manager() = default;
|
||||
public:
|
||||
typedef window_extra_t extra_t;
|
||||
|
||||
@@ -205,19 +202,21 @@ namespace nana{
|
||||
if(owner && (nested == false))
|
||||
::ClientToScreen(reinterpret_cast<HWND>(owner), &pt);
|
||||
|
||||
HWND wnd = ::CreateWindowEx(style_ex, STR("NanaWindowInternal"), STR("Nana Window"),
|
||||
HWND native_wd = ::CreateWindowEx(style_ex, STR("NanaWindowInternal"), STR("Nana Window"),
|
||||
style,
|
||||
pt.x, pt.y, 100, 100,
|
||||
reinterpret_cast<HWND>(owner), 0, ::GetModuleHandle(0), 0);
|
||||
|
||||
//A window may have a border, this should be adjusted the client area fit for the specified size.
|
||||
::RECT client;
|
||||
::GetClientRect(wnd, &client); //The right and bottom of client by GetClientRect indicate the width and height of the area
|
||||
::GetClientRect(native_wd, &client); //The right and bottom of client by GetClientRect indicate the width and height of the area
|
||||
::RECT wd_area;
|
||||
::GetWindowRect(wnd, &wd_area);
|
||||
wd_area.right -= wd_area.left;
|
||||
wd_area.bottom -= wd_area.top;
|
||||
if(nested)
|
||||
::GetWindowRect(native_wd, &wd_area);
|
||||
|
||||
//a dimension with borders and caption title
|
||||
wd_area.right -= wd_area.left; //wd_area.right = width
|
||||
wd_area.bottom -= wd_area.top; //wd_area.bottom = height
|
||||
if (nested)
|
||||
{
|
||||
wd_area.left = pt.x;
|
||||
wd_area.top = pt.y;
|
||||
@@ -226,14 +225,15 @@ namespace nana{
|
||||
int delta_w = static_cast<int>(r.width) - client.right;
|
||||
int delta_h = static_cast<int>(r.height) - client.bottom;
|
||||
|
||||
::MoveWindow(wnd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true);
|
||||
::MoveWindow(native_wd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true);
|
||||
|
||||
::GetClientRect(native_wd, &client);
|
||||
::GetWindowRect(native_wd, &wd_area);
|
||||
|
||||
::GetClientRect(wnd, &client);
|
||||
::GetWindowRect(wnd, &wd_area);
|
||||
wd_area.right -= wd_area.left;
|
||||
wd_area.bottom -= wd_area.top;
|
||||
|
||||
window_result result = {reinterpret_cast<native_window_type>(wnd),
|
||||
window_result result = { reinterpret_cast<native_window_type>(native_wd),
|
||||
static_cast<unsigned>(client.right), static_cast<unsigned>(client.bottom),
|
||||
static_cast<unsigned>(wd_area.right - client.right), static_cast<unsigned>(wd_area.bottom - client.bottom)};
|
||||
#elif defined(NANA_X11)
|
||||
@@ -556,6 +556,7 @@ namespace nana{
|
||||
{
|
||||
::EnableWindow(native_wd, true);
|
||||
::SetActiveWindow(native_wd);
|
||||
::SetForegroundWindow(native_wd);
|
||||
}
|
||||
else
|
||||
::PostMessage(native_wd, nana::detail::messages::async_activate, 0, 0);
|
||||
@@ -580,27 +581,30 @@ namespace nana{
|
||||
//event, when the client receives the event, the specified window has been already
|
||||
//destroyed. This is a feature which is different from Windows. So the following
|
||||
//works should be handled before calling XDestroyWindow.
|
||||
auto & bedrock = bedrock::instance();
|
||||
if(wd == bedrock.get_menu())
|
||||
bedrock.empty_menu();
|
||||
auto & brock = bedrock::instance();
|
||||
if(wd == brock.get_menu())
|
||||
{
|
||||
brock.erase_menu(false);
|
||||
brock.delay_restore(3); //Restores if delay_restore is not decleard
|
||||
}
|
||||
|
||||
Display* disp = restrict::spec.open_display();
|
||||
restrict::spec.remove(wd);
|
||||
auto iwd = bedrock.wd_manager.root(wd);
|
||||
auto iwd = brock.wd_manager.root(wd);
|
||||
if(iwd)
|
||||
{
|
||||
{
|
||||
//Before calling window_manager::destroy, make sure the window is invisible.
|
||||
//It is a behavior like Windows.
|
||||
nana::detail::platform_scope_guard psg;
|
||||
nana::detail::platform_scope_guard lock;
|
||||
restrict::spec.set_error_handler();
|
||||
::XUnmapWindow(disp, reinterpret_cast<Window>(wd));
|
||||
::XFlush(disp);
|
||||
restrict::spec.rev_error_handler();
|
||||
}
|
||||
bedrock.wd_manager.destroy(iwd);
|
||||
bedrock.rt_manager.remove_if_exists(iwd);
|
||||
bedrock.wd_manager.destroy_handle(iwd);
|
||||
brock.wd_manager.destroy(iwd);
|
||||
brock.rt_manager.remove_if_exists(iwd);
|
||||
brock.wd_manager.destroy_handle(iwd);
|
||||
}
|
||||
|
||||
nana::detail::platform_scope_guard psg;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/detail/win32/bedrock.cpp
|
||||
* @contributors: Ariel Vina-Rodriguez
|
||||
*/
|
||||
|
||||
#include <nana/config.hpp>
|
||||
@@ -184,17 +185,18 @@ namespace detail
|
||||
{
|
||||
struct thread_context_cache
|
||||
{
|
||||
unsigned tid = 0;
|
||||
thread_context *object = nullptr;
|
||||
unsigned tid{ 0 };
|
||||
thread_context *object{ nullptr };
|
||||
}tcontext;
|
||||
}cache;
|
||||
|
||||
struct menu_tag
|
||||
{
|
||||
core_window_t* taken_window = nullptr;
|
||||
native_window_type window = nullptr;
|
||||
native_window_type owner = nullptr;
|
||||
bool has_keyboard = false;
|
||||
core_window_t* taken_window{ nullptr };
|
||||
bool delay_restore{ false };
|
||||
native_window_type window{ nullptr };
|
||||
native_window_type owner{ nullptr };
|
||||
bool has_keyboard{false};
|
||||
}menu;
|
||||
|
||||
struct keyboard_tracking_state_tag
|
||||
@@ -266,12 +268,6 @@ namespace detail
|
||||
::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK);
|
||||
}
|
||||
|
||||
if(evt_operation.size())
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss<<"Nana.GUI detects a memory leaks in events operation, "<<static_cast<unsigned>(evt_operation.size())<<" event(s) are not uninstalled.";
|
||||
::MessageBoxA(0, ss.str().c_str(), ("Nana C++ Library"), MB_OK);
|
||||
}
|
||||
delete impl_;
|
||||
delete pi_data_;
|
||||
}
|
||||
@@ -855,7 +851,7 @@ namespace detail
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
if ((reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_SHOWWINDOW) && (!msgwnd->visible))
|
||||
brock.event_expose(msgwnd, true);
|
||||
else if((reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_HIDEWINDOW) && msgwnd->visible)
|
||||
else if ((reinterpret_cast<WINDOWPOS*>(lParam)->flags & SWP_HIDEWINDOW) && msgwnd->visible)
|
||||
brock.event_expose(msgwnd, false);
|
||||
|
||||
def_window_proc = true;
|
||||
@@ -875,6 +871,7 @@ namespace detail
|
||||
if (!brock.emit(event_code::focus, focus, arg, true, &context))
|
||||
brock.wd_manager.set_focus(msgwnd, true);
|
||||
}
|
||||
def_window_proc = true;
|
||||
break;
|
||||
case WM_KILLFOCUS:
|
||||
if(msgwnd->other.attribute.root->focus)
|
||||
@@ -895,10 +892,14 @@ namespace detail
|
||||
//focus_changed means that during an event procedure if the focus is changed
|
||||
if(brock.wd_manager.available(msgwnd))
|
||||
msgwnd->root_widget->other.attribute.root->context.focus_changed = true;
|
||||
|
||||
def_window_proc = true;
|
||||
break;
|
||||
case WM_MOUSEACTIVATE:
|
||||
if(msgwnd->flags.take_active == false)
|
||||
return MA_NOACTIVATE;
|
||||
|
||||
def_window_proc = true;
|
||||
break;
|
||||
case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
|
||||
pressed_wd = nullptr;
|
||||
@@ -926,8 +927,8 @@ namespace detail
|
||||
if(nullptr == msgwnd) break;
|
||||
|
||||
//if event on the menubar, just remove the menu if it is not associating with the menubar
|
||||
if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
|
||||
brock.remove_menu();
|
||||
if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
|
||||
brock.erase_menu(true);
|
||||
else
|
||||
brock.close_menu_if_focus_other_window(msgwnd->root);
|
||||
|
||||
@@ -948,6 +949,8 @@ namespace detail
|
||||
arg_mouse arg;
|
||||
assign_arg(arg, msgwnd, message, pmdec);
|
||||
msgwnd->flags.action = mouse_action::pressed;
|
||||
|
||||
auto retain = msgwnd->together.events_ptr;
|
||||
if (brock.emit(event_code::mouse_down, msgwnd, arg, true, &context))
|
||||
{
|
||||
//If a root_window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event.
|
||||
@@ -982,6 +985,8 @@ namespace detail
|
||||
msgwnd->flags.action = mouse_action::normal;
|
||||
if(msgwnd->flags.enabled)
|
||||
{
|
||||
auto retain = msgwnd->together.events_ptr;
|
||||
|
||||
nana::arg_mouse arg;
|
||||
assign_arg(arg, msgwnd, message, pmdec);
|
||||
|
||||
@@ -1011,19 +1016,19 @@ namespace detail
|
||||
if (fire_click)
|
||||
{
|
||||
arg.evt_code = event_code::click;
|
||||
msgwnd->together.attached_events->click.emit(arg);
|
||||
retain->click.emit(arg);
|
||||
}
|
||||
|
||||
if (brock.wd_manager.available(msgwnd))
|
||||
{
|
||||
arg.evt_code = event_code::mouse_up;
|
||||
msgwnd->together.attached_events->mouse_up.emit(arg);
|
||||
retain->mouse_up.emit(arg);
|
||||
}
|
||||
}
|
||||
else if (fire_click)
|
||||
{
|
||||
arg.evt_code = event_code::click;
|
||||
msgwnd->together.attached_events->click.emit(arg);
|
||||
retain->click.emit(arg);
|
||||
}
|
||||
brock.wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
}
|
||||
@@ -1103,7 +1108,7 @@ namespace detail
|
||||
case WM_MOUSEHWHEEL:
|
||||
{
|
||||
//The focus window receives the message in Windows system, it should be redirected to the hovered window
|
||||
::POINT scr_pos{ int(LOWORD(lParam)), int(HIWORD(lParam)) }; //Screen position
|
||||
::POINT scr_pos{ pmdec.mouse.x, pmdec.mouse.y}; //Screen position
|
||||
auto pointer_wd = ::WindowFromPoint(scr_pos);
|
||||
if (pointer_wd == root_window)
|
||||
{
|
||||
@@ -1114,7 +1119,7 @@ namespace detail
|
||||
auto evt_wd = scrolled_wd;
|
||||
while (evt_wd)
|
||||
{
|
||||
if (evt_wd->together.attached_events->mouse_wheel.length() != 0)
|
||||
if (evt_wd->together.events_ptr->mouse_wheel.length() != 0)
|
||||
{
|
||||
def_window_proc = false;
|
||||
nana::point mspos{ scr_pos.x, scr_pos.y };
|
||||
@@ -1189,7 +1194,7 @@ namespace detail
|
||||
brock.wd_manager.calc_window_point(msgwnd, dropfiles.pos);
|
||||
dropfiles.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
|
||||
msgwnd->together.attached_events->mouse_dropfiles.emit(dropfiles);
|
||||
msgwnd->together.events_ptr->mouse_dropfiles.emit(dropfiles);
|
||||
brock.wd_manager.do_lazy_refresh(msgwnd, false);
|
||||
}
|
||||
}
|
||||
@@ -1308,6 +1313,7 @@ namespace detail
|
||||
}
|
||||
break;
|
||||
case WM_SYSCHAR:
|
||||
def_window_proc = true;
|
||||
brock.set_keyboard_shortkey(true);
|
||||
msgwnd = brock.wd_manager.find_shortkey(native_window, static_cast<unsigned long>(wParam));
|
||||
if(msgwnd)
|
||||
@@ -1319,17 +1325,17 @@ namespace detail
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
arg.ignore = false;
|
||||
brock.emit(event_code::shortkey, msgwnd, arg, true, &context);
|
||||
def_window_proc = false;
|
||||
}
|
||||
def_window_proc = true;
|
||||
break;
|
||||
case WM_SYSKEYDOWN:
|
||||
if(brock.whether_keyboard_shortkey() == false)
|
||||
def_window_proc = true;
|
||||
if (brock.whether_keyboard_shortkey() == false)
|
||||
{
|
||||
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
|
||||
if(msgwnd)
|
||||
if (msgwnd)
|
||||
{
|
||||
brock.wd_manager.set_focus(msgwnd, false);
|
||||
|
||||
bool focused = (brock.focus() == msgwnd);
|
||||
arg_keyboard arg;
|
||||
arg.evt_code = event_code::key_press;
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
@@ -1337,18 +1343,26 @@ namespace detail
|
||||
arg.key = static_cast<nana::char_t>(wParam);
|
||||
brock.get_key_state(arg);
|
||||
brock.emit(event_code::key_press, msgwnd, arg, true, &context);
|
||||
|
||||
msgwnd->root_widget->flags.ignore_menubar_focus = (focused && (brock.focus() != msgwnd));
|
||||
}
|
||||
else if(brock.get_menu())
|
||||
brock.remove_menu();
|
||||
else
|
||||
brock.erase_menu(true);
|
||||
}
|
||||
def_window_proc = true;
|
||||
break;
|
||||
case WM_SYSKEYUP:
|
||||
def_window_proc = true;
|
||||
if(brock.set_keyboard_shortkey(false) == false)
|
||||
{
|
||||
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
|
||||
if(msgwnd)
|
||||
{
|
||||
//Don't call default window proc to avoid popuping system menu.
|
||||
def_window_proc = false;
|
||||
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
|
||||
if (set_focus)
|
||||
brock.wd_manager.set_focus(msgwnd, false);
|
||||
|
||||
arg_keyboard arg;
|
||||
arg.evt_code = event_code::key_release;
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
@@ -1356,21 +1370,30 @@ namespace detail
|
||||
arg.key = static_cast<nana::char_t>(wParam);
|
||||
brock.get_key_state(arg);
|
||||
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
|
||||
|
||||
if (!set_focus)
|
||||
{
|
||||
brock.set_menubar_taken(nullptr);
|
||||
msgwnd->root_widget->flags.ignore_menubar_focus = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
def_window_proc = true;
|
||||
break;
|
||||
case WM_KEYDOWN:
|
||||
if(msgwnd->flags.enabled)
|
||||
{
|
||||
if(msgwnd->root != brock.get_menu())
|
||||
auto menu_wd = brock.get_menu();
|
||||
if (menu_wd)
|
||||
brock.delay_restore(0); //Enable delay restore
|
||||
|
||||
if (msgwnd->root != menu_wd)
|
||||
msgwnd = brock.focus();
|
||||
|
||||
if(msgwnd)
|
||||
{
|
||||
if((wParam == 9) && (false == (msgwnd->flags.tab & tab_type::eating))) //Tab
|
||||
{
|
||||
auto the_next = brock.wd_manager.tabstop(msgwnd, true);
|
||||
auto the_next = brock.wd_manager.tabstop(msgwnd, (::GetKeyState(VK_SHIFT) >= 0));
|
||||
if(the_next)
|
||||
{
|
||||
brock.wd_manager.set_focus(the_next, false);
|
||||
@@ -1388,6 +1411,17 @@ namespace detail
|
||||
arg.key = static_cast<nana::char_t>(wParam);
|
||||
brock.get_key_state(arg);
|
||||
brock.emit(event_code::key_press, msgwnd, arg, true, &context);
|
||||
|
||||
if (msgwnd->root_widget->other.attribute.root->menubar == msgwnd)
|
||||
{
|
||||
//In order to keep the focus on the menubar, cancel the delay_restore
|
||||
//when pressing ESC to close the menu which is popuped by the menubar.
|
||||
//If no menu popuped by the menubar, it should enable delay restore to
|
||||
//restore the focus for taken window.
|
||||
|
||||
int cmd = (menu_wd && (keyboard::escape == static_cast<nana::char_t>(wParam)) ? 1 : 0);
|
||||
brock.delay_restore(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1405,7 +1439,7 @@ namespace detail
|
||||
brock.get_key_state(arg);
|
||||
arg.ignore = false;
|
||||
|
||||
msgwnd->together.attached_events->key_char.emit(arg);
|
||||
msgwnd->together.events_ptr->key_char.emit(arg);
|
||||
if ((false == arg.ignore) && brock.wd_manager.available(msgwnd))
|
||||
brock.emit_drawer(event_code::key_char, msgwnd, arg, &context);
|
||||
|
||||
@@ -1432,6 +1466,8 @@ namespace detail
|
||||
}
|
||||
else
|
||||
brock.set_keyboard_shortkey(false);
|
||||
|
||||
brock.delay_restore(2); //Restores while key release
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
{
|
||||
@@ -1449,8 +1485,12 @@ namespace detail
|
||||
break;
|
||||
}
|
||||
case WM_DESTROY:
|
||||
if(msgwnd->root == brock.get_menu())
|
||||
brock.empty_menu();
|
||||
if (msgwnd->root == brock.get_menu())
|
||||
{
|
||||
brock.erase_menu(false);
|
||||
brock.delay_restore(3); //Restores if delay_restore not decleared
|
||||
}
|
||||
|
||||
brock.wd_manager.destroy(msgwnd);
|
||||
|
||||
nana::detail::platform_spec::instance().release_window_icon(msgwnd->root);
|
||||
@@ -1513,14 +1553,40 @@ namespace detail
|
||||
|
||||
void bedrock::set_menubar_taken(core_window_t* wd)
|
||||
{
|
||||
auto pre = impl_->menu.taken_window;
|
||||
impl_->menu.taken_window = wd;
|
||||
|
||||
//assigning of a nullptr taken window is to restore the focus of pre taken
|
||||
//don't restore the focus if pre is a menu.
|
||||
if ((!wd) && pre && (pre->root != get_menu()))
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
wd_manager.set_focus(pre, false);
|
||||
wd_manager.update(pre, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
bedrock::core_window_t* bedrock::get_menubar_taken()
|
||||
//0:Enable delay, 1:Cancel, 2:Restores, 3: Restores when menu is destroying
|
||||
void bedrock::delay_restore(int state)
|
||||
{
|
||||
core_window_t* wd = impl_->menu.taken_window;
|
||||
impl_->menu.taken_window = nullptr;
|
||||
return wd;
|
||||
switch (state)
|
||||
{
|
||||
case 0: //Enable
|
||||
break;
|
||||
case 1: //Cancel
|
||||
break;
|
||||
case 2: //Restore if key released
|
||||
//restores the focus when menu is closed by pressing keyboard
|
||||
if ((!impl_->menu.window) && impl_->menu.delay_restore)
|
||||
set_menubar_taken(nullptr);
|
||||
break;
|
||||
case 3: //Restores if destroying
|
||||
//when the menu is destroying, restores the focus if delay restore is not declared
|
||||
if (!impl_->menu.delay_restore)
|
||||
set_menubar_taken(nullptr);
|
||||
}
|
||||
|
||||
impl_->menu.delay_restore = (0 == state);
|
||||
}
|
||||
|
||||
bool bedrock::close_menu_if_focus_other_window(native_window_type wd)
|
||||
@@ -1535,7 +1601,7 @@ namespace detail
|
||||
else
|
||||
return false;
|
||||
}
|
||||
remove_menu();
|
||||
erase_menu(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1545,7 +1611,7 @@ namespace detail
|
||||
{
|
||||
if(menu_wd && impl_->menu.window != menu_wd)
|
||||
{
|
||||
remove_menu();
|
||||
erase_menu(true);
|
||||
|
||||
impl_->menu.window = menu_wd;
|
||||
impl_->menu.owner = native_interface::get_owner_window(menu_wd);
|
||||
@@ -1569,21 +1635,13 @@ namespace detail
|
||||
return impl_->menu.window;
|
||||
}
|
||||
|
||||
void bedrock::remove_menu()
|
||||
void bedrock::erase_menu(bool try_destroy)
|
||||
{
|
||||
if(impl_->menu.window)
|
||||
{
|
||||
auto delwin = impl_->menu.window;
|
||||
impl_->menu.window = impl_->menu.owner = nullptr;
|
||||
impl_->menu.has_keyboard = false;
|
||||
native_interface::close_window(delwin);
|
||||
}
|
||||
}
|
||||
|
||||
void bedrock::empty_menu()
|
||||
{
|
||||
if(impl_->menu.window)
|
||||
if (impl_->menu.window)
|
||||
{
|
||||
if (try_destroy)
|
||||
native_interface::close_window(impl_->menu.window);
|
||||
|
||||
impl_->menu.window = impl_->menu.owner = nullptr;
|
||||
impl_->menu.has_keyboard = false;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/detail/window_manager.cpp
|
||||
*
|
||||
* @author: Jinhao
|
||||
* @contributors: Katsuhisa Yuasa
|
||||
*/
|
||||
|
||||
#include <nana/config.hpp>
|
||||
@@ -20,7 +21,6 @@
|
||||
#include <nana/gui/layout_utility.hpp>
|
||||
#include <nana/gui/detail/effects_renderer.hpp>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
@@ -191,7 +191,7 @@ namespace detail
|
||||
switch(evtid)
|
||||
{
|
||||
case event_code::mouse_drop:
|
||||
wd->flags.dropable = (is_make || (0 != wd->together.attached_events->mouse_dropfiles.length()));
|
||||
wd->flags.dropable = (is_make || (0 != wd->together.events_ptr->mouse_dropfiles.length()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -875,7 +875,16 @@ namespace detail
|
||||
if (!root_has_been_focused)
|
||||
native_interface::set_focus(root_wd->root);
|
||||
|
||||
brock.set_menubar_taken(wd);
|
||||
//A fix by Katsuhisa Yuasa
|
||||
//The menubar token window will be redirected to the prev focus window when the new
|
||||
//focus window is a menubar.
|
||||
//The focus window will be restore to the prev focus which losts the focus becuase of
|
||||
//memberbar.
|
||||
if (wd == wd->root_widget->other.attribute.root->menubar)
|
||||
wd = prev_focus;
|
||||
|
||||
if (wd != wd->root_widget->other.attribute.root->menubar)
|
||||
brock.set_menubar_taken(wd);
|
||||
}
|
||||
return prev_focus;
|
||||
}
|
||||
@@ -975,11 +984,15 @@ namespace detail
|
||||
}
|
||||
else
|
||||
{
|
||||
auto i = std::find_if(attr_cap.begin(), attr_cap.end(),
|
||||
[wd](const std::pair<core_window_t*, bool> & x){ return (x.first == wd);});
|
||||
for (auto i = attr_cap.begin(), end = attr_cap.end(); i != end; ++i)
|
||||
{
|
||||
if (i->first == wd)
|
||||
{
|
||||
attr_cap.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(i != attr_cap.end())
|
||||
attr_cap.erase(i);
|
||||
return attr_.capture.window;
|
||||
}
|
||||
return wd;
|
||||
|
||||
@@ -973,6 +973,7 @@ namespace nana
|
||||
|
||||
const nana::char_t * filter;
|
||||
nana::string filter_holder;
|
||||
nana::string default_extension;
|
||||
if(impl_->filters.size())
|
||||
{
|
||||
for(auto & f : impl_->filters)
|
||||
@@ -990,6 +991,21 @@ namespace nana
|
||||
}
|
||||
filter_holder += fs;
|
||||
filter_holder += static_cast<nana::string::value_type>('\0');
|
||||
|
||||
//Get the default file extentsion
|
||||
if (default_extension.empty())
|
||||
{
|
||||
pos = fs.find_last_of('.');
|
||||
if (pos != fs.npos)
|
||||
{
|
||||
fs = fs.substr(pos + 1);
|
||||
if (fs != L"*")
|
||||
{
|
||||
default_extension = fs;
|
||||
ofn.lpstrDefExt = default_extension.data();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
filter = filter_holder.data();
|
||||
}
|
||||
@@ -1002,6 +1018,10 @@ namespace nana
|
||||
ofn.lpstrFileTitle = nullptr;
|
||||
ofn.nMaxFileTitle = 0;
|
||||
ofn.lpstrInitialDir = (impl_->path.size() ? impl_->path.c_str() : nullptr);
|
||||
|
||||
if (!impl_->open_or_save)
|
||||
ofn.Flags = OFN_OVERWRITEPROMPT; //Overwrite prompt if it is save mode
|
||||
|
||||
if(FALSE == (impl_->open_or_save ? ::GetOpenFileName(&ofn) : ::GetSaveFileName(&ofn)))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/layout_utility.hpp
|
||||
*
|
||||
* @contributors: Ryan Gonzalez
|
||||
*
|
||||
*/
|
||||
#include <nana/gui/layout_utility.hpp>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/*
|
||||
* Implementation of Notifier
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/notifier.cpp
|
||||
*/
|
||||
* Implementation of Notifier
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/notifier.cpp
|
||||
* @contributors: Jan
|
||||
*/
|
||||
#include <nana/deploy.hpp>
|
||||
#include <nana/gui/programming_interface.hpp>
|
||||
#include <nana/gui/notifier.hpp>
|
||||
@@ -16,7 +17,12 @@
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#if defined(NANA_MINGW) && defined(STD_THREAD_NOT_SUPPORTED)
|
||||
#include <nana/std_mutex.hpp>
|
||||
#else
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#if defined(NANA_WINDOWS)
|
||||
#include <nana/detail/win32/platform_spec.hpp>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
/**
|
||||
* An Implementation of Place for Layout
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
@@ -558,18 +559,22 @@ namespace nana
|
||||
return token::identifier;
|
||||
}
|
||||
|
||||
std::string err = "an invalid character '";
|
||||
err += *sp_;
|
||||
err += "'";
|
||||
|
||||
_m_throw_error(err);
|
||||
_m_throw_error(*sp_);
|
||||
return token::error; //Useless, just for syntax correction.
|
||||
}
|
||||
private:
|
||||
void _m_throw_error(char err_char)
|
||||
{
|
||||
std::string str = "place: invalid character '";
|
||||
str += err_char;
|
||||
str += '\'';
|
||||
_m_throw_error(str);
|
||||
}
|
||||
|
||||
void _m_throw_error(const std::string& err)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "place: invalid character '" << err_char << "' at " << static_cast<unsigned>(sp_ - divstr_);
|
||||
ss << "place: " << err << " at " << static_cast<unsigned>(sp_ - divstr_);
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
|
||||
@@ -578,8 +583,7 @@ namespace nana
|
||||
if (token::equal != read())
|
||||
_m_throw_error("an equal sign is required after '" + idstr_ + "'");
|
||||
|
||||
const char* p = sp_;
|
||||
for (; *p == ' '; ++p);
|
||||
const char* p = _m_eat_whitespace(sp_);
|
||||
|
||||
auto neg_ptr = p;
|
||||
if ('-' == *p)
|
||||
@@ -598,8 +602,7 @@ namespace nana
|
||||
if (token::equal != read())
|
||||
_m_throw_error("an equal sign is required after '" + idstr + "'");
|
||||
|
||||
const char* p = sp_;
|
||||
for (; *p == ' ' || *p == '\t'; ++p);
|
||||
const char* p = _m_eat_whitespace(sp_);
|
||||
|
||||
reparray_.reset();
|
||||
auto tk = read();
|
||||
@@ -619,14 +622,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
void _m_throw_error(const std::string& err)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "place: " << err << " at " << static_cast<unsigned>(sp_ - divstr_);
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
|
||||
const char* _m_eat_whitespace(const char* sp)
|
||||
static const char* _m_eat_whitespace(const char* sp)
|
||||
{
|
||||
while (*sp && !isgraph(*sp))
|
||||
++sp;
|
||||
@@ -677,7 +673,7 @@ namespace nana
|
||||
|
||||
if (gotcha)
|
||||
{
|
||||
for (; *sp == ' ' || *sp == '\t'; ++sp);
|
||||
sp = _m_eat_whitespace(sp);
|
||||
if ('%' == *sp)
|
||||
{
|
||||
if (number_t::kind::integer == number_.kind_of())
|
||||
@@ -757,6 +753,20 @@ namespace nana
|
||||
for (auto & e : fastened)
|
||||
API::show_window(e.handle, vsb);
|
||||
}
|
||||
|
||||
static event_handle erase_element(std::vector<element_t>& elements, window handle)
|
||||
{
|
||||
for (auto i = elements.begin(), end = elements.end(); i != end; ++i)
|
||||
{
|
||||
if (i->handle == handle)
|
||||
{
|
||||
auto evt_destroy = i->evt_destroy;
|
||||
elements.erase(i);
|
||||
return evt_destroy;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
private:
|
||||
//The defintion is moved after the definition of class division
|
||||
template<typename Function>
|
||||
@@ -768,15 +778,8 @@ namespace nana
|
||||
{
|
||||
return API::events(wd).destroy.connect([this](const arg_destroy& arg)
|
||||
{
|
||||
for (auto i = elements.begin(), end = elements.end(); i != end; ++i)
|
||||
{
|
||||
if (arg.window_handle == i->handle)
|
||||
{
|
||||
elements.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
place_ptr_->collocate();
|
||||
if (erase_element(elements, arg.window_handle))
|
||||
place_ptr_->collocate();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -815,13 +818,7 @@ namespace nana
|
||||
//does not change the layout.
|
||||
auto evt = API::events(wd).destroy([this](const arg_destroy& arg)
|
||||
{
|
||||
auto destroyed_wd = arg.window_handle;
|
||||
auto i = std::find_if(fastened.begin(), fastened.end(), [destroyed_wd](element_t& e){
|
||||
return (e.handle == destroyed_wd);
|
||||
});
|
||||
|
||||
if (i != fastened.end())
|
||||
fastened.erase(i);
|
||||
erase_element(fastened, arg.window_handle);
|
||||
});
|
||||
|
||||
fastened.emplace_back(wd, evt);
|
||||
@@ -929,16 +926,9 @@ namespace nana
|
||||
{
|
||||
for (auto & child : div->children)
|
||||
{
|
||||
if (child->field)
|
||||
{
|
||||
if (vsb)
|
||||
{
|
||||
if (child->visible)
|
||||
child->field->visible(true);
|
||||
}
|
||||
else
|
||||
child->field->visible(false);
|
||||
}
|
||||
if (child->field && (!vsb || child->visible))
|
||||
child->field->visible(vsb);
|
||||
|
||||
_m_visible_for_child(child.get(), vsb);
|
||||
}
|
||||
}
|
||||
@@ -985,7 +975,7 @@ namespace nana
|
||||
const bool vert = (kind::arrange != kind_of_division);
|
||||
|
||||
auto area_margined = margin_area();
|
||||
area_rotator area(vert, area_margined);
|
||||
rectangle_rotator area(vert, area_margined);
|
||||
auto area_px = area.w();
|
||||
|
||||
auto fa = _m_fixed_and_adjustable(kind_of_division, area_px);
|
||||
@@ -1001,7 +991,7 @@ namespace nana
|
||||
if(!child->display) //Ignore the division if the corresponding field is not displayed.
|
||||
continue;
|
||||
|
||||
area_rotator child_area(vert, child->field_area);
|
||||
rectangle_rotator child_area(vert, child->field_area);
|
||||
child_area.x_ref() = static_cast<int>(position);
|
||||
child_area.y_ref() = area.y();
|
||||
child_area.h_ref() = area.h();
|
||||
@@ -1510,17 +1500,6 @@ namespace nana
|
||||
class place::implement::div_splitter
|
||||
: public division
|
||||
{
|
||||
struct div_block
|
||||
{
|
||||
division * div;
|
||||
int pixels;
|
||||
double scale;
|
||||
|
||||
div_block(division* d, int px)
|
||||
: div(d), pixels(px)
|
||||
{}
|
||||
};
|
||||
|
||||
enum{splitter_px = 4};
|
||||
public:
|
||||
div_splitter(place_parts::number_t init_weight)
|
||||
@@ -1533,14 +1512,9 @@ namespace nana
|
||||
this->weight.assign(splitter_px);
|
||||
}
|
||||
|
||||
void leaf_left(division * d)
|
||||
void set_leaf(bool is_left, division * d)
|
||||
{
|
||||
leaf_left_ = d;
|
||||
}
|
||||
|
||||
void leaf_right(division * d)
|
||||
{
|
||||
leaf_right_ = d;
|
||||
(is_left ? leaf_left_ : leaf_right_) = d;
|
||||
}
|
||||
|
||||
void direction(bool horizontal)
|
||||
@@ -1565,8 +1539,9 @@ namespace nana
|
||||
|
||||
auto px_ptr = &nana::rectangle::width;
|
||||
|
||||
auto area_left = leaf_left_->margin_area();
|
||||
auto area_right = leaf_right_->margin_area();
|
||||
//Use field_area of leaf, not margin_area. Otherwise splitter would be at wrong position
|
||||
auto area_left = leaf_left_->field_area;
|
||||
auto area_right = leaf_right_->field_area;
|
||||
|
||||
if (nana::cursor::size_we != splitter_cursor_)
|
||||
{
|
||||
@@ -1590,7 +1565,7 @@ namespace nana
|
||||
return;
|
||||
|
||||
const bool vert = (::nana::cursor::size_we != splitter_cursor_);
|
||||
auto area_px = area_rotator(vert, div_owner->margin_area()).w();
|
||||
auto area_px = rectangle_rotator(vert, div_owner->margin_area()).w();
|
||||
int delta = (vert ? splitter_.pos().y - begin_point_.y : splitter_.pos().x - begin_point_.x);
|
||||
|
||||
int total_pixels = static_cast<int>(left_pixels_ + right_pixels_);
|
||||
@@ -1631,8 +1606,8 @@ namespace nana
|
||||
{
|
||||
const bool vert = (::nana::cursor::size_we != splitter_cursor_);
|
||||
|
||||
area_rotator left(vert, leaf_left_->field_area);
|
||||
area_rotator right(vert, leaf_right_->field_area);
|
||||
rectangle_rotator left(vert, leaf_left_->field_area);
|
||||
rectangle_rotator right(vert, leaf_right_->field_area);
|
||||
auto area_px = right.right() - left.x();
|
||||
auto right_px = static_cast<int>(limit_px(leaf_right_, init_weight_.get_value(area_px), static_cast<unsigned>(area_px)));
|
||||
|
||||
@@ -1642,7 +1617,7 @@ namespace nana
|
||||
else if (pos > limited_range.right())
|
||||
pos = limited_range.right();
|
||||
|
||||
area_rotator sp_r(vert, field_area);
|
||||
nana::rectangle_rotator sp_r(vert, field_area);
|
||||
sp_r.x_ref() = pos;
|
||||
|
||||
left.w_ref() = static_cast<unsigned>(pos - left.x());
|
||||
@@ -1658,7 +1633,7 @@ namespace nana
|
||||
leaf_right_->collocate(wd);
|
||||
|
||||
//Set the leafs' weight
|
||||
area_rotator area(vert, div_owner->field_area);
|
||||
rectangle_rotator area(vert, div_owner->field_area);
|
||||
|
||||
double imd_rate = 100.0 / static_cast<int>(area.w());
|
||||
leaf_left_->weight.assign_percent(imd_rate * static_cast<int>(left.w()));
|
||||
@@ -1673,14 +1648,14 @@ namespace nana
|
||||
splitter_.move(this->field_area);
|
||||
}
|
||||
private:
|
||||
area_rotator _m_update_splitter_range()
|
||||
rectangle_rotator _m_update_splitter_range()
|
||||
{
|
||||
const bool vert = (cursor::size_ns == splitter_cursor_);
|
||||
|
||||
area_rotator area(vert, div_owner->margin_area());
|
||||
rectangle_rotator area(vert, div_owner->margin_area());
|
||||
|
||||
area_rotator left(vert, leaf_left_->field_area);
|
||||
area_rotator right(vert, leaf_right_->field_area);
|
||||
rectangle_rotator left(vert, leaf_left_->field_area);
|
||||
rectangle_rotator right(vert, leaf_right_->field_area);
|
||||
|
||||
const int left_base = left.x(), right_base = right.right();
|
||||
int pos = left_base;
|
||||
@@ -1785,7 +1760,7 @@ namespace nana
|
||||
if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division))
|
||||
{
|
||||
auto splitter = new div_splitter(tknizer.number());
|
||||
splitter->leaf_left(children.back().get());
|
||||
splitter->set_leaf(true, children.back().get());
|
||||
children.back()->div_next = splitter;
|
||||
children.emplace_back(splitter);
|
||||
}
|
||||
@@ -1797,7 +1772,7 @@ namespace nana
|
||||
{
|
||||
children.back()->div_next = div.get();
|
||||
if (division::kind::splitter == children.back()->kind_of_division)
|
||||
dynamic_cast<div_splitter&>(*children.back()).leaf_right(div.get());
|
||||
dynamic_cast<div_splitter&>(*children.back()).set_leaf(false, div.get());
|
||||
}
|
||||
children.emplace_back(div.release());
|
||||
}
|
||||
@@ -2182,29 +2157,14 @@ namespace nana
|
||||
bool recollocate = false;
|
||||
for (auto & fld : impl_->fields)
|
||||
{
|
||||
auto & elements = fld.second->elements;
|
||||
for (auto i = elements.begin(); i != elements.end();)
|
||||
auto evt = fld.second->erase_element(fld.second->elements, handle);
|
||||
if (evt)
|
||||
{
|
||||
if (i->handle == handle)
|
||||
{
|
||||
API::umake_event(i->evt_destroy);
|
||||
i = elements.erase(i);
|
||||
recollocate |= (nullptr != fld.second->attached);
|
||||
}
|
||||
else
|
||||
++i;
|
||||
API::umake_event(evt);
|
||||
recollocate |= (nullptr != fld.second->attached);
|
||||
}
|
||||
|
||||
auto i = std::find_if(fld.second->fastened.begin(), fld.second->fastened.end(), [handle](implement::field_impl::element_t& e)
|
||||
{
|
||||
return (e.handle == handle);
|
||||
});
|
||||
|
||||
if (i != fld.second->fastened.end())
|
||||
{
|
||||
API::umake_event(i->evt_destroy);
|
||||
fld.second->fastened.erase(i);
|
||||
}
|
||||
API::umake_event( fld.second->erase_element(fld.second->fastened, handle));
|
||||
}
|
||||
|
||||
if (recollocate)
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/*
|
||||
* Nana GUI Programming Interface Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/programming_interface.cpp
|
||||
* @author: Jinhao
|
||||
*/
|
||||
|
||||
#include <nana/gui/programming_interface.hpp>
|
||||
@@ -15,7 +16,6 @@
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <nana/gui/detail/native_window_interface.hpp>
|
||||
#include <nana/gui/widgets/widget.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
@@ -53,7 +53,7 @@ namespace API
|
||||
if (!restrict::window_manager.available(reinterpret_cast<restrict::core_window_t*>(wd)))
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<restrict::core_window_t*>(wd)->together.attached_events;
|
||||
return reinterpret_cast<restrict::core_window_t*>(wd)->together.events_ptr.get();
|
||||
}
|
||||
}//end namespace detail
|
||||
|
||||
@@ -239,6 +239,11 @@ namespace API
|
||||
return &reinterpret_cast<restrict::core_window_t*>(wd)->drawer.graphics;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void delay_restore(bool enable)
|
||||
{
|
||||
restrict::bedrock.delay_restore(enable ? 0 : 1);
|
||||
}
|
||||
}//end namespace dev
|
||||
|
||||
//exit
|
||||
@@ -259,8 +264,20 @@ namespace API
|
||||
if((wd->thread_id == tid) && (wd->root != root))
|
||||
{
|
||||
root = wd->root;
|
||||
if(roots.cend() == std::find(roots.cbegin(), roots.cend(), root))
|
||||
for (auto i = roots.cbegin(); i != roots.cend(); ++i)
|
||||
{
|
||||
if (*i == root)
|
||||
{
|
||||
root = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!root)
|
||||
{
|
||||
root = wd->root;
|
||||
roots.push_back(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +615,7 @@ namespace API
|
||||
nana::size window_size(window wd)
|
||||
{
|
||||
nana::rectangle r;
|
||||
API::window_rectangle(wd, r);
|
||||
API::get_window_rectangle(wd, r);
|
||||
return{ r.width, r.height };
|
||||
}
|
||||
|
||||
@@ -618,7 +635,46 @@ namespace API
|
||||
}
|
||||
}
|
||||
|
||||
bool window_rectangle(window wd, rectangle& r)
|
||||
::nana::size window_outline_size(window wd)
|
||||
{
|
||||
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
|
||||
internal_scope_guard lock;
|
||||
if (!restrict::window_manager.available(iwd))
|
||||
return{};
|
||||
|
||||
auto sz = window_size(wd);
|
||||
sz.width += iwd->extra_width;
|
||||
sz.height += iwd->extra_height;
|
||||
return sz;
|
||||
}
|
||||
|
||||
void window_outline_size(window wd, const size& sz)
|
||||
{
|
||||
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
|
||||
internal_scope_guard lock;
|
||||
if (restrict::window_manager.available(iwd))
|
||||
{
|
||||
if (category::flags::root == iwd->other.category)
|
||||
{
|
||||
size inner_size = sz;
|
||||
if (inner_size.width < iwd->extra_width)
|
||||
inner_size.width = 0;
|
||||
else
|
||||
inner_size.width -= iwd->extra_width;
|
||||
|
||||
if (inner_size.height < iwd->extra_height)
|
||||
inner_size.height = 0;
|
||||
else
|
||||
inner_size.height -= iwd->extra_height;
|
||||
|
||||
window_size(wd, inner_size);
|
||||
}
|
||||
else
|
||||
window_size(wd, sz);
|
||||
}
|
||||
}
|
||||
|
||||
bool get_window_rectangle(window wd, rectangle& r)
|
||||
{
|
||||
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
|
||||
internal_scope_guard lock;
|
||||
@@ -751,7 +807,7 @@ namespace API
|
||||
return cursor::arrow;
|
||||
}
|
||||
|
||||
bool is_focus_window(window wd)
|
||||
bool is_focus_ready(window wd)
|
||||
{
|
||||
auto iwd = reinterpret_cast<restrict::core_window_t*>(wd);
|
||||
internal_scope_guard lock;
|
||||
@@ -1163,17 +1219,6 @@ namespace API
|
||||
}
|
||||
}
|
||||
|
||||
void restore_menubar_taken_window()
|
||||
{
|
||||
auto wd = restrict::bedrock.get_menubar_taken();
|
||||
if(wd)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
restrict::window_manager.set_focus(wd, false);
|
||||
restrict::window_manager.update(wd, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_window_zoomed(window wd, bool ask_for_max)
|
||||
{
|
||||
auto const iwd = reinterpret_cast<restrict::core_window_t*>(wd);
|
||||
|
||||
@@ -25,39 +25,22 @@ namespace nana
|
||||
: public display
|
||||
{
|
||||
public:
|
||||
real_display(std::size_t number)
|
||||
: index_(number)
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
DISPLAY_DEVICE disp;
|
||||
disp.cb = sizeof disp;
|
||||
if (::EnumDisplayDevices(nullptr, static_cast<DWORD>(index_), &disp, 0))
|
||||
{
|
||||
DEVMODE mode;
|
||||
mode.dmSize = sizeof mode;
|
||||
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
|
||||
{
|
||||
area_.x = mode.dmPosition.x;
|
||||
area_.y = mode.dmPosition.y;
|
||||
area_.width = mode.dmPelsWidth;
|
||||
area_.height = mode.dmPelsHeight;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (0 == index_)
|
||||
{
|
||||
area_ = detail::native_interface::primary_monitor_size();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
throw std::invalid_argument("Nana.Screen: Invalid monitor index.");
|
||||
}
|
||||
real_display() = default; //For requirement of vector
|
||||
|
||||
real_display(std::size_t number, const ::nana::rectangle& r)
|
||||
: index_(number), area_(r)
|
||||
#if defined(NANA_WINDOWS)
|
||||
real_display(std::size_t number, const MONITORINFOEX& mi)
|
||||
: index_(number),
|
||||
is_primary_(mi.dwFlags & /*MONITORINFOF_PRIMARY*/ 0x1),
|
||||
area_(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top),
|
||||
workarea_(mi.rcWork.left, mi.rcWork.top, mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top)
|
||||
{
|
||||
}
|
||||
#else
|
||||
real_display(std::size_t number, const ::nana::rectangle& r)
|
||||
: index_(number), is_primary_(true), area_(r), workarea_(r)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
public:
|
||||
//Implementation of display
|
||||
std::size_t get_index() const override
|
||||
@@ -65,13 +48,25 @@ namespace nana
|
||||
return index_;
|
||||
}
|
||||
|
||||
bool is_primary_monitor() const override
|
||||
{
|
||||
return is_primary_;
|
||||
}
|
||||
|
||||
const ::nana::rectangle& area() const override
|
||||
{
|
||||
return area_;
|
||||
}
|
||||
|
||||
const ::nana::rectangle& workarea() const override
|
||||
{
|
||||
return workarea_;
|
||||
}
|
||||
private:
|
||||
const std::size_t index_;
|
||||
std::size_t index_;
|
||||
bool is_primary_;
|
||||
::nana::rectangle area_;
|
||||
::nana::rectangle workarea_;
|
||||
};
|
||||
|
||||
//class screen
|
||||
@@ -92,7 +87,61 @@ namespace nana
|
||||
return ::nana::detail::native_interface::primary_monitor_size();
|
||||
}
|
||||
|
||||
std::shared_ptr<display> screen::from_point(const point& pos)
|
||||
|
||||
struct screen::implement
|
||||
{
|
||||
std::vector<real_display> displays;
|
||||
|
||||
#if defined(NANA_WINDOWS)
|
||||
void load_monitors()
|
||||
{
|
||||
std::vector<real_display> tmp;
|
||||
::EnumDisplayMonitors(nullptr, nullptr, implement::enum_proc, reinterpret_cast<LPARAM>(&tmp));
|
||||
tmp.swap(displays);
|
||||
}
|
||||
|
||||
static BOOL __stdcall enum_proc(HMONITOR handle, HDC context, LPRECT r, LPARAM self_ptr)
|
||||
{
|
||||
auto disp_cont = reinterpret_cast<std::vector<real_display>*>(self_ptr);
|
||||
MONITORINFOEX mi;
|
||||
mi.cbSize = sizeof(MONITORINFOEX);
|
||||
if (::GetMonitorInfo(handle, &mi))
|
||||
disp_cont->emplace_back(disp_cont->size(), mi);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
void load_monitors()
|
||||
{
|
||||
displays.clear();
|
||||
displays.emplace_back(0, primary_monitor_size());
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
screen::screen()
|
||||
: impl_(std::make_shared<implement>())
|
||||
{
|
||||
impl_->load_monitors();
|
||||
}
|
||||
|
||||
void screen::reload()
|
||||
{
|
||||
//It is only when the screen is a moved-from object that impl_ is empty
|
||||
if (!impl_)
|
||||
std::make_shared<implement>().swap(impl_);
|
||||
|
||||
impl_->load_monitors();
|
||||
}
|
||||
|
||||
std::size_t screen::count() const
|
||||
{
|
||||
return impl_->displays.size();
|
||||
}
|
||||
|
||||
|
||||
display& screen::from_point(const point& pos)
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD);
|
||||
@@ -107,87 +156,47 @@ namespace nana
|
||||
mi.cbSize = sizeof mi;
|
||||
if (::GetMonitorInfo(monitor, &mi))
|
||||
{
|
||||
DISPLAY_DEVICE disp;
|
||||
disp.cb = sizeof disp;
|
||||
|
||||
DWORD index = 0;
|
||||
while (::EnumDisplayDevices(nullptr, index++, &disp, 0))
|
||||
for (auto & disp : impl_->displays)
|
||||
{
|
||||
DEVMODE mode;
|
||||
mode.dmSize = sizeof mode;
|
||||
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
|
||||
{
|
||||
if (mode.dmPosition.x == mi.rcWork.left && mode.dmPosition.y == mi.rcWork.top &&
|
||||
(static_cast<int>(mode.dmPelsWidth) == mi.rcWork.right - mi.rcWork.left) &&
|
||||
(static_cast<int>(mode.dmPelsHeight) == mi.rcWork.bottom - mi.rcWork.top))
|
||||
{
|
||||
return std::make_shared<real_display>(static_cast<std::size_t>(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast<unsigned>(mode.dmPelsWidth), static_cast<unsigned>(mode.dmPelsHeight) });
|
||||
}
|
||||
}
|
||||
auto & r = disp.area();
|
||||
if (r.x == mi.rcMonitor.left && r.y == mi.rcMonitor.top &&
|
||||
r.width == unsigned(mi.rcMonitor.right - mi.rcMonitor.left) &&
|
||||
r.height == unsigned(mi.rcMonitor.bottom - mi.rcMonitor.top)
|
||||
)
|
||||
return disp;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return screen().get_primary();
|
||||
return get_primary();
|
||||
}
|
||||
|
||||
std::shared_ptr<display> screen::from_window(window wd)
|
||||
display& screen::from_window(window wd)
|
||||
{
|
||||
::nana::point pos;
|
||||
API::calc_screen_point(wd, pos);
|
||||
return from_point(pos);
|
||||
}
|
||||
|
||||
std::size_t screen::count() const
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
DISPLAY_DEVICE disp;
|
||||
disp.cb = sizeof disp;
|
||||
|
||||
DWORD index = 0;
|
||||
while (::EnumDisplayDevices(nullptr, index++, &disp, 0));
|
||||
return static_cast<std::size_t>(index - 1);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
display& screen::get_display(std::size_t index) const
|
||||
{
|
||||
return impl_->displays.at(index);
|
||||
}
|
||||
|
||||
std::shared_ptr<display> screen::get_display(std::size_t index) const
|
||||
display& screen::get_primary() const
|
||||
{
|
||||
return std::make_shared<real_display>(index);
|
||||
}
|
||||
for (auto & disp : impl_->displays)
|
||||
if (disp.is_primary_monitor())
|
||||
return disp;
|
||||
|
||||
std::shared_ptr<display> screen::get_primary() const
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
//return rectangle(mi.rcWork.left, mi.rcWork.top,
|
||||
// mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top);
|
||||
DISPLAY_DEVICE disp;
|
||||
disp.cb = sizeof disp;
|
||||
|
||||
DWORD index = 0;
|
||||
while (::EnumDisplayDevices(nullptr, index++, &disp, 0))
|
||||
{
|
||||
DEVMODE mode;
|
||||
mode.dmSize = sizeof mode;
|
||||
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode))
|
||||
{
|
||||
if (mode.dmPosition.x == 0 && mode.dmPosition.y == 0)
|
||||
return std::make_shared<real_display>(static_cast<std::size_t>(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast<unsigned>(mode.dmPelsWidth), static_cast<unsigned>(mode.dmPelsHeight) });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return std::make_shared<real_display>(0);
|
||||
throw std::logic_error("no primary monitor found");
|
||||
}
|
||||
|
||||
void screen::for_each(std::function<void(display&)> fn) const
|
||||
{
|
||||
auto n = count();
|
||||
for (decltype(n) i = 0; i < n; ++i)
|
||||
{
|
||||
real_display disp(i);
|
||||
for (auto & disp : impl_->displays)
|
||||
fn(disp);
|
||||
}
|
||||
}
|
||||
//end class screen
|
||||
}
|
||||
|
||||
@@ -109,11 +109,11 @@ namespace nana
|
||||
{
|
||||
public:
|
||||
#if defined(NANA_WINDOWS)
|
||||
timer_core(timer_identifier tmid, const nana::basic_event<arg_elapse>& evt_elapse)
|
||||
timer_core(timer_identifier tmid, basic_event<arg_elapse>& evt_elapse)
|
||||
: timer_(tmid), evt_elapse_(evt_elapse)
|
||||
{}
|
||||
#else
|
||||
timer_core(const nana::basic_event<arg_elapse>& evt_elapse)
|
||||
timer_core(basic_event<arg_elapse>& evt_elapse)
|
||||
: timer_(this), evt_elapse_(evt_elapse)
|
||||
{}
|
||||
#endif
|
||||
@@ -138,7 +138,7 @@ namespace nana
|
||||
}
|
||||
private:
|
||||
const timer_identifier timer_;
|
||||
const nana::basic_event<arg_elapse> & evt_elapse_;
|
||||
nana::basic_event<arg_elapse> & evt_elapse_;
|
||||
}; //end class timer_core
|
||||
|
||||
#if defined(NANA_WINDOWS)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* A Tooltip Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -34,14 +35,14 @@ namespace nana
|
||||
|
||||
nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed)
|
||||
{
|
||||
auto scr_area = screen::from_point(pos)->area();
|
||||
if (pos.x + sz.width > scr_area.x + scr_area.width)
|
||||
pos.x = static_cast<int>(scr_area.x + scr_area.width - sz.width);
|
||||
auto scr_area = screen().from_point(pos).workarea();
|
||||
if (pos.x + static_cast<int>(sz.width) > scr_area.right())
|
||||
pos.x = scr_area.right() - static_cast<int>(sz.width);
|
||||
if (pos.x < scr_area.x)
|
||||
pos.x = scr_area.x;
|
||||
|
||||
if (pos.y + sz.height >= scr_area.y + scr_area.height)
|
||||
pos.y = static_cast<int>(scr_area.y + scr_area.height - sz.height);
|
||||
if (pos.y + static_cast<int>(sz.height) >= scr_area.bottom())
|
||||
pos.y = scr_area.bottom() - static_cast<int>(sz.height);
|
||||
else if (!overlap_allowed)
|
||||
pos.y += 20; //Add some pixels to avoid overlapping between cursor and tip window.
|
||||
|
||||
@@ -77,7 +78,7 @@ namespace nana
|
||||
void tooltip_text(const nana::string& text) override
|
||||
{
|
||||
label_.caption(text);
|
||||
auto text_s = label_.measure(screen::from_window(label_)->area().width * 2 / 3);
|
||||
auto text_s = label_.measure(screen().from_window(label_).workarea().width * 2 / 3);
|
||||
this->size(nana::size{ text_s.width + 10, text_s.height + 10 });
|
||||
label_.move(rectangle{ 5, 5, text_s.width, text_s.height });
|
||||
|
||||
|
||||
@@ -129,22 +129,26 @@ namespace checkbox
|
||||
checkbox::checkbox(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
bgcolor(API::bgcolor(wd));
|
||||
}
|
||||
|
||||
checkbox::checkbox(window wd, const nana::string& text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
bgcolor(API::bgcolor(wd));
|
||||
caption(text);
|
||||
}
|
||||
|
||||
checkbox::checkbox(window wd, const nana::char_t* text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
bgcolor(API::bgcolor(wd));
|
||||
caption(text);
|
||||
}
|
||||
|
||||
checkbox::checkbox(window wd, const nana::rectangle& r, bool visible)
|
||||
{
|
||||
bgcolor(API::bgcolor(wd));
|
||||
create(wd, r, visible);
|
||||
}
|
||||
|
||||
|
||||
@@ -677,6 +677,7 @@ namespace nana
|
||||
if(!drawer_->widget_ptr()->enabled())
|
||||
return;
|
||||
|
||||
bool call_other_keys = false;
|
||||
if(drawer_->editable())
|
||||
{
|
||||
bool is_move_up = false;
|
||||
@@ -684,7 +685,7 @@ namespace nana
|
||||
{
|
||||
case keyboard::os_arrow_left:
|
||||
case keyboard::os_arrow_right:
|
||||
drawer_->editor()->move(arg.key);
|
||||
drawer_->editor()->respond_key(arg.key);
|
||||
drawer_->editor()->reset_caret();
|
||||
break;
|
||||
case keyboard::os_arrow_up:
|
||||
@@ -692,6 +693,8 @@ namespace nana
|
||||
case keyboard::os_arrow_down:
|
||||
drawer_->move_items(is_move_up, true);
|
||||
break;
|
||||
default:
|
||||
call_other_keys = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -706,14 +709,19 @@ namespace nana
|
||||
case keyboard::os_arrow_down:
|
||||
drawer_->move_items(is_move_up, true);
|
||||
break;
|
||||
default:
|
||||
call_other_keys = true;
|
||||
}
|
||||
}
|
||||
if (call_other_keys)
|
||||
drawer_->editor()->respond_key(arg.key);
|
||||
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
void trigger::key_char(graph_reference graph, const arg_keyboard& arg)
|
||||
{
|
||||
if (drawer_->editor()->respone_keyboard(arg.key))
|
||||
if (drawer_->editor()->respond_char(arg.key))
|
||||
API::lazy_refresh();
|
||||
}
|
||||
//end class trigger
|
||||
|
||||
@@ -37,21 +37,25 @@ namespace nana
|
||||
::nana::color clr{ 0xaf, 0xc7, 0xe3 };
|
||||
graph.rectangle(r, false, clr);
|
||||
|
||||
auto right = r.right() - 1;
|
||||
auto bottom = r.bottom() - 1;
|
||||
graph.set_color(colors::white);
|
||||
graph.set_pixel(r.x, r.y);
|
||||
graph.set_pixel(r.x + r.width - 1, r.y);
|
||||
graph.set_pixel(r.x, r.y + r.height - 1);
|
||||
graph.set_pixel(r.x + r.width - 1, r.y + r.height - 1);
|
||||
graph.set_pixel(right, r.y);
|
||||
graph.set_pixel(r.x, bottom);
|
||||
graph.set_pixel(right, bottom);
|
||||
|
||||
--right;
|
||||
--bottom;
|
||||
graph.set_color(clr);
|
||||
graph.set_pixel(r.x + 1, r.y + 1);
|
||||
graph.set_pixel(r.x + r.width - 2, r.y + 1);
|
||||
graph.set_pixel(r.x + 1, r.y + r.height - 2);
|
||||
graph.set_pixel(r.x + r.width - 2, r.y + r.height - 2);
|
||||
graph.set_pixel(right, r.y + 1);
|
||||
graph.set_pixel(r.x + 1, bottom);
|
||||
graph.set_pixel(right, bottom);
|
||||
|
||||
nana::rectangle po_r(r);
|
||||
graph.rectangle(po_r.pare_off(1), false, { 0xEB, 0xF4, 0xFB });
|
||||
graph.gradual_rectangle(po_r.pare_off(1), { 0xDD, 0xEC, 0xFD }, { 0xC2, 0xDC, 0xFD }, true);
|
||||
graph.rectangle(po_r.pare_off(1), false, static_cast<color_rgb>(0xEBF4FB));
|
||||
graph.gradual_rectangle(po_r.pare_off(1), static_cast<color_rgb>(0xDDECFD), static_cast<color_rgb>(0xC2DCFD), true);
|
||||
}
|
||||
else
|
||||
graph.rectangle(r, true, colors::white);
|
||||
@@ -113,13 +117,8 @@ namespace nana
|
||||
class drawer_impl
|
||||
{
|
||||
public:
|
||||
typedef widget& widget_reference;
|
||||
typedef nana::paint::graphics& graph_reference;
|
||||
|
||||
drawer_impl()
|
||||
: widget_(nullptr), graph_(nullptr), image_pixels_(16),
|
||||
ignore_first_mouseup_(true), module_(nullptr)
|
||||
{}
|
||||
using widget_reference = widget&;
|
||||
using graph_reference = paint::graphics&;
|
||||
|
||||
void clear_state()
|
||||
{
|
||||
@@ -151,25 +150,19 @@ namespace nana
|
||||
{
|
||||
if(scrollbar_.empty()) return;
|
||||
|
||||
bool update = false;
|
||||
const auto before_change = state_.offset_y;
|
||||
if(upwards)
|
||||
{
|
||||
if(state_.offset_y)
|
||||
{
|
||||
if (before_change)
|
||||
--(state_.offset_y);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((state_.offset_y + module_->max_items) < module_->items.size())
|
||||
{
|
||||
if ((before_change + module_->max_items) < module_->items.size())
|
||||
++(state_.offset_y);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(update)
|
||||
if(before_change != state_.offset_y)
|
||||
{
|
||||
draw();
|
||||
scrollbar_.value(state_.offset_y);
|
||||
@@ -323,8 +316,7 @@ namespace nana
|
||||
state_.renderer->image(_m_image_enabled(), image_pixels_);
|
||||
for(std::size_t i = state_.offset_y; i < items; ++i)
|
||||
{
|
||||
item_renderer::state_t state = item_renderer::StateNone;
|
||||
if(i == state_.index) state = item_renderer::StateHighlighted;
|
||||
auto state = (i != state_.index ? item_renderer::StateNone : item_renderer::StateHighlighted);
|
||||
|
||||
state_.renderer->render(*widget_, *graph_, item_r, module_->items[i].get(), state);
|
||||
item_r.y += item_pixels;
|
||||
@@ -384,20 +376,20 @@ namespace nana
|
||||
scrollbar_.close();
|
||||
}
|
||||
private:
|
||||
widget * widget_;
|
||||
nana::paint::graphics * graph_;
|
||||
unsigned image_pixels_; //Define the width pixels of the image area
|
||||
widget * widget_{nullptr};
|
||||
nana::paint::graphics * graph_{nullptr};
|
||||
unsigned image_pixels_{16}; //Define the width pixels of the image area
|
||||
|
||||
bool ignore_first_mouseup_;
|
||||
bool ignore_first_mouseup_{true};
|
||||
struct state_type
|
||||
{
|
||||
std::size_t offset_y;
|
||||
std::size_t index; //The index of the selected item.
|
||||
std::size_t offset_y{0};
|
||||
std::size_t index{npos}; //The index of the selected item.
|
||||
|
||||
item_renderer * const orig_renderer;
|
||||
item_renderer * renderer;
|
||||
|
||||
state_type(): offset_y(0), index(npos), orig_renderer(new def_item_renderer), renderer(orig_renderer){}
|
||||
state_type(): orig_renderer(new def_item_renderer), renderer(orig_renderer){}
|
||||
~state_type()
|
||||
{
|
||||
delete orig_renderer;
|
||||
@@ -405,7 +397,7 @@ namespace nana
|
||||
}state_;
|
||||
nana::scroll<true> scrollbar_;
|
||||
|
||||
const module_def* module_;
|
||||
const module_def* module_{nullptr};
|
||||
};
|
||||
|
||||
//class drawer_impl;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: source/gui/widgets/label.cpp
|
||||
* @author: Jinhao
|
||||
* @contributors: Ariel Vina-Rodriguez
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/label.hpp>
|
||||
@@ -586,8 +588,6 @@ namespace nana
|
||||
|
||||
std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos)
|
||||
{
|
||||
std::pair<std::size_t, std::size_t> r;
|
||||
|
||||
std::size_t n = i->data_ptr->text().length();
|
||||
while(pos >= n)
|
||||
{
|
||||
@@ -765,23 +765,27 @@ namespace nana
|
||||
label::label(window wd, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
bgcolor(API::bgcolor(wd));
|
||||
}
|
||||
|
||||
label::label(window wd, const nana::string& text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
bgcolor(API::bgcolor(wd));
|
||||
caption(text);
|
||||
}
|
||||
|
||||
label::label(window wd, const nana::char_t* text, bool visible)
|
||||
{
|
||||
create(wd, rectangle(), visible);
|
||||
bgcolor(API::bgcolor(wd));
|
||||
caption(text);
|
||||
}
|
||||
|
||||
label::label(window wd, const rectangle& r, bool visible)
|
||||
{
|
||||
create(wd, r, visible);
|
||||
bgcolor(API::bgcolor(wd));
|
||||
}
|
||||
|
||||
label& label::transparent(bool enabled)
|
||||
@@ -847,24 +851,16 @@ namespace nana
|
||||
|
||||
label& label::text_align(align th, align_v tv)
|
||||
{
|
||||
internal_scope_guard isg;
|
||||
internal_scope_guard lock;
|
||||
auto impl = get_drawer_trigger().impl();
|
||||
|
||||
bool to_update = false;
|
||||
if(impl->text_align != th)
|
||||
if (th != impl->text_align || tv != impl->text_align_v)
|
||||
{
|
||||
impl->text_align = th;
|
||||
to_update = true;
|
||||
}
|
||||
|
||||
if(impl->text_align_v != tv)
|
||||
{
|
||||
impl->text_align_v = tv;
|
||||
to_update = true;
|
||||
API::refresh_window(*this);
|
||||
}
|
||||
|
||||
if(to_update)
|
||||
API::refresh_window(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Menu implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2009-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -106,7 +106,7 @@ namespace nana
|
||||
sz.width -= 30;
|
||||
sz.height -= 2;
|
||||
graph.rectangle(false, colors::gray_border);
|
||||
graph.rectangle({ 1, 1, 28, sz.height }, true, { 0xf6, 0xf6, 0xf6 });
|
||||
graph.rectangle({ 1, 1, 28, sz.height }, true, static_cast<color_rgb>(0xf6f6f6));
|
||||
graph.rectangle({ 29, 1, sz.width, sz.height }, true, colors::white);
|
||||
}
|
||||
|
||||
@@ -122,17 +122,17 @@ namespace nana
|
||||
nana::point(r.x + r.width - 1, r.y + r.height - 1)
|
||||
};
|
||||
|
||||
graph.set_color({0xc0, 0xdd, 0xfc});
|
||||
graph.set_color(static_cast<color_rgb>(0xc0ddfc));
|
||||
for(int i = 0; i < 4; ++i)
|
||||
graph.set_pixel(points[i].x, points[i].y);
|
||||
|
||||
if(at.enabled)
|
||||
graph.gradual_rectangle(nana::rectangle(r).pare_off(1), { 0xE8, 0xF0, 0xF4 }, { 0xDB,0xEC,0xF4 }, true);
|
||||
graph.gradual_rectangle(nana::rectangle(r).pare_off(1), static_cast<color_rgb>(0xE8F0F4), static_cast<color_rgb>(0xDBECF4), true);
|
||||
}
|
||||
|
||||
if(at.checked && (checks::none != at.check_style))
|
||||
{
|
||||
graph.rectangle(r, false, { 0xCD, 0xD3, 0xE6 });
|
||||
graph.rectangle(r, false, static_cast<color_rgb>(0xCDD3E6));
|
||||
|
||||
::nana::color clr(0xE6, 0xEF, 0xF4);
|
||||
graph.rectangle(nana::rectangle(r).pare_off(1), true, clr);
|
||||
@@ -151,7 +151,7 @@ namespace nana
|
||||
|
||||
void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at)
|
||||
{
|
||||
graph.set_color(at.enabled ? colors::black : colors::gray_border);
|
||||
graph.set_text_color(at.enabled ? colors::black : colors::gray_border);
|
||||
nana::paint::text_renderer tr(graph);
|
||||
tr.render(pos, text.c_str(), text.length(), text_pixels, true);
|
||||
}
|
||||
@@ -363,59 +363,58 @@ namespace nana
|
||||
bool goto_next(bool forword)
|
||||
{
|
||||
state_.nullify_mouse = true;
|
||||
if(menu_->items.size())
|
||||
{
|
||||
std::size_t index = state_.active;
|
||||
if (menu_->items.empty())
|
||||
return false;
|
||||
|
||||
bool end = false;
|
||||
while(true)
|
||||
auto pos = state_.active;
|
||||
const auto lastpos = menu_->items.size() - 1;
|
||||
|
||||
bool end = false;
|
||||
while(true)
|
||||
{
|
||||
if(forword)
|
||||
{
|
||||
if(forword)
|
||||
if(pos == lastpos)
|
||||
{
|
||||
if(index == menu_->items.size() - 1)
|
||||
if (end)
|
||||
{
|
||||
if(end == false)
|
||||
{
|
||||
end = true;
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = npos;
|
||||
break;
|
||||
}
|
||||
pos = npos;
|
||||
break;
|
||||
}
|
||||
else
|
||||
++index;
|
||||
|
||||
end = true;
|
||||
pos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(index == 0 || index == npos)
|
||||
{
|
||||
if(end == false)
|
||||
{
|
||||
end = true;
|
||||
index = menu_->items.size() - 1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
--index;
|
||||
}
|
||||
if(menu_->items.at(index).flags.splitter == false)
|
||||
break;
|
||||
++pos;
|
||||
}
|
||||
|
||||
if(index != npos && index != state_.active)
|
||||
else
|
||||
{
|
||||
state_.active = index;
|
||||
state_.sub_window = false;
|
||||
|
||||
draw();
|
||||
return true;
|
||||
if(pos == 0 || pos == npos)
|
||||
{
|
||||
if (end)
|
||||
break;
|
||||
|
||||
end = true;
|
||||
pos = lastpos;
|
||||
}
|
||||
else
|
||||
--pos;
|
||||
}
|
||||
|
||||
if(! menu_->items.at(pos).flags.splitter)
|
||||
break;
|
||||
}
|
||||
|
||||
if(pos != npos && pos != state_.active)
|
||||
{
|
||||
state_.active = pos;
|
||||
state_.sub_window = false;
|
||||
|
||||
draw();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -486,30 +485,32 @@ namespace nana
|
||||
std::size_t index = 0;
|
||||
for(auto & m : menu_->items)
|
||||
{
|
||||
if(std::tolower(m.hotkey) == key)
|
||||
if (std::tolower(m.hotkey) != key)
|
||||
{
|
||||
if(!m.flags.splitter)
|
||||
{
|
||||
if(m.sub_menu)
|
||||
{
|
||||
state_.active = index;
|
||||
state_.active_timestamp = nana::system::timestamp();
|
||||
|
||||
draw();
|
||||
API::update_window(*widget_);
|
||||
return 2;
|
||||
}
|
||||
else if(m.flags.enabled)
|
||||
{
|
||||
std::move(fn_close_tree_)();
|
||||
item_proxy ip(index, m);
|
||||
m.functor.operator()(ip);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
++index;
|
||||
|
||||
if(!m.flags.splitter)
|
||||
{
|
||||
if(m.sub_menu)
|
||||
{
|
||||
state_.active = index;
|
||||
state_.active_timestamp = nana::system::timestamp();
|
||||
|
||||
draw();
|
||||
API::update_window(*widget_);
|
||||
return 2;
|
||||
}
|
||||
else if(m.flags.enabled)
|
||||
{
|
||||
std::move(fn_close_tree_)();
|
||||
item_proxy ip(index, m);
|
||||
m.functor.operator()(ip);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -529,53 +530,53 @@ namespace nana
|
||||
|
||||
int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2;
|
||||
|
||||
std::size_t index = 0;
|
||||
std::size_t pos = 0;
|
||||
for(auto & m : menu_->items)
|
||||
{
|
||||
if(false == m.flags.splitter)
|
||||
{
|
||||
renderer_interface::attr attr = _m_make_renderer_attr(index == state_.active, m);
|
||||
//Draw item background
|
||||
renderer->item(*graph_, item_r, attr);
|
||||
|
||||
//Draw text, the text is transformed from orignal for hotkey character
|
||||
nana::char_t hotkey;
|
||||
nana::string::size_type hotkey_pos;
|
||||
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
|
||||
|
||||
if(m.image.empty() == false)
|
||||
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image);
|
||||
|
||||
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
|
||||
|
||||
if(hotkey)
|
||||
{
|
||||
m.hotkey = hotkey;
|
||||
if(m.flags.enabled)
|
||||
{
|
||||
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
|
||||
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
|
||||
int x = item_r.x + 40 + off_w;
|
||||
int y = item_r.y + text_top_off + hotkey_size.height;
|
||||
|
||||
graph_->set_color(colors::black);
|
||||
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
|
||||
}
|
||||
}
|
||||
|
||||
if(m.sub_menu)
|
||||
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
|
||||
|
||||
item_r.y += item_r.height + 1;
|
||||
}
|
||||
else
|
||||
if(m.flags.splitter)
|
||||
{
|
||||
graph_->set_color(colors::gray_border);
|
||||
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph_->width()) - 1, item_r.y });
|
||||
item_r.y += 2;
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
|
||||
//Draw item background
|
||||
renderer->item(*graph_, item_r, attr);
|
||||
|
||||
//Draw text, the text is transformed from orignal for hotkey character
|
||||
nana::char_t hotkey;
|
||||
nana::string::size_type hotkey_pos;
|
||||
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
|
||||
|
||||
if(m.image.empty() == false)
|
||||
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image);
|
||||
|
||||
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
|
||||
|
||||
if(hotkey)
|
||||
{
|
||||
m.hotkey = hotkey;
|
||||
if(m.flags.enabled)
|
||||
{
|
||||
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
|
||||
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
|
||||
int x = item_r.x + 40 + off_w;
|
||||
int y = item_r.y + text_top_off + hotkey_size.height;
|
||||
|
||||
graph_->set_color(colors::black);
|
||||
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
|
||||
}
|
||||
}
|
||||
|
||||
++index;
|
||||
if(m.sub_menu)
|
||||
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
|
||||
|
||||
item_r.y += item_r.height + 1;
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
private:
|
||||
@@ -592,9 +593,9 @@ namespace nana
|
||||
std::size_t _m_get_index_by_pos(int x, int y) const
|
||||
{
|
||||
if( (x < static_cast<int>(detail_.border.x)) ||
|
||||
(x > static_cast<int>(graph_->width() - detail_.border.x)) ||
|
||||
(x > static_cast<int>(graph_->width()) - static_cast<int>(detail_.border.x)) ||
|
||||
(y < static_cast<int>(detail_.border.y)) ||
|
||||
(y > static_cast<int>(graph_->height() - detail_.border.y)))
|
||||
(y > static_cast<int>(graph_->height()) - static_cast<int>(detail_.border.y)))
|
||||
return npos;
|
||||
|
||||
int pos = detail_.border.y;
|
||||
@@ -659,14 +660,14 @@ namespace nana
|
||||
API::calc_screen_point(*widget_, pos);
|
||||
|
||||
//get the screen coordinates of the widget pos.
|
||||
auto scr_area = screen::from_point(detail_.monitor_pos)->area();
|
||||
auto scr_area = screen().from_point(detail_.monitor_pos).workarea();
|
||||
|
||||
if(pos.x + size.width > scr_area.x + scr_area.width)
|
||||
pos.x = static_cast<int>(scr_area.x + scr_area.width - size.width);
|
||||
if(pos.x + static_cast<int>(size.width) > scr_area.right())
|
||||
pos.x = scr_area.right() - static_cast<int>(size.width);
|
||||
if(pos.x < scr_area.x) pos.x = scr_area.x;
|
||||
|
||||
if(pos.y + size.height > scr_area.y + scr_area.height)
|
||||
pos.y = static_cast<int>(scr_area.y + scr_area.height - size.height);
|
||||
if(pos.y + static_cast<int>(size.height) > scr_area.bottom())
|
||||
pos.y = scr_area.bottom() - static_cast<int>(size.height);
|
||||
if(pos.y < scr_area.y) pos.y = scr_area.y;
|
||||
|
||||
auto owner = API::get_owner_window(*widget_);
|
||||
@@ -705,7 +706,7 @@ namespace nana
|
||||
|
||||
menu_window(window wd, const point& pos, renderer_interface * rdptr)
|
||||
: base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()),
|
||||
want_focus_(nullptr == wd),
|
||||
want_focus_(nullptr == wd || (API::focus_window() != wd)),
|
||||
event_focus_(nullptr)
|
||||
{
|
||||
caption(STR("nana menu window"));
|
||||
@@ -729,11 +730,6 @@ namespace nana
|
||||
API::activate_window(this->parent());
|
||||
API::take_active(this->handle(), false, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
activate();
|
||||
focus();
|
||||
}
|
||||
|
||||
if(submenu_.parent == nullptr)
|
||||
{
|
||||
@@ -753,14 +749,6 @@ namespace nana
|
||||
pick();
|
||||
});
|
||||
|
||||
if (want_focus_)
|
||||
{
|
||||
event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg)
|
||||
{
|
||||
_m_focus_changed(arg);
|
||||
});
|
||||
}
|
||||
|
||||
timer_.interval(100);
|
||||
timer_.elapse([this]{
|
||||
this->_m_check_repeatly();
|
||||
@@ -768,6 +756,30 @@ namespace nana
|
||||
timer_.start();
|
||||
|
||||
show();
|
||||
|
||||
if (want_focus_)
|
||||
{
|
||||
event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg)
|
||||
{
|
||||
//when the focus of the menu window is losing, close the menu.
|
||||
//But here is not every menu window may have focus event installed,
|
||||
//It is only installed when the owner of window is the desktop window.
|
||||
|
||||
if (false == arg.getting && (arg.receiver != API::root(*this)))
|
||||
{
|
||||
for (auto child = submenu_.child; child; child = child->submenu_.child)
|
||||
{
|
||||
if (API::root(child->handle()) == arg.receiver)
|
||||
return;
|
||||
}
|
||||
|
||||
_m_close_all();
|
||||
}
|
||||
});
|
||||
|
||||
focus();
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
void goto_next(bool forward)
|
||||
@@ -783,39 +795,33 @@ namespace nana
|
||||
API::update_window(object->handle());
|
||||
}
|
||||
|
||||
bool goto_submenu()
|
||||
bool submenu(bool enter)
|
||||
{
|
||||
menu_window * object = this;
|
||||
while(object->submenu_.child)
|
||||
while (object->submenu_.child)
|
||||
object = object->submenu_.child;
|
||||
|
||||
state_.auto_popup_submenu = false;
|
||||
|
||||
if (enter)
|
||||
{
|
||||
if (object->submenu_.parent)
|
||||
{
|
||||
auto & sub = object->submenu_.parent->submenu_;
|
||||
sub.child = nullptr;
|
||||
sub.object = nullptr;
|
||||
|
||||
object->close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nana::point pos;
|
||||
menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0);
|
||||
return object->_m_show_submenu(sbm, pos, true);
|
||||
}
|
||||
|
||||
bool exit_submenu()
|
||||
{
|
||||
menu_window * object =this;
|
||||
while(object->submenu_.child)
|
||||
object = object->submenu_.child;
|
||||
|
||||
state_.auto_popup_submenu = false;
|
||||
|
||||
if (object->submenu_.parent)
|
||||
{
|
||||
auto & sub = object->submenu_.parent->submenu_;
|
||||
sub.child = nullptr;
|
||||
sub.object = nullptr;
|
||||
|
||||
object->close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int send_shortkey(nana::char_t key)
|
||||
{
|
||||
menu_window * object = this;
|
||||
@@ -832,62 +838,52 @@ namespace nana
|
||||
object = object->submenu_.child;
|
||||
|
||||
auto active = object->get_drawer_trigger().active();
|
||||
if (active != npos)
|
||||
auto * menu = object->get_drawer_trigger().data();
|
||||
if ((npos == active) || !menu)
|
||||
return;
|
||||
|
||||
menu_item_type & item = menu->items.at(active);
|
||||
if (item.flags.splitter == false && item.sub_menu == nullptr)
|
||||
{
|
||||
auto * menu = object->get_drawer_trigger().data();
|
||||
if (menu)
|
||||
//There is a situation that menu will not call functor if the item style is check_option
|
||||
//and it is checked before clicking.
|
||||
bool call_functor = true;
|
||||
|
||||
if (checks::highlight == item.style)
|
||||
{
|
||||
menu_item_type & item = menu->items.at(active);
|
||||
if (item.flags.splitter == false && item.sub_menu == nullptr)
|
||||
item.flags.checked = !item.flags.checked;
|
||||
}
|
||||
else if (checks::option == item.style)
|
||||
{
|
||||
//Forward Looks for a splitter
|
||||
auto pos = active;
|
||||
while (pos)
|
||||
{
|
||||
//There is a situation that menu will not call functor if the item style is check_option
|
||||
//and it is checked before clicking.
|
||||
bool call_functor = true;
|
||||
|
||||
if (checks::highlight == item.style)
|
||||
{
|
||||
item.flags.checked = !item.flags.checked;
|
||||
}
|
||||
else if (checks::option == item.style)
|
||||
{
|
||||
if (active > 0)
|
||||
{
|
||||
//clear the checked state in front of active if it is check_option.
|
||||
auto i = active;
|
||||
do
|
||||
{
|
||||
--i;
|
||||
menu_item_type & im = menu->items.at(i);
|
||||
if (im.flags.splitter) break;
|
||||
|
||||
if (checks::option == im.style && im.flags.checked)
|
||||
im.flags.checked = false;
|
||||
} while (i);
|
||||
}
|
||||
|
||||
for (auto i = active + 1; i < menu->items.size(); ++i)
|
||||
{
|
||||
menu_item_type & im = menu->items.at(i);
|
||||
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;
|
||||
//The deleting operation has moved here, because item.functor.operator()(ip)
|
||||
//may create a window, which make a killing focus for menu window, if so the close_all
|
||||
//operation preformences after item.functor.operator()(ip), that would be deleting this object twice!
|
||||
|
||||
if (call_functor && item.flags.enabled && item.functor)
|
||||
{
|
||||
item_type::item_proxy ip(active, item);
|
||||
item.functor.operator()(ip);
|
||||
}
|
||||
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;
|
||||
//The deleting operation has moved here, because item.functor.operator()(ip)
|
||||
//may create a window, which make a killing focus for menu window, if so the close_all
|
||||
//operation preformences after item.functor.operator()(ip), that would be deleting this object twice!
|
||||
|
||||
if (call_functor && item.flags.enabled && item.functor)
|
||||
{
|
||||
item_type::item_proxy ip(active, item);
|
||||
item.functor.operator()(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -943,50 +939,29 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
//when the focus of the menu window is losing, close the menu.
|
||||
//But here is not every menu window may have focus event installed,
|
||||
//It is only installed when the owner of window is the desktop window.
|
||||
void _m_focus_changed(const arg_focus& arg)
|
||||
{
|
||||
if (false == arg.getting)
|
||||
{
|
||||
for (auto child = submenu_.child; child; child = child->submenu_.child)
|
||||
{
|
||||
if (API::root(child->handle()) == arg.receiver)
|
||||
return;
|
||||
}
|
||||
|
||||
_m_close_all();
|
||||
}
|
||||
}
|
||||
|
||||
void _m_key_down(const arg_keyboard& arg)
|
||||
{
|
||||
switch(arg.key)
|
||||
{
|
||||
case keyboard::os_arrow_up:
|
||||
this->goto_next(false);
|
||||
break;
|
||||
case keyboard::os_arrow_down:
|
||||
this->goto_next(true);
|
||||
this->goto_next(keyboard::os_arrow_down == arg.key);
|
||||
break;
|
||||
case keyboard::os_arrow_left:
|
||||
this->exit_submenu();
|
||||
break;
|
||||
case keyboard::os_arrow_right:
|
||||
this->goto_submenu();
|
||||
this->submenu(keyboard::os_arrow_right == arg.key);
|
||||
break;
|
||||
case keyboard::enter:
|
||||
this->pick();
|
||||
break;
|
||||
default:
|
||||
if(2 != send_shortkey(arg.key))
|
||||
if (2 != send_shortkey(arg.key))
|
||||
{
|
||||
if(API::empty_window(*this) == false)
|
||||
if (API::empty_window(*this) == false)
|
||||
close();
|
||||
}
|
||||
else
|
||||
goto_submenu();
|
||||
this->submenu(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,7 +1140,7 @@ namespace nana
|
||||
{
|
||||
if(impl_->mbuilder.set_sub_menu(index, menu_obj.impl_->mbuilder.data()))
|
||||
{
|
||||
implement::info& minfo = impl_->sub_container[index];
|
||||
auto& minfo = impl_->sub_container[index];
|
||||
minfo.handle = &menu_obj;
|
||||
minfo.kill = false;
|
||||
return true;
|
||||
@@ -1184,9 +1159,10 @@ namespace nana
|
||||
menu *menu::create_sub_menu(std::size_t index)
|
||||
{
|
||||
menu * sub = new menu;
|
||||
if(link(index, *sub))
|
||||
|
||||
if (this->link(index, *sub))
|
||||
{
|
||||
implement::info& minfo = impl_->sub_container[index];
|
||||
auto& minfo = impl_->sub_container[index];
|
||||
minfo.handle = sub;
|
||||
minfo.kill = true;
|
||||
return sub;
|
||||
@@ -1255,12 +1231,12 @@ namespace nana
|
||||
|
||||
bool menu::goto_submen()
|
||||
{
|
||||
return (impl_->uiobj ? impl_->uiobj->goto_submenu() : false);
|
||||
return (impl_->uiobj ? impl_->uiobj->submenu(true) : false);
|
||||
}
|
||||
|
||||
bool menu::exit_submenu()
|
||||
{
|
||||
return (impl_->uiobj ? impl_->uiobj->exit_submenu() : false);
|
||||
return (impl_->uiobj ? impl_->uiobj->submenu(false) : false);
|
||||
}
|
||||
|
||||
std::size_t menu::size() const
|
||||
@@ -1311,21 +1287,17 @@ namespace nana
|
||||
impl_->mbuilder.renderer(rd);
|
||||
}
|
||||
|
||||
void menu::_m_destroy_menu_window()
|
||||
{
|
||||
impl_->uiobj = nullptr;
|
||||
if(impl_->destroy_answer)
|
||||
impl_->destroy_answer();
|
||||
}
|
||||
|
||||
void menu::_m_popup(window wd, int x, int y, bool called_by_menubar)
|
||||
{
|
||||
if (impl_->mbuilder.data().items.size())
|
||||
{
|
||||
close();
|
||||
|
||||
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, point(x, y), &(*impl_->mbuilder.renderer())));
|
||||
impl_->uiobj->events().destroy.connect_unignorable([this]{
|
||||
_m_destroy_menu_window();
|
||||
impl_->uiobj = nullptr;
|
||||
if (impl_->destroy_answer)
|
||||
impl_->destroy_answer();
|
||||
});
|
||||
impl_->uiobj->popup(impl_->mbuilder.data(), called_by_menubar);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Menubar implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2009-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -30,21 +30,21 @@ namespace nana
|
||||
{
|
||||
struct item_type
|
||||
{
|
||||
item_type(const nana::string& text, unsigned long shortkey)
|
||||
item_type(const ::nana::string& text, unsigned long shortkey)
|
||||
: text(text), shortkey(shortkey)
|
||||
{}
|
||||
|
||||
nana::string text;
|
||||
::nana::string text;
|
||||
unsigned long shortkey;
|
||||
nana::menu menu_obj;
|
||||
nana::point pos;
|
||||
nana::size size;
|
||||
::nana::menu menu_obj;
|
||||
::nana::point pos;
|
||||
::nana::size size;
|
||||
};
|
||||
|
||||
class trigger::itembase
|
||||
{
|
||||
public:
|
||||
typedef std::vector<item_type*> container;
|
||||
using container = std::vector<item_type*>;
|
||||
|
||||
~itembase()
|
||||
{
|
||||
@@ -52,22 +52,12 @@ namespace nana
|
||||
delete i;
|
||||
}
|
||||
|
||||
void append(const nana::string& text, unsigned long shortkey)
|
||||
void append(const ::nana::string& text, unsigned long shortkey)
|
||||
{
|
||||
if(shortkey && shortkey < 0x61) shortkey += (0x61 - 0x41);
|
||||
cont_.push_back(new item_type(text, shortkey));
|
||||
}
|
||||
|
||||
nana::menu* get_menu(std::size_t index) const
|
||||
{
|
||||
return (index < cont_.size() ? &(cont_[index]->menu_obj) : nullptr);
|
||||
}
|
||||
|
||||
const item_type& at(std::size_t index) const
|
||||
{
|
||||
return *cont_.at(index);
|
||||
}
|
||||
|
||||
std::size_t find(unsigned long shortkey) const
|
||||
{
|
||||
if(shortkey)
|
||||
@@ -98,19 +88,19 @@ namespace nana
|
||||
:handle_(wd), graph_(graph)
|
||||
{}
|
||||
|
||||
void item_renderer::background(const nana::point& pos, const nana::size& size, state_t state)
|
||||
void item_renderer::background(const nana::point& pos, const nana::size& size, state item_state)
|
||||
{
|
||||
auto bground = API::fgcolor(handle_);
|
||||
::nana::color border, body, corner;
|
||||
|
||||
switch(state)
|
||||
switch (item_state)
|
||||
{
|
||||
case item_renderer::state_highlight:
|
||||
case state::highlighted:
|
||||
border = colors::highlight;
|
||||
body.from_rgb(0xC0, 0xDD, 0xFC);
|
||||
corner = body.blend(bground, 0.5);
|
||||
break;
|
||||
case item_renderer::state_selected:
|
||||
case state::selected:
|
||||
border = colors::dark_border;
|
||||
body = colors::white;
|
||||
corner = body.blend(bground, 0.5);
|
||||
@@ -122,17 +112,19 @@ namespace nana
|
||||
nana::rectangle r(pos, size);
|
||||
graph_.rectangle(r, false, border);
|
||||
|
||||
int right = pos.x + static_cast<int>(size.width) - 1;
|
||||
int bottom = pos.y + static_cast<int>(size.height) - 1;
|
||||
graph_.set_color(corner);
|
||||
graph_.set_pixel(pos.x, pos.y);
|
||||
graph_.set_pixel(pos.x + size.width - 1, pos.y);
|
||||
graph_.set_pixel(pos.x, pos.y + size.height - 1);
|
||||
graph_.set_pixel(pos.x + size.width - 1, pos.y + size.height - 1);
|
||||
graph_.set_pixel(right, pos.y);
|
||||
graph_.set_pixel(pos.x, bottom);
|
||||
graph_.set_pixel(right, bottom);
|
||||
graph_.rectangle(r.pare_off(1), true, body);
|
||||
}
|
||||
|
||||
void item_renderer::caption(int x, int y, const nana::string& text)
|
||||
void item_renderer::caption(const point& pos, const nana::string& text)
|
||||
{
|
||||
graph_.string({ x, y }, text, colors::black);
|
||||
graph_.string(pos, text, colors::black);
|
||||
}
|
||||
//end class item_renderer
|
||||
|
||||
@@ -146,23 +138,28 @@ namespace nana
|
||||
delete items_;
|
||||
}
|
||||
|
||||
nana::menu* trigger::push_back(const nana::string& text)
|
||||
nana::menu* trigger::push_back(const ::nana::string& text)
|
||||
{
|
||||
nana::string::value_type shkey;
|
||||
::nana::char_t shkey;
|
||||
API::transform_shortkey_text(text, shkey, nullptr);
|
||||
|
||||
if(shkey)
|
||||
API::register_shortkey(widget_->handle(), shkey);
|
||||
|
||||
auto i = items_->cont().size();
|
||||
auto pos = items_->cont().size();
|
||||
items_->append(text, shkey);
|
||||
_m_draw();
|
||||
return items_->get_menu(i);
|
||||
API::update_window(*widget_);
|
||||
|
||||
return at(pos);
|
||||
}
|
||||
|
||||
nana::menu* trigger::at(std::size_t index) const
|
||||
nana::menu* trigger::at(std::size_t pos) const
|
||||
{
|
||||
return items_->get_menu(index);
|
||||
if (pos < items_->cont().size())
|
||||
return &(items_->cont()[pos]->menu_obj);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::size_t trigger::size() const
|
||||
@@ -219,22 +216,17 @@ namespace nana
|
||||
void trigger::mouse_down(graph_reference graph, const arg_mouse& arg)
|
||||
{
|
||||
state_.nullify_mouse = false;
|
||||
|
||||
state_.active = _m_item_by_pos(arg.pos);
|
||||
if(state_.menu_active == false)
|
||||
|
||||
if (npos != state_.active)
|
||||
{
|
||||
if(state_.active != npos)
|
||||
{
|
||||
if (!state_.menu_active)
|
||||
state_.menu_active = true;
|
||||
_m_popup_menu();
|
||||
}
|
||||
else
|
||||
_m_total_close();
|
||||
}
|
||||
else if(npos == state_.active)
|
||||
_m_total_close();
|
||||
else
|
||||
|
||||
_m_popup_menu();
|
||||
}
|
||||
else
|
||||
_m_total_close();
|
||||
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
@@ -256,7 +248,6 @@ namespace nana
|
||||
_m_draw();
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void trigger::focus(graph_reference, const arg_focus& arg)
|
||||
@@ -281,10 +272,10 @@ namespace nana
|
||||
switch(arg.key)
|
||||
{
|
||||
case keyboard::os_arrow_down:
|
||||
state_.menu->goto_next(true); break;
|
||||
case keyboard::backspace:
|
||||
case keyboard::os_arrow_up:
|
||||
state_.menu->goto_next(false); break;
|
||||
state_.menu->goto_next(keyboard::os_arrow_down == arg.key);
|
||||
break;
|
||||
case keyboard::os_arrow_right:
|
||||
if(state_.menu->goto_submen() == false)
|
||||
_m_move(false);
|
||||
@@ -305,17 +296,26 @@ namespace nana
|
||||
state_.menu->pick();
|
||||
break;
|
||||
default:
|
||||
if(2 != state_.menu->send_shortkey(arg.key))
|
||||
//Katsuhisa Yuasa: menubar key_press improvements
|
||||
//send_shortkey has 3 states, 0 = UNKNOWN KEY, 1 = ITEM, 2 = GOTO SUBMENU
|
||||
int sk_state = state_.menu->send_shortkey(arg.key);
|
||||
switch(sk_state)
|
||||
{
|
||||
if(state_.active != npos)
|
||||
case 0: //UNKNOWN KEY
|
||||
break;
|
||||
case 1: //ITEM
|
||||
if (state_.active != npos)
|
||||
{
|
||||
_m_total_close();
|
||||
if(arg.key == 18) //ALT
|
||||
if (arg.key == 18) //ALT
|
||||
state_.behavior = state_.behavior_focus;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
case 2: //GOTO SUBMENU
|
||||
state_.menu->goto_submen();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -323,19 +323,34 @@ namespace nana
|
||||
switch(arg.key)
|
||||
{
|
||||
case keyboard::os_arrow_right:
|
||||
_m_move(false);
|
||||
break;
|
||||
case keyboard::backspace:
|
||||
case keyboard::os_arrow_left:
|
||||
_m_move(true);
|
||||
_m_move(keyboard::os_arrow_right != arg.key);
|
||||
break;
|
||||
case keyboard::os_arrow_up:
|
||||
case keyboard::os_arrow_down:
|
||||
case keyboard::enter:
|
||||
state_.menu_active = true;
|
||||
if(_m_popup_menu())
|
||||
state_.menu->goto_next(true);
|
||||
break;
|
||||
case keyboard::escape:
|
||||
if(state_.behavior == state_.behavior_focus)
|
||||
{
|
||||
state_.active= npos;
|
||||
state_.behavior = state_.behavior_none;
|
||||
API::restore_menubar_taken_window();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
std::size_t index = items_->find(arg.key);
|
||||
if(index != npos)
|
||||
{
|
||||
state_.active = index;
|
||||
state_.menu_active = true;
|
||||
if(_m_popup_menu())
|
||||
state_.menu->goto_next(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,20 +434,37 @@ namespace nana
|
||||
|
||||
bool trigger::_m_popup_menu()
|
||||
{
|
||||
if(state_.menu_active && (state_.menu != items_->get_menu(state_.active)))
|
||||
{
|
||||
std::size_t index = state_.active;
|
||||
_m_close_menu();
|
||||
state_.active = index;
|
||||
auto& items = items_->cont();
|
||||
|
||||
state_.menu = items_->get_menu(state_.active);
|
||||
if(state_.menu)
|
||||
auto pos = state_.active;
|
||||
if (pos >= items.size())
|
||||
return false;
|
||||
|
||||
if(state_.menu_active && (state_.menu != &(items[pos]->menu_obj)))
|
||||
{
|
||||
API::dev::delay_restore(true);
|
||||
_m_close_menu();
|
||||
API::dev::delay_restore(false);
|
||||
state_.active = pos;
|
||||
|
||||
auto & m = items[pos];
|
||||
state_.menu = &(m->menu_obj);
|
||||
state_.menu->destroy_answer([this]
|
||||
{
|
||||
const item_type &m = items_->at(state_.active);
|
||||
state_.menu->destroy_answer(std::bind(&trigger::_m_unload_menu_window, this));
|
||||
menu_accessor::popup(*state_.menu, widget_->handle(), m.pos.x, m.pos.y + m.size.height);
|
||||
return true;
|
||||
}
|
||||
state_.menu = nullptr;
|
||||
if (state_.passive_close)
|
||||
{
|
||||
_m_total_close();
|
||||
|
||||
_m_draw();
|
||||
API::update_window(widget_->handle());
|
||||
}
|
||||
});
|
||||
|
||||
if (API::focus_window() != this->widget_->handle())
|
||||
API::focus_window(widget_->handle());
|
||||
menu_accessor::popup(*state_.menu, *widget_, m->pos.x, m->pos.y + static_cast<int>(m->size.height));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -443,8 +475,6 @@ namespace nana
|
||||
state_.menu_active = false;
|
||||
state_.behavior = state_.behavior_none;
|
||||
|
||||
API::restore_menubar_taken_window();
|
||||
|
||||
auto pos = API::cursor_position();
|
||||
API::calc_window_point(widget_->handle(), pos);
|
||||
state_.active = _m_item_by_pos(pos);
|
||||
@@ -463,17 +493,6 @@ namespace nana
|
||||
return false;
|
||||
}
|
||||
|
||||
void trigger::_m_unload_menu_window()
|
||||
{
|
||||
state_.menu = nullptr;
|
||||
if(state_.passive_close)
|
||||
{
|
||||
_m_total_close();
|
||||
_m_draw();
|
||||
API::update_window(widget_->handle());
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t trigger::_m_item_by_pos(const ::nana::point& pos)
|
||||
{
|
||||
if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25))
|
||||
@@ -521,9 +540,9 @@ namespace nana
|
||||
for(auto i : items_->cont())
|
||||
{
|
||||
//Transform the text if it contains the hotkey character
|
||||
nana::string::value_type hotkey;
|
||||
nana::string::size_type hotkey_pos;
|
||||
nana::string text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos);
|
||||
::nana::char_t hotkey;
|
||||
::nana::string::size_type hotkey_pos;
|
||||
auto text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos);
|
||||
|
||||
nana::size text_s = graph_->text_extent_size(text);
|
||||
|
||||
@@ -532,10 +551,11 @@ namespace nana
|
||||
i->pos = item_pos;
|
||||
i->size = item_s;
|
||||
|
||||
item_renderer::state_t state = (index != state_.active ? ird.state_normal : (state_.menu_active ? ird.state_selected : ird.state_highlight));
|
||||
ird.background(item_pos, item_s, state);
|
||||
using state = item_renderer::state;
|
||||
state item_state = (index != state_.active ? state::normal : (state_.menu_active ? state::selected : state::highlighted));
|
||||
ird.background(item_pos, item_s, item_state);
|
||||
|
||||
if(state == ird.state_selected)
|
||||
if (state::selected == item_state)
|
||||
{
|
||||
int x = item_pos.x + item_s.width;
|
||||
int y1 = item_pos.y + 2, y2 = item_pos.y + item_s.height - 1;
|
||||
@@ -545,7 +565,7 @@ namespace nana
|
||||
|
||||
//Draw text, the text is transformed from orignal for hotkey character
|
||||
int text_top_off = (item_s.height - text_s.height) / 2;
|
||||
ird.caption(item_pos.x + 8, item_pos.y + text_top_off, text);
|
||||
ird.caption({ item_pos.x + 8, item_pos.y + text_top_off }, text);
|
||||
|
||||
if(hotkey)
|
||||
{
|
||||
@@ -566,7 +586,12 @@ namespace nana
|
||||
|
||||
//struct state_type
|
||||
trigger::state_type::state_type()
|
||||
:active(npos), behavior(behavior_none), menu_active(false), passive_close(true), nullify_mouse(false), menu(nullptr)
|
||||
: active(npos),
|
||||
behavior(behavior_none),
|
||||
menu_active(false),
|
||||
passive_close(true),
|
||||
nullify_mouse(false),
|
||||
menu(nullptr)
|
||||
{}
|
||||
//end struct state_type
|
||||
//end class trigger
|
||||
|
||||
@@ -109,8 +109,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
if (fit_size.width < graphsize.width || fit_size.height < graphsize.height)
|
||||
_m_draw_background();
|
||||
_m_draw_background(fit_size.width, fit_size.height);
|
||||
|
||||
backimg.image.stretch(valid_area, graph, { pos, fit_size });
|
||||
}
|
||||
@@ -141,14 +140,15 @@ namespace nana
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid_area.width < graphsize.width || valid_area.height < graphsize.height)
|
||||
_m_draw_background();
|
||||
_m_draw_background(valid_area.width, valid_area.height);
|
||||
|
||||
backimg.image.paste(valid_area, graph, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_m_draw_background(graphsize.width, graphsize.height);
|
||||
|
||||
color invalid_clr_for_call;
|
||||
backimg.bground->draw(graph, invalid_clr_for_call, invalid_clr_for_call, graphsize, element_state::normal);
|
||||
}
|
||||
@@ -156,18 +156,22 @@ namespace nana
|
||||
graph.setsta();
|
||||
}
|
||||
|
||||
void drawer::_m_draw_background()
|
||||
void drawer::_m_draw_background(unsigned w, unsigned h)
|
||||
{
|
||||
auto graph = impl_->graph_ptr;
|
||||
|
||||
if (graph && (bground_mode::basic != API::effects_bground_mode(*impl_->wdg_ptr)))
|
||||
{
|
||||
auto & bground = impl_->gradual_bground;
|
||||
if (bground.gradual_from.invisible() || bground.gradual_to.invisible())
|
||||
graph->rectangle(true, impl_->wdg_ptr->bgcolor());
|
||||
else if (bground.gradual_from == bground.gradual_to)
|
||||
graph->rectangle(true, bground.gradual_from);
|
||||
else
|
||||
graph->gradual_rectangle(graph->size(), bground.gradual_from, bground.gradual_to, !bground.horizontal);
|
||||
if (w < graph->size().width || h < graph->size().width || impl_->backimg.image.alpha())
|
||||
{
|
||||
auto & bground = impl_->gradual_bground;
|
||||
if (bground.gradual_from.invisible() || bground.gradual_to.invisible())
|
||||
graph->rectangle(true, impl_->wdg_ptr->bgcolor());
|
||||
else if (bground.gradual_from == bground.gradual_to)
|
||||
graph->rectangle(true, bground.gradual_from);
|
||||
else
|
||||
graph->gradual_rectangle(graph->size(), bground.gradual_from, bground.gradual_to, !bground.horizontal);
|
||||
}
|
||||
}
|
||||
}
|
||||
//end class drawer
|
||||
|
||||
@@ -52,20 +52,11 @@ namespace nana
|
||||
pos = screen_pos.x;
|
||||
}
|
||||
|
||||
if(scale >= fixedsize * 2)
|
||||
{
|
||||
if(pos < static_cast<int>(fixedsize))
|
||||
return buttons::first;
|
||||
if(pos > static_cast<int>(scale - fixedsize))
|
||||
return buttons::second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pos < static_cast<int>(scale / 2))
|
||||
return buttons::first;
|
||||
if(pos > static_cast<int>(scale / 2))
|
||||
return buttons::second;
|
||||
}
|
||||
const auto bound_pos = static_cast<int>(scale >= fixedsize * 2 ? fixedsize : scale / 2);
|
||||
if (pos < bound_pos)
|
||||
return buttons::first;
|
||||
if (pos > static_cast<int>(scale) - bound_pos)
|
||||
return buttons::second;
|
||||
|
||||
if(metrics_.scroll_length)
|
||||
{
|
||||
@@ -100,7 +91,7 @@ namespace nana
|
||||
metrics_.scroll_pos = pos;
|
||||
auto value_max = metrics_.peak - metrics_.range;
|
||||
metrics_.value = pos * value_max / scroll_area;
|
||||
if(metrics_.value < metrics_.peak - metrics_.range)
|
||||
if(metrics_.value < value_max)
|
||||
{
|
||||
int selfpos = static_cast<int>(metrics_.value * scroll_area / value_max);
|
||||
int nextpos = static_cast<int>((metrics_.value + 1) * scroll_area / value_max);
|
||||
@@ -115,22 +106,22 @@ namespace nana
|
||||
|
||||
void drawer::auto_scroll()
|
||||
{
|
||||
if(_m_check())
|
||||
if (!_m_check())
|
||||
return;
|
||||
|
||||
if(buttons::forward == metrics_.what)
|
||||
{ //backward
|
||||
if(metrics_.value <= metrics_.range)
|
||||
metrics_.value = 0;
|
||||
else
|
||||
metrics_.value -= (metrics_.range-1);
|
||||
}
|
||||
else if(buttons::backward == metrics_.what)
|
||||
{
|
||||
if(buttons::forward == metrics_.what)
|
||||
{ //backward
|
||||
if(metrics_.value <= metrics_.range)
|
||||
metrics_.value = 0;
|
||||
else
|
||||
metrics_.value -= metrics_.range;
|
||||
}
|
||||
else if(buttons::backward == metrics_.what)
|
||||
{
|
||||
if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range)
|
||||
metrics_.value = metrics_.peak - metrics_.range;
|
||||
else
|
||||
metrics_.value += metrics_.range;
|
||||
}
|
||||
if(metrics_.peak - metrics_.range - metrics_.value <= metrics_.range)
|
||||
metrics_.value = metrics_.peak - metrics_.range;
|
||||
else
|
||||
metrics_.value += (metrics_.range-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,26 +132,20 @@ namespace nana
|
||||
|
||||
_m_background(graph);
|
||||
|
||||
::nana::rectangle r(graph.size());
|
||||
if(vertical_)
|
||||
{
|
||||
r.y = r.height - fixedsize;
|
||||
r.height = fixedsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.x = r.width - fixedsize;
|
||||
r.width = fixedsize;
|
||||
}
|
||||
rectangle_rotator r(vertical_, graph.size());
|
||||
r.x_ref() = static_cast<int>(r.w() - fixedsize);
|
||||
r.w_ref() = fixedsize;
|
||||
|
||||
int state = ((_m_check() == false || what == buttons::none) ? states::none : states::highlight);
|
||||
int moused_state = (_m_check() ? (metrics_.pressed ? states::selected : states::actived) : states::none);
|
||||
|
||||
auto result = r.result();
|
||||
|
||||
//draw first
|
||||
_m_draw_button(graph, { 0, 0, r.width, r.height }, buttons::first, (buttons::first == what ? moused_state : state));
|
||||
_m_draw_button(graph, { 0, 0, result.width, result.height }, buttons::first, (buttons::first == what ? moused_state : state));
|
||||
|
||||
//draw second
|
||||
_m_draw_button(graph, r, buttons::second, (buttons::second == what ? moused_state : state));
|
||||
_m_draw_button(graph, result, buttons::second, (buttons::second == what ? moused_state : state));
|
||||
|
||||
//draw scroll
|
||||
_m_draw_scroll(graph, (buttons::scroll == what ? moused_state : states::highlight));
|
||||
@@ -171,64 +156,61 @@ namespace nana
|
||||
{
|
||||
graph.rectangle(true, {0xf0, 0xf0, 0xf0});
|
||||
|
||||
if(metrics_.pressed && _m_check())
|
||||
if (!metrics_.pressed || !_m_check())
|
||||
return;
|
||||
|
||||
nana::rectangle_rotator r(vertical_, graph.size());
|
||||
if(metrics_.what == buttons::forward)
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
unsigned width = graph.width(), height = graph.height();
|
||||
|
||||
if(metrics_.what == buttons::forward)
|
||||
{
|
||||
*(vertical_ ? &y : &x) = fixedsize;
|
||||
*(vertical_ ? &height: &width) = metrics_.scroll_pos;
|
||||
}
|
||||
else if(buttons::backward == metrics_.what)
|
||||
{
|
||||
*(vertical_ ? &y : &x) = static_cast<int>(fixedsize + metrics_.scroll_pos + metrics_.scroll_length);
|
||||
*(vertical_ ? &height: &width) = static_cast<unsigned>((vertical_ ? graph.height() : graph.width()) - (fixedsize * 2 + metrics_.scroll_pos + metrics_.scroll_length));
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
if(width && height)
|
||||
graph.rectangle({ x, y, width, height }, true, {0xDC, 0xDC, 0xDC});
|
||||
r.x_ref() = static_cast<int>(fixedsize);
|
||||
r.w_ref() = metrics_.scroll_pos;
|
||||
}
|
||||
else if(buttons::backward == metrics_.what)
|
||||
{
|
||||
r.x_ref() = static_cast<int>(fixedsize + metrics_.scroll_pos + metrics_.scroll_length);
|
||||
r.w_ref() = static_cast<unsigned>((vertical_ ? graph.height() : graph.width()) - (fixedsize * 2 + metrics_.scroll_pos + metrics_.scroll_length));
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
auto result = r.result();
|
||||
if (!result.empty())
|
||||
graph.rectangle(result, true, static_cast<color_rgb>(0xDCDCDC));
|
||||
}
|
||||
|
||||
void drawer::_m_button_frame(graph_reference graph, rectangle r, int state)
|
||||
{
|
||||
if(state)
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
::nana::color clr{0x97, 0x97, 0x97}; //highlight
|
||||
switch(state)
|
||||
{
|
||||
::nana::color clr{0x97, 0x97, 0x97}; //highlight
|
||||
switch(state)
|
||||
{
|
||||
case states::actived:
|
||||
clr.from_rgb(0x86, 0xD5, 0xFD); break;
|
||||
case states::selected:
|
||||
clr.from_rgb(0x3C, 0x7F, 0xB1); break;
|
||||
}
|
||||
|
||||
graph.rectangle(r, false, clr);
|
||||
|
||||
clr = clr.blend(colors::white, 0.5);
|
||||
graph.set_color(clr);
|
||||
|
||||
r.pare_off(2);
|
||||
|
||||
if(vertical_)
|
||||
{
|
||||
unsigned half = r.width / 2;
|
||||
graph.rectangle({ r.x + static_cast<int>(r.width - half), r.y, half, r.height }, true);
|
||||
r.width -= half;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned half = r.height / 2;
|
||||
graph.rectangle({r.x, r.y + static_cast<int>(r.height - half), r.width, half}, true);
|
||||
r.height -= half;
|
||||
}
|
||||
//graph.shadow_rectangle(x, y, width, height, 0xFFFFFF, color_x, !vertical_);
|
||||
graph.gradual_rectangle(r, colors::white, clr, !vertical_);
|
||||
case states::actived:
|
||||
clr.from_rgb(0x86, 0xD5, 0xFD); break;
|
||||
case states::selected:
|
||||
clr.from_rgb(0x3C, 0x7F, 0xB1); break;
|
||||
}
|
||||
|
||||
graph.rectangle(r, false, clr);
|
||||
|
||||
clr = clr.blend(colors::white, 0.5);
|
||||
graph.set_color(clr);
|
||||
|
||||
r.pare_off(2);
|
||||
if(vertical_)
|
||||
{
|
||||
unsigned half = r.width / 2;
|
||||
graph.rectangle({ r.x + static_cast<int>(r.width - half), r.y, half, r.height }, true);
|
||||
r.width -= half;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned half = r.height / 2;
|
||||
graph.rectangle({r.x, r.y + static_cast<int>(r.height - half), r.width, half}, true);
|
||||
r.height -= half;
|
||||
}
|
||||
graph.gradual_rectangle(r, colors::white, clr, !vertical_);
|
||||
}
|
||||
|
||||
bool drawer::_m_check() const
|
||||
@@ -271,20 +253,11 @@ namespace nana
|
||||
{
|
||||
if(_m_check())
|
||||
{
|
||||
::nana::rectangle r(graph.size());
|
||||
rectangle_rotator r(vertical_, graph.size());
|
||||
r.x_ref() = static_cast<int>(fixedsize + metrics_.scroll_pos);
|
||||
r.w_ref() = static_cast<unsigned>(metrics_.scroll_length);
|
||||
|
||||
if(vertical_)
|
||||
{
|
||||
r.y = fixedsize + metrics_.scroll_pos;
|
||||
r.height = static_cast<unsigned>(metrics_.scroll_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
r.x = fixedsize + metrics_.scroll_pos;
|
||||
r.width = static_cast<unsigned>(metrics_.scroll_length);
|
||||
}
|
||||
|
||||
_m_button_frame(graph, r, state);
|
||||
_m_button_frame(graph, r.result(), state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/*
|
||||
* A text editor implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/skeletons/text_editor.cpp
|
||||
* @description:
|
||||
*/
|
||||
* A text editor implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* @file: nana/gui/widgets/skeletons/text_editor.cpp
|
||||
* @contributors: Ariel Vina-Rodriguez
|
||||
*/
|
||||
#include <nana/gui/widgets/skeletons/text_editor.hpp>
|
||||
#include <nana/gui/widgets/skeletons/textbase_export_interface.hpp>
|
||||
#include <nana/gui/element.hpp>
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <numeric>
|
||||
#include <cwctype>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nana{ namespace widgets
|
||||
{
|
||||
@@ -314,7 +315,13 @@ namespace nana{ namespace widgets
|
||||
if (pos.y > static_cast<unsigned>(textbase.lines()))
|
||||
pos.y = static_cast<unsigned>(textbase.lines());
|
||||
|
||||
pos.x = editor_._m_pixels_by_char(textbase.getline(pos.y), pos.x) + editor_.text_area_.area.x;
|
||||
std::unique_ptr<nana::string> mask_str;
|
||||
if (editor_.mask_char_)
|
||||
mask_str.reset(new nana::string(textbase.getline(pos.y).size(), editor_.mask_char_));
|
||||
|
||||
auto & lnstr = editor_.mask_char_ ? *mask_str : textbase.getline(pos.y);
|
||||
|
||||
pos.x = editor_._m_pixels_by_char(lnstr, pos.x) + editor_.text_area_.area.x;
|
||||
|
||||
int pos_y = static_cast<int>((pos.y - editor_.points_.offset.y) * editor_.line_height() + editor_._m_text_top_base());
|
||||
int pos_x = static_cast<int>(pos.x - editor_.points_.offset.x);
|
||||
@@ -327,7 +334,13 @@ namespace nana{ namespace widgets
|
||||
nana::upoint res{ 0, static_cast<unsigned>(_m_textline_from_screen(scrpos.y)) };
|
||||
|
||||
//Convert the screen point to text caret point
|
||||
const string_type& lnstr = editor_.textbase_.getline(res.y);
|
||||
const string_type& real_str = editor_.textbase_.getline(res.y);
|
||||
|
||||
std::unique_ptr<nana::string> mask_str;
|
||||
if (editor_.mask_char_)
|
||||
mask_str.reset(new nana::string(real_str.size(), editor_.mask_char_));
|
||||
|
||||
auto & lnstr = (editor_.mask_char_ ? *mask_str : real_str);
|
||||
if (lnstr.size() > 0)
|
||||
{
|
||||
scrpos.x += (editor_.points_.offset.x - editor_.text_area_.area.x);
|
||||
@@ -676,7 +689,7 @@ namespace nana{ namespace widgets
|
||||
}
|
||||
}
|
||||
else
|
||||
editor_.render(API::is_focus_window(editor_.window_));
|
||||
editor_.render(API::is_focus_ready(editor_.window_));
|
||||
}
|
||||
|
||||
void render(const ::nana::color& fgcolor) override
|
||||
@@ -737,17 +750,24 @@ namespace nana{ namespace widgets
|
||||
nana::point scrpos;
|
||||
if (0 != pos.x)
|
||||
{
|
||||
nana::string str;
|
||||
for (auto & sec : mtr.line_sections)
|
||||
{
|
||||
std::size_t chsize = sec.end - sec.begin;
|
||||
str.clear();
|
||||
if (editor_.mask_char_)
|
||||
str.append(chsize, editor_.mask_char_);
|
||||
else
|
||||
str.append(sec.begin, sec.end);
|
||||
|
||||
if (pos.x < chsize)
|
||||
{
|
||||
scrpos.x = editor_._m_pixels_by_char(nana::string(sec.begin, sec.end), pos.x);
|
||||
scrpos.x = editor_._m_pixels_by_char(str, pos.x);
|
||||
break;
|
||||
}
|
||||
else if (pos.x == chsize)
|
||||
{
|
||||
scrpos.x = editor_._m_text_extent_size(nana::string(sec.begin, sec.end).data(), sec.end - sec.begin).width;
|
||||
scrpos.x = editor_._m_text_extent_size(str.data(), sec.end - sec.begin).width;
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -773,13 +793,19 @@ namespace nana{ namespace widgets
|
||||
return{ 0, static_cast<unsigned>(primary) };
|
||||
|
||||
//First of all, find the text of secondary.
|
||||
auto str = mtr.line_sections[secondary];
|
||||
auto real_str = mtr.line_sections[secondary];
|
||||
|
||||
std::unique_ptr<nana::string> mask_str;
|
||||
if (editor_.mask_char_)
|
||||
mask_str.reset(new nana::string(real_str.end - real_str.begin, editor_.mask_char_));
|
||||
|
||||
const ::nana::char_t * str = (editor_.mask_char_ ? mask_str->data() : real_str.begin);
|
||||
|
||||
std::vector<unicode_bidi::entity> reordered;
|
||||
unicode_bidi bidi;
|
||||
bidi.linestr(str.begin, str.end - str.begin, reordered);
|
||||
bidi.linestr(str, real_str.end - real_str.begin, reordered);
|
||||
|
||||
nana::upoint res(static_cast<unsigned>(str.begin - mtr.line_sections.front().begin), static_cast<unsigned>(primary));
|
||||
nana::upoint res(static_cast<unsigned>(real_str.begin - mtr.line_sections.front().begin), static_cast<unsigned>(primary));
|
||||
scrpos.x -= editor_.text_area_.area.x;
|
||||
if (scrpos.x < 0)
|
||||
scrpos.x = 0;
|
||||
@@ -793,7 +819,7 @@ namespace nana{ namespace widgets
|
||||
std::unique_ptr<unsigned[]> pxbuf(new unsigned[len]);
|
||||
|
||||
res.x += editor_._m_char_by_pixels(ent.begin, len, pxbuf.get(), str_px, scrpos.x, _m_is_right_text(ent));
|
||||
res.x += static_cast<unsigned>(ent.begin - str.begin);
|
||||
res.x += static_cast<unsigned>(ent.begin - str);
|
||||
return res;
|
||||
}
|
||||
scrpos.x -= str_px;
|
||||
@@ -1133,12 +1159,14 @@ namespace nana{ namespace widgets
|
||||
public:
|
||||
void parse(const ::nana::string& text, const keywords* kwptr)
|
||||
{
|
||||
if (text.empty())
|
||||
if ( kwptr->kwbase.empty() || text.empty() )
|
||||
return;
|
||||
|
||||
using index = ::nana::string::size_type;
|
||||
|
||||
std::vector<entity> entities;
|
||||
|
||||
auto test_whole_word = [&text](std::size_t pos, std::size_t len)
|
||||
auto test_whole_word = [&text](index pos, index len)
|
||||
{
|
||||
if (pos)
|
||||
{
|
||||
@@ -1160,53 +1188,48 @@ namespace nana{ namespace widgets
|
||||
::nana::cistring cistr;
|
||||
for (auto & ds : kwptr->kwbase)
|
||||
{
|
||||
std::size_t pos;
|
||||
const ::nana::char_t* begin;
|
||||
const ::nana::char_t* end;
|
||||
if (ds.case_sensitive)
|
||||
{
|
||||
pos = text.find(ds.text);
|
||||
if (pos == text.npos)
|
||||
continue;
|
||||
index pos{0} ;
|
||||
for (index rest{text.size()}; rest >= ds.text.size() ; ++pos, rest = text.size() - pos)
|
||||
{
|
||||
if (ds.case_sensitive)
|
||||
{
|
||||
pos = text.find(ds.text, pos);
|
||||
if (pos == text.npos)
|
||||
break;
|
||||
|
||||
if (ds.whole_word_matched)
|
||||
{
|
||||
if (!test_whole_word(pos, ds.text.size()))
|
||||
continue;
|
||||
}
|
||||
if (ds.whole_word_matched)
|
||||
{
|
||||
if (!test_whole_word(pos, ds.text.size()))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cistr.empty())
|
||||
cistr.append(text.data(), text.size());
|
||||
|
||||
begin = text.data() + pos;
|
||||
end = begin + ds.text.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cistr.empty())
|
||||
cistr.append(text.data(), text.size());
|
||||
pos = cistr.find(ds.text.data(), pos);
|
||||
if (pos == cistr.npos)
|
||||
break;
|
||||
|
||||
pos = cistr.find(ds.text.data());
|
||||
if (pos == cistr.npos)
|
||||
continue;
|
||||
if (ds.whole_word_matched)
|
||||
{
|
||||
if (!test_whole_word(pos, ds.text.size()))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ds.whole_word_matched)
|
||||
{
|
||||
if (!test_whole_word(pos, ds.text.size()))
|
||||
continue;
|
||||
}
|
||||
|
||||
begin = text.data() + pos;
|
||||
end = begin + ds.text.size();
|
||||
}
|
||||
|
||||
auto ki = kwptr->schemes.find(ds.scheme);
|
||||
if (ki != kwptr->schemes.end() && ki->second)
|
||||
{
|
||||
schemes_.emplace(ds.scheme, ki->second);
|
||||
entities.emplace_back();
|
||||
auto & last = entities.back();
|
||||
last.begin = begin;
|
||||
last.end = end;
|
||||
last.scheme = ki->second.get();
|
||||
}
|
||||
auto ki = kwptr->schemes.find(ds.scheme);
|
||||
if (ki != kwptr->schemes.end() && ki->second)
|
||||
{
|
||||
schemes_.emplace(ds.scheme, ki->second);
|
||||
entities.emplace_back();
|
||||
auto & last = entities.back();
|
||||
last.begin = text.data() + pos;
|
||||
last.end = last.begin + ds.text.size();
|
||||
last.scheme = ki->second.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!entities.empty())
|
||||
@@ -1221,7 +1244,7 @@ namespace nana{ namespace widgets
|
||||
while(i != entities.end())
|
||||
{
|
||||
if (previous->end > i->begin)
|
||||
i = entities.erase(i);
|
||||
i = entities.erase(i); // erase overlaping. Left only the first.
|
||||
else
|
||||
++i;
|
||||
}
|
||||
@@ -1326,7 +1349,7 @@ namespace nana{ namespace widgets
|
||||
attributes_.acceptive = acceptive;
|
||||
}
|
||||
|
||||
bool text_editor::respone_keyboard(char_type key) //key is a character of ASCII code
|
||||
bool text_editor::respond_char(char_type key) //key is a character of ASCII code
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
@@ -1377,6 +1400,24 @@ namespace nana{ namespace widgets
|
||||
return false;
|
||||
}
|
||||
|
||||
bool text_editor::respond_key(char_type key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case keyboard::os_arrow_left: move_left(); break;
|
||||
case keyboard::os_arrow_right: move_right(); break;
|
||||
case keyboard::os_arrow_up: move_ns(true); break;
|
||||
case keyboard::os_arrow_down: move_ns(false); break;
|
||||
case keyboard::os_del:
|
||||
if (this->attr().editable)
|
||||
del();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void text_editor::typeface_changed()
|
||||
{
|
||||
behavior_->pre_calc_lines(width_pixels());
|
||||
@@ -1407,7 +1448,7 @@ namespace nana{ namespace widgets
|
||||
move_caret(upoint{});
|
||||
|
||||
_m_scrollbar();
|
||||
render(API::is_focus_window(window_));
|
||||
render(API::is_focus_ready(window_));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1425,7 +1466,7 @@ namespace nana{ namespace widgets
|
||||
|
||||
_m_reset();
|
||||
behavior_->pre_calc_lines(width_pixels());
|
||||
render(API::is_focus_window(window_));
|
||||
render(API::is_focus_ready(window_));
|
||||
_m_scrollbar();
|
||||
return true;
|
||||
}
|
||||
@@ -1676,7 +1717,7 @@ namespace nana{ namespace widgets
|
||||
//Set caret position through text coordinate
|
||||
void text_editor::move_caret(const upoint& crtpos)
|
||||
{
|
||||
if (!API::is_focus_window(window_))
|
||||
if (!API::is_focus_ready(window_))
|
||||
return;
|
||||
|
||||
const unsigned line_pixels = line_height();
|
||||
@@ -1718,7 +1759,7 @@ namespace nana{ namespace widgets
|
||||
|
||||
void text_editor::show_caret(bool isshow)
|
||||
{
|
||||
if(isshow == false || API::is_focus_window(window_))
|
||||
if(isshow == false || API::is_focus_ready(window_))
|
||||
API::caret_visible(window_, isshow);
|
||||
}
|
||||
|
||||
@@ -1883,7 +1924,7 @@ namespace nana{ namespace widgets
|
||||
{
|
||||
behavior_->adjust_caret_into_screen();
|
||||
reset_caret();
|
||||
render(API::is_focus_window(window_));
|
||||
render(API::is_focus_ready(window_));
|
||||
_m_scrollbar();
|
||||
|
||||
points_.xpos = points_.caret.x;
|
||||
@@ -2105,25 +2146,6 @@ namespace nana{ namespace widgets
|
||||
|
||||
}
|
||||
|
||||
bool text_editor::move(nana::char_t key)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case keyboard::os_arrow_left: move_left(); break;
|
||||
case keyboard::os_arrow_right: move_right(); break;
|
||||
case keyboard::os_arrow_up: move_ns(true); break;
|
||||
case keyboard::os_arrow_down: move_ns(false); break;
|
||||
case keyboard::os_del:
|
||||
if (this->attr().editable)
|
||||
del();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void text_editor::move_ns(bool to_north)
|
||||
{
|
||||
const bool redraw_required = _m_cancel_select(0);
|
||||
@@ -2528,7 +2550,7 @@ namespace nana{ namespace widgets
|
||||
|
||||
//The number of new lines minus one
|
||||
const auto chp_end = text.data() + (begin == text.npos ? text.size() : begin);
|
||||
for (auto chp = text.data() + (pos + 2); chp != chp_end; ++chp)
|
||||
for (auto chp = text.data() + (pos + 1); chp != chp_end; ++chp)
|
||||
if (*chp == '\n')
|
||||
lines.emplace_back(0, 0);
|
||||
|
||||
@@ -2764,18 +2786,17 @@ namespace nana{ namespace widgets
|
||||
}
|
||||
}
|
||||
|
||||
void text_editor::_m_draw_string(int top, const ::nana::color& clr, const nana::upoint& str_pos, const nana::string& linestr, bool if_mask) const
|
||||
void text_editor::_m_draw_string(int top, const ::nana::color& clr, const nana::upoint& str_pos, const nana::string& str, bool if_mask) const
|
||||
{
|
||||
::nana::point text_pos{ text_area_.area.x - points_.offset.x, top };
|
||||
const int xend = text_area_.area.x + static_cast<int>(text_area_.area.width);
|
||||
|
||||
std::unique_ptr<nana::string> mask_str;
|
||||
if (if_mask && mask_char_)
|
||||
{
|
||||
nana::string maskstr;
|
||||
maskstr.append(linestr.size(), mask_char_);
|
||||
graph_.string(text_pos, maskstr, clr);
|
||||
return;
|
||||
}
|
||||
mask_str.reset(new nana::string(str.size(), mask_char_));
|
||||
|
||||
|
||||
auto & linestr = (if_mask && mask_char_ ? *mask_str : str);
|
||||
|
||||
unicode_bidi bidi;
|
||||
std::vector<unicode_bidi::entity> reordered;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <nana/gui/widgets/skeletons/text_editor.hpp>
|
||||
#include <nana/gui/element.hpp>
|
||||
#include <nana/gui/timer.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
@@ -328,7 +329,7 @@ namespace nana
|
||||
|
||||
void render()
|
||||
{
|
||||
editor_->render(API::is_focus_window(editor_->window_handle()));
|
||||
editor_->render(API::is_focus_ready(editor_->window_handle()));
|
||||
_m_draw_spins(spin_stated_);
|
||||
}
|
||||
|
||||
@@ -420,7 +421,7 @@ namespace nana
|
||||
if (!editor_)
|
||||
return;
|
||||
|
||||
if (API::is_focus_window(editor_->window_handle()))
|
||||
if (API::is_focus_ready(editor_->window_handle()))
|
||||
editor_->text(range_->value());
|
||||
else
|
||||
editor_->text(modifier_.prefix + range_->value() + modifier_.suffix);
|
||||
@@ -559,7 +560,7 @@ namespace nana
|
||||
|
||||
void drawer::key_press(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
if (impl_->editor()->move(arg.key))
|
||||
if (impl_->editor()->respond_key(arg.key))
|
||||
{
|
||||
impl_->editor()->reset_caret();
|
||||
impl_->draw_spins();
|
||||
@@ -569,7 +570,7 @@ namespace nana
|
||||
|
||||
void drawer::key_char(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
if (impl_->editor()->respone_keyboard(arg.key))
|
||||
if (impl_->editor()->respond_char(arg.key))
|
||||
{
|
||||
if (!impl_->value(impl_->editor()->text()))
|
||||
impl_->draw_spins();
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace drawerbase {
|
||||
|
||||
void drawer::refresh(graph_reference graph)
|
||||
{
|
||||
editor_->render(API::is_focus_window(*widget_));
|
||||
editor_->render(API::is_focus_ready(*widget_));
|
||||
}
|
||||
|
||||
void drawer::focus(graph_reference graph, const arg_focus& arg)
|
||||
@@ -136,7 +136,7 @@ namespace drawerbase {
|
||||
|
||||
void drawer::key_press(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
if(editor_->move(arg.key))
|
||||
if(editor_->respond_key(arg.key))
|
||||
{
|
||||
editor_->reset_caret();
|
||||
API::lazy_refresh();
|
||||
@@ -145,7 +145,7 @@ namespace drawerbase {
|
||||
|
||||
void drawer::key_char(graph_reference, const arg_keyboard& arg)
|
||||
{
|
||||
if (editor_->respone_keyboard(arg.key))
|
||||
if (editor_->respond_char(arg.key))
|
||||
API::lazy_refresh();
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ namespace drawerbase {
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if (editor->line_wrapped(autl))
|
||||
editor->render(API::is_focus_window(handle()));
|
||||
API::update_window(handle());
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -389,7 +389,7 @@ namespace drawerbase {
|
||||
internal_scope_guard lock;
|
||||
auto editor = get_drawer_trigger().editor();
|
||||
if(editor && editor->select(yes))
|
||||
API::refresh_window(*this);
|
||||
API::update_window(*this);
|
||||
}
|
||||
|
||||
void textbox::copy() const
|
||||
@@ -407,7 +407,7 @@ namespace drawerbase {
|
||||
if(editor)
|
||||
{
|
||||
editor->paste();
|
||||
API::refresh_window(*this);
|
||||
API::update_window(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace nana
|
||||
|
||||
bool widget::focused() const
|
||||
{
|
||||
return API::is_focus_window(handle());
|
||||
return (API::focus_window() == handle());
|
||||
}
|
||||
|
||||
void widget::show()
|
||||
|
||||
Reference in New Issue
Block a user