Merge remote-tracking branch 'cnjinhao/develop' into CMake
This commit is contained in:
commit
49d6faf7cf
@ -220,12 +220,14 @@
|
||||
#endif
|
||||
|
||||
#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)) || \
|
||||
((__cplusplus >= 201703L) && \
|
||||
(defined(__clang__) && (__clang_major__ * 100 + __clang_minor__ >= 400) || \
|
||||
(!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 701))) \
|
||||
)
|
||||
# define _nana_std_has_string_view
|
||||
# define _nana_std_has_returnable_emplace_back
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -65,11 +65,12 @@ namespace nana
|
||||
bool review_utf8(std::string& text);
|
||||
|
||||
const std::string& to_utf8(const std::string&);
|
||||
std::string to_utf8(const std::wstring&);
|
||||
|
||||
#ifdef _nana_std_has_string_view
|
||||
std::string to_utf8(std::wstring_view sv);
|
||||
std::wstring to_wstring(std::string_view utf8_str);
|
||||
#else
|
||||
std::string to_utf8(const std::wstring&);
|
||||
std::wstring to_wstring(const std::string& utf8_str);
|
||||
#endif
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* A Combox Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -77,6 +77,7 @@ namespace nana
|
||||
public:
|
||||
item_proxy(drawer_impl*, std::size_t pos);
|
||||
item_proxy& text(const ::std::string&);
|
||||
|
||||
::std::string text() const;
|
||||
item_proxy& select();
|
||||
bool selected() const;
|
||||
@ -103,22 +104,19 @@ namespace nana
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
item_proxy& value(const T& t)
|
||||
item_proxy& value(T&& val)
|
||||
{
|
||||
*_m_anyobj(true) = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
item_proxy& value(T&& t)
|
||||
{
|
||||
*_m_anyobj(true) = ::std::move(t);
|
||||
*_m_anyobj(true) = ::std::forward<T>(val);
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
/// 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 char*) const;
|
||||
#endif
|
||||
|
||||
/// Behavior of Iterator
|
||||
item_proxy & operator=(const item_proxy&);
|
||||
@ -192,19 +190,11 @@ namespace nana
|
||||
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>
|
||||
void erase_key(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> >(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());
|
||||
}
|
||||
|
||||
|
@ -933,15 +933,20 @@ namespace nana
|
||||
template<typename T>
|
||||
item_proxy & value(T&& t)
|
||||
{
|
||||
*_m_value(true) = std::forward<T>(t);
|
||||
*_m_value(true) = ::std::forward<T>(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// 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 wchar_t * s) const;
|
||||
bool operator==(const ::std::string& s) const;
|
||||
bool operator==(const ::std::wstring& s) const;
|
||||
#endif
|
||||
|
||||
/// Behavior of Iterator
|
||||
item_proxy & operator=(const item_proxy&);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Text Token Stream
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -22,6 +22,7 @@
|
||||
#include <stdexcept>
|
||||
|
||||
#include <nana/push_ignore_diagnostic>
|
||||
#include <nana/unicode_bidi.hpp>
|
||||
|
||||
namespace nana{ namespace widgets{ namespace skeletons
|
||||
{
|
||||
@ -95,10 +96,19 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
return std::stoi(idstr_, nullptr, 0);
|
||||
}
|
||||
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));
|
||||
}
|
||||
*/
|
||||
|
||||
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
|
||||
token _m_token()
|
||||
@ -112,14 +122,14 @@ namespace nana{ namespace widgets{ namespace skeletons
|
||||
idstr_.clear();
|
||||
idstr_.append(1, ch);
|
||||
|
||||
if(_m_unicode_word_breakable(ch))
|
||||
if (_m_unicode_word_breakable(iptr_))
|
||||
{
|
||||
++iptr_;
|
||||
return token::data;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "skeletons/textbase_export_interface.hpp"
|
||||
#include "skeletons/text_editor_part.hpp"
|
||||
|
||||
#include <nana/optional.hpp>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
class textbox;
|
||||
@ -173,6 +175,13 @@ namespace nana
|
||||
/// 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;
|
||||
|
||||
/// 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
|
||||
/// Returns true if the caret is in the area of display, false otherwise.
|
||||
bool caret_pos(point& pos, bool text_coordinate) const;
|
||||
|
@ -71,6 +71,8 @@ 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>
|
||||
|
||||
|
@ -175,12 +175,12 @@ namespace nana
|
||||
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)
|
||||
{
|
||||
if (utf8_str.empty())
|
||||
@ -189,6 +189,11 @@ namespace nana
|
||||
return ::nana::charset(std::string{ utf8_str.data(), utf8_str.size() }, unicode::utf8);
|
||||
}
|
||||
#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)
|
||||
{
|
||||
return ::nana::charset(utf8_str, ::nana::unicode::utf8);
|
||||
|
@ -984,6 +984,15 @@ namespace nana{
|
||||
|
||||
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;
|
||||
::XGetWindowAttributes(disp, reinterpret_cast<Window>(wd), &attr);
|
||||
if(attr.map_state == IsUnmapped)
|
||||
|
@ -821,6 +821,14 @@ namespace nana
|
||||
}
|
||||
|
||||
/// 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
|
||||
{
|
||||
if (pos_ == nana::npos)
|
||||
@ -834,6 +842,7 @@ namespace nana
|
||||
return false;
|
||||
return (impl_->at(pos_).item_text == s);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// Behavior of Iterator
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
#define VISUAL_LINES
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace drawerbase
|
||||
@ -28,6 +30,7 @@ namespace nana
|
||||
{
|
||||
class renderer
|
||||
{
|
||||
#ifndef VISUAL_LINES
|
||||
typedef widgets::skeletons::dstream::linecontainer::iterator iterator;
|
||||
|
||||
struct pixel_tag
|
||||
@ -37,6 +40,32 @@ namespace nana
|
||||
std::size_t baseline; //The baseline for drawing text.
|
||||
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.
|
||||
struct render_status
|
||||
@ -46,8 +75,12 @@ namespace nana
|
||||
align_v text_align_v;
|
||||
|
||||
nana::point pos;
|
||||
#ifndef VISUAL_LINES
|
||||
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
|
||||
@ -102,18 +135,32 @@ namespace nana
|
||||
rs.text_align = th;
|
||||
rs.text_align_v = tv;
|
||||
|
||||
#ifndef VISUAL_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.
|
||||
|
||||
for (auto & line : dstream_)
|
||||
{
|
||||
#ifndef VISUAL_LINES
|
||||
_m_line_pixels(line, def_line_pixels, rs);
|
||||
|
||||
for (auto & m : rs.pixels)
|
||||
extent_v_pixels += m.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())
|
||||
break;
|
||||
@ -129,13 +176,17 @@ namespace nana
|
||||
else
|
||||
rs.pos.y = 0;
|
||||
|
||||
#ifndef VISUAL_LINES
|
||||
auto pixels_iterator = pixel_lines.begin();
|
||||
|
||||
#else
|
||||
auto vsline_iterator = content_lines.begin();
|
||||
#endif
|
||||
for (auto & line : dstream_)
|
||||
{
|
||||
if (rs.pos.y >= static_cast<int>(graph.height()))
|
||||
break;
|
||||
|
||||
#ifndef VISUAL_LINES
|
||||
rs.index = 0;
|
||||
rs.pixels.clear();
|
||||
|
||||
@ -148,6 +199,17 @@ namespace nana
|
||||
break;
|
||||
|
||||
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);
|
||||
@ -194,8 +256,13 @@ namespace nana
|
||||
|
||||
for(auto & line: dstream_)
|
||||
{
|
||||
#ifndef VISUAL_LINES
|
||||
rs.pixels.clear();
|
||||
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))
|
||||
w = limited;
|
||||
@ -203,8 +270,13 @@ namespace nana
|
||||
if(retsize.width < w)
|
||||
retsize.width = w;
|
||||
|
||||
#ifndef VISUAL_LINES
|
||||
for (auto & px : rs.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;
|
||||
@ -315,6 +387,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef VISUAL_LINES
|
||||
void _m_align_x_base(const render_status& rs, pixel_tag & px, unsigned w) noexcept
|
||||
{
|
||||
switch(rs.text_align)
|
||||
@ -330,7 +403,209 @@ namespace nana
|
||||
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)
|
||||
{
|
||||
if (line.empty())
|
||||
@ -441,7 +716,9 @@ namespace nana
|
||||
}
|
||||
return total_w;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef VISUAL_LINES
|
||||
bool _m_each_line(graph_reference graph, dstream::linecontainer&, render_status& rs)
|
||||
{
|
||||
std::wstring text;
|
||||
@ -501,7 +778,36 @@ namespace nana
|
||||
}
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
#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)
|
||||
{
|
||||
switch(fblock_ptr->text_align)
|
||||
@ -524,7 +847,52 @@ namespace nana
|
||||
}
|
||||
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)
|
||||
{
|
||||
auto const reordered = unicode_reorder(s.data(), s.length());
|
||||
@ -550,9 +918,35 @@ namespace nana
|
||||
fblock * fblock_ptr = i->fblock_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;
|
||||
nana::size sz = data_ptr->size();
|
||||
if ((static_cast<int>(sz.width) > w) && (rs.pos.x != px.x_base))
|
||||
nana::size text_extent_size = data_ptr->size();
|
||||
if ((static_cast<int>(text_extent_size.width) > w) && (rs.pos.x != px.x_base))
|
||||
{
|
||||
//Change a new line
|
||||
rs.pos.y += static_cast<int>(px.pixels);
|
||||
@ -569,7 +963,7 @@ namespace nana
|
||||
if (text_range.second != text_sv.size())
|
||||
{
|
||||
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));
|
||||
@ -581,15 +975,15 @@ namespace nana
|
||||
else
|
||||
{
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
#endif //#if 0
|
||||
|
||||
|
||||
_m_insert_if_traceable(rs.pos.x, y, sz, fblock_ptr);
|
||||
rs.pos.x += static_cast<int>(sz.width);
|
||||
_m_insert_if_traceable(rs.pos.x, y, text_extent_size, fblock_ptr);
|
||||
rs.pos.x += static_cast<int>(text_extent_size.width);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -4824,6 +4824,17 @@ namespace nana
|
||||
}
|
||||
|
||||
//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
|
||||
{
|
||||
return this->operator==(std::string(s));
|
||||
@ -4843,6 +4854,7 @@ namespace nana
|
||||
{
|
||||
return (text(0) == to_utf8(s));
|
||||
}
|
||||
#endif
|
||||
|
||||
item_proxy & item_proxy::operator=(const item_proxy& rhs)
|
||||
{
|
||||
|
@ -377,6 +377,27 @@ namespace drawerbase {
|
||||
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
|
||||
bool textbox::caret_pos(point& pos, bool text_coordinate) const
|
||||
{
|
||||
|
@ -946,4 +946,68 @@ namespace nana
|
||||
{
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user