Merge remote-tracking branch 'cnjinhao/develop' into CMake

This commit is contained in:
qPCR4vir 2018-08-19 20:47:49 +02:00
commit 49d6faf7cf
14 changed files with 571 additions and 37 deletions

View File

@ -220,12 +220,14 @@
#endif #endif
#undef _nana_std_has_string_view #undef _nana_std_has_string_view
#undef _nana_std_has_returnable_emplace_back
#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_returnable_emplace_back
#endif #endif

View File

@ -65,11 +65,12 @@ namespace nana
bool review_utf8(std::string& text); bool review_utf8(std::string& text);
const std::string& to_utf8(const std::string&); const std::string& to_utf8(const std::string&);
std::string to_utf8(const std::wstring&);
#ifdef _nana_std_has_string_view #ifdef _nana_std_has_string_view
std::string to_utf8(std::wstring_view sv);
std::wstring to_wstring(std::string_view utf8_str); std::wstring to_wstring(std::string_view utf8_str);
#else #else
std::string to_utf8(const std::wstring&);
std::wstring to_wstring(const std::string& utf8_str); std::wstring to_wstring(const std::string& utf8_str);
#endif #endif

View File

@ -1,7 +1,7 @@
/** /**
* A Combox Implementation * A Combox 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
@ -77,6 +77,7 @@ namespace nana
public: public:
item_proxy(drawer_impl*, std::size_t pos); item_proxy(drawer_impl*, std::size_t pos);
item_proxy& text(const ::std::string&); item_proxy& text(const ::std::string&);
::std::string text() const; ::std::string text() const;
item_proxy& select(); item_proxy& select();
bool selected() const; bool selected() const;
@ -103,22 +104,19 @@ namespace nana
} }
template<typename T> template<typename T>
item_proxy& value(const T& t) item_proxy& value(T&& val)
{ {
*_m_anyobj(true) = t; *_m_anyobj(true) = ::std::forward<T>(val);
return *this;
}
template<typename T>
item_proxy& value(T&& t)
{
*_m_anyobj(true) = ::std::move(t);
return *this; return *this;
} }
public: public:
/// Behavior of Iterator's value_type /// Behavior of Iterator's value_type
#ifdef _nana_std_has_string_view
bool operator==(::std::string_view) const;
#else
bool operator==(const ::std::string&) const; bool operator==(const ::std::string&) const;
bool operator==(const char*) const; bool operator==(const char*) const;
#endif
/// Behavior of Iterator /// Behavior of Iterator
item_proxy & operator=(const item_proxy&); item_proxy & operator=(const item_proxy&);
@ -192,19 +190,11 @@ namespace nana
return _m_at_key(std::move(p)); return _m_at_key(std::move(p));
} }
template<typename Key>
void erase_key(const Key& kv)
{
typedef typename nana::detail::type_escape<Key>::type key_t;
std::unique_ptr<nana::detail::key_interface> p(new nana::key<key_t, std::less<key_t> >(kv));
_m_erase(p.get());
}
template<typename Key> template<typename Key>
void erase_key(Key&& kv) void erase_key(Key&& kv)
{ {
typedef typename nana::detail::type_escape<Key>::type key_t; typedef typename nana::detail::type_escape<Key>::type key_t;
std::unique_ptr<nana::detail::key_interface> p(new nana::key<key_t, std::less<key_t> >(std::move(kv))); std::unique_ptr<nana::detail::key_interface> p(new nana::key<key_t, std::less<key_t> >(std::forward<Key>(kv)));
_m_erase(p.get()); _m_erase(p.get());
} }

View File

@ -933,15 +933,20 @@ namespace nana
template<typename T> template<typename T>
item_proxy & value(T&& t) item_proxy & value(T&& t)
{ {
*_m_value(true) = std::forward<T>(t); *_m_value(true) = ::std::forward<T>(t);
return *this; return *this;
} }
/// Behavior of Iterator's value_type /// Behavior of Iterator's value_type
#ifdef _nana_std_has_string_view
bool operator==(::std::string_view sv) const;
bool operator==(::std::wstring_view sv) const;
#else
bool operator==(const char * s) const; bool operator==(const char * s) const;
bool operator==(const wchar_t * s) const; bool operator==(const wchar_t * s) const;
bool operator==(const ::std::string& s) const; bool operator==(const ::std::string& s) const;
bool operator==(const ::std::wstring& s) const; bool operator==(const ::std::wstring& s) const;
#endif
/// Behavior of Iterator /// Behavior of Iterator
item_proxy & operator=(const item_proxy&); item_proxy & operator=(const item_proxy&);

View File

@ -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,10 +96,19 @@ 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(wchar_t ch) //deprecated
{ {
return ((0x4E00 <= ch) && (ch <= 0x9FFF)); return ((0x4E00 <= ch) && (ch <= 0x9FFF));
} }
*/
static bool _m_unicode_word_breakable(const wchar_t* ch) noexcept
{
if (*ch)
return unicode_wordbreak(*ch, ch[1]);
return true;
}
//Read the data token //Read the data token
token _m_token() token _m_token()
@ -112,14 +122,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);

