Add a new offsetted drawing method.

The code is mainly copy pasted from the current drawing code, but adds
some helpers as well.

The code is used to experiment with a different approach of the
implementation of a listbox.
This commit is contained in:
Mark de Wever 2012-04-28 19:16:10 +00:00
parent a85b712e2a
commit 8f945cf235
22 changed files with 406 additions and 15 deletions

View file

@ -124,6 +124,17 @@ void tcontainer_::impl_draw_children(surface& frame_buffer)
grid_.draw_children(frame_buffer);
}
void tcontainer_::impl_draw_children(
surface& frame_buffer
, int x_offset
, int y_offset)
{
assert(get_visible() == twidget::VISIBLE
&& grid_.get_visible() == twidget::VISIBLE);
grid_.draw_children(frame_buffer, x_offset, y_offset);
}
void tcontainer_::layout_children()
{
grid_.layout_children();

View file

@ -107,6 +107,7 @@ public:
/** Inherited from twidget. */
void impl_draw_children(surface& frame_buffer);
void impl_draw_children(surface& frame_buffer, int x_offset, int y_offset);
protected:

View file

@ -335,6 +335,21 @@ void tcontrol::impl_draw_background(surface& frame_buffer)
canvas(get_state()).blit(frame_buffer, get_rect());
}
void tcontrol::impl_draw_background(
surface& frame_buffer
, int x_offset
, int y_offset)
{
DBG_GUI_D << LOG_HEADER
<< " label '" << debug_truncate(label_)
<< "' size " << get_rect()
<< ".\n";
canvas(get_state()).blit(
frame_buffer
, calculate_blitting_rectangle(x_offset, y_offset));
}
tpoint tcontrol::get_best_text_size(
const tpoint& minimum_size
, const tpoint& maximum_size) const

View file

@ -318,9 +318,19 @@ public:
protected:
/** Inherited from twidget. */
void impl_draw_background(surface& frame_buffer);
void impl_draw_background(
surface& frame_buffer
, int x_offset
, int y_offset);
/** Inherited from twidget. */
void impl_draw_foreground(surface& /*frame_buffer*/) { /* do nothing */ }
void impl_draw_foreground(
surface& /*frame_buffer*/
, int /*x_offset*/
, int /*y_offset*/)
{ /* do nothing */ }
private:
/**

View file

@ -259,6 +259,10 @@ public:
/** Inherited from twidget. */
virtual void impl_draw_children(surface& frame_buffer) = 0;
virtual void impl_draw_children(
surface& frame_buffer
, int x_offset
, int y_offset) = 0;
protected:

View file

@ -811,6 +811,18 @@ public:
}
}
/** Inherited from tgenerator_. */
void impl_draw_children(surface& frame_buffer, int x_offset, int y_offset)
{
assert(this->get_visible() == twidget::VISIBLE);
foreach(titem* item, items_) {
if(item->grid.get_visible() == twidget::VISIBLE && item->shown) {
item->grid.draw_children(frame_buffer, x_offset, y_offset);
}
}
}
/** Inherited from tgenerator_. */
void child_populate_dirty_list(twindow& caller,
const std::vector<twidget*>& call_stack)

View file

@ -956,6 +956,45 @@ void tgrid::impl_draw_children(surface& frame_buffer)
}
}
void tgrid::impl_draw_children(
surface& frame_buffer
, int x_offset
, int y_offset)
{
/*
* The call to SDL_PumpEvents seems a bit like black magic.
* With the call the resizing doesn't seem to lose resize events.
* But when added the queue still only contains one resize event and the
* internal SDL queue doesn't seem to overflow (rarely more than 50 pending
* events).
* Without the call when resizing larger a black area of remains, this is
* the area not used for resizing the screen, this call `fixes' that.
*/
SDL_PumpEvents();
assert(get_visible() == twidget::VISIBLE);
set_dirty(false);
foreach(tchild& child, children_) {
twidget* widget = child.widget();
assert(widget);
if(widget->get_visible() != twidget::VISIBLE) {
continue;
}
if(widget->get_drawing_action() == twidget::NOT_DRAWN) {
continue;
}
widget->draw_background(frame_buffer, x_offset, y_offset);
widget->draw_children(frame_buffer, x_offset, y_offset);
widget->draw_foreground(frame_buffer, x_offset, y_offset);
widget->set_dirty(false);
}
}
unsigned tgrid_implementation::row_request_reduce_height(tgrid& grid,
const unsigned row, const unsigned maximum_height)
{

View file

@ -430,6 +430,7 @@ private:
/** Inherited from twidget. */
void impl_draw_children(surface& frame_buffer);
void impl_draw_children(surface& frame_buffer, int x_offset, int y_offset);
};

