Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/policy application issues #1693

Merged
merged 5 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 62 additions & 32 deletions lively.morphic/components/policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ export function replace (replacedSiblingName, props) {
function handleTextProps (props) {
if (arr.intersect(
['text', 'label', Text, Label], withSuperclasses(props.type)).length === 0) { return props; }
if (props.textAndAttributes) {
delete props.textString;
delete props.value;
}
if (props.textString) {
props.textAndAttributes = [props.textString, null];
delete props.textString;
Expand Down Expand Up @@ -450,7 +454,12 @@ export class StylePolicy {
if (targetMorph._lastIndex && !obj.equals(targetMorph._lastIndex, currIndex)) {
const limitExtent = bpStore.getLimitExtent(currIndex);
const actualExtent = targetMorph.extent;
targetMorph.withMetaDo({ metaInteraction: true, reconcileChanges: false, doNotFit: true }, () => {
targetMorph.withMetaDo({
metaInteraction: true, // do not record
reconcileChanges: false,
doNotFit: true,
doNotOverride: true
}, () => {
const origLayoutableFlag = targetMorph.isLayoutable;
targetMorph.isLayoutable = false; // avoid any resizing interference here
targetMorph.extent = limitExtent;
Expand All @@ -467,8 +476,17 @@ export class StylePolicy {
})();
}

getLastMatchingBreakpoint (target) {
let curr = this;
let matchingBreakpoint;
while (curr = curr.getMatchingBreakpointMaster(target)) {
matchingBreakpoint = curr = curr.stylePolicy || curr;
}
return matchingBreakpoint || curr;
}

needsBreakpointUpdate (target) {
const matchingBreakpoint = this.getMatchingBreakpointMaster(target);
const matchingBreakpoint = this.getLastMatchingBreakpoint(target);
if (typeof matchingBreakpoint === 'undefined') return false;
if (matchingBreakpoint === (target._lastBreakpoint || null)) { return false; }
target._lastBreakpoint = matchingBreakpoint;
Expand Down Expand Up @@ -1273,7 +1291,7 @@ export class StylePolicy {
*/
isPositionedByLayout (aSubmorph) {
const layout = aSubmorph.owner?.layout;
return layout?.name() !== 'Constraint' && layout?.layoutableSubmorphs?.includes(aSubmorph);
return layout && layout.name() !== 'Constraint' && aSubmorph.isLayoutable;
}

/**
Expand All @@ -1282,7 +1300,7 @@ export class StylePolicy {
* @returns { boolean | object } Wether or not size is controlled via layout and if so, the concrete policy.
*/
isResizedByLayout (aSubmorph) {
const layout = aSubmorph.owner && aSubmorph.owner.layout;
let layout = aSubmorph.owner && aSubmorph.owner.layout;
let heightPolicy = 'fixed'; let widthPolicy = 'fixed';
if (aSubmorph.isText) {
if (!aSubmorph.fixedHeight) heightPolicy = 'hug';
Expand All @@ -1293,6 +1311,19 @@ export class StylePolicy {
if (widthPolicy !== 'hug') widthPolicy = layout.getResizeWidthPolicyFor(aSubmorph);
if (heightPolicy === 'fill' || widthPolicy === 'fill') return { widthPolicy, heightPolicy };
}

layout = aSubmorph.layout;

if (layout?.hugContentsVertically ||
layout?.hugContentsHorizontally ||
widthPolicy === 'hug' ||
heightPolicy === 'hug') {
return {
widthPolicy: layout?.hugContentsHorizontally ? 'hug' : widthPolicy,
heightPolicy: layout?.hugContentsVertically ? 'hug' : heightPolicy
};
}

return false;
}

Expand Down Expand Up @@ -1391,11 +1422,21 @@ export class PolicyApplicator extends StylePolicy {
}

synthesizeSubSpec (submorphNameInPolicyContext, parentOfScope, previousTarget) {
const subSpec = super.synthesizeSubSpec(submorphNameInPolicyContext, parentOfScope, previousTarget);
if (subSpec.isPolicy && !subSpec.isPolicyApplicator) {
return new PolicyApplicator({}, subSpec);
let synthesized = super.synthesizeSubSpec(submorphNameInPolicyContext, parentOfScope, previousTarget);
if (synthesized.isPolicy && !synthesized.isPolicyApplicator) {
return new PolicyApplicator({}, synthesized);
}
synthesized = sanitizeSpec(synthesized);
if ('width' in synthesized && synthesized.extent?.isPoint) {
synthesized.extent = synthesized.extent.withX(synthesized.width);
delete synthesized.width;
}
return subSpec;

if ('height' in synthesized && synthesized.extent?.isPoint) {
synthesized.extent = synthesized.extent.withY(synthesized.height);
delete synthesized.height;
}
return synthesized;
}

applyIfNeeded (needsUpdate = false, animationConfig = false) {
Expand Down Expand Up @@ -1472,11 +1513,20 @@ export class PolicyApplicator extends StylePolicy {
continue;
}

if (this.isPositionedByLayout(morphToBeStyled) && propName === 'position') continue;
if (propName === 'position' && this.isPositionedByLayout(morphToBeStyled)) continue;
let resizePolicy;
if (propName === 'extent' && (resizePolicy = this.isResizedByLayout(morphToBeStyled))) {
if (resizePolicy.widthPolicy === 'fixed' && morphToBeStyled.width !== propValue.x) morphToBeStyled.width = propValue.x;
if (resizePolicy.heightPolicy === 'fixed' && morphToBeStyled.height !== propValue.y) morphToBeStyled.height = propValue.y;
morphToBeStyled.withMetaDo({ deferLayoutApplication: true }, () => {
if (resizePolicy.widthPolicy === 'fixed' && morphToBeStyled.width !== propValue.x) {
morphToBeStyled.width = propValue.x;
}
if (resizePolicy.heightPolicy === 'fixed' && morphToBeStyled.height !== propValue.y) {
morphToBeStyled.height = propValue.y;
}
if (morphToBeStyled.isText && (resizePolicy.widthPolicy === 'hug' || resizePolicy.heightPolicy === 'hug')) {
morphToBeStyled.withMetaDo({ doNotFit: false }, () => morphToBeStyled.fit());
}
});
continue;
}

Expand All @@ -1491,32 +1541,11 @@ export class PolicyApplicator extends StylePolicy {
if (propName === 'position') continue;
}

// FIXME: other special cases??
if (morphToBeStyled.isText && propName === 'extent') {
if (!morphToBeStyled.fixedWidth && !morphToBeStyled.fixedHeight) continue;
if (!morphToBeStyled.fixedWidth) propValue = propValue.withX(morphToBeStyled.width);
if (!morphToBeStyled.fixedHeight) propValue = propValue.withY(morphToBeStyled.height);
}

if (morphToBeStyled.isText && propName === 'width' && morphToBeStyled.lineWrapping !== 'no-wrap') {
if (!morphToBeStyled.fixedWidth) continue;
morphToBeStyled.width = propValue;
morphToBeStyled.withMetaDo({ doNotFit: false }, () => morphToBeStyled.fit());
}

if (['border', 'borderTop', 'borderBottom', 'borderRight', 'borderLeft'].includes(propName)) continue; // handled by sub props;

if (!obj.equals(morphToBeStyled[propName], propValue)) {
morphToBeStyled[propName] = propValue;
}

// we may be late for the game when setting these props
// se we need to make sure, we restore the morphs "intended extent"
// for this purpose we enforce the masterSubmorph extent
if (['fixedHeight', 'fixedWidth'].includes(propName) &&
morphToBeStyled._parametrizedProps?.extent) {
morphToBeStyled.extent = morphToBeStyled._parametrizedProps.extent;
}
}
}

Expand Down Expand Up @@ -1550,6 +1579,7 @@ export class PolicyApplicator extends StylePolicy {
*/
onMorphChange (changedMorph, change) {
if (change.meta?.metaInteraction ||
change.meta?.doNotOverride ||
!this.targetMorph ||
this.isCurrentlyAnimated(changedMorph)
) return;
Expand Down
14 changes: 9 additions & 5 deletions lively.morphic/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,10 @@ export class TilingLayout extends Layout {
}

scheduleApply (submorph, animation, change = {}) {
if (change.meta?.deferLayoutApplication) {
return;
}

if (!change.meta?.isLayoutAction || !this.container?._yogaNode?.getParent()) {
this._alreadyComputed = false;
}
Expand Down Expand Up @@ -830,10 +834,10 @@ export class TilingLayout extends Layout {
aMorph._yogaNode = Yoga.Node.create(yogaConfig);
if (aMorph.isText) {
aMorph._yogaNode.setMeasureFunc((width, widthMode, height, heightMode) => {
if (aMorph.fixedWidth && widthMode !== 0) aMorph.width = width;
if (aMorph.fixedHeight && heightMode !== 0) aMorph.height = height;
if (aMorph.fixedWidth && widthMode !== 0) aMorph.withMetaDo({ doNotOverride: true }, () => aMorph.width = width);
if (aMorph.fixedHeight && heightMode !== 0) aMorph.withMetaDo({ doNotOverride: true }, () => aMorph.height = height);
if (!aMorph.visible) return { width: aMorph.width, height: aMorph.height };
if (!aMorph.fixedWidth || !aMorph.fixedHeight) aMorph.withMetaDo({ doNotFit: false }, () => aMorph.fit());
if (!aMorph.fixedWidth || !aMorph.fixedHeight) aMorph.withMetaDo({ doNotFit: false, skipRerender: true }, () => aMorph.fitIfNeeded());
if (!aMorph.fixedWidth) width = aMorph.width;
if (!aMorph.fixedHeight) height = aMorph.height;
return { width, height };
Expand Down Expand Up @@ -930,10 +934,10 @@ export class TilingLayout extends Layout {

if (this.container.submorphs.length > 0) {
if (hugContentsVertically && container.height !== height) {
container.withMetaDo({ isLayoutAction: true, skipRender: true }, () => container.height = height);
container.withMetaDo({ isLayoutAction: true, skipRender: true, doNotOverride: true }, () => container.height = height);
}
if (hugContentsHorizontally && container.width !== width) {
container.withMetaDo({ isLayoutAction: true, skipRender: true }, () => container.width = width);
container.withMetaDo({ isLayoutAction: true, skipRender: true, doNotOverride: true }, () => container.width = width);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions lively.morphic/text/morph.js
Original file line number Diff line number Diff line change
Expand Up @@ -2826,8 +2826,7 @@ export class Text extends Morph {
} else if (this.env.renderer) {
if (this.fixedHeight && this.fixedWidth) return;
let textBoundsExtent = this.textBounds().extent();
this.renderingState.needsFit = this.renderingState.needsRemeasure;
this.withMetaDo({ isLayoutAction: true, doNotFit: true }, () => {
this.withMetaDo({ isLayoutAction: true, doNotFit: true, doNotOverride: true }, () => {
if (this.fixedWidth) textBoundsExtent = textBoundsExtent.withX(this.width);
if (this.fixedHeight) textBoundsExtent = textBoundsExtent.withY(this.height);
const newExt = textBoundsExtent.addXY(
Expand All @@ -2836,6 +2835,7 @@ export class Text extends Morph {
);
if (!this.extent.equals(newExt)) {
this.extent = newExt;
this.renderingState.needsFit = this.renderingState.needsRemeasure;
}
});
} else {
Expand Down