From 494e7218597a6cd94902b3ae6f827e74b41c00b0 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sun, 12 Mar 2017 17:25:04 +0100 Subject: Fix redrawing of underlying exposed area on Widget moves/resizing. --- plugingui/pixelbuffer.cc | 18 +++++++++--------- plugingui/pixelbuffer.h | 37 +++++++++++++++++++++++------------- plugingui/widget.cc | 49 +++++++++++++++++++++++++++++++++++++++++------- plugingui/window.cc | 43 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 29 deletions(-) (limited to 'plugingui') diff --git a/plugingui/pixelbuffer.cc b/plugingui/pixelbuffer.cc index bbef84c..360ad06 100644 --- a/plugingui/pixelbuffer.cc +++ b/plugingui/pixelbuffer.cc @@ -33,7 +33,7 @@ namespace GUI { -PixelBuffer::PixelBuffer(size_t width, size_t height) +PixelBuffer::PixelBuffer(std::size_t width, std::size_t height) : buf(nullptr) { realloc(width, height); @@ -44,7 +44,7 @@ PixelBuffer::~PixelBuffer() free(buf); } -void PixelBuffer::realloc(size_t width, size_t height) +void PixelBuffer::realloc(std::size_t width, std::size_t height) { free(buf); buf = (unsigned char *)calloc(width * height, 3); @@ -53,7 +53,7 @@ void PixelBuffer::realloc(size_t width, size_t height) } #define PX(k) ((x + y * width) * 3 + k) -void PixelBuffer::setPixel(size_t x, size_t y, +void PixelBuffer::setPixel(std::size_t x, std::size_t y, unsigned char red, unsigned char green, unsigned char blue, @@ -84,7 +84,7 @@ void PixelBuffer::setPixel(size_t x, size_t y, } } -PixelBufferAlpha::PixelBufferAlpha(size_t width, size_t height) +PixelBufferAlpha::PixelBufferAlpha(std::size_t width, std::size_t height) : managed(true) , buf(nullptr) , x(0) @@ -101,7 +101,7 @@ PixelBufferAlpha::~PixelBufferAlpha() } } -void PixelBufferAlpha::realloc(size_t width, size_t height) +void PixelBufferAlpha::realloc(std::size_t width, std::size_t height) { free(buf); buf = (unsigned char *)calloc(width * height, 4); @@ -111,7 +111,7 @@ void PixelBufferAlpha::realloc(size_t width, size_t height) #undef PX #define PX(k) ((x + y * width) * 4 + k) -void PixelBufferAlpha::setPixel(size_t x, size_t y, +void PixelBufferAlpha::setPixel(std::size_t x, std::size_t y, unsigned char red, unsigned char green, unsigned char blue, @@ -135,7 +135,7 @@ static inline void getAlpha(unsigned char _a, unsigned char _b, b *= (1 - a); } -void PixelBufferAlpha::addPixel(size_t x, size_t y, +void PixelBufferAlpha::addPixel(std::size_t x, std::size_t y, unsigned char red, unsigned char green, unsigned char blue, @@ -172,13 +172,13 @@ void PixelBufferAlpha::addPixel(size_t x, size_t y, } } -void PixelBufferAlpha::addPixel(size_t x, size_t y, const Colour& c) +void PixelBufferAlpha::addPixel(std::size_t x, std::size_t y, const Colour& c) { addPixel(x, y, c.red() * 255, c.green() * 255, c.blue() * 255, c.alpha() * 255); } -void PixelBufferAlpha::pixel(size_t x, size_t y, +void PixelBufferAlpha::pixel(std::size_t x, std::size_t y, unsigned char* red, unsigned char* green, unsigned char* blue, diff --git a/plugingui/pixelbuffer.h b/plugingui/pixelbuffer.h index 94c5496..71869a0 100644 --- a/plugingui/pixelbuffer.h +++ b/plugingui/pixelbuffer.h @@ -33,47 +33,49 @@ namespace GUI { -class PixelBuffer { +class PixelBuffer +{ public: - PixelBuffer(size_t width, size_t height); + PixelBuffer(std::size_t width, std::size_t height); ~PixelBuffer(); - void realloc(size_t width, size_t height); + void realloc(std::size_t width, std::size_t height); - void setPixel(size_t x, size_t y, + void setPixel(std::size_t x, std::size_t y, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha); unsigned char* buf{nullptr}; - size_t width{0}; - size_t height{0}; + std::size_t width{0}; + std::size_t height{0}; }; -class PixelBufferAlpha { +class PixelBufferAlpha +{ public: PixelBufferAlpha() = default; - PixelBufferAlpha(size_t width, size_t height); + PixelBufferAlpha(std::size_t width, std::size_t height); ~PixelBufferAlpha(); - void realloc(size_t width, size_t height); + void realloc(std::size_t width, std::size_t height); - void setPixel(size_t x, size_t y, + void setPixel(std::size_t x, std::size_t y, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha); - void addPixel(size_t x, size_t y, + void addPixel(std::size_t x, std::size_t y, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha); - void addPixel(size_t x, size_t y, const Colour& c); + void addPixel(std::size_t x, std::size_t y, const Colour& c); - void pixel(size_t x, size_t y, + void pixel(std::size_t x, std::size_t y, unsigned char* red, unsigned char* green, unsigned char* blue, @@ -86,6 +88,15 @@ public: int x{0}; int y{0}; bool dirty{true}; + bool visible{true}; + + // Add optional dirty rect that this pixelbuffer took up since it was last + // rendered. Make sure to update this list on resize and/or move. + std::size_t last_width{0}; + std::size_t last_height{0}; + int last_x{0}; + int last_y{0}; + bool has_last{false}; }; } // GUI:: diff --git a/plugingui/widget.cc b/plugingui/widget.cc index 7d92a22..00acfbf 100644 --- a/plugingui/widget.cc +++ b/plugingui/widget.cc @@ -42,6 +42,9 @@ Widget::Widget(Widget* parent) parent->addChild(this); _window = parent->window(); } + + pixbuf.x = translateToWindowX(); + pixbuf.y = translateToWindowY(); } Widget::~Widget() @@ -64,12 +67,14 @@ void Widget::hide() void Widget::setVisible(bool visible) { - _visible = visible; - - if(visible) + if(_visible == visible) { - redraw(); + return; } + + _visible = visible; + pixbuf.visible = visible; + redraw(); } bool Widget::visible() const @@ -130,7 +135,20 @@ void Widget::resize(std::size_t width, std::size_t height) _width = width; _height = height; + + // Store old size/position in pixelbuffer for rendering invalidation. + if(!pixbuf.has_last) + { + pixbuf.last_width = pixbuf.width; + pixbuf.last_height = pixbuf.height; + pixbuf.last_x = pixbuf.x; + pixbuf.last_y = pixbuf.y; + pixbuf.has_last = true; + } + pixbuf.realloc(width, height); + pixbuf.x = translateToWindowX(); + pixbuf.y = translateToWindowY(); redraw(); sizeChangeNotifier(width, height); } @@ -145,6 +163,20 @@ void Widget::move(int x, int y) _x = x; _y = y; + + // Store old size/position in pixelbuffer for rendering invalidation. + if(!pixbuf.has_last) + { + pixbuf.last_width = pixbuf.width; + pixbuf.last_height = pixbuf.height; + pixbuf.last_x = pixbuf.x; + pixbuf.last_y = pixbuf.y; + pixbuf.has_last = true; + } + + //pixbuf.x = translateToWindowX(); + //pixbuf.y = translateToWindowY(); + positionChangeNotifier(x, y); } @@ -216,11 +248,14 @@ std::vector Widget::getPixelBuffers() dirty = false; } - pixelBuffers.push_back(&pixbuf); + if(pixbuf.dirty || visible()) + { + pixelBuffers.push_back(&pixbuf); + } - for(auto child : children) + if(visible()) { - if(child->visible()) + for(auto child : children) { auto childPixelBuffers = child->getPixelBuffers(); pixelBuffers.insert(pixelBuffers.end(), diff --git a/plugingui/window.cc b/plugingui/window.cc index d4046c2..8bc5c62 100644 --- a/plugingui/window.cc +++ b/plugingui/window.cc @@ -262,10 +262,50 @@ bool Window::updateBuffer() }; } } + + if(pixel_buffer->has_last) + { + auto x1 = (std::size_t)pixel_buffer->last_x; + auto x2 = (std::size_t)(pixel_buffer->last_x + pixel_buffer->last_width); + auto y1 = (std::size_t)pixel_buffer->last_y; + auto y2 = (std::size_t)(pixel_buffer->last_y + pixel_buffer->last_height); + + pixel_buffer->has_last = false; + if(!has_dirty_rect) + { + // Insert this area: + dirty_rect = {x1, y1, x2, y2}; + has_dirty_rect = true; + } + else + { + // Expand existing area: + auto x1_0 = dirty_rect.x1; + auto y1_0 = dirty_rect.y1; + auto x2_0 = dirty_rect.x2; + auto y2_0 = dirty_rect.y2; + dirty_rect = { + (x1_0 < x1) ? x1_0 : x1, + (y1_0 < y1) ? y1_0 : y1, + (x2_0 > x2) ? x2_0 : x2, + (y2_0 > y2) ? y2_0 : y2 + }; + } + } + } + + if(!has_dirty_rect) + { + return false; } for(auto& pixel_buffer : pixel_buffers) { + if(!pixel_buffer->visible) + { + continue; + } + int update_width = pixel_buffer->width; int update_height = pixel_buffer->height; @@ -308,6 +348,9 @@ bool Window::updateBuffer() } } + dirty_rect.x2 = std::min(wpixbuf.width, dirty_rect.x2); + dirty_rect.y2 = std::min(wpixbuf.height, dirty_rect.y2); + native->redraw(dirty_rect); needs_redraw = false; -- cgit v1.2.3