Hi, this patch adds set(), isEmpty(), and merge() methods to core::Rectangle. These methods are then used to maintain a rectangle that contains all screen areas for which a redraw was requested. When fltk really draws to the screen, the drawing is limited to this area. The most obvious improvement is visible on pages with very large images that take some time to load. While the image is loaded the rest of the page is no longer flickering - at least if there is no other stuff that requests complete redraws. Johannes diff --git a/dw/fltkviewbase.cc b/dw/fltkviewbase.cc --- a/dw/fltkviewbase.cc +++ b/dw/fltkviewbase.cc @@ -42,6 +42,7 @@ FltkViewBase::FltkViewBase (int x, int y canvasWidth = 1; canvasHeight = 1; bgColor = WHITE; + redrawArea.set (0, 0, 0, 0); } FltkViewBase::~FltkViewBase () @@ -50,9 +51,18 @@ FltkViewBase::~FltkViewBase () void FltkViewBase::draw () { - Group::draw (); + int d = damage(); + ::fltk::Rectangle rect (x(), y(), w(), h()); - ::fltk::Rectangle rect (x(), y(), w(), h()); + //Group::draw (); + + if (d == DAMAGE_VALUE) { + ::fltk::push_clip( + translateCanvasXToViewX(redrawArea.x), + translateCanvasYToViewY(redrawArea.y), + redrawArea.width, + redrawArea.height); + } /* fltk-clipping seems not to use widget coordinates */ ::fltk::intersect_with_clip(rect); @@ -68,6 +78,12 @@ void FltkViewBase::draw () area.width = rect.w(); area.height = rect.h(); theLayout->expose (this, &area); + + if (d == DAMAGE_VALUE) { + ::fltk::pop_clip(); + } + + redrawArea.set (0, 0, 0, 0); } core::ButtonState getDwButtonState () @@ -223,9 +239,9 @@ void FltkViewBase::finishDrawing (core:: void FltkViewBase::queueDraw (core::Rectangle *area) { - /** \bug Inefficient */ + redrawArea.merge (area); - redraw (DAMAGE_EXPOSE); + redraw (DAMAGE_VALUE); } void FltkViewBase::queueDrawTotal () diff --git a/dw/fltkviewbase.hh b/dw/fltkviewbase.hh --- a/dw/fltkviewbase.hh +++ b/dw/fltkviewbase.hh @@ -14,6 +14,7 @@ class FltkViewBase: public FltkView, pub { private: int bgColor; + core::Rectangle redrawArea; protected: core::Layout *theLayout; diff --git a/dw/types.cc b/dw/types.cc --- a/dw/types.cc +++ b/dw/types.cc @@ -27,10 +27,7 @@ namespace core { Rectangle::Rectangle (int x, int y, int width, int height) { - this->x = x; - this->y = y; - this->width = width; - this->height = height; + set (x, y, width, height); } /** @@ -111,6 +108,35 @@ bool Rectangle::isPointWithin (int x, in x >= this->x && y >= this->y && x < this->x + width && y < this->y + height; } + +/** + * \brief Enlarge the rectangle so that it also includes otherRect. + * If a rectangle has zero size, it is ignored. + */ +void Rectangle::merge (Rectangle *otherRect) +{ + if (otherRect->isEmpty()) { + return; + } + + if (isEmpty()) { + x = otherRect->x; + y = otherRect->y; + width = otherRect->width; + height = otherRect->height; + return; + } + + width = ::misc::max(x + width, otherRect->x + otherRect->width); + height = ::misc::max(y + height, otherRect->y + otherRect->height); + + x = ::misc::min(x, otherRect->x); + y = ::misc::min(y, otherRect->y); + + width -= x; + height -= y; +} + // ---------------------------------------------------------------------- diff --git a/dw/types.hh b/dw/types.hh --- a/dw/types.hh +++ b/dw/types.hh @@ -68,9 +68,18 @@ public: inline Rectangle () { } Rectangle (int x, int y, int width, int height); + void set (int x, int y, int w, int h) { + this->x = x; + this->y = y; + this->width = w; + this->height = h; + } + bool intersectsWith (Rectangle *otherRect, Rectangle *dest); + void merge (Rectangle *otherRect); bool isSubsetOf (Rectangle *otherRect); bool isPointWithin (int x, int y); + bool isEmpty() {return width == 0 && height == 0;}; }; /**