initial commit for #719

This commit is contained in:
thrust26 2020-11-10 19:53:36 +01:00
parent eae7808ddf
commit e7b7bfa3cd
10 changed files with 235 additions and 118 deletions

View File

@ -439,7 +439,7 @@ void FrameBuffer::update(bool force)
force = force || myOSystem.launcher().needsRedraw(); force = force || myOSystem.launcher().needsRedraw();
if(force) if(force)
{ {
clear(); //clear();
myOSystem.launcher().draw(force); myOSystem.launcher().draw(force);
} }
break; // EventHandlerState::LAUNCHER break; // EventHandlerState::LAUNCHER

View File

@ -621,5 +621,5 @@ void ContextMenu::drawDialog()
s.drawBitmap(_downImg, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollDnColor, _arrowSize); s.drawBitmap(_downImg, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollDnColor, _arrowSize);
} }
setDirty(); clearDirty();
} }

View File

@ -149,6 +149,35 @@ void Dialog::center()
positionAt(instance().settings().getInt("dialogpos")); positionAt(instance().settings().getInt("dialogpos"));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Dialog::setDirty()
{
_dirty = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Dialog::isDirty() const
{
return _dirty;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Dialog::isChainDirty() const
{
bool dirty = false;
// Check if widget or any subwidgets are dirty
Widget* w = _firstWidget;
while(!dirty && w)
{
dirty |= w->needsRedraw();
w = w->_next;
}
return dirty;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Dialog::positionAt(uInt32 pos) void Dialog::positionAt(uInt32 pos)
{ {
@ -192,7 +221,9 @@ void Dialog::positionAt(uInt32 pos)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Dialog::render() bool Dialog::render()
{ {
if(!_dirty || !isVisible()) //assert(_dirty);
if(!isVisible() || !needsRedraw())
return false; return false;
// Draw this dialog // Draw this dialog
@ -207,7 +238,7 @@ bool Dialog::render()
surface->render(); surface->render();
}); });
} }
_dirty = false; //_dirty = false;
return true; return true;
} }
@ -371,37 +402,49 @@ void Dialog::drawDialog()
FBSurface& s = surface(); FBSurface& s = surface();
// Dialog is still on top if e.g a ContextMenu is opened if(isDirty())
_onTop = parent().myDialogStack.top() == this
|| (parent().myDialogStack.get(parent().myDialogStack.size() - 2) == this
&& !parent().myDialogStack.top()->hasTitle());
if(_flags & Widget::FLAG_CLEARBG)
{ {
// cerr << "Dialog::drawDialog(): w = " << _w << ", h = " << _h << " @ " << &s << endl << endl; //cerr << "*** draw dialog " << typeid(*this).name() << " ***" << endl;
s.fillRect(_x, _y + _th, _w, _h - _th, _onTop ? kDlgColor : kBGColorLo);
if(_th) // Dialog is still on top if e.g a ContextMenu is opened
{ _onTop = parent().myDialogStack.top() == this
s.fillRect(_x, _y, _w, _th, _onTop ? kColorTitleBar : kColorTitleBarLo); || (parent().myDialogStack.get(parent().myDialogStack.size() - 2) == this
s.drawString(_font, _title, _x + _font.getMaxCharWidth() * 1.25, _y + _font.getFontHeight() / 6, && !parent().myDialogStack.top()->hasTitle());
_font.getStringWidth(_title),
_onTop ? kColorTitleText : kColorTitleTextLo); if(_flags & Widget::FLAG_CLEARBG)
} {
} // cerr << "Dialog::drawDialog(): w = " << _w << ", h = " << _h << " @ " << &s << endl << endl;
else s.fillRect(_x, _y + _th, _w, _h - _th, _onTop ? kDlgColor : kBGColorLo);
s.invalidate(); if(_th)
if(_flags & Widget::FLAG_BORDER) // currently only used by Dialog itself {
s.frameRect(_x, _y, _w, _h, _onTop ? kColor : kShadowColor); s.fillRect(_x, _y, _w, _th, _onTop ? kColorTitleBar : kColorTitleBarLo);
s.drawString(_font, _title, _x + _font.getMaxCharWidth() * 1.25, _y + _font.getFontHeight() / 6,
_font.getStringWidth(_title),
_onTop ? kColorTitleText : kColorTitleTextLo);
}
}
else {
s.invalidate();
cerr << "invalidate " << typeid(*this).name() << endl;
}
if(_flags & Widget::FLAG_BORDER) // currently only used by Dialog itself
s.frameRect(_x, _y, _w, _h, _onTop ? kColor : kShadowColor);
// Make all child widgets dirty
Widget::setDirtyInChain(_firstWidget);
clearDirty();
}
// Make all child widget dirty
Widget* w = _firstWidget; Widget* w = _firstWidget;
Widget::setDirtyInChain(w);
// Draw all children // Draw all children
w = _firstWidget; w = _firstWidget;
while(w) while(w)
{ {
w->draw(); // only redraw changed widgets
if(w->needsRedraw())
w->draw();
w = w->_next; w = w->_next;
} }