View File

@ -17,6 +17,8 @@
#include "skeletons/textbase_export_interface.hpp" #include "skeletons/textbase_export_interface.hpp"
#include "skeletons/text_editor_part.hpp" #include "skeletons/text_editor_part.hpp"
#include <nana/optional.hpp>
namespace nana namespace nana
{ {
class textbox; class textbox;
@ -173,6 +175,13 @@ namespace nana
/// Read the text from a specified line with a set offset. It returns true for success. /// Read the text from a specified line with a set offset. It returns true for success.
bool getline(std::size_t line_index,std::size_t offset,std::string& text) const; bool getline(std::size_t line_index,std::size_t offset,std::string& text) const;
/// Read the text from a specified line; returns an empty optional on failure
std::optional<std::string> getline(std::size_t pos) const;
///Read the text from a specified line with a set offset. Returns an empty optional for
/// failure.
std::optional<std::string> getline(std::size_t line_index, std::size_t offset) const;
/// Gets the caret position /// Gets the caret position
/// Returns true if the caret is in the area of display, false otherwise. /// Returns true if the caret is in the area of display, false otherwise.
bool caret_pos(point& pos, bool text_coordinate) const; bool caret_pos(point& pos, bool text_coordinate) const;

View File

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

View File

@ -175,12 +175,12 @@ namespace nana
return str; return str;
} }
std::string to_utf8(const std::wstring& text) #ifdef _nana_std_has_string_view
std::string to_utf8(std::wstring_view text)
{ {
return ::nana::charset(text).to_bytes(::nana::unicode::utf8); return ::nana::charset(std::wstring{text}).to_bytes(::nana::unicode::utf8);
} }
#ifdef _nana_std_has_string_view
std::wstring to_wstring(std::string_view utf8_str) std::wstring to_wstring(std::string_view utf8_str)
{ {
if (utf8_str.empty()) if (utf8_str.empty())
@ -189,6 +189,11 @@ namespace nana
return ::nana::charset(std::string{ utf8_str.data(), utf8_str.size() }, unicode::utf8); return ::nana::charset(std::string{ utf8_str.data(), utf8_str.size() }, unicode::utf8);
} }
#else #else
std::string to_utf8(const std::wstring& text)
{
return ::nana::charset(text).to_bytes(::nana::unicode::utf8);
}
std::wstring to_wstring(const std::string& utf8_str) std::wstring to_wstring(const std::string& utf8_str)
{ {
return ::nana::charset(utf8_str, ::nana::unicode::utf8); return ::nana::charset(utf8_str, ::nana::unicode::utf8);

View File

@ -984,6 +984,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)

View File

@ -821,6 +821,14 @@ namespace nana
} }
/// Behavior of Iterator's value_type /// Behavior of Iterator's value_type
#ifdef _nana_std_has_string_view
bool item_proxy::operator == (::std::string_view s) const
{
if (pos_ == nana::npos)
return false;
return (impl_->at(pos_).item_text == s);
}
#else
bool item_proxy::operator == (const ::std::string& s) const bool item_proxy::operator == (const ::std::string& s) const
{ {
if (pos_ == nana::npos) if (pos_ == nana::npos)
@ -834,6 +842,7 @@ namespace nana
return false; return false;
return (impl_->at(pos_).item_text == s); return (impl_->at(pos_).item_text == s);
} }
#endif
/// Behavior of Iterator /// Behavior of Iterator

