much faster layout calculation

This commit is contained in:
Eduardo Bart 2011-08-22 22:08:36 -03:00
parent bfa3903940
commit 3c72c844d2
6 changed files with 125 additions and 70 deletions

View File

@ -15,14 +15,16 @@ function Console.onLog(level, message, time)
if level == LogDebug then if level == LogDebug then
color = '#5555ff' color = '#5555ff'
elseif level == LogInfo then elseif level == LogInfo then
color = '#55ff55' color = '#5555ff'
elseif level == LogWarning then elseif level == LogWarning then
color = '#ffff00' color = '#ffff00'
else else
color = '#ff0000' color = '#ff0000'
end end
Console.addLine(message, color) if level ~= LogDebug then
Console.addLine(message, color)
end
logLocked = false logLocked = false
end end
@ -35,12 +37,17 @@ function Console.addLine(text, color)
label:setStyle('ConsoleLabel') label:setStyle('ConsoleLabel')
label:setText(text) label:setText(text)
label:setForegroundColor(color) label:setForegroundColor(color)
console:insertChild(label, -1) console:insertChild(3, label)
local lastLabel = console:getChildByIndex(4)
if lastLabel then
lastLabel:addAnchor(AnchorBottom, "prev", AnchorTop)
end
numLines = numLines + 1 numLines = numLines + 1
if numLines > maxLines then if numLines > maxLines then
local firstLine = console:getChildByIndex(0) local firstLabel = console:getChildByIndex(-1)
firstLine:destroy() firstLabel:destroy()
end end
end end

View File

@ -1,7 +1,7 @@
ConsoleLabel < UILabel ConsoleLabel < UILabel
font: terminus-14px-bold font: terminus-14px-bold
height: 16 height: 16
anchors.bottom: next.top anchors.bottom: commandBox.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
margin.left: 2 margin.left: 2
@ -13,6 +13,7 @@ RectPanel
anchors.fill: parent anchors.fill: parent
UILabel UILabel
id: commandSymbolLabel
size: 18 20 size: 18 20
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
@ -32,4 +33,4 @@ RectPanel
function(self) function(self)
Console.executeCommand(self:getText()) Console.executeCommand(self:getText())
self:clearText() self:clearText()
end end

View File

@ -20,7 +20,7 @@ void Logger::log(LogLevel level, std::string message)
m_logMessages.push_back(LogMessage(level, message, now)); m_logMessages.push_back(LogMessage(level, message, now));
if(m_onLog) if(m_onLog)
g_dispatcher.addEvent(std::bind(m_onLog, level, message, now)); m_onLog(level, message, now);
} }
if(level == LogFatal) { if(level == LogFatal) {
@ -46,7 +46,8 @@ void Logger::logFunc(LogLevel level, const std::string& message, std::string pre
void Logger::fireOldMessages() void Logger::fireOldMessages()
{ {
if(m_onLog) { if(m_onLog) {
for(const LogMessage& logMessage : m_logMessages) auto backup = m_logMessages;
g_dispatcher.addEvent(std::bind(m_onLog, logMessage.level, logMessage.message, logMessage.when)); for(const LogMessage& logMessage : backup)
m_onLog(logMessage.level, logMessage.message, logMessage.when);
} }
} }

View File

@ -44,6 +44,7 @@ void LuaInterface::registerFunctions()
g_lua.bindClassMemberFunction<UIWidget>("addAnchor", &UIWidget::addAnchor); g_lua.bindClassMemberFunction<UIWidget>("addAnchor", &UIWidget::addAnchor);
g_lua.bindClassMemberFunction<UIWidget>("getChildById", &UIWidget::getChildById); g_lua.bindClassMemberFunction<UIWidget>("getChildById", &UIWidget::getChildById);
g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex); g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex);
g_lua.bindClassMemberFunction<UIWidget>("getChildCount", &UIWidget::getChildCount);
g_lua.bindClassMemberFunction<UIWidget>("insertChild", &UIWidget::insertChild); g_lua.bindClassMemberFunction<UIWidget>("insertChild", &UIWidget::insertChild);
g_lua.bindClassMemberFunction<UIWidget>("removeChild", &UIWidget::removeChild); g_lua.bindClassMemberFunction<UIWidget>("removeChild", &UIWidget::removeChild);
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild); g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);

View File

