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" left = "center"
width = 600 width = 600
height = 150 height = 200
window_definition = "default" window_definition = "default"
[grid] [grid]
[row] [row]
scale = 1 #fixme rename scale to grow_factor
scale = 0
[column]
scale = 0
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
label_definition = "default"
label = _ "name :"
[/label]
[/column]
[column] [column]
scale = 1 scale = 1
border = "all" border = "all"
border_size = 5 border_size = 5
horizontal_grow = "true" horizontal_alignment = "left"
horizontal_grow = "true" #FIXME should not be needed
[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]
[label] [label]
# Dummy; empty cells aren't allowed (yet).
label_definition = "default" label_definition = "default"
label = "" label = _ "Connect to Server"
[/label] [/label]
[/column] [/column]
[/row]
[row]
scale = 0
[column] [column]
scale = 1
border = "all" border = "all"
border_size = 5 border_size = 5
horizontal_alignment = "right" horizontal_alignment = "left"
horizontal_grow = "true" #FIXME should not be needed
[label]
label_definition = "default"
[button] label = _ "You will now connect to a server to download add-ons."
# just show how the default looks. [/label]
button_definition = "default"
size_text = _ "manage addons" [/column]
label = _ "manage addons"
# we define the return value manually instead of being [/row]
# linked to the id. Not sure whether that's the best
# solution, but it's nice as proof-of-concept. [row]
return_value = 2 scale = 1
[/button]
[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] [/column]
@ -93,33 +114,84 @@
[row] [row]
scale = 0 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] [column]
border = "all" scale = 1
border_size = 5 horizontal_grow = "true"
horizontal_alignment = "right"
[button] [grid]
id = "cancel"
button_definition = "drawn"
label = _ "cancel" [row]
[/button] scale = 0
[column]
[label]
# Dummy; empty cells aren't allowed (yet).
label_definition = "default"
label = ""
[/label]
[/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] [/column]

View file

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

View file

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

View file

@ -49,54 +49,90 @@
namespace gui2 { 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: private:
tbuilder_button(); tbuilder_button();
public: public:
tbuilder_button(const config& cfg) : tbuilder_button(const config& cfg);
tbuilder_widget(cfg),
retval_(0)
{ read_extra(cfg); }
twidget* build () const; twidget* build () const;
private: private:
int retval_; 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: private:
tbuilder_label(); tbuilder_label();
public: public:
tbuilder_label(const config& cfg) : tbuilder_label(const config& cfg) :
tbuilder_widget(cfg) tbuilder_control(cfg)
{} {}
twidget* build () const; twidget* build () const;
}; };
struct tbuilder_text_box : public tbuilder_widget struct tbuilder_text_box : public tbuilder_control
{ {
private: private:
tbuilder_text_box(); tbuilder_text_box();
public: public:
tbuilder_text_box(const config& cfg) : tbuilder_text_box(const config& cfg) :
tbuilder_widget(cfg) tbuilder_control(cfg)
{} {}
twidget* build () const; 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) 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, 100, 100, definition->width, definition->height); // FIXME use proper origin
// twindow window(video, 0, 0, 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; log_scope2(gui, "Window builder: building grid for window");
const unsigned cols = definition->grid.cols;
const unsigned rows = definition->grid->rows;
const unsigned cols = definition->grid->cols;
window.set_rows_cols(rows, cols); window.set_rows_cols(rows, cols);
for(unsigned x = 0; x < rows; ++x) { 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) { for(unsigned y = 0; y < cols; ++y) {
if(x == 0) { 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(); 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]); 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"])), width(lexical_cast_default<unsigned>(cfg["width"])),
height(lexical_cast_default<unsigned>(cfg["height"])), height(lexical_cast_default<unsigned>(cfg["height"])),
definition(cfg["window_definition"]), definition(cfg["window_definition"]),
grid(cfg.child("grid")) grid(0) //new tbuilder_grid(cfg.child("grid")))
{ {
/*WIKI /*WIKI
* [resolution] * [resolution]
@ -193,6 +231,10 @@ twindow_builder::tresolution::tresolution(const config& cfg) :
* [/resolution] * [/resolution]
*/ */
VALIDATE(cfg.child("grid"), _("No grid defined."));
grid = new tbuilder_grid(*(cfg.child("grid")));
DBG_G_P << "Window builder: parsing resolution " DBG_G_P << "Window builder: parsing resolution "
<< window_width << ',' << window_height << '\n'; << window_width << ',' << window_height << '\n';
@ -255,14 +297,19 @@ static unsigned read_flags(const config& cfg)
return flags; return flags;
} }
twindow_builder::tresolution::tgrid::tgrid(const config* cfg) : tbuilder_grid::tbuilder_grid(const config& cfg) :
tbuilder_widget(cfg),
rows(0), rows(0),
cols(0), cols(0),
row_scale(),
col_scale(),
flags(),
border_size(),
widgets() 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(); for(std::vector<config*>::const_iterator row_itor = row_cfgs.begin();
row_itor != row_cfgs.end(); ++row_itor) { 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")))); widgets.push_back(new tbuilder_button(*((**col_itor).child("button"))));
} else if((**col_itor).child("label")) { } else if((**col_itor).child("label")) {
widgets.push_back(new tbuilder_label(*((**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")))); 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 { } else {
assert(false); assert(false);
} }
@ -307,7 +356,8 @@ twindow_builder::tresolution::tgrid::tgrid(const config* cfg) :
<< rows << " rows and " << cols << " columns.\n"; << 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"]), id(cfg["id"]),
definition(cfg["button_definition"]), definition(cfg["button_definition"]),
label(cfg["label"]) 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"; << id << "' and definition '" << definition << "'.\n";
} }
@ -342,9 +392,10 @@ twidget* tbuilder_button::build() const
return button; 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 twidget* tbuilder_label::build() const
@ -376,5 +427,34 @@ twidget* tbuilder_text_box::build() const
return text_box; 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 } // namespace gui2

View file

@ -26,6 +26,7 @@ class CVideo;
namespace gui2 { namespace gui2 {
class tbuilder_grid;
class twidget; class twidget;
class twindow; class twindow;
@ -39,12 +40,8 @@ private:
tbuilder_widget(); tbuilder_widget();
public: 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 twidget* build() const = 0;
virtual ~tbuilder_widget() {} virtual ~tbuilder_widget() {}
@ -79,33 +76,8 @@ public:
std::string definition; 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; std::vector<tresolution> resolutions;