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:
Jinhao
2015-05-03 03:08:26 +08:00
81 changed files with 2639 additions and 1737 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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 });

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -101,7 +101,7 @@ namespace nana
bool widget::focused() const
{
return API::is_focus_window(handle());
return (API::focus_window() == handle());
}
void widget::show()