[[drawing code fixes]]

* Rewrote the drawing code to be able to force a redraw and to invalidate the
  background. This fixes the ttoggle_panel redraw problems.

* Removed the no_redraw label hack

* Updated the WIKI comment blocks to fix some typos and add some forgotten info.
This commit is contained in:
Mark de Wever 2008-06-23 16:32:37 +00:00
parent fd802000dd
commit e8b1280a7b
20 changed files with 123 additions and 106 deletions

View file

@ -72,64 +72,3 @@
{LABEL_DEFINITION "title" "label used for titles" {FONT_SIZE_NORMAL__TITLE} {FONT_COLOUR_TITLE} "bold"}
#undef LABEL_DEFINITION
###
### Temporary class to avoid the redraw problem for labels in a ttoggle_panel
### This hack can be removed once the the redraw problem is fixed
###
[label_definition]
id = no_redraw
description = "temp hack to avoid redraw problems when used in a toggle panel."
[resolution]
min_width = 0
min_height = 0
default_width = 0
default_height = 0
max_width = 0
max_height = 0
text_font_size = 16
[state_enabled]
[draw]
[text]
x = 0
y = {TEXT_V_CENTRE}
w = "(text_width)"
h = "(text_height)"
font_size = 16
colour = {FONT_COLOUR_ENABLED}
text = "(text)"
[/text]
[/draw]
[/state_enabled]
[state_disabled]
[draw]
[text]
x = 0
y = {TEXT_V_CENTRE}
w = "(text_width)"
h = "(text_height)"
font_size = 16
colour = {FONT_COLOUR_ENABLED}
text = "(text)"
[/text]
[/draw]
[/state_disabled]
[/resolution]
[/label_definition]

View file

@ -126,7 +126,7 @@
[label]
id = "name"
definition = "no_redraw"
definition = "default"
[/label]
@ -143,7 +143,7 @@
[label]
id = "address"
definition = "no_redraw"
definition = "default"
[/label]

View file

@ -71,12 +71,16 @@ tpoint tcontainer_::get_best_size() const
return size;
}
void tcontainer_::draw(surface& surface)
void tcontainer_::draw(surface& surface, const bool force,
const bool invalidate_background)
{
// Inherited.
tcontrol::draw(surface);
tcontrol::draw(surface, force, invalidate_background);
grid_.draw(surface);
const bool redraw_background = invalidate_background || has_background_changed();
set_background_changed(false);
grid_.draw(surface, force, redraw_background);
}
} // namespace gui2

View file

@ -31,7 +31,8 @@ class tcontainer_ : public tcontrol
{
public:
tcontainer_(const unsigned canvas_count) :
tcontrol(canvas_count)
tcontrol(canvas_count),
background_changed_(true)
{
grid_.set_parent(this);
}
@ -63,7 +64,8 @@ public:
tpoint get_best_size() const;
/** Inherited from tcontrol. */
void draw(surface& surface);
void draw(surface& surface, const bool force = false,
const bool invalidate_background = false);
/** Inherited from tcontrol. */
twidget* find_widget(const tpoint& coordinate, const bool must_be_active)
@ -131,6 +133,10 @@ protected:
const tgrid& grid() const { return grid_; }
tgrid& grid() { return grid_; }
void set_background_changed(const bool changed = true)
{ background_changed_ = changed; }
bool has_background_changed() const { return background_changed_; }
private:
@ -139,6 +145,13 @@ private:
/** Returns the space used by the border. */
virtual tpoint border_space() const { return tpoint(0, 0); }
/**
* If the background has been changed the next draw cycle needs to do a full
* redraw and also tell the child items to invalidate their background. This
* overrides the 'invalidate_background' parameter send to draw().
*/
bool background_changed_;
};
} // namespace gui2

View file

