More refactoring, grids can now be nested properly...

...allowing better placement of widgets.
This commit is contained in:
Mark de Wever 2008-04-09 15:31:07 +00:00
parent 2563ef1135
commit b6b02b26e2
5 changed files with 317 additions and 170 deletions

View file

@ -12,80 +12,101 @@
left = "center"
width = 600
height = 150
height = 200
window_definition = "default"
[grid]
[row]
scale = 1
[column]
scale = 0
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
label_definition = "default"
label = _ "name :"
[/label]
[/column]
#fixme rename scale to grow_factor
scale = 0
[column]
scale = 1
border = "all"
border_size = 5
horizontal_grow = "true"
[text_box]
id = "host_name"
edit_box_definition = "default"
size_text = _ "very long text which might need to fit"
label = ""
[/text_box]
[/column]
[/row]
[row]
scale = 0
[column]
horizontal_alignment = "left"
horizontal_grow = "true" #FIXME should not be needed
[label]
# Dummy; empty cells aren't allowed (yet).
label_definition = "default"
label = ""
label = _ "Connect to Server"
[/label]
[/column]
[/row]
[row]
scale = 0
[column]
scale = 1
border = "all"
border_size = 5
horizontal_alignment = "right"
horizontal_alignment = "left"
horizontal_grow = "true" #FIXME should not be needed
[label]
label_definition = "default"
[button]
# just show how the default looks.
button_definition = "default"
label = _ "You will now connect to a server to download add-ons."
[/label]
size_text = _ "manage addons"
label = _ "manage addons"
[/column]
# we define the return value manually instead of being
# linked to the id. Not sure whether that's the best
# solution, but it's nice as proof-of-concept.
return_value = 2
[/button]
[/row]
[row]
scale = 1
[column]
scale = 1
horizontal_grow = "true"
[grid]
[row]
scale = 1
[column]
scale = 0
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
label_definition = "default"
label = _ "name :"
[/label]
[/column]
[column]
scale = 1
border = "all"
border_size = 5
horizontal_grow = "true"
[text_box]
id = "host_name"
edit_box_definition = "default"
size_text = _ "very long text which might need to fit"
label = ""
[/text_box]
[/column]
[/row]
[/grid]
[/column]
@ -95,31 +116,82 @@
scale = 0
[column]
border = "all"
border_size = 5
horizontal_alignment = "right"
scale = 1
horizontal_grow = "true"
[button]
id = "ok"
button_definition = "drawn"
[grid]
size_text = _ "connect"
label = _ "connect"
[/button]
[row]
scale = 0
[/column]
[column]
[column]
border = "all"
border_size = 5
horizontal_alignment = "right"
[label]
# Dummy; empty cells aren't allowed (yet).
label_definition = "default"
[button]
id = "cancel"
button_definition = "drawn"
label = ""
[/label]
label = _ "cancel"
[/button]
[/column]
[column]
border = "all"
border_size = 5
horizontal_alignment = "right"
[button]
# just show how the default looks.
button_definition = "default"
size_text = _ "manage addons"
label = _ "manage addons"
# we define the return value manually instead of being
# linked to the id. Not sure whether that's the best
# solution, but it's nice as proof-of-concept.
return_value = 2
[/button]
[/column]
[/row]
[row]
scale = 0
[column]
border = "all"
border_size = 5
horizontal_alignment = "right"
[button]
id = "ok"
button_definition = "drawn"
size_text = _ "connect"
label = _ "connect"
[/button]
[/column]
[column]
border = "all"
border_size = 5
horizontal_alignment = "right"
[button]
id = "cancel"
button_definition = "drawn"
label = _ "cancel"
[/button]
[/column]
[/row]
[/grid]
[/column]

View file