View file

@ -232,6 +232,31 @@ void tminimap::impl_draw_background(surface& frame_buffer)
}
}
void tminimap::impl_draw_background(
surface& frame_buffer
, int x_offset
, int y_offset)
{
if (!terrain_) return;
assert(terrain_);
DBG_GUI_D << LOG_HEADER
<< " size " << calculate_blitting_rectangle(x_offset, y_offset)
<< ".\n";
if(map_data_.empty()) {
return;
}
SDL_Rect rect = calculate_blitting_rectangle(x_offset, y_offset);
assert(rect.w > 0 && rect.h > 0);
const ::surface surf = get_image(rect.w, rect.h);
if(surf) {
sdl_blit(surf, NULL, frame_buffer, &rect);
}
}
const std::string& tminimap::get_control_type() const
{
static const std::string type = "minimap";

View file

@ -87,6 +87,10 @@ private:
/** Inherited from tcontrol. */
void impl_draw_background(surface& frame_buffer);
void impl_draw_background(
surface& frame_buffer
, int x_offset
, int y_offset);
/** Inherited from tcontrol. */
const std::string& get_control_type() const;

View file

@ -160,6 +160,10 @@ private:
* Since we're always empty the draw does nothing.
*/
void impl_draw_background(surface& /*frame_buffer*/) {}
void impl_draw_background(
surface& /*frame_buffer*/
, int /*x_offset*/
, int /*y_offset*/) {}
/** Inherited from tcontrol. */
const std::string& get_control_type() const;

View file

@ -55,11 +55,35 @@ void tpanel::impl_draw_background(surface& frame_buffer)
canvas(0).blit(frame_buffer, get_rect());
}
void tpanel::impl_draw_background(
surface& frame_buffer
, int x_offset
, int y_offset)
{
DBG_GUI_D << LOG_HEADER
<< " size " << get_rect()
<< ".\n";
canvas(0).blit(
frame_buffer
, calculate_blitting_rectangle(x_offset, y_offset));
}
void tpanel::impl_draw_foreground(surface& frame_buffer)
{
canvas(1).blit(frame_buffer, get_rect());
}
void tpanel::impl_draw_foreground(
surface& frame_buffer
, int x_offset
, int y_offset)
{
canvas(1).blit(
frame_buffer
, calculate_blitting_rectangle(x_offset, y_offset));
}
tpoint tpanel::border_space() const
{
boost::intrusive_ptr<const tpanel_definition::tresolution> conf =

View file

@ -61,9 +61,17 @@ private:
/** Inherited from tcontrol. */
void impl_draw_background(surface& frame_buffer);
void impl_draw_background(
surface& frame_buffer
, int x_offset
, int y_offset);
/** Inherited from tcontrol. */
void impl_draw_foreground(surface& frame_buffer);
void impl_draw_foreground(
surface& frame_buffer
, int x_offset
, int y_offset);
/** Inherited from tcontrol. */
const std::string& get_control_type() const;

View file

@ -758,6 +758,20 @@ void tscrollbar_container::impl_draw_children(surface& frame_buffer)
content_grid_->draw_children(frame_buffer);
}
void tscrollbar_container::impl_draw_children(
surface& frame_buffer
, int x_offset
, int y_offset)
{
assert(get_visible() == twidget::VISIBLE
&& content_grid_->get_visible() == twidget::VISIBLE);
// Inherited.
tcontainer_::impl_draw_children(frame_buffer, x_offset, y_offset);
content_grid_->draw_children(frame_buffer, x_offset, y_offset);
}
void tscrollbar_container::layout_children()
{
// Inherited.

View file

@ -455,6 +455,7 @@ private:
/** Inherited from tcontainer_. */
void impl_draw_children(surface& frame_buffer);
void impl_draw_children(surface& frame_buffer, int x_offset, int y_offset);
/** Inherited from tcontainer_. */
void child_populate_dirty_list(twindow& caller,

View file

@ -78,6 +78,10 @@ private:
* Since we're always empty the draw does nothing.
*/
void impl_draw_background(surface& /*frame_buffer*/) {}
void impl_draw_background(
surface& /*frame_buffer*/
, int /*x_offset*/
, int /*y_offset*/) {}
/** Inherited from tcontrol. */
const std::string& get_control_type() const;

View file

@ -160,6 +160,14 @@ private:
tcontrol::impl_draw_background(frame_buffer);
}
/** Inherited from tpanel. */
void impl_draw_background(surface& frame_buffer, int x_offset, int y_offset)
{
// We don't have a fore and background and need to draw depending on
// our state, like a control. So we use the controls drawing method.
tcontrol::impl_draw_background(frame_buffer, x_offset, y_offset);
}
/** Inherited from tpanel. */
void impl_draw_foreground(surface& frame_buffer)
{
@ -168,6 +176,14 @@ private:
tcontrol::impl_draw_foreground(frame_buffer);
}
/** Inherited from tpanel. */
void impl_draw_foreground(surface& frame_buffer, int x_offset, int y_offset)
{
// We don't have a fore and background and need to draw depending on
// our state, like a control. So we use the controls drawing method.
tcontrol::impl_draw_foreground(frame_buffer, x_offset, y_offset);
}
/** Inherited from tpanel. */
const std::string& get_control_type() const;

View file

@ -496,6 +496,22 @@ void ttree_view_node::impl_draw_children(surface& frame_buffer)
}
}
void ttree_view_node::impl_draw_children(
surface& frame_buffer
, int x_offset
, int y_offset)
{
grid_.draw_children(frame_buffer, x_offset, y_offset);
if(is_folded()) {
return;
}
foreach(ttree_view_node& node, children_) {
node.impl_draw_children(frame_buffer, x_offset, y_offset);
}
}
void ttree_view_node::signal_handler_left_button_click(
const event::tevent event)
{

View file

@ -251,6 +251,7 @@ private:
void set_visible_area(const SDL_Rect& area);
void impl_draw_children(surface& frame_buffer);
void impl_draw_children(surface& frame_buffer, int x_offset, int y_offset);
// FIXME rename to icon
void signal_handler_left_button_click(const event::tevent event);

View file

@ -251,6 +251,26 @@ void twidget::set_visible_area(const SDL_Rect& area)
}
}
SDL_Rect twidget::calculate_blitting_rectangle(
const int x_offset
, const int y_offset)
{
SDL_Rect result = get_rect();
result.x += x_offset;
result.y += y_offset;
return result;
}
SDL_Rect twidget::calculate_clipping_rectangle(
const int x_offset
, const int y_offset)
{
SDL_Rect result = clip_rect_;
result.x += x_offset;
result.y += y_offset;
return result;
}
void twidget::draw_background(surface& frame_buffer)
{
assert(visible_ == VISIBLE);
@ -265,6 +285,23 @@ void twidget::draw_background(surface& frame_buffer)
}
}
void twidget::draw_background(surface& frame_buffer, int x_offset, int y_offset)
{
assert(visible_ == VISIBLE);
if(drawing_action_ == PARTLY_DRAWN) {
const SDL_Rect clipping_rectangle =
calculate_clipping_rectangle(x_offset, y_offset);
clip_rect_setter clip(frame_buffer, &clipping_rectangle);
draw_debug_border(frame_buffer, x_offset, y_offset);
impl_draw_background(frame_buffer, x_offset, y_offset);
} else {
draw_debug_border(frame_buffer, x_offset, y_offset);
impl_draw_background(frame_buffer, x_offset, y_offset);
}
}
void twidget::draw_children(surface& frame_buffer)
{
assert(visible_ == VISIBLE);
@ -277,6 +314,21 @@ void twidget::draw_children(surface& frame_buffer)
}
}
void twidget::draw_children(surface& frame_buffer, int x_offset, int y_offset)
{
assert(visible_ == VISIBLE);
if(drawing_action_ == PARTLY_DRAWN) {
const SDL_Rect clipping_rectangle =
calculate_clipping_rectangle(x_offset, y_offset);
clip_rect_setter clip(frame_buffer, &clipping_rectangle);
impl_draw_children(frame_buffer, x_offset, y_offset);
} else {
impl_draw_children(frame_buffer, x_offset, y_offset);
}
}
void twidget::draw_foreground(surface& frame_buffer)
{
assert(visible_ == VISIBLE);
@ -289,6 +341,21 @@ void twidget::draw_foreground(surface& frame_buffer)
}
}
void twidget::draw_foreground(surface& frame_buffer, int x_offset, int y_offset)
{
assert(visible_ == VISIBLE);
if(drawing_action_ == PARTLY_DRAWN) {
const SDL_Rect clipping_rectangle =
calculate_clipping_rectangle(x_offset, y_offset);
clip_rect_setter clip(frame_buffer, &clipping_rectangle);
impl_draw_foreground(frame_buffer, x_offset, y_offset);
} else {
impl_draw_foreground(frame_buffer, x_offset, y_offset);
}
}
#ifndef LOW_MEM
void twidget::draw_debug_border(surface& frame_buffer)
{
@ -310,6 +377,31 @@ void twidget::draw_debug_border(surface& frame_buffer)
assert(false);
}
}
void twidget::draw_debug_border(
surface& frame_buffer
, int x_offset
, int y_offset)
{
SDL_Rect r = drawing_action_ == PARTLY_DRAWN
? calculate_clipping_rectangle(x_offset, y_offset)
: calculate_blitting_rectangle(x_offset, y_offset);
switch(debug_border_mode_) {
case 0:
/* DO NOTHING */
break;
case 1:
draw_rectangle(r.x, r.y, r.w, r.h
, debug_border_color_, frame_buffer);
break;
case 2:
sdl_fill_rect(frame_buffer, &r, debug_border_color_);
break;
default:
assert(false);
}
}
#endif
bool twidget::is_at(const tpoint& coordinate, const bool must_be_active) const

