Author: mordante
Date: Mon Aug 18 17:35:54 2008
New Revision: 28712
URL: http://svn.gna.org/viewcvs/wesnoth?rev=28712&view=rev
Log:
Make the drawing be event driven instead of a delayed loop.
Modified:
trunk/src/events.hpp
trunk/src/gui/widgets/event_handler.cpp
trunk/src/gui/widgets/window.cpp
trunk/src/gui/widgets/window.hpp
Modified: trunk/src/events.hpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/events.hpp?rev=28712&r1=28711&r2=28712&view=diff
==============================================================================
--- trunk/src/events.hpp (original)
+++ trunk/src/events.hpp Mon Aug 18 17:35:54 2008
@@ -22,6 +22,7 @@
#define DOUBLE_CLICK_EVENT SDL_USEREVENT
#define HOVER_EVENT (SDL_USEREVENT + 1)
#define HOVER_REMOVE_POPUP_EVENT (SDL_USEREVENT + 2)
+#define DRAW_EVENT (SDL_USEREVENT + 3)
namespace events
{
Modified: trunk/src/gui/widgets/event_handler.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/gui/widgets/event_handler.cpp?rev=28712&r1=28711&r2=28712&view=diff
==============================================================================
--- trunk/src/gui/widgets/event_handler.cpp (original)
+++ trunk/src/gui/widgets/event_handler.cpp Mon Aug 18 17:35:54 2008
@@ -228,6 +228,10 @@
case HOVER_REMOVE_POPUP_EVENT:
remove_tooltip();
remove_help_popup();
+ break;
+
+ case DRAW_EVENT:
+ get_window().draw();
break;
case SDL_KEYDOWN:
Modified: trunk/src/gui/widgets/window.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/gui/widgets/window.cpp?rev=28712&r1=28711&r2=28712&view=diff
==============================================================================
--- trunk/src/gui/widgets/window.cpp (original)
+++ trunk/src/gui/widgets/window.cpp Mon Aug 18 17:35:54 2008
@@ -49,6 +49,45 @@
namespace gui2{
+
+namespace {
+
+/**
+ * The interval between draw events.
+ *
+ * When the window is shown this value is set, the callback function always
+ * uses this value instead of the parameter send, that way the window can stop
+ * drawing when it wants.
+ */
+static int draw_interval = 0;
+
+/**
+ * SDL_AddTimer() callback for the draw event.
+ *
+ * When this callback is called it pushes a new draw event in the event queue.
+ *
+ * @returns The new timer interval, 0 to stop.
+ */
+static Uint32 draw_timer(Uint32, void*)
+{
+ DBG_G_E << "Pushing draw event in queue.\n";
+
+ SDL_Event event;
+ SDL_UserEvent data;
+
+ data.type = DRAW_EVENT;
+ data.code = 0;
+ data.data1 = NULL;
+ data.data2 = NULL;
+
+ event.type = DRAW_EVENT;
+ event.user = data;
+
+ SDL_PushEvent(&event);
+ return draw_interval;
+}
+
+} // namespace
twindow::twindow(CVideo& video,
tformula<unsigned>x,
@@ -66,6 +105,11 @@
retval_(0),
owner_(0),
need_layout_(true),
+ resized_(true),
+ suspend_drawing_(true),
+ top_level_(false),
+ window_(),
+ restorer_(),
tooltip_(),
help_popup_(),
automatic_placement_(automatic_placement),
@@ -115,62 +159,155 @@
assert(status_ == NEW);
- // We cut a piece of the screen and use that, that way all coordinates
- // are relative to the window.
- SDL_Rect rect = get_rect();
- surface restorer = get_surface_portion(video_.getSurface(), rect);
- surface screen;
+ top_level_ = (draw_interval == 0);
+ if(top_level_) {
+ draw_interval = 30;
+ SDL_AddTimer(draw_interval, draw_timer, NULL);
+ }
+
+ suspend_drawing_ = false;
// Start our loop drawing will happen here as well.
for(status_ = SHOWING; status_ != REQUEST_CLOSE; ) {
process_events();
-
- if(status_ == REQUEST_CLOSE) {
- break;
- }
-
- if(is_dirty() || need_layout_) {
- if(need_layout_) {
- screen = make_neutral_surface(restorer);
- }
- draw(screen);
- }
-
- // delay until it's our frame see display.ccp code for how to
do that
+ // Add a delay so we don't keep spinning if there's no event.
SDL_Delay(10);
- flip();
+ }
+
+ suspend_drawing_ = true;
+
+ if(top_level_) {
+ draw_interval = 0;
}
// restore area
if(restore) {
- rect = get_rect();
- SDL_BlitSurface(restorer, 0, video_.getSurface(), &rect);
+ SDL_Rect rect = get_rect();
+ SDL_BlitSurface(restorer_, 0, video_.getSurface(), &rect);
update_rect(get_rect());
- flip();
}
return retval_;
}
-/*
-void twindow::layout(const SDL_Rect& position)
-{
- DBG_G << "Window: layout area " << position.x
- << ',' << position.y << " x " << position.w
- << ',' << position.h << ".\n";
-
- set_client_size(position);
- need_layout_ = false;
-}
-*/
+
+void twindow::draw()
+{
+ // NOTE since we're single threaded there's no need to create a critical
+ // section in this drawing routine.
+
+ // Prohibited from drawing?
+ if(suspend_drawing_) {
+ return;
+ }
+
+ // Drawing not required?
+ if(!resized_ && !need_layout_ && !is_dirty()) {
+ return;
+ }
+
+ surface frame_buffer = get_video_surface();
+
+ const bool draw_background = resized_ || need_layout_;
+
+ if(resized_) {
+ // Restore old surface.
+ if(restorer_) {
+ SDL_Rect rect = get_rect();
+ SDL_BlitSurface(restorer_, 0, frame_buffer, &rect);
+ }
+
+ layout();
+
+ // Get new surface
+ SDL_Rect rect = get_rect();
+ restorer_ = get_surface_portion(video_.getSurface(), rect);
+ window_ = make_neutral_surface(restorer_); // should be copy
surface...
+
+ resized_ = false;
+ }
+ assert(window_ && restorer_);
+
+ if(need_layout_) {
+ layout();
+ }
+
+ if(draw_background) {
+ canvas(0).draw();
+ blit_surface(canvas(0).surf(), 0, window_, 0);
+ }
+
+ for(tgrid::iterator itor = begin(); itor != end(); ++itor) {
+ if(! *itor || !itor->is_dirty()) {
+ continue;
+ }
+
+ log_scope2(gui_draw, "Window: draw child.");
+
+ itor->draw(window_, false, false);
+ }
+
+ if(tooltip_.is_dirty()) {
+ tooltip_.draw(window_);
+ }
+
+ if(help_popup_.is_dirty()) {
+ help_popup_.draw(window_);
+ }
+
+ // Floating label hack
+ font::draw_floating_labels(frame_buffer);
+
+ SDL_Rect rect = get_rect();
+ SDL_BlitSurface(window_, 0, frame_buffer, &rect);
+ update_rect(get_rect());
+ set_dirty(false);
+
+ cursor::draw(frame_buffer);
+ video_.flip();
+ cursor::undraw(frame_buffer);
+ // Floating hack part 2.
+ font::undraw_floating_labels(frame_buffer);
+}
+
void twindow::window_resize(tevent_handler&,
const unsigned new_width, const unsigned new_height)
{
settings::screen_width = new_width;
settings::screen_height = new_height;
- need_layout_ = true;
-}
-
-void twindow::recalculate_size()
+ resized_ = true;
+}
+
+void twindow::key_press(tevent_handler& /*event_handler*/, bool& handled,
+ SDLKey key, SDLMod /*modifier*/, Uint16 /*unicode*/)
+{
+ if(key == SDLK_KP_ENTER || key == SDLK_RETURN) {
+ set_retval(OK);
+ handled = true;
+ } else if(key == SDLK_ESCAPE) {
+ set_retval(CANCEL);
+ handled = true;
+ }
+}
+
+SDL_Rect twindow::get_client_rect() const
+{
+ boost::intrusive_ptr<const twindow_definition::tresolution> conf =
+ boost::dynamic_pointer_cast<const
twindow_definition::tresolution>(config());
+ assert(conf);
+
+ SDL_Rect result = get_rect();
+ result.x = conf->left_border;
+ result.y = conf->top_border;
+ result.w -= conf->left_border + conf->right_border;
+ result.h -= conf->top_border + conf->bottom_border;
+
+ // FIXME validate for an available client area.
+
+ return result;
+
+}
+
+void twindow::layout()
{
if(automatic_placement_) {
@@ -227,110 +364,15 @@
set_size(create_rect(position, size));
} else {
- update_size();
- }
-}
-
-void twindow::key_press(tevent_handler& /*event_handler*/, bool& handled,
- SDLKey key, SDLMod /*modifier*/, Uint16 /*unicode*/)
-{
- if(key == SDLK_KP_ENTER || key == SDLK_RETURN) {
- set_retval(OK);
- handled = true;
- } else if(key == SDLK_ESCAPE) {
- set_retval(CANCEL);
- handled = true;
- }
-}
-
-SDL_Rect twindow::get_client_rect() const
-{
- boost::intrusive_ptr<const twindow_definition::tresolution> conf =
- boost::dynamic_pointer_cast<const
twindow_definition::tresolution>(config());
- assert(conf);
-
- SDL_Rect result = get_rect();
- result.x = conf->left_border;
- result.y = conf->top_border;
- result.w -= conf->left_border + conf->right_border;
- result.h -= conf->top_border + conf->bottom_border;
-
- // FIXME validate for an available client area.
-
- return result;
-
-}
-
-void twindow::draw(surface& surf, const bool force,
- const bool invalidate_background)
-{
- // Hack to make the floating labels work again in the editor, it does
fail
- // in the test scenario since the window there is big and transparent.
- // Since it's really needed for the editor this hack does suffice.
- const surface frameBuffer = get_video_surface();
- font::draw_floating_labels(frameBuffer);
-
- const bool draw_foreground = need_layout_ || force;
- if(need_layout_) {
- DBG_G << "Window: layout client area.\n";
-// layout(get_client_rect());
-// Instead of layout() we need to clear the flag.
- need_layout_ = false;
-
- canvas(0).draw();
- blit_surface(canvas(0).surf(), 0, surf, 0);
- }
-
- for(tgrid::iterator itor = begin(); itor != end(); ++itor) {
- if(! *itor || !itor->is_dirty()) {
- continue;
- }
-
- log_scope2(gui_draw, "Window: draw child.");
-
- itor->draw(surf, force, invalidate_background);
- }
- if(draw_foreground) {
- canvas(1).draw();
- blit_surface(canvas(1).surf(), 0, surf, 0);
- }
- if(tooltip_.is_dirty()) {
- tooltip_.draw(surf);
- }
- if(help_popup_.is_dirty()) {
- help_popup_.draw(surf);
- }
-
- SDL_Rect rect = get_rect();
- SDL_BlitSurface(surf, 0, video_.getSurface(), &rect);
- update_rect(get_rect());
- set_dirty(false);
-
-}
-
-void twindow::update_size()
-{
- game_logic::map_formula_callable variables;
- variables.add("screen_width", variant(settings::screen_width));
- variables.add("screen_height", variant(settings::screen_height));
-
- set_size(::create_rect(
- x_(variables), y_(variables), w_(variables), h_(variables)));
-
-}
-
-void twindow::flip()
-{
- // fixme we need to add the option to either call
- // video_.flip() or display.flip()
-
- const surface frameBuffer = get_video_surface();
-
- cursor::draw(frameBuffer);
- video_.flip();
- cursor::undraw(frameBuffer);
- // Floating hack part 2.
- font::undraw_floating_labels(frameBuffer);
+ game_logic::map_formula_callable variables;
+ variables.add("screen_width", variant(settings::screen_width));
+ variables.add("screen_height",
variant(settings::screen_height));
+
+ set_size(::create_rect(
+ x_(variables), y_(variables), w_(variables),
h_(variables)));
+ }
+
+ need_layout_ = false;
}
void twindow::do_show_tooltip(const tpoint& location, const t_string& tooltip)
@@ -411,5 +453,11 @@
help_popup_.set_visible();
}
+void twindow::draw(surface& /*surf*/, const bool /*force*/,
+ const bool /*invalidate_background*/)
+{
+ assert(false);
+}
+
} // namespace gui2
Modified: trunk/src/gui/widgets/window.hpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/gui/widgets/window.hpp?rev=28712&r1=28711&r2=28712&view=diff
==============================================================================
--- trunk/src/gui/widgets/window.hpp (original)
+++ trunk/src/gui/widgets/window.hpp Mon Aug 18 17:35:54 2008
@@ -46,6 +46,8 @@
class twindow : public tpanel, public tevent_handler
{
public:
+ // FIXME this should be removed as well, but easy for the outside world
to keep it a bit longer...
+ void recalculate_size() { /*NOP*/ }
twindow(CVideo& video,
tformula<unsigned>x,
tformula<unsigned>y,
@@ -99,13 +101,15 @@
*/
int show(const bool restore = true, void* flip_function = NULL);
- /**
- * Layouts the window.
- *
- * @todo This function has no purpose at the moment, but also the resize
- * code doesn't work so might be required later.
- */
-// void layout(const SDL_Rect& position);
+ /**
+ * Draws the window.
+ *
+ * This routine draws the window if needed, it's called from the event
+ * handler. This is done by a drawing event. When a window is shown it
+ * manages an SDL timer which fires a drawing event every X
milliseconds,
+ * that event calls this routine. Don't call it manually.
+ */
+ void draw();
/** The status of the window. */
enum tstatus{
@@ -163,7 +167,7 @@
* window. To be used after creation and after modification or items
which
* can have different sizes eg listboxes.
*/
- void recalculate_size();
+ void invalidate_layout() { need_layout_ = true; }
/** Inherited from tevent_executor. */
void key_press(tevent_handler& event_handler, bool& handled,
@@ -207,10 +211,6 @@
/** Inherited from tpanel. */
SDL_Rect get_client_rect() const;
- /** Inherited from tpanel. */
- void draw(surface& surface, const bool force = false,
- const bool invalidate_background = false);
-
/***** ***** ***** setters / getters for members ***** ****** *****/
/**
@@ -241,6 +241,31 @@
/** When set the form needs a full layout redraw cycle. */
bool need_layout_;
+ /**
+ * When set the window is resized.
+ *
+ * This invalidates the layout background etc. So everything should be
+ * recalcalated.
+ */
+ bool resized_;
+
+ /** Avoid drawing the window. */
+ bool suspend_drawing_;
+
+ /**
+ * The first window shown is the toplevel window.
+ *
+ * The toplevel window is the one that starts and stops the drawing
timer.
+ * It's set when the timer is 0 when the window is shown.
+ */
+ bool top_level_;
+
+ /** The surface containing the window. */
+ surface window_;
+
+ /** When the window closes this surface is used to undraw the window. */
+ surface restorer_;
+
/** Widget for the tooltip. */
ttooltip tooltip_;
@@ -278,16 +303,8 @@
/** The formula to calulate the height of the dialog. */
tformula<unsigned>h_;
- /**
- * Updates the size for the widget.
- *
- * Then the window isn't placed automatically the tformula for the sizes
- * need to be recalculated and set_size() called with the result.
- */
- void update_size();
-
- /** Does the real updating of the changes on the screen. */
- void flip();
+ /** Layouts the window. */
+ void layout();
/** Inherited from tevent_handler. */
void do_show_tooltip(const tpoint& location, const t_string& tooltip);
@@ -304,6 +321,14 @@
/** Inherited from tcontrol. */
const std::string& get_control_type() const
{ static const std::string type = "window"; return type; }
+
+ /**
+ * Inherited from tpanel.
+ *
+ * Don't call this function it's only asserts.
+ */
+ void draw(surface& surface, const bool force = false,
+ const bool invalidate_background = false);
};
} // namespace gui2
_______________________________________________
Wesnoth-commits mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-commits