blob: fc73fa333082ab520d84d05e681032cdf45c40ca [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 PreviewBinPackingLayout {
private final @NotNull List<RenderPreview> myPreviews;
private final @NotNull RenderContext myRenderContext;
private final int myX;
private final int myY;
@SuppressWarnings("UnusedDeclaration")
private BinPacker myPacker; // Debug only
public PreviewBinPackingLayout(@NotNull List<RenderPreview> previews, @NotNull RenderContext renderContext, int x, int y) {
myPreviews = previews;
myRenderContext = renderContext;
myX = x;
myY = y;
}
private int myLayoutHeight;
public boolean performLayout() {
Rectangle clientArea = myRenderContext.getClientArea();
Dimension scaledImageSize = myRenderContext.getScaledImageSize();
int scaledImageWidth = scaledImageSize.width;
int scaledImageHeight = scaledImageSize.height;
int availableWidth = clientArea.x + clientArea.width - myX;
int availableHeight = clientArea.y + clientArea.height - myY;
int maxVisibleY = clientArea.y + clientArea.height;
int bottomBorder = scaledImageHeight + SHADOW_SIZE;
int rightHandSide = scaledImageWidth + HORIZONTAL_GAP + SHADOW_SIZE;
int minWidth = Integer.MAX_VALUE;
int minHeight = Integer.MAX_VALUE;
for (RenderPreview preview : myPreviews) {
minWidth = Math.min(minWidth, preview.getLayoutWidth());
minHeight = Math.min(minHeight, preview.getLayoutHeight());
}
BinPacker packer = new BinPacker(minWidth, minHeight);
if (BinPacker.DEBUG) {
myPacker = null;
}
// TODO: Instead of this, just start with client area and occupy scaled image size!
// Add in gap on right and bottom since we'll add that requirement on the width and
// height rectangles too (for spacing)
packer.addSpace(new Rectangle(rightHandSide, 0, availableWidth - rightHandSide + HORIZONTAL_GAP, availableHeight + VERTICAL_GAP));
if (maxVisibleY > bottomBorder) {
packer.addSpace(new Rectangle(0, bottomBorder + VERTICAL_GAP, availableWidth + HORIZONTAL_GAP,
maxVisibleY - bottomBorder + VERTICAL_GAP));
}
// TODO: Sort previews first before attempting to position them?
ArrayList<RenderPreview> aspectOrder = new ArrayList<RenderPreview>(myPreviews);
Collections.sort(aspectOrder, RenderPreview.INCREASING_ASPECT_RATIO);
if (BinPacker.DEBUG) {
packer.dumpDiagnostics();
}
for (RenderPreview preview : aspectOrder) {
int previewWidth = preview.getLayoutWidth();
int previewHeight = preview.getLayoutHeight();
previewHeight += VERTICAL_GAP;
if (preview.isForked()) {
previewHeight += VERTICAL_GAP;
}
previewWidth += HORIZONTAL_GAP;
// title height? how do I account for that?
Rectangle position = packer.occupy(previewWidth, previewHeight);
if (position != null) {
preview.setPosition(position.x, position.y);
preview.setVisible(true);
if (BinPacker.DEBUG) {
myPacker = packer;
}
}
else {
// Can't fit: give up
return false;
}
}
myLayoutHeight = availableHeight;
return true;
}
public int getLayoutHeight() {
return myLayoutHeight;
}
}