From 76b6855284a8f1201429ffcdc34ac1284935fad1 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Tue, 10 Nov 2020 23:29:56 +0100 Subject: [PATCH] added support of transparent widgets (for TimeMachineDialog) --- src/common/FBSurfaceSDL2.cxx | 16 ++++++++++++++++ src/common/FBSurfaceSDL2.hxx | 2 ++ src/emucore/FBSurface.hxx | 11 +++++++++++ src/gui/Dialog.cxx | 8 ++++++-- src/gui/DialogContainer.cxx | 2 +- src/gui/TimeLineWidget.cxx | 18 +++++++++++------- src/gui/TimeMachineDialog.cxx | 3 +++ src/gui/Widget.cxx | 13 ++++++++----- src/gui/Widget.hxx | 4 +++- 9 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index 543195165..398c773ba 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -176,6 +176,22 @@ void FBSurfaceSDL2::invalidate() SDL_FillRect(mySurface, nullptr, 0); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceSDL2::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) +{ + ASSERT_MAIN_THREAD; + + // Clear the rectangle + SDL_Rect tmp; + tmp.x = x; + tmp.y = y; + tmp.w = w; + tmp.h = h; + // Note: Transparency has to be 0 to clear the rectangle foreground + // without affecting the background display. + SDL_FillRect(mySurface, &tmp, 0); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::free() { diff --git a/src/common/FBSurfaceSDL2.hxx b/src/common/FBSurfaceSDL2.hxx index f446bb17b..c19808f27 100644 --- a/src/common/FBSurfaceSDL2.hxx +++ b/src/common/FBSurfaceSDL2.hxx @@ -55,6 +55,8 @@ class FBSurfaceSDL2 : public FBSurface void translateCoords(Int32& x, Int32& y) const override; bool render() override; void invalidate() override; + void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) override; + void free() override; void reload() override; void resize(uInt32 width, uInt32 height) override; diff --git a/src/emucore/FBSurface.hxx b/src/emucore/FBSurface.hxx index a018ac2c9..67eaa86d2 100644 --- a/src/emucore/FBSurface.hxx +++ b/src/emucore/FBSurface.hxx @@ -325,6 +325,17 @@ class FBSurface */ virtual void invalidate() = 0; + /** + This method should be called to reset a surface area to empty + + @param x The x coordinate + @param y The y coordinate + @param w The width of the area + @param h The height of the area + */ + virtual void invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) = 0; + + /** This method should be called to free any resources being used by the surface. diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index 6e81535c2..c691c545a 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -404,7 +404,7 @@ void Dialog::drawDialog() if(isDirty()) { - //cerr << "*** draw dialog " << typeid(*this).name() << " ***" << endl; + cerr << "*** draw dialog " << typeid(*this).name() << " ***" << endl; // Dialog is still on top if e.g a ContextMenu is opened _onTop = parent().myDialogStack.top() == this @@ -414,7 +414,11 @@ void Dialog::drawDialog() if(_flags & Widget::FLAG_CLEARBG) { // cerr << "Dialog::drawDialog(): w = " << _w << ", h = " << _h << " @ " << &s << endl << endl; - s.fillRect(_x, _y + _th, _w, _h - _th, _onTop ? kDlgColor : kBGColorLo); + + if(_flags & Widget::FLAG_TRANSPARENT) + s.invalidateRect(_x, _y + _th, _w, _h - _th); + else + s.fillRect(_x, _y + _th, _w, _h - _th, _onTop ? kDlgColor : kBGColorLo); if(_th) { s.fillRect(_x, _y, _w, _th, _onTop ? kColorTitleBar : kColorTitleBarLo); diff --git a/src/gui/DialogContainer.cxx b/src/gui/DialogContainer.cxx index af353f452..8577eb50f 100644 --- a/src/gui/DialogContainer.cxx +++ b/src/gui/DialogContainer.cxx @@ -91,7 +91,7 @@ void DialogContainer::updateTime(uInt64 time) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DialogContainer::draw(bool full) { - cerr << "draw " << full << endl; + //cerr << "draw " << full << endl; if(myDialogStack.empty()) return false; diff --git a/src/gui/TimeLineWidget.cxx b/src/gui/TimeLineWidget.cxx index 053d7bccf..94c4d3ef9 100644 --- a/src/gui/TimeLineWidget.cxx +++ b/src/gui/TimeLineWidget.cxx @@ -35,8 +35,11 @@ TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font, : ButtonWidget(boss, font, x, y, w, h, label, cmd), _labelWidth(labelWidth) { - _flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE; + _flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE + | Widget::FLAG_CLEARBG | Widget::FLAG_TRANSPARENT; + _bgcolor = kDlgColor; + //_bgcolor = kBGColor; _bgcolorhi = kDlgColor; if(!_label.empty() && _labelWidth == 0) @@ -84,7 +87,7 @@ void TimeLineWidget::setStepValues(const IntArray& steps) if(steps.size() > _stepValue.capacity()) _stepValue.reserve(2 * steps.size()); - double scale = (_w - _labelWidth - 2 - HANDLE_W*0) / double(steps.back()); + double scale = (_w - _labelWidth - 2 - HANDLE_W) / double(steps.back()); // Skip the very last value; we take care of it outside the end of the loop for(uInt32 i = 0; i < steps.size() - 1; ++i) @@ -92,7 +95,7 @@ void TimeLineWidget::setStepValues(const IntArray& steps) // Due to integer <-> double conversion, the last value is sometimes // slightly less than the maximum value; we assign it manually to fix this - _stepValue.push_back(_w - _labelWidth - 2 - HANDLE_W*0); + _stepValue.push_back(_w - _labelWidth - 2 - HANDLE_W); } else _stepValue.push_back(0); @@ -141,17 +144,18 @@ void TimeLineWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); + cerr << "TimeLineWidget::drawWidget " << typeid(s).name() << endl; + // Draw the label, if any if(_labelWidth > 0) s.drawString(_font, _label, _x, _y + 2, _labelWidth, isEnabled() ? kTextColor : kColor, TextAlign::Left); - int p = valueToPos(_value), - x = _x + _labelWidth, - w = _w - _labelWidth; - // Frame the handle const int HANDLE_W2 = (HANDLE_W + 1) / 2; + int p = valueToPos(_value), + x = _x + _labelWidth + HANDLE_W2, + w = _w - _labelWidth - HANDLE_W; s.hLine(x + p - HANDLE_W2, _y + 0, x + p - HANDLE_W2 + HANDLE_W, kColorInfo); s.vLine(x + p - HANDLE_W2, _y + 1, _y + _h - 2, kColorInfo); s.hLine(x + p - HANDLE_W2 + 1, _y + _h - 1, x + p - HANDLE_W2 + 1 + HANDLE_W, kBGColor); diff --git a/src/gui/TimeMachineDialog.cxx b/src/gui/TimeMachineDialog.cxx index 3b591a62d..5982ba693 100644 --- a/src/gui/TimeMachineDialog.cxx +++ b/src/gui/TimeMachineDialog.cxx @@ -225,6 +225,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, // Add index info myCurrentIdxWidget = new StaticTextWidget(this, font, xpos, ypos, "1000", TextAlign::Left, kBGColor); myCurrentIdxWidget->setTextColor(kColorInfo); + myCurrentIdxWidget->setFlags(Widget::FLAG_CLEARBG | Widget::FLAG_TRANSPARENT); myLastIdxWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("1000"), ypos, "1000", TextAlign::Right, kBGColor); myLastIdxWidget->setTextColor(kColorInfo); @@ -241,6 +242,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, // Add time info int ypos_s = ypos + (buttonHeight - font.getFontHeight() + 1) / 2; // align to button vertical center myCurrentTimeWidget = new StaticTextWidget(this, font, xpos, ypos_s, "00:00.00", TextAlign::Left, kBGColor); + myCurrentTimeWidget->setFlags(Widget::FLAG_CLEARBG | Widget::FLAG_TRANSPARENT); myCurrentTimeWidget->setTextColor(kColorInfo); myLastTimeWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("00:00.00"), ypos_s, "00:00.00", TextAlign::Right, kBGColor); @@ -287,6 +289,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, // Add message myMessageWidget = new StaticTextWidget(this, font, xpos, ypos_s, " ", TextAlign::Left, kBGColor); + myMessageWidget->setFlags(Widget::FLAG_CLEARBG | Widget::FLAG_TRANSPARENT); myMessageWidget->setTextColor(kColorInfo); } diff --git a/src/gui/Widget.cxx b/src/gui/Widget.cxx index 33f6b632d..3c0252688 100644 --- a/src/gui/Widget.cxx +++ b/src/gui/Widget.cxx @@ -65,9 +65,9 @@ void Widget::setDirty() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Widget::isDirty() const { - string name = typeid(*this).name(); - if(_dirty && name == "class TabWidget") - cerr << "is dirty " << typeid(*this).name() << endl; + //string name = typeid(*this).name(); + //if(_dirty && name == "class TabWidget") + // cerr << "is dirty " << typeid(*this).name() << endl; return _dirty; } @@ -101,7 +101,7 @@ void Widget::draw() if(isDirty()) { - //cerr << " *** draw widget " << typeid(*this).name() << " ***" << endl; + cerr << " *** draw widget " << typeid(*this).name() << " ***" << endl; FBSurface& s = _boss->dialog().surface(); @@ -122,7 +122,10 @@ void Widget::draw() { x++; y++; w -= 2; h -= 2; } - s.fillRect(x, y, w, h, !onTop ? _bgcolorlo : (_flags & Widget::FLAG_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor); + if(isTransparent()) + s.invalidateRect(x, y, w, h); + else + s.fillRect(x, y, w, h, !onTop ? _bgcolorlo : (_flags & Widget::FLAG_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor); } // Draw border diff --git a/src/gui/Widget.hxx b/src/gui/Widget.hxx index c5fd8dced..15e7a1d9c 100644 --- a/src/gui/Widget.hxx +++ b/src/gui/Widget.hxx @@ -52,7 +52,8 @@ class Widget : public GuiObject FLAG_TRACK_MOUSE = 1 << 5, FLAG_RETAIN_FOCUS = 1 << 6, FLAG_WANTS_TAB = 1 << 7, - FLAG_WANTS_RAWDATA = 1 << 8 + FLAG_WANTS_RAWDATA = 1 << 8, + FLAG_TRANSPARENT = 1 << 9 }; public: @@ -105,6 +106,7 @@ class Widget : public GuiObject virtual bool wantsFocus() const { return _flags & FLAG_RETAIN_FOCUS; } bool wantsTab() const { return _flags & FLAG_WANTS_TAB; } bool wantsRaw() const { return _flags & FLAG_WANTS_RAWDATA; } + bool isTransparent() const { return _flags & FLAG_TRANSPARENT; } void setID(uInt32 id) { _id = id; } uInt32 getID() const { return _id; }