@ -32,6 +32,7 @@ UIWidget::UIWidget()
UIWidget::~UIWidget() UIWidget::~UIWidget()
{ {
//logTraceDebug(m_id);
if(!m_destroyed) { if(!m_destroyed) {
logWarning("widget '", m_id, "' was destructed without being explicit destroyed"); logWarning("widget '", m_id, "' was destructed without being explicit destroyed");
internalDestroy(); internalDestroy();
@ -40,6 +41,7 @@ UIWidget::~UIWidget()
void UIWidget::destroy() void UIWidget::destroy()
{ {
//logTraceDebug(m_id);
// destroy only once // destroy only once
if(!m_destroyed) { if(!m_destroyed) {
internalDestroy(); internalDestroy();
@ -52,10 +54,12 @@ void UIWidget::destroy()
void UIWidget::internalDestroy() void UIWidget::internalDestroy()
{ {
//logTraceDebug(m_id);
// first release lua table, because it may contains references to children // first release lua table, because it may contains references to children
releaseLuaFieldsTable(); releaseLuaFieldsTable();
// clear other references // clear other references
clearHookedWidgets();
m_lockedChildren.clear(); m_lockedChildren.clear();
m_anchors.clear(); m_anchors.clear();
m_anchoredWidgets.clear(); m_anchoredWidgets.clear();
@ -79,12 +83,14 @@ void UIWidget::internalDestroyCheck()
// collect lua garbage before checking // collect lua garbage before checking
g_lua.collectGarbage(); g_lua.collectGarbage();
//logTraceDebug(m_id);
// get real use count // get real use count
int realUseCount = shared_from_this().use_count() - 2; int realUseCount = shared_from_this().use_count() - 2;
// check for leaks upon widget destruction // check for leaks upon widget destruction
if(realUseCount > 0) if(realUseCount > 0)
logWarning("destroyed widget with id '",m_id,"', but it still have ",realUseCount," references left"); {}
//logWarning("destroyed widget with id '",m_id,"', but it still have ",realUseCount," references left");
} }
void UIWidget::render() void UIWidget::render()
@ -122,6 +128,7 @@ void UIWidget::setParent(const UIWidgetPtr& parent)
{ {
assert(!m_destroyed); assert(!m_destroyed);
//logTraceDebug(m_id);
UIWidgetPtr self = asUIWidget(); UIWidgetPtr self = asUIWidget();
// remove from old parent // remove from old parent
@ -144,6 +151,7 @@ void UIWidget::setParent(const UIWidgetPtr& parent)
void UIWidget::applyStyle(const std::string& styleName) void UIWidget::applyStyle(const std::string& styleName)
{ {
//logTraceDebug(m_id);
try { try {
OTMLNodePtr styleNode = g_ui.getStyle(styleName); OTMLNodePtr styleNode = g_ui.getStyle(styleName);
onStyleApply(styleNode); onStyleApply(styleNode);
@ -160,7 +168,7 @@ void UIWidget::setRect(const Rect& rect)
m_rect = rect; m_rect = rect;
// updates children geometry // updates children geometry
updateChildrenLayout(); internalUpdateChildrenLayout();
// avoid massive update events // avoid massive update events
if(!m_updateEventScheduled) { if(!m_updateEventScheduled) {
@ -285,12 +293,13 @@ UIWidgetPtr UIWidget::getChildByPos(const Point& childPos)
return nullptr; return nullptr;
} }
UIWidgetPtr UIWidget::getChildByIndex(int childIndex) UIWidgetPtr UIWidget::getChildByIndex(int index)
{ {
assert(!m_destroyed); assert(!m_destroyed);
if(childIndex >= 0 && childIndex < getChildCount()) index = index <= 0 ? (m_children.size() + index) : index-1;
return m_children.at(childIndex); if(index >= 0 && (uint)index < m_children.size())
return m_children.at(index);
return nullptr; return nullptr;
} }
@ -358,6 +367,7 @@ void UIWidget::addChild(const UIWidgetPtr& child)
{ {
assert(!m_destroyed); assert(!m_destroyed);
//logTraceDebug(m_id);
if(!child) if(!child)
return; return;
@ -367,30 +377,29 @@ void UIWidget::addChild(const UIWidgetPtr& child)
child->setParent(asUIWidget()); child->setParent(asUIWidget());
// recalculate anchors // recalculate anchors
getRootParent()->recalculateAnchoredWidgets(); child->clearHookedWidgets();
child->computeHookedWidgets();
// may need to update children layout child->updateLayout();
updateChildrenLayout();
// always focus new children // always focus new children
if(child->isFocusable() && child->isExplicitlyVisible() && child->isExplicitlyEnabled()) if(child->isFocusable() && child->isExplicitlyVisible() && child->isExplicitlyEnabled())
focusChild(child, UI::ActiveFocusReason); focusChild(child, UI::ActiveFocusReason);
} }
void UIWidget::insertChild(const UIWidgetPtr& child, int index) void UIWidget::insertChild(int index, const UIWidgetPtr& child)
{ {
assert(!m_destroyed); assert(!m_destroyed);
//logTraceDebug(m_id);
// skip null children // skip null children
if(!child) if(!child)
return; return;
assert(!hasChild(child)); assert(!hasChild(child));
if(index < 0) index = index <= 0 ? (m_children.size() + index) : index-1;
index = m_children.size() + index -1;
assert((uint)index <= m_children.size()); assert(index >= 0 && (uint)index <= m_children.size());
// retrieve child by index // retrieve child by index
auto it = m_children.begin() + index; auto it = m_children.begin() + index;
@ -398,16 +407,16 @@ void UIWidget::insertChild(const UIWidgetPtr& child, int index)
child->setParent(asUIWidget()); child->setParent(asUIWidget());
// recalculate anchors // recalculate anchors
getRootParent()->recalculateAnchoredWidgets(); child->clearHookedWidgets();
child->computeHookedWidgets();
// may need to update children layout child->updateLayout();
updateChildrenLayout();
} }
void UIWidget::removeChild(const UIWidgetPtr& child) void UIWidget::removeChild(const UIWidgetPtr& child)
{ {
assert(!m_destroyed); assert(!m_destroyed);
//logTraceDebug(m_id);
// skip null children // skip null children
if(!child) if(!child)
return; return;
@ -429,10 +438,7 @@ void UIWidget::removeChild(const UIWidgetPtr& child)
child->setParent(nullptr); child->setParent(nullptr);
// recalculate anchors // recalculate anchors
getRootParent()->recalculateAnchoredWidgets(); child->clearHookedWidgets();
// may need to update children layout
updateChildrenLayout();
} }
void UIWidget::focusNextChild(UI::FocusReason reason) void UIWidget::focusNextChild(UI::FocusReason reason)
@ -534,10 +540,12 @@ void UIWidget::unlockChild(const UIWidgetPtr& child)
} }
} }
void UIWidget::updateLayout() void UIWidget::updateLayout()
{ {
assert(!m_destroyed); assert(!m_destroyed);
//logTraceDebug(m_id);
if(!m_layoutUpdateScheduled) { if(!m_layoutUpdateScheduled) {
m_layoutUpdateScheduled = true; m_layoutUpdateScheduled = true;
UIWidgetPtr self = asUIWidget(); UIWidgetPtr self = asUIWidget();
@ -553,8 +561,11 @@ void UIWidget::updateChildrenLayout()
{ {
assert(!m_destroyed); assert(!m_destroyed);
//logTraceDebug(m_id);
if(!m_childrenLayoutUpdateScheduled) { if(!m_childrenLayoutUpdateScheduled) {
m_childrenLayoutUpdateScheduled = true; m_childrenLayoutUpdateScheduled = true;
// reset all children anchors update state
resetLayoutUpdateState(false);
UIWidgetPtr self = asUIWidget(); UIWidgetPtr self = asUIWidget();
g_dispatcher.addEvent([self] { g_dispatcher.addEvent([self] {
self->m_childrenLayoutUpdateScheduled = false; self->m_childrenLayoutUpdateScheduled = false;
@ -568,27 +579,40 @@ bool UIWidget::addAnchor(AnchorEdge edge, const std::string& hookedWidgetId, Anc
{ {
assert(!m_destroyed); assert(!m_destroyed);
//logTraceDebug(m_id);
UIAnchor anchor(edge, hookedWidgetId, hookedEdge); UIAnchor anchor(edge, hookedWidgetId, hookedEdge);
UIWidgetPtr hookedWidget = backwardsGetWidgetById(hookedWidgetId); UIWidgetPtr hookedWidget = backwardsGetWidgetById(hookedWidgetId);
anchor.setHookedWidget(hookedWidget);
// we can never anchor with itself if(hookedWidget) {
if(hookedWidget == asUIWidget()) { anchor.setHookedWidget(hookedWidget);
logError("anchoring with itself is not possible");
return false; // we can never anchor with itself
if(hookedWidget == asUIWidget()) {
logError("anchoring with itself is not possible");
return false;
}
// we must never anchor to an anchor child
//TODO: this check
if(hookedWidget)
hookedWidget->addAnchoredWidget(asUIWidget());
} }
// we must never anchor to an anchor child
//TODO: this check
// duplicated anchors must be replaced // duplicated anchors must be replaced
for(auto it = m_anchors.begin(); it != m_anchors.end(); ++it) { auto it = std::find_if(m_anchors.begin(), m_anchors.end(),
const UIAnchor& otherAnchor = *it; [&](const UIAnchor& other) {
if(otherAnchor.getAnchoredEdge() == edge) { return (other.getAnchoredEdge() == edge);
m_anchors.erase(it); });
break;
if(it != m_anchors.end()) {
UIAnchor& other = *it;
if(other.getHookedWidget()) {
other.getHookedWidget()->removeAnchoredWidget(asUIWidget());
other.setHookedWidget(nullptr);
} }
m_anchors.erase(it);
} }
m_anchors.push_back(anchor); m_anchors.push_back(anchor);
@ -619,6 +643,7 @@ void UIWidget::internalUpdateLayout()
{ {
assert(!m_destroyed); assert(!m_destroyed);
//logTraceDebug(m_id);
for(const UIAnchor& anchor : m_anchors) { for(const UIAnchor& anchor : m_anchors) {
// ignore invalid anchors // ignore invalid anchors
if(!anchor.getHookedWidget()) if(!anchor.getHookedWidget())
@ -699,52 +724,71 @@ void UIWidget::internalUpdateChildrenLayout()
{ {
assert(!m_destroyed); assert(!m_destroyed);
// reset all children anchors update state //logTraceDebug(m_id);
resetLayoutUpdateState(false);
// update children layouts // update children layouts
for(const UIWidgetWeakPtr& anchoredWidgetWeak : m_anchoredWidgets) { for(const UIWidgetPtr& anchoredWidget : m_anchoredWidgets)
if(UIWidgetPtr anchoredWidget = anchoredWidgetWeak.lock()) anchoredWidget->internalUpdateLayout();
anchoredWidget->internalUpdateLayout();
}
} }
void UIWidget::resetLayoutUpdateState(bool resetOwn) void UIWidget::resetLayoutUpdateState(bool resetOwn)
{ {
assert(!m_destroyed);
//logTraceDebug(m_id);
if(resetOwn) if(resetOwn)
m_layoutUpdated = false; m_layoutUpdated = false;
// resets children layout update state too // resets children layout update state too
for(const UIWidgetWeakPtr& anchoredWidgetWeak : m_anchoredWidgets) { for(const UIWidgetPtr& anchoredWidget : m_anchoredWidgets)
if(UIWidgetPtr anchoredWidget = anchoredWidgetWeak.lock()) anchoredWidget->resetLayoutUpdateState(true);
anchoredWidget->resetLayoutUpdateState(true);
}
} }
void UIWidget::addAnchoredWidget(const UIWidgetPtr& widget) void UIWidget::addAnchoredWidget(const UIWidgetPtr& widget)
{ {
assert(!m_destroyed);
//logTraceDebug(m_id);
// prevent duplicated anchored widgets // prevent duplicated anchored widgets
for(const UIWidgetWeakPtr& anchoredWidget : m_anchoredWidgets) for(const UIWidgetPtr& anchoredWidget : m_anchoredWidgets)
if(anchoredWidget.lock() == widget) if(anchoredWidget == widget)
return; return;
m_anchoredWidgets.push_back(widget); m_anchoredWidgets.push_back(widget);
} }
void UIWidget::recalculateAnchoredWidgets() void UIWidget::removeAnchoredWidget(const UIWidgetPtr& widget)
{ {
clearAnchoredWidgets(); assert(!m_destroyed);
computeAnchoredWidgets();
//logTraceDebug(m_id);
auto it = std::find(m_anchoredWidgets.begin(), m_anchoredWidgets.end(), widget);
if(it != m_anchoredWidgets.end())
m_anchoredWidgets.erase(it);
} }
void UIWidget::clearAnchoredWidgets() void UIWidget::clearHookedWidgets()
{ {
m_anchoredWidgets.clear(); assert(!m_destroyed);
//logTraceDebug(m_id);
for(UIAnchor& anchor : m_anchors) {
UIWidgetPtr hookedWidget = anchor.getHookedWidget();
if(hookedWidget) {
hookedWidget->removeAnchoredWidget(asUIWidget());
anchor.setHookedWidget(nullptr);
}
}
for(const UIWidgetPtr& child : m_children) for(const UIWidgetPtr& child : m_children)
child->clearAnchoredWidgets(); child->clearHookedWidgets();
} }
void UIWidget::computeAnchoredWidgets() void UIWidget::computeHookedWidgets()
{ {
assert(!m_destroyed);
//logTraceDebug(m_id);
// update anchors's hooked widget // update anchors's hooked widget
for(UIAnchor& anchor : m_anchors) { for(UIAnchor& anchor : m_anchors) {
UIWidgetPtr hookedWidget = backwardsGetWidgetById(anchor.getHookedWidgetId()); UIWidgetPtr hookedWidget = backwardsGetWidgetById(anchor.getHookedWidgetId());
@ -754,7 +798,7 @@ void UIWidget::computeAnchoredWidgets()
} }
for(const UIWidgetPtr& child : m_children) for(const UIWidgetPtr& child : m_children)
child->computeAnchoredWidgets(); child->computeHookedWidgets();
} }
void UIWidget::onStyleApply(const OTMLNodePtr& styleNode) void UIWidget::onStyleApply(const OTMLNodePtr& styleNode)
@ -766,6 +810,7 @@ void UIWidget::onStyleApply(const OTMLNodePtr& styleNode)
// id // id
if(node->tag() == "id") { if(node->tag() == "id") {
setId(node->value()); setId(node->value());
//logTraceDebug(m_id);
} }
// background image // background image
else if(node->tag() == "image") { else if(node->tag() == "image") {

View File

@ -92,13 +92,13 @@ public:
UIWidgetPtr getChildBefore(const UIWidgetPtr& relativeChild); UIWidgetPtr getChildBefore(const UIWidgetPtr& relativeChild);
UIWidgetPtr getChildById(const std::string& childId); UIWidgetPtr getChildById(const std::string& childId);
UIWidgetPtr getChildByPos(const Point& childPos); UIWidgetPtr getChildByPos(const Point& childPos);
UIWidgetPtr getChildByIndex(int childIndex); UIWidgetPtr getChildByIndex(int index);
UIWidgetPtr recursiveGetChildById(const std::string& id); UIWidgetPtr recursiveGetChildById(const std::string& id);
UIWidgetPtr recursiveGetChildByPos(const Point& childPos); UIWidgetPtr recursiveGetChildByPos(const Point& childPos);
UIWidgetPtr backwardsGetWidgetById(const std::string& id); UIWidgetPtr backwardsGetWidgetById(const std::string& id);
void addChild(const UIWidgetPtr& child); void addChild(const UIWidgetPtr& child);
void insertChild(const UIWidgetPtr& child, int index); void insertChild(int index, const UIWidgetPtr& child);
void removeChild(const UIWidgetPtr& child); void removeChild(const UIWidgetPtr& child);
void focusChild(const UIWidgetPtr& child, UI::FocusReason reason); void focusChild(const UIWidgetPtr& child, UI::FocusReason reason);
void focusNextChild(UI::FocusReason reason); void focusNextChild(UI::FocusReason reason);
@ -123,9 +123,9 @@ private:
void internalUpdateChildrenLayout(); void internalUpdateChildrenLayout();
void addAnchoredWidget(const UIWidgetPtr& widget); void addAnchoredWidget(const UIWidgetPtr& widget);
void recalculateAnchoredWidgets(); void removeAnchoredWidget(const UIWidgetPtr& widget);
void clearAnchoredWidgets(); void computeHookedWidgets();
void computeAnchoredWidgets(); void clearHookedWidgets();
void resetLayoutUpdateState(bool resetOwn); void resetLayoutUpdateState(bool resetOwn);
bool m_layoutUpdated; bool m_layoutUpdated;
@ -165,7 +165,7 @@ protected:
bool m_destroyed; bool m_destroyed;
Rect m_rect; Rect m_rect;
UIAnchorList m_anchors; UIAnchorList m_anchors;
UIWeakWidgetList m_anchoredWidgets; UIWidgetList m_anchoredWidgets;
UIWidgetWeakPtr m_parent; UIWidgetWeakPtr m_parent;
UIWidgetList m_children; UIWidgetList m_children;
UIWidgetList m_lockedChildren; UIWidgetList m_lockedChildren;