add fit-content and improve place
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* An Implementation of Place for Layout
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <limits> //numeric_limits
|
||||
#include <cstdlib> //std::abs
|
||||
#include <cstring> //std::memset
|
||||
#include <cctype> //std::isalpha/std::isalnum
|
||||
|
||||
#include "place_parts.hpp"
|
||||
|
||||
@@ -56,18 +57,18 @@ namespace nana
|
||||
enum class token
|
||||
{
|
||||
div_start, div_end, splitter,
|
||||
identifier, dock, vert, grid, number, array, reparray,
|
||||
identifier, dock, fit, vert, grid, number, array, reparray,
|
||||
weight, gap, margin, arrange, variable, repeated, min_px, max_px, left, right, top, bottom, undisplayed, invisible,
|
||||
collapse, parameters,
|
||||
equal,
|
||||
eof, error
|
||||
};
|
||||
|
||||
tokenizer(const char* p)
|
||||
tokenizer(const char* p) noexcept
|
||||
: divstr_(p), sp_(p)
|
||||
{}
|
||||
|
||||
const std::string& idstr() const
|
||||
const std::string& idstr() const noexcept
|
||||
{
|
||||
return idstr_;
|
||||
}
|
||||
@@ -77,22 +78,22 @@ namespace nana
|
||||
return number_;
|
||||
}
|
||||
|
||||
std::vector<number_t>& array()
|
||||
std::vector<number_t>& array() noexcept
|
||||
{
|
||||
return array_;
|
||||
}
|
||||
|
||||
repeated_array&& reparray()
|
||||
repeated_array&& reparray() noexcept
|
||||
{
|
||||
return std::move(reparray_);
|
||||
}
|
||||
|
||||
std::vector<number_t>& parameters()
|
||||
std::vector<number_t>& parameters() noexcept
|
||||
{
|
||||
return parameters_;
|
||||
}
|
||||
|
||||
std::size_t pos() const
|
||||
std::size_t pos() const noexcept
|
||||
{
|
||||
return (sp_ - divstr_);
|
||||
}
|
||||
@@ -230,11 +231,11 @@ namespace nana
|
||||
break;
|
||||
}
|
||||
|
||||
if ('_' == *sp_ || isalpha(*sp_))
|
||||
if ('_' == *sp_ || std::isalpha(*sp_))
|
||||
{
|
||||
const char * idstart = sp_++;
|
||||
|
||||
while ('_' == *sp_ || isalpha(*sp_) || isalnum(*sp_))
|
||||
while ('_' == *sp_ || std::isalpha(*sp_) || std::isalnum(*sp_))
|
||||
++sp_;
|
||||
|
||||
idstr_.assign(idstart, sp_);
|
||||
@@ -252,6 +253,8 @@ namespace nana
|
||||
}
|
||||
else if ("dock" == idstr_)
|
||||
return token::dock;
|
||||
else if ("fit" == idstr_)
|
||||
return token::fit;
|
||||
else if ("vertical" == idstr_ || "vert" == idstr_)
|
||||
return token::vert;
|
||||
else if ("variable" == idstr_ || "repeated" == idstr_)
|
||||
@@ -357,7 +360,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
static const char* _m_eat_whitespace(const char* sp)
|
||||
static const char* _m_eat_whitespace(const char* sp) noexcept
|
||||
{
|
||||
while (*sp && !isgraph(*sp))
|
||||
++sp;
|
||||
@@ -442,9 +445,9 @@ namespace nana
|
||||
}
|
||||
|
||||
|
||||
inline bool is_idchar(int ch)
|
||||
inline bool is_idchar(int ch) noexcept
|
||||
{
|
||||
return ('_' == ch || isalnum(ch));
|
||||
return ('_' == ch || std::isalnum(ch));
|
||||
}
|
||||
|
||||
std::size_t find_idstr(const std::string& text, const char* idstr, std::size_t off = 0)
|
||||
@@ -519,7 +522,6 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//struct implement
|
||||
struct place::implement
|
||||
{
|
||||
@@ -683,7 +685,6 @@ namespace nana
|
||||
|
||||
class place::implement::field_dock
|
||||
{
|
||||
|
||||
public:
|
||||
div_dockpane * attached{ nullptr }; //attached div object
|
||||
std::unique_ptr<place_parts::dockarea> dockarea; //the dockable widget
|
||||
@@ -697,7 +698,7 @@ namespace nana
|
||||
public:
|
||||
enum class kind{ arrange, vertical_arrange, grid, splitter, dock, dockpane};
|
||||
|
||||
division(kind k, std::string&& n)
|
||||
division(kind k, std::string&& n) noexcept
|
||||
: kind_of_division(k),
|
||||
name(std::move(n))
|
||||
{}
|
||||
@@ -709,6 +710,53 @@ namespace nana
|
||||
field->attached = nullptr;
|
||||
}
|
||||
|
||||
std::pair<double, double> calc_weight_floor()
|
||||
{
|
||||
std::pair<double, double> floor;
|
||||
|
||||
run_.weight_floor = floor;
|
||||
|
||||
if (this->display)
|
||||
{
|
||||
double ratio = 0;
|
||||
|
||||
for (auto & child : children)
|
||||
{
|
||||
auto child_floor = child->calc_weight_floor();
|
||||
|
||||
if(child->weight.kind_of() == number_t::kind::percent)
|
||||
{
|
||||
ratio += child->weight.real();
|
||||
}
|
||||
else
|
||||
{
|
||||
floor.first += child_floor.first;
|
||||
floor.second += child_floor.second;
|
||||
}
|
||||
}
|
||||
|
||||
auto const vert = (this->div_owner && (this->div_owner->kind_of_division == kind::vertical_arrange));
|
||||
|
||||
double& fv = (vert ? floor.second : floor.first);
|
||||
|
||||
if(ratio > 0.001)
|
||||
{
|
||||
if(fv > 0)
|
||||
fv = fv / ratio;
|
||||
}
|
||||
|
||||
if (!this->weight.empty())
|
||||
{
|
||||
if (this->weight.kind_of() != number_t::kind::percent)
|
||||
fv = this->weight.real();
|
||||
}
|
||||
else
|
||||
run_.weight_floor = floor;
|
||||
}
|
||||
|
||||
return floor;
|
||||
}
|
||||
|
||||
void set_visible(bool vsb)
|
||||
{
|
||||
if (field)
|
||||
@@ -769,26 +817,39 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
bool is_back(const division* div) const
|
||||
bool is_back(const division* div) const noexcept
|
||||
{
|
||||
for (auto i = children.crbegin(); i != children.crend(); ++i)
|
||||
const division * last = nullptr;
|
||||
for (auto & p : children)
|
||||
{
|
||||
if (!(i->get()->display))
|
||||
if (!(p->display))
|
||||
continue;
|
||||
|
||||
return (div == i->get());
|
||||
last = p.get();
|
||||
}
|
||||
return false;
|
||||
|
||||
return (div == last);
|
||||
}
|
||||
|
||||
static double limit_px(const division* div, double px, unsigned area_px)
|
||||
{
|
||||
auto const vert = (div->div_owner && (div->div_owner->kind_of_division == kind::vertical_arrange));
|
||||
|
||||
auto weight_floor = (vert? div->run_.weight_floor.second : div->run_.weight_floor.first);
|
||||
|
||||
if (!div->min_px.empty())
|
||||
{
|
||||
auto v = div->min_px.get_value(static_cast<int>(area_px));
|
||||
|
||||
if ((weight_floor > 0) && (v < weight_floor))
|
||||
v = weight_floor;
|
||||
|
||||
if (px < v)
|
||||
return v;
|
||||
}
|
||||
else if ((weight_floor > 0) && (px < weight_floor))
|
||||
return weight_floor;
|
||||
|
||||
if (!div->max_px.empty())
|
||||
{
|
||||
auto v = div->max_px.get_value(static_cast<int>(area_px));
|
||||
@@ -813,7 +874,7 @@ namespace nana
|
||||
return margin.area(field_area);
|
||||
}
|
||||
|
||||
division * previous() const
|
||||
division * previous() const noexcept
|
||||
{
|
||||
if (div_owner)
|
||||
{
|
||||
@@ -822,7 +883,6 @@ namespace nana
|
||||
return child.get();
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
public:
|
||||
void _m_visible_for_child(division * div, bool vsb)
|
||||
@@ -842,6 +902,7 @@ namespace nana
|
||||
kind kind_of_division;
|
||||
bool display{ true };
|
||||
bool visible{ true };
|
||||
bool fit_content{ false };
|
||||
::nana::direction dir{::nana::direction::west};
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<division>> children;
|
||||
@@ -855,13 +916,18 @@ namespace nana
|
||||
field_gather * field{ nullptr };
|
||||
division * div_next{ nullptr };
|
||||
division * div_owner{ nullptr };
|
||||
|
||||
struct run_data
|
||||
{
|
||||
std::pair<double, double> weight_floor;
|
||||
}run_;
|
||||
};//end class division
|
||||
|
||||
class place::implement::div_arrange
|
||||
: public division
|
||||
{
|
||||
public:
|
||||
div_arrange(bool vert, std::string&& name, place_parts::repeated_array&& arr)
|
||||
div_arrange(bool vert, std::string&& name, place_parts::repeated_array&& arr) noexcept
|
||||
: division((vert ? kind::vertical_arrange : kind::arrange), std::move(name)),
|
||||
arrange_(std::move(arr))
|
||||
{}
|
||||
@@ -1089,32 +1155,28 @@ namespace nana
|
||||
|
||||
double var_px = area_px - fa.first;
|
||||
|
||||
/*
|
||||
struct revise_t //deprecated
|
||||
{
|
||||
division * div;
|
||||
double min_px;
|
||||
double max_px;
|
||||
};
|
||||
*/
|
||||
|
||||
std::size_t min_count = 0;
|
||||
double sum_min_px = 0;
|
||||
//std::vector<revise_t> revises; //deprecated
|
||||
std::vector<revised_division> revises;
|
||||
|
||||
for (auto& child : children)
|
||||
{
|
||||
if ((!child->weight.empty()) || !child->display)
|
||||
if ((!child->weight.empty()) || (!child->display))
|
||||
continue;
|
||||
|
||||
double min_px = std::numeric_limits<double>::lowest(), max_px = std::numeric_limits<double>::lowest();
|
||||
|
||||
if (!child->min_px.empty())
|
||||
{
|
||||
min_px = child->min_px.get_value(static_cast<int>(area_px));
|
||||
|
||||
auto weight_floor = (this->kind_of_division == kind::arrange ? child->run_.weight_floor.first : child->run_.weight_floor.second);
|
||||
if ((weight_floor > 0) && (min_px < weight_floor))
|
||||
min_px = weight_floor;
|
||||
|
||||
if(!child->min_px.empty() || (weight_floor > 0))
|
||||
{
|
||||
sum_min_px += min_px;
|
||||
++min_count;
|
||||
++min_count;
|
||||
}
|
||||
|
||||
if (!child->max_px.empty())
|
||||
@@ -1122,7 +1184,9 @@ namespace nana
|
||||
|
||||
if (min_px >= 0 && max_px >= 0 && min_px > max_px)
|
||||
{
|
||||
if (child->min_px.kind_of() == number_t::kind::percent)
|
||||
if(weight_floor > 0)
|
||||
max_px = min_px;
|
||||
else if (child->min_px.kind_of() == number_t::kind::percent)
|
||||
min_px = std::numeric_limits<double>::lowest();
|
||||
else if (child->max_px.kind_of() == number_t::kind::percent)
|
||||
max_px = std::numeric_limits<double>::lowest();
|
||||
@@ -1135,47 +1199,6 @@ namespace nana
|
||||
if (revises.empty())
|
||||
return var_px / fa.second;
|
||||
|
||||
/*
|
||||
auto find_lowest = [&revises](double level_px) //deprecated
|
||||
{
|
||||
double v = (std::numeric_limits<double>::max)();
|
||||
|
||||
for (auto i = revises.begin(); i != revises.end(); ++i)
|
||||
{
|
||||
auto & rev = *i;
|
||||
if (rev.min_px >= 0 && rev.min_px < v && rev.min_px > level_px)
|
||||
v = rev.min_px;
|
||||
else if (rev.max_px >= 0 && rev.max_px < v)
|
||||
v = rev.max_px;
|
||||
}
|
||||
return v;
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
auto remove_full = [&revises](double value, std::size_t& full_count)
|
||||
{
|
||||
full_count = 0;
|
||||
std::size_t reached_mins = 0;
|
||||
auto i = revises.begin();
|
||||
while(i != revises.end())
|
||||
{
|
||||
if (i->max_px == value)
|
||||
{
|
||||
++full_count;
|
||||
i = revises.erase(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i->min_px == value)
|
||||
++reached_mins;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return reached_mins;
|
||||
};
|
||||
*/
|
||||
|
||||
double block_px = 0;
|
||||
double level_px = 0;
|
||||
auto rest_px = var_px - sum_min_px;
|
||||
@@ -1183,8 +1206,8 @@ namespace nana
|
||||
|
||||
while ((rest_px > 0) && blocks)
|
||||
{
|
||||
//auto lowest = find_lowest(level_px); //deprecated
|
||||
auto lowest = _m_find_lowest_revised_division(revises, level_px);
|
||||
|
||||
double fill_px = 0;
|
||||
//blocks may be equal to min_count. E.g, all child divisions have min/max attribute.
|
||||
if (blocks > min_count)
|
||||
@@ -1202,7 +1225,6 @@ namespace nana
|
||||
rest_px -= (lowest-level_px) * (blocks - min_count);
|
||||
|
||||
std::size_t full_count;
|
||||
//min_count -= remove_full(lowest, full_count); //deprecated
|
||||
min_count -= _m_remove_revised(revises, lowest, full_count);
|
||||
blocks -= full_count;
|
||||
level_px = lowest;
|
||||
@@ -1218,7 +1240,7 @@ namespace nana
|
||||
: public division
|
||||
{
|
||||
public:
|
||||
div_grid(std::string&& name, place_parts::repeated_array&& arrange, std::vector<rectangle>&& collapses)
|
||||
div_grid(std::string&& name, place_parts::repeated_array&& arrange, std::vector<rectangle>&& collapses) noexcept
|
||||
: division(kind::grid, std::move(name)),
|
||||
arrange_(std::move(arrange)),
|
||||
collapses_(std::move(collapses))
|
||||
@@ -1226,7 +1248,7 @@ namespace nana
|
||||
dimension.first = dimension.second = 0;
|
||||
}
|
||||
|
||||
void revise_collapses()
|
||||
void revise_collapses() noexcept
|
||||
{
|
||||
if (collapses_.empty())
|
||||
return;
|
||||
@@ -1424,7 +1446,7 @@ namespace nana
|
||||
public:
|
||||
std::pair<unsigned, unsigned> dimension;
|
||||
private:
|
||||
void _m_find_collapse(int x, int y, std::pair<unsigned, unsigned>& collapse) const
|
||||
void _m_find_collapse(int x, int y, std::pair<unsigned, unsigned>& collapse) const noexcept
|
||||
{
|
||||
for (auto & col : collapses_)
|
||||
{
|
||||
@@ -1450,14 +1472,14 @@ namespace nana
|
||||
int pixels;
|
||||
double scale;
|
||||
|
||||
div_block(division* d, int px)
|
||||
div_block(division* d, int px) noexcept
|
||||
: div(d), pixels(px)
|
||||
{}
|
||||
};
|
||||
|
||||
enum{splitter_px = 4};
|
||||
public:
|
||||
div_splitter(place_parts::number_t init_weight, implement* impl):
|
||||
div_splitter(const place_parts::number_t & init_weight, implement* impl) noexcept :
|
||||
division(kind::splitter, std::string()),
|
||||
impl_(impl),
|
||||
init_weight_(init_weight)
|
||||
@@ -1465,7 +1487,7 @@ namespace nana
|
||||
this->weight.assign(splitter_px);
|
||||
}
|
||||
|
||||
void direction(bool horizontal)
|
||||
void direction(bool horizontal) noexcept
|
||||
{
|
||||
splitter_cursor_ = (horizontal ? cursor::size_we : cursor::size_ns);
|
||||
}
|
||||
@@ -1528,23 +1550,29 @@ namespace nana
|
||||
auto area_px = rectangle_rotator(vert, div_owner->margin_area()).w();
|
||||
int delta = (vert ? splitter_.pos().y - begin_point_.y : splitter_.pos().x - begin_point_.x);
|
||||
|
||||
int total_pixels = static_cast<int>(left_pixels_ + right_pixels_);
|
||||
|
||||
auto left_px = static_cast<int>(left_pixels_) + delta;
|
||||
const auto total_pixels = static_cast<int>(left_pixels_ + right_pixels_);
|
||||
/*
|
||||
auto left_px = static_cast<int>(left_pixels_) + delta; //deprecated
|
||||
if (left_px > total_pixels)
|
||||
left_px = total_pixels;
|
||||
else if (left_px < 0)
|
||||
left_px = 0;
|
||||
*/
|
||||
auto left_px = std::clamp(static_cast<int>(left_pixels_) + delta, 0, total_pixels);
|
||||
|
||||
double imd_rate = 100.0 / area_px;
|
||||
left_px = static_cast<int>(limit_px(_m_leaf_left(), left_px, area_px));
|
||||
_m_leaf_left()->weight.assign_percent(imd_rate * left_px);
|
||||
|
||||
auto right_px = static_cast<int>(right_pixels_) - delta;
|
||||
/*
|
||||
auto right_px = static_cast<int>(right_pixels_) - delta; //deprecated
|
||||
if (right_px > total_pixels)
|
||||
right_px = total_pixels;
|
||||
else if (right_px < 0)
|
||||
right_px = 0;
|
||||
*/
|
||||
|
||||
auto right_px = std::clamp(static_cast<int>(right_pixels_) - delta, 0, total_pixels);
|
||||
|
||||
right_px = static_cast<int>(limit_px(_m_leaf_right(), right_px, area_px));
|
||||
_m_leaf_right()->weight.assign_percent(imd_rate * right_px);
|
||||
@@ -1579,11 +1607,17 @@ namespace nana
|
||||
auto area_px = right.right() - left.x();
|
||||
auto right_px = static_cast<int>(limit_px(leaf_right, init_weight_.get_value(area_px), static_cast<unsigned>(area_px)));
|
||||
|
||||
/* //deprecated
|
||||
auto pos = area_px - right_px - splitter_px; //New position of splitter
|
||||
if (pos < limited_range.x())
|
||||
pos = limited_range.x();
|
||||
else if (pos > limited_range.right())
|
||||
pos = limited_range.right();
|
||||
*/
|
||||
|
||||
//New position of splitter
|
||||
const auto pos = std::clamp(static_cast<int>(area_px - right_px - splitter_px), limited_range.x(), limited_range.right());
|
||||
|
||||
|
||||
rectangle_rotator sp_r(vert, field_area);
|
||||
sp_r.x_ref() = pos;
|
||||
@@ -1865,29 +1899,31 @@ namespace nana
|
||||
int endpos = right_base;
|
||||
|
||||
if (!leaf_left->min_px.empty())
|
||||
{
|
||||
auto v = leaf_left->min_px.get_value(area.w());
|
||||
pos += static_cast<int>(v);
|
||||
}
|
||||
pos += static_cast<int>(leaf_left->min_px.get_value(area.w()));
|
||||
|
||||
if (!leaf_left->max_px.empty())
|
||||
{
|
||||
auto v = leaf_left->max_px.get_value(area.w());
|
||||
endpos = left_base + static_cast<int>(v);
|
||||
}
|
||||
endpos = left_base + static_cast<int>(leaf_left->max_px.get_value(area.w()));
|
||||
|
||||
if (!leaf_right->min_px.empty())
|
||||
{
|
||||
auto v = leaf_right->min_px.get_value(area.w());
|
||||
/*
|
||||
auto v = leaf_right->min_px.get_value(area.w()); //deprecated
|
||||
auto x = right_base - static_cast<int>(v);
|
||||
if (x < endpos)
|
||||
endpos = x;
|
||||
*/
|
||||
|
||||
endpos = (std::min)(right_base - static_cast<int>(leaf_right->min_px.get_value(area.w())), endpos);
|
||||
}
|
||||
if (!leaf_right->max_px.empty())
|
||||
{
|
||||
auto v = leaf_right->max_px.get_value(area.w());
|
||||
/*
|
||||
auto v = leaf_right->max_px.get_value(area.w()); //deprecated
|
||||
auto x = right_base - static_cast<int>(v);
|
||||
if (x > pos)
|
||||
pos = x;
|
||||
*/
|
||||
pos = (std::max)(right_base - static_cast<int>(leaf_right->max_px.get_value(area.w())), pos);
|
||||
}
|
||||
|
||||
area.x_ref() = pos;
|
||||
@@ -1914,7 +1950,7 @@ namespace nana
|
||||
: public division, public place_parts::dock_notifier_interface
|
||||
{
|
||||
public:
|
||||
div_dockpane(std::string && name, implement* impl, direction pane_dir)
|
||||
div_dockpane(std::string && name, implement* impl, direction pane_dir) noexcept
|
||||
: division(kind::dockpane, std::move(name)),
|
||||
impl_ptr_{impl}
|
||||
{
|
||||
@@ -1922,7 +1958,7 @@ namespace nana
|
||||
this->display = false;
|
||||
}
|
||||
|
||||
~div_dockpane()
|
||||
~div_dockpane() noexcept
|
||||
{
|
||||
if (dockable_field)
|
||||
{
|
||||
@@ -2060,7 +2096,6 @@ namespace nana
|
||||
indicator_.graph.release();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void notify_move_stopped() override
|
||||
@@ -2221,7 +2256,7 @@ namespace nana
|
||||
evt.mouse_move.connect(grab_fn);
|
||||
}
|
||||
|
||||
void range(int begin, int end)
|
||||
void range(int begin, int end) noexcept
|
||||
{
|
||||
range_.x = begin;
|
||||
range_.y = end;
|
||||
@@ -2236,7 +2271,7 @@ namespace nana
|
||||
|
||||
};
|
||||
public:
|
||||
div_dock(std::string && name, implement* impl)
|
||||
div_dock(std::string && name, implement* impl) noexcept
|
||||
: division(kind::dock, std::move(name)), impl_(impl)
|
||||
{}
|
||||
|
||||
@@ -2458,6 +2493,8 @@ namespace nana
|
||||
if (root_division->field_area.empty())
|
||||
return;
|
||||
|
||||
root_division->calc_weight_floor();
|
||||
|
||||
root_division->collocate(window_handle);
|
||||
|
||||
for (auto & field : fields)
|
||||
@@ -2509,6 +2546,7 @@ namespace nana
|
||||
|
||||
std::unique_ptr<division> div;
|
||||
token div_type = token::eof;
|
||||
bool fit_content = false;
|
||||
|
||||
//These variables stand for the new division's attributes
|
||||
std::string name;
|
||||
@@ -2534,6 +2572,9 @@ namespace nana
|
||||
|
||||
div_type = token::dock;
|
||||
break;
|
||||
case token::fit:
|
||||
fit_content = true;
|
||||
break;
|
||||
case token::splitter:
|
||||
//Ignore the splitter when there is not a division.
|
||||
if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division))
|
||||
@@ -2831,6 +2872,7 @@ namespace nana
|
||||
|
||||
div->display = !undisplayed;
|
||||
div->visible = !(undisplayed || invisible);
|
||||
div->fit_content = fit_content;
|
||||
return div;
|
||||
}
|
||||
|
||||
@@ -2973,6 +3015,7 @@ namespace nana
|
||||
if (impl_->root_division)
|
||||
{
|
||||
impl_->root_division->field_area.dimension({ arg.width, arg.height });
|
||||
impl_->root_division->calc_weight_floor();
|
||||
impl_->root_division->collocate(arg.window_handle);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -210,6 +210,14 @@ namespace API
|
||||
return (restrict::wd_manager().available(iwd) ? iwd->annex.scheme : nullptr);
|
||||
}
|
||||
|
||||
void set_measurer(window wd, ::nana::dev::widget_content_measurer_interface* measurer)
|
||||
{
|
||||
auto iwd = reinterpret_cast<basic_window*>(wd);
|
||||
internal_scope_guard lock;
|
||||
if (restrict::wd_manager().available(iwd))
|
||||
iwd->annex.content_measurer = measurer;
|
||||
}
|
||||
|
||||
void attach_drawer(widget& wd, drawer_trigger& dr)
|
||||
{
|
||||
const auto iwd = reinterpret_cast<basic_window*>(wd.handle());
|
||||
@@ -1009,6 +1017,8 @@ namespace API
|
||||
else
|
||||
return;
|
||||
|
||||
//modal has to guarantee that does not lock the mutex of window_manager before invokeing the pump_event,
|
||||
//otherwise, the modal will prevent the other thread access the window.
|
||||
restrict::bedrock.pump_event(wd, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A Label Control Implementation
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
|
||||
* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -13,8 +13,9 @@
|
||||
*/
|
||||
|
||||
#include <nana/gui/widgets/label.hpp>
|
||||
#include <nana/unicode_bidi.hpp>
|
||||
#include <nana/gui/widgets/skeletons/text_token_stream.hpp>
|
||||
#include <nana/gui/detail/widget_content_measurer_interface.hpp>
|
||||
#include <nana/unicode_bidi.hpp>
|
||||
#include <nana/system/platform.hpp>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
@@ -80,14 +81,14 @@ namespace nana
|
||||
{
|
||||
traceable_.clear();
|
||||
|
||||
nana::paint::font ft = graph.typeface(); //used for restoring the font
|
||||
auto pre_font = graph.typeface(); //used for restoring the font
|
||||
|
||||
const unsigned def_line_pixels = graph.text_extent_size(L" ", 1).height;
|
||||
|
||||
font_ = ft;
|
||||
font_ = pre_font;
|
||||
fblock_ = nullptr;
|
||||
|
||||
_m_set_default(ft, fgcolor);
|
||||
_m_set_default(pre_font, fgcolor);
|
||||
|
||||
_m_measure(graph);
|
||||
|
||||
@@ -145,7 +146,7 @@ namespace nana
|
||||
rs.pos.y += static_cast<int>(rs.pixels.back().pixels);
|
||||
}
|
||||
|
||||
graph.typeface(ft);
|
||||
graph.typeface(pre_font);
|
||||
}
|
||||
|
||||
bool find(int x, int y, std::wstring& target, std::wstring& url) const
|
||||
@@ -613,10 +614,13 @@ namespace nana
|
||||
|
||||
//class trigger
|
||||
//@brief: Draw the label
|
||||
struct trigger::impl_t
|
||||
struct trigger::implement
|
||||
{
|
||||
class measurer;
|
||||
|
||||
widget * wd{nullptr};
|
||||
paint::graphics * graph{nullptr};
|
||||
class measurer * measurer{ nullptr };
|
||||
|
||||
align text_align{align::left};
|
||||
align_v text_align_v;
|
||||
@@ -643,8 +647,28 @@ namespace nana
|
||||
std::vector<std::function<void(command, const std::string&)>> listener_;
|
||||
};
|
||||
|
||||
class trigger::implement::measurer
|
||||
: public dev::widget_content_measurer_interface
|
||||
{
|
||||
public:
|
||||
measurer(implement* impl)
|
||||
: impl_{ impl }
|
||||
{}
|
||||
|
||||
optional<size> measure(bool limit_width, unsigned limit_pixels) const override
|
||||
{
|
||||
if (impl_->graph)
|
||||
{
|
||||
|
||||
}
|
||||
return{};
|
||||
}
|
||||
private:
|
||||
implement * const impl_;
|
||||
};
|
||||
|
||||
trigger::trigger()
|
||||
:impl_(new impl_t)
|
||||
:impl_(new implement)
|
||||
{}
|
||||
|
||||
trigger::~trigger()
|
||||
@@ -652,7 +676,7 @@ namespace nana
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
trigger::impl_t * trigger::impl() const
|
||||
trigger::implement * trigger::impl() const
|
||||
{
|
||||
return impl_;
|
||||
}
|
||||
|
||||
468
source/stdc++.cpp
Normal file
468
source/stdc++.cpp
Normal file
@@ -0,0 +1,468 @@
|
||||
/**
|
||||
* Standard Library for C++11/14/17
|
||||
* Nana C++ Library(http://www.nanapro.org)
|
||||
* Copyright(C) 2017 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/stdc++.cpp
|
||||
*/
|
||||
|
||||
#include <nana/stdc++.hpp>
|
||||
|
||||
//Implement workarounds for GCC/MinGW which version is below 4.8.2
|
||||
#if defined(STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED)
|
||||
#include <sstream>
|
||||
namespace std
|
||||
{
|
||||
int stoi(const std::string& str, std::size_t * pos, int base)
|
||||
{
|
||||
auto sptr = str.c_str();
|
||||
char *end;
|
||||
errno = 0;
|
||||
auto result = std::strtol(sptr, &end, base);
|
||||
|
||||
if (sptr == end)
|
||||
throw std::invalid_argument("invalid stoi argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoi argument out of range");
|
||||
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - sptr);
|
||||
return ((int)result);
|
||||
}
|
||||
|
||||
int stoi(const std::wstring& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto sptr = str.data();
|
||||
wchar_t *end;
|
||||
errno = 0;
|
||||
auto result = std::wcstol(sptr, &end, base);
|
||||
|
||||
if (sptr == end)
|
||||
throw std::invalid_argument("invalid stoi argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoi argument out of range");
|
||||
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - sptr);
|
||||
return ((int)result);
|
||||
}
|
||||
using ::strtof;
|
||||
using ::strtold;
|
||||
using ::wcstold;
|
||||
using ::strtoll;
|
||||
using ::wcstoll;
|
||||
using ::strtoull;
|
||||
using ::wcstoull;
|
||||
|
||||
float stof(const std::string& str, std::size_t * pos)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
char *end;
|
||||
auto result = std::strtof(ptr, &end);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stof argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
float stof(const std::wstring& str, std::size_t* pos)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
wchar_t *end;
|
||||
auto result = std::wcstof(ptr, &end);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stof argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
double stod(const std::string& str, std::size_t * pos)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
char *end;
|
||||
auto result = std::strtod(ptr, &end);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stod argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
double stod(const std::wstring& str, std::size_t* pos)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
wchar_t *end;
|
||||
auto result = std::wcstod(ptr, &end);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stod argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
long double stold(const std::string& str, std::size_t * pos)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
char *end;
|
||||
auto result = std::strtold(ptr, &end);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stold argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
long double stold(const std::wstring& str, std::size_t* pos)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
wchar_t *end;
|
||||
auto result = std::wcstold(ptr, &end);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stold argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
long stol(const std::string& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
char *end;
|
||||
auto result = std::strtol(ptr, &end, base);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stol argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
long stol(const std::wstring& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
wchar_t *end;
|
||||
auto result = std::wcstol(ptr, &end, base);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stol argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
//Workaround for no implemenation of std::stoll in MinGW.
|
||||
long long stoll(const std::string& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
char* end;
|
||||
auto result = std::strtoll(ptr, &end, base);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoll argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
long long stoll(const std::wstring& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
wchar_t* end;
|
||||
auto result = std::wcstoll(ptr, &end, base);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoll argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long long stoull(const std::string& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
char* end;
|
||||
auto result = std::strtoull(ptr, &end, base);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoull argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long long stoull(const std::wstring& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
wchar_t* end;
|
||||
auto result = std::wcstoull(ptr, &end, base);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoull argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
//Workaround for no implemenation of std::stoul in MinGW.
|
||||
unsigned long stoul(const std::string& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
char* end;
|
||||
auto result = std::strtoul(ptr, &end, base);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoul argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long stoul(const std::wstring& str, std::size_t* pos, int base)
|
||||
{
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
wchar_t* end;
|
||||
auto result = std::wcstoul(ptr, &end, base);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoul argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
}
|
||||
}//end namespace std
|
||||
#endif //STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED
|
||||
|
||||
#ifdef STD_TO_STRING_NOT_SUPPORTED
|
||||
#include <sstream>
|
||||
namespace std
|
||||
{
|
||||
std::string to_string(double v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string to_string(long double v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string to_string(unsigned v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string to_string(int v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string to_string(long v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string to_string(unsigned long v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string to_string(long long v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string to_string(unsigned long long v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string to_string(float v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
#endif // STD_TO_STRING_NOT_SUPPORTED
|
||||
|
||||
#ifdef STD_TO_WSTRING_NOT_SUPPORTED
|
||||
#include <sstream>
|
||||
namespace std
|
||||
{
|
||||
std::wstring to_wstring(double v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring to_wstring(long double v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring to_wstring(unsigned v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring to_wstring(int v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring to_wstring(long v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring to_wstring(unsigned long v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring to_wstring(long long v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring to_wstring(unsigned long long v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring to_wstring(float v)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _enable_std_put_time
|
||||
#include <ctime>
|
||||
#include <cwchar>
|
||||
namespace std
|
||||
{
|
||||
//Workaround for no implemenation of std::put_time in gcc < 5.
|
||||
/* std unspecified return type */
|
||||
//template< class CharT, class RTSTR >// let fail for CharT != char / wchar_t
|
||||
//RTSTR put_time(const std::tm* tmb, const CharT* fmt);
|
||||
|
||||
//template< >
|
||||
std::string put_time/*<char, std::string>*/(const std::tm* tmb, const char* fmt)
|
||||
{
|
||||
std::size_t sz = 200;
|
||||
std::string str(sz, '\0');
|
||||
sz = std::strftime(&str[0], str.size() - 1, fmt, tmb);
|
||||
str.resize(sz);
|
||||
return str;
|
||||
}
|
||||
//Defined in header <ctime>
|
||||
// std::size_t strftime(char* str, std::size_t count, const char* format, const std::tm* time);
|
||||
//template<>
|
||||
//std::wstring put_time<wchar_t, std::wstring>(const std::tm* tmb, const wchar_t* fmt)
|
||||
//{
|
||||
// unsigned sz = 200;
|
||||
// std::wstring str(sz, L'\0');
|
||||
// sz = std::wcsftime(&str[0], str.size() - 1, fmt, tmb);
|
||||
// str.resize(sz);
|
||||
// return str;
|
||||
//}
|
||||
// http://en.cppreference.com/w/cpp/chrono/c/wcsftime
|
||||
// Defined in header <cwchar>
|
||||
// std::size_t wcsftime(wchar_t* str, std::size_t count, const wchar_t* format, const std::tm* time);
|
||||
// Converts the date and time information from a given calendar time time to a null - terminated
|
||||
// wide character string str according to format string format.Up to count bytes are written.
|
||||
// Parameters
|
||||
// str - pointer to the first element of the wchar_t array for output
|
||||
// count - maximum number of wide characters to write
|
||||
// format - pointer to a null - terminated wide character string specifying the format of conversion.
|
||||
|
||||
}
|
||||
#endif // _enable_std_put_time
|
||||
Reference in New Issue
Block a user