@ -214,6 +214,8 @@ tpoint tgrid::get_best_size() const
void tgrid::set_size(const SDL_Rect& rect)
{
log_scope2(gui, "Grid: set size");
twidget::set_size(rect);
const tpoint orig(rect.x, rect.y);
@ -240,48 +242,50 @@ void tgrid::set_size(const SDL_Rect& rect)
col_width_ = best_col_width_;
// expand it.
const unsigned w = size.x - best_size.x;
unsigned w_size = std::accumulate(col_scaling_.begin(), col_scaling_.end(), 0);
DBG_G << "Grid: extra width " << w << " will be divided amount " << w_size << " units in " << cols_ << " columns.\n";
if(size.x > best_size.x) {
const unsigned w = size.x - best_size.x;
unsigned w_size = std::accumulate(col_scaling_.begin(), col_scaling_.end(), 0);
DBG_G << "Grid: extra width " << w << " will be divided amount " << w_size << " units in " << cols_ << " columns.\n";
if(w_size == 0) {
// If all sizes are 0 reset them to 1
foreach(unsigned& val, col_scaling_) {
val = 1;
if(w_size == 0) {
// If all sizes are 0 reset them to 1
foreach(unsigned& val, col_scaling_) {
val = 1;
}
w_size = cols_;
}
w_size = cols_;
}
// We might have a bit 'extra' if the division doesn't fix exactly
// but we ignore that part for now.
const unsigned w_normal = w / w_size;
for(unsigned i = 0; i < cols_; ++i) {
col_width_[i] += w_normal * col_scaling_[i];
DBG_G << "Grid: column " << i << " with scale factor "
<< col_scaling_[i] << " set width to " << col_width_[i] << ".\n";
}
const unsigned h = size.y - best_size.y;
unsigned h_size = std::accumulate(row_scaling_.begin(), row_scaling_.end(), 0);
DBG_G << "Grid: extra height " << h << " will be divided amount " << h_size << " units in " << rows_ << " rows.\n";
if(h_size == 0) {
// If all sizes are 0 reset them to 1
foreach(unsigned& val, row_scaling_) {
val = 1;
// We might have a bit 'extra' if the division doesn't fix exactly
// but we ignore that part for now.
const unsigned w_normal = w / w_size;
for(unsigned i = 0; i < cols_; ++i) {
col_width_[i] += w_normal * col_scaling_[i];
DBG_G << "Grid: column " << i << " with scale factor "
<< col_scaling_[i] << " set width to " << col_width_[i] << ".\n";
}
h_size = rows_;
}
// We might have a bit 'extra' if the division doesn't fix exactly
// but we ignore that part for now.
const unsigned h_normal = h / h_size;
for(unsigned i = 0; i < rows_; ++i) {
row_height_[i] += h_normal * row_scaling_[i];
DBG_G << "Grid: row " << i << " with scale factor "
<< row_scaling_[i] << " set height to " << row_height_[i] << ".\n";
}
if(size.y > best_size.y) {
const unsigned h = size.y - best_size.y;
unsigned h_size = std::accumulate(row_scaling_.begin(), row_scaling_.end(), 0);
DBG_G << "Grid: extra height " << h << " will be divided amount " << h_size << " units in " << rows_ << " rows.\n";
if(h_size == 0) {
// If all sizes are 0 reset them to 1
foreach(unsigned& val, row_scaling_) {
val = 1;
}
h_size = rows_;
}
// We might have a bit 'extra' if the division doesn't fix exactly
// but we ignore that part for now.
const unsigned h_normal = h / h_size;
for(unsigned i = 0; i < rows_; ++i) {
row_height_[i] += h_normal * row_scaling_[i];
DBG_G << "Grid: row " << i << " with scale factor "
<< row_scaling_[i] << " set height to " << row_height_[i] << ".\n";
}
}
layout(orig);
return;
@ -344,6 +348,21 @@ twidget* tgrid::get_widget_by_id(const std::string& id)
return twidget::get_widget_by_id(id);
}
void tgrid::draw(surface& surface)
{
for(iterator itor = begin(); itor != end(); ++itor) {
if(! *itor || !itor->dirty()) {
continue;
}
log_scope2(gui_draw, "Grid: draw child.");
itor->draw(surface);
}
set_dirty(false);
}
void tgrid::load_config()
{
for(std::vector<tchild>::iterator itor = children_.begin();

View file

@ -102,7 +102,7 @@ public:
twidget* get_widget_by_id(const std::string& id);
//! Inherited from twidget.
void draw(surface& surface) { /* FIXME IMPLEMENT */ }
void draw(surface& surface);
//! Inherited from twidget.
void load_config();
@ -298,6 +298,10 @@ public:
void set_col_scaling(const unsigned col, const unsigned scale)
{ grid_.set_col_scaling(col, scale); }
//! Inherited from twidget.
//FIXME we also need to load our own config
void draw(surface& surface) { grid_.draw(surface); }
//! Inherited from twidget.
//FIXME we also need to load our own config
void load_config() { grid_.load_config(); }

View file

@ -49,54 +49,90 @@
namespace gui2 {
struct tbuilder_button : public tbuilder_widget
struct tbuilder_control : public tbuilder_widget
{
private:
tbuilder_control();
public:
tbuilder_control(const config& cfg);
//! Parameters for the control.
std::string id;
std::string definition;
t_string label;
};
struct tbuilder_button : public tbuilder_control
{
private:
tbuilder_button();
public:
tbuilder_button(const config& cfg) :
tbuilder_widget(cfg),
retval_(0)
{ read_extra(cfg); }
tbuilder_button(const config& cfg);
twidget* build () const;
private:
int retval_;
//! After reading the general part in the constructor read extra data.
void read_extra(const config& cfg);
};
struct tbuilder_label : public tbuilder_widget
struct tbuilder_label : public tbuilder_control
{
private:
tbuilder_label();
public:
tbuilder_label(const config& cfg) :
tbuilder_widget(cfg)
tbuilder_control(cfg)
{}
twidget* build () const;
};
struct tbuilder_text_box : public tbuilder_widget
struct tbuilder_text_box : public tbuilder_control
{
private:
tbuilder_text_box();
public:
tbuilder_text_box(const config& cfg) :
tbuilder_widget(cfg)
tbuilder_control(cfg)
{}
twidget* build () const;
};
struct tbuilder_grid : public tbuilder_widget
{
private:
tbuilder_grid();
public:
tbuilder_grid(const config& cfg);
unsigned rows;
unsigned cols;
//! The scale factor for the rows / columns.
std::vector<unsigned> row_scale;
std::vector<unsigned> col_scale;
//! The flags per grid cell.
std::vector<unsigned> flags;
//! The border size per grid cell.
std::vector<unsigned> border_size;
//! The widgets per grid cell.
std::vector<tbuilder_widget_ptr> widgets;
twidget* build () const;
private:
//! After reading the general part in the constructor read extra data.
void read_extra(const config& cfg);
};
twindow build(CVideo& video, const std::string& type)
{
@ -107,21 +143,23 @@ twindow build(CVideo& video, const std::string& type)
twindow window(video, 100, 100, definition->width, definition->height); // FIXME use proper origin
// twindow window(video, 0, 0, definition->width, definition->height); // FIXME use proper origin
const unsigned rows = definition->grid.rows;
const unsigned cols = definition->grid.cols;
log_scope2(gui, "Window builder: building grid for window");
const unsigned rows = definition->grid->rows;
const unsigned cols = definition->grid->cols;
window.set_rows_cols(rows, cols);
for(unsigned x = 0; x < rows; ++x) {
window.set_row_scaling(x, definition->grid.row_scale[x]);
window.set_row_scaling(x, definition->grid->row_scale[x]);
for(unsigned y = 0; y < cols; ++y) {
if(x == 0) {
window.set_col_scaling(y, definition->grid.col_scale[y]);
window.set_col_scaling(y, definition->grid->col_scale[y]);
}
twidget* widget = definition->grid.widgets[x * cols + y]->build();
window.add_child(widget, x, y, definition->grid.flags[x * cols + y], definition->grid.border_size[x * cols + y]);
twidget* widget = definition->grid->widgets[x * cols + y]->build();
window.add_child(widget, x, y, definition->grid->flags[x * cols + y], definition->grid->border_size[x * cols + y]);
}
}
@ -175,7 +213,7 @@ twindow_builder::tresolution::tresolution(const config& cfg) :
width(lexical_cast_default<unsigned>(cfg["width"])),
height(lexical_cast_default<unsigned>(cfg["height"])),
definition(cfg["window_definition"]),
grid(cfg.child("grid"))
grid(0) //new tbuilder_grid(cfg.child("grid")))
{
/*WIKI
* [resolution]
@ -193,6 +231,10 @@ twindow_builder::tresolution::tresolution(const config& cfg) :
* [/resolution]
*/
VALIDATE(cfg.child("grid"), _("No grid defined."));
grid = new tbuilder_grid(*(cfg.child("grid")));
DBG_G_P << "Window builder: parsing resolution "
<< window_width << ',' << window_height << '\n';
@ -255,14 +297,19 @@ static unsigned read_flags(const config& cfg)
return flags;
}
twindow_builder::tresolution::tgrid::tgrid(const config* cfg) :
tbuilder_grid::tbuilder_grid(const config& cfg) :
tbuilder_widget(cfg),
rows(0),
cols(0),
row_scale(),
col_scale(),
flags(),
border_size(),
widgets()
{
VALIDATE(cfg, _("No grid defined."));
log_scope2(gui_parse, "Window builder: parsing a grid");
const config::child_list& row_cfgs = cfg->get_children("row");
const config::child_list& row_cfgs = cfg.get_children("row");
for(std::vector<config*>::const_iterator row_itor = row_cfgs.begin();
row_itor != row_cfgs.end(); ++row_itor) {
@ -284,8 +331,10 @@ twindow_builder::tresolution::tgrid::tgrid(const config* cfg) :
widgets.push_back(new tbuilder_button(*((**col_itor).child("button"))));
} else if((**col_itor).child("label")) {
widgets.push_back(new tbuilder_label(*((**col_itor).child("label"))));
} else if ((**col_itor).child("text_box")) {
} else if((**col_itor).child("text_box")) {
widgets.push_back(new tbuilder_text_box(*((**col_itor).child("text_box"))));
} else if((**col_itor).child("grid")) {
widgets.push_back(new tbuilder_grid(*((**col_itor).child("grid"))));
} else {
assert(false);
}
@ -307,7 +356,8 @@ twindow_builder::tresolution::tgrid::tgrid(const config* cfg) :
<< rows << " rows and " << cols << " columns.\n";
}
tbuilder_widget::tbuilder_widget(const config& cfg) :
tbuilder_control::tbuilder_control(const config& cfg) :
tbuilder_widget(cfg),
id(cfg["id"]),
definition(cfg["button_definition"]),
label(cfg["label"])
@ -318,7 +368,7 @@ tbuilder_widget::tbuilder_widget(const config& cfg) :
}
DBG_G_P << "Window builder: found widget with id '"
DBG_G_P << "Window builder: found control with id '"
<< id << "' and definition '" << definition << "'.\n";
}
@ -342,9 +392,10 @@ twidget* tbuilder_button::build() const
return button;
}
void tbuilder_button::read_extra(const config& cfg)
tbuilder_button::tbuilder_button(const config& cfg) :
tbuilder_control(cfg),
retval_(lexical_cast_default<int>(cfg["return_value"]))
{
retval_ = lexical_cast_default<int>(cfg["return_value"]);
}
twidget* tbuilder_label::build() const
@ -376,5 +427,34 @@ twidget* tbuilder_text_box::build() const
return text_box;
}
twidget* tbuilder_grid::build() const
{
tgrid *grid = new tgrid(0, 0, 0, 0);
grid->set_rows_cols(rows, cols);
log_scope2(gui, "Window builder: building grid");
DBG_G << "Window builder: grid has " << rows << " rows and "
<< cols << " columns.\n";
for(unsigned x = 0; x < rows; ++x) {
grid->set_row_scaling(x, row_scale[x]);
for(unsigned y = 0; y < cols; ++y) {
if(x == 0) {
grid->set_col_scaling(y, col_scale[y]);
}
DBG_G << "Window builder: adding child at " << x << ',' << y << ".\n";
twidget* widget = widgets[x * cols + y]->build();
grid->add_child(widget, x, y, flags[x * cols + y], border_size[x * cols + y]);
}
}
return grid;
}
} // namespace gui2

View file

@ -26,6 +26,7 @@ class CVideo;
namespace gui2 {
class tbuilder_grid;
class twidget;
class twindow;
@ -39,12 +40,8 @@ private:
tbuilder_widget();
public:
tbuilder_widget(const config& cfg);
tbuilder_widget(const config& /*cfg*/) {}
//! Parameters for the widget.
std::string id;
std::string definition;
t_string label;
virtual twidget* build() const = 0;
virtual ~tbuilder_widget() {}
@ -79,33 +76,8 @@ public:
std::string definition;
struct tgrid
{
private:
tgrid();
public:
tgrid(const config* cfg);
unsigned rows;
unsigned cols;
//! The scale factor for the rows / columns.
std::vector<unsigned> row_scale;
std::vector<unsigned> col_scale;
//! The flags per grid cell.
std::vector<unsigned> flags;
//! The border size per grid cell.
std::vector<unsigned> border_size;
//! The widgets per grid cell.
std::vector<tbuilder_widget_ptr> widgets;
};
tgrid grid;
tbuilder_grid* grid;
};
std::vector<tresolution> resolutions;