Add text wrapping.
The layout engine now first tries to wrap some text if too wide before trying to use scrollbars.
This commit is contained in:
parent
6329273f9e
commit
a36e1ee696
12 changed files with 453 additions and 45 deletions
|
@ -47,6 +47,19 @@ public:
|
|||
|
||||
/***** ***** ***** ***** Inherited ***** ***** ***** *****/
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool can_wrap() const { return grid_.can_wrap() || twidget::can_wrap(); }
|
||||
|
||||
/**
|
||||
* Inherited from twidget.
|
||||
*
|
||||
* @todo Adjust for our border.
|
||||
*/
|
||||
bool set_width_constrain(const unsigned width) { return grid_.set_width_constrain(width); }
|
||||
|
||||
/** Inherited from twidget. */
|
||||
void clear_width_constrain() { grid_.clear_width_constrain(); }
|
||||
|
||||
/**
|
||||
* Inherited from twidget.
|
||||
*
|
||||
|
|
|
@ -20,17 +20,18 @@
|
|||
|
||||
namespace gui2 {
|
||||
|
||||
tcontrol::tcontrol(const unsigned canvas_count) :
|
||||
visible_(true),
|
||||
label_(),
|
||||
multiline_label_(false),
|
||||
use_tooltip_on_label_overflow_(true),
|
||||
tooltip_(),
|
||||
help_message_(),
|
||||
canvas_(canvas_count),
|
||||
restorer_(),
|
||||
config_(0),
|
||||
renderer_()
|
||||
tcontrol::tcontrol(const unsigned canvas_count)
|
||||
: visible_(true)
|
||||
, label_()
|
||||
, multiline_label_(false)
|
||||
, use_tooltip_on_label_overflow_(true)
|
||||
, tooltip_()
|
||||
, help_message_()
|
||||
, canvas_(canvas_count)
|
||||
, restorer_()
|
||||
, config_(0)
|
||||
, renderer_()
|
||||
, text_maximum_width_(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -84,31 +85,104 @@ void tcontrol::load_config()
|
|||
tpoint tcontrol::get_minimum_size() const
|
||||
{
|
||||
assert(config_);
|
||||
const tpoint min_size(config_->min_width, config_->min_height);
|
||||
if(label_.empty()) {
|
||||
return min_size;
|
||||
|
||||
tpoint result(config_->min_width, config_->min_height);
|
||||
if(! label_.empty()) {
|
||||
// If no label text set we use the predefined value.
|
||||
|
||||
/**
|
||||
* @todo The value send should subtract the border size
|
||||
* and readd it after calculation to get the proper result.
|
||||
*/
|
||||
result = get_best_text_size(result);
|
||||
}
|
||||
|
||||
return get_best_text_size(min_size);
|
||||
DBG_G_L << "tcontrol(" + get_control_type() + ") " + __func__ + ":"
|
||||
<< " empty label " << label_.empty()
|
||||
<< " result " << result
|
||||
<< ".\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
tpoint tcontrol::get_best_size() const
|
||||
{
|
||||
assert(config_);
|
||||
tpoint result(config_->default_width, config_->default_height);
|
||||
if(! label_.empty()) {
|
||||
// If no label text set we use the predefined value.
|
||||
|
||||
// Return default on an empty label.
|
||||
const tpoint default_size(config_->default_width, config_->default_height);
|
||||
if(label_.empty()) {
|
||||
return default_size;
|
||||
/**
|
||||
* @todo The value send should subtract the border size
|
||||
* and readd it after calculation to get the proper result.
|
||||
*/
|
||||
result = get_best_text_size(result);
|
||||
}
|
||||
|
||||
return get_best_text_size(default_size);
|
||||
DBG_G_L << "tcontrol(" + get_control_type() + ") " + __func__ + ":"
|
||||
<< " empty label " << label_.empty()
|
||||
<< " result " << result
|
||||
<< ".\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
tpoint tcontrol::get_best_size(const tpoint& maximum_size) const
|
||||
{
|
||||
assert(config_);
|
||||
tpoint result(0, 0);
|
||||
if(! label_.empty()) {
|
||||
// If no label text set we use the predefined value.
|
||||
|
||||
/**
|
||||
* @todo The value send should subtract the border size
|
||||
* and readd it after calculation to get the proper result.
|
||||
*/
|
||||
result = get_best_text_size(tpoint(0,0), maximum_size);
|
||||
}
|
||||
|
||||
DBG_G_L << "tcontrol(" + get_control_type() + ") " + __func__ + ":"
|
||||
<< " empty label " << label_.empty()
|
||||
<< " result " << result
|
||||
<< ".\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
tpoint tcontrol::get_maximum_size() const
|
||||
{
|
||||
assert(config_);
|
||||
return tpoint(config_->max_width, config_->max_height);
|
||||
|
||||
tpoint result = tpoint(config_->max_width, config_->max_height);
|
||||
|
||||
DBG_G_L << "tcontrol(" + get_control_type() + ") " + __func__ + ":"
|
||||
<< " result " << result
|
||||
<< ".\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
bool tcontrol::set_width_constrain(const unsigned width)
|
||||
{
|
||||
assert(can_wrap());
|
||||
assert(text_maximum_width_ == 0);
|
||||
|
||||
bool result = false;
|
||||
if(label_.empty()) {
|
||||
// Return true on empty label but don't set the value.
|
||||
result = true;
|
||||
} else if(get_best_text_size(tpoint(width, 0)).y <= static_cast<int>(width)) {
|
||||
// Test whether we can achieve the wanted size.
|
||||
text_maximum_width_ = width;
|
||||
result = true;
|
||||
}
|
||||
|
||||
DBG_G_L << "tcontrol(" + get_control_type() + ") " + __func__ + ":"
|
||||
<< " empty label " << label_.empty()
|
||||
<< " result " << result
|
||||
<< ".\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
void tcontrol::clear_width_constrain()
|
||||
{
|
||||
text_maximum_width_ = 0;
|
||||
}
|
||||
|
||||
void tcontrol::draw(surface& surface, const bool force,
|
||||
|
@ -206,14 +280,18 @@ void tcontrol::update_canvas()
|
|||
canvas.set_variable("text", variant(label_));
|
||||
canvas.set_variable("text_maximum_width", variant(max_width));
|
||||
canvas.set_variable("text_maximum_height", variant(max_height));
|
||||
canvas.set_variable("text_wrap_mode", variant(can_wrap()
|
||||
? PANGO_ELLIPSIZE_NONE : PANGO_ELLIPSIZE_END));
|
||||
}
|
||||
}
|
||||
|
||||
int tcontrol::get_text_maximum_width() const
|
||||
{
|
||||
assert(config_);
|
||||
|
||||
return get_width() - config_->text_extra_width;
|
||||
|
||||
return text_maximum_width_ != 0
|
||||
? text_maximum_width_
|
||||
: get_width() - config_->text_extra_width;
|
||||
}
|
||||
|
||||
int tcontrol::get_text_maximum_height() const
|
||||
|
@ -235,8 +313,10 @@ void tcontrol::restore_background(surface& dst)
|
|||
gui2::restore_background(restorer_, dst, get_rect());
|
||||
}
|
||||
|
||||
tpoint tcontrol::get_best_text_size(const tpoint& minimum_size) const
|
||||
tpoint tcontrol::get_best_text_size(const tpoint& minimum_size, const tpoint& maximum_size) const
|
||||
{
|
||||
log_scope2(gui_layout, "tcontrol(" + get_control_type() + ") " + __func__);
|
||||
|
||||
assert(!label_.empty());
|
||||
|
||||
const tpoint border(config_->text_extra_width, config_->text_extra_height);
|
||||
|
@ -247,13 +327,34 @@ tpoint tcontrol::get_best_text_size(const tpoint& minimum_size) const
|
|||
renderer_.set_font_style(config_->text_font_style);
|
||||
|
||||
// Try with the minimum wanted size.
|
||||
renderer_.set_maximum_width(size.x);
|
||||
const int maximum_width = text_maximum_width_ != 0
|
||||
? text_maximum_width_
|
||||
: maximum_size.x;
|
||||
|
||||
renderer_.set_maximum_width(maximum_width);
|
||||
|
||||
if(can_wrap()) {
|
||||
renderer_.set_ellipse_mode(PANGO_ELLIPSIZE_NONE);
|
||||
}
|
||||
|
||||
if(multiline_label_) {
|
||||
// FIXME multiline seems to be unused
|
||||
renderer_.set_maximum_height(size.y);
|
||||
}
|
||||
|
||||
DBG_G_L << "tcontrol(" + get_control_type() + ") status:\n";
|
||||
DBG_G_L << "minimum_size " << minimum_size
|
||||
<< " maximum_size " << maximum_size
|
||||
<< " text_maximum_width_ " << text_maximum_width_
|
||||
<< " can_wrap " << can_wrap()
|
||||
<< " truncated " << renderer_.is_truncated()
|
||||
<< " renderer size " << renderer_.get_size()
|
||||
<< ".\n";
|
||||
|
||||
// If doesn't fit try the maximum.
|
||||
if(renderer_.is_truncated()) {
|
||||
if(renderer_.is_truncated() && !can_wrap()) {
|
||||
// FIXME if maximum size is defined we should look at that
|
||||
// but also we don't adjust for the extra text space yet!!!
|
||||
const tpoint maximum_size(config_->max_width, config_->max_height);
|
||||
renderer_.set_maximum_width(maximum_size.x ? maximum_size.x - border.x : -1);
|
||||
if(multiline_label_) {
|
||||
|
@ -270,7 +371,8 @@ tpoint tcontrol::get_best_text_size(const tpoint& minimum_size) const
|
|||
if(size.y < minimum_size.y) {
|
||||
size.y = minimum_size.y;
|
||||
}
|
||||
|
||||
|
||||
DBG_G_L << "tcontrol(" + get_control_type() + ") result " << size << ".\n";
|
||||
return size;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,12 +98,18 @@ public:
|
|||
/** Inherited from twidget. */
|
||||
tpoint get_best_size() const;
|
||||
|
||||
/** Import overloaded versions. */
|
||||
using twidget::get_best_size;
|
||||
/** Inherited from twidget. */
|
||||
tpoint get_best_size(const tpoint& maximum_size) const;
|
||||
|
||||
/** Inherited from twidget. */
|
||||
tpoint get_maximum_size() const;
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool set_width_constrain(const unsigned width);
|
||||
|
||||
/** Inherited from twidget. */
|
||||
void clear_width_constrain();
|
||||
|
||||
/** Inherited from twidget. */
|
||||
void draw(surface& surface, const bool force = false,
|
||||
const bool invalidate_background = false);
|
||||
|
@ -334,10 +340,14 @@ private:
|
|||
* Gets the best size for a text.
|
||||
*
|
||||
* @param minimum_size The minimum size of the text.
|
||||
* @param maximum_size The wanted maximum size of the text, if not
|
||||
* possible it's ignored. A value of 0 means
|
||||
* that it's ignored as well.
|
||||
*
|
||||
* @returns The best size.
|
||||
*/
|
||||
tpoint get_best_text_size(const tpoint& minimum_size) const;
|
||||
tpoint get_best_text_size(const tpoint& minimum_size,
|
||||
const tpoint& maximum_size = tpoint(0,0)) const;
|
||||
|
||||
/**
|
||||
* Contains a helper cache for the rendering.
|
||||
|
@ -351,6 +361,9 @@ private:
|
|||
* as wanted.
|
||||
*/
|
||||
mutable font::ttext renderer_;
|
||||
|
||||
/** The maximum width for the text in a control. */
|
||||
int text_maximum_width_;
|
||||
};
|
||||
|
||||
} // namespace gui2
|
||||
|
|
|
@ -281,6 +281,129 @@ tpoint tgrid::get_best_size(const tpoint& maximum_size) const
|
|||
return tpoint(size.x, size.y);
|
||||
}
|
||||
|
||||
bool tgrid::can_wrap() const
|
||||
{
|
||||
foreach(const tchild& child, children_) {
|
||||
if(child.can_wrap()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Inherit
|
||||
return twidget::can_wrap();
|
||||
}
|
||||
|
||||
bool tgrid::set_width_constrain(const unsigned maximum_width)
|
||||
{
|
||||
|
||||
/*
|
||||
* 1. Test the width of (every) row.
|
||||
* 2. Row wider as wanted?
|
||||
* - No goto 3
|
||||
* - Yes
|
||||
* 2.1 Test every column in the row.
|
||||
* 2.2 Can be resized?
|
||||
* - No goto 2.1.
|
||||
* - Yes can be sized small enough?
|
||||
* - No FAILURE.
|
||||
* - Yes goto 3.
|
||||
* 2.3 Last column?
|
||||
* - No goto 2.1
|
||||
* - Yes FAILURE.
|
||||
* 3. Last row?
|
||||
* - No goto 1.
|
||||
* - Yes SUCCESS.
|
||||
*/
|
||||
|
||||
log_scope2(gui_layout, std::string("tgrid ") + __func__);
|
||||
DBG_G_L << "tgrid: maximum_width " << maximum_width << ".\n";
|
||||
|
||||
std::vector<int> widths(cols_);
|
||||
for(unsigned row = 0; row < rows_; ++row) {
|
||||
|
||||
for(unsigned col = 0; col < cols_; ++col) {
|
||||
|
||||
widths[col] = (child(row, col)./**widget()->**/get_best_size()).x;
|
||||
}
|
||||
|
||||
if(std::accumulate(widths.begin(), widths.end(), 0) >
|
||||
static_cast<int>(maximum_width)) {
|
||||
|
||||
DBG_G_L << "tgrid: row " << row << " out of bounds needs "
|
||||
<< std::accumulate(widths.begin(), widths.end(), 0)
|
||||
<< " available " << maximum_width
|
||||
<< ", try to resize.\n";
|
||||
log_scope2(gui_layout, "tgrid: testing all columns");
|
||||
|
||||
int width = 0;
|
||||
for(unsigned col = 0; col < cols_; ++col) {
|
||||
|
||||
log_scope2(gui_layout, "tgrid: column "
|
||||
+ lexical_cast<std::string>(col));
|
||||
|
||||
tchild& chld = child(row, col);
|
||||
|
||||
if(!chld.can_wrap()) {
|
||||
DBG_G_L << "tgrid: column can't wrap, skip.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if(widths[col] == 0) {
|
||||
DBG_G_L << "tgrid: column has zero width, skip.\n";
|
||||
}
|
||||
|
||||
width = widths[col];
|
||||
widths[col] = 0;
|
||||
|
||||
const int widget_width = maximum_width
|
||||
- std::accumulate(widths.begin(), widths.end(), 0);
|
||||
|
||||
if(widget_width <=0) {
|
||||
|
||||
DBG_G_L << "tgrid: column is too small to resize, skip.\n";
|
||||
widths[col] = width;
|
||||
width = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(chld.get_best_size(tpoint(widget_width, 0)).x <= widget_width
|
||||
&& chld.set_width_constrain(widget_width)) {
|
||||
|
||||
DBG_G_L << "tgrid: column resize succeeded.\n";
|
||||
break;
|
||||
}
|
||||
|
||||
DBG_G_L << "tgrid: column resize failed.\n";
|
||||
widths[col] = width;
|
||||
width = 0;
|
||||
}
|
||||
|
||||
if(width == 0) {
|
||||
DBG_G_L << "tgrid: no solution found.\n";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
DBG_G_L << "tgrid: row " << row << " in bounds.\n";
|
||||
}
|
||||
}
|
||||
|
||||
DBG_G_L << "tgrid: found solution.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
void tgrid::clear_width_constrain()
|
||||
{
|
||||
foreach(tchild& cell, children_) {
|
||||
|
||||
if(cell.widget() && cell.widget()->can_wrap()) {
|
||||
cell.widget()->clear_width_constrain();
|
||||
}
|
||||
}
|
||||
|
||||
// Inherit
|
||||
twidget::clear_width_constrain();
|
||||
}
|
||||
|
||||
bool tgrid::has_vertical_scrollbar() const
|
||||
{
|
||||
for(std::vector<tchild>::const_iterator itor = children_.begin();
|
||||
|
@ -674,6 +797,13 @@ tpoint tgrid::tchild::get_maximum_size() const
|
|||
return maximum_size_;
|
||||
}
|
||||
|
||||
bool tgrid::tchild::set_width_constrain(const unsigned width)
|
||||
{
|
||||
assert(widget_ && widget_->can_wrap());
|
||||
|
||||
return widget_->set_width_constrain(width - border_space().x);
|
||||
}
|
||||
|
||||
tpoint tgrid::tchild::border_space() const
|
||||
{
|
||||
tpoint result(0, 0);
|
||||
|
|
|
@ -183,6 +183,15 @@ public:
|
|||
/** Inherited from twidget. */
|
||||
tpoint get_maximum_size() const;
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool can_wrap() const;
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool set_width_constrain(const unsigned width);
|
||||
|
||||
/** Inherited from twidget. */
|
||||
void clear_width_constrain();
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool has_vertical_scrollbar() const;
|
||||
|
||||
|
@ -260,6 +269,12 @@ private:
|
|||
/** Returns the maximum size for the cell. */
|
||||
tpoint get_maximum_size() const;
|
||||
|
||||
/** Returns the can_wrap for the cell. */
|
||||
bool can_wrap() const { return widget_ ? widget_->can_wrap() : false; }
|
||||
|
||||
/** Returns the set_width_constrain for the cell. */
|
||||
bool set_width_constrain(const unsigned width);
|
||||
|
||||
/**
|
||||
* Sets the size of the widget in the cell.
|
||||
*
|
||||
|
|
|
@ -24,12 +24,16 @@ class tlabel : public tcontrol
|
|||
{
|
||||
public:
|
||||
|
||||
tlabel() :
|
||||
tcontrol(COUNT),
|
||||
state_(ENABLED)
|
||||
tlabel()
|
||||
: tcontrol(COUNT)
|
||||
, state_(ENABLED)
|
||||
, can_wrap_(false)
|
||||
{
|
||||
}
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool can_wrap() const { return can_wrap_; }
|
||||
|
||||
/** Inherited from tcontrol. */
|
||||
void set_active(const bool active)
|
||||
{ if(get_active() != active) set_state(active ? ENABLED : DISABLED); };
|
||||
|
@ -40,6 +44,10 @@ public:
|
|||
/** Inherited from tcontrol. */
|
||||
unsigned get_state() const { return state_; }
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
void set_can_wrap(const bool wrap) { can_wrap_ = wrap; }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
@ -59,6 +67,9 @@ private:
|
|||
*/
|
||||
tstate state_;
|
||||
|
||||
/** Holds the label can wrap or not. */
|
||||
bool can_wrap_;
|
||||
|
||||
/** Inherited from tcontrol. */
|
||||
const std::string& get_control_type() const
|
||||
{ static const std::string type = "label"; return type; }
|
||||
|
|
|
@ -77,14 +77,33 @@ const tspacer* tscroll_label::find_spacer(const bool must_exist) const
|
|||
|
||||
void tscroll_label::finalize()
|
||||
{
|
||||
find_label(true)->set_label(label());
|
||||
|
||||
tspacer* spacer = new tspacer();
|
||||
spacer->set_id("_label");
|
||||
spacer->set_definition("default");
|
||||
|
||||
label_ = dynamic_cast<tlabel*>(grid().swap_child("_label", spacer, true));
|
||||
assert(label_);
|
||||
|
||||
label_->set_label(label());
|
||||
label_->set_can_wrap(true);
|
||||
}
|
||||
|
||||
bool tscroll_label::set_content_width_constrain(const unsigned width)
|
||||
{
|
||||
bool result = !label_ ? true : label_->set_width_constrain(width);
|
||||
|
||||
DBG_G_L << "tscroll_label " << __func__ << ":"
|
||||
<< " no label " << !label_
|
||||
<< " result " << result
|
||||
<< ".\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
void tscroll_label::clear_content_width_constrain()
|
||||
{
|
||||
if(label_) {
|
||||
label_->clear_width_constrain();
|
||||
}
|
||||
}
|
||||
|
||||
tpoint tscroll_label::get_content_best_size(const tpoint& maximum_size) const
|
||||
|
|
|
@ -38,9 +38,6 @@ public:
|
|||
|
||||
~tscroll_label();
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool has_vertical_scrollbar() const { return true; }
|
||||
|
||||
/** Inherited from tcontrol. */
|
||||
void set_label(const t_string& label);
|
||||
|
||||
|
@ -104,6 +101,15 @@ private:
|
|||
const std::string& get_control_type() const
|
||||
{ static const std::string type = "scroll_label"; return type; }
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
bool can_content_wrap() const { return true; }
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
bool set_content_width_constrain(const unsigned width);
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
void clear_content_width_constrain();
|
||||
|
||||
/** Inherited from tvertical_scrollbar_container_. */
|
||||
tpoint get_content_best_size(const tpoint& maximum_size) const;
|
||||
|
||||
|
|
|
@ -156,9 +156,28 @@ void tvertical_scrollbar_container_::key_press(tevent_handler& /*event*/,
|
|||
}
|
||||
}
|
||||
|
||||
bool tvertical_scrollbar_container_::set_width_constrain(const unsigned width)
|
||||
{
|
||||
log_scope2(gui_layout,
|
||||
std::string("tvertical_scrollbar_container_ ") + __func__);
|
||||
|
||||
const unsigned scrollbar_width = scrollbar_mode_ == HIDE
|
||||
? 0 : find_scrollbar_grid()->get_best_size().x;
|
||||
|
||||
const bool result = set_content_width_constrain(width - scrollbar_width);
|
||||
|
||||
DBG_G_L << "tvertical_scrollbar_container_ "
|
||||
<< " width " << width
|
||||
<< " scrollbar_width " << scrollbar_width
|
||||
<< " result " << result
|
||||
<< ".\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
tpoint tvertical_scrollbar_container_::get_best_size() const
|
||||
{
|
||||
log_scope2(gui_layout, std::string("tvertical_scrollbar_container_ ") + __func__);
|
||||
log_scope2(gui_layout,
|
||||
std::string("tvertical_scrollbar_container_ ") + __func__);
|
||||
|
||||
const tpoint content = get_content_best_size();
|
||||
if(scrollbar_mode_ == HIDE) {
|
||||
|
@ -187,8 +206,11 @@ tpoint tvertical_scrollbar_container_::get_best_size() const
|
|||
|
||||
tpoint tvertical_scrollbar_container_::get_best_size(const tpoint& maximum_size) const
|
||||
{
|
||||
log_scope2(gui_layout, std::string("tvertical_scrollbar_container_ ") + __func__);
|
||||
DBG_G_L << "tvertical_scrollbar_container_ maximum_size " << maximum_size << ".\n";
|
||||
log_scope2(gui_layout,
|
||||
std::string("tvertical_scrollbar_container_ ") + __func__);
|
||||
|
||||
DBG_G_L << "tvertical_scrollbar_container_ maximum_size "
|
||||
<< maximum_size << ".\n";
|
||||
|
||||
if(scrollbar_mode_ == HIDE) {
|
||||
// No scrollbar hope the normal size is small enough. Don't send the
|
||||
|
@ -201,7 +223,8 @@ tpoint tvertical_scrollbar_container_::get_best_size(const tpoint& maximum_size)
|
|||
} else {
|
||||
// The scrollbar also can't be resized so ask the best size.
|
||||
const tpoint scrollbar = find_scrollbar_grid()->get_best_size();
|
||||
const tpoint content = get_content_best_size(tpoint(maximum_size.x - scrollbar.x, maximum_size.y));
|
||||
const tpoint content = get_content_best_size(tpoint(
|
||||
maximum_size.x - scrollbar.x, maximum_size.y));
|
||||
|
||||
// Width and height same rules as above.
|
||||
if(scrollbar_mode_ == SHOW) {
|
||||
|
|
|
@ -76,6 +76,15 @@ public:
|
|||
void key_press(tevent_handler& event, bool& handled,
|
||||
SDLKey key, SDLMod modifier, Uint16 unicode);
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool can_wrap() const { return can_content_wrap(); }
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool set_width_constrain(const unsigned width);
|
||||
|
||||
/** Inherited from twidget. */
|
||||
void clear_width_constrain() { clear_content_width_constrain(); }
|
||||
|
||||
/** Inherited from twidget. */
|
||||
bool has_vertical_scrollbar() const { return true; }
|
||||
|
||||
|
@ -214,7 +223,29 @@ private:
|
|||
/** Returns the selected row. */
|
||||
virtual unsigned get_selected_row() const;
|
||||
|
||||
/***** ***** pure virtuals for the subclasses ****** *****/
|
||||
/***** ***** (pure) virtuals for the subclasses ****** *****/
|
||||
|
||||
/**
|
||||
* Returns whether or not the content can wrap.
|
||||
*
|
||||
* See can_wrap() for more info.
|
||||
*/
|
||||
virtual bool can_content_wrap() const { return false; }
|
||||
|
||||
/**
|
||||
* Sets the content width constrain.
|
||||
*
|
||||
* See set_width_contrain() for more info.
|
||||
*/
|
||||
virtual bool set_content_width_constrain(const unsigned /*width*/)
|
||||
{return false; }
|
||||
|
||||
/**
|
||||
* Clears the content width constrain.
|
||||
*
|
||||
* See clear_width_constrain() for more info.
|
||||
*/
|
||||
virtual void clear_content_width_constrain() {}
|
||||
|
||||
/**
|
||||
* Returns the best size for the content part.
|
||||
|
|
|
@ -325,8 +325,7 @@ public:
|
|||
* @returns The best size for the widget.
|
||||
* @retval 0,0 The best size is 0,0.
|
||||
*/
|
||||
virtual tpoint get_best_size(const tpoint& /*maximum_size*/) const
|
||||
{ return get_best_size(); }
|
||||
virtual tpoint get_best_size(const tpoint& maximum_size) const = 0;
|
||||
|
||||
/**
|
||||
* Gets the maximum size for the widget.
|
||||
|
@ -336,6 +335,32 @@ public:
|
|||
*/
|
||||
virtual tpoint get_maximum_size() const = 0;
|
||||
|
||||
/**
|
||||
* Can the widget wrap.
|
||||
*
|
||||
* When a widget can wrap it can reduce it's width by increasing it's
|
||||
* height. When a layout is too wide it should first try to wrap and if
|
||||
* that fails it should check the vertical scrollbar status. After wrapping
|
||||
* the height might (probably will) change so the layout engine needs to
|
||||
* recalculate.
|
||||
*/
|
||||
virtual bool can_wrap() const { return false; }
|
||||
|
||||
/**
|
||||
* Limits the maximum width for a widget.
|
||||
*
|
||||
* This function should only be called on widgets that can wrap.
|
||||
*
|
||||
* @param width The maximum width for the widget.
|
||||
*
|
||||
* @returns True if the widget can wrap in the wanted
|
||||
* width, false otherwise.
|
||||
*/
|
||||
virtual bool set_width_constrain(const unsigned /*width*/) { return false; }
|
||||
|
||||
/** Clears the width constrains set. */
|
||||
virtual void clear_width_constrain() {}
|
||||
|
||||
/**
|
||||
* Does the widget have a vertical scrollbar.
|
||||
*
|
||||
|
|
|
@ -360,6 +360,10 @@ SDL_Rect twindow::get_client_rect() const
|
|||
|
||||
void twindow::layout()
|
||||
{
|
||||
boost::intrusive_ptr<const twindow_definition::tresolution> conf =
|
||||
boost::dynamic_pointer_cast<const twindow_definition::tresolution>(config());
|
||||
assert(conf);
|
||||
|
||||
if(automatic_placement_) {
|
||||
|
||||
log_scope2(gui_layout, "Window: Recalculate size");
|
||||
|
@ -368,6 +372,20 @@ void twindow::layout()
|
|||
DBG_G_L << "twindow " << __func__ << ": " << size << " screen size "
|
||||
<< settings::screen_width << ',' << settings::screen_height << ".\n";
|
||||
|
||||
// Too wide and we can wrap, try that.
|
||||
if(static_cast<size_t>(size.x) > settings::screen_width && can_wrap()) {
|
||||
DBG_G_L << "twindow " << __func__ << ": start wrapping.\n";
|
||||
if(set_width_constrain(settings::screen_width
|
||||
- conf->left_border - conf->right_border)) {
|
||||
|
||||
size = get_best_size();
|
||||
DBG_G_L << "twindow " << __func__
|
||||
<< ": After wrapping : " << size << ".\n";
|
||||
} else {
|
||||
DBG_G_L << "twindow " << __func__ << ": wrapping failed.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// If too big try it gracefully.
|
||||
if(static_cast<size_t>(size.x) > settings::screen_width
|
||||
|| static_cast<size_t>(size.y) > settings::screen_height) {
|
||||
|
@ -424,6 +442,8 @@ void twindow::layout()
|
|||
x_(variables), y_(variables), w_(variables), h_(variables)));
|
||||
}
|
||||
|
||||
// Make sure the contrains are cleared, they might be partially set.
|
||||
clear_width_constrain();
|
||||
need_layout_ = false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue