Merge remote-tracking branch 'jinhao/hotfix-1.6.1' into hotfix-1.6.1
This commit is contained in:
commit
bb34fde7a9
@ -5,7 +5,7 @@
|
|||||||
# Robert Hauck - Enable support for PNG/Freetype
|
# Robert Hauck - Enable support for PNG/Freetype
|
||||||
# Qiangqiang Wu - Add biicode support
|
# Qiangqiang Wu - Add biicode support
|
||||||
# Ariel Vina-Rodriguez (qPCR4vir)
|
# Ariel Vina-Rodriguez (qPCR4vir)
|
||||||
# Pavel O. - fix compilation with boost::filesystem (#281)
|
# Pavel O. - fix compilation with boost::filesystem (#281)
|
||||||
# Frostbane - Add option for compiling a shared library (#263,#265)
|
# Frostbane - Add option for compiling a shared library (#263,#265)
|
||||||
#
|
#
|
||||||
# Nana uses some build systems: MS-VS solution, MAKE, bakefile, codeblock, etc. manually optimized.
|
# Nana uses some build systems: MS-VS solution, MAKE, bakefile, codeblock, etc. manually optimized.
|
||||||
@ -156,25 +156,25 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
|||||||
if(NANA_CMAKE_SHARED_LIB)
|
if(NANA_CMAKE_SHARED_LIB)
|
||||||
list(APPEND NANA_LINKS -lgcc -lstdc++ -pthread)
|
list(APPEND NANA_LINKS -lgcc -lstdc++ -pthread)
|
||||||
else()
|
else()
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread")
|
if(MINGW)
|
||||||
# message("Setting NANA_LINKS to -static-libgcc -static-libstdc++ -pthread or ${NANA_LINKS}")
|
set(CMAKE_EXE_LINKER_FLAGS "-static -pthread")
|
||||||
|
else()
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -pthread")
|
||||||
|
endif()
|
||||||
endif(NANA_CMAKE_SHARED_LIB)
|
endif(NANA_CMAKE_SHARED_LIB)
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
||||||
# GCC 4.9
|
# GCC 4.9
|
||||||
list(APPEND NANA_LINKS "-lboost_system -lboost_thread")
|
list(APPEND NANA_LINKS "-lboost_system -lboost_thread")
|
||||||
|
|
||||||
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3)
|
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.3)
|
||||||
# IS_GNUCXX < 5.3
|
# IS_GNUCXX < 5.3
|
||||||
else()
|
else()
|
||||||
list(APPEND NANA_LINKS -lstdc++fs)
|
list(APPEND NANA_LINKS -lstdc++fs)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
endif(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # AND NOT MINGW
|
|
||||||
|
|
||||||
|
|
||||||
if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # APPLE Clang
|
if (APPLE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") # APPLE Clang
|
||||||
# set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libstdc++")
|
|
||||||
list(APPEND NANA_LINKS -stdlib=libstdc++)
|
list(APPEND NANA_LINKS -stdlib=libstdc++)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
@ -220,12 +220,14 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef _nana_std_has_string_view
|
#undef _nana_std_has_string_view
|
||||||
|
#undef _nana_std_has_emplace_return_type
|
||||||
#if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && defined(_MSVC_LANG) && _MSVC_LANG >= 201703)) || \
|
#if ((defined(_MSC_VER) && (_MSC_VER >= 1912) && defined(_MSVC_LANG) && _MSVC_LANG >= 201703)) || \
|
||||||
((__cplusplus >= 201703L) && \
|
((__cplusplus >= 201703L) && \
|
||||||
(defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ >= 400) || \
|
(defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ >= 400) || \
|
||||||
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 701))) \
|
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 701))) \
|
||||||
)
|
)
|
||||||
# define _nana_std_has_string_view
|
# define _nana_std_has_string_view
|
||||||
|
# define _nana_std_has_emplace_return_type
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* A Tooltip Implementation
|
* A Tooltip Implementation
|
||||||
* 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.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
@ -809,7 +809,6 @@ namespace nana
|
|||||||
/// operate with absolute positions and contain only the position but montain pointers to parts of the real items
|
/// operate with absolute positions and contain only the position but montain pointers to parts of the real items
|
||||||
/// item_proxy self, it references and iterators are not invalidated by sort()
|
/// item_proxy self, it references and iterators are not invalidated by sort()
|
||||||
class item_proxy
|
class item_proxy
|
||||||
//: public std::iterator<std::input_iterator_tag, item_proxy> //deprecated
|
|
||||||
: public ::nana::widgets::detail::widget_iterator<std::input_iterator_tag, item_proxy>
|
: public ::nana::widgets::detail::widget_iterator<std::input_iterator_tag, item_proxy>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -984,7 +983,6 @@ namespace nana
|
|||||||
};
|
};
|
||||||
|
|
||||||
class cat_proxy
|
class cat_proxy
|
||||||
//: public std::iterator<std::input_iterator_tag, cat_proxy> //deprecated
|
|
||||||
: public ::nana::widgets::detail::widget_iterator<std::input_iterator_tag, cat_proxy>
|
: public ::nana::widgets::detail::widget_iterator<std::input_iterator_tag, cat_proxy>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -191,14 +191,14 @@ namespace nana{ namespace widgets
|
|||||||
void draw_corner();
|
void draw_corner();
|
||||||
void render(bool focused);
|
void render(bool focused);
|
||||||
public:
|
public:
|
||||||
void put(std::wstring);
|
void put(std::wstring, bool perform_event);
|
||||||
void put(wchar_t);
|
void put(wchar_t);
|
||||||
void copy() const;
|
void copy() const;
|
||||||
void cut();
|
void cut();
|
||||||
void paste();
|
void paste();
|
||||||
void enter(bool record_undo = true);
|
void enter(bool record_undo, bool perform_event);
|
||||||
void del();
|
void del();
|
||||||
void backspace(bool record_undo = true);
|
void backspace(bool record_undo, bool perform_event);
|
||||||
void undo(bool reverse);
|
void undo(bool reverse);
|
||||||
void set_undo_queue_length(std::size_t len);
|
void set_undo_queue_length(std::size_t len);
|
||||||
void move_ns(bool to_north); //Moves up and down
|
void move_ns(bool to_north); //Moves up and down
|
||||||
@ -243,9 +243,9 @@ namespace nana{ namespace widgets
|
|||||||
void _m_reset();
|
void _m_reset();
|
||||||
|
|
||||||
//Inserts text at position where the caret is
|
//Inserts text at position where the caret is
|
||||||
::nana::upoint _m_put(::std::wstring);
|
::nana::upoint _m_put(::std::wstring, bool perform_event);
|
||||||
|
|
||||||
::nana::upoint _m_erase_select();
|
::nana::upoint _m_erase_select(bool perform_event);
|
||||||
|
|
||||||
::std::wstring _m_make_select_string() const;
|
::std::wstring _m_make_select_string() const;
|
||||||
static bool _m_resolve_text(const ::std::wstring&, std::vector<std::pair<std::size_t, std::size_t>> & lines);
|
static bool _m_resolve_text(const ::std::wstring&, std::vector<std::pair<std::size_t, std::size_t>> & lines);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Text Token Stream
|
* Text Token Stream
|
||||||
* Nana C++ Library(http://www.nanapro.org)
|
* 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.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <nana/push_ignore_diagnostic>
|
#include <nana/push_ignore_diagnostic>
|
||||||
|
#include <nana/unicode_bidi.hpp>
|
||||||
|
|
||||||
namespace nana{ namespace widgets{ namespace skeletons
|
namespace nana{ namespace widgets{ namespace skeletons
|
||||||
{
|
{
|
||||||
@ -95,9 +96,11 @@ namespace nana{ namespace widgets{ namespace skeletons
|
|||||||
return std::stoi(idstr_, nullptr, 0);
|
return std::stoi(idstr_, nullptr, 0);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static bool _m_unicode_word_breakable(wchar_t ch)
|
static bool _m_unicode_word_breakable(const wchar_t* ch) noexcept
|
||||||
{
|
{
|
||||||
return ((0x4E00 <= ch) && (ch <= 0x9FFF));
|
if (*ch)
|
||||||
|
return unicode_wordbreak(*ch, ch[1]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read the data token
|
//Read the data token
|
||||||
@ -112,14 +115,14 @@ namespace nana{ namespace widgets{ namespace skeletons
|
|||||||
idstr_.clear();
|
idstr_.clear();
|
||||||
idstr_.append(1, ch);
|
idstr_.append(1, ch);
|
||||||
|
|
||||||
if(_m_unicode_word_breakable(ch))
|
if (_m_unicode_word_breakable(iptr_))
|
||||||
{
|
{
|
||||||
++iptr_;
|
++iptr_;
|
||||||
return token::data;
|
return token::data;
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = *++iptr_;
|
ch = *++iptr_;
|
||||||
while((iptr_ != endptr_) && (ch > 0xFF) && (false == _m_unicode_word_breakable(ch)))
|
while((iptr_ != endptr_) && (ch > 0xFF) && (false == _m_unicode_word_breakable(iptr_)))
|
||||||
{
|
{
|
||||||
idstr_.append(1, ch);
|
idstr_.append(1, ch);
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* A textbase class implementation
|
* A textbase class implementation
|
||||||
* Nana C++ Library(http://www.nanapro.org)
|
* 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.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@ -301,6 +301,29 @@ namespace skeletons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Triggers the text_changed event.
|
||||||
|
//It is exposed for outter classes. For a outter class(eg. text_editor), a changing text content operation
|
||||||
|
//may contains multiple textbase operations, therefore, the outter class determines when an event should be triggered.
|
||||||
|
//
|
||||||
|
//Addtional, using text_changed() method, it is possible to allow a outter class performing some updating operations
|
||||||
|
//before triggering text_changed event.
|
||||||
|
void text_changed()
|
||||||
|
{
|
||||||
|
if (!changed_)
|
||||||
|
{
|
||||||
|
_m_first_change();
|
||||||
|
changed_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edited_)
|
||||||
|
{
|
||||||
|
if (evt_agent_)
|
||||||
|
evt_agent_->text_changed();
|
||||||
|
|
||||||
|
edited_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_type lines() const
|
size_type lines() const
|
||||||
{
|
{
|
||||||
return text_cont_.size();
|
return text_cont_.size();
|
||||||
@ -330,7 +353,7 @@ namespace skeletons
|
|||||||
_m_at(pos).swap(text);
|
_m_at(pos).swap(text);
|
||||||
|
|
||||||
_m_make_max(pos);
|
_m_make_max(pos);
|
||||||
_m_edited();
|
edited_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(upoint pos, string_type && str)
|
void insert(upoint pos, string_type && str)
|
||||||
@ -351,7 +374,7 @@ namespace skeletons
|
|||||||
}
|
}
|
||||||
|
|
||||||
_m_make_max(pos.y);
|
_m_make_max(pos.y);
|
||||||
_m_edited();
|
edited_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertln(size_type pos, string_type&& str)
|
void insertln(size_type pos, string_type&& str)
|
||||||
@ -362,7 +385,7 @@ namespace skeletons
|
|||||||
text_cont_.emplace_back(new string_type(std::move(str)));
|
text_cont_.emplace_back(new string_type(std::move(str)));
|
||||||
|
|
||||||
_m_make_max(pos);
|
_m_make_max(pos);
|
||||||
_m_edited();
|
edited_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(size_type line, size_type pos, size_type count)
|
void erase(size_type line, size_type pos, size_type count)
|
||||||
@ -378,7 +401,7 @@ namespace skeletons
|
|||||||
if (attr_max_.line == line)
|
if (attr_max_.line == line)
|
||||||
_m_scan_for_max();
|
_m_scan_for_max();
|
||||||
|
|
||||||
_m_edited();
|
edited_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +421,7 @@ namespace skeletons
|
|||||||
else if (pos < attr_max_.line)
|
else if (pos < attr_max_.line)
|
||||||
attr_max_.line -= n;
|
attr_max_.line -= n;
|
||||||
|
|
||||||
_m_edited();
|
edited_ = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,7 +449,7 @@ namespace skeletons
|
|||||||
if(pos < attr_max_.line)
|
if(pos < attr_max_.line)
|
||||||
--attr_max_.line;
|
--attr_max_.line;
|
||||||
|
|
||||||
_m_edited();
|
edited_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,23 +537,12 @@ namespace skeletons
|
|||||||
|
|
||||||
changed_ = false;
|
changed_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _m_edited()
|
|
||||||
{
|
|
||||||
if(!changed_)
|
|
||||||
{
|
|
||||||
_m_first_change();
|
|
||||||
changed_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evt_agent_)
|
|
||||||
evt_agent_->text_changed();
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
std::deque<std::unique_ptr<string_type>> text_cont_;
|
std::deque<std::unique_ptr<string_type>> text_cont_;
|
||||||
textbase_event_agent_interface* evt_agent_{ nullptr };
|
textbase_event_agent_interface* evt_agent_{ nullptr };
|
||||||
|
|
||||||
mutable bool changed_{ false };
|
mutable bool changed_{ false };
|
||||||
|
mutable bool edited_{ false };
|
||||||
mutable std::string filename_; //A string for the saved filename.
|
mutable std::string filename_; //A string for the saved filename.
|
||||||
const string_type nullstr_;
|
const string_type nullstr_;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* A Thread Pool Implementation
|
* A Thread Pool Implementation
|
||||||
* 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.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@ -13,10 +13,14 @@
|
|||||||
#ifndef NANA_THREADS_POOL_HPP
|
#ifndef NANA_THREADS_POOL_HPP
|
||||||
#define NANA_THREADS_POOL_HPP
|
#define NANA_THREADS_POOL_HPP
|
||||||
|
|
||||||
|
#include <nana/c++defines.hpp>
|
||||||
#include <nana/traits.hpp>
|
#include <nana/traits.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
#ifndef STD_THREAD_NOT_SUPPORTED
|
||||||
|
# include <thread>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace nana{
|
namespace nana{
|
||||||
/// Some mutex classes for synchronizing.
|
/// Some mutex classes for synchronizing.
|
||||||
@ -58,9 +62,12 @@ namespace threads
|
|||||||
pool(const pool&) = delete;
|
pool(const pool&) = delete;
|
||||||
pool& operator=(const pool&) = delete;
|
pool& operator=(const pool&) = delete;
|
||||||
public:
|
public:
|
||||||
pool(); ///< Creates a group of threads.
|
#ifndef STD_THREAD_NOT_SUPPORTED
|
||||||
|
pool(unsigned thread_number = std::thread::hardware_concurrency()); ///< Creates a group of threads.
|
||||||
|
#else
|
||||||
|
pool(unsigned thread_number = 0);
|
||||||
|
#endif
|
||||||
pool(pool&&);
|
pool(pool&&);
|
||||||
pool(std::size_t thread_number); ///< Creates a number of threads specifed by thread_number.
|
|
||||||
~pool(); ///< waits for the all running tasks till they are finished and skips all the queued tasks.
|
~pool(); ///< waits for the all running tasks till they are finished and skips all the queued tasks.
|
||||||
|
|
||||||
pool& operator=(pool&&);
|
pool& operator=(pool&&);
|
||||||
|
@ -71,6 +71,8 @@ namespace nana
|
|||||||
|
|
||||||
std::vector<unicode_bidi::entity> unicode_reorder(const wchar_t* text, std::size_t length);
|
std::vector<unicode_bidi::entity> unicode_reorder(const wchar_t* text, std::size_t length);
|
||||||
|
|
||||||
|
bool unicode_wordbreak(wchar_t left, wchar_t right);
|
||||||
|
|
||||||
}
|
}
|
||||||
#include <nana/pop_ignore_diagnostic>
|
#include <nana/pop_ignore_diagnostic>
|
||||||
|
|
||||||
|
@ -186,10 +186,12 @@ namespace nana
|
|||||||
throw std::invalid_argument(excpt_what);
|
throw std::invalid_argument(excpt_what);
|
||||||
|
|
||||||
std::vector<std::string> rgb;
|
std::vector<std::string> rgb;
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto const is_real = (rgb.emplace_back(i->str()).back() == '%');
|
||||||
|
#else
|
||||||
rgb.emplace_back(i->str());
|
rgb.emplace_back(i->str());
|
||||||
|
|
||||||
const bool is_real = (rgb.back().back() == '%');
|
const bool is_real = (rgb.back().back() == '%');
|
||||||
|
#endif
|
||||||
pat.assign(is_real ? "(\\d*\\.)?\\d+\\%" : "\\d+");
|
pat.assign(is_real ? "(\\d*\\.)?\\d+\\%" : "\\d+");
|
||||||
|
|
||||||
for (++i; i != end; ++i)
|
for (++i; i != end; ++i)
|
||||||
@ -275,9 +277,13 @@ namespace nana
|
|||||||
{
|
{
|
||||||
std::vector<std::string> rgb;
|
std::vector<std::string> rgb;
|
||||||
|
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto const is_real = (rgb.emplace_back(std::move(str)).back() == '%');
|
||||||
|
#else
|
||||||
rgb.emplace_back(std::move(str));
|
rgb.emplace_back(std::move(str));
|
||||||
|
|
||||||
const bool is_real = (rgb.back().back() == '%');
|
const bool is_real = (rgb.back().back() == '%');
|
||||||
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
|
@ -656,38 +656,6 @@ namespace detail
|
|||||||
msg_dispatcher_->erase(reinterpret_cast<Window>(wd));
|
msg_dispatcher_->erase(reinterpret_cast<Window>(wd));
|
||||||
|
|
||||||
platform_scope_guard lock;
|
platform_scope_guard lock;
|
||||||
#if 0
|
|
||||||
auto i = wincontext_.find(wd);
|
|
||||||
if(i == wincontext_.end()) return;
|
|
||||||
|
|
||||||
if(i->second.owner)
|
|
||||||
{
|
|
||||||
auto u = wincontext_.find(i->second.owner);
|
|
||||||
if(u != wincontext_.end())
|
|
||||||
{
|
|
||||||
auto * vec = u->second.owned;
|
|
||||||
if(vec)
|
|
||||||
{
|
|
||||||
auto j = std::find(vec->begin(), vec->end(), i->first);
|
|
||||||
if(j != vec->end())
|
|
||||||
vec->erase(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto * vec = i->second.owned;
|
|
||||||
if(vec)
|
|
||||||
{
|
|
||||||
set_error_handler();
|
|
||||||
auto & wd_manager = detail::bedrock::instance().wd_manager();
|
|
||||||
for(auto u = vec->rbegin(); u != vec->rend(); ++u)
|
|
||||||
wd_manager.close(wd_manager.root(*u));
|
|
||||||
|
|
||||||
rev_error_handler();
|
|
||||||
}
|
|
||||||
delete vec;
|
|
||||||
wincontext_.erase(i);
|
|
||||||
#else
|
|
||||||
if(umake_owner(wd))
|
if(umake_owner(wd))
|
||||||
{
|
{
|
||||||
auto i = wincontext_.find(wd);
|
auto i = wincontext_.find(wd);
|
||||||
@ -708,7 +676,6 @@ namespace detail
|
|||||||
wincontext_.erase(i);
|
wincontext_.erase(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
iconbase_.erase(wd);
|
iconbase_.erase(wd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,62 +1133,11 @@ namespace detail
|
|||||||
wd_manager.do_lazy_refresh(msgwnd, false);
|
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
//Fall through
|
|
||||||
case XLookupChars:
|
|
||||||
if (msgwnd->flags.enabled)
|
|
||||||
{
|
|
||||||
const wchar_t* charbuf;
|
|
||||||
|
|
||||||
nana::detail::charset_conv charset(NANA_UNICODE, "UTF-8");
|
|
||||||
const std::string& str = charset.charset(std::string(keybuf, keybuf + len));
|
|
||||||
charbuf = reinterpret_cast<const wchar_t*>(str.c_str());
|
|
||||||
len = str.size() / sizeof(wchar_t);
|
|
||||||
|
|
||||||
for(int i = 0; i < len; ++i)
|
|
||||||
{
|
|
||||||
arg_keyboard arg = modifiers_status;
|
|
||||||
arg.ignore = false;
|
|
||||||
arg.key = charbuf[i];
|
|
||||||
|
|
||||||
// ignore Unicode BOM (it may or may not appear)
|
|
||||||
if (arg.key == 0xFEFF) continue;
|
|
||||||
|
|
||||||
//Only accept tab when it is not ignored.
|
|
||||||
if ((keyboard::tab == arg.key) && root_runtime->condition.ignore_tab)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(context.is_alt_pressed)
|
|
||||||
{
|
|
||||||
arg.ctrl = arg.shift = false;
|
|
||||||
arg.evt_code = event_code::shortkey;
|
|
||||||
brock.shortkey_occurred(true);
|
|
||||||
auto shr_wd = wd_manager.find_shortkey(native_window, arg.key);
|
|
||||||
if(shr_wd)
|
|
||||||
{
|
|
||||||
arg.window_handle = reinterpret_cast<window>(shr_wd);
|
|
||||||
brock.emit(event_code::shortkey, shr_wd, arg, true, &context);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
arg.evt_code = event_code::key_char;
|
|
||||||
arg.window_handle = reinterpret_cast<window>(msgwnd);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(brock.shortkey_occurred(false))
|
|
||||||
context.is_alt_pressed = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#else
|
|
||||||
x_lookup_chars(root_runtime, msgwnd, keybuf, len, modifiers_status);
|
x_lookup_chars(root_runtime, msgwnd, keybuf, len, modifiers_status);
|
||||||
break;
|
break;
|
||||||
case XLookupChars:
|
case XLookupChars:
|
||||||
x_lookup_chars(root_runtime, msgwnd, keybuf, len, modifiers_status);
|
x_lookup_chars(root_runtime, msgwnd, keybuf, len, modifiers_status);
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wd_manager.do_lazy_refresh(msgwnd, false);
|
wd_manager.do_lazy_refresh(msgwnd, false);
|
||||||
|
@ -745,6 +745,14 @@ namespace nana{
|
|||||||
{
|
{
|
||||||
nana::detail::platform_scope_guard psg;
|
nana::detail::platform_scope_guard psg;
|
||||||
Display* disp = restrict::spec.open_display();
|
Display* disp = restrict::spec.open_display();
|
||||||
|
|
||||||
|
//Returns if the requested visibility is same with the current status.
|
||||||
|
//In some X-Server versions/implementations, XMapWindow() doesn't generate
|
||||||
|
//a ConfigureNotify if the requested visibility is same with the current status.
|
||||||
|
//It causes that x11_wait_for always waiting for the ConfigureNotify.
|
||||||
|
if(show == is_window_visible(wd))
|
||||||
|
return;
|
||||||
|
|
||||||
if(show)
|
if(show)
|
||||||
{
|
{
|
||||||
::XMapWindow(disp, reinterpret_cast<Window>(wd));
|
::XMapWindow(disp, reinterpret_cast<Window>(wd));
|
||||||
@ -984,6 +992,15 @@ namespace nana{
|
|||||||
|
|
||||||
nana::detail::platform_scope_guard lock;
|
nana::detail::platform_scope_guard lock;
|
||||||
|
|
||||||
|
if(point{x, y} == window_position(wd))
|
||||||
|
{
|
||||||
|
//Returns if the requested position is same with the current position.
|
||||||
|
//In some X-Server versions/implementations, XMoveWindow() doesn't generate
|
||||||
|
//a ConfigureNotify if the requested position is same with the current position.
|
||||||
|
//It causes that x11_wait_for always waiting for the ConfigureNotify.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
XWindowAttributes attr;
|
XWindowAttributes attr;
|
||||||
::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr);
|
::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr);
|
||||||
if(attr.map_state == IsUnmapped)
|
if(attr.map_state == IsUnmapped)
|
||||||
@ -1041,6 +1058,16 @@ namespace nana{
|
|||||||
XSizeHints hints;
|
XSizeHints hints;
|
||||||
nana::detail::platform_scope_guard psg;
|
nana::detail::platform_scope_guard psg;
|
||||||
|
|
||||||
|
|
||||||
|
//Returns if the requested rectangle is same with the current rectangle.
|
||||||
|
//In some X-Server versions/implementations, XMapWindow() doesn't generate
|
||||||
|
//a ConfigureNotify if the requested rectangle is same with the current rectangle.
|
||||||
|
//It causes that x11_wait_for always waiting for the ConfigureNotify.
|
||||||
|
rectangle current_r;
|
||||||
|
get_window_rect(wd, current_r);
|
||||||
|
if(r == current_r)
|
||||||
|
return true;
|
||||||
|
|
||||||
::XGetWMNormalHints(disp, reinterpret_cast<Window>(wd), &hints, &supplied);
|
::XGetWMNormalHints(disp, reinterpret_cast<Window>(wd), &hints, &supplied);
|
||||||
if((hints.flags & (PMinSize | PMaxSize)) && (hints.min_width == hints.max_width) && (hints.min_height == hints.max_height))
|
if((hints.flags & (PMinSize | PMaxSize)) && (hints.min_width == hints.max_width) && (hints.min_height == hints.max_height))
|
||||||
{
|
{
|
||||||
@ -1230,6 +1257,15 @@ namespace nana{
|
|||||||
auto disp = restrict::spec.open_display();
|
auto disp = restrict::spec.open_display();
|
||||||
nana::detail::platform_scope_guard psg;
|
nana::detail::platform_scope_guard psg;
|
||||||
|
|
||||||
|
//Returns if the requested size is same with the current size.
|
||||||
|
//In some X-Server versions/implementations, XMapWindow() doesn't generate
|
||||||
|
//a ConfigureNotify if the requested size is same with the current size.
|
||||||
|
//It causes that x11_wait_for always waiting for the ConfigureNotify.
|
||||||
|
rectangle current_r;
|
||||||
|
get_window_rect(wd, current_r);
|
||||||
|
if(current_r.dimension() == sz)
|
||||||
|
return true;
|
||||||
|
|
||||||
//Check the XSizeHints for testing whether the window is sizable.
|
//Check the XSizeHints for testing whether the window is sizable.
|
||||||
XSizeHints hints;
|
XSizeHints hints;
|
||||||
long supplied;
|
long supplied;
|
||||||
@ -1265,6 +1301,9 @@ namespace nana{
|
|||||||
unsigned border, depth;
|
unsigned border, depth;
|
||||||
nana::detail::platform_scope_guard psg;
|
nana::detail::platform_scope_guard psg;
|
||||||
::XGetGeometry(restrict::spec.open_display(), reinterpret_cast<Window>(wd), &root, &x, &y, &r.width, &r.height, &border, &depth);
|
::XGetGeometry(restrict::spec.open_display(), reinterpret_cast<Window>(wd), &root, &x, &y, &r.width, &r.height, &border, &depth);
|
||||||
|
|
||||||
|
auto pos = window_position(wd);
|
||||||
|
r.position(pos);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +85,12 @@ namespace nana
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & rep = impl_->base.emplace_back();
|
||||||
|
#else
|
||||||
impl_->base.emplace_back();
|
impl_->base.emplace_back();
|
||||||
auto & rep = impl_->base.back();
|
auto & rep = impl_->base.back();
|
||||||
|
#endif
|
||||||
rep.handle = wd;
|
rep.handle = wd;
|
||||||
rep.keys.emplace_back(key);
|
rep.keys.emplace_back(key);
|
||||||
|
|
||||||
@ -242,8 +246,12 @@ namespace detail
|
|||||||
return kv.second;
|
return kv.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
return table_.emplace_back(key).second;
|
||||||
|
#else
|
||||||
table_.emplace_back(key);
|
table_.emplace_back(key);
|
||||||
return table_.back().second;
|
return table_.back().second;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator find(const Key& key)
|
iterator find(const Key& key)
|
||||||
|
@ -742,8 +742,14 @@ namespace nana
|
|||||||
|
|
||||||
void _m_add_agent(const detail::place_agent& ag) override
|
void _m_add_agent(const detail::place_agent& ag) override
|
||||||
{
|
{
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
this->operator<<(
|
||||||
|
widgets_.emplace_back(ag.create(place_ptr_->window_handle()))->handle()
|
||||||
|
);
|
||||||
|
#else
|
||||||
widgets_.emplace_back(ag.create(place_ptr_->window_handle()));
|
widgets_.emplace_back(ag.create(place_ptr_->window_handle()));
|
||||||
this->operator<<(widgets_.back()->handle());
|
this->operator<<(widgets_.back()->handle());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
division* attached{ nullptr };
|
division* attached{ nullptr };
|
||||||
|
@ -436,10 +436,13 @@ namespace nana
|
|||||||
caption_.caption(wdg->caption());
|
caption_.caption(wdg->caption());
|
||||||
}
|
}
|
||||||
|
|
||||||
panels_.emplace_back();
|
|
||||||
auto wdg_ptr = wdg.get();
|
auto wdg_ptr = wdg.get();
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
panels_.emplace_back().widget_ptr = std::move(wdg);
|
||||||
|
#else
|
||||||
|
panels_.emplace_back();
|
||||||
panels_.back().widget_ptr.swap(wdg);
|
panels_.back().widget_ptr.swap(wdg);
|
||||||
|
#endif
|
||||||
for (auto & pn : panels_)
|
for (auto & pn : panels_)
|
||||||
{
|
{
|
||||||
if (pn.widget_ptr)
|
if (pn.widget_ptr)
|
||||||
|
@ -835,17 +835,6 @@ namespace API
|
|||||||
|
|
||||||
size inner_size = sz;
|
size inner_size = sz;
|
||||||
|
|
||||||
#if 0
|
|
||||||
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;
|
|
||||||
#else
|
|
||||||
if (inner_size.width < static_cast<unsigned>(fm_extents.left + fm_extents.right))
|
if (inner_size.width < static_cast<unsigned>(fm_extents.left + fm_extents.right))
|
||||||
inner_size.width = 0;
|
inner_size.width = 0;
|
||||||
else
|
else
|
||||||
@ -855,7 +844,6 @@ namespace API
|
|||||||
inner_size.height = 0;
|
inner_size.height = 0;
|
||||||
else
|
else
|
||||||
inner_size.height -= static_cast<unsigned>(fm_extents.top + fm_extents.bottom);
|
inner_size.height -= static_cast<unsigned>(fm_extents.top + fm_extents.bottom);
|
||||||
#endif
|
|
||||||
|
|
||||||
window_size(wd, inner_size);
|
window_size(wd, inner_size);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* A Tooltip Implementation
|
* A Tooltip Implementation
|
||||||
* Nana C++ Library(http://www.nanapro.org)
|
* 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.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@ -15,6 +15,7 @@
|
|||||||
#include <nana/gui/timer.hpp>
|
#include <nana/gui/timer.hpp>
|
||||||
#include <nana/gui/screen.hpp>
|
#include <nana/gui/screen.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace nana
|
namespace nana
|
||||||
{
|
{
|
||||||
@ -157,7 +158,14 @@ namespace nana
|
|||||||
|
|
||||||
class controller
|
class controller
|
||||||
{
|
{
|
||||||
typedef std::pair<window, std::string> pair_t;
|
struct tip_value
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
event_handle evt_msenter;
|
||||||
|
event_handle evt_msleave;
|
||||||
|
event_handle evt_msdown;
|
||||||
|
event_handle evt_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
typedef std::function<void(tooltip_interface*)> deleter_type;
|
typedef std::function<void(tooltip_interface*)> deleter_type;
|
||||||
|
|
||||||
@ -207,7 +215,7 @@ namespace nana
|
|||||||
if (str.empty())
|
if (str.empty())
|
||||||
_m_untip(wd);
|
_m_untip(wd);
|
||||||
else
|
else
|
||||||
_m_get(wd).second = str;
|
_m_get(wd).text = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
void show(const std::string& text, const point* pos, std::size_t duration)
|
void show(const std::string& text, const point* pos, std::size_t duration)
|
||||||
@ -236,35 +244,35 @@ namespace nana
|
|||||||
window_.reset();
|
window_.reset();
|
||||||
|
|
||||||
//Destroy the tooltip controller when there are not tooltips.
|
//Destroy the tooltip controller when there are not tooltips.
|
||||||
if (cont_.empty())
|
if (table_.empty())
|
||||||
instance(true);
|
instance(true);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void _m_untip(window wd)
|
void _m_untip(window wd)
|
||||||
{
|
{
|
||||||
for (auto i = cont_.begin(); i != cont_.end(); ++i)
|
auto i = table_.find(wd);
|
||||||
|
if(i != table_.end())
|
||||||
{
|
{
|
||||||
if (i->first == wd)
|
API::umake_event(i->second.evt_msdown);
|
||||||
{
|
API::umake_event(i->second.evt_msenter);
|
||||||
cont_.erase(i);
|
API::umake_event(i->second.evt_msleave);
|
||||||
|
API::umake_event(i->second.evt_destroy);
|
||||||
|
|
||||||
if (cont_.empty())
|
table_.erase(i);
|
||||||
{
|
}
|
||||||
window_.reset();
|
|
||||||
instance(true);
|
if (table_.empty())
|
||||||
}
|
{
|
||||||
return;
|
window_.reset();
|
||||||
}
|
instance(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
pair_t& _m_get(window wd)
|
tip_value& _m_get(window wd)
|
||||||
{
|
{
|
||||||
for (auto & pr : cont_)
|
auto i = table_.find(wd);
|
||||||
{
|
if (i != table_.end())
|
||||||
if (pr.first == wd)
|
return i->second;
|
||||||
return pr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto & events = API::events(wd);
|
auto & events = API::events(wd);
|
||||||
|
|
||||||
@ -272,28 +280,29 @@ namespace nana
|
|||||||
{
|
{
|
||||||
if (event_code::mouse_enter == arg.evt_code)
|
if (event_code::mouse_enter == arg.evt_code)
|
||||||
{
|
{
|
||||||
auto & pr = _m_get(arg.window_handle);
|
auto & value = _m_get(arg.window_handle);
|
||||||
if (pr.second.size())
|
if (value.text.size())
|
||||||
this->show(pr.second, nullptr, 0);
|
this->show(value.text, nullptr, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this->close();
|
this->close();
|
||||||
};
|
};
|
||||||
|
|
||||||
events.mouse_enter.connect(mouse_fn);
|
auto & value = table_[wd];
|
||||||
events.mouse_leave.connect(mouse_fn);
|
|
||||||
events.mouse_down.connect(mouse_fn);
|
|
||||||
|
|
||||||
events.destroy.connect([this](const arg_destroy& arg){
|
value.evt_msenter = events.mouse_enter.connect(mouse_fn);
|
||||||
|
value.evt_msleave = events.mouse_leave.connect(mouse_fn);
|
||||||
|
value.evt_msdown = events.mouse_down.connect(mouse_fn);
|
||||||
|
|
||||||
|
value.evt_destroy = events.destroy.connect([this](const arg_destroy& arg){
|
||||||
_m_untip(arg.window_handle);
|
_m_untip(arg.window_handle);
|
||||||
});
|
});
|
||||||
|
|
||||||
cont_.emplace_back(wd, std::string());
|
return value;
|
||||||
return cont_.back();
|
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<tooltip_interface, deleter_type> window_;
|
std::unique_ptr<tooltip_interface, deleter_type> window_;
|
||||||
std::vector<pair_t> cont_;
|
std::map<window, tip_value> table_;
|
||||||
};
|
};
|
||||||
}//namespace tooltip
|
}//namespace tooltip
|
||||||
}//namespace drawerbase
|
}//namespace drawerbase
|
||||||
|
@ -136,8 +136,12 @@ namespace nana{
|
|||||||
{
|
{
|
||||||
_THROW_IF_EMPTY()
|
_THROW_IF_EMPTY()
|
||||||
|
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & opt = impl_->options.emplace_back(new checkbox{ handle() });
|
||||||
|
#else
|
||||||
impl_->options.emplace_back(new checkbox(handle()));
|
impl_->options.emplace_back(new checkbox(handle()));
|
||||||
auto & opt = impl_->options.back();
|
auto & opt = impl_->options.back();
|
||||||
|
#endif
|
||||||
opt->transparent(true);
|
opt->transparent(true);
|
||||||
opt->caption(std::move(text));
|
opt->caption(std::move(text));
|
||||||
impl_->place_content[field_options] << *opt;
|
impl_->place_content[field_options] << *opt;
|
||||||
|
@ -28,14 +28,28 @@ namespace nana
|
|||||||
{
|
{
|
||||||
class renderer
|
class renderer
|
||||||
{
|
{
|
||||||
typedef widgets::skeletons::dstream::linecontainer::iterator iterator;
|
//Iterator of content element in a line.
|
||||||
|
using content_element_iterator = widgets::skeletons::dstream::linecontainer::const_iterator; //subsitute for member type iterator
|
||||||
|
|
||||||
struct pixel_tag
|
struct visual_line //subsitute of pixel_tag
|
||||||
{
|
{
|
||||||
int x_base; //The x position where this line starts.
|
struct element
|
||||||
std::size_t pixels;
|
{
|
||||||
std::size_t baseline; //The baseline for drawing text.
|
content_element_iterator content_element;
|
||||||
std::vector<iterator> values; //line values
|
std::pair<std::size_t, std::size_t> range; //A part of text in a text element. first: text begin, second: text length
|
||||||
|
|
||||||
|
element(const content_element_iterator& iterator, std::size_t range_begin, std::size_t range_end):
|
||||||
|
content_element(iterator),
|
||||||
|
range(range_begin, range_end)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int x_base; //The x position where this line starts.
|
||||||
|
|
||||||
|
std::size_t extent_height_px;
|
||||||
|
std::size_t baseline; //The baseline for rendering text.
|
||||||
|
std::vector<element> elements; //description of text element in this rendering line.
|
||||||
};
|
};
|
||||||
|
|
||||||
//this is a helper variable, it just keeps the status while drawing.
|
//this is a helper variable, it just keeps the status while drawing.
|
||||||
@ -46,8 +60,8 @@ namespace nana
|
|||||||
align_v text_align_v;
|
align_v text_align_v;
|
||||||
|
|
||||||
nana::point pos;
|
nana::point pos;
|
||||||
std::vector<pixel_tag> pixels;
|
std::vector<visual_line> vslines; //The lines description of a line of text. substitute of member pixels.
|
||||||
std::size_t index;
|
std::size_t index; //indicates the current rendering visual line.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct traceable
|
struct traceable
|
||||||
@ -102,18 +116,19 @@ namespace nana
|
|||||||
rs.text_align = th;
|
rs.text_align = th;
|
||||||
rs.text_align_v = tv;
|
rs.text_align_v = tv;
|
||||||
|
|
||||||
std::deque<std::vector<pixel_tag> > pixel_lines;
|
//All visual lines data of whole text.
|
||||||
|
std::deque<std::vector<visual_line>> content_lines;
|
||||||
|
|
||||||
std::size_t extent_v_pixels = 0; //the pixels, in height, that text will be painted.
|
std::size_t extent_v_pixels = 0; //the pixels, in height, that text will be painted.
|
||||||
|
|
||||||
for (auto & line : dstream_)
|
for (auto & line : dstream_)
|
||||||
{
|
{
|
||||||
_m_line_pixels(line, def_line_pixels, rs);
|
_m_prepare_visual_lines(graph, line, def_line_pixels, rs);
|
||||||
|
|
||||||
for (auto & m : rs.pixels)
|
for (auto & vsline : rs.vslines)
|
||||||
extent_v_pixels += m.pixels;
|
extent_v_pixels += vsline.extent_height_px;
|
||||||
|
|
||||||
pixel_lines.emplace_back(std::move(rs.pixels));
|
content_lines.emplace_back(std::move(rs.vslines));
|
||||||
|
|
||||||
if(extent_v_pixels >= graph.height())
|
if(extent_v_pixels >= graph.height())
|
||||||
break;
|
break;
|
||||||
@ -129,25 +144,21 @@ namespace nana
|
|||||||
else
|
else
|
||||||
rs.pos.y = 0;
|
rs.pos.y = 0;
|
||||||
|
|
||||||
auto pixels_iterator = pixel_lines.begin();
|
auto vsline_iterator = content_lines.begin();
|
||||||
|
|
||||||
for (auto & line : dstream_)
|
for (auto & line : dstream_)
|
||||||
{
|
{
|
||||||
if (rs.pos.y >= static_cast<int>(graph.height()))
|
if (rs.pos.y >= static_cast<int>(graph.height()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
rs.index = 0;
|
rs.index = 0;
|
||||||
rs.pixels.clear();
|
rs.vslines.clear();
|
||||||
|
rs.vslines.swap(*vsline_iterator++);
|
||||||
|
rs.pos.x = rs.vslines.front().x_base;
|
||||||
|
|
||||||
rs.pixels.swap(*pixels_iterator++);
|
if (!_m_foreach_visual_line(graph, rs))
|
||||||
|
|
||||||
rs.pos.x = rs.pixels.front().x_base;
|
|
||||||
|
|
||||||
//Stop drawing when it goes out of range.
|
|
||||||
if(false == _m_each_line(graph, line, rs))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
rs.pos.y += static_cast<int>(rs.pixels.back().pixels);
|
rs.pos.y += static_cast<int>(rs.vslines.back().extent_height_px);
|
||||||
}
|
}
|
||||||
|
|
||||||
graph.typeface(pre_font);
|
graph.typeface(pre_font);
|
||||||
@ -194,8 +205,8 @@ namespace nana
|
|||||||
|
|
||||||
for(auto & line: dstream_)
|
for(auto & line: dstream_)
|
||||||
{
|
{
|
||||||
rs.pixels.clear();
|
rs.vslines.clear();
|
||||||
unsigned w = _m_line_pixels(line, def_line_pixels, rs);
|
auto w = _m_prepare_visual_lines(graph, line, def_line_pixels, rs);
|
||||||
|
|
||||||
if(limited && (w > limited))
|
if(limited && (w > limited))
|
||||||
w = limited;
|
w = limited;
|
||||||
@ -203,8 +214,8 @@ namespace nana
|
|||||||
if(retsize.width < w)
|
if(retsize.width < w)
|
||||||
retsize.width = w;
|
retsize.width = w;
|
||||||
|
|
||||||
for (auto & px : rs.pixels)
|
for (auto& vsline : rs.vslines)
|
||||||
retsize.height += static_cast<unsigned>(px.pixels);
|
retsize.height += static_cast<unsigned>(vsline.extent_height_px);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retsize;
|
return retsize;
|
||||||
@ -215,8 +226,12 @@ namespace nana
|
|||||||
{
|
{
|
||||||
if(fbp->target.size() || fbp->url.size())
|
if(fbp->target.size() || fbp->url.size())
|
||||||
{
|
{
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & tr = traceable_.emplace_back();
|
||||||
|
#else
|
||||||
traceable_.emplace_back();
|
traceable_.emplace_back();
|
||||||
auto & tr = traceable_.back();
|
auto & tr = traceable_.back();
|
||||||
|
#endif
|
||||||
tr.r.x = x;
|
tr.r.x = x;
|
||||||
tr.r.y = y;
|
tr.r.y = y;
|
||||||
tr.r.dimension(sz);
|
tr.r.dimension(sz);
|
||||||
@ -315,291 +330,287 @@ namespace nana
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _m_align_x_base(const render_status& rs, pixel_tag & px, unsigned w) noexcept
|
void _m_prepare_x(const render_status& rs, visual_line & vsline, unsigned w) noexcept
|
||||||
{
|
{
|
||||||
switch(rs.text_align)
|
switch (rs.text_align)
|
||||||
{
|
{
|
||||||
case align::left:
|
case align::left:
|
||||||
px.x_base = 0;
|
vsline.x_base = 0;
|
||||||
break;
|
break;
|
||||||
case align::center:
|
case align::center:
|
||||||
px.x_base = (static_cast<int>(rs.allowed_width - w) >> 1);
|
vsline.x_base = (static_cast<int>(rs.allowed_width - w) >> 1);
|
||||||
break;
|
break;
|
||||||
case align::right:
|
case align::right:
|
||||||
px.x_base = static_cast<int>(rs.allowed_width - w);
|
vsline.x_base = static_cast<int>(rs.allowed_width - w);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned _m_line_pixels(dstream::linecontainer& line, unsigned def_line_pixels, render_status & rs)
|
/**
|
||||||
|
* prepare data for rendering a line of text.
|
||||||
|
*/
|
||||||
|
unsigned _m_prepare_visual_lines(graph_reference graph, dstream::linecontainer& line, unsigned def_line_px, render_status& rs)
|
||||||
{
|
{
|
||||||
if (line.empty())
|
unsigned abs_text_px = 0;
|
||||||
{
|
|
||||||
pixel_tag px;
|
|
||||||
px.baseline = 0;
|
|
||||||
px.pixels = def_line_pixels;
|
|
||||||
px.x_base = 0;
|
|
||||||
|
|
||||||
rs.pixels.emplace_back(px);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned total_w = 0;
|
|
||||||
unsigned w = 0;
|
|
||||||
unsigned max_ascent = 0;
|
unsigned max_ascent = 0;
|
||||||
unsigned max_descent = 0;
|
unsigned max_descent = 0;
|
||||||
unsigned max_px = 0;
|
unsigned max_content_height = 0;
|
||||||
|
|
||||||
//Bidi reorder is requried here
|
int text_pos = 0;
|
||||||
|
|
||||||
std::vector<iterator> line_values;
|
std::vector<visual_line::element> vsline_elements;
|
||||||
|
|
||||||
for(auto i = line.begin(); i != line.end(); ++i)
|
for (auto i = line.cbegin(); i != line.cend(); ++i)
|
||||||
{
|
{
|
||||||
data * data_ptr = i->data_ptr;
|
auto const data = i->data_ptr;
|
||||||
nana::size sz = data_ptr->size();
|
auto fblock = i->fblock_ptr;
|
||||||
total_w += sz.width;
|
|
||||||
|
|
||||||
unsigned as = 0; //ascent
|
abs_text_px += data->size().width;
|
||||||
unsigned ds = 0; //descent
|
|
||||||
|
|
||||||
if(fblock::aligns::baseline == i->fblock_ptr->text_align)
|
unsigned ascent = 0;
|
||||||
|
unsigned descent = 0;
|
||||||
|
|
||||||
|
|
||||||
|
auto extent_size = data->size();
|
||||||
|
|
||||||
|
//Check if the content is displayed in current line.
|
||||||
|
if ((0 == rs.allowed_width) || (text_pos + extent_size.width <= rs.allowed_width))
|
||||||
{
|
{
|
||||||
as = static_cast<unsigned>(data_ptr->ascent());
|
text_pos += static_cast<int>(extent_size.width);
|
||||||
ds = static_cast<unsigned>(sz.height - as);
|
|
||||||
|
|
||||||
if(max_descent < ds)
|
//Adjust height of extent_size for special text alignement.
|
||||||
max_descent = ds;
|
if (fblock::aligns::baseline == fblock->text_align)
|
||||||
|
|
||||||
if((false == data_ptr->is_text()) && (sz.height < max_ascent + max_descent))
|
|
||||||
sz.height = max_ascent + max_descent;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if the content is displayed in a new line.
|
|
||||||
if((0 == rs.allowed_width) || (w + sz.width <= rs.allowed_width))
|
|
||||||
{
|
|
||||||
w += sz.width;
|
|
||||||
|
|
||||||
if(max_ascent < as) max_ascent = as;
|
|
||||||
if(max_descent < ds) max_descent = ds;
|
|
||||||
if(max_px < sz.height) max_px = sz.height;
|
|
||||||
line_values.emplace_back(i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pixel_tag px;
|
|
||||||
_m_align_x_base(rs, px, (w ? w : sz.width));
|
|
||||||
|
|
||||||
if(w)
|
|
||||||
{
|
{
|
||||||
if(max_ascent + max_descent > max_px)
|
ascent = static_cast<unsigned>(data->ascent());
|
||||||
max_px = max_descent + max_ascent;
|
descent = static_cast<unsigned>(extent_size.height - ascent);
|
||||||
else
|
|
||||||
max_ascent = max_px - max_descent;
|
|
||||||
|
|
||||||
px.pixels = max_px;
|
if (max_descent < descent)
|
||||||
px.baseline = max_ascent;
|
max_descent = descent;
|
||||||
px.values.swap(line_values);
|
|
||||||
|
|
||||||
w = sz.width;
|
if ((false == data->is_text()) && (extent_size.height < max_ascent + max_descent))
|
||||||
max_px = sz.height;
|
extent_size.height = max_ascent + max_descent;
|
||||||
max_ascent = as;
|
|
||||||
max_descent = ds;
|
|
||||||
line_values.emplace_back(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_ascent < ascent) max_ascent = ascent;
|
||||||
|
if (max_descent < descent) max_descent = descent;
|
||||||
|
if (max_content_height < extent_size.height) max_content_height = extent_size.height;
|
||||||
|
vsline_elements.emplace_back(i, 0, data->text().size());
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//make a visual line for existing vsline elements
|
||||||
|
if (text_pos)
|
||||||
|
{
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & vsline = rs.vslines.emplace_back();
|
||||||
|
#else
|
||||||
|
rs.vslines.emplace_back();
|
||||||
|
auto & vsline = rs.vslines.back();
|
||||||
|
#endif
|
||||||
|
_m_prepare_x(rs, vsline, static_cast<unsigned>(text_pos));
|
||||||
|
|
||||||
|
if (max_ascent + max_descent > max_content_height)
|
||||||
|
max_content_height = max_descent + max_ascent;
|
||||||
else
|
else
|
||||||
|
max_ascent = max_content_height - max_descent;
|
||||||
|
|
||||||
|
vsline.extent_height_px = max_content_height;
|
||||||
|
vsline.baseline = max_ascent;
|
||||||
|
vsline.elements.swap(vsline_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
text_pos = 0;
|
||||||
|
max_content_height = max_ascent = max_descent = 0;
|
||||||
|
//Adjust height of extent_size for special text alignement.
|
||||||
|
if (fblock::aligns::baseline == fblock->text_align)
|
||||||
|
{
|
||||||
|
ascent = static_cast<unsigned>(data->ascent());
|
||||||
|
descent = static_cast<unsigned>(extent_size.height - ascent);
|
||||||
|
|
||||||
|
if (max_descent < descent)
|
||||||
|
max_descent = descent;
|
||||||
|
|
||||||
|
if ((false == data->is_text()) && (extent_size.height < max_ascent + max_descent))
|
||||||
|
extent_size.height = max_ascent + max_descent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_ascent < ascent) max_ascent = ascent;
|
||||||
|
if (max_descent < descent) max_descent = descent;
|
||||||
|
if (max_content_height < extent_size.height) max_content_height = extent_size.height;
|
||||||
|
|
||||||
|
if (data->is_text())
|
||||||
|
{
|
||||||
|
_m_change_font(graph, fblock);
|
||||||
|
//Split a text into multiple lines
|
||||||
|
auto rest_extent_size = extent_size.width;
|
||||||
|
std::size_t text_begin = 0;
|
||||||
|
while (text_begin < data->text().size())
|
||||||
{
|
{
|
||||||
px.pixels = sz.height;
|
unsigned sub_text_px = 0;
|
||||||
px.baseline = as;
|
auto sub_text_len = _m_fit_text(graph, data->text().substr(text_begin), rs.allowed_width, sub_text_px);
|
||||||
|
|
||||||
px.values.emplace_back(i);
|
if (text_begin + sub_text_len < data->text().size())
|
||||||
|
{
|
||||||
|
//make a new visual line
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & vsline = rs.vslines.emplace_back();
|
||||||
|
#else
|
||||||
|
rs.vslines.emplace_back();
|
||||||
|
auto & vsline = rs.vslines.back();
|
||||||
|
#endif
|
||||||
|
_m_prepare_x(rs, vsline, sub_text_px);
|
||||||
|
|
||||||
max_px = 0;
|
vsline.extent_height_px = max_content_height;
|
||||||
max_ascent = max_descent = 0;
|
vsline.baseline = max_ascent;
|
||||||
|
vsline.elements.emplace_back(i, text_begin, sub_text_len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//the last part, write it to vsline_elements to keep the status for next line element(next i)
|
||||||
|
vsline_elements.emplace_back(i, text_begin, sub_text_len);
|
||||||
|
|
||||||
|
text_pos = sub_text_px;
|
||||||
|
}
|
||||||
|
|
||||||
|
text_begin += sub_text_len;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//the last part, write it to vsline_elements to keep the status for next line element(next i)
|
||||||
|
vsline_elements.emplace_back(i, 0, 0);
|
||||||
|
|
||||||
rs.pixels.emplace_back(px);
|
text_pos = static_cast<int>(i->data_ptr->size().width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_px)
|
if (!vsline_elements.empty())
|
||||||
{
|
{
|
||||||
pixel_tag px;
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & vsline = rs.vslines.emplace_back();
|
||||||
|
#else
|
||||||
|
rs.vslines.emplace_back();
|
||||||
|
auto & vsline = rs.vslines.back();
|
||||||
|
#endif
|
||||||
|
_m_prepare_x(rs, vsline, static_cast<unsigned>(text_pos));
|
||||||
|
|
||||||
_m_align_x_base(rs, px, w);
|
if (max_ascent + max_descent > max_content_height)
|
||||||
|
max_content_height = max_descent + max_ascent;
|
||||||
if (max_ascent + max_descent > max_px)
|
|
||||||
max_px = max_descent + max_ascent;
|
|
||||||
else
|
else
|
||||||
max_ascent = max_px - max_descent;
|
max_ascent = max_content_height - max_descent;
|
||||||
|
|
||||||
px.pixels = max_px;
|
vsline.extent_height_px = max_content_height;
|
||||||
px.baseline = max_ascent;
|
vsline.baseline = max_ascent;
|
||||||
px.values.swap(line_values);
|
vsline.elements.swap(vsline_elements);
|
||||||
rs.pixels.emplace_back(px);
|
|
||||||
}
|
}
|
||||||
return total_w;
|
|
||||||
|
return abs_text_px;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _m_each_line(graph_reference graph, dstream::linecontainer&, render_status& rs)
|
//Get the length of characters in a text whose length in pixels doesn't beyond the limited width.
|
||||||
|
static unsigned _m_fit_text(graph_reference graph, const std::wstring& text, unsigned limited_width_px, unsigned& text_px) noexcept
|
||||||
|
{
|
||||||
|
#ifdef _nana_std_has_string_view
|
||||||
|
auto pxbuf = graph.glyph_pixels(text);
|
||||||
|
#else
|
||||||
|
std::unique_ptr<unsigned[]> pxbuf(new unsigned[text.size()]);
|
||||||
|
graph.glyph_pixels(text.c_str(), text.size(), pxbuf.get());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
text_px = 0;
|
||||||
|
for (unsigned i = 0; i < text.size(); ++i)
|
||||||
|
{
|
||||||
|
if (text_px + pxbuf[i] > limited_width_px)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
text_px += pxbuf[i];
|
||||||
|
}
|
||||||
|
return static_cast<unsigned>(text.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _m_foreach_visual_line(graph_reference graph, render_status& rs)
|
||||||
{
|
{
|
||||||
std::wstring text;
|
std::wstring text;
|
||||||
iterator block_start;
|
|
||||||
|
content_element_iterator block_start;
|
||||||
|
|
||||||
const int lastpos = static_cast<int>(graph.height()) - 1;
|
auto const bottom = static_cast<int>(graph.height()) - 1;
|
||||||
|
|
||||||
for(auto & px : rs.pixels)
|
for (auto & vsline : rs.vslines)
|
||||||
{
|
{
|
||||||
for(auto & render_iterator: px.values)
|
rs.pos.x = vsline.x_base;
|
||||||
|
for (auto& content_elm : vsline.elements)
|
||||||
{
|
{
|
||||||
auto & value = *render_iterator;
|
_m_draw_vsline_element(graph, content_elm, rs);
|
||||||
if (value.data_ptr->is_text())
|
|
||||||
{
|
|
||||||
//hold the block while the text is empty,
|
|
||||||
//it stands for the first block
|
|
||||||
if (text.empty())
|
|
||||||
block_start = render_iterator;
|
|
||||||
|
|
||||||
text += value.data_ptr->text();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(text.size())
|
|
||||||
{
|
|
||||||
_m_draw_block(graph, text, block_start, rs);
|
|
||||||
if(lastpos <= rs.pos.y)
|
|
||||||
return false;
|
|
||||||
text.clear();
|
|
||||||
}
|
|
||||||
nana::size sz = value.data_ptr->size();
|
|
||||||
|
|
||||||
pixel_tag px = rs.pixels[rs.index];
|
|
||||||
if ((rs.allowed_width < rs.pos.x + sz.width) && (rs.pos.x != px.x_base))
|
|
||||||
{
|
|
||||||
//Change a line.
|
|
||||||
rs.pos.y += static_cast<int>(px.pixels);
|
|
||||||
px = rs.pixels[++rs.index];
|
|
||||||
rs.pos.x = px.x_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
int y = rs.pos.y + _m_text_top(px, value.fblock_ptr, value.data_ptr);
|
|
||||||
|
|
||||||
value.data_ptr->nontext_render(graph, rs.pos.x, y);
|
|
||||||
_m_insert_if_traceable(rs.pos.x, y, sz, value.fblock_ptr);
|
|
||||||
rs.pos.x += static_cast<int>(sz.width);
|
|
||||||
|
|
||||||
if(lastpos < y)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(text.size())
|
++rs.index; //next line index
|
||||||
{
|
rs.pos.y += static_cast<int>(vsline.extent_height_px);
|
||||||
_m_draw_block(graph, text, block_start, rs);
|
|
||||||
text.clear();
|
if (rs.pos.y > bottom)
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
return (rs.pos.y <= lastpos);
|
|
||||||
|
return (rs.pos.y <= bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _m_overline(const render_status& rs, int right, bool equal_required) noexcept
|
static int _m_vsline_element_top(const visual_line& vsline, fblock* fblock_ptr, const data* data_ptr) noexcept
|
||||||
{
|
{
|
||||||
if(align::left == rs.text_align)
|
switch (fblock_ptr->text_align)
|
||||||
return (equal_required ? right >= static_cast<int>(rs.allowed_width) : right > static_cast<int>(rs.allowed_width));
|
|
||||||
|
|
||||||
return (equal_required ? rs.pixels[rs.index].x_base <= 0 : rs.pixels[rs.index].x_base < 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _m_text_top(const pixel_tag& px, fblock* fblock_ptr, const data* data_ptr)
|
|
||||||
{
|
|
||||||
switch(fblock_ptr->text_align)
|
|
||||||
{
|
{
|
||||||
case fblock::aligns::center:
|
case fblock::aligns::center:
|
||||||
return static_cast<int>(px.pixels - data_ptr->size().height) / 2;
|
return static_cast<int>(vsline.extent_height_px - data_ptr->size().height) / 2;
|
||||||
case fblock::aligns::bottom:
|
case fblock::aligns::bottom:
|
||||||
return static_cast<int>(px.pixels - data_ptr->size().height);
|
return static_cast<int>(vsline.extent_height_px - data_ptr->size().height);
|
||||||
case fblock::aligns::baseline:
|
case fblock::aligns::baseline:
|
||||||
return static_cast<int>(px.baseline - (data_ptr->is_text() ? data_ptr->ascent() : data_ptr->size().height));
|
return static_cast<int>(vsline.baseline - (data_ptr->is_text() ? data_ptr->ascent() : data_ptr->size().height));
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _m_draw_block(graph_reference graph, const std::wstring& s, dstream::linecontainer::iterator block_start, render_status& rs)
|
void _m_draw_vsline_element(graph_reference graph, const visual_line::element& vsline_elm, render_status& rs)
|
||||||
{
|
{
|
||||||
auto const reordered = unicode_reorder(s.data(), s.length());
|
auto data = vsline_elm.content_element->data_ptr;
|
||||||
|
auto fblock = vsline_elm.content_element->fblock_ptr;
|
||||||
|
|
||||||
pixel_tag px = rs.pixels[rs.index];
|
if (data->is_text())
|
||||||
|
|
||||||
for(auto & bidi : reordered)
|
|
||||||
{
|
{
|
||||||
std::size_t pos = bidi.begin - s.data();
|
auto const text = data->text().c_str() + vsline_elm.range.first;
|
||||||
std::size_t len = bidi.end - bidi.begin;
|
auto const reordered = unicode_reorder(text, vsline_elm.range.second);
|
||||||
|
|
||||||
while (true)
|
_m_change_font(graph, fblock);
|
||||||
|
for (auto & bidi : reordered)
|
||||||
{
|
{
|
||||||
auto i = block_start;
|
auto extent_size = data->size();
|
||||||
|
|
||||||
//Text range indicates the position of text where begin to output
|
|
||||||
//The output length is the min between len and the second of text range.
|
|
||||||
auto text_range = _m_locate(i, pos);
|
|
||||||
|
|
||||||
if (text_range.second > len)
|
|
||||||
text_range.second = len;
|
|
||||||
|
|
||||||
fblock * fblock_ptr = i->fblock_ptr;
|
|
||||||
data * data_ptr = i->data_ptr;
|
|
||||||
|
|
||||||
const int w = static_cast<int>(rs.allowed_width) - rs.pos.x;
|
|
||||||
nana::size sz = data_ptr->size();
|
|
||||||
if ((static_cast<int>(sz.width) > w) && (rs.pos.x != px.x_base))
|
|
||||||
{
|
|
||||||
//Change a new line
|
|
||||||
rs.pos.y += static_cast<int>(px.pixels);
|
|
||||||
px = rs.pixels[++rs.index];
|
|
||||||
rs.pos.x = px.x_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int y = rs.pos.y + _m_text_top(px, fblock_ptr, data_ptr);
|
|
||||||
|
|
||||||
_m_change_font(graph, fblock_ptr);
|
|
||||||
|
|
||||||
#ifdef _nana_std_has_string_view
|
#ifdef _nana_std_has_string_view
|
||||||
std::wstring_view text_sv{ data_ptr->text() };
|
std::wstring_view text_sv{ bidi.begin, static_cast<std::size_t>(bidi.end - bidi.begin) };
|
||||||
if (text_range.second != text_sv.size())
|
if (data->text().size() != text_sv.size())
|
||||||
{
|
extent_size = graph.text_extent_size(text_sv);
|
||||||
text_sv = text_sv.substr(text_range.first, text_range.second);
|
|
||||||
sz = graph.text_extent_size(text_sv);
|
|
||||||
}
|
|
||||||
|
|
||||||
graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock_ptr));
|
const int y = rs.pos.y + _m_vsline_element_top(rs.vslines[rs.index], fblock, data);
|
||||||
|
graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock));
|
||||||
#else
|
#else
|
||||||
if (text_range.second == data_ptr->text().length())
|
std::wstring text{ bidi.begin, static_cast<std::size_t>(bidi.end - bidi.begin) };
|
||||||
{
|
if (data->text().size() != text.size())
|
||||||
graph.string({ rs.pos.x, y }, data_ptr->text(), _m_fgcolor(fblock_ptr));
|
extent_size = graph.text_extent_size(text);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto str = data_ptr->text().substr(text_range.first, text_range.second);
|
|
||||||
sz = graph.text_extent_size(str);
|
|
||||||
|
|
||||||
graph.string({ rs.pos.x, y }, str, _m_fgcolor(fblock_ptr));
|
const int y = rs.pos.y + _m_vsline_element_top(rs.vslines[rs.index], fblock, data);
|
||||||
}
|
graph.string({ rs.pos.x, y }, text, _m_fgcolor(fblock));
|
||||||
#endif
|
#endif
|
||||||
|
_m_insert_if_traceable(rs.pos.x, y, extent_size, fblock);
|
||||||
|
rs.pos.x += static_cast<int>(extent_size.width);
|
||||||
_m_insert_if_traceable(rs.pos.x, y, sz, fblock_ptr);
|
|
||||||
rs.pos.x += static_cast<int>(sz.width);
|
|
||||||
|
|
||||||
if(text_range.second < len)
|
|
||||||
{
|
|
||||||
len -= text_range.second;
|
|
||||||
pos += text_range.second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int y = rs.pos.y + _m_vsline_element_top(rs.vslines[rs.index], fblock, data);
|
||||||
|
|
||||||
|
data->nontext_render(graph, rs.pos.x, y);
|
||||||
|
_m_insert_if_traceable(rs.pos.x, y, data->size(), fblock);
|
||||||
|
rs.pos.x += static_cast<int>(data->size().width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos)
|
static std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos)
|
||||||
|
@ -312,8 +312,12 @@ namespace nana
|
|||||||
|
|
||||||
size_type create(essence* ess, native_string_type&& text, unsigned pixels)
|
size_type create(essence* ess, native_string_type&& text, unsigned pixels)
|
||||||
{
|
{
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
return cont_.emplace_back(ess, std::move(text), pixels, static_cast<size_type>(cont_.size())).index;
|
||||||
|
#else
|
||||||
cont_.emplace_back(ess, std::move(text), pixels, static_cast<size_type>(cont_.size()));
|
cont_.emplace_back(ess, std::move(text), pixels, static_cast<size_type>(cont_.size()));
|
||||||
return cont_.back().index;
|
return cont_.back().index;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
@ -1023,9 +1027,15 @@ namespace nana
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & last_cat = categories_.emplace_back();
|
||||||
|
last_cat.key_ptr = ptr;
|
||||||
|
return &last_cat;
|
||||||
|
#else
|
||||||
categories_.emplace_back();
|
categories_.emplace_back();
|
||||||
categories_.back().key_ptr = ptr;
|
categories_.back().key_ptr = ptr;
|
||||||
return &(categories_.back());
|
return &(categories_.back());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a new category at position specified by pos
|
/// Inserts a new category at position specified by pos
|
||||||
@ -1033,8 +1043,12 @@ namespace nana
|
|||||||
{
|
{
|
||||||
if (::nana::npos == pos)
|
if (::nana::npos == pos)
|
||||||
{
|
{
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
return &categories_.emplace_back(std::move(text));
|
||||||
|
#else
|
||||||
categories_.emplace_back(std::move(text));
|
categories_.emplace_back(std::move(text));
|
||||||
return &categories_.back();
|
return &categories_.back();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return &(*categories_.emplace(this->get(pos), std::move(text)));
|
return &(*categories_.emplace(this->get(pos), std::move(text)));
|
||||||
@ -2622,8 +2636,12 @@ namespace nana
|
|||||||
|
|
||||||
oresolver& oresolver::operator<<(std::nullptr_t)
|
oresolver& oresolver::operator<<(std::nullptr_t)
|
||||||
{
|
{
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
cells_.emplace_back().text.assign(1, wchar_t{});
|
||||||
|
#else
|
||||||
cells_.emplace_back();
|
cells_.emplace_back();
|
||||||
cells_.back().text.assign(1, wchar_t(0)); //means invalid cell
|
cells_.back().text.assign(1, wchar_t(0)); //means invalid cell
|
||||||
|
#endif
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +89,18 @@ namespace nana
|
|||||||
|
|
||||||
if (shortkey && shortkey < 0x61)
|
if (shortkey && shortkey < 0x61)
|
||||||
shortkey += (0x61 - 0x41);
|
shortkey += (0x61 - 0x41);
|
||||||
|
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & last = items.emplace_back(new item_type{std::move(transformed_text), shortkey, shortkey_pos});
|
||||||
|
API::refresh_window(*widget_ptr);
|
||||||
|
return last->menu_obj;
|
||||||
|
#else
|
||||||
items.emplace_back(new item_type{ std::move(transformed_text), shortkey, shortkey_pos });
|
items.emplace_back(new item_type{ std::move(transformed_text), shortkey, shortkey_pos });
|
||||||
|
|
||||||
API::refresh_window(*widget_ptr);
|
API::refresh_window(*widget_ptr);
|
||||||
|
|
||||||
return this->items.back()->menu_obj;
|
return this->items.back()->menu_obj;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cancel()
|
bool cancel()
|
||||||
|
@ -199,7 +199,7 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
editor_.select_.a = sel_a_;
|
editor_.select_.a = sel_a_;
|
||||||
editor_.select_.b = sel_b_;
|
editor_.select_.b = sel_b_;
|
||||||
editor_._m_erase_select();
|
editor_._m_erase_select(false);
|
||||||
editor_.select_.a = editor_.select_.b;
|
editor_.select_.a = editor_.select_.b;
|
||||||
editor_.points_.caret = sel_a_;
|
editor_.points_.caret = sel_a_;
|
||||||
}
|
}
|
||||||
@ -208,7 +208,7 @@ namespace nana{ namespace widgets
|
|||||||
if (is_enter)
|
if (is_enter)
|
||||||
{
|
{
|
||||||
editor_.points_.caret = nana::upoint(0, pos_.y + 1);
|
editor_.points_.caret = nana::upoint(0, pos_.y + 1);
|
||||||
editor_.backspace(false);
|
editor_.backspace(false, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
editor_.textbase().erase(pos_.y, pos_.x, selected_text_.size());
|
editor_.textbase().erase(pos_.y, pos_.x, selected_text_.size());
|
||||||
@ -218,11 +218,11 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
if (is_enter)
|
if (is_enter)
|
||||||
{
|
{
|
||||||
editor_.enter(false);
|
editor_.enter(false, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
editor_._m_put(selected_text_);
|
editor_._m_put(selected_text_, false);
|
||||||
if (sel_a_ != sel_b_)
|
if (sel_a_ != sel_b_)
|
||||||
{
|
{
|
||||||
editor_.select_.a = sel_a_;
|
editor_.select_.a = sel_a_;
|
||||||
@ -234,6 +234,8 @@ namespace nana{ namespace widgets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editor_.textbase().text_changed();
|
||||||
|
|
||||||
editor_.reset_caret();
|
editor_.reset_caret();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -258,7 +260,7 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
if (is_enter)
|
if (is_enter)
|
||||||
{
|
{
|
||||||
editor_.enter(false);
|
editor_.enter(false, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -266,9 +268,9 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
editor_.select_.a = sel_a_;
|
editor_.select_.a = sel_a_;
|
||||||
editor_.select_.b = sel_b_;
|
editor_.select_.b = sel_b_;
|
||||||
editor_._m_erase_select();
|
editor_._m_erase_select(false);
|
||||||
}
|
}
|
||||||
editor_.points_.caret = editor_._m_put(text_); //redo
|
editor_.points_.caret = editor_._m_put(text_, false); //redo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -277,7 +279,7 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
editor_.points_.caret.x = 0;
|
editor_.points_.caret.x = 0;
|
||||||
++editor_.points_.caret.y;
|
++editor_.points_.caret.y;
|
||||||
editor_.backspace(false);
|
editor_.backspace(false, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -286,7 +288,7 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
editor_.select_.a = pos_;
|
editor_.select_.a = pos_;
|
||||||
editor_.select_.b = upoint(static_cast<unsigned>(lines.back().second - lines.back().first), static_cast<unsigned>(pos_.y + lines.size() - 1));
|
editor_.select_.b = upoint(static_cast<unsigned>(lines.back().second - lines.back().first), static_cast<unsigned>(pos_.y + lines.size() - 1));
|
||||||
editor_.backspace(false);
|
editor_.backspace(false, false);
|
||||||
editor_.select_.a = editor_.select_.b;
|
editor_.select_.a = editor_.select_.b;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -296,12 +298,14 @@ namespace nana{ namespace widgets
|
|||||||
if (!selected_text_.empty())
|
if (!selected_text_.empty())
|
||||||
{
|
{
|
||||||
editor_.points_.caret = (std::min)(sel_a_, sel_b_);
|
editor_.points_.caret = (std::min)(sel_a_, sel_b_);
|
||||||
editor_._m_put(selected_text_);
|
editor_._m_put(selected_text_, false);
|
||||||
editor_.points_.caret = sel_b_;
|
editor_.points_.caret = sel_b_;
|
||||||
editor_.select_.a = sel_a_; //Reset the selected text
|
editor_.select_.a = sel_a_; //Reset the selected text
|
||||||
editor_.select_.b = sel_b_;
|
editor_.select_.b = sel_b_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editor_.textbase().text_changed();
|
||||||
editor_.reset_caret();
|
editor_.reset_caret();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@ -333,8 +337,8 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
const auto text = editor_._m_make_select_string();
|
const auto text = editor_._m_make_select_string();
|
||||||
|
|
||||||
editor_._m_erase_select();
|
editor_._m_erase_select(false);
|
||||||
editor_._m_put(text);
|
editor_._m_put(text, false);
|
||||||
|
|
||||||
editor_.select_.a = sel_a_;
|
editor_.select_.a = sel_a_;
|
||||||
editor_.select_.b = sel_b_;
|
editor_.select_.b = sel_b_;
|
||||||
@ -342,6 +346,7 @@ namespace nana{ namespace widgets
|
|||||||
editor_.points_.caret = sel_b_;
|
editor_.points_.caret = sel_b_;
|
||||||
editor_.reset_caret();
|
editor_.reset_caret();
|
||||||
}
|
}
|
||||||
|
editor_.textbase().text_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_destination(const nana::upoint& dest_a, const nana::upoint& dest_b)
|
void set_destination(const nana::upoint& dest_a, const nana::upoint& dest_b)
|
||||||
@ -1004,8 +1009,12 @@ namespace nana{ namespace widgets
|
|||||||
auto ki = keywords.schemes.find(ds.scheme);
|
auto ki = keywords.schemes.find(ds.scheme);
|
||||||
if ((ki != keywords.schemes.end()) && ki->second)
|
if ((ki != keywords.schemes.end()) && ki->second)
|
||||||
{
|
{
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & last = entities.emplace_back();
|
||||||
|
#else
|
||||||
entities.emplace_back();
|
entities.emplace_back();
|
||||||
auto & last = entities.back();
|
auto & last = entities.back();
|
||||||
|
#endif
|
||||||
last.begin = c_str + pos;
|
last.begin = c_str + pos;
|
||||||
last.end = last.begin + ds.text.size();
|
last.end = last.begin + ds.text.size();
|
||||||
last.scheme = ki->second.get();
|
last.scheme = ki->second.get();
|
||||||
@ -1192,9 +1201,9 @@ namespace nana{ namespace widgets
|
|||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case '\b':
|
case '\b':
|
||||||
backspace(); break;
|
backspace(true, true); break;
|
||||||
case '\n': case '\r':
|
case '\n': case '\r':
|
||||||
enter(); break;
|
enter(true, true); break;
|
||||||
case keyboard::sync_idel:
|
case keyboard::sync_idel:
|
||||||
paste(); break;
|
paste(); break;
|
||||||
case keyboard::tab:
|
case keyboard::tab:
|
||||||
@ -1681,7 +1690,7 @@ namespace nana{ namespace widgets
|
|||||||
auto undo_ptr = std::unique_ptr<undo_input_text>{ new undo_input_text(*this, str) };
|
auto undo_ptr = std::unique_ptr<undo_input_text>{ new undo_input_text(*this, str) };
|
||||||
undo_ptr->set_caret_pos();
|
undo_ptr->set_caret_pos();
|
||||||
|
|
||||||
_m_put(std::move(str));
|
_m_put(std::move(str), false);
|
||||||
|
|
||||||
impl_->undo.push(std::move(undo_ptr));
|
impl_->undo.push(std::move(undo_ptr));
|
||||||
|
|
||||||
@ -1698,7 +1707,9 @@ namespace nana{ namespace widgets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
put(std::move(str));
|
put(std::move(str), false);
|
||||||
|
|
||||||
|
textbase().text_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring text_editor::text() const
|
std::wstring text_editor::text() const
|
||||||
@ -1904,6 +1915,7 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
if (_m_move_select(true))
|
if (_m_move_select(true))
|
||||||
{
|
{
|
||||||
|
textbase().text_changed();
|
||||||
this->_m_adjust_view();
|
this->_m_adjust_view();
|
||||||
impl_->try_refresh = sync_graph::refresh;
|
impl_->try_refresh = sync_graph::refresh;
|
||||||
return true;
|
return true;
|
||||||
@ -2021,7 +2033,7 @@ namespace nana{ namespace widgets
|
|||||||
impl_->try_refresh = sync_graph::none;
|
impl_->try_refresh = sync_graph::none;
|
||||||
}
|
}
|
||||||
//public:
|
//public:
|
||||||
void text_editor::put(std::wstring text)
|
void text_editor::put(std::wstring text, bool perform_event)
|
||||||
{
|
{
|
||||||
if (text.empty())
|
if (text.empty())
|
||||||
return;
|
return;
|
||||||
@ -2032,14 +2044,16 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
//Do not forget to assign the _m_erase_select() to caret
|
//Do not forget to assign the _m_erase_select() to caret
|
||||||
//because _m_put() will insert the text at the position where the caret is.
|
//because _m_put() will insert the text at the position where the caret is.
|
||||||
points_.caret = _m_erase_select();
|
points_.caret = _m_erase_select(false);
|
||||||
|
|
||||||
undo_ptr->set_caret_pos();
|
undo_ptr->set_caret_pos();
|
||||||
points_.caret = _m_put(std::move(text));
|
points_.caret = _m_put(std::move(text), false);
|
||||||
|
|
||||||
impl_->undo.push(std::move(undo_ptr));
|
impl_->undo.push(std::move(undo_ptr));
|
||||||
|
|
||||||
_m_reset_content_size(true);
|
_m_reset_content_size(true);
|
||||||
|
if (perform_event)
|
||||||
|
textbase().text_changed();
|
||||||
|
|
||||||
if(graph_)
|
if(graph_)
|
||||||
{
|
{
|
||||||
@ -2060,7 +2074,7 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
undo_ptr->set_selected_text();
|
undo_ptr->set_selected_text();
|
||||||
if(refresh)
|
if(refresh)
|
||||||
points_.caret = _m_erase_select();
|
points_.caret = _m_erase_select(false);
|
||||||
|
|
||||||
undo_ptr->set_caret_pos();
|
undo_ptr->set_caret_pos();
|
||||||
|
|
||||||
@ -2070,6 +2084,8 @@ namespace nana{ namespace widgets
|
|||||||
textbase().insert(points_.caret, std::move(ch_str));
|
textbase().insert(points_.caret, std::move(ch_str));
|
||||||
_m_pre_calc_lines(points_.caret.y, 1);
|
_m_pre_calc_lines(points_.caret.y, 1);
|
||||||
|
|
||||||
|
textbase().text_changed();
|
||||||
|
|
||||||
points_.caret.x ++;
|
points_.caret.x ++;
|
||||||
|
|
||||||
_m_reset_content_size();
|
_m_reset_content_size();
|
||||||
@ -2086,6 +2102,10 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
void text_editor::copy() const
|
void text_editor::copy() const
|
||||||
{
|
{
|
||||||
|
//Disallows copying text if the text_editor is masked.
|
||||||
|
if (mask_char_)
|
||||||
|
return;
|
||||||
|
|
||||||
auto text = _m_make_select_string();
|
auto text = _m_make_select_string();
|
||||||
if (!text.empty())
|
if (!text.empty())
|
||||||
nana::system::dataexch().set(text, API::root(this->window_));
|
nana::system::dataexch().set(text, API::root(this->window_));
|
||||||
@ -2103,7 +2123,7 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
if ((accepts::no_restrict == impl_->capacities.acceptive) || !impl_->capacities.pred_acceptive)
|
if ((accepts::no_restrict == impl_->capacities.acceptive) || !impl_->capacities.pred_acceptive)
|
||||||
{
|
{
|
||||||
put(move(text));
|
put(move(text), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2121,13 +2141,13 @@ namespace nana{ namespace widgets
|
|||||||
if (accepts::no_restrict != impl_->capacities.acceptive)
|
if (accepts::no_restrict != impl_->capacities.acceptive)
|
||||||
{
|
{
|
||||||
text.erase(i, text.end());
|
text.erase(i, text.end());
|
||||||
put(move(text));
|
put(move(text), true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void text_editor::enter(bool record_undo)
|
void text_editor::enter(bool record_undo, bool perform_event)
|
||||||
{
|
{
|
||||||
if(false == attributes_.multi_lines)
|
if(false == attributes_.multi_lines)
|
||||||
return;
|
return;
|
||||||
@ -2135,7 +2155,7 @@ namespace nana{ namespace widgets
|
|||||||
auto undo_ptr = std::unique_ptr<undo_input_text>(new undo_input_text(*this, std::wstring(1, '\n')));
|
auto undo_ptr = std::unique_ptr<undo_input_text>(new undo_input_text(*this, std::wstring(1, '\n')));
|
||||||
|
|
||||||
undo_ptr->set_selected_text();
|
undo_ptr->set_selected_text();
|
||||||
points_.caret = _m_erase_select();
|
points_.caret = _m_erase_select(false);
|
||||||
|
|
||||||
undo_ptr->set_caret_pos();
|
undo_ptr->set_caret_pos();
|
||||||
|
|
||||||
@ -2173,21 +2193,24 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
if (impl_->indent.generator)
|
if (impl_->indent.generator)
|
||||||
{
|
{
|
||||||
put(to_wstring(impl_->indent.generator()));
|
put(nana::to_wstring(impl_->indent.generator()), false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto & text = textbase.getline(points_.caret.y - 1);
|
auto & text = textbase.getline(points_.caret.y - 1);
|
||||||
auto indent_pos = text.find_first_not_of(L"\t ");
|
auto indent_pos = text.find_first_not_of(L"\t ");
|
||||||
if (indent_pos != std::wstring::npos)
|
if (indent_pos != std::wstring::npos)
|
||||||
put(text.substr(0, indent_pos));
|
put(text.substr(0, indent_pos), false);
|
||||||
else
|
else
|
||||||
put(text);
|
put(text, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_m_reset_content_size();
|
_m_reset_content_size();
|
||||||
|
|
||||||
|
if (perform_event)
|
||||||
|
textbase.text_changed();
|
||||||
|
|
||||||
auto origin_moved = impl_->cview->move_origin(origin - impl_->cview->origin());
|
auto origin_moved = impl_->cview->move_origin(origin - impl_->cview->origin());
|
||||||
|
|
||||||
if (this->_m_adjust_view() || origin_moved)
|
if (this->_m_adjust_view() || origin_moved)
|
||||||
@ -2211,10 +2234,10 @@ namespace nana{ namespace widgets
|
|||||||
return; //No characters behind the caret
|
return; //No characters behind the caret
|
||||||
}
|
}
|
||||||
|
|
||||||
backspace();
|
backspace(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void text_editor::backspace(bool record_undo)
|
void text_editor::backspace(bool record_undo, bool perform_event)
|
||||||
{
|
{
|
||||||
auto undo_ptr = std::unique_ptr<undo_backspace>(new undo_backspace(*this));
|
auto undo_ptr = std::unique_ptr<undo_backspace>(new undo_backspace(*this));
|
||||||
bool has_to_redraw = true;
|
bool has_to_redraw = true;
|
||||||
@ -2254,7 +2277,7 @@ namespace nana{ namespace widgets
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
undo_ptr->set_selected_text();
|
undo_ptr->set_selected_text();
|
||||||
points_.caret = _m_erase_select();
|
points_.caret = _m_erase_select(false);
|
||||||
undo_ptr->set_caret_pos();
|
undo_ptr->set_caret_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2263,6 +2286,11 @@ namespace nana{ namespace widgets
|
|||||||
|
|
||||||
_m_reset_content_size(false);
|
_m_reset_content_size(false);
|
||||||
|
|
||||||
|
if (perform_event)
|
||||||
|
textbase().text_changed();
|
||||||
|
|
||||||
|
textbase().text_changed();
|
||||||
|
|
||||||
if(has_to_redraw)
|
if(has_to_redraw)
|
||||||
{
|
{
|
||||||
this->_m_adjust_view();
|
this->_m_adjust_view();
|
||||||
@ -2956,7 +2984,7 @@ namespace nana{ namespace widgets
|
|||||||
select_.a = select_.b;
|
select_.a = select_.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
nana::upoint text_editor::_m_put(std::wstring text)
|
nana::upoint text_editor::_m_put(std::wstring text, bool perform_event)
|
||||||
{
|
{
|
||||||
auto & textbase = this->textbase();
|
auto & textbase = this->textbase();
|
||||||
auto crtpos = points_.caret;
|
auto crtpos = points_.caret;
|
||||||
@ -2998,10 +3026,13 @@ namespace nana{ namespace widgets
|
|||||||
_m_pre_calc_lines(crtpos.y, 1);
|
_m_pre_calc_lines(crtpos.y, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (perform_event)
|
||||||
|
textbase.text_changed();
|
||||||
|
|
||||||
return crtpos;
|
return crtpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
nana::upoint text_editor::_m_erase_select()
|
nana::upoint text_editor::_m_erase_select(bool perform_event)
|
||||||
{
|
{
|
||||||
nana::upoint a, b;
|
nana::upoint a, b;
|
||||||
if (get_selected_points(a, b))
|
if (get_selected_points(a, b))
|
||||||
@ -3023,6 +3054,9 @@ namespace nana{ namespace widgets
|
|||||||
_m_pre_calc_lines(a.y, 1);
|
_m_pre_calc_lines(a.y, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (perform_event)
|
||||||
|
textbase.text_changed();
|
||||||
|
|
||||||
select_.a = select_.b;
|
select_.a = select_.b;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@ -3235,8 +3269,8 @@ namespace nana{ namespace widgets
|
|||||||
{//forward
|
{//forward
|
||||||
undo_ptr->set_caret_pos();
|
undo_ptr->set_caret_pos();
|
||||||
|
|
||||||
_m_erase_select();
|
_m_erase_select(false);
|
||||||
_m_put(text);
|
_m_put(text, false);
|
||||||
|
|
||||||
select_.a = caret;
|
select_.a = caret;
|
||||||
select_.b.y = b.y + (caret.y - a.y);
|
select_.b.y = b.y + (caret.y - a.y);
|
||||||
@ -3245,8 +3279,8 @@ namespace nana{ namespace widgets
|
|||||||
{
|
{
|
||||||
undo_ptr->set_caret_pos();
|
undo_ptr->set_caret_pos();
|
||||||
|
|
||||||
_m_put(text);
|
_m_put(text, false);
|
||||||
_m_erase_select();
|
_m_erase_select(false);
|
||||||
|
|
||||||
select_.b.y = caret.y;
|
select_.b.y = caret.y;
|
||||||
select_.a.y = caret.y - (b.y - a.y);
|
select_.a.y = caret.y - (b.y - a.y);
|
||||||
|
@ -750,8 +750,8 @@ namespace nana
|
|||||||
{
|
{
|
||||||
if((pos == npos) || (pos >= list_.size()))
|
if((pos == npos) || (pos >= list_.size()))
|
||||||
{
|
{
|
||||||
|
pos = list_.size();
|
||||||
this->list_.emplace_back();
|
this->list_.emplace_back();
|
||||||
pos = list_.size() - 1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
list_.emplace(iterator_at(pos));
|
list_.emplace(iterator_at(pos));
|
||||||
|
@ -428,7 +428,7 @@ namespace drawerbase {
|
|||||||
if(at_caret == false)
|
if(at_caret == false)
|
||||||
editor->move_caret_end(false);
|
editor->move_caret_end(false);
|
||||||
|
|
||||||
editor->put(to_wstring(text));
|
editor->put(to_wstring(text), true);
|
||||||
|
|
||||||
editor->try_refresh();
|
editor->try_refresh();
|
||||||
API::update_window(this->handle());
|
API::update_window(this->handle());
|
||||||
@ -445,7 +445,7 @@ namespace drawerbase {
|
|||||||
if(at_caret == false)
|
if(at_caret == false)
|
||||||
editor->move_caret_end(false);
|
editor->move_caret_end(false);
|
||||||
|
|
||||||
editor->put(text);
|
editor->put(text, true);
|
||||||
|
|
||||||
editor->try_refresh();
|
editor->try_refresh();
|
||||||
API::update_window(this->handle());
|
API::update_window(this->handle());
|
||||||
|
@ -351,10 +351,17 @@ namespace threads
|
|||||||
}container_;
|
}container_;
|
||||||
};//end class impl
|
};//end class impl
|
||||||
|
|
||||||
pool::pool()
|
#ifndef STD_THREAD_NOT_SUPPORTED
|
||||||
: impl_(new impl(4))
|
pool::pool(unsigned thread_number)
|
||||||
|
: impl_(new impl(thread_number ? thread_number : std::thread::hardware_concurrency()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
pool::pool(unsigned thread_number)
|
||||||
|
: impl_(new impl(0))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
pool::pool(pool&& other)
|
pool::pool(pool&& other)
|
||||||
: pool()
|
: pool()
|
||||||
@ -362,11 +369,6 @@ namespace threads
|
|||||||
std::swap(impl_, other.impl_);
|
std::swap(impl_, other.impl_);
|
||||||
}
|
}
|
||||||
|
|
||||||
pool::pool(std::size_t thread_number)
|
|
||||||
: impl_(new impl(thread_number))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
pool& pool::operator=(pool&& other)
|
pool& pool::operator=(pool&& other)
|
||||||
{
|
{
|
||||||
if(this != &other)
|
if(this != &other)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <nana/unicode_bidi.hpp>
|
#include <nana/unicode_bidi.hpp>
|
||||||
|
#include <nana/c++defines.hpp>
|
||||||
|
|
||||||
namespace nana
|
namespace nana
|
||||||
{
|
{
|
||||||
@ -611,8 +612,12 @@ namespace nana
|
|||||||
|
|
||||||
void unicode_bidi::_m_push_entity(const char_type * begin, const char_type *end, unsigned level, bidi_char bidi_char_type)
|
void unicode_bidi::_m_push_entity(const char_type * begin, const char_type *end, unsigned level, bidi_char bidi_char_type)
|
||||||
{
|
{
|
||||||
|
#ifdef _nana_std_has_emplace_return_type
|
||||||
|
auto & e = levels_.emplace_back();
|
||||||
|
#else
|
||||||
levels_.emplace_back();
|
levels_.emplace_back();
|
||||||
auto & e = levels_.back();
|
auto & e = levels_.back();
|
||||||
|
#endif
|
||||||
e.begin = begin;
|
e.begin = begin;
|
||||||
e.end = end;
|
e.end = end;
|
||||||
e.level = level;
|
e.level = level;
|
||||||
@ -946,4 +951,68 @@ namespace nana
|
|||||||
{
|
{
|
||||||
return unicode_bidi{}.reorder(text, length);
|
return unicode_bidi{}.reorder(text, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class unicode_character_type
|
||||||
|
{
|
||||||
|
format,
|
||||||
|
katakana,
|
||||||
|
aletter,
|
||||||
|
midletter,
|
||||||
|
midnumlet,
|
||||||
|
midnum,
|
||||||
|
numeric,
|
||||||
|
other
|
||||||
|
};
|
||||||
|
|
||||||
|
//http://www.unicode.org/reports/tr29/WordBreakTest.html
|
||||||
|
unicode_character_type unicode_char_type(unsigned long ch)
|
||||||
|
{
|
||||||
|
if ((0x0600 <= ch && ch <= 0x0603) || (0x06DD == ch || 0x070F == ch || 0x17B4 == ch || 0x17B5 == ch) || (0x200C <= ch && ch <= 0x200F) ||
|
||||||
|
(0x202A <= ch && ch <= 0x202E) || (0x2060 <= ch && ch <= 0x2063) || (0x206A <= ch && ch <= 0x206F) || (0xFEFF == ch) || (0xFFF9 <= ch && ch <= 0xFFFB) ||
|
||||||
|
(0x1D173 <= ch && ch <= 0x1D17A) || (0xE0001 == ch) || (0xE0020 <= ch && ch <= 0xE007F))
|
||||||
|
return unicode_character_type::format;
|
||||||
|
|
||||||
|
if ((0x30A1 <= ch && ch <= 0x30FA) || (0x30FC <= ch && ch <= 0x30FF) || (0x31F0 <= ch && ch <= 0x31FF) || (0xFF66 <= ch && ch <= 0xFF9F))
|
||||||
|
return unicode_character_type::katakana;
|
||||||
|
|
||||||
|
if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || (0x00AA == ch || 0x00B5 == ch || 0x00BA == ch) || (0x00C0 <= ch && ch <= 0x00D6) ||
|
||||||
|
(0x00D8 <= ch && ch <= 0x00F6) || (0x00F8 <= ch && ch <= 0x0236) || (0x0250 <= ch || ch <= 0x02C1))
|
||||||
|
return unicode_character_type::aletter;
|
||||||
|
|
||||||
|
if ('\'' == ch || 0x00AD == ch || 0x00B7 == ch || 0x05F4 == ch || 0x2019 == ch || 0x2027 == ch)
|
||||||
|
return unicode_character_type::midletter;
|
||||||
|
|
||||||
|
if ('.' == ch || '\\' == ch || ':' == ch)
|
||||||
|
return unicode_character_type::midnumlet;
|
||||||
|
|
||||||
|
if (0x2024 <= ch && ch <= 0x2026)
|
||||||
|
return unicode_character_type::midnum;
|
||||||
|
|
||||||
|
if (('0' <= ch && ch <= '9') || (0x0660 <= ch && ch <= 0x0669) || (0x06F0 <= ch && ch <= 0x06F9))
|
||||||
|
return unicode_character_type::numeric;
|
||||||
|
|
||||||
|
return unicode_character_type::other;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unicode_wordbreak(wchar_t left, wchar_t right)
|
||||||
|
{
|
||||||
|
auto l_type = unicode_char_type(left);
|
||||||
|
auto r_type = unicode_char_type(right);
|
||||||
|
|
||||||
|
switch (l_type)
|
||||||
|
{
|
||||||
|
case unicode_character_type::format:
|
||||||
|
case unicode_character_type::midletter:
|
||||||
|
case unicode_character_type::midnumlet:
|
||||||
|
case unicode_character_type::midnum:
|
||||||
|
case unicode_character_type::other:
|
||||||
|
return (r_type != unicode_character_type::format);
|
||||||
|
case unicode_character_type::katakana:
|
||||||
|
return !(unicode_character_type::format == r_type) || (unicode_character_type::katakana == r_type);
|
||||||
|
case unicode_character_type::aletter:
|
||||||
|
case unicode_character_type::numeric:
|
||||||
|
return !(unicode_character_type::format == r_type) || (unicode_character_type::aletter == r_type) || (unicode_character_type::numeric == r_type);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}//end namespace nana
|
}//end namespace nana
|
||||||
|
Loading…
x
Reference in New Issue
Block a user