View File

@ -64,8 +64,9 @@ class Dialog : public GuiObject
// A dialog being dirty indicates that its underlying surface needs to be // A dialog being dirty indicates that its underlying surface needs to be
// redrawn and then re-rendered; this is taken care of in ::render() // redrawn and then re-rendered; this is taken care of in ::render()
void setDirty() override { _dirty = true; } void setDirty() override;
bool isDirty() const { return _dirty; } bool isDirty() const override;
bool isChainDirty() const override;
bool render(); bool render();
void addFocusWidget(Widget* w) override; void addFocusWidget(Widget* w) override;
@ -235,7 +236,7 @@ class Dialog : public GuiObject
int _tabID{0}; int _tabID{0};
int _flags{0}; int _flags{0};
bool _dirty{false}; //bool _dirty{false};
uInt32 _max_w{0}; // maximum wanted width uInt32 _max_w{0}; // maximum wanted width
uInt32 _max_h{0}; // maximum wanted height uInt32 _max_h{0}; // maximum wanted height

View File

@ -91,21 +91,32 @@ void DialogContainer::updateTime(uInt64 time)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool DialogContainer::draw(bool full) bool DialogContainer::draw(bool full)
{ {
cerr << "draw " << full << endl;
if(myDialogStack.empty()) if(myDialogStack.empty())
return false; return false;
// Make the top dialog dirty if a full redraw is requested // Make the top dialog dirty if a full redraw is requested
if(full) //if(full)
myDialogStack.top()->setDirty(); // myDialogStack.top()->setDirty();
// If the top dialog is dirty, then all below it must be redrawn too // If the top dialog is dirty, then all below it must be redrawn too
const bool dirty = needsRedraw(); const bool dirty = needsRedraw();
//if(dirty)
// myDialogStack.top()->setDirty();
myDialogStack.applyAll([&](Dialog*& d){ //myDialogStack.applyAll([&](Dialog*& d){
if(dirty) // if(dirty)
d->setDirty(); // d->setDirty();
full |= d->render(); // full |= d->render();
}); //});
//if(dirty)
{
myDialogStack.applyAll([&](Dialog*& d) {
if(d->needsRedraw())
//d->setDirty();
full |= d->render();
});
}
return full; return full;
} }
@ -113,7 +124,9 @@ bool DialogContainer::draw(bool full)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool DialogContainer::needsRedraw() const bool DialogContainer::needsRedraw() const
{ {
return !myDialogStack.empty() ? myDialogStack.top()->isDirty() : false; return !myDialogStack.empty()
? myDialogStack.top()->needsRedraw()
: false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -133,6 +146,9 @@ int DialogContainer::addDialog(Dialog* d)
"Unable to show dialog box; FIX THE CODE"); "Unable to show dialog box; FIX THE CODE");
else else
{ {
// fade out current top dialog
if(!myDialogStack.empty())
myDialogStack.top()->setDirty();
d->setDirty(); d->setDirty();
myDialogStack.push(d); myDialogStack.push(d);
} }
@ -145,8 +161,16 @@ void DialogContainer::removeDialog()
if(!myDialogStack.empty()) if(!myDialogStack.empty())
{ {
myDialogStack.pop(); myDialogStack.pop();
// necessary as long as all dialogs share the same surface
if(!myDialogStack.empty()) if(!myDialogStack.empty())
myDialogStack.top()->setDirty(); {
//myDialogStack.top()->setDirty();
// Mark all dialogs for redraw
myDialogStack.applyAll([&](Dialog*& d){
d->setDirty();
});
}
} }
} }

View File

