Pārlūkot izejas kodu

When changing any of the top/right/bottom/left properties, we now detect if this can affect the element's size and if so dirty the layout.

Michael Ragazzon 3 gadi atpakaļ
vecāks
revīzija
cfae4a2351
3 mainītis faili ar 46 papildinājumiem un 28 dzēšanām
  1. 0 1
      Include/RmlUi/Core/Element.h
  2. 45 27
      Source/Core/Element.cpp
  3. 1 0
      changelog.md

+ 0 - 1
Include/RmlUi/Core/Element.h

@@ -628,7 +628,6 @@ protected:
 
 	/// Forces a re-layout of this element, and any other elements required.
 	virtual void DirtyLayout();
-
 	/// Returns true if the element has been marked as needing a re-layout.
 	virtual bool IsLayoutDirty();
 

+ 45 - 27
Source/Core/Element.cpp

@@ -1735,24 +1735,49 @@ void Element::OnAttributeChange(const ElementAttributes& changed_attributes)
 void Element::OnPropertyChange(const PropertyIdSet& changed_properties)
 {
 	RMLUI_ZoneScoped;
+	const bool top_right_bottom_left_changed = (
+		changed_properties.Contains(PropertyId::Top) ||
+		changed_properties.Contains(PropertyId::Right) ||
+		changed_properties.Contains(PropertyId::Bottom) ||
+		changed_properties.Contains(PropertyId::Left)
+	);
 
+	// See if the document layout needs to be updated.
 	if (!IsLayoutDirty())
 	{
 		// Force a relayout if any of the changed properties require it.
-		const PropertyIdSet changed_properties_forcing_layout = (changed_properties & StyleSheetSpecification::GetRegisteredPropertiesForcingLayout());
-		
-		if(!changed_properties_forcing_layout.Empty())
+		const PropertyIdSet changed_properties_forcing_layout =
+			(changed_properties & StyleSheetSpecification::GetRegisteredPropertiesForcingLayout());
+
+		if (!changed_properties_forcing_layout.Empty())
+		{
 			DirtyLayout();
+		}
+		else if (top_right_bottom_left_changed)
+		{
+			// Normally, the position properties only affect the position of the element and not the layout. Thus, these properties are not registered
+			// as affecting layout. However, when absolutely positioned elements with both left & right, or top & bottom are set to definite values,
+			// they affect the size of the element and thereby also the layout. This layout-dirtying condition needs to be registered manually.
+			using namespace Style;
+			const ComputedValues& computed = GetComputedValues();
+			const bool absolutely_positioned = (computed.position() == Position::Absolute || computed.position() == Position::Fixed);
+			const bool sized_width =
+				(computed.width().type == Width::Auto && computed.left().type != Left::Auto && computed.right().type != Right::Auto);
+			const bool sized_height =
+				(computed.height().type == Height::Auto && computed.top().type != Top::Auto && computed.bottom().type != Bottom::Auto);
+
+			if (absolutely_positioned && (sized_width || sized_height))
+				DirtyLayout();
+		}
 	}
 
-	const bool border_radius_changed = (
-		changed_properties.Contains(PropertyId::BorderTopLeftRadius) ||
-		changed_properties.Contains(PropertyId::BorderTopRightRadius) ||
-		changed_properties.Contains(PropertyId::BorderBottomRightRadius) ||
-		changed_properties.Contains(PropertyId::BorderBottomLeftRadius)
-	);
-
-
+	// Update the position.
+	if (top_right_bottom_left_changed)
+	{
+		UpdateOffset();
+		DirtyAbsoluteOffset();
+	}
+	
 	// Update the visibility.
 	if (changed_properties.Contains(PropertyId::Visibility) ||
 		changed_properties.Contains(PropertyId::Display))
@@ -1772,16 +1797,6 @@ void Element::OnPropertyChange(const PropertyIdSet& changed_properties)
 		}
 	}
 
-	// Update the position.
-	if (changed_properties.Contains(PropertyId::Left) ||
-		changed_properties.Contains(PropertyId::Right) ||
-		changed_properties.Contains(PropertyId::Top) ||
-		changed_properties.Contains(PropertyId::Bottom))
-	{
-		UpdateOffset();
-		DirtyAbsoluteOffset();
-	}
-
 	// Update the z-index.
 	if (changed_properties.Contains(PropertyId::ZIndex))
 	{
@@ -1825,6 +1840,13 @@ void Element::OnPropertyChange(const PropertyIdSet& changed_properties)
 			}
 		}
 	}
+	
+	const bool border_radius_changed = (
+		changed_properties.Contains(PropertyId::BorderTopLeftRadius) ||
+		changed_properties.Contains(PropertyId::BorderTopRightRadius) ||
+		changed_properties.Contains(PropertyId::BorderBottomRightRadius) ||
+		changed_properties.Contains(PropertyId::BorderBottomLeftRadius)
+	);
 
 	// Dirty the background if it's changed.
     if (border_radius_changed ||
@@ -1907,19 +1929,15 @@ void Element::OnChildRemove(Element* /*child*/)
 {
 }
 
-// Forces a re-layout of this element, and any other children required.
 void Element::DirtyLayout()
 {
-	Element* document = GetOwnerDocument();
-	if (document != nullptr)
+	if (Element* document = GetOwnerDocument())
 		document->DirtyLayout();
 }
 
-// Forces a re-layout of this element, and any other children required.
 bool Element::IsLayoutDirty()
 {
-	Element* document = GetOwnerDocument();
-	if (document != nullptr)
+	if (Element* document = GetOwnerDocument())
 		return document->IsLayoutDirty();
 	return false;
 }

+ 1 - 0
changelog.md

@@ -65,6 +65,7 @@ The `<textarea>` and `<input type="text">` elements have been improved in severa
 
 - Scroll and slider elements now use containing block's height instead of width to calculate height-relative values. #314 #321 (thanks @nimble0)
 - Generate warnings when directly nesting flexboxes and other unsupported elements in a top-level formatting context. #320
+- In some situations, changing the `top`/`right`/`bottom`/`left` properties may affect the element's size. These situations are now correctly handled and the layout is updated when needed.
 
 ### Context input