View File

@ -20,6 +20,8 @@
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
#define VISUAL_LINES
namespace nana namespace nana
{ {
namespace drawerbase namespace drawerbase
@ -28,6 +30,7 @@ namespace nana
{ {
class renderer class renderer
{ {
#ifndef VISUAL_LINES
typedef widgets::skeletons::dstream::linecontainer::iterator iterator; typedef widgets::skeletons::dstream::linecontainer::iterator iterator;
struct pixel_tag struct pixel_tag
@ -37,6 +40,32 @@ namespace nana
std::size_t baseline; //The baseline for drawing text. std::size_t baseline; //The baseline for drawing text.
std::vector<iterator> values; //line values std::vector<iterator> values; //line values
}; };
#else
//Iterator of content element in a line.
using content_element_iterator = widgets::skeletons::dstream::linecontainer::const_iterator; //subsitute for member type iterator
struct visual_line //subsitute of pixel_tag
{
struct element
{
content_element_iterator content_element;
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.
};
#endif
//this is a helper variable, it just keeps the status while drawing. //this is a helper variable, it just keeps the status while drawing.
struct render_status struct render_status
@ -46,8 +75,12 @@ namespace nana
align_v text_align_v; align_v text_align_v;
nana::point pos; nana::point pos;
#ifndef VISUAL_LINES
std::vector<pixel_tag> pixels; std::vector<pixel_tag> pixels;
std::size_t index; #else
std::vector<visual_line> vslines; //The lines description of a line of text. substitute of member pixels.
#endif
std::size_t index; //indicates the current rendering visual line.
}; };
struct traceable struct traceable
@ -102,18 +135,32 @@ namespace nana
rs.text_align = th; rs.text_align = th;
rs.text_align_v = tv; rs.text_align_v = tv;
#ifndef VISUAL_LINES
std::deque<std::vector<pixel_tag> > pixel_lines; std::deque<std::vector<pixel_tag> > pixel_lines;
#else
//All visual lines data of whole text.
std::deque<std::vector<visual_line>> content_lines;
#endif
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_)
{ {
#ifndef VISUAL_LINES
_m_line_pixels(line, def_line_pixels, rs); _m_line_pixels(line, def_line_pixels, rs);
for (auto & m : rs.pixels) for (auto & m : rs.pixels)
extent_v_pixels += m.pixels; extent_v_pixels += m.pixels;
pixel_lines.emplace_back(std::move(rs.pixels)); pixel_lines.emplace_back(std::move(rs.pixels));
#else
_m_prepare_visual_lines(graph, line, def_line_pixels, rs);
for (auto & vsline : rs.vslines)
extent_v_pixels += vsline.extent_height_px;
content_lines.emplace_back(std::move(rs.vslines));
#endif
if(extent_v_pixels >= graph.height()) if(extent_v_pixels >= graph.height())
break; break;
@ -129,13 +176,17 @@ namespace nana
else else
rs.pos.y = 0; rs.pos.y = 0;
#ifndef VISUAL_LINES
auto pixels_iterator = pixel_lines.begin(); auto pixels_iterator = pixel_lines.begin();
#else
auto vsline_iterator = content_lines.begin();
#endif
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;
#ifndef VISUAL_LINES
rs.index = 0; rs.index = 0;
rs.pixels.clear(); rs.pixels.clear();
@ -148,6 +199,17 @@ namespace nana
break; break;
rs.pos.y += static_cast<int>(rs.pixels.back().pixels); rs.pos.y += static_cast<int>(rs.pixels.back().pixels);
#else
rs.index = 0;
rs.vslines.clear();
rs.vslines.swap(*vsline_iterator++);
rs.pos.x = rs.vslines.front().x_base;
if (!_m_foreach_visual_line(graph, rs))
break;
rs.pos.y += static_cast<int>(rs.vslines.back().extent_height_px);
#endif
} }
graph.typeface(pre_font); graph.typeface(pre_font);
@ -194,8 +256,13 @@ namespace nana
for(auto & line: dstream_) for(auto & line: dstream_)
{ {
#ifndef VISUAL_LINES
rs.pixels.clear(); rs.pixels.clear();
unsigned w = _m_line_pixels(line, def_line_pixels, rs); unsigned w = _m_line_pixels(line, def_line_pixels, rs);
#else
rs.vslines.clear();
auto w = _m_prepare_visual_lines(graph, line, def_line_pixels, rs);
#endif
if(limited && (w > limited)) if(limited && (w > limited))
w = limited; w = limited;
@ -203,8 +270,13 @@ namespace nana
if(retsize.width < w) if(retsize.width < w)
retsize.width = w; retsize.width = w;
#ifndef VISUAL_LINES
for (auto & px : rs.pixels) for (auto & px : rs.pixels)
retsize.height += static_cast<unsigned>(px.pixels); retsize.height += static_cast<unsigned>(px.pixels);
#else
for (auto& vsline : rs.vslines)
retsize.height += static_cast<unsigned>(vsline.extent_height_px);
#endif
} }
return retsize; return retsize;
@ -315,6 +387,7 @@ namespace nana
} }
} }
#ifndef VISUAL_LINES
void _m_align_x_base(const render_status& rs, pixel_tag & px, unsigned w) noexcept void _m_align_x_base(const render_status& rs, pixel_tag & px, unsigned w) noexcept
{ {
switch(rs.text_align) switch(rs.text_align)
@ -330,7 +403,209 @@ namespace nana
break; break;
} }
} }
#else
void _m_prepare_x(const render_status& rs, visual_line & vsline, unsigned w) noexcept
{
switch (rs.text_align)
{
case align::left:
vsline.x_base = 0;
break;
case align::center:
vsline.x_base = (static_cast<int>(rs.allowed_width - w) >> 1);
break;
case align::right:
vsline.x_base = static_cast<int>(rs.allowed_width - w);
break;
}
}
#endif
#ifdef VISUAL_LINES
/**
* 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)
{
unsigned abs_text_px = 0;
unsigned max_ascent = 0;
unsigned max_descent = 0;
unsigned max_content_height = 0;
int text_pos = 0;
std::vector<visual_line::element> vsline_elements;
for (auto i = line.cbegin(); i != line.cend(); ++i)
{
auto const data = i->data_ptr;
auto fblock = i->fblock_ptr;
abs_text_px += data->size().width;
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))
{
text_pos += static_cast<int>(extent_size.width);
//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;
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_returnable_emplace_back
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
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())
{
unsigned sub_text_px = 0;
auto sub_text_len = _m_fit_text(graph, data->text().substr(text_begin), rs.allowed_width, sub_text_px);
if (text_begin + sub_text_len < data->text().size())
{
//make a new visual line
#ifdef _nana_std_has_returnable_emplace_back
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);
vsline.extent_height_px = max_content_height;
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);
text_pos = static_cast<int>(i->data_ptr->size().width);
}
}
if (!vsline_elements.empty())
{
#ifdef _nana_std_has_returnable_emplace_back
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
max_ascent = max_content_height - max_descent;
vsline.extent_height_px = max_content_height;
vsline.baseline = max_ascent;
vsline.elements.swap(vsline_elements);
}
return abs_text_px;
}
//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 (std::size_t i = 0; i < text.size(); ++i)
{
if (text_px + pxbuf[i] > limited_width_px)
return i;
text_px += pxbuf[i];
}
return text.size();
}
#else
unsigned _m_line_pixels(dstream::linecontainer& line, unsigned def_line_pixels, render_status & rs) unsigned _m_line_pixels(dstream::linecontainer& line, unsigned def_line_pixels, render_status & rs)
{ {
if (line.empty()) if (line.empty())
@ -441,7 +716,9 @@ namespace nana
} }
return total_w; return total_w;
} }
#endif
#ifndef VISUAL_LINES
bool _m_each_line(graph_reference graph, dstream::linecontainer&, render_status& rs) bool _m_each_line(graph_reference graph, dstream::linecontainer&, render_status& rs)
{ {
std::wstring text; std::wstring text;
@ -501,7 +778,36 @@ namespace nana
} }
return (rs.pos.y <= lastpos); return (rs.pos.y <= lastpos);
} }
#else
bool _m_foreach_visual_line(graph_reference graph, render_status& rs)
{
std::wstring text;
content_element_iterator block_start;
auto const bottom = static_cast<int>(graph.height()) - 1;
for (auto & vsline : rs.vslines)
{
rs.pos.x = vsline.x_base;
for (auto& content_elm : vsline.elements)
{
_m_draw_vsline_element(graph, content_elm, rs);
}
++rs.index; //next line index
rs.pos.y += vsline.extent_height_px;
if (rs.pos.y > bottom)
return false;
}
return (rs.pos.y <= bottom);
}
#endif
#if 0 //deprecated
static bool _m_overline(const render_status& rs, int right, bool equal_required) noexcept static bool _m_overline(const render_status& rs, int right, bool equal_required) noexcept
{ {
if(align::left == rs.text_align) if(align::left == rs.text_align)
@ -509,7 +815,24 @@ namespace nana
return (equal_required ? rs.pixels[rs.index].x_base <= 0 : rs.pixels[rs.index].x_base < 0); return (equal_required ? rs.pixels[rs.index].x_base <= 0 : rs.pixels[rs.index].x_base < 0);
} }
#endif
#ifdef VISUAL_LINES
static int _m_vsline_element_top(const visual_line& vsline, fblock* fblock_ptr, const data* data_ptr) noexcept
{
switch (fblock_ptr->text_align)
{
case fblock::aligns::center:
return static_cast<int>(vsline.extent_height_px - data_ptr->size().height) / 2;
case fblock::aligns::bottom:
return static_cast<int>(vsline.extent_height_px - data_ptr->size().height);
case fblock::aligns::baseline:
return static_cast<int>(vsline.baseline - (data_ptr->is_text() ? data_ptr->ascent() : data_ptr->size().height));
default: break;
}
return 0;
}
#else
static int _m_text_top(const pixel_tag& px, fblock* fblock_ptr, const data* data_ptr) static int _m_text_top(const pixel_tag& px, fblock* fblock_ptr, const data* data_ptr)
{ {
switch(fblock_ptr->text_align) switch(fblock_ptr->text_align)
@ -524,7 +847,52 @@ namespace nana
} }
return 0; return 0;
} }
#endif
#ifdef VISUAL_LINES
void _m_draw_vsline_element(graph_reference graph, const visual_line::element& vsline_elm, render_status& rs)
{
auto data = vsline_elm.content_element->data_ptr;
auto fblock = vsline_elm.content_element->fblock_ptr;
if (data->is_text())
{
auto const text = data->text().c_str() + vsline_elm.range.first;
auto const reordered = unicode_reorder(text, vsline_elm.range.second);
_m_change_font(graph, fblock);
for (auto & bidi : reordered)
{
auto extent_size = data->size();
#ifdef _nana_std_has_string_view
std::wstring_view text_sv{ bidi.begin, static_cast<std::size_t>(bidi.end - bidi.begin) };
if (data->text().size() != text_sv.size())
extent_size = graph.text_extent_size(text_sv);
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
std::wstring text{ bidi.begin, static_cast<std::size_t>(bidi.end - bidi.begin) };
if (data->text().size() != text.size())
extent_size = graph.text_extent_size(text);
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
_m_insert_if_traceable(rs.pos.x, y, extent_size, fblock);
rs.pos.x += static_cast<int>(extent_size.width);
}
}
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);
}
}
#else
void _m_draw_block(graph_reference graph, const std::wstring& s, dstream::linecontainer::iterator block_start, render_status& rs) void _m_draw_block(graph_reference graph, const std::wstring& s, dstream::linecontainer::iterator block_start, render_status& rs)
{ {
auto const reordered = unicode_reorder(s.data(), s.length()); auto const reordered = unicode_reorder(s.data(), s.length());
@ -550,9 +918,35 @@ namespace nana
fblock * fblock_ptr = i->fblock_ptr; fblock * fblock_ptr = i->fblock_ptr;
data * data_ptr = i->data_ptr; data * data_ptr = i->data_ptr;
#if 1
const int range_text_area = static_cast<int>(rs.allowed_width) - rs.pos.x;
_m_change_font(graph, fblock_ptr);
auto text_extent_size = data_ptr->size();
#ifndef _nana_std_has_string_view
std::wstring_view text_sv{ data_ptr->text().c_str() + text_range.first, text_range.second };
if (data_ptr->text().size() != text_sv.size())
text_extent_size = graph.text_extent_size(text_sv);
#else
auto text_sv = data_ptr->text().substr(text_range.first, text_range.second);
if (data_ptr->text().size() != text_sv.size())
text_extent_size = graph.text_extent_size(text_sv);
#endif
if ((static_cast<int>(text_extent_size.width) > range_text_area) && (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);
graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock_ptr));
#else
const int w = static_cast<int>(rs.allowed_width) - rs.pos.x; const int w = static_cast<int>(rs.allowed_width) - rs.pos.x;
nana::size sz = data_ptr->size(); nana::size text_extent_size = data_ptr->size();
if ((static_cast<int>(sz.width) > w) && (rs.pos.x != px.x_base)) if ((static_cast<int>(text_extent_size.width) > w) && (rs.pos.x != px.x_base))
{ {
//Change a new line //Change a new line
rs.pos.y += static_cast<int>(px.pixels); rs.pos.y += static_cast<int>(px.pixels);
@ -569,7 +963,7 @@ namespace nana
if (text_range.second != text_sv.size()) if (text_range.second != text_sv.size())
{ {
text_sv = text_sv.substr(text_range.first, text_range.second); text_sv = text_sv.substr(text_range.first, text_range.second);
sz = graph.text_extent_size(text_sv); text_extent_size = graph.text_extent_size(text_sv);
} }
graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock_ptr)); graph.string({ rs.pos.x, y }, text_sv, _m_fgcolor(fblock_ptr));
@ -581,15 +975,15 @@ namespace nana
else else
{ {
auto str = data_ptr->text().substr(text_range.first, text_range.second); auto str = data_ptr->text().substr(text_range.first, text_range.second);
sz = graph.text_extent_size(str); text_extent_size = graph.text_extent_size(str);
graph.string({ rs.pos.x, y }, str, _m_fgcolor(fblock_ptr)); graph.string({ rs.pos.x, y }, str, _m_fgcolor(fblock_ptr));
} }
#endif #endif
#endif //#if 0
_m_insert_if_traceable(rs.pos.x, y, text_extent_size, fblock_ptr);
_m_insert_if_traceable(rs.pos.x, y, sz, fblock_ptr); rs.pos.x += static_cast<int>(text_extent_size.width);
rs.pos.x += static_cast<int>(sz.width);
if(text_range.second < len) if(text_range.second < len)
{ {
@ -601,6 +995,7 @@ namespace nana
} }
} }
} }
#endif //VISUAL_LINES
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)
{ {

View File

@ -4824,6 +4824,17 @@ namespace nana
} }
//Behavior of Iterator's value_type //Behavior of Iterator's value_type
#ifdef _nana_std_has_string_view
bool item_proxy::operator==(std::string_view sv) const
{
return (text(0) == sv);
}
bool item_proxy::operator==(std::wstring_view sv) const
{
return (text(0) == to_utf8(sv));
}
#else
bool item_proxy::operator==(const char * s) const bool item_proxy::operator==(const char * s) const
{ {
return this->operator==(std::string(s)); return this->operator==(std::string(s));
@ -4843,6 +4854,7 @@ namespace nana
{ {
return (text(0) == to_utf8(s)); return (text(0) == to_utf8(s));
} }
#endif
item_proxy & item_proxy::operator=(const item_proxy& rhs) item_proxy & item_proxy::operator=(const item_proxy& rhs)
{ {

View File

@ -377,6 +377,27 @@ namespace drawerbase {
return false; return false;
} }
std::optional<std::string> textbox::getline(std::size_t pos) const
{
auto result = std::string{};
if ( getline(pos, result) )
{
return { std::move(result) };
}
return {};
}
std::optional<std::string> textbox::getline(std::size_t line_index, std::size_t offset) const
{
auto result = std::string{};
if ( getline(line_index, offset, result) )
{
return { std::move(result) };
}
return {};
}
/// Gets the caret position /// Gets the caret position
bool textbox::caret_pos(point& pos, bool text_coordinate) const bool textbox::caret_pos(point& pos, bool text_coordinate) const
{ {

View File

@ -946,4 +946,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