@ -78,6 +78,10 @@ class GuiObject : public CommandReceiver
virtual bool isVisible() const = 0; virtual bool isVisible() const = 0;
virtual void setDirty() = 0; virtual void setDirty() = 0;
virtual void clearDirty() { _dirty = false; }
virtual bool isDirty() const { return _dirty; }
virtual bool isChainDirty() const = 0;
virtual bool needsRedraw() const { return isDirty() || isChainDirty(); };
/** Add given widget(s) to the focus list */ /** Add given widget(s) to the focus list */
virtual void addFocusWidget(Widget* w) = 0; virtual void addFocusWidget(Widget* w) = 0;
@ -104,6 +108,7 @@ class GuiObject : public CommandReceiver
protected: protected:
int _x{0}, _y{0}, _w{0}, _h{0}; int _x{0}, _y{0}, _w{0}, _h{0};
bool _dirty{false};
Widget* _firstWidget{nullptr}; Widget* _firstWidget{nullptr};
WidgetArray _focusList; WidgetArray _focusList;

View File

@ -315,6 +315,7 @@ void ScrollBarWidget::drawWidget(bool hilite)
s.fillRect(_x + 1, _y + _sliderPos - 1, _w - 2, _sliderHeight + 2, s.fillRect(_x + 1, _y + _sliderPos - 1, _w - 2, _sliderHeight + 2,
onTop ? (hilite && _part == Part::Slider) ? kScrollColorHi : kScrollColor : kColor); onTop ? (hilite && _part == Part::Slider) ? kScrollColorHi : kScrollColor : kColor);
} }
clearDirty();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -275,39 +275,45 @@ void TabWidget::drawWidget(bool hilite)
// The tab widget is strange in that it acts as both a widget (obviously) // The tab widget is strange in that it acts as both a widget (obviously)
// and a dialog (it contains other widgets). Because of the latter, // and a dialog (it contains other widgets). Because of the latter,
// it must assume responsibility for refreshing all its children. // it must assume responsibility for refreshing all its children.
Widget::setDirtyInChain(_tabs[_activeTab].firstWidget);
FBSurface& s = dialog().surface(); if(isDirty())
bool onTop = _boss->dialog().isOnTop();
// Iterate over all tabs and draw them
int i, x = _x + kTabLeftOffset;
for (i = 0; i < int(_tabs.size()); ++i)
{ {
int tabWidth = _tabs[i].tabWidth ? _tabs[i].tabWidth : _tabWidth; FBSurface& s = dialog().surface();
ColorId fontcolor = _tabs[i].enabled && onTop? kTextColor : kColor; bool onTop = _boss->dialog().isOnTop();
int yOffset = (i == _activeTab) ? 0 : 1;
s.fillRect(x, _y + 1, tabWidth, _tabHeight - 1, // Iterate over all tabs and draw them
(i == _activeTab) int i, x = _x + kTabLeftOffset;
? onTop ? kDlgColor : kBGColorLo for(i = 0; i < int(_tabs.size()); ++i)
: onTop ? kBGColorHi : kDlgColor); // ? kWidColor : kDlgColor
s.drawString(_font, _tabs[i].title, x + kTabPadding + yOffset,
_y + yOffset + (_tabHeight - _lineHeight - 1),
tabWidth - 2 * kTabPadding, fontcolor, TextAlign::Center);
if(i == _activeTab)
{ {
s.hLine(x, _y, x + tabWidth - 1, onTop ? kWidColor : kDlgColor); int tabWidth = _tabs[i].tabWidth ? _tabs[i].tabWidth : _tabWidth;
s.vLine(x + tabWidth, _y + 1, _y + _tabHeight - 1, onTop ? kBGColorLo : kColor); ColorId fontcolor = _tabs[i].enabled && onTop ? kTextColor : kColor;
int yOffset = (i == _activeTab) ? 0 : 1;
s.fillRect(x, _y + 1, tabWidth, _tabHeight - 1,
(i == _activeTab)
? onTop ? kDlgColor : kBGColorLo
: onTop ? kBGColorHi : kDlgColor); // ? kWidColor : kDlgColor
s.drawString(_font, _tabs[i].title, x + kTabPadding + yOffset,
_y + yOffset + (_tabHeight - _lineHeight - 1),
tabWidth - 2 * kTabPadding, fontcolor, TextAlign::Center);
if(i == _activeTab)
{
s.hLine(x, _y, x + tabWidth - 1, onTop ? kWidColor : kDlgColor);
s.vLine(x + tabWidth, _y + 1, _y + _tabHeight - 1, onTop ? kBGColorLo : kColor);
}
else
s.hLine(x, _y + _tabHeight, x + tabWidth, onTop ? kWidColor : kDlgColor);
x += tabWidth + kTabSpacing;
} }
else
s.hLine(x, _y + _tabHeight, x + tabWidth, onTop ? kWidColor : kDlgColor);
x += tabWidth + kTabSpacing; // fill empty right space
s.hLine(x - kTabSpacing + 1, _y + _tabHeight, _x + _w - 1, onTop ? kWidColor : kDlgColor);
s.hLine(_x, _y + _h - 1, _x + _w - 1, onTop ? kBGColorLo : kColor);
clearDirty();
// Make all child widgets of currently active tab dirty
Widget::setDirtyInChain(_tabs[_activeTab].firstWidget);
} }
// fill empty right space
s.hLine(x - kTabSpacing + 1, _y + _tabHeight, _x + _w - 1, onTop ? kWidColor : kDlgColor);
s.hLine(_x, _y + _h - 1, _x + _w - 1, onTop ? kBGColorLo : kColor);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -56,7 +56,41 @@ void Widget::setDirty()
{ {
// A widget being dirty indicates that its parent dialog is dirty // A widget being dirty indicates that its parent dialog is dirty
// So we inform the parent about it // So we inform the parent about it
_boss->dialog().setDirty(); //_boss->dialog().setDirty();
//cerr << "set dirty " << typeid(*this).name() << endl;
_dirty = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Widget::isDirty() const
{
string name = typeid(*this).name();
if(_dirty && name == "class TabWidget")
cerr << "is dirty " << typeid(*this).name() << endl;
return _dirty;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Widget::isChainDirty() const
{
string name = typeid(*this).name();
if(_dirty && name == "class TabWidget")
cerr << "is chain dirty " << typeid(*this).name() << endl;
bool dirty = false;
// Check if widget or any subwidgets are dirty
Widget* w = _firstWidget;
while(!dirty && w)
{
dirty |= w->isDirty();
w = w->_next;
}
return dirty;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -65,60 +99,67 @@ void Widget::draw()
if(!isVisible() || !_boss->isVisible()) if(!isVisible() || !_boss->isVisible())
return; return;
FBSurface& s = _boss->dialog().surface(); if(isDirty())
bool onTop = _boss->dialog().isOnTop();
bool hasBorder = _flags & Widget::FLAG_BORDER; // currently only used by Dialog widget
int oldX = _x, oldY = _y;
// Account for our relative position in the dialog
_x = getAbsX();
_y = getAbsY();
// Clear background (unless alpha blending is enabled)
if(_flags & Widget::FLAG_CLEARBG)
{ {
int x = _x, y = _y, w = _w, h = _h; //cerr << " *** draw widget " << typeid(*this).name() << " ***" << endl;
FBSurface& s = _boss->dialog().surface();
bool onTop = _boss->dialog().isOnTop();
bool hasBorder = _flags & Widget::FLAG_BORDER; // currently only used by Dialog widget
int oldX = _x, oldY = _y;
// Account for our relative position in the dialog
_x = getAbsX();
_y = getAbsY();
// Clear background (unless alpha blending is enabled)
if(_flags & Widget::FLAG_CLEARBG)
{
int x = _x, y = _y, w = _w, h = _h;
if(hasBorder)
{
x++; y++; w -= 2; h -= 2;
}
s.fillRect(x, y, w, h, !onTop ? _bgcolorlo : (_flags & Widget::FLAG_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor);
}
// Draw border
if(hasBorder) if(hasBorder)
{ {
x++; y++; w-=2; h-=2; s.frameRect(_x, _y, _w, _h, !onTop ? kColor : (_flags & Widget::FLAG_HILITED) && isEnabled() ? kWidColorHi : kColor);
_x += 4;
_y += 4;
_w -= 8;
_h -= 8;
} }
s.fillRect(x, y, w, h, !onTop ? _bgcolorlo : (_flags & Widget::FLAG_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor);
// Now perform the actual widget draw
drawWidget((_flags & Widget::FLAG_HILITED) ? true : false);
// Restore x/y
if(hasBorder)
{
_x -= 4;
_y -= 4;
_w += 8;
_h += 8;
}
_x = oldX;
_y = oldY;
} }
// Draw border
if(hasBorder)
{
s.frameRect(_x, _y, _w, _h, !onTop ? kColor : (_flags & Widget::FLAG_HILITED) && isEnabled() ? kWidColorHi : kColor);
_x += 4;
_y += 4;
_w -= 8;
_h -= 8;
}
// Now perform the actual widget draw
drawWidget((_flags & Widget::FLAG_HILITED) ? true : false);
// Restore x/y
if (hasBorder)
{
_x -= 4;
_y -= 4;
_w += 8;
_h += 8;
}
_x = oldX;
_y = oldY;
// Draw all children // Draw all children
Widget* w = _firstWidget; Widget* w = _firstWidget;
while(w) while(w)
{ {
w->draw(); if(w->needsRedraw())
w->draw();
w = w->_next; w = w->_next;
} }
clearDirty();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -290,6 +331,7 @@ void Widget::setDirtyInChain(Widget* start)
{ {
while(start) while(start)
{ {
//cerr << "setDirtyInChain " << typeid(*start).name() << endl;
start->setDirty(); start->setDirty();
start = start->_next; start = start->_next;
} }
@ -345,8 +387,6 @@ void StaticTextWidget::drawWidget(bool hilite)
bool onTop = _boss->dialog().isOnTop(); bool onTop = _boss->dialog().isOnTop();
s.drawString(_font, _label, _x, _y, _w, s.drawString(_font, _label, _x, _y, _w,
isEnabled() && onTop ? _textcolor : kColor, _align, 0, true, _shadowcolor); isEnabled() && onTop ? _textcolor : kColor, _align, 0, true, _shadowcolor);
setDirty();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -454,6 +494,7 @@ void ButtonWidget::setBitmap(const uInt32* bitmap, int bmw, int bmh)
_bmh = bmh; _bmh = bmh;
_bmw = bmw; _bmw = bmw;
cerr << "setBitmap" << endl;
setDirty(); setDirty();
} }
@ -474,8 +515,6 @@ void ButtonWidget::drawWidget(bool hilite)
!(isEnabled() && onTop) ? _textcolorlo : !(isEnabled() && onTop) ? _textcolorlo :
hilite ? _textcolorhi : _textcolor, hilite ? _textcolorhi : _textcolor,
_bmw, _bmh); _bmw, _bmh);
setDirty();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -635,8 +674,6 @@ void CheckboxWidget::drawWidget(bool hilite)
// Finally draw the label // Finally draw the label
s.drawString(_font, _label, _x + prefixSize(_font), _y + _textY, _w, s.drawString(_font, _label, _x + prefixSize(_font), _y + _textY, _w,
onTop && isEnabled() ? kTextColor : kColor); onTop && isEnabled() ? kTextColor : kColor);
setDirty();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -652,7 +689,7 @@ SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font,
_valueLabelWidth(valueLabelWidth), _valueLabelWidth(valueLabelWidth),
_forceLabelSign(forceLabelSign) _forceLabelSign(forceLabelSign)
{ {
_flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE; _flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE | Widget::FLAG_CLEARBG;;
_bgcolor = kDlgColor; _bgcolor = kDlgColor;
_bgcolorhi = kDlgColor; _bgcolorhi = kDlgColor;
@ -870,8 +907,6 @@ void SliderWidget::drawWidget(bool hilite)
if(_valueLabelWidth > 0) if(_valueLabelWidth > 0)
s.drawString(_font, _valueLabel + _valueUnit, _x + _w - _valueLabelWidth, _y + 2, s.drawString(_font, _valueLabel + _valueUnit, _x + _w - _valueLabelWidth, _y + 2,
_valueLabelWidth, isEnabled() ? kTextColor : kColor); _valueLabelWidth, isEnabled() ? kTextColor : kColor);
setDirty();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -83,6 +83,8 @@ class Widget : public GuiObject
virtual bool handleEvent(Event::Type event) { return false; } virtual bool handleEvent(Event::Type event) { return false; }
void setDirty() override; void setDirty() override;
bool isDirty() const override;
bool isChainDirty() const override;
void draw() override; void draw() override;
void receivedFocus(); void receivedFocus();
void lostFocus(); void lostFocus();