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
color = '#5555ff'
elseif level == LogInfo then
color = '#55ff55'
color = '#5555ff'
elseif level == LogWarning then
color = '#ffff00'
else
color = '#ff0000'
end
Console.addLine(message, color)
if level ~= LogDebug then
Console.addLine(message, color)
end
logLocked = false
end
@ -35,12 +37,17 @@ function Console.addLine(text, color)
label:setStyle('ConsoleLabel')
label:setText(text)
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
if numLines > maxLines then
local firstLine = console:getChildByIndex(0)
firstLine:destroy()
local firstLabel = console:getChildByIndex(-1)
firstLabel:destroy()
end
end

View File

@ -1,7 +1,7 @@
ConsoleLabel < UILabel
font: terminus-14px-bold
height: 16
anchors.bottom: next.top
anchors.bottom: commandBox.top
anchors.left: parent.left
anchors.right: parent.right
margin.left: 2
@ -13,6 +13,7 @@ RectPanel
anchors.fill: parent
UILabel
id: commandSymbolLabel
size: 18 20
anchors.bottom: parent.bottom
anchors.left: parent.left

View File

@ -20,7 +20,7 @@ void Logger::log(LogLevel level, std::string message)
m_logMessages.push_back(LogMessage(level, message, now));
if(m_onLog)
g_dispatcher.addEvent(std::bind(m_onLog, level, message, now));
m_onLog(level, message, now);
}
if(level == LogFatal) {
@ -46,7 +46,8 @@ void Logger::logFunc(LogLevel level, const std::string& message, std::string pre
void Logger::fireOldMessages()
{
if(m_onLog) {
for(const LogMessage& logMessage : m_logMessages)
g_dispatcher.addEvent(std::bind(m_onLog, logMessage.level, logMessage.message, logMessage.when));
auto backup = m_logMessages;
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>("getChildById", &UIWidget::getChildById);
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>("removeChild", &UIWidget::removeChild);
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);

View File

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

View File

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