@ -143,10 +143,18 @@ tpoint tcontrol::get_maximum_size() const
return tpoint(config_->max_width, config_->max_height);
}
void tcontrol::draw(surface& surface)
void tcontrol::draw(surface& surface, const bool force,
const bool invalidate_background)
{
assert(config_);
if(!dirty() && !force && !invalidate_background) {
return;
}
if(invalidate_background) {
restorer_ = 0;
}
set_dirty(false);
SDL_Rect rect = get_rect();

View file

@ -101,7 +101,8 @@ public:
tpoint get_maximum_size() const;
/** Inherited from twidget. */
void draw(surface& surface);
void draw(surface& surface, const bool force = false,
const bool invalidate_background = false);
/** Inherited from twidget. */
twidget* find_widget(const tpoint& coordinate, const bool must_be_active)

View file

@ -201,21 +201,15 @@ bool tgrid::has_vertical_scrollbar() const
return twidget::has_vertical_scrollbar();
}
void tgrid::draw(surface& surface)
void tgrid::draw(surface& surface, const bool force,
const bool invalidate_background)
{
for(iterator itor = begin(); itor != end(); ++itor) {
/**
* @todo temporary disabled until the nested drawing for
* ttoggle_panel works with this flag set.
*/
/*
if(! *itor || !itor->dirty()) {
continue;
}
*/
log_scope2(gui_draw, "Grid: draw child.");
itor->draw(surface);
assert(*itor);
itor->draw(surface, force, invalidate_background);
}
set_dirty(false);

View file

@ -167,7 +167,8 @@ public:
bool has_vertical_scrollbar() const;
/** Inherited from twidget. */
void draw(surface& surface);
void draw(surface& surface, const bool force = false,
const bool invalidate_background = false);
/** Inherited from twidget. */
twidget* find_widget(const tpoint& coordinate, const bool must_be_active);

View file

@ -234,10 +234,15 @@ tpoint tlistbox::get_best_size() const
return tcontainer_::get_best_size();
}
void tlistbox::draw(surface& surface)
void tlistbox::draw(surface& surface, const bool force,
const bool invalidate_background)
{
// Inherit.
tcontainer_::draw(surface);
tcontainer_::draw(surface, force, invalidate_background);
if(invalidate_background) {
list_background_.assign(NULL);
}
// Handle our full redraw for the spacer area.
if(!list_background_) {
@ -252,9 +257,7 @@ void tlistbox::draw(surface& surface)
trow& row = rows_[i + scrollbar()->get_item_position()];
assert(row.grid());
if(row.grid()->dirty()) {
row.grid()->draw(row.canvas());
}
row.grid()->draw(row.canvas(), force, invalidate_background);
// draw background
const SDL_Rect rect = {list_rect_.x, offset, list_rect_.w, row.get_height() };

View file

@ -77,7 +77,8 @@ public:
tpoint get_best_size() const;
/** Inherited from tcontainer. */
void draw(surface& surface);
void draw(surface& surface, const bool force = false,
const bool invalidate_background = false);
/** Inherited from tcontainer. */
void set_size(const SDL_Rect& rect);

View file

@ -53,15 +53,16 @@ SDL_Rect tpanel::get_client_rect() const
return result;
}
void tpanel::draw(surface& surface)
void tpanel::draw(surface& surface, const bool force,
const bool invalidate_background)
{
// Need to preserve the state and inherited draw clear the flag.
const bool is_dirty = dirty();
tcontainer_::draw(surface);
tcontainer_::draw(surface, force, invalidate_background);
// foreground
if(is_dirty) {
if(is_dirty || force) {
SDL_Rect rect = get_rect();
canvas(1).draw(true);
blit_surface(canvas(1).surf(), 0, surface, &rect);

View file

@ -60,7 +60,8 @@ public:
unsigned get_state() const { return 0; }
/** Inherited from tcontrol. */
void draw(surface& surface);
void draw(surface& surface, const bool force = false,
const bool invalidate_background = false);
/** Inherited from tcontainer_. */
bool has_vertical_scrollbar() const { return false; }
@ -73,6 +74,7 @@ private:
/** Inherited from tcontainer_. */
tpoint border_space() const;
};
} // namespace gui2

View file

@ -622,7 +622,7 @@ tpanel_definition::tresolution::tresolution(const config& cfg) :
* grid. A panel is always enabled and can't be disabled. Instead it uses the
* states as layers to draw on.
*
* The resolution for a text box also contains the following keys:
* The resolution for a panel also contains the following keys:
* @start_table = config
* top_border (unsigned = 0) The size which isn't used for the client area.
* bottom_border (unsigned = 0) The size which isn't used for the client area.
@ -763,7 +763,8 @@ ttoggle_panel_definition::tresolution::tresolution(const config& cfg) :
top_border(lexical_cast_default<unsigned>(cfg["top_border"])),
bottom_border(lexical_cast_default<unsigned>(cfg["bottom_border"])),
left_border(lexical_cast_default<unsigned>(cfg["left_border"])),
right_border(lexical_cast_default<unsigned>(cfg["right_border"]))
right_border(lexical_cast_default<unsigned>(cfg["right_border"])),
state_change_full_redraw(utils::string_bool(cfg["state_change_full_redraw"], true))
{
/*WIKI
* @page = GUIToolkitWML
@ -771,7 +772,28 @@ ttoggle_panel_definition::tresolution::tresolution(const config& cfg) :
*
* == Toogle panel ==
*
* The definition of a toggle panel.
* The definition of a toggle panel. A toggle panel is like a toggle button, but
* instead of being a button it's a panel. This means it can hold multiple child
* items.
*
* The resolution for a toggle panel also contains the following keys:
* @start_table = config
* top_border (unsigned = 0) The size which isn't used for the client area.
* bottom_border (unsigned = 0) The size which isn't used for the client area.
* left_border (unsigned = 0) The size which isn't used for the client area.
* right_border (unsigned = 0) The size which isn't used for the client area.
* state_change_full_redraw (bool = true)
* When the state of the toggle panel changes
* it can change it's background. If that
* happens all child items need to redraw
* themselves and need to modify their cached
* background. Set this variable to true if
* that's the case, in case of doubt set it to
* true, it might give a small performance hit
* but the drawing will always be correct.
* @end_table
*
* The following layers exist:
*
* The following states exist:
* * state_enabled, the panel is enabled and not selected.

View file

@ -214,6 +214,8 @@ struct ttoggle_panel_definition : public tcontrol_definition
unsigned left_border;
unsigned right_border;
bool state_change_full_redraw;
};
};

View file

@ -55,7 +55,8 @@ public:
*
* Since we're always empty the draw does nothing.
*/
void draw(surface&) {}
void draw(surface& /*surface*/, const bool /*force*/ = false,
const bool /*invalidate_background*/ = false) {}
void set_best_size(const tpoint& best_size) { best_size_ = best_size; }

View file

@ -146,9 +146,19 @@ void ttoggle_panel::set_selected(const bool selected)
void ttoggle_panel::set_state(tstate state)
{
if(state != state_) {
state_ = state;
set_dirty(true);
if(state == state_) {
return;
}
state_ = state;
set_dirty(true);
const ttoggle_panel_definition::tresolution* conf =
dynamic_cast<const ttoggle_panel_definition::tresolution*>(config());
assert(conf);
if(conf->state_change_full_redraw) {
set_background_changed();
}
}

View file

@ -95,7 +95,9 @@ public:
unsigned get_state() const { return state_; }
/** Inherited from tpanel. */
void draw(surface& surface) { tcontainer_::draw(surface); }
void draw(surface& surface, const bool force = false,
const bool invalidate_background = false)
{ tcontainer_::draw(surface, force, invalidate_background); }
/**
* Inherited from tpanel.

View file

@ -340,8 +340,20 @@ public:
*
* @param surface The surface to draw the widget upon using the
* coordinates and size of the widget.
* @param force Does the widget need to be drawn even if not
* dirty?
* @param invalidate_background
* Some widgets can cache the background in order
* to undraw and redraw themselves if needed. If
* the background changes this 'feature' will
* cause glitches. When this parameter is set the
* widget need to reload the background and use
* that as new undraw cache.
* \n Note if this is set the widget should also
* be redrawn.
*/
virtual void draw(surface& /*surface*/) = 0;
virtual void draw(surface& /*surface*/, const bool /*force*/ = false,
const bool /*invalidate_background*/ = false) = 0;
/***** ***** ***** ***** query ***** ***** ***** *****/

View file

@ -135,10 +135,10 @@ void twindow::layout(const SDL_Rect position)
need_layout_ = false;
}
//! Inherited from tpanel.
void twindow::draw(surface& surface)
void twindow::draw(surface& surface, const bool force,
const bool invalidate_background)
{
const bool draw_foreground = need_layout_;
const bool draw_foreground = need_layout_ || force;
if(need_layout_) {
DBG_G << "Window: layout client area.\n";
layout(get_client_rect());
@ -154,7 +154,7 @@ void twindow::draw(surface& surface)
log_scope2(gui_draw, "Window: draw child.");
itor->draw(surface);
itor->draw(surface, force, invalidate_background);
}
if(draw_foreground) {
canvas(1).draw();

View file

@ -119,7 +119,8 @@ public:
bool full_redraw() const { return false; /* FIXME IMPLEMENT */ }
//! Inherited from tpanel.
void draw(surface& surface);
void draw(surface& surface, const bool force = false,
const bool invalidate_background = false);
//! Gets the coordinates of the client area, for external use the height
//! and the width are the most interesting things.