diff --git a/doomsday/libdeng2/include/de/data/counted.h b/doomsday/libdeng2/include/de/data/counted.h index bf394f05ff..a5d1e26b9e 100644 --- a/doomsday/libdeng2/include/de/data/counted.h +++ b/doomsday/libdeng2/include/de/data/counted.h @@ -48,11 +48,17 @@ class DENG2_PUBLIC Counted return static_cast(this); } + template + Type const *ref() const { + addRef(); + return static_cast(this); + } + /** * Releases a reference that was acquired earlier with ref(). The * object destroys itself when the reference counter hits zero. */ - void release(); + void release() const; protected: /** @@ -62,22 +68,22 @@ class DENG2_PUBLIC Counted * * @param count Added to the reference counter. */ - void addRef(dint count = 1) { + void addRef(dint count = 1) const { _refCount += count; DENG2_ASSERT(_refCount >= 0); } /** - * When a counted object is destroyed, its reference counter must be - * zero. Note that this is only called from release() when all - * references have been released. + * Non-public destructor. When a counted object is destroyed, its reference + * counter must be zero. Note that this is only called from release() when + * all references have been released. */ virtual ~Counted(); private: /// Number of other things that refer to this object, i.e. have /// a pointer to it. - dint _refCount; + mutable dint _refCount; template friend Type *refless(Type *counted); @@ -95,6 +101,40 @@ inline Type *refless(Type *counted) { return counted; } +/** + * Holds a reference to a Counted object. + * @param counted Counted object. + * @return Same as @a counted (with reference count incremented). + */ +template +inline CountedType *holdRef(CountedType *counted) { + return counted->template ref(); +} + +/** + * Releases a reference to a Counted object. Afterwards, the pointer is cleared + * to NULL. + * + * @param ref Pointer that holds a reference. May be NULL. + */ +template +inline void releaseRef(CountedType *&ref) { + if(ref) ref->release(); + ref = 0; +} + +/** + * Releases a const reference to a Counted object. Afterwards, the pointer is + * cleared to NULL. + * + * @param ref Pointer that holds a reference. May be NULL. + */ +template +inline void releaseRef(CountedType const *&ref) { + if(ref) ref->release(); + ref = 0; +} + } // namespace de #endif /* LIBDENG2_COUNTED_H */ diff --git a/doomsday/libdeng2/include/de/widgets/animation.h b/doomsday/libdeng2/include/de/widgets/animation.h index 07841365b0..421638b22b 100644 --- a/doomsday/libdeng2/include/de/widgets/animation.h +++ b/doomsday/libdeng2/include/de/widgets/animation.h @@ -102,6 +102,13 @@ class Animation : public ISerializable */ float target() const; + /** + * Changes the target value without modifying any other parameters. + * + * @param newTarget Target value. + */ + void adjustTarget(float newTarget); + /** * Number of seconds remaining in the ongoing transition. */ diff --git a/doomsday/libdeng2/include/de/widgets/constantrule.h b/doomsday/libdeng2/include/de/widgets/constantrule.h index 2cc108331c..3a9f79d39d 100644 --- a/doomsday/libdeng2/include/de/widgets/constantrule.h +++ b/doomsday/libdeng2/include/de/widgets/constantrule.h @@ -34,7 +34,7 @@ class ConstantRule : public Rule Q_OBJECT public: - explicit ConstantRule(float constantValue, QObject *parent = 0); + explicit ConstantRule(float constantValue); /** * Changes the value of the constant in the rule. diff --git a/doomsday/libdeng2/include/de/widgets/derivedrule.h b/doomsday/libdeng2/include/de/widgets/derivedrule.h index d833d6bf89..b5282c2c4a 100644 --- a/doomsday/libdeng2/include/de/widgets/derivedrule.h +++ b/doomsday/libdeng2/include/de/widgets/derivedrule.h @@ -33,11 +33,11 @@ class DerivedRule : public ConstantRule Q_OBJECT public: - explicit DerivedRule(Rule const *source, QObject *parent = 0); + explicit DerivedRule(Rule const *source); protected: void update(); - void dependencyReplaced(Rule const *oldRule, Rule const *newRule); + //void dependencyReplaced(Rule const *oldRule, Rule const *newRule); private: Rule const *_source; diff --git a/doomsday/libdeng2/include/de/widgets/operatorrule.h b/doomsday/libdeng2/include/de/widgets/operatorrule.h index 1870d4d733..a84fd8f804 100644 --- a/doomsday/libdeng2/include/de/widgets/operatorrule.h +++ b/doomsday/libdeng2/include/de/widgets/operatorrule.h @@ -43,25 +43,13 @@ class OperatorRule : public Rule }; public: - explicit OperatorRule(Operator op, Rule const *unary, QObject *parent = 0); + explicit OperatorRule(Operator op, Rule const *unary); - /** - * The operator rule takes ownership of the operands that have no parent. - */ - explicit OperatorRule(Operator op, Rule *unaryOwn, QObject *parent = 0); - - explicit OperatorRule(Operator op, Rule const *left, Rule const *right, QObject *parent = 0); - explicit OperatorRule(Operator op, Rule const *left, Rule *rightOwn, QObject *parent = 0); - explicit OperatorRule(Operator op, Rule *leftOwn, Rule const *right, QObject *parent = 0); - - /** - * The operator rule takes ownership of the operands that have no parent. - */ - explicit OperatorRule(Operator op, Rule *leftOwn, Rule *rightOwn, QObject *parent = 0); + explicit OperatorRule(Operator op, Rule const *left, Rule const *right); protected: void update(); - void dependencyReplaced(Rule const *oldRule, Rule const *newRule); + //void dependencyReplaced(Rule const *oldRule, Rule const *newRule); private: Operator _operator; diff --git a/doomsday/libdeng2/include/de/widgets/rectanglerule.h b/doomsday/libdeng2/include/de/widgets/rectanglerule.h index 7d148f1269..3a000fe003 100644 --- a/doomsday/libdeng2/include/de/widgets/rectanglerule.h +++ b/doomsday/libdeng2/include/de/widgets/rectanglerule.h @@ -51,11 +51,11 @@ class RectangleRule : public Rule }; public: - explicit RectangleRule(QObject *parent = 0); + explicit RectangleRule(); /** * Constructs a rectangle rule with individual rules defining the placement - * of the rectangle. Ownership of the input rules is not claimed. + * of the rectangle. References are kept to all non-NULL rules. * * @param left Rule for the left coordinate. * @param top Rule for the top coordinate. @@ -63,11 +63,9 @@ class RectangleRule : public Rule * @param bottom Rule for the bottom coordinate. * @param parent Parent object. */ - explicit RectangleRule(Rule const *left, Rule const *top, Rule const *right, Rule const *bottom, QObject *parent = 0); + explicit RectangleRule(Rule const *left, Rule const *top, Rule const *right, Rule const *bottom); - explicit RectangleRule(RectangleRule const *rect, QObject *parent = 0); - - ~RectangleRule(); + explicit RectangleRule(RectangleRule const *rect); // Output rules. Rule const *left() const; @@ -76,20 +74,10 @@ class RectangleRule : public Rule Rule const *bottom() const; /** - * Sets one of the input rules of the rectangle. If the particular rule has - * previously been defined, the old one is destroyed first. - * - * @param inputRule Input rule to set. - * @param ruleOwn RectangleRule claims ownership (if rule has no parent yet). - */ - RectangleRule &setInput(InputRule inputRule, Rule *ruleOwn); - - /** - * Sets one of the input rules of the rectangle. If the particular rule has - * previously been defined, the old one is destroyed first. + * Sets one of the input rules of the rectangle. * - * @param inputRule Input rule to set. - * @param rule RectangleRule does not take ownership. + * @param inputRule InputRule to set. + * @param rule Rule to use as input. A reference is held. */ RectangleRule &setInput(InputRule inputRule, Rule const *rule); @@ -127,12 +115,13 @@ class RectangleRule : public Rule Rectanglei recti() const; public slots: - void currentTimeChanged(); + void timeChanged(); protected: - void setup(); + ~RectangleRule(); + void update(); - void dependencyReplaced(Rule const *oldRule, Rule const *newRule); + //void dependencyReplaced(Rule const *oldRule, Rule const *newRule); private: struct Instance; diff --git a/doomsday/libdeng2/include/de/widgets/rule.h b/doomsday/libdeng2/include/de/widgets/rule.h index 2e3fbc74da..fe018f230b 100644 --- a/doomsday/libdeng2/include/de/widgets/rule.h +++ b/doomsday/libdeng2/include/de/widgets/rule.h @@ -23,6 +23,7 @@ #include #include #include "../libdeng2.h" +#include "../Counted" namespace de { @@ -35,25 +36,30 @@ namespace de { * - When the value changes, all dependent rules are notified and marked as invalid. * - When a rule is invalid, its current value will be updated (i.e., validated). * - Rules can be replaced dynamically with other rules, see Rule::replace(). + * - Reference counting is used for lifetime management. * * @ingroup widgets */ -class Rule : public QObject +class Rule : public QObject, public Counted { Q_OBJECT public: - explicit Rule(QObject *parent = 0); - explicit Rule(float initialValue, QObject *parent = 0); - ~Rule(); + explicit Rule(float initialValue = 0); + /** + * Determines the rule's current value. If it has been marked invalid, + * the value is updated first (see update()). + */ float value() const; +#if 0 /** * Transfers this rule's dependencies to @a newRule. The dependent rules * are updated accordingly. Afterwards, this rule has no more dependencies. */ void transferDependencies(Rule *toRule); +#endif /** * Updates the rule with a valid value. Derived classes must call @@ -64,50 +70,72 @@ class Rule : public QObject */ virtual void update(); - bool isValid() const; +public slots: + /** + * Marks the rule invalid, causing all dependent rules to be invalid, too. + */ + void invalidate(); protected: + ~Rule(); // Counted + /** - * Links rules together. This rule will depend on @a dependency. + * Links rules together. This rule will depend on @a dependency; if @a + * dependency becomes invalid, this rule will likewise become invalid. + * @a dependency will hold a reference to this rule. */ void dependsOn(Rule const *dependency); + /** + * Unlinks rules. This rule will no longer depend on @a dependency. + * @a dependency will release its reference to this rule. + */ void independentOf(Rule const *dependency); + /** + * Adds a dependent rule. + * + * @param rule Rule that depends on this rule. A reference to @a rule + * is retained. + */ void addDependent(Rule *rule); - void removeDependent(Rule *rule); - void setValue(float value); - - float cachedValue() const; /** - * Takes ownership of a rule. + * Removes a dependent rule. * - * @param child Rule whose ownership should be claimed. + * @param rule Rule that depends on this rule. A reference to @a rule + * is released. + */ + void removeDependent(Rule *rule); + + /** + * Sets the current value of the rule and marks it valid. * - * @return @c true, if ownership was taken. + * @param value New valid value. */ - bool claim(Rule *child); + void setValue(float value); + + float cachedValue() const; +#if 0 /** * Called to notify that the dependency @a oldRule has been replaced with * @a newRule. */ virtual void dependencyReplaced(Rule const *oldRule, Rule const *newRule); +#endif - void invalidateSilently(); - -public slots: - void invalidate(); +signals: + void valueInvalidated(); +#if 0 protected slots: void ruleDestroyed(QObject *rule); - -signals: - void valueInvalidated(); +#endif private: - QSet _dependentRules; + typedef QSet Dependents; + Dependents _dependentRules; // ref'd /// Current value of the rule. float _value; diff --git a/doomsday/libdeng2/include/de/widgets/scalarrule.h b/doomsday/libdeng2/include/de/widgets/scalarrule.h index 719bbf4cd5..cce9032ef1 100644 --- a/doomsday/libdeng2/include/de/widgets/scalarrule.h +++ b/doomsday/libdeng2/include/de/widgets/scalarrule.h @@ -35,14 +35,12 @@ class ScalarRule : public Rule Q_OBJECT public: - explicit ScalarRule(float initialValue, QObject *parent = 0); + explicit ScalarRule(float initialValue); void set(float target, TimeDelta transition = 0); void set(Rule const *target, TimeDelta transition = 0); - void set(Rule *targetOwn, TimeDelta transition = 0); - /** * Read-only access to the scalar animation. */ @@ -52,9 +50,7 @@ class ScalarRule : public Rule protected: void update(); - void dependencyReplaced(Rule const *oldRule, Rule const *newRule); - - void dismissTargetRule(); + //void dependencyReplaced(Rule const *oldRule, Rule const *newRule); protected slots: void timeChanged(); @@ -62,7 +58,6 @@ protected slots: private: Animation _animation; Rule const *_rule; - bool _ruleOwned; }; } // namespace de diff --git a/doomsday/libdeng2/src/data/counted.cpp b/doomsday/libdeng2/src/data/counted.cpp index eb9cb52e0a..2bfc749408 100644 --- a/doomsday/libdeng2/src/data/counted.cpp +++ b/doomsday/libdeng2/src/data/counted.cpp @@ -29,7 +29,7 @@ Counted::~Counted() DENG2_ASSERT(_refCount == 0); } -void Counted::release() +void Counted::release() const { DENG2_ASSERT(_refCount > 0); if(!--_refCount) diff --git a/doomsday/libdeng2/src/widgets/animation.cpp b/doomsday/libdeng2/src/widgets/animation.cpp index ca462fced2..3061dee847 100644 --- a/doomsday/libdeng2/src/widgets/animation.cpp +++ b/doomsday/libdeng2/src/widgets/animation.cpp @@ -222,6 +222,14 @@ float Animation::target() const return d->target; } +void Animation::adjustTarget(float newTarget) +{ + if(!fequal(newTarget, d->target)) + { + setValue(newTarget, remainingTime()); + } +} + TimeDelta Animation::remainingTime() const { Time const now = currentTime(); diff --git a/doomsday/libdeng2/src/widgets/constantrule.cpp b/doomsday/libdeng2/src/widgets/constantrule.cpp index de92e24ee6..8296097761 100644 --- a/doomsday/libdeng2/src/widgets/constantrule.cpp +++ b/doomsday/libdeng2/src/widgets/constantrule.cpp @@ -21,8 +21,8 @@ namespace de { -ConstantRule::ConstantRule(float constantValue, QObject *parent) - : Rule(constantValue, parent), _newValue(constantValue) +ConstantRule::ConstantRule(float constantValue) + : Rule(constantValue), _newValue(constantValue) {} void ConstantRule::set(float newValue) diff --git a/doomsday/libdeng2/src/widgets/derivedrule.cpp b/doomsday/libdeng2/src/widgets/derivedrule.cpp index 0da48786b3..fb0148a92a 100644 --- a/doomsday/libdeng2/src/widgets/derivedrule.cpp +++ b/doomsday/libdeng2/src/widgets/derivedrule.cpp @@ -21,8 +21,8 @@ namespace de { -DerivedRule::DerivedRule(Rule const *source, QObject *parent) - : ConstantRule(0, parent), _source(source) +DerivedRule::DerivedRule(Rule const *source) + : ConstantRule(0), _source(source) { DENG2_ASSERT(source != 0); @@ -40,6 +40,7 @@ void DerivedRule::update() ConstantRule::update(); } +/* void DerivedRule::dependencyReplaced(Rule const *oldRule, Rule const *newRule) { if(_source == oldRule) @@ -47,5 +48,6 @@ void DerivedRule::dependencyReplaced(Rule const *oldRule, Rule const *newRule) _source = newRule; } } +*/ } // namespace de diff --git a/doomsday/libdeng2/src/widgets/operatorrule.cpp b/doomsday/libdeng2/src/widgets/operatorrule.cpp index 9aaae6b0c4..3c91056b6a 100644 --- a/doomsday/libdeng2/src/widgets/operatorrule.cpp +++ b/doomsday/libdeng2/src/widgets/operatorrule.cpp @@ -22,63 +22,20 @@ namespace de { -OperatorRule::OperatorRule(Operator op, Rule const *unary, QObject *parent) - : Rule(parent), _operator(op), _leftOperand(unary), _rightOperand(0) +OperatorRule::OperatorRule(Operator op, Rule const *unary) + : Rule(), _operator(op), _leftOperand(unary), _rightOperand(0) { DENG2_ASSERT(_leftOperand != 0); dependsOn(_leftOperand); } -OperatorRule::OperatorRule(Operator op, Rule *unaryOwn, QObject *parent) - : Rule(parent), _operator(op), _leftOperand(unaryOwn), _rightOperand(0) -{ - DENG2_ASSERT(_leftOperand != 0); - - claim(unaryOwn); - dependsOn(_leftOperand); -} - -OperatorRule::OperatorRule(Operator op, Rule const *left, Rule const *right, QObject *parent) - : Rule(parent), _operator(op), _leftOperand(left), _rightOperand(right) -{ - DENG2_ASSERT(_leftOperand != 0); - DENG2_ASSERT(_rightOperand != 0); - - dependsOn(_leftOperand); - dependsOn(_rightOperand); -} - -OperatorRule::OperatorRule(Operator op, Rule const *left, Rule *rightOwn, QObject *parent) - : Rule(parent), _operator(op), _leftOperand(left), _rightOperand(rightOwn) +OperatorRule::OperatorRule(Operator op, Rule const *left, Rule const *right) + : Rule(), _operator(op), _leftOperand(left), _rightOperand(right) { DENG2_ASSERT(_leftOperand != 0); DENG2_ASSERT(_rightOperand != 0); - claim(rightOwn); - dependsOn(_leftOperand); - dependsOn(_rightOperand); -} - -OperatorRule::OperatorRule(Operator op, Rule *leftOwn, Rule const *right, QObject *parent) - : Rule(parent), _operator(op), _leftOperand(leftOwn), _rightOperand(right) -{ - DENG2_ASSERT(_leftOperand != 0); - DENG2_ASSERT(_rightOperand != 0); - - claim(leftOwn); - dependsOn(_leftOperand); - dependsOn(_rightOperand); -} - -OperatorRule::OperatorRule(Operator op, Rule *leftOwn, Rule *rightOwn, QObject *parent) - : Rule(parent), _operator(op), _leftOperand(leftOwn), _rightOperand(rightOwn) -{ - DENG2_ASSERT(_leftOperand != 0); - DENG2_ASSERT(_rightOperand != 0); - - claim(leftOwn); - claim(rightOwn); dependsOn(_leftOperand); dependsOn(_rightOperand); } @@ -134,6 +91,7 @@ void OperatorRule::update() setValue(v); } +/* void OperatorRule::dependencyReplaced(Rule const *oldRule, Rule const *newRule) { if(_leftOperand == oldRule) @@ -145,5 +103,6 @@ void OperatorRule::dependencyReplaced(Rule const *oldRule, Rule const *newRule) _rightOperand = newRule; } } +*/ } // namespace de diff --git a/doomsday/libdeng2/src/widgets/rectanglerule.cpp b/doomsday/libdeng2/src/widgets/rectanglerule.cpp index 2cbdf53789..c8f6c50c4f 100644 --- a/doomsday/libdeng2/src/widgets/rectanglerule.cpp +++ b/doomsday/libdeng2/src/widgets/rectanglerule.cpp @@ -25,6 +25,7 @@ namespace de { struct RectangleRule::Instance { + /* struct InputRuleRef { union { @@ -50,6 +51,7 @@ struct RectangleRule::Instance return rule.constPtr; } }; + */ RectangleRule &self; @@ -60,132 +62,187 @@ struct RectangleRule::Instance AnimationVector2 normalizedAnchorPoint; - InputRuleRef anchorXRule; - InputRuleRef anchorYRule; - InputRuleRef leftRule; - InputRuleRef topRule; - InputRuleRef rightRule; - InputRuleRef bottomRule; - InputRuleRef widthRule; - InputRuleRef heightRule; - - Instance(RectangleRule &rr) : self(rr) {} + Rule const *inputRules[MAX_RULES]; + /* + Rule const *anchorXRule; + Rule const *anchorYRule; + Rule const *leftRule; + Rule const *topRule; + Rule const *rightRule; + Rule const *bottomRule; + Rule const *widthRule; + Rule const *heightRule; + */ + + Instance(RectangleRule &rr) : self(rr) + { + memset(inputRules, 0, sizeof(inputRules)); + setup(); + } Instance(RectangleRule &rr, Rule const *left, Rule const *top, Rule const *right, Rule const *bottom) - : self(rr), - leftRule(left), - topRule(top), - rightRule(right), - bottomRule(bottom) - {} - - InputRuleRef &ruleRef(InputRule rule) + : self(rr) { - switch(rule) - { - case Left: - return leftRule; + memset(inputRules, 0, sizeof(inputRules)); - case Right: - return rightRule; + inputRules[Left] = left; + inputRules[Top] = top; + inputRules[Right] = right; + inputRules[Bottom] = bottom; - case Top: - return topRule; + setup(); + } - case Bottom: - return bottomRule; + ~Instance() + { + left->release(); + right->release(); + top->release(); + bottom->release(); + } - case Width: - return widthRule; + void setup() + { + // Depend on all specified input rules. + for(int i = 0; i < int(MAX_RULES); ++i) + { + if(inputRules[i]) self.dependsOn(inputRules[i]); + } - case Height: - return heightRule; + // When the application's time changes, check whether this rule + // needs to be invalidated. + //connect(&Clock::appClock(), SIGNAL(timeChanged()), this, SLOT(currentTimeChanged())); - case AnchorX: - return anchorXRule; + // The output rules. + left = new DerivedRule(&self); + right = new DerivedRule(&self); + top = new DerivedRule(&self); + bottom = new DerivedRule(&self); - default: - return anchorYRule; - } + self.invalidate(); } - void setInputRule(InputRule inputRule, Rule *rule, bool owned) + Rule const **ruleRef(InputRule rule) + { + DENG2_ASSERT(rule < MAX_RULES); + return &inputRules[rule]; + } + + void setInputRule(InputRule inputRule, Rule const *rule) { DENG2_ASSERT(rule != 0); - InputRuleRef &input = ruleRef(inputRule); - if(input.rule.ptr) + Rule const **input = ruleRef(inputRule); + if(*input) { - // Move the existing dependencies to the new rule. - //input.rule.ptr->transferDependencies(rule); - - if(input.isOwned) - { - // We own this rule, so let's get rid of it now. - DENG2_ASSERT(input.rule.ptr->parent() == &self); - delete input.rule.ptr; - } + self.independentOf(*input); } - else + + // Define a new dependency. + *input = rule; + self.dependsOn(rule); + } + + void update() + { + // All the edges must be defined, otherwise the rectangle's position is ambiguous. + bool leftDefined = false; + bool topDefined = false; + bool rightDefined = false; + bool bottomDefined = false; + + Rectanglef r; + + if(inputRules[AnchorX] && inputRules[Width]) { - // Define a new dependency. - self.dependsOn(rule); + r.topLeft.x = inputRules[AnchorX]->value() - + normalizedAnchorPoint.x * inputRules[Width]->value(); + r.setWidth(inputRules[Width]->value()); + leftDefined = rightDefined = true; } - input.rule.ptr = rule; - input.isOwned = owned; + if(inputRules[AnchorY] && inputRules[Height]) + { + r.topLeft.y = inputRules[AnchorY]->value() - + normalizedAnchorPoint.y * inputRules[Height]->value(); + r.setHeight(inputRules[Height]->value()); + topDefined = bottomDefined = true; + } - DENG2_ASSERT(input.rule.ptr); - DENG2_ASSERT(!input.isOwned || input.rule.ptr->parent() == &self); - } -}; + if(inputRules[Left]) + { + r.topLeft.x = inputRules[Left]->value(); + leftDefined = true; + } + if(inputRules[Top]) + { + r.topLeft.y = inputRules[Top]->value(); + topDefined = true; + } + if(inputRules[Right]) + { + r.bottomRight.x = inputRules[Right]->value(); + rightDefined = true; + } + if(inputRules[Bottom]) + { + r.bottomRight.y = inputRules[Bottom]->value(); + bottomDefined = true; + } -RectangleRule::RectangleRule(QObject *parent) - : Rule(parent), d(new Instance(*this)) -{ - setup(); -} + if(inputRules[Width] && leftDefined && !rightDefined) + { + r.setWidth(inputRules[Width]->value()); + rightDefined = true; + } + if(inputRules[Width] && !leftDefined && rightDefined) + { + r.topLeft.x = r.bottomRight.x - inputRules[Width]->value(); + leftDefined = true; + } -RectangleRule::RectangleRule(Rule const *left, Rule const *top, Rule const *right, Rule const *bottom, QObject *parent) - : Rule(parent), d(new Instance(*this, left, top, right, bottom)) -{ - setup(); + if(inputRules[Height] && topDefined && !bottomDefined) + { + r.setHeight(inputRules[Height]->value()); + bottomDefined = true; + } + if(inputRules[Height] && !topDefined && bottomDefined) + { + r.topLeft.y = r.bottomRight.y - inputRules[Height]->value(); + topDefined = true; + } - dependsOn(left); - dependsOn(top); - dependsOn(right); - dependsOn(bottom); -} + DENG2_ASSERT(leftDefined); + DENG2_ASSERT(rightDefined); + DENG2_ASSERT(topDefined); + DENG2_ASSERT(bottomDefined); -RectangleRule::RectangleRule(RectangleRule const *rect, QObject *parent) - : Rule(parent), d(new Instance(*this, rect->left(), rect->top(), rect->right(), rect->bottom())) -{ - setup(); + // Update the derived output rules. + left->set(r.topLeft.x); + top->set(r.topLeft.y); + right->set(r.bottomRight.x); + bottom->set(r.bottomRight.y); - dependsOn(d->leftRule); - dependsOn(d->topRule); - dependsOn(d->rightRule); - dependsOn(d->bottomRule); -} + // Mark this rule as valid. + self.setValue(r.width() * r.height()); + } +}; -RectangleRule::~RectangleRule() -{ - delete d; -} +RectangleRule::RectangleRule() + : Rule(), d(new Instance(*this)) +{} -void RectangleRule::setup() -{ - // When the application's time changes, check whether this rule - // needs to be invalidated. - connect(&Clock::appClock(), SIGNAL(timeChanged()), this, SLOT(currentTimeChanged())); +RectangleRule::RectangleRule(Rule const *left, Rule const *top, Rule const *right, Rule const *bottom) + : Rule(), d(new Instance(*this, left, top, right, bottom)) +{} - // The output rules. - d->left = new DerivedRule(this, this); - d->right = new DerivedRule(this, this); - d->top = new DerivedRule(this, this); - d->bottom = new DerivedRule(this, this); +RectangleRule::RectangleRule(RectangleRule const *rect) + : Rule(), d(new Instance(*this, rect->left(), rect->top(), rect->right(), rect->bottom())) +{} - invalidate(); +RectangleRule::~RectangleRule() +{ + delete d; } Rule const *RectangleRule::left() const @@ -208,27 +265,13 @@ Rule const *RectangleRule::bottom() const return d->bottom; } -RectangleRule &RectangleRule::setInput(InputRule inputRule, Rule *ruleOwn) -{ - DENG2_ASSERT(ruleOwn != 0); - - // Claim ownership. - bool owned = false; - if(claim(ruleOwn)) - { - owned = true; - } - - d->setInputRule(inputRule, ruleOwn, owned); - return *this; -} - RectangleRule &RectangleRule::setInput(InputRule inputRule, Rule const *rule) { - d->setInputRule(inputRule, const_cast(rule), false); + d->setInputRule(inputRule, rule); return *this; } +/* void RectangleRule::dependencyReplaced(Rule const *oldRule, Rule const *newRule) { for(int i = 0; i < MAX_RULES; ++i) @@ -240,105 +283,36 @@ void RectangleRule::dependencyReplaced(Rule const *oldRule, Rule const *newRule) } } } +*/ Rule const *RectangleRule::inputRule(InputRule inputRule) { - return d->ruleRef(inputRule).rule.constPtr; + return *d->ruleRef(inputRule); } void RectangleRule::setAnchorPoint(Vector2f const &normalizedPoint, TimeDelta const &transition) { d->normalizedAnchorPoint.setValue(normalizedPoint, transition); invalidate(); -} - -void RectangleRule::update() -{ - // All the edges must be defined, otherwise the rectangle's position is ambiguous. - bool leftDefined = false; - bool topDefined = false; - bool rightDefined = false; - bool bottomDefined = false; - - Rectanglef r; - - if(d->anchorXRule && d->widthRule) - { - r.topLeft.x = d->anchorXRule.value() - d->normalizedAnchorPoint.x * d->widthRule.value(); - r.setWidth(d->widthRule.value()); - leftDefined = rightDefined = true; - } - - if(d->anchorYRule && d->heightRule) - { - r.topLeft.y = d->anchorYRule.value() - d->normalizedAnchorPoint.y * d->heightRule.value(); - r.setHeight(d->heightRule.value()); - topDefined = bottomDefined = true; - } - if(d->leftRule) - { - r.topLeft.x = d->leftRule.value(); - leftDefined = true; - } - if(d->topRule) - { - r.topLeft.y = d->topRule.value(); - topDefined = true; - } - if(d->rightRule) - { - r.bottomRight.x = d->rightRule.value(); - rightDefined = true; - } - if(d->bottomRule) - { - r.bottomRight.y = d->bottomRule.value(); - bottomDefined = true; - } - - if(d->widthRule && leftDefined && !rightDefined) - { - r.setWidth(d->widthRule.value()); - rightDefined = true; - } - if(d->widthRule && !leftDefined && rightDefined) + if(transition > 0.0) { - r.topLeft.x = r.bottomRight.x - d->widthRule.value(); - leftDefined = true; + connect(&Clock::appClock(), SIGNAL(timeChanged()), this, SLOT(timeChanged())); } +} - if(d->heightRule && topDefined && !bottomDefined) - { - r.setHeight(d->heightRule.value()); - bottomDefined = true; - } - if(d->heightRule && !topDefined && bottomDefined) - { - r.topLeft.y = r.bottomRight.y - d->heightRule.value(); - topDefined = true; - } - - DENG2_ASSERT(leftDefined); - DENG2_ASSERT(rightDefined); - DENG2_ASSERT(topDefined); - DENG2_ASSERT(bottomDefined); - - // Update the derived output rules. - d->left->set(r.topLeft.x); - d->top->set(r.topLeft.y); - d->right->set(r.bottomRight.x); - d->bottom->set(r.bottomRight.y); - - // Mark this rule as valid. - setValue(r.width() * r.height()); +void RectangleRule::update() +{ + d->update(); } -void RectangleRule::currentTimeChanged() +void RectangleRule::timeChanged() { - if(!d->normalizedAnchorPoint.done()) + invalidate(); + + if(d->normalizedAnchorPoint.done()) { - invalidate(); + disconnect(this, SLOT(timeChanged())); } } diff --git a/doomsday/libdeng2/src/widgets/rootwidget.cpp b/doomsday/libdeng2/src/widgets/rootwidget.cpp index 62bb1cad82..0e32cc6852 100644 --- a/doomsday/libdeng2/src/widgets/rootwidget.cpp +++ b/doomsday/libdeng2/src/widgets/rootwidget.cpp @@ -25,13 +25,19 @@ namespace de { struct RootWidget::Instance { - std::auto_ptr viewWidth; - std::auto_ptr viewHeight; + ConstantRule *viewWidth; + ConstantRule *viewHeight; Instance() { - viewWidth.reset(new ConstantRule(0)); - viewHeight.reset(new ConstantRule(0)); + viewWidth = new ConstantRule(0); + viewHeight = new ConstantRule(0); + } + + ~Instance() + { + de::releaseRef(viewWidth); + de::releaseRef(viewHeight); } Vector2i viewSize() const @@ -63,12 +69,12 @@ void RootWidget::setViewSize(Vector2i const &size) Rule const *RootWidget::viewWidth() const { - return d->viewWidth.get(); + return d->viewWidth; } Rule const *RootWidget::viewHeight() const { - return d->viewHeight.get(); + return d->viewHeight; } void RootWidget::initialize() diff --git a/doomsday/libdeng2/src/widgets/rule.cpp b/doomsday/libdeng2/src/widgets/rule.cpp index ffaa1d7bb2..13e792a338 100644 --- a/doomsday/libdeng2/src/widgets/rule.cpp +++ b/doomsday/libdeng2/src/widgets/rule.cpp @@ -21,20 +21,16 @@ namespace de { -Rule::Rule(QObject *parent) - : QObject(parent), _value(0), _isValid(true) -{} - -Rule::Rule(float initialValue, QObject *parent) - : QObject(parent), _value(initialValue), _isValid(true) +Rule::Rule(float initialValue) + : QObject(), _value(initialValue), _isValid(true) {} Rule::~Rule() { - // Notify of a dependency going away. - foreach(Rule *rule, _dependentRules) + // Release references to the dependent rules. + DENG2_FOR_EACH(Dependents, i, _dependentRules) { - rule->dependencyReplaced(this, 0); + (*i)->release(); } } @@ -45,6 +41,8 @@ float Rule::value() const // Force an update. const_cast(this)->update(); } + + // It must be valid now, after the update. DENG2_ASSERT(_isValid); return _value; @@ -56,20 +54,12 @@ void Rule::update() _isValid = true; } -bool Rule::isValid() const -{ - return _isValid; -} - +#if 0 void Rule::dependencyReplaced(Rule const *, Rule const *) { // No dependencies. } - -void Rule::invalidateSilently() -{ - _isValid = false; -} +#endif float Rule::cachedValue() const { @@ -82,6 +72,7 @@ void Rule::setValue(float v) _isValid = true; } +#if 0 void Rule::transferDependencies(Rule *toRule) { foreach(Rule *rule, _dependentRules) @@ -98,6 +89,7 @@ void Rule::transferDependencies(Rule *toRule) DENG2_ASSERT(_dependentRules.isEmpty()); } +#endif void Rule::dependsOn(Rule const *dependency) { @@ -117,43 +109,39 @@ void Rule::addDependent(Rule *rule) { DENG2_ASSERT(!_dependentRules.contains(rule)); - connect(rule, SIGNAL(destroyed(QObject *)), this, SLOT(ruleDestroyed(QObject *))); + //connect(rule, SIGNAL(destroyed(QObject *)), this, SLOT(ruleDestroyed(QObject *))); connect(this, SIGNAL(valueInvalidated()), rule, SLOT(invalidate())); - _dependentRules.insert(rule); + // Acquire a reference. + _dependentRules.insert(de::holdRef(rule)); } void Rule::removeDependent(Rule *rule) { DENG2_ASSERT(_dependentRules.contains(rule)); + disconnect(rule, SLOT(invalidate())); + _dependentRules.remove(rule); + de::releaseRef(rule); - disconnect(rule, SLOT(invalidate())); - rule->disconnect(this, SLOT(ruleDestroyed(QObject *))); + //rule->disconnect(this, SLOT(ruleDestroyed(QObject *))); } void Rule::invalidate() { if(_isValid) { - invalidateSilently(); + _isValid = false; emit valueInvalidated(); } } +#if 0 void Rule::ruleDestroyed(QObject *rule) { removeDependent(static_cast(rule)); } - -bool Rule::claim(Rule *child) -{ - if(!child->parent()) - { - child->setParent(this); - } - return (child->parent() == this); -} +#endif } // namespace de diff --git a/doomsday/libdeng2/src/widgets/scalarrule.cpp b/doomsday/libdeng2/src/widgets/scalarrule.cpp index 10d2d055bd..7af78051c4 100644 --- a/doomsday/libdeng2/src/widgets/scalarrule.cpp +++ b/doomsday/libdeng2/src/widgets/scalarrule.cpp @@ -23,15 +23,20 @@ namespace de { -ScalarRule::ScalarRule(float initialValue, QObject *parent) - : Rule(initialValue, parent), _animation(initialValue), _rule(0), _ruleOwned(false) +ScalarRule::ScalarRule(float initialValue) + : Rule(initialValue), _animation(initialValue), _rule(0) {} void ScalarRule::set(float target, de::TimeDelta transition) { - dismissTargetRule(); + if(_rule) + { + independentOf(_rule); + _rule = 0; + } connect(&_animation.clock(), SIGNAL(timeChanged()), this, SLOT(timeChanged())); + _animation.setValue(target, transition); invalidate(); } @@ -40,25 +45,23 @@ void ScalarRule::set(Rule const *target, TimeDelta transition) { set(target->value(), transition); - _ruleOwned = false; - _rule = target; - dependsOn(_rule); -} - -void ScalarRule::set(Rule *targetOwn, TimeDelta transition) -{ - set(targetOwn->value(), transition); - - _ruleOwned = claim(targetOwn); - _rule = targetOwn; + // Keep a reference. dependsOn(_rule); + _rule = target; } void ScalarRule::update() { + // When using a rule for the target, keep it updated. + if(_rule) + { + _animation.adjustTarget(_rule->value()); + } + setValue(_animation); } +#if 0 void ScalarRule::dependencyReplaced(Rule const *oldRule, Rule const *newRule) { if(oldRule == _rule) @@ -67,24 +70,12 @@ void ScalarRule::dependencyReplaced(Rule const *oldRule, Rule const *newRule) oldRule = newRule; } } - -void ScalarRule::dismissTargetRule() -{ - if(_rule) - { - independentOf(_rule); - if(_ruleOwned) delete _rule; - _rule = 0; - } - _ruleOwned = false; -} +#endif void ScalarRule::timeChanged() { - if(!_animation.done() || cachedValue() != _animation.value()) - { - invalidate(); - } + invalidate(); + if(_animation.done()) { disconnect(this, SLOT(timeChanged())); diff --git a/doomsday/tools/shell/shell-text/src/shellapp.cpp b/doomsday/tools/shell/shell-text/src/shellapp.cpp index 7069924c2f..95ad5a05b8 100644 --- a/doomsday/tools/shell/shell-text/src/shellapp.cpp +++ b/doomsday/tools/shell/shell-text/src/shellapp.cpp @@ -34,8 +34,8 @@ struct ShellApp::Instance anim->set(5, 2); logWidget->rule() - .setInput(RectangleRule::Left, anim) - .setInput(RectangleRule::Top, new ConstantRule(0)) + .setInput(RectangleRule::Left, de::refless(anim)) + .setInput(RectangleRule::Top, de::refless(new ConstantRule(0))) .setInput(RectangleRule::Width, self.rootWidget().viewWidth()) .setInput(RectangleRule::Height, self.rootWidget().viewHeight()); diff --git a/doomsday/tools/shell/shell-text/src/textwidget.cpp b/doomsday/tools/shell/shell-text/src/textwidget.cpp index abfbfec1d1..b83a2cdd83 100644 --- a/doomsday/tools/shell/shell-text/src/textwidget.cpp +++ b/doomsday/tools/shell/shell-text/src/textwidget.cpp @@ -29,7 +29,7 @@ struct TextWidget::Instance ~Instance() { - delete rule; + de::releaseRef(rule); } }; @@ -65,8 +65,8 @@ TextCanvas *TextWidget::targetCanvas() const void TextWidget::setRule(de::RectangleRule *rule) { - delete d->rule; - d->rule = rule; + de::releaseRef(d->rule); + d->rule = de::holdRef(rule); } de::RectangleRule &TextWidget::rule()