/* * 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; } }