Example #1
0
// Positions a floating element within this block box.
void LayoutBlockBox::PositionFloat(Element* element, float offset)
{
	Vector2f box_position;
	PositionBox(box_position);

	space->PositionBox(box_position.y + offset, element);
}
// Generates and sets the position for a floating box of a given size within our block box.
float LayoutBlockBoxSpace::PositionBox(float cursor, Element* element)
{
	Vector2f element_size = element->GetBox().GetSize(Box::MARGIN);
	int float_property = element->GetProperty< int >(FLOAT);

	// Shift the cursor down (if necessary) so it isn't placed any higher than a previously-floated box.
	for (int i = 0; i < NUM_ANCHOR_EDGES; ++i)
	{
		if (!boxes[i].empty())
			cursor = Math::Max(cursor, boxes[i].back().offset.y);
	}

	// Shift the cursor down past to clear boxes, if necessary.
	cursor = ClearBoxes(cursor, element->GetProperty< int >(CLEAR));

	// Find a place to put this box.
	Vector2f element_offset;
	PositionBox(element_offset, cursor, element_size, float_property);

	// It's been placed, so we can now add it to our list of floating boxes.
	boxes[float_property == FLOAT_LEFT ? LEFT : RIGHT].push_back(SpaceBox(element_offset, element_size));

	// Set our offset and dimensions (if necessary) so they enclose the new box.
	Vector2f normalised_offset = element_offset - (parent->GetPosition() + parent->GetBox().GetPosition());
	offset.x = Math::Min(offset.x, normalised_offset.x);
	offset.y = Math::Min(offset.y, normalised_offset.y);
	dimensions.x = Math::Max(dimensions.x, normalised_offset.x + element_size.x);
	dimensions.y = Math::Max(dimensions.y, normalised_offset.y + element_size.y);

	// Shift the offset into the correct space relative to the element's offset parent.
	element_offset += Vector2f(element->GetBox().GetEdge(Box::MARGIN, Box::LEFT), element->GetBox().GetEdge(Box::MARGIN, Box::TOP));
	element->SetOffset(element_offset - parent->GetOffsetParent()->GetPosition(), parent->GetOffsetParent()->GetElement());

	return element_offset.y + element_size.y;
}
Example #3
0
// Adds an element to this block box to be handled as an absolutely-positioned element.
void LayoutBlockBox::AddAbsoluteElement(Element* element)
{
	ROCKET_ASSERT(context == BLOCK);

	AbsoluteElement absolute_element;
	absolute_element.element = element;

	PositionBox(absolute_element.position, 0);

	// If we have an open inline-context block box as our last child, then the absolute element must appear after it,
	// but not actually close the box.
	if (!block_boxes.empty()
		&& block_boxes.back()->context == INLINE)
	{
		LayoutBlockBox* inline_context_box = block_boxes.back();
		float last_line_height = inline_context_box->line_boxes.back()->GetDimensions().y;

		absolute_element.position.y += (inline_context_box->box_cursor + Math::Max(0.0f, last_line_height));
	}

	// Find the positioned parent for this element.
	LayoutBlockBox* absolute_parent = this;
	while (absolute_parent != absolute_parent->offset_parent)
		absolute_parent = absolute_parent->parent;

	absolute_parent->absolute_elements.push_back(absolute_element);
}
Example #4
0
// Returns the offset from the top-left corner of this box for the next line.
void LayoutBlockBox::PositionLineBox(Vector2f& box_position, float& box_width, bool& _wrap_content, const Vector2f& dimensions) const
{
	Vector2f cursor;
	PositionBox(cursor);

	space->PositionBox(box_position, box_width, cursor.y, dimensions);

	// Also, probably shouldn't check for widths when positioning the box?
	_wrap_content = wrap_content;
}
// Generates the position for a box of a given size within a containing block box.
void LayoutBlockBoxSpace::PositionBox(Vector2f& box_position, float& box_width, float cursor, const Vector2f& dimensions) const
{
	box_width = PositionBox(box_position, cursor, dimensions);
}
// Generates the position for an arbitrary box within our space layout, floated against either the left or right edge.
float LayoutBlockBoxSpace::PositionBox(Vector2f& box_position, float cursor, const Vector2f& dimensions, int float_property) const
{
	float parent_scrollbar_width = parent->GetElement()->GetElementScroll()->GetScrollbarSize(ElementScroll::VERTICAL);
	float parent_origin = parent->GetPosition().x + parent->GetBox().GetPosition(Box::CONTENT).x;
	float parent_edge = parent->GetBox().GetSize().x + parent_origin - parent_scrollbar_width;

	AnchorEdge box_edge = float_property == FLOAT_RIGHT ? RIGHT : LEFT;

	box_position.y = cursor;
	box_position.x = box_edge == LEFT ? 0 : (parent->GetBox().GetSize().x - dimensions.x) - parent_scrollbar_width;
	box_position.x += parent_origin;

	float next_cursor = FLT_MAX;

	// First up; we iterate through all boxes that share our edge, pushing ourself to the side of them if we intersect
	// them. We record the height of the lowest box that gets in our way; in the event we can't be positioned at this
	// height, we'll reposition ourselves at that height for the next iteration.
	for (size_t i = 0; i < boxes[box_edge].size(); ++i)
	{
		const SpaceBox& fixed_box = boxes[box_edge][i];

		// If the fixed box's bottom edge is above our top edge, then we can safely skip it.
		if (fixed_box.offset.y + fixed_box.dimensions.y <= box_position.y)
			continue;

		// If the fixed box's top edge is below our bottom edge, then we can safely skip it.
		if (fixed_box.offset.y >= box_position.y + dimensions.y)
			continue;

		// We're intersecting this box vertically, so the box is pushed to the side if necessary.
		bool collision = false;
		if (box_edge == LEFT)
		{
			float right_edge = fixed_box.offset.x + fixed_box.dimensions.x;
			collision = box_position.x < right_edge;
			if (collision)
				box_position.x = right_edge;
		}
		else
		{
			collision = box_position.x + dimensions.x > fixed_box.offset.x;
			if (collision)
				box_position.x = fixed_box.offset.x - dimensions.x;
		}

		// If there was a collision, then we *might* want to remember the height of this box if it is the earliest-
		// terminating box we've collided with so far.
		if (collision)
		{
			next_cursor = Math::Min(next_cursor, fixed_box.offset.y + fixed_box.dimensions.y);

			// Were we pushed out of our containing box? If so, try again at the next cursor position.
			float normalised_position = box_position.x - parent_origin;
			if (normalised_position < 0 ||
				normalised_position + dimensions.x > parent->GetBox().GetSize().x)
				return PositionBox(box_position, next_cursor + 0.00001f, dimensions, float_property);
		}
	}

	// Second; we go through all of the boxes on the other edge, checking for horizontal collisions and determining the
	// maximum width the box can stretch to, if it is placed at this location.
	float maximum_box_width = box_edge == LEFT ? parent_edge - box_position.x : box_position.x + dimensions.x;

	for (size_t i = 0; i < boxes[1 - box_edge].size(); ++i)
	{
		const SpaceBox& fixed_box = boxes[1 - box_edge][i];

		// If the fixed box's bottom edge is above our top edge, then we can safely skip it.
		if (fixed_box.offset.y + fixed_box.dimensions.y <= box_position.y)
			continue;

		// If the fixed box's top edge is below our bottom edge, then we can safely skip it.
		if (fixed_box.offset.y >= box_position.y + dimensions.y)
			continue;

		// We intersect this box vertically, so check if it intersects horizontally.
		bool collision = false;
		if (box_edge == LEFT)
		{
			maximum_box_width = Math::Min(maximum_box_width, fixed_box.offset.x - box_position.x);
			collision = box_position.x + dimensions.x > fixed_box.offset.x;
		}
		else
		{
			maximum_box_width = Math::Min(maximum_box_width, (box_position.x + dimensions.x) - (fixed_box.offset.x + fixed_box.dimensions.x));
			collision = box_position.x < fixed_box.offset.x + fixed_box.dimensions.x;
		}

		// If we collided with this box ... d'oh! We'll try again lower down the page, at the highest bottom-edge of
		// any of the boxes we've been pushed around by so far.
		if (collision)
		{
			next_cursor = Math::Min(next_cursor, fixed_box.offset.y + fixed_box.dimensions.y);
			return PositionBox(box_position, next_cursor + 0.00001f, dimensions, float_property);
		}
	}

	// Third; we go through all of the boxes (on both sides), checking for vertical collisions.
	for (int i = 0; i < 2; ++i)
	{
		for (size_t j = 0; j < boxes[i].size(); ++j)
		{
			const SpaceBox& fixed_box = boxes[i][j];

			// If the fixed box's bottom edge is above our top edge, then we can safely skip it.
			if (fixed_box.offset.y + fixed_box.dimensions.y <= box_position.y)
				continue;

			// If the fixed box's top edge is below our bottom edge, then we can safely skip it.
			if (fixed_box.offset.y >= box_position.y + dimensions.y)
				continue;

			// We collide vertically; if we also collide horizontally, then we have to try again further down the
			// layout. If the fixed box's left edge is to right of our right edge, then we can safely skip it.
			if (fixed_box.offset.x >= box_position.x + dimensions.x)
				continue;

			// If the fixed box's right edge is to the left of our left edge, then we can safely skip it.
			if (fixed_box.offset.x + fixed_box.dimensions.x <= box_position.x)
				continue;

			// D'oh! We hit this box. Ah well; we'll try again lower down the page, at the highest bottom-edge of any
			// of the boxes we've been pushed around by so far.
			next_cursor = Math::Min(next_cursor, fixed_box.offset.y + fixed_box.dimensions.y);
			return PositionBox(box_position, next_cursor + 0.00001f, dimensions, float_property);
		}
	}

	// Looks like we've found a winner!
	return maximum_box_width;
}
Example #7
0
// Returns the offset from the top-left corner of this box's offset element the next child block box, of the given
// dimensions, will be positioned at. This will include the margins on the new block box.
void LayoutBlockBox::PositionBlockBox(Vector2f& box_position, const Box& box, int clear_property) const
{
	PositionBox(box_position, box.GetEdge(Box::MARGIN, Box::TOP), clear_property);
	box_position.x += box.GetEdge(Box::MARGIN, Box::LEFT);
	box_position.y += box.GetEdge(Box::MARGIN, Box::TOP);
}