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();
if(force)
{
clear();
//clear();
myOSystem.launcher().draw(force);
}
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);
}
setDirty();
clearDirty();
}

View File

@ -149,6 +149,35 @@ void Dialog::center()
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)
{
@ -192,7 +221,9 @@ void Dialog::positionAt(uInt32 pos)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Dialog::render()
{
if(!_dirty || !isVisible())
//assert(_dirty);
if(!isVisible() || !needsRedraw())
return false;
// Draw this dialog
@ -207,7 +238,7 @@ bool Dialog::render()
surface->render();
});
}
_dirty = false;
//_dirty = false;
return true;
}
@ -371,37 +402,49 @@ void Dialog::drawDialog()
FBSurface& s = surface();
// Dialog is still on top if e.g a ContextMenu is opened
_onTop = parent().myDialogStack.top() == this
|| (parent().myDialogStack.get(parent().myDialogStack.size() - 2) == this
&& !parent().myDialogStack.top()->hasTitle());
if(_flags & Widget::FLAG_CLEARBG)
if(isDirty())
{
// cerr << "Dialog::drawDialog(): w = " << _w << ", h = " << _h << " @ " << &s << endl << endl;
s.fillRect(_x, _y + _th, _w, _h - _th, _onTop ? kDlgColor : kBGColorLo);
if(_th)
{
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();
if(_flags & Widget::FLAG_BORDER) // currently only used by Dialog itself
s.frameRect(_x, _y, _w, _h, _onTop ? kColor : kShadowColor);
//cerr << "*** draw dialog " << typeid(*this).name() << " ***" << endl;
// Dialog is still on top if e.g a ContextMenu is opened
_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;
s.fillRect(_x, _y + _th, _w, _h - _th, _onTop ? kDlgColor : kBGColorLo);
if(_th)
{
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::setDirtyInChain(w);
// Draw all children
w = _firstWidget;
while(w)
{
w->draw();
// only redraw changed widgets
if(w->needsRedraw())
w->draw();
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
// redrawn and then re-rendered; this is taken care of in ::render()
void setDirty() override { _dirty = true; }
bool isDirty() const { return _dirty; }
void setDirty() override;
bool isDirty() const override;
bool isChainDirty() const override;
bool render();
void addFocusWidget(Widget* w) override;
@ -235,7 +236,7 @@ class Dialog : public GuiObject
int _tabID{0};
int _flags{0};
bool _dirty{false};
//bool _dirty{false};
uInt32 _max_w{0}; // maximum wanted width
uInt32 _max_h{0}; // maximum wanted height

View File

@ -91,21 +91,32 @@ void DialogContainer::updateTime(uInt64 time)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool DialogContainer::draw(bool full)
{
cerr << "draw " << full << endl;
if(myDialogStack.empty())
return false;
// Make the top dialog dirty if a full redraw is requested
if(full)
myDialogStack.top()->setDirty();
//if(full)
// myDialogStack.top()->setDirty();
// If the top dialog is dirty, then all below it must be redrawn too
const bool dirty = needsRedraw();
//if(dirty)
// myDialogStack.top()->setDirty();
myDialogStack.applyAll([&](Dialog*& d){
if(dirty)
d->setDirty();
full |= d->render();
});
//myDialogStack.applyAll([&](Dialog*& d){
// if(dirty)
// d->setDirty();
// full |= d->render();
//});
//if(dirty)
{
myDialogStack.applyAll([&](Dialog*& d) {
if(d->needsRedraw())
//d->setDirty();
full |= d->render();
});
}
return full;
}
@ -113,7 +124,9 @@ bool DialogContainer::draw(bool full)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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");
else
{
// fade out current top dialog
if(!myDialogStack.empty())
myDialogStack.top()->setDirty();
d->setDirty();
myDialogStack.push(d);
}
@ -145,8 +161,16 @@ void DialogContainer::removeDialog()
if(!myDialogStack.empty())
{
myDialogStack.pop();
// necessary as long as all dialogs share the same surface
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 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 */
virtual void addFocusWidget(Widget* w) = 0;
@ -104,6 +108,7 @@ class GuiObject : public CommandReceiver
protected:
int _x{0}, _y{0}, _w{0}, _h{0};
bool _dirty{false};
Widget* _firstWidget{nullptr};
WidgetArray _focusList;

View File

@ -315,6 +315,7 @@ void ScrollBarWidget::drawWidget(bool hilite)
s.fillRect(_x + 1, _y + _sliderPos - 1, _w - 2, _sliderHeight + 2,
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)
// and a dialog (it contains other widgets). Because of the latter,
// it must assume responsibility for refreshing all its children.
Widget::setDirtyInChain(_tabs[_activeTab].firstWidget);
FBSurface& s = dialog().surface();
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)
if(isDirty())
{
int tabWidth = _tabs[i].tabWidth ? _tabs[i].tabWidth : _tabWidth;
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)
FBSurface& s = dialog().surface();
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)
{
s.hLine(x, _y, x + tabWidth - 1, onTop ? kWidColor : kDlgColor);
s.vLine(x + tabWidth, _y + 1, _y + _tabHeight - 1, onTop ? kBGColorLo : kColor);
int tabWidth = _tabs[i].tabWidth ? _tabs[i].tabWidth : _tabWidth;
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
// 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())
return;
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)
if(isDirty())
{
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)
{
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
Widget* w = _firstWidget;
while(w)
{
w->draw();
if(w->needsRedraw())
w->draw();
w = w->_next;
}
clearDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -290,6 +331,7 @@ void Widget::setDirtyInChain(Widget* start)
{
while(start)
{
//cerr << "setDirtyInChain " << typeid(*start).name() << endl;
start->setDirty();
start = start->_next;
}
@ -345,8 +387,6 @@ void StaticTextWidget::drawWidget(bool hilite)
bool onTop = _boss->dialog().isOnTop();
s.drawString(_font, _label, _x, _y, _w,
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;
_bmw = bmw;
cerr << "setBitmap" << endl;
setDirty();
}
@ -474,8 +515,6 @@ void ButtonWidget::drawWidget(bool hilite)
!(isEnabled() && onTop) ? _textcolorlo :
hilite ? _textcolorhi : _textcolor,
_bmw, _bmh);
setDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -635,8 +674,6 @@ void CheckboxWidget::drawWidget(bool hilite)
// Finally draw the label
s.drawString(_font, _label, _x + prefixSize(_font), _y + _textY, _w,
onTop && isEnabled() ? kTextColor : kColor);
setDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -652,7 +689,7 @@ SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font,
_valueLabelWidth(valueLabelWidth),
_forceLabelSign(forceLabelSign)
{
_flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE;
_flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE | Widget::FLAG_CLEARBG;;
_bgcolor = kDlgColor;
_bgcolorhi = kDlgColor;
@ -870,8 +907,6 @@ void SliderWidget::drawWidget(bool hilite)
if(_valueLabelWidth > 0)
s.drawString(_font, _valueLabel + _valueUnit, _x + _w - _valueLabelWidth, _y + 2,
_valueLabelWidth, isEnabled() ? kTextColor : kColor);
setDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

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