Merge branch 'feature-keyboard-accelerator' into develop
This commit is contained in:
commit
90b5f17169
@ -131,7 +131,7 @@ endif(APPLE)
|
||||
|
||||
if(UNIX)
|
||||
list(APPEND NANA_LINKS -lX11)
|
||||
find_package(Freetype)
|
||||
include(FindFreetype)
|
||||
if (FREETYPE_FOUND)
|
||||
include_directories( ${FREETYPE_INCLUDE_DIRS})
|
||||
list(APPEND NANA_LINKS -lXft)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Predefined Symbols for C++
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2016-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2016-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -171,9 +171,9 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Assume the std::thread is not implement on MinGW
|
||||
//Assume the std::thread is not implemented on MinGW,
|
||||
//unless it was compiled with POSIX threading support.
|
||||
//But some toolchains may implement std::thread.
|
||||
// it seems that MinGW 6.3 and 7.1 have std::thread
|
||||
#ifdef NANA_MINGW
|
||||
# ifndef STD_THREAD_NOT_SUPPORTED
|
||||
# define STD_THREAD_NOT_SUPPORTED
|
||||
@ -221,8 +221,11 @@
|
||||
# if __has_include(<filesystem>)
|
||||
# undef STD_FILESYSTEM_NOT_SUPPORTED
|
||||
# endif
|
||||
# if __has_include(<mutex>)
|
||||
# undef STD_THREAD_NOT_SUPPORTED
|
||||
# if __has_include(<mutex>)
|
||||
# if !(defined(NANA_MINGW) && !defined(_GLIBCXX_HAS_GTHREADS))
|
||||
//See the comment above regarding MinGW's threading support
|
||||
# undef STD_THREAD_NOT_SUPPORTED
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A ISO C++ filesystem Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -72,13 +72,12 @@ namespace boost
|
||||
// begin() and end() are only used by a range-based for statement in the context of
|
||||
// auto - thus the top-level const is stripped - so returning const is harmless and
|
||||
// emphasizes begin() is just a pass through.
|
||||
inline
|
||||
const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT
|
||||
inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
inline
|
||||
directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT
|
||||
|
||||
inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT
|
||||
{
|
||||
return directory_iterator();
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -18,7 +18,6 @@
|
||||
#include <nana/filesystem/filesystem.hpp>
|
||||
#include <nana/deploy.hpp>
|
||||
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace filesystem_ext
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Basis Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -30,6 +30,15 @@ namespace nana
|
||||
struct native_drawable_impl{};
|
||||
}
|
||||
|
||||
struct accel_key
|
||||
{
|
||||
char key;
|
||||
bool case_sensitive{ false };
|
||||
bool alt{ false };
|
||||
bool ctrl{ false };
|
||||
bool shift{ false };
|
||||
};
|
||||
|
||||
enum class checkstate
|
||||
{
|
||||
unchecked, checked, partial
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Bedrock Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -27,6 +27,7 @@ namespace detail
|
||||
struct basic_window;
|
||||
class window_manager;
|
||||
|
||||
struct window_platform_assoc;
|
||||
|
||||
/// @brief fundamental core component, it provides an abstraction to the OS platform and some basic functions.
|
||||
class bedrock
|
||||
@ -73,6 +74,11 @@ namespace detail
|
||||
|
||||
//Closes the windows which are associated with the specified thread. If the given thread_id is 0, it closes all windows
|
||||
void close_thread_window(unsigned thread_id);
|
||||
|
||||
public:
|
||||
//Platform-dependent functions
|
||||
static void delete_platform_assoc(window_platform_assoc*);
|
||||
void keyboard_accelerator(native_window_type, const accel_key&, const std::function<void()>&);
|
||||
public:
|
||||
void event_expose(core_window_t *, bool exposed);
|
||||
void event_move(core_window_t*, int x, int y);
|
||||
|
||||
@ -1,3 +1,15 @@
|
||||
/*
|
||||
* Effects Renderer
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 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/detail/effects_renderer.cpp
|
||||
*/
|
||||
|
||||
#ifndef NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP
|
||||
#define NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP
|
||||
#include <nana/gui/effects.hpp>
|
||||
@ -76,7 +88,7 @@ namespace nana{
|
||||
nana::rectangle r;
|
||||
for(auto & action : nimbus)
|
||||
{
|
||||
if(_m_edge_nimbus(focused, action.window) && window_layer::read_visual_rectangle(action.window, r))
|
||||
if(_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r))
|
||||
{
|
||||
if (action.window == wd)
|
||||
{
|
||||
@ -140,12 +152,17 @@ namespace nana{
|
||||
}
|
||||
}
|
||||
private:
|
||||
static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd)
|
||||
/// Determines whether the effect will be rendered for the given window.
|
||||
static bool _m_edge_nimbus(core_window_t * const wd, core_window_t * const focused_wd)
|
||||
{
|
||||
if((focused_wd == wd) && (static_cast<unsigned>(wd->effect.edge_nimbus) & static_cast<unsigned>(effects::edge_nimbus::active)))
|
||||
return true;
|
||||
else if((static_cast<unsigned>(wd->effect.edge_nimbus) & static_cast<unsigned>(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered))
|
||||
return true;
|
||||
// Don't render the effect if the window is disabled.
|
||||
if (wd->flags.enabled)
|
||||
{
|
||||
if ((focused_wd == wd) && (static_cast<unsigned>(wd->effect.edge_nimbus) & static_cast<unsigned>(effects::edge_nimbus::active)))
|
||||
return true;
|
||||
else if ((static_cast<unsigned>(wd->effect.edge_nimbus) & static_cast<unsigned>(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Definition of General Events
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -460,8 +460,9 @@ namespace nana
|
||||
::nana::window window_handle; ///< A handle to the event window
|
||||
mutable wchar_t key; ///< the key corresponding to the key pressed
|
||||
mutable bool ignore; ///< this member is only available for key_char event, set 'true' to ignore the input.
|
||||
bool ctrl; ///< keyboard Ctrl is pressed?
|
||||
bool shift; ///< keyboard Shift is pressed
|
||||
bool alt; ///< it is set to indicate the modifier key Alt just prior to the event.
|
||||
bool ctrl; ///< it is set to indicate the modifier key Ctrl just prior to the event.
|
||||
bool shift; ///< it is set to indicate the modifier key Shift just prior to the event.
|
||||
};
|
||||
|
||||
struct arg_move : public event_arg
|
||||
|
||||
@ -301,6 +301,8 @@ namespace API
|
||||
void window_size(window, const size&);
|
||||
size window_outline_size(window);
|
||||
void window_outline_size(window, const size&);
|
||||
|
||||
nana::optional<rectangle> window_rectangle(window);
|
||||
bool get_window_rectangle(window, rectangle&);
|
||||
bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window.
|
||||
void window_enabled(window, bool);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Form Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -68,6 +68,8 @@ namespace nana
|
||||
|
||||
void modality() const;
|
||||
void wait_for_this();
|
||||
|
||||
void keyboard_accelerator(const accel_key&, const std::function<void()>& fn);
|
||||
};
|
||||
|
||||
class nested_form
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A List Box Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Scroll Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -147,7 +147,7 @@ namespace nana
|
||||
|
||||
void step(size_type s)
|
||||
{
|
||||
metrics_.step = s;
|
||||
metrics_.step = (s ? s : 1);
|
||||
}
|
||||
|
||||
bool make_step(bool forward, unsigned multiple)
|
||||
@ -398,7 +398,7 @@ namespace nana
|
||||
/// \brief The construct that creates a widget.
|
||||
/// @param wd A handle to the parent window of the widget being created.
|
||||
/// @param visible specify the visibility after creation.
|
||||
scroll(window wd, bool visible)
|
||||
scroll(window wd, bool visible = true)
|
||||
{
|
||||
this->create(wd, rectangle(), visible); // add a widget scheme? and take some colors from these wd?
|
||||
}
|
||||
@ -501,7 +501,8 @@ namespace nana
|
||||
/// @return true if the vlaue is changed.
|
||||
bool make_page_scroll(bool forward)
|
||||
{
|
||||
return this->make_step(forward, static_cast<unsigned>(range() - 1));
|
||||
auto const count = range() / step();
|
||||
return this->make_step(forward, (count > 2 ? count - 1 : 1));
|
||||
}
|
||||
};//end class scroll
|
||||
}//end namespace nana
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Tabbar implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -42,9 +42,8 @@ namespace nana
|
||||
: arg_tabbar<T>({wdg, v})
|
||||
{}
|
||||
|
||||
bool remove = true; ///< determines whether to remove the item
|
||||
bool close_attach_window = true; ///< determines whether to close the attached window. It is ignored if remove is false
|
||||
|
||||
mutable bool remove = true; ///< determines whether to remove the item
|
||||
mutable bool close_attach_window = true; ///< determines whether to close the attached window. It is ignored if remove is false
|
||||
};
|
||||
|
||||
namespace drawerbase
|
||||
@ -293,7 +292,7 @@ namespace nana
|
||||
if (pos > length())
|
||||
throw std::out_of_range("tabbar::insert invalid position");
|
||||
|
||||
this->get_drawer_trigger().insert(pos, to_nstring(text), std::move(value));
|
||||
this->get_drawer_trigger().insert(pos, to_nstring(std::move(text)), std::move(value));
|
||||
API::update_window(*this);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Bedrock Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -15,10 +15,10 @@
|
||||
#include <nana/gui/detail/bedrock_pi_data.hpp>
|
||||
#include <nana/gui/detail/event_code.hpp>
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <nana/gui/detail/inner_fwd_implement.hpp>
|
||||
#include <nana/gui/detail/native_window_interface.hpp>
|
||||
#include <nana/gui/layout_utility.hpp>
|
||||
#include <nana/gui/detail/element_store.hpp>
|
||||
#include "inner_fwd_implement.hpp"
|
||||
#include <errno.h>
|
||||
#include <algorithm>
|
||||
|
||||
@ -104,6 +104,42 @@ namespace detail
|
||||
void window_proc_for_packet(Display *, nana::detail::msg_packet_tag&);
|
||||
void window_proc_for_xevent(Display*, XEvent&);
|
||||
|
||||
class accel_key_comparer
|
||||
{
|
||||
public:
|
||||
bool operator()(const accel_key& a, const accel_key& b) const
|
||||
{
|
||||
auto va = a.case_sensitive ? a.key : std::tolower(a.key);
|
||||
auto vb = b.case_sensitive ? b.key : std::tolower(b.key);
|
||||
|
||||
if(va < vb)
|
||||
return true;
|
||||
else if(va > vb)
|
||||
return false;
|
||||
|
||||
if (a.case_sensitive != b.case_sensitive)
|
||||
return b.case_sensitive;
|
||||
|
||||
if (a.alt != b.alt)
|
||||
return b.alt;
|
||||
|
||||
if (a.ctrl != b.ctrl)
|
||||
return b.ctrl;
|
||||
|
||||
return ((a.shift != b.shift) && b.shift);
|
||||
}
|
||||
};
|
||||
|
||||
struct accel_key_value
|
||||
{
|
||||
std::function<void()> command;
|
||||
};
|
||||
|
||||
struct window_platform_assoc
|
||||
{
|
||||
std::map<accel_key, accel_key_value, accel_key_comparer> accel_commands;
|
||||
};
|
||||
|
||||
//class bedrock defines a static object itself to implement a static singleton
|
||||
//here is the definition of this object
|
||||
bedrock bedrock::bedrock_object;
|
||||
@ -218,10 +254,28 @@ namespace detail
|
||||
{
|
||||
XKeyEvent xkey;
|
||||
nana::detail::platform_spec::instance().read_keystate(xkey);
|
||||
arg.alt = (xkey.state & Mod1Mask);
|
||||
arg.ctrl = (xkey.state & ControlMask);
|
||||
arg.shift = (xkey.state & ShiftMask);
|
||||
}
|
||||
|
||||
void bedrock::delete_platform_assoc(window_platform_assoc* passoc)
|
||||
{
|
||||
delete passoc;
|
||||
}
|
||||
|
||||
void bedrock::keyboard_accelerator(native_window_type wd, const accel_key& ackey, const std::function<void()>& fn)
|
||||
{
|
||||
auto misc = wd_manager().root_runtime(wd);
|
||||
if (nullptr == misc)
|
||||
return;
|
||||
|
||||
if (!misc->wpassoc)
|
||||
misc->wpassoc = new window_platform_assoc;
|
||||
|
||||
misc->wpassoc->accel_commands[ackey].command = fn;
|
||||
}
|
||||
|
||||
element_store& bedrock::get_element_store() const
|
||||
{
|
||||
return impl_->estore;
|
||||
@ -490,6 +544,34 @@ namespace detail
|
||||
return wchar_t(keysym);
|
||||
}
|
||||
|
||||
bool translate_keyboard_accelerator(root_misc* misc, char os_code, const arg_keyboard& modifiers)
|
||||
{
|
||||
if(!misc->wpassoc)
|
||||
return false;
|
||||
|
||||
auto lower_oc = std::tolower(os_code);
|
||||
|
||||
std::function<void()> command;
|
||||
|
||||
for(auto & accel : misc->wpassoc->accel_commands)
|
||||
{
|
||||
if(accel.first.key != (accel.first.case_sensitive ? os_code : lower_oc))
|
||||
continue;
|
||||
|
||||
if(accel.first.alt == modifiers.alt && accel.first.ctrl == modifiers.ctrl && accel.first.shift == modifiers.shift)
|
||||
{
|
||||
command = accel.second.command;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!command)
|
||||
return false;
|
||||
|
||||
command();
|
||||
return true;
|
||||
}
|
||||
|
||||
void window_proc_for_xevent(Display* /*display*/, XEvent& xevent)
|
||||
{
|
||||
typedef detail::bedrock::core_window_t core_window_t;
|
||||
@ -849,6 +931,9 @@ namespace detail
|
||||
|
||||
if(msgwnd)
|
||||
{
|
||||
arg_keyboard modifiers_status;
|
||||
brock.get_key_state(modifiers_status);
|
||||
|
||||
KeySym keysym;
|
||||
Status status;
|
||||
char fixbuf[33];
|
||||
@ -883,16 +968,20 @@ namespace detail
|
||||
|
||||
keybuf[len] = 0;
|
||||
wchar_t os_code = 0;
|
||||
bool accel_translated = false;
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case XLookupKeySym:
|
||||
case XLookupBoth:
|
||||
os_code = os_code_from_keysym(keysym);
|
||||
accel_translated = translate_keyboard_accelerator(root_runtime, os_code, modifiers_status);
|
||||
if(accel_translated)
|
||||
break;
|
||||
|
||||
if(os_code == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab
|
||||
{
|
||||
arg_keyboard argkey;
|
||||
brock.get_key_state(argkey);
|
||||
auto tstop_wd = wd_manager.tabstop(msgwnd, !argkey.shift);
|
||||
auto tstop_wd = wd_manager.tabstop(msgwnd, !modifiers_status.shift);
|
||||
if (tstop_wd)
|
||||
{
|
||||
root_runtime->condition.ignore_tab = true;
|
||||
@ -907,9 +996,9 @@ namespace detail
|
||||
if((nullptr == pressed_wd) && (nullptr == pressed_wd_space))
|
||||
{
|
||||
arg_mouse arg;
|
||||
arg.alt = false;
|
||||
arg.alt = modifiers_status.alt;
|
||||
arg.button = ::nana::mouse::left_button;
|
||||
arg.ctrl = false;
|
||||
arg.ctrl = modifiers_status.ctrl;
|
||||
arg.evt_code = event_code::mouse_down;
|
||||
arg.left_button = true;
|
||||
arg.mid_button = false;
|
||||
@ -955,11 +1044,10 @@ namespace detail
|
||||
if(keyboard::os_ctrl == os_code)
|
||||
context.is_ctrl_pressed = true;
|
||||
|
||||
arg_keyboard arg;
|
||||
arg_keyboard arg = modifiers_status;
|
||||
arg.ignore = false;
|
||||
arg.key = os_code;
|
||||
arg.evt_code = event_code::key_press;
|
||||
brock.get_key_state(arg);
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
|
||||
brock.emit(event_code::key_press, msgwnd, arg, true, &context);
|
||||
@ -988,7 +1076,7 @@ namespace detail
|
||||
|
||||
for(int i = 0; i < len; ++i)
|
||||
{
|
||||
arg_keyboard arg;
|
||||
arg_keyboard arg = modifiers_status;
|
||||
arg.ignore = false;
|
||||
arg.key = charbuf[i];
|
||||
|
||||
@ -1011,7 +1099,6 @@ namespace detail
|
||||
}
|
||||
arg.evt_code = event_code::key_char;
|
||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
||||
brock.get_key_state(arg);
|
||||
msgwnd->annex.events_ptr->key_char.emit(arg, reinterpret_cast<window>(msgwnd));
|
||||
if(arg.ignore == false && wd_manager.available(msgwnd))
|
||||
draw_invoker(&drawer::key_char, msgwnd, arg, &context);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Bedrock Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -20,11 +20,11 @@
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <nana/system/timepiece.hpp>
|
||||
#include <nana/gui.hpp>
|
||||
#include <nana/gui/detail/inner_fwd_implement.hpp>
|
||||
#include <nana/gui/detail/native_window_interface.hpp>
|
||||
#include <nana/gui/layout_utility.hpp>
|
||||
#include <nana/gui/detail/element_store.hpp>
|
||||
#include <nana/gui/detail/color_schemes.hpp>
|
||||
#include "inner_fwd_implement.hpp"
|
||||
|
||||
#include <iostream> //use std::cerr
|
||||
|
||||
@ -182,6 +182,12 @@ namespace detail
|
||||
}cache;
|
||||
};
|
||||
|
||||
struct window_platform_assoc
|
||||
{
|
||||
HACCEL accel{ nullptr }; ///< A handle to a Windows keyboard accelerator object.
|
||||
std::map<int, std::function<void()>> accel_commands;
|
||||
};
|
||||
|
||||
//class bedrock defines a static object itself to implement a static singleton
|
||||
//here is the definition of this object
|
||||
bedrock bedrock::bedrock_object;
|
||||
@ -345,6 +351,25 @@ namespace detail
|
||||
}
|
||||
}
|
||||
|
||||
void process_msg(bedrock* brock, MSG& msg)
|
||||
{
|
||||
if (WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST)
|
||||
{
|
||||
auto misc = brock->wd_manager().root_runtime(reinterpret_cast<native_window_type>(msg.hwnd));
|
||||
if (misc && misc->wpassoc && misc->wpassoc->accel)
|
||||
{
|
||||
if (::TranslateAccelerator(msg.hwnd, misc->wpassoc->accel, &msg))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto menu_wd = brock->get_menu(reinterpret_cast<native_window_type>(msg.hwnd), true);
|
||||
if (menu_wd) interior_helper_for_menu(msg, menu_wd);
|
||||
|
||||
::TranslateMessage(&msg);
|
||||
::DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
void bedrock::pump_event(window condition_wd, bool is_modal)
|
||||
{
|
||||
const unsigned tid = ::GetCurrentThreadId();
|
||||
@ -383,11 +408,15 @@ namespace detail
|
||||
if (msg.message == WM_QUIT) break;
|
||||
if ((WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST) || !::IsDialogMessage(native_handle, &msg))
|
||||
{
|
||||
#if 0
|
||||
auto menu_wd = get_menu(reinterpret_cast<native_window_type>(msg.hwnd), true);
|
||||
if (menu_wd) interior_helper_for_menu(msg, menu_wd);
|
||||
|
||||
::TranslateMessage(&msg);
|
||||
::TranslateMessage(&msg); //deprecated
|
||||
::DispatchMessage(&msg);
|
||||
#else
|
||||
process_msg(this, msg);
|
||||
#endif
|
||||
|
||||
wd_manager().remove_trash_handle(tid);
|
||||
}
|
||||
@ -400,11 +429,15 @@ namespace detail
|
||||
{
|
||||
if (-1 != ::GetMessage(&msg, 0, 0, 0))
|
||||
{
|
||||
#if 0
|
||||
auto menu_wd = get_menu(reinterpret_cast<native_window_type>(msg.hwnd), true);
|
||||
if (menu_wd) interior_helper_for_menu(msg, menu_wd);
|
||||
|
||||
::TranslateMessage(&msg);
|
||||
::DispatchMessage(&msg);
|
||||
#else
|
||||
process_msg(this, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
wd_manager().call_safe_place(tid);
|
||||
@ -420,11 +453,15 @@ namespace detail
|
||||
{
|
||||
if(-1 != ::GetMessage(&msg, 0, 0, 0))
|
||||
{
|
||||
#if 0
|
||||
auto menu_wd = get_menu(reinterpret_cast<native_window_type>(msg.hwnd), true);
|
||||
if(menu_wd) interior_helper_for_menu(msg, menu_wd);
|
||||
|
||||
::TranslateMessage(&msg);
|
||||
::DispatchMessage(&msg);
|
||||
#else
|
||||
process_msg(this, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
wd_manager().call_safe_place(tid);
|
||||
@ -635,6 +672,7 @@ namespace detail
|
||||
|
||||
switch(msg)
|
||||
{
|
||||
case WM_COMMAND:
|
||||
case WM_DESTROY:
|
||||
case WM_SHOWWINDOW:
|
||||
case WM_SIZING:
|
||||
@ -786,6 +824,17 @@ namespace detail
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_COMMAND:
|
||||
if ((1 == HIWORD(wParam)) && root_runtime->wpassoc)
|
||||
{
|
||||
auto i = root_runtime->wpassoc->accel_commands.find(LOWORD(wParam));
|
||||
if (i != root_runtime->wpassoc->accel_commands.end())
|
||||
{
|
||||
auto fn = i->second;
|
||||
fn();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
if (msgwnd->other.attribute.root->ime_enabled)
|
||||
{
|
||||
@ -1578,10 +1627,58 @@ namespace detail
|
||||
|
||||
void bedrock::get_key_state(arg_keyboard& kb)
|
||||
{
|
||||
kb.alt = (0 != (::GetKeyState(VK_MENU) & 0x80));
|
||||
kb.ctrl = (0 != (::GetKeyState(VK_CONTROL) & 0x80));
|
||||
kb.shift = (0 != (::GetKeyState(VK_SHIFT) & 0x80));
|
||||
}
|
||||
|
||||
void bedrock::delete_platform_assoc(window_platform_assoc* passoc)
|
||||
{
|
||||
delete passoc;
|
||||
}
|
||||
|
||||
//Generates an identitifer for an accel key.
|
||||
std::pair<int, WORD> id_accel_key(const accel_key& key)
|
||||
{
|
||||
std::pair<int, WORD> ret;
|
||||
|
||||
//Use virt-key for non-case sensitive
|
||||
if (!key.case_sensitive)
|
||||
ret.second = static_cast<WORD>(std::tolower(key.key) - 'a' + 0x41);
|
||||
|
||||
ret.first = ret.second | int(key.case_sensitive ? (1 << 8) : 0) | int(key.alt ? (1 << 9) : 0) | int(key.ctrl ? (1 << 10) : 0) | int(key.shift ? (1 << 11) : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bedrock::keyboard_accelerator(native_window_type wd, const accel_key& key, const std::function<void()>& fn)
|
||||
{
|
||||
auto misc = wd_manager().root_runtime(wd);
|
||||
if (nullptr == misc)
|
||||
return;
|
||||
|
||||
if (!misc->wpassoc)
|
||||
misc->wpassoc = new window_platform_assoc;
|
||||
|
||||
auto idkey = id_accel_key(key);
|
||||
|
||||
misc->wpassoc->accel_commands[idkey.first] = fn;
|
||||
|
||||
auto accel_size = ::CopyAcceleratorTable(misc->wpassoc->accel, nullptr, 0);
|
||||
|
||||
std::unique_ptr<ACCEL[]> accels(new ACCEL[accel_size + 1]);
|
||||
|
||||
if (accel_size)
|
||||
::CopyAcceleratorTable(misc->wpassoc->accel, accels.get(), accel_size);
|
||||
|
||||
auto p = accels.get() + accel_size;
|
||||
p->cmd = idkey.first;
|
||||
p->fVirt = (key.case_sensitive ? 0 : FVIRTKEY) | (key.alt ? FALT : 0) | (key.ctrl ? FCONTROL : 0) | (key.shift ? FSHIFT : 0);
|
||||
p->key = idkey.second;
|
||||
|
||||
::DestroyAcceleratorTable(misc->wpassoc->accel);
|
||||
misc->wpassoc->accel = ::CreateAcceleratorTable(accels.get(), accel_size + 1);
|
||||
}
|
||||
|
||||
element_store& bedrock::get_element_store() const
|
||||
{
|
||||
return impl_->estore;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Implementations of Inner Forward Declaration
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -15,9 +15,9 @@
|
||||
#define NANA_GUI_INNER_FWD_IMPLEMENT_HPP
|
||||
|
||||
#include <nana/push_ignore_diagnostic>
|
||||
#include "inner_fwd.hpp"
|
||||
#include "basic_window.hpp"
|
||||
#include "../../paint/graphics.hpp"
|
||||
#include <nana/gui/detail/inner_fwd.hpp>
|
||||
#include <nana/gui/detail/basic_window.hpp>
|
||||
#include <nana/paint/graphics.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
@ -54,10 +54,13 @@ namespace nana{
|
||||
implementation * impl_;
|
||||
};
|
||||
|
||||
struct window_platform_assoc;
|
||||
|
||||
struct root_misc
|
||||
{
|
||||
basic_window * window;
|
||||
window_platform_assoc * wpassoc{ nullptr };
|
||||
|
||||
nana::paint::graphics root_graph;
|
||||
shortkey_container shortkeys;
|
||||
|
||||
@ -71,6 +74,10 @@ namespace nana{
|
||||
|
||||
root_misc(root_misc&&);
|
||||
root_misc(basic_window * wd, unsigned width, unsigned height);
|
||||
~root_misc();
|
||||
private:
|
||||
root_misc(const root_misc&) = delete;
|
||||
root_misc& operator=(const root_misc&) = delete;
|
||||
};//end struct root_misc
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Window Layout Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -106,43 +106,46 @@ namespace nana
|
||||
|
||||
visual = rectangle{ wd->pos_root, wd->dimension };
|
||||
|
||||
if (wd->root_widget != wd)
|
||||
if (category::flags::root != wd->other.category)
|
||||
{
|
||||
//Test if the root widget is overlapped the specified widget
|
||||
//the pos of root widget is (0, 0)
|
||||
if (overlapped(visual, rectangle{ wd->root_widget->pos_owner, wd->root_widget->dimension }) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto parent = wd->parent; parent; parent = parent->parent)
|
||||
{
|
||||
if (category::flags::root == parent->other.category)
|
||||
for (auto parent = wd->parent; parent; parent = parent->parent)
|
||||
{
|
||||
//visual rectangle of wd's parent
|
||||
rectangle vrt_parent{parent->pos_root, parent->dimension};
|
||||
|
||||
point pos_root;
|
||||
while (parent->parent)
|
||||
if (category::flags::root == parent->other.category)
|
||||
{
|
||||
pos_root -= native_interface::window_position(parent->root);
|
||||
|
||||
if (!overlap(rectangle{ pos_root, parent->parent->root_widget->dimension }, vrt_parent, vrt_parent))
|
||||
return false;
|
||||
|
||||
parent = parent->parent->root_widget;
|
||||
wd = parent;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!overlap(vrt_parent, visual, visual))
|
||||
if (!overlap(rectangle{ parent->pos_root, parent->dimension }, visual, visual))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!overlap(rectangle{ parent->pos_root, parent->dimension }, visual, visual))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
//Now, wd actually is the root widget of original parameter wd
|
||||
if (nullptr == wd->parent)
|
||||
return true;
|
||||
|
||||
auto parent_rw = wd->parent->root_widget;
|
||||
//visual rectangle of wd's parent
|
||||
rectangle vrt_parent{ parent_rw->pos_root, parent_rw->dimension };
|
||||
|
||||
point pos_root;
|
||||
while (parent_rw->parent)
|
||||
{
|
||||
pos_root -= native_interface::window_position(parent_rw->root);
|
||||
|
||||
if (!overlap(rectangle{ pos_root, parent_rw->parent->root_widget->dimension }, vrt_parent, vrt_parent))
|
||||
return false;
|
||||
|
||||
parent_rw = parent_rw->parent->root_widget;
|
||||
}
|
||||
|
||||
return overlap(vrt_parent, visual, visual);
|
||||
}
|
||||
|
||||
//read_overlaps
|
||||
@ -386,6 +389,13 @@ namespace nana
|
||||
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
|
||||
for (auto wd : data_sect.effects_bground_windows)
|
||||
{
|
||||
//Don't notify the window if both native root windows are not same(e.g. wd and sigwd have
|
||||
//a some parent). Otherwise, _m_paint_glass_window() recursively paints sigwd to make stack overflow.
|
||||
//On the other hand, a nested root window is always floating on its parent's child widgets, it's unnecessary to
|
||||
//notify the wd if they haven't a same native root window.
|
||||
if (sigwd->root != wd->root)
|
||||
continue;
|
||||
|
||||
if (wd == sigwd || !wd->displayed() ||
|
||||
(false == overlapped(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd)))
|
||||
continue;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Window Manager Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -16,11 +16,11 @@
|
||||
#include <nana/gui/detail/events_operation.hpp>
|
||||
#include <nana/gui/detail/window_manager.hpp>
|
||||
#include <nana/gui/detail/window_layout.hpp>
|
||||
#include "window_register.hpp"
|
||||
#include <nana/gui/detail/native_window_interface.hpp>
|
||||
#include <nana/gui/detail/inner_fwd_implement.hpp>
|
||||
#include <nana/gui/layout_utility.hpp>
|
||||
#include <nana/gui/detail/effects_renderer.hpp>
|
||||
#include "window_register.hpp"
|
||||
#include "inner_fwd_implement.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
@ -140,10 +140,12 @@ namespace nana
|
||||
//struct root_misc
|
||||
root_misc::root_misc(root_misc&& other):
|
||||
window(other.window),
|
||||
wpassoc(other.wpassoc),
|
||||
root_graph(std::move(other.root_graph)),
|
||||
shortkeys(std::move(other.shortkeys)),
|
||||
condition(std::move(other.condition))
|
||||
{
|
||||
other.wpassoc = nullptr; //moved-from
|
||||
}
|
||||
|
||||
root_misc::root_misc(basic_window * wd, unsigned width, unsigned height)
|
||||
@ -155,6 +157,11 @@ namespace nana
|
||||
condition.pressed_by_space = nullptr;
|
||||
condition.hovered = nullptr;
|
||||
}
|
||||
|
||||
root_misc::~root_misc()
|
||||
{
|
||||
bedrock::delete_platform_assoc(wpassoc);
|
||||
}
|
||||
//end struct root_misc
|
||||
|
||||
//class root_register
|
||||
|
||||
@ -1041,7 +1041,8 @@ namespace nana
|
||||
bool filebox::show() const
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
std::wstring wfile;
|
||||
auto winitfile = to_wstring(impl_->file);
|
||||
std::wstring wfile(winitfile);
|
||||
wfile.resize(520);
|
||||
|
||||
OPENFILENAME ofn;
|
||||
|
||||
@ -821,6 +821,15 @@ namespace API
|
||||
}
|
||||
}
|
||||
|
||||
nana::optional<rectangle> window_rectangle(window wd)
|
||||
{
|
||||
auto iwd = reinterpret_cast<basic_window*>(wd);
|
||||
internal_scope_guard lock;
|
||||
if (restrict::wd_manager().available(iwd))
|
||||
return rectangle(iwd->pos_owner, iwd->dimension);
|
||||
return{};
|
||||
}
|
||||
|
||||
bool get_window_rectangle(window wd, rectangle& r)
|
||||
{
|
||||
auto iwd = reinterpret_cast<basic_window*>(wd);
|
||||
|
||||
@ -379,7 +379,7 @@ namespace nana{ namespace drawerbase
|
||||
}//end namespace drawerbase
|
||||
|
||||
//button
|
||||
//@brief: Defaine a button widget and it provides the interfaces to be operational
|
||||
//@brief: Define a button widget and it provides the interfaces to be operational
|
||||
button::button(){}
|
||||
|
||||
button::button(window wd, bool visible)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* A Form Implementation
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/form.hpp>
|
||||
#include <nana/gui/detail/bedrock.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
@ -94,6 +95,11 @@ namespace nana
|
||||
{
|
||||
API::wait_for(handle());
|
||||
}
|
||||
|
||||
void form::keyboard_accelerator(const accel_key& key, const std::function<void()>& fn)
|
||||
{
|
||||
nana::detail::bedrock::instance().keyboard_accelerator(this->native_handle(), key, fn);
|
||||
}
|
||||
//end class form
|
||||
|
||||
//class nested_form
|
||||
|
||||
@ -208,8 +208,8 @@ namespace nana{
|
||||
outter[field_title] << impl_->caption;
|
||||
outter.collocate();
|
||||
|
||||
impl_->caption.transparent(true);
|
||||
color pbg = API::bgcolor(this->parent());
|
||||
|
||||
impl_->caption.bgcolor(pbg.blend(colors::black, 0.025));
|
||||
|
||||
this->bgcolor(pbg.blend(colors::black, 0.05));
|
||||
@ -222,10 +222,27 @@ namespace nana{
|
||||
auto gap_px = impl_->gap - 1;
|
||||
|
||||
graph.rectangle(true, API::bgcolor(this->parent()));
|
||||
graph.round_rectangle(rectangle(point(gap_px, impl_->caption_dimension.height / 2),
|
||||
nana::size(graph.width() - 2 * gap_px, graph.height() - impl_->caption_dimension.height / 2 - gap_px)
|
||||
|
||||
auto const top_round_line = static_cast<int>(impl_->caption_dimension.height) / 2;
|
||||
|
||||
graph.round_rectangle(rectangle(point(gap_px, top_round_line),
|
||||
nana::size(graph.width() - 2 * gap_px, graph.height() - top_round_line - gap_px)
|
||||
),
|
||||
3, 3, colors::gray_border, true, this->bgcolor());
|
||||
|
||||
auto opt_r = API::window_rectangle(impl_->caption);
|
||||
if (opt_r)
|
||||
{
|
||||
rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width, static_cast<unsigned>(top_round_line - opt_r->y) } };
|
||||
|
||||
grad_r.y += top_round_line*2 / 3;
|
||||
grad_r.x -= 2;
|
||||
grad_r.width += 4;
|
||||
|
||||
graph.gradual_rectangle(grad_r,
|
||||
API::bgcolor(this->parent()), this->bgcolor(), true
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A List Box Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -1273,6 +1273,7 @@ namespace nana
|
||||
}
|
||||
|
||||
//Backward
|
||||
n = -n;
|
||||
dpos = pos;
|
||||
if (good(dpos.cat))
|
||||
{
|
||||
@ -1519,8 +1520,6 @@ namespace nana
|
||||
template<typename Pred>
|
||||
std::vector<std::pair<index_pair, bool>> select_display_range_if(const index_pair& fr_abs, index_pair to_dpl, bool deselect_others, Pred pred)
|
||||
{
|
||||
const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{});
|
||||
|
||||
if (to_dpl.empty())
|
||||
{
|
||||
if (fr_abs.empty())
|
||||
@ -1533,6 +1532,11 @@ namespace nana
|
||||
if (fr_dpl > to_dpl)
|
||||
std::swap(fr_dpl, to_dpl);
|
||||
|
||||
if (to_dpl.is_category() && this->size_item(to_dpl.cat) > 0)
|
||||
to_dpl.item = this->size_item(to_dpl.cat) - 1;
|
||||
|
||||
const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{});
|
||||
|
||||
const auto begin = fr_dpl;
|
||||
const auto last = to_dpl;
|
||||
|
||||
@ -1586,7 +1590,7 @@ namespace nana
|
||||
return pairs;
|
||||
}
|
||||
|
||||
bool select_for_all(bool sel, const index_pair& except = index_pair{npos, npos})
|
||||
bool select_for_all(bool sel, const index_pair& except_abs = index_pair{npos, npos})
|
||||
{
|
||||
bool changed = false;
|
||||
index_pair pos;
|
||||
@ -1595,7 +1599,7 @@ namespace nana
|
||||
pos.item = 0;
|
||||
for(auto & m : cat.items)
|
||||
{
|
||||
if (except != pos)
|
||||
if (except_abs != pos)
|
||||
{
|
||||
if (m.flags.selected != sel)
|
||||
{
|
||||
@ -1618,7 +1622,7 @@ namespace nana
|
||||
}
|
||||
|
||||
/// return absolute positions, no relative to display
|
||||
index_pairs pick_items(bool for_selection) const
|
||||
index_pairs pick_items(bool for_selection, bool find_first = false) const
|
||||
{
|
||||
index_pairs results;
|
||||
index_pair id;
|
||||
@ -1629,7 +1633,11 @@ namespace nana
|
||||
for (auto & m : cat.items)
|
||||
{
|
||||
if (for_selection ? m.flags.selected : m.flags.checked)
|
||||
{
|
||||
results.push_back(id); // absolute positions, no relative to display
|
||||
if (find_first)
|
||||
return results;
|
||||
}
|
||||
++id.item;
|
||||
}
|
||||
++id.cat;
|
||||
@ -1978,6 +1986,15 @@ namespace nana
|
||||
};
|
||||
}
|
||||
|
||||
bool cs_status(index_pair abs_pos, bool for_selection) const
|
||||
{
|
||||
if (abs_pos.is_category())
|
||||
return lister.cat_status(abs_pos.cat, for_selection);
|
||||
|
||||
auto & flags = lister.get(abs_pos.cat)->items.at(abs_pos.item).flags;
|
||||
return (for_selection ? flags.selected : flags.checked);
|
||||
}
|
||||
|
||||
void resize_disp_area()
|
||||
{
|
||||
auto head_px = this->header_visible_px();
|
||||
@ -3416,6 +3433,8 @@ namespace nana
|
||||
rect.y - static_cast<int>(origin.y % item_height_px)
|
||||
};
|
||||
|
||||
essence_->inline_buffered_table.swap(essence_->inline_table);
|
||||
|
||||
// The first display is empty when the listbox is empty.
|
||||
if (!first_disp.empty())
|
||||
{
|
||||
@ -3438,8 +3457,6 @@ namespace nana
|
||||
|
||||
auto idx = first_disp;
|
||||
|
||||
essence_->inline_buffered_table.swap(essence_->inline_table);
|
||||
|
||||
for (auto & cat : lister.cat_container())
|
||||
for (auto & ind : cat.indicators)
|
||||
{
|
||||
@ -3509,10 +3526,10 @@ namespace nana
|
||||
++idx.item;
|
||||
}
|
||||
}
|
||||
|
||||
essence_->inline_buffered_table.clear();
|
||||
}
|
||||
|
||||
essence_->inline_buffered_table.clear();
|
||||
|
||||
if (item_coord.y < rect.bottom())
|
||||
{
|
||||
rectangle bground_r{ rect.x, item_coord.y, rect.width, static_cast<unsigned>(rect.bottom() - item_coord.y) };
|
||||
@ -4117,17 +4134,16 @@ namespace nana
|
||||
essence_->content_view->sync(false);
|
||||
}
|
||||
|
||||
bool sel = true;
|
||||
bool new_selected_status = true;
|
||||
|
||||
//no single selected
|
||||
if (!lister.single_status(true))
|
||||
if (!lister.single_status(true)) //multiply selection enabled
|
||||
{
|
||||
if (arg.shift)
|
||||
{
|
||||
//Set the first item as the begin of selected item if there
|
||||
//is not a latest selected item.(#154 reported by RenaudAlpes)
|
||||
if (lister.latest_selected_abs.empty() || lister.latest_selected_abs.is_category())
|
||||
lister.latest_selected_abs.set_both(0);
|
||||
if (lister.latest_selected_abs.empty())
|
||||
lister.latest_selected_abs = lister.first();
|
||||
|
||||
auto before = lister.latest_selected_abs;
|
||||
|
||||
@ -4141,7 +4157,7 @@ namespace nana
|
||||
else if (arg.ctrl)
|
||||
{
|
||||
essence_->mouse_selection.reverse_selection = true;
|
||||
sel = !item_proxy(essence_, abs_item_pos).selected();
|
||||
new_selected_status = !essence_->cs_status(abs_item_pos, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -4150,12 +4166,12 @@ namespace nana
|
||||
//Unselects all selected items if the current item is not selected before selecting.
|
||||
auto selected = lister.pick_items(true);
|
||||
if (selected.cend() == std::find(selected.cbegin(), selected.cend(), item_pos))
|
||||
lister.select_for_all(false, item_pos);
|
||||
lister.select_for_all(false, abs_item_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Unselects all selected items except current item if right button clicked.
|
||||
lister.select_for_all(false, item_pos); //cancel all selections
|
||||
lister.select_for_all(false, abs_item_pos); //cancel all selections
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4164,14 +4180,14 @@ namespace nana
|
||||
//Clicking on a category is ignored when single selection is enabled.
|
||||
//Fixed by Greentwip(issue #121)
|
||||
if (item_ptr)
|
||||
sel = !item_proxy(essence_, abs_item_pos).selected();
|
||||
new_selected_status = !item_proxy(essence_, abs_item_pos).selected();
|
||||
}
|
||||
|
||||
if(item_ptr)
|
||||
{
|
||||
if (item_ptr->flags.selected != sel)
|
||||
if (item_ptr->flags.selected != new_selected_status)
|
||||
{
|
||||
if (sel)
|
||||
if (new_selected_status)
|
||||
{
|
||||
//Deselects the previously selected item.
|
||||
lister.cancel_others_if_single_enabled(true, abs_item_pos);
|
||||
@ -4180,13 +4196,15 @@ namespace nana
|
||||
else if (essence_->lister.latest_selected_abs == abs_item_pos)
|
||||
essence_->lister.latest_selected_abs.set_both(npos);
|
||||
|
||||
item_ptr->flags.selected = sel;
|
||||
item_ptr->flags.selected = new_selected_status;
|
||||
lister.emit_cs(abs_item_pos, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lister.cat_status(item_pos.cat, true, true);
|
||||
//A category was clicked. Sets all child items to be selected only if multiply selection is enabled.
|
||||
if(!lister.single_status(true))
|
||||
lister.cat_status(item_pos.cat, true, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -4336,8 +4354,9 @@ namespace nana
|
||||
|
||||
void trigger::key_press(graph_reference graph, const arg_keyboard& arg)
|
||||
{
|
||||
auto & list = essence_->lister;
|
||||
// Exit if list is empty
|
||||
if (essence_->lister.first().empty())
|
||||
if (list.first().empty())
|
||||
return;
|
||||
|
||||
bool upward = false;
|
||||
@ -4347,12 +4366,12 @@ namespace nana
|
||||
case keyboard::os_arrow_up:
|
||||
upward = true;
|
||||
case keyboard::os_arrow_down:
|
||||
essence_->lister.move_select(upward, !arg.shift, true);
|
||||
list.move_select(upward, !arg.shift, true);
|
||||
break;
|
||||
case L' ':
|
||||
{
|
||||
index_pairs s;
|
||||
bool ck = ! essence_->lister.item_selected_all_checked(s);
|
||||
bool ck = ! list.item_selected_all_checked(s);
|
||||
for(auto i : s)
|
||||
item_proxy(essence_, i).check(ck);
|
||||
}
|
||||
@ -4361,30 +4380,69 @@ namespace nana
|
||||
upward = true;
|
||||
case keyboard::os_pagedown:
|
||||
{
|
||||
//Turns page, then returns if no change occurs
|
||||
if (!essence_->content_view->turn_page(!upward, false))
|
||||
return;
|
||||
auto const item_px = essence_->item_height();
|
||||
auto picked_items = list.pick_items(true, true);
|
||||
index_pair init_idx = (picked_items.empty() ? list.first() : picked_items[0]);
|
||||
|
||||
essence_->lister.select_for_all(false);
|
||||
|
||||
auto idx = essence_->first_display();
|
||||
//Get the pixels between the init item and top edge or bottom edge
|
||||
auto logic_top = static_cast<int>(list.distance(list.first(), init_idx) * item_px);
|
||||
|
||||
if (!upward)
|
||||
idx = essence_->lister.advance(idx, static_cast<int>(essence_->count_of_exposed(false)) - 1);
|
||||
auto const screen_top = essence_->content_view->origin().y;
|
||||
auto const screen_bottom = screen_top + essence_->content_view->view_area().height;
|
||||
index_pair target_idx;
|
||||
|
||||
if (!idx.is_category())
|
||||
item_proxy::from_display(essence_, idx).select(true);
|
||||
else if (!essence_->lister.single_status(true)) //not selected
|
||||
essence_->lister.cat_status(idx.cat, true, true);
|
||||
//Check if it scrolls in current screen window
|
||||
//condition: top of target item is not less than top edge of content view and
|
||||
//the bottom of target item is not greater than bottom edge of content view.
|
||||
if ((screen_top + item_px <= logic_top) && (logic_top + item_px + item_px <= screen_bottom))
|
||||
{
|
||||
int offset = (static_cast<int>(upward ? screen_top : screen_bottom - item_px) - logic_top) / static_cast<int>(item_px);
|
||||
target_idx = list.advance(init_idx, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
//turn page
|
||||
auto page_item_count = (std::max)(1, static_cast<int>(essence_->count_of_exposed(false)));
|
||||
|
||||
break;
|
||||
auto origin = essence_->content_view->origin();
|
||||
if (upward)
|
||||
{
|
||||
target_idx = list.advance(init_idx, -page_item_count);
|
||||
if (target_idx.empty())
|
||||
target_idx = list.first();
|
||||
|
||||
origin.y = list.distance(list.first(), target_idx) * item_px;
|
||||
}
|
||||
else
|
||||
{
|
||||
target_idx = list.advance(init_idx, page_item_count);
|
||||
if (target_idx.empty())
|
||||
target_idx = list.last();
|
||||
|
||||
origin.y = list.distance(list.first(), target_idx) * item_px + item_px;
|
||||
if (origin.y >= (screen_bottom - screen_top))
|
||||
origin.y -= (screen_bottom - screen_top);
|
||||
else
|
||||
origin.y = 0;
|
||||
}
|
||||
|
||||
essence_->content_view->move_origin(origin - essence_->content_view->origin());
|
||||
}
|
||||
|
||||
if (!target_idx.is_category())
|
||||
item_proxy::from_display(essence_, target_idx).select(true);
|
||||
else if (!list.single_status(true)) //not selected
|
||||
list.cat_status(target_idx.cat, true, true);
|
||||
}
|
||||
break;
|
||||
case keyboard::os_home:
|
||||
case keyboard::os_end:
|
||||
{
|
||||
essence_->lister.select_for_all(false);
|
||||
list.select_for_all(false);
|
||||
|
||||
auto pos = (keyboard::os_home == arg.key ? essence_->lister.first() : essence_->lister.last());
|
||||
auto pos = (keyboard::os_home == arg.key ? list.first() : list.last());
|
||||
if (!pos.empty())
|
||||
{
|
||||
//When the pos indicates an empty category, then search forwards/backwards(depending on arg.key whether it is Home or End) for a non empty category.
|
||||
@ -4393,9 +4451,9 @@ namespace nana
|
||||
{
|
||||
if (keyboard::os_home == arg.key)
|
||||
{
|
||||
while (0 == essence_->lister.size_item(pos.cat))
|
||||
while (0 == list.size_item(pos.cat))
|
||||
{
|
||||
if (++pos.cat >= essence_->lister.cat_container().size())
|
||||
if (++pos.cat >= list.cat_container().size())
|
||||
{
|
||||
pos = index_pair{ npos, npos };
|
||||
break;
|
||||
@ -4404,7 +4462,7 @@ namespace nana
|
||||
}
|
||||
else
|
||||
{
|
||||
while (0 == essence_->lister.size_item(pos.cat))
|
||||
while (0 == list.size_item(pos.cat))
|
||||
{
|
||||
if (pos.cat-- == 0)
|
||||
{
|
||||
@ -4416,7 +4474,7 @@ namespace nana
|
||||
|
||||
if (!pos.empty())
|
||||
{
|
||||
if (essence_->lister.expand(pos.cat))
|
||||
if (list.expand(pos.cat))
|
||||
pos.item = 0;
|
||||
}
|
||||
}
|
||||
@ -4425,8 +4483,8 @@ namespace nana
|
||||
{
|
||||
if (pos.is_category())
|
||||
{
|
||||
if (!essence_->lister.single_status(true)) //multiple selection is not enabled
|
||||
essence_->lister.cat_status(pos.cat, true, true);
|
||||
if (!list.single_status(true)) //multiple selection is not enabled
|
||||
list.cat_status(pos.cat, true, true);
|
||||
}
|
||||
else
|
||||
item_proxy::from_display(essence_, pos).select(true);
|
||||
@ -4662,12 +4720,12 @@ namespace nana
|
||||
|
||||
bool item_proxy::operator==(const std::string& s) const
|
||||
{
|
||||
return (text(pos_.item) == s);
|
||||
return (text(0) == s);
|
||||
}
|
||||
|
||||
bool item_proxy::operator==(const std::wstring& s) const
|
||||
{
|
||||
return (text(pos_.item) == to_utf8(s));
|
||||
return (text(0) == to_utf8(s));
|
||||
}
|
||||
|
||||
item_proxy & item_proxy::operator=(const item_proxy& rhs)
|
||||
@ -5158,7 +5216,8 @@ namespace nana
|
||||
cat_->make_sort_order();
|
||||
ess_->lister.sort();
|
||||
|
||||
ess_->update(true);
|
||||
//Don't ignore the auto-draw flag for performance enhancement.
|
||||
ess_->update();
|
||||
}
|
||||
}
|
||||
//end class cat_proxy
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* A Progress Indicator Implementation
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -96,7 +96,11 @@ namespace nana
|
||||
{
|
||||
if (widget_)
|
||||
{
|
||||
auto value_px = (widget_->size().width - border_px * 2) * value_ / max_;
|
||||
auto value_px = (widget_->size().width - border_px * 2);
|
||||
|
||||
//avoid overflow
|
||||
if (value_ < max_)
|
||||
value_px = static_cast<unsigned>(value_px * (double(value_) / double(max_)));
|
||||
|
||||
if (value_px != value_px_)
|
||||
{
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Scroll Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -20,9 +20,15 @@ namespace nana
|
||||
namespace scroll
|
||||
{
|
||||
//struct metrics_type
|
||||
metrics_type::metrics_type()
|
||||
:peak(1), range(1), step(1), value(0),
|
||||
what(buttons::none), pressed(false), scroll_length(0), scroll_pos(0)
|
||||
metrics_type::metrics_type():
|
||||
peak(1),
|
||||
range(1),
|
||||
step(1),
|
||||
value(0),
|
||||
what(buttons::none),
|
||||
pressed(false),
|
||||
scroll_length(0),
|
||||
scroll_pos(0)
|
||||
{}
|
||||
//end struct metrics_type
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ namespace nana
|
||||
{
|
||||
::jpeg_create_decompress(&jdstru);
|
||||
|
||||
::jpeg_mem_src(&jdstru, const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(data)), bytes);
|
||||
::jpeg_mem_src(&jdstru, const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(data)), static_cast<unsigned long>(bytes));
|
||||
_m_read_jpg(jdstru);
|
||||
|
||||
jpeg_finish_decompress(&jdstru);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user