View file

@ -452,6 +452,37 @@ public:
}
#endif
/**
* Calculates the blitting rectangle of the widget.
*
* The blitting rectangle is to entire widget rectangle, but offsetted for
* drawing position.
*
* @param x_offset The x offset when drawn.
* @param y_offset The y offset when drawn.
*
* @returns The drawing rectangle.
*/
SDL_Rect calculate_blitting_rectangle(
const int x_offset
, const int y_offset);
/**
* Calculates the clipping rectangle of the widget.
*
* The clipping rectangle is used then the @ref drawing_action_ is
* @ref PARTLY_DRAWN. Since the drawing can be offsetted it also needs
* offset paramters.
*
* @param x_offset The x offset when drawn.
* @param y_offset The y offset when drawn.
*
* @returns The clipping rectangle.
*/
SDL_Rect calculate_clipping_rectangle(
const int x_offset
, const int y_offset);
/**
* Draws the background of a widget.
*
@ -459,8 +490,11 @@ public:
* this function.
*
* @param frame_buffer The surface to draw upon.
* @param x_offset The x offset in the @p frame_buffer to draw.
* @param y_offset The y offset in the @p frame_buffer to draw.
*/
void draw_background(surface& frame_buffer);
void draw_background(surface& frame_buffer, int x_offset, int y_offset);
/**
* Draws the children of a widget.
@ -471,8 +505,11 @@ public:
* this function.
*
* @param frame_buffer The surface to draw upon.
* @param x_offset The x offset in the @p frame_buffer to draw.
* @param y_offset The y offset in the @p frame_buffer to draw.
*/
void draw_children(surface& frame_buffer);
void draw_children(surface& frame_buffer, int x_offset, int y_offset);
/**
* Draws the foreground of the widgt.
@ -484,8 +521,11 @@ public:
* this function.
*
* @param frame_buffer The surface to draw upon.
* @param x_offset The x offset in the @p frame_buffer to draw.
* @param y_offset The y offset in the @p frame_buffer to draw.
*/
void draw_foreground(surface& frame_buffer);
void draw_foreground(surface& frame_buffer, int x_offset, int y_offset);
/**
* Allows a widget to update its children.
@ -638,8 +678,10 @@ private:
unsigned debug_border_color_;
void draw_debug_border(surface& frame_buffer);
void draw_debug_border(surface& frame_buffer, int x_offset, int y_offset);
#else
void draw_debug_border(surface&) {}
void draw_debug_border(surface&, int, int) {}
#endif
#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
@ -654,12 +696,30 @@ private:
/** See draw_background(). */
virtual void impl_draw_background(surface& /*frame_buffer*/) {}
virtual void impl_draw_background(
surface& /*frame_buffer*/
, int /*x_offset*/
, int /*y_offset*/)
{
}
/** See draw_children. */
virtual void impl_draw_children(surface& /*frame_buffer*/) {}
virtual void impl_draw_children(
surface& /*frame_buffer*/
, int /*x_offset*/
, int /*y_offset*/)
{
}
/** See draw_foreground. */
virtual void impl_draw_foreground(surface& /*frame_buffer*/) {}
virtual void impl_draw_foreground(
surface& /*frame_buffer*/
, int /*x_offset*/
, int /*y_offset*/)
{
}
/** (Will be) inherited from event::tdispatcher. */
virtual bool is_at(const tpoint& coordinate) const

