Merge branch 'develop'
This commit is contained in:
commit
d932020e2c
@ -114,10 +114,13 @@ endforeach()
|
||||
### Some nana compilation options ###
|
||||
option(NANA_CMAKE_AUTOMATIC_GUI_TESTING "Activate automatic GUI testing?" OFF)
|
||||
option(NANA_CMAKE_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ "replaced boost.thread with meganz's mingw-std-threads." OFF) # deprecate?
|
||||
option(NANA_CMAKE_ENABLE_CONF "enable config.hpp" OFF)
|
||||
|
||||
######## Nana options
|
||||
|
||||
target_compile_definitions(nana PRIVATE NANA_IGNORE_CONF) # really ??
|
||||
if(NOT NANA_CMAKE_ENABLE_CONF)
|
||||
target_compile_definitions(nana PRIVATE NANA_IGNORE_CONF) # really ??
|
||||
endif()
|
||||
if(NANA_CMAKE_AUTOMATIC_GUI_TESTING)
|
||||
target_compile_definitions(nana PUBLIC NANA_AUTOMATIC_GUI_TESTING)
|
||||
# todo: enable_testing() # ??
|
||||
|
@ -53,7 +53,7 @@ else()
|
||||
if(NANA_CMAKE_STD_FILESYSTEM_FORCE)
|
||||
target_compile_definitions(nana PUBLIC STD_FILESYSTEM_FORCE)
|
||||
endif()
|
||||
|
||||
include (CheckIncludeFileCXX)
|
||||
check_include_file_cxx (filesystem NANA_HAVE_FILESYSTEM)
|
||||
if (NANA_HAVE_FILESYSTEM)
|
||||
message (STATUS "C++ Filesystem header: <filesystem>")
|
||||
@ -87,7 +87,6 @@ else()
|
||||
|
||||
if (TEST_FS_LIB)
|
||||
include (FindPackageMessage)
|
||||
include (CheckIncludeFileCXX)
|
||||
include (CheckCXXSourceCompiles)
|
||||
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
|
||||
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An Animation Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -29,16 +29,15 @@ namespace nana
|
||||
public:
|
||||
/// function which builds frames.
|
||||
using framebuilder = std::function<bool(std::size_t pos, paint::graphics&, nana::size&)>;
|
||||
|
||||
struct impl;
|
||||
public:
|
||||
frameset();
|
||||
void push_back(paint::image); ///< Inserts frames at the end.
|
||||
void push_back(framebuilder fb, std::size_t length); ///< Inserts a framebuilder and the number of frames that it generates.
|
||||
private:
|
||||
struct impl;
|
||||
std::shared_ptr<impl> impl_;
|
||||
};
|
||||
/// Easy way to display an animation or create an animated GUI
|
||||
/// Easy way to display an animation or create an animated GUI
|
||||
class animation
|
||||
{
|
||||
struct branch_t
|
||||
@ -46,7 +45,7 @@ namespace nana
|
||||
frameset frames;
|
||||
std::function<std::size_t(const std::string&, std::size_t, std::size_t&)> condition;
|
||||
};
|
||||
|
||||
|
||||
struct impl;
|
||||
class performance_manager;
|
||||
|
||||
@ -68,12 +67,21 @@ namespace nana
|
||||
|
||||
void pause();
|
||||
|
||||
/// Renders the animation at a fixed position
|
||||
void output(window wd, const nana::point& pos);
|
||||
|
||||
/// Renders the animation at a rectangle
|
||||
/**
|
||||
* If the size of rectangle is not equal to the size of frame, it stretches the frame for the size of rectangle.
|
||||
* @param wd Output window.
|
||||
* @param r Generator of the rectangle. The generator gets called every time rendering occurs.
|
||||
*/
|
||||
void output(window wd, std::function<nana::rectangle()> r);
|
||||
|
||||
void fps(std::size_t n);
|
||||
std::size_t fps() const;
|
||||
private:
|
||||
impl * impl_;
|
||||
std::unique_ptr<impl> impl_;
|
||||
};
|
||||
} //end namespace nana
|
||||
#include <nana/pop_ignore_diagnostic>
|
||||
|
@ -33,7 +33,7 @@ namespace nana
|
||||
|
||||
struct accel_key
|
||||
{
|
||||
char key;
|
||||
char key{ '\0' };
|
||||
bool case_sensitive{ false };
|
||||
bool alt{ false };
|
||||
bool ctrl{ false };
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Categorize Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -248,7 +248,7 @@ namespace nana
|
||||
/// Retrieves a reference of the current category's value type object. If current category is empty, it throws a exception of std::runtime_error.
|
||||
value_type& value() const
|
||||
{
|
||||
return this->get_drawer_trigger().value();
|
||||
return nana::any_cast<value_type&>(this->get_drawer_trigger().value());
|
||||
}
|
||||
private:
|
||||
//Overrides widget's virtual functions
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A List Box Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -1511,8 +1511,18 @@ the nana::detail::basic_window member pointer scheme
|
||||
/// Returns the index pair of the item which contains the specified "screen" point.
|
||||
index_pair cast(const point & screen_pos) const;
|
||||
|
||||
/// Converts the index between absolute position and display position
|
||||
/**
|
||||
* @param idx The index to be converted
|
||||
* @param from_display_order If this parameter is true, the method converts a display position to an absolute position.
|
||||
* If the parameter is false, the method converts an absolute position to a display position.
|
||||
* @return a display position or an absolute position that are depending on from_display_order.
|
||||
*/
|
||||
index_pair index_cast(index_pair idx, bool from_display_order) const;
|
||||
|
||||
/// Returns the item which is hovered
|
||||
/**
|
||||
* The item position is an absolute position.
|
||||
* @param return_end Indicates whether to return an end position instead of an empty position if no item is hovered.
|
||||
* @return The position of the hovered item. If return_end is true and no item is hovered it returns the position next to the last item of last category.
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Text Token Stream
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -20,6 +20,7 @@
|
||||
#include <list>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
|
||||
#include <nana/push_ignore_diagnostic>
|
||||
#include <nana/unicode_bidi.hpp>
|
||||
@ -41,13 +42,14 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
eof
|
||||
};
|
||||
|
||||
|
||||
class tokenizer
|
||||
{
|
||||
public:
|
||||
tokenizer(const std::wstring& s, bool format_enabled)
|
||||
: iptr_(s.data()),
|
||||
endptr_(s.data() + s.size()),
|
||||
format_enabled_(format_enabled)
|
||||
tokenizer(const std::wstring& s, bool format_enabled) :
|
||||
iptr_(s.data()),
|
||||
endptr_(s.data() + s.size()),
|
||||
format_enabled_(format_enabled)
|
||||
{
|
||||
}
|
||||
|
||||
@ -59,18 +61,18 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
//Read the token.
|
||||
token read()
|
||||
{
|
||||
if(revert_token_ != token::eof)
|
||||
if (revert_token_ != token::eof)
|
||||
{
|
||||
token tk = revert_token_;
|
||||
revert_token_ = token::eof;
|
||||
return tk;
|
||||
}
|
||||
|
||||
if(iptr_ == endptr_)
|
||||
if (iptr_ == endptr_)
|
||||
return token::eof;
|
||||
|
||||
//Check whether it is a format token.
|
||||
if(format_enabled_ && format_state_)
|
||||
if (format_enabled_ && format_state_)
|
||||
return _m_format_token();
|
||||
|
||||
return _m_token();
|
||||
@ -107,8 +109,7 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
token _m_token()
|
||||
{
|
||||
wchar_t ch = *iptr_;
|
||||
|
||||
if(ch > 0xFF)
|
||||
if (ch > 0xFF)
|
||||
{
|
||||
//This is the Unicode.
|
||||
|
||||
@ -122,53 +123,58 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
}
|
||||
|
||||
ch = *++iptr_;
|
||||
while((iptr_ != endptr_) && (ch > 0xFF) && (false == _m_unicode_word_breakable(iptr_)))
|
||||
while ((iptr_ != endptr_) && (ch > 0xFF) && (false == _m_unicode_word_breakable(iptr_)))
|
||||
{
|
||||
idstr_.append(1, ch);
|
||||
|
||||
ch = *++iptr_;
|
||||
}
|
||||
|
||||
//When the last _m_unicode_word_breakable returns true, it implies the ch(left character)
|
||||
//is not the breakable character. So it belongs to the data.
|
||||
idstr_.append(1, ch);
|
||||
++iptr_;
|
||||
|
||||
return token::data;
|
||||
}
|
||||
|
||||
if('\n' == ch)
|
||||
if ('\n' == ch)
|
||||
{
|
||||
++iptr_;
|
||||
return token::endl;
|
||||
}
|
||||
|
||||
if(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))
|
||||
if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))
|
||||
{
|
||||
auto idstr = iptr_;
|
||||
do
|
||||
{
|
||||
ch = *(++iptr_);
|
||||
}
|
||||
while(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'));
|
||||
} while (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'));
|
||||
|
||||
idstr_.assign(idstr, iptr_);
|
||||
|
||||
return token::data;
|
||||
}
|
||||
|
||||
if('0' <= ch && ch <= '9')
|
||||
if ('0' <= ch && ch <= '9')
|
||||
{
|
||||
_m_read_number();
|
||||
return token::data;
|
||||
}
|
||||
|
||||
if(('<' == ch) && format_enabled_)
|
||||
if (('<' == ch) && format_enabled_)
|
||||
{
|
||||
//pos keeps the current position, and it used for restring
|
||||
//pos keeps the current position, and it used for restoring
|
||||
//iptr_ when the search is failed.
|
||||
|
||||
auto pos = ++iptr_;
|
||||
_m_eat_whitespace();
|
||||
if(*iptr_ == '/')
|
||||
if (*iptr_ == '/')
|
||||
{
|
||||
++iptr_;
|
||||
_m_eat_whitespace();
|
||||
if(*iptr_ == '>')
|
||||
if (*iptr_ == '>')
|
||||
{
|
||||
++iptr_;
|
||||
return token::format_end;
|
||||
@ -182,11 +188,10 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
return token::tag_begin;
|
||||
}
|
||||
|
||||
|
||||
//Escape
|
||||
if(this->format_enabled_ && (ch == '\\'))
|
||||
if (this->format_enabled_ && (ch == '\\'))
|
||||
{
|
||||
if(iptr_ + 1 < endptr_)
|
||||
if (iptr_ + 1 < endptr_)
|
||||
{
|
||||
ch = *(iptr_ + 1);
|
||||
|
||||
@ -221,8 +226,7 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
_m_eat_whitespace();
|
||||
|
||||
auto ch = *iptr_++;
|
||||
|
||||
switch(ch)
|
||||
switch (ch)
|
||||
{
|
||||
case ',': return token::comma;
|
||||
case '/': return token::backslash;
|
||||
@ -232,40 +236,40 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
return token::tag_end;
|
||||
case '"':
|
||||
//Here is a string and all the meta characters will be ignored except "
|
||||
{
|
||||
auto str = iptr_;
|
||||
{
|
||||
auto str = iptr_;
|
||||
|
||||
while((iptr_ != endptr_) && (*iptr_ != '"'))
|
||||
++iptr_;
|
||||
while ((iptr_ != endptr_) && (*iptr_ != '"'))
|
||||
++iptr_;
|
||||
|
||||
idstr_.assign(str, iptr_++);
|
||||
}
|
||||
idstr_.assign(str, iptr_++);
|
||||
}
|
||||
return token::string;
|
||||
case '(':
|
||||
_m_eat_whitespace();
|
||||
if((iptr_ < endptr_) && _m_is_idstr_element(*iptr_))
|
||||
if ((iptr_ < endptr_) && _m_is_idstr_element(*iptr_))
|
||||
{
|
||||
auto pbegin = iptr_;
|
||||
while((iptr_ < endptr_) && _m_is_idstr_element(*iptr_))
|
||||
while ((iptr_ < endptr_) && _m_is_idstr_element(*iptr_))
|
||||
++iptr_;
|
||||
|
||||
binary_.first.assign(pbegin, iptr_);
|
||||
|
||||
_m_eat_whitespace();
|
||||
if((iptr_ < endptr_) && (',' == *iptr_))
|
||||
if ((iptr_ < endptr_) && (',' == *iptr_))
|
||||
{
|
||||
++iptr_;
|
||||
_m_eat_whitespace();
|
||||
if((iptr_ < endptr_) && _m_is_idstr_element(*iptr_))
|
||||
if ((iptr_ < endptr_) && _m_is_idstr_element(*iptr_))
|
||||
{
|
||||
pbegin = iptr_;
|
||||
while((iptr_ < endptr_) && _m_is_idstr_element(*iptr_))
|
||||
while ((iptr_ < endptr_) && _m_is_idstr_element(*iptr_))
|
||||
++iptr_;
|
||||
|
||||
binary_.second.assign(pbegin, iptr_);
|
||||
|
||||
_m_eat_whitespace();
|
||||
if((iptr_ < endptr_) && (')' == *iptr_))
|
||||
if ((iptr_ < endptr_) && (')' == *iptr_))
|
||||
{
|
||||
++iptr_;
|
||||
return token::binary;
|
||||
@ -273,62 +277,64 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return token::eof;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || '_' == ch)
|
||||
|
||||
if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || '_' == ch)
|
||||
{
|
||||
--iptr_;
|
||||
|
||||
//Here is a identifier
|
||||
_m_read_idstr();
|
||||
|
||||
if(L"font" == idstr_)
|
||||
if (L"font" == idstr_)
|
||||
return token::font;
|
||||
else if(L"bold" == idstr_)
|
||||
else if (L"bold" == idstr_)
|
||||
return token::bold;
|
||||
else if(L"size" == idstr_)
|
||||
else if (L"size" == idstr_)
|
||||
return token::size;
|
||||
else if(L"baseline" == idstr_)
|
||||
else if (L"baseline" == idstr_)
|
||||
return token::baseline;
|
||||
else if(L"top" == idstr_)
|
||||
else if (L"top" == idstr_)
|
||||
return token::top;
|
||||
else if(L"center" == idstr_)
|
||||
else if (L"center" == idstr_)
|
||||
return token::center;
|
||||
else if(L"bottom" == idstr_)
|
||||
else if (L"bottom" == idstr_)
|
||||
return token::bottom;
|
||||
else if(L"color" == idstr_)
|
||||
else if (L"color" == idstr_)
|
||||
return token::color;
|
||||
else if(L"image" == idstr_)
|
||||
else if (L"image" == idstr_)
|
||||
return token::image;
|
||||
else if(L"true" == idstr_)
|
||||
else if (L"true" == idstr_)
|
||||
return token::_true;
|
||||
else if(L"url" == idstr_)
|
||||
else if (L"url" == idstr_)
|
||||
return token::url;
|
||||
else if(L"target" == idstr_)
|
||||
else if (L"target" == idstr_)
|
||||
return token::target;
|
||||
else if(L"false" == idstr_)
|
||||
else if (L"false" == idstr_)
|
||||
return token::_false;
|
||||
else if(L"red" == idstr_)
|
||||
else if (L"red" == idstr_)
|
||||
return token::red;
|
||||
else if(L"green" == idstr_)
|
||||
else if (L"green" == idstr_)
|
||||
return token::green;
|
||||
else if(L"blue" == idstr_)
|
||||
else if (L"blue" == idstr_)
|
||||
return token::blue;
|
||||
else if(L"white" == idstr_)
|
||||
else if (L"white" == idstr_)
|
||||
return token::white;
|
||||
else if(L"black" == idstr_)
|
||||
else if (L"black" == idstr_)
|
||||
return token::black;
|
||||
else if(L"min_limited" == idstr_)
|
||||
else if (L"min_limited" == idstr_)
|
||||
return token::min_limited;
|
||||
else if(L"max_limited" == idstr_)
|
||||
else if (L"max_limited" == idstr_)
|
||||
return token::max_limited;
|
||||
|
||||
return token::string;
|
||||
}
|
||||
|
||||
if('0' <= ch && ch <= '9')
|
||||
if ('0' <= ch && ch <= '9')
|
||||
{
|
||||
--iptr_;
|
||||
_m_read_number();
|
||||
@ -352,8 +358,7 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
do
|
||||
{
|
||||
ch = *(++iptr_);
|
||||
}
|
||||
while(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('_' == ch) || ('0' <= ch && ch <= '9'));
|
||||
} while (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('_' == ch) || ('0' <= ch && ch <= '9'));
|
||||
|
||||
idstr_.assign(idstr, iptr_);
|
||||
}
|
||||
@ -368,18 +373,18 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
idstr_ += ch;
|
||||
|
||||
//First check the number whether will be a hex number.
|
||||
if('0' == ch)
|
||||
if ('0' == ch)
|
||||
{
|
||||
ch = *++iptr_;
|
||||
if((!('0' <= ch && ch <= '9')) && (ch != 'x' && ch != 'X'))
|
||||
if ((!('0' <= ch && ch <= '9')) && (ch != 'x' && ch != 'X'))
|
||||
return;
|
||||
|
||||
if(ch == 'x' || ch == 'X')
|
||||
if (ch == 'x' || ch == 'X')
|
||||
{
|
||||
//Here is a hex number
|
||||
idstr_ += 'x';
|
||||
ch = *++iptr_;
|
||||
while(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F'))
|
||||
while (('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F'))
|
||||
{
|
||||
idstr_ += ch;
|
||||
ch = *++iptr_;
|
||||
@ -392,7 +397,7 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
}
|
||||
|
||||
ch = *++iptr_;
|
||||
while('0' <= ch && ch <= '9')
|
||||
while ('0' <= ch && ch <= '9')
|
||||
{
|
||||
idstr_ += ch;
|
||||
ch = *++iptr_;
|
||||
@ -401,9 +406,9 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
|
||||
void _m_eat_whitespace()
|
||||
{
|
||||
while(true)
|
||||
while (true)
|
||||
{
|
||||
switch(*iptr_)
|
||||
switch (*iptr_)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
@ -641,6 +646,8 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
while(true)
|
||||
{
|
||||
token tk = tknizer.read();
|
||||
if (token::eof == tk)
|
||||
break;
|
||||
|
||||
switch(tk)
|
||||
{
|
||||
@ -665,12 +672,53 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
if(fstack.size() > 1)
|
||||
fstack.pop();
|
||||
break;
|
||||
case token::eof:
|
||||
return;
|
||||
default:
|
||||
throw std::runtime_error("invalid token");
|
||||
}
|
||||
}
|
||||
|
||||
//Reorder the sequence of line blocks for RTL languages.
|
||||
for (auto & ln : lines_)
|
||||
{
|
||||
std::wstring str;
|
||||
//Position only holds the start positions of blocks in a line.
|
||||
std::vector<std::size_t> position;
|
||||
for (auto & b : ln)
|
||||
{
|
||||
position.push_back(str.size());
|
||||
str += b.data_ptr->text();
|
||||
}
|
||||
|
||||
std::remove_reference<decltype(ln)>::type dump;
|
||||
dump.swap(ln);
|
||||
|
||||
auto entities = unicode_bidi{}.reorder(str.c_str(), str.size());
|
||||
for (auto & e : entities)
|
||||
{
|
||||
auto pos = e.begin - str.c_str();
|
||||
|
||||
auto i = std::find(position.cbegin(), position.cend(), pos);
|
||||
|
||||
//If the pos is not a start position, it indicates the block of bidi entity has been inserted into
|
||||
//the ln container. Because the content of a block may be divided into multiple bidi entities.
|
||||
if (i == position.cend())
|
||||
continue;
|
||||
|
||||
ln.push_back(dump[i - position.cbegin()]);
|
||||
|
||||
auto const endpos = e.end - str.c_str();
|
||||
//Check whether the next position is belone to current entity.
|
||||
while (++i != position.cend())
|
||||
{
|
||||
if (*i < static_cast<std::size_t>(endpos))
|
||||
{
|
||||
ln.push_back(dump[i - position.cbegin()]);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterator begin()
|
||||
|
@ -300,6 +300,12 @@ namespace nana
|
||||
return any_cast<T>(&_m_value());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T * value_ptr()
|
||||
{
|
||||
return any_cast<T>(&_m_value());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& value() const
|
||||
{
|
||||
@ -309,6 +315,15 @@ namespace nana
|
||||
return *p;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& value()
|
||||
{
|
||||
auto p = any_cast<T>(&_m_value());
|
||||
if (nullptr == p)
|
||||
throw std::runtime_error("treebox::value<T>() Invalid type of value.");
|
||||
return *p;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
item_proxy & value(T&& t)
|
||||
{
|
||||
@ -500,6 +515,8 @@ namespace nana
|
||||
*/
|
||||
void use_entire_line(bool enable);
|
||||
|
||||
/// Return the first node of treebox
|
||||
item_proxy first() const;
|
||||
private:
|
||||
std::shared_ptr<scroll_operation_interface> _m_scroll_operation() override;
|
||||
|
||||
|
@ -50,6 +50,7 @@ namespace nana
|
||||
};
|
||||
|
||||
std::vector<entity> reorder(const char_type*, std::size_t len);
|
||||
static bool is_text_right(const entity&);
|
||||
private:
|
||||
static unsigned _m_paragraph_level(const char_type * begin, const char_type * end);
|
||||
|
||||
@ -72,7 +73,6 @@ namespace nana
|
||||
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>
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace {
|
||||
std::tm localtime()
|
||||
|
@ -2,6 +2,9 @@
|
||||
#include <set>
|
||||
#include <nana/deploy.hpp>
|
||||
#include "../paint/truetype.hpp"
|
||||
#ifdef _nana_std_has_string_view
|
||||
# include <string_view>
|
||||
#endif
|
||||
|
||||
#ifdef NANA_WINDOWS
|
||||
|
||||
@ -146,6 +149,8 @@ IsWindows8OrGreater()
|
||||
# include "posix/platform_spec.hpp"
|
||||
# include <fontconfig/fontconfig.h>
|
||||
# if defined(NANA_USE_XFT)
|
||||
# include <nana/unicode_bidi.hpp>
|
||||
# include "text_reshaping.hpp"
|
||||
# include <X11/Xft/Xft.h>
|
||||
# include <iconv.h>
|
||||
# include <fstream>
|
||||
@ -211,16 +216,37 @@ namespace nana
|
||||
int const init_x = x;
|
||||
std::unique_ptr<FT_UInt[]> glyph_indexes(new FT_UInt[len]);
|
||||
|
||||
while(true)
|
||||
//The RTL and shaping should be handled manually, because the libXft and X doesn't support these language features.
|
||||
std::wstring rtl;
|
||||
auto ents = unicode_reorder(str, len);
|
||||
for(auto & e : ents)
|
||||
{
|
||||
auto preferred = _m_scan_fonts(xft, str, len, glyph_indexes.get());
|
||||
x += _m_draw(xftdraw, xftcolor, preferred.first, x, y, str, preferred.second, glyph_indexes.get());
|
||||
auto size = static_cast<std::size_t>(e.end - e.begin);
|
||||
auto p = e.begin;
|
||||
|
||||
if(len == preferred.second)
|
||||
break;
|
||||
if(unicode_bidi::is_text_right(e))
|
||||
{
|
||||
auto restr = nana::reshaping::arabic::reshape(std::wstring{e.begin, e.end});
|
||||
rtl.assign(restr.crbegin(), restr.crend());
|
||||
|
||||
len -= preferred.second;
|
||||
str += preferred.second;
|
||||
p = rtl.c_str();
|
||||
size = rtl.size();
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
//Scan the string until the character which font is not same with the font of the first character where the scan begins.
|
||||
auto preferred = _m_scan_fonts(xft, p, size, glyph_indexes.get());
|
||||
x += _m_draw(xftdraw, xftcolor, preferred.first, x, y, p, preferred.second, glyph_indexes.get());
|
||||
|
||||
if(size == preferred.second)
|
||||
break;
|
||||
|
||||
size -= preferred.second;
|
||||
p += preferred.second;
|
||||
}
|
||||
|
||||
rtl.clear();
|
||||
}
|
||||
|
||||
return x - init_x;
|
||||
@ -236,22 +262,28 @@ namespace nana
|
||||
std::unique_ptr<unsigned[]> pxbuf{new unsigned[len]};
|
||||
|
||||
auto pbuf = pxbuf.get();
|
||||
auto pstr = str;
|
||||
auto size = len;
|
||||
|
||||
while(true)
|
||||
{
|
||||
auto preferred = _m_scan_fonts(xft, pstr, size, glyph_indexes.get());
|
||||
#ifdef _nana_std_has_string_view
|
||||
std::wstring_view s{str, len};
|
||||
#else
|
||||
std::wstring s{str, len};
|
||||
#endif
|
||||
//Don't reverse the string
|
||||
_m_reorder_reshaping(s, false, [&,xft, str](const wchar_t* p, std::size_t size, const wchar_t* pstr) mutable{
|
||||
while(true)
|
||||
{
|
||||
auto preferred = _m_scan_fonts(xft, p, size, glyph_indexes.get());
|
||||
|
||||
_m_glyph_px(preferred.first, pstr, preferred.second, glyph_indexes.get(), pbuf);
|
||||
_m_glyph_px(preferred.first, p, preferred.second, glyph_indexes.get(), pbuf + (pstr - str));
|
||||
|
||||
if(size == preferred.second)
|
||||
break;
|
||||
if(size == preferred.second)
|
||||
break;
|
||||
|
||||
size -= preferred.second;
|
||||
pstr += preferred.second;
|
||||
pbuf += preferred.second;
|
||||
}
|
||||
size -= preferred.second;
|
||||
p += preferred.second;
|
||||
pstr += preferred.second;
|
||||
}
|
||||
});
|
||||
|
||||
return pxbuf;
|
||||
}
|
||||
@ -265,21 +297,69 @@ namespace nana
|
||||
|
||||
std::unique_ptr<FT_UInt[]> glyph_indexes(new FT_UInt[len]);
|
||||
|
||||
while(len > 0)
|
||||
{
|
||||
auto preferred = _m_scan_fonts(xft, str, len, glyph_indexes.get());
|
||||
#ifdef _nana_std_has_string_view
|
||||
std::wstring_view s{str, len};
|
||||
#else
|
||||
std::wstring s{str, len};
|
||||
#endif
|
||||
//Don't reverse the string
|
||||
_m_reorder_reshaping(s, false, [&,xft, str](const wchar_t* p, std::size_t size, const wchar_t* /*pstr*/) mutable{
|
||||
while(true)
|
||||
{
|
||||
auto preferred = _m_scan_fonts(xft, p, size, glyph_indexes.get());
|
||||
|
||||
extent.width += _m_extents(preferred.first, str, preferred.second, glyph_indexes.get());
|
||||
extent.width += _m_extents(preferred.first, p, preferred.second, glyph_indexes.get());
|
||||
|
||||
if(preferred.first->ascent + preferred.first->descent > static_cast<int>(extent.height))
|
||||
extent.height = preferred.first->ascent + preferred.first->descent;
|
||||
if(preferred.first->ascent + preferred.first->descent > static_cast<int>(extent.height))
|
||||
extent.height = preferred.first->ascent + preferred.first->descent;
|
||||
|
||||
if(size == preferred.second)
|
||||
break;
|
||||
|
||||
size -= preferred.second;
|
||||
p += preferred.second;
|
||||
}
|
||||
});
|
||||
|
||||
len -= preferred.second;
|
||||
str += preferred.second;
|
||||
}
|
||||
return extent;
|
||||
}
|
||||
private:
|
||||
/// @param reverse Indicates whether to reverse the string, it only reverse the RTL language string.
|
||||
template<typename Function>
|
||||
#ifdef _nana_std_has_string_view
|
||||
void _m_reorder_reshaping(std::wstring_view str, bool reverse, Function fn)
|
||||
#else
|
||||
void _m_reorder_reshaping(const std::wstring& str, bool reverse, Function fn)
|
||||
#endif
|
||||
{
|
||||
//The RTL and shaping should be handled manually, because the libXft and X doesn't support these language features.
|
||||
std::wstring rtl;
|
||||
auto ents = unicode_reorder(str.data(), str.size());
|
||||
for(auto & e : ents)
|
||||
{
|
||||
auto size = static_cast<std::size_t>(e.end - e.begin);
|
||||
auto p = e.begin;
|
||||
|
||||
if(unicode_bidi::is_text_right(e))
|
||||
{
|
||||
//Reshape the str
|
||||
auto restr = nana::reshaping::arabic::reshape(std::wstring{e.begin, e.end});
|
||||
|
||||
if(reverse)
|
||||
rtl.assign(restr.crbegin(), restr.crend());
|
||||
else
|
||||
rtl.swap(restr);
|
||||
|
||||
p = rtl.c_str();
|
||||
size = rtl.size();
|
||||
}
|
||||
|
||||
fn(p, size, e.begin);
|
||||
|
||||
rtl.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//Tab is a invisible character
|
||||
int _m_draw(::XftDraw* xftdraw, ::XftColor* xftcolor, ::XftFont* xft, int x, int y, const wchar_t* str, std::size_t len, const FT_UInt* glyph_indexes)
|
||||
{
|
||||
@ -298,14 +378,14 @@ namespace nana
|
||||
if(ptab == p)
|
||||
{
|
||||
++p;
|
||||
//x += static_cast<int>(tab_pixels_);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const size = ptab - p;
|
||||
|
||||
::XftDrawGlyphs(xftdraw, xftcolor, xft, x, y, glyph_indexes + off, size);
|
||||
::XftGlyphExtents(disp_, xft, glyph_indexes + off, size, &ext);
|
||||
|
||||
|
||||
x += ext.xOff;
|
||||
|
||||
if(ptab == end)
|
||||
@ -359,10 +439,10 @@ namespace nana
|
||||
if('\t' != *p)
|
||||
{
|
||||
::XftGlyphExtents(disp_, xft, glyph_indexes, 1, &extent);
|
||||
*pxbuf = extent.xOff;
|
||||
*pxbuf++ = extent.xOff;
|
||||
}
|
||||
else
|
||||
*pxbuf = 0;//tab_pixels_;
|
||||
*pxbuf++ = 0;//tab_pixels_;
|
||||
|
||||
++glyph_indexes;
|
||||
}
|
||||
|
297
source/detail/text_reshaping.hpp
Normal file
297
source/detail/text_reshaping.hpp
Normal file
@ -0,0 +1,297 @@
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace reshaping
|
||||
{
|
||||
namespace arabic
|
||||
{
|
||||
const unsigned short TATWEEL = 0x0640;
|
||||
const unsigned short ZWJ = 0x200D;
|
||||
|
||||
const int unshaped = 255;
|
||||
const int isolated = 0;
|
||||
const int initial = 1;
|
||||
const int medial = 2;
|
||||
const int final = 3;
|
||||
|
||||
unsigned short letters[][4] = {
|
||||
{0xFE80, 0, 0, 0}, //ARABIC LETTER HAMZA
|
||||
{0xFE81, 0, 0, 0xFE82}, //ARABIC LETTER ALEF WITH MADDA ABOVE
|
||||
{0xFE83, 0, 0, 0xFE84}, //ARABIC LETTER ALEF WITH HAMZA ABOVE
|
||||
{0xFE85, 0, 0, 0xFE86}, //ARABIC LETTER WAW WITH HAMZA ABOVE
|
||||
{0xFE87, 0, 0, 0xFE88}, //ARABIC LETTER ALEF WITH HAMZA BELOW
|
||||
{0xFE89, 0xFE8B, 0xFE8C, 0xFE8A}, //ARABIC LETTER YEH WITH HAMZA ABOVE
|
||||
{0xFE8D, 0, 0, 0xFE8E}, //ARABIC LETTER ALEF
|
||||
{0xFE8F, 0xFE91, 0xFE92, 0xFE90}, //ARABIC LETTER BEH
|
||||
{0xFE93, 0, 0, 0xFE94}, //ARABIC LETTER TEH MARBUTA
|
||||
{0xFE95, 0xFE97, 0xFE98, 0xFE96}, //ARABIC LETTER TEH
|
||||
{0xFE99, 0xFE9B, 0xFE9C, 0xFE9A}, //ARABIC LETTER THEH
|
||||
{0xFE9D, 0xFE9F, 0xFEA0, 0xFE9E}, //ARABIC LETTER JEEM
|
||||
{0xFEA1, 0xFEA3, 0xFEA4, 0xFEA2}, //ARABIC LETTER HAH
|
||||
{0xFEA5, 0xFEA7, 0xFEA8, 0xFEA6}, //ARABIC LETTER KHAH
|
||||
{0xFEA9, 0, 0, 0xFEAA}, //ARABIC LETTER DAL
|
||||
{0xFEAB, 0, 0, 0xFEAC}, //ARABIC LETTER THAL
|
||||
{0xFEAD, 0, 0, 0xFEAE}, //ARABIC LETTER REH
|
||||
{0xFEAF, 0, 0, 0xFEB0}, //ARABIC LETTER ZAIN
|
||||
{0xFEB1, 0xFEB3, 0xFEB4, 0xFEB2}, //ARABIC LETTER SEEN
|
||||
{0xFEB5, 0xFEB7, 0xFEB8, 0xFEB6}, //ARABIC LETTER SHEEN
|
||||
{0xFEB9, 0xFEBB, 0xFEBC, 0xFEBA}, //ARABIC LETTER SAD
|
||||
{0xFEBD, 0xFEBF, 0xFEC0, 0xFEBE}, //ARABIC LETTER DAD
|
||||
{0xFEC1, 0xFEC3, 0xFEC4, 0xFEC2}, //ARABIC LETTER TAH
|
||||
{0xFEC5, 0xFEC7, 0xFEC8, 0xFEC6}, //ARABIC LETTER ZAH
|
||||
{0xFEC9, 0xFECB, 0xFECC, 0xFECA}, //ARABIC LETTER AIN
|
||||
{0xFECD, 0xFECF, 0xFED0, 0xFECE}, //ARABIC LETTER GHAIN
|
||||
{TATWEEL, TATWEEL, TATWEEL, TATWEEL}, //ARABIC TATWEEL
|
||||
{0xFED1, 0xFED3, 0xFED4, 0xFED2}, //ARABIC LETTER FEH
|
||||
{0xFED5, 0xFED7, 0xFED8, 0xFED6}, //ARABIC LETTER QAF
|
||||
{0xFED9, 0xFEDB, 0xFEDC, 0xFEDA}, //ARABIC LETTER KAF
|
||||
{0xFEDD, 0xFEDF, 0xFEE0, 0xFEDE}, //ARABIC LETTER LAM
|
||||
{0xFEE1, 0xFEE3, 0xFEE4, 0xFEE2}, //ARABIC LETTER MEEM
|
||||
{0xFEE5, 0xFEE7, 0xFEE8, 0xFEE6}, //ARABIC LETTER NOON
|
||||
{0xFEE9, 0xFEEB, 0xFEEC, 0xFEEA}, //ARABIC LETTER HEH
|
||||
{0xFEED, 0, 0, 0xFEEE}, //ARABIC LETTER WAW
|
||||
{0xFEEF, 0xFBE8, 0xFBE9, 0xFEF0}, //ARABIC LETTER (UIGHUR KAZAKH KIRGHIZ)? ALEF MAKSURA
|
||||
{0xFEF1, 0xFEF3, 0xFEF4, 0xFEF2}, //ARABIC LETTER YEH
|
||||
{0xFB50, 0, 0, 0xFB51}, //ARABIC LETTER ALEF WASLA
|
||||
{0xFBDD, 0, 0, 0}, //ARABIC LETTER U WITH HAMZA ABOVE
|
||||
{0xFB66, 0xFB68, 0xFB69, 0xFB67}, //ARABIC LETTER TTEH
|
||||
{0xFB5E, 0xFB60, 0xFB61, 0xFB5F}, //ARABIC LETTER TTEHEH
|
||||
{0xFB52, 0xFB54, 0xFB55, 0xFB53}, //ARABIC LETTER BEEH
|
||||
{0xFB56, 0xFB58, 0xFB59, 0xFB57}, //ARABIC LETTER PEH
|
||||
{0xFB62, 0xFB64, 0xFB65, 0xFB63}, //ARABIC LETTER TEHEH
|
||||
{0xFB5A, 0xFB5C, 0xFB5D, 0xFB5B}, //ARABIC LETTER BEHEH
|
||||
{0xFB76, 0xFB78, 0xFB79, 0xFB77}, //ARABIC LETTER NYEH
|
||||
{0xFB72, 0xFB74, 0xFB75, 0xFB73}, //ARABIC LETTER DYEH
|
||||
{0xFB7A, 0xFB7C, 0xFB7D, 0xFB7B}, //ARABIC LETTER TCHEH
|
||||
{0xFB7E, 0xFB80, 0xFB81, 0xFB7F}, //ARABIC LETTER TCHEHEH
|
||||
{0xFB88, 0, 0, 0xFB89}, //ARABIC LETTER DDAL
|
||||
{0xFB84, 0, 0, 0xFB85}, //ARABIC LETTER DAHAL
|
||||
{0xFB82, 0, 0, 0xFB83}, //ARABIC LETTER DDAHAL
|
||||
{0xFB86, 0, 0, 0xFB87}, //ARABIC LETTER DUL
|
||||
{0xFB8C, 0, 0, 0xFB8D}, //ARABIC LETTER RREH
|
||||
{0xFB8A, 0, 0, 0xFB8B}, //ARABIC LETTER JEH
|
||||
{0xFB6A, 0xFB6C, 0xFB6D, 0xFB6B}, //ARABIC LETTER VEH
|
||||
{0xFB6E, 0xFB70, 0xFB71, 0xFB6F}, //ARABIC LETTER PEHEH
|
||||
{0xFB8E, 0xFB90, 0xFB91, 0xFB8F}, //ARABIC LETTER KEHEH
|
||||
{0xFBD3, 0xFBD5, 0xFBD6, 0xFBD4}, //ARABIC LETTER NG
|
||||
{0xFB92, 0xFB94, 0xFB95, 0xFB93}, //ARABIC LETTER GAF
|
||||
{0xFB9A, 0xFB9C, 0xFB9D, 0xFB9B}, //ARABIC LETTER NGOEH
|
||||
{0xFB96, 0xFB98, 0xFB99, 0xFB97}, //ARABIC LETTER GUEH
|
||||
{0xFB9E, 0, 0, 0xFB9F}, //ARABIC LETTER NOON GHUNNA
|
||||
{0xFBA0, 0xFBA2, 0xFBA3, 0xFBA1}, //ARABIC LETTER RNOON
|
||||
{0xFBAA, 0xFBAC, 0xFBAD, 0xFBAB}, //ARABIC LETTER HEH DOACHASHMEE
|
||||
{0xFBA4, 0, 0, 0xFBA5}, //ARABIC LETTER HEH WITH YEH ABOVE
|
||||
{0xFBA6, 0xFBA8, 0xFBA9, 0xFBA7}, //ARABIC LETTER HEH GOAL
|
||||
{0xFBE0, 0, 0, 0xFBE1}, //ARABIC LETTER KIRGHIZ OE
|
||||
{0xFBD9, 0, 0, 0xFBDA}, //ARABIC LETTER OE
|
||||
{0xFBD7, 0, 0, 0xFBD8}, //ARABIC LETTER U
|
||||
{0xFBDB, 0, 0, 0xFBDC}, //ARABIC LETTER YU
|
||||
{0xFBE2, 0, 0, 0xFBE3}, //ARABIC LETTER KIRGHIZ YU
|
||||
{0xFBDE, 0, 0, 0xFBDF}, //ARABIC LETTER VE
|
||||
{0xFBFC, 0xFBFE, 0xFBFF, 0xFBFD}, //ARABIC LETTER FARSI YEH
|
||||
{0xFBE4, 0xFBE6, 0xFBE7, 0xFBE5}, //ARABIC LETTER E
|
||||
{0xFBAE, 0, 0, 0xFBAF}, //ARABIC LETTER YEH BARREE
|
||||
{0xFBB0, 0, 0, 0xFBB1}, //ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
|
||||
{ZWJ, ZWJ, ZWJ, ZWJ}
|
||||
};
|
||||
|
||||
bool harakat(wchar_t letter)
|
||||
{
|
||||
return
|
||||
(0x0610 <= letter && letter <= 0x061A) ||
|
||||
(0x064B <= letter && letter <= 0x065F) ||
|
||||
(0x0670 == letter) ||
|
||||
(0x06D6 <= letter && letter <= 0x06DC) ||
|
||||
(0x06DF <= letter && letter <= 0x06E8) ||
|
||||
(0x06EA <= letter && letter <= 0x06ED) ||
|
||||
(0x08D4 <= letter && letter <= 0x08E1) ||
|
||||
(0x08D4 <= letter && letter <= 0x08ED) ||
|
||||
(0x08E3 <= letter && letter <= 0x08FF);
|
||||
}
|
||||
|
||||
int form_index(wchar_t letter)
|
||||
{
|
||||
static unsigned short ranges[][2]={
|
||||
{0x0621, 0x063A},
|
||||
{0x0640, 0x064A},
|
||||
{0x0671, 0x0671},
|
||||
{0x0677, 0x0677},
|
||||
{0x0679, 0x067B},
|
||||
{0x067E, 0x0680},
|
||||
{0x0683, 0x0684},
|
||||
{0x0686, 0x0688},
|
||||
{0x068C, 0x068E},
|
||||
{0x0691, 0x0691},
|
||||
{0x0698, 0x0698},
|
||||
{0x06A4, 0x06A4},
|
||||
{0x06A6, 0x06A6},
|
||||
{0x06A9, 0x06A9},
|
||||
{0x06AD, 0x06AD},
|
||||
{0x06AF, 0x06AF},
|
||||
{0x06B1, 0x06B1},
|
||||
{0x06B3, 0x06B3},
|
||||
{0x06BA, 0x06BB},
|
||||
{0x06BE, 0x06BE},
|
||||
{0x06C0, 0x06C1},
|
||||
{0x06C5, 0x06C9},
|
||||
{0x06CB, 0x06CC},
|
||||
{0x06D0, 0x06D0},
|
||||
{0x06D2, 0x06D3},
|
||||
{ZWJ, ZWJ}
|
||||
};
|
||||
|
||||
if((letter < 0x0621) || (0x06D3 < letter && letter != ZWJ))
|
||||
return -1;
|
||||
|
||||
int base = 0;
|
||||
for(std::size_t i = 0; i < sizeof(ranges) / sizeof(unsigned short) / 2; ++i)
|
||||
{
|
||||
if(ranges[i][0] <= letter && letter <= ranges[i][1])
|
||||
return static_cast<int>(letter - ranges[i][0]) + base;
|
||||
|
||||
base += static_cast<int>(ranges[i][1] - ranges[i][0]) + 1;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
wchar_t connect_before(wchar_t letter)
|
||||
{
|
||||
auto idx = form_index(letter);
|
||||
if(idx < 0)
|
||||
return 0;
|
||||
|
||||
return letters[idx][final] || letters[idx][medial];
|
||||
}
|
||||
|
||||
wchar_t connect_after(wchar_t letter)
|
||||
{
|
||||
auto idx = form_index(letter);
|
||||
if(idx < 0)
|
||||
return 0;
|
||||
|
||||
return letters[idx][initial] || letters[idx][medial];
|
||||
}
|
||||
|
||||
wchar_t connect_before_after(wchar_t letter)
|
||||
{
|
||||
auto idx = form_index(letter);
|
||||
if(idx < 0)
|
||||
return 0;
|
||||
|
||||
return letters[idx][medial];
|
||||
}
|
||||
|
||||
std::wstring reshape(const std::wstring& text)
|
||||
{
|
||||
bool const use_unshaped_instead_of_isolated = false;
|
||||
bool const delete_harakat = true;
|
||||
bool const shift_harakat_position = false;
|
||||
bool const delete_tatweel = false;
|
||||
bool const support_zwj = true;
|
||||
|
||||
const int no_form = -1;
|
||||
const int isolated_form = use_unshaped_instead_of_isolated ? unshaped : isolated;
|
||||
|
||||
std::wstring output;
|
||||
std::vector<int> forms;
|
||||
|
||||
std::map<int, std::wstring> positions_harakat;
|
||||
|
||||
for(auto letter: text)
|
||||
{
|
||||
if(harakat(letter))
|
||||
{
|
||||
if(!delete_harakat)
|
||||
{
|
||||
int position = static_cast<int>(output.size()) - 1;
|
||||
|
||||
if (shift_harakat_position)
|
||||
--position;
|
||||
if (positions_harakat.count(position) == 0)
|
||||
positions_harakat[position];
|
||||
|
||||
if (shift_harakat_position)
|
||||
{
|
||||
auto & ph = positions_harakat[position];
|
||||
ph.insert(ph.cbegin(), letter);
|
||||
}
|
||||
else
|
||||
positions_harakat[position] += letter;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if(((TATWEEL == letter) && delete_tatweel) || (ZWJ == letter && !support_zwj))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto idx = form_index(letter);
|
||||
if(idx < 0)
|
||||
{
|
||||
output += letter;
|
||||
forms.push_back(no_form);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(forms.empty())
|
||||
{
|
||||
output += letter;
|
||||
forms.push_back(isolated_form);
|
||||
continue;
|
||||
}
|
||||
|
||||
if((forms.back() == no_form) || (!connect_before(letter)) || (!connect_after(output.back())) ||
|
||||
((forms.back() == final) && !connect_before_after(output.back())))
|
||||
{
|
||||
output += letter;
|
||||
forms.push_back(isolated_form);
|
||||
}
|
||||
else if(forms.back() == isolated_form)
|
||||
{
|
||||
forms.back() = initial;
|
||||
|
||||
output += letter;
|
||||
forms.push_back(final);
|
||||
}
|
||||
else
|
||||
{
|
||||
forms.back() = medial;
|
||||
output += letter;
|
||||
forms.push_back(final);
|
||||
}
|
||||
|
||||
//Remove ZWJ if it's the second to last item as it won't be useful
|
||||
if(support_zwj && (output.size() > 1) && (output[output.size() - 2] == ZWJ))
|
||||
output.erase(output.size() - 2, 1);
|
||||
}
|
||||
|
||||
//Remove ZWJ if it's the second to last item as it won't be useful
|
||||
if(support_zwj && (output.size() > 0) && (output.back() == ZWJ))
|
||||
output.pop_back();
|
||||
|
||||
|
||||
std::wstring result;
|
||||
if((!delete_harakat) && positions_harakat.count(-1))
|
||||
result += positions_harakat[-1];
|
||||
|
||||
for(std::size_t i = 0; i < output.size(); ++i)
|
||||
{
|
||||
if(output[i])
|
||||
{
|
||||
if(forms[i] == no_form || forms[i] == unshaped)
|
||||
result += output[i];
|
||||
else
|
||||
result += letters[form_index(output[i])][forms[i]];
|
||||
}
|
||||
|
||||
if(!delete_harakat)
|
||||
if(positions_harakat.count(i))
|
||||
result += positions_harakat[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}//end namespace arabic
|
||||
}//end namespace reshaping
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An Animation Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -40,6 +40,7 @@ namespace nana
|
||||
{
|
||||
drawing::diehard_t diehard{ nullptr };
|
||||
std::vector<nana::point> points;
|
||||
std::vector<std::function<rectangle()>> areas;
|
||||
};
|
||||
|
||||
struct framebuilder
|
||||
@ -184,7 +185,7 @@ namespace nana
|
||||
std::list<frame> frames;
|
||||
std::list<frame>::iterator this_frame;
|
||||
std::size_t pos_in_this_frame{ 0 };
|
||||
mutable bool good_frame_by_frmbuilder{ false }; //It indicates the state of frame whether is valid.
|
||||
mutable bool good_frame_by_frmbuilder{ false }; //It indicates the state of frame.
|
||||
|
||||
impl()
|
||||
: this_frame(frames.end())
|
||||
@ -200,52 +201,96 @@ namespace nana
|
||||
switch(frmobj.type)
|
||||
{
|
||||
case frame::kind::oneshot:
|
||||
_m_render(outs, [&frmobj](paint::graphics& tar, const nana::point& pos)
|
||||
_m_render(outs, frmobj.u.oneshot->size(), [&frmobj](paint::graphics& tar, const nana::rectangle& area)
|
||||
{
|
||||
frmobj.u.oneshot->paste(tar, pos);
|
||||
if(frmobj.u.oneshot->size() == area.dimension())
|
||||
frmobj.u.oneshot->paste(tar, area.position());
|
||||
else
|
||||
frmobj.u.oneshot->stretch(rectangle{frmobj.u.oneshot->size()}, tar, area);
|
||||
});
|
||||
break;
|
||||
case frame::kind::framebuilder:
|
||||
good_frame_by_frmbuilder = frmobj.u.frbuilder->frbuilder(pos_in_this_frame, framegraph, framegraph_dimension);
|
||||
if(good_frame_by_frmbuilder)
|
||||
{
|
||||
nana::rectangle r(framegraph_dimension);
|
||||
_m_render(outs, [&r, &framegraph](paint::graphics& tar, const nana::point& pos) mutable
|
||||
_m_render(outs, framegraph_dimension, [framegraph_dimension, &framegraph](paint::graphics& tar, const rectangle& area) mutable
|
||||
{
|
||||
r.x = pos.x;
|
||||
r.y = pos.y;
|
||||
tar.bitblt(r, framegraph);
|
||||
if(framegraph_dimension == area.dimension())
|
||||
tar.bitblt(area, framegraph);
|
||||
else
|
||||
framegraph.stretch(tar, area);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Render a frame on a specified window graph
|
||||
void render_this(paint::graphics& graph, const nana::point& pos, paint::graphics& framegraph, nana::size& framegraph_dimension, bool rebuild_frame) const
|
||||
//Render a frame on a specified window graph. If this frame is created by framebuilder, it doesn't rebuild the frame.
|
||||
void render_this(paint::graphics& graph, const rectangle& area, paint::graphics& framegraph, nana::size& framegraph_dimension) const
|
||||
{
|
||||
if(this_frame == frames.end())
|
||||
return;
|
||||
// If the frame is EOF, then renders the last frame
|
||||
std::list<nana::frame>::const_iterator pf = this_frame;
|
||||
if (pf == frames.end())
|
||||
{
|
||||
if (frames.size())
|
||||
{
|
||||
pf = frames.begin();
|
||||
std::advance(pf, frames.size() - 1);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
frame & frmobj = *this_frame;
|
||||
switch(frmobj.type)
|
||||
const frame & frmobj = *pf;
|
||||
switch (frmobj.type)
|
||||
{
|
||||
case frame::kind::oneshot:
|
||||
frmobj.u.oneshot->paste(graph, pos);
|
||||
if (frmobj.u.oneshot->size() == area.dimension())
|
||||
frmobj.u.oneshot->paste(graph, area.position());
|
||||
else
|
||||
frmobj.u.oneshot->stretch(rectangle{frmobj.u.oneshot->size()}, graph, area);
|
||||
break;
|
||||
case frame::kind::framebuilder:
|
||||
if(rebuild_frame)
|
||||
good_frame_by_frmbuilder = frmobj.u.frbuilder->frbuilder(pos_in_this_frame, framegraph, framegraph_dimension);
|
||||
|
||||
if(good_frame_by_frmbuilder)
|
||||
{
|
||||
nana::rectangle r(pos, framegraph_dimension);
|
||||
graph.bitblt(r, framegraph);
|
||||
if (framegraph_dimension == area.dimension())
|
||||
graph.bitblt(area, framegraph);
|
||||
else
|
||||
framegraph.stretch(graph, area);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nana::size this_frame_size(const nana::size& framegraph_dimension) const
|
||||
{
|
||||
// If the frame is EOF, then renders the last frame
|
||||
std::list<nana::frame>::const_iterator pf = this_frame;
|
||||
if (pf == frames.end())
|
||||
{
|
||||
if (frames.size())
|
||||
{
|
||||
pf = frames.begin();
|
||||
std::advance(pf, frames.size() - 1);
|
||||
}
|
||||
else
|
||||
return{};
|
||||
}
|
||||
|
||||
const frame & frmobj = *pf;
|
||||
switch (frmobj.type)
|
||||
{
|
||||
case frame::kind::oneshot:
|
||||
return frmobj.u.oneshot->size();
|
||||
case frame::kind::framebuilder:
|
||||
if (good_frame_by_frmbuilder)
|
||||
return framegraph_dimension;
|
||||
break;
|
||||
}
|
||||
|
||||
return{};
|
||||
}
|
||||
|
||||
bool eof() const
|
||||
{
|
||||
return (frames.end() == this_frame);
|
||||
@ -285,8 +330,10 @@ namespace nana
|
||||
}
|
||||
private:
|
||||
template<typename Renderer>
|
||||
void _m_render(std::map<window, output_t>& outs, Renderer renderer) const
|
||||
void _m_render(std::map<window, output_t>& outs, const nana::size& frame_size, Renderer renderer) const
|
||||
{
|
||||
nana::rectangle frame_area{frame_size};
|
||||
|
||||
for(auto & tar: outs)
|
||||
{
|
||||
auto graph = API::dev::window_graphics(tar.first);
|
||||
@ -294,7 +341,13 @@ namespace nana
|
||||
continue;
|
||||
|
||||
for(auto & outp : tar.second.points)
|
||||
renderer(*graph, outp);
|
||||
{
|
||||
frame_area.position(outp);
|
||||
renderer(*graph, frame_area);
|
||||
}
|
||||
|
||||
for(auto& area_fn: tar.second.areas)
|
||||
renderer(*graph, area_fn());
|
||||
|
||||
API::update_window(tar.first);
|
||||
}
|
||||
@ -302,7 +355,7 @@ namespace nana
|
||||
};//end struct frameset::impl
|
||||
//public:
|
||||
frameset::frameset()
|
||||
: impl_(new impl)
|
||||
: impl_(std::make_unique<impl>())
|
||||
{}
|
||||
|
||||
void frameset::push_back(paint::image img)
|
||||
@ -339,6 +392,8 @@ namespace nana
|
||||
double performance_parameter;
|
||||
};
|
||||
|
||||
~performance_manager();
|
||||
|
||||
void insert(impl* p);
|
||||
void set_fps(impl*, std::size_t new_fps);
|
||||
void close(impl* p);
|
||||
@ -400,19 +455,32 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
void render_this_specifically(paint::graphics& graph, const nana::point& pos)
|
||||
// Renders current frame to a specified graphics
|
||||
void render_this_frame(paint::graphics& graph, const rectangle& area)
|
||||
{
|
||||
if(state.this_frameset != framesets.end())
|
||||
state.this_frameset->impl_->render_this(graph, pos, framegraph, framegraph_dimension, false);
|
||||
state.this_frameset->impl_->render_this(graph, area, framegraph, framegraph_dimension);
|
||||
}
|
||||
|
||||
// Renders current from to all outputs graphics
|
||||
void render_this_frame()
|
||||
{
|
||||
if(state.this_frameset != framesets.end())
|
||||
state.this_frameset->impl_->render_this(outputs, framegraph, framegraph_dimension);
|
||||
}
|
||||
|
||||
bool move_to_next()
|
||||
nana::size this_frame_size() const
|
||||
{
|
||||
if (state.this_frameset != framesets.end())
|
||||
{
|
||||
return state.this_frameset->impl_->this_frame_size(framegraph_dimension);
|
||||
}
|
||||
return{};
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool next_frame()
|
||||
{
|
||||
if(state.this_frameset != framesets.end())
|
||||
{
|
||||
@ -429,9 +497,28 @@ namespace nana
|
||||
if(state.this_frameset != framesets.end())
|
||||
state.this_frameset->impl_->reset();
|
||||
}
|
||||
|
||||
bool eof() const
|
||||
{
|
||||
if(state.this_frameset != framesets.end())
|
||||
return state.this_frameset->impl_->eof();
|
||||
|
||||
return true;
|
||||
}
|
||||
};//end struct animation::impl
|
||||
|
||||
//class animation::performance_manager
|
||||
animation::performance_manager::~performance_manager()
|
||||
{
|
||||
for (auto thr : threads_)
|
||||
{
|
||||
if (thr->thread && thr->thread->joinable())
|
||||
thr->thread->join();
|
||||
|
||||
delete thr;
|
||||
}
|
||||
}
|
||||
|
||||
void animation::performance_manager::insert(impl* p)
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
@ -449,20 +536,26 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
auto thr = new thread_variable;
|
||||
auto thr = std::make_unique<thread_variable>();
|
||||
thr->animations.push_back(p);
|
||||
thr->performance_parameter = 0.0;
|
||||
thr->fps = p->fps;
|
||||
thr->interval = 1000.0 / double(p->fps);
|
||||
thr->thread = std::make_shared<std::thread>([thr]()
|
||||
auto pthr = thr.get();
|
||||
thr->thread = std::make_shared<std::thread>([pthr]()
|
||||
{
|
||||
auto thr = pthr;
|
||||
nana::system::timepiece tmpiece;
|
||||
tmpiece.start();
|
||||
|
||||
while (true)
|
||||
{
|
||||
thr->active = 0;
|
||||
tmpiece.start();
|
||||
|
||||
{
|
||||
//acquire the isg lock first to avoid deadlock that occured by an event hander which operates the animation object.
|
||||
nana::internal_scope_guard isglock;
|
||||
|
||||
std::lock_guard<decltype(thr->mutex)> lock(thr->mutex);
|
||||
for (auto ani : thr->animations)
|
||||
{
|
||||
@ -470,7 +563,25 @@ namespace nana
|
||||
continue;
|
||||
|
||||
ani->render_this_frame();
|
||||
if (false == ani->move_to_next())
|
||||
}
|
||||
}
|
||||
|
||||
thr->performance_parameter = tmpiece.calc();
|
||||
if (thr->performance_parameter < thr->interval)
|
||||
nana::system::sleep(static_cast<unsigned>(thr->interval - thr->performance_parameter));
|
||||
|
||||
//Restart timing this frame
|
||||
tmpiece.start();
|
||||
|
||||
// Move to next frame
|
||||
{
|
||||
std::lock_guard<decltype(thr->mutex)> lock(thr->mutex);
|
||||
for (auto ani : thr->animations)
|
||||
{
|
||||
if (ani->paused)
|
||||
continue;
|
||||
|
||||
if (false == ani->next_frame())
|
||||
{
|
||||
if (ani->looped)
|
||||
{
|
||||
@ -483,25 +594,31 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
if (thr->active)
|
||||
{
|
||||
thr->performance_parameter = tmpiece.calc();
|
||||
if (thr->performance_parameter < thr->interval)
|
||||
nana::system::sleep(static_cast<unsigned>(thr->interval - thr->performance_parameter));
|
||||
}
|
||||
else
|
||||
if (0 == thr->active)
|
||||
{
|
||||
//There isn't an active frame, then let the thread
|
||||
//wait for a signal for an active animation
|
||||
std::unique_lock<std::mutex> lock(thr->mutex);
|
||||
|
||||
//Exit the thread if there is not an animation
|
||||
if (thr->animations.empty())
|
||||
return;
|
||||
|
||||
if (0 == thr->active)
|
||||
thr->condvar.wait(lock);
|
||||
|
||||
//Exit the thread if there is not an animation
|
||||
if (thr->animations.empty())
|
||||
return;
|
||||
|
||||
//Restart timing for this frame when this thread is waking up.
|
||||
tmpiece.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
threads_.push_back(thr);
|
||||
p->thr_variable = thr;
|
||||
threads_.push_back(thr.release());
|
||||
p->thr_variable = threads_.back();
|
||||
}
|
||||
|
||||
void animation::performance_manager::set_fps(impl* p, std::size_t new_fps)
|
||||
@ -525,10 +642,13 @@ namespace nana
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
|
||||
auto u = std::find(thr->animations.begin(), thr->animations.end(), p);
|
||||
if (u != thr->animations.end())
|
||||
thr->animations.erase(u);
|
||||
{
|
||||
// the mutex of thread variable may be acquired by insert()
|
||||
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
|
||||
auto u = std::find(thr->animations.begin(), thr->animations.end(), p);
|
||||
if (u != thr->animations.end())
|
||||
thr->animations.erase(u);
|
||||
}
|
||||
|
||||
p->thr_variable = nullptr;
|
||||
insert(p);
|
||||
@ -542,11 +662,30 @@ namespace nana
|
||||
return;
|
||||
|
||||
auto thr = *i;
|
||||
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
|
||||
|
||||
auto u = std::find(thr->animations.begin(), thr->animations.end(), p);
|
||||
if(u != thr->animations.end())
|
||||
thr->animations.erase(u);
|
||||
{
|
||||
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
|
||||
|
||||
auto u = std::find(thr->animations.begin(), thr->animations.end(), p);
|
||||
if (u != thr->animations.end())
|
||||
thr->animations.erase(u);
|
||||
|
||||
//If there is not an animation in the thread, wake up the thread to exit.
|
||||
//If there is an animation in the thread, set the thr pointer to nullptr to
|
||||
//avoid exiting the thread
|
||||
if (thr->animations.empty())
|
||||
thr->condvar.notify_one();
|
||||
else
|
||||
thr = nullptr;
|
||||
}
|
||||
|
||||
p->thr_variable = nullptr;
|
||||
|
||||
threads_.erase(i);
|
||||
if (thr && thr->thread && thr->thread->joinable())
|
||||
thr->thread->join();
|
||||
|
||||
delete thr;
|
||||
}
|
||||
|
||||
bool animation::performance_manager::empty() const
|
||||
@ -562,30 +701,23 @@ namespace nana
|
||||
//end class animation::performance_manager
|
||||
|
||||
animation::animation(std::size_t fps)
|
||||
: impl_(new impl(fps))
|
||||
: impl_(std::make_unique<impl>(fps))
|
||||
{
|
||||
}
|
||||
|
||||
animation::~animation()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
animation::~animation() = default;
|
||||
|
||||
animation::animation(animation&& rhs)
|
||||
: impl_(rhs.impl_)
|
||||
: impl_(std::move(rhs.impl_))
|
||||
{
|
||||
rhs.impl_ = new impl(23);
|
||||
rhs.impl_ = std::make_unique<impl>(23);
|
||||
}
|
||||
|
||||
animation& animation::operator=(animation&& rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
auto imp = new impl{ 23 };
|
||||
|
||||
delete impl_;
|
||||
impl_ = rhs.impl_;
|
||||
rhs.impl_ = imp;
|
||||
std::swap(rhs.impl_, this->impl_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -633,6 +765,9 @@ namespace nana
|
||||
std::unique_lock<std::mutex> lock(impl_->thr_variable->mutex);
|
||||
if(0 == impl_->thr_variable->active)
|
||||
{
|
||||
if (impl_->eof())
|
||||
impl_->reset();
|
||||
|
||||
impl_->thr_variable->active = 1;
|
||||
impl_->thr_variable->condvar.notify_one();
|
||||
}
|
||||
@ -651,7 +786,7 @@ namespace nana
|
||||
{
|
||||
drawing dw(wd);
|
||||
output.diehard = dw.draw_diehard([this, pos](paint::graphics& tar){
|
||||
impl_->render_this_specifically(tar, pos);
|
||||
impl_->render_this_frame(tar, rectangle{ pos, impl_->this_frame_size() });
|
||||
});
|
||||
|
||||
API::events(wd).destroy.connect([this](const arg_destroy& arg){
|
||||
@ -662,12 +797,31 @@ namespace nana
|
||||
output.points.push_back(pos);
|
||||
}
|
||||
|
||||
void animation::output(window wd, std::function<nana::rectangle()> r)
|
||||
{
|
||||
auto & output = impl_->outputs[wd];
|
||||
|
||||
if(nullptr == output.diehard)
|
||||
{
|
||||
drawing dw(wd);
|
||||
output.diehard = dw.draw_diehard([this, r](paint::graphics& tar){
|
||||
impl_->render_this_frame(tar, r());
|
||||
});
|
||||
|
||||
API::events(wd).destroy.connect([this](const arg_destroy& arg){
|
||||
std::lock_guard<decltype(impl_->thr_variable->mutex)> lock(impl_->thr_variable->mutex);
|
||||
impl_->outputs.erase(arg.window_handle);
|
||||
});
|
||||
}
|
||||
output.areas.push_back(r);
|
||||
}
|
||||
|
||||
void animation::fps(std::size_t n)
|
||||
{
|
||||
if (n == impl_->fps)
|
||||
return;
|
||||
|
||||
impl::perf_manager->set_fps(impl_, n);
|
||||
impl::perf_manager->set_fps(impl_.get(), n);
|
||||
}
|
||||
|
||||
std::size_t animation::fps() const
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Bedrock Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -1191,9 +1191,7 @@ namespace detail
|
||||
}
|
||||
else if (pointer_wd != root_window)
|
||||
{
|
||||
DWORD pid = 0;
|
||||
::GetWindowThreadProcessId(pointer_wd, &pid);
|
||||
if (pid == ::GetCurrentProcessId())
|
||||
if (::GetWindowThreadProcessId(pointer_wd, nullptr) != ::GetCurrentThreadId())
|
||||
::PostMessage(pointer_wd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* An Implementation of Place for Layout
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE or copy at
|
||||
@ -1810,6 +1810,12 @@ namespace nana
|
||||
{
|
||||
grabbed_ = false;
|
||||
this->_m_update_div(impl_->div_text);
|
||||
|
||||
//revise the position of splitter window.(#512)
|
||||
//when the splitter is dragged, the place recalculates the left/right fields the weight in percentage, then update
|
||||
//position of the splitter field. It may cause deviation that new splitter field position is not same with the position of
|
||||
//splitter window after dragging a bit, because the field position is calcuated with left/right fields's weights which are float-point values.
|
||||
splitter_.move(this->field_area);
|
||||
}
|
||||
else if (event_code::mouse_move == arg.evt_code)
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A List Box Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -5736,6 +5736,14 @@ namespace nana
|
||||
return index_pair{ npos, npos };
|
||||
}
|
||||
|
||||
listbox::index_pair listbox::index_cast(index_pair idx, bool from_display_order) const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
|
||||
idx.item = at(idx.cat).index_cast(idx.item, from_display_order);
|
||||
return idx;
|
||||
}
|
||||
|
||||
listbox::index_pair listbox::hovered(bool return_end) const
|
||||
{
|
||||
using parts = drawerbase::listbox::essence::parts;
|
||||
@ -5755,9 +5763,11 @@ namespace nana
|
||||
if (0 < pos.cat)
|
||||
--pos.cat;
|
||||
pos.item = this->size_item(pos.cat);
|
||||
}
|
||||
return pos;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
return index_cast(pos, true);
|
||||
}
|
||||
else if (return_end)
|
||||
return index_pair{ this->size_categ() - 1, this->size_item(this->size_categ() - 1) };
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A text editor implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -1637,16 +1637,16 @@ namespace nana {
|
||||
|
||||
|
||||
|
||||
if (select_.a.x < line.size() && !std::isalnum(line[select_.a.x]) && line[select_.a.x] != '_') {
|
||||
if (select_.a.x < line.size() && !std::iswalnum(line[select_.a.x]) && line[select_.a.x] != '_') {
|
||||
++select_.b.x;
|
||||
}
|
||||
else {
|
||||
// Expand the selection forward to the word's end.
|
||||
while (select_.b.x < line.size() && !std::iswspace(line[select_.b.x]) && (std::isalnum(line[select_.b.x]) || line[select_.b.x] == '_'))
|
||||
while (select_.b.x < line.size() && !std::iswspace(line[select_.b.x]) && (std::iswalnum(line[select_.b.x]) || line[select_.b.x] == '_'))
|
||||
++select_.b.x;
|
||||
|
||||
// Expand the selection backward to the word's start.
|
||||
while (select_.a.x > 0 && !std::iswspace(line[select_.a.x - 1]) && (std::isalnum(line[select_.a.x - 1]) || line[select_.a.x - 1] == '_'))
|
||||
while (select_.a.x > 0 && !std::iswspace(line[select_.a.x - 1]) && (std::iswalnum(line[select_.a.x - 1]) || line[select_.a.x - 1] == '_'))
|
||||
--select_.a.x;
|
||||
}
|
||||
select_.mode_selection = selection::mode::method_selected;
|
||||
@ -2482,10 +2482,8 @@ namespace nana {
|
||||
|
||||
if (coord != coord_org)
|
||||
{
|
||||
auto pos_x = pos.x;
|
||||
impl_->cview->move_origin(origin - impl_->cview->origin());
|
||||
pos = _m_coordinate_to_caret(coord, false);
|
||||
pos.x = pos_x;
|
||||
}
|
||||
|
||||
if (pos != points_.caret) {
|
||||
@ -3485,9 +3483,14 @@ namespace nana {
|
||||
|
||||
void rtl_string(point strpos, const wchar_t* str, std::size_t len, std::size_t str_px, unsigned glyph_front, unsigned glyph_selected, bool has_focused)
|
||||
{
|
||||
editor_._m_draw_parse_string(parser_, true, strpos, selection_color(true, has_focused), str, len);
|
||||
//Draw twices for RTL language in order to avoid character transforming.
|
||||
//one is to draw whole string as unselected, another one is to draw whole string as selected.
|
||||
|
||||
//Draw as unselected
|
||||
editor_._m_draw_parse_string(parser_, true, strpos, editor_.scheme_->foreground, str, len);
|
||||
|
||||
//Draw selected part
|
||||
|
||||
//Draw as selected, and copy the selected part to the graph.
|
||||
paint::graphics graph({ glyph_selected, line_px_ });
|
||||
graph.typeface(this->graph_.typeface());
|
||||
graph.rectangle(true, selection_color(false, has_focused));
|
||||
|
@ -1736,11 +1736,11 @@ namespace nana
|
||||
//class trigger
|
||||
//struct treebox_node_type
|
||||
trigger::treebox_node_type::treebox_node_type()
|
||||
:expanded(false), checked(checkstate::unchecked), hidden(false)
|
||||
:expanded(false), hidden(false), checked(checkstate::unchecked)
|
||||
{}
|
||||
|
||||
trigger::treebox_node_type::treebox_node_type(std::string text)
|
||||
:text(std::move(text)), expanded(false), checked(checkstate::unchecked), hidden(false)
|
||||
:text(std::move(text)), expanded(false), hidden(false), checked(checkstate::unchecked)
|
||||
{}
|
||||
|
||||
trigger::treebox_node_type& trigger::treebox_node_type::operator=(const treebox_node_type& rhs)
|
||||
@ -2465,6 +2465,12 @@ namespace nana
|
||||
dw->impl()->use_entire_line = enable;
|
||||
}
|
||||
|
||||
auto treebox::first() const -> item_proxy
|
||||
{
|
||||
auto impl = get_drawer_trigger().impl();
|
||||
return item_proxy{ const_cast<drawer_trigger_t*>(&get_drawer_trigger()), impl->attr.tree_cont.get_root()->child };
|
||||
}
|
||||
|
||||
std::shared_ptr<scroll_operation_interface> treebox::_m_scroll_operation()
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Bitmap Format Graphics Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -14,6 +14,7 @@
|
||||
#define NANA_PAINT_DETAIL_IMAGE_BMP_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include "image_pixbuf.hpp"
|
||||
|
||||
namespace nana{ namespace paint
|
||||
@ -106,7 +107,7 @@ namespace nana{ namespace paint
|
||||
if (16 <= header->biBitCount)
|
||||
pixbuf_.put(bits, header->biWidth, bmp_height, header->biBitCount, bytes_per_line, (header->biHeight < 0));
|
||||
else
|
||||
_m_put_with_palette(header, bits, bytes_per_line);
|
||||
_m_put_with_palette(header, bits, bmp_file->bfSize - bmp_file->bfOffBits, bytes_per_line);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -132,7 +133,72 @@ namespace nana{ namespace paint
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
void _m_put_with_palette(const bitmap_info_header* header, const unsigned char* pixel_indexes, unsigned line_bytes)
|
||||
std::unique_ptr<unsigned char[]> _m_decompress_rle8(const bitmap_info_header* header, const unsigned char* data, std::size_t data_size)
|
||||
{
|
||||
std::size_t const lines = std::abs(header->biHeight);
|
||||
unsigned char* const indexes = new unsigned char[header->biWidth * lines];
|
||||
auto p = indexes;
|
||||
auto p_line = p;
|
||||
auto const p_end = indexes + header->biWidth * lines;
|
||||
|
||||
std::size_t line_pos = 0;
|
||||
auto end = data + data_size;
|
||||
while (data != end && p < p_end)
|
||||
{
|
||||
if (0 == data[0])
|
||||
{
|
||||
//escape
|
||||
if (0 == data[1])
|
||||
{
|
||||
//eol
|
||||
data += 2;
|
||||
++line_pos;
|
||||
}
|
||||
else if (1 == data[1])
|
||||
{
|
||||
//eof
|
||||
data += 2;
|
||||
break;
|
||||
}
|
||||
else if (2 == data[1])
|
||||
{
|
||||
//delta
|
||||
auto x = data[2];
|
||||
auto y = data[3];
|
||||
|
||||
// Check if the delta is available
|
||||
if ((p + x < p_line + header->biWidth) && (line_pos + y < lines))
|
||||
{
|
||||
p += y * header->biWidth + x;
|
||||
line_pos += y;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
data += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
//absolute
|
||||
std::memcpy(p, data + 2, data[1]);
|
||||
p += data[1];
|
||||
|
||||
data += ((data[1] + 1) & 0xFFE) + 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memset(p, data[1], data[0]);
|
||||
p += data[0];
|
||||
|
||||
data += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<unsigned char[]>{ indexes };
|
||||
}
|
||||
|
||||
void _m_put_with_palette(const bitmap_info_header* header, const unsigned char* bits, std::size_t length, unsigned line_bytes)
|
||||
{
|
||||
auto const image_height = std::abs(header->biHeight);
|
||||
const std::size_t total_pixels = header->biWidth * static_cast<std::size_t>(image_height);
|
||||
@ -152,9 +218,19 @@ namespace nana{ namespace paint
|
||||
|
||||
if (8 == header->biBitCount)
|
||||
{
|
||||
//decompressed indexes
|
||||
std::unique_ptr<unsigned char[]> indexes;
|
||||
|
||||
if (1 == header->biCompression)
|
||||
{
|
||||
indexes = _m_decompress_rle8(header, bits, length);
|
||||
line_bytes = header->biWidth;
|
||||
bits = indexes.get();
|
||||
}
|
||||
|
||||
while (dst_px < end_dst_px)
|
||||
{
|
||||
auto px_indexes = pixel_indexes + line_bytes * line_pos;
|
||||
auto px_indexes = bits + line_bytes * line_pos;
|
||||
auto const line_end_dst_px = dst_px + header->biWidth;
|
||||
while (dst_px != line_end_dst_px)
|
||||
{
|
||||
@ -173,7 +249,7 @@ namespace nana{ namespace paint
|
||||
{
|
||||
while (dst_px < end_dst_px)
|
||||
{
|
||||
auto px_indexes = pixel_indexes + line_bytes * line_pos;
|
||||
auto px_indexes = bits + line_bytes * line_pos;
|
||||
auto const line_end_dst_px = dst_px + header->biWidth;
|
||||
std::size_t pos = 0;
|
||||
switch (header->biBitCount)
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "image_pixbuf.hpp"
|
||||
|
||||
//Separate the libpng from the package that system provides.
|
||||
//Separate the libjpeg from the package that system provides.
|
||||
#if defined(NANA_LIBJPEG)
|
||||
#include <nana_extrlib/jpeglib.h>
|
||||
#else
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Paint Image Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -108,155 +108,72 @@ namespace paint
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::shared_ptr<image::image_impl_interface> create_image(const fs::path & p)
|
||||
// Check file type through file format signature
|
||||
std::shared_ptr<image::image_impl_interface> create_image(const char* buf, std::size_t len)
|
||||
{
|
||||
std::shared_ptr<image::image_impl_interface> ptr;
|
||||
|
||||
auto ext = p.extension().native();
|
||||
if (ext.empty())
|
||||
return ptr;
|
||||
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), [](int ch)
|
||||
if (buf && len >= 8)
|
||||
{
|
||||
if ('A' <= ch && ch <= 'Z')
|
||||
ch -= ('A' - 'a');
|
||||
return ch;
|
||||
});
|
||||
|
||||
#if defined(NANA_WINDOWS)
|
||||
const wchar_t* ext_ico = L".ico";
|
||||
const wchar_t* ext_png = L".png";
|
||||
const wchar_t* ext_jpg = L".jpg";
|
||||
const wchar_t* ext_jpeg = L".jpeg";
|
||||
#else
|
||||
const char* ext_ico = ".ico";
|
||||
const char* ext_png = ".png";
|
||||
const char* ext_jpg = ".jpg";
|
||||
const char* ext_jpeg = ".jpeg";
|
||||
#endif
|
||||
do
|
||||
{
|
||||
if (ext_ico == ext)
|
||||
if (std::strncmp("\x00\x00\x01\x00", buf, 4) == 0)
|
||||
{
|
||||
ptr = std::make_shared<detail::image_ico>();
|
||||
break;
|
||||
return std::make_shared<detail::image_ico>();
|
||||
}
|
||||
|
||||
if (ext_png == ext)
|
||||
else if (std::strncmp(buf, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) == 0)
|
||||
{
|
||||
#if defined(NANA_ENABLE_PNG)
|
||||
ptr = std::make_shared<detail::image_png>();
|
||||
#else
|
||||
return ptr;
|
||||
return std::make_shared<detail::image_png>();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (ext_jpg == ext || ext_jpeg == ext)
|
||||
else if (std::strncmp("\xFF\xD8\xFF", buf, 3) == 0)
|
||||
{
|
||||
#if defined(NANA_ENABLE_JPEG)
|
||||
ptr = std::make_shared<detail::image_jpeg>();
|
||||
#else
|
||||
return ptr;
|
||||
return std::make_shared<detail::image_jpeg>();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
else if (*reinterpret_cast<const short*>("BM") == *reinterpret_cast<const short*>(buf))
|
||||
return std::make_shared<detail::image_bmp>();
|
||||
else if (*reinterpret_cast<const short*>("MZ") == *reinterpret_cast<const short*>(buf))
|
||||
return std::make_shared<detail::image_ico_resource>();
|
||||
}
|
||||
|
||||
//Check for BMP
|
||||
if (!ptr)
|
||||
{
|
||||
#ifndef NANA_MINGW
|
||||
std::ifstream ifs(p.c_str(), std::ios::binary);
|
||||
#else
|
||||
std::ifstream ifs(to_osmbstr(to_utf8(p.native())).c_str(), std::ios::binary);
|
||||
#endif
|
||||
if (ifs)
|
||||
{
|
||||
unsigned short meta = 0;
|
||||
ifs.read(reinterpret_cast<char*>(&meta), 2);
|
||||
if (*reinterpret_cast<const short*>("BM") == meta)
|
||||
ptr = std::make_shared<detail::image_bmp>();
|
||||
else if (*reinterpret_cast<const short*>("MZ") == meta)
|
||||
ptr = std::make_shared<detail::image_ico_resource>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
bool image::open(const ::std::string& img)
|
||||
{
|
||||
fs::path p(img);
|
||||
image_ptr_.reset();
|
||||
|
||||
std::ifstream file{ p, std::ios::binary };
|
||||
if (file)
|
||||
{
|
||||
char buf[8];
|
||||
if (file.read(buf, 8).gcount() == 8)
|
||||
image_ptr_ = create_image(buf, 8);
|
||||
}
|
||||
|
||||
return (image_ptr_ ? image_ptr_->open(p) : false);
|
||||
}
|
||||
|
||||
bool image::open(const ::std::string& file)
|
||||
bool image::open(const std::wstring& img)
|
||||
{
|
||||
fs::path path(file);
|
||||
image_ptr_ = create_image(path);
|
||||
return (image_ptr_ ? image_ptr_->open(path) : false);
|
||||
}
|
||||
fs::path p(img);
|
||||
image_ptr_.reset();
|
||||
|
||||
bool image::open(const std::wstring& file)
|
||||
{
|
||||
fs::path path(file);
|
||||
image_ptr_ = create_image(path);
|
||||
return (image_ptr_ ? image_ptr_->open(path) : false);
|
||||
std::ifstream file{ p, std::ios::binary };
|
||||
if (file)
|
||||
{
|
||||
char buf[8];
|
||||
if (file.read(buf, 8).gcount() == 8)
|
||||
image_ptr_ = create_image(buf, 8);
|
||||
}
|
||||
|
||||
return (image_ptr_ ? image_ptr_->open(p) : false);
|
||||
}
|
||||
|
||||
bool image::open(const void* data, std::size_t bytes)
|
||||
{
|
||||
close();
|
||||
|
||||
if (bytes > 2)
|
||||
{
|
||||
std::shared_ptr<image::image_impl_interface> ptr;
|
||||
|
||||
auto meta = *reinterpret_cast<const unsigned short*>(data);
|
||||
|
||||
if (*reinterpret_cast<const short*>("BM") == meta)
|
||||
ptr = std::make_shared<detail::image_bmp>();
|
||||
else if (*reinterpret_cast<const short*>("MZ") == meta)
|
||||
ptr = std::make_shared<detail::image_ico_resource>();
|
||||
else
|
||||
{
|
||||
if (bytes > 8 && (0x474e5089 == *reinterpret_cast<const unsigned*>(data)))
|
||||
{
|
||||
#if defined(NANA_ENABLE_PNG)
|
||||
ptr = std::make_shared<detail::image_png>();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(NANA_ENABLE_JPEG)
|
||||
if ((bytes > 11) && (0xd8ff == *reinterpret_cast<const unsigned short*>(data)))
|
||||
{
|
||||
switch(*reinterpret_cast<const unsigned*>(reinterpret_cast<const char*>(data)+6))
|
||||
{
|
||||
case 0x4649464A: //JFIF
|
||||
case 0x66697845: //Exif
|
||||
ptr = std::make_shared<detail::image_jpeg>();
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ((!ptr) && (bytes > 40))
|
||||
{
|
||||
switch (*reinterpret_cast<const unsigned*>(data))
|
||||
{
|
||||
case 40:
|
||||
case 0x00010000:
|
||||
if (!ptr && bytes > 40)
|
||||
ptr = std::make_shared<detail::image_ico>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
image_ptr_.swap(ptr);
|
||||
return image_ptr_->open(data, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
image_ptr_ = create_image(static_cast<const char*>(data), bytes);
|
||||
return (image_ptr_ ? image_ptr_->open(data, bytes) : false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Pixel Buffer Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -190,41 +190,42 @@ namespace nana{ namespace paint
|
||||
if (!raw_pixel_buffer)
|
||||
return;
|
||||
|
||||
if ((32 == bits_per_pixel) && (pixel_size.width == width) && (pixel_size.height == height) && (this->bytes_per_line == bytes_per_line) && is_negative)
|
||||
{
|
||||
memcpy(raw_pixel_buffer, rawbits, (bytes_per_line * pixel_size.height));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(pixel_size.width < width)
|
||||
width = pixel_size.width;
|
||||
|
||||
if(pixel_size.height < height)
|
||||
height = pixel_size.height;
|
||||
|
||||
auto rawptr = raw_pixel_buffer;
|
||||
if(32 == bits_per_pixel)
|
||||
{
|
||||
if((pixel_size.width == width) && (pixel_size.height == height) && is_negative)
|
||||
auto d = rawptr;
|
||||
const unsigned char* s;
|
||||
int src_line_bytes;
|
||||
|
||||
if (is_negative)
|
||||
{
|
||||
memcpy(rawptr, rawbits, (pixel_size.width * pixel_size.height) * 4);
|
||||
s = rawbits;
|
||||
src_line_bytes = -static_cast<int>(bytes_per_line);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t line_bytes = (pixel_size.width < width ? pixel_size.width : width) * sizeof(pixel_color_t);
|
||||
s = rawbits + bytes_per_line * (height - 1);
|
||||
src_line_bytes = static_cast<int>(bytes_per_line);
|
||||
}
|
||||
|
||||
if(pixel_size.height < height)
|
||||
height = pixel_size.height;
|
||||
|
||||
auto d = rawptr;
|
||||
const unsigned char* s;
|
||||
int src_line_bytes;
|
||||
|
||||
if (is_negative)
|
||||
{
|
||||
s = rawbits;
|
||||
src_line_bytes = -static_cast<int>(bytes_per_line);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = rawbits + bytes_per_line * (height - 1);
|
||||
src_line_bytes = static_cast<int>(bytes_per_line);
|
||||
}
|
||||
|
||||
for(std::size_t i = 0; i < height; ++i)
|
||||
{
|
||||
memcpy(d, s, line_bytes);
|
||||
d += pixel_size.width;
|
||||
s -= src_line_bytes;
|
||||
}
|
||||
for(std::size_t i = 0; i < height; ++i)
|
||||
{
|
||||
memcpy(d, s, this->bytes_per_line);
|
||||
d += pixel_size.width;
|
||||
s -= src_line_bytes;
|
||||
}
|
||||
}
|
||||
else if(24 == bits_per_pixel)
|
||||
@ -269,12 +270,6 @@ namespace nana{ namespace paint
|
||||
}
|
||||
else if(16 == bits_per_pixel)
|
||||
{
|
||||
if(pixel_size.width < width)
|
||||
width = pixel_size.width;
|
||||
|
||||
if(pixel_size.height < height)
|
||||
height = pixel_size.height;
|
||||
|
||||
unsigned char rgb_table[32];
|
||||
for(std::size_t i =0; i < 32; ++i)
|
||||
rgb_table[i] = static_cast<unsigned char>(i * 255 / 31);
|
||||
@ -310,6 +305,32 @@ namespace nana{ namespace paint
|
||||
rawbits -= src_bytes_per_line;
|
||||
}
|
||||
}
|
||||
else if(8 == bits_per_pixel)
|
||||
{
|
||||
int src_bytes_per_line;
|
||||
if(!is_negative)
|
||||
{
|
||||
rawbits += bytes_per_line * (height - 1);
|
||||
src_bytes_per_line = -static_cast<int>(bytes_per_line);
|
||||
}
|
||||
else
|
||||
src_bytes_per_line = static_cast<int>(bytes_per_line);
|
||||
|
||||
for(std::size_t top = 0; top < height; ++top)
|
||||
{
|
||||
auto dst = rawptr;
|
||||
for(auto p = rawbits, end = rawbits + width; p < end; ++p)
|
||||
{
|
||||
dst->element.red = *p;
|
||||
dst->element.green = *p;
|
||||
dst->element.blue = *p;
|
||||
++dst;
|
||||
}
|
||||
|
||||
rawbits += src_bytes_per_line;
|
||||
rawptr += this->bytes_per_line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(NANA_X11)
|
||||
@ -691,6 +712,17 @@ namespace nana{ namespace paint
|
||||
++px;
|
||||
}
|
||||
}
|
||||
else if(8 == bits_per_pixel)
|
||||
{
|
||||
//Grayscale
|
||||
for (auto p = row_ptr, end = row_ptr + px_count; p != end; ++p)
|
||||
{
|
||||
p->element.red = *buffer;
|
||||
p->element.green = *buffer;
|
||||
p->element.blue = *buffer;
|
||||
++buffer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,46 +18,53 @@
|
||||
#include <windows.h>
|
||||
#include "../detail/mswin/platform_spec.hpp"
|
||||
#elif defined(NANA_POSIX)
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "split_string.hpp"
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <spawn.h>
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
static void posix_open_url(const char *url_utf8)
|
||||
{
|
||||
using nana::system::split_string_type;
|
||||
using nana::system::split_string;
|
||||
|
||||
extern char **environ;
|
||||
const char *home = getenv("HOME");
|
||||
std::string cheat(home);
|
||||
cheat += "/.mozilla";
|
||||
struct stat exists;
|
||||
const split_string_type path = getenv("PATH");
|
||||
|
||||
// TODO: generalize this for chromium, opera, waterfox, etc.
|
||||
// Most desktop environments (KDE, Gnome, Lumina etc.) provide a way to set
|
||||
// your preferred browser - but there are more desktops than browsers.
|
||||
//see https://stackoverflow.com/questions/5116473/linux-command-to-open-url-in-default-browser
|
||||
|
||||
std::string full_path;
|
||||
for (const auto& cur_path : split_string(path, ':')) {
|
||||
full_path = cur_path;
|
||||
full_path += "/xdg-open";
|
||||
if ( stat(full_path.c_str(), &exists) == 0 && S_ISREG(exists.st_mode))
|
||||
break;
|
||||
else
|
||||
full_path.clear();
|
||||
}
|
||||
if (full_path.empty()) {
|
||||
//xdg-open not found sorry :( maybe print a message so users know?
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for $HOME/.mozilla directory as strong evidence they use firefox.
|
||||
if ( stat(cheat.c_str(), &exists) == 0 && S_ISDIR(exists.st_mode))
|
||||
{
|
||||
const char *path = "";
|
||||
static const char *likely[2] = { "/usr/local/bin/firefox", "/usr/bin/firefox"};
|
||||
if ( stat(likely[0], &exists) == 0 && S_ISREG(exists.st_mode))
|
||||
path = likely[0];
|
||||
else if ( stat(likely[1], &exists) == 0 && S_ISREG(exists.st_mode) )
|
||||
path = likely[1];
|
||||
else return;
|
||||
|
||||
pid_t pid = 0;
|
||||
static const char firefox[] = "firefox";
|
||||
char name[sizeof firefox]{};
|
||||
// argv does not like const-literals so make a copy.
|
||||
strcpy(name, firefox);
|
||||
char *argv[3] = {name, const_cast<char *>(url_utf8), nullptr};
|
||||
posix_spawn(&pid, path, NULL, NULL, argv, environ);
|
||||
const auto url_utf8_len = std::strlen(url_utf8);
|
||||
auto string_cpy_buff = std::make_unique<char[]>(full_path.size() + 1 + url_utf8_len + 1);
|
||||
char* const url_utf8_cpy = string_cpy_buff.get();
|
||||
char* const full_path_cpy = string_cpy_buff.get() + url_utf8_len + 1;
|
||||
std::strncpy(url_utf8_cpy, url_utf8, url_utf8_len + 1);
|
||||
std::strncpy(full_path_cpy, full_path.c_str(), full_path.size() + 1);
|
||||
char *argv[3] = {full_path_cpy, url_utf8_cpy, nullptr};
|
||||
//system((full_path + " " + url_utf8).c_str());
|
||||
posix_spawn(&pid, full_path_cpy, nullptr, nullptr, argv, environ);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
32
source/system/split_string.cpp
Normal file
32
source/system/split_string.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "split_string.hpp"
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace system {
|
||||
std::vector<split_string_type> split_string (const split_string_type& text, char sep)
|
||||
{
|
||||
std::vector<split_string_type> retval;
|
||||
const auto estimated_size = std::count(text.begin(), text.end(), sep) + 1;
|
||||
retval.reserve(estimated_size);
|
||||
|
||||
std::size_t sep_pos = 0;
|
||||
while (sep_pos != text.size()) {
|
||||
const std::size_t start = sep_pos;
|
||||
sep_pos = text.find(sep, sep_pos);
|
||||
sep_pos = (text.npos == sep_pos ? text.size() : sep_pos);
|
||||
const std::size_t end = sep_pos;
|
||||
while (sep_pos < text.size() and sep == text[sep_pos]) {
|
||||
++sep_pos;
|
||||
}
|
||||
|
||||
retval.push_back(text.substr(start, end - start));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
41
source/system/split_string.hpp
Normal file
41
source/system/split_string.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* The Deploy Implementation
|
||||
* 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/system/split_string.hpp
|
||||
*
|
||||
* What follows is dependent on what defined in nana/config.hpp
|
||||
*/
|
||||
|
||||
#ifndef NANA_SYSTEM_SPLITSTRING_HPP
|
||||
#define NANA_SYSTEM_SPLITSTRING_HPP
|
||||
|
||||
#include <nana/config.hpp>
|
||||
#include <vector>
|
||||
#ifdef _nana_std_has_string_view
|
||||
# include <string_view>
|
||||
#else
|
||||
# include <string>
|
||||
#endif
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace system
|
||||
{
|
||||
#ifdef _nana_std_has_string_view
|
||||
typedef std::string_view split_string_type;
|
||||
#else
|
||||
typedef std::string split_string_type;
|
||||
#endif
|
||||
|
||||
std::vector<split_string_type> split_string (const split_string_type& text, char sep);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Unicode Bidi-Language Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -606,6 +606,11 @@ namespace nana
|
||||
return reordered;
|
||||
}
|
||||
|
||||
bool unicode_bidi::is_text_right(const entity& e)
|
||||
{
|
||||
return ((e.bidi_char_type != unicode_bidi::bidi_char::L) && (e.level & 1));
|
||||
}
|
||||
|
||||
unsigned unicode_bidi::_m_paragraph_level(const char_type * begin, const char_type * end)
|
||||
{
|
||||
for(const char_type* i = begin; i != end; ++i)
|
||||
@ -990,7 +995,13 @@ namespace nana
|
||||
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))
|
||||
(0x00D8 <= ch && ch <= 0x00F6) || (0x00F8 <= ch && ch <= 0x0236) || (0x0250 <= ch && ch <= 0x02C1) ||
|
||||
//Hebrew
|
||||
(0x05BB <= ch && ch <= 0x05BD) || (0x05BF == ch) || ((0x05C1 <= ch && ch <= 0x05C4) && (0x05C3 != ch)) || (0x05D0 <= ch && ch <= 0x05EA) || (0x05F0 <= ch && ch <= 0x05F3) ||
|
||||
//Arabic
|
||||
(0x0610 <= ch && ch <= 0x0615) || (0x0621 <= ch && ch <= 0x063A) || (0x0640 <= ch && ch <= 0x0657) || (0x066E <= ch && ch <= 0x06D3) || (0x06D5 <= ch && ch <= 0x06DC) || (0x06E1 <= ch && ch <= 0x06E8) ||
|
||||
(0x06ED == ch || 0x06EF == ch) || (0x06FA <= ch && ch <= 0x06FC) || (0x06FF == ch)
|
||||
)
|
||||
return unicode_character_type::aletter;
|
||||
|
||||
if ('\'' == ch || 0x00AD == ch || 0x00B7 == ch || 0x05F4 == ch || 0x2019 == ch || 0x2027 == ch)
|
||||
@ -1025,7 +1036,7 @@ namespace nana
|
||||
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 !((unicode_character_type::format == r_type) || (unicode_character_type::aletter == r_type) || (unicode_character_type::numeric == r_type));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user