blob: 23f3fceb7c13058b9c6ff8669b6962e8517edbc9 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.idea.rendering.multi;
import com.android.tools.idea.configurations.RenderContext;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.android.tools.idea.rendering.ShadowPainter.SHADOW_SIZE;
import static com.android.tools.idea.rendering.multi.RenderPreviewManager.HORIZONTAL_GAP;
import static com.android.tools.idea.rendering.multi.RenderPreviewManager.VERTICAL_GAP;
/**
* Regular row layout for render previews
*/
public class PreviewRowLayout {
private final @NotNull List<RenderPreview> myPreviews;
private final @NotNull RenderContext myRenderContext;
private final boolean myFixedOrder;
public PreviewRowLayout(@NotNull List<RenderPreview> previews, @NotNull RenderContext renderContext, boolean fixedOrder) {
myPreviews = previews;
myRenderContext = renderContext;
myFixedOrder = fixedOrder;
}
private int myLayoutHeight;
public void performLayout() {
// TODO: Separate layout heuristics for portrait and landscape orientations (though
// it also depends on the dimensions of the canvas window, which determines the
// shape of the leftover space)
Rectangle clientArea = myRenderContext.getClientArea();
Dimension scaledImageSize = myRenderContext.getScaledImageSize();
int scaledImageWidth = scaledImageSize.width;
int scaledImageHeight = scaledImageSize.height;
int availableWidth = clientArea.width;
int availableHeight = clientArea.height;
int maxVisibleY = clientArea.y + clientArea.height;
int bottomBorder = scaledImageHeight + SHADOW_SIZE;
int rightHandSide = scaledImageWidth + HORIZONTAL_GAP + SHADOW_SIZE;
int nextY = 0;
// First lay out images across the top right hand side
int x = rightHandSide;
int y = 0;
boolean wrapped = false;
int vgap = VERTICAL_GAP;
for (RenderPreview preview : myPreviews) {
// If we have forked previews, double the vgap to allow space for two labels
if (preview.isForked()) {
vgap *= 2;
break;
}
}
List<RenderPreview> aspectOrder;
if (!myFixedOrder) {
aspectOrder = new ArrayList<RenderPreview>(myPreviews);
Collections.sort(aspectOrder, RenderPreview.INCREASING_ASPECT_RATIO);
}
else {
aspectOrder = myPreviews;
}
for (RenderPreview preview : aspectOrder) {
if (x > 0 && x + preview.getLayoutWidth() > availableWidth) {
x = rightHandSide;
int prevY = y;
y = nextY;
if ((prevY <= bottomBorder || y <= bottomBorder) && Math.max(nextY, y + preview.getLayoutHeight()) > bottomBorder) {
// If there's really no visible room below, don't bother
// Similarly, don't wrap individually scaled views
if (bottomBorder < availableHeight - 40 && preview.getScale() < 1.2) {
// If it's closer to the top row than the bottom, just
// mark the next row for left justify instead
if (bottomBorder - y > y + preview.getLayoutHeight() - bottomBorder) {
rightHandSide = 0;
wrapped = true;
}
else if (!wrapped) {
y = nextY = Math.max(nextY, bottomBorder + vgap);
x = rightHandSide = 0;
wrapped = true;
}
}
}
}
if (x > 0 && y <= bottomBorder && Math.max(nextY, y + preview.getLayoutHeight()) > bottomBorder) {
//noinspection StatementWithEmptyBody
if (clientArea.height - bottomBorder < preview.getLayoutHeight()) {
// No room below the device on the left; just continue on the
// bottom row
}
else if (preview.getScale() < 1.2) {
if (bottomBorder - y > y + preview.getLayoutHeight() - bottomBorder) {
rightHandSide = 0;
wrapped = true;
}
else {
y = nextY = Math.max(nextY, bottomBorder + vgap);
x = rightHandSide = 0;
wrapped = true;
}
}
}
preview.setPosition(x, y);
if (y > maxVisibleY && maxVisibleY > 0) {
preview.setVisible(false);
}
else if (!preview.isVisible()) {
preview.setVisible(true);
}
x += preview.getLayoutWidth();
x += HORIZONTAL_GAP;
nextY = Math.max(nextY, y + preview.getLayoutHeight() + vgap);
}
myLayoutHeight = nextY;
}
public int getLayoutHeight() {
return myLayoutHeight;
}
}