View file

@ -693,7 +693,14 @@ void twindow::draw()
// Now find the widgets that are dirty.
std::vector<twidget*> call_stack;
populate_dirty_list(*this, call_stack);
if(!new_widgets) {
populate_dirty_list(*this, call_stack);
} else {
/* Force to update and redraw the entire screen */
dirty_list_.clear();
dirty_list_.push_back(std::vector<twidget*>(1, this));
update_rect(screen_area());
}
}
if(dirty_list_.empty()) {
@ -774,24 +781,46 @@ void twindow::draw()
SDL_Rect rect = get_rect();
sdl_blit(restorer_, 0, frame_buffer, &rect);
// Background.
for(std::vector<twidget*>::iterator itor = item.begin();
itor != item.end(); ++itor) {
if(new_widgets) {
// Background.
for(std::vector<twidget*>::iterator itor = item.begin();
itor != item.end(); ++itor) {
(**itor).draw_background(frame_buffer);
}
(**itor).draw_background(frame_buffer, 0, 0);
}
// Children.
if(!item.empty()) {
item.back()->draw_children(frame_buffer);
}
// Children.
if(!item.empty()) {
item.back()->draw_children(frame_buffer, 0, 0);
}
// Foreground.
for(std::vector<twidget*>::reverse_iterator ritor = item.rbegin();
ritor != item.rend(); ++ritor) {
// Foreground.
for(std::vector<twidget*>::reverse_iterator ritor = item.rbegin();
ritor != item.rend(); ++ritor) {
(**ritor).draw_foreground(frame_buffer);
(**ritor).set_dirty(false);
(**ritor).draw_foreground(frame_buffer, 0, 0);
(**ritor).set_dirty(false);
}
} else {
// Background.
for(std::vector<twidget*>::iterator itor = item.begin();
itor != item.end(); ++itor) {
(**itor).draw_background(frame_buffer);
}
// Children.
if(!item.empty()) {
item.back()->draw_children(frame_buffer);
}
// Foreground.
for(std::vector<twidget*>::reverse_iterator ritor = item.rbegin();
ritor != item.rend(); ++ritor) {
(**ritor).draw_foreground(frame_buffer);
(**ritor).set_dirty(false);
}
}
update_rect(dirty_rect);