From cec1d9ea562e3d52c98f1219db5e186943f2f0d6 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sun, 12 Feb 2017 11:07:22 +0100 Subject: Refactor/introduce widget and windiow redraw/dirty mechanism to eradicate unnecessary rendering passes during event handling. --- plugin/drumgizmo_plugin.cc | 5 +- plugingui/button.cc | 10 ++-- plugingui/canvas.h | 8 --- plugingui/checkbox.cc | 12 ++--- plugingui/combobox.cc | 8 +-- plugingui/eventhandler.cc | 92 +++++---------------------------- plugingui/eventhandler.h | 4 -- plugingui/knob.cc | 2 +- plugingui/label.cc | 2 +- plugingui/layout.h | 8 +-- plugingui/led.cc | 2 +- plugingui/lineedit.cc | 6 +-- plugingui/listboxbasic.cc | 14 ++--- plugingui/mainwindow.cc | 6 +-- plugingui/nativewindow.h | 4 -- plugingui/nativewindow_win32.cc | 5 +- plugingui/nativewindow_win32.h | 1 - plugingui/nativewindow_x11.cc | 23 ++------- plugingui/nativewindow_x11.h | 1 - plugingui/painter.cc | 19 +++---- plugingui/painter.h | 14 +++-- plugingui/pixelbuffer.cc | 2 +- plugingui/pixelbuffer.h | 2 +- plugingui/progressbar.cc | 6 +-- plugingui/scrollbar.cc | 6 +-- plugingui/slider.cc | 8 +-- plugingui/textedit.cc | 4 +- plugingui/widget.cc | 97 ++++++++++++++++------------------- plugingui/widget.h | 34 ++++++------ plugingui/window.cc | 111 +++++++++++++++------------------------- plugingui/window.h | 22 ++++---- 31 files changed, 196 insertions(+), 342 deletions(-) diff --git a/plugin/drumgizmo_plugin.cc b/plugin/drumgizmo_plugin.cc index 091492f..3db72c1 100644 --- a/plugin/drumgizmo_plugin.cc +++ b/plugin/drumgizmo_plugin.cc @@ -185,12 +185,11 @@ public: { } - GUI::PixelBufferAlpha& GetPixelBuffer() + // From Canvas: + GUI::PixelBufferAlpha& GetPixelBuffer() override { return pixbuf; } - void beginPaint() {} - void endPaint() {} private: InlinePixelBufferAlpha pixbuf; diff --git a/plugingui/button.cc b/plugingui/button.cc index 29d3deb..fb25390 100644 --- a/plugingui/button.cc +++ b/plugingui/button.cc @@ -57,14 +57,14 @@ void Button::buttonEvent(ButtonEvent* buttonEvent) draw_state = down; button_state = down; in_button = true; - repaintEvent(nullptr); + redraw(); } if(buttonEvent->direction == Direction::up) { draw_state = up; button_state = up; - repaintEvent(nullptr); + redraw(); if(in_button) { clicked(); @@ -110,7 +110,7 @@ void Button::repaintEvent(RepaintEvent* repaintEvent) void Button::setText(const std::string& text) { this->text = text; - repaintEvent(nullptr); + redraw(); } void Button::mouseLeaveEvent() @@ -119,7 +119,7 @@ void Button::mouseLeaveEvent() if(button_state == down) { draw_state = up; - repaintEvent(nullptr); + redraw(); } } @@ -129,7 +129,7 @@ void Button::mouseEnterEvent() if(button_state == down) { draw_state = down; - repaintEvent(nullptr); + redraw(); } } diff --git a/plugingui/canvas.h b/plugingui/canvas.h index cafe483..2326f0e 100644 --- a/plugingui/canvas.h +++ b/plugingui/canvas.h @@ -39,14 +39,6 @@ public: //! @returns a reference to the pixel buffer. virtual PixelBufferAlpha& GetPixelBuffer() = 0; - - //! Signal the beginning of a paint operation. - virtual void beginPaint() = 0; - - //! Signal the ending of a paint operation - //! This might trigger a redraw operation. - virtual void endPaint() = 0; - }; } // GUI:: diff --git a/plugingui/checkbox.cc b/plugingui/checkbox.cc index bada623..2a17635 100644 --- a/plugingui/checkbox.cc +++ b/plugingui/checkbox.cc @@ -62,13 +62,13 @@ void CheckBox::buttonEvent(ButtonEvent* buttonEvent) middle = true; } - repaintEvent(nullptr); + redraw(); } void CheckBox::setText(std::string text) { _text = text; - repaintEvent(nullptr); + redraw(); } void CheckBox::keyEvent(KeyEvent* keyEvent) @@ -85,7 +85,7 @@ void CheckBox::keyEvent(KeyEvent* keyEvent) middle = true; } - repaintEvent(nullptr); + redraw(); } } @@ -129,7 +129,7 @@ void CheckBox::mouseLeaveEvent() if(buttonDown) { middle = false; - repaintEvent(nullptr); + redraw(); } } @@ -139,7 +139,7 @@ void CheckBox::mouseEnterEvent() if(buttonDown) { middle = true; - repaintEvent(nullptr); + redraw(); } } @@ -152,7 +152,7 @@ void CheckBox::internalSetChecked(bool checked) state = checked; stateChangedNotifier(state); - repaintEvent(nullptr); + redraw(); } } // GUI:: diff --git a/plugingui/combobox.cc b/plugingui/combobox.cc index ffbde88..82fc6d1 100644 --- a/plugingui/combobox.cc +++ b/plugingui/combobox.cc @@ -65,13 +65,13 @@ void ComboBox::addItem(std::string name, std::string value) void ComboBox::clear() { listbox.clear(); - repaintEvent(nullptr); + redraw(); } bool ComboBox::selectItem(int index) { listbox.selectItem(index); - repaintEvent(nullptr); + redraw(); return true; } @@ -143,7 +143,7 @@ void ComboBox::scrollEvent(ScrollEvent* scrollEvent) { scroll_offset = (items.size() - 1); } - repaintEvent(nullptr); + redraw(); */ } @@ -203,7 +203,7 @@ void ComboBox::keyEvent(KeyEvent* keyEvent) break; } - repaintEvent(nullptr); + redraw(); */ } diff --git a/plugingui/eventhandler.cc b/plugingui/eventhandler.cc index aded993..2cdb6b1 100644 --- a/plugingui/eventhandler.cc +++ b/plugingui/eventhandler.cc @@ -56,21 +56,8 @@ std::shared_ptr EventHandler::getNextEvent() return event; } -std::shared_ptr EventHandler::peekNextEvent() -{ - if(events.empty()) - { - return nullptr; - } - - auto event = events.front(); - return event; -} - void EventHandler::processEvents() { - Painter p(window); // Make sure we only redraw buffer one time. - events = nativeWindow.getEvents(); while(hasEvent()) @@ -96,26 +83,6 @@ void EventHandler::processEvents() case EventType::resize: { - while(true) - { - if(!hasEvent()) - { - break; - } - - auto peekEvent = peekNextEvent(); - if(!peekEvent) - { - break; - } - if(peekEvent->type() != EventType::resize) - { - break; - } - - event = getNextEvent(); - } - auto resizeEvent = static_cast(event.get()); if((resizeEvent->width != window.width()) || (resizeEvent->height != window.height())) @@ -134,16 +101,6 @@ void EventHandler::processEvents() break; } - auto peekEvent = peekNextEvent(); - if(!peekEvent) - { - break; - } - if(peekEvent->type() != EventType::mouseMove) - { - break; - } - event = getNextEvent(); } @@ -171,8 +128,8 @@ void EventHandler::processEvents() if(window.buttonDownFocus()) { auto widget = window.buttonDownFocus(); - moveEvent->x -= widget->windowX(); - moveEvent->y -= widget->windowY(); + moveEvent->x -= widget->translateToWindowX(); + moveEvent->y -= widget->translateToWindowY(); window.buttonDownFocus()->mouseMoveEvent(moveEvent); break; @@ -180,8 +137,8 @@ void EventHandler::processEvents() if(widget) { - moveEvent->x -= widget->windowX(); - moveEvent->y -= widget->windowY(); + moveEvent->x -= widget->translateToWindowX(); + moveEvent->y -= widget->translateToWindowY(); widget->mouseMoveEvent(moveEvent); } } @@ -206,8 +163,8 @@ void EventHandler::processEvents() if(buttonEvent->direction == Direction::up) { auto widget = window.buttonDownFocus(); - buttonEvent->x -= widget->windowX(); - buttonEvent->y -= widget->windowY(); + buttonEvent->x -= widget->translateToWindowX(); + buttonEvent->y -= widget->translateToWindowY(); widget->buttonEvent(buttonEvent); window.setButtonDownFocus(nullptr); @@ -217,8 +174,8 @@ void EventHandler::processEvents() if(widget) { - buttonEvent->x -= widget->windowX(); - buttonEvent->y -= widget->windowY(); + buttonEvent->x -= widget->translateToWindowX(); + buttonEvent->y -= widget->translateToWindowY(); widget->buttonEvent(buttonEvent); @@ -238,38 +195,13 @@ void EventHandler::processEvents() case EventType::scroll: { - int delta = 0; - while(true) - { - if(!hasEvent()) - { - break; - } - - auto peekEvent = peekNextEvent(); - if(!peekEvent) - { - break; - } - if(peekEvent->type() != EventType::scroll) - { - break; - } - - auto scrollEvent = static_cast(event.get()); - delta += scrollEvent->delta; - - event = getNextEvent(); - } - auto scrollEvent = static_cast(event.get()); - scrollEvent->delta += delta; auto widget = window.find(scrollEvent->x, scrollEvent->y); if(widget) { - scrollEvent->x -= widget->windowX(); - scrollEvent->y -= widget->windowY(); + scrollEvent->x -= widget->translateToWindowX(); + scrollEvent->y -= widget->translateToWindowY(); widget->scrollEvent(scrollEvent); } @@ -294,6 +226,10 @@ void EventHandler::processEvents() break; } } + + // Probe window and children to readrw as needed. + // NOTE: This method will invoke native->redraw() if a redraw is needed. + window.updateBuffer(); } } // GUI:: diff --git a/plugingui/eventhandler.h b/plugingui/eventhandler.h index 2a1b657..7e9966c 100644 --- a/plugingui/eventhandler.h +++ b/plugingui/eventhandler.h @@ -53,10 +53,6 @@ public: //! \return A pointer to the event or nullptr if there are none. std::shared_ptr getNextEvent(); - //! \brief Get a single event from the event queue without popping it. - //! \return A pointer to the event or nullptr if there are none. - std::shared_ptr peekNextEvent(); - Notifier<> closeNotifier; private: diff --git a/plugingui/knob.cc b/plugingui/knob.cc index 87779ec..0655a68 100644 --- a/plugingui/knob.cc +++ b/plugingui/knob.cc @@ -203,7 +203,7 @@ void Knob::internalSetValue(float value) currentValue = value; valueChangedNotifier(currentValue); - repaintEvent(nullptr); + redraw(); } } // GUI:: diff --git a/plugingui/label.cc b/plugingui/label.cc index 2ff4f36..781dbca 100644 --- a/plugingui/label.cc +++ b/plugingui/label.cc @@ -39,7 +39,7 @@ Label::Label(Widget *parent) void Label::setText(const std::string& text) { _text = text; - repaintEvent(nullptr); + redraw(); } void Label::setAlignment(TextAlignment alignment) diff --git a/plugingui/layout.h b/plugingui/layout.h index bd64fdd..4d20eb6 100644 --- a/plugingui/layout.h +++ b/plugingui/layout.h @@ -46,10 +46,10 @@ public: virtual void resize(std::size_t width, std::size_t height) = 0; virtual void move(int x, int y) = 0; - virtual int x() = 0; - virtual int y() = 0; - virtual std::size_t width() = 0; - virtual std::size_t height() = 0; + virtual int x() const = 0; + virtual int y() const = 0; + virtual std::size_t width() const = 0; + virtual std::size_t height() const = 0; private: Layout* parent; diff --git a/plugingui/led.cc b/plugingui/led.cc index 03ea661..f77e31a 100644 --- a/plugingui/led.cc +++ b/plugingui/led.cc @@ -41,7 +41,7 @@ void LED::setState(state_t state) if(this->state != state) { this->state = state; - repaintEvent(nullptr); + redraw(); } } diff --git a/plugingui/lineedit.cc b/plugingui/lineedit.cc index c213041..7a8bb53 100644 --- a/plugingui/lineedit.cc +++ b/plugingui/lineedit.cc @@ -61,7 +61,7 @@ void LineEdit::setText(const std::string& text) visibleText = _text; offsetPos = 0; - repaintEvent(nullptr); + redraw(); textChanged(); } @@ -94,7 +94,7 @@ void LineEdit::buttonEvent(ButtonEvent *buttonEvent) break; } } - repaintEvent(nullptr); + redraw(); } } @@ -189,7 +189,7 @@ void LineEdit::keyEvent(KeyEvent *keyEvent) break; } - repaintEvent(nullptr); + redraw(); } if(change) diff --git a/plugingui/listboxbasic.cc b/plugingui/listboxbasic.cc index 730880a..642d03f 100644 --- a/plugingui/listboxbasic.cc +++ b/plugingui/listboxbasic.cc @@ -88,7 +88,7 @@ void ListBoxBasic::addItems(const std::vector& newItems) int numitems = height() / (font.textHeight() + padding); scroll.setRange(numitems); scroll.setMaximum(items.size()); - repaintEvent(nullptr); + redraw(); } void ListBoxBasic::clear() @@ -97,7 +97,7 @@ void ListBoxBasic::clear() setSelection(-1); marked = -1; scroll.setValue(0); - repaintEvent(nullptr); + redraw(); } bool ListBoxBasic::selectItem(int index) @@ -108,7 +108,7 @@ bool ListBoxBasic::selectItem(int index) } setSelection(index); - repaintEvent(nullptr); + redraw(); return true; } @@ -140,7 +140,7 @@ void ListBoxBasic::clearSelectedValue() void ListBoxBasic::onScrollBarValueChange(int value) { - repaintEvent(nullptr); + redraw(); } void ListBoxBasic::repaintEvent(RepaintEvent* repaintEvent) @@ -277,7 +277,7 @@ void ListBoxBasic::keyEvent(KeyEvent* keyEvent) break; } - repaintEvent(nullptr); + redraw(); } void ListBoxBasic::buttonEvent(ButtonEvent* buttonEvent) @@ -329,7 +329,7 @@ void ListBoxBasic::buttonEvent(ButtonEvent* buttonEvent) } } - repaintEvent(nullptr); + redraw(); } if(buttonEvent->direction != Direction::up) @@ -346,7 +346,7 @@ void ListBoxBasic::buttonEvent(ButtonEvent* buttonEvent) } } - repaintEvent(nullptr); + redraw(); } if(buttonEvent->doubleClick) diff --git a/plugingui/mainwindow.cc b/plugingui/mainwindow.cc index 3a1727f..3b951f5 100644 --- a/plugingui/mainwindow.cc +++ b/plugingui/mainwindow.cc @@ -50,13 +50,9 @@ bool MainWindow::processEvents() // return running; // } + settings_notifier.evaluate(); eventHandler()->processEvents(); - { - Painter p(*this); - settings_notifier.evaluate(); - } - if(closing) { closeNotifier(); diff --git a/plugingui/nativewindow.h b/plugingui/nativewindow.h index e041994..7b7fd39 100644 --- a/plugingui/nativewindow.h +++ b/plugingui/nativewindow.h @@ -69,10 +69,6 @@ public: //! Sets the window caption in the title bar (if it has one). virtual void setCaption(const std::string &caption) = 0; - //! Recreate a window render buffer based on the internal buffer. - //! This need to be called whenever the internal buffer size has changed. - virtual void handleBuffer() = 0; - //! Draw the internal rendering buffer to the window buffer. virtual void redraw() = 0; diff --git a/plugingui/nativewindow_win32.cc b/plugingui/nativewindow_win32.cc index 23c9012..669ec13 100644 --- a/plugingui/nativewindow_win32.cc +++ b/plugingui/nativewindow_win32.cc @@ -379,10 +379,6 @@ void NativeWindowWin32::show() ShowWindow(m_hwnd, SW_SHOW); } -void NativeWindowWin32::handleBuffer() -{ -} - void NativeWindowWin32::hide() { ShowWindow(m_hwnd, SW_HIDE); @@ -390,6 +386,7 @@ void NativeWindowWin32::hide() void NativeWindowWin32::redraw() { + // Send WM_PAINT message. Buffer transfering is handled in MessageHandler. if(parent_window == nullptr) { RedrawWindow(m_hwnd, nullptr, nullptr, RDW_ERASE|RDW_INVALIDATE); diff --git a/plugingui/nativewindow_win32.h b/plugingui/nativewindow_win32.h index b8e1c89..69324e3 100644 --- a/plugingui/nativewindow_win32.h +++ b/plugingui/nativewindow_win32.h @@ -52,7 +52,6 @@ public: void show() override; void setCaption(const std::string &caption) override; void hide() override; - void handleBuffer() override; void redraw() override; void grabMouse(bool grab) override; EventQueue getEvents() override; diff --git a/plugingui/nativewindow_x11.cc b/plugingui/nativewindow_x11.cc index bf18ffa..80c0e81 100644 --- a/plugingui/nativewindow_x11.cc +++ b/plugingui/nativewindow_x11.cc @@ -223,11 +223,6 @@ void NativeWindowX11::hide() XUnmapWindow(display, xwindow); } -void NativeWindowX11::handleBuffer() -{ - updateImageFromBuffer(); -} - void NativeWindowX11::redraw() { if(display == nullptr) @@ -235,12 +230,7 @@ void NativeWindowX11::redraw() return; } - if(!image) - { - window.updateBuffer(); - handleBuffer(); - } - + updateImageFromBuffer(); XShmPutImage(display, xwindow, gc, image, 0, 0, 0, 0, std::min(image->width, (int)window.width()), std::min(image->height, (int)window.height()), false); @@ -286,7 +276,6 @@ void NativeWindowX11::translateXMessage(XEvent& xevent) //DEBUG(x11, "MotionNotify"); { auto mouseMoveEvent = std::make_shared(); - //mouseMoveEvent->window_id = xevent.xmotion.window; mouseMoveEvent->x = xevent.xmotion.x; mouseMoveEvent->y = xevent.xmotion.y; event_queue.push_back(mouseMoveEvent); @@ -298,7 +287,6 @@ void NativeWindowX11::translateXMessage(XEvent& xevent) if(xevent.xexpose.count == 0) { auto repaintEvent = std::make_shared(); - //repaintEvent->window_id = xevent.xexpose.window; repaintEvent->x = xevent.xexpose.x; repaintEvent->y = xevent.xexpose.y; repaintEvent->width = xevent.xexpose.width; @@ -314,17 +302,15 @@ void NativeWindowX11::translateXMessage(XEvent& xevent) (window.height() != (std::size_t)xevent.xconfigure.height)) { auto resizeEvent = std::make_shared(); - //resizeEvent->window_id = xevent.xconfigure.window; resizeEvent->width = xevent.xconfigure.width; resizeEvent->height = xevent.xconfigure.height; event_queue.push_back(resizeEvent); } - if((window.windowX() != (std::size_t)xevent.xconfigure.x) || - (window.windowY() != (std::size_t)xevent.xconfigure.y)) + if((window.x() != xevent.xconfigure.x) || + (window.y() != xevent.xconfigure.y)) { auto moveEvent = std::make_shared(); - //moveEvent->window_id = xevent.xconfigure.window; moveEvent->x = xevent.xconfigure.x; moveEvent->y = xevent.xconfigure.y; event_queue.push_back(moveEvent); @@ -340,7 +326,6 @@ void NativeWindowX11::translateXMessage(XEvent& xevent) { int scroll = 1; auto scrollEvent = std::make_shared(); - //scrollEvent->window_id = xevent.xbutton.window; scrollEvent->x = xevent.xbutton.x; scrollEvent->y = xevent.xbutton.y; scrollEvent->delta = scroll * ((xevent.xbutton.button == 4) ? -1 : 1); @@ -349,7 +334,6 @@ void NativeWindowX11::translateXMessage(XEvent& xevent) else { auto buttonEvent = std::make_shared(); - //buttonEvent->window_id = xevent.xbutton.window; buttonEvent->x = xevent.xbutton.x; buttonEvent->y = xevent.xbutton.y; switch(xevent.xbutton.button) { @@ -400,7 +384,6 @@ void NativeWindowX11::translateXMessage(XEvent& xevent) //DEBUG(x11, "KeyPress"); { auto keyEvent = std::make_shared(); - //keyEvent->window_id = xevent.xkey.window; switch(xevent.xkey.keycode) { case 113: keyEvent->keycode = Key::left; break; diff --git a/plugingui/nativewindow_x11.h b/plugingui/nativewindow_x11.h index a026ac8..f98f151 100644 --- a/plugingui/nativewindow_x11.h +++ b/plugingui/nativewindow_x11.h @@ -54,7 +54,6 @@ public: void show() override; void hide() override; void setCaption(const std::string &caption) override; - void handleBuffer() override; void redraw() override; void grabMouse(bool grab) override; EventQueue getEvents() override; diff --git a/plugingui/painter.cc b/plugingui/painter.cc index 3e6fa48..4e7e8ba 100644 --- a/plugingui/painter.cc +++ b/plugingui/painter.cc @@ -29,6 +29,12 @@ #include #include +#include "pixelbuffer.h" +#include "font.h" +#include "drawable.h" +#include "image.h" +#include "canvas.h" + namespace GUI { @@ -36,14 +42,11 @@ Painter::Painter(Canvas& canvas) : canvas(canvas) , pixbuf(canvas.GetPixelBuffer()) { - canvas.beginPaint(); colour = Colour(0.0f, 0.0f, 0.0f, 0.5f); } Painter::~Painter() { - canvas.endPaint(); - flush(); } void Painter::setColour(const Colour& colour) @@ -161,7 +164,7 @@ void Painter::drawRectangle(int x1, int y1, int x2, int y2) void Painter::drawFilledRectangle(int x1, int y1, int x2, int y2) { - for(int y = y1; y < y2; ++y) + for(int y = y1; y <= y2; ++y) { drawLine(x1, y, x2, y); } @@ -543,12 +546,4 @@ void Painter::drawBar(int x, int y, const Bar& bar, int width, int height) bar.right->width(), height); } -void Painter::flush() -{ -#ifdef X11 - // Send the "DrawLine" request to the server - //XFlush(gctx->display); -#endif/*X11*/ -} - } // GUI:: diff --git a/plugingui/painter.h b/plugingui/painter.h index 7e1fede..3f3c2bb 100644 --- a/plugingui/painter.h +++ b/plugingui/painter.h @@ -28,25 +28,23 @@ #include -#include "widget.h" #include "colour.h" -#include "pixelbuffer.h" -#include "font.h" -#include "drawable.h" -#include "texture.h" -#include "image.h" namespace GUI { +class PixelBufferAlpha; +class Font; +class Drawable; +class Image; +class Canvas; + class Painter { public: Painter(Canvas& canvas); ~Painter(); - void flush(); - void setColour(const Colour& colour); void drawLine(int x1, int y1, int x2, int y2); diff --git a/plugingui/pixelbuffer.cc b/plugingui/pixelbuffer.cc index 5d032b4..15270af 100644 --- a/plugingui/pixelbuffer.cc +++ b/plugingui/pixelbuffer.cc @@ -156,7 +156,7 @@ void PixelBufferAlpha::pixel(size_t x, size_t y, unsigned char* red, unsigned char* green, unsigned char* blue, - unsigned char* alpha) + unsigned char* alpha) const { assert(x < width); assert(y < height); diff --git a/plugingui/pixelbuffer.h b/plugingui/pixelbuffer.h index 762aaa6..b9096c9 100644 --- a/plugingui/pixelbuffer.h +++ b/plugingui/pixelbuffer.h @@ -76,7 +76,7 @@ public: unsigned char* red, unsigned char* green, unsigned char* blue, - unsigned char* alpha); + unsigned char* alpha) const; bool managed{false}; unsigned char* buf{nullptr}; diff --git a/plugingui/progressbar.cc b/plugingui/progressbar.cc index 25e735f..c7550c9 100644 --- a/plugingui/progressbar.cc +++ b/plugingui/progressbar.cc @@ -43,7 +43,7 @@ void ProgressBar::setState(ProgressBarState state) if(this->state != state) { this->state = state; - repaintEvent(nullptr); + redraw(); } } @@ -52,7 +52,7 @@ void ProgressBar::setTotal(std::size_t total) if(this->total != total) { this->total = total; - repaintEvent(nullptr); + redraw(); } } @@ -61,7 +61,7 @@ void ProgressBar::setValue(std::size_t value) if(this->value != value) { this->value = value; - repaintEvent(nullptr); + redraw(); } } diff --git a/plugingui/scrollbar.cc b/plugingui/scrollbar.cc index ac5be15..32db4a4 100644 --- a/plugingui/scrollbar.cc +++ b/plugingui/scrollbar.cc @@ -41,7 +41,7 @@ void ScrollBar::setRange(int r) { rangeValue = r; setValue(value()); - repaintEvent(nullptr); + redraw(); } int ScrollBar::range() @@ -57,7 +57,7 @@ void ScrollBar::setMaximum(int m) rangeValue = maxValue; } setValue(value()); - repaintEvent(nullptr); + redraw(); } int ScrollBar::maximum() @@ -91,7 +91,7 @@ void ScrollBar::setValue(int value) valueChangeNotifier(value); - repaintEvent(nullptr); + redraw(); } int ScrollBar::value() diff --git a/plugingui/slider.cc b/plugingui/slider.cc index 7405a69..039123e 100644 --- a/plugingui/slider.cc +++ b/plugingui/slider.cc @@ -46,7 +46,7 @@ Slider::Slider(Widget *parent) void Slider::setValue(float newValue) { currentValue = newValue; - repaintEvent(nullptr); + redraw(); clickNotifier(); } @@ -120,7 +120,7 @@ void Slider::buttonEvent(ButtonEvent* buttonEvent) currentValue = 1; } - repaintEvent(nullptr); + redraw(); clickNotifier(); } @@ -139,7 +139,7 @@ void Slider::buttonEvent(ButtonEvent* buttonEvent) currentValue = 1; } - repaintEvent(nullptr); + redraw(); clickNotifier(); } } @@ -160,7 +160,7 @@ void Slider::mouseMoveEvent(MouseMoveEvent* mouseMoveEvent) currentValue = 1; } - repaintEvent(nullptr); + redraw(); clickNotifier(); } } diff --git a/plugingui/textedit.cc b/plugingui/textedit.cc index 6274d37..4e94566 100644 --- a/plugingui/textedit.cc +++ b/plugingui/textedit.cc @@ -83,7 +83,7 @@ void TextEdit::setText(const std::string& text) scroll.setRange(ran); scroll.setMaximum(preprocessedtext.size()); - repaintEvent(nullptr); + redraw(); textChangedNotifier(); } @@ -190,7 +190,7 @@ void TextEdit::repaintEvent(RepaintEvent* repaintEvent) void TextEdit::scrolled(int value) { (void)value; - repaintEvent(nullptr); + redraw(); } } // GUI:: diff --git a/plugingui/widget.cc b/plugingui/widget.cc index 9b8b173..239c233 100644 --- a/plugingui/widget.cc +++ b/plugingui/widget.cc @@ -31,7 +31,8 @@ #include "painter.h" #include "window.h" -namespace GUI { +namespace GUI +{ Widget::Widget(Widget* parent) : parent(parent) @@ -67,15 +68,21 @@ void Widget::setVisible(bool visible) if(visible) { - repaintEvent(nullptr); + redraw(); } } -bool Widget::visible() +bool Widget::visible() const { return _visible; } +void Widget::redraw() +{ + dirty = true; + window()->needsRedraw(); +} + void Widget::addChild(Widget* widget) { children.push_back(widget); @@ -124,33 +131,39 @@ void Widget::resize(std::size_t width, std::size_t height) _width = width; _height = height; pixbuf.realloc(width, height); - repaintEvent(nullptr); + redraw(); sizeChangeNotifier(width, height); } void Widget::move(int x, int y) { + if((_x == x) && + (_y == y)) + { + return; + } + _x = x; _y = y; positionChangeNotifier(x, y); } -int Widget::x() +int Widget::x() const { return _x; } -int Widget::y() +int Widget::y() const { return _y; } -std::size_t Widget::width() +std::size_t Widget::width() const { return _width; } -std::size_t Widget::height() +std::size_t Widget::height() const { return _height; } @@ -160,44 +173,6 @@ PixelBufferAlpha& Widget::GetPixelBuffer() return pixbuf; } -void Widget::beginPaint() -{ - if(_window) - { - _window->beginPaint(); - } -} - -void Widget::endPaint() -{ - if(_window) - { - _window->endPaint(); - } -} - -size_t Widget::windowX() -{ - size_t window_x = x(); - if(parent) - { - window_x += parent->windowX(); - } - - return window_x; -} - -size_t Widget::windowY() -{ - size_t window_y = y(); - if(parent) - { - window_y += parent->windowY(); - } - - return window_y; -} - ImageCache& Widget::getImageCache() { assert(parent); @@ -231,8 +206,14 @@ std::vector Widget::getPixelBuffers() { std::vector pixelBuffers; - pixbuf.x = windowX(); - pixbuf.y = windowY(); + pixbuf.x = translateToWindowX(); + pixbuf.y = translateToWindowY(); + + if(dirty) + { + repaintEvent(nullptr); + dirty = false; + } pixelBuffers.push_back(&pixbuf); @@ -254,16 +235,26 @@ bool Widget::hasKeyboardFocus() return window()->keyboardFocus() == this; } -void Widget::repaintChildren(RepaintEvent* repaintEvent) +std::size_t Widget::translateToWindowX() { - Painter p(*this); // make sure pixbuf refcount is incremented. + size_t window_x = x(); + if(parent) + { + window_x += parent->translateToWindowX(); + } - this->repaintEvent(repaintEvent); + return window_x; +} - for(auto child : children) +std::size_t Widget::translateToWindowY() +{ + size_t window_y = y(); + if(parent) { - child->repaintChildren(repaintEvent); + window_y += parent->translateToWindowY(); } + + return window_y; } } // GUI:: diff --git a/plugingui/widget.h b/plugingui/widget.h index 4ea79e9..0485c32 100644 --- a/plugingui/widget.h +++ b/plugingui/widget.h @@ -52,25 +52,22 @@ public: virtual void show(); virtual void hide(); + void setVisible(bool visible); + bool visible() const; + + //! Mark widget dirty and shedule redraw on next window redraw. + void redraw(); // From LayoutItem virtual void resize(std::size_t width, std::size_t height) override; virtual void move(int x, int y) override; - virtual int x() override; - virtual int y() override; - virtual std::size_t width() override; - virtual std::size_t height() override; + virtual int x() const override; + virtual int y() const override; + virtual std::size_t width() const override; + virtual std::size_t height() const override; // From Canvas PixelBufferAlpha& GetPixelBuffer() override; - void beginPaint() override; - void endPaint() override; - - //! Translate x-coordinate from parent-space to window-space. - virtual size_t windowX(); - - //! Translate y-coordinate from parent-space to window-space. - virtual size_t windowY(); virtual bool isFocusable() { return false; } virtual bool catchMouse() { return false; } @@ -97,14 +94,17 @@ public: bool hasKeyboardFocus(); - bool visible(); - void setVisible(bool visible); - Notifier sizeChangeNotifier; // (width, height) Notifier positionChangeNotifier; // (x, y) protected: - void repaintChildren(RepaintEvent* repaintEvent); + friend class EventHandler; + + //! Translate x-coordinate from parent-space to window-space. + virtual std::size_t translateToWindowX(); + + //! Translate y-coordinate from parent-space to window-space. + virtual std::size_t translateToWindowY(); PixelBufferAlpha pixbuf{0,0}; @@ -119,6 +119,8 @@ protected: std::size_t _height{0}; bool _visible{true}; + + bool dirty{true}; }; } // GUI:: diff --git a/plugingui/window.cc b/plugingui/window.cc index 98c0c80..44c8e12 100644 --- a/plugingui/window.cc +++ b/plugingui/window.cc @@ -42,7 +42,8 @@ #include "nativewindow_pugl.h" #endif -namespace GUI { +namespace GUI +{ Window::Window(void* native_window) : Widget(nullptr) @@ -101,40 +102,10 @@ void Window::move(int x, int y) native->move(x, y); } -int Window::x() -{ - return native->getPosition().first; -} - -int Window::y() -{ - return native->getPosition().second; -} - -size_t Window::width() -{ - return native->getSize().first; -} - -size_t Window::height() -{ - return native->getSize().second; -} - -size_t Window::windowX() -{ - return 0; -} - -size_t Window::windowY() -{ - return 0; -} - void Window::show() { Widget::show(); - repaintChildren(nullptr); + redraw(); native->show(); } @@ -171,12 +142,12 @@ void Window::setKeyboardFocus(Widget* widget) if(oldFocusWidget) { - oldFocusWidget->repaintEvent(nullptr); + oldFocusWidget->redraw(); } if(_keyboardFocus) { - _keyboardFocus->repaintEvent(nullptr); + _keyboardFocus->redraw(); } } @@ -202,18 +173,34 @@ void Window::setMouseFocus(Widget* widget) } -void Window::redraw() +void Window::needsRedraw() { - native->redraw(); + needs_redraw = true; +} + +std::size_t Window::translateToWindowX() +{ + return 0; +} + +std::size_t Window::translateToWindowY() +{ + return 0; } //! Called by event handler when an windowmanager/OS window resize event has //! been received. Do not call this directly. void Window::resized(std::size_t width, std::size_t height) { - wpixbuf.realloc(this->width(), this->height()); - Widget::resize(this->width(), this->height()); - updateBuffer(); + auto size = native->getSize(); + if((wpixbuf.width == size.first) && + (wpixbuf.height == size.second)) + { + return; + } + wpixbuf.realloc(size.first, size.second); + Widget::resize(size.first, size.second); + //updateBuffer(); } //! Called by event handler when an windowmanager/OS window move event has @@ -224,9 +211,20 @@ void Window::moved(int x, int y) Widget::move(x, y); } -void Window::updateBuffer() +bool Window::updateBuffer() { - for(auto pixelBuffer : getPixelBuffers()) + if(!native) + { + return false; + } + + if(!needs_redraw) + { + // Nothing changed, don't update anything. + return false; + } + + for(const auto& pixelBuffer : getPixelBuffers()) { size_t updateWidth = pixelBuffer->width; size_t updateHeight = pixelBuffer->height; @@ -258,35 +256,10 @@ void Window::updateBuffer() } } - native->handleBuffer(); -} - -void Window::beginPaint() -{ - ++refcount; - if(refcount > maxRefcount) - { - maxRefcount = refcount; - } -} - -void Window::endPaint() -{ - if(refcount) - { - --refcount; - } + native->redraw(); + needs_redraw = false; - if(!refcount) - { - // Did we go deep enough for a buffer update? - if(maxRefcount > 1) - { - updateBuffer(); - redraw(); - } - maxRefcount = 0; - } + return true; } } // GUI:: diff --git a/plugingui/window.h b/plugingui/window.h index 0a10b3e..cfb004d 100644 --- a/plugingui/window.h +++ b/plugingui/window.h @@ -50,12 +50,6 @@ public: // From Widget: void resize(std::size_t width, std::size_t height) override; void move(int x, int y) override; - int x() override; - int y() override; - size_t width() override; - size_t height() override; - size_t windowX() override; - size_t windowY() override; void show() override; void hide() override; Window* window() override; @@ -73,18 +67,25 @@ public: Widget* mouseFocus(); void setMouseFocus(Widget* widget); + //! Tag the window buffer dirty to be rendered. + void needsRedraw(); + protected: // For the EventHandler friend class EventHandler; - void redraw(); + + // From Widget: + std::size_t translateToWindowX() override; + std::size_t translateToWindowY() override; void resized(std::size_t width, std::size_t height); void moved(int x, int y); - void updateBuffer(); + + //! Returns true if window pixel buffer changed and needs to be copied to + //! native window. + bool updateBuffer(); // For the Painter friend class Widget; - void beginPaint() override; - void endPaint() override; // For the NativeWindow friend class NativeWindowX11; @@ -103,6 +104,7 @@ protected: size_t maxRefcount{0}; + bool needs_redraw{false}; ImageCache image_cache; }; -- cgit v1.2.3